Jump to content

Overhauling the weapon rack scripts


Sclerocephalus

Recommended Posts

(1) The keywords for the xMarkers need to be commented out, EXCEPT for WRackTrigger (but that's not an xMarker keyword anyway)

Personally, I strongly disagree. This is how log spam is generated every time I start the game. Annoying. Unless they have never been initialized, I leave them.

Also, although probably not in this case, I always leave constants that might be needed for removing the mod. Folks are often silly enough to try to remove USKP. Heck, even I have removed it to test briefly.

So, I'll need to check and see whether they've been initialized in the base game first.

(2) In the HandleStartingItem function: the dagger case has not been handled in the vanilla script (somehow they forgot it ...); that part has been added by myself

Yes. I see that. I haven't changed that. Is it not working?

I did add a test for unknown rack types....

And one minor improvement:

In the PlaceItem procedure, the script has to discern the rack type again when a staff has to be placed, in order to select the right pivot "layout". Though, it does the check already when the RunPlayerActivation performs the checks whether the player's item is allowed on the rack at all. Thus, you could make "Layout" a script-owned instead of a function-owned variable, give it a default value of -1 and set its value without a further check in the RunPlayerActivation function. This saves two complex checks in the PlaceItem function, i.e. this:

	elseif PlayersDroppedWeapon.HasKeyword(WeaponTypeStaff)
		; Staff
		If ((RackType == StandardRack) || (RackType == LargeDisplayCase)) && (Patch14CoARacks == False)
			PlaceStaff (PlayersDroppedWeapon, TriggerMarker, 0)
		ElseIf (RackType == CoAWeaponRackRL) || (Patch14CoARacks == True)
			PlaceStaff (PlayersDroppedWeapon, TriggerMarker, 1)
		Else
			PlayersDroppedWeapon.MoveToNode(TriggerMarker, "StaffPivot01")
		EndIf
could be reduced to that:

	elseif PlayersDroppedWeapon.HasKeyword(WeaponTypeStaff)
		; Staff

                If (LayOut < 0)
                        PlayersDroppedWeapon.MoveToNode(TriggerMarker, "StaffPivot01")
                Else
			PlaceStaff (PlayersDroppedWeapon, TriggerMarker)
		EndIf
OK, although only an optimization of your own code -- I don't see that series of tests in the original. Also, I'm a fan of zero for defaults, and a bit more range testing. But it's a good idea. I'll take a look!
Link to comment
Share on other sites

While I have your attention, I was wondering why your code disables and enables the activators? (If enabled, it is empty. If disabled, it is occupied.) The vanilla code didn't do that. Does it have any effect?
Link to comment
Share on other sites

While I have your attention, I was wondering why your code disables and enables the activators? (If enabled, it is empty. If disabled, it is occupied.) The vanilla code didn't do that. Does it have any effect?

 

(1) While it is enabled, you can place other weapons. They will stack on the rack, which eventually leads to a big mess.

 

(2) An activator is nothing else than a collision box. If you leave it enabled when the rack is occupied there will be no way to get your weapon back. When you detect an activatable item in the game, this is because you get in contact with its collision surface (or, in some cases, with the surface of the trigger that surrounds it). Most activators perfectly enclose the rack, including all of the weapons placed on them. Now, when you approach the rack with the activator enabled, the game only detects the activator, but not the weapon underneath.

It is not entirely true that the vanilla scripts did not do that. They tried it, but they never managed to do it right (also a result of their problem to detect reliably when a rack was empty; remember the cross-acitvation effect: this all plays together here). That was the infamous vanilla bug of "racks eating weapons".

In addition, their own game-level designers stopped many player-home racks and even more non-activatable racks from working (around 60 in total, plus the three in the Danwguard DLC mentioned above) by linking them to enable markers.

 

There are quite a number of sites on the web that maintain lists of weapon rack bugs (none of them is exhaustive though), such as this one:

http://elderscrolls.wikia.com/wiki/Weapon_Rack

All this had to be cured along the way with a new logics.

 

By the way, perhaps you would like to know why the vanilla scripts did never manage to keep the pre-placed items on the racks. There was a nasty logics bug, which probably would never have slipped in when they (1) had their variables given meaningful names ("PlayersDroppedWeapon" is misleading because it is not always a weapon, but in the vanilla scripts, it was not even always a player's item), and (2) had kept the handling of the starting item and the player's item separate from the beginning. Just follow the way of the starting item through the vanilla script.

Link to comment
Share on other sites

You know. That whole maces hanging upside down thing. Shouldn't that be a bug? How could a mace hang like that without falling straight through the holder?

Link to comment
Share on other sites

Personally, I strongly disagree. This is how log spam is generated every time I start the game. Annoying. Unless they have never been initialized, I leave them.

 

While I agree with your concerns, try to adopt another point of view. There are more than 500 racks in the base game (DLCs not included). They will all store their properties. 500 times nine superfluous properties makes a good bit of savegame bloat. In addition, the warnings you see are garbage collected after the first time you visit the cell that contains the respective rack. After some time, they are entirely gone.

 

 

Yes. I see that. I haven't changed that. Is it not working?

 

 

It works. I only noticed that you added comments to all code that was not in the original script, but left this out. That's why I mention it.

 

 

OK, although only an optimization of your own code -- I don't see that series of tests in the original.

 

Yes, but this shouldn't be a reason for not improving it, should it ?

 

I did add a test for unknown rack types....

 

Not really necessary for the starting item (since all items in the vanilla game are correctly placed), but helpful for forgetful modders, Thus, a good idea.

Link to comment
Share on other sites

You know. That whole maces hanging upside down thing. Shouldn't that be a bug? How could a mace hang like that without falling straight through the holder?

 

To change their placement, you have to rotate them by 180°.

 

180°

 

Does that ring a bell ??

 

 

EDIT:

I will try to modify the node, but I can't guarantee that it will work.

Link to comment
Share on other sites

It does.... but couldn't we rotate them by 179.5 degrees instead? :P

 

Yes, it's a fantasy game, but even so, defiance of gravity like that has bugged me for awhile now.

Link to comment
Share on other sites

Yes, it's a fantasy game, but even so, defiance of gravity like that has bugged me for awhile now.

 

Go tell that the modders whose weapons invalidate leverage.

 

 

EDIT:

By the way, what annoys me much more are those gravity-defiant body mods ...

 

 

EDIT2:

And before I forget it: before you go live, you'll get a pack of mesh edits from me: two corrected collision issues, plus the correction of a hefty gap (actually, why didn't anybody complain about this ?) above the door to Brunwulf's house, due to inverted face normals.

Link to comment
Share on other sites

Thanks for the excellent explanation. I hadn't found it earlier in this thread. I'll add more notes to the script for posterity....

OK, now a minor bug:

If (StartingItemHasBeenGrabbed == False) && StartingItem.IsEnabled()
	If (PlacedItemInit && (PlayersDroppedWeapon != StartingItem)) || !CheckFor3D (StartingItem)
		StartingItemHasBeenGrabbed = True
		Trace (Self + "ActivatorSetup() not handling item; StartingItemHasBeenGrabbed = True.")
	Else
		HandleStartingItem (StartingItem, TriggerMarker)
		StartingItemHasBeenGrabbed = False
	EndIf
EndIf
StartingItemHasBeenGrabbed = True; is only correct for the first clause: PlacedItemInit && (PlayersDroppedWeapon != StartingItem))

