Handling Inventory Items

Post » Sun May 18, 2014 8:07 am

The Papyrus system doesn't understand unsigned integers and formid values are basically just 32-bit integers. Any mod loaded after position 127 (which includes the savegame) will have forms with "negative" formids in Papyrus. Almost all functions work just fine on all forms equally, but we know that Game.GetForm() doesn't work if you give it a formid value for a created potion. I'm guessing that one of the other functions involved here may be breaking too. Even if it does break there's really nothing you can do about it. Call the fact that player-made potions aren't sorted a feature. :)
User avatar
meghan lock
 
Posts: 3451
Joined: Thu Jan 11, 2007 10:26 pm

Post » Sun May 18, 2014 12:43 am

I just tested this fact. http://www.nexusmods.com/skyrim/mods/18340/? is able to handle player created potions and player enchanted gear.

User avatar
Juan Suarez
 
Posts: 3395
Joined: Sun Nov 25, 2007 4:09 am

Post » Sun May 18, 2014 2:15 am

Looking at General Stores scripts it seems that it handles user created items by iterating over the the formlist and removing each item at a time. Considering this, I decided to test the time difference between the FormList Method (shown in the Scan_Inventory_Redux function in the last example) and Remove-As-You-Crawl Method with 954 different items (not to mention the count of each different item) there is a one second difference in the time it takes. The FormList method is 1 second faster but also failed to move 78 different items. Therefor the Remove-As-You-Crawl Method is superior due to the fact that player made items are not moved by the FormList Method.

Take note that both methods crawl over the inventory and that the real slowdown is the iteration over the items using GetNthForm. This is necessary to avoid moving equipped and favorited items.

Another method that I have not tested here is the use of RemoveAllItems(ToCont, True). I could get all the equipped items, but I would not be able to make note of all the favorite items. This method would add two complications. One being that the user would have to define items to keep separately from the UI's favorite feature and that the player character would spend some amount of time naked before being re-equipped. These are complications that I want to avoid entirely.

User avatar
saxon
 
Posts: 3376
Joined: Wed Sep 19, 2007 2:45 am

Post » Sun May 18, 2014 12:57 pm

Below is the sorting script I was testing. It worked last I checked.

Edit: Some lists are marked in comments as "sort out." The idea is to sort these items into a container from the sub categories or elsewhere (where noted) to present them, temporarily, into another container for viewing. This part I have not yet written. The following script merely separates items into containers where they will be stored.

