diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm
index 943e9c005e5..eed6589f7f2 100644
--- a/code/__DEFINES/components.dm
+++ b/code/__DEFINES/components.dm
@@ -84,6 +84,7 @@
#define COMSIG_PARENT_ATTACKBY "atom_attackby" //from base of atom/attackby(): (/obj/item, /mob/living, params)
#define COMPONENT_NO_AFTERATTACK 1 //Return this in response if you don't want afterattack to be called
#define COMSIG_ATOM_HULK_ATTACK "hulk_attack" //from base of atom/attack_hulk(): (/mob/living/carbon/human)
+#define COMSIG_ATOM_ATTACK_ANIMAL "attack_animal" //from base of atom/animal_attack(): (/mob/user)
#define COMSIG_PARENT_EXAMINE "atom_examine" //from base of atom/examine(): (/mob)
#define COMSIG_ATOM_GET_EXAMINE_NAME "atom_examine_name" //from base of atom/get_examine_name(): (/mob, list/overrides)
//Positions for overrides list
@@ -299,6 +300,8 @@
#define COMPONENT_BLOCK_MARK_RETRIEVAL 1
#define COMSIG_ITEM_HIT_REACT "item_hit_react" //from base of obj/item/hit_reaction(): (list/args)
#define COMSIG_ITEM_WEARERCROSSED "wearer_crossed" //called on item when crossed by something (): (/atom/movable, mob/living/crossed)
+#define COMSIG_ITEM_MICROWAVE_ACT "microwave_act" //called on item when microwaved (): (obj/machinery/microwave/M)
+
// /obj/item/clothing signals
#define COMSIG_SHOES_STEP_ACTION "shoes_step_action" //from base of obj/item/clothing/shoes/proc/step_action(): ()
diff --git a/code/__DEFINES/food.dm b/code/__DEFINES/food.dm
index 60f99c4c750..62bdd1d8c38 100644
--- a/code/__DEFINES/food.dm
+++ b/code/__DEFINES/food.dm
@@ -19,3 +19,7 @@
#define DRINK_VERYGOOD 3
#define DRINK_FANTASTIC 4
#define FOOD_AMAZING 5
+
+#define FOOD_IN_CONTAINER (1<<0)
+
+#define STOP_SERVING_BREAKFAST (15 MINUTES)
diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm
index a4b07f97e20..6ef4d0ca692 100644
--- a/code/__DEFINES/obj_flags.dm
+++ b/code/__DEFINES/obj_flags.dm
@@ -51,4 +51,5 @@
#define ORGAN_FAILING (1<<2) //Failing organs perform damaging effects until replaced or fixed
#define ORGAN_EXTERNAL (1<<3) //Was this organ implanted/inserted/etc, if true will not be removed during species change.
#define ORGAN_VITAL (1<<4) //Currently only the brain
-#define ORGAN_SYNTHETIC_EMP (1<<5) //Synthetic organ affected by an EMP. Deteriorates over time.
+#define ORGAN_EDIBLE (1<<5) //is a snack? :D
+#define ORGAN_SYNTHETIC_EMP (1<<6) //Synthetic organ affected by an EMP. Deteriorates over time.
diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm
index f6668eef33e..1d6c4d82852 100644
--- a/code/_onclick/other_mobs.dm
+++ b/code/_onclick/other_mobs.dm
@@ -97,7 +97,7 @@
A.attack_animal(src)
/atom/proc/attack_animal(mob/user)
- return
+ SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_ANIMAL, user)
/mob/living/RestrainedClickOn(atom/A)
return
diff --git a/code/datums/components/edible.dm b/code/datums/components/edible.dm
new file mode 100644
index 00000000000..22825fe3de2
--- /dev/null
+++ b/code/datums/components/edible.dm
@@ -0,0 +1,237 @@
+/*!
+
+This component makes it possible to make things edible. What this means is that you can take a bite or force someone to take a bite (in the case of items).
+These items take a specific time to eat, and can do most of the things our original food items could.
+
+Behavior that's still missing from this component that original food items had that should either be put into seperate components or somewhere else:
+ Components:
+ Drying component (jerky etc)
+ Customizable component (custom pizzas etc)
+ Processable component (Slicing and cooking behavior essentialy, making it go from item A to B when conditions are met.)
+ Dunkable component (Dunking things into reagent containers to absorb a specific amount of reagents)
+
+ Misc:
+ Something for cakes (You can store things inside)
+
+*/
+/datum/component/edible
+ ///Amount of reagents taken per bite
+ var/bite_consumption = 2
+ ///Amount of bites taken so far
+ var/bitecount = 0
+ ///Flags for food
+ var/food_flags = NONE
+ ///Bitfield of the types of this food
+ var/foodtypes = NONE
+ ///Amount of seconds it takes to eat this food
+ var/eat_time = 30
+ ///Defines how much it lowers someones satiety (Need to eat, essentialy)
+ var/junkiness = 0
+ ///Message to send when eating
+ var/list/eatverbs
+ ///Callback to be ran for when you take a bite of something
+ var/datum/callback/after_eat
+ ///Last time we checked for food likes
+ var/last_check_time
+
+/datum/component/edible/Initialize(list/initial_reagents, food_flags = NONE, foodtypes = NONE, volume = 50, eat_time = 30, list/tastes, list/eatverbs = list("bite","chew","nibble","gnaw","gobble","chomp"), bite_consumption = 2, datum/callback/after_eat)
+ if(!isatom(parent))
+ return COMPONENT_INCOMPATIBLE
+
+ RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/examine)
+ RegisterSignal(parent, COMSIG_ATOM_ATTACK_ANIMAL, .proc/UseByAnimal)
+ if(isitem(parent))
+ RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/UseFromHand)
+ else if(isturf(parent))
+ RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, .proc/TryToEatTurf)
+
+ src.bite_consumption = bite_consumption
+ src.food_flags = food_flags
+ src.foodtypes = foodtypes
+ src.eat_time = eat_time
+ src.eatverbs = eatverbs
+ src.junkiness = junkiness
+ src.after_eat = after_eat
+
+ var/atom/owner = parent
+
+ owner.create_reagents(volume, INJECTABLE)
+
+ if(initial_reagents)
+ for(var/rid in initial_reagents)
+ var/amount = initial_reagents[rid]
+ if(tastes && tastes.len && (rid == /datum/reagent/consumable/nutriment || rid == /datum/reagent/consumable/nutriment/vitamin))
+ owner.reagents.add_reagent(rid, amount, tastes.Copy())
+ else
+ owner.reagents.add_reagent(rid, amount)
+
+/datum/component/edible/proc/examine(datum/source, mob/user, list/examine_list)
+ if(!food_flags & FOOD_IN_CONTAINER)
+ switch (bitecount)
+ if (0)
+ return
+ if(1)
+ examine_list += "[parent] was bitten by someone!"
+ if(2,3)
+ examine_list += "[parent] was bitten [bitecount] times!"
+ else
+ examine_list += "[parent] was bitten multiple times!"
+
+/datum/component/edible/proc/UseFromHand(obj/item/source, mob/living/M, mob/living/user)
+ return TryToEat(M, user)
+
+/datum/component/edible/proc/TryToEatTurf(datum/source, mob/user)
+ return TryToEat(user, user)
+
+///All the checks for the act of eating itself and
+/datum/component/edible/proc/TryToEat(mob/living/eater, mob/living/feeder)
+
+ var/atom/owner = parent
+
+ if(feeder.a_intent == INTENT_HARM)
+ return
+ if(!owner.reagents.total_volume)//Shouldn't be needed but it checks to see if it has anything left in it.
+ to_chat(feeder, "None of [owner] left, oh no!")
+ qdel(parent)
+ return
+ if(!CanConsume(eater, feeder))
+ return
+ var/fullness = eater.nutrition + 10 //The theoretical fullness of the person eating if they were to eat this
+ for(var/datum/reagent/consumable/C in eater.reagents.reagent_list) //we add the nutrition value of what we're currently digesting
+ fullness += C.nutriment_factor * C.volume / C.metabolization_rate
+
+ . = COMPONENT_ITEM_NO_ATTACK //Point of no return I suppose
+
+ if(eater == feeder)//If you're eating it yourself.
+ if(!do_mob(feeder, eater, eat_time)) //Gotta pass the minimal eat time
+ return
+ var/eatverb = pick(eatverbs)
+ if(junkiness && eater.satiety < -150 && eater.nutrition > NUTRITION_LEVEL_STARVING + 50 && !HAS_TRAIT(eater, TRAIT_VORACIOUS))
+ to_chat(eater, "You don't feel like eating any more junk food at the moment!")
+ return
+ else if(fullness <= 50)
+ eater.visible_message("[eater] hungrily [eatverb]s \the [parent], gobbling it down!", "You hungrily [eatverb] \the [parent], gobbling it down!")
+ else if(fullness > 50 && fullness < 150)
+ eater.visible_message("[eater] hungrily [eatverb]s \the [parent].", "You hungrily [eatverb] \the [parent].")
+ else if(fullness > 150 && fullness < 500)
+ eater.visible_message("[eater] [eatverb]s \the [parent].", "You [eatverb] \the [parent].")
+ else if(fullness > 500 && fullness < 600)
+ eater.visible_message("[eater] unwillingly [eatverb]s a bit of \the [parent].", "You unwillingly [eatverb] a bit of \the [parent].")
+ else if(fullness > (600 * (1 + eater.overeatduration / 2000))) // The more you eat - the more you can eat
+ eater.visible_message("[eater] cannot force any more of \the [parent] to go down [eater.p_their()] throat!", "You cannot force any more of \the [parent] to go down your throat!")
+ return
+ else //If you're feeding it to someone else.
+ if(isbrain(eater))
+ to_chat(feeder, "[eater] doesn't seem to have a mouth!")
+ return
+ if(fullness <= (600 * (1 + eater.overeatduration / 1000)))
+ eater.visible_message("[feeder] attempts to feed [eater] [parent].", \
+ "[feeder] attempts to feed you [parent].")
+ else
+ eater.visible_message("[feeder] cannot force any more of [parent] down [eater]'s throat!", \
+ "[feeder] cannot force any more of [parent] down your throat!")
+ return
+ if(!do_mob(feeder, eater)) //Wait 3 seconds before you can feed
+ return
+
+ log_combat(feeder, eater, "fed", owner.reagents.log_list())
+ eater.visible_message("[feeder] forces [eater] to eat [parent]!", \
+ "[feeder] forces you to eat [parent]!")
+
+ TakeBite(eater, feeder)
+
+///This function lets the eater take a bite and transfers the reagents to the eater.
+/datum/component/edible/proc/TakeBite(mob/living/eater, mob/living/feeder)
+
+ var/atom/owner = parent
+
+ if(!owner.reagents)
+ return FALSE
+ if(eater.satiety > -200)
+ eater.satiety -= junkiness
+ playsound(eater.loc,'sound/items/eatfood.ogg', rand(10,50), TRUE)
+ if(owner.reagents.total_volume)
+ SEND_SIGNAL(parent, COMSIG_FOOD_EATEN, eater, feeder)
+ var/fraction = min(bite_consumption / owner.reagents.total_volume, 1)
+ owner.reagents.trans_to(eater, bite_consumption, transfered_by = feeder, method = INGEST)
+ bitecount++
+ On_Consume(eater)
+ checkLiked(fraction, eater)
+
+ //Invoke our after eat callback if it is valid
+ if(after_eat)
+ after_eat.Invoke(eater, feeder)
+
+ return TRUE
+
+///Checks whether or not the eater can actually consume the food
+/datum/component/edible/proc/CanConsume(mob/living/eater, mob/living/feeder)
+ if(!iscarbon(eater))
+ return FALSE
+ var/mob/living/carbon/C = eater
+ var/covered = ""
+ if(C.is_mouth_covered(head_only = 1))
+ covered = "headgear"
+ else if(C.is_mouth_covered(mask_only = 1))
+ covered = "mask"
+ if(covered)
+ var/who = (isnull(feeder) || eater == feeder) ? "your" : "[eater.p_their()]"
+ to_chat(feeder, "You have to remove [who] [covered] first!")
+ return FALSE
+ return TRUE
+
+///Check foodtypes to see if we should send a moodlet
+/datum/component/edible/proc/checkLiked(var/fraction, mob/M)
+ if(last_check_time + 50 > world.time)
+ return FALSE
+ if(!ishuman(M))
+ return FALSE
+ var/mob/living/carbon/human/H = M
+ if(HAS_TRAIT(H, TRAIT_AGEUSIA) && foodtypes & H.dna.species.toxic_food)
+ to_chat(H, "You don't feel so good...")
+ H.adjust_disgust(25 + 30 * fraction)
+ else
+ if(foodtypes & H.dna.species.toxic_food)
+ to_chat(H,"What the hell was that thing?!")
+ H.adjust_disgust(25 + 30 * fraction)
+ SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "toxic_food", /datum/mood_event/disgusting_food)
+ else if(foodtypes & H.dna.species.disliked_food)
+ to_chat(H,"That didn't taste very good...")
+ H.adjust_disgust(11 + 15 * fraction)
+ SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "gross_food", /datum/mood_event/gross_food)
+ else if(foodtypes & H.dna.species.liked_food)
+ to_chat(H,"I love this taste!")
+ H.adjust_disgust(-5 + -2.5 * fraction)
+ SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "fav_food", /datum/mood_event/favorite_food)
+ if((foodtypes & BREAKFAST) && world.time - SSticker.round_start_time < STOP_SERVING_BREAKFAST)
+ SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "breakfast", /datum/mood_event/breakfast)
+ last_check_time = world.time
+
+///Delete the item when it is fully eaten
+/datum/component/edible/proc/On_Consume(mob/living/eater)
+
+ var/atom/owner = parent
+
+ if(!eater)
+ return
+ if(!owner.reagents.total_volume)
+ qdel(parent)
+
+///Ability to feed food to puppers
+/datum/component/edible/proc/UseByAnimal(datum/source, mob/user)
+
+ var/atom/owner = parent
+
+ if(!isdog(user))
+ return
+ var/mob/living/L = user
+ if(bitecount == 0 || prob(50))
+ L.emote("me", 1, "nibbles away at \the [parent]")
+ bitecount++
+ . = COMPONENT_ITEM_NO_ATTACK
+ L.taste(owner.reagents) // why should carbons get all the fun?
+ if(bitecount >= 5)
+ var/sattisfaction_text = pick("burps from enjoyment", "yaps for more", "woofs twice", "looks at the area where \the [parent] was")
+ if(sattisfaction_text)
+ L.emote("me", 1, "[sattisfaction_text]")
+ qdel(parent)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 1a8415c549c..6eba8746a31 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -702,6 +702,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
..()
/obj/item/proc/microwave_act(obj/machinery/microwave/M)
+ SEND_SIGNAL(src, COMSIG_ITEM_MICROWAVE_ACT, M)
if(istype(M) && M.dirty < 100)
M.dirty++
diff --git a/code/modules/antagonists/abductor/equipment/gland.dm b/code/modules/antagonists/abductor/equipment/gland.dm
index b1cd2c8ff71..a9f31b8ecc6 100644
--- a/code/modules/antagonists/abductor/equipment/gland.dm
+++ b/code/modules/antagonists/abductor/equipment/gland.dm
@@ -4,6 +4,7 @@
icon = 'icons/obj/abductor.dmi'
icon_state = "gland"
status = ORGAN_ROBOTIC
+ organ_flags = NONE
beating = TRUE
var/true_name = "baseline placebo referencer"
var/cooldown_low = 300
diff --git a/code/modules/food_and_drinks/food.dm b/code/modules/food_and_drinks/food.dm
index 0c79f436033..037a64f3480 100644
--- a/code/modules/food_and_drinks/food.dm
+++ b/code/modules/food_and_drinks/food.dm
@@ -5,7 +5,6 @@
/// the parent to the exclusion list in code/__HELPERS/unsorted.dm's
/// get_random_food proc.
////////////////////////////////////////////////////////////////////////////////
-#define STOP_SERVING_BREAKFAST (15 MINUTES)
/obj/item/reagent_containers/food
possible_transfer_amounts = list()
@@ -46,5 +45,3 @@
if((foodtype & BREAKFAST) && world.time - SSticker.round_start_time < STOP_SERVING_BREAKFAST)
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "breakfast", /datum/mood_event/breakfast)
last_check_time = world.time
-
-#undef STOP_SERVING_BREAKFAST
diff --git a/code/modules/mining/equipment/regenerative_core.dm b/code/modules/mining/equipment/regenerative_core.dm
index e755393d1e3..386fb930a44 100644
--- a/code/modules/mining/equipment/regenerative_core.dm
+++ b/code/modules/mining/equipment/regenerative_core.dm
@@ -110,9 +110,6 @@
go_inert()
return ..()
-/obj/item/organ/regenerative_core/prepare_eat()
- return null
-
/*************************Legion core********************/
/obj/item/organ/regenerative_core/legion
desc = "A strange rock that crackles with power. It can be used to heal completely, but it will rapidly decay into uselessness."
diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm
index 39464265edb..cfafea6ca42 100644
--- a/code/modules/mob/living/brain/brain_item.dm
+++ b/code/modules/mob/living/brain/brain_item.dm
@@ -69,10 +69,6 @@
transfer_identity(C)
C.update_hair()
-/obj/item/organ/brain/prepare_eat(mob/living/carbon/human/H)
- if(iszombie(H))//braaaaaains... otherwise, too important to eat.
- ..()
-
/obj/item/organ/brain/proc/transfer_identity(mob/living/L)
name = "[L.name]'s brain"
if(brainmob || decoy_override)
diff --git a/code/modules/mob/living/carbon/alien/organs.dm b/code/modules/mob/living/carbon/alien/organs.dm
index 5f59ee1cd89..290df6982a9 100644
--- a/code/modules/mob/living/carbon/alien/organs.dm
+++ b/code/modules/mob/living/carbon/alien/organs.dm
@@ -1,5 +1,6 @@
/obj/item/organ/alien
icon_state = "xgibmid2"
+ food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/toxin/acid = 10)
var/list/alien_powers = list()
/obj/item/organ/alien/Initialize()
@@ -24,11 +25,6 @@
M.RemoveAbility(P)
..()
-/obj/item/organ/alien/prepare_eat()
- var/obj/S = ..()
- S.reagents.add_reagent(/datum/reagent/toxin/acid, 10)
- return S
-
/obj/item/organ/alien/plasmavessel
name = "plasma vessel"
@@ -37,17 +33,13 @@
zone = BODY_ZONE_CHEST
slot = "plasmavessel"
alien_powers = list(/obj/effect/proc_holder/alien/plant, /obj/effect/proc_holder/alien/transfer)
+ food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/toxin/plasma = 10)
var/storedPlasma = 100
var/max_plasma = 250
var/heal_rate = 5
var/plasma_rate = 10
-/obj/item/organ/alien/plasmavessel/prepare_eat()
- var/obj/S = ..()
- S.reagents.add_reagent(/datum/reagent/toxin/plasma, storedPlasma/10)
- return S
-
/obj/item/organ/alien/plasmavessel/large
name = "large plasma vessel"
icon_state = "plasma_large"
diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
index 6090f5b35fa..a8904eef6a8 100644
--- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
+++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
@@ -4,6 +4,7 @@
name = "alien embryo"
icon = 'icons/mob/alien.dmi'
icon_state = "larva0_dead"
+ food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/toxin/acid = 10)
var/stage = 0
var/bursting = FALSE
@@ -16,11 +17,6 @@
if(prob(10))
AttemptGrow(0)
-/obj/item/organ/body_egg/alien_embryo/prepare_eat()
- var/obj/S = ..()
- S.reagents.add_reagent(/datum/reagent/toxin/acid, 10)
- return S
-
/obj/item/organ/body_egg/alien_embryo/on_life()
. = ..()
switch(stage)
diff --git a/code/modules/surgery/organ_manipulation.dm b/code/modules/surgery/organ_manipulation.dm
index 173420aecd4..e02df6b395f 100644
--- a/code/modules/surgery/organ_manipulation.dm
+++ b/code/modules/surgery/organ_manipulation.dm
@@ -68,7 +68,7 @@
time = 64
name = "manipulate organs"
repeatable = 1
- implements = list(/obj/item/organ = 100, /obj/item/reagent_containers/food/snacks/organ = 0, /obj/item/organ_storage = 100)
+ implements = list(/obj/item/organ = 100, /obj/item/organ_storage = 100)
var/implements_extract = list(TOOL_HEMOSTAT = 100, TOOL_CROWBAR = 55)
var/current_type
var/obj/item/organ/I = null
@@ -94,7 +94,10 @@
if(target_zone != I.zone || target.getorganslot(I.slot))
to_chat(user, "There is no room for [I] in [target]'s [parse_zone(target_zone)]!")
return -1
-
+ var/obj/item/organ/meatslab = tool
+ if(!meatslab.useable)
+ to_chat(user, "[I] seems to have been chewed on, you can't use this!")
+ return -1
display_results(user, target, "You begin to insert [tool] into [target]'s [parse_zone(target_zone)]...",
"[user] begins to insert [tool] into [target]'s [parse_zone(target_zone)].",
"[user] begins to insert something into [target]'s [parse_zone(target_zone)].")
@@ -122,10 +125,6 @@
else
return -1
- else if(istype(tool, /obj/item/reagent_containers/food/snacks/organ))
- to_chat(user, "[tool] was bitten by someone! It's too damaged to use!")
- return -1
-
/datum/surgery_step/manipulate_organs/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results)
if(current_type == "insert")
if(istype(tool, /obj/item/organ_storage))
diff --git a/code/modules/surgery/organs/appendix.dm b/code/modules/surgery/organs/appendix.dm
index 23d3a2ceb08..89937e7b5fc 100644
--- a/code/modules/surgery/organs/appendix.dm
+++ b/code/modules/surgery/organs/appendix.dm
@@ -39,9 +39,3 @@
..()
if(inflamed)
M.ForceContractDisease(new /datum/disease/appendicitis(), FALSE, TRUE)
-
-/obj/item/organ/appendix/prepare_eat()
- var/obj/S = ..()
- if(inflamed)
- S.reagents.add_reagent(/datum/reagent/toxin/bad_food, 5)
- return S
diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm
index f9a1436d840..311b14e9585 100644
--- a/code/modules/surgery/organs/heart.dm
+++ b/code/modules/surgery/organs/heart.dm
@@ -54,10 +54,10 @@
update_icon()
return 1
-/obj/item/organ/heart/prepare_eat()
- var/obj/S = ..()
- S.icon_state = "heart-off"
- return S
+/obj/item/organ/heart/OnEatFrom(eater, feeder)
+ . = ..()
+ beating = FALSE
+ update_icon()
/obj/item/organ/heart/on_life()
..()
diff --git a/code/modules/surgery/organs/liver.dm b/code/modules/surgery/organs/liver.dm
index 45d71eb2fff..fca2b6092a7 100755
--- a/code/modules/surgery/organs/liver.dm
+++ b/code/modules/surgery/organs/liver.dm
@@ -1,120 +1,117 @@
-#define LIVER_DEFAULT_TOX_TOLERANCE 3 //amount of toxins the liver can filter out
-#define LIVER_DEFAULT_TOX_LETHALITY 0.01 //lower values lower how harmful toxins are to the liver
-
-/obj/item/organ/liver
- name = "liver"
- icon_state = "liver"
- w_class = WEIGHT_CLASS_SMALL
- zone = BODY_ZONE_CHEST
- slot = ORGAN_SLOT_LIVER
- desc = "Pairing suggestion: chianti and fava beans."
-
- maxHealth = STANDARD_ORGAN_THRESHOLD
- healing_factor = STANDARD_ORGAN_HEALING
- decay_factor = STANDARD_ORGAN_DECAY
-
- var/alcohol_tolerance = ALCOHOL_RATE //affects how much damage the liver takes from alcohol
- var/toxTolerance = LIVER_DEFAULT_TOX_TOLERANCE //maximum amount of toxins the liver can just shrug off
- var/toxLethality = LIVER_DEFAULT_TOX_LETHALITY //affects how much damage toxins do to the liver
- var/filterToxins = TRUE //whether to filter toxins
-
-#define HAS_SILENT_TOXIN 0 //don't provide a feedback message if this is the only toxin present
-#define HAS_NO_TOXIN 1
-#define HAS_PAINFUL_TOXIN 2
-
-/obj/item/organ/liver/on_life()
- var/mob/living/carbon/C = owner
- ..() //perform general on_life()
- if(istype(C))
- if(!(organ_flags & ORGAN_FAILING) && !HAS_TRAIT(C, TRAIT_NOMETABOLISM))//can't process reagents with a failing liver
-
- var/provide_pain_message = HAS_NO_TOXIN
- if(filterToxins && !HAS_TRAIT(owner, TRAIT_TOXINLOVER))
- //handle liver toxin filtration
- for(var/datum/reagent/toxin/T in C.reagents.reagent_list)
- var/thisamount = C.reagents.get_reagent_amount(T.type)
- if (thisamount && thisamount <= toxTolerance)
- C.reagents.remove_reagent(T.type, 1)
- else
- damage += (thisamount*toxLethality)
- if(provide_pain_message != HAS_PAINFUL_TOXIN)
- provide_pain_message = T.silent_toxin ? HAS_SILENT_TOXIN : HAS_PAINFUL_TOXIN
-
- //metabolize reagents
- C.reagents.metabolize(C, can_overdose=TRUE)
-
- if(provide_pain_message && damage > 10 && prob(damage/3))//the higher the damage the higher the probability
- to_chat(C, "You feel a dull pain in your abdomen.")
-
- else //for when our liver's failing
- C.liver_failure()
-
- if(damage > maxHealth)//cap liver damage
- damage = maxHealth
-
-#undef HAS_SILENT_TOXIN
-#undef HAS_NO_TOXIN
-#undef HAS_PAINFUL_TOXIN
-
-/obj/item/organ/liver/prepare_eat()
- var/obj/S = ..()
- S.reagents.add_reagent(/datum/reagent/iron, 5)
- return S
-
-/obj/item/organ/liver/fly
- name = "insectoid liver"
- icon_state = "liver-x" //xenomorph liver? It's just a black liver so it fits.
- desc = "A mutant liver designed to handle the unique diet of a flyperson."
- alcohol_tolerance = 0.007 //flies eat vomit, so a lower alcohol tolerance is perfect!
-
-/obj/item/organ/liver/plasmaman
- name = "reagent processing crystal"
- icon_state = "liver-p"
- desc = "A large crystal that is somehow capable of metabolizing chemicals, these are found in plasmamen."
-
-/obj/item/organ/liver/alien
- name = "alien liver" // doesnt matter for actual aliens because they dont take toxin damage
- icon_state = "liver-x" // Same sprite as fly-person liver.
- desc = "A liver that used to belong to a killer alien, who knows what it used to eat."
- toxLethality = LIVER_DEFAULT_TOX_LETHALITY * 2.5 // rejects its owner early after too much punishment
- toxTolerance = 15 // complete toxin immunity like xenos have would be too powerful
-
-/obj/item/organ/liver/cybernetic
- name = "basic cybernetic liver"
- icon_state = "liver-c"
- desc = "A very basic device designed to mimic the functions of a human liver. Handles toxins slightly worse than an organic liver."
- organ_flags = ORGAN_SYNTHETIC
- toxTolerance = 2
- toxLethality = 0.011
- maxHealth = STANDARD_ORGAN_THRESHOLD*0.5
-
- var/emp_vulnerability = 80 //Chance of permanent effects if emp-ed.
-
-/obj/item/organ/liver/cybernetic/tier2
- name = "cybernetic liver"
- icon_state = "liver-c-u"
- desc = "An electronic device designed to mimic the functions of a human liver. Handles toxins slightly better than an organic liver."
- maxHealth = 1.5 * STANDARD_ORGAN_THRESHOLD
- toxTolerance = 5 //can shrug off up to 5u of toxins
- toxLethality = 0.008 //20% less damage than a normal liver
- emp_vulnerability = 40
-
-/obj/item/organ/liver/cybernetic/tier3
- name = "upgraded cybernetic liver"
- icon_state = "liver-c-u2"
- desc = "An upgraded version of the cybernetic liver, designed to improve further upon organic livers. It is resistant to alcohol poisoning and is very robust at filtering toxins."
- alcohol_tolerance = 0.001
- maxHealth = 2 * STANDARD_ORGAN_THRESHOLD
- toxTolerance = 10 //can shrug off up to 10u of toxins
- toxLethality = 0.008 //20% less damage than a normal liver
- emp_vulnerability = 20
-
-/obj/item/organ/liver/cybernetic/emp_act(severity)
- . = ..()
- if(. & EMP_PROTECT_SELF)
- return
- if(world.time > severe_cooldown) //So we cant just spam emp to kill people.
- owner.adjustToxLoss(10)
- severe_cooldown = world.time + 10 SECONDS
- if(prob(emp_vulnerability/severity)) //Chance of permanent effects
- organ_flags = ORGAN_SYNTHETIC_EMP //Starts organ faliure - gonna need replacing soon.
+#define LIVER_DEFAULT_TOX_TOLERANCE 3 //amount of toxins the liver can filter out
+#define LIVER_DEFAULT_TOX_LETHALITY 0.01 //lower values lower how harmful toxins are to the liver
+
+/obj/item/organ/liver
+ name = "liver"
+ icon_state = "liver"
+ w_class = WEIGHT_CLASS_SMALL
+ zone = BODY_ZONE_CHEST
+ slot = ORGAN_SLOT_LIVER
+ desc = "Pairing suggestion: chianti and fava beans."
+
+ maxHealth = STANDARD_ORGAN_THRESHOLD
+ healing_factor = STANDARD_ORGAN_HEALING
+ decay_factor = STANDARD_ORGAN_DECAY
+
+ food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/iron = 5)
+
+ var/alcohol_tolerance = ALCOHOL_RATE//affects how much damage the liver takes from alcohol
+ var/toxTolerance = LIVER_DEFAULT_TOX_TOLERANCE//maximum amount of toxins the liver can just shrug off
+ var/toxLethality = LIVER_DEFAULT_TOX_LETHALITY//affects how much damage toxins do to the liver
+ var/filterToxins = TRUE //whether to filter toxins
+
+#define HAS_SILENT_TOXIN 0 //don't provide a feedback message if this is the only toxin present
+#define HAS_NO_TOXIN 1
+#define HAS_PAINFUL_TOXIN 2
+
+/obj/item/organ/liver/on_life()
+ var/mob/living/carbon/C = owner
+ ..() //perform general on_life()
+ if(istype(C))
+ if(!(organ_flags & ORGAN_FAILING) && !HAS_TRAIT(C, TRAIT_NOMETABOLISM))//can't process reagents with a failing liver
+
+ var/provide_pain_message = HAS_NO_TOXIN
+ if(filterToxins && !HAS_TRAIT(owner, TRAIT_TOXINLOVER))
+ //handle liver toxin filtration
+ for(var/datum/reagent/toxin/T in C.reagents.reagent_list)
+ var/thisamount = C.reagents.get_reagent_amount(T.type)
+ if (thisamount && thisamount <= toxTolerance)
+ C.reagents.remove_reagent(T.type, 1)
+ else
+ damage += (thisamount*toxLethality)
+ if(provide_pain_message != HAS_PAINFUL_TOXIN)
+ provide_pain_message = T.silent_toxin ? HAS_SILENT_TOXIN : HAS_PAINFUL_TOXIN
+
+ //metabolize reagents
+ C.reagents.metabolize(C, can_overdose=TRUE)
+
+ if(provide_pain_message && damage > 10 && prob(damage/3))//the higher the damage the higher the probability
+ to_chat(C, "You feel a dull pain in your abdomen.")
+
+ else //for when our liver's failing
+ C.liver_failure()
+
+ if(damage > maxHealth)//cap liver damage
+ damage = maxHealth
+
+#undef HAS_SILENT_TOXIN
+#undef HAS_NO_TOXIN
+#undef HAS_PAINFUL_TOXIN
+
+/obj/item/organ/liver/fly
+ name = "insectoid liver"
+ icon_state = "liver-x" //xenomorph liver? It's just a black liver so it fits.
+ desc = "A mutant liver designed to handle the unique diet of a flyperson."
+ alcohol_tolerance = 0.007 //flies eat vomit, so a lower alcohol tolerance is perfect!
+
+/obj/item/organ/liver/plasmaman
+ name = "reagent processing crystal"
+ icon_state = "liver-p"
+ desc = "A large crystal that is somehow capable of metabolizing chemicals, these are found in plasmamen."
+
+/obj/item/organ/liver/alien
+ name = "alien liver" // doesnt matter for actual aliens because they dont take toxin damage
+ icon_state = "liver-x" // Same sprite as fly-person liver.
+ desc = "A liver that used to belong to a killer alien, who knows what it used to eat."
+ toxLethality = LIVER_DEFAULT_TOX_LETHALITY * 2.5 // rejects its owner early after too much punishment
+ toxTolerance = 15 // complete toxin immunity like xenos have would be too powerful
+
+/obj/item/organ/liver/cybernetic
+ name = "basic cybernetic liver"
+ icon_state = "liver-c"
+ desc = "A very basic device designed to mimic the functions of a human liver. Handles toxins slightly worse than an organic liver."
+ organ_flags = ORGAN_SYNTHETIC
+ toxTolerance = 2
+ toxLethality = 0.011
+ maxHealth = STANDARD_ORGAN_THRESHOLD*0.5
+
+ var/emp_vulnerability = 80 //Chance of permanent effects if emp-ed.
+
+/obj/item/organ/liver/cybernetic/tier2
+ name = "cybernetic liver"
+ icon_state = "liver-c-u"
+ desc = "An electronic device designed to mimic the functions of a human liver. Handles toxins slightly better than an organic liver."
+ maxHealth = 1.5 * STANDARD_ORGAN_THRESHOLD
+ toxTolerance = 5 //can shrug off up to 5u of toxins
+ toxLethality = 0.008 //20% less damage than a normal liver
+ emp_vulnerability = 40
+
+/obj/item/organ/liver/cybernetic/tier3
+ name = "upgraded cybernetic liver"
+ icon_state = "liver-c-u2"
+ desc = "An upgraded version of the cybernetic liver, designed to improve further upon organic livers. It is resistant to alcohol poisoning and is very robust at filtering toxins."
+ alcohol_tolerance = 0.001
+ maxHealth = 2 * STANDARD_ORGAN_THRESHOLD
+ toxTolerance = 10 //can shrug off up to 10u of toxins
+ toxLethality = 0.008 //20% less damage than a normal liver
+ emp_vulnerability = 20
+
+/obj/item/organ/liver/cybernetic/emp_act(severity)
+ . = ..()
+ if(. & EMP_PROTECT_SELF)
+ return
+ if(world.time > severe_cooldown) //So we cant just spam emp to kill people.
+ owner.adjustToxLoss(10)
+ severe_cooldown = world.time + 10 SECONDS
+ if(prob(emp_vulnerability/severity)) //Chance of permanent effects
+ organ_flags = ORGAN_SYNTHETIC_EMP //Starts organ faliure - gonna need replacing soon.
diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm
index 26c54d188d1..1a2496bbb05 100644
--- a/code/modules/surgery/organs/lungs.dm
+++ b/code/modules/surgery/organs/lungs.dm
@@ -15,6 +15,9 @@
now_fixed = "Your lungs seem to once again be able to hold air."
high_threshold_cleared = "The constriction around your chest loosens as your breathing calms down."
+
+ food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/medicine/salbutamol = 5)
+
//Breath damage
var/safe_oxygen_min = 16 // Minimum safe partial pressure of O2, in kPa
@@ -402,10 +405,6 @@
failed = FALSE
return
-/obj/item/organ/lungs/prepare_eat()
- var/obj/S = ..()
- S.reagents.add_reagent(/datum/reagent/medicine/salbutamol, 5)
- return S
/obj/item/organ/lungs/plasmaman
name = "plasma filter"
diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm
index f795ba8aa03..1a4b6b96e51 100644
--- a/code/modules/surgery/organs/organ_internal.dm
+++ b/code/modules/surgery/organs/organ_internal.dm
@@ -8,7 +8,7 @@
var/zone = BODY_ZONE_CHEST
var/slot
// DO NOT add slots with matching names to different zones - it will break internal_organs_slot list!
- var/organ_flags = 0
+ var/organ_flags = ORGAN_EDIBLE
var/maxHealth = STANDARD_ORGAN_THRESHOLD
var/damage = 0 //total damage this organ has sustained
///Healing factor and decay factor function on % of maxhealth, and do not work by applying a static number per tick
@@ -26,6 +26,15 @@
var/high_threshold_cleared
var/low_threshold_cleared
+ ///When you take a bite you cant jam it in for surgery anymore.
+ var/useable = TRUE
+ var/list/food_reagents = list(/datum/reagent/consumable/nutriment = 5)
+
+/obj/item/organ/Initialize()
+ . = ..()
+ if(organ_flags & ORGAN_EDIBLE)
+ AddComponent(/datum/component/edible, food_reagents, null, RAW | MEAT | GROSS, null, 10, null, null, null, CALLBACK(src, .proc/OnEatFrom))
+
/obj/item/organ/proc/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
if(!iscarbon(M) || owner == M)
return
@@ -101,24 +110,6 @@
if(damage > high_threshold)
. += "[src] is starting to look discolored."
-
-/obj/item/organ/proc/prepare_eat()
- var/obj/item/reagent_containers/food/snacks/organ/S = new
- S.name = name
- S.desc = desc
- S.icon = icon
- S.icon_state = icon_state
- S.w_class = w_class
-
- return S
-
-/obj/item/reagent_containers/food/snacks/organ
- name = "appendix"
- icon_state = "appendix"
- icon = 'icons/obj/surgery.dmi'
- list_reagents = list(/datum/reagent/consumable/nutriment = 5)
- foodtype = RAW | MEAT | GROSS
-
/obj/item/organ/Initialize()
. = ..()
START_PROCESSING(SSobj, src)
@@ -132,17 +123,8 @@
STOP_PROCESSING(SSobj, src)
return ..()
-/obj/item/organ/attack(mob/living/carbon/M, mob/user)
- if(M == user && ishuman(user))
- var/mob/living/carbon/human/H = user
- if(status == ORGAN_ORGANIC)
- var/obj/item/reagent_containers/food/snacks/S = prepare_eat(H)
- if(S)
- qdel(src)
- if(H.put_in_active_hand(S))
- S.attack(H, H)
- else
- ..()
+/obj/item/organ/proc/OnEatFrom(eater, feeder)
+ useable = FALSE //You can't use it anymore after eating it you spaztic
/obj/item/organ/item_action_slot_check(slot,mob/user)
return //so we don't grant the organ's action to mobs who pick up the organ.
diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm
index d6e2a313d75..8c020ccfa85 100644
--- a/code/modules/surgery/organs/tongue.dm
+++ b/code/modules/surgery/organs/tongue.dm
@@ -248,6 +248,7 @@
name = "robotic voicebox"
desc = "A voice synthesizer that can interface with organic lifeforms."
status = ORGAN_ROBOTIC
+ organ_flags = NONE
icon_state = "tonguerobot"
say_mod = "states"
attack_verb = list("beeped", "booped")
diff --git a/tgstation.dme b/tgstation.dme
index 6871a49bbdc..d1f5933768d 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -382,6 +382,7 @@
#include "code\datums\components\decal.dm"
#include "code\datums\components\dejavu.dm"
#include "code\datums\components\earprotection.dm"
+#include "code\datums\components\edible.dm"
#include "code\datums\components\edit_complainer.dm"
#include "code\datums\components\empprotection.dm"
#include "code\datums\components\explodable.dm"