Jump to content

Overhauling the weapon rack scripts


Sclerocephalus

Recommended Posts

No idea, I'd have to go take the thing and see what its reference number is. I doubt very much I'd have consoled a copy. I acquired it back in 2011 and it's been on the middle rack next to the enchanter's table ever since. It's survived every change to the rack scripts from the official patches and all of the USKP updates. There is no script attached to the object in the CK though, or on the base weapon record.

 

Edit: Ref# 0002E526

Link to comment
Share on other sites

No idea, I'd have to go take the thing and see what its reference number is. I doubt very much I'd have consoled a copy. I acquired it back in 2011 and it's been on the middle rack next to the enchanter's table ever since. It's survived every change to the rack scripts from the official patches and all of the USKP updates. There is no script attached to the object in the CK though, or on the base weapon record.

 

Strange. I wonder if maybe back in 2011 the cell-placed reference in the orc stronghold had "Don't havok settle" enabled, and that has persisted on the reference in your save? What happens if you take it off, drop it on the ground, leave, 'pcb', return and try to "grab" and wave it around without actually picking it up?

Link to comment
Share on other sites

Heh, I actually did that when I went to get the ref ID. Took it off, dropped it, left, pcb, returned and before I was able to try grabbing, Serana kicked it across the room :P So the havok on it is working fine. The placed reference has never been edited by official or unofficial patches either.

Link to comment
Share on other sites

Given the code and ideas from Talenden, I'm going to checkpoint what I was doing and call it 4.2. Then I'll try to integrate his into mine. My 4.x scripts keep getting farther and farther from 3.4. The version to version diffs are OK, but the overall is getting hairier. (It's 5:30 am local, so I'll need some sleep to be able to write code.)

Where he stuck the extra PlaceItem() for player-placed items is basically also redoing the starting items too. So I'll try to do something more efficient. :)

OTOH, he also made the normal rack setting considerably less efficient by entirely eliminating Sclero's outer tests. So that will take some rethinking, too.

But working code is more important than efficient code! Wonderful job!

WeaponRack-4-2d.7z

Link to comment
Share on other sites

On first glance, Talenden eliminated a bit at the end of the main test:

        ;    If (LeavingItemBase As Weapon) || LeavingItem.HasKeyword (ArmorShield)

                TOC = GetTriggerObjectCount()

                If  (LeavingItem == MountedItem) || (PlacedItemInit && (MountedItem == None)) || (TOC == 0) ; || (HasNode ("ShieldPivot01") && LeavingItem.HasKeyword (ArmorShield))

Sclerocephalus, how critical is that "(HasNode ("ShieldPivot01") && LeavingItem.HasKeyword (ArmorShield))"?

 

That helps recover stuck shields? It just seems to be saying "even if it isn't recorded as mounted, if it's big and it could have been here, assume it was here." Do we really need that?

Link to comment
Share on other sites

It's true that some of the early bail-outs from handling OnTriggerLeave can't be used if there might be scripted items nearby, because those will spew errors and always appear to return None/0/False to whatever method you tried to call anyway, so a bit more code runs per event than before. But it didn't seem like a huge efficiency loss to me, since that code block already only runs if the trigger's linked activator is disabled (so it only affects filled racks), and the spurious events will still immediately fail the LeavingItem==MountedItem check anyway. So the only real cost to losing the weapon/armor pre-test is having to execute GetTriggerObjectCount(). Is there some reason to believe that function is especially slow?

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.

 

Activators are all fine too. Though, the Castle Volkihar racks are stuffed with dummies, and when he says that only some weapons fell off, it might well be for that reason. Problem is that there's no way to control a dummy. The script doesn't even know that a dummy is placed, because all checks are diverted internally to the item type specified in the leveled list on that dummy. If you check the reference, you get an FF... for the leveled item and not that of the dummy.

 

On the other hand, for some reason, dummies must be placed overlapping with the trigger for the process to work properly (unlike specific objects which can be placed at any distance from the rack). That's the next thing to check (it was too late yesterday to have a look).

Link to comment
Share on other sites

