Mercurial > wow > turok
changeset 6:a9b8b0866ece
clear out log jam
line wrap: on
line diff
--- a/.pkgmeta Tue Dec 15 10:10:22 2015 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -externals: - Libs/LibStub: - url: svn://svn.wowace.com/wow/libstub/mainline/trunk - tag: latest - Libs/CallbackHandler-1.0: - url: svn://svn.wowace.com/wow/callbackhandler/mainline/trunk/CallbackHandler-1.0 - tag: latest - Libs/AceAddon-3.0: - url: svn://svn.wowace.com/wow/ace3/mainline/trunk/AceAddon-3.0 - tag: latest - - -ignore: - - Debug.lua - - Turok.iml - - .idea - -enable-nolib-creation: no \ No newline at end of file
--- a/Equip.lua Tue Dec 15 10:10:22 2015 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ --- User: Krakyn --- Created: 12/4/2015 11:20 PM --- Equipment, spec, etc. -local T = LibStub("AceAddon-3.0"):GetAddon("Turok") -local mod = T:NewModule("Equip", "AceEvent-3.0") ---setprinthandler(function (...) T:debug('Equip', nil, ...) end) - -local t18_slots = { - [INVSLOT_HEAD] = 124296, -- head - [INVSLOT_SHOULDER] = 124307, -- shoulders - [INVSLOT_CHEST] = 124284, -- chest - [INVSLOT_LEGS] = 124301, -- legs - [INVSLOT_HAND] = 124292, -- hands -} - - -local use_slots = { - [INVSLOT_FINGER1] = 1, - [INVSLOT_FINGER2] = 2, - [INVSLOT_TRINKET1] = 3, - [INVSLOT_TRINKET2] = 4, - -} -function mod:OnEnable() - self.equipped = {} - self:RegisterEvent('COMBAT_RATING_UPDATE', 'UpdateCombatRatings') - self:RegisterEvent('PLAYER_EQUIPMENT_CHANGED', 'UpdateEquipment') - self:RegisterEvent('PLAYER_SPECIALIZATION_CHANGED', 'UpdateSpec') -end - -function mod:UpdateEquipment (_, slot, hasItem) - -- ratings event will handle the rest - if not t18_slots[slot] or use_slots[slot] then - return - end - -- debug - local link = GetInventoryItemID('player', slot) - print('|cFF00FFFFequipment ', slot, hasItem, link) - -- /debug - - if t18_slots[slot] then - t18_count = 0 - for slot, itemID in pairs(t18_slots) do - if GetInventoryItemID(slot) == itemID then - t18_count = t18_count + 1 - end - end - if t18 >= 4 then - T.stats.aimedshot = s.gcd - else - T.stats.aimedshot = 2 * T.stats.castingmod - end - T.statstext =string.format('%.2f', s.aimedshot) - end - - if use_slots[slot] then - if hasItem then - local itemID = GetInventoryItemID('player', slot) - self.equipped[slot] = itemID - T:GetModule("Spirit").item_watch[itemID] = {GetInventoryItemCooldown('player', slot) } - else - if self.equipped[slot] then - self.equipped[slot] = nil - end - - end - end - -end - - -function mod:UpdateCombatRatings() - local s = T.stats - s.haste = UnitSpellHaste('player') - s.focusregen = 4 * (1 + s.haste/100) - s.castingmod = 1+ s.haste/1000 - s.gcd = 1.5 * s.castingmod - T.statstext = { - haste = string.format('%.2f', s.haste), - focusregen = string.format('%.2f', s.focusregen), - castingmod = string.format('%.2f', s.castingmod), - } - local t = T.statstext - - print('|cFF00FFFFCOMBAT_RATING_UPDATE:|r', 'haste:', t.haste, 'regen:', t.focusregen) -end - -function mod:UpdateSpec (e, unit) - if unit ~= 'player' then - return - end - - T.stats.focusmax = UnitPowerMax('player') -end \ No newline at end of file
--- a/Fog.lua Tue Dec 15 10:10:22 2015 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,325 +0,0 @@ --- User: Krakyn --- Created: 12/4/2015 11:13 PM ---[[ --- Core tools, mostly frame handling business. It's an interface script after all. --- Types: --- StatusFrame --- Primary container for status data, carries primary value information by default --- FIELDS --- value = exact primary value represented by frame --- min = exact minimum for primary value --- max = exact maximum for primary value --- percent = value / max --- alpha = base frame alpha level, set when a fade animation has completed --- fadeTo = when set, the frame will begin fading to this level --- fadeDuration = set with fadeTo when the transition needs to be time-adjusted for unpredictable alpha states --- fadeTime = set with fadeTo when the transition has an explicit desired timing --- throttle_rate = animation frame delay --- --- METHODS --- Update() = Runs the frame's Update script, and calls UpdateText() --- UpdateText() = Iterates over frame children and calls Update() if it is a StatusText frame --- --- StatusText --- Sub-container for individual text elements, carries string output values, controlled by from Update(). By default --- these are derived from the parent's primary value data, but is mostly overridden in module code. --- FIELDS --- text = WoW FontString object housing text data --- format = a format string for expressing complex data (timer bars, etc.) --- METHODS --- SetText() = shortcut for text:SetText(...) --- SetJustifyH() = shortcut for text:SetJustifyH(...) --- Implements: --- frame = CreateBar(name, config root) --- Creates and displays a generic bar frame with progress textures and default updater, based on the variables from --- the smart config table. Seeded with methods Update() and UpdateText(). --- Update() will refresh the entire frame and tail call UpdateText() --- UpdateText() will iterate over the contents of frame:GetChildren() and call Update() --- NEVER CREATE A CHILD FRAME WITHOUT Update() DEFINED --- NEVER INVOKE METHODS FROM A GetParent() RETURN --- --- Bar_SetUpdateHandler(frame, function) --- Takes the desired OnUpdate script and wraps it inside frame throttling logic, then does SetScript --- --- frame = AddLabel(frame, config root, name) --- Constructs a text display and adds it to the frame's list of internal text objects. Contains method Update(), which --- refreshed text. --- --- HANDLERS --- Bar_Update([value, min/duration, max/end]) --- Default handler for any non-timed bar (where isTimer = false in config vars. Invoked by frame:Update() -]] -local T = LibStub("AceAddon-3.0"):GetAddon("Turok") -local LSM = LibStub("LibSharedMedia-3.0") -local TL = 'Fog' -local print = function(...) - _G.print(TL, ...) -end ---setprinthandler(function (...) T:debug('Fog', nil, ...) end) -local FADE_OUT_TIME = 1 -- duration per 1-0 alpha transition -local FADE_IN_TIME = 0.4 -- duration per 0-1 alpha transition - -local inset_factor = { - ['TOPLEFT'] = {-1, 1}, - ['TOP'] = {0, 1}, - ['TOPRIGHT'] = {1, 1}, - ['RIGHT'] = {1, 0}, - ['BOTTOMRIGHT'] = {1, -1}, - ['BOTTOM'] = {0, -1}, - ['BOTTOMLEFT'] = {-1,-1}, - ['LEFT'] = {-1, 0} -} - -T.anchor_inverse = { ['LEFT'] = 'RIGHT', ['RIGHT'] = 'LEFT', ['UP'] = 'DOWN', ['DOWN'] = 'UP' } -- directional inverse -T.direction_coord = { ['LEFT'] = {1, 0}, ['RIGHT'] = {-1,0}, ['UP'] = {0, -1}, ['DOWN'] = {0, 1 } } -- directional derivatives -T.anchor_direction = { ['LEFT'] = 'RIGHT', ['RIGHT'] = 'LEFT', ['UP'] = 'BOTTOM', ['DOWN'] = 'TOP'} -- directional anchors - -function T:CreateBar(name, config) - local parent = type(config.parent) == 'string' and _G[config.parent] or parent - if not parent then - parent = CreateFrame('Frame', config.parent, UIParent) - print('creating dry frame |cFFDDDDDD' .. config.parent .. '|r for |cFFFFFF00' .. name .. '|r') - end - - local f - if _G[name] and _G[name].GetFrameType and _G[name].GetFrameType() == 'Frame' then - f = _G[name] - print('found existing table |cFFFFFF00' .. name .. '|r') - else - print('creating statusbar '.. name, config.anchor, parent:GetName(), config.anchorTo, config.posX, config.posY) - end - - - f = CreateFrame('Frame', name, UIParent) - f.db = config - - -- state vars - f.combat = InCombatLockdown() - f.min = 0 - f.max = 1 - f.value = 0 - f.percent = 0 - f.alpha = f.combat and config.alpha or config.alpha_ooc - f:SetAlpha(f.combat and config.alpha or config.alpha_ooc) - f:SetPoint(config.anchor, config.parent, config.anchorTo, config.posX, config.posY) - f:SetSize(config.width, config.height) - f:SetFrameStrata(config.strata) - self:CreateStatusTextures(f, config) - - f.throttle_rate = 0.0166666666 -- ~60fps - f.throttle_point = GetTime() - - -- default handler - f.Update = T.Bar_Update - f.UpdateText = T.Bar_UpdateText - T:Bar_SetUpdateHandler(f, T.Bar_Update) - - return f -end - -function T:CreateStatusTextures(region, c) - c = c and c or region.db - print('STATUSTEX_make', region:GetName(), c.background_texture, c.background_color, c.foreground_texture, c.foreground_color) - region.background = region:CreateTexture('background', 'BACKGROUND') - region.background:SetAllPoints(region) - if c.background_texture then - region.background:SetTexture(LSM:Fetch('statusbar', c.background_texture)) - region.background:SetVertexColor(unpack(c.background_color)) - else - region.background:SetTexture(unpack(c.background_color)) - end - region.background:SetBlendMode(c.background_blend) - - region.foreground = region:CreateTexture('foreground', 'ARTWORK') - region.foreground:SetPoint('TOPLEFT', region, 'TOPLEFT', 0-c.foreground_inset, c.foreground_inset) - region.foreground:SetPoint('BOTTOMRIGHT', region, 'BOTTOMRIGHT', c.foreground_inset, 0-c.foreground_inset) - if c.foreground_texture then - region.foreground:SetTexture(LSM:Fetch('statusbar', c.foreground_texture)) - region.foreground:SetVertexColor(unpack(c.foreground_color)) - else - region.foreground:SetTexture(unpack(c.foreground_color)) - end - region.foreground:SetBlendMode(c.foreground_blend) -end - -function T:CreateStatusIcon(region, c) - local file = type(c) == 'string' and c or region.icon - if type(c) ~= 'table' then - c = region.db - end - print('STATUSICON', region:GetName(), file, c.icon_show) - -end - --- Sets the OnUpdate handler within a timing scheme -function T:Bar_SetUpdateHandler(bar, func) - bar:SetScript('OnUpdate', function(bar) - if GetTime() < bar.throttle_point then - return - end - - bar.throttle_point = bar.throttle_point + bar.throttle_rate - if type(func) == 'string' then - if type(bar[func]) ~= 'function' then - error('TurokBar:SetUpdateScript(); string "' ..func.. '" is not a valid method name') - return - end - elseif type(func) ~= 'function' then - error('TurokBar:SetUpdateScript(function or string); got '.. type(func) .. 'instead') - return - end - - func(bar) - end) -end - --- Default update loop -function T:Bar_Update (value, min, max) - - if value ~= nil then -- could be 0 - self.value = value - end - if (min ~= nil and max ~= nil) then - if self.isTimer then - self.duration = min - self.endTime = max - else - self.min = min - self.max = max - self.duration = max - end - end - - if self.combat ~= InCombatLockdown() then - self.combat = InCombatLockdown() - if self.combat then - self.fadeTo = self.db.alpha - self.fadeDuration = FADE_IN_TIME - else - self.fadeTo = self.db.alpha_ooc - self.fadeDuration = FADE_OUT_TIME - end - end - - -- we need the time for something - if self.isTimer or self.fadeTo ~= nil then - local time = GetTime() - - -- start doing fade animation things - if self.fadeTo ~= nil then - - if not self.fadeFrom then - self.fadeFrom = self:GetAlpha() - end - - -- fadeDuration missing, fill it in - if not self.fadeDuration then - self.fadeDuration = self.fadeFrom > self.fadeTo and FADE_OUT_TIME or FADE_IN_TIME - end - - -- fadeTime missing, - if not self.fadeTime then - local fadeRatio = 1 - if self.fadeFrom ~= self.alpha then - fadeRatio = (self.fadeTo - self.fadeFrom) / (self.fadeTo - self.alpha) -- target delta - end - --print(fadeRatio, self.fadeDuration) - self.fadeTime = time + fadeRatio * self.fadeDuration -- fixed rate of change - end - - -- are we done? - if time >= self.fadeTime then - self:SetAlpha(self.fadeTo) - self.alpha = self.fadeTo - self.fadeTo = nil - self.fadeFrom = nil - self.fadeDuration = nil - self.fadeTime = nil - else --nope - local remaining = (self.fadeTime - time) / self.fadeDuration - local fadeTotal = (self.fadeTo - self.fadeFrom) - --print(self.fadeTo - (fadeTotal * remaining), fadeTotal * remaining) - self:SetAlpha(self.fadeTo - (fadeTotal * remaining)) - end - end - - -- termination check - if self.isTimer then - if time >= self.endTime and self.fadeTo == nil then - self:Hide() - return - else - self.percent = (self.endTime - time) / self.duration - end - end - - else - self.percent = (self.value - self.min) / (self.max - self.min) - end - - self:UpdateText() - self.foreground:SetPoint('BOTTOMRIGHT', self, 'BOTTOMLEFT', self.db.width * self.percent + self.db.foreground_inset, 0-self.db.foreground_inset) -end - -function T:Bar_UpdateText() - local c = {self:GetChildren()} - for _, rl in ipairs(c) do - if rl.text then - rl.format = self.db.label_string - rl:Update() - end - end -end - --- addon:AddLabel --- Constructs a text display and adds it to that region --- -function T:AddLabel (region, config, labelname) - assert(region:IsObjectType('Frame'), "T:CreateLabel(table, table [, string])") - labelname = (labelname or string.format('%x', GetTime() % 1000000)) - print('assigning frame for text object |cFFFF9922'..labelname..'|r to '..region:GetName()) - - local lf = CreateFrame('Frame', region:GetName()..'_'..labelname, region) - local ft = lf:CreateFontString(labelname, 'OVERLAY') - local lx, ly, lp = 0,0, config.label_point - if config.label_inset ~= 0 and lp ~= 'CENTER' then - lx = config.label_inset * inset_factor[lp][1] - ly = config.label_inset * inset_factor[lp][2] - end - - lf:SetPoint(lp, region, lp, lx, ly) - lf:SetSize(region:GetWidth(), region:GetHeight()) - lf:SetFrameStrata(config.label_strata) - - ft:SetFont(LSM:Fetch('font', config.label_font), config.label_size, config.label_outline) - ft:SetAllPoints(lf) - ft:SetJustifyH(config.label_justifyH or (config.label_point:find('LEFT') and 'LEFT' or (config.label_point:find('RIGHT') and 'RIGHT' or 'CENTER'))) - ft:SetJustifyV(config.label_justifyV or (config.label_point:find('TOP') and 'TOP' or (config.label_point:find('BOTTOM') and 'BOTTOM' or 'MIDDLE'))) - ft:SetTextColor(1, 1, 1) - ft:SetText('SET ME!') - - lf.Update = region.isTimer and T.Label_UpdateFormat or T.Label_Update - lf.SetJustifyH = function(self, justify) ft:SetJustifyH(justify) end - lf.SetText = function(self, text) ft:SetText(text) end - - lf.text = ft - region[labelname] = lf - return lf -end - --- one of two possible assignments for label:Update() -function T:Label_UpdateFormat() - local region = self:GetParent() - if self.format then - self.value = string.gsub(self.format, '%%p', string.format('%.1f', region.value)) - self.value = string.gsub(self.value, '%%d', region.duration) - if region.name then - self.value = string.gsub(self.value, '%%n', region.name) - end - end - self.text:SetText(self.value) -end -function T:Label_Update() - self.text:SetText(self:GetParent().value) -end -
--- a/Lost.lua Tue Dec 15 10:10:22 2015 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,218 +0,0 @@ --- User: Krakyn --- Created: 12/14/2015 3:03 PM -local T = LibStub("AceAddon-3.0"):GetAddon("Turok") -local TL = 'Lost' -local print = function(...) _G.print(TL, ...) end -local LSM = LibStub("LibSharedMedia-3.0") -local mod = T:NewModule(TL, "AceTimer-3.0") -local time = _G.ct -local spell_trunc = {} -local inv = T.anchor_inverse -local d = T.direction_coord -local a = T.anchor_direction - -mod.encounter_start = { - ['Aspect'] = { - type = 'buff', - - Test = function() - local res = UnitBuff('player', 'Aspect of the Pack', nil, 'PLAYER') - return (res ~= nil) - end, - sound = LSM:Fetch('sound', 'Wilhelm Scream'), - }, - ['Rune'] = { - Test = function() - local res = UnitBuff('player', 'Hyper Augmentation', nil, 'PLAYER') - return (res ~= nil) - end - } -} - -function mod:OnEnable() - self.raidbuffs_active = {} -- active raid buffs - self.raidbuffs_text = {} -- raid buff text - self.raidbuffs_avail = {} -- availability info - self.raidbuffs_display = {} -- buff list ordering info - self.unit_cache = {} -- remember GUIDs we've seen before - self.raidbuffs_shown = NUM_LE_RAID_BUFF_TYPES - - - local db = _G.TurokData - db.raidbuff = { - parent = 'UIParent', - anchor = 'BOTTOMRIGHT', anchorTo = 'BOTTOMRIGHT', - posX = -300, posY = 300, - height = 24*9, width = 72, - raidbuff_width = 72, - raidbuff_height = 24, - label_size = 11, - label_font = 'ArchivoNarrow-Bold', - } - - - - local rw = CreateFrame('Frame', 'TkRaidWatch', UIParent) - local c = db.raidbuff - self.raidbuffs_frame = rw - rw:SetPoint(c.anchor, c.parent, c.anchorTo, c.posX, c.posY) - rw:SetSize(c.width, c.height) - rw:SetMovable(true) - local bd = rw:CreateTexture() - bd:SetTexture(1,1,1,1) - bd:SetGradient('VERTICAL', 0,0,0,1,1,1) - bd:SetBlendMode('MOD') - bd:SetPoint('TOPLEFT',rw,'TOPLEFT', -2, 2) - bd:SetPoint('BOTTOMRIGHT',rw,'BOTTOMRIGHT', 2, -2) - - -- seed raid buff analyzer assets - self.num_raidbuff_columns = math.floor(c.width / c.raidbuff_width) - for i = 1, 9 do - local icon = rw:CreateTexture('TkRaidWatchButton'..i, 'ARTWORK') - icon:SetSize(c.raidbuff_width,c.raidbuff_height) - icon:SetTexCoord(0.15, 0.85, 0.15, 0.85) - - - self.raidbuffs_active[i] = icon - rw:EnableMouse(true) - rw:SetScript('OnMouseDown', function(self) self:StartMoving() end) - rw:SetScript('OnMouseUp', function(self) self:StopMovingOrSizing() end) - - local text = rw:CreateFontString('TkRaidWatchText'.. i, 'OVERLAY') - text:SetPoint('CENTER', icon, 'CENTER') - text:SetFont(LSM:Fetch('font', c.label_font), c.label_size, 'OUTLINE') - text:SetText(i) - self.raidbuffs_text[i] = text - end - - db.raidevent = {} - - - self:RegisterEvent('PARTY_MEMBERS_CHANGED') - self:RegisterEvent('PLAYER_SPECIALIZATION_CHANGED') - self:RegisterEvent('ENCOUNTER_START') - self:RegisterEvent('INSPECT_READY') - self:RegisterEvent('UNIT_AURA', 'RaidBuffScan') - - self:RaidBuffScan() - self:RosterScan() -end -function mod:PLAYER_REGEN_ENABLED(e,...) end -function mod:PLAYER_REGEN_DISABLED(e, ...) end - -function mod:INSPECT_READY() -end -function mod:PLAYER_SPECIALIZATION_CHANGED(e,unit) - local specID - print(e, unit) - if unit == 'player' then - specID = GetSpecializationInfo(GetSpecialization()) - else - --NotifyInspect(unit) - specID = GetInspectSpecialization() - end - - print(GetSpecializationInfoByID(specID)) - self:RosterScan() -end - -function mod:PARTY_MEMBERS_CHANGED(e, ...) - if IsInRaid() or IsInGroup() then - self.raidbuffs_frame:Show() - self:RaidBuffScan() - end -end - -function mod:ENCOUNTER_START(e,...) - for k, v in pairs(self.encounter_start) do - local test, info = v.Test() - if test == true then - print(v.type, k, 'doing a thing') - else - print(v.type, k, info) - end - end -end - --- Updates available raid/party buffs -function mod:RaidBuffScan(unit) - if self.hiding then - return - end - local c = T.db.raidbuff - - -- search for unit data - -- update raidbuffs - - -- set our number of things to track - - local k = 1 - for i = 1, NUM_LE_RAID_BUFF_TYPES do - local rb = self.raidbuffs_active[i] - local rt = self.raidbuffs_text[i] - local name, rank, texture, duration, expiration, spellId, slot = GetRaidBuffTrayAuraInfo(i) - if name then - rb:Hide() - rt:Hide() - self.raidbuffs_display[i] = nil - else - rb:Show() - rt:Show() - if self.raidbuffs_avail[i] then - rb:SetTexture(0.5,0.5,0.5,0.1) - rb:SetBlendMode('MOD') - else - rb:SetTexture(1,0.2,0,0.5) - rb:SetBlendMode('ADD') - end - self.raidbuffs_text[i]:SetText(string.sub(_G['RAID_BUFF_'..i],0,2)) - - if not self.raidbuffs_display[i] or self.raidbuffs_display[i] ~= k then - self.raidbuffs_display[i] = k - local pn = k-1 -- need (n-1) for lua grid math - local py = math.floor(pn / self.num_raidbuff_columns) * c.raidbuff_height - local px = (pn * c.raidbuff_width) % c.width -- x-offset - print('buff slot '..i..' (draw slot '..k..')', pn, py, px) - rb:SetPoint('BOTTOMLEFT', TkRaidWatch, 'BOTTOMLEFT', px, py) - end - - k = k + 1 - end - end -end - -function mod:RosterScan() - local lim = 1 - if IsInRaid() then - lim = 40 - elseif IsInGroup() then - lim = 5 - end - - for i = 1, lim do - local name, rank, subgroup, level, class, fileName, zone, online, isDead, role, isML = GetRaidRosterInfo(i) - local realm - if name then - if string.find(name,'-') then - name, realm = string.match(name, "(.+)-(.+)") - else - realm = GetRealmName() - end - - local GUID = UnitGUID('raid' .. i) - if not self.unit_cache[GUID] then - self.unit_cache[GUID] = { - name = name, - realm = realm, - } - end - - pl = self.unit_cache[GUID] - - - print(i, name, class, role) - end - - end - -end \ No newline at end of file
--- a/Spirit.lua Tue Dec 15 10:10:22 2015 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,276 +0,0 @@ --- User: Krakyn --- Created: 12/8/2015 7:30 PM -local T = LibStub("AceAddon-3.0"):GetAddon("Turok") -local TL = 'Spirit' -local print = function(...) _G.print(TL, ...) end -local LSM = LibStub("LibSharedMedia-3.0") -local mod = T:NewModule("Spirit", "AceTimer-3.0") -local time = _G.ct -local auras = { - 168811, -- sniper training - 168809, -- sniper training: recently moved - 13159, -- aspect of the pack, - 187615, -- Maalus -} -local spells = { - 3045, -- rapid fire, - 26297, -- berserking, - 121818, -- stampede, - -} -local FRAME_PREFIX = 'TkSpirit' -local FADE_TIME = 0.5 --- local repetitive tasks -local function FindSpirit(id) - local db = T.db - local c = db.spirit - local isIcon = false - if db.spirit.progressbar[id] then - c = db.spirit.progressbar[id] - elseif db.spirit.icon[id] then - c = db.spirit.icon[id] - isIcon = true - end - local name, rank, icon, castingTime, minRange, maxRange, spellID = GetSpellInfo(id) - local s = { - name = name, - rank = rank, - icon = icon, - castingTime = castingTime, - minRange = minRange, - maxRange = maxRange, - spellID = spellID - } - - return s, c, isIcon -end - -function mod:OnEnable() - local db = _G.TurokData - self.aura_watch = {} - self.cooldown_watch = {} - self.item_watch = {} - self.myGUID = UnitGUID('player') - - - db.spirit = { - foreground_color = {1, 1, 1, 0.7}, - foreground_texture = 'Cilo', - foreground_blend = 'BLEND', - foreground_inset = -1, - background_color = {0, 0, 0, 0.7}, - background_blend = 'BLEND', - background_texture = 'Cilo', - icon_show = true, - width = 250, height = 20, - anchor = 'CENTER', parent = 'UIParent', anchorTo = 'CENTER', - posX = 0, posY = -150, - label_color = {1, 1, 1, 1}, - label_font = 'turok', - label_size = 14, - label_inset = -2, - label_point = 'LEFT', - label_outline = 'OUTLINE', - label_string = '%n %p', - label_strata = 'HIGH', - expire_sound = LSM:Fetch('sound'), - strata = 'LOW', - icon = { - [13159] = { -- Aspect of the Pack - posX = 20, posY = 20, width = 140, height = 140, - }, - [3045] = { - parent = 13159, anchor = 'RIGHT', anchorTo = 'LEFT', - posx = 0, posY = 0, width = 64, height = 64, - } - }, - progressbar = { - [168811] = { -- Sniper Training (duration) - background_color = {0,0,0,0}, - foreground_color = {1,0,0,1}, - anchor = 'BOTTOMLEFT', parent = 'TkFocusBar', anchorTo = 'TOPLEFT', - posX = 0, posY = 0, height = 16, width = 250, - label_string = '', - label_point = 'TOPLEFT', - strata = 'LOW', - attach = {{ - width_relative = 0.5, - height_relative = 1, - background_color = {1,0,0,1}, - foreground_color = {1,1,0.5, 1}, - background_blend = 'ADD', - foreground_blend = 'ADD', - - anchor = 'LEFT', - anchorTo = 'LEFT', - strata = 'MEDIUM', - }} - }, - [168809] = { -- Sniper Training: Recently Moved - background_color = {0,0,0,0 }, - foreground_color = {1,1,1,1}, - foreground_blend = 'ADD', - anchor = 'BOTTOMLEFT', parent = 'TkFocusBar', anchorTo = 'TOPLEFT', - strata = 'HIGH', - posX = 0, posY = 0, height = 16, width = 125, - icon_show = false, - label_string = '', - exceptions = { - function(aura) - return (mod.aura_watch[168811].expires < aura.expires) - end - }, - }, - }, - } - - for _, id in pairs(auras) do - -- store spellinfo fetch - self.aura_watch[id] = self:CreateSpiritFrame(id) - self.aura_watch[id].count = 0 - self.aura_watch[id].duration = 0 - self.aura_watch[id].expires = 0 - self.aura_watch[id].caster = 0 - print('AURA', id, self.aura_watch[id].name) - end - - for _, id in ipairs(spells) do - self.cooldown_watch[id] = self:CreateSpiritFrame(id) - print('COOLDOWN', id, self.cooldown_watch[id].name) - end - - self:SpiritScan() - self:RegisterEvent('UNIT_AURA') - self:RegisterEvent('COMBAT_LOG_EVENT_UNFILTERED') - self:RegisterEvent('PLAYER_REGEN_DISABLED') - self:RegisterEvent('PLAYER_REGEN_ENABLED') -end - --- StatusBar factory -function mod:CreateSpiritFrame(id) - local s, c, isIcon = FindSpirit(id) - - -- how much frame do we need? - local f - if isIcon then - f = CreateFrame('Frame', FRAME_PREFIX..id, UIParent) - f.db = c - function f:Update() end - else - f = T:CreateBar('TkAuraBar'..id, c) - f.isTimer = true - if (c.label_string ~= '') then - print('has label, add it', id) - T:AddLabel(f, c) - end - end - f:Hide() - - -- general display - f:SetPoint(c.anchor, c.parent, c.anchorTo, c.posX, c.posY) - f:SetSize(c.width, c.height) - f:SetFrameStrata(c.strata) - - -- icon? - f.icon = s.icon - T:CreateStatusIcon(f) - - -- attachment frames? - if c.attach then - for i, e in ipairs(c.attach) do - local ef = CreateFrame('Frame', 'TkExtra'..id, f) - f[i] = ef - ef:SetPoint(e.anchor, f, e.anchorTo) - ef:SetSize(c.width * e.width_relative or e.width, c.height * e.height_relative or e.height) - ef:SetFrameStrata(e.strata or c.strata) - T:CreateStatusTextures(ef, e) - end - end - - -- setup suppression checking - if c.exceptions then - function s:ExceptionCheck () - for i, func in ipairs(c.exceptions) do - if not func(self) then - return false, i - end - end - return true - end - else - function s:ExceptionCheck () return true end - end - - -- access linkage - f.format = c.label_string - f.spirit = s - f.name = s.name - s.frame = f - return s -end - -function mod:UNIT_AURA(e, unit) - if unit == 'player' then - self:SpiritScan() - end -end - --- Updates aura watches -function mod:SpiritScan() - local db = _G.TurokData - for id, aura in pairs(self.aura_watch) do - local c = aura.conf - local f = aura.frame - - local name, _, _, count, _, duration, expires, caster = UnitAura('player', aura.name) - - if name then - aura.duration = duration - aura.expires = expires - aura.caster = caster - aura.count = count - local test, i = aura:ExceptionCheck() - print(name, duration, expires) - if not test then - print('suppressing '..aura.name..' (failed test #'..i..')') - else - f.name = name - f:Update(nil, duration, expires) - f:Show() - end - end - end -end - -function mod:PLAYER_REGEN_ENABLED() - for id, aura in pairs(self.aura_watch) do - print('non-combat alpha for #', id, aura.name, 'is', aura.frame.db.alpha_ooc) - aura.frame.fadeTo = aura.frame.db.alpha_ooc - aura.frame.fadeDuration = FADE_TIME - end -end - -function mod:PLAYER_REGEN_DISABLED() - for id, aura in pairs(self.aura_watch) do - print('combat alpha for #', id, aura.name, 'is', aura.frame.db.alpha) - aura.frame.fadeTo = aura.frame.db.alpha - aura.frame.fadeDuration = FADE_TIME - end -end - --- This is the most reliable way of catching item and spell uses, other events are delayed or too vague to be useful -function mod:COMBAT_LOG_EVENT_UNFILTERED(e, ...) - local timestamp, combatEvent, hideCaster, sourceGUID, sourceName, sourceFlags, sourceRaidFlags, destGUID, destName, destFlags, destRaidFlags = - ...; -- Those arguments appear for all combat event variants. - local eventPrefix, eventSuffix = combatEvent:match("^(.-)_?([^_]*)$"); - if eventPrefix ~= 'SPELL_' or sourceGUID ~= self.myGUID then - return - end - - local spellid, name, count, type = select(13, select('#', ...), ...) - local kc = '' - for i=1,4 do - kc = kc .. string.format('%X',((string.byte(eventSuffix,i) % 8) + 8)) - end - print('|cFFFF'..kc..eventSuffix..'|r', sourceName, destName, spellid, name) -end \ No newline at end of file
--- a/Tek.lua Tue Dec 15 10:10:22 2015 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,404 +0,0 @@ -addon, T_ = ... --- User: Krakyn --- Created: 12/4/2015 11:17 PM -local T = LibStub("AceAddon-3.0"):GetAddon("Turok") -local db = T.db -local TL = 'Tek' -local mod = T:NewModule("Tek") -local print = function(...) - _G.print('Tek', ...) -end -local time = _G.ct - --- events & units -local TRACKED_UNITS = {'player', 'target', 'focus', 'pet'} -local TRACKED_EVENTS = {'UNIT_SPELLCAST_START', 'UNIT_SPELLCAST_DELAYED', 'UNIT_SPELLCAST_STOP', 'UNIT_SPELLCAST_FAILED', 'UNIT_SPELLCAST_FAILED_QUIET', - 'UNIT_SPELLCAST_INTERRUPTED', 'UNIT_SPELLCAST_SUCCEEDED', 'UNIT_SPELLCAST_CHANNEL_START', 'UNIT_SPELLCAST_CHANNEL_STOP', 'UNIT_SPELLCAST_CHANNEL_UPDATE' } - --- animations are a little different here -local FADE_OUT_TIME, FADE_IN_TIME = 1000, 200 - --- values MUST be in chronological order -local CHANNEL_START, CAST_START, CAST_INTERRUPTED, CAST_SUCCEEDED, CAST_STOPPED, CAST_FAILED, CHANNEL_STOPPED = 1, 2, 3, 4, 5, 6, 7 -local TEXTURE_SUFFIX = { - [CHANNEL_START] = '_channeling', - [CAST_START] = '_casting', - [CAST_INTERRUPTED] = '_interrupted', - [CAST_SUCCEEDED] = '_finished', - [CAST_STOPPED] = '_failed', - [CAST_FAILED] = '_failed', - [CHANNEL_STOPPED] = '' -} - --- defaults -db.castbar = { - --T.defaults.castbar = { - width = 300, height = 24, - anchor = 'CENTER', parent = 'UIParent', anchorTo = 'CENTER', - posX = 0, posY = 0, - foreground_casting = {0.80784313725, 0.87843137254, 0.0156862745, 1}, - background_casting = {0,0,0,0.4}, - background_interrupted = {1,0,0,1}, - background_failed = {0.60784313725, 0.87843137254, 0.0156862745, 1}, - foreground_interrupted = {1, 0.5, 0, 1}, - foreground_failed = {0,0,0,1}, - foreground_finished = {0.60784313725, 0.87843137254, 0.0156862745, 1}, - background_finished = {0.60784313725, 0.87843137254, 0.0156862745, 1}, - foreground_inset = -1, - fill_direction = 'RIGHT', - fill_inverse = false, - glow_texture = "Tooltip-BigBorder", - glow_size = 2, - spark_texture = "Tooltip-BigBorder", - spark_size = 2, - ['player'] = { - width = 400, height = 36, - anchor = 'TOP', parent = 'TkFocusBar', anchorTo = 'BOTTOM', - posX = 0, posY = 2, - }, - ['target'] = { - width = 400, height = 36, - anchor = 'BOTTOMLEFT', parent = 'TkplayerCastBar', anchorTo = 'TOPRIGHT', - posX = -30, posY = 4, - }, - ['focus'] = { - width = 200, height = 36, - anchor = 'TOPLEFT', parent = 'TkplayerCastBar', anchorTo='BOTTOMRIGHT', - posX = 2, posY = -2 - }, - ['pet'] = { - width = 300, height = 24, - anchor = 'TOPRIGHT', parent = 'TkFocusBar', anchorTo='TOPLEFT', - posX = -2, posY = 0 - }, -} - -local inv = T.anchor_inverse -local d = T.direction_coord -local a = T.anchor_direction -local c = {} --- c[unit]=nil is used by frame update, thus any indexing from a valid frame is implied to be for new casting info -setmetatable(c, { - __index = function(t,k) - t[k] = {} - return t[k] - end -}) - -function mod:OnEnable() - local db = T.db - - self.casting = c - self.castbar = {} - - - for _, unit in pairs(TRACKED_UNITS) do - local cdb = db.castbar[unit] - print('|cFFFF44FF' .. unit .. '|r castbar creation') - - - -- State info - c[unit] = {} - - -- Set frames - local fn = 'Tk' .. unit .. 'CastBar' - self.castbar[unit] = T:CreateBar(fn, cdb) - local pc = self.castbar[unit] - pc:Hide() - pc:SetAlpha(0) - - T:AddLabel(pc, cdb, 'spelltext') - local casttime = T:AddLabel(pc, cdb, 'casttime') - pc.foreground:SetWidth(0) - - casttime:SetPoint('RIGHT', pc, 'RIGHT') - casttime:SetJustifyH('RIGHT') - - if unit == 'player' then - local lb = pc:CreateTexture('latency', 'OVERLAY') - local lt = T:AddLabel(pc, cdb, 'latency') - lt:SetPoint('TOPRIGHT', pc.casttime, 'BOTTOMRIGHT') - lt:SetJustifyH('RIGHT') - pc.latency = lb - lb.text = lt - end - - pc.transpt = a[cdb.fill_direction] - pc.xtrans = function() return math.min((cdb.width + cdb.foreground_inset) * pc.percent * d[pc.transpt][1], cdb.width) end - pc.ytrans = function() return math.min((cdb.height + cdb.foreground_inset) * pc.percent * d[pc.transpt][2], cdb.height) end - - pc.movement_x = 1 - pc.moving_end = 'LEFT' - - local glow = pc:CreateTexture('glow', 'OVERLAY') - glow:SetTexture(CASTBAR_TAILGLOW) - glow:SetPoint('TOPLEFT', pc, 'TOPLEFT', -5, 5) - glow:SetPoint('BOTTOMRIGHT', pc, 'BOTTOMRIGHT', 5, -5) - pc.glow = glow - - local icon = pc:CreateTexture('icon', 'ARTWORK') - icon:SetPoint('RIGHT', pc, 'LEFT', -2, 0) - icon:SetWidth(pc.foreground:GetHeight()) - icon:SetHeight(pc.foreground:GetHeight()) - icon:SetTexture(0,0,0,1) - pc.icon = icon - - pc.unit = unit - T:Bar_SetUpdateHandler(pc, self.TekUpdate) - end - - -- Casting table events - for i, event in pairs(TRACKED_EVENTS) do - print('listening to |cFF00FFFF' .. event .. '|r') - self:RegisterEvent(event, 'TekEvent') - end - - -- Extra events - self:RegisterEvent('PLAYER_TARGET_CHANGED') - self:RegisterEvent('PLAYER_FOCUS_CHANGED') - - -- kill default casting bar - -- T.cbscripts = {CastingBarFrame:GetScript('OnUpdate'), CastingBarFrame:GetScript('OnEvent')} - CastingBarFrame:SetScript('OnUpdate', nil) - CastingBarFrame:SetScript('OnEvent', nil) - CastingBarFrame:Hide() -end - --- Update handler for castbar -function mod:TekUpdate() - local glow = self.glow - local foreground = self.foreground - local background = self.background - local latency = self.latency - local time = GetTime() * 1000 - local spelltext = self.spelltext - local timetext = self.timetext - local cdb = self.db - if mod.casting[self.unit] ~= nil then - - local u = self.unit - local s = mod.casting[u] - local alpha = self:GetAlpha() - - -- is something casting at all? - if s.casting <= CAST_START then - - -- start = true whenever a new spell cast could be active (i.e. target switching) - if s.init then - print('|cFFDD77DD'..u..'|r init_cast (spell='..s.displayName..', startTime='..s.startTime..', endTime='..s.endTime..', channel=',s.channel,')') - print(self:GetName(), self:IsVisible(), self:IsShown()) - - if u == 'player' then - self.latency.text:SetText(s.latency) - end - - -- update translation point - if s.casting == CHANNEL_START and not cdb.fill_inverse then - self.transpt = inv[a[cdb.fill_direction]] - else - self.transpt = a[cdb.fill_direction] - end - - -- update frame contents - foreground:SetTexture(unpack(cdb['foreground' .. TEXTURE_SUFFIX[s.casting]] and cdb['foreground' .. TEXTURE_SUFFIX[s.casting]] or cdb.foreground_color)) - background:SetTexture(unpack(cdb['background' .. TEXTURE_SUFFIX[s.casting]] and cdb['background' .. TEXTURE_SUFFIX[s.casting]] or cdb.background_color)) - - self.icon:SetTexture(s.texture) - spelltext:SetText(s.displayName) - self.duration = s.endTime - s.startTime - self.fadeIn = s.startTime + (1-alpha) * FADE_IN_TIME - self.fadeOut = s.endTime + FADE_OUT_TIME -- needs to exist for target changes - - print(s.startTime, self.fadeIn, self.fadeIn - s.startTime) - -- clear 'start' - s.init = nil - end - - -- if we're checking this and start was never flipped, then something happened - if time <= self.fadeIn then - alpha = 1- ((self.fadeIn - time) / FADE_IN_TIME) - self:SetAlpha(alpha) - elseif alpha ~= 1 then - self:SetAlpha(1) - end - self.value = time - s.startTime - self.percent = self.value / self.duration - self.casttime:SetText(format("%.1f", self.value / 1000)) - - -- s.casting is nil when the spellcast has finished - else - -- something set a term flag - if s.casting < CHANNEL_STOPPED and s.fade then - print(TL, '|cFFDD77DD'..u..'|r init_fadeout (spell='..s.displayName..', startTime='..s.startTime..', endTime='..s.endTime..', channel=',s.channel,')') - self.fadeOut = time + FADE_OUT_TIME - foreground:SetTexture(unpack(cdb['foreground' .. TEXTURE_SUFFIX[s.casting]] and cdb['foreground' .. TEXTURE_SUFFIX[s.casting]] or cdb.foreground_color)) - background:SetTexture(unpack(cdb['background' .. TEXTURE_SUFFIX[s.casting]] and cdb['background' .. TEXTURE_SUFFIX[s.casting]] or cdb.background_color)) - s.fade = nil - self.value = self.duration - self.percent = 1 - end - - if time < self.fadeOut then - alpha = (self.fadeOut - time) / FADE_OUT_TIME - self:SetAlpha(alpha) - else - alpha = 0 - self:Hide() - self:SetAlpha(alpha) - self.casttime:SetText(nil) - self.spelltext:SetText(nil) - self.debugged = false - self.percent = 0 - if u == 'player' then - self.latency.text:SetText(nil) - end - mod.casting[self.unit] = nil - print('|cFFDD77DD'..u..'|r work complete, hiding...') - end - -- hide and wait until we're pulled out again - end - self.foreground:SetPoint('RIGHT', self, self.transpt, self.xtrans(), self.ytrans()) - end -end - - --- event stub, filters out unwanted cast events -function mod:TekEvent(e, unit, ...) - if not self.castbar[unit] then - return - end - if not self[e] then - error('No method signature for event ' .. tostring(e)) - end - print('popped |cFF00FFFF' .. e .. '|r: ', unit, ...) - self[e](self, e, unit, ...) -end - -function mod:PLAYER_TARGET_CHANGED (e, cause) - print(e) - self:UpdateUnit('target') -end -function mod:PLAYER_FOCUS_CHANGED (e, cause) - print(e) - self:UpdateUnit('focus') -end -function mod:UpdateUnit(unit) - if UnitCastingInfo(unit) then - mod:UNIT_SPELLCAST_START('UNIT_SPELLCAST_START', unit) - elseif UnitChannelInfo(unit) then - mod:UNIT_SPELLCAST_CHANNEL_START('UNIT_SPELLCAST_CHANNEL_START', unit) - else - mod.castbar[unit]:Hide() - end -end - --- Spell event handlers -function mod:UNIT_SPELLCAST_SENT(e, unit, spellname, rank, target) - -- triggered an action buttton tied to a cast - c[unit].sentTime = math.floor(GetTime() * 1000) - print('|cFF44FF44',e,':|r', unit, spellname, c[unit].sentTime) - c[unit].spell = spellname - c[unit].rank = rank - c[unit].target = target -end - -function mod:UNIT_SPELLCAST_START(e, unit) -- Server says: someone started casting - local spellname, rank, displayName, texture, startTime, endTime, isTradeSkill, castID, nonInterruptible = UnitCastingInfo(unit) - print('casting['..unit..'] state updated (=start): spellname='.. spellname ..', startTime='.. startTime ..', endTime='.. endTime) - - c[unit].castID = castID - c[unit].spell = spellname - c[unit].rank = rank - c[unit].displayName = displayName - c[unit].texture = texture - c[unit].startTime = startTime - c[unit].endTime = endTime - c[unit].nonInterruptible = nonInterruptible - c[unit].isTradeSkill = isTradeSkill - if c[unit].sentTime then - c[unit].latency = c[unit].startTime - c[unit].sentTime - end - - -- set state and show - c[unit].casting = CAST_START - c[unit].init = true - self.castbar[unit]:Show() -end - -function mod:UNIT_SPELLCAST_DELAYED(e, unit, spellname, rank, castID, target) -- Server says: they're still casting but it'll take longer - local spellname, rank, displayName, texture, startTime, endTime, isTradeSkill, castID, nonInterruptible = UnitCastingInfo(unit) - print('casting['..unit..'] state updated (=delayed): spellname='.. spellname ..', startTime='.. startTime ..', endTime='.. endTime) - c[unit].castID = castID - c[unit].channel = false - c[unit].startTime = startTime - c[unit].endTime = endTime - -- just update timing data, frame script will adjust -end - --- set exit states -function mod:UNIT_SPELLCAST_STOP(e, unit, spellname, rank, castID, target) -- Server says: someone stopped casting for some reason - --c[unit].casting = CAST_STOPPED -end - -function mod:UNIT_SPELLCAST_INTERRUPTED(e, unit, spellname, rank, castID, target) -- Server says: someone got interrupted - c[unit].casting = CAST_INTERRUPTED - c[unit].fade = true -end - -function mod:UNIT_SPELLCAST_SUCCEEDED(e, unit, spellname, rank, castID, target) -- Server says: they stopped because they're done - - if c[unit].castID == castID and c[unit].casting ~= CHANNEL_START then - c[unit].casting = CAST_SUCCEEDED - c[unit].fade = true - end -end - -function mod:UNIT_SPELLCAST_FAILED(e, unit, spellname, rank, castID, target) -- Server says: someone tried to cast something but they weren't allowed - if c[unit].castID ~= castID then -- can fire from keybind spam - return - end - c[unit].casting = CAST_FAILED - c[unit].fade = true -end - -function mod:UNIT_SPELLCAST_FAILED_QUIET(e, unit, spellname, rank, castID, target) -- Server says: someone tried to cast something but they weren't allowed - if c[unit].castID == castID and c[unit].casting == CAST_START then - c[unit].casting = CAST_FAILED - end -end - -function mod:UNIT_SPELLCAST_INTERRUPTIBLE(e, unit) - c[unit].notInterruptible = false -end -function mod:UNIT_SPELLCAST_NOT_INTERRUPTIBLE(e, unit) - c[unit].notInterruptible = true -end - -function mod:UNIT_SPELLCAST_CHANNEL_START(e, unit, spellname, rank, castID, spellID) - local spellname, rank, displayName, texture, startTime, endTime, isTradeSkill, nonInterruptible = UnitChannelInfo(unit) - displayName = spellname -- channels sometimes just appear as 'Channeling' according to Quartz author - print('casting['..unit..'] state updated (=start, channel): spellname='.. spellname ..', startTime='.. startTime ..', endTime='.. endTime) - c[unit].casting = CHANNEL_START - c[unit].spellname = spellname - c[unit].rank = rank - c[unit].displayName = displayName - c[unit].texture = texture - c[unit].startTime = startTime - c[unit].endTime = endTime - c[unit].nonInterruptible = nonInterruptible - c[unit].isTradeSkill = isTradeSkill - c[unit].init = true - mod.castbar[unit]:Show() -end -- start up -function mod:UNIT_SPELLCAST_CHANNEL_STOP(e, unit, spellname, rank, castID, spellID) - c[unit].casting = CHANNEL_STOPPED -end -function mod:UNIT_SPELLCAST_CHANNEL_UPDATE(e, unit, spellname, rank, castID, spellID) - spellname, rank, displayName, texture, startTime, endTime, isTradeSkill, nonInterruptible = UnitChannelInfo(unit) - displayName = spellname -- channels sometimes just appear as 'Channeling' according to Quartz author - c[unit].channel = true -end -- recalc - - - -
--- a/Turok.iml Tue Dec 15 10:10:22 2015 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<module type="LUA_MODULE" version="4"> - <component name="NewModuleRootManager" inherit-compiler-output="true"> - <exclude-output /> - <content url="file://$MODULE_DIR$"> - <sourceFolder url="file://$MODULE_DIR$" isTestSource="false" /> - </content> - <orderEntry type="inheritedJdk" /> - <orderEntry type="sourceFolder" forTests="false" /> - </component> -</module> \ No newline at end of file
--- a/Turok.lua Tue Dec 15 10:10:22 2015 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,159 +0,0 @@ - --- GLOBALS: DEFAULT_CHAT_FRAME, SlashCmdList, hash_SlashCmdList -local T = LibStub("AceAddon-3.0"):NewAddon("Turok", "AceConsole-3.0", "AceEvent-3.0") -local _G = _G -local rawset = _G.rawset -_G.Turok = T -local print = function(...) - --_G.print('Core', ...) -end - - -T.mods = {} -T:SetDefaultModuleState(true) -T:SetDefaultModuleLibraries("AceEvent-3.0") -T:SetDefaultModulePrototype({OnInitialize = function(mod) - print('CORE', mod:GetName().. ' found') -end}) - --- propagates parameter data around -function T:LinkTable(parent, child, pname, cname) - local mt = { - __index = function(t,k) - if parent[k] then - t[k] = parent[k] - end - print('|cFFFF8800'.. pname ..'.' .. cname .. '|r.|cFFFFFF00'.. k ..'|r inheriting value at |cFFFF8800' .. pname ..'|r.|cFFFFFF00'.. k..'|r') - return parent[k] - end, - __newindex = function (t, k, v) - rawset(t,k,v) - if type(v) == 'table' then - T:LinkTable(child, v, pname, k) - print('|cFFFF8800'.. pname ..'.' .. cname .. '|r.|cFFFFFF00'.. k ..'|r sub-table created') - end - end - } - print('|cFFFF8800'.. pname ..'.|cFFFFFF00'.. cname ..'|r sub-tables will be retconned') - setmetatable(child, mt) - for k, v in pairs(child) do - if type(v) == 'table' then - T:LinkTable(child, v, cname, k) - end - end -end - -function T:OnInitialize() - - local defaults = { - background_color = {0,0,0,0}, - background_blend = 'BLEND', - foreground_color = {1,1,1,0.5}, - foreground_blend = 'BLEND', - foreground_inset = -1, - width = 250, - height = 100, - alpha = 1, - alpha_ooc = 0.1, - strata = 'LOW', - label_strata = 'HIGH', - label_justifyH = 'LEFT', - label_color = {1, 1, 1, 1}, - label_font = 'turok', - label_size = 14, - label_inset = -2, - label_point = 'LEFT', - label_outline = 'OUTLINE', - anchor = 'CENTER', parent = 'UIParent', anchorTo = 'CENTER', - focusbar = { - foreground_color = {1, 1, 1, 0.7}, - background_color = {0,0,0,0.8}, - width = 300, height = 24, - posX = 0, posY = -150, - }, - } - _G.TurokData = defaults - if not _G.TurokData then - _G.TurokData = defaults - end - - T.db = _G.TurokData - local db = T.db - for k, v in pairs(db) do - if type(v) == 'table' then - T:LinkTable(db, v, 'db', k) - end - end - setmetatable(db, - {__newindex = function (t, k, v) - rawset(t,k,v) - if type(v) == 'table' then - T:LinkTable(db, v, 'db', k) - print('CFG', '|cFFFF0000db|r.|cFF00FFFF' .. k ..'|r created at bottom level') - end - end}) - - options = { - type = 'group', - name = 'Turok', - handler = T, - set = function(info,value) - local k = db[info[1]] - for i = 2, #info-1 do - if type(k[i]) ~= 'table' then - print('fart') - end - - k = k[i] - end - k[info[#info]] = value - end, - get = function(info) - local k = db[info[1]] - for i = 2, #info-1 do - if type(k[i]) ~= 'table' then - print('fart') - end - - k = k[i] - end - return k[info[#info]] - end, - desc = '"Dinosaur" Hunter', - args = { - background_color = { - type = 'color', - name = 'Background Color', - hasAlpha = true, - } - } - } - LibStub("AceConfig-3.0"):RegisterOptionsTable('Turok', options, {"tk"}) - -end - - -function T:OnEnable() - local db = _G.TurokData - - print('I... am Turok') - - self.stats = { - maxpower = UnitPowerMax('player') - } - - - T.focusbar = T:CreateBar('TkFocusBar', db.focusbar) - local fb = T.focusbar - T:AddLabel(fb, db.focusbar) - fb:Update(UnitPower("player"), 0, UnitPowerMax("player")) - T:Bar_SetUpdateHandler(fb, function(self) - local pp = UnitPower("player") - if pp == T.stats.maxpower and not T.stats.capped then - T.stats.capped = true - elseif T.stats.capped then - T.stats.capped = false - end - T.Bar_Update(fb, pp) - end) -end
--- a/Turok.toc Tue Dec 15 10:10:22 2015 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -## Interface: 60200 -## Title: Turok -## Notes: Dinosaur Huntin' -## Author: Krakyn -## Version: 1.0 -## SavedVariables: TurokData -## OptionalDep: Ace3 - -Libs\LibStub\LibStub.lua -Libs\AceConsole-3.0\AceConsole-3.0.xml -Libs\AceAddon-3.0\AceAddon-3.0.xml -Libs\AceConfig-3.0\AceConfig-3.0.xml -Libs\AceEvent-3.0\AceEvent-3.0.xml -Libs\AceTimer-3.0\AceTimer-3.0.xml -Libs\CallbackHandler-1.0\CallbackHandler-1.0.xml -Libs\LibSharedMedia-3.0\lib.xml -Media\Manifest.lua -Turok.lua -Fog.lua -Tek.lua -Equip.lua -Spirit.lua -Lost.lua \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/.pkgmeta Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,19 @@ +externals: + Libs/LibStub: + url: svn://svn.wowace.com/wow/libstub/mainline/trunk + tag: latest + Libs/CallbackHandler-1.0: + url: svn://svn.wowace.com/wow/callbackhandler/mainline/trunk/CallbackHandler-1.0 + tag: latest + Libs/AceAddon-3.0: + url: svn://svn.wowace.com/wow/ace3/mainline/trunk/AceAddon-3.0 + tag: latest + Libs/LibGroupInSpecT-1.1: + Libs/LibGroupInSpecT-1.1: svn://svn.wowace.com/wow/libgroupinspect/mainline/trunk + +ignore: + - Debug.lua + - Turok.iml + - .idea + +enable-nolib-creation: no \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Init.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,287 @@ +--- ${PACKAGE_NAME} +-- @file-author@ +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +-- Created: 12/28/2015 6:40 AM +--- Core load sequence goes here. +--@debug@ +local ADDON, TurokEnv = ... +local _G = _G +--@end-debug@ +--GLOBALS: Turok, LibStub, GetAddOnMetadata +local setmetatable, rawset, rawget, pairs, type, unpack, tostring, tinsert = setmetatable, rawset, rawget, pairs, type, unpack, tostring, table.insert +Turok = LibStub("AceAddon-3.0"):NewAddon('Turok', 'AceEvent-3.0', 'AceTimer-3.0', 'AceConsole-3.0') +Turok:SetDefaultModuleState(true) +TurokEnv.Addon = Turok +TurokEnv.LSM = LibStub("LibSharedMedia-3.0") +TurokEnv.LGIST = LibStub("LibGroupInSpecT-1.1") +local T = Turok +--@debug@ +local print = function(...) + if _G.Devian and _G.DevianDB.workspace ~= 1 then + _G.print('DB', ...) + end +end +local cTypes = { ['function'] = 'FF9922', ['table'] = '00FFAA', ['number'] = '77FF00', ['string'] = '00AAFF', ['hl'] = 'FF0088', ['field'] = '00FFFF', + ['boolean'] = 'CC88FF', ['false'] = 'FF7700', ['true'] = '44FF66', ['nil'] = 'FFFF00',} + +local Debuggers = { + cType = function(s) return '|cFF' .. tostring(cTypes[type(s)]) .. tostring(s) .. '|r' end, + cText = function(s) return '|cFF'..cTypes.string..tostring(s)..'|r' end, + cNum = function(n) return '|cFF'..cTypes.number .. tostring(n) .. '|r' end, + cWord = function(w) return '|cFF'..cTypes.table .. tostring(w) .. '|r' end, + cKey = function(k) return '|cFF'..cTypes.field .. tostring(k) .. '|r' end, + cPink = function(s) return '|cFF'..cTypes.hl .. tostring(s) .. '|r' end, + cBool = function(s) return '|cFF'..cTypes[tostring((not not s))] .. tostring(s) .. '|r' end, +} +for fname, func in pairs(Debuggers) do + _G[fname] = func +end +local cType, cText, cNum, cWord, cKey, cPink, cBool = cType, cText, cNum, cWord, cKey, cPink, cBool +--@end-debug@ + +T.db = {} +T.versionString = GetAddOnMetadata("Turok", "Version") + +function T:OnModuleCreated(mod) + if mod.events then + print('Module', unpack(mod.events)) + end +end +--- RegisterEvent embedded to module tables +function T:RegisterCallback(event, func, ...) + if not T.dispatchQueue[event] then + T.dispatchQueue[event] = {} + end + + if not T.dispatchQueue[event][T.ID] then + T.dispatchQueue[event][T.ID] = T:GetName() + end + + if (type(func) == 'function') then + if type(T[event]) == 'function' then + local oldfunc = T[event] + T[event] = function(...) + oldfunc(...) + return func(...) + end + else + T[event] = func + end + end + --@debug@ + print(cText('Adding listener for'), cKey(self:GetName()), cText('on'), cKey(event))--@end-debug@ +end + +--- Default settings base +T.defaults = { + char = {}, + + lefttext = { + parent = 2, -- in an overlay frame + anchor = 'LEFT', + anchorTo = 'LEFT', + size = 18, + x = 5, y = 0, + justifyH = 'LEFT', + justifyV = 'MIDDLE', + }, + + righttext = { + parent = 2, -- in an overlay frame + anchor = 'RIGHT', + anchorTo = 'RIGHT', + x = -5, + y = 0, + size = 18, + justifyH = 'RIGHT', + justifyV = 'MIDDLE', + }, + + alpha = 1, + alpha_ooc = 1, + alpha_fade_in = 0.2, + alpha_fade_out = 0.2, + border_color = {0,0,0,1}, + + background_color = {0,.0,0,1}, + background_blend = 'BLEND', + + foreground_texture = [[Interface\Addons\Turok\Media\statusbar\Minimalist.tga]], + foreground_color = {0,.475,.95,1}, + foreground_blend = 'BLEND', + + foreground_inset = 0, + padding = 2, + spacing = 0, + fill_direction = 'RIGHT', + + anchor = 'CENTER', parent = 'UIParent', anchorTo = 'CENTER', + x = 0, y = 0, + inset = -3, + width = 250, + height = 100, + strata = 'LOW', + font = "Interface\\Addons\\Turok\\Media\\font\\ArchivoNarrow-Regular.ttf", + size = 14, + text_color = {1, 1, 1, 1}, + justifyH = 'LEFT', + outline = 'OUTLINE', + combatFade = true, + + battle_noise_start = [[Interface\Addons\Turok\Media\sound\Low_Beep-Public_D-136_hifi.mp3]], + battle_noise_end = [[Interface\Addons\Turok\Media\sound\Electro_-S_Bainbr-7955_hifi.mp3]], +} + + +T.events = { + 'PLAY_MOVIE', + 'PLAYER_TARGET_CHANGED', + 'PLAYER_FOCUS_CHANGED', + 'PLAYER_EQUIPMENT_CHANGED', + 'PLAYER_REGEN_DISABLED', + 'PLAYER_REGEN_ENABLED', + 'SPELL_UDPATE_COOLDOWN', + 'SPELL_UPDATE_USABLE', + 'UNIT_AURA', + 'UNIT_PET', + 'UNIT_POWER_FREQUENT', + 'UNIT_SPELL_HASTE', + 'UNIT_SPELLCAST_SENT', + 'UNIT_SPELLCAST_START', + 'UNIT_SPELLCAST_DELAYED', + 'UNIT_SPELLCAST_STOP', + 'UNIT_SPELLCAST_CHANNEL_START', + 'UNIT_SPELLCAST_CHANNEL_UPDATE', + 'UNIT_SPELLCAST_CHANNEL_STOP', + 'UNIT_SPELLCAST_FAILED', + 'UNIT_SPELLCAST_INTERRUPTED', + 'UNIT_SPELLCAST_INTERRUPTIBLE', + 'UNIT_SPELLCAST_SUCCEEDED', + 'UNIT_SPELLCAST_UNINTERRUPTIBLE', +} +T.previousSpec = {} +T.talents = { {}, {}} +T.changedTalents = {{}, {} } +T.talentInfo = {} +T.auras = {} +T.spells = {} +T.spellevent = {} +T.channeling = {} +T.casting = {} +T.sent = {} +T.prototype = {} +T.spellBook = {} +T.equipped = {} + +--- player-restricted unit info and text representations +T.player = {} +T.playertext = {} +T.pet = {} + +--- holds non-restricted unit information +T.unit = { + player = {}, + target = {}, + focus = {}, + pet = {}, +} + +-- index of frames with conditional visual properties +T.control_regions = {} + +-- index of frames generated by the lua +T.frames = {} + +-- units +T.units = {} +T.unitsBySlot = {} +setmetatable(T.unitsBySlot, {__mode="v"}) + + + +T.TrueVal = function (self,k) + return rawget(self,k) +end +--- Sets an index hierarchy for db vars and propagates config dialog info +T.LinkTable = function (over, under, pname, cname) + local mt = { + __index = function(t,k) + if type(over[k]) ~= nil then + --t[k] = over[k] + --@debug@ + --print('up-referencing '.. STACK_COLOR2 .. pname ..'|r.'.. STACK_COLOR3.. tostring(k)..'|r -> '.. STACK_COLOR3.. pname ..'.' .. cname .. '|r.'..STACK_COLORN.. tostring(k) ..'|r', over[k])--@end-debug@ + end + return over[k] + end, + __newindex = function (t, k, v) + rawset(t,k,v) + if type(v) == 'table' then + --@debug@ + --print('parenting '.. STACK_COLOR2.. pname ..'|r to created table '.. STACK_COLOR3.. cname ..'|r')--@end-debug@ + T.LinkTable(under, v, pname, k) + end + end + } + --under.TrueVal = T.TrueVal + setmetatable(under, mt) + for k, v in pairs(under) do + if type(v) == 'table' then + --@debug@ + --print('linking '..STACK_COLOR1.. pname ..'|r to '..STACK_COLOR2.. cname ..'|r')--@end-debug@ + T.LinkTable(under, v, pname ..'.'.. cname, k) + end + end +end + + +--- Merges values of table B into table A, and copies over nested values of tables matching the keywords list +local masked = {name = true, virtual = true} +T.Config_Push = function(cvars, push , root, rkey) + local results = {} + root = root or cvars + for k, v in pairs(push) do + if not masked[k] then + if type(v) == 'table' and v ~= root then + cvars[k] = {} + T.Config_Push(cvars[k], v, root) + else + print(' |cFFFF0088B|r ', tostring(rkey)..'.'..cKey(k)) + cvars[k] = v + tinsert(results, ' |cFFFF0088B|r '.. tostring(rkey)..'.'..cKey(k)) + end + end + end + return cvars, results +end +T.Config_Merge = function(cvars, merge, root, rkey) + local diff = {} + root = root or cvars + rkey = rkey or '0' + for k, v in pairs(merge) do + if masked[k] or cvars[k] then + tinsert(diff, ' |cFF00FF00A|r '.. tostring(rkey)..'.'..cWord(k)) + print(' |cFF00FF00A|r ', tostring(rkey)..'.'..cText(k), '=', cvars[k]) + --cvars[k] = cvars[k] + else + if type(v) == 'table' then + if type(cvars[k]) == 'nil' then + cvars[k] = {} + end + if type(cvars[k]) == 'table' then + print(' |cFFFFFF00A+B|r '.. tostring(rkey)..'.'..cWord(k)) + cvars[k] = T.Config_Merge(cvars[k], v, root, tostring(rkey)..'.'..tostring(k)) + end + elseif cvars[k] == nil then + tinsert(diff, ' |cFFFF0088B|r '.. tostring(rkey)..'.'..cKey(k)) + print(' |cFFFF0088B|r ', tostring(rkey)..'.'..cKey(k)) + cvars[k] = v + else + tinsert(diff, ' |cFF00FF00A|r '.. tostring(rkey)..'.'..cWord(k)) + print(' |cFF00FF00A|r ', tostring(rkey)..'.'..cWord(k)) + --cvars[k] = cvars[k] + end + end + end + return cvars, diff +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Layout/Dialog.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,186 @@ +--- Dialog Generator +-- @file-author@ +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +-- Created: 1/1/2016 3:37 PM +--- Framescript template for generating intelligible dialog panels +--[[ +-- Frame << TkListFrame +-- { +-- Frame <rows> << TkListItem <-- Any number of list item frames with parentArray="rows" +-- { + :GetRow(row, values, id, offset) <-- Populates the uiobjects that make up the given row, with data from values[id], on display row offset + <opts> <-- Any layered region of child frame with parentArray=opts" + } + Button <buttons> <-- Any frame with parentArray="buttons" + + .Click (button, list) <-- Defines results of using a control button + .Check (button, row, list) <-- Defines results of operating a row widget + .Wheel (list, delta) <-- Defines response to mousewheel action over the list panel + } + + Globals: + TkList_Init ( object, values, offset, numRows ) + Takes the return from CreateFrame and a table of values and establishes a scrollable list interface. + + TkPanel_Init ( object ) + TkList_Init without the scrollable list operations. Lines up control buttons and nothing else. +--]] +local TK_LIST_SPACING = 1 +local TK_LIST_PADDING = 3 +local TK_LIST_HEADING_SIZE = 26 +local TK_LIST_ITEM_HEIGHT = 24 +local TK_LIST_DISPLAY_ITEMS = 10 + +local print = function(...) + if _G.Devian and _G.DevianDB.workspace ~= 1 then + _G.print('Xui', ...) + end +end +-- GLOBALS: TkList_SetView, TkList_Init, Turok +local type, error, pairs, ipairs, tonumber, max, CreateFrame = type, error, pairs, ipairs, tonumber, math.max, CreateFrame +local checkval = function(valtype, t, fallback) + return (type(t) == valtype) and t or (fallback or error('Expected table reference, got '..type(t))) +end +local tableval = function(t, fallback) + return checkval('table', t, fallback or {}) +end +local funcval = function(f, fallback) + return checkval('function', f, fallback or function() end) +end + +--- Orders list row +-- Does an ipairs iteration over self.opts and distributes the referenced objects along the horizontal axis of 'self' +-- Note that members are only aligned horizontally; no column alignment is done. Widths can be set by datafunc to accomplish that. +local function TkListItem_Init (listrow) + if not listrow.opts then + print('no options to enumerate') + return + end + local rwidth = TK_LIST_PADDING*2 + for i, z in pairs(listrow.opts) do + if i > 1 then + z:SetPoint('LEFT', listrow.opts[i-1], 'RIGHT', TK_LIST_SPACING, 0) + else + z:SetPoint('LEFT', listrow, 'LEFT', TK_LIST_PADDING, 0) + end + rwidth = rwidth + z:GetWidth()+TK_LIST_SPACING + z:Show() + end + listrow:SetSize(rwidth-TK_LIST_PADDING*2,TK_LIST_ITEM_HEIGHT) + listrow:Show() + print(rwidth) + return rwidth +end + + +--- +local function TkControls_Init(self) + local buttonsize = (self._dwidth - (#self.buttons -1) * TK_LIST_SPACING - TK_LIST_PADDING*2) / #self.buttons + for n, b in ipairs(self.buttons) do + --print('Spirit', buttonsize) + b:SetWidth(buttonsize) + b:SetPoint('TOPLEFT', self, 'BOTTOMLEFT', buttonsize* (n-1) + TK_LIST_SPACING * (n-1) + TK_LIST_PADDING, -TK_LIST_PADDING) + end + self.controls:SetHeight(self.buttons[1]:GetHeight()+ TK_LIST_PADDING*2) +end + +--- Populates the list frame with items +function TkList_SetView(self, start_num, num_rows) + print(self, start_num, num_rows) + if not start_num then + start_num = self.offset + end + + if not num_rows then + num_rows = self.num_rows + end + + if start_num > #self.info then + start_num = #self.info - #self.info % num_rows + elseif start_num < 1 then + start_num = 1 + end + + print(' ', self:GetName(), start_num, num_rows, #self.info) + self.offset = start_num + + for draw_num = 1, num_rows do + local actual_row = draw_num + start_num - 1 + if not self.rows[draw_num] then + self.rows[draw_num] = CreateFrame('Frame', self:GetName()..'_Option_'..draw_num, self, 'TurokListItem') + self.rows[draw_num]:SetHeight(TK_LIST_ITEM_HEIGHT) + self.rows[draw_num].row_num = draw_num + end + self.rows[draw_num].actual_row = actual_row + local row = self.rows[draw_num] + if self.info[actual_row] then + print( actual_row, draw_num) + self.GetRow(row, self.info, actual_row, draw_num) + row:Show() + else + print('|cFF888888'..actual_row, draw_num) + row:Hide() + end + row:SetParent(self) + end +end + +--- Prime TkListFrame template-spawn for use +-- @param self frame object to list-ify +-- @param info array of list item values +-- @param datafunc function that takes 1) frame object 2) info table 3) index number 4) row number +-- @param offset starting offset for initial view +function TkList_Init (self, info, offset, num_rows) + -- error checking + --[[if type(info) ~= 'table' then + error('arg #2 info must be an associative array') + end + if type(datafunc) ~= 'function' then + error('arg #3 needs a funcref or method name from the frame object') + end + --]] + self.GetRow = funcval(self.GetRow, function() end) + self.info = tableval(info, {}) + for i, v in ipairs(info) do + print('Main', i, '=', v.spellName, v.spellTab) + self.max_row = i + end + print('Main', 'last row #', self.max_row) + + + -- obtain data contents + self._dwidth = 0 + self.rows = {} + self.offset = offset and offset or 1 + self.num_rows = (tonumber(num_rows) ~= nil) and num_rows or TK_LIST_DISPLAY_ITEMS + self.name:SetHeight(TK_LIST_HEADING_SIZE) + TkList_SetView(self, offset) + + -- sort out the proper width + local rwidth = 1 + local k = 0 + for n, item in ipairs(self.rows) do + print(item:GetName()) + if item:IsShown() then + if n > 1 then + item:SetPoint('TOPLEFT', self.rows[n-1], 'BOTTOMLEFT', 0, - TK_LIST_SPACING) + else + item:SetPoint('TOPLEFT', self, 'TOPLEFT', TK_LIST_PADDING, -(TK_LIST_PADDING+TK_LIST_HEADING_SIZE+TK_LIST_SPACING)) + end + k = k+1 + self._dwidth = max(self._dwidth, TkListItem_Init(item)) + end + end + + TkControls_Init(self) + + self:SetSize(self._dwidth , (k*TK_LIST_ITEM_HEIGHT)+(TK_LIST_PADDING*2)+(k*TK_LIST_SPACING)+TK_LIST_HEADING_SIZE) +end + +--- Set up for a non-list-style panel, no iterative controls +function TkPanel_Init(self) + self._dwidth = self:GetWidth() + TkControls_Init(self) + --self:SetSize(self._dwidth , (k*TK_LIST_ITEM_HEIGHT)+(TK_LIST_PADDING*2)+(k*TK_LIST_SPACING)+TK_LIST_HEADING_SIZE) +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Layout/Dialog.xml Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,462 @@ +<Ui> + <!-- Visual element structures for configuration interfaces --> + <Script file="Dialog.lua" /> + <Font name="TkDialogFieldFont" font="Interface\Addons\Turok\Media\font\ArchivoNarrow-Bold.ttf" outline="NORMAL"> + <Color r="1" g="1" b="1" a="1" /> + <FontHeight> + <AbsValue val="13"/> + </FontHeight> + </Font> + + + <Button name="TurokButton" virtual="true" parentArray="buttons" enableMouse="true"> + <Scripts> + <OnShow> + self:RegisterForClicks("LeftButtonUp") + self.bname:SetText(self:GetName():match("_(%a+)$")) + </OnShow> + <OnClick> + self:GetParent().Click(self, self:GetParent()) + </OnClick> + </Scripts> + <NormalTexture setAllPoints="true"> + <Color r="0" g="0" b="0" a="1" /> + </NormalTexture> + <PushedTexture setAllPoints="true" alphaMode="ADD"> + <Color r="1" g="0.5" b="0" a="1" /> + </PushedTexture> + <HighlightTexture setAllPoints="true" alphaMode="ADD"> + <Color r="0.5" g="0.1" b=".4" a="1" /> + </HighlightTexture> + <DisabledTexture setAllPoints="true"> + <Color r="0.4" g="0.4" b="0.4" a="1" /> + </DisabledTexture> + <Size x="100" y="20" /> + <Layers> + <Layer level="BACKDROP"> + </Layer> + <Layer level="OVERLAY"> + <FontString inherits="TurokFont" parentKey="bname" justifyH="CENTER" justifyV="MIDDLE" setAllPoints="true" text="Foo" /> + </Layer> + <Layer level="HIGHLIGHT"> + </Layer> + </Layers> + </Button> + + <Frame name="TurokDialogMenu" parent="UIParent" enableMouse="true" hidden="true"> + <Size x="200" y="200" /> + <Anchors> + <Anchor point="TOPLEFT" /> + </Anchors> + <Layers> + <Layer level="BACKGROUND"> + <Texture setAllPoints="true"> + <Color r="0" g="0" b="0" a="0.2" /> + </Texture> + </Layer> + </Layers> + </Frame> + + <CheckButton name="TurokCheckButton" virtual="true" enableMouse="true"> + <Scripts> + <OnClick> + if self:GetParent().Check then + self:GetParent().Check(self, self:GetParent()) + else + self:GetParent():GetParent().Check(self, self:GetParent(), self:GetParent():GetParent()) + end + </OnClick> + </Scripts> + <NormalTexture> + <Color r="0.3" g="0.05" b="0.6" a="1" /> + <Size x="16" y="16" /> + <Anchors> + <Anchor point="TOPLEFT" x="2" y="-2" /> + </Anchors> + </NormalTexture> + <PushedTexture> + <Color r="0" g="0" b="0" a="1" /> + <Size x="16" y="16" /> + <Anchors> + <Anchor point="TOPLEFT" x="2" y="-2" /> + </Anchors> + </PushedTexture> + <HighlightTexture> + <Color r="1" g="0" b="0" a="0.1" /> + <Size x="16" y="16" /> + <Anchors> + <Anchor point="TOPLEFT" x="2" y="-2" /> + </Anchors> + </HighlightTexture> + <CheckedTexture> + <Color r="1" g="1" b="0.5" a="1" /> + <Size x="16" y="16" /> + <Anchors> + <Anchor point="TOPLEFT" x="2" y="-2" /> + </Anchors> + </CheckedTexture> + + <DisabledCheckedTexture> + <Color r="0.7" g=".7" b=".7" a="1" /> + <Size x="18" y="18" /> + <Anchor point="TOPLEFT" /> + </DisabledCheckedTexture> + </CheckButton> + + <CheckButton name="TurokCheckButtonInline" inherits="TurokCheckButton" virtual="true" enableMouse="true"> + <Size x="20" y="20" /> + <Layers> + <Layer level="BORDER"> + <Texture name="$parentBorder"> + <Anchors> + <Anchor point="TOPLEFT" x="1" y="-1" /> + <Anchor point="BOTTOMRIGHT" x="-1" y="1" /> + </Anchors> + <Size x="18" y="18" /> + <Color r="1" g="1" b="1" a="1" /> + <Gradient> + <MinColor r="1" g="0" b=".5" a="1" /> + <MaxColor r="0.5" g="0.9" b="1" a="1" /> + </Gradient> + </Texture> + </Layer> + <Layer level="OVERLAY"> + <FontString name="$parentDescText" inherits="TurokFontDetail" justifyH="LEFT" parentKey="description" text="Inline CheckButton"> + <Anchors> + <Anchor point="TOPLEFT" relativePoint="TOPRIGHT" x="4" y="-3" /> + </Anchors> + </FontString> + </Layer> + </Layers> + </CheckButton> + + <!-- CheckButton designed to collapse on top of an EditBox --> + <CheckButton name="TurokCheckButtonOverlay" inherits="TurokCheckButton" virtual="true" enableMouse="true" frameStrata="HIGH"> + <Size x="20" y="48" /> + <Layers> + <Layer level="BORDER"> + <Texture name="$parentBorder"> + <Size x="18" y="18" /> + <Anchors> + <Anchor point="TOPLEFT" x="1" y="-1" /> + </Anchors> + <Color r="1" g="1" b="1" a="1" /> + <Gradient> + <MinColor r="1" g="0" b=".5" a="1" /> + <MaxColor r="0.5" g="0.9" b="1" a="1" /> + </Gradient> + </Texture> + </Layer> + <Layer level="OVERLAY"> + <FontString name="$parentDescText" inherits="TurokFontDetail" justifyH="LEFT" parentKey="description" text="Overlay CheckButton"> + <Anchors> + <Anchor point="TOPLEFT" relativePoint="TOPRIGHT" x="4" y="-3" /> + </Anchors> + </FontString> + </Layer> + </Layers> + </CheckButton> + + <Frame name="TurokDialogFrame" parent="UIParent" enableMouse="true" hidden="true" movable="true" virtual="true" toplevel="true" mouseWheel="true"> + <Scripts> + <OnShow> + for i, g in pairs({self:GetChildren()}) do + g:Show() + end + self:RegisterForDrag("LeftButton") + </OnShow> + <OnDragStart> + self:StartMoving() + </OnDragStart> + <OnDragStop> + self:StopMovingOrSizing() + </OnDragStop> + <OnMouseWheel> + self:Wheel(delta) + </OnMouseWheel> + </Scripts> + <Anchors> + <Anchor point="CENTER" /> + </Anchors> + <Size x="300" y="200" /> + <Layers> + <Layer level="BACKGROUND"> + <Texture setAllPoints="true" blendMode="ADD"> + <Color r="1" b="1" g="1" a="1" /> + <Gradient orientation="HORIZONTAL"> + <MinColor r="1" g="0" b="0.5" a="0.5" /> + <MaxColor r="1" g=".5" b="0" a="0.5" /> + </Gradient> + </Texture> + <Texture blendMode="ADD" parentKey="controls"> + <Anchors> + <Anchor point="TOPLEFT" relativePoint="BOTTOMLEFT" /> + <Anchor point="TOPRIGHT" relativePoint="BOTTOMRIGHT" /> + </Anchors> + <Color r="1" b="1" g="1" a="1" /> + <Gradient orientation="HORIZONTAL"> + <MinColor r=".4" g=".4" b="1" a="1" /> + <MaxColor r="1" g="0" b=".5" a="1" /> + </Gradient> + </Texture> + </Layer> + <Layer level="BORDER"> + <Texture blendMode="BLEND"> + <Color r="0" g="0" b="0" a="1" /> + <Anchors> + <Anchor point="TOPLEFT" /> + <Anchor point="BOTTOMRIGHT" relativePoint="TOPRIGHT" x="0" y="-25" /> + </Anchors> + </Texture> + </Layer> + <Layer level="OVERLAY"> + <FontString name="$parentTitle" parentKey="name" inherits="TurokFont" justifyV="TOP" justifyH="LEFT" text="Set Title!"> + <Color r="1" g="1" b="1" a="1" /> + <Anchors> + <Anchor point="TOPLEFT" x="5" y="-5" /> + </Anchors> + <Size x="200" y="40" /> + </FontString> + <FontString name="$parentTitle" parentKey="pagenum" inherits="TurokFont" justifyV="TOP" justifyH="RIGHT"> + <Color r="1" g="1" b="1" a="1" /> + <Anchors> + <Anchor point="TOPRIGHT" x="-25" y="-5" /> + </Anchors> + </FontString> + </Layer> + </Layers> + <Frames> + + <Button name="$parentButton_Close" inherits="UIPanelCloseButton"> + <Size x="30" y="30" /> + <Anchors> + <Anchor point="TOPRIGHT" x="3" y="3" /> + </Anchors> + </Button> + </Frames> + </Frame> + + <!-- LIST FRAME OVERHEAD --> + <Frame name="TurokListFrame" inherits="TurokDialogFrame" virtual="true"> + <Frames> + <Button name="$parentButton_Prev" inherits="TurokButton" /> + <Button name="$parentButton_Add" inherits="TurokButton" /> + <Button name="$parentButton_Next" inherits="TurokButton" /> + </Frames> + </Frame> + + <!-- LIST FRAME ROW --> + <Frame name="TurokListItem" parent="UIParent" parentArray="tabs" enableMouse="true" hidden="true" virtual="true"> + <Scripts> + <OnEnter> + GameTooltip:SetOwner(self, "ANCHOR_LEFT"); + if self.spellID then + GameTooltip:SetSpellByID(self.spellID); + else + GameTooltip:SetText(self.desc) + end + GameTooltip:Show(); + </OnEnter> + <OnLeave function="GameTooltip_Hide"/> + </Scripts> + <Size x="300" y="30" /> + <Layers> + <Layer level="BACKGROUND"> + <Texture parentKey="background" name="$parentTab" blendMode="BLEND"> + <Size x="50" y="21" /> + <Color r="0" g="0" b="0" a=".3" /> + <Anchors> + <Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parentTab" /> + </Anchors> + </Texture> + </Layer> + <Layer level="HIGHLIGHT"> + <Texture name="$parent_Highlight" parentKey="highlight" selAllPoints="true" blendMode="ADD"> + <Color r="1" g="1" b="1" a=".25" /> + </Texture> + </Layer> + + <Layer level="OVERLAY"> + </Layer> + </Layers> + </Frame> + + <Frame name="TkWidgetScripts" virtual="true"> + <Scripts> + <OnValueChanged> + if self.value then + self.value:SetText(tostring(math.floor(value))) + self.value:SetPoint('LEFT', self:GetThumbTexture(), 'LEFT', 1, 0) + end + </OnValueChanged> + </Scripts> + </Frame> + + <Slider name="TkSlider" orientation="HORIZONTAL" enableMouse="true" + parentArray="_scroller" + minValue="0" maxValue="800" valueStep="4" stepsPerPage="3" defaultValue="400" inherits="TkWidgetScripts" virtual="true"> + <HitRectInsets left="0" right="0" bottom="0" top="0" /> + <Anchors><Anchor point="CENTER" /></Anchors> + <Size x="350" y="30" /> + <ThumbTexture parentKey="thumb" name="$parentThumb"> + <Color r="1" g=".45" b="0" a="1" /> + <Size x="30" y="30" /> + <Anchors> + <Anchor point="BOTTOM" /> + </Anchors> + </ThumbTexture> + <Layers> + <Layer level="BACKGROUND"> + <Texture parentKey="background"> + <Color r="0" g="0" b="0" a="0.5" /> + <Anchors> + <Anchor point="TOPLEFT" x="0" y="-16" /> + <Anchor point="BOTTOMRIGHT" x="0" y="0" /> + </Anchors> + </Texture> + </Layer> + <Layer level="OVERLAY"> + <FontString parentKey="value" inherits="TurokFontDetail" /> + <FontString parentkey="name" inherits="TurokFont"> + <Anchors> + <Anchor point="TOPLEFT" relativePoint="TOPLEFT" /> + </Anchors> + </FontString> + </Layer> + <Layer level="HIGHLIGHT"> + + <Texture alphaMode="MOD"> + <Anchors> + <Anchor point="TOPLEFT" x="0" y="-16" /> + <Anchor point="BOTTOMRIGHT" x="0" y="0" /> + </Anchors> + <Color r="0.5" b="0.5" g="0.5" a="0.25" /> + </Texture> + </Layer> + </Layers> + </Slider> + + + <EditBox name="TkEditBox" font="TurokFont" inherits="TkWidgetScripts" virtual="true" + historyLines="3" + autoFocus="false" + parentArray="_inputs"> + <Backdrop bgFile="Interface\Addons\Turok\Media\border\BG-Solid.blp" edgeFile="Interface\Addons\Turok\Media\border\BigBorder-Solid.blp" tile="true"> + <EdgeSize val="12"/> + <TileSize val="12"/> + <BorderColor r="0" g="0" b="0" a="1" /> + <Color r="1" g="1" b="1" a="1" /> + <BackgroundInsets> + <AbsInset left="3" right="3" top="3" bottom="3"/> + </BackgroundInsets> + </Backdrop> + <Scripts> + <OnEscapePressed> + self:ClearFocus() + </OnEscapePressed> + <OnEnterPressed> + self:ClearFocus() + </OnEnterPressed> + <OnEditFocusGained> + print(self:GetName(),'gained focus') + self.__bg = {self.background:GetTexture()} + self.background:SetTexture(0,0,0,1) + </OnEditFocusGained> + <OnEditFocusLost> + print(self:GetName(),'lost focus') + self:GetParent():GetParent().EditBox(self) + self.background:SetTexture(unpack(self.__bg)) + self.__bg = nil + </OnEditFocusLost> + </Scripts> + <Size x="350" y="48" /> + <TextInsets> + <AbsInset left="4" top="22" right="4" bottom="0" /> + </TextInsets> + <Layers> + <Layer level="BACKGROUND"> + <Texture parentKey="border" alphaMode="MOD"> + <Anchors> + <Anchor point="BOTTOMLEFT" x="3" y="3" /> + <Anchor point="TOPRIGHT" x="-3" y="-3" /> + </Anchors> + <Color r="1" g="1" b="1" a="1" /> + <Gradient orientation="HORIZONTAL"> + <MinColor r="0.4" g="0" b="0.2" a="1" /> + <MaxColor r="1" g="0.35" b="0.15" a="1" /> + </Gradient> + </Texture> + </Layer> + <Layer level="BORDER"> + <Texture parentKey="background"> + <Color r="0" g="0" b="0" a="0.5" /> + <Anchors> + <Anchor point="TOPLEFT" x="3" y="-22" /> + <Anchor point="BOTTOMRIGHT" x="-3" y="3" /> + </Anchors> + </Texture> + </Layer> + <Layer level="OVERLAY"> + <FontString parentkey="description" inherits="TkDialogFieldFont" justifyV="TOP" justifyH="LEFT"> + <Anchors> + <Anchor point="TOPLEFT" relativePoint="TOPLEFT" x="5" y="-6" /> + </Anchors> + </FontString> + </Layer> + </Layers> + </EditBox> + + + <Button name="TurokDDButton" inherits="TurokButton" parent="UIParent" enableMouse="true" virtual="true"> + <NormalTexture setAllPoints="true"> + <Color r=".35" g="0" b=".7" a="1" /> + </NormalTexture> + </Button> + + <Frame name="TurokDialogRow" enableMouse="true" hidden="true" movable="true" virtual="true" toplevel="true" mouseWheel="true"> + <Size x="200" y="42" /> + </Frame> + + <!-- TIMER EDIT FRAME --> + <Frame name="TkTimerConfig" parent="UIParent" hidden="true" inherits="TurokDialogFrame"> + <Scripts> + <OnLoad> + self.Wheel = function(self, delta) print(self:GetName(), 'wheel stuff') + if self._scroller then + for i, region in ipairs(self._scroller) do + if region:IsMouseOver() then + print(self:GetName(),'hit #', i, region:GetName()) + region:SetValue(region:GetValue()+delta) + end + end + else + print(self:GetName(),'no scrollwheel regions') + end + end + + print('uhmmm', type(self)) + LibStub("LibFog-1.0").SetAnimationGroup(self) + -- Turok stuff + </OnLoad> + <OnShow> + TkPanel_Init(self) + self:RegisterForDrag("LeftButton") + self.name:SetText(self.timerName) + self.pagenum:SetText(self.timerID) + self:SetAlpha(0) + self:Fade(0.2, 1) + </OnShow> + </Scripts> + <Size x="400" y="300" /> + <Anchors> + <Anchor point="CENTER" /> + </Anchors> + <Frames> + + + <Button name="$parentButton_Spells" inherits="TurokButton" /> + <Button name="$parentButton_Move" inherits="TurokButton" /> + <Button name="$parentButton_Delete" inherits="TurokButton" /> + </Frames> + </Frame> +</Ui> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Layout/Layout.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,725 @@ +--- LibFog-1.0 +-- In-house solution to processing frame configuration data. +--[[ +-- + Config Table fields: + + background .. _color, _texture, _blend properties of the texture referenced by frame.background + foregound .. " " " properties of the texture referenced by frame.foreground + backdrop arguments for SetBackdrop + border_color sets the border color on an existing frame backdrop + alpha, alpha_ooc uiobject alpha for in and out of combat + combat_fade true to change alpha levels based on combat + fade_time, fade_in, fade_out fade_time = fade_in or fade_out + + anchor, parent, anchorTo, x, y args for UIObject:SetPoint() + height, width args for Region:SetSize() + strata, layer, level override the strata, draw layer, and draw level where they apply + + padding space between frame and background edge + foreground_inset space between background and foreground edge + spacing space between segmented foreground elements (e.g. combo points) + + font, size, outline args for FontString:SetFont() respectively + justifyV, justifyH LEFT/CENTER/RIGHT, TOP/MIDDLE/BOTTOM + + SetFrameLayout(): + Applies: + anchor, parent, anchorTo, x, y + width, height, + padding, spacing, foreground_inset + backdrop, border_color, background_color + alpha, alpha_ooc + + SetStatusTextures(): + Applies: + foreground_texture, foreground_color, foreground_blend + background_texture, background_color, background_blend + + Defines: + fill_direction, fill_width, fill_height, fill_inset + :TranslateX(progress) + :TranslateY(progress) + :SetFillPoints() + + SetFontLayout(): + Applies: + anchor, parent, anchorTo, x, y + width, height + font, size, outline + justifyH, justifyV + + - + ]] +local MAJOR, MINOR = "LibFog-1.0", 1 +local F, oldminor = LibStub:NewLibrary(MAJOR, MINOR) +if not F then return end + +local _G, UIParent, type, unpack, pairs, ipairs, min, abs, tostring, print = _G, UIParent, type, unpack, pairs, ipairs, math.min, math.abs, tostring, print +local InCombatLockdown, GetTime, PlaySoundKitID, CreateFrame = InCombatLockdown, GetTime, PlaySoundKitID, CreateFrame +local tinsert, wipe, concat = table.insert, table.wipe, table.concat +local FADE_OUT_TIME, FADE_IN_TIME = 1, 0.4 + +--@debug@ +local cType, cText, cNum, cWord, cKey, cPink, cBool = cType, cText, cNum, cWord, cKey, cPink, cBool +local ADDON, scriptargs = ... +scriptargs.LibFog = F +local print = function(...) + if _G.Devian and _G.DevianDB.workspace ~= 1 then + _G.print('Layout', ...) + end +end +--- debug highlighters +local namef = function(s) return '|cFFFFFF00' ..tostring(s).. '|r' end -- uiobject targeted function +local namet = function(s) return '|cFFFF4400 '..tostring(s).. '|r' end -- region targeted function +local valuef = function(s) return '|cFF88FF88'..(s ~= nil and ('"'..tostring(s)..'"') or ('nil'))..'|r' end -- uiobject name +local valuet = function(s) return '|cFFAACCAA'..(s ~= nil and ('"'..tostring(s)..'"') or ('nil'))..'|r' end -- string value +local valuen = function(s) return '|cFFAADD77' ..(s ~= nil and ('"'..tostring(s)..'"') or ('nil')).. '|r' end -- string enumeration +local valued = function(s) return '|cFFFFFFFF' ..(s ~= nil and ('"'..tostring(s)..'"') or ('nil')).. '|r' end -- number +--@end-debug@ +local GetPrint = function(trace) + if trace then + return print + else + return function() end + end +end + +--- Layout control metadata +local lastdb -- fallback if a table isn't found mid-operation +local ui_meta = { + beepkit = 15263, -- something to play when debugging +} +local ui_embeds = { + ['Frame'] = 'SetFrameLayout', + ['Texture'] = 'SetTextureLayout', + ['Font'] = 'SetFontLayout', +} + +--- Resolve a parent object from varying depths +-- @param self target object +-- @parent string/number name of global frame or number of GetParent() hops to make +-- @childKey index key to retrieve from the resolved parent object +local function ParentValue(self, parent, childKey) + local print = GetPrint(self.trace) + + local relativeTo = parent + if type(parent) == 'number' then + print(cWord('* Parent Trace:'), cNum(parent), cKey(self:GetName())) + relativeTo = self:GetParent() + for i = 2, parent do + if relativeTo.GetParent and relativeTo:GetParent() ~= UIParent then + --@debug@ + print(' ', 'parent =', relativeTo:GetName()) + --@end-debug + local next = relativeTo:GetParent() + relativeTo = next + else + --@debug@ + print(' ',cWord(self:GetName()), 'parent =', cWord(parent)) + --@debug-end@ + end + end + end + + -- This allows us to call for an immediate sub-frame and still get a usable value if it's not there + if childKey and relativeTo[childKey] then + return relativeTo[childKey] + end + return relativeTo +end + +--- Animations +F.animate_regions = {} +setmetatable(F.animate_regions, { + __newindex = function (t,k,v) + rawset(t,k,v) + v.animationID = k + F.SetAnimationGroup(v) + end +}) + +--- Constructs the generic status frame +function F:SetFrameLayout(c) + local print = GetPrint(c.trace) + self.trace = c.trace or self.trace + + self.db = c + self.labels = {} + + self.name = self:GetName() + self.combat = InCombatLockdown() + self:SetPoint(c.anchor, c.parent, c.anchorTo, c.x, c.y) + self:SetSize(c.width, c.height) + self:SetFrameStrata(c.strata) + self.throttle_rate = 0.010 + self.throttle_point = GetTime() + + if c.backdrop then + c.backdrop.edgeSize = c.padding*4 + self:SetBackdrop(c.backdrop) + end + if c.background_color and c.border_color then + self:SetBackdropColor(unpack(c.background_color)) + self:SetBackdropBorderColor(unpack(c.border_color)) + end + + --@debug@ + print(namef('SetFrameLayout'),'(', valuet(self:GetName()),')') + print(cText(' dimensions:'), cNum(c.width), 'by', cNum(c.height), '::', c.x, c.y, c.anchor, c.anchorTo, c.parent) + --@end-debug@ + + self.width = c.width + self.height = c.height + self.foreground_inset = c.foreground_inset + self.padding = c.padding + self.spacing = c.spacing + self.alpha = c.alpha + + self.combatFade = c.combatFade + self.alpha_fade_in = c.alpha_fade_in or c.alpha_fade + self.alpha_fade_out = c.alpha_fade_out or c.alpha_fade + print(' fade on combat =', self.combatFade) + for _, type in ipairs({'alpha', 'alpha_ooc'}) do + self[type] = c[type] + _G.print('DB', self:GetName(), type, self[type]) + for _, subtype in ipairs({'_passive', '_active'}) do + self[type..subtype] = c[type..subtype] or self[type] + _G.print('DB', self:GetName(), type..subtype, self[type..subtype]) + for _, subsubtype in ipairs({'_empty', '_half', '_full'}) do + self[type..subtype..subsubtype] = c[type..subtype..subsubtype] or self[type..subtype] + _G.print('DB', self:GetName(), type..subtype..subsubtype, self[type..subtype..subsubtype]) + self[type..subsubtype] = c[type..subsubtype] or self[type..subtype] + _G.print('DB', self:GetName(), type..subsubtype, self[type..subsubtype]) + end + end + end + self.UpdateAlpha = F.UpdateAlpha + --if c.combatFade then + self.faderID = #F.animate_regions+1 + F.animate_regions[#F.animate_regions+1] = self + print(cText(' animation target ID #'), cNum(self.faderID)) + --end + + self:UpdateAlpha(InCombatLockdown()) + + if self.lefttext then + print(' auto-lefttext') + F.SetFontLayout(self.lefttext, c.lefttext or c) + end + if self.righttext then + print(' auto-righttext') + F.SetFontLayout(self.righttext, c.righttext or c) + end +end + +--- Seeds basic animations, else a template can be specified by the frame data +function F:SetAnimationGroup(group) + local print = GetPrint(self.trace) + + group = group or self.animationClass or nil + --@debug@ + if not group then + print(' |cFFFF44AAseeding debug animations', self:GetName()) + self.__flash = self:CreateAnimationGroup(self:GetName()..'Flasher') + self.__flash:SetToFinalAlpha(true) + local fade1 = self.__flash:CreateAnimation('Alpha') + fade1:SetChange(-1) + fade1:SetDuration(.6) + fade1:SetOrder(1) + local fade2 = self.__flash:CreateAnimation('Alpha') + fade2:SetChange(1) + fade2:SetDuration(.6) + fade2:SetOrder(2) + fade2:SetEndDelay(.6) + --@debug@ + self.__flash.fade1 = fade1 + self.__flash.fade2 = fade2 + self.__flash:SetLooping('NONE') + self.__flash:SetScript('OnFinished', function() + print(self:GetName(), '[>>>] Done animating flash.') + self.flashing = nil + end)--@end-debug@ + self.Flash = F.Flash + + self.__fade = self:CreateAnimationGroup(self:GetName()..'Fader') + self.__fade:SetToFinalAlpha(true) + self.__fade:SetScript('OnFinished', function() + print(self:GetName(), '[>>>] Done animating fade.') + self.fading = nil + local a = self.__flash.fade1:GetToAlpha() + --self:SetAlpha(a) + if a == 0 and not self.__fade.noHide then + self:Hide() + end + if self.__fade.queuedFade then + print('[>>>] ', cWord(self:GetName())..'.'..cKey('__fade:'), 'starting queued fade') + local fadeTo, fadeDuration, noHide = unpack(self.__fade.queuedFade) + self.__fade.queuedFade = nil + self:Fade(fadeTo, fadeDuration, noHide) + end + end) + self.Fade = F.Fade + end + --@end-debug@ + if not self.animationID then + tinsert(F.animate_regions, self) -- uses rawset, so won't death loop + self.animationID = #F.animate_regions + end +end + +function F:Flash(duration, peak, valley, holdUp, holdDown) + local print = GetPrint(self.trace) + + local fl = self.__flash + print('[>>>]', self:GetName(), duration, peak, valley, holdUp, holdDown) + fl.fade1:SetFromAlpha(valley) + fl.fade1:SetToAlpha(peak) + fl.fade1:SetDuration(duration) + fl.fade1:SetEndDelay(holdUp) + fl.fade2:SetFromAlpha(peak) + fl.fade2:SetToAlpha(valley) + fl.fade2:SetDuration(duration) + fl.fade2:SetEndDelay(2) + self.flashing = true + fl:Play() +end + +--- Fade to a value; fading to 0 will hide the frame +function F:Fade(duration, fadeTo, noHide) + + print('|cFFFF6600[>>>]', cText('Fade('), self:GetName(), cText(')')) + local fader = self.__fade + local fade1 = self.__flash.fade1 + if fader:IsPlaying() then + self.__fade.queuedFade = {duration, fadeTo, noHide } + print(' ', cText('playing:'), cNum(fader:GetDuration())..'s', cNum(fade1:GetToAlpha())) + print(' ', cPink('queued {'), cNum(duration)..'s', cNum(self:GetAlpha()), 'to', cNum(fadeTo), '}') + return + else + print(' ', cNum('starting {'), cNum(duration), cNum(self:GetAlpha()), 'to', cNum(fadeTo), '}') + end + fade1:SetParent(fader) + fade1:SetFromAlpha(self:GetAlpha()) + fade1:SetToAlpha(fadeTo) + fade1:SetDuration(duration) + fade1:SetOrder(1) + self.__fade.noHide = noHide + self.fading = true + fader:Play() +end + +function F:Beep() + if self.quiet then + return + end + PlaySoundKitID(F.beepkit) -- random anub'rhekan sounds +end + + +--- Defines the corners used in filling operations +local directionBase = { + ['LEFT'] = 'TOPRIGHT', + ['RIGHT'] = 'TOPLEFT', + ['UP'] = 'BOTTOMLEFT', + ['DOWN'] = 'TOPLEFT' +} +local directionPeak ={ + ['LEFT'] = 'BOTTOMLEFT', + ['RIGHT'] = 'BOTTOMRIGHT', + ['UP'] = 'TOPRIGHT', + ['DOWN'] = 'BOTTOMRIGHT', +} +local directionPeakTo = { + ['LEFT'] = 'BOTTOMRIGHT', + ['RIGHT'] = 'BOTTOMLEFT', + ['UP'] = 'BOTTOMRIGHT', + ['DOWN'] = 'TOPRIGHT' +} +local anchorInverse = {['LEFT'] = 'RIGHT', ['RIGHT'] = 'LEFT', ['TOP'] = 'BOTTOM', ['BOTTOM'] = 'TOP' } +--- Directional coefficients for corner positions +-- [1] = end X, [2] = end Y, [3] = base X, [4] = base Y +local directionCoord = { + ['LEFT'] = {-1, 0, -1, -1}, + ['RIGHT'] = { 1, 0, 1, -1}, + ['UP'] = { 0, 1, 1, 1}, + ['DOWN'] = { 0, -1, 1, -1}, + ['CENTER'] = {.5, .5, 1, 1} +} +local paddingScale = { + ['UP'] = 1, + ['DOWN'] = -1, + ['LEFT'] = -1, + ['RIGHT'] = 1, +} +local embedScale = { + ['LEFT'] = {1, false}, + ['RIGHT'] = {-1, false}, + ['TOP'] = {false, -1}, + ['BOTTOM'] = {false, 1} +} + +--- Determines the correct relative X offset for a given progress ratio +--- x = 0 + padding + spacing + i, where i = {embedded | icon_size +spacing} +-- Factors padding and spacing parameters, including icon embedding dimensions. +-- @param self frame on which the foreground/background textures and config data exist +-- @param ratio progess from 0 to 1; 0 returns the starting corner coordinate, 1 returns end corner +-- @param scale overrides the pixel fill length, with starting corner used as scaling origin +local TranslateX = function(self, ratio, scale) + if not scale then + scale = self.fill_width + end + if self.fill_inverse then + ratio = 1 - ratio + end + _G.print('Update', 'dx', self.fill_x) + local x = + scale * ratio * directionCoord[self.fill_direction][1] + return min(x, scale) + self.fill_x +end + +--- Determines the correct relative Y offset for a given progress ratio +-- Factors padding and spacing parameters, including icon embedding dimensions. +-- @param self frame on which the foreground/background textures and config data exist +-- @param ratio progess from 0 to 1; 0 returns the starting corner coordinate, 1 returns end corner +-- @param scale overrides the pixel fill length, with starting corner used as scaling origin +local TranslateY = function(self, ratio, scale) + if not scale then + scale = self.fill_height + end + if self.fill_inverse then + ratio = 1 - ratio + end + + _G.print('Update', 'dy', self.fill_y) + -- (height of bar offset by the size of any overlapping element) * progress ratio, offset by the size of any overlapping embed + inset + local y = + scale * ratio * directionCoord[self.fill_direction][2] - self.foreground_inset + return min(y, scale) + self.fill_y +end +local SetProgress = function(self, progress, scaleX, scaleY) + _G.print('Update', cText(self:GetName()), + "\n d:", progress, 'dX:', directionCoord[self.fill_direction][1], 'dY:', directionCoord[self.fill_direction][2], 'dI:', self.fill_inverse, + "\n peak:", self.fill_anchor, self.fill_anchorTo, TranslateX(self, progress), TranslateY(self,progress)) + + self.foreground:SetPoint(self.fill_anchor, self.background, self.fill_anchorTo, TranslateX(self, progress, scaleX), TranslateY(self, progress, scaleY)) +end + +--- Assigns textures to the generic foreground background bar regions +-- Called as F.SetStatusTextures(MyFrame, config pointer) +-- foreground_inset - number of pixels by which the foreground edges occlude the background (basically always negative) +-- padding - number of pixels between the background edge and frame edge (basically always positive) +function F:SetStatusTextures(c) + local print = GetPrint(self.trace) + + if c == nil then + c = self.db or lastdb + if not c then + error('No config table found') + end + end + local relativeTo = ParentValue(self, c.parent, c.parentKey) + + + self.fill_direction = c.fill_direction or 'RIGHT' + self.fill_inset = c.padding - c.foreground_inset -- foreground edge / frame edge + self.fill_width = self.width - self.fill_inset*2 -- foreground left / right edges + self.fill_height = self.height - self.fill_inset*2 -- " top / bottom " + self.fill_inverse = c.fill_inverse + self.fill_x, self.fill_y = 0, 0 + self.fill_insets = { + LEFT = self.fill_inset, + TOP = self.fill_inset, + BOTTOM = self.fill_inset, + RIGHT = self.fill_inset + } + + + -- create filling points + self.fill_base = directionBase[self.fill_direction] + self.fill_anchor = directionPeak[self.fill_direction] + self.fill_anchorTo = directionPeakTo[self.fill_direction] + print(" foreground:", self.fill_base, self.fill_base, TranslateX(self, 0), TranslateY(self, 0)) + print(" foreground fill:", self.fill_anchor, self.fill_anchorTo) + + -- calculate icon embed + if self.icon and self.icon.embedded then + print(cText('#### EMBED ####')) + -- change anchor point so the icon is inside + self.icon.anchor = self.icon.anchorTo + print(' * Icon anchor:' , cText(self.icon.anchor), 'to', cText(self.icon.anchorTo)) + print(' * Fill start:', cText(self.fill_base)) + + + local coordSet = {nil, nil} + local baseSet = {nil, nil } + local endSet = {nil, nil} + for dir, coords in pairs(embedScale) do + if self.icon.anchor:match(dir) then + print(' xtrans { matches', dir, 'include {', coords[1], coords[2], '}') + if not coordSet[1] then coordSet[1] = coords[1] end + if not coordSet[2] then coordSet[2] = coords[2] end + + -- the embedding position can overlap either corner + if self.fill_base:match(dir) then + print(' base corner also matches') + if not baseSet[1] then baseSet[1] = coords[1] end + if not baseSet[2] then baseSet[2] = coords[2] end + else + + if not endSet[1] then endSet[1] = coords[1] end + if not endSet[2] then endSet[2] = coords[2] end + end + end + end + + -- make sure there are values if none of them matched at all for some reason + coordSet = {coordSet[1] or 0, coordSet[2] or 0} + baseSet = {baseSet[1] or 0, baseSet[2] or 0 } + -- needs to produce a negative number + endSet = {endSet[1] or 0, endSet[2] or 0 } + + + print(' == xtrans push =', unpack(coordSet)) + print(' == fbase delta =', unpack(baseSet)) + print(' == ftail delta =', unpack(endSet)) + + -- determine the foreground displacement + + self.icon_dx = (min(self.fill_width, self.fill_height) + self.spacing) + self.icon_dy = (min(self.fill_width, self.fill_height) + self.spacing) + print(' * Foreground compression:', cNum(self.icon_dx)) + + self.icon_size = self.icon.size + self.icon_x = self.padding * baseSet[1] - (self.icon.size - self.icon_dx) + self.icon_y = self.padding * baseSet[2] - (self.icon.size - self.icon_dy) + print(' * Icon dims:' , cNum(self.icon_size), ' offset:', cNum(self.icon_dx)) + + + local ofi = self.fill_insets[self.fill_direction] + print(' * Fill inset('..cWord(self.fill_direction)..') from', cNum(ofi), 'to', cNum(self.fill_insets[self.fill_direction])) + + -- used to place the starting corner + self.fill_x = (self.icon_dx) * baseSet[1] + self.fill_y = (self.icon_dy) * baseSet[2] + print(' * fill offset dX:', self.fill_x) + print(' * fill offset dY:', self.fill_y) + + -- amount taken off of fill scale, subtract spacing + self.icon_dx_cut = abs(self.icon_dx * -baseSet[1]) + self.icon_dy_cut = abs(self.icon_dy * -baseSet[2]) + + local ofw, ofh = self.fill_width, self.fill_height + self.fill_width = self.fill_width - self.icon_dx_cut + self.fill_height = self.fill_height - self.icon_dy_cut + print(' * Scale dX:', self.icon_dx_cut, cNum(ofw), 'to', cNum(self.fill_width)) + print(' * Scale dY:', self.icon_dy_cut, cNum(ofh), 'to', cNum(self.fill_height)) + + self.icon:ClearAllPoints() + self.icon:SetPoint(self.icon.anchor, self, self.icon.anchorTo, self.icon_x, self.padding * coordSet[2]) + self.icon:SetSize(self.icon_size, self.icon_size) + end + + --@debug@ + print(namet('SetStatusTextures'),'(', valuef(self:GetName()), ')') + print(' form:', self.padding,'-', self.foreground_inset, '+', self.fill_width, self.padding,'-', self.foreground_inset, '+','x', self.padding,'-', self.foreground_inset, '+', self.fill_height, self.padding,'-', self.foreground_inset, '+') + print(' ', valuen(concat(c.background_color,', ')),valuet(c.background_texture), valuen(concat(c.foreground_color,', ')), valuet(c.foreground_texture)) + print(' background:', self.padding, self.padding, 'BOTTOMLEFT', 'BOTTOMLEFT' , '::', -self.padding, -self.padding, 'TOPRIGHT', 'TOPRIGHT') + --@end-debug@ + + self.background:ClearAllPoints() + self.background:SetPoint('BOTTOMLEFT', self, 'BOTTOMLEFT', self.padding, self.padding) + self.background:SetPoint('TOPRIGHT', self, 'TOPRIGHT', -self.padding, -self.padding) + if c.background_texture ~= '' and c.background_texture ~= nil then + self.background:SetTexture(c.background_texture) + self.background:SetVertexColor(unpack(c.background_color)) + else + self.background:SetTexture(unpack(c.background_color)) + end + self.background:SetBlendMode(c.background_blend) + + if c.foreground_texture ~= '' and c.foreground_texture ~= nil then + self.foreground:SetTexture(c.foreground_texture) + self.foreground:SetVertexColor(unpack(c.foreground_color)) + else + self.foreground:SetTexture(unpack(c.foreground_color)) + end + self.foreground:SetBlendMode(c.foreground_blend) + + self.foreground:ClearAllPoints() + local dx = (directionCoord[self.fill_direction][3] * -self.foreground_inset) + self.fill_x + local dy = (directionCoord[self.fill_direction][4] * -self.foreground_inset) + self.fill_y + print(' foreground base:', cNum(dx), cNum(dy)) + self.foreground:SetPoint(self.fill_base, self.background, self.fill_base, dx, dy) + + SetProgress(self, 1) + + self.TranslateX = TranslateX + self.TranslateY = TranslateY + self.SetFillPoints = SetFillPoints + self.SetProgress = SetProgress +end +--- Sets properties for a generated FontString +-- Takes the FontString object as a self, and applies config values. +-- In particalur, the anchor parent is derived from either a fixed number of GetParent() or global name +-- @usage Region:SetFontLayout([table]) +function F:SetFontLayout (c) + local print = GetPrint(self.trace) + + if c == nil then + c = lastdb + if not c then + error('No config table found') + end + end + local relativeTo = ParentValue(self, c.parent, c.parentKey) + + --@debug@ + print(namet('FontLayout'),'(', valuet(self:GetName()), ')', valuet(c.font), valuet(c.size), valuet(c.outline)) + print(' ', valuen(c.anchor or 'CENTER'), relativeTo:GetName(), valuen(c.anchorTo or 'CENTER'), valued(c.x or 0), + valued(c.y or 0)) + --@end-debug@ + self:SetPoint( + c.anchor or 'CENTER', + relativeTo, + c.anchorTo or 'CENTER', + c.x or 0, + c.y or 0) + self:SetSize( + c.width or relativeTo:GetWidth(), + c.height or relativeTo:GetHeight()) + self:SetFont( + c.font, + c.size, + c.outline) + self:SetJustifyH(c.justifyH or 'CENTER') + self:SetJustifyV(c.justifyV or 'MIDDLE') + self:SetTextColor(unpack(c.text_color or {1,1,1,1})) +end + +--- For setting up widget pieces +function F:SetTextureLayout(c) + local print = GetPrint(self.trace) + + if c == nil then + c = lastdb + if not c then + error('No config table found') + end + end + local relativeTo = ParentValue(self, c.parent, c.parentKey) + + self.size = c.size + self.width = c.width + self.height = c.height + self.x = c.x + self.y = c.y + self.embedded = c.embedded + self.anchor = c.anchor + self.anchorTo = c.anchorTo + + self:SetPoint(c.anchor, relativeTo, c.anchorTo, c.x, c.y) + self:SetSize(c.size or c.width, c.size or c.height) + self:SetAlpha(c.alpha) + self:SetDesaturated(c.desaturated or false) + print('|cFF00FFFFSetTextureLayout(|r', self:GetName(), '|cFF00FFFF)|r') + print(' ', c.anchor, relativeTo, c.anchorT, c.x, c.v) + if c.combatFade and not (relativeTo.faderID and F.animate_regions[relativeTo.faderID]) then + tinsert(F.animate_regions, self) + self.faderID = #F.animate_regions + --@debug@ + print('register fadeable texture #'..self.faderID) + --@end-debug@ + end +end + +local alphaSubType = { + [1] = '_passive', + [2] = '_active' +} +local alphaFillType = { + [1] = '_empty', + [2] = '_half', + [3] = '_full', +} +function F:UpdateAlpha(inCombat, displayState, fillState) + local print = function() end + print(cWord('UpdateAlpha(')..self:GetName()..cWord(')')) + local alphaType = inCombat and 'alpha' or 'alpha_ooc' + local alphaDuration = inCombat and 'alpha_fade_in' or 'alpha_fade_out' + local displayState = displayState or self.displayState or nil + local fillState = fillState or self.fillState or nil + + local alphaSubType = '' + if displayState then + alphaSubType = (displayState == 1) and '_passive' or ((displayState == 2) and '_active' or '' ) + end + + local alphaFillType = '' + if fillState then + alphaFillType = (fillState == 1) and '_half' or ((fillState == 2) and '_full' or '_empty') + end + + local fadeTo = self[alphaType..alphaSubType..alphaFillType] + local fadeDuration = self[alphaDuration] or 0 + print(' alphaKey:', cWord(alphaType..alphaSubType..alphaFillType)) + print(' alphaTo:', cNum(fadeTo), 'duration:', cNum(fadeDuration)) + if self:IsVisible() and fadeDuration ~= 0 then + self:Fade(fadeDuration, fadeTo or (inCombat and 1 or 0.5), true) + print(' |cFFFFFF00 :Fade()|r', 'dur='..cNum(fadeDuration), cNum(fadeTo), cWord(self:GetName())) + else + self:SetAlpha(fadeTo) + print(' |cFF00FF00 :SetAlpha('..fadeTo..')|r', cText(self:GetName())) + end +end + +--- Sets an OnUpdate within a time-throttled wrapper +-- throttle rate should be slightly smaller than 1/average frame rate +function F:SetFrameScript(updateFunc, showFunc, hideFunc, ...) + local print = GetPrint(self.trace) + + if not self.__oldscripts then + self.__oldscripts = {} + end + + self:SetScript('OnUpdate', nil) -- clear any scripts + self:SetSCript('OnUpdate', function(self) + if GetTime() < self.throttle_time then + return + end + self.throttle_time = self.throttle_time + self.throttle_rate + updateFunc(self) + end) -- put the new function in its place + local changeSet = { + { self.__oldscripts,onUpdate = self:GetScript('OnUpdate') }, + } + + if showFunc then + tinsert(changeSet, + {onShow = self:GetScript('OnShow')}) + self:SetScript('OnShow', showFunc) + end + + if hideFunc then + tinsert(changeSet, + {onHide = self:GetScript('OnShow')}) + self:SetScript('OnHide', hideFunc) + end +end + +--- Embed +function F:Embed(object) + print('Doing embed') + for k, v in pairs(ui_embeds) do + print('embedding Set'..k..'Layout') + object['Set'..k..'Layout'] = self[v] + end + object.SetStatusTextures = self.SetStatusTextures + + --- map a generic layout method if embedded into a frame object + if object.GetObjectType and ui_embeds[object.GetObjectType()] then + if ui_embeds[object.GetObjectType()] then + object.SetLayout = ui_embeds[object.GetObjectType()] + end + end +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Layout/Layout.xml Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,130 @@ +<Ui> + <Script file="Layout.lua" /> + + <Frame name="TurokStatusFrame" parent="UIParent" virtual="true" strata="MEDIUM" hidden="true"> + <Scripts> + <OnShow> + self.throttle_point = 0 + if self.labels then + for _,label in pairs(self.labels) do + label:Show() + end + end + </OnShow> + <OnHide> + if self.labels then + for _,label in pairs(self.labels) do + label:Hide() + end + end + </OnHide> + <OnUpdate> + if GetTime() < self.throttle_point then + return + end + self.throttle_point = self.throttle_point + 0.010 + if self.db and self.db.preUpdate then + self.db.preUpdate(self) + end + self:Update() + if self.db and self.db.postUpdate then + self.db.postUpdate(self) + end + </OnUpdate> + </Scripts> + + <Backdrop bgFile="Interface\Addons\Turok\Media\border\BG-Solid.blp" edgeFile="Interface\Addons\Turok\Media\border\BigBorder-Solid.blp" tile="true"> + <EdgeSize val="12"/> + <TileSize val="12"/> + <BorderColor r="1" g="1" b="1" a="1" /> + <Color r="1" g="1" b="1" a="0" /> + <BackgroundInsets> + <AbsInset left="2" right="2" top="2" bottom="2"/> + </BackgroundInsets> + </Backdrop> + </Frame> + + <Frame name="TurokStatusBar" inherits="TurokStatusFrame" parent="UIParent" virtual="true" strata="HIGH" hidden="true"> + <Scripts> + <OnLoad> + self.lefttext = self.overlay.lefttext + self.righttext = self.overlay.righttext + </OnLoad> + </Scripts> + <Layers> + <Layer level="BORDER"> + <Texture parentKey="background" name="$parent.background" alphaMode="BLEND" /> + </Layer> + <Layer level="ARTWORK"> + <Texture parentKey="foreground" name="$parent.foreground" alphaMode="BLEND" textureSubLevel="0" /> + <Texture name="$parentIcon" parentKey="icon" blendMode="BLEND" textureSubLevel="1"> + <Anchors> + <Anchor point="RIGHT" relativePoint="LEFT" relativeTo="$parent" x="-2" y="0" /> + </Anchors> + </Texture> + </Layer> + </Layers> + <Frames> + <Frame name="$parent_OverLay" parentKey="overlay"> + <Layers> + <Layer point="OVERLAY"> + <FontString name="$parent_LeftText" inherits="TurokFont" parentKey="lefttext"> + <Anchors> + <Anchor point="LEFT" relativePoint="LEFT" x="6" y="0" /> + </Anchors> + </FontString> + + <FontString name="$parent_RightText" inherits="TurokFontDetail" parentKey="righttext"> + <Anchors> + <Anchor point="RIGHT" relativePoint="RIGHT" x="-6" y="0" /> + </Anchors> + </FontString> + </Layer> + </Layers> + </Frame> + </Frames> + </Frame> + + <Font name="TurokFontBig" font="Interface\Addons\Turok\Media\font\ArchivoNarrow-Bold.ttf" outline="NORMAL"> + <Color r="1" g="1" b="1" a="1" /> + <FontHeight> + <AbsValue val="32"/> + </FontHeight> + </Font> + <Font name="TurokFontMed" font="Interface\Addons\Turok\Media\font\ArchivoNarrow-Bold.ttf" outline="NORMAL"> + <Color r="1" g="1" b="1" a="1" /> + <FontHeight> + <AbsValue val="24"/> + </FontHeight> + </Font> + <Font name="TurokFont" font="Interface\Addons\Turok\Media\font\ArchivoNarrow-Bold.ttf" outline="NORMAL"> + <Color r="1" g="1" b="1" a="1" /> + <FontHeight> + <AbsValue val="16"/> + </FontHeight> + </Font> + <Font name="TurokFontNormal" font="Interface\Addons\Turok\Media\font\ArchivoNarrow-Bold.ttf" outline="NONE"> + <Color r="1" g="1" b="1" a="1" /> + <FontHeight> + <AbsValue val="16"/> + </FontHeight> + </Font> + <Font name="TurokFontSmall" inherits="TurokFont"> + <FontHeight> + <AbsValue val="14" /> + </FontHeight> + </Font> + + <Font name="TurokFontDetail" font="Interface\Addons\Turok\Media\font\ArchivoNarrow-Regular.ttf" outline="NORMAL"> + <Color r="1" g="1" b="1" a="1" /> + <FontHeight> + <AbsValue val="16"/> + </FontHeight> + </Font> + + <Font name="TurokFontDetailSmall" inherits="TurokFontDetail"> + <FontHeight> + <AbsValue val="14"/> + </FontHeight> + </Font> +</Ui> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Media.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,96 @@ +local LSM = LibStub("LibSharedMedia-3.0") + +-- ----- +-- BACKGROUND +-- ----- + +-- ----- +-- BORDER +-- ---- +LSM:Register("border", "BG-Solid", [[Interface\Addons\Turok\Media\border\BG-Solid.blp]]) +LSM:Register("border", "BG-Solid", [[Interface\Addons\Turok\Media\border\BG-Solid.png]]) +LSM:Register("border", "BigBorder-Solid", [[Interface\Addons\Turok\Media\border\BigBorder-Solid.blp]]) +LSM:Register("border", "BigBorder-Solid", [[Interface\Addons\Turok\Media\border\BigBorder-Solid.png]]) + +-- ----- +-- FONT +-- ----- +LSM:Register("font", "ArchivoNarrow-Bold", [[Interface\Addons\Turok\Media\font\ArchivoNarrow-Bold.ttf]]) +LSM:Register("font", "ArchivoNarrow-BoldItalic", [[Interface\Addons\Turok\Media\font\ArchivoNarrow-BoldItalic.ttf]]) +LSM:Register("font", "ArchivoNarrow-Italic", [[Interface\Addons\Turok\Media\font\ArchivoNarrow-Italic.ttf]]) +LSM:Register("font", "ArchivoNarrow-Regular", [[Interface\Addons\Turok\Media\font\ArchivoNarrow-Regular.ttf]]) +LSM:Register("font", "Arvo-Bold", [[Interface\Addons\Turok\Media\font\Arvo-Bold.ttf]]) +LSM:Register("font", "Arvo-BoldItalic", [[Interface\Addons\Turok\Media\font\Arvo-BoldItalic.ttf]]) +LSM:Register("font", "Arvo-Italic", [[Interface\Addons\Turok\Media\font\Arvo-Italic.ttf]]) +LSM:Register("font", "Arvo-Regular", [[Interface\Addons\Turok\Media\font\Arvo-Regular.ttf]]) +LSM:Register("font", "constan", [[Interface\Addons\Turok\Media\font\constan.ttf]]) +LSM:Register("font", "DroidSerif-Bold", [[Interface\Addons\Turok\Media\font\DroidSerif-Bold.ttf]]) +LSM:Register("font", "DroidSerif-BoldItalic", [[Interface\Addons\Turok\Media\font\DroidSerif-BoldItalic.ttf]]) +LSM:Register("font", "DroidSerif-Italic", [[Interface\Addons\Turok\Media\font\DroidSerif-Italic.ttf]]) +LSM:Register("font", "DroidSerif", [[Interface\Addons\Turok\Media\font\DroidSerif.ttf]]) +LSM:Register("font", "OpenSans-Bold", [[Interface\Addons\Turok\Media\font\OpenSans-Bold.ttf]]) +LSM:Register("font", "OpenSans-BoldItalic", [[Interface\Addons\Turok\Media\font\OpenSans-BoldItalic.ttf]]) +LSM:Register("font", "OpenSans-ExtraBold", [[Interface\Addons\Turok\Media\font\OpenSans-ExtraBold.ttf]]) +LSM:Register("font", "OpenSans-ExtraBoldItalic", [[Interface\Addons\Turok\Media\font\OpenSans-ExtraBoldItalic.ttf]]) +LSM:Register("font", "OpenSans-Italic", [[Interface\Addons\Turok\Media\font\OpenSans-Italic.ttf]]) +LSM:Register("font", "OpenSans-Light", [[Interface\Addons\Turok\Media\font\OpenSans-Light.ttf]]) +LSM:Register("font", "OpenSans-LightItalic", [[Interface\Addons\Turok\Media\font\OpenSans-LightItalic.ttf]]) +LSM:Register("font", "OpenSans-Regular", [[Interface\Addons\Turok\Media\font\OpenSans-Regular.ttf]]) +LSM:Register("font", "OpenSans-SemiboldItalic", [[Interface\Addons\Turok\Media\font\OpenSans-SemiboldItalic.ttf]]) +LSM:Register("font", "PT_Sans-Narrow-Web-Bold", [[Interface\Addons\Turok\Media\font\PT_Sans-Narrow-Web-Bold.ttf]]) +LSM:Register("font", "PT_Sans-Narrow-Web-Regular", [[Interface\Addons\Turok\Media\font\PT_Sans-Narrow-Web-Regular.ttf]]) +LSM:Register("font", "Roboto-Black", [[Interface\Addons\Turok\Media\font\Roboto-Black.ttf]]) +LSM:Register("font", "Roboto-BlackItalic", [[Interface\Addons\Turok\Media\font\Roboto-BlackItalic.ttf]]) +LSM:Register("font", "Roboto-Bold", [[Interface\Addons\Turok\Media\font\Roboto-Bold.ttf]]) +LSM:Register("font", "Roboto-BoldItalic", [[Interface\Addons\Turok\Media\font\Roboto-BoldItalic.ttf]]) +LSM:Register("font", "Roboto-Italic", [[Interface\Addons\Turok\Media\font\Roboto-Italic.ttf]]) +LSM:Register("font", "Roboto-Light", [[Interface\Addons\Turok\Media\font\Roboto-Light.ttf]]) +LSM:Register("font", "Roboto-LightItalic", [[Interface\Addons\Turok\Media\font\Roboto-LightItalic.ttf]]) +LSM:Register("font", "Roboto-Medium", [[Interface\Addons\Turok\Media\font\Roboto-Medium.ttf]]) +LSM:Register("font", "Roboto-MediumItalic", [[Interface\Addons\Turok\Media\font\Roboto-MediumItalic.ttf]]) +LSM:Register("font", "Roboto-Regular", [[Interface\Addons\Turok\Media\font\Roboto-Regular.ttf]]) +LSM:Register("font", "Roboto-Thin", [[Interface\Addons\Turok\Media\font\Roboto-Thin.ttf]]) +LSM:Register("font", "Roboto-ThinItalic", [[Interface\Addons\Turok\Media\font\Roboto-ThinItalic.ttf]]) +LSM:Register("font", "RobotoSlab-Bold", [[Interface\Addons\Turok\Media\font\RobotoSlab-Bold.ttf]]) +LSM:Register("font", "RobotoSlab-Light", [[Interface\Addons\Turok\Media\font\RobotoSlab-Light.ttf]]) +LSM:Register("font", "RobotoSlab-Regular", [[Interface\Addons\Turok\Media\font\RobotoSlab-Regular.ttf]]) +LSM:Register("font", "RobotoSlab-Thin", [[Interface\Addons\Turok\Media\font\RobotoSlab-Thin.ttf]]) +LSM:Register("font", "SourceCodePro-Black", [[Interface\Addons\Turok\Media\font\SourceCodePro-Black.ttf]]) +LSM:Register("font", "SourceCodePro-Bold", [[Interface\Addons\Turok\Media\font\SourceCodePro-Bold.ttf]]) +LSM:Register("font", "SourceCodePro-ExtraLight", [[Interface\Addons\Turok\Media\font\SourceCodePro-ExtraLight.ttf]]) +LSM:Register("font", "SourceCodePro-Light", [[Interface\Addons\Turok\Media\font\SourceCodePro-Light.ttf]]) +LSM:Register("font", "SourceCodePro-Medium", [[Interface\Addons\Turok\Media\font\SourceCodePro-Medium.ttf]]) +LSM:Register("font", "SourceCodePro-Regular", [[Interface\Addons\Turok\Media\font\SourceCodePro-Regular.ttf]]) +LSM:Register("font", "SourceCodePro-Semibold", [[Interface\Addons\Turok\Media\font\SourceCodePro-Semibold.ttf]]) +LSM:Register("font", "turok", [[Interface\Addons\Turok\Media\font\turok.ttf]]) + +-- ----- +-- SOUND +-- ----- +LSM:Register("sound", "Bell", [[Interface\Addons\Turok\Media\sound\Bell.ogg]]) +LSM:Register("sound", "Chime", [[Interface\Addons\Turok\Media\sound\Chime.ogg]]) +LSM:Register("sound", "Electro_-S_Bainbr-7953_hifi", [[Interface\Addons\Turok\Media\sound\Electro_-S_Bainbr-7953_hifi.mp3]]) +LSM:Register("sound", "Electro_-S_Bainbr-7955_hifi", [[Interface\Addons\Turok\Media\sound\Electro_-S_Bainbr-7955_hifi.mp3]]) +LSM:Register("sound", "FLASH", [[Interface\Addons\Turok\Media\sound\FLASH.mp3]]) +LSM:Register("sound", "Heart", [[Interface\Addons\Turok\Media\sound\Heart.ogg]]) +LSM:Register("sound", "High_Bee-Public_D-135_hifi", [[Interface\Addons\Turok\Media\sound\High_Bee-Public_D-135_hifi.mp3]]) +LSM:Register("sound", "IM", [[Interface\Addons\Turok\Media\sound\IM.ogg]]) +LSM:Register("sound", "Info", [[Interface\Addons\Turok\Media\sound\Info.ogg]]) +LSM:Register("sound", "Kachink", [[Interface\Addons\Turok\Media\sound\Kachink.ogg]]) +LSM:Register("sound", "Link", [[Interface\Addons\Turok\Media\sound\Link.ogg]]) +LSM:Register("sound", "Low_Beep-Public_D-136_hifi", [[Interface\Addons\Turok\Media\sound\Low_Beep-Public_D-136_hifi.mp3]]) +LSM:Register("sound", "Oringz-881", [[Interface\Addons\Turok\Media\sound\Oringz-881.mp3]]) +LSM:Register("sound", "Oringz-940", [[Interface\Addons\Turok\Media\sound\Oringz-940.mp3]]) +LSM:Register("sound", "polish-xrikazen-7425_hifi", [[Interface\Addons\Turok\Media\sound\polish-xrikazen-7425_hifi.mp3]]) +LSM:Register("sound", "Quack", [[Interface\Addons\Turok\Media\sound\Quack.ogg]]) +LSM:Register("sound", "SquishFart", [[Interface\Addons\Turok\Media\sound\SquishFart.ogg]]) +LSM:Register("sound", "Text1", [[Interface\Addons\Turok\Media\sound\Text1.ogg]]) +LSM:Register("sound", "Text2", [[Interface\Addons\Turok\Media\sound\Text2.ogg]]) +LSM:Register("sound", "wilhelm", [[Interface\Addons\Turok\Media\sound\wilhelm.ogg]]) +LSM:Register("sound", "Xylo", [[Interface\Addons\Turok\Media\sound\Xylo.ogg]]) + +-- ----- +-- STATUSBAR +-- ----- +LSM:Register("statusbar", "Minimalist", [[Interface\Addons\Turok\Media\statusbar\Minimalist.tga]]) +LSM:Register("statusbar", "Otravi", [[Interface\Addons\Turok\Media\statusbar\Otravi.tga]])
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Media/Manifest.bat.txt Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,59 @@ +@echo off +echo This script will create our assets manifest for LibSharedMedia + + +echo Creating the file... +echo local LSM = LibStub("LibSharedMedia-3.0") > ..\Media.lua + +echo BACKGROUND +echo.>> ..\Media.lua +echo -- ----- >> ..\Media.lua +echo -- BACKGROUND >> ..\Media.lua +echo -- ----- >> ..\Media.lua +for %%F in (..\Media\background\*.*) do ( +echo %%~nF +echo LSM:Register("background", "%%~nF", [[Interface\Addons\Turok\Media\background\%%~nxF]]^) >> ..\Media.lua +) + +echo BORDER +echo.>> ..\Media.lua +echo -- ----- >> ..\Media.lua +echo -- BORDER >> ..\Media.lua +echo -- ---- >> ..\Media.lua +for %%F in (..\Media\border\*.*) do ( +echo %%~nF +echo LSM:Register("border", "%%~nF", [[Interface\Addons\Turok\Media\border\%%~nxF]]^) >> ..\Media.lua +) + +echo FONT +echo.>> ..\Media.lua +echo -- ----->> ..\Media.lua +echo -- FONT>> ..\Media.lua +echo -- ----->> ..\Media.lua +for %%F in (..\Media\font\*.ttf) do ( +echo %%~nF +echo LSM:Register("font", "%%~nF", [[Interface\Addons\Turok\Media\font\%%~nxF]]^) >> ..\Media.lua +) + +echo SOUND +echo.>> ..\Media.lua +echo -- ----->> ..\Media.lua +echo -- SOUND>> ..\Media.lua +echo -- ----->> ..\Media.lua +for %%F in (..\Media\sound\*.*) do ( +echo %%~nF +echo LSM:Register("sound", "%%~nF", [[Interface\Addons\Turok\Media\sound\%%~nxF]]^) >> ..\Media.lua +) + +echo STATUSBAR +echo.>> ..\Media.lua +echo -- ----->> ..\Media.lua +echo -- STATUSBAR>> ..\Media.lua +echo -- ----->> ..\Media.lua +for %%F in (..\Media\statusbar\*.*) do ( +echo %%~nF +echo LSM:Register("statusbar", "%%~nF", [[Interface\Addons\Turok\Media\statusbar\%%~nxF]]^) >> ..\Media.lua +) + +:end_of_file +pause \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Combat/Castbar.Init.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,124 @@ +--- ${PACKAGE_NAME} +-- @file-author@ +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +-- Created: 12/28/2015 8:00 AM + +Turok.defaults.tek = { + width = 300, height = 30, + anchor = 'CENTER', parent = 'UIParent', anchorTo = 'CENTER', + x = 0, y = 0, + foreground_blend = 'BLEND', + background_blend = 'BLEND', + background_texture = '', + background_color = {1,1,1,0.2}, + combatFade = false, + + foreground_channeling = {0.4,0.2,0.9,1}, + background_channeling = {0.25,0.25,0.25,1}, + foreground_casting = {0.01, 0.46, 0.93, 1}, + background_casting = {0,0,0,0.0}, + background_interrupted = {1,0,0,1}, + foreground_interrupted = {1, 0.5, 0, 1}, + foreground_uninterruptible = {0.8, 0.8, .8, 1}, + background_uninterruptible = {0,0,0,0.25}, + background_failed = {0.25,0.25,0.25, 1}, + foreground_failed = {1,0.5,0.5,0.25}, + foreground_finished = {0.4,.7,.1, 1}, + background_finished = {0,0,0,0.25}, + foreground_inset = 0, + padding = 2, + spacing = 1, + + icon = { + size = 56, + anchor = 'RIGHT', anchorTo = 'LEFT', + parent = 1, + x = 0, y = 0, + }, + + fill_direction = 'RIGHT', + + glow_texture = "Tooltip-BigBorder", + glow_size = 2, + spark_texture = "", + spark_size = 2, + spellname = {}, + casttime = {}, + ping = { + anchor='TOPRIGHT', + anchorTo='BOTTOMRIGHT', + x = -6, y= 0, + parent = 1, + parentKey = 'background', + color = {1,1,0,0.7}, + size = 12, + font = "Interface\\Addons\\Turok\\Media\\font\\ArchivoNarrow-Bold.ttf", + justifyH = 'RIGHT', + justifyV = 'BOTTOM' + }, + casttime = { + parent = 1, + parentKey = 'background', + x = -6, y= 0, + anchor = 'RIGHT', + anchorTo = 'RIGHT', + justifyH = 'RIGHT', + justifyV = 'MIDDLE' + }, + spelltext = { + parent = 1, + parentKey = 'foreground', + x = 6, y = 0, + anchor = 'LEFT', + anchorTo = 'LEFT', + justifyH = 'LEFT', + justifyV = 'MIDDLE', + }, + downtime = { + parent = 1, + parentKey = 'foreground', + anchor='TOPLEFT', + anchorTo='BOTTOMLEFT', + x = 0, y = 0, + text_color = {.75,.75,.75,1}, + justifyH = 'LEFT', + }, + ['player'] = { + icon = { + embedded = true, + size = 36, + anchor = 'RIGHT', anchorTo = 'LEFT', + parent = 1, + x = -2, y = 0, + }, + width = 330, height = 32, + anchor = 'TOP', parent = 'UIParent', anchorTo = 'CENTER', + x = 0, y = -254, + }, + ['target'] = { + icon = { + embedded = true, + size = 36, + width = 300, + anchor = 'LEFT', anchorTo = 'LEFT', + parent = 'TekplayerCastBar', + x = -2, y = 0, + }, + + width = 300, height = 24, + height = 36, + anchor = 'BOTTOMLEFT', parent = 'TekplayerCastBar', anchorTo = 'TOPRIGHT', + x = 1, y =1, + }, + ['focus'] = { + width = 200, height = 36, + anchor = 'TOPLEFT', parent = 'TekplayerCastBar', anchorTo='BOTTOMRIGHT', + x = 2, y = -2 + }, + ['pet'] = { + width = 300, height = 24, + anchor = 'TOPRIGHT', parent = 'TekplayerCastBar', anchorTo='TOPLEFT', + x = -2, y = 0 + }, +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Combat/Castbar.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,510 @@ +--- Turok +-- Castbar.lua +-- Created: 12/4/2015 11:17 PM +-- @file-author@ +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +-- Deals with casting events and works the castingbar interface +local print, tostring, tonumber, rep, pairs, min, format, unpack, select, strpad = print, tostring, tonumber, string.rep, pairs, math.min, string.format, unpack, select, string.rep +local GetTime, UnitCastingInfo, UnitChannelInfo, GetSpellInfo, GetSpellTabInfo = GetTime, UnitCastingInfo, UnitChannelInfo, GetSpellInfo, GetSpellTabInfo +local floor = math.floor +local T = Turok +local db +local PING_CEILING = 190 -- transpacific +local PING_MIDLINE = 100 +local PING_FLOOR = 10 -- transcontinental +--@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('Tek', ...) + end +end + +local EVENT_COLOR = '|cFF44FF44' +local EVENT_COLOR2 = '|cFF88FF88' +local DATA_COLOR = '|cFFDD77DD' +--@end-debug@ + +local mod = T:NewModule("Tek") +function mod:OnInitialize() + self.db = T.db.tek + self.castbar = {} + self.UNIT_SPELLCAST_SENT = self.SpellCastRequest + self.UNIT_SPELLCAST_START = self.SpellCastEvent + self.UNIT_SPELLCAST_DELAYED = self.SpellCastEvent + self.UNIT_SPELLCAST_SUCCEEDED = self.SpellCastEvent + self.UNIT_SPELLCAST_STOP = self.SpellCastEvent + self.UNIT_SPELLCAST_FAILED = self.SpellCastEvent + self.UNIT_SPELLCAST_INTERRUPTED = self.SpellCastEvent + self.UNIT_SPELLCAST_CHANNEL_START = self.SpellCastEvent + self.UNIT_SPELLCAST_CHANNEL_STOP = self.SpellCastEvent + self.UNIT_SPELLCAST_CHANNEL_UPDATE = self.SpellCastEvent + self.UNIT_SPELLCAST_INTERRUPTIBLE = self.SpellCastEvent + self.UNIT_SPELLCAST_UNINTERRUPTIBLE = self.SpellCastEvent +end + +--- events & units +local TRACKED_UNITS = {'player', 'target', 'focus', 'pet'} +local FADE_OUT_TIME, FADE_IN_TIME = 1, .2 + +local TEXTURE_SUFFIX = { + ['CHANNEL_START'] = '_channeling', + ['CHANNEL_UPDATE'] = '_channeling', + ['CHANNEL_STOPPED'] = '_channeling', + ['START'] = '_casting', + ['INTERRUPTED'] = '_interrupted', + ['SUCCEEDED'] = '_finished', +} + +function mod:OnEnable() + db = self.db + -- setup castingbar frames + local c = self.castbar + for _, unit in pairs(TRACKED_UNITS) do + local cdb = db[unit] + --@debug@ + print(DATA_COLOR .. unit .. '|r castbar creation')--@end-debug@ + + -- Set frames + local fn = 'Tek' .. unit .. 'CastBar' + c[unit] = CreateFrame('Frame', fn, _G[cdb.parent], 'TurokCastingBar') + + local pc = c[unit] + T.SetFrameLayout(pc, cdb) + T.SetTextureLayout(pc.icon, cdb.icon or db.icon) + T.SetStatusTextures(pc, cdb.statusbar or db.statusbar) + + if unit == 'player' then + T.SetFontLayout(pc.ping, db.ping) + T.SetFontLayout(pc.downtime, db.downtime) + pc.pingbar:ClearAllPoints() + pc.pingbar:SetPoint('TOPRIGHT', pc.background, 'TOPRIGHT', 0, 0) + pc.pingbar:SetHeight(pc.background:GetHeight()) + else + if pc.interrupt then + pc.interrupt:SetSize(pc.icon.size*3, pc.icon.size* 3) + end + + end + + T.SetFontLayout(pc.casttime, cdb.casttime or db.casttime) + T.SetFontLayout(pc.spelltext, cdb.spelltext or db.spelltext) + + pc:SetAlpha(0) + pc.last = nil + pc.sent = {} + pc.unit = unit + pc.SetSpell = self.SetSpell + pc.SetState = self.SetState + pc.Update = self.Update + end + + + -- kill default casting bar + -- T.cbscripts = {CastingBarFrame:GetScript('OnUpdate'), CastingBarFrame:GetScript('OnEvent')} + CastingBarFrame:SetScript('OnUpdate', nil) + CastingBarFrame:SetScript('OnEvent', nil) + CastingBarFrame:Hide() + PetCastingBarFrame:SetScript('OnUpdate', nil) + PetCastingBarFrame:SetScript('OnEvent', nil) + PetCastingBarFrame:Hide() +end + +function mod:UpdateLocked() + for k, v in pairs(self.castbar) do + if T.unlocked then + local name, texture, offset, numSpells = GetSpellTabInfo(T.specPage) + v.value = offset + v.duration = numSpells + v.spelltext:SetText(k) + v.icon:SetTexture(texture) + v:SetAlpha(1) + v:Show() + v:EnableMouse(true) + v:SetMovable(true) + v:RegisterForDrag("LeftButton") + v:SetScript('OnDragStart', function(self) self:StartMoving() end) + v:SetScript('OnDragStop', function(self) self:StopMovingOrSizing() end) + else + + v:SetScript('OnDragStart', nil) + v:SetScript('OnDragStop', nil) + v:EnableMouse(false) + v:SetMovable(false) + + print('Saving bar coordinates post unlock') + + db[k].x = v:GetLeft() + db[k].y = v:GetTop() + db[k].anchor = 'BOTTOMLEFT' + db[k].anchorTo = 'BOTTOMLEFT' + db[k].parent = 'UIParent' + end + end +end + +--- Store spell requests for use in tracking lag time +function mod:SpellCastRequest(e, unit, spellName, rank, target, castID) + print('|cFFFF4400Request sent:|r ', spellName, castID, target) + self.castbar.player.sent[castID] = { + spellName = spellName, + castID = castID, + sendTime = GetTime()*1000, + } +end + +--- Handle events pertaining to a cast bar +function mod:SpellCastEvent(event, unit, ...) + if not self.castbar[unit] then + return + end + + local u = T.unit[unit] + local c = self.castbar[unit] + + --- doubling as an invocation source test + local spellName, rank, castID, spellID = ... + + local channelinfo = T.unit[unit].channeling + local castinginfo = T.unit[unit].casting + local sendq = c.sent + local castd = c.last + local timestamp = GetTime()*1000 + + --todo: remove truncation + local e = event:match("UNIT_SPELLCAST_([%a_]+)") + print(GetTime(), '|cFFFF8747'..e..(strpad(' ',12-#e))..'|r |cFFDDFF00#'..tostring(castID)..'|r', spellName, spellID) + + c.channeling = channelinfo and channelinfo[1] or nil + c.casting = castinginfo and castinginfo[1] or nil + if c.channeling then + -- {name, subText, text, texture, startTime, endTime, isTradeSkill, notInterruptible} + c.startTime = channelinfo[5] + c.endTime = channelinfo[6] + c.nonInterruptible = channelinfo[8] + elseif c.casting then + --name, subText, text, texture, startTime, endTime, isTradeSkill, castID, notInterruptible + c.startTime = castinginfo[5] + c.endTime = castinginfo[6] + c.castID = castinginfo[8] + c.nonInterruptible = castinginfo[9] + else + print(' |cFFFF7700internal data was nil|r') + end + + --- process the "event" + local setSpell, setState + if e == 'START' then + setSpell = true + setState = true + + -- player data calculations + if unit == 'player' then + if sendq[castID] and sendq[castID].spellName == spellName then + local sent = sendq[castID] + print(' |cFF00AAFFmatched:|r', sent.spellName, castID) + c.pingTime = c.startTime - sent.sendTime + print(' ping:', c.pingTime) + for cid, cdata in pairs(sendq) do + if cdata.sendTime <= sent.sendTime then + --print(' forgetting #'..cdata.sendTime, cid, cdata.spellName) + sendq[cid] = nil + end + end + + if castd ~= nil then + print(' downtime calc hit') + c.downTime = timestamp - castd.endTime + castd = nil + else + c.downTime = nil + end + c.castID = castID + end + end + elseif e == 'CHANNEL_START' or e == 'CHANNEL_UPDATE' then + setSpell = true + setState = true + c.event = e + + elseif e == 'STOP' then + setState = true + c.casting = nil + castd = { + spellName = spellName, + spellID = spellID, + castID = castID, + endTime = timestamp, + } + print(' |cFFFFFF00found', timestamp, spellName) + + elseif e == 'CHANNEL_STOP' then + setState = true + c.channeling = nil + castd = { + spellName = spellName, + spellID = spellID, + castID = castID, + endTime = timestamp, + } + print(' |cFFFF0088found', timestamp, spellName) + + elseif e == 'SUCCEEDED' then + if c.spellName == spellName and not c.channeling then + setState = true + print(' |cFFFF4400',c.spellName,'=',spellName,' pushing event', e) + end + -- if there are 'send' args when this fires, it means it's an instant cast + if sendq[castID] and sendq[castID].spellName == spellName then + castd = { + spellName = spellName, + spellID = spellID, + castID = castID, + endTime = timestamp, + } + print(' |cFFFFAA00found', timestamp, spellName) + end + + elseif e =='FAILED' then + if spellName == c.spellName and not c.channeling then + setState = true + end + + elseif e == 'INTERRUPTED' then + setState = true + + end + + + + + if setSpell then + print(' |cFF44FF00setting spell', spellName) + end + if setState then + print(' |cFFFF4400pushing event', e) + end + + if setSpell then + c:SetSpell(e) + end + if setState then + c:SetState(e) + end +end + + +--- Sets all the static elements of the casting bar, such as config values, icon texture, and name +function mod.SetSpell(c, event) + local _ + local time, alpha = GetTime(), c:GetAlpha() + local u, cdb = T.unit[c.unit], c.db + + c.stopped = nil + c.stopping = nil + print('New spell:', c.spellName) + --- use only internal info + local data = (event == 'CHANNEL_START' or event == 'CHANNEL_UPDATE' or event == 'CHANNEL_STOP') and u.channeling or u.casting + local spellName, rank, displayName, texture, startTime, endTime, isTradeSkill, castID, nonInterruptible = unpack(data) + + + if spellName == nil then + print(" Can't do arithmetic, no data.") + else + print(cText(" Arithmetic vars:"), cNum(startTime), cNum(endTime)) + end + + c.spellName = spellName + c.castID = castID or 0 + c.rank = rank + c.displayName = displayName + c.texture = texture + c.nonInterruptible = nonInterruptible + c.isTradeSkill = isTradeSkill + c.endTime = endTime or 0 + c.startTime = startTime or 0 + c.duration = c.endTime - c.startTime + + if c.unit == 'player' then + if c.pingTime then + print(' ping',c.pingTime, endTime, startTime, c.duration) + local draw_dist = (c.pingTime / c.duration) * (c.fill_width) + if draw_dist > c.fill_width then + draw_dist = c.fill_width + end + print('SET AND SHOW PING ', c.pingTime,'on', c.pingbar:GetName()) + c.pingbar:SetWidth(draw_dist) + c.pingbar:Show() + + local rv = c.pingTime - PING_FLOOR + local rr = PING_MIDLINE - PING_FLOOR + local gv = c.pingTime - PING_MIDLINE + local gr = PING_CEILING - PING_MIDLINE + local r = c.pingTime > PING_MIDLINE and 1 or (c.pingTime < PING_FLOOR and 0 or (rv / rr)) + local g = c.pingTime < PING_MIDLINE and 1 or (c.pingTime > PING_CEILING and 0 or 1-(gv / gr)) + print(c.pingTime, rv, '/', rr, '=', r) + print(c.pingTime, gv, '/', gr, '=', g) + + c.ping:SetText(floor(c.pingTime)) + c.ping:SetTextColor(r,g,0) + c.ping:Show() + else + c.pingbar:Hide() + c.ping:Hide() + end + if c.downTime then + c.downtime:Show() + if c.downTime > 1500 then + c.downtime:SetText(nil) + else + c.downtime:SetText(c.downTime) + end + else + c.downtime:Hide() + end + else + if c.nonInterruptible then + c.interrupt:Show() + else + c.interrupt:Hide() + end + end + + c.icon:SetTexture(texture) + c.spelltext:Show() + c.spelltext:SetText(spellName) + + c.fill_inverse = c.channeling + -- set timers +end + +--- Deals with failed/succeeded/interrupted visuals and fading cues +-- Fired by one of those events, or cast/channel info is returning nothing +function mod:SetState(event) + if T.unlocked then + return + end + + local time = GetTime() * 1000 + print(' ',self:GetName(), '|cFF44FF00event trigger:|r', event) + + -- We want these to be updating no matter what is happening + if TEXTURE_SUFFIX[event] then + local cdb = self.db + if cdb.foreground_texture then + print(' |cFF00AAFFevent|r '..event..', |cFF00AAFFtexture|r ', cdb.foreground_texture) + self.foreground:SetVertexColor(unpack(cdb['foreground' .. TEXTURE_SUFFIX[event]] and cdb['foreground' .. TEXTURE_SUFFIX[event]] or cdb.foreground_color)) + else + self.foreground:SetTexture(unpack(cdb['foreground' .. TEXTURE_SUFFIX[event]] and cdb['foreground' .. TEXTURE_SUFFIX[event]] or cdb.foreground_color)) + end + + if cdb.background_texture then + print(' texture=', cdb.background_texture) + self.background:SetVertexColor(unpack(cdb['background' .. TEXTURE_SUFFIX[event]] and cdb['background' .. TEXTURE_SUFFIX[event]] or cdb.background_color)) + else + self.background:SetTexture(unpack(cdb['background' .. TEXTURE_SUFFIX[event]] and cdb['background' .. TEXTURE_SUFFIX[event]] or cdb.background_color)) + end + end + + -- are we starting or stopping + if event == 'START' or event == 'CHANNEL_START' then + print(' |cFF00AAFFStarting display|r ', self.spellName) + self:Show() + if self.__fade:IsPlaying() then + self.__fade:Stop() + end + + self:Fade(FADE_IN_TIME, self.alpha) + else + if event == 'SUCCEEDED' and not self.channeling then + print(' |cFF00AAFFsuccess deduced values|r', self.value, 'to', self.duration) + self.percent = 1 + self.value = self.duration + end + + -- Actual fading out begins here, anything else is statistical sugar + if event == 'STOP' or event == 'CHANNEL_STOP' then + print('yeah we done') + if self.__fade:IsPlaying() then + self.__fade:Stop() + end + self:Fade(FADE_OUT_TIME, 0) + end + end +end + +--- Animation loop +function mod:Update() + local time = GetTime() * 1000 + local u = self.unit + local s = self + + -- update vals + if s.casting or s.channeling then + self.value = s.casting and (time - s.startTime) or (s.endTime - time) + self.percent = (time - s.startTime) / self.duration + if time > s.endTime then + self.value = self.fill_inverse and 0 or s.duration + self.percent = self.fill_inverse and 0 or 1 + self.elapsed = time - s.endTime + end + --_G.print('Update',' ',self.unit, self.value, self.percent) + else + self.value = 1000 + self.percent = 1 + end + self.casttime:SetText(format("%.2f", self.value / 1000)) + + self:SetProgress(self.percent) +end + +--- Refresh the CastingBar for things like target change, pet despawn, etc. +-- Will attempt to flush out any existing cast action data, then re-invoke SpellCastEvent() with as much data can be acquired. +-- There is no event data such as spellID directly available, so this is essentially the biggest constraint we have on what +-- the castingbar can depend on. +function mod:UpdateUnit(unit) + local print = function(...) _G.print('Update', ...) end + print(cText 'GUID changed:|cFFFFFF99', unit) + local c = mod.castbar[unit] + if c.channeling or c.casting then + print(cText ' was casting a spell, run STOP event and hide completely') + c:SetState(c.casting and 'STOP' or 'CHANNEL_STOP') + c.channeling = nil + c.casting = nil + c:Hide() + end + + if T.unit[unit].casting then + print(cText(' new target is CASTING')) + mod:SpellCastEvent('UNIT_SPELLCAST_START', unit) + end + if T.unit[unit].channeling then + print(cText(' new target is CHANNELING')) + mod:SpellCastEvent('UNIT_SPELLCAST_CHANNEL_START', unit) + end + + T:UNIT_SPELLCAST(unit)-- name, subText, text, texture, startTime, endTime, isTradeSkill, castID, notInterruptible + T:UNIT_CHANNEL(unit) -- name, subText, text, texture, startTime, endTime, isTradeSkill, notInterruptible + +end + +function mod:UpdateInterrupt(e, unit, ...) + mod.castbar[unit].nonInterruptible = (e == 'UNIT_SPELLCAST_UNINTERRUPTIBLE') and true or false + if unit ~= 'player' and unit ~='pet' then + + end +end + +mod.UNIT_PET = function(self, e, unit) + if unit == 'player' then + self:UpdateUnit('pet') + end +end +mod.PLAYER_TARGET_CHANGED = function(self, ...) + _G.print('Main', cPink(self),...) + self:UpdateUnit('target') +end +mod.PLAYER_FOCUS_CHANGED = function(self) + self:UpdateUnit('focus') +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Combat/Castbar.xml Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,74 @@ +<Ui> + + <Frame name="TurokCastingBar" inherits="TurokStatusBar" virtual="true" hidden="true"> + <Scripts> + <OnHide> + self:SetAlpha(0) + self.casttime:SetText(nil) + self.spelltext:SetText(nil) + self.casting = nil + self.channeling = nil + self.succeeded = nil + self.fading = nil + self.fadeIn = nil + self.fadeOut = nil + self.stopping = nil + </OnHide> + </Scripts> + <Layers> + <Layer level="OVERLAY"> + <Texture name="$parentSpark" parentKey="spark" file="Interface\CastingBar\UI-CastingBar-Spark" alphaMode="ADD" hidden="true" /> + <Texture name="$parentPingBox" parentKey="ping" hidden="true" blendMode="ADD"> + <Color r="1" g="0.25" b="0" a="0.5" /> + <Anchors> + <Anchor point="BOTTOMRIGHT" x="-3" y="3" /> + <Anchor point="TOPRIGHT" x="-3" y="-3" /> + </Anchors> + </Texture> + + <!-- SPELL NAME --> + <FontString name="$parentSpellText" parentKey="spelltext" inherits="TurokFont" height="18" outline="NORMAL"> + <Anchors> + <Anchor point="LEFT" relativePoint="LEFT" relativeKey="foreground" x="6" y="0"/> + </Anchors> + </FontString> + + <!-- CAST TIME --> + <FontString name="$parentTimeText" parentKey="casttime" inherits="TurokFont" height="18" outline="NORMAL"> + <Color r="1" g="1" b="1" a="1" /> + <Anchors> + <Anchor point="RIGHT" relativePoint="RIGHT" relativeTo="$parent" x="-6" y="0" /> + </Anchors> + </FontString> + + <!-- CAST LAG --> + <Texture name="$parentPingBar" parentKey="pingbar" alphaMode="ADD" hidden="true"> + <Color r="1" g="0" b="0" a="0.7" /> + </Texture> + + <FontString name="$parentPingText" parentKey="ping" inherits="TurokFontDetail" hidden="true"> + <Color r="1" g="1" b="1" a="1" /> + <Anchors> + <Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMLEFT" outline="NORMAL" relativeTo="$parent" x="-6" y="-3" /> + </Anchors> + </FontString> + + <!-- CHAINCAST LAG --> + <FontString name="$parentDownTimeText" parentKey="downtime" inherits="TurokFontDetail" hidden="true"> + <Color r="1" g="1" b="1" a="1" /> + <Anchors> + <Anchor point="TOPLEFT" relativePoint="BOTTOMLEFT" outline="NORMAL" relativeTo="$parent" x="6" y="-3" /> + </Anchors> + </FontString> + + <!-- NOT-INTERRUPTIBLE --> + <Texture file="Interface/CastingBar/UI-CastingBar-Arena-Shield" name="$parentInterruptStatus" parentKey="interrupt" hidden="true"> + <Size x="94" y="94" /> + <Anchors> + <Anchor point="CENTER" relativePoint="RIGHT" relativeKey="$parent.icon" x="0" y="0" /> + </Anchors> + </Texture> + </Layer> + </Layers> + </Frame> +</Ui> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Combat/Combat.xml Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,10 @@ +<Ui> + <Include file="Castbar.xml" /> + <Include file="CombatLog.xml" /> + <Script file="Castbar.Init.lua" /> + <Script file="Castbar.lua" /> + <Script file="CombatLog.lua" /> + <Include file="Powerbar.xml" /> + <Script file="Powerbar.Init.lua" /> + <Script file="Powerbar.lua" /> +</Ui> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Combat/CombatLog.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,758 @@ +--- Combat +-- @file-author@ +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +-- Created: 1/11/2016 4:27 PM +--- Data collector for API Combat Log Event +local T, _G = Turok, _G +local mod = T:NewModule("Combat") +local pairs, ipairs, select, concat, format, tinsert, wipe = pairs, ipairs, select, table.concat, string.format, tinsert, table.wipe +local GetSpellTexture, CreateFrame, GetTime, unpack, floor = GetSpellTexture, CreateFrame, GetTime, unpack, floor +local db +local cText, cNum, cKey, cWord, cPink, cType, cBool = cText, cNum, cKey, cWord, cPink, cType, cBool +local print = function(...) + if _G.Devian and _G.DevianDB.workspace ~= 1 then + _G.print('CombatText', ...) + end +end + + +--- performance constants +local SCT_NAME = 'TurokSCT%s' +local SCT_TEMPLATE = 'TurokSCTAnchorTemplate' +local SCT_PREGAME = 5 +local SCT_MESSAGE_TEMPLATE = 'TurokCombatMessageTemplate' +local SCT_MESSAGE_NAME = 'CombatString%d' +local LOG_TEMPLATE = 'TurokCombatLogAnchorTemplate' + +--- UX structures +T.defaults.CombatText = { + width = 400, height = 800, + parent = 'UIParent', + Outgoing = { + anchor = 'RIGHT', anchorTo = 'RIGHT', + x = -400, y = -200, + }, + Incoming = { + anchor = 'LEFT', anchorTo = 'LEFT',parent = 'UIParent', + x = 400, y = -200, + }, + DoTTracker = { + anchor = 'BOTTOMLEFT', anchorTo = 'BOTTOM', parent = 'UIParent', + x = 80, y = 400, + }, + defaultFont = {"Interface\\Addons\\Turok\\Media\\font\\ArchivoNarrow-Regular.ttf", 18, 'OUTLINE'}, + defaultAnimation = 'slide', + + textFonts = { + font1 = {"Interface\\Addons\\Turok\\Media\\font\\ArchivoNarrow-Regular.ttf" , 30, 'OUTLINE'}, + font2 = {"Interface\\Addons\\Turok\\Media\\font\\ArchivoNarrow-Regular.ttf" , 24, 'OUTLINE'}, + font3 = {"Interface\\Addons\\Turok\\Media\\font\\ArchivoNarrow-Bold.ttf" , 20, 'OUTLINE'}, + }, + + --- [(string) combatEvent] = {[1] = (string) format [, [2] = fontKey]} + --- Substitution values + -- %d [1] amount [2] overkill [3] absorbed [4] blocked + -- %s [5] spell [6] caster [7] school + textFormat = { + ['SWING_DAMAGE'] = {'%d'}, + ['SPELL_DAMAGE'] = {'%d'}, + ['RANGE_DAMAGE'] = {'%d'}, + Incoming = { + ['SWING_DAMAGE'] = {'-%d'}, + ['SPELL_DAMAGE'] = {'-%d (%s)'}, + ['RANGE_DAMAGE'] = {'-%d'}, + }, + }, + textModifiers ={ + critical = {'%s!', 'pop'}, + overKill = {'%s |cFF0088FFKilling Blow!|r', 'slide'}, + multistrike = {'<%s>', 'lateralSlide', 'font3'}, + absorbed = {'%s (%d)', 'slide'}, + blocked = {'%s {%d}', 'slide'}, + pet = {'(%s)', 'lateralSlide'}, + grouped = {'%s (%d hit)', 'slide'}, + }, + --- [AnimationGroup key] = {[XML attrib] = [value], d[x/y] = (number) 0-1 } + -- d[x/y] indicates the proportional relevance of each FontString dimension when frames are displaced by a new event + -- x/y indicates the ranges of movement made by an animation, and are also considered when calculating displacement + animation = { + slide = { + x = 0, dx = 0, + y = 300, dy = 1, + duration = 2 + }, + lateralSlide = { + x = 300, dx = 1, + y = 0, dy = 0, + duration = 2 + }, + pop = { + toScale = 1.4, + fromScale = 0.1, + duration = 0.14, + dx = 0, dy = 1, + }, + fadeOut = {change = -1, duration = 0.5}, + }, +} +--- [1] text wrapper [2] animation type +local dotEvents = { + SPELL_AURA_APPLIED = true, + SPELL_PERIODIC_DAMAGE = true, + SPELL_AURA_REMOVED = true, + SPELL_AURA_REFRESHED = true, +} +local petGUID = {} + +------------- data structures +local defaultAnimation, defaultFont +local criticalModifier, absorbedModifier, blockedModifier, overKillModifier, multistrikeModifier, groupedModifier +local criticalAnimation, absorbedAnimation, blockedAnimation, overKillAnimation, multistrikeAnimation, groupedAnimation +local criticalFont, absorbedFont, blockedFont, overKillFont,multistrikeFont, groupedFont +local textFonts = {} +local textFormat = {} +local animation = {} +local spellCache = {} +local DoTFrames = {} + +local dotTrackingEvents = { + ['SPELL_AURA_APPLIED'] = true, + ['SPELL_AURA_REMOVED'] = true, + ['SPELL_AURA_REFRESHED'] = true, +} + +--- multi-hit events data +-- [(string) localized name] = { +-- [1] = (bool) controlled channel +-- [2] = (number) minimum time to wait for next damage tick +-- [3] = (number) maximum time to log grouped spell hits +-- [4] = (string) combatEvent full string +-- [5] = (string) combatEvent short prefix (as opposed to SPELL_PERIODIC) +-- [6] = (string) combatEvent short suffix (as opposed to AURA_APPLIED) +-- } +-- tailing fields are set to reduce the number of arguments passed around +local groupedSpells = { + global = {false, 1, 'SPELL_PERIODIC_DAMAGE', 'SPELL', 'DAMAGE'}, + ['Crimson Tempest'] = {false, 0.3, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'}, -- shockwave dot + ['Mind Sear'] = {false, 1, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'}, -- scanning aoe + ['Searing Insanity'] = {false, 1, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'}, -- scanning aoe + ['Ice Nova'] = {false, 0.4, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'}, -- shockwave aoe + ['Blizzard'] = {false, 1, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'}, -- scanning aoe + ['Frozen Orb'] = {false, 1, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'}, + ['Ice Bomb'] = {false, 0.4, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'}, -- shockwave aoe + ['Comet Storm'] = {false, 2.5, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'}, -- staggered multi-hit + ['Barrage'] = {false, 1.1, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'}, -- projectile vommit + ['Glaive Toss'] = {false, 3, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'}, -- path projectile, + ['Doom Nova'] = {false, 0.4, 'SPELL_DAMAGE', 'SPELL', 'DAMAGE'} +} + +local dotSpellIndex = { + ['Shadow Word: Pain'] = {'HARMFUL|PLAYER'}, + ['Vampiric Touch'] = {'HARMFUL|PLAYER'} +} + +local offhandSpellIndex = { + ['Execute'] = {'Execute Off-Hand'}, + ['Mutilate'] = {'Mutilate Off-Hand'}, + ['Stormstrike'] = {'Stormstrike Off-Hand'}, +} + +--- stored as a list of field representations to be concatenated together within a loadstring def + + + +--- Tracking tables +local groupedQueue = {} +local groupedEvents = {} +local offhandQueue = {} +local sct_format = {} + + +local function GetGUIDInfo(guid) + local unitType, flags1, flags2 = guid:match('(%a+)\-(%x+)\-(%x+)') + return concat({unitType, flags1, flags2},'|r::|cFF0088FF')..'|r' +end + +local SpellSchoolColors = { + [1] = {255, 255,0}, -- physical + [2] = {255, 230, 128}, -- holy + [3] = {255, 255, 128}, -- holy+phys + [4] = {255, 128, 0}, -- fire + [8] = {77, 255, 77}, -- nature + [16] = {128, 255, 255}, -- frost + [20] = {255, 192, 128}, -- frostfire + [32] = {128, 128, 255}, -- shadow + [48] = {128, 192, 255}, -- shadow+frost + [64] = {255, 128, 255}, -- arcane, + [72] = {255, 128, 128}, -- spellstorm, +} + +local h = '|cFF%02X%02X%02X' +local SpellSchoolColor = function (flags, spellName) + local i = 64 + local rA, gA, bA + if SpellSchoolColors[flags] then + print(flags, 'match') + print(format('%02X%02X%02X', unpack(SpellSchoolColors[flags]))) + return format(h, unpack(SpellSchoolColors[flags])) + end + + repeat + local rB, gB, bB = unpack(SpellSchoolColors[i]) + if i <= flags then + if not rA then + rA = rB + gA = gB + bA = bB + else + rA = (rA+rB)/2 + gA = (gA+gB)/2 + bA = (bA+bB)/2 + end + print('test:', cWord(i), '<=', cKey(flags), '=', (i <= flags), cPink(rA), cNum(gA), cText(bA)) + flags = flags - i + else + print(i, 'skip') + end + i = i/2 + until (i == 1) + SpellSchoolColors[flags] = {rA, gA, bA } + --print(string.format('%02X%02X%02X', unpack(SpellSchoolColors[flags]))) + return format(h, unpack(SpellSchoolColors[flags])) +end +local myGUID + +mod.NewCombatMessage = function(frame, index) + local ct = CreateFrame('Frame', SCT_MESSAGE_NAME:format(frame.lineID), frame, SCT_MESSAGE_TEMPLATE) + index = index and 'active' or 'expired' + frame.lineID = frame.lineID + 1 + frame.active[#frame.active+1] = ct + ct.index = #frame.active + ct.x = 0 + ct.y = 0 + ct.point = 'BOTTOMLEFT' + return ct +end + +--- frame interaction logic +mod.AddCombatMessage = function(frame, text, icon, animationType, fontKey) + local line + print(fontKey) + + local expired = frame.expired + local active = frame.active + local a = 1 + local shiftY, shiftX + local lastFrame + --- If animation has overlap delta values, find the last active frame of that animation type and check for overlaps. + --- Frames are considered overlapping when the last member's ((height - distance traveled) * delta) is over 0. + --- This assumes the same string height for the upcoming frame since wordwrap isn't enabled. + print(animationType) + if animation[animationType].dx or animation[animationType].dy then + print('animation has displacement') + if frame.last then + lastFrame = frame.last + local dp = lastFrame[animationType]:GetProgress() + if animation[animationType].dx then + local dx = dp * animation[animationType].x + shiftX = (lastFrame.string:GetStringWidth() - dx) * animation[animationType].dx + end + if animation[animationType].dy then + local dy = dp * animation[animationType].y + shiftY = (lastFrame.string:GetStringHeight() - dy) * animation[animationType].dy + print(' ', 'h=', floor(lastFrame.string:GetStringHeight()), 'dY=', dy, 'offsetY=', shiftY) + end + print(cWord('lastFrame hit:'), lastFrame and lastFrame:GetName(), cNum(shiftX), cNum(shiftY)) + end + end + + -- find a usable frame + local currentFrame + for i, ct in ipairs(frame.active) do + if not currentFrame then + if ct.discard then + ct.discard= nil + currentFrame = ct + end + end + + if lastFrame and ct.animationType == animationType and not ct.discard then + --print('lastFrame defined, check for overlap') + if shiftY > 0 then + print(cWord(' * vertical shift'), cNum('+'..floor(shiftY))) + ct.y = ct.y + shiftY + end + if shiftX > 0 then + print(cWord(' * horizontal shift'), cNum('+'..floor(shiftX))) + ct.x = ct.x + shiftX + end + ct:SetPoint(ct.point, frame, ct.point, ct.x, ct.y) + end + end + -- if no expired frames became available, make a new one (should max at 20 or so if groupings are right) + if not currentFrame then + currentFrame = mod.NewCombatMessage(frame) + print(cNum(' creating new string object for the heap')) + end + + print(cText(' * Starting'), cPink(animationType), 'on', cKey(currentFrame:GetName()), ' ['..cNum(currentFrame.index)..']') + + if icon then + currentFrame.icon:Show() + currentFrame.icon:SetTexture(icon) + else + currentFrame.icon:Hide() + end + if fontKey then + local newFont = fontKey and textFonts[fontKey] or defaultFont + + local path, size, flags = currentFrame.string:GetFont() + path = newFont[1] or path + size = newFont[2] or size + flags = newFont[3] or flags + print(cText('font ('..cWord(fontKey)..'):'), path, size, flags) + local result = currentFrame.string:SetFont(path, size, flags) + print(cNum(' result:'), cNum(result), currentFrame.string:GetFont()) + --currentFrame.fontKey = fontKey + end + + currentFrame.animationType = animationType + currentFrame.string:SetText(text) + local cHeight = currentFrame.string:GetStringHeight() + currentFrame:SetSize(currentFrame.string:GetStringWidth(), cHeight) + currentFrame.icon:SetSize(cHeight, cHeight) + currentFrame.y = 0 + currentFrame.x = 0 + currentFrame:SetPoint(currentFrame.point, frame, currentFrame.point, currentFrame.x, currentFrame.y) + currentFrame[animationType]:Play() + frame.last = currentFrame +end + +local GetTextFormatFunc = function(amount, overKill, absorbed, blocked, multistrike, spellName, sourceName, destName) + local sub_text = { + ['%d'] = amount, + ['%o'] = overKill, + ['%a'] = absorbed, + ['%b'] = blocked, + ['%m'] = multistrike, + ['%s'] = spellName, + ['%n'] = sourceName, + ['%t'] = destName, + } + local func = function(token) + print(cPink('gsub run:'), token) + return sub_text[token] + end + return func +end + +--- builds CT messages from combat log event data +-- separated from frame interaction for auxiliary events such as combat/loot/etc +local CreateDamageText = function(frame, timestamp, combatEvent, sourceName, destName, spellID, spellName, effectSchool, amount, overKill, resisted, blocked, absorbed, critical, glancing, crushing, isOffHand, multistrike, ticks) + if combatEvent:match('^SWING') then + spellID = 1 + spellName = 'Attack' + elseif combatEvent:match('^RANGE') then + spellID = 2 + spellName = 'Auto Shot' + end + if not combatEvent:match('DAMAGE') then + return + end + + + local fontKey = 'font1' + local icon = GetSpellTexture(spellID) + local animationType = defaultAnimation + local text = amount + if textFormat[combatEvent] then + local tString, fontKey = unpack(textFormat[combatEvent]) + if amount > 1000000 then + amount = (floor(amount/100000)/10) ..'M' + elseif amount > 1000 then + amount = (floor(amount/100)/10) ..'k' + end + + text = tString:gsub('%%[doabsnt]', GetTextFormatFunc(amount, overKill, absorbed, blocked, multistrike, spellName, sourceName, destName)) + print("** font override:", '"'..cText(tString)..'",', cPink(font), cNum(size), cWord(outline)) + end + + print('** getting color data', cText(spellName)) + if type(effectSchool) == 'number' then + text = SpellSchoolColor(effectSchool) ..text..'|r' + end + + if overKill > 0 then + text = overKillModifier:format(text, overKill) + animationType = overKillAnimation + fontKey = overKillFont or fontKey + end + if critical then + text = criticalModifier:format(text) + animationType = criticalAnimation + fontKey = criticalFont or fontKey + end + if absorbed then + text = absorbedModifier:format(text, absorbed) + animationType = absorbedAnimation + fontKey = absorbedFont or fontKey + end + if blocked then + text = blockedModifier:format(text, blocked) + animationType = blockedAnimation + fontKey = blockedFont or fontKey + end + if multistrike then + text = multistrikeModifier:format(text, multistrike) + animationType = multistrikeAnimation + fontKey = multistrikeFont or fontKey + end + + print(ticks) + if ticks then + text = groupedModifier:format(text, ticks) + animationType = groupedAnimation + fontKey = groupedFont or fontKey + end + + + print('** sending format to SCT:', text, icon, animationType, fontKey) + + + mod.AddCombatMessage(frame, text .. '|r', icon, animationType, fontKey) +end + +local CT_ShowConsolidated = function() + for spellName, queuedSpell in pairs(groupedQueue) do + local isChannel, minDelay, combatEvent, sourceName, destName, spellID, school, SCT, timestamp = unpack(queuedSpell) + for i, v in ipairs(queuedSpell) do + print(' ', i, '=', v) + end + + print(spellName, 'vars:', spellID, spellName, school, SCT, timestamp) + if groupedEvents[spellName] and #groupedEvents[spellName] ~= 0 then + local amount, overKill, resisted, blocked, absorbed, critical, glancing, crushing, multistrike, hit = 0, -1, 0, 0, 0, 0, 0, 0, 0, 0 + for i, line in ipairs(groupedEvents[spellName]) do + -- extra strike? + --{amount, overKill, resisted, blocked, absorbed, critical, glancing, crushing, multistrike} + local amount_n, overKill_n, resisted_n, blocked_n, absorbed_n, critical_n, glancing_n, crushing_n, multi_n, sourceGUID, destGUID, sourceName, destName = unpack (line) + + amount = amount + amount_n + if overKill_n > 0 then overKill = overKill + overKill_n end + if blocked_n then blocked = blocked + line[4] end + if absorbed_n then absorbed = absorbed + line[5] end + if critical_n then critical = critical + 1 end + if multi_n then multistrike = multistrike + 1 end + + hit = hit + 1 + end + if overKill == -1 then + overKill = overKill + 1 + end + wipe(groupedEvents[spellName]) + groupedQueue[spellName] = nil + print(' expelling', spellName, cText('A:'), cNum(amount), cText('O:'), cNum(overKill), cText('Ticks:'), cNum(hit), cText('Crits:'), cNum(critical), cText(school)) + print(SCT, timestamp, combatEvent, sourceName, destName, spellID, spellName, school, amount, overKill, resisted, blocked, absorbed, critical, glancing, crushing, multistrike, hit) + CreateDamageText(SCT, timestamp, combatEvent, sourceName, destName, spellID, spellName, school, amount, -1, nil, nil, nil, false, glancing, crushing, false, multistrike, hit) + end + end +end + +local CT_ConsolidateText = function (self, timestamp, sourceGUID, destGUID, sourceName, destName, spellID, spellName, school, amount, overKill, resisted, blocked, absorbed, critical, glancing, crushing, isOffHand, multistrike) + local archive = groupedSpells[spellName] and groupedSpells[spellName] or groupedSpells.global + local isChannel, minDelay, combatEvent = unpack(archive) + if not groupedEvents[spellName] then + groupedEvents[spellName] = {} + end + + if #groupedEvents[spellName] == 0 then + groupedQueue[spellName] = {isChannel, minDelay, combatEvent, sourceName, destName, spellID, school, self, timestamp} + T:ScheduleTimer(CT_ShowConsolidated, minDelay) + print(' starting archive for', select(7, unpack(archive))) + else + print(' recording into archive', cText(spellName)) + end + tinsert(groupedEvents[spellName], {amount, overKill, resisted, blocked, absorbed, critical, glancing, crushing, multistrike, sourceGUID, destGUID, sourceName, destName, sourceName, destName,}) +end + +local CT_OnCast = function(self, event, unit, spellName, lineID, spellID) + if unit ~= 'player' and unit ~= 'pet' then + return + end + + if groupedSpells[spellName] then + print(cText('** Spell casting info received')) + local isChannel, delay = unpack(groupedSpells[spellName]) + if isChannel and event == 'CHANNEL_STOP' and groupedEvents[spellName] then + T:ScheduleTimer(CT_ShowConsolidated, delay) + else + if not groupedEvents[spellName] then + groupedEvents[spellName] = {} + end + end + end +end + +local CT_Unlock = function(str) + for i, CT in pairs(mod.CombatTextFrames) do + local frame = CT.frame + frame.configMode = (frame.configMode == nil) and true or nil + frame:RegisterForDrag(frame.configMode and 'LeftButton' or nil) + frame:EnableMouse(frame.configMode and true or false) + print(i, frame.configMode and 'ON' or 'OFF') + for _, reg in ipairs(frame.configRegions) do + if frame.configMode then + reg:Show() + else + reg:Hide() + end + end + + if frame.configMode then + CT.configTimer = T:ScheduleRepeatingTimer(function() + print(i, 'config tick') + for i, s in ipairs(CT.sample) do + CT.OnEvent(frame, unpack(s)) + end + end, 2) + else + print(CT.configTimer) + T:CancelTimer(CT.configTimer) + end + + end +end + +--- check for sectors +local queue = {} +mod.OnDamage = function(self, event, ...) + local isVisible + + local timestamp, combatEvent = ... + print(cText('* CT'), cKey(combatEvent)) + if combatEvent == 'UNIT_DIED' then + return + end + local sourceGUID, sourceName, sourceFlags, _, destGUID, destName, destFlags, _, spellID, spellName, spellSchool = select(4, ...) + print(' from', cPink(sourceGUID), 'spell', cNum(spellID), cText(spellName), '->', cKey(destGUID)) + + -- SWING starts at arg 10, SPELL/RANGE start at arg 13, ENVIRONMENTAL starts at arg 8 + local offset = 15 + print(combatEvent:sub(0,3)) + if combatEvent:sub(0,3) == 'SWI' then + offset = 10 + elseif combatEvent:sub(0,3) == 'ENV' then + offset = 8 + end + local amount, overKill, effectSchool, resisted, blocked, absorbed, critical, glancing, crushing, isOffHand, multistrike = select(offset, ...) + + print(' dmg', amount, overKill) + + local sc = SpellSchoolColors[effectSchool] + if groupedSpells[spellName] then + print('* ', cText(spellName), 'to consolidator') + CT_ConsolidateText(self, timestamp, sourceGUID, destGUID, sourceName, destName, spellID, spellName, effectSchool, amount, overKill, resisted, blocked, absorbed, critical, glancing, crushing, isOffHand, multistrike) + return + end + + print('displaying on', cWord(self:GetName())) + CreateDamageText(self, timestamp, combatEvent, sourceName, destName, spellID, spellName, effectSchool, amount, overKill, resisted, blocked, absorbed, critical, glancing, crushing, isOffHand, multistrike) +end + +mod.maxDotFrame = 1 +mod.OnDotEvent = function (self, event, timestamp, combatEvent, ...) + print(cWord('DOT'), combatEvent) + local sourceGUID, sourceName, sourceFlags, _, destGUID, destName, destFlags, destExtraFlags, spellID, spellName, castSchool, amount, overKill, resisted, blocked, absorbed, critical, glancing, crushing, isOffHand, multistrike = select(2, ...) + print(cText('dot from'), cWord(sourceGUID), 'to', cKey(destGUID)) + if sourceGUID == T.GUID then + local p = mod.PeriodicTable + p[destGUID] = p[destGUID] or {} + local unit = p[destGUID] + if not p[spellID] then + if not p.frames[#p.frames] then + unit[spellID] = CreateFrame('Frame', 'DotBar'..mod.maxDotFrame, p, 'TkDotBarTemplate') + mod.maxDotFrame = mod.maxDotFrame + 1 + unit[spellID].dotID = mod.maxDotFrame + + print(' create new frame ['..cKey(unit[spellID]:GetID(), '] for'), cWord(spellName), cKey(destGUID)) + else + unit[spellID] = p.frames[#p.frames] + p.frames[#p.frames] = nil -- remove that entry + print(' recycling frame ['..cKey(unit[spellID].dotID, '] for'), cWord(spellName), cKey(destGUID)) + end + + unit[spellID]:Show() + end + local dot = unit[spellID] + local time = GetTime() + end +end + + + + +function mod:OnInitialize() + print('This is a thing.') + self.UNIT_SPELLCAST_SUCCEEDED = CT_OnCast + self.UNIT_SPELLCAST_CHANNEL_START = CT_OnCast + self.UNIT_SPELLCAST_CHANNEL_STOP = CT_OnCast +end + +function mod:OnInitialize() + mod.db = TurokData.CombatText + db = TurokData.CombatText + myGUID = T.GUID + mod.PeriodicTable = mod.PeriodicTable or CreateFrame('Frame', 'TurokPeriodicFrame', UIParent) + mod.PeriodicTable.frames = {} + + local m = mod.db.textModifiers + --- These values are going to be looked up a lot, so cache as close as possible + criticalModifier = m.critical[1] or '%s CRIT' + criticalAnimation = m.critical[2] or 'slide' + criticalFont = m.critical[3] + + absorbedModifier = m.absorbed[1] or '%s ABS' + absorbedAnimation = m.absorbed[2] or 'slide' + absorbedFont = m.absorbed[3] + + blockedModifier = m.blocked[1] or '%s BLK' + blockedAnimation = m.blocked[2] or 'slide' + blockedFont = m.blocked[3] + + overKillModifier = m.overKill[1] or '%s KILL' + overKillAnimation = m.overKill[2] or 'slide' + overKillFont = m.overKill[3] + + multistrikeModifier = m.multistrike[1] or '%s MS' + multistrikeAnimation = m.multistrike[2] or 'slide' + multistrikeFont = m.multistrike[3] + + groupedModifier = m.grouped[1] or '%s' + groupedAnimation = m.grouped[2] or 'slide' + groupedFont = m.grouped[3] + + --- Same as above, but for specific table values, key is determined by the combat event + defaultAnimation = mod.db.defaultAnimation + defaultFont = mod.db.defaultFont + for k,v in pairs(mod.db.textFormat) do + textFormat[k] = {v[1], v[2]} + print('imported textFormat.'..k, cText(textFormat[k][1]), cNum(textFormat[k][2])) + end + for k,v in pairs(mod.db.textFonts) do + textFonts[k] = {v[1] or defaultFont[1], v[2] or defaultFont[2], v[3] or defaultFont[3]} + print('imported font.'..k, cText(textFonts[k][1]), cNum(textFonts[k][2]), cWord(textFonts[k][3])) + end + + for k,v in pairs(mod.db.animation) do + animation[k] = {} + animation[k].x = v.x + animation[k].y = v.y + animation[k].dx = v.dx + animation[k].dy = v.dy + animation[k].fromScale = v.fromScale + animation[k].toScale = v.toScale + animation[k].deviation = v.deviation + animation[k].change = v.change + animation[k].fromAlpha = v.fromAlpha + animation[k].toAlpha = v.toAlpha + animation[k].duration = v.duration + end +end + +function mod:OnEnable() + T:RegisterChatCommand('tkc', CT_Unlock) + + --- Populate CT frames + for name, CT in pairs(mod.CombatTextFrames) do + print('create CT', name) + -- make frame + CT.frame = CT.frame or CreateFrame('Frame', SCT_NAME:format(name), UIParent, SCT_TEMPLATE) + + -- local vars + local db = db[name] or db + local frame = CT.frame + + -- script defs + frame.IsFrameEvent = CT.trigger + frame.name = name + frame.lineID = 0 + frame.expired = {} + frame.active = {} + + -- frame defs + frame:SetPoint(db.anchor, db.parent, db.anchorTo, db.x, db.y) + frame:RegisterEvent('COMBAT_LOG_EVENT_UNFILTERED') + print('bound ', name, 'with', CT.OnEvent) + db.sample = {} + local logged = {} + frame:SetScript('OnEvent', function(self, e,...) + if CT.trigger(e, ...) then + print('event trigger fired', name) + if #db.sample < 5 and not logged[select(2,...)] then + logged[select(2,...)] = true + tinsert(db.sample, {e, ...}) + end + + CT.OnEvent(frame, e, ...) + end + end) + + -- configurators + frame.configHeader:SetText(name) + frame:EnableMouse(false) + + -- pre-pop some text frames + for i = (CT.lineID or 1), SCT_PREGAME do + print(frame:GetName(), 'pre-pop #'..i) + mod.NewCombatMessage(frame) + end + end +end + + +local damageEvents = { + ['SPELL_DAMAGE'] = true, + ['SPELL_PERIODIC_DAMAGE'] = true, + ['SWING_DAMAGE'] = true, + ['RANGE_DAMAGE'] = true, + ['SPELL_HEAL'] = true, +} +mod.CombatTextFrames = { + Incoming = { + trigger = function(e, _, c, _, _, _, _, _, d) return (d == T.GUID and damageEvents[c]) end, + OnEvent = mod.OnDamage, + sample = { + {"COMBAT_LOG_EVENT_UNFILTERED", 1455887795.271, "SPELL_HEAL", false, "Player-3684-07235A4E", "Klakyn", 1297, 0, "Player-3684-07235A4E", "Klakyn", 1297, 0, 143924, "Leech", 1, 93, 93, 0, false, false, }, + } + }, + Outgoing = { + trigger = function(e, _,c,_, s) return (s == T.GUID and damageEvents[c]) end, + OnEvent = mod.OnDamage, + sample = { + { + "COMBAT_LOG_EVENT_UNFILTERED", 1455887795.006, "SPELL_DAMAGE", false, "Player-3684-07235A4E", "Klakyn", 1297, 0, "Creature-0-3684-1116-7-87761-0000C32119", "Dungeoneer's Training Dummy", 68136, 0, 589, "Shadow Word: Pain", 32, 3944, -1, 32, nil, nil, nil, false, false, false, false, false, }, { + "COMBAT_LOG_EVENT_UNFILTERED", 1455887795.271, "SPELL_HEAL", false, "Player-3684-07235A4E", "Klakyn", 1297, 0, "Player-3684-07235A4E", "Klakyn", 1297, 0, 143924, "Leech", 1, 93, 93, 0, false, false, }, { + "COMBAT_LOG_EVENT_UNFILTERED", 1455887797.377, "SPELL_PERIODIC_DAMAGE", false, "Player-3684-07235A4E", "Klakyn", 1297, 0, "Creature-0-3684-1116-7-87761-0000C32119", "Dungeoneer's Training Dummy", 68136, 0, 589, "Shadow Word: Pain", 32, 3944, -1, 32, nil, nil, nil, false, false, false, false, false, }, { + "COMBAT_LOG_EVENT_UNFILTERED", 1455887812.702, "SWING_DAMAGE", false, "Player-3684-07235A4E", "Klakyn", 1297, 0, "Creature-0-3684-1116-7-87761-0000C32119", "Dungeoneer's Training Dummy", 68136, 0, 279, -1, 1, nil, 120, nil, false, false, false, false, false, }, -- [4] + } + }, + DoTTracker = { + trigger = function(e, _, c, _, s) return (s == T.GUID and dotEvents[c]) end, + OnEvent = mod.OnDotEvent, + sample = { + {"COMBAT_LOG_EVENT_UNFILTERED", 1455887795.006, "SPELL_AURA_APPLIED", false, + "Player-3684-07235A4E", "Klakyn", 1297, 0, + "Creature-0-3684-1116-7-87761-0000C32119", "Dungeoneer's Training Dummy", 68136, 0, + 589, "Shadow Word: Pain", 32, "DEBUFF", }, + {"COMBAT_LOG_EVENT_UNFILTERED", 1455887797.377, "SPELL_PERIODIC_DAMAGE", false, + "Player-3684-07235A4E", "Klakyn", 1297, 0, + "Creature-0-3684-1116-7-87761-0000C32119", "Dungeoneer's Training Dummy", 68136, 0, + 589, "Shadow Word: Pain", 32, 3944, -1, 32, nil, nil, nil, false, false, false, false, false, }, + {"COMBAT_LOG_EVENT_UNFILTERED", 1455887807.199, "SPELL_AURA_REMOVED", false, + "Player-3684-07235A4E", "Klakyn", 1297, 0, + "Player-3684-07235A4E", "Klakyn", 1297, 0, + 15473, "Shadowform", 32, "BUFF", }, + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Combat/CombatLog.xml Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,186 @@ +<Ui> + <Frame name="TurokCombatMessageTemplate" virtual="true"> + <Anchors> + <Anchor point="BOTTOMLEFT" /> + </Anchors> + <Layers> + <Layer level="OVERLAY"> + <Texture parentKey="icon" hidden="true"> + <Size x="28" y="28" /> + <Anchors> + <Anchor point="RIGHT" relativePoint="LEFT" x="-1" y="0" /> + </Anchors> + <TexCoords top="0.15" left="0.15" right=".85" bottom="0.85" /> + </Texture> + </Layer> + <Layer level="OVERLAY"> + <Font name="$parentTkMessageFont" parentKey="font" font="InterfaceAddons\Turok\Media\font\ArchivoNarrow-Regular.ttf" > + <FontHeight> + <AbsValue val="12" /> + </FontHeight> + </Font> + <FontString name="$parentMessageText" parentKey="string" inherits="$parentTkMessageFont"> + <Anchors> + <Anchor point="BOTTOMLEFT" /> + </Anchors> + </FontString> + </Layer> + </Layers> + <Animations> + <AnimationGroup name="pop" parentKey="pop" ignoreFramerateThrottle="true"> + <Scale parentArray="scale" toScaleX="1" fromScaleX="1.75" toScaleY="1" fromScaleY="1.75" duration="0.12" order="1"/> + <Translation parentArray="translation" offsetX="85" offsetY="70" order="1" duration="0.32" /> + <Alpha parentArray="alpha" duration="0.75" order="1" change="-1" startDelay="2.25"/> + <Scripts> + <OnPlay> + self:GetParent():Show() + </OnPlay> + <OnStop> + local ct = self:GetParent() + ct.discard = true + ct:Hide() + </OnStop> + <OnFinished> + local ct = self:GetParent() + ct.discard = true + ct:Hide() + </OnFinished> + </Scripts> + </AnimationGroup> + <AnimationGroup name="$parent_FadeAway" parentKey="slide" ignoreFramerateThrottle="true"> + <Translation parentArray="translation" offsetX="0" offsetY="300" duration="3" order="1" /> + <Alpha parentArray="alpha" change="-1" startDelay="2.25" duration="0.75" order="1" /> + <Scripts> + <OnPlay> + self:GetParent():Show() + </OnPlay> + <OnStop> + local ct = self:GetParent() + ct.discard = true + ct:Hide() + </OnStop> + <OnFinished> + local ct = self:GetParent() + ct.discard = true + ct:Hide() + </OnFinished> + </Scripts> + </AnimationGroup> + <AnimationGroup name="$parent_SideAway" parentKey="lateralSlide" ignoreFramerateThrottle="true"> + <Translation parentArray="translation" offsetX="300" offsetY="0" duration="3" order="1" /> + <Alpha parentArray="alpha" change="-1" startDelay="2.25" duration="0.75" order="1" /> + <Scripts> + <OnPlay> + self:GetParent():Show() + </OnPlay> + <OnStop> + local ct = self:GetParent() + ct.discard = true + ct:Hide() + </OnStop> + <OnFinished> + local ct = self:GetParent() + ct.discard = true + ct:Hide() + </OnFinished> + </Scripts> + </AnimationGroup> + </Animations> + </Frame> + + <Frame name="TurokSCTAnchorTemplate" parent="UIParent" virtual="true" movable="true" resizable="true"> + <ResizeBounds> + <minResize x="40" y="40" /> + <maxResize x="1900" y="1200" /> + </ResizeBounds> + <Scripts> + <OnLoad> + </OnLoad> + <OnMouseDown> + if button ~= 'LeftButton' then + return + end + + print(self.sizer:GetCenter(), self.sizer:IsMouseOver()) + if self.sizer:IsMouseOver() then + self:StartSizing() + else + self:StartMoving() + end + self:SetScript('OnUpdate', function() + self.configHeader:SetText(self.name .."\n" + ..math.floor(self:GetWidth())..' x '..math.floor(self:GetHeight()).."\n(" + ..math.floor(self:GetLeft())..', '.. math.floor(self:GetTop())..')') + print('hammer') + end) + </OnMouseDown> + <OnMouseUp> + if button ~= 'LeftButton' then + return + end + self:SetScript('OnUpdate', nil) + print('stop') + self:StopMovingOrSizing() + </OnMouseUp> + </Scripts> + <Anchors> + <Anchor point="CENTER" relativeTo="UIParent" /> + </Anchors> + <Size x="400" y="500" /> + <Layers> + <Layer level="BACKGROUND"> + <Texture setAllPoints="true" parentArray="configRegions" hidden="true"> + <Color r="0" g="0" b="0" a="1" /> + </Texture> + </Layer> + <Layer level="OVERLAY"> + <FontString parentArray="configRegions" parentKey="configHeader" inherits="TurokFontDetail" text="configHeader" hidden="true"> + <Anchors> + <Anchor point="CENTER" /> + </Anchors> + </FontString> + </Layer> + <Layer level="HIGHLIGHT"> + <Texture parentArray="configRegions" parentKey="sizer" hidden="true"> + <Size x="24" y="24" /> + <Color r="1" g="1" b="1" a="1" /> + <Anchors> + <Anchor point="BOTTOMRIGHT" /> + </Anchors> + </Texture> + </Layer> + </Layers> + </Frame> + + <Frame name="TkDotBarTemplate" virtual="true"> + <Size x="120" y="16" /> + <Layers> + <Layer level="BACKGROUND"> + <Texture name="$parentBackground" parentKey="background" setAllPoint="true"> + <Color a="1" r="0" b="0" g="0" /> + </Texture> + </Layer> + <Layer level="ARTWORK"> + <Texture name="$parentForeground" parentKey="foreground"> + <Color a="1" r="1" b="1" g="0" /> + </Texture> + </Layer> + </Layers> + </Frame> + + <Frame name="TkCombatLogTemplate" parent="UIParent" virtual="true"> + <Scripts> + <OnLoad> + print('Layout', self:GetName(), 'has arrived.') + </OnLoad> + <OnHide> + print('Layout', self:GetName(), ' hidden.') + </OnHide> + </Scripts> + <Frames> + <ScrollingMessageFrame> + + </ScrollingMessageFrame> + </Frames> + </Frame> +</Ui> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Combat/Powerbar.Init.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,119 @@ +--- ${PACKAGE_NAME} +-- @file-author@ +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +-- Created: 12/28/2015 8:01 AM + + +Turok.defaults.powerbar = { + trace = true, + alpha_ooc = 0.1, + alpha_full_ooc = .1, + alpha = 1, + alpha_fade_out = 5, + alpha_fade_in = 0.15, + combatFade = true, + graph_safe = {.5,.5,.5,1}, + graph_alert = {1,0,0,1}, + graph_blend = 'ADD', + graph_blend_alert = 'BLEND', + foreground_color = {.1,.5,1 ,1}, + background_color = {0.2,0.2,0.2,0.2}, + y = -188, + x = 0, + height = 20, + width = 300, + padding = 0, + spacing = 1, + strata = 'BACKGROUND', + level = 5, + resource_max_noise = [[Interface\Addons\Turok\Media\sound\SquishFart.ogg]], + resource_low_noise = [[]], + resource_empty_noise = [[Interface\Addons\Turok\Media\sound\wilhelm.ogg]], + font = [[Interface\Addons\Turok\Media\font\ArchivoNarrow-Bold.ttf]], + secondary = { + anchor = 'BOTTOMLEFT', + anchorTo = 'TOPLEFT', + parent = 'TkPowerBar', + spacing = 1, + padding = 0, + height = 10, + foreground_inset = 0, + foreground_color = {1,1,1,.4}, + foreground_blend = 'ADD', + background_color = {0,0,0,0}, + background_blend = 'BLEND', + x = 0, y = 1, + }, + secondary1 = { + anchor = 'BOTTOMLEFT', + anchorTo = 'TOPLEFT', + parent = 'TkPowerBar', + spacing = 1, + padding = 0, + height = 7, + foreground_inset = 0, + foreground_color = {.7, .4, 1, 1}, + foreground_blend = 'ADD', + background_color = {0,0,0,0.3}, + background_blend = 'BLEND', + x = 0, y = 2, + }, + secondary2 = { + anchor = 'BOTTOMLEFT', + anchorTo = 'TOPLEFT', + parent = 'TkPowerBar', + spacing = 1, + padding = 0, + height = 5, + foreground_inset = 0, + foreground_color = {1,1,1,.8}, + foreground_blend = 'ADD', + background_color = {0,0,1,0}, + background_blend = 'BLEND', + x = 0, y = 8, + }, + secondary3 = { + anchor = 'BOTTOMLEFT', + anchorTo = 'TOPLEFT', + parent = 'TkPowerBar', + spacing = 1, + padding = 0, + height = 5, + foreground_inset = 0, + foreground_color = {1,.5,.2,1}, + foreground_blend = 'MOD', + background_color = {0,0,1,0}, + background_blend = 'BLEND', + x = 0, y = 16, + + }, + + powerText = { + y = 0, + x = 6, + anchor='LEFT', + anchorTo='LEFT', + parent = 1, + justifyH = 'LEFT', + justifyV = 'MIDDLE', + text_color = {1,1,1,1}, + size = 18, + }, + secondaryText = { + y = 0, + x = -6, + anchor='RIGHT', + anchorTo='RIGHT', + parent = 1, + justifyH = 'RIGHT', + justifyV = 'BOTTOM', + text_color = {1,1,0,1}, + size = 18, + }, + graph1 = { + foreground_color = {.2,1,.5,1 }, + foreground_texture = '', + + }, +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Combat/Powerbar.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,585 @@ +-- User: Krakyn +-- Created: 12/15/2015 7:31 PM +--[[ +-- Turok by @project-author@ +-- @file-author@ +-- @file-revision@:@project-revision@ +-- @file-date-iso@ +-- +-- Visible element operations begin here +--]] +local _G = _G +local T, pairs, select, setmetatable, type, tinsert = _G.Turok, pairs, select, setmetatable, type, tinsert +local mod = T:NewModule("PowerBar") +local UnitPower, UnitPowerMax, GetTalentInfoByID, GetTalentInfo, CreateFrame = UnitPower, UnitPowerMax, GetTalentInfoByID, GetTalentInfo, CreateFrame +local bar, db, prototype -- convenience upvalues +local cType, cText, cNum, cWord, cKey, cPink, cBool = cText, cNum, cWord, cKey, cPink, cBool + --@debug +local cType, cText, cNum, cWord, cKey, cPink, cBool = cText, cNum, cWord, cKey, cPink, cBool +local print = function(...) + if _G.Devian and _G.DevianDB.workspace ~= 1 then + _G.print('PowerBar', ...) + end +end +print('Peep!', ...) +local addon, tg = ... +tg.what = tostring(tg.what)..'more' +print(tg.what) +--@end-debug@ +mod.OnInitialize = function(self) + self.UNIT_SPELLCAST_START = self.SpellCastEvent + self.UNIT_SPELLCAST_STOP = self.SpellCastEvent + self.UNIT_SPELLCAST_SUCCEEDED = self.SpellCastEvent + self.UNIT_SPELLCAST_CHANNEL_START = self.SpellCastEvent + self.UNIT_SPELLCAST_CHANNEL_STOP = self.SpellCastEvent + self.SPELL_UPDATE_COOLDOWN = self.SpellCooldownEvent + self.PLAYER_REGEN_DISABLED = self.CombatStart + self.PLAYER_REGEN_ENABLED = self.CombatEnd + self.focusbar = {} + self.parserLog = {} + self.currentParse = {} +end +local SPELL_POWER_MANA, SPELL_POWER_ENERGY, SPELL_POWER_RAGE, SPELL_POWER_FOCUS = SPELL_POWER_MANA, SPELL_POWER_ENERGY, SPELL_POWER_RAGE, SPELL_POWER_FOCUS +local SPELL_POWER_SHADOW_ORBS = SPELL_POWER_SHADOW_ORBS +local SPELL_POWER_SOUL_SHARDS, SPELL_POWER_BURNING_EMBERS, SPELL_POWER_DEMONIC_FURY = SPELL_POWER_SOUL_SHARDS, SPELL_POWER_BURNING_EMBERS, SPELL_POWER_DEMONIC_FURY +local SPELL_POWER_HOLY_POWER = SPELL_POWER_HOLY_POWER +local SPELL_POWER_CHI = SPELL_POWER_CHI +local SPELL_POWER_COMBO_POINTS = SPELL_POWER_COMBO_POINTS + +-- indexes for talent_update cleanup +mod.secondary_rows = {} +mod.disabled_frames = {} + +--[[ +-- Prototype list naming all the data sources and events that need to be handled for the logged in character +-- .power_type {[bliz const] = event token} list of resources represented by global SPELL_POWER_* constants in the blizzard ui and the UNIT_POWER* token argument representing it +-- .frame string frameXML template +-- .spells {[spell name/id] = {events}} list of spells tracked by the updater +-- .secondary {[aura name] = {}} list of auras tracked as secondary resources such as Thrill of Hunt, Anticipatin, Evangelism, etc. +--]] +mod.prototype = { + ['HUNTER'] = { + primary = { + [1] = {"FOCUS", SPELL_POWER_FOCUS}, -- array of power type constants associated to event strings + }, + frame = 'TkThinComboTemplate', ---------------------- desired frame template + spells = { + ["Steady Shot"] = {'UNIT_SPELL_CAST_SUCCEEDED', 'UNIT_SPELLCAST_STOP', 'UNIT_SPELLCAST_START'} -- spell events that this frame should listen to + }, + secondary = {}, + spec = { + [1] = { + secondary = { + ['Frenzy'] = { + type = 'aura', + order = 1, + scale = 5, + filters = 'HELPFUL', + max = 5, + specPage = 1, + unit = 'player', + spellID = 19623, + }, + ['Focus Fire'] = { + type = 'aura', + max = 40, + order = 2, + scale = 5, + line = 3, --------------- use this subtext value instead of count field + filters = 'HELPFUL', + specPage = 1, + unit = 'player', + spellID = 19623, + } + } + }, + [2] = { + secondary = { ------------------------ list of buffs that act as a secondary resource + ['Thrill of the Hunt'] = { + order = 1, + unit = 'player', + type = 'aura', + max = 3, + scale = 5, + filters = 'HELPFUL', + talent = {4,3}, + display = 'progressbar' + }, + }, + }, + }, + }, + ['PRIEST'] = { + primary = { + [1] = {'MANA', SPELL_POWER_MANA} + }, + frame = 'TkThinComboTemplate', + secondary = {}, + spec = { + [1] = { + secondary = { + ['Evangelism'] = { + order = 1, + max = 5, + scale = 5, + type='aura', + unit = 'player', + filters = 'HELPFUL|PLAYER', + spellID = 81662, + } + } + }, + [3] = { + primary = { + [1] = {'SHADOW_ORBS', SPELL_POWER_SHADOW_ORBS}, + }, + secondary = { + ["Surge of Darkness"] = { + order = 2, + type = 'aura', + filters = 'HELPFUL|PLAYER', + spellID = 87160, + talentID = 21751, + max = 3, + scale = 5, + unit = 'player', + }, + ["Insanity"] = { + order = 2, + type = 'aura', + binary = true, + regress = true, + size = 1, scale = 1, max = 1, + filters = 'HELPFUL|PLAYER', + spellID = 132573, + unit = 'player', + talentID = 21753}, + } + }, + }, + }, + ['ROGUE'] = { + primary = { + [1] = {'ENERGY', SPELL_POWER_ENERGY}, + [2] = {'COMBO_POINTS', SPELL_POWER_COMBO_POINTS} + }, + frame = 'TkThinComboTemplate', + secondary = { + ['Anticipation'] = { + type = 'aura', + order = 1, + max = 5, + scale = 5, + unit = 'player', + talentID = 19250, + }, + }, + spec = {}, + }, + ['MAGE'] = { + primary = { + [1] = {'MANA', SPELL_POWER_MANA}, + }, + frame = 'TkThinComboTemplate', + secondary = { + + ["Incanter's Flow"] = { + type = 'aura', + unit = 'player', + filters = 'HELPFUL|PLAYER', + spellID = 1463, + max = 5, + scale = 5, + order = 2, + talentID = 16033, + }, + ["Rune of Power"] = { + type = 'aura', + unit = 'player', + filters = 'HELPFUL|PLAYER', + binary = true, + max = 1, + scale = 1, + order = 2, + talentID = 16032, + } + }, + spec = { + [1] = { + secondary = { + ['Arcane Charge'] = { + type ='aura', + unit = 'player', + filters = 'HARMFUL|PLAYER', + spellID = 114664, + scale = 4, + max = 4, + order = 1, + }, + } + }, + [3] = { + secondary = { + ['Fingers of Frost'] = { + type = 'aura', + unit = 'player', + filters = '', + spellID = 112965, + max = 2, + scale = 4, + order = 1, + }, + ['Brain Freeze'] = { + type = 'aura', + unit = 'player', + filters = '', + spellID = 44549, + scale = 4, + max = 2, + order = 1, + mirror = true, + } + } + }, + } + } +} +local P = mod.prototype + +function mod:OnEnable() + self.disabled_freams = { + [T.playerClass] = { + [T.specPage] = {} + } + } + self.watched_units = {} + self.watched_auras = {} + self.watched_spells = {} + self.db = TurokData.powerbar + db = self.db + + self:Prototype_Init() +end +function mod:Prototype_Init() + -- consult prototype vars + prototype = {} + mod.dcopy = function(t1, t2, d) + d = d or '' + for k,v in pairs(t2) do + if type(v) == 'table' then + if type(t1[k]) ~= 'table' then + t1[k] = {} + print(d, 'adding table', cKey(k)) + else + print(d, 'merging tables', cKey(k)) + end + mod.dcopy(t1[k], v, d..' ') + else + if t1[k] then + print(d, 'clobbered', k) + else + print(d, k, '=', cType(v)) + end + t1[k] = v + end + end + end + mod.dcopy(prototype, mod.prototype[T.playerClass]) + if mod.prototype[T.playerClass].spec[T.specPage] then + mod.dcopy(prototype, mod.prototype[T.playerClass].spec[T.specPage]) + end + + mod.thisproto = prototype + + print('|cFFFF0088Template:|r', 'Frame', 'TkPowerBarFrame', UIParent, prototype.frame) + db = self.db + + if bar and bar.GetObjectType then + bar:Hide() + mod.disabled_frames[bar.specPage] = bar + print('putting away old frame') + end + + if not bar then + bar = CreateFrame('Frame', 'TkPowerBar', UIParent, prototype.frame) + end + bar.specPage = T.specPage + bar.specID = T.specID + bar.primary = {} -- {current, max, token} + bar.secondary = {} -- {current, max, token} + bar.aura = {} -- {name, duration, expires, unit, flags} + bar.spell = {} -- copy of the last T.spellevent match + print(' setting layout', db) + print(bar:GetName()) + T.SetFrameLayout(bar, prototype.cvars and db[prototype.cvars] or db) + T.SetStatusTextures(bar, db) + + print(' setting methods') + bar.Init = mod.Bar_Init + bar.Event = mod.Bar_Event + bar.Update = mod.Bar_Update + + + --- loop through aura definitions and flag accordingly + print('Primary power types:') + for order, power_data in pairs(prototype.primary) do + print( order, unpack(power_data)) + local token, power_type = unpack(power_data) + local power, max = UnitPower('player', power_type), UnitPowerMax('player', power_type) + bar.primary[token] = {power, max, power_type, order} + print(' ', cKey(token), '= {', power, max, power_type, order, '}') + end + + --- go through secondary data args and assign the appropriate source functions + local useAura, useCooldown + local used_rows = {} + if prototype.secondary then + mod.secondary = {} + for name, c in pairs(prototype.secondary) do + local isActive = true + print('parsing extra handler', name) + if c.talentID then + print(c.talentID, T.specPage) + isActive = (type(c.talentID) == 'table') and select(4, GetTalentInfo(unpack(c.talentID), T.specGroup)) or + select(4, GetTalentInfoByID(c.talentID, T.specGroup)) + print(' talentID:', cNum(isActive)) + end + if isActive then + local sc = {} + + sc = c + print(' enable:', cNum(isActive), cWord(c.type)) + if c.type == 'aura' then + sc.spellName = name + if c.binary then + sc.Get = function(self) + print('get: UnitAura', self.unit, self.spellName, c.filters) + local exists = UnitAura(self.unit, self.spellName, nil, self.filters) + return (exists) and 1 or 0 + end + else + sc.Get = function(self) + print('get: UnitAura', self.unit, self.spellName, c.filters) + local _,_,_, count = UnitAura(self.unit, self.spellName, nil, self.filters) + return count or 0 + end + end + + useAura = true + elseif c.type == 'cooldown' then + if c.inverse then + sc.Get = function(self) + local start, duration, enabled = GetSpellCooldown(c.spellID) + sc[1] = (duration > 0) and (GetTime() - start) or c.max + print('get: GetSpellCooldown (inverse)', c.spellID, '=', sc[1]) + end + else + sc.Get = function(self) + local start, duration, enabled = GetSpellCooldown(c.spellID) + sc[1] = (duration > 0) and (start + duration - GetTime()) or 0 + print('get: GetSpellCooldown', c.spellID, '=', sc[1]) + end + end + useCooldown = true + end + print(' committing', name, 'to row', sc.order) + bar.secondary[name] = sc + used_rows[sc.order] = true -- index the drawn rows for talent_update + end + end + end + + + if useAura then bar:RegisterEvent('UNIT_AURA') end + if useCooldown then bar:RegisterEvent('UNIT_SPELLCAST_SUCCEEDED') end + + bar:SetScript('OnUpdate', nil) -- make sure any xml embeds are cleaned out + bar:SetScript('OnEvent', mod.Bar_Event) + bar:RegisterEvent('UNIT_POWER_FREQUENT') + + bar:Init() + bar:Show() + + -- metrics used by data plots + bar.width = db.width + bar.foreground_inset = db.foreground_inset + bar.right_edge = bar:GetRight() + bar.fill_limit = bar.right_edge + bar.foreground.width = bar.width + (bar.foreground_inset) + bar.spacing = 1 + + mod.powerbar = bar +end + +mod.Bar_Init = function(self) + local mainPower, comboPower + for token, power in pairs(self.primary) do + if power[4] == 1 then + mainPower = power + elseif power[4] == 2 then + comboPower = power + end + end + + if mainPower then + local power, max, type, token = unpack(mainPower) + if power and max then + self.powerText:SetText(power) + self:SetProgress(power/max) + end + end + + if comboPower then + local power, max, type, token = unpack(comboPower) + local px = (self.width-db.secondary.spacing* (max -1)-db.secondary.padding*2) / max + self.combo = {} + for i = 1, max do + if not self.combo[i] then + self.combo[i] = self:CreateTexture('TkPrimaryResourcePellet'..i, 'OVERLAY') + end + + local k = i - 1 + local cx = db.secondary.padding + px * k + db.secondary.spacing * k + local cy = db.secondary.padding + self.combo[i]:ClearAllPoints() + self.combo[i]:SetSize(px, db.secondary.height) + self.combo[i]:SetPoint(db.secondary.anchor, self, db.secondary.anchorTo, cx, cy) + --print(' ', self.combo[i]:GetName(), self.pointsize1, cx, cy, self.combo[i]:GetDrawLayer()) + + self.combo[i]:Show() + end + end + + + if self.secondary then + if not self.resources then + print('|cFFFF0000creating resources block') + self.resources = {} + else + local hidecount = 0 + for i, row in pairs(self.resources) do + for j, col in pairs(row) do + col:Hide() + hidecount = hidecount + 1 + end + end + print('hiding', hidecount, 'regions') + end + for name, secondary in pairs(self.secondary) do + local n = secondary.order + local sid = 'secondary'..n + local c = db[sid] or db + if not self.resources[n] then + print(' |cFFFF8800creating resource row') + self.resources[n] = {} + end + local row = self.resources[n] + + print('secondary resource', cText(name), 'max= '..cNum(secondary.max), 'scale= '..cNum(secondary.scale)) + local px = c.padding + local pw = (self.width - c.padding*2 - c.spacing * (secondary.scale - 1)) / secondary.scale + for i = 1, (secondary.max or 1) do + if not row[i] then + row[i] = bar:CreateTexture('TkResourcePellet.'..tostring(secondary.order)..'.'..tostring(i)) + end + row[i]:Show() + row[i]:SetDrawLayer('OVERLAY', sid) + row[i]:SetPoint('BOTTOMLEFT', self, 'TOPLEFT', px, c.y) + row[i]:SetSize(pw, db[sid].height or db.height) + + print(' *', cNum(i), cKey(sid), cNum(px), cNum(c.padding)) + px = px + pw + c.spacing + end + end + end + + mod.Bar_Event(self, nil, 'player') +end + +-- we only want to update at specific points +mod.Bar_Event = function(self, event, ...) + local unit, token = ... + _G.print('Update', event, unit, token) + if token and unit == 'player' then + mod.Bar_Power(self, token) + end + --print(unit, token, ...) + mod.Bar_Aura(bar, event, unit, token, ...) +end + +mod.Bar_Aura = function (self, event, unit) + _G.print('Update','bar updating function called', event, unit) + + + if event == 'UNIT_AURA' or event == nil then + for token, info in pairs(self.secondary) do + local row = self.resources[info.order] + if info.unit == unit then + local count = info.Get(info) + local db = db['secondary'..info.order] or db + for i = 1, info.max do + local palette = (i > count) and ('background_color') or ('foreground_color') + + print(token, i, count, (i > count), palette, unpack(db[palette])) + row[i]:SetTexture(unpack(db[palette])) + end + end + end + end +end + +function mod:Bar_Power(token) + if not self.primary[token] then + return + end + + local p = self.primary[token] + -- 1=cur, 2=max, 3=type, 4=token + p[1] = UnitPower('player', p[3]) + p[2] = UnitPowerMax('player', p[3]) + _G.print('Update',' ', table.concat(self.primary[token],', ')) + + if p[4] == 1 then + _G.print('Update', 'progress:', p[1]/p[2]) + --print(unpack(p)) + self.powerText:SetText(p[1]) + self:SetProgress(p[1]/p[2]) + elseif p[4] == 2 then + --print('update on', token, 'c:', p[1], 'm:', p[2]) + self.secondaryText:SetText(p[1]) + for i = 1, p[2] do + local palette = (i > p[1]) and 'background_color' or 'foreground_color' + self.combo[i]:SetTexture(unpack(db.secondary[palette])) + + end + end +end + +--- Spell parsing +function mod:SpellCastEvent(e, u, spellName, rank, castID, spellID) + if u ~= 'player' then + return true + end + if e == 'UNIT_SPELLCAST_DELAYED' then + elseif e == 'UNIT_SPELLCAST_START' then + bar.casting = true + bar.spellevent = T.spellevent[u] + bar.spell = T.casting[u] + elseif e == 'UNIT_SPELLCAST_CHANNEL_START' then + bar.channeling = true + bar.spellevent = T.spellevent[u] + bar.spell = T.channeling[u] + elseif e == 'UNIT_SPELLCAST_SUCCEEDED' then + elseif e == 'UNIT_SPELLCAST_STOP' then + bar.casting = nil + bar.casting = nil + elseif e == 'UNIT_SPELLCAST_CHANNEL_STOP' then + bar.channeling = nil + bar.channeling = nil + end +end + +function mod:PLAYER_TALENT_UPDATE(event, unit) + print(cText('*** Talent Update'), cKey('Spec:'), cWord(T.specName), cNum(T.specPage)) + mod:Prototype_Init() +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Combat/Powerbar.xml Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,90 @@ +<Ui> + <!-- placed on top of other bars; should be semi-transparent --> + <Texture name="TkGraph" alphaMode="ADD" virtual="true"> + <Colors> + <Color r="1" g="0" b="0" a="0.5" /> + </Colors> + </Texture> + + <!-- StatusBar template inheritor for PowerBar frames --> + <Frame name="TkPowerTemplate" virtual="true" inherits="TurokStatusBar" parent="UIParent" frameStrata="BACKGROUND"> + <Scripts> + <OnLoad> + print('PowerBar', '|cFF44FFFF'..self:GetName()..'|r loaded.') + </OnLoad> + </Scripts> + <Layers> + <Layer level="OVERLAY"> + <FontString name="$parentPowerText" parentKey="powerText" inherits="TurokFont" justifyH="LEFT" textureSubLevel="1"/> + <FontString name="$parentSecondaryText" parentKey="secondaryText" inherits="TurokFontDetail" justifyH="RIGHT" textureSubLevel="1"/> + </Layer> + </Layers> + </Frame> + + + <!-- Secondary powers --> + <Texture name="TkSecondaryPoint1" virtual="true" alphaMode="BLEND" setAllPoints="false" hidden="true" /> + <Texture name="TkSecondaryPoint2" virtual="true" alphaMode="ADD" setAllPoints="false" hidden="true" /> + + + <Frame name="TkComboTemplate" inherits="TkPowerTemplate" virtual="true" frameStrata="BACKGROUND" hidden="true"> + <Layers> + <Layer level="OVERLAY"> + <!-- 6 max chi, 5 max combo --> + <Texture name="$parentCombo1_1" inherits="TkComboPoint" /> + <Texture name="$parentCombo1_2" inherits="TkComboPoint" /> + <Texture name="$parentCombo1_3" inherits="TkComboPoint" /> + <Texture name="$parentCombo1_4" inherits="TkComboPoint" /> + <Texture name="$parentCombo1_5" inherits="TkComboPoint" /> + <Texture name="$parentCombo1_6" inherits="TkComboPoint" /> + <!-- anticipation --> + <Texture name="$parentCombo2_1" inherits="TkAnticipation" /> + <Texture name="$parentCombo2_2" inherits="TkAnticipation" /> + <Texture name="$parentCombo2_3" inherits="TkAnticipation" /> + <Texture name="$parentCombo2_4" inherits="TkAnticipation" /> + <Texture name="$parentCombo2_5" inherits="TkAnticipation" /> + </Layer> + </Layers> + </Frame> + + + <Frame name="TkThinComboTemplate" virtual="true" hidden="true" frameStrata="BACKGROUND"> + <Layers> + <Layer level="BACKGROUND"> + + <Texture name="$parentBackground" parentKey="background" setAllPoints="true"> + <Color r="0" g=".6" b="1" a="0.5" /> + <Size> + <AbsValue y="14" /> + </Size> + </Texture> + </Layer> + <Layer level="BORDER"> + + </Layer> + <Layer level="ARTWORK"> + <Texture name="$parentForeground" parentKey="foreground" setAllPoints="true"> + <Size> + <AbsValue y="14" /> + </Size> + <Color r="0" g=".6" b="1" a="0.5" /> + </Texture> + </Layer> + <Layer level="OVERLAY"> + <!-- 6 max chi, 5 max combo --> + + <FontString name="$parentPowerText" parentKey="powerText" inherits="TurokFont" justifyH="LEFT" textureSubLevel="1"> + <Anchors> + <Anchor point="BOTTOMLEFT" relativeKey="$parent.foreground" /> + </Anchors> + </FontString> + <FontString name="$parentSecondaryText" parentKey="secondaryText" inherits="TurokFontDetail" justifyH="RIGHT" textureSubLevel="1"> + <Anchors> + <Anchor point="BOTTOMRIGHT" relativeKey="$parent.foreground" /> + </Anchors> + </FontString> + </Layer> + </Layers> + </Frame> + +</Ui> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Timer/Aura.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,163 @@ +--- Turok - Aura.lua +-- @file-author@ +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +-- Created: 12/25/2015 5:58 AM +-- Aura data collection +local GetTime, UnitAura, GetSpellDescription, GetSpellInfo = GetTime, UnitAura, GetSpellDescription, GetSpellInfo +local T, _G, tinsert = Turok, _G, tinsert +local mod = T:GetModule("TimerControl") + +--@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('Aura', ...) + end +end +print('Peep!', ...) +--@end-debug@ + +T.defaults.spirit.aura = { + counterText = "%p", + subCounterText = "%.p", + chargesText = "%s", + justifyH = 'CENTER', + justifyV = 'TOP', + leftText = "%p", + rightText = "%n", + + passive = { + icon = { + desaturated = false, + color = {1, 1, 1, 1}, + blend = 'BLEND' + } + }, + active = { + icon = { + desaturated = false, + color = {1, 1, 1, 1}, + blend = 'BLEND' + } + }, +} + +local p = mod.prototype.trigger.aura +p.class = 'trigger' -- identifier values that are visible from function scope +p.type = 'aura' +p.cvars = { -- only define things that could break the frame here +} +p.events = { + ['UNIT_AURA'] = true, +} + +--- takes user supplied values or fills itself with the cvar values provided +p.Init = function(self, auraName, auraFilters, auraUnit) + + _G.print('Prototype', 'Aura.Init') + self.unit = auraUnit and auraUnit or self.dvars.unit + self.spellName = auraName and auraName or self.spellName + self.filters = auraFilters and auraFilters or self.dvars.filters + -- set inversion states, states 0 and 1 are only processed when prevState differs + if self.cvars.inverse then + self.flags = { + active = 0, + active_prev = 2, + passive = 0, + passive_prev = 1, + hidden = 1, + hidden_prev = 0, + } + self.duration = 1 + self.expires = 1 + else + self.flags = { + active = 2, + active_prev = 0, + passive = 1, + passive_prev = 0, + hidden = 0, + hidden_prev = 1} + end + print(cWord('Load:'),cNum(self.spellID or self.inventoryID or self.itemID), cText(self.spellName)) +end + +p.Unload = function(self) + print('unloading events') + for k,v in pairs(p.events) do + self:UnregisterEvent(k) + end +end + +--- Return current status data +p.Query = function(self) + print( ' Q:', self.unit , self.spellName, nil, self.filters) + return UnitAura(self.unit , self.spellName, nil, self.filters) +end + +p.SetText = mod.SetText + +--- Set supplied status data, using the list returned by p.Query() +p.Set = function(self, ...) + self.active, self.rank, _, self.count, self.dispelType, self.duration, self.expires, self.caster, + self.isStealable, self.shouldConsolidate, self.spellID, self.canApplyAura, self.isBossDebuff = ... + if self.active then + if self.cvars.duration then + self.duration = self.cvars.duration + print(cKey('force duration ='), cNum(self.cvars.duration)) + end + self.start = self.expires - self.duration + end +end + +--- Handle in the frame itself to limit collateral from bugs +function p.Event(self, event, unit) + self.event = event + if not event then + print(' DRY FIRE') + elseif unit ~= self.unit then + return + end + + --- 3 states: nil, 0, >0 + + local active, rank, _, count, dispelType, duration, expires, caster, isStealable, shouldConsolidate, spellID, canApplyAura, isBossDebuff = self:Query() + local state + if self.cvars.duration and active ~= self.active then + print('passive aura with forced duration') + state = self.flags.active + duration = self.cvars.duration + expires = GetTime() + self.cvars.duration + elseif (not self.cvars.duration and (duration ~= self.duration or expires ~= self.expires)) or active ~= self.active then + if not active then + if (not self.untriggerFunc) or self:untriggerFunc() then + state = self.flags.hidden + end + else + if (not self.triggerFunc) or self:triggerFunc() then + if duration == 0 then + print('passive aura') + state = self.flags.passive + else + print('updating an active aura') + state = self.flags.active + end + self.start = expires - duration + end + end + end + + if state then + T:Dispatch('TK_AURA_UPDATE', self.spellID, self.filters, state, self.displayState) + self:Set(active, rank, _, count, dispelType, duration, expires, caster, isStealable, shouldConsolidate, spellID, canApplyAura, isBossDebuff) + self:SetState(state) + print(cText('push state'), cNum(self.displayState).. ' (prev: '.. cNum(self.prevState)..')', self.timerName, cText(active), cKey(duration), cNum(expires), cBool(self.cvars.inverse)) + else + print(cText('no changes'), cNum(self.displayState).. ' (prev: '.. cNum(self.prevState)..')', cText(self.timerName)) + end +end + +p.Value = function(self) + return (self.charges and self.charges < self.maxCharges) and ((GetTime() - self.chargeStart) / self.chargeDuration) or ((GetTime() - self.start) / self.duration) +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Timer/Container.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,157 @@ +--- ${PACKAGE_NAME} +-- @file-author@ +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +-- Created: 1/16/2016 12:20 AM +local _G, CreateFrame = _G, CreateFrame +local T, tinsert, UIParent = _G.Turok, table.insert, _G.UIParent +local mod = T.modules.TimerControl +local db, CollectorTray + +local pairs, ipairs, gsub, sub, setmetatable = pairs, ipairs, string.gsub, string.sub, setmetatable +local INVTYPE_FINGER, INVSLOT_FINGER1, INVSLOT_FINGER2, INVTYPE_TRINKET, INVSLOT_TRINKET1, INVSLOT_TRINKET2 = +INVTYPE_FINGER, INVSLOT_FINGER1, INVSLOT_FINGER2, INVTYPE_TRINKET, INVSLOT_TRINKET1, INVSLOT_TRINKET2 +--@debug@ +local DEBUG = true +--@end-debug@ +local cType, cText, cNum, cWord, cKey, cPink, cBool = cType, cText, cNum, cWord, cKey, cPink, cBool +local print = function(...) + if not DEBUG then return end + if _G.Devian and _G.DevianDB.workspace ~= 1 then + _G.print('TimerContainer', ...) + end +end +print('Peep!', ...) + +--- defaults +local Containers = {} + +--- manages collections of timer displays +local TimerContainer_Init = function(frame, cvars) + + frame.num_timers = 0 + frame.anchor = cvars.anchor + frame.parent = cvars.parent + frame.anchorTo = cvars.anchorTo + frame.x = cvars.x + frame.y = cvars.y + frame.name = cvars.name + frame.padding = cvars.padding + frame.spacing = cvars.spacing + frame.width = cvars.width + frame.height = cvars.height + frame.timers = {} + frame.childAnchor = cvars.childAnchor + frame.childAnchorTo = cvars.childAnchorTo + + frame:ClearAllPoints() + frame:SetPoint(cvars.anchor, cvars.parent, cvars.anchorTo, cvars.x, cvars.y) + frame:SetSize(cvars.width, cvars.height) -- initial values + frame.NameText:SetText(frame.name) +end + +local TimerContainer_Add = function(frame, timer) + if timer.containerHandle then + print('stop now') + return + end + timer.containerHandle = 1 + + print('adding', timer.timerName, 'to', frame.name) + local handle = frame.num_timers + 1 + -- if the timer is ordered, start from the top and shift each item upward until they are no longer + -- above the + print('resulting handle:', handle) + print(#frame.timers) + + frame.num_timers = frame.num_timers + 1 + + tinsert(frame.timers, timer) + timer.containerHandle = #frame.timers + --frame.timers[handle] = timer +end + +local TimerContainer_Unlock = function(frame) + +end + +local TimerContainer_Update = function(frame) + local frameCount, hiddenCount = 0, 0 + local w = frame.padding + local translation_points = {} + local dx, dy = 0, 0 -- net change in container dimensions + for k, spirit in pairs(frame.timers) do + hiddenCount = hiddenCount + 1 + if spirit:IsVisible() and not(spirit.trash or spirit.cvars.absolute) then + frameCount = frameCount + 1 + spirit.index = frameCount + print(' -', cNum(hiddenCount), cNum(frameCount), cKey(spirit:GetName())) + --tinsert(frame.timers, spirit) + spirit:ClearAllPoints() + local tx = w + local ty = 0 + if spirit.cvars.relative then + tx = tx + spirit.cvars.x + ty = ty + spirit.cvars.y + else + w = w + spirit:GetWidth() + frame.spacing + end + translation_points[k] = { + x = spirit.cvars.x, y = spirit.cvars.y, + dx = tx - spirit.cvars.x, dy = ty - spirit.cvars.y + } + end + + --- track the size of in/outbound frames + if not spirit.collected then + if spirit.trash then + dx = dx - spirit.width + elseif spirit.add then + dx = dx + spirit.width + end + spirit.collected = true + end + end + print(cText(' dx:'), cNum(dx)) + + + frame.width = frame.width + dx + frame:SetWidth(frame.width) + local ddX = dx / frameCount + + for id, a in pairs(translation_points) do + local spirit = frame.timers[id] + + + spirit.slide.t1:SetOffset(a.dx, a.dy) + spirit.slide:SetScript('OnFinished', function() + spirit.cvars.x = a.x + a.dx + spirit.cvars.y = a.y + a.dy + spirit:SetPoint(frame.childAnchor, frame, frame.childAnchorTo, spirit.cvars.x, spirit.cvars.y) + end) + spirit.slide:Play() + end +end + +--- Updates the appropriate containers' object positions +function mod.Report(self) + if not self.container then + self.container = 'default' + print('reporting to default container') + else + print('reporting to container', self.container) + end + + if not Containers[self.container] then + print('need to create') + Containers[self.container] = CreateFrame('Frame', 'TkCollectorFrame'..self.container, UIParent, 'TkContainerTemplate') + TimerContainer_Init(Containers[self.container], mod.db.containers[self.container] or mod.db.containers) + end + + if not self.containerHandle then + TimerContainer_Add(Containers[self.container], self) + else + print(self.timerName, 'has a container assigned') + end + TimerContainer_Update(Containers[self.container]) +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Timer/Cooldown.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,345 @@ + +--- ${PACKAGE_NAME} +-- @file-author@ +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +-- Created: 12/25/2015 5:33 AM +--- Spell cooldown tracking resides here. +-- +-- Workflow of cooldown tracking: +-- A tracked spell cast is detected. (UNIT_SPELLCAST_*) +-- That spell ID enters the timer table. +-- The table is read by a handler that fires on the next frame, when cooldown information is available. (COOLDOWN_*) +-- Set() is called on the corresponding timer frame, and frame script takes over. +-- Timer table spells are polled on each COOLDOWN_* event, re-applying Set() when certain conditions are met. +-- The framescript or certain handlers will remove the timer table entry when there are no more positive conditions. +-- +local tostring, tonumber, tinsert = tostring, tonumber, tinsert +local GetTime, GetSpellInfo, GetInventoryItemCooldown, GetSpellCooldown, PlaySoundFile = GetTime, GetSpellInfo, GetInventoryItemCooldown, GetSpellCooldown, PlaySoundFile +local GetSpellCharges, GetSpellCount, GetInventoryItemCount, UnitAura = GetSpellCharges, GetSpellCount, GetInventoryItemCount, UnitAura +local IsUsableItem, IsUsableSpell, GetItemSpell = IsUsableItem, IsUsableSpell, GetItemSpell +local xpcall = xpcall + +local CD_SLOT, CD_ITEM, CD_SPELL = 1, 2, 3 +local HIDDEN, PASSIVE, ACTIVE = 0, 1, 2 +local format, ceil = string.format, math.ceil +local strrep, gsub, pairs = string.rep, string.gsub, pairs +local mod = Turok.modules.TimerControl +local T = Turok +local db +local FADE_TIME = 0.2 +--@debug@ +local cType, cText, cNum, cWord, cKey, cPink, cBool = cType, cText, cNum, cWord, cKey, cPink, cBool +local print = function(...) print('Cooldown', ...) end +local function GetPrint (trace) + return trace and print or function() end +end + + +local item_spells = { + ['PvP Trinket'] = 42292, + ['Burning Mirror'] = 184270, +} + +T.defaults.spirit.cooldown = { + + alpha = 1, + alpha_ooc = 0.2, + inverse = false, + persist = false, + desaturated = false, + fill_inverse = true, + size = 24, + counterText = "%p", + subCounterText = "%.p", + chargesText = "%s", + justifyH = 'CENTER', + justifyV = 'TOP', + + iconText = "%p", + leftText = "%p", + rightText = "%n / %d", + passive = { + icon = { + desaturated = false, + color = {1, 1, 1, 1}, + blend = 'BLEND' + } + }, + active = { + icon = { + desaturated = false, + color = {1, 1, 1, .6}, + blend = 'ADD' + } + }, + + --- control displays of aura information in cooldown displays + showAura = false, + cooldownAura = { + icon = { + desaturated = true, + color = {0,1,0,1}, + } + } +} + +local p = mod.prototype.trigger.cooldown +--@end-debug@ +p.class = 'trigger' +p.type = 'cooldown' +p.cvars = { +} +--- Sets initial values before dry Event is fired to check for presence +p.Init = function(self, spellID, caster, tristate, minValue, maxValue) + local print = GetPrint(self.trace) + + self.spellID = spellID and spellID or self.spellID + self.unit = caster and caster or self.unit + self.persist = tristate and tristate or self.persist + self.minValue = minValue and minValue or tonumber(self.minValue) + self.maxValue = maxValue and maxValue or tonumber(self.maxValue) + + --- current and last state values need to be flipped for inverted conditional + --- last state is defined in case it needs to be overridden to ensure proper frame update + print(cWord('Load:'),cNum(self.spellID or self.inventoryID or self.itemID), cText(self.spellName or GetItemSpell('player', self.inventoryID or self.itemID)) ) + print(cWord(' inverse=')..cBool(self.cvars.inverse)) + if self.cvars.inverse then + self.flags = { + active = HIDDEN, + active_prev = ACTIVE, + passive = PASSIVE, + passive_prev = PASSIVE, + hidden = PASSIVE, + hidden_prev = HIDDEN, + } + else + self.flags = { + active = ACTIVE, + active_prev = HIDDEN, + passive = PASSIVE, + passive_prev = HIDDEN, + hidden = HIDDEN, + hidden_prev = PASSIVE + } + end + if not (self.spellID or self.spellName) then + self.debug_info('No valid spell ID or Name') + end +end + +local GetItemCooldown, GetItemInfo = GetItemCooldown, GetItemInfo +p.Query = function(self) + local print = GetPrint(self.trace) + local id = self.inventoryID or self.itemID or self.spellID + local name, usable, start, duration, enabled, charges, maxCharges, chargeStart, chargeDuration, count + + --- checked in order of precedence + if self.inventoryID then + print(cText(' type'), cWord('inventory slot'), cNum(id)) + self.cooldownType = CD_SLOT + start, duration, enabled = GetInventoryItemCooldown('player', id) + charges, maxCharges, chargeStart, chargeDuration = nil, nil, nil, nil + count = GetInventoryItemCount('player', id) + usable = name and true or false + elseif self.itemID then + self.cooldownType = CD_ITEM + + start, duration, enabled = GetItemCooldown(self.itemID) + print(GetItemCooldown(self.itemID)) + print(GetItemInfo(id)) + + elseif self.spellID then + self.cooldownType = CD_SPELL + name = GetSpellInfo(self.spellID) + start, duration, enabled = GetSpellCooldown(self.spellID) + charges, maxCharges, chargeStart, chargeDuration = GetSpellCharges(self.spellID) + count = GetSpellCount(self.spellID) + usable = true -- they still exist even when dead + else + self.unit = 'notaunit' + T:Print('Timer \''..tostring(self.timerName)..'\' doesn\'t have a valid status ID.') + end + + -- may not have been stored for some reason + if charges and not self.maxCharges then + self.maxCharges = maxCharges + end + + print('cooldown.Query(',id,')', name, usable, start, duration, enabled, charges, maxCharges, chargeStart, chargeDuration) + return name, usable, start, duration, enabled, charges, chargeStart, chargeDuration, count +end + +p.Set = function(self, ...) + local print = GetPrint(self.trace) + + --name, usable, start, duration, enabled, charges, maxCharges, chargeStart, chargeDuration, count + local name + name, self.usable, self.start, self.duration, self.enabled, self.charges, self.chargeStart, self.chargeDuration, self.count = ... + if name then + self.spellName = name + end + + if self.duration and self.start then + self.expires = self.start + self.duration + else + self.expires = 0 + end +end + +p.Value = function(self) + return (self.charges and self.charges < self.maxCharges) and ((GetTime() - self.chargeStart) / self.chargeDuration) or ((GetTime() - self.start) / self.duration) +end + +p.SetText = mod.SetText + +--- Assign where meaning won't be amibiguous +local Cooldown_OnCast = function(self) + self.triggerState = true +end + +local Cooldown_OnUpdate = function(self, event) + local print = GetPrint(self.trace) + + if self.triggerState then + print(cWord('Event'), cText(self.timerName)) + if not event then + print(' *', cWord('Poke')) + end + local diff = 'start='..cText(self.start)..' duration='..cText(self.duration)..' charges='.. + cText(self.charges).. ' chargeStart='..cText(self.chargeStart).. ' chargeDuration='..cText(self.chargeDuration) + local name, usable, start, duration, enabled, charges, chargeStart, chargeDuration, count = self:Query() + + -- If we want and can, pull aura data and use that in place of cooldown information + local expires, hasAura, _ + if self.cvars.showAura then + print(cText('UnitAura'), self.unit, self.spellName, nil, 'HELPFUL') + local name, _, _, count, _, auraDuration, auraExpires = UnitAura(self.unit , self.spellName, nil, 'HELPFUL') + if name and (auraDuration ~= self.auraDuration or auraExpires ~= self.auraExpires) then + + print(cText('aura check ='), cBool(name), 's='..cNum(count), 'd='..cNum(auraDuration), 'e='..cNum(auraExpires)) + start = auraExpires - auraDuration + duration = auraDuration + expires = auraExpires + end + end + + -- print(name, usable, start, duration, enabled, charges, maxCharges, chargeStart, chargeDuration, count) + if duration ~= self.duration or + start ~= self.start or + chargeStart ~= self.chargeStart + or charges ~= self.charges then + print('a variable has changed') + local state + + + if duration == 0 and charges == self.maxCharges then + print(cText(' cooldown has reset, drop it from the queue')) + state = self.cvars.persist and self.flags.passive or self.flags.hidden + self.triggerState = nil + print(' ', cText('dropping'), cWord(self.timerName), cText('from spell tracking')) + + + self:Stats(state) + else + if duration ~= 0 then + print(cText(' cooldown has a hard duration')) + if duration > T.GCD and self.displayState ~= self.flags.active then + print(cText(' and its > GCD, update it')) + state = self.flags.active + end + end + + if charges then + print(cText(' cooldown has charges')) + if charges ~= self.charges or chargeStart ~= self.chargeStart then + print(cText(' charges count or starting time has changed')) + state = self.flags.active + end + end + + self:Stats(state) + end + + + -- form ID, id type, displayState, prevState + --T:Dispatch('TK_COOLDOWN_UPDATE', self.spellID, self.cooldownType, state, self.displayState) + if state then + self:Set(name, usable, start, duration, enabled, charges, chargeStart, chargeDuration, count) + self.expires = charges and (self.chargeStart + self.chargeDuration) or (self.start + self.duration) + self:SetState(state) + --print(' ', cText('SetState'), cNum(self.displayState), 'from', cNum(self.prevState), cWord(self.timerName)) + print(' ',diff) + print(' start='..cText(self.start)..' duration='..cText(self.duration)..' charges='.. + cText(self.charges).. ' chargeStart='..cText(self.chargeStart).. ' chargeDuration='..cText(self.chargeDuration)) + end + elseif self.cooldownType == CD_SPELL then + if duration == 0 and charges == self.maxCharges and self.displayState == HIDDEN then + print(cKey(self.timerName), cText('post-framescript clean-up')) + self.triggerState = nil + end + end + end + --self:DumpMessages() + +end + +p.Stats = function(self, state) + print(self.unit, self.spellName) + local auraName, _, _, auraCharges, _, auraDuration, auraExpires = UnitAura(self.unit, self.spellName, nil, 'HELPFUL') + local name, usable, start, duration, enabled, charges, maxCharges, chargeStart, chargeDuration, count = self:Query() + print('# GCD =', T.GCD) + print('# SpellCooldown', 's =', start, 'd =', duration, 's =', charges and (charges..'/'..maxCharges) or 'NA') + print('# Aura', auraName and 'yes' or 'no', auraName and ('d='..cNum(auraDuration)) or '', auraName and ('e='..auraExpires)) + print('# Frame', 'state1 =', self.displayState, 'state2 =', self.previousState, state and ('change to '..cWord(state)) or '') + + +end + +--- Event pointers +p.events = { + ['UNIT_SPELLCAST_SUCCEEDED'] = Cooldown_OnCast, + ['UNIT_SPELLCAST_CHANNEL_START'] = Cooldown_OnCast, + ['BAG_UPDATE_COOLDOWN'] = Cooldown_OnUpdate, + ['SPELL_UPDATE_COOLDOWN'] = Cooldown_OnUpdate, + ['SPELL_UPDATE_USABLE'] = Cooldown_OnUpdate, + ['SPELL_UPDATE_CHARGES'] = Cooldown_OnUpdate, +} + +local unpack, select, debugstack = unpack, select, debugstack +p.Event = function(self, e, ...) + local print = GetPrint(self.trace) + + self.event = e + --- dry event case + if not e then + print('onEvent', self.timerName, e) + self.triggerState = true + Cooldown_OnUpdate(self, e, ...) + else + local unit = select(1,...) + if self.unit and unit ~= self.unit and e ~= 'SPELL_UPDATE_COOLDOWN' then + return + end + local args = {...} + local success, d = xpcall(function() self.events[e](self, e, unpack(args)) end, function(m) print(self.name .."\n".. m .. "\n".. debugstack(3)) end) + + end +end + +p.triggerList = { + ['on_cooldown'] = function(self) + local start, duration, enabled = GetSpellCooldown(self.spellID) + local charges, _, cStart, cDuration = GetSpellCharges(self.spellID) + return (enabled and (duration ~= 0 or start ~= 0 or charges ~= self.maxCharges)), start, duration, enabled, charges, cStart, cDuration + end, + ['not_on_cooldown'] = function(self) + local start, duration, enabled = GetSpellCooldown(self.spellID) + local charges, _, cStart, cDuration = GetSpellCharges(self.spellID) + return (duration == 0 and start == 0 and charges == self.maxCharges), start, duration, enabled, charges, cStart, cDuration + end, + ['buff_active'] = function(self) + local name, rank, icon, count, dispelType, duration, expires, caster, isStealable, shouldConsolidate, spellID, canApplyAura, isBossDebuff, value1, value2, value3 = UnitAura(self.unit, self.spellName, self.filters) + return (name and true or false), expires - duration, duration, true, count, 0, 0 + end +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Timer/Editor.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,257 @@ +--- Modules +-- @file-author@ +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +-- Created: 1/18/2016 3:33 PM +local _G = _G +local T, type, pairs = _G.Turok, type, pairs +local mod = T.modules.TimerControl +local cType, cText, cNum, cWord, cKey, cPink, cBool = cType, cText, cNum, cWord, cKey, cPink, cBool +local print = function(...) + if Devian and DevianDB.workspace ~= 1 then + print('Dialog', ...) + end +end +print('Peep!', ...) + + +local TimerConfig = { + conf = { + padding = 4, + spacing = 1, + width = 450, + }, + info = { + { key = 'timerName', + desc = 'Unique Name:', + type='EditBox', name = 'timerName', fill=true, + line = true, + }, + { key = 'spellEnable', + inherits = 'TurokCheckButtonOverlay', + type='CheckButton', name = 'spellEnable', fixed=25, point='LEFT', + get = Dialog_Boolean, getarg = 'spellID', + collapse = true, + desc = 'Spell Name', + }, + { key = 'spellID', + type='EditBox', name = 'spellName', + line = true, float = true + }, + { key = 'fill_inverse', + desc = 'Reverse Fill', + type='CheckButton', name='fillInverse', fixed=25, point='LEFT', + get = Dialog_Boolean, getarg = 'fill_inverse', text='Inverted Fill', + line = true, + }, + { key = 'display', + desc = 'Display Type', + type='EditBox', name='displayType', + line = true, + }, + }, +} + +local Dialog_SetField = {} +local dget = function(name, key) + if mod.db.timers[name] then + return mod.db.timers[name][key] + end + return nil +end +local inherits = { + EditBox = 'TkEditBox', + CheckButton = 'TurokCheckButtonInline', + Slider = 'TkSlider', +} + +Dialog_SetField['CheckButton'] = function(self, checked) self:SetChecked(checked) end +Dialog_SetField['EditBox'] = function(self, text) + print(' ', cKey(self:GetName()), text) + self:SetText(text or '') end +Dialog_SetField['Button'] = function(self, text) self:SetText(text) end + + +local function Dialog_Boolean(name, key) + print(' Dialog_Boolean', name, key) + return (mod.db.timers[name][key] and true or false) +end + +function mod.Dialog_Select(self, key) + local timer + if self.parent_values[key] then + print('matched timer name', key) + timer = self.parent_values[key] + elseif rawget(mod.frames.spellID, key) then + print('matched spellID', key) + timer = mod.frames.spellID[key][1] + for k,v in pairs(timer) do + print(' -', k, '=', v) + end + end + + if timer then + self.values = timer + self.timerName = timer.timerName + else + self.values = { + timerName = 'New Timer' + } + self.timerName = 'New Timer' + end + mod.Dialog_Init(self, TimerConfig.conf, TimerConfig.info) +end + +function mod.Dialog_Init(self, dconf, dinfo) + print('init,', self.values.timerName) + + if not self.fields then + self.fields = {} + self.rows = {} + self.Click = mod.Dialog_Click + self.Check = mod.Dialog_Check + self.EditBox = mod.Dialog_EditBox + end + print(self.name, self.timerName) + self.name:SetText(self.timerName) + + local inset = dconf.padding + dconf.spacing + -- frame X max + local fX = 0 + -- row number, row Y offset + local rn, ry = 1, -34 + -- row x offset left-align, row x offset right-aligned, largest collapsed element + local rxL, rxR, rC, rh = dconf.spacing, dconf.spacing, 0, 0 + for i, opt in ipairs(dinfo) do + if not self.rows[rn] then + self.rows[rn] = CreateFrame('Frame', self:GetName()..'Row'..rn, self, 'TurokDialogRow') + end + + local k = opt.key + if self.fields[i] == nil then + self.fields[i] = CreateFrame(opt.type, self:GetName()..opt.name, self.rows[rn], opt.inherits or inherits[opt.type]) + self.fields[i].index = i + self.fields[i].key = k + -- row point (from), row point (to), row x offset + local rp, rpt, rx + -- row delta + local rd + if opt.fill then + rpt = opt.float and 'BOTTOMLEFT' or 'BOTTOMRIGHT' + -- row point X offset + local rpx = opt.float and dconf.spacing or -dconf.spacing + self.fields[i]:SetPoint(rpt, self.rows[rn], rpt, rpx, 0) + print(' fill:', rpt, '-', rpt,' :: ', rpx, 0) + rd = 0 + else + rd = self.fields[i]:GetWidth() + dconf.spacing + end + if opt.float then + rp = 'BOTTOMRIGHT' + rx = -rxR + rxR = rxR + rd + elseif opt.collapse then + rp = 'BOTTOMLEFT' + rx = dconf.spacing + rC = math.max(rC, rd + dconf.spacing) -- spacing L + rd{width + spacing R} + else + rp = 'BOTTOMLEFT' + rx = rxL + rxL = rxL + rd + end + + rh = math.max(rh, self.fields[i]:GetHeight()) + self.fields[i]:SetPoint(rp, self.rows[rn], rp, rx, dconf.spacing) + print(' align:', rp, '-', rp, ' :: ', rx, 0) + print(' dR:', cNum(rd), 'nR:',cWord(rn), 'rX:', cNum(rx), 'i:', cText(i)) + + if opt.line or (not dinfo[i+1]) then + print(cText'nR:', cNum(rn), 'rY:', cNum(ry)) + self.rows[rn]:ClearAllPoints() + self.rows[rn]:SetPoint('TOPLEFT', self, 'TOPLEFT', dconf.padding, ry) + self.rows[rn]:SetPoint('TOPRIGHT', self, 'TOPRIGHT', -dconf.padding, ry) + self.rows[rn]:SetHeight(rh + dconf.spacing*2) + self.rows[rn]:Show() + rn = rn + 1 + ry = ry - (rh + dconf.spacing*3) -->| {spacing T + rh + spacing B} + spacing dR |<-- + + print('fX:',cNum(fX), 'rX:', cNum(rxL+rxR+dconf.spacing), 'rC:', cNum(rC)) + fX = math.max(fX, rxL+rxR+dconf.spacing) + fX = math.max(fX, rC) + rxL, rxR = dconf.spacing, dconf.spacing + rh = 0 + end + end + + self.fields[i]:Show() + if opt.desc and self.fields[i].description then + self.fields[i].description:SetText(opt.desc) + end + Dialog_SetField[opt.type](self.fields[i], opt.get and opt.get(self.values.timerName, opt.getarg) or self.values[k]) + + end + if not self.initialized then + self.initialized = true + self:SetSize(fX + dconf.padding + dconf.spacing*2, dconf.padding + math.abs(ry)) + end +end + +function mod.Dialog_Click(self,...) + local command = self:GetName():match("_(a%+)$") + + print(command) +end + +function mod.Dialog_Check(self, ...) + print('field #', self.index, self.key, 'checked') + --self:SetChecked(self:GetChecked() and false or true) +end + +function mod.Dialog_EditBox(self, ...) + print('field #', self.index, self.key, 'changed', self:GetText()) + + if self.key == 'timerName' then + self.values.timerName = self:GetText() + self.name:SetText(self.values.timerName) + self.timerName = self.values.timerName + elseif self.key == 'spellID' then + print('handling spellID') + end + +end + +function mod.Dialog_Command(str, editbox) + --local spellID = T:GetArgs(str, 1,0) + local f = mod.EditDialog + f.values = {} + local db = mod.db + + + local func, t, z = pairs(db.timers) -- iterator, table + local name, values, y = func(t) -- index, values + f.parent_values = {[name] = values} + f.timerName = name + f.values = values + f.values.timerName = name + for k,v in pairs(f.values) do + print(cText(k), cType(v)) + end + print('pairs1', func, t) + print('pairs2', z, y) + name, values = func(t, name) + while name do + print(' entry:', name, values) + f.parent_values[name] = values + name, values = func(t, name) + end + + + + if f:IsVisible() then + f:Hide() + else + mod.Dialog_Init(f, TimerConfig.conf, TimerConfig.info) + + f:Show() + end +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Timer/Icon.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,245 @@ +--- ${PACKAGE_NAME} +-- @file-author@ +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +-- Created: 1/15/2016 6:31 PM +local T, _G = Turok, _G +local mod = T.modules.TimerControl +local GetTime, floor, unpack, tconcat = GetTime, floor, unpack, table.concat +local HIDDEN, PASSIVE, ACTIVE = 0, 1,2 +--@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('Icon', ...) + end +end +print('Peep!', ...) +--@end-debug@ +local GetPrint = function(trace) + if trace then + return print + else + return function() end + end +end + +T.defaults.spirit.icon = { + combatFade = true, + alpha = 1, + alpha_passive = 1, + alpha_active = 1, + alpha_ooc_passive = 0, + alpha_ooc_active = 1, + alpha_ooc = 0.25, + size = 48, + container = 'default', + strata = 'LOW', + fade_in_time = 0.2, + fade_out_time = 0.3, + anchor = 'BOTTOM', anchorTo = 'BOTTOM', + parent = 1, + size = 48, + width = 48, height = 48, + x = 0, + y = 0, + strata = 'MEDIUM', + padding = 3, + spacing = 1, + foreground_inset= 0, +} + +local p = mod.prototype.display.icon + +p.type='display' +p.inherits = 'TurokIconTemplate' + +--- if config flags need to overrided +p.cvars = { + enableIcon = true +} +--- Negotiate the config differences between different display states +-- Hidden - display is or should (via fade-out) be hidden +-- Passive - display is visible, but no timing information is processed +-- Active - display is visible and counting time; on expiration, it will downgrade itself to passive or hidden +p.Init = function(self) + local print = GetPrint(self.trace) + + print('display.Icon.Load') + local c = self.cvars + if c.type == 'aura' then + self.spiral:SetReverse(true) + else + self.spiral:SetReverse(false) + end + + if not self.icon:IsShown() then + self.icon:Show() + end + print('icon texture=', self.spellIcon or self.itemIcon) + self.icon:SetTexture(self.spellIcon or self.itemIcon) +end + + +--- Advances the display state, applying any visual transitions as necessary; +-- @param self frame object +-- @param newState state value; 1 for inactive, 2 for untimed active, 3 for timed active +-- @param forcePrevious force the frame's lastState to this value to block off OnUpdate difference tests +-- even if forced, the actual history value will still be used for method scope +p.SetState = function(self, newState, forcePrevious) + + --print(cWord(self:GetName()), 'state change issued:', cNum(state), cType(previous)) + + local previous = self.displayState + self.prevState = forcePrevious and forcePrevious or previous + self.displayState = newState + print('SetState', cNum(newState), '(from '..cType(previous)..')', cText(self.timerName)) + --_G.print('Prototype.'..self.cvars.type, 'SetState', cNum(newState), '(from '..cType(previous)..')', cText(self.timerName)) + + --- Change transitions + if newState ~= previous then + print(cText(' Transition')) + if newState == HIDDEN then + print(cText(' to HIDDEN')) + -- to HIDDEN + if previous then + -- has to have been ACTIVE or PASSIVE at this point + if previous == ACTIVE then + print(' from ACTIVE') + self.spiral:StopAnimating() + else + print(' from PASSIVE') + end + + self.Intro:Stop() + if self.event then + print(' set by event script') + self.Outro:Play() + else + print(' non-event source') + self:Hide() + end + end + -- want to end here if HIDDEN from nil + else + -- to ACTIVE or PASSIVE + self.Outro:Stop() -- stop any running outro + + + if newState == ACTIVE then + + -- and is ACTIVE + self:Show() + self.spiral:Show() + self.spiral:SetCooldown(self.charges and self.chargeStart or self.start, self.charges and self.chargeDuration or self.duration) + print('spiral:Play() new', self.charges and self.chargeStart or self.start, self.charges and self.chargeDuration or self.duration) + end + + if previous and previous ~= HIDDEN then + print(cText(' from vis')) + -- from visible + if self.event then + self.refresh = true + self.Retro:Play() + end + else + print(cText(' from non-vis')) + if self.event then + self.Intro:Play() + else + self:Show() + end + end + end + else + --- No-change transitions + if newState == ACTIVE then + -- ACTIVE to ACTIVE + print(cText('')) + self.spiral:Show() + self.spiral:SetCooldown(self.charges and self.chargeStart or self.start, self.charges and self.chargeDuration or self.duration) + print('spiral:Play() new', self.charges and self.chargeStart or self.start, self.charges and self.chargeDuration or self.duration) + else + print(cPink('stopping spiral')) + self.spiral:Hide() + end + + -- non-HIDDEN to non-HIDDEN and not a dry fire + if self.event and newState ~= HIDDEN then + self.refresh = true + self.Retro:Play() + end + end + + if newState ~= HIDDEN then + print(cText(' CVars:')) + local c + if newState == ACTIVE then + print('apply active profile') + c = self.cvars.active + self.fillState = 1 + else + print('apply passive profile') + c = self.cvars.passive + self.fillState = 2 + end + + if self.icon and c.icon then + + print(cText(' '), cWord('desat=')..cBool(c.icon.desaturated), cWord('color=')..cNum(tconcat(c.icon.color, ', '))) + self.icon:SetVertexColor(unpack(c.icon.color)) + self.icon:SetDesaturated(c.icon.desaturated) + end + self:UpdateAlpha(T.inCombat, self.displayState, self.fillState) + end +end + +p.Update = function(self) + + if self.displayState == 0 and self.prevState ~= 0 then + print('flip to', self.displayState) + self.prevState = self.displayState -- quietly advance state + self.percent = 1 + self.valueFull = 0 + self.value = 0 + self:SetText() + elseif self.displayState == 1 and self.prevState ~= 1 then + print('flip to', self.displayState) + self.prevState = self.displayState -- quietly advance state + self.valueFull = 0 + self.value = 0 + self.percent = 1 + self:SetText() + print(self.percent, self.duration, self.start, self.expires) + elseif self.displayState == 2 then + if self.prevState ~= 2 or self.refresh then + print('flipped to', self.displayState) + self.prevState = self.displayState -- quietly advance state + self.refresh = nil + end + -- prevState is set externally + local time = GetTime() + if self.expires <= time and self.charges == self.maxCharges then + _G.print(self.cvars.type, 'timer expired, set to', (self.cvars.persist and self.flags.passive or self.flags.hidden)) + self.percent = 1 + self.duration = 0 + self.expires = 0 + self.start= 0 + self.valueFull = self.duration + self.value = self.duration + self.elapsed = self.duration + self.remaining = 0 + self:SetState(self.cvars.persist and self.flags.passive or self.flags.hidden) + else + self.percent = (self.charges and self.charges < self.maxCharges) and ((time - self.chargeStart) / self.chargeDuration) or ((time - self.start) / self.duration) + self.valueFull = self.expires - time + self.elapsed = time - self.start + self.remaining = self.duration - time + + self.value = floor(self.valueFull) + end + + --PlaySoundFile(self.cvars.sound_active) + self:SetText() + end +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Timer/Import.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,331 @@ +--- Turok - Import.lua +-- @file-author@ +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +-- Created: 1/4/2016 11:07 AM +-- Dialog interfaces and framework debugging tools; see the Google Doc + +local tconcat, unpack, pairs, ipairs, tostring, string = table.concat, unpack, pairs, ipairs, tostring, string +local BOOKTYPE_SPELL, GetSpellBookItemName, GetSpellBookItemInfo = BOOKTYPE_SPELL, GetSpellBookItemName, GetSpellBookItemInfo +local GetSpellTabInfo, GetNumSpellTabs, GetSpellInfo, GetFlyoutInfo, GetSpellDescription = GetSpellTabInfo, GetNumSpellTabs, GetSpellInfo, GetFlyoutInfo, GetSpellDescription +local GetFlyoutSlotInfo, GetSpellBaseCooldown, FindSpellBookSlotBySpellID, IsTalentSpell = GetFlyoutSlotInfo, GetSpellBaseCooldown, FindSpellBookSlotBySpellID, IsTalentSpell +local GetNumClasses, GetClassInfo, GetNumSpecializationsForClassID, GetSpecializationInfoForClassID += GetNumClasses, GetClassInfo, GetNumSpecializationsForClassID, GetSpecializationInfoForClassID +local _G, setmetatable, type, T = _G, setmetatable, type, Turok +local mod = Turok.modules.TimerControl +mod.EditDialog = TkTimerConfig +mod.SelectDialog = {} + +local print = function(...) + if Devian and DevianDB.workspace ~= 1 then + print('Dialog', ...) + end +end +print('Peep!', ...) +local strpad = function(str, num) + return tostring(str) .. string.rep(' ', num - #tostring(str)) +end + +--- Handles mouse click on spellbook row frame +mod.SpellBook_Click = function(self, btn) + print('mouse', btn, self.spellID) + mod.Dialog_Select(mod.EditDialog, self.spellID) +end + +--- Creates the spell book import frame +-- +local cmd +function mod.Import_Open() + local self = mod + print('Spirit', 'SpecSpells') + local book_list = {} + local tab = {} + local list_info = {} + local book_max = 0 + for k = 1, GetNumSpellTabs() do + local name, texture, offset, numSpells = GetSpellTabInfo(k) + tab[offset] = {k, name, texture, numSpells} + print('Spirit', name, offset, numSpells) + book_max = offset + numSpells + end + local tabID, tabName, tabTexture + local flyout, spellflyout = {}, {} + for i = 1, book_max do + if tab[i] then + tabID, tabName, tabTexture = unpack(tab[i]) + end + + if book_list[i] == nil then + local skillType, spellID = GetSpellBookItemInfo(i, BOOKTYPE_SPELL) + local spellNameUpper, spellSubText = GetSpellBookItemName(i, BOOKTYPE_SPELL) + local spellName, spellRank, spellTexture, castTime, minRange, maxRange = GetSpellInfo(spellID) + _G.print('Spirit', i, spellID, spellName) + _G.print('Spirit', ' ', skillType, spellSubText) + + local spellDesc + if skillType == 'FLYOUT' then + local numSlots + spellName, spellDesc, numSlots = GetFlyoutInfo(spellID) + print('flyout #'..spellID..':', spellName) + flyout[spellID] = {} + for i=1, numSlots do + local fspellID, _, isKnown, fSpellName, fSpellValue = GetFlyoutSlotInfo(spellID, i) + print(' spell #', fspellID, fSpellName, isKnown) + if isKnown then + flyout[spellID][i] = fspellID + spellflyout[fspellID] = spellID + end + end + + else + spellDesc = GetSpellDescription(spellID) + end + + book_list[i] = { + skillType = skillType, + spellIndex = i, + spellID = spellID, + spellName = spellName, + spellDesc = spellDesc, + spellNameUpper = spellNameUpper, + spellSubText = spellSubText, + spellTexture = spellTexture, + spellCooldown = GetSpellBaseCooldown(spellID), + castTime = castTime, + minRange = minRange, + maxRange = maxRange, + tabID = tabID, + tabName = tabName, + tabTexture = tabTexture + } + + + + end + end + + local selector = CreateFrame('Frame', 'TkSpellSelector', UIParent, 'TurokListFrame') + self.frames.selector = selector + selector.name:SetText("Spells") + selector:SetPoint('TOP') + selector.page = 1 + + selector.GetRow = function(row, info, id, item_num) + print(' ', row:GetName(), info, id, item_num) + if not row.opts then + row.opts = { + CreateFrame('CheckButton', 'TkCheck_'..item_num, row, 'TurokCheckButtonInline'), + row:CreateFontString('TextItem_'..item_num, 'OVERLAY', 'TurokFontDetail'), + row:CreateTexture(nil, 'OVERLAY'), + row:CreateTexture(nil, 'OVERLAY'), + row:CreateFontString('TextItem_'..item_num..'ID', 'OVERLAY', 'TurokFontDetail'), + } + end + local page = book_list[id] + if page.skillType == 'FLYOUT' then + row.background:SetTexture(1,.2,.3,.4) + + elseif rawget(mod.frames.spellID, page.spellID) then + print('has timer frame under spell #', page.spellID, mod.frames.spellID[page.spellID]) + row.background:SetTexture(1,1,0,1) + local timer = mod.frames.spellID[page.spellID] + row:SetScript('OnMouseDown', function(self) self.clicked = true end) + row:SetScript('OnMouseUp', function(self) if self.clicked then self.clicked = nil mod.Dialog_Select(mod.Editor, timer.timerName) end end) + elseif page.spellCooldown and page.spellCooldown > 0 then + row.background:SetTexture(.3,.6,1,1) + else + row.background:SetTexture(0,0,0,0.3) + end + + row:SetScript('OnMouseDown', mod.SpellBook_Click) + + row.desc = page.spellDesc + row.spellID = page.spellID + row.opts[1].desc = page.skillType + row.opts[1]:SetSize(20,20) + row.opts[1].description:SetText(nil) + row.opts[1]:SetChecked(page.checked) + row.opts[2]:SetText(page.spellName) + row.opts[2]:SetWidth(200) + row.opts[2]:SetJustifyH('LEFT') + row.opts[3]:SetSize(20,20) + row.opts[3]:SetTexture(page.spellTexture) + row.opts[3]:SetPoint('CENTER') + row.opts[4]:SetSize(20,20) + row.opts[4]:SetTexture(page.tabTexture) + row.opts[4]:SetPoint('CENTER') + row.opts[5]:SetWidth(60) + row.opts[5]:SetJustifyH('LEFT') + row.opts[5]:SetText(page.spellID) + end + + selector.Click = function(button, list) + local b = button:GetName():match("_(%a+)$") + if b == 'Prev' then + --print(b, list.offset, list.num_rows) + if list.page > 1 then + list.page = list.page - 1 + TkList_SetView(list, list.num_rows * (list.page-1) + 1) + end + list.pagenum:SetText(list.page) + elseif b == 'Next' then + --print(' ',list.page, list.num_rows, list.max_row) + if (list.page) * list.num_rows < list.max_row then + list.page = list.page + 1 + TkList_SetView(list, list.offset + list.num_rows) + end + list.pagenum:SetText(list.page) + + elseif b == 'Add' then + mod.CommitBook(book_list, tab, list_info) + end + --print(list.page, list.offset, list.num_rows) + end + + selector.Wheel = function(self, delta) + local offset = self.offset - delta + if offset > 0 and offset <= (self.max_row - self.num_rows) then + TkList_SetView(self, offset) + end + end + + selector.Check = function(checkbutton, row, list) + local index = checkbutton:GetParent().actual_row + book_list[index].checked = (not book_list[index].checked) and true or false + checkbutton:SetChecked(book_list[index].checked) + + if book_list[index].skillType == 'FLYOUT' then + for slot, spellID in pairs(flyout[book_list[index].spellID]) do + + local spIndex = FindSpellBookSlotBySpellID(spellID) + print(' also toggling', slot, spellID, ' book slot', spIndex, book_list[spIndex].spellName) + book_list[spIndex].checked = book_list[index].checked + end + TkList_SetView(list, list.offset) + end + end + TkList_Init(selector, book_list, 1, 12) + selector:Show() + mod.SelectDialog = selector +end +--@end-debug@ + + +function mod.CommitBook(bookInfo, tabInfo, uiInfo) + print('committing') + print(' book data: ', #bookInfo, 'entries') + print(' tab data: ', #tabInfo, 'entries') + + for index, e in ipairs(bookInfo) do + if e.checked then + local spellPretext = '' + if IsTalentSpell(index) then + spellPretext = 'Talent' + end + print(' ', strpad(spellPretext .. e.spellName, 20)) + print(' ', strpad(e.spellSubText, 10), strpad(e.spellCooldown,5), strpad(e.skillType,6)) + + end + end +end + + + + +--- /tki command +-- Constructs an index that associates global spec ID's with a list of the timers that would display under it. +-- List entries are stored as [name] = true to prevent duplication of values in SavedVariables. + +function mod:CreateIndex() + + --@debug@ Revert config to defaults + _G.TurokData = T.defaults + --@end-debug@ + + mod.db.timerindex = {} + setmetatable(mod.db.timerindex, {__mode = "v"}) -- ensure that dead leafs fall off + local index = mod.index + local timers = mod.timersByName + + -- build class info hash and create subtables + local classID = {} + local className = {} + local specIDPage = {} + local specPageID = {} + local classSpecs = {} + print('|cFF0088FFCreateIndex|r') + + --- use the internal class/specialization list + for i = 1, GetNumClasses() do + local _, tag, id = GetClassInfo(i) + classID[tag] = id + className[id] = tag + index[id] = {} + specPageID[tag] = {} + index[tag] = index[id] + + classSpecs[tag] = GetNumSpecializationsForClassID(id) + for j = 1, classSpecs[tag] do + local specID, specName = GetSpecializationInfoForClassID(id, j) + print('|cFFFF0088map:|r', tag, j, specID, specName) + specIDPage[specID] = j + specPageID[tag][j] = specID + index[specID] = {} + index[id][j] = {} + end + end + index.global = {} + + for name,timer in pairs(timers) do + -- class is set + if type(timer) == 'table' then + print(name) + if timer.playerClass then + + index[timer.playerClass][name] = true + + -- spec restricted + if timer.specPage then + if type(timer.specPage) ~= 'table' then + -- fix it up + timer.specPage = {timer.specPage } + end + + print(' |cFFFFFF00class:|r', timer.playerClass .. ', |cFF99FF00spec:|r '.. tconcat(timer.specPage,', ')) + for _, specPage in ipairs(timer.specPage) do + index[timer.playerClass][specPage][name] = true + index[specPageID[timer.playerClass][specPage]][name] = true + end + + -- no spec restriction, copy it out + elseif not timer.specID then + print(' |cFFFFFF00class:|r', timer.playerClass .. ', |cFF99FF00spec:|r ALL') + for i = 1, classSpecs[timer.playerClass] do + local specID = specPageID[timer.playerClass][i] + + index[timer.playerClass][i][name] = true -- store for local ID + index[specID][name] = true -- store for global ID + end + end + end + + if timer.specID then + index[timer.specID][name] = true + end + + if not (timer.playerClass or timer.specID or timer.specPage) then + for tag, id in pairs(classID) do + index[tag][name] = true + for specPage, specID in pairs(specPageID[tag]) do + index[tag][specPage][name] = true + index[specID][name] = true + end + end + print(' |cFFFFFF00class:|r ALL, |cFF99FF00spec:|r ALL') + end + end + end + + _G.TurokData.timerindex = index + T:Print('Hive data updated. /rl to commit.') +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Timer/Presets.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,394 @@ +local ADDON, Tk = ... +local T = Tk.Addon +local mod, tinsert, ipairs, pairs = T.modules.TimerControl, tinsert, ipairs, pairs +local print = function(...) print('TimerPresets', ...) end + + + +--- Timer config presets +mod.AddTimer = function(batch, container) + if container then + Turok.defaults.spirit.containers[container] = {} + end + + for i, entry in ipairs(batch) do + print(cPink('AddTimer(#=')..cWord(#batch)..cPink(', ')..cWord(container)..cPink(')')) + if container then + entry.container = container + print(' container set to', container) + end + print(' unpacking', entry.name) + tinsert(Turok.defaults.spirit.timers, entry) + end +end +local tp = mod.index.preset + +mod.LoadPresets = function() + for setName, setFunc in pairs(tp) do + setFunc() + end +end + +tp.Containers = function() + local defs = { + anchor = 'TOPLEFT', parent = 'TekplayerCastBar', anchorTo = 'BOTTOMLEFT', x = 0, y = -3, width = 700, + height = 200, + spacing = 3, + padding = 0, + ["default"] = { + name = "Default", + childAnchor = 'TOPLEFT', + childAnchorTo = 'TOPLEFT', + }, + ["DoTs"] = { + anchor ='BOTTOM', anchorTo='TOP', + parent='TekplayerCastBar', + display = 'icon', + size = 48, + height = 48, width = 48, + x = 0, y = 16, + padding = 0, + spacing = 0, + childAnchor = 'BOTTOMLEFT', + childAnchorTo = 'BOTTOMLEFT', + } + } + for k,v in pairs(defs) do + TurokData.spirit.containers[k] = v + end +end + +tp.Rogue = function() + mod.AddTimer( + { + { + name = "Vendetta", + type = 'cooldown', + display = 'icon', + unit = 'player', + spellID = 79140, + playerClass = 'ROGUE', + specPage = 1, + }, + { + name = "Burst of Speed", + type = 'cooldown', + display = 'icon', + unit = 'player', + spellID = 108212, + playerClass = 'ROGUE' + }, + { + name = "Rupture", + type = 'aura', + display = 'icon', + unit = 'target', + spellID = 1943, + filters = 'PLAYER|HARMFUL', + playerClass = 'ROGUE', + specPage = {1,3}, + }, + { + name = "Slice and Dice", + type = 'aura', + display = 'icon', + spellID = 5171, + unit = 'player', + filters = 'PLAYER|HELPFUL', + playerClass = 'ROGUE', + specPage = {2,3}, + }, + { + name = "Deadly Missing", + type = 'aura', + spellID = 2823, + display = 'icon', + unit = 'player', + playerClass = 'ROGUE', + specPage = {1,3}, + inverse = true, + }, + { + name = "Stealth", + type ='aura', + spellID = 1784, + display = 'icon', + unit = 'player', + playerClass = 'ROGUE', + }, + { + name = "Recuperate", + type ='aura', + spellID = 73651, + display = 'icon', + unit = 'player', + playerClass = 'ROGUE', + }, + }) +end +tp.Mage = function() + mod.AddTimer({ + { + name = "Rune of Power", + type = 'aura', + spellID = 116014, + unit = 'player', + display = 'icon', + playerClass = 'MAGE', + talentID = 16032, + }, + { + name = "Mage Nova", + spellID = {157980, 157981, 157997}, + talentOffset = {5, 3}, + unit = 'player', + type='cooldown', + display='icon', + playerClass='MAGE', + persist = true, + }, + { + name = "Mage Bomb", + talentOffset = {5, 1}, + unit = 'target', + type= 'aura', + display='icon', + filters = 'HARMFUL|PLAYER', + playerClass='MAGE', + persist = true, + }, + { + name = "Frozen Orb", + spellID = 84714, + threschold = 2, + unit = 'player', + type='cooldown', + display='icon', + playerClass='MAGE', + specPage=3, + }, + { + name = 'Arcane Power', + type = 'cooldown', + display = 'icon', + unit = 'player', + spellID = 12042, + playerClass = 'MAGE', + specPage = 1, + } + }) +end +tp.UseEffects = function() + mod.AddTimer({ + + { + name = "Trinket 1", + type ='cooldown', display = 'icon', + unit = 'player', + persist = true, + inventoryID = 13, + }, + { + name = "Maalus Effect", -- Maalus + playerClass = {'HUNTER', 'ROGUE'}, + type = 'aura', display = 'progressbar', + unit = 'player', filters = 'HELPFUL', + leftText = "%c", rightText= "%p", + duration = 15, + spellID = 187615, itemID = 124636, hideIcon = true, + + sound_active = [[Interface\Addons\Turok\Media\sound\FLASH.mp3]], + + absolute = true, x = 0, y = -10, width = 300, height = 10, + anchor = 'BOTTOMLEFT', anchorTo = 'BOTTOMLEFT', + parent = 'TekplayerCastBar', padding = 0, spacing = 0, + + foreground_inset = 0, foreground_color = {1,1,1,1}, foreground_blend = 'ADD', + background_color = {0,0,0,0}, + icon = false, + }, + + { + name = "Maalus CD", + type = 'cooldown', display = 'icon', + unit = 'player', + spellID = 187615, itemID = 124636, + playerClass = 'HUNTER', + }, + }) +end + +tp.Hunter = function() + mod.AddTimer({ + ---- Icon templates + { virtual = true, name = "Hunter", + playerClass = 'HUNTER', unit = 'player', container = 'default', display= 'icon', }, + { virtual = true, name = "HunterSticky", inherits = "Hunter", + showAura = true, persist = true, }, + { virtual = true, name = "HunterBar", + playerClass = 'HUNTER', unit = 'player', }, + ---- Talents + { + inherits= "HunterSticky", + name = "Heavy Artillery", type = 'cooldown', + talentRow = 6, + trace = true}, + { + inherits= "HunterSticky", + name = "Animal Power", type = 'cooldown', + talentRow = 5, + trace = true}, + --- Spells + { + inherits = 'Hunter', name = "Camouflage", + type = 'cooldown', display = 'icon', + spellID = 51753, }, + { + inherits = 'Hunter', name = "Ice Trap", + type = 'cooldown', display = 'icon', + spellID = 13809, }, + { + inherits = 'Hunter', name = "Concussive Shot", + type = 'cooldown', display = 'icon', + spellID = 5116, }, + { + inherits = 'Hunter', name = "Flare", + type = 'cooldown', display = 'icon', + spellID = 1543, }, + { + inherits = 'Hunter', name = "Disengage", + type = 'cooldown', display = 'icon', + spellID = 781, }, + { + inherits = "HunterSticky", name = "Rapid Fire", + type = 'cooldown', display = 'icon', + spellID = 3045, specPage = 2, }, + { + inherits = 'HunterSticky', name = "Bestial Wrath", + type = 'cooldown', display = 'icon', + spellID = 19574, specPage = 1, + trace = true + }, + + --- Progress Bars + { + inherits = 'HunterBar', name = "Chimaera Shot", + type = 'cooldown', display = 'progressbar', + spellID = 53209, specPage = 2, persist = true, + + hideIcon = true, + leftText = "", rightText = "%p", + width = 300, height = 8,padding = 0, spacing = 0, + absolute = true, x = 0, y = 0, anchor = 'TOPLEFT', anchorTo = 'TOPLEFT', parent = 'TekplayerCastBar', strata='MEDIUM', + foreground_color = {1,.125,0.43,1}, foreground_blend = 'ADD', foreground_inset = 0, + background_color = {.5,.5,.5,0}, background_blend = 'BLEND', + }, + { + inherits = 'HunterBar', name = "Sniper Training (duration)", + type = 'aura', display = 'progressbar', + spellID = 168811, specPage = 2, + + hideIcon = true, + leftText = "", rightText= "", + width= 330, height = 12, padding = 0, + absolute = true, x = 0, y = 0, anchor = 'BOTTOMLEFT', anchorTo = 'BOTTOMLEFT', parent = 'TekplayerCastBar', level = 1, + foreground_color = {1,0,0,1}, foreground_blend = 'BLEND', + sound_active = '', sound_hidden = '', sound_passive = '', + }, + { + inherits = 'HunterBar', name = "Sniper Training: Recently Moved", + type = 'aura', display = 'progressbar', + spellID = 168809, specPage = 2, + + hideIcon = true, + leftText = "", rightText= "", + height = 12, width= 160, padding = 0, + absolute = true, x = 0, y = 0, anchor = 'BOTTOMLEFT', anchorTo = 'BOTTOMLEFT', parent = 'TekplayerCastBar', level = 2, + foreground_color = {1,1,0,1}, foreground_blend = 'BLEND', + sound_active = '', sound_hidden = '', sound_passive = '', + }, + + --- Static Warnings + { + inherits='Hunter', name = "Aspect of the Pack", + type = 'aura', display = 'icon', + spellID = 13159 + }, + { + inherits = 'Hunter', name = "Trap Launcher", + type = 'aura', display = 'icon', + spellID = 77769, inverse = true, + + absolute = true, x = 0, y = 200, + width = 100, height = 100, + foreground_color = {1,1,1, 0.5}, foreground_blend = 'BLEND', + }, + }) +end +tp.SPriest = function() + mod.AddTimer( { + { + virtual = true, name = "Caster Icon", container = 'DoTs', + playerClass = 'PRIEST', + + combatFade = true, + height = 48, width = 48, + icon = { size = 48, }, + persist = true, + }, + { + inherits = "Caster Icon", name = "Shadowfiend", + unit = "player", spellID = 132603, + type = 'cooldown', display = 'icon', + container ='DoTs', + }, + { + inherits = "Caster Icon", name = "Insanity", + type = 'aura', display = 'icon', + unit = 'player', filters = 'PLAYER|HELPFUL', + spellID = 132573, playerClass = 'PRIEST', + order = 3, + }, + { + name = "Shadow Word: Pain", + type = 'aura', display = 'icon', + unit = 'target', filters = 'PLAYER|HARMFUL', + spellID = 589, playerClass = 'PRIEST', specPage = 3, + + container = 'DoTs', + order = 1, + sound_active = '', + }, + { + name = "Mental Fatigue", + type = 'aura', display = 'icon', + unit = 'target', filters = 'PLAYER|HARMFUL', + spellID = 184915, playerClass = 'PRIEST', specPage = 3, + + parent = 'TekplayerCastBar', + container = 'DoTs', + order = 1, + sound_active = '', + }, + { + name = "Vampiric Touch", + container = 'DoTs', + type = 'aura', display = 'icon', + unit = 'target', filters = 'PLAYER|HARMFUL', + spellID = 34914, playerClass = 'PRIEST', specPage = 3, + order =2, + }, + { + name = "PW:Shield", + type = 'cooldown', display = 'icon', + unit = 'player', + spellID = 17, playerClass = 'PRIEST', + }, + { + name = "Cascade", + type = 'cooldown', display = 'icon', + unit = 'player', + spellID = 127632, talentID = 21718, playerClass = 'PRIEST', + }, + }) +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Timer/Progressbar.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,246 @@ +--- ${PACKAGE_NAME} +-- @file-author@ +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +-- Created: 1/15/2016 6:38 PM +local T, _G = Turok, _G +local GetTime, PlaySoundFile, format = GetTime, PlaySoundFile, string.format +local unpack, tconcat = unpack, table.concat +local ACTIVE, PASSIVE, HIDDEN = 2, 1, 0 +local mod = T.modules.TimerControl +--@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('Progressbar', ...) + end +end +print('Peep!', ...) +--@end-debug@ +local GetPrint = function(trace) + if trace then + return print + else + return function() end + end +end +T.defaults.spirit.progressbar = { + combatFade = true, + alpha = 1, + alpha_ooc = 0, + alpha_ooc_passive = 0, + alpha_ooc_active = 1, + + width = 200, height = 24, + parent = 1, + anchor = 'CENTER', anchorTo = 'CENTER', + setAllPoints = true, + strata = 'MEDIUM', + + foreground_color = {1,0.5,0,0.5}, + foreground_blend = 'ADD', + foreground_texture = [[Interface\Addons\Turok\Media\statusbar\Minimalist.tga]], + background_color = {1,1,1,0.5}, + background_blend = 'BLEND', + padding = 3, + spacing = 1, + foreground_inset= 0, + icon = { + embedded = true, + alpha = 1, + alpha_ooc = 1, + size = 24, + x = -6, y = 0, + anchor = 'RIGHT', anchorTo = 'LEFT', + parent = 1, + }, + + -- text + color = {0,0,0,.5}, +} + +local p = mod.prototype.display.progressbar +p.type='display' + +p.inherits = 'TurokProgressbarTemplate' +p.cvars = {} + +--- Load-time config retrieval +p.Init = function (self) + local print = GetPrint(self.trace) + + print(' ', self:GetName(),'<- Progressbar.Load') + print(' ', self:GetHeight()) + + if self.cvars.hideIcon then + self.enableIcon = false + print('Icon hidden') + else + self.icon:Hide() + if self.cvars.icon then + print('Icon data:') + for k,v in pairs(self.cvars.icon) do + print(' ', k, '=', v) + end + print(cWord(' icon=')..cText(self.itemIcon or self.spellIcon)) + self.icon:SetTexture(self.itemIcon or self.spellIcon) + self.icon:ClearAllPoints() + T.SetTextureLayout(self.icon, self.cvars.icon) + self.enableIcon = true + self.icon:Show() + end + + end + + T.SetStatusTextures(self, self.cvars) + + _G.print('Update', self.background:GetWidth(), self.background:GetHeight()) + _G.print('Update', self.foreground:GetWidth(), self.foreground:GetHeight()) +end + + +--- Negotiate the config differences between different display states +-- Hidden - display is or should (via fade-out) be hidden +-- Passive - display is visible, but no timing information is processed +-- Active - display is visible and counting time; on expiration, it will downgrade itself to passive or hidden +p.SetState = function(self, newState, forcePrevious) + local print = GetPrint(self.trace) + + local previous = self.displayState + self.prevState = forcePrevious and forcePrevious or previous + self.displayState = newState + + local newState, previous = self.displayState, self.prevState + --- Transition + if newState ~= previous then + print(cText(' Transition:'), cWord(self.spellName)) + if newState == HIDDEN then + print(cText(' to HIDDEN')) + -- to HIDDEN + if previous then + -- has to have been ACTIVE or PASSIVE at this point + self.Intro:Stop() + if self.event then + self.Outro:Play() + else + self:Hide() + end + end + -- want to end here if HIDDEN from nil + else + -- to ACTIVE or PASSIVE + self.Outro:Stop() -- stop any running outro + + + if newState == ACTIVE then + + -- and is ACTIVE + self:Show() + end + + print(cText(' from'), cNum(previous)) + if previous and previous ~= HIDDEN then + -- from visible + if self.event then + self.refresh = true + self.Retro:Play() + end + else + if self.event then + self.Intro:Play() + else + self:Show() + end + end + end + else + if newState == ACTIVE then + print(cText('')) + -- and is ACTIVE + end + + if self.event and newState ~= HIDDEN then + self.refresh = true + self.Retro:Play() + end + end + + if newState ~= HIDDEN then + print(cText(' CVars:')) + local c = (newState == ACTIVE) and self.cvars.active or self.cvars.passive + if self.icon and c.icon then + print(cText(' '), cWord('desat=')..cBool(c.icon.desaturated), cWord('color=')..cNum(tconcat(c.icon.color, ', '))) + self.icon:SetVertexColor(unpack(c.icon.color)) + self.icon:SetDesaturated(c.icon.desaturated) + end + local c + if newState == ACTIVE then + self.fillState = 1 + c = self.cvars.active + else + self.fillState = 2 + c = self.cvars.passive + end + + if self.icon and c.icon then + print(cText(' '), cWord('desat=')..cBool(c.icon.desaturated), cWord('color=')..cNum(tconcat(c.icon.color, ', '))) + self.icon:SetVertexColor(unpack(c.icon.color)) + self.icon:SetDesaturated(c.icon.desaturated) + end + + self:UpdateAlpha(T.inCombat) + end +end + +p.Update = function (self) + local print = GetPrint(self.trace) + + -- Trigger business + -- Passive or Hidden, evaluate once + if self.displayState == 0 and self.prevState ~= 0 then + self.prevState = self.displayState -- quietly advance state + self.percent = 0 + self.valueFull = 0 + self.value = 0 + self:SetText() + self:SetProgress(self.percent) + print('go LOW') + elseif self.displayState == 1 and self.prevState ~= 1 then + self.prevState = self.displayState -- quietly advance state + self.valueFull = 0 + self.value = 0 + self.percent = 1 + self:SetText() + self:SetProgress(self.fill_inverse and 0 or 1) + print('go PASSIVE', self.percent, self.duration, self.start, self.expires) + elseif self.displayState == 2 then + if self.prevState ~= 2 or self.refresh then + self.prevState = self.displayState -- quietly advance state + self.refresh = nil + end + -- prevState is set externally + local time = GetTime() + if self.expires <= time and self.charges == self.maxCharges then + self.percent = 1 + self.duration = 0 + self.expires = 0 + self.start= 0 + self.valueFull = self.duration + self.value = self.duration + self.elapsed = self.duration + self.remaining = 0 + self:SetState(self.cvars.persist and self.flags.passive or self.flags.hidden) + else + self.valueFull = self.expires - time + self.percent = self.valueFull / self.duration + self.elapsed = time - self.start + self.remaining = self.duration - time + + self.value = floor(self.valueFull) + end + + --PlaySoundFile(self.cvars.sound_active) + self:SetText() + self:SetProgress(self.percent) + end +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Timer/Status.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,278 @@ +local _G, T = _G, Turok +local mod = T.modules.TimerControl +local P = mod.prototype +local GetInventoryItemID, GetItemInfo, GetInventoryItemTexture = GetInventoryItemID, GetItemInfo, GetInventoryItemTexture +local GetSpellDescription, GetSpellInfo, GetSpellCharges = GetSpellDescription, GetSpellInfo, GetSpellCharges +local GetTalentRowSelectionInfo = GetTalentRowSelectionInfo +local tinsert, type, tonumber, pairs, ipairs, unpack = tinsert, type, tonumber, pairs, ipairs, unpack +local UnitGUID = UnitGUID +local GetTalentInfo, GetTalentInfoByID, GetItemSpell, PaperDoll_IsEquippedSlot = GetTalentInfo, GetTalentInfoByID, GetItemSpell, PaperDoll_IsEquippedSlot +local print = function(...) print('Timer', ...) end +print('Peep!', ...) + +--@debug@ +local DEBUG = true +--@end-debug@ +local cType, cText, cNum, cWord, cKey, cPink, cBool = cType, cText, cNum, cWord, cKey, cPink, cBool +local print = function(...) + if not DEBUG then return end + if _G.Devian and _G.DevianDB.workspace ~= 1 then + _G.print('Timer', ...) + end +end +------------------------------------------ +--- Parameter Prototypes + +local Timer_GetPrintHandler = function(self) + return self.trace and function(...) + print(...) + _G.print('TimerFocus', ...) + end or print +end + +local Timer_UpdateIndex = function(self, key, value) + local print = Timer_GetPrintHandler(self) + -- sfk[value] = frame index key-value handle + -- mfkv = key-value frame index + -- mfkv[sfk[value]] = *frame + if self.frames[key] then + local sfk = self.frames[key] + -- for each unique value + for oldValue, index in pairs(sfk) do + local mfkv = mod.frames[key][oldValue] + -- for each offset after index + for i = index+1, #mfkv do + mfkv[i-1] = mfkv[i] -- slide it down + end + sfk[oldValue] = nil + print(cText(' *= self.frames')..'['..cKey(key)..']['..cNum(value)..'] =', cNum(self.frames[key][value])) + print(cText(' *= mod.frames')..'['..cKey(key)..']['..cNum(value)..']['..cNum(index)..'] =', cNum(self:GetName())) + end + else + self.frames[key] = {} + end + + if value then + local mfkv = mod.frames[key][value] + local sfk = self.frames[key] + mfkv[#mfkv+1] = self + sfk[value] = #mfkv + print(' *= self.frames['..cKey(key)..']['..cNum(value)..'] = ', sfk[value]) + end +end + +--- spellID +do + local spellID = P.status.spellID + spellID.Init = function(self, spellID) + local print = Timer_GetPrintHandler(self) + + if type(spellID) == 'table' then + spellID = spellID[T.specPage] + end + + -- May have changed if invoked through a slot assignment + if spellID ~= self.spellID then + self.spellID = spellID + self.charges, self.maxCharges, self.chargeStart, self.chargeDuration = GetSpellCharges(spellID) + self.spellDescription = GetSpellDescription(spellID) + self.spellName, self.spellRank, self.spellIcon, self.castingTime, self.minRange, self.maxRange = GetSpellInfo(spellID) + --@debug@ + print(' ', cWord('spellID ='), cKey(self.spellID), cNum(self.spellName), cText(self.spellDescription and '<desc>' or '<empty>'))--@end-debug@ + + Timer_UpdateIndex(self, 'spellID', spellID) + end + end +end + +--- spellName +do + local spellName = P.status.spellName + spellName.Init = function(self, spellName) + local print = Timer_GetPrintHandler(self) + -- attempt to get spell info + local exists, _, _, _, _, _, spellID = GetSpellInfo(spellName) + if exists then + local charges, maxCharges, start, duration = GetSpellCharges(spellID or spellName) + Timer_UpdateIndex(self, 'spellName', nil) + print(' ', cKey("spellID"), '=', spellID) + P.status.spellID.Init(self, spellID) + else + print(' ', cPink("spellID"), '=', 'not sure') + Timer_UpdateIndex(self, 'spellID', nil) + Timer_UpdateIndex(self, 'spellName', spellName) + end + end +end + + +--- talentID +do + local talentID = P.status.talentID + local GetTalentInfoByID = GetTalentInfoByID + talentID.type = 'status' + talentID.Init = function(self, talentID) + local print = Timer_GetPrintHandler(self) + + self.talentID, self.spellName, self.spellIcon, self.talentSelected = GetTalentInfoByID(talentID, T.specGroup) + + if self.talentSelected then + print(' ', cKey("spellName"), '=', cWord(self.spellName)) + P.status.spellName.Init(self, self.spellName) + else + self.disable = true + self.debug_info ('Talent not selected.') + end + + print(' ', cKey('talentID ('..cNum(self.talentID)..', '..cNum(T.specGroup)..'):'), self.spellName, self.talentSelected ) + Timer_UpdateIndex(self, 'talentID', talentID) + + end +end + +--- talentRow - use whatever is in that row as data +do + local talentRow = P.status.talentRow + talentRow.Init = function(self, row) + local print = Timer_GetPrintHandler(self) + self.talentRow = row + local noSelect, talentID = GetTalentRowSelectionInfo(row) + if noSelect then + self.disable = true + self.debug_info("No talent selected in target row.") + else + P.status.talentID.Init(self, talentID) + end + print(' ', cKey('talentRow ('.. cNum(row).. ') ='), talentID or 'none') + Timer_UpdateIndex(self, 'talentRow', row) + end +end + + +--- talentOffset +do + local talentOffset = P.status.talentOffset + talentOffset.Init = function(self, coords) + local print = Timer_GetPrintHandler(self) + + local tier, column = unpack(coords) + + + local selected, usable, _ + self.talentID, self.spellName, self.spellIcon, selected, usable = GetTalentInfo(tier, column, T.specGroup) + print(' ', cKey('talentOffset'), '=', cNum(tier), cNum(column), self.spellName, selected, usable) + if not (selected and usable) then + self.disable = true + self.debug_info ((not usable) and 'Unavailable at current level.' or 'Talent not selected.') + end + Timer_UpdateIndex(self, 'talentID', self.talentID) + end +end + +--- specPage +do + local specPage = P.status.specPage + specPage.type = 'status' + specPage.Init = function(self, specPage) + local print = Timer_GetPrintHandler(self) + local match + if tonumber(specPage) then + match = specPage == T.specPage + elseif type(specPage) == 'table' then + for _, pageID in ipairs(specPage) do + if T.specPage == pageID then + specPage = pageID + match = true + break + end + end + else + self.disable = true + self.debug_info ('Bad value for', '('..cWord(self.timerName)..').'..cKey('specPage')) + Timer_UpdateIndex(self,'specPage', nil) + end + + if match then + print(' ', cKey('specPage'), '=', '['..cNum(specPage)..']') + Timer_UpdateIndex(self,'specPage', specPage) + else + print(' ', cKey('specPage'), '~=', '['..cNum(specPage)..']') + self.disable = true + self.debug_info('Not active spec.') + end + end +end + +--- itemID +do + local itemID = P.status.itemID + itemID.type = 'status' + itemID.Init = function(self, item) + local print = Timer_GetPrintHandler(self) + + if not self.dvars.inventoryID then + self.itemID = item or self.dvars.itemID + self.itemType = self.dvars.itemType + else + self.itemID = item + end + + --@debug@ + --name, link, quality, iLevel, reqLevel, class, subclass, maxStack, equipSlot, texture, vendorPrice = GetItemInfo(itemID) or GetItemInfo("itemName") or GetItemInfo("itemLink") + if not self.itemID then + self.disable = true + self.debug_info ('bad itemID value') + end + + self.spellName = GetItemSpell(self.itemID) + + if not self.spellName then + self.disable = true + self.debug_info('no spell detected') + else + if not (self.frames.spellName and self.frames.spellName[self.spellName]) then + if not self.frames.spellName then + self.frames.spellName = {} + end + + Timer_UpdateIndex(self, 'spellName', self.spellName) + end + end + print(' ', cKey('itemID'), cNum(self.itemID), self.isEquipped)--@end-debug@ + end +end + +do + local inventoryID = P.status.inventoryID + inventoryID.type = 'status' + inventoryID.Init = function(self, slot) + local print = Timer_GetPrintHandler(self) + + self.inventoryID = slot + self.itemID = GetInventoryItemID(self.dvars.unit, slot) + local name = GetItemInfo(self.itemID) + if not PaperDoll_IsEquippedSlot(slot) then + self.disable = true + self.debug_info('slot un-equipped') + return + end + + P.status.itemID.Init(self, self.itemID) + self.spellIcon = GetInventoryItemTexture(self.dvars.unit, slot) + print(' ', cKey('inventoryID'), '=', '{'..cNum(self.inventoryID).. ' -> '.. cNum(self.itemID or 'no-equip').. '}') + end +end + + +--- unit +local unit = P.status.unit +unit.type = 'status' +unit.Init = function(self, unit) + local print = Timer_GetPrintHandler(self) + + self.unitGUID = UnitGUID(unit) + self.unit = unit + print(' ', cWord('unitGUID'), '=', cText(self.unitGUID)) + tinsert(mod.frames.unit[unit], self) + self.frames.unit = #mod.frames.unit[unit] +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Timer/Timer.Init.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,205 @@ +--- ${PACKAGE_NAME} +-- @file-author@ +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +-- Created: 12/28/2015 7:40 AM +-- +local _, Tk = ... +local T = Tk.Addon +local mod = T:NewModule("TimerControl", "AceTimer-3.0") +local pairs, ipairs, rawset, getmetatable, setmetatable, type, tostring, tinsert = pairs, ipairs, rawset, getmetatable, setmetatable, type, tostring, tinsert +local cWord, cNum, cText, cKey = cWord, cNum, cText, cKey +local print = function(...) print('Timer', ...) end +local index_mt = { + __newindex = function(t,k,v) + rawset(t,k,v) + if type(v) == 'table' then + print('new table', cKey(k)) + setmetatable(v, getmetatable(t)) + else + print('new index', cText(k)) + end + end + } +mod.index = {} +mod.index.name = setmetatable({}, index_mt) +mod.index.global = setmetatable({}, index_mt) +mod.index.preset = {} +-- dummies +mod.prototype = { + status = { + spellID = {}, + spellName = {}, + talentID = {}, + talentRow = {}, + talentOffset = {}, + itemID = {}, + inventoryID = {}, + specPage = {}, + specID = {}, + unit = {}, + }, + trigger = { + aura = {}, + cooldown = {}, + complex = {}, + }, + display = { + icon = {}, + progressbar = {}, + }, +} + +Turok.defaults.spirit = { + global = { + alpha = 1, + alpha_ooc = 0.5, + + sound_active = '[[Interface\Addons\Turok\Media\sound\link.ogg]]', + sound_passive = [[Interface\Addons\Turok\Media\sound\Heart.ogg]], + sound_hidden = [[Interface\Addons\Turok\Media\sound\Electro_-S_Bainbr-7955_hifi.mp3]], + + strata = 'LOW', + anchor = 'CENTER', + parent = 'UIParent', + anchorTo = 'CENTER', + width = 100, + height = 100, + x = 0, + y = 100, + alpha = 1, + alpha_ooc = 0.3, + inverse = false, + persist = false, + desaturated = false, + + icon = {}, + + passive = { + icon = {} + }, + active = { + inco = {} + }, + }, + + font = [[Interface\Addons\Turok\Media\font\ArchivoNarrow-Regular.ttf]], + lefttext = { + size = 14, + inset = -2, + point = 'LEFT', + outline = 'OUTLINE', + format = '%n %pd', + text_color = {1, 1, 1, 1}, + }, + containers = { + }, + timers = {}, +} + +local tdb = Turok.defaults.spirit.timers + +mod.GetInherited = function(dvars, merge, inherited) + if not inherited then + inherited = {} + end + inherited[merge] = merge + T.Config_Merge(dvars, merge) + + if merge.inherits then + local t = mod.index.name[merge.inherits] + if t and not inherited[t] then + mod.GetInherited(dvars, t, inherited) + end + end +end + +local GetClassInfo, GetNumClasses, GetNumSpecializationsForClassID, GetSpecializationInfoForClassID = GetClassInfo, GetNumClasses, GetNumSpecializationsForClassID, GetSpecializationInfoForClassID +mod.GetIndex = function() + print(cWord('**** Index Init')) + + local index = mod.index + local globalIndex = index.global + local nameIndex = index.name + local tdb = TurokData.spirit.timers + local classID = {} + local className = {} + local classSpecID = {} + local specIDClass = {} + + for id=1, GetNumClasses() do + local _, name = GetClassInfo(id) + classID[name] = id + className[id] = name + index[name] = setmetatable({}, index_mt) + + classSpecID[id] = {} + for h=1, GetNumSpecializationsForClassID(id) do + local specID, specName = GetSpecializationInfoForClassID(id, h) + classSpecID[id][h] = specID + specIDClass[specID] = id + end + end + + if not tdb then + print('Missing config table.') + return + end + --- Setup virtuals + for setID, entry in ipairs(tdb) do + if entry.virtual then + print('loading virtual set:', entry.name) + globalIndex[setID] = entry + nameIndex[entry.name or ('noname'.. setID)] = entry + end + end + + --- Starting readin' + for setID, entry in ipairs(tdb) do + if not entry.virtual then + + print('* .index.global['.. setID..'] =', entry.name) + local dvars = T.Config_Push({}, entry, nil, cKey('['..setID..']')..'.'..cWord('dvars')) + dvars.name = entry.name + globalIndex[setID] = dvars + + local name = dvars.name or ('noname'..setID) + nameIndex[name] = entry + print('* .timersByName['..name..'] =', setID, entry.setID) + + --- Combine with any inherited templates + if dvars.inherits and nameIndex[dvars.inherits] then + print('* Adding heritable data from', cText(dvars.inherits)) + mod.GetInherited(dvars, nameIndex[dvars.inherits], {[dvars] = dvars}) + --T.Config_Merge(dvars, nameIndex[dvars.inherits], dvars, cKey('['..setID..']')..'.'..cWord('dvars')) + end + -- class index + if not (dvars.playerClass or dvars.specID) then + for id, class in pairs(className) do + index[class][setID] = dvars + end + print('* indexed globally') + else + if dvars.playerClass then + if type(dvars.playerClass) ~= 'table' then + dvars.playerClass = {dvars.playerClass } + end + for i, playerClass in ipairs(dvars.playerClass) do + index[playerClass][setID] = dvars + print('* applying playerClass entry '..cNum(i)..': '..cWord(playerClass)) + end + end + + if dvars.specID then + if type(dvars.specID) ~= 'table' then + dvars.specID = {dvars.specID } + end + for i, specID in ipairs(dvars.specID) do + print('* applying globalSpecID entry '..cNum(i)..': '..cNum(specID)..' -> '..cWord(className[specIDClass[dvars.specID]])) + index[className[specIDClass[specID]]][setID] = dvars + end + end + end + end + end +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Timer/Timer.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,587 @@ +--- Turok - Timer/Timer.lua +-- @file-author@ +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +--- Defines common elements for the various timer HUDs +local ADDON, _A = ... +local _G, CreateFrame, tconcat, GetInventoryItemsForSlot, GetInventoryItemID = _G, CreateFrame, table.concat, GetInventoryItemsForSlot, GetInventoryItemID +local T, F, tostring, type, max, tinsert, unpack, UIParent, loadstring = _A.Addon, _A.LibFog, tostring, type, max, table.insert, unpack, _G.UIParent, loadstring +local mod = T.modules.TimerControl +local P = mod.prototype +local db + +local pairs, ipairs, gsub, sub, setmetatable = pairs, ipairs, string.gsub, string.sub, setmetatable +local INVTYPE_FINGER, INVSLOT_FINGER1, INVSLOT_FINGER2, INVTYPE_TRINKET, INVSLOT_TRINKET1, INVSLOT_TRINKET2 = +INVTYPE_FINGER, INVSLOT_FINGER1, INVSLOT_FINGER2, INVTYPE_TRINKET, INVSLOT_TRINKET1, INVSLOT_TRINKET2 +--@debug@ +local DEBUG = true +--@end-debug@ +local cType, cText, cNum, cWord, cKey, cPink, cBool = cType, cText, cNum, cWord, cKey, cPink, cBool +local print = function(...) + if not DEBUG then return end + if _G.Devian and _G.DevianDB.workspace ~= 1 then + _G.print('Timer', ...) + end +end + +local Timer_GetPrintHandler = function(self) + if self.trace then + return function(...) + print(...) + _G.print('TimerFocus', ...) + end else + return print + end +end +local pb_suppressed = {} + +function mod:OnInitialize() + + --@debug@ + TurokData.spirit.timers = Turok.defaults.spirit.timers + --@end-debug@ + self.db = TurokData.spirit + db = self.db + self.active_cooldowns = {} + self.cast_units = {} + self.buff_units = {} + self.loaded_types = {} + self.loaded_triggers = {} + self.equipped = {} + self.containers = {} + self.timers = {} -- active timers + self.empty_frames = {} -- foster table for frames released by talent change + + + T:RegisterChatCommand("tsp", self.Import_Open) + T:RegisterChatCommand("tka", self.Dialog_Command) + T:RegisterChatCommand("tki", self.CreateIndex) + --T:Print("/tsp to import spells. /tka to open create dialog") + -- suppress cacophony from all cooldowns activating at login + self.quiet = true + --self:ScheduleTimer(function() self:Dialog_Command() end, 4) + +end + +local mt_single = { + __mode = "v", + __newindex = function(t,k,v) + rawset(t,k,v) + _G.print('DB', 'TCMeta: adding leaf', k, '=', v) + end} +local mt_double = { + __index = function(t,k) + t[k] = setmetatable({}, mt_single) + _G.print('DB', 'TCMeta: add layer', k, '=', t[k]) + return t[k] + end, + __newindex = function(t,k,v) + rawset(t,k,v) + _G.print('DB', 'TCMeta: adding to top layer', k, '=', v) + end +} +local mt_error = { + __call =function (t, txt) + t.disable = true + tinsert(t, txt) + end +} + +--- Sets and cleans up index data used by event handlers +local Timer_UpdateIndex = function(self, key) + + -- Is there already an entry for this key/value? + if self.frames[key] then + local lim = #mod.frames[key] + --[[ + for i = self.frames[key]+1, lim, 1 do + mod.frames[key][i] = mod.frames[key+1] + end]] + --self.frames[key] = nil + print(' ', cText('mod.frames.')..cWord(key), '=', #mod.frames[key]) + print(' ', cText('self.frames.')..cWord(key), '=', cNum(self.frames[key])) + end + + if key then + local i = #mod.frames[key]+1 + --mod.frames[key][i] = self + self.frames[key] = i + print(' ', cText('self.frames.')..cWord(key), '=', #mod.frames[key]) + end + mod.loaded_types[key] = (#mod.frames[key] == 0) and nil or true + print(' ',cText(key..'_is_loaded'), '=', cBool(mod.loaded_types[key])) +end + +--- Loading initators +function mod:OnEnable() + mod.LoadPresets() + mod.GetIndex() + -- setup indexes, use nested weak table for status since they implicitly have a key variable + mod.frames = {} + for class, p in pairs(mod.prototype.status) do + print('nested index table', class) + mod.frames[class] = setmetatable({}, mt_double) + end + mod.frames.spellName = setmetatable({}, mt_double) + for class, p in pairs(mod.prototype.display) do + mod.frames[class] = setmetatable({}, mt_single) + end + for class, p in pairs(mod.prototype.trigger) do + mod.frames[class] = setmetatable({}, mt_single) + end + + local srcIndex = mod.timers + if T.playerClass and mod.index[T.playerClass] then + srcIndex = mod.index[T.playerClass] + print('*** Found index for '..tostring(T.playerClass)..', using that.') + else + print(cWord('*** Using global index.')) + end + mod.activeSpec = T.specID + + --- go through that list + for id, timer in pairs(srcIndex) do + local result, message = mod:EnableTimer(id, timer) + end + + mod.InitTimers() + --- Delay sound activations so there isn't a giant cacophony on load + mod:ScheduleTimer(function() + self.quiet = nil + end, db.audio_delay or 2) +end + +function mod:EnableTimer(id, dvars) + local print = Timer_GetPrintHandler(dvars) + print('-{', cPink(dvars.name)) + if not dvars then + if not mod.index.global[id] then + return false, "Unable to resolve dvars table." + end + dvars = mod.index.global[id] + end + if dvars.virtual then + return + end + + local spirit, newFrame = mod:GetTimer(id, dvars) + if not spirit then return spirit, newFrame end + + local cvars = spirit.cvars + local dvars = spirit.dvars + local trigger = P.trigger[cvars.type] + local display = P.display[cvars.display] + local cvars = spirit.cvars + local index = mod.frames + local print = Timer_GetPrintHandler(cvars) + + if spirit.disable then + return false, "Manually disabled." -- nothing to do, nothing to say + end + + --- Interpret STATUS vars + print(cText(' *** Merging Status Data')) + spirit.disable = dvars.disable + local pcount = 1 + for k, handler in pairs(P.status) do + if cvars[k] then + if handler.Init then + print(cWord(' * Firing ')..cKey(k)..cWord('.Init'), cNum(cvars[k])) + handler.Init(spirit, cvars[k]) + else + print(' ', cText('skipped'), cKey(k)) + end + pcount = pcount + 1 + end + end + + spirit.Event = trigger.Event + spirit.Value = trigger.Value + spirit.SetText = mod.SetText + spirit.LoadText = mod.LoadText + spirit.Query = trigger.Query + spirit.Set = trigger.Set + + --- Display handler init + if display.Init then + print(cText(' * Display Init:'), cKey(dvars.display)) + display.Init(spirit) + end + + --- Trigger handler and events Load() + print(cText(' * Trigger Init:'), cKey(dvars.type)) + trigger.Init(spirit) + + + if C_PetBattles.IsInBattle() then + spirit.disable = true + spirit.debug_info("Hidden for pet battle") + pb_suppressed[id] = true + end + + + if spirit.disable then + spirit:UnregisterAllEvents() + spirit.displayState = nil + spirit.prevState = nil + spirit:Hide() + return false, tconcat(spirit.debug_info,"\n") + else + print('--', self.disable and cPink('DISABLED') or cNum('ENABLED'), #spirit.debug_info > 0 and tconcat(spirit.debug_info,"\n"), '}') + return true, tconcat(spirit.debug_info,"\n") + end +end + +function mod:GetTimer(id, dvars) + local print = Timer_GetPrintHandler(dvars) + local newFrame + if not mod.timers[id] then + print(cKey(' [[CreateTimer')) + newFrame = true + --- Compile the cvar table from the various config layers: + -- Start with timer dvars, overwritten by any container settings, then a disable check, then merge in prototype values + local cvars = T.Config_Push({}, dvars, nil, cKey('['..id..']')..'.'..cWord('cvars')) + cvars.name = dvars.name -- push function ignores name keys + + if dvars.container and db.containers[dvars.container] then + print(cText(' * Merging Container overrides')) + T.Config_Push(cvars, db.containers[dvars.container], cvars, cKey('['..id..']')..'.'..cWord('cvars')) + end + + --- Stop here if disabled via SavedVars + if cvars.disable then + return false, "Manually disabled" + end + + --- Localize the stuff we are going to loop over + local display = P.display[cvars.display] + local trigger = P.trigger[cvars.type] + local displayType = cvars.display + local triggerType = cvars.type + if not (display and trigger) then + return nil, "Missing prototype data. Summary: "..tostring(displayType).."="..(display and 'OK' or 'MISSING') .. + " "..tostring(triggerType).."="..(trigger and 'OK' or 'MISSING') + end + + --- Establish the order in which values are merged + print(cText(' * Merging object CVars')) + local cvar_class = {cWord('db.'..displayType), cWord('db.'..triggerType), cWord('db.global')} + local cvar_array = { + db[displayType], + db[triggerType], + db.global, + } + local override_class = {cWord('trigger.'..cvars.type), cWord('display.'.. cvars.display)} + local override_array = { + display.cvars, + trigger.cvars } + + --- Table merge user settings + for i, p in pairs(cvar_array) do + print(' '..cNum(i)..' merge ['..cvar_class[i]..']') + T.Config_Merge(cvars, p, cvars, cKey('['..id..']')..'.'..cWord('cvars')) + end + + --- Overwrite with anything defined by the prototype structure because it's important + local _, odiff + for i, p in ipairs(override_array) do + _, odiff = T.Config_Push(cvars, p, cvars, cKey('['..id..']')..'.'..cWord('cvars')) + end + local print = Timer_GetPrintHandler(cvars) + + --- Create the UI frame and seed it with the data we just composed + local spirit = CreateFrame('Frame', 'TurokTimerFrame'..gsub(dvars.name, "[^%a%d]", ''), UIParent, display.inherits) + spirit.trace = cvars.trace + spirit.timerID = id + spirit.timerName = dvars.name + spirit.container = dvars.container + spirit.cvars = cvars + spirit.dvars = dvars + spirit.Update = display.Update + spirit.SetState = display.SetState + spirit.Report = mod.Report + spirit.Stats = trigger.Stats + + --- Set Layout Statics + T.SetFrameLayout(spirit, cvars) + + --- Create troubleshooting collection + spirit.debug_info = setmetatable({}, mt_error) + + --- Add the frame to corresponding prototype indexes + spirit.frames = {} + spirit.events = {} + + if spirit.display ~= displayType then + spirit.display = displayType + Timer_UpdateIndex(spirit, displayType) + end + if spirit.type ~= triggerType then + spirit.type = triggerType + Timer_UpdateIndex(spirit, triggerType) + end + --- Add the frame to global index + mod.timers[id] = spirit + end + + return mod.timers[id], newFrame +end + +function mod.InitTimers() + local print = function(...) _G.print('TimerEvent', ...) end + print('INIT TIMERS ====================') + for id, spirit in pairs(mod.timers) do + if spirit.disable then + print(id, 'disabled:', tconcat(spirit.debug_info or {}, ', ')) + else + + print(cText('init'), cNum(id), cWord(spirit.name)) + --- Throw a dry event to initialize values + print(cText(' *'), cWord('prototype.'..cKey(spirit.dvars.type)..'.'..cWord('Load'))) + P.trigger[spirit.dvars.type].Event(spirit) + + --- Set loose + print(cText(' *'), cWord('prototype')..'.'..cKey('events')..'.'..cWord('Load')) + mod.UpdateEvents(spirit, P.trigger[spirit.dvars.type].events) + end + end + print('INIT DONE =========================') +end + +function mod:DisableTimer(name, timer) + local timer_frame = mod.db.timers[name] + if timer_frame and not timer_frame.disable then + timer_frame.disable = true + timer_frame:UnregisterAllEvents() + timer_frame:Hide() + end +end + +function mod.UpdateEvents(self, events) + local print = Timer_GetPrintHandler(self) + + self:SetScript('OnEvent', nil) + self:UnregisterAllEvents() + + local proxy, listen = {}, {} + for event, handler in pairs(events) do + if mod[event] then + tinsert(proxy, cNum(event)) + else + tinsert(listen, cWord(event)) + self:RegisterEvent(event) + end + self.events[event] = handler + end + + if #proxy > 0 then + print( ' -', cKey(self.name), cWord('receiving'), tconcat(proxy, ', ')) + end + if #listen > 0 then + print( ' -', cKey(self.name), cText('listening'), tconcat(listen, ', ')) + end + + self:SetScript('OnEvent', self.Event) +end + +local match_sub = { + {'%%c', "' .. tostring(t.caster).. '"}, + {'%%h', "' .. tostring((t.valueFull >= 60) and (math.floor(t.valueFull/60)) or t.value) .. '"}, + {'%%i', "' .. tostring((t.valueFull >= 60) and (t.value % 60) or ((t.valueFull < 6) and math.floor((t.ValueFull * 100) % 100) or '')) .. '"}, + {'%%n', "' .. tostring(t.spellName) .. '"}, + {'%%p', "' .. tostring(t.value) .. '"}, + {'%%d', "' .. tostring(t.chargeDuration or t.duration) .. '"}, + {'%%%.p', "' .. string.sub(tostring((t.valueFull %% 1) * 100),0,1) .. '"}, + {"%%s", "' .. (t.stacks or t.charges or '') .. '"}, +} + +-- dot syntax implies use as embedded method +function mod.LoadText(self) + print(cKey('parsing textRegions for'), self.timerName, self.timerID) + self.textTypes = {} + self.textValues = {} + for name, region in pairs(self.textRegions) do + print(' ', cWord('textRegions')..'["'.. cType(self.timerName)..'"].'..cType(name)) + if self.cvars[name..'Text'] then + + -- todo: collect match counts and index the text fields by match types + local str = self.cvars[name..'Text'] + for i, args in ipairs(match_sub) do + if str:match(args[1]) then + if not self.textTypes[args[1]] then + self.textTypes[args[1]] = {} + end + tinsert(self.textTypes[args[1]], region) + str = str:gsub(args[1], args[2]) + end + end + str = "local t = _G.Turok.modules.TimerControl.timers["..self.timerID.."]\n" + .. "\n return '" .. str .. "'" + local func = assert(loadstring(str)) + self.textValues[name] = func + end + end + + --mod.SetText(self) +end + +--- generic text setter +local HIDDEN, PASSIVE, ACTIVE = 0, 1, 2 +mod.SetText = function(self) + if self.displayState ~= ACTIVE then + for name, region in pairs(self.textRegions) do + region:SetText(nil) + end + return + end + + if not self.textValues then + self.textValues = {} + mod.LoadText(self, self.cvars) + end + + -- hide when above a certain number + + if self.spiral and self.spiral.subCounter then + if self.valueFull > 6 then + if self.textValues.subCounter then + --print('hiding milliseconds') + self.textRegions.subCounter:Hide() + self.textRegionsSub = self.textRegions.subCounter + self.textValuesSub = self.textValues.subCounter + self.textRegions.subCounter = nil + self.textValues.subCounter = nil + end + else + if not self.textValues.subCounter then + --print('showing milliseconds') + self.textValues.subCounter = self.textValuesSub + self.textRegions.subCounter = self.textRegionsSub + self.textRegions.subCounter:Show() + end + end + end + + for name, region in pairs(self.textRegions) do + --print(name) + --print(name, self.timerName, self.textValues[name](self)) + region:SetText(self.textValues[name](self)) + end +end + + +------------------------------------------------------------------------- +--- Second-tier handlers to cut down on the number of Status:Event() polls + +--- UNIT_SPELLCAST_*** use args to filter out the number of full handler runs +function mod:UNIT_SPELLCAST_SUCCEEDED (e, unit, spellName, rank, castID, spellID) + if not mod.frames.unit[unit] then + return + end + + if #mod.frames.spellName[spellName] > 0 then + print('spellName-ID relation detected:', cWord(spellName), cNum(spellID)) + for i, frame in pairs(mod.frames.spellName[spellName]) do + if not frame.frames.spellID then + frame.frames.spellID = {} + end + if not frame.frames.spellID[spellID] then + + tinsert(mod.frames.spellID[spellID], frame) + frame.frames.spellID[spellID] = #mod.frames.spellID[spellID] + print(cText(' updating'), cKey(frame.timerName)) + end + end + mod.frames.spellName[spellName] = nil + end + + + + if mod.frames.spellID[spellID] then + for i, timer_frame in pairs(mod.frames.spellID[spellID]) do + print(cText('caught spell'), cWord(spellName), 'for', timer_frame:GetName()) + timer_frame:Event(e, unit, spellName, rank, castID, spellID) + end + end +end +mod.UNIT_SPELLCAST_CHANNEL_START = mod.UNIT_SPELLCAST_SUCCEEDED + +--- Fire a dry event to force status updates on units with changing GUID's +function mod:PLAYER_TARGET_CHANGED(e, unit) + print('doing a target swap thing') + for k, v in pairs( self.frames.unit.target) do + print(k, v) + v:Event(nil, 'target') + end +end + +--- Same thing but for talent/spec-driven +function mod:PLAYER_TALENT_UPDATE(e, unit) + print('') + print('') + print(cText(e), T.specPage, T.specName) + + local update_queue = {} + for _, k in ipairs({'talentID', 'talentRow', 'specPage'}) do + for value, frameSet in pairs(mod.frames.talentID) do + for id, frame in ipairs(frameSet) do + print(frame.timerID, frame.timerName) + update_queue[frame.timerID] = frame + end + end + end + + for id, frame in pairs(update_queue) do + print('Refreshing spec-related frames', id, frame.timerName) + frame.disable = nil + table.wipe(frame.debug_info) + local res, msg = mod:EnableTimer(id, frame.dvars) + end + +end + +function mod:PLAYER_EQUIPMENT_CHANGED(e, slot, hasItem) + print(e, slot, hasItem) + local itemCheckList + if mod.frames.inventoryID and mod.frames.inventoryID[slot] then + print(' Inventory Frames:') + itemCheckList = GetInventoryItemsForSlot(slot, {}, false) + for id, slotFrame in pairs(mod.frames.inventoryID[slot]) do + print(' * Updating', cNum(id), cWord(slotFrame.timerName)) + local res, msg = mod:EnableTimer(slotFrame.timerID, slotFrame.dvars) + print(' ', cBool(res), cText(msg)) + end + end + if itemCheckList then + print(unpack(itemCheckList)) + end + local itemID = GetInventoryItemID('player', slot) + if itemID and mod.frames.itemID[itemID] then + print(' Item ID Frames:') + for id, itemFrame in pairs(mod.frames.itemID[itemID]) do + print(' * Updating', cNum(id), cWord(itemFrame.timerName)) + + local res, msg = mod:EnableTimer(itemFrame.timerID, itemFrame.dvars) + print(' ', cBool(res), cText(msg)) + end + end +end +function mod:PET_BATTLE_OPENING_START () + for i, v in pairs(mod.timers) do + if not v.disable then + print('suppressing', v:GetName()) + v.disable = true + v:Hide() + pb_suppressed[i] = true + end + end +end +function mod:PET_BATTLE_CLOSE() + for id, v in pairs(mod.timers) do + if pb_suppressed[id] then + print('restoring', v:GetName()) + mod:EnableTimer(id) + pb_suppressed[id] = nil + end + end +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Timer/Timer.xml Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,327 @@ +<!-- + Timer-specific XML defs +--> +<Ui> + <Script file="Timer.Init.lua" /> + <Script file="Presets.lua" /> + <Script file="Timer.lua" /> + <Script file="Container.lua" /> + <Script file="Status.lua" /> + <Script file="Aura.lua" /> + <Script file="Cooldown.lua" /> + <Script file="Icon.lua" /> + <Script file="Progressbar.lua" /> + <Script file="Import.lua" /> + <Script file="Editor.lua" /> + + + <!-- EASY TIMER FRAME --> + + <Frame name="TurokTimerScripts" parent="UIParent" virtual="true" hidden="true"> + <Scripts> + <OnLoad> + self.textRegions = {} + </OnLoad> + <OnShow> + self:Report() + </OnShow> + <OnHide> + self:Report() + </OnHide> + <OnUpdate> + self:Update() + </OnUpdate> + </Scripts> + <Size x="64" y="64" /> + <Anchors> + <Anchor point="CENTER" /> + </Anchors> + <Animations> + <AnimationGroup parentKey="iconIntro" looping="NONE" ignoreFramerateThrottle="true"> + <Scale childKey="icon" order="1" duration=".10" fromScaleX="0.1" toScaleX="1.0" fromScaleY=".1" toScaleY="1" /> + </AnimationGroup> + <AnimationGroup parentKey="Intro" looping="NONE" ignoreFramerateThrottle="true"> + <Alpha childKey="foreground" order="1" duration=".5" fromAlpha="0" toAlpha="1" /> + <Alpha childKey="background" order="1" duration=".5" fromAlpha="0" toAlpha="1" /> + <Scripts> + <OnPlay> + local g = self:GetParent() + g.collected = nil + g.add = true + g:Report() + --@debug@ + print('Layout', g.cvars.type, 'Intro |cFFFFFF00START', g:GetName())--@end-debug@ + g:Show() + if g.cvars.sound_active then + PlaySoundFile(g.cvars.sound_active) + end + if g.icon then + g.iconIntro:Play() + end + </OnPlay> + <OnStop> + local g = self:GetParent() + --@debug@ + print('Layout', g.cvars.type, 'Intro |cFFFF4400STOP', g:GetName())--@end-debug@ + if g.enableIcon then + g.iconIntro:Stop() + end + </OnStop> + <OnFinished> + local g = self:GetParent() + --@debug@ + print('Layout', g.cvars.type, 'Intro |cFF00FF00FINISH', g:GetName())--@end-debug@ + if g.enableIcon then + g.iconIntro:Stop() + end + g:UpdateAlpha(Turok.inCombat, g.displayState, g.fillState) + </OnFinished> + </Scripts> + </AnimationGroup> + <AnimationGroup parentKey="iconOutro" looping="NONE" ignoreFramerateThrottle="true"> + <Scale childKey="icon" order="1" duration=".10" fromScaleX="1" toScaleX="0.1" fromScaleY="1" toScaleY="0.1"/> + </AnimationGroup> + <AnimationGroup parentKey="Outro" looping="NONE" ignoreFramerateThrottle="true"> + <Alpha childKey="foreground" order="1" duration=".5" change="-1" /> + <Alpha childKey="background" order="1" duration=".5" change="-1" /> + <Scripts> + <OnPlay> + local g = self:GetParent() + g.collected = nil + g.trash = true + g:Report() + --@debug@ + print('Layout', g.cvars.type, '|cFF0088FFOutro |cFFFFFF00START', g:GetName())--@end-debug@ + if g.spiral then + g.spiral:StopAnimating() + g.spiral:Hide() + end + if g.cvars.sound_hidden then + PlaySoundFile(g.cvars.sound_hidden) + end + if g.enableIcon then + g.iconOutro:Play() + end + </OnPlay> + <OnStop> + local g = self:GetParent() + --@debug@ + print('Layout', g.cvars.type, '|cFF0088FFOutro |cFFFF4400STOP', g:GetName())--@end-debug@ + if g.enableIcon then + g.iconOutro:Stop() + end + </OnStop> + <OnFinished> + local g = self:GetParent() + g.trash = false + --@debug@ + print('Layout', g.cvars.type, '|cFF0088FFOutro |cFF00FF00Finish', g:GetName())--@end-debug@ + if g.enableIcon then + g.iconOutro:Stop() + end + g:Hide() + </OnFinished> + </Scripts> + </AnimationGroup> + <AnimationGroup parentKey="Retro" looping="NONE" ignoreFramerateThrottle="true"> + <Alpha childKey="iconFlash" fromAlpha="0" toAlpha=".7" duration="0.05" order="1" /> + <Alpha childKey="iconFlash" fromAlpha=".7" toAlpha="0" duration="0.15" order="2" /> + <Scripts> + <OnPlay> + local g = self:GetParent() + --@debug@ + print('Layout', g.cvars.type, '|cFFFFFF00Retro |cFFFFFF00START', g:GetName())--@end-debug@ + if g.iconFlash then + g.iconFlash:Show() + end + </OnPlay> + <OnStop> + local g = self:GetParent() + --@debug@ + print('Layout',g.cvars.type, '|cFFFFFF00Retro |cFFFF4400STOP', self:GetParent():GetName())--@end-debug@ + </OnStop> + <OnFinished> + local g = self:GetParent() + --@debug@ + print('Layout',g.cvars.type, '|cFFFFFF00Retro |cFF00FF00FINISH', g:GetName())--@end-debug@ + if g.iconFlash then + g.iconFlash:Hide() + end + g:UpdateAlpha(Turok.inCombat, g.displayState, g.fillState) + </OnFinished> + </Scripts> + </AnimationGroup> + <AnimationGroup name="Slider" parentKey="slide" ignoreFramerateThrottle="true" looping="NONE"> + <Translation parentKey="t1" duration="0.11" order="1" /> + </AnimationGroup> + </Animations> + <Layers> + <Layer level="BACKGROUND"> + <Texture file="Interface\ICONS\INV_Misc_QuestionMark" name="$parentSpellIcon" parentKey="icon" textureSubLevel="-7" hidden="true"> + <TexCoords top="0.1" left="0.1" bottom="0.9" right="0.9" /> + </Texture> + </Layer> + <Layer level="ARTWORK"> + <Texture parentKey="iconFlash" name="$parentIconFlashBox" hidden="true"> + <Anchor point="TOPLEFT" relativeKey="icon"/> + <Anchor point="BOTTOMRIGHT" relativeKey="icon" /> + <Color r="1" g="1" b="1" a="1" /> + </Texture> + </Layer> + <Layer level="OVERLAY"> + <Texture parentKey="debugPanel" name="$parentDebugWindow" hidden="true"> + <Anchors> + <Anchor point="TOPLEFT" relativePoint="BOTTOMLEFT" /> + <Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT" x="0" y="-40" /> + </Anchors> + </Texture> + <FontString inherits="TurokFontDetail" justifyH="LEFT"> + <Anchors> + <Anchor point="TOPLEFT" /> + </Anchors> + </FontString> + </Layer> + </Layers> + </Frame> + + <Frame name="TurokIconTemplate" parent="UIParent" virtual="true" hidden="true" inherits="TurokTimerScripts"> + <Scripts> + <OnLoad inherit="prepend"> + -- not using parentArray because we want name info + self.textRegions = { + counter = self.spiral.counter, + subCounter = self.spiral.subCounter, + charges = self.spiral.charges + } + </OnLoad> + </Scripts> + <Frames> + <Cooldown name="$parentCooldownSpiral" parentKey="spiral" inherits="CooldownFrameTemplate"> + <SwipeTexture parentKey="spiralTex"> + <Color r="0" g="0" b="0" a="0.6" /> + </SwipeTexture> + <Anchors> + <Anchor relativeKey="$parent.icon" point="TOPLEFT" relativePoint="TOPLEFT" x="0" y="0" /> + <Anchor relativeKey="$parent.icon" point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT" x="0" y="0" /> + </Anchors> + <Layers> + <Layer level="OVERLAY"> + <FontString inherits="TurokFontMed" name="$parentCounter" parentKey="counter" justifyH="RIGHT" justifyV="BOTTOM"> + <KeyValues> + <!-- [1] below 6 seconds remaining --> + <KeyValue key="anchor1" value="TOP" /> + <KeyValue key="anchor1_rel" value="TOP" /> + <!-- [2] default --> + <KeyValue key="anchor2" value="TOP" /> + <KeyValue key="anchor2_rel" value="TOP" /> + <!-- [3] > 100 sec remaining --> + <KeyValue key="anchor3" value="TOPRIGHT" /> + <KeyValue key="anchor3_rel" value="TOP" /> + </KeyValues> + <Size x="40" y="40" /> + <Anchors> + <Anchor point="TOPRIGHT" relativePoint="TOP" relativeKey="$parent.$parent.icon" x="0" y="4" /> + </Anchors> + </FontString> + <FontString inherits="TurokFontDetail" name="$parentSubCounter" parentKey="subCounter" justifyH="LEFT" text="subtext" justifyV="BOTTOM"> + <KeyValues> + <KeyValue key="anchor1" value="LEFT" /> + <KeyValue key="anchor1_rel" value="RIGHT" /> + <KeyValue key="anchor2" value="LEFT" /> + <KeyValue key="anchor2_rel" value="RIGHT" /> + <KeyValue key="anchor3" value="LEFT" /> + <KeyValue key="anchor3_rel" value="RIGHT" /> + </KeyValues> + <Size x="40" y="40" /> + <Color r="1" g="1" b="0" a="1" /> + <Anchors> + <Anchor point="LEFT" relativePoint="RIGHT" relativeKey="$parent.counter" x="0" y="1" /> + </Anchors> + </FontString> + <FontString inherits="TurokFontDetail" name="$parentCharges" parentKey="charges" justifyH="RIGHT" justifyV="BOTTOM" text="charges"> + <Size x="80" y="30" /> + <Color a="1" r="1" g="1" b="0" /> + <Anchors> + <Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT" /> + </Anchors> + </FontString> + </Layer> + </Layers> + </Cooldown> + </Frames> + </Frame> + + <Frame name="TurokProgressbarTemplate" parent="UIParent" virtual="true" hidden="true" inherits="TurokTimerScripts"> + <Scripts> + <OnLoad inherit="prepend"> + self.textRegions = { + left = self.left, + right = self.right + } + </OnLoad> + </Scripts> + <Layers> + + <Layer level="BACKGROUND"> + + + <Texture name="$parentProgressBackground" parentKey="background" textureSubLevel="0" /> + </Layer> + <Layer level="ARTWORK"> + <Texture name="$parentProgressForeground" parentKey="foreground" textureSubLevel="1" /> + </Layer> + + <Layer level="OVERLAY"> + <FontString inherits="TurokFontDetail" name="$parentLeftText" parentKey="left" justifyH="LEFT"> + <Anchors> + <Anchor point="LEFT" /> + </Anchors> + </FontString> + <FontString inherits="TurokFontDetail" name="$parentRightText" parentKey="right" justifyH="RIGHT"> + <Anchors> + <Anchor point="RIGHT" /> + </Anchors> + </FontString> + </Layer> + </Layers> + </Frame> + + <!-- Collector Tray --> + <Frame name="TkContainerTemplate" virtual="true" parent="UIParent" alpha="1" movable="true"> + <Size x="700" y="200" /> + <Scripts> + <OnLoad> + self:RegisterForDrag('LeftButton') + self:EnableMouse(false) -- for now + </OnLoad> + <OnDragStart> + if self:GetEnableMouse() then + self.cx = self:GetLeft() + self.cy = self:GetTop() + self:StartMoving() + end + </OnDragStart> + <OnDragStop> + self:StopMovingOrSizing() + self.x = self.x + (self:GetLeft() - self.cx) + self.y = self.y + (self:GetTop() - self.cy) + self:SetPoint(self.anchor, self.parent, self.anchorTo, self.x, self.y) + </OnDragStop> + </Scripts> + <Layers> + <Layer level="BACKGROUND"> + <Texture name="$parentBackdrop" parentKey="ConfigBG" setAllPoints="true" hidden="true"> + <Color r="1" g="1" b="1" a="0.25" /> + </Texture> + </Layer> + <Layer level="OVERLAY"> + <FontString name="$parentNameTag" parentKey="NameText" inherits="TurokFont" justifyH="LEFT" justifyV="BOTTOM" hidden="true"> + <Anchors> + <Anchor point="BOTTOMLEFT" relativePoint="TOPLEFT" x="0" y="2" /> + </Anchors> + </FontString> + </Layer> + </Layers> + </Frame> + +</Ui> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Utilities/Chat.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,8 @@ +--- ${PACKAGE_NAME} +-- @file-author@ +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +-- Created: 2/19/2016 9:00 AM +local ADDON, env = ... +local mod = Turok:NewModule("Chat") +setfenv(0, env) \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Utilities/PetBattle.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,288 @@ +--- ${PACKAGE_NAME} +-- @file-author@ +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +-- Created: 1/17/2016 6:51 PM + +local ADDON, Turok = ... +local T, _G, pairs, pairs = Turok.Addon, _G, pairs, ipairs +local mod = T:NewModule("PetBattle") +local print = function(...) _G.print('Petz', ...) end +local trace = function(self, e, ...) + print(e, ...) +end + +local PBS +local turn_font = [[Interface\Addons\Turok\Media\font\ArchivoNarrow-Bold.ttf]] +local turn_size = 24 +local turn_outline = 'OUTLINE' +local icon_size = 64 +local spacing = 5 +local padding = 0 +local strongweak_size = 20 + +local cpb = C_PetBattles +T.defaults.petbattle = { + swatch = { + anchor = 'BOTTOM', anchorTo = 'BOTTOM', + parent = 'UIParent', + x = 0, y =240, + width = 200, height = 100, + font = [[Interface\Addons\Turok\Media\font\ArchivoNarrow-Bold.ttf]], + size = 16, + }, + spell = { + anchor = 'TOPLEFT', anchorTo = 'TOPLEFT', + size = 24, + width = 72, height = 72, + x = 0, y =0, + padding = 0, + spacing = 0, + }, + sideSwatch = { + width = 100, height = 50, padding = 0, spacing = 5, + anchor = 'TOPLEFT', anchorTo = 'BOTTOMLEFT', x = 0, y = 0, + parent = 'TkPetSwatch', + }, + sideSpell = { + anchor = 'TOPLEFT', anchorTo = 'TOPLEFT', + size = 16, + width = 36, height = 36, + padding = 0, + spacing = 0, + }, + icon = { + size = 72, + width = 64, + height = 64, + } +} +mod.abilityButtons = {} +mod.switcherButtons = {} +mod.icons = {} +mod.strongweak = {} +mod.turns = {} +mod.petlist = {} +local PLAYER, ENEMY = 1, 2 +local function PBS_UpdateEnemySwatch(self) + + print('UpdateSwatch') + local db = TurokData.petbattle.swatch + local playerActivePet = cpb.GetActivePet(PLAYER) + local enemyActivePet = cpb.GetActivePet(ENEMY) + local enemyNumPets = cpb.GetNumPets(ENEMY) + local playerPetType = cpb.GetPetType(PLAYER, playerActivePet) + local enemyPetType = cpb.GetPetType(ENEMY, enemyActivePet) + local enemyPetName = cpb.GetName(ENEMY, playerActivePet) + for petSlot=1, 3 do + local swatchFrame = (petSlot == enemyActivePet) and self or ((petSlot < enemyNumPets) and self.sideSwatch or self.sideSwatch2) + local db = (swatchFrame == self) and db.spell or db.sideSpell + local type = cpb.GetPetType(ENEMY, petSlot) + print(cText(' PetType='), enemyActivePet) + print(cText(' current='), enemyPetType) + for spellSlot=1, 3 do + print(' ', cText('PetSlotOffset='), cNum(petSlot), cText('AbilitySlotOffset'), cNum(spellSlot)) + local id, name, texture, cooldown, desc, numTurns, attackType, noStrongWeakHints = cpb.GetAbilityInfo(ENEMY, petSlot, spellSlot) + local usable, remaining = cpb.GetAbilityState(ENEMY, petSlot, spellSlot) + + --print('info', cpb.GetAbilityInfo(ENEMY, petSlot, spellSlot)) + -- print('effect', cpb.GetAbilityEffectInfo(id, turnIdx, effectIdx, paramName) + --print('state', cpb.GetAbilityState(ENEMY,petSlot,spellSlot)) + --print('statemod', cpb.GetAbilityStateModification(ENEMY,petSlot,spellSlot)) + --print('proc', cpb.GetAbilityProcTurnIndex(ENEMY,petSlot,spellSlot)) + --print('statemod', cpb.GetAbilityState(ENEMY,petSlot,spellSlot)) + local AbilityButton, icon, strong, turns -- Icon, Strength/Weakness, Turns cooldown + if not swatchFrame.buttons[spellSlot] then + swatchFrame.buttons[spellSlot] = CreateFrame('Frame', 'TkPetSpell'..spellSlot, swatchFrame, 'TkPetSpellTemplate') + AbilityButton = swatchFrame.buttons[spellSlot] + + AbilityButton:SetSize(db.width, db.height) + AbilityButton:SetPoint(db.anchor, swatchFrame, db.anchor, (spellSlot-1)*(db.width+ db.spacing), 0) + + AbilityButton.icon:SetSize(db.width, db.height) + AbilityButton.icon:SetTexCoord(0.1, 0.9, 0.1, 0.9) + + AbilityButton.strongWeakHint:SetSize(strongweak_size, strongweak_size) + AbilityButton.strongWeakHint:SetPoint('CENTER', swatchFrame.buttons[spellSlot], 'CENTER', 0, 0) + + AbilityButton.turnsLeft:SetFont(turn_font, turn_size, turn_outline) + AbilityButton.turnsLeft:SetPoint('CENTER', icon, 'CENTER') + else + AbilityButton = swatchFrame.buttons[spellSlot] + end + local icon, strong , turns = AbilityButton.icon, AbilityButton.strongWeakHint, AbilityButton.turnsLeft + + print('Working on:', swatchFrame, AbilityButton) + print('AbilityState('..petSlot..', '..spellSlot..')', 'usable=', usable, 'turnsLeft=', remaining) + print(cWord(name), cKey(attackType)) + + if petSlot > enemyNumPets then + -- this will also eval true when pet battle over since numPets will be 0 + AbilityButton.popOut:Play() + else + local abilityChanged + if id ~= AbilityButton.spellID then + abilityChanged = true + AbilityButton.spellID = id + AbilityButton.spellName = name + AbilityButton.spellDesc = desc + AbilityButton.spellType = attackType + AbilityButton.spellMaxCooldown = cooldown + AbilityButton.spellDesc = desc + AbilityButton.spellCooldown = remaining + AbilityButton.spellNumTurns = numTurns + end + if AbilityButton.petType ~= enemyPetType then + AbilityButton.petType = enemyPetType + AbilityButton.noStrongWeakHints = noStrongWeakHints + end + + if not usable then + icon:SetDesaturated(true) + icon:SetVertexColor(0.5, 0.5, 0.5, 1) + else + icon:SetDesaturated(false) + icon:SetVertexColor(1, 1, 1, 1) + end + + icon:SetTexture(texture) + turns:SetText((cooldown > 0) and cooldown or nil) + --AbilityButton.damage:SetText() + + print('noStrongWeakHints', noStrongWeakHints) + print('abilityModification', cpb.GetAttackModifier(enemyPetType, playerPetType)) + local modifier = cpb.GetAttackModifier(enemyPetType, playerPetType) + if not noStrongWeakHints then + if modifier < 1 then + strong:SetTexture(0,1,0,0.5) + else + strong:SetTexture(1,0,0,0.5) + end + + strong:Show() + else + strong:Hide() + end + if numTurns then + print('numTurns=',numTurns) + end + if not AbilityButton:IsVisible() or abilityChanged then + AbilityButton:Show() + AbilityButton.popIn:Play() + end + + end + + + end + swatchFrame:SetSize(db.width*3+db.spacing*2+db.padding*2, db.height+padding*2) + swatchFrame.petName = enemyPetName + swatchFrame.petType = enemyPetType + local db = (swatchFrame == self) and db.swatch or db.sideSwatch + swatchFrame:Show() + end +end + +local function PBS_Switch () + print('Switch button was clicked.') +end +mod.PLAYER_ENTERING_WORLD = function(self, e) + print(cpb.IsInBattle()) + if cpb.IsInBattle() then + PBS_UpdateEnemySwatch(PBS, e, 2) + end + + + if _G.PetBattleFrame.BottomFrame.SwitchPetButton then + print("There's a pet battle frame button ") + --_G.PetBattleFrame.BottomFrame.SwitchPetButton:SetScript('OnClick', PBS_Switch) + end +end + +local PBS_Hide = function() + for i = 1, 3 do + if PBS.buttons[i] then + PBS.buttons[i].popOut:Play() + end + if PBS.sideSwatch.buttons[i] then + PBS.sideSwatch.buttons[i].popOut:Play() + end + if PBS.sideSwatch2.buttons[i] then + PBS.sideSwatch2.buttons[i].popOut:Play() + end + end +end + +local PBS_Event = function(self, e, ...) + print('event', e) + local owner = ... + if e == 'PET_BATTLE_PET_ROUND_PLAYBACK_COMPLETE' or e == 'PET_BATTLE_OPENING_DONE' then + PBS_UpdateEnemySwatch(PBS) + elseif e == 'PET_BATTLE_CLOSE' then + PBS_Hide(PBS) + end +end +function mod:OnEnable() + PBS = CreateFrame('Frame', 'TkPetSwatch', UIParent, 'TkPetSwatchTemplate') + PBS.buttons = {} + PBS.sideSwatch = CreateFrame('Frame', 'TkSideSwatch', PBS, 'TkPetSwatchTemplate') + PBS.sideSwatch.buttons = {} + PBS.sideSwatch2 = CreateFrame('Frame', 'TkSideSwatch', PBS, 'TkPetSwatchTemplate') + PBS.sideSwatch2.buttons = {} + local db = TurokData.petbattle + T.SetFrameLayout(PBS, db.swatch) + T.SetFrameLayout(PBS.sideSwatch, db.sideSwatch) + T.SetFrameLayout(PBS.sideSwatch2, db.sideSwatch) + PBS.sideSwatch2:ClearAllPoints() + PBS.sideSwatch2:SetPoint('LEFT', PBS.sideSwatch, 'RIGHT', db.sideSpell.spacing, 0) + + mod.effectIndex = { + cpb.GetAllEffectNames() + } + + PBS:SetScript('OnEvent', PBS_Event) + PBS:RegisterEvent('PET_BATTLE_OPENING_DONE') + PBS:RegisterEvent('PET_BATTLE_PET_CHANGED') + PBS:RegisterEvent('PET_BATTLE_OVER') + PBS:RegisterEvent('PET_BATTLE_CLOSE') + PBS:RegisterEvent('PET_BATTLE_ABILITY_CHANGED') + PBS:RegisterEvent('PET_BATTLE_ACTION_SELECTED') + --PBS:RegisterEvent('PET_BATTLE_AURA_APPLIED') + --PBS:RegisterEvent('PET_BATTLE_AURA_CANCELED') + --PBS:RegisterEvent('PET_BATTLE_PET_TYPE_CHANGED') + PBS:RegisterEvent('PET_BATTLE_TURN_STARTED') + --PBS:RegisterEvent('PET_BATTLE_HEALTH_CHANGED') + --PBS:RegisterEvent('PET_BATTLE_MAX_HEALTH_CHANGED') + PBS:RegisterEvent('PET_BATTLE_PET_ROUND_RESULTS') + PBS:RegisterEvent('PET_BATTLE_PET_ROUND_PLAYBACK_COMPLETE') +end + +--[[ +mod.PET_BATTLE_OPENING_DONE = trace +mod.PET_BATTLE_OPENING_START = trace +mod.PET_BATTLE_OVER = trace +mod.PET_BATTLE_ABILITY_CHANGED = trace +mod.PET_BATTLE_ACTION_SELECTED = trace +mod.PET_BATTLE_AURA_APPLIED = trace -- <team> <slot> <id> +mod.PET_BATTLE_AURA_CANCELED = trace -- <team> <slot> <id> +mod.PET_BATTLE_AURA_CHANGED = trace -- <team> <slot> <id> +mod.PET_BATTLE_CAPTURED = trace +mod.PET_BATTLE_CLOSE = trace +mod.PET_BATTLE_FINAL_ROUND = trace -- <team> +mod.PET_BATTLE_HEALTH_CHANGED = trace -- <team> <pet slot> <delta> +mod.PET_BATTLE_LEVEL_CHANGED = trace +mod.PET_BATTLE_LOOT_RECEIVED = trace +mod.PET_BATTLE_MAX_HEALTH_CHANGED = trace +mod.PET_BATTLE_PET_CHANGED = trace -- <team> +mod.PET_BATTLE_PET_TYPE_CHANGED = trace -- <team> <slot> <type> +mod.PET_BATTLE_PET_ROUND_PLAYBACK_COMPLETE = trace -- <round number> +mod.PET_BATTLE_PET_ROUND_RESULTS = trace -- <round number> +mod.PET_BATTLE_PVP_DUEL_REQUESTED = trace +mod.PET_BATTLE_PVP_DUEL_REQUEST_CANCEL = trace +mod.PET_BATTLE_QUEUE_PROPOSAL_ACCEPTED = trace +mod.PET_BATTLE_QUEUE_PROPOSAL_DECLINED = trace +mod.PET_BATTLE_QUEUE_PROPOSE_MATCH = trace +mod.PET_BATTLE_QUEUE_STATUS = trace +mod.PET_BATTLE_TURN_STARTED = trace +mod.PET_BATTLE_XP_CHANGED = trace -- <team> <slot> <exp> +--]] \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Utilities/Raid.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,152 @@ +--- Turok Raid/Raid.lua +-- @file-author@ +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +--- Defines the interfaces for raid tools +local T = Turok +local mod = T:NewModule('RaidReady') +mod.OnInitialize = function(self) + self.db = TurokData.Lost + self.events = { + PARTY_MEMBERS_CHANGED = self.MembersChangedEvent, + PLAYER_SPECIALIZATION_CHANGED = self.SpecChangeEvent, + ENCOUNTER_START = self.EncounterStart, + UNIT_AURA = self.UnitAura + } +end + +T.defaults.Lost = { + parent = 'UIParent', + anchor = 'BOTTOMRIGHT', anchorTo = 'BOTTOMRIGHT', + x = -300, y = 300, + height = 24*9, width = 72, + width = 72, + height = 24, + size = 11, + font = "Interface\\Addons\\Turok\\Media\\font\\ArchivoNarrow-Bold.ttf", + + raidbuff = { + icon = {}, + status = {}, + }, + + durability = { + + }, + + toast = { + + }, +} +local _G = _G +local print = function(...) if Devian and DevianDB.workspace~= 1 then print('RaidInfo', ...) end end +local CreateFrame, floor, GetRaidBuffTrayAuraInfo, NUM_LE_RAID_BUFF_TYPES = CreateFrame, math.floor, GetRaidBuffTrayAuraInfo, NUM_LE_RAID_BUFF_TYPES +local GetSpecialization, GetSpecializationInfo, GetSpecializationInfoByID = GetSpecialization, GetSpecializationInfo, GetSpecializationInfoByID +local IsInRaid, IsInGroup, GetInspectSpecialization = IsInRaid, IsInGroup, GetInspectSpecialization +local find, match, sub = string.find, string.match, string.sub +local GetRealmName, GetRaidRosterInfo, UnitGUID = GetRealmName, GetRaidRosterInfo, UnitGUID +local db + +function mod:OnEnable() + db = self.db + + self.raidbuffs = {} -- active raid buffs + self.buffinfo = {} -- raid buff text + self.available = {} -- availability info + self.units_raid = {} + + self.raidbuffs_tray = _G.TurokRaidbuffsTray + + -- seed raid buff analyzer assets + self.num_raidbuff_columns = floor(db.raidbuff.width / db.raidbuff.icon.width) + for i = 1, 9 do + --print('TurokRaidbuffButton'..i, self.raidbuffs_tray, 'TurokRaidbuffButton') + local buff = CreateFrame('Button', 'TurokRaidbuffButton'..i, self.raidbuffs_tray, 'TurokRaidbuffButton') + + -- T.SetFrameLayout(buff, db.raidbuff) + end + + db.raidevent = {} + + + + +end + +function mod:PLAYER_SPECIALIZATION_CHANGED(e, unit) + local specID + --print(e, unit) + if unit == 'player' then + specID = GetSpecializationInfo(GetSpecialization()) + else + --NotifyInspect(unit) + specID = GetInspectSpecialization() + end + if specID then + --print(GetSpecializationInfoByID(specID)) + end +end + +function mod:PARTY_MEMBERS_CHANGED(e, ...) + if IsInRaid() or IsInGroup() then + self.raidbuffs_frame:Show() + self:RaidBuffScan() + else + end +end + +function mod:ENCOUNTER_START(e,...) + --print(e,...) +end + +-- Updates available raid/party buffs +function mod:RaidbuffsUpdate(unit) + if not (IsInGroup() or IsInRaid()) then + self.raidbuffs_tray:Hide() + return + end + + local c = db.raidbuff + local k = 0 + for i = 1, NUM_LE_RAID_BUFF_TYPES do + + local rb = self.raidbuffs[i] + local buff = {GetRaidBuffTrayAuraInfo(i) } + --name, rank, texture, duration, expiration, spellId, slot + local isShown = false + if buff[1] then + isShown = true + self.raidbuffs[i] = buff + else + self.raidbuffs[i] = nil + end + + if isShown then + rb:Show() + rb.bufftype:SetText(sub(_G['RAID_BUFF_'..i],0,2)) + rb.spellname:SetText(self.buffinfo[i]) + + local pn = k -- need (n-1) for lua grid math + local py = floor(pn / self.num_raidbuff_columns) * c.height + local px = (pn * c.width) % db.width -- x-offset + --print('buff slot '..i..' (draw position '..k..')', pn, py, px) + rb:SetPoint(c.anchor, self.raidbuffs_tray, c.anchor, px, py) + + k = k + 1 + end + end + if k == 0 and self.raidbuffs_tray:IsVisible() then + self.raidbuffs_tray:Hide() + elseif not self.raidbuffs_tray:IsVisible() then + self.raidbuffs_tray:Show() + end +end + +function mod:RosterScan() + local lim = 1 + if IsInRaid() then + lim = 40 + elseif IsInGroup() then + lim = 5 + end +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Utilities/Raid.xml Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,68 @@ +<Ui> + + <Frame name="TurokRaidbuffsTray" alpha="0"> + <Size x="200" y="600" /> + <Anchors> + <Anchor point="RIGHT" x="45" y="-300" /> + </Anchors> + <Layers> + <Layer level="BACKGROUND"> + <Texture name="$parentBackground" parentKey="background" setAllPoints="true"> + <Color r="1" g="1" b="1" a="1" /> + <Gradient> + <ColorMin r="1" g="0" b="0.8" /> + <ColoMax r="0.5" g="0" b="1" /> + </Gradient> + </Texture> + </Layer> + </Layers> + <Frames> + <Button name="$parentAction" parentArray="_buttons" parentKey="action" inherits="TurokButton"> + <Script> + <OnShow> + if Turok.playerClass == 'HUNTER' then + if Turok.specPage == 1 then + self:SetText() + else + self:SetText("Lone Wolf") + end + end + + </OnShow> + </Script> + </Button> + </Frames> + </Frame> + + <Frame name="TurokRaidbuffButton" virtual="true" hidden="true"> + <Anchors> + <Anchor point="CENTER" /> + </Anchors> + <Size x="64" y="64" /> + <Layers> + <Layer level="BACKGROUND"> + <Texture name="$parentBackground" parentKey="background" setAllPoints="true"> + <Color r="0" g="0" b="0" a="1" /> + </Texture> + </Layer> + <Layer level="ARTWORK"> + <Texture name="$parentForeground" parentKey="foreground"> + <Color r="0" g="1" b="1" a="1" /> + <Anchors> + <Anchor point="TOPLEFT" x="1" y="-1" /> + <Anchor point="BOTTOMRIGHT" x="-1" y="1" /> + </Anchors> + </Texture> + <Texture file="" name="BuffIcon" parentKey="icon"> + <Anchor point="TOPLEFT" x="2" y="-2" /> + <Anchor point="BOTTOMRIGHT" x="-2" y="2" /> + </Texture> + </Layer> + <Layer level="OVERLAY"> + <FontString name="$parentSpellName" parentKey="spellname" inherits="TurokFontDetail" /> + <FontString name="$parentBuffType" parentKey="bufftype" inherits="TurokFontDetail" /> + <FontString name="$parentCaster" parentKey="caster" inherits="TurokFontDetail" /> + </Layer> + </Layers> + </Frame> +</Ui> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Utilities/Toast.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,372 @@ +--- ${PACKAGE_NAME} +-- @file-author@ +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +-- Created: 2/2/2016 12:09 AM + +local mod = Turok:NewModule("Toast", "AceTimer-3.0") +local _G = _G +local db +local T, tostring, type, max, tinsert, UIParent, loadstring = _G.Turok, tostring, type, max, table.insert, _G.UIParent, loadstring +--@debug@ +local DEBUG = true +--@end-debug@ +local cType, cText, cNum, cWord, cKey, cPink, cBool = cType, cText, cNum, cWord, cKey, cPink, cBool +local print = function(...) + if not DEBUG then return end + if _G.Devian and _G.DevianDB.workspace ~= 1 then + _G.print('Toast', ...) + end +end + +-- GLOBALS:BossBanner_OnEvent, BossBanner +-- kill off the default BossBanner +local old_bb = BossBanner_OnEvent +BossBanner_OnEvent = function(self, event, ...) + T:Print(event, ...) +end + +T.defaults.toast = { + alert_hold = 2, + alert_fade = 1, + alert_flash = .6, + anchor = 'TOP', + parent = 'UIParent', + anchorTo = 'TOP', + x = 0, y= -56, + loot = { + background_color = {}, + } +} + +mod.events = { + "ACHIEVEMENT_EARNED", + "CRITERIA_EARNED", + "LFG_COMPLETION_REWARD", + "GUILD_CHALLENGE_COMPLETED", + "CHALLENGE_MODE_COMPLETED", + "LOOT_ITEM_ROLL_WON", + "SHOW_LOOT_TOAST", + "SHOW_LOOT_TOAST_UPGRADE", + "SHOW_PVP_FACTION_LOOT_TOAST", + "PET_BATTLE_CLOSE", + "STORE_PRODUCT_DELIVERED", + "GARRISON_BUILDING_ACTIVATABLE", + "GARRISON_MISSION_FINISHED", + "GARRISON_FOLLOWER_ADDED", + "GARRISON_RANDOM_MISSION_ADDED", + "BOSS_KILL", + "ENCOUNTER_LOOT_RECEIVED", +} + +mod.events_args = { + ['ACHIEVEMENT_EARNED'] = {12, false}, + ['ACHIEVEMENT_EARNED'] = {12, true}, + ['LFG_COMPLETED_REWARD'] = {}, +} +local y_factor = -1 +local x_factor = 0 +local tkAlerts = TkAlertContainer +local AlertFrame_FixPosition = function(alertFrame) + print(' pos:', alertFrame.order, cKey(alertFrame.x), cWord(alertFrame.y)) + alertFrame:SetPoint('TOPLEFT', tkAlerts, 'TOPLEFT', alertFrame.x, alertFrame.y) +end + +--- Goes through the alert container index and fixes the frame positions +-- used before and after an alert frame changes visibility +local AlertContainer_Update = function(self) + local anum = 1 + local offset = 0 + for i, alert in ipairs(tkAlerts.alerts) do + if alert:IsShown() then + alert.x = offset * x_factor + alert.y = offset * y_factor + alert.drawHeight = alert.ename:GetStringHeight()+ alert.desc:GetStringHeight() + alert.order = anum + anum = anum + 1 + offset = offset + alert.drawHeight + print(' draw height:', i, cText(alert.drawHeight)) + print(' position:', i, cPink(offset)) + AlertFrame_FixPosition(alert) + print('index', i, 'shifted from position', cNum(alert.order), 'to', cNum(anum), ' at draw point', alert.y) + print(' draw distance update ', cNum(0), 'x', cNum(offset)) + else + print('index', i, 'is not visible') + end + end + self:SetHeight(offset) +end + +--- config mode blocking command +local AlertFrame_Block = function(alertFrame) + -- only do stuff when configMode is on + if not mod.configMode then + return + end +end + +--- if not config mode, then fire at the end of fadeIn animation to queue fadeOut +local AlertFrame_Pin = function(alertFrame) + if not mod.configMode then + alertFrame.fadeOut.a1:SetStartDelay(db.alert_hold) + alertFrame.fadeOut:Play() + end +end + +--- if not config mode, then fire at the end of fadeOut to remove the frame from view and trigger positions update +local AlertFrame_Remove = function(alertFrame) + mod.num_events = mod.num_events - 1 + alertFrame:Hide() + print(mod.num_events) + AlertContainer_Update(tkAlerts) +end + +--- orders all visible frames to fadeOut +-- @param stagger forces the spacing of startDelay times for each frame +local AlertContainer_Clear = function(self, stagger) + stagger = stagger or 0.1 + for i = #self.alerts, 1, -1 do + print('clear check', i) + local alert = self.alerts[i] + if alert:IsShown() and not alert.fadeOut:IsPlaying() then + alert.fadeOut.a1:SetStartDelay((#self.alerts-i)* stagger) + alert.fadeOut:Play() + end + end +end +local AlertContainer_Unlock = function() +end + +--- Displays a new alert +-- @param name text naming the class of event that occurred +-- @param text alert subtext describing basic info about the event +-- @order order (optional) sets display slot of the alert +local function AlertContainer_ShowAlert(self, name, text, order) + local db = TurokData.toast + mod.num_events = mod.num_events + 1 + + local alertFrame + if not order then + local i = 1 + while i <= #self.alerts and not alertFrame do + if not self.alerts[i]:IsShown() then + alertFrame = self.alerts[i] + print('re-using alert frame #', i) + end + i = i +1 + end + else + alertFrame = self.alerts[order] + end + + if not alertFrame then + alertFrame = CreateFrame('Frame', 'TkAlertPanel'..(order or #self.alerts+1), self, 'TkAlertFrame') + self.alerts[#self.alerts+1] = alertFrame + print('creating new alert frame', #self.alerts) + + alertFrame.Pin = AlertFrame_Pin + alertFrame.Remove = AlertFrame_Remove + end + + alertFrame.ename:SetText(name) + local height1 = alertFrame.ename:GetStringHeight() + alertFrame.desc:SetText(text) + local height2 = height1+ alertFrame.desc:GetStringHeight() + alertFrame.desc:SetPoint('TOPLEFT', alertFrame, 'TOPLEFT', 0, -height1) + + alertFrame.order = order or mod.num_events + alertFrame:SetSize(300, height2) + alertFrame:Show() + --alertFrame.flashIn.a1:SetDuration(db.alert_flash/2) + --alertFrame.flashIn.a2:SetDuration(db.alert_flash/2) + alertFrame.flashIn:Play() + if not mod.configMode then + AlertContainer_Update(tkAlerts) + end +end + + +--- updates the completed missions index and returns info on the mission ID if passed +local completedMissions +local Garrison_UpdateCompleteMissions = function(missionID) + completedMissions = C_Garrison.GetCompleteMissions() + --- slide entries around for reference + for i, set in ipairs(completedMissions) do + if i ~= set.missionID then + completedMissions[set.missionID] = set + completedMissions[i] = nil + end + end + + if missionID and completedMissions[missionID] then + local m = completedMissions[missionID] + return m.name, m.location, m.locPrefix, m.isRare, m.followers, m.rewards, m.state + else + return false + end +end +--- container events handler +local AlertContainer_OnEvent = function (self, event, ...) + print(event, ...) + tkAlerts:Show() + if event == 'SHOW_LOOT_TOAST' then + local typeIdentifier, itemLink, quantity, specID, sex, isPersonal, lootSource = ...; + if typeIdentifier == "currency" then + AlertContainer_ShowAlert(self, itemLink, 'x'..quantity) + elseif typeIdentifier == "item" then + local _, _, _, ilvl, _, _, _, _, equipSlot = GetItemInfo(itemLink) + AlertContainer_ShowAlert(self, itemLink, tostring(ilvl)..' '..tostring(_G[equipSlot])) + end + elseif event == 'GARRISON_MISSION_FINISHED' then + local missionID = ... + local name, location, locPrefix, isRare, followers, rewards = Garrison_UpdateCompleteMissions(missionID) + local mission_info = { + (isRare and ('|cFF44BBFF') or ('|cFFFFFF00')..name.. '|r'), + } + + if followers then + for i, guid in ipairs(followers) do + print(C_Garrison.GetFollowerInfo(guid)) + end + end + + --'|T:'..icon..':0 + + + AlertContainer_ShowAlert(self, 'Mission Complete') + elseif event == 'GARRISON_BUILDING_ACTIVATABLE' then + local missionID = ... + elseif event == 'ACHIEVEMENT_EARNED' then + elseif event == 'LFG_COMPLETION_REWARD' then + local name, typeID, subtypeID, textureFilename, moneyBase, moneyVar, experienceBase, experienceVar, numStrangers, numRewards = GetLFGCompletionReward() + local _, _, _, _, hasBonusStep, isBonusStepComplete = C_Scenario.GetInfo(); + + end +end + +local AlertContainer_Test = function() + if not mod.configMode then + print('starting test mode') + tkAlerts:Show() + mod.configMode = true + + tkAlerts.configBG:Show() + tkAlerts.configBG:SetTexture(0,0.5,0,0.5) + tkAlerts:RegisterForDrag('LeftButton') + tkAlerts:EnableMouse(true) + + for i, frame in ipairs(tkAlerts.tools) do + frame:Show() + end + -- test fillers + local _,_, offset, range = GetSpellTabInfo(2) + print(offset, range) + + for i, event in ipairs(mod.events) do + --print(i, event) + local _, id = GetSpellBookItemInfo(math.random(offset, offset+range), 'spell') + print(id) + + local name = GetSpellLink(id) + local text = GetSpellDescription(id) + if not tkAlerts.alerts[i] then + print('creating alert frame #', i) + AlertContainer_ShowAlert(tkAlerts, name, text, i) + else + print('updating alert frame #', i) + local alert = tkAlerts.alerts[i] + alert:Show() + alert.order = i + alert.ename:SetText(name) + alert.desc:SetText(text) + if alert.fadeOut:IsPlaying() then + alert.fadeOut:Stop() + alert.backdrop:SetAlpha(0.5) + end + + alert.flashIn:Play() + end + end + AlertContainer_Update(tkAlerts) + else + tkAlerts:EnableMouse(false) + tkAlerts.configBG:Hide() + mod.configMode = nil + for i, frame in ipairs(tkAlerts.tools) do + frame:Hide() + end + for i, alert in ipairs(tkAlerts.alerts) do + for j, frame in ipairs(alert.tools) do + frame:Hide() + end + alert.fadeOut.a1:SetStartDelay(i*0.2) + alert.fadeOut:Play() + end + + end +end + +mod.OnEnable = function() + db = TurokData.toast + + --- find the closest frame to the center bottom and anchor to that + + local cX, cY = (GetScreenWidth() / 2), (GetScreenHeight() / 2) + local min_skewness = cX + local max_centrality, center_frame + for n, f in ipairs({UIParent:GetChildren()}) do + if type(f) == 'table' and f.GetObjectType and f.GetName then + if f.IsForbidden and f:IsForbidden() then + print(n, 'is a forbidden object') + else + local name = f:GetName() + + if f:IsVisible() and f:IsMouseEnabled() then + print(name and name or tostring(f):sub(8), 'is a frame!') + local x = f:GetCenter() + local y = f:GetTop() -- Y need center top position + if (x and y) and (y <= cY) then + x = math.abs(x - cX) -- X works in either direction + + -- distance of current - distant of record / max to get ratio of 1 where direct center results in 1 + local skewness_factor = (cX - x) / cX + local vertness_factor = y / cY + local centrality = skewness_factor * vertness_factor + print('result: (', floor(x), floor(y), ') = ', skewness_factor, 'skew,', vertness_factor, 'vertness.\nTotal score:', cNum(centrality)) + if (not max_centrality) or max_centrality < centrality then + center_frame = f + max_centrality = centrality + print(cWord(name and name or tostring(f):sub(8)),cPink(' is the new record!')) + end + + end + end + end + end + end + + mod.num_events = 0 + tkAlerts.alerts = {} + for i, event in ipairs(mod.events) do + tkAlerts:RegisterEvent(event) + end + + tkAlerts.Clear = AlertContainer_Clear + tkAlerts.Unlock = AlertContainer_Unlock + tkAlerts.Close = AlertContainer_Test + + tkAlerts:ClearAllPoints() + tkAlerts:SetPoint(db.anchor, db.parent, db.anchorTo, db.x, db.y) + tkAlerts.x = db.x + tkAlerts.y = db.y + tkAlerts.parent = db.parent + tkAlerts.anchor = db.anchor + tkAlerts.anchorTo = db.anchorTo + tkAlerts:EnableMouse(false) + + tkAlerts:SetScript('OnEvent', AlertContainer_OnEvent) + T:RegisterChatCommand("alert", AlertContainer_Test) + T:RegisterChatCommand("atest", function() + AlertContainer_OnEvent(tkAlerts, 'GARRISON_MISSION_FINISHED', 327) + end) +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Modules/Utilities/Utilities.xml Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,252 @@ +<Ui> + <Frame name="TkAlertContainer" parent="UIParent" movable="true"> + <Scripts> + <OnDragStart> + self.cx = self:GetLeft() + self.cy = self:GetTop() + self:StartMoving() + </OnDragStart> + <OnDragStop> + self:StopMovingOrSizing() + self.x = self.x + self:GetLeft() - self.cx + self.y = self.y + self:GetTop() - self.cy + self:ClearAllPoints() + self:SetPoint(self.anchor, self.parent, self.anchorTo, self.x, self.y) + </OnDragStop> + </Scripts> + <Anchors> + <Anchor point="LEFT" x="20" y="0" /> + </Anchors> + <Size x="300" y="100" /> + <Layers> + <Layer level="BACKGROUND"> + <Texture setAllPoints="true" parentKey="configBG" hidden="true"> + <Color r="1" b="1" g="1" a="0.5" /> + </Texture> + <Texture setAllPoints="true" parentKey="flashBG" alpha="0"> + </Texture> + </Layer> + </Layers> + <Animations> + <AnimationGroup parentKey="flashIn" setToFinalAlpha="true"> + <Alpha change="1" childKey="flashBG" parentKey="a1" duration=".3" order="1" /> + <Alpha change="-1" childKey="flashBG" parentKey="a2" duration=".6" order="2" /> + <Scripts> + <OnPlay> + self:GetParent().flashBG:Show() + </OnPlay> + <OnFinished> + self:GetParent().flashBG:Hide() + </OnFinished> + </Scripts> + </AnimationGroup> + </Animations> + <Frames> + <Button parentKey="clear" name="$parentButton_C" inherits="TurokButton" hidden="true"> + <Size x="24" y="24" /> + <Anchors> + <Anchor point="TOPRIGHT" relativePoint="TOPLEFT" x="-4" y="0" /> + </Anchors> + <Scripts> + <OnClick> + self:GetParent():Clear(self:GetParent()) + </OnClick> + </Scripts> + </Button> + <Button parentArray="tools" parentKey="close" name="$parentButton_Close" inherits="TurokButton" hidden="true"> + <Size x="64" y="24" /> + <Anchors> + <Anchor point="TOPLEFT" relativePoint="BOTTOMLEFT" x="0" y="-4" /> + </Anchors> + <Scripts> + <OnClick> + self:GetParent():Close() + </OnClick> + </Scripts> + </Button> + <Button parentArray="tools" name="$parentButton_Unlock" inherits="TurokButton" hidden="true"> + <Size> + <AbsDimension y="24" /> + </Size> + <Scripts> + <OnClick> + self:GetParent():Unlock() + </OnClick> + </Scripts> + <Anchors> + <Anchor point="TOPLEFT" relativePoint="TOPRIGHT" relativeKey="$parent.close" x="2" y="0" /> + <Anchor point="TOPRIGHT" relativePoint="BOTTOMRIGHT" x="0" y="-2" /> + </Anchors> + </Button> + </Frames> + </Frame> + + <Frame name="TkAlertFrame" hidden="true" virtual="true"> + + <Animations> + <AnimationGroup name="flashIn" parentKey="flashIn" looping="NONE" ignoreFramerateThrottle="true" setToFinalAlpha="true"> + <Alpha name="a1" parentKey="a1" childKey="flash" duration=".1" fromAlpha="0" toAlpha="1" order="1" /> + <Alpha name="a2" parentKey="a2" childKey="flash" duration=".5" fromAlpha="1" toAlpha="0" order="2" /> + <Alpha name="a3" parentKey="a3" childKey="backdrop" duration=".1" fromAlpha="0" toAlpha="1" order="1" /> + <Scripts> + <OnPlay> + print(self:GetParent():GetParent():GetName()) + print(self:GetParent():GetParent().num_events) + </OnPlay> + <OnFinished> + self:GetParent():Pin() + </OnFinished> + </Scripts> + </AnimationGroup> + <AnimationGroup name="fadeOut" parentKey="fadeOut" looping="NONE" ignoreFramerateThrottle="true"> + <Alpha startDelay="5" name="a1" parentKey="a1" duration="1.5" change="-1" order="1" /> + <Scripts> + <OnFinished> + + self:GetParent():Remove() + </OnFinished> + </Scripts> + </AnimationGroup> + <AnimationGroup name="sweepOver" parentKey="sweepOver" looping="NONE" ignoreFrameRateThrottle="true"> + <Alpha + name="a1" parentKey="a1" childKey="flare" change="1" duration="0.15" order="1" /> + <Translation + name="t1" parentKey="t1" childKey="flare" offsetX="200" offsetY="0" startDelay="0.2" duration=".4" order="1" /> + <Rotation + name="r1" parentKey="r1" childKey="flare" degrees="180" duration="0.55" order="1" /> + <Alpha + name="a2" parentKey="a2" childKey="flare" change="-1" duration="0.15" order="2" startDelay=".8" /> + <Scripts> + <OnPlay> + self:GetParent():GetParent().flare:Show() + </OnPlay> + <OnFinished> + self:GetParent():GetParent().flare:Hide() + </OnFinished> + </Scripts> + </AnimationGroup> + </Animations> + <Layers> + <Layer level="BACKGROUND"> + <Texture setAllPoints="true" parentKey="backdrop" alpha="1" alphaMode="BLEND"> + <Color r="0" g="0" b="0" a="0.5" /> + </Texture> + <Texture setAllPoints="true" parentKey="flash" alpha="0" alphaMode="ADD"> + <Color r="1" b="1" g="1" a="1" /> + <Gradient orientation="HORIZONTAL"> + <MinColor r="1" g="1" b="1" a="1" /> + <MaxColor r="1" g="1" b="1" a="0" /> + </Gradient> + </Texture> + <Texture parentKey="flare" file="Interface\Cooldown\star4" alphaMode="ADD"> + <Color r="0.3" g="0.6" b="1" a="0.8"/> + <Size x="24" y="24" /> + <Anchors> + <Anchor point="LEFT" /> + </Anchors> + </Texture> + </Layer> + <Layer level="OVERLAY"> + <FontString inherits="TurokFont" parentKey="ename" justifyH="LEFT"> + <Anchors> + <Anchor point="TOPLEFT" /> + </Anchors> + </FontString> + <FontString inherits="TurokFontDetail" parentKey="desc" justifyH="LEFT"> + <Anchors> + <Anchor point="TOPLEFT" relativePoint="BOTTOMLEFT" relativeKey="ename" /> + </Anchors> + </FontString> + </Layer> + </Layers> + <Frames> + + <Button parentArray="tools" name="$parentButton_Block" inherits="UIPanelSquareButton" hidden="true" > + <Scripts> + <OnClick> + self:GetParent():Block(self) + </OnClick> + </Scripts> + <Size x="30" y="30" /> + <Anchors> + <Anchor point="TOPRIGHT" x="36" y="3" /> + </Anchors> + </Button> + </Frames> + </Frame> + + <Frame virtual="true" hidden="true" name="TkPetSwatchTemplate" enableMouse="true"> + <Layers> + <Layer level="OVERLAY"> + <FontString inherits="TurokFont" name="PetName" parentKey="name" /> + </Layer> + </Layers> + </Frame> + + <Frame virtual="true" hidden="true" name="TkPetSpellTemplate" enableMouse="true"> + <Scripts> + <OnEnter> + print(self:GetName(), self.spellID, 'enter') + GameTooltip:SetOwner(self, 'ANCHOR_TOP') + --GameTooltip:SetPetAction(self.spellID) + GameTooltip:Show() + </OnEnter> + <OnLeave> + print(self:GetName(), 'leave') + GameTooltip:Hide() + </OnLeave> + </Scripts> + <Size x="64" y="64" /> + <Layers> + <Layer level="ARTWORK"> + <Texture name="Icon" parentKey="icon" setAllPoints="true"> + <Anchors> + <Anchor point="CENTER" /> + </Anchors> + </Texture> + </Layer> + <Layer level="OVERLAY"> + <Texture name="StrongWeak" parentKey="strongWeakHint"> + <Size x="32" y="32" /> + <Anchor> + <Anchor point="CENTER" /> + </Anchor> + </Texture> + <FontString inherits="TurokFont" name="TurnsLeft" parentKey="turnsLeft" setAllPoints="true" /> + </Layer> + <Layer level="HIGHLIGHT"> + <FontString inherits="TurokFontDetail" name="Description" parentKey="spellDesc" setAllPoints="true" /> + <FontString inherits="TurokFontDetail" name="Damage" parentKey="damageModifier" setAllPoints="true" /> + <Texture alphaMode="ADD" setAllPoints="true"> + <Color a="1" r="1" g="1" b="0" /> + </Texture> + </Layer> + </Layers> + <Animations> + <AnimationGroup name="popIn" parentKey="popIn" ignoreFrameRateThrottle="true" looping="NONE" setToFinalAlpha="true"> + <Scripts> + <OnPlay> + self:GetParent():Show() + self:GetParent():SetAlpha(0) + </OnPlay> + </Scripts> + <Alpha childKey="spellIcon" duration="0.4" change="1" order="1" /> + <Scale childKey="spellIcon" duration="0.4" fromScaleX="0.1" fromScaleY="0.1" toScaleX="1" toScaleY="1" order="1" /> + </AnimationGroup> + <AnimationGroup name="popOut" parentKey="popOut" ignoreFramerateThrottle="true" looping="NONE" setToFinalAlpha="true"> + <Scripts> + <OnFinished> + self:GetParent():Hide() + </OnFinished> + </Scripts> + <Alpha childKey="spellIcon" duration="0.4" change="-1" order="1" /> + <Scale childKey="spellIcon" duration="0.4" fromScaleX="1" toScaleX=".1" fromScaleY="1" toScaleY=".1" order="1" /> + </AnimationGroup> + </Animations> + </Frame> + + <Include file="Raid.xml" /> + <Script file="Toast.lua" /> + <Script file="Raid.lua" /> + <Script file="PetBattle.lua" /> +</Ui> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Turok.iml Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="LUA_MODULE" version="4"> + <component name="NewModuleRootManager" inherit-compiler-output="true"> + <exclude-output /> + <content url="file://$MODULE_DIR$"> + <sourceFolder url="file://$MODULE_DIR$" isTestSource="false" /> + </content> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + </component> +</module> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Turok.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,554 @@ +--- 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 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.isEventUnit[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.isEventUnit[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.isEventUnit[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.isEventUnit[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 + _G.print('Update', 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 + _G.print('Update', 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 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Turok.toc Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,13 @@ +## Interface: 60200 +## Title: Turok - Dinosaur HUD +## Notes: General UI supplement for the raiding hunter. +## Author: Krakyn +## Version: 1.0-@project-revision@ +## SavedVariables: TurokData +## OptionalDeps: Ace3, LibGroupInSpeCT-1.1, LibSharedMedia-3.0 +## X-Category: Interface Enhancements, Hunter, Combat +## X-Website: http://www.curse.com/addons/wow/turok +## DefaultState: Enabled +## LoadOnDemand: 0 + +Turok.xml \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Turok.xml Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,26 @@ +<Ui> + <!--@no-lib-strip@--> + <Script file="!Libs\LibStub\LibStub.lua" /> + <Include file="!Libs\AceConsole-3.0\AceConsole-3.0.xml" /> + <Include file="!Libs\AceAddon-3.0\AceAddon-3.0.xml" /> + <Include file="!Libs\AceConfig-3.0\AceConfig-3.0.xml" /> + <Include file="!Libs\AceEvent-3.0\AceEvent-3.0.xml" /> + <Include file="!Libs\AceTimer-3.0\AceTimer-3.0.xml" /> + <Include file="!Libs\CallbackHandler-1.0\CallbackHandler-1.0.xml" /> + <Include file="!Libs\LibSharedMedia-3.0\lib.xml" /> + <Script file="!Libs\LibGroupInSpecT-1.1\LibGroupInSpecT-1.1.lua" /> + <!--@end-no-lib-strip--> + + + <Script file="Init.lua" /> + <Include file="Layout\Layout.xml" /> + <Include file="Layout\Dialog.xml" /> + <Script file="Prototypes.lua" /> + <Script file="Media.lua" /> + + <Include file="Modules\Combat\Combat.xml" /> + <Include file="Modules\Timer\Timer.xml" /> + <Include file="Modules\Utilities\Utilities.xml" /> + <Script file="Turok.lua" /> +</Ui> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/Turok_Config.lua Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,323 @@ +-- User: Krakyn +-- Created: 12/19/2015 12:18 AM + +local _G = _G +local T = LibStub("AceAddon-3.0"):GetAddon("Turok") +local TL = 'Options' +local mod = T:NewModule(TL) +local LSM = LibStub("LibSharedMedia-3.0") +local ConfigDialog = LibStub("AceConfigDialog-3.0") +--@debug +local print = function(...) _G.print(TL, ...) end +local db + +local TITLE_FONT_COLOR = '|cFF88FF44' +local INPUT_FONT_COLOR = '|cFFFFFF00' +local STACK_COLOR1 = '|cFFFF8800' +local STACK_COLOR2 = '|cFFFFFF00' +local FONTVAR_COLOR = '|cFFFFAA44' +local FRAMEVAR_COLOR = '|cFFFFFF44' +local PARAMETER_COLOR = '|cFF9999FF' +local STATE_COLOR = '|cFFFF99FF' + +function mod:OnInitialize() + T:Print("config mod init") +end + +function mod:OnEnable() + T:Print("config mod enable") + db = T.db + LibStub("AceConfig-3.0"):RegisterOptionsTable('Turok', T.MakeOptions(), {"turok"}) + T.configDialog = ConfigDialog:AddToBlizOptions("Turok") +end + +local optL = { + background_color = 'Background color', + foreground_color = 'Foreground color', + width = FRAMEVAR_COLOR..'Width', + height = FRAMEVAR_COLOR..'Height', + alpha = FRAMEVAR_COLOR..'Alpha', + alpha_ooc = STATE_COLOR..'Alpha (OOC)', + label_strata = FONTVAR_COLOR..'Text Strata', + label_font = FONTVAR_COLOR..'Font', + label_size = FONTVAR_COLOR..'Font Size', + label_inset = FONTVAR_COLOR..'Text Insets', + foreground_blend = 'Foreground Blend Mode', + background_blend = 'Background Blend Mode', + isStatic = PARAMETER_COLOR..'Static Bar', + duration = PARAMETER_COLOR..'Duration', + isIcon = PARAMETER_COLOR..'Icon Only', +} + +local anchors = { + ['CENTER'] = 'Center', + ['TOPLEFT'] = 'Top Left', + ['TOP'] = 'Top', + ['TOPRIGHT'] = 'Top Right', + ['RIGHT'] = 'Right', + ['BOTTOMRIGHT'] = 'Bottom Right', + ['BOTTOM'] = 'Bottom', + ['BOTTOMLEFT'] = 'Bottom Left', + ['LEFT'] = 'Left' +} + +local frames = { + ['UIParent'] = 'UIParent', + ['TkPowerBar'] = 'Power Bar', + ['TekplayerCastBar'] = 'Player Castbar', + ['TektargetCastBar'] = 'Target Castbar', + ['TekfocusCastBar'] = 'Focus Castbar', + ['TekpetCastBar'] = 'Pet Castbar' +} + +local range = { + ['alpha'] = {0, 1, .01}, + ['alpha_ooc'] = {0, 1, .01}, + ['label_size'] = {1, 72, 1}, + ['label_inset'] = {-30, 30, 1}, + ['width'] = {0, 1200, 1}, + ['height'] = {0, 1200, 1}, + ['raidbuff_width'] = {0, 1200, 1}, + ['raidbuff_height'] = {0, 1200, 1}, + ['duration'] = {0, 6000, 0.1 }, + ['glow_size'] = {0, 30, 1}, + ['spark_size'] = {0, 30, 1}, +} + +local opt_order = { + ['width'] = 10, + ['height'] = 15, + ['anchor'] = 20, + ['anchorTo'] = 25, + ['parent'] = 30, + + ['alpha'] = 110, + ['alpha_ooc'] = 115, + ['label_size'] = 200, + ['label_inset'] = 210, + ['label_font'] = 220, + + ['background_texture'] = 300, + ['background_color'] = 320, + ['foreground_texture'] = 350, + ['foreground_color'] = 370, +} +local opt_width = { + +} + +-- options dialog root +T.myopts = { + type = 'group', + name = TITLE_FONT_COLOR..'Turok|r', + desc = 'Dinosaur HUD', + handler = T, + set = function(info,value, ...) + local db = T.db + local index = db + local traversal = 'db' + for i = 1, #info-1 do + if type(index[info[i]]) == 'table' then + --print('|cFFFF0000SET|r:', i, info[i]) + traversal = traversal .. '.' .. info[i] + index = index[info[i]] + end + + end + --print('|cFFFF0000SET|r: hops=',#info,'index=', traversal, ' key=', info[#info]) + + if type(value) ~= 'boolean' and select('#',...) == 3 then + --print('|cFFFF0000SET|r', 'multi-args', select('#',...)) + value = {value, ... } + else + --print('|cFFFF0000SET|r', 'single-arg', value) + end + + index[info[#info]] = value + end, + get = function(info) + local db = T.db + local value = db[info[1]] + local traversal = info[1] + if #info > 1 then + for i=2, #info do + traversal = traversal .. '.' .. info[i] + if value[info[i]] ~= nil then + value = value[info[i]] + end + end + end + --print('|cFFFF00FFGET|r: hops=', #info, 'index=', traversal, 'value=', value) + + if type(value) == 'table' then + return unpack(value) + end + return value + end, +} + +function T:MakeOptions(dbtable, index, name, prefix) + -- index = option insertion destination + -- parent = nesting point + local parent + if not (index and dbtable) then + dbtable = db + name = 'root' + prefix = '' + parent = T.myopts + parent.args = { + main = { + order = 1, + type = 'group', + name = 'Global', + get = function(info) print('db.'..info[#info]..' get') + if type(db[info[#info]]) == 'table' then + print('getting color data', unpack(db[info[#info]])) + return unpack(db[info[#info]]) + end + return db[info[#info]] + end, + set = function(info, value, ...) print('db.'..info[#info]..' SET') + if select('#',...) == 3 then + print('receiving color data', value, ...) + value = {value, ...} + end + db[info[#info]] = value + end, + args = {}, + }} + index = parent.args.main + print(STACK_COLOR1..'using TurokData as index') + else + index.type = 'group' + index.name = name + index.args = {} + parent = index + end + + local order = 2 + for k, v in pairs(dbtable) do + k = tostring(k) + local kt = INPUT_FONT_COLOR .. (optL[k] or k) + local nested = false + --@debug@ + print(STACK_COLOR2..prefix..'.'..STACK_COLOR1..k..'|r =',v)--@debug@ + if type(v) == 'table' then + if table.getn(v) == 4 then + index.args[k] = { + name = kt, + type = 'color', + hasAlpha = true, + --@debug@ + print('color_pack=',unpack(v))--@debug@ + } + else + parent.args[k] = {} + nested = true + T:MakeOptions(v, parent.args[k], k, prefix .. '.' .. name) + end + elseif type(v) == 'string' then + if string.match(k, "_font") then + local font_list = {} + for k, v in pairs(LSM:HashTable('font')) do + font_list[v] = k + end + index.args[k] = { + name = kt, + type = 'select', + values = font_list + } + elseif k:match('anchor$') or k:match('_point$') or k:match('anchorTo') then + + index.args[k] = { + name = kt, + type = 'select', + values = anchors + } + + elseif k:match('justifyH$') then + index.args[k] = { + name = kt, + type = 'select', + values = { + ['LEFT'] = 'Left', + ['CENTER'] = 'Center', + ['RIGHT'] = 'Right' + } + } + + elseif k:match('strata$') then + index.args[k] = { + name = kt, + type = 'select', + values = { + BACKGROUND = 'BACKGROUND (clickthrough)', + LOW = 'LOW', + MEDIUM = 'MEDIUM', + HIGH = 'HIGH', + DIALOG = 'DIALOG', + FULLSCREEN = 'FULLSCREEN', + FULLSCREEN_DIALOG = 'FULLSCREEN_DIALOG', + TOOLTIP = 'TOOLTIP (clickthrough)', + } + } + + elseif k:match('outline$') then + index.args[k] = { + name = kt, + type = 'select', + values = { + ['NONE'] = 'NONE', + ['OUTLINE'] = 'OUTLINE', + ['THICKOUTLINE'] = 'THICKOUTLINE' + } + } + elseif k:match('parent') then + index.args[k] = { + name = kt, + type = 'select', + values = frames + } + else + + index.args[k] = { + name = kt, + type = 'input', + width = 'full', + } + end + elseif type(v) == 'number' then + + if not range[k] then + range[k] = {0,150,1 } + print('missing range values for', k) + end + + index.args[k] ={ + name = kt, + type = 'range', + min = range[k][1], + max = range[k][2], + softMax = range[k][2], + step = range[k][3], + bigStep = range[k][3], + } + elseif type(v) == 'boolean' then + + index.args[k] = { + name = kt, + type = 'toggle', + } + end + if nested then + parent.args[k].order = order + (opt_order[k] and opt_order[k] or 0) + elseif index.args[k] then + index.args[k].order = order + (opt_order[k] and opt_order[k] or 0) + print(' '..kt..' order = '..index.args[k].order) + else + print('|cFF99FFFFSkipped|r', kt) + end + end + + return parent +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok/readme.txt Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,42 @@ +Turok: Dinosaur HUD + +Hardcode of various WeakAura configurations. This is created as a personal learning challenge, so it may or may not be faster than the actual jumble of WeakAuras because that addon is written very well. + +Project Goals: + + - Focus bar with dynamic coloring and prediction lines based on talent effects + - Unit cast bars that are thematically linked with everything else + - Dynamically arranged tracking icons and sliders cooldown/aura information + - Quality-of-life alerts for Lone Wolf and Aspect of the Pack + +Coding Conventions: + + Although AceAddon modules are used, the addon is not truly modular. + The structure provides simple control over the internal loading sequence. + So if needed, "module" enables can be scattered over several post-load frames to make in-combat /reload less hazardous. + + SavedVars data is arranged in a non-propagating hierarchical metatable. + Accessing a deeply-nested member will traverse its parents until one of them contains data. + The only exception to this is on lazy read expressions, such as: + + > if (childtable.unsetvar) then + + This will always yield a false, whether or not a value is assigned in its parents. + To check for hierarchical flag variables, you can compare the index against nil, like so: + + > if (childtable.unsetvar ~= nil) then + + The operation will trigger __index and a value from the hierarchy will be presented. + Any positive flag state will be copied down when direct assignment is used. + To get a useful flag state, you need to run the first logical expression within a ternary idiom: + + > childflag = (childtable.unsetvar) and true or nil -- pulls the true flag value + > parentflag = childtable.unsetvar -- pulls any non-nil value + + Another thing to note is hierarchical values are not assigned downstream. + If an empty child value is indexed, it will always traverse up the tree. + As a result, values consulted frequently will be computationally taxing. + These should be copied into a local variable and read from that instead. + Then, when an event that might change the value is detected, the local variable is updated instead. + From a performance standpoint, the effects are net-positive, since assignments potentially cover dozens of keys. + The memory footprint also isn't much different, while the assignment operations are carried out in spaced intervals. \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Turok_Config/Turok_Config.toc Sun Feb 21 08:32:53 2016 -0500 @@ -0,0 +1,9 @@ +## Interface: 60200 +## Title: Turok Options +## Notes: Option Panel +## Author: Krakyn +## Version: 1.0 +## Dependencies: Turok +## LoadOnDemand: 1 + +..\Turok\Turok_Config.lua \ No newline at end of file
--- a/readme.txt Tue Dec 15 10:10:22 2015 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -Turok: Dinosaur HUD - -Hardcode of various WeakAura configurations. This is created as a personal learning challenge, so it may or may not be faster than the actual jumble of WeakAuras because that addon is written very well. - -Project Goals: - - - Focus bar with dynamic coloring and prediction lines based on talent effects - - Unit cast bars that are thematically linked with everything else - - Dynamically arranged tracking icons and sliders cooldown/aura information - - Quality-of-life alerts for Lone Wolf and Aspect of the Pack -