Mercurial > wow > skeletonkey
diff ActionTemplates.lua @ 70:131d9190db6b
Curseforge migration
author | Nenue |
---|---|
date | Wed, 28 Dec 2016 16:31:15 -0500 |
parents | |
children | ca3118127e5e |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ActionTemplates.lua Wed Dec 28 16:31:15 2016 -0500 @@ -0,0 +1,635 @@ +-- SkeletonKey +-- ActionTemplates.lua +-- Created: 7/29/2016 9:14 PM +-- %file-revision% +-- Code dealing with the implementation of action hotkeys + +local tostring, tonumber, pairs, ipairs = tostring, tonumber, pairs, ipairs +local unpack, SetBinding = unpack, SetBinding +local tinsert, tContains, select, wipe = tinsert, tContains, select, table.wipe +local GetSpellBookItemInfo, GetSpellBookItemName, GetSpellInfo = GetSpellBookItemInfo, GetSpellBookItemName, GetSpellInfo +local GetSpecialization, GetSpecializationInfo, IsPassiveSpell, IsTalentSpell = GetSpecialization, GetSpecializationInfo, IsPassiveSpell, IsTalentSpell +local PetHasSpellbook, PetHasActionBar, GetPetActionInfo, HasPetSpells = PetHasSpellbook, PetHasActionBar, GetPetActionInfo, HasPetSpells +local GetProfessions, GetProfessionInfo, GetTalentInfo = GetProfessions, GetProfessionInfo, GetTalentInfo +local GetNumBindings, GetBinding = GetNumBindings, GetBinding + +local _, kb = ... +local print = (DEVIAN_PNAME == 'SkeletonKey') and function(...) print('SK', ...) end or nop +local cprint = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('Cfg', ...) end or nop + +local CLICK_KEYBINDER_MACRO = "CLICK SkeletonKeyMacro:" +local CLICK_KEYBINDER_KEY = "CLICK SkeletonKeyKey:" +local PET_BASIC_SUBTEXT = 'Basic Attack' +local PET_SPECIAL_SUBTEXT = 'Special Ability' +local PETACTION_SCRIPT = { + [PET_ACTION_MOVE_TO] = {'pet_move_to', SLASH_PET_MOVE_TO1}, + [PET_ACTION_ATTACK] = {'pet_attack', SLASH_PET_ATTACK1}, + [PET_ACTION_FOLLOW] = {'pet_follow', SLASH_PET_FOLLOW1}, + [PET_ACTION_WAIT] = {'pet_stay', SLASH_PET_STAY1 }, + [PET_MODE_AGGRESSIVE] = {'pet_aggressive', SLASH_PET_AGGRESSIVE1 }, + [PET_MODE_DEFENSIVE] = { 'pet_defensive', SLASH_PET_DEFENSIVE1}, + [PET_MODE_PASSIVE] = { 'pet_passive', SLASH_PET_PASSIVE1}, + [PET_MODE_ASSIST] = {'pet_assist', SLASH_PET_ASSIST1}, +} +local SECONDARY_PROFESSIONS = { + [5] = 3, + [7] = 4, + [9] = 5, + [10] = 6 +} +local petSpellCache,petSubtextCache +local SUMMON_RANDOM_FAVORITE_MOUNT_SPELL = 150544 + +--kb.ChangedBindings = {} +--kb.ActionTypes = {} + +local atype = kb.ActionTypes + +--- Caps Lock +atype['mount'] = function(id, name) + if id == SUMMON_RANDOM_FAVORITE_MOUNT_SPELL then + return CLICK_KEYBINDER_MACRO, 'mount_random', "/script C_MountJournal.SummonByID(0)", SkeletonKeyMacro + else + return CLICK_KEYBINDER_MACRO, 'mount_'..id, "/script C_MountJournal.SummonByID("..id..")", SkeletonKeyMacro + end +end + +atype['macro'] = function(id, name) + local _, _, text = GetMacroInfo(id) + return CLICK_KEYBINDER_MACRO, 'macro_' .. tostring(name), name, SkeletonKeyMacro +end + +atype['equipset'] = function(id, name) + return CLICK_KEYBINDER_MACRO, 'equipset_'..tostring(name), "/script UseEquipmentSet("..tostring(id)..")", SkeletonKeyMacro +end + +atype['spell'] = function(id, name) + local attributeName = name + if kb.ProfessionCache[id] then + attributeName = "profession_".. kb.ProfessionCache[id].dynamicIndex .. '_' .. kb.ProfessionCache[id].dynamicSubIndex + end + return CLICK_KEYBINDER_KEY, attributeName, name, SkeletonKeyKey +end + +atype['petaction'] = function(_, name) + -- ID doesn't exist for basic commands, even though they can be picked up + local attributeName, attributeValue = "petaction_" .. tostring(name), "/cast "..tostring(name) + + if not petSpellCache then + kb.UpdatePetInfo() + end + -- Compose a multi-macro for subtext abilities + if petSpellCache[name] then + attributeValue = "" + for spellName, enabled in pairs(petSubtextCache[petSpellCache[name]]) do + attributeValue = attributeValue .. "/cast " .. spellName .. "\n" + end + end + + if PETACTION_SCRIPT[name] then + attributeName, attributeValue = unpack(PETACTION_SCRIPT[name]) + elseif kb.PetCache.special[name] then + attributeName = "petaction_"..kb.PetCache.special[name][3].."_" .. tonumber(kb.PetCache.special[name][6]) + end + return CLICK_KEYBINDER_MACRO, attributeName, attributeValue, SkeletonKeyMacro +end + +atype['battlepet'] = function(id, name) + return CLICK_KEYBINDER_MACRO, 'battlepet_' .. tostring(name), SLASH_SUMMON_BATTLE_PET1 .. " " .. tostring(name), SkeletonKeyMacro +end + +atype['item'] = function(id, name) + return CLICK_KEYBINDER_KEY, tostring(name), id, SkeletonKeyKey +end + + +--- Resolves the SecureActionButton attribute names used for the given action +kb.RegisterAction = function(actionType, id, name) + assert(atype[actionType], 'Missing actionType handler for `'..tostring(actionType)..'`') + local target, attributeName, attributeValue, button = atype[actionType](id, name) + local command = target .. attributeName + + return attributeName, attributeValue, command, target, button +end + + + + +kb.ApplyTalentBinding = function(talentInfo, cache) + talentInfo.assignedKeys = talentInfo.assignedKeys or {} + for i , key in pairs(talentInfo.assignedKeys) do + local command = CLICK_KEYBINDER_KEY.. talentInfo.actionName + SetBinding(key, command) + cprint(' **', i, '->', command) + tinsert(cache, talentInfo) + end +end +kb.CacheTalentBinding = function(talentInfo, cache) + + local spellID = talentInfo.actionID + cache[spellID] = cache[spellID] or {} + cache[spellID] = talentInfo + cprint(spellID, unpack(kb.TalentBindings[spellID])) +end + + +do + local commandActions = {} + local bindings = kb.bindings + local key, macro = SkeletonKeyKey, SkeletonKeyMacro + kb.LoadBinding = function( configTable) + if configTable.command then + configTable.command = configTable.command:gsub('KeyBinder', 'SkeletonKey') + end + + local command, name, icon, actionType, actionID, macroName, macroText = + configTable.command, configTable.actionName, configTable.iconPath, configTable.actionType, + configTable.actionID, configTable.macroName, configTable.macroText + + + local indexKey = actionType..'_'..actionID + local actionPrefix = "*"..actionType.."-" + local button = SkeletonKeyKey + local isAvailable = true + local specialButtonType + if actionType == 'spell' then + if not GetSpellInfo(actionID) then + isAvailable = nil + end + local dynamicInfo = kb.TalentCache[name] or kb.ProfessionCache[name] + if dynamicInfo then + cprint('|cFF00FFFFDynamicInfo:|r', name) + for k, v in pairs(dynamicInfo) do + cprint(' --', k, v) + configTable[k] = v + end + end + else + if actionType ~= 'macro' then + actionPrefix = '*macrotext-' + end + + specialButtonType = 'macro' + end + + local attributeSuffix, attributeValue, command, target, button = kb.RegisterAction(actionType, actionID, name) + local actionKey = actionPrefix .. attributeSuffix + cprint('|cFF00FF88LoadBinding()|r', button:GetName(), "*type-"..attributeSuffix, actionType, '|cFFFFFF00'..actionKey, attributeValue) + + + + if isAvailable then + kb.SecureAttribute(button, "*type-"..attributeSuffix, specialButtonType or actionType) + kb.SecureAttribute(button, actionKey, attributeValue) + kb.bindings[indexKey] = configTable.assignedKeys + commandActions[command] = kb.bindings[indexKey] + return command, kb.bindings[indexKey] + else + return nil + end + end + + local usedSlots = {} + kb.ApplyBindings = function (profile) + cprint('|cFF0088FFApplyBindings()') + --cprint('binding profile', profile) + + wipe(usedSlots) + for slot, configTable in pairs(profile.buttons) do + + + if #configTable >= 1 then + local command, name, icon, actionType, actionID, macroName, macroText, spellbookSlot, spellbookType = unpack(configTable) + + cprint('|CFFFF4400Fixing pad entry', slot, command, name) + local assignedKeys = {GetBindingKey(command)} + for k,v in pairs(profile.bindings) do + if v == command then + tinsert(assignedKeys, k) + end + end + + configTable = { + command = command, + actionType = actionType, + actionName = name, + actionID = actionID, + macroName = macroName, + macroText = macroText, + iconPath = icon, + spellbookSlot = spellbookSlot, + spellbookType = spellbookType, + assignedKeys = assignedKeys + } + kb.currentProfile.buttons[slot] = configTable + end + if not configTable.actionID then + configTable.actionID = configTable.actionName + end + if not configTable.iconPath then + print('corrected missing icon') + configTable.iconPath = GetSpellTexture(configTable.actionName) + end + + usedSlots[configTable.actionName or configTable.actionID] = true + usedSlots[configTable.command] = true + + if kb.LoadBinding(configTable) then + configTable.isAvailable = true + end + end + + for key, command in pairs(profile.bindings) do + command = command:gsub('KeyBinder', 'SkeletonKey') + profile.bindings[key] = command + cprint('|cFF00FFFF'.. key .. '|r to|cFF00FF00', command) + SetBinding(key, command) + + if commandActions[command] and not tContains(commandActions[command], key) then + tinsert(commandActions[command], key) + end + end + + for spellName, talentInfo in pairs(profile.talents) do + if not usedSlots[spellName] then + cprint('|cFFFF4400Unslotted talent', spellName) + profile.talents[spellName] = nil + end + end + for command in pairs(profile.bound) do + if not usedSlots[command] then + cprint('|cFFFF4400Unslotted bound entry', command) + profile.bound[command] = nil + profile.commands[command] = nil + end + end + for command in pairs(profile.commands) do + if not usedSlots[command] then + cprint('|cFFFF4400Unslotted command entry', command) + profile.commands[command] = nil + end + end + + end + + kb.ApplyAllBindings =function () + cprint('|cFF0088FFApplyAllBindings()') + wipe(kb.TalentBindings) + wipe(kb.bindings) + --kb:print('Loading binding profile', kb.profileName) + + -- reflect action key settings + if GetCVarBool("ActionButtonUseKeyDown") then + SkeletonKeyMacro:RegisterForClicks("AnyDown") + SkeletonKeyKey:RegisterForClicks("AnyDown") + else + SkeletonKeyMacro:RegisterForClicks("AnyUp") + SkeletonKeyKey:RegisterForClicks("AnyUp") + end + + for i, profile in ipairs(kb.orderedProfiles) do + kb.ApplyBindings(profile) + end + -- do this after to ensure that profession binds are properly overridden + kb.UpdateProfessionInfo() + + SaveBindings(GetCurrentBindingSet()) + end +end + + +kb.specInfo = {} +kb.UpdateSpecInfo = function() + kb.specInfo.id = GetSpecialization() + kb.specInfo.globalID, kb.specInfo.name, kb.specInfo.desc, kb.specInfo.texture = GetSpecializationInfo(kb.specInfo.id) +end + +kb.UpdateMacroInfo = function() + print('|cFFFFFF00kb.UpdateMacroInfo()|r') + for index = 1, GetNumMacros() do + local name = GetMacroInfo(index) + kb.SecureAttribute(SkeletonKeyMacro, "*type-macro_"..tostring(name), 'macro') + kb.SecureAttribute(SkeletonKeyMacro, "*macro-macro_"..tostring(name), index) + end +end + +kb.UpdateTalentInfo = function() + print('|cFFFFFF00kb.UpdateTalentInfo()|r') + if kb.talentsPushed then + return + end + wipe(kb.TalentCache) + for row =1, MAX_TALENT_TIERS do + for col = 1, NUM_TALENT_COLUMNS do + local talentID, talentName, icon, selected, available, spellID = GetTalentInfo(row, col, 1) + local talentInfo = kb.TalentCache[spellID] or {} + if spellID then + talentInfo.actionType = 'spell' + talentInfo.actionName = talentName + talentInfo.dynamicType = 'talent' + talentInfo.dynamicID = talentID + talentInfo.dynamicIndex = row + talentInfo.dynamicSubIndex = col + talentInfo.actionID = spellID + talentInfo.isAvailable = selected + kb.TalentCache[spellID] = talentInfo + kb.TalentCache[talentName] = talentInfo + kb.DynamicSpells[spellID] = talentInfo + kb.DynamicSpells[talentName] = talentInfo + end + + --print('Talent ', row, col, spellID, talentName) + end + end + + for row = 1, MAX_PVP_TALENT_TIERS do + for col = 1, MAX_PVP_TALENT_COLUMNS do + local id, name, icon, selected, available, spellID, unlocked = GetPvpTalentInfo(row, col, 1) + if spellID then + local talentInfo = kb.TalentCache[spellID] or {} + talentInfo.actionType = 'spell' + talentInfo.actionName = name + talentInfo.dynamicType = 'talent' + talentInfo.dynamicID = id + talentInfo.actionID = spellID + talentInfo.isAvailable = selected + kb.TalentCache[spellID] = talentInfo + kb.TalentCache[name] = talentInfo + kb.DynamicSpells[spellID] = talentInfo + kb.DynamicSpells[name] = talentInfo + end + end + end + + kb.talentsPushed = true + + kb.UpdateDynamicButtons('talent') +end + +kb.UpdateProfessionInfo = function() + wipe(kb.ProfessionCache) + local profs = {GetProfessions() } + --print(GetProfessions()) + local primaryNum = 0 + for i = 1, 6 do + if profs[i] then + local profID = profs[i] + local profName, texture, _, _, numSpells, spellOffset = GetProfessionInfo(profID) + cprint(i, profID, profName, numSpells, spellOffset) + if not SECONDARY_PROFESSIONS[profID] then + primaryNum = primaryNum + 1 + end + local profNum = SECONDARY_PROFESSIONS[profID] or primaryNum + cprint(i, profNum) + + + kb.ProfessionCache[profNum] = kb.ProfessionCache[profNum] or {} + + for j = 1, numSpells do + local spellName, _, icon, _, _, _, spellID = GetSpellInfo(spellOffset+j, BOOKTYPE_PROFESSION) + cprint(j, spellName) + local profInfo = { + actionType = 'spell', + actionName = spellName, + statusText = 'Profession ' .. i, + actionID = spellID, + iconPath = icon, + dynamicIndex = i, + dynamicSubIndex = j, + dynamicType = 'profession', + spellbookOffset = (spellOffset+j), + spellbookType = BOOKTYPE_PROFESSION, + isAvailable = true, + -- need to check if necessary + uniqueID = profID, + } + + kb.SecureAttribute(SkeletonKeyKey, "*type-profession_"..i .. '_' ..j, "spell") + kb.SecureAttribute(SkeletonKeyKey, "*spell-profession_"..i .. '_' ..j, spellName) + + kb.ProfessionCache[spellName] = profInfo + kb.ProfessionCache[spellID] = profInfo + + kb.DynamicSpells[spellName] = profInfo + kb.DynamicSpells[spellID] = profInfo + + kb.DynamicSpells.profession[i] = kb.DynamicSpells.profession[i] or {} + kb.DynamicSpells.profession[i][j] = profInfo + --print(' |cFF0088FF['..i..']|r|cFFFF44BB['..spellOffset+i..']|r', spellName, "profession_"..i .. '_' ..j) + end + end + + end + + kb.UpdateDynamicButtons('profession') +end + + + +kb.UpdatePetInfo = function() + local hasPetSpells, petType = HasPetSpells() + + -- reconcile saved data if it becomes available + if kb.db then + kb.db.petSpellsDB = kb.db.petSpellsDB or {} + kb.db.petSpellsDB.subtext = kb.db.petSpellsDB.subtext or {} + kb.db.petSpellsDB.spell = kb.db.petSpellsDB.spell or {} + local spellCache = kb.db.petSpellsDB.spell + local subtextCache = kb.db.petSpellsDB.subtext + if petSpellCache then + for k,v in pairs(petSpellCache) do + if not spellCache[k] then + spellCache[k] = v + end + end + end + petSpellCache = spellCache + if petSubtextCache then + for k,v in pairs(petSubtextCache) do + if not subtextCache[k] then + subtextCache[k] = v + end + end + end + petSubtextCache = subtextCache + else + petSpellCache = {} + petSubtextCache = {} + end + + if PetHasSpellbook() then + --print('PET SPELLBOOK') + local spellbookOffset = 1 + local specialNum = {} + local newSubtextItems = false + + repeat + + local spellType, spellID = GetSpellBookItemInfo(spellbookOffset, BOOKTYPE_PET) + local spellName, subText = GetSpellBookItemName(spellbookOffset, BOOKTYPE_PET) + local texture = GetSpellBookItemTexture(spellbookOffset, BOOKTYPE_PET) + if (spellType == 'SPELL') and (not IsPassiveSpell(spellbookOffset, BOOKTYPE_PET)) then + local info = kb.PetCache[spellName] or {} + kb.PetCache.spellslot[spellName] = {spellbookOffset, spellName, subText, spellID, texture} + --print('|cFF00FF88spellslot['..spellName..']|r', '=>', i, subText) + + if subText then + kb.PetCache.subtext[subText] = kb.PetCache.subtext[subText] or {} + specialNum[subText] = (specialNum[subText] or 0) + 1 + + petSpellCache[spellName] = subText + petSubtextCache[subText] = petSubtextCache[subText] or {} + + -- add to the list + if not petSubtextCache[subText][spellName] then + petSubtextCache[subText][spellName] = true + newSubtextItems = true + --print('|cFF00FFFFspecial['..spellName..']|r', '\n','|cFF00FFFFsubtext['..subText..']['..specialNum[subText]..']|r', '=>', i, spellName, subText, spellID, texture, specialNum[subText]) + end + + + + local entry = {spellbookOffset, spellName, subText, spellID, texture, specialNum[subText] } + + + info.spellbookOffset = spellbookOffset + info.spellbookType = BOOKTYPE_PET + info.actionName = spellName + info.spellID = spellID + info.dynamicType = 'petaction' + info.dynamicID = spellID + info.dynamicIndex = subText + info.dynamicSubIndex = specialNum[subText] + info.isAvailable = true + + kb.PetCache.special[spellName] = info + kb.PetCache.subtext[subText][specialNum[subText]] = info + kb.DynamicSpells[spellName] = info + kb.DynamicSpells[spellID] = info + + end + + if spellID then + kb.PetCache.spell[spellbookOffset] = {spellID, spellName, subText} + --print('|cFF0088FFspell['..i..']|r', '=>', spellID, spellName, subText) + end + + kb.PetCache[spellName] = info + end + + spellbookOffset = spellbookOffset + 1 + until spellType == nil + + if newSubtextItems then + + local macrotext = "" + for subText, spells in pairs(petSubtextCache) do + if specialNum[subText] then + for spellName, enabled in pairs(spells) do + macrotext = macrotext .. "/cast " .. spellName .. "\n" + end + kb.SecureAttribute(SkeletonKeyMacro, "*macrotext-petaction_"..subText.."_"..specialNum[subText], macrotext) + end + end + end + + + else + --print('NO PET SPELLBOOK') + wipe(kb.PetCache.spell) + wipe(kb.PetCache.spellslot) + end + + if PetHasActionBar() then + --print('PET ACTION BAR') + for i = 1, 10 do + + + local name, subtext, texture, isToken, isActive = GetPetActionInfo(i) + if name then + kb.PetCache.action[i] = {name, subtext, texture, isToken, isActive } + + + end + --print('|cFFFFFF00action['..i..']|r', name, subtext, texture) + end + else + --print('NO PET ACTION BAR') + wipe(kb.PetCache.action) + end + + kb.UpdateDynamicButtons('petaction') + +end + +kb.UpdateSystemBinds = function() + wipe(kb.SystemBindings) + local n = GetNumBindings() + for i=1, n do + local command, key1, key2 = GetBinding(i) + if not command:match('ACTION.*%d+') then + if key1 then + kb.SystemBindings[key1] = command + end + if key2 then + kb.SystemBindings[key2] = command + end + else + --print('ignoring action button binding', command) + end + end +end + +kb.UpdateDynamicButtons = function(dynamicType) + for i, button in ipairs(kb.buttons) do + if button.isDynamic == dynamicType then + kb.UpdateSlot(button, true) + end + end +end + +kb.pendingAttributes = {} +kb.SecureAttribute = function(target, name, value) + if InCombatLockdown() then + if #kb.pendingAttributes == 0 then + kb:print(kb.L('Key bindings will be applied when you exit combat.')) + end + + tinsert(kb.pendingAttributes, {target, name, value}) + SkeletonKey:RegisterEvent('PLAYER_REGEN_ENABLED') + + else + + --cprint('|cFFFF4444' .. target:GetName()..'|r.|cFFFFFF00'.. tostring(name)..'|r = "'..tostring(value)..'"') + target:SetAttribute(name, value) + end +end + +kb.PLAYER_REGEN_ENABLED = function() + if #kb.pendingAttributes >= 1 then + local args = tremove(kb.pendingAttributes) + while args do + local target, name, value = unpack(args) + --print(target:GetName(), 'attribute', '"'.. tostring(name)..'" = "'..tostring(value)..'"') + cprint('deferred', target:GetName(), 'attribute', '"'.. tostring(name)..'" = "'..tostring(value)..'"') + target:SetAttribute(name, value) + args = tremove(kb.pendingAttributes) + end + end + + if #kb.pendingCalls >= 1 then + + local func = tremove(kb.pendingCalls) + while func do + func() + end + end +end + +kb.UpdateBindingsCache = function(actionType, actionID, bindings) + local indexKey = actionType .. '_' .. actionID + kb.bindings[indexKey] = bindings + + cprint('|cFF00FF00'..indexKey..'|r = {'.. table.concat(bindings,', ').. '}') + tinsert(kb.ChangedBindings, {actionType, actionID}) +end \ No newline at end of file