Jump to content

Overhauling the weapon rack scripts


Sclerocephalus

Recommended Posts

I'm not entirely sure whether I do fully understand what you did with the daggers. So you equipped a glass dagger (with two glass daggers in your inventory) and activated two racks in succession, with the result of both daggers being placed on the rack ?

 

Thanks for your insights. One of the glass daggers was smithed as superior.

 

That's a known problem, but there's not much we can do about it:

 

Boot it it over to Hexaee?  :grinning:

Link to comment
Share on other sites

 

I'm not entirely sure whether I do fully understand what you did with the daggers. So you equipped a glass dagger (with two glass daggers in your inventory) and activated two racks in succession, with the result of both daggers being placed on the rack ?

 

Thanks for your insights. One of the glass daggers was smithed as superior.

 

That's a known problem, but there's not much we can do about it:

 

Boot it it over to Hexaee?  :grinning:

 

 

Tempering will only change the item's "ItemHealth" property, but the form remains the same. While you can discern the items based on this property (and also by reading the item's charge, when enchanted items are dealt with; note however that you need to have SKSE installed ro use these functions), doing so requires to know the item's reference for those functions to run on. While in a container, there's no way to retrieve the reference. Thus, as long as we have only the item's form, there will be no way to discern whether they are tempered or not.

 

Leaving this to Hexaae would be mean, as he can nothing do about it either.

Solving this would require to implement a new papyrus function, and this is a job for the SKSE team.

Link to comment
Share on other sites

As to fixing the scripted weapons problem, the canonical method is:

ObjectReference pDriver = currentDriver as ObjectReference

It seems really redundant and silly when the object reference is already an object reference, but there's code like this all over the place.

 

