The Great Lasertag Update (#18691)

* Save~

* Fixes launch_many_projectiles having 100% miss chance

Adds laser landmines.
Makes it so portable turrets don't do janky BS for lasertag.
Gives portable lasertag turrets a fun emag/EMP effect

* emag and equipment

* cargo

* tur et

* milsim rp

* clarify

* PLEASE I HAVE A FAMILY

* cries

* signal drop

* no spawn
This commit is contained in:
Cameron Lennox
2025-11-08 03:13:33 +01:00
committed by GitHub
parent 7b656d712c
commit ee47237aa7
25 changed files with 553 additions and 229 deletions
+152
View File
@@ -0,0 +1,152 @@
/*
* Handles lasertag attacks. Anything can call this.
* Target can be a mob or a lasertag vest on the ground.
* Attacker can be null (if vest_override is set) or a human mob
* tag_damage is how much damage is dealt to the vest (defaults to 1 if no value given)
* vest_override allows attacking without wearing a vest (defaults to FALSE)
* required_vest is a list of what vests are required to have on to do damage
* allowed_suits are what vests the attack is able to deal damage to. Must be a LIST. If not passed, we assume all suits are valid targets.
* returns TRUE if damage was (theoretically) dealt. FALSE if not.
*
*/
/proc/handle_lasertag_attack(target, mob/living/carbon/human/attacker, tag_damage, vest_override, required_vest, list/allowed_suits)
//So, attacker should ALWAYS be true, but there's a problem. The code doesn't actually set 'thrower' which we used for thrown laser knives.
//Instead of this PR getting massively out of scope and refactoring throwing code, we're just going to have thrown knives do vest override.
if(vest_override || (attacker && istype(attacker) && (!required_vest || istype(attacker.wear_suit, required_vest))))
if(ishuman(target))
var/mob/living/carbon/human/human_target = target
if(!allowed_suits) //Wasn't fed a suit. Let's just affect everything.
allowed_suits = list(/obj/item/clothing/suit/lasertag)
if(is_type_in_list(human_target.wear_suit, allowed_suits))
var/obj/item/clothing/suit/lasertag/laser_suit = human_target.wear_suit
laser_suit.handle_hit(tag_damage)
return TRUE
//We allow allow demonstrations of shooting it while it's on the ground.
else if(is_type_in_list(target, allowed_suits))
var/obj/item/clothing/suit/lasertag/laser_suit = target
laser_suit.handle_hit(tag_damage)
return TRUE
if(attacker)
to_chat(attacker, span_warning("You need to be wearing your laser tag vest to use this!"))
return FALSE
/obj/item/gun/energy/lasertag
name = "omni laser tag gun"
desc = "A laser tag gun that works on all vests!"
icon = 'icons/obj/gun_toy.dmi'
item_state = "omnitag"
item_state = "retro"
origin_tech = list(TECH_COMBAT = 1, TECH_MAGNET = 2)
matter = list(MAT_STEEL = 2000)
projectile_type = /obj/item/projectile/beam/lasertag/omni
cell_type = /obj/item/cell/device/weapon/recharge
battery_lock = 1
var/required_vest = /obj/item/clothing/suit/lasertag/omni
///Allows firing without a vest.
var/vest_override = FALSE
/obj/item/gun/energy/lasertag/special_check(var/mob/living/carbon/human/M)
if(ishuman(M) && !vest_override)
if(!istype(M.wear_suit, required_vest))
to_chat(M, span_warning("You need to be wearing your laser tag vest!"))
return FALSE
var/obj/item/clothing/suit/lasertag/tag_vest = M.wear_suit
if(tag_vest.lasertag_health <= 0)
to_chat(M, span_warning("You're out of health!"))
return FALSE
return ..()
/obj/item/gun/energy/lasertag/blue
icon_state = "bluetag"
item_state = "bluetag"
projectile_type = /obj/item/projectile/beam/lasertag/blue
required_vest = /obj/item/clothing/suit/lasertag/bluetag
fire_delay = 10
/obj/item/gun/energy/lasertag/blue/sub
name = "Brigader Sidearm"
desc = "A laser tag replica of the standard issue weapon for the Spacer Union Brigade from the hit series Spacer Trail (Blue Team)."
icon_state = "bluetwo"
item_state = "retro"
/obj/item/gun/energy/lasertag/red
icon_state = "redtag"
item_state = "redtag"
projectile_type = /obj/item/projectile/beam/lasertag/red
required_vest = /obj/item/clothing/suit/lasertag/redtag
fire_delay = 10
/obj/item/gun/energy/lasertag/red/dom
name = "Mu'tu'bi sidearm"
desc = "A laser tag replica of the Mu'tu'bi sidearm from the hit series Spacer Trail (Red Team)."
icon_state = "redtwo"
item_state = "retro"
/obj/item/gun/energy/lasertag/omni
icon_state = "omnitag"
item_state = "omnitag"
projectile_type = /obj/item/projectile/beam/lasertag/omni
//The lasertag knives also go here because whatever, go my bullshit explanation.
/obj/item/lasertagknife
name = "universal laser tag dagger"
desc = "Rubber knife with a glowing fancy edge. It has no team allegiance!"
icon = 'icons/obj/weapons.dmi'
icon_state = "tagknifeomni"
item_icons = list(slot_l_hand_str = 'icons/mob/items/lefthand_melee.dmi',slot_r_hand_str = 'icons/mob/items/righthand_melee.dmi',)
item_state_slots = list(slot_r_hand_str = "tagknifeomni", slot_l_hand_str = "tagknifeomni")
item_state = null
hitsound = null
w_class = ITEMSIZE_SMALL
attackspeed = 1.2 SECONDS
attack_verb = list("patted", "tapped")
drop_sound = 'sound/items/drop/knife.ogg'
pickup_sound = 'sound/items/pickup/knife.ogg'
///The vest we have to wear to use the knife.
var/required_vest = /obj/item/clothing/suit/lasertag/omni
///If we need a vest on ourselves to use it or not.
var/vest_override = FALSE
///How much damage it does to the lasertag vest. Generally for oneshots.
var/tag_damage = 5
///What vests we are allowed to hit with the knife.
var/list/allowed_suits = list(/obj/item/clothing/suit/lasertag/bluetag, /obj/item/clothing/suit/lasertag/redtag, /obj/item/clothing/suit/lasertag/omni)
/obj/item/lasertagknife/blue
name = "blue laser tag dagger"
desc = "Rubber knife with a blue glowing fancy edge!"
icon_state = "tagknifeblue"
item_state_slots = list(slot_r_hand_str = "tagknifeblue", slot_l_hand_str = "tagknifeblue")
required_vest = /obj/item/clothing/suit/lasertag/bluetag
allowed_suits = list(/obj/item/clothing/suit/lasertag/redtag, /obj/item/clothing/suit/lasertag/omni)
/obj/item/lasertagknife/red
name = "red laser tag dagger"
desc = "Rubber knife with a red glowing fancy edge!"
icon_state = "tagknifered"
item_state_slots = list(slot_r_hand_str = "tagknifered", slot_l_hand_str = "tagknifered")
required_vest = /obj/item/clothing/suit/lasertag/redtag
allowed_suits = list(/obj/item/clothing/suit/lasertag/bluetag, /obj/item/clothing/suit/lasertag/omni)
//We have to do this if(user) check all over the place because for some reason someone broke thrower code. Thanks.
/obj/item/lasertagknife/attack(target, mob/user)
if(user)
user.setClickCooldown(user.get_attack_speed(src))
user.do_attack_animation(target)
var/success = handle_lasertag_attack(target, user, tag_damage, vest_override, required_vest, allowed_suits)
if(success)
user.visible_message(span_danger("[target] has been zapped with [src] by [user]!"))
playsound(src, 'sound/weapons/Egloves.ogg', 50, 1, -1)
else
user.visible_message(span_danger("[target] has been harmlessly bonked with [src] by [user]!"))
playsound(src, 'sound/weapons/punchmiss.ogg', 75, 1)
return TRUE
///go my hack
/obj/item/lasertagknife/throw_impact(atom/hit_atom, var/speed)
if(ismob(hit_atom))
//So, attacker should ALWAYS be true, but there's a problem. The code doesn't actually set 'thrower' which we used for thrown laser knives.
//Instead of this PR getting massively out of scope and refactoring throwing code, we're just going to have thrown knives do vest override.
return handle_lasertag_attack(hit_atom, thrower, tag_damage, TRUE, required_vest, allowed_suits)
..()
-61
View File
@@ -258,64 +258,3 @@
to_chat(user, "The [src] vacuums in the darts!")
else
to_chat(user, "No Donk-Soft brand foam darts detected. Aborting.")
/*
* Laser Tag
*/
/obj/item/gun/energy/lasertag
name = "laser tag gun"
desc = "Standard issue weapon of the Imperial Guard."
icon = 'icons/obj/gun_toy.dmi'
item_state = "omnitag"
item_state = "retro"
origin_tech = list(TECH_COMBAT = 1, TECH_MAGNET = 2)
matter = list(MAT_STEEL = 2000)
projectile_type = /obj/item/projectile/beam/lasertag/blue
cell_type = /obj/item/cell/device/weapon/recharge
battery_lock = 1
var/required_vest
/obj/item/gun/energy/lasertag/special_check(var/mob/living/carbon/human/M)
if(ishuman(M))
if(!istype(M.wear_suit, required_vest))
to_chat(M, span_warning("You need to be wearing your laser tag vest!"))
return 0
return ..()
/obj/item/gun/energy/lasertag/blue
icon_state = "bluetag"
item_state = "bluetag"
projectile_type = /obj/item/projectile/beam/lasertag/blue
required_vest = /obj/item/clothing/suit/bluetag
fire_delay = 10
firemodes = list(
list(mode_name="instagib rules", fire_delay=10, projectile_type=/obj/item/projectile/beam/lasertag/blue, charge_cost = 240),
list(mode_name="multi-hit rules", fire_delay=5, projectile_type=/obj/item/projectile/beam/lasertag/blue/multihit, charge_cost = 120),
)
/obj/item/gun/energy/lasertag/blue/sub
name = "Brigader Sidearm"
desc = "A laser tag replica of the standard issue weapon for the Spacer Union Brigade from the hit series Spacer Trail (Blue Team)."
icon_state = "bluetwo"
item_state = "retro"
/obj/item/gun/energy/lasertag/red
icon_state = "redtag"
item_state = "redtag"
projectile_type = /obj/item/projectile/beam/lasertag/red
required_vest = /obj/item/clothing/suit/redtag
fire_delay = 10
firemodes = list(
list(mode_name="instagib rules", fire_delay=12, projectile_type=/obj/item/projectile/beam/lasertag/red, charge_cost = 240),
list(mode_name="multi-hit rules", fire_delay=5, projectile_type=/obj/item/projectile/beam/lasertag/red/multihit, charge_cost = 120),
)
/obj/item/gun/energy/lasertag/red/dom
name = "Mu'tu'bi sidearm"
desc = "A laser tag replica of the Mu'tu'bi sidearm from the hit series Spacer Trail (Red Team)."
icon_state = "redtwo"
item_state = "retro"
/obj/item/gun/energy/lasertag/omni
projectile_type = /obj/item/projectile/beam/lasertag/omni
+17 -55
View File
@@ -224,9 +224,17 @@
damage_type = BURN
check_armour = "laser"
hud_state = "monkey"
///What suits this beam can hit.
var/list/allowed_suits = list(/obj/item/clothing/suit/lasertag/omni, /obj/item/clothing/suit/lasertag/bluetag, /obj/item/clothing/suit/lasertag/redtag)
///How much damage we do to the tag vest.
var/tag_damage = 1
combustion = FALSE
/obj/item/projectile/beam/lasertag/on_hit(var/atom/target, var/blocked = 0)
return handle_lasertag_attack(target, firer, tag_damage, TRUE, allowed_suits = allowed_suits) //We can't shoot this in the first place without having the proper vest / vest_override, so we feed it vest_override = TRUE
/obj/item/projectile/beam/lasertag/blue
icon_state = "bluelaser"
light_color = "#0066FF"
@@ -234,76 +242,25 @@
muzzle_type = /obj/effect/projectile/muzzle/laser_blue
tracer_type = /obj/effect/projectile/tracer/laser_blue
impact_type = /obj/effect/projectile/impact/laser_blue
allowed_suits = list(/obj/item/clothing/suit/lasertag/redtag, /obj/item/clothing/suit/lasertag/omni)
/obj/item/projectile/beam/lasertag/blue/on_hit(var/atom/target, var/blocked = 0)
if(ishuman(target))
var/mob/living/carbon/human/M = target
if(istype(M.wear_suit, /obj/item/clothing/suit/redtag))
M.Weaken(5)
return 1
/obj/item/projectile/beam/lasertag/blue/multhit
name = "blue multi-hit lasertag beam"
/obj/item/projectile/beam/lasertag/blue/multihit/on_hit(var/atom/target, var/blocked = 0)
if(ishuman(target))
var/mob/living/carbon/human/M = target
if(istype(M.wear_suit, /obj/item/clothing/suit/redtag))
var/obj/item/clothing/suit/redtag/S = M.wear_suit
if (S.lasertag_health <= 1)
M.Weaken(5)
to_chat(M,span_warning("You have been defeated!"))
S.lasertag_health = initial(S.lasertag_health)
else
S.lasertag_health--
to_chat(M,span_warning("Danger! You have [num2text(S.lasertag_health)] hits remaining!"))
return 1
/obj/item/projectile/beam/lasertag/red
icon_state = "laser"
light_color = "#FF0D00"
hud_state = "monkey"
/obj/item/projectile/beam/lasertag/red/on_hit(var/atom/target, var/blocked = 0)
if(ishuman(target))
var/mob/living/carbon/human/M = target
if(istype(M.wear_suit, /obj/item/clothing/suit/bluetag))
M.Weaken(5)
return 1
/obj/item/projectile/beam/lasertag/red/multhit
name = "red multi-hit lasertag beam"
/obj/item/projectile/beam/lasertag/red/multihit/on_hit(var/atom/target, var/blocked = 0)
if(ishuman(target))
var/mob/living/carbon/human/M = target
if(istype(M.wear_suit, /obj/item/clothing/suit/bluetag))
var/obj/item/clothing/suit/bluetag/S = M.wear_suit
if(S.lasertag_health <= 1)
M.Weaken(5)
to_chat(M,span_warning("You have been defeated!"))
S.lasertag_health = initial(S.lasertag_health)
else
S.lasertag_health--
to_chat(M,span_warning("Danger! You have [num2text(S.lasertag_health)] hits remaining!"))
return 1
allowed_suits = list(/obj/item/clothing/suit/lasertag/bluetag, /obj/item/clothing/suit/lasertag/omni)
/obj/item/projectile/beam/lasertag/omni//A laser tag bolt that stuns EVERYONE
icon_state = "omnilaser"
light_color = "#00C6FF"
light_color = "#AA24AF"
hud_state = "monkey"
allowed_suits = list(/obj/item/clothing/suit/lasertag)
muzzle_type = /obj/effect/projectile/muzzle/laser_omni
tracer_type = /obj/effect/projectile/tracer/laser_omni
impact_type = /obj/effect/projectile/impact/laser_omni
/obj/item/projectile/beam/lasertag/omni/on_hit(var/atom/target, var/blocked = 0)
if(ishuman(target))
var/mob/living/carbon/human/M = target
if((istype(M.wear_suit, /obj/item/clothing/suit/bluetag))||(istype(M.wear_suit, /obj/item/clothing/suit/redtag)))
M.Weaken(5)
return 1
/obj/item/projectile/beam/sniper
name = "sniper beam"
icon_state = "xray"
@@ -444,6 +401,11 @@
hud_state = "laser"
damage = 20
/obj/item/projectile/beam/rainbow/non_lethal
damage = 0
agony = 50
damage_type = HALLOSS
/obj/item/projectile/beam/sparkledog
name = "rainbow"
fire_sound = 'sound/weapons/sparkle.ogg'
@@ -446,6 +446,10 @@
if(istype(T))
new /obj/item/ammo_casing/afoam_dart(get_turf(loc))
///Doesn't give a damn about what faction you're on, hits you anyway.
/obj/item/projectile/bullet/foam_dart/on_hit(var/atom/target, var/blocked = 0)
handle_lasertag_attack(target, firer, tag_damage = 1, vest_override = TRUE)
/obj/item/projectile/bullet/foam_dart/on_range(var/atom/A)
. = ..()
var/turf/T = get_turf(loc)
@@ -480,3 +484,6 @@
var/turf/T = get_turf(loc)
if(istype(T))
new /obj/item/ammo_casing/afoam_dart/riot(get_turf(loc))
/obj/item/projectile/bullet/foam_dart_riot/on_hit(var/atom/target, var/blocked = 0)
handle_lasertag_attack(target, firer, 5, vest_override = TRUE) //Insult to injury.