Since PlacedItemInit is defined to mean that both PlayersDroppedWeapon and StartingItemHasBeenGrabbed are correct, and there's a conflict, that's OK. It seems to be a cleanup, and should be documented as such.

But !CheckFor3D (StartingItem) doesn't imply StartingItemHasBeenGrabbed. All it means is that the graphics didn't load fast enough. Even though I doubled your time (to the 10 iterations used by vanilla elsewhere), I've been testing and find that occasionally not all weapons manage to get loaded. I remember an earlier post that sometimes the OnLoad event shows up 6 seconds later.

Well, we don't want to wait that long. But we don't want to leave the item on the ground forever, either.

I understand that the check covers the vanilla:

if StartingWeapon.Is3DLoaded()
	if StartingWeapon.GetParentCell() == self.GetParentCell()
		HandleStartingWeapon()
	endif
endif
And I understand that parent cell test didn't work properly.

I'd like to split out an elseif there, so that it will be allowed to try mounting again at a later time. What say you?

Link to comment
Share on other sites

I would like the maces to be right-side up -- or a peg on the rack and loop in the handle, or something. It's bothered me since my 1st or 2nd visit to Helgen. I spent a half hour looking at the mace in the torture room trying to figure out how they hung it. Little did I know they don't actually hang at all. :)

By the way, what annoys me much more are those gravity-defiant body mods ...

