--[[ Name: LibDruidMana-1.0 Revision: $Rev: 29 $ Author: Cameron Kenneth Knight (ckknight@gmail.com) Inspired By: SmartyCat by Darravis Website: http://www.wowace.com/ Description: A library to provide data on mana for druids in bear or cat form. License: LGPL v2.1 ]] if(select(2, UnitClass("player")) ~= "DRUID") then return; end local MAJOR_VERSION = "LibDruidMana-1.0" local MINOR_VERSION = 90001 + tonumber(string.match("$Revision: 29 $", "%d+")) local unpack = unpack local ceil, floor, min = math.ceil, math.floor, math.min local find, format, match = string.find, string.format, string.match local getn = table.getn local GetNumSpellTabs = GetNumSpellTabs local GetSpellName = GetSpellName local GetSpellTabInfo = GetSpellTabInfo local GetSpellTexture = GetSpellTexture local GetTalentInfo = GetTalentInfo local GetTime = GetTime local UnitBuff = UnitBuff local UnitMana = UnitMana local UnitManaMax = UnitManaMax local UnitPowerType = UnitPowerType local UnitStat = UnitStat local lib, oldMinor = LibStub:NewLibrary(MAJOR_VERSION, MINOR_VERSION) if not lib then return end local oldLib if oldMinor then oldLib = {} for k, v in pairs(lib) do oldLib[k] = v lib[k] = nil end end local regenMana, maxMana, currMana, currInt, fiveSecondRule currMana, maxMana = 0, 0 local bearID, bearName, catName -- frame for events and OnUpdate local frame if oldLib and oldLib.frame then frame = oldLib.frame frame:UnregisterAllEvents() frame:SetScript("OnEvent", nil) frame:SetScript("OnUpdate", nil) for k in pairs(frame) do if k ~= 0 then frame[k] = nil end end else frame = CreateFrame("Frame", MAJOR_VERSION .. "_Frame") end lib.frame = frame -- tooltip for scanning the mana cost for shapeshifting. local tt if oldLib and oldLib.tt then tt = oldLib.tt else tt = CreateFrame("GameTooltip", MAJOR_VERSION .. "_Tooltip") end lib.tt = tt if not tt.left then tt.left = {} tt.right = {} end for i = getn(tt.left) + 1, 30 do local left, right = tt:CreateFontString(), tt:CreateFontString() tt.left[i] = left tt.right[i] = right left:SetFontObject(GameFontNormal) right:SetFontObject(GameFontNormal) tt:AddFontStrings(left, right) end tt:SetOwner(UIParent, "ANCHOR_NONE") -- set of functions to call when mana is updated local registry = oldLib and oldLib.registry or {} lib.registry = registry function GetManaRegen() local base = UnitStat("player", 5) local currMana = UnitMana("player") local maxMana = UnitManaMax("player") local regen = ceil(base / 5) + 15 local castingRegen = 0 local _, _, _, _, rank = GetTalentInfo(3, 6) if rank > 0 then castingRegen = ceil(regen * (0.05 * rank)) end local i, icon = 1 while true do icon = UnitBuff("player", i) if not icon then break end if icon and icon == "Interface\\Icons\\Spell_Nature_Lightning" then castingRegen = regen + castingRegen regen = regen * 5 break end i = i + 1 end return regen, castingRegen end local GetManaRegen = GetManaRegen local function getShapeshiftCost() if not bearID then return 0 end tt:ClearLines() tt:SetSpell(bearID, "spell") if not tt:IsOwned(UIParent) then tt:SetOwner(UIParent, "ANCHOR_NONE") end local line = tt.left[2]:GetText() if line then line = tonumber(match(line, "(%d+)")) end return line or 0 end local IsLoggedIn frame:SetScript("OnEvent", function() if event == "PLAYER_LOGIN" then IsLoggedIn = true end print(event, arg1) this[event](this, arg1) end) local SetMax_time = nil local UpdateMana_time = nil local killFSR_time = nil frame:SetScript("OnUpdate", function() local currentTime = GetTime() if SetMax_time and SetMax_time <= currentTime then SetMax_time = nil this:SetMax() end if UpdateMana_time and UpdateMana_time <= currentTime then UpdateMana_time = UpdateMana_time + 2 this:UpdateMana() end if killFSR_time and killFSR_time <= currentTime then killFSR_time = nil fiveSecondRule = false end end) function frame:PLAYER_LOGIN() self.PLAYER_LOGIN = nil self:LEARNED_SPELL_IN_TAB() self:RegisterEvent("UNIT_DISPLAYPOWER") if UnitPowerType("player") == 0 then self:UNIT_DISPLAYPOWER("player") end end function frame:UNIT_DISPLAYPOWER() if arg1 ~= "player" or UnitPowerType("player") ~= 0 then return end self:UnregisterEvent("UNIT_DISPLAYPOWER") self.UNIT_DISPLAYPOWER = nil maxMana = UnitManaMax("player") currMana = UnitMana("player") local _ _, currInt = UnitStat("player", 4) self:RegisterEvent("UNIT_MANA") self:RegisterEvent("UNIT_MAXMANA") self:RegisterEvent("UNIT_INVENTORY_CHANGED") self:RegisterEvent("PLAYER_AURAS_CHANGED") self:RegisterEvent("LEARNED_SPELL_IN_TAB") self:RegisterEvent("PLAYER_ENTERING_WORLD") self:RegisterEvent("PLAYER_LEAVING_WORLD") self:RegisterEvent("COMBAT_TEXT_UPDATE") self:Update() end function frame:PLAYER_ENTERING_WORLD() if UnitPowerType("player") ~= 0 then SetMax_time = GetTime() + 7 end end function frame:PLAYER_LEAVING_WORLD() SetMax_time = nil UpdateMana_time = nil killFSR_time = nil end function frame:UNIT_MANA() if arg1 ~= "player" then return end if UnitPowerType("player") == 0 then currMana = UnitMana("player") maxMana = UnitManaMax("player") self:Update() else if regenMana and not UpdateMana_time then -- Update mana every 2 seconds UpdateMana_time = GetTime() + 2 self:UpdateMana() end -- if mana hasn't been updated for 7 seconds, set current mana to the max mana SetMax_time = GetTime() + 7 end end function frame:UNIT_MAXMANA() if arg1 ~= "player" then return end local _, int = UnitStat("player", 4) if UnitPowerType("player") == 0 then maxMana = UnitManaMax("player") currMana = UnitMana("player") currInt = int elseif currInt ~= int then -- int buff maybe maxMana = maxMana + ((int - currInt) * 15) currInt = int if currMana > maxMana then currMana = maxMana end end self:Update() end frame.UNIT_INVENTORY_CHANGED = frame.UNIT_MAXMANA function frame:PLAYER_AURAS_CHANGED() -- possibly losing the bear/cat buff if UnitPowerType("player") == 0 then regenMana = false SetMax_time = nil UpdateMana_time = nil killFSR_time = nil currMana = UnitMana("player") maxMana = UnitManaMax("player") end self:Update() end function frame:COMBAT_TEXT_UPDATE() -- if the spell is cast for either bear or cat, deduct the cost. -- we can't rely on UNIT_DISPLAYPOWER since you could switch from bear -> bear, never calling that, so we check the spellcast. if (bearName and arg2 == bearName) or (catName and arg2 == catName) then regenMana = true fiveSecondRule = true killFSR_time = GetTime() + 5 currMana = currMana - getShapeshiftCost() end end function frame:LEARNED_SPELL_IN_TAB() for i = 1, GetNumSpellTabs() do local _, texture, offset, numSpells = GetSpellTabInfo(i) -- the spell tab that shows the bear is the feral tree, gonna check for bear form and cat form, gleam important info if strfind(texture, "Ability_Racial_BearForm") then for j = offset + 1, offset + numSpells do if strfind(GetSpellTexture(j, "spell"), "Ability_Racial_BearForm") then bearID = j bearName = GetSpellName(j, "spell") elseif strfind(GetSpellTexture(j, "spell"), "Ability_Druid_CatForm") then catName = GetSpellName(j, "spell") end end break end end end function frame:UpdateMana() local regen, castingRegen = GetManaRegen() print(regen, castingRegen) if fiveSecondRule then currMana = currMana + floor(castingRegen * 2 + 0.5) else currMana = currMana + floor(regen * 2 + 0.5) end if currMana >= maxMana then currMana = maxMana -- we're at max mana, no need for any more checking SetMax_time = nil UpdateMana_time = nil killFSR_time = nil end self:Update() end function frame:SetMax() currMana = maxMana -- we're at max mana, no need for any more checking SetMax_time = nil UpdateMana_time = nil killFSR_time = nil self:Update() end local i = 0 local lastMaxMana, lastCurrMana = 0, 0 function frame:Update() if lastMaxMana == maxMana and lastCurrMana == currMana then return end lastMaxMana = maxMana lastCurrMana = currMana -- trigger event for func in pairs(registry) do local success, ret = pcall(func, currMana, maxMana) if not success then geterrorhandler()(ret) end end end if IsLoggedIn then frame:PLAYER_LOGIN() else frame:RegisterEvent("PLAYER_LOGIN") end function lib:GetCurrentMana() return currMana end function lib:GetMaximumMana() return maxMana end function lib:AddListener(tab, method) local func if type(tab) == "table" then if type(method) ~= "string" then error(format("Bad argument #3 to `AddListener'. Expected %q, got %q.", "string", type(method)), 2) elseif type(tab[method]) ~= "function" then error(format("Bad argument #3 to `AddListener'. Expected method, got %q.", type(tab[method])), 2) end func = function(...) return tab[method](tab, unpack(arg)) end elseif type(tab) == "function" then func = tab if method and type(method) ~= "string" then method = true end else error(format("Bad argument #2 to `AddListener'. Expected %q or %q, got %q.", "table", "function", type(tab)), 2) end registry[func] = method end function lib:RemoveListener(method) if type(method) ~= "string" then error(format("Bad argument #2 to `RemoveListener'. Expected %q, got %q.", "string", type(method)), 2) end for func, methodName in pairs(registry) do if methodName == method then registry[func] = nil break end end end