Files
CallOfElements/COE_TotemData.lua
T
2025-01-02 10:15:40 -05:00

866 lines
30 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.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
-- 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?
-- ---------------------
if (newtotem) 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 (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