diff --git a/COE_TotemData.lua b/COE_TotemData.lua index 9b55c11..5710623 100644 --- a/COE_TotemData.lua +++ b/COE_TotemData.lua @@ -47,6 +47,12 @@ COE.TotemsAvailable["Air"] = 0; -------------------------------------------------------------------]] COE["ActiveTotems"] = {Earth = nil, Fire = nil, Water = nil, Air = nil}; COE["TotemPending"] = {Totem = nil, UseRank = 0, Timeout = 0.75}; +COE["PendingTotems"] = { + Earth = {Totem = nil, Rank = 0, TimeoutStartMS = 0}, + Fire = {Totem = nil, Rank = 0, TimeoutStartMS = 0}, + Water = {Totem = nil, Rank = 0, TimeoutStartMS = 0}, + Air = {Totem = nil, Rank = 0, TimeoutStartMS = 0} +}; --[[ ---------------------------------------------------------------- COE.CleansingTotems stores pointers to the buttons and totems diff --git a/COE_TotemLogic.lua b/COE_TotemLogic.lua index ff91980..7d784d5 100644 --- a/COE_TotemLogic.lua +++ b/COE_TotemLogic.lua @@ -2,24 +2,19 @@ CALL OF ELEMENTS The All-In-One Shaman Addon - - by Wyverex (2006) - - - Totem Module / Logical - -]] -if( not COE_Totem ) then - COE_Totem = {}; -end + 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 @@ -28,594 +23,599 @@ COE_Totem["TimerHooks"] = {}; --[[ ---------------------------------------------------------------- METHOD: COE_Totem:Rescan - - PURPOSE: Scans the totems and totem sets + + 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:ScanTotems(); + COE:InitTotemSets(); - COE_Totem:UpdateAllFrames(); - COETotemFrame.Reconfigure = true; + -- 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 + + PURPOSE: Throws the totem with the specified named id -------------------------------------------------------------------]] -function COE_Totem:ThrowTotem( element, id ) +function COE_Totem:ThrowTotem(element, id) + COE:DebugMessage( + "COE_Totem:ThrowTotem element and id: " .. element .. " " .. id); + if (not COE.Initialized) then return; end - if( not COE.Initialized ) then - return; - end + -- get associated button + -- ---------------------- + local button = getglobal("COETotem" .. element .. id); + if (button == nil) then + COE:Message("Invalid Totem"); - -- get associated button - -- ---------------------- - local button = getglobal( "COETotem" .. element .. id ); - if( button == nil ) then - COE:Message( "Invalid Totem" ); - return; - end + return; + end - local totem = button.totem; - if( totem == nil ) then - COE:Message( COESTR_NOTOTEM ); - return; - end - - -- throw totem - -- ------------ - CastSpellByName( totem.SpellName ); + 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 + + 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; + local overridekey = COE_Config:GetSaved(COEOPT_OVERRIDERANK); - elseif( overridekey == COEMODE_OVERRIDEALT and IsAltKeyDown() ) then - return true; - - elseif( overridekey == COEMODE_OVERRIDECTRL and IsControlKeyDown() ) then - return true; - end - - return false; + -- 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 + 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 + 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 + -- 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 + local warnPoison, warnDisease, warnTremor = false, false, false; + local poison, disease, tremor; - -- scan party member - -- ------------------ - poison, disease, tremor = COE_Totem:ScanTargetForDebuff( "party" .. i ); - - warnPoison = warnPoison or poison; - warnDisease = warnDisease or disease; - warnTremor = warnTremor or tremor; + -- scan player first + -- ------------------ + poison, disease, tremor = COE_Totem:ScanTargetForDebuff("player"); - -- 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 + warnPoison = warnPoison or poison; + warnDisease = warnDisease or disease; + warnTremor = warnTremor or tremor; - -- 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 + -- scan party + -- ----------- + local i; + for i = 1, GetNumPartyMembers() do + if (warnPoison and warnDisease and warnTremor) then break 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 + -- scan party member + -- ------------------ + poison, disease, tremor = COE_Totem:ScanTargetForDebuff("party" .. i); - 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 + warnPoison = warnPoison or poison; + warnDisease = warnDisease or disease; + warnTremor = warnTremor or tremor; - if( warnPoison and COE.CleansingTotems.Poison.Totem and - (COE.ActiveTotems["Water"] ~= COE.CleansingTotems.Poison.Totem or - not COE_Totem:IsTimerActive( COE.ActiveTotems["Water"] )) ) then + -- 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); - 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 + + PURPOSE: Scans the specified target for debuffs that are + curable by totems -------------------------------------------------------------------]] -function COE_Totem:ScanTargetForDebuff( target ) +function COE_Totem:ScanTargetForDebuff(target) - local slot = 1; - local poison, disease, tremor = false, false, false; + 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 + -- 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; - 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 ); + 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 - end - --[[ ---------------------------------------------------------------- METHOD: COE_Totem:IsAdvisedTotem - + PURPOSE: Returns if the specified totem is an advised totem -------------------------------------------------------------------]] -function COE_Totem:IsAdvisedTotem( 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 + 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 + if (COE_Config:GetSaved(COEOPT_ENABLESETS) == 1) then - return false; + 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 ); + if (COE_Config:GetSaved(COEOPT_ENABLESETS) == 1 and + COE_Config:GetSaved(COEOPT_AUTOSWITCH) == 1) then - 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; + if (UnitIsEnemy("player", "target")) then + if (UnitIsPlayer("target")) then + -- switch to pvp set + -- ------------------ + local class = UnitClass("target"); - end - end - - end + 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 ); + if (COE_Config:GetSaved(COEOPT_ENABLESETS) == 1) then + local activeset = COE_Config:GetSaved(COEOPT_ACTIVESET); - elseif( activeset == COE.TotemSetCount ) then - -- last custom set is active or none available - -- switch to default set - -- -------------------------------------------- - COE_Totem:SwitchToSet( COEUI_DEFAULTSET ); + 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 first custom set - -- --------------------------- - COE_Totem:SwitchToSet( COE_CustomTotemSets[1].Name ); + 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 - 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 ); + if (COE_Config:GetSaved(COEOPT_ENABLESETS) == 1) then + local activeset = COE_Config:GetSaved(COEOPT_ACTIVESET); - elseif( activeset == COESET_DEFAULT ) then - -- default set is active - -- switch to last custom set - -- --------------------------- - COE_Totem:SwitchToSet( COE_CustomTotemSets[COE.TotemSetCount - COESET_DEFAULT].Name ); + if (activeset < COESET_DEFAULT) then + -- pvp set is active + -- switch to default set + -- ---------------------- + COE_Totem:SwitchToSet(COEUI_DEFAULTSET); - elseif( activeset == COESET_DEFAULT + 1 ) then - -- first custom 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 - 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 ) +function COE_Totem:SwitchToSet(name) - if( COE_Config:GetSaved( COEOPT_ENABLESETS ) == 0 ) then - return; - end + 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 + local pvpset = false; - -- 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 + -- 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 - -- 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(); + -- 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 - -- 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() + COE:DebugMessage("Method Executing: ThrowSet"); - if( COE_Config:GetSaved( COEOPT_ENABLESETS ) == 1 ) then - - -- ======================================================================= - -- check which totem to throw - -- ======================================================================= - local activeset = COE_Config:GetSaved( COEOPT_ACTIVESET ); + if (COE_Config:GetSaved(COEOPT_ENABLESETS) == 1) then - 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 + -- ======================================================================= + -- check which totem to throw + -- ======================================================================= + local activeset = COE_Config:GetSaved(COEOPT_ACTIVESET); + COE:DebugMessage("ThrowSet activeset value: " .. activeset); + + for k = 1, 4 do + COE:DebugMessage("ThrowSet k value: " .. k); + + local element = COE:LocalizedElement( + COE.TotemSets[activeset].CastOrder[k]); + COE:DebugMessage("ThrowSet element value: " .. element); + + local totem = COE.TotemSets[activeset][element]; + + COE:DebugMessage("ThrowSet COE.SetCycle[element] value: " .. + tostring(COE.SetCycle[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 + + COE:DebugMessage("ThrowSet casting totem: " .. element); + -- first check if the totem is already usable + -- ------------------------------------------- + local start, duration = GetSpellCooldown( + totem.Ranks[totem.MaxRank] + .SpellID, BOOKTYPE_SPELL); + COE:DebugMessage("ThrowSet spell cooldown duration: " .. + duration); + + if (start == 0 and duration == 0) then + + COE:DebugMessage( + "ThrowSet casting spell: " .. + COE.TotemSets[activeset][element].SpellName); + CastSpellByName(COE.TotemSets[activeset][element] + .SpellName); + -- COE_Totem:SetPendingTotem(totem, totem.MaxRank); + 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 }; + 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 @@ -624,577 +624,731 @@ end --[[ ---------------------------------------------------------------- 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 ) + successful SPELLCAST_STOP or removed if it times out first - 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 + PURPOSE: Sets up or clears a pending totem. The pending totem's + timer is activated when the spell is identified as cast. If + the spell is not identified as cast within 1 seconds, then + the pending status is removed. +-------------------------------------------------------------------]] +function COE_Totem:SetPendingTotem(totem, rank) + COE:DebugMessage("Method Executing: SetPendingTotem"); + + if (totem) then + + -- Set PendingTotems for the given totem element type + COE:DebugMessage("SetPendingTotem PendingTotems being set: " .. + totem.SpellName .. " with rank: " .. rank); + COE.PendingTotems[totem.Element].Totem = totem; + COE.PendingTotems[totem.Element].Rank = rank; + -- COE.PendingTotems[totem.Element].TimeoutStartMS = GetTime(); + + -- get the current lag - Not used but saving if needed + -- -------------------- + -- local _, _, lag = GetNetStats(); + -- local timeout = lag / 1000 + COE.TotemPending.Timeout; + local timeoutSec = 1; + + -- use lag + 0.5 seconds as pending timeout + -- ----------------------------------------- + COE:DebugMessage("SetPendingTotem Setting pending timeout to: " .. + timeoutSec .. " seconds"); + + Chronos.scheduleByName("COE_Pending", timeoutSec, + COESched_CheckPendingTotem, totem.Element); + + 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 + PURPOSE: Clears the pending totem if it is still active + + PURPOSE: Clears the pending totem if it is still pending. +-------------------------------------------------------------------]] +function COESched_CheckPendingTotem(element) + COE:DebugMessage("Executing Method: COESched_CheckPendingTotem"); + + if (element) then + COE:DebugMessage("COESched_CheckPendingTotem for element: " .. element); + + COE_Totem:ClearPendingTotem(COE.PendingTotems[element]); + end + +end --[[ ---------------------------------------------------------------- - METHOD: COE_Totem:ActivatePendingTotem - - PURPOSE: Activates the pending totem timer and deactivates a - still active timer of the same element + METHOD: ClearPendingTotem + + PURPOSE: Clears the pending totem. -------------------------------------------------------------------]] -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 +function COE_Totem:ClearPendingTotem(pendingTotem) + COE:DebugMessage("Executing Method: ClearPendingTotem"); - -- 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 - + if (pendingTotem) then + pendingTotem.Totem = nil; + pendingTotem.Rank = nil; + end end +--[[ ---------------------------------------------------------------- + METHOD: COE_Totem:GetTotemFromText + + PURPOSE: Identifies a totem from the text value passed in. Can + return a nil totem. +-------------------------------------------------------------------]] +function COE_Totem:GetTotemFromText(text) + local totem; + COE:DebugMessage("GetTotemFromText for text value: " .. text); + + -- find the totem + for k = 1, COE.TotemCount do + if (string.find(text, COE.TotemData[k].SpellName)) then + -- use existing totem object + -- -------------------------- + totem = COE.TotemData[k]; + + COE:DebugMessage("GetTotemFromText found totem: " .. totem.SpellName); + break + end + end + + return totem; + +end + +--[[ ---------------------------------------------------------------- + METHOD: COE_Totem:ActivateTotem + + PURPOSE: Activates the totem timer and deactivates a + still active timer of the same element +-------------------------------------------------------------------]] +function COE_Totem:ActivateTotem(totem) + COE:DebugMessage("Method Executing: ActivateTotem with totem parameter " .. + totem.SpellName); + + local pendingTotemObj = COE.PendingTotems[totem.Element]; + + if (pendingTotemObj and pendingTotemObj.Totem) then + COE:DebugMessage("ActivateTotem identified pending totem : " .. + pendingTotemObj.Totem.SpellName); + + -- deactivate still active totem of the same element + -- -------------------------------------------------- + local active = COE.ActiveTotems[totem.Element]; + if (active) then COE_Totem:DeactivateTimer(active); end + + local pendingTotem = pendingTotemObj.Totem; + local pendingTotemRank = pendingTotemObj.Rank; + + -- activate timer + -- --------------- + Chronos.startTimer("COE" .. totem.SpellName); + totem.CurDuration = pendingTotem.Ranks[pendingTotemRank].Duration; + totem.CurHealth = pendingTotem.Ranks[pendingTotemRank].Health; + + -- activate cooldown timer if this totem has a cooldown + -- ----------------------------------------------------- + if (pendingTotem.Ranks[pendingTotemRank].Cooldown > 0) then + totem.CurCooldown = pendingTotem.Ranks[pendingTotemRank].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[pendingTotem.Element] = totem; + totem.isActive = true; + + -- set totem in timer frame + -- ------------------------- + if (COE_Config:GetSaved(COEOPT_TIMERFRAME) == 1) then + getglobal("COETimer" .. pendingTotem.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("ActivateTotem Element " .. totem.Element .. + " in current cycle: SET"); + COE.SetCycle[totem.Element] = true; + end + + -- clear pending totem + -- -------------------- + COE_Totem:ClearPendingTotem(pendingTotemObj); + + -- 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 + +end + +--[[ ---------------------------------------------------------------- + DEPRECATED: Use ActivateTotem + 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( + "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 + + PURPOSE: Deactivates an active totem timer -------------------------------------------------------------------]] -function COE_Totem:DeactivateTimer( totem ) +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 ); + if (totem and totem.isActive) then - -- 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(); + COE:DebugMessage("Deactivating totem: " .. totem.SpellName); - -- 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 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("DeactivateTimer 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); + 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 + 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 + 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 + 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; + 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 + a notification if the totem is destroyed -------------------------------------------------------------------]] function COE_Totem:TotemDamage() - COE:DebugMessage("Method Executing: 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" ); + local num, regex, i; + for num, regex in COESTR_TOTEMDAMAGE do + local match = {string.gfind(arg1, regex)()}; + if (table.getn(match) >= 1) then - if( COE_Config:GetSaved( COEOPT_TIMERNOTIFICATIONS ) == 1 ) then - COE:Notification( string.format( COESTR_TOTEMDESTROYED, COE.TotemData[i].SpellName ), - COECOL_TOTEMDESTROYED ); - end + -- 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]); - 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 + -- 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 + + PURPOSE: Resets all active timers to zero -------------------------------------------------------------------]] function COE_Totem:ResetTimers() - COE:DebugMessage("Method Executing: 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 - local k; - for k = 1, 4 do - if( COE.ActiveTotems[COE_Element[k]] ) then - COE_Totem:DeactivateTimer( COE.ActiveTotems[COE_Element[k]] ); - end - end - end - --[[ ============================================================================================= - T I M E R - H O O K S + 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 + original function afterwards -------------------------------------------------------------------]] function COE_Totem:SetupTimerHooks() + COE:DebugMessage("Method Executing: 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["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["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["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; + 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 + a totem -------------------------------------------------------------------]] -function COE_Totem:HookUseAction( id, book ) +function COE_Totem:HookUseAction(id, book) + COE:DebugMessage("Method Executing: HookUseAction"); + -- use only when timers are enabled + -- --------------------------------- + if (COE_Config:GetSaved(COEOPT_ENABLETIMERS) == 0) then return; end - -- 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; + -- get action tooltip + -- ------------------- + COETotemTT:SetAction(id); - -- check if this triggered the trinket - -- ------------------------------------ - trinket = text == COESTR_TRINKET_TOOLTIP; + -- check if this triggered a totem + -- -------------------------------- + local text = COETotemTTTextLeft1:GetText(); + local i, rank, ranktext, trinket; - 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 - + -- check if this triggered the trinket + -- ------------------------------------ + trinket = text == COESTR_TRINKET_TOOLTIP; - -- no totem spell. remove pending totem if set - -- -------------------------------------------- - COE_Totem:SetPendingTotem( nil ); + 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 + a totem -------------------------------------------------------------------]] -function COE_Totem:HookCastSpell( id, book ) +function COE_Totem:HookCastSpell(id, book) + COE:DebugMessage("Method Executing: HookCastSpell"); - -- 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 + -- 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); - -- 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 + a totem -------------------------------------------------------------------]] -function COE_Totem:HookCastSpellByName( SpellName ) +function COE_Totem:HookCastSpellByName(SpellName) + COE:DebugMessage("Method Executing: HookCastSpellByName"); - -- 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 + -- 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); - -- 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 + a totem -------------------------------------------------------------------]] -function COE_Totem:HookUseInventoryItem( slotid ) +function COE_Totem:HookUseInventoryItem(slotid) + COE:DebugMessage("Method Executing: HookUseInventoryItem"); - -- 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 + -- 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); - -- no totem spell. remove pending totem if set - -- -------------------------------------------- - COE_Totem:SetPendingTotem( nil ); - end - diff --git a/COE_TotemVisual.lua b/COE_TotemVisual.lua index 3144890..216adb1 100644 --- a/COE_TotemVisual.lua +++ b/COE_TotemVisual.lua @@ -2,37 +2,37 @@ CALL OF ELEMENTS The All-In-One Shaman Addon - - by Wyverex (2006) - - - Totem Module / Visual - -]] -if( not COE_Totem ) then - COE_Totem = {}; -end + by Wyverex (2006) + + + Totem Module / Visual + +]] if (not COE_Totem) then COE_Totem = {}; end COEUI_BUTTONGAP = 4; COE_Totem.FlexTime = 0.3; -COEFramePositions = { Earth = { x = 0, y = 0 }, Fire = { x = 0, y = 0 }, - Water = { x = 0, y = 0 }, Air = { x = 0, y = 0 } } +COEFramePositions = { + Earth = {x = 0, y = 0}, + Fire = {x = 0, y = 0}, + Water = {x = 0, y = 0}, + Air = {x = 0, y = 0} +} -COEDynamic = { n = 7, nil, nil, nil, nil, nil, nil, nil }; +COEDynamic = {n = 7, nil, nil, nil, nil, nil, nil, nil}; --[[ ============================================================================================= - M A I N F R A M E + M A I N F R A M E ================================================================================================]] --[[ --------------------------------------------------------------------------------------------- Each element frame has the following properties: - + - AdvisorTime :