That's what my cousin's son-in-law (he's professional programmer) recommended when I asked him about three months ago, but it didn't work. Also important to note is that my scripts transfer the value to another property all the time and print the results on the log, since the values are always a good indication of something going wrong:

From the activator script:

   PlayersDroppedWeapon = ItemToPlace
   Debug.TraceUser ("WeaponRackLog", Self + ": Placed Item = " + PlayersDroppedWeapon.GetBaseObject() + "; Ref = " + PlayersDroppedWeapon)

From the trigger script:

  ObjectReference MountedItem

  MountedItem = ActivatorScript.PlayersDroppedWeapon
  Debug.TraceUser ("WeaponRackLog", ActivatorRef + "; Mounted Item = " + MountedItem.GetBaseObject() + "; Ref = " + MountedItem)

There are several logs shown in this thread that demonstrate the problem.

Link to comment
Share on other sites

Would it be beneficial to post a 3rd beta for the USKP and UHFP so you guys can see everything as it will be for the live release?

Link to comment
Share on other sites

For me, yes, so I can make sure that the Honeyside issue is fixed. Also because Honeyside is a test ground for weapon racks anyway: The three weapon plaques on the wall besides the enchanter are particular because the trigger volumes are so close to each other that you get all sorts of cross-activation events when placing an item on the upper two plaques. This has been always in the standard test runs to make sure that the trigerrs are doing what they are supposed to do.

Link to comment
Share on other sites

If you're talking about the broken pointer problem, that doesn't work. The cast seems to work at first (the result is not None), but when you try to call a method on it after casting, it still throws the "no native object ... or incorrect type" error just like it did initially. I even tried casting to Form first and then back to ObjectReference in case the compiler was optimizing it away, but still no dice.

That's what my cousin's son-in-law (he's professional programmer) recommended when I asked him about three months ago, but it didn't work.

As I stated "the canonical" method.... Since we see it all over the existing scripts, we know the Bethesda developers struggled with the same issue. Apparently, never solved.

The work around that I applied in Touring Carriages is to make a new object (cart, driver, horse), and transfer its old variables into the new one. But I don't know whether the specific variables you are accessing can be transferred.

Link to comment
Share on other sites

If it works at once, you are probably safe to remove the OnLoad event from the trigger script.

What the heck are you talking about? Have you actually looked at, compiled, and tested my code?

It does not remove the OnLoad event from the trigger script. It adds the following checks:

	If Self == None
		Trace (Self + ": Skipped handling of OnLoad event.")
		return
	EndIf

	Cell parentCell = GetParentCell()

	If parentCell == None
		Trace (Self + ": Skipped handling of OnLoad event. GetParentCell == None")
		return
	EndIf

	If !parentCell.IsAttached()
		Trace (Self + ": Skipped handling of OnLoad event. !IsAttached")
		return
	EndIf
It removed the OnLoad event from the Activator script, restoring it to the OnCellAttach used by Vanilla code. It works, and it doesn't spam the log with None references.

 

  • Have you made sure that "PlayersDroppedWeapon" is reset to "none" when the item is grabbed from the rack ? The vanilla script doesn't, but the Hearthfires script that checks this property won't work if you don't.
  • Have you made sure that your scripts cooperate properly with the new meshes ?
Again, please read the code -- instead of madly speculating!

The logic is the same as the old code. It terminates PlayersDroppedWeapon in exactly the same place. It makes no changes to meshes, nor to the positioning code.

I am advocating removing the OnUpdate, as it is not working to consolidate the trigger OnCellAttach with the trigger OnLoad. I don't know why you told us it did -- maybe it did in the past?

Link to comment
Share on other sites

USKP and UHFP betas have been updated with all the latest code. Hopefully everyone will be on the same page this way.

Link to comment
Share on other sites

What the heck are you talking about? Have you actually looked at, compiled, and tested my code?

 

Again, please read the code -- instead of madly speculating!

 

In case you didn't know, I'm not member of the USKP team and therefore, do not have access to the "Files for Fixes" section.

 

Also, I am not madly speculating, just asking (e.g. "Have you made sure ... ?" , NOT "Make sure ...")

 

 

The logic is the same as the old code. It terminates PlayersDroppedWeapon in exactly the same place. It makes no changes to meshes, nor to the positioning code.

 

So you might want to indicate this on your download page. Assuming that this is common practice, this was what actually led me to believe that you did write your own code.

 

I am advocating removing the OnUpdate, as it is not working to consolidate the trigger OnCellAttach with the trigger OnLoad. I don't know why you told us it did -- maybe it did in the past?

 

Of course, it doesn't. This has been explicitely noted in the change log on the download page for the overhaul: I have reset the update time to 0.0 because I wasn't happy with the flickering.

 

 

I don't know why you told us it did -- maybe it did in the past?

 

 It perfectly did in earlier versions, which has been documented by the logs posted a few pages back. I never said it does in v3.4.

 

Anyway, this is pointless. While consolidating the events would have been an elegant solution to the problem of double-activation, this can as well be done in a not-so-elegant way by using a bool property on the activator script (as it is done in v3.4).

 

The OnUpdate event is still more appropriate than a direct call of InitActivator, as it prevents an active instance of the trigger script from doing nothing while waiting for the function to return.

Link to comment
Share on other sites

USKP and UHFP betas have been updated with all the latest code. Hopefully everyone will be on the same page this way.

 

 Thanks. Will have a look immediately.

Link to comment
Share on other sites

I started a thread on bethesda's CK forum about the broken ObjectReference pointer issue:

 

http://forums.bethsoft.com/topic/1476556-no-native-object-or-object-is-of-incorrect-type/

 

In the mean time, Sclero and/or DayDreamer and/or anyone else who has tried to get Wuuthrad et al to work with weapon racks, did you ever try using a quest ReferenceAlias on the player to catch the ObjectReference in OnItemRemoved() (which is triggered by DropObject() anyway), rather than using the one returned directly by DropObject() which can be broken? So far in my tests, that event handler always seems to receive a usable pointer, even when all other previously stored pointers have become broken. However I have not yet extensively tested what happens to the OIR() pointer after leaving the cell and returning a few times, so maybe you guys already tried this and it didn't work.

 

EDIT: Thinking about this more, I wonder if the next problem would be that the OnTriggerLeave would be unable to identify whether the player actually picked up that trigger's mounted item. Comparing the ObjectReference pointers probably won't work because by the time OnTriggerLeave fires the item is probably back in inventory where its reference looks different. Comparing base forms would work except it would be confused by another instance of the same form being picked up from an adjacent rack, but that might still be okay for most of the problematic items because they tend to be unique -- two Silver Swords on adjacent racks would still be a problem though. I have one other crackpot idea that might make OnTriggerLeave reliable, but I won't go there until we determine that even placing the items initially can be done using OIR().

Link to comment
Share on other sites

In case you didn't know, I'm not member of the USKP team and therefore, do not have access to the "Files for Fixes" section.

Damn. I'm sorry. I didn't realize. I'll upload the next version (without OnUpdate) somewhere else.

 

The logic is the same as the old code. It terminates PlayersDroppedWeapon in exactly the same place. It makes no changes to meshes, nor to the positioning code.

 

So you might want to indicate this on your download page. Assuming that this is common practice, this was what actually led me to believe that you did write your own code.

It's assumed. Heck, I even left in the redundant:

        If (StartingItemHasBeenGrabbed == False) && StartingItem.IsEnabled()
            If (PlacedItemInit && (PlayersDroppedWeapon != StartingItem)) || !LoadsInSameCell (StartingItem)
                StartingItemHasBeenGrabbed = True
                Trace (Self + "ActivatorSetup() StartingItemHasBeenGrabbed = True.")
            Else
                HandleStartingItem (StartingItem, TriggerMarker)
                StartingItemHasBeenGrabbed = False
            EndIf
        EndIf
StartingItemHasBeenGrabbed = False; isn't needed, as it's already false by the outer if clause. But it does no harm -- and who knows, somebody might make a bad change to HandleStartingItem() someday, and this will save the day.

 

Of course making gratuitous changes is NOT common practice! That's what I meant in my earlier message. Folks working on cooperative projects make their changes so they are easy to diff. We don't change all the "elseif" to "ElseIf" -- it makes it really really hard to do code review!

 

Of course, it doesn't. This has been explicitely noted in the change log on the download page for the overhaul: I have reset the update time to 0.0 because I wasn't happy with the flickering.

 

It perfectly did in earlier versions, which has been documented by the logs posted a few pages back. I never said it does in v3.4.

Well, I'm not aware of a change log for an "overhaul"? And you didn't post any explanation here.

 

Anyway, this is pointless. While consolidating the events would have been an elegant solution to the problem of double-activation, this can as well be done in a not-so-elegant way by using a bool property on the activator script (as it is done in v3.4).

 

The OnUpdate event is still more appropriate than a direct call of InitActivator, as it prevents an active instance of the trigger script from doing nothing while waiting for the function to return.

I'm not interested in consolidating the events. I'm interested in reducing complexity. Now that we've discussed it, I'll make a version that uses the existing semaphores and eliminates the superfluous OnUpdate.

WeaponRack-4-0d.7z

Link to comment
Share on other sites

I started a thread on bethesda's CK forum about the broken ObjectReference pointer issue:

 

http://forums.bethsoft.com/topic/1476556-no-native-object-or-object-is-of-incorrect-type/

 

A very good idea and probably long overdue.

 

 

 

In the mean time, Sclero and/or DayDreamer and/or anyone else who has tried to get Wuuthrad et al to work with weapon racks, did you ever try using a quest ReferenceAlias on the player to catch the ObjectReference in OnItemRemoved() (which is triggered by DropObject() anyway), rather than using the one returned directly by DropObject() which can be broken? So far in my tests, that event handler always seems to receive a usable pointer, even when all other previously stored pointers have become broken. However I have not yet extensively tested what happens to the OIR() pointer after leaving the cell and returning a few times, so maybe you guys already tried this and it didn't work.

 

EDIT: Thinking about this more, I wonder if the next problem would be that the OnTriggerLeave would be unable to identify whether the player actually picked up that trigger's mounted item. Comparing the ObjectReference pointers probably won't work because by the time OnTriggerLeave fires the item is probably back in inventory where its reference looks different. Comparing base forms would work except it would be confused by another instance of the same form being picked up from an adjacent rack, but that might still be okay for most of the problematic items because they tend to be unique -- two Silver Swords on adjacent racks would still be a problem though. I have one other crackpot idea that might make OnTriggerLeave reliable, but I won't go there until we determine that even placing the items initially can be done using OIR().

 

Yes, I tried that - and ran into a problem with the trigger ...

 

The problem was that I still had to use DropObject to remove the item from the player's inventory. Otherwise, there is no way to place it on the rack. Since the reference returned by DropItem would be useless, I did the same I still do and used a test container to retrieve the true reference, then filled that reference in an alias and this worked: with this reference, I could manipulate the item. Though, with the reference from DropObject, any item handling is impossible.

 

And then, the rack stayed inactive when I grabbed it again, because the OnTriggerLeave event returned nonsense. Moreover, when I left the cell and returned, the item fell off the rack ... Well, that's another persistence-related rack phenomenon: pre-placed items also fall off if their placement is not renewed in every cell attach, while the player items usually don't. Nonetheless, that's a minor problem, since I still could add an OnCellAttach event to the alias script which submits the item to the same procedure (assuming that I leave it in the alias, but this should work because the player item never has any true relationship with the rack; it's just a havok-disabled item that floats at some distance from the rack that is small enough to give you the impression it is mounted). So far though, I did not find a workaround for the trigger problem.

 

Also worth noting: when you run a FindClosestRefOfType... function (which takes the base object, not the reference) to search for the item after you dropped it from the player's inventory, it always returns none. You see the item on the floor in front of you, you know that it has been removed from your inventory (you also can easily check this in the game) and you tell the engine how it looks like (i.e. you know the base object), but the script doesn't find it. Once the reference is borked, most commands stop working.

 

Another idea: what if we simply change the way the items are distributed in the game ? I'm thinking at a dummy: make a number of one-item leveled lists (with only the respective problem weapons in them), link them to dummies and place those. Could that prevent the items themselves from becoming persistent ?

Link to comment
Share on other sites

StartingItemHasBeenGrabbed = False; isn't needed, as it's already false by the outer if clause. But it does no harm -- and who knows, somebody might make a bad change to HandleStartingItem() someday, and this will save the day.

 

You're basically right, but there's still a minor chance that the trigger gets an "invalid" OnLeave event when there's a long delay between its OnLoad event and the OnLoad event of the activator (as seen in Arthmoor's log, where the delay was around 6s in one case). Unless the activator script is running, there's simply no way for it to control the trigger's state. Now, if such an event occurs, the trigger will set StartingItemHasBeenGrabbed to "True", even if it is not - with the result of the item falling off because the activator script, once it starts running, thinks that the starting item doesn't have to be handled because it was previously grabbed already. There's a faint chance that this occurs, even with all the safety checks the trigger script does while handling the event.

 

