vanilla-wow-addons – Rev 1
?pathlinks?
-- stuff for the startup log
local SW_SL_RegExCreate = 0;
local SW_SL_RegExAdded = 0;
function SW_SL_Add(msg)
table.insert(SW_StartupLog, msg);
end
function SW_SL_AddTrailer(msg)
SW_StartupLog[table.getn(SW_StartupLog)] = SW_StartupLog[table.getn(SW_StartupLog)].. msg;
end
function SW_SL_SetLastOk()
SW_SL_AddTrailer(SW_SL["OK"]);
end
function SW_SL_Finalize()
SW_SL_Add(SW_SL["MAP_REGEX"].." "..SW_SL_RegExAdded.."/"..SW_SL_RegExCreate);
SW_DumpTable(SW_StartupLog,nil,1,true);
SW_StartupLog = nil;
end
function SW_DEV_FFN(func)
if func == nil then return; end
if type(func) ~= "function" then
return "Not a function";
end
local ret = "??";
local vars = getfenv();
for k,v in pairs(vars) do
if type(v) == "function" then
if func == v then
return k;
end
end
end
return ret;
end
function SW_DEV_FindVar(str, chkVal)
local vars = getfenv();
local sLen =string.len(str);
SW_printStr( "------ "..str.." ------");
for k,v in pairs(vars) do
if chkVal then
if type(v) == "string" then
if string.find(v, str) then
SW_printStr(k.." ==> "..v);
end
end
else
if string.find(k, str) then
if type(v) == "string" then
SW_printStr(k.." ==> "..v);
else
SW_printStr(k.." ("..type(v)..")");
end
end
end
end
end
function SW_DEV_CC(hideCorrectlyOrdered)
local s1, s2;
local headPrinted = false;
local startS, endS;
local problematic = {};
local mainEnding = {};
local mainSDI = 0;
SW_printStr("-------------SW_DEV_CC--------------");
-- get all problematic regex
-- (these end in a string capture.)
local re = "(.+)%(%.%-%)(.-)$";
for i,toCheck in ipairs(SW_EventRegexMap[SW_DEV_EVENTDUMMY]) do
s1 = SW_RegEx_Lookup[toCheck]["r"];
_,_,startS, endS = string.find(s1, re);
if endS ~= nil and string.len( endS ) <=20 then
-- the end capture may not include another capture
if not (string.find(endS,"%(%.%-%)") or string.find(endS,"%(%%d%+%)") ) then
--SW_printStr(s1.." "..endS);
problematic[s1] = {startS, endS, toCheck};
if mainEnding[endS] == nil then
mainEnding[endS] = 1;
else
mainEnding[endS] = mainEnding[endS] + 1;
end
end
end
end
SW_DumpTable(mainEnding);
--SW_DumpTable(problematic);
for k, v in pairs(problematic) do
headPrinted = false;
--s2 = v[1].."(.-)"..v[2];
s2 = v[1];
mainSDI = SW_DEV_GetDummyIndex(k);
for i,toCheck in ipairs(SW_EventRegexMap[SW_DEV_EVENTDUMMY]) do
s1 = SW_RegEx_Lookup[toCheck]["r"];
if string.sub(s1,1,string.len(s2))== s2 then
-- it will collide with istelf..
if k ~= s1 then
if (not hideCorrectlyOrdered) or (mainSDI < SW_DEV_GetDummyIndex(s1)) then
if not headPrinted then
SW_printStr(" ");
SW_printStr("----CHECK "..v[3].." "..k);
headPrinted = true;
end
SW_printStr(toCheck.." "..s1.." LateSort:"..((SW_RegEx_Lookup[toCheck]["ls"]) or "NO"));
end
end
end
end
end
end
function SW_DEV_GetDummyIndex(regEx)
for i,toCheck in ipairs(SW_EventRegexMap[SW_DEV_EVENTDUMMY]) do
if regEx == SW_RegEx_Lookup[toCheck]["r"] then
return i;
end
end
end
-- this function is used to create "junk" for testing
--[[
-- need this to map var names to var values
local SW_G_VARS = getfenv();
-- note to self check GetCVar
local junkIndex =0;
SW_DEV_JUNK_STRINGS ={};
local function SW_CreateJunk(varName)
local strMain = getglobal(varName);
local str ="";
if strMain == nil then return end;
for i=1,SW_DEV_ITEMS_PER_REGEX do
--[[
str = string.gsub(strMain, '(%%(%d?)$?([sd]))',
function(all,num,type)
if type == 's' then
return (string.rep(string.char(math.random(97,122)), math.random(3,5)));
else
return (math.random(1000));
end
end);
--]]
str = string.gsub(strMain, '(%%(%d?)$?([sd]))',
function(all,num,type)
if type == 's' then
return ("STRING");
else
return (12345);
end
end);
table.insert(SW_DEV_JUNK_STRINGS, str);
end
end
--]]
--[[
used this to find ending collisions
only "bad" one found in en,de,fr is en: PERIODICAURAHEALSELFSELF
fr has some with extra attack messages, but not using these atm
SW_EndingTest = {};
SW_EndingCol = {};
function SW_TestEnding(str)
local tmpStr = string.gsub(str, "(%%%d?$?s%.)$", "");
for k,v in pairs(SW_EndingTest) do
if string.sub(k,1,string.len(tmpStr))==tmpStr then
if SW_EndingCol[tmpStr] == nil then
SW_EndingCol[tmpStr] = 1;
else
SW_EndingCol[tmpStr] = SW_EndingCol[tmpStr] +1;
end
end
end
if SW_EndingTest[str] == nil then
SW_EndingTest[str] = 0;
end
end
--]]
--this converts a GlobalVariable to a regex we can use
-- and add it to SW_RegEx_Lookup
local function SW_InitVar(varName,types,fromSelf,toSelf,isCrit,lateSort)
local str = getglobal(varName);
--SW_TestEnding(str);
--check if we are trying to work on a global thats not available
if str == nil then
SW_printStr("SW_InitVar varName NIL: "..varName);
return
end;
--SW_CreateJunk(varName);
if types == nil then return end;
--fixes ambiguous strings
-- fix log strings is a localized function
local strTmp = SW_FixLogStrings(str);
if str ~= strTmp then
setglobal(varName, strTmp);
str = strTmp;
end
SW_SL_RegExCreate = SW_SL_RegExCreate +1;
SW_RegEx_Lookup[varName] ={};
-- "p" stands for positions maps found for numbered vals (e.g. %3$s)
-- in a different langugage these might be used in a different order
SW_RegEx_Lookup[varName]["p"] ={};
SW_RegEx_Lookup[varName]["types"] = types;
if lateSort then
SW_RegEx_Lookup[varName]["ls"] = 1;
end
if fromSelf then
SW_RegEx_Lookup[varName]["fromSelf"] = 1;
end
if toSelf then
SW_RegEx_Lookup[varName]["toSelf"] = 1;
end
if isCrit then
SW_RegEx_Lookup[varName]["isCrit"] = 1;
end
local index=0;
local needPosLookup = false;
-- first we have to "sanitze" the string ^()%.[]*+-? are special chars in a regex (dont escape the $ and %)
-- so we are escaping these with %
str = string.gsub(str, "([%.%(%)%+%-%?%[%]%^])", "%%%1");
-- the inner function actually does the work
str = string.gsub(str, '(%%(%d?)$?([sd]))',
function(all,num,type) -- e.g. %3$s all = %3$s num=3 type=s
index = index+1;
--1.0.2 , fixed the french version bug through "tonumber .. omg DOH .. oh well
-- this will help all non englisch versions
SW_RegEx_Lookup[varName]["p"][index] = tonumber(num);
if num ~= "" then
-- if num is "" then the string e.g. only used %s and not %1$s
-- and we dont need a lookup - its already in order
needPosLookup = true;
end
--this is the actual replacement that makes the regex
-- use non greedy for strings
if type == 's' then
return ('(.-)');
else
return ('(%d+)');
end
end);
-- saves how many captures to expect later using this regex
SW_RegEx_Lookup[varName]["i"] = index;
--generate maps for heal dmg etc info
if index == getn(types) then
local playerName = "";
local mm = {};
local medm = {};
local i;
local max = getn(types);
--1 = target
--2 = caster/attacker/initiator
--3 = someString (normally spell names, or item names)
-- 51 = dmg 52 = heal
--{from,to,dmg,heal, what}
for i, val in ipairs(types) do
if val == 2 then
mm[1] = i;
medm[1] = i;
elseif val == 1 then
mm[2] = i;
medm[2] = i;
elseif val == 51 then
mm[3] = i;
medm[3] = i;
elseif val == 52 then
mm[4] = i;
medm[4] = i;
elseif val == 3 then
mm[5] = i;
medm[5] = i;
elseif val == 7 then
mm[6] = i;
medm[6] = i;
end
end
if fromSelf then
mm[1]= -1;
end
if toSelf then
mm[2]= -1;
end
SW_RegEx_Lookup[varName]["basicInfo"] = mm;
--SW_RegEx_Lookup[varName]["fullInfo"] = medm;
else
SW_printStr(RED_FONT_COLOR_CODE.."SW_InitVar "..varName.." "..index.."~="..getn(types).." caputerN~=TypeN" , 1);
end
if needPosLookup then
-- check if we really do need it
-- could be in order anyways
needPosLookup = false;
for k, v in pairs(SW_RegEx_Lookup[varName]["p"]) do
-- make k, v numbers, so they will compare
-- k,v are of different types so this wouldn't work otherwise
k = k+0;
v = v+0;
if k~=v then
needPosLookup = true;
break;
end
end
end
-- now we are sure if we need it or not
if not needPosLookup then
-- %s %d etc. used info is "in order"
-- or %1$s %2$d etc. was used but all in correct order
-- just junk it
SW_RegEx_Lookup[varName]["p"] = nil;
end
--if string.sub(str,1,1) == "(" then
--SW_RegEx_Lookup[varName]["r"] = str; -- the regex
--else
SW_RegEx_Lookup[varName]["r"] = "^"..str; -- the regex
--end
--[[ Interesting have to comment this out so wow will work??
maybe because this is a local function ?
if SW_DEV_CREATE_JUNK_STRINGS then
SW_CreateJunk(varName);
end
]]--
end
--------------------- the global vars to define a regex for -------------------------------
function SW_CreateRegexFromGlobals()
-- take these out while finding matches and collisions
--SW_InitVar("VULNERABLE_TRAILER");
--SW_InitVar("ABSORB_TRAILER");
--SW_InitVar("BLOCK_TRAILER");
--SW_InitVar("RESIST_TRAILER");
SW_SL_Add(SW_SL["REGEX"]);
--[[ new way, a lot more info
name of string var,
Arrray of types
The array is mapped 1 to 1 to the captures AFTER the captures have been sorted
(for different languages they may be in different order)
1 = target
2 = caster/attacker/initiator
3 = someString (normally spell names, or item names)
4 = unused
5x = Number
6x = number 2
where x
1= Damage
2 = Heal
3 = Other
4 = LeechFrom amount(victim of leech )
5 = LeechTo amount (leech transferred to)
7 = School
8 = LeechFrom (String what is leeched health, mana, etc)
9 = LeechTo (string what has been transferred healt, mana, etc)
10 = Leech benefit (the person the got the "good side" of the leech
(leech and drain use the same types, some fields are just not set)
After the array:
fromself, (did one self start the cast/attack? )
toself, (did one self get the heal/hit...)
iscrit, (is this a crit?)
lateSort (special indicated to check these last; used in recuCheck,
used to push back some regex that capture to early)
note to self... new in 1.9 true if this locale:
LOCALE_enGB, LOCALE_enUS, LOCALE_frFR, LOCALE_deDE, LOCALE_koKR, LOCALE_zhCN, LOCALE zhTW
]]--
if (LOCALE_frFR) then
-- captures to early in fr version
SW_InitVar("COMBATHITCRITOTHEROTHER",{2,1,51},nil,nil,true,true);
SW_InitVar("COMBATHITCRITSCHOOLOTHEROTHER",{2,1,51,7},nil,nil,true,true);
else
SW_InitVar("COMBATHITCRITOTHEROTHER",{2,1,51},nil,nil,true,nil);
SW_InitVar("COMBATHITCRITSCHOOLOTHEROTHER",{2,1,51,7},nil,nil,true,nil);
end
SW_InitVar("COMBATHITCRITOTHERSELF",{2,51},nil,true,true,nil);
SW_InitVar("COMBATHITCRITSCHOOLOTHERSELF",{2,51,7},nil,true,true,nil);
SW_InitVar("COMBATHITCRITSCHOOLSELFOTHER",{1,51,7},true,nil,true,nil);
SW_InitVar("COMBATHITCRITSELFOTHER",{1,51},true,nil,true,nil);
if (LOCALE_zhCN or LOCALE_zhTW) then
SW_InitVar("COMBATHITOTHEROTHER",{2,1,51},nil,nil,nil,true);
SW_InitVar("COMBATHITSCHOOLOTHEROTHER",{2,1,51,7},nil,nil,nil,true);
SW_InitVar("COMBATHITSCHOOLOTHERSELF",{2,51,7},nil,true,nil,true);
else
SW_InitVar("COMBATHITOTHEROTHER",{2,1,51},nil,nil,nil,nil);
SW_InitVar("COMBATHITSCHOOLOTHEROTHER",{2,1,51,7},nil,nil,nil,nil);
SW_InitVar("COMBATHITSCHOOLOTHERSELF",{2,51,7},nil,true,nil,nil);
end
SW_InitVar("COMBATHITOTHERSELF",{2,51},nil,true,nil,nil);
SW_InitVar("COMBATHITSCHOOLSELFOTHER",{1,51,7},true,nil,nil,nil);
SW_InitVar("COMBATHITSELFOTHER",{1,51},true,nil,nil,nil);
SW_InitVar("DAMAGESHIELDOTHEROTHER",{2,51,7,1},nil,nil,nil,nil);
SW_InitVar("DAMAGESHIELDOTHERSELF",{2,51,7},nil,true,nil,nil);
SW_InitVar("DAMAGESHIELDSELFOTHER",{51,7,1},true,nil,nil,nil);
SW_InitVar("ERR_COMBAT_DAMAGE_SSI",{2,1,51},nil,nil,nil,true);
SW_InitVar("HEALEDCRITOTHEROTHER",{2,3,1,52},nil,nil,true,nil);
SW_InitVar("HEALEDCRITOTHERSELF",{2,3,52},nil,true,true,nil);
SW_InitVar("HEALEDCRITSELFOTHER",{3,1,52},true,nil,true,nil);
SW_InitVar("HEALEDCRITSELFSELF",{3,52},true,true,true,nil);
SW_InitVar("HEALEDOTHEROTHER",{2,3,1,52},nil,nil,nil,nil);
SW_InitVar("HEALEDOTHERSELF",{2,3,52},nil,true,nil,nil);
SW_InitVar("HEALEDSELFOTHER",{3,1,52},true,nil,nil,nil);
SW_InitVar("HEALEDSELFSELF",{3,52},true,true,nil,nil);
SW_InitVar("PERIODICAURADAMAGEOTHEROTHER",{1,51,7,2,3},nil,nil,nil,nil);
SW_InitVar("PERIODICAURADAMAGEOTHERSELF",{51,7,2,3},nil,true,nil,nil);
SW_InitVar("PERIODICAURADAMAGESELFOTHER",{1,51,7,3},true,nil,nil,nil);
SW_InitVar("PERIODICAURADAMAGESELFSELF",{51,7,3},true,true,nil,nil);
SW_InitVar("PERIODICAURAHEALOTHEROTHER",{1,52,2,3},nil,nil,nil,nil);
SW_InitVar("PERIODICAURAHEALOTHERSELF",{52,2,3},nil,true,nil,nil);
SW_InitVar("PERIODICAURAHEALSELFOTHER",{1,52,3},true,nil,nil,nil);
if LOCALE_enGB or LOCALE_enUS then
-- captures to early in en versions
SW_InitVar("PERIODICAURAHEALSELFSELF",{52,3},true,true,nil,true);
else
SW_InitVar("PERIODICAURAHEALSELFSELF",{52,3},true,true,nil,nil);
end
SW_InitVar("PET_DAMAGE_PERCENTAGE",{53},nil,nil,nil,nil);
SW_InitVar("SPELLEXTRAATTACKSOTHER",{1,53,3},nil,nil,nil,nil);
SW_InitVar("SPELLEXTRAATTACKSOTHER_SINGULAR",{1,53,3},nil,nil,nil,nil);
SW_InitVar("SPELLEXTRAATTACKSSELF",{53,3},nil,true,nil,nil);
SW_InitVar("SPELLEXTRAATTACKSSELF_SINGULAR",{3,53},nil,true,nil,nil);
SW_InitVar("SPELLHAPPINESSDRAINOTHER",{1,2,53},nil,nil,nil,nil);
SW_InitVar("SPELLHAPPINESSDRAINSELF",{1,53},true,nil,nil,nil);
SW_InitVar("SPELLLOGCRITOTHEROTHER",{2,3,1,51},nil,nil,true,nil);
SW_InitVar("SPELLLOGCRITOTHERSELF",{2,3,51},nil,true,true,nil);
SW_InitVar("SPELLLOGCRITSCHOOLOTHEROTHER",{2,3,1,51,7},nil,nil,true,nil);
SW_InitVar("SPELLLOGCRITSCHOOLOTHERSELF",{2,3,51,7},nil,true,true,nil);
SW_InitVar("SPELLLOGCRITSCHOOLSELFOTHER",{3,1,51,7},true,nil,true,nil);
SW_InitVar("SPELLLOGCRITSCHOOLSELFSELF",{3,51,7},true,true,true,nil);
SW_InitVar("SPELLLOGCRITSELFOTHER",{3,1,51},true,nil,true,nil);
SW_InitVar("SPELLLOGCRITSELFSELF",{3,51},true,true,true,nil);
SW_InitVar("SPELLLOGOTHEROTHER",{2,3,1,51},nil,nil,nil,nil);
SW_InitVar("SPELLLOGOTHERSELF",{2,3,51},nil,true,nil,nil);
SW_InitVar("SPELLLOGSCHOOLOTHEROTHER",{2,3,1,51,7},nil,nil,nil,nil);
SW_InitVar("SPELLLOGSCHOOLOTHERSELF",{2,3,51,7},nil,true,nil,nil);
SW_InitVar("SPELLLOGSCHOOLSELFOTHER",{3,1,51,7},true,nil,nil,nil);
SW_InitVar("SPELLLOGSCHOOLSELFSELF",{3,51,7},true,true,nil,nil);
SW_InitVar("SPELLLOGSELFOTHER",{3,1,51},true,nil,nil,nil);
SW_InitVar("SPELLLOGSELFSELF",{3,51},true,true,nil,nil);
if LOCALE_enGB or LOCALE_enUS then
SW_InitVar("SPELLPOWERDRAINOTHEROTHER",{2,3,54,8,1},nil,nil,nil,true);
SW_InitVar("SPELLPOWERDRAINOTHERSELF",{2,3,54,8},nil,true,nil,true);
else
SW_InitVar("SPELLPOWERDRAINOTHEROTHER",{2,3,54,8,1},nil,nil,nil,nil);
SW_InitVar("SPELLPOWERDRAINOTHERSELF",{2,3,54,8},nil,true,nil,nil);
end
SW_InitVar("SPELLPOWERDRAINSELFOTHER",{3,54,8,1},true,nil,nil,nil);
SW_InitVar("SPELLPOWERLEECHOTHEROTHER",{2,3,54,8,1,10,65,9},nil,nil,nil,nil);
SW_InitVar("SPELLPOWERLEECHOTHERSELF",{2,3,54,8,10,65,9},nil,true,nil,nil);
SW_InitVar("SPELLPOWERLEECHSELFOTHER",{3,54,8,1,65,9},true,nil,nil,nil);
SW_InitVar("SPELLSPLITDAMAGEOTHEROTHER",{2,3,1,51},nil,nil,nil,nil);
SW_InitVar("SPELLSPLITDAMAGEOTHERSELF",{2,3,51},nil,true,nil,nil);
SW_InitVar("SPELLSPLITDAMAGESELFOTHER",{2,1,51},nil,nil,nil,nil);
SW_InitVar("VSENVIRONMENTALDAMAGE_DROWNING_OTHER",{1,51},nil,nil,nil,nil);
SW_InitVar("VSENVIRONMENTALDAMAGE_DROWNING_SELF",{51},nil,true,nil,nil);
SW_InitVar("VSENVIRONMENTALDAMAGE_FALLING_OTHER",{1,51},nil,nil,nil,nil);
SW_InitVar("VSENVIRONMENTALDAMAGE_FALLING_SELF",{51},nil,true,nil,nil);
SW_InitVar("VSENVIRONMENTALDAMAGE_FATIGUE_OTHER",{1,51},nil,nil,nil,nil);
SW_InitVar("VSENVIRONMENTALDAMAGE_FATIGUE_SELF",{51},nil,true,nil,nil);
SW_InitVar("VSENVIRONMENTALDAMAGE_FIRE_OTHER",{1,51},nil,nil,nil,nil);
SW_InitVar("VSENVIRONMENTALDAMAGE_FIRE_SELF",{51},nil,true,nil,nil);
SW_InitVar("VSENVIRONMENTALDAMAGE_LAVA_OTHER",{1,51},nil,nil,nil,nil);
SW_InitVar("VSENVIRONMENTALDAMAGE_LAVA_SELF",{51},nil,true,nil,nil);
SW_InitVar("VSENVIRONMENTALDAMAGE_SLIME_OTHER",{1,51},nil,nil,nil,nil);
SW_InitVar("VSENVIRONMENTALDAMAGE_SLIME_SELF",{51},nil,true,nil,nil);
--1.4 removed in wow 1.10
-- it doesn't hurt to leave them in for easy transition 1.9->1.10
--[[
SW_InitVar("POWERGAIN_OTHER",{1,53,3},nil,nil,nil,true);
SW_InitVar("POWERGAIN_SELF",{53,3},nil,true,nil,true);
SW_InitVar("GENERICPOWERGAIN_OTHER",{1,53,3},nil,nil,nil,true);
SW_InitVar("GENERICPOWERGAIN_SELF",{53,3},nil,true,nil,true);
--]]
--1.4 wow 1.10 changed powergain stuff
-- mana/ health etc isnt really a "LeechTo" but this fits best
-- 1.5.1 selfself and selfother changed to late sort
SW_InitVar("POWERGAINOTHEROTHER",{1,53,9,2,3},nil,nil,nil,nil);
SW_InitVar("POWERGAINOTHERSELF",{53,9,2,3},nil,true,nil,nil);
SW_InitVar("POWERGAINSELFOTHER",{1,53,9,3},true,nil,nil,true);
SW_InitVar("POWERGAINSELFSELF",{53,9,3},true,true,nil,true);
--1.4 wow 1.10 aura stuff
SW_InitVar("AURAAPPLICATIONADDEDOTHERHARMFUL",{1,3,53},nil,nil,nil,nil);
SW_InitVar("AURAAPPLICATIONADDEDOTHERHELPFUL",{1,3,53},nil,nil,nil,nil);
SW_InitVar("AURAAPPLICATIONADDEDSELFHARMFUL",{3,53},nil,true,nil,nil);
SW_InitVar("AURAAPPLICATIONADDEDSELFHELPFUL",{3,53},nil,true,nil,nil);
-- 1.5.1 for decursing (could be used for more)
SW_InitVar("SIMPLECASTOTHEROTHER",{2,3,1},nil,nil,nil,nil);
SW_InitVar("SIMPLECASTOTHERSELF",{2,3},nil,true,nil,nil);
SW_InitVar("SIMPLECASTSELFOTHER",{3,1},true,nil,nil,nil);
SW_InitVar("SIMPLECASTSELFSELF",{3},true,true,nil,true);
-- this one is very generic %s casts %s
-- could use this to count totem placement
--SW_InitVar("SPELLCASTGOOTHER",{2,3},nil,nil,nil,true);
-- 1.5.3.beta.1 Added but not used, but will cause blocking events w/o
-- noticed this through the curse patchwerk kill video ;)
SW_InitVar("COMBATLOG_HONORGAIN",{1,3,53},true,nil,nil,nil);
SW_SL_SetLastOk();
end
local function SW_AddToMap(eventName, regexName, map)
if map == nil then map = SW_EventRegexMap; end
-- first check if we have the info needed
--added this for WOW 1.10 POWERGAINXX changes
if SW_RegEx_Lookup[regexName] == nil then
--DEFAULT_CHAT_FRAME:AddMessage(regexName);
return;
end
if SW_RegEx_Lookup[regexName]["r"] == nil then return; end
if map[eventName] == nil then
map[eventName] ={};
end
--use insert we want to sort this later using table.sort
table.insert(map[eventName], regexName);
SW_SL_RegExAdded = SW_SL_RegExAdded +1;
end
--[[ this resorts SW_EventRegexMap based on the regular expression
to be used
This is done to minimize the chance of a collision
rule 1 -> anything that starts with a string and not a capture goes first
rule 2 -> if it starts with a capture not followed by a space it goes first
rule 3 - > less captures go first
rule 4 -> longer strings go first
]]--
local function recuCheck(a, b, opt)
local l = SW_RegEx_Lookup[a]["r"];
local r = SW_RegEx_Lookup[b]["r"];
if opt == nil then
local sl = string.sub(l,2,2);
local sr = string.sub(r,2,2);
if sl == "(" then
if sr == "(" then
return recuCheck(a, b, 1);
else
return false;
end
else
if sr == "(" then
return true;
else
return recuCheck(a, b, 1);
end
end
elseif opt == 1 then
if SW_RegEx_Lookup[a]["ls"] and SW_RegEx_Lookup[b]["ls"] then
return recuCheck(a, b, 2);
end
if SW_RegEx_Lookup[a]["ls"] then
return false;
end
if SW_RegEx_Lookup[b]["ls"] then
return true;
end
return recuCheck(a, b, 2);
elseif opt == 2 then
local sl = string.sub(l,1,5);
local sr = string.sub(r,1,5);
local slf = string.sub(l,1,2);
if sl == sr and slf == "^(" then
sl = string.sub(l,6,6);
sr = string.sub(r,6,6);
if sl == sr then
return recuCheck(a, b, 3);
else
if sl == " " then
return false;
elseif sr == " " then
return true;
else
return recuCheck(a, b, 3);
end
end
else
return recuCheck(a, b, 3);
end
elseif opt == 3 then
if SW_RegEx_Lookup[a]["i"] == SW_RegEx_Lookup[b]["i"] then
return recuCheck(a, b, 4);
else
return SW_RegEx_Lookup[a]["i"] < SW_RegEx_Lookup[b]["i"];
end
elseif opt == 4 then
return string.len(l) > string.len(r);
else
return false;
end
end
local function SW_finalizeMap()
SW_SL_Add(SW_SL["MAP_SORT"]);
for k,v in pairs(SW_EventRegexMap) do
table.sort(v,
function(a,b)
return recuCheck(a,b);
end);
end
SW_SL_SetLastOk();
end
function SW_CreateEventRegexMap()
SW_SL_Add(SW_SL["MAP"]);
-- first we need the "dummy" for non handeled events
-- added an extra "dummy" for text only events --SW_DECURSEDUMMY
for k,_ in pairs(SW_RegEx_Lookup) do
if string.sub(k,1,string.len("SIMPLECAST"))=="SIMPLECAST" or string.sub(k,1,string.len("SPELLCASTGO"))=="SPELLCASTGO" then
SW_AddToMap(SW_DECURSEDUMMY, k);
else
SW_AddToMap(SW_DEV_EVENTDUMMY, k);
end
end
for k,v in pairs(SW_Map) do
for _, regExName in pairs(v) do
SW_AddToMap(k, regExName);
end
end
for k,v in pairs(SW_EnviroMap) do
for _, regExName in pairs(v) do
SW_AddToMap(k, regExName, SW_EventRegexMapEnviro);
end
end
SW_SL_SetLastOk();
SW_finalizeMap();
-- pulling the SW_TmpMap info here, its already sorted
--[[
for i,v in ipairs(SW_EventRegexMap[SW_DEV_EVENTDUMMY]) do
local tmp = string.sub(SW_RegEx_Lookup[v]["r"],1,4);
if tmp == "(.+)" then
tmp = string.sub(SW_RegEx_Lookup[v]["r"],5,5);
if tmp ~= " " then
if SW_TmpMap == nil then SW_TmpMap = {}; end
table.insert(SW_TmpMap, v);
end
end
end
--]]
end;
-- this is called if there was no direct Event->Regexp entry
-- and a regex was found using the event dummy
function SW_lateAdd(eventName, regexName, map, saveToMap, checkDupes)
if checkDupes then
for _,v in ipairs(map[eventName]) do
if v == regexName then return; end
end
end
SW_AddToMap(eventName, regexName, map);
table.sort(map[eventName],
function(a,b)
return recuCheck(a,b);
end);
-- now add it to the map thats saved
if saveToMap ~= nil then
if saveToMap[eventName] == nil then
saveToMap[eventName] ={};
end
table.insert(saveToMap[eventName], regexName);
end
end
------------------------- Events to listen to --------------------------------
--[[
1.5 added pausing and unpausing of data collection
so changed the event definition here and split it into 2 parts
events that have to be on always, and events that can be switched
--]]
SW_EventCollection = {
SW_EventsMandatory = {
"PLAYER_TARGET_CHANGED",
"VARIABLES_LOADED",
--"UNIT_COMBAT", hmm i wasn't using this?
"UNIT_PET",
"PARTY_MEMBERS_CHANGED",
"PARTY_LEADER_CHANGED",
"RAID_ROSTER_UPDATE",
"PLAYER_ENTERING_WORLD",
-- for joining
"CHAT_MSG_GUILD",
"CHAT_MSG_OFFICER",
"CHAT_MSG_PARTY",
"CHAT_MSG_RAID",
"CHAT_MSG_CHANNEL",
-- 1.5.3 added in wow 1.11
"CHAT_MSG_RAID_LEADER",
-- 1.5.beta.2 this better not be off DOH
"SPELLS_CHANGED",
},
SW_EventsSwitched = {
"CHAT_MSG_COMBAT_CREATURE_VS_CREATURE_HITS",
"CHAT_MSG_COMBAT_CREATURE_VS_CREATURE_MISSES",
"CHAT_MSG_COMBAT_CREATURE_VS_PARTY_HITS",
"CHAT_MSG_COMBAT_CREATURE_VS_PARTY_MISSES",
"CHAT_MSG_COMBAT_CREATURE_VS_SELF_HITS",
"CHAT_MSG_COMBAT_CREATURE_VS_SELF_MISSES",
"CHAT_MSG_COMBAT_FRIENDLYPLAYER_HITS",
"CHAT_MSG_COMBAT_FRIENDLYPLAYER_MISSES",
"CHAT_MSG_COMBAT_FRIENDLY_DEATH",
"CHAT_MSG_COMBAT_HONOR_GAIN",
"CHAT_MSG_COMBAT_HOSTILEPLAYER_HITS",
"CHAT_MSG_COMBAT_HOSTILEPLAYER_MISSES",
"CHAT_MSG_COMBAT_HOSTILE_DEATH",
"CHAT_MSG_COMBAT_LOG_ERROR",
"CHAT_MSG_COMBAT_LOG_MISC_INFO",
"CHAT_MSG_COMBAT_PARTY_HITS",
"CHAT_MSG_COMBAT_PARTY_MISSES",
"CHAT_MSG_COMBAT_PET_HITS",
"CHAT_MSG_COMBAT_PET_MISSES",
"CHAT_MSG_COMBAT_SELF_HITS",
"CHAT_MSG_COMBAT_SELF_MISSES",
"CHAT_MSG_SPELL_CREATURE_VS_CREATURE_BUFF",
"CHAT_MSG_SPELL_CREATURE_VS_CREATURE_DAMAGE",
"CHAT_MSG_SPELL_CREATURE_VS_PARTY_BUFF",
"CHAT_MSG_SPELL_CREATURE_VS_PARTY_DAMAGE",
"CHAT_MSG_SPELL_CREATURE_VS_SELF_BUFF",
"CHAT_MSG_SPELL_CREATURE_VS_SELF_DAMAGE",
"CHAT_MSG_SPELL_DAMAGESHIELDS_ON_OTHERS",
"CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF",
"CHAT_MSG_SPELL_FRIENDLYPLAYER_BUFF",
"CHAT_MSG_SPELL_FRIENDLYPLAYER_DAMAGE",
"CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF",
"CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE",
"CHAT_MSG_SPELL_PARTY_BUFF",
"CHAT_MSG_SPELL_PARTY_DAMAGE",
"CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS",
"CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE",
"CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS",
"CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_DAMAGE",
"CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS",
"CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE",
"CHAT_MSG_SPELL_PERIODIC_PARTY_BUFFS",
"CHAT_MSG_SPELL_PERIODIC_PARTY_DAMAGE",
"CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS",
"CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE",
"CHAT_MSG_SPELL_PET_BUFF",
"CHAT_MSG_SPELL_PET_DAMAGE",
"CHAT_MSG_SPELL_SELF_BUFF",
"CHAT_MSG_SPELL_SELF_DAMAGE",
"PLAYER_REGEN_DISABLED",
"PLAYER_REGEN_ENABLED",
-- added for 1.3.0 to get mana efficiency
"SPELLCAST_CHANNEL_START",
"SPELLCAST_STOP",
"SPELLCAST_FAILED",
"SPELLCAST_INTERRUPTED",
-- added 1.4 for death count
"CHAT_MSG_COMBAT_FRIENDLY_DEATH",
"CHAT_MSG_COMBAT_HOSTILE_DEATH",
},
}
function SW_UnpauseEvents()
local coreFrame = getglobal("SW_CoreFrame");
for i, val in ipairs(SW_EventCollection.SW_EventsSwitched) do
coreFrame:RegisterEvent(val);
end
end
function SW_PauseEvents()
local coreFrame = getglobal("SW_CoreFrame");
for i, val in ipairs(SW_EventCollection.SW_EventsSwitched) do
coreFrame:UnregisterEvent(val);
end
end
function SW_RegisterEvents()
SW_SL_Add(SW_SL["EVENTS"]);
for i, val in ipairs(SW_EventCollection.SW_EventsMandatory) do
this:RegisterEvent(val);
end
--[[
-- used to check what kinds of targets are tracked
this:RegisterEvent("PLAYER_TARGET_CHANGED");
--this:RegisterEvent("CHAT_MSG_CHANNEL_LIST");
this:RegisterEvent("VARIABLES_LOADED");
this:RegisterEvent("UNIT_COMBAT");
this:RegisterEvent("UNIT_PET");
this:RegisterEvent("PARTY_MEMBERS_CHANGED");
-- 1.4.2 added leader change
this:RegisterEvent("PARTY_LEADER_CHANGED");
this:RegisterEvent("RAID_ROSTER_UPDATE");
this:RegisterEvent("PLAYER_ENTERING_WORLD");
--this:RegisterEvent("CHAT_MSG_AFK");
--this:RegisterEvent("CHAT_MSG_BG_SYSTEM_ALLIANCE");
--this:RegisterEvent("CHAT_MSG_BG_SYSTEM_HORDE");
--this:RegisterEvent("CHAT_MSG_BG_SYSTEM_NEUTRAL");
--this:RegisterEvent("CHAT_MSG_CHANNEL_LIST");
this:RegisterEvent("CHAT_MSG_COMBAT_CREATURE_VS_CREATURE_HITS");
this:RegisterEvent("CHAT_MSG_COMBAT_CREATURE_VS_CREATURE_MISSES");
this:RegisterEvent("CHAT_MSG_COMBAT_CREATURE_VS_PARTY_HITS");
this:RegisterEvent("CHAT_MSG_COMBAT_CREATURE_VS_PARTY_MISSES");
this:RegisterEvent("CHAT_MSG_COMBAT_CREATURE_VS_SELF_HITS");
this:RegisterEvent("CHAT_MSG_COMBAT_CREATURE_VS_SELF_MISSES");
this:RegisterEvent("CHAT_MSG_COMBAT_FRIENDLYPLAYER_HITS");
this:RegisterEvent("CHAT_MSG_COMBAT_FRIENDLYPLAYER_MISSES");
this:RegisterEvent("CHAT_MSG_COMBAT_FRIENDLY_DEATH");
this:RegisterEvent("CHAT_MSG_COMBAT_HONOR_GAIN");
this:RegisterEvent("CHAT_MSG_COMBAT_HOSTILEPLAYER_HITS");
this:RegisterEvent("CHAT_MSG_COMBAT_HOSTILEPLAYER_MISSES");
this:RegisterEvent("CHAT_MSG_COMBAT_HOSTILE_DEATH");
this:RegisterEvent("CHAT_MSG_COMBAT_LOG_ERROR");
this:RegisterEvent("CHAT_MSG_COMBAT_LOG_MISC_INFO");
--this:RegisterEvent("CHAT_MSG_COMBAT_MISC_INFO");
this:RegisterEvent("CHAT_MSG_COMBAT_PARTY_HITS");
this:RegisterEvent("CHAT_MSG_COMBAT_PARTY_MISSES");
this:RegisterEvent("CHAT_MSG_COMBAT_PET_HITS");
this:RegisterEvent("CHAT_MSG_COMBAT_PET_MISSES");
this:RegisterEvent("CHAT_MSG_COMBAT_SELF_HITS");
this:RegisterEvent("CHAT_MSG_COMBAT_SELF_MISSES");
--this:RegisterEvent("CHAT_MSG_COMBAT_XP_GAIN");
--this:RegisterEvent("CHAT_MSG_DND");
--this:RegisterEvent("CHAT_MSG_EMOTE");
this:RegisterEvent("CHAT_MSG_GUILD");
--this:RegisterEvent("CHAT_MSG_IGNORED");
--this:RegisterEvent("CHAT_MSG_LOOT");
--this:RegisterEvent("CHAT_MSG_MONSTER_EMOTE");
--this:RegisterEvent("CHAT_MSG_MONSTER_SAY");
--this:RegisterEvent("CHAT_MSG_MONSTER_WHISPER");
--this:RegisterEvent("CHAT_MSG_MONSTER_YELL");
this:RegisterEvent("CHAT_MSG_OFFICER");
this:RegisterEvent("CHAT_MSG_PARTY");
this:RegisterEvent("CHAT_MSG_RAID");
this:RegisterEvent("CHAT_MSG_CHANNEL");
--this:RegisterEvent("CHAT_MSG_SKILL");
--this:RegisterEvent("CHAT_MSG_SPELL_AURA_GONE_OTHER");
--this:RegisterEvent("CHAT_MSG_SPELL_AURA_GONE_PARTY");
--this:RegisterEvent("CHAT_MSG_SPELL_AURA_GONE_SELF");
--this:RegisterEvent("CHAT_MSG_SPELL_BREAK_AURA");
this:RegisterEvent("CHAT_MSG_SPELL_CREATURE_VS_CREATURE_BUFF");
this:RegisterEvent("CHAT_MSG_SPELL_CREATURE_VS_CREATURE_DAMAGE");
this:RegisterEvent("CHAT_MSG_SPELL_CREATURE_VS_PARTY_BUFF");
this:RegisterEvent("CHAT_MSG_SPELL_CREATURE_VS_PARTY_DAMAGE");
this:RegisterEvent("CHAT_MSG_SPELL_CREATURE_VS_SELF_BUFF");
this:RegisterEvent("CHAT_MSG_SPELL_CREATURE_VS_SELF_DAMAGE");
this:RegisterEvent("CHAT_MSG_SPELL_DAMAGESHIELDS_ON_OTHERS");
this:RegisterEvent("CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF");
this:RegisterEvent("CHAT_MSG_SPELL_FRIENDLYPLAYER_BUFF");
this:RegisterEvent("CHAT_MSG_SPELL_FRIENDLYPLAYER_DAMAGE");
this:RegisterEvent("CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF");
this:RegisterEvent("CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE");
this:RegisterEvent("CHAT_MSG_SPELL_PARTY_BUFF");
this:RegisterEvent("CHAT_MSG_SPELL_PARTY_DAMAGE");
this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS");
this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE");
this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS");
this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_DAMAGE");
this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS");
this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE");
this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_PARTY_BUFFS");
this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_PARTY_DAMAGE");
this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS");
this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE");
this:RegisterEvent("CHAT_MSG_SPELL_PET_BUFF");
this:RegisterEvent("CHAT_MSG_SPELL_PET_DAMAGE");
this:RegisterEvent("CHAT_MSG_SPELL_SELF_BUFF");
this:RegisterEvent("CHAT_MSG_SPELL_SELF_DAMAGE");
--this:RegisterEvent("CHAT_MSG_SPELL_TRADESKILLS");
--this:RegisterEvent("CHAT_MSG_SYSTEM");
--this:RegisterEvent("CHAT_MSG_TEXT_EMOTE");
--this:RegisterEvent("CHAT_MSG_WHISPER");
--this:RegisterEvent("CHAT_MSG_WHISPER_INFORM");
--this:RegisterEvent("CHAT_MSG_SAY");
--this:RegisterEvent("SPELLCAST_STOP");
--this:RegisterEvent("UNIT_HEALTH");
-- added for 1.3.0 to get mana efficiency
this:RegisterEvent("SPELLCAST_CHANNEL_START");
--this:RegisterEvent("SPELLCAST_START");
this:RegisterEvent("SPELLCAST_STOP");
this:RegisterEvent("SPELLCAST_FAILED");
this:RegisterEvent("SPELLCAST_INTERRUPTED");
this:RegisterEvent("SPELLS_CHANGED");
this:RegisterEvent("PLAYER_REGEN_DISABLED");
this:RegisterEvent("PLAYER_REGEN_ENABLED");
-- added 1.4 for death count
this:RegisterEvent("CHAT_MSG_COMBAT_FRIENDLY_DEATH");
this:RegisterEvent("CHAT_MSG_COMBAT_HOSTILE_DEATH");
--this:RegisterEvent("SPELLCAST_DELAYED");
--this:RegisterEvent("SPELLCAST_CHANNEL_START");
--this:RegisterEvent("SPELLCAST_CHANNEL_UPDATE");
--]]
SW_SL_SetLastOk();
end
--[[
A wrapper arround timing
If added to saved variables (and inited again)
will retain cross session seconds ( and milliseconds)
to save it accross sessions add myTimer to SavedVariables AND IN
VARIABLES_LOADED: myTimer = SW_C_Timer:new(myTimer);
--]]
SW_C_Timer = {
-- epoch time at init
epochInit = time(),
-- system up time at init
upTimeInit = GetTime(),
new = function (self, o)
o = o or {};
setmetatable(o, self);
self.__index = self;
if o.epochTS ~= nil then
o.uTS = (o.epochTS + o.msO) - self.epochInit ;
else
self.setToNow(o);
end
return o;
end,
setToNow = function(self)
self.epochTS = time();
self.uTS = GetTime() - self.upTimeInit;
-- store the millisecond offset
self.msO = self.uTS - (self.epochTS - self.epochInit);
end,
-- now return value is not to be used cross session (don't save it)
now = function(self)
return GetTime() - self.upTimeInit;
end,
elapsed = function(self)
return self.msRound((GetTime() - self.upTimeInit) - self.uTS);
end,
-- one must be a timer object, the other value may be a number
-- only numbers recieved through :now() make sense
__sub = function(lh, rh)
if type(rh) == "number" then
return lh.uTS - rh;
elseif type(lh) == "number" then
return lh - rh.uTS;
else
return lh.msRound(lh.uTS - rh.uTS);
end
end,
msRound = function(val)
return math.floor((val) * 1000 + 0.5)/1000;
end,
absDiff = function(self, rh)
local ret = self - rh;
if ret < 0 then ret = -ret; end
return ret;
end,
-- seconds since startup
SSS = function(self)
return GetTime() - self.upTimeInit;
end,
dump = function(self)
SW_DumpTable(self);
end,
}
--------- My fun function so don't complain
SW_RND_Strings = {
["CWATER"] = {
"pinkelt in eine Flasche...",
"erleichtert sich.",
"machts euch in Kirschgeschmack.",
"denkt 'Wasser, ja Wasser wollte Ich schon immer machen.'",
"macht euch ein POWER drink.",
"ahhh, besser!",
"sammelt seine Tr\195\164nen in einer Flasche",
"macht noch mehr Blubberwasser.",
"sagt euch da\195\159 Er kein Bier herbeizaubern kann.",
"machts euch in Pfirsichgeschmack",
"zieht die Nase hoch...",
"kriegt ein mulmiges Gefuehl im Magen.",
},
["CBREAD"] = {
"backe backe BROT!",
"schmei\195\159t euch Brot an den Kopf!",
"hat einen eigenartigen Gesichtsausdruck.",
"PLOP!",
"transmutiert Luft zu Brot.",
"sucht sich ein B\195\164ckermeister.",
},
};
function SW_GetRndString(baseIndex)
if SW_RND_Strings[baseIndex] == nil then return; end
local index = math.random(table.getn(SW_RND_Strings[baseIndex]));
SendChatMessage(SW_RND_Strings[baseIndex][index], "EMOTE");
end
-------------------------- Dump Functions mostly for dev --------------------
function SW_printStr(str, toChannelNR)
local chNR =1;
if SW_DEV_INWOW then
if toChannelNR ~= nil then chNR = toChannelNR; end
local con = getglobal("SW_FrameConsole_Text"..chNR.."_MsgFrame");
if con ~= nil then
if str == nil then
con:AddMessage("NIL");
elseif type(str) == "boolean" then
local v2 = "Bool:false";
if str then
v2 = "Bool:true";
end
SW_printStr (v2);
else
con:AddMessage(str);
end
--con:ScrollToBottom();
end
else
print(str);
end
end
function SW_DumpKeys(table)
if table ==nil then return; end
if type(table) ~= "table" then return; end
SW_printStr("-- KEYS -- ");
for k, v in pairs (table) do
SW_printStr(k);
end
end
function SW_DumpTable(table, ds, ch, hideKey)
if ch == nil then ch = 1; end
if table ==nil then return "table is nil"; end
if ds == nil then
ds=""
SW_printStr("----------------------");
end
for k, v in pairs (table) do
if type(v) ~= "table" then
if v == nil then
if hideKey then
SW_printStr (ds.."NIL", ch);
else
SW_printStr (ds.."["..k.."]=NIL", ch);
end
elseif type(v) == "boolean" then
local v2 = "Bool:false";
if v then
v2 = "Bool:true";
end
if hideKey then
SW_printStr (ds..v2, ch);
else
SW_printStr (ds.."["..k.."]="..v2, ch);
end
elseif type(v) == "function" then
if hideKey then
SW_printStr (ds.."function", ch);
else
SW_printStr (ds.."["..k.."]=function", ch);
end
else
if hideKey then
SW_printStr (ds..v, ch);
else
SW_printStr (ds.."["..k.."]="..v, ch);
end
end
else
if not hideKey then
SW_printStr (ds.."["..k.."]=", ch);
end
SW_DumpTable(v, ds.." ");
end
end
end
function SW_DumpRegs()
for k,v in pairs (SW_RegEx_Lookup) do
if v["r"] == nil then
SW_printStr(k.." EMPTY <- No global found with this name");
else
SW_printStr(k.." "..v["r"]);
end
end
end
function SW_DumpResultList(...)
local i = 1;
local ret = "";
while arg[i] ~= nil do
ret = ret..arg[i].." ";
i = i + 1;
end
SW_printStr(ret);
end
function SW_DumpFMAsVar()
SW_printStr("SW_DefaultMap={");
for k, v in pairs (SW_DEV_FINDMATCH) do
SW_printStr("\t[\""..k.."\"] = {") ;
for e, _ in pairs (v) do
-- dont add VSENVIRONMENTALDAMAGE
if string.sub(e,1,string.len("VSENVIRONMENTALDAMAGE"))~="VSENVIRONMENTALDAMAGE" then
SW_printStr("\t\t\""..e.."\",") ;
end
end
SW_printStr("\t},") ;
end
SW_printStr("}");
end
Generated by GNU Enscript 1.6.5.90.