diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index f6ddb6a5a6a..69e26cba515 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -270,6 +270,9 @@
// Macro to get the current elapsed round time, rather than total world runtime
#define ROUND_TIME (round_start_time ? (world.time - round_start_time) : 0)
+// Macro that returns true if it's too early in a round to freely ghost out
+#define TOO_EARLY_TO_GHOST (config && (ROUND_TIME < (config.round_abandon_penalty_period)))
+
// Used by radios to indicate that they have sent a message via something other than subspace
#define RADIO_CONNECTION_FAIL 0
#define RADIO_CONNECTION_NON_SUBSPACE 1
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 5cedd40abfc..09596d4445c 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -61,6 +61,7 @@
var/ToRban = 0
var/automute_on = 0 //enables automuting/spam prevention
var/jobs_have_minimal_access = 0 //determines whether jobs use minimal access or expanded access.
+ var/round_abandon_penalty_period = 30 MINUTES // Time from round start during which ghosting out is penalized
var/reactionary_explosions = 0 //If we use reactionary explosions, explosions that react to walls and doors
@@ -560,6 +561,9 @@
if("max_loadout_points")
config.max_loadout_points = text2num(value)
+ if("round_abandon_penalty_period")
+ config.round_abandon_penalty_period = MinutesToTicks(text2num(value))
+
else
diary << "Unknown setting in configuration: '[name]'"
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
index 89712fefad3..e00322dd2db 100644
--- a/code/game/machinery/cryopod.dm
+++ b/code/game/machinery/cryopod.dm
@@ -174,7 +174,9 @@
var/mob/living/occupant = null // Person waiting to be despawned.
var/orient_right = null // Flips the sprite.
- var/time_till_despawn = 9000 // 15 minutes-ish safe period before being despawned.
+ // 15 minutes-ish safe period before being despawned.
+ var/time_till_despawn = 9000 // This is reduced by 90% if a player manually enters cryo
+ var/willing_time_divisor = 10
var/time_entered = 0 // Used to keep track of the safe period.
var/obj/item/device/radio/intercom/announce //
@@ -384,7 +386,10 @@
// Ghost and delete the mob.
if(!occupant.get_ghost(1))
- occupant.ghostize(0) // Despawned players may not re-enter the game
+ if(TOO_EARLY_TO_GHOST)
+ occupant.ghostize(0) // Players despawned too early may not re-enter the game
+ else
+ occupant.ghostize(1)
qdel(occupant)
occupant = null
name = initial(name)
@@ -406,6 +411,7 @@
var/willing = null //We don't want to allow people to be forced into despawning.
var/mob/living/M = G:affecting
+ time_till_despawn = initial(time_till_despawn)
if(!istype(M) || M.stat == DEAD)
to_chat(user, "Dead people can not be put into cryo.")
@@ -414,7 +420,7 @@
if(M.client)
if(alert(M,"Would you like to enter long-term storage?",,"Yes","No") == "Yes")
if(!M || !G || !G:affecting) return
- willing = 1
+ willing = willing_time_divisor
else
willing = 1
@@ -435,6 +441,8 @@
M.client.perspective = EYE_PERSPECTIVE
M.client.eye = src
+ time_till_despawn = initial(time_till_despawn) / willing
+
else //because why the fuck would you keep going if the mob isn't in the pod
to_chat(user, "You stop putting [M] into the cryopod.")
return
@@ -504,11 +512,12 @@
var/willing = null //We don't want to allow people to be forced into despawning.
+ time_till_despawn = initial(time_till_despawn)
if(L.client)
if(alert(L,"Would you like to enter cryosleep?",,"Yes","No") == "Yes")
if(!L) return
- willing = 1
+ willing = willing_time_divisor
else
willing = 1
@@ -525,6 +534,7 @@
to_chat(user, "\The [src] is in use.")
return
L.loc = src
+ time_till_despawn = initial(time_till_despawn) / willing
if(L.client)
L.client.perspective = EYE_PERSPECTIVE
@@ -624,6 +634,7 @@
usr.client.eye = src
usr.loc = src
src.occupant = usr
+ time_till_despawn = initial(time_till_despawn) / willing_time_divisor
if(orient_right)
icon_state = "[occupied_icon_state]-r"
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 74f7b37c96c..59c26c640bc 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -153,9 +153,14 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/mob/M = src
var/warningmsg = null
+ var/obj/machinery/cryopod/P = istype(loc, /obj/machinery/cryopod) && loc
- if(suiciding)
- warningmsg = "You have committed suicide"
+ if(P)
+ if(TOO_EARLY_TO_GHOST)
+ warningmsg = "It's too early in the shift to enter cryo"
+ // If it's not too early, we'll skip straight to ghosting out without penalty
+ else if(suiciding && TOO_EARLY_TO_GHOST)
+ warningmsg = "You have committed suicide too early in the round"
else if(stat != DEAD)
warningmsg = "You are alive"
else if(non_respawnable_keys[ckey])
@@ -177,8 +182,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
Morgue = M.loc
if(Morgue)
Morgue.update()
- if(istype(M.loc, /obj/machinery/cryopod))
- var/obj/machinery/cryopod/P = M.loc
+ if(P)
if(!P.control_computer)
P.find_control_computer(urgent=1)
if(P.control_computer)
diff --git a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm
index 745ec4084ef..aeed17ef9fd 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm
@@ -133,6 +133,9 @@
to_chat(usr, "You must wait 10 minutes to respawn as a drone!")
return
+ if(alert("Are you sure you want to respawn as a drone?", "Are you sure?", "Yes", "No") != "Yes")
+ return
+
for(var/obj/machinery/drone_fabricator/DF in world)
if(DF.stat & NOPOWER || !DF.produce_drones)
continue
diff --git a/config/example/config.txt b/config/example/config.txt
index 2f723c704f4..eb44c6d828a 100644
--- a/config/example/config.txt
+++ b/config/example/config.txt
@@ -324,3 +324,8 @@ DISABLE_SPACE_RUINS
## How many loadout points players may spend in character setup
#MAX_LOADOUT_POINTS 5
+
+# How many minutes players must wait, from round start, before they can ghost out
+# and still qualify for re-entering the round. Defaults to 30.
+# Setting this to 0 will disable the penalty period
+#ROUND_ABANDON_PENALTY_PERIOD 30