It's true that some of the early bail-outs from handling OnTriggerLeave can't be used if there might be scripted items nearby, because those will spew errors and always appear to return None/0/False to whatever method you tried to call anyway, so a bit more code runs per event than before. But it didn't seem like a huge efficiency loss to me, since that code block already only runs if the trigger's linked activator is disabled (so it only affects filled racks), and the spurious events will still immediately fail the LeavingItem==MountedItem check anyway. So the only real cost to losing the weapon/armor pre-test is having to execute GetTriggerObjectCount(). Is there some reason to believe that function is especially slow?

 

The trigger object count is unreliable as it can have any value (well, it's still < 5) even when the rack is empty (check the logs; all related traces will print its value). In fact, the case that TOC = 0 on an empty rack does only occur with display cases and single-slot wooden racks. That's why most of the extra checks are needed at all. I can make it work, as already shown, when I modify the meshes, but this will take some time. I've chosen the wooden rack for the proof of concept for a good reason: this rack has a convex vertices shape trigger which can be manually edited within a few minutes. The other racks with problem triggers have compressed mesh shape triggers, and these are considerably more difficult to deal with.

 

Thus, until that's done, we should leave the checks as they are. They have been running this way for months now and we know that they work. Anything else will have to be tested. When I have made sure that the TOC is reliable, I will take them out. Promised.

Link to comment
Share on other sites

Where he stuck the extra PlaceItem() for player-placed items is basically also redoing the starting items too. So I'll try to do something more efficient. :)

 

Not having had the time yet to have a look at the scripts, I'm pretty sure that there's a condition check which prevents PlaceItem from being called when PlayersDroppedWeapon is none. Add another check here to make sure that the player is in an interior cell, and skip PlaceItem() if he's not. This should make it efficient enough.

Link to comment
Share on other sites

The trigger object count is unreliable as it can have any value (well, it's still < 5) even when the rack is empty (check the logs; all related traces will print its value). In fact, the case that TOC = 0 on an empty rack does only occur with display cases and single-slot wooden racks. That's why most of the extra checks are needed at all. I can make it work, as already shown, when I modify the meshes, but this will take some time. I've chosen the wooden rack for the proof of concept for a good reason: this rack has a convex vertices shape trigger which can be manually edited within a few minutes. The other racks with problem triggers have compressed mesh shape triggers, and these are considerably more difficult to deal with.

 

Thus, until that's done, we should leave the checks as they are. They have been running this way for months now and we know that they work. Anything else will have to be tested. When I have made sure that the TOC is reliable, I will take them out. Promised.

 

Yes, all these changes will need more testing and probably more tweaking to get them working right, but of course the benefit is that all items will then be usable on racks.

 

I should probably also point out that the existing "bad item test" in the v2.0.0 beta is much too strict. When I first installed the beta and tested a bit before changing the scripts, it wouldn't even let me pick a pre-placed iron sword off a rack and put it right back, probably because that pre-placed sword has a persistent reference which tricks your container test into thinking it's a scripted item. So from then on I was forbidden from putting iron swords on any rack, which is not great.

Link to comment
Share on other sites

Not having had the time yet to have a look at the scripts, I'm pretty sure that there's a condition check which prevents PlaceItem from being called when PlayersDroppedWeapon is none.

Not the problem. The problem is the starting items have been placed, so PlayersDroppedWeapon != none, so it will run again. I'm looking at the conditions now.

Add another check here to make sure that the player is in an interior cell, and skip PlaceItem() if he's not. This should make it efficient enough.

Woah! Maybe there are no player-owned exterior racks now, but that would make it so there could be no mods with player-owned exterior racks. Heck, that would kill off certain mods that allow farm implements.... ;)

So from then on I was forbidden from putting iron swords on any rack, which is not great.

An understatement. :( We really need to fix that!

There's also this test:

ElseIf (iTOC == 0)
	EnableNoWait()
	PlayersDroppedWeapon = None
	PlacedItemInit = True
	Trace (Self + "ActivatorSetup() enabled; PlacedItemInit = True; TOC = Zero")
Else
	DisableNoWait()
	(TriggerMarker as WeaponRackTriggerSCRIPT).ActivatorDone ("ActivatorSetup")
	Trace (Self + "ActivatorSetup() disabled; PlacedItemInit = False; TOC = " + iTOC)
EndIf
That locks up any rack with a big item next to it. That is, a shield will prevent putting anything there. Even just taking the shield away won't work.

You have to take the shield away, leave the cell, and come back. We need to document this....

The new smaller triggers will help fix this test!

Link to comment
Share on other sites

Strange. I wonder if maybe back in 2011 the cell-placed reference in the orc stronghold had "Don't havok settle" enabled, and that has persisted on the reference in your save? What happens if you take it off, drop it on the ground, leave, 'pcb', return and try to "grab" and wave it around without actually picking it up?

 

I recently made tests with it when I had to make sure that my detection method blocks it when it has to, but it was left through. It also performed well on the racks in lakeview manor. That Volendrung version was acquired in a relatively recent playthrough earlier this year.

Link to comment
Share on other sites

Saw your picture of the new trigger: http://www.afkmods.com/index.php?/gallery/image/1544-wooden-rack-triggers/

Are you sure that isn't too small? I can see that dummy weapon placement might be tricky.... This might mean having to go through every placed item and adjust. Couldn't it be a bit larger?

EDIT: My opinion, not based on experiment, would be at least as wide as the visual wooden hanger, and at least as tall to cover all the white nodes -- which I assume are mount points. We'll all still have to check every rack, but a lot fewer adjustments.

Link to comment
Share on other sites

Woah! Maybe there are no player-owned exterior racks now, but that would make it so there could be no mods with player-owned exterior racks. Heck, that would kill off certain mods that allow farm implements.... ;)

 

Sorry, but you didn't get the point. Farm implements (they have been implemented in my own mod ;) ) do not need to have their placement renewed. This only is important for starting items and a few unique items that only the player can place on a rack. There are good reasons why a player can't use any rack in an exterior cell (and also not in most interiors that are not player homes):

 

(1) All cells, except for player homes (and a few dungeons), eventually reset, and all player items would be lost at once, with no chance to ever get them back. I don't think that a mod that allows for exterior racks to be player-activated and does not exclude specific items from being placed at the same time is a good addition, but even less so it deserves to get supported by the USKP.

(2) On the technical side, non-player home racks, while they are running the same scripts, are using different base objects for both triggers and activators, and these are not functional.

Link to comment
Share on other sites

EDIT: My opinion, not based on experiment, would be at least as wide as the visual wooden hanger, and at least as tall to cover all the white nodes -- which I assume are mount points. We'll all still have to check every rack, but a lot fewer adjustments.

 

Those white points are the placement nodes, that's right. Though, they're not mounting points. Many items, when placed, do not even touch the nodes!

Actually, the trigger is still too wide and it has to be placed a little to the left of the center, in order to make sure that it will catch all bows.

Link to comment
Share on other sites

Not the problem. The problem is the starting items have been placed, so PlayersDroppedWeapon != none, so it will run again. I'm looking at the conditions now.

 

You only have to check against the reference of the starting item. This is permanently linked to the activator. The links are never removed.

 

 

 

There's also this test:

 

ElseIf (iTOC == 0)

    EnableNoWait()

    PlayersDroppedWeapon = None

    PlacedItemInit = True

    Trace (Self + "ActivatorSetup() enabled; PlacedItemInit = True; TOC = Zero")

Else

    DisableNoWait()

    (TriggerMarker as WeaponRackTriggerSCRIPT).ActivatorDone ("ActivatorSetup")

    Trace (Self + "ActivatorSetup() disabled; PlacedItemInit = False; TOC = " + iTOC)

EndIf

 

That locks up any rack with a big item next to it.

 

This doesn't lock anything up. Those checks make sure that everything that can be safely unlocked, is unlocked.

 

Those tests will run only when PlacedItemInit is false. This is the only the case after starting a new game or when USKP is installed for the first time on a running game. On a new game, the check for TOC = 0, effectively unlocks all racks without a starting item at once, except for CoA racks (but see below). This is because all pre-placed items are low-level items, and low-level items don't have the size to trigger an adjacent rack, except for crossbows.

 

Handling the few cases with pre-placed crossbows is simple: TOC isn't zero, so the activator is disabled - but the trigger is returned to "WaitingForReference" state! In other words, it will be able now to leave an unrelated event through: it will detect when the crossbow is taken from the adjacent rack and subsequently turns its activator on because TOC = 0.

 

With these checks, I get all racks to work very quickly on a fresh game (needless to say that I had a look at every vanilla rack with pre-placed weapons).

To understand the other case of installing USKP on a running game, you really need to have the logics of the vanilla scripts in mind. There are situations where you can't really do anything and leave the activator turned off. Nonetheless, even in this case, these checks will unlock many racks rather quickly.

 

Again, make your own tests. Go into the player homes and play around with the racks (you'll need to to this anyway to test the script modifications). See whether they really stay inactive after grabbing a weapon. There are very few cases where this happens, but when you investigate them in detail, you'll also notice that you can't do much about it.

 

That is, a shield will prevent putting anything there. Even just taking the shield away won't work.

You have to take the shield away, leave the cell, and come back. We need to document this....

 

No, no, no ...

 

This is why you must not remove the "(HasNode ("ShieldPivot01") && LeavingItem.HasKeyword (ArmorShield))" check from the trigger script. Those checks are not there to recover items; they will recover the racks!

 

"HasNode ("ShieldPivot01")" is a waterproof check for a shield rack.

Link to comment
Share on other sites

Sorry, but you didn't get the point. Farm implements (they have been implemented in my own mod ;) ) do not need to have their placement renewed.

You pointed me at your mod the other day, that's why I winked.

I did get the point. I'm opining that you are wrong. We should be able to allow pre-placed starting farm implements. And we should allow the player to place them on his own racks.

This only is important for starting items and a few unique items that only the player can place on a rack. There are good reasons why a player can't use any rack in an exterior cell (and also not in most interiors that are not player homes):

OK, that's our target for USKP. But should not necessarily be true for everything. See Helgen Reborn. That's being rebuilt in an area where the player will "own" everything, interior and exterior. Likewise, there are player home mods everywhere, and many of them allow exterior remodeling.

(1) All cells, except for player homes (and a few dungeons), eventually reset, and all player items would be lost at once, with no chance to ever get them back. I don't think that a mod that allows for exterior racks to be player-activated and does not exclude specific items from being placed at the same time is a good addition, but even less so it deserves to get supported by the USKP.

No, USKP has to support everything. Helgen exterior is no-reset. Lots of other exteriors are no-reset. It's not just dungeons.

(2) On the technical side, non-player home racks, while they are running the same scripts, are using different base objects for both triggers and activators, and these are not functional.

I noticed that they exist, but had no idea they were "not functional." In fact, I'm pretty sure those are exactly where we are testing the starting item placement.

What you meant is not player activated, because the ownership is set to somebody else.

However, while I'm thinking about it, I think there's a bug in the StartingItemHasBeenGrabbed logic. What about after Resets?

Those white points are the placement nodes, that's right. Though, they're not mounting points. Many items, when placed, do not even touch the nodes!

Actually, the trigger is still too wide and it has to be placed a little to the left of the center, in order to make sure that it will catch all bows.

On this I bow to your expertise. I don't even know how to make them. Just thinking about making it easy to hit the target.
Link to comment
Share on other sites

I should probably also point out that the existing "bad item test" in the v2.0.0 beta is much too strict. When I first installed the beta and tested a bit before changing the scripts, it wouldn't even let me pick a pre-placed iron sword off a rack and put it right back, probably because that pre-placed sword has a persistent reference which tricks your container test into thinking it's a scripted item. So from then on I was forbidden from putting iron swords on any rack, which is not great.

 

Yes, I had the same thing happen with a crossbow that was pre-placed in Fort Dawnguard.

 

Though, I have an exception list implemented to handle such cases. This only has to be filled with the base objects of the pre-placed items. There aren't that many (Beth has been using the same few low-level items all over Tamriel) and none of them is otherwise a problem item.

Link to comment
Share on other sites

This is why you must not remove the "(HasNode ("ShieldPivot01") && LeavingItem.HasKeyword (ArmorShield))" check from the trigger script. Those checks are not there to recover items; they will recover the racks!

OK, I don't understand the special case logic, but I'll figure out how to make that work. I think a None test first will sort it.

However, the "(foo as Weapon)" has to go. I see no way to avoid a papyrus spam on the special items. It was only a quick "efficiency" check before calling the functions anyway.

Link to comment
Share on other sites

Though, I have an exception list implemented to handle such cases. This only has to be filled with the base objects of the pre-placed items. There aren't that many (Beth has been using the same few low-level items all over Tamriel) and none of them is otherwise a problem item.

Shall we re-make that to be a form list of form lists? All valid pre-placed items are probably already in form lists for the dummy items.
Link to comment
Share on other sites

On the other hand, for some reason, dummies must be placed overlapping with the trigger for the process to work properly (unlike specific objects which can be placed at any distance from the rack). That's the next thing to check (it was too late yesterday to have a look).

I didn't even think of dummies. I'll take a look and see where they're positioned and move them in closer if possible. Volkihar has quite a few racks in it.

Link to comment
Share on other sites

I did get the point. I'm opining that you are wrong. We should be able to allow pre-placed starting farm implements. And we should allow the player to place them on his own racks.

 

To get the farm implements mounted, I had to add another three entirely new nodes to the racks. The existing nodes could not be used, as they would make them end up in bizarre positions. The USKP changes were either restricted to existing nodes, or new nodes for items that were explicitely intended to be placed but would end up on the existing nodes either clipping or in inappropriate positions. Thus, the farm items are clearly outside of the USKP's scope.

 

 

OK, that's our target for USKP. But should not necessarily be true for everything. See Helgen Reborn. That's being rebuilt in an area where the player will "own" everything, interior and exterior. Likewise, there are player home mods everywhere, and many of them allow exterior remodeling.

 

Mods are allowed to do what they want, but should use their own script modifications. The USKP's task is to make sure that the vanilla content is working. Everything else is up to the modders.

 

No, USKP has to support everything. Helgen exterior is no-reset. Lots of other exteriors are no-reset. It's not just dungeons.

 

I'll leave it to Arthmoor to comment that.

 

 

I noticed that they exist, but had no idea they were "not functional." In fact, I'm pretty sure those are exactly where we are testing the starting item placement.

What you meant is not player activated, because the ownership is set to somebody else.

 

It's not an ownership problem. They are not activatable. You can grab every item, even steal them, but you can't place items on them. It has nothing to do with the ownership flag.

 

 

However, while I'm thinking about it, I think there's a bug in the StartingItemHasBeenGrabbed logic. What about after Resets?

 

After a reset, "StartingItemHasBeenGrabbed" must be false again. That's because the dummies (Beth has been using mostly dummies in exteriors) will draw an entirely new item from the leveled list when the cell resets. Even the link is renewed! The engine will set it to the new item.

 

Link to comment
Share on other sites

Shall we re-make that to be a form list of form lists? All valid pre-placed items are probably already in form lists for the dummy items.

 

No. A simple form list is sufficient. The dummies are using leveled lists, not formlists (otherwise the dummy concept would be pointless). Anything distributed through leveled lists has never been a problem. Lists of lists are also not good for another reason: The HasForm() check will not look into nested lists:

 

http://www.creationkit.com/HasForm_-_FormList

Link to comment
Share on other sites

This is why you must not remove the "(HasNode ("ShieldPivot01") && LeavingItem.HasKeyword (ArmorShield))" check from the trigger script. Those checks are not there to recover items; they will recover the racks!

 

"HasNode ("ShieldPivot01")" is a waterproof check for a shield rack.

 

The HasNode() isn't the problem, the problem is that if scripted items are allowed to be placed using my workarounds, then picking up a scripted item causes OnTriggerLeave() to fire with a broken objref pointer. That in turn means LeavingItem.HasKeyword() will throw script errors and evaluate like False, even if the scripted item being picked up really is a shield. If that test is really super important, then there may be another workaround to get a usable objref pointer to use in that function, but the one you get from OnTriggerLeave() cannot be safely used.

Link to comment
Share on other sites

The HasNode() isn't the problem, the problem is that if scripted items are allowed to be placed using my workarounds, then picking up a scripted item causes OnTriggerLeave() to fire with a broken objref pointer. That in turn means LeavingItem.HasKeyword() will throw script errors and evaluate like False, even if the scripted item being picked up really is a shield. If that test is really super important, then there may be another workaround to get a usable objref pointer to use in that function, but the one you get from OnTriggerLeave() cannot be safely used.

 

OK. Now I got it.

 

This wouldn't probably have been a misundertsanding if I had had any time yet to look at the scripts, but my most urgent problem at the moment is that there are some meshes I have to get done for Arthmoor as soon as possible. Therefore, I would like to postpone the discussion until later this day, or tomorrow.

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