Files
Aurora.3/code/game/objects/items/devices/magnetic_lock.dm
T
BatrachophrenoandGitHub 4ecb0bc21c Repath obj/machinery to obj/structure/machinery [MDB Ignore] (#22500)
Repaths obj/machinery to obj/structure/machinery. **Note for
reviewers:** the only meaningful changed code exists within
**code/game/objects/structures.dm** and
**code/game/objects/structures/_machinery.dm**, largely concerning
damage procs. With the exception of moving airlock defines to their own
file, ALL OTHER CHANGES ARE STRICTLY PATH CHANGES.

Objects, _categorically_, are largely divided between those you can hold
in your hand/inventory and those you can't. Machinery objects are
already subtypes of Structures behaviorally, this PR just makes their
pathing reflect that, and allows for future work (tool actions, more
health/destruction functionality) to be developed without unnecessary
code duplication.

I have tested this PR by loading up the Horizon and dismantling various
machines and structures with tools, shooting guns of various types
throughout the ship, and detonating a bunch of explosions throughout the
ship.
2026-05-26 19:35:48 +00:00

531 lines
17 KiB
Plaintext

#define STATUS_INACTIVE 0
#define STATUS_ACTIVE 1
#define STATUS_BROKEN -1
#define LAYER_NORMAL 3
/obj/item/magnetic_lock
name = "magnetic door lock"
desc = "A large, ID locked device used for completely locking down airlocks."
icon = 'icons/obj/magnetic_locks.dmi'
icon_state = "inactive_CENTCOM"
//icon_state = "inactive"
w_class = WEIGHT_CLASS_NORMAL
req_access = list(ACCESS_CENT_SPECOPS)
health = 150
var/department = "CENTCOM"
var/status = 0
var/locked = 1
var/hacked = 0
var/invincible = FALSE
var/processpower = TRUE
var/constructionstate = 0
var/drain_per_second = 3
var/last_process_time = 0
var/obj/structure/machinery/door/airlock/target_node1 = null
var/obj/structure/machinery/door/airlock/target_node2 = null
var/obj/structure/machinery/door/airlock/target = null
var/obj/item/cell/powercell
/obj/item/magnetic_lock/condition_hints(mob/user, distance, is_adjacent)
. += ..()
if (status == STATUS_BROKEN)
. += SPAN_DANGER("It looks broken!")
/obj/item/magnetic_lock/feedback_hints(mob/user, distance, is_adjacent)
. += ..()
if (powercell)
var/power = round(powercell.charge / powercell.maxcharge * 100)
. += SPAN_NOTICE("The powercell is at <b>[power]%</b> charge.")
else
. += SPAN_WARNING("It has no powercell to power it!")
/obj/item/magnetic_lock/mechanics_hints(mob/user, distance, is_adjacent)
. += ..()
if(department)
. += "Once applied to an airlock, this device can be activated/deactivated by swiping an ID from the <b>[department] department</b> across it."
/obj/item/magnetic_lock/security
department = "Security"
icon_state = "inactive_Security"
req_access = list(ACCESS_SECURITY)
/obj/item/magnetic_lock/engineering
department = "Engineering"
icon_state = "inactive_Engineering"
req_access = null
req_one_access = list(ACCESS_ENGINE_EQUIP, ACCESS_ATMOSPHERICS)
/obj/item/magnetic_lock/security/legion
name = "legion magnetic door lock"
req_access = null
req_one_access = list(ACCESS_LEGION, ACCESS_TCAF_SHIPS)
w_class = WEIGHT_CLASS_SMALL
/obj/item/magnetic_lock/security/legion/Initialize()
. = ..()
desc = "A large, ID locked device used for completely locking down airlocks. This one carries the insignia of the Tau Ceti Foreign Legion."
/obj/item/magnetic_lock/Initialize()
. = ..()
powercell = new /obj/item/cell/high()
if (istext(department))
desc += " It is painted with [department] colors."
update_icon()
var/obj/structure/machinery/door/airlock/newtarget = (locate(/obj/structure/machinery/door/airlock) in get_turf(src))
if(newtarget)
var/direction = REVERSE_DIR(dir)
forceMove(get_step(newtarget.loc, REVERSE_DIR(direction)))
for (var/obj/structure/machinery/door/airlock/A in oview(1, newtarget))
var/rdir = get_dir(newtarget, A)
if (istype(A, newtarget.type) && (rdir == turn(direction, -90) || rdir == turn(direction, 90)))
if(!target_node1)
target_node1 = A
target_node1.bracer = src
else
target_node2 = A
target_node2.bracer = src
status = STATUS_ACTIVE
attach(newtarget)
/obj/item/magnetic_lock/attack_hand(var/mob/user)
add_fingerprint(user)
if (constructionstate == 1 && powercell)
powercell.update_icon()
powercell.add_fingerprint(user)
user.put_in_active_hand(powercell)
to_chat(user, "You remove \the [powercell].")
powercell = null
setconstructionstate(2)
return TRUE
else if (anchored)
if (!locked)
detach()
return TRUE
else
to_chat(user, SPAN_WARNING("\The [src] is locked in place!"))
else
..()
/obj/item/magnetic_lock/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
. = ..()
if(. != BULLET_ACT_HIT)
return .
takedamage(hitting_projectile.damage)
/obj/item/magnetic_lock/attackby(obj/item/attacking_item, mob/user)
if (status == STATUS_BROKEN)
to_chat(user, SPAN_DANGER("[src] is broken beyond repair!"))
return TRUE
if (istype(attacking_item, /obj/item/card/id))
if (!constructionstate && !hacked)
if (check_access(attacking_item))
locked = !locked
playsound(src, 'sound/machines/ping.ogg', 30, 1)
var/msg = "[attacking_item] through \the [src] and it [locked ? "locks" : "unlocks"] with a beep."
var/pos_adj = "[user.name] swipes [user.get_pronoun("his")] "
var/fp_adj = "You swipe your "
user.visible_message(SPAN_WARNING("[addtext(pos_adj, msg)]"), SPAN_NOTICE("[addtext(fp_adj, msg)]"))
update_icon()
else
playsound(src, 'sound/machines/buzz-sigh.ogg', 30, 1)
to_chat(user, SPAN_WARNING("\The [src] buzzes as you swipe your [attacking_item]."))
return
else
to_chat(user, SPAN_DANGER("You cannot swipe your [attacking_item] through [src] with it partially dismantled!"))
return TRUE
if (istype(attacking_item, /obj/item) && user.a_intent == "harm")
if (attacking_item.force >= 18)
user.visible_message(SPAN_DANGER("[user] bashes [src] with [attacking_item]!"),
SPAN_DANGER("You strike [src] with [attacking_item], damaging it!"))
takedamage(attacking_item.force)
var/sound_to_play = pick(list('sound/weapons/genhit1.ogg', 'sound/weapons/genhit2.ogg', 'sound/weapons/genhit3.ogg'))
playsound(loc, sound_to_play, attacking_item.force*3, 1)
sound_to_play = pick(list('sound/effects/sparks1.ogg', 'sound/effects/sparks2.ogg', 'sound/effects/sparks3.ogg', 'sound/effects/sparks4.ogg'))
addtimer(CALLBACK(GLOBAL_PROC, /proc/playsound, loc, sound_to_play, 30, 1), 3, TIMER_CLIENT_TIME)
else
user.visible_message(SPAN_DANGER("[user] hits [src] with [attacking_item] but fails to damage it."), SPAN_WARNING("You hit [src] with [attacking_item], [attacking_item.force >= 10 ? "and it almost makes a dent!" : "but it appears to have no visible effect."]"))
playsound(loc, 'sound/weapons/Genhit.ogg', attacking_item.force*2.5, 1)
return TRUE
if(invincible)
return TRUE
switch (constructionstate)
if (0)
if (istype(attacking_item, /obj/item/card/emag))
var/obj/item/card/emag/emagcard = attacking_item
emagcard.uses--
visible_message(SPAN_DANGER("[src] sparks and falls off the door!"),
SPAN_DANGER("You emag [src], frying its circuitry[status == STATUS_ACTIVE ? " and making it drop onto the floor" : ""]!"))
status = STATUS_BROKEN
if (target)
detach()
update_icon()
return TRUE
if (attacking_item.tool_behaviour == TOOL_WELDER)
var/obj/item/weldingtool/WT = attacking_item
if (WT.use(2, user))
user.visible_message(SPAN_NOTICE("[user] starts welding the metal shell of [src]."), SPAN_NOTICE("You start [hacked ? "repairing" : "welding open"] the metal covering of [src]."))
playsound(loc, 'sound/items/Welder.ogg', 50, 1)
AddOverlays("overlay_welding")
if(WT.use_tool(src, user, 25, volume = 50))
to_chat(user, SPAN_NOTICE("You are able to [hacked ? "repair" : "weld through"] the metal shell of [src]."))
if (hacked) locked = 1
else locked = 0
hacked = !hacked
CutOverlays("overlay_welding")
else
CutOverlays("overlay_welding")
update_icon()
return TRUE
if (attacking_item.tool_behaviour == TOOL_CROWBAR)
if (!locked)
to_chat(user, SPAN_NOTICE("You pry the cover off [src]."))
setconstructionstate(1)
else
to_chat(user, SPAN_NOTICE("You try to pry the cover off [src] but it doesn't budge."))
return TRUE
if (1)
if (istype(attacking_item, /obj/item/cell))
if (powercell)
to_chat(user, SPAN_NOTICE("There's already a powercell in \the [src]."))
return TRUE
if (attacking_item.tool_behaviour == TOOL_CROWBAR)
to_chat(user, SPAN_NOTICE("You wedge the cover back in place."))
setconstructionstate(0)
return TRUE
if (2)
if (attacking_item.tool_behaviour == TOOL_SCREWDRIVER)
to_chat(user, SPAN_NOTICE("You unscrew and remove the wiring cover from \the [src]."))
attacking_item.play_tool_sound(get_turf(src), 50)
setconstructionstate(3)
return TRUE
if (attacking_item.tool_behaviour == TOOL_CROWBAR)
to_chat(user, SPAN_NOTICE("You wedge the cover back in place."))
setconstructionstate(0)
return TRUE
if (istype(attacking_item, /obj/item/cell))
if (!powercell)
to_chat(user, SPAN_NOTICE("You place the [attacking_item] inside \the [src]."))
user.drop_from_inventory(attacking_item,src)
powercell = attacking_item
setconstructionstate(1)
return TRUE
if (3)
if (attacking_item.tool_behaviour == TOOL_WIRECUTTER)
to_chat(user, SPAN_NOTICE("You cut the wires connecting the [src]'s magnets to their internal powersupply, [target ? "making the device fall off [target] and rendering it unusable." : "rendering the device unusable."]"))
playsound(loc, 'sound/items/Wirecutter.ogg', 50, 1)
setconstructionstate(4)
return TRUE
if (attacking_item.tool_behaviour == TOOL_SCREWDRIVER)
to_chat(user, SPAN_NOTICE("You replace and screw tight the wiring cover from \the [src]."))
attacking_item.play_tool_sound(get_turf(src), 50)
setconstructionstate(2)
return TRUE
if (4)
if (attacking_item.tool_behaviour == TOOL_WIRECUTTER)
to_chat(user, SPAN_NOTICE("You repair the wires connecting the [src]'s magnets to their internal powersupply"))
setconstructionstate(3)
return TRUE
/obj/item/magnetic_lock/process()
if(!processpower)
return
var/obj/item/cell/C = powercell
var/delta_sec = (world.time - last_process_time) / 10
var/drainamount = drain_per_second * delta_sec
if (C)
if (C.charge > drainamount)
C.charge -= drainamount
else
C.charge = 0
visible_message(SPAN_DANGER("[src] beeps loudly and falls off \the [target]; its powercell having run out of power."))
detach(0)
if (!C)
visible_message(SPAN_DANGER("[src] gives two shrill beeps and falls off \the [target]. No cell appears to be installed."))
detach(0)
last_process_time = world.time
/obj/item/magnetic_lock/proc/check_target(var/obj/structure/machinery/door/airlock/newtarget, var/mob/user as mob)
if (status == STATUS_BROKEN)
to_chat(user, SPAN_DANGER("[src] is damaged beyond repair! It cannot be used!"))
return 0
if (hacked)
to_chat(user, SPAN_DANGER("[src] buzzes; it can't be used until you repair it!"))
return 0
if (!newtarget.density || newtarget.operating)
to_chat(user, SPAN_DANGER("[newtarget] must be closed before you can attach [src] to it!"))
return 0
if (newtarget.p_open)
to_chat(user, SPAN_DANGER("You must close [newtarget]'s maintenance panel before attaching [src] to it!"))
return 0
if (!user.Adjacent(newtarget))
to_chat(user, SPAN_DANGER("You must stand next to [newtarget] while attaching it!"))
return 0
return 1
/obj/item/magnetic_lock/proc/attachto(var/obj/structure/machinery/door/airlock/newtarget, var/mob/user as mob)
if (!check_target(newtarget, user)) return
user.visible_message(SPAN_NOTICE("[user] starts mounting [src] onto [newtarget]."),
SPAN_NOTICE("You begin mounting [src] onto [newtarget]."))
if (do_after(user, 3.5 SECONDS))
if (!check_target(newtarget, user)) return
if(powercell)
if(!powercell.charge)
to_chat(user, SPAN_WARNING("\The [src] is clearly out of power."))
return
var/direction = get_dir(user, newtarget)
if ((direction in GLOB.alldirs) && !(direction in GLOB.cardinals))
direction = turn(direction, -45)
if (check_neighbor_density(get_turf(newtarget.loc), direction))
direction = turn(direction, 90)
if (check_neighbor_density(get_turf(newtarget.loc), direction))
to_chat(user, SPAN_WARNING("There is something in the way of \the [newtarget]!"))
return
if (locate(/obj/structure/machinery/door/airlock) in oview(1, newtarget))
if (alert("Brace adjacent airlocks?",,"Yes", "No") == "Yes")
if (!check_target(newtarget, user)) return
for (var/obj/structure/machinery/door/airlock/A in get_step(newtarget.loc, turn(direction, -90)))
if (istype(A, newtarget.type))
if (!check_target(A, user)) return
target_node1 = A
target_node1.bracer = src
break
for (var/obj/structure/machinery/door/airlock/B in get_step(newtarget.loc, turn(direction, 90)))
if (istype(B, newtarget.type))
if (!check_target(B, user)) return
target_node2 = B
target_node2.bracer = src
break
user.drop_from_inventory(src, src.loc)
forceMove(get_step(newtarget.loc, REVERSE_DIR(direction)))
set_dir(REVERSE_DIR(direction))
status = STATUS_ACTIVE
attach(newtarget)
user.visible_message(SPAN_NOTICE("[user] attached [src] onto [newtarget] and flicks it on. The magnetic lock now seals [newtarget]."),
SPAN_NOTICE("You attached [src] onto [newtarget] and switched on the magnetic lock."))
return
/obj/item/magnetic_lock/proc/setconstructionstate(var/newstate)
if (!powercell && newstate == 1)
setconstructionstate(2)
return
else if (newstate == 4)
detach(playflick = 0)
update_icon()
constructionstate = newstate
update_icon()
/obj/item/magnetic_lock/proc/detach(var/playflick = 1)
if (target)
if (playflick)
spawn(-15) flick("release_[department]", src)
status = STATUS_INACTIVE
set_dir(SOUTH)
update_icon()
layer = LAYER_NORMAL
target.bracer = null
target = null
if (target_node1)
target_node1.bracer = null
target_node1 = null
if (target_node2)
target_node2.bracer = null
target_node2 = null
anchored = 0
STOP_PROCESSING(SSprocessing, src)
last_process_time = 0
/obj/item/magnetic_lock/proc/attach(var/obj/structure/machinery/door/airlock/newtarget as obj)
layer = ABOVE_DOOR_LAYER
newtarget.bracer = src
target = newtarget
last_process_time = world.time
START_PROCESSING(SSprocessing, src)
anchored = 1
spawn(-15)
flick("deploy_[department]", src)
update_icon()
/obj/item/magnetic_lock/update_icon()
if (status == STATUS_ACTIVE && target)
icon_state = "active_[department]"
switch (dir)
if (NORTH)
pixel_x = 0
pixel_y = -32
if (EAST)
pixel_x = -32
pixel_y = 0
if (SOUTH)
pixel_x = 0
pixel_y = 32
if (WEST)
pixel_x = 32
pixel_y = 0
else if (status >= STATUS_INACTIVE)
icon_state = "inactive_[department]"
pixel_x = 0
pixel_y = 0
else
icon_state = "broken_[department]"
pixel_x = 0
pixel_y = 0
update_overlays()
/obj/item/magnetic_lock/proc/update_overlays()
ClearOverlays()
switch (status)
if (STATUS_BROKEN)
icon_state = "broken"
return
if (STATUS_INACTIVE to STATUS_ACTIVE)
if (hacked)
AddOverlays("overlay_hacked")
else if (locked)
AddOverlays("overlay_locked")
else
AddOverlays("overlay_unlocked")
switch (constructionstate)
if (0)
return
if (1 to 4)
AddOverlays("overlay_deconstruct_[constructionstate]")
/obj/item/magnetic_lock/proc/takedamage(var/damage)
if(invincible)
return
health -= rand(damage/2, damage)
if (damage >= 40 && prob(50))
health = 0
if (health <= 0)
visible_message(SPAN_DANGER("[src] sparks[target ? " and falls off of \the [target]!" : "!"] It is now completely unusable!"))
detach(0)
status = STATUS_BROKEN
update_icon()
return
if (prob(50))
spark(target ? target : src, 5, GLOB.alldirs)
/obj/item/magnetic_lock/keypad
name = "magnetic door lock"
desc = "A large, passcode locked device used for completely locking down airlocks."
req_access = list(ACCESS_NONE)
var/passcode = "open"
var/configurable = TRUE
/obj/item/magnetic_lock/keypad/mechanics_hints(mob/user, distance, is_adjacent)
. += ..()
. += "Keypad-enabled magnetic locks require a custom passcode to unlock them, configured on initial use."
/obj/item/magnetic_lock/keypad/update_overlays()
..()
switch (status)
if (STATUS_INACTIVE to STATUS_ACTIVE)
if(istype(src, /obj/item/magnetic_lock/keypad))
AddOverlays("overlay_keypad")
/obj/item/magnetic_lock/keypad/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "Maglock", "Maglock", 300, 250)
ui.open()
/obj/item/magnetic_lock/keypad/attack_hand(var/mob/user)
. = ..()
if(.)
return
ui_interact(user)
/obj/item/magnetic_lock/keypad/ui_data(mob/user)
var/list/data = list()
data["locked"] = locked
return data
/obj/item/magnetic_lock/keypad/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
switch(action)
if("passcode")
if(lowertext(params["passcode"]) == passcode)
locked = !locked
playsound(src, 'sound/machines/ping.ogg', 30, 1)
var/msg = "buttons on \the [src] and it [locked ? "locks" : "unlocks"] with a beep."
var/pos_adj = "[usr.name] presses "
var/fp_adj = "You press "
usr.visible_message(SPAN_WARNING("[addtext(pos_adj, msg)]"), SPAN_NOTICE("[addtext(fp_adj, msg)]"))
update_icon()
. = TRUE
else
playsound(src, 'sound/machines/buzz-sigh.ogg', 30, 1)
to_chat(usr, SPAN_WARNING("\The [src] buzzes!"))
return
if("set_passcode")
if(!locked)
passcode = lowertext(params["set_passcode"])
to_chat(usr, SPAN_NOTICE("New passcode has been set."))
. = TRUE
if("lock")
if(!locked)
locked = !locked
playsound(src, 'sound/machines/ping.ogg', 30, 1)
to_chat(usr, SPAN_NOTICE("You have locked \the [src]."))
update_icon()
. = TRUE
#undef STATUS_INACTIVE
#undef STATUS_ACTIVE
#undef STATUS_BROKEN
#undef LAYER_NORMAL