From c9f44897ed216111a2edc6ee113d5dff68aaa71a Mon Sep 17 00:00:00 2001 From: nikothedude <59709059+nikothedude@users.noreply.github.com> Date: Wed, 20 Sep 2023 16:36:06 -0400 Subject: [PATCH] Augments/Prosthetic limbs now spark when shot instead of bleeding (#78248) ## About The Pull Request Title. The amount of sparks are based on the damage dealt by the projectile with slight variation, with one spark representing 25 damage. Also cleans up some code while I was there (not because melbert gave me a side eye or anything for not doing it at first hahaahahah) ## Why It's Good For The Game Bleeding metal is weird, but I feel that having some extra feedback for getting shot was nice - it felt like something was missing when I was testing it out... so I added the sparks. ## Changelog :cl: fix: Projectiles no longer cause a blood graphic or blood splatters if they hit a limb that cant bleed add: Prosthetics/Augments now spark when shot /:cl: --------- Co-authored-by: Jacquerel Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com> --- code/__DEFINES/projectiles.dm | 3 + code/modules/projectiles/projectile.dm | 81 ++++++++++++++------------ 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/code/__DEFINES/projectiles.dm b/code/__DEFINES/projectiles.dm index eec9472c2bf..3bc745756aa 100644 --- a/code/__DEFINES/projectiles.dm +++ b/code/__DEFINES/projectiles.dm @@ -60,6 +60,9 @@ /// For gunpoints, how many tiles around the target the shooter can roam without losing their shot #define GUNPOINT_SHOOTER_STRAY_RANGE 2 +/// A spark will be generated for each THIS amount of damage dealt to a robotic limb by a projectile. +#define PROJECTILE_DAMAGE_PER_ROBOTIC_SPARK 20 + //Designed for things that need precision trajectories like projectiles. //Don't use this for anything that you don't absolutely have to use this with (like projectiles!) because it isn't worth using a datum unless you need accuracy down to decimal places in pixels. diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 0782194f4cf..6bce420a02b 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -227,12 +227,12 @@ SEND_SIGNAL(src, COMSIG_PROJECTILE_RANGE_OUT) qdel(src) -//to get the correct limb (if any) for the projectile hit message -/mob/living/proc/check_limb_hit(hit_zone) +/// Returns the string form of the def_zone we have hit. +/mob/living/proc/check_hit_limb_zone_name(hit_zone) if(has_limbs) return hit_zone -/mob/living/carbon/check_limb_hit(hit_zone) +/mob/living/carbon/check_hit_limb_zone_name(hit_zone) if(get_bodypart(hit_zone)) return hit_zone else //when a limb is missing the damage is actually passed to the chest @@ -249,17 +249,17 @@ /obj/projectile/proc/on_hit(atom/target, blocked = FALSE, pierce_hit) // i know that this is probably more with wands and gun mods in mind, but it's a bit silly that the projectile on_hit signal doesn't ping the projectile itself. // maybe we care what the projectile thinks! See about combining these via args some time when it's not 5AM - var/obj/item/bodypart/hit_limb + var/hit_limb_zone if(isliving(target)) var/mob/living/L = target - hit_limb = L.check_limb_hit(def_zone) + hit_limb_zone = L.check_hit_limb_zone_name(def_zone) if(fired_from) - SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_ON_HIT, firer, target, Angle, hit_limb) - SEND_SIGNAL(src, COMSIG_PROJECTILE_SELF_ON_HIT, firer, target, Angle, hit_limb) + SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_ON_HIT, firer, target, Angle, hit_limb_zone) + SEND_SIGNAL(src, COMSIG_PROJECTILE_SELF_ON_HIT, firer, target, Angle, hit_limb_zone) if(QDELETED(src)) // in case one of the above signals deleted the projectile for whatever reason return - var/turf/target_loca = get_turf(target) + var/turf/target_turf = get_turf(target) var/hitx var/hity @@ -270,18 +270,18 @@ hitx = target.pixel_x + rand(-8, 8) hity = target.pixel_y + rand(-8, 8) - if(damage > 0 && (damage_type == BRUTE || damage_type == BURN) && iswallturf(target_loca) && prob(75)) - var/turf/closed/wall/W = target_loca + if(damage > 0 && (damage_type == BRUTE || damage_type == BURN) && iswallturf(target_turf) && prob(75)) + var/turf/closed/wall/target_wall = target_turf if(impact_effect_type && !hitscan) - new impact_effect_type(target_loca, hitx, hity) + new impact_effect_type(target_wall, hitx, hity) - W.add_dent(WALL_DENT_SHOT, hitx, hity) + target_wall.add_dent(WALL_DENT_SHOT, hitx, hity) return BULLET_ACT_HIT if(!isliving(target)) if(impact_effect_type && !hitscan) - new impact_effect_type(target_loca, hitx, hity) + new impact_effect_type(target_turf, hitx, hity) if(isturf(target) && hitsound_wall) var/volume = clamp(vol_by_damage() + 20, 0, 100) if(suppressed) @@ -289,47 +289,56 @@ playsound(loc, hitsound_wall, volume, TRUE, -1) return BULLET_ACT_HIT - var/mob/living/L = target + var/mob/living/living_target = target if(blocked != 100) // not completely blocked - if(damage && L.blood_volume && damage_type == BRUTE) - var/splatter_dir = dir - if(starting) - splatter_dir = get_dir(starting, target_loca) - if(isalien(L)) - new /obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter(target_loca, splatter_dir) - else - new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_loca, splatter_dir) - if(prob(33)) - L.add_splatter_floor(target_loca) + var/obj/item/bodypart/hit_bodypart = living_target.get_bodypart(hit_limb_zone) + if (damage) + if (living_target.blood_volume && damage_type == BRUTE && (isnull(hit_bodypart) || hit_bodypart.can_bleed())) + var/splatter_dir = dir + if(starting) + splatter_dir = get_dir(starting, target_turf) + if(isalien(living_target)) + new /obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter(target_turf, splatter_dir) + else + new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_turf, splatter_dir) + if(prob(33)) + living_target.add_splatter_floor(target_turf) + else if (!isnull(hit_bodypart) && (hit_bodypart.biological_state & (BIO_METAL|BIO_WIRED))) + var/random_damage_mult = RANDOM_DECIMAL(0.85, 1.15) // SOMETIMES you can get more or less sparks + var/damage_dealt = ((damage / (1 - (blocked / 100))) * random_damage_mult) + + var/spark_amount = round((damage_dealt / PROJECTILE_DAMAGE_PER_ROBOTIC_SPARK)) + if (spark_amount > 0) + do_sparks(spark_amount, FALSE, living_target) + else if(impact_effect_type && !hitscan) - new impact_effect_type(target_loca, hitx, hity) + new impact_effect_type(target_turf, hitx, hity) var/organ_hit_text = "" - var/limb_hit = hit_limb - if(limb_hit) - organ_hit_text = " in \the [parse_zone(limb_hit)]" + if(hit_limb_zone) + organ_hit_text = " in \the [parse_zone(hit_limb_zone)]" if(suppressed == SUPPRESSED_VERY) playsound(loc, hitsound, 5, TRUE, -1) else if(suppressed) playsound(loc, hitsound, 5, TRUE, -1) - to_chat(L, span_userdanger("You're shot by \a [src][organ_hit_text]!")) + to_chat(living_target, span_userdanger("You're shot by \a [src][organ_hit_text]!")) else if(hitsound) var/volume = vol_by_damage() playsound(src, hitsound, volume, TRUE, -1) - L.visible_message(span_danger("[L] is hit by \a [src][organ_hit_text]!"), \ + living_target.visible_message(span_danger("[living_target] is hit by \a [src][organ_hit_text]!"), \ span_userdanger("You're hit by \a [src][organ_hit_text]!"), null, COMBAT_MESSAGE_RANGE) - if(L.is_blind()) - to_chat(L, span_userdanger("You feel something hit you[organ_hit_text]!")) - L.on_hit(src) + if(living_target.is_blind()) + to_chat(living_target, span_userdanger("You feel something hit you[organ_hit_text]!")) + living_target.on_hit(src) var/reagent_note if(reagents?.reagent_list) reagent_note = "REAGENTS: [pretty_string_from_reagent_list(reagents.reagent_list)]" if(ismob(firer)) - log_combat(firer, L, "shot", src, reagent_note) + log_combat(firer, living_target, "shot", src, reagent_note) return BULLET_ACT_HIT if(isvehicle(firer)) @@ -339,10 +348,10 @@ if(!LAZYLEN(logging_mobs)) logging_mobs = firing_vehicle.return_drivers() for(var/mob/logged_mob as anything in logging_mobs) - log_combat(logged_mob, L, "shot", src, "from inside [firing_vehicle][logging_mobs.len > 1 ? " with multiple occupants" : null][reagent_note ? " and contained [reagent_note]" : null]") + log_combat(logged_mob, living_target, "shot", src, "from inside [firing_vehicle][logging_mobs.len > 1 ? " with multiple occupants" : null][reagent_note ? " and contained [reagent_note]" : null]") return BULLET_ACT_HIT - L.log_message("has been shot by [firer] with [src][reagent_note ? " containing [reagent_note]" : null]", LOG_ATTACK, color="orange") + living_target.log_message("has been shot by [firer] with [src][reagent_note ? " containing [reagent_note]" : null]", LOG_ATTACK, color="orange") return BULLET_ACT_HIT /obj/projectile/proc/vol_by_damage()