Therefore, better safe than not.

 

Sorry, I should explain this better:

The one time I had this happen myself (though with a delay of only 2s), the trigger was handling an OnLeave event WHILE the activator was placing the starting item, and did set StartingItemHasBeenGrabbed to "True" before the activator script returned from the handling function. This time, it was still placed, but on a subsequent visit to the cell, it did fall off.

 

Maybe, I'm going to remove this later, but only when I'm sure that the measures undertaken to prevent this from occurring do all work.  It has to be reproducible, not only repeatable.

 

 

Well, I'm not aware of a change log for an "overhaul"? And you didn't post any explanation here.

 

Sorry. It's actually logical that you won't look at the page since you can't download there anyway. I simply didn't think at that (honestly). Sometimes, this happens. Remember that it's usually late at night or very early in the morning here when this forum sees its peak activity (right now, it's about midnight ...).

 

The log is here:

http://www.afkmods.com/index.php?/files/file/785-weapon-rack-overhaul/

 

 

 

Further comments and or questions after a look at your modifications.

 

Link to comment
Share on other sites

The problem was that I still had to use DropObject to remove the item from the player's inventory. Otherwise, there is no way to place it on the rack. Since the reference returned by DropItem would be useless, I did the same I still do and used a test container to retrieve the true reference, then filled that reference in an alias and this worked: with this reference, I could manipulate the item. Though, with the reference from DropObject, any item handling is impossible.

 

