diff --git a/code/__DEFINES/configuration.dm b/code/__DEFINES/configuration.dm index 81965514fcb..477bed243c1 100644 --- a/code/__DEFINES/configuration.dm +++ b/code/__DEFINES/configuration.dm @@ -20,3 +20,11 @@ #define KEY_MODE_TEXT 0 #define KEY_MODE_TYPE 1 + +// Flags for respawn config +/// Respawn not allowed +#define RESPAWN_FLAG_DISABLED 0 +/// Respawn as much as you'd like +#define RESPAWN_FLAG_FREE 1 +/// Can respawn, but not as the same character +#define RESPAWN_FLAG_NEW_CHARACTER 2 diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index b5fc855da31..16791b7fd7e 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -262,10 +262,25 @@ /datum/config_entry/string/hostedby -/datum/config_entry/flag/norespawn +/// Determines if a player can respawn after dying. +/// 0 / RESPAWN_FLAG_DISABLED = Cannot respawn (default) +/// 1 / RESPAWN_FLAG_FREE = Can respawn +/// 2 / RESPAWN_FLAG_NEW_CHARACTER = Can respawn if choosing a different character +/datum/config_entry/flag/allow_respawn + default = RESPAWN_FLAG_DISABLED +/datum/config_entry/flag/allow_respawn/ValidateAndSet(str_val) + if(!VASProcCallGuard(str_val)) + return FALSE + var/val_as_num = text2num(str_val) + if(val_as_num in list(RESPAWN_FLAG_DISABLED, RESPAWN_FLAG_FREE, RESPAWN_FLAG_NEW_CHARACTER)) + config_entry_value = val_as_num + return TRUE + return FALSE + +/// Determines how long (in deciseconds) before a player is allowed to respawn. /datum/config_entry/number/respawn_delay - default = 0 + default = 0 SECONDS /datum/config_entry/flag/usewhitelist diff --git a/code/datums/world_topic.dm b/code/datums/world_topic.dm index 265b9d49815..d930c496de6 100644 --- a/code/datums/world_topic.dm +++ b/code/datums/world_topic.dm @@ -195,7 +195,7 @@ /datum/world_topic/status/Run(list/input) . = list() .["version"] = GLOB.game_version - .["respawn"] = config ? !CONFIG_GET(flag/norespawn) : FALSE + .["respawn"] = config ? !!CONFIG_GET(flag/allow_respawn) : FALSE // show respawn as true regardless of "respawn as char" or "free respawn" .["enter"] = !LAZYACCESS(SSlag_switch.measures, DISABLE_NON_OBSJOBS) .["ai"] = CONFIG_GET(flag/allow_ai) .["host"] = world.host ? world.host : null @@ -240,4 +240,3 @@ // Shuttle status, see /__DEFINES/stat.dm .["shuttle_timer"] = SSshuttle.emergency.timeLeft() // Shuttle timer, in seconds - diff --git a/code/game/world.dm b/code/game/world.dm index e851bb992d4..de638624319 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -361,8 +361,8 @@ GLOBAL_VAR(restart_counter) var/server_name = CONFIG_GET(string/servername) if (server_name) new_status += "[server_name] " - if(!CONFIG_GET(flag/norespawn)) - features += "respawn" + if(CONFIG_GET(flag/allow_respawn)) + features += "respawn" // show "respawn" regardless of "respawn as char" or "free respawn" if(!CONFIG_GET(flag/allow_ai)) features += "AI disabled" hostedby = CONFIG_GET(string/hostedby) diff --git a/code/modules/admin/verbs/server.dm b/code/modules/admin/verbs/server.dm index 811b2a3506d..47fe392c973 100644 --- a/code/modules/admin/verbs/server.dm +++ b/code/modules/admin/verbs/server.dm @@ -185,16 +185,42 @@ set category = "Server" set desc = "Respawn basically" set name = "Toggle Respawn" - var/new_nores = !CONFIG_GET(flag/norespawn) - CONFIG_SET(flag/norespawn, new_nores) - if (!new_nores) - to_chat(world, "You may now respawn.", confidential = TRUE) - else - to_chat(world, "You may no longer respawn :(", confidential = TRUE) - message_admins(span_adminnotice("[key_name_admin(usr)] toggled respawn to [!new_nores ? "On" : "Off"].")) - log_admin("[key_name(usr)] toggled respawn to [!new_nores ? "On" : "Off"].") + + var/respawn_state = CONFIG_GET(flag/allow_respawn) + var/new_state = -1 + var/new_state_text = "" + switch(respawn_state) + if(RESPAWN_FLAG_DISABLED) // respawn currently disabled + new_state = RESPAWN_FLAG_FREE + new_state_text = "Enabled" + to_chat(world, span_bold("You may now respawn."), confidential = TRUE) + + if(RESPAWN_FLAG_FREE) // respawn currently enabled + new_state = RESPAWN_FLAG_NEW_CHARACTER + new_state_text = "Enabled, Different Slot" + to_chat(world, span_bold("You may now respawn as a different character."), confidential = TRUE) + + if(RESPAWN_FLAG_NEW_CHARACTER) // respawn currently enabled for different slot characters only + new_state = RESPAWN_FLAG_DISABLED + new_state_text = "Disabled" + to_chat(world, span_bold("You may no longer respawn :("), confidential = TRUE) + + else + WARNING("Invalid respawn state in config: [respawn_state]") + + if(new_state == -1) + to_chat(usr, span_warning("The config for respawn is set incorrectly, please complain to your nearest server host (or fix it yourself). \ + In the meanwhile respawn has been set to \"Off\".")) + new_state = RESPAWN_FLAG_DISABLED + new_state_text = "Disabled" + + CONFIG_SET(flag/allow_respawn, new_state) + + message_admins(span_adminnotice("[key_name_admin(usr)] toggled respawn to \"[new_state_text]\".")) + log_admin("[key_name(usr)] toggled respawn to \"[new_state_text]\".") + world.update_status() - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Respawn", "[!new_nores ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Respawn", "[new_state_text]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! /datum/admins/proc/delay() set category = "Server" diff --git a/code/modules/client/player_details.dm b/code/modules/client/player_details.dm index 24c6754b95c..8931dffcdb4 100644 --- a/code/modules/client/player_details.dm +++ b/code/modules/client/player_details.dm @@ -2,14 +2,26 @@ ///assoc list of ckey -> /datum/player_details GLOBAL_LIST_EMPTY(player_details) +/// Tracks information about a client between log in and log outs /datum/player_details - var/list/player_actions = list() + /// Action datums assigned to this player + var/list/datum/action/player_actions = list() + /// Tracks client action logging var/list/logging = list() + /// Callbacks invoked when this client logs in again var/list/post_login_callbacks = list() + /// Callbacks invoked when this client logs out var/list/post_logout_callbacks = list() - var/list/played_names = list() //List of names this key played under this round + /// List of names this key played under this round + var/list/played_names = list() + /// Lazylist of preference slots this client has joined the round under + /// Numbers are stored as strings + var/list/joined_as_slots + /// Version of byond this client is using var/byond_version = "Unknown" + /// Tracks achievements they have earned var/datum/achievement_data/achievements + /// World.time this player last died var/time_of_death = 0 /datum/player_details/New(key) diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index a38fe171174..5c07c8c8fd4 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -176,6 +176,12 @@ /mob/dead/new_player/proc/AttemptLateSpawn(rank) + // Check that they're picking someone new for new character respawning + if(CONFIG_GET(flag/allow_respawn) == RESPAWN_FLAG_NEW_CHARACTER) + if("[client.prefs.default_slot]" in client.player_details.joined_as_slots) + tgui_alert(usr, "You already have played this character in this round!") + return FALSE + var/error = IsJobUnavailable(rank) if(error != JOB_AVAILABLE) tgui_alert(usr, get_job_unavailable_error_message(error, rank)) @@ -305,6 +311,8 @@ preserved_mind.original_character_slot_index = client.prefs.default_slot preserved_mind.transfer_to(spawning_mob) //won't transfer key since the mind is not active preserved_mind.set_original_character(spawning_mob) + + LAZYADD(client.player_details.joined_as_slots, "[client.prefs.default_slot]") client.init_verbs() . = spawning_mob new_character = . diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index cebb747f6ba..f75af00ee7d 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -808,18 +808,26 @@ * * This sends you back to the lobby creating a new dead mob * - * Only works if flag/norespawn is allowed in config + * Only works if flag/allow_respawn is allowed in config */ /mob/verb/abandon_mob() set name = "Respawn" set category = "OOC" - if (CONFIG_GET(flag/norespawn)) - if (!check_rights_for(usr.client, R_ADMIN)) - to_chat(usr, span_boldnotice("Respawning is not enabled!")) - return - else if (tgui_alert(usr, "Respawning is currently disabled, do you want to use your permissions to circumvent it?", "Respawn", list("Yes", "No")) != "Yes") - return + switch(CONFIG_GET(flag/allow_respawn)) + if(RESPAWN_FLAG_NEW_CHARACTER) + if(tgui_alert(usr, "Note, respawning is only allowed as another character. If you don't have another free slot you may not be able to respawn.", "Respawn", list("Ok", "Nevermind")) != "Ok") + return + + if(RESPAWN_FLAG_DISABLED) + pass() // Normal respawn + + if(RESPAWN_FLAG_DISABLED) + if (!check_rights_for(usr.client, R_ADMIN)) + to_chat(usr, span_boldnotice("Respawning is not enabled!")) + return + if (tgui_alert(usr, "Respawning is currently disabled, do you want to use your permissions to circumvent it?", "Respawn", list("Yes", "No")) != "Yes") + return if (stat != DEAD) to_chat(usr, span_boldnotice("You must be dead to use this!")) @@ -856,15 +864,14 @@ M.key = key +/// Checks if the mob can respawn yet according to the respawn delay /mob/proc/check_respawn_delay(override_delay = 0) if(!override_delay && !CONFIG_GET(number/respawn_delay)) return TRUE var/death_time = world.time - client.player_details.time_of_death - var/required_delay = override_delay - if(!required_delay) - required_delay = CONFIG_GET(number/respawn_delay) + var/required_delay = override_delay || CONFIG_GET(number/respawn_delay) if(death_time < required_delay) if(!check_rights_for(usr.client, R_ADMIN)) diff --git a/config/config.txt b/config/config.txt index 3b3e0d0746e..3208cf84e92 100644 --- a/config/config.txt +++ b/config/config.txt @@ -136,11 +136,14 @@ VOTE_PERIOD 600 ## players' votes default to "No vote" (otherwise, default to "No change") # DEFAULT_NO_VOTE -## disable abandon mob -NORESPAWN +## Determines if players can respawn after death +## 0 = Cannot respawn (default) +## 1 = Can respawn +## 2 = Can respawn if choosing a different character +ALLOW_RESPAWN 0 -## Respawn delay (deciseconds), which doesn't allow to return to lobby (default 10 minutes) -#RESPAWN_DELAY 6000 +## Respawn delay (deciseconds), which doesn't allow to return to lobby +RESPAWN_DELAY 0 ## set a hosted by name for unix platforms HOSTEDBY Yournamehere