-- to move here: Share stuff, Exchange stuff local KarmaObj = KarmaAvEnK; local KCfg = KarmaObj.Cfg; local KOH = KarmaObj.Helpers; local KSlash = KarmaObj.Slash; local KARMA_DB_L4_RRFF = { -- used subset MEMBERBUCKETS = "MEMBERBUCKETS", }; local KARMA_DB_L5_RRFFM = { LEVEL = "LEVEL", CLASS_ID = "CLSID", CLASS = "CLASS", RACE = "RACE", }; local KARMA_DB_L5_RRFFM_KARMA_TRUST = "K_TRUST"; local KARMA_DB_L5_RRFFM_KARMA_IMPORTED = "K_IMP"; local KARMA_EXCHANGE = { ENABLED_WITH = nil, START_WITH = nil, START_FRAG = nil, START_AT = nil, REQ_IS = nil, REQ_AT = nil, ACK_IS = nil, ACK_AT = nil, FIRST = nil, COUNT = nil, DONE = nil }; local function Karma_ExchangeAllow(args) if (args[2] == nil) or (args[2] == "") then if (KARMA_EXCHANGE.ENABLED_WITH ~= nil) then KarmaChatDefault("Player >" .. KARMA_EXCHANGE.ENABLED_WITH .. "< is now not anymore allowed to pull Karma values..."); end KARMA_EXCHANGE.ENABLED_WITH = nil; else KARMA_EXCHANGE.ENABLED_WITH = args[2]; KarmaChatDefault("Player >" .. args[2] .. "< is at the moment allowed to pull Karma values..."); end end local function Karma_ExchangeRequest(args) if (KARMATRANS_AVAILABLE ~= 1) or (type(KarmaForeign) ~= "table") then -- TODO: xlate KarmaChatDefault("KarmaTrans must be enabled for a large exchange..."); return; end if (args[2] == nil) or (args[2] == "") then KarmaChatDefault("Missing arguments: <player> [<alphabetic character to begin with>]"); return; end local sRequest = "?x1:"; if (args[3] ~= nil) then if (strlen(args[3]) ~= 1) or (strfind(KARMA_ALPHACHARS, args[3]) == nil) then KarmaChatDefault("Additional argument invalid: [<alphabetic character to begin with>] (must be in range of A to Z)"); return; else sRequest = sRequest .. args[3] .. "*"; end else if (KarmaTrans_ForeignKarmaContinueWithGet ~= nil) then local sServer, sFaction, sName; sServer = GetCVar("realmName"); sFaction = UnitFactionGroup("player"); local sName = KarmaTrans_ForeignKarmaContinueWithGet(sServer, sFaction, args[2]); if (sName) then sRequest = sRequest .. sName; end end end KARMA_EXCHANGE.START_WITH = args[2]; KARMA_EXCHANGE.START_FRAG = strsub(sRequest, 5); KARMA_EXCHANGE.START_AT = GetTime(); KARMA_EXCHANGE.REQ_IS = KARMA_EXCHANGE.START_FRAG; KARMA_EXCHANGE.REQ_AT = GetTime(); KARMA_EXCHANGE.ACK_IS = nil; KARMA_EXCHANGE.ACK_AT = nil; KARMA_EXCHANGE.FIRST = nil; KARMA_EXCHANGE.COUNT = 0; KARMA_EXCHANGE.DONE = nil; KarmaChatDefault("Asking >" .. args[2] .. "< for a partial copy of their Karma data: Names, total times joined and assigned Karma values..."); SendAddonMessage("KARMA", sRequest, "WHISPER", args[2]); end local function Karma_ExchangeStatus() if (KARMATRANS_AVAILABLE ~= 1) or (type(KarmaForeign) ~= "table") then -- TODO: xlate KarmaChatDefault("KarmaTrans must be enabled for a large exchange..."); return; end local key, value, text; text = "Karma_ExchangeStatus() -> "; for key, value in pairs(KARMA_EXCHANGE) do text = text .. key .. ": " .. value .. "; "; end KarmaChatDefault(text); end local function Karma_ExchangeTrust(args) if (args[2] == nil) or (args[2] == "") or (args[3] == nil) or (args[3] == "") then -- TODO: xlate KarmaChatDefault("Params: <player> <trust value (0.01 .. 1.0)>"); return; end local oMember = Karma_MemberList_GetObject(args[2]); local trust = tonumber(args[3]); if (trust ~= nil) and (trust >= 0.01) and (trust <= 1.0) then oMember[KARMA_DB_L5_RRFFM_KARMA_TRUST] = trust; -- TODO: xlate KarmaChatDefault("Trust for >" .. args[2] .. "< is now " .. trust); end end local function Karma_ExchangeUpdate() if (KARMATRANS_AVAILABLE ~= 1) or (type(KarmaForeign) ~= "table") then -- TODO: xlate KarmaChatDefault("KarmaTrans must be enabled for a large exchange..."); return; end local sServer = GetCVar("realmName"); -- GetRealmName(): not sure about localization local sFaction = UnitFactionGroup("player"); local sServFact = sServer .. "#" .. sFaction; if (type(KarmaForeign[sServFact]) ~= "table") then -- TODO: xlate KarmaChatDefault("No data from other players. Nothing to do."); return; end -- set all KARMA_DB_L5_RRFFM_KARMA_IMPORTED to 0 do local oFaction = KarmaObj.DB.FactionCacheGet(); local bucket, memberlist, membername, memberdata; for bucket, memberlist in pairs(oFaction[KARMA_DB_L4_RRFF.MEMBERBUCKETS]) do KarmaChatDebug("reset bucket " .. bucket .. "..."); for membername, memberdata in pairs(memberlist) do memberdata[KARMA_DB_L5_RRFFM_KARMA_IMPORTED] = 0; end end end local bAddAllowed = 0; if (KCfg.Get("DEBUG_ENABLED") == 1) then bAddAllowed = 1; end local oForeign = KarmaForeign[sServFact]; local supplier, buckets; for supplier, buckets in pairs(oForeign) do if (type(buckets) == "table") then -- TODO: we want to factor in how much we trust the supplier... -- in test phase hardcoded to factor 0.2 local suppliertrust = 0.2; do local oSupplier = Karma_MemberList_GetObject(supplier); if (oSupplier[KARMA_DB_L5_RRFFM_KARMA_TRUST] ~= nil) then suppliertrust = oSupplier[KARMA_DB_L5_RRFFM_KARMA_TRUST]; end end local bucket, playerlist; for bucket, playerlist in pairs(buckets) do local player, data; KarmaChatDebug("sup " .. supplier .. ", bucket " .. bucket .. "..."); if (type(playerlist) == "table") then for player, data in pairs(playerlist) do local oMember = Karma_MemberList_GetObject(player); if (oMember == nil) and (data.Karma ~= 50) and (bAddAllowed == 1) then -- add if enough (interesting) real info is available if (data.Level) and (data.Class) and (data.Race) then Karma_MemberList_Add(player); oMember = Karma_MemberList_GetObject(player); if (oMember) then oMember[KARMA_DB_L5_RRFFM.LEVEL] = data.Level; oMember[KARMA_DB_L5_RRFFM.CLASS_ID] = data.Class; oMember[KARMA_DB_L5_RRFFM.CLASS] = KOH.IDToClass(data.Class); oMember[KARMA_DB_L5_RRFFM.RACE] = data.Race; end Karma_MemberList_Update(player); end end if (oMember ~= nil) then local delta = data.Karma - 50; if (data.Played < 180) and (math.abs(delta) > 5) then -- if just short groupage, no factor, assuming real stupidity -- (like e.g. someone ninja'ing adamantite while you clear) oMember[KARMA_DB_L5_RRFFM_KARMA_IMPORTED] = delta; else -- otherwise, factor to offset that humans are... human -- max. delta is 40, assuming loss of max. 5 per hour local maxloss = math.floor(5 * data.Played / 3600 + 0.5); maxloss = math.min(maxloss, 40); if (math.abs(delta) > maxloss) then if (delta < 0) then delta = - maxloss else delta = maxloss; end end if (delta < 0) then delta = math.ceil(delta * suppliertrust); else delta = math.floor(delta * suppliertrust); end if (oMember[KARMA_DB_L5_RRFFM_KARMA_IMPORTED] == nil) then oMember[KARMA_DB_L5_RRFFM_KARMA_IMPORTED] = 0; end oMember[KARMA_DB_L5_RRFFM_KARMA_IMPORTED] = oMember[KARMA_DB_L5_RRFFM_KARMA_IMPORTED] + delta; end end end end end end end end function KarmaObj.Share.UpdateEventCheck() return (KARMA_EXCHANGE.ACK_AT ~= nil) and (KARMA_EXCHANGE.DONE == nil) and (KARMA_EXCHANGE.START_WITH ~= nil); end function KarmaObj.Share.UpdateEventDo() -- KARMA_EXCHANGE: only if nothing else is going on if ((KarmaObj.Slash.CommandQLen() == 0) and (#Karma_MessageQueue == 0) and (KARMA_TalentInspect.RequiredCount == 0)) then if (TimeNow - KARMA_EXCHANGE.ACK_AT >= 0.5) and (TimeNow - KARMA_EXCHANGE.REQ_AT >= 1.0) then local sRequest = "?x1:" .. KARMA_EXCHANGE.ACK_IS; KARMA_EXCHANGE.REQ_IS = KARMA_EXCHANGE.ACK_IS; KARMA_EXCHANGE.REQ_AT = GetTime(); KARMA_EXCHANGE.ACK_IS = nil; KARMA_EXCHANGE.ACK_AT = nil; SendAddonMessage("KARMA", sRequest, "WHISPER", KARMA_EXCHANGE.START_WITH); end end end function KarmaObj.Share.AddOnMessageXRequest(arg2, arg3, arg4) -- only in whisper and must be explicitly allowed if (arg3 == "WHISPER") and (KARMA_EXCHANGE.ENABLED_WITH == arg4) then local sBucket, sBorder, sFlags; local iVersion = tonumber(strsub(arg2, 3, 3)); if (iVersion == 1) then sBorder = strsub(arg2, 5); elseif (iVersion == 2) then local sDetails = strsub(arg2, 5); local iPos = strfind(sDetails, ":"); if (iPos) then sBorder = strsub(sDetails, 1, iPos - 1); sDetails = strsub(sDetails, iPos + 1); local iPos = strfind(sDetails, ":"); if (iPos) then sFlags = strsub(sDetails, 1, iPos - 1); else sFlags = sDetails; end else sBorder = sDetails; end if (sFlags == nil) then sFlags = ""; end end if (sBorder and (sBorder ~= "")) then sBucket = KarmaObj.NameToBucket(sBorder); else sBucket = "A"; sBorder = ""; end local sReply = "!x" .. strsub(arg2, 3, 3) .. "+"; local lMembers = KarmaObj.DB.SF.MemberListGet(oFaction); if (lMembers) then local MAXCOUNT = 5; local oBucket = lMembers[sBucket]; if (oBucket) then local bSkipEmpty = false; local bSkipUnchanged = false; local bSkipUnjoined = false; if (iVersion >= 2) then -- Skip empty entries bSkipEmpty = (strfind(sFlags, "See ") ~= nil); -- Skip unchanged entries since iSkipUnchanged = string.match(sFlags, "Sues:(%d+) "); if (iSkipUnchanged) then iSkipUnchanged = tonumber(iSkipUnchanged); end bSkipUnchanged = (iSkipUnchanged ~= nil); -- Skip never joined entries bSkipUnjoined = (strfind(sFlags, "Snje ") ~= nil); end local Found = (sBorder == "") or (strsub(sBorder, 2, 2) == "*"); local Count = 0; local sName, oMember, bSkip; for sName, oMember in pairs(oBucket) do if (not Found) then Found = sName == sBorder; end if (Found) then if (Count < MAXCOUNT) then local iKarma = KarmaObj.DB.M.KarmaGet(oMember); local sClass = Karma_MemberObject_GetClass(oMember); local iClass = KOH.ClassToID(sClass); local sNote = Karma_MemberObject_GetPublicNotes(oMember); if (sNote and (sNote ~= "")) then if ((strsub(sNote, 1, 1) == "#") or strfind(sNote, ":")) then sNote = string.gsub(sNote, "#", "##"); sNote = string.gsub(sNote, "!", "#!"); sNote = string.gsub(sNote, ":", "#!#!"); sNote = "#" .. sNote; end sNote = ":np" .. sNote; else sNote = ""; end local sGUID = Karma_MemberObject_GetGUID(oMember); if (sGUID and (sGUID ~= "")) then sGUID = ":id" .. strsub(sGUID, -4); else sGUID = ""; end local iTotalTime = Karma_MemberObject_GetTotalTimePlayedSummedUp(oMember); bSkip = false; if (bSkipEmpty) then bSkip = bSkip or ((iKarma == 50) and (iTotalTime == 0) and (sNote == "")); end if (not bSkip) then local sAdd = ":p" .. sName .. sGUID .. ":l" .. Karma_MemberObject_GetLevel(oMember) .. ":k" .. iKarma .. sNote .. ":ci" .. iClass .. ":rs" .. Karma_MemberObject_GetRace(oMember) .. ":tt" .. math.floor(iTotalTime); -- looong public note? if (strlen(sAdd) >= 200) then sAdd = ":p" .. sName .. sGUID .. ":l" .. Karma_MemberObject_GetLevel(oMember) .. ":k" .. iKarma .. ":ci" .. iClass .. ":rs" .. Karma_MemberObject_GetRace(oMember) .. ":tt" .. math.floor(iTotalTime); end -- already close to limit? if (strlen(sReply) + strlen(sAdd) < 200) then sReply = sReply .. sAdd; Count = Count + 1; else sReply = sReply .. ":p" .. sName .. "*"; Count = MAXCOUNT + 1; break; end end elseif (Count == MAXCOUNT) then sReply = sReply .. ":p" .. sName .. "*"; Count = Count + 1; break; end end end if (Count ~= MAXCOUNT + 1) then local iPos = strfind(KARMA_ALPHACHARS, sBucket); if (iPos == nil) or ((iPos + 1) > strlen(KARMA_ALPHACHARS)) then iPos = 1; else iPos = iPos + 1; end sReply = sReply .. ":p" .. strsub(KARMA_ALPHACHARS, iPos, iPos) .. "**"; end SendAddonMessage("KARMA", sReply, arg3, arg4); end end else if (KARMA_EXCHANGE.ENABLED_WITH ~= arg4) then KarmaChatSecondary("Data exchange request by >" .. KOH.Name2Clickable(arg4) .. "< refused. Use '" .. KARMA_CMDSELF .. " exchangeallow " .. arg4 .. "' to allow them."); end SendAddonMessage("KARMA", "!x1-", arg3, arg4); end end function KarmaObj.Share.AddOnMessageXReply(arg2, arg3, arg4) if (arg4 == nil) or (KARMA_EXCHANGE.START_WITH ~= arg4) then KarmaChatSecondary("Unsolicited data exchange reply by " .. arg4 .. " - ignored."); elseif (strsub(arg2, 3, 3) == "1") then if (strsub(arg2, 4, 4) == "-") then KarmaChatSecondary("Data exchange request was refused by " .. arg4 .. ". :("); elseif (strsub(arg2, 4, 5) == "+:") then KarmaChatDebug("Data exchange request was processed by " .. arg4 .. "."); if (KarmaTrans_ForeignKarmaEntry == nil) then KarmaChatDebug("No use: KarmaTrans is not active. Stopping."); end local sServer = GetCVar("realmName"); -- GetRealmName(): not sure about localization local sFaction = UnitFactionGroup("player"); local sData = strsub(arg2, 6); if (strsub(sData, -1, -1) ~= ":") then sData = sData .. ":"; end local iPos, sFragment; local sPlayer, iKarma, iLevel, iClass, sRace, iPlayed, sNote, sGUID; while (sData ~= "") do local iPos = strfind(sData, ":"); if (iPos == nil) then sFragment = sData; else sFragment = strsub(sData, 1, iPos - 1); sData = strsub(sData, iPos + 1); end if (strsub(sFragment, 1, 1) == "p") then -- store data if (sPlayer ~= nil) and (iKarma ~= nil) and (iPlayed ~= nil) then local sBucket = KarmaObj.NameToBucket(sPlayer); KarmaTrans_ForeignKarmaEntry(sServer, sFaction, arg4, sBucket, sPlayer, iKarma, iPlayed, iLevel, iClass, sRace, sGUID, sNote); KarmaChatDebug("Storing: " .. arg4 .. " -> " .. sPlayer .. ": " .. iKarma .. " / " .. iPlayed); if (KARMA_EXCHANGE.DONE ~= nil) then KARMA_EXCHANGE.COUNT = KARMA_EXCHANGE.COUNT + 1; end elseif (sPlayer ~= nil) then KarmaChatDebug("Hmmmmmm: " .. arg4 .. " -> " .. Karma_NilToString(sPlayer) .. ": " .. Karma_NilToString(iKarma) .. " / " .. Karma_NilToString(iPlayed)); end -- next player sPlayer = strsub(sFragment, 2); -- seen everything once? if (sPlayer == KARMA_EXCHANGE.FIRST) then KARMA_EXCHANGE.START_WITH = nil; KARMA_EXCHANGE.FIRST = nil; KARMA_EXCHANGE.DONE = GetTime(); KarmaChatDefault("Data exchange with >" .. arg4 .. "< completed. Entry count: " .. KARMA_EXCHANGE.COUNT .. " Duration of exchange: " .. KOH.Duration2String(KARMA_EXCHANGE.DONE - KARMA_EXCHANGE.START_AT)); end -- didn't start with anything: set to first encountered entry if (KARMA_EXCHANGE.FIRST == nil) then KARMA_EXCHANGE.FIRST = sPlayer; end -- end of sequence marker? if (strsub(sPlayer, -1, -1) == "*") then sPlayer = nil; KARMA_EXCHANGE.ACK_IS = strsub(sFragment, 2, -2); KarmaChatDebug("End of group reached, will continue with >" .. KARMA_EXCHANGE.ACK_IS .. "<"); if (KarmaTrans_ForeignKarmaContinueWithSet ~= nil) then KarmaTrans_ForeignKarmaContinueWithSet(sServer, sFaction, arg4, KARMA_EXCHANGE.ACK_IS); end end iKarma = nil; iLevel = nil; iClass = nil; sRace = nil; iPlayed = nil; sNote = nil; sGUID = nil; elseif (strsub(sFragment, 1, 1) == "k") then iKarma = tonumber(strsub(sFragment, 2)); elseif (strsub(sFragment, 1, 1) == "l") then iLevel = tonumber(strsub(sFragment, 2)); elseif (strsub(sFragment, 1, 2) == "ci") then iClass = tonumber(strsub(sFragment, 3)); elseif (strsub(sFragment, 1, 2) == "rs") then sRace = strsub(sFragment, 3); elseif (strsub(sFragment, 1, 2) == "tt") then iPlayed = tonumber(strsub(sFragment, 3)); elseif (strsub(sFragment, 1, 2) == "id") then sGUID = strsub(sFragment, 3); elseif (strsub(sFragment, 1, 2) == "np") then sNote = strsub(sFragment, 3); if (strsub(sNote, 1, 1) == "#") then sNote = strsub(sNote, 2); sNote = string.gsub(sNote, "#!#!", ":"); sNote = string.gsub(sNote, "#!", "!"); sNote = string.gsub(sNote, "##", "#"); end end end KARMA_EXCHANGE.ACK_AT = GetTime() + strlen(arg2) / 100; end end end function KarmaObj.Share.CommandsInsert() KarmaObj.Slash.CommandAdd("exchangeallow", Karma_ExchangeAllow); KarmaObj.Slash.CommandAdd("exchangerequest", Karma_ExchangeRequest); KarmaObj.Slash.CommandAdd("exchangestatus", Karma_ExchangeStatus); KarmaObj.Slash.CommandAdd("exchangeupdate", Karma_ExchangeUpdate); KarmaObj.Slash.CommandAdd("exchangetrust", Karma_ExchangeTrust); end