ScanTotems reads each totem's element from the "Tools: <Element> Totem" tooltip line. That line names the totem item, so it stays incomplete until the item is in the client's item cache (WDB). The OctoWoW launcher clears WDB on every launch by default, so the login scan left every element empty and casting any totem failed in SetPendingTotem with "COE_TotemLogic.lua:645: attempt to index field '?' (a nil value)". - Fall back to a table of the English totem names when the tooltip gives no element. - Leave out spells that only have "Totem" in their name and no element (e.g. "Change Appearance: Mark of the Grim Totem"); they were treated as totems and hit the same error even with a warm cache. - SetPendingTotem skips a totem without a known element instead of erroring.
917 lines
33 KiB
Lua
917 lines
33 KiB
Lua
--[[
|
|
|
|
CALL OF ELEMENTS
|
|
The All-In-One Shaman Addon
|
|
|
|
by Wyverex (2006)
|
|
|
|
|
|
Totem Module Data
|
|
|
|
]] --[[ ----------------------------------------------------------------
|
|
COE.TotemData contains a list of totem classes that are
|
|
returned by COE:CreateTotem
|
|
For every available totem the player has, one object is
|
|
added to this list
|
|
-------------------------------------------------------------------]] COE["TotemData"] =
|
|
{};
|
|
COE["TotemCount"] = 0;
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
COE.MaxTotems stores the maximum number of totems per element
|
|
This is taken right from the current game content
|
|
-------------------------------------------------------------------]]
|
|
COE["MaxTotems"] = {Earth = 5, Fire = 5, Water = 7, Air = 7};
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
COE.TotemsAvailable contains the number of totems available
|
|
of each element
|
|
-------------------------------------------------------------------]]
|
|
COE["TotemsAvailable"] = {};
|
|
COE.TotemsAvailable["Earth"] = 0;
|
|
COE.TotemsAvailable["Fire"] = 0;
|
|
COE.TotemsAvailable["Water"] = 0;
|
|
COE.TotemsAvailable["Air"] = 0;
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
COE.ActiveTotems contains a pointer to the active totem of
|
|
each element
|
|
|
|
COE.TotemPending contains a pointer to the last totem spell
|
|
that was initiated but not yet completed. This lets COE check
|
|
whether something went wrong while casting (sitting etc.) by
|
|
activating the timer first when SPELLCAST_STOP is fired
|
|
After the timeout a pending totem timer is automatically removed
|
|
to prevent actions that trigger SPELLCAST_STOP and are not
|
|
hooked from activating the timer accidentally
|
|
-------------------------------------------------------------------]]
|
|
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.TotemElementsByName is the fallback ScanTotems uses when the
|
|
element cannot be read from the spell tooltip. The
|
|
"Tools: <Element> Totem" line names the totem item, so it stays
|
|
incomplete until that item is in the client's item cache (WDB).
|
|
A client whose WDB was cleared (the OctoWoW launcher does this on
|
|
every launch by default) scans at login with an empty cache.
|
|
English spell names only; other locales still rely on the tooltip.
|
|
-------------------------------------------------------------------]]
|
|
COE["TotemElementsByName"] = {
|
|
["Earthbind Totem"] = "Earth",
|
|
["Stoneclaw Totem"] = "Earth",
|
|
["Stoneskin Totem"] = "Earth",
|
|
["Strength of Earth Totem"] = "Earth",
|
|
["Tremor Totem"] = "Earth",
|
|
["Fire Nova Totem"] = "Fire",
|
|
["Flametongue Totem"] = "Fire",
|
|
["Frost Resistance Totem"] = "Fire",
|
|
["Magma Totem"] = "Fire",
|
|
["Searing Totem"] = "Fire",
|
|
["Disease Cleansing Totem"] = "Water",
|
|
["Fire Resistance Totem"] = "Water",
|
|
["Healing Stream Totem"] = "Water",
|
|
["Mana Spring Totem"] = "Water",
|
|
["Mana Tide Totem"] = "Water",
|
|
["Poison Cleansing Totem"] = "Water",
|
|
["Grace of Air Totem"] = "Air",
|
|
["Grounding Totem"] = "Air",
|
|
["Nature Resistance Totem"] = "Air",
|
|
["Sentry Totem"] = "Air",
|
|
["Tranquil Air Totem"] = "Air",
|
|
["Windfury Totem"] = "Air",
|
|
["Windwall Totem"] = "Air"
|
|
};
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
COE.CleansingTotems stores pointers to the buttons and totems
|
|
that are able to cleanse poisons, diseases and sleep, charm
|
|
or fear effects
|
|
-------------------------------------------------------------------]]
|
|
COE["CleansingTotems"] = {
|
|
Poison = {Totem = nil, Button = nil, Warn = false},
|
|
Disease = {Totem = nil, Button = nil, Warn = false},
|
|
Tremor = {Totem = nil, Button = nil, Warn = false}
|
|
};
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
COE.TotemSets contains the totem pointers for each set and
|
|
element
|
|
-------------------------------------------------------------------]]
|
|
COE["TotemSetCount"] = 0;
|
|
COE["TotemSets"] = {}
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
COE.SetCycle stores which totem of the active set have
|
|
already been thrown
|
|
-------------------------------------------------------------------]]
|
|
COE["SetCycle"] = {Earth = false, Fire = false, Water = false, Air = false};
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
COE.NoTotem is a placeholder for an empty anchor button
|
|
-------------------------------------------------------------------]]
|
|
COE["NoTotem"] = {
|
|
SpellName = "",
|
|
Element = "",
|
|
Texture = "Interface\\Icons\\INV_Misc_Idol_03.blp",
|
|
ToolPresent = false,
|
|
Ranks = {SpellID = 0, Mana = 0, Duration = 0, Health = 0, Cooldown = 0},
|
|
MaxRank = 1,
|
|
isActive = false,
|
|
CurDuration = 0,
|
|
CurHealth = 0,
|
|
CurCooldown = 0
|
|
};
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE:CreateTotem
|
|
|
|
PURPOSE: Returns the totem class for a new totem
|
|
-------------------------------------------------------------------]]
|
|
function COE:CreateTotem()
|
|
return {
|
|
SpellName = "",
|
|
Element = "",
|
|
Texture = "",
|
|
ToolPresent = false,
|
|
Ranks = {},
|
|
MaxRank = 0,
|
|
isActive = false,
|
|
CurDuration = 0,
|
|
CurHealth = 0,
|
|
CurCooldown = 0,
|
|
isTrinket = false,
|
|
TrinketSlot = nil
|
|
};
|
|
end
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE:CreateTotemRank
|
|
|
|
PURPOSE: Returns the class for a new totem rank
|
|
-------------------------------------------------------------------]]
|
|
function COE:CreateTotemRank()
|
|
return {SpellID = 0, Mana = 0, Duration = 0, Health = 0, Cooldown = 0};
|
|
end
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE:ElementFromTool
|
|
|
|
PURPOSE: Returns the element corresponding to a totem tool.
|
|
This is needed for the french version to work. In the
|
|
english and german versions it just returns the input
|
|
-------------------------------------------------------------------]]
|
|
function COE:ElementFromTool(element)
|
|
|
|
if element == COESTR_TOTEMTOOLS_EARTH then
|
|
return COESTR_ELEMENT_EARTH;
|
|
elseif element == COESTR_TOTEMTOOLS_FIRE then
|
|
return COESTR_ELEMENT_FIRE;
|
|
elseif element == COESTR_TOTEMTOOLS_WATER then
|
|
return COESTR_ELEMENT_WATER;
|
|
elseif element == COESTR_TOTEMTOOLS_AIR then
|
|
return COESTR_ELEMENT_AIR;
|
|
end
|
|
|
|
end
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE:LocalizedElement
|
|
|
|
PURPOSE: Translates a localized element name into english
|
|
-------------------------------------------------------------------]]
|
|
function COE:LocalizedElement(element)
|
|
|
|
if (element == COESTR_ELEMENT_EARTH) then
|
|
return "Earth";
|
|
elseif (element == COESTR_ELEMENT_FIRE) then
|
|
return "Fire";
|
|
elseif (element == COESTR_ELEMENT_WATER) then
|
|
return "Water";
|
|
elseif (element == COESTR_ELEMENT_AIR) then
|
|
return "Air";
|
|
end
|
|
|
|
end
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE:ScanTotems
|
|
|
|
PURPOSE: Scans the spellbook for available totems and
|
|
populates the COE.TotemData list
|
|
-------------------------------------------------------------------]]
|
|
function COE:ScanTotems()
|
|
|
|
COE:DebugMessage("Scanning Totems...");
|
|
|
|
-- delete existing totem objects
|
|
-- ------------------------------
|
|
COE.TotemData = {};
|
|
COE.TotemCount = 0;
|
|
COE.TotemsAvailable.Earth = 0;
|
|
COE.TotemsAvailable.Fire = 0;
|
|
COE.TotemsAvailable.Water = 0;
|
|
COE.TotemsAvailable.Air = 0;
|
|
|
|
-- iterate over all spells in the spellbook
|
|
-- -----------------------------------------
|
|
local i = 1;
|
|
while true do
|
|
|
|
local SpellName, SpellRank = GetSpellName(i, BOOKTYPE_SPELL);
|
|
if not SpellName then do break end end
|
|
|
|
-- is this a totem?
|
|
-- -----------------
|
|
if (SpellName ~= "Totemic Recall" and SpellName ~= "Totemic Slam" and
|
|
string.find(SpellName, COESTR_SCANTOTEMS) ~= nil) then
|
|
|
|
local newtotem = true;
|
|
local totem = nil;
|
|
|
|
-- get the rank value
|
|
-- -------------------
|
|
local _, _, rank = string.find(SpellRank, COESTR_TOTEMRANK);
|
|
if (not rank) then
|
|
rank = 1;
|
|
else
|
|
rank = tonumber(rank);
|
|
end
|
|
|
|
-- =======================================================================
|
|
-- check if totem already exists with another rank in the list
|
|
-- =======================================================================
|
|
for k = 1, COE.TotemCount do
|
|
if (SpellName == COE.TotemData[k].SpellName) then
|
|
-- use existing totem object
|
|
-- --------------------------
|
|
totem = COE.TotemData[k];
|
|
newtotem = false;
|
|
break
|
|
end
|
|
end
|
|
|
|
COETotemTT:SetSpell(i, BOOKTYPE_SPELL);
|
|
|
|
-- =======================================================================
|
|
-- create new totem object if not found
|
|
-- =======================================================================
|
|
if (not totem) then
|
|
totem = COE:CreateTotem();
|
|
|
|
-- set totem spell name
|
|
-- ---------------------
|
|
totem.SpellName = SpellName;
|
|
|
|
-- get totem school from tooltip
|
|
-- ------------------------------
|
|
local text = COETotemTTTextLeft4;
|
|
if (text and text:GetText()) then
|
|
|
|
local _, _, element =
|
|
string.find(text:GetText(), COESTR_TOTEMTOOLS);
|
|
if (element) then
|
|
|
|
-- if element starts with a |, the player does
|
|
-- not possess the needed totem for this spell
|
|
-- extract the color code before using the element
|
|
-- ------------------------------------------------
|
|
if (string.sub(element, 1, 1) == "|") then
|
|
element = string.sub(element, 11);
|
|
end
|
|
|
|
-- get element from tool
|
|
-- ----------------------
|
|
element = COE:ElementFromTool(element);
|
|
|
|
-- translate element to english
|
|
-- -----------------------------
|
|
element = COE:LocalizedElement(element);
|
|
-- valid element?
|
|
-- ---------------
|
|
if (COE.TotemsAvailable[element] ~= nil) then
|
|
totem.Element = element;
|
|
COE.TotemsAvailable[element] =
|
|
COE.TotemsAvailable[element] + 1;
|
|
else
|
|
COE:Message(COESTR_INVALIDELEMENT .. SpellName);
|
|
end
|
|
end
|
|
end
|
|
|
|
-- no element from the tooltip: fall back to the
|
|
-- known totem names (see COE.TotemElementsByName)
|
|
-- ------------------------------------------------
|
|
if (totem.Element == "") then
|
|
local element = COE.TotemElementsByName[SpellName];
|
|
if (element) then
|
|
totem.Element = element;
|
|
COE.TotemsAvailable[element] =
|
|
COE.TotemsAvailable[element] + 1;
|
|
end
|
|
end
|
|
|
|
-- get totem texture
|
|
-- ------------------
|
|
totem.Texture = GetSpellTexture(i, BOOKTYPE_SPELL);
|
|
|
|
-- get tool presence
|
|
-- ------------------
|
|
totem.ToolPresent = COE:IsToolPresent(i);
|
|
end
|
|
|
|
-- =======================================================================
|
|
-- create new totem rank
|
|
-- =======================================================================
|
|
local totemrank = COE:CreateTotemRank();
|
|
|
|
-- set totem spell id
|
|
-- -------------------
|
|
totemrank.SpellID = i;
|
|
|
|
-- get totem mana cost from tooltip
|
|
-- ---------------------------------
|
|
text = COETotemTTTextLeft2;
|
|
if (text and text:GetText()) then
|
|
|
|
local _, _, mana = string.find(text:GetText(), COESTR_TOTEMMANA);
|
|
if (mana) then totemrank.Mana = tonumber(mana); end
|
|
end
|
|
|
|
-- get totem duration and health
|
|
-- ------------------------------
|
|
totemrank.Duration, totemrank.Health, totemrank.Cooldown =
|
|
COE:GetTotemDurationAndHealth(i);
|
|
|
|
-- store rank in totem
|
|
-- --------------------
|
|
totem.Ranks[rank] = totemrank;
|
|
if (rank > totem.MaxRank) then totem.MaxRank = rank; end
|
|
|
|
-- is this a new totem? a spell that only has "Totem" in its
|
|
-- name but no element is not a placeable totem: leave it out
|
|
-- ------------------------------------------------------------
|
|
if (newtotem and totem.Element ~= "") then
|
|
-- store totem
|
|
-- ------------
|
|
COE.TotemCount = COE.TotemCount + 1;
|
|
COE.TotemData[COE.TotemCount] = totem;
|
|
|
|
-- check if it's a cleansing totem
|
|
-- --------------------------------
|
|
if (SpellName == COESTR_TOTEMPOISON) then
|
|
COE.CleansingTotems.Poison.Totem = totem;
|
|
elseif (SpellName == COESTR_TOTEMDISEASE) then
|
|
COE.CleansingTotems.Disease.Totem = totem;
|
|
elseif (SpellName == COESTR_TOTEMTREMOR) then
|
|
COE.CleansingTotems.Tremor.Totem = totem;
|
|
end
|
|
|
|
COE:DebugMessage("Found totem: " .. SpellName);
|
|
end
|
|
|
|
-- =======================================================================
|
|
-- check visibility options
|
|
-- =======================================================================
|
|
|
|
if (totem.Element == "") then
|
|
COE:DebugMessage("Skipped spell without a totem element: " ..
|
|
SpellName);
|
|
elseif (COE_DisplayedTotems[SpellName] == nil) then
|
|
-- perhaps a new totem. set it to default visible
|
|
-- and reorder it when the element count is known
|
|
-- -----------------------------------------------
|
|
COE_DisplayedTotems[SpellName] = {
|
|
Order = 0,
|
|
Element = totem.Element,
|
|
Visible = true
|
|
};
|
|
else
|
|
-- update old saved variables versions by adding the element
|
|
-- ----------------------------------------------------------
|
|
COE_DisplayedTotems[SpellName]["Element"] = totem.Element;
|
|
end
|
|
end
|
|
|
|
i = i + 1;
|
|
end
|
|
|
|
-- ====================================
|
|
-- Trinket support
|
|
-- ====================================
|
|
|
|
-- create the trinket totem even if the player doesn't have it.
|
|
-- this makes handling it much simpler and the player can choose
|
|
-- to make it invisible anyway
|
|
-- the player needs to have at least one water totem though
|
|
-- --------------------------------------------------------------
|
|
if (COE.TotemsAvailable.Water > 0) then
|
|
local trinket = COE:CreateTotem();
|
|
trinket.SpellName = "Trinket";
|
|
trinket.Element = "Water";
|
|
trinket.Texture = "Interface\\Icons\\INV_Wand_01";
|
|
trinket.isTrinket = true;
|
|
trinket.ToolPresent, trinket.TrinketSlot = COE:IsTrinketPresent();
|
|
trinket.Ranks[0] = COE:CreateTotemRank();
|
|
trinket.Ranks[0].Duration = 24;
|
|
trinket.Ranks[0].Health = 5;
|
|
trinket.Ranks[0].Cooldown = 180;
|
|
|
|
-- store totem
|
|
-- ------------
|
|
COE.TotemsAvailable.Water = COE.TotemsAvailable.Water + 1;
|
|
COE.TotemCount = COE.TotemCount + 1;
|
|
COE.TotemData[COE.TotemCount] = trinket;
|
|
|
|
if (COE_DisplayedTotems[trinket.SpellName] == nil) then
|
|
-- perhaps a new totem. set it to default visible
|
|
-- and reorder it when the element count is known
|
|
-- -----------------------------------------------
|
|
COE_DisplayedTotems[trinket.SpellName] = {Order = 0, Visible = true};
|
|
end
|
|
end
|
|
|
|
-- ===================================
|
|
-- Finish
|
|
-- ===================================
|
|
|
|
COE:DebugMessage(
|
|
"Found " .. COE.TotemCount .. " totems in spellbook" .. "(" ..
|
|
COE.TotemsAvailable.Earth .. " Earth, " .. COE.TotemsAvailable.Fire ..
|
|
" Fire, " .. COE.TotemsAvailable.Water .. " Water, " ..
|
|
COE.TotemsAvailable.Air .. " Air)");
|
|
|
|
-- reorder new totems
|
|
-- -------------------
|
|
COE:ReorderNewTotems();
|
|
|
|
end
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE:GetTotemDurationAndHealth
|
|
|
|
PURPOSE: Extracts the duration of the totem out of the tooltip
|
|
When there is more than one time specification present,
|
|
the one with the longer duration is used since this is the
|
|
totem duration then
|
|
Also the health and the cooldown of the totem are returned
|
|
-------------------------------------------------------------------]]
|
|
function COE:GetTotemDurationAndHealth(spellid)
|
|
|
|
COETotemTTTextRight3:SetText(nil);
|
|
COETotemTT:SetSpell(spellid, BOOKTYPE_SPELL);
|
|
text = COETotemTTTextLeft5:GetText();
|
|
|
|
if (not text) then
|
|
COE:DebugMessage("nil text with id: " .. spellid);
|
|
return 0, 0;
|
|
end
|
|
|
|
local duration = 0;
|
|
local health = 0;
|
|
local cooldown = 0;
|
|
|
|
-- ===============================================================
|
|
-- Duration
|
|
-- ===============================================================
|
|
|
|
-- first search for a minute specification
|
|
-- if we find one it is surely the totem duration
|
|
-- -----------------------------------------------
|
|
local _, _, minutetext = string.find(text, COESTR_MINUTEDURATION);
|
|
if (minutetext) then
|
|
-- calculate the duration in seconds
|
|
-- ----------------------------------
|
|
local min = tonumber(string.sub(minutetext, 1, 1));
|
|
local sec = tonumber(string.sub(minutetext, 3, 4)) / 100 * 60;
|
|
|
|
duration = min * 60 + sec;
|
|
else
|
|
_, _, minutetext = string.find(text, COESTR_MINUTEDURATION_INT);
|
|
if (minutetext) then
|
|
duration = tonumber(minutetext) * 60;
|
|
else
|
|
-- now test for a duration in seconds
|
|
-- -----------------------------------
|
|
local _, b, sectext1 = string.find(text, COESTR_SECDURATION);
|
|
if (sectext1) then
|
|
|
|
-- look if there are two second specifications
|
|
-- if so, take the greate one
|
|
-- --------------------------------------------
|
|
local _, _, sectext2 = string.find(string.sub(text, b),
|
|
COESTR_SECDURATION);
|
|
|
|
if (sectext2) then
|
|
duration = math.max(tonumber(sectext1), tonumber(sectext2));
|
|
else
|
|
duration = tonumber(sectext1);
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- ===============================================================
|
|
-- Health
|
|
-- ===============================================================
|
|
|
|
for num, regex in COESTR_TOTEMHEALTH do
|
|
local match = {string.gfind(text, regex)()};
|
|
if (table.getn(match) >= 1) then
|
|
|
|
health = tonumber(match[1]);
|
|
break
|
|
end
|
|
end
|
|
|
|
-- ===============================================================
|
|
-- Cooldown
|
|
-- ===============================================================
|
|
|
|
text = COETotemTTTextRight3:GetText();
|
|
|
|
if (not text) then
|
|
cooldown = 0;
|
|
else
|
|
_, _, cooldown = string.find(text, COESTR_SECDURATION);
|
|
if (cooldown) then
|
|
cooldown = tonumber(cooldown);
|
|
else
|
|
_, _, cooldown = string.find(text, COESTR_MINUTEDURATION_INT);
|
|
if (cooldown) then
|
|
cooldown = tonumber(cooldown) * 60;
|
|
else
|
|
cooldown = 0;
|
|
end
|
|
end
|
|
end
|
|
|
|
return duration, health, cooldown;
|
|
|
|
end
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE:IsToolPresent
|
|
|
|
PURPOSE: Checks if the player has the totem of the specified
|
|
element in his inventory
|
|
|
|
This is done by testing the color of the "Tools:" section
|
|
in the totem tooltip
|
|
-------------------------------------------------------------------]]
|
|
function COE:IsToolPresent(spellid)
|
|
|
|
-- get totem tooltip
|
|
-- ------------------
|
|
COETotemTT:SetSpell(spellid, BOOKTYPE_SPELL);
|
|
|
|
-- test for presence of the totem tool
|
|
-- ------------------------------------
|
|
local text = COETotemTTTextLeft4;
|
|
if (text and text:GetText()) then
|
|
|
|
local _, _, element = string.find(text:GetText(), COESTR_TOTEMTOOLS);
|
|
if (element) then
|
|
|
|
-- if element doesn't start with a |, the player
|
|
-- possesses the needed totem for this spell
|
|
-- ------------------------------------------------
|
|
if (string.sub(element, 1, 1) ~= "|") then return true; end
|
|
end
|
|
end
|
|
|
|
return false;
|
|
end
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE:IsTrinketPresent
|
|
|
|
PURPOSE: Checks if the player has the enamored water spirit
|
|
trinket equipped and returns the trinket slot
|
|
|
|
RETURNS: equipped, slot
|
|
-------------------------------------------------------------------]]
|
|
function COE:IsTrinketPresent()
|
|
|
|
for i = 0, 1 do
|
|
local slot = GetInventorySlotInfo("Trinket" .. i .. "Slot");
|
|
local item = GetInventoryItemLink("player", slot);
|
|
|
|
if (item) then
|
|
local itemname = string.find(item, COESTR_TRINKET);
|
|
if (itemname) then
|
|
-- trinket is equipped
|
|
-- --------------------
|
|
return true, slot;
|
|
end
|
|
end
|
|
end
|
|
|
|
return false, nil;
|
|
|
|
end
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE:ReorderNewTotems
|
|
|
|
PURPOSE: Assigns each COE_DisplayedTotems entry with a zero
|
|
order a valid order depending on the number of available
|
|
totems in this element
|
|
-------------------------------------------------------------------]]
|
|
function COE:ReorderNewTotems()
|
|
COE:DebugMessage("Executing ReorderNewTotems");
|
|
|
|
local nextslot = {
|
|
Earth = COE.TotemsAvailable.Earth,
|
|
Fire = COE.TotemsAvailable.Fire,
|
|
Water = COE.TotemsAvailable.Water,
|
|
Air = COE.TotemsAvailable.Air
|
|
};
|
|
|
|
local used = {Earth = {}, Fire = {}, Water = {}, Air = {}};
|
|
local bError = false;
|
|
|
|
COE:DebugMessage("ReorderNewTotems COE.TotemCount: " .. COE.TotemCount);
|
|
|
|
for k = 1, COE.TotemCount do
|
|
|
|
local totem = COE.TotemData[k];
|
|
COE:DebugMessage(
|
|
"ReorderNewTotems processing totem: " .. totem.Element .. " " ..
|
|
totem.SpellName);
|
|
|
|
if (COE_DisplayedTotems[totem.SpellName] ~= nil) then
|
|
if (COE_DisplayedTotems[totem.SpellName].Order == 0) then
|
|
|
|
-- this totem has just been added
|
|
-- assign the currently free slot
|
|
-- -------------------------------
|
|
if (not nextslot[totem.Element]) then
|
|
COE:DebugMessage(
|
|
"ReorderNewTotems nextslot[totem.Element] is nil");
|
|
end
|
|
|
|
COE_DisplayedTotems[totem.SpellName].Order =
|
|
nextslot[totem.Element];
|
|
nextslot[totem.Element] = nextslot[totem.Element] - 1;
|
|
end
|
|
|
|
-- register that this slot of the element is now in use
|
|
-- mark as error if already in use
|
|
-- -----------------------------------------------------
|
|
if (used[totem.Element][COE_DisplayedTotems[totem.SpellName].Order] ==
|
|
nil) then
|
|
used[totem.Element][COE_DisplayedTotems[totem.SpellName].Order] =
|
|
true;
|
|
else
|
|
bError = true;
|
|
end
|
|
end
|
|
end
|
|
|
|
-- are there multiple entries for one slot?
|
|
-- -----------------------------------------
|
|
if (bError) then
|
|
-- there is something wrong with the saved variables
|
|
-- reset all ordering and reassign it
|
|
-- --------------------------------------------------
|
|
for k = 1, COE.TotemCount do
|
|
|
|
local totem = COE.TotemData[k];
|
|
if (COE_DisplayedTotems[totem.SpellName] ~= nil) then
|
|
COE_DisplayedTotems[totem.SpellName].Order = 0;
|
|
end
|
|
end
|
|
|
|
COE:ReorderNewTotems();
|
|
|
|
end
|
|
|
|
end
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE:InitTotemSets
|
|
|
|
PURPOSE: Fills the COE.TotemSets list with the totem objects
|
|
corresponding to the spell names saved in COEOPT_TOTEMSETS
|
|
-------------------------------------------------------------------]]
|
|
function COE:InitTotemSets()
|
|
|
|
local indices = {"Earth", "Fire", "Water", "Air"};
|
|
|
|
COE.TotemSets = {};
|
|
|
|
-- for each standard set
|
|
-- ----------------------
|
|
for set = 1, table.getn(COE_SavedTotemSets) do
|
|
|
|
COE.TotemSets[set] = {
|
|
Earth = nil,
|
|
Fire = nil,
|
|
Water = nil,
|
|
Air = nil,
|
|
CastOrder = COE_SavedTotemSets[set].CastOrder
|
|
};
|
|
|
|
-- for each element
|
|
-- -----------------
|
|
for k = 1, 4 do
|
|
|
|
if (COE_SavedTotemSets[set][indices[k]] ~= "") then
|
|
|
|
-- iterate over all totems
|
|
-- ------------------------
|
|
for totem in COE.TotemData do
|
|
|
|
if (COE.TotemData[totem].SpellName ==
|
|
COE_SavedTotemSets[set][indices[k]]) then
|
|
COE.TotemSets[set][indices[k]] = COE.TotemData[totem];
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- for each custom set
|
|
-- --------------------
|
|
for set = 1, table.getn(COE_CustomTotemSets) do
|
|
|
|
COE.TotemSets[COESET_DEFAULT + set] = {
|
|
Earth = nil,
|
|
Fire = nil,
|
|
Water = nil,
|
|
Air = nil,
|
|
CastOrder = COE_CustomTotemSets[set].CastOrder
|
|
};
|
|
|
|
-- for each element
|
|
-- -----------------
|
|
local k, totem;
|
|
for k = 1, 4 do
|
|
|
|
if (COE_CustomTotemSets[set][indices[k]] ~= "") then
|
|
|
|
-- iterate over all totems
|
|
-- ------------------------
|
|
for totem in COE.TotemData do
|
|
|
|
if (COE.TotemData[totem].SpellName ==
|
|
COE_CustomTotemSets[set][indices[k]]) then
|
|
COE.TotemSets[COESET_DEFAULT + set][indices[k]] =
|
|
COE.TotemData[totem];
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
COE.TotemSetCount = table.getn(COE.TotemSets);
|
|
|
|
end
|
|
|
|
--[[ =============================================================================================
|
|
|
|
F I X E S
|
|
|
|
================================================================================================]]
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE:Fix_CastOrderLocalization
|
|
|
|
PURPOSE: Correctly localizes the element names in the
|
|
cast order in COE_SavedTotemSets
|
|
-------------------------------------------------------------------]]
|
|
function COE:Fix_CastOrderLocalization()
|
|
|
|
-- for each standard set
|
|
-- ----------------------
|
|
local set, k;
|
|
for set = 1, table.getn(COE_SavedTotemSets) do
|
|
|
|
for k = 1, 4 do
|
|
if (COE_SavedTotemSets[set].CastOrder[k] == "Earth") then
|
|
COE_SavedTotemSets[set].CastOrder[k] = COESTR_ELEMENT_EARTH;
|
|
|
|
elseif (COE_SavedTotemSets[set].CastOrder[k] == "Fire") then
|
|
COE_SavedTotemSets[set].CastOrder[k] = COESTR_ELEMENT_FIRE;
|
|
|
|
elseif (COE_SavedTotemSets[set].CastOrder[k] == "Water") then
|
|
COE_SavedTotemSets[set].CastOrder[k] = COESTR_ELEMENT_WATER;
|
|
|
|
elseif (COE_SavedTotemSets[set].CastOrder[k] == "Air") then
|
|
COE_SavedTotemSets[set].CastOrder[k] = COESTR_ELEMENT_AIR;
|
|
end
|
|
end
|
|
end
|
|
|
|
-- notify user
|
|
-- ------------
|
|
COE:Message(COESTR_FIXEDSETS);
|
|
|
|
end
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE:Fix_DisplayedTotems
|
|
|
|
PURPOSE: Fixes errors in the COE_DisplayedTotems array
|
|
-------------------------------------------------------------------]]
|
|
function COE:Fix_DisplayedTotems()
|
|
|
|
local i;
|
|
local fixed = false;
|
|
foreach(COE_DisplayedTotems, function(index, value)
|
|
|
|
-- is this an old-style entry?
|
|
-- ----------------------------
|
|
if (type(value) == "boolean") then
|
|
COE_DisplayedTotems[index] = {Order = 0, Visible = value};
|
|
fixed = true;
|
|
|
|
elseif (type(value) == "table") then
|
|
if (COE_DisplayedTotems[index].Visible == nil) then
|
|
COE_DisplayedTotems[index].Visible = true;
|
|
fixed = true;
|
|
end
|
|
|
|
if (COE_DisplayedTotems[index].Order == nil) then
|
|
COE_DisplayedTotems[index].Order = 0;
|
|
fixed = true;
|
|
end
|
|
|
|
else
|
|
COE_DisplayedTotems[index] = {Order = 0, Visible = value};
|
|
fixed = true;
|
|
end
|
|
|
|
end);
|
|
|
|
-- notify user
|
|
-- ------------
|
|
if (fixed) then COE:Message(COESTR_FIXEDDISPLAY); end
|
|
|
|
end
|
|
|
|
--[[ ----------------------------------------------------------------
|
|
METHOD: COE:Fix_CastOrderLocalization2
|
|
|
|
PURPOSE: Correctly localizes the element names in the
|
|
cast order in COE_SavedTotemSets
|
|
-------------------------------------------------------------------]]
|
|
function COE:Fix_CastOrderLocalization2()
|
|
|
|
-- for each standard set
|
|
-- ----------------------
|
|
local set, k;
|
|
for set = 1, table.getn(COE_SavedTotemSets) do
|
|
|
|
for k = 1, 4 do
|
|
if (COE_SavedTotemSets[set].CastOrder[k] == COESTR_TOTEMTOOLS_EARTH) then
|
|
COE_SavedTotemSets[set].CastOrder[k] = COESTR_ELEMENT_EARTH;
|
|
|
|
elseif (COE_SavedTotemSets[set].CastOrder[k] ==
|
|
COESTR_TOTEMTOOLS_FIRE) then
|
|
COE_SavedTotemSets[set].CastOrder[k] = COESTR_ELEMENT_FIRE;
|
|
|
|
elseif (COE_SavedTotemSets[set].CastOrder[k] ==
|
|
COESTR_TOTEMTOOLS_WATER) then
|
|
COE_SavedTotemSets[set].CastOrder[k] = COESTR_ELEMENT_WATER;
|
|
|
|
elseif (COE_SavedTotemSets[set].CastOrder[k] ==
|
|
COESTR_TOTEMTOOLS_AIR) then
|
|
COE_SavedTotemSets[set].CastOrder[k] = COESTR_ELEMENT_AIR;
|
|
end
|
|
end
|
|
end
|
|
|
|
-- for each custom set
|
|
-- --------------------
|
|
for set = 1, table.getn(COE_CustomTotemSets) do
|
|
|
|
for k = 1, 4 do
|
|
if (COE_CustomTotemSets[set].CastOrder[k] == COESTR_TOTEMTOOLS_EARTH) then
|
|
COE_CustomTotemSets[set].CastOrder[k] = COESTR_ELEMENT_EARTH;
|
|
|
|
elseif (COE_CustomTotemSets[set].CastOrder[k] ==
|
|
COESTR_TOTEMTOOLS_FIRE) then
|
|
COE_CustomTotemSets[set].CastOrder[k] = COESTR_ELEMENT_FIRE;
|
|
|
|
elseif (COE_CustomTotemSets[set].CastOrder[k] ==
|
|
COESTR_TOTEMTOOLS_WATER) then
|
|
COE_CustomTotemSets[set].CastOrder[k] = COESTR_ELEMENT_WATER;
|
|
|
|
elseif (COE_CustomTotemSets[set].CastOrder[k] ==
|
|
COESTR_TOTEMTOOLS_AIR) then
|
|
COE_CustomTotemSets[set].CastOrder[k] = COESTR_ELEMENT_AIR;
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|