annotate SkeletonKey/ActionTemplates.lua @ 27:73df13211b22

- actionbar hotkey text properly updates after hotkeys get switched - remove a unused function call
author Nenue
date Tue, 02 Aug 2016 12:33:13 -0400
parents SkeletonKey/ActionTypes.lua@c081f117c19d
children b0e4d04d428a
rev   line source
Nenue@16 1 -- SkeletonKey
Nenue@27 2 -- ActionTemplates.lua
Nenue@16 3 -- Created: 7/29/2016 9:14 PM
Nenue@16 4 -- %file-revision%
Nenue@27 5 -- Code dealing with the implementation of action hotkeys
Nenue@27 6
Nenue@21 7 local tostring, tonumber, pairs, ipairs = tostring, tonumber, pairs, ipairs
Nenue@21 8 local unpack, SetBinding = unpack, SetBinding
Nenue@21 9 local tinsert, tContains, select, wipe = tinsert, tContains, select, table.wipe
Nenue@21 10 local GetSpellBookItemInfo, GetSpellBookItemName, GetSpellInfo = GetSpellBookItemInfo, GetSpellBookItemName, GetSpellInfo
Nenue@21 11 local GetSpecialization, GetSpecializationInfo, IsPassiveSpell, IsTalentSpell = GetSpecialization, GetSpecializationInfo, IsPassiveSpell, IsTalentSpell
Nenue@21 12 local PetHasSpellbook, PetHasActionBar, GetPetActionInfo, HasPetSpells = PetHasSpellbook, PetHasActionBar, GetPetActionInfo, HasPetSpells
Nenue@21 13 local GetProfessions, GetProfessionInfo, GetTalentInfo = GetProfessions, GetProfessionInfo, GetTalentInfo
Nenue@21 14 local GetNumBindings, GetBinding = GetNumBindings, GetBinding
Nenue@21 15
Nenue@21 16 local kb, print, wrap = LibStub('LibKraken').register(KeyBinder, 'Info')
Nenue@17 17 local cprint = DEVIAN_WORKSPACE and function(...) _G.print('Cfg', ...) end or function() end
Nenue@16 18
Nenue@17 19 local CLICK_KEYBINDER_MACRO = "CLICK KeyBinderMacro:"
Nenue@17 20 local CLICK_KEYBINDER_KEY = "CLICK KeyBinderKey:"
Nenue@21 21 local PET_BASIC_SUBTEXT = 'Basic Attack'
Nenue@21 22 local PET_SPECIAL_SUBTEXT = 'Special Ability'
Nenue@16 23 local PETACTION_SCRIPT = {
Nenue@22 24 [PET_ACTION_MOVE_TO] = {'pet_move_to', SLASH_PET_MOVE_TO1},
Nenue@22 25 [PET_ACTION_ATTACK] = {'pet_attack', SLASH_PET_ATTACK1},
Nenue@22 26 [PET_ACTION_FOLLOW] = {'pet_follow', SLASH_PET_FOLLOW1},
Nenue@22 27 [PET_ACTION_WAIT] = {'pet_stay', SLASH_PET_STAY1 },
Nenue@22 28 [PET_MODE_AGGRESSIVE] = {'pet_aggressive', SLASH_PET_AGGRESSIVE1 },
Nenue@22 29 [PET_MODE_DEFENSIVE] = { 'pet_defensive', SLASH_PET_DEFENSIVE1},
Nenue@22 30 [PET_MODE_PASSIVE] = { 'pet_passive', SLASH_PET_PASSIVE1},
Nenue@22 31 [PET_MODE_ASSIST] = {'pet_assist', SLASH_PET_ASSIST1},
Nenue@16 32 }
Nenue@21 33 local SECONDARY_PROFESSIONS = {
Nenue@21 34 [5] = 3,
Nenue@21 35 [7] = 4,
Nenue@21 36 [9] = 5,
Nenue@21 37 [10] = 6
Nenue@21 38 }
Nenue@21 39 local SUMMON_RANDOM_FAVORITE_MOUNT_SPELL = 150544
Nenue@16 40
Nenue@27 41 --kb.ChangedBindings = {}
Nenue@27 42 --kb.ActionTypes = {}
Nenue@19 43
Nenue@19 44 local atype = kb.ActionTypes
Nenue@19 45
Nenue@17 46 --- Caps Lock
Nenue@19 47 atype['mount'] = function(id, name)
Nenue@17 48 if id == SUMMON_RANDOM_FAVORITE_MOUNT_SPELL then
Nenue@24 49 return CLICK_KEYBINDER_MACRO, 'mount_random', "/script C_MountJournal.SummonByID(0)"
Nenue@17 50 else
Nenue@24 51 return CLICK_KEYBINDER_MACRO, 'mount_'..id, "/script C_MountJournal.SummonByID("..id..")"
Nenue@17 52 end
Nenue@16 53 end
Nenue@19 54
Nenue@19 55 atype['macro'] = function(id, name)
Nenue@17 56 return CLICK_KEYBINDER_MACRO, 'macro_' .. tostring(name), id
Nenue@17 57 end
Nenue@19 58
Nenue@19 59 atype['equipset'] = function(id, name)
Nenue@17 60 return CLICK_KEYBINDER_MACRO, 'equipset_'..tostring(name), "/script UseEquipmentSet("..tostring(id)..")"
Nenue@17 61 end
Nenue@19 62
Nenue@19 63 atype['spell'] = function(id, name)
Nenue@17 64 local attributeName = name
Nenue@17 65 if kb.ProfessionCache[id] then
Nenue@17 66 attributeName = "profession_".. kb.ProfessionCache[id].profOffset .. '_' .. kb.ProfessionCache[id].spellNum
Nenue@17 67 end
Nenue@17 68 return CLICK_KEYBINDER_KEY, attributeName, name
Nenue@17 69 end
Nenue@19 70
Nenue@19 71 atype['petaction'] = function(_, name)
Nenue@17 72 -- ID doesn't exist for basic commands, even though they can be picked up
Nenue@17 73 local attributeName, attributeValue = "petaction_" .. tostring(name), "/cast "..tostring(name)
Nenue@17 74 if PETACTION_SCRIPT[name] then
Nenue@22 75 attributeName, attributeValue = unpack(PETACTION_SCRIPT[name])
Nenue@19 76 elseif kb.PetCache.special[name] then
Nenue@21 77 attributeName = "petaction_"..kb.PetCache.special[name][3].."_" .. tonumber(kb.PetCache.special[name][6])
Nenue@17 78 end
Nenue@17 79 return CLICK_KEYBINDER_MACRO, attributeName, attributeValue
Nenue@16 80 end
Nenue@16 81
Nenue@19 82 atype['battlepet'] = function(id, name)
Nenue@17 83 return CLICK_KEYBINDER_MACRO, 'battlepet_' .. tostring(name), SLASH_SUMMON_BATTLE_PET1 .. " " .. tostring(name)
Nenue@17 84 end
Nenue@19 85
Nenue@19 86 atype['item'] = function(id, name)
Nenue@17 87 return CLICK_KEYBINDER_KEY, 'item_' .. tostring(name), id
Nenue@17 88 end
Nenue@16 89
Nenue@16 90
Nenue@17 91 --- Resolves the SecureActionButton attribute names used for the given action
Nenue@16 92 kb.RegisterAction = function(actionType, id, name)
Nenue@16 93
Nenue@19 94 assert(atype[actionType], 'Missing actionType handler for `'..tostring(actionType)..'`')
Nenue@19 95 local target, attributeName, attributeValue = atype[actionType](id, name)
Nenue@17 96
Nenue@17 97 local command = target .. attributeName
Nenue@17 98 local baseName, iterative = attributeName, 1
Nenue@17 99 while (kb.macros[attributeName] and kb.macros[attributeName][1] ~= attributeValue) do
Nenue@17 100 print(' * cannot use|cFF00FF00', attributeName, '|r"'.. tostring(kb.macros[attributeName][1]) .. '"')
Nenue@17 101 attributeName = baseName .. '_' .. iterative
Nenue@17 102 iterative = iterative + 1
Nenue@17 103 end
Nenue@21 104 if attributeName ~= baseName then
Nenue@21 105 print(' * Creating|cFF00FF00', attributeName)
Nenue@17 106 else
Nenue@21 107 print(' * Re-using|cFF00FF00', attributeName)
Nenue@17 108 end
Nenue@17 109 kb.macros[attributeName] = {attributeValue, command}
Nenue@17 110
Nenue@17 111
Nenue@17 112 print('RegisterAction', actionType, id, '->', attributeName, attributeValue, target .. attributeName)
Nenue@17 113 return attributeName, attributeValue, command
Nenue@17 114 end
Nenue@17 115
Nenue@17 116
Nenue@17 117
Nenue@17 118
Nenue@17 119 kb.ApplyTalentBinding = function(talentInfo, cache)
Nenue@17 120 for i = 5, #talentInfo do
Nenue@17 121 local command = CLICK_KEYBINDER_KEY.. talentInfo[2]
Nenue@17 122 SetBinding(talentInfo[i], command)
Nenue@17 123 cprint(' **', talentInfo[i], '->', command)
Nenue@17 124 tinsert(cache, talentInfo[i])
Nenue@17 125 end
Nenue@17 126 end
Nenue@17 127 kb.CacheTalentBinding = function(talentInfo, cache)
Nenue@17 128
Nenue@17 129 local spellID = talentInfo[4]
Nenue@19 130 cache[spellID] = cache[spellID] or {}
Nenue@19 131 cache[spellID] = {select(5,unpack(talentInfo)) }
Nenue@19 132 --cprint(spellID, unpack(kb.TalentBindings[spellID]))
Nenue@17 133 end
Nenue@17 134
Nenue@27 135
Nenue@17 136 do
Nenue@17 137 local bindings = kb.bindings
Nenue@17 138 local key, macro = KeyBinderKey, KeyBinderMacro
Nenue@17 139 kb.LoadBinding = function(command, name, icon, actionType, actionID, macroName, macroText )
Nenue@17 140
Nenue@17 141 if actionType == 'spell' then
Nenue@17 142 key:SetAttribute("*type-"..name, actionType)
Nenue@17 143 key:SetAttribute("*"..actionType.."-"..name, name)
Nenue@17 144 elseif actionType == 'item' then
Nenue@17 145 key:SetAttribute("*type-"..name, actionType)
Nenue@17 146 key:SetAttribute("*"..actionType.."-"..name, name)
Nenue@17 147 elseif actionType == 'macro' then
Nenue@17 148 macro:SetAttribute("*macro-"..macroName, actionID)
Nenue@16 149 else
Nenue@17 150 macro:SetAttribute("*macrotext-"..macroName, macroText)
Nenue@16 151 end
Nenue@16 152
Nenue@17 153 cprint('Loading binding', actionType, actionID)
Nenue@17 154 bindings[actionType] = bindings[actionType] or {}
Nenue@17 155 bindings[actionType][actionID] = bindings[actionType][actionID] or {}
Nenue@17 156 bindings[command] = bindings[actionType][actionID]
Nenue@17 157 return bindings[actionType], actionID
Nenue@16 158 end
Nenue@16 159
Nenue@17 160 kb.ApplyBindings = function (profile)
Nenue@17 161 cprint('binding profile', profile)
Nenue@17 162 for slot, data in pairs(profile.buttons) do
Nenue@17 163 kb.LoadBinding(unpack(data))
Nenue@17 164 end
Nenue@17 165
Nenue@17 166 for key, command in pairs(profile.bindings) do
Nenue@17 167
Nenue@17 168 cprint(' *', key, '->', command)
Nenue@17 169
Nenue@17 170 --_G.print('HotKey','loading', key, command)
Nenue@17 171 SetBinding(key, command)
Nenue@17 172 if bindings[command] and not tContains(bindings[command], key) then
Nenue@17 173 tinsert(bindings[command], key)
Nenue@17 174 end
Nenue@17 175 end
Nenue@17 176
Nenue@17 177 for spellName, talentInfo in pairs(profile.talents) do
Nenue@17 178 local dummy = GetSpellInfo(spellName)
Nenue@17 179 local func = kb.CacheTalentBinding
Nenue@19 180 local dest = kb.TalentBindings
Nenue@17 181 if dummy then
Nenue@17 182 cprint('|cFFBBFF00Active:|r', dummy)
Nenue@17 183 local macroName, spellName, actionType, actionID = unpack(talentInfo)
Nenue@17 184 bindings[actionType] = bindings[actionType] or {}
Nenue@17 185 bindings[actionType][actionID] = {}
Nenue@17 186 func = kb.ApplyTalentBinding
Nenue@17 187 dest = kb.bindings[actionType][actionID]
Nenue@17 188 else
Nenue@17 189
Nenue@17 190 cprint('|cFFFF4400Inactive:|r', talentInfo[2])
Nenue@17 191 end
Nenue@17 192 func(talentInfo, dest)
Nenue@17 193 end
Nenue@17 194
Nenue@17 195 end
Nenue@17 196
Nenue@17 197 kb.ApplyAllBindings =function ()
Nenue@21 198 wipe(kb.TalentBindings)
Nenue@17 199
Nenue@17 200
Nenue@17 201 -- reflect action key settings
Nenue@17 202 if GetCVarBool("ActionButtonUseKeyDown") then
Nenue@17 203 KeyBinderMacro:RegisterForClicks("AnyDown")
Nenue@17 204 KeyBinderKey:RegisterForClicks("AnyDown")
Nenue@17 205 else
Nenue@17 206 KeyBinderMacro:RegisterForClicks("AnyUp")
Nenue@17 207 KeyBinderKey:RegisterForClicks("AnyUp")
Nenue@17 208 end
Nenue@17 209
Nenue@17 210 for i, profile in ipairs(kb.orderedProfiles) do
Nenue@17 211 kb.ApplyBindings(profile)
Nenue@17 212 end
Nenue@17 213 -- do this after to ensure that profession binds are properly overridden
Nenue@17 214 kb.UpdateProfessionInfo()
Nenue@17 215
Nenue@17 216
Nenue@17 217 SaveBindings(GetCurrentBindingSet())
Nenue@17 218 end
Nenue@19 219 end
Nenue@19 220
Nenue@19 221
Nenue@19 222 kb.specInfo = {}
Nenue@19 223 kb.UpdateSpecInfo = function()
Nenue@19 224 kb.specInfo.id = GetSpecialization()
Nenue@19 225 kb.specInfo.globalID, kb.specInfo.name, kb.specInfo.desc, kb.specInfo.texture = GetSpecializationInfo(kb.specInfo.id)
Nenue@19 226 end
Nenue@19 227
Nenue@19 228 kb.UpdateTalentInfo = function()
Nenue@19 229 if kb.talentsPushed then
Nenue@19 230 return
Nenue@19 231 end
Nenue@21 232 wipe(kb.TalentCache)
Nenue@19 233 for row =1, MAX_TALENT_TIERS do
Nenue@19 234 for col = 1, NUM_TALENT_COLUMNS do
Nenue@19 235 local talentID, talentName, icon, selected, available, spellID = GetTalentInfo(row, col, 1)
Nenue@19 236 local talentInfo = kb.TalentCache[spellID] or {}
Nenue@19 237 talentInfo.row = 1
Nenue@19 238 talentInfo.col = col
Nenue@19 239 talentInfo.name = talentName
Nenue@19 240 talentInfo.talentID = talentID
Nenue@19 241 talentInfo.selected = selected
Nenue@19 242 talentInfo.available = available
Nenue@19 243 talentInfo.spellID = spellID
Nenue@19 244 kb.TalentCache[spellID] = talentInfo
Nenue@19 245 kb.TalentCache[talentName] = talentInfo
Nenue@19 246 print('Talent ', row, col, spellID, talentName)
Nenue@19 247 end
Nenue@19 248 end
Nenue@19 249 kb.talentsPushed = true
Nenue@19 250
Nenue@19 251 kb.UpdateDynamicButtons('talent')
Nenue@19 252 end
Nenue@19 253
Nenue@19 254 kb.UpdateProfessionInfo = function()
Nenue@21 255 wipe(kb.ProfessionCache)
Nenue@19 256 local profs = {GetProfessions() }
Nenue@19 257 local primaryNum = 0
Nenue@19 258 for i, index in ipairs(profs) do
Nenue@19 259 local profName, texture, rank, maxRank, numSpells, spellOffset = GetProfessionInfo(index)
Nenue@19 260 print(i, index, profName, numSpells, spellOffset)
Nenue@19 261 if not SECONDARY_PROFESSIONS[index] then
Nenue@19 262 primaryNum = primaryNum + 1
Nenue@19 263 end
Nenue@19 264 local profNum = SECONDARY_PROFESSIONS[index] or primaryNum
Nenue@19 265
Nenue@19 266
Nenue@19 267 kb.ProfessionCache[profNum] = kb.ProfessionCache[i] or {}
Nenue@19 268
Nenue@19 269 for j = 1, numSpells do
Nenue@19 270 local spellName, _, icon, _, _, _, spellID = GetSpellInfo(spellOffset+j, BOOKTYPE_PROFESSION)
Nenue@19 271
Nenue@19 272 local profInfo = {
Nenue@19 273 spellName = spellName,
Nenue@19 274 spellID = spellID,
Nenue@19 275 icon = icon,
Nenue@19 276 profOffset = i,
Nenue@19 277 profIndex = index,
Nenue@19 278 spellOffset = (spellOffset+j),
Nenue@19 279 spellNum = j
Nenue@19 280 }
Nenue@26 281
Nenue@26 282 kb.SecureAttribute(KeyBinderKey, "*type-profession_"..i .. '_' ..j, "spell")
Nenue@26 283 kb.SecureAttribute(KeyBinderKey, "*spell-profession_"..i .. '_' ..j, spellName)
Nenue@19 284
Nenue@19 285 kb.ProfessionCache[i .. '_' .. j] = profInfo
Nenue@19 286 kb.ProfessionCache[spellName] = profInfo
Nenue@19 287 kb.ProfessionCache[spellID] = profInfo
Nenue@19 288 print(' |cFF0088FF['..i..']|r|cFFFF44BB['..spellOffset+i..']|r', spellName, "profession_"..i .. '_' ..j)
Nenue@19 289 end
Nenue@19 290
Nenue@19 291 end
Nenue@19 292
Nenue@19 293 kb.UpdateDynamicButtons('profession')
Nenue@19 294 end
Nenue@19 295
Nenue@19 296
Nenue@19 297
Nenue@19 298 kb.UpdatePetInfo = function()
Nenue@19 299 local hasPetSpells, petType = HasPetSpells()
Nenue@19 300 if PetHasSpellbook() then
Nenue@19 301 print('PET SPELLBOOK')
Nenue@19 302 local i = 1
Nenue@21 303 local specialNum = {}
Nenue@19 304 repeat
Nenue@19 305
Nenue@19 306 local spellType, spellID = GetSpellBookItemInfo(i, BOOKTYPE_PET)
Nenue@19 307 local spellName, subText = GetSpellBookItemName(i, BOOKTYPE_PET)
Nenue@21 308 local texture = GetSpellBookItemTexture(i, BOOKTYPE_PET)
Nenue@19 309 local isPassive = IsPassiveSpell(i, BOOKTYPE_PET)
Nenue@19 310 if not isPassive then
Nenue@19 311 if spellName then
Nenue@21 312 kb.PetCache.spellslot[spellName] = {i, spellName, subText, spellID, texture}
Nenue@19 313 print('|cFF00FF88spellslot['..spellName..']|r', '=>', i, subText)
Nenue@19 314
Nenue@21 315 if subText then
Nenue@21 316 kb.PetCache.subtext[subText] = kb.PetCache.subtext[subText] or {}
Nenue@21 317 specialNum[subText] = (specialNum[subText] or 0) + 1
Nenue@21 318
Nenue@21 319 local entry = {i, spellName, subText, spellID, texture, specialNum[subText]}
Nenue@21 320
Nenue@21 321 kb.PetCache.special[spellName] = entry
Nenue@21 322 kb.PetCache.subtext[subText][specialNum[subText]] = entry
Nenue@26 323 kb.SecureAttribute(KeyBinderMacro, "*macrotext-petaction_"..subText.."_"..specialNum[subText], "/cast "..spellName)
Nenue@21 324
Nenue@21 325 print('|cFF00FFFFspecial['..spellName..']|r', '\n','|cFF00FFFFsubtext['..subText..']['..specialNum[subText]..']|r', '=>', i, spellName, subText, spellID, texture, specialNum[subText])
Nenue@19 326 end
Nenue@19 327
Nenue@19 328 if spellID then
Nenue@19 329 kb.PetCache.spell[i] = {spellID, spellName, subText}
Nenue@19 330 print('|cFF0088FFspell['..i..']|r', '=>', spellID, spellName, subText)
Nenue@19 331 end
Nenue@19 332 end
Nenue@19 333
Nenue@19 334
Nenue@19 335 end
Nenue@19 336
Nenue@19 337 i = i + 1
Nenue@19 338 until spellType == nil
Nenue@19 339 else
Nenue@19 340 print('NO PET SPELLBOOK')
Nenue@21 341 wipe(kb.PetCache.spell)
Nenue@21 342 wipe(kb.PetCache.spellslot)
Nenue@19 343 end
Nenue@19 344
Nenue@19 345 if PetHasActionBar() then
Nenue@19 346 print('PET ACTION BAR')
Nenue@19 347 for i = 1, 10 do
Nenue@19 348
Nenue@19 349
Nenue@19 350 local name, subtext, texture, isToken, isActive = GetPetActionInfo(i)
Nenue@19 351 if name then
Nenue@19 352 kb.PetCache.action[i] = {name, subtext, texture, isToken, isActive }
Nenue@19 353
Nenue@19 354
Nenue@19 355 end
Nenue@19 356 print('|cFFFFFF00action['..i..']|r', name, subtext, texture)
Nenue@19 357 end
Nenue@19 358 else
Nenue@19 359 print('NO PET ACTION BAR')
Nenue@21 360 wipe(kb.PetCache.action)
Nenue@19 361 end
Nenue@19 362
Nenue@19 363 kb.UpdateDynamicButtons('petaction')
Nenue@19 364
Nenue@19 365 end
Nenue@19 366
Nenue@19 367 kb.UpdateSystemBinds = function()
Nenue@21 368 wipe(kb.SystemBindings)
Nenue@19 369 local n = GetNumBindings()
Nenue@19 370 for i=1, n do
Nenue@19 371 local command, key1, key2 = GetBinding(i)
Nenue@19 372 if key1 then
Nenue@19 373 kb.SystemBindings[key1] = command
Nenue@19 374 end
Nenue@19 375 if key2 then
Nenue@19 376 kb.SystemBindings[key2] = command
Nenue@19 377 end
Nenue@19 378 end
Nenue@19 379 end
Nenue@19 380
Nenue@19 381 kb.UpdateDynamicButtons = function(dynamicType)
Nenue@19 382 for i, button in ipairs(kb.buttons) do
Nenue@19 383 if button.isDynamic == dynamicType then
Nenue@19 384 kb.UpdateSlot(button, true)
Nenue@19 385 end
Nenue@19 386 end
Nenue@26 387 end
Nenue@26 388
Nenue@26 389 kb.pendingAttributes = {}
Nenue@26 390 kb.SecureAttribute = function(target, name, value)
Nenue@26 391 if InCombatLockdown() then
Nenue@26 392 tinsert(kb.pendingAttributes, {target, name, value})
Nenue@26 393 kb:RegisterEvent('PLAYER_REGEN_ENABLED')
Nenue@26 394 else
Nenue@26 395
Nenue@26 396 print(target:GetName(), 'attribute', '"'.. tostring(name)..'" = "'..tostring(value)..'"')
Nenue@26 397 target:SetAttribute(name, value)
Nenue@26 398 end
Nenue@26 399 end
Nenue@26 400
Nenue@26 401 kb.PLAYER_REGEN_ENABLED = function()
Nenue@26 402 if #kb.pendingAttributes >= 1 then
Nenue@26 403 local args = tremove(kb.pendingAttributes)
Nenue@26 404 while args do
Nenue@26 405 local target, name, value = unpack(args)
Nenue@26 406 print(target:GetName(), 'attribute', '"'.. tostring(name)..'" = "'..tostring(value)..'"')
Nenue@26 407 target:SetAttribute(name, value)
Nenue@26 408 args = tremove(kb.pendingAttributes)
Nenue@26 409 end
Nenue@26 410 end
Nenue@27 411
Nenue@27 412 if #kb.pendingCalls >= 1 then
Nenue@27 413
Nenue@27 414 local func = tremove(kb.pendingCalls)
Nenue@27 415 while func do
Nenue@27 416 func()
Nenue@27 417 end
Nenue@27 418 end
Nenue@27 419 end
Nenue@27 420
Nenue@27 421 kb.UpdateBindingsCache = function(actionType, actionID, bindings)
Nenue@27 422 kb.bindings[actionType] = kb.bindings[actionType] or {}
Nenue@27 423 kb.bindings[actionType][actionID] = bindings
Nenue@27 424
Nenue@27 425 print('|cFF00FF00'..actionType..'-'..actionID..'|r = {', table.concat(bindings,', '), '}')
Nenue@27 426 tinsert(kb.ChangedBindings, {actionType, actionID})
Nenue@16 427 end