Code: Select all
------------------------------- Variables and Constants ---------------------------------distance between adjacent aura frameslocal AURA_FRAME_DISTANCE = 4;--ID of the ability last picked by the playerlocal lastPlayerAbilityID; --teams[1] is the current player's roster, teams[2] is the opponent's roster.-- each roster is a list of pets; each pet has a list of (three) ability slots: each slot is a list of possible ability IDs;local teams;--temporary reusable tableslocal idTable = {}; local levelTable = {};--event handler tableslocal DeePetBattleFrame_EventHandlers = {}; local DeePetBattleAbilityButton_EventHandlers = {}; local DeePetBattlePet_EventHandlers = {}; local LE_BATTLE_PET_WEATHER = Enum.BattlePetOwner.Weather;local LE_BATTLE_PET_ALLY = Enum.BattlePetOwner.Ally;local LE_BATTLE_PET_ENEMY = Enum.BattlePetOwner.Enemy;------------------------------ Local function listing --------------------------------this makes order irrelevant, and recursion possiblelocal makeEventHandler, registerAllEvents;local getPetAbilities, populateTeams;local checkMatchingStats, getPlayerAbilityIndex, processPlayerAction;local updateAbilityButtonState, updateAbilityButtonAura, updateAbilityButtonBetterIcon, updateAbilityButtonIcons, updateAbilityButtonAbilityID;local updatePetIndex, updatePetAuras, handleAuraEvent, getPetAuras;local updateAbilityGroupPetIndex, updateAbilityGroupAuras;local getAuraFormattedDuration, setAuraFrameAura;----------------------------------------- OnEvent Handler Generic Functions -----------------------------------------do --creates and returns a generic event handler function that picks what to call from a given table of handlers makeEventHandler = function(handlerTable) return function(self, event, ...) local handler = handlerTable[event]; if (handler) then handler(self, ...); end end end --register all events a given frame is supposed to listen to, according to a table of handlers registerAllEvents = function( self, handlerTable ) for k, _ in pairs(handlerTable) do self:RegisterEvent(k); end end --onEvent handlers for the various frames DeePetBattleFrame_OnEvent = makeEventHandler(DeePetBattleFrame_EventHandlers); DeePetBattleAbilityButton_OnEvent = makeEventHandler(DeePetBattleAbilityButton_EventHandlers); DeePetBattlePet_OnEvent = makeEventHandler(DeePetBattlePet_EventHandlers);end--------------------------- Team Init Functions ---------------------------do --Returns a list with three elements (one per ability slot), each of which can be: -- {} if the pet's too low level to have an ability in that slot, -- {id} if we know what ability it has slotted there, -- {id, id} if we're not sure which of the two abilities is slotted (in PVP) getPetAbilities = function( playerIndex, petIndex, speciesID, level ) local abilities = {}; local foundInfo = false; --try to get slotted abilities directly for abilityIndex=1, 3 do id = C_PetBattles.GetAbilityInfo(playerIndex, petIndex, abilityIndex); if (id == nil) then abilities[abilityIndex] = {}; else abilities[abilityIndex] = {id}; foundInfo = true; end end --if we're in PVP, the previous attempt will fail, finding only {{}, {}, {}}: fill possible pet abilities from the pet journal instead if (not foundInfo) then C_PetJournal.GetPetAbilityList(speciesID, idTable, levelTable); for abilityIndex, abilityLevel in ipairs(levelTable) do if (abilityLevel <= level) then table.insert( abilities[((abilityIndex-1)%3)+1], --nasty modulus maths due to 1-based arrays. (basically, inserts into 1, 2, 3, 1, 2, 3) idTable[abilityIndex] ) end end end return abilities; end --populates teams with info on every pet in their roster, and their respective abilities populateTeams = function() teams = {}; for playerIndex=1, 2 do teams[playerIndex] = {}; local numPets = C_PetBattles.GetNumPets(playerIndex); for petIndex=1, numPets do local speciesID = C_PetBattles.GetPetSpeciesID(playerIndex, petIndex); local level = C_PetBattles.GetLevel(playerIndex, petIndex); teams[playerIndex][petIndex] = getPetAbilities( playerIndex, petIndex, speciesID, level ); end end endend------------------------------------- Ability Use Parsing Functions -------------------------------------do --returns whether the given stats match those of the given player's active pet checkMatchingStats = function(playerIndex, hp, pow, spd) return (hp == C_PetBattles.GetHealth(playerIndex, C_PetBattles.GetActivePet(playerIndex))) and (pow == C_PetBattles.GetPower(playerIndex, C_PetBattles.GetActivePet(playerIndex))) and (spd == C_PetBattles.GetSpeed(playerIndex, C_PetBattles.GetActivePet(playerIndex))); end --returns the slot index for a given ability, if it can be cast by the given player's pet (or nil, if it can't) getPlayerAbilityIndex = function( playerIndex, abilityID ) if (not teams) then populateTeams() end --ensure team roster is populated for slot, slotList in ipairs( teams[playerIndex][C_PetBattles.GetActivePet(playerIndex)] ) do for _, id in ipairs(slotList) do if (id == abilityID) then return slot end end end end --called whenever we detect a battle-pet has activated an ability processPlayerAction = function( playerIndex, abilityIndex, abilityID ) if (not teams) then populateTeams() end --ensure team roster is populated local petIndex = C_PetBattles.GetActivePet(playerIndex); --find the button responsible for this action local abilityGroup; if (playerIndex == LE_BATTLE_PET_ALLY) then abilityGroup = DeePetBattleFrame.Ally1.Abilities; else abilityGroup = DeePetBattleFrame.Enemy1.Abilities; end local button = abilityGroup["Button"..abilityIndex]; button.SelectedHighlight:Show(); --if we didn't know which of its two abilities the pet had in this slot, narrow down ability list for this slot if ( teams[playerIndex][petIndex][abilityIndex][2] ) then teams[playerIndex][petIndex][abilityIndex] = {abilityID}; updateAbilityButtonAbilityID( button ); end end --triggers at the start of each round (after both pets have done their moves), and after a pet switch choice is made -- clears id of ability used by the player in the current round, whenever player can pick a move DeePetBattleFrame_EventHandlers["PET_BATTLE_PET_ROUND_PLAYBACK_COMPLETE"] = function(self) if (C_PetBattles.IsSkipAvailable()) then --if a round starts, and the player can pass, then they aren't doing a multi-turn move lastPlayerAbilityID = nil; --clear last selected ability id end end --updates id of ability used by the player in the current round, whenever a choice is made DeePetBattleFrame_EventHandlers["PET_BATTLE_ACTION_SELECTED"] = function(self) local myActionType, myActionIndex = C_PetBattles.GetSelectedAction(); if (myActionType == LE_BATTLE_PET_ACTION_ABILITY) then lastPlayerAbilityID = C_PetBattles.GetAbilityInfo(LE_BATTLE_PET_ALLY, C_PetBattles.GetActivePet(LE_BATTLE_PET_ALLY), myActionIndex); else --if player selected something, but it's not an ability, clear last used ID lastPlayerAbilityID = nil; end end --parses pet battle combat log entries, finds activated abilities (filtering out auras and other junk) DeePetBattleFrame_EventHandlers["CHAT_MSG_PET_BATTLE_COMBAT_LOG"] = function(self, message) for id, hp, pow, spd in message:gmatch("|HbattlePetAbil:(%d-):(%d-):(%d-):(%d-)|h") do --turn matched strings to integers id=id+0; hp=hp+0; pow=pow+0; spd=spd+0; local isMyAction = (id == lastPlayerAbilityID) and checkMatchingStats(LE_BATTLE_PET_ALLY, hp, pow, spd); if isMyAction then processPlayerAction(LE_BATTLE_PET_ALLY, getPlayerAbilityIndex(LE_BATTLE_PET_ALLY, id), id); return; --Player's action can't also be the opponent's: We're done. end local enemyAbilityIndex = getPlayerAbilityIndex(LE_BATTLE_PET_ENEMY, id); local isEnemyAction = enemyAbilityIndex and checkMatchingStats(LE_BATTLE_PET_ENEMY, hp, pow, spd); if isEnemyAction then processPlayerAction(LE_BATTLE_PET_ENEMY, enemyAbilityIndex, id); return; --Don't parse more abilities: we've already found what we were looking for. end end end --whenever our main frame is shown, a pet battle has started (or UI was reloaded during one): init/refresh the team rosters, reset remaining vars DeePetBattleFrame_OnShow = function(self) populateTeams(); lastPlayerAbilityID = nil; --clear ID of the ability last picked by the player end --whenever our main frame is hidden, a pet battle has ended: forget team rosters until the next battle DeePetBattleFrame_EventHandlers["PET_BATTLE_CLOSE"] = function(self) teams = nil; lastPlayerAbilityID = nil; end --register events for the main frame DeePetBattleFrame_OnLoad = function(self) registerAllEvents(self, DeePetBattleFrame_EventHandlers); endend----------------------------------------- Ability Button Updating Functions -----------------------------------------do updateAbilityButtonState = function(self) local petFrame = self:GetParent():GetParent(); local hp = C_PetBattles.GetHealth(petFrame.playerIndex, petFrame.petIndex); local _, currentCooldown, currentLockdown = C_PetBattles.GetAbilityState(petFrame.playerIndex, petFrame.petIndex, self.abilityIndex); local cooldown = max(currentCooldown or 0, currentLockdown or 0); if ( not self.abilityID ) then --too low level to be able to use this slot. Show it as locked. self.Icon:SetVertexColor(0.5, 0.5, 0.5); self.Icon:SetDesaturated(true); self.Icon2:SetVertexColor(0.5, 0.5, 0.5); self.Icon2:SetDesaturated(true); self:Disable(); self.Lock:Show(); self.CooldownShadow:Show(); self.Cooldown:Hide(); self.BetterIcon:Hide(); elseif (hp <= 0) then --Pet's dead: set the frame up to look unusable self.Icon:SetVertexColor(0.5, 0.5, 0.5); self.Icon:SetDesaturated(true); self.Icon2:SetVertexColor(0.5, 0.5, 0.5); self.Icon2:SetDesaturated(true); self:Disable(); self.Lock:Hide(); self.CooldownShadow:Hide(); self.Cooldown:Hide(); elseif (cooldown > 0) then --Set the frame up to look like a cooldown. self.Icon:SetVertexColor(0.5, 0.5, 0.5); self.Icon:SetDesaturated(true); self.Icon2:SetVertexColor(0.5, 0.5, 0.5); self.Icon2:SetDesaturated(true); self:Disable(); self.Lock:Hide(); self.CooldownShadow:Show(); self.Cooldown:SetText(cooldown); self.Cooldown:Show(); else --Set the frame up to look clickable/usable. self.Icon:SetVertexColor(1, 1, 1); self.Icon:SetDesaturated(false); self.Icon2:SetVertexColor(1, 1, 1); self.Icon2:SetDesaturated(false); self:Enable(); self.Lock:Hide(); self.CooldownShadow:Hide(); self.Cooldown:Hide(); self.CooldownFlashAnim:Play(); end end --updates the aura duration and border for an ability button updateAbilityButtonAura = function( self ) local auraInfo = self.auraInfo; if (auraInfo == nil) then self.Duration:SetText(""); self.AuraBorder:Hide(); else if (auraInfo.duration < 0) then self.Duration:SetText(""); else self.Duration:SetText(auraInfo.duration); end if (auraInfo.isBuff) then self.AuraBorder:SetVertexColor(0, .8, 0, 1); else self.AuraBorder:SetVertexColor(1, 0, 0, 1); end self.AuraBorder:Show(); end end --update the strong/weak indicator for a button updateAbilityButtonBetterIcon = function(self) self.BetterIcon:Hide(); self.BetterIcon2:Hide(); local petFrame = self:GetParent():GetParent(); local opposingTeam = LE_BATTLE_PET_ALLY + LE_BATTLE_PET_ENEMY - petFrame.playerIndex; --the OTHER player local opposingPetSlot = C_PetBattles.GetActivePet(opposingTeam); local opposingType = C_PetBattles.GetPetType(opposingTeam, opposingPetSlot); local abilityIds = { self.abilityID, self.abilityID2 }; local icons = { self.BetterIcon, self.BetterIcon2 }; for k, abilityID in ipairs(abilityIds) do --update the strong/weak icon for BOTH abilities. stop as soon as we run out of abilityIDs if (not abilityID) then return end local icon = icons[k]; local _, _, _, _, _, _, attackPetType, noStrongWeakHints = C_PetBattles.GetAbilityInfoByID(abilityID); if (not attackPetType) then return; end -- show Strong/Weak icons on buttons. local modifier = C_PetBattles.GetAttackModifier(attackPetType, opposingType); if (noStrongWeakHints or modifier == 1) then icon:Hide(); elseif (modifier > 1) then icon:SetTexture("Interface\\PetBattles\\BattleBar-AbilityBadge-Strong"); icon:Show(); elseif (modifier < 1) then icon:SetTexture("Interface\\PetBattles\\BattleBar-AbilityBadge-Weak"); icon:Show(); end end end --updates a given ability button's icons based on its spellIDs, and enemy pet's type updateAbilityButtonIcons = function(self) --if we don't have any ability in this slot, find correct texture, add lock icon, and we're done. if (not self.abilityID) then local petFrame = self:GetParent():GetParent(); local speciesID = C_PetBattles.GetPetSpeciesID(petFrame.playerIndex, petFrame.petIndex); C_PetJournal.GetPetAbilityList(speciesID, idTable, levelTable); local abilityID = idTable[self.abilityIndex]; if ( not abilityID ) then --still haven't found anything? hide button. self.Icon:SetTexture("INTERFACE\\ICONS\\INV_Misc_Key_05"); self:Hide(); else local name, icon = C_PetJournal.GetPetAbilityInfo(abilityID); self.Icon:SetTexture(icon); self.Lock:Show(); self:Show(); end self.Icon:SetVertexColor(1, 1, 1); self:Disable(); return; end --we have at least one possible ability for this slot: get its icon. local id, name, icon = C_PetBattles.GetAbilityInfoByID(self.abilityID); if ( not icon ) then icon = "Interface\\Icons\\INV_Misc_QuestionMark"; end self.Icon:SetTexture(icon); self.Lock:Hide(); self:Enable(); self:Show(); --if there's a second possible abilityID, get its icon too if (self.abilityID2) then local id, name, icon = C_PetBattles.GetAbilityInfoByID(self.abilityID2); if ( not icon ) then icon = "Interface\\Icons\\INV_Misc_QuestionMark"; end self.Icon2:SetTexture(icon); self.Icon2:Show(); self.topHalfBorder:Show(); self.bottomHalfBorder:Show(); else self.Icon2:Hide(); self.topHalfBorder:Hide(); self.bottomHalfBorder:Hide(); end updateAbilityButtonBetterIcon(self); end --updates a given ability button's abilityIDs, its icons, and cooldown updateAbilityButtonAbilityID = function(self) local petFrame = self:GetParent():GetParent(); if (not (petFrame.playerIndex and petFrame.petIndex and self.abilityIndex)) then return end --do nothing if we don't know what we're pointing at if (not teams) then populateTeams() end --ensure team roster is populated local petData = teams[petFrame.playerIndex][petFrame.petIndex]; if (not petData) then return end --if there is no pet with this button's index, updating ends here local abilityList = petData[self.abilityIndex]; self.abilityID = abilityList[1]; self.abilityID2 = abilityList[2]; --in PVP matches, we may have two possible IDs updateAbilityButtonIcons(self); updateAbilityButtonState(self); end --Update weak/strong icon whenever there's a pet swap DeePetBattleAbilityButton_EventHandlers["PET_BATTLE_PET_CHANGED"] = updateAbilityButtonBetterIcon; --update volatile button info every round DeePetBattleAbilityButton_EventHandlers["PET_BATTLE_PET_ROUND_PLAYBACK_COMPLETE"] = function(self) self.SelectedHighlight:Hide(); updateAbilityButtonBetterIcon(self); --Update weak/strong icon here too (enemy can change type, without being swapped) updateAbilityButtonState(self); end --Update weak/strong icon whenever combat starts DeePetBattleAbilityButton_OnShow = updateAbilityButtonBetterIcon; --register events for each button DeePetBattleAbilityButton_OnLoad = function(self) registerAllEvents(self, DeePetBattleAbilityButton_EventHandlers); end --show tooltip when hovering over a button function DeePetBattleAbilityButton_OnEnter(self) local petFrame = self:GetParent():GetParent(); if ( self.abilityID ) then local bonusString = getAuraFormattedDuration( self.auraInfo ); PetBattleAbilityTooltip_SetAbilityByID(petFrame.playerIndex, petFrame.petIndex, self.abilityID, bonusString); if (petFrame.playerIndex == LE_BATTLE_PET_ALLY ) then PetBattleAbilityTooltip_Show("TOPLEFT", self, "BOTTOMRIGHT", 0, 0); else PetBattleAbilityTooltip_Show("TOPRIGHT", self, "BOTTOMLEFT", 0, 0); end else PetBattlePrimaryAbilityTooltip:Hide(); end end --show tooltip when hovering over a pvp half-button function DeePetBattleAbilityButton_topHalf_OnEnter(self) local buttonFrame = self:GetParent(); -- petFrame > groupFrame > buttonFrame > topHalfFrame local petFrame = buttonFrame:GetParent():GetParent(); if ( buttonFrame.abilityID2 ) then local bonusString = getAuraFormattedDuration( buttonFrame.auraInfo ); PetBattleAbilityTooltip_SetAbilityByID(petFrame.playerIndex, petFrame.petIndex, buttonFrame.abilityID2, bonusString); if (petFrame.playerIndex == LE_BATTLE_PET_ALLY ) then PetBattleAbilityTooltip_Show("TOPLEFT", self, "BOTTOMRIGHT", 0, 0); else PetBattleAbilityTooltip_Show("TOPRIGHT", self, "BOTTOMLEFT", 0, 0); end else DeePetBattleAbilityButton_OnEnter(buttonFrame); end end --hide tooltip when mouse leaves a button function DeePetBattleAbilityButton_OnLeave(self) PetBattlePrimaryAbilityTooltip:Hide(); endend------------------------------ Pet Updating Functions ------------------------------do DeePetBattlePet_OnLoad = function( self, playerIndex, frameIndex ) --remember which pet we're watching self.playerIndex = playerIndex; self.frameIndex = frameIndex; local groupFrame = self.Abilities; if (self.Auras == nil) then --active pets get bigger cooldowns, have no aura frames, and their durations are farther groupFrame:SetScale(0.7); for _, button in pairs({groupFrame.Button1, groupFrame.Button2, groupFrame.Button3}) do button.Duration:SetPoint("TOP", button, "BOTTOM", 0, -10); end else --benched pets get smaller cooldowns, and have aura frames. self:SetWidth(99); groupFrame:SetScale(0.6); self.Auras:SetScale(0.7); --this should make auras smaller than cooldowns local auraFrame = self.Auras.NextFrame; self.auraWidth = auraFrame:GetWidth(); self.totalAuraWidth = self.auraWidth; self.growsFromDirection = auraFrame:GetPoint(1); --(this first aura frame MUST exist in the XML) if (self.growsFromDirection == "LEFT") then self.growsToDirection = "RIGHT"; else self.growsToDirection = "LEFT"; end end --show/hide ourselves whenever our anchor is shown or hidden local _, anchorFrame = self:GetPoint(1); if (anchorFrame) then anchorFrame:HookScript("OnShow", function() self:Show() end); anchorFrame:HookScript("OnHide", function() self:Hide() end); if (not anchorFrame:IsShown()) then self:Hide() end end registerAllEvents(self, DeePetBattlePet_EventHandlers); end --updates which pet the given pet frame watches, based on which pet is active updatePetIndex = function( self ) local activePetIndex = C_PetBattles.GetActivePet(self.playerIndex); if (not activePetIndex) then return end --no need to update outside of pet battles local frameIndex = self.frameIndex; local petIndex; --find out who we're meant to watch if (frameIndex == 1) then petIndex = activePetIndex; --group 1 always watches active pet elseif (activePetIndex < frameIndex) then petIndex = frameIndex; --track own index if active pet comes before us else petIndex = frameIndex-1; --track one pet above us if active pet comes after us end --if our petIndex changed, update its children if (petIndex ~= self.petIndex) then self.petIndex = petIndex; updateAbilityGroupPetIndex( self.Abilities ); updatePetAuras( self ); end end --returns a table with info about all auras affecting the given pet getPetAuras = function( playerIndex, petIndex ) local numAuras = C_PetBattles.GetNumAuras(playerIndex, petIndex); if (numAuras == nil) or (C_PetBattles.GetHealth(playerIndex, petIndex) <= 0) then numAuras = 0; --hide auras for missing and/or dead pets end --populate auraTable with this pet's buffs/debuffs local auraTable = {}; for auraIndex=1, numAuras do --get aura info local id, instanceID, duration, isBuff, auraPlayerIndex, auraPetIndex = C_PetBattles.GetAuraInfo(playerIndex, petIndex, auraIndex); local _, name, icon = C_PetBattles.GetAbilityInfoByID(id); --store info in aura table auraTable[auraIndex] = { id = id; name = name; icon = icon; duration = duration; isBuff = isBuff; playerIndex = auraPlayerIndex; petIndex = auraPetIndex; }; end --sort table by remaining durations, putting infinite (-1) duration auras at the END; buffs go before debuffs when tied. table.sort(auraTable, function(a,b) if (a.duration == b.duration) then --If durations are tied, buffs come before debuffs. return (a.isBuff and not b.isBuff); else --If durations differ, smallest goes first. (but -1 goes last) return (b.duration < 0) or ((a.duration >= 0) and (a.duration < b.duration)) end end ); return auraTable; end --updates which auras are active on the current pet updatePetAuras = function( self ) local auraTable = getPetAuras(self.playerIndex, self.petIndex); --Go through this pet's ability buttons, use them to display their own auras, if present. updateAbilityGroupAuras( self.Abilities, auraTable ); --display all the remaining collected auras we can fit local prevAuraFrame = self.Auras; --self.Auras.NextFrame is the first aura frame for _, auraInfo in ipairs(auraTable) do if (prevAuraFrame == nil) then return end; --if we don't have an aura frame to anchor to, we're done --if aura's not shown on a button, try to show aura in an aura frame instead (as long as we have the previous frame it's anchored to) if (not auraInfo.isButtonAura) then local auraFrame = prevAuraFrame.NextFrame; --if the next aura frame doesn't exist yet, create it (if there's room for at least part of it) if (auraFrame == nil) and (self.totalAuraWidth + AURA_FRAME_DISTANCE < self.Auras:GetWidth()) then auraFrame = CreateFrame("frame", nil, self.Auras, "DeePetBattleAuraTemplate"); auraFrame:SetPoint(self.growsFromDirection, prevAuraFrame, self.growsToDirection); self.totalAuraWidth = self.totalAuraWidth + AURA_FRAME_DISTANCE + self.auraWidth; prevAuraFrame.NextFrame = auraFrame; end if (auraFrame ~= nil) then setAuraFrameAura(auraFrame,auraInfo); end prevAuraFrame = auraFrame; end end --hide any existing aura frames that weren't needed while (prevAuraFrame ~= nil) do local auraFrame = prevAuraFrame.NextFrame; if (auraFrame ~= nil) then auraFrame:Hide() end prevAuraFrame = auraFrame; end end --update abilities whenever a pet battle starts (or if UI is reloaded during one) DeePetBattlePet_OnShow = updatePetIndex; --forget petIndex when pet battle ends DeePetBattlePet_EventHandlers["PET_BATTLE_CLOSE"] = function(self) self.petIndex = nil; end --update abilities whenever there is a pet swap DeePetBattlePet_EventHandlers["PET_BATTLE_PET_CHANGED"] = function(self, playerIndex) if (self.playerIndex == playerIndex) then updatePetIndex(self) end end --function that handles aura events handleAuraEvent = function(self, playerIndex, petIndex, instanceID) if ( playerIndex == self.playerIndex and petIndex == self.petIndex ) then updatePetAuras(self); end end --keep track of auras on all pets: all three aura events are handled by the same function DeePetBattlePet_EventHandlers["PET_BATTLE_AURA_APPLIED"] = handleAuraEvent; DeePetBattlePet_EventHandlers["PET_BATTLE_AURA_CANCELED"] = handleAuraEvent; DeePetBattlePet_EventHandlers["PET_BATTLE_AURA_CHANGED"] = handleAuraEvent; --handle pet death and resurrection (update its auras when either happens) DeePetBattlePet_EventHandlers["PET_BATTLE_HEALTH_CHANGED"] = function( self, playerIndex, petIndex, amount ) if ( playerIndex == self.playerIndex and petIndex == self.petIndex ) then local hp = C_PetBattles.GetHealth(playerIndex, petIndex); if (amount < 0 and hp==0) or (amount > 0 and hp==amount) then updatePetAuras(self); end end end end---------------------------------------- Ability Group Updating Functions ----------------------------------------do --setup ability group internal variables for commodity DeePetBattleAbilityGroup_OnLoad = function(self) for index, button in ipairs({self.Button1, self.Button2, self.Button3}) do button.abilityIndex = index; --tell each button which ability slot it's watching end end --update all buttons in an ability group, after pet index changes updateAbilityGroupPetIndex = function( self ) self.nameTable = {}; --table with the names of all this group's abilities, and which button they belong to for _, button in pairs({self.Button1, self.Button2, self.Button3}) do updateAbilityButtonAbilityID( button ); --update this button's ability names, and corresponding buttons for _, id in pairs({button.abilityID, button.abilityID2}) do if (id ~= nil) then _, name = C_PetBattles.GetAbilityInfoByID(id); self.nameTable[name] = button; end end end end --update all buttons to show their own auras updateAbilityGroupAuras = function( self, auraTable ) local petFrame = self:GetParent(); --reset all button aura info for _, button in pairs({self.Button1, self.Button2, self.Button3}) do button.auraInfo = nil end --go through all auras to see which match any buttons for _, auraInfo in ipairs(auraTable) do button = self.nameTable[auraInfo.name]; if --is the aura's name the same as a button's, and it was cast by the same pet? (button ~= nil) and (auraInfo.playerIndex == petFrame.playerIndex) and (auraInfo.petIndex == petFrame.petIndex) then --if so, store that aura in the button auraInfo.isButtonAura = true; button.auraInfo = auraInfo; end end --refresh all button auras for _, button in pairs({self.Button1, self.Button2, self.Button3}) do updateAbilityButtonAura( button ); end end end---------------------------- Aura Frame Functions ----------------------------do --updates an aura frame to show the aura with the given info setAuraFrameAura = function( self, auraInfo ) self.auraInfo = auraInfo; --store info so we know how to make a tooltip, later if ( auraInfo.isBuff ) then self.DebuffBorder:Hide(); else self.DebuffBorder:Show(); end self.Icon:SetTexture(auraInfo.icon); if ( auraInfo.duration < 0 ) then self.Duration:SetText(""); else self.Duration:SetText(auraInfo.duration); end self:Show(); end --returns a tooltip-ready aura-duration string getAuraFormattedDuration = function(auraInfo) if (auraInfo == nil) or (auraInfo.duration < 0) then return ""; else local colorPrefix; if (auraInfo.isBuff) then colorPrefix = "|cFF00DD00"; else colorPrefix = "|cFFFF0000"; end local roundsString; if (auraInfo.duration == 1) then roundsString = " Round"; else roundsString = " Rounds"; end return colorPrefix .. auraInfo.duration .. roundsString .. " Remaining|h"; end end --show tooltip when hovering over an aura frame function DeePetBattleAura_OnEnter(self) local petFrame = self:GetParent():GetParent(); local auraInfo = self.auraInfo; if ( auraInfo ) then local bonusString = getAuraFormattedDuration( auraInfo ); PetBattleAbilityTooltip_SetAbilityByID(auraInfo.playerIndex, auraInfo.petIndex, auraInfo.id, bonusString); if (petFrame.playerIndex == LE_BATTLE_PET_ALLY ) then PetBattleAbilityTooltip_Show("TOPLEFT", self, "BOTTOMRIGHT", 0, 0); else PetBattleAbilityTooltip_Show("TOPRIGHT", self, "BOTTOMLEFT", 0, 0); end else PetBattlePrimaryAbilityTooltip:Hide(); end end function DeePetBattleAura_OnLeave(self) PetBattlePrimaryAbilityTooltip:Hide(); endend