Ha, you don't know the half of it! From the first day of release, and again yesterday, more complaints/queries about Schlongs of Skyrim not working with Touring Carriages. (The modder tests them by deliberately banging them against the ground from time to time to adjust the length. This causes the carriage to flip!)

I've put it in large, red, emphasized letters. Sadly folks with Schlong envy also seem to suffer from intellectual impairment as well.

Anyway, we make fun of them. But the dozens of posts does take its toll.

Link to comment
Share on other sites

Since PlacedItemInit is defined to mean that both PlayersDroppedWeapon and StartingItemHasBeenGrabbed are correct, and there's a conflict, that's OK. It seems to be a cleanup, and should be documented as such.
 
But !CheckFor3D (StartingItem) doesn't imply StartingItemHasBeenGrabbed. All it means is that the graphics didn't load fast enough. Even though I doubled your time (to the 10 iterations used by vanilla elsewhere), I've been testing and find that occasionally not all weapons manage to get loaded. I remember an earlier post that sometimes the OnLoad event shows up 6 seconds later.

Well, we don't want to wait that long. But we don't want to leave the item on the ground forever, either.

 

First, you have to keep in mind here, that PlacedItemInit may take a while until it is set true (considering the case of a script that runs for the first time). If true, the script will imply that the values for StartingItemHasBeenGrabbed and PlayersDroppedWeapon are reliable. If I set PlacedItemInit to true prematurely, I would risk that the activator could be enabled while the rack is occupied or vice versa, and in the worst case, the player would be unable to retrieve his weapon. Therefore, I have been very restrictive with the checks and only set it to true when the results are absolutely safe. For example, TOC = 0 is absolutely safe, as this only occurs when a rack is empty.  Unfortunately, in many cases where a rack is empty, TOC is not zero, but then there's not much I can do. As a result, PlacedItemInit may be false for quite a while and the script has to rely on the starting item to load when it is in the same cell.

 

As you correctly noted, this is a critical check, because the starting item has not necessarily been grabbed when CheckFor3D returns false, but there is also no reliable workaround. Therefore, I have checked this very extensively, but the starting item never failed to load when it was in the same cell. This may be related to the fact that all starting items are persistent: an object reference becomes persistent when it becomes linked from or to another object reference (you can't see this in the CK, but you can check it in TES5Edit, since this lists persistent and temporary references separately), and starting items are linked from the activators (by the way, all triggers and activators are persistent too). Although the items in a cell do generally not load in any particular order, it is my experience that persistent references load faster. This would actually make sense, because most persistent references are important for game mechanics in one way or another. I even ran the scripts with other people's house mods (to help them find out why their racks didn't work), and even with mods that filled the player homes with racks to the brim (in one case, ca. 70 racks in a single cell) the starting items never failed to load.

 

I had the CheckFor3D function configured for 5 cycles for the last two months now and never had a problem.

 

As for the case of a reference loading 6s after cell attach, this has been never documented. We only had the case of a trigger loading 6s before cell attach (documented in a log submitted by Arthmoor).

 

 

I'd like to split out an elseif there, so that it will be allowed to try mounting again at a later time. What say you?

 

The script should not only try to mount it again, it must mount it again, and it must do so even it was already mounted before!

 

As already mentioned, the case that the starting item does not load when it is present in an interior cell (and not in a container in that cell) does never occur. Thus "StartingItemHasBeenGrabbed" cannot be true unless (1) the activator safely detects a different weapon on the rack when it first runs (this is the check discussed above), or (2) the trigger detects that it has been grabbed from the rack. Thus, as long as the starting item is on the rack, the script will renew its placement on every cell attach.

 

Now, why is that important ? Simple: for some reason (well, it almost certainly has to do with the fact that the starting item is persistent in the same cell), its havok setting does not last beyond cell detach, even when it is modified by a script. Mounted items appear as mounted only because they are havok-disabled; when you turn havok on again (and this happens with the starting item when the cell attaches for the next time) they will fall down. Therefore, the starting item must be handled on every cell attach.

 

That's something the vanilla script did properly, but with the flaw that it did always move the starting item back to the rack, even when it was grabbed by the player in the meantime (remember that the vanilla script did never check whether the player removed it). This was the reason for yet another weird bug, which is demonstrated here in a short "comic strip" (in short words, I moved the starting items from the CoA rack in the player's bedroom in Hjerim to another rack (pictures 1 & 2), then left the cell. What I did see when I returned is demonstrated in pictures 3 & 4):

 

1

Before leaving Hjerim 1

 

2

Before leaving Hjerim 2

 
3

After returning to Hjerim 1

 

4

After returning to Hjerim 2

 
Note that the present script may do the same, but only when it runs for the first time, and then only once. This is because there is no way to discern whether the starting item fell off the rack due to the vanilla bug or has been moved deliberately to another place in the same cell by the player.
Link to comment
Share on other sites

I would like the maces to be right-side up -- or a peg on the rack and loop in the handle, or something. It's bothered me since my 1st or 2nd visit to Helgen. I spent a half hour looking at the mace in the torture room trying to figure out how they hung it. Little did I know they don't actually hang at all. :)

 

