diff --git a/sound/items/weapons/attributions.txt b/sound/items/weapons/attributions.txt index 6a7d58874db..a7e4c78883b 100644 --- a/sound/items/weapons/attributions.txt +++ b/sound/items/weapons/attributions.txt @@ -2,3 +2,5 @@ rust_sower_armbomb.ogg - EnterTheJake rust_sower_explode.ogg - EnterTheJake } + +laser.ogg and laser2.ogg are e-fire.ogg and heavy_laser.ogg from Shiptest (https://github.com/shiptest-ss13/Shiptest), CC BY-SA 3.0. diff --git a/sound/items/weapons/laser.ogg b/sound/items/weapons/laser.ogg index 5e4d3143097..bb8242352f2 100644 Binary files a/sound/items/weapons/laser.ogg and b/sound/items/weapons/laser.ogg differ diff --git a/sound/items/weapons/laser2.ogg b/sound/items/weapons/laser2.ogg index 30715495771..1b81326da3c 100644 Binary files a/sound/items/weapons/laser2.ogg and b/sound/items/weapons/laser2.ogg differ diff --git a/tgstation.dme b/tgstation.dme index 6a322525331..b785bc7830c 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6925,6 +6925,7 @@ #include "voidcrew\edits\modules\power\supermatter_anomalies.dm" #include "voidcrew\edits\modules\power\turbine\turbine.dm" #include "voidcrew\edits\modules\projectiles\boxes_magazines\_box_magazine.dm" +#include "voidcrew\edits\modules\projectiles\projectile\beams.dm" #include "voidcrew\edits\modules\research\designs.dm" #include "voidcrew\edits\modules\research\designs\comp_board_designs.dm" #include "voidcrew\edits\modules\research\designs\machine_designs.dm" diff --git a/voidcrew/edits/modules/projectiles/projectile/beams.dm b/voidcrew/edits/modules/projectiles/projectile/beams.dm new file mode 100644 index 00000000000..53cdac8986d --- /dev/null +++ b/voidcrew/edits/modules/projectiles/projectile/beams.dm @@ -0,0 +1,55 @@ +// Voidcrew: the standard laser family is hitscan. A laser lands the moment it is fired and leaves +// tg's beam tracer along its path, instead of flying as a bolt. Same damage as upstream; the instant +// hit is the change. Reflection, blocking, glass and every on-hit signal run exactly as for a bolt, +// because tg's hitscan walks the same per-tile movement and hit code (projectile.dm process_hitscan). +// +// Stays a travelling bolt: disablers and other stun beams, X-ray, pulse, emitters, the ship defense +// turret, lasertag, CTF, mech lasers (below) and the two lasers whose look is the projectile itself. + +/obj/projectile/beam/laser + hitscan = TRUE + +/// Its ball grows as it flies (reduce_range), which a hitscan beam never shows. +/obj/projectile/beam/laser/accelerator + hitscan = FALSE + +/// Genetics laser eyes keep their own eye-beam sprite. +/obj/projectile/beam/laser/laser_eyes + hitscan = FALSE + +// Lasers outside /beam/laser that laser guns and turrets fire. Upstream gives them no tracer. + +/// Laser scattershot and scatter laser shells. +/obj/projectile/beam/scatter + hitscan = TRUE + tracer_type = /obj/effect/projectile/tracer/laser + muzzle_type = /obj/effect/projectile/muzzle/laser + impact_type = /obj/effect/projectile/impact/laser + +/// Laser gatling and some turrets. +/obj/projectile/beam/weak + hitscan = TRUE + tracer_type = /obj/effect/projectile/tracer/laser + muzzle_type = /obj/effect/projectile/muzzle/laser + impact_type = /obj/effect/projectile/impact/laser + +/// Practice laser guns. +/obj/projectile/beam/practice + hitscan = TRUE + tracer_type = /obj/effect/projectile/tracer/laser + muzzle_type = /obj/effect/projectile/muzzle/laser + impact_type = /obj/effect/projectile/impact/laser + +// Mech lasers stay bolts: exosuit weapons are balanced on their own, apart from hand guns. + +/obj/projectile/beam/laser/mech + hitscan = FALSE + +/obj/projectile/beam/laser/heavylaser/mech + hitscan = FALSE + +/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser + projectile = /obj/projectile/beam/laser/mech + +/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy + projectile = /obj/projectile/beam/laser/heavylaser/mech diff --git a/voidcrew/modules/unit_tests/_unit_tests.dm b/voidcrew/modules/unit_tests/_unit_tests.dm index e70ad1b8e66..b9e6637a61f 100644 --- a/voidcrew/modules/unit_tests/_unit_tests.dm +++ b/voidcrew/modules/unit_tests/_unit_tests.dm @@ -93,6 +93,7 @@ #include "voidcrew_gene_injector_loot.dm" #include "voidcrew_helm_access.dm" #include "voidcrew_helpers.dm" +#include "voidcrew_hitscan_lasers.dm" #include "voidcrew_hull_containment.dm" #include "voidcrew_hull_survey.dm" #include "voidcrew_launch_access.dm" diff --git a/voidcrew/modules/unit_tests/voidcrew_hitscan_lasers.dm b/voidcrew/modules/unit_tests/voidcrew_hitscan_lasers.dm new file mode 100644 index 00000000000..273bb2604ac --- /dev/null +++ b/voidcrew/modules/unit_tests/voidcrew_hitscan_lasers.dm @@ -0,0 +1,57 @@ +/// Standard lasers are hitscan with a visible tracer; the beams we chose to keep as bolts are not. +/datum/unit_test/voidcrew_hitscan_lasers/Run() + var/list/obj/projectile/hitscan_types = list( + /obj/projectile/beam/laser, + /obj/projectile/beam/laser/carbine, + /obj/projectile/beam/laser/carbine/cybersun, + /obj/projectile/beam/laser/hellfire, + /obj/projectile/beam/laser/heavylaser, + /obj/projectile/beam/laser/musket, + /obj/projectile/beam/laser/outpost, + /obj/projectile/beam/scatter, + /obj/projectile/beam/weak/penetrator, + /obj/projectile/beam/practice, + ) + for(var/obj/projectile/laser_type as anything in hitscan_types) + TEST_ASSERT(initial(laser_type.hitscan), "[laser_type] is not hitscan") + TEST_ASSERT_NOTNULL(initial(laser_type.tracer_type), "[laser_type] is hitscan with no tracer, so its beam is invisible") + + var/list/obj/projectile/bolt_types = list( + /obj/projectile/beam/disabler, + /obj/projectile/beam/xray, + /obj/projectile/beam/pulse, + /obj/projectile/beam/emitter, + /obj/projectile/beam/ship_defense, + /obj/projectile/beam/laser/accelerator, + /obj/projectile/beam/laser/laser_eyes, + /obj/projectile/beam/laser/mech, + /obj/projectile/beam/laser/heavylaser/mech, + ) + for(var/obj/projectile/bolt_type as anything in bolt_types) + TEST_ASSERT(!initial(bolt_type.hitscan), "[bolt_type] became hitscan") + + var/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/mech_laser = /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser + TEST_ASSERT_EQUAL(initial(mech_laser.projectile), /obj/projectile/beam/laser/mech, "The mech laser fires a hitscan laser") + +/// A hitscan laser fired at someone three tiles away lands, from a bare projectile and from a trigger pull. +/// The beam finishes on the firing tick unless the tick is overrun, which it always is in a test, so wait for it. +/datum/unit_test/voidcrew_hitscan_laser_lands/Run() + var/mob/living/carbon/human/consistent/shooter = allocate(/mob/living/carbon/human/consistent, run_loc_floor_bottom_left) + var/turf/target_turf = locate(run_loc_floor_bottom_left.x + 3, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z) + var/mob/living/carbon/human/consistent/target = allocate(/mob/living/carbon/human/consistent, target_turf) + + var/obj/projectile/beam/laser/beam = new(run_loc_floor_bottom_left) + beam.aim_projectile(target, shooter) + beam.firer = shooter + beam.fire() + UNTIL(QDELETED(beam)) + TEST_ASSERT(target.getFireLoss() > 0, "A hitscan laser fired at a target three tiles away missed") + + var/before = target.getFireLoss() + var/obj/item/gun/energy/laser/rifle = allocate(/obj/item/gun/energy/laser) + TEST_ASSERT(shooter.put_in_active_hand(rifle), "The shooter could not hold the laser rifle") + var/charge_before = rifle.cell.charge + rifle.fire_gun(target, shooter, FALSE) + TEST_ASSERT(rifle.cell.charge < charge_before, "The laser rifle did not fire") + sleep(1 SECONDS) + TEST_ASSERT(target.getFireLoss() > before, "A laser rifle shot three tiles away missed")