From 09acdfd92225de78f764f99057ba01d2063f221e Mon Sep 17 00:00:00 2001 From: Runa Dacino Date: Sun, 13 Aug 2023 20:08:17 +0200 Subject: [PATCH 1/4] fix(blood): Modifies remove_reagent calls to remove_blood calls Fixes https://github.com/VOREStation/VOREStation/issues/14817 remove_reagent has no sanitization for making sure the person has at least 1 u of blood remaining, and is therefore unsafe to use. This commit changes all human remove_reagent("blood", amt) calls with remove_blood(amt). This should prevent blood disappearing from internal bleeding or dragging someone while they're down or from drawing blood from them and so forth. Not all cases of remove_reagent("blood", amt) were changed, as some act on organs or other reagent containers not part of a human mob or because it's set_species --- code/game/gamemodes/cult/construct_spells.dm | 4 ++-- code/modules/mob/living/carbon/human/human.dm | 4 ++-- .../mob/living/simple_mob/subtypes/animal/sif/leech.dm | 2 +- code/modules/organs/blood.dm | 2 +- code/modules/organs/organ_external.dm | 2 +- code/modules/xenoarcheaology/effects/vampire.dm | 2 +- code/modules/xenoarcheaology/finds/special.dm | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/code/game/gamemodes/cult/construct_spells.dm b/code/game/gamemodes/cult/construct_spells.dm index 62cdd5bf48..6273273c98 100644 --- a/code/game/gamemodes/cult/construct_spells.dm +++ b/code/game/gamemodes/cult/construct_spells.dm @@ -472,7 +472,7 @@ var/mob/living/carbon/human/H = owner if(!H.should_have_organ(O_HEART)) return 1 - if(H.vessel.remove_reagent("blood", amount)) + if(H.remove_blood(amount)) return 1 return 0 @@ -673,4 +673,4 @@ else user.visible_message("\The [user] lowers its fist.") return - qdel(src) \ No newline at end of file + qdel(src) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index cc61ca0bd6..6ec2f0ae81 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1261,7 +1261,7 @@ vessel.maximum_volume = species.blood_volume vessel.add_reagent("blood", species.blood_volume - vessel.total_volume) else if(vessel.total_volume > species.blood_volume) - vessel.remove_reagent("blood", vessel.total_volume - species.blood_volume) + vessel.remove_reagent("blood",vessel.total_volume - species.blood_volume) //This one should stay remove_reagent to work even lack of a O_heart vessel.maximum_volume = species.blood_volume fixblood() species.update_attack_types() //VOREStation Edit - Required for any trait that updates unarmed_types in setup. @@ -1731,7 +1731,7 @@ if(blood_volume < species?.blood_volume*species?.blood_level_fatal) bloodtrail = 0 //Most of it's gone already, just leave it be else - vessel.remove_reagent("blood", 1) + remove_blood(1) if(bloodtrail) if(istype(loc, /turf/simulated)) var/turf/T = loc 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 d206cb5820..0b1c99d64b 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 @@ -183,7 +183,7 @@ if(!docile && ishuman(host) && chemicals < max_chemicals) var/mob/living/carbon/human/H = host - H.vessel.remove_reagent("blood", 1) + H.remove_blood(1) if(!H.reagents.has_reagent("inaprovaline")) H.reagents.add_reagent("inaprovaline", 1) chemicals += 2 diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm index 071bb05e91..b264c1eb95 100644 --- a/code/modules/organs/blood.dm +++ b/code/modules/organs/blood.dm @@ -260,7 +260,7 @@ var/const/CE_STABLE_THRESHOLD = 0.5 return null . = ..() - vessel.remove_reagent("blood",amount) // Removes blood if human + remove_blood(amount) // Removes blood if human //Transfers blood from container ot vessels /mob/living/carbon/proc/inject_blood(var/datum/reagent/blood/injected, var/amount) diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index 0c85e2aa27..b22ee48e98 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -750,7 +750,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 * wound_update_accuracy) - owner.vessel.remove_reagent("blood", wound_update_accuracy * W.damage/40) //line should possibly be moved to handle_blood, so all the bleeding stuff is in one place. + owner.remove_blood( wound_update_accuracy * W.damage/40) //line should possibly be moved to handle_blood, so all the bleeding stuff is in one place. if(prob(1 * wound_update_accuracy)) owner.custom_pain("You feel a stabbing pain in your [name]!", 50) diff --git a/code/modules/xenoarcheaology/effects/vampire.dm b/code/modules/xenoarcheaology/effects/vampire.dm index 29cabc5b2a..757f02889a 100644 --- a/code/modules/xenoarcheaology/effects/vampire.dm +++ b/code/modules/xenoarcheaology/effects/vampire.dm @@ -27,7 +27,7 @@ B.target_turf = pick(RANGE_TURFS(1, holder)) B.blood_DNA = list() B.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type - M.vessel.remove_reagent("blood",rand(10,30)) + M.remove_blood(rand(10,30)) /datum/artifact_effect/vampire/DoEffectTouch(var/mob/user) bloodcall(user) diff --git a/code/modules/xenoarcheaology/finds/special.dm b/code/modules/xenoarcheaology/finds/special.dm index e7c66148d5..af22d90dbf 100644 --- a/code/modules/xenoarcheaology/finds/special.dm +++ b/code/modules/xenoarcheaology/finds/special.dm @@ -134,7 +134,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.remove_blood(rand(25,50)) //animated blood 2 SPOOKY /obj/effect/decal/cleanable/blood/splatter/animated From 12bb4f00bf8f8fd557b9dbdb7854fd01fffa33c0 Mon Sep 17 00:00:00 2001 From: Runa Dacino Date: Sun, 13 Aug 2023 20:11:00 +0200 Subject: [PATCH 2/4] fix(blood): Moves bloodloss scaling to before sanity checks Mob size affects how much blood you should lose, by default 1 (20/20). However, in cases this is not true (non-medium mobs), this can lead to overflow of blood taken as this scaling happens AFTER we ensure amt is not greater than whatever it takes to get 1 blood. This should safeguard against that. --- code/modules/organs/blood.dm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm index b264c1eb95..c96a27e5d0 100644 --- a/code/modules/organs/blood.dm +++ b/code/modules/organs/blood.dm @@ -210,10 +210,12 @@ var/const/CE_STABLE_THRESHOLD = 0.5 if(!amt) return 0 + amt = amt * (src.mob_size/MOB_MEDIUM) + 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)) + return vessel.remove_reagent("blood",amt) /**************************************************** BLOOD TRANSFERS From f1b5e812ce3ccc7d0285cf77dcbf6ce2286b00a8 Mon Sep 17 00:00:00 2001 From: Runa Dacino Date: Sun, 13 Aug 2023 20:58:39 +0200 Subject: [PATCH 3/4] fix(blood): Creates fallback for non-existent blood datum. Also stops processing blood loss at 2.1. This allows the mob to regenerate some blood without losing any more, but I doubt anyone would farm a human mob for blood at a rate of 0.1 per multiple ticks. 2.1 is defined as a preprocessor #define to make it easier to sync stuff and avoid magic numbers. The fallback essentially follows the same procedures as a staff member would do to fix this issue: creates blood, sets their blood volume at species amount if wrong, fixes datums around blood. It logs failures and occurances. --- code/modules/organs/blood.dm | 47 ++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm index c96a27e5d0..5f7180e995 100644 --- a/code/modules/organs/blood.dm +++ b/code/modules/organs/blood.dm @@ -1,3 +1,4 @@ +#define BLOOD_MINIMUM_STOP_PROCESS 2.1 // Define to avoid hitting 0 blood. /**************************************************** BLOOD SYSTEM ****************************************************/ @@ -14,8 +15,12 @@ var/const/CE_STABLE_THRESHOLD = 0.5 /mob/living/carbon/human/var/datum/reagents/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() +/***Initializes blood vessels + * Called code/modules/mob/living/carbon/human/human.dm#L1259 set_species procedure with 0 args + * Also called by inject_blood as fallback with amt = injected_amount + * MUST be followed by calling fixblood() allways. +***/ +/mob/living/carbon/human/proc/make_blood(var/amt = 0) if(vessel) return @@ -29,7 +34,11 @@ var/const/CE_STABLE_THRESHOLD = 0.5 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) + if(!amt) + vessel.add_reagent("blood",species.blood_volume) + else + vessel.add_reagent("blood", clamp(amt, 1, species.blood_volume)) + //Resets blood data /mob/living/carbon/human/proc/fixblood() @@ -212,8 +221,12 @@ var/const/CE_STABLE_THRESHOLD = 0.5 amt = amt * (src.mob_size/MOB_MEDIUM) - 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. + var/current_blood = vessel.get_reagent_amount("blood") + if(current_blood < BLOOD_MINIMUM_STOP_PROCESS) + return 0 //We stop processing under 3 units of blood because apparently weird shit can make it overflowrandomly. + + if(amt > current_blood) + amt = current_blood - 2 // 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) @@ -258,7 +271,7 @@ var/const/CE_STABLE_THRESHOLD = 0.5 if(!should_have_organ(O_HEART)) return null - if(vessel.get_reagent_amount("blood") < amount) + if(vessel.get_reagent_amount("blood") < amount || vessel.get_reagent_amount("blood") < BLOOD_MINIMUM_STOP_PROCESS) return null . = ..() @@ -290,8 +303,28 @@ var/const/CE_STABLE_THRESHOLD = 0.5 var/datum/reagent/blood/our = get_blood(vessel) - if (!injected || !our) + if (!injected) return + if(!our) + log_debug("[src] has no blood reagent, proceeding with fallback reinitialization.") + var/vessel_old = vessel + vessel = null + qdel(vessel_old) + make_blood(amount) + if(!vessel) + log_debug("Failed to re-initialize blood datums on [src]!") + return + if(vessel.total_volume < species.blood_volume) + vessel.add_reagent("blood", species.blood_volume - vessel.total_volume) + else if(vessel.total_volume > species.blood_volume) + vessel.maximum_volume = species.blood_volume + fixblood() + our = get_blood(vessel) + if(!our) + log_debug("Failed to re-initialize blood datums on [src]!") + 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() From 62ffeb661ad8a4c5d7ca0cd988fe1be7605a7f2f Mon Sep 17 00:00:00 2001 From: Runa Dacino Date: Sat, 19 Aug 2023 00:03:57 +0200 Subject: [PATCH 4/4] tweak(blood): Implements Maintainer Requests removes(blood): Removes remove_blood scaling with mob size tweak(blood): Simplifies minimum process check in take_blood --- code/modules/organs/blood.dm | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm index 5f7180e995..9d36c005d0 100644 --- a/code/modules/organs/blood.dm +++ b/code/modules/organs/blood.dm @@ -219,8 +219,6 @@ var/const/CE_STABLE_THRESHOLD = 0.5 if(!amt) return 0 - amt = amt * (src.mob_size/MOB_MEDIUM) - var/current_blood = vessel.get_reagent_amount("blood") if(current_blood < BLOOD_MINIMUM_STOP_PROCESS) return 0 //We stop processing under 3 units of blood because apparently weird shit can make it overflowrandomly. @@ -271,7 +269,7 @@ var/const/CE_STABLE_THRESHOLD = 0.5 if(!should_have_organ(O_HEART)) return null - if(vessel.get_reagent_amount("blood") < amount || vessel.get_reagent_amount("blood") < BLOOD_MINIMUM_STOP_PROCESS) + if(vessel.get_reagent_amount("blood") < max(amount, BLOOD_MINIMUM_STOP_PROCESS)) return null . = ..()