And then, the rack stayed inactive when I grabbed it again, because the OnTriggerLeave event returned nonsense. Moreover, when I left the cell and returned, the item fell off the rack ... Well, that's another persistence-related rack phenomenon: pre-placed items also fall off if their placement is not renewed in every cell attach, while the player items usually don't. Nonetheless, that's a minor problem, since I still could add an OnCellAttach event to the alias script which submits the item to the same procedure (assuming that I leave it in the alias, but this should work because the player item never has any true relationship with the rack; it's just a havok-disabled item that floats at some distance from the rack that is small enough to give you the impression it is mounted). So far though, I did not find a workaround for the trigger problem.

 

Yes, the return from DropObject() is broken if the dropped item has a script, so I see why you tried using a test container to get the reference a different way. But I believe object references are handled very differently when they're in-world instead of in some inventory or container, and I think that may be why the reference you got from your test container was still not usable once the item was dropped to the world.

 

That's why I suggested using a ReferenceAlias on the player instead. You still call DropObject() to make the item drop, but you ignore its return value; instead, you have your ReferenceAlias watching for OnItemRemoved(), which will receive a usable reference to the item *after* it is in the world, as opposed to the in-container reference you get from your test container. I'm hoping that difference will make the OIR()-received reference pointer stable, even after leaving the cell and returning a few times.

 

