Files
CHOMPStation2/code/game/machinery/protean_reconstitutor.dm
CHOMPStation2StaffMirrorBot 75e167a92f [MIRROR] Dna, Bodyrecord, Xenochi Revive Refactor (#11038)
Co-authored-by: Will <7099514+Willburd@users.noreply.github.com>
Co-authored-by: Cameron Lennox <killer65311@gmail.com>
2025-06-11 03:41:08 +02:00

306 lines
14 KiB
Plaintext

/obj/machinery/protean_reconstitutor
name = "protean reconstitutor"
desc = "A complex machine that is most definitely <i>not</i> just a large tub into which one pours a large amount of untethered nanites, then adds a protean positronic brain and orchestrator, in order to reconstitute a disintegrated protean... it's complicated, really!"
description_info = "Use a protean positronic brain, orchestrator, refactory, and nanopaste to \'fill\' the machine, then interact with it once it's ready. Protean components can be retrieved using a wrench, but any nanopaste inserted will be converted, cannot be reclaimed, and will be lost if the machine is disassembled!"
icon = 'icons/obj/protean_recon.dmi'
icon_state = "recon-nopower"
var/state_base = "recon"
anchored = TRUE
density = TRUE
power_channel = EQUIP
use_power = USE_POWER_IDLE
idle_power_usage = 10
active_power_usage = 1000
var/processing_revive = FALSE
clicksound = 'sound/machines/buttonbeep.ogg' //standard initialization sound
var/dingsound = 'sound/machines/kitchen/microwave/microwave-end.ogg' //sound to play when the process is complete
var/buzzsound = 'sound/items/nif_tone_bad.ogg' //sound to play when we have to abort due to loss of posibrain client
//vars for basic functionality
var/obj/item/mmi/digital/posibrain/nano/protean_brain = null //only allow protean brains, no midround upgrades to bypass the whitelist!
var/obj/item/organ/internal/nano/orchestrator/protean_orchestrator = null //essential
var/obj/item/organ/internal/nano/refactory/protean_refactory = null //not essential, but nice to have; lets us transfer stored materials
var/nanomass_reserve = 0 //starting reserve - will be wiped if it's deconstructed!
var/nanotank_max = 300 //how much we can store at once, higher = better
var/nanomass_required = 150 //how much we need in order to make a new body, non-adjustable
var/paste_inefficiency = 5 //divisor to mech_repair value of paste added; higher = less effective; adv paste is +40 reserve at base, or +200 at max!
//time vars
var/base_cook_time = 150 SECONDS //how long to initially delay before starting the overall cooking cycle
var/per_organ_delay = 5 SECONDS //how long to delay the cycle per organ and per synch step (multiply by three to get time for all three organs), then add base cook time for total time
var/finalize_time = 135 SECONDS //finally, how long we need before popping them out of the tank
//component vars
circuit = /obj/item/circuitboard/protean_reconstitutor
/obj/machinery/protean_reconstitutor/Initialize(mapload)
component_parts = list()
component_parts += new /obj/item/stock_parts/matter_bin(src)
component_parts += new /obj/item/stock_parts/manipulator(src)
component_parts += new /obj/item/stock_parts/console_screen(src)
component_parts += new /obj/item/stack/cable_coil(src, 5)
RefreshParts()
. = ..()
/obj/machinery/protean_reconstitutor/RefreshParts()
//total paste storage cap (300 * the rating, straightforward)
var/store_rating = initial(nanotank_max)
for(var/obj/item/stock_parts/matter_bin/MB in component_parts)
store_rating = store_rating * MB.rating
nanotank_max = store_rating
//inefficiency of adding paste (amount of uses * (mech_repair / inefficiency)); most complex, good way to get good bang for your buck tho
var/paste_rating = initial(paste_inefficiency)
for(var/obj/item/stock_parts/manipulator/M in component_parts)
paste_rating = paste_rating - (M.rating - 1)
paste_inefficiency = paste_rating
..()
/obj/machinery/protean_reconstitutor/update_icon()
cut_overlays()
if(stat & (NOPOWER|BROKEN) || !anchored)
if(stat & BROKEN)
icon_state = "[state_base]-broken"
else
icon_state = "[state_base]-nopower"
return
icon_state = state_base
if(protean_brain)
add_overlay("[state_base]-brain")
if(protean_orchestrator)
add_overlay("[state_base]-orchestrator")
if(protean_refactory)
add_overlay("[state_base]-refactory")
if(nanomass_reserve >= nanomass_required)
add_overlay("[state_base]-tank_full")
/obj/machinery/protean_reconstitutor/examine()
. = ..()
if(protean_refactory)
. += "A protean refactory is present."
if(protean_orchestrator)
. += "A protean orchestrator is present."
if(protean_brain)
. += "It currently has a protean positronic brain."
if(!protean_brain.brainmob.client)
. += span_warning("The positronic brain appears to be inactive!")
. += "The readout shows that it has [nanomass_reserve] units of nanites ready for use. It requires [nanomass_required] per \'revive\' process, and has a maximum capacity of [nanotank_max] units."
/obj/machinery/protean_reconstitutor/attackby(obj/item/W as obj, mob/user as mob)
src.add_fingerprint(user)
if(processing_revive)
to_chat(user, span_notice("\The [src] is busy. Please wait for completion of previous operation."))
playsound(src, buzzsound, 100, 1, -1)
return
if(default_deconstruction_screwdriver(user, W))
return
if(default_deconstruction_crowbar(user, W))
return
if(default_part_replacement(user, W))
return
if(istype(W,/obj/item/mmi/digital/posibrain/nano))
var/obj/item/mmi/digital/posibrain/nano/NB = W
if(!NB.brainmob.client)
to_chat(user,span_warning("You cannot use an inactive positronic brain for this process."))
return
to_chat(user,span_notice("You slot \the [NB] into \the [src]."))
user.drop_from_inventory(NB)
NB.loc = src
protean_brain = NB
if(istype(W,/obj/item/organ/internal/nano/orchestrator))
to_chat(user,span_notice("You slot \the [W] into \the [src]."))
user.drop_from_inventory(W)
W.loc = src
protean_orchestrator = W
if(istype(W,/obj/item/organ/internal/nano/refactory))
to_chat(user,span_notice("You slot \the [W] into \the [src]."))
user.drop_from_inventory(W)
W.loc = src
protean_refactory = W
if(istype(W,/obj/item/stack/nanopaste))
var/obj/item/stack/nanopaste/NP = W
if(nanomass_reserve >= nanotank_max)
to_chat(user,span_notice("The tank is full!"))
return
nanomass_reserve += NP.amount * max(1,NP.mech_repair / paste_inefficiency)
if(nanomass_reserve > nanotank_max)
nanomass_reserve = nanotank_max
to_chat(user,span_notice("You fill \the [src] with paste from \the [NP]. The display now reads [nanomass_reserve]/[nanotank_max] units."))
qdel(NP)
if(W.has_tool_quality(TOOL_WRENCH))
if(protean_brain || protean_orchestrator || protean_refactory)
var/choice = tgui_input_list(user, "What component would you like to remove?", "Remove Component", list(protean_brain,protean_orchestrator,protean_refactory))
if(!choice) return
if(choice == protean_brain)
to_chat(user, "You fish \the [protean_brain] out of \the [src].")
protean_brain.forceMove(get_turf(src))
playsound(src, W.usesound, 50, 1)
src.protean_brain = null
if(choice == protean_refactory)
to_chat(user, "You fish \the [protean_refactory] out of \the [src].")
protean_refactory.forceMove(get_turf(src))
playsound(src, W.usesound, 50, 1)
src.protean_refactory = null
else if(choice == protean_orchestrator)
to_chat(user, "You fish \the [protean_orchestrator] out of \the [src].")
protean_orchestrator.forceMove(get_turf(src))
playsound(src, W.usesound, 50, 1)
src.protean_orchestrator = null
else
to_chat(user, "\The [src] does not have any protean components you can retrieve.")
update_icon()
..()
/obj/machinery/protean_reconstitutor/attack_hand(mob/user as mob)
if(!protean_brain || !protean_orchestrator || !protean_refactory || (nanomass_reserve < nanomass_required))
//no brain, no orchestrator, and/or not enough goo
to_chat(user,span_warning("Essential components missing, or insufficient materials available!"))
playsound(src, buzzsound, 100, 1, -1)
update_icon()
return
if(processing_revive)
//we're currently processing a patient, chill out!
src.visible_message(span_notice("\The [src] chirps, \"Reconstitution cycle currently in progress, please wait!\""))
playsound(src, buzzsound, 100, 1, -1)
return
if(!protean_brain.brainmob.client)
src.visible_message(span_warning("\The [src] chirps, \"Warning, no positronic neural network activity detected! Recommend removing inactive core.\""))
return
else if(!processing_revive && protean_brain && protean_orchestrator && protean_refactory && (nanomass_reserve >= nanomass_required))
//we're good, let's get recombobulating!
src.visible_message(span_notice("[user] initializes \the [src]. It chirps, \"Please stand by, synchronizing components... estimated time to completion: five minutes.\""))
processing_revive = TRUE
power_change()
if(prob(2))
playsound(src, 'sound/machines/blender.ogg', 50, 1)
else
playsound(src, clicksound, 50, 1)
nanomass_reserve -= nanomass_required
sleep(base_cook_time)
var/mob/living/carbon/human/protean/P = new /mob/living/carbon/human/protean
var/mats_cached
var/list/materials_cache
P.loc = src
P.name = "Unfinished Protean"
P.real_name = "Unfinished Protean"
for(var/organ in P.internal_organs_by_name)
sleep(per_organ_delay)
var/obj/item/O = P.internal_organs_by_name[organ]
if(istype(O,/obj/item/organ/internal/nano/refactory))
src.visible_message(span_notice("\The [src] chirps, \"Initializing refactory...\""))
P.internal_organs_by_name.Remove(O)
P.contents.Remove(O)
qdel(O)
P.internal_organs_by_name.Add(list(O_FACT = protean_refactory))
P.internal_organs.Add(protean_refactory)
//cache our mats otherwise they get wiped by the revive
materials_cache = protean_refactory.materials.Copy()
mats_cached = TRUE
protean_refactory.loc = P
if(istype(O,/obj/item/organ/internal/nano/orchestrator))
src.visible_message(span_notice("\The [src] chirps, \"Linking nanoswarm to orchestrator...\""))
P.internal_organs_by_name.Remove(O)
P.internal_organs.Remove(O)
P.contents.Remove(O)
qdel(O)
P.internal_organs_by_name.Add(list(O_ORCH = protean_orchestrator))
P.internal_organs.Add(protean_orchestrator)
protean_orchestrator.loc = P
if(istype(O,/obj/item/organ/internal/mmi_holder/posibrain/nano))
src.visible_message(span_notice("\The [src] chirps, \"Synchronizing positronic neural architecture...\""))
//on the offchance our client blipped before getting to this step, abort, schloop the organs back into the machine, dissolve the body, and refund the nanos
if(!protean_brain.brainmob.client)
src.visible_message(span_warning("\The [src] buzzes, \"No positronic neural activity detected! Aborting cycle!\""))
playsound(src, buzzsound, 100, 1, -1)
processing_revive = FALSE
qdel(P)
nanomass_reserve += nanomass_required
update_icon()
return
var/obj/item/organ/internal/mmi_holder/posibrain/nano/BR = O
BR.stored_mmi = null //toss the dummy...
BR.contents.Cut()
BR.stored_mmi = protean_brain //...and implant the salvaged mmi in its place
BR.contents.Add(protean_brain)
var/client/posibrain_client = protean_brain.brainmob.client
var/picked_ckey = posibrain_client.ckey
var/picked_slot = posibrain_client.prefs.default_slot
var/charjob
var/datum/data/record/record_found
record_found = find_general_record("name",posibrain_client.prefs.real_name)
if(record_found)
charjob = record_found.fields["real_rank"]
else
return
if(P.dna)
P.dna.ResetUIFrom(P)
P.sync_dna_traits(FALSE) // Traitgenes Sync traits to genetics if needed
P.sync_organ_dna()
P.initialize_vessel()
if(P.mind)
P.mind.loaded_from_ckey = picked_ckey
P.mind.loaded_from_slot = picked_slot
var/datum/antagonist/antag_data = get_antag_data(P.mind.special_role)
if(antag_data)
antag_data.add_antagonist(P.mind)
antag_data.place_mob(P)
P.mind.assigned_role = charjob
P.mind.role_alt_title = job_master.GetPlayerAltTitle(P, charjob)
//no need to be particularly thorough about language handover, we can safely assume that they were allowed to have it if they had it to begin with
P.languages.Cut()
P.languages = protean_brain.brainmob.languages.Copy()
for(var/key in posibrain_client.prefs.language_custom_keys)
if(posibrain_client.prefs.language_custom_keys[key])
var/datum/language/keylang = GLOB.all_languages[posibrain_client.prefs.language_custom_keys[key]]
if(keylang)
P.language_keys[key] = keylang
if(posibrain_client.prefs.preferred_language)
var/datum/language/def_lang = GLOB.all_languages[posibrain_client.prefs.preferred_language]
if(def_lang)
P.default_language = def_lang
SEND_SIGNAL(P, COMSIG_HUMAN_DNA_FINALIZED)
protean_brain.brainmob.mind.transfer_to(P)
protean_brain.loc = BR
protean_refactory = null
protean_brain = null
protean_orchestrator = null
sleep(finalize_time) //let 'em cook a tiny bit longer
P.revive()
P.apply_vore_prefs()
//run a little revive, load their prefs, and boot a new NIF on them for the finishing touches and cleanup... (yes, we need to initialize a new NIF, they don't get one from the revive process)
//using revive is honestly a bit overkill since it kinda deletes-and-replaces most of the guts anyway (hence the cache and restore of refactory contents; otherwise they get wiped!), but it also ensures the new protean comes out in their "base form" as well as hopefully cleaning up any loose ends in the resurrection process
var/obj/item/nif/protean/new_nif = new()
new_nif.quick_implant(P)
//revive complete, now restore the cached mats (if we had any)
if(mats_cached == TRUE)
src.visible_message(span_notice("\The [src] chirps, \"Reindexing archived refactory materials storage.\""))
for(var/organ in P.internal_organs_by_name)
var/obj/item/O = P.internal_organs_by_name[organ]
if(istype(O,/obj/item/organ/internal/nano/refactory))
var/obj/item/organ/internal/nano/refactory/RF = O
RF.materials = materials_cache.Copy()
materials_cache.Cut()
mats_cached = FALSE
//finally... drop them in front of the machine
src.visible_message(span_notice("\The [src] chirps, \"Protean reconstitution cycle complete!\""))
to_chat(P,span_notice("You feel your sense of self expanding, spreading out to inhabit your new \'body\'. You feel... <i><b>ALIVE!</b></i>"))
playsound(src, dingsound, 100, 1, -1) //soup's on!
P.loc = src.loc
processing_revive = FALSE
update_icon()
update_icon()