From ef10c0abcc801df9e41b4eaf6defcef3f78625a5 Mon Sep 17 00:00:00 2001
From: silicons <2003111+silicons@users.noreply.github.com>
Date: Wed, 15 Oct 2025 09:40:42 -0700
Subject: [PATCH] lore enforcement update (#7358)
---
citadel.dme | 6 +-
code/__DEFINES/dna.dm | 7 +
code/game/dna/dna2_domutcheck.dm | 9 +-
.../genetics}/dna_injector.dm | 3 +-
code/modules/genetics/dna_scanner.dm | 165 +++++++++++++
.../genetics/dna_scanner_console.dm} | 216 +-----------------
code/modules/genetics/misc.dm | 33 +++
.../mob/living/carbon/human/human_helpers.dm | 2 +
code/modules/species/protean/protean.dm | 9 +
9 files changed, 240 insertions(+), 210 deletions(-)
rename code/{game/objects/items/weapons => modules/genetics}/dna_injector.dm (99%)
create mode 100644 code/modules/genetics/dna_scanner.dm
rename code/{game/dna/dna_modifier.dm => modules/genetics/dna_scanner_console.dm} (76%)
create mode 100644 code/modules/genetics/misc.dm
diff --git a/citadel.dme b/citadel.dme
index 9ed6274dc3a..10a3c8b44bb 100644
--- a/citadel.dme
+++ b/citadel.dme
@@ -1258,7 +1258,6 @@
#include "code\game\dna\dna2.dm"
#include "code\game\dna\dna2_domutcheck.dm"
#include "code\game\dna\dna2_helpers.dm"
-#include "code\game\dna\dna_modifier.dm"
#include "code\game\dna\genes\_gene.dm"
#include "code\game\dna\genes\disabilities.dm"
#include "code\game\dna\genes\powers.dm"
@@ -1949,7 +1948,6 @@
#include "code\game\objects\items\weapons\candle.dm"
#include "code\game\objects\items\weapons\cigs_lighters.dm"
#include "code\game\objects\items\weapons\cosmetics.dm"
-#include "code\game\objects\items\weapons\dna_injector.dm"
#include "code\game\objects\items\weapons\duct_tape.dm"
#include "code\game\objects\items\weapons\explosives.dm"
#include "code\game\objects\items\weapons\extinguisher.dm"
@@ -3163,6 +3161,10 @@
#include "code\modules\gateway\stargate\stargate-destination.dm"
#include "code\modules\gateway\stargate\stargate-station.dm"
#include "code\modules\gateway\stargate\stargate.dm"
+#include "code\modules\genetics\dna_injector.dm"
+#include "code\modules\genetics\dna_scanner.dm"
+#include "code\modules\genetics\dna_scanner_console.dm"
+#include "code\modules\genetics\misc.dm"
#include "code\modules\genetics\side_effects.dm"
#include "code\modules\roles\role_tweak.dm"
#include "code\modules\roles\ghostroles\instantiator.dm"
diff --git a/code/__DEFINES/dna.dm b/code/__DEFINES/dna.dm
index fd6db84f885..55867491f79 100644
--- a/code/__DEFINES/dna.dm
+++ b/code/__DEFINES/dna.dm
@@ -70,3 +70,10 @@ var/DNABLOCK_HALLUCINATION = 0
var/DNABLOCK_NOPRINTS = 0
var/DNABLOCK_NOSHOCK = 0
var/DNABLOCK_DWARFISM = 0
+
+#define DNA_BLOCK_SIZE 3
+
+// Buffer datatype flags.
+#define DNA2_BUF_UI 1
+#define DNA2_BUF_UE 2
+#define DNA2_BUF_SE 4
diff --git a/code/game/dna/dna2_domutcheck.dm b/code/game/dna/dna2_domutcheck.dm
index d1f75215936..87b4b22c95a 100644
--- a/code/game/dna/dna2_domutcheck.dm
+++ b/code/game/dna/dna2_domutcheck.dm
@@ -5,9 +5,14 @@
// flags: See below, bitfield.
#define MUTCHK_FORCED 1
/proc/domutcheck(mob/living/M, connected=null, flags=0)
+ if(QDELETED(M) || !M.dna)
+ return
+ if(M.isSynthetic())
+ return // fuck off powergamers
for(var/datum/gene/gene in dna_genes)
- if(!M || !M.dna)
- return
+ // incase they get deleted by activation
+ if(QDELETED(M))
+ break
if(!gene.block)
continue
diff --git a/code/game/objects/items/weapons/dna_injector.dm b/code/modules/genetics/dna_injector.dm
similarity index 99%
rename from code/game/objects/items/weapons/dna_injector.dm
rename to code/modules/genetics/dna_injector.dm
index 76ca19abec9..cf2873a1b5b 100644
--- a/code/game/objects/items/weapons/dna_injector.dm
+++ b/code/modules/genetics/dna_injector.dm
@@ -1,3 +1,4 @@
+// TODO: rename to /item/dna_injector
/obj/item/dnainjector
name = "\improper DNA injector"
desc = "This injects the person with DNA."
@@ -121,7 +122,7 @@
target.visible_message("\The [target] has been injected with \the [src] by \the [user].")
var/mob/living/carbon/human/H = target
- if(!istype(H))
+ if(!istype(H) || H.isSynthetic())
to_chat(user, "Apparently it didn't work...")
return
diff --git a/code/modules/genetics/dna_scanner.dm b/code/modules/genetics/dna_scanner.dm
new file mode 100644
index 00000000000..323b47f6999
--- /dev/null
+++ b/code/modules/genetics/dna_scanner.dm
@@ -0,0 +1,165 @@
+// TODO: rename to /machinery/dna_scanner
+/obj/machinery/dna_scannernew
+ name = "\improper DNA modifier"
+ desc = "It scans DNA structures."
+ icon = 'icons/obj/medical/cryogenic2.dmi'
+ icon_state = "scanner_0"
+ density = TRUE
+ anchored = TRUE
+ use_power = USE_POWER_IDLE
+ idle_power_usage = 50
+ active_power_usage = 300
+ interaction_flags_machine = INTERACT_MACHINE_OFFLINE | INTERACT_MACHINE_ALLOW_SILICON
+ circuit = /obj/item/circuitboard/clonescanner
+
+ var/locked = FALSE
+ var/opened = FALSE
+ var/mob/living/carbon/occupant = null
+ var/obj/item/reagent_containers/glass/beaker = null
+
+/obj/machinery/dna_scannernew/relaymove(mob/user)
+ if (user.stat)
+ return
+ src.go_out()
+ return
+
+/obj/machinery/dna_scannernew/verb/eject()
+ set src in oview(1)
+ set category = VERB_CATEGORY_OBJECT
+ set name = "Eject DNA Scanner"
+
+ if (usr.stat != 0)
+ return
+
+ eject_occupant()
+
+ add_fingerprint(usr)
+ return
+
+/obj/machinery/dna_scannernew/proc/eject_occupant()
+ src.go_out()
+ for(var/obj/O in src)
+ if((!istype(O,/obj/item/reagent_containers)) && (!istype(O,/obj/item/circuitboard/clonescanner)) && (!istype(O,/obj/item/stock_parts)) && (!istype(O,/obj/item/stack/cable_coil)))
+ O.forceMove(get_turf(src))
+ if(!occupant)
+ for(var/mob/M in src)//Failsafe so you can get mobs out
+ M.forceMove(get_turf(src))
+
+/**
+ *? Allows borgs to clone people without external assistance.
+ */
+/obj/machinery/dna_scannernew/MouseDroppedOnLegacy(mob/target, mob/user)
+ if(user.stat || user.lying || !Adjacent(user) || !target.Adjacent(user)|| !ishuman(target))
+ return
+ put_in(target)
+
+/obj/machinery/dna_scannernew/verb/move_inside()
+ set src in oview(1)
+ set category = VERB_CATEGORY_OBJECT
+ set name = "Enter DNA Scanner"
+
+ if (usr.stat != 0)
+ return
+ if (!ishuman(usr) && !issmall(usr)) //Make sure they're a mob that has dna
+ to_chat(usr, SPAN_NOTICE("Try as you might, you can not climb up into the scanner."))
+ return
+ if (src.occupant)
+ to_chat(usr, SPAN_WARNING("The scanner is already occupied!"))
+ return
+ if (usr.abiotic())
+ to_chat(usr, SPAN_WARNING("The subject cannot have abiotic items on."))
+ return
+ usr.stop_pulling()
+ usr.forceMove(src)
+ usr.update_perspective()
+ src.occupant = usr
+ src.icon_state = "scanner_1"
+ src.add_fingerprint(usr)
+ return
+
+/obj/machinery/dna_scannernew/attackby(obj/item/item, mob/user)
+ if(istype(item, /obj/item/reagent_containers/glass))
+ if(beaker)
+ to_chat(user, SPAN_WARNING("A beaker is already loaded into the machine."))
+ return
+ if(!user.attempt_insert_item_for_installation(item, src))
+ return
+ beaker = item
+ user.visible_message("\The [user] adds \a [item] to \the [src]!", "You add \a [item] to \the [src]!")
+ return
+
+ else if(istype(item, /obj/item/organ/internal/brain))
+ if (src.occupant)
+ to_chat(user, SPAN_WARNING("The scanner is already occupied!"))
+ return
+ var/obj/item/organ/internal/brain/brain = item
+ if(brain.clone_source)
+ if(!user.attempt_insert_item_for_installation(brain, src))
+ return
+ put_in(brain.brainmob)
+ src.add_fingerprint(user)
+ user.visible_message("\The [user] adds \a [item] to \the [src]!", "You add \a [item] to \the [src]!")
+ return
+ else
+ to_chat(user,"\The [brain] is not acceptable for genetic sampling!")
+
+ else if (!istype(item, /obj/item/grab))
+ return
+ var/obj/item/grab/G = item
+ if (!ismob(G.affecting))
+ return
+ if (src.occupant)
+ to_chat(user, SPAN_WARNING("The scanner is already occupied!"))
+ return
+ if (G.affecting.abiotic())
+ to_chat(user, SPAN_WARNING("The subject cannot have abiotic items on."))
+ return
+ put_in(G.affecting)
+ src.add_fingerprint(user)
+ qdel(G)
+ return
+
+/obj/machinery/dna_scannernew/proc/put_in(mob/M)
+ occupant = M
+ M.forceMove(src)
+ M.update_perspective()
+
+ icon_state = "scanner_1"
+
+ // search for ghosts, if the corpse is empty and the scanner is connected to a cloner
+ if(locate(/obj/machinery/computer/cloning, get_step(src, NORTH)) \
+ || locate(/obj/machinery/computer/cloning, get_step(src, SOUTH)) \
+ || locate(/obj/machinery/computer/cloning, get_step(src, EAST)) \
+ || locate(/obj/machinery/computer/cloning, get_step(src, WEST)))
+
+ if(!M.client && M.mind)
+ for(var/mob/observer/dead/ghost in GLOB.player_list)
+ if(ghost.mind == M.mind)
+ to_chat(ghost, "Your corpse has been placed into a cloning scanner. Return to your body if you want to be resurrected/cloned! (Verbs -> Ghost -> Re-enter corpse)")
+ break
+ return
+
+/obj/machinery/dna_scannernew/proc/go_out()
+ if(!occupant|| locked)
+ return
+ if(istype(occupant,/mob/living/carbon/brain))
+ for(var/obj/O in src)
+ if(istype(O,/obj/item/organ/internal/brain))
+ O.forceMove(loc)
+ occupant.forceMove(O)
+ break
+ else
+ occupant.forceMove(loc)
+ occupant.update_perspective()
+ occupant = null
+ icon_state = "scanner_0"
+
+/obj/machinery/dna_scannernew/proc/occupant_valid(mob/victim)
+ if(isnull(victim))
+ victim = occupant
+ if(isnull(victim))
+ return FALSE
+ if(iscarbon(victim))
+ var/mob/living/carbon/casted_carbon = victim
+ return !casted_carbon.isSynthetic()
+ return FALSE
diff --git a/code/game/dna/dna_modifier.dm b/code/modules/genetics/dna_scanner_console.dm
similarity index 76%
rename from code/game/dna/dna_modifier.dm
rename to code/modules/genetics/dna_scanner_console.dm
index 14e2a73daf0..24e960259e3 100644
--- a/code/game/dna/dna_modifier.dm
+++ b/code/modules/genetics/dna_scanner_console.dm
@@ -1,198 +1,4 @@
-#define DNA_BLOCK_SIZE 3
-
-// Buffer datatype flags.
-#define DNA2_BUF_UI 1
-#define DNA2_BUF_UE 2
-#define DNA2_BUF_SE 4
-
-//list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0),
-/datum/dna2/record
- var/datum/dna/dna = null
- var/types=0
- var/name="Empty"
-
- // Stuff for cloners
- var/id=null
- var/implant=null
- var/ckey=null
- var/mind=null
- var/languages=null
- var/list/flavor=null
- var/gender = null
- var/list/body_descriptors = null
- var/list/genetic_modifiers = list() // Modifiers with the MODIFIER_GENETIC flag are saved. Note that only the type is saved, not an instance.
-
-/datum/dna2/record/proc/GetData()
- var/list/ser=list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0)
- if(dna)
- ser["ue"] = (types & DNA2_BUF_UE) == DNA2_BUF_UE
- if(types & DNA2_BUF_SE)
- ser["data"] = dna.SE
- else
- ser["data"] = dna.UI
- ser["owner"] = src.dna.real_name
- ser["label"] = name
- if(types & DNA2_BUF_UI)
- ser["type"] = "ui"
- else
- ser["type"] = "se"
- return ser
-
-//! ## DNA MACHINES
-/obj/machinery/dna_scannernew
- name = "\improper DNA modifier"
- desc = "It scans DNA structures."
- icon = 'icons/obj/medical/cryogenic2.dmi'
- icon_state = "scanner_0"
- density = TRUE
- anchored = TRUE
- use_power = USE_POWER_IDLE
- idle_power_usage = 50
- active_power_usage = 300
- interaction_flags_machine = INTERACT_MACHINE_OFFLINE | INTERACT_MACHINE_ALLOW_SILICON
- circuit = /obj/item/circuitboard/clonescanner
-
- var/locked = FALSE
- var/opened = FALSE
- var/mob/living/carbon/occupant = null
- var/obj/item/reagent_containers/glass/beaker = null
-
-/obj/machinery/dna_scannernew/relaymove(mob/user)
- if (user.stat)
- return
- src.go_out()
- return
-
-/obj/machinery/dna_scannernew/verb/eject()
- set src in oview(1)
- set category = VERB_CATEGORY_OBJECT
- set name = "Eject DNA Scanner"
-
- if (usr.stat != 0)
- return
-
- eject_occupant()
-
- add_fingerprint(usr)
- return
-
-/obj/machinery/dna_scannernew/proc/eject_occupant()
- src.go_out()
- for(var/obj/O in src)
- if((!istype(O,/obj/item/reagent_containers)) && (!istype(O,/obj/item/circuitboard/clonescanner)) && (!istype(O,/obj/item/stock_parts)) && (!istype(O,/obj/item/stack/cable_coil)))
- O.forceMove(get_turf(src))
- if(!occupant)
- for(var/mob/M in src)//Failsafe so you can get mobs out
- M.forceMove(get_turf(src))
-
-/**
- *? Allows borgs to clone people without external assistance.
- */
-/obj/machinery/dna_scannernew/MouseDroppedOnLegacy(mob/target, mob/user)
- if(user.stat || user.lying || !Adjacent(user) || !target.Adjacent(user)|| !ishuman(target))
- return
- put_in(target)
-
-/obj/machinery/dna_scannernew/verb/move_inside()
- set src in oview(1)
- set category = VERB_CATEGORY_OBJECT
- set name = "Enter DNA Scanner"
-
- if (usr.stat != 0)
- return
- if (!ishuman(usr) && !issmall(usr)) //Make sure they're a mob that has dna
- to_chat(usr, SPAN_NOTICE("Try as you might, you can not climb up into the scanner."))
- return
- if (src.occupant)
- to_chat(usr, SPAN_WARNING("The scanner is already occupied!"))
- return
- if (usr.abiotic())
- to_chat(usr, SPAN_WARNING("The subject cannot have abiotic items on."))
- return
- usr.stop_pulling()
- usr.forceMove(src)
- usr.update_perspective()
- src.occupant = usr
- src.icon_state = "scanner_1"
- src.add_fingerprint(usr)
- return
-
-/obj/machinery/dna_scannernew/attackby(obj/item/item, mob/user)
- if(istype(item, /obj/item/reagent_containers/glass))
- if(beaker)
- to_chat(user, SPAN_WARNING("A beaker is already loaded into the machine."))
- return
- if(!user.attempt_insert_item_for_installation(item, src))
- return
- beaker = item
- user.visible_message("\The [user] adds \a [item] to \the [src]!", "You add \a [item] to \the [src]!")
- return
-
- else if(istype(item, /obj/item/organ/internal/brain))
- if (src.occupant)
- to_chat(user, SPAN_WARNING("The scanner is already occupied!"))
- return
- var/obj/item/organ/internal/brain/brain = item
- if(brain.clone_source)
- if(!user.attempt_insert_item_for_installation(brain, src))
- return
- put_in(brain.brainmob)
- src.add_fingerprint(user)
- user.visible_message("\The [user] adds \a [item] to \the [src]!", "You add \a [item] to \the [src]!")
- return
- else
- to_chat(user,"\The [brain] is not acceptable for genetic sampling!")
-
- else if (!istype(item, /obj/item/grab))
- return
- var/obj/item/grab/G = item
- if (!ismob(G.affecting))
- return
- if (src.occupant)
- to_chat(user, SPAN_WARNING("The scanner is already occupied!"))
- return
- if (G.affecting.abiotic())
- to_chat(user, SPAN_WARNING("The subject cannot have abiotic items on."))
- return
- put_in(G.affecting)
- src.add_fingerprint(user)
- qdel(G)
- return
-
-/obj/machinery/dna_scannernew/proc/put_in(mob/M)
- occupant = M
- M.update_perspective()
-
- icon_state = "scanner_1"
-
- // search for ghosts, if the corpse is empty and the scanner is connected to a cloner
- if(locate(/obj/machinery/computer/cloning, get_step(src, NORTH)) \
- || locate(/obj/machinery/computer/cloning, get_step(src, SOUTH)) \
- || locate(/obj/machinery/computer/cloning, get_step(src, EAST)) \
- || locate(/obj/machinery/computer/cloning, get_step(src, WEST)))
-
- if(!M.client && M.mind)
- for(var/mob/observer/dead/ghost in GLOB.player_list)
- if(ghost.mind == M.mind)
- to_chat(ghost, "Your corpse has been placed into a cloning scanner. Return to your body if you want to be resurrected/cloned! (Verbs -> Ghost -> Re-enter corpse)")
- break
- return
-
-/obj/machinery/dna_scannernew/proc/go_out()
- if(!occupant|| locked)
- return
- if(istype(occupant,/mob/living/carbon/brain))
- for(var/obj/O in src)
- if(istype(O,/obj/item/organ/internal/brain))
- O.forceMove(loc)
- occupant.forceMove(O)
- break
- else
- occupant.forceMove(loc)
- occupant.update_perspective()
- occupant = null
- icon_state = "scanner_0"
-
+// TODO: rename to /computer/dna_scanner_console
/obj/machinery/computer/scan_consolenew
name = "DNA Modifier Access Console"
desc = "Scan DNA."
@@ -323,7 +129,7 @@
var/data[0]
data["selectedMenuKey"] = selected_menu_key
data["locked"] = src.connected.locked
- data["hasOccupant"] = connected.occupant ? 1 : 0
+ data["hasOccupant"] = connected.occupant_valid() ? 1 : 0
data["isInjectorReady"] = injector_ready
@@ -358,7 +164,7 @@
data["selectedUITargetHex"] = selected_ui_target_hex
var/occupantData[0]
- if (!src.connected.occupant || !src.connected.occupant.dna)
+ if (!src.connected.occupant_valid() || !src.connected.occupant.dna)
occupantData["name"] = null
occupantData["stat"] = null
occupantData["isViableSubject"] = null
@@ -434,7 +240,7 @@
sleep(10 * 2)
irradiating = 0
- if (!src.connected.occupant)
+ if (!src.connected.occupant_valid())
return 1 // return 1 forces an update to all Nano uis attached to src
if (prob(95))
@@ -535,7 +341,7 @@
irradiating = 0
- if (!src.connected.occupant)
+ if (!src.connected.occupant_valid())
return 1
if (prob((80 + (src.radiation_duration / 2))))
@@ -557,7 +363,7 @@
////////////////////////////////////////////////////////
if (href_list["injectRejuvenators"])
- if (!connected.occupant)
+ if (!connected.occupant_valid())
return 0
var/inject_amount = round(text2num(href_list["injectRejuvenators"]), 5) // round to nearest 5
if (inject_amount < 0) // Since the user can actually type the commands himself, some sanity checking
@@ -593,7 +399,7 @@
irradiating = 0
- if(src.connected.occupant)
+ if(src.connected.occupant_valid())
if (prob((80 + (src.radiation_duration / 2))))
// FIXME: Find out what these corresponded to and change them to the WHATEVERBLOCK they need to be.
//if ((src.selected_se_block != 2 || src.selected_se_block != 12 || src.selected_se_block != 8 || src.selected_se_block || 10) && prob (20))
@@ -664,7 +470,7 @@
return 0 // Not a valid buffer id
if (bufferOption == "saveUI")
- if(src.connected.occupant && src.connected.occupant.dna)
+ if(src.connected.occupant_valid() && src.connected.occupant.dna)
var/datum/dna2/record/databuf=new
databuf.types = DNA2_BUF_UE
databuf.dna = src.connected.occupant.dna.Clone()
@@ -678,7 +484,7 @@
return 1
if (bufferOption == "saveUIAndUE")
- if(src.connected.occupant && src.connected.occupant.dna)
+ if(src.connected.occupant_valid() && src.connected.occupant.dna)
var/datum/dna2/record/databuf=new
databuf.types = DNA2_BUF_UI|DNA2_BUF_UE
databuf.dna = src.connected.occupant.dna.Clone()
@@ -692,7 +498,7 @@
return 1
if (bufferOption == "saveSE")
- if(src.connected.occupant && src.connected.occupant.dna)
+ if(src.connected.occupant_valid() && src.connected.occupant.dna)
var/datum/dna2/record/databuf=new
databuf.types = DNA2_BUF_SE
databuf.dna = src.connected.occupant.dna.Clone()
@@ -717,7 +523,7 @@
return 1
if (bufferOption == "transfer")
- if (!src.connected.occupant || (MUTATION_NOCLONE in src.connected.occupant.mutations) || !src.connected.occupant.dna)
+ if (!src.connected.occupant_valid() || (MUTATION_NOCLONE in src.connected.occupant.mutations) || !src.connected.occupant.dna)
return
irradiating = 2
diff --git a/code/modules/genetics/misc.dm b/code/modules/genetics/misc.dm
new file mode 100644
index 00000000000..a3ad7a84d81
--- /dev/null
+++ b/code/modules/genetics/misc.dm
@@ -0,0 +1,33 @@
+
+//list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0),
+/datum/dna2/record
+ var/datum/dna/dna = null
+ var/types=0
+ var/name="Empty"
+
+ // Stuff for cloners
+ var/id=null
+ var/implant=null
+ var/ckey=null
+ var/mind=null
+ var/languages=null
+ var/list/flavor=null
+ var/gender = null
+ var/list/body_descriptors = null
+ var/list/genetic_modifiers = list() // Modifiers with the MODIFIER_GENETIC flag are saved. Note that only the type is saved, not an instance.
+
+/datum/dna2/record/proc/GetData()
+ var/list/ser=list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0)
+ if(dna)
+ ser["ue"] = (types & DNA2_BUF_UE) == DNA2_BUF_UE
+ if(types & DNA2_BUF_SE)
+ ser["data"] = dna.SE
+ else
+ ser["data"] = dna.UI
+ ser["owner"] = src.dna.real_name
+ ser["label"] = name
+ if(types & DNA2_BUF_UI)
+ ser["type"] = "ui"
+ else
+ ser["type"] = "se"
+ return ser
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index 4bae6b3e84c..f2827ef5c24 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -117,6 +117,8 @@
if(fast_is_species_type(src, /datum/species/shapeshifter/holosphere))
return TRUE
+ if(fast_is_species_type(src, /datum/species/protean))
+ return TRUE
return FALSE
diff --git a/code/modules/species/protean/protean.dm b/code/modules/species/protean/protean.dm
index 4a3891da23b..4c7d30aa8e4 100644
--- a/code/modules/species/protean/protean.dm
+++ b/code/modules/species/protean/protean.dm
@@ -170,6 +170,15 @@
/datum/species/protean/create_organs(mob/living/carbon/human/H)
H.synth_color = TRUE
. = ..()
+ for(var/obj/item/organ/external/external_organ in H.get_external_organs())
+ if(external_organ.robotic < ORGAN_ROBOT)
+ external_organ.robotize()
+ if(!external_organ.model)
+ // let's not play this game
+ // :trol:
+ external_organ.model = GLOB.all_robolimbs[1]
+ // LEGACY: make sure their synthetic-ness is sticky by calling isSynthetic
+ H.isSynthetic()
// todo: this is utter shitcode and will break if we CHECK_TICK in SSticker, and should probably be part of postspawn or something
spawn(5) //Let their real nif load if they have one