Jump to content

[LE] Quick Questions, Quick Answers


Recommended Posts

 

 

The most compatible way of handling leveled lists is to edit them directly not add things via script. We learned that the hard way back in the Morrowind days when Bethesda first created the functions to manipulate leveled lists.

 

Editing leveled lists via script is a huge problem if any mod (or the game itself) ever calls Revert on a list. Any items added by AddForm will be removed and there are no functions that let you check if a particular item is already in a leveled list so you have no way to know if some other mod has removed your item. You can actually add the same item more than once, so if you're not careful the list could end up with multiple copies of your item in the list too. It's also almost impossible for people to detect potential problems with their leveled lists if entries are being added during the running game.

 

Just edit the leveled list directly and skip the fancy scripting.

 

You can actually pull items out of a leveled list with SKSE these days, with GetNthForm, GetNthCount, and GetNthLevel. I've abused these to get around levelled lists only allowing 255 distinct forms.

I've fiddle a little with the levelled lists so take it for what it is, but why make it harder than it is and I don't understand the reason why would anyone do that.

 

TBH, I am glad I don't have to use a script every time I want to edit the levelled list(s) and if I had to do then I would probably never touch the levelled lists.

 

 

The idea is that if you're doing something like adding forms to a vanilla levelled list that other mods might want to edit, there's basically two choices:

 

1. You directly edit it. This will cause mod conflicts if anybody else took the same approach, with last-loaded winning. A patch *.esp is required to make them work together, and the number of combinations can explode really quickly if it's a commonly-edited list, such as for example the innkeeper vendor list.

2. You can build a leveled list of your own, as per normal, and then use a script to insert that into the levelled list you wish to edit. This approach allows multiple mods to cooperate, in theory, though as cdcooley points out if a revert gets called your changes will be wiped, and checking that a revert has not been called, while possible with SKSE, is resource-intensive.

 

I have worked out a solution specifically for adding stuff to vendor inventories, via some quest shenanigans, that doesn't involve touching vanilla lists at all, but it works only for that one specific use case; you can't use it to e.g. insert new armour into an enemy's gear list.

Edited by foamyesque
Link to comment
Share on other sites

 

 

 

The most compatible way of handling leveled lists is to edit them directly not add things via script. We learned that the hard way back in the Morrowind days when Bethesda first created the functions to manipulate leveled lists.

 

Editing leveled lists via script is a huge problem if any mod (or the game itself) ever calls Revert on a list. Any items added by AddForm will be removed and there are no functions that let you check if a particular item is already in a leveled list so you have no way to know if some other mod has removed your item. You can actually add the same item more than once, so if you're not careful the list could end up with multiple copies of your item in the list too. It's also almost impossible for people to detect potential problems with their leveled lists if entries are being added during the running game.

 

Just edit the leveled list directly and skip the fancy scripting.

 

You can actually pull items out of a leveled list with SKSE these days, with GetNthForm, GetNthCount, and GetNthLevel. I've abused these to get around levelled lists only allowing 255 distinct forms.

I've fiddle a little with the levelled lists so take it for what it is, but why make it harder than it is and I don't understand the reason why would anyone do that.

 

TBH, I am glad I don't have to use a script every time I want to edit the levelled list(s) and if I had to do then I would probably never touch the levelled lists.

 

 

The idea is that if you're doing something like adding forms to a vanilla levelled list that other mods might want to edit, there's basically two choices:

 

1. You directly edit it. This will cause mod conflicts if anybody else took the same approach, with last-loaded winning. A patch *.esp is required to make them work together, and the number of combinations can explode really quickly if it's a commonly-edited list, such as for example the innkeeper vendor list.

2. You can build a leveled list of your own, as per normal, and then use a script to insert that into the levelled list you wish to edit. This approach allows multiple mods to cooperate, in theory, though as cdcooley points out if a revert gets called your changes will be wiped, and checking that a revert has not been called, while possible with SKSE, is resource-intensive.

 

I have worked out a solution specifically for adding stuff to vendor inventories, via some quest shenanigans, that doesn't involve touching vanilla lists at all, but it works only for that one specific use case; you can't use it to e.g. insert new armour into an enemy's gear list.

 

 

Would you mind sharing that technique, foamyesque? I have some items in leveled lists that I'd like to add to specific vendors but adding a second vendor chests does not seem to work. All the tutorials I can find on adding things to vendors are either for new vendors (I'd rather not have to make new vendors) or they just add the stuff directly to the vendor's chest, which is undesirable for the reasons you stated. And, as I said, I've had no luck creating a second vendor chest (and associated faction) for the vendors; the vendors seem to just choose one of the two chests but not both. And I'd rather not add my items to other leveled lists since I only want them to be sold by specific vendors. So any help/guidance would be appreciated!

