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 <funnyman3595@gmail.com>

---------

Signed-off-by: Charlie Nolan <funnyman3595@gmail.com>
Co-authored-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com>
This commit is contained in:
Charlie Nolan
2025-08-19 06:42:43 -07:00
committed by GitHub
parent e43a88de5b
commit 1d068fe25c
25 changed files with 128 additions and 93 deletions
+18 -7
View File
@@ -1746,18 +1746,29 @@
to_chat(usr, "<span class='warning'>This will only work on /mob/dead/observer</span>")
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
-2
View File
@@ -7,8 +7,6 @@
to_chat(src, "<font color='red'>Error: Admin-PM: You cannot send adminhelps (Muted).</font>", 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
+17 -17
View File
@@ -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 = "<span class='[receive_span]' size='3'>-- Click the [receive_pm_type]'s name to reply --</span>\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) ? "(<a href='byond://?src=[pm_tracker.UID()];ping=[C.key]'>PING</a>)" : ""
var/ping_link = check_rights(R_ADMIN, 0, mob) ? "(<a href='byond://?src=[persistent.pm_tracker.UID()];ping=[C.key]'>PING</a>)" : ""
var/ticket_link
var/alert_link = check_rights(R_ADMIN, FALSE, mob) ? "(<a href='byond://?src=[pm_tracker.UID()];adminalert=[C.mob.UID()]'>ALERT</a>)" : ""
var/alert_link = check_rights(R_ADMIN, FALSE, mob) ? "(<a href='byond://?src=[persistent.pm_tracker.UID()];adminalert=[C.mob.UID()]'>ALERT</a>)" : ""
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 = "(<a href='byond://?_src_=holder;openticket=[ticket_id]'>TICKET</a>)"
var/emoji_msg = "<span class='emoji_enabled'>[msg]</span>"
var/receive_window_link = "(<a href='byond://?src=[C.pm_tracker.UID()];newtitle=[key]'>WINDOW</a>)"
var/receive_window_link = "(<a href='byond://?src=[C.persistent.pm_tracker.UID()];newtitle=[key]'>WINDOW</a>)"
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 = "(<a href='byond://?src=[pm_tracker.UID()];newtitle=[C.key]'>WINDOW</a>)"
var/send_window_link = "(<a href='byond://?src=[persistent.pm_tracker.UID()];newtitle=[C.key]'>WINDOW</a>)"
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, "<span class='notice'>Forced open [C]'s messages window.</span>")
return
+1 -1
View File
@@ -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
+6 -1
View File
@@ -621,12 +621,14 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
log_admin("[key_name(usr)] changed the equipment of [key_name(M)] to [dresscode].")
message_admins("<span class='notice'>[key_name_admin(usr)] changed the equipment of [key_name_admin(M)] to [dresscode].</span>", 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
+1 -1
View File
@@ -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