diff --git a/code/datums/materials/_material.dm b/code/datums/materials/_material.dm
index 4186bcb4519..fc0dcaa213a 100644
--- a/code/datums/materials/_material.dm
+++ b/code/datums/materials/_material.dm
@@ -141,3 +141,12 @@ Simple datum which is instanced once per type and is used for every object of sa
/datum/material/proc/on_removed_turf(turf/T, material_flags)
return
+
+/**
+ * This proc is called when the mat is found in an item that's consumed by accident. see /obj/item/proc/on_accidental_consumption.
+ * Arguments
+ * * M - person consuming the mat
+ * * S - (optional) item the mat is contained in (NOT the item with the mat itself)
+ */
+/datum/material/proc/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ return FALSE
diff --git a/code/datums/materials/basemats.dm b/code/datums/materials/basemats.dm
index 9ca34ebd1fd..d45d9bf603a 100644
--- a/code/datums/materials/basemats.dm
+++ b/code/datums/materials/basemats.dm
@@ -7,6 +7,10 @@
sheet_type = /obj/item/stack/sheet/metal
value_per_unit = 0.0025
+/datum/material/iron/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ M.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5)
+ return TRUE
+
///Breaks extremely easily but is transparent.
/datum/material/glass
name = "glass"
@@ -20,6 +24,10 @@
beauty_modifier = 0.05
armor_modifiers = list("melee" = 0.2, "bullet" = 0.2, "laser" = 0, "energy" = 1, "bomb" = 0, "bio" = 0.2, "rad" = 0.2, "fire" = 1, "acid" = 0.2)
+/datum/material/glass/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ M.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5, sharpness = TRUE) //cronch
+ return TRUE
+
/*
Color matrices are like regular colors but unlike with normal colors, you can go over 255 on a channel.
Unless you know what you're doing, only use the first three numbers. They're in RGB order.
@@ -35,6 +43,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
value_per_unit = 0.025
beauty_modifier = 0.075
+/datum/material/silver/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ M.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5)
+ return TRUE
+
///Slight force increase
/datum/material/gold
name = "gold"
@@ -47,6 +59,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
beauty_modifier = 0.15
armor_modifiers = list("melee" = 1.1, "bullet" = 1.1, "laser" = 1.15, "energy" = 1.15, "bomb" = 1, "bio" = 1, "rad" = 1, "fire" = 0.7, "acid" = 1.1)
+/datum/material/gold/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ M.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5)
+ return TRUE
+
///Has no special properties
/datum/material/diamond
name = "diamond"
@@ -59,6 +75,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
beauty_modifier = 0.3
armor_modifiers = list("melee" = 1.3, "bullet" = 1.3, "laser" = 0.6, "energy" = 1, "bomb" = 1.2, "bio" = 1, "rad" = 1, "fire" = 1, "acid" = 1)
+/datum/material/diamond/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ M.apply_damage(15, BRUTE, BODY_ZONE_HEAD, wound_bonus = 7)
+ return TRUE
+
///Is slightly radioactive
/datum/material/uranium
name = "uranium"
@@ -78,6 +98,11 @@ Unless you know what you're doing, only use the first three numbers. They're in
. = ..()
qdel(source.GetComponent(/datum/component/radioactive))
+/datum/material/uranium/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ M.reagents.add_reagent(/datum/reagent/uranium, rand(4, 6))
+ S?.reagents?.add_reagent(/datum/reagent/uranium, S.reagents.total_volume*(2/5))
+ return TRUE
+
///Adds firestacks on hit (Still needs support to turn into gas on destruction)
/datum/material/plasma
name = "plasma"
@@ -100,6 +125,11 @@ Unless you know what you're doing, only use the first three numbers. They're in
source.RemoveElement(/datum/element/firestacker, amount=1)
qdel(source.GetComponent(/datum/component/explodable))
+/datum/material/plasma/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ M.reagents.add_reagent(/datum/reagent/toxin/plasma, rand(6, 8))
+ S?.reagents?.add_reagent(/datum/reagent/toxin/plasma, S.reagents.total_volume*(2/5))
+ return TRUE
+
///Can cause bluespace effects on use. (Teleportation) (Not yet implemented)
/datum/material/bluespace
name = "bluespace crystal"
@@ -111,6 +141,11 @@ Unless you know what you're doing, only use the first three numbers. They're in
sheet_type = /obj/item/stack/sheet/bluespace_crystal
value_per_unit = 0.15
+/datum/material/bluespace/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ M.reagents.add_reagent(/datum/reagent/bluespace, rand(5, 8))
+ S?.reagents?.add_reagent(/datum/reagent/bluespace, S.reagents.total_volume*(2/5))
+ return TRUE
+
///Honks and slips
/datum/material/bananium
name = "bananium"
@@ -127,12 +162,15 @@ Unless you know what you're doing, only use the first three numbers. They're in
source.AddComponent(/datum/component/squeak, list('sound/items/bikehorn.ogg'=1), 50)
source.AddComponent(/datum/component/slippery, min(amount / 10, 80))
-
/datum/material/bananium/on_removed(atom/source, amount, material_flags)
. = ..()
qdel(source.GetComponent(/datum/component/slippery))
qdel(source.GetComponent(/datum/component/squeak))
+/datum/material/bananium/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ M.reagents.add_reagent(/datum/reagent/consumable/banana, rand(8, 12))
+ S?.reagents?.add_reagent(/datum/reagent/consumable/banana, S.reagents.total_volume*(2/5))
+ return TRUE
///Mediocre force increase
/datum/material/titanium
@@ -146,6 +184,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
beauty_modifier = 0.05
armor_modifiers = list("melee" = 1.35, "bullet" = 1.3, "laser" = 1.3, "energy" = 1.25, "bomb" = 1.25, "bio" = 1, "rad" = 1, "fire" = 0.7, "acid" = 1)
+/datum/material/titanium/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ M.apply_damage(15, BRUTE, BODY_ZONE_HEAD, wound_bonus = 7)
+ return TRUE
+
/datum/material/runite
name = "runite"
desc = "Runite"
@@ -157,6 +199,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
beauty_modifier = 0.5
armor_modifiers = list("melee" = 1.35, "bullet" = 2, "laser" = 0.5, "energy" = 1.25, "bomb" = 1.25, "bio" = 1, "rad" = 1, "fire" = 1.4, "acid" = 1) //rune is weak against magic lasers but strong against bullets. This is the combat triangle.
+/datum/material/runite/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ M.apply_damage(20, BRUTE, BODY_ZONE_HEAD, wound_bonus = 10)
+ return TRUE
+
///Force decrease
/datum/material/plastic
name = "plastic"
@@ -169,6 +215,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
beauty_modifier = -0.01
armor_modifiers = list("melee" = 1.5, "bullet" = 1.1, "laser" = 0.3, "energy" = 0.5, "bomb" = 1, "bio" = 1, "rad" = 1, "fire" = 1.1, "acid" = 1)
+/datum/material/plastic/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ M.adjust_disgust(17)
+ return TRUE
+
///Force decrease and mushy sound effect. (Not yet implemented)
/datum/material/biomass
name = "biomass"
@@ -200,6 +250,15 @@ Unless you know what you're doing, only use the first three numbers. They're in
var/obj/wooden = source
wooden.resistance_flags &= ~FLAMMABLE
+/datum/material/wood/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ M.apply_damage(5, BRUTE, BODY_ZONE_HEAD)
+
+ var/obj/item/reagent_containers/food/snacks/food_S = S
+ if(istype(food_S) && food_S?.tastes?.len)
+ food_S.tastes += "wood chips and sawdust"
+ food_S.tastes["wood chips and sawdust"] = 3
+ return TRUE
+
///Stronk force increase
/datum/material/adamantine
name = "adamantine"
@@ -212,6 +271,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
beauty_modifier = 0.4
armor_modifiers = list("melee" = 1.5, "bullet" = 1.5, "laser" = 1.3, "energy" = 1.3, "bomb" = 1, "bio" = 1, "rad" = 1, "fire" = 2.5, "acid" = 1)
+/datum/material/adamantine/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ M.apply_damage(20, BRUTE, BODY_ZONE_HEAD, wound_bonus = 10)
+ return TRUE
+
///RPG Magic.
/datum/material/mythril
name = "mythril"
@@ -234,6 +297,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
if(istype(source, /obj/item))
qdel(source.GetComponent(/datum/component/fantasy))
+/datum/material/mythril/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ M.apply_damage(20, BRUTE, BODY_ZONE_HEAD, wound_bonus = 10)
+ return TRUE
+
//formed when freon react with o2, emits a lot of plasma when heated
/datum/material/hot_ice
name = "hot ice"
@@ -253,6 +320,15 @@ Unless you know what you're doing, only use the first three numbers. They're in
qdel(source.GetComponent(/datum/component/hot_ice, "plasma", amount*150, amount*20+300))
return ..()
+/datum/material/hot_ice/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ M.reagents.add_reagent(/datum/reagent/toxin/plasma, rand(5, 6))
+ S?.reagents?.add_reagent(/datum/reagent/toxin/plasma, S.reagents.total_volume*(3/5))
+ var/obj/item/reagent_containers/food/snacks/food_S = S
+ if(istype(food_S) && food_S?.tastes?.len)
+ food_S.tastes += "salt"
+ food_S.tastes["salt"] = 3
+ return TRUE
+
/datum/material/metalhydrogen
name = "Metal Hydrogen"
desc = "Solid metallic hydrogen. Some say it should be impossible"
@@ -265,6 +341,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
strength_modifier = 1.2
armor_modifiers = list("melee" = 1.35, "bullet" = 1.3, "laser" = 1.3, "energy" = 1.25, "bomb" = 0.7, "bio" = 1, "rad" = 1, "fire" = 1.3, "acid" = 1)
+/datum/material/metalhydrogen/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ M.apply_damage(15, BRUTE, BODY_ZONE_HEAD, wound_bonus = 7)
+ return TRUE
+
//I don't like sand. It's coarse, and rough, and irritating, and it gets everywhere.
/datum/material/sand
name = "sand"
@@ -280,6 +360,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
turf_sound_override = FOOTSTEP_SAND
texture_layer_icon_state = "sand"
+/datum/material/sand/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ M.adjust_disgust(17)
+ return TRUE
+
//And now for our lavaland dwelling friends, sand, but in stone form! Truly revolutionary.
/datum/material/sandstone
name = "sandstone"
@@ -305,6 +389,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
turf_sound_override = FOOTSTEP_SAND
texture_layer_icon_state = "sand"
+/datum/material/snow/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ M.reagents.add_reagent(/datum/reagent/water, rand(5, 10))
+ return TRUE
+
/datum/material/runedmetal
name = "runed metal"
desc = "Mir'ntrath barhah Nar'sie."
@@ -316,6 +404,11 @@ Unless you know what you're doing, only use the first three numbers. They're in
beauty_modifier = -0.15
texture_layer_icon_state = "runed"
+/datum/material/runedmetal/on_accidental_mat_consumption(mob/living/carbon/M, obj/item/S)
+ M.reagents.add_reagent(/datum/reagent/fuel/unholywater, rand(8, 12))
+ M.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5)
+ return TRUE
+
/datum/material/bronze
name = "bronze"
desc = "Clock Cult? Never heard of it."
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index f70ccf5ee70..996ab78ea54 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -1011,3 +1011,106 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
jostle_pain_mult = (!isnull(embedding["jostle_pain_mult"]) ? embedding["jostle_pain_mult"] : EMBEDDED_JOSTLE_PAIN_MULTIPLIER),\
pain_stam_pct = (!isnull(embedding["pain_stam_pct"]) ? embedding["pain_stam_pct"] : EMBEDDED_PAIN_STAM_PCT))
return TRUE
+
+/// How many different types of mats will be counted in a bite?
+#define MAX_BONUS_MATS_PER_BITE 2
+
+/*
+ * On accidental consumption: when you somehow end up eating an item accidentally (currently, this is used for when items are hidden in food like bread or cake)
+ *
+ * The base proc will check if the item is sharp and has a decent force.
+ * Then, it checks the item's mat datums for the effects it applies afterwards.
+ * Then, it checks tiny items.
+ * After all that, it returns TRUE if the item is set to be discovered. Otherwise, it returns FALSE.
+ *
+ * This works similarily to /suicide_act: if you want an item to have a unique interaction, go to that item
+ * and give it an /on_accidental_consumption proc override. For a simple example of this, check out the nuke disk.
+ *
+ * Arguments
+ * * M - the mob accidentally consuming the item
+ * * user - the mob feeding M the item - usually, it's the same as M
+ * * source_item - the item that held the item being consumed - bread, cake, etc
+ * * discover_after - if the item will be discovered after being chomped (FALSE will usually mean it was swallowed, TRUE will usually mean it was bitten into and discovered)
+ */
+/obj/item/proc/on_accidental_consumption(mob/living/carbon/M, mob/living/carbon/user, obj/item/source_item, discover_after = TRUE)
+ /// If source_item is a snack, we can adjust its taste
+ var/obj/item/reagent_containers/food/snacks/S = source_item
+ if(!istype(S))
+ S = null
+
+ if(get_sharpness() && force >= 5) //if we've got something sharp with a decent force (ie, not plastic)
+ M.emote("scream")
+ M.visible_message("[M] looks like [M.p_theyve()] just bit something they shouldn't have!", \
+ "OH GOD! Was that a crunch? That didn't feel good at all!!")
+
+ M.apply_damage(max(15, force), BRUTE, BODY_ZONE_HEAD, wound_bonus = 10, sharpness = TRUE)
+ M.losebreath += 2
+ if(tryEmbed(M.get_bodypart(BODY_ZONE_CHEST), TRUE, TRUE)) //and if it embeds in their chest, cause a lot of pain
+ M.apply_damage(max(25, force*1.5), BRUTE, BODY_ZONE_CHEST, wound_bonus = 7, sharpness = TRUE)
+ M.losebreath += 6
+ discover_after = FALSE
+
+ if(S?.tastes?.len) //is that blood in my mouth?
+ S.tastes += "iron"
+ S.tastes["iron"] = 2
+
+ else if(custom_materials?.len) //if we've got materials, lets see whats in it
+ /// How many 'bonus' mats have we found? You can only be affected by two 'bonus' material datums by default
+ var/found_mats = 0
+ /// How much of each material is in it? Used to determine if the glass should break
+ var/total_material_amount = 0
+
+ for(var/mats in custom_materials)
+ total_material_amount += custom_materials[mats]
+ if(found_mats >= MAX_BONUS_MATS_PER_BITE)
+ continue //continue instead of break so we can finish adding up all the mats to the total
+
+ var/datum/material/FM = mats
+ if(FM.on_accidental_mat_consumption(M, S))
+ found_mats++
+
+ //if there's glass in it and the glass is more than 60% of the item, then we can shatter it
+ if(custom_materials[SSmaterials.GetMaterialRef(/datum/material/glass)] >= total_material_amount * 0.60)
+ if(prob(66)) //66% chance to break it
+ /// The glass shard that is spawned into the source item
+ var/obj/item/shard/broken_glass = new /obj/item/shard(src)
+ broken_glass.name = "broken [name]"
+ broken_glass.desc = "This used to be \a [name], but it sure isn't anymore."
+ playsound(M, "shatter", 25, TRUE)
+ qdel(src)
+ if(S)
+ S.contents += broken_glass //puts the glass back into the source item
+ else
+ broken_glass.on_accidental_consumption(M, user)
+ else //33% chance to just "crack" it (play a sound) and leave it in the bread
+ playsound(M, "shatter", 15, TRUE)
+ discover_after = FALSE
+
+ M.adjust_disgust(33)
+ M.visible_message("[M] looks like [M.p_theyve()] just bitten into something hard.", \
+ "Eugh! Did I just bite into something?")
+
+ else if(w_class == WEIGHT_CLASS_TINY) //small items like soap or toys that don't have mat datums
+ /// M's chest (for cavity implanting the item)
+ var/obj/item/bodypart/chest/CV = M.get_bodypart(BODY_ZONE_CHEST)
+ if(CV.cavity_item)
+ M.vomit(5, FALSE, FALSE, distance = 0)
+ forceMove(drop_location())
+ to_chat(M, "You vomit up a [name]! [source_item? "Was that in \the [source_item]?" : ""]")
+ else
+ M.transferItemToLoc(src, M, TRUE)
+ M.losebreath += 2
+ CV.cavity_item = src
+ to_chat(M, "You swallow hard. [source_item? "Something small was in \the [source_item]..." : ""]")
+ discover_after = FALSE
+
+ else
+ to_chat(M, "[source_item? "Something strange was in the \the [source_item]..." : "I just bit something strange..."] ")
+
+ //Just in case - can't discover something that doesn't exist
+ if(QDELETED(src))
+ return FALSE
+
+ return discover_after
+
+#undef MAX_BONUS_MATS_PER_BITE
diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
index afe1f40f062..2e3a17defc3 100644
--- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
+++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
@@ -662,6 +662,15 @@ This is here to make the tiles around the station mininuke change when it's arme
if(isobserver(user) || HAS_TRAIT(user.mind, TRAIT_DISK_VERIFIER))
. += "The serial numbers on [src] are incorrect."
+/*
+ * You can't accidentally eat the nuke disk, bro
+ */
+/obj/item/disk/nuclear/on_accidental_consumption(mob/living/carbon/M, mob/living/carbon/user, obj/item/source_item, discover_after = TRUE)
+ M.visible_message("[M] looks like [M.p_theyve()] just bitten into something important.", \
+ "Wait, is this the nuke disk?")
+
+ return discover_after
+
/obj/item/disk/nuclear/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/claymore/highlander) && !fake)
var/obj/item/claymore/highlander/H = I
diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm
index 8bbd468a7f5..2bfc7b7099d 100644
--- a/code/modules/food_and_drinks/drinks/drinks.dm
+++ b/code/modules/food_and_drinks/drinks/drinks.dm
@@ -52,6 +52,14 @@
playsound(M.loc,'sound/items/drink.ogg', rand(10,50), TRUE)
return TRUE
+/*
+ * On accidental consumption, make sure the container is partially glass, and continue to the reagent_container proc
+ */
+/obj/item/reagent_containers/food/drinks/on_accidental_consumption(mob/living/carbon/M, mob/living/carbon/user, obj/item/source_item, discover_after = TRUE)
+ if(isGlass && !custom_materials)
+ custom_materials = list(SSmaterials.GetMaterialRef(/datum/material/glass) = 5) //sets it to glass so, later on, it gets picked up by the glass catch
+ return ..()
+
/obj/item/reagent_containers/food/drinks/afterattack(obj/target, mob/user , proximity)
. = ..()
if(!proximity)
diff --git a/code/modules/food_and_drinks/food/snacks.dm b/code/modules/food_and_drinks/food/snacks.dm
index 023adeb3932..cf47992834e 100644
--- a/code/modules/food_and_drinks/food/snacks.dm
+++ b/code/modules/food_and_drinks/food/snacks.dm
@@ -80,10 +80,13 @@ All foods are distributed among various categories. Use common sense.
if(istype(location))
location.put_in_hands(trash_item)
+//it's never an accident when you eat food! right?
+/obj/item/reagent_containers/food/snacks/on_accidental_consumption(mob/living/carbon/M, mob/living/carbon/user, obj/item/source_item, discover_after = TRUE)
+ return TRUE
+
/obj/item/reagent_containers/food/snacks/attack_self(mob/user)
return
-
/obj/item/reagent_containers/food/snacks/attack(mob/living/M, mob/living/user, def_zone)
if(user.a_intent == INTENT_HARM)
return ..()
@@ -185,10 +188,9 @@ All foods are distributed among various categories. Use common sense.
var/obj/item/reagent_containers/food/snacks/customizable/C = new custom_food_type(get_turf(src))
C.initialize_custom_food(src, S, user)
return 0
- var/sharp = W.get_sharpness()
- if(sharp)
- if(slice(sharp, W, user))
- return 1
+ if(user.a_intent != INTENT_DISARM)
+ var/sharp = W.get_sharpness()
+ return sharp && slice(sharp, W, user)
else
..()
@@ -338,26 +340,78 @@ All foods are distributed among various categories. Use common sense.
/// All the food items that can store an item inside itself, like bread or cake.
/obj/item/reagent_containers/food/snacks/store
w_class = WEIGHT_CLASS_NORMAL
- var/stored_item = 0
+ /// If an item has been stored in the food
+ var/stored_item = FALSE
+ /// The amount of volume the food has on creation
+ var/volume_on_creation = 0
+ /// Allows someone to bypass the small weight class requirement, so they can put whatever they want into a slice of bread
+ var/bypass_weight_limit = FALSE
+
+/obj/item/reagent_containers/food/snacks/store/Initialize()
+ . = ..()
+ if(reagents?.total_volume)
+ volume_on_creation = reagents.total_volume
/obj/item/reagent_containers/food/snacks/store/attackby(obj/item/W, mob/user, params)
..()
- if(W.w_class <= WEIGHT_CLASS_SMALL & !istype(W, /obj/item/reagent_containers/food/snacks)) //can't slip snacks inside, they're used for custom foods.
- if(W.get_sharpness())
- return 0
+ if(istype(W, /obj/item/reagent_containers/food/snacks)) //can't slip snacks inside, they're used for custom foods.
+ return FALSE
+
+ if((bypass_weight_limit || W.w_class <= WEIGHT_CLASS_SMALL))
+ if(W.get_sharpness() && user.a_intent != INTENT_DISARM)
+ return FALSE
+ if(istype(W, /obj/item/storage))
+ return FALSE
if(stored_item)
- return 0
+ return FALSE
if(!iscarbon(user))
- return 0
+ return FALSE
if(contents.len >= 20)
to_chat(user, "[src] is full.")
- return 0
+ return FALSE
+ user.visible_message("[user.name] begins inserting [W] into [src].", \
+ "You start to insert the [W] into \the [src].")
+ if(!do_after(user, 1.5 SECONDS, target = src))
+ return FALSE
to_chat(user, "You slip [W] inside [src].")
user.transferItemToLoc(W, src)
+ log_message("[key_name(user)] inserted [W.name] into [src.name] at [AREACOORD(src)]", LOG_ATTACK)
add_fingerprint(user)
contents += W
- stored_item = 1
- return 1 // no afterattack here
+ stored_item = TRUE
+ return TRUE // no afterattack here
+
+/obj/item/reagent_containers/food/snacks/store/attack(mob/living/carbon/M, mob/living/carbon/user, def_zone)
+ if(!..())
+ return
+ /// What are the odds we eat glass? - [Bitecount / Max number of bites] * 100
+ var/bad_chance_of_discovery = (bitecount / (volume_on_creation / bitesize))*100 //the closer you get to finishing it, the higher the chance you bite into it
+ /// What are the odds we see the glass but don't bite it? - ([Bitecount / Max number of bites] * 100) - 50
+ var/good_chance_of_discovery = bad_chance_of_discovery - 50 //the closer you get to finishing it, the more likely you can see what is in it
+ /// We've found the item, and plan on remove it
+ var/discovered = FALSE
+
+ if(stored_item)
+ for(var/obj/item/I in contents)
+ if(istype(I, /obj/item/reagent_containers/food/snacks))
+ return FALSE
+ if(prob(good_chance_of_discovery))
+ discovered = TRUE
+ to_chat(M, "It feels like there's something in this [src.name]...!")
+
+ else if(prob(bad_chance_of_discovery))
+ log_message("[key_name(user)] just fed [key_name(M)] a/an [I.name] which was hidden in [src.name] at [AREACOORD(src)]", LOG_ATTACK)
+ discovered = I.on_accidental_consumption(M, user, src)
+
+ if(!QDELETED(I) && discovered)
+ contents -= I
+ stored_item = FALSE
+ if(M.put_in_hands(I)) //the moment when you slowly pull out whatever you just bit into in your food
+ to_chat(M, "You slowly pull [I] out of \the [src].")
+ else
+ to_chat(M, "[I] falls out of \the [src].")
+
+ return FALSE
/obj/item/reagent_containers/food/snacks/MouseDrop(atom/over)
var/turf/T = get_turf(src)
@@ -366,4 +420,3 @@ All foods are distributed among various categories. Use common sense.
TB.MouseDrop(over)
else
return ..()
-
diff --git a/code/modules/projectiles/ammunition/_ammunition.dm b/code/modules/projectiles/ammunition/_ammunition.dm
index 9d303245688..039fd3a9769 100644
--- a/code/modules/projectiles/ammunition/_ammunition.dm
+++ b/code/modules/projectiles/ammunition/_ammunition.dm
@@ -46,6 +46,25 @@
icon_state = "[initial(icon_state)][BB ? "-live" : ""]"
desc = "[initial(desc)][BB ? "" : " This one is spent."]"
+/*
+ * On accidental consumption, 'spend' the ammo, and add in some gunpowder
+ */
+/obj/item/ammo_casing/on_accidental_consumption(mob/living/carbon/M, mob/living/carbon/user, obj/item/source_item, discover_after = TRUE)
+ if(BB)
+ BB = null
+ update_icon()
+ var/obj/item/reagent_containers/food/snacks/S = source_item
+ if(istype(S))
+ if(S.reagents)
+ S.reagents.add_reagent(/datum/reagent/gunpowder, S.reagents.total_volume*(2/3))
+ if(S.tastes?.len)
+ S.tastes += "salt"
+ S.tastes["salt"] = 3
+
+ M.reagents?.add_reagent(/datum/reagent/gunpowder, 3)
+
+ return ..()
+
//proc to magically refill a casing with a new projectile
/obj/item/ammo_casing/proc/newshot() //For energy weapons, syringe gun, shotgun shells and wands (!).
if(!BB)
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index fea4aed8016..fb2e586244f 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -63,6 +63,17 @@
return 0
return 1
+/*
+ * On accidental consumption, transfer a portion of the reagents to the eater and the item it's in, then continue to the base proc (to deal with shattering glass containers)
+ */
+/obj/item/reagent_containers/on_accidental_consumption(mob/living/carbon/M, mob/living/carbon/user, obj/item/source_item, discover_after = TRUE)
+ M.losebreath += 2
+ reagents?.trans_to(M, min(15, reagents.total_volume / rand(5,10)), transfered_by = user, method = INGEST)
+ if(source_item?.reagents)
+ reagents.trans_to(source_item, min(source_item.reagents.total_volume / 2, reagents.total_volume / 5), transfered_by = user, method = TOUCH)
+
+ return ..()
+
/obj/item/reagent_containers/ex_act()
if(reagents)
for(var/datum/reagent/R in reagents.reagent_list)
diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm
index b7286eaa239..f8c40b7f945 100755
--- a/code/modules/reagents/reagent_containers/glass.dm
+++ b/code/modules/reagents/reagent_containers/glass.dm
@@ -108,6 +108,13 @@
return
..()
+/*
+ * On accidental consumption, make sure the container is partially glass, and continue to the reagent_container proc
+ */
+/obj/item/reagent_containers/glass/on_accidental_consumption(mob/living/carbon/M, mob/living/carbon/user, obj/item/source_item, discover_after = TRUE)
+ if(!custom_materials)
+ custom_materials = list(SSmaterials.GetMaterialRef(/datum/material/glass) = 5) //sets it to glass so, later on, it gets picked up by the glass catch (hope it doesn't 'break' things lol)
+ return ..()
/obj/item/reagent_containers/glass/beaker
name = "beaker"
diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm
index 1ae0c2442a9..1766949e89d 100644
--- a/code/modules/reagents/reagent_containers/pill.dm
+++ b/code/modules/reagents/reagent_containers/pill.dm
@@ -73,6 +73,18 @@
reagents.trans_to(target, reagents.total_volume, transfered_by = user)
qdel(src)
+/*
+ * On accidental consumption, consume the pill
+ */
+/obj/item/reagent_containers/pill/on_accidental_consumption(mob/living/carbon/M, mob/living/carbon/user, obj/item/source_item, discover_after = FALSE)
+ to_chat(M, "You swallow something small. Was that in \the [source_item]?")
+ if(reagents?.total_volume)
+ reagents.trans_to(M, reagents.total_volume, transfered_by = user, method = INGEST)
+
+ source_item?.contents -= src
+ qdel(src)
+ return discover_after
+
/obj/item/reagent_containers/pill/tox
name = "toxins pill"
desc = "Highly toxic."
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index 53c6e2abb18..38bddb8e3b8 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -155,6 +155,17 @@
mode = SYRINGE_DRAW
update_icon()
+/*
+ * On accidental consumption, inject the eater with 2/3rd of the syringe and reveal it
+ */
+/obj/item/reagent_containers/syringe/on_accidental_consumption(mob/living/carbon/M, mob/living/carbon/user, obj/item/source_item, discover_after = TRUE)
+ to_chat(M, "There's a syringe in \the [source_item]!!")
+ M.apply_damage(5, BRUTE, BODY_ZONE_HEAD)
+ if(reagents?.total_volume)
+ reagents.trans_to(M, round(reagents.total_volume*(2/3)), transfered_by = user, method = INJECT)
+
+ return discover_after
+
/obj/item/reagent_containers/syringe/update_icon_state()
var/rounded_vol = get_rounded_vol()
icon_state = "[rounded_vol]"
diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm
index 2c22fc5bdb0..edce458296d 100644
--- a/code/modules/surgery/organs/organ_internal.dm
+++ b/code/modules/surgery/organs/organ_internal.dm
@@ -126,6 +126,48 @@
/obj/item/organ/proc/OnEatFrom(eater, feeder)
useable = FALSE //You can't use it anymore after eating it you spaztic
+/*
+ * On accidental consumption, cause organ damage and check if they like eating organs
+ */
+/obj/item/organ/on_accidental_consumption(mob/living/carbon/M, mob/living/carbon/user, obj/item/source_item, discover_after = TRUE)
+ if(organ_flags & ORGAN_SYNTHETIC)
+ return ..()
+
+ if(organ_flags & ORGAN_FROZEN)
+ return TRUE
+
+ applyOrganDamage(25)
+ OnEatFrom(M, user)
+ if(istype(src, /obj/item/organ/brain)) //brain takes some extra damage
+ applyOrganDamage(25)
+ if(!iszombie(M)) //brains...
+ M.adjust_disgust(50)
+ else if(istype(src, /obj/item/organ/heart)) //heart makes a puddle of blood
+ M.add_splatter_floor(get_turf(src))
+
+ var/obj/item/reagent_containers/food/snacks/S = source_item
+ if(S?.tastes?.len && istype(S))
+ S.tastes += "meat"
+ S.tastes["meat"] = 3
+
+ if(organ_flags & ORGAN_EDIBLE)
+ var/datum/component/edible/EC = src.GetComponent(/datum/component/edible)
+ EC.checkLiked(1, M)
+
+ //people who like gross food or are voracious (voracious people wouldn't even notice)
+ if(((M.dna.species.liked_food & GROSS) && (M.dna.species.liked_food & MEAT)) || M.has_quirk(/datum/quirk/voracious))
+ M.visible_message("[M] looks like [M.p_theyve()] just bitten into something strange.", \
+ "Huh, did I just bite into a [name]?")
+ else
+ M.visible_message("[M] looks like [M.p_theyve()] just bitten into something awful!", \
+ "Ew!! Did I just bite into \a [name]?!")
+
+ if((damage >= maxHealth) && !istype(src, /obj/item/organ/brain)) //don't qdel brains
+ discover_after = FALSE
+ qdel(src) //oops, all gone
+
+ return discover_after
+
/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.