--[[ * AutoInvite * Author: Sasky ]]-- if AutoInvite == nil then AutoInvite = {} end AutoInvite.AddonId = "AutoInvite" ------------------------------------------------ --- Utility functions ------------------------------------------------ local function b(v) if v then return "T" else return "F" end end local function nn(val) if val == nil then return "NIL" else return val end end AutoInvite.isCyrodiil = function(unit) if unit == nil then unit = "player" end d("Current zone: '" .. GetUnitZone(unit) .. "'") return GetUnitZone(unit) == "Cyrodiil" end AutoInvite.guildLookup = function(channel, acctName) local guildId = 0 if channel == CHAT_CHANNEL_GUILD_1 or channel == CHAT_CHANNEL_OFFICER_1 then guildId = GetGuildId(1) end if channel == CHAT_CHANNEL_GUILD_2 or channel == CHAT_CHANNEL_OFFICER_2 then guildId = GetGuildId(2) end if channel == CHAT_CHANNEL_GUILD_3 or channel == CHAT_CHANNEL_OFFICER_3 then guildId = GetGuildId(3) end if channel == CHAT_CHANNEL_GUILD_4 or channel == CHAT_CHANNEL_OFFICER_4 then guildId = GetGuildId(4) end if channel == CHAT_CHANNEL_GUILD_5 or channel == CHAT_CHANNEL_OFFICER_5 then guildId = GetGuildId(5) end if guildId == 0 then d("Error - couldn't invite on channel: " .. channel) end local aName for i=1,GetNumGuildMembers(guildId) do aName = GetGuildMemberInfo(guildId,i) if aName == acctName then local hasChar, charName, zone = GetGuildMemberCharacterInfo(guildId,i) -- Might use zone check to NOT auto-invite people outside current zone if leader in Cyrodiil if not hasChar then d("Could not find player name for " .. acctName .. ". Please manually invite.") return "" end charName = charName:gsub("%^.+", "") if AutoInvite.cfg.cyrCheck then d("In Cyrodiil? " .. b(AutoInvite.isCyrodiil()) .. " / Zone: " .. zone) if AutoInvite.isCyrodiil() and zone ~= "Cyrodiil" then d("Player " .. charName .. " is not in Cyrodiil but in " .. zone) d("Blocking invite to prevent crashes.") return "" end end return charName end end end AutoInvite.kickTable = {} function AutoInvite.checkOffline() local now = GetTimeStamp() for i=1,GetGroupSize() do local tag = GetGroupUnitTagByIndex(i) if not IsUnitOnline(tag) then AutoInvite.kickTable[GetUnitName(tag)] = now end end end --Since KickByName doesn't seem to be working function AutoInvite.kickByName(name) for i=1,GetGroupSize() do local tag = GetGroupUnitTagByIndex(i) if GetUnitName(tag) == name then GroupKick(tag) AutoInvite.kickTable[name] = nil return end end end ------------------------------------------------ --- Event handlers ------------------------------------------------ AutoInvite.callback = function(_, messageType, from, message) if not AutoInvite.enabled or not AutoInvite.listening then return end --TODO: Switch to queue-based with timeouts so don't send out too many invites if GetGroupSize() >= AutoInvite.cfg.maxSize then d("Group full. Disabling AutoInvite") AutoInvite.stopListening() end if string.lower(message) == AutoInvite.cfg.watchStr and from ~= nil and from ~= "" then if (messageType >= CHAT_CHANNEL_GUILD_1 and messageType <= CHAT_CHANNEL_OFFICER_5) then from = AutoInvite.guildLookup(messageType, from) if from == "" then return end end --TODO: Add friends list lookup from = from:gsub("%^.+", "") d("Sending invite to " .. from) GroupInvite(from) GroupInviteByName(from) end --d("Checking message '" .. string.lower(message) .."' ?= '" .. AutoInvite.cfg.watchStr .."'") end AutoInvite.playerLeave = function() if AutoInvite.enabled and AutoInvite.cfg.restart and GetGroupSize() < AutoInvite.cfg.maxSize then AutoInvite.startListening() end local unitName = GetUnitName(unitTag):gsub("%^.+", "") AutoInvite.kickTable[unitName] = nil end AutoInvite.offlineEvent = function(_, unitTag, connectStatus) local unitName = GetUnitName(unitTag):gsub("%^.+", "") if connectStatus then d(unitTag .. "/" .. unitName .. " has reconnected") AutoInvite.kickTable[unitName] = nil else d(unitTag .. "/" .. unitName .. " has disconnected") AutoInvite.kickTable[unitName] = GetTimeStamp() end end -- tick function: called every 15s function AutoInvite.kickCheck() if not AutoInvite.cfg.autoKick then return end local now = GetTimeStamp() --d("Check kick") for p,t in pairs(AutoInvite.kickTable) do local offTime = GetDiffBetweenTimeStamps(now, t) if offTime > AutoInvite.cfg.kickDelay then d(" KICK: " .. p .. " offline for " .. offTime) AutoInvite.kickByName(p) else d(p .. " offline for " .. offTime .. " / " .. AutoInvite.cfg.kickDelay) end end end ------------------------------------------------ --- Main interface ------------------------------------------------ AutoInvite.disable = function() AutoInvite.enabled = false AutoInvite.stopListening() EVENT_MANAGER:UnregisterForUpdate("AutoInviteKickCheck") end AutoInvite.stopListening = function() EVENT_MANAGER:UnregisterForEvent(AutoInvite.AddonId, EVENT_CHAT_MESSAGE_CHANNEL) AutoInvite.listening = false end AutoInvite.startListening = function() if not AutoInvite.enabled then AutoInvite.enabled = true AutoInvite.checkOffline() EVENT_MANAGER:RegisterForUpdate("AutoInviteKickCheck", 1000, AutoInvite.kickCheck) end if not AutoInvite.listening and GetGroupSize() < AutoInvite.cfg.maxSize then --Add handler EVENT_MANAGER:RegisterForEvent(AutoInvite.AddonId, EVENT_CHAT_MESSAGE_CHANNEL, AutoInvite.callback) AutoInvite.listening = true end --First check. When option, will have to check option for disable d("AutoInvite listening on string '" .. AutoInvite.cfg.watchStr .. "'") end ------------------------------------------------ --- Command line ------------------------------------------------ -- print command usage AutoInvite.help = function() d("AutoInvite - command '/ai <str>'. Usage") d(" '/ai foo' - autoInvite on 'foo' command'") d(" '/ai help' - show this menu") d(" '/ai' - turn off autoInvite (auto on group full)") return end --Main interaction switch SLASH_COMMANDS["/ai"] = function(str) if not str or str == "" or str == "help" then if not AutoInvite.listening or str == "help" then AutoInvite.help() return end d("Disabling AutoInvite") AutoInvite.disable() return end AutoInvite.cfg.watchStr = string.lower(str) AutoInvite.startListening() end SLASH_COMMANDS["/zdb9"] = function() d("In Cyrodiil? " .. b(AutoInvite.isCyrodiil())) end ------------------------------------------------ --- Initialization ------------------------------------------------ AutoInvite.init = function() EVENT_MANAGER:UnregisterForEvent("AutoInviteInit", EVENT_PLAYER_ACTIVATED) if AutoInvite.initDone then return end AutoInvite.initDone = true local def = { maxSize = 24, restart = false, cyrCheck = false, autoKick = false, kickDelay = 300, watchStr = "", } AutoInvite.cfg = ZO_SavedVars:NewAccountWide("AutoInviteSettings", 1.0, "config", def) EVENT_MANAGER:RegisterForEvent(AutoInvite.AddonId, EVENT_GROUP_MEMBER_LEFT, AutoInvite.playerLeave) EVENT_MANAGER:RegisterForEvent(AutoInvite.AddonId, EVENT_GROUP_MEMBER_CONNECTED_STATUS, AutoInvite.offlineEvent) AutoInvite.listening = false AutoInvite.enabled = false AutoInviteUI.init() end EVENT_MANAGER:RegisterForEvent("AutoInviteInit", EVENT_PLAYER_ACTIVATED, AutoInvite.init) -- Debug commands SLASH_COMMANDS["/aik"] = function() local now = GetTimeStamp() --d("Current timestamp: " .. GetTimeStamp()) --d("Offline players:") for p,t in pairs(AutoInvite.kickTable) do local offTime = now - t if offTime > 300 then d(" KICK: " .. p .. " offline for " .. now - t) else --d(" " .. p .. " offline for " .. now - t) end end end SLASH_COMMANDS["/aikick"] = function() local now = GetTimeStamp() d("Offline players:") for p,t in pairs(AutoInvite.kickTable) do local offTime = now - t if offTime > AutoInvite.cfg.kickDelay then d(" KICK: " .. p .. " offline for " .. now - t) GroupKickByName(p) else d(" " .. p .. " offline for " .. now - t) end end end