diff --git a/_maps/RandomRuins/SpaceRuins/cloning_facility.dmm b/_maps/RandomRuins/SpaceRuins/cloning_facility.dmm
new file mode 100644
index 0000000000..87f890e0d5
--- /dev/null
+++ b/_maps/RandomRuins/SpaceRuins/cloning_facility.dmm
@@ -0,0 +1,503 @@
+//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
+"a" = (
+/turf/template_noop,
+/area/template_noop)
+"b" = (
+/turf/closed/wall/r_wall,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"c" = (
+/obj/structure/grille,
+/obj/structure/window/reinforced/fulltile,
+/turf/open/floor/plasteel,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"d" = (
+/turf/closed/wall/r_wall/rust,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"e" = (
+/obj/machinery/defibrillator_mount/loaded,
+/turf/closed/wall/r_wall,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"f" = (
+/obj/structure/grille,
+/obj/structure/window/reinforced/fulltile,
+/turf/open/floor/plasteel/airless,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"g" = (
+/obj/structure/table,
+/obj/item/device/flashlight/lamp,
+/obj/effect/decal/cleanable/cobweb,
+/turf/open/floor/plasteel/whiteblue,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"h" = (
+/obj/structure/table,
+/obj/item/pen,
+/obj/item/paper/fluff/ruins/exp_cloning/log,
+/turf/open/floor/plasteel/whiteblue,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"i" = (
+/obj/machinery/dna_scannernew,
+/turf/open/floor/plasteel/whiteblue,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"j" = (
+/obj/machinery/computer/prototype_cloning,
+/obj/machinery/light{
+ dir = 1
+ },
+/obj/item/paper/fluff/ruins/exp_cloning/manual,
+/turf/open/floor/plasteel/whiteblue,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"k" = (
+/obj/machinery/clonepod/experimental,
+/turf/open/floor/plasteel/whiteblue,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"l" = (
+/obj/effect/decal/cleanable/vomit/old,
+/turf/open/floor/plasteel/whiteblue,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"m" = (
+/obj/effect/decal/cleanable/cobweb/cobweb2,
+/turf/open/floor/plasteel/whiteblue,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"n" = (
+/obj/structure/sign/nanotrasen,
+/turf/closed/wall,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"o" = (
+/obj/machinery/vending/snack/teal,
+/turf/open/floor/plasteel/airless/floorgrime,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"p" = (
+/turf/open/floor/plasteel/airless/floorgrime,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"q" = (
+/obj/structure/sign/directions/science{
+ dir = 8
+ },
+/turf/closed/wall/r_wall,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"r" = (
+/obj/effect/decal/remains/human,
+/obj/effect/decal/cleanable/blood/old,
+/turf/open/floor/plasteel,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"s" = (
+/obj/machinery/iv_drip,
+/turf/open/floor/plasteel,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"t" = (
+/obj/machinery/light{
+ dir = 4
+ },
+/obj/structure/bed,
+/obj/item/bedsheet/medical,
+/turf/open/floor/plasteel,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"u" = (
+/obj/machinery/light{
+ dir = 8
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/turf/open/floor/plasteel/white,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"v" = (
+/turf/open/floor/plasteel/whiteblue/corner{
+ dir = 4
+ },
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"w" = (
+/obj/structure/chair/office{
+ dir = 1
+ },
+/turf/open/floor/plasteel/whiteblue/side{
+ dir = 1
+ },
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"x" = (
+/turf/open/floor/plasteel/whiteblue/side{
+ dir = 1
+ },
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"y" = (
+/obj/structure/chair/office{
+ dir = 1
+ },
+/turf/open/floor/plasteel/whiteblue,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"z" = (
+/obj/machinery/light{
+ dir = 4
+ },
+/turf/open/floor/plasteel/whiteblue/corner{
+ dir = 1
+ },
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"A" = (
+/obj/structure/sign/departments/science,
+/turf/closed/wall,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"B" = (
+/turf/open/floor/plasteel/airless,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"C" = (
+/turf/open/floor/plating/airless,
+/area/space/nearstation)
+"D" = (
+/obj/structure/chair/comfy{
+ dir = 8
+ },
+/turf/open/floor/plasteel,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"E" = (
+/turf/open/floor/plasteel,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"F" = (
+/obj/machinery/door/airlock/research/glass,
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/effect/turf_decal/stripes/line,
+/turf/open/floor/plasteel,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"G" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/effect/turf_decal/stripes/line,
+/turf/open/floor/plasteel,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"H" = (
+/obj/machinery/door/airlock/research/glass,
+/obj/effect/turf_decal/stripes/line,
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/turf/open/floor/plasteel,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"I" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/turf/open/floor/plasteel/white,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"J" = (
+/turf/open/floor/plasteel/white,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"K" = (
+/obj/machinery/door/airlock/research/glass,
+/turf/open/floor/plasteel/airless,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"L" = (
+/turf/open/floor/plating/airless{
+ icon_state = "platingdmg1"
+ },
+/area/space/nearstation)
+"M" = (
+/obj/structure/fluff/broken_flooring{
+ name = "broken plating";
+ icon_state = "plating";
+ dir = 8
+ },
+/turf/template_noop,
+/area/space/nearstation)
+"N" = (
+/obj/item/book/random/triple,
+/turf/open/floor/plasteel,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"O" = (
+/obj/machinery/light{
+ dir = 4
+ },
+/obj/structure/bookcase/random/fiction,
+/turf/open/floor/plasteel,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"P" = (
+/obj/structure/table/glass,
+/obj/machinery/light,
+/obj/structure/bedsheetbin,
+/turf/open/floor/plasteel/white,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"Q" = (
+/obj/structure/table/glass,
+/turf/open/floor/plasteel/white,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"R" = (
+/obj/structure/table/glass,
+/obj/item/storage/firstaid/regular,
+/obj/item/device/healthanalyzer{
+ desc = "A prototype hand-held body scanner able to distinguish vital signs of the subject.";
+ name = "prototype health analyzer"
+ },
+/turf/open/floor/plasteel/white,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"S" = (
+/obj/structure/table/glass,
+/obj/item/storage/box/syringes,
+/turf/open/floor/plasteel/white,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"T" = (
+/turf/closed/wall,
+/area/ruin/space/has_grav/powered/ancient_shuttle)
+"U" = (
+/turf/open/floor/plating/airless{
+ icon_state = "platingdmg2"
+ },
+/area/space/nearstation)
+"V" = (
+/turf/closed/wall/r_wall/rust,
+/area/space/nearstation)
+
+(1,1,1) = {"
+a
+a
+a
+a
+a
+a
+a
+a
+a
+"}
+(2,1,1) = {"
+a
+a
+a
+a
+a
+a
+a
+a
+a
+"}
+(3,1,1) = {"
+a
+a
+c
+c
+c
+c
+c
+a
+a
+"}
+(4,1,1) = {"
+a
+a
+c
+r
+D
+N
+c
+a
+a
+"}
+(5,1,1) = {"
+a
+a
+c
+s
+E
+E
+c
+a
+a
+"}
+(6,1,1) = {"
+a
+a
+d
+t
+E
+O
+d
+a
+a
+"}
+(7,1,1) = {"
+a
+a
+d
+b
+F
+d
+d
+a
+a
+"}
+(8,1,1) = {"
+a
+a
+a
+b
+G
+b
+a
+a
+a
+"}
+(9,1,1) = {"
+a
+a
+d
+d
+H
+b
+b
+a
+a
+"}
+(10,1,1) = {"
+a
+b
+b
+u
+I
+I
+c
+a
+a
+"}
+(11,1,1) = {"
+a
+c
+g
+v
+J
+J
+c
+a
+a
+"}
+(12,1,1) = {"
+a
+c
+h
+w
+J
+J
+d
+a
+a
+"}
+(13,1,1) = {"
+a
+d
+i
+x
+J
+P
+b
+a
+a
+"}
+(14,1,1) = {"
+a
+b
+j
+y
+J
+Q
+c
+a
+a
+"}
+(15,1,1) = {"
+a
+b
+k
+x
+J
+R
+c
+a
+a
+"}
+(16,1,1) = {"
+a
+e
+l
+x
+J
+S
+d
+a
+a
+"}
+(17,1,1) = {"
+a
+d
+m
+z
+J
+J
+d
+a
+a
+"}
+(18,1,1) = {"
+a
+d
+n
+A
+K
+T
+b
+a
+a
+"}
+(19,1,1) = {"
+a
+f
+o
+B
+p
+C
+V
+a
+a
+"}
+(20,1,1) = {"
+a
+f
+p
+p
+C
+U
+M
+a
+a
+"}
+(21,1,1) = {"
+a
+d
+q
+C
+L
+M
+a
+a
+a
+"}
+(22,1,1) = {"
+a
+a
+b
+f
+M
+a
+a
+a
+a
+"}
+(23,1,1) = {"
+a
+a
+a
+a
+a
+a
+a
+a
+a
+"}
diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm
index 44fcce6253..bb07582dae 100644
--- a/code/__DEFINES/DNA.dm
+++ b/code/__DEFINES/DNA.dm
@@ -82,19 +82,18 @@
#define NOBLOOD 6
#define NOTRANSSTING 7
#define MUTCOLORS_PARTSONLY 8 //Used if we want the mutant colour to be only used by mutant bodyparts. Don't combine this with MUTCOLORS, or it will be useless.
-#define NOCRITDAMAGE 9
-#define NOZOMBIE 10
-#define DIGITIGRADE 11 //Uses weird leg sprites. Optional for Lizards, required for ashwalkers. Don't give it to other races unless you make sprites for this (see human_parts_greyscale.dmi)
-#define NO_UNDERWEAR 12
-#define NOLIVER 13
-#define NOSTOMACH 14
-#define NO_DNA_COPY 15
-#define DRINKSBLOOD 16
-#define SPECIES_ORGANIC 17
-#define SPECIES_INORGANIC 18
-#define SPECIES_UNDEAD 19
-#define SPECIES_ROBOTIC 20
-#define NOEYES 21
+#define NOZOMBIE 9
+#define DIGITIGRADE 10 //Uses weird leg sprites. Optional for Lizards, required for ashwalkers. Don't give it to other races unless you make sprites for this (see human_parts_greyscale.dmi)
+#define NO_UNDERWEAR 11
+#define NOLIVER 12
+#define NOSTOMACH 13
+#define NO_DNA_COPY 14
+#define DRINKSBLOOD 15
+#define SPECIES_ORGANIC 16
+#define SPECIES_INORGANIC 17
+#define SPECIES_UNDEAD 18
+#define SPECIES_ROBOTIC 19
+#define NOEYES 20
#define ORGAN_SLOT_BRAIN "brain"
#define ORGAN_SLOT_APPENDIX "appendix"
diff --git a/code/__DEFINES/radio.dm b/code/__DEFINES/radio.dm
index 97935d58b7..897d107939 100644
--- a/code/__DEFINES/radio.dm
+++ b/code/__DEFINES/radio.dm
@@ -1,55 +1,55 @@
-// Radios use a large variety of predefined frequencies.
-
-#define MIN_FREE_FREQ 1201 // -------------------------------------------------
-// Frequencies are always odd numbers and range from 1201 to 1599.
-
-#define FREQ_SYNDICATE 1213 // Nuke op comms frequency, dark brown
-#define FREQ_CTF_RED 1215 // CTF red team comms frequency, red
-#define FREQ_CTF_BLUE 1217 // CTF blue team comms frequency, blue
-#define FREQ_CENTCOM 1337 // CentCom comms frequency, gray
-#define FREQ_SUPPLY 1347 // Supply comms frequency, light brown
-#define FREQ_SERVICE 1349 // Service comms frequency, green
-#define FREQ_SCIENCE 1351 // Science comms frequency, plum
-#define FREQ_COMMAND 1353 // Command comms frequency, gold
-#define FREQ_MEDICAL 1355 // Medical comms frequency, soft blue
-#define FREQ_ENGINEERING 1357 // Engineering comms frequency, orange
-#define FREQ_SECURITY 1359 // Security comms frequency, red
-
-#define FREQ_STATUS_DISPLAYS 1435
-#define FREQ_ATMOS_ALARMS 1437 // air alarms <-> alert computers
-#define FREQ_ATMOS_CONTROL 1439 // air alarms <-> vents and scrubbers
-
-#define MIN_FREQ 1441 // ------------------------------------------------------
-// Only the 1441 to 1489 range is freely available for general conversation.
-// This represents 1/8th of the available spectrum.
-
-#define FREQ_ATMOS_STORAGE 1441
-#define FREQ_NAV_BEACON 1445
-#define FREQ_AI_PRIVATE 1447 // AI private comms frequency, magenta
-#define FREQ_PRESSURE_PLATE 1447
-#define FREQ_AIRLOCK_CONTROL 1449
-#define FREQ_ELECTROPACK 1449
-#define FREQ_MAGNETS 1449
-#define FREQ_LOCATOR_IMPLANT 1451
-#define FREQ_SIGNALER 1457 // the default for new signalers
-#define FREQ_COMMON 1459 // Common comms frequency, dark green
-
-#define MAX_FREQ 1489 // ------------------------------------------------------
-
-#define MAX_FREE_FREQ 1599 // -------------------------------------------------
-
-// Transmission types.
-#define TRANSMISSION_WIRE 0 // some sort of wired connection, not used
-#define TRANSMISSION_RADIO 1 // electromagnetic radiation (default)
-#define TRANSMISSION_SUBSPACE 2 // subspace transmission (headsets only)
-#define TRANSMISSION_SUPERSPACE 3 // reaches independent (CentCom) radios only
-
-// Filter types, used as an optimization to avoid unnecessary proc calls.
-#define RADIO_TO_AIRALARM "to_airalarm"
-#define RADIO_FROM_AIRALARM "from_airalarm"
-#define RADIO_SIGNALER "signaler"
-#define RADIO_ATMOSIA "atmosia"
-#define RADIO_AIRLOCK "airlock"
-#define RADIO_MAGNETS "magnets"
-
-#define DEFAULT_SIGNALER_CODE 30
+// Radios use a large variety of predefined frequencies.
+
+#define MIN_FREE_FREQ 1201 // -------------------------------------------------
+// Frequencies are always odd numbers and range from 1201 to 1599.
+
+#define FREQ_SYNDICATE 1213 // Nuke op comms frequency, dark brown
+#define FREQ_CTF_RED 1215 // CTF red team comms frequency, red
+#define FREQ_CTF_BLUE 1217 // CTF blue team comms frequency, blue
+#define FREQ_CENTCOM 1337 // CentCom comms frequency, gray
+#define FREQ_SUPPLY 1347 // Supply comms frequency, light brown
+#define FREQ_SERVICE 1349 // Service comms frequency, green
+#define FREQ_SCIENCE 1351 // Science comms frequency, plum
+#define FREQ_COMMAND 1353 // Command comms frequency, gold
+#define FREQ_MEDICAL 1355 // Medical comms frequency, soft blue
+#define FREQ_ENGINEERING 1357 // Engineering comms frequency, orange
+#define FREQ_SECURITY 1359 // Security comms frequency, red
+
+#define FREQ_STATUS_DISPLAYS 1435
+#define FREQ_ATMOS_ALARMS 1437 // air alarms <-> alert computers
+#define FREQ_ATMOS_CONTROL 1439 // air alarms <-> vents and scrubbers
+
+#define MIN_FREQ 1441 // ------------------------------------------------------
+// Only the 1441 to 1489 range is freely available for general conversation.
+// This represents 1/8th of the available spectrum.
+
+#define FREQ_ATMOS_STORAGE 1441
+#define FREQ_NAV_BEACON 1445
+#define FREQ_AI_PRIVATE 1447 // AI private comms frequency, magenta
+#define FREQ_PRESSURE_PLATE 1447
+#define FREQ_AIRLOCK_CONTROL 1449
+#define FREQ_ELECTROPACK 1449
+#define FREQ_MAGNETS 1449
+#define FREQ_LOCATOR_IMPLANT 1451
+#define FREQ_SIGNALER 1457 // the default for new signalers
+#define FREQ_COMMON 1459 // Common comms frequency, dark green
+
+#define MAX_FREQ 1489 // ------------------------------------------------------
+
+#define MAX_FREE_FREQ 1599 // -------------------------------------------------
+
+// Transmission types.
+#define TRANSMISSION_WIRE 0 // some sort of wired connection, not used
+#define TRANSMISSION_RADIO 1 // electromagnetic radiation (default)
+#define TRANSMISSION_SUBSPACE 2 // subspace transmission (headsets only)
+#define TRANSMISSION_SUPERSPACE 3 // reaches independent (CentCom) radios only
+
+// Filter types, used as an optimization to avoid unnecessary proc calls.
+#define RADIO_TO_AIRALARM "to_airalarm"
+#define RADIO_FROM_AIRALARM "from_airalarm"
+#define RADIO_SIGNALER "signaler"
+#define RADIO_ATMOSIA "atmosia"
+#define RADIO_AIRLOCK "airlock"
+#define RADIO_MAGNETS "magnets"
+
+#define DEFAULT_SIGNALER_CODE 30
diff --git a/code/__DEFINES/sight.dm b/code/__DEFINES/sight.dm
index cfce95a65f..e307e8dd69 100644
--- a/code/__DEFINES/sight.dm
+++ b/code/__DEFINES/sight.dm
@@ -1,30 +1,30 @@
-#define SEE_INVISIBLE_MINIMUM 5
-
-#define INVISIBILITY_LIGHTING 20
-
-#define SEE_INVISIBLE_LIVING 25
-
-//#define SEE_INVISIBLE_LEVEL_ONE 35 //currently unused
-//#define INVISIBILITY_LEVEL_ONE 35 //currently unused
-
-//#define SEE_INVISIBLE_LEVEL_TWO 45 //currently unused
-//#define INVISIBILITY_LEVEL_TWO 45 //currently unused
-
-#define INVISIBILITY_OBSERVER 60
-#define SEE_INVISIBLE_OBSERVER 60
-
-#define INVISIBILITY_MAXIMUM 100 //the maximum allowed for "real" objects
-
-#define INVISIBILITY_ABSTRACT 101 //only used for abstract objects (e.g. spacevine_controller), things that are not really there.
-
-#define BORGMESON 1
-#define BORGTHERM 2
-#define BORGXRAY 4
-#define BORGMATERIAL 8
-
-//for clothing visor toggles, these determine which vars to toggle
-#define VISOR_FLASHPROTECT 1
-#define VISOR_TINT 2
-#define VISOR_VISIONFLAGS 4 //all following flags only matter for glasses
-#define VISOR_DARKNESSVIEW 8
-#define VISOR_INVISVIEW 16
+#define SEE_INVISIBLE_MINIMUM 5
+
+#define INVISIBILITY_LIGHTING 20
+
+#define SEE_INVISIBLE_LIVING 25
+
+//#define SEE_INVISIBLE_LEVEL_ONE 35 //currently unused
+//#define INVISIBILITY_LEVEL_ONE 35 //currently unused
+
+//#define SEE_INVISIBLE_LEVEL_TWO 45 //currently unused
+//#define INVISIBILITY_LEVEL_TWO 45 //currently unused
+
+#define INVISIBILITY_OBSERVER 60
+#define SEE_INVISIBLE_OBSERVER 60
+
+#define INVISIBILITY_MAXIMUM 100 //the maximum allowed for "real" objects
+
+#define INVISIBILITY_ABSTRACT 101 //only used for abstract objects (e.g. spacevine_controller), things that are not really there.
+
+#define BORGMESON 1
+#define BORGTHERM 2
+#define BORGXRAY 4
+#define BORGMATERIAL 8
+
+//for clothing visor toggles, these determine which vars to toggle
+#define VISOR_FLASHPROTECT 1
+#define VISOR_TINT 2
+#define VISOR_VISIONFLAGS 4 //all following flags only matter for glasses
+#define VISOR_DARKNESSVIEW 8
+#define VISOR_INVISVIEW 16
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index 6bc504d48a..854ea01114 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -21,6 +21,7 @@
#define TRAIT_SLEEPIMMUNE "sleep_immunity"
#define TRAIT_PUSHIMMUNE "push_immunity"
#define TRAIT_SHOCKIMMUNE "shock_immunity"
+#define TRAIT_STABLEHEART "stable_heart"
#define TRAIT_RESISTHEAT "resist_heat"
#define TRAIT_RESISTCOLD "resist_cold"
#define TRAIT_RESISTHIGHPRESSURE "resist_high_pressure"
@@ -38,6 +39,7 @@
#define TRAIT_NOBREATH "no_breath"
#define TRAIT_ANTIMAGIC "anti_magic"
#define TRAIT_HOLY "holy"
+#define TRAIT_NOCRITDAMAGE "no_crit"
#define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance"
#define TRAIT_AGEUSIA "ageusia"
@@ -71,4 +73,4 @@
#define TRAIT_HULK "hulk"
#define STASIS_MUTE "stasis"
#define GENETICS_SPELL "genetics_spell"
-#define EYES_COVERED "eyes_covered"
\ No newline at end of file
+#define EYES_COVERED "eyes_covered"
diff --git a/code/datums/ruins/space.dm b/code/datums/ruins/space.dm
index eed23e0711..eea4088905 100644
--- a/code/datums/ruins/space.dm
+++ b/code/datums/ruins/space.dm
@@ -280,4 +280,10 @@
suffix = "mrow_thats_right.dmm"
name = "Feline-Human Combination Den"
description = "With heated debates over the legality of the catperson and their status in the workforce, there's always a place for the blackmarket to slip in for some cash. Whether the results \
- are morally sound or not is another issue entirely."
\ No newline at end of file
+ are morally sound or not is another issue entirely."
+
+/datum/map_template/ruin/space/cloning_facility
+ id = "cloning_facility"
+ suffix = "cloning_facility.dmm"
+ name = "Ancient Cloning Lab"
+ description = "An experimental cloning lab snapped off from an ancient ship. The cloner model inside lacks many modern functionalities and security measures."
\ No newline at end of file
diff --git a/code/game/area/areas/ruins/space.dm b/code/game/area/areas/ruins/space.dm
index 0f57c0ce3b..13b9905874 100644
--- a/code/game/area/areas/ruins/space.dm
+++ b/code/game/area/areas/ruins/space.dm
@@ -466,4 +466,8 @@
/area/ruin/space/has_grav/powered/scp_294
name = "Abandoned SCP-294 Containment"
+ icon_state = "yellow"
+
+/area/ruin/space/has_grav/powered/ancient_shuttle
+ name = "Ancient Shuttle"
icon_state = "yellow"
\ No newline at end of file
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index b46706ce9f..048cac8326 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -29,6 +29,7 @@
var/datum/mind/clonemind
var/grab_ghost_when = CLONER_MATURE_CLONE
+ var/internal_radio = TRUE
var/obj/item/device/radio/radio
var/radio_key = /obj/item/device/encryptionkey/headset_med
var/radio_channel = "Medical"
@@ -38,24 +39,17 @@
var/list/unattached_flesh
var/flesh_number = 0
- // The "brine" is the reagents that are automatically added in small
- // amounts to the occupant.
- var/static/list/brine_types = list(
- "salbutamol", // anti-oxyloss
- "bicaridine", // NOBREATHE species take brute in crit
- "corazone", // prevents cardiac arrest and liver failure damage
- "mimesbane", // stops them gasping from lack of air.
- "mutetoxin") // stops them from killing themselves BY DEATHWHISPERING INSIDE A CLONE POD NICE JOB BREAKING IT HERO
/obj/machinery/clonepod/Initialize()
. = ..()
countdown = new(src)
- radio = new(src)
- radio.keyslot = new radio_key
- radio.subspace_transmission = TRUE
- radio.canhear_range = 0
- radio.recalculateChannels()
+ if(internal_radio)
+ radio = new(src)
+ radio.keyslot = new radio_key
+ radio.subspace_transmission = TRUE
+ radio.canhear_range = 0
+ radio.recalculateChannels()
/obj/machinery/clonepod/Destroy()
go_out()
@@ -116,7 +110,7 @@
/obj/machinery/clonepod/return_air()
// We want to simulate the clone not being in contact with
// the atmosphere, so we'll put them in a constant pressure
- // nitrogen. They'll breathe through the chemicals we pump into them.
+ // nitrogen. They don't need to breathe while cloning anyway.
var/static/datum/gas_mixture/immutable/cloner/GM //global so that there's only one instance made for all cloning pods
if(!GM)
GM = new
@@ -184,7 +178,11 @@
icon_state = "pod_1"
//Get the clone body ready
maim_clone(H)
- check_brine() // put in chemicals NOW to stop death via cardiac arrest
+ H.add_trait(TRAIT_STABLEHEART, "cloning")
+ H.add_trait(TRAIT_EMOTEMUTE, "cloning")
+ H.add_trait(TRAIT_MUTE, "cloning")
+ H.add_trait(TRAIT_NOBREATH, "cloning")
+ H.add_trait(TRAIT_NOCRITDAMAGE, "cloning")
H.Unconscious(80)
clonemind.transfer_to(H)
@@ -219,8 +217,9 @@
else if(mob_occupant && (mob_occupant.loc == src))
if((mob_occupant.stat == DEAD) || (mob_occupant.suiciding) || mob_occupant.hellbound) //Autoeject corpses and suiciding dudes.
connected_message("Clone Rejected: Deceased.")
- SPEAK("The cloning of [mob_occupant.real_name] has been \
- aborted due to unrecoverable tissue failure.")
+ if(internal_radio)
+ SPEAK("The cloning of [mob_occupant.real_name] has been \
+ aborted due to unrecoverable tissue failure.")
go_out()
mob_occupant.apply_vore_prefs()
@@ -248,13 +247,12 @@
//Premature clones may have brain damage.
mob_occupant.adjustBrainLoss(-((speed_coeff / 2) * dmg_mult))
- check_brine()
-
use_power(7500) //This might need tweaking.
else if((mob_occupant.cloneloss <= (100 - heal_level)))
connected_message("Cloning Process Complete.")
- SPEAK("The cloning cycle of [mob_occupant.real_name] is complete.")
+ if(internal_radio)
+ SPEAK("The cloning cycle of [mob_occupant.real_name] is complete.")
// If the cloner is upgraded to debugging high levels, sometimes
// organs and limbs can be missing.
@@ -356,6 +354,11 @@
if(!mob_occupant)
return
+ mob_occupant.remove_trait(TRAIT_STABLEHEART, "cloning")
+ mob_occupant.remove_trait(TRAIT_EMOTEMUTE, "cloning")
+ mob_occupant.remove_trait(TRAIT_MUTE, "cloning")
+ mob_occupant.remove_trait(TRAIT_NOCRITDAMAGE, "cloning")
+ mob_occupant.remove_trait(TRAIT_NOBREATH, "cloning")
if(grab_ghost_when == CLONER_MATURE_CLONE)
mob_occupant.grab_ghost()
@@ -459,15 +462,6 @@
flesh_number = unattached_flesh.len
-/obj/machinery/clonepod/proc/check_brine()
- // Clones are in a pickled bath of mild chemicals, keeping
- // them alive, despite their lack of internal organs
- for(var/bt in brine_types)
- if(bt == "corazone" && occupant.reagents.get_reagent_amount(bt) < 2)
- occupant.reagents.add_reagent(bt, 2)//pump it full of extra corazone as a safety, you can't OD on corazone.
- else if(occupant.reagents.get_reagent_amount(bt) < 1)
- occupant.reagents.add_reagent(bt, 1)
-
/*
* Manual -- A big ol' manual.
*/
diff --git a/code/game/machinery/exp_cloner.dm b/code/game/machinery/exp_cloner.dm
new file mode 100644
index 0000000000..27618668fa
--- /dev/null
+++ b/code/game/machinery/exp_cloner.dm
@@ -0,0 +1,297 @@
+//Experimental cloner; clones a body regardless of the owner's status, letting a ghost control it instead
+/obj/machinery/clonepod/experimental
+ name = "experimental cloning pod"
+ desc = "An ancient cloning pod. It seems to be an early prototype of the experimental cloners used in Nanotrasen Stations."
+ icon = 'icons/obj/machines/cloning.dmi'
+ icon_state = "pod_0"
+ req_access = null
+ circuit = /obj/item/circuitboard/machine/clonepod/experimental
+ internal_radio = FALSE
+
+//Start growing a human clone in the pod!
+/obj/machinery/clonepod/experimental/growclone(clonename, ui, se, datum/species/mrace, list/features, factions)
+ if(panel_open)
+ return FALSE
+ if(mess || attempting)
+ return FALSE
+
+ attempting = TRUE //One at a time!!
+ countdown.start()
+
+ var/mob/living/carbon/human/H = new /mob/living/carbon/human(src)
+
+ H.hardset_dna(ui, se, H.real_name, null, mrace, features)
+
+ if(efficiency > 2)
+ var/list/unclean_mutations = (GLOB.not_good_mutations|GLOB.bad_mutations)
+ H.dna.remove_mutation_group(unclean_mutations)
+ if(efficiency > 5 && prob(20))
+ H.randmutvg()
+ if(efficiency < 3 && prob(50))
+ var/mob/M = H.randmutb()
+ if(ismob(M))
+ H = M
+
+ H.silent = 20 //Prevents an extreme edge case where clones could speak if they said something at exactly the right moment.
+ occupant = H
+
+ if(!clonename) //to prevent null names
+ clonename = "clone ([rand(0,999)])"
+ H.real_name = clonename
+
+ icon_state = "pod_1"
+ //Get the clone body ready
+ maim_clone(H)
+ H.add_trait(TRAIT_STABLEHEART, "cloning")
+ H.add_trait(TRAIT_EMOTEMUTE, "cloning")
+ H.add_trait(TRAIT_MUTE, "cloning")
+ H.add_trait(TRAIT_NOBREATH, "cloning")
+ H.add_trait(TRAIT_NOCRITDAMAGE, "cloning")
+ H.Unconscious(80)
+
+ var/list/candidates = pollCandidatesForMob("Do you want to play as [clonename]'s defective clone?", null, null, null, 100, H)
+ if(LAZYLEN(candidates))
+ var/mob/dead/observer/C = pick(candidates)
+ H.key = C.key
+
+ if(grab_ghost_when == CLONER_FRESH_CLONE)
+ H.grab_ghost()
+ to_chat(H, "Consciousness slowly creeps over you as your body regenerates.
So this is what cloning feels like?")
+
+ if(grab_ghost_when == CLONER_MATURE_CLONE)
+ H.ghostize(TRUE) //Only does anything if they were still in their old body and not already a ghost
+ to_chat(H.get_ghost(TRUE), "Your body is beginning to regenerate in a cloning pod. You will become conscious when it is complete.")
+
+ if(H)
+ H.faction |= factions
+
+ H.set_cloned_appearance()
+
+ H.suiciding = FALSE
+ attempting = FALSE
+ return TRUE
+
+
+//Prototype cloning console, much more rudimental and lacks modern functions such as saving records, autocloning, or safety checks.
+/obj/machinery/computer/prototype_cloning
+ name = "prototype cloning console"
+ desc = "Used to operate an experimental cloner."
+ icon_screen = "dna"
+ icon_keyboard = "med_key"
+ circuit = /obj/item/circuitboard/computer/prototype_cloning
+ var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning.
+ var/list/pods //Linked experimental cloning pods
+ var/temp = "Inactive"
+ var/scantemp = "Ready to Scan"
+ var/loading = FALSE // Nice loading text
+
+ light_color = LIGHT_COLOR_BLUE
+
+/obj/machinery/computer/prototype_cloning/Initialize()
+ . = ..()
+ updatemodules(TRUE)
+
+/obj/machinery/computer/prototype_cloning/Destroy()
+ if(pods)
+ for(var/P in pods)
+ DetachCloner(P)
+ pods = null
+ return ..()
+
+/obj/machinery/computer/prototype_cloning/proc/GetAvailablePod(mind = null)
+ if(pods)
+ for(var/P in pods)
+ var/obj/machinery/clonepod/experimental/pod = P
+ if(pod.is_operational() && !(pod.occupant || pod.mess))
+ return pod
+
+/obj/machinery/computer/prototype_cloning/proc/updatemodules(findfirstcloner)
+ scanner = findscanner()
+ if(findfirstcloner && !LAZYLEN(pods))
+ findcloner()
+
+/obj/machinery/computer/prototype_cloning/proc/findscanner()
+ var/obj/machinery/dna_scannernew/scannerf = null
+
+ // Loop through every direction
+ for(var/direction in GLOB.cardinals)
+ // Try to find a scanner in that direction
+ scannerf = locate(/obj/machinery/dna_scannernew, get_step(src, direction))
+ // If found and operational, return the scanner
+ if (!isnull(scannerf) && scannerf.is_operational())
+ return scannerf
+
+ // If no scanner was found, it will return null
+ return null
+
+/obj/machinery/computer/prototype_cloning/proc/findcloner()
+ var/obj/machinery/clonepod/experimental/podf = null
+ for(var/direction in GLOB.cardinals)
+ podf = locate(/obj/machinery/clonepod/experimental, get_step(src, direction))
+ if (!isnull(podf) && podf.is_operational())
+ AttachCloner(podf)
+
+/obj/machinery/computer/prototype_cloning/proc/AttachCloner(obj/machinery/clonepod/experimental/pod)
+ if(!pod.connected)
+ pod.connected = src
+ LAZYADD(pods, pod)
+
+/obj/machinery/computer/prototype_cloning/proc/DetachCloner(obj/machinery/clonepod/experimental/pod)
+ pod.connected = null
+ LAZYREMOVE(pods, pod)
+
+/obj/machinery/computer/prototype_cloning/attackby(obj/item/W, mob/user, params)
+ if(istype(W, /obj/item/device/multitool))
+ var/obj/item/device/multitool/P = W
+
+ if(istype(P.buffer, /obj/machinery/clonepod/experimental))
+ if(get_area(P.buffer) != get_area(src))
+ to_chat(user, "-% Cannot link machines across power zones. Buffer cleared %-")
+ P.buffer = null
+ return
+ to_chat(user, "-% Successfully linked [P.buffer] with [src] %-")
+ var/obj/machinery/clonepod/experimental/pod = P.buffer
+ if(pod.connected)
+ pod.connected.DetachCloner(pod)
+ AttachCloner(pod)
+ else
+ P.buffer = src
+ to_chat(user, "-% Successfully stored [REF(P.buffer)] [P.buffer.name] in buffer %-")
+ return
+ else
+ return ..()
+
+/obj/machinery/computer/prototype_cloning/attack_hand(mob/user)
+ if(..())
+ return
+ interact(user)
+
+/obj/machinery/computer/prototype_cloning/interact(mob/user)
+ user.set_machine(src)
+ add_fingerprint(user)
+
+ if(..())
+ return
+
+ updatemodules(TRUE)
+
+ var/dat = ""
+ dat += "Refresh"
+
+ dat += "
The provided CLONEPOD SYSTEM will produce the desired clone. Standard clone maturation times are roughly 90 seconds. + The cloning pod may be unlocked early after initial maturation is complete.