From 80758e437445e7d5c641caae324e7815f33c907d Mon Sep 17 00:00:00 2001 From: Casey Date: Fri, 25 Mar 2022 03:21:41 -0400 Subject: [PATCH] Auto-Resleeving --- 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 | 808 ++++++++++++++++-- maps/tether/tether-03-surface3.dmm | 11 + maps/tether/tether_areas.dm | 2 + vorestation.dme | 1 + 11 files changed, 962 insertions(+), 90 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 8e50e0437d..4d5d6f6c50 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 85f76d9aa0..5e3372c57b 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -486,9 +486,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