enderalse/source/scripts/ski_favoritesmanager.psc

1320 lines
31 KiB
Plaintext
Raw Normal View History

2021-10-05 22:22:24 +00:00
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()
2021-10-05 22:22:24 +00:00
int function GetVersion()
return 4
2021-10-05 22:22:24 +00:00
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
2021-10-05 22:22:24 +00:00
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<invalidIdx)
InvalidateItem(invalidItemIds[i])
i += 1
endWhile
endFunction
function UnequipHand(int a_hand)
int a_handEx = 1
if (a_hand == 0)
a_handEx = 2 ; unequipspell and *ItemEx need different hand args
endIf
Form handItem = PlayerREF.GetEquippedObject(a_hand)
if (handItem)
int itemType = handItem.GetType()
if (itemType == 22)
PlayerREF.UnequipSpell(handItem as Spell, a_hand)
else
PlayerREF.UnequipItemEx(handItem, a_handEx)
endIf
endIf
endFunction
bool function IsItemValid(Form a_item, int a_itemType)
; Player has removed this item from Favorites, so don't use it and queue it for removal
if (! Game.IsObjectFavorited(a_item))
return false
endIf
; This is a Spell or Shout and can't be counted like an item
if (a_itemType == 22 || a_itemType == 119)
return PlayerREF.HasSpell(a_item)
; This is an inventory item
else
return PlayerREF.GetItemCount(a_item) > 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))
2021-10-05 22:22:24 +00:00
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
2021-10-05 22:22:24 +00:00
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
2021-10-05 22:22:24 +00:00
int index
2021-10-05 22:22:24 +00:00
; 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
2021-10-05 22:22:24 +00:00
; 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
2021-10-05 22:22:24 +00:00
; 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
2021-10-05 22:22:24 +00:00
; 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
2021-10-05 22:22:24 +00:00
endIf
endWhile
2021-10-05 22:22:24 +00:00
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