Limits beacons to only one of its type. Beacons are actually deleted if the mech is EMP'd, which appears to be a dead feature for almost a decade? (#91660)

## About The Pull Request

Firstly, mech beacons are limited to one of each type.

Secondly, mechs, when EMP'd, may potentially delete the beacons
installed in itself. The probability is based on the severity of the
EMP. 20% chance if the EMP is light. 40% chance if the EMP is heavy.

## Why It's Good For The Game

> Type limitations

I don't think stacking 10 tracking beacons on the same mech to instacook
it is intended. The extra beacons do not do anything. It's just to make
it easier to EMP.

> Beacon Deletion

So what if I told you that there is code in control beacons that
suggests they are intended to be deleted when EMP'd, which wouldn't make
sense unless it could be EMP'd in the mech? What if I said this code has
been there for a really long time? What if I told you it never worked?

I'm not going to sit here and pretend like this is a fix. We've played
with this being the case for a really long time. But it is dead code and
I'm gonna implement it because I think it solves a really annoying
problem with beacons, which is that once they're in, you can't get them
out again. I do still think the beacon is a strong strategy, even if it
self deletes. And I do think you'll get your moneys worth if you manage
to stick one in the mech. It's not like they can eject it early. Even
just one EMP is going to fuck up that mech. Especially true if it has
both types of beacons (since its two EMPs).