I've just been working on implementing this idea myself, so I'll paste what I have so far in case you want to try it. Since you already have a USKPWeaponRackItemHandlingQuest, I was thinking to just add a PlayerRef alias to this quest and give it this script:

Scriptname USKPWeaponRackItemHandlingQuest_PlayerRef_Script extends ReferenceAlias

Form[] caughtForm
ObjectReference[] caughtRef
Int caughtCount = 0


Event OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer)
	; ignore
EndEvent

State active
	Event OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer)
		If caughtCount < caughtForm.Length
			caughtForm[caughtCount] = akBaseItem
			caughtRef[caughtCount] = akItemReference
			caughtCount += 1
		EndIf
	EndEvent
EndState

Function CatchRemovedItems()
	caughtForm = new Form[16]
	caughtRef = new ObjectReference[16]
	caughtCount = 0
	GotoState("active")
EndFunction

ObjectReference Function ReturnCaughtRef(Form akBaseItem = None)
	GotoState("")
	ObjectReference ref = None
	Int i = 0
	While (i < caughtCount)
		If (caughtForm[i] == akBaseItem) || (akBaseItem == None)
			ref = caughtRef[i]
			i = caughtCount
		EndIf
		i += 1
	EndWhile
	caughtForm = None
	caughtRef = None
	caughtCount = 0
	Return ref
EndFunction

The idea then is that inside your HandlePlayerItem(), you do something like:

refScript.CatchRemovedItems()
PlayerRef.DropObject(PlayerItem) ; ignore the return, it's crap
ObjectReference PlayerItemRef = refScript.ReturnCaughtRef(PlayerItem)

I can't remember offhand if reference alias scripts can be easily called this way, so maybe this has to be routed through some functions on the handling quest's own script, but you see the idea. This way, you end up with the ObjectReference pointer that was given to OnitemRemoved() as a result of DropObject(), and that reference (I believe) will remain usable at least until the player picks the item up again, so hopefully resetting the position/physics on attach will be fine.

 

Detecting the pickup is the next issue, but it might be as simple as just comparing via GetFormID() instead of comparing your ObjectReference pointers directly. That is, instead of "ref1 == ref2", use "ref1.GetFormID() == ref2.GetFormID()". And if that doesn't work, then I have another idea we can try.

 

Anyway, I'm going to tinker with this too, but since I'm less familiar with USKP in general it may take me longer to get the test set up. If you feel inclined to try out this idea yourself before I get it working, let me know how it goes.

Link to comment
Share on other sites

Sclero, I did have some minor questions about the existing script choices. While I'm poking at it....

Vanilla OnTriggerLeave() has a test against a developer specified Property:

Bool Property IgnoreArmor = FALSE Auto

if (IgnoreArmor == TRUE) && (triggerRef.GetBaseObject() as Armor)
Instead, you chose to automate it:

(HasNode ("ShieldPivot01") && triggerRef.HasKeyword (ArmorShield))
But didn't you find anywhere that had the developer specified IgnoreArmor? Was it wise to ignore? Or and attempt to make everything that looks the same in-game to act the same, no matter what the developer specified?

Triviality: is there a reason for casting here?

If (leavingItemBase As Weapon) || triggerRef.HasKeyword (ArmorShield)
Is this really a good weapon test? As opposed to the keyword test?
Link to comment
Share on other sites

Triviality: is there a reason for casting here?

If (leavingItemBase As Weapon) || triggerRef.HasKeyword (ArmorShield)
Is this really a good weapon test? As opposed to the keyword test?

 

This is actually not what's in the script. The line in the script looks as follows:

(leavingItemBase As Weapon) || leavingItem.HasKeyword (ArmorShield)

