Fixes an exploit with stacking igniters. Refactors some assembly flag oddities. Limits assembly holders at 12 assemblies. (#71264)

## About The Pull Request

Soft revert of #71224 , Fixes #71222

Fixes an exploit involving attachment of multiple igniters to one
assembly.
- Multiple igniters or condensers can no longer be attached to the same
assembly holder
- Assembly holders have a limit of 12 assemblies maximum
- I'm not sure if this is too low or limited, I picked it arbitrarily.
Please inform me if it could be upped a smidge.
- This lag exploit was born because of limitless assembly holders, which
is a little silly even with the exploit aside. All that uncapped holders
can bring are exploits or bugs, which I feel confident limited can
prevent. What use is there even for having so many?
- Cleans up / refactors some aspects of assemblies and assembly holders.
- Assemblies had a weird wire type flag that was only ever used by
signallers, but also used wrong by signallers. I did some scanning of
the code and realized that ... a lot of this was just straight up
unused, and not even assigned anywhere.
- Now, there is a flag assembly flag var, which everything is read off
of. Tested it and still seemed to all work fine.

## Why It's Good For The Game

Lag exploits are bad. 

## Changelog

🆑 Melbert
fix: Fixed an exploit involving igniters attached to themselves.
Assembly holders are now limited to 12 assemblies maximum, and you
cannot attach multiple igniters to the same assembly.
refactor: Refactored some assembly jank, namely in how they pulse and
are pulsed.
/🆑
This commit is contained in:
MrMelbert
2022-11-22 16:31:51 -08:00
committed by GitHub
parent 021a3bb9cf
commit aa95daa4e8
14 changed files with 89 additions and 95 deletions
+40 -35
View File
@@ -1,9 +1,3 @@
#define WIRE_RECEIVE (1<<0)
#define WIRE_PULSE (1<<1)
#define WIRE_PULSE_SPECIAL (1<<2)
#define WIRE_RADIO_RECEIVE (1<<3)
#define WIRE_RADIO_PULSE (1<<4)
#define ASSEMBLY_BEEP_VOLUME 5
/obj/item/assembly
name = "assembly"
@@ -24,10 +18,11 @@
* This will prevent things such as visible lasers from facing the incorrect direction when transformed by assembly_holder's update_appearance()
*/
var/is_position_sensitive = FALSE
/// Flags related to this assembly. See [assemblies.dm]
var/assembly_flags = NONE
var/secured = TRUE
var/list/attached_overlays = null
var/obj/item/assembly_holder/holder = null
var/wire_type = WIRE_RECEIVE | WIRE_PULSE
var/attachable = FALSE // can this be attached to wires
var/datum/wires/connected = null
var/next_activate = 0 //When we're next allowed to activate - for spam control
@@ -75,24 +70,26 @@
return FALSE
return TRUE
///Called when another assembly acts on this one, var/radio will determine where it came from for wire calcs
/obj/item/assembly/proc/pulsed(radio = FALSE, mob/pulser)
if(wire_type & WIRE_RECEIVE)
INVOKE_ASYNC(src, PROC_REF(activate), pulser)
if(radio && (wire_type & WIRE_RADIO_RECEIVE))
INVOKE_ASYNC(src, PROC_REF(activate), pulser)
/**
* Pulsed: This device was pulsed by another device
*
* * pulser: Who triggered the pulse
*/
/obj/item/assembly/proc/pulsed(mob/pulser)
INVOKE_ASYNC(src, PROC_REF(activate), pulser)
SEND_SIGNAL(src, COMSIG_ASSEMBLY_PULSED)
return TRUE
///Called when this device attempts to act on another device, var/radio determines if it was sent via radio or direct
/obj/item/assembly/proc/pulse(radio = FALSE)
if(connected && wire_type)
/**
* Pulse: This device is emitting a pulse to act on another device
*/
/obj/item/assembly/proc/pulse()
// if we have connected wires and are a pulsing assembly, pulse it
if(connected)
connected.pulse_assembly(src)
return TRUE
if(holder && (wire_type & WIRE_PULSE))
holder.process_activation(src, 1, 0)
if(holder && (wire_type & WIRE_PULSE_SPECIAL))
holder.process_activation(src, 0, 1)
// otherwise if we're attached to a holder, process the activation of it with our flags
else if(holder)
holder.process_activation(src)
return TRUE
/// What the device does when turned on
@@ -116,21 +113,29 @@
return
. = ..()
/obj/item/assembly/attackby(obj/item/W, mob/user, params)
if(isassembly(W))
var/obj/item/assembly/A = W
if((!A.secured) && (!secured))
holder = new/obj/item/assembly_holder(get_turf(src))
holder.assemble(src,A,user)
to_chat(user, span_notice("You attach and secure \the [A] to \the [src]!"))
else
to_chat(user, span_warning("Both devices must be in attachable mode to be attached together."))
/obj/item/assembly/attackby(obj/item/attacking_item, mob/user, params)
if(isassembly(attacking_item))
var/obj/item/assembly/new_assembly = attacking_item
// Check both our's and their's assembly flags to see if either should not duplicate
// If so, and we match types, don't create a holder - block it
if(((new_assembly.assembly_flags|assembly_flags) & ASSEMBLY_NO_DUPLICATES) && istype(new_assembly, type))
balloon_alert(user, "can't attach another of that!")
return
if(new_assembly.secured || secured)
balloon_alert(user, "both devices not attachable!")
return
holder = new /obj/item/assembly_holder(drop_location())
holder.assemble(src, new_assembly, user)
holder.balloon_alert(user, "parts combined")
return
if(istype(W, /obj/item/assembly_holder))
if(!secured)
var/obj/item/assembly_holder/added_to_holder = W
added_to_holder.add_assembly(src, user)
..()
if(istype(attacking_item, /obj/item/assembly_holder))
var/obj/item/assembly_holder/added_to_holder = attacking_item
added_to_holder.try_add_assembly(src, user)
return
return ..()
/obj/item/assembly/screwdriver_act(mob/living/user, obj/item/I)
if(..())
+24 -9
View File
@@ -46,6 +46,24 @@
for(var/obj/item/assembly/assembly in assemblies)
assembly.on_attach()
/obj/item/assembly_holder/proc/try_add_assembly(obj/item/assembly/attached_assembly, mob/user)
if(attached_assembly.secured)
balloon_alert(attached_assembly, "not attachable!")
return FALSE
if(LAZYLEN(assemblies) >= HOLDER_MAX_ASSEMBLIES)
balloon_alert(user, "too many assemblies!")
return FALSE
if(attached_assembly.assembly_flags & ASSEMBLY_NO_DUPLICATES)
if(locate(attached_assembly.type) in assemblies)
balloon_alert(user, "can't attach another of that!")
return FALSE
add_assembly(attached_assembly, user)
balloon_alert(user, "part attached")
return TRUE
/**
* Adds an assembly to the assembly holder
*
@@ -118,12 +136,11 @@
/obj/item/assembly_holder/attackby(obj/item/weapon, mob/user, params)
if(isassembly(weapon))
var/obj/item/assembly/attached_assembly = weapon
if(!attached_assembly.secured)
add_assembly(attached_assembly, user)
balloon_alert(user, "part added")
try_add_assembly(weapon, user)
return
return ..()
/obj/item/assembly_holder/AltClick(mob/user)
return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation
@@ -153,16 +170,14 @@
* send a pulse to the assembly holder, which then calls this proc that actually activates the assemblies
* Arguments:
* * /obj/device - the device we sent the pulse from which called this proc
* * normal - if this is a normal activation
* * special - if this is a special activation
*/
/obj/item/assembly_holder/proc/process_activation(obj/device, normal = TRUE, special = TRUE)
/obj/item/assembly_holder/proc/process_activation(obj/device)
if(!device)
return FALSE
if(normal && LAZYLEN(assemblies) >= 2)
if(LAZYLEN(assemblies) >= 2)
for(var/obj/item/assembly/assembly as anything in assemblies)
if(assembly != device)
assembly.pulsed(FALSE)
assembly.pulsed()
if(master)
master.receive_signal()
return TRUE
+1 -7
View File
@@ -12,6 +12,7 @@
heat = 1000
drop_sound = 'sound/items/handling/component_drop.ogg'
pickup_sound = 'sound/items/handling/component_pickup.ogg'
assembly_flags = ASSEMBLY_NO_DUPLICATES
/obj/item/assembly/igniter/suicide_act(mob/living/carbon/user)
user.visible_message(span_suicide("[user] is trying to ignite [user.p_them()]self with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
@@ -43,13 +44,6 @@
sparks.start()
return TRUE
/obj/item/assembly/igniter/attackby(obj/item/potential_igniter, mob/user, params)
if(isigniter(potential_igniter))
to_chat(user, "You briefly consider attaching [potential_igniter] to [src], and then conclude that's a very silly thing to do and move on.")
return
return ..()
/obj/item/assembly/igniter/attack_self(mob/user)
activate()
add_fingerprint(user)
+1 -1
View File
@@ -149,7 +149,7 @@
switchListener(location)
if(!secured || !on || next_activate > world.time)
return FALSE
pulse(FALSE)
pulse()
audible_message("<span class='infoplain'>[icon2html(src, hearers(src))] *beep* *beep* *beep*</span>", null, hearing_range)
for(var/mob/hearing_mob in get_hearers_in_view(hearing_range, src))
hearing_mob.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
+3 -3
View File
@@ -87,7 +87,7 @@
var/mob/living/carbon/human/user = usr
if((HAS_TRAIT(user, TRAIT_DUMB) || HAS_TRAIT(user, TRAIT_CLUMSY)) && prob(50))
to_chat(user, span_warning("Your hand slips, setting off the trigger!"))
pulse(FALSE)
pulse()
update_appearance()
playsound(src, 'sound/weapons/handcuffs.ogg', 30, TRUE, -3)
@@ -117,7 +117,7 @@
var/mob/living/carbon/human/victim = target
if(HAS_TRAIT(victim, TRAIT_PIERCEIMMUNE))
playsound(src, 'sound/effects/snap.ogg', 50, TRUE)
pulse(FALSE)
pulse()
return FALSE
switch(type)
if("feet")
@@ -148,7 +148,7 @@
visible_message(span_boldannounce("Skreeeee!")) //He's simply too large to be affected by a tiny mouse trap.
playsound(src, 'sound/effects/snap.ogg', 50, TRUE)
pulse(FALSE)
pulse()
/**
* clumsy_check: Sets off the mousetrap if handled by a clown (with some probability)
+1 -1
View File
@@ -90,7 +90,7 @@
/obj/item/assembly/prox_sensor/proc/sense()
if(!scanning || !secured || next_activate > world.time)
return FALSE
pulse(FALSE)
pulse()
audible_message("<span class='infoplain'>[icon2html(src, hearers(src))] *beep* *beep* *beep*</span>", null, hearing_range)
for(var/mob/hearing_mob in get_hearers_in_view(hearing_range, src))
hearing_mob.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
+1 -33
View File
@@ -6,7 +6,6 @@
lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi'
custom_materials = list(/datum/material/iron=400, /datum/material/glass=120)
wires = WIRE_RECEIVE | WIRE_PULSE | WIRE_RADIO_PULSE | WIRE_RADIO_RECEIVE
attachable = TRUE
drop_sound = 'sound/items/handling/component_drop.ogg'
pickup_sound = 'sound/items/handling/component_pickup.ogg'
@@ -156,8 +155,6 @@
return
if(signal.data["code"] != code)
return
if(!(src.wires & WIRE_RADIO_RECEIVE))
return
if(suicider)
manual_suicide(suicider)
return
@@ -165,7 +162,7 @@
// If the holder is a TTV, we want to store the last received signal to incorporate it into TTV logging, else wipe it.
last_receive_signal_log = istype(holder, /obj/item/transfer_valve) ? signal.logging_data : null
pulse(TRUE)
pulse()
audible_message("<span class='infoplain'>[icon2html(src, hearers(src))] *beep* *beep* *beep*</span>", null, hearing_range)
for(var/mob/hearing_mob in get_hearers_in_view(hearing_range, src))
hearing_mob.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
@@ -177,34 +174,6 @@
radio_connection = SSradio.add_object(src, frequency, RADIO_SIGNALER)
return
// Embedded signaller used in grenade construction.
// It's necessary because the signaler doens't have an off state.
// Generated during grenade construction. -Sayu
/obj/item/assembly/signaler/receiver
var/on = FALSE
/obj/item/assembly/signaler/receiver/proc/toggle_safety()
on = !on
/obj/item/assembly/signaler/receiver/activate()
toggle_safety()
return TRUE
/obj/item/assembly/signaler/receiver/examine(mob/user)
. = ..()
. += span_notice("The radio receiver is [on?"on":"off"].")
/obj/item/assembly/signaler/receiver/receive_signal(datum/signal/signal)
if(!on)
return
return ..(signal)
/obj/item/assembly/signaler/anomaly/attack_self()
return
/obj/item/assembly/signaler/crystal_anomaly/attack_self()
return
/obj/item/assembly/signaler/cyborg
/obj/item/assembly/signaler/cyborg/attackby(obj/item/W, mob/user, params)
@@ -228,4 +197,3 @@
if(ispAI(user))
return TRUE
. = ..()
+1 -1
View File
@@ -55,7 +55,7 @@
/obj/item/assembly/timer/proc/timer_end()
if(secured && next_activate <= world.time)
pulse(FALSE)
pulse()
audible_message(span_infoplain("[icon2html(src, hearers(src))] *beep* *beep* *beep*"), null, hearing_range)
for(var/mob/hearing_mob in get_hearers_in_view(hearing_range, src))
hearing_mob.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)