From 2b34897f49d9c0545c4cbb7ac50da1d835707f05 Mon Sep 17 00:00:00 2001 From: Krausus Date: Tue, 26 Jul 2016 10:29:03 -0400 Subject: [PATCH 1/4] Changes to player respawnability - Cryo auto-ghosting and ghosting after suicide will now produce non-respawnable ghosts - Non-respawnable ghosts are now prevented from re-entering the round by as many means as I could find --- code/__HELPERS/game.dm | 2 +- code/game/machinery/cryopod.dm | 4 +++- code/modules/mob/dead/observer/observer.dm | 13 ++++++++++--- .../silicon/robot/drone/drone_manufacturer.dm | 5 ++++- code/modules/research/xenobiology/xenobiology.dm | 2 ++ 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 0852622f2c6..fe23ae6b434 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -442,7 +442,7 @@ proc/pollCandidates(var/Question, var/be_special_type, var/antag_age_check = 0, if(!Question) Question = "Would you like to be a special role?" - for(var/mob/dead/observer/G in player_list) + for(var/mob/dead/observer/G in respawnable_list) if(!G.key || !G.client) continue if(be_special_type) diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index 257c583814b..3ca8d6e479d 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -382,7 +382,9 @@ announce.autosay("[occupant.real_name] [on_store_message]", "[on_store_name]") visible_message("\The [src] hums and hisses as it moves [occupant.real_name] into storage.") - // Delete the mob. + // Ghost and delete the mob. + if(!occupant.get_ghost(1)) + occupant.ghostize(0) // Despawned players may not re-enter the game qdel(occupant) occupant = null name = initial(name) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index b15761d8c57..409214c5fe7 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -149,11 +149,18 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp var/mob/M = src - if(stat == DEAD) + if(!suiciding && stat == DEAD) ghostize(1) else - var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost now, you probably won't be able to rejoin the round! You can't change your mind, so choose wisely!)","Are you sure you want to ghost?","Ghost","Stay in body") - if(response != "Ghost") return //didn't want to ghost after-all + var/response + var/alertmsg + if(suiciding) + alertmsg = "Are you -sure- you want to ghost?\n(You have committed suicide. If you ghost now, you probably won't be able to rejoin the round! You can't change your mind, so choose wisely!)" + else + alertmsg = "Are you -sure- you want to ghost?\n(You are alive. If you ghost now, you probably won't be able to rejoin the round! You can't change your mind, so choose wisely!)" + response = alert(src, alertmsg,"Are you sure you want to ghost?","Ghost","Stay in body") + if(response != "Ghost") + return //didn't want to ghost after-all resting = 1 var/mob/dead/observer/ghost = ghostize(0) //0 parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3 ghost.timeofdeath = world.time // Because the living mob won't have a time of death and we want the respawn timer to work properly. 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 3a316b0140b..81a425fa6d0 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm @@ -113,7 +113,10 @@ if(istype(src,/mob/dead/observer)) var/mob/dead/observer/G = src if(G.has_enabled_antagHUD == 1 && config.antag_hud_restricted) - to_chat(usr, "\blue Upon using the antagHUD you forfeited the ability to join the round.") + to_chat(usr, "Upon using the antagHUD you forfeited the ability to join the round.") + return + if(!G.can_reenter_corpse) + to_chat(usr, "You have given up your right to be respawned.") return if(G.started_as_observer == 1) joinedasobserver = 1 diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm index e3a59183abf..7dc37309b85 100644 --- a/code/modules/research/xenobiology/xenobiology.dm +++ b/code/modules/research/xenobiology/xenobiology.dm @@ -402,6 +402,8 @@ return 0 if(O.mind && O.mind.current && O.mind.current.stat != DEAD) return 0 + if(!O.can_reenter_corpse) + return 0 if(O.has_enabled_antagHUD == 1 && config.antag_hud_restricted) return 0 return 1 From dc9591e5025681c035e1751504672c13548450a7 Mon Sep 17 00:00:00 2001 From: Krausus Date: Wed, 27 Jul 2016 02:27:50 -0400 Subject: [PATCH 2/4] More respawnability changes - Respawning as a drone now ignores respawnability again - Respawning as ERT now ignores respawnability again, but respawnable ghosts get first dibs - Becoming a non-respawnable ghost once means all future ghosting will be be non-respawnable, unless you are sent back to the lobby - Posibrains now disqualify non-respawnable ghosts, and are more fickle about pinging --- code/__HELPERS/game.dm | 4 ++-- code/_globalvars/lists/mobs.dm | 1 + code/game/response_team.dm | 8 ++++++-- code/modules/admin/topic.dm | 1 + code/modules/mob/dead/observer/login.dm | 4 ++++ code/modules/mob/dead/observer/observer.dm | 20 +++++++++++++------ .../mob/living/carbon/brain/posibrain.dm | 9 ++++++++- .../silicon/robot/drone/drone_manufacturer.dm | 3 --- 8 files changed, 36 insertions(+), 14 deletions(-) diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index fe23ae6b434..5c11daabdba 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -435,14 +435,14 @@ /proc/SecondsToTicks(var/seconds) return seconds * 10 -proc/pollCandidates(var/Question, var/be_special_type, var/antag_age_check = 0, var/poll_time = 300) +proc/pollCandidates(var/Question, var/be_special_type, var/antag_age_check = 0, var/poll_time = 300, var/ignore_respawnability = 0) var/roletext = be_special_type ? get_roletext(be_special_type) : null var/list/mob/dead/observer/candidates = list() var/time_passed = world.time if(!Question) Question = "Would you like to be a special role?" - for(var/mob/dead/observer/G in respawnable_list) + for(var/mob/dead/observer/G in (ignore_respawnability ? player_list : respawnable_list)) if(!G.key || !G.client) continue if(be_special_type) diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index b6dc1c58b8f..644740c9e20 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -22,6 +22,7 @@ var/global/list/spirits = list() //List of all the spirits, including Masks var/global/list/living_mob_list = list() //List of all alive mobs, including clientless. Excludes /mob/new_player var/global/list/dead_mob_list = list() //List of all dead mobs, including clientless. Excludes /mob/new_player var/global/list/respawnable_list = list() //List of all mobs, dead or in mindless creatures that still be respawned. +var/global/list/non_respawnable_keys = list() //List of ckeys that are excluded from respawning for remainder of round. var/global/list/simple_animal_list = list() //List of all simple animals, including clientless var/global/list/snpc_list = list() //List of all snpc's, including clientless diff --git a/code/game/response_team.dm b/code/game/response_team.dm index abd4f0fcffa..6751f201f98 100644 --- a/code/game/response_team.dm +++ b/code/game/response_team.dm @@ -114,13 +114,17 @@ var/ert_request_answered = 0 active_team = response_team_type send_emergency_team = 1 - var/list/ert_candidates = pollCandidates("Join the Emergency Response Team?",, responseteam_age, 600) + var/list/ert_candidates = pollCandidates("Join the Emergency Response Team?",, responseteam_age, 600, 1) if(!ert_candidates.len) active_team.cannot_send_team() send_emergency_team = 0 return var/teamsize = 0 - for(var/mob/dead/observer/M in ert_candidates) + // Respawnable players get first dibs + for(var/mob/dead/observer/M in (ert_candidates & respawnable_list)) + teamsize += M.JoinResponseTeam() + // If there's still open slots, non-respawnable players can fill them + for(var/mob/dead/observer/M in (ert_candidates - respawnable_list)) teamsize += M.JoinResponseTeam() send_emergency_team = 0 if (!teamsize) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index a7fc809aa88..2556330a87c 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1252,6 +1252,7 @@ message_admins("[key_name_admin(usr)] has sent [key_name_admin(M)] back to the Lobby.") var/mob/new_player/NP = new() + non_respawnable_keys -= M.ckey NP.ckey = M.ckey qdel(M) diff --git a/code/modules/mob/dead/observer/login.dm b/code/modules/mob/dead/observer/login.dm index 7e3d3f6c4bf..eab9faf9a7a 100644 --- a/code/modules/mob/dead/observer/login.dm +++ b/code/modules/mob/dead/observer/login.dm @@ -3,5 +3,9 @@ if(ghostimage) ghostimage.icon_state = src.icon_state updateghostimages() + + if(non_respawnable_keys[ckey]) + can_reenter_corpse = 0 + respawnable_list -= src update_interface() \ No newline at end of file diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 409214c5fe7..74f7b37c96c 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -129,11 +129,15 @@ Works together with spawning an observer, noted above. /mob/proc/ghostize(var/flags = GHOST_CAN_REENTER) if(key) + if(non_respawnable_keys[ckey]) + flags &= ~GHOST_CAN_REENTER var/mob/dead/observer/ghost = new(src, flags) //Transfer safety to observer spawning proc. ghost.timeofdeath = src.timeofdeath //BS12 EDIT respawnable_list -= src if(ghost.can_reenter_corpse) respawnable_list += ghost + else + non_respawnable_keys[ckey] = 1 ghost.key = key if(!(ghost.client && ghost.client.holder) && !config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed. ghost.verbs -= /mob/dead/observer/verb/toggle_antagHUD // Poor guys, don't know what they are missing! @@ -148,16 +152,20 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp set desc = "Relinquish your life and enter the land of the dead." var/mob/M = src + var/warningmsg = null - if(!suiciding && stat == DEAD) + if(suiciding) + warningmsg = "You have committed suicide" + else if(stat != DEAD) + warningmsg = "You are alive" + else if(non_respawnable_keys[ckey]) + warningmsg = "You have lost your right to respawn" + + if(!warningmsg) ghostize(1) else var/response - var/alertmsg - if(suiciding) - alertmsg = "Are you -sure- you want to ghost?\n(You have committed suicide. If you ghost now, you probably won't be able to rejoin the round! You can't change your mind, so choose wisely!)" - else - alertmsg = "Are you -sure- you want to ghost?\n(You are alive. If you ghost now, you probably won't be able to rejoin the round! You can't change your mind, so choose wisely!)" + var/alertmsg = "Are you -sure- you want to ghost?\n([warningmsg]. If you ghost now, you probably won't be able to rejoin the round! You can't change your mind, so choose wisely!)" response = alert(src, alertmsg,"Are you sure you want to ghost?","Ghost","Stay in body") if(response != "Ghost") return //didn't want to ghost after-all diff --git a/code/modules/mob/living/carbon/brain/posibrain.dm b/code/modules/mob/living/carbon/brain/posibrain.dm index aad88276473..a581aadcb97 100644 --- a/code/modules/mob/living/carbon/brain/posibrain.dm +++ b/code/modules/mob/living/carbon/brain/posibrain.dm @@ -13,6 +13,7 @@ req_access = list(access_robotics) mecha = null//This does not appear to be used outside of reference in mecha.dm. var/silenced = 0 //if set to 1, they can't talk. + var/next_ping_at = 0 /obj/item/device/mmi/posibrain/attack_self(mob/user as mob) @@ -53,6 +54,8 @@ return 0 if(jobban_isbanned(O, "Cyborg") || jobban_isbanned(O,"nonhumandept")) return 0 + if(!O.can_reenter_corpse) + return 0 if(O.client) return 1 return 0 @@ -190,7 +193,11 @@ /obj/item/device/mmi/posibrain/attack_ghost(var/mob/dead/observer/O) if(searching) volunteer(O) - else + return + if(brainmob && brainmob.key) + return // No point pinging a posibrain with a player already inside + if(O.can_reenter_corpse && (world.time >= next_ping_at)) + next_ping_at = world.time + (20 SECONDS) var/turf/T = get_turf_or_move(src.loc) for(var/mob/M in viewers(T)) M.show_message("\blue The positronic brain pings softly.") 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 81a425fa6d0..745ec4084ef 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm @@ -115,9 +115,6 @@ if(G.has_enabled_antagHUD == 1 && config.antag_hud_restricted) to_chat(usr, "Upon using the antagHUD you forfeited the ability to join the round.") return - if(!G.can_reenter_corpse) - to_chat(usr, "You have given up your right to be respawned.") - return if(G.started_as_observer == 1) joinedasobserver = 1 From 08c1dab72f912737112478e9011628633fa4fb38 Mon Sep 17 00:00:00 2001 From: Krausus Date: Wed, 27 Jul 2016 02:34:43 -0400 Subject: [PATCH 3/4] Makes posibrain pings check observers properly --- code/modules/mob/living/carbon/brain/posibrain.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/carbon/brain/posibrain.dm b/code/modules/mob/living/carbon/brain/posibrain.dm index a581aadcb97..ea9dffd3ca0 100644 --- a/code/modules/mob/living/carbon/brain/posibrain.dm +++ b/code/modules/mob/living/carbon/brain/posibrain.dm @@ -196,7 +196,7 @@ return if(brainmob && brainmob.key) return // No point pinging a posibrain with a player already inside - if(O.can_reenter_corpse && (world.time >= next_ping_at)) + if(check_observer(O) && (world.time >= next_ping_at)) next_ping_at = world.time + (20 SECONDS) var/turf/T = get_turf_or_move(src.loc) for(var/mob/M in viewers(T)) From 03abd702e5bb9b35ed9c8dc95eb059a42afcc566 Mon Sep 17 00:00:00 2001 From: Krausus Date: Fri, 29 Jul 2016 18:26:54 -0400 Subject: [PATCH 4/4] Adds early abandon penalty period and other tweaks - New config option to set how many minutes is too early in a round to abandon it - Suicide-ghosting and cryo-ghosting now only make you non-respawnable during the penalty period - Manually entering a cryopod now despawns you 90% faster - Joining as a drone now has a confirmation box --- code/__DEFINES/misc.dm | 3 +++ code/controllers/configuration.dm | 4 ++++ code/game/machinery/cryopod.dm | 19 +++++++++++++++---- code/modules/mob/dead/observer/observer.dm | 12 ++++++++---- .../silicon/robot/drone/drone_manufacturer.dm | 3 +++ config/example/config.txt | 5 +++++ 6 files changed, 38 insertions(+), 8 deletions(-) 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