A shield is of type armor, so "LeavingItemBase As weapon" is "none" when the item is a shield. Thus, to check for weapons only, you have to cast (you can also check for the weapon keywords, but then you will have to check them all. Nonetheless, both methods work well). To check for shields only, you cannot cast, because Armor is too un-specific, and you would leave unrelated events through (with the vanilla scripts active, you could trigger the rack by boxing at it with gloves equipped ...)

 

OnTriggerLeave events (also OnTriggerEnter events, by the way) can be triggered by half Tamriel: any havok-enabled item that is thrown at a rack will trigger one (plus one OnTriggerEnter event before, although this might fire out of order), any NPC walking close to the racks will trigger those events, etc. etc. In addition, the placement procedure itself will trigger an avalanche of events, since the script rotates the weapon in its final position (you can see this yourself in the game, and when you stand too close, you even get hurt). However, this does not only trigger the rack you're placing an item on, but also the adjacent racks. Finally, the MoveToNode command will trigger a pair of events, because it causes a temporary loss of the item's 3D (sic! - that's nowhere documented and I only know this, because it was mentioned in a developer's comment on one of the critter scripts). This final OnTriggerLeave event, which always fires a little after the item has been placed, is the reason for the "Wait (0.05)" command after the actual item placement (also, please leave this at 0.05 seconds for the time being. It's possible that the delay can be further reduced, but I have not tested this and cannot say whether it's safe).

 

