Revolution victories now call the shuttle when enough of the station is revolutionaries (#68630)

When 65% or more of the station is revs, the shuttle will automatically call. This shuttle can be recalled.

Approved with majority vote from me and @ninjanomnom

Should probably be test merged first, I touched some core shuttle code.

Roughly 60% of rev victories I checked called the shuttle shortly after. That's a lot, but there's still a high amount that aren't, either because the population genuinely wants to stay, or the revolutionary victory was a surprise. The latter of which I had happen to me like, recently! Remember that was the core problem revs victories continuing the round was trying to fix.

With that in mind, this plays nicely with both some player grievances with post-revs while keeping in line with the core of the feature. Players are still, in part, controlling the end of the round, but with affordance given to the most likely scenario.
This commit is contained in:
Mothblocks
2022-08-05 18:16:12 -07:00
committed by GitHub
parent c7dc8aeb58
commit 0a29ded0f6
7 changed files with 151 additions and 94 deletions
+54 -39
View File
@@ -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. (<A HREF='?_src_=holder;[HrefToken()];trigger_centcom_recall=1'>TRIGGER CENTCOM RECALL</A>)")
/// 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
@@ -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
@@ -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
@@ -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!"
@@ -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. \
<b>You have been chosen out of your fellow provocateurs to rename the station. Choose wisely.</b> 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. \
<b>You have been chosen out of your fellow provocateurs to rename the station. Choose wisely.</b> 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)
+1 -1
View File
@@ -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
+3 -3
View File
@@ -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)