From 1d068fe25cca49cb6197bb4a30c76ac6147b1c8f Mon Sep 17 00:00:00 2001 From: Charlie Nolan Date: Tue, 19 Aug 2025 06:42:43 -0700 Subject: [PATCH] Persistent clients and body recovery (#29974) * Persistent clients and body recovery * Update code/_globalvars/lists/mob_lists.dm Co-authored-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com> Signed-off-by: Charlie Nolan --------- Signed-off-by: Charlie Nolan Co-authored-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com> --- code/__DEFINES/_math.dm | 3 -- code/__DEFINES/clothing_defines.dm | 2 +- code/_globalvars/lists/mob_lists.dm | 1 + code/controllers/subsystem/SSticker.dm | 4 +- .../subsystem/tickets/SStickets.dm | 8 ++-- code/datums/mind.dm | 37 +++++++++++++------ .../game/gamemodes/autotraitor/autotraitor.dm | 4 +- code/game/gamemodes/dynamic/antag_rulesets.dm | 2 +- code/game/gamemodes/game_mode.dm | 4 +- code/modules/admin/topic.dm | 25 +++++++++---- code/modules/admin/verbs/adminhelp.dm | 2 - code/modules/admin/verbs/adminpm.dm | 34 ++++++++--------- code/modules/admin/verbs/deathsquad.dm | 2 +- code/modules/admin/verbs/debug.dm | 7 +++- code/modules/admin/verbs/one_click_antag.dm | 2 +- code/modules/client/client_defines.dm | 22 +++++++---- code/modules/client/client_procs.dm | 9 ++++- .../mob/dead/observer/observer_base.dm | 16 ++++---- code/modules/mob/living/living.dm | 2 +- .../mob/living/silicon/robot/robot_mob.dm | 2 +- .../living/simple_animal/friendly/mouse.dm | 2 +- code/modules/mob/mob.dm | 11 ++---- code/modules/mob/new_player/new_player.dm | 13 ++++--- .../mob/new_player/new_player_login.dm | 5 --- code/modules/response_team/ert.dm | 2 +- 25 files changed, 128 insertions(+), 93 deletions(-) diff --git a/code/__DEFINES/_math.dm b/code/__DEFINES/_math.dm index f3cdb06cbdb..6ce1dddaf1b 100644 --- a/code/__DEFINES/_math.dm +++ b/code/__DEFINES/_math.dm @@ -104,9 +104,6 @@ #define TORADIANS(degrees) ((degrees) * 0.0174532925) -/// Gets shift x that would be required the bitflag (1< 5 ? special_encouragement_messages : base_encouragement_messages) - to_chat(M, "You received [length(M.mind.kudos_received_from)] kudos from other players this round! [kudos_message]") + to_chat(M, "You received [length(kudos)] kudos from other players this round! [kudos_message]") // Seal the blackbox, stop collecting info SSblackbox.Seal() diff --git a/code/controllers/subsystem/tickets/SStickets.dm b/code/controllers/subsystem/tickets/SStickets.dm index 0471e684587..6d8a76d13bd 100644 --- a/code/controllers/subsystem/tickets/SStickets.dm +++ b/code/controllers/subsystem/tickets/SStickets.dm @@ -576,8 +576,8 @@ UI STUFF dat += "" var/client/C = get_client_by_ckey(T.client_ckey) - for(var/key in C?.pm_tracker.pms) - var/datum/pm_convo/convo = C.pm_tracker.pms[key] + for(var/key in C?.persistent.pm_tracker.pms) + var/datum/pm_convo/convo = C.persistent.pm_tracker.pms[key] if(convo.typing) dat += "[key] is typing
" @@ -587,10 +587,10 @@ UI STUFF continue if(!check_rights_client(rights_needed, FALSE, X)) continue - for(var/key in X.pm_tracker.pms) + for(var/key in X.persistent.pm_tracker.pms) if(ckey(key) != ckey(T.client_ckey)) continue - var/datum/pm_convo/convo = X.pm_tracker.pms[key] + var/datum/pm_convo/convo = X.persistent.pm_tracker.pms[key] if(convo.typing) dat += "[key] is typing
" found_typing = TRUE diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 635634fddba..a438d8e557a 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -23,6 +23,8 @@ var/key var/name //replaces mob/var/original_name var/mob/living/current + /// A serialized copy of this mind's body when it was destroyed, for admin respawn usage. + var/destroyed_body_json /// The original mob's UID. Used for example to see if a silicon with antag status is actually malf. Or just an antag put in a borg var/original_mob_UID /// The original mob's name. Used in Dchat messages @@ -75,9 +77,6 @@ var/list/learned_recipes //List of learned recipe TYPES. - /// List of people who we've received kudos from. - var/list/kudos_received_from = list() - /datum/mind/New(new_key) key = new_key objective_holder = new(src) @@ -86,8 +85,7 @@ SSticker.minds -= src remove_all_antag_datums() qdel(objective_holder) - current = null - kudos_received_from.Cut() + unbind() return ..() /datum/mind/proc/set_original_mob(mob/original) @@ -126,13 +124,27 @@ return out_ckey +/datum/mind/proc/archive_deleted_body() + SIGNAL_HANDLER // COMSIG_PARENT_QDELETING + if(isliving(current)) + destroyed_body_json = json_encode(current.serialize()) + +/datum/mind/proc/bind_to(mob/living/new_character) + current = new_character + new_character.mind = src + RegisterSignal(current, COMSIG_PARENT_QDELETING, PROC_REF(archive_deleted_body), override = TRUE) + +/datum/mind/proc/unbind() + UnregisterSignal(current, COMSIG_PARENT_QDELETING) + current.mind = null + current = null + /datum/mind/proc/transfer_to(mob/living/new_character) var/datum/atom_hud/antag/hud_to_transfer = antag_hud //we need this because leave_hud() will clear this list var/mob/living/old_current = current if(!istype(new_character)) stack_trace("transfer_to(): Some idiot has tried to transfer_to() a non mob/living mob.") if(current) //remove ourself from our old body's mind variable - current.mind = null if(isliving(current)) current.med_hud_set_status() leave_all_huds() //leave all the huds in the old body, so it won't get huds if somebody else enters it @@ -141,11 +153,13 @@ new_character.job = current.job //transfer our job over to the new body - if(new_character.mind) //remove any mind currently in our new body's mind variable - new_character.mind.current = null + unbind() + + if(new_character.mind) //remove any mind currently in our new body's mind variable + new_character.mind.unbind() + + bind_to(new_character) - current = new_character //link ourself to our new body - new_character.mind = src //and link our new body to ourself for(var/a in antag_datums) //Makes sure all antag datums effects are applied in the new body var/datum/antagonist/A = a A.on_body_transfer(old_current, current) @@ -1858,7 +1872,7 @@ error("mind_initialize(): No ticker ready yet! Please inform Carn") if(!mind.name) mind.name = real_name - mind.current = src + mind.bind_to(src) SEND_SIGNAL(src, COMSIG_MIND_INITIALIZE) //HUMAN @@ -1870,6 +1884,7 @@ /mob/proc/sync_mind() mind_initialize() //updates the mind (or creates and initializes one if one doesn't exist) mind.active = TRUE //indicates that the mind is currently synced with a client + client.persistent.minds |= mind //slime /mob/living/simple_animal/slime/mind_initialize() diff --git a/code/game/gamemodes/autotraitor/autotraitor.dm b/code/game/gamemodes/autotraitor/autotraitor.dm index cb4e4048bca..2c45f347277 100644 --- a/code/game/gamemodes/autotraitor/autotraitor.dm +++ b/code/game/gamemodes/autotraitor/autotraitor.dm @@ -73,7 +73,7 @@ traitor_count += 1 continue if(ishuman(player) || is_ai(player)) - if((ROLE_TRAITOR in player.client.prefs.be_special) && !player.client.skip_antag && !jobban_isbanned(player, ROLE_TRAITOR) && !jobban_isbanned(player, ROLE_SYNDICATE)) + if((ROLE_TRAITOR in player.client.prefs.be_special) && !player.client.persistent.skip_antag && !jobban_isbanned(player, ROLE_TRAITOR) && !jobban_isbanned(player, ROLE_SYNDICATE)) possible_traitors += player.mind for(var/datum/mind/player in possible_traitors) for(var/job in restricted_jobs) @@ -119,7 +119,7 @@ if(SSshuttle.emergency.mode >= SHUTTLE_ESCAPE) return - if(character.client && (ROLE_TRAITOR in character.client.prefs.be_special) && !character.client.skip_antag && !jobban_isbanned(character, ROLE_TRAITOR) && !jobban_isbanned(character, ROLE_SYNDICATE)) + if(character.client && (ROLE_TRAITOR in character.client.prefs.be_special) && !character.client.persistent.skip_antag && !jobban_isbanned(character, ROLE_TRAITOR) && !jobban_isbanned(character, ROLE_SYNDICATE)) var/player_count = 0 var/traitor_count = 0 for(var/mob/living/player in GLOB.mob_list) diff --git a/code/game/gamemodes/dynamic/antag_rulesets.dm b/code/game/gamemodes/dynamic/antag_rulesets.dm index 0e6945fb8c1..73b68a855a3 100644 --- a/code/game/gamemodes/dynamic/antag_rulesets.dm +++ b/code/game/gamemodes/dynamic/antag_rulesets.dm @@ -146,7 +146,7 @@ if(jobban_isbanned(player, ROLE_SYNDICATE) || jobban_isbanned(player, antagonist_type::job_rank)) continue // Make sure they want to play antag, and that they're not already something (off station or antag) - if(player.client.skip_antag || player.mind.offstation_role || player.mind.special_role) + if(player.client.persistent.skip_antag || player.mind.offstation_role || player.mind.special_role) continue // Make sure they actually want to be this antagonist if(!(antagonist_type::job_rank in player.client.prefs.be_special)) diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 0e77fe92352..000bbb9cc52 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -299,7 +299,7 @@ players = shuffle(players) // Get a list of all the people who want to be the antagonist for this round for(var/mob/eligible_player in players) - if(!eligible_player.client.skip_antag) + if(!eligible_player.client.persistent.skip_antag) if(species_exclusive && (eligible_player.client.prefs.active_character.species != species_exclusive)) continue if(role in eligible_player.client.prefs.be_special) @@ -339,7 +339,7 @@ // Get a list of all the people who want to be the antagonist for this round, except those with incompatible species, and those who are already antagonists for(var/mob/living/carbon/human/player in players) - if(player.client.skip_antag || !(allow_offstation_roles || !player.mind?.offstation_role) || player.mind?.special_role) + if(player.client.persistent.skip_antag || !(allow_offstation_roles || !player.mind?.offstation_role) || player.mind?.special_role) continue if(!(role in player.client.prefs.be_special) || (player.client.prefs.active_character.species in species_to_mindflayer)) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 8d37e5ec603..03e6eec9ac1 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1746,18 +1746,29 @@ to_chat(usr, "This will only work on /mob/dead/observer") return - var/posttransformoutfit = usr.client.robust_dress_shop() + var/list/potential_minds = list() + for(var/datum/mind/mind in G.client.persistent.minds) + if(ckey(mind.key) == G.ckey && isnull(mind.current) && mind.destroyed_body_json) + potential_minds += mind + var/outfit = usr.client.robust_dress_shop(potential_minds) - if(!posttransformoutfit) + if(!outfit) return - var/mob/living/carbon/human/H = G.incarnate_ghost() + var/mob/M + if(istype(outfit, /datum/mind)) + M = G.incarnate_ghost(outfit) - if(posttransformoutfit && istype(H)) - H.equipOutfit(posttransformoutfit) + log_admin("[key_name(M)] was rebuilt from a mind backup by [key_name(owner)]") + message_admins("[key_name_admin(M)] was rebuilt from a mind backup by [key_name_admin(owner)]") + else + M = G.incarnate_ghost() + if(ishuman(M)) + var/mob/living/carbon/human/H = M + H.equipOutfit(outfit) - log_admin("[key_name(G)] was incarnated by [key_name(owner)]") - message_admins("[key_name_admin(G)] was incarnated by [key_name_admin(owner)]") + log_admin("[key_name(M)] was incarnated by [key_name(owner)]") + message_admins("[key_name_admin(M)] was incarnated by [key_name_admin(owner)]") else if(href_list["togmutate"]) if(!check_rights(R_SPAWN)) return diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index e8de49e3c02..8a63a8e1541 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -7,8 +7,6 @@ to_chat(src, "Error: Admin-PM: You cannot send adminhelps (Muted).", MESSAGE_TYPE_ADMINPM, confidential = TRUE) return - adminhelped = TRUE //Determines if they get the message to reply by clicking the name. - var/msg var/list/type = list("Mentorhelp", "Adminhelp") var/selected_type = input("Pick a category.", "Admin Help") as null|anything in type diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index 47955f68a22..650d84c57de 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -158,15 +158,15 @@ var/receive_message = "" - pm_tracker.add_message(C, src, msg, mob) - C.pm_tracker.add_message(src, src, msg, C.mob) + persistent.pm_tracker.add_message(C, src, msg, mob) + C.persistent.pm_tracker.add_message(src, src, msg, C.mob) if(holder && !C.holder) receive_message = "-- Click the [receive_pm_type]'s name to reply --\n" - if(C.adminhelped) + to_chat(C, receive_message) + if(message_type == MESSAGE_TYPE_ADMINPM) + // Try to get their attention if they're alt-tabbed. window_flash(C) - to_chat(C, receive_message) - C.adminhelped = 0 //AdminPM popup for ApocStation and anybody else who wants to use it. Set it with POPUP_ADMIN_PM in config.txt ~Carn if(GLOB.configuration.general.popup_admin_pm) @@ -181,9 +181,9 @@ adminhelp(reply) //sender has left, adminhelp instead return - var/ping_link = check_rights(R_ADMIN, 0, mob) ? "(PING)" : "" + var/ping_link = check_rights(R_ADMIN, 0, mob) ? "(PING)" : "" var/ticket_link - var/alert_link = check_rights(R_ADMIN, FALSE, mob) ? "(ALERT)" : "" + var/alert_link = check_rights(R_ADMIN, FALSE, mob) ? "(ALERT)" : "" var/observe_link = check_rights(R_MENTOR, FALSE, mob) ? "([ADMIN_OBS(C, "OBS")])" : "" if(ticket_id != -1) if(message_type == MESSAGE_TYPE_MENTORPM) @@ -192,7 +192,7 @@ ticket_link = "(TICKET)" var/emoji_msg = "[msg]" - var/receive_window_link = "(WINDOW)" + var/receive_window_link = "(WINDOW)" if(message_type == MESSAGE_TYPE_MENTORPM && check_rights(R_ADMIN|R_MENTOR, 0, C.mob)) receive_window_link = ticket_link else if(message_type == MESSAGE_TYPE_ADMINPM && check_rights(R_ADMIN, 0, C.mob)) @@ -204,7 +204,7 @@ receive_message = chat_box_ahelp(receive_message) to_chat(C, receive_message) if(C != src) - var/send_window_link = "(WINDOW)" + var/send_window_link = "(WINDOW)" if(message_type == MESSAGE_TYPE_MENTORPM && check_rights(R_ADMIN|R_MENTOR, 0, mob)) send_window_link = ticket_link else if(message_type == MESSAGE_TYPE_ADMINPM && check_rights(R_ADMIN, 0, mob)) @@ -285,18 +285,18 @@ /client/verb/open_pms_ui() set name = "My PMs" set category = "OOC" - pm_tracker.show_ui(usr) + persistent.pm_tracker.show_ui(usr) /client/proc/set_typing(client/target, value) if(!target) return - var/datum/pm_convo/convo = target.pm_tracker.pms[key] + var/datum/pm_convo/convo = target.persistent.pm_tracker.pms[key] if(!convo) convo = new /datum/pm_convo(src) - target.pm_tracker.pms[key] = convo + target.persistent.pm_tracker.pms[key] = convo convo.typing = value - if(target.pm_tracker.open && target.pm_tracker.current_title == key) - target.pm_tracker.show_ui(target.mob) + if(target.persistent.pm_tracker.open && target.persistent.pm_tracker.current_title == key) + target.persistent.pm_tracker.show_ui(target.mob) /datum/pm_tracker var/ckey @@ -449,10 +449,10 @@ if(href_list["ping"]) var/client/C = pms[href_list["ping"]].client if(C) - C.pm_tracker.current_title = usr.key - C.pm_tracker.forced = TRUE // We forced it open + C.persistent.pm_tracker.current_title = usr.key + C.persistent.pm_tracker.forced = TRUE // We forced it open window_flash(C) - C.pm_tracker.show_ui(C.mob) + C.persistent.pm_tracker.show_ui(C.mob) to_chat(usr, "Forced open [C]'s messages window.") return diff --git a/code/modules/admin/verbs/deathsquad.dm b/code/modules/admin/verbs/deathsquad.dm index e984f4b1ce0..174e17c8dd3 100644 --- a/code/modules/admin/verbs/deathsquad.dm +++ b/code/modules/admin/verbs/deathsquad.dm @@ -163,7 +163,7 @@ GLOBAL_VAR_INIT(deathsquad_sent, FALSE) R.custom_name = borgname R.real_name = R.name R.mind = new - R.mind.current = R + R.mind.bind_to(R) R.mind.set_original_mob(R) R.mind.assigned_role = SPECIAL_ROLE_DEATHSQUAD R.mind.special_role = SPECIAL_ROLE_DEATHSQUAD diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 222124060cd..0d54cfb624f 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -621,12 +621,14 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention) log_admin("[key_name(usr)] changed the equipment of [key_name(M)] to [dresscode].") message_admins("[key_name_admin(usr)] changed the equipment of [key_name_admin(M)] to [dresscode].", 1) -/client/proc/robust_dress_shop() +/client/proc/robust_dress_shop(list/potential_minds) var/list/special_outfits = list( "Naked", "As Job...", "Custom..." ) + if(length(potential_minds)) + special_outfits += "Recover destroyed body..." var/list/outfits = list() var/list/paths = subtypesof(/datum/outfit) - typesof(/datum/outfit/job) - list(/datum/outfit/varedit, /datum/outfit/admin) @@ -665,6 +667,9 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention) dresscode = custom_names[selected_name] if(isnull(dresscode)) return + + if(dresscode == "Recover destroyed body...") + dresscode = input("Select body to rebuild", "Robust quick dress shop") as null|anything in potential_minds return dresscode diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index ca0092f88ae..89597123153 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -36,7 +36,7 @@ if((M.mind.assigned_role in temp.restricted_jobs) || (M.client.prefs.active_character.species in temp.species_to_mindflayer)) return FALSE if(role) // Don't even bother evaluating if there's no role - if(player_old_enough_antag(M.client,role) && (role in M.client.prefs.be_special) && !M.client.skip_antag && (!jobban_isbanned(M, role))) + if(player_old_enough_antag(M.client,role) && (role in M.client.prefs.be_special) && !M.client.persistent.skip_antag && (!jobban_isbanned(M, role))) return TRUE else return FALSE diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index 38eb3c674db..ad8d8734e02 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -6,31 +6,27 @@ //////////////// /// hides the byond verb panel as we use our own custom version show_verb_panel = FALSE + + var/datum/persistent_client/persistent + var/datum/admins/holder = null var/last_message = "" //contains the last message sent by this client - used to protect against copy-paste spamming. var/last_message_count = 0 //contains a number of how many times a message identical to last_message was sent. var/last_message_time = 0 //holds the last time (based on world.time) a message was sent - var/datum/pm_tracker/pm_tracker ///////// //OTHER// ///////// var/datum/preferences/prefs = null - var/skip_antag = FALSE //TRUE when a player declines to be included for the selection process of game mode antagonists. ///The visual delay to use for the current client.Move(), mostly used for making a client based move look like it came from some other slower source var/visual_delay = 0 var/move_delay = 1 var/moving = null var/area = null - // why the hell do we track this when you can just file > reconnect to bypass it - var/time_died_as_mouse = null //when the client last died as a mouse - var/typing = FALSE // Prevents typing window stacking - var/adminhelped = 0 - /////////////// //SOUND STUFF// /////////////// @@ -235,3 +231,15 @@ /// If this client has any windows scaling applied var/window_scaling + +/datum/persistent_client + /// Holds admin/mentor PM history. + var/datum/pm_tracker/pm_tracker + /// The Global Antag Candidacy setting from the new player menu. + var/skip_antag = FALSE + /// Used to prevent rapid mouse spamming. + var/time_died_as_mouse = null + /// All of the minds this client has been associated with. + var/list/minds = list() + /// Ckeys that sent us kudos. + var/list/kudos_received_from = list() diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index d43679372be..f5b60b6c797 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -278,8 +278,10 @@ stat_panel = new(src, "statbrowser") stat_panel.subscribe(src, PROC_REF(on_stat_panel_message)) - // Create a PM tracker bound to this ckey. - pm_tracker = new(ckey) + persistent = GLOB.persistent_clients[ckey] + if(!persistent) + persistent = new(ckey) + GLOB.persistent_clients[ckey] = persistent tgui_panel = new(src, "chat_panel") tgui_say = new(src, "tgui_say") @@ -1340,6 +1342,9 @@ src << link("https://secure.byond.com/download/") +/datum/persistent_client/New(ckey) + // Create a PM tracker bound to this ckey. + pm_tracker = new(ckey) #undef LIMITER_SIZE #undef CURRENT_SECOND diff --git a/code/modules/mob/dead/observer/observer_base.dm b/code/modules/mob/dead/observer/observer_base.dm index a6ec09ea865..0b747043960 100644 --- a/code/modules/mob/dead/observer/observer_base.dm +++ b/code/modules/mob/dead/observer/observer_base.dm @@ -803,17 +803,19 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp return TRUE -/mob/dead/observer/proc/incarnate_ghost() +/mob/dead/observer/proc/incarnate_ghost(datum/mind/from_mind = null) if(!client) return - var/mob/living/carbon/human/new_char = new(get_turf(src)) - client.prefs.active_character.copy_to(new_char) - if(mind) - mind.active = TRUE - mind.transfer_to(new_char) + var/mob/new_char + if(from_mind) + new_char = json_to_object(from_mind.destroyed_body_json, get_turf(src)) + from_mind.transfer_to(new_char) else - new_char.key = key + new_char = new /mob/living/carbon/human(get_turf(src)) + client.prefs.active_character.copy_to(new_char) + if(!new_char.ckey) + new_char.ckey = ckey return new_char diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 0562bb5bed4..d13909c7e3c 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -57,7 +57,7 @@ S.be_replaced() QDEL_NULL(middleClickOverride) if(mind?.current == src) - mind.current = null + mind.unbind() UnregisterSignal(src, COMSIG_ATOM_PREHIT) return ..() diff --git a/code/modules/mob/living/silicon/robot/robot_mob.dm b/code/modules/mob/living/silicon/robot/robot_mob.dm index 47d59139fa5..453455ac936 100644 --- a/code/modules/mob/living/silicon/robot/robot_mob.dm +++ b/code/modules/mob/living/silicon/robot/robot_mob.dm @@ -1626,7 +1626,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( custom_name = borgname real_name = name mind = new - mind.current = src + mind.bind_to(src) mind.set_original_mob(src) mind.assigned_role = SPECIAL_ROLE_ERT mind.special_role = SPECIAL_ROLE_ERT diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm index 3221b803cbb..8c58d1974ed 100644 --- a/code/modules/mob/living/simple_animal/friendly/mouse.dm +++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm @@ -126,7 +126,7 @@ return FALSE layer = MOB_LAYER if(client) - client.time_died_as_mouse = world.time + client.persistent.time_died_as_mouse = world.time /* * Mouse types diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 4cec48dda07..9c5d853ea20 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -965,9 +965,6 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \ /mob/proc/is_mechanical() return mind && (mind.assigned_role == "Cyborg" || mind.assigned_role == "AI") -/mob/proc/is_ready() - return client && !!mind - /mob/proc/is_in_brig() if(!loc || !loc.loc) return 0 @@ -1107,8 +1104,8 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \ * Returns true if the player successfully becomes a mouse */ /mob/proc/become_mouse() - var/timedifference = world.time - client.time_died_as_mouse - if(client.time_died_as_mouse && timedifference <= GLOB.mouse_respawn_time * 600) + var/timedifference = world.time - client.persistent.time_died_as_mouse + if(client.persistent.time_died_as_mouse && timedifference <= GLOB.mouse_respawn_time * 600) var/timedifference_text = time2text(GLOB.mouse_respawn_time * 600 - timedifference,"mm:ss") to_chat(src, "You may only spawn again as a mouse more than [GLOB.mouse_respawn_time] minutes after your death. You have [timedifference_text] left.") return FALSE @@ -1519,10 +1516,10 @@ GLOBAL_LIST_INIT(holy_areas, typecacheof(list( // Pretend we've always succeeded when we might not have. // This should prevent people from using it to suss anything out about mobs' states - if(!client || !target.mind) + if(!client || !target.client) return - target.mind.kudos_received_from |= ckey + target.client.persistent.kudos_received_from |= ckey /mob/living/simple_animal/relaymove(mob/living/user, direction) if(user.incapacitated()) diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 280a4fa145a..c62633d9986 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -19,7 +19,8 @@ /mob/new_player/Destroy() if(mind) - mind.current = null // We best null their mind as well, otherwise /every/ single new player is going to explode the server a little more going in/out of the round + // Minds really shouldn't bind to new players, but just in case... + mind.unbind() return ..() /mob/new_player/proc/new_player_panel() @@ -62,11 +63,11 @@ var/list/antags = client.prefs.be_special if(length(antags)) - if(!client.skip_antag) + if(!client.persistent.skip_antag) output += "

Global Antag Candidacy" else output += "

Global Antag Candidacy" - output += "
You are [client.skip_antag ? "ineligible" : "eligible"] for all antag roles.

" + output += "
You are [client.persistent.skip_antag ? "ineligible" : "eligible"] for all antag roles.

" if(SSticker.current_state == GAME_STATE_STARTUP) output += "

Observe (Please wait...)

" @@ -143,7 +144,7 @@ new_player_panel_proc() if(href_list["skip_antag"]) - client.skip_antag = !client.skip_antag + client.persistent.skip_antag = !client.persistent.skip_antag new_player_panel_proc() if(href_list["refresh"]) @@ -613,8 +614,8 @@ if(!client || !client.prefs) ..() return client.prefs.active_character.gender -/mob/new_player/is_ready() - return ready && ..() +/mob/new_player/proc/is_ready() + return ready && client // No hearing announcements /mob/new_player/can_hear() diff --git a/code/modules/mob/new_player/new_player_login.dm b/code/modules/mob/new_player/new_player_login.dm index 95225af0d00..036618d9751 100644 --- a/code/modules/mob/new_player/new_player_login.dm +++ b/code/modules/mob/new_player/new_player_login.dm @@ -3,11 +3,6 @@ if(GLOB.join_motd) to_chat(src, "
[GLOB.join_motd]
") - if(!mind) - mind = new /datum/mind(key) - mind.active = TRUE - mind.current = src - if(length(GLOB.newplayer_start)) loc = pick(GLOB.newplayer_start) else diff --git a/code/modules/response_team/ert.dm b/code/modules/response_team/ert.dm index 5dc233e42ba..f3c1a4f016f 100644 --- a/code/modules/response_team/ert.dm +++ b/code/modules/response_team/ert.dm @@ -208,7 +208,7 @@ GLOBAL_LIST_EMPTY(ert_request_messages) //Creates mind stuff. M.mind = new - M.mind.current = M + M.mind.bind_to(M) M.mind.set_original_mob(M) M.mind.assigned_role = SPECIAL_ROLE_ERT M.mind.special_role = SPECIAL_ROLE_ERT