changeset 1:766d8a40a1d6

first commit?
author Nenue
date Tue, 15 Dec 2015 08:07:21 -0500
parents ebbcc148a407
children 62f9b057c91b
files .pkgmeta Equip.lua Fog.lua Lost.lua Spirit.lua Tek.lua Turok.iml Turok.lua readme.txt
diffstat 9 files changed, 1440 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.pkgmeta	Tue Dec 15 08:07:21 2015 -0500
@@ -0,0 +1,18 @@
+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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Equip.lua	Tue Dec 15 08:07:21 2015 -0500
@@ -0,0 +1,94 @@
+-- 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Fog.lua	Tue Dec 15 08:07:21 2015 -0500
@@ -0,0 +1,326 @@
+-- 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 time = _G.ct
+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 = time
+
+  -- 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
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Lost.lua	Tue Dec 15 08:07:21 2015 -0500
@@ -0,0 +1,165 @@
+-- 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
+
+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
+
+  local db = _G.TurokData
+  db.raidbuff = {
+    parent = 'UIParent',
+    anchor = 'BOTTOMRIGHT', anchorTo = 'BOTTOMRIGHT',
+    posX = -300, posY = 300,
+    height = 50, width = 150,
+    icon_size = 25,
+    label_size = 11,
+    label_font = 'ArchivoNarrow-Bold',
+  }
+
+  local rw = CreateFrame('Frame', 'TkRaidWatch', UIParent)
+  local c =  db.raidbuff
+  self.raid_watcher = 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)
+
+  for i = 1, 9 do
+    local icon = rw:CreateTexture('TkRaidWatchButton'..i, 'ARTWORK')
+    icon:SetSize(c.icon_size,c.icon_size)
+    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, ...)
+end
+function mod:ENCOUNTER_START(e,...)
+end
+
+-- Updates available raid/party buffs
+function mod:RaidBuffScan(unit)
+
+  -- search for unit data
+
+  local changed = false
+  local c = T.db.raidbuff
+  -- update raidbuffs
+  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 axis_a, axis_b = c.icon_size, c.width
+          local w = axis_a * (k-1) % axis_b
+          local h = math.floor((k-1) / (axis_b / axis_a)) * axis_a
+          print(axis_a, axis_b, w, h)
+          rb:SetPoint('BOTTOMLEFT', TkRaidWatch, 'BOTTOMLEFT', w, h)
+        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)
+      if name then
+        if string.find(name,'-') then
+          name, realm = string.match(name, "(.+)-(.+)")
+        else
+          realm = GetRealmName()
+        end
+
+        print(i, name, class, role)
+      end
+
+  end
+
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Spirit.lua	Tue Dec 15 08:07:21 2015 -0500
@@ -0,0 +1,276 @@
+-- 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Tek.lua	Tue Dec 15 08:07:21 2015 -0500
@@ -0,0 +1,387 @@
+addon, T_ = ...
+-- User: Krakyn
+-- Created: 12/4/2015 11:17 PM
+local T = LibStub("AceAddon-3.0"):GetAddon("Turok")
+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' }
+
+local FADE_OUT_TIME, FADE_IN_TIME = 1000, 200             -- animation timings
+
+-- 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] = ''
+}
+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
+
+  db.castbar = {
+  --T.defaults.castbar = {
+    width = 300, height = 24,
+    anchor = 'TOP', parent = 'TkFocusBar', anchorTo = 'BOTTOM',
+    posX = 0, posY = -2,
+    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'] = {},
+    ['target'] = {
+      width = 300, height = 24,
+      anchor = 'BOTTOMLEFT', parent = 'TkplayerCastBar', anchorTo = 'TOPRIGHT',
+      posX = 4, posY = 4,
+    },
+    ['focus'] = {
+      width = 300, height = 24,
+      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
+    },
+  }
+
+  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')
+    local latency = T:AddLabel(pc, cdb, 'latency')
+    pc.foreground:SetWidth(0)
+
+    casttime:SetPoint('RIGHT', pc, 'RIGHT')
+    casttime:SetJustifyH('RIGHT')
+    latency:SetPoint('TOPRIGHT', pc.casttime, 'BOTTOMRIGHT')
+    latency:SetJustifyH('RIGHT')
+
+    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)
+
+
+
+    --print('created', fn)
+  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')
+
+  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())
+
+        -- 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)
+        latency:SetText(s.latency)
+        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.latency:SetText(nil)
+        self.debugged = false
+        self.percent = 0
+        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
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Turok.iml	Tue Dec 15 08:07:21 2015 -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.lua	Tue Dec 15 08:07:21 2015 -0500
@@ -0,0 +1,152 @@
+
+-- 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
+local time = GetTime()
+_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 = {}
+
+
+  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)
+      T.Bar_Update(fb, UnitPower("player"))
+  end)
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/readme.txt	Tue Dec 15 08:07:21 2015 -0500
@@ -0,0 +1,11 @@
+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
+