A little helper for the Admins
Posted: 08 Apr 2026, 19:33
Hello all i just got a little bored ands thought i tried to do some lua scripting again after years and i hope no one is offended when i say the current antirush seems at moment a bit outdated. I understand we are all busy on different stuff so this is not a critic i just used this as prototype how i would approach it.
This is a little prototype with a ingame easy setup. I still need to test it further to make it bulletproof i just thought before i invest more time in this if that would make sense.
I hope this is displayed correct.
The ingame setup is available at moment for slot0 (should still be the first private slot) and if the guid is in the specified file.
Yeah i am sometimes bored in the train.
Have a good day
This is a little prototype with a ingame easy setup. I still need to test it further to make it bulletproof i just thought before i invest more time in this if that would make sense.
I hope this is displayed correct.
Code: Select all
-- AutoAdmin
-- ET 2.60b / N!tmod
--
-- Commands:
-- aa help
-- aa antirush
-- aa antirush [ID]
-- aa trickplant
-- aa trickplant [ID]
-- aa list
-- aa remove [NUMBER]
-- aa edit [NUMBER] [DISTANCE]
--
-- Authorization:
-- Commands only work for client slot 0
-- and only if the player's n_guid is listed in:
-- luas/autoadmin/guid.cfg
--
-- File format:
-- luas/autoadmin/protected_maps/[mapname].cfg
--
-- [antirush]
-- "Shortname" X Y Z Distance
--
-- [trickplant]
-- X Y Z Distance
--
-- Behavior:
-- Antirush:
-- During the first 30% of the map timelimit, rushing protected objectives
-- is blocked. Player is killed, planted dynamite is removed.
--
-- Trickplant:
-- If a player plants dynamite inside a protected trickplant area,
-- the planted dynamite is removed, but the player is not killed.
local MODNAME = "AutoAdmin"
local VERSION = "2.0"
local MAX_GENTITIES = 1024
local ANTIRUSH_SCAN_RANGE = 1000
local TRICKPLANT_SCAN_RANGE = 650
local PROTECT_PERCENT = 0.30
local GUID_FILE = "luas/autoadmin/guid.cfg"
local MAP_DIR = "luas/autoadmin/protected_maps/"
local antirushEntries = {}
local trickplantEntries = {}
local currentLevelTime = 0
local protectionStartLevelTime = 0
local announceDone = false
local announceAtLevelTime = 0
local protectionExpiredAnnounced = false
local DYNAMITE_PLANT_PATTERN = '^Dynamite_Plant:%s*(%d+)%s*$'
local function printToClient(clientNum, text)
et.trap_SendServerCommand(clientNum, 'print "' .. text .. '\n"')
end
local function chatAll(text)
et.trap_SendServerCommand(-1, 'chat "' .. text .. '\n"')
end
local function appendLine(fd, line)
local text = tostring(line) .. "\n"
et.trap_FS_Write(text, string.len(text), fd)
end
local function trim(s)
if not s then
return ""
end
return string.gsub(string.gsub(s, "^%s+", ""), "%s+$", "")
end
local function sanitizeMapname(name)
if not name or name == "" then
return "unknownmap"
end
return string.gsub(name, "[^%w_%-%+]", "_")
end
local function sanitizeText(value)
if not value or value == "" then
return "-"
end
value = tostring(value)
value = string.gsub(value, '"', "'")
value = string.gsub(value, "[\r\n]", " ")
return value
end
local function tryGetField(entNum, fieldName)
local ok, value = pcall(et.gentity_get, entNum, fieldName)
if ok and value ~= nil then
return value
end
return nil
end
local function vectorToXYZ(v)
if type(v) ~= "table" then
return nil, nil, nil
end
if v[1] ~= nil and v[2] ~= nil and v[3] ~= nil then
return tonumber(v[1]), tonumber(v[2]), tonumber(v[3])
end
return nil, nil, nil
end
local function parseOriginString(origin)
if not origin or origin == "" then
return nil, nil, nil
end
local x, y, z = string.match(
tostring(origin),
"([%-%.%d]+)%s+([%-%.%d]+)%s+([%-%.%d]+)"
)
if x and y and z then
return tonumber(x), tonumber(y), tonumber(z)
end
return nil, nil, nil
end
local function distance3d(x1, y1, z1, x2, y2, z2)
local dx = x2 - x1
local dy = y2 - y1
local dz = z2 - z1
return math.sqrt(dx * dx + dy * dy + dz * dz)
end
local function getSpawnVar(entNum, key)
local ok, value = pcall(et.G_GetSpawnVar, entNum, key)
if ok and value and value ~= "" then
return tostring(value)
end
return nil
end
local function getMapName()
local mapname = et.trap_Cvar_Get("mapname")
if not mapname or mapname == "" then
mapname = "unknownmap"
end
return sanitizeMapname(mapname)
end
local function getMapFilePath()
return MAP_DIR .. getMapName() .. ".cfg"
end
local function getMapTimeLimitMinutes()
local timelimit = et.trap_Cvar_Get("timelimit")
local n = tonumber(timelimit)
if not n or n < 0 then
return 0
end
return n
end
local function getProtectMinutes()
return getMapTimeLimitMinutes() * PROTECT_PERCENT
end
local function getProtectMilliseconds()
return getProtectMinutes() * 60000.0
end
local function isProtectionActive()
return currentLevelTime < (protectionStartLevelTime + getProtectMilliseconds())
end
local function readWholeFile(path)
local fd, len = et.trap_FS_FOpenFile(path, et.FS_READ)
if not fd or fd < 0 then
return nil
end
if not len or len <= 0 then
et.trap_FS_FCloseFile(fd)
return ""
end
local content = et.trap_FS_Read(fd, len)
et.trap_FS_FCloseFile(fd)
return content
end
local function getPlayerOrigin(clientNum)
local vec = tryGetField(clientNum, "ps.origin")
if vec then
local x, y, z = vectorToXYZ(vec)
if x and y and z then
return x, y, z
end
end
vec = tryGetField(clientNum, "r.currentOrigin")
if vec then
local x, y, z = vectorToXYZ(vec)
if x and y and z then
return x, y, z
end
end
return nil, nil, nil
end
local function getPlayerName(clientNum)
local userinfo = et.trap_GetUserinfo(clientNum)
if not userinfo or userinfo == "" then
return tostring(clientNum)
end
local name = et.Info_ValueForKey(userinfo, "name")
if not name or name == "" then
return tostring(clientNum)
end
return name
end
local function getPlayerNGuid(clientNum)
local userinfo = et.trap_GetUserinfo(clientNum)
if not userinfo or userinfo == "" then
return nil
end
local nguid = et.Info_ValueForKey(userinfo, "n_guid")
if not nguid or nguid == "" then
return nil
end
return nguid
end
local allowedGuids = {}
local function loadAllowedGuids()
allowedGuids = {}
local content = readWholeFile(GUID_FILE)
if not content then
et.G_Print(MODNAME .. ": no guid file found at " .. GUID_FILE .. "\n")
return
end
for line in string.gmatch(content, "[^\r\n]+") do
local guid = trim(line)
if guid ~= "" then
allowedGuids[guid] = true
end
end
et.G_Print(MODNAME .. ": loaded allowed GUIDs from " .. GUID_FILE .. "\n")
end
local function isAuthorized(clientNum)
if clientNum ~= 0 then
return false
end
local nguid = getPlayerNGuid(clientNum)
if not nguid then
return false
end
return allowedGuids[nguid] == true
end
local function requireAuthorization(clientNum)
if isAuthorized(clientNum) then
return true
end
printToClient(clientNum, "^1AUTOADMIN:^7 command not authorized")
return false
end
local function getEntityClassname(entNum)
local classname = tryGetField(entNum, "classname")
if classname then
return tostring(classname)
end
classname = getSpawnVar(entNum, "classname")
if classname then
return classname
end
return nil
end
local function isAntirushClass(classname)
return classname == "team_WOLF_objective"
or classname == "team_CTF_redflag"
or classname == "team_CTF_blueflag"
or classname == "trigger_objective_info"
end
local function isDynamiteClass(classname)
if not classname then
return false
end
return string.find(string.lower(classname), "dynamite", 1, true) ~= nil
end
local function getEntityShortname(entNum)
local shortname = getSpawnVar(entNum, "shortname")
if shortname and shortname ~= "" then
return shortname
end
local message = getSpawnVar(entNum, "message")
if message and message ~= "" then
return message
end
local targetname = getSpawnVar(entNum, "targetname")
if targetname and targetname ~= "" then
return targetname
end
return "unknown"
end
local function getEntityOrigin(entNum)
local origin = getSpawnVar(entNum, "origin")
if origin then
local x, y, z = parseOriginString(origin)
if x and y and z then
return x, y, z
end
end
local vec = tryGetField(entNum, "r.currentOrigin")
if vec then
local x, y, z = vectorToXYZ(vec)
if x and y and z then
return x, y, z
end
end
return nil, nil, nil
end
local function isWithinBoxRange(px, py, pz, ex, ey, ez, range)
return math.abs(ex - px) <= range
and math.abs(ey - py) <= range
and math.abs(ez - pz) <= range
end
local function writeProtectedFile()
local path = getMapFilePath()
local fd, len = et.trap_FS_FOpenFile(path, et.FS_WRITE)
if not fd or fd < 0 then
return false, path
end
appendLine(fd, "[antirush]")
for i = 1, #antirushEntries do
local e = antirushEntries[i]
appendLine(fd, string.format('"%s" %.3f %.3f %.3f %.3f',
sanitizeText(e.shortname), e.x, e.y, e.z, e.distance))
end
appendLine(fd, "")
appendLine(fd, "[trickplant]")
for i = 1, #trickplantEntries do
local e = trickplantEntries[i]
appendLine(fd, string.format('%.3f %.3f %.3f %.3f',
e.x, e.y, e.z, e.distance))
end
et.trap_FS_FCloseFile(fd)
return true, path
end
local function loadProtectedFile()
antirushEntries = {}
trickplantEntries = {}
local content = readWholeFile(getMapFilePath())
if not content then
et.G_Print(MODNAME .. ": no protected map cfg found for " .. getMapName() .. "\n")
return
end
local section = ""
for line in string.gmatch(content, "[^\r\n]+") do
line = trim(line)
if line ~= "" then
if line == "[antirush]" then
section = "antirush"
elseif line == "[trickplant]" then
section = "trickplant"
elseif section == "antirush" then
local shortname, x, y, z, distance = string.match(
line,
'^"(.-)"%s+([%-%.%d]+)%s+([%-%.%d]+)%s+([%-%.%d]+)%s+([%-%.%d]+)%s*$'
)
if shortname and x and y and z and distance then
antirushEntries[#antirushEntries + 1] = {
shortname = shortname,
x = tonumber(x),
y = tonumber(y),
z = tonumber(z),
distance = tonumber(distance)
}
end
elseif section == "trickplant" then
local x, y, z, distance = string.match(
line,
'^([%-%.%d]+)%s+([%-%.%d]+)%s+([%-%.%d]+)%s+([%-%.%d]+)%s*$'
)
if x and y and z and distance then
trickplantEntries[#trickplantEntries + 1] = {
x = tonumber(x),
y = tonumber(y),
z = tonumber(z),
distance = tonumber(distance)
}
end
end
end
end
et.G_Print(MODNAME .. ": loaded " .. tostring(#antirushEntries) .. " antirush entries and "
.. tostring(#trickplantEntries) .. " trickplant entries\n")
end
local function getAntirushNamesString()
local names = {}
for i = 1, #antirushEntries do
names[#names + 1] = antirushEntries[i].shortname
end
return table.concat(names, ", ")
end
local function announceProtectedObjectives()
if #antirushEntries == 0 then
return
end
chatAll(string.format(
'^3AUTOADMIN:^7 Rushing the following objectives is prohibited for the first ^3%.1f ^7minutes: ^3%s',
getProtectMinutes(),
getAntirushNamesString()
))
end
local function announceProtectionEnded()
if #antirushEntries == 0 then
return
end
chatAll(string.format(
'^3AUTOADMIN:^7 The following objectives are no longer protected: ^3%s',
getAntirushNamesString()
))
end
local function buildCombinedList()
local combined = {}
for i = 1, #antirushEntries do
combined[#combined + 1] = {
type = "antirush",
index = i
}
end
for i = 1, #trickplantEntries do
combined[#combined + 1] = {
type = "trickplant",
index = i
}
end
return combined
end
local function listSavedEntries(clientNum)
local combined = buildCombinedList()
printToClient(clientNum, "^3AUTOADMIN")
if #combined == 0 then
printToClient(clientNum, "^1No saved entries.")
return
end
for i = 1, #combined do
local ref = combined[i]
if ref.type == "antirush" then
local e = antirushEntries[ref.index]
printToClient(clientNum,
string.format("%d - ANTIRUSH - %s - %.0f", i, sanitizeText(e.shortname), e.distance))
else
local e = trickplantEntries[ref.index]
printToClient(clientNum,
string.format("%d - TRICKPLANT - %.3f %.3f %.3f - %.0f", i, e.x, e.y, e.z, e.distance))
end
end
printToClient(clientNum, "^3aa remove [NUMBER]^7 removes an entry.")
printToClient(clientNum, "^3aa edit [NUMBER] [DISTANCE]^7 changes the distance.")
end
local function removeSavedEntry(clientNum, wantedIndex)
local idx = tonumber(wantedIndex)
if not idx then
printToClient(clientNum, "^1aa remove:^7 invalid number")
return
end
local combined = buildCombinedList()
if idx < 1 or idx > #combined then
printToClient(clientNum, "^1aa remove:^7 number out of range")
return
end
local ref = combined[idx]
local removedText
if ref.type == "antirush" then
removedText = sanitizeText(antirushEntries[ref.index].shortname)
table.remove(antirushEntries, ref.index)
else
local e = trickplantEntries[ref.index]
removedText = string.format("%.3f %.3f %.3f", e.x, e.y, e.z)
table.remove(trickplantEntries, ref.index)
end
local ok, path = writeProtectedFile()
if not ok then
printToClient(clientNum, "^1aa remove:^7 failed to write " .. path)
return
end
printToClient(clientNum, string.format('^3aa remove:^7 removed %s', removedText))
end
local function editSavedEntryDistance(clientNum, wantedIndex, wantedDistance)
local idx = tonumber(wantedIndex)
local distance = tonumber(wantedDistance)
if not idx then
printToClient(clientNum, "^1aa edit:^7 invalid number")
return
end
if not distance or distance <= 0 then
printToClient(clientNum, "^1aa edit:^7 invalid distance")
return
end
local combined = buildCombinedList()
if idx < 1 or idx > #combined then
printToClient(clientNum, "^1aa edit:^7 number out of range")
return
end
local ref = combined[idx]
if ref.type == "antirush" then
antirushEntries[ref.index].distance = distance
else
trickplantEntries[ref.index].distance = distance
end
local ok, path = writeProtectedFile()
if not ok then
printToClient(clientNum, "^1aa edit:^7 failed to write " .. path)
return
end
printToClient(clientNum, string.format("^3aa edit:^7 entry %d distance changed to %.0f", idx, distance))
end
local function findAntirushEntitiesNearPlayer(clientNum)
local px, py, pz = getPlayerOrigin(clientNum)
if not px then
return nil, "could not read your position"
end
local results = {}
for entNum = 0, MAX_GENTITIES - 1 do
local classname = getEntityClassname(entNum)
if classname and isAntirushClass(classname) then
local x, y, z = getEntityOrigin(entNum)
if x and y and z and isWithinBoxRange(px, py, pz, x, y, z, ANTIRUSH_SCAN_RANGE) then
results[#results + 1] = {
entnum = entNum,
shortname = sanitizeText(getEntityShortname(entNum)),
x = x,
y = y,
z = z,
distance = ANTIRUSH_SCAN_RANGE
}
end
end
end
table.sort(results, function(a, b) return a.entnum < b.entnum end)
return results, nil
end
local function listAntirushCandidates(clientNum)
local results, err = findAntirushEntitiesNearPlayer(clientNum)
if not results then
printToClient(clientNum, "^1aa antirush:^7 " .. err)
return
end
printToClient(clientNum, "^3AUTOADMIN ANTIRUSH")
if #results == 0 then
printToClient(clientNum, "^1No matching entities found.")
else
for i = 1, #results do
printToClient(clientNum,
string.format("ID: %d - NAME: %s", results[i].entnum, results[i].shortname))
end
end
printToClient(clientNum, "^3aa antirush [ID]^7 saves the selected objective.")
end
local function saveAntirushById(clientNum, wantedId)
local entnum = tonumber(wantedId)
if not entnum then
printToClient(clientNum, "^1aa antirush:^7 invalid id")
return
end
local results, err = findAntirushEntitiesNearPlayer(clientNum)
if not results then
printToClient(clientNum, "^1aa antirush:^7 " .. err)
return
end
local selected = nil
for i = 1, #results do
if results[i].entnum == entnum then
selected = results[i]
break
end
end
if not selected then
printToClient(clientNum, "^1aa antirush:^7 id not found in your nearby list")
return
end
antirushEntries[#antirushEntries + 1] = {
shortname = selected.shortname,
x = selected.x,
y = selected.y,
z = selected.z,
distance = selected.distance
}
local ok, path = writeProtectedFile()
if not ok then
printToClient(clientNum, "^1aa antirush:^7 failed to write " .. path)
return
end
printToClient(clientNum, string.format(
'^3aa antirush:^7 saved "%s" at %.3f %.3f %.3f with distance %.0f',
selected.shortname, selected.x, selected.y, selected.z, selected.distance
))
end
local function findTrickplantEntitiesNearPlayer(clientNum)
local px, py, pz = getPlayerOrigin(clientNum)
if not px then
return nil, "could not read your position"
end
local results = {}
for entNum = 0, MAX_GENTITIES - 1 do
local classname = getEntityClassname(entNum)
if isDynamiteClass(classname) then
local x, y, z = getEntityOrigin(entNum)
if x and y and z and isWithinBoxRange(px, py, pz, x, y, z, TRICKPLANT_SCAN_RANGE) then
results[#results + 1] = {
entnum = entNum,
x = x,
y = y,
z = z,
distance = TRICKPLANT_SCAN_RANGE
}
end
end
end
table.sort(results, function(a, b) return a.entnum < b.entnum end)
return results, nil
end
local function listTrickplantCandidates(clientNum)
local results, err = findTrickplantEntitiesNearPlayer(clientNum)
if not results then
printToClient(clientNum, "^1aa trickplant:^7 " .. err)
return
end
printToClient(clientNum, "^3AUTOADMIN TRICKPLANT")
if #results == 0 then
printToClient(clientNum, "^1No nearby dynamite entities found.")
else
for i = 1, #results do
printToClient(clientNum,
string.format("ID: %d - POS: %.3f %.3f %.3f", results[i].entnum, results[i].x, results[i].y, results[i].z))
end
end
printToClient(clientNum, "^3aa trickplant [ID]^7 saves the selected trickplant area.")
end
local function saveTrickplantById(clientNum, wantedId)
local entnum = tonumber(wantedId)
if not entnum then
printToClient(clientNum, "^1aa trickplant:^7 invalid id")
return
end
local results, err = findTrickplantEntitiesNearPlayer(clientNum)
if not results then
printToClient(clientNum, "^1aa trickplant:^7 " .. err)
return
end
local selected = nil
for i = 1, #results do
if results[i].entnum == entnum then
selected = results[i]
break
end
end
if not selected then
printToClient(clientNum, "^1aa trickplant:^7 id not found in your nearby list")
return
end
trickplantEntries[#trickplantEntries + 1] = {
x = selected.x,
y = selected.y,
z = selected.z,
distance = selected.distance
}
local ok, path = writeProtectedFile()
if not ok then
printToClient(clientNum, "^1aa trickplant:^7 failed to write " .. path)
return
end
printToClient(clientNum, string.format(
'^3aa trickplant:^7 saved %.3f %.3f %.3f with distance %.0f',
selected.x, selected.y, selected.z, selected.distance
))
end
local function killPlayer(clientNum)
et.G_Damage(clientNum, clientNum, 1022, 400, 24, 0)
end
local function removeClosestDynamiteFromPlayer(clientNum)
local px, py, pz = getPlayerOrigin(clientNum)
if not px then
return false
end
local bestEnt = nil
local bestDist = nil
for entNum = 0, MAX_GENTITIES - 1 do
local classname = getEntityClassname(entNum)
if isDynamiteClass(classname) then
local ex, ey, ez = getEntityOrigin(entNum)
if ex and ey and ez then
local dist = distance3d(px, py, pz, ex, ey, ez)
if not bestDist or dist < bestDist then
bestDist = dist
bestEnt = entNum
end
end
end
end
if bestEnt then
et.G_FreeEntity(bestEnt)
et.G_Print(string.format(
"%s: removed dynamite entity %d from client %d\n",
MODNAME, bestEnt, clientNum
))
return true
end
return false
end
local function findMatchingAntirushEntry(clientNum)
local px, py, pz = getPlayerOrigin(clientNum)
if not px then
return nil
end
for i = 1, #antirushEntries do
local e = antirushEntries[i]
if isWithinBoxRange(px, py, pz, e.x, e.y, e.z, e.distance) then
return e
end
end
return nil
end
local function findMatchingTrickplantEntry(clientNum)
local px, py, pz = getPlayerOrigin(clientNum)
if not px then
return nil
end
for i = 1, #trickplantEntries do
local e = trickplantEntries[i]
if isWithinBoxRange(px, py, pz, e.x, e.y, e.z, e.distance) then
return e
end
end
return nil
end
local function handleDynamitePlant(clientNum)
if #antirushEntries > 0 and isProtectionActive() then
local antirush = findMatchingAntirushEntry(clientNum)
if antirush then
chatAll(string.format(
'^3AUTOADMIN:^7 %s ^7was killed for rushing protected objective ^3%s^7.',
getPlayerName(clientNum),
antirush.shortname
))
killPlayer(clientNum)
removeClosestDynamiteFromPlayer(clientNum)
return
end
end
if #trickplantEntries > 0 then
local trickplant = findMatchingTrickplantEntry(clientNum)
if trickplant then
if removeClosestDynamiteFromPlayer(clientNum) then
chatAll(string.format(
'^3AUTOADMIN:^7 Dynamite planted by %s ^7was removed due to trickplant protection.',
getPlayerName(clientNum)
))
end
return
end
end
end
local function getObjectiveTakenSlot(text)
local slot = string.match(text, '^Item:%s*(%d+)%s+team_CTF_redflag%s*$')
if slot then
return tonumber(slot)
end
slot = string.match(text, '^Item:%s*(%d+)%s+team_CTF_blueflag%s*$')
if slot then
return tonumber(slot)
end
return nil
end
local function handleObjectiveTake(clientNum)
if #antirushEntries == 0 then
return
end
if not isProtectionActive() then
return
end
local antirush = findMatchingAntirushEntry(clientNum)
if antirush then
chatAll(string.format(
'^3AUTOADMIN:^7 %s ^7was killed for rushing protected objective ^3%s^7.',
getPlayerName(clientNum),
antirush.shortname
))
killPlayer(clientNum)
end
end
local function showHelp(clientNum)
printToClient(clientNum, "^3AUTOADMIN HELP")
printToClient(clientNum, "aa help")
printToClient(clientNum, " Shows this help text.")
printToClient(clientNum, "aa antirush")
printToClient(clientNum, " Lists nearby objective entities that can be protected against rushing.")
printToClient(clientNum, "aa antirush [ID]")
printToClient(clientNum, " Saves the selected antirush objective.")
printToClient(clientNum, "aa trickplant")
printToClient(clientNum, " Lists nearby dynamite entities that can be protected against trickplants.")
printToClient(clientNum, "aa trickplant [ID]")
printToClient(clientNum, " Saves the selected trickplant area.")
printToClient(clientNum, "aa list")
printToClient(clientNum, " Shows all saved antirush and trickplant entries.")
printToClient(clientNum, "aa remove [NUMBER]")
printToClient(clientNum, " Removes one saved entry from the combined list.")
printToClient(clientNum, "aa edit [NUMBER] [DISTANCE]")
printToClient(clientNum, " Changes the distance of one saved entry.")
end
function et_InitGame(levelTime, randomSeed, restart)
et.G_Print(string.format("%s %s loaded\n", MODNAME, VERSION))
loadAllowedGuids()
loadProtectedFile()
currentLevelTime = levelTime or 0
protectionStartLevelTime = currentLevelTime
announceDone = false
announceAtLevelTime = currentLevelTime + 5000
protectionExpiredAnnounced = false
et.G_Print(string.format(
"%s: protection starts at levelTime=%d and antirush lasts %.1f minutes\n",
MODNAME,
protectionStartLevelTime,
getProtectMinutes()
))
end
function et_RunFrame(lvltime)
currentLevelTime = lvltime or 0
if not announceDone and currentLevelTime >= announceAtLevelTime then
announceProtectedObjectives()
announceDone = true
end
if announceDone and not protectionExpiredAnnounced and not isProtectionActive() then
announceProtectionEnded()
protectionExpiredAnnounced = true
end
end
function et_Print(text)
if not text then
return
end
local plantSlot = string.match(text, DYNAMITE_PLANT_PATTERN)
if plantSlot then
handleDynamitePlant(tonumber(plantSlot))
return
end
local takeSlot = getObjectiveTakenSlot(text)
if takeSlot then
handleObjectiveTake(takeSlot)
return
end
end
function et_ClientCommand(clientNum, command)
local cmd0 = et.trap_Argv(0)
local cmd1 = et.trap_Argv(1)
local cmd2 = et.trap_Argv(2)
local cmd3 = et.trap_Argv(3)
if cmd0 ~= "aa" then
return 0
end
if not requireAuthorization(clientNum) then
return 1
end
if cmd1 == "help" or cmd1 == "" or cmd1 == nil then
showHelp(clientNum)
return 1
end
if cmd1 == "antirush" then
if cmd2 and cmd2 ~= "" then
saveAntirushById(clientNum, cmd2)
else
listAntirushCandidates(clientNum)
end
return 1
end
if cmd1 == "trickplant" then
if cmd2 and cmd2 ~= "" then
saveTrickplantById(clientNum, cmd2)
else
listTrickplantCandidates(clientNum)
end
return 1
end
if cmd1 == "list" then
listSavedEntries(clientNum)
return 1
end
if cmd1 == "remove" then
if cmd2 and cmd2 ~= "" then
removeSavedEntry(clientNum, cmd2)
else
printToClient(clientNum, "^1aa remove:^7 usage: aa remove [NUMBER]")
end
return 1
end
if cmd1 == "edit" then
if cmd2 and cmd2 ~= "" and cmd3 and cmd3 ~= "" then
editSavedEntryDistance(clientNum, cmd2, cmd3)
else
printToClient(clientNum, "^1aa edit:^7 usage: aa edit [NUMBER] [DISTANCE]")
end
return 1
end
showHelp(clientNum)
return 1
endYeah i am sometimes bored in the train.
Have a good day