Jump to content

[LE] Endless frustrations with container inventories and/or player-modified items


Recommended Posts

My goal is to be able to go through the gameworld and return the inventory-displayed gold value of any items therein, for use in later calculations. This includes not just loose items, but things in containers and actor inventories. However I've hit multiple difficulties.

 

1. When I pull the inventory of a container, either via iterating GetNthForm or its faster equivalent GetContainerForms, the results are the basic forms. These are castable to their types (e.g. Armor, Weapon, etc) but not to ObjectReference. Hence functions that only work on ObjectRefs, such as GetItemHealthPercent (which returns the smithing improvement level) or the ObjectRef version of GetEnchantment (which returns player-made enchantments), do not work. This means that, say, a dual-enchanted Steel Armor (legendary) in a container produces the same gold value as an ordinary Steel Armor.

 

2. Even as loose items, player-made enchantments do not follow the same rules as ordinary pre-generated ones for value. There's a known bug that impacts this in Skyrim itself, of course.

 

3. Enchantments that have a manually set value in the CK are not distinguishable by any means I've found from ones that follow the auto-calculate rules. As such, they also return incorrect values.

 

 

 

All of the above notwithstanding this information is clearly saved somewhere because the game UI and bartering have access to it. So too I assume does SkyUI, to drive the sort function. Does anybody have any thoughts on how to solve these? Simply being able to distinguish player-made or modified items from their basic forms would be very useful; a way to pull the game's actual gold values directly would be ideal (GetGoldValue only returns the value of the basic form, disregarding any enchantments (player or CK) or smithing).

Edited by foamyesque
Link to comment
Share on other sites

You're not going to like this but I don't think you're going to be able to get those things. They only way it will be possible is if someone creates an SKSE plugin after tracing through how the inventory screen gets the values and finds that missing enchantment flag value.

 

I knew the inventory and item reference structure used in Morrowind fairly well and the ones in Skyrim seem to be handled in the same way. Here's how I believe things work and how I came to the conclusion above.

 

It appears that the game really does calculate prices dynamically whenever they are displayed instead of storing them. The other information you want gets stored in at least two different ways, one when an item is in the game world and a completely different one when it's in a container.

 

Items in containers don't exist as individual objects. Basically each container only stores a "base item" list and an "item changes" list for each base item. When normal items are put into a container they are destroyed and the base item list is updated to record how many of the particular base type are now in the container. If any of the items have special features (being persistent, smithing improvements, player enchantments, charges used, etc.) then those features are converted into entries on the item changes list. (Persistent objects are special because the object itself isn't deleted and the item changes list simply has a pointer to the actual object.) When you do anything with inventory you really only have access to that base item list. Everything in the changes list is hidden because there's absolutely no relationship between how it is stored and any object in the game at that point.

 

The developers did it that way so that the game wouldn't have to keep as much information in memory. Almost everything in a container can be reduced to a fairly short list of numbers. And for the exceptional cases the game uses the change lists to store information as efficiently as possible. Unfortunately that means it's not accessible in any meaningful way.

 

When the player opens a container there's code deep in the game somewhere that cycles through the base items list and the item changes lists to create the information shown in the user interface. But that information is being generated for display purposes only and doesn't match up to any sort of real objects. You can potentially write code to pull the information out of the inventory display itself while the player has the container open, but even if you do that you won't have a way to link it back to actual objects usable in Papyrus.

 

When you select an item in the inventory screen (either to drop it into the game world or to move it to another container) the user interface make a call back to the game telling it to move or drop the item by its position in the information list it was provided. The game then looks to see which type of base item it is and if that particular entry was created based on one of the item change list entries. If it's a normal item and the item is being moved then the base item list for each container is simply updated. If it's a special item the change list entry is also moved over to the other container. When items are dropped the process is basically the same except a new object reference is created and assigned the appropriate properties from the change list if needed.

 

In theory it would be possible for someone to reverse engineer how all of that works and create a SKSE plugin but it won't be an easy task. Finding that auto-calculate flag for enchantments would be the easiest one, but the fact that the SKSE team didn't find it when the provided all of the other enchantment related functions means it's probably pretty well hidden.

 

So like the rest of us who try to deal with inventory you may have to be very creative and find a way to work around all of those limitations. Yes, it's very frustrating.

Link to comment
Share on other sites

I was afraid of that. Unfortunately I haven't come up with a brilliant solution or I wouldn't be asking; the closest thing that's occurred to me is yanking everything out into the game world, working on it there, and then stuffing them back into the containers, but that has some really ugly flaws. Cloning them might solve some of them, but almost certainly runs into the same "information not present" kind of problem, and would be ridiculously slow.

Blargh. Creating my own SKSE plugin is not a task I think I'm up for. I think I'm just going to have to file this as "can't fix", which sucks. Ordinarily I wouldn't care terrifically about player modifications, since they're generally limited in number, but there are, for example, mods out there that distribute smithed weapons and armour among various NPCs and it would've been real nice to be able to handle those.

 

EDIT:

 

To clarify, this is for the player-modified items specifically. I do have workarounds for fixed-value enchantments in the base game/DLCs, though it's only extendable to mods via user interaction. Works, though, since RemoveAddedForm was fixed. Effectively what I do is categorize stuff into one of seven tiers based on their calculated value and value-to-weight numbers, and stuff them into formlists based on their tier level. These formlists are the first step of checking for something's value; if it's in one of them, all the value calculations and so on get skipped. Hotkeys allow for an item to be moved from one formlist to another, effectively changing what the mod thinks it is worth (and therefore the graphical effect applied to it). For enchantments with a preset value, I have "seed" lists that I can assign them to that match their actual value, which a preloader moves into the primary assessment lists.

Edited by foamyesque
Link to comment
Share on other sites

Actually, it looks like the SKSE team did uncover this stuff, at least partially. I ran across the doc for the WornObject script object, and -- if it does what it says it does -- it will pull the tempering/enchanting data, but only for forms that are equipped to an actor. I am not entirely sure why they stopped there but I suspect there's a reason... The forms are pulled by passing in an actor and a slot as parameters, which obviously doesn't work in the general case.

 

Looking at the C code this is still pretty ugly though. I dunno. It's a place to start, I guess.

Link to comment
Share on other sites

  • 7 months later...
  • Recently Browsing   0 members

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