scriptname SKI_FavoritesManager extends SKI_QuestBase import Math ; SCRIPT VERSION ---------------------------------------------------------------------------------- ; ; History ; ; 1: - Initial version ; ; 2: - Added check for vampire lord ; ; 3: - Less eagerly clearing of invalid entries ; ; 4: - EDC - Added repeat find to InvalidateItem() int function GetVersion() return 4 endFunction ; CONSTANTS --------------------------------------------------------------------------------------- string property FAVORITES_MENU = "FavoritesMenu" autoReadonly string property MENU_ROOT = "_root.MenuHolder.Menu_mc" autoReadonly int property GROUP_FLAG_UNEQUIP_ARMOR = 1 autoReadonly int property GROUP_FLAG_UNEQUIP_HANDS = 2 autoReadonly ; PROPERTIES -------------------------------------------------------------------------------------- ; -- Version 1 -- Actor Property PlayerREF auto bool property ButtonHelpEnabled = true auto int property GroupAddKey int function get() return _groupAddKey endFunction function set(int a_val) SwapControlKey(a_val, _groupAddKey) _groupAddKey = a_val endFunction endProperty int property GroupUseKey int function get() return _groupUseKey endFunction function set(int a_val) SwapControlKey(a_val, _groupUseKey) _groupUseKey = a_val endFunction endProperty int property SetIconKey int function get() return _setIconKey endFunction function set(int a_val) SwapControlKey(a_val, _setIconKey) _setIconKey = a_val endFunction endProperty int property SaveEquipStateKey int function get() return _saveEquipStateKey endFunction function set(int a_val) SwapControlKey(a_val, _saveEquipStateKey) _saveEquipStateKey = a_val endFunction endProperty int property ToggleFocusKey int function get() return _toggleFocusKey endFunction function set(int a_val) SwapControlKey(a_val, _toggleFocusKey) _toggleFocusKey = a_val endFunction endProperty ; PRIVATE VARIABLES ------------------------------------------------------------------------------- ; -- Version 1 -- Form[] _items1 Form[] _items2 int[] _itemIds1 int[] _itemIds2 int[] _groupFlags Form[] _groupMainHandItems int[] _groupMainHandItemIds Form[] _groupOffHandItems int[] _groupOffHandItemIds Form[] _groupIconItems int[] _groupIconItemIds bool _silenceEquipSounds = false SoundCategory _audioCategoryUI ; Forms to support EquipSlot comparisons EquipSlot _rightHandSlot EquipSlot _eitherHandSlot EquipSlot _leftHandSlot EquipSlot _bothHandsSlot EquipSlot _voiceSlot ; State variables for Group Use bool _usedRightHand = false bool _usedLeftHand = false bool _usedVoice = false int _usedOutfitMask = 0 ; Keys int _groupAddKey = 33 ; F int _groupUseKey = 19 ; R int _setIconKey = 56 ; LAlt int _saveEquipStateKey = 20 ; T int _toggleFocusKey = 57 ; Space int[] _groupHotkeys ; -- Version 2 -- Race _vampireLordRace ; -- Version 3 -- bool[] _itemInvalidFlags1 bool[] _itemInvalidFlags2 ; INITIALIZATION ---------------------------------------------------------------------------------- event OnInit() _items1 = new Form[128] _items2 = new Form[128] _itemIds1 = new int[128] _itemIds2 = new int[128] _groupFlags = new int[8] _groupMainHandItems = new Form[8] _groupMainHandItemIds = new int[8] _groupOffHandItems = new Form[8] _groupOffHandItemIds = new int[8] _groupIconItems = new Form[8] _groupIconItemIds = new int[8] _groupHotkeys = new int[8] _groupHotkeys[0] = 59 ; F1 _groupHotkeys[1] = 60 ; F2 _groupHotkeys[2] = 61 ; F3 _groupHotkeys[3] = 62 ; F4 _groupHotkeys[4] = -1 _groupHotkeys[5] = -1 _groupHotkeys[6] = -1 _groupHotkeys[7] = -1 _audioCategoryUI = Game.GetFormFromFile(0x00064451, "Skyrim.esm") as SoundCategory _rightHandSlot = Game.GetFormFromFile(0x00013f42, "Skyrim.esm") as EquipSlot _leftHandSlot = Game.GetFormFromFile(0x00013f43, "Skyrim.esm") as EquipSlot _eitherHandSlot = Game.GetFormFromFile(0x00013f44, "Skyrim.esm") as EquipSlot _bothHandsSlot = Game.GetFormFromFile(0x00013f45, "Skyrim.esm") as EquipSlot _voiceSlot = Game.GetFormFromFile(0x00025bee, "Skyrim.esm") as EquipSlot OnGameReload() endEvent ; @implements SKI_QuestBase event OnGameReload() CheckVersion() RegisterForModEvent("SKIFM_groupAdd", "OnGroupAdd") RegisterForModEvent("SKIFM_groupRemove", "OnGroupRemove") RegisterForModEvent("SKIFM_groupUse", "OnGroupUse") RegisterForModEvent("SKIFM_saveEquipState", "OnSaveEquipState") RegisterForModEvent("SKIFM_setGroupIcon", "OnSetGroupIcon") RegisterForModEvent("SKIFM_foundInvalidItem", "OnFoundInvalidItem") RegisterForMenu(FAVORITES_MENU) RegisterHotkeys() CleanUp() endEvent ; @implements SKI_QuestBase event OnVersionUpdate(int a_version) ; Version 2 if (a_version >= 2 && CurrentVersion < 2) Debug.Trace(self + ": Updating to script version 2") ;_vampireLordRace = Game.GetFormFromFile(0x0000283A, "Dawnguard.esm") as Race endIf ; Version 3 if (a_version >= 3 && CurrentVersion < 3) Debug.Trace(self + ": Updating to script version 3") _itemInvalidFlags1 = new bool[128] _itemInvalidFlags2 = new bool[128] endIf ; Version 4 if (a_version >= 4 && CurrentVersion < 4) Debug.Trace(self + ": Updating to script version 4") endIf endEvent ; EVENTS ------------------------------------------------------------------------------------------ event OnMenuOpen(string a_menuName) int i = 0 while (i < 128) _itemInvalidFlags1[i] = false i += 1 endWhile i = 0 while (i < 128) _itemInvalidFlags2[i] = false i += 1 endWhile InitControls() InitMenuGroupData() endEvent event OnFoundInvalidItem(string a_eventName, string a_strArg, float a_numArg, Form a_sender) InvalidateItem(a_strArg as int,true) endEvent event OnGroupAdd(string a_eventName, string a_strArg, float a_numArg, Form a_sender) int groupIndex = a_numArg as int int itemId = a_strArg as int Form item = a_sender if (GroupAdd(groupIndex, itemId, item)) UpdateMenuGroupData(groupIndex) else UI.InvokeBool(FAVORITES_MENU, MENU_ROOT + ".unlock", true) Debug.Notification("Group full!") endIf endEvent event OnGroupRemove(string a_eventName, string a_strArg, float a_numArg, Form a_sender) int groupIndex = a_numArg as int int itemId = a_strArg as int if (GroupRemove(groupIndex, itemId)) UpdateMenuGroupData(groupIndex) else UI.InvokeBool(FAVORITES_MENU, MENU_ROOT + ".unlock", true) endIf endEvent ; Read the player's current equipment and save it to the target group event OnSaveEquipState(string a_eventName, string a_strArg, float a_numArg, Form a_sender) int groupIndex = a_numArg as int int mainHandItemId = UI.GetInt(FAVORITES_MENU, MENU_ROOT + ".rightHandItemId") int offHandItemId = UI.GetInt(FAVORITES_MENU, MENU_ROOT + ".leftHandItemId") form mainHandForm = GetFormFromItemId(groupIndex,mainHandItemId) ; will return none if not in group if (mainHandForm) _groupMainHandItemIds[groupIndex] = mainHandItemId _groupMainHandItems[groupIndex] = mainHandForm else _groupMainHandItemIds[groupIndex] = 0 _groupMainHandItems[groupIndex] = none endIf form offHandForm = GetFormFromItemId(groupIndex,offHandItemId) if (offHandForm) _groupOffHandItemIds[groupIndex] = offHandItemId _groupOffHandItems[groupIndex] = offHandForm else _groupOffHandItemIds[groupIndex] = 0 _groupOffHandItems[groupIndex] = none endIf UpdateMenuGroupData(groupIndex) endEvent ; This will set a form as the icon form for a group event OnSetGroupIcon(string a_eventName, string a_strArg, float a_numArg, Form a_sender) int groupIndex = a_numArg as int int itemId = a_strArg as int Form item = a_sender _groupIconItems[groupIndex] = item _groupIconItemIds[groupIndex] = itemId UpdateMenuGroupData(groupIndex) endEvent event OnGroupUse(string a_eventName, string a_strArg, float a_numArg, Form a_sender) gotoState("PROCESSING") GroupUse(a_numArg as int) gotoState("") endEvent event OnKeyDown(int a_keyCode) gotoState("PROCESSING") int groupIndex = _groupHotkeys.Find(a_keyCode) if (groupIndex != -1 && !Utility.IsInMenuMode()) GroupUse(groupIndex) endIf gotoState("") endEvent state PROCESSING event OnGroupUse(string a_eventName, string a_strArg, float a_numArg, Form a_sender) endEvent event OnKeyDown(int a_keyCode) endEvent endState ; FUNCTIONS --------------------------------------------------------------------------------------- ;get whether a flag is set for the specified group bool function GetGroupFlag(int a_groupIndex, int a_flag) return LogicalAnd(_groupFlags[a_groupIndex], a_flag) as bool endFunction ;set a flag for the specified group function SetGroupFlag(int a_groupIndex, int a_flag, bool a_value) if (a_value) _groupFlags[a_groupIndex] = LogicalOr(_groupFlags[a_groupIndex], a_flag) else _groupFlags[a_groupIndex] = LogicalAnd(_groupFlags[a_groupIndex], LogicalNot(a_flag)) endIf endFunction int[] function GetGroupHotkeys() ; Return a copy int[] result = new int[8] int i = 0 while (i<8) result[i] = _groupHotkeys[i] i += 1 endWhile return result endFunction bool function SetGroupHotkey(int a_groupIndex, int a_keycode) ; Special case for unmap if (a_keycode == -1) _groupHotkeys[a_groupIndex] = -1 UnregisterForKey(oldKeycode) return true endIf ; Old group index this keycode was bound to int oldIndex = _groupHotkeys.Find(a_keycode) ; Old keycode at the target position int oldKeycode = _groupHotkeys[a_groupIndex] ; Already assigned, no need to do anything if (oldIndex == a_groupIndex) return false endIf ; Swap if (oldIndex != -1 && oldKeycode != -1) _groupHotkeys[oldIndex] = oldKeycode else ; Unset previous group this key was assigned to if (oldIndex != -1) _groupHotkeys[oldIndex] = -1 endIf ; If we replaced a key, unregister it if (oldKeycode != -1) UnregisterForKey(oldKeycode) endIf RegisterForKey(a_keycode) endIf _groupHotkeys[a_groupIndex] = a_keycode return true endFunction ; Send the group data to the UI, so that when the user selects a group, it can filter its entries. function InitControls() int[] args = new int[6] args[0] = ButtonHelpEnabled as int args[1] = _groupAddKey args[2] = _groupUseKey args[3] = _setIconKey args[4] = _saveEquipStateKey args[5] = _toggleFocusKey UI.InvokeIntA(FAVORITES_MENU, MENU_ROOT + ".initControls", args) endFunction ; Send the group data to the UI, so that when the user selects a group, it can filter its entries. function InitMenuGroupData() ; Don't send group data if vampire lord if (_vampireLordRace == PlayerRef.GetRace()) return endIf ; groupCount, mainHandFormId[8], offHandFormId[8], iconFormId[8] int[] args = new int[25] args[0] = 8 int c = 1 int i = 0 while (i<8) args[c] = _groupMainHandItemIds[i] i += 1 c += 1 endWhile i = 0 while (i<8) args[c] = _groupOffHandItemIds[i] i += 1 c += 1 endWhile i = 0 while (i<8) args[c] = _groupIconItemIds[i] i += 1 c += 1 endWhile UI.InvokeIntA(FAVORITES_MENU, MENU_ROOT + ".pushGroupItems", _itemIds1) UI.InvokeIntA(FAVORITES_MENU, MENU_ROOT + ".pushGroupItems", _itemIds2) UI.InvokeIntA(FAVORITES_MENU, MENU_ROOT + ".finishGroupData", args) endFunction function UpdateMenuGroupData(int a_groupIndex) int offset = 32 * a_groupIndex int[] itemIds if (offset >= 128) offset -= 128 itemIds = _itemIds2 else itemIds = _itemIds1 endIf ; groupIndex, mainHandItemId, offHandItemID, iconItemId, itemIds[32] int[] args = new int[36] args[0] = a_groupIndex args[1] = _groupMainHandItemIds[a_groupIndex] args[2] = _groupOffHandItemIds[a_groupIndex] args[3] = _groupIconItemIds[a_groupIndex] int i = 4 int j = offset while (i<36) args[i] = itemIds[j] i += 1 j += 1 endWhile ; This also unlocks the menu, so no need to call unlock UI.InvokeIntA(FAVORITES_MENU, MENU_ROOT + ".updateGroupData", args) endFunction ; Ensure that our data is still valid. Might not be the case if a mod was uninstalled function CleanUp() ; Note on thread safety: ; Since we don't manage an explicit group count, items can just be set or unset from multiple threads int i = 0 while (i < _items1.length) if (_items1[i] == none || _items1[i].GetFormID() == 0) _items1[i] = none _itemIds1[i] = 0 endIf i += 1 endWhile i = 0 while (i < _items2.length) if (_items2[i] == none || _items2[i].GetFormID() == 0) _items2[i] = none _itemIds2[i] = 0 endIf i += 1 endWhile endFunction bool function GroupAdd(int a_groupIndex, int a_itemId, Form a_item) int offset = 32 * a_groupIndex ; Select the target set of arrays, adjust offset Form[] items int[] itemIds bool[] itemInvalidFlags if (offset >= 128) offset -= 128 items = _items2 itemIds = _itemIds2 itemInvalidFlags = _itemInvalidFlags2 else items = _items1 itemIds = _itemIds1 itemInvalidFlags = _itemInvalidFlags1 endIf ; Prevent the same itemId being added to a group twice if (IsItemIdInGroup(a_groupIndex,a_itemId)) return true endIf ; Pick next free slot int index = FindFreeIndex(itemIds, itemInvalidFlags, offset) ; No more space in group? if (index == -1) return false endIf ; Store received data items[index] = a_item itemIds[index] = a_itemId itemInvalidFlags[index] = false ; If there's no icon item set yet, use this one if (_groupIconItems[a_groupIndex] == none) _groupIconItems[a_groupIndex] = a_item _groupIconItemIds[a_groupIndex] = a_itemId endIf return true endFunction bool function GroupRemove(int a_groupIndex, int a_itemId) int offset = 32 * a_groupIndex ; Select the target set of arrays, adjust offset Form[] items int[] itemIds bool[] itemInvalidFlags if (offset >= 128) offset -= 128 items = _items2 itemIds = _itemIds2 itemInvalidFlags = _itemInvalidFlags2 else items = _items1 itemIds = _itemIds1 itemInvalidFlags = _itemInvalidFlags1 endIf int i = offset int n = offset+32 while (i < n) if (itemIds[i] == a_itemId) items[i] = none itemIds[i] = 0 itemInvalidFlags[i] = false i = n else i += 1 endIf endWhile if (a_itemId == _groupMainHandItemIds[a_groupIndex]) _groupMainHandItems[a_groupIndex] = none _groupMainHandItemIds[a_groupIndex] = 0 endIf if (a_itemId == _groupOffHandItemIds[a_groupIndex]) _groupOffHandItems[a_groupIndex] = none _groupOffHandItemIds[a_groupIndex] = 0 endIf if (a_itemId == _groupIconItemIds[a_groupIndex]) ReplaceGroupIcon(a_groupIndex) endIf return true endFunction function GroupUse(int a_groupIndex) int offset = 32 * a_groupIndex ; Select the target set of arrays, adjust offset Form[] items int[] itemIds bool[] itemInvalidFlags if (offset >= 128) offset -= 128 items = _items2 itemIds = _itemIds2 itemInvalidFlags = _itemInvalidFlags2 else items = _items1 itemIds = _itemIds1 itemInvalidFlags = _itemInvalidFlags1 endIf ; Reset state _usedRightHand = false _usedLeftHand = false _usedVoice = false _usedOutfitMask = 0 ; These items are equipped later form[] deferredItems = new Form[32] int deferredIdx = 0 ; Encountered invalid items are removed at the end when speed is no longer an issue int[] invalidItemIds = new int[32] int invalidIdx = 0 ; Turn off UI sounds to avoid annoying clicking noise while swapping spells _audioCategoryUI.Mute() ; Unequip hands first? if (GetGroupFlag(a_groupIndex,GROUP_FLAG_UNEQUIP_HANDS)) UnequipHand(0) UnequipHand(1) endIf ; Process main and offhand items ; Left first, to avoid problems when equipping the same weapon twice Form offHandItem = _groupOffHandItems[a_groupIndex] int offHandItemId = _groupOffHandItemIds[a_groupIndex] if (offHandItem) int itemType = offHandItem.GetType() if (IsItemValid(offHandItem, itemType)) ProcessItem(offHandItem, itemType, false, true, offHandItemId) endIf endIf Form mainHandItem = _groupMainHandItems[a_groupIndex] int mainHandItemId = _groupMainHandItemIds[a_groupIndex] if (mainHandItem) int itemType = mainHandItem.GetType() if (IsItemValid(mainHandItem, itemType)) ProcessItem(mainHandItem, itemType, false, false, mainHandItemId) endIf endIf ; Validate & process items int i = offset int n = offset + 32 while (i < n) Form item = items[i] int itemId = itemIds[i] if (item && item != mainHandItem && item != offHandItem && !itemInvalidFlags[i]) int itemType = item.GetType() if (! IsItemValid(item, itemType)) invalidItemIds[invalidIdx] = itemId invalidIdx += 1 elseIf (! ProcessItem(item, itemType, a_itemId = itemId)) deferredItems[deferredIdx] = item deferredIdx += 1 endIf endIf i += 1 endWhile ; Process deferred items i = 0 while (i < deferredIdx) Form item = deferredItems[i] int itemType = item.GetType() ProcessItem(item, itemType, false) i += 1 endWhile ; Unequip any armor not belonging to current outfit mask if (GetGroupFlag(a_groupIndex,GROUP_FLAG_UNEQUIP_ARMOR)) int h = 0x00000001 while (h < 0x80000000) Form wornForm = PlayerREF.GetWornForm(h) if (wornForm) if (!LogicalAND(h, _usedOutfitMask)) PlayerREF.UnEquipItemEX(wornForm) endIf endIf h = LeftShift(h,1) endWhile endIf _audioCategoryUI.UnMute() ; Turn UI sounds back on i = 0 while (i 0 endIf endFunction bool function ProcessItem(Form a_item, int a_itemType, bool a_allowDeferring = true, bool a_offHandOnly = false, int a_itemId = 0) ; WEAPON ------------ if (a_itemType == 41) ; Any weapon needs at least one free hand if (_usedRightHand && _usedLeftHand) return true endIf Weapon itemWeapon = a_item as Weapon int weaponType = itemWeapon.GetweaponType() ; It's one-handed and the player has a free hand if (weaponType <= 4 || weaponType == 8) ; Fists(0), Swords(1), Daggers(2), War Axes(3), Maces(4), Staffs(8) if (!_usedRightHand && !a_offHandOnly) if (a_item == PlayerREF.GetEquippedObject(1) && a_itemId != PlayerREF.GetEquippedItemId(1)) UnequipHand(1) ; avoid damage-related bug when swapping for enhanced item endIf PlayerREF.EquipItemById(itemWeapon, a_itemId, 1, equipSound = _silenceEquipSounds) _usedRightHand = true elseIf (!_usedLeftHand) if (a_item == PlayerREF.GetEquippedObject(0) && a_itemId != PlayerREF.GetEquippedItemId(0)) UnequipHand(0) endIf PlayerREF.EquipItemById(itemWeapon, a_itemId, 2, equipSound = _silenceEquipSounds) _usedLeftHand = true endIf ; It's two-handed and both hands are free elseIf (weaponType > 4 && !_usedRightHand && !_usedLeftHand) ; EDC - Changed this line from GetEquippedItemId(0) to GetEquippedItemId(1) since two-handed weapons don't seem to appear in left hand ;Debug.Trace(self + ": PlayerREF.GetEquippedObject(0) is " + PlayerREF.GetEquippedObject(0) + ", PlayerREF.GetEquippedObject(1) is " + PlayerREF.GetEquippedObject(1)) ;Debug.Trace(self + ": PlayerREF.GetEquippedItemId(0) is " + PlayerREF.GetEquippedItemId(0) + ", PlayerREF.GetEquippedItemId(1) is " + PlayerREF.GetEquippedItemId(1)) if (a_item == PlayerREF.GetEquippedObject(0) && a_itemId != PlayerREF.GetEquippedItemId(1)) UnequipHand(0) endIf PlayerREF.EquipItemById(itemWeapon, a_itemId, equipSlot = 0, equipSound = _silenceEquipSounds) _usedRightHand = true _usedLeftHand = true endIf return true ; ARMOR ------------ elseIf (a_itemType == 26) int slotMask = (a_item as Armor).GetslotMask() ; It's a shield... if (slotMask == 512) if (!_usedLeftHand) PlayerREF.EquipItemById(a_item, a_itemId, equipSlot = 0, equipSound = _silenceEquipSounds) _usedLeftHand = true _usedOutfitMask += slotMask endIf ; 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 ; AMMO ------------ elseIf (a_itemType == 42) ;kAmmo PlayerREF.EquipItemEX(a_item, equipSlot = 0, equipSound = _silenceEquipSounds) return true ; SPELL ------------ elseIf (a_itemType == 22) Spell itemSpell = a_item as Spell EquipSlot spellEquipSlot = itemSpell.GetEquipType() if (spellEquipSlot != _voiceSlot) ; Any non power spell needs at least one free hand if (_usedRightHand && _usedLeftHand) return true endIf ; spell is eitherhanded if (spellEquipSlot == _eitherHandSlot) if (!_usedRightHand && !a_offHandOnly) PlayerREF.EquipSpell(itemSpell, 1) _usedRightHand = true elseIf (!_usedLeftHand) PlayerREF.EquipSpell(itemSpell, 0) _usedLeftHand = true endIf ; Spell requires two hands ... elseIf (spellEquipSlot == _bothHandsSlot) if (!_usedRightHand && !_usedLeftHand) PlayerREF.EquipSpell(itemSpell, 1) _usedRightHand = true _usedLeftHand = true endIf ; a lot of NPC spells are left-hand only, so if the player is using PSB they'll need this elseIf (spellEquipSlot == _leftHandSlot) if (!_usedLeftHand) PlayerREF.EquipSpell(itemSpell, 0) _usedLeftHand = true endIf endIf else if (!_usedVoice) PlayerREF.EquipSpell(itemSpell, 2) _usedVoice = true endIf endIf return true ; SCROLL ------------ elseIf (a_itemType == 23) Scroll itemScroll = a_item as Scroll ; Any scroll needs at least one free hand if (_usedRightHand && _usedLeftHand) return true endIf ;FIXME - GetEquipType seems to be broken for scrolls ;If (itemScroll.GetEquipType() == _bothHandsSlot && !_usedLeftHand && !_usedRightHand) ; PlayerREF.EquipItemEX(itemScroll, equipSlot = 0, equipSound = _silenceEquipSounds) ; _usedLeftHand = true ; _usedRightHand = true if (!_usedRightHand && !a_offHandOnly) PlayerREF.EquipItemEX(itemScroll, equipSlot = 1, equipSound = _silenceEquipSounds) _usedRightHand = true elseIf (!_usedLeftHand) PlayerREF.EquipItemEX(itemScroll, equipSlot = 2, equipSound = _silenceEquipSounds) _usedLeftHand = true endIf return true ; SHOUT ------------ elseIf (a_itemType == 119) if (!_usedVoice) PlayerREF.EquipShout(a_item as Shout) _usedVoice = true endIf return true ; POTION ------------ elseIf (a_itemType == 46) if ((a_item as Potion).IsHostile()) ; This is a poison and should only be applied after new weapons have been equipped. if (a_allowDeferring) return false endIf ; This will fail if a poisonable weapon is only equipped in the offhand. That's a Skyrim bug, not my bug. PlayerREF.EquipItem(a_item, abSilent = True) return true endiF ; This is a non-hostile potion, food, or... something? and can be used immediately PlayerREF.EquipItem(a_item as Potion, abSilent = True) return true ; INGREDIENT ------------ elseIf (a_itemType == 30) ;kIngredient PlayerREF.EquipItem(a_item as Ingredient, abSilent = True) return true ; LIGHT (TORCH) ------------ elseIf (a_itemType == 31) if (!_usedLeftHand) PlayerREF.EquipItemEX(a_item, equipSlot = 0, equipSound = _silenceEquipSounds) _usedLeftHand = true endIf return true ; MISC ------------ elseIf a_itemType == 32 PlayerREF.EquipItem(a_item, abSilent = True) return true endIf return true endFunction function InvalidateItem(int a_itemId, bool redrawIcon = false) ; EDC - Version 3 implementation only invalidates the first appearance of ; an itemID. Any subsequent use in other groups is missed. ; This version recursively searches for additional items beyond the first ;int loop int index ; GroupData [1-4] ;loop = 0 index = 0 while index < 128 index = _itemIds1.Find(a_itemId, index) if (index != -1) ;Debug.Trace(self + ": Setting _itemInvalidFlags1[" + index + "] = true. Loop number " + loop) ;loop += 1 _itemInvalidFlags1[index] = true index += 1 else index = 128 endIf endWhile ; GroupData [5-8] ;loop = 0 index = 0 while index < 128 index = _itemIds2.Find(a_itemId, index) if (index != -1) ;Debug.Trace(self + ": Setting _itemInvalidFlags2[" + index + "] = true. Loop number " + loop) ;loop += 1 _itemInvalidFlags2[index] = true index += 1 else index = 128 endIf endWhile ; Main hand index = 0 while index < 8 index = _groupMainHandItemIds.Find(a_itemId, index) if (index != -1) _groupMainHandItems[index] = none _groupMainHandItemIds[index] = 0 index += 1 else index = 8 endIf endWhile ; Off hand index = 0 while index < 8 index = _groupOffHandItemIds.Find(a_itemId, index) if (index != -1) _groupOffHandItems[index] = none _groupOffHandItemIds[index] = 0 index += 1 else index = 8 endIf endWhile ; Icon index = 0 while index < 8 index = _groupIconItemIds.Find(a_itemId, index) if (index != -1) ReplaceGroupIcon(index) if (redrawIcon) UpdateMenuGroupData(index) endIf index += 1 else index = 8 endIf endWhile endFunction int function FindFreeIndex(int[] a_itemIds, bool[] a_itemInvalidFlags, int offset) int i = a_itemIds.Find(0,offset) ; First try to find an entry that is 0 if (i >= offset && i < offset + 32) return i endIf ; Failed. Now try to claim an entry flagged as invalid. i = offset int n = offset + 32 while (i < n) if (a_itemInvalidFlags[i]) return i endIf i += 1 endWhile return -1 endFunction function ReplaceGroupIcon(int a_groupIndex) ; If player has MH or OH set for the group, use it first if (_groupMainHandItemIds[a_groupIndex]) _groupIconItems[a_groupIndex] = _groupMainHandItems[a_groupIndex] _groupIconItemIds[a_groupIndex] = _groupMainHandItemIds[a_groupIndex] return elseIf (_groupOffHandItemIds[a_groupIndex]) _groupIconItems[a_groupIndex] = _groupOffHandItems[a_groupIndex] _groupIconItemIds[a_groupIndex] = _groupOffHandItemIds[a_groupIndex] return endIf int offset = a_groupIndex * 32 ; Select the target set of arrays, adjust offset Form[] items int[] itemIds bool[] itemInvalidFlags if (offset >= 128) offset -= 128 items = _items2 itemIds = _itemIds2 itemInvalidFlags = _itemInvalidFlags2 else items = _items1 itemIds = _itemIds1 itemInvalidFlags = _itemInvalidFlags1 endIf int i = offset int n = offset+32 ; Use icon of first found item while (i < n) if (items[i] != none && !itemInvalidFlags[i]) _groupIconItems[a_groupIndex] = items[i] _groupIconItemIds[a_groupIndex] = itemIds[i] return else i += 1 endIf endWhile _groupIconItems[a_groupIndex] = none _groupIconItemIds[a_groupIndex] = 0 endFunction ; utility function to see if form is in the specified group. bool function IsFormInGroup(int a_groupIndex, form a_item) int offset = 32 * a_groupIndex ; Select the target set of arrays, adjust offset Form[] items if (offset >= 128) offset -= 128 items = _items2 else items = _items1 endIf int i = items.Find(a_item,offset) if (i >= offset && i < offset+32) return true endIf return false endFunction ; utility function to see how many of the form are in a group int function GetNumFormsInGroup(int a_groupIndex,form a_item) int offset = 32 * a_groupIndex ; Select the target set of arrays, adjust offset form[] items if (offset >= 128) offset -= 128 items = _items2 else items = _items1 endIf int i = offset int n = offset + 32 int count while (i < n) if (items[i] == a_item) count += 1 endIf i += 1 endWhile return count endFunction form function GetFormFromItemId(int a_groupIndex,int itemId) int offset = 32 * a_groupIndex ; Select the target set of arrays, adjust offset form[] items int[] itemIds if (offset >= 128) offset -= 128 items = _items2 itemIds = _itemIds2 else items = _items1 itemIds = _itemIds1 endIf int i = itemIds.Find(itemId,offset) if (i >= offset && i < offset + 32) return items[i] else return none endIf endFunction ; return the Nth itemId int function GetNthItemIdInGroup(int a_groupIndex,form a_item,int a_num = 1) int offset = 32 * a_groupIndex ; Select the target set of arrays, adjust offset form[] items int[] itemIds if (offset >= 128) offset -= 128 items = _items2 itemIds = _itemIds2 else items = _items1 itemIds = _itemIds1 endIf int i = offset int n = offset + 32 int count = 0 int result = offset while (result >= offset && result < n && count < a_num) result = items.Find(a_item,i) i = result + 1 count += 1 endWhile if (result >= offset && result < n) return itemIds[result] endIf return 0 endFunction ; utility function to see if itemId is in the specified group. bool function IsItemIdInGroup(int a_groupIndex, int a_itemId) int offset = 32 * a_groupIndex ; Select the target set of arrays, adjust offset int[] itemIds if (offset >= 128) offset -= 128 itemIds = _itemIds2 else itemIds = _itemIds1 endIf int i = itemIds.Find(a_itemId,offset) if (i >= offset && i < offset+32) return true endIf return false endFunction function RegisterHotkeys() int i = 0 while (i < _groupHotkeys.Length) if (_groupHotkeys[i] != -1) RegisterForKey(_groupHotkeys[i]) endIf i += 1 endWhile endFunction function SwapControlKey(int a_newKey, int a_curKey) if (a_newKey == _groupAddKey) _groupAddKey = a_curKey elseIf (a_newKey == _groupUseKey) _groupUseKey = a_curKey elseIf (a_newKey == _setIconKey) _setIconKey = a_curKey elseIf (a_newKey == _saveEquipStateKey) _saveEquipStateKey = a_curKey elseIf (a_newKey == _toggleFocusKey) _toggleFocusKey = a_curKey endIf endFunction ; DEBUG ------------------------------------------------------------------------------------------ function PrintGroupItems(int a_groupIndex) ;This is here so I can see what's in the group, because the UI is currently broken Debug.Trace("PrintGroupItems called on group " + a_groupIndex) int offset = 32 * a_groupIndex ; Select the target set of arrays, adjust offset Form[] items int[] itemIds if (offset >= 128) offset -= 128 items = _items2 itemIds = _itemIds2 else items = _items1 itemIds = _itemIds1 endIf int i = offset int n = offset + 32 while (i < n) if (items[i]) Debug.Trace(i + " is " + itemIds[i] + ", form is " + items[i] + ": " + items[i].GetName()) endIf i += 1 endWhile if (_groupIconItemIds[a_groupIndex]) Debug.Trace("Group icon is " + _groupIconItemIds[a_groupIndex] + ", form is " + _groupIconItems[a_groupIndex] + ": " + _groupIconItems[a_groupIndex].GetName()) endIf if (_groupMainHandItemIds[a_groupIndex]) Debug.Trace("Group MH is " + _groupMainHandItemIds[a_groupIndex] + ", form is " + _groupMainHandItems[a_groupIndex] + ": " + _groupMainHandItems[a_groupIndex].GetName()) endIf if (_groupOffHandItemIds[a_groupIndex]) Debug.Trace("Group OH is " + _groupOffHandItemIds[a_groupIndex] + ", form is " + _groupOffHandItems[a_groupIndex] + ": " + _groupOffHandItems[a_groupIndex].GetName()) endIf endFunction