vanilla-wow-addons – Rev 1
?pathlinks?
--[[
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