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.