diff --git a/code/game/machinery/protean_reconstitutor.dm b/code/game/machinery/protean_reconstitutor.dm
new file mode 100644
index 0000000000..9ae0261d07
--- /dev/null
+++ b/code/game/machinery/protean_reconstitutor.dm
@@ -0,0 +1,305 @@
+/obj/machinery/protean_reconstitutor
+ name = "protean reconstitutor"
+ desc = "A complex machine that is most definitely not 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, optionally a 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/device/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/weapon/circuitboard/protean_reconstitutor
+
+/obj/machinery/protean_reconstitutor/Initialize()
+ component_parts = list()
+ component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
+ component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
+ component_parts += new /obj/item/weapon/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/weapon/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/weapon/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)
+ . += "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, "\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/device/mmi/digital/posibrain/nano))
+ var/obj/item/device/mmi/digital/posibrain/nano/NB = W
+ if(!NB.brainmob.client)
+ to_chat(user,"You cannot use an inactive positronic brain for this process.")
+ return
+ to_chat(user,"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,"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,"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,"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,"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(usr, "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 || (nanomass_reserve < nanomass_required))
+ //no brain, no orchestrator, and/or not enough goo
+ to_chat(user,"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("\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("\The [src] chirps, \"Warning, no positronic neural network activity detected! Recommend removing inactive core.\"")
+ return
+ else if(!processing_revive && protean_brain && protean_orchestrator && (nanomass_reserve >= nanomass_required))
+ //we're good, let's get recombobulating!
+ src.visible_message("[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))
+ if(protean_refactory) //if we have a refactory present, install it, otherwise they get a free replacement (for now; perhaps no free replacement but they can be made printable at the prosfab?)
+ src.visible_message("\The [src] chirps, \"Reinitializing 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
+ else
+ src.visible_message("\The [src] chirps, \"No refactory detected in storage, fabricating replacement...\"")
+ continue
+ if(istype(O,/obj/item/organ/internal/nano/orchestrator))
+ src.visible_message("\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("\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("\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_organ_dna()
+
+ 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
+
+ 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/device/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("\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("\The [src] chirps, \"Protean reconstitution cycle complete!\"")
+ to_chat(P,"You feel your sense of self expanding, spreading out to inhabit your new \'body\'. You feel... ALIVE!")
+ playsound(src, dingsound, 100, 1, -1) //soup's on!
+ P.loc = src.loc
+ processing_revive = FALSE
+ update_icon()
+ update_icon()
diff --git a/code/game/objects/items/weapons/circuitboards/machinery/research.dm b/code/game/objects/items/weapons/circuitboards/machinery/research.dm
index 380de53fd2..8f23291f8a 100644
--- a/code/game/objects/items/weapons/circuitboards/machinery/research.dm
+++ b/code/game/objects/items/weapons/circuitboards/machinery/research.dm
@@ -94,3 +94,14 @@
origin_tech = list(TECH_DATA = 4)
req_components = list(
/obj/item/stack/cable_coil = 15)
+
+/obj/item/weapon/circuitboard/protean_reconstitutor
+ name = T_BOARD("protean reconstitutor")
+ board_type = new /datum/frame/frame_types/machine
+ build_path = /obj/machinery/protean_reconstitutor
+ origin_tech = list(TECH_MAGNET = 5, TECH_BLUESPACE = 5, TECH_MATERIAL = 5, TECH_ENGINEERING = 5, TECH_DATA = 5)
+ req_components = list(
+ /obj/item/weapon/stock_parts/matter_bin = 1,
+ /obj/item/weapon/stock_parts/manipulator = 1,
+ /obj/item/weapon/stock_parts/console_screen = 1,
+ /obj/item/stack/cable_coil = 5)
diff --git a/code/modules/research/designs/circuits/circuits.dm b/code/modules/research/designs/circuits/circuits.dm
index 933cd26091..3dd78473fa 100644
--- a/code/modules/research/designs/circuits/circuits.dm
+++ b/code/modules/research/designs/circuits/circuits.dm
@@ -441,6 +441,13 @@ CIRCUITS BELOW
build_path = /obj/item/weapon/circuitboard/arf_generator
sort_string = "LAAAD"
+/datum/design/circuit/protean_reconstitutor
+ name = "protean reconstitutor"
+ id = "protean_recon"
+ req_tech = list(TECH_MAGNET = 5, TECH_BLUESPACE = 5, TECH_MATERIAL = 5, TECH_ENGINEERING = 5, TECH_DATA = 5)
+ build_path = /obj/item/weapon/circuitboard/protean_reconstitutor
+ sort_string = "LAAAE"
+
/datum/design/circuit/mecha
req_tech = list(TECH_DATA = 3)
diff --git a/icons/obj/protean_recon.dmi b/icons/obj/protean_recon.dmi
new file mode 100644
index 0000000000..9620e5f504
Binary files /dev/null and b/icons/obj/protean_recon.dmi differ
diff --git a/maps/stellar_delight/stellar_delight1.dmm b/maps/stellar_delight/stellar_delight1.dmm
index d5a56d023a..c19670a506 100644
--- a/maps/stellar_delight/stellar_delight1.dmm
+++ b/maps/stellar_delight/stellar_delight1.dmm
@@ -219,6 +219,9 @@
icon_state = "0-4"
},
/obj/item/weapon/storage/box/backup_kit,
+/obj/machinery/atmospherics/unary/vent_pump/on{
+ dir = 1
+ },
/turf/simulated/floor/tiled/steel_dirty,
/area/assembly/robotics)
"aw" = (
@@ -1029,6 +1032,8 @@
/obj/machinery/light{
dir = 1
},
+/obj/structure/table/standard,
+/obj/machinery/cell_charger,
/turf/simulated/floor/bluegrid,
/area/assembly/robotics)
"bX" = (
@@ -8532,6 +8537,9 @@
/obj/effect/floor_decal/steeldecal/steel_decals4{
dir = 6
},
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 6
+ },
/turf/simulated/floor/tiled/steel_dirty,
/area/assembly/robotics)
"rw" = (
@@ -8958,16 +8966,12 @@
/turf/simulated/floor,
/area/maintenance/security_port)
"sq" = (
-/obj/structure/table/standard,
-/obj/machinery/cell_charger,
/obj/structure/cable/green{
color = "#42038a";
icon_state = "4-8"
},
/obj/machinery/light,
-/obj/machinery/atmospherics/unary/vent_pump/on{
- dir = 1
- },
+/obj/machinery/protean_reconstitutor,
/turf/simulated/floor/tiled/steel,
/area/assembly/robotics)
"sr" = (
@@ -19761,7 +19765,7 @@
/area/medical/exam_room)
"Qq" = (
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 6
+ dir = 4
},
/turf/simulated/floor/tiled/steel,
/area/assembly/robotics)
diff --git a/maps/tether/tether-03-surface3.dmm b/maps/tether/tether-03-surface3.dmm
index 56f6f66e1b..6132ab32fb 100644
--- a/maps/tether/tether-03-surface3.dmm
+++ b/maps/tether/tether-03-surface3.dmm
@@ -34771,10 +34771,13 @@
/obj/machinery/alarm{
pixel_y = 30
},
+/obj/machinery/atmospherics/unary/vent_scrubber/on,
+/obj/effect/floor_decal/industrial/warning{
+ dir = 4
+ },
/turf/simulated/floor/tiled/steel_grid,
/area/rnd/robotics/resleeving)
"bky" = (
-/obj/machinery/atmospherics/unary/vent_scrubber/on,
/obj/machinery/button/windowtint{
id = "robo_resleeving";
pixel_x = 10;
@@ -34784,7 +34787,8 @@
pixel_x = -10;
pixel_y = 22
},
-/turf/simulated/floor/tiled/steel_grid,
+/obj/machinery/protean_reconstitutor,
+/turf/simulated/floor/tiled/dark,
/area/rnd/robotics/resleeving)
"bkz" = (
/obj/machinery/light{
@@ -34799,6 +34803,9 @@
/obj/structure/cable/green{
icon_state = "0-2"
},
+/obj/effect/floor_decal/industrial/warning{
+ dir = 8
+ },
/turf/simulated/floor/tiled/steel_grid,
/area/rnd/robotics/resleeving)
"bkA" = (
@@ -34889,30 +34896,36 @@
/turf/simulated/floor/tiled/steel_grid,
/area/rnd/robotics/resleeving)
"bkJ" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
- },
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
dir = 10
},
/obj/structure/cable/green{
icon_state = "4-8"
},
-/turf/simulated/floor/tiled/steel_grid,
-/area/rnd/robotics/resleeving)
-"bkK" = (
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 9
},
+/obj/effect/floor_decal/industrial/warning/corner{
+ dir = 4
+ },
+/turf/simulated/floor/tiled/steel_grid,
+/area/rnd/robotics/resleeving)
+"bkK" = (
/obj/structure/cable/green{
icon_state = "4-8"
},
+/obj/effect/floor_decal/industrial/warning{
+ dir = 1
+ },
/turf/simulated/floor/tiled/steel_grid,
/area/rnd/robotics/resleeving)
"bkL" = (
/obj/structure/cable/green{
icon_state = "1-8"
},
+/obj/effect/floor_decal/industrial/warning/corner{
+ dir = 1
+ },
/turf/simulated/floor/tiled/steel_grid,
/area/rnd/robotics/resleeving)
"bkM" = (
diff --git a/modular_chomp/code/modules/mob/living/carbon/human/species/station/protean/protean_organs.dm b/modular_chomp/code/modules/mob/living/carbon/human/species/station/protean/protean_organs.dm
index 2c1f76ef83..3393b6ccec 100644
--- a/modular_chomp/code/modules/mob/living/carbon/human/species/station/protean/protean_organs.dm
+++ b/modular_chomp/code/modules/mob/living/carbon/human/species/station/protean/protean_organs.dm
@@ -96,6 +96,14 @@
/mob/living/carbon/human/proc/self_diagnostics
)
+/obj/item/organ/internal/nano/orchestrator/robotize()
+ . = ..()
+ icon_state = "orchestrator"
+
+/obj/item/organ/internal/nano/orchestrator/mechassist()
+ . = ..()
+ icon_state = "orchestrator"
+
/obj/item/organ/internal/nano/refactory
name = "refactory module"
desc = "A miniature metal processing unit and nanite factory."
@@ -110,6 +118,14 @@
/mob/living/carbon/human/proc/reagent_purge
)
+/obj/item/organ/internal/nano/refactory/robotize()
+ . = ..()
+ icon_state = "refactory"
+
+/obj/item/organ/internal/nano/refactory/mechassist()
+ . = ..()
+ icon_state = "refactory"
+
/obj/item/organ/internal/nano/refactory/proc/get_stored_material(var/material)
if(status & ORGAN_DEAD)
return 0
diff --git a/vorestation.dme b/vorestation.dme
index 0f053ed0d4..ca8269f891 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -918,6 +918,7 @@
#include "code\game\machinery\pointdefense.dm"
#include "code\game\machinery\portable_turret.dm"
#include "code\game\machinery\portable_turret_vr.dm"
+#include "code\game\machinery\protean_reconstitutor.dm"
#include "code\game\machinery\recharger.dm"
#include "code\game\machinery\rechargestation.dm"
#include "code\game\machinery\requests_console.dm"