From c5c79aa9295dba63fa1f50e61cf9bdfb5d070aaf Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Sat, 7 Oct 2023 22:45:23 +0200 Subject: [PATCH] [MIRROR] Adds respawn config option forcing respawn as another character slot [MDB IGNORE] (#23943) * Adds respawn config option forcing respawn as another character slot (#78459) ## About The Pull Request Adds an option to the respawn config which forces you to pick another character (slot) before you respawn. ## Why It's Good For The Game Just an idea i'm throwing out there, not necessarily pushing for it to be enabled on any servers. Respawning as an alternative character can be a good way to make people less frustrated at dying, particularly if paired with the cooldown config that already exists: "Oh shucks, I died and got my head cut off and got absorbed and got spaced by some changeling. I won't be able to finish my project or whatever. At least in 15 minutes I may be able to join as my botanist character to try something else rather than having to wait an hour and a half for the round to tick over." Also nice for downstream support. (Obviously you can just, *ban* people who respawn as the same character, use an honor system, but codifying it seems better than not.) ## Changelog :cl: Melbert config: Adds a config option for player respawning that enables respawns, but forces you pick a new character. config: "NORESPAWN" has been replaced with "ALLOW_RESPAWN 0". Unlimited respawns is "ALLOW_RESPAWN 1" and character limited respawns is "ALLOW_RESPAWN 2". /:cl: --------- Co-authored-by: san7890 * Adds respawn config option forcing respawn as another character slot --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: san7890 --- code/__DEFINES/configuration.dm | 8 ++++ .../configuration/entries/general.dm | 19 +++++++- code/datums/world_topic.dm | 3 +- code/game/world.dm | 4 +- code/modules/admin/verbs/server.dm | 44 +++++++++++++++---- code/modules/client/player_details.dm | 16 ++++++- .../modules/mob/dead/new_player/new_player.dm | 8 ++++ code/modules/mob/mob.dm | 27 +++++++----- config/config.txt | 11 +++-- 9 files changed, 109 insertions(+), 31 deletions(-) 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