From 57d561d4bcebcb96644c7a952d01747ab4d8bfad Mon Sep 17 00:00:00 2001 From: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Date: Fri, 4 Jul 2025 04:40:38 +1000 Subject: [PATCH] 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 :cl: 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. /:cl: --- code/__DEFINES/mecha.dm | 2 + .../vehicles/mecha/mecha_control_console.dm | 43 +++++++++---------- code/modules/vehicles/mecha/mecha_defense.dm | 6 +++ 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/code/__DEFINES/mecha.dm b/code/__DEFINES/mecha.dm index 78128b250c6..602a34d76c4 100644 --- a/code/__DEFINES/mecha.dm +++ b/code/__DEFINES/mecha.dm @@ -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) diff --git a/code/modules/vehicles/mecha/mecha_control_console.dm b/code/modules/vehicles/mecha/mecha_control_console.dm index 42d4a460d03..8d87825c808 100644 --- a/code/modules/vehicles/mecha/mecha_control_console.dm +++ b/code/modules/vehicles/mecha/mecha_control_console.dm @@ -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 diff --git a/code/modules/vehicles/mecha/mecha_defense.dm b/code/modules/vehicles/mecha/mecha_defense.dm index 0714d9dd07b..5bb9084c550 100644 --- a/code/modules/vehicles/mecha/mecha_defense.dm +++ b/code/modules/vehicles/mecha/mecha_defense.dm @@ -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)