Vore mob, first upload

Just to get them on github
This commit is contained in:
SatinIsle
2024-10-08 20:29:08 +01:00
parent b925514b65
commit dca29dfd1e
14 changed files with 742 additions and 0 deletions
@@ -96,3 +96,9 @@
//VOREStation edit ends
/obj/effect/projectile/impact/pointdefense
icon_state = "impact_pointdef"
/obj/effect/projectile/impact/rainbow
icon_state = "impact_rainbow"
light_range = 3
light_power = 1
light_color = "#ffffff"
@@ -108,3 +108,9 @@
//VOREStation edit ends
/obj/effect/projectile/muzzle/pointdefense
icon_state = "muzzle_pointdef"
/obj/effect/projectile/muzzle/rainbow
icon_state = "muzzle_rainbow"
light_range = 3
light_power = 1
light_color = "#ffffff"
@@ -135,3 +135,9 @@
//VOREStation edit ends
/obj/effect/projectile/tracer/pointdefense
icon_state = "beam_pointdef"
/obj/effect/projectile/tracer/rainbow
icon_state = "rainbow"
light_range = 3
light_power = 1
light_color = "#ffffff"
@@ -0,0 +1,441 @@
/mob/living/simple_mob/vore/ddraig
name = "ddraig"
desc = "A massive drake-like creature with dark purple scales and a seemingly exposed skull."
tt_desc = "Draconis glamoris"
icon = 'icons/mob/vore96x96.dmi'
icon_dead = "ddraig-dead"
icon_living = "ddraig"
icon_state = "ddraig"
icon_rest = "ddraig_rest"
faction = FACTION_DRAGON
old_x = -32
old_y = 0
vis_height = 92
melee_damage_lower = 20
melee_damage_upper = 15
friendly = list("nudges", "sniffs on", "rumbles softly at", "nuzzles")
default_pixel_x = -32
pixel_x = -32
pixel_y = 0
response_help = "bumps"
response_disarm = "shoves"
response_harm = "bites"
movement_cooldown = -1
harm_intent_damage = 10
melee_damage_lower = 15
melee_damage_upper = 25
maxHealth = 1000
attacktext = list("mauled")
see_in_dark = 8
minbodytemp = 0
ai_holder_type = /datum/ai_holder/simple_mob/vore/ddraig
max_buckled_mobs = 1
mount_offset_y = 32
can_buckle = TRUE
buckle_movable = TRUE
buckle_lying = FALSE
minbodytemp = 0
var/flames
var/firebreathtimer
special_attack_min_range = 2
special_attack_max_range = 6
special_attack_cooldown = 30 SECONDS
var/leap_warmup = 2 SECOND // How long the leap telegraphing is.
var/leap_sound = 'sound/weapons/spiderlunge.ogg'
/mob/living/simple_mob/vore/ddraig
vore_bump_chance = 25
vore_digest_chance = 50
vore_escape_chance = 5
vore_pounce_chance = 100
vore_active = 1
vore_icons = 3
vore_icons = SA_ICON_LIVING | SA_ICON_REST
vore_capacity = 3
swallowTime = 50
vore_ignores_undigestable = TRUE
vore_default_mode = DM_DIGEST
vore_pounce_maxhealth = 125
vore_bump_emote = "tries to devour"
/mob/living/simple_mob/vore/ddraig/Login()
. = ..()
if(!riding_datum)
riding_datum = new /datum/riding/simple_mob(src)
verbs |= /mob/living/simple_mob/proc/animal_mount
verbs |= /mob/living/proc/toggle_rider_reins
verbs |= /mob/living/proc/set_size
verbs |= /mob/living/proc/polymorph
verbs |= /mob/living/proc/invisibility
movement_cooldown = -1
/mob/living/simple_mob/vore/ddraig/init_vore()
. = ..()
var/obj/belly/B = vore_selected
B.name = "stomach"
B.desc = "The enormous beast snaps it's boney jaws around your form, effortlessly lifting you from the ground. Throwing it's head backwards, your body is tossed up momentarily as the maw parts wider, only for you to descend rapidly moments later. You're caught in the creature's throat for a moment, contracting dark purple flesh holding tightly onto you, there's no going back at this point. The peristaltic motions squeeze you down this tunnel towards your final destination, where you're soon relieved of the intense squelching to be pushed into a move flexible, stretching chamber. Immediately coated in caustic oozes, the world around you seems more than eager to ensure that you're soaked over every inch, wrinkled walls twisting and grinding around your body. The drake's stomach clenches and compresses over you rhythmically, attempting to eagerly add you to the soup of fluids that fill this sloshing gut. Omnipresent sounds of groaning, gurgling and burbling bodily functions signify just how active this process already is."
B.vore_sound = "Tauric Swallow"
B.release_sound = "Pred Escape"
B.mode_flags = DM_FLAG_THICKBELLY
B.fancy_vore = 1
B.selective_preference = DM_DIGEST
B.vore_verb = "devour"
B.digest_brute = 3
B.digest_burn = 2
B.digest_oxy = 0
B.digestchance = 50
B.absorbchance = 0
B.escapechance = 3
B.escape_stun = 5
B.contamination_color = "grey"
B.contamination_flavor = "Wet"
B.emote_lists[DM_DIGEST] = list(
"The drake growls in annoyance before clenching those wrinkled walls tight against your form, grinding away at you!",
"As the beast wanders about, you're forced to slip and slide around amidst a pool of thick digestive goop, sinking briefly into the thick, heavy walls!",
"You can barely hear the drake let out a pleased rumble as its stomach eagerly gurgles around its newfound meal!",
"As the thinning air begins to make you feel dizzy, menacing bworps and grumbles fill that dark, constantly shifting organ!",
"The constant, rhythmic kneading and massaging starts to take its toll along with the muggy heat, making you feel weaker and weaker!",
"The drake happily wanders around while digesting its meal, almost like it is trying to show off the hanging gut you've given it. Not like it made much of a difference on his already borderline obese form anyway~")
/mob/living/simple_mob/vore/ddraig/do_special_attack(atom/A)
. = TRUE
if(ckey)
return
var/specialattack = rand(1,3)
if(rand == 1)
lunge(A)
if(rand == 2)
firebreathstart(A)
if(rand == 3)
tfbeam(A)
/mob/living/simple_mob/vore/ddraig/proc/lunge(atom/A) //Mostly copied from hunter.dm
set waitfor = FALSE
if(!isliving(A))
return FALSE
var/mob/living/L = A
if(!L.devourable || !L.allowmobvore || !L.can_be_drop_prey || !L.throw_vore || L.unacidable)
return FALSE
set_AI_busy(TRUE)
visible_message(span_warning("\The [src] rears back, ready to lunge!"))
to_chat(L, span_danger("\The [src] focuses on you!"))
// Telegraph, since getting stunned suddenly feels bad.
do_windup_animation(A, leap_warmup)
sleep(leap_warmup) // For the telegraphing.
if(L.z != z) //Make sure you haven't disappeared to somewhere we can't go
set_AI_busy(FALSE)
return FALSE
// Do the actual leap.
status_flags |= LEAPING // Lets us pass over everything.
visible_message(span_critical("\The [src] leaps at \the [L]!"))
throw_at(get_step(L, get_turf(src)), special_attack_max_range+1, 1, src)
playsound(src, leap_sound, 75, 1)
sleep(5) // For the throw to complete. It won't hold up the AI ticker due to waitfor being false.
if(status_flags & LEAPING)
status_flags &= ~LEAPING // Revert special passage ability.
set_AI_busy(FALSE)
if(Adjacent(L)) //We leapt at them but we didn't manage to hit them, let's see if we're next to them
L.Weaken(2) //get knocked down, idiot
/mob/living/simple_mob/vore/ddraig/proc/firebreathstart(var/atom/A) //Borrowed from le big dragon
glow_toggle = 1
set_light(glow_range, glow_intensity, glow_color) //Setting it here so the light starts immediately
if(!enraged)
set_AI_busy(TRUE)
flames = 1
build_icons()
firebreathtimer = addtimer(CALLBACK(src, PROC_REF(firebreathend), A), charge_warmup, TIMER_STOPPABLE)
playsound(src, "sound/magic/Fireball.ogg", 50, 1)
/mob/living/simple_mob/vore/ddraig/proc/firebreathend(var/atom/A)
//make sure our target still exists and is on a turf
if(QDELETED(A) || !isturf(get_turf(A)))
set_AI_busy(FALSE)
return
var/obj/item/projectile/P = new /obj/item/projectile/bullet/dragon(get_turf(src))
src.visible_message(span_danger("\The [src] spews fire at \the [A]!"))
playsound(src, "sound/weapons/Flamer.ogg", 50, 1)
P.launch_projectile(A, BP_TORSO, src)
set_AI_busy(FALSE)
glow_toggle = 0
flames = 0
build_icons()
/mob/living/simple_mob/vore/ddraig/proc/tfbeam(var/atom/A)
if(!isturf(get_turf(A)))
return
var/obj/item/projectile/P = new /obj/item/projectile/beam/mouselaser/ddraig(get_turf(src))
src.visible_message(span_danger("\The [src] breathes a beam at \the [A]!"))
playsound(src, "sound/weapons/sparkle.ogg", 50, 1)
P.launch_projectile(A, BP_TORSO, src)
/obj/item/projectile/beam/mouselaser/ddraig
tf_admin_pref_override = TRUE //It will TF them regardless of their prefs because it is only very temporary
icon_state = "rainbow"
muzzle_type = /obj/effect/projectile/muzzle/rainbow
tracer_type = /obj/effect/projectile/tracer/rainbow
impact_type = /obj/effect/projectile/impact/rainbow
/obj/item/projectile/beam/mouselaser/on_hit(var/atom/target)
var/list/tf_list = list("mouse" = /mob/living/simple_mob/animal/passive/mouse,
"rat" = /mob/living/simple_mob/animal/passive/mouse/rat,
"dust jumper" = /mob/living/simple_mob/vore/alienanimals/dustjumper,
"woof" = /mob/living/simple_mob/vore/woof,
"corgi" = /mob/living/simple_mob/animal/passive/dog/corgi,
"cat" = /mob/living/simple_mob/animal/passive/cat,
"chicken" = /mob/living/simple_mob/animal/passive/chicken,
"cow" = /mob/living/simple_mob/animal/passive/cow,
"lizard" = /mob/living/simple_mob/animal/passive/lizard,
"rabbit" = /mob/living/simple_mob/vore/rabbit,
"fox" = /mob/living/simple_mob/animal/passive/fox,
"fennec" = /mob/living/simple_mob/vore/fennec,
"cute fennec" = /mob/living/simple_mob/animal/passive/fennec,
"fennix" = /mob/living/simple_mob/vore/fennix,
"red panda" = /mob/living/simple_mob/vore/redpanda,
"opossum" = /mob/living/simple_mob/animal/passive/opossum,
"horse" = /mob/living/simple_mob/vore/horse,
"goose" = /mob/living/simple_mob/animal/space/goose,
"sheep" = /mob/living/simple_mob/vore/sheep)
tf_type = pick(tf_list)
. = ..()
spawn(30 SECONDS)
target.revert_mob_tf() //TF them back after 30 seconds, basically takes them out of the fight for a short time.
/datum/ai_holder/simple_mob/vore/ddraig
var/used_invis = 0
/datum/ai_holder/simple_mob/vore/ddraig/engage_target()
ai_log("engage_target() : Entering.", AI_LOG_DEBUG)
if(holder.cloaked)
set_stance(STANCE_FLEE)
return
if((holder.health < (holder.maxHealth / 4)) && !used_invis)
holder.cloak()
used_invis = 1
spawn(60 SECONDS)
holder.uncloak()
// Can we still see them?
if(!target || !can_attack(target))
ai_log("engage_target() : Lost sight of target.", AI_LOG_TRACE)
if(lose_target()) // We lost them (returns TRUE if we found something else to do)
ai_log("engage_target() : Pursuing other options (last seen, or a new target).", AI_LOG_TRACE)
return
var/distance = get_dist(holder, target)
ai_log("engage_target() : Distance to target ([target]) is [distance].", AI_LOG_TRACE)
holder.face_atom(target)
last_conflict_time = world.time
// Do a 'special' attack, if one is allowed.
// if(prob(special_attack_prob) && (distance >= special_attack_min_range) && (distance <= special_attack_max_range))
if(holder.ICheckSpecialAttack(target))
ai_log("engage_target() : Attempting a special attack.", AI_LOG_TRACE)
on_engagement(target)
if(special_attack(target)) // If this fails, then we try a regular melee/ranged attack.
ai_log("engage_target() : Successful special attack. Exiting.", AI_LOG_DEBUG)
return
// Stab them.
else if(distance <= 1 && !pointblank)
ai_log("engage_target() : Attempting a melee attack.", AI_LOG_TRACE)
on_engagement(target)
melee_attack(target)
else if(distance <= 1 && !holder.ICheckRangedAttack(target)) // Doesn't have projectile, but is pointblank
ai_log("engage_target() : Attempting a melee attack.", AI_LOG_TRACE)
on_engagement(target)
melee_attack(target)
// Shoot them.
else if(holder.ICheckRangedAttack(target) && (distance <= max_range(target)) )
on_engagement(target)
if(firing_lanes && !test_projectile_safety(target))
// Nudge them a bit, maybe they can shoot next time.
var/turf/T = get_step(holder, pick(cardinal))
if(T)
holder.IMove(T) // IMove() will respect movement cooldown.
holder.face_atom(target)
ai_log("engage_target() : Could not safely fire at target. Exiting.", AI_LOG_DEBUG)
return
ai_log("engage_target() : Attempting a ranged attack.", AI_LOG_TRACE)
ranged_attack(target)
// Run after them.
else if(!stand_ground)
ai_log("engage_target() : Target ([target]) too far away. Exiting.", AI_LOG_DEBUG)
set_stance(STANCE_APPROACH)
////////////////////////////Player controlled verbs///////////////////////////////
/mob/living/proc/polymorph()
set name = "Polymorph"
set desc = "Take the form of a non-humanoid creature."
set category = "Abilities"
var/list/beast_options = list("Rabbit" = /mob/living/simple_mob/vore/rabbit,
"Red Panda" = /mob/living/simple_mob/vore/redpanda,
"Fennec" = /mob/living/simple_mob/vore/fennec,
"Giant Frog" = /mob/living/simple_mob/vore/aggressive/frog,
"Giant Rat" = /mob/living/simple_mob/vore/aggressive/rat,
"Wolf" = /mob/living/simple_mob/vore/wolf,
"Dire Wolf" = /mob/living/simple_mob/vore/wolf/direwolf,
"Fox" = /mob/living/simple_mob/animal/passive/fox/beastmode,
"Panther" = /mob/living/simple_mob/vore/aggressive/panther,
"Giant Snake" = /mob/living/simple_mob/vore/aggressive/giant_snake,
"Otie" = /mob/living/simple_mob/vore/otie,
"Squirrel" = /mob/living/simple_mob/vore/squirrel,
"Raptor" = /mob/living/simple_mob/vore/raptor,
"Giant Bat" = /mob/living/simple_mob/vore/bat,
"Horse" = /mob/living/simple_mob/vore/horse,
"Horse (Big)" = /mob/living/simple_mob/vore/horse/big,
"Kelpie" = /mob/living/simple_mob/vore/horse/kelpie,
"Bear" = /mob/living/simple_mob/animal/space/bear/brown/beastmode,
"Seagull" = /mob/living/simple_mob/vore/seagull,
"Sheep" = /mob/living/simple_mob/vore/sheep,
"Azure Tit" = /mob/living/simple_mob/animal/passive/bird/azure_tit/beastmode,
"Robin" = /mob/living/simple_mob/animal/passive/bird/european_robin/beastmode,
"Cat" = /mob/living/simple_mob/animal/passive/cat/black/beastmode,
"Tamaskan Dog" = /mob/living/simple_mob/animal/passive/dog/tamaskan,
"Corgi" = /mob/living/simple_mob/animal/passive/dog/corgi,
"Bull Terrier" = /mob/living/simple_mob/animal/passive/dog/bullterrier,
"Duck" = /mob/living/simple_mob/animal/sif/duck,
"Cow" = /mob/living/simple_mob/animal/passive/cow,
"Chicken" = /mob/living/simple_mob/animal/passive/chicken,
"Goat" = /mob/living/simple_mob/animal/goat,
"Penguin" = /mob/living/simple_mob/animal/passive/penguin,
"Goose" = /mob/living/simple_mob/animal/space/goose
)
var/chosen_beast = tgui_input_list(src, "Which form would you like to take?", "Choose Beast Form", beast_options)
if(!chosen_beast)
return
var/mob/living/M = src
log_debug("polymorph start")
if(!istype(M))
log_debug("polymorph istype")
return
if(M.stat) //We can let it undo the TF, because the person will be dead, but otherwise things get weird.
log_debug("polymorph stat")
to_chat(src, span_warning("You can't do that in your condition."))
return
if(M.health <= 10) //We can let it undo the TF, because the person will be dead, but otherwise things get weird.
log_debug("polymorph injured")
to_chat(src, span_warning("You are too injured to transform into a beast."))
return
visible_message("<b>\The [src]</b> begins significantly shifting their form.")
if(!do_after(src, 10 SECONDS, src, exclusive = TASK_USER_EXCLUSIVE))
visible_message("<b>\The [src]</b> ceases shifting their form.")
return 0
var/image/coolanimation = image('icons/obj/glamour.dmi', null, "animation")
coolanimation.plane = PLANE_LIGHTING_ABOVE
src.overlays += coolanimation
spawn(10)
src.overlays -= coolanimation
log_debug("polymorph not dead")
var/mob/living/new_mob = spawn_polymorph_mob(beast_options[chosen_beast])
new_mob.faction = M.faction
if(new_mob && isliving(new_mob))
log_debug("polymorph new_mob")
for(var/obj/belly/B as anything in new_mob.vore_organs)
log_debug("polymorph new_mob belly")
new_mob.vore_organs -= B
qdel(B)
new_mob.vore_organs = list()
new_mob.name = M.name
new_mob.real_name = M.real_name
new_mob.verbs |= /mob/living/proc/revert_beast_form
new_mob.verbs |= /mob/living/proc/set_size
for(var/lang in M.languages)
new_mob.languages |= lang
M.copy_vore_prefs_to_mob(new_mob)
new_mob.vore_selected = M.vore_selected
if(ishuman(M))
log_debug("polymorph ishuman part2")
var/mob/living/carbon/human/H = M
if(ishuman(new_mob))
log_debug("polymorph ishuman(newmob)")
var/mob/living/carbon/human/N = new_mob
N.gender = H.gender
N.identifying_gender = H.identifying_gender
else
log_debug("polymorph gender else")
new_mob.gender = H.gender
else
log_debug("polymorph gender else 2")
new_mob.gender = M.gender
if(ishuman(new_mob))
var/mob/living/carbon/human/N = new_mob
N.identifying_gender = M.gender
for(var/obj/belly/B as anything in M.vore_organs)
B.loc = new_mob
B.forceMove(new_mob)
B.owner = new_mob
M.vore_organs -= B
new_mob.vore_organs += B
new_mob.ckey = M.ckey
if(M.ai_holder && new_mob.ai_holder)
var/datum/ai_holder/old_AI = M.ai_holder
old_AI.set_stance(STANCE_SLEEP)
var/datum/ai_holder/new_AI = new_mob.ai_holder
new_AI.hostile = old_AI.hostile
new_AI.retaliate = old_AI.retaliate
M.loc = new_mob
M.forceMove(new_mob)
new_mob.tf_mob_holder = M
new_mob.visible_message("<b>\The [src]</b> has transformed into \the [chosen_beast]!")
/mob/living/proc/spawn_polymorph_mob(var/chosen_beast)
log_debug("polymorph proc spawn mob")
var/tf_type = chosen_beast
log_debug("polymorph [tf_type]")
if(!ispath(tf_type))
log_debug("polymorph tf_type fail")
return
log_debug("polymorph tf_type pass")
var/new_mob = new tf_type(get_turf(src))
return new_mob
/mob/living/proc/invisibility()
set name = "Invisibility"
set desc = "Change your appearance to match your surroundings, becoming completely invisible to the naked eye."
set category = "Abilities"
if(stat)
to_chat(src, span_warning("You can't go invisible when weakened like this."))
return
if(!cloaked)
cloak()
block_hud = 1
hud_updateflag = 1
to_chat(src, span_warning("Your fur shimmers and shifts around you, hiding you from the naked eye."))
else
uncloak()
block_hud = 0
hud_updateflag = 1
to_chat(src, span_warning("The brustling of your fur settles down and you become visible once again."))
@@ -0,0 +1,212 @@
/mob/living/simple_mob/vore/scrubble
name = "fluffball"
desc = "A small, rotund humanoid creature. It is difficult to make out physical features of it as it covers most of its face behind big floppy, fluffy ears with only beady yellow eyes looking out. Most of its body is covered by a thick, soft tail that it wraps around itself and holds onto with small stumpy arms."
catalogue_data = list(/datum/category_item/catalogue/fauna/scrubble)
tt_desc = "glamoris fluffalia"
icon = 'icons/mob/vore.dmi'
icon_dead = "fluffball-dead"
icon_living = "fluffball"
icon_state = "fluffball"
faction = FACTION_SCRUBBLE
friendly = list("nudges", "sniffs on", "rumbles softly at", "nuzzles")
response_help = "bumps"
response_disarm = "shoves"
response_harm = "attacks"
movement_cooldown = 0
harm_intent_damage = 2
melee_damage_lower = 1
melee_damage_upper = 4
maxHealth = 50
attacktext = list("tail whips")
see_in_dark = 8
minbodytemp = 0
ai_holder_type = /datum/ai_holder/simple_mob/hostile/fluffball
say_list_type = /datum/say_list/fluffball
faction = FACTION_GLAMOUR
vore_bump_chance = 25
vore_digest_chance = 50
vore_escape_chance = 5
vore_pounce_chance = 1000
vore_active = 1
vore_icons = 1
vore_icons = SA_ICON_LIVING
vore_capacity = 1
swallowTime = 50
vore_ignores_undigestable = TRUE
vore_default_mode = DM_SELECT
vore_pounce_maxhealth = 1000
vore_bump_emote = "pounces on"
vore_pounce_falloff = 0 //Always eat someone at full health
vore_standing_too = 1
/mob/living/simple_mob/vore/fluffball/init_vore()
..()
var/obj/belly/B = vore_selected
B.name = "tail"
B.desc = "The small critter seems to suddenly panic, lunging at you with its massive fluffy tail, using it like a weapon. Despite the appearance of the tail, it seems to be much larger on the inside, suddenly engulfing you completely in a world of endless softness. Inside, you are bound up nice and tight in an oddly comfortable prison of hair, it ripples over your body tickling every bit of exposed body on offer."
B.mode_flags = DM_FLAG_THICKBELLY
B.belly_fullscreen = "yet_another_tumby"
B.digest_brute = 1
B.digest_burn = 1
B.digest_oxy = 0
B.digestchance = 10
B.absorbchance = 60
B.escapechance = 10
B.selective_preference = DM_ABSORB
B.escape_stun = 5
B.transferlocation_absorb = "fluff"
var/obj/belly/fluff = new /obj/belly(src)
fluff.immutable = TRUE
fluff.name = "fluff"
fluff.desc = "You find yourself sinking deeper and deeper into the fluff around you, steadily it wraps around your entire body, binding you up. It seems to grow tighter and tigher forever, although never to the point of discomfort. Before long, the tightness goes beyond a physical sensation, it starts to feel like it buries into you, becoming part of you. It is becoming hard to discern yourself from the fluff, you feel floaty, wavy and soft yourself. Eventually, you can't feel yourself at all, there's nothing but fur. Every movement you make feels pointless, simply causing the slightest rustling of fluff as though the hair was moving on its own."
fluff.digest_mode = DM_HOLD // like, shes got you already, doesn't need to get you more
fluff.mode_flags = DM_FLAG_FORCEPSAY
fluff.escapable = TRUE // good luck
fluff.escapechance = 40 // high chance of STARTING a successful escape attempt
fluff.escapechance_absorbed = 5 // m i n e
fluff.vore_verb = "soak"
fluff.count_absorbed_prey_for_sprite = FALSE
fluff.absorbed_struggle_messages_inside = list(
"You try and push free from %pred's %belly, but can't seem to will yourself to move.",
"Your fruitless mental struggles only cause %pred to giggle lightly.",
"You can't make any progress freeing yourself from %pred's %belly.")
fluff.escape_attempt_absorbed_messages_owner = list(
"%prey is attempting to free themselves from your %belly!")
fluff.escape_attempt_absorbed_messages_prey = list(
"You try to force yourself out of %pred's %belly.",
"You strain and push, attempting to reach out of %pred's %belly.",
"You work up the will to try and force yourself free of %pred's clutches.")
fluff.escape_absorbed_messages_owner = list(
"%prey forces themselves free of your %belly!")
fluff.escape_absorbed_messages_prey = list(
"You finally manage to wrest yourself free from %pred's %belly, re-asserting your more usual form.",
"You heave and push, eventually spilling out from %pred's %belly, eliciting a happy chirp from your former captor.")
fluff.escape_absorbed_messages_outside = list(
"%prey suddenly forces themselves free of %pred's %belly!")
fluff.escape_fail_absorbed_messages_owner = list(
"%prey's attempt to escape form your %belly has failed!")
fluff.escape_fail_absorbed_messages_prey = list(
"Before you manage to reach freedom, you feel yourself getting dragged back into %pred's %belly!",
"%pred laughs lightly, simply pressing your wrigging form back into her %belly before you get anywhere.",
"Try as you might, you barely make an impression before %pred simply clenches with the most minimal effort, binding you back into her %belly.",
"Unfortunately, %pred seems to have absolutely no intention of letting you go, and your futile effort goes nowhere.",
"Strain as you might, you can't keep up the effort long enough before you sink back into %pred's %belly.")
/datum/say_list/fluffball
emote_hear = list("makes a shy squeal","whimpers","lets out a little squeak")
emote_see = list("hides its face","cuddles up to its own tail","stands there awkwardly","avoids eye contact")
/datum/category_item/catalogue/fauna/fluffball
name = "Extra-Realspace Fauna - Fluffball"
desc = "Classification: Glamoris Fluffalia\
<br><br>\
A stout creature with an apparently quite round figure, known to habit the location known as the Glamour. It is generally difficult to identify any physical features on the creature \
due to its anxiety around other creatures, it hides itself beneath its heavily furred ears and tail. Most creatures that approach it will find the fluffball fleeing quickly, \
though it is known to act more calm around those carrying food, which it is quick to steal from people's hands if offered. However, they have been observed to use their tails as weapons when panicked and unable to flee."
value = CATALOGUER_REWARD_HARD
/mob/living/simple_mob/vore/fluffball/PounceTarget(var/mob/living/M, var/successrate = 100)
vore_pounce_cooldown = world.time + 20 SECONDS // don't attempt another pounce for a while
if(prob(successrate)) // pounce success!
M.Weaken(5)
M.visible_message("<span class='danger'>\The [src] pounces on \the [M]!</span>!")
else // pounce misses!
M.visible_message("<span class='danger'>\The [src] attempts to pounce \the [M] but misses!</span>!")
playsound(src, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
if(will_eat(M) && (!M.canmove || vore_standing_too)) //if they're edible then eat them too
return EatTarget(M)
else
return //just leave them
/mob/living/simple_mob/vore/fluffball/attackby(obj/item/W as obj, mob/user as mob)
..()
if(W.istype(/obj/item/reagent_containers/food))
user.drop_item(W)
qdel(W)
M.visible_message("<span class='notice'>\The [src] quickly steals \the [w] into its fluff, it seems to have become a little less shy!</span>!")
if(ai_holder_type.istype(/datum/ai_holder/simple_mob/hostile/fluffball))
L.ai_holder_type = /datum/ai_holder/simple_mob/vore/fluffball
L.initialize_ai_holder()
//AI
/datum/ai_holder/simple_mob/hostile/fluffball
can_flee = TRUE
vision_range = 2 //Only react if you get close
can_flee = TRUE // If they're even allowed to flee.
flee_when_dying = TRUE // If they should flee when low on health.
dying_threshold = 1.1 // Flee at max health
/datum/ai_holder/simple_mob/hostile/fluffball/flee_from_target()
ai_log("flee_from_target() : Entering.", AI_LOG_DEBUG)
if(!target || !should_flee() || !can_attack(target)) // can_attack() is used since it checks the same things we would need to anyways.
ai_log("flee_from_target() : Lost target to flee from.", AI_LOG_INFO)
lose_target()
set_stance(STANCE_IDLE)
ai_log("flee_from_target() : Exiting.", AI_LOG_DEBUG)
return
var/mob/living/simple_mob/vore/H = holder
var/mob/living/L = target
var/distance = get_dist(holder, target)
if(distance <= 1)
if(H.will_eat(L) && H.CanPounceTarget(L))
H.face_atom(L)
H.PounceTarget(L)
return
ai_log("flee_from_target() : Stepping away.", AI_LOG_TRACE)
step_away(holder, target, 5)
ai_log("flee_from_target() : Exiting.", AI_LOG_DEBUG)
/datum/ai_holder/simple_mob/hostile/fluffball/find_target(list/possible_targets, has_targets_list)
if(!isanimal(holder)) //Only simplemobs have the vars we need
return ..()
var/list/L = list()
if(!has_targets_list)
possible_targets = list_targets()
var/list/valid_mobs = list()
for(var/mob/living/possible_target in possible_targets)
var/mob/living/carbon/human/H = possible_target
if(H.istype())
/obj/item/reagent_containers/food/L = H.get_active_hand()
/obj/item/reagent_containers/food/R = H.get_inactive_hand()
if(R.istype() || L.istype())
continue
if(!can_attack(possible_target))
continue
L |= possible_target
if(!isliving(possible_target))
continue
if(vore_check(possible_target))
valid_mobs |= possible_target
var/new_target
if(valid_mobs.len)
new_target = pick(valid_mobs)
else if(hostile && L.len)
new_target = pick(L)
if(!new_target)
return null
give_target(new_target)
return new_target
/datum/ai_holder/simple_mob/vore/fluffball
vision_range = 4
hostile = FALSE
retaliate = TRUE
vore_hostile = FALSE
forgive_resting = TRUE
cooperative = FALSE
@@ -0,0 +1,71 @@
/mob/living/simple_mob/vore/horse/unicorn
name = "unicorn"
icon_state = "unicorn"
icon_living = "unicorn"
icon_dead = "unicorn-dead"
icon = 'icons/mob/vore64x64.dmi'
desc = "A bright white horse-like creature with a golden horn protruding from its forehead. It's mane and hooves is a similarly golden."
tt_desc = "Equus unicornis"
vore_capacity = 2
maxHealth = 250
health = 250
meat_amount = 10
old_x = -16
old_y = 0
default_pixel_x = -16
pixel_x = -16
pixel_y = 0
mount_offset_y = 22
say_list_type = /datum/say_list/horse/unicorn
ai_holder_type = /datum/ai_holder/simple_mob/vore
minbodytemp = 0
vore_bump_chance = 75
vore_pounce_chance = 75
vore_pounce_maxhealth = 200
vore_bump_emote = "chomps down on"
faction = FACTION_GLAMOUR
projectiletype = /obj/item/projectile/beam/rainbow
projectilesound = 'sound/weapons/sparkle.ogg'
projectile_dispersion = 7
projectile_accuracy = -20
/mob/living/simple_mob/vore/horse/unicorn/init_vore()
..()
var/obj/belly/B = vore_selected
B.name = "stomach"
B.desc = "With a final few gulps, the unicorn finishes swallowing you down into its hot, humid gut... and with a slosh, your weight makes the equine's belly hang down slightly like some sort of organic hammock. The thick, damp air is tinged with the smell of... candyfloss(?), and the surrounding flesh wastes no time in clenching and massaging down over its newfound fodder."
B.digest_brute = 3
B.digest_burn = 3
B.digestchance = 40
B.absorbchance = 1
B.escapechance = 7
B.escape_stun = 5
B.emote_lists[DM_HOLD] = list(
"The unicorn's idle trotting helps its stomach gently churn around you, slimily squelching against your figure.",
"The equine predator takes a moment to intentionally clench its gut around you, encapsulating you in a strange, fleshy hug.",
"Some hot, viscous slime oozes down over your form, helping slicken you up during your stay.",
"During a moment of relative silence, you can hear the beast's soft, relaxed breathing as it casually goes about its day.",
"The thick, humid atmosphere within the unicorn's hanging belly works in tandem with its steady, metronome-like heartbeat to soothe you.",
"Your surroundings sway from side to side as the unicorn trots about, as if it is showing off its newest catch.")
B.emote_lists[DM_DIGEST] = list(
"The unicorn huffs in annoyance before clenching those wrinkled walls tight against your form, grinding away at you!",
"As the beast trots about, you're forced to slip and slide around amidst a pool of thick digestive goop!",
"You can barely hear the unicorn let out a pleased nicker as its stomach eagerly gurgles around its newfound meal!",
"As the thinning air begins to make you feel dizzy, menacing bworps and grumbles fill that dark, constantly shifting organ!",
"The constant, rhythmic kneading and massaging starts to take its toll along with the muggy heat, making you feel weaker and weaker!",
"The unicorn happily trots around while digesting its meal, almost like it is trying to show off the hanging gut you've given it.")
/datum/say_list/horse/unicorn
speak = list("...","?")
emote_hear = list("makes some sort of sparkling sound","whinnies with the most beautiful sounds")
emote_see = list("twinkles prettily", "shakes its mane", "looks so very regal")
/mob/living/simple_mob/vore/horse/unicorn/hostile
ai_holder_type = /datum/ai_holder/simple_mob/vore/hostile
Binary file not shown.

Before

Width:  |  Height:  |  Size: 435 KiB

After

Width:  |  Height:  |  Size: 438 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 708 KiB

After

Width:  |  Height:  |  Size: 720 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

After

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB