more code clean up (#10330)

This commit is contained in:
Kashargul
2025-03-07 16:57:03 +01:00
committed by GitHub
parent c78c0aec04
commit 9d5f8c09bd
25 changed files with 83 additions and 130 deletions

View File

@@ -1,4 +1,4 @@
/mob/living/carbon/human/ai_controlled/greytide/Initialize()
/mob/living/carbon/human/ai_controlled/greytide/Initialize(mapload)
to_wear_r_hand = pick(
prob(20); /obj/item/storage/toolbox/electrical,
prob(20); /obj/item/storage/toolbox/mechanical,
@@ -20,7 +20,7 @@
)
else
to_wear_gloves = null
..()
. = ..()
/mob/living/carbon/human/ai_controlled/greytide
name = "John Greytide" //theyll get a normal name on spawn

View File

@@ -1,5 +0,0 @@
/mob/living/simple_mob/metroid/juvenile/gamma
projectiletype = /obj/item/projectile/energy/mob/electric_spider
/mob/living/simple_mob/metroid/juvenile/omega
projectiletype = /obj/item/projectile/energy/mob/smalllaser

View File

@@ -1,39 +0,0 @@
//File unticked due to combat refactor walkback
/mob/living/simple_mob/metroid/jellybrig
maxHealth = 200
health = 200
/mob/living/simple_mob/metroid/juvenile/baby
health = 100
maxHealth = 100
/mob/living/simple_mob/metroid/juvenile/super
health = 125
maxHealth = 125
/mob/living/simple_mob/metroid/juvenile/alpha
health = 150
maxHealth = 150
/mob/living/simple_mob/metroid/juvenile/gamma
health = 200
maxHealth = 200
melee_damage_lower = 5
melee_damage_upper = 10
/mob/living/simple_mob/metroid/juvenile/zeta
health = 250
maxHealth = 250
melee_damage_lower = 7
melee_damage_upper = 12
/mob/living/simple_mob/metroid/juvenile/omega
health = 300
maxHealth = 300
melee_damage_lower = 12
melee_damage_upper = 20
/mob/living/simple_mob/metroid/juvenile/queen
health = 500
maxHealth = 500

View File

@@ -0,0 +1,62 @@
// Specialized AI for metroid simplemobs.
// Unlike the parent AI code, this will probably break a lot of things if you put it on something that isn't /mob/living/simple_mob/metroid/juvenile
/datum/ai_holder/simple_mob/juvenile_metroid
hostile = TRUE
cooperative = TRUE
firing_lanes = TRUE
mauling = TRUE // They need it to get the most out of monkeys.
conserve_ammo = TRUE // Might help avoid 'I shoot the wall forever' cheese.
var/closest_desired_distance = 1 // Otherwise run up to them to be able to potentially shock or punch them.
var/always_stun = FALSE // If true, the metroid will elect to attempt to permastun the target.
/datum/ai_holder/simple_mob/juvenile_metroid/on_engagement(atom/A)
if(get_dist(holder, A) > closest_desired_distance)
holder.IMove(get_step_towards(holder, A))
/datum/ai_holder/simple_mob/juvenile_metroid/New()
..()
ASSERT(istype(holder, /mob/living/simple_mob/metroid/juvenile))
/datum/ai_holder/simple_mob/juvenile_metroid/handle_special_tactic()
evolve_and_reproduce()
// Hit the correct verbs to keep the metroid species going.
/datum/ai_holder/simple_mob/juvenile_metroid/proc/evolve_and_reproduce()
var/mob/living/simple_mob/metroid/juvenile/my_juvenile = holder
if(my_juvenile.nutrition >= my_juvenile.evo_point)
// Press the correct verb when we can.
my_juvenile.evolve() // Turns our holder into an adult metroid.
// The holder's attack changes based on intent. This lets the AI choose what effect is desired.
/datum/ai_holder/simple_mob/juvenile_metroid/pre_melee_attack(atom/A)
if(istype(A, /mob/living))
var/mob/living/L = A
var/mob/living/simple_mob/metroid/juvenile/my_juvenile = holder
if( (!L.lying && prob(30 + (my_juvenile.power_charge * 7) ) || (!L.lying && always_stun) ))
my_juvenile.a_intent = I_DISARM // Stun them first.
else if(my_juvenile.is_juvenile && my_juvenile.can_consume(L) && L.lying)
my_juvenile.a_intent = I_GRAB // Then eat them.
else
my_juvenile.a_intent = I_HURT // Otherwise robust them.
/datum/ai_holder/simple_mob/juvenile_metroid/closest_distance(atom/movable/AM)
if(istype(AM, /mob/living))
var/mob/living/L = AM
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(istype(H.species, /datum/species/monkey))
return 1 // Otherwise ranged metroids will eat a lot less often.
if(L.stat >= UNCONSCIOUS)
return 1 // Melee (eat) the target if dead/dying, don't shoot it.
return ..()
/datum/ai_holder/simple_mob/juvenile_metroid/can_attack(atom/movable/AM, var/vision_required = TRUE)
. = ..()
if(.) // Do some additional checks because we have Special Code(tm).
if(ishuman(AM))
var/mob/living/carbon/human/H = AM
if(istype(H.species, /datum/species/monkey)) // istype() is so they'll eat the alien monkeys too.
return TRUE // Monkeys are always food (sorry Pun Pun).

View File

@@ -0,0 +1,122 @@
// The top-level metroid defines. Xenobio slimes and feral slimes will inherit from this. Stolen from as much slime code as possible.
/mob/living/simple_mob/metroid
name = "metroid"
desc = "Some sort of person eaty thing! This is the prototype mob and shouldn't be spawned. If you see this, yell at your local dev or event manager who spawned this one >.>"
tt_desc = "Headamus Suckumus"
icon = 'icons/mob/metroid/small.dmi'
icon_state = "metroid"
icon_living = "metroid"
icon_dead = "metroid_dead"
layer = MOB_LAYER + 1 // Need them on top of other mobs or it looks weird when consuming something.
var/icon_state_override = null // Used for special slime appearances like the rainbow slime.
gender = NEUTER
faction = "metroids"
maxHealth = 25
movement_cooldown = 1.7
pass_flags = PASSTABLE
makes_dirt = FALSE // Floats, mostly.
mob_class = MOB_CLASS_SLIME //This needs to be updated in simple_mob.dm and _defines/mobs.dm
response_help = "pets"
// Atmos stuff.
minbodytemp = T0C-30
heat_damage_per_tick = 0
cold_damage_per_tick = 40
min_oxy = 0
max_oxy = 0
min_tox = 0
max_tox = 0
min_co2 = 0
max_co2 = 0
min_n2 = 0
max_n2 = 0
unsuitable_atoms_damage = 0
melee_damage_lower = 10
melee_damage_upper = 15
base_attack_cooldown = 10 // One attack a second.
attack_sound = 'sound/metroid/metroidattack.ogg'
attacktext = list("suckulated")
speak_emote = list("chirps")
friendly = list("pokes")
ai_holder_type = /datum/ai_holder/simple_mob/melee
say_list_type = /datum/say_list/metroid
harm_intent_damage = 5 //When someone uses fists. Default is 3
vore_active = 1
vore_pounce_chance = 25
vore_icons = SA_ICON_LIVING
nutrition = 1000 //This actually gets overridden further down on initialize.
max_nutrition = 2200
var/evo_point = 0
var/evo_limit = 0
var/next
meat_type = /obj/item/toy/figure/bounty_hunter
can_be_drop_prey = FALSE //CHOMP Add
can_pain_emote = TRUE
species_sounds = "Metroid"
pain_emote_1p = list("skree")
pain_emote_3p = list("skrees")
/mob/living/simple_mob/metroid/Initialize()
nutrition = 100 //Have them start off pretty hungry still.
add_verb(src,/mob/living/proc/ventcrawl) //CHOMPEdit TGPanel //May not do anything at the moment.
return ..()
/datum/say_list/metroid
speak = list("Skree.", "Eree.", "Errer?")
emote_see = list("floats about","looks around", "rubs its talons")
emote_hear = list("chitters")
say_understood = list("Eree.")
say_cannot = list("Errerr.")
say_maybe_target = list("Eree?")
say_got_target = list("Ereet!")
say_threaten = list("Skree!")
say_stand_down = list("Eee.")
say_escalate = list("SKREE!")
threaten_sound = 'sound/metroid/metroidsee.ogg'
stand_down_sound = 'sound/metroid/metroiddetach.ogg'
/mob/living/simple_mob/metroid/init_vore()
if(!voremob_loaded)
return
.=..()
var/obj/belly/B = vore_selected
B.digest_brute = 1
B.digest_burn = 1
B.vore_verb = "swallow"
B.name = "membrane" //THERE IS A RUNTIME HERE SOMEHOW
B.desc = "The metroid positions itself above you and swoops down, lazily enveloping you through its tight mouth and sending you straight to its bulbous membrane for all to see."
B.emote_lists[DM_HOLD] = list(
"The metroid's cortex tentacles wriggle over you, violating and teasing you as they sopped you in viscous slime.",
"The cortex you are forced against pulses with life, gently squeezing you between it and the stretchy membrane around you.",
"You press your face against the transparent membrane, watching how the world distorts as it stretches over your eyes.",
"The air around you is so thick. You struggle to breathe occasionally, choking on the heat and moisture.",
"You struggle a bit, making the membrane swell out."
)
B.emote_lists[DM_DIGEST] = list(
"The cortex tentacles are pulsating like lines of power streaking away from you as it drains you. Waves of sleepiness wash over you as the areas most closest to the tentacles are drained of energy.",
"The air feels a tinge incendiary as the cortex you rest on heats up, fueled by your own body as the metroid draws your strenght away from you.",
"As you grow weaker, your movements against the membrane grow weaker as well, making you feel as if the membrane is closing around you, wrapping and squeezing you, draining you for all you are worth.",
"You feel faint as the tentacles wrapped around you sap you of your strength, seemingly eager to drain and claim you for food."
)
B.digest_messages_prey = list(
"You can't stay awake anymore, the clear world around you going fuzzy until you can see it no more.",
"The tinge of the air grows to a crescendo and then fades away, just as the rest of your body fizzles into energy for the metroid.",
"The tentacles squeeze you one last time as the last of your energy is sapped and your body is claimed as food for the metroid.",
"The metroid swells as it absorbs the rest of your life force and nutrients into its body, making it stronger and even hungry for more."
)
/mob/living/simple_mob/metroid/death()
// playsound(src, 'sound/metroid/metroiddeath.ogg', 75, 1)
..()

View File

@@ -0,0 +1,140 @@
// Handles hunger, starvation, growth, and eatting humans.
/mob/living/simple_mob/metroid/juvenile/adjust_nutrition(input, var/heal = 1)
..(input)
if(input > 0)
// Gain around one level per 50 nutrition.
if(prob(input * 2))
power_charge = min(power_charge++, 10)
if(power_charge == 10)
adjustToxLoss(-10)
// Heal 1 point of damage per 5 nutrition coming in.
if(heal)
adjustBruteLoss(-input * 0.2)
adjustFireLoss(-input * 0.2)
adjustToxLoss(-input * 0.2)
adjustOxyLoss(-input * 0.2)
adjustCloneLoss(-input * 0.2)
/mob/living/simple_mob/metroid/juvenile/proc/handle_consumption()
if(victim && !stat)
if(istype(victim) && consume(victim, 20))
if(prob(25))
to_chat(src, span_notice("You continue absorbing \the [victim]."))
else
var/list/feedback = list(
"This subject is incompatable",
"This subject does not have a life energy",
"This subject is empty",
"I am not satisfied",
"I can not feed from this subject",
"I do not feel nourished",
"This subject is not food"
)
to_chat(src, span_warning("[pick(feedback)]..."))
stop_consumption()
if(victim)
victim.updatehealth()
else
stop_consumption()
/mob/living/simple_mob/metroid/juvenile/proc/start_consuming(mob/living/L)
if(!is_juvenile)
return
if(!can_consume(L))
return
if(!Adjacent(L))
return
step_towards(src, L) // Get on top of them to feed.
if(loc != L.loc)
return
if(L.buckle_mob(src, forced = TRUE))
victim = L
update_icon()
set_AI_busy(TRUE) // Don't want the AI to interfere with eatting.
playsound(src, 'sound/metroid/metroidattach.ogg', 50, 1)
victim.visible_message(
span_danger("\The [src] latches onto \the [victim]!"),
span_critical("\The [src] latches onto you!")
)
/mob/living/simple_mob/metroid/juvenile/proc/stop_consumption(mob/living/L)
if(!victim)
return
playsound(src, 'sound/metroid/metroiddetach.ogg', 50, 1)
victim.unbuckle_mob()
victim.visible_message(
span_notice("\The [src] slides off of [victim]!"),
span_notice("\The [src] slides off of you!")
)
victim = null
update_icon()
spawn(30)
set_AI_busy(FALSE) // Resume normal operations.
/mob/living/simple_mob/metroid/juvenile/proc/can_consume(mob/living/L)
if(!L || !istype(L))
to_chat(src, "This subject is incomparable...")
return FALSE
if(harmless)
to_chat(src, "I am pacified... I cannot eat...")
return FALSE
if(L.mob_class & MOB_CLASS_SLIME)
to_chat(src, "I cannot feed on other slimes...")
return FALSE
if(L.isSynthetic())
to_chat(src, "This subject is not biological...")
return FALSE
if(L.getarmor(null, "bio") >= 75)
to_chat(src, "I cannot reach this subject's biological matter...")
return FALSE
if(!Adjacent(L))
to_chat(src, "This subject is too far away...")
return FALSE
if(L.getCloneLoss() >= L.getMaxHealth() * 1.5)
to_chat(src, "This subject does not have an edible life energy...")
return FALSE
//VOREStation Addition start
if(istype(L, /mob/living/carbon/human))
var/mob/living/carbon/human/H = L
if(H.species.flags & NO_SCAN)
to_chat(src, "This subject's life energy is beyond my reach...")
return FALSE
//VOREStation Addition end
if(L.has_buckled_mobs())
for(var/A in L.buckled_mobs)
if(istype(A, /mob/living/simple_mob/slime/xenobio))
if(A != src)
to_chat(src, "\The [A] is already feeding on this subject...")
return FALSE
return TRUE
// This does the actual damage, as well as give nutrition and heals.
// Assuming no bio armor, calling consume(10) will result in;
// 6 clone damage to victim
// 4 tox damage to victim.
// 25 nutrition for the slime.
// 2 points of damage healed on the slime (as a result of the nutrition).
// 50% of giving +1 charge to the slime (same as above).
/mob/living/simple_mob/metroid/juvenile/proc/consume(mob/living/victim, amount)
if(can_consume(victim))
var/armor_modifier = abs((victim.getarmor(null, "bio") / 100) - 1)
var/damage_done = amount * armor_modifier
if(damage_done > 0)
playsound(src, 'sound/metroid/metroidattack.ogg', 100, 1)
victim.adjustCloneLoss(damage_done * 0.6)
victim.adjustToxLoss(damage_done * 0.4)
adjust_nutrition(damage_done * 5)
Beam(victim, icon_state = "slime_consume", time = 8)
to_chat(src, span_notice("You absorb some biomaterial from \the [victim]."))
to_chat(victim, span_danger("\The [src] consumes some of your flesh!"))
return TRUE
return FALSE

View File

@@ -0,0 +1,172 @@
//Some basic metroid specific mechanics. Lifted from slime code, but gutted all the xenobio taming stuff. Feel free to add it back in, but I recommend making a new specific subset of tamable metroids and leaving the others as wild or soemthing.
/mob/living/simple_mob/metroid/juvenile
desc = "This metroid should not be spawned. Yell at your local dev or event manager."
layer = MOB_LAYER + 1 // Need them on top of other mobs or it looks weird when consuming something.
max_nutrition = 1000
var/is_queen = FALSE // When the metroid is a queen, it should just be shitting out babies. Found in metAI.dm and in metTypes for the queen.
var/maxHealth_adult = 200
var/power_charge = 0 // Disarm attacks can shock someone if high/lucky enough.
var/mob/living/victim = null // the person the metroid is currently feeding on
var/amount_grown = 0 // controls how long the metroid has been overfed, if 10, grows or reproduces
var/number = 0 // This is used to make the metroid semi-unique for indentification.
var/harmless = FALSE // Set to true when pacified. Makes the metroid harmless, not get hungry, and not be able to grow/reproduce.
/mob/living/simple_mob/metroid/juvenile/Destroy()
if(victim)
stop_consumption() // Unbuckle us from our victim.
return ..()
/mob/living/simple_mob/metroid/juvenile/handle_special()
if(stat != DEAD)
if(victim)
handle_consumption()
handle_stuttering() // ??
..()
/mob/living/simple_mob/metroid/juvenile/examine(mob/user)
. = ..()
if(stat == DEAD)
. += "It appears to be dead."
else if(incapacitated(INCAPACITATION_DISABLED))
. += "It appears to be incapacitated."
else if(harmless)
. += "It appears to have been pacified."
/mob/living/simple_mob/metroid/juvenile/verb/evolve()
set category = "metroid"
set desc = "This will let you advance to next form."
if(stat)
to_chat(src, span_warning("I must be conscious to do this..."))
return
if(is_queen)
paralysis = 7998
playsound(src, 'sound/metroid/metroidgrow.ogg', 50, 1)
src.visible_message(span_notice("\The [src] begins to lay an egg."))
spawn(50)
new /obj/effect/metroid/egg(loc, src)
adjust_nutrition(-500)
paralysis = 0
return
if(nutrition >= evo_point && !buckled && vore_fullness == 0 && !victim)
if(next == "/mob/living/simple_mob/metroid/juvenile/queen" && GLOB.queen_amount > 0)
to_chat(src, span_warning("There is already a queen."))
return
playsound(src, 'sound/metroid/metroidgrow.ogg', 50, 1)
paralysis = 7998
sleep(50)
expand_troid()
if(nutrition >= evo_limit && (buckled || vore_fullness == 1)) //spit dat crap out if nutrition gets too high!
release_vore_contents()
prey_excludes.Cut()
stop_consumption()
else
to_chat(src, span_warning("I am not ready to evolve yet..."))
/mob/living/simple_mob/metroid/juvenile/proc/expand_troid()
var/mob/living/L
L = new next(get_turf(src)) //Next is a variable defined by metTypes.dm that just points to the next metroid in the evolutionary stage.
if(mind)
src.mind.transfer_to(L)
visible_message(span_warning("\The [src] suddenly evolves!"))
qdel(src)
// Code for metroids attacking other things.
// metroid attacks change based on intent.
/mob/living/simple_mob/metroid/juvenile/apply_attack(mob/living/L, damage_to_do)
if(istype(L))
switch(a_intent)
if(I_HELP) // This shouldn't happen but just in case.
return FALSE
if(I_DISARM)
var/stun_power = between(0, power_charge + rand(0, 3), 10)
if(ishuman(L))
var/mob/living/carbon/human/H = L
stun_power *= max(H.species.siemens_coefficient, 0)
if(prob(stun_power * 10)) // Try an electric shock.
power_charge = max(0, power_charge - 3)
L.visible_message(
span_danger("\The [src] has shocked \the [L]!"),
span_danger("\The [src] has shocked you!")
)
playsound(src, 'sound/weapons/Egloves.ogg', 75, 1)
L.Weaken(4)
L.Stun(4)
do_attack_animation(L)
if(L.buckled)
L.buckled.unbuckle_mob() // To prevent an exploit where being buckled prevents metroids from jumping on you.
L.stuttering = max(L.stuttering, stun_power)
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(5, 1, L)
s.start()
if(prob(stun_power * 10) && stun_power >= 8)
L.adjustFireLoss(power_charge * rand(1, 2))
return FALSE
else if(prob(20)) // Try to do a regular disarm attack.
L.visible_message(
span_danger("\The [src] has pounced at \the [L]!"),
span_danger("\The [src] has pounced at you!")
)
playsound(src, 'sound/weapons/thudswoosh.ogg', 75, 1)
L.Weaken(2)
do_attack_animation(L)
if(L.buckled)
L.buckled.unbuckle_mob() // To prevent an exploit where being buckled prevents metroids from jumping on you.
return FALSE
else // Failed to do anything this time.
L.visible_message(
span_warning("\The [src] has tried to pounce at \the [L]!"),
span_warning("\The [src] has tried to pounce at you!")
)
playsound(src, 'sound/weapons/punchmiss.ogg', 75, 1)
do_attack_animation(L)
return FALSE
if(I_GRAB)
start_consuming(L)
return FALSE
if(I_HURT)
return ..() // Regular stuff.
else
return ..() // Do the regular stuff if we're hitting a window/mech/etc.
/mob/living/simple_mob/metroid/juvenile/apply_melee_effects(mob/living/L)
if(istype(L) && a_intent == I_HURT)
// Feed off of their flesh, if able.
consume(L, 5)
//Code to remove metroid from someone
/mob/living/simple_mob/metroid/juvenile/attack_hand(mob/living/L)
if(victim) // Are we eating someone?
var/fail_odds = 30
if(victim == L) // Harder to get the metroid off if it's you that is being eatten.
fail_odds = 60
if(prob(fail_odds))
visible_message(span_warning("\The [L] attempts to wrestle \the [name] off!"))
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
else
visible_message(span_warning("\The [L] manages to wrestle \the [name] off!"))
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
stop_consumption()
step_away(src, L)
else
..()

View File

@@ -0,0 +1,42 @@
/*
//Objects related to the Metroids.
*/
//Projectile for the Metroids.
/obj/item/projectile/energy/metroidacid
name = "metroid acid"
icon_state = "neurotoxin"
damage = 10
damage_type = TOX
agony = 10
check_armour = "bio"
armor_penetration = 50
//EGG! Metroid egg and its mechanics. Ripped from spiders.
/obj/effect/metroid/egg
name = "egg cluster"
desc = "It seems to pulse slightly with an inner life"
icon = 'icons/mob/metroid/small.dmi'
icon_state = "egg"
var/amount_grown = 0
var/metroid_type = /mob/living/simple_mob/metroid/juvenile/baby
/obj/effect/metroid/egg/Initialize()
pixel_x = rand(3,-3)
pixel_y = rand(3,-3)
START_PROCESSING(SSobj, src)
return ..()
/obj/effect/metroid/egg/New(var/location, var/atom/parent)
get_light_and_color(parent)
..()
/obj/effect/metroid/egg/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/effect/metroid/egg/process()
amount_grown += rand(0,2)
if(amount_grown >= 100)
new metroid_type(src.loc, src)
qdel(src)

View File

@@ -0,0 +1,669 @@
GLOBAL_VAR_INIT(queen_amount, 0) //We only gonna want 1 queen in the world.
/*
//All the REAL types of metroids!
*/
//Remember to add vent crawling at some point.
/mob/living/simple_mob/metroid/jellybrig //Security's pet
name = "Jellybrig"
desc = "This one scree's happily at you."
ai_holder_type = /datum/ai_holder/simple_mob/jellybrig //Instead of normal metroid code, this guy is basically a retaliatory punching bag.
say_list_type = /datum/say_list/metroid
faction = "notmetroid"
maxHealth = 400
health = 400
melee_damage_lower = 0
melee_damage_upper = 0
movement_cooldown = 6
harm_intent_damage = 2
armor = list(
"melee" = 50,
"bullet" = -90,
"laser" = 0,
"energy" = -50,
"bomb" = -100,
"bio" = 100,
"rad" = 100)
vore_active = 1
vore_bump_chance = 25
vore_capacity = 1
vore_icons = SA_ICON_LIVING
vore_pounce_chance = 90 //Don't punch or grab this guy. He will grab you instead!
swallowTime = 1 SECONDS //Hungry little bastards.
vore_default_mode = DM_HOLD
vore_digest_chance = 1 //Chance to switch to digest mode if resisted
vore_absorb_chance = 0
vore_escape_chance = 2 //Chance to escape if resisted.
/datum/ai_holder/simple_mob/jellybrig
hostile = FALSE // The majority of simplemobs are hostile, jellybrig is nice.
cooperative = FALSE
retaliate = TRUE //so the monster can attack back
returns_home = FALSE
can_flee = FALSE
wander = TRUE
base_wander_delay = 9
/mob/living/simple_mob/metroid/mine
name = "Mochtroid"
desc = "Some sort of person eaty thing! But weak compared to regular Metroids!"
tt_desc = "Headamus Suckumus Weakamus"
icon = 'icons/mob/metroid/small.dmi'
icon_dead = "metroid_dead"
icon_living = "mochtroid"
icon_state = "mochtroid"
movement_cooldown = 2
next = null
vore_active = 1
vore_pounce_chance = 25
vore_icons = SA_ICON_LIVING
/mob/living/simple_mob/metroid/mine/init_vore()
if(!voremob_loaded)
return
.=..()
var/obj/belly/B = vore_selected
B.digest_burn = 0.5
B.digest_brute = 0
/mob/living/simple_mob/metroid/mine/death()
// playsound(src, 'sound/metroid/metroiddeath.ogg', 50, 1)
..()
if(prob(20))
visible_message(span_notice("\The [src] dropped some toy!"))
new /obj/item/toy/figure/bounty_hunter(loc, src)
/mob/living/simple_mob/metroid/juvenile
var/is_juvenile = FALSE
/mob/living/simple_mob/metroid/juvenile/baby
name = "baby metroid"
desc = "The baby the baby the baby the baby the baby the baby the baby the baby."
tt_desc = "Minimus Headamus Suckumus"
icon = 'icons/mob/metroid/small.dmi'
icon_dead = "baby_dead"
icon_living = "baby"
icon_state = "baby"
ai_holder_type = /datum/ai_holder/simple_mob/juvenile_metroid
say_list_type = /datum/say_list/metroid
health = 200
maxHealth = 200
melee_damage_lower = 1
melee_damage_upper = 5
melee_miss_chance = 0
armor = list(
"melee" = 0,
"bullet" = -60,
"laser" = 60,
"energy" = 10,
"bomb" = -100,
"bio" = 100,
"rad" = 100)
gender = NEUTER
faction = "metroids"
max_nutrition = 2200
nutrition = 0
//Metroids aren't affected by most atmospheres except cold.
minbodytemp = T0C-40
cold_damage_per_tick = 100
min_oxy = 0
max_oxy = 0
min_tox = 0
max_tox = 0
min_co2 = 0
max_co2 = 0
min_n2 = 0
max_n2 = 0
response_help = "pets"
evo_point = 800
evo_limit = 1000
next = "/mob/living/simple_mob/metroid/juvenile/super"
vore_active = 0
is_juvenile = TRUE
/mob/living/simple_mob/metroid/juvenile/baby/Initialize(mapload)
. = ..()
playsound(src, 'sound/metroid/metroidsee.ogg', 100, 1)
//------------------------------------------------------------------------------------------------------------
/mob/living/simple_mob/metroid/juvenile/super
name = "super metroid"
desc = "Some kind of head sucky thing!"
tt_desc = "Maximus Headamus Suckumus"
icon = 'icons/mob/metroid/small.dmi'
icon_dead = "metroid_dead"
icon_living = "metroid"
icon_state = "metroid"
ai_holder_type = /datum/ai_holder/simple_mob/juvenile_metroid
say_list_type = /datum/say_list/metroid
health = 250
maxHealth = 250
melee_damage_lower = 2
melee_damage_upper = 9
melee_miss_chance = 0
armor = list(
"melee" = 0,
"bullet" = -50,
"laser" = 70,
"energy" = 10,
"bomb" = -100,
"bio" = 100,
"rad" = 100)
gender = NEUTER
faction = "metroids"
max_nutrition = 2200
nutrition = 0
//Metroids aren't affected by most atmospheres except cold.
minbodytemp = T0C-40
cold_damage_per_tick = 100
min_oxy = 0
max_oxy = 0
min_tox = 0
max_tox = 0
min_co2 = 0
max_co2 = 0
min_n2 = 0
max_n2 = 0
response_help = "pets"
speak_emote = list(
"Skree...",
"Ereeeer..."
)
evo_point = 1200
evo_limit = 1600
next = "/mob/living/simple_mob/metroid/juvenile/alpha"
vore_active = 1
vore_bump_chance = 0
vore_capacity = 1
vore_icons = SA_ICON_LIVING
vore_pounce_chance = 25 //Metroids only eat incapacitated targets
vore_default_mode = DM_DIGEST
swallowTime = 1 SECONDS //Hungry little bastards.
vore_escape_chance = 50
is_juvenile = TRUE
/mob/living/simple_mob/metroid/juvenile/super/Initialize(mapload)
. = ..()
playsound(src, 'sound/metroid/metroidsee.ogg', 100, 1)
/mob/living/simple_mob/metroid/juvenile/super/death()
// playsound(src, 'sound/metroid/metroiddeath.ogg', 100, 1)
..()
/mob/living/simple_mob/metroid/juvenile/alpha
name = "alpha metroid"
desc = "Some kind of head rammy thing!"
tt_desc = "Minimus Headamus Rammamus"
icon = 'icons/mob/metroid/small.dmi'
icon_dead = "alpha_dead"
icon_living = "alpha"
icon_state = "alpha"
ai_holder_type = /datum/ai_holder/simple_mob/juvenile_metroid
say_list_type = /datum/say_list/metroid
health = 300
maxHealth = 300
melee_damage_lower = 10
melee_damage_upper = 15
melee_miss_chance = 5
attacktext = list("rammed")
armor = list(
"melee" = 40,
"bullet" = 15,
"laser" = 50,
"energy" = 60,
"bomb" = 10,
"bio" = 100,
"rad" = 100)
gender = NEUTER
faction = "metroids"
max_nutrition = 2200
nutrition = 0
//Alphas lose their vulnerability to cold.
minbodytemp = 0
min_oxy = 0
max_oxy = 0
min_tox = 0
max_tox = 0
min_co2 = 0
max_co2 = 0
min_n2 = 0
max_n2 = 0
unsuitable_atoms_damage = 0
evo_point = 1000
evo_limit = 1500
next = "/mob/living/simple_mob/metroid/juvenile/gamma"
/mob/living/simple_mob/metroid/juvenile/alpha/Initialize(mapload)
. = ..()
playsound(src, 'sound/metroid/metroidsee.ogg', 100, 1)
/mob/living/simple_mob/metroid/juvenile/alpha/death()
// playsound(src, 'sound/metroid/metroiddeath.ogg', 100, 1)
..()
/mob/living/simple_mob/metroid/juvenile/alpha //active noms
vore_active = 1
vore_bump_chance = 0
vore_capacity = 1
vore_icons = SA_ICON_LIVING
vore_pounce_chance = 15 //Alphas will try knocking targets over since they lost their stun ability from the initial phases.
vore_default_mode = DM_DIGEST
swallowTime = 3 SECONDS
vore_escape_chance = 40
//------------------------------------------------------------------------------------------------------------
/mob/living/simple_mob/metroid/juvenile/gamma
name = "gamma metroid"
desc = "Some kind of head rammy thing! This one shoots electricity!"
tt_desc = "Maximus Headamus Rammamus"
icon = 'icons/mob/metroid/small.dmi'
icon_dead = "gamma_dead"
icon_living = "gamma"
icon_state = "gamma"
ai_holder_type = /datum/ai_holder/simple_mob/juvenile_metroid
say_list_type = /datum/say_list/metroid
movement_cooldown = 2
health = 400
maxHealth = 400
melee_damage_lower = 10
melee_damage_upper = 20
melee_miss_chance = 5
attacktext = list("rammed")
armor = list(
"melee" = 55,
"bullet" = 15,
"laser" = 50,
"energy" = 90,
"bomb" = 10,
"bio" = 100,
"rad" = 100)
gender = NEUTER
faction = "metroids"
max_nutrition = 2200
nutrition = 0
ranged_cooldown_time = 5 SECOND
projectilesound = 'sound/weapons/taser2.ogg'
projectiletype = /obj/item/projectile/energy/mob/electric_spider
//Not affected by atmos.
minbodytemp = 0
min_oxy = 0
max_oxy = 0
min_tox = 0
max_tox = 0
min_co2 = 0
max_co2 = 0
min_n2 = 0
max_n2 = 0
unsuitable_atoms_damage = 0
var/emp_chance = 20 // Beware synths
evo_point = 1000
evo_limit = 1500
next = "/mob/living/simple_mob/metroid/juvenile/zeta"
/mob/living/simple_mob/metroid/juvenile/gamma/Initialize(mapload)
. = ..()
playsound(src, 'sound/metroid/metroidgamma.ogg', 100, 1)
/mob/living/simple_mob/metroid/juvenile/gamma/death()
// playsound(src, 'sound/metroid/metroiddeath.ogg', 100, 1)
..()
/mob/living/simple_mob/metroid/juvenile/gamma //active noms
vore_active = 1
vore_bump_chance = 0
vore_capacity = 1
vore_icons = SA_ICON_LIVING
vore_pounce_chance = 15
vore_default_mode = DM_DIGEST
swallowTime = 3 SECONDS
vore_escape_chance = 30
/datum/say_list/metroid
speak = list("Skree.", "Eree.", "Errer?")
emote_see = list("floats about","looks around", "rubs its talons")
emote_hear = list("chitters")
say_understood = list("Eree.")
say_cannot = list("Errerr.")
say_maybe_target = list("Eree?")
say_got_target = list("Ereet!")
say_threaten = list("Skree!")
say_stand_down = list("Eee.")
say_escalate = list("SKREE!")
threaten_sound = 'sound/metroid/metroidsee.ogg'
stand_down_sound = 'sound/metroid/metroiddetach.ogg'
//------------------------------------------------------------------------------------------------------------
/mob/living/simple_mob/metroid/juvenile/zeta
name = "zeta metroid"
desc = "Some kind of feet stompy thing!"
tt_desc = "Minimus Feetamus Walkamus"
icon = 'icons/mob/metroid/large.dmi'
icon_dead = "zeta_dead"
icon_living = "zeta"
icon_state = "zeta"
ai_holder_type = /datum/ai_holder/simple_mob/juvenile_metroid
say_list_type = /datum/say_list/metroid/zeta
movement_cooldown = 2
health = 500
maxHealth = 500
melee_damage_lower = 15
melee_damage_upper = 25
melee_miss_chance = 5
ranged_cooldown_time = 5 SECOND
attack_armor_pen = 10
attacktext = list("slashed")
armor = list(
"melee" = 70,
"bullet" = 0,
"laser" = 50,
"energy" = 60,
"bomb" = 10,
"bio" = 100,
"rad" = 100)
gender = NEUTER
faction = "metroids"
max_nutrition = 2200
nutrition = 0
makes_dirt = TRUE
projectiletype = /obj/item/projectile/energy/metroidacid //The projectiles I shoot
projectilesound = 'sound/weapons/slashmiss.ogg' // The sound I make when I do it
//Unaffected by atmos.
minbodytemp = 0
min_oxy = 0
max_oxy = 0
min_tox = 0
max_tox = 0
min_co2 = 0
max_co2 = 0
min_n2 = 0
max_n2 = 0
unsuitable_atoms_damage = 0
pixel_x = -16
pixel_y = -16
old_x = -16
old_y = -16
evo_point = 1200
evo_limit = 1500
next = "/mob/living/simple_mob/metroid/juvenile/omega"
/mob/living/simple_mob/metroid/juvenile/zeta/Initialize(mapload)
. = ..()
playsound(src, 'sound/metroid/metroidzeta.ogg', 100, 1)
/mob/living/simple_mob/metroid/juvenile/zeta/death()
// playsound(src, 'sound/metroid/metroiddeath.ogg', 100, 1)
..()
/mob/living/simple_mob/metroid/juvenile/zeta //active noms
vore_active = 1
vore_bump_chance = 0
vore_capacity = 1
vore_icons = SA_ICON_LIVING
vore_pounce_chance = 20
vore_default_mode = DM_DIGEST
swallowTime = 3 SECONDS
vore_escape_chance = 20
/datum/say_list/metroid/zeta
speak = list("Rurrr.", "Rrerr.", "Rawr?")
emote_see = list("stomps about","looks around", "rubs its talons")
emote_hear = list("chitters")
say_understood = list("Rur.")
say_cannot = list("Errurr.")
say_maybe_target = list("Erurr?")
say_got_target = list("Eruur!")
say_threaten = list("Rrurr!")
say_stand_down = list("Eeer.")
say_escalate = list("RAWR!")
threaten_sound = 'sound/metroid/metroidzeta.ogg'
stand_down_sound = 'sound/metroid/metroiddetach.ogg'
//------------------------------------------------------------------------------------------------------------
/mob/living/simple_mob/metroid/juvenile/omega
name = "omega metroid"
desc = "Those are some big claws!"
tt_desc = "Maximus Feetamus Walkamus"
icon = 'icons/mob/metroid/large.dmi'
icon_dead = "omega_dead"
icon_living = "omega"
icon_state = "omega"
ai_holder_type = /datum/ai_holder/simple_mob/juvenile_metroid
say_list_type = /datum/say_list/metroid/omega
movement_cooldown = 2.5
health = 600
maxHealth = 600
melee_damage_lower = 25
melee_damage_upper = 40
melee_miss_chance = 5
ranged_cooldown_time = 2.5 SECOND
attack_armor_pen = 20
attacktext = list("slashed")
armor = list(
"melee" = 75,
"bullet" = 20,
"laser" = 55,
"energy" = 60,
"bomb" = 10,
"bio" = 100,
"rad" = 100)
gender = NEUTER
faction = "metroids"
max_nutrition = 2200
nutrition = 0
makes_dirt = TRUE
projectiletype = /obj/item/projectile/energy/mob/smalllaser
projectilesound = 'sound/weapons/Flamer.ogg' // The sound I make when I do it
//Unaffected by atmos.
minbodytemp = 0
min_oxy = 0
max_oxy = 0
min_tox = 0
max_tox = 0
min_co2 = 0
max_co2 = 0
min_n2 = 0
max_n2 = 0
unsuitable_atoms_damage = 0
old_x = -16
old_y = 0
default_pixel_x = -16
pixel_x = -16
pixel_y = 0
evo_point = 1300
evo_limit = 2000
next = "/mob/living/simple_mob/metroid/juvenile/queen"
death_sound_override = list('sound/metroid/metroidomegadeath.ogg') // We override the death sound to play our custom here
/mob/living/simple_mob/metroid/juvenile/omega/Initialize(mapload)
. = ..()
playsound(src, 'sound/metroid/metroidomega.ogg', 100, 1)
/mob/living/simple_mob/metroid/juvenile/omega/death()
// playsound(src, 'sound/metroid/metroidomegadeath.ogg', 100, 1)
..()
/mob/living/simple_mob/metroid/juvenile/omega //active noms
vore_active = 1
vore_bump_chance = 0
vore_capacity = 2
vore_icons = SA_ICON_LIVING
vore_pounce_chance = 40
vore_default_mode = DM_DIGEST
swallowTime = 3 SECONDS
vore_escape_chance = 10
/datum/say_list/metroid/omega
speak = list("Rurrr.", "Rrerr.", "Rawr?")
emote_see = list("stomps about","looks around", "rubs its talons")
emote_hear = list("chitters")
say_understood = list("Rur.")
say_cannot = list("Errurr.")
say_maybe_target = list("Erurr?")
say_got_target = list("Roar!")
say_threaten = list("Rrurr!")
say_stand_down = list("Eeer.")
say_escalate = list("ROAR!")
threaten_sound = 'sound/metroid/metroidomega.ogg'
stand_down_sound = 'sound/metroid/metroiddetach.ogg'
//------------------------------------------------------------------------------------------------------------
/mob/living/simple_mob/metroid/juvenile/queen
name = "queen metroid"
desc = "The mother of all Metroids - allowed to have grown too far!"
tt_desc = "Maximus Queenamus Deathamus"
icon = 'icons/mob/metroid/queen.dmi'
icon_dead = "queen_dead"
icon_living = "queen"
icon_state = "queen"
ai_holder_type = /datum/ai_holder/simple_mob/juvenile_metroid
say_list_type = /datum/say_list/metroid/queen
movement_cooldown = 3
health = 1000
maxHealth = 1000
melee_damage_lower = 30
melee_damage_upper = 60
melee_miss_chance = 5
attack_armor_pen = 20
attacktext = list("gnashed")
armor = list(
"melee" = 75,
"bullet" = 40,
"laser" = 60,
"energy" = 90,
"bomb" = 10,
"bio" = 100,
"rad" = 100)
gender = NEUTER
faction = "metroids"
max_nutrition = 2200
nutrition = 0
makes_dirt = TRUE
ranged_cooldown_time = 1.5 SECOND
projectiletype = /obj/item/projectile/energy/metroidacid // The projectiles I shoot
projectilesound = 'sound/weapons/slashmiss.ogg' // The sound I make when I do it
//Unaffected by atmos.
minbodytemp = 0
min_oxy = 0
max_oxy = 0
min_tox = 0
max_tox = 0
min_co2 = 0
max_co2 = 0
min_n2 = 0
max_n2 = 0
unsuitable_atoms_damage = 0
pixel_x = -16
pixel_y = -16
old_x = -16
old_y = -16
evo_point = 1200
evo_limit = INFINITY
next = null
is_queen = TRUE
death_sound_override = list('sound/metroid/metroidqueendeath.ogg') // We override the death sound to play our custom here
/mob/living/simple_mob/metroid/juvenile/queen/Initialize(mapload)
. = ..()
playsound(src, 'sound/metroid/metroidqueen.ogg', 100, 1)
GLOB.queen_amount++
/mob/living/simple_mob/metroid/juvenile/queen/death()
// playsound(src, 'sound/metroid/metroidqueendeath.ogg', 100, 1)
GLOB.queen_amount--
..()
/mob/living/simple_mob/metroid/juvenile/queen //active noms
vore_active = 1
vore_bump_chance = 0
vore_capacity = 4
vore_icons = SA_ICON_LIVING
vore_pounce_chance = 60 //It's the queen, and it's hungry.
vore_default_mode = DM_DIGEST
swallowTime = 3 SECONDS
vore_escape_chance = 0 //You're not climbing out of that neck
/datum/say_list/metroid/queen
speak = list("Rurrr.", "Rrerr.", "Rawr?")
emote_see = list("stomps about","looks around", "rubs its talons")
emote_hear = list("chitters")
say_understood = list("Rur.")
say_cannot = list("Errurr.")
say_maybe_target = list("Erurr?")
say_got_target = list("Roar!")
say_threaten = list("Rrurr!")
say_stand_down = list("Eeer.")
say_escalate = list("ROAR!")
threaten_sound = 'sound/metroid/metroidqueen.ogg'
stand_down_sound = 'sound/metroid/metroiddetach.ogg'

View File

@@ -0,0 +1,325 @@
#define NUTRITION_FRUIT 250 //The amount of nutrition needed to produce a fruit
#define NUTRITION_PITCHER 3 * NUTRITION_FRUIT //The amount of nutrition needed to produce a new pitcher
#define NUTRITION_MEAT 50 //The amount of nutrition provided by slabs of meat
#define PITCHER_SATED 250 //The amount of nutrition needed before the pitcher will attempt to grow fruit.
#define PITCHER_HUNGRY 150 //The nutrition cap under which the pitcher actively attempts to lure prey.
GLOBAL_LIST_INIT(pitcher_plant_lure_messages, list(
"The pitcher plant smells lovely, beckoning you closer.",
"The sweet scent wafting from the pitcher plant makes your mouth water.",
"You feel an urge to investigate the pitcher plant closely.",
"You find yourself staring at the pitcher plant without really thinking about it.",
"Doesn't the pitcher plant smell amazing?")) //Messages sent to nearby players if the pitcher is trying to lure prey. This is global to prevent a new list every time a new pitcher plant spawns.
//Pitcher plants, a passive carnivorous plant mob for xenobio and space vine spawning.
//Consider making immune to space vine entangling. Check entangle_immunity in the old CHOMPstation github for an example.
/mob/living/simple_mob/vore/pitcher_plant
name = "pitcher plant"
desc = "A carnivorous pitcher plant, bigger than a man."
tt_desc = "Sarraceniaceae gigantus"
icon_state = "pitcher_plant"
icon_living = "pitcher_plant"
icon_dead = "pitcher_plant_dead"
icon = 'modular_chomp/icons/mob/vore_ch.dmi'
anchored = 1 //Rooted plant. Only killing it will let you move it.
maxHealth = 200
health = 200
a_intent = I_HELP //White this is help by default I'm leaving this here as a reminder thatdisarm will prevent playersfrom swapping places with the pitcher (but interfere with vore bump).
faction = "plants" //Makes plantbgone deadly.
ai_holder_type = /datum/ai_holder/simple_mob/passive/pitcher //It's a passive carnivorous plant, it can't detect or interact with people.
min_oxy = 0 //Immune to atmos because so are space vines. This is arbitrary and can be tweaked if desired.
max_oxy = 0
min_tox = 0
max_tox = 0
min_co2 = 0
max_co2 = 0
min_n2 = 0
max_n2 = 0
minbodytemp = 0
melee_damage_upper = 0 //This shouldn't attack people but if it does (admemes) no damage can be dealt.
melee_damage_lower = 0
armor = list(
"melee" = 0,
"bullet" = 0,
"laser" = -50,
"energy" = 0,
"bomb" = 0,
"bio" = 0,
"rad" = 100)
var/fruit = FALSE //Has the pitcher produced a fruit?
var/meat = 0 //How many units of meat is the plant digesting? Separate from actual vore mechanics.
var/meatspeed = 5 //How many units of meat is converted to nutrition each tick?
var/pitcher_metabolism = 0.1 //How much nutriment does the pitcher lose every 2 seconds? 0.1 should be around 30 every 10 minutes.
var/scent_strength = 5 //How much can a hungry pitcher confuse nearby people?
var/last_lifechecks = 0 //Timing variable to limit vore/hungry proc calls
var/list/pitcher_plant_lure_messages = null
can_be_drop_prey = FALSE //CHOMP Add
/mob/living/simple_mob/vore/pitcher_plant //Putting vore variables separately because apparently that's tradition.
vore_bump_chance = 100
vore_bump_emote = "slurps up" //Not really a good way to make the grammar work with a passive vore plant.
vore_active = 1
vore_icons = 1
vore_capacity = 1
vore_pounce_chance = 0 //Plants only eat people who stumble into them.
swallowTime = 3 //3 deciseconds. This is intended to be nearly instant, e.g. victim trips and falls in.
vore_ignores_undigestable = 0
vore_default_mode = DM_DIGEST
/mob/living/simple_mob/vore/pitcher_plant/init_vore()
if(!voremob_loaded)
return
.=..()
var/obj/belly/B = vore_selected
B.desc = "You leaned a little too close to the pitcher plant, stumbling over the lip and splashing into a puddle of liquid filling the bottom of the cramped pitcher. You squirm madly, righting yourself and scrabbling at the walls in vain as the slick surface offers no purchase. The dim light grows dark as the pitcher's cap lowers, silently sealing the exit. With a sinking feeling you realize you won't be able to push the exit open even if you could somehow climb that high, leaving you helplessly trapped in the slick, tingling fluid. ((You can't escape this mob without help but you may use OOC Escape if you wish.))"
B.digest_burn = 0.5
B.digest_brute = 0
B.vore_verb = "trip"
B.name = "pitcher"
B.mode_flags = DM_FLAG_THICKBELLY
B.wet_loop = 0 //As nice as the fancy internal sounds are this is a plant.
B.digestchance = 0
B.escapechance = 0
B.fancy_vore = 1
B.vore_sound = "Squish2"
B.release_sound = "Pred Escape"
B.contamination_color = "purple"
B.contamination_flavor = "Wet"
//Why is it we have all these customizeable belly options which nobody ever alters for mobs?
B.emote_lists[DM_HOLD] = list(
"Slick fluid trickles over you, carrying threads of sweetness.",
"Everything is still, dark, and quiet. Your breaths echo quietly.",
"The surrounding air feels thick and humid.")
B.emote_lists[DM_DIGEST] = list(
"The slimy puddle stings faintly. It seems the plant has no need to quickly break down victims.",
"The humid air settles in your lungs, keeping each breath more labored than the last.",
"Fluid drips onto you, burning faintly as your body heat warms it."
)
B.emote_lists[DM_DRAIN] = list(
"Each bead of slick fluid running down your body leaves you feeling weaker.",
"It's cramped and dark, the air thick and heavy. Your limbs feel like lead.",
"Strength drains from your frame. The cramped chamber feels easier to settle into with each passing moment.")
/mob/living/simple_mob/vore/pitcher_plant/Life()
. = ..()
if(!.)
return
var/lastmeat = meat //If Life procs every 2 seconds that means it takes 20 seconds to digest a steak
meat = max(0,meat - meatspeed) //Clamp it to zero
adjust_nutrition(lastmeat - meat) //If there's no meat, this will just be zero.
if(nutrition >= PITCHER_SATED + NUTRITION_FRUIT)
if(prob(10)) //Should be about once every 20 seconds.
grow_fruit()
var/lastnutrition = nutrition
adjust_nutrition(-pitcher_metabolism)
adjustBruteLoss(nutrition - lastnutrition)
adjustToxLoss((nutrition - lastnutrition) * 3)
if(nutrition < pitcher_metabolism)
adjustToxLoss(pitcher_metabolism)
if(world.time > last_lifechecks + 30 SECONDS)
last_lifechecks = world.time
vore_checks()
handle_hungry()
/mob/living/simple_mob/vore/pitcher_plant/Initialize(mapload)
. = ..()
pitcher_plant_lure_messages = GLOB.pitcher_plant_lure_messages
/mob/living/simple_mob/vore/pitcher_plant/death()
..()
anchored = 0
if(fruit)
new /obj/item/reagent_containers/food/snacks/pitcher_fruit(get_turf(src))
fruit = FALSE
/mob/living/simple_mob/vore/pitcher_plant/proc/grow_fruit() //This proc handles the pitcher turning nutrition into fruit (and new pitchers).
if(!fruit)
if(nutrition >= PITCHER_SATED + NUTRITION_FRUIT)
fruit = TRUE
adjust_nutrition(-NUTRITION_FRUIT)
return
else
return
if(fruit)
if(nutrition >= PITCHER_SATED + NUTRITION_PITCHER)
var/turf/T = safepick(circleviewturfs(src, 2))
if(T.density) //No spawning in walls
return
else if(src.loc ==T)
return
else
new /mob/living/simple_mob/vore/pitcher_plant(get_turf(T))
fruit = FALSE //No admeming this to spawn endless pitchers.
adjust_nutrition(-NUTRITION_PITCHER)
/mob/living/simple_mob/vore/pitcher_plant/attack_hand(mob/living/user)
if(user.a_intent == I_HELP)
if(fruit)
to_chat(user, "You pick a fruit from \the [src].")
var/obj/F = new /obj/item/reagent_containers/food/snacks/pitcher_fruit(get_turf(user)) //Drops at the user's feet if put_in_hands fails
fruit = FALSE
user.put_in_hands(F)
else
to_chat(user, "The [src] hasn't grown any fruit yet!")
else
..()
/mob/living/simple_mob/vore/pitcher_plant/examine(mob/user)
. = ..()
if(fruit)
. += "A plump fruit glistens beneath \the [src]'s cap."
/mob/living/simple_mob/vore/pitcher_plant/attackby(obj/item/O, mob/user)
if(istype(O, /obj/item/reagent_containers/food/snacks/meat))
if(meat > NUTRITION_FRUIT - NUTRITION_MEAT) //Can't exceed 250
to_chat(user, "The [src] is full!")
return
else
meat += NUTRITION_MEAT
qdel(O)
return
if(istype(O, /obj/item/stack/cable_coil)) //How to free people without killing the pitcher. I guess cable is ss13 rope.
var/mob/living/carbon/human/H
var/N = 0
for(H in vore_selected.contents) //Only works for carbons, RIP mice. Should pick the first human the code finds.
user.visible_message("[user] tries to fish somebody out of \the [src].", "You try to snag somebody trapped in \the [src]...")
if(do_after(user, rand(3 SECONDS, 7 SECONDS))) //You can just spam click to stack attempts if you feel like abusing it.
if(prob(15))
user.visible_message("[user] tugs a sticky [H] free from \the [src].", "You heft [H] free from \the [src].")
LAZYSET(prey_excludes, H, world.time)
vore_selected.release_specific_contents(H)
N = 1
addtimer(CALLBACK(src, PROC_REF(removeMobFromPreyExcludes), WEAKREF(H)), 1 MINUTES)
break
else
to_chat(user, "The victim slips from your grasp!")
N = 1
break //We need to terminate the loop after each outcome or this could loop through multiple bellies. Of course, there should only be one belly.
if(!N)
to_chat(user, "The pitcher is empty.")
if(istype(O, /obj/item/newspaper))
return //Can't newspaper people to freedom.
..()
/mob/living/simple_mob/vore/pitcher_plant/proc/vore_checks()
if(ckey) //This isn't intended to be a playable mob but skip all of this if it's player-controlled.
return
if(vore_selected && vore_selected.contents.len) //Looping through all (potential) vore bellies would be more thorough but probably not worth the processing power if this check happens every 30 seconds.
var/mob/living/L
var/N = 0
var/hasdigestable = 0
var/hasindigestable = 0
for(L in vore_selected.contents)
if(istype(L, /mob/living/carbon/human/monkey))
L.nutrition = 0 //No stuffing monkeys with protein shakes for massive nutrition.
if(!L.digestable)
vore_selected.digest_mode = DM_DRAIN
N = 1
hasindigestable = 1
continue
else
vore_selected.digest_mode = DM_DIGEST
N = 1
hasdigestable = 1
continue
if(hasdigestable && hasindigestable)
vore_selected.digest_mode = DM_DIGEST //Let's digest until we digest all the digestable prey, then move onto draining indigestable prey.
if(!N)
vore_selected.release_all_contents() //If there's no prey, spit out everything.
/mob/living/simple_mob/vore/pitcher_plant/proc/handle_hungry() //Let's run this check every 30 seconds. This is how a hungry pitcher tries to lure prey.
if(nutrition <= PITCHER_HUNGRY) //Is sanity check another way to say redundancy?
var/turf/T = get_turf(src)
var/cardinal_turfs = T.CardinalTurfs()
for(var/mob/living/carbon/human/H in oview(2, src))
if(!istype(H) || !isliving(H) || H.stat == DEAD) //Living mobs only
continue
if(isSynthetic(H) || !H.species.breath_type || H.internal) //Exclude species which don't breathe or have internals.
continue
if(src.Adjacent(H)) //If they can breathe and are next to the pitcher, confuse them.
to_chat(H,span_red("The sweet, overwhelming scent from \the [src] makes your senses reel!"))
H.Confuse(scent_strength)
continue
else
to_chat(H, span_red("[pick(pitcher_plant_lure_messages)]"))
for(var/turf/simulated/TR in cardinal_turfs)
TR.wet_floor(1) //Same effect as water. Slip into plant, get ate.
else
return
/mob/living/simple_mob/vore/pitcher_plant/Crossed(atom/movable/AM as mob|obj) //Yay slipnoms
if(AM.is_incorporeal())
return
if(istype(AM, /mob/living) && will_eat(AM) && !istype(AM, type) && prob(vore_bump_chance) && !ckey)
animal_nom(AM)
..()
/datum/ai_holder/simple_mob/passive/pitcher
wander = 0
/obj/item/reagent_containers/food/snacks/pitcher_fruit //As much as I want to tie hydroponics harvest code to the mob, this is simpler (albeit kinda hacky).
name = "squishy fruit"
desc = "A tender, fleshy fruit with a thin skin."
icon = 'icons/obj/hydroponics_products.dmi'
icon_state = "treefruit-product"
color = "#a839a2"
trash = /obj/item/seeds/pitcherseed
nutriment_amt = 1
nutriment_desc = list("pineapple" = 1)
w_class = ITEMSIZE_SMALL
var/datum/seed/seed = null
var/obj/item/seeds/pit = null
/obj/item/reagent_containers/food/snacks/pitcher_fruit/Initialize(mapload)
. = ..()
reagents.add_reagent(REAGENT_ID_PITCHERNECTAR, 5)
bitesize = 4
pit = new /obj/item/seeds/pitcherseed(src.contents)
seed = pit.seed
/obj/item/reagent_containers/food/snacks/pitcher_fruit/afterattack(obj/O as obj, mob/user as mob, proximity)
if(istype(O,/obj/machinery/microwave))
return ..()
if(istype (O, /obj/machinery/seed_extractor))
pit.loc = O.loc //1 seed, perhaps balanced because you can get the reagents and the seed. Can be increased if desirable.
qdel(src)
if(!(proximity && O.is_open_container()))
return
to_chat(user, span_notice("You squeeze \the [src], juicing it into \the [O]."))
reagents.trans_to(O, reagents.total_volume)
user.drop_from_inventory(src)
pit.loc = user.loc
qdel(src)
/obj/item/reagent_containers/food/snacks/pitcher_fruit/attack_self(mob/user)
to_chat(user, span_notice("You plant the fruit."))
new /obj/machinery/portable_atmospherics/hydroponics/soil/invisible(get_turf(user),src.seed)
GLOB.seed_planted_shift_roundstat++
qdel(src)
return
#undef NUTRITION_FRUIT
#undef NUTRITION_PITCHER
#undef NUTRITION_MEAT
#undef PITCHER_SATED
#undef PITCHER_HUNGRY

View File

@@ -50,7 +50,7 @@ GLOBAL_VAR_INIT(dynamic_sector_master, null)
shuttle_landmarks[i] = spawn_directions
generated_z = TRUE
/obj/effect/overmap/visitable/dynamic/Initialize()
/obj/effect/overmap/visitable/dynamic/Initialize(mapload)
if(!GLOB.dynamic_sector_master)
GLOB.dynamic_sector_master = src
. = ..()
@@ -141,7 +141,7 @@ GLOBAL_VAR_INIT(dynamic_sector_master, null)
var/loaded = FALSE
var/my_index = 0 // Tracks which z-level we're using in the parent. Corresponds to index in parent's active_pois[]
/obj/effect/overmap/visitable/dynamic/poi/Initialize()
/obj/effect/overmap/visitable/dynamic/poi/Initialize(mapload)
if(!global.using_map.use_overmap)
return INITIALIZE_HINT_QDEL