diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm
index 390de70f33c..67ee5928fe9 100644
--- a/code/controllers/subsystem/shuttle.dm
+++ b/code/controllers/subsystem/shuttle.dm
@@ -265,10 +265,10 @@ SUBSYSTEM_DEF(shuttle)
/// Check if we can call the evac shuttle.
/// Returns TRUE if we can. Otherwise, returns a string detailing the problem.
-/datum/controller/subsystem/shuttle/proc/canEvac(mob/user)
- var/srd = CONFIG_GET(number/shuttle_refuel_delay)
- if(world.time - SSticker.round_start_time < srd)
- return "The emergency shuttle is refueling. Please wait [DisplayTimeText(srd - (world.time - SSticker.round_start_time))] before attempting to call."
+/datum/controller/subsystem/shuttle/proc/canEvac()
+ var/shuttle_refuel_delay = CONFIG_GET(number/shuttle_refuel_delay)
+ if(world.time - SSticker.round_start_time < shuttle_refuel_delay)
+ return "The emergency shuttle is refueling. Please wait [DisplayTimeText(shuttle_refuel_delay - (world.time - SSticker.round_start_time))] before attempting to call."
switch(emergency.mode)
if(SHUTTLE_RECALL)
@@ -286,58 +286,73 @@ SUBSYSTEM_DEF(shuttle)
return TRUE
-/datum/controller/subsystem/shuttle/proc/requestEvac(mob/user, call_reason)
- if(!emergency)
- WARNING("requestEvac(): There is no emergency shuttle, but the \
- shuttle was called. Using the backup shuttle instead.")
- if(!backup_shuttle)
- CRASH("requestEvac(): There is no emergency shuttle, \
- or backup shuttle! The game will be unresolvable. This is \
- possibly a mapping error, more likely a bug with the shuttle \
- manipulation system, or badminry. It is possible to manually \
- resolve this problem by loading an emergency shuttle template \
- manually, and then calling register() on the mobile docking port. \
- Good luck.")
- emergency = backup_shuttle
+/datum/controller/subsystem/shuttle/proc/check_backup_emergency_shuttle()
+ if(emergency)
+ return TRUE
- var/can_evac_or_fail_reason = SSshuttle.canEvac(user)
+ WARNING("check_backup_emergency_shuttle(): There is no emergency shuttle, but the \
+ shuttle was called. Using the backup shuttle instead.")
+
+ if(!backup_shuttle)
+ CRASH("check_backup_emergency_shuttle(): There is no emergency shuttle, \
+ or backup shuttle! The game will be unresolvable. This is \
+ possibly a mapping error, more likely a bug with the shuttle \
+ manipulation system, or badminry. It is possible to manually \
+ resolve this problem by loading an emergency shuttle template \
+ manually, and then calling register() on the mobile docking port. \
+ Good luck.")
+ emergency = backup_shuttle
+
+ return TRUE
+
+/datum/controller/subsystem/shuttle/proc/requestEvac(mob/user, call_reason)
+ if (!check_backup_emergency_shuttle())
+ return
+
+ var/can_evac_or_fail_reason = SSshuttle.canEvac()
if(can_evac_or_fail_reason != TRUE)
to_chat(user, span_alert("[can_evac_or_fail_reason]"))
return
- call_reason = trim(html_encode(call_reason))
-
- if(length(call_reason) < CALL_SHUTTLE_REASON_LENGTH && SSsecurity_level.get_current_level_as_number() > SEC_LEVEL_GREEN)
+ if(length(trim(call_reason)) < CALL_SHUTTLE_REASON_LENGTH && SSsecurity_level.get_current_level_as_number() > SEC_LEVEL_GREEN)
to_chat(user, span_alert("You must provide a reason."))
return
var/area/signal_origin = get_area(user)
- var/emergency_reason = "\nNature of emergency:\n\n[call_reason]"
- var/security_num = SSsecurity_level.get_current_level_as_number()
- switch(security_num)
- if(SEC_LEVEL_RED,SEC_LEVEL_DELTA)
- emergency.request(null, signal_origin, html_decode(emergency_reason), 1) //There is a serious threat we gotta move no time to give them five minutes.
- else
- emergency.request(null, signal_origin, html_decode(emergency_reason), 0)
-
- var/datum/radio_frequency/frequency = SSradio.return_frequency(FREQ_STATUS_DISPLAYS)
-
- if(!frequency)
- return
-
- var/datum/signal/status_signal = new(list("command" = "update")) // Start processing shuttle-mode displays to display the timer
- frequency.post_signal(src, status_signal)
-
- var/area/A = get_area(user)
+ call_evac_shuttle(call_reason, signal_origin)
log_shuttle("[key_name(user)] has called the emergency shuttle.")
- deadchat_broadcast(" has called the shuttle at [span_name("[A.name]")].", span_name("[user.real_name]"), user, message_type=DEADCHAT_ANNOUNCEMENT)
+ deadchat_broadcast(" has called the shuttle at [span_name("[signal_origin.name]")].", span_name("[user.real_name]"), user, message_type=DEADCHAT_ANNOUNCEMENT)
if(call_reason)
SSblackbox.record_feedback("text", "shuttle_reason", 1, "[call_reason]")
log_shuttle("Shuttle call reason: [call_reason]")
SSticker.emergency_reason = call_reason
message_admins("[ADMIN_LOOKUPFLW(user)] has called the shuttle. (TRIGGER CENTCOM RECALL)")
+/// Call the emergency shuttle.
+/// If you are doing this on behalf of a player, use requestEvac instead.
+/// `signal_origin` is fluff occasionally provided to players.
+/datum/controller/subsystem/shuttle/proc/call_evac_shuttle(call_reason, signal_origin)
+ if (!check_backup_emergency_shuttle())
+ return
+
+ call_reason = trim(html_encode(call_reason))
+
+ var/emergency_reason = "\nNature of emergency:\n\n[call_reason]"
+
+ emergency.request(
+ signal_origin = signal_origin,
+ reason = html_decode(emergency_reason),
+ red_alert = (SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED)
+ )
+
+ var/datum/radio_frequency/frequency = SSradio.return_frequency(FREQ_STATUS_DISPLAYS)
+
+ if(frequency)
+ // Start processing shuttle-mode displays to display the timer
+ var/datum/signal/status_signal = new(list("command" = "update"))
+ frequency.post_signal(src, status_signal)
+
/datum/controller/subsystem/shuttle/proc/centcom_recall(old_timer, admiral_message)
if(emergency.mode != SHUTTLE_CALL || emergency.timer != old_timer)
return
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm
index e00ccd27b70..ebe0780b539 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm
@@ -119,8 +119,6 @@
blocking_rules = list(/datum/dynamic_ruleset/roundstart/revs)
var/required_heads_of_staff = 3
var/finished = FALSE
- /// How much threat should be injected when the revolution wins?
- var/revs_win_threat_injection = 20
var/datum/team/revolution/revolution
/datum/dynamic_ruleset/latejoin/provocateur/ready(forced=FALSE)
@@ -155,7 +153,7 @@
return FALSE
/datum/dynamic_ruleset/latejoin/provocateur/rule_process()
- var/winner = revolution.process_victory(revs_win_threat_injection)
+ var/winner = revolution.process_victory()
if (isnull(winner))
return
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm
index 6c1bb16baec..39447b369b4 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm
@@ -495,8 +495,6 @@
blocking_rules = list(/datum/dynamic_ruleset/latejoin/provocateur)
// I give up, just there should be enough heads with 35 players...
minimum_players = 35
- /// How much threat should be injected when the revolution wins?
- var/revs_win_threat_injection = 20
var/datum/team/revolution/revolution
var/finished = FALSE
@@ -539,7 +537,7 @@
..()
/datum/dynamic_ruleset/roundstart/revs/rule_process()
- var/winner = revolution.process_victory(revs_win_threat_injection)
+ var/winner = revolution.process_victory()
if (isnull(winner))
return
diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm
index 2c12d3b4d2d..d940fdb0b70 100755
--- a/code/game/machinery/computer/communications.dm
+++ b/code/game/machinery/computer/communications.dm
@@ -520,7 +520,7 @@
data["alertLevel"] = SSsecurity_level.get_current_level_as_text()
data["authorizeName"] = authorize_name
data["canLogOut"] = !issilicon(user)
- data["shuttleCanEvacOrFailReason"] = SSshuttle.canEvac(user)
+ data["shuttleCanEvacOrFailReason"] = SSshuttle.canEvac()
if(syndicate)
data["shuttleCanEvacOrFailReason"] = "You cannot summon the shuttle from this console!"
diff --git a/code/modules/antagonists/revolution/revolution.dm b/code/modules/antagonists/revolution/revolution.dm
index 86593367058..22b04b63be4 100644
--- a/code/modules/antagonists/revolution/revolution.dm
+++ b/code/modules/antagonists/revolution/revolution.dm
@@ -405,8 +405,7 @@
/// Updates the state of the world depending on if revs won or loss.
/// Returns who won, at which case this method should no longer be called.
-/// If revs_win_injection_amount is passed, then that amount of threat will be added if the revs win.
-/datum/team/revolution/proc/process_victory(revs_win_injection_amount)
+/datum/team/revolution/proc/process_victory()
if (check_rev_victory())
. = REVOLUTION_VICTORY
else if (check_heads_victory())
@@ -417,8 +416,6 @@
SSshuttle.clearHostileEnvironment(src)
save_members()
- var/charter_given = FALSE
-
// Remove everyone as a revolutionary
for (var/_rev_mind in members)
var/datum/mind/rev_mind = _rev_mind
@@ -441,56 +438,105 @@
priority_announce("It appears the mutiny has been quelled. Please return yourself and your incapacitated colleagues to work. \
We have remotely blacklisted the head revolutionaries in your medical records to prevent accidental revival.", null, null, null, "Central Command Loyalty Monitoring Division")
else
- for(var/datum/mind/headrev_mind as anything in ex_headrevs)
- if(charter_given)
- break
- if(!headrev_mind.current || headrev_mind.current.stat != CONSCIOUS)
- continue
- charter_given = TRUE
- podspawn(list(
- "target" = get_turf(headrev_mind.current),
- "style" = STYLE_SYNDICATE,
- "spawn" = /obj/item/station_charter/revolution,
- ))
- to_chat(headrev_mind.current, span_hear("You hear something crackle in your ears for a moment before a voice speaks. \
- \"Please stand by for a message from your benefactor. Message as follows, provocateur. \
- You have been chosen out of your fellow provocateurs to rename the station. Choose wisely. Message ends.\""))
- SEND_GLOBAL_SIGNAL(COMSIG_GLOB_REVOLUTION_TAX_REMOVAL)
+ victory_effects()
- for (var/mob/living/player as anything in GLOB.player_list)
- var/datum/mind/player_mind = player.mind
+/datum/team/revolution/proc/victory_effects(revs_win_injection_amount)
+ var/charter_given = FALSE
- if (isnull(player_mind))
- continue
+ for(var/datum/mind/headrev_mind as anything in ex_headrevs)
+ if(charter_given)
+ break
+ if(!headrev_mind.current || headrev_mind.current.stat != CONSCIOUS)
+ continue
+ charter_given = TRUE
+ podspawn(list(
+ "target" = get_turf(headrev_mind.current),
+ "style" = STYLE_SYNDICATE,
+ "spawn" = /obj/item/station_charter/revolution,
+ ))
+ to_chat(headrev_mind.current, span_hear("You hear something crackle in your ears for a moment before a voice speaks. \
+ \"Please stand by for a message from your benefactor. Message as follows, provocateur. \
+ You have been chosen out of your fellow provocateurs to rename the station. Choose wisely. Message ends.\""))
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_REVOLUTION_TAX_REMOVAL)
- if (!(player_mind.assigned_role.departments_bitflags & (DEPARTMENT_BITFLAG_SECURITY|DEPARTMENT_BITFLAG_COMMAND)))
- continue
+ for (var/mob/living/player as anything in GLOB.player_list)
+ var/datum/mind/player_mind = player.mind
- if (player_mind in ex_revs + ex_headrevs)
- continue
+ if (isnull(player_mind))
+ continue
- player_mind.add_antag_datum(/datum/antagonist/enemy_of_the_revolution)
+ if (!(player_mind.assigned_role.departments_bitflags & (DEPARTMENT_BITFLAG_SECURITY|DEPARTMENT_BITFLAG_COMMAND)))
+ continue
- if (!istype(player))
- continue
+ if (player_mind in ex_revs + ex_headrevs)
+ continue
- if(player_mind.assigned_role.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND)
- ADD_TRAIT(player, TRAIT_DEFIB_BLACKLISTED, REF(src))
- player.med_hud_set_status()
+ player_mind.add_antag_datum(/datum/antagonist/enemy_of_the_revolution)
- for(var/datum/job/job as anything in SSjob.joinable_occupations)
- if(!(job.departments_bitflags & (DEPARTMENT_BITFLAG_SECURITY|DEPARTMENT_BITFLAG_COMMAND)))
- continue
- job.allow_bureaucratic_error = FALSE
- job.total_positions = 0
+ if (!istype(player))
+ continue
- if (revs_win_injection_amount)
- var/datum/game_mode/dynamic/dynamic = SSticker.mode
- dynamic.unfavorable_situation()
+ if(player_mind.assigned_role.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND)
+ ADD_TRAIT(player, TRAIT_DEFIB_BLACKLISTED, REF(src))
+ player.med_hud_set_status()
- priority_announce("A recent assessment of your station has marked your station as a severe risk area for high ranking Nanotrasen officials. \
- For the safety of our staff, we have blacklisted your station for new employment of security and command. \
- [pick(world.file2list("strings/anti_union_propaganda.txt"))]", null, null, null, "Central Command Loyalty Monitoring Division")
+ for(var/datum/job/job as anything in SSjob.joinable_occupations)
+ if(!(job.departments_bitflags & DEPARTMENT_BITFLAG_SECURITY|DEPARTMENT_BITFLAG_COMMAND))
+ continue
+ job.allow_bureaucratic_error = FALSE
+ job.total_positions = 0
+
+ var/datum/game_mode/dynamic/dynamic = SSticker.mode
+ dynamic.unfavorable_situation()
+
+ var/message_header = "A recent assessment of your station has marked your station as a severe risk area for high ranking Nanotrasen officials."
+ var/extra_detail = try_auto_call_shuttle() \
+ ? "For the safety of our staff, we are expediting an emergency shuttle for remaining members of security and command." \
+ : "For the safety of our staff, we have blacklisted your station for new employment of security and command."
+ var/propaganda = pick(world.file2list("strings/anti_union_propaganda.txt"))
+
+ priority_announce(
+ "[message_header]\n\n[extra_detail]\n\n[propaganda]",
+ sender_override = "Central Command Loyalty Monitoring Division"
+ )
+
+/// How much of the station, ignoring sec and command, should be revs before a shuttle will be automatically called?
+#define REV_AUTO_CALL_THRESHOLD 0.65
+
+/datum/team/revolution/proc/try_auto_call_shuttle()
+ var/total_revs = ex_revs.len + ex_headrevs.len
+ var/total_candidates = 0
+
+ for (var/mob/player as anything in GLOB.player_list)
+ if (player.mind.has_antag_datum(/datum/antagonist/enemy_of_the_revolution))
+ continue
+
+ total_candidates += 1
+
+ var/display_percent = round(total_revs / total_candidates * 100)
+
+ if (total_revs / total_candidates < REV_AUTO_CALL_THRESHOLD)
+ log_game("REVOLUTION: Not calling the shuttle, [display_percent]% are revs")
+ return FALSE
+
+ // Do it later so everyone has time to see the messages
+ addtimer(CALLBACK(src, .proc/perform_auto_shuttle_call), 20 SECONDS)
+
+ var/log = "REVOLUTION: Auto-calling the shuttle, [display_percent]% are revs"
+ log_game(log)
+ message_admins(log)
+
+ return TRUE
+
+#undef REV_AUTO_CALL_THRESHOLD
+
+/datum/team/revolution/proc/perform_auto_shuttle_call()
+ var/can_evac_result = SSshuttle.canEvac()
+ if (can_evac_result != TRUE)
+ log_game("REVOLUTION: Not calling the shuttle, canEvac() returned [can_evac_result]")
+ return
+
+ SSshuttle.call_evac_shuttle("Sending emergency shuttle to rescue command and security staff.")
/// Mutates the ticker to report that the revs have won
/datum/team/revolution/proc/round_result(finished)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 88703333a0a..b3cfe93d9a1 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -318,7 +318,7 @@
to_chat(usr, span_warning("Wireless control is disabled!"))
return
- var/can_evac_or_fail_reason = SSshuttle.canEvac(src)
+ var/can_evac_or_fail_reason = SSshuttle.canEvac()
if(can_evac_or_fail_reason != TRUE)
to_chat(usr, span_alert("[can_evac_or_fail_reason]"))
return
diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm
index e173e4c72ed..2cf09e2f86a 100644
--- a/code/modules/shuttle/emergency.dm
+++ b/code/modules/shuttle/emergency.dm
@@ -319,7 +319,7 @@
. = ..()
-/obj/docking_port/mobile/emergency/request(obj/docking_port/stationary/S, area/signalOrigin, reason, redAlert, set_coefficient=null)
+/obj/docking_port/mobile/emergency/request(obj/docking_port/stationary/S, area/signal_origin, reason, red_alert, set_coefficient=null)
if(!isnum(set_coefficient))
var/security_num = SSsecurity_level.get_current_level_as_number()
switch(security_num)
@@ -342,11 +342,11 @@
SSshuttle.emergencyCallAmount++
if(prob(70))
- SSshuttle.emergency_last_call_loc = signalOrigin
+ SSshuttle.emergency_last_call_loc = signal_origin
else
SSshuttle.emergency_last_call_loc = null
- priority_announce("The emergency shuttle has been called. [redAlert ? "Red Alert state confirmed: Dispatching priority shuttle. " : "" ]It will arrive in [timeLeft(600)] minutes.[reason][SSshuttle.emergency_last_call_loc ? "\n\nCall signal traced. Results can be viewed on any communications console." : "" ][SSshuttle.admin_emergency_no_recall ? "\n\nWarning: Shuttle recall subroutines disabled; Recall not possible." : ""]", null, ANNOUNCER_SHUTTLECALLED, "Priority")
+ priority_announce("The emergency shuttle has been called. [red_alert ? "Red Alert state confirmed: Dispatching priority shuttle. " : "" ]It will arrive in [timeLeft(600)] minutes.[reason][SSshuttle.emergency_last_call_loc ? "\n\nCall signal traced. Results can be viewed on any communications console." : "" ][SSshuttle.admin_emergency_no_recall ? "\n\nWarning: Shuttle recall subroutines disabled; Recall not possible." : ""]", null, ANNOUNCER_SHUTTLECALLED, "Priority")
/obj/docking_port/mobile/emergency/cancel(area/signalOrigin)
if(mode != SHUTTLE_CALL)