mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-10 17:52:36 +00:00
## About The Pull Request
This PR adds several circuit features, and changes several
assembly-related features to make them a bit more logical in how they
work. Included are the following changes/additions:
- Assemblies and wires have been refactored with vars that describe
their behavior:
- Assemblies have an `assembly_behavior` bitflag instead of a
`attachable` var. This var has 3 flags:
- `ASSEMBLY_INPUT`: The assembly is able to pulse the wire it is
attached to.
- `ASSEMBLY_TOGGLE_ARMED`: On activation, the assembly toggles whether
it can pulse the wire it is attached to.
- `ASSEMBLY_FUNCTIONAL_OUTPUT`: On activation, the assembly does
something other than just toggling whether it's armed.
- Wires have a `wires_behavior` bitflag with 3 flags:
- `WIRES_INPUT`: The object the wires are attached to does something
when the wires are pulsed.
- `WIRES_TOGGLE_ARMED`: The object the wires are attached to can
activate assemblies attached to those wires, and is fine if all that
activating that assembly does is toggle whether it's armed.
- `WIRES_FUNCTIONAL_OUTPUT`: The object the wires are attached to
expects that assemblies attached to its wires do something other than
toggling themselves when activated.
- Buttons can only accept assemblies with `ASSEMBLY_FUNCTIONAL_OUTPUT`.
- Pressure plates can now accept any assembly with
`ASSEMBLY_FUNCTIONAL_OUTPUT`, not just signalers. Assembly shells
attached to pressure plates will draw power from the powernet if the
pressure plate is under a tile.
- Adds a new circuit component - the wire bundle.
- This component gives the circuit a number of wires corresponding to
the size of the shell.
- Each wire has a corresponding port on the component that can pulse,
and receive pulses from, that wire.
- A circuit can only have one wire bundle component.
- Assembly shells cannot be attached to these wires, and no wires will
be created if the component is added to an assembly shell.
- Available with roundstart tech.
- Adds two new shells.
- The wallmounted shell is a large shell that can be hung on walls, and
uses power from the area it's placed in.
- Frame icon:

- Constructed icon:

- The undertile shell is a small shell that only works when fit under a
floor tile, but uses power from the area it's placed in.

