diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm
index 0f12d1d9ae..595af38848 100644
--- a/code/controllers/configuration/entries/game_options.dm
+++ b/code/controllers/configuration/entries/game_options.dm
@@ -404,10 +404,6 @@
lowercase = FALSE
splitter = ","
-/datum/config_entry/number/auto_transfer_delay
- config_entry_value = 72000
- min_val = 0
-
/datum/config_entry/flag/pai_custom_holoforms
/datum/config_entry/number/marauder_delay_non_reebe
diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm
index cb8c0fe966..2d9264adf5 100644
--- a/code/controllers/configuration/entries/general.dm
+++ b/code/controllers/configuration/entries/general.dm
@@ -82,6 +82,18 @@
config_entry_value = 600
min_val = 0
+/datum/config_entry/number/vote_autotransfer_initial //length of time before the first autotransfer vote is called (deciseconds, default 2 hours)
+ config_entry_value = 72000
+ min_val = 0
+
+/datum/config_entry/number/vote_autotransfer_interval //length of time to wait before subsequent autotransfer votes (deciseconds, default 30 minutes)
+ config_entry_value = 18000
+ min_val = 0
+
+/datum/config_entry/number/vote_autotransfer_maximum // maximum extensions until the round autoends
+ config_entry_value = 4
+ min_val = 0
+
/datum/config_entry/flag/default_no_vote // vote does not default to nochange/norestart
/datum/config_entry/flag/no_dead_vote // dead people can't vote
diff --git a/code/controllers/subsystem/autotransfer.dm b/code/controllers/subsystem/autotransfer.dm
new file mode 100644
index 0000000000..4f8fc3631d
--- /dev/null
+++ b/code/controllers/subsystem/autotransfer.dm
@@ -0,0 +1,27 @@
+SUBSYSTEM_DEF(autotransfer)
+ name = "Autotransfer Vote"
+ flags = SS_KEEP_TIMING | SS_BACKGROUND
+ wait = 1 MINUTES
+
+ var/starttime
+ var/targettime
+ var/voteinterval
+ var/maxvotes
+ var/curvotes
+
+/datum/controller/subsystem/autotransfer/Initialize(timeofday)
+ starttime = world.time
+ targettime = starttime + CONFIG_GET(number/vote_autotransfer_initial)
+ voteinterval = CONFIG_GET(number/vote_autotransfer_interval)
+ maxvotes = CONFIG_GET(number/vote_autotransfer_maximum)
+ curvotes = 0
+ return ..()
+
+/datum/controller/subsystem/autotransfer/fire()
+ if(maxvotes > curvotes)
+ if(world.time > targettime)
+ SSvote.initiate_vote("transfer",null) //TODO figure out how to not use null as the user
+ targettime = targettime + voteinterval
+ curvotes += 1
+ else
+ SSshuttle.autoEnd()
diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm
index 7eff8b9e3c..bcbe2bb49b 100644
--- a/code/controllers/subsystem/shuttle.dm
+++ b/code/controllers/subsystem/shuttle.dm
@@ -55,7 +55,8 @@ SUBSYSTEM_DEF(shuttle)
var/lockdown = FALSE //disallow transit after nuke goes off
- var/auto_call = 72000 //CIT CHANGE - time before in deciseconds in which the shuttle is auto called. Default is 2ish hours plus 15 for the shuttle. So total is 3.
+ var/endvote_passed = FALSE
+
var/realtimeofstart = 0
/datum/controller/subsystem/shuttle/Initialize(timeofday)
@@ -78,7 +79,6 @@ SUBSYSTEM_DEF(shuttle)
if(!supply)
WARNING("No /obj/docking_port/mobile/supply placed on the map!")
realtimeofstart = world.realtime
- auto_call = CONFIG_GET(number/auto_transfer_delay)
return ..()
/datum/controller/subsystem/shuttle/proc/initial_load()
@@ -643,10 +643,11 @@ SUBSYSTEM_DEF(shuttle)
QDEL_LIST(remove_images)
-/datum/controller/subsystem/shuttle/proc/autoEnd() //CIT CHANGE - allows shift to end after 2 hours have passed.
- if((world.realtime - SSshuttle.realtimeofstart) > auto_call && EMERGENCY_IDLE_OR_RECALLED) //2 hours
+/datum/controller/subsystem/shuttle/proc/autoEnd() //CIT CHANGE - allows shift to end without being a proper shuttle call?
+ if(EMERGENCY_IDLE_OR_RECALLED)
SSshuttle.emergency.request(silent = TRUE)
priority_announce("The shift has come to an end and the shuttle called. [seclevel2num(get_security_level()) == SEC_LEVEL_RED ? "Red Alert state confirmed: Dispatching priority shuttle. " : "" ]It will arrive in [emergency.timeLeft(600)] minutes.", null, "shuttlecalled", "Priority")
- log_game("Round time limit reached. Shuttle has been auto-called.")
- message_admins("Round time limit reached. Shuttle called.")
- emergencyNoRecall = TRUE
+ log_game("Round end vote passed. Shuttle has been auto-called.")
+ message_admins("Round end vote passed. Shuttle has been auto-called.")
+ emergencyNoRecall = TRUE
+ endvote_passed = TRUE
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index 606aca2d3a..5d960964a0 100755
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -213,7 +213,7 @@ SUBSYSTEM_DEF(ticker)
check_queue()
check_maprotate()
scripture_states = scripture_unlock_alert(scripture_states)
- SSshuttle.autoEnd()
+ //SSshuttle.autoEnd()
if(!roundend_check_paused && mode.check_finished(force_ending) || force_ending)
current_state = GAME_STATE_FINISHED
diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm
index 0bd4840c7d..9d5c85e4e4 100644
--- a/code/controllers/subsystem/vote.dm
+++ b/code/controllers/subsystem/vote.dm
@@ -89,6 +89,20 @@ SUBSYSTEM_DEF(vote)
choices[GLOB.master_mode] += non_voters.len
if(choices[GLOB.master_mode] >= greatest_votes)
greatest_votes = choices[GLOB.master_mode]
+ else if(mode == "transfer") // austation begin -- Crew autotransfer vote
+ var/factor = 1
+ switch(world.time / (1 MINUTES))
+ if(0 to 60)
+ factor = 0.5
+ if(61 to 120)
+ factor = 0.8
+ if(121 to 240)
+ factor = 1
+ if(241 to 300)
+ factor = 1.2
+ else
+ factor = 1.4
+ choices["Initiate Crew Transfer"] += round(non_voters.len * factor) // austation end
//get all options with that many votes and return them in a list
. = list()
if(greatest_votes)
@@ -365,6 +379,12 @@ SUBSYSTEM_DEF(vote)
log_admin("The map has been voted for and will change to: [VM.map_name]")
if(SSmapping.changemap(config.maplist[.]))
to_chat(world, "The map vote has chosen [VM.map_name] for next round!")
+ if("transfer") // austation begin -- Crew autotransfer vote
+ if(. == "Initiate Crew Transfer")
+ SSshuttle.autoEnd()
+ var/obj/machinery/computer/communications/C = locate() in GLOB.machines
+ if(C)
+ C.post_status("shuttle") // austation end
if(restart)
var/active_admins = 0
for(var/client/C in GLOB.admins)
@@ -444,6 +464,7 @@ SUBSYSTEM_DEF(vote)
to_chat(usr, "A vote was initiated recently, you must wait [DisplayTimeText(next_allowed_time-world.time)] before a new vote can be started!")
return 0
+ SEND_SOUND(world, sound('sound/misc/notice2.ogg'))
reset()
obfuscated = hideresults //CIT CHANGE - adds obfuscated votes
switch(vote_type)
@@ -465,6 +486,8 @@ SUBSYSTEM_DEF(vote)
if(targetmap.max_round_search_span && count_occurences_of_value(lastmaps, M, targetmap.max_round_search_span) >= targetmap.max_rounds_played)
continue
choices |= M
+ if("transfer") // austation begin -- Crew autotranfer vote
+ choices.Add("Initiate Crew Transfer","Continue Playing") // austation end
if("roundtype") //CIT CHANGE - adds the roundstart secret/extended vote
choices.Add("secret", "extended")
if("mode tiers")
@@ -496,7 +519,7 @@ SUBSYSTEM_DEF(vote)
else
return 0
mode = vote_type
- initiator = initiator_key
+ initiator = initiator_key ? initiator_key : "the Server" // austation -- Crew autotransfer vote
started_time = world.time
var/text = "[capitalize(mode)] vote started by [initiator]."
if(mode == "custom")
diff --git a/code/datums/elements/ghost_role_eligibility.dm b/code/datums/elements/ghost_role_eligibility.dm
index e57aaddd5a..ab87d7f1d2 100644
--- a/code/datums/elements/ghost_role_eligibility.dm
+++ b/code/datums/elements/ghost_role_eligibility.dm
@@ -17,7 +17,8 @@
penalty += roundstart_quit_limit - world.time
if(penalty)
penalty += world.realtime
- if(penalty - SSshuttle.realtimeofstart > SSshuttle.auto_call + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
+ var/maximumRoundEnd = SSautotransfer.starttime + SSautotransfer.voteinterval * SSautotransfer.maxvotes
+ if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
penalty = CANT_REENTER_ROUND
if(!(M.ckey in timeouts))
timeouts += M.ckey
diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm
index 6ea357163f..4c3ef824b9 100644
--- a/code/game/gamemodes/dynamic/dynamic.dm
+++ b/code/game/gamemodes/dynamic/dynamic.dm
@@ -672,7 +672,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic)
// Time to inject some threat into the round
if(EMERGENCY_ESCAPED_OR_ENDGAMED) // Unless the shuttle is gone
return
- if((world.realtime - SSshuttle.realtimeofstart) > SSshuttle.auto_call) // no rules after shuttle is auto-called
+ if(SSshuttle.endvote_passed) // no rules after shuttle call is voted
return
message_admins("DYNAMIC: Checking for midround injection.")
log_game("DYNAMIC: Checking for midround injection.")
@@ -748,7 +748,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic)
return
if(EMERGENCY_ESCAPED_OR_ENDGAMED) // No more rules after the shuttle has left
return
- if((world.realtime - SSshuttle.realtimeofstart) > SSshuttle.auto_call) // no rules after shuttle is auto-called
+ if(SSshuttle.endvote_passed) // no rules after shuttle is auto-called
return
update_playercounts()
diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm
index 9d0053c9b2..5fe141d2cd 100755
--- a/code/game/machinery/computer/communications.dm
+++ b/code/game/machinery/computer/communications.dm
@@ -194,7 +194,7 @@
state = STATE_CANCELSHUTTLE
if("cancelshuttle2")
if(authenticated)
- if((world.realtime - SSshuttle.realtimeofstart) > SSshuttle.auto_call) //Citadel Edit Removing auto_call caused recall.
+ if(SSshuttle.endvote_passed) //Citadel Edit - endvote passing = no recalls
say("Warning: Emergency shuttle recalls have been blocked by Central Command due to ongoing crew transfer procedures.")
else
SSshuttle.cancelEvac(usr)
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 325ea6e8ed..d2cf3608e6 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -289,7 +289,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit) MINUTES
if(world.time < roundstart_quit_limit)
penalty += roundstart_quit_limit - world.time
- if(penalty + world.realtime - SSshuttle.realtimeofstart > SSshuttle.auto_call + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
+ var/maximumRoundEnd = SSautotransfer.starttime + SSautotransfer.voteinterval * SSautotransfer.maxvotes
+ if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
penalty = CANT_REENTER_ROUND
if(SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, (stat == DEAD) ? TRUE : FALSE, FALSE, (stat == DEAD)? penalty : 0, (stat == DEAD)? TRUE : FALSE) & COMPONENT_BLOCK_GHOSTING)
@@ -323,7 +324,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit) MINUTES
if(world.time < roundstart_quit_limit)
penalty += roundstart_quit_limit - world.time
- if(penalty + world.realtime - SSshuttle.realtimeofstart > SSshuttle.auto_call + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
+ var/maximumRoundEnd = SSautotransfer.starttime + SSautotransfer.voteinterval * SSautotransfer.maxvotes
+ if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
penalty = CANT_REENTER_ROUND
var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst alive you won't be able to re-enter this round [penalty ? "or play ghost roles [penalty == CANT_REENTER_ROUND ? "until the round is over" : "for the next [DisplayTimeText(penalty)]"]" : ""]! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
diff --git a/config/config.txt b/config/config.txt
index 0ab0cc911e..1d987070dd 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -184,6 +184,15 @@ VOTE_DELAY 6000
## time period (deciseconds) which voting session will last (default 1 minute)
VOTE_PERIOD 600
+## autovote initial delay (deciseconds) before first automatic transfer vote call (default 120 minutes)
+VOTE_AUTOTRANSFER_INITIAL 72000
+
+## autovote delay (deciseconds) before sequential automatic transfer votes are called (default 30 minutes)
+VOTE_AUTOTRANSFER_INTERVAL 18000
+
+## autovote maximum votes until automatic transfer call (default 4)
+VOTE_AUTOTRANSFER_MAXIMUM 4
+
## prevents dead players from voting or starting votes
# NO_DEAD_VOTE
diff --git a/tgstation.dme b/tgstation.dme
index a4b9834b92..3072ce93aa 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -245,6 +245,7 @@
#include "code\controllers\subsystem\assets.dm"
#include "code\controllers\subsystem\atoms.dm"
#include "code\controllers\subsystem\augury.dm"
+#include "code\controllers\subsystem\autotransfer.dm"
#include "code\controllers\subsystem\blackbox.dm"
#include "code\controllers\subsystem\chat.dm"
#include "code\controllers\subsystem\communications.dm"