From 13e8bf9d8da5d0ddf95b41330cd09b4e2cc160c3 Mon Sep 17 00:00:00 2001 From: VerySoft Date: Fri, 25 Mar 2022 02:49:10 -0400 Subject: [PATCH] Auto-Resleeving Adds auto-resleeving! Under normal conditions, this allows one to resleeve their character after they have died in the round. The auto-resleever requires a bit of time after death to be used: -Characters who died due to vore reasons must wait 15 minutes -Characters who died for other reasons must wait 30 minutes The auto-resleever only requires power, there is no biomass requirement. The auto-resleever also works for species that can ordinarily not be resleeved, since the potential for abuse there is minimal. To use the auto-resleever, one only needs to click it as a ghost. If it is ready to revive you, it will pop up a confirmation dialogue. Additionally, the automatic transcore notification, and the 'Cancel Transcore Notification' verb has been removed. Ghosts have a 'Notify Transcore' verb, which can be used around 5 minutes after death if they wish to notify medical. This should eliminate false positives for medical, because no one likes resleeving people who don't need it. This does not otherwise alter the original resleeving process or machines. The auto-resleever for the tether is on Z1, just south of the psych office. It also features a return chute for items right next to the door. (I wanted to put it in the resleeving room's cleaning room, but it's really far into medical) The auto-resleever for the stellar delight is in the resleeving's cleaning room. I also fixed the access on the tourbus's APC while I was there. --- code/controllers/subsystems/transcore_vr.dm | 3 +- code/modules/admin/verbs/randomverbs.dm | 2 + code/modules/mob/dead/observer/observer_vr.dm | 14 +- code/modules/organs/organ_external.dm | 7 +- code/modules/resleeving/autoresleever.dm | 173 ++++++++ icons/obj/machines/autoresleever.dmi | Bin 0 -> 2904 bytes maps/stellardelight/stellar_delight1.dmm | 31 +- maps/tether/tether-01-surface1.dmm | 369 +++++++++++++----- maps/tether/tether-03-surface3.dmm | 4 +- maps/tether/tether_areas.dm | 2 + vorestation.dme | 1 + 11 files changed, 492 insertions(+), 114 deletions(-) create mode 100644 code/modules/resleeving/autoresleever.dm create mode 100644 icons/obj/machines/autoresleever.dmi diff --git a/code/controllers/subsystems/transcore_vr.dm b/code/controllers/subsystems/transcore_vr.dm index 6b0815999b..f185c4bbb8 100644 --- a/code/controllers/subsystems/transcore_vr.dm +++ b/code/controllers/subsystems/transcore_vr.dm @@ -112,10 +112,11 @@ SUBSYSTEM_DEF(transcore) if(since_backup < overdue_time) curr_MR.dead_state = MR_NORMAL else - if(curr_MR.dead_state != MR_DEAD) //First time switching to dead +/* if(curr_MR.dead_state != MR_DEAD) //First time switching to dead //Remove auto notification! Ghosts have a button to notify, so no more false flags. if(curr_MR.do_notify) db.notify(curr_MR) curr_MR.last_notification = world.time +*/ curr_MR.dead_state = MR_DEAD if(MC_TICK_CHECK) diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 267871366b..fcf5d64e7e 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -9,6 +9,8 @@ return for(var/obj/item/W in M) + if(istype(W, /obj/item/weapon/implant/backup) || istype(W, /obj/item/device/nif)) //VOREStation Edit - There's basically no reason to remove either of these + continue //VOREStation Edit M.drop_from_inventory(W) log_admin("[key_name(usr)] made [key_name(M)] drop everything!") diff --git a/code/modules/mob/dead/observer/observer_vr.dm b/code/modules/mob/dead/observer/observer_vr.dm index 1fb9d913c9..c6ea1050d9 100644 --- a/code/modules/mob/dead/observer/observer_vr.dm +++ b/code/modules/mob/dead/observer/observer_vr.dm @@ -68,8 +68,14 @@ var/datum/transcore_db/db = SStranscore.db_by_mind_name(mind.name) if(db) var/datum/transhuman/mind_record/record = db.backed_up[src.mind.name] - if(!(record.dead_state == MR_DEAD)) - to_chat(src, "Your backup is not past-due yet.") + if(!(record.dead_state == MR_DEAD)) + if((world.time - timeofdeath ) > 5 MINUTES) //Allows notify transcore to be used if you have an entry but for some reason weren't marked as dead + record.dead_state = MR_DEAD //Such as if you got scanned but didn't take an implant. It's a little funky, but I mean, you got scanned + db.notify(record) //So you probably will want to let someone know if you die. + record.last_notification = world.time + to_chat(src, "New notification has been sent.") + else + to_chat(src, "Your backup is not past-due yet.") else if((world.time - record.last_notification) < 5 MINUTES) to_chat(src, "Too little time has passed since your last notification.") else @@ -78,7 +84,7 @@ to_chat(src, "New notification has been sent.") else to_chat(src,"No backup record could be found, sorry.") - +/* /mob/observer/dead/verb/backup_delay() set category = "Ghost" set name = "Cancel Transcore Notification" @@ -97,7 +103,7 @@ to_chat(src, "Overdue mind backup notification delayed successfully.") else to_chat(src,"No backup record could be found, sorry.") - +*/ /mob/observer/dead/verb/findghostpod() //Moves the ghost instead of just changing the ghosts's eye -Nodrak set category = "Ghost" set name = "Find Ghost Pod" diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index 363353c2ec..85d0720670 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -485,9 +485,10 @@ This function completely restores a damaged organ to perfect condition. // remove embedded objects and drop them on the floor for(var/obj/implanted_object in implants) - if(!istype(implanted_object,/obj/item/weapon/implant) && !istype(implanted_object,/obj/item/device/nif)) // We don't want to remove REAL implants. Just shrapnel etc. //VOREStation Edit - NIFs pls - implanted_object.loc = get_turf(src) - implants -= implanted_object + if(istype(implanted_object,/obj/item/weapon/implant) || istype(implanted_object,/obj/item/device/nif)) // We don't want to remove REAL implants. Just shrapnel etc. //VOREStation Edit - NIFs pls + continue + implanted_object.loc = get_turf(src) + implants -= implanted_object if(!owner.has_embedded_objects()) owner.clear_alert("embeddedobject") diff --git a/code/modules/resleeving/autoresleever.dm b/code/modules/resleeving/autoresleever.dm new file mode 100644 index 0000000000..bbef48b8ae --- /dev/null +++ b/code/modules/resleeving/autoresleever.dm @@ -0,0 +1,173 @@ +/obj/machinery/transhuman/autoresleever + name = "automatic resleever" + desc = "Uses advanced technology to detect when someone needs to be resleeved, and automatically prints and sleeves them into a new body. It even generates its own biomass!" + icon = 'icons/obj/machines/autoresleever.dmi' + icon_state = "autoresleever" + density = TRUE + anchored = TRUE + var/equip_body = FALSE //If true, this will spawn the person with equipment + var/default_job = USELESS_JOB //The job that will be assigned if equip_body is true and the ghost doesn't have a job + var/ghost_spawns = FALSE //If true, allows ghosts who haven't been spawned yet to spawn + var/vore_respawn = 15 MINUTES //The time to wait if you died from vore + var/respawn = 30 MINUTES //The time to wait if you didn't die from vore + var/spawn_slots = -1 //How many people can be spawned from this? If -1 it's unlimited + var/spawntype //The kind of mob that will be spawned, if set. + var/update_i = FALSE + +/obj/machinery/transhuman/autoresleever/update_icon() + . = ..() + if(stat) + icon_state = "autoresleever-o" + else + icon_state = "autoresleever" + +/obj/machinery/transhuman/autoresleever/power_change() + . = ..() + update_icon() + +/obj/machinery/transhuman/autoresleever/attack_ghost(mob/observer/dead/user as mob) + update_icon() + if(spawn_slots == 0) + to_chat(user, "There are no more respawn slots.") + return + if(user.mind) + if(user.mind.vore_death) + if(vore_respawn <= world.time - user.timeofdeath) + autoresleeve(user) + else + to_chat(user, "You must wait [((vore_respawn - (world.time - user.timeofdeath)) * 0.1) / 60] minutes to use \the [src].") + return + else if(respawn <= world.time - user.timeofdeath) + autoresleeve(user) + else + to_chat(user, "You must wait [((respawn - (world.time - user.timeofdeath)) * 0.1) /60] minutes to use \the [src].") + return + else if(spawntype) + if(tgui_alert(user, "This [src] spawns something special, would you like to play as it?", "Creachur", list("No","Yes")) == "Yes") + autoresleeve(user) + else if(ghost_spawns) + if(tgui_alert(user, "Would you like to be spawned here as your presently loaded character?", "Spawn here", list("No","Yes")) == "Yes") + autoresleeve(user) + else + to_chat(user, "You need to have been spawned in order to respawn here.") + +/obj/machinery/transhuman/autoresleever/attackby(var/mob/user) //Let's not let people mess with this. + update_icon() + if(istype(user,/mob/observer/dead)) + attack_ghost(user) + else + return + +/obj/machinery/transhuman/autoresleever/proc/autoresleeve(var/mob/observer/dead/ghost) + if(stat) + to_chat(ghost, "This machine is not functioning...") + return + if(!istype(ghost,/mob/observer/dead)) + return + + if(ghost.mind && ghost.mind.current && ghost.mind.current.stat != DEAD) + to_chat(ghost, "Your body is still alive, you cannot be resleeved.") + return + + var/client/ghost_client = ghost.client + + //Name matching is ugly but mind doesn't persist to look at. + var/charjob + var/datum/data/record/record_found + record_found = find_general_record("name",ghost_client.prefs.real_name) + + //Found their record, they were spawned previously + if(record_found) + charjob = record_found.fields["real_rank"] + else if(equip_body || ghost_spawns) + charjob = default_job + else + to_chat(ghost, "It appears as though your loaded character has not been spawned this round, or has quit the round. If you died as a different character, please load them, and try again.") + return + + //For logging later + var/player_key = ghost_client.key + var/picked_ckey = ghost_client.ckey + var/picked_slot = ghost_client.prefs.default_slot + + var/spawnloc = get_turf(src) + //Did we actually get a loc to spawn them? + if(!spawnloc) + to_chat(ghost, "Could not find a valid location to spawn your character.") + return + + if(spawntype) + var/spawnthing = new spawntype(spawnloc) + if(isliving(spawnthing)) + var/mob/living/L = spawnthing + L.key = player_key + L.ckey = picked_ckey + log_admin("[L.ckey]'s has been spawned as [L] via \the [src].") + message_admins("[L.ckey]'s has been spawned as [L] via \the [src].") + else + to_chat(ghost, "You can't play as a [spawnthing]...") + return + if(spawn_slots == -1) + return + else if(spawn_slots == 0) + return + else + spawn_slots -- + return + + if(tgui_alert(ghost, "Would you like to be resleeved?", "Resleeve", list("No","Yes")) == "No") + return + var/mob/living/carbon/human/new_character + new_character = new(spawnloc) + + //We were able to spawn them, right? + if(!new_character) + to_chat(ghost, "Something went wrong and spawning failed.") + return + + //Write the appearance and whatnot out to the character + ghost_client.prefs.copy_to(new_character) + if(new_character.dna) + new_character.dna.ResetUIFrom(new_character) + new_character.sync_organ_dna() + + new_character.key = player_key + + //Were they any particular special role? If so, copy. + if(new_character.mind) + new_character.mind.loaded_from_ckey = picked_ckey + new_character.mind.loaded_from_slot = picked_slot + + var/datum/antagonist/antag_data = get_antag_data(new_character.mind.special_role) + if(antag_data) + antag_data.add_antagonist(new_character.mind) + antag_data.place_mob(new_character) + + for(var/lang in ghost_client.prefs.alternate_languages) + var/datum/language/chosen_language = GLOB.all_languages[lang] + if(chosen_language) + if(is_lang_whitelisted(src,chosen_language) || (new_character.species && (chosen_language.name in new_character.species.secondary_langs))) + new_character.add_language(lang) + + //If desired, apply equipment. + if(equip_body) + if(charjob) + job_master.EquipRank(new_character, charjob, 1) + new_character.mind.assigned_role = charjob + new_character.mind.role_alt_title = job_master.GetPlayerAltTitle(new_character, charjob) + + //A redraw for good measure + new_character.regenerate_icons() + + new_character.update_transform() + + log_admin("[new_character.ckey]'s character [new_character.real_name] has been auto-resleeved.") + message_admins("[new_character.ckey]'s character [new_character.real_name] has been auto-resleeved.") + + if(spawn_slots == -1) + return + else if(spawn_slots == 0) + return + else + spawn_slots -- + return diff --git a/icons/obj/machines/autoresleever.dmi b/icons/obj/machines/autoresleever.dmi new file mode 100644 index 0000000000000000000000000000000000000000..1c1bb50706e88e11cc86391cc24594ae2ee52f2a GIT binary patch literal 2904 zcmV-e3#asnP)V=-0C=2r%CQQAFce1NIrk}kbgop}HH$BD_>)n9o*#U0Fm%4QQ&5=YybcXmPtfGRA_<4nOSTdZBB>%WDi{J`3Xp&T&8u4jfhR7+z;=ouH3=b!Y_O0kELL8*66&2Ij2=H$ zQ3)P@I!mFD=fd>26${m|sxxpOnVngZZ85)BfXN(k%g)`T6A6y|?J%1=b|K;+L|P&8 zWDbe#IkB;^F>z}v00j*N#j_D8bUa;;Y_yRr246*v^SwLvRxEDbhDf3UpV7PTDil;iLPNwfhocA{f6+MZ>+559 zc$l`fHlopJ+3#}C0NUEx7#<#`udgrQvzQ~W3J6;u3WDhKdA97?MC6}v%YhxdeD4R` z|7Jgbx$}e4pRWw=f3u&L@BM%u9_VM{IkFeube0sA2o+HEVg z9UmXB$fW@sediwlgp6gh#n#fxemd`R0^c+U!$ZO3&kn)%!45tgIt9S)!D|9-1B3m6 zKAm^Lx3Am0_tqhzty37GJOJAtybnLWA8z2?-Q65LdbA{=ty{P9>8GCpuyg0ml7bcY zi9{m2`p1I-j_nWLcToYCcWp#9LNqqCbLz$;tb2Vk8xA-L0f7V)L^v^Y(b0*a$f8Y$ zXXEzSaKKT~sT+^bw)Qf@D^;wJ!THIr1HoM0wXvcCitlw@XKZZDvvsel^=a?w4sf{q z8bCZ2CA6#_#a5{gHDjqJ-~{f6n>;|8C^^zzTO(~Gh;VkOBhbh7VW}oo$YgGQ8e6f5 z$D*E%%MZa#OR;p_w4Kfez@{?`4xaCAA3YZW~NbW6=4gcaMr4g zzYG?@O&%aentB?kr!i0nzm4CA6gI*ZD7H#uW|}7-d&HX!UH)QpcXtQw-Q>a9>uZ{Z zrfGpf_-)Gh00R69z|+sZAUitOqF5TL5kj#w);<7V|JIRxG15f6#N9%qiI&)H8gzWD zeE<}D(YK}1(YcnVpMAmGq&xg;N&H{y)MY6MxugSOU>ui2B?VlH4=5S}00Ob3Ad3}H3qlIq)8kTy zKs6LA;8IX_2=r`owu$j*sg%oMDGDft>$_*$j*=nJvu&pnT$NLuA4^d{FO>?_bq-sN;_?+*DKgmi8s8$Hqcf}zf6`NQ*LVeTnicVZy z>Ksttw47Kxf>i99L!hO#x|-n9=YW>hwpv4A28qNL7O8B!ro&5}15(*Iwy==MnrDGp zLjW#)4yZH)E*^$vrU_Yf(-p z<%g0NxG(XgD8Ne26>ZTL{Q&gc@&o730!tv$D$_@Tzo>#*($O#d9O;rtPzi1^urayk zz{AK!3slL;(a*d#kAD$M`3uZ1ebY2+PJ#drKlW?y+T{mjg0zxd~*u5{JXewr1p8T>Dr;nt$@y;Jr4f6d%uX4?G*9V?OBBj6GQWS96 zhHg|X1i-3|Ht!#Lm7DLlC+Nq!2!;6gox^;0&-ckj(_|*{Xqh^Mu5teE<6QOHu0Y3H z3Yfe1-)!D|9V=G1U^e6_G^NSp;~Y8k8aLf>cWFY4{5RaRmrN>2Jh~8Qk52t3a9>LS zJ-hnYas6)EJ62(u26~}DCY3DV*8o&i<y471ru!e#@>bm^p6 zO9AOjoS1rnl$<3jLSz<_G6!T*Nfzd2G4#s(;^ANXO7`v9$MVKTVhi(} z`f?P@G`%+}YCcTzWQNU$Z+HIILZF}o-UGPr32baYqM-5B{sh&M4eFvgtdPlkei}WTBNCq?m&%f#OVif6oHbW; zdBl;~86vYYfgoz}PfboRac&Z*qiIDm?yI4q&DSz}e##qn{_6XK zs0RNp0FX+=*xI`-AjOF@r-;WE`1wzNEP($j|9=4$F8C_j3l}W_0000