Sigh ...

 

It may still take a long while until you know of all the bugs that showed up about the fringes of the weapon racks.

 

Fixing an item placement requires a mesh edit. This is not necessarily difficult, but in this case extraordinarily time-consuming because you have to copy all mace meshes one-by-one into the nif of the rack and check their placement individually. Unfortunately though, there is no guarantee that the position you set on the node will be adopted by the respective item in the game.

 

Check this for a starter (this bug was truly spectacular):

http://www.afkmods.com/index.php?/tracdown/issue/12564-hearthfire-bugged-rack-in-lakeview-manor-bedroom/

Link to comment
Share on other sites

Since you guys are discussing parts of the logic that rely on GetParentCell(), here are a few tidbits I noticed while testing the objref pointer bug; maybe you guys both know this already, but just in case:

  • GetParentCell() gives a sensible result when an item is first created, even if it's in a container/inventory at the time, but after that it only gives an accurate result if the item is directly in the world and not in some container/inventory. If the player picks up an item (such as from a rack) and carries it to some other cell, GetParentCell() continues to return the last cell the item was directly in, until it is dropped to the world again and then GetParentCell() updates.
  • Whenever an object reference is in any container or inventory, IsDeleted() returns True. When the item is dropped to the world gain, IsDeleted() goes back to False.

So in general, GetParentCell() can't be trusted if IsDeleted(). Conversely, I think it can definitely be trusted if Is3DLoaded(). So in your tests for whether starting items have been grabbed, it might be worth adding a test for IsDeleted() first; if that's True then you know that the item must have been grabbed, even though GetParentCell() might still return the starting cell if the player never dropped it to the world after first grabbing it.

Link to comment
Share on other sites

So in general, GetParentCell() can't be trusted if IsDeleted(). Conversely, I think it can definitely be trusted if Is3DLoaded(). So in your tests for whether starting items have been grabbed, it might be worth adding a test for IsDeleted() first; if that's True then you know that the item must have been grabbed, even though GetParentCell() might still return the starting cell if the player never dropped it to the world after first grabbing it.

 

Makes sense. If it's in a container, it cannost just have fallen off (but why does IsDeleted() react to containers/inventories ?)

Thank you.

 

@DayDreamer, please exercise your mandate.

 

BTW, when you sell it to a merchant and wait until his chest resets, GetParentCell() will again start to return the starting cell. Same if you drop it in an exterior cell and wait until that cell resets.

Link to comment
Share on other sites

BTW, when you sell it to a merchant and wait until his chest resets, GetParentCell() will again start to return the starting cell. Same if you drop it in an exterior cell and wait until that cell resets.

 

I actually didn't observe this in my testing. When I grabbed a persistent item (a pre-placed shield on a rack) and carried to a merchant, GetParentCell() still returned the original, but as soon as I dropped it in the cell with the merchant, GetParentCell() updated to that cell. When I picked it up and sold it, GetParentCell() remained unchanged and MoveTo() would pull it back from the merchant chest to my feet. When I waited 3 days for the chest to reset, MoveTo() would no longer revive it, but GetParentCell() still returned the merchant's cell where it was last in the world -- it didn't seem to revert to the starting cell. At least that's my recollection.

Link to comment
Share on other sites

500 times nine superfluous properties makes a good bit of savegame bloat.

Removed the 9 variables, as they've already been removed from the USKP VMAD itself. So anybody running it has already lost the values. There's no going back....

 

Passed along the "layout" using the existing constants you made. Added [uSKP] in a few places to attribute additions and changes.

 

