diff --git a/code/__DEFINES/~skyrat_defines/span.dm b/code/__DEFINES/~skyrat_defines/span.dm
index 2699f0d7ff7..1c9f186d109 100644
--- a/code/__DEFINES/~skyrat_defines/span.dm
+++ b/code/__DEFINES/~skyrat_defines/span.dm
@@ -10,3 +10,5 @@
#define span_smalldanger(str) ("" + str + "")
#define span_userlove(str) ("" + str + "")
#define span_warningplain(str) ("" + str + "")
+#define span_crossooc(str) ("" + str + "")
+#define span_crossasay(str) ("" + str + "")
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index cc99644b64b..df858a24c2a 100644
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -572,7 +572,7 @@ SUBSYSTEM_DEF(ticker)
/datum/controller/subsystem/ticker/proc/send_news_report()
var/news_message
var/news_source = "Nanotrasen News Network"
- var/decoded_station_name = html_decode(station_name()) //decode station_name to avoid minor_announce double encode
+ var/decoded_station_name = html_decode("[CONFIG_GET(string/cross_comms_name)]([station_name()])") //decode station_name to avoid minor_announce double encode //SKYRAT EDIT CHANGE
switch(news_report)
if(NUKE_SYNDICATE_BASE)
news_message = "In a daring raid, the heroic crew of [decoded_station_name] detonated a nuclear device in the heart of a terrorist base."
@@ -632,6 +632,7 @@ SUBSYSTEM_DEF(ticker)
//SKYRAT EDIT - END
if(news_message && length(CONFIG_GET(keyed_list/cross_server))) //SKYRAT EDIT - CONFIG CHECK MOVED FROM ROUNDEND.DM
+ news_message += " (Shift on [CONFIG_GET(string/cross_server_name)] ending!)" //SKYRAT EDIT ADDITION
send2otherserver(news_source, news_message,"News_Report")
//SKYRAT EDIT - START
if(news_message)
diff --git a/code/datums/world_topic.dm b/code/datums/world_topic.dm
index 662dc1a1472..10fe9829722 100644
--- a/code/datums/world_topic.dm
+++ b/code/datums/world_topic.dm
@@ -157,7 +157,8 @@
require_comms_key = TRUE
/datum/world_topic/news_report/Run(list/input)
- minor_announce(input["message"], "Breaking Update From [input["message_sender"]]")
+
+ priority_announce(input["message"], "Breaking Update From [input["message_sender"]]") //SKYRAT EDIT CHANGE
/datum/world_topic/adminmsg
keyword = "adminmsg"
diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm
index 77c030a2c37..072983e2738 100755
--- a/code/game/machinery/computer/communications.dm
+++ b/code/game/machinery/computer/communications.dm
@@ -445,7 +445,9 @@ GLOBAL_VAR_INIT(cops_arrived, FALSE)
payload["network"] = network_name
payload["sender_ckey"] = usr.ckey
- send2otherserver(html_decode(station_name()), message, "Comms_Console", destination == "all" ? null : list(destination), additional_data = payload)
+ var/name_to_send = "[CONFIG_GET(string/cross_comms_name)]([station_name()])" //SKYRAT EDIT ADDITION
+
+ send2otherserver(html_decode(name_to_send), message, "Comms_Console", destination == "all" ? null : list(destination), additional_data = payload) //SKYRAT EDIT END
minor_announce(message, title = "Outgoing message to allied station")
usr.log_talk(message, LOG_SAY, tag = "message to the other server")
message_admins("[ADMIN_LOOKUPFLW(usr)] has sent a message to the other server\[s].")
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 0d492370552..2796b3d46db 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -38,6 +38,7 @@ GLOBAL_PROTECT(admin_verbs_admin)
/client/proc/check_ai_laws, /*shows AI and borg laws*/
/client/proc/ghost_pool_protection, /*opens a menu for toggling ghost roles*/
/datum/admins/proc/toggledchat, // SKYRAT EDIT ADDITION
+ /client/proc/request_help, // SKYRAT EDIT ADDITION
/datum/admins/proc/toggleooc, /*toggles ooc on/off for everyone*/
/datum/admins/proc/toggleoocdead, /*toggles ooc on/off for everyone who is dead*/
/datum/admins/proc/toggleenter, /*toggles whether people can join the current game*/
diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm
index 76c79712e36..67805d9e9ec 100644
--- a/code/modules/admin/verbs/adminhelp.dm
+++ b/code/modules/admin/verbs/adminhelp.dm
@@ -822,12 +822,19 @@ GLOBAL_DATUM_INIT(admin_help_ui_handler, /datum/admin_help_ui_handler, new)
additional_data += type
var/list/servers = CONFIG_GET(keyed_list/cross_server)
- for(var/I in servers)
- if(I == our_id) //No sending to ourselves
- continue
- if(target_servers && !(I in target_servers))
- continue
- world.send_cross_comms(I, additional_data)
+ // SKYRAT EDTI ADDITION
+ if(target_servers == "all")
+ for(var/server in servers)
+ if(server == our_id)
+ continue
+ world.send_cross_comms(server, additional_data)
+ else //SKYRAT EDIT END
+ for(var/I in servers)
+ if(I == our_id) //No sending to ourselves
+ continue
+ if(target_servers && !(I in target_servers))
+ continue
+ world.send_cross_comms(I, additional_data)
/// Sends a message to a given cross comms server by name (by name for security).
/world/proc/send_cross_comms(server_name, list/message, auth = TRUE)
diff --git a/code/modules/admin/verbs/adminsay.dm b/code/modules/admin/verbs/adminsay.dm
index 34ec74f9f57..d5add900737 100644
--- a/code/modules/admin/verbs/adminsay.dm
+++ b/code/modules/admin/verbs/adminsay.dm
@@ -23,6 +23,7 @@
mob.log_talk(msg, LOG_ASAY)
msg = keywords_lookup(msg)
+ send_asay_to_other_server(ckey, msg) //SKYRAT EDIT ADDITION
var/asay_color = prefs.read_preference(/datum/preference/color/asay_color)
var/custom_asay_color = (CONFIG_GET(flag/allow_admin_asaycolor) && asay_color) ? "" : ""
msg = "[span_adminsay("[span_prefix("ADMIN:")] [key_name(usr, 1)] [ADMIN_FLW(mob)]: [custom_asay_color][msg]")][custom_asay_color ? "":null]"
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 6d690f75114..9588a786128 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -226,6 +226,11 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
else if(GLOB.deadmins[ckey])
add_verb(src, /client/proc/readmin)
connecting_admin = TRUE
+ //SKYRAT EDIT ADDITION //We will check the population here, because we need to know if the client is an admin or not.
+ if(!check_population(connecting_admin))
+ qdel(src)
+ return
+ // SKYRAT EDIT END
if(CONFIG_GET(flag/autoadmin))
if(!GLOB.admin_datums[ckey])
var/datum/admin_rank/autorank
diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm
index 4837dc037cd..2352ae86dc8 100644
--- a/code/modules/client/verbs/ooc.dm
+++ b/code/modules/client/verbs/ooc.dm
@@ -72,12 +72,17 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8")
mob.log_talk(raw_msg, LOG_OOC)
var/keyname = key
+
+ if(CONFIG_GET(flag/enable_cross_server_ooc)) //SKYRAT EDIT ADDITION
+ send_ooc_to_other_server(ckey, msg) //SKYRAT EDIT ADDITION
+
if(prefs.unlock_content)
if(prefs.toggles & MEMBER_PUBLIC)
keyname = "[icon2html('icons/member_content.dmi', world, "blag")][keyname]"
if(prefs.hearted)
var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/chat)
keyname = "[sheet.icon_tag("emoji-heart")][keyname]"
+
//The linkify span classes and linkify=TRUE below make ooc text get clickable chat href links if you pass in something resembling a url
for(var/client/receiver as anything in GLOB.clients)
if(!receiver.prefs) // Client being created or deleted. Despite all, this can be null.
diff --git a/code/modules/mob/dead/new_player/login.dm b/code/modules/mob/dead/new_player/login.dm
index f9609f9ea82..ab35f55f04a 100644
--- a/code/modules/mob/dead/new_player/login.dm
+++ b/code/modules/mob/dead/new_player/login.dm
@@ -21,6 +21,13 @@
if(GLOB.admin_notice)
to_chat(src, span_notice("Admin Notice:\n \t [GLOB.admin_notice]"))
+ //SKYRAT EDIT ADDITION
+ var/soft_player_cap = CONFIG_GET(number/player_soft_cap)
+ if(soft_player_cap >= TGS_CLIENT_COUNT)
+ var/datum/callback/connect_callback = CALLBACK(src, .proc/connect_to_second_server)
+ tgui_alert_async(src, "The server is currently experiencing high demand, please consider joining our secondary server.", "High Demand", list("Stay here", "Connect me!"), connect_callback)
+ //SKYRAT EDIT END
+
var/spc = CONFIG_GET(number/soft_popcap)
if(spc && living_player_count() >= spc)
to_chat(src, span_notice("Server Notice:\n \t [CONFIG_GET(string/soft_popcap_message)]"))
diff --git a/config/skyrat/skyrat_config.txt b/config/skyrat/skyrat_config.txt
index 6f556ac1907..002512f0c15 100644
--- a/config/skyrat/skyrat_config.txt
+++ b/config/skyrat/skyrat_config.txt
@@ -5,6 +5,30 @@ SERVERSQLNAME
## Comment this out if you'd like a server that cares only about local bans in the database.
RESPECT_GLOBAL_BANS
+## Automatic population control population limit, will send players(not admins) to the overflow server.
+## Set to 0 to disable
+## MAKE SURE YOU SET AN OVERFLOW IP!
+HARD_PLAYER_CAP 0
+
+## Player prompt to change servers after this cap.
+## Set to 0 to disable
+## MAKE SURE YOU SET AN OVERFLOW IP!
+SOFT_PLAYER_CAP 0
+
+## The IP of the overflow server. See above.
+#OVERFLOW_SERVER_IP byond://example:1337
+
+## Cross server OOC
+## Sends this servers OOC to all other cross servers. Uses cross server name as an identity.
+#ENABLE_CROSS_SERVER_OOC
+
+## Cross server ASAY
+## Sends this servers ASAY to all other cross servers. Uses cross server name as an identity.
+#ENABLE_CROSS_SERVER_ASAY
+
+## The non-IC name we send to OOC and adminsay.
+#CROSS_SERVER_NAME
+
## Comment this out if you want to use the SQL based mentor system, the legacy system uses mentors.txt.
## You need to set up your database to use the SQL based system.
## This flag is automatically enabled if SQL_ENABLED isn't
diff --git a/config/skyrat/swap_ips.txt b/config/skyrat/swap_ips.txt
deleted file mode 100644
index f92baefc75b..00000000000
--- a/config/skyrat/swap_ips.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-# FILE CONTAINS ALTERNATE SERVER IPS THAT YOU'D LIKE TO GIVE PLAYERS ACCESS TO WHEN THEY PRESS THE SWAP SERVER BUTTON
-# FORMAT HAS TO BE SERVERNAME+byond://IPHERE
-
-Action Server+byond://skyrat13.tk:22099
-Roleplay Server+byond://skyrat13.tk:22094
-Bay Server+byond://skyrat13.tk:22095
-Legacy Server+byond://skyrat13.tk:22096
diff --git a/modular_skyrat/master_files/code/_onclick/hud/new_player.dm b/modular_skyrat/master_files/code/_onclick/hud/new_player.dm
index 49b4b04cff5..e5285df0f01 100644
--- a/modular_skyrat/master_files/code/_onclick/hud/new_player.dm
+++ b/modular_skyrat/master_files/code/_onclick/hud/new_player.dm
@@ -8,21 +8,20 @@
. = ..()
if(!.)
return
- if(!CONFIG_GET(flag/server_swap_enabled))
- return
+ var/list/servers = CONFIG_GET(keyed_list/cross_server)
var/mob/dead/new_player/new_player = hud.mymob
- if(GLOB.swappable_ips.len == 1)
- var/server_name = GLOB.swappable_ips[1]
- var/server_ip = GLOB.swappable_ips[server_name]
- var/confirm = tgui_alert(new_player, "Are you sure you want to swap to [server_name] ([server_ip])?", "Swapping server!", list("Connect me!", "Stay here!"))
+ if(servers.len == 1)
+ var/server_name = servers[1]
+ var/server_ip = servers[server_name]
+ var/confirm = tgui_alert(new_player, "Are you sure you want to swap to [server_name] ([server_ip])?", "Swapping server!", list("Send me there", "Stay here"))
if(confirm == "Connect me!")
to_chat_immediate(new_player, "So long, spaceman.")
new_player.client << link(server_ip)
return
- var/server_name = tgui_input_list(new_player, "Please select the server you wish to swap to:", "Swap servers!", GLOB.swappable_ips)
+ var/server_name = tgui_input_list(new_player, "Please select the server you wish to swap to:", "Swap servers!", servers)
if(!server_name)
return
- var/server_ip = GLOB.swappable_ips[server_name]
+ var/server_ip = servers[server_name]
var/confirm = tgui_alert(new_player, "Are you sure you want to swap to [server_name] ([server_ip])?", "Swapping server!", list("Connect me!", "Stay here!"))
if(confirm == "Connect me!")
to_chat_immediate(new_player, "So long, spaceman.")
diff --git a/modular_skyrat/master_files/code/controllers/configuration/entries/skryat_config_entries.dm b/modular_skyrat/master_files/code/controllers/configuration/entries/skyrat_config_entries.dm
similarity index 53%
rename from modular_skyrat/master_files/code/controllers/configuration/entries/skryat_config_entries.dm
rename to modular_skyrat/master_files/code/controllers/configuration/entries/skyrat_config_entries.dm
index cb898e94620..82213bb65c8 100644
--- a/modular_skyrat/master_files/code/controllers/configuration/entries/skryat_config_entries.dm
+++ b/modular_skyrat/master_files/code/controllers/configuration/entries/skyrat_config_entries.dm
@@ -6,6 +6,24 @@
/datum/config_entry/flag/russian_text_formation
+// Overflow server HARD pop cap
+/datum/config_entry/number/player_hard_cap
+
+// Overflow server SOFT pop cap - Notifiaction to join the overflow
+/datum/config_entry/number/player_soft_cap
+
+// Overflow server IP
+/datum/config_entry/string/overflow_server_ip
+
+// Do we broadcast our OOC to all dem servers in cross servers?
+/datum/config_entry/flag/enable_cross_server_ooc
+
+// Do we broadcast our asay to all dem servers in cross servers?
+/datum/config_entry/flag/enable_cross_server_asay
+
+// Name of our server, ooc.
+/datum/config_entry/string/cross_server_name
+
//DISCORD GAME ALERT CONFIGS
//Role id to ping
/datum/config_entry/string/game_alert_role_id
diff --git a/modular_skyrat/modules/admin/code/loud_say.dm b/modular_skyrat/modules/admin/code/loud_say.dm
index 98973c744ae..82d73fc3723 100644
--- a/modular_skyrat/modules/admin/code/loud_say.dm
+++ b/modular_skyrat/modules/admin/code/loud_say.dm
@@ -12,9 +12,12 @@
msg = emoji_parse(msg)
mob.log_talk(msg, LOG_ASAY)
+ send_asay_to_other_server(ckey, span_command_headset(msg))
+
msg = keywords_lookup(msg)
var/custom_asay_color = (CONFIG_GET(flag/allow_admin_asaycolor) && prefs?.read_preference(/datum/preference/color/asay_color)) ? "" : ""
msg = span_command_headset("ADMIN: [key_name(usr, 1)] [ADMIN_FLW(mob)]: [custom_asay_color][msg][custom_asay_color ? "":null]")
+
to_chat(GLOB.admins,
type = MESSAGE_TYPE_ADMINCHAT,
html = msg,
diff --git a/modular_skyrat/modules/lobbyscreen/code/load_servers.dm b/modular_skyrat/modules/lobbyscreen/code/load_servers.dm
deleted file mode 100644
index d1f627d50c7..00000000000
--- a/modular_skyrat/modules/lobbyscreen/code/load_servers.dm
+++ /dev/null
@@ -1,33 +0,0 @@
-/datum/config_entry/flag/server_swap_enabled
-
-GLOBAL_LIST_EMPTY(swappable_ips)
-
-SUBSYSTEM_DEF(serverswap)
- name = "Server Swap"
- flags = SS_NO_FIRE
- init_order = INIT_ORDER_DEFAULT
-
-
-/datum/controller/subsystem/serverswap/Initialize()
- if(!CONFIG_GET(flag/server_swap_enabled))
- return ..()
-
- if(!fexists("config/skyrat/swap_ips.txt"))
- to_chat_immediate(world, span_boldwarning("SERVER SWAP ERROR: swap_ips.txt does not exist, unable to set up server swapping!"))
- return ..()
-
- var/list/lines = world.file2list("config/skyrat/swap_ips.txt")
- for(var/line in lines)
- if(!length(line))
- continue
- if(findtextEx(line, "#", 1, 2))
- continue
- var/list/L = splittext(line,"+")
- if(L.len < 2)
- continue
- var/server_name = L[1]
- var/IP = L[2]
- GLOB.swappable_ips[server_name] = IP
- to_chat(world, span_boldannounce("SERVER SWAP: [server_name] loaded with IP: [IP]!"))
-
- return ..()
diff --git a/modular_skyrat/modules/server_overflow/code/chat_link.dm b/modular_skyrat/modules/server_overflow/code/chat_link.dm
index d219ff910cb..862a8529bcc 100644
--- a/modular_skyrat/modules/server_overflow/code/chat_link.dm
+++ b/modular_skyrat/modules/server_overflow/code/chat_link.dm
@@ -1,35 +1,111 @@
-
-/proc/send_ooc_to_other_server(ckey, message)
- if(!CONFIG_GET(flag/secondary_server_enabled))
- return
+// Sends an OOC message to all dem other servers!
+/proc/send_ooc_to_other_server(exp_name, message)
+ if(!CONFIG_GET(flag/enable_cross_server_ooc))
+ return FALSE
var/list/ooc_information = list()
- ooc_information["server_name"] = CONFIG_GET(string/our_server_name)
- ooc_information["expected_ckey"] = ckey(ckey)
- ooc_information["message"] = message
- var/second_server = CONFIG_GET(string/server_two_ip)
- if(!second_server)
- message_admins("SERVER CONTROL CRITICAL ERROR: No second server IP set in config!")
- return
- send2otherserver(station_name(), null, "incoming_ooc_message", second_server, ooc_information)
+ ooc_information["server_name"] = CONFIG_GET(string/cross_server_name) ? CONFIG_GET(string/cross_server_name) : station_name()
+ ooc_information["expected_name"] = exp_name
+ send2otherserver(html_decode(ooc_information["server_name"]), message, "incoming_ooc_message", "all", additional_data = ooc_information)
+ return TRUE
/datum/world_topic/incoming_ooc_message
keyword = "incoming_ooc_message"
require_comms_key = TRUE
/datum/world_topic/incoming_ooc_message/Run(list/input)
+ if(!CONFIG_GET(flag/enable_cross_server_ooc))
+ return FALSE
var/server_name = input["server_name"]
- var/exp_ckey = ckey(input["expected_ckey"])
+ var/exp_name = input["expected_name"]
var/message = input["message"]
- send_ooc_message("[server_name] - [exp_ckey]", message)
+ send_ooc_message(exp_name, server_name, message)
-/proc/send_ooc_message(sender_name, message)
+/proc/send_ooc_message(sender_name, server_name, message)
if(!GLOB.ooc_allowed)
return
for(var/client/C in GLOB.clients)
if(C.prefs.chat_toggles & CHAT_OOC)
- if(GLOB.OOC_COLOR)
- to_chat(C, span_oocplain("OOC: [sender_name]: [message]"))
- else
- to_chat(C, span_ooc(span_prefix("OOC: [sender_name]: [message]"))
+ to_chat(C, span_crossooc("[span_prefix("CROSSLINK-OOC([server_name]):")] [sender_name]: [message]"), type = MESSAGE_TYPE_OOC)
+
+
+// Sends an asay message to all deh other servers!
+/proc/send_asay_to_other_server(exp_name, message)
+ if(!CONFIG_GET(flag/enable_cross_server_asay))
+ return
+ var/list/asay_information = list()
+ asay_information["server_name"] = CONFIG_GET(string/cross_server_name) ? CONFIG_GET(string/cross_server_name) : station_name()
+ asay_information["expected_name"] = exp_name
+ send2otherserver(html_decode(asay_information["server_name"]), message, "incoming_asay_message", "all", additional_data = asay_information)
+ return TRUE
+
+/datum/world_topic/incoming_asay_message
+ keyword = "incoming_asay_message"
+ require_comms_key = TRUE
+
+/datum/world_topic/incoming_asay_message/Run(list/input)
+ if(!CONFIG_GET(flag/enable_cross_server_asay))
+ return
+ var/server_name = input["server_name"]
+ var/exp_name = input["expected_name"]
+ var/message = input["message"]
+
+ send_asay_message(exp_name, server_name, message)
+
+/proc/send_asay_message(sender_name, server_name, message)
+ var/msg = "[span_adminsay("[span_crossasay("CROSSLINK-ASAY")]([server_name]): [sender_name]: [message]")]"
+ to_chat(GLOB.admins,
+ type = MESSAGE_TYPE_ADMINCHAT,
+ html = msg,
+ confidential = TRUE)
+
+/client/proc/request_help()
+ set category = "Admin"
+ set name = "Cross-server Help Request"
+ set desc = "Sends a loud message to all other servers that we are crosslinked to!"
+
+ var/help_request_message = tgui_input_text(src, "Input help message!", "Help message", "Send help!", 150, FALSE)
+ if(!help_request_message)
+ return
+ send2adminchat(ckey, "CROSSLINK HELP REQUEST([CONFIG_GET(string/cross_server_name) ? CONFIG_GET(string/cross_server_name) : station_name()]): [help_request_message]")
+ send_help_request_to_other_server(ckey, help_request_message)
+
+ message_admins("[ADMIN_LOOKUPFLW(usr)] sent out a cross-server help request with the message: [help_request_message].")
+ log_admin("[key_name(usr)] sent cross-server help request [help_request_message].")
+
+// Oh no, they need help!
+/proc/send_help_request_to_other_server(exp_name, message)
+ if(!CONFIG_GET(flag/enable_cross_server_asay))
+ return
+ var/list/asay_information = list()
+ asay_information["server_name"] = CONFIG_GET(string/cross_server_name) ? CONFIG_GET(string/cross_server_name) : station_name()
+ asay_information["expected_name"] = exp_name
+ send2otherserver(html_decode(asay_information["server_name"]), message, "incoming_help_request", "all", additional_data = asay_information)
+ return TRUE
+
+/datum/world_topic/incoming_help_request
+ keyword = "incoming_help_request"
+ require_comms_key = TRUE
+
+/datum/world_topic/incoming_help_request/Run(list/input)
+ if(!CONFIG_GET(flag/enable_cross_server_asay))
+ return
+ var/server_name = input["server_name"]
+ var/exp_name = ckey(input["expected_name"])
+ var/message = input["message"]
+
+ send_help_request(exp_name, server_name, message)
+
+/proc/send_help_request(sender_name, server_name, message)
+ var/msg = span_command_headset("[span_adminsay("[span_crossasay("CROSSLINK HELP REQUEST")]([server_name]): [sender_name]: [message]")]")
+
+ to_chat(GLOB.admins,
+ type = MESSAGE_TYPE_ADMINCHAT,
+ html = msg,
+ confidential = TRUE)
+
+ for(var/client/admin_client in GLOB.admins)
+ if(admin_client?.prefs?.toggles & SOUND_ADMINHELP)
+ SEND_SOUND(admin_client, sound('modular_skyrat/modules/admin/sound/duckhonk.ogg'))
+ window_flash(admin_client, ignorepref = TRUE)
diff --git a/modular_skyrat/modules/server_overflow/code/client_procs.dm b/modular_skyrat/modules/server_overflow/code/client_procs.dm
new file mode 100644
index 00000000000..431bc139dfb
--- /dev/null
+++ b/modular_skyrat/modules/server_overflow/code/client_procs.dm
@@ -0,0 +1,34 @@
+/**
+ * This proc is designed to be lightweight and straight forward, clients are finicky and joining all the time.
+ * FALSE = Deny connection
+ * True = Confirm connection
+ */
+/client/proc/check_population(connecting_admin = FALSE)
+ if(connecting_admin)
+ return TRUE //We allow admins to pass freeeeeeeely
+
+ var/population = TGS_CLIENT_COUNT
+ var/player_cap = CONFIG_GET(number/player_hard_cap)
+
+ if(player_cap && population >= player_cap)
+ var/overflow_server_ip = CONFIG_GET(string/overflow_server_ip)
+ if(!overflow_server_ip)
+ message_admins("WARNING: Overflow server IP not set!")
+ return TRUE
+ to_chat_immediate(src, span_boldwarning("The round is full, please wait while you are transferred to the secondary server..."))
+ message_admins("[src] attempted to join, but the server was full and were sent to the secondary server.")
+ src << link(overflow_server_ip)
+ return FALSE
+ return TRUE
+
+/mob/dead/new_player/proc/connect_to_second_server(choice)
+ if(!client)
+ return
+ if(choice != "Send me there")
+ return
+ to_chat(client, span_notice("So long, spaceman."))
+ var/overflow_server_ip = CONFIG_GET(string/overflow_server_ip)
+ if(!overflow_server_ip)
+ message_admins("WARNING: Overflow server IP not set!")
+ return
+ client << link(overflow_server_ip)
diff --git a/modular_skyrat/modules/server_overflow/code/server_connect_panel.dm b/modular_skyrat/modules/server_overflow/code/server_connect_panel.dm
new file mode 100644
index 00000000000..a1240564bf2
--- /dev/null
+++ b/modular_skyrat/modules/server_overflow/code/server_connect_panel.dm
@@ -0,0 +1,39 @@
+GLOBAL_DATUM(server_control_panel, /datum/server_control_panel)
+
+/datum/server_control_panel
+
+/datum/server_control_panel/New()
+ . = ..()
+
+/datum/server_control_panel/ui_state(mob/user)
+ return GLOB.always_state
+
+/datum/server_control_panel/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if (!ui)
+ ui = new(user, src, "ServerControlPanel")
+ ui.open()
+
+/datum/server_control_panel/ui_data(mob/user)
+ var/list/data = list()
+
+ data["player_cap"] = CONFIG_GET(number/player_hard_cap)
+
+ data["connections"] = TGS_CLIENT_COUNT
+
+ data["overflow_server_name"] = "Overflow Server"
+
+ data["servers"] = list()
+ var/list/servers = CONFIG_GET(keyed_list/cross_server)
+ for(var/server_name in servers)
+ data["servers"] += list(list(
+ "name" = server_name,
+ "ip" = servers[server_name],
+ ))
+
+
+/mob/dead/new_player/proc/show_connection_panel()
+ if(!GLOB.server_control_panel)
+ GLOB.server_control_panel = new /datum/server_control_panel(src)
+
+ GLOB.server_control_panel.ui_interact(src)
diff --git a/tgstation.dme b/tgstation.dme
index af51028b58a..36db2ba9f23 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -4168,7 +4168,7 @@
#include "modular_skyrat\master_files\code\_globalvars\lists\chat.dm"
#include "modular_skyrat\master_files\code\_onclick\cyborg.dm"
#include "modular_skyrat\master_files\code\_onclick\hud\new_player.dm"
-#include "modular_skyrat\master_files\code\controllers\configuration\entries\skryat_config_entries.dm"
+#include "modular_skyrat\master_files\code\controllers\configuration\entries\skyrat_config_entries.dm"
#include "modular_skyrat\master_files\code\controllers\subsystem\statpanel.dm"
#include "modular_skyrat\master_files\code\datums\emotes.dm"
#include "modular_skyrat\master_files\code\datums\ert.dm"
@@ -4780,7 +4780,6 @@
#include "modular_skyrat\modules\loadouts\loadout_items\under\loadout_datum_under.dm"
#include "modular_skyrat\modules\loadouts\loadout_ui\loadout_manager.dm"
#include "modular_skyrat\modules\loadouts\loadout_ui\loadout_outfit_helpers.dm"
-#include "modular_skyrat\modules\lobbyscreen\code\load_servers.dm"
#include "modular_skyrat\modules\mapping\code\color.dm"
#include "modular_skyrat\modules\mapping\code\command.dm"
#include "modular_skyrat\modules\mapping\code\dungeon.dm"
@@ -5123,6 +5122,9 @@
#include "modular_skyrat\modules\secbotsrback\code\botpacks.dm"
#include "modular_skyrat\modules\secbotsrback\code\packs.dm"
#include "modular_skyrat\modules\secbotsrback\code\recipes.dm"
+#include "modular_skyrat\modules\server_overflow\code\chat_link.dm"
+#include "modular_skyrat\modules\server_overflow\code\client_procs.dm"
+#include "modular_skyrat\modules\server_overflow\code\server_connect_panel.dm"
#include "modular_skyrat\modules\SEVA_suit\code\seva_obj.dm"
#include "modular_skyrat\modules\SEVA_suit\code\suit_voucher.dm"
#include "modular_skyrat\modules\shapeshifting_module\code\all_nodes.dm"
diff --git a/tgui/packages/tgui-panel/styles/goon/chat-dark.scss b/tgui/packages/tgui-panel/styles/goon/chat-dark.scss
index 5daff380d79..761cb45491a 100644
--- a/tgui/packages/tgui-panel/styles/goon/chat-dark.scss
+++ b/tgui/packages/tgui-panel/styles/goon/chat-dark.scss
@@ -987,3 +987,13 @@ em {
font-weight: bold;
text-shadow: 0 0 6px #ff6dbc;
}
+
+.crossooc {
+ color: #9f6efc;
+ font-weight: bold;
+}
+
+.crossasay {
+ color: #ff0000;
+ font-weight: bold;
+}
diff --git a/tgui/packages/tgui-panel/styles/goon/chat-light.scss b/tgui/packages/tgui-panel/styles/goon/chat-light.scss
index 38d13e7cafd..31986f469aa 100644
--- a/tgui/packages/tgui-panel/styles/goon/chat-light.scss
+++ b/tgui/packages/tgui-panel/styles/goon/chat-light.scss
@@ -943,3 +943,13 @@ h1.alert, h2.alert {
height: 1px;
margin: 8px 16px 8px 16px;
}
+
+.crossooc {
+ color: #9f6efc;
+ font-weight: bold;
+}
+
+.crossasay {
+ color: #ff0000;
+ font-weight: bold;
+}
diff --git a/tgui/packages/tgui/interfaces/ServerControlPanel.js b/tgui/packages/tgui/interfaces/ServerControlPanel.js
new file mode 100644
index 00000000000..ad6016be5ae
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/ServerControlPanel.js
@@ -0,0 +1,45 @@
+import { useBackend } from '../backend';
+import { NoticeBox, Section, Button, LabeledList } from '../components';
+import { Window } from '../layouts';
+
+export const MicrofusionGunControl = (props, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ current_players,
+ servers = [],
+ } = data;
+ return (
+
+
+ {servers.len === 0 ? (
+
+ No server is currently online.
+
+ ) : (
+ servers.map(server => (
+ act('connect', {
+ server_ref: server.name,
+ })} />
+ )}>
+
+
+ {server.players}/{server.max_players}
+
+
+
+ ))
+ )}
+
+
+ );
+};