Spoiler
ScriptName _t_Test_Sorting_Container Extends ObjectReference{}; ################################ CHESTS #####################################ObjectReference Property _t_ref_chest_arrows                    Auto ; aka ammoObjectReference Property _t_ref_chest_armor_all                 Auto ; sort outObjectReference Property _t_ref_chest_armor_clothing            AutoObjectReference Property _t_ref_chest_armor_heavy               AutoObjectReference Property _t_ref_chest_armor_light               AutoObjectReference Property _t_ref_chest_armor_shields             AutoObjectReference Property _t_ref_chest_armor_jewelry             Auto; ObjectReference Property _t_ref_chest_other_armor               Auto why do I have this?ObjectReference Property _t_ref_chest_books_all                 Auto ; sort outObjectReference Property _t_ref_chest_books_spell_tomes         Auto ;ObjectReference Property _t_ref_chest_books_recipes             Auto ;ObjectReference Property _t_ref_chest_books_skill               Auto ;ObjectReference Property _t_ref_chest_books_other               Auto ;ObjectReference Property _t_ref_chest_books_bound               Auto ;ObjectReference Property _t_ref_chest_cons_food_all             Auto ; sort outObjectReference Property _t_ref_chest_cons_food_cooked          AutoObjectReference Property _t_ref_chest_cons_food_raw             Auto ; sort out food raw / ingredients from ingredientsObjectReference Property _t_ref_chest_cons_pots_all             Auto ; sort outObjectReference Property _t_ref_chest_cons_pots_buffs           AutoObjectReference Property _t_ref_chest_cons_pots_restore         AutoObjectReference Property _t_ref_chest_cons_pots_poisons         AutoObjectReference Property _t_ref_chest_cons_scrolls              AutoObjectReference Property _t_ref_chest_mats_ingredients          AutoObjectReference Property _t_ref_chest_mats_smithing_all         Auto ; sort outObjectReference Property _t_ref_chest_mats_smithing             AutoObjectReference Property _t_ref_chest_mats_smelting             AutoObjectReference Property _t_ref_chest_mats_tanning              AutoObjectReference Property _t_ref_chest_mats_gems                 Auto ; sort outObjectReference Property _t_ref_chest_misc_clutter              AutoObjectReference Property _t_ref_chest_misc_animal_parts         AutoObjectReference Property _t_ref_chest_soul_gems                 AutoObjectReference Property _t_ref_chest_weap_all                  Auto ; sort outObjectReference Property _t_ref_chest_weap_swords               AutoObjectReference Property _t_ref_chest_weap_greatswords          AutoObjectReference Property _t_ref_chest_weap_waraxes              AutoObjectReference Property _t_ref_chest_weap_battleaxes           AutoObjectReference Property _t_ref_chest_weap_maces                AutoObjectReference Property _t_ref_chest_weap_warhammers           AutoObjectReference Property _t_ref_chest_weap_bows                 AutoObjectReference Property _t_ref_chest_weap_daggers              AutoObjectReference Property _t_ref_chest_weap_staves               AutoObjectReference Property _t_ref_chest_temp                      AutoObjectReference Property _t_ref_chest_unsorted                  Auto; ################################# LISTS #####################################FormList Property _t_List_Ammo                           AutoFormList Property _t_List_Armor_All                      Auto ; sort out from all armorFormList Property _t_List_Armor_Clothing                 AutoFormList Property _t_List_Armor_Heavy                    AutoFormList Property _t_List_Armor_Light                    AutoFormList Property _t_List_Armor_Shields                  AutoFormList Property _t_List_Armor_Jewelry                  AutoFormList Property _t_List_Books_All                      Auto ; sort out from all booksFormList Property _t_List_Books_Spell_Tomes              AutoFormList Property _t_List_Books_Recipes                  AutoFormList Property _t_List_Books_Skill                    AutoFormList Property _t_List_Books_Other                    AutoFormList Property _t_List_Books_Bound                    AutoFormList Property _t_List_Cons_Food_All                  Auto ; sort out from all foodFormList Property _t_List_Cons_Food_Cooked               AutoFormList Property _t_List_Cons_Food_Raw                  AutoFormList Property _t_List_Cons_Food_Raw_Ingredients      Auto ; sort out to raw/ingredients - no chestFormList Property _t_List_Cons_Potions_ALL               Auto ; sort out from all potionsFormList Property _t_List_Cons_Potions_Buffs             AutoFormList Property _t_List_Cons_Potions_Restore           AutoFormList Property _t_List_Cons_Potions_Poisons           AutoFormList Property _t_List_Cons_Scrolls                   AutoFormList Property _t_List_Mats_Ingredients               AutoFormList Property _t_List_Mats_Ingredients_Smithing      Auto ; sort out to smithing/ingredients - no chestFormList Property _t_List_Mats_Smithing_All              Auto ; sort out from all materialsFormList Property _t_List_Mats_Smithing                  AutoFormList Property _t_List_Mats_Smelting                  AutoFormList Property _t_List_Mats_Tanning                   AutoFormList Property _t_List_Mats_Gems                      Auto ; sort out from smithingFormList Property _t_List_Misc_Animal_Parts              AutoFormList Property _t_List_Soul_Gems_ALL                  AutoFormList Property _t_List_Misc_Clutter                   AutoFormList Property _t_List_Weap_All                       Auto ; sort out from all weaponsFormList Property _t_List_Weap_Swords                    AutoFormList Property _t_List_Weap_Greatswords               AutoFormList Property _t_List_Weap_Waraxes                   AutoFormList Property _t_List_Weap_Battlaxes                 AutoFormList Property _t_List_Weap_Maces                     AutoFormList Property _t_List_Weap_Warhammers                AutoFormList Property _t_List_Weap_Bows                      AutoFormList Property _t_List_Weap_Daggers                   AutoFormList Property _t_List_Weap_Staves                    Auto;---------------------------- Discovery Lists ---------------------------------FormList Property _t_List_Disc_Ammo                      AutoFormList Property _t_List_Disc_Armor_All                 AutoFormList Property _t_List_Disc_Armor_Clothing            AutoFormList Property _t_List_Disc_Armor_Heavy               AutoFormList Property _t_List_Disc_Armor_Light               AutoFormList Property _t_List_Disc_Armor_Shields             AutoFormList Property _t_List_Disc_Armor_Jewelry             AutoFormList Property _t_List_Disc_Books_All                 AutoFormList Property _t_List_Disc_Books_Bound               Auto ; need special function to check against model path. The idea is to seperate notes and journals into other. Not like there would be many mod added books anyway.FormList Property _t_List_Disc_Books_Other               AutoFormList Property _t_List_Disc_Books_Recipes             AutoFormList Property _t_List_Disc_Books_Skill               AutoFormList Property _t_List_Disc_Books_Spell_Tomes         AutoFormList Property _t_List_Disc_Cons_Food_All             AutoFormList Property _t_List_Disc_Cons_Food_Cooked          AutoFormList Property _t_List_Disc_Cons_Food_Raw             AutoFormList Property _t_List_Disc_Cons_Food_Raw_Ingredients AutoFormList Property _t_List_Disc_Cons_Potions_ALL          AutoFormList Property _t_List_Disc_Cons_Potions_Buffs        Auto ; restorative potions will sort here too unless predefinedFormList Property _t_List_Disc_Cons_Potions_Restore      Auto ; need special function for checking effects - this may yet be limited where anyone has expanded potion effectsFormList Property _t_List_Disc_Cons_Potions_Poisons      AutoFormList Property _t_List_Disc_Cons_Scrolls              AutoFormList Property _t_List_Disc_Mats_Ingredients          AutoFormList Property _t_List_Disc_Mats_Ingredients_Smithing AutoFormList Property _t_List_Disc_Mats_Smithing_All         AutoFormList Property _t_List_Disc_Mats_Smithing             AutoFormList Property _t_List_Disc_Mats_Smelting             AutoFormList Property _t_List_Disc_Mats_Tanning              AutoFormList Property _t_List_Disc_Mats_Gems                 AutoFormList Property _t_List_Disc_Misc_Animal_Parts         AutoFormList Property _t_List_Disc_Misc_Clutter              Auto; FormList Property _t_List_Disc_Soul_Gems_ALL             Auto ; would/has anyone really add more soul gems?FormList Property _t_List_Disc_Weap_All                  AutoFormList Property _t_List_Disc_Weap_Swords               AutoFormList Property _t_List_Disc_Weap_Greatswords          AutoFormList Property _t_List_Disc_Weap_Waraxes              AutoFormList Property _t_List_Disc_Weap_Battlaxes            AutoFormList Property _t_List_Disc_Weap_Maces                AutoFormList Property _t_List_Disc_Weap_Warhammers           AutoFormList Property _t_List_Disc_Weap_Bows                 AutoFormList Property _t_List_Disc_Weap_Daggers              AutoFormList Property _t_List_Disc_Weap_Staves               Auto; User defines items that will be destroyed on cell reset.; Items removed from Junk will be unlearned.FormList Property _t_List_Disc_Misc_Junk                 Auto; #############################################################################Keyword Property ArmorClothing             AutoKeyword Property ArmorHeavy                AutoKeyword Property ArmorJewelry              AutoKeyword Property ArmorLight                AutoKeyword Property ArmorShield               AutoKeyword Property GiftApothecarySpecial     AutoKeyword Property GiftPriestSpecial         AutoKeyword Property GiftThiefSpecial          AutoKeyword Property GiftWarriorSpecial        AutoKeyword Property GiftWizardSpecial         AutoKeyword Property VendorItemAnimalHide      AutoKeyword Property VendorItemAnimalPart      AutoKeyword Property VendorItemClothing        AutoKeyword Property VendorItemClutter         AutoKeyword Property VendorItemFireword        AutoKeyword Property VendorItemFood            AutoKeyword Property VendorItemFoodRaw         AutoKeyword Property VendorItemGem             AutoKeyword Property VendorItemJewelry         AutoKeyword Property VendorItemOreIngot        AutoKeyword Property VendorItemPoison          AutoKeyword Property VendorItemPotion          AutoKeyword Property VendorItemRecipe          AutoKeyword Property VendorItemSpellTome       AutoKeyword Property VendorItemTool            AutoKeyword Property WeapTypeBattleaxe         AutoKeyword Property WeapTypeBow               AutoKeyword Property WeapTypeDagger            AutoKeyword Property WeapTypeGreatsword        AutoKeyword Property WeapTypeMace              AutoKeyword Property WeapTypeStaff             AutoKeyword Property WeapTypeSword             AutoKeyword Property WeapTypeWaraxe            AutoKeyword Property WeapTypeWarhammer         Auto; #############################################################################ObjectReference Property _t_ref_sorting_activator               AutoObjectReference Property PlayerRef                              AutoBool Property Report_Error AutoEvent OnActivate(ObjectReference akActionRef)    Report_Error = False    if akActionRef == _t_ref_sorting_activator        ; Debug.MessageBox("Activator Activated Unsorted Chest")        Sort_Unsorted()    elseif akActionRef == PlayerRef        _t_ref_chest_unsorted.Activate(PlayerRef,true)    endif       if Report_Error        Debug.MessageBox("[triloth] An error or errors has occurred in function" + \        "HandleUnkown of Sorting Container. If not enabled, enable logging to" + \        "see the details.")    endif   EndEventFunction Sort_Unsorted()    {        Sort items using form lists, then call SortUnkown on the remaining items.    }       ; PREDEFINED       ; Ammo    Debug.Trace("=========================================================================")    Debug.Trace("[t] Begin Sorting Unsorted.")    Debug.Trace("=========================================================================")    Int NumItems = _t_ref_chest_unsorted.GetNumItems()    Debug.Trace("[t] Items = " + NumItems)    _t_ref_chest_unsorted.RemoveItem(_t_List_Ammo, 99999, true, _t_ref_chest_arrows)       ; Armor    _t_ref_chest_unsorted.RemoveItem(_t_List_Armor_Clothing, 99999, true, _t_ref_chest_armor_clothing)    _t_ref_chest_unsorted.RemoveItem(_t_List_Armor_Heavy, 99999, true, _t_ref_chest_armor_heavy)    _t_ref_chest_unsorted.RemoveItem(_t_List_Armor_Light, 99999, true, _t_ref_chest_armor_light)    _t_ref_chest_unsorted.RemoveItem(_t_List_Armor_Shields, 99999, true, _t_ref_chest_armor_shields)    _t_ref_chest_unsorted.RemoveItem(_t_List_Armor_Jewelry, 99999, true, _t_ref_chest_armor_jewelry)       ; Books    _t_ref_chest_unsorted.RemoveItem(_t_List_Books_Spell_Tomes, 99999, true, _t_ref_chest_books_spell_tomes)    _t_ref_chest_unsorted.RemoveItem(_t_List_Books_Recipes, 99999, true, _t_ref_chest_books_recipes)    _t_ref_chest_unsorted.RemoveItem(_t_List_Books_Skill, 99999, true, _t_ref_chest_books_skill)    _t_ref_chest_unsorted.RemoveItem(_t_List_Books_Other, 99999, true, _t_ref_chest_books_other)    _t_ref_chest_unsorted.RemoveItem(_t_List_Books_Bound, 99999, true, _t_ref_chest_books_bound)       ; Consumables - Food    _t_ref_chest_unsorted.RemoveItem(_t_List_Cons_Food_Cooked, 99999, true, _t_ref_chest_cons_food_cooked)    _t_ref_chest_unsorted.RemoveItem(_t_List_Cons_Food_Raw, 99999, true, _t_ref_chest_cons_food_raw)       ; Consumables - Potions    _t_ref_chest_unsorted.RemoveItem(_t_List_Cons_Potions_Buffs, 99999, true, _t_ref_chest_cons_pots_buffs)    _t_ref_chest_unsorted.RemoveItem(_t_List_Cons_Potions_Restore, 99999, true, _t_ref_chest_cons_pots_restore)    _t_ref_chest_unsorted.RemoveItem(_t_List_Cons_Potions_Poisons, 99999, true, _t_ref_chest_cons_pots_poisons)       ; Consumables - Scrolls    _t_ref_chest_unsorted.RemoveItem(_t_List_Cons_Scrolls, 99999, true, _t_ref_chest_cons_scrolls)       ; Materials    _t_ref_chest_unsorted.RemoveItem(_t_List_Mats_Ingredients, 99999, true, _t_ref_chest_mats_ingredients)    _t_ref_chest_unsorted.RemoveItem(_t_List_Mats_Smithing, 99999, true, _t_ref_chest_mats_smithing)    _t_ref_chest_unsorted.RemoveItem(_t_List_Mats_Smelting, 99999, true, _t_ref_chest_mats_smelting)    _t_ref_chest_unsorted.RemoveItem(_t_List_Mats_Tanning, 99999, true, _t_ref_chest_mats_tanning)       ; Misc    _t_ref_chest_unsorted.RemoveItem(_t_List_Misc_Animal_Parts, 99999, true, _t_ref_chest_misc_animal_parts)    _t_ref_chest_unsorted.RemoveItem(_t_List_Soul_Gems_ALL, 99999, true, _t_ref_chest_soul_gems)    _t_ref_chest_unsorted.RemoveItem(_t_List_Misc_Clutter, 99999, true, _t_ref_chest_misc_clutter)       ; Weapons    _t_ref_chest_unsorted.RemoveItem(_t_List_Weap_Swords, 99999, true, _t_ref_chest_weap_swords)    _t_ref_chest_unsorted.RemoveItem(_t_List_Weap_Greatswords, 99999, true, _t_ref_chest_weap_greatswords)    _t_ref_chest_unsorted.RemoveItem(_t_List_Weap_Waraxes, 99999, true, _t_ref_chest_weap_waraxes)    _t_ref_chest_unsorted.RemoveItem(_t_List_Weap_Battlaxes, 99999, true, _t_ref_chest_weap_battleaxes)    _t_ref_chest_unsorted.RemoveItem(_t_List_Weap_Maces, 99999, true, _t_ref_chest_weap_maces)    _t_ref_chest_unsorted.RemoveItem(_t_List_Weap_Warhammers, 99999, true, _t_ref_chest_weap_warhammers)    _t_ref_chest_unsorted.RemoveItem(_t_List_Weap_Bows, 99999, true, _t_ref_chest_weap_bows)    _t_ref_chest_unsorted.RemoveItem(_t_List_Weap_Daggers, 99999, true, _t_ref_chest_weap_daggers)    _t_ref_chest_unsorted.RemoveItem(_t_List_Weap_Staves, 99999, true, _t_ref_chest_weap_staves)    ; DISCOVERED    ;/    ; Ammo    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Ammo, 99999, true, _t_ref_chest_arrows)       ; Armor    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Armor_Clothing, 99999, true, _t_ref_chest_armor_clothing)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Armor_Heavy, 99999, true, _t_ref_chest_armor_heavy)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Armor_Light, 99999, true, _t_ref_chest_armor_light)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Armor_Shields, 99999, true, _t_ref_chest_armor_shields)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Armor_Jewelry, 99999, true, _t_ref_chest_armor_jewelry)       ; Books    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Books_Spell_Tomes, 99999, true, _t_ref_chest_books_spell_tomes)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Books_Recipes, 99999, true, _t_ref_chest_books_recipes)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Books_Skill, 99999, true, _t_ref_chest_books_skill)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Books_Other, 99999, true, _t_ref_chest_books_other)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Books_Bound, 99999, true, _t_ref_chest_books_bound)       ; Consumables - Food    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Cons_Food_Cooked, 99999, true, _t_ref_chest_cons_food_cooked)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Cons_Food_Raw, 99999, true, _t_ref_chest_cons_food_raw)       ; Consumables - Potions    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Cons_Potions_Buffs, 99999, true, _t_ref_chest_cons_pots_buffs)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Cons_Potions_Restore, 99999, true, _t_ref_chest_cons_pots_restore)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Cons_Potions_Poisons, 99999, true, _t_ref_chest_cons_pots_poisons)       ; Consumables - Scrolls    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Cons_Scrolls, 99999, true, _t_ref_chest_cons_scrolls)       ; Materials    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Mats_Ingredients, 99999, true, _t_ref_chest_mats_ingredients)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Mats_Smithing, 99999, true, _t_ref_chest_mats_smithing)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Mats_Smelting, 99999, true, _t_ref_chest_mats_smelting)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Mats_Tanning, 99999, true, _t_ref_chest_mats_tanning)       ; Misc    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Misc_Animal_Parts, 99999, true, _t_ref_chest_misc_animal_parts)    ;_t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Soul_Gems_ALL, 99999, true, _t_ref_chest_soul_gems)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Misc_Clutter, 99999, true, _t_ref_chest_misc_clutter)       ; Weapons    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Weap_Swords, 99999, true, _t_ref_chest_weap_swords)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Weap_Greatswords, 99999, true, _t_ref_chest_weap_greatswords)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Weap_Waraxes, 99999, true, _t_ref_chest_weap_waraxes)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Weap_Battlaxes, 99999, true, _t_ref_chest_weap_battleaxes)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Weap_Maces, 99999, true, _t_ref_chest_weap_maces)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Weap_Warhammers, 99999, true, _t_ref_chest_weap_warhammers)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Weap_Bows, 99999, true, _t_ref_chest_weap_bows)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Weap_Daggers, 99999, true, _t_ref_chest_weap_daggers)    _t_ref_chest_unsorted.RemoveItem(_t_List_Disc_Weap_Staves, 99999, true, _t_ref_chest_weap_staves)    /;    Int RemovedItems = NumItems    NumItems = _t_ref_chest_unsorted.GetNumItems()    RemovedItems -= NumItems    Debug.Trace("[t] Items after list method = " + RemovedItems)    SortUnkown()    NumItems = _t_ref_chest_unsorted.GetNumItems()    Debug.Trace("[t] =========================================================================")    Debug.Trace("[t] Completed Complex Sorting Pass. Items Remaining: " + NumItems)    Debug.Trace("[t] =========================================================================")EndFunctionFunction SortUnkown()    {        Rescan the remaining items starting with comparisons from the result of        Form.GetType, then check for keywords relative to the item type.    }    Form Item    Int Index = _t_ref_chest_unsorted.GetNumItems()While Index > 0        Index -= 1  Item = _t_ref_chest_unsorted.GetNthForm(Index)        HandleUnkown(Item)EndWhileEndFunction; BELOW BE DRAGONS!!!Function SetListTo(Form Item, FormList DiscList, ObjectReference ToCont)    DiscList.AddForm(Item)    _t_ref_chest_unsorted.RemoveItem(Item, 99999, true, ToCont)EndFunctionFunction HandleUnkown(Form Item)    ; -1 = Take; 0 = Keep; >0 == Keep that amount    int ItemTypeCode = Item.GetType()    ; Debug.Trace("ItemCheck: Type: " + ItemTypeCode + "  " + Item)    int Count = 0    bool type_test = false    if     ItemTypeCode == 42                                                           ; Ammo        SetListTo(Item, _t_List_Disc_Ammo, _t_ref_chest_arrows)           elseif ItemTypeCode == 26                                                           ; Armor Checks        ; Check for Armor Type        type_test = true               if      Item.HasKeyword(ArmorShield)                                            ; Armor - Shield            SetListTo(Item, _t_List_Disc_Armor_Shields, _t_ref_chest_armor_shields)                   elseif  Item.HasKeyword(ArmorLight)                                             ; Armor - Light            SetListTo(Item, _t_List_Disc_Armor_Light, _t_ref_chest_armor_light)               elseif  Item.HasKeyword(ArmorHeavy)                                             ; Armor - Heavy            SetListTo(Item, _t_List_Disc_Armor_Heavy, _t_ref_chest_armor_heavy)                   elseif  Item.HasKeyword(VendorItemJewelry)                                      ; Armor - Jewelry            SetListTo(Item, _t_List_Disc_Armor_Jewelry, _t_ref_chest_armor_jewelry)                   elseif  Item.HasKeyword(ArmorJewelry)                                           ; Armor - Jewelry            SetListTo(Item, _t_List_Disc_Armor_Jewelry, _t_ref_chest_armor_jewelry)                   elseif  Item.HasKeyword(ArmorClothing)                                          ; Armor - Clothing ; checked last because some items have keywords for jewelry and clothing            SetListTo(Item, _t_List_Disc_Armor_Clothing, _t_ref_chest_armor_clothing)                   elseif  Item.HasKeyword(VendorItemClothing)                                     ; Armor - Clothing ; checked last because some items have keywords for jewelry and clothing            SetListTo(Item, _t_List_Disc_Armor_Clothing, _t_ref_chest_armor_clothing)                   else            type_test = false        endif               if type_test                                                                    ; Armor - ALL            _t_List_Disc_Armor_All.AddForm(Item) ; Parent Category        else                                                                            ; Armor Type Unknown            ; This is actually a bug in the item. The item            ; needs the proper keywords for perks and vendors.            ; It could also be possible that it's a non-playable item.            Report_Error = True            Debug.Trace("[t] Armor missing ArmorType keyword: " + Item)        endif           elseif ItemTypeCode == 30                                                           ; Ingredient        if      Item.HasKeyword(VendorItemFoodRaw)                                      ; Ingredient/FoodRaw            SetListTo(Item, _t_List_Disc_Cons_Food_Raw_Ingredients, _t_ref_chest_mats_ingredients)                   else            SetListTo(Item, _t_List_Disc_Mats_Ingredients, _t_ref_chest_mats_ingredients)                   endif    ; elseif ItemTypeCode == 45                                                           ; Key    elseif ItemTypeCode == 32                                                           ; Misc        if      Item.HasKeyword(VendorItemAnimalHide)                                   ; Misc - Hide (Tanning) ; this will not catch fur armor because fur would have been caught above            SetListTo(Item, _t_List_Disc_Mats_Tanning, _t_ref_chest_mats_tanning)                   elseif  Item.HasKeyword(VendorItemGem)                                          ; Misc - Gem (Smithing)            SetListTo(Item, _t_List_Disc_Mats_Smithing, _t_ref_chest_mats_smithing)                   elseif  Item.HasKeyword(VendorItemOreIngot)                                     ; Misc - Ore/Ingot (Smithing All/Smithing/Smelting) ; This does not conform to the level of separation I have for vanilla items. Therefore, I am forced to include these items in the Smelting, Smithing and Smithing All categories.            SetListTo(Item, _t_List_Disc_Mats_Smelting, _t_ref_chest_mats_smelting)            _t_List_Disc_Mats_Smithing.AddForm(Item)            _t_List_Disc_Mats_Smithing_All.AddForm(Item) ; Parent Category                   elseif  Item.HasKeyword(VendorItemTool)                                         ; Misc - Tool (Clutter)            SetListTo(Item, _t_List_Disc_Misc_Clutter, _t_ref_chest_misc_clutter)                   elseif  Item.HasKeyword(VendorItemClutter)                                      ; Misc - Clutter            SetListTo(Item, _t_List_Disc_Misc_Clutter, _t_ref_chest_misc_clutter)                   elseif  Item.HasKeyword(VendorItemAnimalPart)                                   ; Misc - Animal Part            SetListTo(Item, _t_List_Disc_Misc_Animal_Parts, _t_ref_chest_misc_animal_parts)                   elseif  Item.HasKeyword(VendorItemFireword)                                     ; Misc - Firewood (Smelting); yes I spelled the key word correctly            SetListTo(Item, _t_List_Disc_Mats_Smelting, _t_ref_chest_mats_smelting)                   else            Debug.Trace("[t] Misc Item failed checks " + Item.GetName() + Item )        ; Misc - Unsorted (sent to clutter)            _t_ref_chest_unsorted.RemoveItem(Item, 99999, true, _t_ref_chest_misc_clutter)                   endif                  elseif ItemTypeCode == 27                                                           ; Book - ALL        _t_List_Disc_Books_All.AddForm(Item)        if      Item.HasKeyword(VendorItemSpellTome)                                    ; Book - Spell Tome            SetListTo(Item, _t_List_Disc_Books_Spell_Tomes, _t_ref_chest_books_spell_tomes)                   elseif  Item.HasKeyword(VendorItemRecipe)                                       ; Book - Recipe            SetListTo(Item, _t_List_Disc_Books_Recipes, _t_ref_chest_books_recipes)                   elseif  Item.HasKeyword(GiftApothecarySpecial)                                  ; Book - Skill Book            SetListTo(Item, _t_List_Disc_Books_Skill, _t_ref_chest_books_skill)                   elseif  Item.HasKeyword(GiftThiefSpecial)                                       ; Book - Skill Book            SetListTo(Item, _t_List_Disc_Books_Skill, _t_ref_chest_books_skill)                   elseif  Item.HasKeyword(GiftWarriorSpecial)                                     ; Book - Skill Book            SetListTo(Item, _t_List_Disc_Books_Skill, _t_ref_chest_books_skill)                   elseif  Item.HasKeyword(GiftWizardSpecial)                                      ; Book - Skill Book            SetListTo(Item, _t_List_Disc_Books_Skill, _t_ref_chest_books_skill)                   elseif  Item.HasKeyword(GiftPriestSpecial)                                      ; Book - Skill Book            SetListTo(Item, _t_List_Disc_Books_Skill, _t_ref_chest_books_skill)                   else                                                                            ; Book - Other            SetListTo(Item, _t_List_Disc_Books_Other, _t_ref_chest_books_other)                   endif           elseif  ItemTypeCode == 46                                                          ; Potion/Poison/Food        if      Item.HasKeyword(VendorItemPotion)                                       ; Potion/Potions All            SetListTo(Item, _t_List_Disc_Cons_Potions_Buffs, _t_ref_chest_cons_pots_buffs)            _t_List_Disc_Cons_Potions_ALL.AddForm(Item)                   elseif  Item.HasKeyword(VendorItemPoison)                                       ; Poison/Potions All            SetListTo(Item, _t_List_Disc_Cons_Potions_Poisons, _t_ref_chest_cons_pots_poisons)            _t_List_Disc_Cons_Potions_ALL.AddForm(Item)                   elseif  Item.HasKeyword(VendorItemFood)                                         ; Food - Raw/ Food - All (If using for vanilla sort, Mammoth Steak will end up here due to vanilla error. It has both key words so does Mammoth Meat)            SetListTo(Item, _t_List_Disc_Cons_Food_Raw, _t_ref_chest_cons_food_raw)            _t_List_Disc_Cons_Food_All.AddForm(Item)                   elseif  Item.HasKeyword(VendorItemFoodRaw)                                      ; Food - Cooked / Food - All            SetListTo(Item, _t_List_Disc_Cons_Food_Cooked, _t_ref_chest_cons_food_cooked)            _t_List_Disc_Cons_Food_All.AddForm(Item)                   endif    elseif ItemTypeCode == 23                                                           ; Scroll        SetListTo(Item, _t_List_Disc_Cons_Scrolls, _t_ref_chest_cons_scrolls)           ; elseif ItemTypeCode == 52                                                          ; Soul Gem    elseif ItemTypeCode == 41                                                           ; Weapons Check               type_test = true        if      Item.HasKeyword(WeapTypeBattleaxe)                                    ; Weapon - Battle Axe            SetListTo(Item, _t_List_Disc_Weap_Battlaxes, \                            _t_ref_chest_weap_battleaxes)                   elseif  Item.HasKeyword(WeapTypeBow)                                          ; Weapon - Bow            SetListTo(Item, _t_List_Disc_Weap_Bows, \                            _t_ref_chest_weap_bows)                   elseif  Item.HasKeyword(WeapTypeDagger)                                       ; Weapon - Dagger            SetListTo(Item, _t_List_Disc_Weap_Daggers, \                            _t_ref_chest_weap_daggers)                   elseif  Item.HasKeyword(WeapTypeGreatsword)                                   ; Weapon - Great Sword            SetListTo(Item, _t_List_Disc_Weap_Greatswords, \                            _t_ref_chest_weap_greatswords)                   elseif  Item.HasKeyword(WeapTypeMace)                                         ; Weapon - Mace            SetListTo(Item, _t_List_Disc_Weap_Maces, \                            _t_ref_chest_weap_maces)                   elseif  Item.HasKeyword(WeapTypeStaff)                                        ; Weapon - Staff            SetListTo(Item, _t_List_Disc_Weap_Staves, \                            _t_ref_chest_weap_staves)                   elseif  Item.HasKeyword(WeapTypeSword)                                        ; Weapon - Sword            SetListTo(Item, _t_List_Disc_Weap_Swords, \                            _t_ref_chest_weap_swords)                   elseif  Item.HasKeyword(WeapTypeWaraxe)                                       ; Weapon - War Axe            SetListTo(Item, _t_List_Disc_Weap_Waraxes, \                            _t_ref_chest_weap_waraxes)                   elseif  Item.HasKeyword(WeapTypeWarhammer)                                    ; Weapon - War Hammer            SetListTo(Item, _t_List_Disc_Weap_Warhammers, \                            _t_ref_chest_weap_warhammers)                   else            type_test = false        endif        if type_test                                                                    ; Weapon - ALL            _t_List_Disc_Weap_All.AddForm(Item)        else                                                                            ; Weapon Type Unknown            ; This is actually a bug in the item. The item            ; needs the proper keywords for perks and vendors.            ; It could also be possible that it's a non-playable item.            Report_Error = True            Debug.Trace("[t] Weapon missing WeaponType keyword: " + Item)        endif           else        ; Nothing to do here. The item apparently failed all checks ever.        ; Fail mod is fail? Can SkyUI even recognize this thing?        Report_Error = True        Debug.Trace("[t] Inventory item failed to sort: " + Item)    endif    EndFunction

