From 54491a67e92c660acf2bbdd64ade503bd590c2fc Mon Sep 17 00:00:00 2001 From: Ghom <42542238+Ghommie@users.noreply.github.com> Date: Sun, 20 Aug 2023 18:40:03 +0200 Subject: [PATCH] Fixing embedding for projectiles. (#77674) So, the main issue was that the variables for the embed element wouldn't set when attached to a projectile but only on items for some insignificant reason, which means it'll spawn the shrapnel yes, but won't embed it since the chance is null/zero. I read the code over and over and over with the assumption that something like this wouldn't have been done, yet it was. As for the secondary issue, because of how embedding works, the casing types of arrows and harpoon aren't spawned when hitting a non-carbon or reaching their maximum range. So, I'm re-enabling the reusable arg/var for the caseless component of harpoons and arrows, and modifying the `projectile_drop` to not drop their payload if the embedding component would already do that, so we avoid duping. --- code/datums/elements/embed.dm | 41 ++++++++++--------- code/datums/elements/projectile_drop.dm | 22 ++++++++-- .../ammunition/ballistic/harpoon.dm | 2 +- .../guns/ballistic/bows/bow_arrows.dm | 7 +++- code/modules/projectiles/projectile.dm | 7 ++-- 5 files changed, 50 insertions(+), 29 deletions(-) diff --git a/code/datums/elements/embed.dm b/code/datums/elements/embed.dm index 3b3f02ecb08..0ba3a581d9a 100644 --- a/code/datums/elements/embed.dm +++ b/code/datums/elements/embed.dm @@ -40,23 +40,23 @@ RegisterSignal(target, COMSIG_ATOM_EXAMINE, PROC_REF(examined)) RegisterSignal(target, COMSIG_EMBED_TRY_FORCE, PROC_REF(tryForceEmbed)) RegisterSignal(target, COMSIG_ITEM_DISABLE_EMBED, PROC_REF(detachFromWeapon)) - if(!initialized) - src.embed_chance = embed_chance - src.fall_chance = fall_chance - src.pain_chance = pain_chance - src.pain_mult = pain_mult - src.remove_pain_mult = remove_pain_mult - src.rip_time = rip_time - src.impact_pain_mult = impact_pain_mult - src.ignore_throwspeed_threshold = ignore_throwspeed_threshold - src.jostle_chance = jostle_chance - src.jostle_pain_mult = jostle_pain_mult - src.pain_stam_pct = pain_stam_pct - initialized = TRUE else payload_type = projectile_payload RegisterSignal(target, COMSIG_PROJECTILE_SELF_ON_HIT, PROC_REF(checkEmbedProjectile)) + if(!initialized) + src.embed_chance = embed_chance + src.fall_chance = fall_chance + src.pain_chance = pain_chance + src.pain_mult = pain_mult + src.remove_pain_mult = remove_pain_mult + src.rip_time = rip_time + src.impact_pain_mult = impact_pain_mult + src.ignore_throwspeed_threshold = ignore_throwspeed_threshold + src.jostle_chance = jostle_chance + src.jostle_pain_mult = jostle_pain_mult + src.pain_stam_pct = pain_stam_pct + initialized = TRUE /datum/element/embed/Detach(obj/target) . = ..() @@ -136,24 +136,25 @@ * That's awful, and it'll limit us to drop-deletable shrapnels in the worry of stuff like * arrows and harpoons being embeddable even when not let loose by their weapons. */ -/datum/element/embed/proc/checkEmbedProjectile(obj/projectile/P, atom/movable/firer, atom/hit, angle, hit_zone) +/datum/element/embed/proc/checkEmbedProjectile(obj/projectile/source, atom/movable/firer, atom/hit, angle, hit_zone) SIGNAL_HANDLER - if(!iscarbon(hit) || HAS_TRAIT(hit, TRAIT_PIERCEIMMUNE)) - Detach(P) + if(!source.can_embed_into(hit)) + Detach(source) return // we don't care var/obj/item/payload = new payload_type(get_turf(hit)) if(istype(payload, /obj/item/shrapnel/bullet)) - payload.name = P.name - SEND_SIGNAL(P, COMSIG_PROJECTILE_ON_SPAWN_EMBEDDED, payload) + payload.name = source.name + SEND_SIGNAL(source, COMSIG_PROJECTILE_ON_SPAWN_EMBEDDED, payload) var/mob/living/carbon/C = hit var/obj/item/bodypart/limb = C.get_bodypart(hit_zone) if(!limb) limb = C.get_bodypart() - tryForceEmbed(payload, limb) - Detach(P) + if(!tryForceEmbed(payload, limb)) + payload.failedEmbed() + Detach(source) /** * tryForceEmbed() is called here when we fire COMSIG_EMBED_TRY_FORCE from [/obj/item/proc/tryEmbed]. Mostly, this means we're a piece of shrapnel from a projectile that just impacted something, and we're trying to embed in it. diff --git a/code/datums/elements/projectile_drop.dm b/code/datums/elements/projectile_drop.dm index 633d43c201b..36e189d6c3a 100644 --- a/code/datums/elements/projectile_drop.dm +++ b/code/datums/elements/projectile_drop.dm @@ -1,4 +1,8 @@ -///A simple element that spawns an atom when the bullet hits an object or reaches the end of its range +/** + * A simple element that spawns an atom when the bullet hits an object or reaches the end of its range + * If the projectile has embedding and it can embed into the target, then it won't spawn the drop, + * since embedding the embed element already handles that. + */ /datum/element/projectile_drop element_flags = ELEMENT_BESPOKE argument_hash_start_idx = 2 @@ -9,7 +13,12 @@ if(!isprojectile(target)) return ELEMENT_INCOMPATIBLE src.drop_type = drop_type - RegisterSignals(target, list(COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PROJECTILE_SELF_ON_HIT), PROC_REF(spawn_drop)) + RegisterSignal(target, COMSIG_PROJECTILE_RANGE_OUT, PROC_REF(spawn_drop)) + RegisterSignal(target, COMSIG_PROJECTILE_SELF_ON_HIT, PROC_REF(spawn_drop_if_not_embeddable)) + +/datum/element/projectile_drop/Detach(datum/source) + UnregisterSignal(source, list(COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PROJECTILE_SELF_ON_HIT)) + return ..() /datum/element/projectile_drop/proc/spawn_drop(obj/projectile/source) SIGNAL_HANDLER @@ -17,4 +26,11 @@ var/atom/new_drop = new drop_type(turf) SEND_SIGNAL(source, COMSIG_PROJECTILE_ON_SPAWN_DROP, new_drop) //Just to be safe, knowing it won't be spawned multiple times. - UnregisterSignal(source, list(COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PROJECTILE_SELF_ON_HIT, COMSIG_QDELETING)) + Detach(source) + +/datum/element/projectile_drop/proc/spawn_drop_if_not_embeddable(obj/projectile/source, atom/movable/firer, atom/hit, angle, hit_zone) + SIGNAL_HANDLER + if(source.can_embed_into(hit)) + Detach(source) + return + spawn_drop(source) diff --git a/code/modules/projectiles/ammunition/ballistic/harpoon.dm b/code/modules/projectiles/ammunition/ballistic/harpoon.dm index 61aa16fe56e..79590ccb97d 100644 --- a/code/modules/projectiles/ammunition/ballistic/harpoon.dm +++ b/code/modules/projectiles/ammunition/ballistic/harpoon.dm @@ -7,7 +7,7 @@ /obj/item/ammo_casing/harpoon/Initialize(mapload) . = ..() - AddElement(/datum/element/caseless) + AddElement(/datum/element/caseless, TRUE) /obj/item/ammo_casing/harpoon/update_icon_state() . = ..() diff --git a/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm b/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm index 50d0d456ee2..d9443719a7e 100644 --- a/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm +++ b/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm @@ -12,11 +12,13 @@ firing_effect_type = null caliber = CALIBER_ARROW is_cased_ammo = FALSE + ///Whether the bullet type spawns another casing of the same type or not. + var/reusable = TRUE /obj/item/ammo_casing/arrow/Initialize(mapload) . = ..() AddElement(/datum/element/envenomable_casing) - AddElement(/datum/element/caseless) + AddElement(/datum/element/caseless, reusable) /obj/item/ammo_casing/arrow/update_icon_state() . = ..() @@ -58,7 +60,7 @@ desc = "Here it comes, cultist scum!" icon_state = "holy_arrow_projectile" damage = 20 //still a lot but this is roundstart gear so far less - shrapnel_type =/obj/projectile/bullet/arrow/holy + shrapnel_type =/obj/item/ammo_casing/arrow/holy embedding = list( embed_chance = 50, fall_chance = 2, @@ -80,6 +82,7 @@ name = "blazing star arrow" desc = "A holy diver seeking its target, blessed with fire. Will ignite on hit, destroying the arrow. But if you hit an already ignited target...?" projectile_type = /obj/projectile/bullet/arrow/blazing + reusable = FALSE /obj/projectile/bullet/arrow/blazing name = "blazing arrow" diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index ec4fc9227e9..0782194f4cf 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -740,9 +740,6 @@ SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_BEFORE_FIRE, src, original) if(firer) SEND_SIGNAL(firer, COMSIG_PROJECTILE_FIRER_BEFORE_FIRE, src, fired_from, original) - //If no angle needs to resolve it from xo/yo! - if(shrapnel_type && LAZYLEN(embedding)) - AddElement(/datum/element/embed, projectile_payload = shrapnel_type) if(!log_override && firer && original) log_combat(firer, original, "fired at", src, "from [get_area_name(src, TRUE)]") //note: mecha projectile logging is handled in /obj/item/mecha_parts/mecha_equipment/weapon/action(). try to keep these messages roughly the sameish just for consistency's sake. @@ -1129,6 +1126,10 @@ return FALSE +///Checks if the projectile can embed into someone +/obj/projectile/proc/can_embed_into(atom/hit) + return embedding && shrapnel_type && iscarbon(hit) && !HAS_TRAIT(hit, TRAIT_PIERCEIMMUNE) + #undef MOVES_HITSCAN #undef MUZZLE_EFFECT_PIXEL_INCREMENT