Link to comment
Share on other sites

 

 

 

 

The most compatible way of handling leveled lists is to edit them directly not add things via script. We learned that the hard way back in the Morrowind days when Bethesda first created the functions to manipulate leveled lists.

 

Editing leveled lists via script is a huge problem if any mod (or the game itself) ever calls Revert on a list. Any items added by AddForm will be removed and there are no functions that let you check if a particular item is already in a leveled list so you have no way to know if some other mod has removed your item. You can actually add the same item more than once, so if you're not careful the list could end up with multiple copies of your item in the list too. It's also almost impossible for people to detect potential problems with their leveled lists if entries are being added during the running game.

 

Just edit the leveled list directly and skip the fancy scripting.

 

You can actually pull items out of a leveled list with SKSE these days, with GetNthForm, GetNthCount, and GetNthLevel. I've abused these to get around levelled lists only allowing 255 distinct forms.

I've fiddle a little with the levelled lists so take it for what it is, but why make it harder than it is and I don't understand the reason why would anyone do that.

 

TBH, I am glad I don't have to use a script every time I want to edit the levelled list(s) and if I had to do then I would probably never touch the levelled lists.

 

 

The idea is that if you're doing something like adding forms to a vanilla levelled list that other mods might want to edit, there's basically two choices:

 

1. You directly edit it. This will cause mod conflicts if anybody else took the same approach, with last-loaded winning. A patch *.esp is required to make them work together, and the number of combinations can explode really quickly if it's a commonly-edited list, such as for example the innkeeper vendor list.

2. You can build a leveled list of your own, as per normal, and then use a script to insert that into the levelled list you wish to edit. This approach allows multiple mods to cooperate, in theory, though as cdcooley points out if a revert gets called your changes will be wiped, and checking that a revert has not been called, while possible with SKSE, is resource-intensive.

 

I have worked out a solution specifically for adding stuff to vendor inventories, via some quest shenanigans, that doesn't involve touching vanilla lists at all, but it works only for that one specific use case; you can't use it to e.g. insert new armour into an enemy's gear list.

 

 

Would you mind sharing that technique, foamyesque? I have some items in leveled lists that I'd like to add to specific vendors but adding a second vendor chests does not seem to work. All the tutorials I can find on adding things to vendors are either for new vendors (I'd rather not have to make new vendors) or they just add the stuff directly to the vendor's chest, which is undesirable for the reasons you stated. And, as I said, I've had no luck creating a second vendor chest (and associated faction) for the vendors; the vendors seem to just choose one of the two chests but not both. And I'd rather not add my items to other leveled lists since I only want them to be sold by specific vendors. So any help/guidance would be appreciated!

 

 

Not at all. It does involve adding them to a chest, but you don't do it by editing the chest nor the leveled lists within it.

 

Instead, you use a quest reference alias. Reference aliases have an Inventory tab, the contents of which will be added to the aliases' inventory (provided it has one) and will persist through refreshes, including -- crucially -- the ones triggered by entering into a dialogue with a merchant. By itself, this only allows for the inventory to be added once; if a player purchases something (or it's otherwise removed, say by a specific script) it won't reset.

 

However, the stuff in the inventory tab is added every time an alias is filled. You can therefore script a clear/forcerefto pair on a timer (a merchant's default is 48 hours) to re-add your items. This will not remove any old items added by this process. You can leave clearing that up to the game, as the next game-driven refresh should clear it, but because the game refreshes and your refreshes may not be in-sync for various reasons I build a list of what was added and then, on my script-driven refresh, remove them.

 

Since all the work is being done by the quest aliases it should work for basically any merchant regardless of other mods. Ones that modify what merchant chest is assigned to which vendor faction can be a bit tricky, but there are ways around that.

 

I came up with the technique to allow me to make working display mannequins for various vendors. Apparently this forum doesn't like Steam screenshots though :v

Link to comment
Share on other sites

OK, great. I think I've mostly got it. I made a quest, added my reference alias with specific reference (the merchant's vanilla chest), and added the desired inventory records to the inventory section of the reference alias. The items appear to be initially added to the merchant chest since both vendors are able to sell the items. This is a great start. Unfortunately, I'm having some trouble getting the items to respawn in the chest.

 

The part I'm a little lost on is the script to refill the alias. I just really am not familiar enough with papyrus. Would that be as simple as the script I put below?

 

 

Scriptname MyAliasScript extends ReferenceAlias

 

ReferenceAlias Property MyAlias Auto

ObjectReference Property SpecificVendorChest Auto

 

Event OnPlayerLoadGame()

RegisterForUpdate(1.0)

EndEvent

 

Event OnUpdate()

Utility.WaitGameTime(48)

MyAlias.ForceRefTo(SpecificVendorChest)