You have to make sure that the event is not handled when it is not related to the rack (and that's more difficult than it appears to be). There are more specific checks further on, but they will cost time, so it is wise to place a quick check at the start that will "divert" most unrelated stuff. Hence, a simple check for weapons and one for shields.

 

---------------------

 

As for the vanilla checks, you have to keep in mind that the vanilla scripts were not using states to keep the trigger disabled. They basically were evaluating every OnTriggerLeave event (plus every OnTriggerEnter event, the latter was entirely superfluous and only caused problems) and were trying at the same time to keep the checks as simple as possible. That didn't work.

 

The best check to find out whether the OnLeave event is valid, i.e. whether it has anything to do with the rack it runs on (and does not fire for example, because an oversized weapon is grabbed from an adjacent rack ... I say this again here, because the vanilla scripts were unable to discern this, and this was the primary cause of most of the more common weapon rack glitches) is by checking the reference that triggers the event against "PlayersDroppedWeapon". Only this is safe. All the other checks in my script only take care of the situation that the USKP has just been installed, and in this case, "PlayersDroppedWeapon" is not reliable, because the value is carried over from the vanilla script and that script did never properly update this property (related info: if "PlacedItemInit" is "true", this tells the activator script that the values for "PlayersDroppedWeapon" and "StartingItemHasBeenGrabbed" are reliable).

 

 

EDIT:

 

Instead, you chose to automate it:
 
(HasNode ("ShieldPivot01") && triggerRef.HasKeyword (ArmorShield))
 
An almost entirely superfluous check. Never needed - except the script runs for the first time and there's no reliable reference in "PlacersDroppedWeapon" to check against (but then, it is important).
 
I use this (and a few other, equally trivial checks) because it helps to get the activator faster to regular work than only by repeatedly running its initialization procedure, as this alone could take forever without the properties ever getting properly initialized.

 

These simple checks are safe (e.g. when the trigger has a shield pivot, it must be a shield rack, and when I grab a shield from a shield rack, the rack must be empty), so I know I can the activators help to initialize their start values when they run for the first time. That's also why I did recommend to empty all racks, leave the cell and return to make them work after USKP 1.3.3 went live.

 

If you run the racks without a valid reference in "PlayersDroppedWeapon", you always risk to enable the activator when the rack is occupied or vice versa, and this has detrimental results: since an activator is nothing else than a collision box, enabling it on an occupied rack will make it impossible to ever retrieve the placed weapons.

Link to comment
Share on other sites

This is actually not what's in the script....

Well, it was my reconstruction for my apparently not-so-trivial question. At the moment, my code looks like this:

If !myActivatorRef.IsDisabled()
	return
EndIf

; the activator either thinks it has something on it, or that this trigger is disabled.
Bool isArmorShield = triggerRef.HasKeyword (ArmorShield)
Form leavingItemBase = triggerRef.GetBaseObject()

; NOTE: the following test uses a cast to discern whether the game engine thinks this is a
; weapon, instead of exhaustively testing all the appropriate keywords.
If (leavingItemBase As Weapon) || isArmorShield
You're living dangerously. But as long as it's well-commented, we know where to look in the future.

Do you have any information about the less trivial query?

Link to comment
Share on other sites

Just a quick update: with a little tweaking I was able to get that ReferenceAlias idea to work, at least for placing items.

 

I started with the latest 2.0.0 beta + the v4.0 weapon rack scripts DayDreamer posted, but disabled the test container sanity check in HandlePlayerItem() in order to see the original buggy behavior with scripted items. Sure enough, a Silver Sword would just hover in the air and throw log errors, but wouldn't go on the rack.

 

After switching to the ReferenceAlias-OnItemRemoved() scheme for capturing the dropped weapon reference, I was then able to place and retrieve my Silver Sword many times in a row on a CoA rack as well as a vertical wooden rack. The sword seemed to go into the rack just fine every time, and I also tried leaving the cell and re-entering a few times, including a 'pcb' in between one time, and four different silver swords on various racks remained in position when re-entering the cell.

 

So far so good. But OnTriggerLeave is still problematic because when a silver sword is picked up, either its rack or a neighboring one receive a broken pointer to this handler, so they can't test whether the grabbed item was their own item. I'm still toying with that issue and I have an idea at least, although it'll be ugly even if it works.

Link to comment
Share on other sites

So far so good. But OnTriggerLeave is still problematic because when a silver sword is picked up, either its rack or a neighboring one receive a broken pointer to this handler, so they can't test whether the grabbed item was their own item. I'm still toying with that issue and I have an idea at least, although it'll be ugly even if it works.

 

At present, there is still a minor problem with DayDreamer's concept of enabling/disabling the trigger. This does not work in all instances as intended (and is also not the same as in v3.4 - which must be horrible for you pros to read ...), and we will have to discuss this further. I can't fully exclude therefore, that the trigger is evaluating events which it should actually leave out.

 

EDIT:

Just got an idea: there aren't that many problem weapons in the game and they all are unique items. Thus, we could add a bool property to the trigger script, which is set "true" by the alias script when a problem weapon is placed. If true, the trigger script would skip the reference test and would check only the base objects instead.

Link to comment
Share on other sites

Just got an idea: there aren't that many problem weapons in the game and they all are unique items. Thus, we could add a bool property to the trigger script, which is set "true" by the alias script when a problem weapon is placed. If true, the trigger script would skip the reference test and would check only the base objects instead.

 

Unfortunately they're not all unique items -- the Silver Sword is a prime example, the player can craft 100 of those and every one gets a script from its base form. Also, the trigger script can't test base forms because the only thing OnTriggerLeave() receives is an ObjectReference, it doesn't get a Form of the base item the way some other events do. So you'd have to call GetBaseObject() on that ref, but if the ref is broken, that won't work.

Link to comment
Share on other sites

Sigh ...

 

I remember very vaguely (although I can be wrong), that it even might have been the USKP which actually made the silver swords craftable ...

 

 

EDIT:

There's still a workaround without having to try ugly things: The main reason for all the testing on the trigger script is that there's no other way to discern whether the event came from the rack the script runs on or from a "cross activation", which usually occurs when a large weapon is grabbed from an adjacent rack. We could throw out the tests when we make sure that there can't be a cross activation, but to accomplish this, we would have to edit the trigger meshes: reduce the size of the trigger volumes (to see them, turn collision on in the CK), so that an item leaving from the same rack is still easily detected while cross activation is impossible.

Link to comment
Share on other sites

Sigh ...

 

I remember very vaguely (although I can be wrong), that it even might have been the USKP which actually made the silver swords craftable ...

 

Actually I misremembered; the USKP made them temperable, but still not craftable. Still, the player could conceivably *find* more than one in random loot, probably from fighting Silver Hand NPCs. And there's always player-made mods that could easily have non-unique scripted items.

Link to comment
Share on other sites

Confirming the theory about it being scripted items that are causing all the trouble.

 

Something I'm cooking up behind the scenes for another mod has had two referenced objects with the "no havok" script attached to them. They can't be placed. (curse this script, does it even serve a purpose?)

 

A 3rd has "defaultDisableOtherObjectWhenTaken" attached to it, and it also can't be placed.

 

The rest can be, despite some of them being held in permanently persistent quest aliases.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...