Files
Bubberstation/code/modules/surgery/organs/internal/stomach/_stomach.dm
MrMelbert c080b83c41 Monkey eating glowup (#93759)
## About The Pull Request

1. Monkeys will only seek out food to eat if they are actually hungry,
rather than on an arbitrary cooldown.
2. Monkeys will no longer teleport-yoink food out of your hands.
Instead, they may get angry at you for stealing their food, and fight
you over it. The hungrier the monkey, the more likely they are to fight.
3. Monkeys will discard trash and empty glasses (on the floor) after
eating or drinking them.
4. Monkeys can target soup to eat
5. PunPun will no longer seek out drinks if they are hungry.
6. PunPun will now, if the bartender is absent and there are multiple
patrons around, attempt to find filled glasses or food to hand out to
patrons.
7. Several places that sought edible items no longer include drinking
glasses as edible items

<img width="656" height="185" alt="image"
src="https://github.com/user-attachments/assets/8b3a6ac1-ae2c-41a0-919f-b471ad93bb0f"
/>

## Why It's Good For The Game

PunPun shouldn't be yoinking glasses out of patron's hands - their
intended behavior is to serve drinks not steal them

Otherwise, monkey eating was a bit jank due to it being some of our
oldest ai code. I largely just brought it up to more modern ai
standards.

## Changelog

🆑 Melbert
add: If the bartender is absent, PunPun will serve filled drink glasses
to patrons that don't have one.
add: PunPun will now ignore filled drinks and items being held when
looking for stuff to eat.
add: Monkeys can eat soup.
add: Monkeys will no longer seek out food if they are not hungry.
add: Hungry monkeys might fight you over the food you are holding. The
hungrier the monkey, the angrier the monkey.
fix: Monkeys can no longer teleport items out of your hands to eat. 
/🆑
2025-11-08 01:32:46 +01:00

582 lines
23 KiB
Plaintext

//The contant in the rate of reagent transfer on life ticks
#define STOMACH_METABOLISM_CONSTANT 0.25
/obj/item/organ/stomach
name = "stomach"
desc = "Onaka ga suite imasu."
icon_state = "stomach"
w_class = WEIGHT_CLASS_SMALL
zone = BODY_ZONE_CHEST
slot = ORGAN_SLOT_STOMACH
attack_verb_continuous = list("gores", "squishes", "slaps", "digests")
attack_verb_simple = list("gore", "squish", "slap", "digest")
healing_factor = STANDARD_ORGAN_HEALING
decay_factor = STANDARD_ORGAN_DECAY * 1.15 // ~13 minutes, the stomach is one of the first organs to die
low_threshold_passed = span_info("Your stomach flashes with pain before subsiding. Food doesn't seem like a good idea right now.")
high_threshold_passed = span_warning("Your stomach flares up with constant pain- you can hardly stomach the idea of food right now!")
high_threshold_cleared = span_info("The pain in your stomach dies down for now, but food still seems unappealing.")
low_threshold_cleared = span_info("The last bouts of pain in your stomach have died out.")
food_reagents = list(/datum/reagent/consumable/nutriment/organ_tissue/stomach_lining = 5)
//This is a reagent user and needs more then the 10u from edible component
reagent_vol = 1000
cell_line = CELL_LINE_ORGAN_STOMACH
cells_minimum = 1
cells_maximum = 2
///The rate that disgust decays
var/disgust_metabolism = 1
///The rate that the stomach will transfer reagents to the body
var/metabolism_efficiency = 0.05 // the lowest we should go is 0.025
/// Multiplier for hunger rate
var/hunger_modifier = 1
/// Whether the stomach's been repaired with surgery and can be fixed again or not
var/operated = FALSE
/// List of all atoms within the stomach
var/list/atom/movable/stomach_contents = list()
/// Have we been cut open with a scalpel? If so, how much damage from it we still have from it and can be recovered with a cauterizing tool.
/// All healing goes towards recovering this.
var/cut_open_damage = 0
/obj/item/organ/stomach/Initialize(mapload)
. = ..()
//None edible organs do not get a reagent holder by default
if(!reagents)
create_reagents(reagent_vol, REAGENT_HOLDER_ALIVE)
else
reagents.flags |= REAGENT_HOLDER_ALIVE
/obj/item/organ/stomach/Destroy()
QDEL_LIST(stomach_contents)
return ..()
/obj/item/organ/stomach/on_life(seconds_per_tick, times_fired)
. = ..()
//Manage species digestion
if(ishuman(owner))
var/mob/living/carbon/human/humi = owner
if(!(organ_flags & ORGAN_FAILING))
handle_hunger(humi, seconds_per_tick, times_fired)
var/mob/living/carbon/body = owner
// digest food, sent all reagents that can metabolize to the body
for(var/datum/reagent/bit as anything in reagents?.reagent_list)
// If the reagent does not metabolize then it will sit in the stomach
// This has an effect on items like plastic causing them to take up space in the stomach
if(bit.metabolization_rate <= 0)
continue
//Ensure that the the minimum is equal to the metabolization_rate of the reagent if it is higher then the STOMACH_METABOLISM_CONSTANT
var/rate_min = max(bit.metabolization_rate, STOMACH_METABOLISM_CONSTANT)
//Do not transfer over more then we have
var/amount_max = bit.volume
//If the reagent is part of the food reagents for the organ
//prevent all the reagents form being used leaving the food reagents
var/amount_food = food_reagents[bit.type]
if(amount_food)
amount_max = max(amount_max - amount_food, 0)
// Transfer the amount of reagents based on volume with a min amount of 1u
var/amount = min((round(metabolism_efficiency * amount_max, 0.05) + rate_min) * seconds_per_tick, amount_max)
if(amount <= 0)
continue
// transfer the reagents over to the body at the rate of the stomach metabolim
// this way the body is where all reagents that are processed and react
// the stomach manages how fast they are feed in a drip style
reagents.trans_to(body, amount, target_id = bit.type)
//Handle disgust
if(body)
handle_disgust(body, seconds_per_tick, times_fired)
//If the stomach is not damage exit out
if(damage < low_threshold)
return
//We are checking if we have nutriment in a damaged stomach.
var/datum/reagent/nutri = locate(/datum/reagent/consumable/nutriment) in reagents?.reagent_list
//No nutriment found lets exit out
if(!nutri)
return
// remove the food reagent amount
var/nutri_vol = nutri.volume
var/amount_food = food_reagents[nutri.type]
if(amount_food)
nutri_vol = max(nutri_vol - amount_food, 0)
// found nutriment was stomach food reagent
if(!(nutri_vol > 0))
return
//The stomach is damage has nutriment but low on theshhold, lo prob of vomit
if(SPT_PROB(0.0125 * damage * nutri_vol * nutri_vol, seconds_per_tick))
body.vomit(VOMIT_CATEGORY_DEFAULT, lost_nutrition = damage)
to_chat(body, span_warning("Your stomach reels in pain as you're incapable of holding down all that food!"))
return
// the change of vomit is now high
if(damage > high_threshold && SPT_PROB(0.05 * damage * nutri_vol * nutri_vol, seconds_per_tick))
body.vomit(VOMIT_CATEGORY_DEFAULT, lost_nutrition = damage)
to_chat(body, span_warning("Your stomach reels in pain as you're incapable of holding down all that food!"))
/obj/item/organ/stomach/proc/handle_hunger(mob/living/carbon/human/human, seconds_per_tick, times_fired)
if(HAS_TRAIT(human, TRAIT_NOHUNGER))
return //hunger is for BABIES
//The fucking TRAIT_FAT mutation is the dumbest shit ever. It makes the code so difficult to work with
if(HAS_TRAIT_FROM(human, TRAIT_FAT, OBESITY))//I share your pain, past coder.
if(human.overeatduration < (200 SECONDS))
to_chat(human, span_notice("You feel fit again!"))
human.remove_traits(list(TRAIT_FAT, TRAIT_OFF_BALANCE_TACKLER), OBESITY)
else
if(human.overeatduration >= (200 SECONDS))
to_chat(human, span_danger("You suddenly feel blubbery!"))
human.add_traits(list(TRAIT_FAT, TRAIT_OFF_BALANCE_TACKLER), OBESITY)
// nutrition decrease and satiety
if (human.nutrition > 0 && human.stat != DEAD)
// THEY HUNGER
var/hunger_rate = HUNGER_FACTOR
if(human.mob_mood && human.mob_mood.sanity > SANITY_DISTURBED)
hunger_rate *= max(1 - 0.002 * human.mob_mood.sanity, 0.5) //0.85 to 0.75
// Whether we cap off our satiety or move it towards 0
if(human.satiety > MAX_SATIETY)
human.satiety = MAX_SATIETY
else if(human.satiety > 0)
human.satiety--
else if(human.satiety < -MAX_SATIETY)
human.satiety = -MAX_SATIETY
else if(human.satiety < 0)
human.satiety++
if(SPT_PROB(round(-human.satiety/77), seconds_per_tick))
human.set_jitter_if_lower(10 SECONDS)
hunger_rate = 3 * HUNGER_FACTOR
hunger_rate *= hunger_modifier
hunger_rate *= human.physiology.hunger_mod
human.adjust_nutrition(-hunger_rate * seconds_per_tick)
var/nutrition = human.nutrition
if(nutrition > NUTRITION_LEVEL_FULL && !HAS_TRAIT(human, TRAIT_NOFAT))
if(human.overeatduration < 20 MINUTES) //capped so people don't take forever to unfat
human.overeatduration = min(human.overeatduration + (1 SECONDS * seconds_per_tick), 20 MINUTES)
else
if(human.overeatduration > 0)
human.overeatduration = max(human.overeatduration - (2 SECONDS * seconds_per_tick), 0) //doubled the unfat rate
//metabolism change
if(nutrition > NUTRITION_LEVEL_FAT)
human.metabolism_efficiency = 1
else if(nutrition > NUTRITION_LEVEL_FED && human.satiety > 80)
if(human.metabolism_efficiency != 1.25)
to_chat(human, span_notice("You feel vigorous."))
human.metabolism_efficiency = 1.25
else if(nutrition < NUTRITION_LEVEL_STARVING + 50)
if(human.metabolism_efficiency != 0.8)
to_chat(human, span_notice("You feel sluggish."))
human.metabolism_efficiency = 0.8
else
if(human.metabolism_efficiency == 1.25)
to_chat(human, span_notice("You no longer feel vigorous."))
human.metabolism_efficiency = 1
//Hunger slowdown for if mood isn't enabled
if(CONFIG_GET(flag/disable_human_mood))
handle_hunger_slowdown(human)
///for when mood is disabled and hunger should handle slowdowns
/obj/item/organ/stomach/proc/handle_hunger_slowdown(mob/living/carbon/human/human)
var/hungry = (500 - human.nutrition) / 5 //So overeat would be 100 and default level would be 80
if(hungry >= 70)
human.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/hunger, multiplicative_slowdown = (hungry / 50))
else
human.remove_movespeed_modifier(/datum/movespeed_modifier/hunger)
/obj/item/organ/stomach/get_availability(datum/species/owner_species, mob/living/owner_mob)
return owner_species.mutantstomach
///This gets called after the owner takes a bite of food
/obj/item/organ/stomach/proc/after_eat(atom/edible)
return
/obj/item/organ/stomach/proc/consume_thing(atom/movable/thing)
RegisterSignal(thing, COMSIG_MOVABLE_MOVED, PROC_REF(content_moved))
RegisterSignal(thing, COMSIG_QDELETING, PROC_REF(content_deleted))
stomach_contents += thing
thing.forceMove(owner || src) // We assert that if we have no owner, we will not be nullspaced
return TRUE
/obj/item/organ/stomach/proc/content_deleted(atom/movable/source)
SIGNAL_HANDLER
stomach_contents -= source
/obj/item/organ/stomach/proc/content_moved(atom/movable/source)
SIGNAL_HANDLER
if(source.loc == src || source.loc == owner) // not in us? out da list then
return
stomach_contents -= source
UnregisterSignal(source, list(COMSIG_MOVABLE_MOVED, COMSIG_QDELETING))
/obj/item/organ/stomach/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change)
. = ..()
if(loc == null && owner)
for(var/atom/movable/thing as anything in stomach_contents)
thing.forceMove(owner)
else if(loc != null)
for(var/atom/movable/thing as anything in stomach_contents)
thing.forceMove(src)
/// Empties stomach contents on our current turf
/obj/item/organ/stomach/proc/empty_contents(chance = 100, damaging = FALSE, min_amount = 0)
var/emptied = 0
var/atom/movable/drop_as = owner || src
var/drop_loc = drop_as.drop_location()
for (var/atom/movable/nugget as anything in stomach_contents)
var/total_chance = chance
// If min_amount is set, make sure that we vomit at least some of our contents
if (min_amount)
total_chance += 100 / (length(stomach_contents) + 1 - min_amount)
if (!prob(total_chance))
continue
nugget.forceMove(drop_loc)
emptied += 1
min_amount -= 1
if (!damaging || QDELETED(owner))
continue
var/damage = 5
if (isitem(nugget))
var/obj/item/as_item = nugget
damage = as_item.w_class * 2
else if (isliving(nugget))
var/mob/living/as_living = nugget
damage = as_living.mob_size * 5
owner.apply_damage(damage, BRUTE, BODY_ZONE_CHEST, wound_bonus = CANT_WOUND, wound_clothing = FALSE)
return emptied
/obj/item/organ/stomach/on_life(seconds_per_tick, times_fired)
. = ..()
if (!owner || SSmobs.times_fired % 3 != 0)
return
if (!length(stomach_contents))
return
var/obj/item/bodypart/chest/chest = owner.get_bodypart(zone)
var/datum/wound/slash/flesh/slash = chest.get_wound_type(/datum/wound/slash/flesh)
// A chance to spill out all the contents
if (cut_open_damage && slash?.severity >= WOUND_SEVERITY_CRITICAL)
if (SPT_PROB(chest.get_damage(), seconds_per_tick * 3))
var/emptied = empty_contents()
if (emptied > 0)
owner.apply_damage(emptied * 5, BRUTE, BODY_ZONE_CHEST, wound_bonus = CANT_WOUND, wound_clothing = FALSE)
playsound(get_turf(src), 'sound/effects/splat.ogg', 50)
owner.visible_message(span_danger("Contents of [owner]'s intestines spill out from a huge cut in [owner.p_their()] [chest]!"),
span_userdanger("Contents of your intestines spill out from a huge cut in your [chest]!"))
return
// Digest the stuff in our stomach, just a bit
for (var/atom/movable/thing as anything in stomach_contents)
if (SEND_SIGNAL(thing, COMSIG_ATOM_STOMACH_DIGESTED, src, owner, seconds_per_tick) & COMPONENT_CANCEL_DIGESTION)
continue
var/acid_pwr = stomach_acid_power(thing, seconds_per_tick)
if (acid_pwr)
thing.acid_act(acid_pwr, 10)
// If you have strong stomach you can eat glass, literally
if (!isitem(thing) || HAS_TRAIT(owner, TRAIT_STRONG_STOMACH))
continue
var/obj/item/as_item = thing
// If your stomach is cut open, it will hurt like hell
if (cut_open_damage)
if (chest && !chest.cavity_item && as_item.w_class <= WEIGHT_CLASS_NORMAL)
// Oopsie!
chest.cavity_item = as_item
stomach_contents -= as_item
continue
owner.apply_damage(as_item.w_class * (as_item.sharpness ? 2 : 1), BRUTE, BODY_ZONE_CHEST, wound_bonus = CANT_WOUND,
sharpness = as_item.sharpness, attacking_item = as_item, wound_clothing = FALSE)
if (!as_item.sharpness)
continue
var/was_failing = (organ_flags & ORGAN_FAILING)
apply_organ_damage(as_item.w_class)
// Damage caused organ failure
if (was_failing || !(organ_flags & ORGAN_FAILING))
continue
cut_open_damage = maxHealth * 0.5
if (HAS_TRAIT(owner, TRAIT_ANALGESIA))
continue
owner.visible_message(span_warning("[owner] doubles over in pain!"), span_userdanger("You feel a sharp, searing sensation in your stomach!"))
owner.Paralyze(1 SECONDS)
owner.adjust_eye_blur(5 SECONDS)
/// Acid power of whatever we're digesting
/obj/item/organ/stomach/proc/stomach_acid_power(atom/movable/nomnom, seconds_per_tick)
if (isliving(nomnom)) // NO VORE ALLOWED
return 0
// Yeah maybe don't, if something edible ended up here it should either handle itself or not be digested
if (IS_EDIBLE(nomnom))
return 0
if (HAS_TRAIT(owner, TRAIT_STRONG_STOMACH))
return 10
return 0
/obj/item/organ/stomach/proc/handle_disgust(mob/living/carbon/human/disgusted, seconds_per_tick, times_fired)
var/old_disgust = disgusted.old_disgust
var/disgust = disgusted.disgust
if(disgust)
var/pukeprob = 2.5 + (0.025 * disgust)
if(disgust >= DISGUST_LEVEL_GROSS)
if(SPT_PROB(5, seconds_per_tick))
disgusted.adjust_stutter(2 SECONDS)
disgusted.adjust_confusion(2 SECONDS)
if(SPT_PROB(5, seconds_per_tick) && !disgusted.stat)
to_chat(disgusted, span_warning("You feel kind of iffy..."))
disgusted.adjust_jitter(-6 SECONDS)
if(disgust >= DISGUST_LEVEL_VERYGROSS)
if(SPT_PROB(pukeprob, seconds_per_tick)) //iT hAndLeS mOrE ThaN PukInG
disgusted.adjust_confusion(2.5 SECONDS)
disgusted.adjust_stutter(2 SECONDS)
disgusted.vomit(VOMIT_CATEGORY_KNOCKDOWN, distance = 0)
disgusted.adjust_disgust(-50)
disgusted.set_dizzy_if_lower(10 SECONDS)
if(disgust >= DISGUST_LEVEL_DISGUSTED)
if(SPT_PROB(13, seconds_per_tick))
disgusted.set_eye_blur_if_lower(6 SECONDS) //We need to add more shit down here
disgusted.adjust_disgust(-0.25 * disgust_metabolism * seconds_per_tick)
// I would consider breaking this up into steps matching the disgust levels
// But disgust is used so rarely it wouldn't save a significant amount of time, and it makes the code just way worse
// We're in the same state as the last time we processed, so don't bother
if(old_disgust == disgust)
return
disgusted.old_disgust = disgust
switch(disgust)
if(0 to DISGUST_LEVEL_GROSS)
disgusted.clear_alert(ALERT_DISGUST)
disgusted.clear_mood_event("disgust")
if(DISGUST_LEVEL_GROSS to DISGUST_LEVEL_VERYGROSS)
disgusted.throw_alert(ALERT_DISGUST, /atom/movable/screen/alert/gross)
disgusted.add_mood_event("disgust", /datum/mood_event/gross)
if(DISGUST_LEVEL_VERYGROSS to DISGUST_LEVEL_DISGUSTED)
disgusted.throw_alert(ALERT_DISGUST, /atom/movable/screen/alert/verygross)
disgusted.add_mood_event("disgust", /datum/mood_event/verygross)
if(DISGUST_LEVEL_DISGUSTED to INFINITY)
disgusted.throw_alert(ALERT_DISGUST, /atom/movable/screen/alert/disgusted)
disgusted.add_mood_event("disgust", /datum/mood_event/disgusted)
/obj/item/organ/stomach/on_mob_insert(mob/living/carbon/receiver, special, movement_flags)
. = ..()
receiver.hud_used?.hunger?.update_hunger_bar()
RegisterSignal(receiver, COMSIG_CARBON_VOMITED, PROC_REF(on_vomit))
RegisterSignal(receiver, COMSIG_HUMAN_GOT_PUNCHED, PROC_REF(on_punched))
/obj/item/organ/stomach/on_mob_remove(mob/living/carbon/stomach_owner, special, movement_flags)
if(ishuman(stomach_owner))
var/mob/living/carbon/human/human_owner = stomach_owner
human_owner.clear_alert(ALERT_DISGUST)
human_owner.clear_mood_event("disgust")
stomach_owner.hud_used?.hunger?.update_hunger_bar()
UnregisterSignal(stomach_owner, list(COMSIG_CARBON_VOMITED, COMSIG_HUMAN_GOT_PUNCHED))
return ..()
/obj/item/organ/stomach/feel_for_damage(self_aware)
if(damage < low_threshold)
return ""
if(damage < high_threshold)
return span_warning("Your stomach hurts.")
return span_boldwarning("Your stomach cramps in pain!")
/// If damage is high enough, we may end up vomiting out whatever we had stored
/obj/item/organ/stomach/proc/on_punched(datum/source, mob/living/carbon/human/attacker, damage, attack_type, obj/item/bodypart/affecting, final_armor_block, kicking, limb_sharpness)
SIGNAL_HANDLER
if (!length(stomach_contents) || damage < 9 || final_armor_block || kicking)
return
if (owner.vomit(MOB_VOMIT_MESSAGE | MOB_VOMIT_FORCE))
// Since we vomited with a force flag, we should've vomited out at least one item
owner.visible_message(span_danger("[owner] doubles over from [attacker]'s punch, vomiting out the contents of [owner.p_their()] stomach!"))
/// 60% chance to spew out each item when vomiting
/obj/item/organ/stomach/proc/on_vomit(mob/living/carbon/vomiter, distance, force)
SIGNAL_HANDLER
// If we're forced to vomit, try to spew out at least one item
empty_contents(chance = 60, damaging = TRUE, min_amount = (force ? 1 : 0))
/obj/item/organ/stomach/tool_act(mob/living/user, obj/item/tool, list/modifiers)
if (tool.tool_behaviour == TOOL_SCALPEL)
if (cut_open_damage > 0)
balloon_alert(user, "already cut open!")
return ITEM_INTERACT_FAILURE
balloon_alert(user, "cutting open...")
playsound(user, 'sound/items/handling/surgery/scalpel1.ogg', 75)
if (!do_after(user, 3 SECONDS, src))
balloon_alert(user, "interrupted!")
apply_organ_damage(tool.force)
return ITEM_INTERACT_FAILURE
playsound(user, 'sound/items/handling/surgery/scalpel2.ogg', 75)
var/emptied = empty_contents()
if (emptied > 0)
playsound(get_turf(src), 'sound/effects/splat.ogg', 50)
user.visible_message(span_warning("[user] cuts [src] open[emptied ? "!" : ", but it's empty."]"), span_notice("You cut [src] open[emptied ? "." : ", but there's nothing inside."]"))
cut_open_damage += apply_organ_damage(maxHealth * 0.5)
return ITEM_INTERACT_SUCCESS
if (tool.tool_behaviour != TOOL_CAUTERY)
return ..()
if (cut_open_damage <= 0)
balloon_alert(user, "fully intact!")
return ITEM_INTERACT_FAILURE
playsound(user, 'sound/items/handling/surgery/cautery1.ogg', 75)
balloon_alert(user, "mending the incision...")
if (!do_after(user, 3 SECONDS, src))
balloon_alert(user, "interrupted!")
apply_organ_damage(tool.force)
return ITEM_INTERACT_FAILURE
playsound(user, 'sound/items/handling/surgery/cautery2.ogg', 75)
balloon_alert(user, "incision mended")
apply_organ_damage(-cut_open_damage)
cut_open_damage = 0 // Just in case
return ITEM_INTERACT_SUCCESS
/obj/item/organ/stomach/apply_organ_damage(damage_amount, maximum, required_organ_flag)
. = ..()
// So after a while, or a bunch of stomach meds, even a cut stomach can recover
if (. < 0)
cut_open_damage = max(0, cut_open_damage + .)
/obj/item/organ/stomach/examine(mob/user)
. = ..()
if (cut_open_damage)
. += span_danger("It has a sizeable cut in it, exposing its insides!")
/obj/item/organ/stomach/bone
name = "mass of bones"
desc = "You have no idea what this strange ball of bones does."
icon_state = "stomach-bone"
metabolism_efficiency = 0.025 //very bad
organ_traits = list(TRAIT_NOHUNGER)
/obj/item/organ/stomach/bone/plasmaman
name = "digestive crystal"
desc = "A strange crystal that is responsible for metabolizing the unseen energy force that feeds plasmamen."
icon_state = "stomach-p"
metabolism_efficiency = 0.06
organ_traits = null
/obj/item/organ/stomach/cybernetic
name = "basic cybernetic stomach"
desc = "A basic device designed to mimic the functions of a human stomach"
failing_desc = "seems to be broken."
icon_state = "stomach-c"
organ_flags = ORGAN_ROBOTIC
maxHealth = STANDARD_ORGAN_THRESHOLD * 0.5
metabolism_efficiency = 0.035 // not as good at digestion
var/emp_vulnerability = 80 //Chance of permanent effects if emp-ed.
/obj/item/organ/stomach/cybernetic/emp_act(severity)
. = ..()
if(. & EMP_PROTECT_SELF)
return
if(!COOLDOWN_FINISHED(src, severe_cooldown)) //So we cant just spam emp to kill people.
owner.vomit(vomit_flags = (MOB_VOMIT_MESSAGE | MOB_VOMIT_HARM))
COOLDOWN_START(src, severe_cooldown, 10 SECONDS)
if(prob(emp_vulnerability/severity)) //Chance of permanent effects
organ_flags |= ORGAN_EMP //Starts organ faliure - gonna need replacing soon.
/obj/item/organ/stomach/cybernetic/tier2
name = "cybernetic stomach"
desc = "An electronic device designed to mimic the functions of a human stomach. Handles disgusting food a bit better."
icon_state = "stomach-c-u"
maxHealth = 1.5 * STANDARD_ORGAN_THRESHOLD
disgust_metabolism = 2
emp_vulnerability = 40
metabolism_efficiency = 0.07
/obj/item/organ/stomach/cybernetic/tier2/stomach_acid_power(atom/movable/nomnom)
if (isliving(nomnom))
return 0
if (IS_EDIBLE(nomnom))
return 0
return 20
/obj/item/organ/stomach/cybernetic/tier3
name = "upgraded cybernetic stomach"
desc = "An upgraded version of the cybernetic stomach, designed to improve further upon organic stomachs. Handles disgusting food very well."
icon_state = "stomach-c-u2"
maxHealth = 2 * STANDARD_ORGAN_THRESHOLD
disgust_metabolism = 3
emp_vulnerability = 20
metabolism_efficiency = 0.1
/obj/item/organ/stomach/cybernetic/tier3/stomach_acid_power(atom/movable/nomnom)
if (isliving(nomnom))
return 0
if (IS_EDIBLE(nomnom))
return 0
return 35
/obj/item/organ/stomach/cybernetic/surplus
name = "surplus prosthetic stomach"
desc = "A mechanical plastic oval that utilizes sulfuric acid instead of stomach acid. \
Very fragile, with painfully slow metabolism.\
Offers no protection against EMPs."
icon_state = "stomach-c-s"
maxHealth = STANDARD_ORGAN_THRESHOLD * 0.35
emp_vulnerability = 100
metabolism_efficiency = 0.025
//surplus organs are so awful that they explode when removed, unless failing
/obj/item/organ/stomach/cybernetic/surplus/Initialize(mapload)
. = ..()
AddElement(/datum/element/dangerous_organ_removal, /*surgical = */ TRUE)
/obj/item/organ/stomach/pod
name = "pod chloroplast"
desc = "A green plant-like organ that functions similarly to a human stomach."
foodtype_flags = PODPERSON_ORGAN_FOODTYPES
color = COLOR_LIME
/obj/item/organ/stomach/ghost
name = "ghost stomach"
desc = "Ghosts eat plenty, you know? And it's not just your life, I swear!"
icon_state = "stomach-ghost"
movement_type = PHASING
organ_flags = parent_type::organ_flags | ORGAN_GHOST
/obj/item/organ/stomach/evolved
name = "evolved stomach"
desc = "It can draw nutrients from your food even harder!"
icon_state = "stomach-evolved"
maxHealth = 1.2 * STANDARD_ORGAN_THRESHOLD
disgust_metabolism = 2.5
metabolism_efficiency = 0.08
#undef STOMACH_METABOLISM_CONSTANT