diff --git a/baystation12.dme b/baystation12.dme
index 03a27e50166..1dab615d87d 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -1396,6 +1396,9 @@
#include "code\modules\research\xenoarchaeology\finds\finds_fossils.dm"
#include "code\modules\research\xenoarchaeology\finds\finds_misc.dm"
#include "code\modules\research\xenoarchaeology\finds\finds_talkingitem.dm"
+#include "code\modules\research\xenoarchaeology\genetics\prehistoric_animals.dm"
+#include "code\modules\research\xenoarchaeology\genetics\prehistoric_plants.dm"
+#include "code\modules\research\xenoarchaeology\genetics\reconstitutor.dm"
#include "code\modules\research\xenoarchaeology\machinery\artifact_analyser.dm"
#include "code\modules\research\xenoarchaeology\machinery\artifact_harvester.dm"
#include "code\modules\research\xenoarchaeology\machinery\artifact_scanner.dm"
diff --git a/code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi b/code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi
index 13cd5e77396..f27897881ce 100644
Binary files a/code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi and b/code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi differ
diff --git a/code/game/dna/dna2_domutcheck.dm b/code/game/dna/dna2_domutcheck.dm
index 954c86f2a6a..02495bbc490 100644
--- a/code/game/dna/dna2_domutcheck.dm
+++ b/code/game/dna/dna2_domutcheck.dm
@@ -6,7 +6,7 @@
#define MUTCHK_FORCED 1
/proc/domutcheck(var/mob/living/M, var/connected=null, var/flags=0)
for(var/datum/dna/gene/gene in dna_genes)
- if(!M)
+ if(!M || !M.dna)
return
if(!gene.block)
continue
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index 87958b69338..9f761e6add7 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -298,6 +298,21 @@
user.drop_item()
del(W)
return
+ else if (istype(W, /obj/item/weapon/wrench))
+ if(src.locked && (src.anchored || src.occupant))
+ user << "\red Can not do that while [src] is in use."
+ else
+ if(src.anchored)
+ src.anchored = 0
+ connected.pod1 = null
+ connected = null
+ else
+ src.anchored = 1
+ playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1)
+ if(anchored)
+ user.visible_message("[user] secures [src] to the floor.", "You secure [src] to the floor.")
+ else
+ user.visible_message("[user] unsecures [src] from the floor.", "You unsecure [src] from the floor.")
else
..()
diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm
index 303b490a1fc..ae5e7ff3544 100644
--- a/code/modules/mining/mine_turfs.dm
+++ b/code/modules/mining/mine_turfs.dm
@@ -491,6 +491,12 @@ var/list/artifact_spawn = list() // Runtime fix for geometry loading before cont
for(var/obj/item/weapon/ore/O in contents)
O.attackby(W,user)
return
+ else if(istype(W,/obj/item/weapon/storage/bag/fossils))
+ var/obj/item/weapon/storage/bag/fossils/S = W
+ if(S.collection_mode)
+ for(var/obj/item/weapon/fossil/F in contents)
+ F.attackby(W,user)
+ return
else
..(W,user)
diff --git a/code/modules/research/xenoarchaeology/finds/finds_fossils.dm b/code/modules/research/xenoarchaeology/finds/finds_fossils.dm
index 89fc33396d2..57d510015fc 100644
--- a/code/modules/research/xenoarchaeology/finds/finds_fossils.dm
+++ b/code/modules/research/xenoarchaeology/finds/finds_fossils.dm
@@ -7,6 +7,7 @@
icon = 'icons/obj/xenoarchaeology.dmi'
icon_state = "bone"
desc = "It's a fossil."
+ var/animal = 1
/obj/item/weapon/fossil/base/New()
var/list/l = list("/obj/item/weapon/fossil/bone"=9,"/obj/item/weapon/fossil/skull"=3,
@@ -97,6 +98,7 @@
name = "Fossilised plant"
icon_state = "plant1"
desc = "It's fossilised plant remains."
+ animal = 0
/obj/item/weapon/fossil/plant/New()
icon_state = "plant[rand(1,4)]"
diff --git a/code/modules/research/xenoarchaeology/genetics/prehistoric_animals.dm b/code/modules/research/xenoarchaeology/genetics/prehistoric_animals.dm
new file mode 100644
index 00000000000..c9022726a6c
--- /dev/null
+++ b/code/modules/research/xenoarchaeology/genetics/prehistoric_animals.dm
@@ -0,0 +1,77 @@
+/mob/living/simple_animal/hostile/samak
+ name = "samak"
+ desc = "A fast, armoured predator accustomed to hiding and ambushing in cold terrain."
+ faction = "samak"
+ icon_state = "samak"
+ icon_living = "samak"
+ icon_dead = "samak_dead"
+ icon = 'code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi'
+ move_to_delay = 2
+ maxHealth = 125
+ health = 125
+ speed = 2
+ melee_damage_lower = 5
+ melee_damage_upper = 15
+ attacktext = "mauls"
+ cold_damage_per_tick = 0
+ speak_chance = 5
+ speak = list("Hruuugh!","Hrunnph")
+ emote_see = list("paws the ground","shakes its mane","stomps")
+ emote_hear = list("snuffles")
+
+/mob/living/simple_animal/hostile/diyaab
+ name = "diyaab"
+ desc = "A small pack animal. Although omnivorous, it will hunt meat on occasion."
+ faction = "diyaab"
+ icon_state = "diyaab"
+ icon_living = "diyaab"
+ icon_dead = "diyaab_dead"
+ icon = 'code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi'
+ move_to_delay = 1
+ maxHealth = 25
+ health = 25
+ speed = 1
+ melee_damage_lower = 1
+ melee_damage_upper = 8
+ attacktext = "gouges"
+ cold_damage_per_tick = 0
+ speak_chance = 5
+ speak = list("Awrr?","Aowrl!","Worrl")
+ emote_see = list("sniffs the air cautiously","looks around")
+ emote_hear = list("snuffles")
+
+/mob/living/simple_animal/hostile/shantak
+ name = "shantak"
+ desc = "A piglike creature with a bright iridiscent mane that sparkles as though lit by an inner light. Don't be fooled by its beauty though."
+ faction = "shantak"
+ icon_state = "shantak"
+ icon_living = "shantak"
+ icon_dead = "shantak_dead"
+ icon = 'code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi'
+ move_to_delay = 1
+ maxHealth = 75
+ health = 75
+ speed = 1
+ melee_damage_lower = 3
+ melee_damage_upper = 12
+ attacktext = "gouges"
+ cold_damage_per_tick = 0
+ speak_chance = 5
+ speak = list("Shuhn","Shrunnph?","Shunpf")
+ emote_see = list("scratches the ground","shakes out it's mane","tinkles gently")
+
+/mob/living/simple_animal/yithian
+ name = "yithian"
+ desc = "A friendly creature vaguely resembling an oversized snail without a shell."
+ icon_state = "yithian"
+ icon_living = "yithian"
+ icon_dead = "yithian_dead"
+ icon = 'code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi'
+
+/mob/living/simple_animal/tindalos
+ name = "tindalos"
+ desc = "It looks like a large, flightless grasshopper."
+ icon_state = "tindalos"
+ icon_living = "tindalos"
+ icon_dead = "tindalos_dead"
+ icon = 'code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi'
diff --git a/code/modules/research/xenoarchaeology/genetics/prehistoric_plants.dm b/code/modules/research/xenoarchaeology/genetics/prehistoric_plants.dm
new file mode 100644
index 00000000000..8496869c853
--- /dev/null
+++ b/code/modules/research/xenoarchaeology/genetics/prehistoric_plants.dm
@@ -0,0 +1,202 @@
+
+/obj/item/seeds/telriis
+ name = "pack of telriis seeds"
+ desc = "These seeds grow into telriis grass. Not recommended for consumption by sentient species."
+ icon_state = "seed-alien1"
+ mypath = "/obj/item/seeds/telriis"
+ species = "telriis"
+ plantname = "Telriis grass"
+ productname = "/obj/item/weapon/telriis_clump"
+ lifespan = 50 //number of ticks
+ endurance = 50 //
+ maturation = 5 //ticks to full growth stage
+ production = 5 //ticks till ready to harvest
+ yield = 4 //number produced when harvest
+ potency = 5
+ plant_type = 1 //1=weed, 2=shroom, 0=normal
+ growthstages = 4
+
+/obj/item/weapon/reagent_containers/food/snacks/grown/telriis_clump
+ name = "telriis grass"
+ desc = "A clump of telriis grass, not recommended for consumption by sentients."
+ icon = 'icons/obj/xenoarchaeology.dmi'
+ icon_state = "telriisclump"
+ New(var/loc, var/potency)
+ ..()
+ reagents.add_reagent("pwine", potency * 5)
+ reagents.add_reagent("nutriment", potency)
+ bitesize = 1+round(reagents.total_volume / 2, 1)
+
+
+/obj/item/seeds/thaadra
+ name = "pack of thaa'dra seeds"
+ desc = "These seeds grow into Thaa'dra lichen. Likes the cold."
+ icon_state = "seed-alien3"
+ mypath = "/obj/item/seeds/thaadra"
+ species = "thaadra"
+ plantname = "Thaa'dra lichen"
+ productname = "/obj/item/weapon/reagent_containers/food/snacks/grown/thaadra"
+ lifespan = 20
+ endurance = 10
+ maturation = 5
+ production = 9
+ yield = 2
+ potency = 5
+ plant_type = 2
+ growthstages = 4
+
+/obj/item/weapon/reagent_containers/food/snacks/grown/thaadrabloom
+ name = "thaa'dra bloom"
+ desc = "Looks chewy, might be good to eat."
+ icon = 'icons/obj/xenoarchaeology.dmi'
+ icon_state = "thaadrabloom"
+ New(var/loc, var/potency)
+ ..()
+ reagents.add_reagent("frostoil", potency * 1.5 + 5)
+ reagents.add_reagent("nutriment", potency)
+ bitesize = 1+round(reagents.total_volume / 2, 1)
+
+
+/obj/item/seeds/jurlmah
+ name = "pack of jurl'mah seeds"
+ desc = "These seeds grow into jurl'mah reeds, which produce large syrupy pods."
+ icon_state = "seed-alien3"
+ mypath = "/obj/item/seeds/jurlmah"
+ species = "jurlmah"
+ plantname = "jurl'mah reeds"
+ productname = "/obj/item/weapon/reagent_containers/food/snacks/grown/jurlmah"
+ lifespan = 20
+ endurance = 12
+ maturation = 8
+ production = 9
+ yield = 3
+ potency = 10
+ growthstages = 5
+
+/obj/item/weapon/reagent_containers/food/snacks/grown/jurlmah
+ name = "jurl'mah pod"
+ desc = "Bulbous and veiny, it appears to pulse slightly as you look at it."
+ icon = 'icons/obj/xenoarchaeology.dmi'
+ icon_state = "jurlmahpod"
+ New(var/loc, var/potency)
+ ..()
+ reagents.add_reagent("serotrotium", potency)
+ reagents.add_reagent("nutriment", potency)
+ bitesize = 1+round(reagents.total_volume / 2, 1)
+
+
+/obj/item/seeds/amauri
+ name = "pack of amauri seeds"
+ desc = "Grows into a straight, dark plant with small round fruit."
+ icon_state = "seed-alien3"
+ mypath = "/obj/item/seeds/amauri"
+ species = "amauri"
+ plantname = "amauri plant"
+ productname = "/obj/item/weapon/reagent_containers/food/snacks/grown/amauri"
+ lifespan = 30
+ endurance = 10
+ maturation = 8
+ production = 9
+ yield = 4
+ potency = 10
+ growthstages = 3
+
+/obj/item/weapon/reagent_containers/food/snacks/grown/amauri
+ name = "amauri fruit"
+ desc = "It is small, round and hard. Its skin is a thick dark purple."
+ icon = 'icons/obj/xenoarchaeology.dmi'
+ icon_state = "amaurifruit"
+ New(var/loc, var/potency)
+ ..()
+ reagents.add_reagent("zombiepowder", potency * 10)
+ reagents.add_reagent("condensedcapsaicin", potency * 5)
+ reagents.add_reagent("nutriment", potency)
+ bitesize = 1+round(reagents.total_volume / 2, 1)
+
+
+/obj/item/seeds/gelthi
+ name = "pack of gelthi seeds"
+ desc = "Grows into a bright, wavy plant with many small fruits."
+ icon_state = "seed-alien2"
+ mypath = "/obj/item/seeds/gelthi"
+ species = "gelthi"
+ plantname = "gelthi plant"
+ productname = "/obj/item/weapon/reagent_containers/food/snacks/grown/gelthi"
+ lifespan = 20
+ endurance = 15
+ maturation = 6
+ production = 6
+ yield = 2
+ potency = 1
+ growthstages = 3
+
+/obj/item/weapon/reagent_containers/food/snacks/grown/gelthi
+ name = "gelthi berries"
+ desc = "They feel fluffy and slightly warm to the touch."
+ icon = 'icons/obj/xenoarchaeology.dmi'
+ icon_state = "gelthiberries"
+ New(var/loc, var/potency)
+ ..()
+ //this may prove a little strong
+ reagents.add_reagent("stoxin", (potency * potency) / 5)
+ reagents.add_reagent("capsaicin", (potency * potency) / 5)
+ reagents.add_reagent("nutriment", potency)
+ bitesize = 1+round(reagents.total_volume / 2, 1)
+
+
+/obj/item/seeds/vale
+ name = "pack of vale seeds"
+ desc = "The vale bush is often depicted in ancient heiroglyphs and is similar to cherry blossoms."
+ icon_state = "seed-alien2"
+ mypath = "/obj/item/seeds/vale"
+ species = "vale"
+ plantname = "vale bush"
+ productname = "/obj/item/weapon/reagent_containers/food/snacks/grown/vale"
+ lifespan = 25
+ endurance = 15
+ maturation = 8
+ production = 10
+ yield = 3
+ potency = 3
+ growthstages = 4
+
+/obj/item/weapon/reagent_containers/food/snacks/grown/vale
+ name = "vale leaves"
+ desc = "Small, curly leaves covered in a soft pale fur."
+ icon = 'icons/obj/xenoarchaeology.dmi'
+ icon_state = "valeleaves"
+ New(var/loc, var/potency)
+ ..()
+ reagents.add_reagent("paracetamol", potency * 5)
+ reagents.add_reagent("dexalin", potency * 2)
+ reagents.add_reagent("nutriment", potency)
+ bitesize = 1+round(reagents.total_volume / 2, 1)
+
+
+/obj/item/seeds/surik
+ name = "pack of surik seeds"
+ desc = "A spiky blue vine with large fruit resembling pig ears."
+ icon_state = "seed-alien3"
+ mypath = "/obj/item/seeds/surik"
+ species = "surik"
+ plantname = "surik vine"
+ productname = "/obj/item/weapon/reagent_containers/food/snacks/grown/surik"
+ lifespan = 30
+ endurance = 18
+ maturation = 7
+ production = 7
+ yield = 3
+ potency = 3
+ growthstages = 4
+
+/obj/item/weapon/reagent_containers/food/snacks/grown/surik
+ name = "surik fruit"
+ desc = "Multiple layers of blue skin peeling away to reveal a spongey core, vaguely resembling an ear."
+ icon = 'icons/obj/xenoarchaeology.dmi'
+ icon_state = "surikfruit"
+ New(var/loc, var/potency)
+ ..()
+ reagents.add_reagent("impedrezene", potency * 3)
+ reagents.add_reagent("synaptizine", potency * 2)
+ reagents.add_reagent("nutriment", potency)
+ bitesize = 1+round(reagents.total_volume / 2, 1)
diff --git a/code/modules/research/xenoarchaeology/genetics/reconstitutor.dm b/code/modules/research/xenoarchaeology/genetics/reconstitutor.dm
new file mode 100644
index 00000000000..6bd699483dd
--- /dev/null
+++ b/code/modules/research/xenoarchaeology/genetics/reconstitutor.dm
@@ -0,0 +1,335 @@
+var/global/list/alphabet_uppercase = list("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z")
+var/list/genome_prefixes = list("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z")
+
+var/list/spawn_types_animal = list("/mob/living/carbon/slime",\
+"/mob/living/simple_animal/hostile/alien",\
+"/mob/living/simple_animal/hostile/alien/drone",\
+"/mob/living/simple_animal/hostile/alien/sentinel",\
+"/mob/living/simple_animal/hostile/giant_spider",\
+"/mob/living/simple_animal/hostile/giant_spider/hunter",\
+"/mob/living/simple_animal/hostile/giant_spider/nurse",\
+"/mob/living/simple_animal/hostile/creature",\
+"/mob/living/simple_animal/hostile/samak",\
+"/mob/living/simple_animal/hostile/diyaab",\
+"/mob/living/simple_animal/hostile/shantak",\
+"/mob/living/simple_animal/tindalos",\
+"/mob/living/simple_animal/yithian")
+
+var/list/spawn_types_plant = list("/obj/item/seeds/walkingmushroommycelium",\
+"/obj/item/seeds/killertomatoseed",\
+"/obj/item/seeds/shandseed",
+"/obj/item/seeds/mtearseed",
+"/obj/item/seeds/thaadra",\
+"/obj/item/seeds/telriis",\
+"/obj/item/seeds/jurlmah",\
+"/obj/item/seeds/amauri",\
+"/obj/item/seeds/gelthi",\
+"/obj/item/seeds/vale",\
+"/obj/item/seeds/surik")
+
+var/list/all_animal_genesequences = list()
+var/list/all_plant_genesequences = list()
+
+datum/genesequence
+ var/spawned_type
+ var/spawned_type_text
+ var/list/full_genome_sequence = list()
+
+/proc/create_all_genesequences()
+ //create animal gene sequences
+ while(spawn_types_animal.len && genome_prefixes.len)
+ var/datum/genesequence/new_sequence = new/datum/genesequence()
+ new_sequence.spawned_type_text = pick(spawn_types_animal)
+ new_sequence.spawned_type = text2path(new_sequence.spawned_type_text)
+ spawn_types_animal -= new_sequence.spawned_type
+
+ var/prefixletter = pick(genome_prefixes)
+ genome_prefixes -= prefixletter
+ while(new_sequence.full_genome_sequence.len < 7)
+ new_sequence.full_genome_sequence.Add("[prefixletter][pick(alphabet_uppercase)][pick(alphabet_uppercase)][pick(1,2,3,4,5,6,7,8,9,0)][pick(1,2,3,4,5,6,7,8,9,0)]")
+
+ all_animal_genesequences.Add(new_sequence)
+
+ //create plant gene sequences
+ while(spawn_types_plant.len && genome_prefixes.len)
+ var/datum/genesequence/new_sequence = new/datum/genesequence()
+ new_sequence.spawned_type = pick(spawn_types_plant)
+ spawn_types_plant -= new_sequence.spawned_type
+
+ var/prefixletter = pick(genome_prefixes)
+ genome_prefixes -= prefixletter
+ while(new_sequence.full_genome_sequence.len < 7)
+ new_sequence.full_genome_sequence.Add("[prefixletter][pick(1,2,3,4,5,6,7,8,9,0)][pick(1,2,3,4,5,6,7,8,9,0)][pick(alphabet_uppercase)][pick(alphabet_uppercase)]")
+
+ all_plant_genesequences.Add(new_sequence)
+
+
+
+/obj/machinery/computer/reconstitutor
+ name = "Flora reconstitution console"
+ icon = 'icons/obj/computer.dmi'
+ icon_state = "dna"
+ circuit = "/obj/item/weapon/circuitboard/reconstitutor"
+ req_access = list(access_heads) //Only used for record deletion right now.
+ var/obj/machinery/clonepod/pod1 = null //Linked cloning pod.
+ var/temp = ""
+ var/menu = 1 //Which menu screen to display
+ var/list/records = list()
+ var/datum/dna2/record/active_record = null
+ var/obj/item/weapon/disk/data/diskette = null //Mostly so the geneticist can steal everything.
+ var/loading = 0 // Nice loading text
+ var/list/undiscovered_genesequences = null
+ var/list/discovered_genesequences = list()
+ var/list/completed_genesequences = list()
+ var/list/undiscovered_genomes = list()
+ var/list/manually_placed_genomes = list()
+ var/list/discovered_genomes = list("! Clear !")
+ var/list/accepted_fossil_types = list(/obj/item/weapon/fossil/plant)
+
+/obj/machinery/computer/reconstitutor/New()
+ create_all_genesequences()
+ if(!undiscovered_genesequences)
+ undiscovered_genesequences = all_plant_genesequences.Copy()
+ ..()
+
+/obj/machinery/computer/reconstitutor/animal
+ name = "Fauna reconstitution console"
+ accepted_fossil_types = list(/obj/item/weapon/fossil/bone,/obj/item/weapon/fossil/shell,/obj/item/weapon/fossil/skull)
+
+/obj/machinery/computer/reconstitutor/animal/New()
+ create_all_genesequences()
+ undiscovered_genesequences = all_animal_genesequences.Copy()
+ ..()
+
+/obj/machinery/computer/reconstitutor/attackby(obj/item/W, mob/user)
+ if(istype(W,/obj/item/weapon/fossil))
+ user.drop_item()
+ W.loc = src.loc
+ switch(scan_fossil(W))
+ if(1)
+ src.visible_message("\red \icon[src] [src] scans the fossil and rejects it.")
+ if(2)
+ visible_message("\red \icon[src] can not extract any more genetic data from new fossils.")
+ if(4)
+ src.visible_message("\blue \icon[src] [user] inserts [W] into [src], the fossil is consumed.")
+ del(W)
+ updateDialog()
+ else if (istype(W, /obj/item/weapon/storage))
+ var/obj/item/weapon/storage/S = W
+ S.hide_from(usr)
+ var/numaccepted = 0
+ var/numrejected = 0
+ var/full = 0
+ for(var/obj/item/weapon/fossil/F in S.contents)
+ switch(scan_fossil(F))
+ if(1)
+ numrejected += 1
+ if(2)
+ full = 1
+ if(4)
+ numaccepted += 1
+ S.remove_from_storage(F, src) //This will move the item to this item's contents
+ del(F)
+ updateDialog()
+ var/outmsg = "\blue You empty all the fossils from [S] into [src]."
+ if(numaccepted)
+ outmsg += " \blue[numaccepted] fossils were accepted."
+ if(numrejected)
+ outmsg += " \red[numrejected] fossils were rejected."
+ if(full)
+ outmsg += " \red[src] can not extract any more genetic data from new fossils."
+ visible_message(outmsg)
+
+ else
+ ..()
+
+/obj/machinery/computer/reconstitutor/attack_hand(var/mob/user as mob)
+ src.add_fingerprint(user)
+ interact(user)
+
+/obj/machinery/computer/reconstitutor/interact(mob/user)
+ if(stat & (NOPOWER|BROKEN) || get_dist(src, user) > 1)
+ user.unset_machine(src)
+ return
+
+ var/dat = "Garland Corp genetic reconstitutor
"
+ dat += "
| GENE1 | " + dat += "GENE2 | " + dat += "GENE3 | " + dat += "GENE4 | " + dat += "GENE5 | " + dat += "GENE6 | " + dat += "GENE7 | " + dat += "" + dat += " | " + dat += " |
| [this_genome_slot] | " + dat += "Reset | " + //dat += "Clone | " + dat += "||||||
| [this_genome_slot] | " + dat += "Wipe | " + dat += "Clone | " + dat += "