e109bf4bfd
Totemic recall needs to reset totem timers.
1203 lines
36 KiB
Lua
1203 lines
36 KiB
Lua
--[[
|
|
|
|
CALL OF ELEMENTS
|
|
The All-In-One Shaman Addon
|
|
|
|
by Wyverex (2006)
|
|
|
|
|
|
Totem Module / Logical
|
|
|
|
]]
|
|
|
|
if( not COE_Totem ) then
|
|
COE_Totem = {};
|
|
end
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
stores the original functions hooked by SetupTimerHooks()
|
|
-------------------------------------------------------------------]]
|
|
COE_Totem["TimerHooks"] = {};
|
|
|
|
|
|
--[[ =============================================================================================
|
|
|
|
L O G I C
|
|
|
|
================================================================================================]]
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:Rescan
|
|
|
|
PURPOSE: Scans the totems and totem sets
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:Rescan()
|
|
COE:ScanTotems();
|
|
COE:InitTotemSets();
|
|
|
|
-- Reset all active totems
|
|
-- ------------------------
|
|
COE_Totem:ResetTimers();
|
|
|
|
COE.ActiveTotems.Earth = nil;
|
|
COE.ActiveTotems.Fire = nil;
|
|
COE.ActiveTotems.Water = nil;
|
|
COE.ActiveTotems.Air = nil;
|
|
|
|
COE_Totem:UpdateAllFrames();
|
|
COETotemFrame.Reconfigure = true;
|
|
end
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:ThrowTotem
|
|
|
|
PURPOSE: Throws the totem with the specified named id
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:ThrowTotem( element, id )
|
|
|
|
if( not COE.Initialized ) then
|
|
return;
|
|
end
|
|
|
|
-- get associated button
|
|
-- ----------------------
|
|
local button = getglobal( "COETotem" .. element .. id );
|
|
if( button == nil ) then
|
|
COE:Message( "Invalid Totem" );
|
|
return;
|
|
end
|
|
|
|
local totem = button.totem;
|
|
if( totem == nil ) then
|
|
COE:Message( COESTR_NOTOTEM );
|
|
return;
|
|
end
|
|
|
|
-- throw totem
|
|
-- ------------
|
|
CastSpellByName( totem.SpellName );
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:RankModifierDown
|
|
|
|
PURPOSE: Returns if the rank 1 modifier is currently pressed
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:RankModifierDown()
|
|
|
|
local overridekey = COE_Config:GetSaved( COEOPT_OVERRIDERANK );
|
|
|
|
-- check if the override key is down
|
|
-- ----------------------------------
|
|
if( overridekey == COEMODE_OVERRIDESHIFT and IsShiftKeyDown() ) then
|
|
return true;
|
|
|
|
elseif( overridekey == COEMODE_OVERRIDEALT and IsAltKeyDown() ) then
|
|
return true;
|
|
|
|
elseif( overridekey == COEMODE_OVERRIDECTRL and IsControlKeyDown() ) then
|
|
return true;
|
|
end
|
|
|
|
return false;
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COESched_AdviseTotem
|
|
|
|
PURPOSE: If the totem warning is still active, a notification
|
|
is displayed and the function rescheduled
|
|
-------------------------------------------------------------------]]
|
|
function COESched_AdviseTotem( totem, msg )
|
|
|
|
if( COE_Config:GetSaved( COEOPT_ADVISOR ) == 1 and totem.Warn ) then
|
|
-- issue warning
|
|
-- --------------
|
|
COE:Notification( string.format( COESTR_CLEANSINGTOTEM, msg ), COECOL_TOTEMCLEANSING );
|
|
|
|
-- reschedule
|
|
-- -----------
|
|
Chronos.scheduleByName( "COEAdvise" .. msg, COE.AdvisorWarningInterval, COESched_AdviseTotem, totem, msg );
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COESched_RunAdvisor
|
|
|
|
PURPOSE: Scans the party/raid for debuffs that are curable by
|
|
totems and shows a notification if it finds such
|
|
-------------------------------------------------------------------]]
|
|
function COESched_RunAdvisor()
|
|
|
|
-- advisor still activated?
|
|
-- -------------------------
|
|
if( COE_Config:GetSaved( COEOPT_ADVISOR ) == 0 ) then
|
|
return;
|
|
end
|
|
|
|
local warnPoison, warnDisease, warnTremor = false, false, false;
|
|
local poison, disease, tremor;
|
|
|
|
-- scan player first
|
|
-- ------------------
|
|
poison, disease, tremor = COE_Totem:ScanTargetForDebuff( "player" );
|
|
|
|
warnPoison = warnPoison or poison;
|
|
warnDisease = warnDisease or disease;
|
|
warnTremor = warnTremor or tremor;
|
|
|
|
-- scan party
|
|
-- -----------
|
|
local i;
|
|
for i = 1, GetNumPartyMembers() do
|
|
if( warnPoison and warnDisease and warnTremor ) then
|
|
break;
|
|
end
|
|
|
|
-- scan party member
|
|
-- ------------------
|
|
poison, disease, tremor = COE_Totem:ScanTargetForDebuff( "party" .. i );
|
|
|
|
warnPoison = warnPoison or poison;
|
|
warnDisease = warnDisease or disease;
|
|
warnTremor = warnTremor or tremor;
|
|
|
|
-- scan party member's pet
|
|
-- ------------------------
|
|
if( UnitExists( "partypet" .. i ) ) then
|
|
poison, disease, tremor = COE_Totem:ScanTargetForDebuff( "partypet" .. i );
|
|
|
|
warnPoison = warnPoison or poison;
|
|
warnDisease = warnDisease or disease;
|
|
warnTremor = warnTremor or tremor;
|
|
end
|
|
end
|
|
|
|
-- issue warnings if necessary
|
|
-- ----------------------------
|
|
if( warnTremor and COE.CleansingTotems.Tremor.Totem and
|
|
(COE.ActiveTotems["Earth"] ~= COE.CleansingTotems.Tremor.Totem or
|
|
not COE_Totem:IsTimerActive( COE.ActiveTotems["Earth"] )) ) then
|
|
|
|
if( not COE.CleansingTotems.Tremor.Warn ) then
|
|
COE.CleansingTotems.Tremor.Warn = true;
|
|
COESched_AdviseTotem( COE.CleansingTotems.Tremor, COESTR_TOTEMTREMOR );
|
|
end
|
|
else
|
|
COE.CleansingTotems.Tremor.Warn = false;
|
|
end
|
|
|
|
if( warnDisease and COE.CleansingTotems.Disease.Totem and
|
|
(COE.ActiveTotems["Water"] ~= COE.CleansingTotems.Disease.Totem or
|
|
not COE_Totem:IsTimerActive( COE.ActiveTotems["Water"] )) ) then
|
|
|
|
if( not COE.CleansingTotems.Disease.Warn ) then
|
|
COE.CleansingTotems.Disease.Warn = true;
|
|
COESched_AdviseTotem( COE.CleansingTotems.Disease, COESTR_TOTEMDISEASE );
|
|
end
|
|
else
|
|
COE.CleansingTotems.Disease.Warn = false;
|
|
end
|
|
|
|
if( warnPoison and COE.CleansingTotems.Poison.Totem and
|
|
(COE.ActiveTotems["Water"] ~= COE.CleansingTotems.Poison.Totem or
|
|
not COE_Totem:IsTimerActive( COE.ActiveTotems["Water"] )) ) then
|
|
|
|
if( not COE.CleansingTotems.Poison.Warn ) then
|
|
COE.CleansingTotems.Poison.Warn = true;
|
|
COESched_AdviseTotem( COE.CleansingTotems.Poison, COESTR_TOTEMPOISON );
|
|
end
|
|
else
|
|
COE.CleansingTotems.Poison.Warn = false;
|
|
end
|
|
|
|
-- reschedule
|
|
-- -----------
|
|
Chronos.scheduleByName( "COEAdvise", COE.AdvisorInterval, COESched_RunAdvisor );
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:ScanTargetForDebuff
|
|
|
|
PURPOSE: Scans the specified target for debuffs that are
|
|
curable by totems
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:ScanTargetForDebuff( target )
|
|
|
|
local slot = 1;
|
|
local poison, disease, tremor = false, false, false;
|
|
|
|
-- iterate over all possible 16 debuff slots
|
|
-- ------------------------------------------
|
|
COETotemTTTextLeft1:SetText( "" );
|
|
COETotemTTTextRight1:SetText( "" );
|
|
COETotemTT:SetUnitDebuff( target, slot );
|
|
|
|
local debufftype = COETotemTTTextRight1:GetText();
|
|
local debuffname = COETotemTTTextLeft1:GetText();
|
|
|
|
while( debuffname and slot <= 16 and not(poison and disease and tremor) ) do
|
|
|
|
if( debufftype ) then
|
|
|
|
if( debufftype == COESTR_POISON ) then
|
|
-- it's a poison debuff
|
|
-- ---------------------
|
|
poison = true;
|
|
elseif( debufftype == COESTR_DISEASE ) then
|
|
-- it's a disease debuff
|
|
-- ---------------------
|
|
disease = true;
|
|
else
|
|
-- check if it's a debuff curable
|
|
-- by the tremor totem
|
|
-- -------------------------------
|
|
local debuff;
|
|
for debuff in COESTR_TREMOR do
|
|
if( debuffname == COESTR_TREMOR[debuff] ) then
|
|
tremor = true;
|
|
break
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
slot = slot + 1;
|
|
COETotemTTTextLeft1:SetText( "" );
|
|
COETotemTTTextRight1:SetText( "" );
|
|
COETotemTT:SetUnitDebuff( target, slot );
|
|
|
|
debufftype = COETotemTTTextRight1:GetText();
|
|
debuffname = COETotemTTTextLeft1:GetText();
|
|
end
|
|
|
|
return poison, disease, tremor;
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:ThrowAdvisedTotem
|
|
|
|
PURPOSE: If there is an advised totem waiting to be thrown
|
|
is is done here
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:ThrowAdvisedTotem()
|
|
|
|
if( COE.CleansingTotems.Tremor.Warn and
|
|
(COE.ActiveTotems.Earth ~= COE.CleansingTotems.Tremor.Totem or
|
|
not COE_Totem:IsTimerActive( COE.ActiveTotems["Earth"] )) ) then
|
|
|
|
CastSpellByName( COE.CleansingTotems.Tremor.Totem.SpellName );
|
|
|
|
elseif( COE.CleansingTotems.Disease.Warn and
|
|
(COE.ActiveTotems.Water ~= COE.CleansingTotems.Disease.Totem or
|
|
not COE_Totem:IsTimerActive( COE.ActiveTotems["Water"] )) ) then
|
|
|
|
CastSpellByName( COE.CleansingTotems.Disease.Totem.SpellName );
|
|
|
|
elseif( COE.CleansingTotems.Poison.Warn and
|
|
(COE.ActiveTotems.Water ~= COE.CleansingTotems.Poison.Totem or
|
|
not COE_Totem:IsTimerActive( COE.ActiveTotems["Water"] )) ) then
|
|
|
|
CastSpellByName( COE.CleansingTotems.Poison.Totem.SpellName );
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:IsAdvisedTotem
|
|
|
|
PURPOSE: Returns if the specified totem is an advised totem
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:IsAdvisedTotem( totem )
|
|
|
|
if( (COE.CleansingTotems.Tremor.Warn and totem == COE.CleansingTotems.Tremor.Totem) or
|
|
(COE.CleansingTotems.Disease.Warn and totem == COE.CleansingTotems.Disease.Totem) or
|
|
(COE.CleansingTotems.Poison.Warn and totem == COE.CleansingTotems.Poison.Totem) ) then
|
|
return true;
|
|
else
|
|
return false;
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--[[ =============================================================================================
|
|
|
|
T O T E M - S E T S
|
|
|
|
================================================================================================]]
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:SwitchNamedSet
|
|
|
|
PURPOSE: If there exists a custom set with the name of the
|
|
playertarget and the target is hostile, switch to this set
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:SwitchNamedSet()
|
|
|
|
if( COE_Config:GetSaved( COEOPT_ENABLESETS ) == 1 ) then
|
|
|
|
if( UnitIsEnemy( "player", "target" ) ) then
|
|
|
|
-- iterate over all custom sets
|
|
-- -----------------------------
|
|
local i;
|
|
for i = 1, table.getn( COE_CustomTotemSets ) do
|
|
|
|
if( COE_CustomTotemSets[i].Name == UnitName( "target" ) ) then
|
|
COE_Totem:SwitchToSet( COE_CustomTotemSets[i].Name );
|
|
return true;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return false;
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:SwitchPVPSet
|
|
|
|
PURPOSE: If the playertarget is a hostile player, activate the
|
|
class totem set, else switch back to the last active set
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:SwitchPVPSet()
|
|
|
|
if( COE_Config:GetSaved( COEOPT_ENABLESETS ) == 1 and
|
|
COE_Config:GetSaved( COEOPT_AUTOSWITCH ) == 1 ) then
|
|
|
|
if( UnitIsEnemy( "player", "target" ) ) then
|
|
if( UnitIsPlayer( "target" ) ) then
|
|
-- switch to pvp set
|
|
-- ------------------
|
|
local class = UnitClass( "target" );
|
|
|
|
COE_Totem:SwitchToSet( "[PVP] " .. class );
|
|
|
|
elseif( UnitExists( "target" ) ) then
|
|
-- targeted a mob. switch back to the last set
|
|
-- --------------------------------------------
|
|
if( COE.LastActiveSet ~= nil ) then
|
|
COE_Totem:SwitchToSet( COE.LastActiveSet );
|
|
else
|
|
COE_Totem:SwitchToSet( COEUI_DEFAULTSET );
|
|
end;
|
|
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:SwitchToNextSet
|
|
|
|
PURPOSE: If a pvp set is activated, the default set is activated
|
|
Otherwise the next custom set is activated
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:SwitchToNextSet()
|
|
|
|
if( COE_Config:GetSaved( COEOPT_ENABLESETS ) == 1 ) then
|
|
local activeset = COE_Config:GetSaved( COEOPT_ACTIVESET );
|
|
|
|
if( activeset < COESET_DEFAULT ) then
|
|
-- pvp set is active
|
|
-- switch to default set
|
|
-- ----------------------
|
|
COE_Totem:SwitchToSet( COEUI_DEFAULTSET );
|
|
|
|
elseif( activeset == COE.TotemSetCount ) then
|
|
-- last custom set is active or none available
|
|
-- switch to default set
|
|
-- --------------------------------------------
|
|
COE_Totem:SwitchToSet( COEUI_DEFAULTSET );
|
|
|
|
elseif( activeset == COESET_DEFAULT ) then
|
|
-- default set is active
|
|
-- switch to first custom set
|
|
-- ---------------------------
|
|
COE_Totem:SwitchToSet( COE_CustomTotemSets[1].Name );
|
|
|
|
else
|
|
-- switch to next custom set
|
|
-- --------------------------
|
|
COE_Totem:SwitchToSet( COE_CustomTotemSets[activeset - COESET_DEFAULT + 1].Name );
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:SwitchToPriorSet
|
|
|
|
PURPOSE: If a pvp set is activated, the default set is activated
|
|
Otherwise the next custom set is activated
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:SwitchToPriorSet()
|
|
|
|
if( COE_Config:GetSaved( COEOPT_ENABLESETS ) == 1 ) then
|
|
local activeset = COE_Config:GetSaved( COEOPT_ACTIVESET );
|
|
|
|
if( activeset < COESET_DEFAULT ) then
|
|
-- pvp set is active
|
|
-- switch to default set
|
|
-- ----------------------
|
|
COE_Totem:SwitchToSet( COEUI_DEFAULTSET );
|
|
|
|
elseif( activeset == COESET_DEFAULT ) then
|
|
-- default set is active
|
|
-- switch to last custom set
|
|
-- ---------------------------
|
|
COE_Totem:SwitchToSet( COE_CustomTotemSets[COE.TotemSetCount - COESET_DEFAULT].Name );
|
|
|
|
elseif( activeset == COESET_DEFAULT + 1 ) then
|
|
-- first custom set is active
|
|
-- switch to default set
|
|
-- ---------------------------
|
|
COE_Totem:SwitchToSet( COEUI_DEFAULTSET );
|
|
|
|
else
|
|
-- switch to prior custom set
|
|
-- ---------------------------
|
|
COE_Totem:SwitchToSet( COE_CustomTotemSets[activeset - COESET_DEFAULT - 1].Name );
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:SwitchToSet
|
|
|
|
PURPOSE: Activates the specified totem set
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:SwitchToSet( name )
|
|
|
|
if( COE_Config:GetSaved( COEOPT_ENABLESETS ) == 0 ) then
|
|
return;
|
|
end
|
|
|
|
local pvpset = false;
|
|
|
|
-- check for pvp sets
|
|
-- -------------------
|
|
local i, set;
|
|
for i = 1, table.getn( COE_SavedTotemSets ) do
|
|
if( COE_SavedTotemSets[i].Name == name ) then
|
|
-- set found
|
|
-- ----------
|
|
set = i;
|
|
pvpset = i ~= COESET_DEFAULT;
|
|
break;
|
|
end
|
|
end
|
|
|
|
-- check for custom sets
|
|
-- ----------------------
|
|
if( not set ) then
|
|
for i = 1, table.getn( COE_CustomTotemSets ) do
|
|
if( COE_CustomTotemSets[i].Name == name ) then
|
|
-- set found
|
|
-- ----------
|
|
set = COESET_DEFAULT + i;
|
|
break;
|
|
end
|
|
end
|
|
end
|
|
|
|
if( not set ) then
|
|
return;
|
|
end
|
|
|
|
-- activate set if not already active
|
|
-- chech this to stop notification spamming in a duel
|
|
-- ---------------------------------------------------
|
|
if( COE_Config:GetSaved( COEOPT_ACTIVESET ) ~= set ) then
|
|
COE_Config:ActivateSet( set );
|
|
|
|
if( not pvpset ) then
|
|
COE.LastActiveSet = name;
|
|
end
|
|
|
|
-- reset set cycle
|
|
-- ----------------
|
|
COE_Totem:ResetSetCycle();
|
|
|
|
-- notify player
|
|
-- --------------
|
|
COE:Message( string.format( COESTR_SWITCHTOSET, name ) );
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:ThrowSet
|
|
|
|
PURPOSE: Throws the next totem in the active set that is not
|
|
yet thrown
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:ThrowSet()
|
|
|
|
if( COE_Config:GetSaved( COEOPT_ENABLESETS ) == 1 ) then
|
|
|
|
-- =======================================================================
|
|
-- check which totem to throw
|
|
-- =======================================================================
|
|
local activeset = COE_Config:GetSaved( COEOPT_ACTIVESET );
|
|
|
|
local k;
|
|
for k = 1,4 do
|
|
|
|
local element = COE:LocalizedElement( COE.TotemSets[activeset].CastOrder[k] );
|
|
local totem = COE.TotemSets[activeset][element];
|
|
|
|
if( COE.SetCycle[element] == false and totem ) then
|
|
|
|
if( totem.isTrinket ) then
|
|
|
|
if( totem.TrinketSlot ) then
|
|
-- first check if the trinket is already usable
|
|
-- ---------------------------------------------
|
|
local start, duration = GetInventoryItemCooldown( "player", totem.TrinketSlot );
|
|
|
|
if( start == 0 and duration == 0 ) then
|
|
UseInventoryItem( totem.TrinketSlot );
|
|
return;
|
|
end
|
|
end
|
|
|
|
else
|
|
-- first check if the totem is already usable
|
|
-- -------------------------------------------
|
|
local start, duration = GetSpellCooldown( totem.Ranks[totem.MaxRank].SpellID, BOOKTYPE_SPELL );
|
|
|
|
if( start == 0 and duration == 0 ) then
|
|
CastSpellByName( COE.TotemSets[activeset][element].SpellName );
|
|
return;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:ResetSetCycle
|
|
|
|
PURPOSE: Marks all totems of the current set as not yet thrown
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:ResetSetCycle()
|
|
|
|
COE:Message( COESTR_RESTARTINGSET );
|
|
COE.SetCycle = { Earth = false, Fire = false, Water = false, Air = false };
|
|
|
|
end
|
|
|
|
|
|
--[[ =============================================================================================
|
|
|
|
T I M E R - L O G I C
|
|
|
|
================================================================================================]]
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:SetPendingTotem
|
|
|
|
PURPOSE: Sets up or clears a pending totem
|
|
The pending totem's timer is activated on the next
|
|
successful SPELLCAST_STOP or removed if it times out first
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:SetPendingTotem( totem, rank )
|
|
|
|
if( totem ) then
|
|
COE:DebugMessage( "Setting pending totem: " .. totem.SpellName .. " with rank: " .. rank );
|
|
COE.TotemPending.Totem = totem;
|
|
COE.TotemPending.UseRank = rank;
|
|
|
|
-- get the current lag
|
|
-- --------------------
|
|
local _,_,lag = GetNetStats();
|
|
local timeout = lag / 1000 + COE.TotemPending.Timeout;
|
|
|
|
-- use lag + 0.5 seconds as pending timeout
|
|
-- -----------------------------------------
|
|
COE:DebugMessage( "Setting pending timeout to: " .. timeout .. " msec" );
|
|
|
|
Chronos.scheduleByName( "COE_Pending", timeout, COESched_CheckPendingTotem );
|
|
else
|
|
COE.TotemPending.Totem = nil;
|
|
COE.TotemPending.UseRank = 0;
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COESched_CheckPendingTotem
|
|
|
|
PURPOSE: Clears the pending totem if it is still active
|
|
-------------------------------------------------------------------]]
|
|
function COESched_CheckPendingTotem()
|
|
|
|
-- if there is still a pending totem it has timed out
|
|
-- ---------------------------------------------------
|
|
if( COE.TotemPending.Totem ) then
|
|
COE:DebugMessage( "Pending totem has timed out: " .. COE.TotemPending.Totem.SpellName );
|
|
COE_Totem:SetPendingTotem( nil );
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:ActivatePendingTotem
|
|
|
|
PURPOSE: Activates the pending totem timer and deactivates a
|
|
still active timer of the same element
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:ActivatePendingTotem( totem )
|
|
COE:DebugMessage("Method Executing: ActivatePendingTotem with totem parameter ".. totem.SpellName);
|
|
|
|
-- deactivate still active totem of the same element
|
|
-- --------------------------------------------------
|
|
COE:DebugMessage("Method Executing: ActivatePendingTotem - identifying active totems of type".. COE.TotemPending.Totem.Element);
|
|
local active = COE.ActiveTotems[COE.TotemPending.Totem.Element];
|
|
if( active ) then
|
|
COE_Totem:DeactivateTimer( active );
|
|
end
|
|
|
|
-- activate timer
|
|
-- ---------------
|
|
Chronos.startTimer( "COE" .. totem.SpellName );
|
|
totem.CurDuration = COE.TotemPending.Totem.Ranks[COE.TotemPending.UseRank].Duration;
|
|
totem.CurHealth = COE.TotemPending.Totem.Ranks[COE.TotemPending.UseRank].Health;
|
|
|
|
-- activate cooldown timer if this totem has a cooldown
|
|
-- -----------------------------------------------------
|
|
if( COE.TotemPending.Totem.Ranks[COE.TotemPending.UseRank].Cooldown > 0 ) then
|
|
totem.CurCooldown = COE.TotemPending.Totem.Ranks[COE.TotemPending.UseRank].Cooldown;
|
|
Chronos.startTimer( "COECooldown" .. totem.SpellName );
|
|
Chronos.scheduleByName( "COECooldownSwitch" .. totem.SpellName, totem.CurCooldown, COESched_CooldownEnd, totem );
|
|
end
|
|
|
|
-- activate warning timers
|
|
-- ------------------------
|
|
if( totem.CurDuration >= 10 ) then
|
|
Chronos.scheduleByName( "COEWarn10" .. totem.SpellName, totem.CurDuration - 10, COESched_ExpirationWarning, 10, totem );
|
|
end
|
|
Chronos.scheduleByName( "COEWarn5" .. totem.SpellName, totem.CurDuration - 5, COESched_ExpirationWarning, 5, totem );
|
|
Chronos.scheduleByName( "COEWarn0" .. totem.SpellName, totem.CurDuration, COESched_ExpirationWarning, 0, totem );
|
|
|
|
-- mark totem as active
|
|
-- ---------------------
|
|
COE.ActiveTotems[COE.TotemPending.Totem.Element] = totem;
|
|
totem.isActive = true;
|
|
|
|
-- set totem in timer frame
|
|
-- -------------------------
|
|
if( COE_Config:GetSaved( COEOPT_TIMERFRAME ) == 1 ) then
|
|
getglobal( "COETimer" .. COE.TotemPending.Totem.Element ).totem = totem;
|
|
COETimerFrame:Show();
|
|
end
|
|
|
|
-- mark totem as thrown if in current set
|
|
-- ---------------------------------------
|
|
local activeset = COE_Config:GetSaved( COEOPT_ACTIVESET );
|
|
|
|
if( COE.TotemSets[activeset][totem.Element] and
|
|
COE.TotemSets[activeset][totem.Element].SpellName == totem.SpellName ) then
|
|
|
|
COE:DebugMessage( "Element " .. totem.Element .. " in current cycle: SET" );
|
|
COE.SetCycle[totem.Element] = true;
|
|
end
|
|
|
|
-- clear pending totem
|
|
-- --------------------
|
|
COE_Totem:SetPendingTotem( nil );
|
|
|
|
-- if in timers only mode, reconfigure the totem bar
|
|
-- --------------------------------------------------
|
|
if( COE_Config:GetSaved( COEOPT_DISPLAYMODE ) == COEMODE_TIMERSONLY ) then
|
|
COE_Totem:Invalidate( getglobal( "COE" .. totem.Element .. "Frame" ), true, true, true );
|
|
COETotemFrame.Reconfigure = true;
|
|
else
|
|
-- otherwise just invalidate the dynamic buttons
|
|
-- ----------------------------------------------
|
|
COE_Totem:Invalidate( getglobal( "COE" .. totem.Element .. "Frame" ), false, false, true );
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:DeactivateTimer
|
|
|
|
PURPOSE: Deactivates an active totem timer
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:DeactivateTimer( totem )
|
|
|
|
if( totem and totem.isActive ) then
|
|
|
|
COE:DebugMessage( "Deactivating totem: " .. totem.SpellName );
|
|
|
|
-- end timers
|
|
-- -----------
|
|
Chronos.endTimer( "COE" .. totem.SpellName );
|
|
Chronos.unscheduleByName( "COEWarn10" ..totem.SpellName );
|
|
Chronos.unscheduleByName( "COEWarn5" ..totem.SpellName );
|
|
Chronos.unscheduleByName( "COEWarn0" ..totem.SpellName );
|
|
|
|
-- reset totem data
|
|
-- ------------------
|
|
totem.CurDuration = 0;
|
|
totem.CurHealth = 0;
|
|
totem.isActive = false;
|
|
|
|
-- unset totem in timerframe
|
|
-- --------------------------
|
|
local timer = getglobal( "COETimer" .. totem.Element );
|
|
timer.totem = nil;
|
|
COETimerFrame:StopMovingOrSizing();
|
|
|
|
-- mark totem as unthrown if in current set
|
|
-- -----------------------------------------
|
|
local activeset = COE_Config:GetSaved( COEOPT_ACTIVESET );
|
|
|
|
if( COE.TotemSets[activeset][totem.Element] and
|
|
COE.TotemSets[activeset][totem.Element].SpellName == totem.SpellName ) then
|
|
|
|
COE:DebugMessage( "Element " .. totem.Element .. " in current cycle: UNSET" );
|
|
COE.SetCycle[totem.Element] = false;
|
|
end
|
|
|
|
-- invalidate dynamic buttons
|
|
-- ---------------------------
|
|
COE_Totem:Invalidate( getglobal( "COE" .. totem.Element .. "Frame" ), false, false, true );
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:IsTimerActive
|
|
|
|
PURPOSE: Returns if the specified totem timer is active
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:IsTimerActive( totem )
|
|
|
|
if( not totem ) then
|
|
return false;
|
|
end
|
|
|
|
return (totem.CurDuration > 0) and
|
|
(totem.CurDuration - Chronos.getTimer( "COE" .. totem.SpellName ) > 0);
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:GetTimeLeft
|
|
|
|
PURPOSE: Returns the amount of seconds left on the totem timer
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:GetTimeLeft( totem )
|
|
|
|
if( totem.CurDuration == 0 ) then
|
|
return 0;
|
|
else
|
|
return totem.CurDuration - Chronos.getTimer( "COE" .. totem.SpellName );
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:GetCooldownLeft
|
|
|
|
PURPOSE: Returns the amount of seconds left on the totem cooldown
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:GetCooldownLeft( totem )
|
|
|
|
if( totem.CurCooldown == 0 ) then
|
|
return 0;
|
|
else
|
|
return totem.CurCooldown - Chronos.getTimer( "COECooldown" .. totem.SpellName );
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COESched_ExpirationWarning
|
|
|
|
PURPOSE: Issues an expiration warning for the specified totem
|
|
-------------------------------------------------------------------]]
|
|
function COESched_ExpirationWarning( timemark, totem )
|
|
COE:DebugMessage("Method Executing: COESched_ExpirationWarning with totem parameter ".. totem.SpellName);
|
|
|
|
if( COE_Config:GetSaved( COEOPT_ENABLETOTEMBAR ) == 1 and
|
|
COE_Config:GetSaved( COEOPT_ENABLETIMERS ) == 1 and
|
|
COE_Config:GetSaved( COEOPT_TIMERNOTIFICATIONS ) == 1 ) then
|
|
|
|
local text;
|
|
if( totem.isTrinket ) then
|
|
text = COESTR_TRINKET_TOTEM;
|
|
else
|
|
text = totem.SpellName;
|
|
end
|
|
|
|
if( timemark > 0 ) then
|
|
COE:Notification( string.format( COESTR_TOTEMWARNING, text, timemark ), COECOL_TOTEMWARNING );
|
|
else
|
|
COE:Notification( string.format( COESTR_TOTEMEXPIRED, text ), COECOL_TOTEMDESTROYED );
|
|
COE_Totem:DeactivateTimer( totem );
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COESched_CooldownEnd
|
|
|
|
PURPOSE: Stops the cooldown timer of the totem when the
|
|
cooldown has ended
|
|
-------------------------------------------------------------------]]
|
|
function COESched_CooldownEnd( totem )
|
|
|
|
Chronos.endTimer( "COECooldown" .. totem.SpellName );
|
|
totem.CurCooldown = 0;
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:TotemDamage
|
|
|
|
PURPOSE: Assigns damage to the totem being hit and triggers
|
|
a notification if the totem is destroyed
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:TotemDamage()
|
|
COE:DebugMessage("Method Executing: TotemDamage");
|
|
|
|
local num, regex, i;
|
|
for num, regex in COESTR_TOTEMDAMAGE do
|
|
local match = { string.gfind( arg1, regex )() };
|
|
if ( table.getn(match) >= 1 ) then
|
|
|
|
-- find totem
|
|
-- -----------
|
|
for i = 1, COE.TotemCount do
|
|
if( COE.TotemData[i].SpellName == match[1] ) then
|
|
-- subtract damage
|
|
-- ----------------
|
|
COE.TotemData[i].CurHealth = COE.TotemData[i].CurHealth - tonumber( match[2] );
|
|
|
|
-- totem destroyed?
|
|
-- -----------------
|
|
if( COE_Config:GetSaved( COEOPT_ENABLETIMERS ) == 1 ) then
|
|
if( COE.TotemData[i].CurHealth <= 0 ) then
|
|
COE:DebugMessage( match[1] .. " destroyed" );
|
|
|
|
if( COE_Config:GetSaved( COEOPT_TIMERNOTIFICATIONS ) == 1 ) then
|
|
COE:Notification( string.format( COESTR_TOTEMDESTROYED, COE.TotemData[i].SpellName ),
|
|
COECOL_TOTEMDESTROYED );
|
|
end
|
|
|
|
COE_Totem:DeactivateTimer( COE.TotemData[i] );
|
|
else
|
|
COE:DebugMessage( match[1] .. " took " .. match[2] .. " damage. " ..
|
|
COE.TotemData[i].CurHealth .. " health left" );
|
|
end
|
|
end
|
|
break;
|
|
end
|
|
end
|
|
|
|
break;
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:ResetTimers
|
|
|
|
PURPOSE: Resets all active timers to zero
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:ResetTimers()
|
|
COE:DebugMessage("Method Executing: COE_Totem:ResetTimers");
|
|
|
|
local k;
|
|
for k = 1, 4 do
|
|
if( COE.ActiveTotems[COE_Element[k]] ) then
|
|
COE_Totem:DeactivateTimer( COE.ActiveTotems[COE_Element[k]] );
|
|
end
|
|
end
|
|
|
|
COE:Message( COESTR_RESET );
|
|
|
|
end
|
|
|
|
|
|
--[[ =============================================================================================
|
|
|
|
T I M E R - H O O K S
|
|
|
|
================================================================================================]]
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:SetupTimerHooks
|
|
|
|
PURPOSE: Stores the CastSpell, CastSpellByName, UseAction
|
|
and UseInventoryItem functions and replaces them with
|
|
a call to the corresponding hook functions and the
|
|
original function afterwards
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:SetupTimerHooks()
|
|
|
|
COE_Totem.TimerHooks["UseAction"] = UseAction;
|
|
UseAction = function( id, book, onself )
|
|
COE_Totem:HookUseAction( id, book );
|
|
COE_Totem.TimerHooks["UseAction"]( id, book, onself );
|
|
end;
|
|
|
|
COE_Totem.TimerHooks["CastSpell"] = CastSpell;
|
|
CastSpell = function( id, book )
|
|
COE_Totem:HookCastSpell( id, book );
|
|
COE_Totem.TimerHooks["CastSpell"]( id, book );
|
|
end;
|
|
|
|
COE_Totem.TimerHooks["CastSpellByName"] = CastSpellByName;
|
|
CastSpellByName = function( SpellName )
|
|
COE_Totem:HookCastSpellByName( SpellName );
|
|
COE_Totem.TimerHooks["CastSpellByName"]( SpellName );
|
|
end;
|
|
|
|
COE_Totem.TimerHooks["UseInventoryItem"] = UseInventoryItem;
|
|
UseInventoryItem = function( slotid )
|
|
COE_Totem:HookUseInventoryItem( slotid );
|
|
COE_Totem.TimerHooks["UseInventoryItem"]( slotid );
|
|
end;
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:HookUseAction
|
|
|
|
PURPOSE: Setup the totem timer if the action triggered
|
|
a totem
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:HookUseAction( id, book )
|
|
|
|
-- use only when timers are enabled
|
|
-- ---------------------------------
|
|
if( COE_Config:GetSaved( COEOPT_ENABLETIMERS ) == 0 ) then
|
|
return;
|
|
end
|
|
|
|
-- get action tooltip
|
|
-- -------------------
|
|
COETotemTT:SetAction( id );
|
|
|
|
-- check if this triggered a totem
|
|
-- --------------------------------
|
|
local text = COETotemTTTextLeft1:GetText();
|
|
local i, rank, ranktext, trinket;
|
|
|
|
-- check if this triggered the trinket
|
|
-- ------------------------------------
|
|
trinket = text == COESTR_TRINKET_TOOLTIP;
|
|
|
|
for i = 1, COE.TotemCount do
|
|
if( (trinket and COE.TotemData[i].isTrinket) or COE.TotemData[i].SpellName == text ) then
|
|
|
|
if( COE.TotemData[i].isTrinket ) then
|
|
rank = 0;
|
|
|
|
else
|
|
-- get rank information
|
|
-- Since WOW doesn't seem to clear the rank information
|
|
-- when setting a tooltip for an action that doesn't
|
|
-- have such, we need to test if the rank info is
|
|
-- actually shown first
|
|
-- -----------------------------------------------------
|
|
if( COETotemTTTextRight1:IsShown() ) then
|
|
ranktext = COETotemTTTextRight1:GetText();
|
|
end
|
|
if( ranktext ) then
|
|
_,_,rank = string.find( ranktext, COESTR_TOTEMRANK );
|
|
rank = tonumber( rank );
|
|
else
|
|
rank = COE.TotemData[i].MaxRank;
|
|
end
|
|
end
|
|
|
|
-- set pending totem
|
|
-- ------------------
|
|
COE_Totem:SetPendingTotem( COE.TotemData[i], rank );
|
|
|
|
return;
|
|
end
|
|
|
|
end
|
|
|
|
|
|
-- no totem spell. remove pending totem if set
|
|
-- --------------------------------------------
|
|
COE_Totem:SetPendingTotem( nil );
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:HookCastSpell
|
|
|
|
PURPOSE: Setup the totem timer if the spell triggered
|
|
a totem
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:HookCastSpell( id, book )
|
|
|
|
-- use only when timers are enabled
|
|
-- ---------------------------------
|
|
if( COE_Config:GetSaved( COEOPT_ENABLETIMERS ) == 0 ) then
|
|
return;
|
|
end
|
|
|
|
-- get the associated totem object
|
|
-- --------------------------------
|
|
local i, k, totem;
|
|
for i = 1, COE.TotemCount do
|
|
for k = 1, COE.TotemData[i].MaxRank do
|
|
if( COE.TotemData[i].Ranks[k].SpellID == id ) then
|
|
-- totem found. mark it as pending
|
|
-- --------------------------------
|
|
COE_Totem:SetPendingTotem( COE.TotemData[i], k );
|
|
|
|
return;
|
|
end
|
|
end
|
|
end
|
|
|
|
-- no totem spell. remove pending totem if set
|
|
-- --------------------------------------------
|
|
COE_Totem:SetPendingTotem( nil );
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:HookCastSpellByName
|
|
|
|
PURPOSE: Setup the totem timer if the spell triggered
|
|
a totem
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:HookCastSpellByName( SpellName )
|
|
|
|
-- use only when timers are enabled
|
|
-- ---------------------------------
|
|
if( COE_Config:GetSaved( COEOPT_ENABLETIMERS ) == 0 ) then
|
|
return;
|
|
end
|
|
|
|
-- extract rank information
|
|
-- -------------------------
|
|
local _,_,rank = string.find( SpellName, COESTR_CASTBYNAME );
|
|
local spell = string.gsub( SpellName, COESTR_CASTBYNAME, "" );
|
|
|
|
-- get the associated totem object
|
|
-- --------------------------------
|
|
local i, k, totem;
|
|
for i = 1, COE.TotemCount do
|
|
if( COE.TotemData[i].SpellName == spell ) then
|
|
if( rank ) then
|
|
rank = tonumber( rank );
|
|
else
|
|
rank = COE.TotemData[i].MaxRank;
|
|
end
|
|
|
|
-- totem found. mark it as pending
|
|
-- --------------------------------
|
|
COE_Totem:SetPendingTotem( COE.TotemData[i], rank );
|
|
|
|
return;
|
|
end
|
|
end
|
|
|
|
-- no totem spell. remove pending totem if set
|
|
-- --------------------------------------------
|
|
COE_Totem:SetPendingTotem( nil );
|
|
|
|
end
|
|
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE_Totem:HookUseInventoryItem
|
|
|
|
PURPOSE: Setup the totem timer if the item triggered
|
|
a totem
|
|
-------------------------------------------------------------------]]
|
|
function COE_Totem:HookUseInventoryItem( slotid )
|
|
|
|
-- use only when timers are enabled
|
|
-- ---------------------------------
|
|
if( COE_Config:GetSaved( COEOPT_ENABLETIMERS ) == 0 ) then
|
|
return;
|
|
end
|
|
|
|
-- only use for trinket slots
|
|
-- ---------------------------
|
|
if( slotid ~= GetInventorySlotInfo( "Trinket0Slot" ) and slotid ~= GetInventorySlotInfo( "Trinket1Slot" ) ) then
|
|
return;
|
|
end
|
|
|
|
-- iterate through out totems and find the trinket totem
|
|
-- ------------------------------------------------------
|
|
local i;
|
|
for i = 1, COE.TotemCount do
|
|
if( COE.TotemData[i].isTrinket ) then
|
|
-- does the totem have the same slot id?
|
|
-- --------------------------------------
|
|
if( COE.TotemData[i].TrinketSlot == slotid ) then
|
|
-- our trinket totem was cast
|
|
-- ---------------------------
|
|
COE_Totem:SetPendingTotem( COE.TotemData[i], 0 );
|
|
|
|
return;
|
|
end
|
|
end
|
|
end
|
|
|
|
-- no totem spell. remove pending totem if set
|
|
-- --------------------------------------------
|
|
COE_Totem:SetPendingTotem( nil );
|
|
|
|
end
|
|
|
|
|