Skip to content

Commit

Permalink
Updated XM43E1 for Sniper Spec (#5774)
Browse files Browse the repository at this point in the history
# About the pull request

New Updates:
- Using Aimed Shot on a fully-focused target will now change the laser
and icon to blue.
- 
- Aimed Shot Damage has been adjusted across the board with two new
effects, which stack together.
- The first is **current health damage**, which allows it to stay about
as dangerous against full-health Xenos, but reduces the pressure at low
health, and the likelihood of going from 375 HP to crit immediately.
Low-health burst sniping becomes even more unlikely from Aimed Shots
when combined with the second effect, **Focused Fire**. The scaling is
20% against most xenos, and 30% against big xenos.
- **Focused Fire** triggers whenever Aimed Shot lands on a target,
though it only modifies damage applied to most xenos at the moment,
except Runners. This effect reduces the bonus Aimed Shot Damage by 50%
when hitting a new target. However, subsequent Aimed Shot hits against
the same xeno will increase the modifier, with the second going up to
75%, and then the 3 onwards at 100%. **This effect resets when landing
an Aimed Shot on another target.** If you're the sniper, consider using
normal shots for damage and support to preserve your focus on a priority
target.
- Defenders are now excluded from the higher-tier size calculations, so
they only take 200 + 10% current health damage from Aimed Shots. Focused
Fire damage reduction doesn't apply to them because of this, but it
might be added in if they still continue to struggle when trying to
block shots for allies. However, they may also be targeted less by the
ability with this update, and only take normal hits (can survive 4-5 on
weeds, which takes the sniper about 16-20s of open sightlines and free
shots) because the focus mark is being kept on a more dangerous target.

Fixed PR built from the master branch. Thank you to Zonespace for the
idea of making a Wall-Penetrating Ammo subtype, with more nuance and
falloff mechanics to expand on stemming from the Vulture, and all the
help in messing around with the code.

The XM43E1 is an experimental anti-materiel rifle that's existed in the
code for a while as a test weapon, but had several bugs and insufficient
testing. This PR should hopefully allow it to be testmerged in a
balanced manner as an M42A sniper sidegrade, without the need for staff
to spawn it in. It can be picked as a normal option from Spec Vendors,
being mutually exclusive with the M42A, as well as cryo spec kits.

Its design purpose is that of a sniper weapon that fires slower, with
less direct combat utility, but more supportive utility and higher
impact on shots that actually land. To this purpose, in comparison to
the normal sniper rifle (M42A), it:
- Has around half the magazine of the normal sniper (8 vs 15)
- Has slightly less damage potential within the magazine (1000 vs 1050)
- Has less DPS than the M42A (125 vs 140, per 3s)
- Loses out on combining ammunition types, and their special effects. It
cannot set targets on fire, hit around corners with flak, or use their
respective special effects from aimed shots (blindness and slows).
- Has special damage scaling on its aimed shot, causing it to lose
massive amounts of potential damage per magazine when hitting small
targets. 1.8x vs Non-Xenos and Runners, 2.4x vs most Xenos, and only the
normal 3x vs Big Xenos. Most T3s, the Queen, and Fortified Defenders.
This comes out to as little as 1800 damage per magazine from Aimed
Shots, compared to Marksman M42A mags dealing up to 3150, with a max
single-target potential of 3000 vs 3150.

In return, however, it has higher single-shot damage that allows for
more surprising burst, and effects of its own to enable alternative
support and utility, alongside special balancing to make them more
balanced and interesting to play around, explained below.

Also included in this PR are several backend fixes to actually make this
work properly - without this, the weapon would deal more damage when
wallbanging, and also deal multiplied damage to mobs inside of walls,
like a Queen building beneath herself.
# Explain why it's good for the game

The updated XM43E1's design keeps the weapon's wall-and-mob-piercing,
but adds in **_falloff_** for balancing and interactivity, **_which
applies to everything it hits_.** While it retains massive damage
against walls and structures, able to break even Thick Resin in a single
shot, normal metal walls in 4, and reinforced in 8, it now loses a huge
portion of its energy when doing so, subsequently reducing its damage
and penetration power.

What this means in practice is that it can no longer theoretically
multiply its potential damage by up to 8x if everything lines up. In
fact, it can barely even get through 2 walls, doing very little damage
after that. Mobs, it can handle a bit better, but bodyblocking for more
vulnerable targets is a valid strategy to try and protect allies from
the AMR. You take the brunt of the hit, and increase their technical
DPS, but greatly blunt the damage to the targets behind you.

The actual numbers are 20% reduction in damage for most targets hit, and
60% for dense walls (normal and resin walls) **_and Big Xenos_.** Note
that this _does not include Resin Membranes or windows_, which goes into
another of the XM43E1's sidegrade utilities: the ability to **_fight
Boilers_**, something Sniper Spec has been lacking for years ever since
the caste was updated, and a feature this weapon had been originally
been designed around.

Membranes will still reduces the AMR's effectiveness temporarily, but
such defenses break under sustained focus from it, forcing the Boiler to
either seek out allies to cover for it (Fortify Defender escort is
back!) or shift to new positions and angles, prepared by builders to
force the AMR to expend more ammo.

Additionally, this also affects the Aimed Shot's potential, stacking
with the existing special modifiers. Against single targets, the XM43E1
is still far inferior in most cases, only being able to deal more damage
when you can only fire off one shot before needing to run, at the cost
of way less actual damage and none of the special effects compared to
the M42A's special ammos, but in a crowd it gains some benefits and
loses others.

The main benefit is that the technical damage it's dealing is
increasing. More targets, more hits, more efficiency. **_However, the
Aimed Shot target can be covered by others, potentially reducing that
multiplier down, or even blocking the shot completely_.** A few big
xenos can entirely eat an Aimed Shot for a Queen, **_and they don't take
the increased damage_.**

Wallbreaking and wallbanging potential is also heavily reduced by this
new effect, as the XM43E1 should usually only be able to hit targets at
most 2 walls in, and that's within pretty close ranges. At most sniping
ranges it'll probably be only one. It can break a Thick Resin Wall in 1
shot, but it'll only slightly hurt the second one behind that, and have
to spend another full shot to break that down, and so on. The Sniper
Spec also doesn't have thermals, so while true wallbanging is still
possible, it's not consistent like the PMC Sniper, nor is it nearly as
effective due to the above mentioned falloff. You'll be looking at
around like 50 damage after just 1 wall.

That one shot can save people, though, like the old-school masterkey
supports. Gotta get someone out who got dragged behind a door? Blast
away like the XM51 does these days, except from a long-range support
position. Its design also emphasizes aiming for structural weakspots
like Resin Membranes, glass, and doors.

Essentially, it serves as a sidegrade where you trade off superior
overall stats, extremely flexible combat utility, and special Aimed Shot
effects for:
- Slightly worse damage against single target, but better damage against
multiple that line up, with diminished effectiveness for each target, at
long ranges, and against big xenos.
- An Aimed Shot 60% as efficient as a M42A's aimed shot against runners,
80% against most xenos, and only equal efficiency against big xenos. It
can potentially still hit and get that sweet multiplier through a few
xenos, or if a target ducks behind a wall once the shot goes out but
before it hits. However, any blocking, whether mobs or walls, will
greatly reduce the final damage, and may even completely block it. No
more hitting a full damage Aimed Shot through 7 xenos.
- The ability to break singular walls and obstacles with precisely aimed
shots, especially resin, but at the cost of a full shot. You only get 8
per mag, and each mag costs the same as a sniper's, and it'll be 3
seconds before you can shoot something else.
- A weapon that isn't CAS/Mortar/OB to counter Boilers, by easily
breaking their cover and chipping away at them, and performing better
against peeking than the M42A's lower single-shot damage.
# Testing Photographs and Procedure
<details>
<summary>Screenshots & Videos</summary>

Put screenshots and videos here with an empty line between the
screenshots and the `<details>` tags.

</details>


# Changelog
:cl: Kaga
add: Added the XM43E1 Anti-Materiel Rifle as a pickable sidegrade option
for USCM Sniper Specs through the vendor, mutually exclusive with the
normal M42A Sniper Rifle. The AMR can shred obstacles, blow a hole
through most infantry and their equipment, and even hit a collateral on
multiple targets or through light cover, but its lack of specialized
ammunition and small magazine mean that you'll need to make every shot
count. Ammo can be bought from Req, at the same cost per magazine as the
M42A.
balance: Completely updated the XM43E1 AMR, adding damage falloff to its
wall-piercing properties whenever it hits something alongside range
loss. Most things reduce its damage by 20%. Dense walls and big xenos
reduce both the damage and range 3 times as much.
/:cl:

---------

Co-authored-by: forest2001 <[email protected]>
Co-authored-by: Drathek <[email protected]>
  • Loading branch information
3 people committed Apr 6, 2024
1 parent 7dbca5b commit 48fde5d
Show file tree
Hide file tree
Showing 18 changed files with 291 additions and 58 deletions.
2 changes: 2 additions & 0 deletions code/__DEFINES/weapon_stats.dm
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,9 @@ 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
#define FIRE_DELAY_TIER_2 10
#define FIRE_DELAY_TIER_3 9
Expand Down
2 changes: 2 additions & 0 deletions code/_globalvars/global_lists.dm
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,7 @@ 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"
Expand All @@ -502,6 +503,7 @@ GLOBAL_LIST_INIT(available_specialist_kit_boxes, list(
"Sniper" = 2,
"Scout" = 2,
"Demo" = 2,
"Anti-materiel Sniper" = 2,
))

/proc/init_global_referenced_datums()
Expand Down
1 change: 1 addition & 0 deletions code/datums/ammo/ammo.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
111 changes: 98 additions & 13 deletions code/datums/ammo/bullet/sniper.dm
Original file line number Diff line number Diff line change
Expand Up @@ -107,19 +107,104 @@
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)
// 180% damage to all targets (225), 240% (300) against non-Runner xenos, and 300% against Big xenos (375). -Kaga
to_chat(P.firer, SPAN_WARNING("Bullseye!"))
/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(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) // Can stack up to twice.
amr.focused_fire_counter += 1
else
amr.focused_fire_counter = 2
else // If it's a new target
amr.focused_fire_counter = 0 // Stacks to 0
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
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/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 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 || isxeno(target_mob)) && !(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."))
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) && !(old_xeno.stat)) // Must be in same hive and conscious
to_chat(old_xeno,SPAN_XENOLEADER("The feeling of looming danger fades as we sense that another sister has been targeted instead."))
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()
. = ..()
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
Expand Down
50 changes: 25 additions & 25 deletions code/datums/elements/bullet_trait/damage_boost.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand All @@ -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,
Expand All @@ -68,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
Expand All @@ -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(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

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[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)
boosted_projectile.last_damage_mult = active_damage_mult //Save multiplier for next check
else
boosted_projectile.last_damage_mult = 1

boosted_projectile.damage_boosted++ //Mark that a boosted hit occurred.
boosted_projectile.last_atom_signaled = WEAKREF(hit_atom) //Save the current triggering atom to the projectile
60 changes: 60 additions & 0 deletions code/datums/elements/bullet_trait/penetrating/weak.dm
Original file line number Diff line number Diff line change
@@ -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
8 changes: 3 additions & 5 deletions code/datums/supply_packs/spec_ammo.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -122,9 +120,9 @@
)
cost = 30
containertype = /obj/structure/closet/crate/ammo
containername = "XM43E1 Anti-Materiel Magazine Crate"
group = "Specialist Ammo"
*/
containername = "XM43E1 Marksman Magazine Crate"
group = "Weapons Specialist Ammo"

//M4RA

/datum/supply_packs/ammo_scout_mix
Expand Down
1 change: 1 addition & 0 deletions code/game/machinery/cryopod.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions code/game/machinery/vending/cm_vending.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "Heavy Sniper"
GLOB.available_specialist_sets -= "Sniper Set"
if("Demolitionist Set")
user.skills.set_skill(SKILL_SPEC_WEAPONS, SKILL_SPEC_ROCKET)
specialist_assignment = "Demo"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -17,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),
Expand Down
24 changes: 24 additions & 0 deletions code/modules/cm_marines/equipment/kit_boxes.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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."
Expand Down Expand Up @@ -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 = "Heavy 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"
Expand Down
Loading

0 comments on commit 48fde5d

Please sign in to comment.