From 4f235496a1b05e9808dbd3c258eba3d07fb8b3f0 Mon Sep 17 00:00:00 2001 From: Noelle Lavenza Date: Sun, 1 Dec 2024 19:55:00 -0500 Subject: [PATCH] Make sharp weapons apply coating as reagents on hit --- code/game/objects/items/__item.dm | 36 +++++++++++++++++++++-- code/modules/mob/living/living_defense.dm | 13 ++++++-- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/code/game/objects/items/__item.dm b/code/game/objects/items/__item.dm index 69b1449b419..873cfc68b51 100644 --- a/code/game/objects/items/__item.dm +++ b/code/game/objects/items/__item.dm @@ -928,10 +928,11 @@ modules/mob/living/human/life.dm if you die, you will be zoomed out. /obj/item/proc/on_active_hand() return -/obj/item/proc/has_embedded(mob/living/victim) +/obj/item/proc/has_embedded(mob/living/victim, def_zone) if(istype(victim)) LAZYDISTINCTADD(victim.embedded, src) victim.verbs |= /mob/proc/yank_out_object + apply_coating_on_hit(null, victim, def_zone, embedded = TRUE) return TRUE return FALSE @@ -1005,9 +1006,40 @@ modules/mob/living/human/life.dm if you die, you will be zoomed out. /obj/item/proc/attack_message_name() return "\a [src]" +/// Returns the fraction of coating applied on a successful hit. +/obj/item/proc/get_coating_apply_fraction() + return is_sharp(src) ? 0.7 ** (w_class - 1) : 0 + +/// Returns the fraction of applied coating that enters the bloodstream on a successful hit. +/// This is applied to the result of get_coating_apply_fraction(). +/obj/item/proc/get_coating_inject_fraction() + // I put no thought into this implementation. + return is_sharp(src) ? 0.8 : 0.2 + +/obj/item/proc/get_coating_volume() + return round(10 * sqrt(w_class)) + +/// Returns the number of units applied. +/// User is allowed to be null, target must not be. +/obj/item/proc/apply_coating_on_hit(mob/user, mob/target, def_zone, embedded = FALSE) + if(coating?.total_liquid_volume <= 0) + return 0 + var/transferred_coating_amount = min(get_coating_apply_fraction(), coating.total_liquid_volume) + if(embedded) + transferred_coating_amount = coating.total_liquid_volume + else // user is allowed to be null + transferred_coating_amount *= (1 - get_blocked_ratio(def_zone, BRUTE, damage_flags(), armor_penetration, get_attack_force(user))) + if(transferred_coating_amount <= 0) + return 0 + // first apply the injected reagents + . = poisoned_weapon.coating.trans_to_mob(src, transferred_coating_amount * poisoned_weapon.get_coating_inject_fraction(), CHEM_INJECT, transferred_phases = MAT_PHASE_LIQUID) + transferred_coating_amount -= . + if(transferred_coating_amount > 0) + . += poisoned_weapon.coating.trans_to_mob(src, transferred_coating_amount, CHEM_TOUCH, transferred_phases = MAT_PHASE_LIQUID) + /obj/item/proc/add_coating(reagent_type, amount, data) if(!coating) - coating = new/datum/reagents(10, src) + coating = new/datum/reagents(get_coating_volume(), src) coating.add_reagent(reagent_type, amount, data) if(!blood_overlay) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 97fe9281e2c..89e9be16194 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -229,8 +229,8 @@ //Sharp objects will always embed if they do enough damage. //Thrown sharp objects have some momentum already and have a small chance to embed even if the damage is below the threshold if((sharp && prob(sharp_embed_chance)) || (embed_damage > embed_threshold && prob(embed_chance))) - affecting.embed_in_organ(I, supplied_wound = (istype(supplied_wound) ? supplied_wound : null)) - I.has_embedded(src) + affecting.embed_in_organ(I, supplied_wound = supplied_wound) + I.has_embedded(src, def_zone) . = TRUE // Simple embed for mobs with no limbs. @@ -238,9 +238,16 @@ O.forceMove(src) if(isitem(O)) var/obj/item/I = O - I.has_embedded(src) + I.has_embedded(src, def_zone) . = TRUE + // we want coated items to inject their coating if sharp and not embedded + // if it's embedded it's transferred separately in has_embedded + // todo: maybe check if the created wound is bleeding instead of checking if it's sharp + if(isitem(O) && !. && is_sharp(O)) + var/obj/item/poisoned_weapon = O + poisoned_weapon.apply_coating_on_hit(user, src, def_zone) + // Allow a tick for throwing/striking to resolve. if(. && direction) addtimer(CALLBACK(src, PROC_REF(check_embed_pinning), O, direction), 1)