diff --git a/code/__DEFINES/reagents.dm b/code/__DEFINES/reagents.dm index 58db74fa044..508080183bc 100644 --- a/code/__DEFINES/reagents.dm +++ b/code/__DEFINES/reagents.dm @@ -27,8 +27,8 @@ //Special properties ///If the holder is a sealed container - Used if you don't want reagent contents boiling out (plasma, specifically, in which case it only bursts out when at ignition temperatures) #define SEALED_CONTAINER (1<<10) -/// Prevents spilling and splashing but does prevent pouring and drinking reagents like the badly named spillable var. -#define SMART_CAP (1<<11) +/// Prevents splashing for open reagent containers +#define NO_SPLASH (1<<11) // Is an open container for all intents and purposes. #define OPENCONTAINER (REFILLABLE | DRAINABLE | TRANSPARENT) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 6070dd862d5..879732717b1 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -1176,8 +1176,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai ///generic atom traits /// Trait from [/datum/element/rust]. Its rusty and should be applying a special overlay to denote this. #define TRAIT_RUSTY "rust_trait" -/// Stops someone from splashing their reagent_container on an object with this trait -#define TRAIT_DO_NOT_SPLASH "do_not_splash" /// Marks an atom when the cleaning of it is first started, so that the cleaning overlay doesn't get removed prematurely #define TRAIT_CURRENTLY_CLEANING "currently_cleaning" /// Objects with this trait are deleted if they fall into chasms, rather than entering abstract storage diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index b26f22b5483..757a6238be1 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -7,25 +7,24 @@ GLOBAL_LIST_INIT(traits_by_type, list( /atom = list( - "TRAIT_AI_PAUSED" = TRAIT_AI_PAUSED, "TRAIT_AI_MOVEMENT_HALTED" = TRAIT_AI_MOVEMENT_HALTED, + "TRAIT_AI_PAUSED" = TRAIT_AI_PAUSED, "TRAIT_BANNED_FROM_CARGO_SHUTTLE" = TRAIT_BANNED_FROM_CARGO_SHUTTLE, "TRAIT_BEAUTY_APPLIED" = TRAIT_BEAUTY_APPLIED, "TRAIT_BEING_SHOCKED" = TRAIT_BEING_SHOCKED, "TRAIT_CATCH_AND_RELEASE" = TRAIT_CATCH_AND_RELEASE, - "TRAIT_COMMISSIONED" = TRAIT_COMMISSIONED, "TRAIT_CLIMBABLE" = TRAIT_CLIMBABLE, + "TRAIT_COMMISSIONED" = TRAIT_COMMISSIONED, "TRAIT_CURRENTLY_CLEANING" = TRAIT_CURRENTLY_CLEANING, - "TRAIT_DO_NOT_SPLASH" = TRAIT_DO_NOT_SPLASH, "TRAIT_DRIED" = TRAIT_DRIED, "TRAIT_DRYABLE" = TRAIT_DRYABLE, "TRAIT_ELEVATING_OBJECT" = TRAIT_ELEVATING_OBJECT, "TRAIT_FISHING_SPOT" = TRAIT_FISHING_SPOT, "TRAIT_FOOD_CHEF_MADE" = TRAIT_FOOD_CHEF_MADE, "TRAIT_FOOD_FRIED" = TRAIT_FOOD_FRIED, + "TRAIT_FOOD_SILVER" = TRAIT_FOOD_SILVER, "TRAIT_GOT_DAMPENED" = TRAIT_GOT_DAMPENED, "TRAIT_INGREDIENTS_HOLDER" = TRAIT_INGREDIENTS_HOLDER, - "TRAIT_FOOD_SILVER" = TRAIT_FOOD_SILVER, "TRAIT_KEEP_TOGETHER" = TRAIT_KEEP_TOGETHER, "TRAIT_LIGHTING_DEBUGGED" = TRAIT_LIGHTING_DEBUGGED, "TRAIT_MESSAGE_IN_A_BOTTLE_LOCATION" = TRAIT_MESSAGE_IN_A_BOTTLE_LOCATION, diff --git a/code/datums/elements/envenomable_casing.dm b/code/datums/elements/envenomable_casing.dm index bb4890bfa9e..0d09953b30b 100644 --- a/code/datums/elements/envenomable_casing.dm +++ b/code/datums/elements/envenomable_casing.dm @@ -25,23 +25,21 @@ ///signal called on the parent attacking an item /datum/element/envenomable_casing/proc/handle_interaction(obj/item/ammo_casing/casing, mob/user, atom/target, list/modifiers) SIGNAL_HANDLER - if(!is_reagent_container(target)) + + if(!target.is_open_container()) return NONE - var/obj/item/reagent_containers/venom_container = target if(!casing.loaded_projectile) user.balloon_alert(user, "casing is already spent!") return ITEM_INTERACT_BLOCKING - if(!(venom_container.reagent_flags & OPENCONTAINER)) - user.balloon_alert(user, "open the container!") - return ITEM_INTERACT_BLOCKING - var/datum/reagent/venom_applied = venom_container.reagents.get_master_reagent() + + var/datum/reagent/venom_applied = target.reagents.get_master_reagent() if(!venom_applied) return ITEM_INTERACT_BLOCKING var/amount_applied = min(venom_applied.volume, amount_allowed) casing.loaded_projectile.AddElement(/datum/element/venomous, venom_applied.type, amount_applied) to_chat(user, span_notice("You coat [casing] in [venom_applied].")) - venom_container.reagents.remove_reagent(venom_applied.type, amount_applied) + target.reagents.remove_reagent(venom_applied.type, amount_applied) ///stops further poison application UnregisterSignal(casing, COMSIG_ITEM_INTERACTING_WITH_ATOM) RegisterSignal(casing, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine_after_dip), override = TRUE) diff --git a/code/datums/elements/food/dunkable.dm b/code/datums/elements/food/dunkable.dm index baf4be2a813..fa2a9cbbc1c 100644 --- a/code/datums/elements/food/dunkable.dm +++ b/code/datums/elements/food/dunkable.dm @@ -16,21 +16,19 @@ . = ..() UnregisterSignal(target, COMSIG_ITEM_INTERACTING_WITH_ATOM) -/datum/element/dunkable/proc/get_dunked(datum/source, mob/user, atom/target, params) +/datum/element/dunkable/proc/get_dunked(obj/item/source, mob/user, atom/target, params) SIGNAL_HANDLER - var/obj/item/reagent_containers/container = target // the container we're trying to dunk into - if(istype(container) && (container.reagent_flags & DUNKABLE)) // container should be a valid target for dunking - if(!container.is_drainable()) - to_chat(user, span_warning("[container] is unable to be dunked in!")) + if(target.reagents?.flags & DUNKABLE) // container should be a valid target for dunking + if(!target.is_drainable()) + to_chat(user, span_warning("[target] is unable to be dunked in!")) return ITEM_INTERACT_BLOCKING - var/obj/item/I = source // the item that has the dunkable element - if(container.reagents.trans_to(I, dunk_amount, transferred_by = user)) //if reagents were transferred, show the message - to_chat(user, span_notice("You dunk \the [I] into \the [container].")) + if(target.reagents.trans_to(source, dunk_amount, transferred_by = user)) //if reagents were transferred, show the message + to_chat(user, span_notice("You dunk \the [target] into \the [target].")) return ITEM_INTERACT_SUCCESS - if(!container.reagents.total_volume) - to_chat(user, span_warning("[container] is empty!")) + if(!target.reagents.total_volume) + to_chat(user, span_warning("[target] is empty!")) else - to_chat(user, span_warning("[I] is full!")) + to_chat(user, span_warning("[source] is full!")) return ITEM_INTERACT_BLOCKING return NONE diff --git a/code/game/atom/_atom.dm b/code/game/atom/_atom.dm index ff3093a0951..ce77ca09ada 100644 --- a/code/game/atom/_atom.dm +++ b/code/game/atom/_atom.dm @@ -394,11 +394,11 @@ return is_refillable() && is_drainable() /// Is this atom injectable into other atoms -/atom/proc/is_injectable(mob/user, allowmobs = TRUE) +/atom/proc/is_injectable() return reagents && (reagents.flags & (INJECTABLE | REFILLABLE)) /// Can we draw from this atom with an injectable atom -/atom/proc/is_drawable(mob/user, allowmobs = TRUE) +/atom/proc/is_drawable() return reagents && (reagents.flags & (DRAWABLE | DRAINABLE)) /// Can this atoms reagents be refilled diff --git a/code/game/objects/items/drug_items.dm b/code/game/objects/items/drug_items.dm index 68d6c6b546f..bea5cec30fa 100644 --- a/code/game/objects/items/drug_items.dm +++ b/code/game/objects/items/drug_items.dm @@ -42,8 +42,7 @@ icon_state = "blastoff_ampoule" base_icon_state = "blastoff_ampoule" volume = 20 - reagent_flags = TRANSPARENT - spillable = FALSE + initial_reagent_flags = TRANSPARENT list_reagents = list(/datum/reagent/drug/blastoff = 10) reagent_consumption_method = INHALE consumption_sound = 'sound/effects/spray2.ogg' @@ -52,16 +51,15 @@ . = ..() if(!reagents.total_volume) icon_state = "[base_icon_state]_empty" - else if(spillable) + else if(is_open_container()) icon_state = "[base_icon_state]_open" else icon_state = base_icon_state /obj/item/reagent_containers/cup/blastoff_ampoule/attack_self(mob/user) - if(!user.can_perform_action(src, NEED_DEXTERITY) || spillable) + if(!user.can_perform_action(src, NEED_DEXTERITY) || is_open_container()) return ..() - reagent_flags |= OPENCONTAINER - spillable = TRUE + add_container_flags(OPENCONTAINER) playsound(src, 'sound/items/ampoule_snap.ogg', 40) update_appearance() @@ -74,8 +72,7 @@ var/obj/item/shard/ampoule_shard = new(drop_location()) playsound(src, SFX_SHATTER, 40, TRUE) transfer_fingerprints_to(ampoule_shard) - spillable = TRUE - SplashReagents(hit_atom, throwingdatum) + splash_reagents(hit_atom, throwingdatum?.get_thrower(), was_thrown = TRUE, allow_closed_splash = FALSE) qdel(src) hit_atom.Bumped(ampoule_shard) diff --git a/code/game/objects/items/food/salad.dm b/code/game/objects/items/food/salad.dm index 58e40439d15..c95a284e8f5 100644 --- a/code/game/objects/items/food/salad.dm +++ b/code/game/objects/items/food/salad.dm @@ -181,7 +181,7 @@ icon = 'icons/obj/food/soupsalad.dmi' icon_state = "bowl" base_icon_state = "bowl" - reagent_flags = OPENCONTAINER | DUNKABLE + initial_reagent_flags = OPENCONTAINER | DUNKABLE custom_materials = list(/datum/material/glass = SMALL_MATERIAL_AMOUNT*5) w_class = WEIGHT_CLASS_NORMAL custom_price = PAYCHECK_CREW * 0.6 diff --git a/code/game/objects/items/robot/items/hypo.dm b/code/game/objects/items/robot/items/hypo.dm index b6d4bf00f41..c68d4e0bb26 100644 --- a/code/game/objects/items/robot/items/hypo.dm +++ b/code/game/objects/items/robot/items/hypo.dm @@ -175,32 +175,35 @@ cyborg.cell.use(charge_cost) stored_reagents.add_reagent(reagent_to_regen, 5, reagtemp = dispensed_temperature, no_react = TRUE) -/obj/item/reagent_containers/borghypo/attack(mob/living/carbon/injectee, mob/user) - if(!istype(injectee)) - return +/obj/item/reagent_containers/borghypo/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(!iscarbon(interacting_with)) + return NONE + var/mob/living/carbon/injectee = interacting_with if(!selected_reagent) balloon_alert(user, "no reagent selected!") - return + return ITEM_INTERACT_BLOCKING if(!stored_reagents.has_reagent(selected_reagent.type, amount_per_transfer_from_this)) balloon_alert(user, "not enough [selected_reagent.name]!") - return + return ITEM_INTERACT_BLOCKING - if(injectee.try_inject(user, user.zone_selected, injection_flags = INJECT_TRY_SHOW_ERROR_MESSAGE | (bypass_protection ? INJECT_CHECK_PENETRATE_THICK : 0))) - // This is the in-between where we're storing the reagent we're going to inject the injectee with - // because we cannot specify a singular reagent to transfer in trans_to - var/datum/reagents/hypospray_injector = new() - stored_reagents.remove_reagent(selected_reagent.type, amount_per_transfer_from_this) - hypospray_injector.add_reagent(selected_reagent.type, amount_per_transfer_from_this, reagtemp = dispensed_temperature, no_react = TRUE) - - to_chat(injectee, span_warning("You feel a tiny prick!")) - to_chat(user, span_notice("You inject [injectee] with the injector ([selected_reagent.name]).")) - - if(injectee.reagents) - hypospray_injector.trans_to(injectee, amount_per_transfer_from_this, transferred_by = user, methods = INJECT) - balloon_alert(user, "[amount_per_transfer_from_this] unit\s injected") - log_combat(user, injectee, "injected", src, "(CHEMICALS: [selected_reagent])") - else + if(!injectee.try_inject(user, user.zone_selected, injection_flags = INJECT_TRY_SHOW_ERROR_MESSAGE | (bypass_protection ? INJECT_CHECK_PENETRATE_THICK : 0))) balloon_alert(user, "[injectee.parse_zone_with_bodypart(user.zone_selected)] is blocked!") + return ITEM_INTERACT_BLOCKING + + // This is the in-between where we're storing the reagent we're going to inject the injectee with + // because we cannot specify a singular reagent to transfer in trans_to + var/datum/reagents/hypospray_injector = new() + stored_reagents.remove_reagent(selected_reagent.type, amount_per_transfer_from_this) + hypospray_injector.add_reagent(selected_reagent.type, amount_per_transfer_from_this, reagtemp = dispensed_temperature, no_react = TRUE) + + to_chat(injectee, span_warning("You feel a tiny prick!")) + to_chat(user, span_notice("You inject [injectee] with the injector ([selected_reagent.name]).")) + + if(injectee.reagents) + hypospray_injector.trans_to(injectee, amount_per_transfer_from_this, transferred_by = user, methods = INJECT) + balloon_alert(user, "[amount_per_transfer_from_this] unit\s injected") + log_combat(user, injectee, "injected", src, "(CHEMICALS: [selected_reagent])") + return ITEM_INTERACT_SUCCESS /obj/item/reagent_containers/borghypo/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) @@ -394,9 +397,6 @@ data["apparatusHasItem"] = !isnull(beverage_apparatus.stored) return data -/obj/item/reagent_containers/borghypo/borgshaker/attack(mob/M, mob/user) - return //Can't inject stuff with a shaker, can we? //not with that attitude - /obj/item/reagent_containers/borghypo/borgshaker/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!interacting_with.is_refillable()) return NONE @@ -456,9 +456,6 @@ data["selectedReagent"] = selected_reagent?.name return data -/obj/item/reagent_containers/borghypo/condiment_synthesizer/attack(mob/M, mob/user) - return - /obj/item/reagent_containers/borghypo/condiment_synthesizer/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!interacting_with.is_refillable()) return NONE diff --git a/code/game/objects/items/robot/items/storage.dm b/code/game/objects/items/robot/items/storage.dm index 88349a65f4d..a9e94b7c0d9 100644 --- a/code/game/objects/items/robot/items/storage.dm +++ b/code/game/objects/items/robot/items/storage.dm @@ -118,9 +118,6 @@ stored = new /obj/item/reagent_containers/cup/beaker/large(src) /obj/item/borg/apparatus/beaker/Destroy() - if(stored) - var/obj/item/reagent_containers/reagent_container = stored - reagent_container.SplashReagents(get_turf(src)) QDEL_NULL(stored) return ..() diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm index 0b97caa3caa..a704d49a7f3 100644 --- a/code/game/objects/items/tanks/watertank.dm +++ b/code/game/objects/items/tanks/watertank.dm @@ -396,8 +396,7 @@ /// How much to inject per second var/injection_amount = 0.5 amount_per_transfer_from_this = 5 - reagent_flags = OPENCONTAINER - spillable = FALSE + initial_reagent_flags = TRANSPARENT possible_transfer_amounts = list(5,10,15) fill_icon_thresholds = list(0, 15, 60) fill_icon_state = "backpack" diff --git a/code/game/objects/structures/cannons/cannon.dm b/code/game/objects/structures/cannons/cannon.dm index 1261ae6e8a3..4c44ae646a8 100644 --- a/code/game/objects/structures/cannons/cannon.dm +++ b/code/game/objects/structures/cannons/cannon.dm @@ -84,7 +84,7 @@ else if(is_reagent_container(used_item)) var/obj/item/reagent_containers/powder_keg = used_item - if(!(powder_keg.reagent_flags & OPENCONTAINER)) + if(!powder_keg.is_open_container()) return ..() if(istype(powder_keg, /obj/item/rag)) return ..() diff --git a/code/modules/antagonists/heretic/items/eldritch_flask.dm b/code/modules/antagonists/heretic/items/eldritch_flask.dm index fc0dd054497..101da331241 100644 --- a/code/modules/antagonists/heretic/items/eldritch_flask.dm +++ b/code/modules/antagonists/heretic/items/eldritch_flask.dm @@ -15,7 +15,7 @@ icon_state = "phylactery" base_icon_state = "phylactery" has_variable_transfer_amount = FALSE - reagent_flags = OPENCONTAINER | DUNKABLE | TRANSPARENT + initial_reagent_flags = OPENCONTAINER | DUNKABLE | TRANSPARENT volume = 10 /// Cooldown before you can steal blood again COOLDOWN_DECLARE(drain_cooldown) diff --git a/code/modules/fishing/aquarium/aquarium_kit.dm b/code/modules/fishing/aquarium/aquarium_kit.dm index 1360cc089d4..9a248c8b286 100644 --- a/code/modules/fishing/aquarium/aquarium_kit.dm +++ b/code/modules/fishing/aquarium/aquarium_kit.dm @@ -5,11 +5,10 @@ icon = 'icons/obj/aquarium/supplies.dmi' icon_state = "fish_feed" w_class = WEIGHT_CLASS_TINY - spillable = FALSE volume = 5 amount_per_transfer_from_this = 2.5 has_variable_transfer_amount = FALSE - reagent_flags = OPENCONTAINER + initial_reagent_flags = TRANSPARENT reagent_container_liquid_sound = null list_reagents = list(/obj/item/fish::food = 2.5) //Default fish diet gulp_size = 1 diff --git a/code/modules/food_and_drinks/machinery/stove.dm b/code/modules/food_and_drinks/machinery/stove.dm index 5d2b0f808dd..94aa16a9da2 100644 --- a/code/modules/food_and_drinks/machinery/stove.dm +++ b/code/modules/food_and_drinks/machinery/stove.dm @@ -34,7 +34,7 @@ volume = 200 possible_transfer_amounts = list(20, 50, 100, 200) amount_per_transfer_from_this = 50 - reagent_flags = REFILLABLE | DRAINABLE + initial_reagent_flags = REFILLABLE | DRAINABLE custom_materials = list(/datum/material/iron =SHEET_MATERIAL_AMOUNT * 2.5) w_class = WEIGHT_CLASS_BULKY custom_price = PAYCHECK_LOWER * 8 @@ -142,36 +142,36 @@ update_appearance(UPDATE_OVERLAYS) return TRUE -/obj/item/reagent_containers/cup/soup_pot/attackby(obj/item/attacking_item, mob/user, list/modifiers, list/attack_modifiers) +/obj/item/reagent_containers/cup/soup_pot/item_interaction(mob/living/user, obj/item/item, list/modifiers) . = ..() - if(.) - return - - if(!can_add_ingredient(attacking_item)) - return FALSE + if(. & ITEM_INTERACT_ANY_BLOCKER) + return . + if(item.is_open_container()) + // (assuming they want to pour rather than add the container itself) + // allow interaction to fall through to reagent container coed + return NONE + if(!can_add_ingredient(item)) + return ITEM_INTERACT_BLOCKING // Too many ingredients if(LAZYLEN(added_ingredients) >= max_ingredients) balloon_alert(user, "too many ingredients!") - return TRUE - if(!user.transferItemToLoc(attacking_item, src)) + return ITEM_INTERACT_BLOCKING + if(!user.transferItemToLoc(item, src)) balloon_alert(user, "can't add that!") - return TRUE + return ITEM_INTERACT_BLOCKING // Ensures that faceatom works correctly, since we can can often be in another atom's loc (a stove) var/atom/movable/balloon_loc = ismovable(loc) ? loc : src balloon_loc.balloon_alert(user, "ingredient added") user.face_atom(balloon_loc) - LAZYADD(added_ingredients, attacking_item) + LAZYADD(added_ingredients, item) update_appearance(UPDATE_OVERLAYS) - return TRUE + return ITEM_INTERACT_SUCCESS -/obj/item/reagent_containers/cup/soup_pot/item_interaction(mob/living/user, obj/item/item, list/modifiers) - if(LAZYACCESS(modifiers, RIGHT_CLICK)) - return NONE - - return transfer_from_container_to_pot(item, user) +/obj/item/reagent_containers/cup/soup_pot/item_interaction_secondary(mob/living/user, obj/item/tool, list/modifiers) + return transfer_from_container_to_pot(tool, user) /obj/item/reagent_containers/cup/soup_pot/attack_hand_secondary(mob/user, list/modifiers) if(!LAZYLEN(added_ingredients)) diff --git a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm index 0f2be5a8ac1..5ef69e41242 100644 --- a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm +++ b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat.dm @@ -216,7 +216,7 @@ * * atom/lean_target - the target we try to add the spit to */ /mob/living/basic/regal_rat/proc/poison_target(atom/target) - if(isnull(target.reagents) || !target.is_injectable(src, allowmobs = TRUE)) + if(isnull(target.reagents) || !target.is_injectable(src, /*allowmobs = */TRUE)) return FALSE visible_message( diff --git a/code/modules/reagents/chemistry/holder/holder.dm b/code/modules/reagents/chemistry/holder/holder.dm index 13cd0541e87..37dcffec79b 100644 --- a/code/modules/reagents/chemistry/holder/holder.dm +++ b/code/modules/reagents/chemistry/holder/holder.dm @@ -776,10 +776,8 @@ * * coeff - multiplier to be applied on temp diff between param temp and current temp */ /datum/reagents/proc/expose_temperature(temperature, coeff = 0.02) - if(istype(my_atom,/obj/item/reagent_containers)) - var/obj/item/reagent_containers/RCs = my_atom - if(RCs.reagent_flags & NO_REACT) //stasis holders IE cryobeaker - return + if(flags & NO_REACT) //stasis holders IE cryobeaker + return var/temp_delta = (temperature - chem_temp) * coeff if(temp_delta > 0) chem_temp = min(chem_temp + max(temp_delta, 1), temperature) diff --git a/code/modules/reagents/chemistry/machinery/chem_mass_spec.dm b/code/modules/reagents/chemistry/machinery/chem_mass_spec.dm index b868d2423ea..7cf10157aad 100644 --- a/code/modules/reagents/chemistry/machinery/chem_mass_spec.dm +++ b/code/modules/reagents/chemistry/machinery/chem_mass_spec.dm @@ -33,8 +33,6 @@ /obj/machinery/chem_mass_spec/Initialize(mapload) . = ..() - ADD_TRAIT(src, TRAIT_DO_NOT_SPLASH, INNATE_TRAIT) - if(mapload) beaker2 = new /obj/item/reagent_containers/cup/beaker/large(src) diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm index 1e2c94c0646..62b3c70774a 100644 --- a/code/modules/reagents/chemistry/machinery/chem_master.dm +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -507,7 +507,7 @@ var/datum/reagent/master_reagent = reagents.get_master_reagent() if(selected_container == default_container) // Tubes and bottles gain reagent name item_name_default = "[master_reagent.name] [item_name_default]" - if(!(initial(selected_container.reagent_flags) & OPENCONTAINER)) // Closed containers get both reagent name and units in the name + if(!(initial(selected_container.initial_reagent_flags) & OPENCONTAINER)) // Closed containers get both reagent name and units in the name item_name_default = "[master_reagent.name] [item_name_default] ([volume_in_each]u)" var/item_name = tgui_input_text( usr, diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index 30339d1f0dc..02b44330bd4 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -14,8 +14,8 @@ var/list/possible_transfer_amounts = list(5,10,15,20,25,30) /// The maximum amount of reagents this container can hold var/volume = 30 - /// Reagent flags, a few examples being if the container is open or not, if its transparent, if you can inject stuff in and out of the container, and so on - var/reagent_flags + /// The base reagent flags that our reagent datum takes on when created + var/initial_reagent_flags = NONE /// A list of what initial reagents this container should spawn with var/list/list_reagents = null /// The purity of the spawned reagents in list_reagents. Default purity if `null` @@ -74,7 +74,9 @@ . = ..() if(isnum(vol) && vol > 0) volume = vol - create_reagents(volume, reagent_flags) + if(!force) + item_flags |= NOBLUDGEON + create_reagents(volume, initial_reagent_flags) if(spawned_disease) var/datum/disease/F = new spawned_disease() var/list/data = list("viruses"= list(F)) @@ -97,18 +99,16 @@ . = ..() RegisterSignal(reagents, COMSIG_REAGENTS_HOLDER_UPDATED, PROC_REF(on_reagent_change)) -/obj/item/reagent_containers/attack(mob/living/target_mob, mob/living/user, list/modifiers, list/attack_modifiers) - if (!user.combat_mode) - return - return ..() - /obj/item/reagent_containers/proc/add_initial_reagents() if(list_reagents) reagents.add_reagent_list(list_reagents, added_purity = list_reagents_purity) /obj/item/reagent_containers/attack_self(mob/user) + if(reagents.flags & SEALED_CONTAINER) + return TRUE if(has_variable_transfer_amount) change_transfer_amount(user, FORWARD) + return TRUE /obj/item/reagent_containers/attack_self_secondary(mob/user) if(has_variable_transfer_amount) @@ -133,19 +133,16 @@ balloon_alert(user, "transferring [amount_per_transfer_from_this]u") mode_change_message(user) -/obj/item/reagent_containers/pre_attack_secondary(atom/target, mob/living/user, list/modifiers, list/attack_modifiers) - if(HAS_TRAIT(target, TRAIT_DO_NOT_SPLASH)) - return ..() +/obj/item/reagent_containers/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers) if(!user.combat_mode) - return ..() - if (try_splash(user, target)) - return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN - - return ..() + return NONE // non-combat-mode-rmb allows for stuff like opening containers or attacking (bottle breaking) + if(try_splash(user, interacting_with)) + return ITEM_INTERACT_SUCCESS + return NONE /// Tries to splash the target, called when right-clicking with a reagent container. /obj/item/reagent_containers/proc/try_splash(mob/user, atom/target) - if (!spillable || reagent_flags & SMART_CAP) + if (!is_open_container() || (reagents.flags & NO_SPLASH)) return FALSE if (!reagents?.total_volume) @@ -153,7 +150,6 @@ var/punctuation = ismob(target) ? "!" : "." - var/reagent_text user.visible_message( span_danger("[user] splashes the contents of [src] onto [target][punctuation]"), span_danger("You splash the contents of [src] onto [target][punctuation]"), @@ -176,11 +172,8 @@ splash_animation.color = mix_color_from_reagents(reagents.reagent_list) target.flick_overlay_view(splash_animation, 1 SECONDS) - for(var/datum/reagent/reagent as anything in reagents.reagent_list) - reagent_text += "[reagent] ([num2text(reagent.volume)])," - reagents.expose(target, TOUCH) - log_combat(user, target, "splashed", reagent_text) + log_combat(user, target, "splashed", reagents.get_reagent_log_string()) reagents.clear_reagents() return TRUE @@ -188,6 +181,9 @@ /obj/item/reagent_containers/proc/canconsume(mob/eater, mob/user) if(!iscarbon(eater)) return FALSE + if(!reagents || !reagents.total_volume) + to_chat(user, span_warning("[src] is empty!")) + return FALSE var/mob/living/carbon/as_carbon = eater var/covered = "" if(as_carbon.is_mouth_covered(ITEM_SLOT_HEAD)) @@ -200,6 +196,18 @@ return FALSE return TRUE +/// Sets reagent flags to the passed flags outright +/obj/item/reagent_containers/proc/update_container_flags(new_flags) + reagents.flags = new_flags + +/// Adds the passed flags to the current reagent flags +/obj/item/reagent_containers/proc/add_container_flags(new_flags) + reagents.flags |= new_flags + +/// Resets to base flags +/obj/item/reagent_containers/proc/reset_container_flags() + reagents.flags = initial_reagent_flags + /* * 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) */ @@ -214,44 +222,46 @@ /obj/item/reagent_containers/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum, do_splash = TRUE) . = ..() if(do_splash) - SplashReagents(hit_atom, throwingdatum) + splash_reagents(hit_atom, throwingdatum?.get_thrower(), was_thrown = TRUE, allow_closed_splash = FALSE) /obj/item/reagent_containers/proc/bartender_check(atom/target, mob/thrown_by) . = FALSE if(target.CanPass(src, get_dir(target, src)) && thrown_by && HAS_TRAIT(thrown_by, TRAIT_BOOZE_SLIDER)) . = TRUE -/obj/item/reagent_containers/proc/SplashReagents(atom/target, datum/thrownthing/throwingdatum, override_spillable = FALSE) - if(!reagents || !reagents.total_volume || (!spillable && !override_spillable) || reagent_flags & SMART_CAP) +/** + * Attempts to splash the reagents in the container onto the target. + * + * * target - The target to splash the reagents onto. + * * throwingdatum - The throwingdatum behind the throw if the + */ +/obj/item/reagent_containers/proc/splash_reagents(atom/target, mob/splasher, was_thrown = FALSE, allow_closed_splash = FALSE) + if(!reagents || !reagents.total_volume || (!is_open_container() && !allow_closed_splash) || (reagents.flags & NO_SPLASH)) return - var/mob/thrown_by = throwingdatum?.get_thrower() if(ismob(target) && target.reagents) var/splash_multiplier = 1 - if(throwingdatum) + if(was_thrown) splash_multiplier *= (rand(5,10) * 0.1) //Not all of it makes contact with the target + var/turf_splash_multiplier = 1 - splash_multiplier var/mob/M = target var/turf/target_turf = get_turf(target) - var/R target.visible_message(span_danger("[M] is splashed with something!"), \ span_userdanger("[M] is splashed with something!")) - for(var/datum/reagent/A in reagents.reagent_list) - R += "[A.type] ([num2text(A.volume)])," - - if(thrown_by) - log_combat(thrown_by, M, "splashed", R) + if(splasher) + log_combat(splasher, M, "splashed", src, "containing [reagents.get_reagent_log_string()] [was_thrown ? "(thrown)" : ""]") reagents.expose(target, TOUCH, splash_multiplier) - reagents.expose(target_turf, TOUCH, (1 - splash_multiplier)) // 1 - splash_multiplier because it's what didn't hit the target + if(turf_splash_multiplier > 0) + reagents.expose(target_turf, TOUCH, turf_splash_multiplier) // 1 - splash_multiplier because it's what didn't hit the target - else if(throwingdatum && bartender_check(target, thrown_by)) + else if(bartender_check(target, splasher) && was_thrown) visible_message(span_notice("[src] lands onto \the [target] without spilling a single drop.")) return else - if(isturf(target) && reagents.reagent_list.len && thrown_by) - log_combat(thrown_by, target, "splashed (thrown) [english_list(reagents.reagent_list)]", "in [AREACOORD(target)]") - thrown_by.log_message("splashed (thrown) [english_list(reagents.reagent_list)] on [target].", LOG_ATTACK) - message_admins("[ADMIN_LOOKUPFLW(thrown_by)] splashed (thrown) [english_list(reagents.reagent_list)] on [target] in [ADMIN_VERBOSEJMP(target)].") + if(isturf(target) && length(reagents.reagent_list) && splasher) + log_combat(splasher, target, "splashed [english_list(reagents.reagent_list)]", src, "in [AREACOORD(target)] [was_thrown ? "(thrown)" : ""]") + message_admins("[ADMIN_LOOKUPFLW(splasher)] splashed (thrown) [english_list(reagents.reagent_list)] on [target] in [ADMIN_VERBOSEJMP(target)].") visible_message(span_notice("[src] spills its contents all over [target].")) reagents.expose(target, TOUCH) if(QDELETED(src)) @@ -381,3 +391,35 @@ // If consumed in crafting, we should dump contents out before qdeling them. if(!is_type_in_list(src, current_recipe.parts)) reagents.expose(loc, TOUCH) + +/obj/item/reagent_containers/proc/try_refill(atom/target, mob/living/user) + if(!reagents.total_volume) + to_chat(user, span_warning("[src] is empty!")) + return ITEM_INTERACT_BLOCKING + + if(target.reagents.holder_full()) + to_chat(user, span_warning("[target] is full.")) + return ITEM_INTERACT_BLOCKING + + var/trans = round(reagents.trans_to(target, amount_per_transfer_from_this, transferred_by = user), CHEMICAL_VOLUME_ROUNDING) + playsound(target.loc, SFX_LIQUID_POUR, 50, TRUE) + to_chat(user, span_notice("You transfer [trans] unit\s of the solution to [target].")) + SEND_SIGNAL(src, COMSIG_REAGENTS_CUP_TRANSFER_TO, target) + target.update_appearance() + return ITEM_INTERACT_SUCCESS + +/obj/item/reagent_containers/proc/try_drain(atom/target, mob/living/user) + if(!target.reagents.total_volume) + to_chat(user, span_warning("[target] is empty and can't be refilled!")) + return ITEM_INTERACT_BLOCKING + + if(reagents.holder_full()) + to_chat(user, span_warning("[src] is full.")) + return ITEM_INTERACT_BLOCKING + + var/trans = round(target.reagents.trans_to(src, amount_per_transfer_from_this, transferred_by = user), CHEMICAL_VOLUME_ROUNDING) + playsound(target.loc, SFX_LIQUID_POUR, 50, TRUE) + to_chat(user, span_notice("You fill [src] with [trans] unit\s of the contents of [target].")) + SEND_SIGNAL(src, COMSIG_REAGENTS_CUP_TRANSFER_FROM, target) + target.update_appearance() + return ITEM_INTERACT_SUCCESS diff --git a/code/modules/reagents/reagent_containers/chem_pack.dm b/code/modules/reagents/reagent_containers/chem_pack.dm index 98ffa2e596e..abe9d39dab9 100644 --- a/code/modules/reagents/reagent_containers/chem_pack.dm +++ b/code/modules/reagents/reagent_containers/chem_pack.dm @@ -4,43 +4,30 @@ icon = 'icons/obj/medical/bloodpack.dmi' icon_state = "chempack" volume = 100 - reagent_flags = OPENCONTAINER - spillable = TRUE + initial_reagent_flags = OPENCONTAINER obj_flags = UNIQUE_RENAME resistance_flags = ACID_PROOF fill_icon_thresholds = list(10, 20, 30, 40, 50, 60, 70, 80, 90, 100) has_variable_transfer_amount = FALSE interaction_flags_click = NEED_DEXTERITY - /// Whether this has been sealed shut - var/sealed = FALSE /obj/item/reagent_containers/chem_pack/click_alt(mob/living/user) - if(sealed) - balloon_alert(user, "sealed!") + if(reagents.flags & SEALED_CONTAINER) + balloon_alert(user, "already sealed!") return CLICK_ACTION_BLOCKING if(iscarbon(user) && (HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))) to_chat(user, span_warning("Uh... whoops! You accidentally spill the content of the bag onto yourself.")) - SplashReagents(user) + splash_reagents(user, user, allow_closed_splash = TRUE) return CLICK_ACTION_BLOCKING - reagents.flags = NONE - reagent_flags = DRAWABLE | INJECTABLE //To allow for sabotage or ghetto use. - reagents.flags = reagent_flags - spillable = FALSE - sealed = TRUE + update_container_flags(SEALED_CONTAINER | DRAWABLE | INJECTABLE) balloon_alert(user, "sealed") return CLICK_ACTION_SUCCESS /obj/item/reagent_containers/chem_pack/examine() . = ..() - if(sealed) + if(reagents.flags & SEALED_CONTAINER) . += span_notice("The bag is sealed shut.") else . += span_notice("Alt-click to seal it.") - - -/obj/item/reagent_containers/chem_pack/attack_self(mob/user) - if(sealed) - return - ..() diff --git a/code/modules/reagents/reagent_containers/condiment.dm b/code/modules/reagents/reagent_containers/condiment.dm index afb0bf30899..c76a1d0daba 100644 --- a/code/modules/reagents/reagent_containers/condiment.dm +++ b/code/modules/reagents/reagent_containers/condiment.dm @@ -13,7 +13,7 @@ inhand_icon_state = "beer" //Generic held-item sprite until unique ones are made. lefthand_file = 'icons/mob/inhands/items/drinks_lefthand.dmi' righthand_file = 'icons/mob/inhands/items/drinks_righthand.dmi' - reagent_flags = OPENCONTAINER + initial_reagent_flags = OPENCONTAINER obj_flags = UNIQUE_RENAME possible_transfer_amounts = list(1, 5, 10, 15, 20, 25, 30, 50) volume = 50 @@ -40,57 +40,59 @@ user.visible_message(span_suicide("[user] is trying to eat the entire [src]! It looks like [user.p_they()] forgot how food works!")) return OXYLOSS -/obj/item/reagent_containers/condiment/attack(mob/M, mob/user, def_zone) +/obj/item/reagent_containers/condiment/proc/try_eat(atom/target, mob/living/user) + if(!canconsume(target, user)) + return ITEM_INTERACT_BLOCKING - if(!reagents || !reagents.total_volume) - to_chat(user, span_warning("None of [src] left, oh no!")) - return FALSE - - if(!canconsume(M, user)) - return FALSE - - if(M == user) - user.visible_message(span_notice("[user] swallows some of the contents of \the [src]."), \ - span_notice("You swallow some of the contents of \the [src].")) + if(target == user) + user.visible_message( + span_notice("[user] swallows some of the contents of \the [src]."), + span_notice("You swallow some of the contents of \the [src]."), + ) else - M.visible_message(span_warning("[user] attempts to feed [M] from [src]."), \ - span_warning("[user] attempts to feed you from [src].")) - if(!do_after(user, 3 SECONDS, M)) - return + target.visible_message( + span_warning("[user] attempts to feed [target] from [src]."), + span_warning("[user] attempts to feed you from [src]."), + ) + if(!do_after(user, 3 SECONDS, target)) + return ITEM_INTERACT_BLOCKING if(!reagents || !reagents.total_volume) - return // The condiment might be empty after the delay. - M.visible_message(span_warning("[user] fed [M] from [src]."), \ - span_warning("[user] fed you from [src].")) - log_combat(user, M, "fed", reagents.get_reagent_log_string()) - reagents.trans_to(M, 10, transferred_by = user, methods = INGEST) - playsound(M.loc,'sound/items/drink.ogg', rand(10,50), TRUE) - return TRUE + return ITEM_INTERACT_BLOCKING // The condiment might be empty after the delay. + target.visible_message( + span_warning("[user] fed [target] from [src]."), + span_warning("[user] fed you from [src]."), + ) + log_combat(user, target, "fed", reagents.get_reagent_log_string()) + reagents.trans_to(target, 10, transferred_by = user, methods = INGEST) + playsound(target, 'sound/items/drink.ogg', rand(10, 50), TRUE) + return ITEM_INTERACT_SUCCESS /obj/item/reagent_containers/condiment/interact_with_atom(atom/target, mob/living/user, list/modifiers) - if(istype(target, /obj/structure/reagent_dispensers)) //A dispenser. Transfer FROM it TO us. - if(!target.reagents.total_volume) - to_chat(user, span_warning("[target] is empty!")) - return ITEM_INTERACT_BLOCKING - - if(reagents.total_volume >= reagents.maximum_volume) - to_chat(user, span_warning("[src] is full!")) - return ITEM_INTERACT_BLOCKING - - var/trans = round(target.reagents.trans_to(src, amount_per_transfer_from_this, transferred_by = user), CHEMICAL_VOLUME_ROUNDING) - to_chat(user, span_notice("You fill [src] with [trans] units of the contents of [target].")) - return ITEM_INTERACT_SUCCESS + if(!is_open_container()) + return NONE //Something like a glass or a food item. Player probably wants to transfer TO it. - else if(target.is_drainable() || IS_EDIBLE(target)) - if(!reagents.total_volume) - to_chat(user, span_warning("[src] is empty!")) - return ITEM_INTERACT_BLOCKING - if(target.reagents.total_volume >= target.reagents.maximum_volume) - to_chat(user, span_warning("you can't add anymore to [target]!")) - return ITEM_INTERACT_BLOCKING - var/trans = round(reagents.trans_to(target, amount_per_transfer_from_this, transferred_by = user), CHEMICAL_VOLUME_ROUNDING) - to_chat(user, span_notice("You transfer [trans] units of the condiment to [target].")) - return ITEM_INTERACT_SUCCESS + if(target.is_refillable() || IS_EDIBLE(target)) + return try_refill(target, user) + //A dispenser. Transfer FROM it TO us. + if(target.is_drainable()) + return try_drain(target, user) + //Eating directly from the ketchup packet + if(isliving(target)) + return try_eat(target, user) + + return NONE + + +/obj/item/reagent_containers/condiment/interact_with_atom_secondary(atom/target, mob/living/user, list/modifiers) + . = ..() + if(. & ITEM_INTERACT_ANY_BLOCKER) + return . + if(!is_open_container()) + return NONE + //A dispenser. Transfer FROM it TO us. + if(target.is_drainable()) + return try_drain(target, user) return NONE @@ -443,8 +445,8 @@ SHOULD_CALL_PARENT(FALSE) return -/obj/item/reagent_containers/condiment/pack/attack(mob/M, mob/user, def_zone) //Can't feed these to people directly. - return +/obj/item/reagent_containers/condiment/pack/try_eat(atom/target, mob/living/user) + return NONE /obj/item/reagent_containers/condiment/pack/interact_with_atom(atom/target, mob/living/user, list/modifiers) //You can tear the bag open above food to put the condiments on it, obviously. diff --git a/code/modules/reagents/reagent_containers/cooler_jug.dm b/code/modules/reagents/reagent_containers/cooler_jug.dm index 89fc7f1ea2a..8d0b628ceda 100644 --- a/code/modules/reagents/reagent_containers/cooler_jug.dm +++ b/code/modules/reagents/reagent_containers/cooler_jug.dm @@ -5,7 +5,7 @@ icon_state = "cooler_jug" volume = 200 custom_materials = list(/datum/material/plastic = SHEET_MATERIAL_AMOUNT * 4) - reagent_flags = REFILLABLE | DRAINABLE | INJECTABLE | DRAWABLE | TRANSPARENT | SMART_CAP + initial_reagent_flags = REFILLABLE | DRAINABLE | INJECTABLE | DRAWABLE | TRANSPARENT | NO_SPLASH spillable = TRUE has_variable_transfer_amount = FALSE interaction_flags_click = NEED_DEXTERITY diff --git a/code/modules/reagents/reagent_containers/cups/_cup.dm b/code/modules/reagents/reagent_containers/cups/_cup.dm index b66794e41d1..bcc484c25dd 100644 --- a/code/modules/reagents/reagent_containers/cups/_cup.dm +++ b/code/modules/reagents/reagent_containers/cups/_cup.dm @@ -4,8 +4,7 @@ amount_per_transfer_from_this = 10 possible_transfer_amounts = list(5, 10, 15, 20, 25, 30, 50) volume = 50 - reagent_flags = OPENCONTAINER | DUNKABLE - spillable = TRUE + initial_reagent_flags = OPENCONTAINER | DUNKABLE resistance_flags = ACID_PROOF icon_state = "bottle" lefthand_file = 'icons/mob/inhands/items/drinks_lefthand.dmi' @@ -66,152 +65,90 @@ gourmand.adjust_disgust(-5 + -2.5 * fraction) gourmand.add_mood_event("fav_food", /datum/mood_event/favorite_food) -/obj/item/reagent_containers/cup/attack(mob/living/target_mob, mob/living/user, obj/target) +/obj/item/reagent_containers/cup/proc/try_drink(mob/living/target_mob, mob/living/user) if(!canconsume(target_mob, user)) - return - - if(!spillable) - return - - if(!reagents || !reagents.total_volume) - to_chat(user, span_warning("[src] is empty!")) - return - - if(!istype(target_mob)) - return + return ITEM_INTERACT_BLOCKING if(target_mob != user) - target_mob.visible_message(span_danger("[user] attempts to feed [target_mob] something from [src]."), \ - span_userdanger("[user] attempts to feed you something from [src].")) + target_mob.visible_message( + span_danger("[user] attempts to feed [target_mob] something from [src]."), + span_userdanger("[user] attempts to feed you something from [src]."), + ) if(!do_after(user, 3 SECONDS, target_mob)) - return + return ITEM_INTERACT_BLOCKING if(!reagents || !reagents.total_volume) - return // The drink might be empty after the delay, such as by spam-feeding - target_mob.visible_message(span_danger("[user] feeds [target_mob] something from [src]."), \ - span_userdanger("[user] feeds you something from [src].")) + return ITEM_INTERACT_BLOCKING // The drink might be empty after the delay, such as by spam-feeding + target_mob.visible_message( + span_danger("[user] feeds [target_mob] something from [src]."), + span_userdanger("[user] feeds you something from [src]."), + ) log_combat(user, target_mob, "fed", reagents.get_reagent_log_string()) else to_chat(user, span_notice("You swallow a gulp of [src].")) + . = ITEM_INTERACT_SUCCESS SEND_SIGNAL(src, COMSIG_GLASS_DRANK, target_mob, user) var/fraction = min(gulp_size/reagents.total_volume, 1) reagents.trans_to(target_mob, gulp_size, transferred_by = user, methods = reagent_consumption_method) checkLiked(fraction, target_mob) playsound(target_mob.loc, consumption_sound, rand(10,50), TRUE) if(!iscarbon(target_mob)) - return + return . var/mob/living/carbon/carbon_drinker = target_mob var/list/diseases = carbon_drinker.get_static_viruses() if(!LAZYLEN(diseases)) - return + return . var/list/datum/disease/diseases_to_add = list() for(var/datum/disease/malady as anything in diseases) if(malady.spread_flags & DISEASE_SPREAD_CONTACT_FLUIDS) diseases_to_add += malady if(LAZYLEN(diseases_to_add)) AddComponent(/datum/component/infective, diseases_to_add) + return . /obj/item/reagent_containers/cup/interact_with_atom(atom/target, mob/living/user, list/modifiers) - if(!check_allowed_items(target, target_self = TRUE)) - return NONE - if(!spillable) + . = ..() + if(. & ITEM_INTERACT_ANY_BLOCKER) + return . + if(!is_open_container()) return NONE if(target.is_refillable()) //Something like a glass. Player probably wants to transfer TO it. - if(!reagents.total_volume) - to_chat(user, span_warning("[src] is empty!")) - return ITEM_INTERACT_BLOCKING - - if(target.reagents.holder_full()) - to_chat(user, span_warning("[target] is full.")) - return ITEM_INTERACT_BLOCKING - - var/trans = round(reagents.trans_to(target, amount_per_transfer_from_this, transferred_by = user), CHEMICAL_VOLUME_ROUNDING) - playsound(target.loc, SFX_LIQUID_POUR, 50, TRUE) - to_chat(user, span_notice("You transfer [trans] unit\s of the solution to [target].")) - SEND_SIGNAL(src, COMSIG_REAGENTS_CUP_TRANSFER_TO, target) - target.update_appearance() - return ITEM_INTERACT_SUCCESS + return try_refill(target, user) if(target.is_drainable()) //A dispenser. Transfer FROM it TO us. - if(!target.reagents.total_volume) - to_chat(user, span_warning("[target] is empty and can't be refilled!")) - return ITEM_INTERACT_BLOCKING + return try_drain(target, user) - if(reagents.holder_full()) - to_chat(user, span_warning("[src] is full.")) - return ITEM_INTERACT_BLOCKING - - var/trans = round(target.reagents.trans_to(src, amount_per_transfer_from_this, transferred_by = user), CHEMICAL_VOLUME_ROUNDING) - playsound(target.loc, SFX_LIQUID_POUR, 50, TRUE) - to_chat(user, span_notice("You fill [src] with [trans] unit\s of the contents of [target].")) - SEND_SIGNAL(src, COMSIG_REAGENTS_CUP_TRANSFER_FROM, target) - target.update_appearance() - return ITEM_INTERACT_SUCCESS + if(isliving(target)) + return try_drink(target, user) return NONE /obj/item/reagent_containers/cup/interact_with_atom_secondary(atom/target, mob/living/user, list/modifiers) - if(user.combat_mode) - return NONE - if(!check_allowed_items(target, target_self = TRUE)) - return NONE - if(!spillable) + . = ..() + if(. & ITEM_INTERACT_ANY_BLOCKER) + return . + if(!is_open_container()) return NONE if(target.is_drainable()) //A dispenser. Transfer FROM it TO us. - if(!target.reagents.total_volume) - to_chat(user, span_warning("[target] is empty!")) - return ITEM_INTERACT_BLOCKING - - if(reagents.holder_full()) - to_chat(user, span_warning("[src] is full.")) - return ITEM_INTERACT_BLOCKING - - var/trans = round(target.reagents.trans_to(src, amount_per_transfer_from_this, transferred_by = user), CHEMICAL_VOLUME_ROUNDING) - playsound(target.loc, SFX_LIQUID_POUR, 50, TRUE) - to_chat(user, span_notice("You fill [src] with [trans] unit\s of the contents of [target].")) - SEND_SIGNAL(src, COMSIG_REAGENTS_CUP_TRANSFER_FROM, target) - target.update_appearance() - return ITEM_INTERACT_SUCCESS + return try_drain(target, user) return NONE -/obj/item/reagent_containers/cup/attackby(obj/item/attacking_item, mob/user, list/modifiers, list/attack_modifiers) - var/hotness = attacking_item.get_temperature() - if(hotness && reagents) - reagents.expose_temperature(hotness) - to_chat(user, span_notice("You heat [name] with [attacking_item]!")) - return TRUE - - //Cooling method - if(istype(attacking_item, /obj/item/extinguisher)) - var/obj/item/extinguisher/extinguisher = attacking_item - if(extinguisher.safety) - return TRUE - if (extinguisher.reagents.total_volume < 1) - to_chat(user, span_warning("\The [extinguisher] is empty!")) - return TRUE - var/cooling = (0 - reagents.chem_temp) * extinguisher.cooling_power * 2 - reagents.expose_temperature(cooling) - to_chat(user, span_notice("You cool \the [src] with the [attacking_item]!")) - playsound(loc, 'sound/effects/extinguish.ogg', 75, TRUE, -3) - extinguisher.reagents.remove_all(1) - return TRUE - - if(istype(attacking_item, /obj/item/food/egg)) //breaking eggs - var/obj/item/food/egg/attacking_egg = attacking_item - if(!reagents) - return TRUE +/obj/item/reagent_containers/cup/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(!is_open_container()) + return NONE + if(istype(tool, /obj/item/food/egg)) //breaking eggs if(reagents.holder_full()) to_chat(user, span_notice("[src] is full.")) - else - to_chat(user, span_notice("You break [attacking_egg] in [src].")) - attacking_egg.reagents.trans_to(src, attacking_egg.reagents.total_volume, transferred_by = user) - qdel(attacking_egg) - return TRUE + return ITEM_INTERACT_BLOCKING + to_chat(user, span_notice("You break [tool] in [src].")) + tool.reagents.trans_to(src, tool.reagents.total_volume, transferred_by = user) + qdel(tool) + return ITEM_INTERACT_SUCCESS - return ..() + return NONE /* * On accidental consumption, make sure the container is partially glass, and continue to the reagent_container proc @@ -295,7 +232,7 @@ reactions. Can hold up to 50 units." icon_state = "beakernoreact" custom_materials = list(/datum/material/iron=SHEET_MATERIAL_AMOUNT * 1.5) - reagent_flags = OPENCONTAINER | NO_REACT + initial_reagent_flags = OPENCONTAINER | NO_REACT volume = 50 amount_per_transfer_from_this = 10 @@ -410,21 +347,21 @@ melee = 10 acid = 50 -/obj/item/reagent_containers/cup/bucket/attackby(obj/O, mob/user, list/modifiers, list/attack_modifiers) - if(istype(O, /obj/item/mop)) +/obj/item/reagent_containers/cup/bucket/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(istype(tool, /obj/item/mop)) if(reagents.total_volume < 1) user.balloon_alert(user, "empty!") - else - reagents.trans_to(O, 5, transferred_by = user) - user.balloon_alert(user, "doused [O]") - playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE) - return - else if(isprox(O)) //This works with wooden buckets for now. Somewhat unintended, but maybe someone will add sprites for it soon(TM) - to_chat(user, span_notice("You add [O] to [src].")) - qdel(O) + return ITEM_INTERACT_BLOCKING + reagents.trans_to(tool, 5, transferred_by = user) + user.balloon_alert(user, "doused [tool]") + playsound(src, 'sound/effects/slosh.ogg', 25, TRUE) + return ITEM_INTERACT_SUCCESS + if(isprox(tool)) //This works with wooden buckets for now. Somewhat unintended, but maybe someone will add sprites for it soon(TM) + to_chat(user, span_notice("You add [tool] to [src].")) + qdel(tool) var/obj/item/bot_assembly/cleanbot/new_cleanbot_ass = new(null, src) user.put_in_hands(new_cleanbot_ass) - return + return ITEM_INTERACT_SUCCESS return ..() @@ -435,11 +372,11 @@ to_chat(user, span_userdanger("[src]'s contents spill all over you!")) reagents.expose(user, TOUCH) reagents.clear_reagents() - reagents.flags = NONE + update_container_flags(NONE) /obj/item/reagent_containers/cup/bucket/dropped(mob/user) . = ..() - reagents.flags = initial(reagent_flags) + reset_container_flags() /obj/item/reagent_containers/cup/bucket/equip_to_best_slot(mob/M) if(reagents.total_volume) //If there is water in a bucket, don't quick equip it to the head @@ -468,8 +405,7 @@ volume = 100 custom_materials = list(/datum/material/wood = SHEET_MATERIAL_AMOUNT) resistance_flags = FLAMMABLE - reagent_flags = OPENCONTAINER - spillable = TRUE + initial_reagent_flags = OPENCONTAINER var/obj/item/grinded /obj/item/reagent_containers/cup/mortar/click_alt(mob/user) @@ -480,43 +416,45 @@ balloon_alert(user, "ejected") return CLICK_ACTION_SUCCESS -/obj/item/reagent_containers/cup/mortar/attackby(obj/item/I, mob/living/carbon/human/user) - ..() - if(istype(I,/obj/item/pestle)) - if(grinded) - if(user.getStaminaLoss() > 50) - to_chat(user, span_warning("You are too tired to work!")) - return - var/list/choose_options = list( - "Grind" = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_grind"), - "Juice" = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_juice") - ) - var/picked_option = show_radial_menu(user, src, choose_options, radius = 38, require_near = TRUE) - if(grinded && in_range(src, user) && user.is_holding(I) && picked_option) - to_chat(user, span_notice("You start grinding...")) - if(do_after(user, 2.5 SECONDS, target = src)) - user.adjustStaminaLoss(40) - switch(picked_option) - if("Juice") - return juice_item(grinded, user) - if("Grind") - return grind_item(grinded, user) - else - to_chat(user, span_notice("You try to grind the mortar itself instead of [grinded]. You failed.")) - return - return - else +/obj/item/reagent_containers/cup/mortar/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + . = ..() + if(. & ITEM_INTERACT_ANY_BLOCKER) + return . + if(istype(tool, /obj/item/pestle)) + if(!grinded) to_chat(user, span_warning("There is nothing to grind!")) - return + return ITEM_INTERACT_BLOCKING + if(user.getStaminaLoss() > 50) + to_chat(user, span_warning("You are too tired to work!")) + return ITEM_INTERACT_BLOCKING + var/list/choose_options = list( + "Grind" = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_grind"), + "Juice" = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_juice") + ) + var/picked_option = show_radial_menu(user, src, choose_options, radius = 38, require_near = TRUE) + if(!grinded || !in_range(src, user) || !user.is_holding(tool) || !picked_option) + return ITEM_INTERACT_BLOCKING + to_chat(user, span_notice("You start grinding...")) + if(!do_after(user, 2.5 SECONDS, target = src)) + return ITEM_INTERACT_BLOCKING + user.adjustStaminaLoss(40) + switch(picked_option) + if("Juice") + return juice_item(grinded, user) ? ITEM_INTERACT_BLOCKING : ITEM_INTERACT_SUCCESS + if("Grind") + return grind_item(grinded, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING + to_chat(user, span_notice("You try to grind the mortar itself instead of [grinded]. You failed.")) + return ITEM_INTERACT_BLOCKING if(grinded) to_chat(user, span_warning("There is something inside already!")) - return - if(!I.blend_requirements(src)) + return ITEM_INTERACT_BLOCKING + if(!tool.blend_requirements(src)) to_chat(user, span_warning("Cannot grind this!")) - return - if(length(I.grind_results) || I.reagents?.total_volume) - I.forceMove(src) - grinded = I + return ITEM_INTERACT_BLOCKING + if((length(tool.grind_results) || tool.reagents?.total_volume) && user.transferItemToLoc(tool, src)) + grinded = tool + return ITEM_INTERACT_SUCCESS + return NONE /obj/item/reagent_containers/cup/mortar/blended(obj/item/blended_item, grinded) src.grinded = null diff --git a/code/modules/reagents/reagent_containers/cups/bottle.dm b/code/modules/reagents/reagent_containers/cups/bottle.dm index ef0ba9c53bf..f0b79742630 100644 --- a/code/modules/reagents/reagent_containers/cups/bottle.dm +++ b/code/modules/reagents/reagent_containers/cups/bottle.dm @@ -499,13 +499,12 @@ fill_icon_thresholds = list(0, 20, 40, 60, 80, 100) possible_transfer_amounts = list(5, 10) amount_per_transfer_from_this = 5 - spillable = FALSE - /// Do we currently have our pump cap on? - var/cap_on = TRUE /obj/item/reagent_containers/cup/bottle/syrup_bottle/Initialize(mapload) . = ..() register_context() + // this is not done via initial_reagent_flags because it represents state + update_container_flags(SEALED_CONTAINER | TRANSPARENT) /obj/item/reagent_containers/cup/bottle/syrup_bottle/examine(mob/user) . = ..() @@ -515,10 +514,10 @@ /obj/item/reagent_containers/cup/bottle/syrup_bottle/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) . = ..() - context[SCREENTIP_CONTEXT_ALT_LMB] = (cap_on ? "Remove Pump Cap" : "Add Pump Cap") + context[SCREENTIP_CONTEXT_ALT_LMB] = (is_open_container() ? "Add Pump Cap" : "Remove Pump Cap") if(IS_WRITING_UTENSIL(held_item)) context[SCREENTIP_CONTEXT_LMB] = "Write Label" - else if(cap_on && held_item?.is_refillable()) + else if(is_open_container() && held_item?.is_refillable()) context[SCREENTIP_CONTEXT_LMB] = "Use Pump" return CONTEXTUAL_SCREENTIP_SET @@ -527,7 +526,7 @@ /obj/item/reagent_containers/cup/bottle/syrup_bottle/item_interaction(mob/living/user, obj/item/tool, list/modifiers) if(IS_WRITING_UTENSIL(tool)) return writing_utensil_act(user, tool) - if(cap_on && tool.is_refillable()) + if(is_open_container() && tool.is_refillable()) return refillable_act(user, tool) return ..() @@ -561,18 +560,22 @@ update_appearance() return ITEM_INTERACT_SUCCESS -/obj/item/reagent_containers/cup/bottle/syrup_bottle/click_alt(mob/user) - cap_on = !cap_on - if(cap_on) - icon_state = "syrup" - spillable = FALSE - balloon_alert(user, "put pump cap on") - else +/obj/item/reagent_containers/cup/bottle/syrup_bottle/update_icon_state() + . = ..() + if(is_open_container()) icon_state = "syrup_open" - spillable = TRUE - balloon_alert(user, "removed pump cap") + else + icon_state = "syrup" - update_icon_state() +/obj/item/reagent_containers/cup/bottle/syrup_bottle/click_alt(mob/user) + if(is_open_container()) + balloon_alert(user, "put pump cap on") + update_container_flags(SEALED_CONTAINER | TRANSPARENT) + else + balloon_alert(user, "removed pump cap") + reset_container_flags() + + update_appearance() return CLICK_ACTION_SUCCESS //types of syrups diff --git a/code/modules/reagents/reagent_containers/cups/drinkingglass.dm b/code/modules/reagents/reagent_containers/cups/drinkingglass.dm index 3c23d4d2ee0..103a8cf7df5 100644 --- a/code/modules/reagents/reagent_containers/cups/drinkingglass.dm +++ b/code/modules/reagents/reagent_containers/cups/drinkingglass.dm @@ -9,7 +9,6 @@ volume = 50 custom_materials = list(/datum/material/glass=SMALL_MATERIAL_AMOUNT*5) max_integrity = 20 - spillable = TRUE resistance_flags = ACID_PROOF obj_flags = UNIQUE_RENAME drop_sound = 'sound/items/handling/drinkglass_drop.ogg' diff --git a/code/modules/reagents/reagent_containers/cups/drinks.dm b/code/modules/reagents/reagent_containers/cups/drinks.dm index b25e99e7000..3ab16562102 100644 --- a/code/modules/reagents/reagent_containers/cups/drinks.dm +++ b/code/modules/reagents/reagent_containers/cups/drinks.dm @@ -11,7 +11,8 @@ resistance_flags = NONE isGlass = TRUE - + attack_verb_continuous = list("smashes", "bashes") + attack_verb_simple = list("smash", "bash") /obj/item/reagent_containers/cup/glass/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum, do_splash = TRUE) . = ..() @@ -26,7 +27,7 @@ return if(bartender_check(target, thrower) && throwingdatum) return - SplashReagents(target, throwingdatum, override_spillable = TRUE) + splash_reagents(target, thrower || throwingdatum?.get_thrower(), allow_closed_splash = TRUE) var/obj/item/broken_bottle/B = new (loc) B.mimic_broken(src, target, break_top) qdel(src) @@ -54,7 +55,6 @@ has_variable_transfer_amount = FALSE volume = 5 obj_flags = CONDUCTS_ELECTRICITY - spillable = TRUE resistance_flags = FIRE_PROOF isGlass = FALSE @@ -108,7 +108,6 @@ icon_state = "coffee" base_icon_state = "coffee" list_reagents = list(/datum/reagent/consumable/coffee = 30) - spillable = TRUE resistance_flags = FREEZE_PROOF isGlass = FALSE drink_type = BREAKFAST @@ -153,7 +152,6 @@ custom_price = PAYCHECK_LOWER * 0.6 icon_state = "icecup" list_reagents = list(/datum/reagent/consumable/ice = 30) - spillable = TRUE isGlass = FALSE /obj/item/reagent_containers/cup/glass/ice/prison @@ -168,7 +166,6 @@ icon_state = "tea_empty" base_icon_state = "tea" inhand_icon_state = "coffee" - spillable = TRUE /obj/item/reagent_containers/cup/glass/mug/update_icon_state() icon_state = "[base_icon_state][reagents.total_volume ? null : "_empty"]" @@ -203,7 +200,6 @@ base_icon_state = "coffee_cup" possible_transfer_amounts = list(10) volume = 30 - spillable = TRUE isGlass = FALSE /obj/item/reagent_containers/cup/glass/coffee_cup/update_icon_state() @@ -234,7 +230,7 @@ // The 2 bottles have separate cap overlay icons because if the bottle falls over while bottle flipping the cap stays fucked on the moved overlay var/cap_icon = 'icons/obj/drinks/drink_effects.dmi' var/cap_icon_state = "bottle_cap_small" - var/cap_on = TRUE + var/start_capped = TRUE var/cap_lost = FALSE var/mutable_appearance/cap_overlay var/flip_chance = 10 @@ -244,20 +240,21 @@ /obj/item/reagent_containers/cup/glass/waterbottle/Initialize(mapload) cap_overlay = mutable_appearance(cap_icon, cap_icon_state) . = ..() - if(cap_on) - spillable = FALSE + if(start_capped) + // this is not done via initial_reagent_flags because it represents state + update_container_flags(SEALED_CONTAINER | TRANSPARENT) update_appearance() /obj/item/reagent_containers/cup/glass/waterbottle/update_overlays() . = ..() - if(cap_on) + if(!is_open_container()) . += cap_overlay /obj/item/reagent_containers/cup/glass/waterbottle/examine(mob/user) . = ..() if(cap_lost) . += span_notice("The cap seems to be missing.") - else if(cap_on) + else if(!is_open_container()) . += span_notice("The cap is firmly on to prevent spilling. Alt-click to remove the cap.") else . += span_notice("The cap has been taken off. Alt-click to put a cap on.") @@ -268,9 +265,8 @@ return CLICK_ACTION_BLOCKING var/fumbled = HAS_TRAIT(user, TRAIT_CLUMSY) && prob(5) - if(cap_on || fumbled) - cap_on = FALSE - spillable = TRUE + if(!is_open_container() || fumbled) + reset_container_flags() animate(src, transform = null, time = 2, loop = 0) if(fumbled) to_chat(user, span_warning("You fumble with [src]'s cap! The cap falls onto the ground and simply vanishes. Where the hell did it go?")) @@ -279,52 +275,18 @@ to_chat(user, span_notice("You remove the cap from [src].")) playsound(loc, 'sound/items/handling/reagent_containers/plastic_bottle/bottle_cap_open.ogg', 50, TRUE) else - cap_on = TRUE - spillable = FALSE + update_container_flags(SEALED_CONTAINER | TRANSPARENT) to_chat(user, span_notice("You put the cap on [src].")) playsound(loc, 'sound/items/handling/reagent_containers/plastic_bottle/bottle_cap_close.ogg', 50, TRUE) update_appearance() return CLICK_ACTION_SUCCESS -/obj/item/reagent_containers/cup/glass/waterbottle/is_refillable() - if(cap_on) - return FALSE - return ..() - -/obj/item/reagent_containers/cup/glass/waterbottle/is_drainable() - if(cap_on) - return FALSE - return ..() - -/obj/item/reagent_containers/cup/glass/waterbottle/attack(mob/target, mob/living/user, def_zone) - if(!target) - return - - if(cap_on && reagents.total_volume && istype(target)) - to_chat(user, span_warning("You must remove the cap before you can do that!")) - return - - return ..() - -/obj/item/reagent_containers/cup/glass/waterbottle/interact_with_atom(atom/target, mob/living/user, list/modifiers) - if(cap_on && (target.is_refillable() || target.is_drainable() || (reagents.total_volume && !user.combat_mode))) - to_chat(user, span_warning("You must remove the cap before you can do that!")) - return ITEM_INTERACT_BLOCKING - - if(istype(target, /obj/item/reagent_containers/cup/glass/waterbottle)) - var/obj/item/reagent_containers/cup/glass/waterbottle/other_bottle = target - if(other_bottle.cap_on) - to_chat(user, span_warning("[other_bottle] has a cap firmly twisted on!")) - return ITEM_INTERACT_BLOCKING - - return ..() - // heehoo bottle flipping /obj/item/reagent_containers/cup/glass/waterbottle/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) . = ..() if(QDELETED(src)) return - if(!cap_on || !reagents.total_volume) + if(is_open_container() || !reagents.total_volume) return if(prob(flip_chance)) // landed upright src.visible_message(span_notice("[src] lands upright!")) @@ -340,7 +302,7 @@ /obj/item/reagent_containers/cup/glass/waterbottle/empty list_reagents = list() - cap_on = FALSE + start_capped = FALSE /obj/item/reagent_containers/cup/glass/waterbottle/large desc = "A fresh commercial-sized bottle of water." @@ -354,7 +316,7 @@ /obj/item/reagent_containers/cup/glass/waterbottle/large/empty list_reagents = list() - cap_on = FALSE + start_capped = FALSE // Admin spawn /obj/item/reagent_containers/cup/glass/waterbottle/relic @@ -377,7 +339,6 @@ icon_state = "water_cup_e" possible_transfer_amounts = list(10) volume = 10 - spillable = TRUE isGlass = FALSE /obj/item/reagent_containers/cup/glass/sillycup/update_icon_state() @@ -404,8 +365,8 @@ /obj/item/reagent_containers/cup/glass/bottle/juice/smallcarton/smash(atom/target, mob/thrower, datum/thrownthing/throwingdatum, break_top) if(bartender_check(target, thrower) && throwingdatum) return - SplashReagents(target, throwingdatum, override_spillable = TRUE) - var/obj/item/broken_bottle/bottle_shard = new (loc) + splash_reagents(target, thrower || throwingdatum?.get_thrower(), allow_closed_splash = TRUE) + var/obj/item/broken_bottle/bottle_shard = new(drop_location()) bottle_shard.mimic_broken(src, target) qdel(src) target.Bumped(bottle_shard) @@ -559,4 +520,3 @@ icon_state = "britcup_empty" base_icon_state = "britcup" volume = 30 - spillable = TRUE diff --git a/code/modules/reagents/reagent_containers/cups/glassbottle.dm b/code/modules/reagents/reagent_containers/cups/glassbottle.dm index a76974b1052..bcd1d91c2eb 100644 --- a/code/modules/reagents/reagent_containers/cups/glassbottle.dm +++ b/code/modules/reagents/reagent_containers/cups/glassbottle.dm @@ -128,8 +128,8 @@ /obj/item/reagent_containers/cup/glass/bottle/smash(mob/living/target, mob/thrower, datum/thrownthing/throwingdatum, break_top) if(bartender_check(target, thrower) && throwingdatum) - return - SplashReagents(target, throwingdatum, override_spillable = TRUE) + return FALSE + splash_reagents(target, thrower || throwingdatum?.get_thrower(), allow_closed_splash = TRUE) var/obj/item/broken_bottle/broken = new(drop_location()) if(!throwingdatum && thrower) thrower.put_in_hands(broken) @@ -140,70 +140,44 @@ qdel(src) target.Bumped(broken) + return TRUE -/obj/item/reagent_containers/cup/glass/bottle/try_splash(mob/living/user, atom/target) - - if(!target || !isliving(target)) - return ..() - +/obj/item/reagent_containers/cup/glass/bottle/try_splash(mob/user, atom/target) if(!isGlass) return ..() + return FALSE // instead of splashing, hit them with the bottle! - if(HAS_TRAIT(user, TRAIT_PACIFISM)) - to_chat(user, span_warning("You don't want to harm [target]!")) - return FALSE +/obj/item/reagent_containers/cup/glass/bottle/afterattack(atom/target, mob/user, list/modifiers) + if(!isGlass) + return - var/mob/living/living_target = target - var/obj/item/bodypart/affecting = user.zone_selected //Find what the player is aiming at + var/head_hitter = user.zone_selected == BODY_ZONE_HEAD && isliving(target) - var/armor_block = 0 //Get the target's armor values for normal attack damage. - var/knockdown_effectiveness = 0 //The more force the bottle has, the longer the duration. + // An attack that targets the head of a living mob will attempt to knock them down + if(head_hitter) + var/mob/living/living_target = target + var/knockdown_effectiveness = 0 + if(!HAS_TRAIT(target, TRAIT_HEAD_INJURY_BLOCKED)) + knockdown_effectiveness = bottle_knockdown_duration + ((force / 10) * 1 SECONDS) - living_target.getarmor(BODY_ZONE_HEAD, MELEE) + if(prob(knockdown_effectiveness)) + living_target.Knockdown(min(knockdown_effectiveness, 20 SECONDS)) - //Calculating duration and calculating damage. - if(ishuman(target)) - - var/mob/living/carbon/human/H = target - var/headarmor = 0 // Target's head armor - armor_block = H.run_armor_check(affecting, MELEE, "", "", armour_penetration) // For normal attack damage - - //If they have a hat/helmet and the user is targeting their head. - if(istype(H.head, /obj/item/clothing/head) && affecting == BODY_ZONE_HEAD) - headarmor = H.head.get_armor_rating(MELEE) - //Calculate the knockdown duration for the target. - knockdown_effectiveness = (bottle_knockdown_duration - headarmor) + force + // Displays a custom message which follows the attack + if(target == user) + target.visible_message( + span_warning("[user] smashes [src] [head_hitter ? "over [user.p_their()] head" : "against [user.p_them()]selves"]!"), + span_warning("You smash [src] [head_hitter ? "over your head" : "against yourself"]!"), + ) else - //Only humans can have armor, right? - armor_block = living_target.run_armor_check(affecting, MELEE) - if(affecting == BODY_ZONE_HEAD) - knockdown_effectiveness = bottle_knockdown_duration + force - //Apply the damage! - armor_block = min(90,armor_block) - living_target.apply_damage(force, BRUTE, affecting, armor_block) + target.visible_message( + span_warning("[user] smashes [src] [head_hitter ? "over [target]'s head" : "against [target]"]!"), + span_warning("[user] smashes [src] [head_hitter ? "over your head" : "against you"]!"), + ) - // You are going to knock someone down for longer if they are not wearing a helmet. - var/head_attack_message = "" - if(affecting == BODY_ZONE_HEAD && iscarbon(target) && !HAS_TRAIT(target, TRAIT_HEAD_INJURY_BLOCKED)) - head_attack_message = " on the head" - if(knockdown_effectiveness && prob(knockdown_effectiveness)) - living_target.apply_effect(min(knockdown_effectiveness, 200) , EFFECT_KNOCKDOWN) - - //Display an attack message. - if(target != user) - target.visible_message(span_danger("[user] hits [target][head_attack_message] with a bottle of [src.name]!"), \ - span_userdanger("[user] hits you [head_attack_message] with a bottle of [src.name]!")) - else - target.visible_message(span_danger("[target] hits [target.p_them()]self with a bottle of [src.name][head_attack_message]!"), \ - span_userdanger("You hit yourself with a bottle of [src.name][head_attack_message]!")) - - //Attack logs - log_combat(user, target, "attacked", src) - - //Finally, smash the bottle. This kills (del) the bottle. + // Finally, smash the bottle. This kills (del) the bottle and also does all the logging for us smash(target, user) - return TRUE - /* * Proc to make the bottle spill some of its contents out in a froth geyser of varying intensity/height * Arguments: @@ -679,8 +653,7 @@ desc = "Finely sourced from only the most pretentious French vineyards." icon_state = "champagne_bottle" base_icon_state = "champagne_bottle" - reagent_flags = TRANSPARENT - spillable = FALSE + initial_reagent_flags = TRANSPARENT list_reagents = list(/datum/reagent/consumable/ethanol/champagne = 100) drink_type = ALCOHOL ///Used for sabrage; increases the chance of success per 1 force of the attacking sharp item @@ -695,33 +668,34 @@ sabrage_success_percentile = 0 //force of the sharp item used to sabrage will not increase success chance /obj/item/reagent_containers/cup/glass/bottle/champagne/attack_self(mob/user) - if(spillable) + if(is_open_container()) return ..() balloon_alert(user, "fiddling with cork...") if(do_after(user, 1 SECONDS, src)) return pop_cork(user, sabrage = FALSE, froth_severity = pick(0, 1)) -/obj/item/reagent_containers/cup/glass/bottle/champagne/attackby(obj/item/attacking_item, mob/living/user, list/modifiers, list/attack_modifiers) +/obj/item/reagent_containers/cup/glass/bottle/champagne/item_interaction(mob/living/user, obj/item/tool, list/modifiers) . = ..() + if(. & ITEM_INTERACT_ANY_BLOCKER) + return . + if(is_open_container()) + return NONE - if(spillable) - return + if(tool.get_sharpness() != SHARP_EDGED) + return NONE - if(attacking_item.get_sharpness() != SHARP_EDGED) - return - - if(attacking_item != user.get_active_held_item()) //no TK allowed + if(tool != user.get_active_held_item()) //no TK allowed to_chat(user, span_userdanger("Such a feat is beyond your skills of telekinesis!")) - return + return ITEM_INTERACT_BLOCKING - if(attacking_item.force < 5) + if(tool.force < 5) balloon_alert(user, "not strong enough!") - return + return ITEM_INTERACT_BLOCKING playsound(user, 'sound/items/unsheath.ogg', 25, TRUE) balloon_alert(user, "preparing to swing...") if(!do_after(user, 2 SECONDS, src)) //takes longer because you are supposed to take the foil off the bottle first - return + return ITEM_INTERACT_BLOCKING //The bonus to success chance that the user gets for being a command role var/obj/item/organ/liver/liver = user.get_organ_slot(ORGAN_SLOT_LIVER) @@ -730,7 +704,7 @@ //The bonus to success chance that the user gets for having a sabrage skillchip installed/otherwise having the trait through other means var/skillchip_bonus = HAS_TRAIT(user, TRAIT_SABRAGE_PRO) ? 35 : 0 //calculate success chance. example: captain's sabre - 15 force = 75% chance - var/sabrage_chance = (attacking_item.force * sabrage_success_percentile) + command_bonus + skillchip_bonus + var/sabrage_chance = (tool.force * sabrage_success_percentile) + command_bonus + skillchip_bonus if(prob(sabrage_chance)) ///Severity of the resulting froth to pass to make_froth() @@ -745,18 +719,18 @@ severity_to_pass = 2 if(67 to 99) severity_to_pass = 1 - return pop_cork(user, sabrage = TRUE, froth_severity = severity_to_pass) - else //you dun goofed - user.visible_message( - span_danger("[user] fumbles the sabrage and cuts [src] in half, spilling it over themselves!"), - span_danger("You fail your stunt and cut [src] in half, spilling it over you!"), - ) - user.add_mood_event("sabrage_fail", /datum/mood_event/sabrage_fail) - return smash(target = user, break_top = TRUE) + return pop_cork(user, sabrage = TRUE, froth_severity = severity_to_pass) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING + + user.visible_message( + span_danger("[user] fumbles the sabrage and cuts [src] in half, spilling it over themselves!"), + span_danger("You fail your stunt and cut [src] in half, spilling it over you!"), + ) + user.add_mood_event("sabrage_fail", /datum/mood_event/sabrage_fail) + return smash(target = user, break_top = TRUE) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING /obj/item/reagent_containers/cup/glass/bottle/champagne/update_icon_state() . = ..() - if(spillable) + if(is_open_container()) if(sabraged) icon_state = "[base_icon_state]_sabrage" else @@ -783,9 +757,8 @@ continue stunt_witness.add_mood_event("sabrage_witness", /datum/mood_event/sabrage_witness) - reagents.flags |= OPENCONTAINER + add_container_flags(OPENCONTAINER) playsound(src, 'sound/items/champagne_pop.ogg', 70, TRUE) - spillable = TRUE update_appearance() make_froth(offset_x = 0, offset_y = sabraged ? 13 : 15, intensity = froth_severity) //the y offset for sabraged is lower because the bottle's lip is smashed ///Type of cork to fire away @@ -795,6 +768,7 @@ popped_cork.firer = user popped_cork.fired_from = src popped_cork.fire(dir2angle(user.dir) + rand(-30, 30)) + return TRUE /obj/projectile/bullet/champagne_cork name = "champagne cork" @@ -946,15 +920,17 @@ target.fire_act() new /obj/effect/hotspot(get_turf(target)) -/obj/item/reagent_containers/cup/glass/bottle/molotov/attackby(obj/item/I, mob/user, list/modifiers, list/attack_modifiers) - if(I.get_temperature() && !active) - active = TRUE - log_bomber(user, "has primed a", src, "for detonation") +/obj/item/reagent_containers/cup/glass/bottle/molotov/item_interaction(mob/living/user, obj/item/item, list/modifiers) + if(!item.get_temperature() || active) + return NONE + active = TRUE + log_bomber(user, "has primed a", src, "for detonation") - to_chat(user, span_info("You light [src] on fire.")) - add_overlay(custom_fire_overlay() || GLOB.fire_overlay) - if(!isGlass) - addtimer(CALLBACK(src, PROC_REF(explode)), 5 SECONDS) + to_chat(user, span_info("You light [src] on fire.")) + add_overlay(custom_fire_overlay() || GLOB.fire_overlay) + if(!isGlass) + addtimer(CALLBACK(src, PROC_REF(explode)), 5 SECONDS) + return ITEM_INTERACT_SUCCESS /obj/item/reagent_containers/cup/glass/bottle/molotov/proc/explode() if(!active) @@ -964,7 +940,7 @@ for(var/i in 1 to 2) if(istype(target, /obj/item/storage)) target = target.loc - SplashReagents(target, override_spillable = TRUE) + splash_reagents(target, allow_closed_splash = TRUE) target.fire_act() qdel(src) diff --git a/code/modules/reagents/reagent_containers/cups/mauna_mug.dm b/code/modules/reagents/reagent_containers/cups/mauna_mug.dm index b443229358b..569cf815f09 100644 --- a/code/modules/reagents/reagent_containers/cups/mauna_mug.dm +++ b/code/modules/reagents/reagent_containers/cups/mauna_mug.dm @@ -4,8 +4,7 @@ icon = 'icons/obj/devices/mauna_mug.dmi' icon_state = "maunamug" base_icon_state = "maunamug" - spillable = TRUE - reagent_flags = OPENCONTAINER + initial_reagent_flags = OPENCONTAINER fill_icon_state = "maunafilling" fill_icon_thresholds = list(25) var/obj/item/stock_parts/power_store/cell @@ -73,21 +72,21 @@ to_chat(user, span_notice("You screw the battery case on [src] [open ? "open" : "closed"] .")) update_appearance() -/obj/item/reagent_containers/cup/maunamug/attackby(obj/item/I, mob/user, list/modifiers, list/attack_modifiers) - add_fingerprint(user) - if(!istype(I, /obj/item/stock_parts/power_store/cell)) +/obj/item/reagent_containers/cup/maunamug/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(!istype(tool, /obj/item/stock_parts/power_store/cell)) return ..() if(!open) to_chat(user, span_warning("The battery case must be open to insert a power cell!")) - return FALSE + return ITEM_INTERACT_BLOCKING if(cell) to_chat(user, span_warning("There is already a power cell inside!")) - return FALSE - else if(!user.transferItemToLoc(I, src)) - return - cell = I + return ITEM_INTERACT_BLOCKING + else if(!user.transferItemToLoc(tool, src)) + return ITEM_INTERACT_BLOCKING + cell = tool user.visible_message(span_notice("[user] inserts a power cell into [src]."), span_notice("You insert the power cell into [src].")) update_appearance() + return ITEM_INTERACT_SUCCESS /obj/item/reagent_containers/cup/maunamug/attack_hand(mob/living/user, list/modifiers) if(cell && open) diff --git a/code/modules/reagents/reagent_containers/cups/organ_jar.dm b/code/modules/reagents/reagent_containers/cups/organ_jar.dm index 99309787a0d..52754f5836a 100644 --- a/code/modules/reagents/reagent_containers/cups/organ_jar.dm +++ b/code/modules/reagents/reagent_containers/cups/organ_jar.dm @@ -43,12 +43,11 @@ // Clicking on the jar with an organ lets you put the organ inside, if there isn't one already // Otherwise it should act like a normal bottle /obj/item/reagent_containers/cup/beaker/organ_jar/item_interaction(mob/living/user, obj/item/tool, list/modifiers) - . = ..() if(!istype(tool, /obj/item/organ)) - return + return ..() if(held_organ) balloon_alert(user, "the jar already contains [held_organ]") - return ITEM_INTERACT_BLOCKING + return ITEM_INTERACT_BLOCKING if(!user.transferItemToLoc(tool, src)) return ITEM_INTERACT_BLOCKING diff --git a/code/modules/reagents/reagent_containers/cups/soda.dm b/code/modules/reagents/reagent_containers/cups/soda.dm index 34c9d0d9233..e8304d71cb9 100644 --- a/code/modules/reagents/reagent_containers/cups/soda.dm +++ b/code/modules/reagents/reagent_containers/cups/soda.dm @@ -12,8 +12,7 @@ icon_state = "cola" icon_state_preview = "cola" abstract_type = /obj/item/reagent_containers/cup/soda_cans - reagent_flags = NONE - spillable = FALSE + initial_reagent_flags = NONE custom_price = PAYCHECK_CREW * 0.9 obj_flags = CAN_BE_HIT possible_transfer_amounts = list(5, 10, 15, 25, 30) @@ -64,17 +63,24 @@ sleep(2 SECONDS) //dramatic pause return TOXLOSS -/obj/item/reagent_containers/cup/soda_cans/attack(mob/M, mob/living/user) - if(iscarbon(M) && !reagents.total_volume && user.combat_mode && user.zone_selected == BODY_ZONE_HEAD) - if(M == user) - user.visible_message(span_warning("[user] crushes the can of [src] on [user.p_their()] forehead!"), span_notice("You crush the can of [src] on your forehead.")) +/obj/item/reagent_containers/cup/soda_cans/interact_with_atom(atom/target, mob/living/user, list/modifiers) + if(iscarbon(target) && !reagents.total_volume && user.combat_mode && user.zone_selected == BODY_ZONE_HEAD) + if(target == user) + user.visible_message( + span_warning("[user] crushes the can of [src] on [user.p_their()] forehead!"), + span_notice("You crush the can of [src] on your forehead."), + ) else - user.visible_message(span_warning("[user] crushes the can of [src] on [M]'s forehead!"), span_notice("You crush the can of [src] on [M]'s forehead.")) - playsound(M,'sound/items/weapons/pierce.ogg', rand(10,50), TRUE) - var/obj/item/trash/can/crushed_can = new /obj/item/trash/can(M.loc) + user.visible_message( + span_warning("[user] crushes the can of [src] on [target]'s forehead!"), + span_notice("You crush the can of [src] on [target]'s forehead."), + ) + playsound(src, 'sound/items/weapons/pierce.ogg', rand(10, 50), TRUE) + var/obj/item/trash/can/crushed_can = new /obj/item/trash/can(target.drop_location()) crushed_can.icon_state = icon_state qdel(src) - return TRUE + return ITEM_INTERACT_SUCCESS + return ..() /obj/item/reagent_containers/cup/soda_cans/bullet_act(obj/projectile/proj) @@ -96,9 +102,8 @@ return to_chat(user, "You pull back the tab of [src] with a satisfying pop.") //Ahhhhhhhh - reagents.flags |= OPENCONTAINER + add_container_flags(OPENCONTAINER) playsound(src, SFX_CAN_OPEN, 50, TRUE) - spillable = TRUE throwforce = 0 /** @@ -122,15 +127,14 @@ playsound(src, 'sound/items/can/can_pop.ogg', 80, TRUE) if(!hide_message) visible_message(span_danger("[src] spills over, fizzing its contents all over [target]!")) - spillable = TRUE - reagents.flags |= OPENCONTAINER + add_container_flags(OPENCONTAINER) reagents.expose(target, TOUCH) reagents.clear_reagents() throwforce = 0 /obj/item/reagent_containers/cup/soda_cans/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) . = ..() - if(. || spillable || !reagents.total_volume) // if it was caught, already opened, or has nothing in it + if(. || is_open_container() || !reagents.total_volume) // if it was caught, already opened, or has nothing in it return fizziness += SODA_FIZZINESS_THROWN diff --git a/code/modules/reagents/reagent_containers/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm index f2b2099a888..cfb72af6186 100644 --- a/code/modules/reagents/reagent_containers/dropper.dm +++ b/code/modules/reagents/reagent_containers/dropper.dm @@ -8,7 +8,7 @@ amount_per_transfer_from_this = 5 possible_transfer_amounts = list(1, 2, 3, 4, 5) volume = 5 - reagent_flags = TRANSPARENT + initial_reagent_flags = TRANSPARENT custom_price = PAYCHECK_CREW /obj/item/reagent_containers/dropper/interact_with_atom(atom/target, mob/living/user, list/modifiers) @@ -55,12 +55,7 @@ SEND_SIGNAL(target, COMSIG_MOB_REAGENTS_DROPPED_INTO_EYES, user, src, reagents, fraction) reagents.expose(target, TOUCH, fraction) var/mob/M = target - var/R - if(reagents) - for(var/datum/reagent/A in src.reagents.reagent_list) - R += "[A] ([num2text(A.volume)])," - - log_combat(user, M, "squirted", R) + log_combat(user, M, "squirted", reagents.get_reagent_log_string()) trans = round(reagents.trans_to(target, amount_per_transfer_from_this, transferred_by = user), CHEMICAL_VOLUME_ROUNDING) to_chat(user, span_notice("You transfer [trans] unit\s of the solution.")) diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index bd953c1ec6e..c4812b62ce1 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -11,7 +11,7 @@ volume = 30 possible_transfer_amounts = list(5) resistance_flags = ACID_PROOF - reagent_flags = OPENCONTAINER + initial_reagent_flags = OPENCONTAINER slot_flags = ITEM_SLOT_BELT var/ignore_flags = NONE var/infinite = FALSE @@ -23,8 +23,10 @@ /obj/item/reagent_containers/hypospray/attack_paw(mob/user, list/modifiers) return attack_hand(user, modifiers) -/obj/item/reagent_containers/hypospray/attack(mob/living/affected_mob, mob/user) - inject(affected_mob, user) +/obj/item/reagent_containers/hypospray/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(!isliving(interacting_with)) + return NONE + return inject(interacting_with, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING ///Handles all injection checks, injection and logging. /obj/item/reagent_containers/hypospray/proc/inject(mob/living/affected_mob, mob/user) @@ -122,7 +124,7 @@ has_variable_transfer_amount = FALSE volume = 15 ignore_flags = 1 //so you can medipen through spacesuits - reagent_flags = NONE + initial_reagent_flags = NONE flags_1 = null list_reagents = list(/datum/reagent/medicine/epinephrine = 10, /datum/reagent/toxin/formaldehyde = 3, /datum/reagent/medicine/coagulant = 2) custom_price = PAYCHECK_CREW diff --git a/code/modules/reagents/reagent_containers/inhaler.dm b/code/modules/reagents/reagent_containers/inhaler.dm index 5600625df6c..2af15aadf44 100644 --- a/code/modules/reagents/reagent_containers/inhaler.dm +++ b/code/modules/reagents/reagent_containers/inhaler.dm @@ -216,7 +216,7 @@ icon = 'icons/obj/medical/chemical.dmi' icon_state = "canister_generic" - reagent_flags = SEALED_CONTAINER|DRAINABLE|REFILLABLE + initial_reagent_flags = SEALED_CONTAINER|DRAINABLE|REFILLABLE has_variable_transfer_amount = FALSE max_integrity = 60 diff --git a/code/modules/reagents/reagent_containers/jerrycan.dm b/code/modules/reagents/reagent_containers/jerrycan.dm index e3b97e82b99..05f3149ae54 100644 --- a/code/modules/reagents/reagent_containers/jerrycan.dm +++ b/code/modules/reagents/reagent_containers/jerrycan.dm @@ -50,7 +50,7 @@ w_class = WEIGHT_CLASS_BULKY volume = 200 obj_flags = UNIQUE_RENAME - reagent_flags = OPENCONTAINER | SMART_CAP + initial_reagent_flags = OPENCONTAINER | NO_SPLASH fill_icon_thresholds = list(0, 20, 40, 60, 80, 100, 120, 140, 160, 180, 200) possible_transfer_amounts = list(5, 10, 15, 30, 50, 100, 200) adjust_color_contrast = TRUE @@ -97,7 +97,7 @@ /obj/item/reagent_containers/cup/jerrycan/opaque fill_icon_thresholds = null - reagent_flags = REFILLABLE | DRAINABLE | SMART_CAP + initial_reagent_flags = parent_type::initial_reagent_flags & ~TRANSPARENT highlight_strenght = 0.75 /obj/item/reagent_containers/cup/jerrycan/opaque/yellow diff --git a/code/modules/reagents/reagent_containers/medigel.dm b/code/modules/reagents/reagent_containers/medigel.dm index 4f45caebf4a..f459a08211b 100644 --- a/code/modules/reagents/reagent_containers/medigel.dm +++ b/code/modules/reagents/reagent_containers/medigel.dm @@ -9,7 +9,7 @@ righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi' item_flags = NOBLUDGEON obj_flags = UNIQUE_RENAME - reagent_flags = OPENCONTAINER + initial_reagent_flags = OPENCONTAINER slot_flags = ITEM_SLOT_BELT throwforce = 0 w_class = WEIGHT_CLASS_SMALL @@ -37,39 +37,41 @@ var/squirt_mode = amount_per_transfer_from_this == initial(amount_per_transfer_from_this) to_chat(user, span_notice("You will now apply the medigel's contents in [squirt_mode ? "extended sprays":"short bursts"]. You'll now use [amount_per_transfer_from_this] units per use.")) -/obj/item/reagent_containers/medigel/attack(mob/M, mob/user, def_zone) +/obj/item/reagent_containers/medigel/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(!isliving(interacting_with)) + return NONE if(!reagents || !reagents.total_volume) to_chat(user, span_warning("[src] is empty!")) - return + return ITEM_INTERACT_BLOCKING - if(M == user) - M.visible_message(span_notice("[user] attempts to [apply_method] [src] on [user.p_them()]self.")) + if(interacting_with == user) + interacting_with.visible_message(span_notice("[user] attempts to [apply_method] [src] on [user.p_them()]self.")) if(self_delay) - if(!do_after(user, self_delay, M)) - return + if(!do_after(user, self_delay, interacting_with)) + return ITEM_INTERACT_BLOCKING if(!reagents || !reagents.total_volume) - return - to_chat(M, span_notice("You [apply_method] yourself with [src].")) + return ITEM_INTERACT_BLOCKING + to_chat(interacting_with, span_notice("You [apply_method] yourself with [src].")) else - log_combat(user, M, "attempted to apply", src, reagents.get_reagent_log_string()) - M.visible_message(span_danger("[user] attempts to [apply_method] [src] on [M]."), \ - span_userdanger("[user] attempts to [apply_method] [src] on you.")) - if(!do_after(user, CHEM_INTERACT_DELAY(3 SECONDS, user), M)) - return + log_combat(user, interacting_with, "attempted to apply", src, reagents.get_reagent_log_string()) + interacting_with.visible_message( + span_danger("[user] attempts to [apply_method] [src] on [interacting_with]."), + span_userdanger("[user] attempts to [apply_method] [src] on you."), + ) + if(!do_after(user, CHEM_INTERACT_DELAY(3 SECONDS, user), interacting_with)) + return ITEM_INTERACT_BLOCKING if(!reagents || !reagents.total_volume) - return - M.visible_message(span_danger("[user] [apply_method]s [M] down with [src]."), \ - span_userdanger("[user] [apply_method]s you down with [src].")) + return ITEM_INTERACT_BLOCKING + interacting_with.visible_message( + span_danger("[user] [apply_method]s [interacting_with] down with [src]."), + span_userdanger("[user] [apply_method]s you down with [src]."), + ) - if(!reagents || !reagents.total_volume) - return - - else - log_combat(user, M, "applied", src, reagents.get_reagent_log_string()) - playsound(src, 'sound/effects/spray.ogg', 30, TRUE, -6) - reagents.trans_to(M, amount_per_transfer_from_this, transferred_by = user, methods = apply_type) - return + log_combat(user, interacting_with, "applied", src, reagents.get_reagent_log_string()) + playsound(src, 'sound/effects/spray.ogg', 30, TRUE, -6) + reagents.trans_to(interacting_with, amount_per_transfer_from_this, transferred_by = user, methods = apply_type) + return ITEM_INTERACT_SUCCESS /obj/item/reagent_containers/medigel/libital name = "medical gel (libital)" @@ -101,9 +103,9 @@ if(reagents.total_volume >= 60) . += span_info("One full bottle can restore a corpse husked by burns.") -/obj/item/reagent_containers/medigel/synthflesh/attack(mob/M, mob/user, def_zone) - if(iscarbon(M)) - var/mob/living/carbon/carbies = M +/obj/item/reagent_containers/medigel/synthflesh/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(iscarbon(interacting_with) && reagents?.total_volume) + var/mob/living/carbon/carbies = interacting_with if(HAS_TRAIT_FROM(carbies, TRAIT_HUSK, BURN) && carbies.getFireLoss() > UNHUSK_DAMAGE_THRESHOLD * 2.5) // give them a warning if the mob is a husk but synthflesh won't unhusk yet carbies.visible_message(span_boldwarning("[carbies]'s burns need to be repaired first before synthflesh will unhusk it!")) diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index a04044a50eb..51ae159de14 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -8,7 +8,7 @@ lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi' item_flags = NOBLUDGEON - reagent_flags = OPENCONTAINER + initial_reagent_flags = OPENCONTAINER slot_flags = ITEM_SLOT_BELT throwforce = 0 w_class = WEIGHT_CLASS_SMALL @@ -27,6 +27,10 @@ var/spray_sound = 'sound/effects/spray2.ogg' reagent_container_liquid_sound = SFX_DEFAULT_LIQUID_SLOSH +/obj/item/reagent_containers/spray/Initialize(mapload, vol) + . = ..() + AddElement(/datum/element/reagents_item_heatable) + /obj/item/reagent_containers/spray/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) return try_spray(interacting_with, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING @@ -132,28 +136,6 @@ current_range = spray_range to_chat(user, span_notice("You switch the nozzle setting to [stream_mode ? "\"stream\"":"\"spray\""].")) -/obj/item/reagent_containers/spray/attackby(obj/item/I, mob/user, list/modifiers, list/attack_modifiers) - var/hotness = I.get_temperature() - if(hotness && reagents) - reagents.expose_temperature(hotness) - to_chat(user, span_notice("You heat [name] with [I]!")) - - //Cooling method - if(istype(I, /obj/item/extinguisher)) - var/obj/item/extinguisher/extinguisher = I - if(extinguisher.safety) - return - if (extinguisher.reagents.total_volume < 1) - to_chat(user, span_warning("\The [extinguisher] is empty!")) - return - var/cooling = (0 - reagents.chem_temp) * extinguisher.cooling_power * 2 - reagents.expose_temperature(cooling) - to_chat(user, span_notice("You cool \the [src] with the [I]!")) - playsound(loc, 'sound/effects/extinguish.ogg', 75, TRUE, -3) - extinguisher.reagents.remove_all(1) - - return ..() - /obj/item/reagent_containers/spray/verb/empty() set name = "Empty Spray Bottle" set category = "Object" @@ -275,7 +257,7 @@ list_reagents = list(/datum/reagent/lube/superlube = 30) /obj/item/reagent_containers/spray/waterflower/cyborg - reagent_flags = NONE + initial_reagent_flags = NONE volume = 100 list_reagents = list(/datum/reagent/water = 100) var/generate_amount = 5 @@ -360,7 +342,7 @@ inhand_icon_state = "chemsprayer_janitor" lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' - reagent_flags = NONE + initial_reagent_flags = NONE list_reagents = list(/datum/reagent/space_cleaner = 1000) volume = 1000 amount_per_transfer_from_this = 5 @@ -392,7 +374,7 @@ lefthand_file = 'icons/mob/inhands/items_lefthand.dmi' righthand_file = 'icons/mob/inhands/items_righthand.dmi' w_class = WEIGHT_CLASS_TINY - reagent_flags = NONE + initial_reagent_flags = NONE list_reagents = list(/datum/reagent/confetti = 15) volume = 15 amount_per_transfer_from_this = 5 diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index 2454416062a..a016a0805a4 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -12,7 +12,7 @@ possible_transfer_amounts = list(5, 10, 15) volume = 15 custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT, /datum/material/glass=SMALL_MATERIAL_AMOUNT*0.2) - reagent_flags = TRANSPARENT + initial_reagent_flags = TRANSPARENT custom_price = PAYCHECK_CREW * 0.5 sharpness = SHARP_POINTY embed_type = /datum/embedding/syringe @@ -34,9 +34,6 @@ CALLBACK(src, PROC_REF(get_dart_var_modifiers))\ ) -/obj/item/reagent_containers/syringe/attackby(obj/item/I, mob/user, list/modifiers, list/attack_modifiers) - return - /obj/item/reagent_containers/syringe/proc/try_syringe(atom/target, mob/user) if(!target.reagents) return FALSE diff --git a/code/modules/unit_tests/bake_a_cake.dm b/code/modules/unit_tests/bake_a_cake.dm index 424d5668a44..302516673ab 100644 --- a/code/modules/unit_tests/bake_a_cake.dm +++ b/code/modules/unit_tests/bake_a_cake.dm @@ -32,16 +32,31 @@ human.mind = new /datum/mind(null) // Add brain for the food buff // It's a piece of cake to bake a pretty cake + var/sanity = 0 while(beaker.reagents.get_reagent_amount(/datum/reagent/consumable/sugar) < sugar_required && beaker.reagents.total_volume < total_volume) sugar_bag.melee_attack_chain(human, beaker) + sanity++ + if(sanity > 50) + TEST_FAIL("Failed to add sugar to beaker!") + return + sanity = 0 while(beaker.reagents.get_reagent_amount(/datum/reagent/consumable/flour) < flour_required && beaker.reagents.total_volume < total_volume) flour_bag.melee_attack_chain(human, beaker) + sanity++ + if(sanity > 50) + TEST_FAIL("Failed to add flour to beaker!") + return + sanity = 0 while((beaker.reagents.get_reagent_amount(/datum/reagent/consumable/eggyolk) < eggyolk_required \ || beaker.reagents.get_reagent_amount(/datum/reagent/consumable/eggwhite) < eggwhite_required) \ && beaker.reagents.total_volume < total_volume \ && beaker.reagents.total_volume >= (sugar_required + flour_required)) // Make sure that we won't miss the reaction var/obj/item/egg = egg_box.contents[1] egg.melee_attack_chain(human, beaker, list(RIGHT_CLICK = TRUE)) + sanity++ + if(sanity > 50) + TEST_FAIL("Failed to add egg to beaker!") + return var/obj/item/food/cake_batter = locate(/obj/item/food/cakebatter) in table_loc TEST_ASSERT_NOTNULL(cake_batter, "Failed making cake batter!") TEST_ASSERT_EQUAL(beaker.reagents.total_volume, 0, "Cake batter did not consume all beaker reagents!") diff --git a/code/modules/unit_tests/reagent_mob_expose.dm b/code/modules/unit_tests/reagent_mob_expose.dm index 20aa9c72e03..383225d3fab 100644 --- a/code/modules/unit_tests/reagent_mob_expose.dm +++ b/code/modules/unit_tests/reagent_mob_expose.dm @@ -23,7 +23,7 @@ // INGEST TEST_ASSERT_EQUAL(human.fire_stacks, 0, "Human has fire stacks before taking phlogiston") drink.reagents.add_reagent(/datum/reagent/phlogiston, 10) - drink.attack(human, human) + drink.melee_attack_chain(human, human) TEST_ASSERT_EQUAL(human.fire_stacks, 1, "Human does not have fire stacks after taking phlogiston") human.Life(SSMOBS_DT) TEST_ASSERT(human.fire_stacks > 1, "Human fire stacks did not increase after life tick")