It's been a while since I worked on sorting. It's not that I don't intend to work out sorting it's just that I am working out other aspects of Dragonborn's Entourage at the moment. Some of the features I intend to include work well on their own and I intended to release them as seperate mods. So far, I have released http://www.nexusmods.com/skyrim/mods/53103/?.

I am currently working on my ability to check all aspects of armor and weapons so that I might create custom objects. I would like to overcome certain difficulties in dealing with player enchantments. For instance, while testing Quick Stash I discovered that a player enchanted silver ring is counted as a silver ring while iterating over the contents of a container. I also discovered that SkyUI's Focus Group Feature does not recognize the difference between a silver ring and a player enchanted silver ring. I had made the mistake of enchanting several silver rings with different enchantments to be equipped with focus groups and discovered my rings weren't switching.

It may seem simple enough to remember this fact and to always use different rings for enchanting, but I don't like the limitation and I feel that it would be useful to come up with a way of overcoming this limitation through papyrus scripting. I have an idea involving blank base items that get filled out with other item's data in order to become completely unique items at the base level and therefore overcome the limitation. I am currently working on that feature and intend to release it separately one I got it worked out. I think I will call it, Gear Saver.

User avatar
Jessie Butterfield
 
Posts: 3453
Joined: Wed Jun 21, 2006 5:59 pm