There was a nasty logics bug, which probably would never have slipped in when they (1) had their variables given meaningful names ("PlayersDroppedWeapon" is misleading because it is not always a weapon, but in the vanilla scripts, it was not even always a player's item), and (2) had kept the handling of the starting item and the player's item separate from the beginning. Just follow the way of the starting item through the vanilla script.

Thanks! I've tried to add a modicum of additional explanation to the comments, as well as the warning that some names were poorly chosen.

Link to comment
Share on other sites

There's a lot of information; hard to reply to all of it. So bear with me.

 

First, you have to keep in mind here, that PlacedItemInit may take a while until it is set true (considering the case of a script that runs for the first time). If true, the script will imply that the values for StartingItemHasBeenGrabbed and PlayersDroppedWeapon are reliable. If I set PlacedItemInit to true prematurely, I would risk that the activator could be enabled while the rack is occupied or vice versa, and in the worst case, the player would be unable to retrieve his weapon. Therefore, I have been very restrictive with the checks and only set it to true when the results are absolutely safe.

Not restrictive enough. I'd already quietly fixed an ordering problem back in 4.0, where you set it before the others. Currently:

; When an item is grabbed from the rack, StartingItemHasBeenGrabbed must be true,
; no matter whether or not the grabbed item was the starting item.
StartingItemHasBeenGrabbed = True
PlayersDroppedWeapon = None
PlacedItemInit = True
To be honest, a professional would have used a state variable (not a "state"), and probably a simple Moore model Finite State Machine. But I'm trying to fix things with as few changes as possible.

As you correctly noted, this is a critical check, because the starting item has not necessarily been grabbed when CheckFor3D returns false, but there is also no reliable workaround. Therefore, I have checked this very extensively, but the starting item never failed to load when it was in the same cell.

OK, now I have existence proof that they don't always load. Taking the carriage from Whiterun to Riverwood, one of the 2 objects didn't load fast enough, but was sitting on the walkway there. Showed in the logs. The carriages exacerbate the problem, because so much is loading more quickly than usual. Horses too. Also, exteriors are busier than interiors.

Unfortunately, even after I went in and out of the Inn several times, it didn't attach to the rack. That's how I narrowed it down to that test.

As for the case of a reference loading 6s after cell attach, this has been never documented. We only had the case of a trigger loading 6s before cell attach (documented in a log submitted by Arthmoor).

 

The script should not only try to mount it again, it must mount it again, and it must do so even it was already mounted before!

So I put the tests for cell attached in the OnLoad. And agreed!!!

... its havok setting does not last beyond cell detach, even when it is modified by a script. Mounted items appear as mounted only because they are havok-disabled; when you turn havok on again (and this happens with the starting item when the cell attaches for the next time) they will fall down. Therefore, the starting item must be handled on every cell attach.

Same with horses and carts. Unfortunately, to get the engine to re-attach them, you have to delete and replace the cart object. I've got a whole bunch of code built around doing that. :(

... Note that the present script may do the same, but only when it runs for the first time, and then only once. This is because there is no way to discern whether the starting item fell off the rack due to the vanilla bug or has been moved deliberately to another place in the same cell by the player.

Understood.

There's also the problem that 3D may still be loaded after moving from one cell to another, or an exterior to an interior or vice versa. So this test isn't very good on its own. I could have taken a sword off the rack in an old version and put it inside. And reloaded the saved game with the new version and walked outside. It will probably still be is3DLoaded().

  • GetParentCell() gives a sensible result when an item is first created, even if it's in a container/inventory at the time, but after that it only gives an accurate result if the item is directly in the world and not in some container/inventory. If the player picks up an item (such as from a rack) and carries it to some other cell, GetParentCell() continues to return the last cell the item was directly in, until it is dropped to the world again and then GetParentCell() updates.
  • Whenever an object reference is in any container or inventory, IsDeleted() returns True. When the item is dropped to the world gain, IsDeleted() goes back to False.
So in general, GetParentCell() can't be trusted if IsDeleted(). Conversely, I think it can definitely be trusted if Is3DLoaded(). So in your tests for whether starting items have been grabbed, it might be worth adding a test for IsDeleted() first; if that's True then you know that the item must have been grabbed, even though GetParentCell() might still return the starting cell if the player never dropped it to the world after first grabbing it.
This is really important information. Thanks! I'll try it!
Link to comment
Share on other sites

There's a lot of information; hard to reply to all of it. So bear with me.

 

Not restrictive enough. I'd already quietly fixed an ordering problem back in 4.0, where you set it before the others. Currently:

; When an item is grabbed from the rack, StartingItemHasBeenGrabbed must be true,
; no matter whether or not the grabbed item was the starting item.
StartingItemHasBeenGrabbed = True
PlayersDroppedWeapon = None
PlacedItemInit = True
To be honest, a professional would have used a state variable (not a "state"), and probably a simple Moore model Finite State Machine. But I'm trying to fix things with as few changes as possible.

 

Ordering is irrelevant here, because (1) the activator is disabled when this code is executed and (2) it wouldn't run its initialization procedure anyway before the next cell attach.

 

OK, now I have existence proof that they don't always load. Taking the carriage from Whiterun to Riverwood, one of the 2 objects didn't load fast enough, but was sitting on the walkway there. Showed in the logs. The carriages exacerbate the problem, because so much is loading more quickly than usual. Horses too. Also, exteriors are busier than interiors.

 

First, I disagree here, since this is not a valid testing scenario. If your carriage scripts impart that high a workload on the machine, you've got a mod conflict. I'm running the game on a 4 year-old dual core with 30-35 fps on average and the only reason why it it runs acceptably at all is the graphics card which I spent a lot of money on. Nonetheless, I had never a problem with the items loading. I also had no problem with the states not working with v3.4, neither on a save from a running game (where the new version scripts replaced a previous version) nor on a fresh game. This is a log from the Warmaiden's on a fresh game:

 

WarmaidensRackLog_v3.4.log.7z

 

All starting items load within the same second as the racks, and the trigger is in the right state as it skips the OnLeave events as expected.

 

Second, the rack in front of Alvor's shop is particular in that all items are placed via dummies which are entirely engine-controlled (there aren't any scripts running on them). That is, it is the engine that selects the item from the leveled list and places it in the game world (side note, as this might be interesting: although the dummies have a dummy keyword, checking the linked reference on the activators for that keyword always returns false), i.e. they aren't physically there on cell attach, unlike spre-placed pecific items. When the workload on the engine is particularly high, it is not surprising therefore, that those weapons won't load. Though again: this is a mod conflict as the vanilla game easily handles this.

 

 

