diff --git a/vore/bee.dm b/code/modules/mob/living/simple_mob/subtypes/vore/bee.dm
similarity index 100%
rename from vore/bee.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/bee.dm
diff --git a/vore/catgirl.dm b/code/modules/mob/living/simple_mob/subtypes/vore/catgirl.dm
similarity index 100%
rename from vore/catgirl.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/catgirl.dm
diff --git a/vore/cookiegirl.dm b/code/modules/mob/living/simple_mob/subtypes/vore/cookiegirl.dm
similarity index 96%
rename from vore/cookiegirl.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/cookiegirl.dm
index 2e4fa8b378..af4636ef96 100644
--- a/vore/cookiegirl.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/cookiegirl.dm
@@ -1,53 +1,53 @@
-/mob/living/simple_mob/vore/cookiegirl
- name = "cookiegirl"
- desc = "A woman made with a combination of, well... Whatever you put in a cookie. What were the chefs thinking?"
-
- icon_state = "cookiegirl"
- icon_living = "cookiegirl"
- icon_rest = "cookiegirl_rest"
- icon_dead = "cookiegirl-dead"
- icon = 'icons/mob/vore.dmi'
-
- maxHealth = 10
- health = 10
-
- harm_intent_damage = 2
- melee_damage_lower = 5
- melee_damage_upper = 10
-
- say_list_type = /datum/say_list/cookiegirl
- ai_holder_type = /datum/ai_holder/simple_mob/passive/cookiegirl
-
- // Activate Noms!
-/mob/living/simple_mob/vore/cookiegirl
- vore_active = 1
- vore_bump_chance = 2
- vore_pounce_chance = 25
- vore_standing_too = 1
- vore_ignores_undigestable = 0 // Do they look like they care?
- vore_default_mode = DM_HOLD // They're cookiepeople, what do you expect?
- vore_digest_chance = 10 // Gonna become as sweet as sugar, soon.
- vore_icons = SA_ICON_LIVING | SA_ICON_REST
-
-/datum/ai_holder/simple_mob/passive/cookiegirl/on_hear_say(mob/living/speaker, message)
-
- if(!speaker.client)
- return
-
- if(findtext(message, "Can I eat you?"))
- delayed_say(pick("Do you really wanna eat someone as sweet as me~?"), speaker)
-
- if(findtext(message, "You look tasty."))
- delayed_say(pick("Awww, thank you~!"), speaker)
-
- if(findtext(message, "Can I serve you to the crew?"))
- delayed_say(pick("If I have a backup, sure!"), speaker)
-
-/datum/say_list/cookiegirl
- speak = list("Hi!","Are you hungry?","Got milk~?","What to do, what to do...")
- emote_hear = list("hums","whistles")
- emote_see = list("shakes her head","shivers", "picks a bit of crumb off of her body and sticks it in her mouth.")
-
-/datum/ai_holder/simple_mob/passive/cookiegirl
- base_wander_delay = 8
+/mob/living/simple_mob/vore/cookiegirl
+ name = "cookiegirl"
+ desc = "A woman made with a combination of, well... Whatever you put in a cookie. What were the chefs thinking?"
+
+ icon_state = "cookiegirl"
+ icon_living = "cookiegirl"
+ icon_rest = "cookiegirl_rest"
+ icon_dead = "cookiegirl-dead"
+ icon = 'icons/mob/vore.dmi'
+
+ maxHealth = 10
+ health = 10
+
+ harm_intent_damage = 2
+ melee_damage_lower = 5
+ melee_damage_upper = 10
+
+ say_list_type = /datum/say_list/cookiegirl
+ ai_holder_type = /datum/ai_holder/simple_mob/passive/cookiegirl
+
+ // Activate Noms!
+/mob/living/simple_mob/vore/cookiegirl
+ vore_active = 1
+ vore_bump_chance = 2
+ vore_pounce_chance = 25
+ vore_standing_too = 1
+ vore_ignores_undigestable = 0 // Do they look like they care?
+ vore_default_mode = DM_HOLD // They're cookiepeople, what do you expect?
+ vore_digest_chance = 10 // Gonna become as sweet as sugar, soon.
+ vore_icons = SA_ICON_LIVING | SA_ICON_REST
+
+/datum/ai_holder/simple_mob/passive/cookiegirl/on_hear_say(mob/living/speaker, message)
+
+ if(!speaker.client)
+ return
+
+ if(findtext(message, "Can I eat you?"))
+ delayed_say(pick("Do you really wanna eat someone as sweet as me~?"), speaker)
+
+ if(findtext(message, "You look tasty."))
+ delayed_say(pick("Awww, thank you~!"), speaker)
+
+ if(findtext(message, "Can I serve you to the crew?"))
+ delayed_say(pick("If I have a backup, sure!"), speaker)
+
+/datum/say_list/cookiegirl
+ speak = list("Hi!","Are you hungry?","Got milk~?","What to do, what to do...")
+ emote_hear = list("hums","whistles")
+ emote_see = list("shakes her head","shivers", "picks a bit of crumb off of her body and sticks it in her mouth.")
+
+/datum/ai_holder/simple_mob/passive/cookiegirl
+ base_wander_delay = 8
intelligence_level = AI_NORMAL //not sure why we have this, but I'm just porting.
\ No newline at end of file
diff --git a/vore/corrupt_hounds.dm b/code/modules/mob/living/simple_mob/subtypes/vore/corrupt_hounds.dm
similarity index 100%
rename from vore/corrupt_hounds.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/corrupt_hounds.dm
diff --git a/vore/deathclaw.dm b/code/modules/mob/living/simple_mob/subtypes/vore/deathclaw.dm
similarity index 100%
rename from vore/deathclaw.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/deathclaw.dm
diff --git a/vore/dino.dm b/code/modules/mob/living/simple_mob/subtypes/vore/dino.dm
similarity index 100%
rename from vore/dino.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/dino.dm
diff --git a/vore/dragon.dm b/code/modules/mob/living/simple_mob/subtypes/vore/dragon.dm
similarity index 100%
rename from vore/dragon.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/dragon.dm
diff --git a/vore/fennec.dm b/code/modules/mob/living/simple_mob/subtypes/vore/fennec.dm
similarity index 100%
rename from vore/fennec.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/fennec.dm
diff --git a/vore/fennix.dm b/code/modules/mob/living/simple_mob/subtypes/vore/fennix.dm
similarity index 96%
rename from vore/fennix.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/fennix.dm
index cbc2eb4af2..bcbb2d831f 100644
--- a/vore/fennix.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/fennix.dm
@@ -1,30 +1,30 @@
-/mob/living/simple_mob/vore/fennix
- name = "Fennix"
- desc = "A feral fennix, Warm to the touch"
- tt_desc = "Incaendium Faeles Vulpes"
-
- icon_state = "fennix"
- icon_living = "fennix"
- icon_dead = "fennix_dead"
- icon = 'icons/mob/vore.dmi'
-
- faction = "fennec" // Will protec other fenfens
- maxHealth = 60
- health = 60
-
- response_help = "pats the"
- response_disarm = "gently pushes aside the"
- response_harm = "hits the"
-
- harm_intent_damage = 20
- melee_damage_lower = 1
- melee_damage_upper = 5
- attacktext = list("Bites")
-
- say_list_type = /datum/say_list/fennix
- ai_holder_type = /datum/ai_holder/simple_mob/retaliate/cooperative
-
-/datum/say_list/fennix
- speak = list("SQUEL!","SQEL?","Skree.")
- emote_hear = list("Screeeeecheeeeessss!","Chirrup.")
- emote_see = list("earflicks","pats at the ground")
+/mob/living/simple_mob/vore/fennix
+ name = "Fennix"
+ desc = "A feral fennix, Warm to the touch"
+ tt_desc = "Incaendium Faeles Vulpes"
+
+ icon_state = "fennix"
+ icon_living = "fennix"
+ icon_dead = "fennix_dead"
+ icon = 'icons/mob/vore.dmi'
+
+ faction = "fennec" // Will protec other fenfens
+ maxHealth = 60
+ health = 60
+
+ response_help = "pats the"
+ response_disarm = "gently pushes aside the"
+ response_harm = "hits the"
+
+ harm_intent_damage = 20
+ melee_damage_lower = 1
+ melee_damage_upper = 5
+ attacktext = list("Bites")
+
+ say_list_type = /datum/say_list/fennix
+ ai_holder_type = /datum/ai_holder/simple_mob/retaliate/cooperative
+
+/datum/say_list/fennix
+ speak = list("SQUEL!","SQEL?","Skree.")
+ emote_hear = list("Screeeeecheeeeessss!","Chirrup.")
+ emote_see = list("earflicks","pats at the ground")
diff --git a/vore/frog.dm b/code/modules/mob/living/simple_mob/subtypes/vore/frog.dm
similarity index 100%
rename from vore/frog.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/frog.dm
diff --git a/vore/hippo.dm b/code/modules/mob/living/simple_mob/subtypes/vore/hippo.dm
similarity index 100%
rename from vore/hippo.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/hippo.dm
diff --git a/vore/horse.dm b/code/modules/mob/living/simple_mob/subtypes/vore/horse.dm
similarity index 100%
rename from vore/horse.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/horse.dm
diff --git a/vore/jelly.dm b/code/modules/mob/living/simple_mob/subtypes/vore/jelly.dm
similarity index 100%
rename from vore/jelly.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/jelly.dm
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/otie.dm b/code/modules/mob/living/simple_mob/subtypes/vore/otie.dm
new file mode 100644
index 0000000000..5de33d56b7
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/otie.dm
@@ -0,0 +1,400 @@
+// ToDo: Make this code not a fucking snowflaky horrible broken mess. Do not use until it's actually fixed. It's miserably bad right now.
+// Also ToDo: Dev-to-dev communication to ensure responsible parties (if available. In this case, yes.) are aware of what's going on and what's broken.
+// Probably easier to troubleshoot when we ain't breaking the server by spawning a buttload of heavily extra feature coded snowflake mobs to the wilderness as mass cannonfodder.
+// Also ToDo: An actual "simple" mob for that purpose if necessary :v
+
+/mob/living/simple_mob/otie //Spawn this one only if you're looking for a bad time. Not friendly.
+ name = "otie"
+ desc = "The classic bioengineered longdog."
+ tt_desc = "Otus robustus"
+ icon = 'icons/mob/vore64x32.dmi'
+ icon_state = "otie"
+ icon_living = "otie"
+ icon_dead = "otie-dead"
+ icon_rest = "otie_rest"
+ faction = "otie"
+ recruitable = 1
+ maxHealth = 150
+ health = 150
+ minbodytemp = 200
+ move_to_delay = 4
+ hostile = 1
+ investigates = 1
+ reacts = 1
+ animal = 1
+ specific_targets = 1
+ run_at_them = 0
+ attack_same = 0
+ speak_chance = 4
+ speak = list("Boof.","Waaf!","Prurr.","Bork!","Rurrr..","Arf.")
+ speak_emote = list("growls", "roars", "yaps", "Awoos")
+ emote_hear = list("rurrs", "rumbles", "rowls", "groans softly", "murrs", "sounds hungry", "yawns")
+ emote_see = list("stares ferociously", "snarls", "licks their chops", "stretches", "yawns")
+ say_maybe_target = list("Ruh?", "Waf?")
+ say_got_target = list("Rurrr!", "ROAR!", "MARR!", "RERR!", "RAHH!", "RAH!", "WARF!")
+ melee_damage_lower = 5
+ melee_damage_upper = 15 //Don't break my bones bro
+ response_help = "pets the"
+ response_disarm = "bops the"
+ response_harm = "hits the"
+ attacktext = list("mauled")
+ friendly = list("nuzzles", "slobberlicks", "noses softly at", "noseboops", "headbumps against", "leans on", "nibbles affectionately on")
+ meat_amount = 6
+ old_x = -16
+ old_y = 0
+ default_pixel_x = -16
+ pixel_x = -16
+ pixel_y = 0
+
+ max_buckled_mobs = 1 //Yeehaw
+ can_buckle = TRUE
+ buckle_movable = TRUE
+ buckle_lying = FALSE
+ mount_offset_y = 10
+
+ var/glowyeyes = FALSE
+ var/image/eye_layer = null
+ var/eyetype
+ var/mob/living/carbon/human/friend
+ var/tamed = 0
+ var/tame_chance = 50 //It's a fiddy-fiddy default you may get a buddy pal or you may get mauled and ate. Win-win!
+
+// Activate Noms!
+
+/mob/living/simple_mob/otie
+ vore_active = 1
+ vore_capacity = 1
+ vore_pounce_chance = 20
+ vore_icons = SA_ICON_LIVING | SA_ICON_REST
+
+/mob/living/simple_mob/otie/feral //gets the pet2tame feature. starts out hostile tho so get gamblin'
+ name = "mutated feral otie"
+ desc = "The classic bioengineered longdog. No pets. Only bite. This one has mutated from too much time out on the surface of Virgo-3B."
+ tt_desc = "Otus phoronis"
+ icon_state = "siftusian"
+ icon_living = "siftusian"
+ icon_dead = "siftusian-dead"
+ icon_rest = "siftusian_rest"
+ faction = "virgo3b"
+ tame_chance = 5 // Only a 1 in 20 chance of success. It's feral. What do you expect?
+ melee_damage_lower = 10
+ melee_damage_upper = 25
+ // Lazy way of making sure this otie survives outside.
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ glowyeyes = TRUE
+ eyetype = "photie"
+
+/mob/living/simple_mob/otie/red
+ name = "feral red otie"
+ desc = "Seems this ominous looking longdog has been infused with wicked infernal forces."
+ tt_desc = "Otus infernalis"
+ icon_state = "hotie"
+ icon_living = "hotie"
+ icon_dead = "hotie-dead"
+ icon_rest = "hotie_rest"
+ faction = "cult"
+ tame_chance = 20
+ melee_damage_lower = 10
+ melee_damage_upper = 25
+ // Lazy way of making sure this otie survives outside.
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ glowyeyes = TRUE
+ eyetype = "hotie"
+
+/mob/living/simple_mob/otie/red/friendly //gets the pet2tame feature and doesn't kill you right away
+ name = "red otie"
+ desc = "Seems this ominous looking longdog has been infused with wicked infernal forces. This one seems rather peaceful though."
+ faction = "neutral"
+ tamed = 1
+
+/mob/living/simple_mob/otie/friendly //gets the pet2tame feature and doesn't kill you right away
+ name = "otie"
+ desc = "The classic bioengineered longdog. This one might even tolerate you!"
+ faction = "neutral"
+ tamed = 1
+
+/mob/living/simple_mob/otie/cotie //same as above but has a little collar :v
+ name = "tamed otie"
+ desc = "The classic bioengineered longdog. This one has a nice little collar on its neck. However a proper domesticated otie is an oxymoron and the collar is likely just a decoration."
+ icon_state = "cotie"
+ icon_living = "cotie"
+ icon_rest = "cotie_rest"
+ faction = "neutral"
+ tamed = 1
+
+/mob/living/simple_mob/otie/cotie/phoron //friendly phoron pup with collar
+ name = "mutated otie"
+ desc = "Looks like someone did manage to domesticate one of those wild phoron mutants. What a badass."
+ tt_desc = "Otus phoronis"
+ icon_state = "pcotie"
+ icon_living = "pcotie"
+ icon_rest = "pcotie_rest"
+ icon_dead = "siftusian-dead"
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ glowyeyes = TRUE
+ eyetype = "photie"
+
+/mob/living/simple_mob/otie/security //tame by default unless you're a marked crimester. can be befriended to follow with pets tho.
+ name = "guard otie"
+ desc = "The VARMAcorp bioengineering division flagship product on trained optimal snowflake guard dogs."
+ icon_state = "sotie"
+ icon_living = "sotie"
+ icon_rest = "sotie_rest"
+ icon_dead = "sotie-dead"
+ faction = "neutral"
+ maxHealth = 200 //armored or something
+ health = 200
+ tamed = 1
+ glowyeyes = TRUE
+ eyetype = "sotie"
+ loot_list = list(/obj/item/clothing/glasses/sunglasses/sechud,/obj/item/clothing/suit/armor/vest/alt)
+ vore_pounce_chance = 60 // Good boys don't do too much police brutality.
+
+ var/check_records = 0 // If true, arrests people without a record.
+ var/check_arrest = 1 // If true, arrests people who are set to arrest.
+
+/mob/living/simple_mob/otie/security/phoron
+ name = "mutated guard otie"
+ desc = "An extra rare phoron resistant version of the VARMAcorp trained snowflake guard dogs."
+ tt_desc = "Otus phoronis"
+ icon_state = "sifguard"
+ icon_living = "sifguard"
+ icon_rest = "sifguard_rest"
+ icon_dead = "sifguard-dead"
+ melee_damage_lower = 10
+ melee_damage_upper = 25
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ glowyeyes = TRUE
+ eyetype = "sotie"
+
+/mob/living/simple_mob/otie/PunchTarget()
+ if(istype(target_mob,/mob/living/simple_mob/mouse))
+ return EatTarget()
+ else ..()
+
+/mob/living/simple_mob/otie/Found(var/atom/found_atom)
+ if(!SA_attackable(found_atom))
+ return null
+ if(istype(found_atom,/mob/living/simple_mob/mouse))
+ return found_atom
+ else if(ismob(found_atom))
+ var/mob/found_mob = found_atom
+ if(found_mob.faction == faction)
+ return null
+ else if(friend == found_atom)
+ return null
+ else if(tamed == 1 && ishuman(found_atom))
+ return null
+ else if(tamed == 1 && isrobot(found_atom))
+ return null
+ else
+ if(resting)
+ lay_down()
+ return found_atom
+ else
+ return null
+
+/mob/living/simple_mob/otie/security/Found(var/atom/found_atom)
+ if(check_threat(found_atom) >= 4)
+ if(resting)
+ lay_down()
+ return found_atom
+ ..()
+
+/mob/living/simple_mob/otie/attackby(var/obj/item/O, var/mob/user) // Trade donuts for bellybrig victims.
+ if(istype(O, /obj/item/weapon/reagent_containers/food))
+ qdel(O)
+ playsound(src.loc,'sound/items/eatfood.ogg', rand(10,50), 1)
+ if(ai_inactive)//No autobarf on player control.
+ return
+ if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/donut) && istype(src, /mob/living/simple_mob/otie/security))
+ to_chat(user,"The guard pup accepts your offer for their catch.")
+ release_vore_contents()
+ else if(prob(2)) //Small chance to get prey out from non-sec oties.
+ to_chat(user,"The pup accepts your offer for their catch.")
+ release_vore_contents()
+ return
+ . = ..()
+
+/mob/living/simple_mob/otie/security/feed_grabbed_to_self(var/mob/living/user, var/mob/living/prey) // Make the gut start out safe for bellybrigging.
+ if(ishuman(prey))
+ vore_selected.digest_mode = DM_HOLD
+ if(check_threat(prey) >= 4)
+ global_announcer.autosay("[src] has detained suspect [target_name(prey)] in [get_area(src)].", "SmartCollar oversight", "Security")
+ if(istype(prey,/mob/living/simple_mob/mouse))
+ vore_selected.digest_mode = DM_DIGEST
+ . = ..()
+
+/mob/living/simple_mob/otie/security/proc/check_threat(var/mob/living/M)
+ if(!M || !ishuman(M) || M.stat == DEAD || src == M)
+ return 0
+ return M.assess_perp(0, 0, 0, check_records, check_arrest)
+
+/mob/living/simple_mob/otie/security/set_target(var/mob/M)
+ ai_log("SetTarget([M])",2)
+ if(!M || (world.time - last_target_time < 5 SECONDS) && target_mob)
+ ai_log("SetTarget() can't set it again so soon",3)
+ return 0
+
+ var/turf/seen = get_turf(M)
+
+ if(investigates && (annoyed < 10))
+ try_say_list(say_maybe_target)
+ face_atom(seen)
+ annoyed += 14
+ sleep(1 SECOND) //For realism
+
+ if(M in ListTargets(view_range))
+ try_say_list(say_got_target)
+ target_mob = M
+ last_target_time = world.time
+ if(check_threat(M) >= 4)
+ global_announcer.autosay("[src] is attempting to detain suspect [target_name(M)] in [get_area(src)].", "SmartCollar oversight", "Security")
+ return M
+ else if(investigates)
+ spawn(1)
+ WanderTowards(seen)
+
+ return 0
+
+
+/mob/living/simple_mob/otie/security/proc/target_name(mob/living/T)
+ if(ishuman(T))
+ var/mob/living/carbon/human/H = T
+ return H.get_id_name("unidentified person")
+ return "unidentified lifeform"
+
+//Basic friend AI
+
+/mob/living/simple_mob/otie/Life()
+ . = ..()
+ if(!. || ai_inactive) return
+
+ if(prob(5) && (stance == STANCE_IDLE))
+ lay_down()
+
+ if(!friend) return
+
+ var/friend_dist = get_dist(src,friend)
+
+ if (friend_dist <= 4)
+ if(stance == STANCE_IDLE)
+ if(set_follow(friend))
+ handle_stance(STANCE_FOLLOW)
+ if(resting)
+ lay_down()
+
+ if (friend_dist <= 1)
+ if (friend.stat >= DEAD || friend.health <= config.health_threshold_softcrit)
+ if (prob((friend.stat < DEAD)? 50 : 15))
+ var/verb = pick("whines", "yelps", "whimpers")
+ audible_emote(pick("[verb] in distress.", "[verb] anxiously."))
+ else
+ if (prob(5))
+ visible_emote(pick("nuzzles [friend].",
+ "brushes against [friend].",
+ "rubs against [friend].",
+ "noses at [friend].",
+ "slobberlicks [friend].",
+ "murrs contently.",
+ "leans on [friend].",
+ "nibbles affectionately on [friend]."))
+ else if (friend.health <= 50)
+ if (prob(10))
+ var/verb = pick("whines", "yelps", "whimpers")
+ audible_emote("[verb] anxiously.")
+
+//Pet 4 friendly
+
+/mob/living/simple_mob/otie/attack_hand(mob/living/carbon/human/M as mob)
+
+ switch(M.a_intent)
+ if(I_HELP)
+ if(health > 0)
+ M.visible_message("[M] [response_help] \the [src].")
+ if(ai_inactive)
+ return
+ LoseTarget()
+ handle_stance(STANCE_IDLE)
+ if(prob(tame_chance))
+ friend = M
+ if(tamed != 1)
+ tamed = 1
+ faction = M.faction
+ sleep(1 SECOND)
+
+ if(I_GRAB)
+ if(health > 0)
+ if(ai_inactive)
+ return
+ audible_emote("growls disapprovingly at [M].")
+ if(M == friend)
+ friend = null
+ return
+ else
+ ..()
+
+ else
+ ..()
+
+/mob/living/simple_mob/otie/proc/add_eyes()
+ if(!eye_layer)
+ eye_layer = image(icon, "[eyetype]-eyes")
+ eye_layer.plane = PLANE_LIGHTING_ABOVE
+ add_overlay(eye_layer)
+
+/mob/living/simple_mob/otie/proc/remove_eyes()
+ cut_overlay(eye_layer)
+
+/mob/living/simple_mob/otie/New()
+ if(glowyeyes)
+ add_eyes()
+ ..()
+
+/mob/living/simple_mob/otie/update_icon()
+ . = ..()
+ remove_eyes()
+ if(glowyeyes && stat == CONSCIOUS && !resting)
+ add_eyes()
+
+/mob/living/simple_mob/otie/death(gibbed, deathmessage = "dies!")
+ .=..()
+ resting = 0
+ icon_state = icon_dead
+
+/mob/living/simple_animal/otie/Login()
+ . = ..()
+ if(!riding_datum)
+ riding_datum = new /datum/riding/simple_animal(src)
+ verbs |= /mob/living/simple_animal/proc/animal_mount
+
+/mob/living/simple_animal/otie/MouseDrop_T(mob/living/M, mob/living/user)
+ return
\ No newline at end of file
diff --git a/vore/panther.dm b/code/modules/mob/living/simple_mob/subtypes/vore/panther.dm
similarity index 100%
rename from vore/panther.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/panther.dm
diff --git a/vore/rat.dm b/code/modules/mob/living/simple_mob/subtypes/vore/rat.dm
similarity index 100%
rename from vore/rat.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/rat.dm
diff --git a/vore/redpanda.dm b/code/modules/mob/living/simple_mob/subtypes/vore/redpanda.dm
similarity index 100%
rename from vore/redpanda.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/redpanda.dm
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/_defines.dm b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/_defines.dm
new file mode 100644
index 0000000000..1567134c4d
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/_defines.dm
@@ -0,0 +1,13 @@
+#define NOT_WHILE_SHIFTED 1
+#define ONLY_WHILE_SHIFTED 2
+#define SHIFTED_OR_NOT 3
+
+#define BLUE_EYES 1
+#define RED_EYES 2
+#define PURPLE_EYES 3
+#define YELLOW_EYES 4
+#define GREEN_EYES 5
+#define ORANGE_EYES 6
+
+#define AB_PHASE_SHIFTED 0x1
+#define AB_SHADE_REGEN 0x2
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/ability_objects.dm b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/ability_objects.dm
new file mode 100644
index 0000000000..6990623043
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/ability_objects.dm
@@ -0,0 +1,165 @@
+/obj/effect/shadekin_ability
+ name = ""
+ desc = ""
+ icon = 'icons/mob/screen_spells.dmi'
+ var/ability_name = "FIX ME"
+ var/cost = 50
+ var/mob/living/simple_mob/shadekin/my_kin
+ var/shift_mode = NOT_WHILE_SHIFTED
+ var/ab_sound
+
+/obj/effect/shadekin_ability/New(var/new_kin)
+ ..()
+ my_kin = new_kin
+ loc = null
+
+/obj/effect/shadekin_ability/Destroy()
+ my_kin = null
+ return ..()
+
+/obj/effect/shadekin_ability/proc/atom_button_text()
+ var/shift_denial
+
+ if(shift_mode == NOT_WHILE_SHIFTED && (my_kin.ability_flags & AB_PHASE_SHIFTED))
+ shift_denial = "Physical Only"
+ else if(shift_mode == ONLY_WHILE_SHIFTED && !(my_kin.ability_flags & AB_PHASE_SHIFTED))
+ shift_denial = "Shifted Only"
+
+ if(shift_denial)
+ name = shift_denial
+ else
+ name = my_kin.energy >= cost ? "Activate" : "No Energy"
+ return src
+
+/obj/effect/shadekin_ability/Click(var/location, var/control, var/params)
+ if(my_kin.stat) return
+
+ var/list/clickprops = params2list(params)
+ var/opts = clickprops["shift"]
+
+ if(opts)
+ to_chat(my_kin,"[name] (Cost: [cost]%) - [desc]")
+ else
+ do_ability(my_kin)
+
+/obj/effect/shadekin_ability/proc/do_ability()
+ if(my_kin.stat)
+ to_chat(my_kin,"Can't use that ability in your state!")
+ return FALSE
+ if(shift_mode == NOT_WHILE_SHIFTED && (my_kin.ability_flags & AB_PHASE_SHIFTED))
+ to_chat(my_kin,"Can't use that ability while phase shifted!")
+ return FALSE
+ else if(shift_mode == ONLY_WHILE_SHIFTED && !(my_kin.ability_flags & AB_PHASE_SHIFTED))
+ to_chat(my_kin,"Can only use that ability while phase shifted!")
+ return FALSE
+ else if(my_kin.energy < cost)
+ to_chat(my_kin,"Not enough energy for that ability!")
+ return FALSE
+
+ my_kin.energy -= cost
+ if(ab_sound)
+ playsound(src,ab_sound,75,1)
+
+ return TRUE
+
+/////////////////////////////////////////////////////////////////
+/obj/effect/shadekin_ability/phase_shift
+ ability_name = "Phase Shift"
+ desc = "Shift yourself out of alignment with realspace to travel quickly between dark areas (or light areas, with a price)."
+ icon_state = "tech_passwall"
+ cost = 100
+ shift_mode = SHIFTED_OR_NOT
+ ab_sound = 'sound/effects/stealthoff.ogg'
+/obj/effect/shadekin_ability/phase_shift/do_ability()
+ if(!..())
+ return
+ my_kin.phase_shift()
+ if(my_kin.ability_flags & AB_PHASE_SHIFTED)
+ cost = 0 //Shifting back is free (but harmful in light)
+ else
+ cost = initial(cost)
+/////////////////////////////////////////////////////////////////
+/obj/effect/shadekin_ability/heal_boop
+ ability_name = "Regenerate Other"
+ desc = "Spend energy to heal physical wounds in another creature."
+ icon_state = "tech_biomedaura"
+ cost = 50
+ shift_mode = NOT_WHILE_SHIFTED
+ ab_sound = 'sound/effects/EMPulse.ogg'
+/obj/effect/shadekin_ability/heal_boop/do_ability()
+ if(!..())
+ return
+ if(!my_kin.mend_other())
+ my_kin.energy += cost //Refund due to abort
+
+/datum/modifier/shadekin/heal_boop
+ name = "Shadekin Regen"
+ desc = "You feel serene and well rested."
+ mob_overlay_state = "green_sparkles"
+
+ on_created_text = "Sparkles begin to appear around you, and all your ills seem to fade away."
+ on_expired_text = "The sparkles have faded, although you feel much healthier than before."
+ stacks = MODIFIER_STACK_EXTEND
+
+/datum/modifier/shadekin/heal_boop/tick()
+ if(!holder.getBruteLoss() && !holder.getFireLoss() && !holder.getToxLoss() && !holder.getOxyLoss() && !holder.getCloneLoss()) // No point existing if the spell can't heal.
+ expire()
+ return
+ holder.adjustBruteLoss(-2)
+ holder.adjustFireLoss(-2)
+ holder.adjustToxLoss(-2)
+ holder.adjustOxyLoss(-2)
+ holder.adjustCloneLoss(-2)
+/////////////////////////////////////////////////////////////////
+/obj/effect/shadekin_ability/create_shade
+ ability_name = "Create Shade"
+ desc = "Create a field of darkness that follows you."
+ icon_state = "tech_dispelold"
+ cost = 25
+ shift_mode = NOT_WHILE_SHIFTED
+ ab_sound = 'sound/effects/bamf.ogg'
+/obj/effect/shadekin_ability/create_shade/do_ability()
+ if(!..())
+ return
+ my_kin.add_modifier(/datum/modifier/shadekin/create_shade,20 SECONDS)
+/datum/modifier/shadekin/create_shade
+ name = "Shadekin Shadegen"
+ desc = "Darkness envelops you."
+ mob_overlay_state = ""
+
+ on_created_text = "You drag part of The Dark into realspace, enveloping yourself."
+ on_expired_text = "You lose your grasp on The Dark and realspace reasserts itself."
+ stacks = MODIFIER_STACK_EXTEND
+ var/mob/living/simple_mob/shadekin/my_kin
+
+/datum/modifier/shadekin/create_shade/tick()
+ if(my_kin.ability_flags & AB_PHASE_SHIFTED)
+ expire()
+
+/datum/modifier/shadekin/create_shade/on_applied()
+ my_kin = holder
+ holder.glow_toggle = TRUE
+ holder.glow_range = 8
+ holder.glow_intensity = -10
+ holder.glow_color = "#FFFFFF"
+ holder.set_light(8, -10, "#FFFFFF")
+
+/datum/modifier/shadekin/create_shade/on_expire()
+ holder.glow_toggle = initial(holder.glow_toggle)
+ holder.glow_range = initial(holder.glow_range)
+ holder.glow_intensity = initial(holder.glow_intensity)
+ holder.glow_color = initial(holder.glow_color)
+ holder.set_light(0)
+ my_kin = null
+/*
+/////////////////////////////////////////////////////////////////
+/obj/effect/shadekin_ability/energy_feast
+ ability_name = "Devour Energy"
+ desc = "Devour the energy from another creature (potentially fatal)."
+ icon_state = "gen_eat"
+ cost = 25
+ shift_mode = NOT_WHILE_SHIFTED
+/obj/effect/shadekin_ability/energy_feast/do_ability()
+ if(!..())
+ return
+*/
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/ability_procs.dm b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/ability_procs.dm
new file mode 100644
index 0000000000..0be707f852
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/ability_procs.dm
@@ -0,0 +1,133 @@
+// Phase shifting procs (and related procs)
+/mob/living/simple_mob/shadekin/proc/phase_shift()
+ var/turf/T = get_turf(src)
+ if(!T.CanPass(null,T) || loc != T)
+ to_chat(src,"You can't use that here!")
+ return FALSE
+
+ forceMove(T)
+ var/original_canmove = canmove
+ SetStunned(0)
+ SetWeakened(0)
+ if(buckled)
+ buckled.unbuckle_mob()
+ if(pulledby)
+ pulledby.stop_pulling()
+ stop_pulling()
+ canmove = FALSE
+
+ //Shifting in
+ if(ability_flags & AB_PHASE_SHIFTED)
+ ability_flags &= ~AB_PHASE_SHIFTED
+ name = real_name
+ for(var/belly in vore_organs)
+ var/obj/belly/B = belly
+ B.escapable = initial(B.escapable)
+
+ overlays.Cut()
+ alpha = initial(alpha)
+ invisibility = initial(invisibility)
+ see_invisible = initial(see_invisible)
+ incorporeal_move = initial(incorporeal_move)
+ density = initial(density)
+ force_max_speed = initial(force_max_speed)
+
+ //Cosmetics mostly
+ flick("tp_in",src)
+ custom_emote(1,"phases in!")
+ sleep(5) //The duration of the TP animation
+ canmove = original_canmove
+
+ //Potential phase-in vore
+ if(can_be_drop_pred) //Toggleable in vore panel
+ var/list/potentials = living_mobs(0)
+ if(potentials.len)
+ var/mob/living/target = pick(potentials)
+ if(istype(target) && vore_selected)
+ target.forceMove(vore_selected)
+ to_chat(target,"\The [src] phases in around you, [vore_selected.vore_verb]ing you into their [vore_selected.name]!")
+
+ // Do this after the potential vore, so we get the belly
+ update_icon()
+
+ //Affect nearby lights
+ var/destroy_lights = 0
+ if(eye_state == RED_EYES)
+ destroy_lights = 80
+ if(eye_state == PURPLE_EYES)
+ destroy_lights = 25
+
+ for(var/obj/machinery/light/L in machines)
+ if(L.z != z || get_dist(src,L) > 10)
+ continue
+
+ if(prob(destroy_lights))
+ spawn(rand(5,25))
+ L.broken()
+ else
+ L.flicker(10)
+
+ //Shifting out
+ else
+ ability_flags |= AB_PHASE_SHIFTED
+ custom_emote(1,"phases out!")
+ real_name = name
+ name = "Something"
+
+ for(var/belly in vore_organs)
+ var/obj/belly/B = belly
+ B.escapable = FALSE
+
+ overlays.Cut()
+ flick("tp_out",src)
+ sleep(5)
+ invisibility = INVISIBILITY_LEVEL_TWO
+ see_invisible = INVISIBILITY_LEVEL_TWO
+ update_icon()
+ alpha = 127
+
+ canmove = original_canmove
+ incorporeal_move = TRUE
+ density = FALSE
+ force_max_speed = TRUE
+
+/mob/living/simple_mob/shadekin/UnarmedAttack()
+ if(ability_flags & AB_PHASE_SHIFTED)
+ return FALSE //Nope.
+
+ . = ..()
+
+/mob/living/simple_mob/shadekin/can_fall()
+ if(ability_flags & AB_PHASE_SHIFTED)
+ return FALSE //Nope!
+
+ return ..()
+
+/mob/living/simple_mob/shadekin/zMove(direction)
+ if(ability_flags & AB_PHASE_SHIFTED)
+ var/turf/destination = (direction == UP) ? GetAbove(src) : GetBelow(src)
+ if(destination)
+ forceMove(destination)
+ return TRUE
+
+ return ..()
+
+// Healing others
+/mob/living/simple_mob/shadekin/proc/mend_other()
+ //I hate to crunch a view() but I only want ones I can see
+ var/list/viewed = oview(1)
+ var/list/targets = list()
+ for(var/mob/living/L in viewed)
+ targets += L
+ if(!targets.len)
+ to_chat(src,"Nobody nearby to mend!")
+ return FALSE
+
+ var/mob/living/target = input(src,"Pick someone to mend:","Mend Other") as null|anything in targets
+ if(!target)
+ return FALSE
+
+ target.add_modifier(/datum/modifier/shadekin/heal_boop,1 MINUTE)
+ visible_message("\The [src] gently places a hand on \the [target]...")
+ face_atom(target)
+ return TRUE
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/shadekin.dm b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/shadekin.dm
new file mode 100644
index 0000000000..7b151161be
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/shadekin.dm
@@ -0,0 +1,447 @@
+/mob/living/simple_mob/shadekin //Spawning the prototype spawns a random one, see initialize()
+ name = "shadekin"
+ desc = "Some sort of fluffer. Big ears, long tail."
+ icon = 'icons/mob/vore_shadekin.dmi'
+ icon_state = "map_example"
+ icon_living = "map_example"
+ faction = "shadekin"
+ ui_icons = 'icons/mob/shadekin_hud.dmi'
+ intelligence_level = SA_HUMANOID
+
+ maxHealth = 200
+ health = 200
+
+ move_to_delay = 2
+ speed = -1
+ see_in_dark = 10 //SHADEkin
+ has_hands = TRUE //Pawbs
+ seedarkness = FALSE //SHAAAADEkin
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+ has_langs = list(LANGUAGE_GALCOM,LANGUAGE_SHADEKIN)
+
+ investigates = TRUE
+ reacts = TRUE
+ run_at_them = FALSE
+ cooperative = FALSE
+
+ melee_damage_lower = 10
+ melee_damage_upper = 20
+
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ minbodytemp = 0
+ maxbodytemp = 900
+
+ speak_chance = 2
+ speak = list("Marrr.", "Marrr?", "Marrr!")
+ emote_hear = list("chrrrrrs", "wurbles", "wrrrrbles")
+ emote_see = list("tailtwitches", "earflicks")
+ say_maybe_target = list("...mar?")
+ say_got_target = list("MAR!!!")
+ response_help = "pets the"
+ response_disarm = "bops the"
+ response_harm = "hits the"
+ attacktext = list("mauled","slashed","clawed")
+ friendly = list("boops", "pawbs", "mars softly at", "sniffs on")
+ reactions = list("Mar?" = "Marrr!", "Mar!" = "Marrr???", "Mar." = "Marrr.")
+
+ vore_active = TRUE
+ vore_pounce_chance = 10
+ vore_icons = SA_ICON_LIVING
+ swallowTime = 2 SECONDS
+ vore_escape_chance = 25
+
+ //None, they stay as their defaults.
+ vore_digest_chance = 0
+ vore_absorb_chance = 0
+ vore_bump_chance = 0 //They follow people, this would be DENGEROUS
+
+ var/eye_state = RED_EYES //Eye color/energy gain/loss mode
+ var/eye_icon_state = null //Default, changed in init
+ var/eye_desc //Eye color description added to examine
+
+ var/mob/living/carbon/human/henlo_human //Human we're stalking currently
+
+ //Behavior
+ var/stalker = TRUE //Do we creep up on humans
+ var/shy_approach = FALSE //Do we creep up slowly on humans to boop them
+
+ //Icon handling
+ var/image/tailimage //Cached tail image
+
+ //Darknesssss
+ var/energy = 100 //For abilities
+ var/energy_adminbuse = FALSE //For adminbuse infinite energy
+ var/dark_gains = 0 //Last tick's change in energy
+ var/ability_flags = 0 //Flags for active abilities
+ var/obj/screen/darkhud //Holder to update this icon
+ var/obj/screen/energyhud //Holder to update this icon
+
+ var/list/shadekin_abilities
+
+/mob/living/simple_mob/shadekin/initialize()
+ //You spawned the prototype, and want a totally random one.
+ if(type == /mob/living/simple_mob/shadekin)
+
+ //I'm told by VerySoft these are the liklihood values
+ var/list/sk_types = list(
+ /mob/living/simple_mob/shadekin/red = 20, //Actively seek people out to nom, so fairly common to see (relatively speaking),
+ /mob/living/simple_mob/shadekin/blue = 15, //Explorers that like to interact with people, so still fairly common,
+ /mob/living/simple_mob/shadekin/purple = 15, //Also explorers that may or may not homf people,
+ /mob/living/simple_mob/shadekin/yellow = 1 //Very rare, usually never leaves their home
+ )
+ var/new_type = pickweight(sk_types)
+
+ new new_type(loc)
+ initialized = TRUE
+ return INITIALIZE_HINT_QDEL
+
+ if(icon_state == "map_example")
+ icon_state = pick("white","dark","brown")
+
+ icon_living = icon_state
+
+ switch(eye_state)
+ if(BLUE_EYES)
+ eye_icon_state = "e_blue"
+ if(RED_EYES)
+ eye_icon_state = "e_red"
+ if(PURPLE_EYES)
+ eye_icon_state = "e_purple"
+ if(YELLOW_EYES)
+ eye_icon_state = "e_yellow"
+ if(GREEN_EYES)
+ eye_icon_state = "e_green"
+ if(ORANGE_EYES)
+ eye_icon_state = "e_orange"
+ else
+ eye_icon_state = "e_red"
+
+ tailimage = image('icons/mob/vore_shadekin64.dmi',null,icon_state)
+ tailimage.pixel_x = -16
+
+ if(eye_desc)
+ desc += " This one has [eye_desc]!"
+
+ var/list/ability_types = subtypesof(/obj/effect/shadekin_ability)
+ shadekin_abilities = list()
+ for(var/type in ability_types)
+ shadekin_abilities += new type(src)
+
+ update_icon()
+
+ return ..()
+
+/mob/living/simple_mob/shadekin/Destroy()
+ QDEL_NULL_LIST(shadekin_abilities)
+ . = ..()
+
+/mob/living/simple_mob/shadekin/init_vore()
+ if(LAZYLEN(vore_organs))
+ return
+
+ var/obj/belly/B = new /obj/belly(src)
+ vore_selected = B
+ B.immutable = 1
+ B.name = vore_stomach_name ? vore_stomach_name : "stomach"
+ B.desc = vore_stomach_flavor ? vore_stomach_flavor : "Your surroundings are warm, soft, and slimy. Makes sense, considering you're inside \the [name]."
+ B.digest_mode = vore_default_mode
+ B.escapable = vore_escape_chance > 0
+ B.escapechance = vore_escape_chance
+ B.digestchance = vore_digest_chance
+ B.absorbchance = vore_absorb_chance
+ B.human_prey_swallow_time = swallowTime
+ B.nonhuman_prey_swallow_time = swallowTime
+ B.vore_verb = "swallow"
+ // TODO - Customizable per mob
+ B.emote_lists[DM_HOLD] = list(
+ "The walls gently squeeze against you. The wet sounds of shifting flesh against your form fill the air.",
+ "The hot, humid air rushes around you for a moment as the creature urps. The walls clench in around you for a moment, before relaxing again.",
+ "Your body is soaked in the fluids that cling to the churning walls. They squeeze across your form gently, conforming to your shape.",
+ "You can feel the world around you shift and sway as the creature moves! The flesh is stretchy, doughy. You can sink into it a little ways before it bounces back, curling you into a small shape."
+ )
+ B.emote_lists[DM_DIGEST] = list(
+ "The walls slop thick slime across your body! It tingles briefly before the sting and ache sets in!",
+ "The sound of your body slipping and sliding against the powerfully churning stomach fills the air!",
+ "The grip of that stomach is harsh. Eagerly mushing and rubbing that slime into your body in attempts to break you down!",
+ "The intense churning and grinding jostles your around within the thick slime as you're slowly broken down!"
+ )
+ B.emote_lists[DM_ABSORB] = list(
+ "The walls cling to you awfully close... It's almost like you're sinking into them.",
+ "You can feel the walls press in tightly against you, clinging to you posessively!",
+ "It almost feels like you're sinking into the soft, doughy flesh!",
+ "You can feel the walls press in around you. Almost molten, so squishy!!"
+ )
+ B.emote_lists[DM_DRAIN] = list(
+ "The walls churn down on you heavily!! It's hard to move!",
+ "You can feel yourself getting weaker with every moment! The doughy walls sap your strength!",
+ "You're practically smothered in the oppressive heat of the creature's stomach!",
+ "It's hot, wet and tight!"
+ )
+ B.emote_lists[DM_HEAL] = list(
+ "The walls pulse against you almost rhythmically. It feels nice, almost like a massage.",
+ "You're gently squeezed in pleasant warmth, softly churned.",
+ "The doughy feel of the heavy flesh clinging to you makes you feel a little stronger with every passing moment.",
+ "The flesh caresses across your body gently as you're held."
+ )
+ B.digest_messages_prey = list(
+ "Your body is steadily softened more and more over time! Eventually you pass out. The creature's stomach rumbles powerfully as you are reduced to paste, processed for energy!",
+ "The creature's slimy gut lets out a heavy groan as you're slowly melted away. Gushing deeper through the creature.",
+ "The stinging and aching gives way to numbness as you're slowly smothered out. Your body is steadily reduced to nutrients and energy for the creature to continue on its way.",
+ "The chaos of being digested fades as you're snuffed out by a harsh clench! You're steadily broken down into a thick paste, processed and absorbed by the predator!"
+ )
+
+/mob/living/simple_mob/shadekin/Life()
+ . = ..()
+ if(ability_flags & AB_PHASE_SHIFTED)
+ density = FALSE
+
+ //Convert spare nutrition into energy at a certain ratio
+ if(. && nutrition > initial(nutrition) && energy < 100)
+ nutrition = max(0, nutrition-5)
+ energy = min(100,energy+1)
+
+/mob/living/simple_mob/shadekin/update_icon()
+ . = ..()
+
+ cut_overlay(tailimage)
+
+ tailimage.icon_state = icon_state
+
+ add_overlay(tailimage)
+ add_overlay(eye_icon_state)
+
+/mob/living/simple_mob/shadekin/Stat()
+ . = ..()
+ if(statpanel("Shadekin"))
+ abilities_stat()
+
+/mob/living/simple_mob/shadekin/proc/abilities_stat()
+ for(var/A in shadekin_abilities)
+ var/obj/effect/shadekin_ability/ability = A
+ stat("[ability.ability_name]",ability.atom_button_text())
+
+//They phase back to the dark when killed
+/mob/living/simple_mob/shadekin/death(gibbed, deathmessage = "phases to somewhere far away!")
+ overlays = list()
+ icon_state = ""
+ flick("tp_out",src)
+ spawn(1 SECOND)
+ qdel(src) //Back from whence you came!
+
+ . = ..(FALSE, deathmessage)
+
+//Blue-eyes want to nom people to heal them
+/mob/living/simple_mob/shadekin/Found(var/atom/A)
+ if(specific_targets && isliving(A)) //Healing!
+ var/mob/living/L = A
+ var/health_percent = (L.health/L.maxHealth)*100
+ if(health_percent <= 50 && will_eat(A))
+ return A
+ . = ..()
+
+//They reach nutritional equilibrium (important for blue-eyes healbelly)
+/mob/living/simple_mob/shadekin/Life()
+ if((. = ..()))
+ handle_shade()
+
+/mob/living/simple_mob/shadekin/proc/handle_shade()
+ //Shifted kin don't gain/lose energy (and save time if we're at the cap)
+ var/darkness = 1
+
+
+ var/turf/T = get_turf(src)
+ if(!T)
+ dark_gains = 0
+ return
+
+ var/brightness = T.get_lumcount() //Brightness in 0.0 to 1.0
+ darkness = 1-brightness //Invert
+
+ if(ability_flags & AB_PHASE_SHIFTED)
+ dark_gains = 0
+ else
+ //Heal (very) slowly in good darkness
+ if(darkness >= 0.75)
+ adjustFireLoss(-0.05)
+ adjustBruteLoss(-0.05)
+ adjustToxLoss(-0.05)
+
+ switch(eye_state)
+ //Blue has constant, steady (slow) regen and ignores darkness.
+ if(BLUE_EYES)
+ dark_gains = 0.5
+ //Red has extremely tiny energy buildup in dark, none in light, and hunts for energy.
+ if(RED_EYES)
+ if(darkness >= 0.75)
+ dark_gains = 0.25
+ //Purple eyes have moderate gains in darkness and loss in light.
+ if(PURPLE_EYES)
+ dark_gains = round((darkness - 0.5) * 2, 0.1)
+ //Yellow has extreme gains in darkness and loss in light.
+ if(YELLOW_EYES)
+ dark_gains = round((darkness - 0.5) * 4, 0.1)
+ //Similar to blues, but passive is less, and affected by dark
+ if(GREEN_EYES)
+ dark_gains = 0.25
+ dark_gains += round((darkness - 0.5), 0.1)
+ //More able to get energy out of the dark, worse attack gains tho
+ if(ORANGE_EYES)
+ if(darkness >= 0.65)
+ dark_gains = 0.30
+
+ energy = max(0,min(initial(energy),energy + dark_gains))
+
+ if(energy_adminbuse)
+ energy = 100
+
+ //Update turf darkness hud
+ if(darkhud)
+ switch(darkness)
+ if(0.80 to 1.00)
+ darkhud.icon_state = "dark2"
+ if(0.60 to 0.80)
+ darkhud.icon_state = "dark1"
+ if(0.40 to 0.60)
+ darkhud.icon_state = "dark"
+ if(0.20 to 0.40)
+ darkhud.icon_state = "dark-1"
+ if(0.00 to 0.20)
+ darkhud.icon_state = "dark-2"
+
+ //Update energy storage hud
+ if(energyhud)
+ switch(energy)
+ if(80 to INFINITY)
+ energyhud.icon_state = "energy0"
+ if(60 to 80)
+ energyhud.icon_state = "energy1"
+ if(40 to 60)
+ energyhud.icon_state = "energy2"
+ if(20 to 40)
+ energyhud.icon_state = "energy3"
+ if(0 to 20)
+ energyhud.icon_state = "energy4"
+
+//Friendly ones wander towards people, maybe shy-ly if they are set to shy
+/mob/living/simple_mob/shadekin/handle_wander_movement()
+ if(isturf(src.loc) && !resting && !buckled && canmove)
+ lifes_since_move++
+ if(lifes_since_move >= turns_per_move)
+ if(!(stop_when_pulled && pulledby))
+ var/moving_to
+
+ if(stalker)
+ //Sniff sniff.
+ var/list/humans = human_mobs(world.view)
+
+ //Can we see the last person we were following?
+ if(henlo_human && !(henlo_human in humans))
+ henlo_human = null
+
+ //Can we find a new person to follow?
+ if(!henlo_human)
+ while(!henlo_human && humans.len)
+ henlo_human = pick(humans)
+ if(!isturf(henlo_human.loc))
+ humans -= henlo_human
+ henlo_human = null
+
+ //Boopable hunam?
+ if(henlo_human)
+ moving_to = get_dir(src,henlo_human)
+
+ if((get_dist(src,henlo_human) <= 1))
+ dir = moving_to
+ if(prob(speak_chance))
+ visible_message("\The [src] [pick(friendly)] \the [henlo_human].")
+ shy_approach = FALSE //ACCLIMATED
+ lifes_since_move = 0
+ return //No need to move
+
+ if(shy_approach)
+ var/them_to_us = turn(moving_to,180)
+ if(abs(dir2angle(henlo_human.dir) - dir2angle(them_to_us)) <= 90)
+ dir = them_to_us
+ return //AAA!
+
+ dir = moving_to
+
+ //Random walk
+ if(!moving_to)
+ moving_to = pick(cardinal)
+ dir = moving_to
+
+ var/turf/T = get_step(src,moving_to)
+ if(avoid_turf(T))
+ return
+ Move(T)
+ lifes_since_move = 0
+
+/mob/living/simple_mob/shadekin/speech_bubble_appearance()
+ return "ghost"
+
+/mob/living/simple_mob/shadekin/DoPunch(var/atom/A)
+ . = ..(A)
+ if(isliving(A)) //We punched something!
+ var/mob/living/L = A
+ if(L.stat != DEAD)
+ var/gains = 0
+ switch(eye_state)
+ if(RED_EYES)
+ gains = 8
+ if(BLUE_EYES)
+ gains = 1
+ if(PURPLE_EYES)
+ gains = 4
+ if(YELLOW_EYES)
+ gains = 3
+ if(GREEN_EYES)
+ gains = 1
+ if(ORANGE_EYES)
+ gains = 5
+
+ energy += gains
+
+//Special hud elements for darkness and energy gains
+/mob/living/simple_mob/shadekin/extra_huds(var/datum/hud/hud,var/icon/ui_style,var/list/hud_elements)
+ //Darkness hud
+ darkhud = new /obj/screen()
+ darkhud.icon = ui_style
+ darkhud.icon_state = "dark"
+ darkhud.name = "darkness"
+ darkhud.screen_loc = "CENTER-2:16,SOUTH:5" //Left of the left hand
+ darkhud.alpha = 150
+ hud_elements |= darkhud
+
+ //Energy hud
+ energyhud = new /obj/screen()
+ energyhud.icon = ui_style
+ energyhud.icon_state = "energy0"
+ energyhud.name = "energy"
+ energyhud.screen_loc = "CENTER+1:16,SOUTH:5" //Right of the right hand
+ energyhud.alpha = 150
+ hud_elements |= energyhud
+
+// When someone clicks us with an empty hand
+/mob/living/simple_mob/shadekin/attack_hand(mob/living/carbon/human/M as mob)
+ . = ..()
+ if(M.a_intent == I_HELP)
+ shy_approach = FALSE //ACCLIMATED
+
+/datum/language/shadekin
+ name = "Shadekin Empathy"
+ desc = "Shadekin seem to always know what the others are thinking. This is probably why."
+ colour = "changeling"
+ speech_verb = "mars"
+ ask_verb = "mars"
+ exclaim_verb = "mars"
+ key = "m"
+ machine_understands = 0
+ flags = WHITELISTED | HIVEMIND
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/types.dm b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/types.dm
new file mode 100644
index 0000000000..ea7a9b0f2c
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/types.dm
@@ -0,0 +1,256 @@
+/////////////////////////////////////////////////////////////////
+/mob/living/simple_mob/shadekin/red
+ name = "red-eyed shadekin"
+ eye_state = RED_EYES
+ hostile = TRUE
+ animal = TRUE
+ stop_when_pulled = FALSE
+ destroy_surroundings = TRUE
+ armor = list(
+ "melee" = 30,
+ "bullet" = 20,
+ "laser" = 20,
+ "energy" = 50,
+ "bomb" = 10,
+ "bio" = 100,
+ "rad" = 100)
+
+ eye_desc = "red eyes"
+
+ vore_stomach_flavor = "You slip past pointy triangle teeth and down the slick, \
+ slippery gullet of the creature. It's warm, and the air is thick. You can hear \
+ its body squelch and shift around you as you settle into its stomach! Thick digestive \
+ enzymes cling to you within that dark space, tingling and stinging immediately! The weight of \
+ the doughy walls press in around you instantly, churning you up as you begin to digest!"
+
+ player_msg = "You hunt for energy to fuel yourself, not minding in the least \
+ if you strip it off unsuspecting prey. You're stronger than other shadekin, faster, and more capable in \
+ a brawl, but you barely generate any of your own energy. You can stand in a dark spot to gather scraps \
+ of energy in a pinch, but otherwise need to take it, by force if necessary."
+
+/mob/living/simple_mob/shadekin/red/white
+ icon_state = "white"
+/mob/living/simple_mob/shadekin/red/dark
+ icon_state = "dark"
+/mob/living/simple_mob/shadekin/red/brown
+ icon_state = "brown"
+
+/////////////////////////////////////////////////////////////////
+/mob/living/simple_mob/shadekin/blue
+ name = "blue-eyed shadekin"
+ eye_state = BLUE_EYES
+ health = 100
+ hostile = FALSE
+ animal = FALSE
+ stop_when_pulled = TRUE
+ specific_targets = TRUE //For finding injured people
+ destroy_surroundings = FALSE
+ vore_default_mode = DM_HEAL
+ vore_escape_chance = 75
+ vore_standing_too = 1
+ vore_pounce_chance = 100
+ swallowTime = 4 SECONDS //A little longer to compensate for the above
+ vore_ignores_undigestable = FALSE
+ attacktext = list("shoved")
+ armor = list(
+ "melee" = 5,
+ "bullet" = 5,
+ "laser" = 5,
+ "energy" = 5,
+ "bomb" = 0,
+ "bio" = 100,
+ "rad" = 100)
+
+ eye_desc = "blue eyes"
+ shy_approach = TRUE
+ stalker = TRUE
+ vore_stomach_flavor = "You slip past pointy triangle teeth and down the slick, \
+ slippery gullet of the creature. It's warm, and the air is thick. You can hear its body \
+ squelch and shift around you as you settle into its stomach! It's oddly calm, and very dark. \
+ The doughy flesh rolls across your form in gentle waves. The aches and pains across your form slowly begin to \
+ diminish, your body is healing much faster than normal! You're also soon soaked in harmless slime."
+
+ player_msg = "You've chosen to generate your own energy rather than taking \
+ it from others. Most of the time, anyway. You don't have a need to steal energy from others, and gather it up \
+ without doing so, albeit slowly. Dark and light are irrelevant to you, they are just different places to explore and \
+ discover new things and new people."
+
+/mob/living/simple_mob/shadekin/blue/white
+ icon_state = "white"
+/mob/living/simple_mob/shadekin/blue/dark
+ icon_state = "dark"
+/mob/living/simple_mob/shadekin/blue/brown
+ icon_state = "brown"
+
+/////////////////////////////////////////////////////////////////
+/mob/living/simple_mob/shadekin/purple
+ name = "purple-eyed shadekin"
+ eye_state = PURPLE_EYES
+ health = 150
+ hostile = FALSE
+ animal = TRUE
+ stop_when_pulled = FALSE
+ destroy_surroundings = TRUE
+ vore_default_mode = DM_HOLD
+ vore_digest_chance = 25
+ vore_absorb_chance = 25
+ armor = list(
+ "melee" = 15,
+ "bullet" = 15,
+ "laser" = 15,
+ "energy" = 15,
+ "bomb" = 15,
+ "bio" = 100,
+ "rad" = 100)
+
+ eye_desc = "purple eyes"
+ shy_approach = TRUE
+ stalker = TRUE
+ vore_stomach_flavor = "You slip past pointy triangle teeth and down the slick, slippery gullet of the creature. \
+ It's warm, and the air is thick. You can hear its body squelch and shift around you as you settle into its stomach! \
+ It's relatively calm inside the dark organ. Wet and almost molten for how gooey your surroundings feel. \
+ You can feel the doughy walls cling to you posessively... It's almost like you could sink into them. \
+ There is also an ominous gurgling from somewhere nearby..."
+
+ player_msg = "You're familiar with generating your own energy, but occasionally \
+ steal it from others when it suits you. You generate energy at a moderate pace in dark areas, and staying in well-lit \
+ areas is taxing on your energy. You can harvest energy from others in a fight, but since you don't need to, you may \
+ just choose to simply not fight."
+
+/mob/living/simple_mob/shadekin/purple/white
+ icon_state = "white"
+/mob/living/simple_mob/shadekin/purple/dark
+ icon_state = "dark"
+/mob/living/simple_mob/shadekin/purple/brown
+ icon_state = "brown"
+
+/////////////////////////////////////////////////////////////////
+/mob/living/simple_mob/shadekin/yellow
+ name = "yellow-eyed shadekin"
+ eye_state = YELLOW_EYES
+ health = 100
+ hostile = FALSE
+ animal = TRUE
+ stop_when_pulled = FALSE
+ destroy_surroundings = TRUE
+ vore_default_mode = DM_DRAIN
+ vore_digest_chance = 5
+ vore_ignores_undigestable = FALSE
+ armor = list(
+ "melee" = 5,
+ "bullet" = 5,
+ "laser" = 5,
+ "energy" = 5,
+ "bomb" = 0,
+ "bio" = 100,
+ "rad" = 100)
+
+ eye_desc = "yellow eyes"
+ stalker = FALSE
+ vore_stomach_flavor = "You slip past pointy triangle teeth and down the slick, slippery gullet \
+ of the creature. It's warm, and the air is thick. You can hear its body squelch and shift around you \
+ as you settle into its stomach! The doughy walls within cling to you heavily, churning down on you, wearing \
+ you out!! There doesn't appear to be any actual danger here, harmless slime clings to you, but it's getting \
+ harder and harder to move as those walls press in on you insistently!"
+
+ player_msg = "Your kind rarely ventures into realspace. Being in any well-lit \
+ area is very taxing on you, but you gain energy extremely fast in any very dark area. You're weaker than other \
+ shadekin, but your fast energy generation in the dark allows you to phase shift more often."
+
+/mob/living/simple_mob/shadekin/yellow/white
+ icon_state = "white"
+/mob/living/simple_mob/shadekin/yellow/dark
+ icon_state = "dark"
+/mob/living/simple_mob/shadekin/yellow/brown
+ icon_state = "brown"
+
+/////////////////////////////////////////////////////////////////
+/mob/living/simple_mob/shadekin/green
+ name = "green-eyed shadekin"
+ eye_state = GREEN_EYES
+ health = 125
+ hostile = FALSE
+ animal = TRUE
+ stop_when_pulled = FALSE
+ destroy_surroundings = TRUE
+ vore_default_mode = DM_DRAIN
+ vore_digest_chance = 0
+ vore_ignores_undigestable = FALSE
+ armor = list(
+ "melee" = 5,
+ "bullet" = 5,
+ "laser" = 5,
+ "energy" = 5,
+ "bomb" = 0,
+ "bio" = 100,
+ "rad" = 100)
+
+ eye_desc = "green eyes"
+ stalker = TRUE
+ vore_stomach_flavor = "You slip past pointy triangle teeth and down the slick, slippery gullet \
+ of the creature. It's warm, and the air is thick. You can hear its body squelch and shift around you \
+ as you settle into its stomach! The doughy walls within cling to you heavily, churning down on you, wearing \
+ you out!! There doesn't appear to be any actual danger here, harmless slime clings to you, but it's getting \
+ harder and harder to move as those walls press in on you insistently!"
+
+ player_msg = "Your kind rarely ventures into realspace. Being in any well-lit area is very taxing on you, but you \
+ have more experience than your yellow-eyed cousins. You gain energy decently fast in any very dark area. You're weaker than other \
+ shadekin, but your slight energy generation constnatly, and especially in the dark allows for a good mix of uses."
+
+/mob/living/simple_mob/shadekin/green/white
+ icon_state = "white"
+/mob/living/simple_mob/shadekin/green/dark
+ icon_state = "dark"
+/mob/living/simple_mob/shadekin/green/brown
+ icon_state = "brown"
+
+/////////////////////////////////////////////////////////////////
+/mob/living/simple_mob/shadekin/orange
+ name = "orange-eyed shadekin"
+ eye_state = ORANGE_EYES
+ health = 175
+ hostile = TRUE
+ animal = TRUE
+ stop_when_pulled = FALSE
+ destroy_surroundings = TRUE
+ armor = list(
+ "melee" = 20,
+ "bullet" = 15,
+ "laser" = 15,
+ "energy" = 25,
+ "bomb" = 10,
+ "bio" = 100,
+ "rad" = 100)
+
+ eye_desc = "orange eyes"
+
+ vore_stomach_flavor = "You slip past pointy triangle teeth and down the slick, \
+ slippery gullet of the creature. It's warm, and the air is thick. You can hear \
+ its body squelch and shift around you as you settle into its stomach! Thick digestive \
+ enzymes cling to you within that dark space, tingling and stinging immediately! The weight of \
+ the doughy walls press in around you instantly, churning you up as you begin to digest!"
+
+ player_msg = "You usually hunt for energy to fuel yourself, though not as often as your red-eyed cousins. \
+ You're stronger than most shadekin, faster, and more capable in a brawl, but you don't generate much of your own energy. \
+ You can stand in a dark spot to gather some energy, but otherwise need to take it, by force if necessary."
+
+/mob/living/simple_mob/shadekin/orange/white
+ icon_state = "white"
+/mob/living/simple_mob/shadekin/orange/dark
+ icon_state = "dark"
+/mob/living/simple_mob/shadekin/orange/brown
+ icon_state = "brown"
+
+/////////////////////////////////////////////////////////////////
+//Fluffy specific fluffer
+/mob/living/simple_mob/shadekin/blue/rivyr
+ name = "Rivyr"
+ desc = "She appears to be a fluffer of some sort. Deep blue eyes and curious attitude."
+ icon_state = "rivyr"
+ eye_desc = ""
+ vore_stomach_flavor = "Blue flesh gleams in the fading light as you slip down the little mar's gullet! \
+ Gooey flesh and heat surrounds your form as you're tucked away into the darkness of her stomach! Thick slimes cling \
+ to you, but they seem to be harmless. The organ gently churns around you, clinging to your shape and forcing \
+ you to curl up a bit. You can feel her rub at you some through the layers of flesh and fluff, while aches \
+ and pains begin to fade away across your body."
+ player_msg = "Mar? Mar mar. Mar mar mar. Mar. Mar mar? Mar! Mar. Marrrr."
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/~defines.dm b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/~defines.dm
new file mode 100644
index 0000000000..28ce75c50b
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/~defines.dm
@@ -0,0 +1,11 @@
+#undef NOT_WHILE_SHIFTED
+#undef ONLY_WHILE_SHIFTED
+#undef SHIFTED_OR_NOT
+
+#undef BLUE_EYES
+#undef RED_EYES
+#undef PURPLE_EYES
+#undef YELLOW_EYES
+
+#undef AB_PHASE_SHIFTED
+#undef AB_SHADE_REGEN
\ No newline at end of file
diff --git a/vore/snake.dm b/code/modules/mob/living/simple_mob/subtypes/vore/snake.dm
similarity index 100%
rename from vore/snake.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/snake.dm
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/solargrub.dm b/code/modules/mob/living/simple_mob/subtypes/vore/solargrub.dm
new file mode 100644
index 0000000000..8444d55538
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/solargrub.dm
@@ -0,0 +1,108 @@
+/*
+A work in progress, lore will go here later.
+List of things solar grubs should be able to do:
+
+2. have three stages of growth depending on time. (Or energy drained altho that seems like a hard one to code)
+3. be capable of eating people that get knocked out. (also be able to shock attackers that don’t wear insulated gloves.)
+5. ((potentially use digested people to reproduce))
+6. add glow?
+*/
+
+#define SINK_POWER 1
+
+/mob/living/simple_mob/animal/space/solargrub
+ name = "juvenile solargrub"
+ desc = "A young sparkling solargrub"
+ icon = 'icons/mob/vore.dmi' //all of these are placeholders
+ icon_state = "solargrub"
+ icon_living = "solargrub"
+ icon_dead = "solargrub-dead"
+
+ faction = "grubs"
+ maxHealth = 50 //grubs can take a lot of harm
+ health = 50
+
+ melee_damage_lower = 1
+ melee_damage_upper = 5
+
+ speed = 2
+
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/grubmeat
+
+ response_help = "pokes"
+ response_disarm = "pushes"
+ response_harm = "roughly pushes"
+
+ var/poison_per_bite = 5 //grubs cause a shock when they bite someone
+ var/poison_type = "shockchem"
+ var/poison_chance = 50
+ var/datum/powernet/PN // Our powernet
+ var/obj/structure/cable/attached // the attached cable
+ var/emp_chance = 20 // Beware synths
+
+/datum/say_list/solargrub
+ emote_see = list("squelches", "squishes")
+/* //Commented out pending reworks - 2/2/19
+/mob/living/simple_mob/animal/solargrub/PunchTarget()
+ if(target_mob&& prob(emp_chance))
+ target_mob.emp_act(4) //The weakest strength of EMP
+ visible_message("The grub releases a powerful shock!")
+ ..()
+
+/mob/living/simple_mob/animal/solargrub/Life()
+ . = ..()
+ if(!. || ai_inactive) return
+
+ if(stance == STANCE_IDLE)
+ //first, check for potential cables nearby to powersink
+ var/turf/S = loc
+ attached = locate() in S
+ if(attached)
+ if(prob(2))
+ src.visible_message("\The [src] begins to sink power from the net.")
+ if(prob(5))
+ var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread()
+ sparks.set_up(5, 0, get_turf(src))
+ sparks.start()
+ anchored = 1
+ PN = attached.powernet
+ PN.draw_power(100000) // previous value 150000
+ var/apc_drain_rate = 750 //Going to see if grubs are better as a minimal bother. previous value : 4000
+ for(var/obj/machinery/power/terminal/T in PN.nodes)
+ if(istype(T.master, /obj/machinery/power/apc))
+ var/obj/machinery/power/apc/A = T.master
+ if(A.operating && A.cell)
+ var/cur_charge = A.cell.charge / CELLRATE
+ var/drain_val = min(apc_drain_rate, cur_charge)
+ A.cell.use(drain_val * CELLRATE)
+ else if(!attached && anchored)
+ anchored = 0
+ PN = null
+*/
+/mob/living/simple_mob/animal/solargrub //active noms
+ vore_bump_chance = 50
+ vore_bump_emote = "applies minimal effort to try and slurp up"
+ vore_active = 1
+ vore_capacity = 1
+ vore_pounce_chance = 0 //grubs only eat incapacitated targets
+ vore_default_mode = DM_DIGEST
+/*
+/mob/living/simple_mob/animal/solargrub/PunchTarget()
+ . = ..()
+ if(isliving(.))
+ var/mob/living/L = .
+ if(L.reagents)
+ if(prob(poison_chance))
+ L << "You feel a shock rushing through your veins."
+ L.reagents.add_reagent(poison_type, poison_per_bite) */
+
+/mob/living/simple_mob/animal/solargrub/death()
+ src.anchored = 0
+ set_light(0)
+ ..()
+
+/mob/living/simple_mob/animal/solargrub/handle_light()
+ . = ..()
+ if(. == 0 && !is_dead())
+ set_light(2.5, 1, COLOR_YELLOW)
+ return 1
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/solargrub_larva.dm b/code/modules/mob/living/simple_mob/subtypes/vore/solargrub_larva.dm
new file mode 100644
index 0000000000..898a3d2757
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/solargrub_larva.dm
@@ -0,0 +1,256 @@
+var/global/list/grub_machine_overlays = list()
+
+/mob/living/simple_mob/solargrub_larva
+ name = "solargrub larva"
+ desc = "A tiny wormy thing that can grow to massive sizes under the right conditions."
+ icon = 'icons/mob/vore.dmi'
+ icon_state = "grublarva"
+ icon_living = "grublarva"
+ icon_dead = "grublarva-dead"
+
+ health = 5
+ maxHealth = 5
+
+ meat_amount = 2
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/grubmeat
+
+ faction = "grubs"
+
+ response_help = "pats"
+ response_disarm = "nudges"
+ response_harm = "stomps on"
+
+ mob_size = MOB_MINISCULE
+ pass_flags = PASSTABLE
+ can_pull_size = ITEMSIZE_TINY
+ can_pull_mobs = MOB_PULL_NONE
+ density = 0
+
+ stop_when_pulled = 0
+
+ var/static/list/ignored_machine_types = list(
+ /obj/machinery/atmospherics/unary/vent_pump,
+ /obj/machinery/atmospherics/unary/vent_scrubber,
+ /obj/machinery/door/firedoor
+ )
+
+ var/obj/machinery/atmospherics/unary/vent_pump/target_vent
+
+ var/datum/effect/effect/system/spark_spread/sparks
+ var/image/machine_effect
+
+ var/obj/machinery/abstract_grub_machine/powermachine
+ var/power_drained = 0
+ var/forced_out = 0
+
+/mob/living/simple_mob/solargrub_larva/New()
+ ..()
+ powermachine = new(src)
+ sparks = new(src)
+ sparks.set_up()
+ sparks.attach(src)
+ verbs += /mob/living/proc/ventcrawl
+
+/mob/living/simple_mob/solargrub_larva/death()
+ powermachine.draining = 0
+ set_light(0)
+ return ..()
+
+/mob/living/simple_mob/solargrub_larva/Destroy()
+ QDEL_NULL(powermachine)
+ QDEL_NULL(sparks)
+ QDEL_NULL(machine_effect)
+ target_vent = null
+ return ..()
+
+/mob/living/simple_mob/solargrub_larva/Life()
+ . = ..()
+
+ if(machine_effect && !istype(loc, /obj/machinery))
+ QDEL_NULL(machine_effect)
+
+ if(!. || ai_inactive)
+ return
+
+ if(power_drained >= 7 MEGAWATTS && prob(5))
+ expand_grub()
+ return
+
+ if(istype(loc, /obj/machinery))
+ if(machine_effect && air_master.current_cycle%30)
+ for(var/mob/M in player_list)
+ M << machine_effect
+ if(prob(10))
+ sparks.start()
+ return
+
+ if(stance == STANCE_IDLE)
+ if(forced_out)
+ forced_out = Clamp(0, forced_out--, forced_out)
+ return
+
+ if(target_vent)
+ if(Adjacent(target_vent))
+ spawn()
+ do_ventcrawl(target_vent)
+ target_vent = null
+ else
+ target_vent = null
+ stop_automated_movement = 0
+ walk(src, 0)
+ return
+
+ if(prob(20))
+ var/list/possible_machines = list()
+ for(var/obj/machinery/M in orange(1,src))
+ if(!Adjacent(M))
+ continue
+ if(istype(M, /obj/machinery/power/apc) || istype(M, /obj/machinery/power/smes)) //APCs and SMES units don't actually use power, but it's too thematic to ignore them
+ possible_machines += M
+ continue
+ if(is_type_in_list(M, ignored_machine_types))
+ continue
+ if(!M.idle_power_usage && !M.active_power_usage) //If it can't use power at all, ignore it
+ continue
+ possible_machines += M
+ if(possible_machines.len)
+ enter_machine(pick(possible_machines))
+ return
+
+ if(prob(10))
+ var/list/vents = list()
+ for(var/obj/machinery/atmospherics/unary/vent_pump/vent in view(7,src))
+ if(vent.welded)
+ continue
+ vents += vent
+ if(vents.len)
+ var/picked = pick(vents)
+ target_vent = picked
+ WanderTowards(get_turf(picked))
+ return
+
+/mob/living/simple_mob/solargrub_larva/proc/enter_machine(var/obj/machinery/M)
+ if(!istype(M))
+ return
+ forceMove(M)
+ powermachine.draining = 2
+ visible_message("\The [src] finds an opening and crawls inside \the [M].")
+ if(!(M.type in grub_machine_overlays))
+ generate_machine_effect(M)
+ machine_effect = image(grub_machine_overlays[M.type], M) //Can't do this the reasonable way with an overlay,
+ for(var/mob/L in player_list) //because nearly every machine updates its icon by removing all overlays first
+ L << machine_effect
+
+/mob/living/simple_mob/solargrub_larva/proc/generate_machine_effect(var/obj/machinery/M)
+ var/icon/I = new /icon(M.icon, M.icon_state)
+ I.Blend(new /icon('icons/effects/blood.dmi', rgb(255,255,255)),ICON_ADD)
+ I.Blend(new /icon('icons/effects/alert.dmi', "_red"),ICON_MULTIPLY)
+ grub_machine_overlays[M.type] = I
+
+/mob/living/simple_mob/solargrub_larva/proc/eject_from_machine(var/obj/machinery/M)
+ if(!M)
+ if(istype(loc, /obj/machinery))
+ M = loc
+ else
+ return
+ forceMove(get_turf(M))
+ sparks.start()
+ if(machine_effect)
+ QDEL_NULL(machine_effect)
+ forced_out += rand(5,15)
+ powermachine.draining = 1
+
+/mob/living/simple_mob/solargrub_larva/proc/do_ventcrawl(var/obj/machinery/atmospherics/unary/vent_pump/vent)
+ if(!vent)
+ return
+ var/obj/machinery/atmospherics/unary/vent_pump/end_vent = get_safe_ventcrawl_target(vent)
+ if(!end_vent)
+ return
+ forceMove(vent)
+ playsound(vent, 'sound/machines/ventcrawl.ogg', 50, 1, -3)
+ vent.visible_message("\The [src] wiggles into \the [vent]!")
+ var/redirect_attempts = 3
+ while(redirect_attempts)
+ var/travel_time = round(get_dist(get_turf(src), get_turf(end_vent)) / 2)
+ sleep(travel_time)
+ if(end_vent.welded)
+ end_vent = get_safe_ventcrawl_target(vent)
+ if(!end_vent)
+ forceMove(get_turf(vent))
+ return
+ redirect_attempts--
+ continue
+ break
+ playsound(end_vent, 'sound/machines/ventcrawl.ogg', 50, 1, -3)
+ forceMove(get_turf(end_vent))
+
+/mob/living/simple_mob/solargrub_larva/proc/expand_grub()
+ eject_from_machine()
+ visible_message("\The [src] suddenly balloons in size!")
+ new /mob/living/simple_mob/animal/solargrub(get_turf(src))
+// var/mob/living/simple_mob/animal/solargrub/grub = new(get_turf(src))
+// grub.power_drained = power_drained //TODO
+ qdel(src)
+
+/mob/living/simple_mob/solargrub_larva/handle_light()
+ . = ..()
+ if(. == 0 && !is_dead())
+ set_light(1.5, 1, COLOR_YELLOW)
+ return 1
+
+
+/obj/machinery/abstract_grub_machine
+ var/total_active_power_usage = 45 KILOWATTS
+ var/list/active_power_usages = list(15 KILOWATTS, 15 KILOWATTS, 15 KILOWATTS)
+ var/total_idle_power_usage = 3 KILOWATTS
+ var/list/idle_power_usages = list(1 KILOWATTS, 1 KILOWATTS, 1 KILOWATTS)
+ var/draining = 1
+ var/mob/living/simple_mob/solargrub_larva/grub
+
+/obj/machinery/abstract_grub_machine/New()
+ ..()
+ shuffle_power_usages()
+ grub = loc
+ if(!istype(grub))
+ grub = null
+ qdel(src)
+
+/obj/machinery/abstract_grub_machine/Destroy()
+ grub = null
+ return ..()
+
+/obj/machinery/abstract_grub_machine/process()
+ if(!draining)
+ return
+ var/area/A = get_area(src)
+ if(!A)
+ return
+ var/list/power_list
+ switch(draining)
+ if(1)
+ power_list = idle_power_usages
+ if(2)
+ power_list = active_power_usages
+ for(var/i = 1 to power_list.len)
+ if(A.powered(i))
+ use_power(power_list[i], i)
+ grub.power_drained += power_list[i]
+ if(prob(5))
+ shuffle_power_usages()
+
+/obj/machinery/abstract_grub_machine/proc/shuffle_power_usages()
+ total_active_power_usage = rand(30 KILOWATTS, 60 KILOWATTS)
+ total_idle_power_usage = rand(1 KILOWATTS, 5 KILOWATTS)
+ active_power_usages = split_into_3(total_active_power_usage)
+ idle_power_usages = split_into_3(total_idle_power_usage)
+
+
+/obj/item/device/multitool/afterattack(obj/O, mob/user, proximity)
+ if(proximity)
+ if(istype(O, /obj/machinery))
+ var/mob/living/simple_mob/solargrub_larva/grub = locate() in O
+ if(grub)
+ grub.eject_from_machine(O)
+ to_chat(user, "You disturb a grub nesting in \the [O]!")
+ return
+ return ..()
diff --git a/vore/wolf.dm b/code/modules/mob/living/simple_mob/subtypes/vore/wolf.dm
similarity index 100%
rename from vore/wolf.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/wolf.dm
diff --git a/vore/wolfgirl.dm b/code/modules/mob/living/simple_mob/subtypes/vore/wolfgirl.dm
similarity index 100%
rename from vore/wolfgirl.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/wolfgirl.dm
diff --git a/vore/zz_vore_overrides.dm b/code/modules/mob/living/simple_mob/subtypes/vore/zz_vore_overrides.dm
similarity index 100%
rename from vore/zz_vore_overrides.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/zz_vore_overrides.dm
diff --git a/code/modules/ventcrawl/ventcrawl.dm b/code/modules/ventcrawl/ventcrawl.dm
index 5cef7f694a..87459904e1 100644
--- a/code/modules/ventcrawl/ventcrawl.dm
+++ b/code/modules/ventcrawl/ventcrawl.dm
@@ -9,10 +9,10 @@ var/list/ventcrawl_machinery = list(
/obj/item/device/radio/borg,
/obj/item/weapon/holder,
/obj/machinery/camera,
- ///mob/living/simple_mob/borer, //VORESTATION AI TEMPORARY REMOVAL //VOREStation Edit
- /obj/belly, //VOREStation Edit,
+ /obj/belly, //VOREStation Edit
/obj/screen
)
+ //mob/living/simple_mob/borer, //VORESTATION AI TEMPORARY REMOVAL REPLACE BACK IN LIST WHEN RESOLVED //VOREStation Edit
/mob/living/var/list/icon/pipes_shown = list()
/mob/living/var/last_played_vent
diff --git a/code/modules/xenoarcheaology/artifacts/autocloner.dm b/code/modules/xenoarcheaology/artifacts/autocloner.dm
index c5e89a7b51..5d70e62752 100644
--- a/code/modules/xenoarcheaology/artifacts/autocloner.dm
+++ b/code/modules/xenoarcheaology/artifacts/autocloner.dm
@@ -25,9 +25,9 @@
/mob/living/simple_mob/animal/giant_spider/nurse,
/mob/living/simple_mob/animal/space/alien,
/mob/living/simple_mob/animal/space/bear,
- // /mob/living/simple_mob/carp, // Vorestation edit //VORESTATION AI TEMPORARY REMOVAL
/mob/living/simple_mob/creature,
/mob/living/simple_mob/slime/xenobio)
+ // /mob/living/simple_mob/carp, // Vorestation edit //VORESTATION AI TEMPORARY REMOVAL, REPLACE BACK IN LIST WHEN FIXED
else
spawn_type = pick(\
/mob/living/simple_mob/animal/passive/cat,
diff --git a/code/modules/xenoarcheaology/artifacts/replicator.dm b/code/modules/xenoarcheaology/artifacts/replicator.dm
index 3dd5fca3d0..af78f320e5 100644
--- a/code/modules/xenoarcheaology/artifacts/replicator.dm
+++ b/code/modules/xenoarcheaology/artifacts/replicator.dm
@@ -26,7 +26,6 @@
/obj/item/roller,
/obj/structure/closet/crate,
/obj/structure/closet/acloset,
- // /mob/living/simple_mob/mimic/crate, // Vorestation edit //VORESTATION AI TEMPORARY REMOVAL
/mob/living/simple_mob/mechanical/viscerator,
/mob/living/simple_mob/mechanical/hivebot,
/obj/item/device/analyzer,
@@ -65,6 +64,7 @@
/obj/item/weapon/grenade/chem_grenade/cleaner,
/obj/item/weapon/grenade/chem_grenade/metalfoam)
+// /mob/living/simple_mob/mimic/crate, // Vorestation edit //VORESTATION AI TEMPORARY REMOVAL, REPLACE BACK IN LIST WHEN FIXED
var/quantity = rand(5, 15)
for(var/i=0, i