-- 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