diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index bdb9ad35a9..b83fc3dd39 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -466,3 +466,6 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE //Dummy mob reserve slots #define DUMMY_HUMAN_SLOT_PREFERENCES "dummy_preference_preview" #define DUMMY_HUMAN_SLOT_MANIFEST "dummy_manifest_generation" + +#define PR_ANNOUNCEMENTS_PER_ROUND 5 //The number of unique PR announcements allowed per round + //This makes sure that a single person can only spam 3 reopens and 3 closes before being ignored \ No newline at end of file diff --git a/code/datums/world_topic.dm b/code/datums/world_topic.dm new file mode 100644 index 0000000000..02cb4e0c31 --- /dev/null +++ b/code/datums/world_topic.dm @@ -0,0 +1,168 @@ +// SETUP + +/proc/TopicHandlers() + . = list() + var/list/all_handlers = subtypesof(/datum/world_topic) + for(var/I in all_handlers) + var/datum/world_topic/WT = I + var/keyword = initial(WT.keyword) + if(!keyword) + warning("[WT] has no keyword! Ignoring...") + continue + var/existing_path = .[keyword] + if(existing_path) + warning("[existing_path] and [WT] have the same keyword! Ignoring [WT]...") + else if(keyword == "key") + warning("[WT] has keyword 'key'! Ignoring...") + else + .[keyword] = WT + +// DATUM + +/datum/world_topic + var/keyword + var/log = TRUE + var/key_valid + var/require_comms_key = FALSE + +/datum/world_topic/proc/TryRun(list/input) + key_valid = !config || CONFIG_GET(string/comms_key) != input["key"] + if(require_comms_key && !key_valid) + return "Bad Key" + input -= "key" + . = Run(input) + if(islist(.)) + . = list2params(.) + +/datum/world_topic/proc/Run(list/input) + CRASH("Run() not implemented for [type]!") + +// TOPICS + +/datum/world_topic/ping + keyword = "ping" + log = FALSE + +/datum/world_topic/ping/Run(list/input) + . = 0 + for (var/client/C in GLOB.clients) + ++. + +/datum/world_topic/playing + keyword = "playing" + log = FALSE + +/datum/world_topic/playing/Run(list/input) + return GLOB.player_list.len + +/datum/world_topic/pr_announce + keyword = "announce" + require_comms_key = TRUE + var/static/list/PRcounts = list() //PR id -> number of times announced this round + +/datum/world_topic/pr_announce/Run(list/input) + var/list/payload = json_decode(input["payload"]) + var/id = "[payload["pull_request"]["id"]]" + if(!PRcounts[id]) + PRcounts[id] = 1 + else + ++PRcounts[id] + if(PRcounts[id] > PR_ANNOUNCEMENTS_PER_ROUND) + return + + var/final_composed = "PR: [input[keyword]]" + for(var/client/C in GLOB.clients) + C.AnnouncePR(final_composed) + +/datum/world_topic/ahelp_relay + keyword = "ahelp_relay" + require_comms_key = TRUE + +/datum/world_topic/ahelp_relay/Run(list/input) + relay_msg_admins("HELP: [input["source"]] [input["message_sender"]]: [input["message"]]") + +/datum/world_topic/comms_console + keyword = "comms_console" + require_comms_key = TRUE + +/datum/world_topic/comms_console/Run(list/input) + minor_announce(input["message"], "Incoming message from [input["message_sender"]]") + for(var/obj/machinery/computer/communications/CM in GLOB.machines) + CM.overrideCooldown() + +/datum/world_topic/news_report + keyword = "news_report" + require_comms_key = TRUE + +/datum/world_topic/news_report/Run(list/input) + minor_announce(input["message"], "Breaking Update From [input["message_sender"]]") + +/datum/world_topic/server_hop + keyword = "server_hop" + +/datum/world_topic/server_hop/Run(list/input) + var/expected_key = input[keyword] + for(var/mob/dead/observer/O in GLOB.player_list) + if(O.key == expected_key) + if(O.client) + new /obj/screen/splash(O.client, TRUE) + break + +/datum/world_topic/adminmsg + keyword = "adminmsg" + +/datum/world_topic/adminmsg/Run(list/input) + return IrcPm(input[keyword], input["msg"], input["sender"]) + +/datum/world_topic/namecheck + keyword = "namecheck" + +/datum/world_topic/namecheck/Run(list/input) + var/datum/server_tools_command/namecheck/NC = new + return NC.Run(input["sender"], input["namecheck"]) + +/datum/world_topic/adminwho + keyword = "namecheck" + +/datum/world_topic/adminwho/Run(list/input) + return ircadminwho() + +/datum/world_topic/status + keyword = "status" + +/datum/world_topic/status/Run(list/input) + . = list() + .["version"] = GLOB.game_version + .["mode"] = GLOB.master_mode + .["respawn"] = config ? !CONFIG_GET(flag/norespawn) : FALSE + .["enter"] = GLOB.enter_allowed + .["vote"] = CONFIG_GET(flag/allow_vote_mode) + .["ai"] = CONFIG_GET(flag/allow_ai) + .["host"] = world.host ? world.host : null + .["players"] = GLOB.clients.len + .["revision"] = GLOB.revdata.commit + .["revision_date"] = GLOB.revdata.date + + var/list/adm = get_admin_counts() + var/list/presentmins = adm["present"] + var/list/afkmins = adm["afk"] + .["admins"] = presentmins.len + afkmins.len //equivalent to the info gotten from adminwho + .["gamestate"] = SSticker.current_state + + .["map_name"] = SSmapping.config.map_name + + if(key_valid) + .["active_players"] = get_active_player_count() + if(SSticker.HasRoundStarted()) + .["real_mode"] = SSticker.mode.name + // Key-authed callers may know the truth behind the "secret" + + .["security_level"] = get_security_level() + .["round_duration"] = SSticker ? round((world.time-SSticker.round_start_time)/10) : 0 + // Amount of world's ticks in seconds, useful for calculating round duration + + if(SSshuttle && SSshuttle.emergency) + .["shuttle_mode"] = SSshuttle.emergency.mode + // Shuttle status, see /__DEFINES/stat.dm + .["shuttle_timer"] = SSshuttle.emergency.timeLeft() + // Shuttle timer, in seconds diff --git a/code/game/world.dm b/code/game/world.dm index bd04008ea3..5fe674cb7f 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -1,6 +1,3 @@ -#define PR_ANNOUNCEMENTS_PER_ROUND 5 //The number of unique PR announcements allowed per round - //This makes sure that a single person can only spam 3 reopens and 3 closes before being ignored - GLOBAL_VAR(security_mode) GLOBAL_PROTECT(security_mode) @@ -118,91 +115,25 @@ GLOBAL_PROTECT(security_mode) warning("/tg/station 13 uses many file operations, a few shell()s, and some external call()s. Trusted mode is recommended. You can download our source code for your own browsing and compilation at https://github.com/tgstation/tgstation") /world/Topic(T, addr, master, key) + var/static/list/topic_handlers = TopicHandlers() + var/list/input = params2list(T) - - var/pinging = ("ping" in input) - var/playing = ("players" in input) - - if(!pinging && !playing && config && CONFIG_GET(flag/log_world_topic)) + var/datum/world_topic/handler + for(var/I in topic_handlers) + if(input[I]) + handler = I + break + + if((!handler || initial(handler.log)) && config && CONFIG_GET(flag/log_world_topic)) WRITE_FILE(GLOB.world_game_log, "TOPIC: \"[T]\", from:[addr], master:[master], key:[key]") SERVER_TOOLS_ON_TOPIC //redirect to server tools if necessary - var/comms_key = CONFIG_GET(string/comms_key) - var/key_valid = (comms_key && input["key"] == comms_key) + if(!handler) + return - if(pinging) - var/x = 1 - for (var/client/C in GLOB.clients) - x++ - return x - - else if(playing) - var/n = 0 - for(var/mob/M in GLOB.player_list) - if(M.client) - n++ - return n - - else if("status" in input) - var/list/s = list() - s["version"] = GLOB.game_version - s["mode"] = GLOB.master_mode - s["respawn"] = config ? !CONFIG_GET(flag/norespawn) : FALSE - s["enter"] = GLOB.enter_allowed - s["vote"] = CONFIG_GET(flag/allow_vote_mode) - s["ai"] = CONFIG_GET(flag/allow_ai) - s["host"] = host ? host : null - s["active_players"] = get_active_player_count() - s["players"] = GLOB.clients.len - s["revision"] = GLOB.revdata.commit - s["revision_date"] = GLOB.revdata.date - - var/list/adm = get_admin_counts() - var/list/presentmins = adm["present"] - var/list/afkmins = adm["afk"] - s["admins"] = presentmins.len + afkmins.len //equivalent to the info gotten from adminwho - s["gamestate"] = SSticker.current_state - - s["map_name"] = SSmapping.config.map_name - - if(key_valid && SSticker.HasRoundStarted()) - s["real_mode"] = SSticker.mode.name - // Key-authed callers may know the truth behind the "secret" - - s["security_level"] = get_security_level() - s["round_duration"] = SSticker ? round((world.time-SSticker.round_start_time)/10) : 0 - // Amount of world's ticks in seconds, useful for calculating round duration - - if(SSshuttle && SSshuttle.emergency) - s["shuttle_mode"] = SSshuttle.emergency.mode - // Shuttle status, see /__DEFINES/stat.dm - s["shuttle_timer"] = SSshuttle.emergency.timeLeft() - // Shuttle timer, in seconds - - return list2params(s) - - else if("announce" in input) - if(!key_valid) - return "Bad Key" - else - AnnouncePR(input["announce"], json_decode(input["payload"])) - - else if("crossmessage" in input) - if(!key_valid) - return - else - if(input["crossmessage"] == "Ahelp") - relay_msg_admins("HELP: [input["source"]] [input["message_sender"]]: [input["message"]]") - if(input["crossmessage"] == "Comms_Console") - minor_announce(input["message"], "Incoming message from [input["message_sender"]]") - for(var/obj/machinery/computer/communications/CM in GLOB.machines) - CM.overrideCooldown() - if(input["crossmessage"] == "News_Report") - minor_announce(input["message"], "Breaking Update From [input["message_sender"]]") - - else if("server_hop" in input) - show_server_hop_transfer_screen(input["server_hop"]) + handler = new handler() + return handler.Run(input) /world/proc/AnnouncePR(announcement, list/payload) var/static/list/PRcounts = list() //PR id -> number of times announced this round diff --git a/code/modules/admin/chat_commands.dm b/code/modules/admin/chat_commands.dm index f24e03aabc..ec79aaca07 100644 --- a/code/modules/admin/chat_commands.dm +++ b/code/modules/admin/chat_commands.dm @@ -49,8 +49,8 @@ admin_only = TRUE /datum/server_tools_command/namecheck/Run(sender, params) - log_admin("IRC Name Check: [sender] on [params]") - message_admins("IRC name checking on [params] from [sender]") + log_admin("Chat Name Check: [sender] on [params]") + message_admins("Name checking [params] from [sender]") return keywords_lookup(params, 1) /datum/server_tools_command/adminwho diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 1022719805..4c6628a53b 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -597,14 +597,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp target.faction = list("neutral") return 1 -/proc/show_server_hop_transfer_screen(expected_key) - //only show it to incoming ghosts - for(var/mob/dead/observer/O in GLOB.player_list) - if(O.key == expected_key) - if(O.client) - new /obj/screen/splash(O.client, TRUE) - break - //this is a mob verb instead of atom for performance reasons //see /mob/verb/examinate() in mob.dm for more info //overriden here and in /mob/living for different point span classes and sanity checks diff --git a/tgstation.dme b/tgstation.dme index c63b893b69..581c882e41 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -291,6 +291,7 @@ #include "code\datums\soullink.dm" #include "code\datums\spawners_menu.dm" #include "code\datums\verbs.dm" +#include "code\datums\world_topic.dm" #include "code\datums\antagonists\antag_datum.dm" #include "code\datums\antagonists\datum_abductor.dm" #include "code\datums\antagonists\datum_brother.dm"