Compare with Previous | Blame | View Log
-- AKA -- Author: Lon Koenig -- License: Creative Commons Attribution-Noncommercial 3.0 Unported License (see Readme.txt) -- Globals: -- ======== -- AKASavedVars = {}; AKA_Version=2.8; AKA_HighestSeenVersion=0; AKA_FormatVersion=1.2; AKA_variablesLoaded = false; AKA_RaidInfoByName = {}; local VISIBLE_MAX=17; -- for scrolling menu AKA_DEBUG=false; AKA_ShowEvent=false; AKA_TRAFFICMONITOR=false; AKA_LinkedName=nil; -- keep this global for testing AKA_LinkedName=""; AKA_USERID=nil; AKA_LastSeen={}; AKAPrefs_PanelFrames ={"AKAUsersPanel","AKAOptionsPanel"}; AKAPrefs_CurrentPanel=0; AKA_ToonListDirty=true; -- whether we need to redraw the scrolling character list AKA_SessionList={}; AKA_PendingWhispers={}; AKA_GuildNotes={}; -- data structures -- -- AKASavedVars={ -- AKA_Defaults["MyToons"]={ -- ToonID -- toon Name + "**" + Realm name -- {"name"=name, etc. -- list below in messageFields -- }; -- AKA_Defaults["FriendToons"] ={ -- same format as MyToons -- -- Locals: -- ======= -- constants: local MYADDON_NAME = "AKA"; local MYADDON_VERSION = "2.8"; local MYADDON_AUTHOR = "Schnoggo"; local MYADDON_EMAIL = "schnoggo@gmail.com"; local MYADDON_WEBSITE = "http://war-monkey.com/files/"; local OPTIONS_FRAME = "AKA_PrefsFrame"; local MSG_DELIMITER="`"; local REQ_TOKEN="R3Q"; local HEARTBEAT_INTERVAL = 3.0; -- how many seconds per heartbeat of our internal timer local NOISE_THRESHHOLD = 2.5; -- how many seconds must pass before we consider the channel clear local TRANSMIT_INTERVAL = .5; -- how many seconds between our own messages local MSG_PREFIX = "AKAT2_"; local CHANNEL_PREFIX="<AKA_"; local GUILD_NOTE_STRINGS={}; GUILD_NOTE_STRINGS[0]=""; -- none, GUILD_NOTE_STRINGS[1]='%s-(%a-)%A+.*$'; -- 1st word GUILD_NOTE_STRINGS[2]='.*%((.*)%).-$'; -- parenthese GUILD_NOTE_STRINGS[3]='.*%[(.*)%].-$'; --brackets GUILD_NOTE_STRINGS[4]='[aA][lL][tT]%s+(%a-).-$'; --ALT primary char name local BASE64={ "0","1","2","3","4","5", "6","7","8","9","A","B", "C","D","E","F","G","H", "I","J","K","L","M","N", "O","P","Q","R","S","T", "U","V","W","X","Y","Z", "a","b","c","d","e","f", "g","h","i","j","k","l", "m","n","o","p","q","r", "s","t","u","v","w","x", "y","z","+","/"}; local BASE10={}; -- build reverse table for professions: (For compressing Profession skill names AKA_ProfessionIndex = {}; for k, v in pairs (AKA_ProfessionList) do AKA_ProfessionIndex[v] = k; end -- build reverse table for races: (For compressing race names) AKA_RaceIndex = {}; for k, v in pairs (AKA_RaceList) do AKA_RaceIndex[v] = k; end local MESSAGE_FORMAT=BASE64[1]; -- version 1 local messageFields={ "name", "userid", "nickname", "class", "race", "guild", "level", "profession1", "profession2", "realm", "zone", "note"}; local displayFields={ "name","nickname","level","gender","race","class","prof1name", "prof1skill","prof2name","prof2skill", "zone"}; local tooltipFields={ "name","level","gender","race","class","prof1name", "prof1skill","prof2name","prof2skill", "zone"}; local tooltipDelimiters={ ": ", " ", " ", " ", " ", " ", " ", " ", " ", ""}; local daysAtyear={}; daysAtyear[2004]=-364; daysAtyear[2005]=0; daysAtyear[2006]=365; daysAtyear[2007]=730; daysAtyear[2008]=1095; daysAtyear[2009]=1460; daysAtyear[2010]=1824; -- date stuff: local wowEpoch=38; -- Nove 23, was 38 days from end of year 2004 local todayTable=date("*t"); local TODAY=daysAtyear[todayTable["year"]]+todayTable["yday"]+wowEpoch; -- days at year start + day-of-year -- TODAY is an integer of days since game launch -- if the user never logs out, calculating this only here could be a problem local myPlayerRealm=GetCVar("realmName"); local myPlayerName=UnitName("player"); local myPlayerClassText, myPlayerClassType = UnitClass("player"); local myPlayerID=myPlayerName.."**"..myPlayerRealm; local myPlayerZone=""; local myPlayerFaction, myLocalizedFaction=UnitFactionGroup("player"); local DEFAULT_COM_CHANNELS={}; DEFAULT_COM_CHANNELS["Guild"]={}; DEFAULT_COM_CHANNELS["Guild"]["active"]="yes"; DEFAULT_COM_CHANNELS["Raid"]={}; DEFAULT_COM_CHANNELS["Raid"]["active"]="no"; DEFAULT_COM_CHANNELS["Chat"]={}; DEFAULT_COM_CHANNELS["Chat"]["active"]="no"; local guildieNames={}; local guildiePlayers={}; -- default config settings local AKA_Defaults={}; AKA_Defaults["MyToons"]={}; AKA_Defaults["FriendToons"]={}; AKA_Defaults["AKA_PrefsShowMeCheck"]=false; AKA_Defaults["realmchannels"]={}; -- AKA_Defaults["MyNickname"]="*pending*"; AKA_Defaults["MyNickname"]=UnitName("player"); -- just to get them started -- scoped vars: local secondsSinceUpdate = 0; local pendingSingleAnnounce=false; local secondsUntilMyRequest = 0; local secondsSinceLastMsg = 0; local secondsSinceLastScreenDraw = 0; local needHello=true; local hasHookedChat=false; local hasHookedCalendar=false; local original_CalendarDayButton_OnEnter = nil; local originalChatFrame_OnEvent = nil; local hasHookedGatherer=false; local originalGathererChat=nil; -- gatherer chat function is Gatherer.Util.ChatPrint in GatherUtil.lua local hasHookedChatLink=false; local originalSetItemRef = nil; local MessagesSentPerChannel={}; MessagesSentPerChannel["GUILD"]=0; MessagesSentPerChannel["RAID"]=0; MessagesSentPerChannel["PARTY"]=0; MessagesSentPerChannel["WHISPER"]=0; local MessagesRxPerChannel={}; MessagesRxPerChannel["GUILD"]=0; MessagesRxPerChannel["RAID"]=0; MessagesRxPerChannel["PARTY"]=0; MessagesRxPerChannel["WHISPER"]=0; local pendingRequests={}; local k,v; -- My local functions: -- ==================== local function UnpackProfession(packedProf) -- AKA_ProfessionList end local function NoNull(inString) if (inString == nil) then return "" else return inString end end local function UpdateRadios() local guildNoteOption=AKA_SavedVars["MyToons"][myPlayerID]["guildnotes"]; if (guildNoteOption==nil) then guildNoteOption=0; end for i = 0, 4 do if (i==guildNoteOption) then getglobal("AKA_Prefs_RB"..i):SetChecked(true); else getglobal("AKA_Prefs_RB"..i):SetChecked(false); end i=i+1; end end function tcount(tab) local n=0; local k,v; for k,v in pairs(tab) do n=n+1; end return n; end local function Dec2BASE64(inDec) -- Convert numeric value into Base64 string -- Inputs: -- inDec - INT *NOTE* This MUST be an integer in this implementation -- Outputs: -- return numeric value local outStr=""; local tDec = inDec; -- make a copy to destroy local rem,dig; while (tDec>63) do rem=mod(tDec, 64); dig=BASE64[rem+1]; outStr=dig..outStr; tDec=tDec-rem; tDec=tDec/64; end dig=BASE64[tDec+1]; outStr=dig..outStr; return outStr; end local function BASE642Dec(in64) -- Convert Base64 string into decimal number -- Inputs: -- in64 - STR -- Outputs: -- return numeric value local res=0; local len=strlen(in64); for i=1, len do res=res+BASE10[strsub(in64, i, i)]; if (i ~= len) then res=res*64; end end return res; end local function InitMath() -- Creates reverse lookup table for Base64 routines -- BASE64 must be created and populated -- BASE10 must be declared and scoped -- populates BASE10 BASE10={}; for i=1, 64 do BASE10[BASE64[i]]=i-1; end end local function GenerateUSERID() -- UserId format is -- char 1 - flags (None defined, current value must be 0) -- chars 2-6 Base64 digits (this yields slightly over 1 billion possibilities. Close enough to unique for our purposes) local outStr="0"; -- noflags currently defined for i = 1, 5 do outStr=outStr..BASE64[random(64)]; end return outStr; end local function ShowSpells() AKA_SpellBookList={}; local i = 1 while true do local spellName, spellRank = GetSpellName(i, BOOKTYPE_SPELL) if not spellName then do break end end table.insert(AKA_SpellBookList,"'"..spellName .."'".. "(" .. spellRank .. ")"); DEFAULT_CHAT_FRAME:AddMessage( "'"..spellName .."'".. "(" .. spellRank .. ")" ); i = i + 1 end end local function GetNickname(visibleName, noColor) -- Return a nickname string in parenthesis if one should be displayed -- nickame contains color codes from CleanChat if available -- the optional {noColor} parameter will return the nickname without color codes if present -- This function is global in case other mods want to call it local speakerID=visibleName.."**"..myPlayerRealm; local speakerNick=""; if ((speakerID ~= myPlayerID) or (AKA_SavedVars["AKA_PrefsShowMe"]) ) then -- Only show our own name if set in preferences if (AKA_SavedVars["FriendToons"] == nil) then FixDefaults(); -- needs to be an array end if (AKA_SavedVars["FriendToons"][speakerID]) then -- if there is an entry for this person local speakerRec=AKA_SavedVars["FriendToons"][speakerID]; speakerNick=speakerRec["nickname"]; else -- no FriendToons entry for this player, try the guild notes if (guildieNames[visibleName]) then -- if there is an entry for this person speakerNick=guildieNames[visibleName]; end end -- was an entry for this speaker end -- skip our own name? if ((speakerNick ~= "") and (speakerNick~=visibleName) and (noColor==nil)) then if (CleanChat_GetColorFor) then -- if cleanchat colors are available then use those speakerNick=CleanChat_GetColorFor(visibleName) .."("..speakerNick..")|r"; else speakerNick="|c909090FF("..speakerNick..")|r "; end end -- something we want to change for speakerNick return speakerNick; end -- function AKA_AddMessage(this, msg, r, g, b, id) -- this, msg, r, g, b, id -- -- arg[1]=arg[1].."!!"; -- if (msg ~= nil) then -- msg=msg.."!!"; -- end -- this:AKA_AddMessage_Orig(this, msg, r, g, b, id) -- local rettab = { this:AKA_AddMessage_Orig(unpack(arg)) } -- return unpack(rettab); -- end local function ParseMessage(msg, whoSent, whichChannel) -- whichChannel = "PARTY", "RAID", "GUILD", "BATTLEGROUND", "WHISPER" or chat channel name -- Split each comma separated element into individual Tokens -- so that they can be handled properly -- local messageFields={ -- "name", "class", "race", "guild", "level", "prof1name", "prof1skill", -- "prof2name", "prof2skill", "note"}; -- update the list of speakers to mark that this person has AKA: if (AKA_SessionList[whoSent] ~= nil) then AKA_SessionList[whoSent]['status']='available'; AKA_SessionList[whoSent]['lastcontact']=GetTime(); -- seconds AKA_SessionList[whoSent]['channelList'][whichChannel]=true; else AKA_SessionList[whoSent]={}; AKA_SessionList[whoSent]['status']='available'; -- 'unknown' when first seen, 'na' if request has timed out, 'available' if AKA request has been answered AKA_SessionList[whoSent]['lastcontact']=GetTime(); -- seconds AKA_SessionList[whoSent]['channelList']={}; AKA_SessionList[whoSent]['channelList'][whichChannel]=true; AKA_SessionList[whoSent]['bestchannel']=whichChannel; end AKA_ErrorMsg("ParseMessage("..msg..","..whoSent..", "..whichChannel..")"); local pString =msg; -- make a copy to take apart -- pString="hoser`dude`hooman`flying monkeys`2`sproting`1`dancing`300`the coolist dud in the wowerzerverserse."; local dashOffset=string.find(whoSent, "-"); local senderID=whoSent.."**"..myPlayerRealm; if (dashOffset ~= nil) then -- battlegroup format with dash: senderID=string.gsub(whoSent,"\-","**"); end AKA_ParsedMsg={}; for count = 1, table.getn(messageFields) do commaIndex = string.find(pString, MSG_DELIMITER); local thisFieldName=messageFields[count]; if (commaIndex) then AKA_ParsedMsg[thisFieldName] = strsub(pString, 1, commaIndex - 1); pString = strsub(pString, commaIndex + 1); AKA_ErrorMsg("parsed: "..thisFieldName.."->"..AKA_ParsedMsg[messageFields[count]]); else -- last entry AKA_ParsedMsg[thisFieldName] = pString; -- AKA_ErrorMsg(AKA_ParsedMsg[messageFields[count]]); break; end end if (AKA_SavedVars["FriendToons"] == nil) then AKA_SavedVars["FriendToons"]={}; end local altID=""; if ((AKA_ParsedMsg["realm"] == nil) or (AKA_ParsedMsg["realm"] == "")) then altID=AKA_ParsedMsg["name"].."**"..myPlayerRealm; else altID=AKA_ParsedMsg["name"].."**"..AKA_ParsedMsg["realm"]; end -- AKA_SavedVars["FriendToons"][whoSent.."**"..myPlayerRealm]=AKA_ParsedMsg; -- save the parsed table in FriendToons if (altID == senderID) then AKA_ParsedMsg["firsthand"]=true; else AKA_ParsedMsg["firsthand"]=false; end if (AKA_ParsedMsg["profession1"] ~= nil) then AKA_ParsedMsg["prof1name"]=AKA_ProfessionList[strsub(AKA_ParsedMsg["profession1"], 1, 1)]; AKA_ParsedMsg["prof1skill"]=BASE642Dec(strsub(AKA_ParsedMsg["profession1"], 2, 3)); end if (AKA_ParsedMsg["profession1"] ~= nil) then AKA_ParsedMsg["prof2name"]=AKA_ProfessionList[strsub(AKA_ParsedMsg["profession2"], 1, 1)]; AKA_ParsedMsg["prof2skill"]=BASE642Dec(strsub(AKA_ParsedMsg["profession2"], 2, 3)); end if (AKA_ParsedMsg["race"] ~= nil) then if (strlen(AKA_ParsedMsg["race"])>1) then -- upacked version of race else -- needs unpacking local raceSexValue=BASE642Dec(AKA_ParsedMsg["race"]); -- thisToon["race_sex"]=((gender-1)*16)+raceValue; local raceValue = mod(raceSexValue, 16); local sexValue= (raceSexValue-raceValue)/16; AKA_ParsedMsg["race"]=AKA_RaceList[raceValue]; if (sexValue == 0) then -- "unknown" AKA_ParsedMsg["gender"]=""; else AKA_ParsedMsg["gender"]=AKA_GenderList[sexValue+1]; end end -- race is packed end -- race not nil -- altID=AKA_ParsedMsg["userid"]; AKA_ParsedMsg["lastupdate"]=TODAY; AKA_SavedVars["FriendToons"][altID]=AKA_ParsedMsg; -- save the parsed table in FriendToons AKA_ErrorMsg("from:"..whoSent..msg); if (AKA_ParsedMsg["userid"] ~= nil) then AKA_LastSeen[AKA_ParsedMsg["userid"]]={["name"]=whoSent,["time"]=GetTime()}; end AKA_ToonListDirty=true; -- we have new data to display end -- local minimapzonetext = GetMinimapZoneText(); -- if GetNumRaidMembers()>0 then local function UpdateMyData() local guildName, guildRankName, guildRankIndex = GetGuildInfo("player"); local level= UnitLevel("player"); local race = UnitRace("player"); local raceNum=AKA_RaceIndex[race]; local raceValue=BASE642Dec(raceNum); local gender=UnitSex("player"); -- 1=unknown,2=male,3=female as of 1.10 local genderText=AKA_GenderList[gender]; local englishFaction, toss =UnitFactionGroup("player"); -- we are just comparing, so English will be used local thisToon={}; thisToon["name"]=myPlayerName; thisToon["realm"]=myPlayerRealm; thisToon["class"]=myPlayerClassText; thisToon["race"]=race; thisToon["guild"]=guildName; thisToon["level"]=level; thisToon["race"]=race; thisToon["raceNum"]=raceNum; thisToon["faction"]=englishFaction; thisToon["gender"]=genderText; thisToon["race_sex"]=Dec2BASE64(((gender-1)*16)+raceValue); if (AKA_SavedVars["MyToons"]) then if (AKA_SavedVars["MyToons"][myPlayerID]) then -- copy over per-toon preferences: if (AKA_SavedVars["MyToons"][myPlayerID]["guildnotes"]) then thisToon["guildnotes"]=AKA_SavedVars["MyToons"][myPlayerID]["guildnotes"]; else thisToon["guildnotes"]=0; end if (AKA_SavedVars["MyToons"][myPlayerID]["com_channels"]) then thisToon["com_channels"]=AKA_SavedVars["MyToons"][myPlayerID]["com_channels"]; else thisToon["com_channels"]=DEFAULT_COM_CHANNELS; end else thisToon["guildnotes"]=0; thisToon["com_channels"]=DEFAULT_COM_CHANNELS; end else thisToon["guildnotes"]=0; thisToon["com_channels"]=DEFAULT_COM_CHANNELS; end if (myPlayerZone=="") then myPlayerZone=GetRealZoneText(); -- GetMinimapZoneText(); end thisToon["zone"]=myPlayerZone; -- Get trade skill information: local professionCount=1; local skillCategory=""; for i=1, GetNumSkillLines() do local skillName, isHeader, isExpanded, skillRank, numTempPoints, skillModifier, skillMaxRank, isAbandonable, stepCost, rankCost, minLevel, skillCostType, skillDescription = GetSkillLineInfo(i); if (skillName) then -- DEFAULT_CHAT_FRAME:AddMessage("skill:"..skillName.." "..skillRank.."type:"..skillCostType, 0.5, 1.0, 0.5, 3); if (isHeader) then skillCategory=skillName; else if (skillCategory == "Professions") then thisToon["prof"..professionCount.."name"]=skillName; thisToon["prof"..professionCount.."num"]=AKA_ProfessionIndex[skillName]; thisToon["prof"..professionCount.."skill"]=skillRank; -- DEFAULT_CHAT_FRAME:AddMessage("skill:"..skillName.." "..skillRank, 0.5, 1.0, 0.5, 3); professionCount=professionCount+1; end end end -- testing for nil skill end -- for loop -- Now step through spell book and check for trade skill specializations: local p1=thisToon["prof1num"]; if (p1 == nil) then p1=""; end local p2=thisToon["prof2num"]; if (p2 == nil) then p2=""; end local pRank1=0; local pRank2=0; local thisSpellNumber=""; if ((p1 ~= "") or (p2 ~= "")) then -- only test specialization if necessary local i = 1 while true do local spellName, spellRank = GetSpellName(i, BOOKTYPE_SPELL) if not spellName then do break end end thisSpellNumber=AKA_ProfessionIndex[spellName]; if (( thisSpellNumber ~= nil) and (AKA_ProfSpecialMap[thisSpellNumber] ~= nil)) then -- DEFAULT_CHAT_FRAME:AddMessage( "thisSpellNumber="..thisSpellNumber.." Special= "..AKA_ProfessionList[thisSpellNumber]); local tList=AKA_ProfSpecialMap[thisSpellNumber]; if ((tList[1]==p1) and (tList[2]>pRank1)) then thisToon["prof1num"]=thisSpellNumber; pRank1=tList[2]; -- DEFAULT_CHAT_FRAME:AddMessage( "upgrading skill "..thisToon["prof1name"].." to "..AKA_ProfessionList[thisSpellNumber]); end if ((tList[1]==p2) and (tList[2]>pRank2)) then thisToon["prof2num"]=thisSpellNumber; pRank2=tList[2]; -- DEFAULT_CHAT_FRAME:AddMessage( "upgrading skill "..thisToon["prof2name"].." to "..AKA_ProfessionList[thisSpellNumber]); end end i = i + 1 end end -- p1,p1 ~= nil if (AKA_SavedVars["MyToons"] == nil) then AKA_SavedVars["MyToons"]={}; end AKA_SavedVars["MyToons"][myPlayerID]=thisToon; -- local myPlayerRealm=GetCVar("realmName"); -- local myPlayerName=UnitName("player"); -- local myPlayerClassText, myPlayerClassType = UnitClass("player"); -- local myPlayerID=myPlayerName.."**"..myPlayerRealm; end local function TransmitMyData(destToon) -- transmit the data for this toon? local myNickname=AKA_SavedVars["MyNickname"]; if ((myNickname=="*pending*") or (myNickname ==nil)) then -- they have not set up the system yet - we should warn them. else local toonIndex=0; local fieldCount=0; local thisID=""; local thisRecord={}; local myToonList=AKA_SavedVars["MyToons"]; local k,v; AKA_SuperToonList=AKA_SavedVars["MyToons"]; if (myToonList == nil) then -- something is wrong. we should have at least the current toon on file AKA_ErrorMsg("No toons on file."); else -- AKA_ErrorMsg("Toon count = "..table.getn(myToonList)); -- if (table.getn(myToonList)>0) then -- make sure somethign is in the table before iterating -- for toonIndex = 1, table.getn(myToonList) do for k,v in pairs(myToonList) do local outStr,fieldValue; if ((v["faction"] == myPlayerFaction) and (v["realm"]==myPlayerRealm)) then outStr=""; AKA_ErrorMsg(k..":"..v["name"]); for fieldCount = 1, table.getn(messageFields) do -- AKA_ErrorMsg(fieldCount.."->"..messageFields[fieldCount]); fieldName=messageFields[fieldCount]; fieldValue=v[fieldName]; if (fieldName == "nickname") then fieldValue=myNickname; end if (fieldName == "race") then if (v["race_sex"] ~= nil) then fieldValue=v["race_sex"]; end end if (fieldName == "profession1") then if (v["prof1num"] ~= nil) then fieldValue=v["prof1num"]..Dec2BASE64(v["prof1skill"]); else if (v["prof1name"] == nil) then fieldValue=""; else fieldValue=AKA_ProfessionIndex[v["prof1name"]]..Dec2BASE64(v["prof1skill"]); end end -- prof1num end -- profession1 if (fieldName == "profession2") then if (v["prof2num"] ~= nil) then fieldValue=v["prof2num"]..Dec2BASE64(v["prof2skill"]); else if (v["prof2name"] == nil) then fieldValue=""; else fieldValue=AKA_ProfessionIndex[v["prof2name"]]..Dec2BASE64(v["prof2skill"]); end end -- prof2num end -- profession2 if (fieldName == "userid") then fieldValue=AKA_USERID; end if (fieldValue==nil) then outStr=outStr..MSG_DELIMITER; else outStr=outStr.. fieldValue..MSG_DELIMITER; end end -- for fieldCount AKA_SendMsg(outStr,destToon); end -- faction & realm match end -- pairs -- end -- if >0 toons end -- if (myToonList == nil) end AKA_SendVersion(); end local function DrawScrollContents(topline) -- Doesn't actually DRAW the contents? -- Just returns a table items to be placed the buttons used for the Faux Scroller -- Inputs: AKA_SavedVars["FriendToons"] -- outputs: -- AKA_BIGLIST -- linnear list of content lines for the scroller -- AKA_BIGKEY -- list of toonIDs being displayed in the scroller, indexed by toonID -- AKA_BIGIDS -- list of friend ID in {name}**{realm} format local lineCount = 1; local toonList = AKA_SavedVars["FriendToons"]; local toonKey={}; local toonAlts={}; local filtered; local k,v; if (topline == nil) then topline=1; end -- step one: build a key of known toons: AKA_BIGLIST={}; AKA_BIGKEY={}; AKA_BIGIDS={}; if (toonList == nil) then -- AKA_PrefsNickList:SetText("No nicknames known.");= else local listText=""; -- table.foreach(toonList, function(k,v) for k,v in pairs(toonList) do -- if (v["userid"] ~= nil) then -- DEFAULT_CHAT_FRAME:AddMessage( v["name"].." "..v["userid"].." "..v["realm"]); -- else -- DEFAULT_CHAT_FRAME:AddMessage( v["name"].." "..v["realm"]); -- end -- if ((v["realm"] == myPlayerRealm) and (v["faction"] == myFaction)) then -- displayable for this toon if ((v["realm"] == myPlayerRealm) ) then local thisToonID=v["userid"]; if (thisToonID ~= nil) then if (lineCount>= topline) then if (AKA_BIGKEY[thisToonID] == nil) then -- create an index: local nick=v["nickname"]; if (nick == nil) then nick="NO NICKNAME"; end table.insert(AKA_BIGLIST,"|cFF8080FF"..nick.."|r: "); AKA_BIGKEY[thisToonID]=table.getn(AKA_BIGLIST); table.insert(AKA_BIGIDS,v["name"].."**"..v["realm"]) end local thisToonName=v["name"]; if (thisToonName == nil) then thisToonName="NO NAME"; end -- if (UnitIsConnected(thisToonName)) then -- thisToonName -- else local thisToonNameText=thisToonName; if (AKA_LastSeen[thisToonID] ~= nil) then if (AKA_LastSeen[thisToonID]["name"]==thisToonName) then thisToonNameText="|cFFFFCC00["..thisToonNameText.."]|r"; end end local oStr=AKA_BIGLIST[AKA_BIGKEY[thisToonID]]; if (strsub(oStr,-1) ~= " ") then oStr=oStr..", "; end AKA_BIGLIST[AKA_BIGKEY[thisToonID]]=oStr..thisToonNameText; -- end end -- toonID not nil end -- within the display range? (topline) end -- realm/action filter lineCount = lineCount+1; end -- pairs (toonList) end -- toonlist == nil -- at this point AKA_BIGLIST is a linear array of toons info strings end local function FixDefaults() -- inputs: -- AKA_SavedVars -- ouputs: -- AKA_SavedVars if not (AKA_SavedVars) then AKA_SavedVars = {}; AKA_SavedVars=AKA_Defaults; AKA_SavedVars["Version"]=AKA_SavedVars; AKA_SavedVars["FormatVersion"]=AKA_FormatVersion; DEFAULT_CHAT_FRAME:AddMessage("AKA loading defaults.", 0.5, 1.0, 0.5, 3); end if (AKA_SavedVars["FormatVersion"] == nil) then AKA_SavedVars["FormatVersion"]=AKA_FormatVersion; end if (AKA_SavedVars["FormatVersion"] < AKA_FormatVersion) then -- convert from ealier format -- 1st version so nothing to do here yet if (AKA_SavedVars["FormatVersion"] == 1.1) then DEFAULT_CHAT_FRAME:AddMessage("AKA version change. converting character data.", 0.5, 1.0, 0.5, 3); else if (AKA_SavedVars["FormatVersion"] < 1.01) then DEFAULT_CHAT_FRAME:AddMessage("AKA database change from 1.0. Erasing old data. Sorry for the inconvenience.", 0.5, 1.0, 0.5, 3); local tempNick=AKA_SavedVars["myNickName"] AKA_SavedVars = {}; AKA_SavedVars=AKA_Defaults; AKA_SavedVars["Version"]=AKA_Version; AKA_SavedVars["myNickName"]=tempNick; UpdateMyData(); end end AKA_SavedVars["FormatVersion"]=AKA_FormatVersion; end if ((AKA_SavedVars["FriendToons"] == nil) or (AKA_SavedVars["FriendToons"] == {})) then local fToons={}; AKA_SavedVars["FriendToons"] =fToons; end if ((AKA_SavedVars["MyNickname"] == nil) or (AKA_SavedVars["MyNickname"] == "")) then AKA_SavedVars["MyNickname"] =myPlayerName; end -- updateMyData must be last since it actually uses some of the above fields if (AKA_SavedVars["MyToons"][myPlayerID] == nil) then UpdateMyData(); end if (AKA_SavedVars["MyToons"][myPlayerID]["guildnotes"] == nil) then AKA_SavedVars["MyToons"][myPlayerID]["guildnotes"]=0; end if (AKA_SavedVars["MyToons"][myPlayerID]["com_channels"] == nil) then DEFAULT_CHAT_FRAME:AddMessage("AKA Communications preferences set to defaults.", 0.5, 1.0, 0.5, 3); AKA_SavedVars["MyToons"][myPlayerID]["com_channels"]=DEFAULT_COM_CHANNELS; end if (AKA_SavedVars["MyToons"][myPlayerID]["com_channels"]["Raid"] == nil) then DEFAULT_CHAT_FRAME:AddMessage("AKA Communications preferences set to defaults.", 0.5, 1.0, 0.5, 3); AKA_SavedVars["MyToons"][myPlayerID]["com_channels"]=DEFAULT_COM_CHANNELS; end end -- Guild Functions: local function UpdateGuildNotes() -- AKA_SavedVars["MyToons"][myPlayerID]["guildnotes"]=arg1; -- 0=no, 1=1st word, 2=(), 3=[] local guildNoteExp=""; local guildNoteOption=AKA_SavedVars["MyToons"][myPlayerID]["guildnotes"]; if (guildNoteOption ==nil) then guildNoteOption=0; end guildNoteExp=GUILD_NOTE_STRINGS[guildNoteOption]; guildieNames={}; guildiePlayers={}; if (guildNoteOption>0) then local name, rank, rankIndex, level, class, zone, note, officernote, online, status; local guildNick, matchcount; local numGuildMembers = GetNumGuildMembers(); for i=1, numGuildMembers do note = ""; officernote = ""; name, rank, rankIndex, level, class, zone, note, officernote, online, status = GetGuildRosterInfo(i); guildNick, matchcount=string.gsub(note, guildNoteExp, "%1"); if (matchcount>0)then -- DEFAULT_CHAT_FRAME:AddMessage(name..","..guildNick, 0.5, 1.0, 0.5, 3); guildieNames[name]=guildNick; end end end -- guildNoteOption>0 end -- Tooltip (Chat): -- --------------- local function ShowWhoTooltip2() -- this will be the one called by the regular /who event --[[if (numWhos > 0) then for i=1, numWhos do name, guild, level, race, class, zone, group = GetWhoInfo(i); if (name == AKA_LinkedName) then foundAWho=true; break; end end ]]-- -- if (follow_mouse) then -- GameTooltip:SetOwner(UIParent, "ANCHOR_CURSOR"); -- else GameTooltip_SetDefaultAnchor(GameTooltip, UIParent); -- end -- at this point: -- name, guild, et al = the info for the clicked-on player -- local speakerID=name.."**"..myPlayerRealm; end local function ShowWhoTooltip() local numWhos, totalCount = GetNumWhoResults(); -- numWhos is # of results returned (max 49). totalCount is matches on server local name, guild, level, race, class, zone, group; local foundAWho=false; local outStr=""; local speakerRec=nil; local linkedNickname=nil; local altTable={}; local toonAlts={}; local fieldCount if (numWhos > 0) then for i=1, numWhos do name, guild, level, race, class, zone, group = GetWhoInfo(i); if (name == AKA_LinkedName) then foundAWho=true; break; end end -- if (follow_mouse) then -- GameTooltip:SetOwner(UIParent, "ANCHOR_CURSOR"); -- else GameTooltip_SetDefaultAnchor(GameTooltip, UIParent); -- end -- at this point: -- name, guild, et al = the info for the clicked-on player local speakerID=name.."**"..myPlayerRealm; if (AKA_SavedVars["FriendToons"] == nil) then -- repair FriendToons if necessary AKA_FixDefaults(); end if (AKA_SavedVars["FriendToons"][speakerID]) then -- if there is an entry for this person speakerRec=AKA_SavedVars["FriendToons"][speakerID]; if ((speakerRec["nickname"] ~= "") and (speakerRec["nickname"] ~= nil)) then -- there is a nickname linkedNickname=speakerRec["nickname"] ; end -- there is a nickname -- build a structure of alts local toonList = AKA_SavedVars["FriendToons"]; local toonKey={}; if (toonList == nil) then -- we are done else table.insert(toonAlts,"AKA:\"|c9090FFFF"..linkedNickname.."\"|r"); for k,v in pairs(toonList) do if (((v["faction"] == myPlayerFaction) and (v["realm"]==myPlayerRealm)) or (v["faction"] == nil) or (v["realm"] == nil)) then AKA_ErrorMsg(k..":"..v["name"]); if (v["nickname"] == linkedNickname) then local thisToonText = ""; for fieldCount = 1, table.getn(tooltipFields) do -- tooltipDelimiters local fieldName=tooltipFields[fieldCount]; local fieldValue=v[fieldName]; if ((fieldValue ~= nil) and (fieldValue ~= "")) then -- if no value, skip thisToonText=thisToonText.. fieldValue..tooltipDelimiters[fieldCount]; end end -- for fieldCount table.insert(toonAlts,thisToonText); end -- nickname matches end -- meets factio/realm criteria end -- pairs (toonList) end -- toonlist == nil end -- there are alts to check AKA_TAL=toonAlts; -- debugging GameTooltip:AddLine(name, .6,1.0,.8); -- GameTooltip:AddLine(name, GameTooltip_UnitColor("player")); if (guild == "") then outStr=outStr.."Level "..level.." "..race.." "..class.." - "..zone; else outStr=outStr.."Level "..level.." "..race.." "..class.." <"..guild.."> - "..zone; -- GameTooltip:AddLine("<"..guild..">", 1, .8, 0); end GameTooltip:AddLine(outStr, 1, 1, 1); -- GameTooltip:AddLine(zone, 1, 1, 1); -- WHO_LIST_FORMAT %s : Level %d %s %s - %s "Lonk: Level 21 Troll Hunter - Undercity" -- WHO_LIST_GUILD_FORMAT %s : Level %d %s %s <%s> - %s "Rumplestump: Level 60 Gnome Rogue - Iron Forge" if (table.getn(toonAlts))>0 then for fieldCount = 1, table.getn(toonAlts) do GameTooltip:AddLine(toonAlts[fieldCount], .8, .8, 1.8); end -- for fieldCount end GameTooltip:Show(); -- GameTooltip:FadeOut(); end -- there was a /who response to show end function AKA_SetItemRef (link, text, button) -- Get hooked into chat links -- keeping it global on purpose... AKA_LinkedName=""; if (strsub(link, 1, 6) == "player") then -- "player:{plaeryname}" local namelink = strsub(link, 8); local name, lineid = strsplit(":", namelink); -- local name = strsub(link, 8); if ( name and (strlen(name) > 0) ) then if ( IsShiftKeyDown() ) then AKA_LinkedName = name; --ShowWhoTooltip(name); --AKA_LinkedName=""; -- tip has been shown. move along end end end -- if (AKA_LinkedName=="") then originalSetItemRef(link, text, button); -- always pass through -- end end -- GLOBAL FUNCTIONS -- __ _ _ _ _ ___ ___ _ __ -- /__ | / \ |_) /\ | |_ | | |\ | / | | / \ |\ | (_ -- \_| |_ \_/ |_) /--\ |_ | |_| | \| \_ | _|_ \_/ | \| __) -- function AKA_ChatModder(this, event, arg1, arg2, ...) local arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11 = ...; -- arg1 = event -- arg2 = speaker (usually) local killEvent=false; AKA_LASTEVENT=event; if ((event == "CHAT_MSG_CHANNEL") or (event == "CHAT_MSG_GUILD") or (event == "CHAT_MSG_RAID") or (event == "CHAT_MSG_PARTY")) then if ((arg1 ~= nil) and (arg2 ~= nil))then if (strsub(arg1, 1, 5) == CHANNEL_PREFIX) then killEvent=true; -- toss it else if (strsub(arg1, 1, 4) ~= "<GEM") then -- test for non-chat stuff arg1=GetNickname(arg2)..' '..arg1; end -- not GEM end -- toss <AKA messages end -- event args not nil end -- event if (killEvent == true) then -- don't pass it along the chain else originalChatFrame_OnEvent(this, event, arg1, arg2, ...); end end function AKA_GathererModder(msg) --[[ --"Received gather of %1 in %2 from %3 (%4)" function Gatherer.Util.ChatPrint(str) if ( DEFAULT_CHAT_FRAME ) then DEFAULT_CHAT_FRAME:AddMessage(str, 1.0, 0.5, 0.25) end end ]]-- local pName=string.gsub(msg,".* from (.-) .*","%1"); local nickName=GetNickname(pName) if (nickName ~= '') then local repstring=' from '..pName..' '..nickName..' '; local str=string.gsub(msg," from %a+ ",repstring); if ( DEFAULT_CHAT_FRAME ) then DEFAULT_CHAT_FRAME:AddMessage(str, 1.0, 0.5, 0.25) end end end -- TIMERS -- =================== function AKA_OnUpdate(elapsed) secondsSinceLastMsg = secondsSinceLastMsg + elapsed; secondsSinceUpdate = secondsSinceUpdate + elapsed; secondsSinceLastScreenDraw = secondsSinceLastScreenDraw + elapsed; if (secondsSinceUpdate > HEARTBEAT_INTERVAL) then -- time to do stuff! -- local p=" ("..secondsSinceLastMsg..")"; -- if (tcount(pendingRequests)>0) then -- there are any elements in the pendingRequests array -- DEFAULT_CHAT_FRAME:AddMessage("pending requests: "..tcount(pendingRequests), 1, .2, .2, 1); -- p=p.." pendingRequests "; -- end -- if (pendingSingleAnnounce) then -- p=p.." pendingSingleAnnounce "; -- end -- DEFAULT_CHAT_FRAME:AddMessage("pending requests: "..p, 1, .2, .2, 1); -- local pendingRequests = false; -- local secondsUntilMyRequest = 0; local k,v; for k,v in pairs(pendingRequests) do -- DEFAULT_CHAT_FRAME:AddMessage("AKA_OnUpdate sending to: "..k, 1, .2, .2, 1); if (v==true) then if ((k=="GUILD") or (k=="PARTY") or (k=="RAID")) then local chanType=k; if ((k=="PARTY") and (UnitInRaid("player")==1)) then chanType="RAID"; end if (secondsSinceLastMsg>NOISE_THRESHHOLD) then -- channel is clear TransmitMyData(chanType); -- pendingRequests{k}=false; -- no longer needede since we now wipe the queue whe we're done end else -- whisper if (secondsSinceLastMsg>NOISE_THRESHHOLD) then -- channel is clear TransmitMyData(k); -- pendingRequests{k}=false; -- no longer needede since we now wipe the queue whe we're done end end -- whisper end end -- loop through pending requests pendingRequests={}; -- assume all requests have been handled -- if (secondsSinceLastMsg>NOISE_THRESHHOLD) then -- -- channel is clear -- TransmitMyData(); -- end if (needHello) then UpdateMyData(); AKA_RequestSync(); needHello=false; end if ((pendingSingleAnnounce==true) and (secondsSinceLastMsg>NOISE_THRESHHOLD)) then -- AKA_TransmitOneToon(myPlayerID); TransmitMyData(); -- go with the overkill model for now pendingSingleAnnounce=false; end -- test to see if we have hooked the chat window yet. if (hasHookedChat == false) then if (ChatFrame_OnEvent ~= AKA_ChatModder) then originalChatFrame_OnEvent = ChatFrame_OnEvent; --hooked ChatFrame_OnEvent=AKA_ChatModder; end hasHookedChat=true; end -- test to see if we have hooked the chat link yet. if (hasHookedChatLink == false) then if (SetItemRef ~= nil) then if (SetItemRef ~= AKA_SetItemRef) then originalSetItemRef = SetItemRef; --hooked SetItemRef=AKA_SetItemRef; hasHookedChatLink=true; --DEFAULT_CHAT_FRAME:AddMessage("who hooked", 1.0, 0.5, 0.25) else -- DEFAULT_CHAT_FRAME:AddMessage("who good", 1.0, 0.5, 0.25) end else --DEFAULT_CHAT_FRAME:AddMessage("who not avail", 1.0, 0.5, 0.25) end end secondsSinceUpdate = 0; -- test to see if we have hooked Gatherer yet. if (hasHookedGatherer == false) then -- add preference check here eventually if (Gatherer) then -- check for older Gatherer: if (Gatherer.Util ~= nil) then if (Gatherer.Util.ChatPrint ~= AKA_GathererModder) then originalGathererChat = Gatherer.Util.ChatPrint; --hooked Gatherer.Util.ChatPrint=AKA_GathererModder; end end -- Gatherer.Util end -- is Gatherer installed? hasHookedGatherer=true; end --[[ -- test to see if we have hooked the calendar yet. if (hasHookedCalendar == false) then if (IsAddOnLoaded("Blizzard_Calendar")) then if (CalendarDayButton_OnEnter ~= AKA_CalendarDayButton_OnEnter) then original_CalendarDayButton_OnEnter = CalendarDayButton_OnEnter; --hooked CalendarDayButton_OnEnter=AKA_CalendarDayButton_OnEnter; --DEFAULT_CHAT_FRAME:AddMessage("calendar hooked", 1.0, 0.5, 0.25) hasHookedCalendar=true; end end end ]]-- -- check if we need to whisper anyone -- AKA_SessionList[arg2]['status']='unknown'; local now = GetTime(); for k, v in pairs (AKA_SessionList) do local thisStatus=v['status']; if (thisStatus == 'na') then -- short circuit out. maybe put in an hourly test eventually elseif (thisStatus == 'unknown') then -- send a whisper to this person AKA_SendMsg(REQ_TOKEN,k); AKA_SessionList[k]['status']='pending'; AKA_SessionList[k]['lastcontact']=GetTime(); -- mark when we sent the whisper elseif (thisStatus == 'pending') then -- check for the timeout if (now-v['lastcontact']>45) then AKA_SessionList[k]['status']='na'; end end -- AKA_ProfessionIndex[v] = k; --[[AKA_SessionList[arg2]['status']='unknown'; -- 'unknown' when first seen, 'pending' if request has been sent, 'na' if request has timed out, 'available' if AKA request has been answered AKA_SessionList[arg2]['lastcontact']=GetTime(); -- seconds AKA_SessionList[arg2]['channelList']={}; AKA_SessionList[arg2]['bestchannel']=''; ]]-- end -- loop through AKA_SessionList end -- heartbeat if (secondsSinceLastScreenDraw > 10.0) then if ((AKA_ToonListDirty == true) and (getglobal("AKAUsersPanel"):IsVisible())) then AKA_ScrollBar_Update(); -- redraw scoll list contents end end end -- function function AKA_TransmitOneToon(toonName) local fieldCount=0; local myNickname=AKA_SavedVars["MyNickname"]; local outStr=""; v=AKA_SavedVars["MyToons"][toonName] AKA_ErrorMsg("AKA_TransmitOneToon("..toonName..") myNickname="..myNickname); for fieldCount = 1, table.getn(messageFields) do -- AKA_ErrorMsg(fieldCount.."->"..messageFields[fieldCount]); fieldName=messageFields[fieldCount]; local fieldValue=v[fieldName]; if (fieldName == "nickname") then fieldValue=myNickname; end if (fieldName == "race") then if (v["race_sex"] ~= nil) then fieldValue=v["race_sex"]; end end if (fieldName == "profession1") then if (v["prof1num"] ~= nil) then fieldValue=v["prof1num"]..Dec2BASE64(v["prof1skill"]); else if (v["prof1name"] == nil) then fieldValue=""; else fieldValue=AKA_ProfessionIndex[v["prof1name"]]..Dec2BASE64(v["prof1skill"]); AKA_ErrorMsg("profession1->"..fieldValue); end end end if (fieldName == "profession2") then if (v["prof2num"] ~= nil) then fieldValue=v["prof2num"]..Dec2BASE64(v["prof2skill"]); else if (v["prof2name"] == nil) then fieldValue=""; else fieldValue=AKA_ProfessionIndex[v["prof2name"]]..Dec2BASE64(v["prof2skill"]); AKA_ErrorMsg("profession2->"..fieldValue); end end end if (fieldName == "userid") then fieldValue=AKA_USERID; end if (fieldValue==nil) then outStr=outStr..MSG_DELIMITER; else outStr=outStr.. fieldValue..MSG_DELIMITER; end end -- for fieldCount AKA_SendMsg(outStr); AKA_SendVersion(); end function AKA_EnterNewNickname() local newNickname=getglobal("AKA_PrefsMyNickname"):GetText(); if (newNickname ~= "" and newNickname ~= nil) then AKA_SavedVars["MyNickname"]=newNickname; end if (AKA_SavedVars["MyNickname"]=="") then AKA_SavedVars["MyNickname"]=myPlayerName; -- use current name if no default end AKA_CurrentNickname:SetText("Current nickname: "..AKA_SavedVars["MyNickname"]); UpdateMyData(); pendingSingleAnnounce=true; end function AKA_RequestSync() AKA_SendMsg(REQ_TOKEN); -- DEFAULT_CHAT_FRAME:AddMessage("AKA-REQUESTING SYNC:", 0.5, 1.0, 0.5, 3); needHello=false; -- we wil be responding to a sync request anyway end function AKA_SendMsg(msg, targetPlayer) -- send a message using the appropriate channel local rChanNum,rChanName, r2, channelInfo; if (targetPlayer ~= nil) then local dashOffset=string.find(targetPlayer, "-"); if (dashOffset ~= nil) then -- DEFAULT_CHAT_FRAME:AddMessage("AKA_SendMsg(targetPlayer:"..targetPlayer..")", 0.5, 1.0, 0.5, 3); targetPlayer = "PARTY"; if (UnitInRaid("player")==1) then targetPlayer = "RAID"; end end end channelInfo=AKA_SavedVars["MyToons"][myPlayerID]["com_channels"]; -- make a shorter reference if ((targetPlayer == nil) or (targetPlayer == "")) then -- regular broadcasts: if (channelInfo == nil) then UpdateMyData(); channelInfo=AKA_SavedVars["MyToons"][myPlayerID]["com_channels"]; end AKAg=channelInfo; -- make a global for testing dbc -- guild traffic: if (IsInGuild() and (channelInfo["Guild"]["active"] == "yes")) then -- only send on guild channel if in a guild SendAddonMessage(MSG_PREFIX, MESSAGE_FORMAT..msg, "GUILD"); MessagesSentPerChannel["GUILD"]=MessagesSentPerChannel["GUILD"]+1; if (AKA_TRAFFICMONITOR) then DEFAULT_CHAT_FRAME:AddMessage("AKA_TX(Guild):"..MESSAGE_FORMAT..msg, 0.5, 1.0, 0.5, 3); end end elseif ( targetPlayer == "GUILD") then if (IsInGuild() and (channelInfo["Guild"]["active"] == "yes")) then -- only send on guild channel if in a guild SendAddonMessage(MSG_PREFIX, MESSAGE_FORMAT..msg, "GUILD"); MessagesSentPerChannel["GUILD"]=MessagesSentPerChannel["GUILD"]+1; if (AKA_TRAFFICMONITOR) then DEFAULT_CHAT_FRAME:AddMessage("AKA_TX(Guild):"..MESSAGE_FORMAT..msg, 0.5, 1.0, 0.5, 3); end end elseif (targetPlayer == "RAID") then if ( (channelInfo["Raid"]["active"] == "yes")) then -- put in test for in-raid eventually SendAddonMessage(MSG_PREFIX, MESSAGE_FORMAT..msg, "RAID"); MessagesSentPerChannel["RAID"]=MessagesSentPerChannel["RAID"]+1; if (AKA_TRAFFICMONITOR) then DEFAULT_CHAT_FRAME:AddMessage("AKA_TX(RAID):"..MESSAGE_FORMAT..msg, 0.5, 1.0, 0.5, 3); end end elseif (targetPlayer == "PARTY") then if ( (channelInfo["Raid"]["active"] == "yes")) then -- put in test for in-raid eventually SendAddonMessage(MSG_PREFIX, MESSAGE_FORMAT..msg, "PARTY"); MessagesSentPerChannel["PARTY"]=MessagesSentPerChannel["PARTY"]+1; if (AKA_TRAFFICMONITOR) then DEFAULT_CHAT_FRAME:AddMessage("AKA_TX(PARTY):"..MESSAGE_FORMAT..msg, 0.5, 1.0, 0.5, 3); end end else --whispers: if (AKA_TRAFFICMONITOR) then DEFAULT_CHAT_FRAME:AddMessage("AKA_TX(WHISPER:"..targetPlayer.."):"..MESSAGE_FORMAT..msg, 0.5, 1.0, 0.5, 3); end SendAddonMessage(MSG_PREFIX, MESSAGE_FORMAT..msg, "WHISPER", targetPlayer); MessagesSentPerChannel["WHISPER"]=MessagesSentPerChannel["WHISPER"]+1; end end function AKA_ErrorMsg(msg) -- send a message using the appropriate channel if (AKA_DEBUG) then DEFAULT_CHAT_FRAME:AddMessage("AKA-DEBUG:"..msg, 0.5, 1.0, 0.5, 3); end end function AKA_TestVersionMsg(msg) -- Input: is the regular string from the addon channel -- Returns: true if this is a version test. false is some other sort of message -- AKA_VersionNote will be the note for the version we don't have if (strsub(msg, 1, 2) == "V:") then -- this is a version message local toss, prefix,version,note = string.find(msg,"V:(.*)`(.*)"); local parsedVersion=tonumber(version) if (parsedVersion>AKA_HighestSeenVersion) then AKA_HighestSeenVersion=parsedVersion; if (AKA_HighestSeenVersion>AKA_Version) then DEFAULT_CHAT_FRAME:AddMessage(AKA_TEXT["VERSION_UPDATE"].."(old:"..AKA_Version.." new:"..parsedVersion..") "..note, 0.5, 1.0, 0.5, 3); end end return true; else return false; end end function AKA_SendVersion() if (AKA_Version>AKA_HighestSeenVersion) then AKA_HighestSeenVersion=AKA_Version; AKA_SendMsg("V:"..AKA_Version.."`"..AKA_TEXT["VERSION_NOTES"]); end end -- GUI Handlers: -- ============================= -- Prefs: -- ------ -- Handle clicks for Prefs function AKAOptions_OnClick(self) local buttonName=self:GetName() --DEFAULT_CHAT_FRAME:AddMessage("LookoutOptions_OnClick: OnClick: " .. buttonName ); AKA_Defaults[buttonName] =getglobal(buttonName):GetChecked(); AKA_SavedVars[buttonName] =getglobal(buttonName):GetChecked(); end function AKAOptions_SharingOnClick(shareType) -- Called by checkbuttons in preferences frame -- sharetype = one of ["Guild" "Raid "Chat" local checkbuttonName = "AKA_PrefsShare"..shareType; local currentState=getglobal("AKA_PrefsShare"..shareType):GetChecked(); local newSetting="no"; if (currentState) then newSetting="yes"; end AKA_SavedVars["MyToons"][myPlayerID]["com_channels"][shareType]["active"]=newSetting; end function AKAOptions_RadioClick(butNum) AKA_SavedVars["MyToons"][myPlayerID]["guildnotes"]=butNum+0; -- 0=no, 1=1st word, 2=(), 3=[] UpdateGuildNotes(); UpdateRadios(); end function AKA_ListClick(passedFrame) local level,race,class,guild,zone; local thisToonID=passedFrame.toonID; -- DEFAULT_CHAT_FRAME:AddMessage(thisToonID , 0.5, 1.0, 0.5, 3); if (thisToonID ~= nil) then if (AKA_SavedVars["FriendToons"] == nil) then -- repair FriendToons if necessary AKA_FixDefaults(); end if (AKA_SavedVars["FriendToons"][thisToonID]) then -- if there is an entry for this person speakerRec=AKA_SavedVars["FriendToons"][thisToonID]; if ((speakerRec["nickname"] ~= "") and (speakerRec["nickname"] ~= nil)) then -- there is a nickname linkedNickname=speakerRec["nickname"] ; end -- there is a nickname -- build a structure of alts local toonList = AKA_SavedVars["FriendToons"]; if (toonList == nil) then -- we are done outStr=("No player selected"); else outStr="AKA:\"|c9090FFFF"..linkedNickname.."\"|r\n"; -- table.foreach(toonList,function(k,v) for k,v in pairs(toonList) do if (((v["faction"] == myPlayerFaction) and (v["realm"]==myPlayerRealm)) or (v["faction"] == nil) or (v["realm"] == nil)) then AKA_ErrorMsg(k..":"..v["name"]); if (v["nickname"] == linkedNickname) then local thisToonText = ""; for fieldCount = 1, table.getn(tooltipFields) do -- tooltipDelimiters local fieldName=tooltipFields[fieldCount]; local fieldValue=v[fieldName]; if ((fieldValue ~= nil) and (fieldValue ~= "")) then -- if no value, skip thisToonText=thisToonText.. fieldValue..tooltipDelimiters[fieldCount]; end end -- for fieldCount outStr=outStr..thisToonText.."\n"; end -- nickname matches end -- meets factio/realm criteria end -- pairs end -- toonlist == nil end -- there are alts to check getglobal("AKA_DispPlayerNotes"):SetText(outStr); end end -- function -- OnShow for prefs function AKA_PrefsFrameOnShow() -- read settings from profile, and change our checkbuttons and slider to represent them local currentOptions = getglobal(this:GetName().."Options"); PlaySound("igCharacterInfoOpen"); if (not currentOptions) then currentOptions=LookoutDefaults; end UpdateRadios(); -- draw the current settings: if (AKA_SavedVars["AKA_PrefsShowMe"]) then getglobal("AKA_PrefsShowMe"):SetChecked(true) else getglobal("AKA_PrefsShowMe"):SetChecked(false) end if (AKA_SavedVars["MyNickname"] ~= nil) then AKA_CurrentNickname:SetText("Current nickname: "..AKA_SavedVars["MyNickname"]); end -- prefill nickname local textValue=AKA_SavedVars["MyNickname"]; if (textValue == nil) then textValue="" end getglobal("AKA_PrefsMyNickname"):SetText(textValue); -- draw sharing preferences: for i,v in ipairs({"Guild","Raid","Chat"}) do if (AKA_SavedVars["MyToons"][myPlayerID]["com_channels"][v]["active"] == "yes") then getglobal("AKA_PrefsShare"..v):SetChecked(true) else getglobal("AKA_PrefsShare"..v):SetChecked(false) end end if ((AKAPrefs_CurrentPanel == nil) or (AKAPrefs_CurrentPanel == 0)) then AKAPrefs_CurrentPanel=-1; AKA_HidePanel(2); -- PanelTemplates_Tab_OnClick(1); AKA_ShowPanel(1); -- default to panel 1 end end function AKA_ShowPanel(whichPanel) if (AKAPrefs_CurrentPanel > 0) then AKA_HidePanel(AKAPrefs_CurrentPanel); end getglobal(AKAPrefs_PanelFrames[whichPanel]):Show(); AKAPrefs_CurrentPanel=whichPanel; end function AKA_HidePanel(whichPanel) getglobal(AKAPrefs_PanelFrames[whichPanel]):Hide(); AKAPrefs_CurrentPanel = 0; end function AKA_ScrollBar_Update(self) -- Uses the buttons created by AKA_CreateScrollItems and filles in their text and toonID's DrawScrollContents(FauxScrollFrame_GetOffset(self)); -- local scrollTestData = {}; -- for i=1,50 do -- scrollTestData[i] = "Test "..math.random(100); -- end local totalLines=table.getn(AKA_BIGLIST); -- FauxScrollFrame_Update(AKA_FrameScrollBar,VISIBLE_MAX,5,16); -- function, max entries, # visible, pixel height of one FauxScrollFrame_Update(self,totalLines,VISIBLE_MAX,16); -- DEFAULT_CHAT_FRAME:AddMessage("We're at "..FauxScrollFrame_GetOffset(AKA_FrameScrollBar)); if (AKA_ScrollItem1 == nil) then AKA_CreateScrollItems(); end local lineCounter, dataLine, buttonName; local listText=""; -- temporary simple list version -- DEFAULT_CHAT_FRAME:AddMessage("top="..FauxScrollFrame_GetOffset(AKA_FrameScrollBar)); for lineCounter=1,VISIBLE_MAX do dataLine= lineCounter + FauxScrollFrame_GetOffset(AKA_FrameScrollBar); buttonName="AKA_ListLine"..lineCounter; if (dataLine <= table.getn(AKA_BIGLIST)) then -- DEFAULT_CHAT_FRAME:AddMessage("lineCounter="..lineCounter.." dataLine="..dataLine.." "..AKA_BIGLIST[dataLine]); getglobal("AKA_ListLine"..lineCounter):SetText(AKA_BIGLIST[dataLine]); getglobal("AKA_ListLine"..lineCounter).toonID=AKA_BIGIDS[dataLine]; getglobal("AKA_ListLine"..lineCounter):Show(); else getglobal("AKA_ListLine"..lineCounter):Hide(); end end -- for AKA_ToonListDirty=false; end function AKA_CreateScrollItems() -- Create the buttons that make up the "faux" scrolling list of toon names local i, f, entryName; for i = 1, VISIBLE_MAX do entryName="AKA_ListLine"..i; if (getglobal(entryName) == nil) then f = CreateFrame("Button", entryName, AKAUsersPanel,"AKA_ScrollMenuEntryTemplate"); --CreateFrame("frameType", "frameName", parentFrame[, "inheritsFrame"]); --f:SetID(i); f:SetWidth(700); f:SetHeight(19); f:ClearAllPoints(); f:SetPoint("TOPLEFT", "AKA_PrefsTitle", "TOPLEFT", 0, -90+(-16*i)); f:SetText("Test #"..i); --f:Show(); end end end -- text changed on prefs panel: function AKA_PrefsTextChanged() -- eventually only show change button if something changes end function AKA_EnterNewChannelName(whichChannel) -- attempt to leave the old channel is available -- save the data, but don't try to join right away - leave that for the transmit fuction local oldChanName = AKA_SavedVars["MyToons"][myPlayerID]["com_channels"]["Chan"..whichChannel]["name"]; if (oldChanName == nil) or (oldChanName == "") then -- no old channel to leave else LeaveChannelByName(oldChanName); DEFAULT_CHAT_FRAME:AddMessage("Leaving Channel:"..oldChanName, 1, .2, .2, 1); end local chanName=getglobal("AKA_PrefsChannel"..whichChannel.."Name"):GetText(); local chanPW=getglobal("AKA_PrefsChannel"..whichChannel.."PW"):GetText(); if (AKA_SavedVars["MyToons"][myPlayerID]["com_channels"] == nil) then AKA_SavedVars["MyToons"][myPlayerID]["com_channels"]=DEFAULT_COM_CHANNELS; end AKA_SavedVars["MyToons"][myPlayerID]["com_channels"]["Chan"..whichChannel]["name"]=chanName; AKA_SavedVars["MyToons"][myPlayerID]["com_channels"]["Chan"..whichChannel]["pw"]=chanPW; ALA_DrawChannelPrefsValues(whichChannel); -- update the name in the head if needed pendingSingleAnnounce=true; -- announce our presence in the channel AKA_RequestSync(); -- ask users in the new channels for information end -- CheckButton:GetChecked() - Get the status of the checkbox. -- CheckButton:SetChecked([state]) - Set the status of the checkbox. -- CheckButton:SetCheckedTexture("texture") - Set the texture to use for a checked box. -- CheckButton:SetDisabledCheckedTexture("texture") - Set the texture to use for an unchecked box. -- math lib: function AKA_TestBase() local orig=0; local t64=Dec2BASE64(orig); local res=BASE642Dec(t64); DEFAULT_CHAT_FRAME:AddMessage("orig:"..orig, 0.5, 1.0, 0.5, 3); DEFAULT_CHAT_FRAME:AddMessage("b64 :"..t64, 0.5, 1.0, 0.5, 3); DEFAULT_CHAT_FRAME:AddMessage("dec :"..res, 0.5, 1.0, 0.5, 3); local orig=math.random(1,1000); local t64=Dec2BASE64(orig); local res=BASE642Dec(t64); DEFAULT_CHAT_FRAME:AddMessage("orig:"..orig, 0.5, 1.0, 0.5, 3); DEFAULT_CHAT_FRAME:AddMessage("b64 :"..t64, 0.5, 1.0, 0.5, 3); DEFAULT_CHAT_FRAME:AddMessage("dec :"..res, 0.5, 1.0, 0.5, 3); end -- Event functions -- Onload: function AKA_OnLoad(self) -- this:RegisterEvent("ADDON_LOADED"); -- Register the slash command -- -------------------------- SLASH_AKA1 = "/aka"; SlashCmdList["AKA"] = AKA_ParseCommandLine; -- trying this global - didn't kick in with local InitMath(); -- Register the event handlers: -- ============================= -- this:RegisterEvent("VARIABLES_LOADED"); -- eventually will call OnEvent self:RegisterEvent("CHAT_MSG"); self:RegisterEvent("CHAT_MSG_ADDON"); self:RegisterEvent("CHAT_MSG_SYSTEM"); -- for the /who self:RegisterEvent("WHO_LIST_UPDATE"); -- for the /who -- raid command stuff: -- self:RegisterEvent("CHAT_MSG_RAID"); -- self:RegisterEvent("CHAT_MSG_PARTY"); -- Party/Roster stuff: self:RegisterEvent("RAID_ROSTER_UPDATE"); self:RegisterEvent("CHAT_MSG_CHANNEL"); -- will update with alias names, will watch for potential peers self:RegisterEvent("CHAT_MSG_GUILD"); -- will update with alias names self:RegisterEvent("CHAT_MSG_RAID"); -- will update with alias names self:RegisterEvent("CHAT_MSG_PARTY"); -- will update with alias names self:RegisterEvent("VARIABLES_LOADED"); self:RegisterEvent("PLAYER_ENTERING_WORLD"); -- will start a timer for initial syncs self:RegisterEvent("MINIMAP_ZONE_CHANGED"); -- Update our last known location self:RegisterEvent("CHAT_MSG_CHANNEL_JOIN"); -- watch for potential peers joining the channel self:RegisterEvent("GUILD_ROSTER_UPDATE"); -- watch for potential peers joining the channel if (not myPlayerName) then myPlayerName = UnitName("player"); end DEFAULT_CHAT_FRAME:AddMessage(AKA_TITLE.." loaded. Type /aka to change settings.", 0.5, 1.0, 0.5, 1); tinsert(UISpecialFrames,'AKA_PrefsFrame'); end -- OnLoad function AKA_Event(self, event, ...) local arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11 = ...; if (event==nil) then -- DEFAULT_CHAT_FRAME:AddMessage("AKA: event="..event .. " arg1="..arg1.." arg2="..arg2, 0.5, 1.0, 0.5, 1); end local eventHandled = false; local msgText = ""; -- oh to have a case statement! -- debug if (AKA_ShowEvent) then DEFAULT_CHAT_FRAME:AddMessage("AKA: event "..event, 0.5, 1.0, 0.5, 1); end if (event == "GUILD_ROSTER_UPDATE") then -- if (arg1 ~= nil) then UpdateGuildNotes(); eventHandled = true; -- end end if (eventHandled == false) then if ((event == "CHAT_MSG_SYSTEM") or (event =="WHO_LIST_UPDATE")) then -- looking for the "who" event set earlier by the linky if ((AKA_LinkedName~="") and (AKA_LinkedName~=nil)) then ShowWhoTooltip(); AKA_LinkedName=""; -- tip has been shown. move along eventHandled = true; end end -- CHAT_MSG_SYSTEM end -- eventHandled -- VARIABLES_LOADED -- ================ if ( event == "VARIABLES_LOADED" ) then -- Reseed the random # generator -- supposedly not needed with 3.x+ clients -- math.randomseed(math.random(0,2147483647)+(GetTime()*1000)); if (not AKA_USERID) then AKA_USERID=GenerateUSERID(); -- this will be expanded into a larger version to handle -- people playing on multiple machines. -- we will implment a "who am I?" function to try to determine if there is an existing ID. end -- DEFAULT_CHAT_FRAME:AddMessage("AKA: realm="..myPlayerRealm.. "("..AKA_USERID..") today="..TODAY, 0.5, 1.0, 0.5, 1); FixDefaults(); -- Delete old entries: for k,v in pairs(AKA_SavedVars["FriendToons"]) do if ((TODAY-v["lastupdate"])>100) then -- table.remove(AKA_SavedVars["FriendToons"],k); AKA_SavedVars["FriendToons"][k]=nil; end end -- record that we have been loaded AKA_variablesLoaded = true; eventHandled = true; end -- ( event == "VARIABLES_LOADED" ) -- Raid update event -- =========================== if (eventHandled == false) then if ((event == "RAID_ROSTER_UPDATE") or (event == "PARTY_MEMBERS_CHANGED")) then -- Lookout_UpdateRaidtable(); eventHandled = true; end end if (eventHandled == false) then if ((event == "ZONE_CHANGED") or (event == "MINIMAP_ZONE_CHANGED") ) then if (myPlayerZone ~= GetRealZoneText()) then -- GetMinimapZoneText() had too much detail myPlayerZone=GetRealZoneText(); UpdateMyData(); pendingSingleAnnounce=true; end eventHandled = true; end end if (eventHandled == false) then if (event == "CHAT_MSG_ADDON") then -- process incoming messages -- AKA2 supports WHISPER, PARTY and RAID messages as well --[[ Fired when the client receives a message from SendAddonMessage arg1 prefix arg2 message arg3 distribution type ("PARTY", "RAID", "GUILD", "BATTLEGROUND" or "WHISPER") arg4 sender ]]-- if (arg1 == MSG_PREFIX) then --if (arg3 == "GUILD") then -- Only use ADDON channel for guild local chanInfo = AKA_SavedVars["MyToons"][myPlayerID]["com_channels"]; -- create a shorter reference if ((arg3=="GUILD") and (chanInfo["Guild"]["active"] =="yes")) or ((arg3=="RAID") and (chanInfo["Raid"]["active"] =="yes")) or ((arg3=="PARTY") and (chanInfo["Raid"]["active"] =="yes")) or (arg3=="WHISPER") then if (arg2 ~= nil) then secondsSinceLastMsg=0; -- reset the message timer if (AKA_TRAFFICMONITOR) then DEFAULT_CHAT_FRAME:AddMessage("AKA_RX:("..arg3.."):"..arg2, 0.5, 1.0, 0.5, 1); end local msgText=strsub(arg2,2); -- strip off version byte -- char 1 is the version which we can test later... if (msgText== REQ_TOKEN)then -- DEFAULT_CHAT_FRAME:AddMessage("AKA token recieved:("..msgText.."):"..arg2, 1.0, .6, 0.6, 1); -- determined we're getting at least this far... if( arg3=="WHISPER") then pendingRequests[arg4]=true; else -- GUILD, PARTY, RAID pendingRequests[arg3]=true; end -- pendingRequests is an associative array of player names who have requested data. -- It will also contain the names of channels in which requests have arrived. -- i.e. PARTY, RAID, or GUILD else if (AKA_TestVersionMsg(msgText)) then -- version test packet else ParseMessage(msgText,arg4, arg3); -- this is a data packet -- arg2 = message text, arg4=sender name end end -- REQ_TOKEN end end -- checks for preferences end -- Lookout_UpdateRaidtable(); -- Fired when the client receives a message from SendAddonMessage -- -- arg1 prefix -- arg2 message -- arg3 distribution type ("PARTY","RAID","GUILD" or "BATTLEGROUND") -- arg4 sender eventHandled = true; end end -- Raid chat events (incoming) -- =========================== if (event == "CHAT_MSG_RAID" or event == "CHAT_MSG_PARTY" or event =="CHAT_MSG_CHANNEL") then -- arg1 = messsage text -- arg2 = message sender local sendingMember = nil; local inStr; local msgStr; local cmdStr; local toss; local toss2; -- General, Trade, and LocalDefense -- end -- (string.find( arg1, "::") -- put in logic here to determine which channels to monitor: -- record everyone we've seen speak: if (AKA_SessionList[arg2]) then -- we've seen this person before else -- add this speaker to our list and check if they are running AKA AKA_SessionList[arg2]={}; AKA_SessionList[arg2]['status']='unknown'; -- 'unknown' when first seen, 'pending' if request has been sent, 'na' if request has timed out, 'available' if AKA request has been answered AKA_SessionList[arg2]['lastcontact']=GetTime(); -- seconds AKA_SessionList[arg2]['channelList']={}; AKA_SessionList[arg2]['bestchannel']=''; end end -- event=CHAT_MSG_RAID et. al. -- channel monitor end if (eventHandled == false) then -- msgText = string.lower(arg1); end end -- end of function -- command line parameters: (slash command handler) function AKA_ParseCommandLine(msg) cmd=string.lower(msg); if ( ( msg=="1") or (msg=="")) then AKA_PrefsFrame:Show(); end if ( cmd =="t") then AKA_TestBase(); end if ( cmd =="help") then DEFAULT_CHAT_FRAME:AddMessage("/aka reset - restore default values", 0.5, 1.0, 0.5, 1); DEFAULT_CHAT_FRAME:AddMessage("/aka debug - toggle display of debug messages", 0.5, 1.0, 0.5, 1); DEFAULT_CHAT_FRAME:AddMessage("/aka messages - toggle display of netowork traffic", 0.5, 1.0, 0.5, 1); DEFAULT_CHAT_FRAME:AddMessage("/aka updateme - send your data to other AKA clients", 0.5, 1.0, 0.5, 1); end if ( cmd =="reset") then DEFAULT_CHAT_FRAME:AddMessage("Setting AKA variables to default values.", 0.5, 1.0, 0.5, 1); AKA_SavedVars = {}; AKA_SavedVars=AKA_Defaults; AKA_SavedVars["Version"]=AKA_Version; UpdateMyData(); -- LookoutAlertHandler(" Variables reset "); end if ( cmd =="messages") then AKA_TRAFFICMONITOR= not AKA_TRAFFICMONITOR; if (AKA_TRAFFICMONITOR) then DEFAULT_CHAT_FRAME:AddMessage("AKA now diplaying communications traffic", 0.5, 1.0, 0.5, 1); else DEFAULT_CHAT_FRAME:AddMessage("AKA message display off", 0.5, 1.0, 0.5, 1); end end if ( cmd =="debug") then AKA_DEBUG = not AKA_DEBUG; if (AKA_DEBUG) then DEFAULT_CHAT_FRAME:AddMessage("AKA Debug messages enabled.", 0.5, 1.0, 0.5, 1); else DEFAULT_CHAT_FRAME:AddMessage("AKA Debug messages off.", 0.5, 1.0, 0.5, 1); end end if ( cmd =="updateme") then DEFAULT_CHAT_FRAME:AddMessage("Sending update to other AKA clients.", 0.5, 1.0, 0.5, 1); UpdateMyData(); pendingSingleAnnounce=true; end if ( cmd =="sync") then DEFAULT_CHAT_FRAME:AddMessage("Request sync from other AKA clients.", 0.5, 1.0, 0.5, 1); AKA_RequestSync(); --pendingSingleAnnounce=true; end if ( cmd =="spells") then DEFAULT_CHAT_FRAME:AddMessage("Displaying Spellbook...", 0.5, 1.0, 0.5, 1); ShowSpells(); pendingSingleAnnounce=true; end if( string.sub(cmd,1,5)=="name ") then AKA_LookupName(string.sub(msg,6)); pendingSingleAnnounce=true; end end function AKA_LookupName(whatname) local str=""; DEFAULT_CHAT_FRAME:AddMessage(GetNickname(whatname)); end function AKA_GetNickname(visibleName, noColor) --global form for other addons return GetNickname(visibleName, noColor) end function AKA_ExpandNickname(visibleName, noColor) --global form for other addons return visibleName..' '..GetNickname(visibleName, noColor); end