From d701f8d96470ce8793a2e2d6a1dea8ad661c11a1 Mon Sep 17 00:00:00 2001 From: Kaga <103199482+Kaga-404@users.noreply.github.com> Date: Wed, 21 Feb 2024 01:24:41 -0800 Subject: [PATCH 01/16] Initial Commit --- code/_globalvars/global_lists.dm | 4 +- code/datums/ammo/ammo.dm | 1 + code/datums/ammo/bullet/sniper.dm | 9 ++- .../elements/bullet_trait/damage_boost.dm | 40 ++++++------- .../elements/bullet_trait/penetrating/weak.dm | 60 +++++++++++++++++++ code/datums/supply_packs/spec_ammo.dm | 4 +- code/game/machinery/vending/cm_vending.dm | 5 ++ .../squad_prep/squad_specialist.dm | 1 + .../modules/cm_marines/equipment/kit_boxes.dm | 24 ++++++++ code/modules/projectiles/gun.dm | 4 ++ .../projectiles/guns/specialist/sniper.dm | 13 ++-- .../projectiles/magazines/specialist.dm | 2 +- code/modules/projectiles/projectile.dm | 17 ++++++ colonialmarines.dme | 1 + 14 files changed, 154 insertions(+), 31 deletions(-) create mode 100644 code/datums/elements/bullet_trait/penetrating/weak.dm diff --git a/code/_globalvars/global_lists.dm b/code/_globalvars/global_lists.dm index 7d9cd3324067..a5665ea322e5 100644 --- a/code/_globalvars/global_lists.dm +++ b/code/_globalvars/global_lists.dm @@ -480,7 +480,8 @@ GLOBAL_LIST_INIT(available_specialist_sets, list( "Sniper Set", "Demolitionist Set", "Heavy Grenadier Set", - "Pyro Set" + "Pyro Set", + "Anti-materiel Sniper Set" )) //Similar thing, but used in /obj/item/spec_kit @@ -490,6 +491,7 @@ GLOBAL_LIST_INIT(available_specialist_kit_boxes, list( "Sniper" = 2, "Scout" = 2, "Demo" = 2, + "Anti-materiel Sniper" = 2, )) /proc/init_global_referenced_datums() diff --git a/code/datums/ammo/ammo.dm b/code/datums/ammo/ammo.dm index 7a4006deee73..3c40303f0a36 100644 --- a/code/datums/ammo/ammo.dm +++ b/code/datums/ammo/ammo.dm @@ -230,6 +230,7 @@ P.generate_bullet(GLOB.ammo_list[bonus_projectiles_type]) //No bonus damage or anything. P.accuracy = round(P.accuracy * original_P.accuracy/initial(original_P.accuracy)) //if the gun changes the accuracy of the main projectile, it also affects the bonus ones. original_P.give_bullet_traits(P) + P.bonus_projectile_check = 2 //It's a bonus projectile! var/total_scatter_angle = P.scatter final_angle += rand(-total_scatter_angle, total_scatter_angle) diff --git a/code/datums/ammo/bullet/sniper.dm b/code/datums/ammo/bullet/sniper.dm index 22371972e623..c580407ee804 100644 --- a/code/datums/ammo/bullet/sniper.dm +++ b/code/datums/ammo/bullet/sniper.dm @@ -118,9 +118,16 @@ if(target.mob_size >= MOB_SIZE_BIG) size_damage_mod += 0.6 L.apply_armoured_damage(damage*size_damage_mod, ARMOR_BULLET, BRUTE, null, penetration) - // 180% damage to all targets (225), 240% (300) against non-Runner xenos, and 300% against Big xenos (375). -Kaga + // Base 180% damage to all targets (225), 240% (300) against non-Runner xenos, and 300% against Big xenos (375). -Kaga + // This applies after pen reductions. After hitting 1 other thing, it deals 180/240/300 damage, or 135/180/225 after hitting a dense wall or big xeno. to_chat(P.firer, SPAN_WARNING("Bullseye!")) +/datum/ammo/bullet/sniper/anti_materiel/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating/weak) + )) + /datum/ammo/bullet/sniper/anti_materiel/vulture damage = 400 // Fully intended to vaporize anything smaller than a mini cooper accurate_range_min = 10 diff --git a/code/datums/elements/bullet_trait/damage_boost.dm b/code/datums/elements/bullet_trait/damage_boost.dm index eee4a8e80f4b..640026a8dfa9 100644 --- a/code/datums/elements/bullet_trait/damage_boost.dm +++ b/code/datums/elements/bullet_trait/damage_boost.dm @@ -28,17 +28,10 @@ GLOBAL_LIST_INIT(damage_boost_vehicles, typecacheof(/obj/vehicle/multitile)) /// A typecache of objs or turfs that, upon being hit, boost the damage of the attached projectile var/list/damage_boosted_atoms - //vars for dealing with interaction issues with the Penetrating trait - var/boosted_hits - var/last_damage_mult - //allows for nuance in Breaching-Resistant interactions var/active_damage_mult var/atom_type - //var for dealing with bonus projectiles - var/bonus_projectile_check - /** * vars: * * damage_mult - the damage multiplier to be applied if the bullet hits an atom whose type is in `breaching_objs` @@ -51,11 +44,8 @@ GLOBAL_LIST_INIT(damage_boost_vehicles, typecacheof(/obj/vehicle/multitile)) src.damage_mult = damage_mult src.damage_boosted_atoms = damage_boosted_atoms - src.boosted_hits = 0 - src.last_damage_mult = 1 src.active_damage_mult = 1 src.atom_type = 0 - src.bonus_projectile_check = 0 RegisterSignal(target, list( COMSIG_BULLET_PRE_HANDLE_OBJ, @@ -71,7 +61,7 @@ GLOBAL_LIST_INIT(damage_boost_vehicles, typecacheof(/obj/vehicle/multitile)) /datum/element/bullet_trait_damage_boost/proc/handle_bullet(obj/projectile/P, atom/A) SIGNAL_HANDLER - atom_type = check_type(A) + src.atom_type = check_type(A) switch(atom_type) if("door") @@ -87,12 +77,22 @@ GLOBAL_LIST_INIT(damage_boost_vehicles, typecacheof(/obj/vehicle/multitile)) else active_damage_mult = damage_mult - if(boosted_hits > 0) - if(bonus_projectile_check == P.damage) - P.damage = P.damage / last_damage_mult - boosted_hits-- - if(damage_boosted_atoms[A.type]) - P.damage = round(P.damage * active_damage_mult) - last_damage_mult = active_damage_mult - boosted_hits++ - bonus_projectile_check = P.damage + + if(P.damage_boosted && (P.last_atom_signaled != A) && (!P.bonus_projectile_check)) + //If this is after a boosted hit, the last atom that procced this isn't the same as the current target, and this isn't a bonus projectile sharing the same damage_boost + if(!P.last_damage_mult) //Make sure stored mult isn't 0 + P.last_damage_mult = 1 + + P.damage = P.damage / P.last_damage_mult //Reduce the damage back to normal + P.damage_boosted-- //Mark that damage has been returned to normal. + + if(damage_boosted_atoms[A.type]) //If hitting a valid atom for damage boost + P.damage = round(P.damage * active_damage_mult) //Modify Damage by multiplier + + if (active_damage_mult) + P.last_damage_mult = active_damage_mult //Save multiplier for next check + else + P.last_damage_mult = 1 + + P.damage_boosted++ //Mark that a boosted hit occurred. + P.last_atom_signaled = A //Save the current triggering atom to the projectile diff --git a/code/datums/elements/bullet_trait/penetrating/weak.dm b/code/datums/elements/bullet_trait/penetrating/weak.dm new file mode 100644 index 000000000000..99c94a9c90ba --- /dev/null +++ b/code/datums/elements/bullet_trait/penetrating/weak.dm @@ -0,0 +1,60 @@ +/datum/element/bullet_trait_penetrating/weak + // Generic bullet trait vars + element_flags = ELEMENT_DETACH|ELEMENT_BESPOKE + id_arg_index = 4 + + /// For each thing this hits, how much damage it loses normally. This can be modified by what it penetrates later. + var/damage_percent_lost_per_hit = 20 + // XM43E1 AMR: First target takes full damage, each subsequent target takes at least 20% less damage (increased for large mobs and dense turfs), 25 from base 125 damage. + + /// For each thing this hits, how much distance it loses normally. + distance_loss_per_hit = 4 + // XM43E1 AMR: Hits 7 things at most, at point blank, with no additional modifiers. This greatly increases at actual sniping ranges. + + /// How many times more effective turfs are at slowing down the projectile normally, reducing both range and damage. + var/turf_hit_slow_mult = 3 + // XM43E1 AMR: Unable to hit anything through more than 2 walls, less at maximum ranges. Pens 2 walls at 8 tiles or less, 1 at 20 tiles or less, and can't wallbang through normal walls at maximum range. + // Also loses 75 damage with each normal wall pen. + +/datum/element/bullet_trait_penetrating/weak/Attach(datum/target, distance_loss_per_hit = 4, damage_percent_lost_per_hit = 20, turf_hit_slow_mult = 3) + . = ..() + if(. == ELEMENT_INCOMPATIBLE) + return + + src.damage_percent_lost_per_hit = damage_percent_lost_per_hit + src.turf_hit_slow_mult = turf_hit_slow_mult + +/datum/element/bullet_trait_penetrating/weak/handle_passthrough_movables(obj/projectile/bullet, atom/movable/hit_movable, did_hit) + if(did_hit) + var/slow_mult = 1 + if(ismob(hit_movable)) + var/mob/mob = hit_movable + if(mob.mob_size >= MOB_SIZE_BIG) // Big Xenos (including fortified Defender) can soak hits and greatly reduce penetration. + slow_mult = 2 // 8 tiles of range lost per Big hit. At point blank, this comes out to only 3 targets. At sniping ranges, even a single one can stop the bullet dead. + + bullet.distance_travelled += (distance_loss_per_hit * slow_mult) + + bullet.damage -= (damage_percent_lost_per_hit * slow_mult) + + return COMPONENT_BULLET_PASS_THROUGH + + +/datum/element/bullet_trait_penetrating/weak/handle_passthrough_turf(obj/projectile/bullet, turf/closed/wall/hit_wall) + var/slow_mult = turf_hit_slow_mult + + // Better penetration against Membranes to still be able to counter Boilers at most ranges. Still loses 4 tiles of range and 25 damage per. + if(istype(hit_wall, /turf/closed/wall/resin/membrane)) + if(istype(hit_wall, /turf/closed/wall/resin/membrane/thick)) + slow_mult = 1.5 + else + slow_mult = 1 + + bullet.distance_travelled += (distance_loss_per_hit * slow_mult) + + bullet.damage *= (1 - (damage_percent_lost_per_hit * slow_mult * 0.01)) + + if(!istype(hit_wall)) + return COMPONENT_BULLET_PASS_THROUGH + + if(!hit_wall.hull) + return COMPONENT_BULLET_PASS_THROUGH diff --git a/code/datums/supply_packs/spec_ammo.dm b/code/datums/supply_packs/spec_ammo.dm index f0eb5ab9cea2..b16966c3fc0b 100644 --- a/code/datums/supply_packs/spec_ammo.dm +++ b/code/datums/supply_packs/spec_ammo.dm @@ -109,8 +109,6 @@ containername = "M42A Incendiary Magazine Crate" group = "Weapons Specialist Ammo" -//XM43E1 - Disabled during testing per request. -/* /datum/supply_packs/ammo_amr_marksman name = "XM43E1 anti-materiel rifle marksman magazines crate (x5)" contains = list( @@ -124,7 +122,7 @@ containertype = /obj/structure/closet/crate/ammo containername = "XM43E1 Anti-Materiel Magazine Crate" group = "Specialist Ammo" -*/ + //M4RA /datum/supply_packs/ammo_scout_mix diff --git a/code/game/machinery/vending/cm_vending.dm b/code/game/machinery/vending/cm_vending.dm index 4f825030d627..56977d23675b 100644 --- a/code/game/machinery/vending/cm_vending.dm +++ b/code/game/machinery/vending/cm_vending.dm @@ -566,6 +566,11 @@ GLOBAL_LIST_EMPTY(vending_products) if("Sniper Set") user.skills.set_skill(SKILL_SPEC_WEAPONS, SKILL_SPEC_SNIPER) specialist_assignment = "Sniper" + GLOB.available_specialist_sets -= "Anti-materiel Sniper Set" + if("Anti-materiel Sniper Set") + user.skills.set_skill(SKILL_SPEC_WEAPONS, SKILL_SPEC_SNIPER) + specialist_assignment = "Sniper" + GLOB.available_specialist_sets -= "Sniper Set" if("Demolitionist Set") user.skills.set_skill(SKILL_SPEC_WEAPONS, SKILL_SPEC_ROCKET) specialist_assignment = "Demo" diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_specialist.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_specialist.dm index e800fc1efd56..6006a7635277 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_specialist.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_specialist.dm @@ -7,6 +7,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_spec, list( list("Pyro Set", 0, /obj/item/storage/box/spec/pyro, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_REGULAR), list("Scout Set", 0, /obj/item/storage/box/spec/scout, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_REGULAR), list("Sniper Set", 0, /obj/item/storage/box/spec/sniper, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_RECOMMENDED), + list("Anti-materiel Sniper Set", 0, /obj/item/storage/box/spec/sniper/anti_materiel, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_RECOMMENDED), list("EXTRA SCOUT AMMUNITION", 0, null, null, null), list("A19 High Velocity Impact Magazine (10x24mm)", 40, /obj/item/ammo_magazine/rifle/m4ra/custom/impact, null, VENDOR_ITEM_REGULAR), diff --git a/code/modules/cm_marines/equipment/kit_boxes.dm b/code/modules/cm_marines/equipment/kit_boxes.dm index d99da8f59f2c..cdf91b6ef076 100644 --- a/code/modules/cm_marines/equipment/kit_boxes.dm +++ b/code/modules/cm_marines/equipment/kit_boxes.dm @@ -69,6 +69,26 @@ // spotter new /obj/item/storage/box/kit/spotter(src) +/obj/item/storage/box/spec/sniper/anti_materiel/fill_preset_inventory() + name = "\improper AMR equipment case" + desc = "A large case containing an experimental XM43E1, a set of M45 ghillie armor and helmet, a M42 scout sight, ammunition, spotter equipment, and additional pieces of equipment.\nDrag this sprite onto yourself to open it up! NOTE: You cannot put items back inside this case." + new /obj/item/clothing/suit/storage/marine/ghillie(src) + new /obj/item/clothing/head/helmet/marine/ghillie(src) + new /obj/item/clothing/glasses/night/m42_night_goggles(src) + new /obj/item/weapon/gun/rifle/sniper/XM43E1(src) + new /obj/item/ammo_magazine/sniper/anti_materiel(src) + new /obj/item/ammo_magazine/sniper/anti_materiel(src) + new /obj/item/ammo_magazine/sniper/anti_materiel(src) + new /obj/item/ammo_magazine/sniper/anti_materiel(src) + new /obj/item/ammo_magazine/sniper/anti_materiel(src) + new /obj/item/storage/backpack/marine/smock(src) + new /obj/item/weapon/gun/pistol/vp78(src) + new /obj/item/ammo_magazine/pistol/vp78(src) + new /obj/item/ammo_magazine/pistol/vp78(src) + new /obj/item/facepaint/sniper(src) + // spotter + new /obj/item/storage/box/kit/spotter(src) + /obj/item/storage/box/spec/scout name = "\improper Scout equipment case" desc = "A large case containing an M4RA battle rifle, M3-S light armor and helmet, M4RA battle sight, M68 thermal cloak, V3 reactive thermal tarp, improved scout laser designator, ammunition and additional pieces of equipment.\nDrag this sprite onto yourself to open it up! NOTE: You cannot put items back inside this case." @@ -257,6 +277,10 @@ spec_box = new /obj/item/storage/box/spec/sniper(T) specialist_assignment = "Sniper" user.skills.set_skill(SKILL_SPEC_WEAPONS, SKILL_SPEC_SNIPER) + if("Anti-materiel Sniper") + spec_box = new /obj/item/storage/box/spec/sniper/anti_materiel(T) + specialist_assignment = "Sniper" + user.skills.set_skill(SKILL_SPEC_WEAPONS, SKILL_SPEC_SNIPER) if("Scout") spec_box = new /obj/item/storage/box/spec/scout(T) specialist_assignment = "Scout" diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 3f7533f26620..68f169fa2b25 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -1419,6 +1419,10 @@ and you're good to go. BP.generate_bullet(GLOB.ammo_list[projectile_to_fire.ammo.bonus_projectiles_type], 0, NO_FLAGS) BP.accuracy = round(BP.accuracy * projectile_to_fire.accuracy/initial(projectile_to_fire.accuracy)) //Modifies accuracy of pellets per fire_bonus_projectiles. BP.damage *= damage_buff + + BP.bonus_projectile_check = 2 + projectile_to_fire.bonus_projectile_check = 1 + projectile_to_fire.give_bullet_traits(BP) if(bullets_fired > 1) BP.original = attacked_mob //original == the original target of the projectile. If the target is downed and this isn't set, the projectile will try to fly over it. Of course, it isn't going anywhere, but it's the principle of the thing. Very embarrassing. diff --git a/code/modules/projectiles/guns/specialist/sniper.dm b/code/modules/projectiles/guns/specialist/sniper.dm index bdb0ba02f3ab..77ce0069cce3 100644 --- a/code/modules/projectiles/guns/specialist/sniper.dm +++ b/code/modules/projectiles/guns/specialist/sniper.dm @@ -345,6 +345,7 @@ item_state = "xm43e1" unacidable = TRUE indestructible = 1 + aimed_shot_cooldown_delay = 4 SECONDS fire_sound = 'sound/weapons/sniper_heavy.ogg' current_mag = /obj/item/ammo_magazine/sniper/anti_materiel //Renamed from anti-tank to align with new identity/description. Other references have been changed as well. -Kaga @@ -354,9 +355,9 @@ attachable_allowed = list(/obj/item/attachable/bipod) flags_gun_features = GUN_AUTO_EJECTOR|GUN_SPECIALIST|GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER starting_attachment_types = list(/obj/item/attachable/pmc_sniperbarrel) - sniper_beam_type = /obj/effect/ebeam/laser/intense - sniper_beam_icon = "laser_beam_intense" - sniper_lockon_icon = "sniper_lockon_intense" + sniper_beam_type = /obj/effect/ebeam/laser + sniper_beam_icon = "laser_beam" + sniper_lockon_icon = "sniper_lockon" /obj/item/weapon/gun/rifle/sniper/XM43E1/handle_starting_attachment() ..() @@ -376,6 +377,7 @@ ..() set_fire_delay(FIRE_DELAY_TIER_6 * 6 )//Big boy damage, but it takes a lot of time to fire a shot. //Kaga: Adjusted from 56 (Tier 4, 7*8) -> 30 (Tier 6, 5*6) ticks. 95 really wasn't big-boy damage anymore, although I updated it to 125 to remain consistent with the other 10x99mm caliber weapon (M42C). Now takes only twice as long as the M42A. + //This outright deals less DPS than the normal sniper rifle, 125 vs 140 per 3s. set_burst_amount(BURST_AMOUNT_TIER_1) accuracy_mult = BASE_ACCURACY_MULT + 2*HIT_ACCURACY_MULT_TIER_10 //Who coded this like this, and why? It just calculates out to 1+1=2. Leaving a note here to check back later. scatter = SCATTER_AMOUNT_TIER_10 @@ -385,10 +387,11 @@ /obj/item/weapon/gun/rifle/sniper/XM43E1/set_bullet_traits() LAZYADD(traits_to_give, list( BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_iff), - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating), BULLET_TRAIT_ENTRY_ID("turfs", /datum/element/bullet_trait_damage_boost, 11, GLOB.damage_boost_turfs), BULLET_TRAIT_ENTRY_ID("breaching", /datum/element/bullet_trait_damage_boost, 11, GLOB.damage_boost_breaching), - //At 1375 per shot it'll take 1 shot to break resin turfs, and a full mag of 8 to break reinforced walls. + //At 1375 per shot it'll take 1 shot to break resin turfs usually (thick resin at 1350, RNG may vary), and a full mag of 8 to break reinforced walls. + //However, the second wall it hits will only take 550 damage, unable to even kill a full-health normal resin wall (900). + //Much more effective at breaking resin doors and membranes, which have less HP and slow down the projectile less. BULLET_TRAIT_ENTRY_ID("pylons", /datum/element/bullet_trait_damage_boost, 6, GLOB.damage_boost_pylons) //At 750 per shot it'll take 3 to break a Pylon (1800 HP). No Damage Boost vs other xeno structures yet, those will require a whole new list w/ the damage_boost trait. )) diff --git a/code/modules/projectiles/magazines/specialist.dm b/code/modules/projectiles/magazines/specialist.dm index 761e77305254..698d9efeaca2 100644 --- a/code/modules/projectiles/magazines/specialist.dm +++ b/code/modules/projectiles/magazines/specialist.dm @@ -30,7 +30,7 @@ //XM43E1 Magazine /obj/item/ammo_magazine/sniper/anti_materiel name = "\improper XM43E1 marksman magazine (10x99mm)" - desc = "A magazine of caseless 10x99mm anti-materiel rounds." + desc = "A magazine of caseless 10x99mm anti-materiel rounds, capable of penetrating through most infantry-level materiel. Depending on what you hit, it might even have enough energy to wound anything behind the target." max_rounds = 8 caliber = "10x99mm" default_ammo = /datum/ammo/bullet/sniper/anti_materiel diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 3ed10129f4d6..c3a27f7117fe 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -80,6 +80,16 @@ /// How much to make the bullet fall off by accuracy-wise when closer than the ideal range var/accuracy_range_falloff = 10 + /// Is this a lone (0), original (1), or bonus (2) projectile. Used in gun.dm and fire_bonus_projectiles() currently. + var/bonus_projectile_check = 0 + + /// What atom did this last receive a registered signal from? Used by damage_boost.dm + var/atom/last_atom_signaled = null + + /// Was this projectile affected by damage_boost.dm? If so, what was the last modifier? + var/damage_boosted = 0 + var/last_damage_mult = 1 + /obj/projectile/Initialize(mapload, datum/cause_data/cause_data) . = ..() path = list() @@ -164,6 +174,12 @@ apply_bullet_trait(L) /obj/projectile/proc/calculate_damage() + + if(damage_boosted) + damage = damage / last_damage_mult + damage_boosted-- + last_damage_mult = 1 + if(effective_range_min && distance_travelled < effective_range_min) return max(0, damage - round((effective_range_min - distance_travelled) * damage_buildup)) else if(distance_travelled > effective_range_max) @@ -215,6 +231,7 @@ //If we have the right kind of ammo, we can fire several projectiles at once. if(ammo.bonus_projectiles_amount && ammo.bonus_projectiles_type) ammo.fire_bonus_projectiles(src) + bonus_projectile_check = 1 //Mark this projectile as having spawned a set of bonus projectiles. path = get_line(starting, target_turf) p_x += clamp((rand()-0.5)*scatter*3, -8, 8) diff --git a/colonialmarines.dme b/colonialmarines.dme index 602e4fa9de30..2c0f257c22c0 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -486,6 +486,7 @@ #include "code\datums\elements\bullet_trait\iff.dm" #include "code\datums\elements\bullet_trait\ignored_range.dm" #include "code\datums\elements\bullet_trait\incendiary.dm" +#include "code\datums\elements\bullet_trait\penetrating\weak.dm" #include "code\datums\elements\bullet_trait\penetrating\heavy.dm" #include "code\datums\elements\bullet_trait\penetrating\penetrating.dm" #include "code\datums\elements\traitbound\_traitbound.dm" From df664e90fa5bd5364ad4b8dc5dbacfe451775a45 Mon Sep 17 00:00:00 2001 From: Kaga <103199482+Kaga-404@users.noreply.github.com> Date: Wed, 21 Feb 2024 01:50:22 -0800 Subject: [PATCH 02/16] Documentation correction. --- code/datums/ammo/bullet/sniper.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/ammo/bullet/sniper.dm b/code/datums/ammo/bullet/sniper.dm index c580407ee804..a900456e434d 100644 --- a/code/datums/ammo/bullet/sniper.dm +++ b/code/datums/ammo/bullet/sniper.dm @@ -119,7 +119,7 @@ size_damage_mod += 0.6 L.apply_armoured_damage(damage*size_damage_mod, ARMOR_BULLET, BRUTE, null, penetration) // Base 180% damage to all targets (225), 240% (300) against non-Runner xenos, and 300% against Big xenos (375). -Kaga - // This applies after pen reductions. After hitting 1 other thing, it deals 180/240/300 damage, or 135/180/225 after hitting a dense wall or big xeno. + // This applies after pen reductions. After hitting 1 other thing, it deals 180/240/300 damage, or 90/120/150 after hitting a dense wall or big xeno. to_chat(P.firer, SPAN_WARNING("Bullseye!")) /datum/ammo/bullet/sniper/anti_materiel/set_bullet_traits() From c38cc048c4eefe4d92fdce57efbf0cd14bf09498 Mon Sep 17 00:00:00 2001 From: Kaga <103199482+Kaga-404@users.noreply.github.com> Date: Wed, 21 Feb 2024 02:27:46 -0800 Subject: [PATCH 03/16] Fixes include order and adds ammo to spec vendor --- code/datums/supply_packs/spec_ammo.dm | 2 +- .../vending/vendor_types/squad_prep/squad_specialist.dm | 1 + colonialmarines.dme | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/code/datums/supply_packs/spec_ammo.dm b/code/datums/supply_packs/spec_ammo.dm index b16966c3fc0b..4e1d0b34f2be 100644 --- a/code/datums/supply_packs/spec_ammo.dm +++ b/code/datums/supply_packs/spec_ammo.dm @@ -120,7 +120,7 @@ ) cost = 30 containertype = /obj/structure/closet/crate/ammo - containername = "XM43E1 Anti-Materiel Magazine Crate" + containername = "XM43E1 Marksman Magazine Crate" group = "Specialist Ammo" //M4RA diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_specialist.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_specialist.dm index 6006a7635277..93ec16cbb48e 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_specialist.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_specialist.dm @@ -18,6 +18,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_spec, list( list("M42A Flak Magazine (10x28mm)", 40, /obj/item/ammo_magazine/sniper/flak, null, VENDOR_ITEM_REGULAR), list("M42A Incendiary Magazine (10x28mm)", 40, /obj/item/ammo_magazine/sniper/incendiary, null, VENDOR_ITEM_REGULAR), list("M42A Marksman Magazine (10x28mm Caseless)", 40, /obj/item/ammo_magazine/sniper, null, VENDOR_ITEM_REGULAR), + list("XM43E1 Marksman Magazine (10x99mm Caseless)", 40, /obj/item/ammo_magazine/sniper/anti_materiel, null, VENDOR_ITEM_REGULAR), list("EXTRA DEMOLITIONIST AMMUNITION", 0, null, null, null), list("84mm Anti-Armor Rocket", 40, /obj/item/ammo_magazine/rocket/ap, null, VENDOR_ITEM_REGULAR), diff --git a/colonialmarines.dme b/colonialmarines.dme index 2c0f257c22c0..a5f92930bf54 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -486,9 +486,9 @@ #include "code\datums\elements\bullet_trait\iff.dm" #include "code\datums\elements\bullet_trait\ignored_range.dm" #include "code\datums\elements\bullet_trait\incendiary.dm" -#include "code\datums\elements\bullet_trait\penetrating\weak.dm" #include "code\datums\elements\bullet_trait\penetrating\heavy.dm" #include "code\datums\elements\bullet_trait\penetrating\penetrating.dm" +#include "code\datums\elements\bullet_trait\penetrating\weak.dm" #include "code\datums\elements\traitbound\_traitbound.dm" #include "code\datums\elements\traitbound\crawler.dm" #include "code\datums\elements\traitbound\gun_silenced.dm" From 531ad7517bb7cc899db4505b87e08ffaba0857f8 Mon Sep 17 00:00:00 2001 From: Kaga-404 <103199482+Kaga-404@users.noreply.github.com> Date: Tue, 27 Feb 2024 02:04:57 -0800 Subject: [PATCH 04/16] Update code/datums/supply_packs/spec_ammo.dm Co-authored-by: forest2001 <41653574+realforest2001@users.noreply.github.com> --- code/datums/supply_packs/spec_ammo.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/supply_packs/spec_ammo.dm b/code/datums/supply_packs/spec_ammo.dm index 4e1d0b34f2be..889d2e25b8af 100644 --- a/code/datums/supply_packs/spec_ammo.dm +++ b/code/datums/supply_packs/spec_ammo.dm @@ -121,7 +121,7 @@ cost = 30 containertype = /obj/structure/closet/crate/ammo containername = "XM43E1 Marksman Magazine Crate" - group = "Specialist Ammo" + group = "Weapons Specialist Ammo" //M4RA From e0ac9cc2ef7e9d40f8829ebffe5a8cd83528e50d Mon Sep 17 00:00:00 2001 From: Kaga-404 <103199482+Kaga-404@users.noreply.github.com> Date: Tue, 27 Feb 2024 02:29:55 -0800 Subject: [PATCH 05/16] Update code/datums/elements/bullet_trait/damage_boost.dm Co-authored-by: Drathek <76988376+Drulikar@users.noreply.github.com> --- code/datums/elements/bullet_trait/damage_boost.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/elements/bullet_trait/damage_boost.dm b/code/datums/elements/bullet_trait/damage_boost.dm index 640026a8dfa9..c32b92bf66d7 100644 --- a/code/datums/elements/bullet_trait/damage_boost.dm +++ b/code/datums/elements/bullet_trait/damage_boost.dm @@ -61,7 +61,7 @@ GLOBAL_LIST_INIT(damage_boost_vehicles, typecacheof(/obj/vehicle/multitile)) /datum/element/bullet_trait_damage_boost/proc/handle_bullet(obj/projectile/P, atom/A) SIGNAL_HANDLER - src.atom_type = check_type(A) + atom_type = check_type(A) switch(atom_type) if("door") From a8f5e8791f44d5670552221579c127f180868545 Mon Sep 17 00:00:00 2001 From: Kaga <103199482+Kaga-404@users.noreply.github.com> Date: Tue, 27 Feb 2024 02:50:20 -0800 Subject: [PATCH 06/16] Variable Name Updates --- code/_globalvars/global_lists.dm | 4 +-- .../elements/bullet_trait/damage_boost.dm | 34 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/code/_globalvars/global_lists.dm b/code/_globalvars/global_lists.dm index fe4c9c83ed9d..a205aa5bd559 100644 --- a/code/_globalvars/global_lists.dm +++ b/code/_globalvars/global_lists.dm @@ -481,10 +481,10 @@ GLOBAL_LIST_EMPTY(timelocks) GLOBAL_LIST_INIT(available_specialist_sets, list( "Scout Set", "Sniper Set", + "Anti-materiel Sniper Set", "Demolitionist Set", "Heavy Grenadier Set", - "Pyro Set", - "Anti-materiel Sniper Set" + "Pyro Set" )) //Similar thing, but used in /obj/item/spec_kit diff --git a/code/datums/elements/bullet_trait/damage_boost.dm b/code/datums/elements/bullet_trait/damage_boost.dm index c32b92bf66d7..165980acb4ab 100644 --- a/code/datums/elements/bullet_trait/damage_boost.dm +++ b/code/datums/elements/bullet_trait/damage_boost.dm @@ -58,17 +58,17 @@ GLOBAL_LIST_INIT(damage_boost_vehicles, typecacheof(/obj/vehicle/multitile)) //add more cases for other interactions (switch doesn't seem to work with istype) else return 0 -/datum/element/bullet_trait_damage_boost/proc/handle_bullet(obj/projectile/P, atom/A) +/datum/element/bullet_trait_damage_boost/proc/handle_bullet(obj/projectile/boosted_projectile, atom/hit_atom) SIGNAL_HANDLER - atom_type = check_type(A) + atom_type = check_type(hit_atom) switch(atom_type) if("door") - var/obj/structure/machinery/door/D = A - if(D.masterkey_resist) - if(D.masterkey_mod) - active_damage_mult = damage_mult * D.masterkey_mod + var/obj/structure/machinery/door/hit_door = hit_atom + if(hit_door.masterkey_resist) + if(hit_door.masterkey_mod) + active_damage_mult = damage_mult * hit_door.masterkey_mod else active_damage_mult = 1 //no bonus damage else @@ -78,21 +78,21 @@ GLOBAL_LIST_INIT(damage_boost_vehicles, typecacheof(/obj/vehicle/multitile)) active_damage_mult = damage_mult - if(P.damage_boosted && (P.last_atom_signaled != A) && (!P.bonus_projectile_check)) + if(boosted_projectile.damage_boosted && (boosted_projectile.last_atom_signaled != hit_atom) && (!boosted_projectile.bonus_projectile_check)) //If this is after a boosted hit, the last atom that procced this isn't the same as the current target, and this isn't a bonus projectile sharing the same damage_boost - if(!P.last_damage_mult) //Make sure stored mult isn't 0 - P.last_damage_mult = 1 + if(!boosted_projectile.last_damage_mult) //Make sure stored mult isn't 0 + boosted_projectile.last_damage_mult = 1 - P.damage = P.damage / P.last_damage_mult //Reduce the damage back to normal - P.damage_boosted-- //Mark that damage has been returned to normal. + boosted_projectile.damage = boosted_projectile.damage / boosted_projectile.last_damage_mult //Reduce the damage back to normal + boosted_projectile.damage_boosted-- //Mark that damage has been returned to normal. - if(damage_boosted_atoms[A.type]) //If hitting a valid atom for damage boost - P.damage = round(P.damage * active_damage_mult) //Modify Damage by multiplier + if(damage_boosted_atoms[hit_atom.type]) //If hitting a valid atom for damage boost + boosted_projectile.damage = round(boosted_projectile.damage * active_damage_mult) //Modify Damage by multiplier if (active_damage_mult) - P.last_damage_mult = active_damage_mult //Save multiplier for next check + boosted_projectile.last_damage_mult = active_damage_mult //Save multiplier for next check else - P.last_damage_mult = 1 + boosted_projectile.last_damage_mult = 1 - P.damage_boosted++ //Mark that a boosted hit occurred. - P.last_atom_signaled = A //Save the current triggering atom to the projectile + boosted_projectile.damage_boosted++ //Mark that a boosted hit occurred. + boosted_projectile.last_atom_signaled = hit_atom //Save the current triggering atom to the projectile From d731a2065cfab066f7aded81f167638b18ff8142 Mon Sep 17 00:00:00 2001 From: Kaga <103199482+Kaga-404@users.noreply.github.com> Date: Tue, 27 Feb 2024 02:50:37 -0800 Subject: [PATCH 07/16] Fixes lineart --- icons/obj/items/weapons/guns/lineart.dmi | Bin 17104 -> 17103 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/icons/obj/items/weapons/guns/lineart.dmi b/icons/obj/items/weapons/guns/lineart.dmi index 6c1dae5bd5c1c37600b270f22be512343c682756..a746bce1716b31ca6ee35585e290962bec69711e 100644 GIT binary patch delta 545 zcmV++0^a@5g#pin0gxnr26|LjbVOxyV{&P5bZKvH004NLm6y$Kqc9YO*WoEpyC3mm z0xY^2wHkFXeFfwM2M`!rwn>_|AJdFxH#(;~8-23xJ@?0#=k({>ulJAi_4j*nRnAXl zO1{~aSQw#_meq6gMleTL}3Mspm>IxjF53&@(Aay;3czQG2GeHzWun=N2& zTf?*tkeh?RjxVBr&~pwkogWzn8x22L__3VQ(Q3A5{cfHOaaPsPUtONNk||a)2z6mLeE8iL8xUm%vi!fi@V->ua8(z zE2ni)9v6e1al%9fcZCRH5v=uNUgM7DXX9)fu4%Btcl($a!A?FHJR8OtQo2zQqm*X{ zG{0G=wCQe`y!Kg!+oHdf6;79(YA|(oae`5dA3=IzDhqe3YFs!E3^&Lx4oh;iHTLyW ji&A0JK6UjIU+6h~`*{8O3H$@LeBi|IY zPDVgVnY3sX=4fz@wt-aJ6z2e`uFfzcd##2G)}tdG_{+)QbT_FB=EG>?ur4$xTh&9j zSDreQbiQYe?7w5=*)>^)L-fF;GaW<+Hk#v5)_H-kR6x$&wC73LeuIq)`!w21Z`X*q zb&1n5KyHo#JAM&=g_(1Rnf%Bw*r)_4;<`fMblD)RmPzri8H!+Vze-GtMK>bH{bhr= zqcn$6aTYmFYaiYUU0k)f&;e)7$c zsKJ`3i4&1`r{avEhDh|LWC~DqIia`mB_V{4~`Rf6aeBynVcW{R931*wx^WKw1ZavoivmK#A86ivR!s From e3323fc0fee3d89358b6783a19ebafe912ac6553 Mon Sep 17 00:00:00 2001 From: Kaga <103199482+Kaga-404@users.noreply.github.com> Date: Tue, 27 Feb 2024 07:26:25 -0800 Subject: [PATCH 08/16] Prototype: Aimed Shot Focusing and Current Health Scaling --- code/datums/ammo/bullet/sniper.dm | 80 +++++++++++++++---- .../projectiles/guns/specialist/sniper.dm | 4 +- 2 files changed, 69 insertions(+), 15 deletions(-) diff --git a/code/datums/ammo/bullet/sniper.dm b/code/datums/ammo/bullet/sniper.dm index a900456e434d..10f0d7fc3ac2 100644 --- a/code/datums/ammo/bullet/sniper.dm +++ b/code/datums/ammo/bullet/sniper.dm @@ -107,20 +107,72 @@ damage = 125 shell_speed = AMMO_SPEED_TIER_6 -/datum/ammo/bullet/sniper/anti_materiel/on_hit_mob(mob/M,obj/projectile/P) - if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original) - var/mob/living/L = M - var/size_damage_mod = 0.8 - if(isxeno(M)) - var/mob/living/carbon/xenomorph/target = M - if(target.mob_size >= MOB_SIZE_XENO) - size_damage_mod += 0.6 - if(target.mob_size >= MOB_SIZE_BIG) - size_damage_mod += 0.6 - L.apply_armoured_damage(damage*size_damage_mod, ARMOR_BULLET, BRUTE, null, penetration) - // Base 180% damage to all targets (225), 240% (300) against non-Runner xenos, and 300% against Big xenos (375). -Kaga - // This applies after pen reductions. After hitting 1 other thing, it deals 180/240/300 damage, or 90/120/150 after hitting a dense wall or big xeno. - to_chat(P.firer, SPAN_WARNING("Bullseye!")) +/datum/ammo/bullet/sniper/anti_materiel/on_hit_mob(mob/target_mob,obj/projectile/aimed_projectile) + if((aimed_projectile.projectile_flags & PROJECTILE_BULLSEYE) && target_mob == aimed_projectile.original) + + var/amr_counter = 0 + + if(istype(aimed_projectile.shot_from, /obj/item/weapon/gun/rifle/sniper/XM43E1)) + var/obj/item/weapon/gun/rifle/sniper/XM43E1/amr = aimed_projectile.shot_from + if(target_mob == amr.focused_fire_target) + if(amr.focused_fire_counter < 2) + amr.focused_fire_counter += 1 + else + amr.focused_fire_counter = 2 + else + amr.focused_fire_counter = 0 + + amr_counter = amr.focused_fire_counter + 1 + amr.focused_fire_target = target_mob + + var/mob/living/living_target = target_mob + var/size_damage_mod = 0.8 // 1.8x vs Non-Xenos (225) + var/size_current_health_damage = 0 // % Current Health calculation, only used for Xeno calculations at the moment. + var/focused_fire_active = 0 // Whether to try and use focused fire calculations or not, for that kind of target. + + if(isxeno(target_mob)) + var/mob/living/carbon/xenomorph/target = target_mob + size_damage_mod -= 0.2 // Down to 1.6x damage, 200. + size_current_health_damage = 0.1 // 1.6x Damage + 10% current health (200 + 10%, 223 vs Runners) + + if(target.mob_size >= MOB_SIZE_XENO && (target.caste_type != XENO_CASTE_DEFENDER)) + size_current_health_damage += 0.1 // 1.6x Damage + 20% current health + focused_fire_active = 1 // Focus Fire Required. Only deals 50% bonus damage on a first Aimed Shot, then 75%, then 100%. Resets with a successful aimed shot on another target. + + if(target.mob_size >= MOB_SIZE_BIG && (target.caste_type != XENO_CASTE_DEFENDER)) + size_damage_mod -= 0.6 // Down to 1x Damage. + size_current_health_damage += 0.1 // 1x Damage + 30% current health. + focused_fire_active = 1 + // Most T3s have around 650 to 700 HP, meaning the health modifier grants a MAXIMUM of around 195-210 damage for a total max of 320-335. This is fully focused (3 shots) and at max HP. + // Queen takes around 275 at max health and unfocused, 425 fully focused. Defender only takes 200 damage, even while fortified, but still causes falloff like a Big Xeno. + // At low health, does little more than a normal shot. Does WORSE than a normal shot if unfocused and hitting through blockers, all of which stack to reduce it. + + var/final_xeno_damage = ((damage * size_damage_mod) + ((target.health + damage) * size_current_health_damage)) + + if(focused_fire_active && amr_counter) // If this is a target that needs to be focus-fired and the gun supports it, reduce bonus damage to 50%, then 75%, then 100% + // If amr_counter is 0, then the gun likely doesn't have the tracker functions, so skip this and deal normal damage. + final_xeno_damage *= (0.25 + (0.25 * amr_counter)) + + living_target.apply_armoured_damage((final_xeno_damage), ARMOR_BULLET, BRUTE, null, penetration) + + else + living_target.apply_armoured_damage((damage*size_damage_mod), ARMOR_BULLET, BRUTE, null, penetration) + + // Base 1.8x damage to non-xeno targets (225), 1.6x + 10% current against Runners (223), 1.2x + 20% current health against most non-Runner xenos, and +30% current health against Big xenos. -Kaga + // This applies after pen reductions. After hitting 1 other thing, it deals 80% damage, or 40% after hitting a dense wall or big xeno. + + if(focused_fire_active) + switch(amr_counter) + if(1) + to_chat(aimed_projectile.firer, SPAN_WARNING("One Hit! You begin to carefully track the target's movements.")) + if(2) + to_chat(aimed_projectile.firer, SPAN_WARNING("Two Hits! You're starting to get a good read on the target's patterns.")) + if(3) + to_chat(aimed_projectile.firer, SPAN_WARNING("Bullseye! You're fully focused on the target.")) + else + to_chat(aimed_projectile.firer, SPAN_WARNING("Bullseye!")) + else + to_chat(aimed_projectile.firer, SPAN_WARNING("Bullseye!")) /datum/ammo/bullet/sniper/anti_materiel/set_bullet_traits() . = ..() diff --git a/code/modules/projectiles/guns/specialist/sniper.dm b/code/modules/projectiles/guns/specialist/sniper.dm index 77ce0069cce3..bb44aaf47ade 100644 --- a/code/modules/projectiles/guns/specialist/sniper.dm +++ b/code/modules/projectiles/guns/specialist/sniper.dm @@ -339,13 +339,15 @@ /obj/item/weapon/gun/rifle/sniper/XM43E1 name = "\improper XM43E1 experimental anti-materiel rifle" - desc = "An experimental anti-materiel rifle produced by Armat Systems, recently reacquired from the deep storage of an abandoned prototyping facility. This one in particular is currently undergoing field testing. Chambered in 10x99mm Caseless." + desc = "An experimental anti-materiel rifle produced by Armat Systems, recently reacquired from the deep storage of an abandoned prototyping facility. This one in particular is currently undergoing field testing. Chambered in 10x99mm Caseless.\nThis weapon can punch through metal plating and walls, though it'll lose most of its lethality in the process. It even works for demolitions, with experienced users known to disassemble solid reinforced walls in the field with a single standard magazine in lieu of explosives of an engineer, using each of the 8 shots to break down vital structural support and take the wall apart." icon = 'icons/obj/items/weapons/guns/guns_by_faction/uscm.dmi' icon_state = "xm43e1" item_state = "xm43e1" unacidable = TRUE indestructible = 1 aimed_shot_cooldown_delay = 4 SECONDS + var/focused_fire_counter = 0 + var/mob/focused_fire_target = null fire_sound = 'sound/weapons/sniper_heavy.ogg' current_mag = /obj/item/ammo_magazine/sniper/anti_materiel //Renamed from anti-tank to align with new identity/description. Other references have been changed as well. -Kaga From 6ebba89c492c71574fc6e26295da6e03333a7f16 Mon Sep 17 00:00:00 2001 From: Kaga <103199482+Kaga-404@users.noreply.github.com> Date: Tue, 27 Feb 2024 07:33:44 -0800 Subject: [PATCH 09/16] Desc Update --- code/modules/projectiles/guns/specialist/sniper.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/projectiles/guns/specialist/sniper.dm b/code/modules/projectiles/guns/specialist/sniper.dm index bb44aaf47ade..16761416d7d5 100644 --- a/code/modules/projectiles/guns/specialist/sniper.dm +++ b/code/modules/projectiles/guns/specialist/sniper.dm @@ -339,7 +339,7 @@ /obj/item/weapon/gun/rifle/sniper/XM43E1 name = "\improper XM43E1 experimental anti-materiel rifle" - desc = "An experimental anti-materiel rifle produced by Armat Systems, recently reacquired from the deep storage of an abandoned prototyping facility. This one in particular is currently undergoing field testing. Chambered in 10x99mm Caseless.\nThis weapon can punch through metal plating and walls, though it'll lose most of its lethality in the process. It even works for demolitions, with experienced users known to disassemble solid reinforced walls in the field with a single standard magazine in lieu of explosives of an engineer, using each of the 8 shots to break down vital structural support and take the wall apart." + desc = "An experimental anti-materiel rifle produced by Armat Systems, recently reacquired from the deep storage of an abandoned prototyping facility. This one in particular is currently undergoing field testing. Chambered in 10x99mm Caseless.\nThis weapon can punch through thin metal plating and walls, though it'll lose most of its lethality in the process. It can even work for demolitions, with experienced users known to disassemble segments of solid, reinforced walls in the field with just a single standard magazine of 10x99mm. In lieu of explosives or an engineer, they instead use each of the 8 shots to break down vital structural supports, taking the wall apart in the process." icon = 'icons/obj/items/weapons/guns/guns_by_faction/uscm.dmi' icon_state = "xm43e1" item_state = "xm43e1" From cca9bf350d09f37344926289ed6ff499042ea637 Mon Sep 17 00:00:00 2001 From: Kaga <103199482+Kaga-404@users.noreply.github.com> Date: Tue, 27 Feb 2024 17:55:46 -0800 Subject: [PATCH 10/16] hardrefs to weakrefs --- code/datums/ammo/bullet/sniper.dm | 4 ++-- code/datums/elements/bullet_trait/damage_boost.dm | 4 ++-- code/modules/projectiles/guns/specialist/sniper.dm | 2 +- code/modules/projectiles/projectile.dm | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/code/datums/ammo/bullet/sniper.dm b/code/datums/ammo/bullet/sniper.dm index 10f0d7fc3ac2..1900802ad350 100644 --- a/code/datums/ammo/bullet/sniper.dm +++ b/code/datums/ammo/bullet/sniper.dm @@ -114,7 +114,7 @@ if(istype(aimed_projectile.shot_from, /obj/item/weapon/gun/rifle/sniper/XM43E1)) var/obj/item/weapon/gun/rifle/sniper/XM43E1/amr = aimed_projectile.shot_from - if(target_mob == amr.focused_fire_target) + if(target_mob == (amr.focused_fire_target?.resolve())) if(amr.focused_fire_counter < 2) amr.focused_fire_counter += 1 else @@ -123,7 +123,7 @@ amr.focused_fire_counter = 0 amr_counter = amr.focused_fire_counter + 1 - amr.focused_fire_target = target_mob + amr.focused_fire_target = WEAKREF(target_mob) var/mob/living/living_target = target_mob var/size_damage_mod = 0.8 // 1.8x vs Non-Xenos (225) diff --git a/code/datums/elements/bullet_trait/damage_boost.dm b/code/datums/elements/bullet_trait/damage_boost.dm index 165980acb4ab..43d9d1b23377 100644 --- a/code/datums/elements/bullet_trait/damage_boost.dm +++ b/code/datums/elements/bullet_trait/damage_boost.dm @@ -78,7 +78,7 @@ GLOBAL_LIST_INIT(damage_boost_vehicles, typecacheof(/obj/vehicle/multitile)) active_damage_mult = damage_mult - if(boosted_projectile.damage_boosted && (boosted_projectile.last_atom_signaled != hit_atom) && (!boosted_projectile.bonus_projectile_check)) + if(boosted_projectile.damage_boosted && ((boosted_projectile.last_atom_signaled?.resolve()) != hit_atom) && (!boosted_projectile.bonus_projectile_check)) //If this is after a boosted hit, the last atom that procced this isn't the same as the current target, and this isn't a bonus projectile sharing the same damage_boost if(!boosted_projectile.last_damage_mult) //Make sure stored mult isn't 0 boosted_projectile.last_damage_mult = 1 @@ -95,4 +95,4 @@ GLOBAL_LIST_INIT(damage_boost_vehicles, typecacheof(/obj/vehicle/multitile)) boosted_projectile.last_damage_mult = 1 boosted_projectile.damage_boosted++ //Mark that a boosted hit occurred. - boosted_projectile.last_atom_signaled = hit_atom //Save the current triggering atom to the projectile + boosted_projectile.last_atom_signaled = WEAKREF(hit_atom) //Save the current triggering atom to the projectile diff --git a/code/modules/projectiles/guns/specialist/sniper.dm b/code/modules/projectiles/guns/specialist/sniper.dm index 16761416d7d5..5cfdbf556080 100644 --- a/code/modules/projectiles/guns/specialist/sniper.dm +++ b/code/modules/projectiles/guns/specialist/sniper.dm @@ -347,7 +347,7 @@ indestructible = 1 aimed_shot_cooldown_delay = 4 SECONDS var/focused_fire_counter = 0 - var/mob/focused_fire_target = null + var/datum/weakref/focused_fire_target = null fire_sound = 'sound/weapons/sniper_heavy.ogg' current_mag = /obj/item/ammo_magazine/sniper/anti_materiel //Renamed from anti-tank to align with new identity/description. Other references have been changed as well. -Kaga diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index c3a27f7117fe..8e0e7ee003c4 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -84,7 +84,7 @@ var/bonus_projectile_check = 0 /// What atom did this last receive a registered signal from? Used by damage_boost.dm - var/atom/last_atom_signaled = null + var/datum/weakref/last_atom_signaled = null /// Was this projectile affected by damage_boost.dm? If so, what was the last modifier? var/damage_boosted = 0 From a82f520c4da53ea061905541963bde10fb5593cf Mon Sep 17 00:00:00 2001 From: Kaga <103199482+Kaga-404@users.noreply.github.com> Date: Wed, 28 Feb 2024 17:37:39 -0800 Subject: [PATCH 11/16] Different title on ID + kit can be picked again after cryo --- code/game/machinery/cryopod.dm | 1 + code/game/machinery/vending/cm_vending.dm | 2 +- code/modules/cm_marines/equipment/kit_boxes.dm | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index 69c2c897e276..1793b87c72ae 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -342,6 +342,7 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li set_name = "Scout Set" if(SKILL_SPEC_SNIPER) set_name = "Sniper Set" + GLOB.available_specialist_sets += "Anti-materiel Sniper Set" if(set_name && !GLOB.available_specialist_sets.Find(set_name)) GLOB.available_specialist_sets += set_name diff --git a/code/game/machinery/vending/cm_vending.dm b/code/game/machinery/vending/cm_vending.dm index 56977d23675b..19aaec500fa2 100644 --- a/code/game/machinery/vending/cm_vending.dm +++ b/code/game/machinery/vending/cm_vending.dm @@ -569,7 +569,7 @@ GLOBAL_LIST_EMPTY(vending_products) GLOB.available_specialist_sets -= "Anti-materiel Sniper Set" if("Anti-materiel Sniper Set") user.skills.set_skill(SKILL_SPEC_WEAPONS, SKILL_SPEC_SNIPER) - specialist_assignment = "Sniper" + specialist_assignment = "Heavy Sniper" GLOB.available_specialist_sets -= "Sniper Set" if("Demolitionist Set") user.skills.set_skill(SKILL_SPEC_WEAPONS, SKILL_SPEC_ROCKET) diff --git a/code/modules/cm_marines/equipment/kit_boxes.dm b/code/modules/cm_marines/equipment/kit_boxes.dm index cdf91b6ef076..c26bafe7123a 100644 --- a/code/modules/cm_marines/equipment/kit_boxes.dm +++ b/code/modules/cm_marines/equipment/kit_boxes.dm @@ -279,7 +279,7 @@ user.skills.set_skill(SKILL_SPEC_WEAPONS, SKILL_SPEC_SNIPER) if("Anti-materiel Sniper") spec_box = new /obj/item/storage/box/spec/sniper/anti_materiel(T) - specialist_assignment = "Sniper" + specialist_assignment = "Heavy Sniper" user.skills.set_skill(SKILL_SPEC_WEAPONS, SKILL_SPEC_SNIPER) if("Scout") spec_box = new /obj/item/storage/box/spec/scout(T) From 8d63ab4430e96533ab2c19a676feb2ab321519e3 Mon Sep 17 00:00:00 2001 From: Kaga <103199482+Kaga-404@users.noreply.github.com> Date: Tue, 12 Mar 2024 19:32:42 -0700 Subject: [PATCH 12/16] Firerate define, aimed shot marker, aiming through glass. --- code/__DEFINES/weapon_stats.dm | 1 + code/datums/ammo/bullet/sniper.dm | 38 ++++++++++++++++--- .../mob/living/carbon/human/human_defines.dm | 3 ++ .../projectiles/guns/specialist/sniper.dm | 12 +++--- 4 files changed, 42 insertions(+), 12 deletions(-) diff --git a/code/__DEFINES/weapon_stats.dm b/code/__DEFINES/weapon_stats.dm index 3a69002a3b93..d4cbd92628aa 100644 --- a/code/__DEFINES/weapon_stats.dm +++ b/code/__DEFINES/weapon_stats.dm @@ -137,6 +137,7 @@ As such, don't expect any values assigned to common firearms to even consider ho */ #define FIRE_DELAY_TIER_VULTURE 20 +#define FIRE_DELAY_TIER_SNIPER 15 #define FIRE_DELAY_TIER_1 12 #define FIRE_DELAY_TIER_2 10 #define FIRE_DELAY_TIER_3 9 diff --git a/code/datums/ammo/bullet/sniper.dm b/code/datums/ammo/bullet/sniper.dm index 1900802ad350..6568e5ab0023 100644 --- a/code/datums/ammo/bullet/sniper.dm +++ b/code/datums/ammo/bullet/sniper.dm @@ -108,24 +108,45 @@ shell_speed = AMMO_SPEED_TIER_6 /datum/ammo/bullet/sniper/anti_materiel/on_hit_mob(mob/target_mob,obj/projectile/aimed_projectile) + + var/mob/living/living_target = target_mob + if((aimed_projectile.projectile_flags & PROJECTILE_BULLSEYE) && target_mob == aimed_projectile.original) var/amr_counter = 0 + var/datum/weakref/old_target = null // This is used to let xenos know when they're no longer targeted. + + var/mob/living/carbon/human/human_firer + var/image/focused_fire_marker_temp = image('icons/mob/hud/hud.dmi', target_mob, "hudeye") + + if(istype(aimed_projectile.firer, /mob/living/carbon/human)) // Preps the Focused Fire marker. + human_firer = aimed_projectile.firer + focused_fire_marker_temp.color = human_firer.assigned_squad?.chat_color - if(istype(aimed_projectile.shot_from, /obj/item/weapon/gun/rifle/sniper/XM43E1)) + if(target_mob.icon_size > world.icon_size) // Centers marker on their tile. + focused_fire_marker_temp.pixel_x = (target_mob.icon_size / 4) + + if(istype(aimed_projectile.shot_from, /obj/item/weapon/gun/rifle/sniper/XM43E1)) // Calculates the Focus Counter. var/obj/item/weapon/gun/rifle/sniper/XM43E1/amr = aimed_projectile.shot_from + + old_target = amr.focused_fire_target + if(target_mob == (amr.focused_fire_target?.resolve())) - if(amr.focused_fire_counter < 2) + if(amr.focused_fire_counter < 2) // Can stack up to twice. amr.focused_fire_counter += 1 else amr.focused_fire_counter = 2 - else - amr.focused_fire_counter = 0 + else // If it's a new target + amr.focused_fire_counter = 0 // Stacks to 0 + if(human_firer) + human_firer.client?.images -= human_firer?.focused_fire_marker // Remove old marker + qdel(human_firer?.focused_fire_marker) + human_firer.focused_fire_marker = focused_fire_marker_temp // Store new marker ref + human_firer.client?.images += focused_fire_marker_temp // Add new marker amr_counter = amr.focused_fire_counter + 1 amr.focused_fire_target = WEAKREF(target_mob) - var/mob/living/living_target = target_mob var/size_damage_mod = 0.8 // 1.8x vs Non-Xenos (225) var/size_current_health_damage = 0 // % Current Health calculation, only used for Xeno calculations at the moment. var/focused_fire_active = 0 // Whether to try and use focused fire calculations or not, for that kind of target. @@ -158,13 +179,18 @@ else living_target.apply_armoured_damage((damage*size_damage_mod), ARMOR_BULLET, BRUTE, null, penetration) - // Base 1.8x damage to non-xeno targets (225), 1.6x + 10% current against Runners (223), 1.2x + 20% current health against most non-Runner xenos, and +30% current health against Big xenos. -Kaga + // Base 1.8x damage to non-xeno targets (225), 1.6x + 10% current against Runners and Defenders (223), 1.6x + 20% current health against most non-Runner xenos, and +30% current health against Big xenos. -Kaga // This applies after pen reductions. After hitting 1 other thing, it deals 80% damage, or 40% after hitting a dense wall or big xeno. if(focused_fire_active) switch(amr_counter) if(1) to_chat(aimed_projectile.firer, SPAN_WARNING("One Hit! You begin to carefully track the target's movements.")) + if(isxeno(target_mob) && isxeno(old_target?.resolve())) + var/mob/living/carbon/xenomorph/old_xeno = old_target?.resolve() + var/mob/living/carbon/xenomorph/new_xeno = target_mob + if(old_xeno.hive == new_xeno.hive) + to_chat(old_xeno,SPAN_XENOLEADER("We sense that the far-spitter host has begun targeting another sister.")) if(2) to_chat(aimed_projectile.firer, SPAN_WARNING("Two Hits! You're starting to get a good read on the target's patterns.")) if(3) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 9ec9d0b05ec5..7d5c6d23a6cb 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -167,6 +167,9 @@ /// static associated list of limb key -> image to avoid unnecessary overlay generation var/static/list/icon_render_image_cache = list() + /// Stored image references associated with focus-fire. + var/image/focused_fire_marker + /client/var/cached_human_playtime /client/proc/get_total_human_playtime(skip_cache = FALSE) diff --git a/code/modules/projectiles/guns/specialist/sniper.dm b/code/modules/projectiles/guns/specialist/sniper.dm index 5cfdbf556080..a2acb70fda4c 100644 --- a/code/modules/projectiles/guns/specialist/sniper.dm +++ b/code/modules/projectiles/guns/specialist/sniper.dm @@ -204,12 +204,12 @@ var/blocked = FALSE for(var/turf/T in path) - if(T.density || T.opacity) + if(T.density && T.opacity) blocked = TRUE break for(var/obj/O in T) - if(O.get_projectile_hit_boolean(P)) + if(O.get_projectile_hit_boolean(P) && O.opacity) blocked = TRUE break @@ -330,7 +330,7 @@ /obj/item/weapon/gun/rifle/sniper/M42A/set_gun_config_values() ..() - set_fire_delay(FIRE_DELAY_TIER_7*3) + set_fire_delay(FIRE_DELAY_TIER_SNIPER) set_burst_amount(BURST_AMOUNT_TIER_1) accuracy_mult = BASE_ACCURACY_MULT * 3 //you HAVE to be able to hit scatter = SCATTER_AMOUNT_TIER_8 @@ -345,7 +345,7 @@ item_state = "xm43e1" unacidable = TRUE indestructible = 1 - aimed_shot_cooldown_delay = 4 SECONDS + aimed_shot_cooldown_delay = 4.5 SECONDS var/focused_fire_counter = 0 var/datum/weakref/focused_fire_target = null @@ -377,8 +377,8 @@ /obj/item/weapon/gun/rifle/sniper/XM43E1/set_gun_config_values() ..() - set_fire_delay(FIRE_DELAY_TIER_6 * 6 )//Big boy damage, but it takes a lot of time to fire a shot. - //Kaga: Adjusted from 56 (Tier 4, 7*8) -> 30 (Tier 6, 5*6) ticks. 95 really wasn't big-boy damage anymore, although I updated it to 125 to remain consistent with the other 10x99mm caliber weapon (M42C). Now takes only twice as long as the M42A. + set_fire_delay(FIRE_DELAY_TIER_SNIPER * 2)//Big boy damage, but it takes a lot of time to fire a shot. + //Kaga: Fixed back to half the M42A's firerate (3 seconds), using a new define. //This outright deals less DPS than the normal sniper rifle, 125 vs 140 per 3s. set_burst_amount(BURST_AMOUNT_TIER_1) accuracy_mult = BASE_ACCURACY_MULT + 2*HIT_ACCURACY_MULT_TIER_10 //Who coded this like this, and why? It just calculates out to 1+1=2. Leaving a note here to check back later. From 4b81b686bd5d3a8c9a45af923da0aacef4a13df0 Mon Sep 17 00:00:00 2001 From: Kaga-404 <103199482+Kaga-404@users.noreply.github.com> Date: Mon, 18 Mar 2024 03:27:27 -0700 Subject: [PATCH 13/16] Capitalization suggestions Co-authored-by: Drathek <76988376+Drulikar@users.noreply.github.com> --- code/datums/ammo/bullet/sniper.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/datums/ammo/bullet/sniper.dm b/code/datums/ammo/bullet/sniper.dm index 6568e5ab0023..88ae6db2fc06 100644 --- a/code/datums/ammo/bullet/sniper.dm +++ b/code/datums/ammo/bullet/sniper.dm @@ -185,14 +185,14 @@ if(focused_fire_active) switch(amr_counter) if(1) - to_chat(aimed_projectile.firer, SPAN_WARNING("One Hit! You begin to carefully track the target's movements.")) + to_chat(aimed_projectile.firer, SPAN_WARNING("One hit! You begin to carefully track the target's movements.")) if(isxeno(target_mob) && isxeno(old_target?.resolve())) var/mob/living/carbon/xenomorph/old_xeno = old_target?.resolve() var/mob/living/carbon/xenomorph/new_xeno = target_mob if(old_xeno.hive == new_xeno.hive) to_chat(old_xeno,SPAN_XENOLEADER("We sense that the far-spitter host has begun targeting another sister.")) if(2) - to_chat(aimed_projectile.firer, SPAN_WARNING("Two Hits! You're starting to get a good read on the target's patterns.")) + to_chat(aimed_projectile.firer, SPAN_WARNING("Two hits! You're starting to get a good read on the target's patterns.")) if(3) to_chat(aimed_projectile.firer, SPAN_WARNING("Bullseye! You're fully focused on the target.")) else From e51606625e7d0497ff92f011339e9c3623c9dfcc Mon Sep 17 00:00:00 2001 From: Kaga-404 <103199482+Kaga-404@users.noreply.github.com> Date: Mon, 18 Mar 2024 03:28:10 -0700 Subject: [PATCH 14/16] .? suggestions Co-authored-by: Drathek <76988376+Drulikar@users.noreply.github.com> --- code/datums/ammo/bullet/sniper.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/datums/ammo/bullet/sniper.dm b/code/datums/ammo/bullet/sniper.dm index 88ae6db2fc06..48a0c56ea73c 100644 --- a/code/datums/ammo/bullet/sniper.dm +++ b/code/datums/ammo/bullet/sniper.dm @@ -139,8 +139,8 @@ else // If it's a new target amr.focused_fire_counter = 0 // Stacks to 0 if(human_firer) - human_firer.client?.images -= human_firer?.focused_fire_marker // Remove old marker - qdel(human_firer?.focused_fire_marker) + human_firer.client?.images -= human_firer.focused_fire_marker // Remove old marker + qdel(human_firer.focused_fire_marker) human_firer.focused_fire_marker = focused_fire_marker_temp // Store new marker ref human_firer.client?.images += focused_fire_marker_temp // Add new marker @@ -187,7 +187,7 @@ if(1) to_chat(aimed_projectile.firer, SPAN_WARNING("One hit! You begin to carefully track the target's movements.")) if(isxeno(target_mob) && isxeno(old_target?.resolve())) - var/mob/living/carbon/xenomorph/old_xeno = old_target?.resolve() + var/mob/living/carbon/xenomorph/old_xeno = old_target.resolve() var/mob/living/carbon/xenomorph/new_xeno = target_mob if(old_xeno.hive == new_xeno.hive) to_chat(old_xeno,SPAN_XENOLEADER("We sense that the far-spitter host has begun targeting another sister.")) From 47e5cbc185fb77c4c2aa91461cf7af645d5f8741 Mon Sep 17 00:00:00 2001 From: Kaga <103199482+Kaga-404@users.noreply.github.com> Date: Tue, 19 Mar 2024 12:10:52 -0700 Subject: [PATCH 15/16] Split firerate defines + is_dead check for focus message --- code/__DEFINES/weapon_stats.dm | 1 + code/datums/ammo/bullet/sniper.dm | 6 +++--- code/modules/projectiles/guns/specialist/sniper.dm | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/code/__DEFINES/weapon_stats.dm b/code/__DEFINES/weapon_stats.dm index d4cbd92628aa..1c3c09e9b28d 100644 --- a/code/__DEFINES/weapon_stats.dm +++ b/code/__DEFINES/weapon_stats.dm @@ -136,6 +136,7 @@ As such, don't expect any values assigned to common firearms to even consider ho //How many ticks you have to wait between firing. Burst delay uses the same variable! */ +#define FIRE_DELAY_TIER_AMR 30 #define FIRE_DELAY_TIER_VULTURE 20 #define FIRE_DELAY_TIER_SNIPER 15 #define FIRE_DELAY_TIER_1 12 diff --git a/code/datums/ammo/bullet/sniper.dm b/code/datums/ammo/bullet/sniper.dm index 48a0c56ea73c..56fb98d05e15 100644 --- a/code/datums/ammo/bullet/sniper.dm +++ b/code/datums/ammo/bullet/sniper.dm @@ -138,7 +138,7 @@ amr.focused_fire_counter = 2 else // If it's a new target amr.focused_fire_counter = 0 // Stacks to 0 - if(human_firer) + if(human_firer && !(target_mob.is_dead())) human_firer.client?.images -= human_firer.focused_fire_marker // Remove old marker qdel(human_firer.focused_fire_marker) human_firer.focused_fire_marker = focused_fire_marker_temp // Store new marker ref @@ -182,7 +182,7 @@ // Base 1.8x damage to non-xeno targets (225), 1.6x + 10% current against Runners and Defenders (223), 1.6x + 20% current health against most non-Runner xenos, and +30% current health against Big xenos. -Kaga // This applies after pen reductions. After hitting 1 other thing, it deals 80% damage, or 40% after hitting a dense wall or big xeno. - if(focused_fire_active) + if(focused_fire_active && !(target_mob.is_dead())) switch(amr_counter) if(1) to_chat(aimed_projectile.firer, SPAN_WARNING("One hit! You begin to carefully track the target's movements.")) @@ -190,7 +190,7 @@ var/mob/living/carbon/xenomorph/old_xeno = old_target.resolve() var/mob/living/carbon/xenomorph/new_xeno = target_mob if(old_xeno.hive == new_xeno.hive) - to_chat(old_xeno,SPAN_XENOLEADER("We sense that the far-spitter host has begun targeting another sister.")) + to_chat(old_xeno,SPAN_XENOLEADER("We sense that the far-spitter host is targeting another sister.")) if(2) to_chat(aimed_projectile.firer, SPAN_WARNING("Two hits! You're starting to get a good read on the target's patterns.")) if(3) diff --git a/code/modules/projectiles/guns/specialist/sniper.dm b/code/modules/projectiles/guns/specialist/sniper.dm index a2acb70fda4c..e919fbae9c19 100644 --- a/code/modules/projectiles/guns/specialist/sniper.dm +++ b/code/modules/projectiles/guns/specialist/sniper.dm @@ -377,7 +377,7 @@ /obj/item/weapon/gun/rifle/sniper/XM43E1/set_gun_config_values() ..() - set_fire_delay(FIRE_DELAY_TIER_SNIPER * 2)//Big boy damage, but it takes a lot of time to fire a shot. + set_fire_delay(FIRE_DELAY_TIER_AMR)//Big boy damage, but it takes a lot of time to fire a shot. //Kaga: Fixed back to half the M42A's firerate (3 seconds), using a new define. //This outright deals less DPS than the normal sniper rifle, 125 vs 140 per 3s. set_burst_amount(BURST_AMOUNT_TIER_1) From 174c8ba2c11585ad2c998b483a3fdacfccfaf57e Mon Sep 17 00:00:00 2001 From: Kaga <103199482+Kaga-404@users.noreply.github.com> Date: Thu, 21 Mar 2024 21:56:47 -0700 Subject: [PATCH 16/16] State check for the sending note --- code/datums/ammo/bullet/sniper.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/ammo/bullet/sniper.dm b/code/datums/ammo/bullet/sniper.dm index 56fb98d05e15..31f5a281c04d 100644 --- a/code/datums/ammo/bullet/sniper.dm +++ b/code/datums/ammo/bullet/sniper.dm @@ -189,7 +189,7 @@ if(isxeno(target_mob) && isxeno(old_target?.resolve())) var/mob/living/carbon/xenomorph/old_xeno = old_target.resolve() var/mob/living/carbon/xenomorph/new_xeno = target_mob - if(old_xeno.hive == new_xeno.hive) + if((old_xeno.hive == new_xeno.hive) && !(old_xeno.stat)) // Must be in same hive and conscious to_chat(old_xeno,SPAN_XENOLEADER("We sense that the far-spitter host is targeting another sister.")) if(2) to_chat(aimed_projectile.firer, SPAN_WARNING("Two hits! You're starting to get a good read on the target's patterns."))