Nenue@16: -- SkeletonKey Nenue@16: -- ActionTypes.lua Nenue@16: -- Created: 7/29/2016 9:14 PM Nenue@16: -- %file-revision% Nenue@16: -- Nenue@21: local tostring, tonumber, pairs, ipairs = tostring, tonumber, pairs, ipairs Nenue@21: local unpack, SetBinding = unpack, SetBinding Nenue@21: local tinsert, tContains, select, wipe = tinsert, tContains, select, table.wipe Nenue@21: local GetSpellBookItemInfo, GetSpellBookItemName, GetSpellInfo = GetSpellBookItemInfo, GetSpellBookItemName, GetSpellInfo Nenue@21: local GetSpecialization, GetSpecializationInfo, IsPassiveSpell, IsTalentSpell = GetSpecialization, GetSpecializationInfo, IsPassiveSpell, IsTalentSpell Nenue@21: local PetHasSpellbook, PetHasActionBar, GetPetActionInfo, HasPetSpells = PetHasSpellbook, PetHasActionBar, GetPetActionInfo, HasPetSpells Nenue@21: local GetProfessions, GetProfessionInfo, GetTalentInfo = GetProfessions, GetProfessionInfo, GetTalentInfo Nenue@21: local GetNumBindings, GetBinding = GetNumBindings, GetBinding Nenue@21: Nenue@21: local kb, print, wrap = LibStub('LibKraken').register(KeyBinder, 'Info') Nenue@17: local cprint = DEVIAN_WORKSPACE and function(...) _G.print('Cfg', ...) end or function() end Nenue@16: Nenue@17: local CLICK_KEYBINDER_MACRO = "CLICK KeyBinderMacro:" Nenue@17: local CLICK_KEYBINDER_KEY = "CLICK KeyBinderKey:" Nenue@21: local PET_BASIC_SUBTEXT = 'Basic Attack' Nenue@21: local PET_SPECIAL_SUBTEXT = 'Special Ability' Nenue@16: local PETACTION_SCRIPT = { Nenue@22: [PET_ACTION_MOVE_TO] = {'pet_move_to', SLASH_PET_MOVE_TO1}, Nenue@22: [PET_ACTION_ATTACK] = {'pet_attack', SLASH_PET_ATTACK1}, Nenue@22: [PET_ACTION_FOLLOW] = {'pet_follow', SLASH_PET_FOLLOW1}, Nenue@22: [PET_ACTION_WAIT] = {'pet_stay', SLASH_PET_STAY1 }, Nenue@22: [PET_MODE_AGGRESSIVE] = {'pet_aggressive', SLASH_PET_AGGRESSIVE1 }, Nenue@22: [PET_MODE_DEFENSIVE] = { 'pet_defensive', SLASH_PET_DEFENSIVE1}, Nenue@22: [PET_MODE_PASSIVE] = { 'pet_passive', SLASH_PET_PASSIVE1}, Nenue@22: [PET_MODE_ASSIST] = {'pet_assist', SLASH_PET_ASSIST1}, Nenue@16: } Nenue@21: local SECONDARY_PROFESSIONS = { Nenue@21: [5] = 3, Nenue@21: [7] = 4, Nenue@21: [9] = 5, Nenue@21: [10] = 6 Nenue@21: } Nenue@21: local SUMMON_RANDOM_FAVORITE_MOUNT_SPELL = 150544 Nenue@16: Nenue@19: kb.ActionTypes = {} Nenue@21: kb.PetCache = { Nenue@21: spell = {}, Nenue@21: spellslot = {}, Nenue@21: action = {}, Nenue@21: special = {}, Nenue@21: subtext = {} Nenue@21: } Nenue@19: kb.TalentCache = {} Nenue@19: kb.ProfessionCache = {} Nenue@19: Nenue@19: local atype = kb.ActionTypes Nenue@19: Nenue@17: --- Caps Lock Nenue@19: atype['mount'] = function(id, name) Nenue@17: if id == SUMMON_RANDOM_FAVORITE_MOUNT_SPELL then Nenue@24: return CLICK_KEYBINDER_MACRO, 'mount_random', "/script C_MountJournal.SummonByID(0)" Nenue@17: else Nenue@24: return CLICK_KEYBINDER_MACRO, 'mount_'..id, "/script C_MountJournal.SummonByID("..id..")" Nenue@17: end Nenue@16: end Nenue@19: Nenue@19: atype['macro'] = function(id, name) Nenue@17: return CLICK_KEYBINDER_MACRO, 'macro_' .. tostring(name), id Nenue@17: end Nenue@19: Nenue@19: atype['equipset'] = function(id, name) Nenue@17: return CLICK_KEYBINDER_MACRO, 'equipset_'..tostring(name), "/script UseEquipmentSet("..tostring(id)..")" Nenue@17: end Nenue@19: Nenue@19: atype['spell'] = function(id, name) Nenue@17: local attributeName = name Nenue@17: if kb.ProfessionCache[id] then Nenue@17: attributeName = "profession_".. kb.ProfessionCache[id].profOffset .. '_' .. kb.ProfessionCache[id].spellNum Nenue@17: end Nenue@17: return CLICK_KEYBINDER_KEY, attributeName, name Nenue@17: end Nenue@19: Nenue@19: atype['petaction'] = function(_, name) Nenue@17: -- ID doesn't exist for basic commands, even though they can be picked up Nenue@17: local attributeName, attributeValue = "petaction_" .. tostring(name), "/cast "..tostring(name) Nenue@17: if PETACTION_SCRIPT[name] then Nenue@22: attributeName, attributeValue = unpack(PETACTION_SCRIPT[name]) Nenue@19: elseif kb.PetCache.special[name] then Nenue@21: attributeName = "petaction_"..kb.PetCache.special[name][3].."_" .. tonumber(kb.PetCache.special[name][6]) Nenue@17: end Nenue@17: return CLICK_KEYBINDER_MACRO, attributeName, attributeValue Nenue@16: end Nenue@16: Nenue@19: atype['battlepet'] = function(id, name) Nenue@17: return CLICK_KEYBINDER_MACRO, 'battlepet_' .. tostring(name), SLASH_SUMMON_BATTLE_PET1 .. " " .. tostring(name) Nenue@17: end Nenue@19: Nenue@19: atype['item'] = function(id, name) Nenue@17: return CLICK_KEYBINDER_KEY, 'item_' .. tostring(name), id Nenue@17: end Nenue@16: Nenue@16: Nenue@17: --- Resolves the SecureActionButton attribute names used for the given action Nenue@16: kb.RegisterAction = function(actionType, id, name) Nenue@16: Nenue@19: assert(atype[actionType], 'Missing actionType handler for `'..tostring(actionType)..'`') Nenue@19: local target, attributeName, attributeValue = atype[actionType](id, name) Nenue@17: Nenue@17: local command = target .. attributeName Nenue@17: local baseName, iterative = attributeName, 1 Nenue@17: while (kb.macros[attributeName] and kb.macros[attributeName][1] ~= attributeValue) do Nenue@17: print(' * cannot use|cFF00FF00', attributeName, '|r"'.. tostring(kb.macros[attributeName][1]) .. '"') Nenue@17: attributeName = baseName .. '_' .. iterative Nenue@17: iterative = iterative + 1 Nenue@17: end Nenue@21: if attributeName ~= baseName then Nenue@21: print(' * Creating|cFF00FF00', attributeName) Nenue@17: else Nenue@21: print(' * Re-using|cFF00FF00', attributeName) Nenue@17: end Nenue@17: kb.macros[attributeName] = {attributeValue, command} Nenue@17: Nenue@17: Nenue@17: print('RegisterAction', actionType, id, '->', attributeName, attributeValue, target .. attributeName) Nenue@17: return attributeName, attributeValue, command Nenue@17: end Nenue@17: Nenue@17: Nenue@17: Nenue@17: Nenue@17: kb.ApplyTalentBinding = function(talentInfo, cache) Nenue@17: for i = 5, #talentInfo do Nenue@17: local command = CLICK_KEYBINDER_KEY.. talentInfo[2] Nenue@17: SetBinding(talentInfo[i], command) Nenue@17: cprint(' **', talentInfo[i], '->', command) Nenue@17: tinsert(cache, talentInfo[i]) Nenue@17: end Nenue@17: end Nenue@17: kb.CacheTalentBinding = function(talentInfo, cache) Nenue@17: Nenue@17: local spellID = talentInfo[4] Nenue@19: cache[spellID] = cache[spellID] or {} Nenue@19: cache[spellID] = {select(5,unpack(talentInfo)) } Nenue@19: --cprint(spellID, unpack(kb.TalentBindings[spellID])) Nenue@17: end Nenue@17: Nenue@17: do Nenue@17: local bindings = kb.bindings Nenue@17: local key, macro = KeyBinderKey, KeyBinderMacro Nenue@17: kb.LoadBinding = function(command, name, icon, actionType, actionID, macroName, macroText ) Nenue@17: Nenue@17: if actionType == 'spell' then Nenue@17: key:SetAttribute("*type-"..name, actionType) Nenue@17: key:SetAttribute("*"..actionType.."-"..name, name) Nenue@17: elseif actionType == 'item' then Nenue@17: key:SetAttribute("*type-"..name, actionType) Nenue@17: key:SetAttribute("*"..actionType.."-"..name, name) Nenue@17: elseif actionType == 'macro' then Nenue@17: macro:SetAttribute("*macro-"..macroName, actionID) Nenue@16: else Nenue@17: macro:SetAttribute("*macrotext-"..macroName, macroText) Nenue@16: end Nenue@16: Nenue@17: cprint('Loading binding', actionType, actionID) Nenue@17: bindings[actionType] = bindings[actionType] or {} Nenue@17: bindings[actionType][actionID] = bindings[actionType][actionID] or {} Nenue@17: bindings[command] = bindings[actionType][actionID] Nenue@17: return bindings[actionType], actionID Nenue@16: end Nenue@16: Nenue@17: kb.ApplyBindings = function (profile) Nenue@17: cprint('binding profile', profile) Nenue@17: for slot, data in pairs(profile.buttons) do Nenue@17: kb.LoadBinding(unpack(data)) Nenue@17: end Nenue@17: Nenue@17: for key, command in pairs(profile.bindings) do Nenue@17: Nenue@17: cprint(' *', key, '->', command) Nenue@17: Nenue@17: --_G.print('HotKey','loading', key, command) Nenue@17: SetBinding(key, command) Nenue@17: if bindings[command] and not tContains(bindings[command], key) then Nenue@17: tinsert(bindings[command], key) Nenue@17: end Nenue@17: end Nenue@17: Nenue@17: for spellName, talentInfo in pairs(profile.talents) do Nenue@17: local dummy = GetSpellInfo(spellName) Nenue@17: local func = kb.CacheTalentBinding Nenue@19: local dest = kb.TalentBindings Nenue@17: if dummy then Nenue@17: cprint('|cFFBBFF00Active:|r', dummy) Nenue@17: local macroName, spellName, actionType, actionID = unpack(talentInfo) Nenue@17: bindings[actionType] = bindings[actionType] or {} Nenue@17: bindings[actionType][actionID] = {} Nenue@17: func = kb.ApplyTalentBinding Nenue@17: dest = kb.bindings[actionType][actionID] Nenue@17: else Nenue@17: Nenue@17: cprint('|cFFFF4400Inactive:|r', talentInfo[2]) Nenue@17: end Nenue@17: func(talentInfo, dest) Nenue@17: end Nenue@17: Nenue@17: end Nenue@17: Nenue@17: kb.ApplyAllBindings =function () Nenue@21: wipe(kb.TalentBindings) Nenue@17: Nenue@17: Nenue@17: -- reflect action key settings Nenue@17: if GetCVarBool("ActionButtonUseKeyDown") then Nenue@17: KeyBinderMacro:RegisterForClicks("AnyDown") Nenue@17: KeyBinderKey:RegisterForClicks("AnyDown") Nenue@17: else Nenue@17: KeyBinderMacro:RegisterForClicks("AnyUp") Nenue@17: KeyBinderKey:RegisterForClicks("AnyUp") Nenue@17: end Nenue@17: Nenue@17: for i, profile in ipairs(kb.orderedProfiles) do Nenue@17: kb.ApplyBindings(profile) Nenue@17: end Nenue@17: -- do this after to ensure that profession binds are properly overridden Nenue@17: kb.UpdateProfessionInfo() Nenue@17: Nenue@17: Nenue@17: SaveBindings(GetCurrentBindingSet()) Nenue@17: end Nenue@19: end Nenue@19: Nenue@19: Nenue@19: kb.specInfo = {} Nenue@19: kb.UpdateSpecInfo = function() Nenue@19: kb.specInfo.id = GetSpecialization() Nenue@19: kb.specInfo.globalID, kb.specInfo.name, kb.specInfo.desc, kb.specInfo.texture = GetSpecializationInfo(kb.specInfo.id) Nenue@19: end Nenue@19: Nenue@19: kb.UpdateTalentInfo = function() Nenue@19: if kb.talentsPushed then Nenue@19: return Nenue@19: end Nenue@21: wipe(kb.TalentCache) Nenue@19: for row =1, MAX_TALENT_TIERS do Nenue@19: for col = 1, NUM_TALENT_COLUMNS do Nenue@19: local talentID, talentName, icon, selected, available, spellID = GetTalentInfo(row, col, 1) Nenue@19: local talentInfo = kb.TalentCache[spellID] or {} Nenue@19: talentInfo.row = 1 Nenue@19: talentInfo.col = col Nenue@19: talentInfo.name = talentName Nenue@19: talentInfo.talentID = talentID Nenue@19: talentInfo.selected = selected Nenue@19: talentInfo.available = available Nenue@19: talentInfo.spellID = spellID Nenue@19: kb.TalentCache[spellID] = talentInfo Nenue@19: kb.TalentCache[talentName] = talentInfo Nenue@19: print('Talent ', row, col, spellID, talentName) Nenue@19: end Nenue@19: end Nenue@19: kb.talentsPushed = true Nenue@19: Nenue@19: kb.UpdateDynamicButtons('talent') Nenue@19: end Nenue@19: Nenue@19: kb.UpdateProfessionInfo = function() Nenue@21: wipe(kb.ProfessionCache) Nenue@19: local profs = {GetProfessions() } Nenue@19: local primaryNum = 0 Nenue@19: for i, index in ipairs(profs) do Nenue@19: local profName, texture, rank, maxRank, numSpells, spellOffset = GetProfessionInfo(index) Nenue@19: print(i, index, profName, numSpells, spellOffset) Nenue@19: if not SECONDARY_PROFESSIONS[index] then Nenue@19: primaryNum = primaryNum + 1 Nenue@19: end Nenue@19: local profNum = SECONDARY_PROFESSIONS[index] or primaryNum Nenue@19: Nenue@19: Nenue@19: kb.ProfessionCache[profNum] = kb.ProfessionCache[i] or {} Nenue@19: Nenue@19: for j = 1, numSpells do Nenue@19: local spellName, _, icon, _, _, _, spellID = GetSpellInfo(spellOffset+j, BOOKTYPE_PROFESSION) Nenue@19: Nenue@19: local profInfo = { Nenue@19: spellName = spellName, Nenue@19: spellID = spellID, Nenue@19: icon = icon, Nenue@19: profOffset = i, Nenue@19: profIndex = index, Nenue@19: spellOffset = (spellOffset+j), Nenue@19: spellNum = j Nenue@19: } Nenue@26: Nenue@26: kb.SecureAttribute(KeyBinderKey, "*type-profession_"..i .. '_' ..j, "spell") Nenue@26: kb.SecureAttribute(KeyBinderKey, "*spell-profession_"..i .. '_' ..j, spellName) Nenue@19: Nenue@19: kb.ProfessionCache[i .. '_' .. j] = profInfo Nenue@19: kb.ProfessionCache[spellName] = profInfo Nenue@19: kb.ProfessionCache[spellID] = profInfo Nenue@19: print(' |cFF0088FF['..i..']|r|cFFFF44BB['..spellOffset+i..']|r', spellName, "profession_"..i .. '_' ..j) Nenue@19: end Nenue@19: Nenue@19: end Nenue@19: Nenue@19: kb.UpdateDynamicButtons('profession') Nenue@19: end Nenue@19: Nenue@19: Nenue@19: Nenue@19: kb.UpdatePetInfo = function() Nenue@19: local hasPetSpells, petType = HasPetSpells() Nenue@19: if PetHasSpellbook() then Nenue@19: print('PET SPELLBOOK') Nenue@19: local i = 1 Nenue@21: local specialNum = {} Nenue@19: repeat Nenue@19: Nenue@19: local spellType, spellID = GetSpellBookItemInfo(i, BOOKTYPE_PET) Nenue@19: local spellName, subText = GetSpellBookItemName(i, BOOKTYPE_PET) Nenue@21: local texture = GetSpellBookItemTexture(i, BOOKTYPE_PET) Nenue@19: local isPassive = IsPassiveSpell(i, BOOKTYPE_PET) Nenue@19: if not isPassive then Nenue@19: if spellName then Nenue@21: kb.PetCache.spellslot[spellName] = {i, spellName, subText, spellID, texture} Nenue@19: print('|cFF00FF88spellslot['..spellName..']|r', '=>', i, subText) Nenue@19: Nenue@21: if subText then Nenue@21: kb.PetCache.subtext[subText] = kb.PetCache.subtext[subText] or {} Nenue@21: specialNum[subText] = (specialNum[subText] or 0) + 1 Nenue@21: Nenue@21: local entry = {i, spellName, subText, spellID, texture, specialNum[subText]} Nenue@21: Nenue@21: kb.PetCache.special[spellName] = entry Nenue@21: kb.PetCache.subtext[subText][specialNum[subText]] = entry Nenue@26: kb.SecureAttribute(KeyBinderMacro, "*macrotext-petaction_"..subText.."_"..specialNum[subText], "/cast "..spellName) Nenue@21: Nenue@21: print('|cFF00FFFFspecial['..spellName..']|r', '\n','|cFF00FFFFsubtext['..subText..']['..specialNum[subText]..']|r', '=>', i, spellName, subText, spellID, texture, specialNum[subText]) Nenue@19: end Nenue@19: Nenue@19: if spellID then Nenue@19: kb.PetCache.spell[i] = {spellID, spellName, subText} Nenue@19: print('|cFF0088FFspell['..i..']|r', '=>', spellID, spellName, subText) Nenue@19: end Nenue@19: end Nenue@19: Nenue@19: Nenue@19: end Nenue@19: Nenue@19: i = i + 1 Nenue@19: until spellType == nil Nenue@19: else Nenue@19: print('NO PET SPELLBOOK') Nenue@21: wipe(kb.PetCache.spell) Nenue@21: wipe(kb.PetCache.spellslot) Nenue@19: end Nenue@19: Nenue@19: if PetHasActionBar() then Nenue@19: print('PET ACTION BAR') Nenue@19: for i = 1, 10 do Nenue@19: Nenue@19: Nenue@19: local name, subtext, texture, isToken, isActive = GetPetActionInfo(i) Nenue@19: if name then Nenue@19: kb.PetCache.action[i] = {name, subtext, texture, isToken, isActive } Nenue@19: Nenue@19: Nenue@19: end Nenue@19: print('|cFFFFFF00action['..i..']|r', name, subtext, texture) Nenue@19: end Nenue@19: else Nenue@19: print('NO PET ACTION BAR') Nenue@21: wipe(kb.PetCache.action) Nenue@19: end Nenue@19: Nenue@19: kb.UpdateDynamicButtons('petaction') Nenue@19: Nenue@19: end Nenue@19: Nenue@19: kb.UpdateSystemBinds = function() Nenue@21: wipe(kb.SystemBindings) Nenue@19: local n = GetNumBindings() Nenue@19: for i=1, n do Nenue@19: local command, key1, key2 = GetBinding(i) Nenue@19: if key1 then Nenue@19: kb.SystemBindings[key1] = command Nenue@19: end Nenue@19: if key2 then Nenue@19: kb.SystemBindings[key2] = command Nenue@19: end Nenue@19: end Nenue@19: end Nenue@19: Nenue@19: kb.UpdateDynamicButtons = function(dynamicType) Nenue@19: for i, button in ipairs(kb.buttons) do Nenue@19: if button.isDynamic == dynamicType then Nenue@19: kb.UpdateSlot(button, true) Nenue@19: end Nenue@19: end Nenue@26: end Nenue@26: Nenue@26: kb.pendingAttributes = {} Nenue@26: kb.SecureAttribute = function(target, name, value) Nenue@26: if InCombatLockdown() then Nenue@26: tinsert(kb.pendingAttributes, {target, name, value}) Nenue@26: kb:RegisterEvent('PLAYER_REGEN_ENABLED') Nenue@26: else Nenue@26: Nenue@26: print(target:GetName(), 'attribute', '"'.. tostring(name)..'" = "'..tostring(value)..'"') Nenue@26: target:SetAttribute(name, value) Nenue@26: end Nenue@26: end Nenue@26: Nenue@26: kb.PLAYER_REGEN_ENABLED = function() Nenue@26: if #kb.pendingAttributes >= 1 then Nenue@26: local args = tremove(kb.pendingAttributes) Nenue@26: while args do Nenue@26: local target, name, value = unpack(args) Nenue@26: print(target:GetName(), 'attribute', '"'.. tostring(name)..'" = "'..tostring(value)..'"') Nenue@26: target:SetAttribute(name, value) Nenue@26: args = tremove(kb.pendingAttributes) Nenue@26: end Nenue@26: end Nenue@16: end