Merge pull request #844 from CHOMPStation2/metroid

Current Metroid Progress
This commit is contained in:
Razgriz
2020-11-15 13:59:33 -07:00
committed by GitHub
8 changed files with 1262 additions and 1206 deletions
@@ -1,78 +1,75 @@
// 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.
var/always_stun = FALSE // If true, the slime will elect to attempt to permastun the target.
/*
/datum/ai_holder/simple_mob/juvenile_metroid/ranged
pointblank = TRUE
*/
/datum/ai_holder/simple_mob/juvenile_metroid/passive/New() // For Jellybrig.
..()
pacify()
/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 slime 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.
if(my_juvenile.is_adult)
my_juvenile.reproduce() // Splits into four new baby slimes.
else
my_juvenile.evolve() // Turns our holder into an adult slime.
// Called when using a pacification agent (or it's Jellybrig being initalized). Actually it's all just jellybrig, but I'm stealing everything from slime code anyway.
/datum/ai_holder/simple_mob/juvenile_metroid/proc/pacify()
remove_target() // So it stops trying to kill them.
hostile = FALSE
retaliate = TRUE //Exceot for this. He retaliates because he's a vore mob.
cooperative = FALSE
holder.a_intent = I_HELP
// 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.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 slimes 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).
// 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 slime 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/passive/New() // For Jellybrig.
..()
pacify()
/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 slime 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 slime.
// Called when using a pacification agent (or it's Jellybrig being initalized). Actually it's all just jellybrig, but I'm stealing everything from slime code anyway.
/datum/ai_holder/simple_mob/juvenile_metroid/proc/pacify()
remove_target() // So it stops trying to kill them.
hostile = FALSE
retaliate = TRUE //Exceot for this. He retaliates because he's a vore mob.
cooperative = FALSE
holder.a_intent = I_HELP
// 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 slimes 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).
@@ -1,111 +1,111 @@
// 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 = 0
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
max_nutrition = 2200
nutrition = 0
var/evo_point = 0
var/evo_limit = 0
var/next
meat_type = /obj/item/toy/figure/bounty_hunter
/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/slime/Initialize()
verbs += /mob/living/proc/ventcrawl
update_icon()
return ..()
/mob/living/simple_mob/metroid/init_vore()
..()
var/obj/belly/B = vore_selected
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)
// 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 = 0
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
max_nutrition = 2200
nutrition = 0
var/evo_point = 0
var/evo_limit = 0
var/next
meat_type = /obj/item/toy/figure/bounty_hunter
/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/slime/Initialize()
verbs += /mob/living/proc/ventcrawl
update_icon()
return ..()
/mob/living/simple_mob/metroid/init_vore()
..()
var/obj/belly/B = vore_selected
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)
..()
@@ -1,136 +1,138 @@
// 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.
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
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()
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)
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
// 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.
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()
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
@@ -1,141 +1,176 @@
// These slimes have the mechanics xenobiologists care about, such as reproduction, mutating into new colors, and being able to submit through fear.
/mob/living/simple_mob/metroid/juvenile
desc = "The most basic of slimes. The grey slime has no remarkable qualities, however it remains one of the most useful colors for scientists."
layer = MOB_LAYER + 1 // Need them on top of other mobs or it looks weird when consuming something.
// ai_holder_type = /datum/ai_holder/simple_mob/xenobio_slime // This should never be changed for xenobio slimes.
max_nutrition = 1000
var/is_adult = FALSE // Slimes turn into adults when fed enough. Adult slimes are somewhat stronger, and can reproduce if fed enough.
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 slime is currently feeding on
// var/mutation_chance = 25 // Odds of spawning as a new color when reproducing. Can be modified by certain xenobio products. Carried across generations of slimes.
var/amount_grown = 0 // controls how long the slime has been overfed, if 10, grows or reproduces
var/number = 0 // This is used to make the slime semi-unique for indentification.
var/harmless = FALSE // Set to true when pacified. Makes the slime 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/update_icon()
icon = "
icon_living = "[icon_state_override ? "[icon_state_override] slime" : "slime"] [is_adult ? "adult" : "baby"][victim ? " eating" : ""]"
icon_dead = "[icon_state_override ? "[icon_state_override] slime" : "slime"] [is_adult ? "adult" : "baby"] dead"
icon_rest = icon_dead
..() // This will apply the correct icon_state and do the other overlay-related things.
*/
/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/proc/alien_evolve(mob/living/simple_mob/metroid/new_metroid)
to_chat(src, "<span class='noticealien'>You begin to evolve!</span>")
visible_message("<span class='alertalien'>[src] begins to twist and contort!</span>")
if(mind)
mind.transfer_to(new_metroid)
qdel(src)
/mob/living/simple_mob/metroid/juvenile/verb/reproduce()
set category = "Slime"
set desc = "This will make you split into four new slimes."
if(stat)
to_chat(src, span("warning", "I must be conscious to do this..."))
return
if(harmless)
to_chat(src, span("warning", "I have been pacified. I cannot reproduce..."))
return
/mob/living/simple_mob/metroid/juvenile/verb/evolve()
set category = "Slime"
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 class='notice'>\The [src] begins to lay an egg.</span>")
spawn(50)
new /obj/effect/metroid/egg(loc, src)
nutrition = 500
paralysis = 0
return
*/
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()
if(nutrition >= evo_point && !buckled && vore_fullness == 0 && !victim)
playsound(src, 'sound/metroid/metroidgrow.ogg', 50, 1)
paralysis = 7998
sleep(50)
expand_troid()
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/E
E = new next(get_turf(src)) //Next is a variable defined by metTypes.dm that just points to the next metroid in the evolutionary stage.
src.mind.transfer_to(E)
visible_message("<span class='warning'>\The [src] suddenly evolves!</span>")
qdel(src)
/mob/living/simple_mob/metroid/juvenile/proc/pacify()
harmless = TRUE
if(has_AI())
var/datum/ai_holder/simple_mob/xenobio_slime/AI = ai_holder
AI.pacify()
faction = "neutral"
// If for whatever reason the mob AI (or player) decides to try to attack something anyways.
melee_damage_upper = 1
melee_damage_lower = 3
// These slimes have the mechanics xenobiologists care about, such as reproduction, mutating into new colors, and being able to submit through fear.
/mob/living/simple_mob/metroid/juvenile
desc = "The most basic of slimes. The grey slime has no remarkable qualities, however it remains one of the most useful colors for scientists."
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 slime is currently feeding on
var/amount_grown = 0 // controls how long the slime has been overfed, if 10, grows or reproduces
var/number = 0 // This is used to make the slime semi-unique for indentification.
var/harmless = FALSE // Set to true when pacified. Makes the slime 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/update_icon()
icon = "
icon_living = "[icon_state_override ? "[icon_state_override] slime" : "slime"] [is_adult ? "adult" : "baby"][victim ? " eating" : ""]"
icon_dead = "[icon_state_override ? "[icon_state_override] slime" : "slime"] [is_adult ? "adult" : "baby"] dead"
icon_rest = icon_dead
..() // This will apply the correct icon_state and do the other overlay-related things.
*/
/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 = "Slime"
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 class='notice'>\The [src] begins to lay an egg.</span>")
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" && 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 class='warning'>\The [src] suddenly evolves!</span>")
qdel(src)
/mob/living/simple_mob/metroid/juvenile/proc/pacify()
harmless = TRUE
if(has_AI())
var/datum/ai_holder/simple_mob/xenobio_slime/AI = ai_holder
AI.pacify()
faction = "neutral"
// If for whatever reason the mob AI (or player) decides to try to attack something anyways.
melee_damage_upper = 1
melee_damage_lower = 3
// Code for slimes attacking other things.
// Slime 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 slimes 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 slimes 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)
@@ -1,42 +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)
/*
//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)
File diff suppressed because it is too large Load Diff