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
This commit is contained in:
TemporalOroboros
2020-12-22 14:20:00 -08:00
committed by GitHub
parent 6e8b04d3c1
commit 863977e5fa
32 changed files with 741 additions and 514 deletions
+67 -55
View File
@@ -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..."
@@ -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"
+21 -12
View File
@@ -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
-4
View File
@@ -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))
. += "<span class='notice'>The status display reads: Productivity at <b>[productivity*100]%</b>.<br>Matter consumption reduced by <b>[(efficiency*25)-25]</b>%.<br>Machine can hold up to <b>[max_items]</b> pieces of produce.</span>"
/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"
+51 -29
View File
@@ -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("<span class='notice'>The [src] is injected with a fresh blood sample.</span>")
log_cloning("[key_name(mind)]'s cloning record was added to [src] at [AREACOORD(src)].")
else
visible_message("<span class='warning'>The [src] rejects the sample!</span>")
/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("<span class='notice'>The [src] is injected with a fresh blood sample.</span>")
log_cloning("[key_name(mind)]'s cloning record was added to [src] at [AREACOORD(src)].")
else
visible_message("<span class='warning'>The [src] rejects the sample!</span>")
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 = ..()
@@ -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()
. = ..()
@@ -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)
@@ -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
@@ -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()
. = ..()
@@ -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()
. = ..()
+15 -3
View File
@@ -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("<span class='suicide'>[user] is licking the electrodes of [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
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()
+26 -5
View File
@@ -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
+329 -304
View File
@@ -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)<amount)
amount = src.get_reagent_amount(reagent)
amount = min(amount, R.maximum_volume-R.total_volume)
var/trans_data = null
for (var/CR in cached_reagents)
var/datum/reagent/current_reagent = CR
if(current_reagent.type == reagent)
if(preserve_data)
trans_data = current_reagent.data
R.add_reagent(current_reagent.type, amount, trans_data, src.chem_temp)
remove_reagent(current_reagent.type, amount, 1)
break
src.update_total()
R.update_total()
R.handle_reactions()
return amount
/// Copies the reagents to the target object
/datum/reagents/proc/copy_to(obj/target, amount=1, multiplier=1, preserve_data=1)
var/list/cached_reagents = reagent_list
@@ -340,34 +507,45 @@
update_total()
handle_reactions()
/// 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
/// Get the name of the reagent there is the most of in this holder
/datum/reagents/proc/get_master_reagent_name()
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/name
var/max_volume = 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/datum/reagents/R = target.reagents
if(src.get_reagent_amount(reagent)<amount)
amount = src.get_reagent_amount(reagent)
amount = min(amount, R.maximum_volume-R.total_volume)
var/trans_data = null
for (var/CR in cached_reagents)
var/datum/reagent/current_reagent = CR
if(current_reagent.type == reagent)
if(preserve_data)
trans_data = current_reagent.data
R.add_reagent(current_reagent.type, amount, trans_data, src.chem_temp)
remove_reagent(current_reagent.type, amount, 1)
break
return name
src.update_total()
R.update_total()
R.handle_reactions()
return amount
/// Get the id of the reagent there is the most of in this holder
/datum/reagents/proc/get_master_reagent_id()
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
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, "<span class='notice'>You feel like you've gotten over your need for [R.name].</span>")
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, "<span class='notice'>You feel like you've gotten over your need for [R.name].</span>")
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
@@ -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
```
@@ -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
@@ -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!?
@@ -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))
+17 -1
View File
@@ -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()
. = ..()
@@ -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"
@@ -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.
@@ -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
@@ -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()
@@ -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()
@@ -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)