Post » Sun May 18, 2014 2:00 am

I just released an skse plugin, which adds the following functions to papyrus:

GetNumItemsWithKeyword(Keyword Key, bool getTotalCount = false)

and

GetNthFormWithKeyword(Keyword Key, int KeywordIndex)

Both functions run as fast as GetNumItems() and GetNthForm(Int Index)

After discovering your discussion here i thought they might be usefull for you..

http://www.nexusmods.com/skyrim/mods/53320/?

User avatar
Je suis
 
Posts: 3350
Joined: Sat Mar 17, 2007 7:44 pm

Post » Sun May 18, 2014 3:19 am

I am not sure that I can have a use for these yet, but I will keep them in mind. They may be useful to others who are considering this type of problem.

Thank you for your consideration.

User avatar
Eire Charlotta
 
Posts: 3394
Joined: Thu Nov 09, 2006 6:00 pm

Post » Sat May 17, 2014 11:24 pm

The concept of Gear Saver is proving to be a difficult task. It seems that I would have to create a blank item for every armor slot keyword and material type as well as create corresponding armor addons and tempering constructible objects.

I discovered that items without armor slot keywords cannot be enchanted. The Enchanter lets you select the item, but it does not let you set any enchantments. I added the keyword ArmorBoots and discovered I could then enchant the item with http://www.uesp.net/wiki/Skyrim:Enchanting_Effects. There is no SKSE function for adding keywords to an item so this means the keywords have to be set in the CK.

