--[[ Healers Assist by Kiki of European Cho'gall (Alliance) Process channel events ]] --------------- Constantes --------------- HA_STATE_CASTING = 1; HA_STATE_HEALED = 2; HA_STATE_STOP = 3; HA_STATE_FAILED = 4; HA_STATE_RESTING = 5; HA_STATE_NOTHING = 6; HA_STATE_DEAD = 7; HA_GUI_MAX_HEALERS = 16; HA_GUI_MAX_EMERG = 6; local MAX_COOLDOWN_SPELLS = 2; local MAX_OVERTIME_SPELLS=4; local HA_SPELL_REQUEST_CODE_DENIED_DENIED = 1; local HA_SPELL_REQUEST_CODE_DENIED_BLOCKED = 2; local HA_SPELL_REQUEST_CODE_DENIED_BUSY = 3; local HA_START_SLOT = 1; local HA_END_SLOT = 120; --------------- Shared variables --------------- HA_CustomOnClickFunction = nil; HA_SpellRequest = nil; HA_EmergList = {}; -- Profiling HA_PROFILE_StatusRoutine = 0; HA_PROFILE_OvertimeRoutine = 0; HA_PROFILE_RaidersInfosRoutine = 0; HA_PROFILE_GUIRoutine = 0; HA_PROFILE_AnalyseRaidersRoutine = 0; --------------- Local variables --------------- local _HA_LastTimeGUI = 0; local _HA_LastTimeHPMP = 0; local _HA_CurrentTarget = nil; local _HA_SortByName = false; local _HA_CurrentWindowAlpha = 1.0; local _HA_CurrentUIRefresh = 0.1; local _HA_NewVersionNotice = false; --------------- Internal functions --------------- local function _HA_ResetRaiderState(raider) raider.count = 0; raider.estimates = {}; raider.estimate_ratio = 1; raider.overtime = {}; end local function _HA_ResetHealerEstimate(healer) local raider = HA_Raiders[healer.TargetName]; if(raider) then if(raider.estimates[healer.Name] and raider.count > 0) then raider.count = raider.count - 1; end raider.estimates[healer.Name] = nil; end end local function _HA_ResetHealerState(healer,reset_warn) if(healer.State == HA_STATE_CASTING) -- If was casting, reset estimates then _HA_ResetHealerEstimate(healer); if(reset_warn and HA_Config.Debug) -- Should issue a warning then --HA_ChatWarning("_HA_ResetHealerState : Was in CASTING state on "..tostring(healer.TargetName).." with spell "..tostring(healer.SpellName)..", but should not !"); end end if(healer.NextResetState) then healer.State = healer.NextResetState; else healer.State = HA_STATE_NOTHING; end healer.NextResetState = nil; healer.SpellCode = nil; healer.NonHeal = nil; healer.SpellName = nil; healer.SpellRank = nil; healer.ShortSpellName = nil; healer.TargetName = nil; healer.Estimate = 0; healer.CastTime = nil; healer.StartTime = 0; healer.EndTime = nil; healer.OverHealed = nil; healer.OverHealPercent = 0; healer.EstimateRatio = 1; healer.GroupHeal = nil; end local function _HA_CheckForResetStates() for name,tab in HA_Healers do if((tab.State == HA_STATE_HEALED) or (tab.State == HA_STATE_FAILED) or (tab.State == HA_STATE_STOP)) then if(HA_CurrentTime > tab.EndTime) then _HA_ResetHealerState(tab,false); end end end end -- (Duration and Estimated) ~= 0 -> Healing spell (Show Heal/Duration in 'Casting column') local function _HA_Process_SpellHitInstant(healer,raider,SpellCode,SpellName,Duration,Estimated,SpellRank) -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnSpellHitInstant) then pl.OnSpellHitInstant(healer,raider,SpellCode,SpellName,Duration,Estimated,SpellRank); end end if((Duration ~= 0 and HA_Config.ShowHoT and SpellCode ~= HA_SPELL_REGROWTH_HOT) or (Duration == 0 and HA_Config.ShowInstants)) then healer.State = HA_STATE_HEALED; healer.SpellCode = SpellCode; healer.NonHeal = HA_InstantSpells[SpellName].nonheal; healer.SpellName = SpellName; healer.SpellRank = SpellRank; healer.TargetName = raider.name; healer.ShortSpellName = HA_InstantSpells[SpellName].short; healer.EndTime = HA_CurrentTime + HA_Config.KeepValue; healer.Value = Estimated; healer.Duration = Duration; healer.Crit = false; healer.HoT = true; healer.GroupHeal = HA_InstantSpells[SpellName].group; end end local function _HA_EatHoT(healer,raider) local rejuvName = HA_GetLocalName(HA_SPELL_REJUVENATION); local regrowName = HA_GetLocalName(HA_SPELL_REGROWTH_HOT); local spell = raider.overtime[rejuvName]; if(spell) -- Rejuv has priority over regrowth then HA_ChatDebug(HA_DEBUG_SPELLS,"_HA_EatHoT : Eat HoT "..rejuvName.." from "..healer.Name.." to "..raider.name); -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnEatHot) then pl.OnEatHot(HA_SPELL_REJUVENATION,raider,spell.From,spell.Start,spell.Duration); end end raider.overtime[rejuvName] = nil; return; end spell = raider.overtime[regrowName]; if(spell) then HA_ChatDebug(HA_DEBUG_SPELLS,"_HA_EatHoT : Eat HoT "..regrowName.." from "..healer.Name.." to "..raider.name); -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnEatHot) then pl.OnEatHot(HA_SPELL_REGROWTH_HOT,raider,spell.From,spell.Start,spell.Duration); end end raider.overtime[regrowName] = nil; return; end end local function _HA_GetRaiderHealthBeforeHeal(raider,Value,healer) for i,tab in raider.heal_updates do if(tab.value == Value) -- Found it then local val = tab.oldhp; HA_ChatDebug(HA_DEBUG_SPELLS,"_HA_GetRaiderHealthBeforeHeal : Heal value ("..tostring(Value)..") found from "..tostring(healer.Name).." to "..raider.name.." : HP before="..tostring(val).." : Array size="..tostring(getn(raider.heal_updates))); table.remove(raider.heal_updates,i); return val; end end if(HA_Config.Debug and HA_Config.UseEstimatedHealth and getn(raider.heal_updates) == HA_MAX_HEAL_UPDATES) -- Estim health algo used, but value not found then HA_ChatWarning("_HA_GetRaiderHealthBeforeHeal : Heal value ("..tostring(Value)..") not found from "..tostring(healer.Name).." to "..raider.name.." : Array size="..tostring(getn(raider.heal_updates))); end return raider.hp; end local function _HA_Process_SpellHit(healer,SpellCode,SpellName,raider,Value,Crit,InstantSpell) -- Traitement if(raider) then if(Crit) then HA_ChatDebug(HA_DEBUG_SPELLS,"SpellHit CRIT from "..healer.Name.." to "..raider.name.." with "..SpellName.." for "..tostring(Value).." hp."); else HA_ChatDebug(HA_DEBUG_SPELLS,"SpellHit from "..healer.Name.." to "..raider.name.." with "..SpellName.." for "..tostring(Value).." hp."); end -- Check overhealed status local new_hp = _HA_GetRaiderHealthBeforeHeal(raider,Value,healer) + Value; local overhealed = 0; if(new_hp > raider.hpmax) then overhealed = new_hp - raider.hpmax; healer.OverHealed = overhealed / Value; end if(SpellCode == HA_SPELL_SWIFTMEND) then _HA_EatHoT(healer,raider); end -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnSpellHit) then pl.OnSpellHit(healer,raider,SpellCode,SpellName,Value,Crit,overhealed,InstantSpell); end end end if(healer.State == HA_STATE_STOP and healer.SpellCode == SpellCode) -- Added SpellCode check, to prevent an instant heal (like SwiftMend) to come before a casted spell then -- Reset data healer.State = HA_STATE_HEALED; healer.EndTime = HA_CurrentTime + HA_Config.KeepValue; healer.Value = Value; healer.Crit = Crit; healer.HoT = false; end end local function _HA_GetCurrentInfos() for name,infos in HA_Raiders do local healer = HA_Healers[name]; local death_state_changed = false; infos.isconnected = UnitIsConnected(infos.id); if(infos.isconnected and (infos.subgrp ~= 0 or (HA_CurrentTarget and name == HA_CurrentTarget))) -- If a special "Target" raider, must be current target then -- Update infos infos.isdead = UnitIsDeadOrGhost(infos.id); infos.ischarmed = UnitIsCharmed(infos.id); -- Check Raider death state if(infos.isdead and not infos.oldisdead) -- was alive, is now dead then death_state_changed = true; _HA_ResetRaiderState(infos); -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnEvent) then pl.OnEvent(HA_EVENT_RAIDER_DIED,{name}); end end elseif(infos.oldisdead and not infos.isdead) -- Was dead, got rez then death_state_changed = true; -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnEvent) then pl.OnEvent(HA_EVENT_RAIDER_RESURRECTED,{name}); end end end infos.oldisdead = infos.isdead; -- Check Raider is a Healer if(infos.ishealer) then if(death_state_changed) then if(infos.isdead) -- Was alive, is now dead then _HA_ResetHealerState(healer,false); -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnEvent) then pl.OnEvent(HA_EVENT_HEALER_DIED,{name}); end end HA_Healers[name].State = HA_STATE_DEAD; else -- Was dead, got resurrection _HA_ResetHealerState(healer,false); -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnEvent) then pl.OnEvent(HA_EVENT_HEALER_RESURRECTED,{name}); end end end end end end -- Check for a possible Estimates reset of Raider if(not infos.isconnected) -- Offline, reset estimates then _HA_ResetRaiderState(infos); if(infos.ishealer and healer) then _HA_ResetHealerState(healer,false); end end end _HA_LastTimeHPMP = HA_CurrentTime; end local function _HA_WillOverHeal(healer) local raider = HA_Raiders[healer.TargetName]; local my_end_time = healer.StartTime + healer.CastTime; if(raider and (raider.subgrp ~= 0 or healer.TargetName == HA_PlayerName)) then local hp = raider.hp; -- Check all other healers, casting on the same target than me, if their spell will hit before me, forcing me to overheal for name,tab in HA_Healers do if(name ~= HA_PlayerName and tab.State == HA_STATE_CASTING and tab.TargetName == healer.TargetName and (tab.StartTime+tab.CastTime) < my_end_time) then hp = hp + tab.Estimate * tab.EstimateRatio * raider.estimate_ratio; if(hp >= raider.hpmax) then healer.OverHealPercent = 100; -- My spell will overheal at 100% return; end end end -- Nobody will force me to overheal at 100%, check how much my spell will overheal local my_estim = healer.Estimate * healer.EstimateRatio * raider.estimate_ratio; local my_spell = hp + my_estim; if(my_spell > raider.hpmax) then healer.OverHealPercent = (my_spell-raider.hpmax) / my_estim * 100; return; end end healer.OverHealPercent = 0; end local function HA_ScanDebufName(unitid,i) HealersAssistTooltip:SetOwner(UIParent, "ANCHOR_NONE"); HealersAssistTooltip:ClearLines(); HealersAssistTooltip:SetUnitDebuff(unitid,i); local debuffName = tostring(HealersAssistTooltipTextLeft1:GetText()); HealersAssistTooltip:Hide(); --HA_ChatPrint("HA_ScanDebufName : Unit="..unitid.." i="..i.." Name="..debuffName); return debuffName; end function HA_ShowDebuf() for i=1,16 do local texture,count = UnitDebuff("target",i); if(texture == nil) then break; end; HA_ChatPrint("DebufName : i="..i.." Name="..HA_ScanDebufName("target",i)); if(count == nil or count == 0) then count = 1; end; local debuf = HA_HealDebuffs[texture]; if(debuf) then if(debuf.malus) -- No zone check then HA_ChatPrint("Found GLOBAL debuff ("..i..") with malus="..debuf.malus.." count="..count.." : "..texture); ret = ret * (1 - count * debuf.malus); elseif(debuf.zones) then local malus = debuf.zones[HA_CurrentZone]; if(malus) then if(type(malus) == "table") then else HA_ChatPrint("Found Zone ("..HA_CurrentZone..")debuff ("..i..") with malus="..malus.." count="..count.." : "..texture); ret = ret * (1 - count * malus); end else HA_ChatPrint("Debuf texture found ("..texture.."), but malus for this zone : "..HA_CurrentZone); end end end end end function HA_UnitHasHealDebuf(unitid) local malus; local names; local ret = 1; local texture; local count; local debuf; for i=1,16 do texture,count = UnitDebuff(unitid,i); if(texture == nil) then break; end; if(count == nil or count == 0) then count = 1; end; debuf = HA_HealDebuffs[texture]; if(debuf) then if(debuf.malus) -- No zone check then ret = ret * (1 - count * debuf.malus); elseif(debuf.zones) then malus = debuf.zones[HA_CurrentZone]; if(malus) then if(type(malus) == "table") then names = malus.names; if(names) then malus = names[HA_ScanDebufName(unitid,i)]; if(malus) then ret = ret * (1 - count * malus); end end else ret = ret * (1 - count * malus); end end end end end return ret; end function HA_StatusScheduleRoutine() debugprofilestart(); -- First, check my overheal status local healer = HA_MyselfHealer; if(healer and healer.State == HA_STATE_CASTING) then _HA_WillOverHeal(healer); end -- Second, check estimates debufs (for mortal strike or other) for name,tab in HA_Raiders do tab.estimate_ratio = 1; -- Reset value if(tab.count ~= 0) -- Someone casting, time to check ratio then tab.estimate_ratio = HA_UnitHasHealDebuf(tab.id); end end -- Third, check estimates bufs for name,tab in HA_Healers do tab.EstimateRatio = 1; -- Reset value if(HA_RaiderInfused(name)) -- Got infused with power ? then tab.EstimateRatio = tab.EstimateRatio * 1.2; end end HA_PROFILE_StatusRoutine = debugprofilestop(); -- Finally reschedule HASystem_Schedule(0.10,HA_StatusScheduleRoutine); end function HA_OvertimeScheduleRoutine() debugprofilestart(); local serv_time = GetTime(); -- Check overtime timers for name,tab in HA_Raiders do for spell,infos in tab.overtime do if(serv_time > (infos.Start + infos.Duration)) -- Expired then tab.overtime[spell] = nil; end end end -- Check IsRegen state local raider = HA_MyselfRaider; local healer = HA_MyselfHealer; if(healer and raider and healer.State == HA_STATE_RESTING) then if(raider.isdead or raider.mp == raider.mpmax) -- I'm dead, or my mana is full then HA_SetRegenMode(false); end end HA_PROFILE_OvertimeRoutine = debugprofilestop(); -- Re schedule HASystem_Schedule(1,HA_OvertimeScheduleRoutine); end local function _HA_ConvertToMinSec(val) local minutes = floor(val / 60); local secondes = val - (minutes*60); return minutes.." min "..secondes.." sec"; end -- Range code from decursive local function _HA_FindActionSlot(texture,SpellName) local i = 0; for i = HA_START_SLOT, HA_END_SLOT do if(HasAction(i)) then icon = GetActionTexture(i); if(icon == texture) then return i; -- Don't check the spell name end end end return 0; end local function _HA_UnitInRange(id,ISpell) if(not UnitIsVisible(id)) then return false; end local SpellName = HA_GetLocalName(ISpell); local cdspell = HA_Cooldown[ISpell]; if(SpellName and cdspell and not cdspell.norange) then if(cdspell.longrange) then local Range_Slot = _HA_FindActionSlot(cdspell.texture,SpellName); if(Range_Slot ~= 0) then local ret_val = false; TargetUnit(id); if(UnitIsUnit("target",id)) then ret_val = (IsActionInRange(Range_Slot) == 1); end return ret_val; end else if(CheckInteractDistance(id,4)) then return true; else return false; end end end return true; end function HA_GUI_GetHealersLines() local healerslines = HA_Config.HealersLines; if(HA_Config.HealersCollapsed) then healerslines = 1; end; return healerslines; end function HA_GUI_GetHealersHeight() return 16+2 + HA_GUI_GetHealersLines() * 16; end function HA_GUI_GetEmergencyHeight() local emerg_height = 0; if(HA_Config.EmergLines ~= 0) then emerg_height = 16+2 + HA_Config.EmergLines * 16; end return emerg_height; end function HA_GUI_GetMainHeight() return 25+10+10 + HA_GUI_GetHealersHeight() + HA_GUI_GetEmergencyHeight(); end local _ha_first_show = true; function HA_SetWidgetSizeAndPosition() local healerslines = HA_GUI_GetHealersLines(); local healers_height = HA_GUI_GetHealersHeight(); local emerg_height = HA_GUI_GetEmergencyHeight(); local main_height = HA_GUI_GetMainHeight(); local scale = HA_Config.Scale / 100; local back_alpha = HA_Config.BackdropAlpha / 100; _HA_CurrentWindowAlpha = HA_Config.Alpha / 100; _HA_CurrentUIRefresh = HA_Config.GUIRefresh / 1000; if scale < 0.3 then scale = 0.3; elseif scale > 1.5 then scale = 1.5; end -- Hide non-used Healers for i=healerslines+1,HA_GUI_MAX_HEALERS do getglobal("HAItem_"..i):Hide(); end -- Hide non-used emerg for i=HA_Config.EmergLines+1,HA_GUI_MAX_EMERG do getglobal("HAItemEmergency_"..i):Hide(); end if(HA_Config.EmergLines ~= 0) then -- Set emergency position HAEmergencyFrame:Show(); HAEmergencyFrame:SetHeight(emerg_height); HAEmergencyFrame:SetPoint("TOPLEFT","HAItem_"..healerslines,"BOTTOMLEFT",0,-10); else HAEmergencyFrame:Hide(); end -- Set main window anchor and height if(HA_Config.GrowUpwards) then local i = HealersAssistMainFrame:GetBottom(); local j = HealersAssistMainFrame:GetLeft(); if(i and j) then if(not _ha_first_show) then HealersAssistMainFrame:ClearAllPoints(); HealersAssistMainFrame:SetPoint("TOPLEFT","UIParent","BOTTOMLEFT",j,i+main_height); end end end HealersAssistMainFrame:SetHeight(main_height); HealersAssistMainFrame:SetScale(scale); HealersAssistMainFrame:SetAlpha(_HA_CurrentWindowAlpha); HealersAssistMainFrame:SetBackdropColor(1,1,1,back_alpha); HealersAssistMainFrame:SetBackdropBorderColor(1,1,1,back_alpha); if(healerslines >= 4) then HAItemScrollFrame:SetHeight(healerslines * 16); else HAItemScrollFrame:SetHeight(4 * 16); end -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnEvent) then pl.OnEvent(HA_EVENT_WINDOW_SIZED,{healerslines,HA_Config.EmergLines,healers_height,emerg_height,main_height,scale,_HA_CurrentWindowAlpha,back_alpha}); end end _ha_first_show = false; end --------------- Shared functions --------------- function HA_IsPlayerCasting() local healer = HA_MyselfHealer; if(healer and healer.State == HA_STATE_CASTING) then return true; end; return false; end function HA_RaiderInfused(Name) local raider = HA_Raiders[Name]; if(raider) then for ispell,tab in raider.overtime do if(ispell == HA_POWER_INFUSION) then return true; end end end return false; end --------------- XML functions --------------- function HA_Collapse_Healers_Click(state) if(state) then HA_Config.HealersCollapsed = true; else HA_Config.HealersCollapsed = false; end HA_SetWidgetSizeAndPosition(); end function HA_SelectEmergency(pos) local infos = HA_EmergList[pos]; if(infos and infos.raider) then TargetUnit(infos.raider.id); else ClearTarget(); end end function HAHeader_SortByName(byname) _HA_SortByName = byname; end function HA_OnShow() HealersAssistMainFrameCollapseHealers:SetChecked(HA_Config.HealersCollapsed); HA_SetWidgetSizeAndPosition(); _HA_CheckForResetStates(); HA_UpdateList(); HA_UpdateListEmergency(); -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnEvent) then pl.OnEvent(HA_EVENT_WINDOW_SHOW); end end end function HA_OnHide() -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnEvent) then pl.OnEvent(HA_EVENT_WINDOW_HIDE); end end end function HA_CheckGetCurrentInfos() -- Update Raider infos every 0.25 sec if(HA_CurrentTime > (_HA_LastTimeHPMP+0.25)) then debugprofilestart(); _HA_GetCurrentInfos(); HA_PROFILE_RaidersInfosRoutine = debugprofilestop(); end end function HA_OnUpdate(arg1) -- Update GUI every 0.10 sec if(HA_CurrentTime > (_HA_LastTimeGUI+_HA_CurrentUIRefresh)) then debugprofilestart(); _HA_CheckForResetStates(); HA_UpdateList(); HA_UpdateListEmergency(); _HA_LastTimeGUI = HA_CurrentTime; HA_PROFILE_GUIRoutine = debugprofilestop(); end end function HASetColumnWidth( width, frame ) if ( not frame ) then frame = this; end frame:SetWidth(width); getglobal(frame:GetName().."Middle"):SetWidth(width - 9); end local function _HA_SortHealersByAlphabetic(a,b) return a.Name < b.Name; -- Return alphabetic order end local function _HA_SortByCastingTime(a,b) return (a.StartTime+a.CastTime) < (b.StartTime+b.CastTime); end local _HA_NextSortingFunction = {}; _HA_NextSortingFunction[HA_STATE_HEALED] = _HA_SortHealersByAlphabetic; _HA_NextSortingFunction[HA_STATE_STOP] = _HA_SortHealersByAlphabetic; _HA_NextSortingFunction[HA_STATE_CASTING] = _HA_SortByCastingTime; _HA_NextSortingFunction[HA_STATE_FAILED] = _HA_SortHealersByAlphabetic; _HA_NextSortingFunction[HA_STATE_RESTING] = _HA_SortHealersByAlphabetic; _HA_NextSortingFunction[HA_STATE_NOTHING] = _HA_SortHealersByAlphabetic; _HA_NextSortingFunction[HA_STATE_DEAD] = _HA_SortHealersByAlphabetic; local function _HA_SortHealersByState(a,b) if(a.State == b.State) then return _HA_NextSortingFunction[a.State](a,b); end return a.State < b.State; end local function _HA_SortHealersList(a,b) if(a.Name == HA_PlayerName) -- Put myself on top of the list then return true; end if(b.Name == HA_PlayerName) -- Put myself on top of the list then return false; end if(_HA_SortByName) then return _HA_SortHealersByAlphabetic(a,b); end if(_HA_CurrentTarget) -- I have a target then if(tostring(a.TargetName) == _HA_CurrentTarget) -- 'a' has the same target then if(tostring(b.TargetName) == _HA_CurrentTarget) -- 'b' has too, check from state (can not be dead) then return _HA_SortHealersByState(a,b); else -- 'b' doesn't, 'a' before 'b' return true; end else -- 'a' doesn't have the same target, check if 'b' has if(tostring(b.TargetName) == _HA_CurrentTarget) -- 'b' has, 'b' before 'a' then return false; else -- Else, check from State return _HA_SortHealersByState(a,b); end end end return _HA_SortHealersByState(a,b); -- I don't have a target, return from State end function HA_DefaultFilter_Healer(healer) if(healer.Raider and healer.Raider.ishealer and (healer.Name == HA_PlayerName or HA_Config.HealersClasses[healer.Raider.classid])) then return true; end return false; end local function HA_GetList() local UIList = {}; local get_done = false; local sort_done = false; -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnGetHealersList) then UIList = pl.OnGetHealersList(); get_done = true; break; end end if(not get_done) then for name,tab in HA_Healers do if(HA_DefaultFilter_Healer(tab)) then tinsert(UIList, tab); end end _HA_CurrentTarget = nil; if(HA_MyselfHealer) then _HA_CurrentTarget = HA_MyselfHealer.TargetName; end end -- Call plugins for n,pl in HA_ActivePlugins do if(pl.SortHealers) then table.sort(UIList,pl.SortHealers); sort_done = true; break; end end if(not sort_done) then table.sort(UIList,_HA_SortHealersList); end return UIList; end local function _HA_SortEmergencyList(a,b) if(a.raider.count == 0) -- Nobody on 'a' then if(b.raider.count == 0) -- Nobody on 'b' -> Sort by % then return a.raider.percent < b.raider.percent; -- Everything else, sort by remain end end return ((a.raider.hpmax-a.raider.hp)-a.total) > ((b.raider.hpmax-b.raider.hp)-b.total); -- Compares a.remain - b.remain (remain = deficit-totalHeal) end function HA_DefaultFilter_Raider(raider) if(raider.percent < HA_Config.MinEmergencyPercent and -- percent < Config raider.isconnected and not raider.isdead and not raider.ischarmed and UnitIsVisible(raider.id) and -- Connected, not dead, is not charmed, is visible -- Check for filter (raider == HA_MyselfRaider or -- Always show myself ((raider.subgrp ~= 0 or (HA_CurrentTarget and raider.name == HA_CurrentTarget)) and -- If a special "Target" raider, must be current target (HA_CurrentGroupMode ~= HA_MODE_RAID or raider.subgrp == 0 or HA_Config.EmergencyGroups[raider.subgrp]) and -- Not Group filtered HA_Config.EmergencyClasses[raider.classid])) and -- Not class filtered (not HA_Config.FilterRange or CheckInteractDistance(raider.id,4))) -- Not range filtered then return true; end return false; end function HA_ComputeIncomingHeals(raider) local total = 0; local healer; for name,value in raider.estimates do heal_ratio = 1; healer = HA_Healers[name]; if(healer) then heal_ratio = healer.EstimateRatio; end total = total + value*heal_ratio; end return floor(total * raider.estimate_ratio); -- Apply ratio end local function HA_GetListEmergency() local ret_vals = {}; local temp = {}; local heal_ratio; local healer; local get_done = false; local sort_done = false; -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnGetEmergencyList) then temp = pl.OnGetEmergencyList(); get_done = true; break; end end if(not get_done) then local total; for name,tab in HA_Raiders do if(HA_DefaultFilter_Raider(tab)) then total = HA_ComputeIncomingHeals(tab); tinsert(temp, { raider = tab; total = total }); end end end -- Call plugins for n,pl in HA_ActivePlugins do if(pl.SortEmergency) then table.sort(temp,pl.SortEmergency); sort_done = true; break; end end if(not sort_done) then table.sort(temp,_HA_SortEmergencyList); end if(HA_Config.EmergLines ~= 0) then local pos = 1; for i=1,HA_Config.EmergLines do if(temp[i]) then ret_vals[pos] = { raider = temp[i].raider; deficit = temp[i].raider.hpmax-temp[i].raider.hp; total = temp[i].total }; getglobal("HAItemEmergency_"..pos.."ClickFrame").unitid = temp[i].raider.id; pos = pos + 1; end end if(pos <= HA_Config.EmergLines) then for i=pos,HA_Config.EmergLines do ret_vals[i] = {}; end end end HA_EmergList = ret_vals; return ret_vals; end local function _HA_SetTargetHealth(prefix,TargetName) if(TargetName ~= nil) then local percent = nil; if(HA_Raiders[TargetName]) -- Target is in the raid then local infos = HA_Raiders[TargetName]; percent = infos.percent; elseif(UnitName("target") == TargetName) -- My target is the person I'm tyrying to heal then percent = floor(UnitHealth("target") / UnitHealthMax("target") * 100); end if(percent ~= nil) then if(percent > 100) then percent = 100; end; getglobal(prefix.."HPBar"):Show(); getglobal(prefix.."HPBar"):SetValue(percent); return; end end getglobal(prefix.."HPBar"):Hide(); end local function _HA_SetHealerMana(prefix,PlayerName,State) local infos = HA_Raiders[PlayerName]; if(infos) then local percent = infos.mppercent; if(percent ~= nil) then -- Draw MP bar if(percent > 100) then percent = 100; end; local powertype = UnitPowerType(infos.id); if(powertype ~= 0) -- Check powertype for druids then percent = 0; if(powertype == 1) -- Bear then getglobal(prefix.."MPBarBG"):SetVertexColor(1, 0, 0, 0.2); else -- Cat getglobal(prefix.."MPBarBG"):SetVertexColor(1, 1, 0, 0.2); end else getglobal(prefix.."MPBarBG"):SetVertexColor(0, 0, 1, 0.2); end getglobal(prefix.."MPBar"):Show(); getglobal(prefix.."MPBar"):SetValue(percent); -- Check for MP bar flashing if(State == HA_STATE_RESTING) then local cur_alpha = getglobal(prefix.."MPBar"):GetAlpha(); cur_alpha = cur_alpha + _HA_CurrentWindowAlpha/10; if(cur_alpha >= _HA_CurrentWindowAlpha) then cur_alpha = _HA_CurrentWindowAlpha/3; end getglobal(prefix.."MPBar"):SetAlpha(cur_alpha); else getglobal(prefix.."MPBar"):SetAlpha(_HA_CurrentWindowAlpha); end return; end end getglobal(prefix.."MPBar"):Hide(); end function HA_UpdateList() if(not HealersAssistMainFrame:IsVisible()) then return; end local list = HA_GetList(); local size = table.getn(list); local target_raider; local estim_ratio; local isdead; local healer; local offset = FauxScrollFrame_GetOffset(HAItemScrollFrame); local healerslines = HA_Config.HealersLines; if(HA_Config.HealersCollapsed) then healerslines = 1; end; numButtons = healerslines; i = 1; while (i <= numButtons) do local j = i + offset local prefix = "HAItem_"..i; local button = getglobal(prefix); if (j <= size) then healer = list[j]; getglobal("HAItem_"..i.."ClickFrame").unitid = healer.Raider.id; button.infos = healer; isdead = false; if(healer.State == HA_STATE_DEAD) then getglobal(prefix.."MPBarText"):SetTextColor(1, 0.1, 0.1); isdead = true; else local colors = RAID_CLASS_COLORS[healer.Raider.class]; if(colors) then getglobal(prefix.."MPBarText"):SetTextColor(colors.r, colors.g, colors.b); end end getglobal(prefix.."MPBarText"):SetText(healer.Name); _HA_SetHealerMana(prefix,healer.Name,healer.State); if(healer.State == HA_STATE_CASTING or healer.State == HA_STATE_STOP) then getglobal(prefix.."State"):SetTextColor(0,0.9,0); getglobal(prefix.."State"):SetText(healer.ShortSpellName); if(healer.OverHealPercent ~= 0) -- Overhealing then local col = 1.0 - (healer.OverHealPercent / 100); getglobal(prefix.."HPBarText"):SetVertexColor(1.0, col, col, 0.8); else getglobal(prefix.."HPBarText"):SetVertexColor(1.0, 1.0, 1.0, 0.8); end getglobal(prefix.."HPBarText"):SetText(healer.TargetName); local percent = (HA_CurrentTime - healer.StartTime) / healer.CastTime * 100; if(percent > 100) then percent = 100; end; getglobal(prefix.."CTBar"):Show(); getglobal(prefix.."CTBar"):SetValue(percent); getglobal(prefix.."CTBarText"):SetTextColor(0,0.8,0); if(healer.Estimate ~= 0) then target_raider = HA_Raiders[healer.TargetName]; estim_ratio = 1; if(target_raider) then estim_ratio = target_raider.estimate_ratio; end getglobal(prefix.."CTBarText"):SetText("("..tostring(floor(healer.Estimate*healer.EstimateRatio*estim_ratio))..")"); else getglobal(prefix.."CTBarText"):SetText(""); end _HA_SetTargetHealth(prefix,healer.TargetName); elseif(healer.State == HA_STATE_FAILED) then getglobal(prefix.."State"):SetTextColor(0.8,0,0); getglobal(prefix.."State"):SetText(healer.Reason); getglobal(prefix.."HPBarText"):SetVertexColor(1.0, 1.0, 1.0, 0.8); getglobal(prefix.."HPBarText"):SetText(healer.TargetName); getglobal(prefix.."CTBar"):Hide(); _HA_SetTargetHealth(prefix,healer.TargetName); elseif(healer.State == HA_STATE_HEALED) then getglobal(prefix.."State"):SetTextColor(0.1,0.4,0.1); getglobal(prefix.."State"):SetText(healer.ShortSpellName); if(healer.OverHealed) -- Overhealing then local col = 1.0 - healer.OverHealed; getglobal(prefix.."HPBarText"):SetVertexColor(1.0, col, col, 0.8); else getglobal(prefix.."HPBarText"):SetVertexColor(1.0, 1.0, 1.0, 0.8); end getglobal(prefix.."HPBarText"):SetText(healer.TargetName); getglobal(prefix.."CTBar"):Show(); getglobal(prefix.."CTBar"):SetValue(0); if(healer.HoT) -- A HoT spell (or instant) then if(healer.Duration == 0) -- Instant then getglobal(prefix.."CTBarText"):SetText(""); else -- HoT getglobal(prefix.."CTBarText"):SetText(tostring(healer.Value).."/"..tostring(healer.Duration).."s"); getglobal(prefix.."CTBarText"):SetTextColor(0,0.9,0); end else -- Casted spell if(healer.Value == 0) -- Non-heal spell (rez ?) then getglobal(prefix.."CTBarText"):SetText(""); elseif(healer.Crit) then getglobal(prefix.."CTBarText"):SetText("C:+"..tostring(healer.Value)); getglobal(prefix.."CTBarText"):SetTextColor(0,1,0); else getglobal(prefix.."CTBarText"):SetText("+"..tostring(healer.Value)); getglobal(prefix.."CTBarText"):SetTextColor(0,0.9,0); end end _HA_SetTargetHealth(prefix,healer.TargetName); else -- All other cases (NOTHING/DEAD/RESTING) if(healer.State == HA_STATE_RESTING) then getglobal(prefix.."State"):SetTextColor(0.2,0.2,1.0); getglobal(prefix.."State"):SetText(HA_GUI_RESTING_STATE); if(HA_CurrentGroupMode == HA_MODE_RAID) then getglobal(prefix.."HPBarText"):SetVertexColor(1.0, 1.0, 1.0, 1.0); getglobal(prefix.."HPBarText"):SetText("Grp "..healer.Raider.subgrp); getglobal(prefix.."HPBar"):SetValue(0); getglobal(prefix.."HPBar"):Show(); else getglobal(prefix.."HPBar"):Hide(); end else getglobal(prefix.."State"):SetText(""); getglobal(prefix.."HPBar"):Hide(); end getglobal(prefix.."CTBar"):Hide(); end -- Cooldown receiver status local under_Cooldown = {}; local cur_specific = 1; for spell,tab in healer.Raider.overtime do if(cur_specific > MAX_COOLDOWN_SPELLS) then break; end if(HA_Cooldown[tab.ispell]) -- I'm under a Cooldown spell then getglobal(prefix.."ClassSpecific"..cur_specific):Show(); getglobal(prefix.."ClassSpecific"..cur_specific.."Texture"):SetVertexColor(HA_Cooldown[tab.ispell].flash_r,HA_Cooldown[tab.ispell].flash_g,HA_Cooldown[tab.ispell].flash_b); getglobal(prefix.."ClassSpecific"..cur_specific.."Texture"):SetTexture(HA_Cooldown[tab.ispell].texture); local cur_alpha = getglobal(prefix.."ClassSpecific"..cur_specific):GetAlpha(); cur_alpha = cur_alpha + _HA_CurrentWindowAlpha/10; if(cur_alpha >= _HA_CurrentWindowAlpha) then cur_alpha = _HA_CurrentWindowAlpha/3; end getglobal(prefix.."ClassSpecific"..cur_specific):SetAlpha(cur_alpha); getglobal(prefix.."ClassSpecific"..cur_specific).cooldown = nil; getglobal(prefix.."ClassSpecific"..cur_specific).spell = spell; getglobal(prefix.."ClassSpecific"..cur_specific).ispell = tab.ispell; getglobal(prefix.."ClassSpecific"..cur_specific).from = tab.From; getglobal(prefix.."ClassSpecific"..cur_specific).me = nil; cur_specific = cur_specific + 1; under_Cooldown[spell] = true; end end -- Cooldown owner status for spell,cdinfos in healer.Cooldown do if(HA_Cooldown[cdinfos.ispell]) then if(cur_specific > MAX_COOLDOWN_SPELLS) then break; end if(under_Cooldown[spell] == nil) -- I'm not under a Cooldown spell myself, show my Cooldown status then if(cdinfos.Remain > 0 or isdead) -- Still in cooldown, or dead then getglobal(prefix.."ClassSpecific"..cur_specific):SetAlpha(_HA_CurrentWindowAlpha/5); else getglobal(prefix.."ClassSpecific"..cur_specific):SetAlpha(_HA_CurrentWindowAlpha); end getglobal(prefix.."ClassSpecific"..cur_specific.."Texture"):SetVertexColor(1,1,1); getglobal(prefix.."ClassSpecific"..cur_specific.."Texture"):SetTexture(HA_Cooldown[cdinfos.ispell].texture); getglobal(prefix.."ClassSpecific"..cur_specific):Show(); getglobal(prefix.."ClassSpecific"..cur_specific).cooldown = cdinfos.Remain; getglobal(prefix.."ClassSpecific"..cur_specific).spell = spell; getglobal(prefix.."ClassSpecific"..cur_specific).ispell = cdinfos.ispell; getglobal(prefix.."ClassSpecific"..cur_specific).me = healer.Name; getglobal(prefix.."ClassSpecific"..cur_specific).isdead = isdead; cur_specific = cur_specific + 1; end end end for k=cur_specific,MAX_COOLDOWN_SPELLS do getglobal(prefix.."ClassSpecific"..k):Hide(); end button:Show(); else button.infos = nil; button:Hide(); end i = i + 1; end FauxScrollFrame_Update(HAItemScrollFrame, size, healerslines, 1); -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnEvent) then pl.OnEvent(HA_EVENT_GUI_UPDATED_HEALERS); end end end function HA_UpdateListEmergency() local list = HA_GetListEmergency(); if(not HealersAssistMainFrame:IsVisible()) then return; end local size = table.getn(list); local healer = HA_MyselfHealer; local raider; for i,infos in list do local prefix = "HAItemEmergency_"..i; local button = getglobal(prefix); raider = infos.raider; if(raider) then local colors = RAID_CLASS_COLORS[raider.class]; if(colors) then getglobal(prefix.."Name"):SetTextColor(colors.r, colors.g, colors.b); end getglobal(prefix.."Name"):SetText(raider.name); if(raider.subgrp == 0) -- Current Target then getglobal(prefix.."HPBarText"):SetText(raider.percent.."%"); else getglobal(prefix.."HPBarText"):SetText("-"..tostring(infos.deficit)); end if(healer and healer.State == HA_STATE_CASTING and healer.TargetName == raider.name) then getglobal(prefix.."HPBarText"):SetVertexColor(0.4, 0.4, 1.0, 0.9); else getglobal(prefix.."HPBarText"):SetVertexColor(1.0, 1.0, 1.0, 0.9); end getglobal(prefix.."HPBar"):SetValue(tostring(raider.percent)); getglobal(prefix.."Count"):SetText(tostring(raider.count)); if(infos.total == 0) then getglobal(prefix.."Total"):SetText("-"); else getglobal(prefix.."Total"):SetText(tostring(infos.total)); end -- Update overtime local pos = 1; for spell,tab in raider.overtime do if(HA_Cooldown[tab.ispell] == nil) -- Don't show cooldown spells then if(HA_InstantSpells[spell] and HA_SpellOvertime[tab.ispell]) -- A changer, on accede direct sans le iname coté serveur then getglobal(prefix.."Overtime"..pos.."Texture"):SetTexture(HA_SpellOvertime[tab.ispell].texture); getglobal(prefix.."Overtime"..pos):Show(); -- Break if too many spells pos = pos + 1; if(pos > MAX_OVERTIME_SPELLS) then break; end end end end for k=pos,MAX_OVERTIME_SPELLS do getglobal(prefix.."Overtime"..k):Hide(); end button.infos = raider; button.unitid = raider.id; button:Show(); else button.infos = nil; button.unitid = nil; button:Hide(); end end -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnEvent) then pl.OnEvent(HA_EVENT_GUI_UPDATED_EMERGENCY); end end end function HA_RequestSpell(SpellName) local request_name = nil; local spell_code = HA_GetSpellCode(SpellName); local spell_class = HA_GetSpellClass(spell_code); if(HA_Cooldown[spell_code] == nil or not HA_Cooldown[spell_code].can_request) then HA_ChatPrint(string.format(HA_GUI_REQUEST_SEARCH_INVALID_SPELL,SpellName)); return; end for name,healer in HA_Healers do if(not healer.isdead and healer.Raider and spell_class == healer.Raider.class) then for spell,cdinfos in healer.Cooldown do if(cdinfos.ispell == spell_code and cdinfos.Remain == 0) -- Found somebody then request_name = name; -- Store the name to fallback in case nobody in range if(CheckInteractDistance(healer.id,4) and UnitPowerType(healer.id) == 0) -- In range and not a druid in feral form, stop checking then break; end end end end end if(request_name) -- Found someone then HA_COM_SpellRequest(spell_code,request_name); HA_ChatPrint(string.format(HA_GUI_REQUEST_SEARCH_OK,SpellName,request_name)); else HA_ChatPrint(string.format(HA_GUI_REQUEST_SEARCH_FAILED,SpellName)); end end function HA_GUI_ClassSpecificTooltip(spell,from,cooldown) GameTooltip:SetOwner(this, "ANCHOR_RIGHT"); GameTooltip:ClearLines(); if(cooldown == nil) -- Receiver then GameTooltip:AddLine(string.format(HA_GUI_TOOLTIP_GOT_SPELL,spell,from)); else if(cooldown == 0) then GameTooltip:AddLine(string.format(HA_GUI_TOOLTIP_READY,spell)); else GameTooltip:AddLine(string.format(HA_GUI_TOOLTIP_COOLDOWN,spell)); GameTooltip:AddLine(_HA_ConvertToMinSec(floor(cooldown))); end end GameTooltip:Show(); end function HA_GUI_ClassSpecificClick(SpellCode,PlayerName,cooldown) if(cooldown == nil or cooldown ~= 0 or PlayerName == nil or HA_Cooldown[SpellCode] == nil or not HA_Cooldown[SpellCode].can_request) -- Under this spell, or spell not ready, or spell cannot be requested then return; end local SpellName = HA_GetLocalName(SpellCode); local spellinfos = HA_Spells[SpellName]; if(spellinfos == nil) then spellinfos = HA_InstantSpells[SpellName]; end if(spellinfos) then if(UnitIsDeadOrGhost("player") and not spellinfos.rez) -- I'm dead then HA_ChatPrint(HA_GUI_REQUEST_YOU_ARE_DEAD); return; elseif(not UnitIsDeadOrGhost("player") and spellinfos.rez) -- Not dead then HA_ChatPrint(HA_GUI_REQUEST_NOT_DEAD_YET); return; end end if(PlayerName == HA_PlayerName) then HA_GUI_Process_SpellRequest(PlayerName,SpellCode); else HA_COM_SpellRequest(SpellCode,PlayerName); end end StaticPopupDialogs["HA_REQUEST_FOR_SPELL"] = { text = TEXT(""), button1 = TEXT(OKAY), button2 = TEXT(CANCEL), OnShow = function() local TargetName = HA_SpellRequest.target; local SpellName = HA_SpellRequest.spell; HA_ChatDebug(HA_DEBUG_ACTIONS,"StaticPopup : SpellRequest show for "..tostring(HA_SpellRequest.spell)); if(SpellName) then if(HA_SpellRequest.failure) then getglobal(this:GetName().."Text"):SetText(format(HA_GUI_POPUP_REQUEST_FOR_SPELL_WITH_FAILURE,TargetName,SpellName,HA_SpellRequest.failure)); else getglobal(this:GetName().."Text"):SetText(format(HA_GUI_POPUP_REQUEST_FOR_SPELL,TargetName,SpellName)); end else getglobal(this:GetName().."Text"):SetText("HealersAssist Spell Request Error !\nPlease inform kiki."); end if(_HA_UnitInRange(HA_SpellRequest.id,HA_SpellRequest.ispell)) then getglobal(this:GetName().."Button1"):Enable(); HA_SpellRequest.WasEnabled = true; else getglobal(this:GetName().."Button1"):Disable(); HA_SpellRequest.WasEnabled = false; end HA_SpellRequest.LastTime = HA_CurrentTime; this.FirstUpdate = true; end, OnUpdate = function() if(this.FirstUpdate) then local bb = getglobal(this:GetName().."Button1"); this:SetHeight(this:GetTop() - bb:GetBottom() + 20); this.FirstUpdate = nil; end if(HA_SpellRequest and HA_SpellRequest.LastTime and (HA_CurrentTime > (HA_SpellRequest.LastTime+0.2))) then HA_SpellRequest.LastTime = HA_CurrentTime; if(this and getglobal(this:GetName().."Button1")) then local new_state = _HA_UnitInRange(HA_SpellRequest.id,HA_SpellRequest.ispell); if(new_state ~= HA_SpellRequest.WasEnabled) then if(new_state) then getglobal(this:GetName().."Button1"):Enable(); else getglobal(this:GetName().."Button1"):Disable(); end HA_SpellRequest.WasEnabled = new_state; end end end end, OnAccept = function() if(HA_SpellRequest) then local TargetName = HA_SpellRequest.target; local unitid = HA_SpellRequest.id; local SpellName = HA_GetLocalName(HA_SpellRequest.ispell); if(SpellName) then HA_ChatDebug(HA_DEBUG_ACTIONS,"StaticPopup : SpellRequest accepted for "..tostring(HA_SpellRequest.spell)); if(not HA_Cooldown[HA_SpellRequest.ispell].norange) then TargetUnit(unitid); end SpellStopCasting(); HA_SpellTargetName = TargetName; CastSpellByName(SpellName); end end end, OnCancel = function() if(HA_SpellRequest) then local TargetName = HA_SpellRequest.target; local SpellCode = HA_SpellRequest.ispell; HA_ChatDebug(HA_DEBUG_ACTIONS,"StaticPopup : SpellRequest denied for "..tostring(HA_SpellRequest.spell).." : "..tostring(HA_SpellRequest.failure)); HA_COM_SpellRequestDenied(SpellCode,TargetName,HA_SPELL_REQUEST_CODE_DENIED_DENIED); end HA_SpellRequest = nil; end, OnHide = function() if(HA_SpellRequest ~= nil) then StaticPopup_Show("HA_REQUEST_FOR_SPELL"); end end, whileDead = 0, hideOnEscape = 1, timeout = 0 }; function HA_SetRegenMode(state) local healer = HA_MyselfHealer; if(healer) then if(state) then healer.NextResetState = HA_STATE_RESTING; HA_COM_RegenMode(true); HealersAssistMainFrameSetResting:SetChecked(1); if(healer.State == HA_STATE_NOTHING) -- Was doing nothing, change the state now then _HA_ResetHealerState(healer,false); end else healer.NextResetState = nil; if(healer.State == HA_STATE_RESTING) -- Was already in regen state, reset the state then _HA_ResetHealerState(healer,false); end HA_COM_RegenMode(false); HealersAssistMainFrameSetResting:SetChecked(0); end end end --------------- Process functions --------------- --[[ HA_GUI_Process_SpellStart function : - From : String -- Source player - SpellCode : Int -- International Spell Code (use HA_GetLocalName to get local name) - TargetName : String -- Target of the heal - CastTime : Int -- Casttime of the spell - Estimated : Int -- Estimated spell value (can be 0) - WillCrit : Bool -- If you are sure the spell will crit (Estimated is crit value) - SpellRank : Int -- Rank of the spell (can be 0) ]] function HA_GUI_Process_SpellStart(From,SpellCode,TargetName,CastTime,Estimated,WillCrit,SpellRank) local SpellName = HA_GetLocalName(SpellCode); local healer = HA_Healers[From]; if(healer and SpellName) then local spell = HA_Spells[SpellName]; if(spell) then if(SpellRank == nil) then SpellRank = 0; end _HA_ResetHealerState(healer,true); healer.SpellCode = SpellCode; healer.NonHeal = spell.nonheal; healer.SpellName = SpellName; healer.SpellRank = SpellRank; healer.ShortSpellName = spell.short; healer.TargetName = TargetName; healer.Estimate = Estimated; healer.WillCrit = WillCrit; healer.GroupHeal = spell.group; if(CastTime == nil) then HA_ChatWarning("SPELLCAST_START : CastTime is nil : "..tostring(arg2)); healer.CastTime = 1; else healer.CastTime = CastTime / 1000; end healer.StartTime = HA_CurrentTime; local raider = HA_Raiders[TargetName]; if(raider and Estimated ~= 0 and raider.estimates[From] == nil and not spell.group) then raider.count = raider.count + 1; raider.estimates[From] = healer.Estimate; end healer.State = HA_STATE_CASTING; if(raider) then -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnSpellStart) then pl.OnSpellStart(healer,raider,SpellCode,SpellName,CastTime,Estimated,WillCrit,SpellRank); end end end HA_ChatDebug(HA_DEBUG_SPELLS,"SpellStart from "..From.." to "..tostring(TargetName).." with "..SpellName.." ("..tostring(SpellRank)..") for "..tostring(CastTime)); end end end --[[ HA_GUI_Process_SpellStop function : - From : String -- Source player ]] function HA_GUI_Process_SpellStop(From) local healer = HA_Healers[From]; if(healer) then -- Remove estimate value _HA_ResetHealerEstimate(healer); -- Set STOP state healer.EndTime = HA_CurrentTime + HA_Config.KeepValue; healer.State = HA_STATE_STOP; if(healer.CastTime == nil) then healer.CastTime = 1; end HA_ChatDebug(HA_DEBUG_SPELLS,"SpellStop from "..From); end end --[[ HA_GUI_Process_SpellHit function : - From : String -- Source player - SpellCode : Int -- International Spell Code (use HA_GetLocalName to get local name) - TargetName : String -- Target of the heal - Value : Int -- Healed value - Crit : Bool -- Heal has crit ]] function HA_GUI_Process_SpellHit(From,SpellCode,TargetName,Value,Crit) local SpellName = HA_GetLocalName(SpellCode); local healer = HA_Healers[From]; local spell = HA_Spells[SpellName]; local raider = HA_Raiders[TargetName]; if(healer) then if(spell) -- Casted spell then _HA_Process_SpellHit(healer,SpellCode,SpellName,raider,Value,Crit,false); elseif(HA_InstantSpells[SpellName]) then _HA_Process_SpellHit(healer,SpellCode,SpellName,raider,Value,Crit,true); end end end --[[ HA_GUI_Process_SpellFailed function : - From : String -- Source player - SpellCode : Int -- International Spell Code (use HA_GetLocalName to get local name) - IReason : Int -- Reason code of failure - Reason : String -- Reason text of failure (nil if IReason ~= 0) ]] function HA_GUI_Process_SpellFailed(From,SpellCode,IReason,Reason) local SpellName = HA_GetLocalName(SpellCode); local healer = HA_Healers[From]; local spell = HA_Spells[SpellName]; if(healer and spell) then if(IReason ~= 0) then if(IReason == HA_SPELL_FAILED_OUT_OF_SIGHT) then Reason = HA_FAILED_TEXT_OUT_OF_SIGHT; elseif(IReason == HA_SPELL_FAILED_OUT_OF_RANGE) then Reason = HA_FAILED_TEXT_TOO_FAR; elseif(IReason == HA_SPELL_FAILED_TARGET_DIED) then Reason = HA_FAILED_TEXT_DEAD; else Reason = HA_GetLocalReason(IReason); end end local raider = HA_Raiders[healer.TargetName]; if(raider) then -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnSpellFailed) then pl.OnSpellFailed(healer,raider,SpellCode,IReason,Reason); end end end -- Set failed mode, if not currently casting if(healer.State == HA_STATE_STOP) then healer.State = HA_STATE_FAILED; healer.EndTime = HA_CurrentTime + HA_Config.KeepValue; healer.Reason = Reason; end HA_ChatDebug(HA_DEBUG_SPELLS,"SpellFailed from "..healer.Name.." with "..tostring(SpellName).." : "..Reason); end end --[[ HA_GUI_Process_SpellDelayed function : - From : String -- Source player - Value : Int -- Delayed value in msec ]] function HA_GUI_Process_SpellDelayed(From,Value) local healer = HA_Healers[From]; if(healer) then if(healer.State == HA_STATE_CASTING) then healer.StartTime = healer.StartTime + Value/1000; -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnSpellDelayed) then pl.OnSpellDelayed(healer,Value); end end HA_ChatDebug(HA_DEBUG_SPELLS,"SpellDelayed from "..From.." for "..Value); end end end --[[ HA_GUI_Process_SpellCooldown function : - From : String -- Source player - SpellCode : Int -- International Spell Code (use HA_GetLocalName to get local name) - TargetName : String -- Target ]] function HA_GUI_Process_SpellCooldown(From,SpellCode,TargetName) local SpellName = HA_GetLocalName(SpellCode); local healer = HA_Healers[From]; if(healer and SpellName) then local raider = HA_Raiders[TargetName]; if(raider) then if(SpellCode == HA_SPELL_INNERVATE) -- Druid's Innervate then raider.overtime[HA_INNERVATE] = { From = healer.Name; Start = GetTime(); Duration = 20; ispell = SpellCode }; if(raider.name == HA_PlayerName and healer.Name ~= HA_PlayerName) then HA_ChatPrint(HA_CHAT_MSG_INNERVATED); PlaySoundFile("Sound\\interface\\levelup2.wav"); end elseif(SpellCode == HA_SPELL_BLESSING_OF_PROTECTION) -- Paladin's BoP then raider.overtime[HA_BLESSING_OF_PROTECTION] = { From = healer.Name; Start = GetTime(); Duration = 10; ispell = SpellCode }; elseif(SpellCode == HA_SPELL_DIVINE_INTERVENTION) -- Paladin's Divine Intervention then raider.overtime[HA_DIVINE_INTERVENTION] = { From = healer.Name; Start = GetTime(); Duration = 180; ispell = SpellCode }; elseif(SpellCode == HA_SPELL_POWER_INFUSION) -- Priest's Power Infusion then if(HA_RaiderInfused(TargetName)) then raider.overtime[HA_POWER_INFUSION].From = healer.Name; else raider.overtime[HA_POWER_INFUSION] = { From = healer.Name; Start = GetTime(); Duration = 15; ispell = SpellCode }; if(raider.name == HA_PlayerName and healer.Name ~= HA_PlayerName) then HA_ChatPrint(HA_CHAT_MSG_INFUSED); PlaySoundFile("Sound\\Doodad\\HornGoober.wav"); end end end -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnSpellCooldown) then pl.OnSpellCooldown(healer,raider,SpellCode,SpellName); end end HA_ChatDebug(HA_DEBUG_SPELLS,"SpellCooldown "..SpellName.." from "..healer.Name.." to "..tostring(raider.name)); end end end --[[ HA_GUI_Process_CooldownUpdate function : - From : String -- Source player - SpellCode : Int -- International Spell Code (use HA_GetLocalName to get local name) - Cooldown : Int -- Cooldown in sec (0 = up) ]] function HA_GUI_Process_CooldownUpdate(From,SpellCode,Cooldown) local SpellName = HA_GetLocalName(SpellCode); local healer = HA_Healers[From]; if(healer and SpellName and HA_Cooldown[SpellCode]) then healer.Cooldown[SpellName] = { Start = GetTime(); Remain = Cooldown; ispell = SpellCode }; -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnCooldownUpdate) then pl.OnCooldownUpdate(healer,SpellCode,SpellName,Cooldown); end end HA_ChatDebug(HA_DEBUG_SPELLS,SpellName.." cooldown of "..From.." is "..Cooldown); end end --[[ HA_GUI_Process_SpellOvertime function : - From : String -- Source player - SpellCode : Int -- International Spell Code (use HA_GetLocalName to get local name) - TargetName : String -- Target of the heal - Duration : Int -- Duration over time - Estimated : Int -- Estimated spell value (can be 0) - SpellRank : Int -- Rank of the spell (can be 0) ]] function HA_GUI_Process_SpellOvertime(From,SpellCode,TargetName,Duration,Estimated,SpellRank) local SpellName = HA_GetLocalName(SpellCode); local healer = HA_Healers[From]; if(healer and SpellName) then if(HA_InstantSpells[SpellName]) then if(SpellRank == nil) then SpellRank = 0; end local raider = HA_Raiders[TargetName]; if(raider and HA_SpellOvertime[HA_InstantSpells[SpellName].iname]) then raider.overtime[SpellName] = { From = From; Start = GetTime(); Duration = Duration; ispell = SpellCode; Estimated = Estimated }; _HA_Process_SpellHitInstant(healer,raider,SpellCode,SpellName,Duration,Estimated,SpellRank); end HA_ChatDebug(HA_DEBUG_SPELLS,"SpellOvertime from "..From.." to "..tostring(TargetName).." with "..SpellName.." ("..tostring(SpellRank)..") for "..Duration.." secondes (Estimated "..Estimated..")"); end end end --[[ HA_GUI_Process_SpellInstant function : - From : String -- Source player - SpellCode : Int -- International Spell Code (use HA_GetLocalName to get local name) - TargetName : String -- Target of the spell - SpellRank : Int -- Rank of the spell (can be 0) ]] function HA_GUI_Process_SpellInstant(From,SpellCode,TargetName,SpellRank) local SpellName = HA_GetLocalName(SpellCode); local healer = HA_Healers[From]; if(healer and SpellName) then if(HA_InstantSpells[SpellName]) then if(SpellRank == nil) then SpellRank = 0; end local raider = HA_Raiders[TargetName]; if(raider) then _HA_Process_SpellHitInstant(healer,raider,SpellCode,SpellName,0,0,SpellRank); if(HA_SpellOvertime[HA_InstantSpells[SpellName].iname]) -- Is it a spell over time ? then raider.overtime[SpellName] = { From = From; Start = GetTime(); Duration = HA_SpellOvertime[HA_InstantSpells[SpellName].iname].duration; ispell = SpellCode }; end end HA_ChatDebug(HA_DEBUG_SPELLS,"SpellInstant from "..From.." to "..tostring(TargetName).." with "..SpellName.." ("..tostring(SpellRank)..")"); end end end --[[ HA_GUI_Process_SpellRequest function : - From : String -- Source player - SpellCode : Int -- International Spell Code (use HA_GetLocalName to get local name) ]] function HA_GUI_Process_SpellRequest(From,SpellCode) local SpellName = HA_GetLocalName(SpellCode); if(SpellName and HA_Raiders[From]) then HA_ChatDebug(HA_DEBUG_SPELLS,"HA_GUI_Process_SpellRequest from "..From.." for "..SpellName); if(HA_Config.AllowSpellRequest[SpellName] and HA_SpellRequest == nil) -- I allow this spell to be auto-casted, and I'm not currently under a request then HA_SpellRequest = { spell=SpellName; ispell=SpellCode; target=From; id=HA_Raiders[From].id }; StaticPopup_Show("HA_REQUEST_FOR_SPELL"); else if(HA_Config.AllowSpellRequest[SpellName] == nil) then HA_ChatDebug(HA_DEBUG_SPELLS,"HA_GUI_Process_SpellRequest : Automatically denying request !"); HA_COM_SpellRequestDenied(SpellCode,From,HA_SPELL_REQUEST_CODE_DENIED_BLOCKED); else HA_ChatDebug(HA_DEBUG_SPELLS,"HA_GUI_Process_SpellRequest : Denying request, already got one !"); HA_COM_SpellRequestDenied(SpellCode,From,HA_SPELL_REQUEST_CODE_DENIED_BUSY); end end end end --[[ HA_GUI_Process_SpellRequestDenied function : - From : String -- Source player - SpellCode : Int -- International Spell Code (use HA_GetLocalName to get local name) - ReasonCode : Int -- Reason ]] function HA_GUI_Process_SpellRequestDenied(From,SpellCode,ReasonCode) local SpellName = HA_GetLocalName(SpellCode); if(SpellName) then HA_ChatDebug(HA_DEBUG_SPELLS,"HA_GUI_Process_SpellRequestDenied from "..From.." for "..SpellName); HA_ChatPrint(string.format(HA_SpellRequestDenied[ReasonCode],SpellName,From)); end end --[[ HA_GUI_Process_RegenMode function : - From : String -- Source player - IsInRegen : Bool -- If I go in regen mode ]] function HA_GUI_Process_RegenMode(From,IsInRegen) local healer = HA_Healers[From]; if(healer and HA_Raiders[From]) then if(IsInRegen) then healer.NextResetState = HA_STATE_RESTING; if(HA_Config.NotifyRegen) then HA_ChatPrint(string.format(HA_CHAT_MSG_IN_REGEN,From)); end if(healer.State == HA_STATE_NOTHING) -- Was doing nothing, change the state now then _HA_ResetHealerState(healer,false); end else healer.NextResetState = nil; if(healer.State == HA_STATE_RESTING) -- Was already in regen state, reset the state then _HA_ResetHealerState(healer,false); end if(HA_Config.NotifyRegen) then HA_ChatPrint(string.format(HA_CHAT_MSG_OUT_OF_REGEN,From)); end end HA_ChatDebug(HA_DEBUG_SPELLS,"HA_GUI_Process_RegenMode from "..From.." : "..tostring(IsInRegen)); end end --[[ HA_GUI_Process_GotPowerInfusion function : - From : String -- Source player ]] function HA_GUI_Process_GotPowerInfusion(From) local raider = HA_Raiders[From]; if(raider) then if(not HA_RaiderInfused(From)) then raider.overtime[HA_POWER_INFUSION] = { From = "???"; Start = GetTime(); Duration = 15; ispell = HA_SPELL_POWER_INFUSION }; if(From == HA_PlayerName) then HA_ChatPrint(HA_CHAT_MSG_INFUSED); PlaySoundFile("Sound\\Doodad\\HornGoober.wav"); end HA_ChatDebug(HA_DEBUG_SPELLS,"HA_GUI_Process_GotPowerInfusion : Processing since I didn't get the SpellCooldown message yet"); end end end --[[ HA_GUI_Process_Announce function : - From : String -- Source player - Message : String -- Message to show ]] function HA_GUI_Process_Announce(From,Message) local raider = HA_Raiders[From]; if(raider) then RaidWarningFrame:AddMessage("[HA] "..Message, 0.2, 0.8, 0.2, 1.0); DEFAULT_CHAT_FRAME:AddMessage("[HA Warning] "..From..": "..Message, 0.2, 0.8, 0.2, 1.0); PlaySound("RaidWarning"); end end --[[ HA_GUI_Process_Version function : - From : String -- Source player - Version : String -- Player's HA Version ]] function HA_GUI_Process_Version(From,Version) local raider = HA_Raiders[From]; if(raider) then raider.Version = Version; end if(_HA_NewVersionNotice == false and Version > HA_VERSION) then _HA_NewVersionNotice = true; HA_ChatPrint(HA_TEXT_MINOR_VERSION); end end --[[ HA_GUI_Process_SpellHotTick function : - From : String -- Source player - SpellCode : Int -- International Spell Code (use HA_GetLocalName to get local name) - TargetName : String -- Target of the heal - Value : Int -- Healed value ]] function HA_GUI_Process_SpellHotTick(From,SpellCode,TargetName,Value) local SpellName = HA_GetLocalName(SpellCode); local healer = HA_Healers[From]; local spell = HA_InstantSpells[SpellName]; if(healer and spell) then HA_ChatDebug(HA_DEBUG_SPELLS,"SpellHotTick from "..From.." to "..TargetName.." with "..SpellName.." for "..tostring(Value).." hp."); local raider = HA_Raiders[TargetName]; if(raider) then -- Check overhealed status local new_hp = _HA_GetRaiderHealthBeforeHeal(raider,Value,healer) + Value; local overhealed = 0; if(new_hp > raider.hpmax) then overhealed = new_hp - raider.hpmax; end -- Call plugins for n,pl in HA_ActivePlugins do if(pl.OnSpellHotTick) then pl.OnSpellHotTick(healer,raider,SpellCode,SpellName,Value,overhealed); end end end end end