annotate ActionTemplates.lua @ 87:b80e78f4a17b

Unintended fork
author Nenue
date Tue, 17 Jul 2018 14:49:10 -0400
parents d6831be74cf4 1605319122ce
children f9df7cd7bfd6
rev   line source
Nenue@70 1 -- SkeletonKey
Nenue@70 2 -- ActionTemplates.lua
Nenue@70 3 -- Created: 7/29/2016 9:14 PM
Nenue@70 4 -- %file-revision%
Nenue@70 5 -- Code dealing with the implementation of action hotkeys
Nenue@70 6
Nenue@70 7 local tostring, tonumber, pairs, ipairs = tostring, tonumber, pairs, ipairs
Nenue@70 8 local unpack, SetBinding = unpack, SetBinding
Nenue@70 9 local tinsert, tContains, select, wipe = tinsert, tContains, select, table.wipe
Nenue@70 10 local GetSpellBookItemInfo, GetSpellBookItemName, GetSpellInfo = GetSpellBookItemInfo, GetSpellBookItemName, GetSpellInfo
Nenue@70 11 local GetSpecialization, GetSpecializationInfo, IsPassiveSpell, IsTalentSpell = GetSpecialization, GetSpecializationInfo, IsPassiveSpell, IsTalentSpell
Nenue@70 12 local PetHasSpellbook, PetHasActionBar, GetPetActionInfo, HasPetSpells = PetHasSpellbook, PetHasActionBar, GetPetActionInfo, HasPetSpells
Nenue@70 13 local GetProfessions, GetProfessionInfo, GetTalentInfo = GetProfessions, GetProfessionInfo, GetTalentInfo
Nenue@70 14 local GetNumBindings, GetBinding = GetNumBindings, GetBinding
Nenue@70 15
Nenue@70 16 local _, kb = ...
Nenue@70 17 local print = (DEVIAN_PNAME == 'SkeletonKey') and function(...) print('SK', ...) end or nop
Nenue@70 18 local cprint = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('Cfg', ...) end or nop
Nenue@70 19
Nenue@70 20 local CLICK_KEYBINDER_MACRO = "CLICK SkeletonKeyMacro:"
Nenue@70 21 local CLICK_KEYBINDER_KEY = "CLICK SkeletonKeyKey:"
Nenue@70 22 local PET_BASIC_SUBTEXT = 'Basic Attack'
Nenue@70 23 local PET_SPECIAL_SUBTEXT = 'Special Ability'
Nenue@70 24 local PETACTION_SCRIPT = {
Nenue@70 25 [PET_ACTION_MOVE_TO] = {'pet_move_to', SLASH_PET_MOVE_TO1},
Nenue@70 26 [PET_ACTION_ATTACK] = {'pet_attack', SLASH_PET_ATTACK1},
Nenue@70 27 [PET_ACTION_FOLLOW] = {'pet_follow', SLASH_PET_FOLLOW1},
Nenue@70 28 [PET_ACTION_WAIT] = {'pet_stay', SLASH_PET_STAY1 },
Nenue@70 29 [PET_MODE_AGGRESSIVE] = {'pet_aggressive', SLASH_PET_AGGRESSIVE1 },
Nenue@70 30 [PET_MODE_DEFENSIVE] = { 'pet_defensive', SLASH_PET_DEFENSIVE1},
Nenue@70 31 [PET_MODE_PASSIVE] = { 'pet_passive', SLASH_PET_PASSIVE1},
Nenue@70 32 [PET_MODE_ASSIST] = {'pet_assist', SLASH_PET_ASSIST1},
Nenue@70 33 }
Nenue@70 34 local SECONDARY_PROFESSIONS = {
Nenue@70 35 [5] = 3,
Nenue@70 36 [7] = 4,
Nenue@70 37 [9] = 5,
Nenue@70 38 [10] = 6
Nenue@70 39 }
Nenue@81 40
Nenue@81 41
Nenue@70 42 local petSpellCache,petSubtextCache
Nenue@70 43 local SUMMON_RANDOM_FAVORITE_MOUNT_SPELL = 150544
Nenue@70 44
Nenue@70 45
Nenue@70 46 local atype = kb.ActionTypes
Nenue@70 47
Nenue@70 48 --- Caps Lock
Nenue@70 49 atype['mount'] = function(id, name)
Nenue@70 50 if id == SUMMON_RANDOM_FAVORITE_MOUNT_SPELL then
Nenue@70 51 return CLICK_KEYBINDER_MACRO, 'mount_random', "/script C_MountJournal.SummonByID(0)", SkeletonKeyMacro
Nenue@70 52 else
Nenue@70 53 return CLICK_KEYBINDER_MACRO, 'mount_'..id, "/script C_MountJournal.SummonByID("..id..")", SkeletonKeyMacro
Nenue@70 54 end
Nenue@70 55 end
Nenue@70 56
Nenue@70 57 atype['macro'] = function(id, name)
Nenue@70 58 local _, _, text = GetMacroInfo(id)
Nenue@70 59 return CLICK_KEYBINDER_MACRO, 'macro_' .. tostring(name), name, SkeletonKeyMacro
Nenue@70 60 end
Nenue@70 61
Nenue@70 62 atype['equipset'] = function(id, name)
Nenue@70 63 return CLICK_KEYBINDER_MACRO, 'equipset_'..tostring(name), "/script UseEquipmentSet("..tostring(id)..")", SkeletonKeyMacro
Nenue@70 64 end
Nenue@70 65
Nenue@70 66 atype['spell'] = function(id, name)
Nenue@70 67 local attributeName = name
Nenue@78 68 local profInfo = kb.DynamicSpells.profession[id]
Nenue@78 69 if profInfo then
Nenue@78 70 attributeName = "profession_".. profInfo.dynamicIndex .. '_' .. profInfo.dynamicSubIndex
Nenue@70 71 end
Nenue@70 72 return CLICK_KEYBINDER_KEY, attributeName, name, SkeletonKeyKey
Nenue@70 73 end
Nenue@70 74
Nenue@70 75 atype['petaction'] = function(_, name)
Nenue@70 76 -- ID doesn't exist for basic commands, even though they can be picked up
Nenue@70 77 local attributeName, attributeValue = "petaction_" .. tostring(name), "/cast "..tostring(name)
Nenue@70 78
Nenue@70 79 if not petSpellCache then
Nenue@70 80 kb.UpdatePetInfo()
Nenue@70 81 end
Nenue@70 82 -- Compose a multi-macro for subtext abilities
Nenue@70 83 if petSpellCache[name] then
Nenue@70 84 attributeValue = ""
Nenue@70 85 for spellName, enabled in pairs(petSubtextCache[petSpellCache[name]]) do
Nenue@70 86 attributeValue = attributeValue .. "/cast " .. spellName .. "\n"
Nenue@70 87 end
Nenue@70 88 end
Nenue@70 89
Nenue@70 90 if PETACTION_SCRIPT[name] then
Nenue@70 91 attributeName, attributeValue = unpack(PETACTION_SCRIPT[name])
Nenue@70 92 elseif kb.PetCache.special[name] then
Nenue@70 93 attributeName = "petaction_"..kb.PetCache.special[name][3].."_" .. tonumber(kb.PetCache.special[name][6])
Nenue@70 94 end
Nenue@70 95 return CLICK_KEYBINDER_MACRO, attributeName, attributeValue, SkeletonKeyMacro
Nenue@70 96 end
Nenue@70 97
Nenue@70 98 atype['battlepet'] = function(id, name)
Nenue@70 99 return CLICK_KEYBINDER_MACRO, 'battlepet_' .. tostring(name), SLASH_SUMMON_BATTLE_PET1 .. " " .. tostring(name), SkeletonKeyMacro
Nenue@70 100 end
Nenue@70 101
Nenue@70 102 atype['item'] = function(id, name)
Nenue@75 103 return CLICK_KEYBINDER_KEY, tostring(name), tostring(name), SkeletonKeyKey
Nenue@70 104 end
Nenue@70 105
Nenue@70 106
Nenue@70 107 --- Resolves the SecureActionButton attribute names used for the given action
Nenue@70 108 kb.RegisterAction = function(actionType, id, name)
Nenue@83 109 if not atype[actionType]then
Nenue@83 110 kb.print('Missing actionType handler for `'..tostring(actionType)..'`')
Nenue@83 111 return
Nenue@83 112 end
Nenue@74 113 local prefix, attributeName, attributeValue, button = atype[actionType](id, name)
Nenue@74 114 local command = prefix .. attributeName
Nenue@74 115 return attributeName, attributeValue, command, prefix, button
Nenue@70 116 end
Nenue@70 117
Nenue@70 118
Nenue@74 119 local spells = {}
Nenue@74 120 local SkeletonKey_GetGenericSpell = function(spellName, spellID, icon)
Nenue@74 121 if not spells[spellID] then
Nenue@74 122 spells[spellID] = {}
Nenue@74 123 spells[spellID].actionType = 'spell'
Nenue@74 124 spells[spellID].actionID = spellID
Nenue@74 125 spells[spellID].actionName = spellName
Nenue@74 126 spells[spellID].iconPath = icon
Nenue@74 127 spells[spellID].statusText = '|cFFBBBBBBSpell|r'
Nenue@74 128 spells[spellID].dynamicType = nil
Nenue@74 129 end
Nenue@74 130 return spells[spellID]
Nenue@74 131 end
Nenue@74 132
Nick@80 133 -- verifies binding slot data
Nenue@74 134 local dynamicTypes = {['profession'] = 'ProfessionCache', ['talent'] = 'TalentCache', ['petaction'] = 'PetInfoCache'}
Nenue@74 135 kb.ResolveSpellSlot = function(self)
Nenue@74 136 local spellName, spellID, command, icon = self.actionName, self.actionID, self.command, self.iconPath
Nick@80 137
Nenue@74 138 --print(GetSpellInfo(spellName or spellID))
Nick@80 139 local internalName, _, internalIcon, _, _, _, _ = GetSpellInfo(spellID)
Nick@80 140 local replacerName, _, _, _, _, _, replacerID = GetSpellInfo(internalName)
Nick@80 141 print('Resolve Slot: id =', spellID, 'nameFromID =', internalName, 'nameFromName =', replacerName)
Nenue@74 142 local isAvailable = internalName and true
Nenue@74 143
Nick@80 144 -- keep current slotInfo if it's a spell that has been replaced by spec/talent
Nick@80 145 if internalName and (internalName ~= replacerName) then
Nick@80 146 print(' |cFFFF4400spell name is overridden by', replacerName, '(was', internalName,')')
Nenue@74 147 self.statusText = '|cFFFFFF00Spell|r'
Nenue@74 148 self.isAvailable = true
Nenue@74 149 return
Nenue@74 150 end
Nenue@74 151
Nick@80 152 -- resolve spell name
Nick@80 153 local info = kb.DynamicSpells[spellName]
Nenue@74 154 if not info then
Nenue@74 155 local dynamicType, dynamicIndex, dynamicSubIndex = command:match("(%a+)_(%S+)_(%S+)")
Nenue@74 156 if kb.DynamicSpells[dynamicType] then
Nenue@74 157 print('|cFFFF4400resolving dynamic type index:', internalName, spellName, command)
Nenue@74 158 dynamicIndex = tonumber(dynamicIndex)
Nenue@74 159 dynamicSubIndex = tonumber(dynamicSubIndex)
Nenue@74 160 local cache = kb.DynamicSpells[dynamicType]
Nenue@74 161 print('type:', dynamicType)
Nenue@74 162 if dynamicIndex and cache[dynamicIndex] then
Nenue@74 163 info = kb.DynamicSpells[dynamicType][dynamicIndex]
Nenue@74 164 print('index:', dynamicIndex)
Nenue@74 165 if dynamicSubIndex and info[dynamicSubIndex] then
Nenue@74 166 info = info[dynamicSubIndex]
Nenue@74 167 print('sub-index:', dynamicSubIndex)
Nenue@74 168 end
Nenue@74 169 isAvailable = true
Nenue@74 170 end
Nenue@74 171 end
Nenue@74 172 if not info then
Nenue@74 173 info = SkeletonKey_GetGenericSpell(spellName, spellID, internalIcon or icon)
Nenue@74 174 end
Nenue@74 175 end
Nenue@81 176
Nenue@81 177
Nenue@81 178
Nenue@74 179 info.isAvailable = isAvailable
Nenue@74 180
Nenue@74 181 print('|cFF00FF88Slot Details:|r', info.actionName, info.actionID, info.dynamicType, info.isAvailable)
Nenue@74 182 for k,v in pairs(info) do
Nenue@74 183 --cprint(' ',k,v)
Nenue@74 184 self[k] = v
Nenue@74 185 end
Nenue@74 186
Nenue@74 187 return info
Nenue@74 188 end
Nenue@70 189
Nenue@70 190 do
Nenue@76 191 local PROFILE_VERSION = 320
Nenue@70 192 local commandActions = {}
Nenue@70 193 local bindings = kb.bindings
Nenue@70 194 local key, macro = SkeletonKeyKey, SkeletonKeyMacro
Nenue@70 195 kb.LoadBinding = function( configTable)
Nenue@70 196 if configTable.command then
Nenue@70 197 configTable.command = configTable.command:gsub('KeyBinder', 'SkeletonKey')
Nenue@70 198 end
Nenue@70 199
Nenue@83 200 cprint('|cFF0088FFLoadBinding()|r', configTable.actionName, configTable.dynamicType)
Nenue@83 201 local isAvailable
Nenue@83 202 local dynamicType = configTable.dynamicType
Nenue@83 203 if dynamicType == 'profession' then
Nenue@83 204 local dynamicIndex, dynamicSubIndex = tonumber(configTable.dynamicIndex), tonumber(configTable.dynamicSubIndex)
Nenue@83 205 cprint(' |cFF00FFFFDynamicInfo:|r', dynamicType, dynamicIndex, dynamicSubIndex)
Nenue@83 206
Nenue@83 207 local extendedTable = kb.DynamicSpells[dynamicType][dynamicIndex]
Nenue@83 208
Nenue@83 209 if extendedTable then
Nenue@83 210 cprint(extendedTable)
Nenue@83 211 for k,v in pairs(extendedTable) do
Nenue@83 212 cprint(type(k), k)
Nenue@83 213 end
Nenue@83 214 local subTable = extendedTable[dynamicSubIndex]
Nenue@83 215
Nenue@83 216 if subTable then
Nenue@83 217 for k,v in pairs(subTable) do
Nenue@83 218 cprint(' override', k, '=', v, '(was', configTable[k])
Nenue@83 219 configTable[k] = subTable[k]
Nenue@83 220 end
Nenue@83 221 --isAvailable = configTable.isAvailabl
Nenue@83 222 --name, actionID = configTable.actionName, configTable.actionID
Nenue@83 223 cprint(subTable.actionName, subTable.actionID)
Nenue@83 224 isAvailable = true
Nenue@83 225 end
Nenue@83 226 end
Nenue@83 227 end
Nenue@83 228
Nenue@70 229 local command, name, icon, actionType, actionID, macroName, macroText =
Nenue@70 230 configTable.command, configTable.actionName, configTable.iconPath, configTable.actionType,
Nenue@70 231 configTable.actionID, configTable.macroName, configTable.macroText
Nenue@70 232
Nenue@83 233 local indexKey = tostring(actionType)..'_'..tostring(actionID)
Nenue@83 234 local actionPrefix = "*"..tostring(actionType).."-"
Nenue@70 235 local button = SkeletonKeyKey
Nenue@70 236 local specialButtonType
Nenue@70 237 if actionType == 'spell' then
Nick@80 238 local realName, _, _, _, _, _, realID = GetSpellInfo(name)
Nenue@83 239
Nenue@81 240 if realName then
Nenue@81 241 if (realName ~= name) then
Nenue@83 242 cprint(' *** "', name, '" is replaced by...', realName, realID)
Nick@80 243 --name, actionID = realName, realID
Nick@80 244 indexKey = actionType .. '_'.. realID
Nenue@81 245 end
Nenue@83 246 elseif dynamicType == 'talent' then
Nenue@83 247 cprint(' |cFF00FFFFDynamicInfo:|r', dynamicType, table.concat(configTable.assignedKeys, ','))
Nenue@83 248 cprint(' *** "', name, '" is a non-selected talent.')
Nenue@81 249 return
Nick@80 250 end
Nick@80 251
Nenue@83 252 if GetSpellInfo(realName or name) then
Nick@80 253
Nenue@76 254 isAvailable = true
Nenue@76 255
Nenue@70 256 end
Nenue@75 257 elseif actionType == 'item' then
Nenue@75 258 actionID = configTable.actionName
Nenue@75 259 isAvailable = true
Nenue@75 260 else
Nenue@71 261
Nenue@70 262 if actionType ~= 'macro' then
Nenue@70 263 actionPrefix = '*macrotext-'
Nenue@70 264 end
Nenue@70 265
Nenue@70 266 specialButtonType = 'macro'
Nenue@73 267 isAvailable = true
Nenue@70 268 end
Nenue@70 269
Nenue@72 270 if isAvailable then
Nenue@83 271 cprint(' available', actionType, actionID, name)
Nenue@70 272
Nenue@72 273 local attributeSuffix, attributeValue, command, target, button = kb.RegisterAction(actionType, actionID, name)
Nenue@83 274 local actionKey = tostring(actionPrefix) .. tostring(attributeSuffix)
Nenue@83 275
Nenue@83 276 if not attributeSuffix then
Nenue@83 277 cprint('failed to generate button attribute')
Nenue@83 278 return
Nenue@83 279 end
Nenue@83 280
Nenue@83 281
Nenue@83 282 cprint('|cFF00FF88 result:|r', button and button:GetName(), "*type-"..tostring(attributeSuffix), actionType, '|cFFFFFF00'..actionKey, attributeValue, isAvailable)
Nenue@70 283
Nenue@70 284
Nenue@70 285 kb.SecureAttribute(button, "*type-"..attributeSuffix, specialButtonType or actionType)
Nenue@70 286 kb.SecureAttribute(button, actionKey, attributeValue)
Nenue@72 287
Nenue@83 288 cprint(' |cFFFF4400add', name, isAvailable, indexKey, unpack(configTable.assignedKeys))
Nenue@70 289 kb.bindings[indexKey] = configTable.assignedKeys
Nenue@70 290 commandActions[command] = kb.bindings[indexKey]
Nenue@70 291 return command, kb.bindings[indexKey]
Nenue@70 292 else
Nenue@72 293 if kb.bindings[indexKey] then
Nenue@83 294 cprint(' |cFFFF4400remove', name, isAvailable, indexKey, unpack(configTable.assignedKeys))
Nenue@72 295 kb.bindings[indexKey] = nil
Nenue@72 296 end
Nenue@72 297
Nenue@70 298 return nil
Nenue@70 299 end
Nenue@70 300 end
Nenue@70 301
Nenue@71 302
Nenue@70 303 local usedSlots = {}
Nenue@71 304 kb.UpgradeProfile = function(profile)
Nenue@70 305 wipe(usedSlots)
Nenue@70 306 for slot, configTable in pairs(profile.buttons) do
Nenue@70 307
Nenue@71 308 -- convert old style table
Nenue@70 309 if #configTable >= 1 then
Nenue@70 310 local command, name, icon, actionType, actionID, macroName, macroText, spellbookSlot, spellbookType = unpack(configTable)
Nenue@70 311
Nenue@70 312 cprint('|CFFFF4400Fixing pad entry', slot, command, name)
Nenue@70 313 local assignedKeys = {GetBindingKey(command)}
Nenue@70 314 for k,v in pairs(profile.bindings) do
Nenue@70 315 if v == command then
Nenue@70 316 tinsert(assignedKeys, k)
Nenue@70 317 end
Nenue@70 318 end
Nenue@70 319
Nenue@70 320 configTable = {
Nenue@70 321 command = command,
Nenue@70 322 actionType = actionType,
Nenue@70 323 actionName = name,
Nenue@70 324 actionID = actionID,
Nenue@70 325 macroName = macroName,
Nenue@70 326 macroText = macroText,
Nenue@70 327 iconPath = icon,
Nenue@70 328 spellbookSlot = spellbookSlot,
Nenue@70 329 spellbookType = spellbookType,
Nenue@70 330 assignedKeys = assignedKeys
Nenue@70 331 }
Nenue@71 332
Nenue@71 333 local dynamic = kb.DynamicSpells[name]
Nenue@71 334 if dynamic then
Nenue@71 335 configTable.dynamicType = dynamic.dynamicType
Nenue@71 336 configTable.dynamicIndex = dynamic.dynamicIndex
Nenue@71 337 configTable.dynamicSubIndex = dynamic.dynamicSubIndex
Nenue@71 338 configTable.dynamicID = dynamic.dynamicID
Nenue@71 339 if configTable.dynamicType == 'talent' then
Nenue@71 340 profile.talents[name] = configTable
Nenue@71 341 end
Nenue@71 342 end
Nenue@71 343
Nenue@71 344
Nenue@70 345 kb.currentProfile.buttons[slot] = configTable
Nenue@70 346 end
Nenue@70 347 if not configTable.actionID then
Nenue@70 348 configTable.actionID = configTable.actionName
Nenue@70 349 end
Nenue@70 350 if not configTable.iconPath then
Nenue@70 351 print('corrected missing icon')
Nenue@70 352 configTable.iconPath = GetSpellTexture(configTable.actionName)
Nenue@70 353 end
Nenue@70 354
Nenue@70 355 usedSlots[configTable.actionName or configTable.actionID] = true
Nenue@70 356 usedSlots[configTable.command] = true
Nenue@70 357 end
Nenue@70 358
Nenue@70 359
Nenue@71 360 -- clean up legacy data
Nenue@70 361 for spellName, talentInfo in pairs(profile.talents) do
Nenue@70 362 if not usedSlots[spellName] then
Nenue@70 363 cprint('|cFFFF4400Unslotted talent', spellName)
Nenue@70 364 profile.talents[spellName] = nil
Nenue@70 365 end
Nenue@70 366 end
Nenue@70 367 for command in pairs(profile.bound) do
Nenue@70 368 if not usedSlots[command] then
Nenue@70 369 cprint('|cFFFF4400Unslotted bound entry', command)
Nenue@70 370 profile.bound[command] = nil
Nenue@70 371 profile.commands[command] = nil
Nenue@70 372 end
Nenue@70 373 end
Nenue@70 374 for command in pairs(profile.commands) do
Nenue@70 375 if not usedSlots[command] then
Nenue@70 376 cprint('|cFFFF4400Unslotted command entry', command)
Nenue@70 377 profile.commands[command] = nil
Nenue@70 378 end
Nenue@70 379 end
Nenue@76 380
Nenue@76 381 if profile.talents then
Nenue@76 382 profile.talents = nil
Nenue@76 383 end
Nenue@76 384
Nenue@76 385
Nenue@76 386 profile.versionID = PROFILE_VERSION
Nenue@71 387 end
Nenue@70 388
Nenue@71 389 kb.ApplyBindings = function (profile)
Nenue@71 390 cprint('|cFF0088FFApplyBindings()')
Nenue@71 391 --cprint('binding profile', profile)
Nenue@71 392
Nenue@71 393 local version = profile.versionID or 0
Nenue@76 394 if version < PROFILE_VERSION then
Nenue@71 395 kb.UpgradeProfile(profile)
Nenue@71 396 end
Nenue@71 397
Nenue@71 398
Nenue@71 399 -- then buttons
Nenue@71 400 for slot, configTable in pairs(profile.buttons) do
Nenue@71 401 -- convert old style table
Nenue@71 402 if kb.LoadBinding(configTable) then
Nenue@76 403
Nenue@71 404 if not configTable.assignedKeys then
Nenue@75 405 configTable.assignedKeys = {GetBindingKey(configTable.command)}
Nenue@71 406 end
Nenue@75 407 --if configTable.dynamicType == 'talent' then
Nenue@75 408 -- kb:print(table.concat(configTable.assignedKeys, ', ') .. ' bound to '.. configTable.actionName)
Nenue@75 409 --end
Nenue@74 410 for _, key in pairs(configTable.assignedKeys) do
Nenue@76 411 local command = configTable.command
Nenue@76 412 cprint('|cFF00FFFF'.. key .. '|r to|cFF00FF00', command)
Nenue@76 413 SetBinding(key, command)
Nenue@76 414 if commandActions[command] and not tContains(commandActions[command], key) then
Nenue@76 415 tinsert(commandActions[command], key)
Nenue@76 416 end
Nenue@74 417 end
Nenue@74 418
Nenue@71 419 end
Nenue@71 420 end
Nenue@70 421 end
Nenue@70 422
Nenue@70 423 kb.ApplyAllBindings =function ()
Nenue@74 424 print('|cFFFFFF00ApplyAllBindings()')
Nenue@70 425 wipe(kb.bindings)
Nenue@70 426 --kb:print('Loading binding profile', kb.profileName)
Nenue@70 427
Nenue@70 428 -- reflect action key settings
Nenue@70 429 if GetCVarBool("ActionButtonUseKeyDown") then
Nenue@70 430 SkeletonKeyMacro:RegisterForClicks("AnyDown")
Nenue@70 431 SkeletonKeyKey:RegisterForClicks("AnyDown")
Nenue@70 432 else
Nenue@70 433 SkeletonKeyMacro:RegisterForClicks("AnyUp")
Nenue@70 434 SkeletonKeyKey:RegisterForClicks("AnyUp")
Nenue@70 435 end
Nenue@70 436
Nenue@70 437 for i, profile in ipairs(kb.orderedProfiles) do
Nenue@70 438 kb.ApplyBindings(profile)
Nenue@70 439 end
Nenue@70 440 -- do this after to ensure that profession binds are properly overridden
Nenue@70 441 kb.UpdateProfessionInfo()
Nenue@70 442
Nenue@70 443 SaveBindings(GetCurrentBindingSet())
Nenue@72 444
Nenue@75 445
Nenue@70 446 end
Nenue@70 447 end
Nenue@70 448
Nenue@70 449
Nenue@78 450 local AddSpellInfo = function(id, name, icon, dynamicType, dynamicID, dynamicIndex, dynamicSubIndex, isAvailable)
Nenue@78 451 local spell = kb.DynamicSpells[id] or {}
Nenue@78 452 spell.actionName = name
Nenue@78 453 spell.dynamicType = dynamicType
Nenue@78 454 spell.dynamicID = dynamicID
Nenue@78 455 spell.iconPath = icon
Nenue@78 456 spell.dynamicIndex = dynamicIndex
Nenue@78 457 spell.dynamicSubIndex = dynamicSubIndex
Nenue@78 458 spell.isAvailable = isAvailable
Nenue@78 459 spell.actionType = 'spell'
Nenue@78 460 spell.spellbookType = BOOKTYPE_SPELL
Nenue@78 461 kb.DynamicSpells[name] = spell
Nenue@78 462
Nenue@78 463 local spellList = dynamicType and kb.DynamicSpells[dynamicType]
Nenue@78 464 if spellList then
Nenue@78 465 spellList[dynamicIndex] = spellList[dynamicIndex] or {}
Nenue@78 466 spellList[dynamicIndex][dynamicSubIndex] = spell
Nenue@78 467 end
Nenue@78 468
Nenue@78 469 cprint('|cFF00FFFFSpellInfo:|r', name, isAvailable, dynamicType or 'spell')
Nenue@78 470 end
Nenue@78 471
Nenue@70 472 kb.UpdateSpecInfo = function()
Nenue@70 473 kb.specInfo.id = GetSpecialization()
Nenue@70 474 kb.specInfo.globalID, kb.specInfo.name, kb.specInfo.desc, kb.specInfo.texture = GetSpecializationInfo(kb.specInfo.id)
Nenue@70 475 end
Nenue@70 476
Nenue@70 477 kb.UpdateMacroInfo = function()
Nenue@70 478 print('|cFFFFFF00kb.UpdateMacroInfo()|r')
Nenue@70 479 for index = 1, GetNumMacros() do
Nenue@70 480 local name = GetMacroInfo(index)
Nenue@70 481 kb.SecureAttribute(SkeletonKeyMacro, "*type-macro_"..tostring(name), 'macro')
Nenue@70 482 kb.SecureAttribute(SkeletonKeyMacro, "*macro-macro_"..tostring(name), index)
Nenue@70 483 end
Nenue@70 484 end
Nenue@70 485
Nenue@78 486
Nenue@70 487 kb.UpdateTalentInfo = function()
Nenue@78 488 print('|cFFFFFF00kb.UpdateSpells()|r')
Nenue@78 489 cprint('|cFFFFFF00kb.UpdateSpells()|r')
Nenue@70 490 if kb.talentsPushed then
Nenue@70 491 return
Nenue@70 492 end
Nenue@70 493 for row =1, MAX_TALENT_TIERS do
Nenue@70 494 for col = 1, NUM_TALENT_COLUMNS do
Nenue@70 495 local talentID, talentName, icon, selected, available, spellID = GetTalentInfo(row, col, 1)
Nenue@78 496 local talentInfo = kb.DynamicSpells[spellID] or {}
Nenue@70 497 if spellID then
Nenue@78 498 AddSpellInfo(spellID, talentName, icon, 'talent', talentID, row, col, selected)
Nenue@70 499 end
Nenue@70 500
Nenue@70 501 end
Nenue@70 502 end
Nenue@70 503
Nenue@86 504 --[[
Nenue@70 505 for row = 1, MAX_PVP_TALENT_TIERS do
Nenue@70 506 for col = 1, MAX_PVP_TALENT_COLUMNS do
Nenue@78 507 local talentID, talentName, icon, selected, available, spellID, unlocked = GetPvpTalentInfo(row, col, 1)
Nenue@70 508 if spellID then
Nenue@78 509 AddSpellInfo(spellID, talentName, icon, 'talent', talentID, row, col, selected)
Nenue@70 510 end
Nenue@70 511 end
Nenue@70 512 end
Nenue@86 513 --]]
Nenue@70 514
Nenue@78 515 local numTabs = GetNumSpellTabs()
Nenue@78 516 for i = 1, numTabs do
Nenue@78 517 local name, texture, offset, numSpells = GetSpellTabInfo(i)
Nenue@78 518 for spellLine = offset+1, offset+numSpells do
Nenue@78 519 local skillType, spellID = GetSpellBookItemInfo(spellLine)
Nenue@78 520 if skillType == 'SPELL' then
Nenue@78 521 local name, _, icon = GetSpellInfo(spellID)
Nenue@78 522 AddSpellInfo(spellID, name, icon, nil, nil, nil, nil, true)
Nenue@78 523 elseif skillType == 'FLYOUT' then
Nenue@78 524 local flyoutID = GetFlyoutID(spellLine)
Nenue@78 525 local _, _, numSlots = GetFlyoutInfo(flyoutID)
Nenue@78 526 if numSlots then
Nenue@78 527 for slot = 1, numSlots do
Nenue@78 528 local spellID, isKnown = GetFlyoutSlotInfo(flyoutID, slot)
Nenue@78 529 local name, rank, icon = GetSpellInfo(spellID)
Nenue@78 530 AddSpellInfo(spellID, name, icon, nil, nil, nil, nil, true)
Nenue@78 531 end
Nenue@78 532 end
Nenue@78 533 end
Nenue@78 534 end
Nenue@78 535 end
Nenue@78 536
Nenue@78 537
Nenue@78 538
Nenue@70 539 kb.talentsPushed = true
Nenue@70 540 kb.UpdateDynamicButtons('talent')
Nenue@70 541 end
Nenue@78 542 kb.UpdateSpells = kb.UpdateTalentInfo
Nenue@70 543
Nenue@70 544 kb.UpdateProfessionInfo = function()
Nenue@70 545 wipe(kb.ProfessionCache)
Nenue@70 546 local profs = {GetProfessions() }
Nenue@70 547 --print(GetProfessions())
Nenue@70 548 local primaryNum = 0
Nenue@70 549 for i = 1, 6 do
Nenue@70 550 if profs[i] then
Nenue@70 551 local profID = profs[i]
Nenue@70 552 local profName, texture, _, _, numSpells, spellOffset = GetProfessionInfo(profID)
Nenue@70 553 cprint(i, profID, profName, numSpells, spellOffset)
Nenue@70 554 if not SECONDARY_PROFESSIONS[profID] then
Nenue@70 555 primaryNum = primaryNum + 1
Nenue@70 556 end
Nenue@70 557 local profNum = SECONDARY_PROFESSIONS[profID] or primaryNum
Nenue@70 558 cprint(i, profNum)
Nenue@70 559
Nenue@70 560
Nenue@70 561 for j = 1, numSpells do
Nenue@70 562 local spellName, _, icon, _, _, _, spellID = GetSpellInfo(spellOffset+j, BOOKTYPE_PROFESSION)
Nenue@70 563 cprint(j, spellName)
Nenue@70 564 local profInfo = {
Nenue@70 565 actionType = 'spell',
Nenue@70 566 actionName = spellName,
Nenue@70 567 actionID = spellID,
Nenue@70 568 iconPath = icon,
Nenue@70 569 dynamicIndex = i,
Nenue@70 570 dynamicSubIndex = j,
Nenue@70 571 dynamicType = 'profession',
Nenue@70 572 spellbookOffset = (spellOffset+j),
Nenue@70 573 spellbookType = BOOKTYPE_PROFESSION,
Nenue@70 574 isAvailable = true,
Nenue@78 575 dynamicID = profID,
Nenue@70 576 }
Nenue@70 577
Nenue@70 578 kb.SecureAttribute(SkeletonKeyKey, "*type-profession_"..i .. '_' ..j, "spell")
Nenue@70 579 kb.SecureAttribute(SkeletonKeyKey, "*spell-profession_"..i .. '_' ..j, spellName)
Nenue@70 580
Nenue@70 581
Nenue@70 582 kb.DynamicSpells[spellName] = profInfo
Nenue@70 583 kb.DynamicSpells[spellID] = profInfo
Nenue@70 584
Nenue@78 585 kb.DynamicSpells.profession[spellName] = profInfo
Nenue@78 586 kb.DynamicSpells.profession[spellID] = profInfo
Nenue@70 587 kb.DynamicSpells.profession[i] = kb.DynamicSpells.profession[i] or {}
Nenue@70 588 kb.DynamicSpells.profession[i][j] = profInfo
Nenue@83 589 cprint(' |cFF0088FF['..i..']|r|cFFFF44BB['..j..']|r', spellName, "profession_"..i .. '_' ..j)
Nenue@70 590 end
Nenue@70 591 end
Nenue@70 592
Nenue@70 593 end
Nenue@70 594
Nenue@70 595 kb.UpdateDynamicButtons('profession')
Nenue@70 596 end
Nenue@70 597
Nenue@70 598
Nenue@70 599
Nenue@70 600 kb.UpdatePetInfo = function()
Nenue@70 601 local hasPetSpells, petType = HasPetSpells()
Nenue@70 602
Nenue@70 603 -- reconcile saved data if it becomes available
Nenue@70 604 if kb.db then
Nenue@70 605 kb.db.petSpellsDB = kb.db.petSpellsDB or {}
Nenue@70 606 kb.db.petSpellsDB.subtext = kb.db.petSpellsDB.subtext or {}
Nenue@70 607 kb.db.petSpellsDB.spell = kb.db.petSpellsDB.spell or {}
Nenue@70 608 local spellCache = kb.db.petSpellsDB.spell
Nenue@70 609 local subtextCache = kb.db.petSpellsDB.subtext
Nenue@70 610 if petSpellCache then
Nenue@70 611 for k,v in pairs(petSpellCache) do
Nenue@70 612 if not spellCache[k] then
Nenue@70 613 spellCache[k] = v
Nenue@70 614 end
Nenue@70 615 end
Nenue@70 616 end
Nenue@70 617 petSpellCache = spellCache
Nenue@70 618 if petSubtextCache then
Nenue@70 619 for k,v in pairs(petSubtextCache) do
Nenue@70 620 if not subtextCache[k] then
Nenue@70 621 subtextCache[k] = v
Nenue@70 622 end
Nenue@70 623 end
Nenue@70 624 end
Nenue@70 625 petSubtextCache = subtextCache
Nenue@70 626 else
Nenue@70 627 petSpellCache = {}
Nenue@70 628 petSubtextCache = {}
Nenue@70 629 end
Nenue@70 630
Nenue@70 631 if PetHasSpellbook() then
Nenue@70 632 --print('PET SPELLBOOK')
Nenue@70 633 local spellbookOffset = 1
Nenue@70 634 local specialNum = {}
Nenue@70 635 local newSubtextItems = false
Nenue@70 636
Nenue@70 637 repeat
Nenue@70 638
Nenue@70 639 local spellType, spellID = GetSpellBookItemInfo(spellbookOffset, BOOKTYPE_PET)
Nenue@70 640 local spellName, subText = GetSpellBookItemName(spellbookOffset, BOOKTYPE_PET)
Nenue@70 641 local texture = GetSpellBookItemTexture(spellbookOffset, BOOKTYPE_PET)
Nenue@70 642 if (spellType == 'SPELL') and (not IsPassiveSpell(spellbookOffset, BOOKTYPE_PET)) then
Nenue@70 643 local info = kb.PetCache[spellName] or {}
Nenue@70 644 kb.PetCache.spellslot[spellName] = {spellbookOffset, spellName, subText, spellID, texture}
Nenue@70 645 --print('|cFF00FF88spellslot['..spellName..']|r', '=>', i, subText)
Nenue@70 646
Nenue@70 647 if subText then
Nenue@70 648 kb.PetCache.subtext[subText] = kb.PetCache.subtext[subText] or {}
Nenue@70 649 specialNum[subText] = (specialNum[subText] or 0) + 1
Nenue@70 650
Nenue@70 651 petSpellCache[spellName] = subText
Nenue@70 652 petSubtextCache[subText] = petSubtextCache[subText] or {}
Nenue@70 653
Nenue@70 654 -- add to the list
Nenue@70 655 if not petSubtextCache[subText][spellName] then
Nenue@70 656 petSubtextCache[subText][spellName] = true
Nenue@70 657 newSubtextItems = true
Nenue@70 658 --print('|cFF00FFFFspecial['..spellName..']|r', '\n','|cFF00FFFFsubtext['..subText..']['..specialNum[subText]..']|r', '=>', i, spellName, subText, spellID, texture, specialNum[subText])
Nenue@70 659 end
Nenue@70 660
Nenue@70 661
Nenue@70 662
Nenue@70 663 local entry = {spellbookOffset, spellName, subText, spellID, texture, specialNum[subText] }
Nenue@70 664
Nenue@70 665
Nenue@70 666 info.spellbookOffset = spellbookOffset
Nenue@70 667 info.spellbookType = BOOKTYPE_PET
Nenue@70 668 info.actionName = spellName
Nenue@70 669 info.spellID = spellID
Nenue@70 670 info.dynamicType = 'petaction'
Nenue@70 671 info.dynamicID = spellID
Nenue@70 672 info.dynamicIndex = subText
Nenue@70 673 info.dynamicSubIndex = specialNum[subText]
Nenue@70 674 info.isAvailable = true
Nenue@70 675
Nenue@70 676 kb.PetCache.special[spellName] = info
Nenue@70 677 kb.PetCache.subtext[subText][specialNum[subText]] = info
Nenue@78 678
Nenue@70 679 kb.DynamicSpells[spellName] = info
Nenue@70 680 kb.DynamicSpells[spellID] = info
Nenue@70 681
Nenue@70 682 end
Nenue@70 683
Nenue@70 684 if spellID then
Nenue@70 685 kb.PetCache.spell[spellbookOffset] = {spellID, spellName, subText}
Nenue@70 686 --print('|cFF0088FFspell['..i..']|r', '=>', spellID, spellName, subText)
Nenue@70 687 end
Nenue@70 688
Nenue@70 689 kb.PetCache[spellName] = info
Nenue@70 690 end
Nenue@70 691
Nenue@70 692 spellbookOffset = spellbookOffset + 1
Nenue@70 693 until spellType == nil
Nenue@70 694
Nenue@70 695 if newSubtextItems then
Nenue@70 696
Nenue@70 697 local macrotext = ""
Nenue@70 698 for subText, spells in pairs(petSubtextCache) do
Nenue@70 699 if specialNum[subText] then
Nenue@70 700 for spellName, enabled in pairs(spells) do
Nenue@70 701 macrotext = macrotext .. "/cast " .. spellName .. "\n"
Nenue@70 702 end
Nenue@70 703 kb.SecureAttribute(SkeletonKeyMacro, "*macrotext-petaction_"..subText.."_"..specialNum[subText], macrotext)
Nenue@70 704 end
Nenue@70 705 end
Nenue@70 706 end
Nenue@70 707
Nenue@70 708
Nenue@70 709 else
Nenue@70 710 --print('NO PET SPELLBOOK')
Nenue@70 711 wipe(kb.PetCache.spell)
Nenue@70 712 wipe(kb.PetCache.spellslot)
Nenue@70 713 end
Nenue@70 714
Nenue@70 715 if PetHasActionBar() then
Nenue@70 716 --print('PET ACTION BAR')
Nenue@70 717 for i = 1, 10 do
Nenue@70 718
Nenue@70 719
Nenue@70 720 local name, subtext, texture, isToken, isActive = GetPetActionInfo(i)
Nenue@70 721 if name then
Nenue@70 722 kb.PetCache.action[i] = {name, subtext, texture, isToken, isActive }
Nenue@70 723
Nenue@70 724
Nenue@70 725 end
Nenue@70 726 --print('|cFFFFFF00action['..i..']|r', name, subtext, texture)
Nenue@70 727 end
Nenue@70 728 else
Nenue@70 729 --print('NO PET ACTION BAR')
Nenue@70 730 wipe(kb.PetCache.action)
Nenue@70 731 end
Nenue@70 732
Nenue@70 733 kb.UpdateDynamicButtons('petaction')
Nenue@70 734
Nenue@70 735 end
Nenue@70 736
Nenue@70 737 kb.UpdateSystemBinds = function()
Nenue@70 738 wipe(kb.SystemBindings)
Nenue@70 739 local n = GetNumBindings()
Nenue@70 740 for i=1, n do
Nenue@70 741 local command, key1, key2 = GetBinding(i)
Nenue@70 742 if not command:match('ACTION.*%d+') then
Nenue@70 743 if key1 then
Nenue@70 744 kb.SystemBindings[key1] = command
Nenue@70 745 end
Nenue@70 746 if key2 then
Nenue@70 747 kb.SystemBindings[key2] = command
Nenue@70 748 end
Nenue@70 749 else
Nenue@70 750 --print('ignoring action button binding', command)
Nenue@70 751 end
Nenue@70 752 end
Nenue@70 753 end
Nenue@70 754
Nenue@70 755 kb.UpdateDynamicButtons = function(dynamicType)
Nenue@70 756 for i, button in ipairs(kb.buttons) do
Nenue@70 757 if button.isDynamic == dynamicType then
Nenue@70 758 kb.UpdateSlot(button, true)
Nenue@70 759 end
Nenue@70 760 end
Nenue@70 761 end
Nenue@70 762
Nenue@70 763 kb.pendingAttributes = {}
Nenue@70 764 kb.SecureAttribute = function(target, name, value)
Nenue@70 765 if InCombatLockdown() then
Nenue@70 766 if #kb.pendingAttributes == 0 then
Nenue@70 767 kb:print(kb.L('Key bindings will be applied when you exit combat.'))
Nenue@70 768 end
Nenue@70 769 tinsert(kb.pendingAttributes, {target, name, value})
Nenue@70 770 SkeletonKey:RegisterEvent('PLAYER_REGEN_ENABLED')
Nenue@70 771 else
Nenue@70 772 --cprint('|cFFFF4444' .. target:GetName()..'|r.|cFFFFFF00'.. tostring(name)..'|r = "'..tostring(value)..'"')
Nenue@70 773 target:SetAttribute(name, value)
Nenue@70 774 end
Nenue@70 775 end
Nenue@70 776
Nenue@70 777 kb.PLAYER_REGEN_ENABLED = function()
Nenue@70 778 if #kb.pendingAttributes >= 1 then
Nenue@70 779 local args = tremove(kb.pendingAttributes)
Nenue@70 780 while args do
Nenue@70 781 local target, name, value = unpack(args)
Nenue@70 782 --print(target:GetName(), 'attribute', '"'.. tostring(name)..'" = "'..tostring(value)..'"')
Nenue@70 783 cprint('deferred', target:GetName(), 'attribute', '"'.. tostring(name)..'" = "'..tostring(value)..'"')
Nenue@70 784 target:SetAttribute(name, value)
Nenue@70 785 args = tremove(kb.pendingAttributes)
Nenue@70 786 end
Nenue@70 787 end
Nenue@70 788
Nenue@70 789 if #kb.pendingCalls >= 1 then
Nenue@70 790
Nenue@70 791 local func = tremove(kb.pendingCalls)
Nenue@70 792 while func do
Nenue@70 793 func()
Nenue@70 794 end
Nenue@70 795 end
Nenue@70 796 end
Nenue@70 797
Nenue@70 798 kb.UpdateBindingsCache = function(actionType, actionID, bindings)
Nenue@70 799 local indexKey = actionType .. '_' .. actionID
Nenue@70 800 kb.bindings[indexKey] = bindings
Nenue@70 801
Nenue@70 802 cprint('|cFF00FF00'..indexKey..'|r = {'.. table.concat(bindings,', ').. '}')
Nenue@70 803 tinsert(kb.ChangedBindings, {actionType, actionID})
Nenue@70 804 end