diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm
index 9c3c3571fe..8a34fb50b7 100644
--- a/code/_helpers/global_lists.dm
+++ b/code/_helpers/global_lists.dm
@@ -22,6 +22,9 @@ var/global/list/joblist = list() //list of all jobstypes, minus borg and AI
var/list/mannequins_
+// Times that players are allowed to respawn ("ckey" = world.time)
+GLOBAL_LIST_EMPTY(respawn_timers)
+
// Posters
var/global/list/poster_designs = list()
var/global/list/NT_poster_designs = list()
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 98a3f817a3..3a649b4ad4 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -68,7 +68,11 @@ var/list/gamemode_cache = list()
var/static/allow_ai_shells = FALSE // allow AIs to enter and leave special borg shells at will, and for those shells to be buildable.
var/static/give_free_ai_shell = FALSE // allows a specific spawner object to instantiate a premade AI Shell
var/static/hostedby = null
+
var/static/respawn = 1
+ var/static/respawn_time = 3000 // time before a dead player is allowed to respawn (in ds, though the config file asks for minutes, and it's converted below)
+ var/static/respawn_message = "Make sure to play a different character, and please roleplay correctly!"
+
var/static/guest_jobban = 1
var/static/usewhitelist = 0
var/static/kick_inactive = 0 //force disconnect for inactive players after this many minutes, if non-0
@@ -482,6 +486,13 @@ var/list/gamemode_cache = list()
if ("norespawn")
config.respawn = 0
+ if ("respawn_time")
+ var/raw_minutes = text2num(value)
+ config.respawn_time = raw_minutes MINUTES
+
+ if ("respawn_message")
+ config.respawn_message = value
+
if ("servername")
config.server_name = value
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index d85a88cbef..2898145795 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -265,32 +265,39 @@ Ccomp's first proc.
/client/proc/allow_character_respawn()
set category = "Special Verbs"
set name = "Allow player to respawn"
- set desc = "Let's the player bypass the wait to respawn or allow them to re-enter their corpse."
+ set desc = "Let a player bypass the wait to respawn or allow them to re-enter their corpse."
if(!holder)
return
- var/list/ghosts= get_ghosts(1,1)
-
- var/target = input("Please, select a ghost!", "COME BACK TO LIFE!", null, null) as null|anything in ghosts
+ var/target = input("Select a ckey to allow to rejoin", "Allow Respawn Selector") as null|anything in GLOB.respawn_timers
if(!target)
- to_chat(src, "Hrm, appears you didn't select a ghost") // Sanity check, if no ghosts in the list we don't want to edit a null variable and cause a runtime error.
return
+
+ if(GLOB.respawn_timers[target] == -1) // Their respawn timer is set to -1, which is 'not allowed to respawn'
+ var/response = alert(src, "Are you sure you wish to allow this individual to respawn? They would normally not be able to.","Allow impossible respawn?","No","Yes")
+ if(response == "No")
+ return
+
+ GLOB.respawn_timers -= target
- var/mob/observer/dead/G = ghosts[target]
- if(G.has_enabled_antagHUD && config.antag_hud_restricted)
- var/response = alert(src, "Are you sure you wish to allow this individual to play?","Ghost has used AntagHUD","Yes","No")
- if(response == "No") return
- G.timeofdeath=-19999 /* time of death is checked in /mob/verb/abandon_mob() which is the Respawn verb.
- timeofdeath is used for bodies on autopsy but since we're messing with a ghost I'm pretty sure
- there won't be an autopsy.
- */
- G.has_enabled_antagHUD = 2
- G.can_reenter_corpse = 1
+ var/found_client = FALSE
+ for(var/c in GLOB.clients)
+ var/client/C = c
+ if(C.ckey == target)
+ found_client = C
+ to_chat(C, "You may now respawn. You should roleplay as if you learned nothing about the round during your time with the dead.")
+ if(isobserver(C.mob))
+ var/mob/observer/dead/G = C.mob
+ G.can_reenter_corpse = 1
+ to_chat(C, "You can also re-enter your corpse, if you still have one!")
+ break
- G:show_message(text("You may now respawn. You should roleplay as if you learned nothing about the round during your time with the dead."), 1)
- log_admin("[key_name(usr)] allowed [key_name(G)] to bypass the respawn time limit")
- message_admins("Admin [key_name_admin(usr)] allowed [key_name_admin(G)] to bypass the respawn time limit", 1)
+ if(!found_client)
+ to_chat(src, "The associated client didn't appear to be connected, so they couldn't be notified, but they can now respawn if they reconnect.")
+
+ log_admin("[key_name(usr)] allowed [found_client ? key_name(found_client) : target] to bypass the respawn time limit")
+ message_admins("Admin [key_name_admin(usr)] allowed [found_client ? key_name_admin(found_client) : target] to bypass the respawn time limit", 1)
/client/proc/toggle_antagHUD_use()
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 5670793983..9dca9c6fdc 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -229,6 +229,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/mob/observer/dead/ghost = ghostize(0) // 0 parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3
if(ghost)
ghost.timeofdeath = world.time // Because the living mob won't have a time of death and we want the respawn timer to work properly.
+ ghost.set_respawn_timer()
announce_ghost_joinleave(ghost)
/mob/observer/dead/can_use_hands() return 0
@@ -304,6 +305,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/response = alert(src, "If you turn this on, you will not be able to take any part in the round.","Are you sure you want to turn this feature on?","Yes","No")
if(response == "No") return
can_reenter_corpse = FALSE
+ set_respawn_timer(-1) // Foreeeever
if(!has_enabled_antagHUD && !client.holder)
has_enabled_antagHUD = TRUE
diff --git a/code/modules/mob/death.dm b/code/modules/mob/death.dm
index c2f5c586eb..9d6735ee8b 100644
--- a/code/modules/mob/death.dm
+++ b/code/modules/mob/death.dm
@@ -100,7 +100,8 @@
if(mind) mind.store_memory("Time of death: [stationtime2text()]", 0)
living_mob_list -= src
dead_mob_list |= src
-
+
+ set_respawn_timer()
updateicon()
handle_regular_hud_updates()
handle_vision()
diff --git a/code/modules/mob/living/silicon/ai/latejoin.dm b/code/modules/mob/living/silicon/ai/latejoin.dm
index 87751aa006..e953c09597 100644
--- a/code/modules/mob/living/silicon/ai/latejoin.dm
+++ b/code/modules/mob/living/silicon/ai/latejoin.dm
@@ -29,4 +29,5 @@ var/global/list/empty_playable_ai_cores = list()
global_announcer.autosay("[src] has been moved to intelligence storage.", "Artificial Intelligence Oversight")
//Handle job slot/tater cleanup.
+ set_respawn_timer()
clear_client()
\ No newline at end of file
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index db7ec7fd81..7bff8715aa 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -341,46 +341,56 @@
return
*/
+/mob/proc/set_respawn_timer(var/time)
+ // Try to figure out what time to use
+
+ // Special cases, can never respawn
+ if(ticker?.mode?.deny_respawn)
+ time = -1
+ else if(!config.abandon_allowed)
+ time = -1
+ else if(!config.respawn)
+ time = -1
+
+ // Special case for observing before game start
+ else if(ticker?.current_state <= GAME_STATE_SETTING_UP)
+ time = 1 MINUTE
+
+ // Wasn't given a time, use the config time
+ else if(!time)
+ time = config.respawn_time
+
+ var/keytouse = ckey
+ // Try harder to find a key to use
+ if(!keytouse && key)
+ keytouse = ckey(key)
+ else if(!keytouse && mind?.key)
+ keytouse = ckey(mind.key)
+
+ GLOB.respawn_timers[keytouse] = world.time + time
+
+/mob/observer/dead/set_respawn_timer()
+ if(config.antag_hud_restricted && has_enabled_antagHUD)
+ ..(-1)
+ else
+ return // Don't set it, no need
+
/mob/verb/abandon_mob()
- set name = "Respawn"
+ set name = "Return to Menu"
set category = "OOC"
- if (!( config.abandon_allowed ))
- to_chat(usr, "Respawn is disabled.")
- return
- if ((stat != 2 || !( ticker )))
+ if(stat != DEAD || !ticker)
to_chat(usr, "You must be dead to use this!")
return
- if (ticker.mode && ticker.mode.deny_respawn) //BS12 EDIT
- to_chat(usr, "Respawn is disabled for this roundtype.")
- return
- else
- var/deathtime = world.time - src.timeofdeath
- if(istype(src,/mob/observer/dead))
- var/mob/observer/dead/G = src
- if(G.has_enabled_antagHUD == 1 && config.antag_hud_restricted)
- to_chat(usr, "By using the antagHUD you forfeit the ability to join the round.")
- return
- var/deathtimeminutes = round(deathtime / 600)
- var/pluralcheck = "minute"
- if(deathtimeminutes == 0)
- pluralcheck = ""
- else if(deathtimeminutes == 1)
- pluralcheck = " [deathtimeminutes] minute and"
- else if(deathtimeminutes > 1)
- pluralcheck = " [deathtimeminutes] minutes and"
- var/deathtimeseconds = round((deathtime - deathtimeminutes * 600) / 10,1)
- to_chat(usr, "You have been dead for[pluralcheck] [deathtimeseconds] seconds.")
- if ((deathtime < (1 * 600)) && (ticker && ticker.current_state > GAME_STATE_PREGAME)) //VOREStation Edit: lower respawn timer
- to_chat(usr, "You must wait 1 minute to respawn!")
+ // Final chance to abort "respawning"
+ if(mind && timeofdeath) // They had spawned before
+ var/choice = alert(usr, "Returning to the menu will prevent your character from being revived in-round. Are you sure?", "Confirmation", "No, wait", "Yes, leave")
+ if(choice == "No, wait")
return
- else
- to_chat(usr, "You can respawn now, enjoy your new life!")
-
- log_game("[usr.name]/[usr.key] used abandon mob.")
-
- to_chat(usr, "Make sure to play a different character, and please roleplay correctly!")
+
+ // Beyond this point, you're going to respawn
+ to_chat(usr, config.respawn_message)
if(!client)
log_game("[usr.key] AM failed due to disconnect.")
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index 30f5853524..939856c7a2 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -120,8 +120,9 @@
new_player_panel_proc()
if(href_list["observe"])
+ var/alert_time = ticker?.current_state <= GAME_STATE_SETTING_UP ? 1 : round(config.respawn_time/10/60)
- if(alert(src,"Are you sure you wish to observe? You will have to wait 60 seconds before being able to respawn!","Player Setup","Yes","No") == "Yes") //Vorestation edit - Rykka corrected to 60 seconds to match current spawn time
+ if(alert(src,"Are you sure you wish to observe? You will have to wait up to [alert_time] minute\s before being able to spawn into the game!","Player Setup","Yes","No") == "Yes")
if(!client) return 1
//Make a new mannequin quickly, and allow the observer to take the appearance
@@ -143,7 +144,6 @@
observer.forceMove(O.loc)
else
to_chat(src, "Could not locate an observer spawn point. Use the Teleport verb to jump to the station map.")
- observer.timeofdeath = world.time // Set the time of death so that the respawn timer works correctly.
announce_ghost_joinleave(src)
@@ -154,6 +154,7 @@
if(!client.holder && !config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed.
observer.verbs -= /mob/observer/dead/verb/toggle_antagHUD // Poor guys, don't know what they are missing!
observer.key = key
+ observer.set_respawn_timer(time_till_respawn()) // Will keep their existing time if any, or return 0 and pass 0 into set_respawn_timer which will use the defaults
qdel(src)
return 1
@@ -163,6 +164,13 @@
if(!ticker || ticker.current_state != GAME_STATE_PLAYING)
to_chat(usr, "The round is either not ready, or has already finished...")
return
+
+ var/time_till_respawn = time_till_respawn()
+ if(time_till_respawn == -1) // Special case, never allowed to respawn
+ to_chat(usr, "Respawning is not allowed!")
+ else if(time_till_respawn) // Nonzero time to respawn
+ to_chat(usr, "You can't respawn yet! You need to wait another [round(time_till_respawn/10/60, 0.1)] minutes.")
+ return
/*
if(client.prefs.species != "Human" && !check_rights(R_ADMIN, 0)) //VORESTATION EDITS: THE COMMENTED OUT AREAS FROM LINE 154 TO 178
if (config.usealienwhitelist)
@@ -341,6 +349,23 @@
popup.set_content(dat)
popup.open()
+/mob/new_player/proc/time_till_respawn()
+ if(!ckey)
+ return -1 // What?
+
+ var/timer = GLOB.respawn_timers[ckey]
+ // No timer at all
+ if(!timer)
+ return 0
+ // Special case, infinite timer
+ if(timer == -1)
+ return -1
+ // Timer expired
+ if(timer <= world.time)
+ GLOB.respawn_timers -= ckey
+ return 0
+ // Timer still going
+ return timer - world.time
/mob/new_player/proc/IsJobAvailable(rank)
var/datum/job/job = job_master.GetJob(rank)
diff --git a/config/example/config.txt b/config/example/config.txt
index 713d741b17..eaff246194 100644
--- a/config/example/config.txt
+++ b/config/example/config.txt
@@ -196,10 +196,15 @@ ANTAG_HUD_RESTRICTED
## allow AI job
ALLOW_AI
-
-## disable abandon mob
+## Disable respawning
# NORESPAWN
+## set a respawn time (in minutes)
+# RESPAWN_TIME 5
+
+## set a message to give to players when they respawn
+# RESPAWN_MESSAGE Remember to play a different character or something!
+
## disables calling del(src) on newmobs if they logout before spawnin in
# DONT_DEL_NEWMOB