diff --git a/code/modules/mob/living/simple_animal/vore/otie.dm b/code/modules/mob/living/simple_animal/vore/otie.dm
new file mode 100644
index 0000000000..993df4870c
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/vore/otie.dm
@@ -0,0 +1,297 @@
+/mob/living/simple_animal/otie //Spawn this one only if you're looking for a bad time.
+ name = "otie"
+ desc = "The classic bioengineered longdog."
+ icon = 'icons/mob/vore64x32.dmi'
+ icon_state = "otie"
+ icon_living = "otie"
+ icon_dead = "otie-dead"
+ icon_rest = "otie_rest"
+
+ faction = "otie"
+ recruitable = 1
+ maxHealth = 160
+ health = 160
+ minbodytemp = 200
+ move_to_delay = 4
+ hostile = 1
+ cooperative = 1
+ investigates = 1
+ reacts = 1
+ retaliate = 1
+ specific_targets = 1
+ run_at_them = 0
+ attack_same = 0
+
+ speak_chance = 4
+ speak = list("Boof.","Waaf!","Prurrrr.","Growl!","Bork!","Rurrr..","Aruur!","Awoo!")
+ 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!", "MINE!", "RAHH!", "Slurp.. RAH!")
+
+ melee_damage_lower = 5
+ melee_damage_upper = 20
+
+ response_help = "pets the"
+ response_disarm = "bops the"
+ response_harm = "hits the"
+ attacktext = "mauled"
+ friendly = list("nuzzles", "slobberlicks", "noses softly at", "noseboops")
+ meat_amount = 5
+
+ old_x = -16
+ old_y = 0
+ pixel_x = -16
+ pixel_y = 0
+
+ var/mob/living/carbon/human/friend
+ var/tamed = 0
+ var/threat = null
+
+/mob/living/simple_animal/otie/fluff
+ name = "otie"
+ desc = "The classic bioengineered longdog. This one might even tolerate you!"
+ icon_state = "otie"
+ icon_living = "otie"
+ icon_rest = "otie_rest"
+ faction = "neutral"
+
+/mob/living/simple_animal/otie/fluff/cotie
+ 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"
+
+/mob/living/simple_animal/otie/fluff/security
+ name = "guard otie"
+ desc = "The V.A.R.M.A.corp 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"
+ tamed = 1
+
+ var/check_records = 1 // If true, arrests people without a record.
+ var/check_arrest = 1 // If true, arrests people who are set to arrest.
+
+//Holy shit oh god how do I make it not destroy and devour everything indiscriminately!
+
+/mob/living/simple_animal/otie/PunchTarget()
+ if(istype(target_mob,/mob/living/simple_animal/mouse))
+ return EatTarget()
+ else ..()
+
+/mob/living/simple_animal/otie/Found(var/atom/found_atom)
+ if(!SA_attackable(found_atom))
+ return null
+ if(istype(found_atom,/mob/living/simple_animal/mouse))
+ return found_atom
+ if(will_eat(found_atom))
+ if(found_atom in friends)
+ return null
+ else if(found_atom in faction_friends)
+ 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
+ return found_atom
+
+/mob/living/simple_animal/otie/fluff/security/Found(var/atom/found_atom)
+ if(!SA_attackable(found_atom))
+ return null
+ if(istype(found_atom,/mob/living/simple_animal/mouse))
+ return found_atom
+ if(check_threat(found_atom) >= 4)
+ return found_atom
+ if(will_eat(found_atom))
+ if(found_atom in friends)
+ return null
+ else if(found_atom in faction_friends)
+ 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
+ return found_atom
+
+/mob/living/simple_animal/otie/fluff/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_animal/otie/FindTarget()
+ var/atom/T = null
+ for(var/atom/A in ListTargets(view_range))
+
+ if(A == src)
+ continue
+
+ var/atom/F = Found(A)
+ if(F)
+ T = F
+ break
+ else if(specific_targets)
+ return 0
+
+ if(isliving(A))
+ var/mob/living/L = A
+ if(L.faction == src.faction && !attack_same)
+ continue
+ else if(L in friends)
+ continue
+ else if(!SA_attackable(L))
+ continue
+ else if(tamed == 1 && ishuman(L))
+ continue
+ else if(tamed == 1 && isrobot(L))
+ continue
+ else
+ T = L
+ break
+
+ else if(istype(A, /obj/mecha)) // Our line of sight stuff was already done in ListTargets().
+ var/obj/mecha/M = A
+ if(!SA_attackable(M))
+ continue
+ if((M.occupant.faction != src.faction) || attack_same)
+ T = M
+ break
+
+ if(T) //Permission to fuck up and vore GET!
+ ai_log("FindTarget() found [T]!",1)
+ if(set_target(T))
+ handle_stance(STANCE_ATTACK)
+
+ return T
+
+/mob/living/simple_animal/otie/fluff/security/FindTarget()
+ var/atom/T = null
+ for(var/atom/A in ListTargets(view_range))
+
+ if(A == src)
+ continue
+
+ var/atom/F = Found(A)
+ if(F)
+ T = F
+ break
+ else if(specific_targets)
+ return 0
+
+ if(isliving(A))
+ var/mob/living/L = A
+ if(L.faction == src.faction && !attack_same)
+ continue
+ else if(L in friends)
+ continue
+ else if(!SA_attackable(L))
+ continue
+ else if(tamed == 1 && ishuman(L))
+ continue
+ else if(tamed == 1 && isrobot(L))
+ continue
+ else
+ T = L
+ break
+
+ else if(istype(A, /obj/mecha)) // Our line of sight stuff was already done in ListTargets().
+ var/obj/mecha/M = A
+ if(!SA_attackable(M))
+ continue
+ if((M.occupant.faction != src.faction) || attack_same)
+ T = M
+ break
+
+ if(T) //Permission to fuck up and vore GET!
+ ai_log("FindTarget() found [T]!",1)
+ if(set_target(T))
+ if(check_threat(T) >= 4)
+ broadcast_security_hud_message("[src] is attempting to 'detain' suspect [target_name(T)] in [get_area(src)].", src)
+ handle_stance(STANCE_ATTACK)
+ else
+ handle_stance(STANCE_ATTACK)
+
+ return T
+
+/mob/living/simple_animal/otie/fluff/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_animal/otie/fluff/Life()
+ . = ..()
+ if(!. || ai_inactive || !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 softly at [friend].",
+ "slobberlicks [friend].",
+ "murrs."))
+ else if (friend.health <= 50)
+ if (prob(10))
+ var/verb = pick("whines", "yelps", "whimpers")
+ audible_emote("[verb] anxiously.")
+
+/mob/living/simple_animal/otie/Life()
+ . = ..()
+ if(!. || ai_inactive) return
+
+ if(prob(5))
+ lay_down()
+
+//Pet 4 frond
+
+/mob/living/simple_animal/otie/attack_hand(mob/living/carbon/human/M as mob)
+ ..()
+ switch(M.a_intent)
+
+ if(I_HELP)
+ if (health > 0)
+ LoseTarget()
+ handle_stance(STANCE_IDLE)
+ if(prob(50)) //It's a fiddy-fiddy you may get a buddy pal or you may get mauled and ate. Win-win!
+ friend = M
+ if(tamed != 1)
+ tamed = 1
+ return
+ ..()
+
+// Activate Noms!
+
+/mob/living/simple_animal/otie
+ vore_active = 1
+ vore_capacity = 1
+ vore_escape_chance = 8
+ vore_pounce_chance = 19
+ vore_icons = SA_ICON_LIVING
diff --git a/icons/mob/vore64x32.dmi b/icons/mob/vore64x32.dmi
new file mode 100644
index 0000000000..05e8113766
Binary files /dev/null and b/icons/mob/vore64x32.dmi differ