diff --git a/code/__DEFINES/server_tools.dm b/code/__DEFINES/server_tools.dm
index 4624c5914f..a4afa58a87 100644
--- a/code/__DEFINES/server_tools.dm
+++ b/code/__DEFINES/server_tools.dm
@@ -4,6 +4,9 @@
#define IRC_STATUS_THROTTLE 5
+#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
+
//keep these in sync with TGS3
#define SERVICE_WORLD_PARAM "server_service"
#define SERVICE_PR_TEST_JSON "..\\..\\prtestjob.json"
@@ -17,7 +20,7 @@
#define SERVICE_CMD_NAME_CHECK "namecheck"
#define SERVICE_CMD_ADMIN_WHO "adminwho"
-//#define SERVICE_CMD_PARAM_KEY //defined in __compile_options.dm
+#define SERVICE_CMD_PARAM_KEY "serviceCommsKey"
#define SERVICE_CMD_PARAM_COMMAND "command"
#define SERVICE_CMD_PARAM_MESSAGE "message"
#define SERVICE_CMD_PARAM_TARGET "target"
diff --git a/code/_compile_options.dm b/code/_compile_options.dm
index 964c956eca..a669f1b4f5 100644
--- a/code/_compile_options.dm
+++ b/code/_compile_options.dm
@@ -69,8 +69,6 @@
#error You need version 511 or higher
#endif
- #define SERVICE_CMD_PARAM_KEY "serviceCommsKey"
-
//Update this whenever the db schema changes
//make sure you add an update to the schema_version stable in the db changelog
#define DB_MAJOR_VERSION 3
diff --git a/code/game/world.dm b/code/game/world.dm
new file mode 100644
index 0000000000..f5b45a46ca
--- /dev/null
+++ b/code/game/world.dm
@@ -0,0 +1,292 @@
+/world/New()
+ log_world("World loaded at [time_stamp()]")
+
+ SetupExternalRSC()
+
+ GLOB.config_error_log = GLOB.world_href_log = GLOB.world_runtime_log = GLOB.world_attack_log = GLOB.world_game_log = file("data/logs/config_error.log") //temporary file used to record errors with loading config, moved to log directory once logging is set bl
+
+ make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once)
+
+ config = new
+
+ CheckSchemaVersion()
+ SetRoundID()
+
+ SetupLogs()
+
+ if(!RunningService()) //tgs2 support
+ GLOB.revdata.DownloadPRDetails()
+
+ load_motd()
+ load_admins()
+ LoadVerbs(/datum/verbs/menu)
+ if(config.usewhitelist)
+ load_whitelist()
+ LoadBans()
+
+ GLOB.timezoneOffset = text2num(time2text(0,"hh")) * 36000
+
+ Master.Initialize(10, FALSE)
+
+ if(config.irc_announce_new_game)
+ IRCBroadcast("New round starting on [SSmapping.config.map_name]!")
+
+/world/proc/SetupExternalRSC()
+#if (PRELOAD_RSC == 0)
+ external_rsc_urls = world.file2list("config/external_rsc_urls.txt","\n")
+ var/i=1
+ while(i<=external_rsc_urls.len)
+ if(external_rsc_urls[i])
+ i++
+ else
+ external_rsc_urls.Cut(i,i+1)
+#endif
+
+/world/proc/CheckSchemaVersion()
+ if(config.sql_enabled)
+ if(SSdbcore.Connect())
+ log_world("Database connection established.")
+ var/datum/DBQuery/query_db_version = SSdbcore.NewQuery("SELECT major, minor FROM [format_table_name("schema_revision")] ORDER BY date DESC LIMIT 1")
+ query_db_version.Execute()
+ if(query_db_version.NextRow())
+ var/db_major = text2num(query_db_version.item[1])
+ var/db_minor = text2num(query_db_version.item[2])
+ if(db_major < DB_MAJOR_VERSION || db_minor < DB_MINOR_VERSION)
+ message_admins("Database schema ([db_major].[db_minor]) is behind latest schema version ([DB_MAJOR_VERSION].[DB_MINOR_VERSION]), this may lead to undefined behaviour or errors")
+ log_sql("Database schema ([db_major].[db_minor]) is behind latest schema version ([DB_MAJOR_VERSION].[DB_MINOR_VERSION]), this may lead to undefined behaviour or errors")
+ else
+ message_admins("Could not get schema version from database")
+ else
+ log_world("Your server failed to establish a connection with the database.")
+
+/world/proc/SetRoundID()
+ if(config.sql_enabled)
+ if(SSdbcore.Connect())
+ var/datum/DBQuery/query_round_start = SSdbcore.NewQuery("INSERT INTO [format_table_name("round")] (start_datetime, server_ip, server_port) VALUES (Now(), INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]')")
+ query_round_start.Execute()
+ var/datum/DBQuery/query_round_last_id = SSdbcore.NewQuery("SELECT LAST_INSERT_ID()")
+ query_round_last_id.Execute()
+ if(query_round_last_id.NextRow())
+ GLOB.round_id = query_round_last_id.item[1]
+
+/world/proc/SetupLogs()
+ GLOB.log_directory = "data/logs/[time2text(world.realtime, "YYYY/MM/DD")]/round-"
+ if(GLOB.round_id)
+ GLOB.log_directory += "[GLOB.round_id]"
+ else
+ GLOB.log_directory += "[replacetext(time_stamp(), ":", ".")]"
+ GLOB.world_game_log = file("[GLOB.log_directory]/game.log")
+ GLOB.world_attack_log = file("[GLOB.log_directory]/attack.log")
+ GLOB.world_runtime_log = file("[GLOB.log_directory]/runtime.log")
+ GLOB.world_href_log = file("[GLOB.log_directory]/hrefs.html")
+ WRITE_FILE(GLOB.world_game_log, "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------")
+ WRITE_FILE(GLOB.world_attack_log, "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------")
+ WRITE_FILE(GLOB.world_runtime_log, "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------")
+ GLOB.changelog_hash = md5('html/changelog.html') //used for telling if the changelog has changed recently
+ if(fexists(GLOB.config_error_log))
+ fcopy(GLOB.config_error_log, "[GLOB.log_directory]/config_error.log")
+ fdel(GLOB.config_error_log)
+
+ if(GLOB.round_id)
+ log_game("Round ID: [GLOB.round_id]")
+
+/world/Topic(T, addr, master, key)
+ var/list/input = params2list(T)
+
+ var/pinging = ("ping" in input)
+ var/playing = ("players" in input)
+
+ if(!pinging && !playing && config && config.log_world_topic)
+ WRITE_FILE(GLOB.world_game_log, "TOPIC: \"[T]\", from:[addr], master:[master], key:[key]")
+
+ if(input[SERVICE_CMD_PARAM_KEY])
+ return ServiceCommand(input)
+ var/key_valid = (global.comms_allowed && input["key"] == global.comms_key)
+
+ 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("ircstatus" in input) //tgs2 support
+ var/static/last_irc_status = 0
+ if(world.time - last_irc_status < 50)
+ return
+ var/list/adm = get_admin_counts()
+ var/list/allmins = adm["total"]
+ var/status = "Admins: [allmins.len] (Active: [english_list(adm["present"])] AFK: [english_list(adm["afk"])] Stealth: [english_list(adm["stealth"])] Skipped: [english_list(adm["noflags"])]). "
+ status += "Players: [GLOB.clients.len] (Active: [get_active_player_count(0,1,0)]). Mode: [SSticker.mode.name]."
+ send2irc("Status", status)
+ last_irc_status = world.time
+
+ else if("status" in input)
+ var/list/s = list()
+ s["version"] = GLOB.game_version
+ s["mode"] = GLOB.master_mode
+ s["respawn"] = config ? GLOB.abandon_allowed : 0
+ s["enter"] = GLOB.enter_allowed
+ s["vote"] = config.allow_vote_mode
+ s["ai"] = config.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("adminmsg" in input) //tgs2 support
+ if(!key_valid)
+ return "Bad Key"
+ else
+ return IrcPm(input["adminmsg"],input["msg"],input["sender"])
+
+ else if("namecheck" in input) //tgs2 support
+ if(!key_valid)
+ return "Bad Key"
+ else
+ log_admin("IRC Name Check: [input["sender"]] on [input["namecheck"]]")
+ message_admins("IRC name checking on [input["namecheck"]] from [input["sender"]]")
+ return keywords_lookup(input["namecheck"],1)
+ else if("adminwho" in input) //tgs2 support
+ if(!key_valid)
+ return "Bad Key"
+ else
+ return ircadminwho()
+ else if("server_hop" in input)
+ show_server_hop_transfer_screen(input["server_hop"])
+
+/world/proc/AnnouncePR(announcement, list/payload)
+ var/static/list/PRcounts = list() //PR id -> number of times announced this round
+ 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: [announcement]"
+ for(var/client/C in GLOB.clients)
+ C.AnnouncePR(final_composed)
+
+/world/Reboot(reason = 0, fast_track = FALSE)
+ ServiceReboot() //handles alternative actions if necessary
+ if (reason || fast_track) //special reboot, do none of the normal stuff
+ if (usr)
+ log_admin("[key_name(usr)] Has requested an immediate world restart via client side debugging tools")
+ message_admins("[key_name_admin(usr)] Has requested an immediate world restart via client side debugging tools")
+ to_chat(world, "Rebooting World immediately due to host request")
+ else
+ to_chat(world, "Rebooting world...")
+ Master.Shutdown() //run SS shutdowns
+ log_world("World rebooted at [time_stamp()]")
+ ..()
+
+/world/proc/load_motd()
+ GLOB.join_motd = file2text("config/motd.txt") + "
" + GLOB.revdata.GetTestMergeInfo()
+
+/world/proc/update_status()
+ var/s = ""
+
+ if (config && config.server_name)
+ s += "[config.server_name] — "
+
+ s += "[station_name()]";
+ s += " ("
+ s += "" //Change this to wherever you want the hub to link to.
+ s += "Default" //Replace this with something else. Or ever better, delete it and uncomment the game version.
+ s += ""
+ s += ")"
+
+ var/list/features = list()
+
+ if(GLOB.master_mode)
+ features += GLOB.master_mode
+
+ if (!GLOB.enter_allowed)
+ features += "closed"
+
+ features += GLOB.abandon_allowed ? "respawn" : "no respawn"
+
+ if (config && config.allow_vote_mode)
+ features += "vote"
+
+ if (config && config.allow_ai)
+ features += "AI allowed"
+
+ var/n = 0
+ for (var/mob/M in GLOB.player_list)
+ if (M.client)
+ n++
+
+ if (n > 1)
+ features += "~[n] players"
+ else if (n > 0)
+ features += "~[n] player"
+
+ if (!host && config && config.hostedby)
+ features += "hosted by [config.hostedby]"
+
+ if (features)
+ s += ": [jointext(features, ", ")]"
+
+ status = s
+
+/world/proc/update_hub_visibility(new_visibility)
+ if(new_visibility == GLOB.hub_visibility)
+ return
+ GLOB.hub_visibility = new_visibility
+ if(GLOB.hub_visibility)
+ hub_password = "kMZy3U5jJHSiBQjr"
+ else
+ hub_password = "SORRYNOPASSWORD"
diff --git a/code/world.dm b/code/world.dm
index a0c5ae43f8..7e17e579b1 100644
--- a/code/world.dm
+++ b/code/world.dm
@@ -1,3 +1,6 @@
+//This file is just for the necessary /world definition
+//Try looking in game/world.dm
+
/world
mob = /mob/dead/new_player
turf = /turf/open/space/basic
diff --git a/code/world.dm.rej b/code/world.dm.rej
index cde7698a21..e82c17e503 100644
--- a/code/world.dm.rej
+++ b/code/world.dm.rej
@@ -1,10 +1,301 @@
diff a/code/world.dm b/code/world.dm (rejected hunks)
-@@ -59,7 +59,7 @@
- if(config.sql_enabled)
- if(SSdbcore.Connect())
- log_world("Database connection established.")
-- var/datum/DBQuery/query_db_version = SSdbcore.NewQuery("SELECT major, minor FROM [format_table_name("schema_version")] ORDER BY date DESC LIMIT 1")
-+ var/datum/DBQuery/query_db_version = SSdbcore.NewQuery("SELECT major, minor FROM [format_table_name("schema_revision")] ORDER BY date DESC LIMIT 1")
- query_db_version.Execute()
- if(query_db_version.NextRow())
- var/db_major = query_db_version.item[1]
+@@ -10,299 +13,3 @@
+ #ifdef GC_FAILURE_HARD_LOOKUP
+ loop_checks = FALSE
+ #endif
+-
+-/world/New()
+- log_world("World loaded at [time_stamp()]")
+-
+- SetupExternalRSC()
+-
+- GLOB.config_error_log = GLOB.world_href_log = GLOB.world_runtime_log = GLOB.world_attack_log = GLOB.world_game_log = file("data/logs/config_error.log") //temporary file used to record errors with loading config, moved to log directory once logging is set bl
+-
+- make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once)
+-
+- config = new
+-
+- CheckSchemaVersion()
+- SetRoundID()
+-
+- SetupLogs()
+-
+- if(!RunningService()) //tgs2 support
+- GLOB.revdata.DownloadPRDetails()
+-
+- load_motd()
+- load_admins()
+- LoadVerbs(/datum/verbs/menu)
+- if(config.usewhitelist)
+- load_whitelist()
+- LoadBans()
+-
+- GLOB.timezoneOffset = text2num(time2text(0,"hh")) * 36000
+-
+- Master.Initialize(10, FALSE)
+-
+- if(config.irc_announce_new_game)
+- IRCBroadcast("New round starting on [SSmapping.config.map_name]!")
+-
+-/world/proc/SetupExternalRSC()
+-#if (PRELOAD_RSC == 0)
+- external_rsc_urls = world.file2list("config/external_rsc_urls.txt","\n")
+- var/i=1
+- while(i<=external_rsc_urls.len)
+- if(external_rsc_urls[i])
+- i++
+- else
+- external_rsc_urls.Cut(i,i+1)
+-#endif
+-
+-/world/proc/CheckSchemaVersion()
+- if(config.sql_enabled)
+- if(SSdbcore.Connect())
+- log_world("Database connection established.")
+- var/datum/DBQuery/query_db_version = SSdbcore.NewQuery("SELECT major, minor FROM [format_table_name("schema_revision")] ORDER BY date DESC LIMIT 1")
+- query_db_version.Execute()
+- if(query_db_version.NextRow())
+- var/db_major = text2num(query_db_version.item[1])
+- var/db_minor = text2num(query_db_version.item[2])
+- if(db_major < DB_MAJOR_VERSION || db_minor < DB_MINOR_VERSION)
+- message_admins("Database schema ([db_major].[db_minor]) is behind latest schema version ([DB_MAJOR_VERSION].[DB_MINOR_VERSION]), this may lead to undefined behaviour or errors")
+- log_sql("Database schema ([db_major].[db_minor]) is behind latest schema version ([DB_MAJOR_VERSION].[DB_MINOR_VERSION]), this may lead to undefined behaviour or errors")
+- else
+- message_admins("Could not get schema version from database")
+- else
+- log_world("Your server failed to establish a connection with the database.")
+-
+-/world/proc/SetRoundID()
+- if(config.sql_enabled)
+- if(SSdbcore.Connect())
+- var/datum/DBQuery/query_round_start = SSdbcore.NewQuery("INSERT INTO [format_table_name("round")] (start_datetime, server_ip, server_port) VALUES (Now(), INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]')")
+- query_round_start.Execute()
+- var/datum/DBQuery/query_round_last_id = SSdbcore.NewQuery("SELECT LAST_INSERT_ID()")
+- query_round_last_id.Execute()
+- if(query_round_last_id.NextRow())
+- GLOB.round_id = query_round_last_id.item[1]
+-
+-/world/proc/SetupLogs()
+- GLOB.log_directory = "data/logs/[time2text(world.realtime, "YYYY/MM/DD")]/round-"
+- if(GLOB.round_id)
+- GLOB.log_directory += "[GLOB.round_id]"
+- else
+- GLOB.log_directory += "[replacetext(time_stamp(), ":", ".")]"
+- GLOB.world_game_log = file("[GLOB.log_directory]/game.log")
+- GLOB.world_attack_log = file("[GLOB.log_directory]/attack.log")
+- GLOB.world_runtime_log = file("[GLOB.log_directory]/runtime.log")
+- GLOB.world_href_log = file("[GLOB.log_directory]/hrefs.html")
+- GLOB.world_game_log << "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------"
+- GLOB.world_attack_log << "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------"
+- GLOB.world_runtime_log << "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------"
+- GLOB.changelog_hash = md5('html/changelog.html') //used for telling if the changelog has changed recently
+- if(fexists(GLOB.config_error_log))
+- fcopy(GLOB.config_error_log, "[GLOB.log_directory]/config_error.log")
+- fdel(GLOB.config_error_log)
+-
+- if(GLOB.round_id)
+- log_game("Round ID: [GLOB.round_id]")
+-
+-/world/Topic(T, addr, master, key)
+- var/list/input = params2list(T)
+-
+- var/pinging = ("ping" in input)
+- var/playing = ("players" in input)
+-
+- if(!pinging && !playing && config && config.log_world_topic)
+- GLOB.world_game_log << "TOPIC: \"[T]\", from:[addr], master:[master], key:[key]"
+-
+- if(input[SERVICE_CMD_PARAM_KEY])
+- return ServiceCommand(input)
+- var/key_valid = (global.comms_allowed && input["key"] == global.comms_key)
+-
+- 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("ircstatus" in input) //tgs2 support
+- var/static/last_irc_status = 0
+- if(world.time - last_irc_status < 50)
+- return
+- var/list/adm = get_admin_counts()
+- var/list/allmins = adm["total"]
+- var/status = "Admins: [allmins.len] (Active: [english_list(adm["present"])] AFK: [english_list(adm["afk"])] Stealth: [english_list(adm["stealth"])] Skipped: [english_list(adm["noflags"])]). "
+- status += "Players: [GLOB.clients.len] (Active: [get_active_player_count(0,1,0)]). Mode: [SSticker.mode.name]."
+- send2irc("Status", status)
+- last_irc_status = world.time
+-
+- else if("status" in input)
+- var/list/s = list()
+- s["version"] = GLOB.game_version
+- s["mode"] = GLOB.master_mode
+- s["respawn"] = config ? GLOB.abandon_allowed : 0
+- s["enter"] = GLOB.enter_allowed
+- s["vote"] = config.allow_vote_mode
+- s["ai"] = config.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("adminmsg" in input) //tgs2 support
+- if(!key_valid)
+- return "Bad Key"
+- else
+- return IrcPm(input["adminmsg"],input["msg"],input["sender"])
+-
+- else if("namecheck" in input) //tgs2 support
+- if(!key_valid)
+- return "Bad Key"
+- else
+- log_admin("IRC Name Check: [input["sender"]] on [input["namecheck"]]")
+- message_admins("IRC name checking on [input["namecheck"]] from [input["sender"]]")
+- return keywords_lookup(input["namecheck"],1)
+- else if("adminwho" in input) //tgs2 support
+- if(!key_valid)
+- return "Bad Key"
+- else
+- return ircadminwho()
+- else if("server_hop" in input)
+- show_server_hop_transfer_screen(input["server_hop"])
+-
+-#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
+-
+-/world/proc/AnnouncePR(announcement, list/payload)
+- var/static/list/PRcounts = list() //PR id -> number of times announced this round
+- 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: [announcement]"
+- for(var/client/C in GLOB.clients)
+- C.AnnouncePR(final_composed)
+-
+-/world/Reboot(reason = 0, fast_track = FALSE)
+- ServiceReboot() //handles alternative actions if necessary
+- if (reason || fast_track) //special reboot, do none of the normal stuff
+- if (usr)
+- log_admin("[key_name(usr)] Has requested an immediate world restart via client side debugging tools")
+- message_admins("[key_name_admin(usr)] Has requested an immediate world restart via client side debugging tools")
+- to_chat(world, "Rebooting World immediately due to host request")
+- else
+- to_chat(world, "Rebooting world...")
+- Master.Shutdown() //run SS shutdowns
+- log_world("World rebooted at [time_stamp()]")
+- ..()
+-
+-/world/proc/load_motd()
+- GLOB.join_motd = file2text("config/motd.txt") + "
" + GLOB.revdata.GetTestMergeInfo()
+-
+-/world/proc/update_status()
+- var/s = ""
+-
+- if (config && config.server_name)
+- s += "[config.server_name] — "
+-
+- s += "[station_name()]";
+- s += " ("
+- s += "" //Change this to wherever you want the hub to link to.
+- s += "Default" //Replace this with something else. Or ever better, delete it and uncomment the game version.
+- s += ""
+- s += ")"
+-
+- var/list/features = list()
+-
+- if(GLOB.master_mode)
+- features += GLOB.master_mode
+-
+- if (!GLOB.enter_allowed)
+- features += "closed"
+-
+- features += GLOB.abandon_allowed ? "respawn" : "no respawn"
+-
+- if (config && config.allow_vote_mode)
+- features += "vote"
+-
+- if (config && config.allow_ai)
+- features += "AI allowed"
+-
+- var/n = 0
+- for (var/mob/M in GLOB.player_list)
+- if (M.client)
+- n++
+-
+- if (n > 1)
+- features += "~[n] players"
+- else if (n > 0)
+- features += "~[n] player"
+-
+- if (!host && config && config.hostedby)
+- features += "hosted by [config.hostedby]"
+-
+- if (features)
+- s += ": [jointext(features, ", ")]"
+-
+- status = s
+-
+-/world/proc/update_hub_visibility(new_visibility)
+- if(new_visibility == GLOB.hub_visibility)
+- return
+- GLOB.hub_visibility = new_visibility
+- if(GLOB.hub_visibility)
+- hub_password = "kMZy3U5jJHSiBQjr"
+- else
+- hub_password = "SORRYNOPASSWORD"
diff --git a/tgstation.dme b/tgstation.dme
index 23ffe1fef1..1475d2335c 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -375,6 +375,7 @@
#include "code\game\shuttle_engines.dm"
#include "code\game\skincmd.dm"
#include "code\game\sound.dm"
+#include "code\game\world.dm"
#include "code\game\area\ai_monitored.dm"
#include "code\game\area\areas.dm"
#include "code\game\area\Space_Station_13_areas.dm"