diff --git a/citadel.dme b/citadel.dme index 7c7f9707d0ac..ad778783a38c 100644 --- a/citadel.dme +++ b/citadel.dme @@ -1621,7 +1621,6 @@ #include "code\game\objects\items\signs.dm" #include "code\game\objects\items\spritechanger.dm" #include "code\game\objects\items\throwing.dm" -#include "code\game\objects\items\toys.dm" #include "code\game\objects\items\trash.dm" #include "code\game\objects\items\upgradekit.dm" #include "code\game\objects\items\circuitboards\broken.dm" @@ -1801,6 +1800,8 @@ #include "code\game\objects\items\tools\weldingtool.dm" #include "code\game\objects\items\tools\wirecutters.dm" #include "code\game\objects\items\tools\wrench.dm" +#include "code\game\objects\items\toys\balloon.dm" +#include "code\game\objects\items\toys\toys.dm" #include "code\game\objects\items\weapons\AI_modules.dm" #include "code\game\objects\items\weapons\autopsy.dm" #include "code\game\objects\items\weapons\barrier_tape.dm" @@ -1932,7 +1933,7 @@ #include "code\game\objects\structures\loot_piles.dm" #include "code\game\objects\structures\low_wall.dm" #include "code\game\objects\structures\map_blocker.dm" -#include "code\game\objects\structures\medical_stand_vr.dm" +#include "code\game\objects\structures\medical_stand.dm" #include "code\game\objects\structures\mineral_bath.dm" #include "code\game\objects\structures\mirror.dm" #include "code\game\objects\structures\mop_bucket.dm" @@ -3718,7 +3719,11 @@ #include "code\modules\mob\living\bot\mulebot.dm" #include "code\modules\mob\living\bot\secbot.dm" #include "code\modules\mob\living\bot\SLed209bot.dm" +#include "code\modules\mob\living\carbon\blood_fragment.dm" +#include "code\modules\mob\living\carbon\blood_holder.dm" +#include "code\modules\mob\living\carbon\blood_mixture.dm" #include "code\modules\mob\living\carbon\breathe.dm" +#include "code\modules\mob\living\carbon\carbon-blood.dm" #include "code\modules\mob\living\carbon\carbon-defense.dm" #include "code\modules\mob\living\carbon\carbon-hands.dm" #include "code\modules\mob\living\carbon\carbon.dm" @@ -4668,17 +4673,18 @@ #include "code\modules\random_map\noise\tundra.dm" #include "code\modules\reagents\exposedprocs.dm" #include "code\modules\reagents\reagent_containers.dm" -#include "code\modules\reagents\chemistry\_readme.dm" #include "code\modules\reagents\chemistry\chemical_reaction-legacy.dm" #include "code\modules\reagents\chemistry\chemical_reaction.dm" -#include "code\modules\reagents\chemistry\colors.dm" #include "code\modules\reagents\chemistry\helpers.dm" #include "code\modules\reagents\chemistry\machinery.dm" -#include "code\modules\reagents\chemistry\metabolism.dm" #include "code\modules\reagents\chemistry\reagent.dm" +#include "code\modules\reagents\chemistry\reagent_holder-color.dm" +#include "code\modules\reagents\chemistry\reagent_holder-helpers.dm" #include "code\modules\reagents\chemistry\reagent_holder-legacy.dm" +#include "code\modules\reagents\chemistry\reagent_holder-metabolism.dm" #include "code\modules\reagents\chemistry\reagent_holder-reactions.dm" #include "code\modules\reagents\chemistry\reagent_holder.dm" +#include "code\modules\reagents\chemistry\reagent_metabolism.dm" #include "code\modules\reagents\chemistry\wiki_generation.dm" #include "code\modules\reagents\chemistry\reactions\automata.dm" #include "code\modules\reagents\chemistry\reactions\carpet.dm" @@ -4701,13 +4707,31 @@ #include "code\modules\reagents\chemistry\reagents\Chemistry-Reagents-Other.dm" #include "code\modules\reagents\chemistry\reagents\Chemistry-Reagents-Toxins.dm" #include "code\modules\reagents\chemistry\reagents\Chemistry-Topical.dm" +#include "code\modules\reagents\chemistry\reagents\core\acid.dm" +#include "code\modules\reagents\chemistry\reagents\core\blood.dm" #include "code\modules\reagents\chemistry\reagents\core\elements.dm" +#include "code\modules\reagents\chemistry\reagents\core\ethanol.dm" +#include "code\modules\reagents\chemistry\reagents\core\toxin.dm" +#include "code\modules\reagents\chemistry\reagents\core\water.dm" +#include "code\modules\reagents\chemistry\reagents\nutrition\nutriment.dm" +#include "code\modules\reagents\chemistry\reagents\nutrition\nutriment\coating.dm" +#include "code\modules\reagents\chemistry\reagents\other\adminordrazine.dm" +#include "code\modules\reagents\chemistry\reagents\other\carpet.dm" +#include "code\modules\reagents\chemistry\reagents\other\chalk_dust.dm" #include "code\modules\reagents\chemistry\reagents\other\cleaner.dm" +#include "code\modules\reagents\chemistry\reagents\other\crayon_dust.dm" +#include "code\modules\reagents\chemistry\reagents\other\holywater.dm" +#include "code\modules\reagents\chemistry\reagents\other\luminol.dm" +#include "code\modules\reagents\chemistry\reagents\other\marker_ink.dm" +#include "code\modules\reagents\chemistry\reagents\other\paint.dm" #include "code\modules\reagents\chemistry\reagents\pyrotechnics\thermite.dm" #include "code\modules\reagents\distilling\Distilling-Recipes.dm" #include "code\modules\reagents\distilling\distilling.dm" #include "code\modules\reagents\items\hypospray.dm" #include "code\modules\reagents\items\hypovial.dm" +#include "code\modules\reagents\items\spray.dm" +#include "code\modules\reagents\items\spray\squirt.dm" +#include "code\modules\reagents\items\spray\waterflower.dm" #include "code\modules\reagents\machinery\chem_master.dm" #include "code\modules\reagents\machinery\reagent_dispenser.dm" #include "code\modules\reagents\machinery\dispenser\cartridge.dm" @@ -4737,8 +4761,6 @@ #include "code\modules\reagents\reagent_containers\patch.dm" #include "code\modules\reagents\reagent_containers\pill.dm" #include "code\modules\reagents\reagent_containers\pill_vr.dm" -#include "code\modules\reagents\reagent_containers\spray.dm" -#include "code\modules\reagents\reagent_containers\spray_vr.dm" #include "code\modules\reagents\reagent_containers\syringes.dm" #include "code\modules\reagents\reagent_containers\syringes_vr.dm" #include "code\modules\reagents\reagent_containers\unidentified_hypospray.dm" diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm index 53c7f16bb372..a2d26e2c8e64 100644 --- a/code/datums/components/crafting/crafting.dm +++ b/code/datums/components/crafting/crafting.dm @@ -146,8 +146,10 @@ if(istype(I, /obj/item/reagent_containers)) var/obj/item/reagent_containers/RC = I if(RC.is_open_container()) - for(var/datum/reagent/A in RC.reagents.reagent_list) - .["other"][A.type] += A.volume + // todo: this shouldn't be by type. + for(var/id in RC.reagents.reagent_volumes) + var/datum/reagent/A = SSchemistry.fetch_reagent(id) + .["other"][A.type] += RC.reagents.reagent_volumes[id] .["other"][I.type] += 1 /datum/component/personal_crafting/proc/check_tools(atom/a, datum/crafting_recipe/R, list/contents) @@ -235,34 +237,17 @@ surroundings = get_environment(a, R.blacklist) surroundings -= Deletion if(ispath(A, /datum/reagent)) - var/datum/reagent/RG = new A - var/datum/reagent/RGNT + var/datum/reagent/wanted_reagent = SSchemistry.fetch_reagent(A) while(amt > 0) var/obj/item/reagent_containers/RC = locate() in surroundings - RG = RC.reagents.get_reagent(RG.id) - if(RG) - if(!locate(RG.type) in Deletion) - Deletion += new RG.type() - if(RG.volume > amt) - RG.volume -= amt - data = RG.data - RC.reagents.conditional_update(RC) - RG = locate(RG.type) in Deletion - RG.volume = amt - RG.data += data + surroundings -= RC + if(RC.reagents?.reagent_volumes?[wanted_reagent.id]) + var/removing_volume = RC.reagents.reagent_volumes[wanted_reagent.id] + removing_volume = min(removing_volume, amt) + RC.reagents.remove_reagent(wanted_reagent.id, removing_volume) + amt -= removing_volume + if(amt <= 0) continue main_loop - else - surroundings -= RC - amt -= RG.volume - RC.reagents.reagent_list -= RG - RC.reagents.conditional_update(RC) - RGNT = locate(RG.type) in Deletion - RGNT.volume += RG.volume - RGNT.data += RG.data - qdel(RG) - RC.on_reagent_change() - else - surroundings -= RC else if(ispath(A, /obj/item/stack)) var/obj/item/stack/S var/obj/item/stack/SD @@ -296,14 +281,7 @@ for(var/M in R.parts) partlist[M] = R.parts[M] for(var/A in R.parts) - if(istype(A, /datum/reagent)) - var/datum/reagent/RG = locate(A) in Deletion - if(RG.volume > partlist[A]) - RG.volume = partlist[A] - . += RG - Deletion -= RG - continue - else if(istype(A, /obj/item/stack)) + if(istype(A, /obj/item/stack)) var/obj/item/stack/ST = locate(A) in Deletion if(ST.amount > partlist[A]) ST.amount = partlist[A] diff --git a/code/datums/material_container.dm b/code/datums/material_container.dm index f372fb790ebf..d2cfc8935f90 100644 --- a/code/datums/material_container.dm +++ b/code/datums/material_container.dm @@ -214,14 +214,14 @@ /** * basically, divides by given resources and takes lowest. */ -/datum/material_container/proc/has_multiple(list/wanted, multiplier = 1) +/datum/material_container/proc/has_multiple(list/wanted) if(isnull(stored)) return 0 . = INFINITY for(var/key in wanted) if(!wanted[key]) continue - . = min(., stored[key] / (wanted[key] * multiplier)) + . = min(., stored[key] / wanted[key]) if(!.) return diff --git a/code/datums/recipe/recipe.dm b/code/datums/recipe/recipe.dm index 2bb732f9cc96..ee2cd529332d 100644 --- a/code/datums/recipe/recipe.dm +++ b/code/datums/recipe/recipe.dm @@ -92,7 +92,7 @@ else return -1 - if ((reagents?(reagents.len):(0)) < avail_reagents.reagent_list.len) + if ((reagents?(reagents.len):(0)) < avail_reagents.reagent_volumes.len) return 0 return . @@ -268,26 +268,20 @@ if (RECIPE_REAGENT_MAX) //We want the highest of each. //Iterate through everything in buffer. If the target has less than the buffer, then top it up - for (var/datum/reagent/R in temp.reagents.reagent_list) - var/rvol = tempholder.reagents.get_reagent_amount(R.id) - if (rvol < R.volume) - //Transfer the difference - temp.reagents.trans_id_to(tempholder, R.id, R.volume-rvol) + for(var/id in temp.reagents.reagent_volumes) + var/volume = temp.reagents.reagent_volumes[id] + if(tempholder.reagents.reagent_volumes[id] < volume) + temp.reagents.trans_id_to(tempholder, id, volume - tempholder.reagents.reagent_volumes[id]) if (RECIPE_REAGENT_MIN) //Min is slightly more complex. We want the result to have the lowest from each side //But zero will not count. Where a side has zero its ignored and the side with a nonzero value is used - for (var/datum/reagent/R in temp.reagents.reagent_list) - var/rvol = tempholder.reagents.get_reagent_amount(R.id) - if (rvol == 0) //If the target has zero of this reagent - temp.reagents.trans_id_to(tempholder, R.id, R.volume) - //Then transfer all of ours - - else if (rvol > R.volume) - //if the target has more than ours - //Remove the difference - tempholder.reagents.remove_reagent(R.id, rvol-R.volume) - + for(var/id in temp.reagents.reagent_volumes) + var/volume = temp.reagents.reagent_volumes[id] + if(!tempholder.reagents.reagent_volumes[id]) + temp.reagents.trans_id_to(tempholder, id, volume) + else if(tempholder.reagents.reagent_volumes[id] > volume) + temp.reagents.remove_reagent(id, tempholder.reagents.reagent_volumes[id] - volume) if (results.len > 1) //If we're here, then holder is a buffer containing the total reagents for all the results. diff --git a/code/game/atoms/_atom.dm b/code/game/atoms/_atom.dm index e4e9097fd3ed..db4b0a483b88 100644 --- a/code/game/atoms/_atom.dm +++ b/code/game/atoms/_atom.dm @@ -95,6 +95,8 @@ //? Chemistry // todo: properly finalize the semantics of this variable and what it's for. + // todo: should this variable even exist? most atoms don't need this, and we can easily have an APi + // to fetch a relevant holder upon being inspected by an analyzer. var/datum/reagent_holder/reagents = null //? Detective Work @@ -297,7 +299,6 @@ found += A.search_contents_for(path,filter_path) return found - // called by mobs when e.g. having the atom as their machine, pulledby, loc (AKA mob being inside the atom) or buckled var set. // see code/modules/mob/mob_movement.dm for more. /atom/proc/relaymove() @@ -671,12 +672,13 @@ /atom/proc/CheckParts(list/parts_list) for(var/A in parts_list) - if(istype(A, /datum/reagent)) - if(!reagents) - reagents = new() - reagents.reagent_list.Add(A) - reagents.conditional_update() - else if(ismovable(A)) + // todo: i don't know why we do this in crafting but crafting needs fucking refactored lmao + // if(istype(A, /datum/reagent)) + // if(!reagents) + // reagents = new() + // reagents.reagent_list.Add(A) + // reagents.conditional_update() + if(ismovable(A)) var/atom/movable/M = A M.forceMove(src) diff --git a/code/game/atoms/atom-examine.dm b/code/game/atoms/atom-examine.dm index 3d734f0a984c..003abd8438e9 100644 --- a/code/game/atoms/atom-examine.dm +++ b/code/game/atoms/atom-examine.dm @@ -73,19 +73,19 @@ if(reagents) if(reagents.reagents_holder_flags & TRANSPARENT) . += "It contains:" - if(length(reagents.reagent_list)) + if(reagents.total_volume) var/has_alcohol = FALSE if(user.can_see_reagents()) //Show each individual reagent - for(var/datum/reagent/current_reagent as anything in reagents.reagent_list) + for(var/datum/reagent/current_reagent as anything in reagents.get_reagent_datums()) if(!has_alcohol && istype(current_reagent,/datum/reagent/ethanol)) has_alcohol = TRUE - . += "• [round(current_reagent.volume, 0.01)] units of [current_reagent.name]" + . += "• [round(reagents.reagent_volumes[current_reagent.id], 0.01)] units of [current_reagent.name]" else //Otherwise, just show the total volume var/total_volume = 0 - for(var/datum/reagent/current_reagent as anything in reagents.reagent_list) + for(var/datum/reagent/current_reagent as anything in reagents.get_reagent_datums()) if(!has_alcohol && istype(current_reagent,/datum/reagent/ethanol)) has_alcohol = TRUE - total_volume += current_reagent.volume + total_volume += reagents.reagent_volumes[current_reagent.id] . += "[total_volume] units of various reagents" if(has_alcohol) . += "It smells of alcohol." diff --git a/code/game/atoms/movable/pulling.dm b/code/game/atoms/movable/pulling.dm index f02c792439fc..f219e6ad36a7 100644 --- a/code/game/atoms/movable/pulling.dm +++ b/code/game/atoms/movable/pulling.dm @@ -119,11 +119,11 @@ if(H.species.species_flags & NO_BLOOD) bloodtrail = 0 else - var/blood_volume = H.vessel.get_reagent_amount("blood") + var/blood_volume = H.blood_holder.get_total_volume() if(blood_volume < H.species?.blood_volume * H.species?.blood_level_fatal) bloodtrail = 0 //Most of it's gone already, just leave it be else - H.vessel.remove_reagent("blood", 1) + H.blood_holder?.draw(1) if(bloodtrail) var/turf/location = M.loc if(istype(location, /turf/simulated)) @@ -144,11 +144,11 @@ if(H.species.species_flags & NO_BLOOD) bloodtrail = 0 else - var/blood_volume = H.vessel.get_reagent_amount("blood") + var/blood_volume = H.blood_holder.get_total_volume() if(blood_volume < H.species?.blood_volume * H.species?.blood_level_fatal) bloodtrail = 0 //Most of it's gone already, just leave it be else - H.vessel.remove_reagent("blood", 1) + H.blood_holder?.draw(1) if(bloodtrail) if(istype(location, /turf/simulated)) location.add_blood(M) diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm index 1956e08c89e1..17c126b3f381 100644 --- a/code/game/dna/dna_modifier.dm +++ b/code/game/dna/dna_modifier.dm @@ -389,9 +389,7 @@ data["beakerVolume"] = 0 if(connected.beaker) data["beakerLabel"] = connected.beaker.label_text ? connected.beaker.label_text : null - if (connected.beaker.reagents && connected.beaker.reagents.reagent_list.len) - for(var/datum/reagent/R in connected.beaker.reagents.reagent_list) - data["beakerVolume"] += R.volume + data["beakerVolume"] = connected.beaker.reagents?.total_volume || 0 // update the ui if it exists, returns null if no ui is passed/found ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) diff --git a/code/game/gamemodes/changeling/powers/epinephrine_overdose.dm b/code/game/gamemodes/changeling/powers/epinephrine_overdose.dm index 9ecf521ff101..17a0475630c2 100644 --- a/code/game/gamemodes/changeling/powers/epinephrine_overdose.dm +++ b/code/game/gamemodes/changeling/powers/epinephrine_overdose.dm @@ -50,10 +50,10 @@ description = "Reduces stun times, but causing toxicity due to high concentration." reagent_state = REAGENT_LIQUID color = "#C8A5DC" - metabolism = REM * 2 + metabolism_rate = REM * 2 overdose = 5 //This is intentionally low, as we want the ling to take some tox damage, to discourage spamming the ability. -/datum/reagent/epinephrine/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/epinephrine/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return M.add_chemical_effect(CE_SPEEDBOOST, 3) diff --git a/code/game/gamemodes/cult/construct_spells.dm b/code/game/gamemodes/cult/construct_spells.dm index aeeff476bc82..708034f934b3 100644 --- a/code/game/gamemodes/cult/construct_spells.dm +++ b/code/game/gamemodes/cult/construct_spells.dm @@ -473,8 +473,8 @@ var/mob/living/carbon/human/H = owner if(!H.should_have_organ(O_HEART)) return 1 - if(H.vessel.remove_reagent("blood", amount)) - return 1 + if(H.erase_checked_blood(amount)) + return TRUE return 0 /obj/item/spell/construct/afterattack(atom/target, mob/user, clickchain_flags, list/params) diff --git a/code/game/gamemodes/cult/narsie.dm b/code/game/gamemodes/cult/narsie.dm index abfa87f6cf79..3c051228fcff 100644 --- a/code/game/gamemodes/cult/narsie.dm +++ b/code/game/gamemodes/cult/narsie.dm @@ -189,8 +189,6 @@ var/global/list/narsie_list = list() if (dist <= consume_range && !istype(A, /turf/space)) var/turf/T = A - if(T.holy) - T.holy = 0 //Nar-Sie doesn't give a shit about sacred grounds. T.cultify() /obj/singularity/narsie/proc/old_narsie(const/atom/A) diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm index 14d54e5a7a68..c49c3e0a93a6 100644 --- a/code/game/machinery/Sleeper.dm +++ b/code/game/machinery/Sleeper.dm @@ -253,11 +253,11 @@ beaker.reagents, min( remaining_beaker_volume_for_dialysis * (3 / 4), - length(occupant.reagents.reagent_list) * 3, + length(occupant.reagents.reagent_volumes) * 3, ), dialysis_reagent_filter_flags, ) - occupant.vessel.trans_to_holder(beaker.reagents, filtered_volume * (1 / 3)) + occupant.take_blood_legacy(beaker, filtered_volume * (1 / 3)) else toggle_filter() @@ -268,7 +268,7 @@ beaker.reagents, min( beaker.reagents.maximum_volume - beaker.reagents.total_volume, - length(occupant.ingested.reagent_list) * 3, + length(occupant.ingested.reagent_volumes) * 3, ), dialysis_reagent_filter_flags, ) diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm index ae3898fc44ea..70158b200c54 100644 --- a/code/game/machinery/adv_med.dm +++ b/code/game/machinery/adv_med.dm @@ -292,8 +292,8 @@ occupantData["hasBorer"] = H.has_brain_worms() var/bloodData[0] - if(H.vessel) - var/blood_volume = round(H.vessel.get_reagent_amount("blood")) + if(H.blood_holder) + var/blood_volume = round(H.blood_holder.get_total_volume()) var/blood_max = H.species.blood_volume bloodData["volume"] = blood_volume bloodData["percent"] = round(((blood_volume / blood_max)*100)) @@ -301,18 +301,22 @@ occupantData["blood"] = bloodData var/reagentData[0] - if(H.reagents.reagent_list.len >= 1) - for(var/datum/reagent/R in H.reagents.reagent_list) - reagentData[++reagentData.len] = list("name" = R.name, "amount" = R.volume) + if(length(H.reagents.reagent_volumes)) + for(var/id in H.reagents?.reagent_volumes) + var/datum/reagent/R = SSchemistry.fetch_reagent(id) + var/volume = H.reagents.reagent_volumes[id] + reagentData[++reagentData.len] = list("name" = R.name, "amount" = volume) else reagentData = null occupantData["reagents"] = reagentData var/ingestedData[0] - if(H.ingested.reagent_list.len >= 1) - for(var/datum/reagent/R in H.ingested.reagent_list) - ingestedData[++ingestedData.len] = list("name" = R.name, "amount" = R.volume) + if(length(H.ingested.reagent_volumes)) + for(var/id in H.ingested?.reagent_volumes) + var/datum/reagent/R = SSchemistry.fetch_reagent(id) + var/volume = H.ingested.reagent_volumes[id] + ingestedData[++ingestedData.len] = list("name" = R.name, "amount" = volume) else ingestedData = null @@ -479,8 +483,8 @@ if(occupant.has_brain_worms()) dat += "Large growth detected in frontal lobe, possibly cancerous. Surgical removal is recommended.
" - if(occupant.vessel) - var/blood_volume = round(occupant.vessel.get_reagent_amount("blood")) + if(occupant.blood_holder) + var/blood_volume = round(occupant.blood_holder.get_total_volume()) var/blood_max = occupant.species.blood_volume var/blood_percent = blood_volume / blood_max blood_percent *= 100 @@ -488,13 +492,15 @@ extra_font = " 448 ? "blue" : "red"]>" dat += "[extra_font]\tBlood Level %: [blood_percent] ([blood_volume] units)
" - if(occupant.reagents) - for(var/datum/reagent/R in occupant.reagents.reagent_list) - dat += "Reagent: [R.name], Amount: [R.volume]
" + for(var/id in occupant.reagents?.reagent_volumes) + var/datum/reagent/R = SSchemistry.fetch_reagent(id) + var/volume = occupant.reagents.reagent_volumes[id] + dat += "Reagent: [R.name], Amount: [volume]
" - if(occupant.ingested) - for(var/datum/reagent/R in occupant.ingested.reagent_list) - dat += "Stomach: [R.name], Amount: [R.volume]
" + for(var/id in occupant.ingested?.reagent_volumes) + var/datum/reagent/R = SSchemistry.fetch_reagent(id) + var/volume = occupant.ingested.reagent_volumes[id] + dat += "Stomach: [R.name], Amount: [volume]
" dat += "
" dat += "" diff --git a/code/game/machinery/bioprinter.dm b/code/game/machinery/bioprinter.dm index b9a8ce78f739..5cb108fc872d 100644 --- a/code/game/machinery/bioprinter.dm +++ b/code/game/machinery/bioprinter.dm @@ -21,8 +21,8 @@ var/base_print_delay = 100 ///Is the bioprinter printing var/printing = FALSE - ///Blood sample for DNA hashing. - var/loaded_dna + /// Blood sample for DNA hashing. + var/datum/blood_mixture/loaded_blood_mixture ///May cause rejection, or the printing of some alien limb instead! var/malfunctioning = FALSE ///Can it print more 'complex' organs? @@ -206,13 +206,7 @@ /// Checks for reagents, then reports how much biomass it has in it. /obj/machinery/organ_printer/proc/get_biomass_volume() - var/biomass_count = 0 - if(container && container.reagents) - for(var/datum/reagent/R in container.reagents.reagent_list) - if(R.id == "biomass") - biomass_count += R.volume - - return biomass_count + return container.reagents?.reagent_volumes?[/datum/reagent/nutriment/biomass::id] /obj/machinery/organ_printer/proc/can_print(choice, biomass_needed = 0) var/biomass = get_biomass_volume() @@ -220,7 +214,8 @@ visible_message(SPAN_INFO("\The [src] displays a warning: 'Not enough biomass. [biomass] stored and [biomass_needed] needed.'")) return FALSE - if(!loaded_dna || !loaded_dna["donor"]) + var/datum/blood_fragment/using_fragment = (length(loaded_blood_mixture?.fragments) && loaded_blood_mixture.fragments[1]) || null + if(!using_fragment) visible_message(SPAN_INFO("\The [src] displays a warning: 'No DNA saved. Insert a blood sample.'")) return FALSE return TRUE @@ -229,7 +224,8 @@ var/new_organ = choice var/obj/item/organ/O = new new_organ(get_turf(src)) O.status |= ORGAN_CUT_AWAY - var/mob/living/carbon/human/C = loaded_dna["donor"] + var/datum/blood_fragment/using_fragment = loaded_blood_mixture.fragments[1] + var/mob/living/carbon/human/C = using_fragment.legacy_donor O.set_dna(C.dna) O.species = C.species @@ -299,10 +295,9 @@ // DNA sample from syringe. if(istype(W,/obj/item/reagent_containers/syringe)) //TODO: Make this actually empty the syringe var/obj/item/reagent_containers/syringe/S = W - var/datum/reagent/blood/injected = locate() in S.reagents.reagent_list //Grab some blood - if(injected && injected.data) - loaded_dna = injected.data - S.reagents.remove_reagent("blood", injected.volume) + var/datum/blood_mixture/mixture = S.reagents?.reagent_datas[/datum/reagent/blood::id] + if((loaded_blood_mixture = mixture)) + S.reagents.del_reagent(/datum/reagent/blood) to_chat(user, SPAN_INFO("You scan the blood sample into the bioprinter.")) return else if(istype(W,/obj/item/reagent_containers/glass)) diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 4e203298c624..98647ace0ea1 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -344,34 +344,17 @@ // Returns the total amount of biomass reagent in all of the pod's stored containers /obj/machinery/clonepod/proc/get_biomass() var/biomass_count = 0 - if(LAZYLEN(containers)) - for(var/obj/item/reagent_containers/glass/G in containers) - for(var/datum/reagent/R in G.reagents.reagent_list) - if(R.id == "biomass") - biomass_count += R.volume - + for(var/obj/item/reagent_containers/container in containers) + biomass_count += container.reagents?.reagent_volumes?[/datum/reagent/nutriment/biomass::id] return biomass_count // Removes [amount] biomass, spread across all containers. Doesn't have any check that you actually HAVE enough biomass, though. -/obj/machinery/clonepod/proc/remove_biomass(var/amount = CLONE_BIOMASS) //Just in case it doesn't get passed a new amount, assume one clone - var/to_remove = 0 // Tracks how much biomass has been found so far - if(LAZYLEN(containers)) - for(var/obj/item/reagent_containers/glass/G in containers) - if(to_remove < amount) //If we have what we need, we can stop. Checked every time we switch beakers - for(var/datum/reagent/R in G.reagents.reagent_list) - if(R.id == "biomass") // Finds Biomass - var/need_remove = max(0, amount - to_remove) //Figures out how much biomass is in this container - if(R.volume >= need_remove) //If we have more than enough in this beaker, only take what we need - R.remove_self(need_remove) - to_remove = amount - else //Otherwise, take everything and move on - to_remove += R.volume - R.remove_self(R.volume) - else - continue - else - return 1 - return 0 +/obj/machinery/clonepod/proc/remove_biomass(amount = CLONE_BIOMASS) //Just in case it doesn't get passed a new amount, assume one clone + for(var/obj/item/reagent_containers/glass/beaker in containers) + amount -= beaker.reagents.remove_reagent(/datum/reagent/nutriment/biomass, amount) + if(!amount) + return TRUE + return !amount // Empties all of the beakers from the cloning pod, used to refill it /obj/machinery/clonepod/verb/empty_beakers() diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm index 853f74f96f03..bbc6c28f274d 100644 --- a/code/game/machinery/computer/Operating.dm +++ b/code/game/machinery/computer/Operating.dm @@ -110,10 +110,10 @@ occupantData["btCelsius"] = occupant.bodytemperature - T0C occupantData["btFaren"] = ((occupant.bodytemperature - T0C) * (9.0/5.0))+ 32 - if(ishuman(occupant) && !(NO_BLOOD in occupant.species.species_flags) && occupant.vessel) + if(ishuman(occupant) && !(NO_BLOOD in occupant.species.species_flags) && occupant.blood_holder) occupantData["pulse"] = occupant.get_pulse(GETPULSE_TOOL) occupantData["hasBlood"] = 1 - var/blood_volume = round(occupant.vessel.get_reagent_amount("blood")) + var/blood_volume = round(occupant.blood_holder.get_total_volume()) occupantData["bloodLevel"] = blood_volume occupantData["bloodMax"] = occupant.species.blood_volume occupantData["bloodPercent"] = round(100*(blood_volume/occupant.species.blood_volume), 0.01) //copy pasta ends here diff --git a/code/game/machinery/computer/arcade/_arcade.dm b/code/game/machinery/computer/arcade/_arcade.dm index 93529c4d883e..7ff9acca744a 100644 --- a/code/game/machinery/computer/arcade/_arcade.dm +++ b/code/game/machinery/computer/arcade/_arcade.dm @@ -19,7 +19,7 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list( /obj/item/toy/prize/mauler = 1, /obj/item/toy/prize/odysseus = 1, /obj/item/toy/prize/phazon = 1, - /obj/item/toy/waterflower = 1, + /obj/item/reagent_containers/spray/waterflower = 1, /obj/random/action_figure = 1, /obj/random/plushie = 1, /obj/item/toy/cultsword = 1, diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm index 6f4ef4ab70b5..d6ba7bcfeb0c 100644 --- a/code/game/machinery/cryo.dm +++ b/code/game/machinery/cryo.dm @@ -139,9 +139,8 @@ data["beakerVolume"] = 0 if(beaker) data["beakerLabel"] = beaker.label_text ? beaker.label_text : null - if(beaker.reagents && beaker.reagents.reagent_list.len) - for(var/datum/reagent/R in beaker.reagents.reagent_list) - data["beakerVolume"] += R.volume + if(beaker.reagents) + data["beakerVolume"] = beaker.reagents?.total_volume // update the ui if it exists, returns null if no ui is passed/found ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm index d652621f749a..a8fdadedd55a 100644 --- a/code/game/machinery/iv_drip.dm +++ b/code/game/machinery/iv_drip.dm @@ -113,7 +113,7 @@ if(91 to INFINITY) filling_overlay.icon_state = "reagent100" - filling_overlay.color = mix_color_from_reagents(target_reagents.reagent_list) + filling_overlay.color = target_reagents.get_color() . += filling_overlay /obj/machinery/iv_drip/OnMouseDropLegacy(mob/living/target) @@ -218,8 +218,8 @@ visible_message(SPAN_HEAR("[src] beeps loudly.")) playsound(loc, 'sound/machines/twobeep_high.ogg', 50, TRUE) var/atom/movable/target = reagent_container - attached_victim.take_blood(target, amount) - update_appearance() + if(attached_victim.take_blood_legacy(target, amount) > 0) + update_appearance() /// Called when an IV is attached. /obj/machinery/iv_drip/proc/attach_iv(mob/living/target, mob/user) @@ -303,7 +303,7 @@ . += "[src] is [injection_mode ? "injecting" : "taking blood"]." if(reagent_container) - if(reagent_container.reagents && reagent_container.reagents.reagent_list.len) + if(reagent_container.reagents?.total_volume) . += SPAN_NOTICE("Attached is \a [reagent_container] with [reagent_container.reagents.total_volume] units of liquid.") else . += SPAN_NOTICE("Attached is an empty [reagent_container.name].") diff --git a/code/game/machinery/lathes/lathe.dm b/code/game/machinery/lathes/lathe.dm index c5e622c1fe6d..472cb48dfa32 100644 --- a/code/game/machinery/lathes/lathe.dm +++ b/code/game/machinery/lathes/lathe.dm @@ -288,11 +288,11 @@ for(var/key in instance.material_costs) var/id = material_parts[key] materials[id] += instance.material_costs[key] - . = stored_materials.has_multiple(materials, efficiency_multiplier) + . = stored_materials.has_multiple(materials) / efficiency_multiplier if(!.) return if(length(instance.reagents)) - . = min(., stored_reagents?.has_multiple(instance.reagents, efficiency_multiplier)) + . = min(., stored_reagents?.has_multiple(instance.reagents) / efficiency_multiplier) if(!.) return // ingredients? return 1 at most. diff --git a/code/game/machinery/vending/plants.dm b/code/game/machinery/vending/plants.dm index 07116a335ee8..49c0675e2f69 100644 --- a/code/game/machinery/vending/plants.dm +++ b/code/game/machinery/vending/plants.dm @@ -80,7 +80,7 @@ /obj/item/seeds/shandseed = 2, ) premium = list( - /obj/item/toy/waterflower = 1, + /obj/item/reagent_containers/spray/waterflower = 1, /obj/item/toy/gnome = 1, ) diff --git a/code/game/objects/effects/chem/coating.dm b/code/game/objects/effects/chem/coating.dm index 246d22ffd5ae..c980a78a9a48 100644 --- a/code/game/objects/effects/chem/coating.dm +++ b/code/game/objects/effects/chem/coating.dm @@ -19,18 +19,11 @@ continue if(istype(O, /obj/effect/debris/cleanable/chemcoating)) var/obj/effect/debris/cleanable/chemcoating/C = O - if(C.reagents && C.reagents.reagent_list.len) + if(C.reagents?.total_volume) C.reagents.trans_to_obj(src,C.reagents.total_volume) qdel(O) -/obj/effect/debris/cleanable/chemcoating/Bumped(A as mob|obj) - if(reagents) - reagents.touch(A) - return ..() - -/obj/effect/debris/cleanable/chemcoating/Crossed(AM as mob|obj) - . = ..() - Bumped(AM) +// todo: apply to whole body or just feet depending on if they're laying down, when crossed by mob or obj /obj/effect/debris/cleanable/chemcoating/update_icon() ..() diff --git a/code/game/objects/effects/chem/foam.dm b/code/game/objects/effects/chem/foam.dm index 0508452dba0d..490d1d577c2b 100644 --- a/code/game/objects/effects/chem/foam.dm +++ b/code/game/objects/effects/chem/foam.dm @@ -69,8 +69,8 @@ if(!metal) F.create_reagents(10) if(reagents) - for(var/datum/reagent/R in reagents.reagent_list) - F.reagents.add_reagent(R.id, 1, null, TRUE) + for(var/id in reagents.reagent_volumes) + F.reagents.add_reagent(id, 1, null, TRUE) /obj/effect/foam/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) // foam disolves when heated, except metal foams if(!metal && prob(max(0, exposed_temperature - 475))) diff --git a/code/game/objects/items/contraband.dm b/code/game/objects/items/contraband.dm index 52ed441d1982..11dbc8d26c55 100644 --- a/code/game/objects/items/contraband.dm +++ b/code/game/objects/items/contraband.dm @@ -40,7 +40,7 @@ reagents.add_reagent(reagent, picked_reagents[reagent]) var/list/names = new - for(var/datum/reagent/R in reagents.reagent_list) + for(var/datum/reagent/R in reagents.get_reagent_datums()) names += R.name desc = "Contains [english_list(names)]." diff --git a/code/game/objects/items/defib/shockpaddles.dm b/code/game/objects/items/defib/shockpaddles.dm index 6194487dc220..f6b9d4ea2c26 100644 --- a/code/game/objects/items/defib/shockpaddles.dm +++ b/code/game/objects/items/defib/shockpaddles.dm @@ -134,7 +134,7 @@ if(!heart) return TRUE - var/blood_volume = H.vessel.get_reagent_amount("blood") + var/blood_volume = H.blood_holder.get_total_volume() if(!heart || heart.is_broken()) blood_volume *= 0.3 else if(heart.is_bruised()) diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index f75e992a18f8..a9bc680d5a5e 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -1414,10 +1414,10 @@ GLOBAL_LIST_EMPTY(PDAs) if(!isobj(target)) return if(!isnull(target.reagents)) - if(target.reagents.reagent_list.len > 0) - var/reagents_length = target.reagents.reagent_list.len + if(target.reagents.total_volume) + var/reagents_length = length(target.reagents.reagent_volumes) to_chat(user, "[reagents_length] chemical agent[reagents_length > 1 ? "s" : ""] found.") - for (var/re in target.reagents.reagent_list) + for (var/re in target.reagents.get_reagent_datums()) to_chat(user," [re]") else to_chat(user,"No active chemical agents found in [target].") diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 5e4f88d287b6..0d6aefd11a30 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -175,11 +175,18 @@ if(L.getBrainLoss() > 15) to_chat(user, SPAN_NOTICE("There's visible lag between left and right pupils' reactions.")) - var/list/pinpoint = list("oxycodone"=1,"tramadol"=5) - var/list/dilating = list("space_drugs"=5,"mindbreaker"=1) - if(L.reagents.has_any_reagent(pinpoint) || H.ingested.has_any_reagent(pinpoint)) + // todo: reagent effects. + var/static/list/reagents_that_cause_constriction = list( + /datum/reagent/tramadol, + /datum/reagent/oxycodone, + ) + var/static/list/reagents_that_cause_dilation = list( + /datum/reagent/space_drugs, + /datum/reagent/mindbreaker, + ) + if(L.reagents.has_any(reagents_that_cause_constriction) || H.ingested.has_any(reagents_that_cause_constriction)) to_chat(user, SPAN_NOTICE("\The [L]'s pupils are already pinpoint and cannot narrow any more.")) - else if(L.reagents.has_any_reagent(dilating) || H.ingested.has_any_reagent(dilating)) + else if(L.reagents.has_any(reagents_that_cause_dilation) || H.ingested.has_any(reagents_that_cause_dilation)) to_chat(user, SPAN_NOTICE("\The [L]'s pupils narrow slightly, but are still very dilated.")) else to_chat(user, SPAN_NOTICE("\The [L]'s pupils narrow.")) diff --git a/code/game/objects/items/scanners/health.dm b/code/game/objects/items/scanners/health.dm index a5a907d2b98b..f4a5cd42bc24 100644 --- a/code/game/objects/items/scanners/health.dm +++ b/code/game/objects/items/scanners/health.dm @@ -122,8 +122,8 @@ var/unknown = 0 var/reagentdata[0] var/unknownreagents[0] - for(var/A in C.reagents.reagent_list) - var/datum/reagent/R = A + for(var/A in C.reagents.reagent_volumes) + var/datum/reagent/R = SSchemistry.fetch_reagent(A) if(R.scannable) reagentdata["[R.id]"] = SPAN_NOTICE("\n[round(C.reagents.get_reagent_amount(R.id), 1)]u [R.name]") else @@ -144,8 +144,8 @@ var/unknown = 0 var/stomachreagentdata[0] var/stomachunknownreagents[0] - for(var/B in C.ingested.reagent_list) - var/datum/reagent/T = B + for(var/B in C.ingested.reagent_volumes) + var/datum/reagent/T = SSchemistry.fetch_reagent(B) if(T.scannable) stomachreagentdata["[T.id]"] = SPAN_NOTICE("\n[round(C.ingested.get_reagent_amount(T.id), 1)]u [T.name]") if (advscan == 0 || showadvscan == 0) @@ -168,8 +168,8 @@ var/unknown = 0 var/touchreagentdata[0] var/touchunknownreagents[0] - for(var/B in C.touching.reagent_list) - var/datum/reagent/T = B + for(var/B in C.touching.reagent_volumes) + var/datum/reagent/T = SSchemistry.fetch_reagent(B) if(T.scannable) touchreagentdata["[T.id]"] = SPAN_NOTICE("\n[round(C.touching.get_reagent_amount(T.id), 1)]u [T.name]") if (advscan == 0 || showadvscan == 0) @@ -258,7 +258,7 @@ // Blood level if(M:vessel) - var/blood_volume = H.vessel.get_reagent_amount("blood") + var/blood_volume = H.blood_holder.get_total_volume() var/blood_percent = round((blood_volume / H.species.blood_volume)*100) var/blood_type = H.dna.b_type if(blood_volume <= H.species.blood_volume*H.species.blood_level_danger) diff --git a/code/game/objects/items/scanners/plant.dm b/code/game/objects/items/scanners/plant.dm index b517b638c1cc..73acc8b91f3c 100644 --- a/code/game/objects/items/scanners/plant.dm +++ b/code/game/objects/items/scanners/plant.dm @@ -90,12 +90,12 @@ user.visible_message("[user] runs the scanner over \the [target].") last_reagents = list() - if(grown_reagents && grown_reagents.reagent_list && grown_reagents.reagent_list.len) - for(var/datum/reagent/R in grown_reagents.reagent_list) - last_reagents.Add(list(list( - "name" = R.name, - "volume" = grown_reagents.get_reagent_amount(R.id), - ))) + for(var/reagent_id in grown_reagents?.reagent_volumes) + var/datum/reagent/R = SSchemistry.fetch_reagent(reagent_id) + last_reagents.Add(list(list( + "name" = R.name, + "volume" = grown_reagents.get_reagent_amount(R.id), + ))) ui_interact(user) diff --git a/code/game/objects/items/scanners/reagent.dm b/code/game/objects/items/scanners/reagent.dm index b76223f485bf..c32663a78554 100644 --- a/code/game/objects/items/scanners/reagent.dm +++ b/code/game/objects/items/scanners/reagent.dm @@ -27,10 +27,11 @@ return var/dat = "" - if(target.reagents.reagent_list.len > 0) + if(target.reagents.reagent_volumes.len > 0) var/one_percent = target.reagents.total_volume / 100 - for (var/datum/reagent/R in target.reagents.reagent_list) - dat += "\n \t " + SPAN_NOTICE("[R][details ? ": [R.volume / one_percent]%" : ""]") + for (var/id in target.reagents.reagent_volumes) + var/datum/reagent/R = SSchemistry.fetch_reagent(id) + dat += "\n \t " + SPAN_NOTICE("[R][details ? ": [target.reagents.reagent_volumes[id] / one_percent]%" : ""]") if(dat) to_chat(user, SPAN_NOTICE("Chemicals found: [dat]")) else diff --git a/code/game/objects/items/scanners/spectrometer.dm b/code/game/objects/items/scanners/spectrometer.dm index d5619348f47a..8668ba41ada6 100644 --- a/code/game/objects/items/scanners/spectrometer.dm +++ b/code/game/objects/items/scanners/spectrometer.dm @@ -39,13 +39,13 @@ return if(reagents.total_volume) var/list/blood_traces = list() - for(var/datum/reagent/R in reagents.reagent_list) - if(R.id != "blood") - reagents.clear_reagents() - to_chat(user, "The sample was contaminated! Please insert another sample") - return + for(var/id in reagents.reagent_volumes) + var/datum/reagent/R = SSchemistry.fetch_reagent(id) + if(R.type != /datum/reagent/blood) + continue else - blood_traces = params2list(R.data["trace_chem"]) + var/datum/blood_mixture/mixture = reagents.reagent_datas?[id] + blood_traces = params2list(mixture.legacy_trace_chem) break var/dat = "Trace Chemicals Found: " for(var/R in blood_traces) diff --git a/code/game/objects/items/toys/balloon.dm b/code/game/objects/items/toys/balloon.dm new file mode 100644 index 000000000000..680d76fb2b0d --- /dev/null +++ b/code/game/objects/items/toys/balloon.dm @@ -0,0 +1,60 @@ +/obj/item/toy/balloon + name = "water balloon" + desc = "A translucent balloon. There's nothing in it." + icon = 'icons/obj/toy.dmi' + icon_state = "waterballoon-e" + damage_force = 0 + +/obj/item/toy/balloon/Initialize(mapload) + . = ..() + create_reagents(10) + +/obj/item/toy/balloon/afterattack(atom/target, mob/user, clickchain_flags, list/params) + if(!(clickchain_flags & CLICKCHAIN_HAS_PROXIMITY)) return + if (istype(target, /obj/structure/reagent_dispensers/watertank) && get_dist(src,target) <= 1) + target.reagents.trans_to_obj(src, 10) + to_chat(user, "You fill the balloon with the contents of [target].") + src.desc = "A translucent balloon with some form of liquid sloshing around in it." + src.update_icon() + return + +/obj/item/toy/balloon/attackby(obj/O as obj, mob/user as mob) + if(istype(O, /obj/item/reagent_containers/glass)) + if(O.reagents) + if(O.reagents.total_volume < 1) + to_chat(user, "The [O] is empty.") + else if(O.reagents.total_volume >= 1) + if(O.reagents.has_reagent("pacid", 1)) + to_chat(user, "The acid chews through the balloon!") + O.reagents.splash(user, reagents.total_volume) + qdel(src) + else + src.desc = "A translucent balloon with some form of liquid sloshing around in it." + to_chat(user, "You fill the balloon with the contents of [O].") + O.reagents.trans_to_obj(src, 10) + src.update_icon() + return + +/obj/item/toy/balloon/throw_impact(atom/A, datum/thrownthing/TT) + . = ..() + if(!(TT.throw_flags & THROW_AT_IS_GENTLE)) + if(src.reagents.total_volume >= 1) + src.visible_message("\The [src] bursts!","You hear a pop and a splash.") + reagents.auto_spill(A, 1, TRUE, FALSE) + src.icon_state = "burst" + QDEL_IN(src, 5) + +/obj/item/toy/balloon/throw_land(atom/A, datum/thrownthing/TT) + . = ..() + if(!(TT.throw_flags & THROW_AT_IS_GENTLE)) + if(src.reagents.total_volume >= 1) + src.visible_message("\The [src] bursts!","You hear a pop and a splash.") + reagents.auto_spill(A, 1, TRUE, FALSE) + src.icon_state = "burst" + QDEL_IN(src, 5) + +/obj/item/toy/balloon/update_icon() + if(src.reagents.total_volume >= 1) + icon_state = "waterballoon" + else + icon_state = "waterballoon-e" diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys/toys.dm similarity index 93% rename from code/game/objects/items/toys.dm rename to code/game/objects/items/toys/toys.dm index 069da682a19a..02faa2c0f852 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys/toys.dm @@ -27,64 +27,9 @@ throw_range = 20 damage_force = 0 - /* * Balloons */ -/obj/item/toy/balloon - name = "water balloon" - desc = "A translucent balloon. There's nothing in it." - icon = 'icons/obj/toy.dmi' - icon_state = "waterballoon-e" - damage_force = 0 - -/obj/item/toy/balloon/Initialize(mapload) - . = ..() - create_reagents(10) - -/obj/item/toy/balloon/afterattack(atom/target, mob/user, clickchain_flags, list/params) - if(!(clickchain_flags & CLICKCHAIN_HAS_PROXIMITY)) return - if (istype(target, /obj/structure/reagent_dispensers/watertank) && get_dist(src,target) <= 1) - target.reagents.trans_to_obj(src, 10) - to_chat(user, "You fill the balloon with the contents of [target].") - src.desc = "A translucent balloon with some form of liquid sloshing around in it." - src.update_icon() - return - -/obj/item/toy/balloon/attackby(obj/O as obj, mob/user as mob) - if(istype(O, /obj/item/reagent_containers/glass)) - if(O.reagents) - if(O.reagents.total_volume < 1) - to_chat(user, "The [O] is empty.") - else if(O.reagents.total_volume >= 1) - if(O.reagents.has_reagent("pacid", 1)) - to_chat(user, "The acid chews through the balloon!") - O.reagents.splash(user, reagents.total_volume) - qdel(src) - else - src.desc = "A translucent balloon with some form of liquid sloshing around in it." - to_chat(user, "You fill the balloon with the contents of [O].") - O.reagents.trans_to_obj(src, 10) - src.update_icon() - return - -/obj/item/toy/balloon/throw_impact(atom/hit_atom) - if(src.reagents.total_volume >= 1) - src.visible_message("\The [src] bursts!","You hear a pop and a splash.") - src.reagents.touch_turf(get_turf(hit_atom)) - for(var/atom/A in get_turf(hit_atom)) - src.reagents.touch(A) - src.icon_state = "burst" - spawn(5) - if(src) - qdel(src) - return - -/obj/item/toy/balloon/update_icon() - if(src.reagents.total_volume >= 1) - icon_state = "waterballoon" - else - icon_state = "waterballoon-e" /obj/item/toy/syndicateballoon name = "criminal balloon" @@ -401,70 +346,6 @@ playsound(src, 'sound/effects/snap.ogg', 50, 1) qdel(src) -/* - * Water flower - */ -/obj/item/toy/waterflower - name = "water flower" - desc = "A seemingly innocent sunflower...with a twist." - icon = 'icons/obj/device.dmi' - icon_state = "sunflower" - item_state = "sunflower" - var/empty = 0 - slot_flags = SLOT_HOLSTER - damage_force = 0 - -/obj/item/toy/waterflower/Initialize(mapload) - . = ..() - var/datum/reagent_holder/R = create_reagents(10) - R.add_reagent("water", 10) - -/obj/item/toy/waterflower/afterattack(atom/target, mob/user, clickchain_flags, list/params) - - if (istype(target, /obj/item/storage/backpack )) - return - - else if (locate (/obj/structure/table, src.loc)) - return - - else if (istype(target, /obj/structure/reagent_dispensers/watertank) && get_dist(src,target) <= 1) - target.reagents.trans_to(src, 10) - to_chat(user, "You refill your flower!") - return - - else if (src.reagents.total_volume < 1) - src.empty = 1 - to_chat(user, "Your flower has run dry!") - return - - else - src.empty = 0 - - - var/obj/effect/decal/D = new/obj/effect/decal/(get_turf(src)) - D.name = "water" - D.icon = 'icons/obj/medical/chemical.dmi' - D.icon_state = "chempuff" - D.create_reagents(5) - src.reagents.trans_to_obj(D, 1) - playsound(src.loc, 'sound/effects/spray3.ogg', 50, 1, -6) - - spawn(0) - for(var/i=0, i<1, i++) - step_towards(D,target) - D.reagents.touch_turf(get_turf(D)) - for(var/atom/T in get_turf(D)) - D.reagents.touch(T) - if(ismob(T)) - to_chat(T, "\The [user] has sprayed you with water!") - sleep(4) - qdel(D) - - return - -/obj/item/toy/waterflower/examine(mob/user, dist) - . = ..() - . += "[src] has [src.reagents.total_volume] units of water left!" /* * Bosun's whistle diff --git a/code/game/objects/random/mapping.dm b/code/game/objects/random/mapping.dm index c53397dcc2dd..aaaec4bc5b57 100644 --- a/code/game/objects/random/mapping.dm +++ b/code/game/objects/random/mapping.dm @@ -419,7 +419,7 @@ /obj/item/pda/clown, /obj/item/clothing/mask/gas/clown_hat, /obj/item/bikehorn, - /obj/item/toy/waterflower, + /obj/item/reagent_containers/spray/waterflower, /obj/item/pen/crayon/rainbow, /obj/structure/closet/crate ), diff --git a/code/game/objects/random/misc.dm b/code/game/objects/random/misc.dm index e7868cde8b70..f5003588af29 100644 --- a/code/game/objects/random/misc.dm +++ b/code/game/objects/random/misc.dm @@ -540,7 +540,7 @@ /obj/item/toy/balloon, /obj/item/toy/crossbow, /obj/item/toy/blink, - /obj/item/toy/waterflower, + /obj/item/reagent_containers/spray/waterflower, /obj/item/toy/eight_ball, /obj/item/toy/eight_ball/conch, /obj/item/toy/prize/ripley, diff --git a/code/game/objects/structures/medical_stand_vr.dm b/code/game/objects/structures/medical_stand.dm similarity index 97% rename from code/game/objects/structures/medical_stand_vr.dm rename to code/game/objects/structures/medical_stand.dm index 05f1c7681468..34149bf080e3 100644 --- a/code/game/objects/structures/medical_stand_vr.dm +++ b/code/game/objects/structures/medical_stand.dm @@ -423,15 +423,10 @@ return // If the human is losing too much blood, beep. - if(H.vessel.get_reagent_amount("blood") < H.species.blood_volume*H.species.blood_level_safe) + if(H.blood_holder.get_total_volume() < H.species.blood_volume*H.species.blood_level_safe) visible_message("\The [src] beeps loudly.") - var/datum/reagent/B = H.take_blood(beaker,amount) - if (B) - beaker.reagents.reagent_list |= B - beaker.reagents.update_total() - beaker.on_reagent_change() - beaker.reagents.reconsider_reactions() + if(H.take_blood_legacy(beaker, amount) > 0) update_icon() if ((!valve_opened || tank.distribute_pressure == 0) && !breather && !attached) diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm index 999bdbbaa7e9..807fe344005a 100644 --- a/code/game/turfs/simulated.dm +++ b/code/game/turfs/simulated.dm @@ -34,6 +34,7 @@ return ..() // This is not great. +// todo: this is shit, rework wet floors to be component, element, or just a goddamn cached datum at this point /turf/simulated/proc/wet_floor(var/wet_val = 1) if(wet > 2) //Can't mop up ice return @@ -43,9 +44,9 @@ cut_overlay(wet_overlay) wet_overlay = image('icons/effects/water.dmi', icon_state = "wet_floor") add_overlay(wet_overlay) - sleep(800) + sleep(1 MINUTES + 20 SECONDS) if(wet == 2) - sleep(3200) + sleep(5 MINUTES + 20 SECONDS) wet = 0 if(wet_overlay) cut_overlay(wet_overlay) @@ -167,7 +168,7 @@ B.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type B.virus2 = virus_copylist(M.virus2) return 1 //we bloodied the floor - blood_splatter(src,M.get_blood(M.vessel),1) + blood_splatter_legacy(src, M.get_blood_mixture(), TRUE) return 1 //we bloodied the floor return 0 diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm index 62daecd72cc6..080c1d36241f 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm @@ -1045,42 +1045,6 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null v = Failsafe if("CFG") v = config -/* - //Subsystem switches - if("SSgarbage") - v = SSgarbage - if("SSmachines") - v = SSmachines - if("SSobj") - v = SSobj - if("SSresearch") - v = SSresearch - if("SSprojectiles") - v = SSprojectiles - if("SSprocess_5fps") - v = SSprocess_5fps - if("SSticker") - v = SSticker - if("SStimer") - v = SStimer - if("SSradiation") - v = SSradiation - if("SSnpcpool") - v = SSnpcpool - if("SSmobs") - v = SSmobs - if("SSquirks") - v = SSquirks - if("SSwet_floors") - v = SSwet_floors - if("SSshuttle") - v = SSshuttle - if("SSmapping") - v = SSmapping - if("SSevents") - v = SSevents - //End -*/ else return null else if(object == GLOB) // Shitty ass hack kill me. diff --git a/code/modules/detectivework/tools/rag.dm b/code/modules/detectivework/tools/rag.dm index fdf66d521e5a..3e97be729505 100644 --- a/code/modules/detectivework/tools/rag.dm +++ b/code/modules/detectivework/tools/rag.dm @@ -190,8 +190,8 @@ fuel += reagents.get_reagent_amount("fuel") else - for(var/datum/reagent/ethanol/R in reagents.reagent_list) - fuel += reagents.get_reagent_amount(R.id) + for(var/datum/reagent/ethanol/R in reagents.get_reagent_datums()) + fuel += reagents.reagent_volumes[R.id] return (fuel >= 2 && fuel >= reagents.total_volume*0.8) @@ -250,7 +250,7 @@ return reagents.remove_reagent("fuel", reagents.maximum_volume/25) - for(var/datum/reagent/ethanol/R in reagents.reagent_list) + for(var/datum/reagent/ethanol/R in reagents.get_reagent_datums()) if(istype(R, /datum/reagent/ethanol)) reagents.remove_reagent(R.id, reagents.maximum_volume/25) update_name() diff --git a/code/modules/food/drinkingglass/glass1.dm b/code/modules/food/drinkingglass/glass1.dm index 9a8a1fac1857..8c3c57d7f8dc 100644 --- a/code/modules/food/drinkingglass/glass1.dm +++ b/code/modules/food/drinkingglass/glass1.dm @@ -18,8 +18,8 @@ /*else if(reagents.reagent_list.len == 1) for(var/datum/reagent/R in reagents.reagent_list) switch(R.id)*/ - if (reagents.reagent_list.len > 0) - var/datum/reagent/R = reagents.get_master_reagent() + if (reagents.total_volume) + var/datum/reagent/R = reagents.get_majority_reagent_datum() if(R.glass_icon_state) icon_state = R.glass_icon_state @@ -62,8 +62,8 @@ materials_base = list(MAT_GLASS = 60) /obj/item/reagent_containers/food/drinks/cup/on_reagent_change() - if (reagents.reagent_list.len > 0) - var/datum/reagent/R = reagents.get_master_reagent() + if (reagents.total_volume) + var/datum/reagent/R = reagents.get_majority_reagent_datum() if(R.cup_icon_state) icon_state = R.cup_icon_state @@ -132,7 +132,7 @@ filling.color += reagents.get_color() add_overlay(filling) - name = "shot glass of " + reagents.get_master_reagent_name() //No matter what, the glass will tell you the reagent's name. Might be too abusable in the future. + name = "shot glass of " + reagents.get_majority_reagent_name() //No matter what, the glass will tell you the reagent's name. Might be too abusable in the future. else name = "shot glass" diff --git a/code/modules/food/drinkingglass/glass2.dm b/code/modules/food/drinkingglass/glass2.dm index 65a6a64e32f8..97edc8f12b29 100644 --- a/code/modules/food/drinkingglass/glass2.dm +++ b/code/modules/food/drinkingglass/glass2.dm @@ -45,8 +45,8 @@ . += "It is fizzing slightly." /obj/item/reagent_containers/food/drinks/glass2/proc/has_ice() - if(reagents.reagent_list.len > 0) - var/datum/reagent/R = reagents.get_master_reagent() + if(reagents.total_volume) + var/datum/reagent/R = reagents.get_majority_reagent_datum() if(!((R.id == "ice") || ("ice" in R.glass_special))) // if it's not a cup of ice, and it's not already supposed to have ice in, see if the bartender's put ice in it if(reagents.has_reagent("ice", reagents.total_volume / 10)) // 10% ice by volume return 1 @@ -54,13 +54,13 @@ return 0 /obj/item/reagent_containers/food/drinks/glass2/proc/has_fizz() - if(reagents.reagent_list.len > 0) - var/datum/reagent/R = reagents.get_master_reagent() + if(reagents.total_volume) + var/datum/reagent/R = reagents.get_majority_reagent_datum() if(!("fizz" in R.glass_special)) var/totalfizzy = 0 - for(var/datum/reagent/re in reagents.reagent_list) + for(var/datum/reagent/re in reagents.get_reagent_datums()) if("fizz" in re.glass_special) - totalfizzy += re.volume + totalfizzy += reagents.reagent_volumes[re.id] if(totalfizzy >= reagents.total_volume / 5) // 20% fizzy by volume return 1 return 0 @@ -84,8 +84,8 @@ /obj/item/reagent_containers/food/drinks/glass2/update_icon() underlays.Cut() - if (reagents.reagent_list.len > 0) - var/datum/reagent/R = reagents.get_master_reagent() + if (reagents.total_volume) + var/datum/reagent/R = reagents.get_majority_reagent_datum() name = "[base_name] of [R.glass_name ? R.glass_name : "something"]" desc = R.glass_desc ? R.glass_desc : initial(desc) diff --git a/code/modules/food/drinkingglass/metaglass.dm b/code/modules/food/drinkingglass/metaglass.dm index 2ce50b7d500f..3da94ee4f1c5 100644 --- a/code/modules/food/drinkingglass/metaglass.dm +++ b/code/modules/food/drinkingglass/metaglass.dm @@ -10,8 +10,8 @@ icon = 'icons/obj/drinks.dmi' /obj/item/reagent_containers/food/drinks/metaglass/on_reagent_change() - if (reagents.reagent_list.len > 0) - var/datum/reagent/R = reagents.get_master_reagent() + if (reagents.total_volume) + var/datum/reagent/R = reagents.get_majority_reagent_datum() if(R.glass_icon_state) icon_state = R.glass_icon_state @@ -49,10 +49,6 @@ Drinks Data */ -/datum/reagent - var/glass_icon_state = null - var/glass_center_of_mass = null - /datum/reagent/adminordrazine glass_icon_state = "golden_cup" diff --git a/code/modules/food/drinks/cup.dm b/code/modules/food/drinks/cup.dm index 5e4f9e26681c..d2d89b515c4e 100644 --- a/code/modules/food/drinks/cup.dm +++ b/code/modules/food/drinks/cup.dm @@ -8,8 +8,8 @@ /obj/item/reagent_containers/food/drinks/cup/on_reagent_change() ..() - if (reagents.reagent_list.len > 0) - var/datum/reagent/R = reagents.get_master_reagent() + if (reagents.total_volume) + var/datum/reagent/R = reagents.get_majority_reagent_datum() if(R.cup_icon_state) icon_state = R.cup_icon_state @@ -58,8 +58,8 @@ 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(changetype) - if (reagents.reagent_list.len) - switch(reagents.get_master_reagent_id()) + if (reagents.total_volume) + switch(reagents.get_majority_reagent_id()) if("orangejuice") icon_state = "orangebox" name = "orange juice box" diff --git a/code/modules/food/drinks/jar.dm b/code/modules/food/drinks/jar.dm index db60cc816231..cb4c7d1d9cc1 100644 --- a/code/modules/food/drinks/jar.dm +++ b/code/modules/food/drinks/jar.dm @@ -8,8 +8,8 @@ integrity_flags = INTEGRITY_ACIDPROOF /obj/item/reagent_containers/food/drinks/jar/on_reagent_change() - if (reagents.reagent_list.len > 0) - switch(reagents.get_master_reagent_id()) + if (reagents.total_volume > 0) + switch(reagents.get_majority_reagent_id()) if("slime") icon_state = "jar_slime" name = "slime jam" diff --git a/code/modules/food/food.dm b/code/modules/food/food.dm index 64318cdd0de6..a7e966b53add 100644 --- a/code/modules/food/food.dm +++ b/code/modules/food/food.dm @@ -37,8 +37,9 @@ src.pixel_y = rand(-6.0, 6) . = ..() // prefill depending on if we were cooked or an actual spawn. + var/static/datum/nutriment_data/static_nutrient_data_initializer = new /datum/nutriment_data/static_spawn_initializer for(var/key in cooked? inherent_reagents : inherent_reagents | prefill_reagents) - reagents.add_reagent(key, inherent_reagents[key]) + reagents.add_reagent(key, inherent_reagents[key], static_nutrient_data_initializer) /obj/item/reagent_containers/food/afterattack(atom/target, mob/user, clickchain_flags, list/params) if(center_of_mass.len && (clickchain_flags & CLICKCHAIN_HAS_PROXIMITY) && istype(target, /obj/structure/table)) diff --git a/code/modules/food/food/condiment.dm b/code/modules/food/food/condiment.dm index e23b5299148f..e434f36269c2 100644 --- a/code/modules/food/food/condiment.dm +++ b/code/modules/food/food/condiment.dm @@ -57,8 +57,8 @@ to_chat(user, "You swallow some of contents of \the [src].") /obj/item/reagent_containers/food/condiment/on_reagent_change() - if(reagents.reagent_list.len > 0) - switch(reagents.get_master_reagent_id()) + if(reagents.total_volume) + switch(reagents.get_majority_reagent_id()) if("ketchup") name = "Ketchup" desc = "You feel more American already." @@ -117,10 +117,10 @@ center_of_mass = list("x"=16, "y"=6) // END CITADEL CHANGE - AURORA KITCHEN PORT else name = "Misc Condiment Bottle" - if (reagents.reagent_list.len==1) - desc = "Looks like it is [reagents.get_master_reagent_name()], but you are not sure." + if (length(reagents.reagent_volumes) > 1) + desc = "Looks like it is [reagents.get_majority_reagent_name()], but you are not sure." else - desc = "A mixture of various condiments. [reagents.get_master_reagent_name()] is one of them." + desc = "A mixture of various condiments. [reagents.get_majority_reagent_name()] is one of them." icon_state = "mixedcondiments" center_of_mass = list("x"=16, "y"=6) else diff --git a/code/modules/food/food/drinks.dm b/code/modules/food/food/drinks.dm index 22144611a5b0..a1a40f592066 100644 --- a/code/modules/food/food/drinks.dm +++ b/code/modules/food/food/drinks.dm @@ -17,8 +17,8 @@ var/custom_open_sound /obj/item/reagent_containers/food/drinks/on_reagent_change() - if (reagents.reagent_list.len > 0) - var/datum/reagent/R = reagents.get_master_reagent() + if (reagents.total_volume) + var/datum/reagent/R = reagents.get_majority_reagent_datum() if(R.price_tag) price_tag = R.price_tag else @@ -94,7 +94,7 @@ else . += "\The [src] is full!" if(reagents) - var/datum/reagent/ethanol/R = locate() in reagents.reagent_list + var/datum/reagent/ethanol/R = locate() in reagents.get_reagent_datums() if(istype(R)) . += "It contains alcohol." diff --git a/code/modules/food/food/snacks.dm b/code/modules/food/food/snacks.dm index 4992efb9a1ea..ea4af7a28325 100644 --- a/code/modules/food/food/snacks.dm +++ b/code/modules/food/food/snacks.dm @@ -16,6 +16,7 @@ var/survivalfood = FALSE var/nutriment_amt = 0 var/list/nutriment_desc = list("food" = 1) + #warn ohhh no var/datum/reagent/nutriment/coating/coating = null var/sealed = FALSE var/custom_open_sound @@ -3985,9 +3986,7 @@ END CITADEL CHANGE */ //Code for dipping food in batter /obj/item/reagent_containers/food/snacks/afterattack(atom/target, mob/user, clickchain_flags, list/params) if(target.is_open_container() && target.reagents && !(istype(target, /obj/item/reagent_containers/food))) - for (var/r in target.reagents.reagent_list) - - var/datum/reagent/R = r + for(var/datum/reagent/R as anything in target.reagents.get_reagent_datums()) if (istype(R, /datum/reagent/nutriment/coating)) if (apply_coating(R, user)) return 1 @@ -4002,12 +4001,11 @@ END CITADEL CHANGE */ //Calculate the reagents of the coating needed var/req = 0 - for (var/r in reagents.reagent_list) - var/datum/reagent/R = r + for(var/datum/reagent/R as anything in reagents.get_reagent_datums()) if (istype(R, /datum/reagent/nutriment)) - req += R.volume * 0.2 + req += reagents.reagent_volumes[R.id] * 0.2 else - req += R.volume * 0.1 + req += reagents.reagent_volumes[R.id] * 0.1 req += w_class*0.5 @@ -4030,7 +4028,7 @@ END CITADEL CHANGE */ C.holder.trans_to_holder(reagents, req) //We're done with C now, repurpose the var to hold a reference to our local instance of it - C = reagents.get_reagent(id) + C = SSchemistry.fetch_reagent(id) if (!C) return diff --git a/code/modules/food/machinery/appliance/_appliance.dm b/code/modules/food/machinery/appliance/_appliance.dm index 7f6356ef76ce..c723c8f36aac 100644 --- a/code/modules/food/machinery/appliance/_appliance.dm +++ b/code/modules/food/machinery/appliance/_appliance.dm @@ -297,26 +297,25 @@ for (var/obj/item/J in CI.container) oilwork(J, CI) - for (var/r in CI.container.reagents.reagent_list) - var/datum/reagent/R = r - if (istype(R, /datum/reagent/nutriment)) - CI.max_cookwork += R.volume *2//Added reagents contribute less than those in food items due to granular form - - //Nonfat reagents will soak oil - if (!istype(R, /datum/reagent/nutriment/triglyceride)) - CI.max_oil += R.volume * 0.25 + for(var/id in CI.container.reagents.reagent_volumes) + var/datum/reagent/the_reagent = SSchemistry.fetch_reagent(id) + var/the_volume = CI.container.reagents.reagent_volumes[id] + if(istype(the_reagent, /datum/reagent/nutriment)) + CI.max_cookwork += the_volume * 2 + if(!istype(the_reagent, /datum/reagent/nutriment/triglyceride)) + CI.max_oil += the_volume * 0.25 else - CI.max_cookwork += R.volume - CI.max_oil += R.volume * 0.10 + CI.max_cookwork += the_volume + CI.max_oil += the_volume * 0.1 //Rescaling cooking work to avoid insanely long times for large things var/buffer = CI.max_cookwork CI.max_cookwork = 0 var/multiplier = 1 - var/step = 4 - while (buffer > step) - buffer -= step - CI.max_cookwork += step*multiplier + var/step_amount = 4 + while (buffer > step_amount) + buffer -= step_amount + CI.max_cookwork += step_amount * multiplier multiplier *= 0.95 CI.max_cookwork += buffer*multiplier @@ -326,19 +325,16 @@ var/obj/item/reagent_containers/food/snacks/S = I var/work = 0 if (istype(S)) - if (S.reagents) - for (var/r in S.reagents.reagent_list) - var/datum/reagent/R = r - if (istype(R, /datum/reagent/nutriment)) - work += R.volume *3//Core nutrients contribute much more than peripheral chemicals - - //Nonfat reagents will soak oil - if (!istype(R, /datum/reagent/nutriment/triglyceride)) - CI.max_oil += R.volume * 0.35 - else - work += R.volume - CI.max_oil += R.volume * 0.15 - + for(var/id in S.reagents.reagent_volumes) + var/datum/reagent/the_reagent = SSchemistry.fetch_reagent(id) + var/the_volume = S.reagents.reagent_volumes[id] + if(istype(the_reagent, /datum/reagent/nutriment)) + work += the_volume + if(!istype(the_reagent, /datum/reagent/nutriment/triglyceride)) + CI.max_oil += the_volume * 0.35 + else + work += the_volume + CI.max_oil += the_volume * 0.15 else if(istype(I, /obj/item/holder)) var/obj/item/holder/H = I diff --git a/code/modules/food/machinery/appliance/container.dm b/code/modules/food/machinery/appliance/container.dm index 4005e7741f02..e7990da77b00 100644 --- a/code/modules/food/machinery/appliance/container.dm +++ b/code/modules/food/machinery/appliance/container.dm @@ -110,7 +110,7 @@ .+=O.name//Just append the name of the first object return else if (reagents && reagents.total_volume > 0) - var/datum/reagent/R = reagents.get_master_reagent() + var/datum/reagent/R = reagents.get_majority_reagent_datum() .+=R.name//Append name of most voluminous reagent return else diff --git a/code/modules/food/machinery/appliance/fryer.dm b/code/modules/food/machinery/appliance/fryer.dm index 03ee80157ae5..55a37838226a 100644 --- a/code/modules/food/machinery/appliance/fryer.dm +++ b/code/modules/food/machinery/appliance/fryer.dm @@ -46,26 +46,17 @@ /obj/machinery/appliance/cooker/fryer/heat_up() if (..()) - //Set temperature of oil reagent - var/datum/reagent/nutriment/triglyceride/oil/OL = oil.get_master_reagent() - if (OL && istype(OL)) - OL.data["temperature"] = temperature + oil.temperature = temperature /obj/machinery/appliance/cooker/fryer/equalize_temperature() if (..()) //Set temperature of oil reagent - var/datum/reagent/nutriment/triglyceride/oil/OL = oil.get_master_reagent() - if (OL && istype(OL)) - OL.data["temperature"] = temperature - + oil.temperature = temperature /obj/machinery/appliance/cooker/fryer/update_cooking_power() ..()//In addition to parent temperature calculation //Fryer efficiency also drops when oil levels arent optimal - var/oil_level = 0 - var/datum/reagent/nutriment/triglyceride/oil/OL = oil.get_master_reagent() - if (OL && istype(OL)) - oil_level = OL.volume + var/oil_level = oil.reagent_volumes[/datum/reagent/nutriment/triglyceride/oil::id] || 0 var/oil_efficiency = 0 if (oil_level) @@ -104,19 +95,21 @@ var/total_oil = 0 var/total_our_oil = 0 var/total_removed = 0 - var/datum/reagent/our_oil = oil.get_master_reagent() + var/datum/reagent/our_oil = oil.get_majority_reagent_datum() for (var/obj/item/I in CI.container) - if (I.reagents && I.reagents.total_volume) - for (var/datum/reagent/R in I.reagents.reagent_list) - if (istype(R, /datum/reagent/nutriment/triglyceride/oil)) - total_oil += R.volume - if (R.id != our_oil.id) - total_removed += R.volume - I.reagents.remove_reagent(R.id, R.volume) - else - total_our_oil += R.volume - + if(!I.reagents?.total_volume) + continue + for(var/datum/reagent/reagent as anything in I.reagents.get_reagent_datums()) + if(!istype(reagent, /datum/reagent/nutriment/triglyceride/oil)) + continue + var/the_volume = I.reagents.reagent_volumes[reagent.id] + total_oil += the_volume + if(reagent.id != our_oil.id) + total_removed += the_volume + I.reagents.remove_reagent(reagent.id, the_volume) + else + total_our_oil += the_volume if (total_removed > 0 || total_oil != CI.max_oil) total_oil = min(total_oil, CI.max_oil) @@ -131,13 +124,10 @@ //If we have more than the maximum allowed then we delete some. //This could only happen if one of the objects spawns with the same type of oil as ours var/portion = 1 - (total_oil / total_our_oil) //find the percentage to remove - for (var/obj/item/I in CI.container) - if (I.reagents && I.reagents.total_volume) - for (var/datum/reagent/R in I.reagents.reagent_list) - if (R.id == our_oil.id) - I.reagents.remove_reagent(R.id, R.volume*portion) - - + for (var/obj/item/I as anything in CI.container) + if(!I.reagents?.total_volume) + continue + I.reagents.remove_reagent(our_oil.id, I.reagents.reagent_volumes[our_oil.id] * portion) /obj/machinery/appliance/cooker/fryer/cook_mob(var/mob/living/victim, var/mob/user) @@ -160,8 +150,8 @@ var/damage = rand(7,13) //Though this damage seems reduced, some hot oil is transferred to the victim and will burn them for a while after - var/datum/reagent/nutriment/triglyceride/oil/OL = oil.get_master_reagent() - damage *= OL.heatdamage(victim) + var/datum/reagent/nutriment/triglyceride/oil/OL = oil.get_majority_reagent_datum() + damage *= OL.heatdamage(victim, oil) var/obj/item/organ/external/E var/nopain diff --git a/code/modules/food/machinery/microwave.dm b/code/modules/food/machinery/microwave.dm index 8318bb6802ca..27ba7308e3de 100644 --- a/code/modules/food/machinery/microwave.dm +++ b/code/modules/food/machinery/microwave.dm @@ -130,8 +130,8 @@ ) if (!O.reagents) return 1 - for (var/datum/reagent/R in O.reagents.reagent_list) - if (!(R.id in acceptable_reagents)) + for (var/id in O.reagents.reagent_volumes) + if (!(id in acceptable_reagents)) to_chat(user, "Your [O] contains components unsuitable for cookery.") return 1 return @@ -211,15 +211,15 @@ else dat += {"[capitalize(O)]: [N] [items_measures_p[O]]
"} - for (var/datum/reagent/R in reagents.reagent_list) + for (var/datum/reagent/R in reagents.get_reagent_datums()) var/display_name = R.name if (R.id == "capsaicin") display_name = "Hotsauce" if (R.id == "frostoil") display_name = "Coldsauce" - dat += {"[display_name]: [R.volume] unit\s
"} + dat += {"[display_name]: [reagents.reagent_volumes[R.id]] unit\s
"} - if (items_counts.len==0 && reagents.reagent_list.len==0) + if (items_counts.len==0 && !reagents.total_volume==0) dat = {"The microwave is empty
"} else dat = {"Ingredients:
[dat]"} @@ -405,7 +405,7 @@ for (var/obj/O in contents-ffuu) amount++ if (O.reagents) - var/id = O.reagents.get_master_reagent_id() + var/id = O.reagents.get_majority_reagent_id() if (id) amount+=O.reagents.get_reagent_amount(id) qdel(O) diff --git a/code/modules/hardsuits/modules/utility.dm b/code/modules/hardsuits/modules/utility.dm index f5fb2a8f031e..1da36cd43028 100644 --- a/code/modules/hardsuits/modules/utility.dm +++ b/code/modules/hardsuits/modules/utility.dm @@ -180,12 +180,12 @@ // Magical chemical filtration system, do not question it. var/total_transferred = 0 - for(var/datum/reagent/R in input_item.reagents.reagent_list) + for(var/datum/reagent/R in input_item.reagents.get_reagent_datums()) for(var/chargetype in charges) var/datum/rig_charge/charge = charges[chargetype] if(charge.display_name == R.id) - var/chems_to_transfer = R.volume + var/chems_to_transfer = input_item.reagents.reagent_volumes[R.id] if((charge.charges + chems_to_transfer) > max_reagent_volume) chems_to_transfer = max_reagent_volume - charge.charges @@ -193,7 +193,6 @@ charge.charges += chems_to_transfer input_item.reagents.remove_reagent(R.id, chems_to_transfer) total_transferred += chems_to_transfer - break if(total_transferred) diff --git a/code/modules/hydroponics/trays/tray.dm b/code/modules/hydroponics/trays/tray.dm index 707cf82533f7..9fd56cde328c 100644 --- a/code/modules/hydroponics/trays/tray.dm +++ b/code/modules/hydroponics/trays/tray.dm @@ -241,7 +241,7 @@ reagents.trans_to_obj(temp_chem_holder, min(reagents.total_volume,rand(1,3))) - for(var/datum/reagent/R in temp_chem_holder.reagents.reagent_list) + for(var/datum/reagent/R in temp_chem_holder.reagents.get_reagent_datums()) var/reagent_total = temp_chem_holder.reagents.get_reagent_amount(R.id) diff --git a/code/modules/integrated_electronics/passive/power.dm b/code/modules/integrated_electronics/passive/power.dm index a862baf5599f..196423ba1cd5 100644 --- a/code/modules/integrated_electronics/passive/power.dm +++ b/code/modules/integrated_electronics/passive/power.dm @@ -143,12 +143,6 @@ for(var/I in fuel) if(DYNAMIC_CELL_UNITS_TO_W(assembly.battery.maxcharge - assembly.battery.charge, 1) > fuel[I]) var/power = 1 - if(I == "blood") - var/list/data = reagents.get_data(I) - if(data && istype(data["donor"], /mob/living/carbon/human)) - var/mob/living/carbon/human/H = data["donor"] - if(H.mind && H.mind.ckey) - power = 10 if(reagents.remove_reagent(I, 1)) assembly.give_power(fuel[I]*power) diff --git a/code/modules/integrated_electronics/subtypes/input.dm b/code/modules/integrated_electronics/subtypes/input.dm index 2dd9e32b12b2..7cef7f79cc35 100644 --- a/code/modules/integrated_electronics/subtypes/input.dm +++ b/code/modules/integrated_electronics/subtypes/input.dm @@ -321,13 +321,13 @@ set_pin_data(IC_OUTPUT, 7, H.getToxLoss()) set_pin_data(IC_OUTPUT, 8, H.getOxyLoss()) set_pin_data(IC_OUTPUT, 9, H.getCloneLoss()) - set_pin_data(IC_OUTPUT, 10, round((H.vessel.get_reagent_amount("blood") / H.species.blood_volume)*100)) + set_pin_data(IC_OUTPUT, 10, round((H.blood_holder.get_total_volume() / H.species.blood_volume)*100)) set_pin_data(IC_OUTPUT, 11, H.traumatic_shock) set_pin_data(IC_OUTPUT, 12, H.radiation) set_pin_data(IC_OUTPUT, 13, H.nutrition) var/cont[0] var/amt[0] - for(var/datum/reagent/RE in H.reagents.reagent_list) + for(var/datum/reagent/RE in H.reagents.get_reagent_datums()) if(RE.scannable || advscan >= 3) cont += RE.id amt += round(H.reagents.get_reagent_amount(RE.id), 1) diff --git a/code/modules/integrated_electronics/subtypes/reagents.dm b/code/modules/integrated_electronics/subtypes/reagents.dm index fc491f64e633..711a0df99242 100644 --- a/code/modules/integrated_electronics/subtypes/reagents.dm +++ b/code/modules/integrated_electronics/subtypes/reagents.dm @@ -196,13 +196,7 @@ busy = TRUE if(do_atom(src, L, extra_checks=CALLBACK(L, TYPE_PROC_REF(/mob/living, can_inject),null,0,BP_TORSO,bypass),uninterruptible = bypass)) var/mob/living/carbon/LB = L - var/datum/reagent/B - B = LB.take_blood(src, tramount) - if(B) - reagents.reagent_list += B - reagents.update_total() - AM.on_reagent_change() - reagents.reconsider_reactions() + if(LB.take_blood_legacy(src, tramount) > 0) L.visible_message("[acting_object] takes a blood sample from [L]!", \ "[acting_object] takes a blood sample from you!") else @@ -569,7 +563,7 @@ var/obj/item/I = get_pin_data_as_type(IC_INPUT, 1, /obj/item) if(istype(I) && (I.reagents?.total_volume) && check_target(I)) var/list/reagent_names_list = list() - for(var/datum/reagent/R in reagents?.reagent_list) + for(var/datum/reagent/R in reagents?.get_reagent_datums()) reagent_names_list.Add(R.name) var/atom/AM = get_object() AM.investigate_log("ground reagents: [jointext(reagent_names_list, ", ")] with [src].", INVESTIGATE_CIRCUIT) @@ -595,7 +589,7 @@ /obj/item/integrated_circuit/reagent/storage/scan/do_work() var/cont[0] - for(var/datum/reagent/RE in reagents.reagent_list) + for(var/datum/reagent/RE in reagents.get_reagent_datums()) cont += RE.id set_pin_data(IC_OUTPUT, 3, cont) push_data() @@ -648,7 +642,7 @@ return if(!target.reagents.available_volume()) return - for(var/datum/reagent/G in source.reagents.reagent_list) + for(var/datum/reagent/G in source.reagents.get_reagent_datums()) if (!direc) if(G.id in demand) source.reagents.trans_id_to(target, G.id, transfer_amount) diff --git a/code/modules/loot/packs/misc.dm b/code/modules/loot/packs/misc.dm index c7dad6fb77aa..767d4e016aa4 100644 --- a/code/modules/loot/packs/misc.dm +++ b/code/modules/loot/packs/misc.dm @@ -19,7 +19,7 @@ /obj/item/clothing/mask/gas/clown_hat, /obj/item/bikehorn, /obj/item/pen/crayon/rainbow, - /obj/item/toy/waterflower, + /obj/item/reagent_containers/spray/waterflower, ) /datum/prototype/struct/loot_pack/misc/clown/draw(amount) diff --git a/code/modules/mob/living/bot/medibot.dm b/code/modules/mob/living/bot/medibot.dm index 895abfebedcc..31c006470e3c 100644 --- a/code/modules/mob/living/bot/medibot.dm +++ b/code/modules/mob/living/bot/medibot.dm @@ -527,8 +527,8 @@ // If they're injured, we're using a beaker, and they don't have on of the chems in the beaker. if(reagent_glass && use_beaker && ((victim.getBruteLoss() >= heal_threshold) || (victim.getToxLoss() >= heal_threshold) || (victim.getToxLoss() >= heal_threshold) || (victim.getOxyLoss() >= (heal_threshold + 15)))) - for(var/datum/reagent/R in reagent_glass.reagents.reagent_list) - if(!victim.reagents.has_reagent(R)) + for(var/datum/reagent/R in reagent_glass.reagents.get_reagent_datums()) + if(!victim.reagents.has_reagent(R.id)) return 1 continue diff --git a/code/modules/mob/living/bot/mulebot.dm b/code/modules/mob/living/bot/mulebot.dm index 4b683e5b746a..52c6ad05efa1 100644 --- a/code/modules/mob/living/bot/mulebot.dm +++ b/code/modules/mob/living/bot/mulebot.dm @@ -235,8 +235,8 @@ /mob/living/bot/mulebot/Bump(var/mob/living/M) if(!safety && istype(M)) visible_message("[src] knocks over [M]!") - M.afflict_stun(20 * 8) - M.afflict_paralyze(20 * 5) + M.afflict_paralyze(1 SECONDS) + M.afflict_knockdown(2 SECONDS) ..() /mob/living/bot/mulebot/proc/runOver(var/mob/living/M) @@ -252,7 +252,11 @@ M.apply_damage(0.5 * damage, DAMAGE_TYPE_BRUTE, BP_L_ARM) M.apply_damage(0.5 * damage, DAMAGE_TYPE_BRUTE, BP_R_ARM) - blood_splatter(src, M, 1) + var/datum/blood_mixture/to_use + if(iscarbon(M)) + var/mob/living/carbon/carbon = M + to_use = carbon.get_blood_mixture() + blood_splatter_legacy(get_turf(M), to_use, TRUE) /mob/living/bot/mulebot/relaymove(var/mob/user, var/direction) if(load == user) diff --git a/code/modules/mob/living/carbon/blood_fragment.dm b/code/modules/mob/living/carbon/blood_fragment.dm new file mode 100644 index 000000000000..1ddfc939e9e2 --- /dev/null +++ b/code/modules/mob/living/carbon/blood_fragment.dm @@ -0,0 +1,87 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station developers. *// + +/** + * Reagent blood data + */ +/datum/blood_fragment + /// the blood's color + var/color + + //! LEGACY FIELDS + var/legacy_species + var/legacy_blood_dna + var/legacy_blood_type + var/legacy_donor + var/legacy_name + //! END + +/datum/blood_fragment/clone(include_contents) + var/datum/blood_fragment/copy = new /datum/blood_fragment + copy.color = color + if(legacy_blood_dna) + copy.legacy_blood_dna = legacy_blood_dna + if(legacy_blood_type) + copy.legacy_blood_type = legacy_blood_type + if(legacy_donor) + copy.legacy_donor = legacy_donor + if(legacy_name) + copy.legacy_name = legacy_name + if(legacy_species) + copy.legacy_species = legacy_species + return copy + +/** + * Checks if other is equivalent to self. + * + * * We intentionally do not check color. It's too expensive to, given this is used for + * deduping. + * * We intentionally do not check name. It's too expensive to, given this is used for + * deduping. + * * This implies that color / name should implicitly be the same if this proc returns TRUE + * for two given blood fragments. + */ +/datum/blood_fragment/proc/equivalent(datum/blood_fragment/other) + if(other.legacy_species != src.legacy_species) + return FALSE + if(other.legacy_blood_dna != src.legacy_blood_dna) + return FALSE + if(other.legacy_blood_type != src.legacy_blood_type) + return FALSE + return TRUE + +/** + * Checks if other is compatible with self. + * + * * This is **not** a symmetric relation. Some bloods are universally compatible with others, + * and accept everything. + * * This means that if host is not compatible with donor, but donor is compatible with host, + * the host attacks the donoar, even if the donor wouldn't if it was reversed. + */ +/datum/blood_fragment/proc/compatible_with_self(datum/blood_fragment/other) + return legacy_blood_compatible_with_self(legacy_blood_type, other.legacy_blood_type, legacy_species, other.legacy_species) + +/proc/legacy_blood_compatible_with_self(our_blood_type, their_blood_type, our_species_name, their_species_name) + // todo: remove species check, we have dumb xeno-compatibility-like canon anyways + if(our_species_name && their_species_name && (their_species_name != our_species_name)) + return FALSE + + var/our_antigen = copytext(our_blood_type, 1, length(our_blood_type)) + var/their_antigen = copytext(their_blood_type, 1, length(their_blood_type)) + + var/static/antigen_incompatible_matrix = list( + "AB" = list(), + "A" = list("AB" = TRUE, "B" = TRUE), + "B" = list("AB" = TRUE, "A" = TRUE), + "O" = list("AB" = TRUE, "A" = TRUE, "B" = TRUE), + ) + if(antigen_incompatible_matrix[our_antigen]?[their_antigen]) + return FALSE + + var/our_rh = our_blood_type[length(our_blood_type)] == "+" + var/their_rh = their_blood_type[length(their_blood_type)] == "+" + + if(their_rh && !our_rh) + return FALSE + + return TRUE diff --git a/code/modules/mob/living/carbon/blood_holder.dm b/code/modules/mob/living/carbon/blood_holder.dm new file mode 100644 index 000000000000..1a93d927aa59 --- /dev/null +++ b/code/modules/mob/living/carbon/blood_holder.dm @@ -0,0 +1,167 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station developers. *// + +/** + * Blood holder. + * + * This is basically just a blood mixture datum but permanent. Caching is more pronounced, + * and things can be stored that otherwise wouldn't be because we're considered cheap to store. + * + * * We own all fragments in us. We always copy when giving references, and always copy + * when accepting references. + */ +/datum/blood_holder + /// Our host blood. + var/datum/blood_fragment/host_blood + /// Amount of host blood we have + var/host_blood_volume = 0 + /// Our fragments that aren't ourselves, associated to ratio. + var/list/datum/blood_fragment/guest_bloods + /// Total amount of guest blood volume + var/guest_blood_volume = 0 + +/datum/blood_holder/proc/get_total_volume() + return host_blood_volume + guest_blood_volume + +/datum/blood_holder/proc/set_host_fragment_to(datum/blood_fragment/fragment) + host_blood = fragment.clone() + +/datum/blood_holder/proc/set_host_volume(amount) + host_blood_volume = amount + +/** + * @return amount change + */ +/datum/blood_holder/proc/adjust_host_volume(amount) + . = host_blood_volume + host_blood_volume = max(host_blood_volume + amount, 0) + . = host_blood_volume - . + +/** + * @return amount injected + */ +/datum/blood_holder/proc/inject_mixture(datum/blood_mixture/mixture, amount) + if(amount < 0) + return 0 + if(isnull(amount)) + amount = mixture.ctx_return_amount + if(!amount) + return 0 + #warn impl; check for host blood + + // todo: auto-trim system + + var/list/datum/blood_fragment/new_fragments = list() + + first_pass: + for(var/datum/blood_fragment/potential_injecting as anything in mixture.fragments) + if(host_blood.equivalent(potential_injecting)) + var/computed_amount = (1 - mixture.fragments[potential_injecting]) * amount + amount -= computed_amount + . += adjust_host_volume(computed_amount) + continue + for(var/datum/blood_fragment/potential_pair as anything in guest_bloods) + if(potential_pair.equivalent(potential_injecting)) + #warn impl; scaling will be a pain here + continue first_pass + new_fragments += potential_injecting + + var/old_volume = guest_blood_volume + +/** + * @return amount injected + */ +/datum/blood_holder/proc/inject_fragment(datum/blood_fragment/fragment, amount) + if(amount < 0) + return 0 + if(host_blood.equivalent(fragment)) + return adjust_host_volume(amount) + + // todo: auto-trim system + + var/datum/blood_fragment/existing + for(var/datum/blood_fragment/checking as anything in guest_bloods) + if(checking.equivalent(fragment)) + existing = checking + break + + var/old_volume = guest_blood_volume + guest_blood_volume += amount + var/scaler = old_volume / guest_blood_volume + + for(var/datum/blood_fragment/scaling as anything in guest_bloods) + guest_bloods[scaling] *= scaler + + if(!existing) + guest_bloods[fragment] = 1 - scaler + else + guest_bloods[existing] += 1 - scaler + + return amount + +/** + * Erases blood uniformly. + * + * * Fails if we don't have enough. + * + * @return amount erased + */ +/datum/blood_holder/proc/erase_checked_amount(amount) + var/total = host_blood_volume + guest_blood_volume + if(amount < total) + return 0 + var/multiplier = 1 - (amount / total) + host_blood_volume *= multiplier + guest_blood_volume *= multiplier + return amount + +/** + * Erases blood uniformly. + * + * @return amount erased + */ +/datum/blood_holder/proc/erase_amount(amount) + var/total = host_blood_volume + guest_blood_volume + var/multiplier = max(0, 1 - (amount / total)) + . = min(amount, total) + host_blood_volume *= multiplier + guest_blood_volume *= multiplier + +/** + * Takes a blood mixture from us. + * + * * Expensive. + * * Fails if we don't have enough. + * * Does not put viruses/antibodies/etc into it; that's the responsibiliy of the host, for now. + * * `ctx_return_amount` will be set on the returned mixture. + * + * @return mixture taken or null + */ +/datum/blood_holder/proc/checked_draw(amount) as /datum/blood_mixture + if(get_total_volume() < amount) + return null + var/datum/blood_mixture/taken = draw(amount) + // assert that it is enough + taken.ctx_return_amount = amount + return taken + +/** + * Takes a blood mixture from us. + * + * * Expensive. + * * Does not put viruses/antibodies/etc into it; that's the responsibiliy of the host, for now. + * * `ctx_return_amount` will be set on the returned mixture. + * + * @params + * * amount - amount to take + * * infinite - don't actually take any, and allow drawing any amount + * + * @return mixture taken + */ +/datum/blood_holder/proc/draw(amount, infinite) as /datum/blood_mixture + var/datum/blood_mixture/creating = new + creating.fragments = list() + #warn impl fragments self/others, amounts + return creating + +#warn how to handle color? compute_color_from_data, don't forget! diff --git a/code/modules/mob/living/carbon/blood_mixture.dm b/code/modules/mob/living/carbon/blood_mixture.dm new file mode 100644 index 000000000000..88631177342b --- /dev/null +++ b/code/modules/mob/living/carbon/blood_mixture.dm @@ -0,0 +1,69 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station developers. *// + +/** + * Reagent blood data + */ +/datum/blood_mixture + var/list/legacy_antibodies + var/list/legacy_virus2 + #warn uhh + var/legacy_trace_chem + #warn hook + var/legacy_is_synthetic = FALSE + + /// Fragments, associated to **ratio of total**. + var/list/datum/blood_fragment/fragments + + /// The total amount of all of our fragments + /// * Only useful in a return-value context. This is to avoid needing to recalcualte this. + /// * This can, in-fact, be '0'. + /// * In a reagent / storage context, the reagent's volume will always supercede this. + /// * This is not copied during a clone, as it's purely return-value context. + var/tmp/ctx_return_amount = 0 + +/datum/blood_mixture/clone(include_contents) + var/datum/blood_mixture/copy = new /datum/blood_mixture + if(!isnull(legacy_trace_chem)) + copy.legacy_trace_chem = legacy_trace_chem + if(!isnull(legacy_antibodies)) + copy.legacy_antibodies = legacy_antibodies + if(!isnull(legacy_is_synthetic)) + copy.legacy_is_synthetic = legacy_is_synthetic + if(!isnull(legacy_virus2)) + copy.legacy_virus2 = legacy_virus2 + if(length(fragments)) + copy.fragments = list() + for(var/datum/blood_fragment/data as anything in fragments) + copy.fragments[data.clone()] = fragments[data] + return copy + +/** + * Get overall color + */ +/datum/blood_mixture/proc/get_color() + #warn impl + +/** + * Get overall name + */ +/datum/blood_mixture/proc/get_name() + #warn impl + +/** + * Get atom blood DNA variable + * + * * this is shit, ugh + */ +/datum/blood_mixture/proc/legacy_get_forensic_blood_dna() + if(!length(fragments)) + return null + var/highest_so_far + var/datum/blood_fragment/highest_to_use + for(var/datum/blood_fragment/fragment as anything in fragments) + if(fragments[fragment] > highest_so_far) + highest_so_far = fragments[fragment] + highest_to_use = fragment + return list( + (highest_to_use.legacy_blood_dna) = (highest_to_use.legacy_blood_type), + ) diff --git a/code/modules/mob/living/carbon/carbon-blood.dm b/code/modules/mob/living/carbon/carbon-blood.dm new file mode 100644 index 000000000000..fb020faf19ea --- /dev/null +++ b/code/modules/mob/living/carbon/carbon-blood.dm @@ -0,0 +1,176 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/** + * Creates our blood. + */ +/mob/living/carbon/proc/create_blood() + if(!blood_holder) + blood_holder = new + reset_blood_to_species() + +/** + * Hard resets our data to our 'natural' blood. + * + * @params + * * do_not_regenerate - if set, do not reset to species.blood_volume, instead use current + */ +/mob/living/carbon/proc/reset_blood_to_species(do_not_regenerate) + if(!blood_holder) + return + + if(!do_not_regenerate) + blood_holder.set_host_volume(species.blood_volume) + #warn erase all others, combine volumes + + blood_holder.set_host_fragment_to(create_natural_blood_fragment()) + #warn erase all others, combine volumes + +/** + * Imprint ourselves on an outgoing blood mixture. + * + * * Accepts null, for ease of use. + * + * @return the imprinted mixture + */ +/mob/living/carbon/proc/imprint_blood_mixture(datum/blood_mixture/mixture) + if(!mixture) + return null + mixture.legacy_trace_chem = list2params(bloodstr.reagent_volumes) + mixture.legacy_virus2 = virus_copylist(virus2) + mixture.legacy_antibodies = antibodies?.Copy() + return mixture + +/** + * Gets our blood mixture. + * + * todo: get_blood + * + * @return /datum/blood_mixture or null + */ +/mob/living/carbon/proc/get_blood_mixture() as /datum/blood_mixture + var/datum/blood_mixture/mixture = blood_holder?.draw(0) + if(!mixture) + return + imprint_blood_mixture(mixture) + return mixture + +/** + * Regenerates our blood by a certain amount / volume. + * + * @return amount regenerated + */ +/mob/living/carbon/proc/regen_blood(amount) + return blood_holder.adjust_host_volume(amount) + +/** + * [take_checked_blood_mixture] but fast, + * + * * This returns just a number, not the mixture. + * + * @return amount erased + */ +/mob/living/carbon/proc/erase_checked_blood(amount) as num + return blood_holder.erase_checked_amount(amount) + +/** + * [take_mixture] but fast, + * + * * This returns just a number, not the mixture. + * + * @return amount erased + */ +/mob/living/carbon/proc/erase_blood(amount) as num + return blood_holder.erase_amount(amount) + + +/** + * Takes a blood mixture from ourselves. + * + * * Expensive + * * Fails if we don't have enough. + * + * todo: take_checked_blood + * + * @params + * * amount - amount to take + * * infinite - allow taking any amount, don't actually remove any + * + * @return mixture or null + */ +/mob/living/carbon/proc/take_checked_blood_mixture(amount) as /datum/blood_mixture + return imprint_blood_mixture(blood_holder?.checked_draw(amount)) + +/** + * Takes a blood mixture from ourselves. + * + * * Expensive + * + * todo: take_blood + * + * @params + * * amount - amount to take + * * infinite - allow taking any amount, don't actually remove any + * + * @return mixture or null + */ +/mob/living/carbon/proc/take_blood_mixture(amount, infinite) as /datum/blood_mixture + return imprint_blood_mixture(blood_holder?.draw(amount, infinite)) + +/** + * Puts a blood mixture into ourselves. + * + * todo: give_blood + * + * @params + * * mixture - mixture descriptor + * * amount - the amount. defaults to the mixture's `ctx_return_amount`. + * + * @return amount given + */ +/mob/living/carbon/proc/give_blood_mixture(datum/blood_mixture/mixture, amount) + if(!blood_holder) + return 0 + if(isnull(amount)) + amount = mixture.ctx_return_amount + + // give them the blood + blood_holder.inject_mixture(mixture, amount) + // give them the sniffles + var/list/i_hate_old_virology = virus_copylist(mixture.legacy_virus2) + for(var/id in i_hate_old_virology) + var/datum/disease2/the_coof = i_hate_old_virology[id] + infect_virus2(src, the_coof, TRUE) + // give them the anti-sniffles but only sometimes + // yes this does mean IV drips are very good for this. too bad! + // i don't care to deal with this dumb shit. + if(length(mixture.legacy_antibodies) && prob(5)) + antibodies |= mixture.legacy_antibodies + // this is very questionable but this does mean that you can cross-contaminate chemicals via blood + // this dumb part is the chemicals aren't actually in the extracted reagent holder, + // so this only .. does anything to humans. + // oh well. here, let's fix this with this one simple trick: + // todo: taking blood should generally draw out a bit of the reagents in someone's bloodstream, + // without using the trace chem system! + var/list/decoded_trace_chem = params2list(mixture.legacy_trace_chem) + for(var/id in decoded_trace_chem) + var/volume_str = decoded_trace_chem[id] + // the math here is weird; this means that this scales to blood volume and not bloodstream volume of + // where it came from. oh well, we'll fix it later. it's called legacy_trace_chem for a reason. + bloodstr.add_reagent(id, (text2num(volume_str) / species.blood_volume) * amount) + + return amount + +/** + * Makes a blood fragment of our natural blood + */ +/mob/living/carbon/proc/create_natural_blood_fragment() + var/datum/blood_fragment/creating = new + creating.legacy_blood_dna = dna.unique_enzymes + creating.legacy_blood_type = dna.b_type + creating.legacy_donor = src + creating.legacy_species = isSynthetic() ? "synthetic" : species.name + #warn how to deal with name / color? + creating.legacy_name = species.get_blood_name(src) + creating.color = species.get_blood_colour(src) + return creating diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 4e26578962f9..001233b556a2 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1,3 +1,9 @@ +/mob/living/carbon + //* Organs, Reagents, Biologies *// + + /// Our blood holder. + var/datum/blood_holder/blood_holder + /mob/living/carbon/Initialize(mapload) . = ..() //setup reagent holders @@ -9,6 +15,7 @@ default_language = RSlanguages.legacy_resolve_language_name(species_language) /mob/living/carbon/Destroy() + QDEL_NULL(blood_holder) qdel(ingested) qdel(touching) // We don't qdel(bloodstr) because it's the same as qdel(reagents) diff --git a/code/modules/mob/living/carbon/human/blood.dm b/code/modules/mob/living/carbon/human/blood.dm index f220de966e8b..4eb7de0a3dff 100644 --- a/code/modules/mob/living/carbon/human/blood.dm +++ b/code/modules/mob/living/carbon/human/blood.dm @@ -11,48 +11,14 @@ var/const/BLOOD_VOLUME_SURVIVE = 40 var/const/CE_STABLE_THRESHOLD = 0.5 */ -/mob/living/carbon/human/var/datum/reagent_holder/vessel // Container for blood and BLOOD ONLY. Do not transfer other chems here. /mob/living/carbon/human/var/var/pale = 0 // Should affect how mob sprite is drawn, but currently doesn't. -//Initializes blood vessels -/mob/living/carbon/human/proc/make_blood() - - if(vessel) - return - - if(species.species_flags & NO_BLOOD) - return - - vessel = new/datum/reagent_holder(species.blood_volume) - vessel.my_atom = src - - if(!should_have_organ(O_HEART)) //We want the var for safety but we can do without the actual blood. - return - - vessel.add_reagent("blood",species.blood_volume) - -//Resets blood data -/mob/living/carbon/human/proc/fixblood() - for(var/datum/reagent/blood/B in vessel.reagent_list) - if(B.id == "blood") - B.data = list( "donor"=src,"viruses"=null,"species"=species.name,"blood_DNA"=dna.unique_enzymes,"blood_colour"= species.get_blood_colour(src),"blood_type"=dna.b_type, \ - "resistances"=null,"trace_chem"=null, "virus2" = null, "antibodies" = list(), "blood_name" = species.get_blood_name(src)) - - if(isSynthetic()) - B.data["species"] = "synthetic" - - - B.color = B.data["blood_colour"] - B.name = B.data["blood_name"] - -/mob/living/carbon/human/proc/fixblood_if_broken() +/mob/living/carbon/human/proc/reset_blood_to_species_if_needed(do_not_regenerate) if(species.species_flags & NO_BLOOD) return if(!should_have_organ(O_HEART)) return - if(!vessel.has_reagent("blood")) - vessel.add_reagent("blood", 0.1) - fixblood() + reset_blood_to_species(do_not_regenerate) // Takes care blood loss and regeneration /mob/living/carbon/human/handle_blood() @@ -67,22 +33,15 @@ var/const/CE_STABLE_THRESHOLD = 0.5 if(stat != DEAD && bodytemperature >= 170) //Dead or cryosleep people do not pump the blood. - var/blood_volume_raw = vessel.get_reagent_amount("blood") + var/blood_volume_raw = blood_holder.get_total_volume() var/blood_volume = round((blood_volume_raw/species.blood_volume)*100) // Percentage. + #warn assimilate other bloods; no hemolytic reaction system yet + //Blood regeneration if there is some space if(blood_volume_raw < species.blood_volume) - var/datum/reagent/blood/B = locate() in vessel.reagent_list //Grab some blood - if(B) // Make sure there's some blood at all - if(B.data["donor"] != src) //If it's not theirs, then we look for theirs - for(var/datum/reagent/blood/D in vessel.reagent_list) - if(D.data["donor"] == src) - B = D - break - - B.volume += 0.1 // regenerate blood VERY slowly - if(CE_BLOODRESTORE in chem_effects) - B.volume += chem_effects[CE_BLOODRESTORE] + var/regenerating_volume = 0.1 + max(0, chem_effects[CE_BLOODRESTORE]) + blood_holder.adjust_host_volume(regenerating_volume) // Damaged heart virtually reduces the blood volume, as the blood isn't // being pumped properly anymore. @@ -210,209 +169,119 @@ var/const/CE_STABLE_THRESHOLD = 0.5 //Makes a blood drop, leaking amt units of blood from the mob /mob/living/carbon/human/proc/drip(var/amt) - if(remove_blood(amt)) - blood_splatter(src,src) - -/mob/living/carbon/human/proc/remove_blood(var/amt) - if(!should_have_organ(O_HEART)) //TODO: Make drips come from the reagents instead. - return 0 - - if(!amt) - return 0 - - if(amt >= vessel.get_reagent_amount("blood")) - amt = vessel.get_reagent_amount("blood") - 1 // Bit of a safety net; it's impossible to add blood if there's not blood already in the vessel. - - return vessel.remove_reagent("blood",amt * (src.mob_size/MOB_MEDIUM)) + if(erase_blood(amt)) + blood_splatter_legacy(get_turf(src), get_blood_mixture()) /**************************************************** BLOOD TRANSFERS ****************************************************/ -//Gets blood from mob to the container, preserving all data in it. -/mob/living/carbon/proc/take_blood(obj/item/reagent_containers/container, var/amount) - - var/datum/reagent/B = get_blood(container.reagents) - if(!B) - B = new /datum/reagent/blood - B.holder = container.reagents - B.volume += amount - B.initialize_data() - // todo: burn this file with fire - container.reagents.reagent_list |= B - container.reagents.update_total() - - //set reagent data - B.data["donor"] = src - if (!B.data["virus2"]) - B.data["virus2"] = list() - B.data["virus2"] |= virus_copylist(src.virus2) - B.data["antibodies"] = src.antibodies - B.data["blood_DNA"] = copytext(src.dna.unique_enzymes,1,0) - B.data["blood_type"] = copytext(src.dna.b_type,1,0) - - // Putting this here due to return shenanigans. - if(istype(src,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = src - B.data["blood_colour"] = H.species.get_blood_colour(H) - B.color = B.data["blood_colour"] - - var/list/temp_chem = list() - for(var/datum/reagent/R in src.reagents.reagent_list) - temp_chem += R.id - temp_chem[R.id] = R.volume - B.data["trace_chem"] = list2params(temp_chem) - return B +/** + * puts blood into container + * + * @return amount transferred + */ +/mob/living/carbon/proc/take_blood_legacy(obj/item/reagent_containers/container, amount) + ASSERT(container.reagents) -//For humans, blood does not appear from blue, it comes from vessels. -/mob/living/carbon/human/take_blood(obj/item/reagent_containers/container, var/amount) + var/wanted = max(0, container.reagents.maximum_volume - container.reagents.total_volume) + if(!wanted) + return 0 - if(!should_have_organ(O_HEART)) - return null + var/datum/blood_mixture/taken_mixture = take_blood_mixture(wanted) + var/amount_given = container.reagents.add_reagent(/datum/reagent/blood, taken_mixture.ctx_return_amount, taken_mixture) - if(vessel.get_reagent_amount("blood") < amount) - return null + if(amount_given < taken_mixture.ctx_return_amount) + // give back the remainder if we couldn't fill + give_blood_mixture(taken_mixture, taken_mixture.ctx_return_amount - amount_given) - if(amount >= vessel.get_reagent_amount("blood")) - amount = vessel.get_reagent_amount("blood") - 1 // Bit of a safety net; it's impossible to add blood if there's not blood already in the vessel. + return amount_given - . = ..() - vessel.remove_reagent("blood",amount) // Removes blood if human +//For humans, blood does not appear from blue, it comes from vessels. +/mob/living/carbon/human/take_blood_legacy(obj/item/reagent_containers/container, amount) + if(!should_have_organ(O_HEART)) + return 0 + if(blood_holder.get_total_volume() < amount) + return 0 + return ..() //Transfers blood from container ot vessels -/mob/living/carbon/proc/inject_blood(var/datum/reagent/blood/injected, var/amount) - if (!injected || !istype(injected)) - return - var/list/sniffles = virus_copylist(injected.data["virus2"]) - for(var/ID in sniffles) - var/datum/disease2/disease/sniffle = sniffles[ID] - infect_virus2(src,sniffle,1) - if (injected.data["antibodies"] && prob(5)) - antibodies |= injected.data["antibodies"] - var/list/chems = list() - chems = params2list(injected.data["trace_chem"]) - for(var/C in chems) - src.reagents.add_reagent(C, (text2num(chems[C]) / species.blood_volume) * amount)//adds trace chemicals to owner's blood - reagents.update_total() +/mob/living/carbon/proc/inject_blood_legacy(datum/blood_mixture/mixture, amount) + return give_blood_mixture(mixture, amount) //Transfers blood from reagents to vessel, respecting blood types compatability. -/mob/living/carbon/human/inject_blood(var/datum/reagent/blood/injected, var/amount) - +/mob/living/carbon/human/inject_blood_legacy(datum/blood_mixture/mixture, amount) + if(!blood_holder) + return 0 if(!should_have_organ(O_HEART)) - reagents.add_reagent("blood", amount, injected.data) - reagents.update_total() + return ..() + + // todo: ??? why is this here ??? + reset_blood_to_species_if_needed() + + // at some point we'll simulate immune system but for now this is just + // raw conversion to toxin + // + // too bad! + + mixture = mixture.clone() + var/total_ratio_removed = 0 + for(var/datum/blood_fragment/fragment as anything in mixture.fragments) + if(blood_holder.host_blood.compatible_with_self(fragment)) + continue + // rejected + var/fragment_ratio = mixture.fragments[fragment] + bloodstr.add_reagent(/datum/reagent/toxin, amount * 0.5 * fragment_ratio) + total_ratio_removed += fragment_ratio + mixture.fragments -= fragment + if(total_ratio_removed) + amount *= (1 - total_ratio_removed) + var/expand_ratio = 1 / total_ratio_removed + for(var/datum/blood_fragment/expanding_to_fill as anything in mixture.fragments) + mixture.fragments[expanding_to_fill] *= expand_ratio + + return ..() + +/proc/blood_splatter_legacy(turf/target, datum/blood_mixture/mixture, large) + if(!istype(target)) return - fixblood_if_broken() + var/splatter_type = /obj/effect/debris/cleanable/blood/splatter + var/obj/effect/debris/cleanable/blood/existing_splatter - var/datum/reagent/blood/our = get_blood(vessel) + // todo: change how this works, we should stop making effects like this! only one should ever + // exist. - if (!injected || !our) - return - if(blood_incompatible(injected.data["blood_type"],our.data["blood_type"],injected.data["species"],our.data["species"]) ) - reagents.add_reagent("toxin",amount * 0.5) - reagents.update_total() - else - vessel.add_reagent("blood", amount, injected.data) - vessel.update_total() - ..() - -//Gets human's own blood. -/mob/living/carbon/proc/get_blood(datum/reagent_holder/container) - var/datum/reagent/blood/res = locate() in container.reagent_list //Grab some blood - if(res) // Make sure there's some blood at all - if(res.data["donor"] != src) //If it's not theirs, then we look for theirs - for(var/datum/reagent/blood/D in container.reagent_list) - if(D.data["donor"] == src) - return D - return res - -/proc/blood_incompatible(donor, receiver, donor_species, receiver_species) - if(!donor || !receiver) - return 0 - - if(donor_species && receiver_species) - if(donor_species != receiver_species) - return 1 - - var/donor_antigen = copytext(donor,1,length(donor)) - var/receiver_antigen = copytext(receiver,1,length(receiver)) - var/donor_rh = (findtext(donor,"+")>0) - var/receiver_rh = (findtext(receiver,"+")>0) - - if(donor_rh && !receiver_rh) return 1 - switch(receiver_antigen) - if("A") - if(donor_antigen != "A" && donor_antigen != "O") return 1 - if("B") - if(donor_antigen != "B" && donor_antigen != "O") return 1 - if("O") - if(donor_antigen != "O") return 1 - //AB is a universal receiver. - return 0 - -/proc/blood_splatter(target, datum/reagent/blood/source, large) - - // We're not going to splatter at all because we're in something and that's silly. - if(istype(source,/atom/movable)) - var/atom/movable/A = source - if(!isturf(A.loc)) - return - - var/obj/effect/debris/cleanable/blood/B - var/decal_type = /obj/effect/debris/cleanable/blood/splatter - var/turf/T = get_turf(target) - var/synth = 0 - - if(istype(source,/mob/living/carbon/human)) - var/mob/living/carbon/human/M = source - if(M.isSynthetic()) synth = 1 - source = M.get_blood(M.vessel) - - // Are we dripping or splattering? var/list/drips = list() - // Only a certain number of drips (or one large splatter) can be on a given turf. - for(var/obj/effect/debris/cleanable/blood/drip/drop in T) - drips |= drop.drips + for(var/obj/effect/debris/cleanable/blood/drip/drop in target) + drips += drop.icon_state qdel(drop) - if(!large && drips.len < 3) - decal_type = /obj/effect/debris/cleanable/blood/drip - - // Find a blood decal or create a new one. - B = locate(decal_type) in T - if(!B) - B = new decal_type(T) - - var/obj/effect/debris/cleanable/blood/drip/drop = B - if(istype(drop) && drips && drips.len && !large) - drop.add_overlay(drips) - drop.drips |= drips - - // If there's no data to copy, call it quits here. - if(!istype(source)) - return B - - // Update appearance. - if(source.data["blood_colour"]) - B.basecolor = source.data["blood_colour"] - B.synthblood = synth - B.update_icon() - - if(source.data["blood_name"]) - B.name = source.data["blood_name"] - - // Update blood information. - if(source.data["blood_DNA"]) - B.blood_DNA = list() - if(source.data["blood_type"]) - B.blood_DNA[source.data["blood_DNA"]] = source.data["blood_type"] - else - B.blood_DNA[source.data["blood_DNA"]] = "O+" - - // Update virus information. - if(source.data["virus2"]) - B.virus2 = virus_copylist(source.data["virus2"]) - - B.fluorescent = 0 - B.invisibility = 0 - return B + + if(!large && length(drips) < 3) + splatter_type = /obj/effect/debris/cleanable/blood/drip + + existing_splatter = locate(splatter_type) in target + if(!existing_splatter) + existing_splatter = new splatter_type(target) + + // todo: this is fucking stupid + + var/obj/effect/debris/cleanable/blood/drip/is_it_drips = existing_splatter + if(istype(is_it_drips) && length(drips) && !large) + is_it_drips.add_overlay(drips) + is_it_drips.drips |= drips + + // is there data to copy? + if(!mixture) + return existing_splatter + + existing_splatter.name = mixture.get_name() + existing_splatter.basecolor = mixture.get_color() + existing_splatter.synthblood = mixture.legacy_is_synthetic + existing_splatter.update_icon() + + existing_splatter.blood_DNA = mixture.legacy_get_forensic_blood_dna() + if(mixture.legacy_virus2) + existing_splatter.virus2 = virus_copylist(mixture.legacy_virus2) + + return existing_splatter diff --git a/code/modules/mob/living/carbon/human/health.dm b/code/modules/mob/living/carbon/human/health.dm index 91ac2b4d3fe2..75dee9715c00 100644 --- a/code/modules/mob/living/carbon/human/health.dm +++ b/code/modules/mob/living/carbon/human/health.dm @@ -12,7 +12,7 @@ return // blood restore_blood() - fixblood() + reset_blood_to_species() // todo: this obviously doesn't respect reset_to_slot. if(fix_missing || reset_to_slot) diff --git a/code/modules/mob/living/carbon/human/human-damage-legacy.dm b/code/modules/mob/living/carbon/human/human-damage-legacy.dm index 0f699869fc39..b4e8719a53e8 100644 --- a/code/modules/mob/living/carbon/human/human-damage-legacy.dm +++ b/code/modules/mob/living/carbon/human/human-damage-legacy.dm @@ -337,10 +337,7 @@ This function restores the subjects blood to max. */ /mob/living/carbon/human/proc/restore_blood() - if(!should_have_organ(O_HEART)) - return - if(vessel.total_volume < species.blood_volume) - vessel.add_reagent("blood", species.blood_volume - vessel.total_volume) + blood_holder.set_host_volume(species.blood_volume) /* This function restores all organs. diff --git a/code/modules/mob/living/carbon/human/human-defense-legacy.dm b/code/modules/mob/living/carbon/human/human-defense-legacy.dm index 4d0e86fa83fb..b9bce27dc723 100644 --- a/code/modules/mob/living/carbon/human/human-defense-legacy.dm +++ b/code/modules/mob/living/carbon/human/human-defense-legacy.dm @@ -315,7 +315,7 @@ put_in_active_hand(O) visible_message("[src] catches [O]!") throw_mode_off() - return + return COMPONENT_THROW_HIT_NEVERMIND var/dtype = DAMAGE_TYPE_BRUTE if(isitem(AM)) diff --git a/code/modules/mob/living/carbon/human/human_organs.dm b/code/modules/mob/living/carbon/human/human_organs.dm index f529701c0e7d..d03e74b44115 100644 --- a/code/modules/mob/living/carbon/human/human_organs.dm +++ b/code/modules/mob/living/carbon/human/human_organs.dm @@ -153,7 +153,7 @@ //Handles chem traces /mob/living/carbon/human/proc/handle_trace_chems() //New are added for reagents to random organs. - for(var/datum/reagent/A in reagents.reagent_list) + for(var/datum/reagent/A in reagents.get_reagent_datums()) var/obj/item/organ/O = pick(organs) O.trace_chemicals[A.name] = 100 @@ -161,4 +161,4 @@ var/list/all_bits = internal_organs|organs for(var/obj/item/organ/O in all_bits) O.set_dna(dna) - fixblood() // make sure we have the right DNA since blood is an ""organ"" (scientists say it is!!) + reset_blood_to_species() // make sure we have the right DNA since blood is an ""organ"" (scientists say it is!!) diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index cfd9aec30caa..82cc52fc04b1 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -1795,7 +1795,7 @@ if(Pump) temp += Pump.standard_pulse_level - PULSE_NORM - if(round(vessel.get_reagent_amount("blood")) <= species.blood_volume*species.blood_level_danger) //how much blood do we have + if(round(blood_holder.get_total_volume()) <= species.blood_volume*species.blood_level_danger) //how much blood do we have temp = temp + 3 //not enough :( if(status_flags & STATUS_FAKEDEATH) @@ -1807,7 +1807,7 @@ temp = max(0, temp + modifier_shift) // No negative pulses. if(Pump) - for(var/datum/reagent/R in reagents.reagent_list) + for(var/datum/reagent/R in reagents.get_reagent_datums()) if(R.id in bradycardics) if(temp <= Pump.standard_pulse_level + 3 && temp >= Pump.standard_pulse_level) temp-- @@ -1817,11 +1817,11 @@ if(R.id in heartstopper) //To avoid using fakedeath temp = PULSE_NONE if(R.id in cheartstopper) //Conditional heart-stoppage - if(R.volume >= R.overdose) + if(reagents.get_reagent_amount(R.id) >= R.overdose) temp = PULSE_NONE return temp * brain_modifier //handles different chems' influence on pulse - for(var/datum/reagent/R in reagents.reagent_list) + for(var/datum/reagent/R in reagents.get_reagent_datums()) if(R.id in bradycardics) if(temp <= PULSE_THREADY && temp >= PULSE_NORM) temp-- @@ -1831,7 +1831,7 @@ if(R.id in heartstopper) //To avoid using fakedeath temp = PULSE_NONE if(R.id in cheartstopper) //Conditional heart-stoppage - if(R.volume >= R.overdose) + if(reagents.get_reagent_amount(R.id) >= R.overdose) temp = PULSE_NONE return max(0, round(temp * brain_modifier)) diff --git a/code/modules/mob/living/carbon/taste.dm b/code/modules/mob/living/carbon/taste.dm index 0a047fe30bf2..d3ead87eb550 100644 --- a/code/modules/mob/living/carbon/taste.dm +++ b/code/modules/mob/living/carbon/taste.dm @@ -24,11 +24,13 @@ calculate text size per text. var/list/out = list() var/list/tastes = list() //descriptor = strength if(minimum_percent <= 100) - for(var/datum/reagent/R in reagent_list) + for(var/id in reagent_volumes) + var/datum/reagent/R = SSchemistry.fetch_reagent(id) if(!R.taste_mult) continue + #warn check this shit if(R.id == "nutriment") //this is ugly but apparently only nutriment (not subtypes) has taste data TODO figure out why - var/list/taste_data = R.get_data() + var/list/taste_data = reagent_datas?[id] for(var/taste in taste_data) if(taste in tastes) tastes[taste] += taste_data[taste] diff --git a/code/modules/mob/living/silicon/robot/dogborg/dog_modules_vr.dm b/code/modules/mob/living/silicon/robot/dogborg/dog_modules_vr.dm index 07f1d3ef29eb..d5282bff2cca 100644 --- a/code/modules/mob/living/silicon/robot/dogborg/dog_modules_vr.dm +++ b/code/modules/mob/living/silicon/robot/dogborg/dog_modules_vr.dm @@ -103,9 +103,9 @@ user.visible_message("[user] sniffs at \the [target.name].", "You sniff \the [target.name]...") if(!isnull(target.reagents)) var/dat = "" - if(target.reagents.reagent_list.len > 0) - for (var/datum/reagent/R in target.reagents.reagent_list) - dat += "\n \t [R]" + for(var/id in target.reagents.reagent_volumes) + var/datum/reagent/R = SSchemistry.fetch_reagent(id) + dat += "\n \t [R]" if(dat) to_chat(user, "Your BOOP module indicates: [dat]") else diff --git a/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm b/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm index 6c03d9fd4db1..40a5a99c3870 100644 --- a/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm +++ b/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm @@ -282,9 +282,10 @@ dat += "
Significant brain damage detected.

" if(patient.getCloneLoss()) dat += "
Patient may be improperly cloned.

" - if(patient.reagents.reagent_list.len) - for(var/datum/reagent/R in patient.reagents.reagent_list) - dat += "
[R.name]:
[round(R.volume, 0.1)] units

" + for(var/id in patient.reagents.reagent_volumes) + var/datum/reagent/R = SSchemistry.fetch_reagent(id) + var/volume = patient.reagents.reagent_volumes[id] + dat += "
[R.name]:
[round(volume, 0.1)] units

" dat += "" var/datum/browser/popup = new(user, "sleeper_b", "[name] Console", 400, 500, src) diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/sif/leech.dm b/code/modules/mob/living/simple_mob/subtypes/animal/sif/leech.dm index 1306b7868f26..6a54ac7e842d 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/sif/leech.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/sif/leech.dm @@ -174,7 +174,7 @@ if(!docile && ishuman(host) && chemicals < max_chemicals) var/mob/living/carbon/human/H = host - H.vessel.remove_reagent("blood", 1) + H.take_blood_mixture(1) if(!H.reagents.has_reagent("inaprovaline")) H.reagents.add_reagent("inaprovaline", 1) chemicals += 2 diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/space/horing.dm b/code/modules/mob/living/simple_mob/subtypes/animal/space/horing.dm index 2f8bf86e6d79..ccea54ce2103 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/space/horing.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/space/horing.dm @@ -111,7 +111,11 @@ M.apply_damage(0.5 * damage, DAMAGE_TYPE_BRUTE, BP_R_LEG) M.apply_damage(0.5 * damage, DAMAGE_TYPE_BRUTE, BP_L_ARM) M.apply_damage(0.5 * damage, DAMAGE_TYPE_BRUTE, BP_R_ARM) - blood_splatter(src, M, 1) + var/datum/blood_mixture/using_blood_mixture + if(iscarbon(M)) + var/mob/living/carbon/carbon_victim = M + using_blood_mixture = carbon_victim.get_blood_mixture() + blood_splatter_legacy(get_turf(src), using_blood_mixture, TRUE) /mob/living/simple_mob/animal/horing/handle_special() if(ai_holder) diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/xenomorph/xenomorph_abilities.dm b/code/modules/mob/living/simple_mob/subtypes/animal/xenomorph/xenomorph_abilities.dm index c0a083a3e38f..1da1e4fb8531 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/xenomorph/xenomorph_abilities.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/xenomorph/xenomorph_abilities.dm @@ -42,11 +42,11 @@ /mob/living/simple_mob/animal/space/xenomorph/breaker/Bump(atom/movable/AM) if(charging) - visible_message("[src] runs [AM]!") + visible_message("[src] rams [AM]!") if(istype(AM, /mob/living)) var/mob/living/M = AM - M.afflict_stun(20 * 5) - M.afflict_paralyze(20 * 3) + M.afflict_paralyze(1 SECONDS) + M.afflict_knockdown(2 SECONDS) var/throwdir = pick(turn(dir, 45), turn(dir, -45)) M.throw_at_old(get_step(src.loc, throwdir), 1, 1, src) runOver(M) // Actually should not use this, placeholder @@ -66,7 +66,12 @@ M.apply_damage(0.5 * damage, DAMAGE_TYPE_BRUTE, BP_R_LEG) M.apply_damage(0.5 * damage, DAMAGE_TYPE_BRUTE, BP_L_ARM) M.apply_damage(0.5 * damage, DAMAGE_TYPE_BRUTE, BP_R_ARM) - blood_splatter(src, M, 1) + + var/datum/blood_mixture/to_use + if(iscarbon(M)) + var/mob/living/carbon/carbon = M + to_use = carbon.get_blood_mixture() + blood_splatter_legacy(get_turf(M), to_use, TRUE) /mob/living/simple_mob/animal/space/xenomorph/breaker/apply_melee_effects(atom/A) if(isliving(A)) @@ -152,7 +157,11 @@ M.apply_damage(0.5 * damage, DAMAGE_TYPE_BRUTE, BP_R_LEG) M.apply_damage(0.5 * damage, DAMAGE_TYPE_BRUTE, BP_L_ARM) M.apply_damage(0.5 * damage, DAMAGE_TYPE_BRUTE, BP_R_ARM) - blood_splatter(src, M, 1) + var/datum/blood_mixture/using_blood_mixture + if(iscarbon(M)) + var/mob/living/carbon/carbon_victim = M + using_blood_mixture = carbon_victim.get_blood_mixture() + blood_splatter_legacy(get_turf(src), using_blood_mixture, TRUE) /mob/living/simple_mob/animal/space/xenomorph/monarch/apply_melee_effects(atom/A) if(isliving(A)) diff --git a/code/modules/mob/living/simple_mob/subtypes/lavaland/gutshank.dm b/code/modules/mob/living/simple_mob/subtypes/lavaland/gutshank.dm index fee458b99ca3..e1c506702eaf 100644 --- a/code/modules/mob/living/simple_mob/subtypes/lavaland/gutshank.dm +++ b/code/modules/mob/living/simple_mob/subtypes/lavaland/gutshank.dm @@ -139,7 +139,7 @@ /mob/living/simple_mob/animal/gutshank/proc/blood_drink(var/mob/living/carbon/human/M) if(istype(M)) to_chat(M, "The [src] pierces your flesh! You feel a sickening suction!") - M.vessel.remove_reagent("blood",rand(10,20)) + M.take_blood_mixture(rand(10, 20)) /mob/living/simple_mob/animal/gutshank/death() STOP_PROCESSING(SSobj, src) @@ -265,7 +265,7 @@ /mob/living/simple_mob/animal/shank/proc/blood_drink(var/mob/living/carbon/human/M) if(istype(M)) to_chat(M, "The [src] pierces your flesh! You feel a sickening suction!") - M.vessel.remove_reagent("blood",rand(20,25)) + M.take_blood_mixture(rand(20, 25)) /mob/living/simple_mob/animal/shank/update_icon() if(rideable) diff --git a/code/modules/organs/external/external.dm b/code/modules/organs/external/external.dm index e6507bcfb7a3..7db8976e1820 100644 --- a/code/modules/organs/external/external.dm +++ b/code/modules/organs/external/external.dm @@ -801,7 +801,7 @@ Note that amputating the affected organ does in fact remove the infection from t if(!(W.can_autoheal() || (bicardose && inaprovaline) || myeldose)) //bicaridine and inaprovaline stop internal wounds from growing bigger with time, unless it is so small that it is already healing W.open_wound(0.1) - owner.vessel.remove_reagent("blood", W.damage/40) //line should possibly be moved to handle_blood, so all the bleeding stuff is in one place. + owner.erase_blood(W.damage / 40) if(prob(1)) owner.custom_pain("You feel a stabbing pain in your [name]!", 50) diff --git a/code/modules/organs/external/wound.dm b/code/modules/organs/external/wound.dm index a56c1f153e98..5de7560bec10 100644 --- a/code/modules/organs/external/wound.dm +++ b/code/modules/organs/external/wound.dm @@ -18,7 +18,7 @@ if((damage > 5 || damage + burn_dam >= 15) && type == WOUND_TYPE_BURN && (robotic < ORGAN_ROBOT) && !(species.species_flags & NO_BLOOD)) var/fluid_loss = 0.4 * (damage/(owner.getMaxHealth() - config_legacy.health_threshold_dead)) * owner.species.blood_volume*(1 - owner.species.blood_level_fatal) - owner.remove_blood(fluid_loss) + owner.erase_blood(fluid_loss) // first check whether we can widen an existing wound if(length(wounds) > 0 && prob(max(50+(wound_tally-1)*10,90))) diff --git a/code/modules/organs/internal/misc.dm b/code/modules/organs/internal/misc.dm index f06ac698a3bd..12e784a029ea 100644 --- a/code/modules/organs/internal/misc.dm +++ b/code/modules/organs/internal/misc.dm @@ -16,19 +16,19 @@ owner.reagents.add_reagent(chem, 5) // They're also super gross and ooze ichor. - if(prob(5)) - var/mob/living/carbon/human/H = owner - if(!istype(H)) - return - - var/datum/reagent/blood/B = locate(/datum/reagent/blood) in H.vessel.reagent_list - blood_splatter(H,B,1) - var/obj/effect/debris/cleanable/blood/splatter/goo = locate() in get_turf(owner) - if(goo) - goo.name = "husk ichor" - goo.desc = "It's thick and stinks of decay." - goo.basecolor = "#412464" - goo.update_icon() + // if(prob(5)) + // var/mob/living/carbon/human/H = owner + // if(!istype(H)) + // return + + // var/datum/reagent/blood/B = locate(/datum/reagent/blood) in H.vessel.reagent_list + // blood_splatter(H,B,1) + // var/obj/effect/debris/cleanable/blood/splatter/goo = locate() in get_turf(owner) + // if(goo) + // goo.name = "husk ichor" + // goo.desc = "It's thick and stinks of decay." + // goo.basecolor = "#412464" + // goo.update_icon() /obj/item/organ/internal/borer/removed(var/mob/living/user) diff --git a/code/modules/organs/internal/species/unathi.dm b/code/modules/organs/internal/species/unathi.dm index 72167c29ace5..0c61ed1b9456 100644 --- a/code/modules/organs/internal/species/unathi.dm +++ b/code/modules/organs/internal/species/unathi.dm @@ -17,15 +17,13 @@ ..() if(!owner) return - var/datum/reagent/coffee = locate(/datum/reagent/drink/coffee) in owner.reagents.reagent_list - if(coffee) + if(owner.reagents.has_reagent(/datum/reagent/drink/coffee::id)) if(is_bruised()) owner.adjustToxLoss(0.1 * (delta_time * 5)) else if(is_broken()) owner.adjustToxLoss(0.3 * (delta_time * 5)) - var/datum/reagent/sugar = locate(/datum/reagent/sugar) in owner.reagents.reagent_list - if(sugar) + if(owner.reagents.has_reagent(/datum/reagent/sugar::id)) if(is_bruised()) owner.adjustToxLoss(0.1 * (delta_time * 5)) else if(is_broken()) diff --git a/code/modules/organs/internal/subtypes/kidneys.dm b/code/modules/organs/internal/subtypes/kidneys.dm index e8ccb9d844c0..f997311b2d31 100644 --- a/code/modules/organs/internal/subtypes/kidneys.dm +++ b/code/modules/organs/internal/subtypes/kidneys.dm @@ -12,7 +12,7 @@ // Coffee is really bad for you with busted kidneys. // This should probably be expanded in some way, but fucked if I know // what else kidneys can process in our reagent list. - var/datum/reagent/coffee = locate(/datum/reagent/drink/coffee) in owner.reagents.reagent_list + var/datum/reagent/coffee = locate(/datum/reagent/drink/coffee) in owner.reagents.get_reagent_datums() if(coffee) if(is_bruised()) owner.adjustToxLoss(0.1 * (dt * 5)) diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index 3ca01afc5760..17798a8498d8 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -383,19 +383,20 @@ reconsider_processing() /obj/item/organ/proc/replaced(var/mob/living/carbon/human/target,var/obj/item/organ/external/affected) + if(!istype(target)) + return - if(!istype(target)) return - - var/datum/reagent/blood/transplant_blood = locate(/datum/reagent/blood) in reagents.reagent_list + var/datum/blood_mixture/mixture_data = reagents.get_reagent_data(/datum/reagent/blood) transplant_data = list() - if(!transplant_blood) + if(!mixture_data || length(mixture_data.fragments) < 1) transplant_data["species"] = target?.species.name transplant_data["blood_type"] = target?.dna.b_type transplant_data["blood_DNA"] = target?.dna.unique_enzymes else - transplant_data["species"] = transplant_blood?.data["species"] - transplant_data["blood_type"] = transplant_blood?.data["blood_type"] - transplant_data["blood_DNA"] = transplant_blood?.data["blood_DNA"] + var/datum/blood_fragment/use_fragment = mixture_data.fragments[1] + transplant_data["species"] = use_fragment.legacy_species + transplant_data["blood_type"] = use_fragment.legacy_blood_type + transplant_data["blood_DNA"] = use_fragment.legacy_blood_dna owner = target loc = owner @@ -630,7 +631,7 @@ // immunosuppressant that changes transplant data to make it match. if(dna && can_reject) if(!rejecting) - if(blood_incompatible(dna.b_type, owner.dna.b_type, species.name, owner.species.name)) // Process species by name. + if(!legacy_blood_compatible_with_self(owner.dna.b_type, dna.b_type, owner.species.name, species.name)) rejecting = 1 else rejecting++ //Rejection severity increases over time. diff --git a/code/modules/power/engines/rust/fuel_assembly/fuel_compressor.dm b/code/modules/power/engines/rust/fuel_assembly/fuel_compressor.dm index 496e5bf66775..8ca1f64ee8fb 100644 --- a/code/modules/power/engines/rust/fuel_assembly/fuel_compressor.dm +++ b/code/modules/power/engines/rust/fuel_assembly/fuel_compressor.dm @@ -14,16 +14,16 @@ /obj/machinery/fusion_fuel_compressor/proc/do_special_fuel_compression(var/obj/item/thing, var/mob/user) if(istype(thing) && thing.reagents && thing.reagents.total_volume && thing.is_open_container()) - if(thing.reagents.reagent_list.len > 1) + if(length(thing.reagents.reagent_volumes) > 1) to_chat(user, "The contents of \the [thing] are impure and cannot be used as fuel.") return 1 if(thing.reagents.total_volume < 50) to_chat(user, "You need at least fifty units of material to form a fuel rod.") return 1 - var/datum/reagent/R = thing.reagents.reagent_list[1] + var/datum/reagent/R = SSchemistry.fetch_reagent(thing.reagents.reagent_volumes[1]) visible_message("\The [src] compresses the contents of \the [thing] into a new fuel assembly.") var/obj/item/fuel_assembly/F = new(get_turf(src), R.id, R.color) - thing.reagents.remove_reagent(R.id, R.volume) + thing.reagents.remove_reagent(R.id, thing.reagents.get_reagent_amount(R.id)) user.put_in_hands(F) else if(istype(thing, /obj/machinery/power/supermatter)) diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 1fbe3f438125..b7d9b3d9da29 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -85,7 +85,7 @@ end_nutrition = H.nutrition if(start_nutrition - max(0, end_nutrition) < rechargeamt / 10) - H.remove_blood((rechargeamt / 10) - (start_nutrition - max(0, end_nutrition))) + H.erase_blood((rechargeamt / 10) - (start_nutrition - max(0, end_nutrition))) power_supply.give(rechargeamt) //... to recharge 1/5th the battery update_icon() diff --git a/code/modules/projectiles/guns/projectile/dartgun.dm b/code/modules/projectiles/guns/projectile/dartgun.dm index 23c87c79e17a..f4bc84fccacd 100644 --- a/code/modules/projectiles/guns/projectile/dartgun.dm +++ b/code/modules/projectiles/guns/projectile/dartgun.dm @@ -58,18 +58,6 @@ if(istype(dart)) fill_dart(dart) -/obj/item/gun/ballistic/dartgun/examine(mob/user, dist) - //update_icon() - //if (!..(user, 2)) - // return - . = ..() - if (beakers.len) - to_chat(user, "[src] contains:") - for(var/obj/item/reagent_containers/glass/beaker/B in beakers) - if(B.reagents && B.reagents.reagent_list.len) - for(var/datum/reagent/R in B.reagents.reagent_list) - . += "[R.volume] units of [R.name]" - /obj/item/gun/ballistic/dartgun/attackby(obj/item/I as obj, mob/user as mob) if(istype(I, /obj/item/reagent_containers/glass)) if(!istype(I, container_type)) @@ -105,9 +93,9 @@ var/i = 1 for(var/obj/item/reagent_containers/glass/beaker/B in beakers) dat += "Beaker [i] contains: " - if(B.reagents && B.reagents.reagent_list.len) - for(var/datum/reagent/R in B.reagents.reagent_list) - dat += "
[R.volume] units of [R.name], " + if(B.reagents?.total_volume) + for(var/datum/reagent/R in B.reagents.get_reagent_datums()) + dat += "
[B.reagents.reagent_volumes[R.id]] units of [R.name], " if (check_beaker_mixing(B)) dat += "Mixing " else diff --git a/code/modules/reagents/chemistry/_readme.dm b/code/modules/reagents/chemistry/_readme.dm deleted file mode 100644 index 3833cd11ba3c..000000000000 --- a/code/modules/reagents/chemistry/_readme.dm +++ /dev/null @@ -1,305 +0,0 @@ -/* -NOTE: IF YOU UPDATE THE REAGENT-SYSTEM, ALSO UPDATE THIS README. - -Structure: /////////////////// ////////////////////////// - // Mob or object // -------> // Reagents var (datum) // Is a reference to the datum that holds the reagents. - /////////////////// ////////////////////////// - | | - The object that holds everything. V - reagent_list var (list) A List of datums, each datum is a reagent. - - | | | - V V V - - reagents (datums) Reagents. I.e. Water , antitoxins 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 - - Vars: - list/datum/reagent/reagent_list - List of reagent datums. - - total_volume - Total volume of all reagents. - - maximum_volume - Maximum volume. - - atom/my_atom - Reference to the object that contains this. - - Procs: - - available_volume() - Returns the remaining free volume in the holder. - - get_master_reagent() - Returns the reference to the reagent with the largest volume - - get_master_reagent_name() - Ditto, but returns the name. - - get_master_reagent_id() - Ditto, but returns ID. - - update_total() - Updates total volume, called automatically. - - handle_reactions() - Checks reagents and triggers any reactions that happen. Usually called automatically. - - add_reagent(id, amount, data = null, safety = 0) - Adds [amount] units of [id] reagent. [data] will be passed to reagent's mix_data() or initialize_data(). If [safety] is 0, handle_reactions() will be called. Returns 1 if successful, 0 otherwise. - - remove_reagent(id, amount, safety = 0) - Ditto, but removes reagent. Returns 1 if successful, 0 otherwise. - - del_reagent(id) - Removes all of the reagent. - - has_reagent(id, amount = 0) - Checks if holder has at least [amount] of [id] reagent. Returns 1 if the reagent is found and volume is above [amount]. Returns 0 otherwise. - - clear_reagents() - Removes all reagents. - - get_reagent_amount(id) - Returns reagent volume. Returns 0 if reagent is not found. - - get_data(id) - Returns get_data() of the reagent. - - get_reagents() - Returns a string containing all reagent ids and volumes, e.g. "carbon(4),nittrogen(5)". - - remove_any(amount = 1) - Removes up to [amount] of reagents from [src]. Returns actual amount removed. - - trans_to_holder(datum/reagent_holder/target, amount = 1, multiplier = 1, copy = 0) - Transfers [amount] reagents from [src] to [target], multiplying them by [multiplier]. Returns actual amount removed from [src] (not amount transferred to [target]). If [copy] is 1, copies reagents instead. - - touch(var/atom/target) - When applying reagents to an atom externally, touch() is called to trigger any on-touch effects of the reagent. - This does not handle transferring reagents to things. - For example, splashing someone with water will get them wet and extinguish them if they are on fire, - even if they are wearing an impermeable suit that prevents the reagents from contacting the skin. - Basically just defers to touch_mob(target), touch_turf(target), or touch_obj(target), depending on target's type. - Not recommended to use this directly, since trans_to() calls it before attempting to transfer. - - touch_mob(mob/target) - Calls each reagent's touch_mob(target). - - touch_turf(var/turf/target) - Calls each reagent's touch_turf(target). - - touch_obj(var/obj/target) - Calls each reagent's touch_obj(target). - - trans_to(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0) - The general proc for applying reagents to things externally (as opposed to directly injected into the contents). - It first calls touch, then the appropriate trans_to_*() or splash_mob(). - If for some reason you want touch effects to be bypassed (e.g. injecting stuff directly into a reagent container or person), call the appropriate trans_to_*() proc. - - Calls touch() before checking the type of [target], calling splash_mob(target, amount), trans_to_turf(target, amount, multiplier, copy), or trans_to_obj(target, amount, multiplier, copy). - - trans_id_to(atom/target, id, amount = 1) - Transfers [amount] of [id] to [target]. Returns amount transferred. - - splash_mob(var/mob/target, var/amount = 1, var/clothes = 1) - Checks mob's clothing if [clothes] is 1 and transfers [amount] reagents to mob's skin. - Don't call this directly. Call apply_to() instead. - - trans_to_mob(mob/target, amount = 1, type = CHEM_INJECT, multiplier = 1, copy = 0) - Transfers [amount] reagents to the mob's appropriate holder, depending on [type]. Ignores protection. - - trans_to_turf(turf/target, amount = 1, multiplier = 1, copy = 0) - Turfs don't currently have any reagents. Puts [amount] reagents into a temporary holder, calls touch_turf(target) from it, and deletes it. - - trans_to_obj(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0) - If target has reagents, transfers [amount] to it. Otherwise, same as trans_to_turf(). - - atom/proc/create_reagents(var/max_vol) - Creates a new reagent datum. - -About Reagents: - - Reagents are all the things you can mix and fille in bottles etc. This can be anything from - rejuvs over water to... iron. - - Vars: - - name - Name that shows up in-game. - - id - ID that is used for internal tracking. MUST BE UNIQUE. - - description - Description that shows up in-game. - - datum/reagent_holder/holder - Reference to holder. - - reagent_state - Could be GAS, LIQUID, or SOLID. Affects nothing. Reserved for future use. - - list/data - Use varies by reagent. Custom variable. For example, blood stores blood group and viruses. - - volume - Current volume. - - metabolism - How quickly reagent is processed in mob's bloodstream; by default aslo affects ingest and touch metabolism. - - ingest_met - How quickly reagent is processed when ingested; [metabolism] is used if zero. - - touch_met - Ditto when touching. - - dose - How much of the reagent has been processed, limited by [max_dose]. Used for reagents with varying effects (e.g. ethanol or rezadone) and overdosing. - - max_dose - Maximum amount of reagent that has ever been in a mob. Exists so dose won't grow infinitely when small amounts of reagent are added over time. - - overdose - If [dose] is bigger than [overdose], overdose() proc is called every tick. - - scannable - If set to 1, will show up on health analyzers by name. - - affects_dead - If set to 1, will affect dead players. Used by Adminordrazine. - - glass_icon_state - Used by drinks. icon_state of the glass when this reagent is the master reagent. - - glass_name - Ditto for glass name. - - glass_desc - Ditto for glass desciption. - - glass_center_of_mass - Used for glass placement on tables. - - color - "#RRGGBB" or "#RRGGBBAA" where A is alpha channel. - - color_weight - How much reagent affects color of holder. Used by paint. - - Procs: - - remove_self(var/amount) - Removes [amount] of itself. - - touch_mob(var/mob/M) - Called when reagent is in another holder and not splashing the mob. Can be used with noncarbons. - - touch_obj(obj/O) - How reagent reacts with objects. - - touch_turf(turf/T) - How reagent reacts with turfs. - - on_mob_life(var/mob/living/carbon/M, var/alien, var/location) - Makes necessary checks and calls one of affect procs. - - affect_blood(mob/living/carbon/M, alien, removed) - How reagent affects mob when injected. [removed] is the amount of reagent that has been removed this tick. [alien] is the mob's reagent flag. - - affect_ingest(mob/living/carbon/M, alien, removed) - Ditto, ingested. Defaults to affect_blood with halved dose. - - affect_touch(mob/living/carbon/M, alien, removed) - Ditto, touching. - - overdose(mob/living/carbon/M, alien) - Called when dose is above overdose. Defaults to M.adjustToxLoss(REM). - - initialize_data(newdata) - Called when reagent is created. Defaults to setting [data] to [newdata]. - - mix_data(var/newdata, var/newamount) - Called when [newamount] of reagent with [newdata] data is added to the current reagent. Used by paint. - - get_data() - Returns data. Can be overriden. - -About Recipes: - - Recipes are simple datums that contain a list of required reagents and a result. - They also have a proc that is called when the recipe is matched. - - Vars: - - name - Name of the reaction, currently unused. - - id - ID of the reaction, must be unique. - - result - ID of the resulting reagent. Can be null. - - list/required_reagents - Reagents that are required for the reaction and are used up during it. - - list/catalysts - Ditto, but not used up. - - list/inhibitors - Opposite, prevent the reaction from happening. - - result_amount - Amount of resulting reagent. - - mix_message - Message that is shown to mobs when reaction happens. - - Procs: - - can_happen(var/datum/reagent_holder/holder) - Customizable. If it returns 0, reaction will not happen. Defaults to always returning 1. Used by slime core reactions. - - on_reaction(datum/reagent_holder/holder, created_volume) - Called when reaction happens. Used by explosives. - - send_data(var/datum/reagent_holder/T) - Sets resulting reagent's data. Used by blood paint. - -About the Tools: - - By default, all atom have a reagents var - but its empty. if you want to use an object for the chem. - system you'll need to add something like this in its new proc: - - atom/proc/create_reagents(var/max_volume) - - Other important stuff: - - amount_per_transfer_from_this var - This var is mostly used by beakers and bottles. - It simply tells us how much to transfer when - 'pouring' our reagents into something else. - - atom/proc/is_open_container() - Checks atom/var/atom_flags & OPENCONTAINER. - If this returns 1 , you can use syringes, beakers etc - to manipulate the contents of this object. - If it's 0, you'll need to write your own custom reagent - transfer code since you will not be able to use the standard - tools to manipulate it. - -*/ diff --git a/code/modules/reagents/chemistry/chemical_reaction.dm b/code/modules/reagents/chemistry/chemical_reaction.dm index e4af0cf7e949..022767ebc011 100644 --- a/code/modules/reagents/chemistry/chemical_reaction.dm +++ b/code/modules/reagents/chemistry/chemical_reaction.dm @@ -203,6 +203,7 @@ //obtains any special data that will be provided to the reaction products //this is called just before reactants are removed. // todo: rework data system +#warn refactor /datum/chemical_reaction/proc/send_data(datum/reagent_holder/holder, reaction_limit) return null diff --git a/code/modules/reagents/chemistry/colors.dm b/code/modules/reagents/chemistry/colors.dm deleted file mode 100644 index 1f239859b486..000000000000 --- a/code/modules/reagents/chemistry/colors.dm +++ /dev/null @@ -1,46 +0,0 @@ -/proc/mix_color_from_reagents(list/reagent_list) - if(!istype(reagent_list)) - return - - var/mixcolor - var/vol_counter = 0 - var/vol_temp - - for(var/datum/reagent/R in reagent_list) - vol_temp = R.volume - vol_counter += vol_temp - - if(!mixcolor) - mixcolor = R.color - - else if (length(mixcolor) >= length(R.color)) - mixcolor = BlendRGB(mixcolor, R.color, vol_temp/vol_counter) - else - mixcolor = BlendRGB(R.color, mixcolor, vol_temp/vol_counter) - - return mixcolor - -/datum/reagent_holder/proc/get_color() - // todo: cache this shit - if(!reagent_list || !reagent_list.len) - return "#ffffffff" - if(reagent_list.len == 1) // It's pretty common and saves a lot of work - var/datum/reagent/R = reagent_list[1] - return R.color - - var/list/colors = list(0, 0, 0, 0) - var/tot_w = 0 - for(var/datum/reagent/R in reagent_list) - var/hex = uppertext(R.color) - if(length(hex) == 7) - hex += "FF" - if(length(hex) != 9) // PANIC PANIC PANIC - warning("Reagent [R.id] has an incorrect color set ([R.color])") - hex = "#FFFFFFFF" - colors[1] += hex2num(copytext(hex, 2, 4)) * R.volume * R.color_weight - colors[2] += hex2num(copytext(hex, 4, 6)) * R.volume * R.color_weight - colors[3] += hex2num(copytext(hex, 6, 8)) * R.volume * R.color_weight - colors[4] += hex2num(copytext(hex, 8, 10)) * R.volume * R.color_weight - tot_w += R.volume * R.color_weight - - return rgb(colors[1] / tot_w, colors[2] / tot_w, colors[3] / tot_w, colors[4] / tot_w) diff --git a/code/modules/reagents/chemistry/reagent.dm b/code/modules/reagents/chemistry/reagent.dm index 2b8dc3122323..99cae6702cb6 100644 --- a/code/modules/reagents/chemistry/reagent.dm +++ b/code/modules/reagents/chemistry/reagent.dm @@ -17,20 +17,27 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) /// reagent flags - see [code/__DEFINES/reagents/flags.dm] var/reagent_flags = NONE - //* Filtering *// - /// reagent filter flags - dynamic flags used for simulations of filtration/identification/detection - /// - /// * used for a lot of things - /// * REAGENT_FILTER_GENERIC is a default because this allows us to have a single 'flags' on filter, - /// instead of a 'include flags' and 'exclude flags'. - var/reagent_filter_flags = REAGENT_FILTER_GENERIC + //* Color *// + /// our reagent color + var/color = "#000000" + /// multiplier to effective volume when calculating color + var/color_weight = 1 + + //* Data *// + /// Supports data system. + var/holds_data = FALSE - //* Identity + //* Economy *// + /// Raw intrinsic worth of this reagent + var/worth = 0 + /// economic category of the reagent + var/economic_category_reagent = ECONOMIC_CATEGORY_REAGENT_DEFAULT + + //* Identity *// /// our name - visible from guidebooks and to admins var/name = "Reagent" /// our description - visible from guidebooks and to admins var/description = "A non-descript chemical of some kind." - /// player-facing name - visible via scan tools /// defaults to [name] /// overrides name in guidebook var/display_name @@ -39,6 +46,14 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) /// overrides desc in guidebook var/display_description + //* Filtering *// + /// reagent filter flags - dynamic flags used for simulations of filtration/identification/detection + /// + /// * used for a lot of things + /// * REAGENT_FILTER_GENERIC is a default because this allows us to have a single 'flags' on filter, + /// instead of a 'include flags' and 'exclude flags'. + var/reagent_filter_flags = REAGENT_FILTER_GENERIC + //* Guidebook /// guidebook flags var/reagent_guidebook_flags = NONE @@ -46,14 +61,13 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) var/reagent_guidebook_category = "Unsorted" //? legacy / unsorted + var/glass_icon_state = null + var/glass_center_of_mass = null var/taste_description = "bitterness" /// How this taste compares to others. Higher values means it is more noticable var/taste_mult = 1 - var/datum/reagent_holder/holder = null var/reagent_state = REAGENT_SOLID - var/list/data = null - var/volume = 0 - var/metabolism = REM // This would be 0.2 normally + var/metabolism_rate = REM // This would be 0.2 normally /// Used for vampric-Digestion var/blood_content = 0 /// Organs that will slow the processing of this chemical. @@ -62,8 +76,6 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) var/mrate_static = FALSE var/ingest_met = 0 var/touch_met = 0 - var/dose = 0 - var/max_dose = 0 ///Amount at which overdose starts var/overdose = 0 ///Modifier to overdose damage @@ -81,20 +93,11 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) var/cup_desc = null var/cup_center_of_mass = null - var/color = "#000000" - var/color_weight = 1 - var/glass_icon = DRINK_ICON_DEFAULT var/glass_name = "something" var/glass_desc = "It's a glass of... what, exactly?" var/list/glass_special = null // null equivalent to list() - //? Economy - /// Raw intrinsic worth of this reagent - var/worth = 0 - /// economic category of the reagent - var/economic_category_reagent = ECONOMIC_CATEGORY_REAGENT_DEFAULT - //? wiki markup generation additional /// override "name" var/wiki_name @@ -105,21 +108,17 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) /// forced sort ordering in its category - falls back to name otherwise. var/wiki_sort = 0 -/datum/reagent/proc/remove_self(var/amount) // Shortcut - if(holder) - holder.remove_reagent(id, amount) - /// This doesn't apply to skin contact - this is for, e.g. extinguishers and sprays. The difference is that reagent is not directly on the mob's skin - it might just be on their clothing. /datum/reagent/proc/touch_mob(mob/M, amount) - return + SHOULD_NOT_OVERRIDE(TRUE) /// Acid melting, cleaner cleaning, etc /datum/reagent/proc/touch_obj(obj/O, amount) - return + SHOULD_NOT_OVERRIDE(TRUE) /// Cleaner cleaning, lube lubbing, etc, all go here /datum/reagent/proc/touch_turf(turf/T, amount) - return + SHOULD_NOT_OVERRIDE(TRUE) /// Currently, on_mob_life is called on carbons. Any interaction with non-carbon mobs (lube) will need to be done in touch_mob. /datum/reagent/proc/on_mob_life(var/mob/living/carbon/M, var/alien, var/datum/reagent_holder/metabolism/location, speed_mult = 1, force_allow_dead) @@ -133,7 +132,7 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) return var/datum/reagent_holder/metabolism/active_metab = location - var/removed = metabolism + var/removed = metabolism_rate var/mechanical_circulation = HAS_TRAIT(M, TRAIT_MECHANICAL_CIRCULATION) var/ingest_rem_mult = 1 @@ -222,37 +221,41 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) removed = ingest_met * ingest_rem_mult if(touch_met && (active_metab.metabolism_class == CHEM_TOUCH)) removed = touch_met + var/volume = location.reagent_volumes[id] + var/datum/reagent_metabolism/metabolism = location.reagent_metabolisms[id] removed = min(removed, volume) - max_dose = max(volume, max_dose) - dose = min(dose + removed, max_dose) - if(removed >= (metabolism * 0.1) || removed >= 0.1) // If there's too little chemical, don't affect the mob, just remove it + metabolism.peak_dose = max(volume, metabolism.peak_dose) + metabolism.total_processed_dose = min(metabolism.peak_dose, metabolism.total_processed_dose + removed) + metabolism.cycles_so_far++ + metabolism.legacy_volume_remaining = volume + metabolism.legacy_data = location.reagent_datas?[id] + metabolism.legacy_current_holder = active_metab + if(removed >= (metabolism_rate * 0.1) || removed >= 0.1) // If there's too little chemical, don't affect the mob, just remove it switch(active_metab.metabolism_class) if(CHEM_INJECT) - affect_blood(M, alien, removed) + legacy_affect_blood(M, alien, removed, metabolism) if(CHEM_INGEST) - affect_ingest(M, alien, removed * ingest_abs_mult) + legacy_affect_ingest(M, alien, removed * ingest_abs_mult, metabolism) if(CHEM_TOUCH) - affect_touch(M, alien, removed) + legacy_affect_touch(M, alien, removed, metabolism) if(overdose && (volume > overdose) && (active_metab.metabolism_class != CHEM_TOUCH && !can_overdose_touch)) - overdose(M, alien, removed) - remove_self(removed) + metabolism.cycles_overdosing++ + legacy_affect_overdose(M, alien, removed, metabolism) + else + metabolism.cycles_overdosing = 0 + metabolism.legacy_current_holder = null + active_metab.remove_reagent(id, removed) + +/datum/reagent/proc/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) return -// todo: on_mob_life with method of CHEM_INJECT, or tick_mob_blood -/datum/reagent/proc/affect_blood(mob/living/carbon/M, alien, removed) - return - -// todo: on_mob_life with method of CHEM_INGEST, or tick_mob_ingest -/datum/reagent/proc/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/proc/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.bloodstr.add_reagent(id, removed) return -// todo: on_mob_life with method of CHEM_TOUCH, or tick_mob_touch -/datum/reagent/proc/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/proc/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) return -// todo: fourth apply method of CHEM_VAPOR implementation? - /datum/reagent/proc/handle_vampire(var/mob/living/carbon/M, var/alien, var/removed, var/is_vampire) if(blood_content > 0 && is_vampire) #define blud_warn_timer 3000 @@ -264,7 +267,7 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) return M.nutrition += removed * blood_content //We should always be able to process real blood. -/datum/reagent/proc/overdose(var/mob/living/carbon/M, var/alien, var/removed) // Overdose effect. +/datum/reagent/proc/legacy_affect_overdose(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return if(ishuman(M)) @@ -272,40 +275,60 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) overdose_mod *= H.species.chemOD_mod M.adjustToxLoss(removed * overdose_mod) -/datum/reagent/proc/initialize_data(newdata) // Called when the reagent is created. - if(!isnull(newdata)) - data = newdata - return - -/datum/reagent/proc/get_data() // Just in case you have a reagent that handles data differently. - if(data && istype(data, /list)) - return data.Copy() - else if(data) - return data - return null - -/datum/reagent/Destroy() // This should only be called by the holder, so it's already handled clearing its references - holder = null - . = ..() - -/* DEPRECATED - TODO: REMOVE EVERYWHERE */ +//* Color *// -/datum/reagent/proc/reaction_turf(var/turf/target, amt) - touch_turf(target, amt) +/** + * Only called if holds_data is TRUE. + */ +/datum/reagent/proc/compute_color_with_data(data) + return color -/datum/reagent/proc/reaction_obj(var/obj/target, amt) - touch_obj(target, amt) +//* Data *// -/datum/reagent/proc/reaction_mob(var/mob/target, amt) - touch_mob(target, amt) +/** + * Get data to feed in as the `data_initializer` during a reagents transfer. + * + * * `data` is not considered mutable. You may not edit it in this proc. + * * Do not modify the returned value. It is not considered mutable. + * + * @return an initializer. This initializer is not mutable. + */ +/datum/reagent/proc/make_copy_data_initializer(data) + return null -/datum/reagent/proc/on_move(mob/M) - return +/** + * Preprocess data fed in during add_reagent + * + * * `data_initializer` is not considered mutable. You may not edit it in this proc. + * * Do not modify the returned value. It is not considered mutable. + * + * @return data to put into mix_data. This data is immutable. + */ +/datum/reagent/proc/preprocess_data(data_initializer) + return null -/datum/reagent/proc/on_update(atom/A) - return +/** + * Mixes data + * + * * in add_reagent, this is called with the preprocessed new data + * * in transfer procs, this is called with the old data + * * this is not called if there's no reagents of ourselves in the new container. + * * `old_data` is considered mutable. `new_data` is not. This is becuase `old_data` belongs to the holder + * calling us, but `new_data` can potentially be a shared struct. + * + * @params + * * old_data - existing data; null if not there + * * old_volume - existing volume; 0 if not there + * * new_data - adding data; this is from the returns of `preprocess_data()` + * * new_volume - adding volume + * * holder - (optional) the holder we're mixing in, if any + * + * @return overall data to assign to reagent + */ +/datum/reagent/proc/mix_data(old_data, old_volume, new_data, new_volume, datum/reagent_holder/holder) + return null -//* Guidebook +//* Guidebook *// /** * Guidebook Data for TGUIGuidebookReagent @@ -322,63 +345,119 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) "alcoholStrength" = null, ) -//* Holder - Application +//* Holder - Application *// + +/** + * Called when we're sprayed / splashed onto an obj + * + * @params + * * target - turf + * * remaining - how much is being applied / is remaining / is in the container right now + * * allocated - how much is supposed to be hitting the obj (useful for sprays) + * this will never be over remaining. + * * data - our reagent data, if any + * * spread_between - (optional) unlike turfs, there's potentially a lot of objects. + * this hints at how many objs are being hit. this is optional. + * + * @return amount used, if any + */ +/datum/reagent/proc/on_touch_obj(obj/target, remaining, allocated, data, spread_between) + return 0 /** - * called when we first get applied to a mob + * Called when we're sprayed / splashed onto a turf * * @params - * * target - target mob - * * holder - the holder on the target mob - * * method - an enum of how we're applied from [code/__DEFINES/chemistry.dm] - * * amount - how much is being applied - * * data - data. not necessarily a list, but casted as one. this is before mix_data is called. + * * target - turf + * * remaining - how much is being applied / is remaining / is in the container right now + * * allocated - how much is supposed to be hitting the turf (useful for sprays) + * this will never be over remaining. + * * data - our reagent data, if any * - * @return amount to inject into the mob side holder. defaults to amount. this can be overriden by the mob / transfer procs. + * @return amount used, if any */ -// todo: implement this proc, replace reaction mob and similar with it. -// /datum/reagent/proc/apply_to_mob(mob/target, datum/reagent_holder/holder, amount, list/data) -// return amount +/datum/reagent/proc/on_touch_turf(turf/target, remaining, allocated, data) + return 0 /** - * called when we first get sprayed/splashed on a non-mob + * This should only be called when the reagent reaches the mob's skin / whatever, not before. * - * not called if we're transferred into a holder on the obj + * * Do not manually implement splashing if a limb is specified. The caller does this already. * * @params - * * target - the target. - * * amount - how much is being applied - * * data - data. not necessarily a list, but casted as one. this is before mix_data is caled. + * * target - the mob + * * remaining - how much is left in the thing being splashed. + * * allocated - how much is supposed to be hitting the target limb (useful for sprays). + * this will never be over remaining. + * it might be useful to subtract from this in overrides before invoking ..() sometimes. + * * data - our reagent data, if any + * * zone - (optional) the body zone targeted + * * limb - (optional) the external organ splashed onto. + * + * @return amount used, if any */ -// todo: implement this proc, replace touch_obj/reaction_obj and similar with it. -// /datum/reagent/proc/apply_to_obj(obj/target, amount, list/data) +/datum/reagent/proc/on_touch_mob(mob/target, remaining, allocated, data, zone) + . = 0 + if(istype(src, /mob/living/carbon)) + var/mob/living/carbon/casted = src + . += on_touch_carbon(target, remaining, allocated, data, zone, casted.get_bodypart_for_zone(zone)) + else if(istype(src, /mob/living/simple_mob)) + . += on_touch_simple(target, remaining, allocated, data, zone) + else if(istype(src, /mob/living/silicon)) + . += on_touch_silicon(target, remaining, allocated, data, zone) + return 0 /** - * called when we first get sprayed/splashed on a turf + * Called by on_touch_mob(). * - * not called if we're transferred into a holder on the turf, somehow + * * Do not manually implement splashing if a limb is specified. The caller does this already. * * @params - * * target - the target. - * * amount - how much is being applied - * * data - data. not necessarily a list, but casted as one. this is before mix_data is caled. + * * target - the mob + * * remaining - how much is left in the thing being splashed. + * * allocated - how much is supposed to be hitting the target limb (useful for sprays). + * this will never be over remaining. + * * data - our reagent data, if any + * * zone - (optional) target body zone + * * limb - (optional) the external organ splashed onto. + * + * @return amount used, if any */ -// todo: implement this proc, replace touch_turf/reaction_turf and similar with it. -// /datum/reagent/proc/apply_to_turf(turf/target, amount, list/data) +/datum/reagent/proc/on_touch_carbon(mob/living/carbon/target, remaining, allocated, data, zone, obj/item/organ/external/limb) + return 0 -//* Holder - Mixing +/** + * Called by on_touch_mob(). + * + * * Do not manually implement splashing if a limb is specified. The caller does this already. + * + * @params + * * target - the mob + * * remaining - how much is left in the thing being splashed. + * * allocated - how much is supposed to be hitting the target limb (useful for sprays). + * this will never be over remaining. + * * data - our reagent data, if any + * * zone - (optional) target body zone + * + * @return amount used, if any + */ +/datum/reagent/proc/on_touch_silicon(mob/living/silicon/target, remaining, allocated, data, zone) + return 0 /** - * called when a new reagent is being mixed with this one to mix our data lists. + * Called by on_touch_mob(). * - * this may not be called if the data is the exact same! + * * Do not manually implement splashing if a limb is specified. The caller does this already. * * @params - * * holder - (optional) the holder we're mixing in, if any. - * * current_data - our current data. not necessarily a list, only typecasted to one. - * * current_amount - our current amount - * * new_data - new inbound data. not necessarily a list, only typedcasted to one. - * * new_amount - the amount that's coming in, not what we will be at after mixing. + * * target - the mob + * * remaining - how much is left in the thing being splashed. + * * allocated - how much is supposed to be hitting the target limb (useful for sprays). + * this will never be over remaining. + * * data - our reagent data, if any + * * zone - (optional) target body zone + * + * @return amount used, if any */ -/datum/reagent/proc/mix_data(datum/reagent_holder/holder, list/current_data, current_amount, list/new_data, new_amount) - return +/datum/reagent/proc/on_touch_simple(mob/living/simple_mob/target, remaining, allocated, data, zone) + return 0 diff --git a/code/modules/reagents/chemistry/reagent_holder-color.dm b/code/modules/reagents/chemistry/reagent_holder-color.dm new file mode 100644 index 000000000000..60a3d624e7aa --- /dev/null +++ b/code/modules/reagents/chemistry/reagent_holder-color.dm @@ -0,0 +1,31 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/reagent_holder/proc/get_color() + switch(length(reagent_volumes)) + if(0) + return "#ffffff" + if(1) + var/datum/reagent/solo_reagent = SSchemistry.reagent_lookup[reagent_volumes[1]] + return solo_reagent.holds_data ? solo_reagent.compute_color_with_data(reagent_datas?[solo_reagent.id]) : solo_reagent.color + var/total_r = 0 + var/total_g = 0 + var/total_b = 0 + var/total_a = 0 + var/total_weight = 0 + for(var/id in reagent_volumes) + var/volume = reagent_volumes[id] + var/datum/reagent/resolved_reagent = SSchemistry.reagent_lookup[id] + var/effective_color = resolved_reagent.holds_data ? resolved_reagent.compute_color_with_data(reagent_datas?[resolved_reagent.id]) : resolved_reagent.color + switch(effective_color) + if(7) + if(9) + total_a += hex2num(copytext(resolved_reagent.color, 8, 10)) * volume * resolved_reagent.color_weight + else + // todo: this should be checked in reagent init. just runtime at this point. + stack_trace("reagent id [id] has an incorrect color set: [resolved_reagent.color]") + resolved_reagent.color = "#ffffff" + total_r += hex2num(copytext(resolved_reagent.color, 2, 4)) * volume * resolved_reagent.color_weight + total_g += hex2num(copytext(resolved_reagent.color, 4, 6)) * volume * resolved_reagent.color_weight + total_b += hex2num(copytext(resolved_reagent.color, 6, 8)) * volume * resolved_reagent.color_weight + return rgb(total_r / total_weight, total_g / total_weight, total_b / total_weight, total_a / total_weight) diff --git a/code/modules/reagents/chemistry/reagent_holder-helpers.dm b/code/modules/reagents/chemistry/reagent_holder-helpers.dm new file mode 100644 index 000000000000..5b415eee59ba --- /dev/null +++ b/code/modules/reagents/chemistry/reagent_holder-helpers.dm @@ -0,0 +1,24 @@ +//* Majority Reagent *// + +/** + * Returns reagent datum of highest single reagent in volume, or null if we are empty. + */ +/datum/reagent_holder/proc/get_majority_reagent_datum() as /datum/reagent + var/highest_so_far = 0 + var/id_so_far + for(var/id in reagent_volumes) + if(reagent_volumes[id] > highest_so_far) + id_so_far = id + return SSchemistry.fetch_reagent(id_so_far) + +/** + * Returns reagent name of highest single reagent in volume, or null if we are empty. + */ +/datum/reagent_holder/proc/get_majority_reagent_name() + return get_majority_reagent_datum()?.name + +/** + * Returns reagent ID of highest single reagent in volume, or null if we are empty. + */ +/datum/reagent_holder/proc/get_majority_reagent_id() + return get_majority_reagent_datum()?.id diff --git a/code/modules/reagents/chemistry/reagent_holder-legacy.dm b/code/modules/reagents/chemistry/reagent_holder-legacy.dm index 4ed9a85f5508..01a08651889b 100644 --- a/code/modules/reagents/chemistry/reagent_holder-legacy.dm +++ b/code/modules/reagents/chemistry/reagent_holder-legacy.dm @@ -1,13 +1,10 @@ /** - * todo: this should just be reagent_volumes[id] but the current system is pants on head stupid + * todo: this should just be reagent_volumes[id], this is not done for PR atomicity reasons * * @return null if not found, otherwise amount as number */ /datum/reagent_holder/proc/legacy_direct_access_reagent_amount(id) - for(var/datum/reagent/reagent in reagent_list) - if(reagent.id == id) - return reagent.volume - return null + return reagent_volumes[id] /** * todo: what do we do with this? diff --git a/code/modules/reagents/chemistry/metabolism.dm b/code/modules/reagents/chemistry/reagent_holder-metabolism.dm similarity index 75% rename from code/modules/reagents/chemistry/metabolism.dm rename to code/modules/reagents/chemistry/reagent_holder-metabolism.dm index 469d40a3a8c8..479f51e4bf45 100644 --- a/code/modules/reagents/chemistry/metabolism.dm +++ b/code/modules/reagents/chemistry/reagent_holder-metabolism.dm @@ -1,4 +1,7 @@ /datum/reagent_holder/metabolism + /// reagent id to /datum/reagent_metabolism + var/list/reagent_metabolisms + var/metabolism_class //CHEM_TOUCH, CHEM_INGEST, or CHEM_INJECT var/metabolism_speed = 1 // Multiplicative, 1 is full speed, 0.5 is half, etc. var/mob/living/carbon/parent @@ -22,6 +25,16 @@ current.on_mob_life(parent, metabolism_type, src, speed_mult, force_allow_dead) update_total() +/datum/reagent_holder/metabolism/add_reagent(id, amount, data_initializer, skip_reactions) + . = ..() + LAZYINITLIST(reagent_metabolisms) + #warn impl + +/datum/reagent_holder/metabolism/remove_reagent(id, amount, skip_reactions) + . = ..() + LAZYINITLIST(reagent_metabolisms) + #warn impl + // "Specialized" metabolism datums /datum/reagent_holder/metabolism/bloodstream metabolism_class = CHEM_INJECT diff --git a/code/modules/reagents/chemistry/reagent_holder-reactions.dm b/code/modules/reagents/chemistry/reagent_holder-reactions.dm index a62162d0bb60..05a6e5e0c015 100644 --- a/code/modules/reagents/chemistry/reagent_holder-reactions.dm +++ b/code/modules/reagents/chemistry/reagent_holder-reactions.dm @@ -12,11 +12,7 @@ /datum/reagent_holder/proc/reconsider_reactions() SHOULD_NOT_SLEEP(TRUE) - var/list/reagent_ids = list() - for(var/datum/reagent/reagent in reagent_list) - reagent_ids[reagent.id] = TRUE - - var/list/datum/chemical_reaction/reactions = SSchemistry.immutable_relevant_reactions_for_reagent_ids(reagent_ids) + var/list/datum/chemical_reaction/reactions = SSchemistry.immutable_relevant_reactions_for_reagent_ids(reagent_volumes) check_reactions(reactions) //* Internal API *// diff --git a/code/modules/reagents/chemistry/reagent_holder.dm b/code/modules/reagents/chemistry/reagent_holder.dm index 45505ac908c1..7d42be9c18c6 100644 --- a/code/modules/reagents/chemistry/reagent_holder.dm +++ b/code/modules/reagents/chemistry/reagent_holder.dm @@ -4,6 +4,11 @@ /// reagent holder flags - see [code/__DEFINES/reagents/flags.dm] var/reagent_holder_flags = NONE + //* Container *// + + /// Our maximum volume + var/maximum_volume = 100 + //* Reactions *// /// active reactions @@ -15,14 +20,22 @@ //* Reagents *// + /// Our reagent volumes + /// + /// * Lazy list. + var/list/reagent_volumes + /// Our reagent datas + /// + /// * Lazy list. + var/list/reagent_datas /// Our temperature var/temperature = T20C + /// Our current volume + /// + /// * Must be eagerly updated. Many internal procs depend on this for speed. + var/total_volume = 0 ///? legacy / unsorted - // todo: 3 lists, for volume, data, flags; data should always be a list. - var/list/datum/reagent/reagent_list = list() - var/total_volume = 0 - var/maximum_volume = 100 var/atom/my_atom = null // todo: remove / refactor this var into reagent_holder_flags with proper defines, this was never ported properly. @@ -35,68 +48,36 @@ reagents_holder_flags = new_flags /datum/reagent_holder/Destroy() + // stop all reactions if(reagent_holder_flags & REAGENT_HOLDER_FLAG_CURRENTLY_REACTING) stop_reacting() - - for(var/datum/reagent/R in reagent_list) - qdel(R) - reagent_list = null - if(my_atom && my_atom.reagents == src) - my_atom.reagents = null + // unreference volumes and datas + reagent_volumes = reagent_datas = null + // unreference our atom + if(my_atom) + if(my_atom.reagents == src) + my_atom.reagents = null + my_atom = null return ..() // Used in attack logs for reagents in pills and such /datum/reagent_holder/proc/log_list() - if(!length(reagent_list)) + if(!length(reagent_volumes)) return "no reagents" var/list/data = list() - for(var/r in reagent_list) //no reagents will be left behind - var/datum/reagent/R = r - data += "[R.type] [R.volume]u)" + for(var/id in reagent_volumes) + data += "[id] ([reagent_volumes[id]]u)" //Using IDs because SOME chemicals (I'm looking at you, chlorhydrate-beer) have the same names as other chemicals. return english_list(data) /* Internal procs */ -/datum/reagent_holder/proc/get_master_reagent() // Returns reference to the reagent with the biggest volume. - var/the_reagent = null - var/the_volume = 0 - - for(var/datum/reagent/A in reagent_list) - if(A.volume > the_volume) - the_volume = A.volume - the_reagent = A - - return the_reagent - -/datum/reagent_holder/proc/get_master_reagent_name() // Returns the name of the reagent with the biggest volume. - var/the_name = null - var/the_volume = 0 - for(var/datum/reagent/A in reagent_list) - if(A.volume > the_volume) - the_volume = A.volume - the_name = A.name - - return the_name - -/datum/reagent_holder/proc/get_master_reagent_id() // Returns the id of the reagent with the biggest volume. - var/the_id = null - var/the_volume = 0 - for(var/datum/reagent/A in reagent_list) - if(A.volume > the_volume) - the_volume = A.volume - the_id = A.id - - return the_id - /datum/reagent_holder/proc/update_total() // Updates volume. - total_volume = 0 - for(var/datum/reagent/R in reagent_list) - if(R.volume < MINIMUM_CHEMICAL_VOLUME) - del_reagent_impl(R) - else - total_volume += R.volume + var/new_volume = 0 + for(var/id in reagent_volumes) + new_volume += reagent_volumes[id] + total_volume = new_volume /datum/reagent_holder/proc/holder_full() if(total_volume >= maximum_volume) @@ -121,55 +102,55 @@ var/datum/reagent/accessing = id id = initial(accessing.id) - if(!isnum(amount) || amount <= 0) + amount = min(amount, maximum_volume - total_volume) + if(amount <= 0) + return 0 + + // this reagent may need to be loaded from persistence + var/datum/reagent/reagent = SSchemistry.fetch_reagent(id) + + if(!reagent) return 0 - // todo: rewrite this entire proc; especially data. - - update_total() - amount = min(amount, available_volume()) - - for(var/datum/reagent/current in reagent_list) - if(current.id == id) - if(current.id == "blood") - if(data_initializer && !isnull(data_initializer["species"]) && !isnull(current.data["species"]) && data_initializer["species"] != current.data["species"]) // Species bloodtypes are already incompatible, this just stops it from mixing into the one already in a container. - continue - - current.volume += amount - if(!isnull(data_initializer)) // For all we know, it could be zero or empty string and meaningful - current.mix_data(src, current.data, current.volume, data_initializer, amount) - update_total() - if(!skip_reactions) - try_reactions_for_reagent_change(id) - if(my_atom) - my_atom.on_reagent_change() - return amount - var/datum/reagent/D = SSchemistry.reagent_lookup[id] - if(D) - var/datum/reagent/R = new D.type() - reagent_list += R - R.holder = src - R.volume = amount - R.initialize_data(data_initializer) - update_total() - if(!skip_reactions) - // todo: use the relevant reactions on add, instead of all relevant reactions, for speed - try_reactions_for_reagent_change(id) - if(my_atom) - my_atom.on_reagent_change() - return amount + if(reagent_volumes) + reagent_volumes[id] += amount else - stack_trace("[my_atom] attempted to add a reagent called '[id]' which doesn't exist. ([usr])") - return 0 + reagent_volumes = list((id) = amount) + + if(reagent.holds_data) + if(reagent_datas) + reagent_datas[id] = reagent.mix_data( + reagent_datas[id], + reagent_volumes[id] - amount, + reagent.preprocess_data(data_initializer), + amount, + src, + ) + else + reagent_datas = list((id) = reagent.mix_data(null, 0, reagent.preprocess_data(data_initializer), amount, src)) + + total_volume += amount + + if(!skip_reactions) + try_reactions_for_reagent_change(id) + + //! LEGACY + if(my_atom) + my_atom.on_reagent_change() + //! END + + return amount /datum/reagent_holder/proc/isolate_reagent(reagent) + if(ispath(reagent)) + var/datum/reagent/path = reagent + reagent = initial(path.id) var/list/changed_ids = list() - for(var/A in reagent_list) - var/datum/reagent/R = A - if(R.id != reagent) - changed_ids[R.id] = TRUE - del_reagent(R.id) - update_total() + for(var/id in reagent_volumes) + if(id == reagent) + continue + changed_ids += id + del_reagent(id, TRUE) try_reactions_for_reagents_changed(changed_ids) /** @@ -186,150 +167,103 @@ if(ispath(id)) var/datum/reagent/path = id id = initial(path.id) - if(!isnum(amount)) + if(amount <= 0) return 0 - for(var/datum/reagent/current in reagent_list) - if(current.id == id) - amount = min(amount, current.volume) - current.volume -= amount - update_total() - if(!skip_reactions) - // todo: use the relevant reactions on remove, instead of all relevant reactions, for speed - try_reactions_for_reagent_change(id) - if(my_atom) - my_atom.on_reagent_change() - return amount - return 0 - -/datum/reagent_holder/proc/del_reagent(id, skip_reactions) - for(var/datum/reagent/current in reagent_list) - if (current.id == id) - del_reagent_impl(current) - update_total() - if(!skip_reactions) - // todo: use the relevant reactions on remove, instead of all relevant reactions, for speed - try_reactions_for_reagent_change(current.id) - if(my_atom) - my_atom.on_reagent_change() - return 0 - -// todo: burn this shit with fire -/datum/reagent_holder/proc/del_reagent_impl(datum/reagent/reagent) - if(!(reagent in reagent_list)) + var/current = reagent_volumes?[id] + if(!current) return - reagent_list -= reagent - qdel(reagent) - -/datum/reagent_holder/proc/clear_reagents(skip_reactions) - for(var/datum/reagent/current in reagent_list) - //* telling del_reagent skip reactions is very very important *// - // without it, if you have potassium, water, and something halting the explosion, // - // you can have an explosion by clearing the beaker if it goes in the wrong order // - // that and it's faster this way. do not touch this call! // - del_reagent(current.id, TRUE) + if(amount >= current) + reagent_volumes -= id + if(reagent_datas) + reagent_datas -= id + total_volume -= current + . = current + else + reagent_volumes[id] -= amount + total_volume -= amount + . = amount if(!skip_reactions) - reconsider_reactions() + try_reactions_for_reagent_change(id) + //! LEGACY + if(my_atom) + my_atom.on_reagent_change() + //! END -/datum/reagent_holder/proc/has_reagent(id, amount = 0) +/** + * Completely remove a reagent. + * + * @params + * * id - id or typepath. + * * skip_reactions - do not reconsider relevant reactions. + * + * @return amount removed + */ +/datum/reagent_holder/proc/del_reagent(id, skip_reactions) if(ispath(id)) var/datum/reagent/path = id id = initial(path.id) - for(var/datum/reagent/current in reagent_list) - if(current.id == id) - if(current.volume >= amount) - return 1 - else - return 0 - return 0 + var/current = reagent_volumes?[id] + if(!current) + return 0 + reagent_volumes -= id + total_volume -= current + if(!skip_reactions) + try_reactions_for_reagent_change(id) + //! LEGACY + if(my_atom) + my_atom.on_reagent_change() + //! END + return current -/datum/reagent_holder/proc/has_any_reagent(list/check_reagents) - for(var/datum/reagent/current in reagent_list) - if(current.id in check_reagents) - if(current.volume >= check_reagents[current.id]) - return 1 - else - return 0 - return 0 +/** + * Completely remove all reagents. + */ +/datum/reagent_holder/proc/clear_reagents() + reagent_volumes = null + reagent_datas = null -/datum/reagent_holder/proc/has_all_reagents(list/check_reagents, multiplier = 1) - //this only works if check_reagents has no duplicate entries... hopefully okay since it expects an associative list - var/missing = check_reagents.len - for(var/datum/reagent/current in reagent_list) - if(current.id in check_reagents) - if(current.volume >= check_reagents[current.id] * multiplier) - missing-- - return !missing - -/datum/reagent_holder/proc/get_reagent(id) - for(var/datum/reagent/current in reagent_list) - if(current.id == id) - return current - -/datum/reagent_holder/proc/get_reagent_amount(id) +/datum/reagent_holder/proc/has_reagent(id, amount = 0.00001) if(ispath(id)) var/datum/reagent/path = id id = initial(path.id) - for(var/datum/reagent/current in reagent_list) - if(current.id == id) - return current.volume - return 0 - -/datum/reagent_holder/proc/get_data(id) - for(var/datum/reagent/current in reagent_list) - if(current.id == id) - return current.get_data() - return 0 + return !isnull(reagent_volumes?[id]) /datum/reagent_holder/proc/get_reagents() . = list() - for(var/datum/reagent/current in reagent_list) - . += "[current.id] ([current.volume])" + for(var/id in reagent_volumes) + var/volume = reagent_volumes[id] + . += "[id] ([volume])" return english_list(., "EMPTY", "", ", ", ", ") /* Holder-to-holder and similar procs */ -/datum/reagent_holder/proc/remove_any(amount = 1) // Removes up to [amount] of reagents from [src]. Returns actual amount removed. - amount = min(amount, total_volume) - - if(!amount) +/** + * Removes a given amount from the holder, equally from all reagents. + * + * @params + * * amount - amount to remove + * + * @return amount removed + */ +/datum/reagent_holder/proc/remove_any(amount) + if(amount <= 0 || !total_volume) + return 0 + if(amount >= total_volume) + . = total_volume + clear_reagents() return - - var/part = amount / total_volume - - for(var/datum/reagent/current in reagent_list) - var/amount_to_remove = current.volume * part - remove_reagent(current.id, amount_to_remove, 1) - - update_total() - // todo: do we really need to update everything? + var/remaining_ratio = 1 - (amount / total_volume) + for(var/id in reagent_volumes) + reagent_volumes[id] *= remaining_ratio + // todo: don't update everything, just update relevant? reconsider_reactions() return amount +// todo: annihilate this proc // Transfers [amount] reagents from [src] to [target], multiplying them by [multiplier]. // Returns actual amount removed from [src] (not amount transferred to [target]). /datum/reagent_holder/proc/trans_to_holder(datum/reagent_holder/target, amount = 1, multiplier = 1, copy = 0) - if(!target || !istype(target)) - return - - amount = max(0, min(amount, total_volume, target.available_volume() / multiplier)) - - if(!amount) - return - - var/part = amount / total_volume - - for(var/datum/reagent/current in reagent_list) - var/amount_to_transfer = current.volume * part - target.add_reagent(current.id, amount_to_transfer * multiplier, current.get_data(), TRUE) - if(!copy) - remove_reagent(current.id, amount_to_transfer, 1) - - // todo: do we really need to update everything? - if(!copy) - reconsider_reactions() - target.reconsider_reactions() - - return amount + return transfer_to_holder(target, null, amount, copy, multiplier) /* Holder-to-atom and similar procs */ @@ -377,46 +311,6 @@ return F.trans_to(target, amount) // Let this proc check the atom's type -// When applying reagents to an atom externally, touch() is called to trigger any on-touch effects of the reagent. -// This does not handle transferring reagents to things. -// For example, splashing someone with water will get them wet and extinguish them if they are on fire, -// even if they are wearing an impermeable suit that prevents the reagents from contacting the skin. -/datum/reagent_holder/proc/touch(atom/target, amount) - if(ismob(target)) - touch_mob(target, amount) - if(isturf(target)) - touch_turf(target, amount) - if(isobj(target)) - touch_obj(target, amount) - return - -/datum/reagent_holder/proc/touch_mob(mob/target) - if(!target || !istype(target)) - return - - for(var/datum/reagent/current in reagent_list) - current.touch_mob(target, current.volume) - - update_total() - -/datum/reagent_holder/proc/touch_turf(turf/target, amount) - if(!target || !istype(target)) - return - - for(var/datum/reagent/current in reagent_list) - current.touch_turf(target, amount) - - update_total() - -/datum/reagent_holder/proc/touch_obj(obj/target, amount) - if(!target || !istype(target)) - return - - for(var/datum/reagent/current in reagent_list) - current.touch_obj(target, amount) - - update_total() - // Attempts to place a reagent on the mob's skin. // Reagents are not guaranteed to transfer to the target. // Do not call this directly, call trans_to() instead. @@ -494,7 +388,8 @@ for (var/turf/T in turfs) var/datum/reagent_holder/TR = new /datum/reagent_holder(turfportion) R.trans_to_holder(TR, turfportion, 1, 0) - TR.splash_turf(T) + #warn uh + // TR.splash_turf(T) qdel(R) //Spreads the contents of this reagent holder all over the target turf, dividing among things in it. @@ -527,17 +422,42 @@ if (total_volume <= 0) qdel(src) -/datum/reagent_holder/proc/conditional_update_move(atom/A, Running = 0) - var/list/cached_reagents = reagent_list - for(var/datum/reagent/R in cached_reagents) - R.on_move (A, Running) - update_total() +//* Application *// -/datum/reagent_holder/proc/conditional_update(atom/A) - var/list/cached_reagents = reagent_list - for(var/datum/reagent/R in cached_reagents) - R.on_update (A) - update_total() +/** + * Spill us onto an entity. + * + * * 'auto' designates the fact that we're default handling. Use with caution; this reserves + * the right to do pretty much anything, really. + * * Returned amount is amount removed. This doesn't actually return the amount 'consumed'. + * * The ratio controls actual amount consumed for splash; if something isn't consumed, it's still deleted. + * + * The reality of this proc is that this is not enough (intentionally) to prevent reagent duping of any kind. + * + * If we actually enforced hard unit conservation, a lot of reagents would just not do much on splash + * because it wouldn't apply enough to be a big deal, and we can't have it do more with less because + * that would make the reagent too powerful. + * + * @params + * * target - what to splash on + * * ratio - % to apply + * * splash - splash around. if it's an object, we can hit stuff around it; if it's a turf, we can hit + * anything on the turf. + * * keep_remaining - return unused reagents to holder. + * + * @return amount splashed + */ +/datum/reagent_holder/proc/auto_spill(atom/target, ratio, splash, keep_remaining) + . = ratio * total_volume + if(splash) + + if(isturf(target)) + else if(ismob(target)) + else if(isobj(target)) + + + +#warn deal with these //* Filtering *// @@ -553,10 +473,11 @@ if(amount <= 0) return var/list/filtering_ids = list() - for(var/datum/reagent/reagent in reagent_list) + for(var/id in reagent_volumes) + var/datum/reagent/reagent = SSchemistry.fetch_reagent(id) if(!(reagent.reagent_filter_flags & flags)) continue - filtering_ids += reagent.id + filtering_ids += id return transfer_to_holder(transfer_to, filtering_ids, amount) /** @@ -570,18 +491,43 @@ if(amount <= 0) return var/total_filterable = 0 - var/list/datum/reagent/filtering = list() - for(var/datum/reagent/reagent in reagent_list) + var/list/filtering_ids = list() + for(var/id in reagent_volumes) + var/datum/reagent/reagent = SSchemistry.fetch_reagent(id) if(!(reagent.reagent_filter_flags & flags)) continue - total_filterable += reagent.volume - filtering += reagent + total_filterable += reagent_volumes[id] + filtering_ids += id var/ratio = amount / total_filterable - for(var/datum/reagent/to_filter in filtering) - remove_reagent(to_filter.id, to_filter.volume * ratio, TRUE) + for(var/id in filtering_ids) + remove_reagent(id, reagent_volumes[id] * ratio, TRUE) reconsider_reactions() return min(amount, total_filterable) +//* Getters *// + +/** + * Gets the amount of a reagent ID or path + */ +/datum/reagent_holder/proc/get_reagent_amount(datum/reagent/reagentlike) + return reagent_volumes ? reagent_volumes[ispath(reagentlike) ? initial(reagentlike.id) : (istype(reagentlike) ? reagentlike.id : reagentlike)] : 0 + +/** + * Gets the data of a reagent ID or path + */ +/datum/reagent_holder/proc/get_reagent_data(datum/reagent/reagentlike) + return reagent_datas ? reagent_datas[ispath(reagentlike) ? initial(reagentlike.id) : (istype(reagentlike) ? reagentlike.id : reagentlike)] : null + +/** + * Gets the global singletons of reagents in us. + * + * todo: how do we handle this cleanly? this shouldn't be the usual case. rename to fetch_reagent_datums()? + */ +/datum/reagent_holder/proc/get_reagent_datums() as /list + . = list() + for(var/id in reagent_volumes) + . += SSchemistry.fetch_reagent(id) + //* Queries *// /** @@ -591,18 +537,33 @@ return maximum_volume - total_volume /** - * returns lowest multiple of what we have compared to reagents list. + * Returns if we have any of the given reagent IDs or paths. * - * both typepaths and ids are acceptable. + * @params + * * reagent_ids - ids or paths + * * minimum - minimum to be considered to be there. Do not set this to 0 or this proc will always succeed. */ -/datum/reagent_holder/proc/has_multiple(list/reagents, multiplier = 1) +/datum/reagent_holder/proc/has_any(list/reagent_ids, minimum = 0.00001) + for(var/datum/reagent/id as anything in reagent_ids) + if(ispath(id)) + id = initial(id.id) + if(reagent_volumes[id] >= minimum) + return TRUE + return FALSE + +/** + * Returns lowest multiple of what we have compared to reagents list. + * + * * Reagent instances are not allowed in reagent ids list. + * + * @params + * * reagent_ids - ids or paths + */ +/datum/reagent_holder/proc/has_multiple(list/reagent_ids) . = INFINITY // *sigh* - var/list/legacy_translating = list() - for(var/datum/reagent/R in reagent_list) - legacy_translating[R.id] = R.volume - for(var/datum/reagent/reagent as anything in reagents) - . = min(., legacy_translating[ispath(reagent)? initial(reagent.id) : reagent] / reagents[reagent]) + for(var/datum/reagent/reagent as anything in reagent_ids) + . = min(., reagent_volumes[ispath(reagent)? initial(reagent.id) : reagent] / reagent_ids[reagent]) if(!.) return @@ -628,6 +589,7 @@ * If 'no_check_reactions' is set to TRUE, we skip that. */ /datum/reagent_holder/proc/set_no_react(new_value, no_check_reactions) + // todo: this shouldn't be on atom AAAAA if(!my_atom) return if(!!new_value == !!(my_atom?.atom_flags & NOREACT)) @@ -647,59 +609,59 @@ //* Transfers *// /** + * Transfers to a holder. + * + * * It is **undefined behavior** to have duplicate IDs in the list of reagent IDs to filter by. + * * Reagent instances are not allowed in reagent filter list. + * * @params * * target - target holder - * * reagents - list of paths or ids to filter by + * * reagents - list of reagent ids or paths to filter by; * * amount - limit of how much * * copy - do not remove the reagent from source * * multiplier - magically multiply the transferred reagent volumes by this much; does not affect return value. - * * defer_reactions - should we + the recipient handle reactions? + * * defer_reactions - should we + the recipient skip handling reactions immediately? * - * @return reagents transferred + * @return total volume transferred */ /datum/reagent_holder/proc/transfer_to_holder(datum/reagent_holder/target, list/reagents, amount = INFINITY, copy, multiplier = 1, defer_reactions) - . = 0 - // todo: rework this proc if(!total_volume) - return - if(!reagents) - var/ratio = min(1, min(amount, target.maximum_volume - target.total_volume) / total_volume) - . = total_volume * ratio - if(!copy) - for(var/datum/reagent/R as anything in reagent_list) - var/transferred = R.volume * ratio - target.add_reagent(R.id, transferred * multiplier, R.get_data(), TRUE) - remove_reagent(R.id, transferred, TRUE) - else - for(var/datum/reagent/R as anything in reagent_list) - var/transferred = R.volume * ratio - target.add_reagent(R.id, transferred * multiplier, R.get_data(), TRUE) - else + return 0 + + var/list/ids_to_transfer + var/ratio + + if(reagents) var/total_transferable = 0 - var/list/reagents_transferring = list() - // preprocess to IDs - for(var/i in 1 to length(reagents)) - var/datum/reagent/resolved = SSchemistry.fetch_reagent(reagents[i]) - reagents[i] = resolved.id - // filter & gather - for(var/datum/reagent/R as anything in reagent_list) - if(!(R.id in reagents)) + ids_to_transfer = list() + for(var/datum/reagent/potential as anything in reagents) + if(ispath(potential)) + potential = initial(potential.id) + var/volume = reagent_volumes[potential] + if(!volume) continue - total_transferable += R.volume - reagents_transferring += R + total_transferable += volume + ids_to_transfer += potential if(!total_transferable) return 0 var/ratio = min(1, min(amount, target.maximum_volume - target.total_volume) / total_transferable) . = total_transferable * ratio - if(!copy) - for(var/datum/reagent/R as anything in reagents_transferring) - var/transferred = R.volume * ratio - target.add_reagent(R.id, transferred * multiplier, R.get_data(), TRUE) - remove_reagent(R.id, transferred, TRUE) - else - for(var/datum/reagent/R as anything in reagents_transferring) - var/transferred = R.volume * ratio - target.add_reagent(R.id, transferred * multiplier, R.get_data(), TRUE) + else + ids_to_transfer = reagent_volumes + ratio = min(1, min(amount, target.maximum_volume - target.total_volume) / total_volume) + . = total_volume * ratio + + if(!copy) + for(var/id in ids_to_transfer) + var/datum/reagent/resolved = SSchemistry.fetch_reagent(id) + var/transferred = reagent_volumes[id] * ratio + target.add_reagent(id, transferred, resolved.make_copy_data_initializer(reagent_datas[id]), TRUE) + remove_reagent(id, transferred, TRUE) + else + for(var/id in ids_to_transfer) + var/datum/reagent/resolved = SSchemistry.fetch_reagent(id) + var/transferred = reagent_volumes[id] * ratio + target.add_reagent(id, transferred, resolved.make_copy_data_initializer(reagent_datas[id]), TRUE) if(!defer_reactions) if(!copy) @@ -713,10 +675,12 @@ */ /datum/reagent_holder/proc/tgui_reagent_contents() var/list/built = list() - for(var/datum/reagent/R as anything in reagent_list) + for(var/id in reagent_volumes) + var/datum/reagent/R = SSchemistry.fetch_reagent(id) + var/volume = reagent_volumes[id] built[++built.len] = list( "name" = R.name, - "amount" = R.volume, + "amount" = volume, "id" = R.id, ) return built diff --git a/code/modules/reagents/chemistry/reagent_metabolism.dm b/code/modules/reagents/chemistry/reagent_metabolism.dm new file mode 100644 index 000000000000..e831992e4293 --- /dev/null +++ b/code/modules/reagents/chemistry/reagent_metabolism.dm @@ -0,0 +1,31 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/** + * Holds metabolism state on reagents. + */ +/datum/reagent_metabolism + /// arbitrary blackboard for metabolism + /// + /// * This is separate from data because a lot of things require this and data is far more expensive. + var/list/blackboard = list() + + /// maximum amount ever put in + var/peak_dose = 0 + /// maximum amount processed so far + var/total_processed_dose = 0 + + /// cycles we've been in a mob + var/cycles_so_far = 0 + /// cycles we've been overdosing + /// + /// * This is reset if we stop overdosing, even for a single tick. + var/cycles_overdosing = 0 + + //! LEGACY LOOKUP VARIABLES !// + /// set to volume remaining + var/legacy_volume_remaining + /// set to data + var/legacy_data + /// the reagent holder we're in + var/datum/reagent_holder/legacy_current_holder diff --git a/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Core.dm b/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Core.dm index 3030bec93dd0..0c63c409a386 100644 --- a/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Core.dm +++ b/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Core.dm @@ -1,162 +1,9 @@ -/datum/reagent/blood - data = new/list("donor" = null, "viruses" = null, "species" = SPECIES_HUMAN, "blood_DNA" = null, "blood_type" = null, "blood_colour" = "#A10808", "resistances" = null, "trace_chem" = null, "antibodies" = list()) - name = "Blood" - id = "blood" - taste_description = "iron" - taste_mult = 1.3 - reagent_state = REAGENT_LIQUID - metabolism = REM * 5 - mrate_static = TRUE - affects_dead = 1 //so you can pump blood into someone before defibbing them - color = "#C80000" - var/volume_mod = 1 // So if you add different subtypes of blood, you can affect how much vessel blood each unit of reagent adds - blood_content = 4 //How effective this is for vampires. - - glass_name = "tomato juice" - glass_desc = "Are you sure this is tomato juice?" - -/datum/reagent/blood/initialize_data(newdata) - ..() - if(data && data["blood_colour"]) - color = data["blood_colour"] - return - -/datum/reagent/blood/get_data() // Just in case you have a reagent that handles data differently. - var/t = data.Copy() - if(t["virus2"]) - var/list/v = t["virus2"] - t["virus2"] = v.Copy() - return t - -/datum/reagent/blood/touch_turf(turf/simulated/T) - if(!istype(T) || volume < 3) - return - if(!data["donor"] || istype(data["donor"], /mob/living/carbon/human)) - blood_splatter(T, src, 1) - else if(istype(data["donor"], /mob/living/carbon/alien)) - var/obj/effect/debris/cleanable/blood/B = blood_splatter(T, src, 1) - if(B) - B.blood_DNA["UNKNOWN DNA STRUCTURE"] = "X*" - -/datum/reagent/blood/affect_ingest(mob/living/carbon/M, alien, removed) - - var/effective_dose = dose - if(issmall(M)) - effective_dose *= 2 - - var/nutritionvalue = 10 //for reference, normal nutrition has a value of about 30. - var/is_vampire = M.species.is_vampire - switch(alien) //unique interactions sorted from the species who benefit the least to the species who benefit the most. - if(IS_SKRELL) //arguing that blood is "meat" and is still toxic for the vegan skrell at least - if(effective_dose > 5) - if(!is_vampire) //a vetalan skrell sounds funny as hell - M.adjustToxLoss(removed) - if(effective_dose > 15) - if(!is_vampire) - M.adjustToxLoss(removed) - if(IS_SLIME) - nutritionvalue = 20 - if(data["species"] == M.species.name) //just 'inject' the blood if it happens to be promethean "blood". - M.inject_blood(src, volume * volume_mod) - remove_self(volume) - return - if(IS_TESHARI) //birb. - nutritionvalue = 30 - if(IS_UNATHI) //carnivorous lizord... - nutritionvalue = 45 - if(IS_ALRAUNE) //lorewise, alraune are meant to enjoy blood. - nutritionvalue = 60 - if(IS_CHIMERA) //obligate carnivores. - nutritionvalue = 80 - - if(is_vampire) - handle_vampire(M, alien, removed, is_vampire) - M.heal_organ_damage(0.7 * removed * volume_mod, 0) // Heals vampires more. - M.adjust_hydration(7 * removed) // Hydrates vetalan better. - M.add_chemical_effect(CE_BLOODRESTORE, 8 * removed) // Same rating as taking iron - else - M.adjust_nutrition(nutritionvalue * removed * volume_mod) - M.heal_organ_damage(0.2 * removed * volume_mod, 0) // Heal brute slightly like normal nutrition. More 'effective' blood means more usable material. - M.adjust_hydration(2 * removed) // Still has some water in the form of plasma. Hydrates less than a normal drink. - M.add_chemical_effect(CE_BLOODRESTORE, 4 * removed) //same rating as eating nutriment - - if(data && data["virus2"]) - var/list/vlist = data["virus2"] - if(vlist.len) - for(var/ID in vlist) - var/datum/disease2/disease/V = vlist[ID] - if(V.spreadtype == "Contact") - infect_virus2(M, V.getcopy()) - -/datum/reagent/blood/affect_touch(mob/living/carbon/M, alien, removed) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.isSynthetic()) - return - if(alien == IS_SLIME) - affect_ingest(M, alien, removed) - return - if(data && data["virus2"]) - var/list/vlist = data["virus2"] - if(vlist.len) - for(var/ID in vlist) - var/datum/disease2/disease/V = vlist[ID] - if(V.spreadtype == "Contact") - infect_virus2(M, V.getcopy()) - if(data && data["antibodies"]) - M.antibodies |= data["antibodies"] - -/datum/reagent/blood/affect_blood(mob/living/carbon/M, alien, removed) - if(alien == IS_SLIME) //They don't have blood, so it seems weird that they would instantly 'process' the chemical like another species does. - affect_ingest(M, alien, removed) - return - - if(M.isSynthetic()) - return - - if(ishuman(M)) - var/mob/living/carbon/human/H = M - - var/datum/reagent/blood/recipient = H.get_blood(H.vessel) - - if(recipient && blood_incompatible(data["blood_type"], recipient.data["blood_type"], data["species"], recipient.data["species"])) - H.inject_blood(src, removed * volume_mod) - - if(!H.isSynthetic() && data["species"] == "synthetic") // Remember not to inject oil into your veins, it's bad for you. - H.reagents.add_reagent("toxin", removed * 1.5) - - return - - M.inject_blood(src, volume * volume_mod) - remove_self(volume) - -/datum/reagent/blood/synthblood - name = "Synthetic blood" - id = "synthblood" - color = "#999966" - volume_mod = 2 - -/datum/reagent/blood/synthblood/initialize_data(newdata) - ..() - if(data && !data["blood_type"]) - data["blood_type"] = "O-" - return - -/datum/reagent/blood/bludbloodlight - name = "Synthetic blood" - id = "bludbloodlight" - color = "#999966" - volume_mod = 2 - -/datum/reagent/blood/bludbloodlight/initialize_data(newdata) - ..() - if(data && !data["blood_type"]) - data["blood_type"] = "AB+" - return - -// pure concentrated antibodies +/** + * * Data: list of raw antibodies as per definition in virus system + * * Data: basically, i don't know what it is and i don't care, and neither does the reagent + */ /datum/reagent/antibodies - data = list("antibodies"=list()) + holds_data = TRUE name = "Antibodies" taste_description = "slime" id = "antibodies" @@ -164,86 +11,26 @@ color = "#0050F0" mrate_static = TRUE -/datum/reagent/antibodies/affect_blood(mob/living/carbon/M, alien, removed) - if(src.data) - M.antibodies |= src.data["antibodies"] - ..() - -/// How much heat is removed when applied to a hot turf, in J/unit (19000 makes 120 u of water roughly equivalent to 4L) -#define WATER_LATENT_HEAT 19000 -/datum/reagent/water - name = "Water" - id = "water" - taste_description = "water" - description = "A ubiquitous chemical substance that is composed of hydrogen and oxygen." - reagent_state = REAGENT_LIQUID - color = "#0064C877" - metabolism = REM * 10 - - glass_name = "water" - glass_desc = "The father of all refreshments." - - cup_name = "water" - cup_desc = "The father of all refreshments." - -/datum/reagent/water/touch_turf(turf/simulated/T) - if(!istype(T)) - return +/datum/reagent/antibodies/make_copy_data_initializer(data) + return data - var/datum/gas_mixture/environment = T.return_air() - var/min_temperature = T0C + 100 // 100C, the boiling point of water +/datum/reagent/antibodies/preprocess_data(data_initializer) + return data_initializer - var/hotspot = (locate(/atom/movable/fire) in T) - if(hotspot && !istype(T, /turf/space)) - var/datum/gas_mixture/lowertemp = T.remove_cell_volume() - lowertemp.temperature = max(min(lowertemp.temperature-2000, lowertemp.temperature / 2), 0) - lowertemp.react() - T.assume_air(lowertemp) - qdel(hotspot) - - if (environment && environment.temperature > min_temperature) // Abstracted as steam or something - var/removed_heat = between(0, volume * WATER_LATENT_HEAT, -environment.get_thermal_energy_change(min_temperature)) - environment.adjust_thermal_energy(-removed_heat) - if (prob(5)) - T.visible_message("The water sizzles as it lands on \the [T]!") - - else if(volume >= 10) - T.wet_floor(1) - -/datum/reagent/water/touch_obj(obj/O, amount) - if(istype(O, /obj/item/reagent_containers/food/snacks/monkeycube)) - var/obj/item/reagent_containers/food/snacks/monkeycube/cube = O - if(!cube.wrapped) - cube.Expand() +/datum/reagent/antibodies/mix_data(list/old_data, old_volume, list/new_data, new_volume, datum/reagent_holder/holder) + if(old_data) + if(new_data) + return old_data | new_data + return old_data + else if(new_data) + // new data is not mutable, so copy it for an owned reference + return new_data.Copy() else - O.water_act(amount / 5) - var/effective = amount || 10 - O.clean_radiation(RAD_CONTAMINATION_CLEANSE_POWER * (effective / 10), RAD_CONTAMINATION_CLEANSE_FACTOR ** (1 / (effective / 10))) - -/datum/reagent/water/touch_mob(mob/living/L, amount) - if(istype(L)) - // First, kill slimes. - if(istype(L, /mob/living/simple_mob/slime)) - var/mob/living/simple_mob/slime/S = L - var/amt = 15 * amount * (1-S.water_resist) - if(amt>0) - S.adjustToxLoss(amt) - S.visible_message("[S]'s flesh sizzles where the water touches it!", "Your flesh burns in the water!") - - // Then extinguish people on fire. - var/needed = L.fire_stacks * 5 - if(amount > needed) - L.ExtinguishMob() - L.adjust_fire_stacks(-(amount / 5)) - remove_self(needed) - var/effective = amount || 10 - L.clean_radiation(RAD_CONTAMINATION_CLEANSE_POWER * (effective / 10), RAD_CONTAMINATION_CLEANSE_FACTOR ** (1 / (effective / 10))) + return list() -/datum/reagent/water/affect_ingest(mob/living/carbon/M, alien, removed) - //if(alien == IS_SLIME) - // M.adjustToxLoss(6 * removed) - //else - M.adjust_hydration(removed * 10) +/datum/reagent/antibodies/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + if(metabolism.legacy_data) + M.antibodies |= metabolism.legacy_data ..() /datum/reagent/fuel @@ -257,15 +44,19 @@ glass_name = "welder fuel" glass_desc = "Unless you are an industrial tool, this is probably not safe for consumption." -/datum/reagent/fuel/touch_turf(turf/T, amount) - new /obj/effect/debris/cleanable/liquid_fuel(T, amount, FALSE) - remove_self(amount) - return +/datum/reagent/fuel/on_touch_turf(turf/target, remaining, allocated, data) + // todo: pseudofludi system + new /obj/effect/debris/cleanable/liquid_fuel(target, allocated, FALSE) + return allocated -/datum/reagent/fuel/affect_blood(mob/living/carbon/M, alien, removed) - if(issmall(M)) removed *= 2 +/datum/reagent/fuel/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + if(issmall(M)) + removed *= 2 M.adjustToxLoss(4 * removed) -/datum/reagent/fuel/touch_mob(mob/living/L, amount) - if(istype(L)) - L.adjust_fire_stacks(amount / 10) // Splashing people with welding fuel to make them easy to ignite! +/datum/reagent/fuel/on_touch_mob(mob/target, remaining, allocated, data, zone) + if(isliving(target)) + // todo: rework and actually use some + var/mob/living/living_target = target + living_target.adjust_fire_stacks(allocated / 10) + return ..() diff --git a/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Dispenser.dm b/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Dispenser.dm index f65c970acf9b..d0b2022f262a 100644 --- a/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Dispenser.dm +++ b/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Dispenser.dm @@ -1,250 +1,3 @@ -#define ETHANOL_MET_DIVISOR 20 - -/datum/reagent/ethanol - name = "Ethanol" //Parent class for all alcoholic reagents. - id = "ethanol" - description = "A well-known alcohol with a variety of applications." - taste_description = "pure alcohol" - reagent_state = REAGENT_LIQUID - color = "#404030" - - metabolism = REM/ETHANOL_MET_DIVISOR - - ingest_met = REM * 5 - - var/nutriment_factor = 0 - var/hydration_factor = 0 - var/proof = 200 - var/toxicity = 1 - - var/druggy = 0 - var/adj_temp = 0 - var/targ_temp = 310 - var/halluci = 0 - - data=0 - - glass_name = "ethanol" - glass_desc = "A well-known alcohol with a variety of applications." - -/datum/reagent/ethanol/touch_mob(mob/living/L, amount) - if(istype(L)) - L.adjust_fire_stacks(amount / 15) - -#define ABV (proof/200) - -/datum/reagent/ethanol/affect_blood(mob/living/carbon/M, alien, removed) //This used to do just toxin. That's boring. Let's make this FUN. - var/strength_mod = 1 //Alcohol is 3x stronger when injected into the veins. - if(alien == IS_SKRELL) - strength_mod *= 5 - if(alien == IS_TAJARA) - strength_mod *= 1.25 - if(alien == IS_UNATHI) - strength_mod *= 0.75 - if(alien == IS_DIONA) - strength_mod = 0 - if(alien == IS_SLIME) - strength_mod *= 2 - if(alien == IS_ALRAUNE) - if(prob(5)) - to_chat(M, "You feel your leaves start to wilt.") - strength_mod *=5 //cit change - alcohol ain't good for plants - - var/effective_dose = volume * strength_mod * ABV * min(1,dose*(ETHANOL_MET_DIVISOR/10)) // give it 50 ticks to ramp up - M.add_chemical_effect(CE_ALCOHOL, 1) - if(HAS_TRAIT(M, TRAIT_ALCOHOL_INTOLERANT)) - if(proof > 0) - var/intolerant_dose = strength_mod*removed*ABV*10 - if(prob((intolerant_dose))) - M.add_chemical_effect(CE_ALCOHOL_TOXIC, 1) - M.adjustToxLoss(intolerant_dose) - return 0 - #define DOSE_LEVEL 6 - var/effect_level=round(effective_dose/DOSE_LEVEL) - if(effect_level != data) - var/lowering=(data>effect_level) - data=effect_level - if(lowering) - switch(effect_level) - if(0) - to_chat(M,SPAN_NOTICE("You no longer feel under the influence.")) - if(1) - to_chat(M,SPAN_DANGER("You are no longer slurring your words as much.")) - if(2) - to_chat(M,SPAN_DANGER("You're not seeing double anymore.")) - if(3) - to_chat(M,SPAN_DANGER("You can walk straight again.")) - if(4) - to_chat(M,SPAN_DANGER("You no longer feel like you're going to puke.")) - if(5) - to_chat(M,SPAN_DANGER("You don't feel like you're going to pass out anymore.")) - if(6) - to_chat(M,SPAN_DANGER("You feel like you're out of the danger zone.")) - else - var/hydration_str="" - if(M.hydration<250) - hydration_str=" You're feeling a little dehydrated, too." - switch(effect_level) - if(1) - to_chat(M,SPAN_DANGER("You're starting to feel a little tipsy.[hydration_str]")) - M.dizziness=max(M.dizziness,150) - if(2) - to_chat(M,SPAN_DANGER("You're getting drunk.[hydration_str] Use the Feign Impairment verb if you want slurring.")) - if(3) - to_chat(M,SPAN_DANGER("You're seeing double![hydration_str]")) - M.eye_blurry=max(M.eye_blurry,30) - if(4) - to_chat(M,SPAN_DANGER("You can barely walk straight![hydration_str]")) - if(5) - to_chat(M,SPAN_USERDANGER("You feel like you might puke...[hydration_str]")) - if(6) - to_chat(M,SPAN_USERDANGER("Your eyelids feel heavy![hydration_str]")) - if(7) - to_chat(M,SPAN_USERDANGER("You are getting dangerously drunk![hydration_str]")) - var/hydration_removal=(clamp((M.hydration-150)/300,0,1)*effect_level) + max(0,(M.hydration-450)/300) - if(hydration_removal>0) - M.adjust_hydration(-hydration_removal) - volume-=removed*hydration_removal*3 - if(effect_level>=4 && prob(effect_level-2)) - M.Confuse(60) - if(effect_level>=5 && prob(effect_level-4) && !M.lastpuke) - M.vomit(1,0) - if(M.nutrition>=100) - volume-=DOSE_LEVEL/4 - if(effect_level>=6 && prob(effect_level-5)) - M.drowsyness=max(M.drowsyness,60) - if(effect_level>=7) - M.add_chemical_effect(CE_ALCOHOL_TOXIC, toxicity*strength_mod) - if(volume>DOSE_LEVEL*7) - volume-=REM // liver working overtime, or whatever (mostly to prevent people from always just dying from this) - #undef DOSE_LEVEL - return - -/datum/reagent/ethanol/affect_ingest(mob/living/carbon/M, alien, removed) - if(issmall(M)) removed *= 2 - M.adjust_nutrition(nutriment_factor * removed) - M.adjust_hydration(hydration_factor * removed) - M.bloodstr.add_reagent("ethanol", removed * ABV) - if(druggy != 0) - M.druggy = max(M.druggy, druggy) - - if(adj_temp > 0 && M.bodytemperature < targ_temp) // 310 is the normal bodytemp. 310.055 - M.bodytemperature = min(targ_temp, M.bodytemperature + (adj_temp * TEMPERATURE_DAMAGE_COEFFICIENT)) - if(adj_temp < 0 && M.bodytemperature > targ_temp) - M.bodytemperature = min(targ_temp, M.bodytemperature - (adj_temp * TEMPERATURE_DAMAGE_COEFFICIENT)) - - if(halluci) - M.setHallucination(max(M.hallucination, halluci)) - return - -/datum/reagent/ethanol/touch_obj(obj/O) - if(istype(O, /obj/item/paper)) - var/obj/item/paper/paperaffected = O - paperaffected.clearpaper() - to_chat(usr, "The solution dissolves the ink on the paper.") - return - if(istype(O, /obj/item/book)) - if(volume < 5) - return - if(istype(O, /obj/item/book/tome)) - to_chat(usr, "The solution does nothing. Whatever this is, it isn't normal ink.") - return - var/obj/item/book/affectedbook = O - affectedbook.dat = null - to_chat(usr, "The solution dissolves the ink on the book.") - return - -#undef ABV - -/datum/reagent/acid - name = "Sulphuric acid" - id = "sacid" - description = "A very corrosive mineral acid with the molecular formula H2SO4." - taste_description = "acid" - reagent_state = REAGENT_LIQUID - color = "#DB5008" - metabolism = REM * 2 - touch_met = 50 // It's acid! - var/power = 5 - var/meltdose = 10 // How much is needed to melt - -/datum/reagent/acid/affect_blood(mob/living/carbon/M, alien, removed) - if(issmall(M)) removed *= 2 - M.take_random_targeted_damage(brute = 0, brute = removed * power * 2) - -/datum/reagent/acid/affect_touch(mob/living/carbon/M, alien, removed) // This is the most interesting - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.head) - if(H.head.integrity_flags & INTEGRITY_ACIDPROOF) - to_chat(H, "Your [H.head] protects you from the acid.") - remove_self(volume) - return - else if(removed > meltdose) - to_chat(H, "Your [H.head] melts away!") - qdel(H.head) - H.update_inv_head(1) - H.update_hair(1) - removed -= meltdose - if(removed <= 0) - return - - if(H.wear_mask) - if(H.wear_mask.integrity_flags & INTEGRITY_ACIDPROOF) - to_chat(H, "Your [H.wear_mask] protects you from the acid.") - remove_self(volume) - return - else if(removed > meltdose) - to_chat(H, "Your [H.wear_mask] melts away!") - qdel(H.wear_mask) - H.update_inv_wear_mask(1) - H.update_hair(1) - removed -= meltdose - if(removed <= 0) - return - - if(H.glasses) - if(H.glasses.integrity_flags & INTEGRITY_ACIDPROOF) - to_chat(H, "Your [H.glasses] partially protect you from the acid!") - removed /= 2 - else if(removed > meltdose) - to_chat(H, "Your [H.glasses] melt away!") - qdel(H.glasses) - H.update_inv_glasses(1) - removed -= meltdose / 2 - if(removed <= 0) - return - - if(volume < meltdose) // Not enough to melt anything - M.take_random_targeted_damage(brute = 0, brute = removed * power * 0.2) //burn damage, since it causes chemical burns. Acid doesn't make bones shatter, like brute trauma would. - return - if(!M.unacidable && removed > 0) - if(istype(M, /mob/living/carbon/human) && volume >= meltdose) - var/mob/living/carbon/human/H = M - var/obj/item/organ/external/affecting = H.get_organ(BP_HEAD) - if(affecting) - affecting.inflict_bodypart_damage( - burn = removed * power * 0.1, - ) - if(prob(100 * removed / meltdose)) // Applies disfigurement - if (affecting.organ_can_feel_pain()) - H.emote("scream") - else - M.take_random_targeted_damage(brute = 0, brute = removed * power * 0.1) // Balance. The damage is instant, so it's weaker. 10 units -> 5 damage, double for pacid. 120 units beaker could deal 60, but a) it's burn, which is not as dangerous, b) it's a one-use weapon, c) missing with it will splash it over the ground and d) clothes give some protection, so not everything will hit - -/datum/reagent/acid/touch_obj(obj/O) - if(O.integrity_flags & INTEGRITY_INDESTRUCTIBLE) - return - // todo: newacid - if((istype(O, /obj/item) || istype(O, /obj/effect/plant)) && (volume > meltdose)) - var/obj/effect/debris/cleanable/molten_item/I = new/obj/effect/debris/cleanable/molten_item(O.loc) - I.desc = "Looks like this was \an [O] some time ago." - for(var/mob/M in viewers(5, O)) - to_chat(M, "\The [O] melts.") - qdel(O) - remove_self(meltdose) // 10 units of acid will not melt EVERYTHING on the tile - - /datum/reagent/sugar name = "Sugar" id = "sugar" @@ -258,16 +11,16 @@ glass_desc = "The organic compound commonly known as table sugar and sometimes called saccharose. This white, odorless, crystalline powder has a pleasing, sweet taste." glass_icon = DRINK_ICON_NOISY -/datum/reagent/sugar/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/sugar/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.nutrition += removed * 3 - var/effective_dose = dose + var/effective_dose = metabolism.total_processed_dose if(issmall(M)) effective_dose *= 2 if(alien == IS_UNATHI) if(effective_dose < 2) - if(effective_dose == metabolism * 2 || prob(5)) + if(effective_dose == metabolism_rate * 2 || prob(5)) M.emote("yawn") else if(effective_dose < 5) M.eye_blurry = max(M.eye_blurry, 10) diff --git a/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Food-Drinks.dm b/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Food-Drinks.dm index 56c37118c323..5b5cd9b342a5 100644 --- a/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Food-Drinks.dm +++ b/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Food-Drinks.dm @@ -1,64 +1,5 @@ /* Food */ -/datum/reagent/nutriment - name = "Nutriment" - id = "nutriment" - description = "All the vitamins, minerals, and carbohydrates the body needs in pure form." - taste_mult = 4 - reagent_state = REAGENT_SOLID - metabolism = REM * 4 - ingest_met = REM * 4 - var/nutriment_factor = 30 // Per unit - var/hydration_factor = 0 //Per unit - var/injectable = 0 - color = "#664330" - -// todo: review data procs - -/datum/reagent/nutriment/mix_data(datum/reagent_holder/holder, list/current_data, current_amount, list/new_data, new_amount) - - if(!islist(new_data) || !length(new_data)) - return - - LAZYINITLIST(data) - - //add the new taste data - for(var/taste in new_data) - if(taste in data) - data[taste] += new_data[taste] - else - data[taste] = new_data[taste] - - //cull all tastes below 10% of total - var/totalFlavor = 0 - for(var/taste in data) - totalFlavor += data[taste] - if(totalFlavor) //Let's not divide by zero for things w/o taste - for(var/taste in data) - if(data[taste]/totalFlavor < 0.1) - data -= taste - -/datum/reagent/nutriment/affect_blood(mob/living/carbon/M, alien, removed) - if(!injectable && alien != IS_SLIME && alien != IS_CHIMERA) - M.adjustToxLoss(0.1 * removed) - return - affect_ingest(M, alien, removed) - -/datum/reagent/nutriment/affect_ingest(mob/living/carbon/M, alien, removed) - switch(alien) - if(IS_DIONA) - return - if(IS_UNATHI) - removed *= 0.5 - if(IS_CHIMERA) - removed *= 0.25 - if(issmall(M)) - removed *= 2 // Small bodymass, more effect from lower volume. - M.heal_organ_damage(0.5 * removed, 0) - if(!M.species.is_vampire) // If this is set to 0, they don't get nutrition from food. - M.nutrition += nutriment_factor * removed // For hunger and fatness - M.adjust_hydration(hydration_factor * removed) - M.add_chemical_effect(CE_BLOODRESTORE, 4 * removed) /datum/reagent/nutriment/glucose name = "Glucose" @@ -74,7 +15,7 @@ taste_description = "some sort of meat" color = "#440000" -/datum/reagent/nutriment/protein/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/nutriment/protein/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) switch(alien) if(IS_SKRELL) M.adjustToxLoss(0.5 * removed) @@ -87,7 +28,7 @@ else ..() -/datum/reagent/nutriment/protein/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/nutriment/protein/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien && alien == IS_SKRELL) M.adjustToxLoss(2 * removed) return @@ -113,16 +54,14 @@ nutriment_factor = 10 color = "#FFFF00" -/datum/reagent/nutriment/honey/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/nutriment/honey/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() - var/effective_dose = dose - if(issmall(M)) - effective_dose *= 2 + var/effective_dose = metabolism.total_processed_dose if(alien == IS_UNATHI) if(effective_dose < 2) - if(effective_dose == metabolism * 2 || prob(5)) + if(effective_dose == metabolism_rate * 2 || prob(5)) M.emote("yawn") else if(effective_dose < 5) M.eye_blurry = max(M.eye_blurry, 10) @@ -274,20 +213,12 @@ nutriment_factor = 15 color = "#4F3500" -/datum/reagent/nutriment/peanutoil/touch_turf(turf/simulated/T) - if(!istype(T)) - return - - var/hotspot = (locate(/atom/movable/fire) in T) - if(hotspot && !istype(T, /turf/space)) - var/datum/gas_mixture/lowertemp = T.remove_cell_volume() - lowertemp.temperature = max(min(lowertemp.temperature-2000, lowertemp.temperature / 2), 0) - lowertemp.react() - T.assume_air(lowertemp) - qdel(hotspot) - - if(volume >= 5) - T.wet_floor() +// todo: reagent effects +/datum/reagent/nutriment/peanutoil/apply_to_turf(turf/target, remaining, allocated, data) + if(allocate >= 5) + target.wet_floor() + return 5 + return 0 /datum/reagent/nutriment/peanutbutter name = "Peanut Butter" @@ -319,20 +250,19 @@ glass_name = "durian paste" glass_desc = "Durian paste. It smells horrific." -/datum/reagent/nutriment/durian/touch_mob(mob/M, amount) - if(iscarbon(M) && !M.isSynthetic()) +/datum/reagent/nutriment/durian/on_touch_carbon(mob/living/carbon/target, remaining, allocated, data, zone, obj/item/organ/external/limb) + if(!target.isSynthetic()) var/message = pick("Oh god, it smells disgusting here.", "What is that stench?", "That's an awful odor.") - to_chat(M,"[message]") - if(prob(clamp(amount, 5, 90))) - var/mob/living/L = M - L.vomit() + to_chat(target, "[message]") + if(prob(clamp(allocated, 5, 90))) + target.vomit() return ..() -/datum/reagent/nutriment/durian/touch_turf(turf/T, amount) - if(istype(T)) - var/obj/effect/debris/cleanable/chemcoating/C = new /obj/effect/debris/cleanable/chemcoating(T) - C.reagents.add_reagent(id, amount) - return ..() +/datum/reagent/nutriment/durian/on_touch_turf(turf/target, remaining, allocated, data) + var/obj/effect/debris/cleanable/chemcoating/C = new /obj/effect/debris/cleanable/chemcoating(target) + var/amount_used = C.reagents.add_reagent(id, allocated) + allocated -= amount_used + return ..() + amount_used /datum/reagent/nutriment/virus_food name = "Virus Food" @@ -387,7 +317,7 @@ color = "#BBEDA4" overdose = REAGENTS_OVERDOSE -/datum/reagent/lipozine/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/lipozine/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.nutrition = max(M.nutrition - 10 * removed, 0) M.overeatduration = 0 if(M.nutrition < 0) @@ -405,15 +335,15 @@ overdose = REAGENTS_OVERDOSE ingest_met = REM -/datum/reagent/sodiumchloride/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/sodiumchloride/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_SLIME) M.adjustFireLoss(removed) -/datum/reagent/sodiumchloride/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/sodiumchloride/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/pass_mod = rand(3,5) var/passthrough = (removed - (removed/pass_mod)) //Some may be nullified during consumption, between one third and one fifth. - affect_blood(M, alien, passthrough) + legacy_affect_blood(M, alien, passthrough, metabolism) /datum/reagent/blackpepper name = "Black Pepper" @@ -444,13 +374,13 @@ ingest_met = REM color = "#B31008" -/datum/reagent/frostoil/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/frostoil/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return M.bodytemperature = max(M.bodytemperature - 10 * TEMPERATURE_DAMAGE_COEFFICIENT, 215) if(prob(1)) M.emote("shiver") - holder.remove_reagent("capsaicin", 5) + metabolism.legacy_current_holder.remove_reagent(/datum/reagent/capsaicin, 5) /datum/reagent/frostoil/cryotoxin //A longer lasting version of frost oil. name = "Cryotoxin" @@ -458,7 +388,7 @@ description = "Lowers the body's internal temperature." reagent_state = REAGENT_LIQUID color = "#B31008" - metabolism = REM * 0.5 + metabolism_rate = REM * 0.5 /datum/reagent/capsaicin name = "Capsaicin Oil" @@ -470,12 +400,12 @@ ingest_met = REM color = "#B31008" -/datum/reagent/capsaicin/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/capsaicin/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return M.adjustToxLoss(0.5 * removed) -/datum/reagent/capsaicin/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/capsaicin/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return if(alien == IS_NARAMADI) @@ -490,13 +420,13 @@ if(!H.can_feel_pain()) return - if(dose < 5 && (dose == metabolism || prob(5))) + if(metabolism.total_processed_dose < 5 && (metabolism.cycles_so_far == 1 || prob(5))) to_chat(M, "Your insides feel uncomfortably hot!") - if(dose >= 5) + if(metabolism.total_processed_dose >= 5) M.apply_effect(2, AGONY, 0) if(prob(5)) M.visible_message("[M] [pick("dry heaves!","coughs!","splutters!")]", "You feel like your insides are burning!") - holder.remove_reagent("frostoil", 5) + metabolism.legacy_current_holder.remove_reagent(/datum/reagent/frostoil, 5) /datum/reagent/hexaisin name = "Hexaisin" @@ -508,7 +438,7 @@ ingest_met = REM color = "#B31008" -/datum/reagent/hexaisin/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/hexaisin/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_UNATHI) return if(alien == IS_NARAMADI) @@ -517,13 +447,13 @@ var/mob/living/carbon/human/H = M if(!H.can_feel_pain()) return - if(dose == metabolism) + if(metabolism.cycles_so_far == 1) to_chat(M, "You feel like your insides are burning!") else M.apply_effect(3, AGONY, 0) if(prob(5)) M.visible_message("[M] [pick("dry heaves!","coughs!","splutters!")]", "You feel like your insides are burning!") - holder.remove_reagent("frostoil", 5) + metabolism.legacy_current_holder.remove_reagent(/datum/reagent/frostoil, 5) /datum/reagent/condensedcapsaicin name = "Condensed Capsaicin" @@ -536,12 +466,12 @@ ingest_met = REM color = "#B31008" -/datum/reagent/condensedcapsaicin/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/condensedcapsaicin/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return M.adjustToxLoss(0.5 * removed) -/datum/reagent/condensedcapsaicin/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/condensedcapsaicin/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/eyes_covered = 0 var/mouth_covered = 0 @@ -662,7 +592,7 @@ to_chat(M, "The exposed flesh on your feet burns!") M.apply_effect(effective_strength / 2, AGONY, 0) -/datum/reagent/condensedcapsaicin/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/condensedcapsaicin/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_NARAMADI) //Moghes species with exception of Zaddat (for obvious reasons) are immune to taste and ingested effects of Capsaisin and Condensed variants. return if(alien == IS_UNATHI) //If you want to know why, look at Hexaisin. They are still affected by pepperspray, but not drinking it. @@ -671,13 +601,13 @@ var/mob/living/carbon/human/H = M if(!H.can_feel_pain()) return - if(dose == metabolism) + if(metabolism.cycles_so_far == 1) to_chat(M, "You feel like your insides are burning!") else M.apply_effect(4, AGONY, 0) if(prob(5)) M.visible_message("[M] [pick("dry heaves!","coughs!","splutters!")]", "You feel like your insides are burning!") - holder.remove_reagent("frostoil", 5) + metabolism.legacy_current_holder.remove_reagent(/datum/reagent/frostoil, 5) /* Drinks */ @@ -696,14 +626,14 @@ var/adj_temp = 0 var/water_based = TRUE -/datum/reagent/drink/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/strength_mod = 1 if(alien == IS_SLIME && water_based) strength_mod = 3 M.adjustToxLoss(removed * strength_mod) // Probably not a good idea; not very deadly though return -/datum/reagent/drink/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.adjust_nutrition(nutrition * removed) M.adjust_hydration(hydration * removed) M.dizziness = max(0, M.dizziness + adj_dizzy) @@ -718,7 +648,7 @@ if(is_vampire) handle_vampire(M, alien, removed, is_vampire) -/datum/reagent/drink/overdose(mob/living/carbon/M, alien) //Add special interactions here in the future if desired. +/datum/reagent/drink/legacy_affect_overdose(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() // Juices @@ -763,7 +693,7 @@ glass_name = "Carrot Juice" glass_desc = "It is just like a carrot but without crunching." -/datum/reagent/drink/juice/carrot/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/juice/carrot/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() M.reagents.add_reagent("imidazoline", removed * 0.2) @@ -779,16 +709,14 @@ glass_name = "Grape Juice" glass_desc = "It's grrrrrape!" -/datum/reagent/drink/juice/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/juice/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() - var/effective_dose = dose/2 - if(issmall(M)) - effective_dose *= 2 + var/effective_dose = metabolism.total_processed_dose if(alien == IS_UNATHI) if(effective_dose < 2) - if(effective_dose == metabolism * 2 || prob(5)) + if(effective_dose == metabolism_rate * 2 || prob(5)) M.emote("yawn") else if(effective_dose < 5) M.eye_blurry = max(M.eye_blurry, 10) @@ -833,7 +761,7 @@ glass_name = "Lime Juice" glass_desc = "A glass of sweet-sour lime juice" -/datum/reagent/drink/juice/lime/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/juice/lime/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_DIONA) return @@ -849,7 +777,7 @@ glass_name = "orange juice" glass_desc = "Vitamins! Yay!" -/datum/reagent/drink/juice/orange/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/juice/orange/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_DIONA) return @@ -888,7 +816,7 @@ glass_name = "Tomato Juice" glass_desc = "Are you sure this is tomato juice?" -/datum/reagent/drink/juice/tomato/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/juice/tomato/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_DIONA) return @@ -946,19 +874,19 @@ glass_name = "Chocolate Milk" glass_desc = "Deliciously fattening!" -/datum/reagent/drink/milk/chocolate/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/milk/chocolate/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_ALRAUNE) //cit change: choccy is full of natural easily digestible plant fats M.nutrition += removed * 5 -/datum/reagent/drink/milk/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/milk/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_DIONA) return if(alien == IS_ALRAUNE) //cit change: milk good for plant. M.nutrition += removed * 3 M.heal_organ_damage(0.5 * removed, 0) - holder.remove_reagent("capsaicin", 10 * removed) + metabolism.legacy_current_holder.remove_reagent(/datum/reagent/capsaicin, 10 * removed) if(contains_lactose == TRUE && alien == IS_NARAMADI) //Species-wide lactose intolerance, also funny that cheeses can't drink milk. if(prob(5)) to_chat(M, SPAN_WARNING("You feel nauseous!")) @@ -1031,7 +959,7 @@ cup_name = "Cup of Tea" cup_desc = "Tasty black tea, it has antioxidants, it's good for you!" -/datum/reagent/drink/tea/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/tea/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_DIONA) return @@ -1053,7 +981,7 @@ cup_name = "Cup of Iced Tea" cup_desc = "No relation to a certain rap artist/ actor." -/datum/reagent/drink/tea/icetea/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/tea/icetea/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_SLIME) if(M.bodytemperature > T0C) @@ -1061,7 +989,7 @@ if(M.bodytemperature < T0C) M.bodytemperature += 0.5 -/datum/reagent/drink/tea/icetea/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/tea/icetea/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_SLIME) if(M.bodytemperature > T0C) @@ -1153,7 +1081,7 @@ cup_name = "Cup of Milk Tea" cup_desc = "Sweet iced tea cut with milk." -/datum/reagent/drink/tea/icetea/milktea/affect_ingest(mob/living/carbon/M, alien, removed) //Milk tea and its variants inherit the properties of both iced tea and milk. +/datum/reagent/drink/tea/icetea/milktea/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) //Milk tea and its variants inherit the properties of both iced tea and milk. ..() if(alien == IS_DIONA) return @@ -1269,17 +1197,17 @@ glass_desc = "Don't drop it, or you'll send scalding liquid and glass shards everywhere." -/datum/reagent/drink/coffee/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/coffee/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return ..() if(adj_temp > 0) - holder.remove_reagent("frostoil", 10 * removed) + metabolism.legacy_current_holder.remove_reagent(/datum/reagent/frostoil, 10 * removed) -/datum/reagent/drink/coffee/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/coffee/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() -/datum/reagent/drink/coffee/overdose(mob/living/carbon/M, alien) +/datum/reagent/drink/coffee/legacy_affect_overdose(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return M.make_jittery(5) @@ -1295,7 +1223,7 @@ glass_desc = "A drink to perk you up and refresh you!" glass_special = list(DRINK_ICE) -/datum/reagent/drink/coffee/icecoffee/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/coffee/icecoffee/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_SLIME) if(M.bodytemperature > T0C) @@ -1303,7 +1231,7 @@ if(M.bodytemperature < T0C) M.bodytemperature += 0.5 -/datum/reagent/drink/coffee/icecoffee/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/coffee/icecoffee/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_SLIME) if(M.bodytemperature > T0C) @@ -1328,7 +1256,7 @@ cup_name = "Cup of Soy Latte" cup_desc = "A nice and refreshing beverage while you are reading." -/datum/reagent/drink/coffee/soy_latte/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/coffee/soy_latte/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() M.heal_organ_damage(0.5 * removed, 0) @@ -1348,7 +1276,7 @@ cup_name = "Cup of Cafe Latte" cup_desc = "A nice and refreshing beverage while you are reading." -/datum/reagent/drink/coffee/cafe_latte/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/coffee/cafe_latte/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() M.heal_organ_damage(0.5 * removed, 0) @@ -1369,7 +1297,7 @@ cup_name = "Cup of Hot Chocolate" cup_desc = "Made with love! And cocoa beans." -/datum/reagent/drink/hot_coco/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/hot_coco/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_ALRAUNE) //cit change: choccy is full of natural easily digestible plant fats M.nutrition += removed * 5 @@ -1532,16 +1460,14 @@ glass_name = "Milkshake" glass_desc = "Glorious brainfreezing mixture." -/datum/reagent/drink/milkshake/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/milkshake/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() - var/effective_dose = dose/2 - if(issmall(M)) - effective_dose *= 2 + var/effective_dose = metabolism.total_processed_dose / 2 if(alien == IS_UNATHI) if(effective_dose < 2) - if(effective_dose == metabolism * 2 || prob(5)) + if(effective_dose == metabolism_rate * 2 || prob(5)) M.emote("yawn") else if(effective_dose < 5) M.eye_blurry = max(M.eye_blurry, 10) @@ -1574,7 +1500,7 @@ glass_name = "Chocolate Milkshake" glass_desc = "A refreshing chocolate milkshake, just like mom used to make." -/datum/reagent/drink/milkshake/chocoshake/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/milkshake/chocoshake/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_ALRAUNE) //cit change: it wouldn't affect plants that much. M.nutrition += removed * 5 @@ -1605,7 +1531,7 @@ glass_name = "Coffee Milkshake" glass_desc = "An energizing coffee milkshake, perfect for hot days at work.." -/datum/reagent/drink/milkshake/coffeeshake/overdose(mob/living/carbon/M, alien) +/datum/reagent/drink/milkshake/coffeeshake/legacy_affect_overdose(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.make_jittery(5) /datum/reagent/drink/milkshake/peanutshake @@ -1631,7 +1557,7 @@ glass_name = "Rewriter" glass_desc = "The secret of the sanctuary of the Libarian..." -/datum/reagent/drink/rewriter/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/rewriter/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() M.make_jittery(5) @@ -1649,7 +1575,7 @@ glass_desc = "Don't cry, Don't raise your eye, It's only nuclear wasteland" glass_special = list(DRINK_FIZZ) -/datum/reagent/drink/soda/nuka_cola/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/soda/nuka_cola/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() M.add_chemical_effect(CE_SPEEDBOOST, 1) M.make_jittery(20) @@ -1922,7 +1848,7 @@ glass_name = "The Doctor's Delight" glass_desc = "A healthy mixture of juices, guaranteed to keep you healthy until the next toolboxing takes place." -/datum/reagent/drink/doctor_delight/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/doctor_delight/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_DIONA) return @@ -1972,7 +1898,7 @@ glass_name = "Hell Ramen" glass_desc = "A glass of extremely spicy noodles. Wait, why did you put this into a glass?" -/datum/reagent/drink/hell_ramen/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/hell_ramen/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_DIONA) return @@ -2003,7 +1929,7 @@ glass_desc = "Generally, you're supposed to put something else in there too..." glass_icon = DRINK_ICON_NOISY -/datum/reagent/drink/ice/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/ice/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_SLIME) if(M.bodytemperature > T0C) @@ -2011,7 +1937,7 @@ if(M.bodytemperature < T0C) M.bodytemperature += rand(1,3) -/datum/reagent/drink/ice/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/ice/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_SLIME) if(M.bodytemperature > T0C) @@ -2124,13 +2050,13 @@ glass_icon = DRINK_ICON_NOISY glass_special = list(DRINK_FIZZ) -/datum/reagent/drink/nuclearwaste/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/nuclearwaste/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_DIONA) return M.bloodstr.add_reagent("radium", 0.3) -/datum/reagent/drink/nuclearwaste/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/nuclearwaste/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_DIONA) return @@ -2150,19 +2076,19 @@ glass_icon = DRINK_ICON_NOISY glass_special = list(DRINK_FIZZ) -/datum/reagent/drink/sodaoil/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/sodaoil/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(M.bloodstr) // If, for some reason, they are injected, dilute them as well. - for(var/datum/reagent/R in M.ingested.reagent_list) + for(var/datum/reagent/R in M.ingested.get_reagent_datums()) if(istype(R, /datum/reagent/drink)) var/datum/reagent/drink/D = R if(D.water_based) M.adjustToxLoss(removed * -3) -/datum/reagent/drink/sodaoil/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/sodaoil/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(M.ingested) // Find how many drinks are causing tox, and negate them. - for(var/datum/reagent/R in M.ingested.reagent_list) + for(var/datum/reagent/R in M.ingested.get_reagent_datums()) if(istype(R, /datum/reagent/drink)) var/datum/reagent/drink/D = R if(D.water_based) @@ -2373,7 +2299,7 @@ glass_name = "Beer" glass_desc = "A freezing pint of beer" -/datum/reagent/ethanol/beer/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/ethanol/beer/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) . = ..() if(.) M.jitteriness = max(M.jitteriness - 3, 0) @@ -2418,7 +2344,7 @@ glass_name = "Rum" glass_desc = "Now you want to Pray for a pirate suit, don't you?" -/datum/reagent/ethanol/deadrum/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/ethanol/deadrum/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) . = ..() if(.) M.dizziness += 5 @@ -2455,7 +2381,7 @@ id = "coffee_alcohol" overdose = 45 -/datum/reagent/ethanol/coffee/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/ethanol/coffee/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return . = ..() // the rest is coffee stuff, ugh, go make reagent traits etc @@ -2465,7 +2391,7 @@ if(M.bodytemperature > 310) M.bodytemperature = max(310, M.bodytemperature - (5 * TEMPERATURE_DAMAGE_COEFFICIENT)) -/datum/reagent/ethanol/coffee/overdose(mob/living/carbon/M, alien) +/datum/reagent/ethanol/coffee/legacy_affect_overdose(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return M.make_jittery(5) @@ -2549,7 +2475,7 @@ glass_name = "Thirteen Loko" glass_desc = "This is a glass of Thirteen Loko, it appears to be of the highest quality. The drink, not the glass." -/datum/reagent/ethanol/thirteenloko/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/ethanol/thirteenloko/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) . = ..() if(alien == IS_DIONA) return @@ -2585,7 +2511,7 @@ glass_name = "Vodka" glass_desc = "The glass contain wodka. Xynta." -/datum/reagent/ethanol/vodka/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/ethanol/vodka/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) . = ..() M.cure_radiation(RAD_MOB_CURE_STRENGTH_VODKA(removed)) @@ -2982,7 +2908,7 @@ glass_name = "Beepsky Smash" glass_desc = "Heavy, hot and strong. Just like the Iron fist of the LAW." -/datum/reagent/ethanol/beepsky_smash/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/ethanol/beepsky_smash/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) . = ..() M.afflict_stun(20 * 2) @@ -3292,7 +3218,7 @@ glass_icon = DRINK_ICON_NOISY glass_special = list("neuroright") -/datum/reagent/ethanol/neurotoxin/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/ethanol/neurotoxin/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) . = ..() M.afflict_paralyze(20 * 3) @@ -3319,7 +3245,7 @@ glass_name = "???" glass_desc = "A black ichor with an oily purple sheer on top. Are you sure you should drink this?" -/datum/reagent/ethanol/pwine/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/ethanol/pwine/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(. > 30) M.adjustToxLoss(2 * removed) @@ -3532,7 +3458,7 @@ glass_name = "Redeemer's Brew" glass_desc = "This barely qualifies as a drink, and may cause euphoria and numbness. Imbiber beware!" -/datum/reagent/ethanol/unathiliquor/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/ethanol/unathiliquor/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_DIONA) return @@ -3552,7 +3478,7 @@ var/mob/living/carbon/human/H = M if(!H.can_feel_pain()) return - if(dose == metabolism) + if(metabolism.cycles_so_far == 1) to_chat(M, "You feel like your insides are burning!") else M.apply_effect(4, AGONY, 0) @@ -3739,7 +3665,7 @@ glass_name = "Soemmer Fire" glass_desc = "A painfully hot mixed drink, for when you absolutely need to hurt right now." -/datum/reagent/ethanol/soemmerfire/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/ethanol/soemmerfire/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_DIONA) return @@ -3789,7 +3715,7 @@ glass_name = "Vox's Delight" glass_desc = "Not recommended if you enjoy having organs." -/datum/reagent/ethanol/voxdelight/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/ethanol/voxdelight/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_DIONA) return @@ -3854,7 +3780,7 @@ glass_name = "Named Bullet" glass_desc = "A thick slime jelly shot. You can feel your death approaching." -/datum/reagent/ethanol/slimeshot/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/ethanol/slimeshot/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_DIONA) return @@ -3998,7 +3924,7 @@ glass_desc = "The glass is barely able to contain the wodka. Xynta." glass_special = list(DRINK_FIZZ) -/datum/reagent/ethanol/godka/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/ethanol/godka/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) . = ..() M.cure_radiation(RAD_MOB_CURE_STRENGTH_GODKA(removed * .)) if(. && ishuman(M)) @@ -4342,7 +4268,7 @@ glass_desc = "A drink usually enjoyed by only the highest castes of Apinae society. Incredibly sweet, it is said to have enormous health benefits." //This functions the same as Doctor's Delight, except it gets you drunk too. -/datum/reagent/ethanol/royaljelly/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/ethanol/royaljelly/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) . = ..() if(alien == IS_DIONA) return @@ -4536,81 +4462,6 @@ /////////////////////////////////////////////// //// End of list for drinks for bartenders //// /////////////////////////////////////////////// -/* - Coatings are used in cooking. Dipping food items in a reagent container with a coating in it - allows it to be covered in that, which will add a masked overlay to the sprite. - Coatings have both a raw and a cooked image. Raw coating is generally unhealthy - Generally coatings are intended for deep frying foods -*/ -/datum/reagent/nutriment/coating - name = "coating" - id = "coating" - nutriment_factor = 6 //Less dense than the food itself, but coatings still add extra calories - var/messaged = 0 - var/icon_raw - var/icon_cooked - var/coated_adj = "coated" - var/cooked_name = "coating" - -/datum/reagent/nutriment/coating/affect_ingest(mob/living/carbon/M, alien, removed) - - //We'll assume that the batter isnt going to be regurgitated and eaten by someone else. Only show this once - if (data["cooked"] != 1) - if (!messaged) - to_chat(M, "Ugh, this raw [name] tastes disgusting.") - nutriment_factor *= 0.5 - messaged = 1 - - //Raw coatings will sometimes cause vomiting - if (prob(1)) - M.vomit() - ..() - -/datum/reagent/nutriment/coating/initialize_data(newdata) // Called when the reagent is created. - ..() - if (!data) - data = list() - else - if (isnull(data["cooked"])) - data["cooked"] = 0 - return - data["cooked"] = 0 - if (holder && holder.my_atom && istype(holder.my_atom,/obj/item/reagent_containers/food/snacks)) - data["cooked"] = 1 - name = cooked_name - - //Batter which is part of objects at compiletime spawns in a cooked state - - -//Handles setting the temperature when oils are mixed -// todo: review data procs -/datum/reagent/nutriment/coating/mix_data(datum/reagent_holder/holder, list/current_data, current_amount, list/new_data, new_amount) - LAZYINITLIST(data) - data["cooked"] = new_data["cooked"] - -/datum/reagent/nutriment/coating/batter - name = "batter mix" - cooked_name = "batter" - id = "batter" - color = "#f5f4e9" - reagent_state = REAGENT_LIQUID - icon_raw = "batter_raw" - icon_cooked = "batter_cooked" - coated_adj = "battered" - -/datum/reagent/nutriment/coating/beerbatter - name = "beer batter mix" - cooked_name = "beer batter" - id = "beerbatter" - color = "#f5f4e9" - reagent_state = REAGENT_LIQUID - icon_raw = "batter_raw" - icon_cooked = "batter_cooked" - coated_adj = "beer-battered" - -/datum/reagent/nutriment/coating/beerbatter/affect_ingest(mob/living/carbon/M, alien, removed) - ..() - M.add_chemical_effect(CE_ALCOHOL, 0.02) //Very slightly alcoholic //========================= //Fats @@ -4635,40 +4486,23 @@ touch_met = 1.5 var/lastburnmessage = 0 -/datum/reagent/nutriment/triglyceride/oil/touch_turf(turf/simulated/T) - if(!istype(T)) - return - - if(volume >= 3) - T.wet_floor(2) - -// todo: review data procs -/datum/reagent/nutriment/triglyceride/oil/initialize_data(newdata) // Called when the reagent is created. - ..() - if (!data) - data = list("temperature" = T20C) - -//Handles setting the temperature when oils are mixed -/datum/reagent/nutriment/triglyceride/oil/mix_data(datum/reagent_holder/holder, list/current_data, current_amount, list/new_data, new_amount) - LAZYINITLIST(data) - if (current_amount <= 0 || !data["temperature"] || !volume) - //If we get here, then this reagent has just been created, just copy the temperature exactly - data["temperature"] = new_data["temperature"] - else - //Our temperature is set to the mean of the two mixtures, taking volume into account - var/total = (data["temperature"] * current_amount) + (new_data["temperature"] * new_amount) - data["temperature"] = total / volume +/datum/reagent/nutriment/triglyceride/oil/on_touch_turf(turf/target, remaining, allocated, data) + if(allocated >= 3) + if(istype(target, /turf/simulated)) + var/turf/simulated/simulated_target = target + simulated_target.wet_floor(2) return ..() //Calculates a scaling factor for scalding damage, based on the temperature of the oil and creature's heat resistance -/datum/reagent/nutriment/triglyceride/oil/proc/heatdamage(mob/living/carbon/M) +/datum/reagent/nutriment/triglyceride/oil/proc/heatdamage(mob/living/carbon/M, datum/reagent_holder/holder) + var/temperature = holder.temperature var/threshold = 360//Human heatdamage threshold var/datum/species/S = M.species if (S && istype(S)) threshold = S.heat_level_1 //If temperature is too low to burn, return a factor of 0. no damage - if (data["temperature"] < threshold) + if (temperature < threshold) return 0 //Step = degrees above heat level 1 for 1.0 multiplier @@ -4676,15 +4510,16 @@ if (S && istype(S)) step = (S.heat_level_2 - S.heat_level_1)*1.5 - . = data["temperature"] - threshold + . = temperature - threshold . /= step . = min(., 2.5)//Cap multiplier at 2.5 -/datum/reagent/nutriment/triglyceride/oil/affect_touch(mob/living/carbon/M, alien, removed) - var/dfactor = heatdamage(M) +/datum/reagent/nutriment/triglyceride/oil/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + var/temperature = metabolism.legacy_current_holder.temperature + var/dfactor = heatdamage(M, metabolism.legacy_current_holder) if (dfactor) M.take_random_targeted_damage(brute = 0, brute = removed * 1.5 * dfactor) - data["temperature"] -= (6 * removed) / (1 + volume*0.1)//Cools off as it burns you + temperature -= (6 * removed) / (1 + volume*0.1)//Cools off as it burns you if (lastburnmessage+100 < world.time ) to_chat(M, SPAN_DANGER("Searing hot oil burns you, wash it off quick!")) lastburnmessage = world.time @@ -4738,7 +4573,7 @@ color = "#EDB91F" taste_description = "cheese" -/datum/reagent/nutriment/protein/cheese/affect_ingest(mob/living/carbon/M, alien, removed) //Cheese is a kind of milk. +/datum/reagent/nutriment/protein/cheese/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) //Cheese is a kind of milk. if(alien == IS_NARAMADI) if(prob(5)) to_chat(M, SPAN_WARNING("You feel nauseous!")) @@ -4820,19 +4655,19 @@ taste_description = "the gross yet satisfying combination of chewing on a raw steak while downing a shot of whiskey" proof = WHISKEY/2 color = "#d3785d" - metabolism = REM * 2.5 // about right for mixing nutriment and ethanol. + metabolism_rate = REM * 2.5 // about right for mixing nutriment and ethanol. var/alt_nutriment_factor = 5 //half as much as protein since it's half protein. //using a new variable instead of nutriment_factor so we can call ..() without that adding nutrition for us without taking factors for protein into account glass_name = "Monster Tamer" glass_desc = "This looks like an alcoholic slurry of meat. Gross." -/datum/reagent/ethanol/monstertamer/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/ethanol/monstertamer/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() monster_tamer(M,alien, removed, alt_nutriment_factor) -/datum/reagent/ethanol/monstertamer/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/ethanol/monstertamer/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_SKRELL) M.adjustToxLoss(removed) //Equivalent to half as much protein, since it's half protein. @@ -4846,19 +4681,19 @@ description = "A questionably-delicious blend of a carnivore's favorite food and, it turns out, certain oligosaccharides common to certain plants." taste_description = "the gross yet satisfying combination of chewing on a raw steak while gulping a bunch of root beer" color = "#d3785d" - metabolism = REM * 2.5 // not actually right for the mix, but required to make it mechanically equivalent for feralness purposes + metabolism_rate = REM * 2.5 // not actually right for the mix, but required to make it mechanically equivalent for feralness purposes var/alt_nutriment_factor = 5 //half as much as protein since it's half protein. //using a new variable instead of nutriment_factor so we can call ..() without that adding nutrition for us without taking factors for protein into account glass_name = "Dry Monster Tamer" glass_desc = "This looks like a fizzy slurry of meat. Gross." -/datum/reagent/drink/drymonstertamer/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/drymonstertamer/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() monster_tamer(M,alien, removed, alt_nutriment_factor) -/datum/reagent/drink/drymonstertamer/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/drymonstertamer/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_SKRELL) M.adjustToxLoss(removed) //Equivalent to half as much protein, since it's half protein. @@ -4880,7 +4715,7 @@ glass_name = "Galactic Panic Attack" glass_desc = "Looking into this is like staring at the stars." -/datum/reagent/ethanol/galacticpanic/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/ethanol/galacticpanic/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) . = ..() M.afflict_stun(20 * 2) @@ -4961,7 +4796,7 @@ glass_name = "Dumb Shroom Juice" glass_desc = "Touch fuzzy, get dizzy." -/datum/reagent/drink/shroomjuice/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/drink/shroomjuice/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) . = ..() if(alien == IS_DIONA) @@ -4976,7 +4811,7 @@ M.druggy = max(M.druggy, 30) - var/effective_dose = dose + var/effective_dose = metabolism.total_processed_dose if(issmall(M)) effective_dose *= 2 if(effective_dose < 1 * threshold) M.apply_effect(3, STUTTER) @@ -5129,13 +4964,13 @@ glass_name = "A Desire to Die" glass_desc = "Deathbell and nuclear waste. The bane of your liver." -/datum/reagent/ethanol/desiretodie/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/ethanol/desiretodie/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) . = ..() if(alien == IS_DIONA) return M.bloodstr.add_reagent("radium", 0.3) -/datum/reagent/ethanol/desiretodie/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/ethanol/desiretodie/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) . = ..() if(alien == IS_DIONA) return diff --git a/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Medicine.dm b/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Medicine.dm index cb52e4e473da..7c2d4174742e 100644 --- a/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Medicine.dm +++ b/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Medicine.dm @@ -8,10 +8,10 @@ reagent_state = REAGENT_LIQUID color = "#00BFFF" overdose = REAGENTS_OVERDOSE * 2 - metabolism = REM * 0.5 + metabolism_rate = REM * 0.5 scannable = 1 -/datum/reagent/inaprovaline/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/inaprovaline/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien != IS_DIONA) M.add_chemical_effect(CE_STABLE, 15)//Reduces bleeding rate, and allowes the patient to breath even when in shock M.ceiling_chemical_effect(CE_PAINKILLER, 10) @@ -27,14 +27,14 @@ overdose = REAGENTS_OVERDOSE scannable = 1 -/datum/reagent/bicaridine/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/bicaridine/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/chem_effective = 1 if(alien == IS_SLIME) chem_effective = 0.75 if(alien != IS_DIONA) M.heal_organ_damage(4 * removed * chem_effective, 0) //The first Parameter of the function is brute, the second burn damage -/datum/reagent/bicaridine/overdose(mob/living/carbon/M, alien, removed) +/datum/reagent/bicaridine/legacy_affect_overdose(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() var/wound_heal = 1.5 * removed//Overdose enhances the healing effects M.eye_blurry = min(M.eye_blurry + wound_heal, 250) @@ -62,7 +62,7 @@ touch_met = REM * 0.75 can_overdose_touch = TRUE -/datum/reagent/bicaridine/topical/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/bicaridine/topical/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/chem_effective = 1 if(alien == IS_SLIME) chem_effective = 0.75 @@ -70,7 +70,7 @@ ..(M, alien, removed * chem_effective)//heals the patient like Bicardine would M.adjustToxLoss(2 * removed)//deals toxic damage like the other topical gels -/datum/reagent/bicaridine/topical/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/bicaridine/topical/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/chem_effective = 1 if(alien == IS_SLIME) chem_effective = 0.75 @@ -88,7 +88,7 @@ overdose = REAGENTS_OVERDOSE * 0.5 scannable = 1 -/datum/reagent/vermicetol/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/vermicetol/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/chem_effective = 1 if(alien == IS_SLIME) chem_effective = 0.75 @@ -103,14 +103,14 @@ reagent_state = REAGENT_SOLID color = "#eae6e3" overdose = REAGENTS_OVERDOSE * 0.8 - metabolism = REM * 0.4 + metabolism_rate = REM * 0.4 scannable = 1 -/datum/reagent/calciumcarbonate/affect_blood(mob/living/carbon/M, alien, removed) // Why would you inject this. +/datum/reagent/calciumcarbonate/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) // Why would you inject this. if(alien != IS_DIONA) M.adjustToxLoss(3 * removed) -/datum/reagent/calciumcarbonate/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/calciumcarbonate/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien != IS_DIONA) M.add_chemical_effect(CE_ANTACID, 3)//Antipuke effect @@ -124,7 +124,7 @@ overdose = REAGENTS_OVERDOSE scannable = 1 -/datum/reagent/kelotane/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/kelotane/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/chem_effective = 1 if(alien == IS_SLIME) chem_effective = 0.5 @@ -142,7 +142,7 @@ overdose = REAGENTS_OVERDOSE * 0.5 scannable = 1 -/datum/reagent/dermaline/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/dermaline/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/chem_effective = 1 if(alien == IS_SLIME) chem_effective = 0.75 @@ -161,7 +161,7 @@ touch_met = REM * 0.75 can_overdose_touch = TRUE -/datum/reagent/dermaline/topical/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/dermaline/topical/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/chem_effective = 1 if(alien == IS_SLIME) chem_effective = 0.75 @@ -169,7 +169,7 @@ ..(M, alien, removed * chem_effective) M.adjustToxLoss(2 * removed) -/datum/reagent/dermaline/topical/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/dermaline/topical/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/chem_effective = 1 if(alien == IS_SLIME) chem_effective = 0.75 @@ -185,11 +185,11 @@ color = "#00A000" scannable = 1 -/datum/reagent/dylovene/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/dylovene/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/chem_effective = 1 if(alien == IS_SLIME) chem_effective = 0.66 - if(dose >= 15) + if(metabolism.total_processed_dose >= 15) M.druggy = max(M.druggy, 5) if(alien != IS_DIONA) M.drowsyness = max(0, M.drowsyness - 6 * removed * chem_effective)//reduces drowsyness to zero @@ -206,7 +206,7 @@ color = "#225722" scannable = 1 -/datum/reagent/carthatoline/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/carthatoline/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return if(M.getToxLoss() && prob(10))//if the patient has toxin damage 10% chance to cause vomiting @@ -234,13 +234,14 @@ color = "#0080FF" overdose = REAGENTS_OVERDOSE scannable = 1 - metabolism = REM * 0.25 -/datum/reagent/dexalin/affect_blood(mob/living/carbon/M, alien, removed) + metabolism_rate = REM * 0.25 + +/datum/reagent/dexalin/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_VOX) M.adjustToxLoss(removed * 24) //Vox breath phoron, oxygen is rather deadly to them if(alien == IS_ALRAUNE) M.adjustToxLoss(removed * 10) //cit change: oxygen is waste for plants - else if(alien == IS_SLIME && dose >= 15) + else if(alien == IS_SLIME && metabolism.total_processed_dose >= 15) M.ceiling_chemical_effect(CE_PAINKILLER, 15) if(prob(15)) to_chat(M, "You have a moment of clarity as you collapse.") @@ -249,8 +250,8 @@ else if(alien != IS_DIONA) M.adjustOxyLoss(-60 * removed) //Heals alot of oxyloss damage/but //keep in mind that Dexaline has a metabolism rate of 0.25*REM meaning only 0.25 units are removed every tick(if your metabolism takes usuall 1u per tick) + metabolism.legacy_current_holder.remove_reagent(/datum/reagent/lexorin, 8 * removed) - holder.remove_reagent("lexorin", 8 * removed) /datum/reagent/dexalinp name = "Dexalin Plus" id = "dexalinp" @@ -261,12 +262,12 @@ overdose = REAGENTS_OVERDOSE * 0.5 scannable = 1 -/datum/reagent/dexalinp/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/dexalinp/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_VOX) M.adjustToxLoss(removed * 9)//Again, vox dont like O2 if(alien == IS_ALRAUNE) M.adjustToxLoss(removed * 5) //cit change: oxygen is waste for plants - else if(alien == IS_SLIME && dose >= 10) + else if(alien == IS_SLIME && metabolism.total_processed_dose >= 10) M.ceiling_chemical_effect(CE_PAINKILLER, 25) if(prob(25)) to_chat(M, "You have a moment of clarity, as you feel your tubes lose pressure rapidly.") @@ -275,7 +276,7 @@ else if(alien != IS_DIONA) M.adjustOxyLoss(-150 * removed)//Heals more oxyloss than Dex and has no metabolism reduction - holder.remove_reagent("lexorin", 3 * removed) + metabolism.legacy_current_holder.remove_reagent(/datum/reagent/lexorin, 3 * removed) /datum/reagent/tricordrazine name = "Tricordrazine" @@ -286,18 +287,20 @@ color = "#8040FF" scannable = 1 -/datum/reagent/tricordrazine/affect_blood(mob/living/carbon/M, alien, removed) - if(alien != IS_DIONA)//Heals everyone besides diona on all 4 base damage types. - var/chem_effective = 1 - if(alien == IS_SLIME) - chem_effective = 0.5 - M.adjustOxyLoss(-3 * removed * chem_effective) - M.heal_organ_damage(1.5 * removed, 1.5 * removed * chem_effective) - M.adjustToxLoss(-1.5 * removed * chem_effective) +/datum/reagent/tricordrazine/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + if(alien == IS_DIONA) + return + var/chem_effective = 1 + if(alien == IS_SLIME) + chem_effective = 0.5 + M.adjustOxyLoss(-3 * removed * chem_effective) + M.heal_organ_damage(1.5 * removed, 1.5 * removed * chem_effective) + M.adjustToxLoss(-1.5 * removed * chem_effective) -/datum/reagent/tricordrazine/affect_touch(mob/living/carbon/M, alien, removed) - if(alien != IS_DIONA) - affect_blood(M, alien, removed * 0.4) +/datum/reagent/tricordrazine/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + if(alien == IS_DIONA) + return + legacy_affect_blood(M, alien, removed * 0.4, metabolism) /datum/reagent/earthsblood name = "Earthsblood" @@ -309,7 +312,7 @@ overdose = REAGENTS_OVERDOSE * 0.50 -/datum/reagent/earthsblood/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/earthsblood/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/chem_effective = 1 if(alien == IS_ALRAUNE) chem_effective = 1.1 //Plant to Plant Restoration @@ -335,7 +338,7 @@ scannable = 1 can_overdose_touch = TRUE -/datum/reagent/tricorlidaze/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/tricorlidaze/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien != IS_DIONA) var/chem_effective = 1 if(alien == IS_SLIME) @@ -344,7 +347,7 @@ M.heal_organ_damage(2 * removed, 2 * removed * chem_effective)//alittle more potent on brute and burns than Tricordrazine M.adjustToxLoss(-0.5 * removed * chem_effective)//Same as Oxyloss -/datum/reagent/tricorlidaze/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/tricorlidaze/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien != IS_DIONA) M.adjustToxLoss(3 * removed) @@ -368,11 +371,11 @@ taste_description = "overripe bananas" reagent_state = REAGENT_LIQUID color = "#8080FF" - metabolism = REM * 0.5 + metabolism_rate = REM * 0.5 mrate_static = TRUE scannable = 1 -/datum/reagent/cryoxadone/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/cryoxadone/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(M.bodytemperature < 170) var/chem_effective = 1 if(alien == IS_SLIME) @@ -393,11 +396,11 @@ taste_description = "rotten bananas" reagent_state = REAGENT_LIQUID color = "#80BFFF" - metabolism = REM * 0.5 + metabolism_rate = REM * 0.5 mrate_static = TRUE scannable = 1 -/datum/reagent/clonexadone/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/clonexadone/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(M.bodytemperature < 170) var/chem_effective = 1 if(alien == IS_SLIME) @@ -419,7 +422,7 @@ taste_description = "meat" reagent_state = REAGENT_LIQUID color = "#94B21C" - metabolism = REM * 0.5 + metabolism_rate = REM * 0.5 mrate_static = TRUE scannable = 1 @@ -431,7 +434,7 @@ . = ..(M, alien, location) -/datum/reagent/necroxadone/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/necroxadone/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(M.bodytemperature < 170 || (M.stat == DEAD && M.has_modifier_of_type(/datum/modifier/bloodpump_corpse))) var/chem_effective = 1 if(alien == IS_SLIME) @@ -456,16 +459,16 @@ color = "#C8A5DC" overdose = 60 scannable = 1 - metabolism = 0.02 + metabolism_rate = 0.02 mrate_static = TRUE -/datum/reagent/paracetamol/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/paracetamol/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/chem_effective = 1 if(alien == IS_SLIME) chem_effective = 0.75 M.ceiling_chemical_effect(CE_PAINKILLER, 25 * chem_effective)//kinda weak painkilling, for non life threatening injuries -/datum/reagent/paracetamol/overdose(mob/living/carbon/M, alien) +/datum/reagent/paracetamol/legacy_affect_overdose(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_SLIME) M.add_chemical_effect(CE_SLOWDOWN, 1) @@ -480,17 +483,17 @@ color = "#CB68FC" overdose = 30 scannable = 1 - metabolism = 0.02 + metabolism_rate = 0.02 mrate_static = TRUE -/datum/reagent/tramadol/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/tramadol/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/chem_effective = 1 if(alien == IS_SLIME) chem_effective = 0.8 M.add_chemical_effect(CE_SLOWDOWN, 1) M.ceiling_chemical_effect(CE_PAINKILLER, 80 * chem_effective)//more potent painkilling, for close to fatal injuries -/datum/reagent/tramadol/overdose(mob/living/carbon/M, alien) +/datum/reagent/tramadol/legacy_affect_overdose(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() M.setHallucination(max(M.hallucination, 2)) @@ -503,10 +506,10 @@ color = "#800080" overdose = 20 scannable = 1 - metabolism = 0.02 + metabolism_rate = 0.02 mrate_static = TRUE -/datum/reagent/oxycodone/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/oxycodone/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/chem_effective = 1 if(alien == IS_SLIME) chem_effective = 0.75 @@ -515,7 +518,7 @@ M.add_chemical_effect(CE_SLOWDOWN, 1) M.eye_blurry = min(M.eye_blurry + 10, 250 * chem_effective) -/datum/reagent/oxycodone/overdose(mob/living/carbon/M, alien) +/datum/reagent/oxycodone/legacy_affect_overdose(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() M.druggy = max(M.druggy, 10) M.setHallucination(max(M.hallucination, 3)) @@ -527,18 +530,18 @@ taste_description = "sourness" reagent_state = REAGENT_LIQUID color = "#800080" - metabolism = 0.1 //Lasts up to 200 seconds if you give 20u which is OD. + metabolism_rate = 0.1 //Lasts up to 200 seconds if you give 20u which is OD. mrate_static = TRUE overdose = 20 //High OD. This is to make numbing bites have somewhat of a downside if you get bit too much. Have to go to medical for dialysis. scannable = 0 //Let's not have medical mechs able to make an extremely strong organic painkiller -/datum/reagent/numbing_enzyme/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/numbing_enzyme/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.ceiling_chemical_effect(CE_PAINKILLER, 200)//Similar to Oxycodone if(prob(0.01)) //1 in 10000 chance per tick. Extremely rare. to_chat(M,"Your body feels numb as a light, tingly sensation spreads throughout it, like some odd warmth.") //Not noted here, but a movement debuff of 1.5 is handed out in human_movement.dm when numbing_enzyme is in a person's bloodstream! -/datum/reagent/numbing_enzyme/overdose(mob/living/carbon/M, alien) +/datum/reagent/numbing_enzyme/legacy_affect_overdose(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) //..() //Add this if you want it to do toxin damage. Personally, let's allow them to have the horrid effects below without toxin damage. if(ishuman(M)) var/mob/living/carbon/human/H = M @@ -572,16 +575,16 @@ taste_description = "bitterness" reagent_state = REAGENT_LIQUID color = "#99CCFF" - metabolism = REM * 0.05 + metabolism_rate = REM * 0.05 overdose = REAGENTS_OVERDOSE scannable = 1 -/datum/reagent/synaptizine/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/synaptizine/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/chem_effective = 1 if(alien == IS_DIONA) return if(alien == IS_SLIME) - if(dose >= 5) //Not effective in small doses, though it causes toxloss at higher ones, it will make the regeneration for brute and burn more 'efficient' at the cost of more nutrition. + if(metabolism.total_processed_dose >= 5) //Not effective in small doses, though it causes toxloss at higher ones, it will make the regeneration for brute and burn more 'efficient' at the cost of more nutrition. M.nutrition -= removed * 2 M.adjustBruteLoss(-2 * removed) M.adjustFireLoss(-1 * removed) @@ -590,7 +593,7 @@ M.adjust_unconscious(20 * -1) M.adjust_stunned(20 * -1) M.adjust_paralyzed(20 * -1) - holder.remove_reagent("mindbreaker", 5) + metabolism.legacy_current_holder.remove_reagent(/datum/reagent/mindbreaker, 5) M.adjustHallucination(-10) //Primary use M.adjustToxLoss(5 * removed * chem_effective) // It used to be incredibly deadly due to an oversight. Not anymore! M.ceiling_chemical_effect(CE_PAINKILLER, 20 * chem_effective) @@ -600,18 +603,16 @@ id = "hyperzine" description = "Hyperzine is a highly effective, long lasting, muscle stimulant." taste_description = "bitterness" - metabolism = REM * 0.25 // see "long lasting" + metabolism_rate = REM * 0.25 // see "long lasting" reagent_state = REAGENT_LIQUID color = "#FF3300" overdose = REAGENTS_OVERDOSE * 0.5 -/datum/reagent/hyperzine/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/hyperzine/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_TAJARA) removed *= 1.25 if(alien == IS_SLIME) M.make_jittery(4) //Hyperactive fluid pumping results in unstable 'skeleton', resulting in vibration. - if(dose >= 5) - M.nutrition = (M.nutrition - (removed * 2)) //Sadly this movement starts burning food in higher doses. ..() if(prob(5)) M.emote(pick("twitch", "blink_r", "shiver")) @@ -624,11 +625,11 @@ taste_description = "bitterness" reagent_state = REAGENT_LIQUID color = "#FFFF66" - metabolism = REM * 0.25 + metabolism_rate = REM * 0.25 overdose = REAGENTS_OVERDOSE scannable = 1 -/datum/reagent/alkysine/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/alkysine/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return var/chem_effective = 1 @@ -636,7 +637,7 @@ chem_effective = 0.25 if(M.brainloss >= 10) M.afflict_paralyze(20 * 5) - if(dose >= 10 && M.is_unconscious()) + if(metabolism.total_processed_dose >= 10 && M.is_unconscious()) M.adjust_unconscious(20 * 1) //Messing with the core with a simple chemical probably isn't the best idea. M.adjustBrainLoss(-8 * removed * chem_effective) //the Brain damage heal M.ceiling_chemical_effect(CE_PAINKILLER, 10 * chem_effective) @@ -651,7 +652,7 @@ overdose = REAGENTS_OVERDOSE scannable = 1 -/datum/reagent/imidazoline/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/imidazoline/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.eye_blurry = max(M.eye_blurry - 5, 0) if(ishuman(M)) var/mob/living/carbon/human/H = M @@ -674,7 +675,7 @@ overdose = 10 scannable = 1 -/datum/reagent/peridaxon/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/peridaxon/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(ishuman(M)) var/mob/living/carbon/human/H = M for(var/obj/item/organ/I in H.internal_organs) @@ -701,7 +702,7 @@ overdose = 10 scannable = 1 -/datum/reagent/nanoperidaxon/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/nanoperidaxon/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(ishuman(M)) var/mob/living/carbon/human/H = M for(var/obj/item/organ/I in H.internal_organs) @@ -722,11 +723,11 @@ description = "An experimental drug used to heal bone fractures." reagent_state = REAGENT_LIQUID color = "#C9BCE3" - metabolism = REM * 0.5 + metabolism_rate = REM * 0.5 overdose = REAGENTS_OVERDOSE * 0.5 scannable = 1 -/datum/reagent/osteodaxon/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/osteodaxon/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return M.heal_organ_damage(3 * removed, 0) //Gives the bones a chance to set properly even without other meds @@ -744,12 +745,12 @@ description = "Used to rapidly clot internal hemorrhages by increasing the effectiveness of platelets." reagent_state = REAGENT_LIQUID color = "#4246C7" - metabolism = REM * 0.5 + metabolism_rate = REM * 0.5 overdose = REAGENTS_OVERDOSE * 0.5 scannable = 1 var/repair_strength = 3 -/datum/reagent/myelamine/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/myelamine/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return M.eye_blurry += min(M.eye_blurry + (repair_strength * removed), 250) @@ -776,11 +777,11 @@ taste_description = "metallic" reagent_state = REAGENT_LIQUID color = "#4444FF" - metabolism = REM * 1.5 + metabolism_rate = REM * 1.5 overdose = 10 scannable = 1 -/datum/reagent/respirodaxon/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/respirodaxon/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/repair_strength = 1 if(alien == IS_SLIME) repair_strength = 0.6 @@ -799,14 +800,8 @@ H.losebreath = clamp(H.losebreath + 3, 0, 20) else H.losebreath = max(H.losebreath - 4, 0) - if(M.ingested) - for(var/datum/reagent/asbestos/R in M.ingested.reagent_list) - R.remove_self(removed * 4) - if(M.bloodstr) - for(var/datum/reagent/asbestos/R in M.bloodstr.reagent_list) - R.remove_self(removed * 4) - - + M.ingested?.remove_reagent(/datum/reagent/asbestos) + M.bloodstr?.remove_reagent(/datum/reagent/asbestos) /datum/reagent/gastirodaxon name = "Gastirodaxon" @@ -815,11 +810,11 @@ taste_description = "chalk" reagent_state = REAGENT_LIQUID color = "#8B4513" - metabolism = REM * 1.5 + metabolism_rate = REM * 1.5 overdose = 10 scannable = 1 -/datum/reagent/gastirodaxon/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/gastirodaxon/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/repair_strength = 1 if(alien == IS_SLIME) repair_strength = 0.6 @@ -846,11 +841,11 @@ taste_description = "glue" reagent_state = REAGENT_LIQUID color = "#D2691E" - metabolism = REM * 1.5 + metabolism_rate = REM * 1.5 overdose = 10 scannable = 1 -/datum/reagent/hepanephrodaxon/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/hepanephrodaxon/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/repair_strength = 1 if(alien == IS_SLIME) repair_strength = 0.4 @@ -879,11 +874,11 @@ taste_description = "rust" reagent_state = REAGENT_LIQUID color = "#FF4444" - metabolism = REM * 1.5 + metabolism_rate = REM * 1.5 overdose = 10 scannable = 1 -/datum/reagent/cordradaxon/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/cordradaxon/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/repair_strength = 1 if(alien == IS_SLIME) repair_strength = 0.6 @@ -910,7 +905,7 @@ overdose = 20 scannable = 1 -/datum/reagent/immunosuprizine/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/immunosuprizine/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/strength_mod = 1 if(alien == IS_DIONA) // It's a tree. @@ -941,7 +936,7 @@ if(I.robotic >= ORGAN_ROBOT) organtotal -= I - if(dose >= 15) + if(metabolism.total_processed_dose >= 15) for(var/obj/item/organ/I in organtotal) if(I.transplant_data && prob(round(15 * strength_mod))) // Reset the rejection process, toggle it to not reject. I.rejecting = 0 @@ -963,11 +958,11 @@ taste_description = "mordant" reagent_state = REAGENT_SOLID color = "#84B2B0" - metabolism = REM * 0.75 + metabolism_rate = REM * 0.75 overdose = 20 scannable = 1 -/datum/reagent/skrellimmuno/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/skrellimmuno/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/strength_mod = 0.5 if(alien == IS_SKRELL) @@ -986,7 +981,7 @@ if(I.robotic >= ORGAN_ROBOT) organtotal -= I - if(dose >= 15) + if(metabolism.total_processed_dose >= 15) for(var/obj/item/organ/I in organtotal) if(I.transplant_data && prob(round(15 * strength_mod))) I.rejecting = 0 @@ -1010,7 +1005,7 @@ color = "#004000" overdose = REAGENTS_OVERDOSE -/datum/reagent/ryetalyn/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/ryetalyn/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/needs_update = M.mutations.len > 0 M.mutations = list() @@ -1057,19 +1052,17 @@ color = "#605048" overdose = REAGENTS_OVERDOSE -/datum/reagent/ethylredoxrazine/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/ethylredoxrazine/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return M.dizziness = 0 M.drowsyness = 0 M.stuttering = 0 M.SetConfused(0) - if(M.ingested) - for(var/datum/reagent/ethanol/R in M.ingested.reagent_list) - R.remove_self(removed * 30) - if(M.bloodstr) - for(var/datum/reagent/ethanol/R in M.bloodstr.reagent_list) - R.remove_self(removed * 20) + for(var/datum/reagent/ethanol/ethanol_filter in M.ingested.get_reagent_datums()) + M.ingested.remove_reagent(ethanol_filter.id, removed * 30) + for(var/datum/reagent/ethanol/ethanol_filter in M.bloodstr.get_reagent_datums()) + M.ingested.remove_reagent(ethanol_filter.id, removed * 20) /datum/reagent/hyronalin name = "Hyronalin" @@ -1078,11 +1071,11 @@ taste_description = "bitterness" reagent_state = REAGENT_LIQUID color = "#408000" - metabolism = REM * 0.25 + metabolism_rate = REM * 0.25 overdose = REAGENTS_OVERDOSE scannable = 1 -/datum/reagent/hyronalin/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/hyronalin/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return M.cure_radiation(RAD_MOB_CURE_STRENGTH_HYRONALIN(removed)) @@ -1094,11 +1087,11 @@ taste_description = "bitterness" reagent_state = REAGENT_LIQUID color = "#008000" - metabolism = REM * 0.25 + metabolism_rate = REM * 0.25 overdose = REAGENTS_OVERDOSE scannable = 1 -/datum/reagent/arithrazine/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/arithrazine/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return M.cure_radiation(RAD_MOB_CURE_STRENGTH_ARITHRAZINE(removed)) @@ -1113,27 +1106,26 @@ taste_description = "bitterness" reagent_state = REAGENT_LIQUID color = "#C1C1C1" - metabolism = REM * 0.25 + metabolism_rate = REM * 0.25 mrate_static = TRUE overdose = REAGENTS_OVERDOSE scannable = 1 - data = 0 -/datum/reagent/spaceacillin/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/spaceacillin/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_SLIME) - if(volume <= 0.1 && data != -1) - data = -1 + if(metabolism.legacy_volume_remaining <= 0.1 && metabolism.blackboard["last-message"] != -1) + metabolism.blackboard["last-message"] = -1 to_chat(M, "You regain focus...") else var/delay = (5 MINUTES) - if(world.time > data + delay) - data = world.time + if(world.time > metabolism.blackboard["last-message"] + delay) + metabolism.blackboard["last-message"] = world.time to_chat(M, "Your senses feel unfocused, and divided.") - M.add_chemical_effect(CE_ANTIBIOTIC, dose >= overdose ? ANTIBIO_OD : ANTIBIO_NORM) + M.add_chemical_effect(CE_ANTIBIOTIC, metabolism.total_processed_dose >= overdose ? ANTIBIO_OD : ANTIBIO_NORM) -/datum/reagent/spaceacillin/affect_touch(mob/living/carbon/M, alien, removed) - affect_blood(M, alien, removed * 0.8) // Not 100% as effective as injections, though still useful. +/datum/reagent/spaceacillin/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + legacy_affect_blood(M, alien, removed * 0.8, metabolism) /datum/reagent/corophizine name = "Corophizine" @@ -1145,26 +1137,26 @@ mrate_static = TRUE overdose = 10 scannable = 1 - data = 0 -/datum/reagent/corophizine/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/corophizine/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() M.add_chemical_effect(CE_ANTIBIOTIC, ANTIBIO_SUPER) var/mob/living/carbon/human/H = M if(ishuman(M) && alien == IS_SLIME) //Everything about them is treated like a targetted organism. Widespread bodily function begins to fail. - if(volume <= 0.1 && data != -1) - data = -1 + if(metabolism.legacy_volume_remaining <= 0.1 && metabolism.blackboard["last-message"] != -1) + metabolism.blackboard["last-message"] = -1 to_chat(M, "Your body ceases its revolt.") else var/delay = (3 MINUTES) - if(world.time > data + delay) - data = world.time + if(world.time > metabolism.blackboard["last-message"] + delay) + metabolism.blackboard["last-message"] = world.time to_chat(M, "It feels like your body is revolting!") M.Confuse(7) M.adjustFireLoss(removed * 2) M.adjustToxLoss(removed * 2) + var/dose = metabolism.total_processed_dose if(dose >= 5 && M.toxloss >= 10) //It all starts going wrong. M.adjustBruteLoss(removed * 3) M.eye_blurry = min(20, max(0, M.eye_blurry + 10)) @@ -1209,46 +1201,46 @@ taste_description = "oil" reagent_state = REAGENT_SOLID color = "#C1C1C8" - metabolism = REM * 0.4 + metabolism_rate = REM * 0.4 mrate_static = TRUE overdose = REAGENTS_OVERDOSE scannable = 1 - data = 0 can_overdose_touch = TRUE -/datum/reagent/spacomycaze/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/spacomycaze/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.ceiling_chemical_effect(CE_PAINKILLER, 10) M.adjustToxLoss(3 * removed) -/datum/reagent/spacomycaze/affect_ingest(mob/living/carbon/M, alien, removed) - affect_blood(M, alien, removed * 0.8) +/datum/reagent/spacomycaze/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + legacy_affect_blood(M, alien, removed * 0.8, metabolism) -/datum/reagent/spacomycaze/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/spacomycaze/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_SLIME) - if(volume <= 0.1 && data != -1) - data = -1 + if(metabolism.legacy_volume_remaining <= 0.1 && metabolism.blackboard["last-message"] != -1) + metabolism.blackboard["last-message"] = -1 to_chat(M, "The itching fades...") else var/delay = (2 MINUTES) - if(world.time > data + delay) - data = world.time + if(world.time > metabolism.blackboard["last-message"] + delay) + metabolism.blackboard["last-message"] = world.time to_chat(M, "Your skin itches.") - M.add_chemical_effect(CE_ANTIBIOTIC, dose >= overdose ? ANTIBIO_OD : ANTIBIO_NORM) + M.add_chemical_effect(CE_ANTIBIOTIC, metabolism.total_processed_dose >= overdose ? ANTIBIO_OD : ANTIBIO_NORM) M.ceiling_chemical_effect(CE_PAINKILLER, 20) // 5 less than paracetamol. -/datum/reagent/spacomycaze/touch_obj(obj/O) - if(istype(O, /obj/item/stack/medical/crude_pack) && round(volume) >= 1) - var/obj/item/stack/medical/crude_pack/C = O +/datum/reagent/spacomycaze/on_touch_obj(obj/target, remaining, allocated, data, spread_between) + if(istype(target, /obj/item/stack/medical/crude_pack) && round(volume) >= 1) + var/obj/item/stack/medical/crude_pack/C = target var/packname = C.name - var/to_produce = min(C.amount, round(volume)) + var/to_produce = min(C.amount, floor(allocated)) var/obj/item/stack/medical/M = C.upgrade_stack(to_produce) if(M && M.amount) - holder.my_atom.visible_message("\The [packname] bubbles.") - remove_self(to_produce) + target.visible_message("\The [packname] bubbles.") + . += to_produce + return . + ..() /datum/reagent/sterilizine name = "Sterilizine" @@ -1259,13 +1251,13 @@ color = "#C8A5DC" touch_met = 5 -/datum/reagent/sterilizine/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/sterilizine/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_SLIME) M.adjustFireLoss(removed) M.adjustToxLoss(2 * removed) return -/datum/reagent/sterilizine/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/sterilizine/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.germ_level -= min(removed*20, M.germ_level) for(var/obj/item/I in M.contents) I.was_bloodied = null @@ -1305,7 +1297,7 @@ overdose = REAGENTS_OVERDOSE scannable = 1 -/datum/reagent/leporazine/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/leporazine/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return if(M.bodytemperature > 310) @@ -1323,7 +1315,7 @@ overdose = REAGENTS_OVERDOSE scannable = 1 -/datum/reagent/rezadone/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/rezadone/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return var/mob/living/carbon/human/H = M @@ -1368,20 +1360,19 @@ taste_description = "bitterness" reagent_state = REAGENT_LIQUID color = "#BF80BF" - metabolism = 0.01 + metabolism_rate = 0.01 ingest_met = 0.25 mrate_static = TRUE - data = 0 -/datum/reagent/methylphenidate/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/methylphenidate/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return - if(volume <= 0.1 && data != -1) - data = -1 + if(metabolism.legacy_volume_remaining <= 0.1 && metabolism.blackboard["last-message"] != -1) + metabolism.blackboard["last-message"] = -1 to_chat(M, "You lose focus...") else - if(world.time > data + ANTIDEPRESSANT_MESSAGE_DELAY) - data = world.time + if(world.time > metabolism.blackboard["last-message"] + ANTIDEPRESSANT_MESSAGE_DELAY) + metabolism.blackboard["last-message"] = world.time to_chat(M, "Your mind feels focused and undivided.") /datum/reagent/citalopram @@ -1391,20 +1382,19 @@ taste_description = "bitterness" reagent_state = REAGENT_LIQUID color = "#FF80FF" - metabolism = 0.01 + metabolism_rate = 0.01 ingest_met = 0.25 mrate_static = TRUE - data = 0 -/datum/reagent/citalopram/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/citalopram/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return - if(volume <= 0.1 && data != -1) - data = -1 + if(metabolism.legacy_volume_remaining <= 0.1 && metabolism.blackboard["last-message"] != -1) + metabolism.blackboard["last-message"] = -1 to_chat(M, "Your mind feels a little less stable...") else - if(world.time > data + ANTIDEPRESSANT_MESSAGE_DELAY) - data = world.time + if(world.time > metabolism.blackboard["last-message"] + ANTIDEPRESSANT_MESSAGE_DELAY) + metabolism.blackboard["last-message"] = world.time to_chat(M, "Your mind feels stable... a little stable.") /datum/reagent/paroxetine @@ -1414,20 +1404,19 @@ taste_description = "bitterness" reagent_state = REAGENT_LIQUID color = "#FF80BF" - metabolism = 0.01 + metabolism_rate = 0.01 ingest_met = 0.25 mrate_static = TRUE - data = 0 -/datum/reagent/paroxetine/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/paroxetine/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return - if(volume <= 0.1 && data != -1) - data = -1 + if(metabolism.legacy_volume_remaining <= 0.1 && metabolism.blackboard["last-message"] != -1) + metabolism.blackboard["last-message"] = -1 to_chat(M, "Your mind feels much less stable...") else - if(world.time > data + ANTIDEPRESSANT_MESSAGE_DELAY) - data = world.time + if(world.time > metabolism.blackboard["last-message"] + ANTIDEPRESSANT_MESSAGE_DELAY) + metabolism.blackboard["last-message"] = world.time if(prob(1)) to_chat(M, "Your mind breaks apart...") M.adjustHallucination(200) @@ -1442,7 +1431,7 @@ reagent_state = REAGENT_SOLID color = "#d5e2e5" -/datum/reagent/adranol/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/adranol/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return if(M.confused) @@ -1459,20 +1448,19 @@ taste_description = "mint" reagent_state = REAGENT_LIQUID color = "#e6efe3" - metabolism = 0.01 + metabolism_rate = 0.01 ingest_met = 0.25 mrate_static = TRUE - data = 0 -/datum/reagent/qerr_quem/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/qerr_quem/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return - if(volume <= 0.1 && data != -1) - data = -1 + if(metabolism.legacy_volume_remaining <= 0.1 && metabolism.blackboard["last-message"] != -1) + metabolism.blackboard["last-message"] = -1 to_chat(M, "You feel antsy, your concentration wavers...") else - if(world.time > data + ANTIDEPRESSANT_MESSAGE_DELAY) - data = world.time + if(world.time > metabolism.blackboard["last-message"] + ANTIDEPRESSANT_MESSAGE_DELAY) + metabolism.blackboard["last-message"] = world.time to_chat(M, "You feel invigorated and calm.") // This exists to cut the number of chemicals a merc borg has to juggle on their hypo. @@ -1483,17 +1471,17 @@ taste_description = "metal" reagent_state = REAGENT_SOLID color = "#555555" - metabolism = REM * 4 // Nanomachines gotta go fast. + metabolism_rate = REM * 4 // Nanomachines gotta go fast. scannable = TRUE affects_robots = TRUE -/datum/reagent/nanite/healing/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/nanite/healing/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.heal_organ_damage(2 * removed, 2 * removed) M.adjustOxyLoss(-4 * removed) M.adjustToxLoss(-2 * removed) M.adjustCloneLoss(-2 * removed) -/datum/reagent/nanite/healing/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/nanite/healing/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.heal_organ_damage(2 * removed, 2 * removed) M.adjustOxyLoss(-4 * removed) M.adjustToxLoss(-2 * removed) @@ -1508,7 +1496,7 @@ color = "#0E900E" overdose = REAGENTS_OVERDOSE -/datum/reagent/ickypak/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/ickypak/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.make_dizzy(1) M.adjustHalLoss(2) @@ -1531,7 +1519,7 @@ color = "#EF77E5" overdose = REAGENTS_OVERDOSE -/datum/reagent/unsorbitol/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/unsorbitol/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.make_dizzy(1) M.adjustHalLoss(1) if(!M.confused) M.confused = 1 @@ -1563,7 +1551,7 @@ color = "#333333" scannable = 1 -/datum/reagent/nif_repair_nanites/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/nif_repair_nanites/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(ishuman(M)) var/mob/living/carbon/human/H = M if(H.nif) @@ -1627,19 +1615,19 @@ taste_description = "sour metal" taste_mult = 2 reagent_state = REAGENT_LIQUID - metabolism = REM * 0.016 + metabolism_rate = REM * 0.016 mrate_static = TRUE color = "#52ca22" scannable = 1 overdose = 16 -/datum/reagent/neuratrextate/affect_ingest(mob/living/carbon/M) +/datum/reagent/neuratrextate/legacy_affect_ingest(mob/living/carbon/M, datum/reagent_metabolism/metabolism) remove_self(30) to_chat(M, "It feels like there's a pile of knives in your stomach!") M.druggy += 10 M.vomit() -/datum/reagent/neuratrextate/overdose(mob/living/carbon/M) +/datum/reagent/neuratrextate/legacy_affect_overdose(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() M.druggy += 30 M.adjustHallucination(20) diff --git a/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Modifiers.dm b/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Modifiers.dm index 5ed243757767..ae7162010236 100644 --- a/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Modifiers.dm +++ b/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Modifiers.dm @@ -9,15 +9,15 @@ taste_description = "metal" reagent_state = REAGENT_LIQUID color = "#ff5555" - metabolism = REM + metabolism_rate = REM var/modifier_to_add = /datum/modifier/berserk var/modifier_duration = 2 SECONDS // How long, per unit dose, will this last? -/datum/reagent/modapplying/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/modapplying/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return - M.add_modifier(modifier_to_add, dose * modifier_duration) + M.add_modifier(modifier_to_add, metabolism.total_processed_dose * modifier_duration) /datum/reagent/modapplying/cryofluid name = "cryogenic slurry" @@ -25,20 +25,20 @@ description = "An incredibly strange liquid that rapidly absorbs thermal energy from materials it contacts." taste_description = "siberian hellscape" color = "#4CDBDB" - metabolism = REM * 0.5 + metabolism_rate = REM * 0.5 modifier_to_add = /datum/modifier/cryogelled modifier_duration = 3 SECONDS -/datum/reagent/modapplying/cryofluid/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/modapplying/cryofluid/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..(M, alien, removed) M.bodytemperature -= removed * 20 -/datum/reagent/modapplying/cryofluid/affect_ingest(mob/living/carbon/M, alien, removed) - affect_blood(M, alien, removed * 2.5) +/datum/reagent/modapplying/cryofluid/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + legacy_affect_blood(M, alien, removed * 2.5, metabolism) -/datum/reagent/modapplying/cryofluid/affect_touch(mob/living/carbon/M, alien, removed) - affect_blood(M, alien, removed * 0.6) +/datum/reagent/modapplying/cryofluid/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + legacy_affect_blood(M, alien, removed * 0.6, metabolism) /datum/reagent/modapplying/cryofluid/touch_mob(mob/M, amount) if(isliving(M)) diff --git a/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Other.dm b/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Other.dm index aa3fb658bdb7..aebe8a15a147 100644 --- a/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Other.dm +++ b/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Other.dm @@ -1,254 +1,5 @@ -/* Paint and crayons */ - -/datum/reagent/crayon_dust - name = "Crayon dust" - id = "crayon_dust" - description = "Intensely coloured powder obtained by grinding crayons." - taste_description = "powdered wax" - reagent_state = REAGENT_LIQUID - color = "#888888" - overdose = 5 - -/datum/reagent/crayon_dust/red - name = "Red crayon dust" - id = "crayon_dust_red" - color = "#FE191A" - -/datum/reagent/crayon_dust/orange - name = "Orange crayon dust" - id = "crayon_dust_orange" - color = "#FFBE4F" - -/datum/reagent/crayon_dust/yellow - name = "Yellow crayon dust" - id = "crayon_dust_yellow" - color = "#FDFE7D" - -/datum/reagent/crayon_dust/green - name = "Green crayon dust" - id = "crayon_dust_green" - color = "#18A31A" - -/datum/reagent/crayon_dust/blue - name = "Blue crayon dust" - id = "crayon_dust_blue" - color = "#247CFF" - -/datum/reagent/crayon_dust/purple - name = "Purple crayon dust" - id = "crayon_dust_purple" - color = "#CC0099" - -/datum/reagent/crayon_dust/grey //Mime - name = "Grey crayon dust" - id = "crayon_dust_grey" - color = "#808080" - -/datum/reagent/crayon_dust/brown //Rainbow - name = "Brown crayon dust" - id = "crayon_dust_brown" - color = "#846F35" - -/datum/reagent/marker_ink - name = "Marker ink" - id = "marker_ink" - description = "Intensely coloured ink used in markers." - taste_description = "extremely bitter" - reagent_state = REAGENT_LIQUID - color = "#888888" - overdose = 5 - -/datum/reagent/marker_ink/black - name = "Black marker ink" - id = "marker_ink_black" - color = "#000000" - -/datum/reagent/marker_ink/red - name = "Red marker ink" - id = "marker_ink_red" - color = "#FE191A" - -/datum/reagent/marker_ink/orange - name = "Orange marker ink" - id = "marker_ink_orange" - color = "#FFBE4F" - -/datum/reagent/marker_ink/yellow - name = "Yellow marker ink" - id = "marker_ink_yellow" - color = "#FDFE7D" - -/datum/reagent/marker_ink/green - name = "Green marker ink" - id = "marker_ink_green" - color = "#18A31A" - -/datum/reagent/marker_ink/blue - name = "Blue marker ink" - id = "marker_ink_blue" - color = "#247CFF" - -/datum/reagent/marker_ink/purple - name = "Purple marker ink" - id = "marker_ink_purple" - color = "#CC0099" - -/datum/reagent/marker_ink/grey //Mime - name = "Grey marker ink" - id = "marker_ink_grey" - color = "#808080" - -/datum/reagent/marker_ink/brown //Rainbow - name = "Brown marker ink" - id = "marker_ink_brown" - color = "#846F35" - -/datum/reagent/chalk_dust - name = "chalk dust" - id = "chalk_dust" - description = "Dusty powder obtained by grinding chalk." - taste_description = "powdered chalk" - reagent_state = REAGENT_LIQUID - color = "#FFFFFF" - overdose = 5 - -/datum/reagent/chalk_dust/red - name = "red chalk dust" - id = "chalk_dust_red" - color = "#aa0000" - -/datum/reagent/chalk_dust/black - name = "black chalk dust" - id = "chalk_dust_black" - color = "#180000" - -/datum/reagent/chalk_dust/blue - name = "blue chalk dust" - id = "chalk_dust_blue" - color = "#000370" - -/datum/reagent/paint - name = "Paint" - id = "paint" - description = "This paint will stick to almost any object." - taste_description = "chalk" - reagent_state = REAGENT_LIQUID - color = "#808080" - overdose = REAGENTS_OVERDOSE * 0.5 - color_weight = 20 - -/datum/reagent/paint/touch_turf(turf/T) - if(istype(T) && !istype(T, /turf/space)) - T.color = color - -/datum/reagent/paint/touch_obj(obj/O) - if(istype(O)) - O.color = color - -/datum/reagent/paint/touch_mob(mob/M) - if(istype(M) && !istype(M, /mob/observer)) //painting ghosts: not allowed - M.color = color //maybe someday change this to paint only clothes and exposed body parts for human mobs. - -/datum/reagent/paint/get_data() - return color - -/datum/reagent/paint/initialize_data(newdata) - color = newdata - return - -/datum/reagent/paint/mix_data(newdata, newamount) - var/list/colors = list(0, 0, 0, 0) - var/tot_w = 0 - - var/hex1 = uppertext(color) - var/hex2 = uppertext(newdata) - if(length(hex1) == 7) - hex1 += "FF" - if(length(hex2) == 7) - hex2 += "FF" - if(length(hex1) != 9 || length(hex2) != 9) - return - colors[1] += hex2num(copytext(hex1, 2, 4)) * volume - colors[2] += hex2num(copytext(hex1, 4, 6)) * volume - colors[3] += hex2num(copytext(hex1, 6, 8)) * volume - colors[4] += hex2num(copytext(hex1, 8, 10)) * volume - tot_w += volume - colors[1] += hex2num(copytext(hex2, 2, 4)) * newamount - colors[2] += hex2num(copytext(hex2, 4, 6)) * newamount - colors[3] += hex2num(copytext(hex2, 6, 8)) * newamount - colors[4] += hex2num(copytext(hex2, 8, 10)) * newamount - tot_w += newamount - - color = rgb(colors[1] / tot_w, colors[2] / tot_w, colors[3] / tot_w, colors[4] / tot_w) - return - /* Things that didn't fit anywhere else */ -/datum/reagent/adminordrazine //An OP chemical for admins - name = "Adminordrazine" - id = "adminordrazine" - description = "It's magic. We don't have to explain it." - taste_description = "bwoink" - reagent_state = REAGENT_LIQUID - color = "#C8A5DC" - affects_dead = 1 //This can even heal dead people. - metabolism = 0.1 - mrate_static = TRUE //Just in case - - glass_name = "liquid gold" - glass_desc = "It's magic. We don't have to explain it." - -/datum/reagent/adminordrazine/affect_touch(mob/living/carbon/M, alien, removed) - affect_blood(M, alien, removed) - -/datum/reagent/adminordrazine/affect_blood(mob/living/carbon/M, alien, removed) - M.setCloneLoss(0) - M.setOxyLoss(0) - M.radiation = 0 - M.heal_organ_damage(20,20) - M.adjustToxLoss(-20) - M.setHallucination(0) - M.setHalLoss(0) - M.setBrainLoss(0) - M.disabilities = 0 - M.sdisabilities = 0 - M.eye_blurry = 0 - M.remove_status_effect(/datum/status_effect/sight/blindness) - M.set_paralyzed(0) - M.set_stunned(0) - M.set_unconscious(0) - M.silent = 0 - M.dizziness = 0 - M.drowsyness = 0 - M.stuttering = 0 - M.SetConfused(0) - M.set_sleeping(0) - M.jitteriness = 0 - M.radiation = 0 - M.ExtinguishMob() - M.fire_stacks = 0 - if(M.bodytemperature > 310) - M.bodytemperature = max(310, M.bodytemperature - (40 * TEMPERATURE_DAMAGE_COEFFICIENT)) - else if(M.bodytemperature < 311) - M.bodytemperature = min(310, M.bodytemperature + (40 * TEMPERATURE_DAMAGE_COEFFICIENT)) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - var/wound_heal = 5 - for(var/obj/item/organ/external/O in H.bad_external_organs) - if(O.status & ORGAN_BROKEN) - O.mend_fracture() //Only works if the bone won't rebreak, as usual - for(var/datum/wound/W as anything in O.wounds) - if(W.bleeding()) - W.damage = max(W.damage - wound_heal, 0) - if(W.damage <= 0) - O.cure_exact_wound(W) - continue - if(W.internal) - W.damage = max(W.damage - wound_heal, 0) - if(W.damage <= 0) - O.cure_exact_wound(W) - continue - /datum/reagent/gold name = "Gold" id = "gold" @@ -281,10 +32,10 @@ reagent_state = REAGENT_SOLID color = "#777777" -/datum/reagent/uranium/affect_touch(mob/living/carbon/M, alien, removed) - affect_ingest(M, alien, removed) +/datum/reagent/uranium/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + legacy_affect_ingest(M, alien, removed, metabolism) -/datum/reagent/uranium/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/uranium/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.apply_effect(5 * removed, IRRADIATE, 0) /datum/reagent/uranium/touch_turf(turf/T) @@ -304,34 +55,13 @@ color = "#C8A5DC" mrate_static = TRUE -/datum/reagent/adrenaline/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/adrenaline/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return M.set_unconscious(0) M.set_paralyzed(0) M.adjustToxLoss(rand(3)) -/datum/reagent/water/holywater - name = "Holy Water" - id = "holywater" - description = "An ashen-obsidian-water mix, this solution will alter certain sections of the brain's rationality." - taste_description = "water" - color = "#E0E8EF" - mrate_static = TRUE - - glass_name = "holy water" - glass_desc = "An ashen-obsidian-water mix, this solution will alter certain sections of the brain's rationality." - -/datum/reagent/water/holywater/affect_ingest(mob/living/carbon/M, alien, removed) - ..() - if(ishuman(M)) // Any location - if(M.mind && cult.is_antagonist(M.mind) && prob(10)) - cult.remove_antagonist(M.mind) - -/datum/reagent/water/holywater/touch_turf(turf/T) - if(volume >= 5) - T.holy = 1 - return /datum/reagent/ammonia name = "Ammonia" @@ -342,7 +72,7 @@ reagent_state = REAGENT_GAS color = "#404030" -/datum/reagent/ammonia/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/ammonia/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_ALRAUNE) M.nutrition += removed * 2 //cit change: fertilizer is waste for plants return @@ -355,7 +85,7 @@ reagent_state = REAGENT_LIQUID color = "#604030" -/datum/reagent/diethylamine/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/diethylamine/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_ALRAUNE) M.nutrition += removed * 5 //cit change: fertilizer is waste for plants return @@ -431,22 +161,6 @@ color = "#C8A5DC" affects_robots = TRUE -/datum/reagent/coolant/affect_blood(mob/living/carbon/M, alien, removed) - if(M.isSynthetic() && ishuman(M)) - var/mob/living/carbon/human/H = M - - var/datum/reagent/blood/coolant = H.get_blood(H.vessel) - - if(coolant) - H.vessel.add_reagent("blood", removed, coolant.data) - - else - H.vessel.add_reagent("blood", removed) - H.fixblood() - - else - ..() - /datum/reagent/ultraglue name = "Ultra Glue" id = "glue" @@ -462,20 +176,6 @@ reagent_state = REAGENT_LIQUID color = "#B97A57" -/datum/reagent/luminol - name = "Luminol" - id = "luminol" - description = "A compound that interacts with blood on the molecular level." - taste_description = "metal" - reagent_state = REAGENT_LIQUID - color = "#F2F3F4" - -/datum/reagent/luminol/touch_obj(obj/O) - O.reveal_blood() - -/datum/reagent/luminol/touch_mob(mob/living/L) - L.reveal_blood() - /datum/reagent/nutriment/biomass name = "Biomass" id = "biomass" @@ -492,10 +192,10 @@ taste_description = "metal" reagent_state = REAGENT_SOLID color = "#333333" - metabolism = REM * 3 // Broken nanomachines go a bit slower. + metabolism_rate = REM * 3 // Broken nanomachines go a bit slower. scannable = 1 -/datum/reagent/defective_nanites/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/defective_nanites/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.take_random_targeted_damage(brute = 2 * removed, brute = 2 * removed) M.adjustOxyLoss(4 * removed) M.adjustToxLoss(2 * removed) @@ -533,72 +233,6 @@ color = "#464650" taste_description = "salt" -/*Liquid Carpets*/ - -/datum/reagent/carpet - name = "Liquid Carpet" - id = "liquidcarpet" - description = "Liquified carpet fibers, ready for dyeing." - reagent_state = REAGENT_LIQUID - color = "#b51d05" - taste_description = "carpet" - -/datum/reagent/carpet/black - name = "Liquid Black Carpet" - id = "liquidcarpetb" - description = "Black Carpet Fibers, ready for reinforcement." - reagent_state = REAGENT_LIQUID - color = "#000000" - taste_description = "rare and ashy carpet" - -/datum/reagent/carpet/blue - name = "Liquid Blue Carpet" - id = "liquidcarpetblu" - description = "Blue Carpet Fibers, ready for reinforcement." - reagent_state = REAGENT_LIQUID - color = "#3f4aee" - taste_description = "commanding carpet" - -/datum/reagent/carpet/turquoise - name = "Liquid Turquoise Carpet" - id = "liquidcarpettur" - description = "Turquoise Carpet Fibers, ready for reinforcement." - reagent_state = REAGENT_LIQUID - color = "#0592b5" - taste_description = "water-logged carpet" - -/datum/reagent/carpet/sblue - name = "Liquid Silver Blue Carpet" - id = "liquidcarpetsblu" - description = "Silver Blue Carpet Fibers, ready for reinforcement." - reagent_state = REAGENT_LIQUID - color = "#0011ff" - taste_description = "sterile and medicinal carpet" - -/datum/reagent/carpet/clown - name = "Liquid Clown Carpet" - id = "liquidcarpetc" - description = "Clown Carpet Fibers.... No clowns were harmed in the making of this." - reagent_state = REAGENT_LIQUID - color = "#e925be" - taste_description = "clown shoes and banana peels" - -/datum/reagent/carpet/purple - name = "Liquid Purple Carpet" - id = "liquidcarpetp" - description = "Purple Carpet Fibers, ready for reinforcement." - reagent_state = REAGENT_LIQUID - color = "#a614d3" - taste_description = "bleeding edge carpet research" - -/datum/reagent/carpet/orange - name = "Liquid Orange Carpet" - id = "liquidcarpeto" - description = "Orange Carpet Fibers, ready for reinforcement." - reagent_state = REAGENT_LIQUID - color = "#f16e16" - taste_description = "extremely overengineered carpet" - //Ashlander Alchemy! /datum/reagent/alchemybase name = "Alchemical Base" diff --git a/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Toxins.dm b/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Toxins.dm index 4491514ddbbf..2ef2b758aa47 100644 --- a/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Toxins.dm +++ b/code/modules/reagents/chemistry/reagents/Chemistry-Reagents-Toxins.dm @@ -1,32 +1,5 @@ /* Toxins, poisons, venoms */ -/datum/reagent/toxin - name = "toxin" - id = "toxin" - description = "A toxic chemical." - taste_description = "bitterness" - taste_mult = 1.2 - reagent_state = REAGENT_LIQUID - color = "#CF3600" - metabolism = REM * 0.25 // 0.05 by default. Hopefully enough to get some help, or die horribly, whatever floats your boat - filtered_organs = list(O_LIVER, O_KIDNEYS) - var/strength = 4 // How much damage it deals per unit - var/skin_danger = 0.2 // The multiplier for how effective the toxin is when making skin contact. - -/datum/reagent/toxin/affect_blood(mob/living/carbon/M, alien, removed) - if(strength && alien != IS_DIONA) - if(issmall(M)) removed *= 2 // Small bodymass, more effect from lower volume. - if(alien == IS_SLIME) - removed *= 0.25 // Results in half the standard tox as normal. Prometheans are 'Small' for flaps. - if(dose >= 10) - M.nutrition += strength * removed //Body has to deal with the massive influx of toxins, rather than try using them to repair. - else - M.heal_organ_damage((10/strength) * removed, (10/strength) * removed) //Doses of toxins below 10 units, and 10 strength, are capable of providing useful compounds for repair. - M.adjustToxLoss(strength * removed) - -/datum/reagent/toxin/affect_touch(mob/living/carbon/M, alien, removed) - affect_blood(M, alien, removed * 0.2) - /datum/reagent/toxin/plasticide name = "Plasticide" id = "plasticide" @@ -64,7 +37,7 @@ strength = 8 skin_danger = 0.4 -/datum/reagent/toxin/neurotoxic_protein/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/toxin/neurotoxic_protein/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien != IS_DIONA) if(CHECK_MOBILITY(M, MOBILITY_CAN_MOVE) && istype(M.loc, /turf/space)) @@ -87,7 +60,7 @@ if(istype(L)) L.adjust_fire_stacks(amount / fire_mult) -/datum/reagent/toxin/hydrophoron/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/toxin/hydrophoron/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.take_random_targeted_damage(brute = 0, brute = removed * 0.1) //being splashed directly with hydrophoron causes minor chemical burns if(prob(10 * fire_mult)) M.pl_effects() @@ -101,7 +74,7 @@ spawn (0) target_tile.hotspot_expose(700, 400) remove_self(volume) -/datum/reagent/toxin/hydrophoron/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/toxin/hydrophoron/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_SLIME) M.adjust_fire_stacks(removed * 10) @@ -132,7 +105,7 @@ if(istype(L)) L.adjust_fire_stacks(amount / 5) -/datum/reagent/toxin/phoron/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/toxin/phoron/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() M.adjust_fire_stacks(removed / 5) if(alien == IS_VOX || alien == IS_XENOHYBRID) @@ -141,7 +114,7 @@ if(prob(50)) M.pl_effects() -/datum/reagent/toxin/phoron/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/toxin/phoron/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_VOX) M.adjustOxyLoss(-100 * removed) //5 oxyloss healed per tick. return //You're wasting plasma (a semi-limited chemical) to save someone, so it might as well be somewhat strong. @@ -154,7 +127,7 @@ /datum/reagent/toxin/phoron/touch_turf(turf/simulated/T, amount) if(!istype(T)) return - T.assume_gas(GAS_ID_VOLATILE_FUEL, amount, T20C) + T.assume_gas(GAS_ID_PHORON, amount, T20C) remove_self(amount) /datum/reagent/toxin/cyanide //Fast and Lethal @@ -166,9 +139,9 @@ reagent_state = REAGENT_LIQUID color = "#CF3600" strength = 20 - metabolism = REM * 2 + metabolism_rate = REM * 2 -/datum/reagent/toxin/cyanide/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/toxin/cyanide/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() M.adjustOxyLoss(20 * removed) M.afflict_sleeping(20 * 1) @@ -181,7 +154,7 @@ reagent_state = REAGENT_SOLID strength = 5 -/datum/reagent/toxin/mold/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/toxin/mold/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() M.adjustToxLoss(strength * removed) if(prob(5)) @@ -205,14 +178,13 @@ strength = 5 filtered_organs = list(O_SPLEEN) -/datum/reagent/toxin/expired_medicine/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/toxin/expired_medicine/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(prob(5)) M.vomit() -/datum/reagent/toxin/expired_medicine/affect_ingest(mob/living/carbon/M, alien, removed) - affect_blood(M, alien, removed * 0.66) - +/datum/reagent/toxin/expired_medicine/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + legacy_affect_blood(M, alien, removed * 0.66, metabolism) /datum/reagent/toxin/stimm //Homemade Hyperzine name = "Stimm" @@ -221,11 +193,11 @@ taste_description = "sweetness" taste_mult = 1.8 color = "#d0583a" - metabolism = REM * 3 + metabolism_rate = REM * 3 overdose = 10 strength = 3 -/datum/reagent/toxin/stimm/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/toxin/stimm/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_TAJARA) removed *= 1.25 ..() @@ -247,12 +219,12 @@ overdose = REAGENTS_OVERDOSE filtered_organs = list(O_SPLEEN, O_KIDNEYS) -/datum/reagent/toxin/potassium_chloride/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/toxin/potassium_chloride/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_SLIME) M.adjustFireLoss(removed * 2) -/datum/reagent/toxin/potassium_chloride/overdose(mob/living/carbon/M, alien) +/datum/reagent/toxin/potassium_chloride/legacy_affect_overdose(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(ishuman(M)) var/mob/living/carbon/human/H = M @@ -273,7 +245,7 @@ overdose = 20 filtered_organs = list(O_SPLEEN, O_KIDNEYS) -/datum/reagent/toxin/potassium_chlorophoride/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/toxin/potassium_chlorophoride/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(ishuman(M)) var/mob/living/carbon/human/H = M @@ -292,25 +264,26 @@ taste_description = "numbness" reagent_state = REAGENT_SOLID color = "#669900" - metabolism = REM + metabolism_rate = REM strength = 3 mrate_static = TRUE -/datum/reagent/toxin/zombiepowder/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/toxin/zombiepowder/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_DIONA) return M.status_flags |= STATUS_FAKEDEATH + addtimer(CALLBACK(M, __really_shitty_zombie_powder_shim), 0.5 SECONDS) M.adjustOxyLoss(3 * removed) - M.afflict_paralyze(20 * 10) + M.afflict_paralyze(20 SECONDS) M.silent = max(M.silent, 10) M.tod = stationtime2text() -/datum/reagent/toxin/zombiepowder/Destroy() - if(holder && holder.my_atom && ismob(holder.my_atom)) - var/mob/M = holder.my_atom - M.status_flags &= ~STATUS_FAKEDEATH - return ..() +/mob/living/carbon/proc/__really_shitty_zombie_powder_shim() + if(bloodstr.has_reagent(/datum/reagent/toxin/zombiepowder)) + return + status_flags &= ~STATUS_FAKEDEATH + update_mobility() /datum/reagent/toxin/lichpowder name = "Lich Powder" @@ -318,15 +291,16 @@ description = "A stablized nerve agent that puts the subject into a strange state of un-death." reagent_state = REAGENT_SOLID color = "#666666" - metabolism = REM * 0.75 + metabolism_rate = REM * 0.75 strength = 2 mrate_static = TRUE -/datum/reagent/toxin/lichpowder/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/toxin/lichpowder/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() if(alien == IS_DIONA) return M.status_flags |= STATUS_FAKEDEATH + addtimer(CALLBACK(M, __really_shitty_lich_powder_shim), 0.5 SECONDS) M.adjustOxyLoss(1 * removed) M.silent = max(M.silent, 10) M.tod = stationtime2text() @@ -335,11 +309,11 @@ M.visible_message("[M] wheezes.", "You wheeze sharply... it's cold.") M.bodytemperature = max(M.bodytemperature - 10 * TEMPERATURE_DAMAGE_COEFFICIENT, T0C - 10) -/datum/reagent/toxin/lichpowder/Destroy() - if(holder && holder.my_atom && ismob(holder.my_atom)) - var/mob/M = holder.my_atom - M.status_flags &= ~STATUS_FAKEDEATH - return ..() +/mob/living/carbon/proc/__really_shitty_lich_powder_shim() + if(bloodstr.has_reagent(/datum/reagent/toxin/lichpowder)) + return + status_flags &= ~STATUS_FAKEDEATH + update_mobility() /datum/reagent/toxin/fertilizer //Reagents used for plant fertilizers. name = "fertilizer" @@ -351,7 +325,7 @@ strength = 0.5 // It's not THAT poisonous. color = "#664330" -/datum/reagent/toxin/fertilizer/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/toxin/fertilizer/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_ALRAUNE) //cit change: fertilizer is full of natural easily digestible plant fats M.nutrition += removed * 5 return @@ -392,11 +366,11 @@ var/obj/structure/alien/weeds/alien_weeds = O alien_weeds.damage_integrity(15, 35) -/datum/reagent/toxin/plantbgone/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/toxin/plantbgone/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_ALRAUNE) M.adjustToxLoss(50 * removed) -/datum/reagent/toxin/plantbgone/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/toxin/plantbgone/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_ALRAUNE) M.adjustToxLoss(50 * removed) @@ -415,11 +389,11 @@ else if(istype(A, /mob/living/simple_mob/animal/giant_spider)) A.adjustToxLoss(5 * removed) -/datum/reagent/toxin/pestbgone/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/toxin/pestbgone/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_APIDAEN) M.adjustToxLoss(50 * removed) -/datum/reagent/toxin/pestbgone/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/toxin/pestbgone/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_APIDAEN) M.adjustToxLoss(50 * removed) @@ -433,7 +407,7 @@ strength = 2 overdose = 20 -/datum/reagent/toxin/sifslurry/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/toxin/sifslurry/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) // Symbiotic bacteria. M.nutrition += strength * removed return @@ -441,7 +415,7 @@ M.add_modifier(/datum/modifier/slow_pulse, 30 SECONDS) ..() -/datum/reagent/toxin/sifslurry/overdose(mob/living/carbon/M, alien, removed) // Overdose effect. +/datum/reagent/toxin/sifslurry/legacy_affect_overdose(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return if(ishuman(M)) @@ -450,8 +424,8 @@ M.afflict_radiation(RAD_MOB_AFFLICT_STRENGTH_SIFSLURRY_OD(removed)) M.apply_effect(5 * removed, DROWSY, 0, 0) -/datum/reagent/toxin/sifslurry/affect_ingest(mob/living/carbon/M, alien, removed) - affect_blood(M, alien, removed * 0.7) +/datum/reagent/toxin/sifslurry/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + legacy_affect_blood(M, alien, removed * 0.7, metabolism) /datum/reagent/acid/polyacid name = "Polytrinic acid" @@ -473,16 +447,13 @@ power = 2 meltdose = 30 -//Solid Chlorine is alkaline, but gaseous Chlorine is acidic. -/datum/reagent/acid/chlorine_gas +/datum/reagent/toxin/chlorine_gas name = "Chlorine gas" id = "chlorinegas" description = "A pungent yellow-green acidic gas." taste_description = "bleach" reagent_state = REAGENT_GAS color = "#c5f72d" - power = 5 - meltdose = 10 /datum/reagent/thermite/venom name = "Pyrotoxin" @@ -493,7 +464,7 @@ color = "#673910" touch_met = 50 -/datum/reagent/thermite/venom/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/thermite/venom/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.adjustFireLoss(3 * removed) if(M.fire_stacks <= 1.5) M.adjust_fire_stacks(0.15) @@ -514,7 +485,7 @@ color = "#B31008" filtered_organs = list(O_SPLEEN) -/datum/reagent/condensedcapsaicin/venom/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/condensedcapsaicin/venom/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return if(prob(50)) @@ -537,7 +508,7 @@ color = "#C8A5DC" overdose = REAGENTS_OVERDOSE -/datum/reagent/lexorin/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/lexorin/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return if(alien == IS_SLIME) @@ -565,15 +536,15 @@ reagent_state = REAGENT_LIQUID color = "#13BC5E" -/datum/reagent/mutagen/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/mutagen/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(prob(33)) - affect_blood(M, alien, removed) + legacy_affect_blood(M, alien, removed, metabolism) -/datum/reagent/mutagen/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/mutagen/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(prob(67)) - affect_blood(M, alien, removed) + legacy_affect_blood(M, alien, removed, metabolism) -/datum/reagent/mutagen/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/mutagen/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(M.isSynthetic()) return @@ -659,7 +630,7 @@ reagent_state = REAGENT_LIQUID color = "#801E28" -/datum/reagent/slimejelly/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/slimejelly/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return if(alien == IS_SLIME) //Partially made of the stuff. Why would it hurt them? @@ -682,7 +653,7 @@ reagent_state = REAGENT_LIQUID color = "#13BC5E" -/datum/reagent/advmutationtoxin/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/advmutationtoxin/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(ishuman(M)) var/mob/living/carbon/human/H = M if(H.species.get_species_id() != SPECIES_ID_PROMETHEAN) @@ -713,11 +684,11 @@ taste_description = "bitterness" reagent_state = REAGENT_LIQUID color = "#009CA8" - metabolism = REM * 0.5 + metabolism_rate = REM * 0.5 ingest_met = REM * 1.5 overdose = REAGENTS_OVERDOSE -/datum/reagent/soporific/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/soporific/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return @@ -728,9 +699,7 @@ if(alien == IS_SLIME) threshold = 6 //Evens to 3 due to the fact they are considered 'small' for flaps. - var/effective_dose = dose - if(issmall(M)) - effective_dose *= 2 + var/effective_dose = metabolism.total_processed_dose if(effective_dose < 1 * threshold) if(effective_dose == metabolism * 2 || prob(5)) @@ -761,12 +730,12 @@ taste_description = "bitterness" reagent_state = REAGENT_SOLID color = "#000067" - metabolism = REM * 0.5 + metabolism_rate = REM * 0.5 ingest_met = REM * 1.5 overdose = REAGENTS_OVERDOSE * 0.5 overdose_mod = 5 //For that good, lethal feeling -/datum/reagent/chloralhydrate/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/chloralhydrate/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return @@ -777,7 +746,7 @@ if(alien == IS_SLIME) threshold = 6 //Evens to 3 due to the fact they are considered 'small' for flaps. - var/effective_dose = dose + var/effective_dose = metabolism.total_processed_dose if(issmall(M)) effective_dose *= 2 @@ -800,7 +769,7 @@ if(effective_dose > 1 * threshold) M.adjustToxLoss(removed) -/datum/reagent/chloralhydrate/overdose(mob/living/carbon/M, alien, removed) +/datum/reagent/chloralhydrate/legacy_affect_overdose(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) ..() M.SetLosebreath(10) M.adjustOxyLoss(removed * overdose_mod) @@ -826,10 +795,10 @@ taste_mult = 0.4 reagent_state = REAGENT_LIQUID color = "#60A584" - metabolism = REM * 0.5 + metabolism_rate = REM * 0.5 overdose = REAGENTS_OVERDOSE -/datum/reagent/space_drugs/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/space_drugs/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return @@ -853,10 +822,10 @@ taste_description = "bitterness" reagent_state = REAGENT_LIQUID color = "#202040" - metabolism = REM * 0.25 + metabolism_rate = REM * 0.25 overdose = REAGENTS_OVERDOSE -/datum/reagent/serotrotium/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/serotrotium/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return if(prob(7)) @@ -870,7 +839,7 @@ taste_description = "chalky bitterness" filtered_organs = list(O_SPLEEN) -/datum/reagent/serotrotium/venom/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/serotrotium/venom/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return if(prob(30)) @@ -886,10 +855,10 @@ taste_description = "sourness" reagent_state = REAGENT_LIQUID color = "#000055" - metabolism = REM * 0.5 + metabolism_rate = REM * 0.5 overdose = REAGENTS_OVERDOSE -/datum/reagent/cryptobiolin/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/cryptobiolin/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return var/drug_strength = 4 @@ -913,7 +882,7 @@ overdose = REAGENTS_OVERDOSE filtered_organs = list(O_SPLEEN) -/datum/reagent/impedrezene/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/impedrezene/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return M.jitteriness = max(M.jitteriness - 5, 0) @@ -931,10 +900,10 @@ taste_description = "sourness" reagent_state = REAGENT_LIQUID color = "#B31008" - metabolism = REM * 0.25 + metabolism_rate = REM * 0.25 overdose = REAGENTS_OVERDOSE -/datum/reagent/mindbreaker/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/mindbreaker/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return @@ -955,9 +924,9 @@ taste_description = "mushroom" color = "#E700E7" overdose = REAGENTS_OVERDOSE - metabolism = REM * 0.5 + metabolism_rate = REM * 0.5 -/datum/reagent/psilocybin/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/psilocybin/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return @@ -970,8 +939,8 @@ M.druggy = max(M.druggy, 30) - var/effective_dose = dose - if(issmall(M)) effective_dose *= 2 + var/effective_dose = metabolism.total_processed_dose + if(effective_dose < 1 * threshold) M.apply_effect(3, STUTTER) M.make_dizzy(5) @@ -1008,10 +977,10 @@ taste_mult = 1.6 reagent_state = REAGENT_LIQUID color = "#db2ed8" - metabolism = REM * 0.5 + metabolism_rate = REM * 0.5 overdose = REAGENTS_OVERDOSE -/datum/reagent/talum_quem/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/talum_quem/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return @@ -1037,7 +1006,7 @@ reagent_state = REAGENT_LIQUID color = "#13BC5E" -/datum/reagent/slimetoxin/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/slimetoxin/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(M.isSynthetic()) return @@ -1067,7 +1036,7 @@ reagent_state = REAGENT_LIQUID color = "#FF69B4" -/datum/reagent/aslimetoxin/affect_blood(mob/living/carbon/M, alien, removed) // TODO: check if there's similar code anywhere else +/datum/reagent/aslimetoxin/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) // TODO: check if there's similar code anywhere else if(M.isSynthetic()) return @@ -1103,15 +1072,15 @@ reagent_state = REAGENT_SOLID color = "#555555" mrate_static = TRUE - metabolism = 0.01 //Fast no more they stick in you for a long time + metabolism_rate = 0.01 //Fast no more they stick in you for a long time reagent_filter_flags = REAGENT_FILTER_NO_COMMON_BIOANALYSIS affects_robots = TRUE -/datum/reagent/nanite/shredding/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/nanite/shredding/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.adjustBruteLoss(40 * removed) //Bicaridine can outheal it (unless Metabolism is less then 75%). M.adjustOxyLoss(40 * removed) -/datum/reagent/nanite/shredding/affect_ingest(mob/living/carbon/M, alien, removed) //Now they can be used in chemsmoke (Nanite Kill Clouds) +/datum/reagent/nanite/shredding/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) //Now they can be used in chemsmoke (Nanite Kill Clouds) M.adjustBruteLoss(40 * removed) M.adjustOxyLoss(40 * removed) @@ -1124,11 +1093,11 @@ reagent_state = REAGENT_SOLID mrate_static = TRUE color = "#555555" - metabolism = 0.01 //No gimmick you just glow for longer now! + metabolism_rate = 0.01 //No gimmick you just glow for longer now! reagent_filter_flags = REAGENT_FILTER_NO_COMMON_BIOANALYSIS affects_robots = TRUE -/datum/reagent/nanite/irradiated/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/nanite/irradiated/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) // todo: this should be more brutal on people around the person without being too brutal on the person // new radiation just kind of scales pretty badly /// rads to everyone around you @@ -1136,7 +1105,7 @@ /// radiate the person a bit just in case they're armored M.rad_act(RAD_INTENSITY_CHEM_IRRADIATED_NANITES_SELF) -/datum/reagent/nanite/irradiated/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/nanite/irradiated/affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) radiation_pulse(M, RAD_INTENSITY_CHEM_IRRADIATED_NANITES) M.rad_act(RAD_INTENSITY_CHEM_IRRADIATED_NANITES_SELF) @@ -1149,31 +1118,22 @@ reagent_state = REAGENT_SOLID mrate_static = TRUE color = "#555555" - metabolism = 0.01 + metabolism_rate = 0.01 reagent_filter_flags = REAGENT_FILTER_NO_COMMON_BIOANALYSIS filtered_organs = list(O_SPLEEN) affects_robots = TRUE -/datum/reagent/nanite/neurophage/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/nanite/neurophage/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.adjustBrainLoss(20 * removed) // Alkysine can outheal it, however since mrate is so slow you need 5 times the Alky to fully heal through it M.adjustBruteLoss(20 * removed) - if(M.ingested) - for(var/datum/reagent/alkysine/R in M.ingested.reagent_list) //Alkysine takes a while to metabolize this means the brain shield Alkysine gives you wears off quicker - R.remove_self(removed * 10) - if(M.bloodstr) - for(var/datum/reagent/alkysine/R in M.bloodstr.reagent_list) //This is about triple alkysine's regular metabolization rate. - R.remove_self(removed * 10) - + M.ingested?.remove_reagent(/datum/reagent/alkysine, removed * 10) + M.bloodstr?.remove_reagent(/datum/reagent/alkysine, removed * 10) -/datum/reagent/nanite/neurophage/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/nanite/neurophage/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.adjustBrainLoss(20 * removed) M.adjustBruteLoss(20 * removed) - if(M.ingested) - for(var/datum/reagent/alkysine/R in M.ingested.reagent_list) - R.remove_self(removed * 10) - if(M.bloodstr) - for(var/datum/reagent/alkysine/R in M.bloodstr.reagent_list) - R.remove_self(removed * 10) + M.ingested?.remove_reagent(/datum/reagent/alkysine, removed * 10) + M.bloodstr?.remove_reagent(/datum/reagent/alkysine, removed * 10) /datum/reagent/nanite/heartkill name = "Heartkill Nanites" @@ -1184,21 +1144,20 @@ reagent_state = REAGENT_SOLID mrate_static = TRUE color = "#555555" - metabolism = 0.01 + metabolism_rate = 0.01 -/datum/reagent/nanite/heartkill/affect_ingest(mob/living/carbon/M, alien, removed) //Damage handled using the heart_attack() proc in heart.dm +/datum/reagent/nanite/heartkill/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) //Damage handled using the heart_attack() proc in heart.dm var/mob/living/carbon/human/H = M if(istype(H)) if(prob(5)) H.heart_attack() -/datum/reagent/nanite/heartkill/affect_blood(mob/living/carbon/M, alien, removed)//Damage handled using the heart_attack() proc in heart.dm +/datum/reagent/nanite/heartkill/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism)//Damage handled using the heart_attack() proc in heart.dm var/mob/living/carbon/human/H = M if(istype(H)) if(prob(5)) H.heart_attack() - //Special toxins for solargrubs //Moved from Chemistry-Reagents-Vore_vr.dm /datum/reagent/grubshock @@ -1207,30 +1166,25 @@ description = "A liquid that quickly dissapates to deliver a painful shock. It can also disable nanomachines in the body." reagent_state = REAGENT_LIQUID color = "#E4EC2F" - metabolism = 2.50 + metabolism_rate = 2.50 affects_robots = TRUE -/datum/reagent/grubshock/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/grubshock/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.electrocute_act(10 * removed, src, 1.0, BP_TORSO, 0) - if(M.ingested) - for(var/datum/reagent/nanite/R in M.ingested.reagent_list) - R.remove_self(removed * 30) - if(M.bloodstr) - for(var/datum/reagent/nanite/R in M.bloodstr.reagent_list) - R.remove_self(removed * 20) - + for(var/datum/reagent/nanite/path_check in M.ingested.get_reagent_datums()) + M.ingested.remove_reagent(path_check.id, removed * 30) + for(var/datum/reagent/nanite/path_check in M.bloodstr.get_reagent_datums()) + M.bloodstr.remove_reagent(path_check.id, removed * 30) -/datum/reagent/grubshock/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/grubshock/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.electrocute_act(10 * removed, src, 1.0, BP_TORSO, 0) - if(M.ingested) - for(var/datum/reagent/nanite/R in M.ingested.reagent_list) - R.remove_self(removed * 30) - if(M.bloodstr) - for(var/datum/reagent/nanite/R in M.bloodstr.reagent_list) - R.remove_self(removed * 20) + for(var/datum/reagent/nanite/path_check in M.ingested.get_reagent_datums()) + M.ingested.remove_reagent(path_check.id, removed * 30) + for(var/datum/reagent/nanite/path_check in M.bloodstr.get_reagent_datums()) + M.bloodstr.remove_reagent(path_check.id, removed * 30) -/datum/reagent/grubshock/affect_touch(mob/living/carbon/M, alien, removed) - M.electrocute_act(10 * volume, src, 1.0, BP_TORSO, 0) +/datum/reagent/grubshock/affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + M.electrocute_act(10 * removed, src, 1.0, BP_TORSO, 0) //This chem is for removing nanites without grubmeat /datum/reagent/lessershock @@ -1239,30 +1193,26 @@ description = "A liquidified Lithium-Iron-Phosphate battery. Can be used to deliver shocks to the body in order to counter hostile nanomachines." reagent_state = REAGENT_SOLID color = "#E4EC2F" - metabolism = 2.50 + metabolism_rate = 2.50 affects_robots = TRUE -/datum/reagent/lessershock/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/lessershock/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.electrocute_act(5 * removed, src, 1.0, BP_TORSO, 0) - if(M.ingested) - for(var/datum/reagent/nanite/R in M.ingested.reagent_list) - R.remove_self(removed) - if(M.bloodstr) - for(var/datum/reagent/nanite/R in M.bloodstr.reagent_list) - R.remove_self(removed) - -/datum/reagent/lessershock/affect_ingest(mob/living/carbon/M, alien, removed) + for(var/datum/reagent/nanite/path_check in M.ingested.get_reagent_datums()) + M.ingested.remove_reagent(path_check.id, removed) + for(var/datum/reagent/nanite/path_check in M.bloodstr.get_reagent_datums()) + M.bloodstr.remove_reagent(path_check.id, removed) + +/datum/reagent/lessershock/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.electrocute_act(5 * removed, src, 1.0, BP_TORSO, 0) - if(M.ingested) - for(var/datum/reagent/nanite/R in M.ingested.reagent_list) - R.remove_self(removed) - if(M.bloodstr) - for(var/datum/reagent/nanite/R in M.bloodstr.reagent_list) - R.remove_self(removed) + for(var/datum/reagent/nanite/path_check in M.ingested.get_reagent_datums()) + M.ingested.remove_reagent(path_check.id, removed) + for(var/datum/reagent/nanite/path_check in M.bloodstr.get_reagent_datums()) + M.bloodstr.remove_reagent(path_check.id, removed) -/datum/reagent/lessershock/affect_touch(mob/living/carbon/M, alien, removed) - M.electrocute_act(5 * volume, src, 1.0, BP_TORSO, 0) +/datum/reagent/lessershock/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + M.electrocute_act(5 * removed, src, 1.0, BP_TORSO, 0) /datum/reagent/asbestos //asbestos removal handled in under datum/reagent/respirodaxon name = "Asbestos" @@ -1271,15 +1221,15 @@ taste_description = "sharp dust" reagent_state = REAGENT_SOLID color = "#d8d6d6" - metabolism = 0.01 // Does not leave your system easily + metabolism_rate = 0.01 // Does not leave your system easily mrate_static = TRUE reagent_filter_flags = REAGENT_FILTER_NO_COMMON_BIOANALYSIS overdose = 10 -/datum/reagent/asbestos/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/asbestos/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.ingested.add_reagent(/datum/reagent/asbestos, 0.02) //No idea what to do with injected asbestos I will simply say it goes to your lungs faster. -/datum/reagent/asbestos/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/asbestos/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) var/mob/living/carbon/human/H = M if(prob(2)) M.emote("cough") @@ -1315,14 +1265,14 @@ taste_mult = 0 //It would be a rather bad if you could taste this poison reagent_state = REAGENT_SOLID color = "#A6FAFF" - metabolism = 0.01 //This is around 100 radiation a tick for a total of 5k radiaion a unit. Use stasis!!! + metabolism_rate = 0.01 //This is around 100 radiation a tick for a total of 5k radiaion a unit. Use stasis!!! mrate_static = TRUE reagent_filter_flags = REAGENT_FILTER_NO_COMMON_BIOANALYSIS -/datum/reagent/polonium/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/polonium/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.afflict_radiation(RAD_MOB_AFFLICT_STRENGTH_POL210(removed)) -/datum/reagent/polonium/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/polonium/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.afflict_radiation(RAD_MOB_AFFLICT_STRENGTH_POL210(removed)) /datum/reagent/polonium/touch_turf(turf/T) @@ -1340,10 +1290,10 @@ taste_description = "burning alcohol" color = "#404030" taste_mult = 0.1 - metabolism = 0.01 + metabolism_rate = 0.01 mrate_static = TRUE reagent_filter_flags = REAGENT_FILTER_NO_COMMON_BIOANALYSIS -/datum/reagent/superhol/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/superhol/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.bloodstr.add_reagent(/datum/reagent/ethanol, removed * 200) //Two Ethanol a tick enough so the drunkeness hits slow enough to be semi plausible M.add_chemical_effect(CE_ALCOHOL_TOXIC, 5) diff --git a/code/modules/reagents/chemistry/reagents/Chemistry-Topical.dm b/code/modules/reagents/chemistry/reagents/Chemistry-Topical.dm index 76fe7a487c03..4912da0706a4 100644 --- a/code/modules/reagents/chemistry/reagents/Chemistry-Topical.dm +++ b/code/modules/reagents/chemistry/reagents/Chemistry-Topical.dm @@ -8,7 +8,7 @@ taste_description = "Sourness" taste_mult = 2 - metabolism = REM / 2//The skin is not directly connected to any filter organs so reagents are removed much slower + metabolism_rate = REM / 2//The skin is not directly connected to any filter organs so reagents are removed much slower overdose = REAGENTS_OVERDOSE //Usually we want topicals to overdose just as other chems do. overdose_mod = 0.5 // deals little damage on overdose, because the chem should only be applied via touch. @@ -19,19 +19,21 @@ var/toxicity = 1//factor of toxin damage dealt by improper application -/datum/reagent/topical/affect_blood(mob/living/carbon/M, alien, removed) - if(alien != IS_DIONA) - M.adjustToxLoss(toxicity * removed)//if injected cause toxin damage - -/datum/reagent/topical/affect_ingest(mob/living/carbon/M, alien, removed) - if(alien != IS_DIONA) - if(prob(10) && toxicity)//If ingested, either throw up - M.vomit(1) - else//or half the reagent passes through into blood(rest is filtered off) and alittle bit affects the inner skin - affect_blood(M, alien, removed/2) - affect_touch(M, alien, removed/10) - -/datum/reagent/topical/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/topical/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + if(alien == IS_DIONA) + return + M.adjustToxLoss(toxicity * removed)//if injected cause toxin damage + +/datum/reagent/topical/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + if(alien == IS_DIONA) + return + if(prob(10) && toxicity)//If ingested, either throw up + M.vomit(1) + else//or half the reagent passes through into blood(rest is filtered off) and alittle bit affects the inner skin + legacy_affect_blood(M, alien, removed/2, metabolism) + legacy_affect_touch(M, alien, removed/10, metabolism) + +/datum/reagent/topical/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.ceiling_chemical_effect(CE_PAINKILLER, 1)//just so there is something here... /datum/reagent/topical/bicarilaze @@ -42,7 +44,7 @@ toxicity = 3 -/datum/reagent/topical/bicarilaze/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/topical/bicarilaze/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien != IS_DIONA) M.heal_organ_damage(6*removed,0)//Heal brute damage @@ -54,7 +56,7 @@ toxicity = 2 -/datum/reagent/topical/kelotalaze/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/topical/kelotalaze/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien != IS_DIONA) M.heal_organ_damage(0,6*removed)//Heal burns @@ -65,7 +67,7 @@ toxicity = 0 -/datum/reagent/topical/tricoralaze/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/topical/tricoralaze/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien != IS_DIONA) M.heal_organ_damage(3*removed,3*removed)//Heal both damage @@ -76,7 +78,7 @@ toxicity = 0 -/datum/reagent/topical/inaprovalaze/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/topical/inaprovalaze/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien != IS_DIONA) M.add_chemical_effect(CE_STABLE, 20)//Reduces bleeding rate, and allowes the patient to breath even when in shock M.ceiling_chemical_effect(CE_PAINKILLER, 40) @@ -96,14 +98,14 @@ name = "Neurolaze" id = "neurolaze" description = "Superficial painkiller, do not inject or ingest" - metabolism = REM * 2 //Nervocells absorb this chem super fast so much faster metabolism... + metabolism_rate = REM * 2 //Nervocells absorb this chem super fast so much faster metabolism... overdose = REAGENTS_OVERDOSE * 0.5 color = "#000000" toxicity = 5 -/datum/reagent/topical/neurolaze/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/topical/neurolaze/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien != IS_DIONA) M.ceiling_chemical_effect(CE_PAINKILLER, 100)//Half oxycodone M.make_jittery(50*removed)//Your nerves are itching @@ -112,20 +114,20 @@ if(prob(5))// Speed boost and emotes M.emote(pick("twitch", "blink_r", "shiver")) if(world.time > (data + (60*10))) - data = world.time + metabolism.blackboard["last-message"] = world.time to_chat(M, "You feel like all your nerves are itching.") -/datum/reagent/topical/neurolaze/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/topical/neurolaze/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien != IS_DIONA) M.apply_damage(5 * removed, DAMAGE_TYPE_HALLOSS)//holodeck boxing glove damage M.make_jittery(200) -/datum/reagent/topical/neurolaze/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/topical/neurolaze/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien != IS_DIONA) M.vomit() holder.remove_reagent("neurolaze", 10 * removed)//purges itself... -/datum/reagent/topical/neurolaze/overdose(mob/living/carbon/M, alien) +/datum/reagent/topical/neurolaze/legacy_affect_overdose(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien != IS_DIONA) M.adjustBrainLoss(0.1)//deals braindamage on overdose @@ -136,7 +138,7 @@ toxicity = 3 -/datum/reagent/topical/sterilaze/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/topical/sterilaze/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(ishuman(M)) var/mob/living/carbon/human/H = M for(var/obj/item/organ/external/O in H.bad_external_organs) @@ -150,7 +152,7 @@ toxicity = 1 -/datum/reagent/topical/cleansalaze/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/topical/cleansalaze/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien != IS_DIONA) M.cure_radiation(RAD_MOB_CURE_STRENGTH_CLEANSALAZE(removed)) @@ -161,12 +163,11 @@ toxicity = 0 -/datum/reagent/topical/lotion/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/topical/lotion/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if (alien != IS_DIONA) M.ceiling_chemical_effect(CE_PAINKILLER, 5)//Not really usefull but I guess a lotion would help alittle with pain - if(world.time > (data + (5*60*10))) - data = world.time - to_chat(M, "Your skin feels refreshed and sooth.") + if(prob(1)) + to_chat(M, "Your skin feels refreshed and soothed.") //Remove before merge /obj/item/storage/box/touch_bottles diff --git a/code/modules/reagents/chemistry/reagents/core/acid.dm b/code/modules/reagents/chemistry/reagents/core/acid.dm new file mode 100644 index 000000000000..c16eaffa43cf --- /dev/null +++ b/code/modules/reagents/chemistry/reagents/core/acid.dm @@ -0,0 +1,88 @@ +/datum/reagent/acid + name = "Sulphuric acid" + id = "sacid" + description = "A very corrosive mineral acid with the molecular formula H2SO4." + taste_description = "acid" + reagent_state = REAGENT_LIQUID + color = "#DB5008" + metabolism_rate = REM * 2 + touch_met = 50 // It's acid! + var/power = 5 + var/meltdose = 10 // How much is needed to melt + +/datum/reagent/acid/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + if(issmall(M)) removed *= 2 + M.take_random_targeted_damage(brute = 0, brute = removed * power * 2) + +/datum/reagent/acid/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) // This is the most interesting + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.head) + if(H.head.integrity_flags & INTEGRITY_ACIDPROOF) + to_chat(H, "Your [H.head] protects you from the acid.") + remove_self(volume) + return + else if(removed > meltdose) + to_chat(H, "Your [H.head] melts away!") + qdel(H.head) + H.update_inv_head(1) + H.update_hair(1) + removed -= meltdose + if(removed <= 0) + return + + if(H.wear_mask) + if(H.wear_mask.integrity_flags & INTEGRITY_ACIDPROOF) + to_chat(H, "Your [H.wear_mask] protects you from the acid.") + remove_self(volume) + return + else if(removed > meltdose) + to_chat(H, "Your [H.wear_mask] melts away!") + qdel(H.wear_mask) + H.update_inv_wear_mask(1) + H.update_hair(1) + removed -= meltdose + if(removed <= 0) + return + + if(H.glasses) + if(H.glasses.integrity_flags & INTEGRITY_ACIDPROOF) + to_chat(H, "Your [H.glasses] partially protect you from the acid!") + removed /= 2 + else if(removed > meltdose) + to_chat(H, "Your [H.glasses] melt away!") + qdel(H.glasses) + H.update_inv_glasses(1) + removed -= meltdose / 2 + if(removed <= 0) + return + + if(volume < meltdose) // Not enough to melt anything + M.take_random_targeted_damage(brute = 0, brute = removed * power * 0.2) //burn damage, since it causes chemical burns. Acid doesn't make bones shatter, like brute trauma would. + return + if(!M.unacidable && removed > 0) + if(istype(M, /mob/living/carbon/human) && volume >= meltdose) + var/mob/living/carbon/human/H = M + var/obj/item/organ/external/affecting = H.get_organ(BP_HEAD) + if(affecting) + affecting.inflict_bodypart_damage( + burn = removed * power * 0.1, + ) + if(prob(100 * removed / meltdose)) // Applies disfigurement + if (affecting.organ_can_feel_pain()) + H.emote("scream") + else + M.take_random_targeted_damage(brute = 0, brute = removed * power * 0.1) // Balance. The damage is instant, so it's weaker. 10 units -> 5 damage, double for pacid. 120 units beaker could deal 60, but a) it's burn, which is not as dangerous, b) it's a one-use weapon, c) missing with it will splash it over the ground and d) clothes give some protection, so not everything will hit + +/datum/reagent/acid/touch_obj(obj/O) + if(O.integrity_flags & INTEGRITY_INDESTRUCTIBLE) + return + // todo: newacid + if((istype(O, /obj/item) || istype(O, /obj/effect/plant)) && (volume > meltdose)) + var/obj/effect/debris/cleanable/molten_item/I = new/obj/effect/debris/cleanable/molten_item(O.loc) + I.desc = "Looks like this was \an [O] some time ago." + for(var/mob/M in viewers(5, O)) + to_chat(M, "\The [O] melts.") + qdel(O) + remove_self(meltdose) // 10 units of acid will not melt EVERYTHING on the tile + diff --git a/code/modules/reagents/chemistry/reagents/core/blood.dm b/code/modules/reagents/chemistry/reagents/core/blood.dm new file mode 100644 index 000000000000..18dbccf5a496 --- /dev/null +++ b/code/modules/reagents/chemistry/reagents/core/blood.dm @@ -0,0 +1,167 @@ +// todo: stuff in this file might need to be moved somewhere else, this being in reagents/core is weird. + +/** + * Blood. + * + * I'm not sure what you expected this to say. + * + * * `data_initializer`: `/datum/blood_mixture` instance + * * `data`: /datum/blood_mixture instance + */ +/datum/reagent/blood + name = "Blood" + id = "blood" + taste_description = "iron" + taste_mult = 1.3 + reagent_state = REAGENT_LIQUID + metabolism_rate = REM * 5 + mrate_static = TRUE + affects_dead = 1 //so you can pump blood into someone before defibbing them + color = "#A80000" + holds_data = TRUE + blood_content = 4 //How effective this is for vampires. + + glass_name = "tomato juice" + glass_desc = "Are you sure this is tomato juice?" + var/volume_mod = 1 // So if you add different subtypes of blood, you can affect how much vessel blood each unit of reagent adds + +/datum/reagent/blood/make_copy_data_initializer(datum/blood_mixture/data) + return data + +/datum/reagent/blood/mix_data(datum/blood_mixture/old_data, old_volume, datum/blood_mixture/new_data, new_volume, datum/reagent_holder/holder) + . = ..() + + #warn impl ; hard limit of 10 blood instances. also, dedupe. + +/datum/reagent/blood/on_touch_turf(turf/target, remaining, allocated, data) + . = ..() + +/datum/reagent/blood/ + +/datum/reagent/blood/touch_turf(turf/simulated/T) + if(!istype(T) || volume < 3) + return + if(!data["donor"] || istype(data["donor"], /mob/living/carbon/human)) + blood_splatter(T, src, 1) + else if(istype(data["donor"], /mob/living/carbon/alien)) + var/obj/effect/debris/cleanable/blood/B = blood_splatter(T, src, 1) + if(B) + B.blood_DNA["UNKNOWN DNA STRUCTURE"] = "X*" + +/datum/reagent/blood/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + + var/effective_dose = dose + if(issmall(M)) + effective_dose *= 2 + + var/nutritionvalue = 10 //for reference, normal nutrition has a value of about 30. + var/is_vampire = M.species.is_vampire + switch(alien) //unique interactions sorted from the species who benefit the least to the species who benefit the most. + if(IS_SKRELL) //arguing that blood is "meat" and is still toxic for the vegan skrell at least + if(effective_dose > 5) + if(!is_vampire) //a vetalan skrell sounds funny as hell + M.adjustToxLoss(removed) + if(effective_dose > 15) + if(!is_vampire) + M.adjustToxLoss(removed) + if(IS_SLIME) + nutritionvalue = 20 + if(data["species"] == M.species.name) //just 'inject' the blood if it happens to be promethean "blood". + M.inject_blood(src, volume * volume_mod) + remove_self(volume) + return + if(IS_TESHARI) //birb. + nutritionvalue = 30 + if(IS_UNATHI) //carnivorous lizord... + nutritionvalue = 45 + if(IS_ALRAUNE) //lorewise, alraune are meant to enjoy blood. + nutritionvalue = 60 + if(IS_CHIMERA) //obligate carnivores. + nutritionvalue = 80 + + if(is_vampire) + handle_vampire(M, alien, removed, is_vampire) + M.heal_organ_damage(0.7 * removed * volume_mod, 0) // Heals vampires more. + M.adjust_hydration(7 * removed) // Hydrates vetalan better. + M.add_chemical_effect(CE_BLOODRESTORE, 8 * removed) // Same rating as taking iron + else + M.adjust_nutrition(nutritionvalue * removed * volume_mod) + M.adjust_hydration(2 * removed) // Still has some water in the form of plasma. Hydrates less than a normal drink. + M.add_chemical_effect(CE_BLOODRESTORE, 4 * removed) //same rating as eating nutriment + if(effective_dose >= 20 && prob(10)) + M.vomit(FALSE, FALSE) //Drinking blood makes you vomit, due to the high iron content and unpleasant consistency + + if(data && data["virus2"]) + var/list/vlist = data["virus2"] + if(vlist.len) + for(var/ID in vlist) + var/datum/disease2/disease/V = vlist[ID] + if(V.spreadtype == "Contact") + infect_virus2(M, V.getcopy()) + +/datum/reagent/blood/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.isSynthetic()) + return + if(alien == IS_SLIME) + legacy_affect_ingest(M, alien, removed, metabolism) + return + if(data && data["virus2"]) + var/list/vlist = data["virus2"] + if(vlist.len) + for(var/ID in vlist) + var/datum/disease2/disease/V = vlist[ID] + if(V.spreadtype == "Contact") + infect_virus2(M, V.getcopy()) + if(data && data["antibodies"]) + M.antibodies |= data["antibodies"] + +/datum/reagent/blood/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + if(alien == IS_SLIME) //They don't have blood, so it seems weird that they would instantly 'process' the chemical like another species does. + legacy_affect_ingest(M, alien, removed, metabolism) + return + + if(M.isSynthetic()) + return + + if(ishuman(M)) + var/mob/living/carbon/human/H = M + + var/datum/reagent/blood/recipient = H.get_blood(H.vessel) + + if(recipient && blood_incompatible(data["blood_type"], recipient.data["blood_type"], data["species"], recipient.data["species"])) + H.inject_blood(src, removed * volume_mod) + + if(!H.isSynthetic() && data["species"] == "synthetic") // Remember not to inject oil into your veins, it's bad for you. + H.reagents.add_reagent("toxin", removed * 1.5) + + return + + M.inject_blood(src, volume * volume_mod) + remove_self(volume) + +// todo: this should be the same as /datum/reagent/blood! +/datum/reagent/blood/synthblood + name = "Synthetic blood" + id = "synthblood" + color = "#999966" + volume_mod = 2 + +/datum/reagent/blood/synthblood/initialize_data(newdata) + ..() + if(data && !data["blood_type"]) + data["blood_type"] = "O-" + +// todo: this should be the same as /datum/reagent/blood! +/datum/reagent/blood/bludbloodlight + name = "Synthetic blood" + id = "bludbloodlight" + color = "#999966" + volume_mod = 2 + +// todo: this should be the same as /datum/reagent/blood! +/datum/reagent/blood/bludbloodlight/initialize_data(newdata) + ..() + if(data && !data["blood_type"]) + data["blood_type"] = "AB+" diff --git a/code/modules/reagents/chemistry/reagents/core/elements.dm b/code/modules/reagents/chemistry/reagents/core/elements.dm index afcd425c111c..b20dfad06d44 100644 --- a/code/modules/reagents/chemistry/reagents/core/elements.dm +++ b/code/modules/reagents/chemistry/reagents/core/elements.dm @@ -26,12 +26,12 @@ color = "#1C1300" ingest_met = REM * 5 -/datum/reagent/carbon/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/carbon/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_DIONA) return - if(M.ingested && M.ingested.reagent_list.len > 1) // Need to have at least 2 reagents - cabon and something to remove - var/effect = 1 / (M.ingested.reagent_list.len - 1) - for(var/datum/reagent/R in M.ingested.reagent_list) + if(length(M.ingested.reagent_volumes) > 1) + var/effect = 1 / (length(M.ingested.reagent_volumes) - 1) + for(var/datum/reagent/R in M.ingested.get_reagent_datums()) if(R == src) continue M.ingested.remove_reagent(R.id, removed * effect) @@ -53,10 +53,10 @@ reagent_state = REAGENT_GAS color = "#d1db77" -/datum/reagent/chlorine/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/chlorine/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.take_random_targeted_damage(brute = 1*REM, brute = 0) -/datum/reagent/chlorine/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/chlorine/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.take_random_targeted_damage(brute = 1*REM, brute = 0) /datum/reagent/copper @@ -74,10 +74,10 @@ reagent_state = REAGENT_GAS color = "#808080" -/datum/reagent/fluorine/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/fluorine/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.adjustToxLoss(removed) -/datum/reagent/fluorine/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/fluorine/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.adjustToxLoss(removed) /datum/reagent/hydrogen @@ -96,7 +96,7 @@ reagent_state = REAGENT_SOLID color = "#353535" -/datum/reagent/iron/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/iron/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien != IS_DIONA) M.add_chemical_effect(CE_BLOODRESTORE, 8 * removed) @@ -108,7 +108,7 @@ reagent_state = REAGENT_SOLID color = "#808080" -/datum/reagent/lithium/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/lithium/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien != IS_DIONA) if(CHECK_MOBILITY(M, MOBILITY_CAN_MOVE) && istype(M.loc, /turf/space)) step(M, pick(GLOB.cardinal)) @@ -123,7 +123,7 @@ reagent_state = REAGENT_LIQUID color = "#484848" -/datum/reagent/mercury/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/mercury/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien != IS_DIONA) if(CHECK_MOBILITY(M, MOBILITY_CAN_MOVE) && istype(M.loc, /turf/space)) step(M, pick(GLOB.cardinal)) @@ -147,7 +147,7 @@ reagent_state = REAGENT_GAS color = "#808080" -/datum/reagent/oxygen/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/oxygen/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_VOX) M.adjustToxLoss(removed * 3) @@ -159,7 +159,7 @@ reagent_state = REAGENT_SOLID color = "#832828" -/datum/reagent/phosphorus/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/phosphorus/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_ALRAUNE) M.nutrition += removed * 2 //cit change - phosphorus is good for plants @@ -179,7 +179,7 @@ reagent_state = REAGENT_SOLID color = "#C7C7C7" -/datum/reagent/radium/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/radium/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(issmall(M)) removed *= 2 M.afflict_radiation(RAD_MOB_AFFLICT_STRENGTH_RADIUM(removed)) diff --git a/code/modules/reagents/chemistry/reagents/core/ethanol.dm b/code/modules/reagents/chemistry/reagents/core/ethanol.dm new file mode 100644 index 000000000000..b292ce39c89b --- /dev/null +++ b/code/modules/reagents/chemistry/reagents/core/ethanol.dm @@ -0,0 +1,155 @@ +#define ETHANOL_MET_DIVISOR 20 + +/datum/reagent/ethanol + name = "Ethanol" //Parent class for all alcoholic reagents. + id = "ethanol" + description = "A well-known alcohol with a variety of applications." + taste_description = "pure alcohol" + reagent_state = REAGENT_LIQUID + color = "#404030" + + metabolism_rate = REM/ETHANOL_MET_DIVISOR + + ingest_met = REM * 5 + + var/nutriment_factor = 0 + var/hydration_factor = 0 + var/proof = 200 + var/toxicity = 1 + + var/druggy = 0 + var/adj_temp = 0 + var/targ_temp = 310 + var/halluci = 0 + + glass_name = "ethanol" + glass_desc = "A well-known alcohol with a variety of applications." + +/datum/reagent/ethanol/touch_mob(mob/living/L, amount) + if(istype(L)) + L.adjust_fire_stacks(amount / 15) + +#define ABV (proof/200) + +/datum/reagent/ethanol/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) //This used to do just toxin. That's boring. Let's make this FUN. + var/strength_mod = 1 //Alcohol is 3x stronger when injected into the veins. + if(alien == IS_SKRELL) + strength_mod *= 5 + if(alien == IS_TAJARA) + strength_mod *= 1.25 + if(alien == IS_UNATHI) + strength_mod *= 0.75 + if(alien == IS_DIONA) + strength_mod = 0 + if(alien == IS_SLIME) + strength_mod *= 2 + if(alien == IS_ALRAUNE) + if(prob(5)) + to_chat(M, "You feel your leaves start to wilt.") + strength_mod *=5 //cit change - alcohol ain't good for plants + + var/effective_dose = volume * strength_mod * ABV * min(1,dose*(ETHANOL_MET_DIVISOR/10)) // give it 50 ticks to ramp up + M.add_chemical_effect(CE_ALCOHOL, 1) + if(HAS_TRAIT(M, TRAIT_ALCOHOL_INTOLERANT)) + if(proof > 0) + var/intolerant_dose = strength_mod*removed*ABV*10 + if(prob((intolerant_dose))) + M.add_chemical_effect(CE_ALCOHOL_TOXIC, 1) + M.adjustToxLoss(intolerant_dose) + return 0 + #define DOSE_LEVEL 6 + var/effect_level=round(effective_dose/DOSE_LEVEL) + if(effect_level != metabolism.blackboard["last-effect-level"]) + var/lowering=(metabolism.blackboard["last-effect-level"]>effect_level) + metabolism.blackboard["last-effect-level"]=effect_level + if(lowering) + switch(effect_level) + if(0) + to_chat(M,SPAN_NOTICE("You no longer feel under the influence.")) + if(1) + to_chat(M,SPAN_DANGER("You are no longer slurring your words as much.")) + if(2) + to_chat(M,SPAN_DANGER("You're not seeing double anymore.")) + if(3) + to_chat(M,SPAN_DANGER("You can walk straight again.")) + if(4) + to_chat(M,SPAN_DANGER("You no longer feel like you're going to puke.")) + if(5) + to_chat(M,SPAN_DANGER("You don't feel like you're going to pass out anymore.")) + if(6) + to_chat(M,SPAN_DANGER("You feel like you're out of the danger zone.")) + else + var/hydration_str="" + if(M.hydration<250) + hydration_str=" You're feeling a little dehydrated, too." + switch(effect_level) + if(1) + to_chat(M,SPAN_DANGER("You're starting to feel a little tipsy.[hydration_str]")) + M.dizziness=max(M.dizziness,150) + if(2) + to_chat(M,SPAN_DANGER("You're getting drunk.[hydration_str] Use the Feign Impairment verb if you want slurring.")) + if(3) + to_chat(M,SPAN_DANGER("You're seeing double![hydration_str]")) + M.eye_blurry=max(M.eye_blurry,30) + if(4) + to_chat(M,SPAN_DANGER("You can barely walk straight![hydration_str]")) + if(5) + to_chat(M,SPAN_USERDANGER("You feel like you might puke...[hydration_str]")) + if(6) + to_chat(M,SPAN_USERDANGER("Your eyelids feel heavy![hydration_str]")) + if(7) + to_chat(M,SPAN_USERDANGER("You are getting dangerously drunk![hydration_str]")) + var/hydration_removal=(clamp((M.hydration-150)/300,0,1)*effect_level) + max(0,(M.hydration-450)/300) + if(hydration_removal>0) + M.adjust_hydration(-hydration_removal) + volume-=removed*hydration_removal*3 + if(effect_level>=4 && prob(effect_level-2)) + M.Confuse(60) + if(effect_level>=5 && prob(effect_level-4) && !M.lastpuke) + M.vomit(1,0) + if(M.nutrition>=100) + volume-=DOSE_LEVEL/4 + if(effect_level>=6 && prob(effect_level-5)) + M.drowsyness=max(M.drowsyness,60) + if(effect_level>=7) + M.add_chemical_effect(CE_ALCOHOL_TOXIC, toxicity*strength_mod) + if(volume>DOSE_LEVEL*7) + volume-=REM // liver working overtime, or whatever (mostly to prevent people from always just dying from this) + #undef DOSE_LEVEL + return + +/datum/reagent/ethanol/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + if(issmall(M)) removed *= 2 + M.adjust_nutrition(nutriment_factor * removed) + M.adjust_hydration(hydration_factor * removed) + M.bloodstr.add_reagent("ethanol", removed * ABV) + if(druggy != 0) + M.druggy = max(M.druggy, druggy) + + if(adj_temp > 0 && M.bodytemperature < targ_temp) // 310 is the normal bodytemp. 310.055 + M.bodytemperature = min(targ_temp, M.bodytemperature + (adj_temp * TEMPERATURE_DAMAGE_COEFFICIENT)) + if(adj_temp < 0 && M.bodytemperature > targ_temp) + M.bodytemperature = min(targ_temp, M.bodytemperature - (adj_temp * TEMPERATURE_DAMAGE_COEFFICIENT)) + + if(halluci) + M.setHallucination(max(M.hallucination, halluci)) + return + +/datum/reagent/ethanol/touch_obj(obj/O) + if(istype(O, /obj/item/paper)) + var/obj/item/paper/paperaffected = O + paperaffected.clearpaper() + to_chat(usr, "The solution dissolves the ink on the paper.") + return + if(istype(O, /obj/item/book)) + if(volume < 5) + return + if(istype(O, /obj/item/book/tome)) + to_chat(usr, "The solution does nothing. Whatever this is, it isn't normal ink.") + return + var/obj/item/book/affectedbook = O + affectedbook.dat = null + to_chat(usr, "The solution dissolves the ink on the book.") + return + +#undef ABV diff --git a/code/modules/reagents/chemistry/reagents/core/toxin.dm b/code/modules/reagents/chemistry/reagents/core/toxin.dm new file mode 100644 index 000000000000..f1d6d8994e53 --- /dev/null +++ b/code/modules/reagents/chemistry/reagents/core/toxin.dm @@ -0,0 +1,27 @@ +// todo: replace with reagent effects +/datum/reagent/toxin + name = "toxin" + id = "toxin" + description = "A toxic chemical." + taste_description = "bitterness" + taste_mult = 1.2 + reagent_state = REAGENT_LIQUID + color = "#CF3600" + metabolism_rate = REM * 0.25 // 0.05 by default. Hopefully enough to get some help, or die horribly, whatever floats your boat + filtered_organs = list(O_LIVER, O_KIDNEYS) + var/strength = 4 // How much damage it deals per unit + var/skin_danger = 0.2 // The multiplier for how effective the toxin is when making skin contact. + +/datum/reagent/toxin/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + if(strength && alien != IS_DIONA) + if(issmall(M)) removed *= 2 // Small bodymass, more effect from lower volume. + if(alien == IS_SLIME) + removed *= 0.25 // Results in half the standard tox as normal. Prometheans are 'Small' for flaps. + if(metabolism.total_processed_dose >= 10) + M.nutrition += strength * removed //Body has to deal with the massive influx of toxins, rather than try using them to repair. + else + M.heal_organ_damage((10/strength) * removed, (10/strength) * removed) //Doses of toxins below 10 units, and 10 strength, are capable of providing useful compounds for repair. + M.adjustToxLoss(strength * removed) + +/datum/reagent/toxin/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + legacy_affect_blood(M, alien, removed * 0.2, metabolism) diff --git a/code/modules/reagents/chemistry/reagents/core/water.dm b/code/modules/reagents/chemistry/reagents/core/water.dm new file mode 100644 index 000000000000..bc41adf61509 --- /dev/null +++ b/code/modules/reagents/chemistry/reagents/core/water.dm @@ -0,0 +1,79 @@ +/// How much heat is removed when applied to a hot turf, in J/unit (19000 makes 120 u of water roughly equivalent to 4L) +#define WATER_LATENT_HEAT 19000 +/datum/reagent/water + name = "Water" + id = "water" + taste_description = "water" + description = "A ubiquitous chemical substance that is composed of hydrogen and oxygen." + reagent_state = REAGENT_LIQUID + color = "#0064C877" + metabolism_rate = REM * 10 + + glass_name = "water" + glass_desc = "The father of all refreshments." + + cup_name = "water" + cup_desc = "The father of all refreshments." + +/datum/reagent/water/on_touch_turf(turf/target, remaining, allocated, data) + . = ..() + + var/datum/gas_mixture/environment = target.return_air() + var/min_temperature = T0C + 100 // 100C, the boiling point of water + + var/hotspot = (locate(/atom/movable/fire) in target) + if(hotspot && !istype(target, /turf/space)) + var/datum/gas_mixture/lowertemp = target.remove_cell_volume() + lowertemp.temperature = max(min(lowertemp.temperature-2000, lowertemp.temperature / 2), 0) + lowertemp.react() + target.assume_air(lowertemp) + qdel(hotspot) + + if (environment && environment.temperature > min_temperature) // Abstracted as steam or something + var/removed_heat = between(0, allocated * WATER_LATENT_HEAT, -environment.get_thermal_energy_change(min_temperature)) + environment.adjust_thermal_energy(-removed_heat) + if (prob(5)) + target.visible_message("The water sizzles as it lands on \the [target]!") + else if(allocated >= 10) + if(istype(target, /turf/simulated)) + var/turf/simulated/simulated_target = target + simulated_target.wet_floor(1) + +/datum/reagent/water/on_touch_obj(obj/target, remaining, allocated, data, spread_between) + if(istype(target, /obj/item/reagent_containers/food/snacks/monkeycube)) + var/obj/item/reagent_containers/food/snacks/monkeycube/cube = target + if(!cube.wrapped) + cube.Expand() + else + target.water_act(allocated / 5) + var/effective = allocated || 10 + target.clean_radiation(RAD_CONTAMINATION_CLEANSE_POWER * (effective / 10), RAD_CONTAMINATION_CLEANSE_FACTOR ** (1 / (effective / 10))) + return ..() + +/datum/reagent/water/on_touch_mob(mob/target, remaining, allocated, data, zone) + if(isliving(target)) + var/mob/living/living_target = target + // First, kill slimes. + if(istype(living_target, /mob/living/simple_mob/slime)) + var/mob/living/simple_mob/slime/S = living_target + var/amt = 15 * allocated * (1-S.water_resist) + if(amt>0) + S.adjustToxLoss(amt) + S.visible_message("[S]'s flesh sizzles where the water touches it!", "Your flesh burns in the water!") + + // Then extinguish people on fire. + var/needed = living_target.fire_stacks * 5 + if(allocated > needed) + living_target.ExtinguishMob() + living_target.adjust_fire_stacks(-(allocated / 5)) + allocated -= needed + . += needed + + var/effective = allocated || 10 + target.clean_radiation(RAD_CONTAMINATION_CLEANSE_POWER * (effective / 10), RAD_CONTAMINATION_CLEANSE_FACTOR ** (1 / (effective / 10))) + return . + ..() + +/datum/reagent/water/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + //else + M.adjust_hydration(removed * 10) + ..() diff --git a/code/modules/reagents/chemistry/reagents/nutrition/nutriment.dm b/code/modules/reagents/chemistry/reagents/nutrition/nutriment.dm new file mode 100644 index 000000000000..510cfeb4df5d --- /dev/null +++ b/code/modules/reagents/chemistry/reagents/nutrition/nutriment.dm @@ -0,0 +1,93 @@ +/** + * datastruct for nutriment data. + */ +/datum/nutriment_data + /// were we cooked? + var/cooked = FALSE + /// taste list as "description" = amount + /// + /// * always sorted from largest to least + var/list/taste + /// total taste amount used for blending + var/taste_total = 0 + +/datum/nutriment_data/proc/set_taste(description, amount) + #warn impl + +/datum/nutriment_data/proc/add_taste(description, amount, skip_culling) + #warn impl ; cull if needed + + if(!skip_culling) + cull_taste() + +/datum/nutriment_data/proc/remove_taste(description, amount) + #warn impl + +/datum/nutriment_data/proc/cull_taste() + // this should be a define (10 being max) but idrc lol + taste?.len = min(length(taste), 10) + +/datum/nutriment_data/proc/merge_from(datum/nutriment_data/source) + for(var/description in source.taste) + var/power = source.taste[description] + add_taste(description, power, TRUE) + cull_taste() + cooked ||= source.cooked + +/datum/nutriment_data/clone(include_contents) + var/datum/nutriment_data/copying = new + copying.cooked = cooked + copying.taste = taste?.Copy() + copying.taste_total = taste_total + return copying + +/datum/nutriment_data/static_spawn_initializer + cooked = TRUE + +/datum/reagent/nutriment + name = "Nutriment" + id = "nutriment" + holds_data = TRUE + description = "All the vitamins, minerals, and carbohydrates the body needs in pure form." + taste_mult = 4 + reagent_state = REAGENT_SOLID + metabolism_rate = REM * 4 + ingest_met = REM * 4 + var/nutriment_factor = 30 // Per unit + var/hydration_factor = 0 //Per unit + var/injectable = 0 + color = "#664330" + +/datum/reagent/nutriment/make_copy_data_initializer(datum/nutriment_data/data) + return data + +/datum/reagent/nutriment/preprocess_data(datum/nutriment_data/data_initializer) + return data_initializer + +/datum/reagent/nutriment/mix_data(datum/nutriment_data/old_data, old_volume, datum/nutriment_data/new_data, new_volume, datum/reagent_holder/holder) + if(!istype(new_data)) + return old_data + old_data.merge_from(new_data) + return old_data + +/datum/reagent/nutriment/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + if(!injectable && alien != IS_SLIME && alien != IS_CHIMERA) + M.adjustToxLoss(0.1 * removed) + return + legacy_affect_ingest(M, alien, removed, metabolism) + +/datum/reagent/nutriment/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + switch(alien) + if(IS_DIONA) + return + if(IS_UNATHI) + removed *= 0.5 + if(IS_CHIMERA) + removed *= 0.25 + if(issmall(M)) + removed *= 2 // Small bodymass, more effect from lower volume. + M.heal_organ_damage(0.5 * removed, 0) + if(!M.species.is_vampire) // If this is set to 0, they don't get nutrition from food. + M.nutrition += nutriment_factor * removed // For hunger and fatness + M.adjust_hydration(hydration_factor * removed) + M.add_chemical_effect(CE_BLOODRESTORE, 4 * removed) diff --git a/code/modules/reagents/chemistry/reagents/nutrition/nutriment/coating.dm b/code/modules/reagents/chemistry/reagents/nutrition/nutriment/coating.dm new file mode 100644 index 000000000000..27a11cde3426 --- /dev/null +++ b/code/modules/reagents/chemistry/reagents/nutrition/nutriment/coating.dm @@ -0,0 +1,57 @@ +/* + Coatings are used in cooking. Dipping food items in a reagent container with a coating in it + allows it to be covered in that, which will add a masked overlay to the sprite. + Coatings have both a raw and a cooked image. Raw coating is generally unhealthy + Generally coatings are intended for deep frying foods +*/ + +/datum/reagent/nutriment/coating + name = "coating" + id = "coating" + nutriment_factor = 6 //Less dense than the food itself, but coatings still add extra calories + var/messaged = 0 + var/icon_raw + var/icon_cooked + var/coated_adj = "coated" + var/cooked_name = "coating" + +/datum/reagent/nutriment/coating/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + var/datum/nutriment_data/data = M.ingested.get_reagent_data(src) + //We'll assume that the batter isnt going to be regurgitated and eaten by someone else. Only show this once + if(!data.cooked) + if (!messaged) + to_chat(M, "Ugh, this raw [name] tastes disgusting.") + nutriment_factor *= 0.5 + messaged = 1 + + //Raw coatings will sometimes cause vomiting + if (prob(1)) + M.vomit() + ..() + +// todo: cooked_name isn't implemented right now! +#warn cooked name? + +/datum/reagent/nutriment/coating/batter + name = "batter mix" + cooked_name = "batter" + id = "batter" + color = "#f5f4e9" + reagent_state = REAGENT_LIQUID + icon_raw = "batter_raw" + icon_cooked = "batter_cooked" + coated_adj = "battered" + +/datum/reagent/nutriment/coating/beerbatter + name = "beer batter mix" + cooked_name = "beer batter" + id = "beerbatter" + color = "#f5f4e9" + reagent_state = REAGENT_LIQUID + icon_raw = "batter_raw" + icon_cooked = "batter_cooked" + coated_adj = "beer-battered" + +/datum/reagent/nutriment/coating/beerbatter/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + ..() + M.add_chemical_effect(CE_ALCOHOL, 0.02) //Very slightly alcoholic diff --git a/code/modules/reagents/chemistry/reagents/other/adminordrazine.dm b/code/modules/reagents/chemistry/reagents/other/adminordrazine.dm new file mode 100644 index 000000000000..771128523c1e --- /dev/null +++ b/code/modules/reagents/chemistry/reagents/other/adminordrazine.dm @@ -0,0 +1,64 @@ +/datum/reagent/adminordrazine //An OP chemical for admins + name = "Adminordrazine" + id = "adminordrazine" + description = "It's magic. We don't have to explain it." + taste_description = "bwoink" + reagent_state = REAGENT_LIQUID + color = "#C8A5DC" + affects_dead = 1 //This can even heal dead people. + metabolism_rate = 0.1 + mrate_static = TRUE //Just in case + + glass_name = "liquid gold" + glass_desc = "It's magic. We don't have to explain it." + +/datum/reagent/adminordrazine/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + legacy_affect_blood(M, alien, removed, metabolism) + +/datum/reagent/adminordrazine/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + M.setCloneLoss(0) + M.setOxyLoss(0) + M.radiation = 0 + M.heal_organ_damage(20,20) + M.adjustToxLoss(-20) + M.setHallucination(0) + M.setHalLoss(0) + M.setBrainLoss(0) + M.disabilities = 0 + M.sdisabilities = 0 + M.eye_blurry = 0 + M.remove_status_effect(/datum/status_effect/sight/blindness) + M.set_paralyzed(0) + M.set_stunned(0) + M.set_unconscious(0) + M.silent = 0 + M.dizziness = 0 + M.drowsyness = 0 + M.stuttering = 0 + M.SetConfused(0) + M.set_sleeping(0) + M.jitteriness = 0 + M.radiation = 0 + M.ExtinguishMob() + M.fire_stacks = 0 + if(M.bodytemperature > 310) + M.bodytemperature = max(310, M.bodytemperature - (40 * TEMPERATURE_DAMAGE_COEFFICIENT)) + else if(M.bodytemperature < 311) + M.bodytemperature = min(310, M.bodytemperature + (40 * TEMPERATURE_DAMAGE_COEFFICIENT)) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/wound_heal = 5 + for(var/obj/item/organ/external/O in H.bad_external_organs) + if(O.status & ORGAN_BROKEN) + O.mend_fracture() //Only works if the bone won't rebreak, as usual + for(var/datum/wound/W as anything in O.wounds) + if(W.bleeding()) + W.damage = max(W.damage - wound_heal, 0) + if(W.damage <= 0) + O.cure_exact_wound(W) + continue + if(W.internal) + W.damage = max(W.damage - wound_heal, 0) + if(W.damage <= 0) + O.cure_exact_wound(W) + continue diff --git a/code/modules/reagents/chemistry/reagents/other/carpet.dm b/code/modules/reagents/chemistry/reagents/other/carpet.dm new file mode 100644 index 000000000000..5344a51cbd1d --- /dev/null +++ b/code/modules/reagents/chemistry/reagents/other/carpet.dm @@ -0,0 +1,63 @@ +/datum/reagent/carpet + name = "Liquid Carpet" + id = "liquidcarpet" + description = "Liquified carpet fibers, ready for dyeing." + reagent_state = REAGENT_LIQUID + color = "#b51d05" + taste_description = "carpet" + +/datum/reagent/carpet/black + name = "Liquid Black Carpet" + id = "liquidcarpetb" + description = "Black Carpet Fibers, ready for reinforcement." + reagent_state = REAGENT_LIQUID + color = "#000000" + taste_description = "rare and ashy carpet" + +/datum/reagent/carpet/blue + name = "Liquid Blue Carpet" + id = "liquidcarpetblu" + description = "Blue Carpet Fibers, ready for reinforcement." + reagent_state = REAGENT_LIQUID + color = "#3f4aee" + taste_description = "commanding carpet" + +/datum/reagent/carpet/turquoise + name = "Liquid Turquoise Carpet" + id = "liquidcarpettur" + description = "Turquoise Carpet Fibers, ready for reinforcement." + reagent_state = REAGENT_LIQUID + color = "#0592b5" + taste_description = "water-logged carpet" + +/datum/reagent/carpet/sblue + name = "Liquid Silver Blue Carpet" + id = "liquidcarpetsblu" + description = "Silver Blue Carpet Fibers, ready for reinforcement." + reagent_state = REAGENT_LIQUID + color = "#0011ff" + taste_description = "sterile and medicinal carpet" + +/datum/reagent/carpet/clown + name = "Liquid Clown Carpet" + id = "liquidcarpetc" + description = "Clown Carpet Fibers.... No clowns were harmed in the making of this." + reagent_state = REAGENT_LIQUID + color = "#e925be" + taste_description = "clown shoes and banana peels" + +/datum/reagent/carpet/purple + name = "Liquid Purple Carpet" + id = "liquidcarpetp" + description = "Purple Carpet Fibers, ready for reinforcement." + reagent_state = REAGENT_LIQUID + color = "#a614d3" + taste_description = "bleeding edge carpet research" + +/datum/reagent/carpet/orange + name = "Liquid Orange Carpet" + id = "liquidcarpeto" + description = "Orange Carpet Fibers, ready for reinforcement." + reagent_state = REAGENT_LIQUID + color = "#f16e16" + taste_description = "extremely overengineered carpet" diff --git a/code/modules/reagents/chemistry/reagents/other/chalk_dust.dm b/code/modules/reagents/chemistry/reagents/other/chalk_dust.dm new file mode 100644 index 000000000000..78938ad06854 --- /dev/null +++ b/code/modules/reagents/chemistry/reagents/other/chalk_dust.dm @@ -0,0 +1,23 @@ +/datum/reagent/chalk_dust + name = "chalk dust" + id = "chalk_dust" + description = "Dusty powder obtained by grinding chalk." + taste_description = "powdered chalk" + reagent_state = REAGENT_LIQUID + color = "#FFFFFF" + overdose = 5 + +/datum/reagent/chalk_dust/red + name = "red chalk dust" + id = "chalk_dust_red" + color = "#aa0000" + +/datum/reagent/chalk_dust/black + name = "black chalk dust" + id = "chalk_dust_black" + color = "#180000" + +/datum/reagent/chalk_dust/blue + name = "blue chalk dust" + id = "chalk_dust_blue" + color = "#000370" diff --git a/code/modules/reagents/chemistry/reagents/other/cleaner.dm b/code/modules/reagents/chemistry/reagents/other/cleaner.dm index 37009458c0fc..47abb0d0f07a 100644 --- a/code/modules/reagents/chemistry/reagents/other/cleaner.dm +++ b/code/modules/reagents/chemistry/reagents/other/cleaner.dm @@ -24,7 +24,7 @@ for(var/mob/living/simple_mob/slime/M in T) M.adjustToxLoss(rand(5, 10)) -/datum/reagent/space_cleaner/affect_touch(mob/living/carbon/M, alien, removed) +/datum/reagent/space_cleaner/legacy_affect_touch(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) for(var/obj/item/held as anything in M.get_held_items()) held.clean_blood() if(M.wear_mask) @@ -51,7 +51,7 @@ return M.clean_blood() -/datum/reagent/space_cleaner/affect_ingest(mob/living/carbon/M, alien, removed) +/datum/reagent/space_cleaner/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) if(alien == IS_SLIME) M.adjustToxLoss(6 * removed) else diff --git a/code/modules/reagents/chemistry/reagents/other/crayon_dust.dm b/code/modules/reagents/chemistry/reagents/other/crayon_dust.dm new file mode 100644 index 000000000000..d25059e2f6ba --- /dev/null +++ b/code/modules/reagents/chemistry/reagents/other/crayon_dust.dm @@ -0,0 +1,48 @@ +/datum/reagent/crayon_dust + name = "Crayon dust" + id = "crayon_dust" + description = "Intensely coloured powder obtained by grinding crayons." + taste_description = "powdered wax" + reagent_state = REAGENT_LIQUID + color = "#888888" + overdose = 5 + +/datum/reagent/crayon_dust/red + name = "Red crayon dust" + id = "crayon_dust_red" + color = "#FE191A" + +/datum/reagent/crayon_dust/orange + name = "Orange crayon dust" + id = "crayon_dust_orange" + color = "#FFBE4F" + +/datum/reagent/crayon_dust/yellow + name = "Yellow crayon dust" + id = "crayon_dust_yellow" + color = "#FDFE7D" + +/datum/reagent/crayon_dust/green + name = "Green crayon dust" + id = "crayon_dust_green" + color = "#18A31A" + +/datum/reagent/crayon_dust/blue + name = "Blue crayon dust" + id = "crayon_dust_blue" + color = "#247CFF" + +/datum/reagent/crayon_dust/purple + name = "Purple crayon dust" + id = "crayon_dust_purple" + color = "#CC0099" + +/datum/reagent/crayon_dust/grey //Mime + name = "Grey crayon dust" + id = "crayon_dust_grey" + color = "#808080" + +/datum/reagent/crayon_dust/brown //Rainbow + name = "Brown crayon dust" + id = "crayon_dust_brown" + color = "#846F35" diff --git a/code/modules/reagents/chemistry/reagents/other/holywater.dm b/code/modules/reagents/chemistry/reagents/other/holywater.dm new file mode 100644 index 000000000000..97737d4e7b79 --- /dev/null +++ b/code/modules/reagents/chemistry/reagents/other/holywater.dm @@ -0,0 +1,16 @@ +/datum/reagent/water/holywater + name = "Holy Water" + id = "holywater" + description = "An ashen-obsidian-water mix, this solution will alter certain sections of the brain's rationality." + taste_description = "water" + color = "#E0E8EF" + mrate_static = TRUE + + glass_name = "holy water" + glass_desc = "An ashen-obsidian-water mix, this solution will alter certain sections of the brain's rationality." + +/datum/reagent/water/holywater/legacy_affect_ingest(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) + ..() + if(ishuman(M)) // Any location + if(M.mind && cult.is_antagonist(M.mind) && prob(10)) + cult.remove_antagonist(M.mind) diff --git a/code/modules/reagents/chemistry/reagents/other/luminol.dm b/code/modules/reagents/chemistry/reagents/other/luminol.dm new file mode 100644 index 000000000000..f2b39d9e74d2 --- /dev/null +++ b/code/modules/reagents/chemistry/reagents/other/luminol.dm @@ -0,0 +1,15 @@ +/datum/reagent/luminol + name = "Luminol" + id = "luminol" + description = "A compound that interacts with blood on the molecular level." + taste_description = "metal" + reagent_state = REAGENT_LIQUID + color = "#F2F3F4" + +/datum/reagent/luminol/on_touch_obj(obj/target, remaining, allocated, data, spread_between) + target.reveal_blood() + return ..() + +/datum/reagent/luminol/on_touch_mob(mob/target, remaining, allocated, data, zone) + target.reveal_blood() + return ..() diff --git a/code/modules/reagents/chemistry/reagents/other/marker_ink.dm b/code/modules/reagents/chemistry/reagents/other/marker_ink.dm new file mode 100644 index 000000000000..2e9a0deacd08 --- /dev/null +++ b/code/modules/reagents/chemistry/reagents/other/marker_ink.dm @@ -0,0 +1,53 @@ +/datum/reagent/marker_ink + name = "Marker ink" + id = "marker_ink" + description = "Intensely coloured ink used in markers." + taste_description = "extremely bitter" + reagent_state = REAGENT_LIQUID + color = "#888888" + overdose = 5 + +/datum/reagent/marker_ink/black + name = "Black marker ink" + id = "marker_ink_black" + color = "#000000" + +/datum/reagent/marker_ink/red + name = "Red marker ink" + id = "marker_ink_red" + color = "#FE191A" + +/datum/reagent/marker_ink/orange + name = "Orange marker ink" + id = "marker_ink_orange" + color = "#FFBE4F" + +/datum/reagent/marker_ink/yellow + name = "Yellow marker ink" + id = "marker_ink_yellow" + color = "#FDFE7D" + +/datum/reagent/marker_ink/green + name = "Green marker ink" + id = "marker_ink_green" + color = "#18A31A" + +/datum/reagent/marker_ink/blue + name = "Blue marker ink" + id = "marker_ink_blue" + color = "#247CFF" + +/datum/reagent/marker_ink/purple + name = "Purple marker ink" + id = "marker_ink_purple" + color = "#CC0099" + +/datum/reagent/marker_ink/grey //Mime + name = "Grey marker ink" + id = "marker_ink_grey" + color = "#808080" + +/datum/reagent/marker_ink/brown //Rainbow + name = "Brown marker ink" + id = "marker_ink_brown" + color = "#846F35" diff --git a/code/modules/reagents/chemistry/reagents/other/paint.dm b/code/modules/reagents/chemistry/reagents/other/paint.dm new file mode 100644 index 000000000000..9afb31806b07 --- /dev/null +++ b/code/modules/reagents/chemistry/reagents/other/paint.dm @@ -0,0 +1,54 @@ +/** + * data: #ffffffff 7-9 character rgb/rgba color string + */ +/datum/reagent/paint + name = "Paint" + id = "paint" + holds_data = TRUE + description = "This paint will stick to almost any object." + taste_description = "chalk" + reagent_state = REAGENT_LIQUID + color = "#808080" + overdose = REAGENTS_OVERDOSE * 0.5 + color_weight = 20 + +// todo: rework +/datum/reagent/paint/on_touch_turf(turf/target, remaining, allocated, data) + target.color = compute_color_with_data(data) + . = allocated + allocated -= allocated + . += ..() + +// todo: rework +/datum/reagent/paint/on_touch_obj(obj/target, remaining, allocated, data, spread_between) + target.color = compute_color_with_data(data) + . = allocated + allocated -= allocated + . += ..() + +// todo: rework +/datum/reagent/paint/on_touch_mob(mob/target, remaining, allocated, data, zone) + target.color = compute_color_with_data(data) + . = allocated + allocated -= allocated + . += ..() + +/datum/reagent/paint/compute_color_with_data(data) + return data || "#ffffff" + +/datum/reagent/paint/make_copy_data_initializer(data) + return data + +/datum/reagent/paint/preprocess_data(data_initializer) + return data_initializer + +/datum/reagent/paint/mix_data(old_data, old_volume, new_data, new_volume, datum/reagent_holder/holder) + var/total_volume = old_volume + new_volume + var/old_hex = uppertext(old_data || "#ffffff") + var/new_hex = uppertext(new_data || "#ffffff") + return rgb( + ((hex2num(copytext(old_hex, 2, 4)) * old_volume) + (hex2num(copytext(new_hex, 2, 4)))) / total_volume, + ((hex2num(copytext(old_hex, 4, 6)) * old_volume) + (hex2num(copytext(new_hex, 4, 6)))) / total_volume, + ((hex2num(copytext(old_hex, 6, 8)) * old_volume) + (hex2num(copytext(new_hex, 6, 8)))) / total_volume, + ((hex2num(length(old_hex) > 7 ? copytext(old_hex, 8, 10) : 255) * old_volume) + (hex2num(length(new_hex) > 7 ? copytext(new_hex, 8, 10) : 255))) / total_volume, + ) diff --git a/code/modules/reagents/chemistry/reagents/pyrotechnics/thermite.dm b/code/modules/reagents/chemistry/reagents/pyrotechnics/thermite.dm index a7b6b7ef82dd..a28b950de217 100644 --- a/code/modules/reagents/chemistry/reagents/pyrotechnics/thermite.dm +++ b/code/modules/reagents/chemistry/reagents/pyrotechnics/thermite.dm @@ -7,18 +7,22 @@ color = "#673910" touch_met = 50 -/datum/reagent/thermite/touch_turf(turf/T) - if(volume >= 5) - if(istype(T, /turf/simulated/wall)) - var/turf/simulated/wall/W = T - W.thermite = 1 - W.add_overlay(image('icons/effects/effects.dmi', icon_state = "#673910")) - remove_self(5) - return +/datum/reagent/thermite/on_touch_turf(turf/target, remaining, allocated, data) + // todo: refactor + if(allocated >= 5 && istype(target, /turf/simulated/wall)) + var/turf/simulated/wall/wall = target + wall.thermite = TRUE + wall.add_overlay(image('icons/effects/effects.dmi', icon_state = "#673910")) + allocated -= 5 + . += 5 + return . + ..() -/datum/reagent/thermite/touch_mob(mob/living/L, amount) - if(istype(L)) - L.adjust_fire_stacks(amount / 5) +/datum/reagent/thermite/on_touch_mob(mob/target, remaining, allocated, data, zone) + if(isliving(target)) + // todo: rework and actually use some + var/mob/living/living_target = target + living_target.adjust_fire_stacks(allocated / 5) + return ..() -/datum/reagent/thermite/affect_blood(mob/living/carbon/M, alien, removed) +/datum/reagent/thermite/legacy_affect_blood(mob/living/carbon/M, alien, removed, datum/reagent_metabolism/metabolism) M.adjustFireLoss(3 * removed) diff --git a/code/modules/reagents/exposedprocs.dm b/code/modules/reagents/exposedprocs.dm index 28fbe79acca1..fac249035fe3 100644 --- a/code/modules/reagents/exposedprocs.dm +++ b/code/modules/reagents/exposedprocs.dm @@ -12,9 +12,8 @@ if(!src) return reagents.trans_to_obj(D, amount_per_transfer_from_this) - D.color = mix_color_from_reagents(D.reagents.reagent_list) + D.color = D.reagents.get_color() D.set_up(my_target, spray_size, delay) - return /// Chem thrower style spray. If spray_size = null a random value from 6-8 will be chosen. /obj/item/proc/spray_at_wide(atom/A as mob|obj, var/amount_per_transfer_from_this = 10, var/spray_size = null, var/delay = 2) @@ -34,10 +33,9 @@ return playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1, -6) reagents.trans_to_obj(D, amount_per_transfer_from_this) - D.color = mix_color_from_reagents(D.reagents.reagent_list) + D.color = D.reagents.get_color() spray_size ? null : (spray_size = rand(6, 8)) D.set_up(my_target, spray_size, delay) - return /// Extinguisher spray, intended for use with afterattack. See '/obj/effect/water/proc/set_up' for more details. /obj/item/proc/extinguish_spray(atom/A as mob|obj|turf, var/mob/living/user, var/amount_per_transfer_from_this = 10, var/spray_size = 3, var/delay = 10, var/spray_particles = 3) diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/items/spray.dm similarity index 83% rename from code/modules/reagents/reagent_containers/spray.dm rename to code/modules/reagents/items/spray.dm index 914e7182d4a0..a3cd14b1fa32 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/items/spray.dm @@ -65,7 +65,7 @@ if(!src) return reagents.trans_to_obj(D, amount_per_transfer_from_this) - D.color = mix_color_from_reagents(D.reagents.reagent_list) + D.color = D.reagents.get_color() D.set_up(my_target, spray_size, 10) return @@ -222,40 +222,15 @@ . = ..() reagents.add_reagent("pestbgone", volume) -/obj/item/reagent_containers/spray/squirt - name = "HydroBlaster 4000" - desc = "A popular toy produced by Donk Co, the HydroBlaster 4000 is the latest in a long line of recreational pressurized water delivery systems." - icon = 'icons/obj/toy.dmi' - icon_state = "squirtgun" - item_state = "squirtgun" - w_class = WEIGHT_CLASS_NORMAL - volume = 100 - var/pumped = TRUE - materials_base = list(MAT_PLASTIC = 1500) - -/obj/item/reagent_containers/spray/squirt/Initialize(mapload) - . = ..() - reagents.add_reagent("water", volume) - -/obj/item/reagent_containers/spray/squirt/examine(mob/user, dist) - . = ..() - . += "The tank is [pumped ? "depressurized" : "pressurized"]." - -/obj/item/reagent_containers/spray/squirt/attack_self(mob/user, datum/event_args/actor/actor) - pumped = !pumped - to_chat(usr, "You pump the handle [pumped ? "to depressurize" : "to pressurize"] the tank.") +/obj/item/reagent_containers/spray/windowsealant + name = "Krak-b-gone" + desc = "A spray bottle of silicate sealant for rapid window repair." + icon = 'icons/obj/items_vr.dmi' + icon_state = "windowsealant" + item_state = "spraycan" + possible_transfer_amounts = null + volume = 80 -/obj/item/reagent_containers/spray/squirt/Spray_at(atom/A as mob|obj) - if(pumped) - to_chat(usr, "The tank has no pressure!") - return +/obj/item/reagent_containers/spray/windowsealant/Initialize(mapload) . = ..() - -/obj/item/reagent_containers/spray/squirt/nt - name = "HydroBlaster 4001" - desc = "A popular toy produced by Donk Co, the HydroBlaster 4001 is modeled in Nanotrasen corporate colors. This is largely considered a sarcastic gesture." - icon = 'icons/obj/toy.dmi' - icon_state = "squirtgun_nt" - item_state = "squirtgun_nt" - w_class = WEIGHT_CLASS_NORMAL - volume = 101 + reagents.add_reagent("silicate", 80) diff --git a/code/modules/reagents/items/spray/squirt.dm b/code/modules/reagents/items/spray/squirt.dm new file mode 100644 index 000000000000..554aca748d69 --- /dev/null +++ b/code/modules/reagents/items/spray/squirt.dm @@ -0,0 +1,37 @@ +/obj/item/reagent_containers/spray/squirt + name = "HydroBlaster 4000" + desc = "A popular toy produced by Donk Co, the HydroBlaster 4000 is the latest in a long line of recreational pressurized water delivery systems." + icon = 'icons/obj/toy.dmi' + icon_state = "squirtgun" + item_state = "squirtgun" + w_class = WEIGHT_CLASS_NORMAL + volume = 100 + var/pumped = TRUE + materials_base = list(MAT_PLASTIC = 1500) + +/obj/item/reagent_containers/spray/squirt/Initialize(mapload) + . = ..() + reagents.add_reagent("water", volume) + +/obj/item/reagent_containers/spray/squirt/examine(mob/user, dist) + . = ..() + . += "The tank is [pumped ? "depressurized" : "pressurized"]." + +/obj/item/reagent_containers/spray/squirt/attack_self(mob/user, datum/event_args/actor/actor) + pumped = !pumped + to_chat(usr, "You pump the handle [pumped ? "to depressurize" : "to pressurize"] the tank.") + +/obj/item/reagent_containers/spray/squirt/Spray_at(atom/A as mob|obj) + if(pumped) + to_chat(usr, "The tank has no pressure!") + return + . = ..() + +/obj/item/reagent_containers/spray/squirt/nt + name = "HydroBlaster 4001" + desc = "A popular toy produced by Donk Co, the HydroBlaster 4001 is modeled in Nanotrasen corporate colors. This is largely considered a sarcastic gesture." + icon = 'icons/obj/toy.dmi' + icon_state = "squirtgun_nt" + item_state = "squirtgun_nt" + w_class = WEIGHT_CLASS_NORMAL + volume = 101 diff --git a/code/modules/reagents/items/spray/waterflower.dm b/code/modules/reagents/items/spray/waterflower.dm new file mode 100644 index 000000000000..808a7b87258d --- /dev/null +++ b/code/modules/reagents/items/spray/waterflower.dm @@ -0,0 +1,15 @@ + +/obj/item/reagent_containers/spray/waterflower + name = "water flower" + desc = "A seemingly innocent sunflower...with a twist." + icon = 'icons/obj/device.dmi' + icon_state = "sunflower" + item_state = "sunflower" + var/empty = 0 + slot_flags = SLOT_HOLSTER + damage_force = 0 + +/obj/item/reagent_containers/spray/waterflower/Initialize(mapload) + . = ..() + var/datum/reagent_holder/R = create_reagents(10) + R.add_reagent("water", 10) diff --git a/code/modules/reagents/machinery/chem_master.dm b/code/modules/reagents/machinery/chem_master.dm index 050d55ef6f81..32d211057ca8 100644 --- a/code/modules/reagents/machinery/chem_master.dm +++ b/code/modules/reagents/machinery/chem_master.dm @@ -243,10 +243,10 @@ var/beaker_contents[0] if(beaker) - for(var/datum/reagent/R in beaker.reagents.reagent_list) + for(var/datum/reagent/R in beaker.reagents.get_reagent_datums()) beaker_contents.Add(list(list( //! list in a list because Byond merges the first list... "name" = R.name, - "volume" = round(R.volume, 0.01), + "volume" = round(beaker.reagents.reagent_volumes[R.id], 0.01), "description" = R.description, "id" = R.id, ))) @@ -254,10 +254,10 @@ var/buffer_contents[0] if(reagents.total_volume) - for(var/datum/reagent/R in reagents.reagent_list) + for(var/datum/reagent/R in reagents.get_reagent_datums()) buffer_contents.Add(list(list( //! ^ "name" = R.name, - "volume" = round(R.volume, 0.01), + "volume" = round(reagents.reagent_volumes[R.id], 0.01), "description" = R.description, "id" = R.id, ))) @@ -382,7 +382,7 @@ if (style && style["name"] && !style["generate_name"]) name_default = style["name"] else - name_default = reagents.get_master_reagent_name() + name_default = reagents.get_majority_reagent_name() if (name_has_units) name_default += " ([vol_each]u)" name = tgui_input_text(usr, @@ -494,7 +494,7 @@ state = "Liquid" else if(initial(analyzed_reagent.reagent_state) == REAGENT_GAS) state = "Gas" - var/metabolization_rate = initial(analyzed_reagent.metabolism)// * (60 / SSMOBS_DT) + var/metabolization_rate = initial(analyzed_reagent.metabolism_rate)// * (60 / SSMOBS_DT) analyze_vars = list( "name" = initial(analyzed_reagent.name), "state" = state, @@ -773,8 +773,8 @@ */ /obj/machinery/chem_master/proc/guess_condi_style(datum/reagent_holder/reagents) var/list/styles = get_condi_styles() - if (reagents.reagent_list.len > 0) - var/main_reagent = reagents.get_master_reagent_id() + if (reagents.total_volume) + var/main_reagent = reagents.get_majority_reagent_id() if (main_reagent) var/list/path = splittext("[main_reagent]", "/") main_reagent = path[path.len] diff --git a/code/modules/reagents/machinery/reagent_dispenser.dm b/code/modules/reagents/machinery/reagent_dispenser.dm index f78c043b66d7..cb7cab583bea 100644 --- a/code/modules/reagents/machinery/reagent_dispenser.dm +++ b/code/modules/reagents/machinery/reagent_dispenser.dm @@ -32,10 +32,11 @@ /obj/structure/reagent_dispensers/examine(mob/user, dist) . = ..() if(get_dist(user, src) <= 2) + // todo: generic reagent examine . += "It contains:" - if(reagents && reagents.reagent_list.len) - for(var/datum/reagent/R in reagents.reagent_list) - . += "[R.volume] units of [R.name]" + if(reagents.total_volume) + for(var/datum/reagent/R in reagents?.get_reagent_datums()) + . += "[reagents.reagent_volumes[R.id]] units of [R.name]" else . += "Nothing." diff --git a/code/modules/reagents/machinery/reagent_dispenser/oil.dm b/code/modules/reagents/machinery/reagent_dispenser/oil.dm index e28b3074f4e1..01014b915cb2 100644 --- a/code/modules/reagents/machinery/reagent_dispenser/oil.dm +++ b/code/modules/reagents/machinery/reagent_dispenser/oil.dm @@ -20,16 +20,3 @@ /datum/reagent/nutriment/triglyceride/oil/tallow = 5000, ) starting_capacity = 5000 - -/obj/structure/reagent_dispensers/cookingoil/on_bullet_act(obj/projectile/proj, impact_flags, list/bullet_act_args) - . = ..() - if(proj.get_structure_damage()) - explode() - -/obj/structure/reagent_dispensers/cookingoil/legacy_ex_act() - explode() - -/obj/structure/reagent_dispensers/cookingoil/proc/explode() - reagents.splash_area(get_turf(src), 3) - visible_message(SPAN_DANGER("The [src] bursts open, spreading oil all over the area.")) - qdel(src) diff --git a/code/modules/reagents/machinery/reagent_dispenser/watercooler.dm b/code/modules/reagents/machinery/reagent_dispenser/watercooler.dm index 95e3b73397d5..6e019b73f0b1 100644 --- a/code/modules/reagents/machinery/reagent_dispenser/watercooler.dm +++ b/code/modules/reagents/machinery/reagent_dispenser/watercooler.dm @@ -45,9 +45,7 @@ if(do_after(user, 20) && bottle) to_chat(user, "You unfasten the jug.") var/obj/item/reagent_containers/glass/cooler_bottle/G = new /obj/item/reagent_containers/glass/cooler_bottle( src.loc ) - for(var/datum/reagent/R in reagents.reagent_list) - var/total_reagent = reagents.get_reagent_amount(R.id) - G.reagents.add_reagent(R.id, total_reagent) + reagents.transfer_to_holder(G.reagents) reagents.clear_reagents() bottle = 0 update_icon() @@ -94,9 +92,7 @@ bottle = 1 update_icon() to_chat(user, "You screw the bottle onto the water-cooler!") - for(var/datum/reagent/R in G.reagents.reagent_list) - var/total_reagent = G.reagents.get_reagent_amount(R.id) - reagents.add_reagent(R.id, total_reagent) + G.reagents.transfer_to_holder(reagents) qdel(G) else to_chat(user, "You need to wrench down the cooler first.") diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm index 92bade4d10e5..92cfd12cbc38 100644 --- a/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -36,7 +36,7 @@ if(blood_type != null) label_text = "[blood_type]" update_iv_label() - reagents.add_reagent("blood", 200, list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=blood_type,"resistances"=null,"trace_chem"=null)) + reagents.add_reagent("blood", 200, list("donor"=null,"blood_DNA"=null,"blood_type"=blood_type,"trace_chem"=null)) update_icon() /obj/item/reagent_containers/blood/on_reagent_change() diff --git a/code/modules/reagents/reagent_containers/blood_pack_vr.dm b/code/modules/reagents/reagent_containers/blood_pack_vr.dm index 7a7c947e2186..7dc1b88aa12f 100644 --- a/code/modules/reagents/reagent_containers/blood_pack_vr.dm +++ b/code/modules/reagents/reagent_containers/blood_pack_vr.dm @@ -8,8 +8,8 @@ if(user.a_intent == INTENT_HARM) if(reagents.total_volume && volume) var/remove_volume = volume* 0.1 //10% of what the bloodpack can hold. - var/reagent_to_remove = reagents.get_master_reagent_id() - switch(reagents.get_master_reagent_id()) + var/reagent_to_remove = reagents.get_majority_reagent_id() + switch(reagents.get_majority_reagent_id()) if("blood") user.show_message("You sink your fangs into \the [src] and suck the blood out of it!") user.visible_message("[user] sinks their fangs into \the [src] and drains it!") diff --git a/code/modules/reagents/reagent_containers/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm index 9d911d7b0e38..09cb9d1497de 100644 --- a/code/modules/reagents/reagent_containers/dropper.dm +++ b/code/modules/reagents/reagent_containers/dropper.dm @@ -17,7 +17,7 @@ /obj/item/reagent_containers/dropper/examine(mob/user, dist) . = ..() - if(reagents && reagents.reagent_list.len) + if(length(reagents?.reagent_volumes)) . += "It contains [reagents.total_volume] units of liquid." else . += "It is empty." diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm index 6088bce70717..0c28d99e2caf 100644 --- a/code/modules/reagents/reagent_containers/glass.dm +++ b/code/modules/reagents/reagent_containers/glass.dm @@ -128,7 +128,7 @@ return if(W && W.get_weight_class() <= get_weight_class() && (atom_flags & OPENCONTAINER)) to_chat(user, "You dip \the [W] into \the [src].") - reagents.touch_obj(W, reagents.total_volume) + reagents.auto_spill(W, 1, FALSE, TRUE) /obj/item/reagent_containers/glass/proc/update_name_label() if(label_text == "") @@ -375,9 +375,9 @@ /obj/item/reagent_containers/glass/bucket/sandstone/examine(mob/user, dist) . = ..() - if(reagents && reagents.reagent_list.len) - for(var/datum/reagent/R in reagents.reagent_list) - . += "[icon2html(thing = src, target = world)] The [src.name] currently contains [R.volume] units of [R.name]!" + if(reagents?.total_volume) + for(var/datum/reagent/R in reagents.get_reagent_datums()) + . += "[icon2html(thing = src, target = world)] The [src.name] currently contains [reagents.reagent_volumes[R.id]] units of [R.name]!" else . += "It is empty." @@ -462,9 +462,9 @@ /obj/item/reagent_containers/glass/stone/examine(mob/user, dist) . = ..() - if(reagents && reagents.reagent_list.len) - for(var/datum/reagent/R in reagents.reagent_list) - . += "[icon2html(thing = src, target = world)] The [src.name] currently contains [R.volume] units of [R.name]!" + if(reagents?.total_volume) + for(var/datum/reagent/R in reagents.get_reagent_datums()) + . += "[icon2html(thing = src, target = world)] The [src.name] currently contains [reagents.reagent_volumes[R.id]] units of [R.name]!" else . += "It is empty." diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 70066556c1fc..1edfecf79d6b 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -1,6 +1,7 @@ //////////////////////////////////////////////////////////////////////////////// /// HYPOSPRAY //////////////////////////////////////////////////////////////////////////////// +// todo: remove these, move behavior to /obj/item/autoinjector for autoinjectors /obj/item/reagent_containers/hypospray name = "hypospray" @@ -176,7 +177,7 @@ /obj/item/reagent_containers/hypospray/autoinjector/examine(mob/user, dist) . = ..() - if(reagents && reagents.reagent_list.len) + if(reagents?.total_volume) . += "It is currently loaded." else . += "It is spent." @@ -439,7 +440,7 @@ /obj/item/reagent_containers/hypospray/glukoz/examine(mob/user, dist) . = ..() - if(reagents && reagents.reagent_list.len) + if(reagents?.total_volume) . += "It is currently loaded." else . += "It is spent." diff --git a/code/modules/reagents/reagent_containers/organic.dm b/code/modules/reagents/reagent_containers/organic.dm index c6e8ade3ade2..cb7a545979e7 100644 --- a/code/modules/reagents/reagent_containers/organic.dm +++ b/code/modules/reagents/reagent_containers/organic.dm @@ -135,7 +135,7 @@ return if(W && W.get_weight_class() <= get_weight_class() && (atom_flags & OPENCONTAINER)) to_chat(user, "You dip \the [W] into \the [src].") - reagents.touch_obj(W, reagents.total_volume) + reagents.auto_spill(W, 1, FALSE, TRUE) /obj/item/reagent_containers/organic/proc/update_name_label() if(label_text == "") diff --git a/code/modules/reagents/reagent_containers/spray_vr.dm b/code/modules/reagents/reagent_containers/spray_vr.dm deleted file mode 100644 index 73915d211ebd..000000000000 --- a/code/modules/reagents/reagent_containers/spray_vr.dm +++ /dev/null @@ -1,12 +0,0 @@ -/obj/item/reagent_containers/spray/windowsealant - name = "Krak-b-gone" - desc = "A spray bottle of silicate sealant for rapid window repair." - icon = 'icons/obj/items_vr.dmi' - icon_state = "windowsealant" - item_state = "spraycan" - possible_transfer_amounts = null - volume = 80 - -/obj/item/reagent_containers/spray/windowsealant/Initialize(mapload) - . = ..() - reagents.add_reagent("silicate", 80) diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index fc1117b70ece..b36534e9887d 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -99,7 +99,7 @@ to_chat(user, "You are already drawing blood from [T.name].") return - var/datum/reagent/B + var/amount_drawn = 0 drawing = 1 if(istype(T, /mob/living/carbon/human)) var/mob/living/carbon/human/H = T @@ -110,20 +110,15 @@ if(!do_mob(user, target, time)) drawing = 0 return - B = T.take_blood(src, amount) + amount_drawn = T.take_blood_legacy(src, amount) drawing = 0 else if(!do_mob(user, target, time)) drawing = 0 return - B = T.take_blood(src,amount) + amount_drawn = T.take_blood_legacy(src,amount) drawing = 0 - if (B && !(B in reagents.reagent_list)) - reagents.reagent_list += B - reagents.update_total() - on_reagent_change() - reagents.reconsider_reactions() to_chat(user, "You take a blood sample from [target].") for(var/mob/O in viewers(4, user)) O.show_message("[user] takes a blood sample from [target].", 1) diff --git a/code/modules/research/machinery/rdconsole_tgui.dm b/code/modules/research/machinery/rdconsole_tgui.dm index ef76dd32287f..9707ad37077f 100644 --- a/code/modules/research/machinery/rdconsole_tgui.dm +++ b/code/modules/research/machinery/rdconsole_tgui.dm @@ -85,11 +85,11 @@ data["info"]["linked_lathe"]["mats"] = materials var/list/reagents = list() - for(var/datum/reagent/R in linked_lathe.reagents.reagent_list) + for(var/datum/reagent/R in linked_lathe.reagents.get_reagent_datums()) reagents.Add(list(list( "name" = R.name, "id" = R.id, - "volume" = R.volume, + "volume" = linked_lathe.reagents.reagent_volumes[R.id], ))) data["info"]["linked_lathe"]["reagents"] = reagents @@ -133,11 +133,11 @@ data["info"]["linked_imprinter"]["mats"] = materials var/list/reagents = list() - for(var/datum/reagent/R in linked_imprinter.reagents.reagent_list) + for(var/datum/reagent/R in linked_imprinter.reagents.get_reagent_datums()) reagents.Add(list(list( "name" = R.name, "id" = R.id, - "volume" = R.volume, + "volume" = linked_imprinter.reagents.reagent_volumes[R.id], ))) data["info"]["linked_imprinter"]["reagents"] = reagents diff --git a/code/modules/species/species.dm b/code/modules/species/species.dm index c94cfb4b646b..0b6326b0dbad 100644 --- a/code/modules/species/species.dm +++ b/code/modules/species/species.dm @@ -752,14 +752,9 @@ GLOBAL_LIST_INIT(species_oxygen_tank_by_gas, list( * this is a destructive proc and will erase incompatible blood. */ /datum/species/proc/create_blood(mob/living/carbon/human/H) - H.make_blood() - if(H.vessel.total_volume < blood_volume) - H.vessel.maximum_volume = blood_volume - H.vessel.add_reagent("blood", blood_volume - H.vessel.total_volume) - else if(H.vessel.total_volume > blood_volume) - H.vessel.remove_reagent("blood", H.vessel.total_volume - blood_volume) - H.vessel.maximum_volume = blood_volume - H.fixblood() + if(species_flags & NO_BLOOD) + else + H.create_blood() /datum/species/proc/hug(var/mob/living/carbon/human/H, var/mob/living/target) diff --git a/code/modules/species/station/station_special_abilities.dm b/code/modules/species/station/station_special_abilities.dm index b7debb074b5d..5dfb9a3d7d3d 100644 --- a/code/modules/species/station/station_special_abilities.dm +++ b/code/modules/species/station/station_special_abilities.dm @@ -75,8 +75,12 @@ revive_ready = REVIVING_READY //reset their cooldown /mob/living/carbon/human/proc/hasnutriment() - return (nutrition+ bloodstr.get_reagent("protein") * 10 + bloodstr.get_reagent("nutriment") * 5 + ingested.get_reagent("protein") * 5 + ingested.get_reagent("nutriment") * 2.5) > 425 - + . = nutrition + . += bloodstr.reagent_volumes[/datum/reagent/nutriment::id] * 5 + . += bloodstr.reagent_volumes[/datum/reagent/nutriment/protein::id] * 10 + . += ingested.reagent_volumes[/datum/reagent/nutriment::id] * 2.5 + . += ingested.reagent_volumes[/datum/reagent/nutriment/protein::id] * 5 + return . > 425 /mob/living/carbon/human/proc/hatch() set name = "Hatch" diff --git a/code/modules/species/station/xenomorph_hybrids/xeno_hybrids.dm b/code/modules/species/station/xenomorph_hybrids/xeno_hybrids.dm index 4f807228f546..c4f452a936b6 100644 --- a/code/modules/species/station/xenomorph_hybrids/xeno_hybrids.dm +++ b/code/modules/species/station/xenomorph_hybrids/xeno_hybrids.dm @@ -149,6 +149,6 @@ if(H.nutrition < 100 || heal_amount <= 0.6) return - if(H.vessel.get_reagent_amount("blood") <= blood_level_safe && H.try_take_nutrition(heal_amount * 4)) - H.vessel.add_reagent("blood", heal_amount)//instead of IB healing, they regenerate blood a lot faster + if(H.blood_holder.get_total_volume() <= blood_level_safe && H.try_take_nutrition(heal_amount * 4)) + H.regen_blood(heal_amount) diff --git a/code/modules/vehicles/sealed/mecha/equipment/tools/sleeper.dm b/code/modules/vehicles/sealed/mecha/equipment/tools/sleeper.dm index 1074fe36cf70..080453f54600 100644 --- a/code/modules/vehicles/sealed/mecha/equipment/tools/sleeper.dm +++ b/code/modules/vehicles/sealed/mecha/equipment/tools/sleeper.dm @@ -166,17 +166,19 @@ /obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_occupant_reagents() if(occupant_legacy.reagents) - for(var/datum/reagent/R in occupant_legacy.reagents.reagent_list) - if(R.volume > 0) - . += "[R]: [round(R.volume,0.01)]
" + for(var/datum/reagent/R in occupant_legacy.reagents.get_reagent_datums()) + var/volume = occupant_legacy.reagents.reagent_volumes[R.id] + if(volume > 0) + . += "[R]: [round(volume,0.01)]
" return . || "None" /obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_available_reagents() var/output var/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/SG = locate(/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun) in chassis - if(SG && SG.reagents && islist(SG.reagents.reagent_list)) - for(var/datum/reagent/R in SG.reagents.reagent_list) - if(R.volume > 0) + if(length(SG.reagents.reagent_volumes)) + for(var/datum/reagent/R in SG.reagents.get_reagent_datums()) + var/volume = occupant_legacy.reagents.reagent_volumes[R.id] + if(volume > 0) output += "Inject [R.name]
" return output @@ -184,7 +186,7 @@ /obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/inject_reagent(var/datum/reagent/R,var/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/SG) if(!R || !occupant_legacy || !SG || !(SG in chassis.equipment)) return 0 - var/to_inject = min(R.volume, inject_amount) + var/to_inject = min(SG.reagents.reagent_volumes[R.id], inject_amount) if(to_inject && occupant_legacy.reagents.get_reagent_amount(R.id) + to_inject > inject_amount*4) occupant_message("Sleeper safeties prohibit you from injecting more than [inject_amount*4] units of [R.name].") else @@ -194,7 +196,6 @@ SG.reagents.remove_reagent(R.id,to_inject) occupant_legacy.reagents.add_reagent(R.id,to_inject) update_equip_info() - return /obj/item/mecha_parts/mecha_equipment/tool/sleeper/update_equip_info() if(..()) @@ -202,7 +203,6 @@ send_byjax(chassis.occupant_legacy,"msleeper.browser","reagents",get_occupant_reagents()) send_byjax(chassis.occupant_legacy,"msleeper.browser","injectwith",get_available_reagents()) return 1 - return /obj/item/mecha_parts/mecha_equipment/tool/sleeper/verb/eject() set name = "Sleeper Eject" diff --git a/code/modules/vehicles/sealed/mecha/equipment/tools/syringe_gun.dm b/code/modules/vehicles/sealed/mecha/equipment/tools/syringe_gun.dm index b4783e26d63b..549d9170d684 100644 --- a/code/modules/vehicles/sealed/mecha/equipment/tools/syringe_gun.dm +++ b/code/modules/vehicles/sealed/mecha/equipment/tools/syringe_gun.dm @@ -192,9 +192,8 @@ /obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_current_reagents() var/output - for(var/datum/reagent/R in reagents.reagent_list) - if(R.volume > 0) - output += "[R]: [round(R.volume,0.001)] - Purge Reagent
" + for(var/datum/reagent/R in reagents.get_reagent_datums()) + output += "[R]: [round(reagents.reagent_volumes[R.id],0.001)] - Purge Reagent
" if(output) output += "Total: [round(reagents.total_volume,0.001)]/[reagents.maximum_volume] - Purge All" return output || "None" @@ -229,7 +228,7 @@ occupant_message("No reagent info gained from [A].") return 0 occupant_message("Analyzing reagents...") - for(var/datum/reagent/R in A.reagents.reagent_list) + for(var/datum/reagent/R in A.reagents.get_reagent_datums()) if(R.id in known_reagents) occupant_message("Reagent \"[R.name]\" already present in database, skipping.") else if(R.reagent_state == 2 && add_known_reagent(R.id,R.name)) diff --git a/code/modules/virus2/centrifuge.dm b/code/modules/virus2/centrifuge.dm index ffe41f72a5b9..0c71193850c1 100644 --- a/code/modules/virus2/centrifuge.dm +++ b/code/modules/virus2/centrifuge.dm @@ -136,7 +136,8 @@ . = TRUE /obj/machinery/computer/centrifuge/proc/cure() - if(!sample) return + if(!sample) + return var/datum/reagent/blood/B = locate(/datum/reagent/blood) in sample.reagents.reagent_list if(!B) return @@ -150,7 +151,8 @@ ping("\The [src] pings, \"Antibody isolated.\"") /obj/machinery/computer/centrifuge/proc/isolate() - if(!sample) return + if(!sample) + return var/obj/item/virusdish/dish = new/obj/item/virusdish(loc) dish.virus2 = virus2 virus2 = null diff --git a/code/modules/virus2/curer.dm b/code/modules/virus2/curer.dm index 4735ccdf43ce..55bfac0a6a9c 100644 --- a/code/modules/virus2/curer.dm +++ b/code/modules/virus2/curer.dm @@ -22,7 +22,7 @@ return var/obj/item/reagent_containers/glass/beaker/product = new(src.loc) - var/list/data = list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=null,"resistances"=null,"trace_chem"=null,"virus2"=list(),"antibodies"=list()) + var/list/data = list("donor"=null,"blood_DNA"=null,"blood_type"=null, "trace_chem"=null,"virus2"=list(),"antibodies"=list()) data["virus2"] |= I:virus2 product.reagents.add_reagent("blood",30,data) diff --git a/code/modules/virus2/dishincubator.dm b/code/modules/virus2/dishincubator.dm index eb32bee10fb0..91505b21df23 100644 --- a/code/modules/virus2/dishincubator.dm +++ b/code/modules/virus2/dishincubator.dm @@ -186,15 +186,11 @@ if (!dish) return 1 - var/datum/reagent/blood/B = locate(/datum/reagent/blood) in beaker.reagents.reagent_list - if (!B) - return 1 - - if (!B.data["virus2"]) - B.data["virus2"] = list() - - var/list/virus = list("[dish.virus2.uniqueID]" = dish.virus2.getcopy()) - B.data["virus2"] += virus + var/datum/blood_mixture/mixture = beaker.reagents.reagent_datas?[/datum/reagent/blood::id] + if(!mixture) + return TRUE + LAZYINITLIST(mixture.legacy_virus2) + mixture.legacy_virus2["[dish.virus2.uniqueID]"] = dish.virus2.getcopy() ping("\The [src] pings, \"Injection complete.\"") return 1 diff --git a/code/modules/virus2/isolator.dm b/code/modules/virus2/isolator.dm index 80093b43806d..72433b4d9235 100644 --- a/code/modules/virus2/isolator.dm +++ b/code/modules/virus2/isolator.dm @@ -61,18 +61,19 @@ var/list/pathogen_pool = list() if(sample) - for(var/datum/reagent/blood/B in sample.reagents.reagent_list) - var/list/virus = B.data["virus2"] + var/datum/blood_mixture/mixture = sample.reagents.get_reagent_data(/datum/reagent/blood) + for(var/datum/blood_fragment/blood_data as anything in mixture.fragments) + var/list/virus = blood_data.legacy_virus2 for (var/ID in virus) var/datum/disease2/disease/V = virus[ID] var/datum/data/record/R = null if (ID in virusDB) R = virusDB[ID] - var/mob/living/carbon/human/D = B.data["donor"] + var/mob/living/carbon/human/D = blood_data.legacy_donor pathogen_pool.Add(list(list(\ - "name" = "[D.get_true_species_name()] [B.name]", \ - "dna" = B.data["blood_DNA"], \ + "name" = "[D.get_true_species_name()] [B]", \ + "dna" = blood_data.legacy_blood_dna, \ "unique_id" = V.uniqueID, \ "reference" = "\ref[V]", \ "is_in_database" = !!R, \ @@ -158,11 +159,12 @@ P.info += "
" - for(var/datum/reagent/blood/B in sample.reagents.reagent_list) - var/mob/living/carbon/human/D = B.data["donor"] - P.info += "[D.get_true_species_name()] [B.name]:
[B.data["blood_DNA"]]
" + var/datum/blood_mixture/mixture = sample.reagents.get_reagent_data(/datum/reagent/blood) + for(var/datum/blood_fragment/blood_data as anything in mixture.fragments) + var/mob/living/carbon/human/D = blood_data.legacy_donor + P.info += "[D.get_true_species_name()] [B.name]:
[blood_data.legacy_blood_dna]
" - var/list/virus = B.data["virus2"] + var/list/virus = mixture.legacy_virus2 P.info += "Pathogens:
" if (virus.len > 0) for (var/ID in virus) diff --git a/code/modules/vore/eating/living_vr.dm b/code/modules/vore/eating/living_vr.dm index d7a14a5e4bfd..fda8e62b9ed8 100644 --- a/code/modules/vore/eating/living_vr.dm +++ b/code/modules/vore/eating/living_vr.dm @@ -341,8 +341,8 @@ if(ishuman(src)) var/mob/living/carbon/human/H = src - if(H.touching.reagent_list.len) // Just the first one otherwise I'll go insane. - var/datum/reagent/R = H.touching.reagent_list[1] + if(H.touching.total_volume) // Just the first one otherwise I'll go insane. + var/datum/reagent/R = H.touching.get_majority_reagent_datum() taste_message += " You also get the flavor of [R.taste_description] from something on them" return taste_message @@ -655,7 +655,7 @@ return if(istype(I,/obj/item/reagent_containers/hypospray/autoinjector)) var/obj/item/reagent_containers/hypospray/autoinjector/A = I - if(A.reagents && A.reagents.reagent_list.len) + if(A.reagents?.total_volume) if(istype(src,/mob/living/carbon/human)) //in case other mobs besides humans have trashcan trait to_chat(src, "[A] gets injected into you as you try to consume it!") A.do_injection(src,src) //a rather strange way of injecting yourself, don't you think? diff --git a/code/modules/xenoarcheaology/effects/heal.dm b/code/modules/xenoarcheaology/effects/heal.dm index 4cd6acd9c215..3bc9eba681bd 100644 --- a/code/modules/xenoarcheaology/effects/heal.dm +++ b/code/modules/xenoarcheaology/effects/heal.dm @@ -16,13 +16,13 @@ if(affecting && istype(affecting)) affecting.heal_damage(25 * weakness, 25 * weakness) //H:heal_organ_damage(25, 25) - H.vessel.add_reagent("blood",5) + H.blood_holder.adjust_host_volume(5) H.nutrition += 50 * weakness H.adjustBrainLoss(-25 * weakness) H.cure_radiation(RAD_MOB_CURE_ANOMALY_BURST * weakness) H.bodytemperature = initial(H.bodytemperature) spawn(1) - H.fixblood() + H.reset_blood_to_species() // C.adjustOxyLoss(-25 * weakness) C.adjustToxLoss(-25 * weakness) diff --git a/code/modules/xenoarcheaology/finds/special.dm b/code/modules/xenoarcheaology/finds/special.dm index 98b8a1f7ceda..327c097c72a3 100644 --- a/code/modules/xenoarcheaology/finds/special.dm +++ b/code/modules/xenoarcheaology/finds/special.dm @@ -128,7 +128,7 @@ B.target_turf = pick(range(1, src)) B.blood_DNA = list() B.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type - M.vessel.remove_reagent("blood",rand(25,50)) + M.erase_blood(rand(25, 50)) //animated blood 2 SPOOKY /obj/effect/debris/cleanable/blood/splatter/animated diff --git a/code/modules/xenoarcheaology/tools/geosample_scanner.dm b/code/modules/xenoarcheaology/tools/geosample_scanner.dm index d994f8a2ccf6..0b4a607016f1 100644 --- a/code/modules/xenoarcheaology/tools/geosample_scanner.dm +++ b/code/modules/xenoarcheaology/tools/geosample_scanner.dm @@ -101,7 +101,7 @@ fresh_coolant = 0 coolant_purity = 0 var/num_reagent_types = 0 - for (var/datum/reagent/current_reagent in reagents.reagent_list) + for (var/datum/reagent/current_reagent in reagents.get_reagent_datums()) if (!current_reagent) continue var/cur_purity = coolant_reagents_purity[current_reagent.id] @@ -109,8 +109,8 @@ cur_purity = 0.1 else if(cur_purity > 1) cur_purity = 1 - total_purity += cur_purity * current_reagent.volume - fresh_coolant += current_reagent.volume + total_purity += cur_purity * reagents.reagent_volumes[current_reagent.id] + fresh_coolant += reagents.reagent_volumes[current_reagent.id] num_reagent_types += 1 if(total_purity && fresh_coolant) coolant_purity = total_purity / fresh_coolant diff --git a/maps/away_missions/140x140/zoo.dmm b/maps/away_missions/140x140/zoo.dmm index d29742391bfd..c8a1ecf61e9c 100644 --- a/maps/away_missions/140x140/zoo.dmm +++ b/maps/away_missions/140x140/zoo.dmm @@ -3771,7 +3771,7 @@ /area/awaymission/zoo) "kv" = ( /obj/structure/table/rack, -/obj/item/toy/waterflower, +/obj/item/reagent_containers/spray/waterflower, /turf/simulated/floor/holofloor/carpet, /area/awaymission/zoo) "kw" = (