Mercurial > wow > turok
view Turok/Turok.lua @ 9:9400a0ff8540
Ugh
Timer:
- container update directionality
- talent update iterates over a non-volatile table to carry out updates
- index management steps organized
- talentRow status implemented, returns the spell associated with the talent chosen from that row
CombatLog:
- sort out font controls and unbork arguments
author | Nenue |
---|---|
date | Sun, 21 Feb 2016 13:08:30 -0500 |
parents | a9b8b0866ece |
children |
line wrap: on
line source
--- Turok -- @file-author@ -- @project-revision@ @project-hash@ -- @file-revision@ @file-hash@ --- Defines the mechanisms for the storage and dispatch of events data. --@debug@ --@end-debug@ -- GLOBALS: LibStub, Turok, TurokData, ReloadUI local ADDON, Tk = ... local db, L local MAJOR, MINOR = "Turok", "@project-revision@" local T, LGIST, _G = Tk.Addon, Tk.LGIST, _G local pcall, type, ipairs, pairs, format, tinsert, match, strpad, error = pcall, type, ipairs, pairs, string.format, table.insert, string.match, string.rep, error local PlaySoundFile, LoadAddOn, IsAddOnLoaded, UnitName, UnitGUID, UnitPowerMax = PlaySoundFile, LoadAddOn, IsAddOnLoaded, UnitName, UnitGUID, UnitPowerMax local GetSpecializationInfo, GetSpecialization, UnitSpellHaste, GetActiveSpecGroup = GetSpecializationInfo, GetSpecialization, UnitSpellHaste, GetActiveSpecGroup local UnitInfo, UnitCastingInfo, UnitChannelInfo = UnitInfo, UnitCastingInfo, UnitChannelInfo local rawset, unpack, tostring, setmetatable, xpcall, unpack = rawset, unpack, tostring, setmetatable, xpcall, unpack --@debug@ local cType, cText, cNum, cWord, cKey, cPink, cBool = cType, cText, cNum, cWord, cKey, cPink, cBool local print = function(...) if _G.Devian and _G.DevianDB.workspace ~= 1 then _G.print('Turok', ...) end end local uprint = function(...) if _G.Devian and _G.DevianDB.workspace ~= 1 then _G.print('Update', ...) end end local GetPrint = function(trace) return trace and print or function() end end --@end-debug@ --- Pull saved variables and make them sane function T.OnInitialize(T) --@debug@ local tmpidx if TurokData and TurokData.spirit and TurokData.spirit.timerindex then tmpidx = TurokData.spirit.timerindex end TurokData = Turok.defaults if tmpidx then TurokData.spirit.timerindex = tmpidx end --@end-debug@ T.db = _G.TurokData LibStub("LibFog-1.0"):Embed(T) if T.db.queue_for_wipe then T:Print("db reset flag received") local index = _G.TurokData.spirit.timerindex _G.TurokData = T.defaults T.db = _G.TurokData T.db.spirit.timerindex = index end T:RegisterChatCommand("tkr", function() T.db.queue_for_wipe = true ReloadUI() end) -- db hierarchy for k, v in pairs(T.db) do if type(v) == 'table' then --@debug@ --print('|cFF44FF88loading stored db|r: db.|cFF44AAFF'.. k ..'|r')--@end-debug@ T.LinkTable(T.db, v, 'db', k) end end setmetatable(T.db, {__newindex = function (t, k, v) rawset(t,k,v) if type(v) == 'table' then --@debug@ --print('|cFF44FF88creating new db|r: db.|cFF44AAFF'.. k ..'|r')--@end-debug@ T.LinkTable(T.db, v, 'db', k) end end}) T.L = setmetatable({}, {__call = function(t, s) return t[s] or s end}) end --- Get everything rolling function T:OnEnable() db = TurokData L = T.L self.dispatchQueue = {} self.sharedTables = {} local skip = {modules = true, db = true, defaultModuleLibraries = true, orderedModules = true, prototype = true, events = true} -- local data that exists before init for id, mod in pairs(self.orderedModules) do mod.ID = id mod.RegisterCallback = self.RegisterCallback print('load', mod:GetName()) for k, v in pairs(mod) do if not skip[k] then if match(k, '^[%u_]+$') then if not self.dispatchQueue[k] then self.dispatchQueue[k] = {} end self:RegisterEvent(k, 'Dispatch') self.dispatchQueue[k][id] = mod:GetName() end end end end print('events') for k, v in pairs(self.dispatchQueue) do print(' ',k,'->', unpack(v)) end print('shared') for k, v in pairs(self.sharedTables) do print(' ',k) end --@debug@ self:Print(MAJOR, MINOR, 'enabled.')--@end-debug@ self:RegisterChatCommand("tkl", function() PlaySoundFile([[Interface\Addons\Turok\Media\sound\wilhelm.ogg]]) if not IsAddOnLoaded("Turok_Config") then local loaded, message = LoadAddOn("Turok_Config") if not loaded then return T:Print("|cFFFF0000Load-on-Demand failed!|r Reason: " .. message) end --self.config = LibStub('AceConfigDialog-3.0'):AddToBlizOptions(MAJOR) end InterfaceOptionsFrame_OpenToCategory(MAJOR) InterfaceOptionsFrame_OpenToCategory(MAJOR) end) self:RegisterChatCommand("unlock", function() T.unlocked = (not T.unlocked) and true or nil if T.unlocked then self:Print('frames unlocked') else self:Print('frames locked') end for k, v in pairs(self.orderedModules) do if v.UpdateLocked then v:UpdateLocked() end end end) self:RegisterChatCommand("lsm", function(input) local a1, n = self:GetArgs(input, 1,0) local a2 = self:GetArgs(input, 1, n) self:Print(self.LSM:Fetch(a1, a2)) end) local name, realm = UnitFullName('player') LGIST.RegisterCallback(self, "GroupInSpecT_InspectReady", 'GIST_InspectReady') LGIST.RegisterCallback(self, "GroupInSpecT_Update", 'GIST_Update') self:RegisterCharacterInfo(name, realm) if InCombatLockdown() then T.inCombat = true end T:PLAYER_SPECIALIZATION_CHANGED('PLAYER_SPECIALIZATION_CHANGED','player') for order, event in ipairs(self.events) do self:RegisterEvent(event, 'Dispatch') end end do local bucket_events = {['PLAYER_SPECIALIZATION_CHANGED'] = {}, ['PLAYER_TALENT_UPDATE'] = {}} local bucket_start = {} local event_queue = {} local wipe, debugstack = table.wipe, debugstack --- Passes event data to the appropriate handlers, and runs any callback returned -- @param e event name -- @param ... event arguments as given by WoW Lua -- @return callback1 runs after its corresponding method has been dispatched to -- @return callback2 runs after all dispatching has completed, in the order that dispatches occurred function T:Dispatch(event, ...) if not (self[event] or self.dispatchQueue[event]) then return end if bucket_events[event] then local unit = ... if unit and unit ~= 'player' then return end print(cText('*** Bucket Event:'), cWord(event)) if not bucket_start[event] then self['TKBATCH_'..event] = {} bucket_start[event] = GetTime() T:ScheduleTimer( function() print('*** Firing bucketed event ('..#bucket_events[event]..'):', event, unpack(bucket_events[event][#bucket_events[event]])) T:Dispatch('TKBATCH_'..event, unpack(bucket_events[event][#bucket_events[event]])) bucket_start[event] = nil self['TKBATCH_'..event] = nil end,0.1) end tinsert(bucket_events[event], {...}) return else event = event:gsub('^TKBATCH_', '') end if event ~= 'COMBAT_LOG_EVENT_UNFILTERED' then print('|cFFFF0088received|r', event, ...) end local args = {event, ...} -- if addon is listening directly if self[event] then print(cWord(event)) local reg = function() print(unpack(args)) self[event](self, unpack(args)) end tinsert(event_queue, {self, event, reg}) -- if modules want this event directly end if self.dispatchQueue[event] then for id, name in pairs(self.dispatchQueue[event]) do local mod = self.orderedModules[id] local reg = function() print(unpack(args)) mod[event](mod, unpack(args)) end tinsert(event_queue, {mod, event, reg}) end else print("Received", event, "but nothing is listening to it.") end for i, entry in ipairs(event_queue) do local handler, event, func = unpack(entry) print('->', cWord(handler:GetName()), cBool(result), cText(message)) local result, message = xpcall(func, function(m) print(m, debugstack()) return debugstack() end) if bucket_events[event] then wipe(bucket_events[event]) bucket_events[event].history = {} end end wipe(event_queue) end end --- Store character data to speed up spec-specific load time function T:RegisterCharacterInfo(name,realm) local classLocalized, classEnglish, classID = UnitClass('player') -- set savedvars self.playerName = name self.playerRealm = realm self.playerClass = classEnglish self.playerClassLocalized = classLocalized self.playerClassID = classID self.GUID = UnitGUID('player') local namerealm = name..'-'..realm if not db.char[namerealm] then db.char[namerealm] = { spellBook = {} } end T.spellBook = db.char[namerealm].spellBook -- push combat ratings calc self:COMBAT_RATING_UPDATE() end --- Polls for specialization info until it's available function T:RegisterSpecEvents() local specPage = GetSpecialization() if specPage then local specID, specName, specDesc, specTexture = GetSpecializationInfo(specPage) local specGroup = GetActiveSpecGroup() print('Turok', cText('* Spec Info:'), GetSpecializationInfo(GetSpecialization())) if T.specID and specID ~= T.specID then print('pushing out old spec data') T.previousSpec = { specPage = T.specPage, specGroup = T.specGroup, specID = T.specID, specName = T.specName, specTexture = T.specTexture } elseif not T.previousSpec then print('first run probably') T.previousSpec = {} end T.specUpdate = (specID ~= T.specID) T.talentsChanged = (T.specGroup ~= specGroup) T.specPage = specPage T.specGroup = specGroup T.specID = specID T.specName = specName T.specTexture = specTexture else print('Turok', cText('* No Spec Info yet, start polling')) -- repeat until we get something to update with T:ScheduleTimer('RegisterSpecEvents', 1) end if T.specID and not T.__specevents then T.__specevents = true T:PLAYER_SPECIALIZATION_CHANGED('PLAYER_SPECIALIZATION_CHANGED','player') T:RegisterEvent('PLAYER_TALENT_UPDATE', 'Dispatch') T:RegisterEvent('PLAYER_SPECIALIZATION_CHANGED', 'Dispatch') T:RegisterEvent('ACTIVE_TALENT_GROUP_CHANGED', 'Dispatch') T:RegisterEvent('UNIT_SPELLCAST_INTERRUPTED', 'Dispatch') end end --- Event handler wrapper for the Specialization getter used at load time local GetSpecializationSpells, GetSpellInfo = GetSpecializationSpells, GetSpellInfo function T:PLAYER_SPECIALIZATION_CHANGED(event, unit) -- make sure this was fired for player if (unit ~= 'player') then return end print('Turok', '|cFF00FF00'.. event) -- Set current spec values and fill out previousSpec table T:RegisterSpecEvents() local ot = T.previousSpec -- Is the new spec different? if T.specUpdate then print(cText('Spec changed from'), cWord(ot.specName), cText('to'), cKey(T.specName)) if ot.specPage and not T.spellBook[ot.specPage] then T.spellBook[ot.specPage] = {} end local spellBook = {GetSpecializationSpells(T.specPage)} if not T.spellBook[T.specPage] then T.spellBook[T.specPage] = {} for i = 1, #spellBook, 2 do T.spellBook[T.specPage][spellBook[i]] = GetSpellInfo(spellBook[i]) if (not ot.specPage) or (T.spellBook[ot.specPage] and not T.spellBook[ot.specPage][spellBook[i]]) then print(cText('activating for spell'), T.spellBook[T.specPage][spellBook[i]]) end end end -- list changed spells for use by spell posession checks local diff = { gained = {}, lost = {} } --- Check against current for removed spells if T.spellBook[ot.specPage] then for id, spellInfo in pairs(T.spellBook[ot.specPage]) do if not T.spellBook[ot.specPage] then tinsert(diff.lost, spellInfo) print('lost', spellInfo.spellName) else print('keep', spellInfo.spellName) end end end T.spellBook.change = diff end end local GetInventoryItemID, GetItemSpell, GetSpellInfo, GetItemInfo = GetInventoryItemID, GetItemSpell, GetSpellInfo, GetItemInfo function T:PLAYER_EQUIPMENT_CHANGED(event, slot, hasItem) print('Equip slot #', slot, ' has?', hasItem) if hasItem then local itemID = GetInventoryItemID('player', slot) print('itemID?', itemID) local spellName = GetItemSpell(itemID) print('spell?', spellName) local _, spellID if spellName then _, _, _, _, _, _, spellID = GetSpellInfo(spellName) end local name, link, quality, iLevel, reqLevel, class, subclass, maxStack, equipSlot, texture, vendorPrice = GetItemInfo(itemID) T.equipped[slot] = { itemID = itemID, spellName = spellName, spellID = spellID, name = name, link = link, equipSlot = equipSlot, texture = texture, } print('equipped', name) else self.equipped[slot] = nil end end local GetPowerRegen, UnitPowerType = GetPowerRegen, UnitPowerType function T:COMBAT_RATING_UPDATE(t,e) --@debug@ print('|cFF00FFFFCOMBAT_RATING_UPDATE')--@end-debug@ self.haste = UnitSpellHaste('player') self.powerRegen = GetPowerRegen() self.powerType = UnitPowerType('player') self.castTimeMod = 1+ self.haste/100 self.GCD = 1.5 * self.castTimeMod L.haste = format('%.2f', self.haste) L.focusregen = format('%.2f', self.powerRegen) L.castingmod = format('%.2f', self.castTimeMod) end function T:UNIT_SPELLCAST_INTERRUPTED(e, unit, spellName, rank, target, castID) if not T.unit[unit] then return end T.spellevent[unit] = {unit, spellName, rank, target, castID, nil } end function T:UNIT_SPELLCAST_SENT(e,unit, spellName, rank, target, castID) if not T.unit[unit] then return end T.unit[unit].spellEventString = e T.unit[unit].spellevent = {unit, spellName, rank, target, castID} end function T:UNIT_SPELLCAST (e, unit, spellName, rank, castID, spellID) if not T.unit[unit] then return end --name, subText, text, texture, startTime, endTime, isTradeSkill, castID, notInterruptible local q = {UnitCastingInfo(unit)} T.unit[unit].casting = q[1] and q or false T.unit[unit].spellEventString = e T.unit[unit].spellevent = {unit, spellName, rank, nil,castID, spellID } print(e, unit) end function T:UNIT_CHANNEL(e, unit, spellName, rank, castID, spellID) if not T.unit[unit] then return end --name, subText, text, texture, startTime, endTime, isTradeSkill, notInterruptible local q = {UnitChannelInfo(unit) } T.unit[unit].channeling = q[1] and q or false T.unit[unit].spellEventString = e T.unit[unit].spellevent = {unit, spellName, rank, nil, castID, spellID } print(e, unit) end T.UNIT_SPELLCAST_START = T.UNIT_SPELLCAST T.UNIT_SPELLCAST_STOP = T.UNIT_SPELLCAST T.UNIT_SPELLCAST_DELAYED = T.UNIT_SPELLCAST T.UNIT_SPELLCAST_INTERRUPTED = T.UNIT_SPELLCAST T.UNIT_SPELLCAST_FAILED = T.UNIT_SPELLCAST T.UNIT_SPELLCAST_SUCCEEDED = T.UNIT_SPELLCAST T.UNIT_SPELLCAST_CHANNEL_START = T.UNIT_CHANNEL T.UNIT_SPELLCAST_CHANNEL_UPDATE= T.UNIT_CHANNEL T.UNIT_SPELLCAST_CHANNEL_STOP= T.UNIT_CHANNEL local UnitExists, GetRealmName, UnitClassification, UnitClass, UnitIsFriend, UnitIsEnemy, UnitIsFeignDeath = UnitExists, GetRealmName, UnitClassification, UnitClass, UnitIsFriend, UnitIsEnemy, UnitIsFeignDeath function T:UnitChanged(e, unit) local u = T.unit[unit] local exists = UnitExists(unit) local realm uprint(cText(' '..unit..' change:'), cText(unit), cText(exists and UnitName(unit))) u.exists = exists u.name, realm = UnitName(unit) u.realm = realm or GetRealmName() u.classification = UnitClassification(unit) u.class = UnitClass(unit) u.isFriendly = UnitIsFriend('player', unit) u.isEnemy = UnitIsEnemy('player', unit) u.isFeign = UnitIsFeignDeath(unit) u.isNeutral = not(u.isHostile or u.isFriendly) local castinfo, channelinfo = {UnitCastingInfo(unit)}, {UnitChannelInfo(unit)} u.casting = (u.exists and castinfo[1]) and castinfo or false u.channeling = (u.exists and channelinfo[1]) and channelinfo or false u.isCasting = (u.casting or u.channeling) and true or false for k,v in pairs(T.unit[unit]) do uprint(cText(' -'), cText(k),'->', cText(v)) end end function T:PLAYER_TARGET_CHANGED(e) T:UnitChanged(e, 'target') end function T:PLAYER_FOCUS_CHANGED(e) T:UnitChanged(e, 'focus') end function T:UNIT_PET(e, unit,...) if unit == 'player' then print(e, unit, ...) T:UnitChanged(e, 'pet') end end local Turok_OnCombat = function(inCombat) print(cText('* CombatToggle:'), cBool(inCombat)) PlaySoundFile(db['battle_noise'.. (inCombat and '_start' or '_end')]) for _, region in pairs(Tk.LibFog.animate_regions) do if region.combatFade then print(' |cFFFFFF00+|r', region:GetName()) region:UpdateAlpha(inCombat) else print(' |cFFFF4400-|r', region:GetName()) end end end --- InCombatLockdown() isn't updated immediately, so we have to assume function T:PLAYER_REGEN_DISABLED(e,...) T.inCombat = true Turok_OnCombat(true) end function T:PLAYER_REGEN_ENABLED(e,...) T.inCombat = nil Turok_OnCombat(false) end -- GIST datas function T:GIST_InspectReady (event, guid, unit) print('GIST barf', guid, unit) end function T:GIST_Update(event, guid, unit, info) if info.class_id and info.global_spec_id and info.guid and info.lku then --_G.print('GIST', 'Update', unit) --_G.print('GIST',' class:', info.class_id, 'specid:', info.global_spec_id, 'guid:', info.guid) self.units[info.guid] = info self.unitsBySlot[info.lku] = info end end -- todo: re-locate these T.PLAY_MOVIE = function (e, id) MovieFrame:Hide() T:Print('skipped a shitty movie', e, id) end T.CINEMATIC_START = function(...) CinematicFrame_CancelCinematic() T:Print('skipped a shitty cinematic', ...) end