There's also the problem that 3D may still be loaded after moving from one cell to another, or an exterior to an interior or vice versa.

 

When its 3D is still loaded, it's still in the cell, and that's what we actually want to know. There's nothing wrong with that.

 

 

 

I could have taken a sword off the rack in an old version and put it inside. And reloaded the saved game with the new version and walked outside. It will probably still be is3DLoaded().

 

 Irrelevant, since the trigger detects it as taken off the rack when you grab it.

Link to comment
Share on other sites

Excuse me, but some (oddly, not all) the pre-placed weapons on the wooden weapon racks in Castle Volkihar are falling off for me. Is there something wrong with how they're set up?

Link to comment
Share on other sites

Excuse me, but some (oddly, not all) the pre-placed weapons on the wooden weapon racks in Castle Volkihar are falling off for me. Is there something wrong with how they're set up?

 

Which version are you running ? If it is the latest beta, please grab the v3.4 debugger version at the link below, drop the content in your Skyrim\Data folder and try to repeat the bug. Then show me the log.

 

It is possible that this is a placement problem. I checked Fort Dawnguard for placement errors, but completely forgot to do Castle Volkihar (probably because I didn't play on the vampire side yet). Fort Dawnguard had in fact three borked activators (due to inappropriate links). Nonetheless, I also would like to see the log, just to be sure.

 

Link:

http://www.afkmods.com/index.php?/files/download/843-extended-racks/

 

EDIT:

Also possible: v3.4 was not yet in the latest beta update, but the log will tell this.

Link to comment
Share on other sites

3.4 is in the latest beta, so that shouldn't be an issue. Castle was fine when I checked it.

Link to comment
Share on other sites

Here's my proof-of-concept for the placement of scripted items on racks. I've tested it with Silver Swords, Red Eagle's Fury, Wuuthrad, Ebony Blade, Ghostblade, Keening and Volendrung and in all of my tests, the items go on the rack with no log errors, and stay on the rack after leaving the cell and returning, even after running 'pcb'.
 
Two issues had to be worked around to get these items working. The first was the by now well-known ObjectReference pointer bug on scripted items, which causes DropObject() to return a broken pointer that cannot be used to move the item to the rack or disable its physics to keep it there. The fix for this is to just ignore what DropObject() returns and instead use a ReferenceAlias on the player to catch the pointer received by OnItemRemoved(), which is triggered by the DropObject() call. In my experience, that pointer is always usable at least until the item is picked up again, but at that point the rack doesn't need it any more anyway.
 
The second issue was that, although Wuuthrad and Ghostblade would stay put even after 'pcb' to force the cell to reload, the other test items would still fall down and leave their activator disabled. I was stuck on this until I re-read this comment:
 

... for some reason (well, it almost certainly has to do with the fact that the starting item is persistent in the same cell), its havok setting does not last beyond cell detach, even when it is modified by a script. Mounted items appear as mounted only because they are havok-disabled; when you turn havok on again (and this happens with the starting item when the cell attaches for the next time) they will fall down. Therefore, the starting item must be handled on every cell attach.

 
It turns out that this behavior is not limited to items whose original persistent references are in the same cell as the rack. The engine seems to re-enable physics on all items which have persistent cell-placed references, and that's what caused Ebony Blade, Keening, etc to fall down. Wuuthrad avoided this problem because it has no original cell-placed reference, and Ghostblade stayed put because its cell-placed reference has the "Don't havok settle" flag set, which seems to prevent the engine from re-enabling physics on cell load (and incidentally causes another oddity: if you drop Ghostblade on the floor, leave and 'pcb', then when you return you can't "grab" it and move it around until you pick it up and drop it again).
 
Anyway, all that was needed to fix this second issue was an extra PlaceItem() in InitActivator() for player-placed items, just like what was already done for starting items.
 
I based my alterations on the USKP v2.0.0 beta. I tried also diffing against DayDreamer's "v4" scripts, but those files are so drastically different that I gave up wading through the comparison, so I'll let you guys work out whose scripts to use going forward. Instead, here's a summary of my changes:
  • In the trigger script, my only change is that the ObjectReference pointer received by OnTriggerLeave may well be broken if the item was scripted, so it's best not to try to call any methods on it. That means UpdateActivatorState() can't use GetBaseObject() or HasKeyword() to filter out irrelevant events or check for a shield leaving a shield-only rack, which in turn means the logic will run for additional spurious non-weapon items that leave the trigger volume, and the shield activator can't reliably initialize until TOC=0 or an item is placed and retrieved. As far as I can tell those are basically just optimizations anyway and everything still works without them, just maybe a little slower.
  • In the activator script, there are two changes. One is for InitActivator() to call PlaceItem() for the player-placed item as well as the starting item, in order to keep persistent references physics-disabled on reload. The second change is the method of obtaining the ObjectReference pointer in HandlePlayerItem(), as mentioned above.
  • The main addition is USKPWeaponRackPlayerMonitorQuest and its PlayerRef alias script. When called by the rack activator script, this starts watching for the player to drop a specific form (the one being force-dropped for rack placement), and stores away the ObjectReference received by the OnItemRemoved() event for later retrieval by the activator script. In theory this monitor will wait up to 1-2s for the event to be received, but in practice I always see it get what it needs within 1 or 2 frame draws.
So that's it. To try it out, install the USKP v2.0.0 beta, and then this demo package. Load order doesn't matter since there are no .esp overrides and my loose scripts will override the beta's BSA anyway.
 
EDIT: Forgot the alias script from the attached v1 download; fixed for v2 download. Must have had too much scotch.

Taledens Weapon Rack Item Fix v2.7z

Edited by taleden
Link to comment
Share on other sites

Why was Volendrung in the test? It's been happily sitting on a rack in Honeyside now for ages and has never demonstrated any desire to fall off, no matter how many times I've visited the place.

Link to comment
Share on other sites

Why was Volendrung in the test? It's been happily sitting on a rack in Honeyside now for ages and has never demonstrated any desire to fall off, no matter how many times I've visited the place.

 

In my main save using USKP 1.3.3c it kept falling off my racks, so I'm surprised it works for you. Are you sure you picked up the particular copy pre-placed in the antlers in the orc stronghold? Any chance the quest bugged out on your or something and you gave yourself a copy in the console, which would therefore not have a persistent reference causing physics to re-enable all the time?

 

I guess another possibility is that the racks it kept falling out of were in a mod home called Rayek's End. Could be there's something funky about the racks in that mod that makes Volendeung fall. Or maybe it was the type of racks I was putting it on, but I remember it falling from both the densely-packed vertical wooden racks and also the single-weapon racks. Don't think I ever tried it in a CoA rack.

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...