diff --git a/code/datums/components/storage/concrete/emergency.dm b/code/datums/components/storage/concrete/emergency.dm
index 48880ff605..348821a913 100644
--- a/code/datums/components/storage/concrete/emergency.dm
+++ b/code/datums/components/storage/concrete/emergency.dm
@@ -36,3 +36,4 @@
/datum/component/storage/concrete/emergency/proc/unlock_me(datum/source)
if(locked)
set_locked(source, FALSE)
+ return TRUE
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 88fe2c8d13..6665e4d59b 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -379,7 +379,7 @@
SEND_SIGNAL(src, COMSIG_ATOM_ACID_ACT, acidpwr, acid_volume)
/atom/proc/emag_act()
- SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT)
+ return SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT)
/atom/proc/rad_act(strength)
SEND_SIGNAL(src, COMSIG_ATOM_RAD_ACT, strength)
diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm
index aa363428fb..76ea855c77 100644
--- a/code/game/machinery/Sleeper.dm
+++ b/code/game/machinery/Sleeper.dm
@@ -193,8 +193,10 @@
to_chat(usr, "Chem System Re-route detected, results may not be as expected!")
/obj/machinery/sleeper/emag_act(mob/user)
+ . = ..()
scramble_chem_buttons()
to_chat(user, "You scramble the sleeper's user interface!")
+ return TRUE
/obj/machinery/sleeper/proc/inject_chem(chem, mob/user)
if((chem in available_chems) && chem_allowed(chem))
diff --git a/code/game/machinery/announcement_system.dm b/code/game/machinery/announcement_system.dm
index 884b818f32..56227cdd53 100644
--- a/code/game/machinery/announcement_system.dm
+++ b/code/game/machinery/announcement_system.dm
@@ -177,7 +177,9 @@ GLOBAL_LIST_EMPTY(announcement_systems)
act_up()
/obj/machinery/announcement_system/emag_act()
+ . = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
act_up()
+ return TRUE
diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm
index 879be046c9..968cbe7254 100644
--- a/code/game/machinery/buttons.dm
+++ b/code/game/machinery/buttons.dm
@@ -101,12 +101,14 @@
return ..()
/obj/machinery/button/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
req_access = list()
req_one_access = list()
playsound(src, "sparks", 100, 1)
obj_flags |= EMAGGED
+ return TRUE
/obj/machinery/button/attack_ai(mob/user)
if(!panel_open)
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index 4f04335852..a175558f74 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -320,10 +320,12 @@
return ..()
/obj/machinery/clonepod/emag_act(mob/user)
+ . = ..()
if(!occupant)
return
to_chat(user, "You corrupt the genetic compiler.")
malfunction()
+ return TRUE
//Put messages in the connected computer's temp var for display.
/obj/machinery/clonepod/proc/connected_message(message)
diff --git a/code/game/machinery/computer/apc_control.dm b/code/game/machinery/computer/apc_control.dm
index e51d623c2f..1c517d6e8f 100644
--- a/code/game/machinery/computer/apc_control.dm
+++ b/code/game/machinery/computer/apc_control.dm
@@ -185,15 +185,19 @@
ui_interact(usr) //Refresh the UI after a filter changes
/obj/machinery/computer/apc_control/emag_act(mob/user)
+ . = ..()
if(!authenticated)
to_chat(user, "You bypass [src]'s access requirements using your emag.")
authenticated = TRUE
log_activity("logged in")
- else if(!(obj_flags & EMAGGED))
+ else
+ if(obj_flags & EMAGGED)
+ return
user.visible_message("You emag [src], disabling precise logging and allowing you to clear logs.")
log_game("[key_name(user)] emagged [src] at [AREACOORD(src)], disabling operator tracking.")
obj_flags |= EMAGGED
- playsound(src, "sparks", 50, 1)
+ playsound(src, "sparks", 50, 1)
+ return TRUE
/obj/machinery/computer/apc_control/proc/log_activity(log_text)
var/op_string = operator && !(obj_flags & EMAGGED) ? operator : "\[NULL OPERATOR\]"
diff --git a/code/game/machinery/computer/arcade/battle.dm b/code/game/machinery/computer/arcade/battle.dm
index ded9cf95f6..b906b1afb5 100644
--- a/code/game/machinery/computer/arcade/battle.dm
+++ b/code/game/machinery/computer/arcade/battle.dm
@@ -186,6 +186,7 @@
/obj/machinery/computer/arcade/battle/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
to_chat(user, "A mesmerizing Rhumba beat starts playing from the arcade machine's speakers!")
@@ -202,5 +203,5 @@
enemy_name = "Cuban Pete"
name = "Outbomb Cuban Pete"
-
updateUsrDialog()
+ return TRUE
\ No newline at end of file
diff --git a/code/game/machinery/computer/arcade/minesweeper.dm b/code/game/machinery/computer/arcade/minesweeper.dm
index e90e05966c..641ef1c9cd 100644
--- a/code/game/machinery/computer/arcade/minesweeper.dm
+++ b/code/game/machinery/computer/arcade/minesweeper.dm
@@ -284,6 +284,7 @@
return
/obj/machinery/computer/arcade/minesweeper/emag_act(mob/user)
+ . = ..()
if(CHECK_BITFIELD(obj_flags, EMAGGED))
return
desc = "An arcade machine that generates grids. It's clunking and sparking everywhere, almost as if threatening to explode at any moment!"
@@ -298,6 +299,7 @@
to_chat(user, "The machine buzzes and sparks... the game has been reset!")
playsound(user, 'sound/machines/buzz-sigh.ogg', 100, 0, extrarange = 3, falloff = 10) //Loud buzz
game_status = MINESWEEPER_GAME_MAIN_MENU
+ return TRUE
/obj/machinery/computer/arcade/minesweeper/proc/custom_generation(mob/user)
playsound(loc, 'sound/arcade/minesweeper_menuselect.ogg', 50, 0, extrarange = -3, falloff = 10) //Entered into the menu so ping sound
diff --git a/code/game/machinery/computer/arcade/orion_trail.dm b/code/game/machinery/computer/arcade/orion_trail.dm
index 12941dea35..023b1048ce 100644
--- a/code/game/machinery/computer/arcade/orion_trail.dm
+++ b/code/game/machinery/computer/arcade/orion_trail.dm
@@ -736,6 +736,7 @@
desc = "Learn how our ancestors got to Orion, and have fun in the process!"
/obj/machinery/computer/arcade/orion_trail/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
to_chat(user, "You override the cheat code menu and skip to Cheat #[rand(1, 50)]: Realism Mode.")
@@ -743,6 +744,7 @@
desc = "Learn how our ancestors got to Orion, and try not to die in the process!"
newgame()
obj_flags |= EMAGGED
+ return TRUE
/mob/living/simple_animal/hostile/syndicate/ranged/smg/orion
name = "spaceport security"
diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm
index 752765baa1..eceaefd2b2 100755
--- a/code/game/machinery/computer/communications.dm
+++ b/code/game/machinery/computer/communications.dm
@@ -432,6 +432,7 @@
return ..()
/obj/machinery/computer/communications/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
@@ -440,6 +441,7 @@
authenticated = 2
to_chat(user, "You scramble the communication routing circuits!")
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
+ return TRUE
/obj/machinery/computer/communications/ui_interact(mob/user)
. = ..()
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 1081cb5fa7..365d19b826 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -1280,20 +1280,23 @@
return !density || (check_access(ID) && !locked && hasPower())
/obj/machinery/door/airlock/emag_act(mob/user)
- if(!operating && density && hasPower() && !(obj_flags & EMAGGED))
- operating = TRUE
- update_icon(AIRLOCK_EMAG, 1)
- sleep(6)
- if(QDELETED(src))
- return
- operating = FALSE
- if(!open())
- update_icon(AIRLOCK_CLOSED, 1)
- obj_flags |= EMAGGED
- lights = FALSE
- locked = TRUE
- loseMainPower()
- loseBackupPower()
+ . = ..()
+ if(operating || !density || !hasPower() || obj_flags & EMAGGED)
+ return
+ operating = TRUE
+ update_icon(AIRLOCK_EMAG, 1)
+ addtimer(CALLBACK(src, .proc/open_sesame), 6)
+ return TRUE
+
+/obj/machinery/door/airlock/proc/open_sesame()
+ operating = FALSE
+ if(!open())
+ update_icon(AIRLOCK_CLOSED, 1)
+ obj_flags |= EMAGGED
+ lights = FALSE
+ locked = TRUE
+ loseMainPower()
+ loseBackupPower()
/obj/machinery/door/airlock/attack_alien(mob/living/carbon/alien/humanoid/user)
add_fingerprint(user)
diff --git a/code/game/machinery/doors/unpowered.dm b/code/game/machinery/doors/unpowered.dm
index 2e7e7d5cba..702f700617 100644
--- a/code/game/machinery/doors/unpowered.dm
+++ b/code/game/machinery/doors/unpowered.dm
@@ -13,9 +13,6 @@
else
return ..()
-/obj/machinery/door/unpowered/emag_act()
- return
-
/obj/machinery/door/unpowered/shuttle
icon = 'icons/turf/shuttle.dmi'
name = "door"
diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm
index 97ab664b85..933bb4f42a 100644
--- a/code/game/machinery/doors/windowdoor.dm
+++ b/code/game/machinery/doors/windowdoor.dm
@@ -206,15 +206,20 @@
..()
/obj/machinery/door/window/emag_act(mob/user)
- if(!operating && density && !(obj_flags & EMAGGED))
- obj_flags |= EMAGGED
- operating = TRUE
- flick("[src.base_state]spark", src)
- playsound(src, "sparks", 75, 1)
- sleep(6)
- operating = FALSE
- desc += "
Its access panel is smoking slightly."
- open(2)
+ . = ..()
+ if(operating || !density || obj_flags & EMAGGED)
+ return
+ obj_flags |= EMAGGED
+ operating = TRUE
+ flick("[src.base_state]spark", src)
+ playsound(src, "sparks", 75, 1)
+ addtimer(CALLBACK(src, .proc/open_windows_me), 6)
+ return TRUE
+
+/obj/machinery/door/window/proc/open_windows_me()
+ operating = FALSE
+ desc += "
Its access panel is smoking slightly."
+ open(2)
/obj/machinery/door/window/attackby(obj/item/I, mob/living/user, params)
diff --git a/code/game/machinery/embedded_controller/access_controller.dm b/code/game/machinery/embedded_controller/access_controller.dm
index 70ce3d36ae..3b9322d207 100644
--- a/code/game/machinery/embedded_controller/access_controller.dm
+++ b/code/game/machinery/embedded_controller/access_controller.dm
@@ -26,6 +26,7 @@
findObjsByTag()
/obj/machinery/doorButtons/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
@@ -33,6 +34,7 @@
req_one_access = list()
playsound(src, "sparks", 100, 1)
to_chat(user, "You short out the access controller.")
+ return TRUE
/obj/machinery/doorButtons/proc/removeMe()
diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm
index 8f0d56a49e..5c2676c2b9 100644
--- a/code/game/machinery/firealarm.dm
+++ b/code/game/machinery/firealarm.dm
@@ -97,6 +97,7 @@
alarm()
/obj/machinery/firealarm/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
@@ -104,6 +105,7 @@
user.visible_message("Sparks fly out of [src]!",
"You emag [src], disabling its thermal sensors.")
playsound(src, "sparks", 50, 1)
+ return TRUE
/obj/machinery/firealarm/temperature_expose(datum/gas_mixture/air, temperature, volume)
if((temperature > T0C + 200 || temperature < BODYTEMP_COLD_DAMAGE_LIMIT) && (last_alarm+FIREALARM_COOLDOWN < world.time) && !(obj_flags & EMAGGED) && detecting && !stat)
diff --git a/code/game/machinery/gulag_item_reclaimer.dm b/code/game/machinery/gulag_item_reclaimer.dm
index f6cb58bbbc..320430be39 100644
--- a/code/game/machinery/gulag_item_reclaimer.dm
+++ b/code/game/machinery/gulag_item_reclaimer.dm
@@ -24,10 +24,12 @@
return ..()
/obj/machinery/gulag_item_reclaimer/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED) // emagging lets anyone reclaim all the items
return
req_access = list()
obj_flags |= EMAGGED
+ return TRUE
/obj/machinery/gulag_item_reclaimer/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/card/id))
diff --git a/code/game/machinery/harvester.dm b/code/game/machinery/harvester.dm
index 8be7becfdd..1fccadda21 100644
--- a/code/game/machinery/harvester.dm
+++ b/code/game/machinery/harvester.dm
@@ -158,11 +158,13 @@
open_machine()
/obj/machinery/harvester/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
allow_living = TRUE
to_chat(user, "You overload [src]'s lifesign scanners.")
+ return TRUE
/obj/machinery/harvester/container_resist(mob/living/user)
if(!harvesting)
diff --git a/code/game/machinery/limbgrower.dm b/code/game/machinery/limbgrower.dm
index a3250fe1b0..59806e97a4 100644
--- a/code/game/machinery/limbgrower.dm
+++ b/code/game/machinery/limbgrower.dm
@@ -215,6 +215,7 @@
return dat
/obj/machinery/limbgrower/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
for(var/id in SSresearch.techweb_designs)
@@ -223,3 +224,4 @@
stored_research.add_design(D)
to_chat(user, "A warning flashes onto the screen, stating that safety overrides have been deactivated!")
obj_flags |= EMAGGED
+ return TRUE
diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm
index b0204ddeb8..b0a75c99dc 100644
--- a/code/game/machinery/porta_turret/portable_turret.dm
+++ b/code/game/machinery/porta_turret/portable_turret.dm
@@ -290,6 +290,7 @@
return ..()
/obj/machinery/porta_turret/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
to_chat(user, "You short out [src]'s threat assessment circuits.")
@@ -300,6 +301,7 @@
update_icon()
sleep(60) //6 seconds for the traitor to gtfo of the area before the turret decides to ruin his shit
on = TRUE //turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here
+ return TRUE
/obj/machinery/porta_turret/emp_act(severity)
@@ -837,6 +839,7 @@
to_chat(user, "Access denied.")
/obj/machinery/turretid/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
to_chat(user, "You short out the turret controls' access analysis module.")
@@ -844,6 +847,7 @@
locked = FALSE
if(user && user.machine == src)
attack_hand(user)
+ return TRUE
/obj/machinery/turretid/attack_ai(mob/user)
if(!ailock || IsAdminGhost(user))
diff --git a/code/game/machinery/porta_turret/portable_turret_cover.dm b/code/game/machinery/porta_turret/portable_turret_cover.dm
index 6ff795c1cc..afb00d4ee2 100644
--- a/code/game/machinery/porta_turret/portable_turret_cover.dm
+++ b/code/game/machinery/porta_turret/portable_turret_cover.dm
@@ -86,10 +86,13 @@
. = 0
/obj/machinery/porta_turret_cover/emag_act(mob/user)
- if(!(parent_turret.obj_flags & EMAGGED))
- to_chat(user, "You short out [parent_turret]'s threat assessment circuits.")
- visible_message("[parent_turret] hums oddly...")
- parent_turret.obj_flags |= EMAGGED
- parent_turret.on = 0
- spawn(40)
- parent_turret.on = 1
+ . = ..()
+ if(parent_turret.obj_flags & EMAGGED)
+ return
+ to_chat(user, "You short out [parent_turret]'s threat assessment circuits.")
+ visible_message("[parent_turret] hums oddly...")
+ parent_turret.obj_flags |= EMAGGED
+ parent_turret.on = 0
+ spawn(40)
+ parent_turret.on = 1
+ return TRUE
diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm
index ff40a8539a..9d431487e0 100644
--- a/code/game/machinery/recycler.dm
+++ b/code/game/machinery/recycler.dm
@@ -65,6 +65,7 @@
return ..()
/obj/machinery/recycler/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
@@ -73,6 +74,7 @@
update_icon()
playsound(src, "sparks", 75, 1, -1)
to_chat(user, "You use the cryptographic sequencer on [src].")
+ return TRUE
/obj/machinery/recycler/update_icon()
..()
diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm
index e2aebd2370..fc6577a4f1 100644
--- a/code/game/machinery/shieldgen.dm
+++ b/code/game/machinery/shieldgen.dm
@@ -195,6 +195,7 @@
return ..()
/obj/machinery/shieldgen/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
to_chat(user, "The access controller is damaged!")
return
@@ -202,6 +203,7 @@
locked = FALSE
playsound(src, "sparks", 100, 1)
to_chat(user, "You short out the access controller.")
+ return TRUE
/obj/machinery/shieldgen/update_icon()
if(active)
@@ -387,6 +389,7 @@
add_fingerprint(user)
/obj/machinery/shieldwallgen/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
to_chat(user, "The access controller is damaged!")
return
@@ -394,6 +397,7 @@
locked = FALSE
playsound(src, "sparks", 100, 1)
to_chat(user, "You short out the access controller.")
+ return TRUE
//////////////Containment Field START
/obj/machinery/shieldwall
diff --git a/code/game/machinery/slotmachine.dm b/code/game/machinery/slotmachine.dm
index 298587cdea..4b73032a8a 100644
--- a/code/game/machinery/slotmachine.dm
+++ b/code/game/machinery/slotmachine.dm
@@ -99,6 +99,7 @@
return ..()
/obj/machinery/computer/slot_machine/emag_act()
+ . = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
@@ -106,6 +107,7 @@
spark_system.set_up(4, 0, src.loc)
spark_system.start()
playsound(src, "sparks", 50, 1)
+ return TRUE
/obj/machinery/computer/slot_machine/ui_interact(mob/living/user)
. = ..()
diff --git a/code/game/machinery/telecomms/computers/message.dm b/code/game/machinery/telecomms/computers/message.dm
index b11c6c102d..ebb40148d8 100644
--- a/code/game/machinery/telecomms/computers/message.dm
+++ b/code/game/machinery/telecomms/computers/message.dm
@@ -42,21 +42,23 @@
return ..()
/obj/machinery/computer/message_monitor/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
- if(!isnull(linkedServer))
- obj_flags |= EMAGGED
- screen = 2
- spark_system.set_up(5, 0, src)
- spark_system.start()
- var/obj/item/paper/monitorkey/MK = new(loc, linkedServer)
- // Will help make emagging the console not so easy to get away with.
- MK.info += "
�%@%(*$%&(�&?*(%&�/{}"
- var/time = 100 * length(linkedServer.decryptkey)
- addtimer(CALLBACK(src, .proc/UnmagConsole), time)
- message = rebootmsg
- else
+ if(isnull(linkedServer))
to_chat(user, "A no server error appears on the screen.")
+ return
+ obj_flags |= EMAGGED
+ screen = 2
+ spark_system.set_up(5, 0, src)
+ spark_system.start()
+ var/obj/item/paper/monitorkey/MK = new(loc, linkedServer)
+ // Will help make emagging the console not so easy to get away with.
+ MK.info += "
�%@%(*$%&(�&?*(%&�/{}"
+ var/time = 100 * length(linkedServer.decryptkey)
+ addtimer(CALLBACK(src, .proc/UnmagConsole), time)
+ message = rebootmsg
+ return TRUE
/obj/machinery/computer/message_monitor/New()
. = ..()
diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index 01e304872f..e1dc80911f 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -64,10 +64,15 @@
/obj/machinery/mecha_part_fabricator/emag_act()
+ . = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
req_access = list()
+ INVOKE_ASYNC(src, .proc/error_action_sucessful)
+ return TRUE
+
+/obj/machinery/mecha_part_fabricator/proc/error_action_sucessful()
say("DB error \[Code 0x00F1\]")
sleep(10)
say("Attempting auto-repair...")
diff --git a/code/game/objects/items/RSF.dm b/code/game/objects/items/RSF.dm
index f0d15cc3a2..01205ee889 100644
--- a/code/game/objects/items/RSF.dm
+++ b/code/game/objects/items/RSF.dm
@@ -134,12 +134,14 @@ RSF
return
/obj/item/cookiesynth/emag_act(mob/user)
+ . = ..()
obj_flags ^= EMAGGED
if(obj_flags & EMAGGED)
to_chat(user, "You short out [src]'s reagent safety checker!")
else
to_chat(user, "You reset [src]'s reagent safety checker!")
- toxin = 0
+ toxin = FALSE
+ return TRUE
/obj/item/cookiesynth/attack_self(mob/user)
var/mob/living/silicon/robot/P = null
diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm
index 96bbe759ca..05ffcbf2fd 100644
--- a/code/game/objects/items/cards_ids.dm
+++ b/code/game/objects/items/cards_ids.dm
@@ -93,34 +93,22 @@
/obj/item/card/emag/afterattack(atom/target, mob/user, proximity)
. = ..()
var/atom/A = target
- if(!proximity && prox_check)
+ if(!proximity && prox_check || !(isobj(A) || issilicon(A) || isbot(A) || isdrone(A)))
+ return
+ if(istype(A, /obj/item/storage) && !(istype(A, /obj/item/storage/lockbox) || istype(A, /obj/item/storage/pod)))
return
- //Citadel changes: modular code misfiring, so we're bypassing into main code.
if(!uses)
user.visible_message("[src] emits a weak spark. It's burnt out!")
playsound(src, 'sound/effects/light_flicker.ogg', 100, 1)
return
else if(uses <= 3)
playsound(src, 'sound/effects/light_flicker.ogg', 30, 1) //Tiiiiiiny warning sound to let ya know your emag's almost dead
-
- if(isturf(A))
+ if(!A.emag_act(user))
return
- if(istype(A,/obj/item/storage/lockbox) || istype(A, /obj/item/storage/pod))
- A.emag_act(user)
- uses = max(uses - 1, 0)
- if(!uses)
- user.visible_message("[src] fizzles and sparks. It seems like it's out of charges.")
- playsound(src, 'sound/effects/light_flicker.ogg', 100, 1)
- if(istype(A,/obj/item/storage))
- return
- if(!(isobj(A) || issilicon(A) || isbot(A) || isdrone(A)))
- return
- else
- A.emag_act(user)
- uses = max(uses - 1, 0)
- if(!uses)
- user.visible_message("[src] fizzles and sparks. It seems like it's out of charges.")
- playsound(src, 'sound/effects/light_flicker.ogg', 100, 1)
+ uses = max(uses - 1, 0)
+ if(!uses)
+ user.visible_message("[src] fizzles and sparks. It seems like it's out of charges.")
+ playsound(src, 'sound/effects/light_flicker.ogg', 100, 1)
/obj/item/card/emagfake
diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm
index 000c52ae43..09a128c558 100644
--- a/code/game/objects/items/cigs_lighters.dm
+++ b/code/game/objects/items/cigs_lighters.dm
@@ -764,20 +764,22 @@ CIGARETTE PACKETS ARE IN FANCY.DM
..()
/obj/item/clothing/mask/vape/emag_act(mob/user)// I WON'T REGRET WRITTING THIS, SURLY.
- if(screw)
- if(!(obj_flags & EMAGGED))
- cut_overlays()
- obj_flags |= EMAGGED
- super = FALSE
- to_chat(user, "You maximize the voltage of [src].")
- add_overlay("vapeopen_high")
- var/datum/effect_system/spark_spread/sp = new /datum/effect_system/spark_spread //for effect
- sp.set_up(5, 1, src)
- sp.start()
- else
- to_chat(user, "[src] is already emagged!")
- else
+ . = ..()
+ if(!screw)
to_chat(user, "You need to open the cap to do that.")
+ return
+ if(obj_flags & EMAGGED)
+ to_chat(user, "[src] is already emagged!")
+ return
+ cut_overlays()
+ obj_flags |= EMAGGED
+ super = FALSE
+ to_chat(user, "You maximize the voltage of [src].")
+ add_overlay("vapeopen_high")
+ var/datum/effect_system/spark_spread/sp = new /datum/effect_system/spark_spread //for effect
+ sp.set_up(5, 1, src)
+ sp.start()
+ return TRUE
/obj/item/clothing/mask/vape/attack_self(mob/user)
if(reagents.total_volume > 0)
diff --git a/code/game/objects/items/circuitboards/computer_circuitboards.dm b/code/game/objects/items/circuitboards/computer_circuitboards.dm
index 7d2ffe0a02..bb45f80f2d 100644
--- a/code/game/objects/items/circuitboards/computer_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/computer_circuitboards.dm
@@ -217,10 +217,13 @@
to_chat(user, "The spectrum chip is unresponsive.")
/obj/item/circuitboard/computer/cargo/emag_act(mob/living/user)
- if(!(obj_flags & EMAGGED))
- contraband = TRUE
- obj_flags |= EMAGGED
- to_chat(user, "You adjust [src]'s routing and receiver spectrum, unlocking special supplies and contraband.")
+ . = ..()
+ if(obj_flags & EMAGGED)
+ return
+ contraband = TRUE
+ obj_flags |= EMAGGED
+ to_chat(user, "You adjust [src]'s routing and receiver spectrum, unlocking special supplies and contraband.")
+ return TRUE
/obj/item/circuitboard/computer/cargo/express
name = "Express Supply Console (Computer Board)"
@@ -234,8 +237,12 @@
obj_flags &= ~EMAGGED
/obj/item/circuitboard/computer/cargo/express/emag_act(mob/living/user)
- to_chat(user, "You change the routing protocols, allowing the Drop Pod to land anywhere on the station.")
- obj_flags |= EMAGGED
+ . = SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT)
+ if(obj_flags & EMAGGED)
+ return
+ to_chat(user, "You change the routing protocols, allowing the Drop Pod to land anywhere on the station.")
+ obj_flags |= EMAGGED
+ return TRUE
/obj/item/circuitboard/computer/cargo/request
name = "Supply Request Console (Computer Board)"
diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm
index 55e75b3992..5bef86c6d2 100644
--- a/code/game/objects/items/defib.dm
+++ b/code/game/objects/items/defib.dm
@@ -140,12 +140,10 @@
return ..()
/obj/item/defibrillator/emag_act(mob/user)
- if(safety)
- safety = FALSE
- to_chat(user, "You silently disable [src]'s safety protocols with the cryptographic sequencer.")
- else
- safety = TRUE
- to_chat(user, "You silently enable [src]'s safety protocols with the cryptographic sequencer.")
+ . = ..()
+ safety = !safety
+ to_chat(user, "You silently [safety ? "enable" : "disable"] [src]'s safety protocols with the cryptographic sequencer.")
+ return TRUE
/obj/item/defibrillator/emp_act(severity)
. = ..()
diff --git a/code/game/objects/items/devices/geiger_counter.dm b/code/game/objects/items/devices/geiger_counter.dm
index 7823e570e0..38133e37bc 100644
--- a/code/game/objects/items/devices/geiger_counter.dm
+++ b/code/game/objects/items/devices/geiger_counter.dm
@@ -192,13 +192,15 @@
update_icon()
/obj/item/geiger_counter/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
if(scanning)
to_chat(user, "Turn off [src] before you perform this action!")
- return 0
+ return
to_chat(user, "You override [src]'s radiation storing protocols. It will now generate small doses of radiation, and stored rads are now projected into creatures you scan.")
obj_flags |= EMAGGED
+ return TRUE
/obj/item/geiger_counter/cyborg
var/datum/component/mobhook
diff --git a/code/game/objects/items/devices/lightreplacer.dm b/code/game/objects/items/devices/lightreplacer.dm
index 6615ebe8a8..1e31f14cfd 100644
--- a/code/game/objects/items/devices/lightreplacer.dm
+++ b/code/game/objects/items/devices/lightreplacer.dm
@@ -149,9 +149,11 @@
to_chat(user, "You fill \the [src] with lights from \the [S]. " + status_string() + "")
/obj/item/lightreplacer/emag_act()
+ . = ..()
if(obj_flags & EMAGGED)
return
Emag()
+ return TRUE
/obj/item/lightreplacer/attack_self(mob/user)
to_chat(user, status_string())
diff --git a/code/game/objects/items/devices/megaphone.dm b/code/game/objects/items/devices/megaphone.dm
index 347bb6894d..915fcac504 100644
--- a/code/game/objects/items/devices/megaphone.dm
+++ b/code/game/objects/items/devices/megaphone.dm
@@ -38,11 +38,13 @@
speech_args[SPEECH_SPANS] |= voicespan
/obj/item/megaphone/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
to_chat(user, "You overload \the [src]'s voice synthesizer.")
obj_flags |= EMAGGED
voicespan = list(SPAN_REALLYBIG, "userdanger")
+ return TRUE
/obj/item/megaphone/sec
name = "security megaphone"
diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm
index 6d7c3036f9..5454b0fdb8 100644
--- a/code/game/objects/items/robot/robot_items.dm
+++ b/code/game/objects/items/robot/robot_items.dm
@@ -282,11 +282,13 @@
var/cooldown = 0
/obj/item/harmalarm/emag_act(mob/user)
+ . = ..()
obj_flags ^= EMAGGED
if(obj_flags & EMAGGED)
to_chat(user, "You short out the safeties on [src]!")
else
to_chat(user, "You reset the safeties on [src]!")
+ return TRUE
/obj/item/harmalarm/attack_self(mob/user)
var/safety = !(obj_flags & EMAGGED)
diff --git a/code/game/objects/items/storage/lockbox.dm b/code/game/objects/items/storage/lockbox.dm
index 4924051855..eeebc6f4c5 100644
--- a/code/game/objects/items/storage/lockbox.dm
+++ b/code/game/objects/items/storage/lockbox.dm
@@ -48,14 +48,16 @@
to_chat(user, "It's locked!")
/obj/item/storage/lockbox/emag_act(mob/user)
- if(!broken)
- broken = TRUE
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, FALSE)
- desc += "It appears to be broken."
- icon_state = src.icon_broken
- if(user)
- visible_message("\The [src] has been broken by [user] with an electromagnetic card!")
- return
+ . = ..()
+ if(broken)
+ return
+ broken = TRUE
+ SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, FALSE)
+ desc += "It appears to be broken."
+ icon_state = src.icon_broken
+ if(user)
+ visible_message("\The [src] has been broken by [user] with an electromagnetic card!")
+ return TRUE
/obj/item/storage/lockbox/Entered()
. = ..()
diff --git a/code/game/objects/structures/barsigns.dm b/code/game/objects/structures/barsigns.dm
index 1ab28a33de..2093ae5660 100644
--- a/code/game/objects/structures/barsigns.dm
+++ b/code/game/objects/structures/barsigns.dm
@@ -112,12 +112,16 @@
/obj/structure/sign/barsign/emag_act(mob/user)
+ . = ..()
if(broken || (obj_flags & EMAGGED))
to_chat(user, "Nothing interesting happens!")
return
obj_flags |= EMAGGED
to_chat(user, "You emag the barsign. Takeover in progress...")
- sleep(10 SECONDS)
+ addtimer(CALLBACK(src, .proc/syndie_bar_good), 10 SECONDS)
+ return TRUE
+
+/obj/structure/sign/barsign/proc/syndie_bar_good()
set_sign(new /datum/barsign/hiddensigns/syndibarsign)
req_access = list(ACCESS_SYNDICATE)
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index f097d2903a..edcb4a6181 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -1,616 +1,617 @@
-/obj/structure/closet
- name = "closet"
- desc = "It's a basic storage unit."
- icon = 'icons/obj/closet.dmi'
- icon_state = "generic"
- density = TRUE
- layer = BELOW_OBJ_LAYER
- var/icon_door = null
- var/icon_door_override = FALSE //override to have open overlay use icon different to its base's
- var/secure = FALSE //secure locker or not, also used if overriding a non-secure locker with a secure door overlay to add fancy lights
- var/opened = FALSE
- var/welded = FALSE
- var/locked = FALSE
- var/large = TRUE
- var/wall_mounted = 0 //never solid (You can always pass over it)
- max_integrity = 200
- integrity_failure = 50
- armor = list("melee" = 20, "bullet" = 10, "laser" = 10, "energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 60)
- var/breakout_time = 1200
- var/message_cooldown
- var/can_weld_shut = TRUE
- var/horizontal = FALSE
- var/allow_objects = FALSE
- var/allow_dense = FALSE
- var/dense_when_open = FALSE //if it's dense when open or not
- var/max_mob_size = MOB_SIZE_HUMAN //Biggest mob_size accepted by the container
- var/mob_storage_capacity = 3 // how many human sized mob/living can fit together inside a closet.
- var/storage_capacity = 30 //This is so that someone can't pack hundreds of items in a locker/crate then open it in a populated area to crash clients.
- var/cutting_tool = /obj/item/weldingtool
- var/open_sound = 'sound/machines/click.ogg'
- var/close_sound = 'sound/machines/click.ogg'
- var/material_drop = /obj/item/stack/sheet/metal
- var/material_drop_amount = 2
- var/delivery_icon = "deliverycloset" //which icon to use when packagewrapped. null to be unwrappable.
- var/anchorable = TRUE
- var/icon_welded = "welded"
- var/obj/item/electronics/airlock/lockerelectronics //Installed electronics
- var/lock_in_use = FALSE //Someone is doing some stuff with the lock here, better not proceed further
- var/eigen_teleport = FALSE //If the closet leads to Mr Tumnus.
- var/obj/structure/closet/eigen_target //Where you go to.
-
-
-/obj/structure/closet/Initialize(mapload)
- . = ..()
- update_icon()
- PopulateContents()
- if(mapload && !opened) // if closed, any item at the crate's loc is put in the contents
- take_contents()
- if(secure)
- lockerelectronics = new(src)
- lockerelectronics.accesses = req_access
-
-//USE THIS TO FILL IT, NOT INITIALIZE OR NEW
-/obj/structure/closet/proc/PopulateContents()
- return
-
-/obj/structure/closet/Destroy()
- dump_contents(override = FALSE)
- return ..()
-
-/obj/structure/closet/update_icon()
- cut_overlays()
- if(opened & icon_door_override)
- add_overlay("[icon_door]_open")
- layer = OBJ_LAYER
- return
- else if(opened)
- add_overlay("[icon_state]_open")
- return
- if(icon_door)
- add_overlay("[icon_door]_door")
- else
- layer = BELOW_OBJ_LAYER
- add_overlay("[icon_state]_door")
- if(welded)
- add_overlay("welded")
- if(!secure)
- return
- if(broken)
- add_overlay("off")
- add_overlay("sparking")
- else if(locked)
- add_overlay("locked")
- else
- add_overlay("unlocked")
-
-/obj/structure/closet/examine(mob/user)
- ..()
- if(welded)
- to_chat(user, "It's welded shut.")
- if(anchored)
- to_chat(user, "It is bolted to the ground.")
- if(opened)
- to_chat(user, "The parts are welded together.")
- else if(secure && !opened)
- else if(broken)
- to_chat(user, "The lock is screwed in.")
- else if(secure)
- to_chat(user, "Alt-click to [locked ? "unlock" : "lock"].")
- if(isliving(user))
- var/mob/living/L = user
- if(HAS_TRAIT(L, TRAIT_SKITTISH))
- to_chat(user, "Ctrl-Shift-click [src] to jump inside.")
-
-/obj/structure/closet/CanPass(atom/movable/mover, turf/target)
- if(wall_mounted)
- return TRUE
- return !density
-
-/obj/structure/closet/proc/can_open(mob/living/user)
- if(welded || locked)
- return FALSE
- var/turf/T = get_turf(src)
- for(var/mob/living/L in T)
- if(L.anchored || horizontal && L.mob_size > MOB_SIZE_TINY && L.density)
- if(user)
- to_chat(user, "There's something large on top of [src], preventing it from opening." )
- return FALSE
- return TRUE
-
-/obj/structure/closet/proc/can_close(mob/living/user)
- var/turf/T = get_turf(src)
- for(var/obj/structure/closet/closet in T)
- if(closet != src && !closet.wall_mounted)
- return FALSE
- for(var/mob/living/L in T)
- if(L.anchored || horizontal && L.mob_size > MOB_SIZE_TINY && L.density)
- if(user)
- to_chat(user, "There's something too large in [src], preventing it from closing.")
- return FALSE
- return TRUE
-
-/obj/structure/closet/proc/can_lock(mob/living/user, var/check_access = TRUE) //set check_access to FALSE if you only need to check if a locker has a functional lock rather than access
- if(!secure)
- return FALSE
- if(broken)
- to_chat(user, "[src] is broken!")
- return FALSE
- if(QDELETED(lockerelectronics) && !locked) //We want to be able to unlock it regardless of electronics, but only lockable with electronics
- to_chat(user, "[src] is missing locker electronics!")
- return FALSE
- if(!check_access)
- return TRUE
- if(allowed(user))
- return TRUE
- to_chat(user, "Access denied.")
-
-/obj/structure/closet/proc/togglelock(mob/living/user)
- add_fingerprint(user)
- if(eigen_target)
- return
- if(opened)
- return
- if(!can_lock(user))
- return
- locked = !locked
- user.visible_message("[user] [locked ? null : "un"]locks [src].",
- "You [locked ? null : "un"]lock [src].")
- update_icon()
-
-/obj/structure/closet/proc/dump_contents(var/override = TRUE) //Override is for not revealing the locker electronics when you open the locker, for example
- var/atom/L = drop_location()
- for(var/atom/movable/AM in src)
- if(AM == lockerelectronics && override)
- continue
- AM.forceMove(L)
- if(throwing) // you keep some momentum when getting out of a thrown closet
- step(AM, dir)
- if(throwing)
- throwing.finalize(FALSE)
-
-/obj/structure/closet/proc/take_contents()
- var/atom/L = drop_location()
- for(var/atom/movable/AM in L)
- if(AM != src && insert(AM) == -1) // limit reached
- break
-
-/obj/structure/closet/proc/open(mob/living/user)
- if(opened || !can_open(user))
- return
- playsound(loc, open_sound, 15, 1, -3)
- opened = TRUE
- if(!dense_when_open)
- density = FALSE
- climb_time *= 0.5 //it's faster to climb onto an open thing
- dump_contents()
- update_icon()
- return 1
-
-/obj/structure/closet/proc/insert(atom/movable/AM)
- if(contents.len >= storage_capacity)
- return -1
- if(insertion_allowed(AM))
- if(eigen_teleport) // For teleporting people with linked lockers.
- do_teleport(AM, get_turf(eigen_target), 0)
- if(eigen_target.opened == FALSE)
- eigen_target.bust_open()
- else
- AM.forceMove(src)
- return TRUE
- else
- return FALSE
-
-
-/obj/structure/closet/proc/insertion_allowed(atom/movable/AM)
- if(ismob(AM))
- if(!isliving(AM)) //let's not put ghosts or camera mobs inside closets...
- return FALSE
- var/mob/living/L = AM
- if(L.anchored || L.buckled || L.incorporeal_move || L.has_buckled_mobs())
- return FALSE
- if(L.mob_size > MOB_SIZE_TINY) // Tiny mobs are treated as items.
- if(horizontal && L.density)
- return FALSE
- if(L.mob_size > max_mob_size)
- return FALSE
- var/mobs_stored = 0
- for(var/mob/living/M in contents)
- if(++mobs_stored >= mob_storage_capacity)
- return FALSE
- L.stop_pulling()
-
- else if(istype(AM, /obj/structure/closet))
- return FALSE
-
- else if(istype(AM, /obj/effect))
- return FALSE
-
- else if(isobj(AM))
- if((!allow_dense && AM.density) || AM.anchored || AM.has_buckled_mobs())
- return FALSE
- if(isitem(AM) && !HAS_TRAIT(AM, TRAIT_NODROP))
- return TRUE
- else if(!allow_objects && !istype(AM, /obj/effect/dummy/chameleon))
- return FALSE
- else
- return FALSE
-
- return TRUE
-
-/obj/structure/closet/proc/close(mob/living/user)
- if(!opened || !can_close(user))
- return FALSE
- take_contents()
- playsound(loc, close_sound, 15, 1, -3)
- climb_time = initial(climb_time)
- opened = FALSE
- density = TRUE
- update_icon()
- return TRUE
-
-/obj/structure/closet/proc/toggle(mob/living/user)
- if(opened)
- return close(user)
- else
- return open(user)
-
-/obj/structure/closet/proc/bust_open()
- welded = FALSE //applies to all lockers
- locked = FALSE //applies to critter crates and secure lockers only
- broken = TRUE //applies to secure lockers only
- open()
-
-/obj/structure/closet/proc/handle_lock_addition(mob/user, obj/item/electronics/airlock/E)
- add_fingerprint(user)
- if(lock_in_use)
- to_chat(user, "Wait for work on [src] to be done first!")
- return
- if(secure)
- to_chat(user, "This locker already has a lock!")
- return
- if(broken)
- to_chat(user, "Unscrew the broken lock first!")
- return
- if(!istype(E))
- return
- user.visible_message("[user] begins installing a lock on [src]...","You begin installing a lock on [src]...")
- lock_in_use = TRUE
- playsound(loc, 'sound/items/screwdriver.ogg', 50, 1)
- if(!do_after(user, 60, target = src))
- lock_in_use = FALSE
- return
- lock_in_use = FALSE
- to_chat(user, "You finish the lock on [src]!")
- E.forceMove(src)
- lockerelectronics = E
- req_access = E.accesses
- secure = TRUE
- update_icon()
- return TRUE
-
-/obj/structure/closet/proc/handle_lock_removal(mob/user, obj/item/screwdriver/S)
- if(lock_in_use)
- to_chat(user, "Wait for work on [src] to be done first!")
- return
- if(locked)
- to_chat(user, "Unlock it first!")
- return
- if(!secure)
- to_chat(user, "[src] doesn't have a lock that you can remove!")
- return
- if(!istype(S))
- return
- var/brokenword = broken ? "broken " : null
- user.visible_message("[user] begins removing the [brokenword]lock on [src]...","You begin removing the [brokenword]lock on [src]...")
- playsound(loc, S.usesound, 50, 1)
- lock_in_use = TRUE
- if(!do_after(user, 100 * S.toolspeed, target = src))
- lock_in_use = FALSE
- return
- to_chat(user, "You remove the [brokenword]lock from [src]!")
- if(!QDELETED(lockerelectronics))
- lockerelectronics.add_fingerprint(user)
- lockerelectronics.forceMove(user.loc)
- lockerelectronics = null
- req_access = null
- secure = FALSE
- broken = FALSE
- locked = FALSE
- lock_in_use = FALSE
- update_icon()
- return TRUE
-
-
-/obj/structure/closet/deconstruct(disassembled = TRUE)
- if(ispath(material_drop) && material_drop_amount && !(flags_1 & NODECONSTRUCT_1))
- new material_drop(loc, material_drop_amount)
- qdel(src)
-
-/obj/structure/closet/obj_break(damage_flag)
- if(!broken && !(flags_1 & NODECONSTRUCT_1))
- bust_open()
-
-/obj/structure/closet/attackby(obj/item/W, mob/user, params)
- if(user in src)
- return
- if(src.tool_interact(W,user))
- return 1 // No afterattack
- else
- return ..()
-
-/obj/structure/closet/proc/tool_interact(obj/item/W, mob/user)//returns TRUE if attackBy call shouldnt be continued (because tool was used/closet was of wrong type), FALSE if otherwise
- . = TRUE
- if(opened)
- if(istype(W, cutting_tool))
- if(istype(W, /obj/item/weldingtool))
- if(!W.tool_start_check(user, amount=0))
- return
-
- to_chat(user, "You begin cutting \the [src] apart...")
- if(W.use_tool(src, user, 40, volume=50))
- if(eigen_teleport)
- to_chat(user, "The unstable nature of \the [src] makes it impossible to cut!")
- return
- if(!opened)
- return
- user.visible_message("[user] slices apart \the [src].",
- "You cut \the [src] apart with \the [W].",
- "You hear welding.")
- deconstruct(TRUE)
- return
- else // for example cardboard box is cut with wirecutters
- user.visible_message("[user] cut apart \the [src].", \
- "You cut \the [src] apart with \the [W].")
- deconstruct(TRUE)
- return
- if(user.transferItemToLoc(W, drop_location())) // so we put in unlit welder too
- return TRUE
- else if(istype(W, /obj/item/electronics/airlock))
- handle_lock_addition(user, W)
- else if(istype(W, /obj/item/screwdriver))
- handle_lock_removal(user, W)
- else if(istype(W, /obj/item/weldingtool) && can_weld_shut)
- if(!W.tool_start_check(user, amount=0))
- return
-
- to_chat(user, "You begin [welded ? "unwelding":"welding"] \the [src]...")
- if(W.use_tool(src, user, 40, volume=50))
- if(eigen_teleport)
- to_chat(user, "The unstable nature of \the [src] makes it impossible to weld!")
- return
- if(opened)
- return
- welded = !welded
- after_weld(welded)
- user.visible_message("[user] [welded ? "welds shut" : "unwelds"] \the [src].",
- "You [welded ? "weld" : "unwelded"] \the [src] with \the [W].",
- "You hear welding.")
- update_icon()
- else if(istype(W, /obj/item/wrench) && anchorable)
- if(isinspace() && !anchored)
- return
- setAnchored(!anchored)
- W.play_tool_sound(src, 75)
- user.visible_message("[user] [anchored ? "anchored" : "unanchored"] \the [src] [anchored ? "to" : "from"] the ground.", \
- "You [anchored ? "anchored" : "unanchored"] \the [src] [anchored ? "to" : "from"] the ground.", \
- "You hear a ratchet.")
- else if(user.a_intent != INTENT_HARM && !(W.item_flags & NOBLUDGEON))
- if(W.GetID() || !toggle(user))
- togglelock(user)
- else
- return FALSE
-
-/obj/structure/closet/proc/after_weld(weld_state)
- return
-
-/obj/structure/closet/MouseDrop_T(atom/movable/O, mob/living/user)
- if(!istype(O) || O.anchored || istype(O, /obj/screen))
- return
- if(!istype(user) || user.incapacitated() || user.lying)
- return
- if(!Adjacent(user) || !user.Adjacent(O))
- return
- if(user == O) //try to climb onto it
- return ..()
- if(!opened)
- return
- if(!isturf(O.loc))
- return
-
- var/actuallyismob = 0
- if(isliving(O))
- actuallyismob = 1
- else if(!isitem(O))
- return
- var/turf/T = get_turf(src)
- var/list/targets = list(O, src)
- add_fingerprint(user)
- user.visible_message("[user] [actuallyismob ? "tries to ":""]stuff [O] into [src].", \
- "You [actuallyismob ? "try to ":""]stuff [O] into [src].", \
- "You hear clanging.")
- if(actuallyismob)
- if(do_after_mob(user, targets, 40))
- user.visible_message("[user] stuffs [O] into [src].", \
- "You stuff [O] into [src].", \
- "You hear a loud metal bang.")
- var/mob/living/L = O
- if(!issilicon(L))
- L.Knockdown(40)
- O.forceMove(T)
- close()
- else
- O.forceMove(T)
- return 1
-
-/obj/structure/closet/relaymove(mob/user)
- if(user.stat || !isturf(loc) || !isliving(user))
- return
- if(locked)
- if(message_cooldown <= world.time)
- message_cooldown = world.time + 50
- to_chat(user, "[src]'s door won't budge!")
- return
- container_resist(user)
-
-/obj/structure/closet/attack_hand(mob/user)
- . = ..()
- if(.)
- return
- if(user.lying && get_dist(src, user) > 0)
- return
-
- if(!toggle(user))
- togglelock(user)
-
-/obj/structure/closet/attack_paw(mob/user)
- return attack_hand(user)
-
-/obj/structure/closet/attack_robot(mob/user)
- if(user.Adjacent(src))
- return attack_hand(user)
-
-// tk grab then use on self
-/obj/structure/closet/attack_self_tk(mob/user)
- return attack_hand(user)
-
-/obj/structure/closet/verb/verb_toggleopen()
- set src in oview(1)
- set category = "Object"
- set name = "Toggle Open"
-
- if(!usr.canmove || usr.stat || usr.restrained())
- return
-
- if(iscarbon(usr) || issilicon(usr) || isdrone(usr))
- return attack_hand(usr)
- else
- to_chat(usr, "This mob type can't use this verb.")
-
-// Objects that try to exit a locker by stepping were doing so successfully,
-// and due to an oversight in turf/Enter() were going through walls. That
-// should be independently resolved, but this is also an interesting twist.
-/obj/structure/closet/Exit(atom/movable/AM)
- open()
- if(AM.loc == src)
- return 0
- return 1
-
-/obj/structure/closet/container_resist(mob/living/user)
- if(opened)
- return
- if(ismovableatom(loc))
- user.changeNext_move(CLICK_CD_BREAKOUT)
- user.last_special = world.time + CLICK_CD_BREAKOUT
- var/atom/movable/AM = loc
- AM.relay_container_resist(user, src)
- return
- if(!welded && !locked)
- open()
- return
-
- //okay, so the closet is either welded or locked... resist!!!
- user.changeNext_move(CLICK_CD_BREAKOUT)
- user.last_special = world.time + CLICK_CD_BREAKOUT
- user.visible_message("[src] begins to shake violently!", \
- "You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)", \
- "You hear banging from [src].")
- if(do_after(user,(breakout_time), target = src))
- if(!user || user.stat != CONSCIOUS || user.loc != src || opened || (!locked && !welded) )
- return
- //we check after a while whether there is a point of resisting anymore and whether the user is capable of resisting
- user.visible_message("[user] successfully broke out of [src]!",
- "You successfully break out of [src]!")
- bust_open()
- else
- if(user.loc == src) //so we don't get the message if we resisted multiple times and succeeded.
- to_chat(user, "You fail to break out of [src]!")
-
-/obj/structure/closet/AltClick(mob/user)
- ..()
- if(!user.canUseTopic(src, be_close=TRUE) || !isturf(loc))
- to_chat(user, "You can't do that right now!")
- return
- togglelock(user)
-
-/obj/structure/closet/CtrlShiftClick(mob/living/user)
- if(!HAS_TRAIT(user, TRAIT_SKITTISH))
- return ..()
- if(!user.canUseTopic(src) || !isturf(user.loc))
- return
- dive_into(user)
-
-/obj/structure/closet/emag_act(mob/user)
- if(secure && !broken)
- user.visible_message("Sparks fly from [src]!",
- "You scramble [src]'s lock, breaking it open!",
- "You hear a faint electrical spark.")
- playsound(src, "sparks", 50, 1)
- broken = TRUE
- locked = FALSE
- if(!QDELETED(lockerelectronics))
- qdel(lockerelectronics)
- lockerelectronics = null
- update_icon()
-
-/obj/structure/closet/get_remote_view_fullscreens(mob/user)
- if(user.stat == DEAD || !(user.sight & (SEEOBJS|SEEMOBS)))
- user.overlay_fullscreen("remote_view", /obj/screen/fullscreen/impaired, 1)
-
-/obj/structure/closet/emp_act(severity)
- . = ..()
- if(. & EMP_PROTECT_SELF)
- return
- if (!(. & EMP_PROTECT_CONTENTS))
- for(var/obj/O in src)
- O.emp_act(severity)
- if(!secure || broken)
- return ..()
- if(prob(50 / severity))
- locked = !locked
- update_icon()
- if(prob(20 / severity) && !opened)
- if(!locked)
- open()
- else
- req_access = list()
- req_access += pick(get_all_accesses())
- if(!QDELETED(lockerelectronics))
- lockerelectronics.accesses = req_access
-
-/obj/structure/closet/contents_explosion(severity, target)
- for(var/atom/A in contents)
- A.ex_act(severity, target)
- CHECK_TICK
-
-/obj/structure/closet/singularity_act()
- dump_contents()
- ..()
-
-/obj/structure/closet/AllowDrop()
- return TRUE
-
-
-/obj/structure/closet/return_temperature()
- return
-
-/obj/structure/closet/proc/dive_into(mob/living/user)
- var/turf/T1 = get_turf(user)
- var/turf/T2 = get_turf(src)
- if(!opened)
- if(locked)
- togglelock(user, TRUE)
- if(!open(user))
- to_chat(user, "It won't budge!")
- return
- step_towards(user, T2)
- T1 = get_turf(user)
- if(T1 == T2)
- user.resting = TRUE //so people can jump into crates without slamming the lid on their head
- if(!close(user))
- to_chat(user, "You can't get [src] to close!")
- user.resting = FALSE
- return
- user.resting = FALSE
- togglelock(user)
- T1.visible_message("[user] dives into [src]!")
+/obj/structure/closet
+ name = "closet"
+ desc = "It's a basic storage unit."
+ icon = 'icons/obj/closet.dmi'
+ icon_state = "generic"
+ density = TRUE
+ layer = BELOW_OBJ_LAYER
+ var/icon_door = null
+ var/icon_door_override = FALSE //override to have open overlay use icon different to its base's
+ var/secure = FALSE //secure locker or not, also used if overriding a non-secure locker with a secure door overlay to add fancy lights
+ var/opened = FALSE
+ var/welded = FALSE
+ var/locked = FALSE
+ var/large = TRUE
+ var/wall_mounted = 0 //never solid (You can always pass over it)
+ max_integrity = 200
+ integrity_failure = 50
+ armor = list("melee" = 20, "bullet" = 10, "laser" = 10, "energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 60)
+ var/breakout_time = 1200
+ var/message_cooldown
+ var/can_weld_shut = TRUE
+ var/horizontal = FALSE
+ var/allow_objects = FALSE
+ var/allow_dense = FALSE
+ var/dense_when_open = FALSE //if it's dense when open or not
+ var/max_mob_size = MOB_SIZE_HUMAN //Biggest mob_size accepted by the container
+ var/mob_storage_capacity = 3 // how many human sized mob/living can fit together inside a closet.
+ var/storage_capacity = 30 //This is so that someone can't pack hundreds of items in a locker/crate then open it in a populated area to crash clients.
+ var/cutting_tool = /obj/item/weldingtool
+ var/open_sound = 'sound/machines/click.ogg'
+ var/close_sound = 'sound/machines/click.ogg'
+ var/material_drop = /obj/item/stack/sheet/metal
+ var/material_drop_amount = 2
+ var/delivery_icon = "deliverycloset" //which icon to use when packagewrapped. null to be unwrappable.
+ var/anchorable = TRUE
+ var/icon_welded = "welded"
+ var/obj/item/electronics/airlock/lockerelectronics //Installed electronics
+ var/lock_in_use = FALSE //Someone is doing some stuff with the lock here, better not proceed further
+ var/eigen_teleport = FALSE //If the closet leads to Mr Tumnus.
+ var/obj/structure/closet/eigen_target //Where you go to.
+
+
+/obj/structure/closet/Initialize(mapload)
+ . = ..()
+ update_icon()
+ PopulateContents()
+ if(mapload && !opened) // if closed, any item at the crate's loc is put in the contents
+ take_contents()
+ if(secure)
+ lockerelectronics = new(src)
+ lockerelectronics.accesses = req_access
+
+//USE THIS TO FILL IT, NOT INITIALIZE OR NEW
+/obj/structure/closet/proc/PopulateContents()
+ return
+
+/obj/structure/closet/Destroy()
+ dump_contents(override = FALSE)
+ return ..()
+
+/obj/structure/closet/update_icon()
+ cut_overlays()
+ if(opened & icon_door_override)
+ add_overlay("[icon_door]_open")
+ layer = OBJ_LAYER
+ return
+ else if(opened)
+ add_overlay("[icon_state]_open")
+ return
+ if(icon_door)
+ add_overlay("[icon_door]_door")
+ else
+ layer = BELOW_OBJ_LAYER
+ add_overlay("[icon_state]_door")
+ if(welded)
+ add_overlay("welded")
+ if(!secure)
+ return
+ if(broken)
+ add_overlay("off")
+ add_overlay("sparking")
+ else if(locked)
+ add_overlay("locked")
+ else
+ add_overlay("unlocked")
+
+/obj/structure/closet/examine(mob/user)
+ ..()
+ if(welded)
+ to_chat(user, "It's welded shut.")
+ if(anchored)
+ to_chat(user, "It is bolted to the ground.")
+ if(opened)
+ to_chat(user, "The parts are welded together.")
+ else if(secure && !opened)
+ else if(broken)
+ to_chat(user, "The lock is screwed in.")
+ else if(secure)
+ to_chat(user, "Alt-click to [locked ? "unlock" : "lock"].")
+ if(isliving(user))
+ var/mob/living/L = user
+ if(HAS_TRAIT(L, TRAIT_SKITTISH))
+ to_chat(user, "Ctrl-Shift-click [src] to jump inside.")
+
+/obj/structure/closet/CanPass(atom/movable/mover, turf/target)
+ if(wall_mounted)
+ return TRUE
+ return !density
+
+/obj/structure/closet/proc/can_open(mob/living/user)
+ if(welded || locked)
+ return FALSE
+ var/turf/T = get_turf(src)
+ for(var/mob/living/L in T)
+ if(L.anchored || horizontal && L.mob_size > MOB_SIZE_TINY && L.density)
+ if(user)
+ to_chat(user, "There's something large on top of [src], preventing it from opening." )
+ return FALSE
+ return TRUE
+
+/obj/structure/closet/proc/can_close(mob/living/user)
+ var/turf/T = get_turf(src)
+ for(var/obj/structure/closet/closet in T)
+ if(closet != src && !closet.wall_mounted)
+ return FALSE
+ for(var/mob/living/L in T)
+ if(L.anchored || horizontal && L.mob_size > MOB_SIZE_TINY && L.density)
+ if(user)
+ to_chat(user, "There's something too large in [src], preventing it from closing.")
+ return FALSE
+ return TRUE
+
+/obj/structure/closet/proc/can_lock(mob/living/user, var/check_access = TRUE) //set check_access to FALSE if you only need to check if a locker has a functional lock rather than access
+ if(!secure)
+ return FALSE
+ if(broken)
+ to_chat(user, "[src] is broken!")
+ return FALSE
+ if(QDELETED(lockerelectronics) && !locked) //We want to be able to unlock it regardless of electronics, but only lockable with electronics
+ to_chat(user, "[src] is missing locker electronics!")
+ return FALSE
+ if(!check_access)
+ return TRUE
+ if(allowed(user))
+ return TRUE
+ to_chat(user, "Access denied.")
+
+/obj/structure/closet/proc/togglelock(mob/living/user)
+ add_fingerprint(user)
+ if(eigen_target)
+ return
+ if(opened)
+ return
+ if(!can_lock(user))
+ return
+ locked = !locked
+ user.visible_message("[user] [locked ? null : "un"]locks [src].",
+ "You [locked ? null : "un"]lock [src].")
+ update_icon()
+
+/obj/structure/closet/proc/dump_contents(var/override = TRUE) //Override is for not revealing the locker electronics when you open the locker, for example
+ var/atom/L = drop_location()
+ for(var/atom/movable/AM in src)
+ if(AM == lockerelectronics && override)
+ continue
+ AM.forceMove(L)
+ if(throwing) // you keep some momentum when getting out of a thrown closet
+ step(AM, dir)
+ if(throwing)
+ throwing.finalize(FALSE)
+
+/obj/structure/closet/proc/take_contents()
+ var/atom/L = drop_location()
+ for(var/atom/movable/AM in L)
+ if(AM != src && insert(AM) == -1) // limit reached
+ break
+
+/obj/structure/closet/proc/open(mob/living/user)
+ if(opened || !can_open(user))
+ return
+ playsound(loc, open_sound, 15, 1, -3)
+ opened = TRUE
+ if(!dense_when_open)
+ density = FALSE
+ climb_time *= 0.5 //it's faster to climb onto an open thing
+ dump_contents()
+ update_icon()
+ return 1
+
+/obj/structure/closet/proc/insert(atom/movable/AM)
+ if(contents.len >= storage_capacity)
+ return -1
+ if(insertion_allowed(AM))
+ if(eigen_teleport) // For teleporting people with linked lockers.
+ do_teleport(AM, get_turf(eigen_target), 0)
+ if(eigen_target.opened == FALSE)
+ eigen_target.bust_open()
+ else
+ AM.forceMove(src)
+ return TRUE
+ else
+ return FALSE
+
+
+/obj/structure/closet/proc/insertion_allowed(atom/movable/AM)
+ if(ismob(AM))
+ if(!isliving(AM)) //let's not put ghosts or camera mobs inside closets...
+ return FALSE
+ var/mob/living/L = AM
+ if(L.anchored || L.buckled || L.incorporeal_move || L.has_buckled_mobs())
+ return FALSE
+ if(L.mob_size > MOB_SIZE_TINY) // Tiny mobs are treated as items.
+ if(horizontal && L.density)
+ return FALSE
+ if(L.mob_size > max_mob_size)
+ return FALSE
+ var/mobs_stored = 0
+ for(var/mob/living/M in contents)
+ if(++mobs_stored >= mob_storage_capacity)
+ return FALSE
+ L.stop_pulling()
+
+ else if(istype(AM, /obj/structure/closet))
+ return FALSE
+
+ else if(istype(AM, /obj/effect))
+ return FALSE
+
+ else if(isobj(AM))
+ if((!allow_dense && AM.density) || AM.anchored || AM.has_buckled_mobs())
+ return FALSE
+ if(isitem(AM) && !HAS_TRAIT(AM, TRAIT_NODROP))
+ return TRUE
+ else if(!allow_objects && !istype(AM, /obj/effect/dummy/chameleon))
+ return FALSE
+ else
+ return FALSE
+
+ return TRUE
+
+/obj/structure/closet/proc/close(mob/living/user)
+ if(!opened || !can_close(user))
+ return FALSE
+ take_contents()
+ playsound(loc, close_sound, 15, 1, -3)
+ climb_time = initial(climb_time)
+ opened = FALSE
+ density = TRUE
+ update_icon()
+ return TRUE
+
+/obj/structure/closet/proc/toggle(mob/living/user)
+ if(opened)
+ return close(user)
+ else
+ return open(user)
+
+/obj/structure/closet/proc/bust_open()
+ welded = FALSE //applies to all lockers
+ locked = FALSE //applies to critter crates and secure lockers only
+ broken = TRUE //applies to secure lockers only
+ open()
+
+/obj/structure/closet/proc/handle_lock_addition(mob/user, obj/item/electronics/airlock/E)
+ add_fingerprint(user)
+ if(lock_in_use)
+ to_chat(user, "Wait for work on [src] to be done first!")
+ return
+ if(secure)
+ to_chat(user, "This locker already has a lock!")
+ return
+ if(broken)
+ to_chat(user, "Unscrew the broken lock first!")
+ return
+ if(!istype(E))
+ return
+ user.visible_message("[user] begins installing a lock on [src]...","You begin installing a lock on [src]...")
+ lock_in_use = TRUE
+ playsound(loc, 'sound/items/screwdriver.ogg', 50, 1)
+ if(!do_after(user, 60, target = src))
+ lock_in_use = FALSE
+ return
+ lock_in_use = FALSE
+ to_chat(user, "You finish the lock on [src]!")
+ E.forceMove(src)
+ lockerelectronics = E
+ req_access = E.accesses
+ secure = TRUE
+ update_icon()
+ return TRUE
+
+/obj/structure/closet/proc/handle_lock_removal(mob/user, obj/item/screwdriver/S)
+ if(lock_in_use)
+ to_chat(user, "Wait for work on [src] to be done first!")
+ return
+ if(locked)
+ to_chat(user, "Unlock it first!")
+ return
+ if(!secure)
+ to_chat(user, "[src] doesn't have a lock that you can remove!")
+ return
+ if(!istype(S))
+ return
+ var/brokenword = broken ? "broken " : null
+ user.visible_message("[user] begins removing the [brokenword]lock on [src]...","You begin removing the [brokenword]lock on [src]...")
+ playsound(loc, S.usesound, 50, 1)
+ lock_in_use = TRUE
+ if(!do_after(user, 100 * S.toolspeed, target = src))
+ lock_in_use = FALSE
+ return
+ to_chat(user, "You remove the [brokenword]lock from [src]!")
+ if(!QDELETED(lockerelectronics))
+ lockerelectronics.add_fingerprint(user)
+ lockerelectronics.forceMove(user.loc)
+ lockerelectronics = null
+ req_access = null
+ secure = FALSE
+ broken = FALSE
+ locked = FALSE
+ lock_in_use = FALSE
+ update_icon()
+ return TRUE
+
+
+/obj/structure/closet/deconstruct(disassembled = TRUE)
+ if(ispath(material_drop) && material_drop_amount && !(flags_1 & NODECONSTRUCT_1))
+ new material_drop(loc, material_drop_amount)
+ qdel(src)
+
+/obj/structure/closet/obj_break(damage_flag)
+ if(!broken && !(flags_1 & NODECONSTRUCT_1))
+ bust_open()
+
+/obj/structure/closet/attackby(obj/item/W, mob/user, params)
+ if(user in src)
+ return
+ if(src.tool_interact(W,user))
+ return 1 // No afterattack
+ else
+ return ..()
+
+/obj/structure/closet/proc/tool_interact(obj/item/W, mob/user)//returns TRUE if attackBy call shouldnt be continued (because tool was used/closet was of wrong type), FALSE if otherwise
+ . = TRUE
+ if(opened)
+ if(istype(W, cutting_tool))
+ if(istype(W, /obj/item/weldingtool))
+ if(!W.tool_start_check(user, amount=0))
+ return
+
+ to_chat(user, "You begin cutting \the [src] apart...")
+ if(W.use_tool(src, user, 40, volume=50))
+ if(eigen_teleport)
+ to_chat(user, "The unstable nature of \the [src] makes it impossible to cut!")
+ return
+ if(!opened)
+ return
+ user.visible_message("[user] slices apart \the [src].",
+ "You cut \the [src] apart with \the [W].",
+ "You hear welding.")
+ deconstruct(TRUE)
+ return
+ else // for example cardboard box is cut with wirecutters
+ user.visible_message("[user] cut apart \the [src].", \
+ "You cut \the [src] apart with \the [W].")
+ deconstruct(TRUE)
+ return
+ if(user.transferItemToLoc(W, drop_location())) // so we put in unlit welder too
+ return TRUE
+ else if(istype(W, /obj/item/electronics/airlock))
+ handle_lock_addition(user, W)
+ else if(istype(W, /obj/item/screwdriver))
+ handle_lock_removal(user, W)
+ else if(istype(W, /obj/item/weldingtool) && can_weld_shut)
+ if(!W.tool_start_check(user, amount=0))
+ return
+
+ to_chat(user, "You begin [welded ? "unwelding":"welding"] \the [src]...")
+ if(W.use_tool(src, user, 40, volume=50))
+ if(eigen_teleport)
+ to_chat(user, "The unstable nature of \the [src] makes it impossible to weld!")
+ return
+ if(opened)
+ return
+ welded = !welded
+ after_weld(welded)
+ user.visible_message("[user] [welded ? "welds shut" : "unwelds"] \the [src].",
+ "You [welded ? "weld" : "unwelded"] \the [src] with \the [W].",
+ "You hear welding.")
+ update_icon()
+ else if(istype(W, /obj/item/wrench) && anchorable)
+ if(isinspace() && !anchored)
+ return
+ setAnchored(!anchored)
+ W.play_tool_sound(src, 75)
+ user.visible_message("[user] [anchored ? "anchored" : "unanchored"] \the [src] [anchored ? "to" : "from"] the ground.", \
+ "You [anchored ? "anchored" : "unanchored"] \the [src] [anchored ? "to" : "from"] the ground.", \
+ "You hear a ratchet.")
+ else if(user.a_intent != INTENT_HARM && !(W.item_flags & NOBLUDGEON))
+ if(W.GetID() || !toggle(user))
+ togglelock(user)
+ else
+ return FALSE
+
+/obj/structure/closet/proc/after_weld(weld_state)
+ return
+
+/obj/structure/closet/MouseDrop_T(atom/movable/O, mob/living/user)
+ if(!istype(O) || O.anchored || istype(O, /obj/screen))
+ return
+ if(!istype(user) || user.incapacitated() || user.lying)
+ return
+ if(!Adjacent(user) || !user.Adjacent(O))
+ return
+ if(user == O) //try to climb onto it
+ return ..()
+ if(!opened)
+ return
+ if(!isturf(O.loc))
+ return
+
+ var/actuallyismob = 0
+ if(isliving(O))
+ actuallyismob = 1
+ else if(!isitem(O))
+ return
+ var/turf/T = get_turf(src)
+ var/list/targets = list(O, src)
+ add_fingerprint(user)
+ user.visible_message("[user] [actuallyismob ? "tries to ":""]stuff [O] into [src].", \
+ "You [actuallyismob ? "try to ":""]stuff [O] into [src].", \
+ "You hear clanging.")
+ if(actuallyismob)
+ if(do_after_mob(user, targets, 40))
+ user.visible_message("[user] stuffs [O] into [src].", \
+ "You stuff [O] into [src].", \
+ "You hear a loud metal bang.")
+ var/mob/living/L = O
+ if(!issilicon(L))
+ L.Knockdown(40)
+ O.forceMove(T)
+ close()
+ else
+ O.forceMove(T)
+ return 1
+
+/obj/structure/closet/relaymove(mob/user)
+ if(user.stat || !isturf(loc) || !isliving(user))
+ return
+ if(locked)
+ if(message_cooldown <= world.time)
+ message_cooldown = world.time + 50
+ to_chat(user, "[src]'s door won't budge!")
+ return
+ container_resist(user)
+
+/obj/structure/closet/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
+ if(user.lying && get_dist(src, user) > 0)
+ return
+
+ if(!toggle(user))
+ togglelock(user)
+
+/obj/structure/closet/attack_paw(mob/user)
+ return attack_hand(user)
+
+/obj/structure/closet/attack_robot(mob/user)
+ if(user.Adjacent(src))
+ return attack_hand(user)
+
+// tk grab then use on self
+/obj/structure/closet/attack_self_tk(mob/user)
+ return attack_hand(user)
+
+/obj/structure/closet/verb/verb_toggleopen()
+ set src in oview(1)
+ set category = "Object"
+ set name = "Toggle Open"
+
+ if(!usr.canmove || usr.stat || usr.restrained())
+ return
+
+ if(iscarbon(usr) || issilicon(usr) || isdrone(usr))
+ return attack_hand(usr)
+ else
+ to_chat(usr, "This mob type can't use this verb.")
+
+// Objects that try to exit a locker by stepping were doing so successfully,
+// and due to an oversight in turf/Enter() were going through walls. That
+// should be independently resolved, but this is also an interesting twist.
+/obj/structure/closet/Exit(atom/movable/AM)
+ open()
+ if(AM.loc == src)
+ return 0
+ return 1
+
+/obj/structure/closet/container_resist(mob/living/user)
+ if(opened)
+ return
+ if(ismovableatom(loc))
+ user.changeNext_move(CLICK_CD_BREAKOUT)
+ user.last_special = world.time + CLICK_CD_BREAKOUT
+ var/atom/movable/AM = loc
+ AM.relay_container_resist(user, src)
+ return
+ if(!welded && !locked)
+ open()
+ return
+
+ //okay, so the closet is either welded or locked... resist!!!
+ user.changeNext_move(CLICK_CD_BREAKOUT)
+ user.last_special = world.time + CLICK_CD_BREAKOUT
+ user.visible_message("[src] begins to shake violently!", \
+ "You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)", \
+ "You hear banging from [src].")
+ if(do_after(user,(breakout_time), target = src))
+ if(!user || user.stat != CONSCIOUS || user.loc != src || opened || (!locked && !welded) )
+ return
+ //we check after a while whether there is a point of resisting anymore and whether the user is capable of resisting
+ user.visible_message("[user] successfully broke out of [src]!",
+ "You successfully break out of [src]!")
+ bust_open()
+ else
+ if(user.loc == src) //so we don't get the message if we resisted multiple times and succeeded.
+ to_chat(user, "You fail to break out of [src]!")
+
+/obj/structure/closet/AltClick(mob/user)
+ ..()
+ if(!user.canUseTopic(src, be_close=TRUE) || !isturf(loc))
+ to_chat(user, "You can't do that right now!")
+ return
+ togglelock(user)
+
+/obj/structure/closet/CtrlShiftClick(mob/living/user)
+ if(!HAS_TRAIT(user, TRAIT_SKITTISH))
+ return ..()
+ if(!user.canUseTopic(src) || !isturf(user.loc))
+ return
+ dive_into(user)
+
+/obj/structure/closet/emag_act(mob/user)
+ . = ..()
+ if(!secure || broken)
+ return
+ user.visible_message("Sparks fly from [src]!",
+ "You scramble [src]'s lock, breaking it open!",
+ "You hear a faint electrical spark.")
+ playsound(src, "sparks", 50, 1)
+ broken = TRUE
+ locked = FALSE
+ if(!QDELETED(lockerelectronics))
+ QDEL_NULL(lockerelectronics)
+ update_icon()
+
+/obj/structure/closet/get_remote_view_fullscreens(mob/user)
+ if(user.stat == DEAD || !(user.sight & (SEEOBJS|SEEMOBS)))
+ user.overlay_fullscreen("remote_view", /obj/screen/fullscreen/impaired, 1)
+
+/obj/structure/closet/emp_act(severity)
+ . = ..()
+ if(. & EMP_PROTECT_SELF)
+ return
+ if (!(. & EMP_PROTECT_CONTENTS))
+ for(var/obj/O in src)
+ O.emp_act(severity)
+ if(!secure || broken)
+ return ..()
+ if(prob(50 / severity))
+ locked = !locked
+ update_icon()
+ if(prob(20 / severity) && !opened)
+ if(!locked)
+ open()
+ else
+ req_access = list()
+ req_access += pick(get_all_accesses())
+ if(!QDELETED(lockerelectronics))
+ lockerelectronics.accesses = req_access
+
+/obj/structure/closet/contents_explosion(severity, target)
+ for(var/atom/A in contents)
+ A.ex_act(severity, target)
+ CHECK_TICK
+
+/obj/structure/closet/singularity_act()
+ dump_contents()
+ ..()
+
+/obj/structure/closet/AllowDrop()
+ return TRUE
+
+
+/obj/structure/closet/return_temperature()
+ return
+
+/obj/structure/closet/proc/dive_into(mob/living/user)
+ var/turf/T1 = get_turf(user)
+ var/turf/T2 = get_turf(src)
+ if(!opened)
+ if(locked)
+ togglelock(user, TRUE)
+ if(!open(user))
+ to_chat(user, "It won't budge!")
+ return
+ step_towards(user, T2)
+ T1 = get_turf(user)
+ if(T1 == T2)
+ user.resting = TRUE //so people can jump into crates without slamming the lid on their head
+ if(!close(user))
+ to_chat(user, "You can't get [src] to close!")
+ user.resting = FALSE
+ return
+ user.resting = FALSE
+ togglelock(user)
+ T1.visible_message("[user] dives into [src]!")
diff --git a/code/modules/VR/vr_sleeper.dm b/code/modules/VR/vr_sleeper.dm
index bfbf6b5b79..89e9c33ecc 100644
--- a/code/modules/VR/vr_sleeper.dm
+++ b/code/modules/VR/vr_sleeper.dm
@@ -54,12 +54,16 @@
only_current_user_can_interact = TRUE
/obj/machinery/vr_sleeper/hugbox/emag_act(mob/user)
- return
+ return SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT)
/obj/machinery/vr_sleeper/emag_act(mob/user)
+ . = ..()
+ if(you_die_in_the_game_you_die_for_real)
+ return
you_die_in_the_game_you_die_for_real = TRUE
sparks.start()
addtimer(CALLBACK(src, .proc/emagNotify), 150)
+ return TRUE
/obj/machinery/vr_sleeper/update_icon()
icon_state = "[initial(icon_state)][state_open ? "-open" : ""]"
diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm
index 3bf54a1178..6ca25c0d80 100644
--- a/code/modules/atmospherics/machinery/airalarm.dm
+++ b/code/modules/atmospherics/machinery/airalarm.dm
@@ -1,880 +1,882 @@
-/datum/tlv
- var/min2
- var/min1
- var/max1
- var/max2
-
-/datum/tlv/New(min2 as num, min1 as num, max1 as num, max2 as num)
- if(min2) src.min2 = min2
- if(min1) src.min1 = min1
- if(max1) src.max1 = max1
- if(max2) src.max2 = max2
-
-/datum/tlv/proc/get_danger_level(val as num)
- if(max2 != -1 && val >= max2)
- return 2
- if(min2 != -1 && val <= min2)
- return 2
- if(max1 != -1 && val >= max1)
- return 1
- if(min1 != -1 && val <= min1)
- return 1
- return 0
-
-/datum/tlv/no_checks
- min2 = -1
- min1 = -1
- max1 = -1
- max2 = -1
-
-/datum/tlv/dangerous
- min2 = -1
- min1 = -1
- max1 = 0.2
- max2 = 0.5
-
-/obj/item/electronics/airalarm
- name = "air alarm electronics"
- icon_state = "airalarm_electronics"
-
-/obj/item/wallframe/airalarm
- name = "air alarm frame"
- desc = "Used for building Air Alarms."
- icon = 'icons/obj/monitors.dmi'
- icon_state = "alarm_bitem"
- result_path = /obj/machinery/airalarm
-
-#define AALARM_MODE_SCRUBBING 1
-#define AALARM_MODE_VENTING 2 //makes draught
-#define AALARM_MODE_PANIC 3 //like siphon, but stronger (enables widenet)
-#define AALARM_MODE_REPLACEMENT 4 //sucks off all air, then refill and swithes to scrubbing
-#define AALARM_MODE_OFF 5
-#define AALARM_MODE_FLOOD 6 //Emagged mode; turns off scrubbers and pressure checks on vents
-#define AALARM_MODE_SIPHON 7 //Scrubbers suck air
-#define AALARM_MODE_CONTAMINATED 8 //Turns on all filtering and widenet scrubbing.
-#define AALARM_MODE_REFILL 9 //just like normal, but with triple the air output
-
-#define AALARM_REPORT_TIMEOUT 100
-
-#define AALARM_OVERLAY_OFF "alarm_off"
-#define AALARM_OVERLAY_GREEN "alarm_green"
-#define AALARM_OVERLAY_WARN "alarm_amber"
-#define AALARM_OVERLAY_DANGER "alarm_red"
-
-/obj/machinery/airalarm
- name = "air alarm"
- desc = "A machine that monitors atmosphere levels. Goes off if the area is dangerous."
- icon = 'icons/obj/monitors.dmi'
- icon_state = "alarm0"
- use_power = IDLE_POWER_USE
- idle_power_usage = 4
- active_power_usage = 8
- power_channel = ENVIRON
- req_access = list(ACCESS_ATMOSPHERICS)
- max_integrity = 250
- integrity_failure = 80
- armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 90, "acid" = 30)
- resistance_flags = FIRE_PROOF
-
- var/danger_level = 0
- var/mode = AALARM_MODE_SCRUBBING
-
- var/locked = TRUE
- var/aidisabled = 0
- var/shorted = 0
- var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone
- var/brightness_on = 1
-
- var/frequency = FREQ_ATMOS_CONTROL
- var/alarm_frequency = FREQ_ATMOS_ALARMS
- var/datum/radio_frequency/radio_connection
-
- var/list/TLV = list( // Breathable air.
- "pressure" = new/datum/tlv(ONE_ATMOSPHERE * 0.8, ONE_ATMOSPHERE* 0.9, ONE_ATMOSPHERE * 1.1, ONE_ATMOSPHERE * 1.2), // kPa
- "temperature" = new/datum/tlv(T0C, T0C+10, T0C+40, T0C+66),
- /datum/gas/oxygen = new/datum/tlv(16, 19, 135, 140), // Partial pressure, kpa
- /datum/gas/nitrogen = new/datum/tlv(-1, -1, 1000, 1000),
- /datum/gas/carbon_dioxide = new/datum/tlv(-1, -1, 5, 10),
- /datum/gas/miasma = new/datum/tlv/(-1, -1, 2, 5),
- /datum/gas/plasma = new/datum/tlv/dangerous,
- /datum/gas/nitrous_oxide = new/datum/tlv/dangerous,
- /datum/gas/bz = new/datum/tlv/dangerous,
- /datum/gas/hypernoblium = new/datum/tlv(-1, -1, 1000, 1000), // Hyper-Noblium is inert and nontoxic
- /datum/gas/water_vapor = new/datum/tlv/dangerous,
- /datum/gas/tritium = new/datum/tlv/dangerous,
- /datum/gas/stimulum = new/datum/tlv(-1, -1, 1000, 1000), // Stimulum has only positive effects
- /datum/gas/nitryl = new/datum/tlv/dangerous,
- /datum/gas/pluoxium = new/datum/tlv(-1, -1, 1000, 1000) // Unlike oxygen, pluoxium does not fuel plasma/tritium fires
- )
-
-/obj/machinery/airalarm/server // No checks here.
- TLV = list(
- "pressure" = new/datum/tlv/no_checks,
- "temperature" = new/datum/tlv/no_checks,
- /datum/gas/oxygen = new/datum/tlv/no_checks,
- /datum/gas/nitrogen = new/datum/tlv/no_checks,
- /datum/gas/carbon_dioxide = new/datum/tlv/no_checks,
- /datum/gas/miasma = new/datum/tlv/no_checks,
- /datum/gas/plasma = new/datum/tlv/no_checks,
- /datum/gas/nitrous_oxide = new/datum/tlv/no_checks,
- /datum/gas/bz = new/datum/tlv/no_checks,
- /datum/gas/hypernoblium = new/datum/tlv/no_checks,
- /datum/gas/water_vapor = new/datum/tlv/no_checks,
- /datum/gas/tritium = new/datum/tlv/no_checks,
- /datum/gas/stimulum = new/datum/tlv/no_checks,
- /datum/gas/nitryl = new/datum/tlv/no_checks,
- /datum/gas/pluoxium = new/datum/tlv/no_checks
- )
-
-/obj/machinery/airalarm/kitchen_cold_room // Copypasta: to check temperatures.
- TLV = list(
- "pressure" = new/datum/tlv(ONE_ATMOSPHERE * 0.8, ONE_ATMOSPHERE* 0.9, ONE_ATMOSPHERE * 1.1, ONE_ATMOSPHERE * 1.2), // kPa
- "temperature" = new/datum/tlv(T0C-73.15, T0C-63.15, T0C, T0C+10),
- /datum/gas/oxygen = new/datum/tlv(16, 19, 135, 140), // Partial pressure, kpa
- /datum/gas/nitrogen = new/datum/tlv(-1, -1, 1000, 1000),
- /datum/gas/carbon_dioxide = new/datum/tlv(-1, -1, 5, 10),
- /datum/gas/miasma = new/datum/tlv/(-1, -1, 2, 5),
- /datum/gas/plasma = new/datum/tlv/dangerous,
- /datum/gas/nitrous_oxide = new/datum/tlv/dangerous,
- /datum/gas/bz = new/datum/tlv/dangerous,
- /datum/gas/hypernoblium = new/datum/tlv(-1, -1, 1000, 1000), // Hyper-Noblium is inert and nontoxic
- /datum/gas/water_vapor = new/datum/tlv/dangerous,
- /datum/gas/tritium = new/datum/tlv/dangerous,
- /datum/gas/stimulum = new/datum/tlv(-1, -1, 1000, 1000), // Stimulum has only positive effects
- /datum/gas/nitryl = new/datum/tlv/dangerous,
- /datum/gas/pluoxium = new/datum/tlv(-1, -1, 1000, 1000) // Unlike oxygen, pluoxium does not fuel plasma/tritium fires
- )
-
-/obj/machinery/airalarm/unlocked
- locked = FALSE
-
-/obj/machinery/airalarm/engine
- name = "engine air alarm"
- locked = FALSE
- req_access = null
- req_one_access = list(ACCESS_ATMOSPHERICS, ACCESS_ENGINE)
-
-/obj/machinery/airalarm/mixingchamber
- name = "chamber air alarm"
- locked = FALSE
- req_access = null
- req_one_access = list(ACCESS_ATMOSPHERICS, ACCESS_TOX, ACCESS_TOX_STORAGE)
-
-/obj/machinery/airalarm/all_access
- name = "all-access air alarm"
- desc = "This particular atmos control unit appears to have no access restrictions."
- locked = FALSE
- req_access = null
- req_one_access = null
-
-/obj/machinery/airalarm/syndicate //general syndicate access
- req_access = list(ACCESS_SYNDICATE)
-
-/obj/machinery/airalarm/directional/north //Pixel offsets get overwritten on New()
- dir = SOUTH
- pixel_y = 24
-
-/obj/machinery/airalarm/directional/south
- dir = NORTH
- pixel_y = -24
-
-/obj/machinery/airalarm/directional/east
- dir = WEST
- pixel_x = 24
-
-/obj/machinery/airalarm/directional/west
- dir = EAST
- pixel_x = -24
-
-//all air alarms in area are connected via magic
-/area
- var/list/air_vent_names = list()
- var/list/air_scrub_names = list()
- var/list/air_vent_info = list()
- var/list/air_scrub_info = list()
-
-/obj/machinery/airalarm/Initialize(mapload, ndir, nbuild)
- . = ..()
- wires = new /datum/wires/airalarm(src)
-
- if(ndir)
- setDir(ndir)
-
- if(nbuild)
- buildstage = 0
- panel_open = TRUE
- pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24)
- pixel_y = (dir & 3)? (dir == 1 ? -24 : 24) : 0
-
- if(name == initial(name))
- name = "[get_area_name(src)] Air Alarm"
-
- power_change()
- set_frequency(frequency)
-
-/obj/machinery/airalarm/Destroy()
- SSradio.remove_object(src, frequency)
- qdel(wires)
- wires = null
- return ..()
-
-/obj/machinery/airalarm/examine(mob/user)
- . = ..()
- switch(buildstage)
- if(0)
- to_chat(user, "It is missing air alarm electronics.")
- if(1)
- to_chat(user, "It is missing wiring.")
- if(2)
- to_chat(user, "Alt-click to [locked ? "unlock" : "lock"] the interface.")
-
-/obj/machinery/airalarm/ui_status(mob/user)
- if(user.has_unlimited_silicon_privilege && aidisabled)
- to_chat(user, "AI control has been disabled.")
- else if(!shorted)
- return ..()
- return UI_CLOSE
-
-/obj/machinery/airalarm/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
- datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "airalarm", name, 440, 650, master_ui, state)
- ui.open()
-
-/obj/machinery/airalarm/ui_data(mob/user)
- var/data = list(
- "locked" = locked,
- "siliconUser" = user.has_unlimited_silicon_privilege,
- "emagged" = (obj_flags & EMAGGED ? 1 : 0),
- "danger_level" = danger_level,
- )
-
- var/area/A = get_area(src)
- data["atmos_alarm"] = A.atmosalm
- data["fire_alarm"] = A.fire
-
- var/turf/T = get_turf(src)
- var/datum/gas_mixture/environment = T.return_air()
- var/datum/tlv/cur_tlv
-
- data["environment_data"] = list()
- var/pressure = environment.return_pressure()
- cur_tlv = TLV["pressure"]
- data["environment_data"] += list(list(
- "name" = "Pressure",
- "value" = pressure,
- "unit" = "kPa",
- "danger_level" = cur_tlv.get_danger_level(pressure)
- ))
- var/temperature = environment.temperature
- cur_tlv = TLV["temperature"]
- data["environment_data"] += list(list(
- "name" = "Temperature",
- "value" = temperature,
- "unit" = "K ([round(temperature - T0C, 0.1)]C)",
- "danger_level" = cur_tlv.get_danger_level(temperature)
- ))
- var/total_moles = environment.total_moles()
- var/partial_pressure = R_IDEAL_GAS_EQUATION * environment.temperature / environment.volume
- for(var/gas_id in environment.gases)
- if(!(gas_id in TLV)) // We're not interested in this gas, it seems.
- continue
- cur_tlv = TLV[gas_id]
- data["environment_data"] += list(list(
- "name" = GLOB.meta_gas_names[gas_id],
- "value" = environment.gases[gas_id] / total_moles * 100,
- "unit" = "%",
- "danger_level" = cur_tlv.get_danger_level(environment.gases[gas_id] * partial_pressure)
- ))
-
- if(!locked || user.has_unlimited_silicon_privilege)
- data["vents"] = list()
- for(var/id_tag in A.air_vent_names)
- var/long_name = A.air_vent_names[id_tag]
- var/list/info = A.air_vent_info[id_tag]
- if(!info || info["frequency"] != frequency)
- continue
- data["vents"] += list(list(
- "id_tag" = id_tag,
- "long_name" = sanitize(long_name),
- "power" = info["power"],
- "checks" = info["checks"],
- "excheck" = info["checks"]&1,
- "incheck" = info["checks"]&2,
- "direction" = info["direction"],
- "external" = info["external"],
- "internal" = info["internal"],
- "extdefault"= (info["external"] == ONE_ATMOSPHERE),
- "intdefault"= (info["internal"] == 0)
- ))
- data["scrubbers"] = list()
- for(var/id_tag in A.air_scrub_names)
- var/long_name = A.air_scrub_names[id_tag]
- var/list/info = A.air_scrub_info[id_tag]
- if(!info || info["frequency"] != frequency)
- continue
- data["scrubbers"] += list(list(
- "id_tag" = id_tag,
- "long_name" = sanitize(long_name),
- "power" = info["power"],
- "scrubbing" = info["scrubbing"],
- "widenet" = info["widenet"],
- "filter_types" = info["filter_types"]
- ))
- data["mode"] = mode
- data["modes"] = list()
- data["modes"] += list(list("name" = "Filtering - Scrubs out contaminants", "mode" = AALARM_MODE_SCRUBBING, "selected" = mode == AALARM_MODE_SCRUBBING, "danger" = 0))
- data["modes"] += list(list("name" = "Contaminated - Scrubs out ALL contaminants quickly","mode" = AALARM_MODE_CONTAMINATED, "selected" = mode == AALARM_MODE_CONTAMINATED, "danger" = 0))
- data["modes"] += list(list("name" = "Draught - Siphons out air while replacing", "mode" = AALARM_MODE_VENTING, "selected" = mode == AALARM_MODE_VENTING, "danger" = 0))
- data["modes"] += list(list("name" = "Refill - Triple vent output", "mode" = AALARM_MODE_REFILL, "selected" = mode == AALARM_MODE_REFILL, "danger" = 1))
- data["modes"] += list(list("name" = "Cycle - Siphons air before replacing", "mode" = AALARM_MODE_REPLACEMENT, "selected" = mode == AALARM_MODE_REPLACEMENT, "danger" = 1))
- data["modes"] += list(list("name" = "Siphon - Siphons air out of the room", "mode" = AALARM_MODE_SIPHON, "selected" = mode == AALARM_MODE_SIPHON, "danger" = 1))
- data["modes"] += list(list("name" = "Panic Siphon - Siphons air out of the room quickly","mode" = AALARM_MODE_PANIC, "selected" = mode == AALARM_MODE_PANIC, "danger" = 1))
- data["modes"] += list(list("name" = "Off - Shuts off vents and scrubbers", "mode" = AALARM_MODE_OFF, "selected" = mode == AALARM_MODE_OFF, "danger" = 0))
- if(obj_flags & EMAGGED)
- data["modes"] += list(list("name" = "Flood - Shuts off scrubbers and opens vents", "mode" = AALARM_MODE_FLOOD, "selected" = mode == AALARM_MODE_FLOOD, "danger" = 1))
-
- var/datum/tlv/selected
- var/list/thresholds = list()
-
- selected = TLV["pressure"]
- thresholds += list(list("name" = "Pressure", "settings" = list()))
- thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "min2", "selected" = selected.min2))
- thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "min1", "selected" = selected.min1))
- thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "max1", "selected" = selected.max1))
- thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "max2", "selected" = selected.max2))
-
- selected = TLV["temperature"]
- thresholds += list(list("name" = "Temperature", "settings" = list()))
- thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "min2", "selected" = selected.min2))
- thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "min1", "selected" = selected.min1))
- thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "max1", "selected" = selected.max1))
- thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "max2", "selected" = selected.max2))
-
- for(var/gas_id in GLOB.meta_gas_names)
- if(!(gas_id in TLV)) // We're not interested in this gas, it seems.
- continue
- selected = TLV[gas_id]
- thresholds += list(list("name" = GLOB.meta_gas_names[gas_id], "settings" = list()))
- thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "min2", "selected" = selected.min2))
- thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "min1", "selected" = selected.min1))
- thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "max1", "selected" = selected.max1))
- thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "max2", "selected" = selected.max2))
-
- data["thresholds"] = thresholds
- return data
-
-/obj/machinery/airalarm/ui_act(action, params)
- if(..() || buildstage != 2)
- return
- if((locked && !usr.has_unlimited_silicon_privilege) || (usr.has_unlimited_silicon_privilege && aidisabled))
- return
- var/device_id = params["id_tag"]
- switch(action)
- if("lock")
- if(usr.has_unlimited_silicon_privilege && !wires.is_cut(WIRE_IDSCAN))
- locked = !locked
- . = TRUE
- if("power", "toggle_filter", "widenet", "scrubbing")
- send_signal(device_id, list("[action]" = params["val"]), usr)
- . = TRUE
- if("excheck")
- send_signal(device_id, list("checks" = text2num(params["val"])^1), usr)
- . = TRUE
- if("incheck")
- send_signal(device_id, list("checks" = text2num(params["val"])^2), usr)
- . = TRUE
- if("set_external_pressure", "set_internal_pressure")
- var/area/A = get_area(src)
- var/target = input("New target pressure:", name, A.air_vent_info[device_id][(action == "set_external_pressure" ? "external" : "internal")]) as num|null
- if(!isnull(target) && !..())
- send_signal(device_id, list("[action]" = target), usr)
- . = TRUE
- if("reset_external_pressure")
- send_signal(device_id, list("reset_external_pressure"), usr)
- . = TRUE
- if("reset_internal_pressure")
- send_signal(device_id, list("reset_internal_pressure"), usr)
- . = TRUE
- if("threshold")
- var/env = params["env"]
- if(text2path(env))
- env = text2path(env)
-
- var/name = params["var"]
- var/datum/tlv/tlv = TLV[env]
- if(isnull(tlv))
- return
- var/value = input("New [name] for [env]:", name, tlv.vars[name]) as num|null
- if(!isnull(value) && !..())
- if(value < 0)
- tlv.vars[name] = -1
- else
- tlv.vars[name] = round(value, 0.01)
- investigate_log(" treshold value for [env]:[name] was set to [value] by [key_name(usr)]",INVESTIGATE_ATMOS)
- . = TRUE
- if("mode")
- mode = text2num(params["mode"])
- investigate_log("was turned to [get_mode_name(mode)] mode by [key_name(usr)]",INVESTIGATE_ATMOS)
- apply_mode()
- . = TRUE
- if("alarm")
- var/area/A = get_area(src)
- if(A.atmosalert(2, src))
- post_alert(2)
- . = TRUE
- if("reset")
- var/area/A = get_area(src)
- if(A.atmosalert(0, src))
- post_alert(0)
- . = TRUE
- update_icon()
-
-/obj/machinery/airalarm/proc/reset(wire)
- switch(wire)
- if(WIRE_POWER)
- if(!wires.is_cut(WIRE_POWER))
- shorted = FALSE
- update_icon()
- if(WIRE_AI)
- if(!wires.is_cut(WIRE_AI))
- aidisabled = FALSE
-
-
-/obj/machinery/airalarm/proc/shock(mob/user, prb)
- if((stat & (NOPOWER))) // unpowered, no shock
- return 0
- if(!prob(prb))
- return 0 //you lucked out, no shock for you
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
- s.set_up(5, 1, src)
- s.start() //sparks always.
- if (electrocute_mob(user, get_area(src), src, 1, TRUE))
- return 1
- else
- return 0
-
-/obj/machinery/airalarm/proc/refresh_all()
- var/area/A = get_area(src)
- for(var/id_tag in A.air_vent_names)
- var/list/I = A.air_vent_info[id_tag]
- if(I && I["timestamp"] + AALARM_REPORT_TIMEOUT / 2 > world.time)
- continue
- send_signal(id_tag, list("status"))
- for(var/id_tag in A.air_scrub_names)
- var/list/I = A.air_scrub_info[id_tag]
- if(I && I["timestamp"] + AALARM_REPORT_TIMEOUT / 2 > world.time)
- continue
- send_signal(id_tag, list("status"))
-
-/obj/machinery/airalarm/proc/set_frequency(new_frequency)
- SSradio.remove_object(src, frequency)
- frequency = new_frequency
- radio_connection = SSradio.add_object(src, frequency, RADIO_TO_AIRALARM)
-
-/obj/machinery/airalarm/proc/send_signal(target, list/command, mob/user)//sends signal 'command' to 'target'. Returns 0 if no radio connection, 1 otherwise
- if(!radio_connection)
- return 0
-
- var/datum/signal/signal = new(command)
- signal.data["tag"] = target
- signal.data["sigtype"] = "command"
- signal.data["user"] = user
- radio_connection.post_signal(src, signal, RADIO_FROM_AIRALARM)
-
- return 1
-
-/obj/machinery/airalarm/proc/get_mode_name(mode_value)
- switch(mode_value)
- if(AALARM_MODE_SCRUBBING)
- return "Filtering"
- if(AALARM_MODE_CONTAMINATED)
- return "Contaminated"
- if(AALARM_MODE_VENTING)
- return "Draught"
- if(AALARM_MODE_REFILL)
- return "Refill"
- if(AALARM_MODE_PANIC)
- return "Panic Siphon"
- if(AALARM_MODE_REPLACEMENT)
- return "Cycle"
- if(AALARM_MODE_SIPHON)
- return "Siphon"
- if(AALARM_MODE_OFF)
- return "Off"
- if(AALARM_MODE_FLOOD)
- return "Flood"
-
-/obj/machinery/airalarm/proc/apply_mode()
- var/area/A = get_area(src)
- switch(mode)
- if(AALARM_MODE_SCRUBBING)
- for(var/device_id in A.air_scrub_names)
- send_signal(device_id, list(
- "power" = 1,
- "set_filters" = list(/datum/gas/carbon_dioxide, /datum/gas/miasma),
- "scrubbing" = 1,
- "widenet" = 0,
- ))
- for(var/device_id in A.air_vent_names)
- send_signal(device_id, list(
- "power" = 1,
- "checks" = 1,
- "set_external_pressure" = ONE_ATMOSPHERE
- ))
- if(AALARM_MODE_CONTAMINATED)
- for(var/device_id in A.air_scrub_names)
- send_signal(device_id, list(
- "power" = 1,
- "set_filters" = list(
- /datum/gas/carbon_dioxide,
- /datum/gas/miasma,
- /datum/gas/plasma,
- /datum/gas/water_vapor,
- /datum/gas/hypernoblium,
- /datum/gas/nitrous_oxide,
- /datum/gas/nitryl,
- /datum/gas/tritium,
- /datum/gas/bz,
- /datum/gas/stimulum,
- /datum/gas/pluoxium
- ),
- "scrubbing" = 1,
- "widenet" = 1,
- ))
- for(var/device_id in A.air_vent_names)
- send_signal(device_id, list(
- "power" = 1,
- "checks" = 1,
- "set_external_pressure" = ONE_ATMOSPHERE
- ))
- if(AALARM_MODE_VENTING)
- for(var/device_id in A.air_scrub_names)
- send_signal(device_id, list(
- "power" = 1,
- "widenet" = 0,
- "scrubbing" = 0
- ))
- for(var/device_id in A.air_vent_names)
- send_signal(device_id, list(
- "power" = 1,
- "checks" = 1,
- "set_external_pressure" = ONE_ATMOSPHERE*2
- ))
- if(AALARM_MODE_REFILL)
- for(var/device_id in A.air_scrub_names)
- send_signal(device_id, list(
- "power" = 1,
- "set_filters" = list(/datum/gas/carbon_dioxide, /datum/gas/miasma),
- "scrubbing" = 1,
- "widenet" = 0,
- ))
- for(var/device_id in A.air_vent_names)
- send_signal(device_id, list(
- "power" = 1,
- "checks" = 1,
- "set_external_pressure" = ONE_ATMOSPHERE * 3
- ))
- if(AALARM_MODE_PANIC,
- AALARM_MODE_REPLACEMENT)
- for(var/device_id in A.air_scrub_names)
- send_signal(device_id, list(
- "power" = 1,
- "widenet" = 1,
- "scrubbing" = 0
- ))
- for(var/device_id in A.air_vent_names)
- send_signal(device_id, list(
- "power" = 0
- ))
- if(AALARM_MODE_SIPHON)
- for(var/device_id in A.air_scrub_names)
- send_signal(device_id, list(
- "power" = 1,
- "widenet" = 0,
- "scrubbing" = 0
- ))
- for(var/device_id in A.air_vent_names)
- send_signal(device_id, list(
- "power" = 0
- ))
-
- if(AALARM_MODE_OFF)
- for(var/device_id in A.air_scrub_names)
- send_signal(device_id, list(
- "power" = 0
- ))
- for(var/device_id in A.air_vent_names)
- send_signal(device_id, list(
- "power" = 0
- ))
- if(AALARM_MODE_FLOOD)
- for(var/device_id in A.air_scrub_names)
- send_signal(device_id, list(
- "power" = 0
- ))
- for(var/device_id in A.air_vent_names)
- send_signal(device_id, list(
- "power" = 1,
- "checks" = 2,
- "set_internal_pressure" = 0
- ))
-
-/obj/machinery/airalarm/update_icon()
- set_light(0)
- cut_overlays()
- SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays)
- if(stat & NOPOWER)
- icon_state = "alarm0"
- return
-
- if(stat & BROKEN)
- icon_state = "alarmx"
- return
-
- if(panel_open)
- switch(buildstage)
- if(2)
- icon_state = "alarmx"
- if(1)
- icon_state = "alarm_b2"
- if(0)
- icon_state = "alarm_b1"
- return
-
- icon_state = "alarm1"
- var/overlay_state = AALARM_OVERLAY_OFF
- var/area/A = get_area(src)
- switch(max(danger_level, A.atmosalm))
- if(0)
- add_overlay(AALARM_OVERLAY_GREEN)
- overlay_state = AALARM_OVERLAY_GREEN
- light_color = LIGHT_COLOR_GREEN
- set_light(brightness_on)
- if(1)
- add_overlay(AALARM_OVERLAY_WARN)
- overlay_state = AALARM_OVERLAY_WARN
- light_color = LIGHT_COLOR_LAVA
- set_light(brightness_on)
- if(2)
- add_overlay(AALARM_OVERLAY_DANGER)
- overlay_state = AALARM_OVERLAY_DANGER
- light_color = LIGHT_COLOR_RED
- set_light(brightness_on)
-
- SSvis_overlays.add_vis_overlay(src, icon, overlay_state, ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir)
- update_light()
-
-/obj/machinery/airalarm/process()
- if((stat & (NOPOWER|BROKEN)) || shorted)
- return
-
- var/turf/location = get_turf(src)
- if(!location)
- return
-
- var/datum/tlv/cur_tlv
-
- var/datum/gas_mixture/environment = location.return_air()
- var/list/env_gases = environment.gases
- var/partial_pressure = R_IDEAL_GAS_EQUATION * environment.temperature / environment.volume
-
- cur_tlv = TLV["pressure"]
- var/environment_pressure = environment.return_pressure()
- var/pressure_dangerlevel = cur_tlv.get_danger_level(environment_pressure)
-
- cur_tlv = TLV["temperature"]
- var/temperature_dangerlevel = cur_tlv.get_danger_level(environment.temperature)
-
- var/gas_dangerlevel = 0
- for(var/gas_id in env_gases)
- if(!(gas_id in TLV)) // We're not interested in this gas, it seems.
- continue
- cur_tlv = TLV[gas_id]
- gas_dangerlevel = max(gas_dangerlevel, cur_tlv.get_danger_level(env_gases[gas_id] * partial_pressure))
-
- GAS_GARBAGE_COLLECT(environment.gases)
-
- var/old_danger_level = danger_level
- danger_level = max(pressure_dangerlevel, temperature_dangerlevel, gas_dangerlevel)
-
- if(old_danger_level != danger_level)
- apply_danger_level()
- if(mode == AALARM_MODE_REPLACEMENT && environment_pressure < ONE_ATMOSPHERE * 0.05)
- mode = AALARM_MODE_SCRUBBING
- apply_mode()
-
- return
-
-
-/obj/machinery/airalarm/proc/post_alert(alert_level)
- var/datum/radio_frequency/frequency = SSradio.return_frequency(alarm_frequency)
-
- if(!frequency)
- return
-
- var/datum/signal/alert_signal = new(list(
- "zone" = get_area_name(src),
- "type" = "Atmospheric"
- ))
- if(alert_level==2)
- alert_signal.data["alert"] = "severe"
- else if (alert_level==1)
- alert_signal.data["alert"] = "minor"
- else if (alert_level==0)
- alert_signal.data["alert"] = "clear"
-
- frequency.post_signal(src, alert_signal, range = -1)
-
-/obj/machinery/airalarm/proc/apply_danger_level()
- var/area/A = get_area(src)
-
- var/new_area_danger_level = 0
- for(var/obj/machinery/airalarm/AA in A)
- if (!(AA.stat & (NOPOWER|BROKEN)) && !AA.shorted)
- new_area_danger_level = max(new_area_danger_level,AA.danger_level)
- if(A.atmosalert(new_area_danger_level,src)) //if area was in normal state or if area was in alert state
- post_alert(new_area_danger_level)
-
- update_icon()
-
-/obj/machinery/airalarm/attackby(obj/item/W, mob/user, params)
- switch(buildstage)
- if(2)
- if(istype(W, /obj/item/wirecutters) && panel_open && wires.is_all_cut())
- W.play_tool_sound(src)
- to_chat(user, "You cut the final wires.")
- new /obj/item/stack/cable_coil(loc, 5)
- buildstage = 1
- update_icon()
- return
- else if(istype(W, /obj/item/screwdriver)) // Opening that Air Alarm up.
- W.play_tool_sound(src)
- panel_open = !panel_open
- to_chat(user, "The wires have been [panel_open ? "exposed" : "unexposed"].")
- update_icon()
- return
- else if(istype(W, /obj/item/card/id) || istype(W, /obj/item/pda))// trying to unlock the interface with an ID card
- togglelock(user)
- else if(panel_open && is_wire_tool(W))
- wires.interact(user)
- return
- if(1)
- if(istype(W, /obj/item/crowbar))
- user.visible_message("[user.name] removes the electronics from [src.name].",\
- "You start prying out the circuit...")
- W.play_tool_sound(src)
- if (W.use_tool(src, user, 20))
- if (buildstage == 1)
- to_chat(user, "You remove the air alarm electronics.")
- new /obj/item/electronics/airalarm( src.loc )
- playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
- buildstage = 0
- update_icon()
- return
-
- if(istype(W, /obj/item/stack/cable_coil))
- var/obj/item/stack/cable_coil/cable = W
- if(cable.get_amount() < 5)
- to_chat(user, "You need five lengths of cable to wire the air alarm!")
- return
- user.visible_message("[user.name] wires the air alarm.", \
- "You start wiring the air alarm...")
- if (do_after(user, 20, target = src))
- if (cable.get_amount() >= 5 && buildstage == 1)
- cable.use(5)
- to_chat(user, "You wire the air alarm.")
- wires.repair()
- aidisabled = 0
- locked = FALSE
- mode = 1
- shorted = 0
- post_alert(0)
- buildstage = 2
- update_icon()
- return
- if(0)
- if(istype(W, /obj/item/electronics/airalarm))
- if(user.temporarilyRemoveItemFromInventory(W))
- to_chat(user, "You insert the circuit.")
- buildstage = 1
- update_icon()
- qdel(W)
- return
-
- if(istype(W, /obj/item/electroadaptive_pseudocircuit))
- var/obj/item/electroadaptive_pseudocircuit/P = W
- if(!P.adapt_circuit(user, 25))
- return
- user.visible_message("[user] fabricates a circuit and places it into [src].", \
- "You adapt an air alarm circuit and slot it into the assembly.")
- buildstage = 1
- update_icon()
- return
-
- if(istype(W, /obj/item/wrench))
- to_chat(user, "You detach \the [src] from the wall.")
- W.play_tool_sound(src)
- new /obj/item/wallframe/airalarm( user.loc )
- qdel(src)
- return
-
- return ..()
-
-/obj/machinery/airalarm/AltClick(mob/user)
- ..()
- if(!user.canUseTopic(src, !issilicon(user)) || !isturf(loc))
- return
- else
- togglelock(user)
-
-/obj/machinery/airalarm/proc/togglelock(mob/living/user)
- if(stat & (NOPOWER|BROKEN))
- to_chat(user, "It does nothing!")
- else
- if(src.allowed(usr) && !wires.is_cut(WIRE_IDSCAN))
- locked = !locked
- updateUsrDialog()
- to_chat(user, "You [ locked ? "lock" : "unlock"] the air alarm interface.")
- else
- to_chat(user, "Access denied.")
- return
-
-/obj/machinery/airalarm/power_change()
- ..()
- if(stat & NOPOWER)
- set_light(0)
- update_icon()
-
-/obj/machinery/airalarm/emag_act(mob/user)
- if(obj_flags & EMAGGED)
- return
- obj_flags |= EMAGGED
- visible_message("Sparks fly out of [src]!", "You emag [src], disabling its safeties.")
- playsound(src, "sparks", 50, 1)
-
-/obj/machinery/airalarm/obj_break(damage_flag)
- ..()
- update_icon()
- set_light(0)
-
-/obj/machinery/airalarm/deconstruct(disassembled = TRUE)
- if(!(flags_1 & NODECONSTRUCT_1))
- new /obj/item/stack/sheet/metal(loc, 2)
- var/obj/item/I = new /obj/item/electronics/airalarm(loc)
- if(!disassembled)
- I.obj_integrity = I.max_integrity * 0.5
- new /obj/item/stack/cable_coil(loc, 3)
- qdel(src)
-
-#undef AALARM_MODE_SCRUBBING
-#undef AALARM_MODE_VENTING
-#undef AALARM_MODE_PANIC
-#undef AALARM_MODE_REPLACEMENT
-#undef AALARM_MODE_OFF
-#undef AALARM_MODE_FLOOD
-#undef AALARM_MODE_SIPHON
-#undef AALARM_MODE_CONTAMINATED
-#undef AALARM_MODE_REFILL
-#undef AALARM_REPORT_TIMEOUT
+/datum/tlv
+ var/min2
+ var/min1
+ var/max1
+ var/max2
+
+/datum/tlv/New(min2 as num, min1 as num, max1 as num, max2 as num)
+ if(min2) src.min2 = min2
+ if(min1) src.min1 = min1
+ if(max1) src.max1 = max1
+ if(max2) src.max2 = max2
+
+/datum/tlv/proc/get_danger_level(val as num)
+ if(max2 != -1 && val >= max2)
+ return 2
+ if(min2 != -1 && val <= min2)
+ return 2
+ if(max1 != -1 && val >= max1)
+ return 1
+ if(min1 != -1 && val <= min1)
+ return 1
+ return 0
+
+/datum/tlv/no_checks
+ min2 = -1
+ min1 = -1
+ max1 = -1
+ max2 = -1
+
+/datum/tlv/dangerous
+ min2 = -1
+ min1 = -1
+ max1 = 0.2
+ max2 = 0.5
+
+/obj/item/electronics/airalarm
+ name = "air alarm electronics"
+ icon_state = "airalarm_electronics"
+
+/obj/item/wallframe/airalarm
+ name = "air alarm frame"
+ desc = "Used for building Air Alarms."
+ icon = 'icons/obj/monitors.dmi'
+ icon_state = "alarm_bitem"
+ result_path = /obj/machinery/airalarm
+
+#define AALARM_MODE_SCRUBBING 1
+#define AALARM_MODE_VENTING 2 //makes draught
+#define AALARM_MODE_PANIC 3 //like siphon, but stronger (enables widenet)
+#define AALARM_MODE_REPLACEMENT 4 //sucks off all air, then refill and swithes to scrubbing
+#define AALARM_MODE_OFF 5
+#define AALARM_MODE_FLOOD 6 //Emagged mode; turns off scrubbers and pressure checks on vents
+#define AALARM_MODE_SIPHON 7 //Scrubbers suck air
+#define AALARM_MODE_CONTAMINATED 8 //Turns on all filtering and widenet scrubbing.
+#define AALARM_MODE_REFILL 9 //just like normal, but with triple the air output
+
+#define AALARM_REPORT_TIMEOUT 100
+
+#define AALARM_OVERLAY_OFF "alarm_off"
+#define AALARM_OVERLAY_GREEN "alarm_green"
+#define AALARM_OVERLAY_WARN "alarm_amber"
+#define AALARM_OVERLAY_DANGER "alarm_red"
+
+/obj/machinery/airalarm
+ name = "air alarm"
+ desc = "A machine that monitors atmosphere levels. Goes off if the area is dangerous."
+ icon = 'icons/obj/monitors.dmi'
+ icon_state = "alarm0"
+ use_power = IDLE_POWER_USE
+ idle_power_usage = 4
+ active_power_usage = 8
+ power_channel = ENVIRON
+ req_access = list(ACCESS_ATMOSPHERICS)
+ max_integrity = 250
+ integrity_failure = 80
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 90, "acid" = 30)
+ resistance_flags = FIRE_PROOF
+
+ var/danger_level = 0
+ var/mode = AALARM_MODE_SCRUBBING
+
+ var/locked = TRUE
+ var/aidisabled = 0
+ var/shorted = 0
+ var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone
+ var/brightness_on = 1
+
+ var/frequency = FREQ_ATMOS_CONTROL
+ var/alarm_frequency = FREQ_ATMOS_ALARMS
+ var/datum/radio_frequency/radio_connection
+
+ var/list/TLV = list( // Breathable air.
+ "pressure" = new/datum/tlv(ONE_ATMOSPHERE * 0.8, ONE_ATMOSPHERE* 0.9, ONE_ATMOSPHERE * 1.1, ONE_ATMOSPHERE * 1.2), // kPa
+ "temperature" = new/datum/tlv(T0C, T0C+10, T0C+40, T0C+66),
+ /datum/gas/oxygen = new/datum/tlv(16, 19, 135, 140), // Partial pressure, kpa
+ /datum/gas/nitrogen = new/datum/tlv(-1, -1, 1000, 1000),
+ /datum/gas/carbon_dioxide = new/datum/tlv(-1, -1, 5, 10),
+ /datum/gas/miasma = new/datum/tlv/(-1, -1, 2, 5),
+ /datum/gas/plasma = new/datum/tlv/dangerous,
+ /datum/gas/nitrous_oxide = new/datum/tlv/dangerous,
+ /datum/gas/bz = new/datum/tlv/dangerous,
+ /datum/gas/hypernoblium = new/datum/tlv(-1, -1, 1000, 1000), // Hyper-Noblium is inert and nontoxic
+ /datum/gas/water_vapor = new/datum/tlv/dangerous,
+ /datum/gas/tritium = new/datum/tlv/dangerous,
+ /datum/gas/stimulum = new/datum/tlv(-1, -1, 1000, 1000), // Stimulum has only positive effects
+ /datum/gas/nitryl = new/datum/tlv/dangerous,
+ /datum/gas/pluoxium = new/datum/tlv(-1, -1, 1000, 1000) // Unlike oxygen, pluoxium does not fuel plasma/tritium fires
+ )
+
+/obj/machinery/airalarm/server // No checks here.
+ TLV = list(
+ "pressure" = new/datum/tlv/no_checks,
+ "temperature" = new/datum/tlv/no_checks,
+ /datum/gas/oxygen = new/datum/tlv/no_checks,
+ /datum/gas/nitrogen = new/datum/tlv/no_checks,
+ /datum/gas/carbon_dioxide = new/datum/tlv/no_checks,
+ /datum/gas/miasma = new/datum/tlv/no_checks,
+ /datum/gas/plasma = new/datum/tlv/no_checks,
+ /datum/gas/nitrous_oxide = new/datum/tlv/no_checks,
+ /datum/gas/bz = new/datum/tlv/no_checks,
+ /datum/gas/hypernoblium = new/datum/tlv/no_checks,
+ /datum/gas/water_vapor = new/datum/tlv/no_checks,
+ /datum/gas/tritium = new/datum/tlv/no_checks,
+ /datum/gas/stimulum = new/datum/tlv/no_checks,
+ /datum/gas/nitryl = new/datum/tlv/no_checks,
+ /datum/gas/pluoxium = new/datum/tlv/no_checks
+ )
+
+/obj/machinery/airalarm/kitchen_cold_room // Copypasta: to check temperatures.
+ TLV = list(
+ "pressure" = new/datum/tlv(ONE_ATMOSPHERE * 0.8, ONE_ATMOSPHERE* 0.9, ONE_ATMOSPHERE * 1.1, ONE_ATMOSPHERE * 1.2), // kPa
+ "temperature" = new/datum/tlv(T0C-73.15, T0C-63.15, T0C, T0C+10),
+ /datum/gas/oxygen = new/datum/tlv(16, 19, 135, 140), // Partial pressure, kpa
+ /datum/gas/nitrogen = new/datum/tlv(-1, -1, 1000, 1000),
+ /datum/gas/carbon_dioxide = new/datum/tlv(-1, -1, 5, 10),
+ /datum/gas/miasma = new/datum/tlv/(-1, -1, 2, 5),
+ /datum/gas/plasma = new/datum/tlv/dangerous,
+ /datum/gas/nitrous_oxide = new/datum/tlv/dangerous,
+ /datum/gas/bz = new/datum/tlv/dangerous,
+ /datum/gas/hypernoblium = new/datum/tlv(-1, -1, 1000, 1000), // Hyper-Noblium is inert and nontoxic
+ /datum/gas/water_vapor = new/datum/tlv/dangerous,
+ /datum/gas/tritium = new/datum/tlv/dangerous,
+ /datum/gas/stimulum = new/datum/tlv(-1, -1, 1000, 1000), // Stimulum has only positive effects
+ /datum/gas/nitryl = new/datum/tlv/dangerous,
+ /datum/gas/pluoxium = new/datum/tlv(-1, -1, 1000, 1000) // Unlike oxygen, pluoxium does not fuel plasma/tritium fires
+ )
+
+/obj/machinery/airalarm/unlocked
+ locked = FALSE
+
+/obj/machinery/airalarm/engine
+ name = "engine air alarm"
+ locked = FALSE
+ req_access = null
+ req_one_access = list(ACCESS_ATMOSPHERICS, ACCESS_ENGINE)
+
+/obj/machinery/airalarm/mixingchamber
+ name = "chamber air alarm"
+ locked = FALSE
+ req_access = null
+ req_one_access = list(ACCESS_ATMOSPHERICS, ACCESS_TOX, ACCESS_TOX_STORAGE)
+
+/obj/machinery/airalarm/all_access
+ name = "all-access air alarm"
+ desc = "This particular atmos control unit appears to have no access restrictions."
+ locked = FALSE
+ req_access = null
+ req_one_access = null
+
+/obj/machinery/airalarm/syndicate //general syndicate access
+ req_access = list(ACCESS_SYNDICATE)
+
+/obj/machinery/airalarm/directional/north //Pixel offsets get overwritten on New()
+ dir = SOUTH
+ pixel_y = 24
+
+/obj/machinery/airalarm/directional/south
+ dir = NORTH
+ pixel_y = -24
+
+/obj/machinery/airalarm/directional/east
+ dir = WEST
+ pixel_x = 24
+
+/obj/machinery/airalarm/directional/west
+ dir = EAST
+ pixel_x = -24
+
+//all air alarms in area are connected via magic
+/area
+ var/list/air_vent_names = list()
+ var/list/air_scrub_names = list()
+ var/list/air_vent_info = list()
+ var/list/air_scrub_info = list()
+
+/obj/machinery/airalarm/Initialize(mapload, ndir, nbuild)
+ . = ..()
+ wires = new /datum/wires/airalarm(src)
+
+ if(ndir)
+ setDir(ndir)
+
+ if(nbuild)
+ buildstage = 0
+ panel_open = TRUE
+ pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24)
+ pixel_y = (dir & 3)? (dir == 1 ? -24 : 24) : 0
+
+ if(name == initial(name))
+ name = "[get_area_name(src)] Air Alarm"
+
+ power_change()
+ set_frequency(frequency)
+
+/obj/machinery/airalarm/Destroy()
+ SSradio.remove_object(src, frequency)
+ qdel(wires)
+ wires = null
+ return ..()
+
+/obj/machinery/airalarm/examine(mob/user)
+ . = ..()
+ switch(buildstage)
+ if(0)
+ to_chat(user, "It is missing air alarm electronics.")
+ if(1)
+ to_chat(user, "It is missing wiring.")
+ if(2)
+ to_chat(user, "Alt-click to [locked ? "unlock" : "lock"] the interface.")
+
+/obj/machinery/airalarm/ui_status(mob/user)
+ if(user.has_unlimited_silicon_privilege && aidisabled)
+ to_chat(user, "AI control has been disabled.")
+ else if(!shorted)
+ return ..()
+ return UI_CLOSE
+
+/obj/machinery/airalarm/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
+ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "airalarm", name, 440, 650, master_ui, state)
+ ui.open()
+
+/obj/machinery/airalarm/ui_data(mob/user)
+ var/data = list(
+ "locked" = locked,
+ "siliconUser" = user.has_unlimited_silicon_privilege,
+ "emagged" = (obj_flags & EMAGGED ? 1 : 0),
+ "danger_level" = danger_level,
+ )
+
+ var/area/A = get_area(src)
+ data["atmos_alarm"] = A.atmosalm
+ data["fire_alarm"] = A.fire
+
+ var/turf/T = get_turf(src)
+ var/datum/gas_mixture/environment = T.return_air()
+ var/datum/tlv/cur_tlv
+
+ data["environment_data"] = list()
+ var/pressure = environment.return_pressure()
+ cur_tlv = TLV["pressure"]
+ data["environment_data"] += list(list(
+ "name" = "Pressure",
+ "value" = pressure,
+ "unit" = "kPa",
+ "danger_level" = cur_tlv.get_danger_level(pressure)
+ ))
+ var/temperature = environment.temperature
+ cur_tlv = TLV["temperature"]
+ data["environment_data"] += list(list(
+ "name" = "Temperature",
+ "value" = temperature,
+ "unit" = "K ([round(temperature - T0C, 0.1)]C)",
+ "danger_level" = cur_tlv.get_danger_level(temperature)
+ ))
+ var/total_moles = environment.total_moles()
+ var/partial_pressure = R_IDEAL_GAS_EQUATION * environment.temperature / environment.volume
+ for(var/gas_id in environment.gases)
+ if(!(gas_id in TLV)) // We're not interested in this gas, it seems.
+ continue
+ cur_tlv = TLV[gas_id]
+ data["environment_data"] += list(list(
+ "name" = GLOB.meta_gas_names[gas_id],
+ "value" = environment.gases[gas_id] / total_moles * 100,
+ "unit" = "%",
+ "danger_level" = cur_tlv.get_danger_level(environment.gases[gas_id] * partial_pressure)
+ ))
+
+ if(!locked || user.has_unlimited_silicon_privilege)
+ data["vents"] = list()
+ for(var/id_tag in A.air_vent_names)
+ var/long_name = A.air_vent_names[id_tag]
+ var/list/info = A.air_vent_info[id_tag]
+ if(!info || info["frequency"] != frequency)
+ continue
+ data["vents"] += list(list(
+ "id_tag" = id_tag,
+ "long_name" = sanitize(long_name),
+ "power" = info["power"],
+ "checks" = info["checks"],
+ "excheck" = info["checks"]&1,
+ "incheck" = info["checks"]&2,
+ "direction" = info["direction"],
+ "external" = info["external"],
+ "internal" = info["internal"],
+ "extdefault"= (info["external"] == ONE_ATMOSPHERE),
+ "intdefault"= (info["internal"] == 0)
+ ))
+ data["scrubbers"] = list()
+ for(var/id_tag in A.air_scrub_names)
+ var/long_name = A.air_scrub_names[id_tag]
+ var/list/info = A.air_scrub_info[id_tag]
+ if(!info || info["frequency"] != frequency)
+ continue
+ data["scrubbers"] += list(list(
+ "id_tag" = id_tag,
+ "long_name" = sanitize(long_name),
+ "power" = info["power"],
+ "scrubbing" = info["scrubbing"],
+ "widenet" = info["widenet"],
+ "filter_types" = info["filter_types"]
+ ))
+ data["mode"] = mode
+ data["modes"] = list()
+ data["modes"] += list(list("name" = "Filtering - Scrubs out contaminants", "mode" = AALARM_MODE_SCRUBBING, "selected" = mode == AALARM_MODE_SCRUBBING, "danger" = 0))
+ data["modes"] += list(list("name" = "Contaminated - Scrubs out ALL contaminants quickly","mode" = AALARM_MODE_CONTAMINATED, "selected" = mode == AALARM_MODE_CONTAMINATED, "danger" = 0))
+ data["modes"] += list(list("name" = "Draught - Siphons out air while replacing", "mode" = AALARM_MODE_VENTING, "selected" = mode == AALARM_MODE_VENTING, "danger" = 0))
+ data["modes"] += list(list("name" = "Refill - Triple vent output", "mode" = AALARM_MODE_REFILL, "selected" = mode == AALARM_MODE_REFILL, "danger" = 1))
+ data["modes"] += list(list("name" = "Cycle - Siphons air before replacing", "mode" = AALARM_MODE_REPLACEMENT, "selected" = mode == AALARM_MODE_REPLACEMENT, "danger" = 1))
+ data["modes"] += list(list("name" = "Siphon - Siphons air out of the room", "mode" = AALARM_MODE_SIPHON, "selected" = mode == AALARM_MODE_SIPHON, "danger" = 1))
+ data["modes"] += list(list("name" = "Panic Siphon - Siphons air out of the room quickly","mode" = AALARM_MODE_PANIC, "selected" = mode == AALARM_MODE_PANIC, "danger" = 1))
+ data["modes"] += list(list("name" = "Off - Shuts off vents and scrubbers", "mode" = AALARM_MODE_OFF, "selected" = mode == AALARM_MODE_OFF, "danger" = 0))
+ if(obj_flags & EMAGGED)
+ data["modes"] += list(list("name" = "Flood - Shuts off scrubbers and opens vents", "mode" = AALARM_MODE_FLOOD, "selected" = mode == AALARM_MODE_FLOOD, "danger" = 1))
+
+ var/datum/tlv/selected
+ var/list/thresholds = list()
+
+ selected = TLV["pressure"]
+ thresholds += list(list("name" = "Pressure", "settings" = list()))
+ thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "min2", "selected" = selected.min2))
+ thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "min1", "selected" = selected.min1))
+ thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "max1", "selected" = selected.max1))
+ thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "max2", "selected" = selected.max2))
+
+ selected = TLV["temperature"]
+ thresholds += list(list("name" = "Temperature", "settings" = list()))
+ thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "min2", "selected" = selected.min2))
+ thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "min1", "selected" = selected.min1))
+ thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "max1", "selected" = selected.max1))
+ thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "max2", "selected" = selected.max2))
+
+ for(var/gas_id in GLOB.meta_gas_names)
+ if(!(gas_id in TLV)) // We're not interested in this gas, it seems.
+ continue
+ selected = TLV[gas_id]
+ thresholds += list(list("name" = GLOB.meta_gas_names[gas_id], "settings" = list()))
+ thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "min2", "selected" = selected.min2))
+ thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "min1", "selected" = selected.min1))
+ thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "max1", "selected" = selected.max1))
+ thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "max2", "selected" = selected.max2))
+
+ data["thresholds"] = thresholds
+ return data
+
+/obj/machinery/airalarm/ui_act(action, params)
+ if(..() || buildstage != 2)
+ return
+ if((locked && !usr.has_unlimited_silicon_privilege) || (usr.has_unlimited_silicon_privilege && aidisabled))
+ return
+ var/device_id = params["id_tag"]
+ switch(action)
+ if("lock")
+ if(usr.has_unlimited_silicon_privilege && !wires.is_cut(WIRE_IDSCAN))
+ locked = !locked
+ . = TRUE
+ if("power", "toggle_filter", "widenet", "scrubbing")
+ send_signal(device_id, list("[action]" = params["val"]), usr)
+ . = TRUE
+ if("excheck")
+ send_signal(device_id, list("checks" = text2num(params["val"])^1), usr)
+ . = TRUE
+ if("incheck")
+ send_signal(device_id, list("checks" = text2num(params["val"])^2), usr)
+ . = TRUE
+ if("set_external_pressure", "set_internal_pressure")
+ var/area/A = get_area(src)
+ var/target = input("New target pressure:", name, A.air_vent_info[device_id][(action == "set_external_pressure" ? "external" : "internal")]) as num|null
+ if(!isnull(target) && !..())
+ send_signal(device_id, list("[action]" = target), usr)
+ . = TRUE
+ if("reset_external_pressure")
+ send_signal(device_id, list("reset_external_pressure"), usr)
+ . = TRUE
+ if("reset_internal_pressure")
+ send_signal(device_id, list("reset_internal_pressure"), usr)
+ . = TRUE
+ if("threshold")
+ var/env = params["env"]
+ if(text2path(env))
+ env = text2path(env)
+
+ var/name = params["var"]
+ var/datum/tlv/tlv = TLV[env]
+ if(isnull(tlv))
+ return
+ var/value = input("New [name] for [env]:", name, tlv.vars[name]) as num|null
+ if(!isnull(value) && !..())
+ if(value < 0)
+ tlv.vars[name] = -1
+ else
+ tlv.vars[name] = round(value, 0.01)
+ investigate_log(" treshold value for [env]:[name] was set to [value] by [key_name(usr)]",INVESTIGATE_ATMOS)
+ . = TRUE
+ if("mode")
+ mode = text2num(params["mode"])
+ investigate_log("was turned to [get_mode_name(mode)] mode by [key_name(usr)]",INVESTIGATE_ATMOS)
+ apply_mode()
+ . = TRUE
+ if("alarm")
+ var/area/A = get_area(src)
+ if(A.atmosalert(2, src))
+ post_alert(2)
+ . = TRUE
+ if("reset")
+ var/area/A = get_area(src)
+ if(A.atmosalert(0, src))
+ post_alert(0)
+ . = TRUE
+ update_icon()
+
+/obj/machinery/airalarm/proc/reset(wire)
+ switch(wire)
+ if(WIRE_POWER)
+ if(!wires.is_cut(WIRE_POWER))
+ shorted = FALSE
+ update_icon()
+ if(WIRE_AI)
+ if(!wires.is_cut(WIRE_AI))
+ aidisabled = FALSE
+
+
+/obj/machinery/airalarm/proc/shock(mob/user, prb)
+ if((stat & (NOPOWER))) // unpowered, no shock
+ return 0
+ if(!prob(prb))
+ return 0 //you lucked out, no shock for you
+ var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
+ s.set_up(5, 1, src)
+ s.start() //sparks always.
+ if (electrocute_mob(user, get_area(src), src, 1, TRUE))
+ return 1
+ else
+ return 0
+
+/obj/machinery/airalarm/proc/refresh_all()
+ var/area/A = get_area(src)
+ for(var/id_tag in A.air_vent_names)
+ var/list/I = A.air_vent_info[id_tag]
+ if(I && I["timestamp"] + AALARM_REPORT_TIMEOUT / 2 > world.time)
+ continue
+ send_signal(id_tag, list("status"))
+ for(var/id_tag in A.air_scrub_names)
+ var/list/I = A.air_scrub_info[id_tag]
+ if(I && I["timestamp"] + AALARM_REPORT_TIMEOUT / 2 > world.time)
+ continue
+ send_signal(id_tag, list("status"))
+
+/obj/machinery/airalarm/proc/set_frequency(new_frequency)
+ SSradio.remove_object(src, frequency)
+ frequency = new_frequency
+ radio_connection = SSradio.add_object(src, frequency, RADIO_TO_AIRALARM)
+
+/obj/machinery/airalarm/proc/send_signal(target, list/command, mob/user)//sends signal 'command' to 'target'. Returns 0 if no radio connection, 1 otherwise
+ if(!radio_connection)
+ return 0
+
+ var/datum/signal/signal = new(command)
+ signal.data["tag"] = target
+ signal.data["sigtype"] = "command"
+ signal.data["user"] = user
+ radio_connection.post_signal(src, signal, RADIO_FROM_AIRALARM)
+
+ return 1
+
+/obj/machinery/airalarm/proc/get_mode_name(mode_value)
+ switch(mode_value)
+ if(AALARM_MODE_SCRUBBING)
+ return "Filtering"
+ if(AALARM_MODE_CONTAMINATED)
+ return "Contaminated"
+ if(AALARM_MODE_VENTING)
+ return "Draught"
+ if(AALARM_MODE_REFILL)
+ return "Refill"
+ if(AALARM_MODE_PANIC)
+ return "Panic Siphon"
+ if(AALARM_MODE_REPLACEMENT)
+ return "Cycle"
+ if(AALARM_MODE_SIPHON)
+ return "Siphon"
+ if(AALARM_MODE_OFF)
+ return "Off"
+ if(AALARM_MODE_FLOOD)
+ return "Flood"
+
+/obj/machinery/airalarm/proc/apply_mode()
+ var/area/A = get_area(src)
+ switch(mode)
+ if(AALARM_MODE_SCRUBBING)
+ for(var/device_id in A.air_scrub_names)
+ send_signal(device_id, list(
+ "power" = 1,
+ "set_filters" = list(/datum/gas/carbon_dioxide, /datum/gas/miasma),
+ "scrubbing" = 1,
+ "widenet" = 0,
+ ))
+ for(var/device_id in A.air_vent_names)
+ send_signal(device_id, list(
+ "power" = 1,
+ "checks" = 1,
+ "set_external_pressure" = ONE_ATMOSPHERE
+ ))
+ if(AALARM_MODE_CONTAMINATED)
+ for(var/device_id in A.air_scrub_names)
+ send_signal(device_id, list(
+ "power" = 1,
+ "set_filters" = list(
+ /datum/gas/carbon_dioxide,
+ /datum/gas/miasma,
+ /datum/gas/plasma,
+ /datum/gas/water_vapor,
+ /datum/gas/hypernoblium,
+ /datum/gas/nitrous_oxide,
+ /datum/gas/nitryl,
+ /datum/gas/tritium,
+ /datum/gas/bz,
+ /datum/gas/stimulum,
+ /datum/gas/pluoxium
+ ),
+ "scrubbing" = 1,
+ "widenet" = 1,
+ ))
+ for(var/device_id in A.air_vent_names)
+ send_signal(device_id, list(
+ "power" = 1,
+ "checks" = 1,
+ "set_external_pressure" = ONE_ATMOSPHERE
+ ))
+ if(AALARM_MODE_VENTING)
+ for(var/device_id in A.air_scrub_names)
+ send_signal(device_id, list(
+ "power" = 1,
+ "widenet" = 0,
+ "scrubbing" = 0
+ ))
+ for(var/device_id in A.air_vent_names)
+ send_signal(device_id, list(
+ "power" = 1,
+ "checks" = 1,
+ "set_external_pressure" = ONE_ATMOSPHERE*2
+ ))
+ if(AALARM_MODE_REFILL)
+ for(var/device_id in A.air_scrub_names)
+ send_signal(device_id, list(
+ "power" = 1,
+ "set_filters" = list(/datum/gas/carbon_dioxide, /datum/gas/miasma),
+ "scrubbing" = 1,
+ "widenet" = 0,
+ ))
+ for(var/device_id in A.air_vent_names)
+ send_signal(device_id, list(
+ "power" = 1,
+ "checks" = 1,
+ "set_external_pressure" = ONE_ATMOSPHERE * 3
+ ))
+ if(AALARM_MODE_PANIC,
+ AALARM_MODE_REPLACEMENT)
+ for(var/device_id in A.air_scrub_names)
+ send_signal(device_id, list(
+ "power" = 1,
+ "widenet" = 1,
+ "scrubbing" = 0
+ ))
+ for(var/device_id in A.air_vent_names)
+ send_signal(device_id, list(
+ "power" = 0
+ ))
+ if(AALARM_MODE_SIPHON)
+ for(var/device_id in A.air_scrub_names)
+ send_signal(device_id, list(
+ "power" = 1,
+ "widenet" = 0,
+ "scrubbing" = 0
+ ))
+ for(var/device_id in A.air_vent_names)
+ send_signal(device_id, list(
+ "power" = 0
+ ))
+
+ if(AALARM_MODE_OFF)
+ for(var/device_id in A.air_scrub_names)
+ send_signal(device_id, list(
+ "power" = 0
+ ))
+ for(var/device_id in A.air_vent_names)
+ send_signal(device_id, list(
+ "power" = 0
+ ))
+ if(AALARM_MODE_FLOOD)
+ for(var/device_id in A.air_scrub_names)
+ send_signal(device_id, list(
+ "power" = 0
+ ))
+ for(var/device_id in A.air_vent_names)
+ send_signal(device_id, list(
+ "power" = 1,
+ "checks" = 2,
+ "set_internal_pressure" = 0
+ ))
+
+/obj/machinery/airalarm/update_icon()
+ set_light(0)
+ cut_overlays()
+ SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays)
+ if(stat & NOPOWER)
+ icon_state = "alarm0"
+ return
+
+ if(stat & BROKEN)
+ icon_state = "alarmx"
+ return
+
+ if(panel_open)
+ switch(buildstage)
+ if(2)
+ icon_state = "alarmx"
+ if(1)
+ icon_state = "alarm_b2"
+ if(0)
+ icon_state = "alarm_b1"
+ return
+
+ icon_state = "alarm1"
+ var/overlay_state = AALARM_OVERLAY_OFF
+ var/area/A = get_area(src)
+ switch(max(danger_level, A.atmosalm))
+ if(0)
+ add_overlay(AALARM_OVERLAY_GREEN)
+ overlay_state = AALARM_OVERLAY_GREEN
+ light_color = LIGHT_COLOR_GREEN
+ set_light(brightness_on)
+ if(1)
+ add_overlay(AALARM_OVERLAY_WARN)
+ overlay_state = AALARM_OVERLAY_WARN
+ light_color = LIGHT_COLOR_LAVA
+ set_light(brightness_on)
+ if(2)
+ add_overlay(AALARM_OVERLAY_DANGER)
+ overlay_state = AALARM_OVERLAY_DANGER
+ light_color = LIGHT_COLOR_RED
+ set_light(brightness_on)
+
+ SSvis_overlays.add_vis_overlay(src, icon, overlay_state, ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir)
+ update_light()
+
+/obj/machinery/airalarm/process()
+ if((stat & (NOPOWER|BROKEN)) || shorted)
+ return
+
+ var/turf/location = get_turf(src)
+ if(!location)
+ return
+
+ var/datum/tlv/cur_tlv
+
+ var/datum/gas_mixture/environment = location.return_air()
+ var/list/env_gases = environment.gases
+ var/partial_pressure = R_IDEAL_GAS_EQUATION * environment.temperature / environment.volume
+
+ cur_tlv = TLV["pressure"]
+ var/environment_pressure = environment.return_pressure()
+ var/pressure_dangerlevel = cur_tlv.get_danger_level(environment_pressure)
+
+ cur_tlv = TLV["temperature"]
+ var/temperature_dangerlevel = cur_tlv.get_danger_level(environment.temperature)
+
+ var/gas_dangerlevel = 0
+ for(var/gas_id in env_gases)
+ if(!(gas_id in TLV)) // We're not interested in this gas, it seems.
+ continue
+ cur_tlv = TLV[gas_id]
+ gas_dangerlevel = max(gas_dangerlevel, cur_tlv.get_danger_level(env_gases[gas_id] * partial_pressure))
+
+ GAS_GARBAGE_COLLECT(environment.gases)
+
+ var/old_danger_level = danger_level
+ danger_level = max(pressure_dangerlevel, temperature_dangerlevel, gas_dangerlevel)
+
+ if(old_danger_level != danger_level)
+ apply_danger_level()
+ if(mode == AALARM_MODE_REPLACEMENT && environment_pressure < ONE_ATMOSPHERE * 0.05)
+ mode = AALARM_MODE_SCRUBBING
+ apply_mode()
+
+ return
+
+
+/obj/machinery/airalarm/proc/post_alert(alert_level)
+ var/datum/radio_frequency/frequency = SSradio.return_frequency(alarm_frequency)
+
+ if(!frequency)
+ return
+
+ var/datum/signal/alert_signal = new(list(
+ "zone" = get_area_name(src),
+ "type" = "Atmospheric"
+ ))
+ if(alert_level==2)
+ alert_signal.data["alert"] = "severe"
+ else if (alert_level==1)
+ alert_signal.data["alert"] = "minor"
+ else if (alert_level==0)
+ alert_signal.data["alert"] = "clear"
+
+ frequency.post_signal(src, alert_signal, range = -1)
+
+/obj/machinery/airalarm/proc/apply_danger_level()
+ var/area/A = get_area(src)
+
+ var/new_area_danger_level = 0
+ for(var/obj/machinery/airalarm/AA in A)
+ if (!(AA.stat & (NOPOWER|BROKEN)) && !AA.shorted)
+ new_area_danger_level = max(new_area_danger_level,AA.danger_level)
+ if(A.atmosalert(new_area_danger_level,src)) //if area was in normal state or if area was in alert state
+ post_alert(new_area_danger_level)
+
+ update_icon()
+
+/obj/machinery/airalarm/attackby(obj/item/W, mob/user, params)
+ switch(buildstage)
+ if(2)
+ if(istype(W, /obj/item/wirecutters) && panel_open && wires.is_all_cut())
+ W.play_tool_sound(src)
+ to_chat(user, "You cut the final wires.")
+ new /obj/item/stack/cable_coil(loc, 5)
+ buildstage = 1
+ update_icon()
+ return
+ else if(istype(W, /obj/item/screwdriver)) // Opening that Air Alarm up.
+ W.play_tool_sound(src)
+ panel_open = !panel_open
+ to_chat(user, "The wires have been [panel_open ? "exposed" : "unexposed"].")
+ update_icon()
+ return
+ else if(istype(W, /obj/item/card/id) || istype(W, /obj/item/pda))// trying to unlock the interface with an ID card
+ togglelock(user)
+ else if(panel_open && is_wire_tool(W))
+ wires.interact(user)
+ return
+ if(1)
+ if(istype(W, /obj/item/crowbar))
+ user.visible_message("[user.name] removes the electronics from [src.name].",\
+ "You start prying out the circuit...")
+ W.play_tool_sound(src)
+ if (W.use_tool(src, user, 20))
+ if (buildstage == 1)
+ to_chat(user, "You remove the air alarm electronics.")
+ new /obj/item/electronics/airalarm( src.loc )
+ playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
+ buildstage = 0
+ update_icon()
+ return
+
+ if(istype(W, /obj/item/stack/cable_coil))
+ var/obj/item/stack/cable_coil/cable = W
+ if(cable.get_amount() < 5)
+ to_chat(user, "You need five lengths of cable to wire the air alarm!")
+ return
+ user.visible_message("[user.name] wires the air alarm.", \
+ "You start wiring the air alarm...")
+ if (do_after(user, 20, target = src))
+ if (cable.get_amount() >= 5 && buildstage == 1)
+ cable.use(5)
+ to_chat(user, "You wire the air alarm.")
+ wires.repair()
+ aidisabled = 0
+ locked = FALSE
+ mode = 1
+ shorted = 0
+ post_alert(0)
+ buildstage = 2
+ update_icon()
+ return
+ if(0)
+ if(istype(W, /obj/item/electronics/airalarm))
+ if(user.temporarilyRemoveItemFromInventory(W))
+ to_chat(user, "You insert the circuit.")
+ buildstage = 1
+ update_icon()
+ qdel(W)
+ return
+
+ if(istype(W, /obj/item/electroadaptive_pseudocircuit))
+ var/obj/item/electroadaptive_pseudocircuit/P = W
+ if(!P.adapt_circuit(user, 25))
+ return
+ user.visible_message("[user] fabricates a circuit and places it into [src].", \
+ "You adapt an air alarm circuit and slot it into the assembly.")
+ buildstage = 1
+ update_icon()
+ return
+
+ if(istype(W, /obj/item/wrench))
+ to_chat(user, "You detach \the [src] from the wall.")
+ W.play_tool_sound(src)
+ new /obj/item/wallframe/airalarm( user.loc )
+ qdel(src)
+ return
+
+ return ..()
+
+/obj/machinery/airalarm/AltClick(mob/user)
+ ..()
+ if(!user.canUseTopic(src, !issilicon(user)) || !isturf(loc))
+ return
+ else
+ togglelock(user)
+
+/obj/machinery/airalarm/proc/togglelock(mob/living/user)
+ if(stat & (NOPOWER|BROKEN))
+ to_chat(user, "It does nothing!")
+ else
+ if(src.allowed(usr) && !wires.is_cut(WIRE_IDSCAN))
+ locked = !locked
+ updateUsrDialog()
+ to_chat(user, "You [ locked ? "lock" : "unlock"] the air alarm interface.")
+ else
+ to_chat(user, "Access denied.")
+ return
+
+/obj/machinery/airalarm/power_change()
+ ..()
+ if(stat & NOPOWER)
+ set_light(0)
+ update_icon()
+
+/obj/machinery/airalarm/emag_act(mob/user)
+ . = ..()
+ if(obj_flags & EMAGGED)
+ return
+ obj_flags |= EMAGGED
+ visible_message("Sparks fly out of [src]!", "You emag [src], disabling its safeties.")
+ playsound(src, "sparks", 50, 1)
+ return TRUE
+
+/obj/machinery/airalarm/obj_break(damage_flag)
+ ..()
+ update_icon()
+ set_light(0)
+
+/obj/machinery/airalarm/deconstruct(disassembled = TRUE)
+ if(!(flags_1 & NODECONSTRUCT_1))
+ new /obj/item/stack/sheet/metal(loc, 2)
+ var/obj/item/I = new /obj/item/electronics/airalarm(loc)
+ if(!disassembled)
+ I.obj_integrity = I.max_integrity * 0.5
+ new /obj/item/stack/cable_coil(loc, 3)
+ qdel(src)
+
+#undef AALARM_MODE_SCRUBBING
+#undef AALARM_MODE_VENTING
+#undef AALARM_MODE_PANIC
+#undef AALARM_MODE_REPLACEMENT
+#undef AALARM_MODE_OFF
+#undef AALARM_MODE_FLOOD
+#undef AALARM_MODE_SIPHON
+#undef AALARM_MODE_CONTAMINATED
+#undef AALARM_MODE_REFILL
+#undef AALARM_REPORT_TIMEOUT
diff --git a/code/modules/cargo/console.dm b/code/modules/cargo/console.dm
index b5b9a616d0..1a607b4b96 100644
--- a/code/modules/cargo/console.dm
+++ b/code/modules/cargo/console.dm
@@ -36,6 +36,7 @@
cat |= EXPORT_EMAG
/obj/machinery/computer/cargo/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
user.visible_message("[user] swipes a suspicious card through [src]!",
@@ -48,6 +49,8 @@
var/obj/item/circuitboard/computer/cargo/board = circuit
board.contraband = TRUE
board.obj_flags |= EMAGGED
+ req_access = list()
+ return TRUE
/obj/machinery/computer/cargo/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
diff --git a/code/modules/cargo/expressconsole.dm b/code/modules/cargo/expressconsole.dm
index 5288c27ff6..0097346a34 100644
--- a/code/modules/cargo/expressconsole.dm
+++ b/code/modules/cargo/expressconsole.dm
@@ -54,6 +54,7 @@
..()
/obj/machinery/computer/cargo/express/emag_act(mob/living/user)
+ . = SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT)
if(obj_flags & EMAGGED)
return
user.visible_message("[user] swipes a suspicious card through [src]!",
@@ -63,6 +64,8 @@
var/obj/item/circuitboard/computer/cargo/board = circuit
board.obj_flags |= EMAGGED
packin_up()
+ req_access = list()
+ return TRUE
/obj/machinery/computer/cargo/express/proc/packin_up() // oh shit, I'm sorry
meme_pack_data = list() // sorry for what?
diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm
index a87e95e28c..387aa65d20 100644
--- a/code/modules/clothing/glasses/hud.dm
+++ b/code/modules/clothing/glasses/hud.dm
@@ -24,11 +24,13 @@
desc = "[desc] The display is flickering slightly."
/obj/item/clothing/glasses/hud/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
to_chat(user, "PZZTTPFFFT")
desc = "[desc] The display is flickering slightly."
+ return TRUE
/obj/item/clothing/glasses/hud/health
name = "health scanner HUD"
diff --git a/code/modules/clothing/masks/hailer.dm b/code/modules/clothing/masks/hailer.dm
index f004f07bf5..086d47e8bf 100644
--- a/code/modules/clothing/masks/hailer.dm
+++ b/code/modules/clothing/masks/hailer.dm
@@ -69,12 +69,14 @@
/obj/item/clothing/mask/gas/sechailer/attack_self()
halt()
-/obj/item/clothing/mask/gas/sechailer/emag_act(mob/user as mob)
- if(safety)
- safety = FALSE
- to_chat(user, "You silently fry [src]'s vocal circuit with the cryptographic sequencer.")
- else
+
+/obj/item/clothing/mask/gas/sechailer/emag_act(mob/user)
+ . = ..()
+ if(!safety)
return
+ safety = FALSE
+ to_chat(user, "You silently fry [src]'s vocal circuit with the cryptographic sequencer.")
+ return TRUE
/obj/item/clothing/mask/gas/sechailer/verb/halt()
set category = "Object"
diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm
index 4ffc10f9c2..6cc11afdf5 100644
--- a/code/modules/holodeck/computer.dm
+++ b/code/modules/holodeck/computer.dm
@@ -149,6 +149,7 @@
active_power_usage = 50 + spawned.len * 3 + effects.len * 5
/obj/machinery/computer/holodeck/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
if(!LAZYLEN(emag_programs))
@@ -160,6 +161,7 @@
to_chat(user, "Warning. Automatic shutoff and derezing protocols have been corrupted. Please call Nanotrasen maintenance and do not use the simulator.")
log_game("[key_name(user)] emagged the Holodeck Control Console")
nerf(!(obj_flags & EMAGGED))
+ return TRUE
/obj/machinery/computer/holodeck/emp_act(severity)
. = ..()
diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm
index 699df5de12..ef58943731 100644
--- a/code/modules/library/lib_machines.dm
+++ b/code/modules/library/lib_machines.dm
@@ -343,8 +343,11 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
return ..()
/obj/machinery/computer/libraryconsole/bookmanagement/emag_act(mob/user)
- if(density && !(obj_flags & EMAGGED))
- obj_flags |= EMAGGED
+ . = ..()
+ if(!density || obj_flags & EMAGGED)
+ return
+ obj_flags |= EMAGGED
+ return TRUE
/obj/machinery/computer/libraryconsole/bookmanagement/Topic(href, href_list)
if(..())
diff --git a/code/modules/mining/abandoned_crates.dm b/code/modules/mining/abandoned_crates.dm
index 86499e694b..4a0faf69f5 100644
--- a/code/modules/mining/abandoned_crates.dm
+++ b/code/modules/mining/abandoned_crates.dm
@@ -214,8 +214,11 @@
return ..()
/obj/structure/closet/crate/secure/loot/emag_act(mob/user)
- if(locked)
- boom(user)
+ . = SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT)
+ if(!locked)
+ return
+ boom(user)
+ return TRUE
/obj/structure/closet/crate/secure/loot/togglelock(mob/user)
if(locked)
diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm
index 4a628c5f34..953da6cbb0 100644
--- a/code/modules/mining/laborcamp/laborstacker.dm
+++ b/code/modules/mining/laborcamp/laborstacker.dm
@@ -128,9 +128,12 @@ GLOBAL_LIST(labor_sheet_values)
qdel(src)
/obj/machinery/mineral/labor_claim_console/emag_act(mob/user)
- if(!(obj_flags & EMAGGED))
- obj_flags |= EMAGGED
- to_chat(user, "PZZTTPFFFT")
+ . = ..()
+ if(obj_flags & EMAGGED)
+ return
+ obj_flags |= EMAGGED
+ to_chat(user, "PZZTTPFFFT")
+ return TRUE
/**********************Prisoner Collection Unit**************************/
diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm
index c90c719e8a..0f09b6f62a 100644
--- a/code/modules/mob/living/silicon/robot/robot_defense.dm
+++ b/code/modules/mob/living/silicon/robot/robot_defense.dm
@@ -92,17 +92,18 @@
/mob/living/silicon/robot/emag_act(mob/user)
if(user == src)//To prevent syndieborgs from emagging themselves
- return
+ return FALSE
+ if(world.time < emag_cooldown)
+ return FALSE
+ . = ..()
if(!opened)//Cover is closed
if(locked)
to_chat(user, "You emag the cover lock.")
locked = FALSE
if(shell) //A warning to Traitors who may not know that emagging AI shells does not slave them.
to_chat(user, "[src] seems to be controlled remotely! Emagging the interface may not work as expected.")
- else
- to_chat(user, "The cover is already unlocked!")
- return
- if(world.time < emag_cooldown)
+ return TRUE
+ to_chat(user, "The cover is already unlocked!")
return
if(wiresexposed)
to_chat(user, "You must unexpose the wires first!")
@@ -115,20 +116,24 @@
to_chat(src, "\"[text2ratvar("You will serve Engine above all else")]!\"\n\
ALERT: Subversion attempt denied.")
log_game("[key_name(user)] attempted to emag cyborg [key_name(src)], but they serve only Ratvar.")
- return
+ return TRUE
if(connected_ai && connected_ai.mind && connected_ai.mind.has_antag_datum(/datum/antagonist/traitor))
to_chat(src, "ALERT: Foreign software execution prevented.")
to_chat(connected_ai, "ALERT: Cyborg unit \[[src]] successfully defended against subversion.")
log_game("[key_name(user)] attempted to emag cyborg [key_name(src)], but they were slaved to traitor AI [connected_ai].")
- return
+ return TRUE
if(shell) //AI shells cannot be emagged, so we try to make it look like a standard reset. Smart players may see through this, however.
to_chat(user, "[src] is remotely controlled! Your emag attempt has triggered a system reset instead!")
log_game("[key_name(user)] attempted to emag an AI shell belonging to [key_name(src) ? key_name(src) : connected_ai]. The shell has been reset as a result.")
ResetModule()
- return
+ return TRUE
+ INVOKE_ASYNC(src, .proc/beep_boop_rogue_bot, user)
+ return TRUE
+
+/mob/living/silicon/robot/proc/beep_boop_rogue_bot(mob/user)
SetEmagged(1)
SetStun(60) //Borgs were getting into trouble because they would attack the emagger before the new laws were shown
lawupdate = 0
diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm
index 91515e4511..49261d6e38 100644
--- a/code/modules/mob/living/simple_animal/bot/bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/bot.dm
@@ -187,22 +187,23 @@
qdel(src)
/mob/living/simple_animal/bot/emag_act(mob/user)
+ . = ..()
if(locked) //First emag application unlocks the bot's interface. Apply a screwdriver to use the emag again.
locked = FALSE
emagged = 1
to_chat(user, "You bypass [src]'s controls.")
- return
- if(!locked && open) //Bot panel is unlocked by ID or emag, and the panel is screwed open. Ready for emagging.
- emagged = 2
- remote_disabled = 1 //Manually emagging the bot locks out the AI built in panel.
- locked = TRUE //Access denied forever!
- bot_reset()
- turn_on() //The bot automatically turns on when emagged, unless recently hit with EMP.
- to_chat(src, "(#$*#$^^( OVERRIDE DETECTED")
- log_combat(user, src, "emagged")
- return
- else //Bot is unlocked, but the maint panel has not been opened with a screwdriver yet.
+ return TRUE
+ if(!open)
to_chat(user, "You need to open maintenance panel first!")
+ return
+ emagged = 2
+ remote_disabled = 1 //Manually emagging the bot locks out the AI built in panel.
+ locked = TRUE //Access denied forever!
+ bot_reset()
+ turn_on() //The bot automatically turns on when emagged, unless recently hit with EMP.
+ to_chat(src, "(#$*#$^^( OVERRIDE DETECTED")
+ log_combat(user, src, "emagged")
+ return TRUE
/mob/living/simple_animal/bot/examine(mob/user)
..()
diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
index e09eb13886..bdffb032a3 100644
--- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
@@ -78,7 +78,7 @@
return ..()
/mob/living/simple_animal/bot/cleanbot/emag_act(mob/user)
- ..()
+ . = ..()
if(emagged == 2)
if(user)
to_chat(user, "[src] buzzes and beeps.")
diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
index 0781c2907a..e272878574 100644
--- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
@@ -195,7 +195,7 @@ Auto Patrol[]"},
shootAt(user)
/mob/living/simple_animal/bot/ed209/emag_act(mob/user)
- ..()
+ . = ..()
if(emagged == 2)
if(user)
to_chat(user, "You short out [src]'s target assessment circuits.")
diff --git a/code/modules/mob/living/simple_animal/bot/firebot.dm b/code/modules/mob/living/simple_animal/bot/firebot.dm
index 1c2a6393ae..2b52da6821 100644
--- a/code/modules/mob/living/simple_animal/bot/firebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/firebot.dm
@@ -120,7 +120,7 @@
return dat
/mob/living/simple_animal/bot/firebot/emag_act(mob/user)
- ..()
+ . = ..()
if(emagged == 1)
if(user)
to_chat(user, "[src] buzzes and beeps.")
diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm
index 4709680ad9..396c6de166 100644
--- a/code/modules/mob/living/simple_animal/bot/floorbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm
@@ -124,7 +124,7 @@
..()
/mob/living/simple_animal/bot/floorbot/emag_act(mob/user)
- ..()
+ . = ..()
if(emagged == 2)
if(user)
to_chat(user, "[src] buzzes and beeps.")
diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm
index e069b46e9d..1c19cd82a1 100644
--- a/code/modules/mob/living/simple_animal/bot/honkbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm
@@ -127,10 +127,9 @@ Maintenance panel panel is [open ? "opened" : "closed"]"},
..()
/mob/living/simple_animal/bot/honkbot/emag_act(mob/user)
- ..()
+ . = ..()
if(emagged == 2)
if(user)
- user << "You short out [src]'s sound control system. It gives out an evil laugh!!"
oldtarget_name = user.name
audible_message("[src] gives out an evil laugh!")
playsound(src, 'sound/machines/honkbot_evil_laugh.ogg', 75, 1, -1) // evil laughter
diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm
index 5eaaaea175..1bff7dc10c 100644
--- a/code/modules/mob/living/simple_animal/bot/medbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/medbot.dm
@@ -240,7 +240,7 @@
step_to(src, (get_step_away(src,user)))
/mob/living/simple_animal/bot/medbot/emag_act(mob/user)
- ..()
+ . = ..()
if(emagged == 2)
declare_crit = 0
if(user)
diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm
index 2efdf09f24..1bc7493684 100644
--- a/code/modules/mob/living/simple_animal/bot/mulebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm
@@ -115,6 +115,7 @@
return
/mob/living/simple_animal/bot/mulebot/emag_act(mob/user)
+ . = SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT)
if(emagged < 1)
emagged = TRUE
if(!open)
@@ -122,6 +123,7 @@
to_chat(user, "You [locked ? "lock" : "unlock"] [src]'s controls!")
flick("mulebot-emagged", src)
playsound(src, "sparks", 100, 0)
+ return TRUE
/mob/living/simple_animal/bot/mulebot/update_icon()
if(open)
diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm
index b6ef509d54..9572b4dafc 100644
--- a/code/modules/mob/living/simple_animal/bot/secbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/secbot.dm
@@ -190,7 +190,7 @@ Auto Patrol: []"},
return
/mob/living/simple_animal/bot/secbot/emag_act(mob/user)
- ..()
+ . = ..()
if(emagged == 2)
if(user)
to_chat(user, "You short out [src]'s target assessment circuits.")
diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm
index 580374c5c0..db4cdc2ff5 100644
--- a/code/modules/modular_computers/computers/item/computer.dm
+++ b/code/modules/modular_computers/computers/item/computer.dm
@@ -178,13 +178,13 @@
turn_on(user)
/obj/item/modular_computer/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
to_chat(user, "\The [src] was already emagged.")
- return 0
- else
- obj_flags |= EMAGGED
- to_chat(user, "You emag \the [src]. It's screen briefly shows a \"OVERRIDE ACCEPTED: New software downloads available.\" message.")
- return 1
+ return
+ obj_flags |= EMAGGED
+ to_chat(user, "You emag \the [src]. It's screen briefly shows a \"OVERRIDE ACCEPTED: New software downloads available.\" message.")
+ return TRUE
/obj/item/modular_computer/examine(mob/user)
..()
diff --git a/code/modules/modular_computers/computers/machinery/modular_computer.dm b/code/modules/modular_computers/computers/machinery/modular_computer.dm
index 19d3b56046..b3476e7046 100644
--- a/code/modules/modular_computers/computers/machinery/modular_computer.dm
+++ b/code/modules/modular_computers/computers/machinery/modular_computer.dm
@@ -44,7 +44,9 @@
cpu.attack_ghost(user)
/obj/machinery/modular_computer/emag_act(mob/user)
- return cpu ? cpu.emag_act(user) : 1
+ . = ..()
+ if(cpu)
+ . |= cpu.emag_act(user)
/obj/machinery/modular_computer/update_icon()
cut_overlays()
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 7c377ffa22..d837f0d420 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -267,7 +267,7 @@
to_chat(user, "There is an integration cog installed!")
to_chat(user, "Alt-Click the APC to [ locked ? "unlock" : "lock"] the interface.")
-
+
if(issilicon(user))
to_chat(user, "Ctrl-Click the APC to switch the breaker [ operating ? "off" : "on"].")
@@ -747,7 +747,7 @@
if(damage_flag == "melee" && damage_amount < damage_deflection)
return 0
. = ..()
-
+
/obj/machinery/power/apc/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
if(!(stat & BROKEN))
@@ -759,21 +759,23 @@
update_icon()
/obj/machinery/power/apc/emag_act(mob/user)
- if(!(obj_flags & EMAGGED) && !malfhack)
- if(opened)
- to_chat(user, "You must close the cover to swipe an ID card!")
- else if(panel_open)
- to_chat(user, "You must close the panel first!")
- else if(stat & (BROKEN|MAINT))
- to_chat(user, "Nothing happens!")
- else
- flick("apc-spark", src)
- playsound(src, "sparks", 75, 1)
- obj_flags |= EMAGGED
- locked = FALSE
- to_chat(user, "You emag the APC interface.")
- update_icon()
-
+ . = ..()
+ if(obj_flags & EMAGGED || malfhack)
+ return
+ if(opened)
+ to_chat(user, "You must close the cover to swipe an ID card!")
+ else if(panel_open)
+ to_chat(user, "You must close the panel first!")
+ else if(stat & (BROKEN|MAINT))
+ to_chat(user, "Nothing happens!")
+ else
+ flick("apc-spark", src)
+ playsound(src, "sparks", 75, 1)
+ obj_flags |= EMAGGED
+ locked = FALSE
+ to_chat(user, "You emag the APC interface.")
+ update_icon()
+ return TRUE
// attack with hand - remove cell (if cover open) or interact with the APC
diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm
index 7a6e313cd0..7375a3e17a 100644
--- a/code/modules/power/port_gen.dm
+++ b/code/modules/power/port_gen.dm
@@ -194,10 +194,12 @@
return ..()
/obj/machinery/power/port_gen/pacman/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
emp_act(EMP_HEAVY)
+ return TRUE
/obj/machinery/power/port_gen/pacman/attack_ai(mob/user)
interact(user)
diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm
index d805713fa6..4d6ede69d1 100644
--- a/code/modules/power/singularity/emitter.dm
+++ b/code/modules/power/singularity/emitter.dm
@@ -339,12 +339,13 @@
projectile_sound = initial(projectile_sound)
/obj/machinery/power/emitter/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
locked = FALSE
obj_flags |= EMAGGED
- if(user)
- user.visible_message("[user.name] emags [src].","You short out the lock.")
+ user?.visible_message("[user.name] emags [src].","You short out the lock.")
+ return TRUE
/obj/machinery/power/emitter/prototype
diff --git a/code/modules/projectiles/pins.dm b/code/modules/projectiles/pins.dm
index 05d6367306..da3743f053 100644
--- a/code/modules/projectiles/pins.dm
+++ b/code/modules/projectiles/pins.dm
@@ -37,10 +37,12 @@
to_chat(user, "This firearm already has a firing pin installed.")
/obj/item/firing_pin/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
to_chat(user, "You override the authentication mechanism.")
+ return TRUE
/obj/item/firing_pin/proc/gun_insert(mob/living/user, obj/item/gun/G)
gun = G
diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
index bc998c6657..9a228b28e3 100644
--- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
@@ -139,12 +139,14 @@
/obj/machinery/chem_dispenser/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
to_chat(user, "[src] has no functional safeties to emag.")
return
to_chat(user, "You short out [src]'s safeties.")
dispensable_reagents |= emagged_reagents//add the emagged reagents to the dispensable ones
obj_flags |= EMAGGED
+ return TRUE
/obj/machinery/chem_dispenser/ex_act(severity, target)
if(severity < 3)
diff --git a/code/modules/research/nanites/nanite_remote.dm b/code/modules/research/nanites/nanite_remote.dm
index 60dd78cf94..824d033bf4 100644
--- a/code/modules/research/nanites/nanite_remote.dm
+++ b/code/modules/research/nanites/nanite_remote.dm
@@ -37,6 +37,7 @@
to_chat(user, "Access denied.")
/obj/item/nanite_remote/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
to_chat(user, "You override [src]'s ID lock.")
@@ -44,6 +45,7 @@
if(locked)
locked = FALSE
update_icon()
+ return TRUE
/obj/item/nanite_remote/update_icon()
. = ..()
diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm
index cb5062904d..a7d7857a24 100644
--- a/code/modules/research/rdconsole.dm
+++ b/code/modules/research/rdconsole.dm
@@ -184,12 +184,14 @@ Nothing else in the console has ID requirements.
..()
/obj/machinery/computer/rdconsole/emag_act(mob/user)
- if(!(obj_flags & EMAGGED))
- to_chat(user, "You disable the security protocols[locked? " and unlock the console":""].")
- playsound(src, "sparks", 75, 1)
- obj_flags |= EMAGGED
- locked = FALSE
- return ..()
+ . = ..()
+ if(obj_flags & EMAGGED)
+ return
+ to_chat(user, "You disable the security protocols[locked? " and unlock the console":""].")
+ playsound(src, "sparks", 75, 1)
+ obj_flags |= EMAGGED
+ locked = FALSE
+ return TRUE
/obj/machinery/computer/rdconsole/multitool_act(mob/user, obj/item/multitool/I)
var/lathe = linked_lathe && linked_lathe.multitool_act(user, I)
diff --git a/code/modules/research/server.dm b/code/modules/research/server.dm
index 20e05782ef..b3e114d2ad 100644
--- a/code/modules/research/server.dm
+++ b/code/modules/research/server.dm
@@ -155,8 +155,10 @@
src.updateUsrDialog()
/obj/machinery/computer/rdservercontrol/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
playsound(src, "sparks", 75, 1)
obj_flags |= EMAGGED
to_chat(user, "You disable the security protocols.")
+ return TRUE
diff --git a/code/modules/shuttle/computer.dm b/code/modules/shuttle/computer.dm
index 0c957919a1..946f0fb9a4 100644
--- a/code/modules/shuttle/computer.dm
+++ b/code/modules/shuttle/computer.dm
@@ -63,11 +63,13 @@
to_chat(usr, "Unable to comply.")
/obj/machinery/computer/shuttle/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
req_access = list()
obj_flags |= EMAGGED
to_chat(user, "You fried the consoles ID checking system.")
+ return TRUE
/obj/machinery/computer/shuttle/proc/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
if(port && (shuttleId == initial(shuttleId) || override))
diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm
index 020b4b29ab..119023d465 100644
--- a/code/modules/shuttle/emergency.dm
+++ b/code/modules/shuttle/emergency.dm
@@ -134,6 +134,8 @@
. = TRUE
/obj/machinery/computer/emergency_shuttle/emag_act(mob/user)
+ . = ..()
+
// How did you even get on the shuttle before it go to the station?
if(!IS_DOCKED)
return
@@ -159,6 +161,7 @@
authorized += ID
process()
+ return TRUE
/obj/machinery/computer/emergency_shuttle/Destroy()
// Our fake IDs that the emag generated are just there for colour
@@ -459,10 +462,12 @@
return
/obj/machinery/computer/shuttle/pod/emag_act(mob/user)
+ . = SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT)
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
to_chat(user, "You fry the pod's alert level checking system.")
+ return TRUE
/obj/machinery/computer/shuttle/pod/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
. = ..()
diff --git a/code/modules/shuttle/ferry.dm b/code/modules/shuttle/ferry.dm
index 06e38bb3eb..39ab087f9c 100644
--- a/code/modules/shuttle/ferry.dm
+++ b/code/modules/shuttle/ferry.dm
@@ -12,7 +12,7 @@
/obj/machinery/computer/shuttle/ferry/emag_act(mob/user)
if(!allow_emag)
to_chat(user, "[src]'s security firewall is far too powerful for you to bypass.")
- return FALSE
+ return SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT)
return ..()
/obj/machinery/computer/shuttle/ferry/attack_ai()
diff --git a/code/modules/shuttle/special.dm b/code/modules/shuttle/special.dm
index d1435a554c..9bea790957 100644
--- a/code/modules/shuttle/special.dm
+++ b/code/modules/shuttle/special.dm
@@ -48,7 +48,7 @@
return
/obj/machinery/power/emitter/energycannon/magical/emag_act(mob/user)
- return
+ return SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT)
/obj/structure/table/abductor/wabbajack
name = "wabbajack altar"
diff --git a/code/modules/station_goals/shield.dm b/code/modules/station_goals/shield.dm
index be88d0ecdc..b09dee04c7 100644
--- a/code/modules/station_goals/shield.dm
+++ b/code/modules/station_goals/shield.dm
@@ -198,9 +198,11 @@
change_meteor_chance(0.5)
/obj/machinery/satellite/meteor_shield/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
to_chat(user, "You access the satellite's debug mode, increasing the chance of meteor strikes.")
if(active)
change_meteor_chance(4)
+ return TRUE
diff --git a/code/modules/surgery/organs/augments_arms.dm b/code/modules/surgery/organs/augments_arms.dm
index 33e62d21e4..2489aa0705 100644
--- a/code/modules/surgery/organs/augments_arms.dm
+++ b/code/modules/surgery/organs/augments_arms.dm
@@ -185,11 +185,12 @@
zone = BODY_ZONE_L_ARM
/obj/item/organ/cyberimp/arm/toolset/emag_act()
- if(!(locate(/obj/item/kitchen/knife/combat/cyborg) in items_list))
- to_chat(usr, "You unlock [src]'s integrated knife!")
- items_list += new /obj/item/kitchen/knife/combat/cyborg(src)
- return 1
- return 0
+ . = ..()
+ if(locate(/obj/item/kitchen/knife/combat/cyborg) in items_list)
+ return
+ to_chat(usr, "You unlock [src]'s integrated knife!")
+ items_list += new /obj/item/kitchen/knife/combat/cyborg(src)
+ return TRUE
/obj/item/organ/cyberimp/arm/esword
name = "arm-mounted energy blade"
diff --git a/code/modules/vehicles/cars/clowncar.dm b/code/modules/vehicles/cars/clowncar.dm
index 63ef4fda5a..e504ea84f2 100644
--- a/code/modules/vehicles/cars/clowncar.dm
+++ b/code/modules/vehicles/cars/clowncar.dm
@@ -63,11 +63,13 @@
DumpMobs(TRUE)
/obj/vehicle/sealed/car/clowncar/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
to_chat(user, "You scramble the clowncar child safety lock and a panel with 6 colorful buttons appears!")
initialize_controller_action_type(/datum/action/vehicle/sealed/RollTheDice, VEHICLE_CONTROL_DRIVE)
+ return TRUE
/obj/vehicle/sealed/car/clowncar/Destroy()
playsound(src, 'sound/vehicles/clowncar_fart.ogg', 100)
diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm
index 410952397d..5165343993 100644
--- a/code/modules/vending/_vending.dm
+++ b/code/modules/vending/_vending.dm
@@ -65,7 +65,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
var/scan_id = 1
var/obj/item/coin/coin
var/obj/item/stack/spacecash/bill
-
+
var/global/vending_cache = list() //used for storing the icons of items being vended
var/dish_quants = list() //used by the snack machine's custom compartment to count dishes.
@@ -306,10 +306,12 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
. = ..()
/obj/machinery/vending/emag_act(mob/user)
+ . = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
to_chat(user, "You short out the product lock on [src].")
+ return TRUE
/obj/machinery/vending/_try_interact(mob/user)
if(seconds_electrified && !(stat & NOPOWER))
diff --git a/modular_citadel/code/game/machinery/plasmacases.dm b/modular_citadel/code/game/machinery/plasmacases.dm
index ac3621b58a..c45eb48caa 100644
--- a/modular_citadel/code/game/machinery/plasmacases.dm
+++ b/modular_citadel/code/game/machinery/plasmacases.dm
@@ -19,5 +19,6 @@
return MouseDrop(user)
/obj/structure/guncase/plasma/emag_act()
- to_chat(usr, "The locking mechanism is fitted with old style parts, The card has no effect.")
- return
\ No newline at end of file
+ . = SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT)
+ if(!.)
+ to_chat(usr, "The locking mechanism is fitted with old style parts, The card has no effect.")
\ No newline at end of file
diff --git a/modular_citadel/code/modules/cargo/console.dm b/modular_citadel/code/modules/cargo/console.dm
index 490f72d1d1..f54a6c577a 100644
--- a/modular_citadel/code/modules/cargo/console.dm
+++ b/modular_citadel/code/modules/cargo/console.dm
@@ -1,13 +1,9 @@
/obj/machinery/computer/cargo
req_access = list(ACCESS_CARGO)
-
+
/obj/machinery/computer/cargo/request
req_access = list()
-/obj/machinery/computer/cargo/emag_act(mob/user)
- req_access = list()
- . = ..()
-
/obj/machinery/computer/cargo/ui_act(action, params, datum/tgui/ui)
if(!allowed(usr))
to_chat(usr, "Access denied.")
diff --git a/modular_citadel/code/modules/reagents/reagent container/hypospraymkii.dm b/modular_citadel/code/modules/reagents/reagent container/hypospraymkii.dm
index 6cd9e1badc..9e7da03f9b 100755
--- a/modular_citadel/code/modules/reagents/reagent container/hypospraymkii.dm
+++ b/modular_citadel/code/modules/reagents/reagent container/hypospraymkii.dm
@@ -141,12 +141,18 @@
// Gunna allow this for now, still really don't approve - Pooj
/obj/item/hypospray/mkii/emag_act(mob/user)
+ . = ..()
+ if(obj_flags & EMAGGED)
+ to_chat(user, "[src] happens to be already overcharged.")
+ return
inject_wait = COMBAT_WAIT_INJECT
spray_wait = COMBAT_WAIT_SPRAY
spray_self = COMBAT_SELF_INJECT
inject_self = COMBAT_SELF_SPRAY
penetrates = TRUE
to_chat(user, "You overcharge [src]'s control circuit.")
+ obj_flags |= EMAGGED
+ return TRUE
/obj/item/hypospray/mkii/attack_hand(mob/user)
. = ..() //Don't bother changing this or removing it from containers will break.