EndEvent

 

I have a few more related questions. Should the script be attached directly to the ReferenceAlais or to the quest itself? I assume the ReferenceAlias, but I'm kind of guessing here. One question I had was about the timing of this updating versus the timing of the "vanilla" refreshing of the inventory. If it updates 3 hours before the "vanilla" reset, would that mean my items would only be available for those 3 hours because the "vanilla" reset would clean them out? If that is the case, is there a way to synchronize the refreshes? Or am I missing something? Again, your help is much appreciated!

Edited by candlepin
Link to comment
Share on other sites

If you want to give a merchant a second chest you need to also create a faction to go with it. The link between merchant and chest is through a merchant faction. You can then add the new faction to the merchant via script or an alias.

 

This was the first thing that I tried. But when I went to buy from the merchant, they would only sell the contents of one of the chests, not both. In the case of Elgrim and his wife, they ended up having completely different inventories to sell since they were linked to different chests even though they were each in both factions.

Link to comment
Share on other sites

OK, great. I think I've mostly got it. I made a quest, added my reference alias with specific reference (the merchant's vanilla chest), and added the desired inventory records to the inventory section of the reference alias. The items appear to be initially added to the merchant chest since both vendors are able to sell the items. This is a great start. Unfortunately, I'm having some trouble getting the items to respawn in the chest.

 

The part I'm a little lost on is the script to refill the alias. I just really am not familiar enough with papyrus. Would that be as simple as the script I put below?

 

 

Scriptname MyAliasScript extends ReferenceAlias

 

ReferenceAlias Property MyAlias Auto

ObjectReference Property SpecificVendorChest Auto

 

Event OnPlayerLoadGame()

RegisterForUpdate(1.0)

EndEvent

 

Event OnUpdate()

Utility.WaitGameTime(48)

MyAlias.ForceRefTo(SpecificVendorChest)

EndEvent

 

I have a few more related questions. Should the script be attached directly to the ReferenceAlais or to the quest itself? I assume the ReferenceAlias, but I'm kind of guessing here. One question I had was about the timing of this updating versus the timing of the "vanilla" refreshing of the inventory. If it updates 3 hours before the "vanilla" reset, would that mean my items would only be available for those 3 hours because the "vanilla" reset would clean them out? If that is the case, is there a way to synchronize the refreshes? Or am I missing something? Again, your help is much appreciated!

Just pointing out that said script can be potentially bad if things go wrong for unforeseen reasons.. Never use RegisterForUpdate - best practice is use all the RegisterForSinglexxx ones, and going by your script, you want an update to actually occur after 48 hours.

 

 

ReferenceAlias property MyAlias auto
 
Event OnPlayerLoadGame()
 
    ; Safety net: Will fire the event once without need to unregister.
    ; Does not take in account for sleeping, waiting, being in the menu or fast traveling.
    ; Does not tie the VM up, like Waits functions do(they all pause the script).
   
    RegisterForSingleUpdateGameTime(48.0)
 
EndEvent
 
Event OnUpdateGameTime()
 
    MyAlias.ForceRefTo(SpecificVendorChest)
 
EndEvent

 

Pardon me if I'm stepping on toes here.

Link to comment
Share on other sites

OK, great. I think I've mostly got it. I made a quest, added my reference alias with specific reference (the merchant's vanilla chest), and added the desired inventory records to the inventory section of the reference alias. The items appear to be initially added to the merchant chest since both vendors are able to sell the items. This is a great start. Unfortunately, I'm having some trouble getting the items to respawn in the chest.

 

The part I'm a little lost on is the script to refill the alias. I just really am not familiar enough with papyrus. Would that be as simple as the script I put below?

 

 

Scriptname MyAliasScript extends ReferenceAlias

 

ReferenceAlias Property MyAlias Auto

ObjectReference Property SpecificVendorChest Auto

 

Event OnPlayerLoadGame()

RegisterForUpdate(1.0)

EndEvent

 

Event OnUpdate()

Utility.WaitGameTime(48)

MyAlias.ForceRefTo(SpecificVendorChest)

EndEvent

 

I have a few more related questions. Should the script be attached directly to the ReferenceAlais or to the quest itself? I assume the ReferenceAlias, but I'm kind of guessing here. One question I had was about the timing of this updating versus the timing of the "vanilla" refreshing of the inventory. If it updates 3 hours before the "vanilla" reset, would that mean my items would only be available for those 3 hours because the "vanilla" reset would clean them out? If that is the case, is there a way to synchronize the refreshes? Or am I missing something? Again, your help is much appreciated!

 

