diff Turok/Modules/Timer/Cooldown.lua @ 6:a9b8b0866ece

clear out log jam
author Nenue
date Sun, 21 Feb 2016 08:32:53 -0500
parents
children 9400a0ff8540
line wrap: on
line diff
--- /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