corrado33 Posted September 23, 2018 Share Posted September 23, 2018 (edited) Last... issue, shall we say. My mod transfers stuff in and out of the players inventory based on formlists. However, when transferring stuff OUT of the player's inventory, I simply transfer a large amount of those items because I never counted them anywhere (and counting them would require twice the number of lists and that's already too many lists.) So ideas for protecting player equipped items from being transferred away from the player. Idea 1: When transferring items out of the player's inventory, run a script on the player that utilizes the "onObjectUnequipped" event. If that event fires, then re-equip that item, and remove the item from the chest it was transferred to. Potential problems: I likely have no idea where the item was transferred do. Although I could loop through all possibilities. (30ish containers.) Other potential problem: I'm unsure if the correct version of that thing will be grabbed. Armor that is improved is seemingly identical to the game's eyes to normal armor. So I'm unsure if the "improved" version will be given back to you. Same goes for enchantments. Idea 2: Before transferring items out of the player's inventory, create a formlist of all of the equipped gear the player is using. Then, prevent that stuff from being unequipped by... well.... unequipping it, then equipping it with the cursed bool true (preventing removal.) I'm.... unsure if this will prevent a script from taking the equipped item. Then of course unequip/equip it again allowing the player to unequip it at will. This seems like a great way for the script to screw up and curse all of the player's armor. Idea 3: Similar to idea 2, except this time I go through and physically remove the equipped items from the formlists to be removed from the player's inventory. This, in itself would require a couple of loops. Then I count how many the player has, and remove 1 less. Then add them BACK to the formlists afterward. This one seems... complicated. Potential Problems: I'm unsure if the "1 less" will actually be the one the player has equipped. Any other ideas that I'm missing? Which sounds best to the you guys and gals(who have a lot more experience than I?) EDIT: When I remove the items, I simply do "player.removeitem(formList,1000,true,chestRef)" and that loops through the formlist and removes everything. If I were to manually loop through the formlist, I could check to see if the item was equipped, but that'd be slow. Edited September 23, 2018 by corrado33 Link to comment Share on other sites More sharing options...
JonathanOstrus Posted September 23, 2018 Share Posted September 23, 2018 Heh. This is why every sorting mod I've ever seen asks the player to put the stuff they want sorted into a designated container. Then it sorts it from there instead of straight out of the player inventory. Then it doesn't have to care whether it's an equipped item or not. The player has already designated that they want it sorted out for them. I would argue that is a better process as some players (myself included) carry "extra" gear that can be switched in and out depending on the circumstances. Having a mod yank everything except the active equipped items would be totally useless in such cases. That said, generally speaking your issues about #1 are right on. There is no reliable way to distinguish between a plain or player upgraded/enchanted item if you have one of each. RE #2. That won't work. Even if you set the bool to prevent removal, scripts can still remove it. The flag only prevents the player from removing it themselves. You also still have the same problem as #1 where you can't tell whether it's a plain or a player modified item. RE #3. That still won't work. Removing n-1 will not always leave the equipped item. It may not always be the last in the list as the game returns it. Besides the issue as you stated for speed. Link to comment Share on other sites More sharing options...
corrado33 Posted September 23, 2018 Author Share Posted September 23, 2018 (edited) Heh. This is why every sorting mod I've ever seen asks the player to put the stuff they want sorted into a designated container. Then it sorts it from there instead of straight out of the player inventory. Then it doesn't have to care whether it's an equipped item or not. The player has already designated that they want it sorted out for them. I would argue that is a better process as some players (myself included) carry "extra" gear that can be switched in and out depending on the circumstances. Having a mod yank everything except the active equipped items would be totally useless in such cases. That said, generally speaking your issues about #1 are right on. There is no reliable way to distinguish between a plain or player upgraded/enchanted item if you have one of each. RE #2. That won't work. Even if you set the bool to prevent removal, scripts can still remove it. The flag only prevents the player from removing it themselves. You also still have the same problem as #1 where you can't tell whether it's a plain or a player modified item. RE #3. That still won't work. Removing n-1 will not always leave the equipped item. It may not always be the last in the list as the game returns it. Besides the issue as you stated for speed. Hmmmm ok. Idea #4: Make a list of the players contents and refuse to transfer those items to the player from the chests. Idea #5: Design an "Everything but this" script that sets a "base" item set that the player has. When a button is pressed, everything but what the player has designated will be transferred out of their inventory (honestly this was going to be my next mod anyway.) Of course, this still runs into the problems from the idea 1 above. Idea #6: Tell the player to enchant their items so that they have different names so that none of this will be a problem? :wink: EDIT: Idea #7: Create a cloud chest that transfers everything the player has into it when activating a crafting station (before the stuff is given to the player.) Then when finished, and after transferring stuff OUT of the player's inventory, transfer the stuff back and equip the stuff that was equipped. Of course,the player would be naked.... and any enchanted items wouldn't... you know... work. UNLESS I forced the effects onto the player... that'd be some.... work. For now, I'm just going to not transfer armor or weapons to the player when activating a crafting station. :wink: Edited September 23, 2018 by corrado33 Link to comment Share on other sites More sharing options...
IsharaMeradin Posted September 23, 2018 Share Posted September 23, 2018 Maybe this will be of help. I have an improved version of my Inventory Management System mod locally. In this version I have a single function that handles sorting items back out to their respective containers. I allow the player to manually store weapons and armor and they are sent to the player when accessing merchants and crafting stations (to account for breakdown mods). However, I do not have them transfer back out for speed reasons. Yet, I retained the code that ensures that equipped & favorite items are not transferred when they happen to be on the associated list. This does mean that the player has to manually store any left over weapons or armors themselves, but with all my containers being accessible from inventory it is a non-issue. Function ReturnItems(Bool isMerchant = false) ;sends items back to containers based on lists built as items are added Debug.Notification("Sorting items, please be patient.") ; ReturningItems = true int mcs = abim_IMS_ModContainers.GetSize() - 1 While mcs >= 0 If mcs != 9 && mcs != 10 ; do not do ammo containers - let those sort out on next bow equip/unequip If isMerchant == true If (abim_IMS_MerchExcludeGVLIst.GetAt(mcs) as GlobalVariable).GetValue() == 0.0 ; this method is faster to sort out, but cannot include weapons and armor in the lists FormList MasterList = (abim_IMS_MasterItemList.GetAt(mcs) as FormList) int q = PlayerRef.GetItemCount(MasterList) If q > 0 PlayerRef.RemoveItem(MasterList,q,true,(abim_IMS_ModContainers.GetAt(mcs) as ObjectReference)) EndIf ; this method is slwower to sort out, but can include weapons and armor in the lists ; FormList MasterList = (abim_IMS_MasterItemList.GetAt(mcs) as FormList) ; int s = MasterList.GetSize() - 1 ; While s >= 0 ; Form Entry = MasterList.GetAt(s) ; Int q = PlayerRef.GetItemCount(Entry) ; If Entry as Weapon || Entry as Armor ; If !(PlayerRef.IsEquipped(Entry)) && !(Game.IsObjectFavorited(Entry)) ; PlayerRef.RemoveItem(Entry,q,true,(abim_IMS_ModContainers.GetAt(mcs) as ObjectReference)) ; EndIf ; Else ; PlayerRef.RemoveItem(Entry,q,true,(abim_IMS_ModContainers.GetAt(mcs) as ObjectReference)) ; EndIf ; s -= 1 ; EndWhile EndIf Else ; this method is faster to sort out, but cannot include weapons and armor in the lists FormList MasterList = (abim_IMS_MasterItemList.GetAt(mcs) as FormList) int q = PlayerRef.GetItemCount(MasterList) If q > 0 PlayerRef.RemoveItem(MasterList,q,true,(abim_IMS_ModContainers.GetAt(mcs) as ObjectReference)) EndIf ; this method is slwower to sort out, but can include weapons and armor in the lists ; FormList MasterList = (abim_IMS_MasterItemList.GetAt(mcs) as FormList) ; int s = MasterList.GetSize() - 1 ; While s >= 0 ; Form Entry = MasterList.GetAt(s) ; Int q = PlayerRef.GetItemCount(Entry) ; If Entry as Weapon || Entry as Armor ; If !(PlayerRef.IsEquipped(Entry)) && !(Game.IsObjectFavorited(Entry)) ; PlayerRef.RemoveItem(Entry,q,true,(abim_IMS_ModContainers.GetAt(mcs) as ObjectReference)) ; EndIf ; Else ; PlayerRef.RemoveItem(Entry,q,true,(abim_IMS_ModContainers.GetAt(mcs) as ObjectReference)) ; EndIf ; s -= 1 ; EndWhile EndIf ; Debug.Notification("Still sorting items.") EndIf mcs -= 1 EndWhile ; ReturningItems = false Debug.Notification("Sorting finished.") EndFunction Link to comment Share on other sites More sharing options...
foamyesque Posted September 23, 2018 Share Posted September 23, 2018 (edited) Ishara, your dummied out code does avoid removing equipped or favourited items, but it also has the issue that it will not remove any unequipped but duplicate copies either, and I think the OP's after something that can. Unfortunately, to the best of my knowledge, the tools to do that don't exist. EDIT: Your loop structure hurts my soul, too. Why not this: ; FormList MasterList = (abim_IMS_MasterItemList.GetAt(mcs) as FormList) ; int s = MasterList.GetSize() ; While s > 0 ; s -= 1 ; <loop contents> ; EndWhile By putting the decrementor directly after the loop opening, I find I'm less likely to forget it, it saves you writing out a redundant - 1 operation on the starting count, and also I hate how ugly the greater-than-or-equal-to comparator looks and avoid it whenever possible :v Edited September 23, 2018 by foamyesque Link to comment Share on other sites More sharing options...
corrado33 Posted September 23, 2018 Author Share Posted September 23, 2018 (edited) IsharaMeradin : Wait so you DID this already? Grumble grumble grumble :wink: Good learning experience regardless. I'm still publishing it ;) Edited September 23, 2018 by corrado33 Link to comment Share on other sites More sharing options...
IsharaMeradin Posted September 23, 2018 Share Posted September 23, 2018 Ishara, your dummied out code does avoid removing equipped or favourited items, but it also has the issue that it will not remove any unequipped but duplicate copies either, and I think the OP's after something that can. Unfortunately, to the best of my knowledge, the tools to do that don't exist. EDIT: Your loop structure hurts my soul, too. Why not this: ; FormList MasterList = (abim_IMS_MasterItemList.GetAt(mcs) as FormList) ; int s = MasterList.GetSize() ; While s > 0 ; s -= 1 ; <loop contents> ; EndWhile By putting the decrementor directly after the loop opening, I find I'm less likely to forget it, it saves you writing out a redundant - 1 operation on the starting count, and also I hate how ugly the greater-than-or-equal-to comparator looks and avoid it whenever possible :vWe all prefer different ways. I like to be able to increment to the next after doing all the work on the current. It "hurts my brain" to increment then do the work as it "doesn't make sense" to me. And you are right that it will not move duplicates of those that are equipped or made favorite. But that is not possible. Link to comment Share on other sites More sharing options...
cdcooley Posted September 24, 2018 Share Posted September 24, 2018 It is amazing how many people keep trying to come up with solutions to this same basic problem. It's even more amazing how many approaches have been tried. But since none of us have found the perfect solution, people should keep trying. Someday someone might succeed where the rest of us have failed. IsharaMeradin is right about moving duplicates of equipped/favorite items. The game's remove functions actually give preference to removing whatever is equipped first. But the DropObject function does try to remove unequipped items first so there is a workaround if you're willing to do an item-by-item loop and drop items into the world one-by-one and then transfer the resulting reference into some container. (Drop returns a reference to the item dropped.) There's apparently no other way short of someone creating a new SKSE function. I gave up on the idea of scripted removal of generic items from the player specifically because there's no way to prevent the script from taking things it shouldn't. The bad cases include quest items, favorites, equipped gear, alternate weapons and gear, special books, soul gems, various special misc items, food for those using survival mods, and even hidden token items that the player never sees but might be used by other mods to track various things or provide adjustments to encumbrance. My Storage Helpers and Better Container Controls mods can still grab items they shouldn't even after I found a way to avoid taking quest items, favorites, equipped items, gold, lockpicks, hidden items, and anything in a exclusion list. Some items are special only in the mod of a mod author or the player and there's absolute no way to know what your script shouldn't be taking from the player. My advice is that when using scripts if you didn't put it into the player's inventory you shouldn't be taking it back out. That seems to be the only relatively safe approach. Link to comment Share on other sites More sharing options...
corrado33 Posted September 25, 2018 Author Share Posted September 25, 2018 (edited) It is amazing how many people keep trying to come up with solutions to this same basic problem. It's even more amazing how many approaches have been tried. But since none of us have found the perfect solution, people should keep trying. Someday someone might succeed where the rest of us have failed. IsharaMeradin is right about moving duplicates of equipped/favorite items. The game's remove functions actually give preference to removing whatever is equipped first. But the DropObject function does try to remove unequipped items first so there is a workaround if you're willing to do an item-by-item loop and drop items into the world one-by-one and then transfer the resulting reference into some container. (Drop returns a reference to the item dropped.) There's apparently no other way short of someone creating a new SKSE function. I gave up on the idea of scripted removal of generic items from the player specifically because there's no way to prevent the script from taking things it shouldn't. The bad cases include quest items, favorites, equipped gear, alternate weapons and gear, special books, soul gems, various special misc items, food for those using survival mods, and even hidden token items that the player never sees but might be used by other mods to track various things or provide adjustments to encumbrance. My Storage Helpers and Better Container Controls mods can still grab items they shouldn't even after I found a way to avoid taking quest items, favorites, equipped items, gold, lockpicks, hidden items, and anything in a exclusion list. Some items are special only in the mod of a mod author or the player and there's absolute no way to know what your script shouldn't be taking from the player. My advice is that when using scripts if you didn't put it into the player's inventory you shouldn't be taking it back out. That seems to be the only relatively safe approach. Thanks for the support :smile: On a side note.... I program in the real world too (for fun... mostly)... what were you saying about writing new skse scripts? I didn't even know that was possible. What language is it? Python? C++? Any more info on that? I'm guessing it's more complicated than writing papyrus scripts but if it gives greater control over the player inventory... I may be able to write a "drop all but equipped" function. Edited September 25, 2018 by corrado33 Link to comment Share on other sites More sharing options...
IsharaMeradin Posted September 25, 2018 Share Posted September 25, 2018 What you're asking about is referred to as SKSE plugins. Here is some information on it: https://github.com/xanderdunn/skaar/wiki/Writing-Your-Plugin.It is beyond my understanding, I'll be of no help. Link to comment Share on other sites More sharing options...
Recommended Posts