- Both shells support usb cables.
- The above shells are available with the Advanced Shells techweb node.
## Why It's Good For The Game
The wire bundle component complements the functionality of the assembly
shell by allowing circuits to use assemblies directly in their logic.
The wallmounted and undertile shells provide ways of placing circuits
that don't necessarily take up space for machines. The undertile shell
is particularly useful for relaying usb component data over wirenets.
Pressure plates being able to accept assemblies other than signalers
expands their uses significantly.
## Changelog
🆑
refactor: Wires and assemblies have been refactored to have
directionality to them. This mostly makes it so that assemblies can only
be attached to wires it would make sense for them to be attached to.
qol: Pressure plates can now also accept igniters, condensers, flashes,
assembly shells, and door controllers.
add: Undertile circuit shells. They only work when placed under floor
tiles, but support USB cables and use APC power instead of cell power.
add: Wallmounted circuit shells. Large shells that support USB cables
and use APC power instead of cell power.
add: Wire bundle component. Adds a number of wires to the circuit
proportional to the capacity of the shell, allowing you to use
assemblies in circuit logic.
/🆑
236 lines
7.8 KiB
Plaintext
236 lines
7.8 KiB
Plaintext
/obj/item/assembly/mousetrap
|
|
name = "mousetrap"
|
|
desc = "A handy little spring-loaded trap for catching pesty rodents."
|
|
icon_state = "mousetrap"
|
|
inhand_icon_state = "mousetrap"
|
|
custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT)
|
|
assembly_behavior = ASSEMBLY_TOGGLEABLE_INPUT
|
|
var/armed = FALSE
|
|
drop_sound = 'sound/items/handling/component_drop.ogg'
|
|
pickup_sound = 'sound/items/handling/component_pickup.ogg'
|
|
var/obj/item/host = null
|
|
var/turf/host_turf = null
|
|
|
|
/**
|
|
* update_host: automatically setup host and host_turf
|
|
*
|
|
* Arguments:
|
|
* * force: Re-register signals even if the host or loc is unchanged
|
|
*/
|
|
/obj/item/assembly/mousetrap/proc/update_host(force = FALSE)
|
|
var/obj/item/newhost
|
|
// Pick the first valid object in this list:
|
|
// Wiring datum's owner
|
|
// assembly holder's attached object
|
|
// assembly holder itself
|
|
// us
|
|
newhost = connected?.holder || holder?.master || holder || src
|
|
|
|
// ok look
|
|
// previously this wasn't working and thus no concern, but I made mousetraps work with wires
|
|
// specifically in step-on-the-mousetrap mode, ie, when you enter its turf
|
|
// and as a consequence, you can put a mousetrap in door wires and it will be set off
|
|
// the first time someone walks through a door (enters the door's loc)
|
|
// that's an interesting mechanic (bolt open a door for example) but it's not appropriate for a mousetrap
|
|
// similarly if used on say an apc's wires it would go into effect when someone walked by it. Not appropriate.
|
|
// other assemblies could be made to do something similar instead.
|
|
// mousetrap assemblies will still receive on-found notifications when you open a wiring panel
|
|
// and (whether reasonable or not) mousetraps that do this do still trigger wires
|
|
// the point is for now step-on-mousetrap mode should only work on items
|
|
// maybe it should never have been an assembly in the first place.
|
|
|
|
// tl;dr only trigger step-on mode if the host is an item
|
|
if(!istype(newhost,/obj/item))
|
|
if(host)
|
|
UnregisterSignal(host,COMSIG_MOVABLE_MOVED)
|
|
host = src
|
|
if(isturf(host_turf))
|
|
UnregisterSignal(host_turf,COMSIG_ATOM_ENTERED)
|
|
host_turf = null
|
|
return
|
|
|
|
// If host changed
|
|
if((newhost != host) || force)
|
|
if(host)
|
|
UnregisterSignal(host,COMSIG_MOVABLE_MOVED)
|
|
host = newhost
|
|
RegisterSignal(host,COMSIG_MOVABLE_MOVED, PROC_REF(holder_movement))
|
|
|
|
// If host moved
|
|
if((host_turf != host.loc) || force)
|
|
if(isturf(host_turf))
|
|
UnregisterSignal(host_turf,COMSIG_ATOM_ENTERED)
|
|
host_turf = null
|
|
if(isturf(host.loc))
|
|
host_turf = host.loc
|
|
RegisterSignal(host_turf,COMSIG_ATOM_ENTERED, PROC_REF(on_entered))
|
|
else
|
|
host_turf = null
|
|
|
|
/obj/item/assembly/mousetrap/holder_movement()
|
|
. = ..()
|
|
update_host()
|
|
|
|
/obj/item/assembly/mousetrap/Initialize(mapload)
|
|
. = ..()
|
|
update_host(force = TRUE)
|
|
|
|
/obj/item/assembly/mousetrap/examine(mob/user)
|
|
. = ..()
|
|
. += span_notice("The pressure plate is [armed?"primed":"safe"].")
|
|
|
|
/obj/item/assembly/mousetrap/activate()
|
|
if(..())
|
|
armed = !armed
|
|
if(!armed)
|
|
if(ishuman(usr))
|
|
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()
|
|
update_appearance()
|
|
playsound(loc, 'sound/items/weapons/handcuffs.ogg', 30, TRUE, -3)
|
|
|
|
/obj/item/assembly/mousetrap/update_icon_state()
|
|
icon_state = "mousetrap[armed ? "armed" : ""]"
|
|
return ..()
|
|
|
|
/obj/item/assembly/mousetrap/update_icon(updates=ALL)
|
|
. = ..()
|
|
holder?.update_icon(updates)
|
|
|
|
/obj/item/assembly/mousetrap/on_attach()
|
|
. = ..()
|
|
update_host()
|
|
|
|
/obj/item/assembly/mousetrap/on_detach()
|
|
. = ..()
|
|
update_host()
|
|
|
|
/obj/item/assembly/mousetrap/proc/triggered(mob/target, type = "feet")
|
|
if(!armed)
|
|
return
|
|
armed = FALSE // moved to the top because you could trigger it more than once under some circumstances
|
|
update_appearance()
|
|
var/obj/item/bodypart/affecting = null
|
|
if(ishuman(target))
|
|
var/mob/living/carbon/human/victim = target
|
|
if(HAS_TRAIT(victim, TRAIT_PIERCEIMMUNE))
|
|
playsound(src, 'sound/effects/snap.ogg', 50, TRUE)
|
|
pulse()
|
|
return FALSE
|
|
switch(type)
|
|
if("feet")
|
|
if(!victim.shoes)
|
|
affecting = victim.get_bodypart(pick(GLOB.leg_zones))
|
|
victim.Paralyze(6 SECONDS)
|
|
else
|
|
to_chat(victim, span_notice("Your [victim.shoes.name] protects you from [src]."))
|
|
if(BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND)
|
|
if(!victim.gloves)
|
|
affecting = victim.get_bodypart(type)
|
|
victim.Stun(6 SECONDS)
|
|
else
|
|
to_chat(victim, span_notice("Your [victim.gloves.name] protects you from [src]."))
|
|
if(affecting)
|
|
victim.apply_damage(1, BRUTE, affecting, wound_bonus = CANT_WOUND)
|
|
else if(ismouse(target))
|
|
var/mob/living/basic/mouse/splatted = target
|
|
visible_message(span_bolddanger("SPLAT!"))
|
|
splatted.splat() // mousetraps are instadeath for mice
|
|
|
|
else if(isregalrat(target))
|
|
visible_message(span_bolddanger("Skreeeee!")) //He's simply too large to be affected by a tiny mouse trap.
|
|
|
|
playsound(src, 'sound/effects/snap.ogg', 50, TRUE)
|
|
pulse()
|
|
|
|
/**
|
|
* clumsy_check: Sets off the mousetrap if handled by a clown (with some probability)
|
|
*
|
|
* Arguments:
|
|
* * user: The mob handling the trap
|
|
*/
|
|
/obj/item/assembly/mousetrap/proc/clumsy_check(mob/living/carbon/human/user)
|
|
if(!armed || !user)
|
|
return FALSE
|
|
if((HAS_TRAIT(user, TRAIT_DUMB) || HAS_TRAIT(user, TRAIT_CLUMSY)) && prob(50))
|
|
var/which_hand = BODY_ZONE_PRECISE_L_HAND
|
|
if(IS_RIGHT_INDEX(user.active_hand_index))
|
|
which_hand = BODY_ZONE_PRECISE_R_HAND
|
|
triggered(user, which_hand)
|
|
user.visible_message(span_warning("[user] accidentally sets off [src], breaking their fingers."), \
|
|
span_warning("You accidentally trigger [src]!"))
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/obj/item/assembly/mousetrap/attack_self(mob/living/carbon/human/user)
|
|
if(!armed)
|
|
to_chat(user, span_notice("You arm [src]."))
|
|
else
|
|
if(clumsy_check(user))
|
|
return
|
|
to_chat(user, span_notice("You disarm [src]."))
|
|
armed = !armed
|
|
update_appearance()
|
|
playsound(src, 'sound/items/weapons/handcuffs.ogg', 30, TRUE, -3)
|
|
|
|
|
|
// Clumsy check only
|
|
/obj/item/assembly/mousetrap/attack_hand(mob/living/carbon/human/user, list/modifiers)
|
|
if(clumsy_check(user))
|
|
return
|
|
return ..()
|
|
|
|
|
|
/obj/item/assembly/mousetrap/proc/on_entered(datum/source, atom/movable/AM as mob|obj)
|
|
SIGNAL_HANDLER
|
|
if(armed)
|
|
if(ismob(AM))
|
|
var/mob/MM = AM
|
|
if(!(MM.movement_type & MOVETYPES_NOT_TOUCHING_GROUND))
|
|
if(ishuman(AM))
|
|
var/mob/living/carbon/H = AM
|
|
if(H.move_intent == MOVE_INTENT_RUN)
|
|
INVOKE_ASYNC(src, PROC_REF(triggered), H)
|
|
H.visible_message(span_warning("[H] accidentally steps on [src]."), \
|
|
span_warning("You accidentally step on [src]"))
|
|
else if(ismouse(MM) || isregalrat(MM))
|
|
INVOKE_ASYNC(src, PROC_REF(triggered), MM)
|
|
else if(AM.density) // For mousetrap grenades, set off by anything heavy
|
|
INVOKE_ASYNC(src, PROC_REF(triggered), AM)
|
|
|
|
/obj/item/assembly/mousetrap/on_found(mob/finder)
|
|
if(armed)
|
|
if(finder)
|
|
finder.visible_message(span_warning("[finder] accidentally sets off [src], breaking their fingers."), \
|
|
span_warning("You accidentally trigger [src]!"))
|
|
triggered(finder, (IS_RIGHT_INDEX(finder.active_hand_index)) ? BODY_ZONE_PRECISE_R_HAND : BODY_ZONE_PRECISE_L_HAND)
|
|
return TRUE //end the search!
|
|
else
|
|
visible_message(span_warning("[src] snaps shut!"))
|
|
triggered(loc)
|
|
return FALSE
|
|
return FALSE
|
|
|
|
|
|
/obj/item/assembly/mousetrap/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
|
|
if(!armed)
|
|
return ..()
|
|
visible_message(span_warning("[src] is triggered by [AM]."))
|
|
triggered(null)
|
|
|
|
|
|
/obj/item/assembly/mousetrap/Destroy()
|
|
if(host)
|
|
UnregisterSignal(host,COMSIG_MOVABLE_MOVED)
|
|
host = null
|
|
if(isturf(host_turf))
|
|
UnregisterSignal(host_turf,COMSIG_ATOM_ENTERED)
|
|
host_turf = null
|
|
return ..()
|
|
|
|
/obj/item/assembly/mousetrap/armed
|
|
icon_state = "mousetraparmed"
|
|
armed = TRUE
|