mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 21:18:37 +01:00
Fixes a race condition in reagent metabolism (#86509)
## About The Pull Request Fixes a race condition that was causing organ damage to occur when it shouldn't be. The species `handle_chemical()` procs as well as the liver version of that same proc get called in `metabolize_reagent()`, and in those procs some toxins like carpotoxin get neutered. Problem was, `metabolize_reagent()` was not being called until after the organ damage calculation was already made using the un-neutered `toxpwr` value. Due to the way things are set up, the only option was to move the liver damage code into `metabolize()`. The code itself is functionally unchanged, it just has been relocated. This was a straightforward process and actually eliminated a for loop (as well as some duplicated code), so things may run a bit faster too. I did my best to keep it legible as possible. Fixes https://github.com/NovaSector/NovaSector/issues/2326 - this is what got me to investigate, the issue doesn't come up as often on TG but it becomes very obvious that something is not right when you have a species' own exotic blood causing organ damage when it's just supposed to be getting removed and added to blood_volume. This fixes that issue and any other similar ones. ## Why It's Good For The Game Species-specific damage immunities and such will now be respected. ## Changelog 🆑 fix: fixed a race condition that was causing carpotoxin to cause liver damage to felinids despite being immune /🆑 --------- Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com>
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
#define HAS_SILENT_TOXIN 0 //don't provide a feedback message if this is the only toxin present
|
||||
#define HAS_NO_TOXIN 1
|
||||
#define HAS_PAINFUL_TOXIN 2
|
||||
#define MAX_TOXIN_LIVER_DAMAGE 2 //the max damage the liver can receive per second (~1 min at max damage will destroy liver)
|
||||
|
||||
/**
|
||||
* Triggers metabolizing for all the reagents in this holder
|
||||
*
|
||||
@@ -16,16 +21,22 @@
|
||||
var/need_mob_update = FALSE
|
||||
var/obj/item/organ/internal/stomach/belly = owner.get_organ_slot(ORGAN_SLOT_STOMACH)
|
||||
var/obj/item/organ/internal/liver/liver = owner.get_organ_slot(ORGAN_SLOT_LIVER)
|
||||
var/liver_tolerance
|
||||
var/liver_tolerance = 0
|
||||
var/liver_damage = 0
|
||||
var/provide_pain_message
|
||||
var/amount
|
||||
if(liver)
|
||||
var/liver_health_percent = (liver.maxHealth - liver.damage) / liver.maxHealth
|
||||
liver_tolerance = liver.toxTolerance * liver_health_percent
|
||||
provide_pain_message = HAS_NO_TOXIN
|
||||
|
||||
for(var/datum/reagent/reagent as anything in cached_reagents)
|
||||
var/datum/reagent/toxin/toxin
|
||||
if(istype(reagent, /datum/reagent/toxin))
|
||||
toxin = reagent
|
||||
// skip metabolizing effects for small units of toxins
|
||||
if(istype(reagent, /datum/reagent/toxin) && liver && !dead)
|
||||
var/datum/reagent/toxin/toxin = reagent
|
||||
var/amount = toxin.volume
|
||||
if(toxin && liver && !dead)
|
||||
amount = toxin.volume
|
||||
if(belly)
|
||||
amount += belly.reagents.get_reagent_amount(toxin.type)
|
||||
|
||||
@@ -35,10 +46,35 @@
|
||||
|
||||
need_mob_update += metabolize_reagent(owner, reagent, seconds_per_tick, times_fired, can_overdose, liverless, dead)
|
||||
|
||||
// If applicable, calculate any toxin-related liver damage
|
||||
// Note: we have to do this AFTER metabolize_reagent, because we want handle_reagent to run before we make the determination.
|
||||
// The order is really important unfortunately.
|
||||
if(toxin && liver && liver.filterToxins && !HAS_TRAIT(owner, TRAIT_TOXINLOVER))
|
||||
if(toxin.affected_organ_flags && !(liver.organ_flags & toxin.affected_organ_flags)) //this particular toxin does not affect this type of organ
|
||||
continue
|
||||
|
||||
// a 15u syringe is a nice baseline to scale lethality by
|
||||
liver_damage += ((amount/15) * toxin.toxpwr * toxin.liver_damage_multiplier) / liver.liver_resistance
|
||||
|
||||
if(provide_pain_message != HAS_PAINFUL_TOXIN)
|
||||
provide_pain_message = toxin.silent_toxin ? HAS_SILENT_TOXIN : HAS_PAINFUL_TOXIN
|
||||
|
||||
// if applicable, apply our liver damage and display the accompanying pain message
|
||||
if(liver_damage)
|
||||
liver.apply_organ_damage(min(liver_damage * seconds_per_tick , MAX_TOXIN_LIVER_DAMAGE * seconds_per_tick))
|
||||
|
||||
if(provide_pain_message && liver.damage > 10 && SPT_PROB(liver.damage/6, seconds_per_tick)) //the higher the damage the higher the probability
|
||||
to_chat(owner, span_warning("You feel a dull pain in your abdomen."))
|
||||
|
||||
if(owner && need_mob_update) //some of the metabolized reagents had effects on the mob that requires some updates.
|
||||
owner.updatehealth()
|
||||
update_total()
|
||||
|
||||
#undef HAS_SILENT_TOXIN
|
||||
#undef HAS_NO_TOXIN
|
||||
#undef HAS_PAINFUL_TOXIN
|
||||
#undef MAX_TOXIN_LIVER_DAMAGE
|
||||
|
||||
/*
|
||||
* Metabolises a single reagent for a target owner carbon mob. See above.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#define LIVER_DEFAULT_TOX_TOLERANCE 3 //amount of toxins the liver can filter out
|
||||
#define LIVER_DEFAULT_TOX_RESISTANCE 1 //lower values lower how harmful toxins are to the liver
|
||||
#define LIVER_FAILURE_STAGE_SECONDS 60 //amount of seconds before liver failure reaches a new stage
|
||||
#define MAX_TOXIN_LIVER_DAMAGE 2 //the max damage the liver can receive per second (~1 min at max damage will destroy liver)
|
||||
|
||||
/obj/item/organ/internal/liver
|
||||
name = "liver"
|
||||
@@ -124,10 +123,6 @@
|
||||
continue
|
||||
ADD_TRAIT(replacement, readded_trait, JOB_TRAIT)
|
||||
|
||||
#define HAS_SILENT_TOXIN 0 //don't provide a feedback message if this is the only toxin present
|
||||
#define HAS_NO_TOXIN 1
|
||||
#define HAS_PAINFUL_TOXIN 2
|
||||
|
||||
/obj/item/organ/internal/liver/on_life(seconds_per_tick, times_fired)
|
||||
. = ..()
|
||||
//If your liver is failing, then we use the liverless version of metabolize
|
||||
@@ -136,34 +131,8 @@
|
||||
owner.reagents.metabolize(owner, seconds_per_tick, times_fired, can_overdose = TRUE, liverless = TRUE)
|
||||
return
|
||||
|
||||
var/obj/belly = owner.get_organ_slot(ORGAN_SLOT_STOMACH)
|
||||
var/list/cached_reagents = owner.reagents?.reagent_list
|
||||
var/liver_damage = 0
|
||||
var/provide_pain_message = HAS_NO_TOXIN
|
||||
|
||||
if(filterToxins && !HAS_TRAIT(owner, TRAIT_TOXINLOVER))
|
||||
for(var/datum/reagent/toxin/toxin in cached_reagents)
|
||||
if(toxin.affected_organ_flags && !(organ_flags & toxin.affected_organ_flags)) //this particular toxin does not affect this type of organ
|
||||
continue
|
||||
var/amount = toxin.volume
|
||||
if(belly)
|
||||
amount += belly.reagents.get_reagent_amount(toxin.type)
|
||||
|
||||
// a 15u syringe is a nice baseline to scale lethality by
|
||||
liver_damage += ((amount/15) * toxin.toxpwr * toxin.liver_damage_multiplier) / liver_resistance
|
||||
|
||||
if(provide_pain_message != HAS_PAINFUL_TOXIN)
|
||||
provide_pain_message = toxin.silent_toxin ? HAS_SILENT_TOXIN : HAS_PAINFUL_TOXIN
|
||||
|
||||
owner.reagents?.metabolize(owner, seconds_per_tick, times_fired, can_overdose = TRUE)
|
||||
|
||||
if(liver_damage)
|
||||
apply_organ_damage(min(liver_damage * seconds_per_tick , MAX_TOXIN_LIVER_DAMAGE * seconds_per_tick))
|
||||
|
||||
if(provide_pain_message && damage > 10 && SPT_PROB(damage/6, seconds_per_tick)) //the higher the damage the higher the probability
|
||||
to_chat(owner, span_warning("You feel a dull pain in your abdomen."))
|
||||
|
||||
|
||||
/obj/item/organ/internal/liver/handle_failing_organs(seconds_per_tick)
|
||||
if(HAS_TRAIT(owner, TRAIT_STABLELIVER) || HAS_TRAIT(owner, TRAIT_LIVERLESS_METABOLISM))
|
||||
return
|
||||
@@ -303,10 +272,6 @@
|
||||
. = ..()
|
||||
AddElement(/datum/element/dangerous_surgical_removal)
|
||||
|
||||
#undef HAS_SILENT_TOXIN
|
||||
#undef HAS_NO_TOXIN
|
||||
#undef HAS_PAINFUL_TOXIN
|
||||
#undef LIVER_DEFAULT_TOX_TOLERANCE
|
||||
#undef LIVER_DEFAULT_TOX_RESISTANCE
|
||||
#undef LIVER_FAILURE_STAGE_SECONDS
|
||||
#undef MAX_TOXIN_LIVER_DAMAGE
|
||||
|
||||
Reference in New Issue
Block a user