From 863977e5fa9739016ef8a57b38de4e4b3ba5b9e1 Mon Sep 17 00:00:00 2001 From: TemporalOroboros Date: Tue, 22 Dec 2020 14:20:00 -0800 Subject: [PATCH] Makes reagent updates more event based, also makes plasma boil properly. (#54790) Converts most on_reagent_change calls to signals. Converts on_reagent_change to a signal handler. Expands the reagent exposure signals Add a setter proc and signal for reagent temperature Fixes adjust_thermal_energy not sending a temperature change event Makes min_temp and max_temp actually do something with adjust_thermal_energy --- code/__DEFINES/dcs/signals.dm | 25 + code/__DEFINES/reagents.dm | 7 - code/datums/components/crafting/crafting.dm | 2 +- .../components/plumbing/reaction_chamber.dm | 2 +- code/datums/datumvars.dm | 3 - code/game/atoms.dm | 1 + code/game/objects/objs.dm | 1 + code/game/turfs/turf.dm | 1 + code/modules/food_and_drinks/drinks/drinks.dm | 122 ++-- .../drinks/drinks/drinkingglass.dm | 90 ++- .../modules/food_and_drinks/food/condiment.dm | 33 +- code/modules/hydroponics/biogenerator.dm | 4 - code/modules/hydroponics/grown/replicapod.dm | 80 ++- .../mob/living/carbon/monkey/monkey.dm | 21 +- code/modules/mob/living/living_defense.dm | 1 + .../mob/living/simple_animal/bot/secbot.dm | 1 - .../mob/living/simple_animal/slime/slime.dm | 21 +- .../plumbing/plumbers/reaction_chamber.dm | 21 +- code/modules/power/cell.dm | 18 +- code/modules/power/lighting.dm | 31 +- code/modules/reagents/chemistry/holder.dm | 633 +++++++++--------- code/modules/reagents/chemistry/readme.md | 3 - code/modules/reagents/chemistry/reagents.dm | 3 - .../chemistry/reagents/alcohol_reagents.dm | 2 - .../chemistry/reagents/toxin_reagents.dm | 22 +- code/modules/reagents/reagent_containers.dm | 18 +- .../reagents/reagent_containers/blood_pack.dm | 25 +- .../reagents/reagent_containers/borghydro.dm | 1 - .../reagents/reagent_containers/spray.dm | 21 +- .../reagents/reagent_containers/syringes.dm | 3 - .../xenobiology/vatgrowing/vatgrower.dm | 18 +- .../mecha/equipment/tools/medical_tools.dm | 21 +- 32 files changed, 741 insertions(+), 514 deletions(-) diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 2a7405fa0b0..eb198e14ccc 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -180,6 +180,31 @@ ///from base of [/datum/reagent/proc/expose_atom]: (/turf, reac_volume) #define COMSIG_REAGENT_EXPOSE_TURF "reagent_expose_turf" +///from base of [/datum/reagents/proc/add_reagent]: (/datum/reagent, amount, reagtemp, data, no_react) +#define COMSIG_REAGENTS_NEW_REAGENT "reagents_new_reagent" +///from base of [/datum/reagents/proc/add_reagent]: (/datum/reagent, amount, reagtemp, data, no_react) +#define COMSIG_REAGENTS_ADD_REAGENT "reagents_add_reagent" +///from base of [/datum/reagents/proc/del_reagent]: (/datum/reagent) +#define COMSIG_REAGENTS_DEL_REAGENT "reagents_del_reagent" +///from base of [/datum/reagents/proc/clear_reagents]: () +#define COMSIG_REAGENTS_REM_REAGENT "reagents_rem_reagent" +///from base of [/datum/reagents/proc/set_temperature]: (new_temp, old_temp) +#define COMSIG_REAGENTS_CLEAR_REAGENTS "reagents_clear_reagents" +///from base of [/datum/reagents/proc/remove_reagent]: (/datum/reagent, amount) +#define COMSIG_REAGENTS_TEMP_CHANGE "reagents_temp_change" +///from base of [/datum/reagents/proc/handle_reactions]: (num_reactions) +#define COMSIG_REAGENTS_REACTED "reagents_reacted" +///from base of [/atom/proc/expose_reagents]: (/atom, /list, methods, volume_modifier, show_message) +#define COMSIG_REAGENTS_EXPOSE_ATOM "reagents_expose_atom" +///from base of [/obj/proc/expose_reagents]: (/obj, /list, methods, volume_modifier, show_message) +#define COMSIG_REAGENTS_EXPOSE_OBJ "reagents_expose_obj" +///from base of [/mob/living/proc/expose_reagents]: (/mob/living, /list, methods, volume_modifier, show_message, touch_protection) +#define COMSIG_REAGENTS_EXPOSE_MOB "reagents_expose_mob" +///from base of [/turf/proc/expose_reagents]: (/turf, /list, methods, volume_modifier, show_message) +#define COMSIG_REAGENTS_EXPOSE_TURF "reagents_expose_turf" +///from base of [/datum/component/personal_crafting/proc/del_reqs]: () +#define COMSIG_REAGENTS_CRAFTING_PING "reagents_crafting_ping" + ///Called right before the atom changes the value of light_range to a different one, from base atom/set_light_range(): (new_range) #define COMSIG_ATOM_SET_LIGHT_RANGE "atom_set_light_range" ///Called right before the atom changes the value of light_power to a different one, from base atom/set_light_power(): (new_power) diff --git a/code/__DEFINES/reagents.dm b/code/__DEFINES/reagents.dm index 23de112bf4a..c149c503a69 100644 --- a/code/__DEFINES/reagents.dm +++ b/code/__DEFINES/reagents.dm @@ -28,13 +28,6 @@ /// Used for direct injection of reagents. #define INJECT (1<<4) - -//defines passed through to the on_reagent_change proc -#define DEL_REAGENT 1 // reagent deleted (fully cleared) -#define ADD_REAGENT 2 // reagent added -#define REM_REAGENT 3 // reagent removed (may still exist) -#define CLEAR_REAGENTS 4 // all reagents were cleared - #define MIMEDRINK_SILENCE_DURATION 30 //ends up being 60 seconds given 1 tick every 2 seconds ///Health threshold for synthflesh and rezadone to unhusk someone #define UNHUSK_DAMAGE_THRESHOLD 50 diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm index d1fb0b72b11..f5069cf1237 100644 --- a/code/datums/components/crafting/crafting.dm +++ b/code/datums/components/crafting/crafting.dm @@ -252,7 +252,7 @@ RGNT.volume += RG.volume RGNT.data += RG.data qdel(RG) - RC.on_reagent_change() + SEND_SIGNAL(RC.reagents, COMSIG_REAGENTS_CRAFTING_PING) // - [] TODO: Make this entire thing less spaghetti else surroundings -= RC else if(ispath(A, /obj/item/stack)) diff --git a/code/datums/components/plumbing/reaction_chamber.dm b/code/datums/components/plumbing/reaction_chamber.dm index 3345eb0e76d..88d7c760a7d 100644 --- a/code/datums/components/plumbing/reaction_chamber.dm +++ b/code/datums/components/plumbing/reaction_chamber.dm @@ -35,4 +35,4 @@ RC.emptying = TRUE //If we move this up, it'll instantly get turned off since any reaction always sets the reagent_total to zero. Other option is make the reaction update //everything for every chemical removed, wich isn't a good option either. - RC.on_reagent_change() //We need to check it now, because some reactions leave nothing left. + RC.on_reagent_change(reagents) //We need to check it now, because some reactions leave nothing left. diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 51741c9cb9a..dd28dd55f43 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -47,6 +47,3 @@ . = list() if(("name" in vars) && !isatom(src)) . += "[vars["name"]]
" - -/datum/proc/on_reagent_change(changetype) - return diff --git a/code/game/atoms.dm b/code/game/atoms.dm index b18ae480a0a..d5a4206974a 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -506,6 +506,7 @@ if(. & COMPONENT_NO_EXPOSE_REAGENTS) return + SEND_SIGNAL(source, COMSIG_REAGENTS_EXPOSE_ATOM, src, reagents, methods, volume_modifier, show_message) for(var/reagent in reagents) var/datum/reagent/R = reagent . |= R.expose_atom(src, reagents[R]) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index c35e0ad7bc9..8c09dc27e01 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -365,6 +365,7 @@ if(. & COMPONENT_NO_EXPOSE_REAGENTS) return + SEND_SIGNAL(source, COMSIG_REAGENTS_EXPOSE_OBJ, src, reagents, methods, volume_modifier, show_message) for(var/reagent in reagents) var/datum/reagent/R = reagent . |= R.expose_obj(src, reagents[R]) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 24a99742210..67ac9215446 100755 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -592,6 +592,7 @@ GLOBAL_LIST_EMPTY(station_turfs) if(. & COMPONENT_NO_EXPOSE_REAGENTS) return + SEND_SIGNAL(source, COMSIG_REAGENTS_EXPOSE_TURF, src, reagents, methods, volume_modifier, show_message) for(var/reagent in reagents) var/datum/reagent/R = reagent . |= R.expose_turf(src, reagents[R]) diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm index eb2459a878b..0d45eb253c9 100644 --- a/code/modules/food_and_drinks/drinks/drinks.dm +++ b/code/modules/food_and_drinks/drinks/drinks.dm @@ -238,18 +238,16 @@ desc = "Either Nanotrasen's water supply is contaminated, or this machine actually vends lemon, chocolate, and cherry snow cones." list_reagents = list(/datum/reagent/consumable/ice = 25, /datum/reagent/liquidgibs = 5) -/obj/item/reagent_containers/food/drinks/mug/ // parent type is literally just so empty mug sprites are a thing +/obj/item/reagent_containers/food/drinks/mug // parent type is literally just so empty mug sprites are a thing name = "mug" desc = "A drink served in a classy mug." icon_state = "tea" inhand_icon_state = "coffee" spillable = TRUE -/obj/item/reagent_containers/food/drinks/mug/on_reagent_change(changetype) - if(reagents.total_volume) - icon_state = "tea" - else - icon_state = "tea_empty" +/obj/item/reagent_containers/food/drinks/mug/update_icon_state() + . = ..() + icon_state = reagents.total_volume ? "tea" : "tea_empty" /obj/item/reagent_containers/food/drinks/mug/tea name = "Duke Purple tea" @@ -450,11 +448,9 @@ spillable = TRUE isGlass = FALSE -/obj/item/reagent_containers/food/drinks/sillycup/on_reagent_change(changetype) - if(reagents.total_volume) - icon_state = "water_cup" - else - icon_state = "water_cup_e" +/obj/item/reagent_containers/food/drinks/sillycup/update_icon_state() + . = ..() + icon_state = reagents.total_volume ? "water_cup" : "water_cup_e" /obj/item/reagent_containers/food/drinks/sillycup/smallcarton name = "small carton" @@ -462,6 +458,66 @@ icon_state = "juicebox" volume = 15 //I figure if you have to craft these it should at least be slightly better than something you can get for free from a watercooler +/obj/item/reagent_containers/food/drinks/sillycup/smallcarton/on_reagent_change(datum/reagents/holder, ...) + . = ..() + if(!length(reagents.reagent_list)) + name = "small carton" + desc = "A small carton, intended for holding drinks." + foodtype = NONE + return + + switch(reagents.get_master_reagent_id()) // - [] TODO: Unshitcode this. Right now I'm just passing through and this really needs it's own dedicated PR. + if(/datum/reagent/consumable/orangejuice) + name = "orange juice box" // I know this shouldn't be here, but I really don't have the time to fix this right now. Blame the last guy + desc = "A great source of vitamins. Stay healthy!" // Ditto + foodtype = FRUIT | BREAKFAST // Ditto + if(/datum/reagent/consumable/milk) + name = "carton of milk" + desc = "An excellent source of calcium for growing space explorers." + foodtype = DAIRY | BREAKFAST + if(/datum/reagent/consumable/applejuice) + name = "apple juice box" + desc = "Sweet apple juice. Don't be late for school!" + foodtype = FRUIT + if(/datum/reagent/consumable/grapejuice) + name = "grape juice box" + desc = "Tasty grape juice in a fun little container. Non-alcoholic!" + foodtype = FRUIT + if(/datum/reagent/consumable/pineapplejuice) + name = "pineapple juice box" + desc = "Why would you even want this?" + foodtype = FRUIT | PINEAPPLE + if(/datum/reagent/consumable/milk/chocolate_milk) + name = "carton of chocolate milk" + desc = "Milk for cool kids!" + foodtype = SUGAR + if(/datum/reagent/consumable/ethanol/eggnog) + name = "carton of eggnog" + desc = "For enjoying the most wonderful time of the year." + foodtype = MEAT + +/obj/item/reagent_containers/food/drinks/sillycup/smallcarton/update_icon_state() + . = ..() + if(!length(reagents.reagent_list)) + icon_state = "juicebox" + return + + switch(reagents.get_master_reagent_id()) // Thanks to update_name not existing we need to do this whole switch twice + if(/datum/reagent/consumable/orangejuice) + icon_state = "orangebox" + if(/datum/reagent/consumable/milk) + icon_state = "milkbox" + if(/datum/reagent/consumable/applejuice) + icon_state = "juicebox" + if(/datum/reagent/consumable/grapejuice) + icon_state = "grapebox" + if(/datum/reagent/consumable/pineapplejuice) + icon_state = "pineapplebox" + if(/datum/reagent/consumable/milk/chocolate_milk) + icon_state = "chocolatebox" + if(/datum/reagent/consumable/ethanol/eggnog) + icon_state = "nog2" + /obj/item/reagent_containers/food/drinks/sillycup/smallcarton/smash(atom/target, mob/thrower, ranged = FALSE) if(bartender_check(target) && ranged) return @@ -479,50 +535,6 @@ qdel(src) target.Bumped(B) -/obj/item/reagent_containers/food/drinks/sillycup/smallcarton/on_reagent_change(changetype) - if (reagents.reagent_list.len) - switch(reagents.get_master_reagent_id()) - if(/datum/reagent/consumable/orangejuice) - icon_state = "orangebox" - name = "orange juice box" - desc = "A great source of vitamins. Stay healthy!" - foodtype = FRUIT | BREAKFAST - if(/datum/reagent/consumable/milk) - icon_state = "milkbox" - name = "carton of milk" - desc = "An excellent source of calcium for growing space explorers." - foodtype = DAIRY | BREAKFAST - if(/datum/reagent/consumable/applejuice) - icon_state = "juicebox" - name = "apple juice box" - desc = "Sweet apple juice. Don't be late for school!" - foodtype = FRUIT - if(/datum/reagent/consumable/grapejuice) - icon_state = "grapebox" - name = "grape juice box" - desc = "Tasty grape juice in a fun little container. Non-alcoholic!" - foodtype = FRUIT - if(/datum/reagent/consumable/pineapplejuice) - icon_state = "pineapplebox" - name = "pineapple juice box" - desc = "Why would you even want this?" - foodtype = FRUIT | PINEAPPLE - if(/datum/reagent/consumable/milk/chocolate_milk) - icon_state = "chocolatebox" - name = "carton of chocolate milk" - desc = "Milk for cool kids!" - foodtype = SUGAR - if(/datum/reagent/consumable/ethanol/eggnog) - icon_state = "nog2" - name = "carton of eggnog" - desc = "For enjoying the most wonderful time of the year." - foodtype = MEAT - else - icon_state = "juicebox" - name = "small carton" - desc = "A small carton, intended for holding drinks." - - /obj/item/reagent_containers/food/drinks/colocup name = "colo cup" desc = "A cheap, mass produced style of cup, typically used at parties. They never seem to come out red, for some reason..." diff --git a/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm b/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm index 6c8002861cc..5ecf173cf3c 100644 --- a/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm +++ b/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm @@ -15,23 +15,38 @@ pickup_sound = 'sound/items/handling/drinkglass_pickup.ogg' custom_price = PAYCHECK_PRISONER -/obj/item/reagent_containers/food/drinks/drinkingglass/on_reagent_change(changetype) - cut_overlays() - if(reagents.reagent_list.len) - var/datum/reagent/R = reagents.get_master_reagent() - if(!renamedByPlayer) - name = R.glass_name - desc = R.glass_desc - if(R.glass_icon_state) - icon_state = R.glass_icon_state - else - var/mutable_appearance/reagent_overlay = mutable_appearance(icon, "glassoverlay") - icon_state = "glass_empty" - reagent_overlay.color = mix_color_from_reagents(reagents.reagent_list) - add_overlay(reagent_overlay) - else - icon_state = "glass_empty" +/obj/item/reagent_containers/food/drinks/drinkingglass/on_reagent_change(datum/reagents/holder, ...) + . = ..() + if(!length(reagents.reagent_list)) renamedByPlayer = FALSE //so new drinks can rename the glass + return + + if(renamedByPlayer) + return + + var/datum/reagent/largest_reagent = reagents.get_master_reagent() + name = largest_reagent.glass_name || initial(name) + desc = largest_reagent.glass_desc || initial(desc) + +/obj/item/reagent_containers/food/drinks/drinkingglass/update_icon_state() + . = ..() + if(!length(reagents.reagent_list)) + icon_state = "glass_empty" + return + + var/datum/reagent/largest_reagent = reagents.get_master_reagent() + if(largest_reagent.glass_icon_state) + icon_state = largest_reagent.glass_icon_state + return NONE + +/obj/item/reagent_containers/food/drinks/drinkingglass/update_overlays() + . = ..() + if(icon_state != initial(icon_state)) + return + + var/mutable_appearance/reagent_overlay = mutable_appearance(icon, "glassoverlay") + reagent_overlay.color = mix_color_from_reagents(reagents.reagent_list) + . += reagent_overlay //Shot glasses!// // This lets us add shots in here instead of lumping them in with drinks because >logic // @@ -51,34 +66,37 @@ custom_materials = list(/datum/material/glass=100) custom_price = PAYCHECK_ASSISTANT * 0.4 -/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass/on_reagent_change(changetype) - cut_overlays() +/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass/on_reagent_change(datum/reagents/holder, ...) + . = ..() + if(!length(reagents.reagent_list)) + name = "shot glass" + desc = "A shot glass - the universal symbol for bad decisions." + return - gulp_size = max(round(reagents.total_volume / 15), 15) + name = "filled shot glass" + desc = "The challenge is not taking as many as you can, but guessing what it is before you pass out." - if (reagents.reagent_list.len > 0) - var/datum/reagent/largest_reagent = reagents.get_master_reagent() - name = "filled shot glass" - desc = "The challenge is not taking as many as you can, but guessing what it is before you pass out." - - if(largest_reagent.shot_glass_icon_state) - icon_state = largest_reagent.shot_glass_icon_state - else - icon_state = "shotglassclear" - var/mutable_appearance/shot_overlay = mutable_appearance(icon, "shotglassoverlay") - shot_overlay.color = mix_color_from_reagents(reagents.reagent_list) - add_overlay(shot_overlay) - - - else +/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass/update_icon_state() + . = ..() + if(!length(reagents.reagent_list)) icon_state = "shotglass" name = "shot glass" desc = "A shot glass - the universal symbol for bad decisions." return -/obj/item/reagent_containers/food/drinks/drinkingglass/filled/Initialize() + var/datum/reagent/largest_reagent = reagents.get_master_reagent() + name = "filled shot glass" + desc = "The challenge is not taking as many as you can, but guessing what it is before you pass out." + icon_state = largest_reagent.shot_glass_icon_state || "shotglassclear" + +/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass/update_overlays() . = ..() - on_reagent_change(ADD_REAGENT) + if(icon_state != "shotglassclear") + return + + var/mutable_appearance/shot_overlay = mutable_appearance(icon, "shotglassoverlay") + shot_overlay.color = mix_color_from_reagents(reagents.reagent_list) + . += shot_overlay /obj/item/reagent_containers/food/drinks/drinkingglass/filled/soda name = "Soda Water" diff --git a/code/modules/food_and_drinks/food/condiment.dm b/code/modules/food_and_drinks/food/condiment.dm index 1381eaa7c01..35f4b688ea9 100644 --- a/code/modules/food_and_drinks/food/condiment.dm +++ b/code/modules/food_and_drinks/food/condiment.dm @@ -237,6 +237,11 @@ /// Can't use initial(name) for this. This stores the name set by condimasters. var/originalname = "condiment" +/obj/item/reagent_containers/food/condiment/pack/create_reagents(max_vol, flags) + . = ..() + RegisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_REM_REAGENT), .proc/on_reagent_add, TRUE) + RegisterSignal(reagents, COMSIG_REAGENTS_DEL_REAGENT, .proc/on_reagent_del, TRUE) + /obj/item/reagent_containers/food/condiment/pack/update_icon() return @@ -264,19 +269,23 @@ return . = ..() -/obj/item/reagent_containers/food/condiment/pack/on_reagent_change(changetype) - if(reagents.reagent_list.len > 0) - var/main_reagent = reagents.get_master_reagent_id() - if(main_reagent in possible_states) - var/list/temp_list = possible_states[main_reagent] - icon_state = temp_list[1] - desc = temp_list[3] - else - icon_state = "condi_mixed" - desc = "A small condiment pack. The label says it contains [originalname]" +/// Handles reagents getting added to the condiment pack. +/obj/item/reagent_containers/food/condiment/pack/proc/on_reagent_add(datum/reagents/reagents) + SIGNAL_HANDLER + var/main_reagent = reagents.get_master_reagent_id() + if(main_reagent in possible_states) + var/list/temp_list = possible_states[main_reagent] + icon_state = temp_list[1] + desc = temp_list[3] else - icon_state = "condi_empty" - desc = "A small condiment pack. It is empty." + icon_state = "condi_mixed" + desc = "A small condiment pack. The label says it contains [originalname]" + +/// Handles reagents getting removed from the condiment pack. +/obj/item/reagent_containers/food/condiment/pack/proc/on_reagent_del(datum/reagents/reagents) + SIGNAL_HANDLER + icon_state = "condi_empty" + desc = "A small condiment pack. It is empty." //Ketchup /obj/item/reagent_containers/food/condiment/pack/ketchup diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm index 49d036831b0..b580fada7a3 100644 --- a/code/modules/hydroponics/biogenerator.dm +++ b/code/modules/hydroponics/biogenerator.dm @@ -21,7 +21,6 @@ /obj/machinery/biogenerator/Initialize() . = ..() stored_research = new /datum/techweb/specialized/autounlocking/biogenerator - create_reagents(1000) /obj/machinery/biogenerator/Destroy() QDEL_NULL(beaker) @@ -62,9 +61,6 @@ if(in_range(user, src) || isobserver(user)) . += "The status display reads: Productivity at [productivity*100]%.
Matter consumption reduced by [(efficiency*25)-25]%.
Machine can hold up to [max_items] pieces of produce.
" -/obj/machinery/biogenerator/on_reagent_change(changetype) //When the reagents change, change the icon as well. - update_icon() - /obj/machinery/biogenerator/update_icon_state() if(panel_open) icon_state = "biogen-empty-o" diff --git a/code/modules/hydroponics/grown/replicapod.dm b/code/modules/hydroponics/grown/replicapod.dm index 189ef7a2e71..1c94513d525 100644 --- a/code/modules/hydroponics/grown/replicapod.dm +++ b/code/modules/hydroponics/grown/replicapod.dm @@ -31,36 +31,58 @@ create_reagents(volume, INJECTABLE|DRAWABLE) -/obj/item/seeds/replicapod/on_reagent_change(changetype) - if(changetype == ADD_REAGENT) - var/datum/reagent/blood/B = reagents.has_reagent(/datum/reagent/blood) - if(B) - if(B.data["mind"] && B.data["cloneable"]) - mind = B.data["mind"] - ckey = B.data["ckey"] - realName = B.data["real_name"] - blood_gender = B.data["gender"] - blood_type = B.data["blood_type"] - features = B.data["features"] - factions = B.data["factions"] - quirks = B.data["quirks"] - sampleDNA = B.data["blood_DNA"] - contains_sample = TRUE - visible_message("The [src] is injected with a fresh blood sample.") - log_cloning("[key_name(mind)]'s cloning record was added to [src] at [AREACOORD(src)].") - else - visible_message("The [src] rejects the sample!") +/obj/item/seeds/replicapod/create_reagents(max_vol, flags) + . = ..() + RegisterSignal(reagents, list(COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_NEW_REAGENT), .proc/on_reagent_add) + RegisterSignal(reagents, COMSIG_REAGENTS_DEL_REAGENT, .proc/on_reagent_del) + RegisterSignal(reagents, COMSIG_PARENT_QDELETING, .proc/on_reagents_del) - if(!reagents.has_reagent(/datum/reagent/blood)) - mind = null - ckey = null - realName = null - blood_gender = null - blood_type = null - features = null - factions = null - sampleDNA = null - contains_sample = FALSE +/// Handles the seeds' reagents datum getting deleted. +/obj/item/seeds/replicapod/proc/on_reagents_del(datum/reagents/reagents) + SIGNAL_HANDLER + UnregisterSignal(reagents, list(COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_PARENT_QDELETING)) + return NONE + +/// Handles reagents getting added to this seed. +/obj/item/seeds/replicapod/proc/on_reagent_add(datum/reagents/reagents) + SIGNAL_HANDLER + var/datum/reagent/blood/B = reagents.has_reagent(/datum/reagent/blood) + if(!B) + return + + if(B.data["mind"] && B.data["cloneable"]) + mind = B.data["mind"] + ckey = B.data["ckey"] + realName = B.data["real_name"] + blood_gender = B.data["gender"] + blood_type = B.data["blood_type"] + features = B.data["features"] + factions = B.data["factions"] + quirks = B.data["quirks"] + sampleDNA = B.data["blood_DNA"] + contains_sample = TRUE + visible_message("The [src] is injected with a fresh blood sample.") + log_cloning("[key_name(mind)]'s cloning record was added to [src] at [AREACOORD(src)].") + else + visible_message("The [src] rejects the sample!") + return NONE + +/// Handles reagents being deleted from these seeds. +/obj/item/seeds/replicapod/proc/on_reagent_del(changetype) + SIGNAL_HANDLER + if(reagents.has_reagent(/datum/reagent/blood)) + return + + mind = null + ckey = null + realName = null + blood_gender = null + blood_type = null + features = null + factions = null + sampleDNA = null + contains_sample = FALSE + return NONE /obj/item/seeds/replicapod/get_analyzer_text() var/text = ..() diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index 5d892fd00c7..5c411cb3df9 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -57,6 +57,17 @@ SSmobs.cubemonkeys -= src return ..() +/mob/living/carbon/monkey/create_reagents(max_vol, flags) + . = ..() + RegisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_DEL_REAGENT), .proc/on_reagent_change) + RegisterSignal(reagents, COMSIG_PARENT_QDELETING, .proc/on_reagents_del) + +/// Handles removing signal hooks incase someone is crazy enough to reset the reagents datum. +/mob/living/carbon/monkey/proc/on_reagents_del(datum/reagents/reagents) + SIGNAL_HANDLER + UnregisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_PARENT_QDELETING)) + return NONE + /mob/living/carbon/monkey/create_internal_organs() internal_organs += new /obj/item/organ/appendix internal_organs += new /obj/item/organ/lungs @@ -69,8 +80,13 @@ internal_organs += new /obj/item/organ/stomach ..() -/mob/living/carbon/monkey/on_reagent_change() - . = ..() +/** + * Snowflake handling for morphine and nuka cola speed mods. + * + * Should be moved to the reagents at some future point. As it is I'm in a hurry. + */ +/mob/living/carbon/monkey/proc/on_reagent_change(datum/reagents/holder, ...) + SIGNAL_HANDLER var/amount if(reagents.has_reagent(/datum/reagent/medicine/morphine)) amount = -1 @@ -78,6 +94,7 @@ amount = -1 if(amount) add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/monkey_reagent_speedmod, TRUE, amount) + return NONE /mob/living/carbon/monkey/updatehealth() . = ..() diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 25bac22a63e..4624c76a75f 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -437,6 +437,7 @@ taste(source) var/touch_protection = (methods & VAPOR) ? get_permeability_protection() : 0 + SEND_SIGNAL(source, COMSIG_REAGENTS_EXPOSE_MOB, src, reagents, methods, volume_modifier, show_message, touch_protection) for(var/reagent in reagents) var/datum/reagent/R = reagent . |= R.expose_mob(src, methods, reagents[R], show_message, touch_protection) diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index ec3f6eb2b9a..25e05c3ccb5 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -67,7 +67,6 @@ new /obj/item/stock_parts/cell/potato(Tsec) var/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass/S = new(Tsec) S.reagents.add_reagent(/datum/reagent/consumable/ethanol/whiskey, 15) - S.on_reagent_change(ADD_REAGENT) ..() /mob/living/simple_animal/bot/secbot/pingsky diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index 7c23346ee0e..c1507dc4e70 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -113,6 +113,17 @@ Friends = null return ..() +/mob/living/simple_animal/slime/create_reagents(max_vol, flags) + . = ..() + RegisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_DEL_REAGENT), .proc/on_reagent_change) + RegisterSignal(reagents, COMSIG_PARENT_QDELETING, .proc/on_reagents_del) + +/// Handles removing signal hooks incase someone is crazy enough to reset the reagents datum. +/mob/living/simple_animal/slime/proc/on_reagents_del(datum/reagents/reagents) + SIGNAL_HANDLER + UnregisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_PARENT_QDELETING)) + return NONE + /mob/living/simple_animal/slime/proc/set_colour(new_colour) colour = new_colour update_name() @@ -142,8 +153,13 @@ icon_state = icon_dead ..() -/mob/living/simple_animal/slime/on_reagent_change() - . = ..() +/** + * Snowflake handling of reagent movespeed modifiers + * + * Should be moved to the reagents at some point in the future. As it is I'm in a hurry. + */ +/mob/living/simple_animal/slime/proc/on_reagent_change(datum/reagents/holder, ...) + SIGNAL_HANDLER remove_movespeed_modifier(/datum/movespeed_modifier/slime_reagentmod) var/amount = 0 if(reagents.has_reagent(/datum/reagent/medicine/morphine)) // morphine slows slimes down @@ -152,6 +168,7 @@ amount = 5 if(amount) add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/slime_reagentmod, multiplicative_slowdown = amount) + return NONE /mob/living/simple_animal/slime/updatehealth() . = ..() diff --git a/code/modules/plumbing/plumbers/reaction_chamber.dm b/code/modules/plumbing/plumbers/reaction_chamber.dm index ee6275916bf..794987e5e04 100644 --- a/code/modules/plumbing/plumbers/reaction_chamber.dm +++ b/code/modules/plumbing/plumbers/reaction_chamber.dm @@ -17,10 +17,25 @@ . = ..() AddComponent(/datum/component/plumbing/reaction_chamber, bolt) -/obj/machinery/plumbing/reaction_chamber/on_reagent_change() - if(reagents.total_volume == 0 && emptying) //we were emptying, but now we aren't +/obj/machinery/plumbing/reaction_chamber/create_reagents(max_vol, flags) + . = ..() + RegisterSignal(reagents, list(COMSIG_REAGENTS_REM_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_CLEAR_REAGENTS, COMSIG_REAGENTS_REACTED), .proc/on_reagent_change) + RegisterSignal(reagents, COMSIG_PARENT_QDELETING, .proc/on_reagents_del) + +/// Handles properly detaching signal hooks. +/obj/machinery/plumbing/reaction_chamber/proc/on_reagents_del(datum/reagents/reagents) + SIGNAL_HANDLER + UnregisterSignal(reagents, list(COMSIG_REAGENTS_REM_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_CLEAR_REAGENTS, COMSIG_REAGENTS_REACTED, COMSIG_PARENT_QDELETING)) + return NONE + + +/// Handles stopping the emptying process when the chamber empties. +/obj/machinery/plumbing/reaction_chamber/proc/on_reagent_change(datum/reagents/holder, ...) + SIGNAL_HANDLER + if(holder.total_volume == 0 && emptying) //we were emptying, but now we aren't emptying = FALSE - reagents.flags |= NO_REACT + holder.flags |= NO_REACT + return NONE /obj/machinery/plumbing/reaction_chamber/power_change() . = ..() diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index fa54e9115fe..261aad8e259 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -38,6 +38,17 @@ desc += " This one has a rating of [DisplayEnergy(maxcharge)], and you should not swallow it." update_icon() +/obj/item/stock_parts/cell/create_reagents(max_vol, flags) + . = ..() + RegisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_REM_REAGENT), .proc/on_reagent_change) + RegisterSignal(reagents, COMSIG_PARENT_QDELETING, .proc/on_reagents_del) + +/// Handles properly detaching signal hooks. +/obj/item/stock_parts/cell/proc/on_reagents_del(datum/reagents/reagents) + SIGNAL_HANDLER + UnregisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_REM_REAGENT, COMSIG_PARENT_QDELETING)) + return NONE + /obj/item/stock_parts/cell/update_overlays() . = ..() if(grown_battery) @@ -86,9 +97,10 @@ user.visible_message("[user] is licking the electrodes of [src]! It looks like [user.p_theyre()] trying to commit suicide!") return (FIRELOSS) -/obj/item/stock_parts/cell/on_reagent_change(changetype) - rigged = (corrupted || reagents.has_reagent(/datum/reagent/toxin/plasma, 5)) //has_reagent returns the reagent datum - return ..() +/obj/item/stock_parts/cell/proc/on_reagent_change(datum/reagents/holder, ...) + SIGNAL_HANDLER + rigged = (corrupted || holder.has_reagent(/datum/reagent/toxin/plasma, 5)) ? TRUE : FALSE //has_reagent returns the reagent datum + return NONE /obj/item/stock_parts/cell/proc/explode() diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index e264eca6a2d..f1b5be2c2d4 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -925,11 +925,32 @@ if(status == LIGHT_BURNED || status == LIGHT_OK) shatter() -// attack bulb/tube with object -// if a syringe, can inject plasma to make it explode -/obj/item/light/on_reagent_change(changetype) - rigged = (reagents.has_reagent(/datum/reagent/toxin/plasma, LIGHT_REAGENT_CAPACITY)) //has_reagent returns the reagent datum - return ..() +/obj/item/light/create_reagents(max_vol, flags) + . = ..() + RegisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_REM_REAGENT), .proc/on_reagent_change) + RegisterSignal(reagents, COMSIG_PARENT_QDELETING, .proc/on_reagents_del) + +/** + * Handles rigging the cell if it contains enough plasma. + */ +/obj/item/light/proc/on_reagent_change(datum/reagents/holder, ...) + SIGNAL_HANDLER + rigged = (reagents.has_reagent(/datum/reagent/toxin/plasma, LIGHT_REAGENT_CAPACITY)) ? TRUE : FALSE //has_reagent returns the reagent datum, we don't want to hold a reference to prevent hard dels + return NONE + +/** + * Handles the reagent holder datum being deleted for some reason. Probably someone making pizza lights. + */ +/obj/item/light/proc/on_reagents_del(datum/reagents/holder) + SIGNAL_HANDLER + UnregisterSignal(holder, list( + COMSIG_PARENT_QDELETING, + COMSIG_REAGENTS_NEW_REAGENT, + COMSIG_REAGENTS_ADD_REAGENT, + COMSIG_REAGENTS_REM_REAGENT, + COMSIG_REAGENTS_DEL_REAGENT, + )) + return NONE #undef LIGHT_REAGENT_CAPACITY diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index 2e7f3ef203d..feb49c20db2 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -90,38 +90,130 @@ my_atom.reagents = null my_atom = null + /** - * Used in attack logs for reagents in pills and such + * Adds a reagent to this holder * * Arguments: - * * external_list - list of reagent types = amounts + * * reagent - The reagent id to add + * * amount - Amount to add + * * list/data - Any reagent data for this reagent, used for transferring data with reagents + * * reagtemp - Temperature of this reagent, will be equalized + * * no_react - prevents reactions being triggered by this addition */ -/datum/reagents/proc/log_list(external_list) - if((external_list && !length(external_list)) || !length(reagent_list)) - return "no reagents" +/datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = 300, no_react = 0) + if(!isnum(amount) || !amount) + return FALSE - var/list/data = list() - if(external_list) - for(var/r in external_list) - data += "[r] ([round(external_list[r], 0.1)]u)" - else - for(var/r in reagent_list) //no reagents will be left behind - var/datum/reagent/R = r - data += "[R.type] ([round(R.volume, 0.1)]u)" - //Using types because SOME chemicals (I'm looking at you, chlorhydrate-beer) have the same names as other chemicals. - return english_list(data) + if(amount <= 0) + return FALSE + + var/datum/reagent/glob_reagent = GLOB.chemical_reagents_list[reagent] + if(!glob_reagent) + WARNING("[my_atom] attempted to add a reagent called '[reagent]' which doesn't exist. ([usr])") + return FALSE + + update_total() + var/cached_total = total_volume + if(cached_total + amount > maximum_volume) + amount = (maximum_volume - cached_total) //Doesnt fit in. Make it disappear. shouldn't happen. Will happen. + if(amount <= 0) + return FALSE + + var/cached_temp = chem_temp + var/list/cached_reagents = reagent_list + + //Equalize temperature - Not using specific_heat() because the new chemical isn't in yet. + var/old_heat_capacity = 0 + if(reagtemp != cached_temp) + for(var/r in cached_reagents) + var/datum/reagent/iter_reagent = r + old_heat_capacity += iter_reagent.specific_heat * iter_reagent.volume + + //add the reagent to the existing if it exists + for(var/r in cached_reagents) + var/datum/reagent/iter_reagent = r + if (iter_reagent.type == reagent) + iter_reagent.volume += amount + update_total() + + iter_reagent.on_merge(data, amount) + if(reagtemp != cached_temp) + set_temperature(((old_heat_capacity * cached_temp) + (iter_reagent.specific_heat * amount * reagtemp)) / heat_capacity()) + + SEND_SIGNAL(src, COMSIG_REAGENTS_ADD_REAGENT, iter_reagent, amount, reagtemp, data, no_react) + if(!no_react) + handle_reactions() + return TRUE + + //otherwise make a new one + var/datum/reagent/new_reagent = new reagent(data) + cached_reagents += new_reagent + new_reagent.holder = src + new_reagent.volume = amount + if(data) + new_reagent.data = data + new_reagent.on_new(data) + + if(isliving(my_atom)) + new_reagent.on_mob_add(my_atom) //Must occur before it could posibly run on_mob_delete + + update_total() + if(reagtemp != cached_temp) + set_temperature(((old_heat_capacity * cached_temp) + (new_reagent.specific_heat * amount * reagtemp)) / heat_capacity()) + + SEND_SIGNAL(src, COMSIG_REAGENTS_NEW_REAGENT, new_reagent, amount, reagtemp, data, no_react) + if(!no_react) + handle_reactions() + return TRUE + +/// Like add_reagent but you can enter a list. Format it like this: list(/datum/reagent/toxin = 10, "beer" = 15) +/datum/reagents/proc/add_reagent_list(list/list_reagents, list/data=null) + for(var/r_id in list_reagents) + var/amt = list_reagents[r_id] + add_reagent(r_id, amt, data) + + +/// Remove a specific reagent +/datum/reagents/proc/remove_reagent(reagent, amount, safety)//Added a safety check for the trans_id_to + if(isnull(amount)) + amount = 0 + CRASH("null amount passed to reagent code") + + if(!isnum(amount)) + return FALSE + + if(amount < 0) + return FALSE + + var/list/cached_reagents = reagent_list + for(var/A in cached_reagents) + var/datum/reagent/R = A + if (R.type == reagent) + //clamp the removal amount to be between current reagent amount + //and zero, to prevent removing more than the holder has stored + amount = clamp(amount, 0, R.volume) + R.volume -= amount + update_total() + SEND_SIGNAL(src, COMSIG_REAGENTS_REM_REAGENT, QDELING(R) ? reagent : R, amount) + if(!safety)//So it does not handle reactions when it need not to + handle_reactions() + + return TRUE + + return FALSE /// Remove an amount of reagents without caring about what they are /datum/reagents/proc/remove_any(amount = 1) var/list/cached_reagents = reagent_list - var/total_transfered = 0 + var/total_removed = 0 var/current_list_element = 1 var/initial_list_length = cached_reagents.len //stored here because removing can cause some reagents to be deleted, ergo length change. current_list_element = rand(1, cached_reagents.len) - while(total_transfered != amount) - if(total_transfered >= amount) + while(total_removed != amount) + if(total_removed >= amount) break if(total_volume <= 0 || !cached_reagents.len) break @@ -130,16 +222,16 @@ current_list_element = 1 var/datum/reagent/R = cached_reagents[current_list_element] - var/remove_amt = min(amount-total_transfered,round(amount/rand(2,initial_list_length),round(amount/10,0.01))) //double round to keep it at a somewhat even spread relative to amount without getting funky numbers. + var/remove_amt = min(amount-total_removed,round(amount/rand(2,initial_list_length),round(amount/10,0.01))) //double round to keep it at a somewhat even spread relative to amount without getting funky numbers. //min ensures we don't go over amount. remove_reagent(R.type, remove_amt) current_list_element++ - total_transfered += remove_amt + total_removed += remove_amt update_total() handle_reactions() - return total_transfered //this should be amount unless the loop is prematurely broken, in which case it'll be lower. It shouldn't ever go OVER amount. + return total_removed //this should be amount unless the loop is prematurely broken, in which case it'll be lower. It shouldn't ever go OVER amount. /// Removes all reagents from this holder /datum/reagents/proc/remove_all(amount = 1) @@ -154,44 +246,90 @@ handle_reactions() return amount -/// Get the name of the reagent there is the most of in this holder -/datum/reagents/proc/get_master_reagent_name() +/// Removes all reagent of X type. @strict set to 1 determines whether the childs of the type are included. +/datum/reagents/proc/remove_all_type(reagent_type, amount, strict = 0, safety = 1) + if(!isnum(amount)) + return 1 var/list/cached_reagents = reagent_list - var/name - var/max_volume = 0 + var/has_removed_reagent = 0 + for(var/reagent in cached_reagents) var/datum/reagent/R = reagent - if(R.volume > max_volume) - max_volume = R.volume - name = R.name + var/matches = 0 + // Switch between how we check the reagent type + if(strict) + if(R.type == reagent_type) + matches = 1 + else + if(istype(R, reagent_type)) + matches = 1 + // We found a match, proceed to remove the reagent. Keep looping, we might find other reagents of the same type. + if(matches) + // Have our other proc handle removement + has_removed_reagent = remove_reagent(R.type, amount, safety) - return name + return has_removed_reagent -/// Get the id of the reagent there is the most of in this holder -/datum/reagents/proc/get_master_reagent_id() +/// Fuck this one reagent +/datum/reagents/proc/del_reagent(reagent) + var/list/cached_reagents = reagent_list + for(var/_reagent in cached_reagents) + var/datum/reagent/R = _reagent + if(R.type == reagent) + if(isliving(my_atom)) + if(R.metabolizing) + R.metabolizing = FALSE + R.on_mob_end_metabolize(my_atom) + R.on_mob_delete(my_atom) + + //Clear from relevant lists + LAZYREMOVE(addiction_list, R) + reagent_list -= R + qdel(R) + update_total() + SEND_SIGNAL(src, COMSIG_REAGENTS_DEL_REAGENT, reagent) + return TRUE + +/// Remove every reagent except this one +/datum/reagents/proc/isolate_reagent(reagent) + var/list/cached_reagents = reagent_list + for(var/_reagent in cached_reagents) + var/datum/reagent/R = _reagent + if(R.type != reagent) + del_reagent(R.type) + update_total() + +/// Removes all reagents +/datum/reagents/proc/clear_reagents() var/list/cached_reagents = reagent_list - var/max_type - var/max_volume = 0 for(var/reagent in cached_reagents) var/datum/reagent/R = reagent - if(R.volume > max_volume) - max_volume = R.volume - max_type = R.type + del_reagent(R.type) + SEND_SIGNAL(src, COMSIG_REAGENTS_CLEAR_REAGENTS) - return max_type -/// Get a reference to the reagent there is the most of in this holder -/datum/reagents/proc/get_master_reagent() +/** + * Check if this holder contains this reagent. + * Reagent takes a PATH to a reagent. + * Amount checks for having a specific amount of that chemical. + * Needs matabolizing takes into consideration if the chemical is matabolizing when it's checked. + */ +/datum/reagents/proc/has_reagent(reagent, amount = -1, needs_metabolizing = FALSE) var/list/cached_reagents = reagent_list - var/datum/reagent/master - var/max_volume = 0 - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.volume > max_volume) - max_volume = R.volume - master = R + for(var/_reagent in cached_reagents) + var/datum/reagent/R = _reagent + if (R.type == reagent) + if(!amount) + if(needs_metabolizing && !R.metabolizing) + return FALSE + return R + else + if(round(R.volume, CHEMICAL_QUANTISATION_LEVEL) >= amount) + if(needs_metabolizing && !R.metabolizing) + return FALSE + return R + return FALSE - return master /** * Transfer some stuff from this holder to a target object @@ -292,6 +430,35 @@ src.handle_reactions() return amount +/// Transfer a specific reagent id to the target object +/datum/reagents/proc/trans_id_to(obj/target, reagent, amount=1, preserve_data=1)//Not sure why this proc didn't exist before. It does now! /N + var/list/cached_reagents = reagent_list + if (!target) + return + if (!target.reagents || src.total_volume<=0 || !src.get_reagent_amount(reagent)) + return + if(amount < 0) + return + + var/datum/reagents/R = target.reagents + if(src.get_reagent_amount(reagent) max_volume) + max_volume = R.volume + name = R.name - var/datum/reagents/R = target.reagents - if(src.get_reagent_amount(reagent) max_volume) + max_volume = R.volume + max_type = R.type + + return max_type + +/// Get a reference to the reagent there is the most of in this holder +/datum/reagents/proc/get_master_reagent() + var/list/cached_reagents = reagent_list + var/datum/reagent/master + var/max_volume = 0 + for(var/reagent in cached_reagents) + var/datum/reagent/R = reagent + if(R.volume > max_volume) + max_volume = R.volume + master = R + + return master /** * Triggers metabolizing the reagents in this holder @@ -448,13 +626,6 @@ C.update_stamina() update_total() -/// Removes addiction to a specific reagent on [/datum/reagents/var/my_atom] -/datum/reagents/proc/remove_addiction(datum/reagent/R) - to_chat(my_atom, "You feel like you've gotten over your need for [R.name].") - SEND_SIGNAL(my_atom, COMSIG_CLEAR_MOOD_EVENT, "[R.type]_overdose") - LAZYREMOVE(addiction_list, R) - qdel(R) - /// Signals that metabolization has stopped, triggering the end of trait-based effects /datum/reagents/proc/end_metabolization(mob/living/carbon/C, keep_liverless = TRUE) var/list/cached_reagents = reagent_list @@ -470,6 +641,14 @@ R.metabolizing = FALSE R.on_mob_end_metabolize(C) +/// Removes addiction to a specific reagent on [/datum/reagents/var/my_atom] +/datum/reagents/proc/remove_addiction(datum/reagent/R) + to_chat(my_atom, "You feel like you've gotten over your need for [R.name].") + SEND_SIGNAL(my_atom, COMSIG_CLEAR_MOOD_EVENT, "[R.type]_overdose") + LAZYREMOVE(addiction_list, R) + qdel(R) + + /** * Calls [/datum/reagent/proc/on_move] on every reagent in this holder * @@ -481,7 +660,7 @@ var/list/cached_reagents = reagent_list for(var/reagent in cached_reagents) var/datum/reagent/R = reagent - R.on_move (A, Running) + R.on_move(A, Running) update_total() /** @@ -494,22 +673,23 @@ var/list/cached_reagents = reagent_list for(var/reagent in cached_reagents) var/datum/reagent/R = reagent - R.on_update (A) + R.on_update(A) update_total() /// Handle any reactions possible in this holder /datum/reagents/proc/handle_reactions() if(flags & NO_REACT) - return //Yup, no reactions here. No siree. + return 0 //Yup, no reactions here. No siree. var/list/cached_reagents = reagent_list var/list/cached_reactions = GLOB.chemical_reactions_list var/datum/cached_my_atom = my_atom - var/reaction_occurred = 0 + . = 0 + var/reaction_occurred do var/list/possible_reactions = list() - reaction_occurred = 0 + reaction_occurred = FALSE for(var/reagent in cached_reagents) var/datum/reagent/R = reagent for(var/reaction in cached_reactions[R.type]) // Was a big list but now it should be smaller since we filtered it with our reagent id @@ -610,40 +790,14 @@ ME2.desc = "This extract has been used up." selected_reaction.on_reaction(src, multiplier) - reaction_occurred = 1 + reaction_occurred = TRUE + .++ while(reaction_occurred) update_total() + if(.) + SEND_SIGNAL(src, COMSIG_REAGENTS_REACTED, .) -/// Remove every reagent except this one -/datum/reagents/proc/isolate_reagent(reagent) - var/list/cached_reagents = reagent_list - for(var/_reagent in cached_reagents) - var/datum/reagent/R = _reagent - if(R.type != reagent) - del_reagent(R.type) - update_total() - -/// Fuck this one reagent -/datum/reagents/proc/del_reagent(reagent) - var/list/cached_reagents = reagent_list - for(var/_reagent in cached_reagents) - var/datum/reagent/R = _reagent - if(R.type == reagent) - if(isliving(my_atom)) - if(R.metabolizing) - R.metabolizing = FALSE - R.on_mob_end_metabolize(my_atom) - R.on_mob_delete(my_atom) - - //Clear from relevant lists - LAZYREMOVE(addiction_list, R) - reagent_list -= R - qdel(R) - update_total() - if(my_atom) - my_atom.on_reagent_change(DEL_REAGENT) - return 1 /// Updates [/datum/reagents/var/total_volume] /datum/reagents/proc/update_total() @@ -656,16 +810,6 @@ else total_volume += R.volume - -/// Removes all reagents -/datum/reagents/proc/clear_reagents() - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - del_reagent(R.type) - if(my_atom) - my_atom.on_reagent_change(CLEAR_REAGENTS) - /** * Applies the relevant expose_ proc for every reagent in this holder * * [/datum/reagent/proc/expose_mob] @@ -713,155 +857,6 @@ return TRUE return FALSE -/// Returns the average specific heat for all reagents currently in this holder. -/datum/reagents/proc/specific_heat() - . = 0 - var/cached_amount = total_volume //cache amount - var/list/cached_reagents = reagent_list //cache reagents - for(var/I in cached_reagents) - var/datum/reagent/R = I - . += R.specific_heat * (R.volume / cached_amount) - -/datum/reagents/proc/adjust_thermal_energy(J, min_temp = 2.7, max_temp = 1000) - var/S = specific_heat() - chem_temp = clamp(chem_temp + (J / (S * total_volume)), 2.7, 1000) - -/** - * Adds a reagent to this holder - * - * Arguments: - * * reagent - The reagent id to add - * * amount - Amount to add - * * list/data - Any reagent data for this reagent, used for transferring data with reagents - * * reagtemp - Temperature of this reagent, will be equalized - * * no_react - prevents reactions being triggered by this addition - */ -/datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = 300, no_react = 0) - if(!isnum(amount) || !amount) - return FALSE - - if(amount <= 0) - return FALSE - - var/datum/reagent/D = GLOB.chemical_reagents_list[reagent] - if(!D) - WARNING("[my_atom] attempted to add a reagent called '[reagent]' which doesn't exist. ([usr])") - return FALSE - - update_total() - var/cached_total = total_volume - if(cached_total + amount > maximum_volume) - amount = (maximum_volume - cached_total) //Doesnt fit in. Make it disappear. shouldn't happen. Will happen. - if(amount <= 0) - return FALSE - var/new_total = cached_total + amount - var/cached_temp = chem_temp - var/list/cached_reagents = reagent_list - - //Equalize temperature - Not using specific_heat() because the new chemical isn't in yet. - var/specific_heat = 0 - var/thermal_energy = 0 - for(var/i in cached_reagents) - var/datum/reagent/R = i - specific_heat += R.specific_heat * (R.volume / new_total) - thermal_energy += R.specific_heat * R.volume * cached_temp - specific_heat += D.specific_heat * (amount / new_total) - thermal_energy += D.specific_heat * amount * reagtemp - chem_temp = thermal_energy / (specific_heat * new_total) - //// - - //add the reagent to the existing if it exists - for(var/A in cached_reagents) - var/datum/reagent/R = A - if (R.type == reagent) - R.volume += amount - update_total() - if(my_atom) - my_atom.on_reagent_change(ADD_REAGENT) - R.on_merge(data, amount) - if(!no_react) - handle_reactions() - return TRUE - - //otherwise make a new one - var/datum/reagent/R = new D.type(data) - cached_reagents += R - R.holder = src - R.volume = amount - if(data) - R.data = data - R.on_new(data) - - if(isliving(my_atom)) - R.on_mob_add(my_atom) //Must occur before it could posibly run on_mob_delete - - update_total() - if(my_atom) - my_atom.on_reagent_change(ADD_REAGENT) - if(!no_react) - handle_reactions() - return TRUE - -/// Like add_reagent but you can enter a list. Format it like this: list(/datum/reagent/toxin = 10, "beer" = 15) -/datum/reagents/proc/add_reagent_list(list/list_reagents, list/data=null) - for(var/r_id in list_reagents) - var/amt = list_reagents[r_id] - add_reagent(r_id, amt, data) - -/// Remove a specific reagent -/datum/reagents/proc/remove_reagent(reagent, amount, safety)//Added a safety check for the trans_id_to - - if(isnull(amount)) - amount = 0 - CRASH("null amount passed to reagent code") - - if(!isnum(amount)) - return FALSE - - if(amount < 0) - return FALSE - - var/list/cached_reagents = reagent_list - - for(var/A in cached_reagents) - var/datum/reagent/R = A - if (R.type == reagent) - //clamp the removal amount to be between current reagent amount - //and zero, to prevent removing more than the holder has stored - amount = clamp(amount, 0, R.volume) - R.volume -= amount - update_total() - if(!safety)//So it does not handle reactions when it need not to - handle_reactions() - if(my_atom) - my_atom.on_reagent_change(REM_REAGENT) - return TRUE - - return FALSE - - -/* -Check if this holder contains this reagent. -Reagent takes a PATH to a reagent. -Amount checks for having a specific amount of that chemical. -Needs matabolizing takes into consideration if the chemical is matabolizing when it's checked. -*/ -/datum/reagents/proc/has_reagent(reagent, amount = -1, needs_metabolizing = FALSE) - var/list/cached_reagents = reagent_list - for(var/_reagent in cached_reagents) - var/datum/reagent/R = _reagent - if (R.type == reagent) - if(!amount) - if(needs_metabolizing && !R.metabolizing) - return FALSE - return R - else - if(round(R.volume, CHEMICAL_QUANTISATION_LEVEL) >= amount) - if(needs_metabolizing && !R.metabolizing) - return FALSE - return R - return FALSE - /// Get the amount of this reagent /datum/reagents/proc/get_reagent_amount(reagent) var/list/cached_reagents = reagent_list @@ -871,8 +866,8 @@ Needs matabolizing takes into consideration if the chemical is matabolizing when return round(R.volume, CHEMICAL_QUANTISATION_LEVEL) return 0 -/// Get a comma separated string of every reagent name in this holder -/datum/reagents/proc/get_reagents() +/// Get a comma separated string of every reagent name in this holder. UNUSED +/datum/reagents/proc/get_reagent_names() var/list/names = list() var/list/cached_reagents = reagent_list for(var/reagent in cached_reagents) @@ -881,30 +876,6 @@ Needs matabolizing takes into consideration if the chemical is matabolizing when return jointext(names, ",") -/// Removes all reagent of X type. @strict set to 1 determines whether the childs of the type are included. -/datum/reagents/proc/remove_all_type(reagent_type, amount, strict = 0, safety = 1) - if(!isnum(amount)) - return 1 - var/list/cached_reagents = reagent_list - var/has_removed_reagent = 0 - - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - var/matches = 0 - // Switch between how we check the reagent type - if(strict) - if(R.type == reagent_type) - matches = 1 - else - if(istype(R, reagent_type)) - matches = 1 - // We found a match, proceed to remove the reagent. Keep looping, we might find other reagents of the same type. - if(matches) - // Have our other proc handle removement - has_removed_reagent = remove_reagent(R.type, amount, safety) - - return has_removed_reagent - /// helper function to preserve data across reactions (needed for xenoarch) /datum/reagents/proc/get_data(reagent_id) var/list/cached_reagents = reagent_list @@ -988,6 +959,26 @@ Needs matabolizing takes into consideration if the chemical is matabolizing when return english_list(out, "something indescribable") + +/// Returns the total heat capacity for all of the reagents currently in this holder. +/datum/reagents/proc/heat_capacity() + . = 0 + var/list/cached_reagents = reagent_list //cache reagents + for(var/I in cached_reagents) + var/datum/reagent/R = I + . += R.specific_heat * R.volume + +/** Adjusts the thermal energy of the reagents in this holder by an amount. + * + * Arguments: + * - delta_energy: The amount to change the thermal energy by. + * - min_temp: The minimum temperature that can be reached. + * - max_temp: The maximum temperature that can be reached. + */ +/datum/reagents/proc/adjust_thermal_energy(delta_energy, min_temp = 2.7, max_temp = 1000) + var/heat_capacity = heat_capacity() + set_temperature(clamp(chem_temp + (delta_energy / heat_capacity), min_temp, max_temp)) + /// Applies heat to this holder /datum/reagents/proc/expose_temperature(temperature, coeff=0.02) if(istype(my_atom,/obj/item/reagent_containers)) @@ -999,12 +990,46 @@ Needs matabolizing takes into consideration if the chemical is matabolizing when chem_temp = min(chem_temp + max(temp_delta, 1), temperature) else chem_temp = max(chem_temp + min(temp_delta, -1), temperature) - chem_temp = round(chem_temp) - for(var/i in reagent_list) - var/datum/reagent/R = i - R.on_temp_change() + set_temperature(round(chem_temp)) handle_reactions() +/** Sets the temperature of this reagent container to a new value. + * + * Handles setter signals. + * + * Arguments: + * - _temperature: The new temperature value. + */ +/datum/reagents/proc/set_temperature(_temperature) + if(_temperature == chem_temp) + return + + . = chem_temp + chem_temp = _temperature + SEND_SIGNAL(src, COMSIG_REAGENTS_TEMP_CHANGE, _temperature, .) + + +/** + * Used in attack logs for reagents in pills and such + * + * Arguments: + * * external_list - list of reagent types = amounts + */ +/datum/reagents/proc/log_list(external_list) + if((external_list && !length(external_list)) || !length(reagent_list)) + return "no reagents" + + var/list/data = list() + if(external_list) + for(var/r in external_list) + data += "[r] ([round(external_list[r], 0.1)]u)" + else + for(var/r in reagent_list) //no reagents will be left behind + var/datum/reagent/R = r + data += "[R.type] ([round(R.volume, 0.1)]u)" + //Using types because SOME chemicals (I'm looking at you, chlorhydrate-beer) have the same names as other chemicals. + return english_list(data) + /////////////////////////////////////////////////////////////////////////////////// @@ -1024,7 +1049,7 @@ Needs matabolizing takes into consideration if the chemical is matabolizing when /proc/get_random_reagent_id() // Returns a random reagent ID minus blacklisted reagents var/static/list/random_reagents = list() if(!random_reagents.len) - for(var/thing in subtypesof(/datum/reagent)) + for(var/thing in subtypesof(/datum/reagent)) var/datum/reagent/R = thing if(initial(R.can_synth)) random_reagents += R diff --git a/code/modules/reagents/chemistry/readme.md b/code/modules/reagents/chemistry/readme.md index 3ead7a5d185..9acfb65fc76 100644 --- a/code/modules/reagents/chemistry/readme.md +++ b/code/modules/reagents/chemistry/readme.md @@ -14,9 +14,6 @@ Structure: /////////////////// ////////////////////////// reagents (datums) Reagents. I.e. Water , cryoxadone or mercury. ``` -# Random important notes: -An objects on_reagent_change will be called every time the objects reagents change. Useful if you want to update the objects icon etc. - # About the Holder: The holder (reagents datum) is the datum that holds a list of all reagents currently in the object.It also has all the procs needed to manipulate reagents ``` diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index cbf8e1a2d11..5f27bcbe39a 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -165,9 +165,6 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) /datum/reagent/proc/on_update(atom/A) return -///called on expose_temperature -/datum/reagent/proc/on_temp_change() - return /// Called when the reagent container is hit by an explosion /datum/reagent/proc/on_ex_act(severity) return diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index 5f47738756c..1af7487fb76 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -2028,8 +2028,6 @@ All effects don't start immediately, but rather get worse over time; the rate is flavor += ", with a hint of " flavor += english_list(secondary_tastes) taste_description = flavor - if(holder.my_atom) - holder.my_atom.on_reagent_change() /datum/reagent/consumable/ethanol/champagne //How the hell did we not have champagne already!? diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index 91ca8b0821a..3ab31b8fe19 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -73,19 +73,31 @@ material = /datum/material/plasma penetrates_skin = NONE +/datum/reagent/toxin/plasma/on_new(data) + . = ..() + RegisterSignal(holder, COMSIG_REAGENTS_TEMP_CHANGE, .proc/on_temp_change) + +/datum/reagent/toxin/plasma/Destroy() + UnregisterSignal(holder, COMSIG_REAGENTS_TEMP_CHANGE) + return ..() + /datum/reagent/toxin/plasma/on_mob_life(mob/living/carbon/C) if(holder.has_reagent(/datum/reagent/medicine/epinephrine)) holder.remove_reagent(/datum/reagent/medicine/epinephrine, 2*REM) C.adjustPlasma(20) return ..() -/datum/reagent/toxin/plasma/on_temp_change() +/// Handles plasma boiling. +/datum/reagent/toxin/plasma/proc/on_temp_change(datum/reagents/_holder, old_temp) + SIGNAL_HANDLER if(holder.chem_temp < LIQUID_PLASMA_BP) return - if(holder.my_atom) - var/atom/A = holder.my_atom - A.atmos_spawn_air("plasma=[volume];TEMP=[holder.chem_temp]") - holder.del_reagent(type) + if(!holder.my_atom) + return + + var/atom/A = holder.my_atom + A.atmos_spawn_air("plasma=[volume];TEMP=[holder.chem_temp]") + holder.del_reagent(type) /datum/reagent/toxin/plasma/expose_turf(turf/open/exposed_turf, reac_volume) if(!istype(exposed_turf)) diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index 295a1da9dcf..9e3f0968a0a 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -27,6 +27,19 @@ add_initial_reagents() +/obj/item/reagent_containers/create_reagents(max_vol, flags) + . = ..() + RegisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_REM_REAGENT), .proc/on_reagent_change) + RegisterSignal(reagents, COMSIG_PARENT_QDELETING, .proc/on_reagents_del) + +/obj/item/reagent_containers/Destroy() + return ..() + +/obj/item/reagent_containers/proc/on_reagents_del(datum/reagents/reagents) + SIGNAL_HANDLER + UnregisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_REM_REAGENT, COMSIG_PARENT_QDELETING)) + return NONE + /obj/item/reagent_containers/proc/add_initial_reagents() if(list_reagents) reagents.add_reagent_list(list_reagents) @@ -135,8 +148,11 @@ /obj/item/reagent_containers/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) reagents.expose_temperature(exposed_temperature) -/obj/item/reagent_containers/on_reagent_change(changetype) +/// Updates the icon of the container when the reagents change. Eats signal args +/obj/item/reagent_containers/proc/on_reagent_change(datum/reagents/holder, ...) + SIGNAL_HANDLER update_icon() + return NONE /obj/item/reagent_containers/update_overlays() . = ..() diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm index 0ff2618f661..a3b3954941e 100644 --- a/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -15,22 +15,21 @@ reagents.add_reagent(unique_blood ? unique_blood : /datum/reagent/blood, 200, list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=blood_type,"resistances"=null,"trace_chem"=null)) update_icon() -/obj/item/reagent_containers/blood/on_reagent_change(changetype) - if(reagents) - var/datum/reagent/blood/B = reagents.has_reagent(/datum/reagent/blood) - if(B && B.data && B.data["blood_type"]) - blood_type = B.data["blood_type"] - else - blood_type = null +/// Handles updating the container when the reagents change. +/obj/item/reagent_containers/blood/on_reagent_change(datum/reagents/holder, ...) + var/datum/reagent/blood/B = holder.has_reagent(/datum/reagent/blood) + if(B && B.data && B.data["blood_type"]) + blood_type = B.data["blood_type"] + else + blood_type = null update_pack_name() - update_icon() + return ..() /obj/item/reagent_containers/blood/proc/update_pack_name() - if(!labelled) - if(blood_type) - name = "blood pack - [blood_type]" - else - name = "blood pack" + if(labelled) + return + + name = "blood_pack[blood_type ? " - [blood_type]" : ""]" /obj/item/reagent_containers/blood/random icon_state = "random_bloodpack" diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm index 3ca6fef15ba..77bb6f94e1f 100644 --- a/code/modules/reagents/reagent_containers/borghydro.dm +++ b/code/modules/reagents/reagent_containers/borghydro.dm @@ -54,7 +54,6 @@ Borg Hypospray regenerate_reagents() charge_timer = 0 - //update_icon() return 1 // Use this to add more chemicals for the borghypo to produce. diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 469ed5b2c02..b3e8eca4502 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -144,18 +144,23 @@ reagents.expose(usr.loc) src.reagents.clear_reagents() -/obj/item/reagent_containers/spray/on_reagent_change(changetype) - var/total_reagent_weight - var/amount_of_reagents - for (var/datum/reagent/R in reagents.reagent_list) - total_reagent_weight = total_reagent_weight + R.reagent_weight - amount_of_reagents++ +/// Handles updating the spreay distance when the reagents change. +/obj/item/reagent_containers/spray/on_reagent_change(datum/reagents/holder, ...) + . = ..() + var/total_reagent_weight = 0 + var/number_of_reagents = 0 + var/amount_of_reagents = holder.total_volume + var/list/cached_reagents = holder.reagent_list + for(var/datum/reagent/reagent in cached_reagents) + total_reagent_weight += reagent.reagent_weight * reagent.volume + number_of_reagents++ - if(total_reagent_weight && amount_of_reagents) //don't bother if the container is empty - DIV/0 + if(total_reagent_weight && number_of_reagents && amount_of_reagents) //don't bother if the container is empty - DIV/0 var/average_reagent_weight = total_reagent_weight / amount_of_reagents - spray_range = clamp(round((initial(spray_range) / average_reagent_weight) - ((amount_of_reagents - 1) * 1)), 3, 5) //spray distance between 3 and 5 tiles rounded down; extra reagents lose a tile + spray_range = clamp(round((initial(spray_range) / average_reagent_weight) - ((number_of_reagents - 1) * 1)), 3, 5) //spray distance between 3 and 5 tiles rounded down; extra reagents lose a tile else spray_range = initial(spray_range) + if(stream_mode == 0) current_range = spray_range diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index 52dbebce403..4499a93d95d 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -28,9 +28,6 @@ . = ..() AddElement(/datum/element/update_icon_updates_onmob) -/obj/item/reagent_containers/syringe/on_reagent_change(changetype) - update_icon() - /obj/item/reagent_containers/syringe/pickup(mob/user) ..() update_icon() diff --git a/code/modules/research/xenobiology/vatgrowing/vatgrower.dm b/code/modules/research/xenobiology/vatgrowing/vatgrower.dm index 325ae26ab87..c0accc7467c 100644 --- a/code/modules/research/xenobiology/vatgrowing/vatgrower.dm +++ b/code/modules/research/xenobiology/vatgrowing/vatgrower.dm @@ -12,6 +12,17 @@ . = ..() AddComponent(/datum/component/plumbing/simple_demand, bolt) +/obj/machinery/plumbing/growing_vat/create_reagents(max_vol, flags) + . = ..() + RegisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_REM_REAGENT), .proc/on_reagent_change) + RegisterSignal(reagents, COMSIG_PARENT_QDELETING, .proc/on_reagents_del) + +/// Handles properly detaching signal hooks. +/obj/machinery/plumbing/growing_vat/proc/on_reagents_del(datum/reagents/reagents) + SIGNAL_HANDLER + UnregisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_REM_REAGENT, COMSIG_PARENT_QDELETING)) + return NONE + ///When we process, we make use of our reagents to try and feed the samples we have. /obj/machinery/plumbing/growing_vat/process() if(!is_operational) @@ -64,10 +75,11 @@ . = ..() QDEL_NULL(biological_sample) -///Call update icon when reagents change to update the reagent content icons -/obj/machinery/plumbing/growing_vat/on_reagent_change(changetype) +/// Call update icon when reagents change to update the reagent content icons. Eats signal args. +/obj/machinery/plumbing/growing_vat/proc/on_reagent_change(datum/reagents/holder, ...) + SIGNAL_HANDLER update_icon() - return ..() + return NONE ///Adds overlays to show the reagent contents /obj/machinery/plumbing/growing_vat/update_overlays() diff --git a/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm b/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm index 49fea9fdfb3..6d713cc80ad 100644 --- a/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm @@ -284,11 +284,22 @@ create_reagents(max_volume, NO_REACT) known_reagents = list(/datum/reagent/medicine/epinephrine="Epinephrine",/datum/reagent/medicine/c2/multiver="Multiver") -/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/detach() +/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/Destroy() STOP_PROCESSING(SSobj, src) return ..() -/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/Destroy() +/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/create_reagents(max_vol, flags) + . = ..() + RegisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_REM_REAGENT), .proc/on_reagent_change) + RegisterSignal(reagents, COMSIG_PARENT_QDELETING, .proc/on_reagents_del) + +/// Handles detaching signal hooks incase someone is crazy enough to make this edible. +/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/on_reagents_del(datum/reagents/reagents) + SIGNAL_HANDLER + UnregisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_REM_REAGENT, COMSIG_PARENT_QDELETING)) + return NONE + +/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/detach() STOP_PROCESSING(SSobj, src) return ..() @@ -477,9 +488,11 @@ send_byjax(chassis.occupants,"msyringegun.browser","reagents",get_current_reagents()) send_byjax(chassis.occupants,"msyringegun.browser","reagents_form",get_reagents_form()) -/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/on_reagent_change(changetype) - . = ..() +/// Updates the equipment info list when the reagents change. Eats signal args. +/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/on_reagent_change(datum/reagents/holder, ...) + SIGNAL_HANDLER update_equip_info() + return NONE /obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/process(delta_time)