Armor Slot Keywords:

  • ArmorBoots
  • ArmorCuirass
  • ArmorGuantlets
  • ArmorHelmet
  • ArmorShield
  • ClothingBody
  • ClothingCirclet
  • ClothingFeet
  • ClothingHands
  • ClothingHead
  • ClothingNecklace
  • ClothingRing

I have tested each of these individually to see if they all relate to enchanting. I wouldn't say that some of these are completely redundant (like ArmorHelmet, ClothingCirclet and ClothingRing), but as far as enchanting is concerned they are. So this begs the question: How else are these keywords used (other than http://www.creationkit.com/Armor_Script#SKSE_Member_Functions that use these keywords internally)? If it doesn't cause problems, could reduce the list to:

  1. ArmorBoots
  2. ArmorCuirass
  3. ArmorHelmet
  4. ArmorShield
  5. ClothingNecklace
  6. ClothingRing

Material Type Keywords:

  • ArmorMaterialBearStormcloak
  • ArmorMaterialBlades (as in the faction)
  • ArmorMaterialDaedric
  • ArmorMaterialDragonplate
  • ArmorMaterialDragonscale
  • ArmorMaterialDwarven (Dwarven/Dwemer... vanilla assets should stick to one!)
  • ArmorMaterialEbony
  • ArmorMaterialElven
  • ArmorMaterialElvenGilded
  • ArmorMaterialFalmer
  • ArmorMaterialForsworn
  • ArmorMaterialGlass
  • ArmorMaterialHide
  • ArmorMaterialImperialHeavy
  • ArmorMaterialImperialLight
  • ArmorMaterialImperialStudded
  • ArmorMaterialIron
  • ArmorMaterialIronBanded
  • ArmorMaterialLeather
  • ArmorMaterialMS02Forsworn
  • ArmorMaterialOrchish
  • ArmorMaterialPenitus
  • ArmorMaterialScaled
  • ArmorMaterialSteel
  • ArmorMaterialSteelPlate
  • ArmorMaterialStormcloak
  • ArmorMaterialStudded (Oddly, this one isn't used by a matching set perk. There may be more like that.)
  • ArmorMaterialThievesGuild (No related tempering recipe that I could find)
  • ArmorMaterialTheivesGuildLeader

Besides these, more are added by armor mods. I didn't even cover DLC Content and there may be more that aren't prefixed as ArmorMaterial. Keywords are necessary for perks for matching sets. I was thinking that I could reduce the number of combinations to focus solely on materials used in tempering recipes, until I noticed that some tempering recipes have more than one material requirement (I haven't gotten around to smithing in game yet.). Then again I could focus it down some. Possibly with the following catagories:

  1. Iron
  2. Leather
  3. Steel
  4. Elven
  5. Advanced
  6. Glass
  7. Dragon
  8. Dwarven
  9. Orchish
  10. Ebony
  11. Daedric

It should also be noted that not all vanilla items falling in the above categories require all the same materials in order to temper. One example is the the Daedric Shield, which only required Ebony, where a Daedric Helmet also requires a Daedra Heart and Leather Strips.

That still means that I will have to create at least 44 blank base items and 44 tempering recipes for these blank items. Already I have given up on the idea of Gear Saver, which would merely be a basic version of a more advanced idea I am (was?) working on for copying one items appearance while using another items stats. I know there are mods that are based on WoW's Transmogrify concept, but I found their limitations or implementations lacking. I am learning that some of these limitations exist for reasons other than simply how it worked in WoW.

WEAPONS!!! I have only been digging into armor and speaking about armor. I have not even touched on weapons yet. So to include weapons the number of blank base items and tempering recipes goes up.

Not wanting to give up on my advanced concept, which I intend to call Hallowed Smithing (this name seems to be unique at the moment). I could make all Hallowed items require a limited set of materials and justify this with the idea that the Hallowing changes the tempering requirements. Although I have to set a limit on the number of Hallowed Items the player can have, I wanted to at least make it so that the player can have multiple items for each gear slot. Personally, I would like to use SkyUI's Focus group to equip items with different enchantments depending on how I am about to attack or what spells I am planning to cast or even what kind of attacks or spells are being directed at me. This is one of the main reasons I decided to move towards this basic concept in the first place.

Other than the considerations for player enchanting and tempering, the number of base blank forms has to be limited for the obvious reason that they have to be created in the CK. The idea in-game is that the Hallowing "creates a connection" between the items and the player and that there can only be so many. But this raises another issue. Once the limit is reached how do I release previously hallowed forms from the connection? I answered this with "breaking the connection destroys the item." The Hallowed Smithing is to be handled by a single NPC. In order to justify this in game in an immersive way, He will need the item returned to him in order to break the connection.

Given these limitations and justifications, Problems could arise from the player losing Hallowed items. I can easily prevent Hallowed Items from being sold by not adding Vendor Keywords. Setting the gold value to 0 would remove the player's incentive to sell the items, but selling to vendors is not the only way to lose an item. I could force the items into an alias and I had even considered making them quest items so that they could be located through quest markers if the player happens to loose track of where he stored one, but I'd also like to be able to give Hallowed Items to followers (another reason for wanting to have multiple sets).

Giving items to followers has been known as a way of losing items too. Sometimes it's as if the follower's inventory is completely reset or something. I have seen specifically body slot items and cloaks vanish. I was surprised the last time I lost Lydia that she didn't "eat" any gear items. I swear I left her in the inn in Winterhold waiting, but I found her in Dragonsreach and had to "hire" her again.

Nothing I can think of will resolve this issue of needing to know what has become of a Hallowed Item before I can justify "breaking the connection." Simply, which item of all the items that are currently in use would I choose and why if not simply hand-picked by the player to be "recycled" into a new Hallowed Item? If I can't prevent Hallowed Items from being lost forever then potentially I could run out of items to be recycled.

I don't know how other mod authors are handling this concept or if they have even ruled out these kinds of complications.

Arriving at this point in the writing... which is mostly a self dialogue with elements of research and project documentation... I stopped to go dig up the mods which similar concepts.

http://www.nexusmods.com/skyrim/mods/33902/? It doesn't require patches for mod added items, but does not use new base forms thus NPCs would end up using the changed items.

http://www.nexusmods.com/skyrim/mods/50773/? Seems to use new base forms, but requires patches for mod added items.

There was another (that I can't find right now) that allowed you to make the items at the tanning rack, but this would require patches for mod added items--not to mention the tedium of creating recipes for every possible combination by hand.

Is there some way to possibly wear items that would essentially hide the worn armor and thus achieve the ultimate goal of having the look you want with stats you need without altering the base forms of existing items?

If I could overcome the issue of lost items then I could move forward with this concept as is.

I am open to suggestions. I posted this here because this is directly related to my research into handling inventory items. I am also open to other suggestion related to inventory items and reducing time spent in inventory management.

Edit: fixed the link to Transmogrification - Copy Armor Stats by Dienes

User avatar
Dalton Greynolds
 
Posts: 3476
Joined: Thu Oct 18, 2007 5:12 pm

Post » Sun May 18, 2014 6:08 am

Hello and welcome to my madness as of about one year ago.

First trying to create blank objects by hand lies even more madness and also repetitive stress injury and mod incompatibility. A skyproc patcher is perfect for that though. Either internally that you use and then just release the created esp or that you release so users can run on their load order and it makes compatible with their mods as well.

Second is that blank armors aren't really a solution to transmogrifying armors anyway since there is no way to add armor addons to an armor. So you can't properly make your blank armor look like whatever armor it is transmuted into. I believe armor addons suffer the same problem that keywords do that the skse people aren't certain they can safely modify them without breaking other stuff which is why there aren't already add or remove functions. You could request they look into it again but be polite and don't get your hopes up.

Weapons however are less unreasonable. They don't have addons so skse can correctly modify nearly everything about them (no keywords and in the 1.7.0 beta setResist() function crashes the game if you pass it none which is what most weapons use as their resist type). I've got a mod in the works that does some cool things with them if I ever get some bugs worked out / beta testers ever beta test.

For keeping the items one option would be for the vendor/blacksmith npc to offer to recall missing items for a fee. When the item is created force it into an alias. Delete the item in the alias and create a new one and give that one to the player. Its quite hard to track where a specific item is because of how papyrus and the game work plus an outstanding bug with persistent ObjectReferences and containers so faking it is easier. Just have the NPC explain that recalling the item will blah blah no tempering or enchantments.

In conclusion skyrim is not a game we play but a game the devs are playing in which we are the pieces and they win when we go mad.

User avatar
Cesar Gomez
 
Posts: 3344
Joined: Thu Aug 02, 2007 11:06 am

Post » Sun May 18, 2014 10:27 am

The problem is knowing if an item is lost or identifying the lost item. For where I am standing having the item is key to "recycling" it. I intend to handle a list of items and I can't see anyway of differentiating them.

As for the armor addon problem. It seems to me that I have that covered. I just discovered one feature that I hadn't realized would be an issue. I discovered it while examining an armor addon for the forsworn helmet. It has Additional Races for Khajiit and Argonian. I could simply deny the user the ability to copy the properties of that piece. Unless.... GetModelNthTextureSet is pointing at Nth Additonal Races Model Paths... Other than that business... you don't have to set ArmorAddons... I use blank armor addons and set their properties.

Here's a Basic Clone Function I was testing. It basically clones all aspects that I was aware of when I wrote it and gets called on Maintenance to refresh it settings.

Spoiler
Function Clone_Armor(Armor origin, Armor dest, String Name)    ; GET Values ========================================================================    int AR              = origin.GetAR()    int WC              = origin.GetWeightClass()    string MPM          = origin.GetModelPath(false)    string MPF          = origin.GetModelPath(true)    int slotmask        = origin.GetSlotMask()    Enchantment Ench    = origin.GetEnchantment()           ; SET Values ========================================================================    dest.SetAR(AR)    dest.SetWeightClass(WC)    dest.SetModelPath(MPM,false)    if MPF        dest.SetModelPath(MPF,true)    endif    dest.SetSlotMask(slotmask)    if Ench        dest.SetEnchantment(Ench)    endif    dest.SetName(Name)       ; Handle Armor Addon ================================================================    ;   Supposedly there is only 1...    ;       Additional Races cannot be set, maybe that won't be a problem    ;       Texture Sets... why is there functions for this? I don't see this in the CK.    ArmorAddon AA      = origin.GetNthArmorAddon(0)    string AAMP_M_FP   = AA.GetModelPath(true,false)    string AAMP_F_FP   = AA.GetModelPath(true,true)    string AAMP_M      = AA.GetModelPath(false,false)    string AAMP_F      = AA.GetModelPath(false,true)    int AAslotmask     = AA.GetSlotMask()    ArmorAddon AAC     = dest.GetNthArmorAddon(0)    if AAMP_M_FP        AAC.SetModelPath(AAMP_M_FP, true, false)    endif    if AAMP_F_FP        AAC.SetModelPath(AAMP_F_FP, true, true)    endif    if AAMP_M        AAC.SetModelPath(AAMP_M, false, false)    endif    if AAMP_F        AAC.SetModelPath(AAMP_F, false, true)    endif    AAC.SetSlotMask(AAslotmask)    ; DONE ==============================================================================EndFunction

Edit: You can see where I had questions about some functions in the comments. That was copied fresh out of the Maintenance Quest Script. I tested it yesterday.

Edit: Again... Nevermind I was confused about what Additional Races meant. I still don't get the http://www.creationkit.com/ArmorAddon_Script... They aren't documented yet. At any rate, I can certainly check to see what additional races are set and see if an armor addon excludes a "required" race.

User avatar
Love iz not
 
Posts: 3377
Joined: Sat Aug 25, 2007 8:55 pm

Post » Sun May 18, 2014 8:25 am

I just noticed the Show All checkbox on the Armor Form Dialogue next to the Armor Addon Pane. When Looking at the Forsworn Helmet (000D8D52), it shows the other two armor addons that are designed individually for Argonians and Khajiits. My example above doesn't iterate over Armor Addons nor does it check to see if there is more than one. I had assumed there was only one to deal with, since I had not seen any armor with more than one Armor Addon. Rather than work around this problem, I could simply exclude it from the being used as a visual template, OR I could simply ignore Armor Addons for other races and hope it doesn't clip. I'd rather not create 3 armor addons per blank armor item.

User avatar
Shelby McDonald
 
Posts: 3497
Joined: Sat Jan 13, 2007 2:29 pm

Post » Sat May 17, 2014 11:03 pm

Bam! It just hit me. Have all the "recall options" displayed in a Barter Menu. Fee is a temporary Item value and that's how the service is charged as well as it gives the player an immersive way to recognize what he is missing. This completely solves the issue of lost Hallowed Items.

User avatar
Chavala
 
Posts: 3355
Joined: Sun Jun 25, 2006 5:28 am

Post » Sat May 17, 2014 9:46 pm

Using blank ArmorAddons and filling them in is a solution but kinda a partial one. Most armors only use one Addon but some use multiple, usually for racial variants but I think not always. And often but not always the general one is first but sometimes it can be in any position so you can't just assume. I believe I've seen armors that used multiple addons to construct the actual armor and not just racial alternatives so if you only copied one of them you would only get part of the look.

You also need to copy all the other info about the Armor addon or it won't work right. You have to loop through the Additional races or the armor won't show up on them or might not even equip at all for them, same with texture sets but you will need to loop for first person = true, female = true, and both = true. I'm pretty sure textureSets refer to the male/female world model MO2S entries in tesedit. Not sure what they are in the ck. I don't recall what they do exactly but I do remember an issue with lootification not setting them right and it messing up a mod and having to fix it at one point.

User avatar
Steven Hardman
 
Posts: 3323
Joined: Sun Jun 10, 2007 5:12 pm

Post » Sun May 18, 2014 11:48 am

I was avoiding the addition races part by defining that in blank object's Armor Addon. Like I said the other Armor Addon's was a gotcha for me.

My example shows the textures sets being copied. It's the GetModelNthTextureSet and related functions that get me. I can't find anything that could be referencing in the CK. The Forsworn helmet has Armor Addons for 2 races that aren't covered in primary Armor Addon and those point to different... shall we say... worn models. It was a gotcha for me when I first started testing a blank armor that I needed to set an Armor Addon and set the paths for them in order for them to show on the character. I totally missed the fact that the paths on the Armor Form where merely the world object models. Once I set those then boots I was testing actually showed up.

About armor that uses multiple armor addons to create it's appearance. I just did that as a test to see if I could. I combined the forsworn Helmet, Cuirass, Boots and Gauntlets into one armor piece for with no other values set than the visuals as a test to see if I could do it and if that could be the part of the solution to an armor that could cover up the functional pieces. I have already tested using 2 items worn at the same time as boots. One for the appearance and the other for the stats. (I going to start calling the appearance piece the vanity armor... got the idea for Allods Online.)

There is a catch to this method. With the functional armor not having any armor addons, one could essentially where as many under the vanity as you have. I have tested this with the boots. What just came to mind and I have not tested is what would happen if I attached an armor addon with no visual data set. My original idea (and I tested this) was using a script attached to the stat armor (sounds like a good term) to check for potential stat armor stacking. It worked as implemented, but my test was only handling the potential of a copy of itself being stacked. I am sure I could expand that concept, but I'd rather not have to if I can find a "cleaner" solution to preventing the stacking.

I was aware of the potential for stacking because I have some broken masks (bandanas worn on the face) which I believe was introduced into my game by OBIS. I discovered that they didn't have any armor addons. I already new they were invisible and that was one of the reasons I investigated them. I have a test key which I use to scan my inventory or the contents of containers and display data relevant to Armor and Weapons--well not all, as I am finding out. After I had added the code to gather Armor Addon data, I checked my logs for info on those bandanas. Using this key (not really a key much like my Quick Stash key), I was able to discover other craziness with slotmasks defined in armor forms (which is what I was looking for in the first place). I actually have this wacky function that breaks down the slot masks to determine what slots are combined:

Spoiler
Function Slot_Mask_Info(int _mask_, int tabs = 0)    int mask_check = _mask_    int slot_check = 0x40000000    String Slots = ""    ; Print("MASK FUNC " + _mask_ + " AND " + slot_check )    While _mask_ > 0        if _mask_ > slot_check            ; Print("MASK FUNC " + _mask_ + " > " + slot_check)            _mask_ -= slot_check            mask_check = slot_check            slot_check /= 2        elseif _mask_ == slot_check            ; Print("MASK FUNC " + _mask_ + " == " + slot_check)            _mask_ = 0 ; end of the line            mask_check = slot_check        else            ; Print("MASK FUNC " + _mask_ + " ELSE " + slot_check)            slot_check /= 2            mask_check = 0        endif        if mask_check            if      mask_check == 0x80000000 ; can't use this number... it's too big. It becomes a negative.                Slots += "(61) FX01, "            elseif  mask_check == 0x40000000                Slots += "(60) misc/FX*, "            elseif  mask_check == 0x20000000                Slots += "(59) right arm*, "            elseif  mask_check == 0x10000000                Slots += "(58) left arm*, "            elseif  mask_check == 0x08000000                Slots += "(57) shoulder*, "            elseif  mask_check == 0x04000000                Slots += "(56) chest 2nd*, "            elseif  mask_check == 0x02000000                Slots += "(55) face alt*, "            elseif  mask_check == 0x01000000                Slots += "(54) left leg*, "            elseif  mask_check == 0x00800000                Slots += "(53) right leg*, "            elseif  mask_check == 0x00400000                Slots += "(52) pelvis 2nd*, "            elseif  mask_check == 0x00200000                Slots += "(51) deprecated, "            elseif  mask_check == 0x00100000                Slots += "(50) deprecated, "            elseif  mask_check == 0x00080000                Slots += "(49) pelvis 1st*, "            elseif  mask_check == 0x00040000                Slots += "(48) misc/FX*, "            elseif  mask_check == 0x00020000                Slots += "(47) back*, "            elseif  mask_check == 0x00010000                Slots += "(46) chest 1st*, "            elseif  mask_check == 0x00008000                Slots += "(45) neck*, "            elseif  mask_check == 0x00004000                Slots += "(44) face/mouth*, "            elseif  mask_check == 0x00002000                Slots += "(43) ears, "            elseif  mask_check == 0x00001000                Slots += "(42) circlet, "            elseif  mask_check == 0x00000800                Slots += "(41) long hair, "            elseif  mask_check == 0x00000400                Slots += "(40) tail, "            elseif  mask_check == 0x00000200                Slots += "(39) shield, "            elseif  mask_check == 0x00000100                Slots += "(38) calves, "            elseif  mask_check == 0x00000080                Slots += "(37) feet, "            elseif  mask_check == 0x00000040                Slots += "(36) ring, "            elseif  mask_check == 0x00000020                Slots += "(35) amulet, "            elseif  mask_check == 0x00000010                Slots += "(34) forearms, "            elseif  mask_check == 0x00000008                Slots += "(33) hands, "            elseif  mask_check == 0x00000004                Slots += "(32) body (full), "            elseif  mask_check == 0x00000002                Slots += "(31) hair, "            elseif  mask_check == 0x00000001                Slots += "(30) head"            else                Slots += " ???? "            endif        endif    EndWhile    Print("Slots: " + Slots + "["+_mask_+"]", 3 + tabs)EndFunction

TL;DR (long story short)

  • I don't need the Hallowed items to be "permanent", Solved with the retrieval function (Thanks Dienes)
  • I would like a method for user input to name the items.
  • I am testing the concept of layering vanity pieces over stat pieces as a way to consolidate vanity while keeping stat items modular.
    • Layering introduces it's own catches, but I want to do more testing to see what I can come up with.
  • The Armor Addon problem is not yet fully fleshed. Gears are turning. Gotchas acquired. (Thanks Dienes)
  • Tempering patterns remain tedious, but I intend to focus them.
  • I have no experience with SkyProc. It feels like a bit too technical for users. Hopefully this doesn't become high maintenance. I can't be expected to solved for all armor mods. I hope to catch a resonable set and I am currently using Hothtrooper44's Immersive Armors and Immersive Weapons, as well as Cloaks of Skyrim to cover a large range of potential issues.
User avatar
sally R
 
Posts: 3503
Joined: Mon Sep 25, 2006 10:34 pm

Post » Sun May 18, 2014 12:40 pm

In SkyUI, you'll have to rename the item when enchanting it. Then it is distinguished from other items with the same base form.
User avatar
Elizabeth Falvey
 
Posts: 3347
Joined: Fri Oct 26, 2007 1:37 am

Post » Sun May 18, 2014 5:03 am

I did rename the items. I still didn't equip them with the focus group hot key. Maybe SkyUI has a way of distinguishing the items that is not accessable in Papyrus. I am under the impression that it uses Flash (I am assuming as in Adobe Flash I have just read things in forums.). My test didn't work out.

User avatar
Veronica Martinez
 
Posts: 3498
Joined: Tue Jun 20, 2006 9:43 am

Post » Sun May 18, 2014 10:44 am

Hm well, when I tested it last, it worked. If you have already assigned the item to a group, you'll have to re-assign it after you renamed it.

To uniquely identify custom items so called item IDs are used. They are calculated as the CRC32 of the item name and the base formid. The relevant SKSE functions are
Actor.EquipItemById/GetEquippedItemId/GetWornItemId

Each SkyUI favorites group consists of a list of item IDs, which are equipped using EquipItemById.
User avatar
Daniel Lozano
 
Posts: 3452
Joined: Fri Aug 24, 2007 7:42 am

Post » Sun May 18, 2014 9:52 am

I didn't already have a silver ring assigned to favorites. I had a named player enchanted silver ring assigned already when I created two more named player enchanted silver rings and assigned them to different focus groups. I take your word for it. I could simply be mistaken. You seem to know what you are talking about. I reverted to a previous save then decided to start working on the current project after this happened.

Fail Test as inspiration to mod. Oh well. I still want to work on my Hallowed Smithing concept. =D

Edit: All three rings had different names.

Edit Again: After a second look at the functions you listed. I realized... I didn't actually equip two new rings before testing. Maybe it simply didn't have the unique IDs because I had never equipped them.

User avatar
Russell Davies
 
Posts: 3429
Joined: Wed Nov 07, 2007 5:01 am

Post » Sun May 18, 2014 6:08 am

It might also very well be broken. I'll test it again later. I did most of my testing on smithing, since different improved variants of the same weapon have the same problem. I didn't really do that much testing for enchanted armor.

/E: Ok, tested with two enchanted rings, it's not working
User avatar
jess hughes
 
Posts: 3382
Joined: Tue Oct 24, 2006 8:10 pm

Post » Sun May 18, 2014 5:56 am

Did you try equipping the item manually after it was favorited before testing? I am sure I didn't test that.

User avatar
Sarah Bishop
 
Posts: 3387
Joined: Wed Oct 04, 2006 9:59 pm

Post » Sun May 18, 2014 1:17 pm

Yes, it is definitely not working. Lucky for me, the problem is not related to SKSE though.

There was this bug that resulted in incorrect damage when equipping a weapon in a slot that previously held a weapon of the same type. I was not able to figure out why that happened. IIRC calling unequip from native code before didn't help either. So if this case is detected, EquipItemById bails out. This condition is also triggered in the ring case (same type, same slot, different item).
The responsible part of EquipItemById:
Spoiler

		if (hasItemMinCount)		{			// Case 1: Type already equipped in both hands.			if (itemData.isTypeWorn && itemData.isTypeWornLeft)			{				isTargetSlotInUse = true;			}			// Case 2: Type already equipped in right hand.			else if (itemData.isTypeWorn)			{				isTargetSlotInUse = targetEquipSlot == GetRightHandSlot() || targetEquipSlot == NULL;			}			// Case 3: Type already equipped in left hand.			else if (itemData.isTypeWornLeft)			{				isTargetSlotInUse = targetEquipSlot == GetLeftHandSlot();			}			// Case 4: Type not equipped yet.			else			{				isTargetSlotInUse = false;			}		}		// This also returns if the target slot is in use by another weapon of the same type.		// Could handle this, but switching them here causes a bug (0 damage) for some reason.		// So we just skip it. Can be handled on the Papyrus side.		if (isTargetSlotInUse || !hasItemMinCount)			return;

(As you can tell from the comments, I primarily tested that with weapons.)

The workaround is to handle this on the Papyrus side by detecting the case and calling unequip first. For weapons, it's done properly:
Spoiler

				if (a_item == PlayerREF.GetEquippedObject(kHand) && a_itemId != PlayerREF.GetEquippedItemId(kHand))					UnequipHand(kHand) ; same type, different item => unequip first avoid damage-related bug when swapping for enhanced item				endIf


But for armor, this part was missing. To fix it, change SKI_FavoritesManager.psc, line 789ff, to
		; It's not a shield, just equip it if slot is free		elseIf (! LogicalAnd(_usedOutfitMask,slotMask))+			if (a_item == PlayerREF.GetWornForm(slotMask) && a_itemId != PlayerREF.GetWornItemId(slotMask))+				PlayerREF.UnequipItemEx(a_item)+			endIf						PlayerREF.EquipItemById(a_item, a_itemId, equipSlot = 0, equipSound = _silenceEquipSounds)			_usedOutfitMask += slotMask		endIf		return true
(Note: During my tests, it sometimes failed to equip the new ring but only unequipped the old one. Probably a timing issue between unequip and equip?)
User avatar
David Chambers
 
Posts: 3333
Joined: Fri May 18, 2007 4:30 am

Post » Sat May 17, 2014 9:49 pm

After testing, I have determined I can work out the layering concept, but the method is proving to be too elusive, unnatural and cumbersome to implement. I don't even wish to spread this disease upon the community. Stadards exist to keep things compatible and it would break immersion to add such an alien concept to the inventory screen. I use SkyUI. I have from the first time I ran the game. I don't have any clue what this looks like in the vanilla inventory menu, but in SkyUI it's terrible.

Short version: Layering Concept is bad. Mmmkay.

User avatar
Sophie Morrell
 
Posts: 3364
Joined: Sat Aug 12, 2006 11:13 am

Post » Sun May 18, 2014 9:09 am

Next Step: Seeing if I can Clone the Forsworn Helmet (Forsworn Headress) without leaving out the Armor Addons for the the Argonian and Khajiit races.

User avatar
Lilit Ager
 
Posts: 3444
Joined: Thu Nov 23, 2006 9:06 pm

Post » Sun May 18, 2014 1:34 pm

@ schlangster

I hadn't noticed you're the mod Author of SkyUI. :sweat:

Are you suggesting that I make the change and compile or do you intend to release an Update for SkyUI?

Edit: Nevermind. That file is not in my source.

User avatar
Conor Byrne
 
Posts: 3411
Joined: Wed Jul 11, 2007 3:37 pm

Post » Sun May 18, 2014 12:52 pm

I don't think there will be an update in the near future, so I just posted that quick fix here for the time being.

Regarding the script sources, they are packaged in SkyUI.bsa. But you can find them here as well: https://github.com/schlangster/skyui/tree/master/dist/Data/Scripts/Source

Oh, and thanks for making me aware of the problem in the first place :smile:
User avatar
Natasha Callaghan
 
Posts: 3523
Joined: Sat Dec 09, 2006 7:44 pm

Post » Sun May 18, 2014 1:33 pm

Doh. Didn't think to look in the BSA. I have unpacked scripts from there, so it's not a new concept for me. GitHub works too... too bad it didn't detect my Skyrim install and put them there for me. :tongue:

I have changed and compiled. Thanks. :D

User avatar
Catharine Krupinski
 
Posts: 3377
Joined: Sun Aug 12, 2007 3:39 pm

PreviousNext

Return to V - Skyrim