annotate SkeletonKey.lua @ 70:131d9190db6b

Curseforge migration
author Nenue
date Wed, 28 Dec 2016 16:31:15 -0500
parents
children c48913c5924c
rev   line source
Nenue@70 1 --------------------------------------------
Nenue@70 2 -- SkeletonKey
Nenue@70 3 -- Krakyn-Mal'Ganis
Nenue@70 4 -- @project-revision@ @project-hash@
Nenue@70 5 -- @file-revision@ @file-hash@
Nenue@70 6 -- Created: 6/16/2016 3:47 AM
Nenue@70 7 --------------------------------------------
Nenue@70 8 -- Header script
Nenue@70 9
Nenue@70 10 local addonName, kb = ...
Nenue@70 11 local print = DEVIAN_WORKSPACE and function(...) print('SK',...) end or nop
Nenue@70 12 SkeletonKeyMixin = {
Nenue@70 13 scrollCache = {},
Nenue@70 14 tabButtons = {},
Nenue@70 15 keyButtons = {},
Nenue@70 16 panelButtons = {},
Nenue@70 17 numTabs = 0,
Nenue@70 18 }
Nenue@70 19 kb.L = setmetatable({}, {
Nenue@70 20 __call = function(t, k, ...) return format(t[k] or k, ...) end
Nenue@70 21 })
Nenue@70 22 local L = kb.L
Nenue@70 23
Nenue@70 24 --- Caps Lock literals
Nenue@70 25 L.UNSELECTED_TALENT_ASSIGNED = '|cFF00FF00%s|r added for |cFFFFFF00%s|r (%s).'
Nenue@70 26 L.BINDING_ASSIGNED = '|cFF00FF00%s|r assigned to |cFFFFFF00%s|r (%s).'
Nenue@70 27 L.BINDING_REMOVED = '|cFFFFFF00%s|r (|cFF00FFFF%s|r) unbound.'
Nenue@70 28 L.BINDING_FAILED_PROTECTED = '|cFFFF4400Cannot use |r|cFF00FF00%s|r|cFFFF4400 (currently |cFFFFFF00%s|r|cFFFF4400). Uncheck "Safety" to ignore this restraint.|r'
Nenue@70 29
Nenue@70 30
Nenue@70 31 local BINDING_TYPE_SPECIALIZATION = 3
Nenue@70 32 local BINDING_TYPE_CHARACTER = 2
Nenue@70 33 local BINDING_TYPE_GLOBAL = 1
Nenue@70 34 kb.configTitle = {
Nenue@70 35 [BINDING_TYPE_GLOBAL] = L('Global Binds'),
Nenue@70 36 [BINDING_TYPE_CHARACTER] = L('%%s'),
Nenue@70 37 [BINDING_TYPE_SPECIALIZATION] = L('%%s')
Nenue@70 38 }
Nenue@70 39 kb.configDescription = {
Nenue@70 40 [BINDING_TYPE_GLOBAL] = L('The bindings are applied globally.'),
Nenue@70 41 [BINDING_TYPE_CHARACTER] = L('Applied when you log onto this character.'),
Nenue@70 42 [BINDING_TYPE_SPECIALIZATION] = L('Applied when you select this specialization.'),
Nenue@70 43 }
Nenue@70 44
Nenue@70 45
Nenue@70 46 kb.ChangedBindings = {}
Nenue@70 47 kb.SystemBindings = {}
Nenue@70 48 kb.ActionTypes = {}
Nenue@70 49 kb.TalentBindings = {}
Nenue@70 50 kb.PetCache = {
Nenue@70 51 spell = {},
Nenue@70 52 spellslot = {},
Nenue@70 53 action = {},
Nenue@70 54 special = {},
Nenue@70 55 subtext = {}
Nenue@70 56 }
Nenue@70 57 kb.DynamicSpells = {
Nenue@70 58 profession = {},
Nenue@70 59 petaction = {},
Nenue@70 60 talent = {},
Nenue@70 61 }
Nenue@70 62 kb.TalentCache = {}
Nenue@70 63 kb.ProfessionCache = {}
Nenue@70 64 kb.pendingCalls = {}
Nenue@70 65 kb.pendingAttributes = {}
Nenue@70 66
Nenue@70 67 kb.configHeaders = {}
Nenue@70 68 kb.loadedProfiles = {}
Nenue@70 69 kb.orderedProfiles = {}
Nenue@70 70 kb.buttons = {}
Nenue@70 71 kb.macros = {}
Nenue@70 72 kb.bindings = {}
Nenue@70 73 kb.petFrames = {} -- pet data is slightly delayed, their buttons are indexed here so they can be refreshed
Nenue@70 74 kb.talentFrames = {}
Nenue@70 75 kb.professionFrames = {}
Nenue@70 76
Nenue@70 77 -- these are sent to plugin
Nenue@70 78
Nenue@70 79
Nenue@70 80 local db
Nenue@70 81 local _G = _G
Nenue@70 82 local UnitName, SelectedRealmName, InCombatLockdown, UnitClass = UnitName, SelectedRealmName, InCombatLockdown, UnitClass
Nenue@70 83 local tostring, select, tinsert, pairs = tostring, select, tinsert, pairs
Nenue@70 84 local concat, wipe = table.concat, table.wipe
Nenue@70 85 local classHeader, className, classID = '', '', 0
Nenue@70 86
Nenue@70 87
Nenue@70 88 local CloseButton_OnClick = function()
Nenue@70 89
Nenue@70 90 kb.db.showUI = false
Nenue@70 91 print(kb.db.showUI)
Nenue@70 92 SkeletonKey:SetShown(kb.db.showUI)
Nenue@70 93 end
Nenue@70 94
Nenue@70 95 --- Returns conflicting assignment and binding profiles for use in displaying confirmations
Nenue@70 96 kb.IsCommandBound = function(self, command)
Nenue@70 97 local isAssigned, assignedBy = false, kb.db.bindMode
Nenue@70 98 local isBound, boundBy = false, kb.db.bindMode
Nenue@70 99 command = command or self.command
Nenue@70 100 for i = 1, #kb.orderedProfiles do
Nenue@70 101 local profile = kb.orderedProfiles[i]
Nenue@70 102 if i ~= kb.db.bindMode then
Nenue@70 103
Nenue@70 104 if profile.commands[command] then
Nenue@70 105 print(' command: ', i , kb.configHeaders[i], profile.commands[command])
Nenue@70 106 isAssigned = true
Nenue@70 107 assignedBy = i
Nenue@70 108 end
Nenue@70 109 if profile.bound[command] then
Nenue@70 110 print(' bound: ', i , kb.configHeaders[i], profile.bound[command])
Nenue@70 111 isBound = true
Nenue@70 112 boundBy = i
Nenue@70 113 end
Nenue@70 114
Nenue@70 115
Nenue@70 116
Nenue@70 117
Nenue@70 118 if isAssigned and isBound then
Nenue@70 119 print(' hit: ', i , kb.configHeaders[i], profile.commands[command], profile.bound[command])
Nenue@70 120 break
Nenue@70 121 end
Nenue@70 122 end
Nenue@70 123
Nenue@70 124 end
Nenue@70 125
Nenue@70 126 print('|cFFFFFF00IsCommandBound:|r', command,'|r [profile:', kb.db.bindMode .. ']', isAssigned, isBound, assignedBy, boundBy)
Nenue@70 127 return isAssigned, isBound, assignedBy, boundBy
Nenue@70 128 end
Nenue@70 129
Nenue@70 130 local talentSpellHardCodes = {
Nenue@70 131 [109248] = 'Binding Shot',
Nenue@70 132 }
Nenue@70 133
Nenue@70 134 --- Returns a value for use with Texture:SetDesaturated()
Nenue@70 135 kb.BindingIsLocked = function(key)
Nenue@70 136 local success = false
Nenue@70 137 for i = 1, db.bindMode-1 do
Nenue@70 138 local tier = kb.orderedProfiles[i]
Nenue@70 139 if tier.bindings[key] then
Nenue@70 140 success = true
Nenue@70 141 break
Nenue@70 142 end
Nenue@70 143 end
Nenue@70 144 return success
Nenue@70 145 end
Nenue@70 146
Nenue@70 147 --- Translates GetBindingKey() results into a printable string.
Nenue@70 148 kb.BindingString = function(...)
Nenue@70 149 local stack = {}
Nenue@70 150 for i = 1, select('#', ...) do
Nenue@70 151 local key = select(i, ...)
Nenue@70 152 if type(key) == 'string' then
Nenue@70 153 stack[i] = key:gsub('SHIFT', 's'):gsub('ALT', 'a'):gsub('CTRL', 'c'):gsub('SPACE', 'Sp'):gsub('BUTTON', 'M '):gsub('NUMPAD', '# ')
Nenue@70 154 end
Nenue@70 155 end
Nenue@70 156
Nenue@70 157 if #stack >= 1 then
Nenue@70 158 return concat(stack, ',')
Nenue@70 159 else
Nenue@70 160 return nil
Nenue@70 161 end
Nenue@70 162 end
Nenue@70 163
Nenue@70 164
Nenue@70 165 function kb:print(...)
Nenue@70 166
Nenue@70 167 local msg = '|cFF0088FFSkeletonKey|r:'
Nenue@70 168 for i = 1, select('#', ...) do
Nenue@70 169 msg = msg .. ' ' .. tostring(select(i, ...))
Nenue@70 170 end
Nenue@70 171 DEFAULT_CHAT_FRAME:AddMessage(msg)
Nenue@70 172 end
Nenue@70 173
Nenue@70 174
Nenue@70 175 kb.Command = function(args, editor)
Nenue@70 176 if args:match("import") then
Nenue@70 177 kb.ImportCommmit(args)
Nenue@70 178 return
Nenue@70 179 elseif args:match("scan") then
Nenue@70 180 kb.ImportScan(args)
Nenue@70 181 SkeletonKey:Update()
Nenue@70 182 return
Nenue@70 183 elseif args:match("load") then
Nenue@70 184 kb:ApplyAllBindings()
Nenue@70 185 return
Nenue@70 186 end
Nenue@70 187
Nenue@70 188 if db.showUI then
Nenue@70 189 db.showUI = false
Nenue@70 190 else
Nenue@70 191 db.showUI = true
Nenue@70 192 if not InCombatLockdown() then
Nenue@70 193 kb:print(L('Config frame opened.'))
Nenue@70 194 else
Nenue@70 195 kb:print(L('Config frame will open upon exiting combat.'))
Nenue@70 196 end
Nenue@70 197 end
Nenue@70 198 SkeletonKey:SetShown(db.showUI)
Nenue@70 199 SkeletonKey:Update(true)
Nenue@70 200 end
Nenue@70 201
Nenue@70 202 kb.InitProfile = function(profile, prototype)
Nenue@70 203 print('|cFF00FFFFkb.InitProfile()', profile, prototype)
Nenue@70 204 if not profile then
Nenue@70 205 profile = {}
Nenue@70 206 end
Nenue@70 207 if prototype then
Nenue@70 208 for k,v in pairs(prototype) do
Nenue@70 209 if not profile[k] then
Nenue@70 210 profile[k] = v
Nenue@70 211 end
Nenue@70 212 end
Nenue@70 213 end
Nenue@70 214
Nenue@70 215 profile.bound = profile.bound or {}
Nenue@70 216 profile.buttons = profile.buttons or {}
Nenue@70 217 profile.commands = profile.commands or {}
Nenue@70 218 profile.bindings = profile.bindings or {}
Nenue@70 219 profile.macros = profile.macros or {}
Nenue@70 220 profile.talents = profile.talents or {}
Nenue@70 221 return profile
Nenue@70 222 end
Nenue@70 223
Nenue@70 224 kb.ResetProfile = function(profile, prototype)
Nenue@70 225 if profile == kb.currentProfile then
Nenue@70 226 for i, button in pairs(kb.buttons) do
Nenue@70 227 kb.ReleaseSlot(button)
Nenue@70 228 end
Nenue@70 229 end
Nenue@70 230 wipe(profile)
Nenue@70 231 kb.InitProfile(profile, prototype)
Nenue@70 232 end
Nenue@70 233
Nenue@70 234
Nenue@70 235
Nenue@70 236 --- Handles constructing spec profiles as they are selected
Nenue@70 237
Nenue@70 238
Nenue@70 239 --- Obtains profile data or creates the necessary tables
Nenue@70 240 kb.SelectProfileSet = function(name)
Nenue@70 241
Nenue@70 242 local defaultMode
Nenue@70 243 --- General info
Nenue@70 244 classHeader, className, classID = UnitClass('player')
Nenue@70 245 print('|cFF00FF00profile:|r', name)
Nenue@70 246 print('|cFF00FF00class:|r', UnitClass('player'))
Nenue@70 247
Nenue@70 248 defaultMode = BINDING_TYPE_GLOBAL
Nenue@70 249 if db[name] then
Nenue@70 250 defaultMode = BINDING_TYPE_CHARACTER
Nenue@70 251 if db[name][kb.specInfo.id] then
Nenue@70 252 defaultMode = BINDING_TYPE_SPECIALIZATION
Nenue@70 253 end
Nenue@70 254 end
Nenue@70 255
Nenue@70 256 db[name] = kb.InitProfile(db[name],
Nenue@70 257 {
Nenue@70 258 classHeader = classHeader,
Nenue@70 259 className = className,
Nenue@70 260 classID = classID
Nenue@70 261 })
Nenue@70 262 db[name][kb.specInfo.id] = kb.InitProfile(db[name][kb.specInfo.id],
Nenue@70 263 {
Nenue@70 264 specID = kb.specInfo.id,
Nenue@70 265 specName = kb.specInfo.name
Nenue@70 266 })
Nenue@70 267
Nenue@70 268 kb.loadedProfiles[BINDING_TYPE_GLOBAL] = db
Nenue@70 269 kb.loadedProfiles[BINDING_TYPE_CHARACTER] = db[name]
Nenue@70 270 kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION] = db[name][kb.specInfo.id]
Nenue@70 271 kb.orderedProfiles = {db, db[name], db[name][kb.specInfo.id]}
Nenue@70 272
Nenue@70 273 if (not db.bindMode) or (not kb.configTitle[db.bindMode]) then
Nenue@70 274 print('fixing bad bindMode value, was', db.bindMode)
Nenue@70 275 db.bindMode = defaultMode
Nenue@70 276 end
Nenue@70 277
Nenue@70 278
Nenue@70 279 print(BINDING_TYPE_GLOBAL)
Nenue@70 280 kb.configHeaders[BINDING_TYPE_GLOBAL] = kb.configTitle[BINDING_TYPE_GLOBAL]
Nenue@70 281 kb.configHeaders[BINDING_TYPE_CHARACTER] = kb.configTitle[BINDING_TYPE_CHARACTER]:format(UnitName('player', true))
Nenue@70 282 kb.configHeaders[BINDING_TYPE_SPECIALIZATION] = kb.configTitle[BINDING_TYPE_SPECIALIZATION]:format(kb.specInfo.name or '')
Nenue@70 283
Nenue@70 284
Nenue@70 285 setmetatable(kb.loadedProfiles[BINDING_TYPE_GLOBAL], {__tostring =function() return kb.configHeaders[BINDING_TYPE_GLOBAL] end})
Nenue@70 286 setmetatable(kb.loadedProfiles[BINDING_TYPE_CHARACTER], {__tostring =function() return kb.configHeaders[BINDING_TYPE_CHARACTER] end})
Nenue@70 287 setmetatable(kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION], {__tostring =function() return kb.configHeaders[BINDING_TYPE_SPECIALIZATION] end})
Nenue@70 288
Nenue@70 289 print('|cFF00FF00bindMode:|r', db.bindMode)
Nenue@70 290 kb.currentProfile = kb.loadedProfiles[db.bindMode]
Nenue@70 291 kb.currentHeader = kb.configHeaders[db.bindMode]
Nenue@70 292 end
Nenue@70 293
Nenue@70 294
Nenue@70 295 function SkeletonKeyMixin:SetTab (id)
Nenue@70 296 self.scrollCache[db.bindMode] = kb.scrollOffset
Nenue@70 297 db.bindMode =id
Nenue@70 298 kb.currentProfile = kb.loadedProfiles[id]
Nenue@70 299 kb.currentHeader = kb.configHeaders[db.bindMode]
Nenue@70 300 kb.scrollOffset = self.scrollCache[db.bindMode] or 0
Nenue@70 301 self:Update(true)
Nenue@70 302 end
Nenue@70 303
Nenue@70 304 kb.ConfirmBindings = function()
Nenue@70 305 kb.ApplyAllBindings()
Nenue@70 306 if #kb.pendingAttributes == 0 then
Nenue@70 307 kb:print(L("Manual bindings update finished."))
Nenue@70 308 else
Nenue@70 309 kb:print(L("Manual update will complete upon exiting combat."))
Nenue@70 310 end
Nenue@70 311 SkeletonKey:Update()
Nenue@70 312 end
Nenue@70 313
Nenue@70 314 function SkeletonKeyMixin:OnLoad()
Nenue@70 315 kb.frame = self
Nenue@70 316 print('|cFF0088FF'..self:GetName()..':OnLoad()')
Nenue@70 317
Nenue@70 318 self.CloseButton:SetScript('OnClick', CloseButton_OnClick)
Nenue@70 319 self:RegisterEvent('PLAYER_ENTERING_WORLD')
Nenue@70 320 self:RegisterEvent('ADDON_LOADED')
Nenue@70 321 self:EnableKeyboard(false)
Nenue@70 322
Nenue@70 323 self.zoomScale = self:GetScale()
Nenue@70 324 self.backdrop = self:GetBackdrop()
Nenue@70 325 self.backdropColor = {self:GetBackdropColor() }
Nenue@70 326 self.backdropBorder = {self:GetBackdropBorderColor() }
Nenue@70 327
Nenue@70 328 end
Nenue@70 329
Nenue@70 330 function SkeletonKeyMixin:OnEvent(event, arg)
Nenue@70 331 if event == 'ADDON_LOADED' then
Nenue@70 332
Nenue@70 333 print('|cFF00FFFF'..event ..'|r', arg or '', IsLoggedIn())
Nenue@70 334 if IsLoggedIn() and not self.initialized then
Nenue@70 335 self:Setup()
Nenue@70 336 self.initialized = true
Nenue@70 337 self:Update()
Nenue@70 338 end
Nenue@70 339
Nenue@70 340
Nenue@70 341 elseif kb[event] then
Nenue@70 342 if self.initialized then
Nenue@70 343 print('|cFF0088FF'..event ..'|r', arg or '')
Nenue@70 344 kb[event](self, event, arg)
Nenue@70 345 else
Nenue@70 346
Nenue@70 347 print('|cFF004488'..event ..'|r', arg or '')
Nenue@70 348 end
Nenue@70 349 end
Nenue@70 350 end
Nenue@70 351
Nenue@70 352
Nenue@70 353 --- post ADDON_LOADED
Nenue@70 354 function SkeletonKeyMixin:Setup ()
Nenue@70 355 print('|cFF00FFFF'..self:GetName()..':Setup()')
Nenue@70 356 SkeletonKeyDB = kb.InitProfile(SkeletonKeyDB, {})
Nenue@70 357 kb.db = _G.SkeletonKeyDB
Nenue@70 358 kb.playerName = UnitName('player')
Nenue@70 359 kb.playerRealm = SelectedRealmName()
Nenue@70 360 kb.profileName = kb.playerRealm .. '_' .. kb.playerName
Nenue@70 361 db = kb.db
Nenue@70 362
Nenue@70 363 kb.UpdateSpecInfo()
Nenue@70 364 kb.UpdateTalentInfo()
Nenue@70 365 kb.SelectProfileSet(kb.profileName)
Nenue@70 366 -- todo: redo import checking
Nenue@70 367
Nenue@70 368 kb.UpdateSystemBinds()
Nenue@70 369 kb.ApplyAllBindings()
Nenue@70 370
Nenue@70 371 if not InCombatLockdown() then
Nenue@70 372 kb.CreateHooks()
Nenue@70 373 else
Nenue@70 374 kb:print('Some functionality will not load until breaking combat.')
Nenue@70 375 tinsert(kb.pendingCalls, kb.CreateHooks)
Nenue@70 376 end
Nenue@70 377 SLASH_SKB1 = "/skb"
Nenue@70 378 SLASH_SKB2 = "/skeletonkey"
Nenue@70 379 SlashCmdList.SKB = kb.Command
Nenue@70 380
Nenue@70 381 self:SetShown(kb.db.showUI)
Nenue@70 382 self:Update(true)
Nenue@70 383
Nenue@70 384 self:RegisterEvent('UPDATE_MACROS')
Nenue@70 385 self:RegisterEvent('UPDATE_BINDINGS')
Nenue@70 386 self:RegisterUnitEvent('UNIT_PORTRAIT_UPDATE', 'player', 'pet')
Nenue@70 387 self:RegisterUnitEvent('PLAYER_SPECIALIZATION_CHANGED', 'player', 'pet')
Nenue@70 388 self:RegisterUnitEvent('SPELLS_CHANGED')
Nenue@70 389 self:RegisterUnitEvent('TALENT_UPDATE', 'player', 'pet')
Nenue@70 390 self:RegisterEvent('PLAYER_REGEN_DISABLED')
Nenue@70 391 self:RegisterEvent('PLAYER_REGEN_ENABLED')
Nenue@70 392
Nenue@70 393 self:RegisterForDrag('LeftButton')
Nenue@70 394 self:SetMovable(true)
Nenue@70 395 for index, frame in ipairs(self.Plugins) do
Nenue@70 396 frame:Setup()
Nenue@70 397 end
Nenue@70 398 end
Nenue@70 399
Nenue@70 400
Nenue@70 401 -- Volatiles Access
Nenue@70 402 kb.FormatActionID = function(actionType, actionID) return tostring(actionType) .. '_' .. tostring(actionID) end
Nenue@70 403 kb.GetBindings = function() return kb.bindings end
Nenue@70 404 kb.GetButtons = function() return kb.buttons end
Nenue@70 405 kb.GetCharacterProfile = function () return kb.loadedProfiles[BINDING_TYPE_CHARACTER] end
Nenue@70 406 kb.GetGlobalProfile = function () return kb.loadedProfiles[BINDING_TYPE_GLOBAL] end
Nenue@70 407 kb.GetSpecProfile = function () return kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION] end
Nenue@70 408
Nenue@70 409