You want to use RegisterForSingleUpdateGameTime(48) (and OnUpdateGameTime()) in place of your WaitGameTime. As you coded it, you will have only one ForceTo ever happen, 48 hours after the quest starts. RegisterForSingleUpdate will create a self-perpetuating chain, which is what's desired. I believe an Alias.Clear() command is also required to make the game realize the alias has been filled by something 'new', and should be placed directly before the ForceRefTo event.

 

You can also dispense with the ObjectReference and ReferenceAlias properties and save yourself some clicking. Everywhere you have myAlias, you can simply use 'self' (or just use the functions directly; the compiler will assume you're running them on self). For the ObjectReference, directly before the Clear command, use GetRef() to pull the objectreference the alias is on, store it in a local variable, then use that in the ForceRefTo() function. That way you don't need to spend your time passing information to a script that already knows it.

 

To answer your other questions:

 

1) Items added through a quest alias's alias tab will remain through a merchant chest's reset. That's the entire reason to do this v. just adding them directly to the container through AddItem. When I was setting things up, I discovered that the first time you talk to a merchant, you will actually trigger a chest refresh, wiping anything added prior. And, unfortunately, I couldn't find any way to detect when that event occurred, hence this workaround.

 

2) Yes, the script should be attached to a reference alias. If you put it on the quest it can be made to work, sort of, but putting it on the alias has two very useful advantages:

First, you can use exactly the same script on as many vendor containers as you like, just by copying the alias and changing what it points to, and secondly, the alias will receive events from the container, so you can, for example, make it do things when items are purchased and so on.

 

EDIT:

 

Also, as Rasikko points out, you used a RegisterForUpdate in your OnInit block, which is bad practice even if you want to set up a recurring event (chained RegisterForSingleUpdates are less likely to cause problems), but isn't what you want to do if all you're trying to do is kick off the refresh sequence; you only need to have OnUpdate() fire once (or not at all; you can call RegisterForSingleUpdateGameTime() directly in the OnInit block, though if you had extensive initialization routines doing them in an OnUpdate() would be good practice), and then OnUpdateGameTime() every 48 hours thereafter, not every second.

 

However, I believe that OnPlayerLoadGame() event only fires in a player alias, Rasikko. To trigger a reset coming out of a load game (not needed as far as I've found, but I can't claim to've tested everything) you'd want a separate player alias, then, which could fire something on a quest script, which would then fire all the OnUpdate() event of the quest's container aliases.

 

PS:

 

I believe I actually have a worked-out, simplified version of this posted somewhere on this forum. I'll see if I can dig it up.

Edited by foamyesque
Link to comment
Share on other sites

Found it:

 

https://forums.nexusmods.com/index.php?/topic/6041698-papyrus-refreshing-merchant-inventory/page-3&do=findComment&comment=54144758

scriptname SB_SkoomaCycler extends ReferenceAlias

FormList Property SB_Skooma Auto

Event OnInit()
    RegisterForSingleUpdateGameTime(48)
EndEvent

Event OnUpdateGameTime()
    RegisterForSingleUpdateGameTime(48)
    RemoveSkooma()
    AddSkooma()
EndEvent

Function AddSkooma()
    ObjectReference myRef = GetRef()
    Clear()
    ForceRefTo(myRef)
EndFunction

Function RemoveSkooma()
    GetRef().RemoveItem(SB_Skooma, 10000)
EndFunction

There's some shortcuts taken in this implementation because it was only being requested for one, specific, set of mod-created items. It can be extended to arbitrary items with some work, though it requires horsing around and/or SKSE to do so.

Edited by foamyesque
Link to comment
Share on other sites

Found it:

 

https://forums.nexusmods.com/index.php?/topic/6041698-papyrus-refreshing-merchant-inventory/page-3&do=findComment&comment=54144758

scriptname SB_SkoomaCycler extends ReferenceAlias

FormList Property SB_Skooma Auto

Event OnInit()
    RegisterForSingleUpdateGameTime(48)
EndEvent

Event OnUpdateGameTime()
    RegisterForSingleUpdateGameTime(48)
    RemoveSkooma()
    AddSkooma()
EndEvent

Function AddSkooma()
    ObjectReference myRef = GetRef()
    Clear()
    ForceRefTo(myRef)
EndFunction

Function RemoveSkooma()
    GetRef().RemoveItem(SB_Skooma, 10000)
EndFunction

There's some shortcuts taken in this implementation because it was only being requested for one, specific, set of mod-created items. It can be extended to arbitrary items with some work, though it requires horsing around and/or SKSE to do so.

 

Awesome. So to implement a script like this, I would need to create a form list with anything I want removed from the chest, right? Basically a form list with all the items I added to the inventory of the Reference Alias. And then just swap out the SB_Skooma form list for my new form list (at the very least, just change this out in the script properties). No need to specify what items I want added to the container, since re-applying the reference alias already does that.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...