## Changelog
🆑
balance: Mecha that are EMP'd properly delete their tracking beacons
after many years where they haven't. There is a probability for whether
or not the beacon is destroyed from an EMP.
fix:  You cannot stack multiple of the same beacon onto a single mech.
/🆑
This commit is contained in:
necromanceranne
2025-07-03 20:40:38 +02:00
committed by GitHub
parent 82a5c6590e
commit 57d561d4bc
3 changed files with 29 additions and 22 deletions
+2
View File
@@ -73,6 +73,8 @@
#define MECH_EMP_DAMAGE_LOWER 100
#define MECH_EMP_DAMAGE_UPPER 180
#define MECH_EMP_BEACON_DESTRUCTION_PROB 40
/// bitflags for do_after checks on mechs
#define MECH_DO_AFTER_DIR_CHANGE_FLAG (1 << 0)
#define MECH_DO_AFTER_ADJACENCY_FLAG (1 << 1)
@@ -52,25 +52,25 @@
switch(action)
if("send_message")
var/obj/item/mecha_parts/mecha_tracking/MT = locate(params["tracker_ref"])
if(!istype(MT))
var/obj/item/mecha_parts/mecha_tracking/our_mecha_tracker = locate(params["tracker_ref"])
if(!istype(our_mecha_tracker))
return
var/message = tgui_input_text(usr, "Input message", "Transmit message", max_length = MAX_MESSAGE_LEN)
var/obj/vehicle/sealed/mecha/M = MT.chassis
if(trim(message) && M)
to_chat(M.occupants, message)
var/obj/vehicle/sealed/mecha/our_mecha = our_mecha_tracker.chassis
if(trim(message) && our_mecha)
to_chat(our_mecha.occupants, message)
to_chat(usr, span_notice("Message sent."))
. = TRUE
if("shock")
var/obj/item/mecha_parts/mecha_tracking/MT = locate(params["tracker_ref"])
if(!istype(MT))
var/obj/item/mecha_parts/mecha_tracking/our_mecha_tracker = locate(params["tracker_ref"])
if(!istype(our_mecha_tracker))
return
var/obj/vehicle/sealed/mecha/M = MT.chassis
if(M)
MT.shock()
usr.log_message("has activated remote EMP on exosuit [M], located at [loc_name(M)], which is currently [LAZYLEN(M.occupants) ? "occupied by [M.occupants.Join(", ")]." : "without a pilot."]", LOG_ATTACK)
usr.log_message("has activated remote EMP on exosuit [M], located at [loc_name(M)], which is currently [LAZYLEN(M.occupants) ? "occupied by [M.occupants.Join(", ")]." : "without a pilot."]", LOG_GAME, log_globally = FALSE)
message_admins("[key_name_admin(usr)][ADMIN_FLW(usr)] has activated remote EMP on exosuit [M][ADMIN_JMP(M)], which is currently [LAZYLEN(M.occupants) ? "occupied by [M.occupants.Join(",")][ADMIN_FLW(M)]." : "without a pilot."]")
var/obj/vehicle/sealed/mecha/our_mecha = our_mecha_tracker.chassis
if(our_mecha)
our_mecha_tracker.shock()
usr.log_message("has activated remote EMP on exosuit [our_mecha], located at [loc_name(our_mecha)], which is currently [LAZYLEN(our_mecha.occupants) ? "occupied by [our_mecha.occupants.Join(", ")]." : "without a pilot."]", LOG_ATTACK)
usr.log_message("has activated remote EMP on exosuit [our_mecha], located at [loc_name(our_mecha)], which is currently [LAZYLEN(our_mecha.occupants) ? "occupied by [our_mecha.occupants.Join(", ")]." : "without a pilot."]", LOG_GAME, log_globally = FALSE)
message_admins("[key_name_admin(usr)][ADMIN_FLW(usr)] has activated remote EMP on exosuit [our_mecha][ADMIN_JMP(our_mecha)], which is currently [LAZYLEN(our_mecha.occupants) ? "occupied by [our_mecha.occupants.Join(",")][ADMIN_FLW(our_mecha)]." : "without a pilot."]")
. = TRUE
/obj/item/mecha_parts/mecha_tracking
@@ -111,11 +111,6 @@
return jointext(output, "\n")
/obj/item/mecha_parts/mecha_tracking/emp_act(severity)
. = ..()
if(!(. & EMP_PROTECT_SELF))
qdel(src)
/obj/item/mecha_parts/mecha_tracking/Destroy()
if(chassis)
if(src in chassis.trackers)
@@ -126,6 +121,9 @@
/obj/item/mecha_parts/mecha_tracking/try_attach_part(mob/user, obj/vehicle/sealed/mecha/mecha_to_attach, attach_right = FALSE)
if(!(mecha_to_attach.mecha_flags & flag_to_check))
return
for(var/obj/item/mecha_parts/mecha_tracking/tracker in chassis.trackers)
if(tracker.flag_to_check == flag_to_check)
return //there can only be one...type of this tracker
if(!..())
return
mecha_to_attach.trackers += src
@@ -138,10 +136,11 @@
/obj/item/mecha_parts/mecha_tracking/proc/shock()
if(recharging)
return
if(chassis)
chassis.emp_act(EMP_HEAVY)
addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/mecha_parts/mecha_tracking, recharge)), 5 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE)
recharging = TRUE
if(!chassis)
return
chassis.emp_act(EMP_HEAVY)
addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/mecha_parts/mecha_tracking, recharge)), 5 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE)
recharging = TRUE
/**
* Resets recharge variable, allowing tracker to be EMP pulsed again
@@ -192,6 +192,12 @@
diag_hud_set_camera()
addtimer(CALLBACK(chassis_camera, TYPE_PROC_REF(/obj/machinery/camera/exosuit, emp_refocus), src), 10 SECONDS / severity)
for(var/obj/item/mecha_parts/mecha_tracking/tracker in trackers) // Go through our list of trackers and potentially delete our trackers due to an EMP.
if(prob(MECH_EMP_BEACON_DESTRUCTION_PROB / severity))
if((mecha_flags & SILICON_PILOT) && tracker.ai_beacon) // ignore any beacons which allows our AI pilot to be in the mech. Even if it isn't using a beacon, let's just do this to be safe. The code doesn't make a distinction! YAY!
continue // Does this mean that a AI tracking beacon can be EMP'd over and over without risk of self-destruction? Yes. Is this a nerf to silicon mechs? I guess. Do I care? No.
qdel(tracker)
if(!equipment_disabled && LAZYLEN(occupants)) //prevent spamming this message with back-to-back EMPs
to_chat(occupants, span_warning("Error -- Connection to equipment control unit has been lost."))
addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/vehicle/sealed/mecha, restore_equipment)), 3 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE)