diff --git a/_maps/map_files/Delta/delta.dmm b/_maps/map_files/Delta/delta.dmm
index 02f36f5ea40..28907e9e05e 100644
--- a/_maps/map_files/Delta/delta.dmm
+++ b/_maps/map_files/Delta/delta.dmm
@@ -47144,7 +47144,7 @@
pixel_y = 3
},
/obj/item/circuitboard/powermonitor,
-/obj/item/circuitboard/stationalert_all{
+/obj/item/circuitboard/stationalert{
pixel_x = 3;
pixel_y = -3
},
diff --git a/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm b/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm
index bcbbe8b2351..4152ad16382 100644
--- a/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm
@@ -31415,7 +31415,7 @@
pixel_x = -2;
pixel_y = 2
},
-/obj/item/circuitboard/stationalert_all{
+/obj/item/circuitboard/stationalert{
pixel_x = 1;
pixel_y = -1
},
diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm
index 2c12ac11e44..8f6f8d77f7f 100644
--- a/_maps/map_files/cyberiad/cyberiad.dmm
+++ b/_maps/map_files/cyberiad/cyberiad.dmm
@@ -35244,7 +35244,7 @@
},
/area/bridge)
"bnW" = (
-/obj/machinery/computer/station_alert/all,
+/obj/machinery/computer/station_alert,
/turf/simulated/floor/plasteel{
dir = 0;
icon_state = "yellow"
@@ -72578,7 +72578,7 @@
pixel_x = -2;
pixel_y = 2
},
-/obj/item/circuitboard/stationalert_all{
+/obj/item/circuitboard/stationalert{
pixel_x = 1;
pixel_y = -1
},
@@ -75846,7 +75846,7 @@
pixel_x = 32;
pixel_y = 0
},
-/obj/machinery/computer/station_alert/all,
+/obj/machinery/computer/station_alert,
/obj/structure/cable/yellow{
d1 = 4;
d2 = 8;
@@ -77210,6 +77210,10 @@
pixel_x = -22
},
/obj/item/stack/tape_roll,
+/obj/machinery/camera/motion{
+ c_tag = "EVA Motion Sensor";
+ dir = 4
+ },
/turf/simulated/floor/plasteel{
icon_state = "dark"
},
diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm
index 10aa1718dda..26b1d2d44aa 100644
--- a/code/__DEFINES/dcs/signals.dm
+++ b/code/__DEFINES/dcs/signals.dm
@@ -726,3 +726,7 @@
#define COMSIG_XENO_TURF_CLICK_CTRL "xeno_turf_click_alt"
///from monkey CtrlClickOn(): (/mob)
#define COMSIG_XENO_MONKEY_CLICK_CTRL "xeno_monkey_click_ctrl"
+
+///SSalarm signals
+#define COMSIG_TRIGGERED_ALARM "ssalarm_triggered"
+#define COMSIG_CANCELLED_ALARM "ssalarm_cancelled"
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index af087eb6082..0a36db1b185 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -242,20 +242,69 @@
0.4,0.6,0.0,\
0.2,0.2,0.6)
-#define LIST_REPLACE_RENAME list("rebeccapurple" = "dark purple", "darkslategrey" = "dark grey", "darkolivegreen" = "dark green", "darkslateblue" = "dark blue",\
- "darkkhaki" = "khaki", "darkseagreen" = "light green", "midnightblue" = "blue", "lightgrey" = "light grey", "darkgrey" = "dark grey",\
- "steelblue" = "blue", "goldenrod" = "gold")
+/*
+ Used for wire name appearances. Replaces the color name on the left with the one on the right.
+ The color on the left is the one used as the actual color of the wire, but it doesn't look good when written.
+ So, we need to replace the name to something that looks better.
+*/
+#define LIST_COLOR_RENAME \
+ list( \
+ "rebeccapurple" = "dark purple",\
+ "darkslategrey" = "dark grey", \
+ "darkolivegreen"= "dark green", \
+ "darkslateblue" = "dark blue", \
+ "darkkhaki" = "khaki", \
+ "darkseagreen" = "light green",\
+ "midnightblue" = "blue", \
+ "lightgrey" = "light grey", \
+ "darkgrey" = "dark grey", \
+ "steelblue" = "blue", \
+ "goldenrod" = "gold" \
+ )
-#define LIST_GREYSCALE_REPLACE list("red" = "lightgrey", "blue" = "grey", "green" = "grey", "orange" = "lightgrey", "brown" = "grey",\
- "gold" = "lightgrey", "cyan" = "lightgrey", "navy" = "grey", "purple" = "grey", "pink"= "lightgrey")
+/// Pure Black and white colorblindness. Every species except Vulpkanins and Tajarans will have this.
+#define GREYSCALE_COLOR_REPLACE \
+ list( \
+ "red" = "grey", \
+ "blue" = "grey", \
+ "green" = "grey", \
+ "orange" = "light grey", \
+ "brown" = "grey", \
+ "gold" = "light grey", \
+ "cyan" = "silver", \
+ "magenta" = "grey", \
+ "purple" = "grey", \
+ "pink" = "light grey" \
+ )
-#define LIST_VULP_REPLACE list("pink" = "beige", "orange" = "goldenrod", "gold" = "goldenrod", "red" = "darkolivegreen", "brown" = "darkolivegreen",\
- "green" = "darkslategrey", "cyan" = "steelblue", "purple" = "darkslategrey", "navy" = "midnightblue")
-
-#define LIST_TAJ_REPLACE list("red" = "rebeccapurple", "brown" = "rebeccapurple", "purple" = "darkslateblue", "blue" = "darkslateblue",\
- "green" = "darkolivegreen", "orange" = "darkkhaki", "gold" = "darkkhaki", "cyan" = "darkseagreen", \
- "navy" = "midnightblue", "pink" = "lightgrey")
+/// Red colorblindness. Vulpkanins/Wolpins have this.
+#define PROTANOPIA_COLOR_REPLACE \
+ list( \
+ "red" = "darkolivegreen", \
+ "green" = "darkslategrey", \
+ "orange" = "goldenrod", \
+ "gold" = "goldenrod", \
+ "brown" = "darkolivegreen", \
+ "cyan" = "steelblue", \
+ "magenta" = "blue", \
+ "purple" = "darkslategrey", \
+ "pink" = "beige" \
+ )
+/// Yellow-Blue colorblindness. Tajarans/Farwas have this.
+#define TRITANOPIA_COLOR_REPLACE \
+ list( \
+ "red" = "rebeccapurple", \
+ "blue" = "darkslateblue", \
+ "green" = "darkolivegreen", \
+ "orange" = "darkkhaki", \
+ "gold" = "darkkhaki", \
+ "brown" = "rebeccapurple", \
+ "cyan" = "darkseagreen", \
+ "magenta" = "darkslateblue", \
+ "purple" = "darkslateblue", \
+ "pink" = "lightgrey" \
+ )
//Gun trigger guards
#define TRIGGER_GUARD_ALLOW_ALL -1
diff --git a/code/__DEFINES/wires.dm b/code/__DEFINES/wires.dm
new file mode 100644
index 00000000000..f7ea1c3cf38
--- /dev/null
+++ b/code/__DEFINES/wires.dm
@@ -0,0 +1,77 @@
+// Wire defines for all machines/items.
+
+// Miscellaneous
+#define WIRE_DUD_PREFIX "__dud"
+
+// General
+#define WIRE_IDSCAN "ID Scan"
+#define WIRE_MAIN_POWER1 "Primary Power"
+#define WIRE_MAIN_POWER2 "Secondary Power"
+#define WIRE_AI_CONTROL "AI Control"
+#define WIRE_ELECTRIFY "Electrification"
+#define WIRE_SAFETY "Safety"
+
+// Vendors and smartfridges
+#define WIRE_THROW_ITEM "Item Throw"
+#define WIRE_CONTRABAND "Contraband"
+
+// Airlock
+#define WIRE_DOOR_BOLTS "Door Bolts"
+#define WIRE_BACKUP_POWER1 "Primary Backup Power"
+#define WIRE_OPEN_DOOR "Door State"
+#define WIRE_SPEED "Door Timing"
+#define WIRE_BOLT_LIGHT "Bolt Lights"
+
+// Air alarm
+#define WIRE_SYPHON "Siphon"
+#define WIRE_AALARM "Atmospherics Alarm"
+
+// Camera
+#define WIRE_FOCUS "Focus"
+
+// Mulebot
+#define WIRE_MOB_AVOIDANCE "Mob Avoidance"
+#define WIRE_LOADCHECK "Load Checking"
+#define WIRE_MOTOR1 "Primary Motor"
+#define WIRE_MOTOR2 "Secondary Motor"
+#define WIRE_REMOTE_RX "Signal Receiver"
+#define WIRE_REMOTE_TX "Signal Sender"
+#define WIRE_BEACON_RX "Beacon Receiver"
+
+// Explosives, bombs
+#define WIRE_EXPLODE "Explode" // Explodes if pulsed or cut while active, defuses a bomb that isn't active on cut.
+#define WIRE_BOMB_UNBOLT "Unbolt" // Unbolts the bomb if cut, hint on pulsed.
+#define WIRE_BOMB_DELAY "Delay" // Raises the timer on pulse, does nothing on cut.
+#define WIRE_BOMB_PROCEED "Proceed" // Lowers the timer, explodes if cut while the bomb is active.
+#define WIRE_BOMB_ACTIVATE "Activate" // Will start a bombs timer if pulsed, will hint if pulsed while already active, will stop a timer a bomb on cut.
+
+// Nuclear bomb
+#define WIRE_BOMB_LIGHT "Bomb Light"
+#define WIRE_BOMB_TIMING "Bomb Timing"
+#define WIRE_BOMB_SAFETY "Bomb Safety"
+
+// Particle accelerator
+#define WIRE_PARTICLE_POWER "Power Toggle" // Toggles whether the PA is on or not.
+#define WIRE_PARTICLE_STRENGTH "Strength" // Determines the strength of the PA.
+#define WIRE_PARTICLE_INTERFACE "Interface" // Determines the interface showing up.
+#define WIRE_PARTICLE_POWER_LIMIT "Maximum Power" // Determines how strong the PA can be.
+
+// Autolathe
+#define WIRE_AUTOLATHE_HACK "Hack"
+#define WIRE_AUTOLATHE_DISABLE "Disable"
+
+// Radio
+#define WIRE_RADIO_SIGNAL "Signal"
+#define WIRE_RADIO_RECEIVER "Receiver"
+#define WIRE_RADIO_TRANSMIT "Transmitter"
+
+// Cyborg
+#define WIRE_BORG_LOCKED "Lockdown"
+#define WIRE_BORG_CAMERA "Camera"
+#define WIRE_BORG_LAWCHECK "Law Check"
+
+// Suit storage unit
+#define WIRE_SSU_UV "UV wire"
+
+// Tesla coil
+#define WIRE_TESLACOIL_ZAP "Zap"
diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index 181d2a5140c..829c2c4fade 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -5,11 +5,11 @@
var/turf/T = get_turf(A)
return T ? T.loc : null
-/proc/get_area_name(N) //get area by its name
- for(var/area/A in world)
- if(A.name == N)
- return A
- return 0
+/proc/get_area_name(atom/X, format_text = FALSE)
+ var/area/A = isarea(X) ? X : get_area(X)
+ if(!A)
+ return null
+ return format_text ? format_text(A.name) : A.name
/proc/get_location_name(atom/X, format_text = FALSE)
var/area/A = isarea(X) ? X : get_area(X)
@@ -31,6 +31,24 @@
areas |= T.loc
return areas
+/proc/get_open_turf_in_dir(atom/center, dir)
+ var/turf/T = get_ranged_target_turf(center, dir, 1)
+ if(T && !T.density)
+ return T
+
+/proc/get_adjacent_open_turfs(atom/center)
+ . = list(get_open_turf_in_dir(center, NORTH),
+ get_open_turf_in_dir(center, SOUTH),
+ get_open_turf_in_dir(center, EAST),
+ get_open_turf_in_dir(center, WEST))
+ listclearnulls(.)
+
+/proc/get_adjacent_open_areas(atom/center)
+ . = list()
+ var/list/adjacent_turfs = get_adjacent_open_turfs(center)
+ for(var/I in adjacent_turfs)
+ . |= get_area(I)
+
// Like view but bypasses luminosity check
/proc/hear(var/range, var/atom/source)
diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm
index c1cf5d53520..075f3370965 100644
--- a/code/__HELPERS/lists.dm
+++ b/code/__HELPERS/lists.dm
@@ -672,9 +672,6 @@ proc/dd_sortedObjectList(list/incoming)
/obj/machinery/camera/dd_SortValue()
return "[c_tag]"
-/datum/alarm/dd_SortValue()
- return "[sanitize(last_name)]"
-
//Picks from the list, with some safeties, and returns the "default" arg if it fails
#define DEFAULTPICK(L, default) ((istype(L, /list) && L:len) ? pick(L) : default)
diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm
index 21af95cab48..ab3bfa85451 100644
--- a/code/_globalvars/lists/objects.dm
+++ b/code/_globalvars/lists/objects.dm
@@ -47,7 +47,10 @@ GLOBAL_LIST_EMPTY(ladders)
GLOBAL_LIST_INIT(active_diseases, list()) //List of Active disease in all mobs; purely for quick referencing.
GLOBAL_LIST_EMPTY(mob_spawners) // All mob_spawn objects
-
+GLOBAL_LIST_EMPTY(alert_consoles) // Station alert consoles, /obj/machinery/computer/station_alert
GLOBAL_LIST_EMPTY(explosive_walls)
GLOBAL_LIST_EMPTY(engine_beacon_list)
+
+/// List of wire colors for each object type of that round. One for airlocks, one for vendors, etc.
+GLOBAL_LIST_EMPTY(wire_color_directory) // This is an associative list with the `holder_type` as the key, and a list of colors as the value.
diff --git a/code/_onclick/hud/ai.dm b/code/_onclick/hud/ai.dm
index ada0ce8cd30..856f724f925 100644
--- a/code/_onclick/hud/ai.dm
+++ b/code/_onclick/hud/ai.dm
@@ -64,7 +64,7 @@
/obj/screen/ai/alerts/Click()
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
- AI.subsystem_alarm_monitor()
+ AI.ai_alerts()
/obj/screen/ai/announcement
name = "Make Announcement"
diff --git a/code/controllers/subsystem/alarm.dm b/code/controllers/subsystem/alarm.dm
index 289adf6de40..3d91d763be3 100644
--- a/code/controllers/subsystem/alarm.dm
+++ b/code/controllers/subsystem/alarm.dm
@@ -1,31 +1,31 @@
-SUBSYSTEM_DEF(alarms)
- name = "Alarms"
- init_order = INIT_ORDER_ALARMS // 2
- offline_implications = "Alarms (Power, camera, fire, etc) will no longer be checked. No immediate action is needed."
- var/datum/alarm_handler/atmosphere/atmosphere_alarm = new()
- var/datum/alarm_handler/burglar/burglar_alarm = new()
- var/datum/alarm_handler/camera/camera_alarm = new()
- var/datum/alarm_handler/fire/fire_alarm = new()
- var/datum/alarm_handler/motion/motion_alarm = new()
- var/datum/alarm_handler/power/power_alarm = new()
- var/list/datum/alarm/all_handlers
+SUBSYSTEM_DEF(alarm)
+ name = "Alarm"
+ flags = SS_NO_INIT | SS_NO_FIRE
+ var/list/alarms = list("Motion" = list(), "Fire" = list(), "Atmosphere" = list(), "Power" = list(), "Camera" = list(), "Burglar" = list())
-/datum/controller/subsystem/alarms/Initialize(start_timeofday)
- all_handlers = list(SSalarms.atmosphere_alarm, SSalarms.burglar_alarm, SSalarms.camera_alarm, SSalarms.fire_alarm, SSalarms.motion_alarm, SSalarms.power_alarm)
- return ..()
+/datum/controller/subsystem/alarm/proc/triggerAlarm(class, area/A, list/O, obj/alarmsource)
+ var/list/L = alarms[class]
+ for(var/I in L)
+ if(I == A.name)
+ var/list/alarm = L[I]
+ var/list/sources = alarm[3]
+ if(!(alarmsource.UID() in sources))
+ sources += alarmsource.UID()
+ return TRUE
+ L[A.name] = list(get_area_name(A, TRUE), O, list(alarmsource.UID()))
+ SEND_SIGNAL(SSalarm, COMSIG_TRIGGERED_ALARM, class, A, O, alarmsource)
+ return TRUE
-/datum/controller/subsystem/alarms/fire()
- for(var/datum/alarm_handler/AH in all_handlers)
- AH.process()
+/datum/controller/subsystem/alarm/proc/cancelAlarm(class, area/A, obj/origin)
+ var/list/L = alarms[class]
+ var/cleared = FALSE
+ for(var/I in L)
+ if(I == A.name)
+ var/list/alarm = L[I]
+ var/list/srcs = alarm[3]
+ srcs -= origin.UID()
+ if(!length(srcs))
+ cleared = TRUE
+ L -= I
-/datum/controller/subsystem/alarms/proc/active_alarms()
- var/list/all_alarms = new ()
- for(var/datum/alarm_handler/AH in all_handlers)
- var/list/alarms = AH.alarms
- all_alarms += alarms
-
- return all_alarms
-
-/datum/controller/subsystem/alarms/proc/number_of_active_alarms()
- var/list/alarms = active_alarms()
- return alarms.len
+ SEND_SIGNAL(SSalarm, COMSIG_CANCELLED_ALARM, class, A, origin, cleared)
diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm
index abb0b604069..8d02529ae6b 100644
--- a/code/controllers/verbs.dm
+++ b/code/controllers/verbs.dm
@@ -20,7 +20,7 @@
message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.")
/client/proc/debug_controller(controller in list("failsafe", "Master", "Ticker", "Air", "Jobs", "Sun", "Radio", "Configuration", "pAI",
- "Cameras", "Garbage", "Event", "Alarm", "Nano", "Vote", "Fires",
+ "Cameras", "Garbage", "Event", "Nano", "Vote", "Fires",
"Mob", "NPC Pool", "Shuttle", "Timer", "Weather", "Space", "Mob Hunt Server","Input"))
set category = "Debug"
set name = "Debug Controller"
@@ -65,9 +65,6 @@
if("Event")
debug_variables(SSevents)
feedback_add_details("admin_verb","DEvent")
- if("Alarm")
- debug_variables(SSalarms)
- feedback_add_details("admin_verb", "DAlarm")
if("Nano")
debug_variables(SSnanoui)
feedback_add_details("admin_verb","DNano")
diff --git a/code/datums/wires/airlock.dm b/code/datums/wires/airlock.dm
index dcde08d7ec1..6f7291a3a69 100644
--- a/code/datums/wires/airlock.dm
+++ b/code/datums/wires/airlock.dm
@@ -1,67 +1,29 @@
// Wires for airlocks
/datum/wires/airlock/secure
- random = 1
+ randomize = TRUE
/datum/wires/airlock
holder_type = /obj/machinery/door/airlock
- wire_count = 12
- window_x = 410
- window_y = 570
+ wire_count = 12 // 10 actual, 2 duds.
+ proper_name = "Airlock"
+ window_x = 400
+ window_y = 101
-#define AIRLOCK_WIRE_IDSCAN 1
-#define AIRLOCK_WIRE_MAIN_POWER1 2
-#define AIRLOCK_WIRE_DOOR_BOLTS 4
-#define AIRLOCK_WIRE_BACKUP_POWER1 8
-#define AIRLOCK_WIRE_OPEN_DOOR 16
-#define AIRLOCK_WIRE_AI_CONTROL 32
-#define AIRLOCK_WIRE_ELECTRIFY 64
-#define AIRLOCK_WIRE_SAFETY 128
-#define AIRLOCK_WIRE_SPEED 256
-#define AIRLOCK_WIRE_LIGHT 512
+/datum/wires/airlock/New(atom/_holder)
+ wires = list(
+ WIRE_IDSCAN, WIRE_MAIN_POWER1, WIRE_DOOR_BOLTS, WIRE_BACKUP_POWER1, WIRE_OPEN_DOOR,
+ WIRE_AI_CONTROL, WIRE_ELECTRIFY, WIRE_SAFETY, WIRE_SPEED, WIRE_BOLT_LIGHT
+ )
+ return ..()
-/datum/wires/airlock/GetWireName(index)
- switch(index)
- if(AIRLOCK_WIRE_IDSCAN)
- return "ID Scan"
-
- if(AIRLOCK_WIRE_MAIN_POWER1)
- return "Primary Power"
-
- if(AIRLOCK_WIRE_DOOR_BOLTS)
- return "Door Bolts"
-
- if(AIRLOCK_WIRE_BACKUP_POWER1)
- return "Primary Backup Power"
-
- if(AIRLOCK_WIRE_OPEN_DOOR)
- return "Door State"
-
- if(AIRLOCK_WIRE_AI_CONTROL)
- return "AI Control"
-
- if(AIRLOCK_WIRE_ELECTRIFY)
- return "Electrification"
-
- if(AIRLOCK_WIRE_ELECTRIFY)
- return "Door Safeties"
-
- if(AIRLOCK_WIRE_ELECTRIFY)
- return "Door Timing"
-
- if(AIRLOCK_WIRE_ELECTRIFY)
- return "Bolt Lights"
-
-/datum/wires/airlock/CanUse(mob/living/L)
+/datum/wires/airlock/interactable(mob/user)
var/obj/machinery/door/airlock/A = holder
- if(iscarbon(L))
- if(A.Adjacent(L))
- if(A.isElectrified())
- if(A.shock(L, 100))
- return 0
+ if(iscarbon(user) && A.Adjacent(user) && A.isElectrified() && A.shock(user, 100))
+ return FALSE
if(A.panel_open)
- return 1
- return 0
+ return TRUE
+ return FALSE
/datum/wires/airlock/get_status()
. = ..()
@@ -70,21 +32,20 @@
. += "The door bolts [A.locked ? "have fallen!" : "look up."]"
. += "The door bolt lights are [(A.lights && haspower) ? "on." : "off!"]"
- . += "The test light is [haspower ? "on." : "off!"]"
+ . += "The test light is [haspower ? "on." : "off!"]"
. += "The 'AI control allowed' light is [(A.aiControlDisabled == 0 && !A.emagged && haspower) ? "on" : "off"]."
. += "The 'Check Wiring' light is [(A.safe == 0 && haspower) ? "on" : "off"]."
. += "The 'Check Timing Mechanism' light is [(A.normalspeed == 0 && haspower) ? "on" : "off"]."
. += "The emergency lights are [(A.emergency && haspower) ? "on" : "off"]."
-/datum/wires/airlock/UpdateCut(index, mended)
-
+/datum/wires/airlock/on_cut(wire, mend)
var/obj/machinery/door/airlock/A = holder
- switch(index)
- if(AIRLOCK_WIRE_IDSCAN)
- A.aiDisabledIdScanner = !mended
- if(AIRLOCK_WIRE_MAIN_POWER1)
+ switch(wire)
+ if(WIRE_IDSCAN)
+ A.aiDisabledIdScanner = !mend
+ if(WIRE_MAIN_POWER1)
- if(!mended)
+ if(!mend)
//Cutting either one disables the main door power, but unless backup power is also cut, the backup power re-powers the door in 10 seconds. While unpowered, the door may be crowbarred open, but bolts-raising will not work. Cutting these wires may electocute the user.
A.loseMainPower()
A.shock(usr, 50)
@@ -92,9 +53,9 @@
A.regainMainPower()
A.shock(usr, 50)
- if(AIRLOCK_WIRE_BACKUP_POWER1)
+ if(WIRE_BACKUP_POWER1)
- if(!mended)
+ if(!mend)
//Cutting either one disables the backup door power (allowing it to be crowbarred open, but disabling bolts-raising), but may electocute the user.
A.loseBackupPower()
A.shock(usr, 50)
@@ -102,16 +63,16 @@
A.regainBackupPower()
A.shock(usr, 50)
- if(AIRLOCK_WIRE_DOOR_BOLTS)
+ if(WIRE_DOOR_BOLTS)
- if(!mended)
+ if(!mend)
//Cutting this wire also drops the door bolts, and mending it does not raise them. (This is what happens now, except there are a lot more wires going to door bolts at present)
A.lock(1)
A.update_icon()
- if(AIRLOCK_WIRE_AI_CONTROL)
+ if(WIRE_AI_CONTROL)
- if(!mended)
+ if(!mend)
//one wire for AI control. Cutting this prevents the AI from controlling the door unless it has hacked the door through the power connection (which takes about a minute). If both main and backup power are cut, as well as this wire, then the AI cannot operate or hack the door at all.
//aiControlDisabled: If 1, AI control is disabled until the AI hacks back in and disables the lock. If 2, the AI has bypassed the lock. If -1, the control is enabled but the AI had bypassed it earlier, so if it is disabled again the AI would have no trouble getting back in.
if(A.aiControlDisabled == 0)
@@ -124,44 +85,44 @@
else if(A.aiControlDisabled == 2)
A.aiControlDisabled = -1
- if(AIRLOCK_WIRE_ELECTRIFY)
- if(!mended)
+ if(WIRE_ELECTRIFY)
+ if(!mend)
//Cutting this wire electrifies the door, so that the next person to touch the door without insulated gloves gets electrocuted.
A.electrify(-1)
else
A.electrify(0)
return // Don't update the dialog.
- if(AIRLOCK_WIRE_SAFETY)
- A.safe = mended
+ if(WIRE_SAFETY)
+ A.safe = mend
- if(AIRLOCK_WIRE_SPEED)
- A.autoclose = mended
- if(mended)
+ if(WIRE_SPEED)
+ A.autoclose = mend
+ if(mend)
if(!A.density)
- spawn(0)
- A.close()
+ INVOKE_ASYNC(A, /obj/machinery/door/airlock/.proc/close)
- if(AIRLOCK_WIRE_LIGHT)
- A.lights = mended
+ if(WIRE_BOLT_LIGHT)
+ A.lights = mend
A.update_icon()
..()
-/datum/wires/airlock/UpdatePulsed(index)
-
+/datum/wires/airlock/on_pulse(wire)
var/obj/machinery/door/airlock/A = holder
- switch(index)
- if(AIRLOCK_WIRE_IDSCAN)
+ switch(wire)
+ if(WIRE_IDSCAN)
//Sending a pulse through flashes the red light on the door (if the door has power).
if(A.arePowerSystemsOn() && A.density)
A.do_animate("deny")
if(A.emergency)
A.emergency = 0
A.update_icon()
- if(AIRLOCK_WIRE_MAIN_POWER1)
+
+ if(WIRE_MAIN_POWER1)
//Sending a pulse through either one causes a breaker to trip, disabling the door for 10 seconds if backup power is connected, or 1 minute if not (or until backup power comes back on, whichever is shorter).
A.loseMainPower()
- if(AIRLOCK_WIRE_DOOR_BOLTS)
+
+ if(WIRE_DOOR_BOLTS)
//one wire for door bolts. Sending a pulse through this drops door bolts if they're not down (whether power's on or not),
//raises them if they are down (only if power's on)
if(!A.locked)
@@ -170,45 +131,40 @@
else if(A.unlock())
A.audible_message("You hear a click from the bottom of the door.", hearing_distance = 1)
- if(AIRLOCK_WIRE_BACKUP_POWER1)
+ if(WIRE_BACKUP_POWER1)
//two wires for backup power. Sending a pulse through either one causes a breaker to trip, but this does not disable it unless main power is down too (in which case it is disabled for 1 minute or however long it takes main power to come back, whichever is shorter).
A.loseBackupPower()
- if(AIRLOCK_WIRE_AI_CONTROL)
+
+ if(WIRE_AI_CONTROL)
if(A.aiControlDisabled == 0)
A.aiControlDisabled = 1
else if(A.aiControlDisabled == -1)
A.aiControlDisabled = 2
+ addtimer(CALLBACK(A, /obj/machinery/door/airlock/.proc/ai_control_callback), 1 SECONDS)
- spawn(10)
- if(A)
- if(A.aiControlDisabled == 1)
- A.aiControlDisabled = 0
- else if(A.aiControlDisabled == 2)
- A.aiControlDisabled = -1
-
- if(AIRLOCK_WIRE_ELECTRIFY)
+ if(WIRE_ELECTRIFY)
//one wire for electrifying the door. Sending a pulse through this electrifies the door for 30 seconds.
A.electrify(30)
- if(AIRLOCK_WIRE_OPEN_DOOR)
+
+ if(WIRE_OPEN_DOOR)
//tries to open the door without ID
//will succeed only if the ID wire is cut or the door requires no access and it's not emagged
if(A.emagged) return
if(!A.requiresID() || A.check_access(null))
- spawn(0)
- if(A.density)
- A.open()
- else
- A.close()
- if(AIRLOCK_WIRE_SAFETY)
+ if(A.density)
+ INVOKE_ASYNC(A, /obj/machinery/door/airlock/.proc/open)
+ else
+ INVOKE_ASYNC(A, /obj/machinery/door/airlock/.proc/close)
+
+ if(WIRE_SAFETY)
A.safe = !A.safe
if(!A.density)
- spawn(0)
- A.close()
+ INVOKE_ASYNC(A, /obj/machinery/door/airlock/.proc/close)
- if(AIRLOCK_WIRE_SPEED)
+ if(WIRE_SPEED)
A.normalspeed = !A.normalspeed
- if(AIRLOCK_WIRE_LIGHT)
+ if(WIRE_BOLT_LIGHT)
A.lights = !A.lights
A.update_icon()
diff --git a/code/datums/wires/alarm.dm b/code/datums/wires/alarm.dm
index f6b49b0dd99..cd13c9fe1d8 100644
--- a/code/datums/wires/alarm.dm
+++ b/code/datums/wires/alarm.dm
@@ -2,35 +2,22 @@
/datum/wires/alarm
holder_type = /obj/machinery/alarm
wire_count = 5
+ window_x = 385
+ window_y = 90
+ proper_name = "Air alarm"
-#define AALARM_WIRE_IDSCAN 1
-#define AALARM_WIRE_POWER 2
-#define AALARM_WIRE_SYPHON 4
-#define AALARM_WIRE_AI_CONTROL 8
-#define AALARM_WIRE_AALARM 16
+/datum/wires/alarm/New(atom/_holder)
+ wires = list(
+ WIRE_IDSCAN , WIRE_MAIN_POWER1 , WIRE_SYPHON,
+ WIRE_AI_CONTROL, WIRE_AALARM
+ )
+ return ..()
-/datum/wires/alarm/GetWireName(index)
- switch(index)
- if(AALARM_WIRE_IDSCAN)
- return "ID Scan"
-
- if(AALARM_WIRE_POWER)
- return "Power"
-
- if(AALARM_WIRE_SYPHON)
- return "Syphon"
-
- if(AALARM_WIRE_AI_CONTROL)
- return "AI Control"
-
- if(AALARM_WIRE_AALARM)
- return "Atmospherics Alarm"
-
-/datum/wires/alarm/CanUse(mob/living/L)
+/datum/wires/alarm/interactable(mob/user)
var/obj/machinery/alarm/A = holder
if(A.wiresexposed)
- return 1
- return 0
+ return TRUE
+ return FALSE
/datum/wires/alarm/get_status()
. = ..()
@@ -39,75 +26,60 @@
. += "The Air Alarm is [(A.shorted || (A.stat & (NOPOWER|BROKEN))) ? "offline." : "working properly!"]"
. += "The 'AI control allowed' light is [A.aidisabled ? "off" : "on"]."
-/datum/wires/alarm/UpdateCut(index, mended)
+/datum/wires/alarm/on_cut(wire, mend)
var/obj/machinery/alarm/A = holder
- switch(index)
- if(AALARM_WIRE_IDSCAN)
- if(!mended)
+ switch(wire)
+ if(WIRE_IDSCAN)
+ if(!mend)
A.locked = 1
-// to_chat(world, "Idscan wire cut")
- if(AALARM_WIRE_POWER)
+ if(WIRE_MAIN_POWER1)
A.shock(usr, 50)
- A.shorted = !mended
+ A.shorted = !mend
A.update_icon()
-// to_chat(world, "Power wire cut")
- if(AALARM_WIRE_AI_CONTROL)
- A.aidisabled = !mended
-// to_chat(world, "AI Control Wire Cut")
+ if(WIRE_AI_CONTROL)
+ A.aidisabled = !mend
- if(AALARM_WIRE_SYPHON)
- if(!mended)
+ if(WIRE_SYPHON)
+ if(!mend)
A.mode = 3 // AALARM_MODE_PANIC
A.apply_mode()
-// to_chat(world, "Syphon Wire Cut")
- if(AALARM_WIRE_AALARM)
- if(A.alarm_area.atmosalert(2, A))
- A.post_alert(2)
+ if(WIRE_AALARM)
+ if(A.alarm_area.atmosalert(ATMOS_ALARM_DANGER, A))
+ A.post_alert(ATMOS_ALARM_DANGER)
A.update_icon()
..()
-/datum/wires/alarm/UpdatePulsed(index)
+/datum/wires/alarm/on_pulse(wire)
var/obj/machinery/alarm/A = holder
- switch(index)
- if(AALARM_WIRE_IDSCAN)
+ switch(wire)
+ if(WIRE_IDSCAN)
A.locked = !A.locked
-// to_chat(world, "Idscan wire pulsed")
- if(AALARM_WIRE_POWER)
-// to_chat(world, "Power wire pulsed")
- if(A.shorted == 0)
- A.shorted = 1
+ if(WIRE_MAIN_POWER1)
+ if(!A.shorted)
+ A.shorted = TRUE
A.update_icon()
+ addtimer(CALLBACK(A, /obj/machinery/alarm/.proc/unshort_callback), 120 SECONDS)
- spawn(12000)
- if(A.shorted == 1)
- A.shorted = 0
- A.update_icon()
-
-
- if(AALARM_WIRE_AI_CONTROL)
-// to_chat(world, "AI Control wire pulsed")
- if(A.aidisabled == 0)
- A.aidisabled = 1
+ if(WIRE_AI_CONTROL)
+ if(!A.aidisabled)
+ A.aidisabled = TRUE
A.updateDialog()
- spawn(100)
- if(A.aidisabled == 1)
- A.aidisabled = 0
+ addtimer(CALLBACK(A, /obj/machinery/alarm/.proc/enable_ai_control_callback), 10 SECONDS)
- if(AALARM_WIRE_SYPHON)
-// to_chat(world, "Syphon wire pulsed")
+
+ if(WIRE_SYPHON)
if(A.mode == 1) // AALARM_MODE_SCRUB
A.mode = 3 // AALARM_MODE_PANIC
else
A.mode = 1 // AALARM_MODE_SCRUB
A.apply_mode()
- if(AALARM_WIRE_AALARM)
-// to_chat(world, "Aalarm wire pulsed")
- if(A.alarm_area.atmosalert(0, A))
- A.post_alert(0)
+ if(WIRE_AALARM)
+ if(A.alarm_area.atmosalert(ATMOS_ALARM_NONE, A))
+ A.post_alert(ATMOS_ALARM_NONE)
A.update_icon()
..()
diff --git a/code/datums/wires/apc.dm b/code/datums/wires/apc.dm
index b1076c8e29b..49931d8fa31 100644
--- a/code/datums/wires/apc.dm
+++ b/code/datums/wires/apc.dm
@@ -1,25 +1,13 @@
/datum/wires/apc
holder_type = /obj/machinery/power/apc
wire_count = 4
+ proper_name = "APC"
+ window_x = 355
+ window_y = 97
-#define APC_WIRE_IDSCAN 1
-#define APC_WIRE_MAIN_POWER1 2
-#define APC_WIRE_MAIN_POWER2 4
-#define APC_WIRE_AI_CONTROL 8
-
-/datum/wires/apc/GetWireName(index)
- switch(index)
- if(APC_WIRE_IDSCAN)
- return "ID Scan"
-
- if(APC_WIRE_MAIN_POWER1)
- return "Primary Power"
-
- if(APC_WIRE_MAIN_POWER2)
- return "Secondary Power"
-
- if(APC_WIRE_AI_CONTROL)
- return "AI Control"
+/datum/wires/apc/New(atom/_holder)
+ wires = list(WIRE_IDSCAN, WIRE_MAIN_POWER1, WIRE_MAIN_POWER2, WIRE_AI_CONTROL)
+ return ..()
/datum/wires/apc/get_status()
. = ..()
@@ -29,66 +17,53 @@
. += "The 'AI control allowed' light is [A.aidisabled ? "off" : "on"]."
-/datum/wires/apc/CanUse(mob/living/L)
+/datum/wires/apc/interactable(mob/user)
var/obj/machinery/power/apc/A = holder
if(A.panel_open && !A.opened)
return TRUE
return FALSE
-/datum/wires/apc/UpdatePulsed(index)
+/datum/wires/apc/on_pulse(wire)
var/obj/machinery/power/apc/A = holder
- switch(index)
+ switch(wire)
+ if(WIRE_IDSCAN)
+ A.locked = FALSE
+ addtimer(CALLBACK(A, /obj/machinery/power/apc/.proc/relock_callback), 30 SECONDS)
- if(APC_WIRE_IDSCAN)
- A.locked = 0
- spawn(300)
- if(A)
- A.locked = 1
- A.updateDialog()
+ if(WIRE_MAIN_POWER1, WIRE_MAIN_POWER2)
+ if(!A.shorted)
+ A.shorted = TRUE
+ addtimer(CALLBACK(A, /obj/machinery/power/apc/.proc/check_main_power_callback), 120 SECONDS)
- if(APC_WIRE_MAIN_POWER1, APC_WIRE_MAIN_POWER2)
- if(A.shorted == 0)
- A.shorted = 1
- spawn(1200)
- if(A && !IsIndexCut(APC_WIRE_MAIN_POWER1) && !IsIndexCut(APC_WIRE_MAIN_POWER2))
- A.shorted = 0
- A.updateDialog()
-
- if(APC_WIRE_AI_CONTROL)
- if(A.aidisabled == 0)
- A.aidisabled = 1
-
- spawn(10)
- if(A && !IsIndexCut(APC_WIRE_AI_CONTROL))
- A.aidisabled = 0
- A.updateDialog()
+ if(WIRE_AI_CONTROL)
+ if(!A.aidisabled)
+ A.aidisabled = TRUE
+ addtimer(CALLBACK(A, /obj/machinery/power/apc/.proc/check_ai_control_callback), 1 SECONDS)
..()
-/datum/wires/apc/UpdateCut(index, mended)
+/datum/wires/apc/on_cut(wire, mend)
var/obj/machinery/power/apc/A = holder
- switch(index)
- if(APC_WIRE_MAIN_POWER1, APC_WIRE_MAIN_POWER2)
-
- if(!mended)
+ switch(wire)
+ if(WIRE_MAIN_POWER1, WIRE_MAIN_POWER2)
+ if(!mend)
A.shock(usr, 50)
- A.shorted = 1
+ A.shorted = TRUE
- else if(!IsIndexCut(APC_WIRE_MAIN_POWER1) && !IsIndexCut(APC_WIRE_MAIN_POWER2))
- A.shorted = 0
+ else if(!is_cut(WIRE_MAIN_POWER1) && !is_cut(WIRE_MAIN_POWER2))
+ A.shorted = FALSE
A.shock(usr, 50)
- if(APC_WIRE_AI_CONTROL)
-
- if(!mended)
- if(A.aidisabled == 0)
- A.aidisabled = 1
+ if(WIRE_AI_CONTROL)
+ if(!mend)
+ if(!A.aidisabled)
+ A.aidisabled = TRUE
else
- if(A.aidisabled == 1)
- A.aidisabled = 0
+ if(A.aidisabled)
+ A.aidisabled = FALSE
..()
diff --git a/code/datums/wires/autolathe.dm b/code/datums/wires/autolathe.dm
index c1413abd0cc..0d2aab5a81f 100644
--- a/code/datums/wires/autolathe.dm
+++ b/code/datums/wires/autolathe.dm
@@ -1,21 +1,13 @@
/datum/wires/autolathe
holder_type = /obj/machinery/autolathe
wire_count = 10
+ proper_name = "Autolathe"
+ window_x = 340
+ window_y = 55
-#define AUTOLATHE_HACK_WIRE 1
-#define AUTOLATHE_SHOCK_WIRE 2
-#define AUTOLATHE_DISABLE_WIRE 4
-
-/datum/wires/autolathe/GetWireName(index)
- switch(index)
- if(AUTOLATHE_HACK_WIRE)
- return "Hack"
-
- if(AUTOLATHE_SHOCK_WIRE)
- return "Shock"
-
- if(AUTOLATHE_DISABLE_WIRE)
- return "Disable"
+/datum/wires/autolathe/New(atom/_holder)
+ wires = list(WIRE_AUTOLATHE_HACK, WIRE_ELECTRIFY, WIRE_AUTOLATHE_DISABLE)
+ return ..()
/datum/wires/autolathe/get_status()
. = ..()
@@ -24,51 +16,38 @@
. += "The green light is [A.shocked ? "off" : "on"]."
. += "The blue light is [A.hacked ? "off" : "on"]."
-/datum/wires/autolathe/CanUse()
+/datum/wires/autolathe/interactable(mob/user)
var/obj/machinery/autolathe/A = holder
+ if(iscarbon(user) && A.Adjacent(user) && A.shocked && A.shock(user, 100))
+ return FALSE
if(A.panel_open)
- return 1
- return 0
+ return TRUE
+ return FALSE
-/datum/wires/autolathe/UpdateCut(index, mended)
+/datum/wires/autolathe/on_cut(wire, mend)
var/obj/machinery/autolathe/A = holder
- switch(index)
- if(AUTOLATHE_HACK_WIRE)
- A.adjust_hacked(!mended)
- if(AUTOLATHE_SHOCK_WIRE)
- A.shocked = !mended
- if(AUTOLATHE_DISABLE_WIRE)
- A.disabled = !mended
+ switch(wire)
+ if(WIRE_AUTOLATHE_HACK)
+ A.adjust_hacked(!mend)
+ if(WIRE_ELECTRIFY)
+ A.shocked = !mend
+ if(WIRE_AUTOLATHE_DISABLE)
+ A.disabled = !mend
..()
-/datum/wires/autolathe/UpdatePulsed(index)
- if(IsIndexCut(index))
+/datum/wires/autolathe/on_pulse(wire)
+ if(is_cut(wire))
return
var/obj/machinery/autolathe/A = holder
- switch(index)
- if(AUTOLATHE_HACK_WIRE)
+ switch(wire)
+ if(WIRE_AUTOLATHE_HACK)
A.adjust_hacked(!A.hacked)
- updateUIs()
- spawn(50)
- if(A && !IsIndexCut(index))
- A.adjust_hacked(0)
- updateUIs()
- if(AUTOLATHE_SHOCK_WIRE)
- A.shocked = !A.shocked
- updateUIs()
- spawn(50)
- if(A && !IsIndexCut(index))
- A.shocked = 0
- updateUIs()
- if(AUTOLATHE_DISABLE_WIRE)
- A.disabled = !A.disabled
- updateUIs()
- spawn(50)
- if(A && !IsIndexCut(index))
- A.disabled = 0
- updateUIs()
+ addtimer(CALLBACK(A, /obj/machinery/autolathe/.proc/check_hacked_callback), 5 SECONDS)
-/datum/wires/autolathe/proc/updateUIs()
- SSnanoui.update_uis(src)
- if(holder)
- SSnanoui.update_uis(holder)
+ if(WIRE_ELECTRIFY)
+ A.shocked = !A.shocked
+ addtimer(CALLBACK(A, /obj/machinery/autolathe/.proc/check_electrified_callback), 5 SECONDS)
+
+ if(WIRE_AUTOLATHE_DISABLE)
+ A.disabled = !A.disabled
+ addtimer(CALLBACK(A, /obj/machinery/autolathe/.proc/check_disabled_callback), 5 SECONDS)
diff --git a/code/datums/wires/camera.dm b/code/datums/wires/camera.dm
index a6b1549fbe1..39e0cb2c3e1 100644
--- a/code/datums/wires/camera.dm
+++ b/code/datums/wires/camera.dm
@@ -1,9 +1,15 @@
// Wires for cameras.
/datum/wires/camera
- random = 0
holder_type = /obj/machinery/camera
wire_count = 2
+ proper_name = "Camera"
+ window_x = 350
+ window_y = 95
+
+/datum/wires/camera/New(atom/_holder)
+ wires = list(WIRE_FOCUS, WIRE_MAIN_POWER1)
+ return ..()
/datum/wires/camera/get_status()
. = ..()
@@ -11,51 +17,40 @@
. += "The focus light is [(C.view_range == initial(C.view_range)) ? "on" : "off"]."
. += "The power link light is [C.can_use() ? "on" : "off"]."
-/datum/wires/camera/CanUse(mob/living/L)
+/datum/wires/camera/interactable(mob/user)
var/obj/machinery/camera/C = holder
if(!C.panel_open)
return FALSE
return TRUE
-#define CAMERA_WIRE_FOCUS 1
-#define CAMERA_WIRE_POWER 2
-
-/datum/wires/camera/GetWireName(index)
- switch(index)
- if(CAMERA_WIRE_FOCUS)
- return "Focus"
-
- if(CAMERA_WIRE_POWER)
- return "Power"
-
-/datum/wires/camera/UpdateCut(index, mended)
+/datum/wires/camera/on_cut(wire, mend)
var/obj/machinery/camera/C = holder
- switch(index)
- if(CAMERA_WIRE_FOCUS)
- var/range = (mended ? initial(C.view_range) : C.short_range)
+ switch(wire)
+ if(WIRE_FOCUS)
+ var/range = (mend ? initial(C.view_range) : C.short_range)
C.setViewRange(range)
- if(CAMERA_WIRE_POWER)
- if(C.status && !mended || !C.status && mended)
+ if(WIRE_MAIN_POWER1)
+ if(C.status && !mend || !C.status && mend)
C.toggle_cam(usr, TRUE)
C.obj_integrity = C.max_integrity //this is a pretty simplistic way to heal the camera, but there's no reason for this to be complex.
..()
-/datum/wires/camera/UpdatePulsed(index)
+/datum/wires/camera/on_pulse(wire)
var/obj/machinery/camera/C = holder
- if(IsIndexCut(index))
+ if(is_cut(wire))
return
- switch(index)
- if(CAMERA_WIRE_FOCUS)
+ switch(wire)
+ if(WIRE_FOCUS)
var/new_range = (C.view_range == initial(C.view_range) ? C.short_range : initial(C.view_range))
C.setViewRange(new_range)
- if(CAMERA_WIRE_POWER)
+ if(WIRE_MAIN_POWER1)
C.toggle_cam(null) // Deactivate the camera
..()
/datum/wires/camera/proc/CanDeconstruct()
- if(IsIndexCut(CAMERA_WIRE_POWER) && IsIndexCut(CAMERA_WIRE_FOCUS))
+ if(is_cut(WIRE_MAIN_POWER1) && is_cut(WIRE_FOCUS))
return TRUE
else
return FALSE
diff --git a/code/datums/wires/explosive.dm b/code/datums/wires/explosive.dm
index 47fd627d597..988aa0f37a8 100644
--- a/code/datums/wires/explosive.dm
+++ b/code/datums/wires/explosive.dm
@@ -1,36 +1,36 @@
/datum/wires/explosive
wire_count = 1
+ proper_name = "Explosive"
+ window_x = 320
+ window_y = 50
-#define WIRE_EXPLODE 1
-
-/datum/wires/explosive/GetWireName(index)
- switch(index)
- if(WIRE_EXPLODE)
- return "Explode"
+/datum/wires/explosive/New(atom/_holder)
+ wires = list(WIRE_EXPLODE)
+ return ..()
/datum/wires/explosive/proc/explode()
return
-/datum/wires/explosive/UpdatePulsed(index)
- switch(index)
+/datum/wires/explosive/on_pulse(wire)
+ switch(wire)
if(WIRE_EXPLODE)
explode()
..()
-/datum/wires/explosive/UpdateCut(index, mended)
- switch(index)
+/datum/wires/explosive/on_cut(wire, mend)
+ switch(wire)
if(WIRE_EXPLODE)
- if(!mended)
+ if(!mend)
explode()
..()
/datum/wires/explosive/gibtonite
holder_type = /obj/item/twohanded/required/gibtonite
-/datum/wires/explosive/gibtonite/CanUse(mob/L)
- return 1
+/datum/wires/explosive/gibtonite/interactable(mob/user)
+ return TRUE
-/datum/wires/explosive/gibtonite/UpdateCut(index, mended)
+/datum/wires/explosive/gibtonite/on_cut(wire, mend)
return
/datum/wires/explosive/gibtonite/explode()
diff --git a/code/datums/wires/mulebot.dm b/code/datums/wires/mulebot.dm
index 988b520854f..cb13b0d6718 100644
--- a/code/datums/wires/mulebot.dm
+++ b/code/datums/wires/mulebot.dm
@@ -1,90 +1,35 @@
/datum/wires/mulebot
- random = 1
+ randomize = TRUE
holder_type = /mob/living/simple_animal/bot/mulebot
wire_count = 10
- window_x = 410
+ proper_name = "Mulebot"
+ window_x = 370
+ window_y = -12
-#define MULEBOT_WIRE_POWER1 1 // power connections
-#define MULEBOT_WIRE_POWER2 2
-#define MULEBOT_WIRE_AVOIDANCE 4 // mob avoidance
-#define MULEBOT_WIRE_LOADCHECK 8 // load checking (non-crate)
-#define MULEBOT_WIRE_MOTOR1 16 // motor wires
-#define MULEBOT_WIRE_MOTOR2 32 //
-#define MULEBOT_WIRE_REMOTE_RX 64 // remote recv functions
-#define MULEBOT_WIRE_REMOTE_TX 128 // remote trans status
-#define MULEBOT_WIRE_BEACON_RX 256 // beacon ping recv
+/datum/wires/mulebot/New(atom/_holder)
+ wires = list(
+ WIRE_MAIN_POWER1, WIRE_MAIN_POWER2, WIRE_MOB_AVOIDANCE,
+ WIRE_LOADCHECK, WIRE_MOTOR1, WIRE_MOTOR2,
+ WIRE_REMOTE_RX, WIRE_REMOTE_TX, WIRE_BEACON_RX
+ )
+ return ..()
-/datum/wires/mulebot/GetWireName(index)
- switch(index)
- if(MULEBOT_WIRE_POWER1)
- return "Primary Power"
-
- if(MULEBOT_WIRE_POWER2)
- return "Secondary Power"
-
- if(MULEBOT_WIRE_AVOIDANCE)
- return "Mob Avoidance"
-
- if(MULEBOT_WIRE_LOADCHECK)
- return "Load Checking"
-
- if(MULEBOT_WIRE_MOTOR1)
- return "Primary Motor"
-
- if(MULEBOT_WIRE_MOTOR2)
- return "Secondary Motor"
-
- if(MULEBOT_WIRE_REMOTE_RX)
- return "Remote Signal Receiver"
-
- if(MULEBOT_WIRE_REMOTE_TX)
- return "Remote Signal Sender"
-
- if(MULEBOT_WIRE_BEACON_RX)
- return "Navigation Beacon Receiver"
-
-/datum/wires/mulebot/CanUse(mob/living/L)
+/datum/wires/mulebot/interactable(mob/user)
var/mob/living/simple_animal/bot/mulebot/M = holder
if(M.open)
- return 1
- return 0
+ return TRUE
+ return FALSE
-/datum/wires/mulebot/UpdatePulsed(index)
- switch(index)
- if(MULEBOT_WIRE_POWER1, MULEBOT_WIRE_POWER2)
+/datum/wires/mulebot/on_pulse(wire)
+ switch(wire)
+ if(WIRE_MAIN_POWER1, WIRE_MAIN_POWER2)
holder.visible_message("[bicon(holder)] The charge light flickers.")
- if(MULEBOT_WIRE_AVOIDANCE)
+ if(WIRE_MOB_AVOIDANCE)
holder.visible_message("[bicon(holder)] The external warning lights flash briefly.")
- if(MULEBOT_WIRE_LOADCHECK)
+ if(WIRE_LOADCHECK)
holder.visible_message("[bicon(holder)] The load platform clunks.")
- if(MULEBOT_WIRE_MOTOR1, MULEBOT_WIRE_MOTOR2)
+ if(WIRE_MOTOR1, WIRE_MOTOR2)
holder.visible_message("[bicon(holder)] The drive motor whines briefly.")
else
holder.visible_message("[bicon(holder)] You hear a radio crackle.")
..()
-
-// HELPER PROCS
-
-/datum/wires/mulebot/proc/Motor1()
- return !(wires_status & MULEBOT_WIRE_MOTOR1)
-
-/datum/wires/mulebot/proc/Motor2()
- return !(wires_status & MULEBOT_WIRE_MOTOR2)
-
-/datum/wires/mulebot/proc/HasPower()
- return !(wires_status & MULEBOT_WIRE_POWER1) && !(wires_status & MULEBOT_WIRE_POWER2)
-
-/datum/wires/mulebot/proc/LoadCheck()
- return !(wires_status & MULEBOT_WIRE_LOADCHECK)
-
-/datum/wires/mulebot/proc/MobAvoid()
- return !(wires_status & MULEBOT_WIRE_AVOIDANCE)
-
-/datum/wires/mulebot/proc/RemoteTX()
- return !(wires_status & MULEBOT_WIRE_REMOTE_TX)
-
-/datum/wires/mulebot/proc/RemoteRX()
- return !(wires_status & MULEBOT_WIRE_REMOTE_RX)
-
-/datum/wires/mulebot/proc/BeaconRX()
- return !(wires_status & MULEBOT_WIRE_BEACON_RX)
diff --git a/code/datums/wires/nuclearbomb.dm b/code/datums/wires/nuclearbomb.dm
index 3b8ff5db098..51918c02ff4 100644
--- a/code/datums/wires/nuclearbomb.dm
+++ b/code/datums/wires/nuclearbomb.dm
@@ -1,28 +1,20 @@
/datum/wires/nuclearbomb
holder_type = /obj/machinery/nuclearbomb
- random = 1
- wire_count = 7
+ randomize = TRUE
+ wire_count = 7 // 3 actual, 4 duds.
+ proper_name = "Nuclear bomb"
+ window_x = 345
+ window_y = 75
-#define NUCLEARBOMB_WIRE_LIGHT 1
-#define NUCLEARBOMB_WIRE_TIMING 2
-#define NUCLEARBOMB_WIRE_SAFETY 4
+/datum/wires/nuclearbomb/New(atom/_holder)
+ wires = list(WIRE_BOMB_LIGHT, WIRE_BOMB_TIMING, WIRE_BOMB_SAFETY)
+ return ..()
-/datum/wires/nuclearbomb/GetWireName(index)
- switch(index)
- if(NUCLEARBOMB_WIRE_LIGHT)
- return "Bomb Light"
-
- if(NUCLEARBOMB_WIRE_TIMING)
- return "Bomb Timing"
-
- if(NUCLEARBOMB_WIRE_SAFETY)
- return "Bomb Safety"
-
-/datum/wires/nuclearbomb/CanUse(mob/living/L)
+/datum/wires/nuclearbomb/interactable(mob/user)
var/obj/machinery/nuclearbomb/N = holder
if(N.panel_open)
- return 1
- return 0
+ return TRUE
+ return FALSE
/datum/wires/nuclearbomb/get_status()
. = ..()
@@ -31,52 +23,36 @@
. += "The device is is [N.safety ? "quiet" : "whirring"]."
. += "The lights are [N.lighthack ? "static" : "functional"]."
-/datum/wires/nuclearbomb/UpdatePulsed(index)
+/datum/wires/nuclearbomb/on_pulse(wire)
var/obj/machinery/nuclearbomb/N = holder
- switch(index)
- if(NUCLEARBOMB_WIRE_LIGHT)
+ switch(wire)
+ if(WIRE_BOMB_LIGHT)
N.lighthack = !N.lighthack
- updateUIs()
- spawn(100)
- N.lighthack = !N.lighthack
- updateUIs()
- if(NUCLEARBOMB_WIRE_TIMING)
+ addtimer(CALLBACK(N, /obj/machinery/nuclearbomb/.proc/reset_lighthack_callback), 10 SECONDS)
+
+ if(WIRE_BOMB_TIMING)
if(N.timing)
message_admins("[key_name_admin(usr)] pulsed a nuclear bomb's detonation wire, causing it to explode (JMP)")
N.explode()
- if(NUCLEARBOMB_WIRE_SAFETY)
- N.safety = !N.safety
- updateUIs()
- spawn(100)
- N.safety = !N.safety
- if(N.safety == 1)
- if(!N.is_syndicate)
- set_security_level(N.previous_level)
- N.visible_message("The [N] quiets down.")
- if(!N.lighthack)
- if(N.icon_state == "nuclearbomb2")
- N.icon_state = "nuclearbomb1"
- else
- N.visible_message("The [N] emits a quiet whirling noise!")
- updateUIs()
-/datum/wires/nuclearbomb/UpdateCut(index, mended)
+ if(WIRE_BOMB_SAFETY)
+ N.safety = !N.safety
+ addtimer(CALLBACK(N, /obj/machinery/nuclearbomb/.proc/reset_safety_callback), 10 SECONDS)
+
+/datum/wires/nuclearbomb/on_cut(wire, mend)
var/obj/machinery/nuclearbomb/N = holder
- switch(index)
- if(NUCLEARBOMB_WIRE_SAFETY)
+ switch(wire)
+ if(WIRE_BOMB_SAFETY)
if(N.timing)
message_admins("[key_name_admin(usr)] cut a nuclear bomb's timing wire, causing it to explode (JMP)")
N.explode()
- if(NUCLEARBOMB_WIRE_TIMING)
+
+ if(WIRE_BOMB_TIMING)
if(!N.lighthack)
if(N.icon_state == "nuclearbomb2")
N.icon_state = "nuclearbomb1"
N.timing = 0
- GLOB.bomb_set = 0
- if(NUCLEARBOMB_WIRE_LIGHT)
- N.lighthack = !N.lighthack
+ GLOB.bomb_set = FALSE
-/datum/wires/nuclearbomb/proc/updateUIs()
- SSnanoui.update_uis(src)
- if(holder)
- SSnanoui.update_uis(holder)
+ if(WIRE_BOMB_LIGHT)
+ N.lighthack = !N.lighthack
diff --git a/code/datums/wires/particle_accelerator.dm b/code/datums/wires/particle_accelerator.dm
index d6e68a79cfb..e285f4cf898 100644
--- a/code/datums/wires/particle_accelerator.dm
+++ b/code/datums/wires/particle_accelerator.dm
@@ -1,67 +1,52 @@
/datum/wires/particle_acc/control_box
wire_count = 5
holder_type = /obj/machinery/particle_accelerator/control_box
+ proper_name = "Particle accelerator control"
+ window_x = 361
+ window_y = 22
-#define PARTICLE_TOGGLE_WIRE 1 // Toggles whether the PA is on or not.
-#define PARTICLE_STRENGTH_WIRE 2 // Determines the strength of the PA.
-#define PARTICLE_INTERFACE_WIRE 4 // Determines the interface showing up.
-#define PARTICLE_LIMIT_POWER_WIRE 8 // Determines how strong the PA can be.
+/datum/wires/particle_acc/control_box/New(atom/_holder)
+ wires = list(WIRE_PARTICLE_POWER, WIRE_PARTICLE_STRENGTH, WIRE_PARTICLE_INTERFACE, WIRE_PARTICLE_POWER_LIMIT)
+ return ..()
-/datum/wires/particle_acc/control_box/GetWireName(index)
- switch(index)
- if(PARTICLE_TOGGLE_WIRE)
- return "Power Toggle"
-
- if(PARTICLE_STRENGTH_WIRE)
- return "Strength"
-
- if(PARTICLE_INTERFACE_WIRE)
- return "Interface"
-
- if(PARTICLE_LIMIT_POWER_WIRE)
- return "Maximum Power"
-
-/datum/wires/particle_acc/control_box/CanUse(mob/living/L)
+/datum/wires/particle_acc/control_box/interactable(mob/user)
var/obj/machinery/particle_accelerator/control_box/C = holder
if(C.construction_state == 2)
- return 1
- return 0
+ return TRUE
+ return FALSE
-/datum/wires/particle_acc/control_box/UpdatePulsed(index)
+/datum/wires/particle_acc/control_box/on_pulse(wire)
var/obj/machinery/particle_accelerator/control_box/C = holder
- switch(index)
-
- if(PARTICLE_TOGGLE_WIRE)
+ switch(wire)
+ if(WIRE_PARTICLE_POWER)
C.toggle_power()
- if(PARTICLE_STRENGTH_WIRE)
+ if(WIRE_PARTICLE_STRENGTH)
C.add_strength()
- if(PARTICLE_INTERFACE_WIRE)
+ if(WIRE_PARTICLE_INTERFACE)
C.interface_control = !C.interface_control
- if(PARTICLE_LIMIT_POWER_WIRE)
+ if(WIRE_PARTICLE_POWER_LIMIT)
C.visible_message("[bicon(C)][C] makes a large whirring noise.")
..()
-/datum/wires/particle_acc/control_box/UpdateCut(index, mended)
+/datum/wires/particle_acc/control_box/on_cut(wire, mend)
var/obj/machinery/particle_accelerator/control_box/C = holder
- switch(index)
-
- if(PARTICLE_TOGGLE_WIRE)
- if(C.active == !mended)
+ switch(wire)
+ if(WIRE_PARTICLE_POWER)
+ if(C.active == !mend)
C.toggle_power()
- if(PARTICLE_STRENGTH_WIRE)
-
- for(var/i = 1; i < 3; i++)
+ if(WIRE_PARTICLE_STRENGTH)
+ for(var/i in 1 to 2)
C.remove_strength()
- if(PARTICLE_INTERFACE_WIRE)
- C.interface_control = mended
+ if(WIRE_PARTICLE_INTERFACE)
+ C.interface_control = mend
- if(PARTICLE_LIMIT_POWER_WIRE)
- C.strength_upper_limit = (mended ? 2 : 3)
+ if(WIRE_PARTICLE_POWER_LIMIT)
+ C.strength_upper_limit = (mend ? 2 : 3)
if(C.strength_upper_limit < C.strength)
C.remove_strength()
..()
diff --git a/code/datums/wires/radio.dm b/code/datums/wires/radio.dm
index 90a72935c53..1efee71692d 100644
--- a/code/datums/wires/radio.dm
+++ b/code/datums/wires/radio.dm
@@ -1,52 +1,44 @@
/datum/wires/radio
holder_type = /obj/item/radio
wire_count = 3
+ proper_name = "Radio"
+ window_x = 330
+ window_y = 37
-#define RADIO_WIRE_SIGNAL 1
-#define RADIO_WIRE_RECEIVE 2
-#define RADIO_WIRE_TRANSMIT 4
+/datum/wires/radio/New(atom/_holder)
+ wires = list(WIRE_RADIO_SIGNAL, WIRE_RADIO_RECEIVER, WIRE_RADIO_TRANSMIT)
+ return ..()
-/datum/wires/radio/GetWireName(index)
- switch(index)
- if(RADIO_WIRE_SIGNAL)
- return "Signal"
-
- if(RADIO_WIRE_RECEIVE)
- return "Receiver"
-
- if(RADIO_WIRE_TRANSMIT)
- return "Transmitter"
-
-/datum/wires/radio/CanUse(mob/living/L)
+/datum/wires/radio/interactable(mob/user)
var/obj/item/radio/R = holder
if(R.b_stat)
- return 1
- return 0
+ return TRUE
+ return FALSE
-/datum/wires/radio/UpdatePulsed(index)
+/datum/wires/radio/on_pulse(wire)
var/obj/item/radio/R = holder
- switch(index)
- if(RADIO_WIRE_SIGNAL)
- R.listening = !R.listening && !IsIndexCut(RADIO_WIRE_RECEIVE)
- R.broadcasting = R.listening && !IsIndexCut(RADIO_WIRE_TRANSMIT)
+ switch(wire)
+ if(WIRE_RADIO_SIGNAL)
+ R.listening = !R.listening && !is_cut(WIRE_RADIO_RECEIVER)
+ R.broadcasting = R.listening && !is_cut(WIRE_RADIO_TRANSMIT)
- if(RADIO_WIRE_RECEIVE)
- R.listening = !R.listening && !IsIndexCut(RADIO_WIRE_SIGNAL)
+ if(WIRE_RADIO_RECEIVER)
+ R.listening = !R.listening && !is_cut(WIRE_RADIO_SIGNAL)
- if(RADIO_WIRE_TRANSMIT)
- R.broadcasting = !R.broadcasting && !IsIndexCut(RADIO_WIRE_SIGNAL)
+ if(WIRE_RADIO_TRANSMIT)
+ R.broadcasting = !R.broadcasting && !is_cut(WIRE_RADIO_SIGNAL)
..()
-/datum/wires/radio/UpdateCut(index, mended)
+/datum/wires/radio/on_cut(wire, mend)
var/obj/item/radio/R = holder
- switch(index)
- if(RADIO_WIRE_SIGNAL)
- R.listening = mended && !IsIndexCut(RADIO_WIRE_RECEIVE)
- R.broadcasting = mended && !IsIndexCut(RADIO_WIRE_TRANSMIT)
+ switch(wire)
+ if(WIRE_RADIO_SIGNAL)
+ R.listening = mend && !is_cut(WIRE_RADIO_RECEIVER)
+ R.broadcasting = mend && !is_cut(WIRE_RADIO_TRANSMIT)
- if(RADIO_WIRE_RECEIVE)
- R.listening = mended && !IsIndexCut(RADIO_WIRE_SIGNAL)
+ if(WIRE_RADIO_RECEIVER)
+ R.listening = mend && !is_cut(WIRE_RADIO_SIGNAL)
- if(RADIO_WIRE_TRANSMIT)
- R.broadcasting = mended && !IsIndexCut(RADIO_WIRE_SIGNAL)
+ if(WIRE_RADIO_TRANSMIT)
+ R.broadcasting = mend && !is_cut(WIRE_RADIO_SIGNAL)
..()
diff --git a/code/datums/wires/robot.dm b/code/datums/wires/robot.dm
index 04a9509cfe2..927980c57fa 100644
--- a/code/datums/wires/robot.dm
+++ b/code/datums/wires/robot.dm
@@ -1,32 +1,14 @@
/datum/wires/robot
- random = 1
+ randomize = TRUE
holder_type = /mob/living/silicon/robot
wire_count = 5
+ window_x = 340
+ window_y = 106
+ proper_name = "Cyborg"
-// /vg/ ordering
-
-#define BORG_WIRE_MAIN_POWER 1 // The power wires do nothing whyyyyyyyyyyyyy
-#define BORG_WIRE_LOCKED_DOWN 2
-#define BORG_WIRE_CAMERA 4
-#define BORG_WIRE_AI_CONTROL 8 // Not used on MoMMIs
-#define BORG_WIRE_LAWCHECK 16 // Not used on MoMMIs
-
-/datum/wires/robot/GetWireName(index)
- switch(index)
- if(BORG_WIRE_MAIN_POWER)
- return "Main Power"
-
- if(BORG_WIRE_LOCKED_DOWN)
- return "Lockdown"
-
- if(BORG_WIRE_CAMERA)
- return "Camera"
-
- if(BORG_WIRE_AI_CONTROL)
- return "AI Control"
-
- if(BORG_WIRE_LAWCHECK)
- return "Law Check"
+/datum/wires/robot/New(atom/_holder)
+ wires = list(WIRE_AI_CONTROL, WIRE_BORG_CAMERA, WIRE_BORG_LAWCHECK, WIRE_BORG_LOCKED)
+ return ..()
/datum/wires/robot/get_status()
. = ..()
@@ -36,70 +18,53 @@
. += "The Camera light is [(R.camera && R.camera.status == 1) ? "on" : "off"]."
. += "The lockdown light is [R.lockcharge ? "on" : "off"]."
-/datum/wires/robot/UpdateCut(index, mended)
-
+/datum/wires/robot/on_cut(wire, mend)
var/mob/living/silicon/robot/R = holder
- switch(index)
- if(BORG_WIRE_LAWCHECK) //Cut the law wire, and the borg will no longer receive law updates from its AI
- if(!mended)
- if(R.lawupdate == 1)
+ switch(wire)
+ if(WIRE_BORG_LAWCHECK) //Cut the law wire, and the borg will no longer receive law updates from its AI
+ if(!mend)
+ if(R.lawupdate)
to_chat(R, "LawSync protocol engaged.")
+ R.lawsync()
R.show_laws()
else
- if(R.lawupdate == 0 && !R.emagged)
- R.lawupdate = 1
+ if(!R.lawupdate && !R.emagged)
+ R.lawupdate = TRUE
- if(BORG_WIRE_AI_CONTROL) //Cut the AI wire to reset AI control
- if(!mended)
+ if(WIRE_AI_CONTROL) //Cut the AI wire to reset AI control
+ if(!mend)
if(R.connected_ai)
R.disconnect_from_ai()
- if(BORG_WIRE_CAMERA)
+ if(WIRE_BORG_CAMERA)
if(!isnull(R.camera) && !R.scrambledcodes)
- R.camera.status = mended
+ R.camera.status = mend
R.camera.toggle_cam(usr, 0) // Will kick anyone who is watching the Cyborg's camera.
- if(BORG_WIRE_LAWCHECK) //Forces a law update if the borg is set to receive them. Since an update would happen when the borg checks its laws anyway, not much use, but eh
- if(R.lawupdate)
- R.lawsync()
-
- if(BORG_WIRE_LOCKED_DOWN)
- R.SetLockdown(!mended)
+ if(WIRE_BORG_LOCKED)
+ R.SetLockdown(!mend)
..()
-/datum/wires/robot/UpdatePulsed(index)
-
+/datum/wires/robot/on_pulse(wire)
var/mob/living/silicon/robot/R = holder
- switch(index)
- if(BORG_WIRE_AI_CONTROL) //pulse the AI wire to make the borg reselect an AI
+ switch(wire)
+ if(WIRE_AI_CONTROL) //pulse the AI wire to make the borg reselect an AI
if(!R.emagged)
R.connect_to_ai(select_active_ai())
- if(BORG_WIRE_CAMERA)
+ if(WIRE_BORG_CAMERA)
if(!isnull(R.camera) && R.camera.can_use() && !R.scrambledcodes)
R.camera.toggle_cam(usr, 0) // Kick anyone watching the Cyborg's camera, doesn't display you disconnecting the camera.
R.visible_message("[R]'s camera lense focuses loudly.")
to_chat(R, "Your camera lense focuses loudly.")
- if(BORG_WIRE_LOCKED_DOWN)
+ if(WIRE_BORG_LOCKED)
R.SetLockdown(!R.lockcharge) // Toggle
..()
-/datum/wires/robot/CanUse(mob/living/L)
+/datum/wires/robot/interactable(mob/user)
var/mob/living/silicon/robot/R = holder
if(R.wiresexposed)
- return 1
- return 0
-
-/datum/wires/robot/proc/IsCameraCut()
- return wires_status & BORG_WIRE_CAMERA
-
-/datum/wires/robot/proc/LockedCut()
- return wires_status & BORG_WIRE_LOCKED_DOWN
-
-/datum/wires/robot/proc/CanLawCheck()
- return wires_status & BORG_WIRE_LAWCHECK
-
-/datum/wires/robot/proc/AIHasControl()
- return wires_status & BORG_WIRE_AI_CONTROL
+ return TRUE
+ return FALSE
diff --git a/code/datums/wires/smartfridge.dm b/code/datums/wires/smartfridge.dm
index a65377ead1a..3955b1849b0 100644
--- a/code/datums/wires/smartfridge.dm
+++ b/code/datums/wires/smartfridge.dm
@@ -1,35 +1,26 @@
/datum/wires/smartfridge
holder_type = /obj/machinery/smartfridge
wire_count = 3
+ proper_name = "Smartfridge"
+ window_x = 340
+ window_y = 103
+
+/datum/wires/smartfridge/New(atom/_holder)
+ wires = list(WIRE_ELECTRIFY, WIRE_IDSCAN, WIRE_THROW_ITEM)
+ return ..()
/datum/wires/smartfridge/secure
- random = 1
- wire_count = 4
+ randomize = TRUE
+ wire_count = 4 // 3 actual, 1 dud.
+ window_y = 97
-#define SMARTFRIDGE_WIRE_ELECTRIFY 1
-#define SMARTFRIDGE_WIRE_THROW 2
-#define SMARTFRIDGE_WIRE_IDSCAN 4
-
-/datum/wires/smartfridge/GetWireName(index)
- switch(index)
- if(SMARTFRIDGE_WIRE_ELECTRIFY)
- return "Electrification"
-
- if(SMARTFRIDGE_WIRE_THROW)
- return "Item Throw"
-
- if(SMARTFRIDGE_WIRE_IDSCAN)
- return "ID Scan"
-
-/datum/wires/smartfridge/CanUse(mob/living/L)
+/datum/wires/smartfridge/interactable(mob/user)
var/obj/machinery/smartfridge/S = holder
- if(!issilicon(L))
- if(S.seconds_electrified)
- if(S.shock(L, 100))
- return 0
+ if(iscarbon(user) && S.Adjacent(user) && S.seconds_electrified && S.shock(user, 100))
+ return FALSE
if(S.panel_open)
- return 1
- return 0
+ return TRUE
+ return FALSE
/datum/wires/smartfridge/get_status()
. = ..()
@@ -38,27 +29,27 @@
. += "The red light is [S.shoot_inventory ? "off" : "blinking"]."
. += "A [S.scan_id ? "purple" : "yellow"] light is on."
-/datum/wires/smartfridge/UpdatePulsed(index)
+/datum/wires/smartfridge/on_pulse(wire)
var/obj/machinery/smartfridge/S = holder
- switch(index)
- if(SMARTFRIDGE_WIRE_THROW)
+ switch(wire)
+ if(WIRE_THROW_ITEM)
S.shoot_inventory = !S.shoot_inventory
- if(SMARTFRIDGE_WIRE_ELECTRIFY)
+ if(WIRE_ELECTRIFY)
S.seconds_electrified = 30
- if(SMARTFRIDGE_WIRE_IDSCAN)
+ if(WIRE_IDSCAN)
S.scan_id = !S.scan_id
..()
-/datum/wires/smartfridge/UpdateCut(index, mended)
+/datum/wires/smartfridge/on_cut(wire, mend)
var/obj/machinery/smartfridge/S = holder
- switch(index)
- if(SMARTFRIDGE_WIRE_THROW)
- S.shoot_inventory = !mended
- if(SMARTFRIDGE_WIRE_ELECTRIFY)
- if(mended)
+ switch(wire)
+ if(WIRE_THROW_ITEM)
+ S.shoot_inventory = !mend
+ if(WIRE_ELECTRIFY)
+ if(mend)
S.seconds_electrified = 0
else
S.seconds_electrified = -1
- if(SMARTFRIDGE_WIRE_IDSCAN)
- S.scan_id = 1
+ if(WIRE_IDSCAN)
+ S.scan_id = TRUE
..()
diff --git a/code/datums/wires/suitstorage.dm b/code/datums/wires/suitstorage.dm
index 175b36e6081..828e56884bf 100644
--- a/code/datums/wires/suitstorage.dm
+++ b/code/datums/wires/suitstorage.dm
@@ -1,24 +1,13 @@
/datum/wires/suitstorage
holder_type = /obj/machinery/suit_storage_unit
wire_count = 8
+ proper_name = "Suit storage unit"
+ window_x = 350
+ window_y = 85
-#define SSU_WIRE_ID 1
-#define SSU_WIRE_SHOCK 2
-#define SSU_WIRE_SAFETY 4
-#define SSU_WIRE_UV 8
-
-
-/datum/wires/suitstorage/GetWireName(index)
- switch(index)
- if(SSU_WIRE_ID)
- return "ID lock"
- if(SSU_WIRE_SHOCK)
- return "Shock wire"
- if(SSU_WIRE_SAFETY)
- return "Safety wire"
- if(SSU_WIRE_UV)
- return "UV wire"
-
+/datum/wires/suitstorage/New(atom/_holder)
+ wires = list(WIRE_IDSCAN, WIRE_ELECTRIFY, WIRE_SAFETY, WIRE_SSU_UV)
+ return ..()
/datum/wires/suitstorage/get_status()
. = ..()
@@ -28,42 +17,48 @@
. += "The green light is [A.shocked ? "on" : "off"]."
. += "The UV display shows [A.uv_super ? "15 nm" : "185 nm"]."
-datum/wires/suitstorage/CanUse()
+datum/wires/suitstorage/interactable(mob/user)
var/obj/machinery/suit_storage_unit/A = holder
+ if(iscarbon(user) && A.Adjacent(user) && A.shocked)
+ return A.shock(user, 100)
if(A.panel_open)
- return 1
- return 0
+ return TRUE
+ return FALSE
-/datum/wires/suitstorage/UpdateCut(index, mended)
+/datum/wires/suitstorage/on_cut(wire, mend)
var/obj/machinery/suit_storage_unit/A = holder
- switch(index)
- if(SSU_WIRE_ID)
- A.secure = mended
- if(SSU_WIRE_SAFETY)
- A.safeties = mended
- if(SSU_WIRE_SHOCK)
- A.shocked = !mended
+ switch(wire)
+ if(WIRE_IDSCAN)
+ A.secure = mend
+
+ if(WIRE_SAFETY)
+ A.safeties = mend
+
+ if(WIRE_ELECTRIFY)
+ A.shocked = !mend
A.shock(usr, 50)
- if(SSU_WIRE_UV)
- A.uv_super = !mended
+
+ if(WIRE_SSU_UV)
+ A.uv_super = !mend
..()
-datum/wires/suitstorage/UpdatePulsed(index)
+datum/wires/suitstorage/on_pulse(wire)
var/obj/machinery/suit_storage_unit/A = holder
- if(IsIndexCut(index))
+ if(is_cut(wire))
return
- switch(index)
- if(SSU_WIRE_ID)
+ switch(wire)
+ if(WIRE_IDSCAN)
A.secure = !A.secure
- if(SSU_WIRE_SAFETY)
+
+ if(WIRE_SAFETY)
A.safeties = !A.safeties
- if(SSU_WIRE_SHOCK)
+
+ if(WIRE_ELECTRIFY)
A.shocked = !A.shocked
if(A.shocked)
A.shock(usr, 100)
- spawn(50)
- if(A && !IsIndexCut(index))
- A.shocked = FALSE
- if(SSU_WIRE_UV)
+ addtimer(CALLBACK(A, /obj/machinery/suit_storage_unit/.proc/check_electrified_callback), 5 SECONDS)
+
+ if(WIRE_SSU_UV)
A.uv_super = !A.uv_super
..()
diff --git a/code/datums/wires/syndicatebomb.dm b/code/datums/wires/syndicatebomb.dm
index 430b5ce88aa..bd996f72fcc 100644
--- a/code/datums/wires/syndicatebomb.dm
+++ b/code/datums/wires/syndicatebomb.dm
@@ -1,47 +1,31 @@
/datum/wires/syndicatebomb
- random = TRUE
+ randomize = TRUE
holder_type = /obj/machinery/syndicatebomb
wire_count = 5
+ proper_name = "Syndicate bomb"
+ window_x = 320
+ window_y = 22
-#define BOMB_WIRE_BOOM 1 // Explodes if pulsed or cut while active, defuses a bomb that isn't active on cut
-#define BOMB_WIRE_UNBOLT 2 // Unbolts the bomb if cut, hint on pulsed
-#define BOMB_WIRE_DELAY 4 // Raises the timer on pulse, does nothing on cut
-#define BOMB_WIRE_PROCEED 8 // Lowers the timer, explodes if cut while the bomb is active
-#define BOMB_WIRE_ACTIVATE 16 // Will start a bombs timer if pulsed, will hint if pulsed while already active, will stop a timer a bomb on cut
+/datum/wires/syndicatebomb/New(atom/_holder)
+ wires = list(WIRE_BOMB_DELAY, WIRE_EXPLODE, WIRE_BOMB_UNBOLT,WIRE_BOMB_PROCEED, WIRE_BOMB_ACTIVATE)
+ return ..()
-/datum/wires/syndicatebomb/GetWireName(index)
- switch(index)
- if(BOMB_WIRE_BOOM)
- return "Explode"
-
- if(BOMB_WIRE_UNBOLT)
- return "Unbolt"
-
- if(BOMB_WIRE_DELAY)
- return "Delay"
-
- if(BOMB_WIRE_PROCEED)
- return "Proceed"
-
- if(BOMB_WIRE_ACTIVATE)
- return "Activate"
-
-/datum/wires/syndicatebomb/CanUse(mob/living/L)
+/datum/wires/syndicatebomb/interactable(mob/user)
var/obj/machinery/syndicatebomb/P = holder
if(P.open_panel)
return TRUE
return FALSE
-/datum/wires/syndicatebomb/UpdatePulsed(index)
+/datum/wires/syndicatebomb/on_pulse(wire)
var/obj/machinery/syndicatebomb/B = holder
- switch(index)
- if(BOMB_WIRE_BOOM)
+ switch(wire)
+ if(WIRE_EXPLODE)
if(B.active)
holder.visible_message("[bicon(B)] An alarm sounds! It's go-")
B.explode_now = TRUE
- if(BOMB_WIRE_UNBOLT)
+ if(WIRE_BOMB_UNBOLT)
holder.visible_message("[bicon(holder)] The bolts spin in place for a moment.")
- if(BOMB_WIRE_DELAY)
+ if(WIRE_BOMB_DELAY)
if(B.delayedbig)
holder.visible_message("[bicon(B)] The bomb has already been delayed.")
else
@@ -49,7 +33,7 @@
playsound(B, 'sound/machines/chime.ogg', 30, 1)
B.detonation_timer += 300
B.delayedbig = TRUE
- if(BOMB_WIRE_PROCEED)
+ if(WIRE_BOMB_PROCEED)
holder.visible_message("[bicon(B)] The bomb buzzes ominously!")
playsound(B, 'sound/machines/buzz-sigh.ogg', 30, 1)
var/seconds = B.seconds_remaining()
@@ -59,7 +43,7 @@
B.detonation_timer -= 100
else if(seconds >= 11) // Both to prevent negative timers and to have a little mercy.
B.detonation_timer = world.time + 100
- if(BOMB_WIRE_ACTIVATE)
+ if(WIRE_BOMB_ACTIVATE)
if(!B.active && !B.defused)
holder.visible_message("[bicon(B)] You hear the bomb start ticking!")
B.activate()
@@ -72,11 +56,11 @@
B.delayedlittle = TRUE
..()
-/datum/wires/syndicatebomb/UpdateCut(index, mended)
+/datum/wires/syndicatebomb/on_cut(wire, mend)
var/obj/machinery/syndicatebomb/B = holder
- switch(index)
- if(BOMB_WIRE_BOOM)
- if(mended)
+ switch(wire)
+ if(WIRE_EXPLODE)
+ if(mend)
B.defused = FALSE // Cutting and mending all the wires of an inactive bomb will thus cure any sabotage.
else
if(B.active)
@@ -84,17 +68,17 @@
B.explode_now = TRUE
else
B.defused = TRUE
- if(BOMB_WIRE_UNBOLT)
- if(!mended && B.anchored)
+ if(WIRE_BOMB_UNBOLT)
+ if(!mend && B.anchored)
holder.visible_message("[bicon(B)] The bolts lift out of the ground!")
playsound(B, 'sound/effects/stealthoff.ogg', 30, 1)
B.anchored = FALSE
- if(BOMB_WIRE_PROCEED)
- if(!mended && B.active)
+ if(WIRE_BOMB_PROCEED)
+ if(!mend && B.active)
holder.visible_message("[bicon(B)] An alarm sounds! It's go-")
B.explode_now = TRUE
- if(BOMB_WIRE_ACTIVATE)
- if(!mended && B.active)
+ if(WIRE_BOMB_ACTIVATE)
+ if(!mend && B.active)
holder.visible_message("[bicon(B)] The timer stops! The bomb has been defused!")
B.defused = TRUE
B.update_icon()
diff --git a/code/datums/wires/tesla_coil.dm b/code/datums/wires/tesla_coil.dm
index bc513c6c6c0..f4dbf39017a 100644
--- a/code/datums/wires/tesla_coil.dm
+++ b/code/datums/wires/tesla_coil.dm
@@ -1,23 +1,23 @@
/datum/wires/tesla_coil
wire_count = 1
holder_type = /obj/machinery/power/tesla_coil
+ proper_name = "Tesla coil"
+ window_x = 320
+ window_y = 50
-#define TESLACOIL_WIRE_ZAP 1
+/datum/wires/tesla_coil/New(atom/_holder)
+ wires = list(WIRE_TESLACOIL_ZAP)
+ return ..()
-/datum/wires/tesla_coil/GetWireName(index)
- switch(index)
- if(TESLACOIL_WIRE_ZAP)
- return "Zap"
-
-/datum/wires/tesla_coil/CanUse(mob/living/L)
+/datum/wires/tesla_coil/interactable(mob/user)
var/obj/machinery/power/tesla_coil/T = holder
if(T && T.panel_open)
- return 1
- return 0
+ return TRUE
+ return FALSE
-/datum/wires/tesla_coil/UpdatePulsed(index)
+/datum/wires/tesla_coil/on_pulse(wire)
var/obj/machinery/power/tesla_coil/T = holder
- switch(index)
- if(TESLACOIL_WIRE_ZAP)
+ switch(wire)
+ if(WIRE_TESLACOIL_ZAP)
T.zap()
..()
diff --git a/code/datums/wires/vending.dm b/code/datums/wires/vending.dm
index c9e6032afee..299e18d815a 100644
--- a/code/datums/wires/vending.dm
+++ b/code/datums/wires/vending.dm
@@ -1,35 +1,21 @@
/datum/wires/vending
holder_type = /obj/machinery/vending
wire_count = 4
+ window_y = 112
+ window_x = 350
+ proper_name = "Vending machine"
-#define VENDING_WIRE_THROW 1
-#define VENDING_WIRE_CONTRABAND 2
-#define VENDING_WIRE_ELECTRIFY 4
-#define VENDING_WIRE_IDSCAN 8
+/datum/wires/vending/New(atom/_holder)
+ wires = list(WIRE_THROW_ITEM, WIRE_IDSCAN, WIRE_ELECTRIFY, WIRE_CONTRABAND)
+ return ..()
-/datum/wires/vending/GetWireName(index)
- switch(index)
- if(VENDING_WIRE_THROW)
- return "Item Throw"
-
- if(VENDING_WIRE_CONTRABAND)
- return "Contraband"
-
- if(VENDING_WIRE_ELECTRIFY)
- return "Electrification"
-
- if(VENDING_WIRE_IDSCAN)
- return "ID Scan"
-
-/datum/wires/vending/CanUse(mob/living/L)
+/datum/wires/vending/interactable(mob/user)
var/obj/machinery/vending/V = holder
- if(!istype(L, /mob/living/silicon))
- if(V.seconds_electrified)
- if(V.shock(L, 100))
- return 0
+ if(!istype(user, /mob/living/silicon) && V.seconds_electrified && V.shock(user, 100))
+ return FALSE
if(V.panel_open)
- return 1
- return 0
+ return TRUE
+ return FALSE
/datum/wires/vending/get_status()
. = ..()
@@ -39,31 +25,31 @@
. += "The green light is [V.extended_inventory ? "on" : "off"]."
. += "A [V.scan_id ? "purple" : "yellow"] light is on."
-/datum/wires/vending/UpdatePulsed(index)
+/datum/wires/vending/on_pulse(wire)
var/obj/machinery/vending/V = holder
- switch(index)
- if(VENDING_WIRE_THROW)
+ switch(wire)
+ if(WIRE_THROW_ITEM)
V.shoot_inventory = !V.shoot_inventory
- if(VENDING_WIRE_CONTRABAND)
+ if(WIRE_CONTRABAND)
V.extended_inventory = !V.extended_inventory
- if(VENDING_WIRE_ELECTRIFY)
+ if(WIRE_ELECTRIFY)
V.seconds_electrified = 30
- if(VENDING_WIRE_IDSCAN)
+ if(WIRE_IDSCAN)
V.scan_id = !V.scan_id
..()
-/datum/wires/vending/UpdateCut(index, mended)
+/datum/wires/vending/on_cut(wire, mend)
var/obj/machinery/vending/V = holder
- switch(index)
- if(VENDING_WIRE_THROW)
- V.shoot_inventory = !mended
- if(VENDING_WIRE_CONTRABAND)
+ switch(wire)
+ if(WIRE_THROW_ITEM)
+ V.shoot_inventory = !mend
+ if(WIRE_CONTRABAND)
V.extended_inventory = FALSE
- if(VENDING_WIRE_ELECTRIFY)
- if(mended)
+ if(WIRE_ELECTRIFY)
+ if(mend)
V.seconds_electrified = 0
else
V.seconds_electrified = -1
- if(VENDING_WIRE_IDSCAN)
- V.scan_id = 1
+ if(WIRE_IDSCAN)
+ V.scan_id = TRUE
..()
diff --git a/code/datums/wires/wires.dm b/code/datums/wires/wires.dm
index 40aeda21b58..27d1448ac77 100644
--- a/code/datums/wires/wires.dm
+++ b/code/datums/wires/wires.dm
@@ -1,331 +1,456 @@
-// Wire datums. Created by Giacomand.
-// Was created to replace a horrible case of copy and pasted code with no care for maintability.
-// Goodbye Door wires, Cyborg wires, Vending Machine wires, Autolathe wires
-// Protolathe wires, APC wires and Camera wires!
-
-#define MAX_FLAG 65535
-
-GLOBAL_LIST_EMPTY(same_wires)
-// 12 colours, if you're adding more than 12 wires then add more colours here
-GLOBAL_LIST_INIT(wireColours, list("red", "blue", "green", "black", "orange", "brown", "gold", "gray", "cyan", "navy", "purple", "pink"))
/datum/wires
+ /// TRUE if the wires will be different every time a new wire datum is created.
+ var/randomize = FALSE
+ /// The atom the wires belong too. For example: an airlock.
+ var/atom/holder
+ /// The holder type; used to make sure that the holder is the correct type.
+ var/holder_type
+ /// The display name for the TGUI window. For example, given the var is "APC"...
+ /// When the TGUI window is opened, "wires" will be appended to it's title, and it would become "APC wires".
+ var/proper_name = "Unknown"
+ /// The total number of wires that our holder atom has.
+ var/wire_count = NONE
+ /// A list of all wires. For a list of valid wires defines that can go here, see `code/__DEFINES/wires.dm`
+ var/list/wires
+ /// A list of all cut wires. The same values that can go into `wires` will get added and removed from this list.
+ var/list/cut_wires
+ /// An associative list with the wire color as the key, and the wire define as the value.
+ var/list/colors
+ /// An associative list of signalers attached to the wires. The wire color is the key, and the signaler object reference is the value.
+ var/list/assemblies
+ /// The width of the wire TGUI window.
+ var/window_x = 300
+ /// The height of the wire TGUI window. Will get longer as needed, based on the `wire_count`.
+ var/window_y = 100
- var/random = 0 // Will the wires be different for every single instance.
- var/atom/holder = null // The holder
- var/holder_type = null // The holder type; used to make sure that the holder is the correct type.
- var/wire_count = 0 // Max is 16
- var/wires_status = 0 // BITFLAG OF WIRES
-
- var/list/wires = list()
- var/list/signallers = list()
-
- var/table_options = " align='center'"
- var/row_options1 = " width='80px'"
- var/row_options2 = " width='260px'"
- var/window_x = 370
- var/window_y = 470
-
-/datum/wires/New(atom/holder)
+/datum/wires/New(atom/_holder)
..()
- src.holder = holder
- if(!istype(holder, holder_type))
+ if(!istype(_holder, holder_type))
CRASH("Our holder is null/the wrong type!")
- // Generate new wires
- if(random)
- GenerateWires()
- // Get the same wires
+ holder = _holder
+ cut_wires = list()
+ colors = list()
+ assemblies = list()
+
+ // Add in the appropriate amount of dud wires.
+ var/wire_len = length(wires)
+ if(wire_len < wire_count) // If the amount of "real" wires is less than the total we're suppose to have...
+ add_duds(wire_count - wire_len) // Add in the appropriate amount of duds to reach `wire_count`.
+
+ // If the randomize is true, we need to generate a new set of wires and ignore any wire color directories.
+ if(randomize)
+ randomize()
+ return
+
+ if(!GLOB.wire_color_directory[holder_type])
+ randomize()
+ GLOB.wire_color_directory[holder_type] = colors
else
- // We don't have any wires to copy yet, generate some and then copy it.
- if(!GLOB.same_wires[holder_type])
- GenerateWires()
- GLOB.same_wires[holder_type] = src.wires.Copy()
- else
- var/list/wires = GLOB.same_wires[holder_type]
- src.wires = wires // Reference the wires list.
+ colors = GLOB.wire_color_directory[holder_type]
/datum/wires/Destroy()
holder = null
+ for(var/color in colors)
+ detach_assembly(color)
return ..()
-/datum/wires/proc/GenerateWires()
- var/list/colours_to_pick = GLOB.wireColours.Copy() // Get a copy, not a reference.
- var/list/indexes_to_pick = list()
- //Generate our indexes
- for(var/i = 1; i < MAX_FLAG && i < (1 << wire_count); i += i)
- indexes_to_pick += i
- colours_to_pick.len = wire_count // Downsize it to our specifications.
+/**
+ * Randomly generates a new set of wires. and corresponding colors from the given pool. Assigns the information as an associative list, to `colors`.
+ *
+ * In the `colors` list, the name of the color is the key, and the wire is the value.
+ * For example: `colors["red"] = WIRE_ELECTRIFY`. This will look like `list("red" = WIRE_ELECTRIFY)` internally.
+ */
+datum/wires/proc/randomize()
+ var/static/list/possible_colors = list("red", "blue", "green", "silver", "orange", "brown", "gold", "white", "cyan", "magenta", "purple", "pink")
+ var/list/my_possible_colors = possible_colors.Copy()
- while(colours_to_pick.len && indexes_to_pick.len)
- // Pick and remove a colour
- var/colour = pick_n_take(colours_to_pick)
-
- // Pick and remove an index
- var/index = pick_n_take(indexes_to_pick)
-
- src.wires[colour] = index
- //wires = shuffle(wires)
-
-/datum/wires/proc/get_status()
- return list()
+ for(var/wire in shuffle(wires))
+ colors[pick_n_take(my_possible_colors)] = wire
+/**
+ * Proc called when the user attempts to interact with wires UI.
+ *
+ * Checks if the user exists, is a mob, the wires are attached to something (`holder`) and makes sure `interactable(user)` returns TRUE.
+ * If all the checks succeed, open the TGUI interface for the user.
+ *
+ * Arugments:
+ * * user - the mob trying to interact with the wires.
+ */
/datum/wires/proc/Interact(mob/user)
- if(user && istype(user) && holder && CanUse(user))
- ui_interact(user)
+ if(user && istype(user) && holder && interactable(user))
+ tgui_interact(user)
-/datum/wires/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
+/**
+ * Base proc, intended to be overriden. Wire datum specific checks you want to run before the TGUI is shown to the user should go here.
+ */
+/datum/wires/proc/interactable(mob/user)
+ return TRUE
+
+/// Users will be interacting with our holder object and not the wire datum directly, therefore we need to return the holder.
+/datum/wires/tgui_host()
+ return holder
+
+/datum/wires/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_physical_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
- ui = new(user, src, ui_key, "wires.tmpl", holder.name, window_x, window_y)
+ ui = new(user, src, ui_key, "Wires", "[proper_name] wires", window_x, window_y + wire_count * 30, master_ui, state)
ui.open()
-/datum/wires/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.physical_state)
- var/data[0]
- var/list/replace_colours = null
+/datum/wires/tgui_data(mob/user)
+ var/list/data = list()
+ var/list/replace_colors
+
if(ishuman(user))
var/mob/living/carbon/human/H = user
var/obj/item/organ/internal/eyes/eyes = H.get_int_organ(/obj/item/organ/internal/eyes)
- if(eyes && (COLOURBLIND in H.mutations))
- replace_colours = eyes.replace_colours
+ if(eyes && (COLOURBLIND in H.mutations)) // Check if the human has colorblindness.
+ replace_colors = eyes.replace_colours // Get the colorblind replacement colors list.
+ var/list/wires_list = list()
- var/list/W[0]
- for(var/colour in wires)
- var/new_colour = colour
- var/colour_name = colour
- if(colour in replace_colours)
- new_colour = replace_colours[colour]
- if(new_colour in LIST_REPLACE_RENAME)
- colour_name = LIST_REPLACE_RENAME[new_colour]
+ for(var/color in colors)
+ var/replaced_color = color
+ var/color_name = color
+
+ if(color in replace_colors) // If this color is one that needs to be replaced using the colorblindness list.
+ replaced_color = replace_colors[color]
+ if(replaced_color in LIST_COLOR_RENAME) // If its an ugly written color name like "darkolivegreen", rename it to something like "dark green".
+ color_name = LIST_COLOR_RENAME[replaced_color]
else
- colour_name = new_colour
- else
- new_colour = colour
- colour_name = new_colour
- W[++W.len] = list("colour_name" = capitalize(colour_name), "seen_colour" = capitalize(new_colour),"colour" = capitalize(colour), "cut" = IsColourCut(colour), "index" = can_see_wire_index(user) ? GetWireName(GetIndex(colour)) : null, "attached" = IsAttached(colour))
+ color_name = replaced_color // Else just keep the normal color name
- if(W.len > 0)
- data["wires"] = W
+ wires_list += list(list(
+ "seen_color" = replaced_color, // The color of the wire that the mob will see. This will be the same as `color` if the user is NOT colorblind.
+ "color_name" = color_name, // The wire's name. This will be the same as `color` if the user is NOT colorblind.
+ "color" = color, // The "real" color of the wire. No replacements.
+ "wire" = can_see_wire_info(user) && !is_dud_color(color) ? get_wire(color) : null, // Wire define information like "Contraband" or "Door Bolts".
+ "cut" = is_color_cut(color), // Whether the wire is cut or not. Used to display "cut" or "mend".
+ "attached" = is_attached(color) // Whether or not a signaler is attached to this wire.
+ ))
+ data["wires"] = wires_list
+ // Get the information shown at the bottom of wire TGUI window, such as "The red light is blinking", etc.
+ // If the user is colorblind, we need to replace these colors as well.
var/list/status = get_status()
- if(replace_colours)
- var/i
- for(i=1, i<=status.len, i++)
- for(var/colour in replace_colours)
- var/new_colour = replace_colours[colour]
- if(new_colour in LIST_REPLACE_RENAME)
- new_colour = LIST_REPLACE_RENAME[new_colour]
- if(findtext(status[i],colour))
- status[i] = replacetext(status[i],colour,new_colour)
- break
- data["status_len"] = status.len
- data["status"] = status
+ if(replace_colors)
+ var/i
+ for(i in 1 to length(status))
+ for(var/color in replace_colors)
+ var/new_color = replace_colors[color]
+ if(new_color in LIST_COLOR_RENAME)
+ new_color = LIST_COLOR_RENAME[new_color]
+ if(findtext(status[i], color))
+ status[i] = replacetext(status[i], color, new_color)
+ break
+
+ data["status"] = status
return data
-/datum/wires/nano_host()
- return holder
+/datum/wires/tgui_act(action, list/params)
+ if(..())
+ return
-/datum/wires/proc/can_see_wire_index(mob/user)
+ var/mob/user = usr
+ if(!interactable(user))
+ return
+
+ var/obj/item/I = user.get_active_hand()
+ var/color = lowertext(params["wire"])
+ holder.add_hiddenprint(user)
+
+ switch(action)
+ // Toggles the cut/mend status.
+ if("cut")
+ if(!istype(I, /obj/item/wirecutters) && !user.can_admin_interact())
+ to_chat(user, "You need wirecutters!")
+ return
+
+ if(istype(I))
+ playsound(holder, I.usesound, 20, 1)
+ cut_color(color)
+ return TRUE
+
+ // Pulse a wire.
+ if("pulse")
+ if(!istype(I, /obj/item/multitool) && !user.can_admin_interact())
+ to_chat(user, "You need a multitool!")
+ return
+
+ playsound(holder, 'sound/weapons/empty.ogg', 20, 1)
+ pulse_color(color)
+
+ // If they pulse the electrify wire, call interactable() and try to shock them.
+ if(get_wire(color) == WIRE_ELECTRIFY)
+ interactable(user)
+
+ return TRUE
+
+ // Attach a signaler to a wire.
+ if("attach")
+ if(is_attached(color))
+ var/obj/item/O = detach_assembly(color)
+ if(O)
+ user.put_in_hands(O)
+ return TRUE
+
+ if(!istype(I, /obj/item/assembly/signaler))
+ to_chat(user, "You need a remote signaller!")
+ return
+
+ if(user.drop_item())
+ attach_assembly(color, I)
+ return TRUE
+ else
+ to_chat(user, "[user.get_active_hand()] is stuck to your hand!")
+
+/**
+ * Proc called to determine if the user can see wire define information, such as "Contraband", "Door Bolts", etc.
+ *
+ * If the user is an admin, or has a multitool which reveals wire information in their active hand, the proc returns TRUE.
+ *
+ * Arguments:
+ * * user - the mob who is interacting with the wires.
+ */
+/datum/wires/proc/can_see_wire_info(mob/user)
if(user.can_admin_interact())
return TRUE
else if(istype(user.get_active_hand(), /obj/item/multitool))
var/obj/item/multitool/M = user.get_active_hand()
if(M.shows_wire_information)
return TRUE
-
return FALSE
-/datum/wires/Topic(href, href_list)
- if(..())
- return 1
- var/mob/L = usr
- if(CanUse(L) && href_list["action"])
- var/obj/item/I = L.get_active_hand()
- var/colour = lowertext(href_list["wire"])
- holder.add_hiddenprint(L)
- switch(href_list["action"])
- if("cut") // Toggles the cut/mend status
- if(istype(I, /obj/item/wirecutters) || L.can_admin_interact())
- if(istype(I))
- playsound(holder, I.usesound, 20, 1)
- CutWireColour(colour)
- else
- to_chat(L, "You need wirecutters!")
- if("pulse")
- if(istype(I, /obj/item/multitool) || L.can_admin_interact())
- playsound(holder, 'sound/weapons/empty.ogg', 20, 1)
- PulseColour(colour)
- else
- to_chat(L, "You need a multitool!")
- if("attach")
- if(IsAttached(colour))
- var/obj/item/O = Detach(colour)
- if(O)
- L.put_in_hands(O)
- else
- if(istype(I, /obj/item/assembly/signaler))
- if(L.drop_item())
- Attach(colour, I)
- else
- to_chat(L, "[L.get_active_hand()] is stuck to your hand!")
- else
- to_chat(L, "You need a remote signaller!")
+/**
+ * Base proc, intended to be overwritten. Put wire information you'll see at the botton of the TGUI window here, such as "The red light is blinking".
+ */
+/datum/wires/proc/get_status()
+ return list()
- SSnanoui.update_uis(src)
- return 1
+/**
+ * Clears the `colors` list, and randomizes it to a new set of color-to-wire relations.
+ */
+/datum/wires/proc/shuffle_wires()
+ colors.Cut()
+ randomize()
-//
-// Overridable Procs
-//
+/**
+ * Repairs all cut wires.
+ */
+/datum/wires/proc/repair()
+ cut_wires.Cut()
-// Called when wires cut/mended.
-/datum/wires/proc/UpdateCut(index, mended)
- if(holder)
- SSnanoui.update_uis(holder)
+/**
+ * Adds in dud wires, which do nothing when cut/pulsed.
+ *
+ * Arguments:
+ * * duds - the amount of dud wires to generate.
+ */
+/datum/wires/proc/add_duds(duds)
+ while(duds)
+ var/dud = WIRE_DUD_PREFIX + "[--duds]"
+ if(dud in wires)
+ continue
+ wires += dud
-// Called when wire pulsed. Add code here.
-/datum/wires/proc/UpdatePulsed(index)
- if(holder)
- SSnanoui.update_uis(holder)
+/**
+ * Determines if the passed in wire is a dud or not. Returns TRUE if the wire is a dud, FALSE otherwise.
+ *
+ * Arugments:
+ * * wire - a wire define, NOT a color. For example `WIRE_ELECTRIFY`.
+ */
+/datum/wires/proc/is_dud(wire)
+ return findtext(wire, WIRE_DUD_PREFIX, 1, length(WIRE_DUD_PREFIX) + 1)
-/datum/wires/proc/CanUse(mob/L)
- return 1
+/**
+ * Returns TRUE if the wire that corresponds to the passed in color is a dud. FALSE otherwise.
+ *
+ * Arugments:
+ * * color - a wire color.
+ */
+/datum/wires/proc/is_dud_color(color)
+ return is_dud(get_wire(color))
-/datum/wires/CanUseTopic(mob/user, datum/topic_state/state)
- if(!holder || !CanUse(user))
- return STATUS_CLOSE
- return ..()
+/**
+ * Gets the wire associated with the color passed in.
+ *
+ * Arugments:
+ * * color - a wire color.
+ */
+/datum/wires/proc/get_wire(color)
+ return colors[color]
-// Example of use:
-/*
+/**
+ * Determines if the passed in wire is cut or not. Returns TRUE if it's cut, FALSE otherwise.
+ *
+ * Arugments:
+ * * wire - a wire define, NOT a color. For example `WIRE_ELECTRIFY`.
+ */
+/datum/wires/proc/is_cut(wire)
+ return (wire in cut_wires)
-#define NAME_WIRE_BOLTED 1
-#define NAME_WIRE_SHOCKED 2
-#define NAME_WIRE_SAFETY 4
-#define NAME_WIRE_POWER 8
+/**
+ * Determines if the wire associated with the passed in color, is cut or not. Returns TRUE if it's cut, FALSE otherwise.
+ *
+ * Arugments:
+ * * wire - a wire color.
+ */
+/datum/wires/proc/is_color_cut(color)
+ return is_cut(get_wire(color))
-/datum/wires/door/UpdateCut(var/index, var/mended)
- var/obj/machinery/door/airlock/A = holder
- switch(index)
- if(NAME_WIRE_BOLTED)
- if(!mended)
- A.bolt()
- if(NAME_WIRE_SHOCKED)
- A.shock()
- if(NAME_WIRE_SAFETY)
- A.safety()
+/**
+ * Determines if all of the wires are cut. Returns TRUE they're all cut, FALSE otherwise.
+ */
+/datum/wires/proc/is_all_cut()
+ return (length(cut_wires) == length(wires))
-*/
-
-
-//
-// Helper Procs
-//
-
-/datum/wires/proc/PulseColour(colour)
- PulseIndex(GetIndex(colour))
-
-/datum/wires/proc/PulseIndex(index)
- if(IsIndexCut(index))
- return
- UpdatePulsed(index)
-
-/datum/wires/proc/GetIndex(colour)
- if(wires[colour])
- var/index = wires[colour]
- return index
+/**
+ * Cut or mend a wire. Calls `on_cut()`.
+ *
+ * Arugments:
+ * * wire - a wire define, NOT a color. For example `WIRE_ELECTRIFY`.
+ */
+/datum/wires/proc/cut(wire)
+ if(is_cut(wire))
+ cut_wires -= wire
+ on_cut(wire, mend = TRUE)
else
- CRASH("[colour] is not a key in wires.")
+ cut_wires += wire
+ on_cut(wire, mend = FALSE)
-/datum/wires/proc/GetWireName(index)
+/**
+ * Cut the wire which corresponds with the passed in color.
+ *
+ * Arugments:
+ * * color - a wire color.
+ */
+/datum/wires/proc/cut_color(color)
+ cut(get_wire(color))
+
+/**
+ * Cuts a random wire.
+ */
+/datum/wires/proc/cut_random()
+ cut(wires[rand(1, length(wires))])
+
+/**
+ * Cuts all wires.
+ */
+/datum/wires/proc/cut_all()
+ for(var/wire in wires)
+ cut(wire)
+
+/**
+ * Proc called when any wire is cut.
+ *
+ * Base proc, intended to be overriden.
+ * Place an behavior you want to happen when certain wires are cut, into this proc.
+ *
+ * Arugments:
+ * * wire - a wire define, NOT color. For example 'WIRE_ELECTRIFY'.
+ * * mend - TRUE if we're mending the wire. FALSE if we're cutting.
+ */
+/datum/wires/proc/on_cut(wire, mend = FALSE)
return
-//
-// Is Index/Colour Cut procs
-//
+/**
+ * Pulses the given wire. Calls `on_pulse()`.
+ *
+ * Arugments:
+ * * wire - a wire define, NOT a color. For example `WIRE_ELECTRIFY`.
+ */
+/datum/wires/proc/pulse(wire)
+ if(is_cut(wire))
+ return
+ on_pulse(wire)
-/datum/wires/proc/IsColourCut(colour)
- var/index = GetIndex(colour)
- return IsIndexCut(index)
+/**
+ * Pulses the wire associated with the given color.
+ *
+ * Arugments:
+ * * wire - a wire color.
+ */
+/datum/wires/proc/pulse_color(color)
+ pulse(get_wire(color))
-/datum/wires/proc/IsIndexCut(index)
- return (index & wires_status)
+/**
+ * Proc called when any wire is pulsed.
+ *
+ * Base proc, intended to be overriden.
+ * Place behavior you want to happen when certain wires are pulsed, into this proc.
+ *
+ * Arugments:
+ * * wire - a wire define, NOT color. For example 'WIRE_ELECTRIFY'.
+ */
+/datum/wires/proc/on_pulse(wire)
+ return
-//
-// Signaller Procs
-//
+/**
+ * Proc called when an attached signaler receives a signal.
+ *
+ * Searches through the `assemblies` list for the wire that the signaler is attached to. Pulses the wire when it's found.
+ *
+ * Arugments:
+ * * S - the attached signaler receiving the signal.
+ */
+/datum/wires/proc/pulse_assembly(obj/item/assembly/signaler/S)
+ for(var/color in assemblies)
+ if(S == assemblies[color])
+ pulse_color(color)
+ return TRUE
-/datum/wires/proc/IsAttached(colour)
- if(signallers[colour])
- return 1
- return 0
+/**
+ * Proc called when a mob tries to attach a signaler to a wire.
+ *
+ * Makes sure that `S` is actually a signaler and that something is not already attached to the wire.
+ * Adds the signaler to the `assemblies` list as a value, with the `color` as a the key.
+ *
+ * Arguments:
+ * * color - the wire color.
+ * * S - the signaler that a mob is trying to attach.
+ */
+/datum/wires/proc/attach_assembly(color, obj/item/assembly/signaler/S)
+ if(S && istype(S) && !is_attached(color))
+ assemblies[color] = S
+ S.forceMove(holder)
+ S.connected = src
+ return S
-/datum/wires/proc/GetAttached(colour)
- if(signallers[colour])
- return signallers[colour]
+/**
+ * Proc called when a mob tries to detach a signaler from a wire.
+ *
+ * First checks if there is a signaler on the wire. If so, removes the signaler, and clears it from `assemblies` list.
+ *
+ * Arguments:
+ * * color - the wire color.
+ */
+/datum/wires/proc/detach_assembly(color)
+ var/obj/item/assembly/signaler/S = get_attached(color)
+ if(S && istype(S))
+ assemblies -= color
+ S.connected = null
+ S.forceMove(holder.drop_location())
+ return S
+
+/**
+ * Gets the signaler attached to the given wire color, if there is one.
+ *
+ * Arguments:
+ * * color - the wire color.
+ */
+/datum/wires/proc/get_attached(color)
+ if(assemblies[color])
+ return assemblies[color]
return null
-/datum/wires/proc/Attach(colour, obj/item/assembly/signaler/S)
- if(colour && S)
- if(!IsAttached(colour))
- signallers[colour] = S
- S.loc = holder
- S.connected = src
- return S
-
-/datum/wires/proc/Detach(colour)
- if(colour)
- var/obj/item/assembly/signaler/S = GetAttached(colour)
- if(S)
- signallers -= colour
- S.connected = null
- S.loc = holder.loc
- return S
-
-
-/datum/wires/proc/Pulse(obj/item/assembly/signaler/S)
-
- for(var/colour in signallers)
- if(S == signallers[colour])
- PulseColour(colour)
- break
-
-
-//
-// Cut Wire Colour/Index procs
-//
-
-/datum/wires/proc/CutWireColour(colour)
- var/index = GetIndex(colour)
- CutWireIndex(index)
-
-/datum/wires/proc/CutWireIndex(index)
- if(IsIndexCut(index))
- wires_status &= ~index
- UpdateCut(index, 1)
- else
- wires_status |= index
- UpdateCut(index, 0)
-
-/datum/wires/proc/RandomCut()
- var/r = rand(1, wires.len)
- CutWireIndex(r)
-
-/datum/wires/proc/CutAll()
- for(var/i = 1; i < MAX_FLAG && i < (1 << wire_count); i += i)
- CutWireIndex(i)
-
-/datum/wires/proc/IsAllCut()
- if(wires_status == (1 << wire_count) - 1)
- return 1
- return 0
-
-//
-//Shuffle and Mend
-//
-
-/datum/wires/proc/Shuffle()
- wires_status = 0
- GenerateWires()
+/**
+ * Checks if the given wire has a signaler on it.
+ *
+ * Arguments:
+ * * color - the wire color.
+ */
+/datum/wires/proc/is_attached(color)
+ if(assemblies[color])
+ return TRUE
diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm
index c33e7609685..9a333d268f3 100644
--- a/code/game/area/Space Station 13 areas.dm
+++ b/code/game/area/Space Station 13 areas.dm
@@ -50,10 +50,10 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
/area/space/atmosalert()
return
-/area/space/fire_alert()
+/area/space/firealert(obj/source)
return
-/area/space/fire_reset()
+/area/space/firereset(obj/source)
return
/area/space/readyalert()
diff --git a/code/game/area/ai_monitored.dm b/code/game/area/ai_monitored.dm
index 8f65ac634f4..723574ee949 100644
--- a/code/game/area/ai_monitored.dm
+++ b/code/game/area/ai_monitored.dm
@@ -1,24 +1,30 @@
/area/ai_monitored
name = "AI Monitored Area"
- var/obj/machinery/camera/motioncamera = null
+ var/list/motioncameras = list()
+ var/list/motionTargets = list()
-
-/area/ai_monitored/LateInitialize()
+/area/ai_monitored/Initialize(mapload)
. = ..()
- // locate and store the motioncamera
- for(var/obj/machinery/camera/M in src)
- if(M.isMotion())
- motioncamera = M
- M.area_motion = src
- break
+ if(mapload)
+ for(var/obj/machinery/camera/M in src)
+ if(M.isMotion())
+ motioncameras.Add(M)
+ M.set_area_motion(src)
/area/ai_monitored/Entered(atom/movable/O)
..()
- if(ismob(O) && motioncamera)
- motioncamera.newTarget(O)
+ if(ismob(O) && length(motioncameras))
+ for(var/X in motioncameras)
+ var/obj/machinery/camera/cam = X
+ cam.newTarget(O)
+ return
/area/ai_monitored/Exited(atom/movable/O)
- if(ismob(O) && motioncamera)
- motioncamera.lostTarget(O)
+ ..()
+ if(ismob(O) && length(motioncameras))
+ for(var/X in motioncameras)
+ var/obj/machinery/camera/cam = X
+ cam.lostTargetRef(O.UID())
+ return
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index da80a6e775c..de913ac9f91 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -57,6 +57,11 @@
var/list/ambientsounds = GENERIC_SOUNDS
+ var/list/firedoors
+ var/list/cameras
+ var/list/firealarms
+ var/firedoors_last_closed_on = 0
+
var/fast_despawn = FALSE
var/can_get_auto_cryod = TRUE
var/hide_attacklogs = FALSE // For areas such as thunderdome, lavaland syndiebase, etc which generate a lot of spammy attacklogs. Reduces log priority.
@@ -125,35 +130,6 @@
cameras += C
return cameras
-
-/area/proc/atmosalert(danger_level, var/alarm_source, var/force = FALSE)
- if(report_alerts)
- if(danger_level == ATMOS_ALARM_NONE)
- SSalarms.atmosphere_alarm.clearAlarm(src, alarm_source)
- else
- SSalarms.atmosphere_alarm.triggerAlarm(src, alarm_source, severity = danger_level)
-
- //Check all the alarms before lowering atmosalm. Raising is perfectly fine. If force = 1 we don't care.
- for(var/obj/machinery/alarm/AA in src)
- if(!(AA.stat & (NOPOWER|BROKEN)) && !AA.shorted && AA.report_danger_level && !force)
- danger_level = max(danger_level, AA.danger_level)
-
- if(danger_level != atmosalm)
- if(danger_level < ATMOS_ALARM_WARNING && atmosalm >= ATMOS_ALARM_WARNING)
- //closing the doors on red and opening on green provides a bit of hysteresis that will hopefully prevent fire doors from opening and closing repeatedly due to noise
- air_doors_open()
- else if(danger_level >= ATMOS_ALARM_DANGER && atmosalm < ATMOS_ALARM_DANGER)
- air_doors_close()
-
- atmosalm = danger_level
- for(var/obj/machinery/alarm/AA in src)
- AA.update_icon()
-
- GLOB.air_alarm_repository.update_cache(src)
- return 1
- GLOB.air_alarm_repository.update_cache(src)
- return 0
-
/area/proc/air_doors_close()
if(!air_doors_activated)
air_doors_activated = TRUE
@@ -179,44 +155,151 @@
D.open()
-/area/proc/fire_alert()
- if(!fire)
- fire = 1 //used for firedoor checks
- updateicon()
- mouse_opacity = MOUSE_OPACITY_TRANSPARENT
- air_doors_close()
+/area/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ return ..()
-/area/proc/fire_reset()
- if(fire)
- fire = 0 //used for firedoor checks
- updateicon()
- mouse_opacity = MOUSE_OPACITY_TRANSPARENT
- air_doors_open()
+/**
+ * Generate a power alert for this area
+ *
+ * Sends to all ai players, alert consoles, drones and alarm monitor programs in the world
+ */
+/area/proc/poweralert(state, obj/source)
+ if(state != poweralm)
+ poweralm = state
+ if(istype(source)) //Only report power alarms on the z-level where the source is located.
+ for(var/thing in cameras)
+ var/obj/machinery/camera/C = locateUID(thing)
+ if(!QDELETED(C) && is_station_level(C.z))
+ if(state)
+ C.network -= "Power Alarms"
+ else
+ C.network |= "Power Alarms"
- return
+ if(state)
+ SSalarm.cancelAlarm("Power", src, source)
+ else
+ SSalarm.triggerAlarm("Power", src, cameras, source)
-/area/proc/burglaralert(var/obj/trigger)
- if(always_unpowered == 1) //no burglar alarms in space/asteroid
+/**
+ * Generate an atmospheric alert for this area
+ *
+ * Sends to all ai players, alert consoles, drones and alarm monitor programs in the world
+ */
+/area/proc/atmosalert(danger_level, obj/source)
+ if(danger_level != atmosalm)
+ if(danger_level == ATMOS_ALARM_DANGER)
+
+ for(var/thing in cameras)
+ var/obj/machinery/camera/C = locateUID(thing)
+ if(!QDELETED(C) && is_station_level(C.z))
+ C.network |= "Atmosphere Alarms"
+
+
+ SSalarm.triggerAlarm("Atmosphere", src, cameras, source)
+
+ else if(atmosalm == ATMOS_ALARM_DANGER)
+ for(var/thing in cameras)
+ var/obj/machinery/camera/C = locateUID(thing)
+ if(!QDELETED(C) && is_station_level(C.z))
+ C.network -= "Atmosphere Alarms"
+
+ SSalarm.cancelAlarm("Atmosphere", src, source)
+
+ atmosalm = danger_level
+ return TRUE
+ return FALSE
+
+/**
+ * Try to close all the firedoors in the area
+ */
+/area/proc/ModifyFiredoors(opening)
+ if(firedoors)
+ firedoors_last_closed_on = world.time
+ for(var/FD in firedoors)
+ var/obj/machinery/door/firedoor/D = FD
+ var/cont = !D.welded
+ if(cont && opening) //don't open if adjacent area is on fire
+ for(var/I in D.affecting_areas)
+ var/area/A = I
+ if(A.fire)
+ cont = FALSE
+ break
+ if(cont && D.is_operational())
+ if(D.operating)
+ D.nextstate = opening ? FD_OPEN : FD_CLOSED
+ else if(!(D.density ^ opening))
+ INVOKE_ASYNC(D, (opening ? /obj/machinery/door/firedoor.proc/open : /obj/machinery/door/firedoor.proc/close))
+
+/**
+ * Generate a firealarm alert for this area
+ *
+ * Sends to all ai players, alert consoles, drones and alarm monitor programs in the world
+ *
+ * Also starts the area processing on SSobj
+ */
+/area/proc/firealert(obj/source)
+ if(always_unpowered) //no fire alarms in space/asteroid
return
- //Trigger alarm effect
- set_fire_alarm_effect()
+ if(!fire)
+ set_fire_alarm_effect()
+ ModifyFiredoors(FALSE)
+ for(var/item in firealarms)
+ var/obj/machinery/firealarm/F = item
+ F.update_icon()
- //Lockdown airlocks
- for(var/obj/machinery/door/airlock/A in src)
- spawn(0)
- A.close()
- if(A.density)
- A.lock()
+ for(var/thing in cameras)
+ var/obj/machinery/camera/C = locateUID(thing)
+ if(!QDELETED(C) && is_station_level(C.z))
+ C.network |= "Fire Alarms"
- SSalarms.burglar_alarm.triggerAlarm(src, trigger)
- spawn(600)
- SSalarms.burglar_alarm.clearAlarm(src, trigger)
+ SSalarm.triggerAlarm("Fire", src, cameras, source)
-/area/proc/set_fire_alarm_effect()
- fire = 1
- updateicon()
- mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ START_PROCESSING(SSobj, src)
+
+/**
+ * Reset the firealarm alert for this area
+ *
+ * resets the alert sent to all ai players, alert consoles, drones and alarm monitor programs
+ * in the world
+ *
+ * Also cycles the icons of all firealarms and deregisters the area from processing on SSOBJ
+ */
+/area/proc/firereset(obj/source)
+ if(fire)
+ unset_fire_alarm_effects()
+ ModifyFiredoors(TRUE)
+ for(var/item in firealarms)
+ var/obj/machinery/firealarm/F = item
+ F.update_icon()
+
+ for(var/thing in cameras)
+ var/obj/machinery/camera/C = locateUID(thing)
+ if(!QDELETED(C) && is_station_level(C.z))
+ C.network -= "Fire Alarms"
+
+ SSalarm.cancelAlarm("Fire", src, source)
+
+ STOP_PROCESSING(SSobj, src)
+
+/**
+ * If 100 ticks has elapsed, toggle all the firedoors closed again
+ */
+/area/process()
+ if(firedoors_last_closed_on + 100 < world.time) //every 10 seconds
+ ModifyFiredoors(FALSE)
+
+/**
+ * Close and lock a door passed into this proc
+ *
+ * Does this need to exist on area? probably not
+ */
+/area/proc/close_and_lock_door(obj/machinery/door/DOOR)
+ set waitfor = FALSE
+ DOOR.close()
+ if(DOOR.density)
+ DOOR.lock()
/area/proc/readyalert()
if(!eject)
@@ -240,13 +323,62 @@
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
updateicon()
+/**
+ * Raise a burglar alert for this area
+ *
+ * Close and locks all doors in the area and alerts silicon mobs of a break in
+ *
+ * Alarm auto resets after 600 ticks
+ */
+/area/proc/burglaralert(obj/trigger)
+ if(always_unpowered) //no burglar alarms in space/asteroid
+ return
+
+ //Trigger alarm effect
+ set_fire_alarm_effect()
+ //Lockdown airlocks
+ for(var/obj/machinery/door/DOOR in src)
+ close_and_lock_door(DOOR)
+
+ if(SSalarm.triggerAlarm("Burglar", src, cameras, trigger))
+ //Cancel silicon alert after 1 minute
+ addtimer(CALLBACK(SSalarm, /datum/controller/subsystem/alarm.proc/cancelAlarm, "Burglar", src, trigger), 600)
+
+/**
+ * Trigger the fire alarm visual affects in an area
+ *
+ * Updates the fire light on fire alarms in the area and sets all lights to emergency mode
+ */
+/area/proc/set_fire_alarm_effect()
+ fire = TRUE
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ for(var/alarm in firealarms)
+ var/obj/machinery/firealarm/F = alarm
+ F.update_fire_light(fire)
+ for(var/obj/machinery/light/L in src)
+ L.update()
+
+/**
+ * unset the fire alarm visual affects in an area
+ *
+ * Updates the fire light on fire alarms in the area and sets all lights to emergency mode
+ */
+/area/proc/unset_fire_alarm_effects()
+ fire = FALSE
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ for(var/alarm in firealarms)
+ var/obj/machinery/firealarm/F = alarm
+ F.update_fire_light(fire)
+ for(var/obj/machinery/light/L in src)
+ L.update()
+
/area/proc/updateicon()
- if((fire || eject || party) && (!requires_power||power_environ))//If it doesn't require power, can still activate this proc.
- if(fire && !eject && !party)
+ if((eject || party) && (!requires_power||power_environ))//If it doesn't require power, can still activate this proc.
+ if(!eject && !party)
icon_state = "red"
- else if(!fire && eject && !party)
+ else if(eject && !party)
icon_state = "red"
- else if(party && !fire && !eject)
+ else if(party && !eject)
icon_state = "party"
else
icon_state = "blue-red"
diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm
index feff3be1f05..9f5db8d5dae 100644
--- a/code/game/gamemodes/malfunction/Malf_Modules.dm
+++ b/code/game/gamemodes/malfunction/Malf_Modules.dm
@@ -616,7 +616,7 @@
active = FALSE
return
var/turf/T = get_turf(owner_AI.eyeobj)
- new /obj/machinery/transformer/conveyor(T)
+ new /obj/machinery/transformer(T, owner_AI)
playsound(T, 'sound/effects/phasein.ogg', 100, 1)
owner_AI.can_shunt = FALSE
to_chat(owner, "You are no longer able to shunt your core to APCs.")
diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm
index 8e38f106cc7..c73293da519 100644
--- a/code/game/gamemodes/nuclear/nuclearbomb.dm
+++ b/code/game/gamemodes/nuclear/nuclearbomb.dm
@@ -42,6 +42,7 @@ GLOBAL_VAR(bomb_set)
GLOB.poi_list |= src
/obj/machinery/nuclearbomb/Destroy()
+ SStgui.close_uis(wires)
QDEL_NULL(wires)
GLOB.poi_list.Remove(src)
return ..()
@@ -407,6 +408,20 @@ GLOBAL_VAR(bomb_set)
return
return
+/obj/machinery/nuclearbomb/proc/reset_lighthack_callback()
+ lighthack = !lighthack
+
+/obj/machinery/nuclearbomb/proc/reset_safety_callback()
+ safety = !safety
+ if(safety == 1)
+ if(!is_syndicate)
+ set_security_level(previous_level)
+ visible_message("The [src] quiets down.")
+ if(!lighthack)
+ if(icon_state == "nuclearbomb2")
+ icon_state = "nuclearbomb1"
+ else
+ visible_message("The [src] emits a quiet whirling noise!")
//==========DAT FUKKEN DISK===============
/obj/item/disk/nuclear
diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm
index 9fda2cfe45c..951f2a1e9cf 100644
--- a/code/game/machinery/alarm.dm
+++ b/code/game/machinery/alarm.dm
@@ -222,6 +222,7 @@
first_run()
/obj/machinery/alarm/Destroy()
+ SStgui.close_uis(wires)
GLOB.air_alarms -= src
if(SSradio)
SSradio.remove_object(src, frequency)
@@ -314,7 +315,7 @@
temperature_dangerlevel
)
- if(old_danger_level!=danger_level)
+ if(old_danger_level != danger_level)
apply_danger_level()
if(mode == AALARM_MODE_REPLACEMENT && environment_pressure < ONE_ATMOSPHERE * 0.05)
@@ -534,28 +535,35 @@
"checks"= 0,
))
-/obj/machinery/alarm/proc/apply_danger_level(var/new_danger_level)
- if(report_danger_level && alarm_area.atmosalert(new_danger_level, src))
- post_alert(new_danger_level)
+/obj/machinery/alarm/proc/apply_danger_level()
+ var/new_area_danger_level = ATMOS_ALARM_NONE
+ for(var/obj/machinery/alarm/AA in alarm_area)
+ if(!(AA.stat & (NOPOWER|BROKEN)) && !AA.shorted)
+ new_area_danger_level = max(new_area_danger_level, AA.danger_level)
+ if(alarm_area.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/alarm/proc/post_alert(alert_level)
+ if(!report_danger_level)
+ return
var/datum/radio_frequency/frequency = SSradio.return_frequency(alarm_frequency)
+
if(!frequency)
return
var/datum/signal/alert_signal = new
alert_signal.source = src
alert_signal.transmission_method = 1
- alert_signal.data["zone"] = alarm_area.name
+ alert_signal.data["zone"] = get_area_name(src, TRUE)
alert_signal.data["type"] = "Atmospheric"
- if(alert_level==2)
+ if(alert_level == ATMOS_ALARM_DANGER)
alert_signal.data["alert"] = "severe"
- else if(alert_level==1)
+ else if(alert_level == ATMOS_ALARM_WARNING)
alert_signal.data["alert"] = "minor"
- else if(alert_level==0)
+ else if(alert_level == ATMOS_ALARM_NONE)
alert_signal.data["alert"] = "clear"
frequency.post_signal(src, alert_signal)
@@ -889,14 +897,14 @@
if(href_list["atmos_alarm"])
if(alarm_area.atmosalert(ATMOS_ALARM_DANGER, src))
- apply_danger_level(ATMOS_ALARM_DANGER)
+ post_alert(ATMOS_ALARM_DANGER)
alarmActivated = 1
update_icon()
return 1
if(href_list["atmos_reset"])
if(alarm_area.atmosalert(ATMOS_ALARM_NONE, src, TRUE))
- apply_danger_level(ATMOS_ALARM_NONE)
+ post_alert(ATMOS_ALARM_NONE)
alarmActivated = 0
update_icon()
return 1
@@ -951,7 +959,7 @@
to_chat(user, "It does nothing")
return
else
- if(allowed(usr) && !wires.IsIndexCut(AALARM_WIRE_IDSCAN))
+ if(allowed(usr) && !wires.is_cut(WIRE_IDSCAN))
locked = !locked
to_chat(user, "You [ locked ? "lock" : "unlock"] the Air Alarm interface.")
updateUsrDialog()
@@ -1030,7 +1038,7 @@
. = TRUE
if(!I.use_tool(src, user, 0, volume = I.tool_volume))
return
- if(wires.wires_status == 31) // all wires cut
+ if(wires.is_all_cut()) // all wires cut
var/obj/item/stack/cable_coil/new_coil = new /obj/item/stack/cable_coil(user.drop_location())
new_coil.amount = 5
buildstage = AIR_ALARM_BUILDING
@@ -1076,6 +1084,15 @@
if(buildstage < 1)
. += "The circuit is missing."
+/obj/machinery/alarm/proc/unshort_callback()
+ if(shorted)
+ shorted = FALSE
+ update_icon()
+
+/obj/machinery/alarm/proc/enable_ai_control_callback()
+ if(aidisabled)
+ aidisabled = FALSE
+
/obj/machinery/alarm/all_access
name = "all-access air alarm"
desc = "This particular atmos control unit appears to have no access restrictions."
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index c22922e4d14..5c1b84d8cba 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -65,6 +65,7 @@
RefreshParts()
/obj/machinery/autolathe/Destroy()
+ SStgui.close_uis(wires)
QDEL_NULL(wires)
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.retrieve_all()
@@ -467,3 +468,15 @@
for(var/datum/design/D in files.known_designs)
if("hacked" in D.category)
files.known_designs -= D.id
+
+/obj/machinery/autolathe/proc/check_hacked_callback()
+ if(!wires.is_cut(WIRE_AUTOLATHE_HACK))
+ adjust_hacked(FALSE)
+
+/obj/machinery/autolathe/proc/check_electrified_callback()
+ if(!wires.is_cut(WIRE_ELECTRIFY))
+ shocked = FALSE
+
+/obj/machinery/autolathe/proc/check_disabled_callback()
+ if(!wires.is_cut(WIRE_AUTOLATHE_DISABLE))
+ disabled = FALSE
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index b66cad8d328..4e185feb4a8 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -28,13 +28,14 @@
var/view_range = 7
var/short_range = 2
+ var/alarm_on = FALSE
var/busy = FALSE
var/emped = FALSE //Number of consecutive EMP's on this camera
var/in_use_lights = 0 // TO BE IMPLEMENTED
var/toggle_sound = 'sound/items/wirecutter.ogg'
-/obj/machinery/camera/Initialize()
+/obj/machinery/camera/Initialize(mapload)
. = ..()
wires = new(src)
assembly = new(src)
@@ -44,11 +45,17 @@
GLOB.cameranet.cameras += src
GLOB.cameranet.addCamera(src)
+ if(isturf(loc))
+ LAZYADD(myArea.cameras, UID())
if(is_station_level(z) && prob(3) && !start_active)
toggle_cam(null, FALSE)
- wires.CutAll()
+ wires.cut_all()
+
+/obj/machinery/camera/proc/set_area_motion(area/A)
+ area_motion = A
/obj/machinery/camera/Destroy()
+ SStgui.close_uis(wires)
toggle_cam(null, FALSE) //kick anyone viewing out
QDEL_NULL(assembly)
if(istype(bug))
@@ -59,10 +66,14 @@
QDEL_NULL(wires)
GLOB.cameranet.removeCamera(src) //Will handle removal from the camera network and the chunks, so we don't need to worry about that
GLOB.cameranet.cameras -= src
+ if(isarea(myArea))
+ LAZYREMOVE(myArea.cameras, UID())
var/area/ai_monitored/A = get_area(src)
if(istype(A))
- A.motioncamera = null
+ A.motioncameras -= src
area_motion = null
+ cancelCameraAlarm()
+ cancelAlarm()
return ..()
/obj/machinery/camera/emp_act(severity)
@@ -252,7 +263,7 @@
if(status && !(flags & NODECONSTRUCT))
triggerCameraAlarm()
toggle_cam(null, FALSE)
- wires.CutAll()
+ wires.cut_all()
/obj/machinery/camera/deconstruct(disassembled = TRUE)
if(!(flags & NODECONSTRUCT))
@@ -282,9 +293,16 @@
status = !status
if(can_use())
GLOB.cameranet.addCamera(src)
+ if(isturf(loc))
+ myArea = get_area(src)
+ LAZYADD(myArea.cameras, UID())
+ else
+ myArea = null
else
set_light(0)
GLOB.cameranet.removeCamera(src)
+ if(isarea(myArea))
+ LAZYREMOVE(myArea.cameras, UID())
GLOB.cameranet.updateChunk(x, y, z)
var/change_msg = "deactivates"
if(status)
@@ -313,12 +331,12 @@
to_chat(O, "The screen bursts into static.")
/obj/machinery/camera/proc/triggerCameraAlarm()
- if(is_station_contact(z))
- SSalarms.camera_alarm.triggerAlarm(loc, src)
+ alarm_on = TRUE
+ SSalarm.triggerAlarm("Camera", get_area(src), list(UID()), src)
/obj/machinery/camera/proc/cancelCameraAlarm()
- if(is_station_contact(z))
- SSalarms.camera_alarm.clearAlarm(loc, src)
+ alarm_on = FALSE
+ SSalarm.cancelAlarm("Camera", get_area(src), src)
/obj/machinery/camera/proc/can_use()
if(!status)
@@ -414,8 +432,8 @@
/obj/machinery/camera/portable //Cameras which are placed inside of things, such as helmets.
var/turf/prev_turf
-/obj/machinery/camera/portable/New()
- ..()
+/obj/machinery/camera/portable/Initialize(mapload)
+ . = ..()
assembly.state = 0 //These cameras are portable, and so shall be in the portable state if removed.
assembly.anchored = 0
assembly.update_icon()
diff --git a/code/game/machinery/camera/motion.dm b/code/game/machinery/camera/motion.dm
index 16fb6eca204..7d33361e4b9 100644
--- a/code/game/machinery/camera/motion.dm
+++ b/code/game/machinery/camera/motion.dm
@@ -1,60 +1,60 @@
/obj/machinery/camera
-
- var/list/motionTargets = list()
+ var/list/localMotionTargets = list()
var/detectTime = 0
var/area/ai_monitored/area_motion = null
- var/alarm_delay = 100
-
+ var/alarm_delay = 30 // Don't forget, there's another 3 seconds in queueAlarm()
/obj/machinery/camera/process()
// motion camera event loop
- if(stat & (EMPED|NOPOWER))
- return
if(!isMotion())
. = PROCESS_KILL
return
+ if(stat & (EMPED|NOPOWER))
+ return
if(detectTime > 0)
var/elapsed = world.time - detectTime
if(elapsed > alarm_delay)
triggerAlarm()
else if(detectTime == -1)
- for(var/mob/target in motionTargets)
- if(target.stat == 2) lostTarget(target)
- // If not detecting with motion camera...
- if(!area_motion)
- // See if the camera is still in range
- if(!in_range(src, target))
- // If they aren't in range, lose the target.
- lostTarget(target)
+ for(var/thing in getTargetList())
+ var/mob/target = locateUID(thing)
+ if(QDELETED(target) || target.stat == DEAD || (!area_motion && !in_range(src, target)))
+ //If not part of a monitored area and the camera is not in range or the target is dead
+ lostTargetRef(thing)
-/obj/machinery/camera/proc/newTarget(var/mob/target)
- if(istype(target, /mob/living/silicon/ai)) return 0
+/obj/machinery/camera/proc/getTargetList()
+ if(area_motion)
+ return area_motion.motionTargets
+ return localMotionTargets
+
+/obj/machinery/camera/proc/newTarget(mob/target)
+ if(isAI(target))
+ return FALSE
if(detectTime == 0)
detectTime = world.time // start the clock
- if(!(target in motionTargets))
- motionTargets += target
- return 1
+ var/list/targets = getTargetList()
+ targets |= target.UID()
+ return TRUE
-/obj/machinery/camera/proc/lostTarget(var/mob/target)
- if(target in motionTargets)
- motionTargets -= target
- if(motionTargets.len == 0)
+/obj/machinery/camera/proc/lostTargetRef(uid)
+ var/list/targets = getTargetList()
+ targets -= uid
+ if(length(targets))
cancelAlarm()
/obj/machinery/camera/proc/cancelAlarm()
- if(!status || (stat & NOPOWER))
- return FALSE
- if(detectTime == -1 && is_station_contact(z))
- SSalarms.motion_alarm.clearAlarm(loc, src)
+ if(detectTime == -1)
+ if(status)
+ SSalarm.cancelAlarm("Motion", get_area(src), src)
detectTime = 0
return TRUE
/obj/machinery/camera/proc/triggerAlarm()
- if(!status || (stat & NOPOWER))
+ if(!detectTime)
return FALSE
- if(!detectTime || !is_station_contact(z))
- return FALSE
- SSalarms.motion_alarm.triggerAlarm(loc, src)
+ if(status)
+ SSalarm.triggerAlarm("Motion", get_area(src), list(UID()), src)
+ visible_message("A red light flashes on the [src]!")
detectTime = -1
return TRUE
diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm
index b7ae75cd13f..33c970639e5 100644
--- a/code/game/machinery/camera/presets.dm
+++ b/code/game/machinery/camera/presets.dm
@@ -2,7 +2,7 @@
// EMP
-/obj/machinery/camera/emp_proof/Initialize()
+/obj/machinery/camera/emp_proof/Initialize(mapload)
. = ..()
upgradeEmpProof()
@@ -11,19 +11,23 @@
/obj/machinery/camera/xray
icon_state = "xraycam" // Thanks to Krutchen for the icons.
-/obj/machinery/camera/xray/Initialize()
+/obj/machinery/camera/xray/Initialize(mapload)
. = ..()
upgradeXRay()
// MOTION
+/obj/machinery/camera/motion
+ name = "motion-sensitive security camera"
-/obj/machinery/camera/motion/Initialize()
+/obj/machinery/camera/motion/Initialize(mapload)
. = ..()
upgradeMotion()
// ALL UPGRADES
+/obj/machinery/camera/all
+ icon_state = "xraycamera" //mapping icon.
-/obj/machinery/camera/all/Initialize()
+/obj/machinery/camera/all/Initialize(mapload)
. = ..()
upgradeEmpProof()
upgradeXRay()
@@ -78,6 +82,10 @@
// If you are upgrading Motion, and it isn't in the camera's New(), add it to the machines list.
/obj/machinery/camera/proc/upgradeMotion()
+ if(isMotion())
+ return
+ if(name == initial(name))
+ name = "motion-sensitive security camera"
assembly.upgrades.Add(new /obj/item/assembly/prox_sensor(assembly))
setPowerUsage()
// Add it to machines that process
diff --git a/code/game/machinery/computer/atmos_alert.dm b/code/game/machinery/computer/atmos_alert.dm
index 123cee3ae4e..0be4aa0449b 100644
--- a/code/game/machinery/computer/atmos_alert.dm
+++ b/code/game/machinery/computer/atmos_alert.dm
@@ -1,84 +1,90 @@
-GLOBAL_LIST_EMPTY(priority_air_alarms)
-GLOBAL_LIST_EMPTY(minor_air_alarms)
-
-
/obj/machinery/computer/atmos_alert
name = "atmospheric alert computer"
desc = "Used to access the station's atmospheric sensors."
circuit = /obj/item/circuitboard/atmos_alert
+ var/ui_x = 350
+ var/ui_y = 300
icon_keyboard = "atmos_key"
icon_screen = "alert:0"
light_color = LIGHT_COLOR_CYAN
+ var/list/priority_alarms = list()
+ var/list/minor_alarms = list()
+ var/receive_frequency = ATMOS_FIRE_FREQ
+ var/datum/radio_frequency/radio_connection
-/obj/machinery/computer/atmos_alert/New()
- ..()
- SSalarms.atmosphere_alarm.register(src, /obj/machinery/computer/station_alert/.proc/update_icon)
+/obj/machinery/computer/atmos_alert/Initialize(mapload)
+ . = ..()
+ set_frequency(receive_frequency)
/obj/machinery/computer/atmos_alert/Destroy()
- SSalarms.atmosphere_alarm.unregister(src)
- return ..()
+ SSradio.remove_object(src, receive_frequency)
+ return ..()
/obj/machinery/computer/atmos_alert/attack_hand(mob/user)
- ui_interact(user)
+ tgui_interact(user)
-/obj/machinery/computer/atmos_alert/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/computer/atmos_alert/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
- ui = new(user, src, ui_key, "atmos_alert.tmpl", src.name, 500, 500)
+ ui = new(user, src, ui_key, "AtmosAlertConsole", name, ui_x, ui_y, master_ui, state)
ui.open()
- ui.set_auto_update(1)
-/obj/machinery/computer/atmos_alert/ui_data(mob/user, datum/topic_state/state)
- var/data[0]
- var/major_alarms[0]
- var/minor_alarms[0]
+/obj/machinery/computer/atmos_alert/tgui_data(mob/user)
+ var/list/data = list()
- for(var/datum/alarm/alarm in SSalarms.atmosphere_alarm.major_alarms())
- major_alarms[++major_alarms.len] = list("name" = sanitize(alarm.alarm_name()), "ref" = "\ref[alarm]")
-
- for(var/datum/alarm/alarm in SSalarms.atmosphere_alarm.minor_alarms())
- minor_alarms[++minor_alarms.len] = list("name" = sanitize(alarm.alarm_name()), "ref" = "\ref[alarm]")
-
- data["priority_alarms"] = major_alarms
- data["minor_alarms"] = minor_alarms
+ data["priority"] = list()
+ for(var/zone in priority_alarms)
+ data["priority"] |= zone
+ data["minor"] = list()
+ for(var/zone in minor_alarms)
+ data["minor"] |= zone
return data
-/obj/machinery/computer/atmos_alert/update_icon()
- var/list/alarms = SSalarms.atmosphere_alarm.major_alarms()
- if(alarms.len)
- icon_screen = "alert:2"
- else
- alarms = SSalarms.atmosphere_alarm.minor_alarms()
- if(alarms.len)
- icon_screen = "alert:1"
- else
- icon_screen = "alert:0"
- ..()
-
-/obj/machinery/computer/atmos_alert/Topic(href, href_list)
+/obj/machinery/computer/atmos_alert/tgui_act(action, params)
if(..())
- return 1
+ return
+ switch(action)
+ if("clear")
+ var/zone = params["zone"]
+ if(zone in priority_alarms)
+ to_chat(usr, "Priority alarm for [zone] cleared.")
+ priority_alarms -= zone
+ . = TRUE
+ if(zone in minor_alarms)
+ to_chat(usr, "Minor alarm for [zone] cleared.")
+ minor_alarms -= zone
+ . = TRUE
+ update_icon()
- if(href_list["clear_alarm"])
- var/datum/alarm/alarm = locate(href_list["clear_alarm"]) in SSalarms.atmosphere_alarm.alarms
- if(alarm)
- for(var/datum/alarm_source/alarm_source in alarm.sources)
- var/obj/machinery/alarm/air_alarm = alarm_source.source
- if(istype(air_alarm))
- var/list/new_ref = list("atmos_reset" = 1)
- air_alarm.Topic(href, new_ref, state = GLOB.air_alarm_topic)
- update_icon()
- return 1
+/obj/machinery/computer/atmos_alert/proc/set_frequency(new_frequency)
+ SSradio.remove_object(src, receive_frequency)
+ receive_frequency = new_frequency
+ radio_connection = SSradio.add_object(src, receive_frequency, RADIO_ATMOSIA)
-GLOBAL_DATUM_INIT(air_alarm_topic, /datum/topic_state/air_alarm_topic, new)
+/obj/machinery/computer/atmos_alert/receive_signal(datum/signal/signal)
+ if(!signal)
+ return
-/datum/topic_state/air_alarm_topic/href_list(var/mob/user)
- var/list/extra_href = list()
- extra_href["remote_connection"] = 1
- extra_href["remote_access"] = 1
+ var/zone = signal.data["zone"]
+ var/severity = signal.data["alert"]
- return extra_href
+ if(!zone || !severity)
+ return
-/datum/topic_state/air_alarm_topic/can_use_topic(var/src_object, var/mob/user)
- return STATUS_INTERACTIVE
+ minor_alarms -= zone
+ priority_alarms -= zone
+ if(severity == "severe")
+ priority_alarms += zone
+ else if(severity == "minor")
+ minor_alarms += zone
+ update_icon()
+
+/obj/machinery/computer/atmos_alert/update_icon()
+ if(length(priority_alarms))
+ icon_screen = "alert:2"
+ else if(length(minor_alarms))
+ icon_screen = "alert:1"
+ else
+ icon_screen = "alert:0"
+ ..()
diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm
index b502d6e5441..a07f3c04348 100644
--- a/code/game/machinery/computer/buildandrepair.dm
+++ b/code/game/machinery/computer/buildandrepair.dm
@@ -165,12 +165,9 @@
/obj/item/circuitboard/stationalert_engineering
name = "Circuit Board (Station Alert Console (Engineering))"
build_path = /obj/machinery/computer/station_alert
-/obj/item/circuitboard/stationalert_security
- name = "Circuit Board (Station Alert Console (Security))"
+/obj/item/circuitboard/stationalert
+ name = "Circuit Board (Station Alert Console)"
build_path = /obj/machinery/computer/station_alert
-/obj/item/circuitboard/stationalert_all
- name = "Circuit Board (Station Alert Console (All))"
- build_path = /obj/machinery/computer/station_alert/all
/obj/item/circuitboard/atmos_alert
name = "Circuit Board (Atmospheric Alert Computer)"
build_path = /obj/machinery/computer/atmos_alert
diff --git a/code/game/machinery/computer/station_alert.dm b/code/game/machinery/computer/station_alert.dm
index 607918442ea..3b4631b171a 100644
--- a/code/game/machinery/computer/station_alert.dm
+++ b/code/game/machinery/computer/station_alert.dm
@@ -6,48 +6,91 @@
icon_screen = "alert:0"
light_color = LIGHT_COLOR_CYAN
circuit = /obj/item/circuitboard/stationalert_engineering
- var/datum/nano_module/alarm_monitor/alarm_monitor
- var/monitor_type = /datum/nano_module/alarm_monitor/engineering
+ var/ui_x = 325
+ var/ui_y = 500
+ var/list/alarms_listend_for = list("Fire", "Atmosphere", "Power")
-/obj/machinery/computer/station_alert/security
- monitor_type = /datum/nano_module/alarm_monitor/security
- circuit = /obj/item/circuitboard/stationalert_security
-
-/obj/machinery/computer/station_alert/all
- monitor_type = /datum/nano_module/alarm_monitor/all
- circuit = /obj/item/circuitboard/stationalert_all
-
-/obj/machinery/computer/station_alert/New()
- ..()
- alarm_monitor = new monitor_type(src)
- alarm_monitor.register(src, /obj/machinery/computer/station_alert/.proc/update_icon)
+/obj/machinery/computer/station_alert/Initialize(mapload)
+ . = ..()
+ GLOB.alert_consoles += src
+ RegisterSignal(SSalarm, COMSIG_TRIGGERED_ALARM, .proc/alarm_triggered)
+ RegisterSignal(SSalarm, COMSIG_CANCELLED_ALARM, .proc/alarm_cancelled)
/obj/machinery/computer/station_alert/Destroy()
- alarm_monitor.unregister(src)
- QDEL_NULL(alarm_monitor)
+ GLOB.alert_consoles -= src
return ..()
/obj/machinery/computer/station_alert/attack_ai(mob/user)
add_fingerprint(user)
if(stat & (BROKEN|NOPOWER))
return
- interact(user)
+ tgui_interact(user)
/obj/machinery/computer/station_alert/attack_hand(mob/user)
add_fingerprint(user)
if(stat & (BROKEN|NOPOWER))
return
- interact(user)
+ tgui_interact(user)
-/obj/machinery/computer/station_alert/interact(mob/user)
- alarm_monitor.ui_interact(user)
+/obj/machinery/computer/station_alert/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "StationAlertConsole", name, ui_x, ui_y, master_ui, state)
+ ui.open()
+
+/obj/machinery/computer/station_alert/tgui_data(mob/user)
+ var/list/data = list()
+
+ data["alarms"] = list()
+ for(var/class in SSalarm.alarms)
+ if(!(class in alarms_listend_for))
+ continue
+ data["alarms"][class] = list()
+ for(var/area in SSalarm.alarms[class])
+ for(var/thing in SSalarm.alarms[class][area][3])
+ var/atom/A = locateUID(thing)
+ if(atoms_share_level(A, src))
+ data["alarms"][class] += area
+
+ return data
+
+/obj/machinery/computer/station_alert/proc/alarm_triggered(src, class, area/A, list/O, obj/alarmsource)
+ if(!(class in alarms_listend_for))
+ return
+ if(alarmsource.z != z)
+ return
+ if(stat & (BROKEN))
+ return
+ update_icon()
+
+/obj/machinery/computer/station_alert/proc/alarm_cancelled(src, class, area/A, obj/origin, cleared)
+ if(!(class in alarms_listend_for))
+ return
+ if(origin.z != z)
+ return
+ if(stat & (BROKEN))
+ return
+ update_icon()
/obj/machinery/computer/station_alert/update_icon()
- if(alarm_monitor)
- var/list/alarms = alarm_monitor.major_alarms()
- if(alarms.len)
- icon_screen = "alert:2"
- else
- icon_screen = "alert:0"
+ var/active_alarms = FALSE
+ var/list/list/temp_alarm_list = SSalarm.alarms.Copy()
+ for(var/cat in temp_alarm_list)
+ if(!(cat in alarms_listend_for))
+ continue
+ var/list/list/L = temp_alarm_list[cat].Copy()
+ for(var/alarm in L)
+ var/list/list/alm = L[alarm].Copy()
+ var/list/list/sources = alm[3].Copy()
+ for(var/thing in sources)
+ var/atom/A = locateUID(thing)
+ if(A && A.z != z)
+ L -= alarm
+ if(length(L))
+ active_alarms = TRUE
+ if(active_alarms)
+ icon_screen = "alert:2"
+ else
+ icon_screen = "alert:0"
..()
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 42ff08ff00f..d2e983b3eb3 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -142,6 +142,7 @@ About the new airlock wires panel:
break
/obj/machinery/door/airlock/Destroy()
+ SStgui.close_uis(wires)
QDEL_NULL(electronics)
QDEL_NULL(wires)
QDEL_NULL(note)
@@ -188,10 +189,6 @@ About the new airlock wires panel:
return 1
return 0
-/obj/machinery/door/airlock/proc/isWireCut(wireIndex)
- // You can find the wires in the datum folder.
- return wires.IsIndexCut(wireIndex)
-
/obj/machinery/door/airlock/proc/canAIControl()
return ((aiControlDisabled!=1) && (!isAllPowerLoss()))
@@ -204,27 +201,21 @@ About the new airlock wires panel:
return (main_power_lost_until==0 || backup_power_lost_until==0)
/obj/machinery/door/airlock/requiresID()
- return !(isWireCut(AIRLOCK_WIRE_IDSCAN) || aiDisabledIdScanner)
+ return !(wires.is_cut(WIRE_IDSCAN) || aiDisabledIdScanner)
/obj/machinery/door/airlock/proc/isAllPowerLoss()
if(stat & (NOPOWER|BROKEN))
return 1
- if(mainPowerCablesCut() && backupPowerCablesCut())
+ if(wires.is_cut(WIRE_MAIN_POWER1) && wires.is_cut(WIRE_BACKUP_POWER1))
return 1
return 0
-/obj/machinery/door/airlock/proc/mainPowerCablesCut()
- return isWireCut(AIRLOCK_WIRE_MAIN_POWER1)
-
-/obj/machinery/door/airlock/proc/backupPowerCablesCut()
- return isWireCut(AIRLOCK_WIRE_BACKUP_POWER1)
-
/obj/machinery/door/airlock/proc/loseMainPower()
- main_power_lost_until = mainPowerCablesCut() ? -1 : world.time + 60 SECONDS
+ main_power_lost_until = wires.is_cut(WIRE_MAIN_POWER1) ? -1 : world.time + 60 SECONDS
if(main_power_lost_until > 0)
main_power_timer = addtimer(CALLBACK(src, .proc/regainMainPower), 60 SECONDS, TIMER_UNIQUE | TIMER_STOPPABLE)
// If backup power is permanently disabled then activate in 10 seconds if possible, otherwise it's already enabled or a timer is already running
- if(backup_power_lost_until == -1 && !backupPowerCablesCut())
+ if(backup_power_lost_until == -1 && !wires.is_cut(WIRE_BACKUP_POWER1))
backup_power_lost_until = world.time + 10 SECONDS
backup_power_timer = addtimer(CALLBACK(src, .proc/regainBackupPower), 10 SECONDS, TIMER_UNIQUE | TIMER_STOPPABLE)
// Disable electricity if required
@@ -232,7 +223,7 @@ About the new airlock wires panel:
electrify(0)
/obj/machinery/door/airlock/proc/loseBackupPower()
- backup_power_lost_until = backupPowerCablesCut() ? -1 : world.time + 60 SECONDS
+ backup_power_lost_until = wires.is_cut(WIRE_BACKUP_POWER1) ? -1 : world.time + 60 SECONDS
if(backup_power_lost_until > 0)
backup_power_timer = addtimer(CALLBACK(src, .proc/regainBackupPower), 60 SECONDS, TIMER_UNIQUE | TIMER_STOPPABLE)
@@ -243,7 +234,7 @@ About the new airlock wires panel:
/obj/machinery/door/airlock/proc/regainMainPower()
main_power_timer = null
- if(!mainPowerCablesCut())
+ if(!wires.is_cut(WIRE_MAIN_POWER1))
main_power_lost_until = 0
// If backup power is currently active then disable, otherwise let it count down and disable itself later
if(!backup_power_lost_until)
@@ -253,7 +244,7 @@ About the new airlock wires panel:
/obj/machinery/door/airlock/proc/regainBackupPower()
backup_power_timer = null
- if(!backupPowerCablesCut())
+ if(!wires.is_cut(WIRE_BACKUP_POWER1))
// Restore backup power only if main power is offline, otherwise permanently disable
backup_power_lost_until = main_power_lost_until == 0 ? -1 : 0
update_icon()
@@ -264,7 +255,7 @@ About the new airlock wires panel:
electrified_timer = null
var/message = ""
- if(isWireCut(AIRLOCK_WIRE_ELECTRIFY) && arePowerSystemsOn())
+ if(wires.is_cut(WIRE_ELECTRIFY) && arePowerSystemsOn())
message = text("The electrification wire is cut - Door permanently electrified.")
electrified_until = -1
else if(duration && !arePowerSystemsOn())
@@ -763,7 +754,7 @@ About the new airlock wires panel:
var/activate = text2num(href_list["activate"])
switch(href_list["command"])
if("idscan")
- if(isWireCut(AIRLOCK_WIRE_IDSCAN))
+ if(wires.is_cut(WIRE_IDSCAN))
to_chat(usr, "The IdScan wire has been cut - IdScan feature permanently disabled.")
else if(activate && aiDisabledIdScanner)
aiDisabledIdScanner = 0
@@ -780,14 +771,14 @@ About the new airlock wires panel:
loseBackupPower()
update_icon()
if("bolts")
- if(isWireCut(AIRLOCK_WIRE_DOOR_BOLTS))
+ if(wires.is_cut(WIRE_DOOR_BOLTS))
to_chat(usr, "The door bolt control wire has been cut - Door bolts permanently dropped.")
else if(activate && lock())
to_chat(usr, "The door bolts have been dropped.")
else if(!activate && unlock())
to_chat(usr, "The door bolts have been raised.")
if("electrify_temporary")
- if(activate && isWireCut(AIRLOCK_WIRE_ELECTRIFY))
+ if(activate && wires.is_cut(WIRE_ELECTRIFY))
to_chat(usr, text("The electrification wire is cut - Door permanently electrified."))
else if(!activate && electrified_until != 0)
to_chat(usr, "The door is now un-electrified.")
@@ -799,7 +790,7 @@ About the new airlock wires panel:
to_chat(usr, "The door is now electrified for thirty seconds.")
electrify(30)
if("electrify_permanently")
- if(isWireCut(AIRLOCK_WIRE_ELECTRIFY))
+ if(wires.is_cut(WIRE_ELECTRIFY))
to_chat(usr, text("The electrification wire is cut - Cannot electrify the door."))
else if(!activate && electrified_until != 0)
to_chat(usr, "The door is now un-electrified.")
@@ -821,7 +812,7 @@ About the new airlock wires panel:
close()
if("safeties")
// Safeties! We don't need no stinking safeties!
- if(isWireCut(AIRLOCK_WIRE_SAFETY))
+ if(wires.is_cut(WIRE_SAFETY))
to_chat(usr, text("The safety wire is cut - Cannot secure the door."))
else if(activate && safe)
safe = 0
@@ -829,7 +820,7 @@ About the new airlock wires panel:
safe = 1
if("timing")
// Door speed control
- if(isWireCut(AIRLOCK_WIRE_SPEED))
+ if(wires.is_cut(WIRE_SPEED))
to_chat(usr, text("The timing wire is cut - Cannot alter timing."))
else if(activate && normalspeed)
normalspeed = 0
@@ -837,7 +828,7 @@ About the new airlock wires panel:
normalspeed = 1
if("lights")
// Bolt lights
- if(isWireCut(AIRLOCK_WIRE_LIGHT))
+ if(wires.is_cut(WIRE_BOLT_LIGHT))
to_chat(usr, "The bolt lights wire has been cut - The door bolt lights are permanently disabled.")
else if(!activate && lights)
lights = 0
@@ -1126,7 +1117,7 @@ About the new airlock wires panel:
if(operating || welded || locked || emagged)
return 0
if(!forced)
- if(!arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_OPEN_DOOR))
+ if(!arePowerSystemsOn() || wires.is_cut(WIRE_OPEN_DOOR))
return 0
use_power(360) //360 W seems much more appropriate for an actuator moving an industrial door capable of crushing people
if(forced)
@@ -1163,7 +1154,7 @@ About the new airlock wires panel:
if(!forced)
//despite the name, this wire is for general door control.
//Bolts are already covered by the check for locked, above
- if(!arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_OPEN_DOOR))
+ if(!arePowerSystemsOn() || wires.is_cut(WIRE_OPEN_DOOR))
return
if(safe)
for(var/turf/turf in locs)
@@ -1219,7 +1210,7 @@ About the new airlock wires panel:
return
if(!forced)
- if(operating || !arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_DOOR_BOLTS))
+ if(operating || !arePowerSystemsOn() || wires.is_cut(WIRE_DOOR_BOLTS))
return
locked = 0
@@ -1314,7 +1305,7 @@ About the new airlock wires panel:
stat |= BROKEN
if(!panel_open)
panel_open = TRUE
- wires.CutAll()
+ wires.cut_all()
update_icon()
/obj/machinery/door/airlock/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
@@ -1407,6 +1398,12 @@ About the new airlock wires panel:
A.name = name
qdel(src)
+/obj/machinery/door/airlock/proc/ai_control_callback()
+ if(aiControlDisabled == 1)
+ aiControlDisabled = 0
+ else if(aiControlDisabled == 2)
+ aiControlDisabled = -1
+
#undef AIRLOCK_CLOSED
#undef AIRLOCK_CLOSING
#undef AIRLOCK_OPEN
diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm
index 37dbdb6c9c0..c509675868b 100644
--- a/code/game/machinery/doors/firedoor.dm
+++ b/code/game/machinery/doors/firedoor.dm
@@ -28,6 +28,11 @@
var/nextstate = null
var/boltslocked = TRUE
var/active_alarm = FALSE
+ var/list/affecting_areas
+
+/obj/machinery/door/firedoor/Initialize(mapload)
+ . = ..()
+ CalculateAffectingAreas()
/obj/machinery/door/firedoor/examine(mob/user)
. = ..()
@@ -40,11 +45,31 @@
else
. += "The bolt locks have been unscrewed, but the bolts themselves are still wrenched to the floor."
+/obj/machinery/door/firedoor/proc/CalculateAffectingAreas()
+ remove_from_areas()
+ affecting_areas = get_adjacent_open_areas(src) | get_area(src)
+ for(var/I in affecting_areas)
+ var/area/A = I
+ LAZYADD(A.firedoors, src)
+
/obj/machinery/door/firedoor/closed
icon_state = "door_closed"
opacity = TRUE
density = TRUE
+//see also turf/AfterChange for adjacency shennanigans
+
+/obj/machinery/door/firedoor/proc/remove_from_areas()
+ if(affecting_areas)
+ for(var/I in affecting_areas)
+ var/area/A = I
+ LAZYREMOVE(A.firedoors, src)
+
+/obj/machinery/door/firedoor/Destroy()
+ remove_from_areas()
+ affecting_areas.Cut()
+ return ..()
+
/obj/machinery/door/firedoor/Bumped(atom/AM)
if(panel_open || operating)
return
diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm
index 1bbecf29d18..911f85be753 100644
--- a/code/game/machinery/firealarm.dm
+++ b/code/game/machinery/firealarm.dm
@@ -25,6 +25,11 @@ FIRE ALARM
active_power_usage = 6
power_channel = ENVIRON
resistance_flags = FIRE_PROOF
+
+ light_power = 0
+ light_range = 7
+ light_color = "#ff3232"
+
var/last_process = 0
var/wiresexposed = 0
var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone
@@ -192,6 +197,7 @@ FIRE ALARM
/obj/machinery/firealarm/obj_break(damage_flag)
if(!(stat & BROKEN) && !(flags & NODECONSTRUCT) && buildstage != 0) //can't break the electronics if there isn't any inside.
stat |= BROKEN
+ LAZYREMOVE(myArea.firealarms, src)
update_icon()
/obj/machinery/firealarm/deconstruct(disassembled = TRUE)
@@ -204,6 +210,14 @@ FIRE ALARM
new /obj/item/stack/cable_coil(loc, 3)
qdel(src)
+/obj/machinery/firealarm/proc/update_fire_light(fire)
+ if(fire == !!light_power)
+ return // do nothing if we're already active
+ if(fire)
+ set_light(l_power = 0.8)
+ else
+ set_light(l_power = 0)
+
/obj/machinery/firealarm/process()//Note: this processing was mostly phased out due to other code, and only runs when needed
if(stat & (NOPOWER|BROKEN))
return
@@ -287,28 +301,16 @@ FIRE ALARM
time = min(max(round(time), 0), 120)
/obj/machinery/firealarm/proc/reset()
- if(!working)
+ if(!working || !report_fire_alarms)
return
var/area/A = get_area(src)
- A.fire_reset()
+ A.firereset(src)
- for(var/obj/machinery/firealarm/FA in A)
- if(is_station_contact(z) && FA.report_fire_alarms)
- SSalarms.fire_alarm.clearAlarm(loc, FA)
- enabled = FALSE
-
-/obj/machinery/firealarm/proc/alarm(var/duration = 0)
- if(!working)
+/obj/machinery/firealarm/proc/alarm()
+ if(!working || !report_fire_alarms)
return
-
var/area/A = get_area(src)
- for(var/obj/machinery/firealarm/FA in A)
- if(is_station_contact(z) && FA.report_fire_alarms)
- SSalarms.fire_alarm.triggerAlarm(loc, FA, duration)
- else
- A.fire_alert() // Manually trigger alarms if the alarm isn't reported
- enabled = TRUE
-
+ A.firealert(src) // Manually trigger alarms if the alarm isn't reported
update_icon()
/obj/machinery/firealarm/New(location, direction, building)
@@ -326,8 +328,14 @@ FIRE ALARM
else
overlays += image('icons/obj/monitors.dmi', "overlay_green")
+ myArea = get_area(src)
+ LAZYADD(myArea.firealarms, src)
update_icon()
+/obj/machinery/firealarm/Destroy()
+ LAZYREMOVE(myArea.firealarms, src)
+ return ..()
+
/*
FIRE ALARM CIRCUIT
Just a object used in constructing fire alarms
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index cd6b33d0a95..822c4af3e1a 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -255,6 +255,7 @@
occupant_typecache = typecacheof(occupant_typecache)
/obj/machinery/suit_storage_unit/Destroy()
+ SStgui.close_uis(wires)
QDEL_NULL(suit)
QDEL_NULL(helmet)
QDEL_NULL(mask)
@@ -802,3 +803,7 @@
/obj/machinery/suit_storage_unit/attack_ai(mob/user as mob)
return attack_hand(user)
+
+/obj/machinery/suit_storage_unit/proc/check_electrified_callback()
+ if(!wires.is_cut(WIRE_ELECTRIFY))
+ shocked = FALSE
diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm
index 181d5e494da..2a476c215ef 100644
--- a/code/game/machinery/syndicatebomb.dm
+++ b/code/game/machinery/syndicatebomb.dm
@@ -91,6 +91,7 @@
..()
/obj/machinery/syndicatebomb/Destroy()
+ SStgui.close_uis(wires)
QDEL_NULL(wires)
QDEL_NULL(countdown)
STOP_PROCESSING(SSfastprocess, src)
@@ -174,7 +175,7 @@
. = TRUE
if(!I.use_tool(src, user, 0, volume = I.tool_volume))
return
- if(open_panel && wires.IsAllCut())
+ if(open_panel && wires.is_all_cut())
if(payload)
to_chat(user, "You carefully pry out [payload].")
payload.loc = user.loc
@@ -188,7 +189,7 @@
/obj/machinery/syndicatebomb/welder_act(mob/user, obj/item/I)
. = TRUE
- if(payload || !wires.IsAllCut() || !open_panel)
+ if(payload || !wires.is_all_cut() || !open_panel)
return
if(!I.tool_use_check(user, 0))
return
@@ -264,9 +265,6 @@
investigate_log("[key_name(user)] has has primed a [name] ([payload]) for detonation at [A.name] [COORD(bombturf)]", INVESTIGATE_BOMB)
payload.adminlog = "\The [src] that [key_name(user)] had primed detonated!"
-/obj/machinery/syndicatebomb/proc/isWireCut(var/index)
- return wires.IsIndexCut(index)
-
///Bomb Subtypes///
/obj/machinery/syndicatebomb/training
@@ -297,7 +295,7 @@
/obj/machinery/syndicatebomb/empty/New()
..()
- wires.CutAll()
+ wires.cut_all()
/obj/machinery/syndicatebomb/self_destruct
name = "self destruct device"
@@ -368,7 +366,7 @@
var/obj/machinery/syndicatebomb/holder = loc
if(istype(holder))
if(holder.wires)
- holder.wires.Shuffle()
+ holder.wires.shuffle_wires()
holder.defused = 0
holder.open_panel = 0
holder.delayedbig = FALSE
diff --git a/code/game/machinery/transformer.dm b/code/game/machinery/transformer.dm
index cc9fc3e4666..18abeba7400 100644
--- a/code/game/machinery/transformer.dm
+++ b/code/game/machinery/transformer.dm
@@ -6,17 +6,45 @@
layer = MOB_LAYER+1 // Overhead
anchored = 1
density = 1
- var/transform_dead = 0
- var/transform_standing = 0
- var/cooldown_duration = 600 // 1 minute
- var/cooldown = 0
- var/robot_cell_charge = 5000
+ /// TRUE if the factory can transform dead mobs.
+ var/transform_dead = TRUE
+ /// TRUE if the mob can be standing and still be transformed.
+ var/transform_standing = TRUE
+ /// Cooldown between each transformation, in deciseconds.
+ var/cooldown_duration = 1 MINUTES
+ /// If the factory is currently on cooldown from its last transformation.
+ var/is_on_cooldown = FALSE
+ /// The type of cell that newly created borgs get.
+ var/robot_cell_type = /obj/item/stock_parts/cell/high/plus
+ /// The direction that mobs must moving in to get transformed.
var/acceptdir = EAST
+ /// The AI who placed this factory.
+ var/mob/living/silicon/ai/masterAI
-/obj/machinery/transformer/New()
- // On us
- ..()
- new /obj/machinery/conveyor/auto(loc, WEST)
+/obj/machinery/transformer/Initialize(mapload, mob/living/silicon/ai/_ai = null)
+ . = ..()
+ if(_ai)
+ masterAI = _ai
+ initialize_belts()
+
+/// Used to create all of the belts the transformer will be using. All belts should be pushing `WEST`.
+/obj/machinery/transformer/proc/initialize_belts()
+ var/turf/T = get_turf(src)
+ if(!T)
+ return
+
+ // Belt under the factory.
+ new /obj/machinery/conveyor/auto(T, WEST)
+
+ // Get the turf 1 tile to the EAST.
+ var/turf/east = locate(T.x + 1, T.y, T.z)
+ if(istype(east, /turf/simulated/floor))
+ new /obj/machinery/conveyor/auto(east, WEST)
+
+ // Get the turf 1 tile to the WEST.
+ var/turf/west = locate(T.x - 1, T.y, T.z)
+ if(istype(west, /turf/simulated/floor))
+ new /obj/machinery/conveyor/auto(west, WEST)
/obj/machinery/transformer/power_change()
..()
@@ -24,7 +52,7 @@
/obj/machinery/transformer/update_icon()
..()
- if(stat & (BROKEN|NOPOWER) || cooldown == 1)
+ if(is_on_cooldown || stat & (BROKEN|NOPOWER))
icon_state = "separator-AO0"
else
icon_state = initial(icon_state)
@@ -35,120 +63,76 @@
C.setDir(newdir)
acceptdir = turn(newdir, 180)
-/obj/machinery/transformer/Bumped(var/atom/movable/AM)
+/// Resets `is_on_cooldown` to `FALSE` and updates our icon. Used in a callback after the transformer does a transformation.
+/obj/machinery/transformer/proc/reset_cooldown()
+ is_on_cooldown = FALSE
+ update_icon()
- if(cooldown == 1)
+/obj/machinery/transformer/Bumped(atom/movable/AM)
+ // They have to be human to be transformed.
+ if(is_on_cooldown || !ishuman(AM))
return
- // Crossed didn't like people lying down.
- if(ishuman(AM))
- // Only humans can enter from the west side, while lying down.
- var/move_dir = get_dir(loc, AM.loc)
- var/mob/living/carbon/human/H = AM
- if((transform_standing || H.lying) && move_dir == acceptdir)// || move_dir == WEST)
- AM.loc = src.loc
- do_transform(AM)
+ var/mob/living/carbon/human/H = AM
+ var/move_dir = get_dir(loc, H.loc)
-/obj/machinery/transformer/proc/do_transform(var/mob/living/carbon/human/H)
- if(stat & (BROKEN|NOPOWER))
- return
- if(cooldown == 1)
+ if((transform_standing || H.lying) && move_dir == acceptdir)
+ H.forceMove(drop_location())
+ do_transform(H)
+
+/// Transforms a human mob into a cyborg, connects them to the malf AI which placed the factory.
+/obj/machinery/transformer/proc/do_transform(mob/living/carbon/human/H)
+ if(is_on_cooldown || stat & (BROKEN|NOPOWER))
return
if(!transform_dead && H.stat == DEAD)
- playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
return
- playsound(src.loc, 'sound/items/welder.ogg', 50, 1)
- H.emote("scream") // It is painful
- H.adjustBruteLoss(max(0, 80 - H.getBruteLoss())) // Hurt the human, don't try to kill them though.
-
- // Sleep for a couple of ticks to allow the human to see the pain
- sleep(5)
-
+ playsound(loc, 'sound/items/welder.ogg', 50, 1)
use_power(5000) // Use a lot of power.
- var/mob/living/silicon/robot/R = H.Robotize(1) // Delete the items or they'll all pile up in a single tile and lag
-
- R.cell.maxcharge = robot_cell_charge
- R.cell.charge = robot_cell_charge
-
- // So he can't jump out the gate right away.
- R.lockcharge = !R.lockcharge
- spawn(50)
- playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
- sleep(30)
- if(R)
- R.lockcharge = !R.lockcharge
- R.notify_ai(1)
// Activate the cooldown
- cooldown = 1
+ is_on_cooldown = TRUE
update_icon()
- spawn(cooldown_duration)
- cooldown = 0
- update_icon()
-
-/obj/machinery/transformer/conveyor/New()
- ..()
- var/turf/T = loc
- if(T)
- // Spawn Conveyour Belts
-
- //East
- var/turf/east = locate(T.x + 1, T.y, T.z)
- if(istype(east, /turf/simulated/floor))
- new /obj/machinery/conveyor/auto(east, WEST)
-
- // West
- var/turf/west = locate(T.x - 1, T.y, T.z)
- if(istype(west, /turf/simulated/floor))
- new /obj/machinery/conveyor/auto(west, WEST)
+ addtimer(CALLBACK(src, .proc/reset_cooldown), cooldown_duration)
+ addtimer(CALLBACK(null, .proc/playsound, loc, 'sound/machines/ping.ogg', 50, 0), 3 SECONDS)
+ H.emote("scream")
+ if(!masterAI) // If the factory was placed via admin spawning or other means, it wont have an owner_AI.
+ H.Robotize(robot_cell_type)
+ return
+ var/mob/living/silicon/robot/R = H.Robotize(robot_cell_type, FALSE, masterAI)
+ if(R.mind && !R.client && !R.grab_ghost()) // Make sure this is an actual player first and not just a humanized monkey or something.
+ message_admins("[key_name_admin(R)] was just transformed by a borg factory, but they were SSD. Polling ghosts for a replacement.")
+ var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a malfunctioning cyborg?", ROLE_TRAITOR, poll_time = 15 SECONDS)
+ if(!length(candidates))
+ return
+ var/mob/dead/observer/O = pick(candidates)
+ R.key= O.key
/obj/machinery/transformer/mime
name = "Mimetech Greyscaler"
desc = "Turns anything placed inside black and white."
-
-/obj/machinery/transformer/mime/conveyor/New()
- ..()
- var/turf/T = loc
- if(T)
- // Spawn Conveyour Belts
-
- //East
- var/turf/east = locate(T.x + 1, T.y, T.z)
- if(istype(east, /turf/simulated/floor))
- new /obj/machinery/conveyor/auto(east, WEST)
-
- // West
- var/turf/west = locate(T.x - 1, T.y, T.z)
- if(istype(west, /turf/simulated/floor))
- new /obj/machinery/conveyor/auto(west, WEST)
-
-/obj/machinery/transformer/mime/Bumped(var/atom/movable/AM)
-
- if(cooldown == 1)
+/obj/machinery/transformer/mime/Bumped(atom/movable/AM)
+ if(is_on_cooldown)
return
// Crossed didn't like people lying down.
- if(isatom(AM))
- AM.loc = src.loc
+ if(istype(AM))
+ AM.forceMove(drop_location())
do_transform_mime(AM)
else
to_chat(AM, "Only items can be greyscaled.")
return
-/obj/machinery/transformer/proc/do_transform_mime(var/obj/item/I)
- if(stat & (BROKEN|NOPOWER))
- return
- if(cooldown == 1)
+/obj/machinery/transformer/proc/do_transform_mime(obj/item/I)
+ if(is_on_cooldown || stat & (BROKEN|NOPOWER))
return
- playsound(src.loc, 'sound/items/welder.ogg', 50, 1)
- // Sleep for a couple of ticks to allow the human to see the pain
- sleep(5)
+ playsound(loc, 'sound/items/welder.ogg', 50, 1)
use_power(5000) // Use a lot of power.
var/icon/newicon = new(I.icon, I.icon_state)
@@ -156,42 +140,27 @@
I.icon = newicon
// Activate the cooldown
- cooldown = 1
+ is_on_cooldown = TRUE
update_icon()
- spawn(cooldown_duration)
- cooldown = 0
- update_icon()
+ addtimer(CALLBACK(src, .proc/reset_cooldown), cooldown_duration)
/obj/machinery/transformer/xray
name = "Automatic X-Ray 5000"
desc = "A large metalic machine with an entrance and an exit. A sign on the side reads, 'backpack go in, backpack come out', 'human go in, irradiated human come out'."
+ acceptdir = WEST
-/obj/machinery/transformer/xray/Initialize(mapload)
- . = ..()
- // On us
- new /obj/machinery/conveyor/auto(loc, EAST)
-
-/obj/machinery/transformer/xray/conveyor/New()
- ..()
- var/turf/T = loc
+/obj/machinery/transformer/xray/initialize_belts()
+ var/turf/T = get_turf(src)
if(T)
- // Spawn Conveyour Belts
+ // This handles the belt under the transformer and 1 tile to the left and right.
+ . = ..()
- //East
- var/turf/east = locate(T.x + 1, T.y, T.z)
- if(istype(east, /turf/simulated/floor))
- new /obj/machinery/conveyor/auto(east, EAST)
- //East2
+ // Get the turf 2 tiles to the EAST.
var/turf/east2 = locate(T.x + 2, T.y, T.z)
if(istype(east2, /turf/simulated/floor))
new /obj/machinery/conveyor/auto(east2, EAST)
- // West
- var/turf/west = locate(T.x - 1, T.y, T.z)
- if(istype(west, /turf/simulated/floor))
- new /obj/machinery/conveyor/auto(west, EAST)
-
- // West2
+ // Get the turf 2 tiles to the WEST.
var/turf/west2 = locate(T.x - 2, T.y, T.z)
if(istype(west2, /turf/simulated/floor))
new /obj/machinery/conveyor/auto(west2, EAST)
@@ -207,30 +176,30 @@
else
icon_state = initial(icon_state)
-/obj/machinery/transformer/xray/Bumped(var/atom/movable/AM)
-
- if(cooldown == 1)
+/obj/machinery/transformer/xray/Bumped(atom/movable/AM)
+ if(is_on_cooldown)
return
// Crossed didn't like people lying down.
if(ishuman(AM))
// Only humans can enter from the west side, while lying down.
- var/move_dir = get_dir(loc, AM.loc)
var/mob/living/carbon/human/H = AM
- if(H.lying && move_dir == WEST)// || move_dir == WEST)
- AM.loc = src.loc
- irradiate(AM)
+ var/move_dir = get_dir(loc, H.loc)
- else if(isatom(AM))
- AM.loc = src.loc
+ if(H.lying && move_dir == acceptdir)
+ H.forceMove(drop_location())
+ irradiate(H)
+
+ else if(istype(AM))
+ AM.forceMove(drop_location())
scan(AM)
-/obj/machinery/transformer/xray/proc/irradiate(var/mob/living/carbon/human/H)
+/obj/machinery/transformer/xray/proc/irradiate(mob/living/carbon/human/H)
if(stat & (BROKEN|NOPOWER))
return
flick("separator-AO0",src)
- playsound(src.loc, 'sound/effects/alert.ogg', 50, 0)
+ playsound(loc, 'sound/effects/alert.ogg', 50, 0)
sleep(5)
H.apply_effect((rand(150,200)),IRRADIATE,0)
if(prob(5))
@@ -242,15 +211,15 @@
domutcheck(H,null,1)
-/obj/machinery/transformer/xray/proc/scan(var/obj/item/I)
+/obj/machinery/transformer/xray/proc/scan(obj/item/I)
if(scan_rec(I))
- playsound(src.loc, 'sound/effects/alert.ogg', 50, 0)
+ playsound(loc, 'sound/effects/alert.ogg', 50, 0)
flick("separator-AO0",src)
else
- playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
+ playsound(loc, 'sound/machines/ping.ogg', 50, 0)
sleep(30)
-/obj/machinery/transformer/xray/proc/scan_rec(var/obj/item/I)
+/obj/machinery/transformer/xray/proc/scan_rec(obj/item/I)
if(istype(I, /obj/item/gun))
return TRUE
if(istype(I, /obj/item/transfer_valve))
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index afed001f63e..d7a2213c5b7 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -101,6 +101,7 @@
power_change()
/obj/machinery/vending/Destroy()
+ SStgui.close_uis(wires)
QDEL_NULL(wires)
QDEL_NULL(coin)
QDEL_NULL(inserted_item)
diff --git a/code/game/objects/items/blueprints.dm b/code/game/objects/items/blueprints.dm
index 5f5c62abd21..97e46e3abb5 100644
--- a/code/game/objects/items/blueprints.dm
+++ b/code/game/objects/items/blueprints.dm
@@ -221,6 +221,12 @@
A.contents += thing
thing.change_area(old_area, A)
+ var/area/oldA = get_area(get_turf(usr))
+ var/list/firedoors = oldA.firedoors
+ for(var/door in firedoors)
+ var/obj/machinery/door/firedoor/FD = door
+ FD.CalculateAffectingAreas()
+
interact()
area_created = TRUE
return area_created
@@ -236,6 +242,10 @@
return
set_area_machinery_title(A,str,prevname)
A.name = str
+ if(A.firedoors)
+ for(var/D in A.firedoors)
+ var/obj/machinery/door/firedoor/FD = D
+ FD.CalculateAffectingAreas()
to_chat(usr, "You rename the '[prevname]' to '[str]'.")
interact()
return 1
diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm
index 59d2c2a99bd..c8122fc34d6 100644
--- a/code/game/objects/items/devices/radio/intercom.dm
+++ b/code/game/objects/items/devices/radio/intercom.dm
@@ -186,10 +186,10 @@
update_icon()
START_PROCESSING(SSobj, src)
for(var/i, i<= 5, i++)
- wires.UpdateCut(i,1)
+ wires.on_cut(i, 1)
/obj/item/radio/intercom/wirecutter_act(mob/user, obj/item/I)
- if(!(buildstage == 3 && b_stat && wires.IsAllCut()))
+ if(!(buildstage == 3 && b_stat && wires.is_all_cut()))
return
. = TRUE
if(!I.use_tool(src, user, 0, volume = I.tool_volume))
@@ -270,4 +270,4 @@
/obj/item/radio/intercom/locked/prison/New()
..()
- wires.CutWireIndex(RADIO_WIRE_TRANSMIT)
+ wires.cut(WIRE_RADIO_TRANSMIT)
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index f18c862f878..528be3c5f87 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -76,6 +76,7 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
GLOB.global_radios |= src
/obj/item/radio/Destroy()
+ SStgui.close_uis(wires)
QDEL_NULL(wires)
if(SSradio)
SSradio.remove_object(src, frequency)
@@ -127,8 +128,8 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
data["freq"] = format_frequency(frequency)
data["rawfreq"] = num2text(frequency)
- data["mic_cut"] = (wires.IsIndexCut(RADIO_WIRE_TRANSMIT) || wires.IsIndexCut(RADIO_WIRE_SIGNAL))
- data["spk_cut"] = (wires.IsIndexCut(RADIO_WIRE_RECEIVE) || wires.IsIndexCut(RADIO_WIRE_SIGNAL))
+ data["mic_cut"] = (wires.is_cut(WIRE_RADIO_TRANSMIT) || wires.is_cut(WIRE_RADIO_SIGNAL))
+ data["spk_cut"] = (wires.is_cut(WIRE_RADIO_RECEIVER) || wires.is_cut(WIRE_RADIO_SIGNAL))
var/list/chanlist = list_channels(user)
if(islist(chanlist) && chanlist.len)
@@ -184,10 +185,10 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
return can_admin_interact()
/obj/item/radio/proc/ToggleBroadcast()
- broadcasting = !broadcasting && !(wires.IsIndexCut(RADIO_WIRE_TRANSMIT) || wires.IsIndexCut(RADIO_WIRE_SIGNAL))
+ broadcasting = !broadcasting && !(wires.is_cut(WIRE_RADIO_TRANSMIT) || wires.is_cut(WIRE_RADIO_SIGNAL))
/obj/item/radio/proc/ToggleReception()
- listening = !listening && !(wires.IsIndexCut(RADIO_WIRE_RECEIVE) || wires.IsIndexCut(RADIO_WIRE_SIGNAL))
+ listening = !listening && !(wires.is_cut(WIRE_RADIO_RECEIVER) || wires.is_cut(WIRE_RADIO_SIGNAL))
/obj/item/radio/Topic(href, href_list)
if(..())
@@ -334,7 +335,7 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
// Uncommenting this. To the above comment:
// The permacell radios aren't suppose to be able to transmit, this isn't a bug and this "fix" is just making radio wires useless. -Giacom
- if(wires.IsIndexCut(RADIO_WIRE_TRANSMIT)) // The device has to have all its wires and shit intact
+ if(wires.is_cut(WIRE_RADIO_TRANSMIT)) // The device has to have all its wires and shit intact
return 0
if(!M.IsVocal())
@@ -515,7 +516,7 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
var/is_listening = TRUE
if(!on)
is_listening = FALSE
- if(!wires || wires.IsIndexCut(RADIO_WIRE_RECEIVE))
+ if(!wires || wires.is_cut(WIRE_RADIO_RECEIVER))
is_listening = FALSE
if(!listening)
is_listening = FALSE
diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm
index 9ded7947202..abc267d3a34 100644
--- a/code/game/objects/items/weapons/tanks/tanks.dm
+++ b/code/game/objects/items/weapons/tanks/tanks.dm
@@ -43,35 +43,31 @@
/obj/item/tank/proc/toggle_internals(mob/user, silent = FALSE)
var/mob/living/carbon/C = user
if(!istype(C))
- return 0
+ return FALSE
if(C.internal == src)
to_chat(C, "You close \the [src] valve.")
C.internal = null
else
- var/can_open_valve = 0
- if(C.get_organ_slot("breathing_tube"))
- can_open_valve = 1
- else if(C.wear_mask && C.wear_mask.flags & AIRTIGHT)
- can_open_valve = 1
- else if(ishuman(C))
- var/mob/living/carbon/human/H = C
- if(H.head && H.head.flags & AIRTIGHT)
- can_open_valve = 1
+ if(!C.get_organ_slot("breathing_tube")) // Breathing tubes can always use internals, if they have one, skip ahead and turn internals on/off
+ if(!C.wear_mask) // Do we have a mask equipped?
+ return FALSE
- if(can_open_valve)
+ var/obj/item/clothing/mask/M = C.wear_mask
+ // If the "mask" isn't actually a mask OR That mask isn't internals compatible AND Their headgear isn't internals compatible
+ if(!istype(M) || (!(initial(M.flags) & AIRTIGHT) && !(C.head.flags & AIRTIGHT)))
+ if(!silent)
+ to_chat(C, "You are not wearing a suitable mask or helmet.")
+ return FALSE
+ if(M.mask_adjusted) // If the mask is equipped but pushed down
+ M.adjustmask(C) // Adjust it back
+
+ if(!silent)
if(C.internal)
- if(!silent)
- to_chat(C, "You switch your internals to [src].")
+ to_chat(C, "You switch your internals to [src].")
else
- if(!silent)
- to_chat(C, "You open \the [src] valve.")
- C.internal = src
- else
- if(!silent)
- to_chat(C, "You are not wearing a suitable mask or helmet.")
- return 0
-
+ to_chat(C, "You open \the [src] valve.")
+ C.internal = src
C.update_action_buttons_icon()
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm
index fd67afcf797..311bc4a38c7 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm
@@ -45,8 +45,6 @@
new /obj/item/clothing/suit/storage/labcoat(src)
new /obj/item/radio/headset/headset_sci(src)
new /obj/item/radio/headset/headset_sci(src)
- new /obj/item/reagent_containers/food/drinks/oilcan(src)
- new /obj/item/reagent_containers/food/drinks/oilcan(src)
/obj/structure/closet/secure_closet/RD
name = "research director's locker"
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 8d1f3920c0c..2f90e4d7cc4 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -263,6 +263,13 @@
if(SSair && !ignore_air)
SSair.add_to_active(src)
+ //update firedoor adjacency
+ var/list/turfs_to_check = get_adjacent_open_turfs(src) | src
+ for(var/I in turfs_to_check)
+ var/turf/T = I
+ for(var/obj/machinery/door/firedoor/FD in T)
+ FD.CalculateAffectingAreas()
+
if(!keep_cabling && !can_have_cabling())
for(var/obj/structure/cable/C in contents)
qdel(C)
diff --git a/code/modules/alarm/alarm.dm b/code/modules/alarm/alarm.dm
deleted file mode 100644
index 752d3232d23..00000000000
--- a/code/modules/alarm/alarm.dm
+++ /dev/null
@@ -1,136 +0,0 @@
-#define ALARM_RESET_DELAY 100 // How long will the alarm/trigger remain active once origin/source has been found to be gone?
-
-/datum/alarm_source
- var/source = null // The source trigger
- var/source_name = "" // The name of the source should it be lost (for example a destroyed camera)
- var/duration = 0 // How long this source will be alarming, 0 for indefinetely.
- var/severity = 1 // How severe the alarm from this source is.
- var/start_time = 0 // When this source began alarming.
- var/end_time = 0 // Use to set when this trigger should clear, in case the source is lost.
-
-/datum/alarm_source/New(var/atom/source)
- src.source = source
- start_time = world.time
- source_name = source.get_source_name()
-
-/datum/alarm
- var/atom/origin //Used to identify the alarm area.
- var/list/sources = new() //List of sources triggering the alarm. Used to determine when the alarm should be cleared.
- var/list/sources_assoc = new() //Associative list of source triggers. Used to efficiently acquire the alarm source.
- var/list/cameras //List of cameras that can be switched to, if the player has that capability.
- var/area/last_area //The last acquired area, used should origin be lost (for example a destroyed borg containing an alarming camera).
- var/area/last_name //The last acquired name, used should origin be lost
- var/area/last_camera_area //The last area in which cameras where fetched, used to see if the camera list should be updated.
- var/end_time //Used to set when this alarm should clear, in case the origin is lost.
-
-/datum/alarm/New(var/atom/origin, var/atom/source, var/duration, var/severity)
- src.origin = origin
-
- cameras() // Sets up both cameras and last alarm area.
- set_source_data(source, duration, severity)
-
-/datum/alarm/process()
- // Has origin gone missing?
- if(!origin && !end_time)
- end_time = world.time + ALARM_RESET_DELAY
- for(var/datum/alarm_source/AS in sources)
- // Has the alarm passed its best before date?
- if((AS.end_time && world.time > AS.end_time) || (AS.duration && world.time > (AS.start_time + AS.duration)))
- sources -= AS
- // Has the source gone missing? Then reset the normal duration and set end_time
- if(!AS.source && !AS.end_time) // end_time is used instead of duration to ensure the reset doesn't remain in the future indefinetely.
- AS.duration = 0
- AS.end_time = world.time + ALARM_RESET_DELAY
-
-/datum/alarm/proc/set_source_data(var/atom/source, var/duration, var/severity)
- var/datum/alarm_source/AS = sources_assoc[source]
- if(!AS)
- AS = new/datum/alarm_source(source)
- sources += AS
- sources_assoc[source] = AS
- // Currently only non-0 durations can be altered (normal alarms VS EMP blasts)
- if(AS.duration)
- duration = duration SECONDS
- AS.duration = duration
- AS.severity = severity
-
-/datum/alarm/proc/clear(var/source)
- var/datum/alarm_source/AS = sources_assoc[source]
- sources -= AS
- sources_assoc -= source
-
-/datum/alarm/proc/alarm_area()
- if(!origin)
- return last_area
-
- last_area = origin.get_alarm_area()
- return last_area
-
-/datum/alarm/proc/alarm_name()
- if(!origin)
- return last_name
-
- last_name = origin.get_alarm_name()
- return last_name
-
-/datum/alarm/proc/cameras()
- // If the alarm origin has changed area, for example a borg containing an alarming camera, reset the list of cameras
- if(cameras && (last_camera_area != alarm_area()))
- cameras = null
-
- // The list of cameras is also reset by /proc/invalidateCameraCache()
- if(!cameras)
- cameras = origin ? origin.get_alarm_cameras() : last_area.get_alarm_cameras()
-
- last_camera_area = last_area
- return cameras
-
-/datum/alarm/proc/max_severity()
- var/max_severity = 0
- for(var/datum/alarm_source/AS in sources)
- max_severity = max(AS.severity, max_severity)
-
- return max_severity
-
-/******************
-* Assisting procs *
-******************/
-/atom/proc/get_alarm_area()
- var/area/A = get_area(src)
- return A
-
-/area/get_alarm_area()
- return src
-
-/atom/proc/get_alarm_name()
- var/area/A = get_area(src)
- return A.name
-
-/area/get_alarm_name()
- return name
-
-/mob/get_alarm_name()
- return name
-
-/atom/proc/get_source_name()
- return name
-
-/obj/machinery/camera/get_source_name()
- return c_tag
-
-/atom/proc/get_alarm_cameras()
- var/area/A = get_area(src)
- return A.get_cameras()
-
-/area/get_alarm_cameras()
- return get_cameras()
-
-/mob/living/silicon/robot/get_alarm_cameras()
- var/list/cameras = ..()
- if(camera)
- cameras += camera
-
- return cameras
-
-/mob/living/silicon/robot/syndicate/get_alarm_cameras()
- return list()
diff --git a/code/modules/alarm/alarm_handler.dm b/code/modules/alarm/alarm_handler.dm
deleted file mode 100644
index 56a673bb5b4..00000000000
--- a/code/modules/alarm/alarm_handler.dm
+++ /dev/null
@@ -1,103 +0,0 @@
-#define ALARM_RAISED 1
-#define ALARM_CLEARED 0
-
-/datum/alarm_handler
- var/category = ""
- var/list/datum/alarm/alarms = new // All alarms, to handle cases when an origin has been deleted with one or more active alarms
- var/list/datum/alarm/alarms_assoc = new // Associative list of alarms, to efficiently acquire them based on origin.
- var/list/listeners = new // A list of all objects interested in alarm changes.
-
-/datum/alarm_handler/process()
- for(var/datum/alarm/A in alarms)
- A.process()
- check_alarm_cleared(A)
-
-/datum/alarm_handler/proc/triggerAlarm(var/atom/origin, var/atom/source, var/duration = 0, var/severity = 1)
- var/new_alarm
- //Proper origin and source mandatory
- if(!(origin && source))
- return
- origin = origin.get_alarm_origin()
-
- new_alarm = 0
- //see if there is already an alarm of this origin
- var/datum/alarm/existing = alarms_assoc[origin]
- if(existing)
- existing.set_source_data(source, duration, severity)
- else
- existing = new/datum/alarm(origin, source, duration, severity)
- new_alarm = 1
-
- alarms |= existing
- alarms_assoc[origin] = existing
- if(new_alarm)
- alarms = dd_sortedObjectList(alarms)
- on_alarm_change(existing, ALARM_RAISED)
-
- return new_alarm
-
-/datum/alarm_handler/proc/clearAlarm(var/atom/origin, var/source)
- //Proper origin and source mandatory
- if(!(origin && source))
- return
- origin = origin.get_alarm_origin()
-
- var/datum/alarm/existing = alarms_assoc[origin]
- if(existing)
- existing.clear(source)
- return check_alarm_cleared(existing)
-
-/datum/alarm_handler/proc/has_major_alarms()
- if(alarms && alarms.len)
- return 1
- return 0
-
-/datum/alarm_handler/proc/major_alarms()
- return alarms
-
-/datum/alarm_handler/proc/minor_alarms()
- return alarms
-
-/datum/alarm_handler/proc/check_alarm_cleared(var/datum/alarm/alarm)
- if((alarm.end_time && world.time > alarm.end_time) || !alarm.sources.len)
- alarms -= alarm
- alarms_assoc -= alarm.origin
- on_alarm_change(alarm, ALARM_CLEARED)
- return 1
- return 0
-
-/datum/alarm_handler/proc/on_alarm_change(var/datum/alarm/alarm, var/was_raised)
- for(var/obj/machinery/camera/C in alarm.cameras())
- if(was_raised)
- C.network.Add(category)
- else
- C.network.Remove(category)
- notify_listeners(alarm, was_raised)
-
-/datum/alarm_handler/proc/get_alarm_severity_for_origin(var/atom/origin)
- if(!origin)
- return
-
- origin = origin.get_alarm_origin()
- var/datum/alarm/existing = alarms_assoc[origin]
- if(!existing)
- return
-
- return existing.max_severity()
-
-/atom/proc/get_alarm_origin()
- return src
-
-/turf/get_alarm_origin()
- var/area/area = get_area(src)
- return area // Very important to get area.master, as dynamic lightning can and will split areas.
-
-/datum/alarm_handler/proc/register(var/object, var/procName)
- listeners[object] = procName
-
-/datum/alarm_handler/proc/unregister(var/object)
- listeners -= object
-
-/datum/alarm_handler/proc/notify_listeners(var/alarm, var/was_raised)
- for(var/listener in listeners)
- call(listener, listeners[listener])(src, alarm, was_raised)
diff --git a/code/modules/alarm/atmosphere_alarm.dm b/code/modules/alarm/atmosphere_alarm.dm
deleted file mode 100644
index cc29b40ac44..00000000000
--- a/code/modules/alarm/atmosphere_alarm.dm
+++ /dev/null
@@ -1,19 +0,0 @@
-/datum/alarm_handler/atmosphere
- category = "Atmosphere Alarms"
-
-/datum/alarm_handler/atmosphere/triggerAlarm(var/atom/origin, var/atom/source, var/duration = 0, var/severity = 1)
- ..()
-
-/datum/alarm_handler/atmosphere/major_alarms()
- var/list/major_alarms = new()
- for(var/datum/alarm/A in alarms)
- if(A.max_severity() > 1)
- major_alarms.Add(A)
- return major_alarms
-
-/datum/alarm_handler/atmosphere/minor_alarms()
- var/list/minor_alarms = new()
- for(var/datum/alarm/A in alarms)
- if(A.max_severity() == 1)
- minor_alarms.Add(A)
- return minor_alarms
diff --git a/code/modules/alarm/burglar_alarm.dm b/code/modules/alarm/burglar_alarm.dm
deleted file mode 100644
index c55cb12deef..00000000000
--- a/code/modules/alarm/burglar_alarm.dm
+++ /dev/null
@@ -1,2 +0,0 @@
-/datum/alarm_handler/burglar
- category = "Burglar Alarms"
diff --git a/code/modules/alarm/camera_alarm.dm b/code/modules/alarm/camera_alarm.dm
deleted file mode 100644
index bef53ad466f..00000000000
--- a/code/modules/alarm/camera_alarm.dm
+++ /dev/null
@@ -1,2 +0,0 @@
-/datum/alarm_handler/camera
- category = "Camera Alarms"
diff --git a/code/modules/alarm/fire_alarm.dm b/code/modules/alarm/fire_alarm.dm
deleted file mode 100644
index dfae3cc8177..00000000000
--- a/code/modules/alarm/fire_alarm.dm
+++ /dev/null
@@ -1,11 +0,0 @@
-/datum/alarm_handler/fire
- category = "Fire Alarms"
-
-/datum/alarm_handler/fire/on_alarm_change(var/datum/alarm/alarm, var/was_raised)
- var/area/A = alarm.origin
- if(istype(A))
- if(was_raised)
- A.fire_alert()
- else
- A.fire_reset()
- ..()
diff --git a/code/modules/alarm/motion_alarm.dm b/code/modules/alarm/motion_alarm.dm
deleted file mode 100644
index fd7e6febe48..00000000000
--- a/code/modules/alarm/motion_alarm.dm
+++ /dev/null
@@ -1,2 +0,0 @@
-/datum/alarm_handler/motion
- category = "Motion Alarms"
diff --git a/code/modules/alarm/power_alarm.dm b/code/modules/alarm/power_alarm.dm
deleted file mode 100644
index 4a0947a8f94..00000000000
--- a/code/modules/alarm/power_alarm.dm
+++ /dev/null
@@ -1,10 +0,0 @@
-/datum/alarm_handler/power
- category = "Power Alarms"
-
-/datum/alarm_handler/power/on_alarm_change(var/datum/alarm/alarm, var/was_raised)
- var/area/A = alarm.origin
- if(istype(A))
- A.power_alert(was_raised)
- ..()
-
-/area/proc/power_alert(var/alarming)
diff --git a/code/modules/assembly/assembly.dm b/code/modules/assembly/assembly.dm
index 5fea7baa019..6567dd62ede 100644
--- a/code/modules/assembly/assembly.dm
+++ b/code/modules/assembly/assembly.dm
@@ -1,3 +1,9 @@
+#define WIRE_RECEIVE (1<<0) //Allows pulse(0) to call Activate()
+#define WIRE_PULSE (1<<1) //Allows pulse(0) to act on the holder
+#define WIRE_PULSE_SPECIAL (1<<2) //Allows pulse(0) to act on the holders special assembly
+#define WIRE_RADIO_RECEIVE (1<<3) //Allows pulse(1) to call Activate()
+#define WIRE_RADIO_PULSE (1<<4) //Allows pulse(1) to send a radio message
+
/obj/item/assembly
name = "assembly"
desc = "A small electronic device that should never exist."
@@ -22,21 +28,12 @@
var/wires = WIRE_RECEIVE | WIRE_PULSE
var/datum/wires/connected = null // currently only used by timer/signaler
- var/const/WIRE_RECEIVE = 1 //Allows Pulsed(0) to call Activate()
- var/const/WIRE_PULSE = 2 //Allows Pulse(0) to act on the holder
- var/const/WIRE_PULSE_SPECIAL = 4 //Allows Pulse(0) to act on the holders special assembly
- var/const/WIRE_RADIO_RECEIVE = 8 //Allows Pulsed(1) to call Activate()
- var/const/WIRE_RADIO_PULSE = 16 //Allows Pulse(1) to send a radio message
-
/obj/item/assembly/proc/activate() //What the device does when turned on
return
/obj/item/assembly/proc/pulsed(radio = FALSE) //Called when another assembly acts on this one, var/radio will determine where it came from for wire calcs
return
-/obj/item/assembly/proc/pulse(radio = FALSE) //Called when this device attempts to act on another device, var/radio determines if it was sent via radio or direct
- return
-
/obj/item/assembly/proc/toggle_secure() //Code that has to happen when the assembly is un\secured goes here
return
@@ -79,7 +76,11 @@
activate()
return TRUE
-/obj/item/assembly/pulse(radio = FALSE)
+//Called when this device attempts to act on another device, var/radio determines if it was sent via radio or direct
+/obj/item/assembly/proc/pulse(radio = FALSE)
+ if(connected && wires)
+ connected.pulse_assembly(src)
+ return TRUE
if(holder && (wires & WIRE_PULSE))
holder.process_activation(src, 1, 0)
if(holder && (wires & WIRE_PULSE_SPECIAL))
diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm
index 2759d12c21a..0c3fcfec3ac 100644
--- a/code/modules/assembly/signaler.dm
+++ b/code/modules/assembly/signaler.dm
@@ -128,12 +128,6 @@
if(usr)
GLOB.lastsignalers.Add("[time] : [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) : [format_frequency(frequency)]/[code]")
-/obj/item/assembly/signaler/pulse(var/radio = FALSE)
- if(connected && wires)
- connected.Pulse(src)
- else
- return ..(radio)
-
/obj/item/assembly/signaler/receive_signal(datum/signal/signal)
if(!receiving || !signal)
return FALSE
diff --git a/code/modules/clothing/suits/jobs.dm b/code/modules/clothing/suits/jobs.dm
index a7bd3fb2627..6ffa40fe727 100644
--- a/code/modules/clothing/suits/jobs.dm
+++ b/code/modules/clothing/suits/jobs.dm
@@ -162,7 +162,7 @@
desc = "A slick, authoritative cloak designed for the Chief Engineer."
icon_state = "cemantle"
item_state = "cemantle"
- allowed = list(/obj/item/flashlight, /obj/item/tank, /obj/item/t_scanner, /obj/item/rcd)
+ allowed = list(/obj/item/flashlight, /obj/item/tank, /obj/item/t_scanner, /obj/item/rcd, /obj/item/rpd)
//Chief Medical Officer
/obj/item/clothing/suit/mantle/labcoat/chief_medical_officer
@@ -231,7 +231,7 @@
icon_state = "hazard"
item_state = "hazard"
blood_overlay_type = "armor"
- allowed = list (/obj/item/flashlight, /obj/item/t_scanner, /obj/item/tank/emergency_oxygen)
+ allowed = list (/obj/item/flashlight, /obj/item/t_scanner, /obj/item/tank/emergency_oxygen, /obj/item/rcd, /obj/item/rpd)
resistance_flags = NONE
sprite_sheets = list(
diff --git a/code/modules/events/apc_short.dm b/code/modules/events/apc_short.dm
index c19b6cbe8b7..fcb31972204 100644
--- a/code/modules/events/apc_short.dm
+++ b/code/modules/events/apc_short.dm
@@ -46,10 +46,10 @@
if(prob(APC_BREAK_PROBABILITY))
// if it has internal wires, cut the power wires
if(C.wires)
- if(!C.wires.IsIndexCut(APC_WIRE_MAIN_POWER1))
- C.wires.CutWireIndex(APC_WIRE_MAIN_POWER1)
- if(!C.wires.IsIndexCut(APC_WIRE_MAIN_POWER2))
- C.wires.CutWireIndex(APC_WIRE_MAIN_POWER2)
+ if(!C.wires.is_cut(WIRE_MAIN_POWER1))
+ C.wires.cut(WIRE_MAIN_POWER1)
+ if(!C.wires.is_cut(WIRE_MAIN_POWER2))
+ C.wires.cut(WIRE_MAIN_POWER2)
// if it was operating, toggle off the breaker
if(C.operating)
C.toggle_breaker()
diff --git a/code/modules/events/brand_intelligence.dm b/code/modules/events/brand_intelligence.dm
index 8d91635c458..35cc199c3ff 100644
--- a/code/modules/events/brand_intelligence.dm
+++ b/code/modules/events/brand_intelligence.dm
@@ -32,7 +32,7 @@
log_debug("Original brand intelligence machine: [originMachine] ([ADMIN_VV(originMachine,"VV")]) [ADMIN_JMP(originMachine)]")
/datum/event/brand_intelligence/tick()
- if(!originMachine || QDELETED(originMachine) || originMachine.shut_up || originMachine.wires.IsAllCut()) //if the original vending machine is missing or has it's voice switch flipped
+ if(!originMachine || QDELETED(originMachine) || originMachine.shut_up || originMachine.wires.is_all_cut()) //if the original vending machine is missing or has it's voice switch flipped
for(var/obj/machinery/vending/saved in infectedMachines)
saved.shoot_inventory = 0
if(originMachine)
diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
index f179de1459a..f6bb3c8e1c4 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
@@ -70,6 +70,7 @@
max_n_of_items = 1500 * B.rating
/obj/machinery/smartfridge/Destroy()
+ SStgui.close_uis(wires)
QDEL_NULL(wires)
for(var/atom/movable/A in contents)
A.forceMove(loc)
diff --git a/code/modules/hydroponics/grown/replicapod.dm b/code/modules/hydroponics/grown/replicapod.dm
index d6f8cae7519..0f2b54ab971 100644
--- a/code/modules/hydroponics/grown/replicapod.dm
+++ b/code/modules/hydroponics/grown/replicapod.dm
@@ -29,7 +29,8 @@
if(istype(W,/obj/item/reagent_containers/syringe))
if(!contains_sample)
for(var/datum/reagent/blood/bloodSample in W.reagents.reagent_list)
- if(bloodSample.data["mind"] && bloodSample.data["cloneable"] == 1)
+ var/datum/dna/dna = bloodSample.data["dna"]
+ if(bloodSample.data["mind"] && bloodSample.data["cloneable"] && !(NO_SCAN in dna.species.species_traits))
var/datum/mind/tempmind = bloodSample.data["mind"]
if(tempmind.is_revivable())
mind = bloodSample.data["mind"]
diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm
index fd675bac32c..058b64d3c18 100644
--- a/code/modules/mining/machine_vending.dm
+++ b/code/modules/mining/machine_vending.dm
@@ -1,104 +1,21 @@
-/**********************Mining Equipment Locker**************************/
+// Use this define to register something as a purchasable!
+// * n — The proper name of the purchasable
+// * o — The object type path of the purchasable to spawn
+// * p — The price of the purchasable in mining points
+#define EQUIPMENT(n, o, p) n = new /datum/data/mining_equipment(n, o, p)
+
+/**********************Mining Equipment Vendor**************************/
/obj/machinery/mineral/equipment_vendor
name = "mining equipment vendor"
desc = "An equipment vendor for miners, points collected at an ore redemption machine can be spent here."
icon = 'icons/obj/machines/mining_machines.dmi'
icon_state = "mining"
- density = 1
- anchored = 1.0
+ density = TRUE
+ anchored = TRUE
var/obj/item/card/id/inserted_id
- var/list/prize_list = list( //if you add something to this, please, for the love of god, sort it by price/type. use tabs and not spaces.
- new /datum/data/mining_equipment("1 Marker Beacon", /obj/item/stack/marker_beacon, 10),
- new /datum/data/mining_equipment("10 Marker Beacons", /obj/item/stack/marker_beacon/ten, 100),
- new /datum/data/mining_equipment("30 Marker Beacons", /obj/item/stack/marker_beacon/thirty, 300),
- new /datum/data/mining_equipment("Whiskey", /obj/item/reagent_containers/food/drinks/bottle/whiskey, 100),
- new /datum/data/mining_equipment("Absinthe", /obj/item/reagent_containers/food/drinks/bottle/absinthe/premium, 100),
- new /datum/data/mining_equipment("Cigar", /obj/item/clothing/mask/cigarette/cigar/havana, 150),
- new /datum/data/mining_equipment("Soap", /obj/item/soap/nanotrasen, 200),
- new /datum/data/mining_equipment("Laser Pointer", /obj/item/laser_pointer, 300),
- new /datum/data/mining_equipment("Alien Toy", /obj/item/clothing/mask/facehugger/toy, 300),
- new /datum/data/mining_equipment("Stabilizing Serum", /obj/item/hivelordstabilizer, 400),
- new /datum/data/mining_equipment("Space Cash", /obj/item/stack/spacecash/c1000, 2000),
- new /datum/data/mining_equipment("Point Transfer Card", /obj/item/card/mining_point_card, 500),
- new /datum/data/mining_equipment("Fulton Beacon", /obj/item/fulton_core, 400),
- new /datum/data/mining_equipment("Shelter Capsule", /obj/item/survivalcapsule, 400),
- new /datum/data/mining_equipment("GAR Meson Scanners", /obj/item/clothing/glasses/meson/gar, 500),
- new /datum/data/mining_equipment("Explorer's Webbing", /obj/item/storage/belt/mining, 500),
- new /datum/data/mining_equipment("Survival Medipen", /obj/item/reagent_containers/hypospray/autoinjector/survival, 500),
- new /datum/data/mining_equipment("Brute First-Aid Kit", /obj/item/storage/firstaid/brute, 600),
- new /datum/data/mining_equipment("Tracking Implant Kit", /obj/item/storage/box/minertracker, 600),
- new /datum/data/mining_equipment("Jaunter", /obj/item/wormhole_jaunter, 750),
- new /datum/data/mining_equipment("Kinetic Crusher", /obj/item/twohanded/kinetic_crusher, 750),
- new /datum/data/mining_equipment("Kinetic Accelerator", /obj/item/gun/energy/kinetic_accelerator, 750),
- new /datum/data/mining_equipment("Advanced Scanner", /obj/item/t_scanner/adv_mining_scanner, 800),
- new /datum/data/mining_equipment("Resonator", /obj/item/resonator, 800),
- new /datum/data/mining_equipment("Fulton Pack", /obj/item/extraction_pack, 1000),
- new /datum/data/mining_equipment("Lazarus Injector", /obj/item/lazarus_injector, 1000),
- new /datum/data/mining_equipment("Silver Pickaxe", /obj/item/pickaxe/silver, 1000),
- new /datum/data/mining_equipment("Mining Conscription Kit", /obj/item/storage/backpack/duffel/mining_conscript/full, 1500),
- new /datum/data/mining_equipment("Jetpack Upgrade", /obj/item/tank/jetpack/suit, 2000),
- new /datum/data/mining_equipment("Mining Hardsuit", /obj/item/clothing/suit/space/hardsuit/mining, 2000),
- new /datum/data/mining_equipment("Diamond Pickaxe", /obj/item/pickaxe/diamond, 2000),
- new /datum/data/mining_equipment("Super Resonator", /obj/item/resonator/upgraded, 2500),
- new /datum/data/mining_equipment("Jump Boots", /obj/item/clothing/shoes/bhop, 2500),
- new /datum/data/mining_equipment("Luxury Shelter Capsule", /obj/item/survivalcapsule/luxury, 3000),
- new /datum/data/mining_equipment("Nanotrasen Minebot", /obj/item/mining_drone_cube, 800),
- new /datum/data/mining_equipment("Minebot Melee Upgrade", /obj/item/mine_bot_upgrade, 400),
- new /datum/data/mining_equipment("Minebot Armor Upgrade", /obj/item/mine_bot_upgrade/health, 400),
- new /datum/data/mining_equipment("Minebot Cooldown Upgrade", /obj/item/borg/upgrade/modkit/cooldown/minebot, 600),
- new /datum/data/mining_equipment("Minebot AI Upgrade", /obj/item/slimepotion/sentience/mining, 1000),
- new /datum/data/mining_equipment("KA Minebot Passthrough", /obj/item/borg/upgrade/modkit/minebot_passthrough, 100),
- new /datum/data/mining_equipment("Lazarus Capsule", /obj/item/mobcapsule, 800),
- new /datum/data/mining_equipment("Lazarus Capsule belt", /obj/item/storage/belt/lazarus, 200),
- new /datum/data/mining_equipment("KA White Tracer Rounds", /obj/item/borg/upgrade/modkit/tracer, 100),
- new /datum/data/mining_equipment("KA Adjustable Tracer Rounds", /obj/item/borg/upgrade/modkit/tracer/adjustable, 150),
- new /datum/data/mining_equipment("KA Super Chassis", /obj/item/borg/upgrade/modkit/chassis_mod, 250),
- new /datum/data/mining_equipment("KA Hyper Chassis", /obj/item/borg/upgrade/modkit/chassis_mod/orange, 300),
- new /datum/data/mining_equipment("KA Range Increase", /obj/item/borg/upgrade/modkit/range, 1000),
- new /datum/data/mining_equipment("KA Damage Increase", /obj/item/borg/upgrade/modkit/damage, 1000),
- new /datum/data/mining_equipment("KA Cooldown Decrease", /obj/item/borg/upgrade/modkit/cooldown, 1000),
- new /datum/data/mining_equipment("KA AoE Damage", /obj/item/borg/upgrade/modkit/aoe/mobs, 2000)
- )
-
-/obj/machinery/mineral/equipment_vendor/golem
- name = "golem ship equipment vendor"
-
-/obj/machinery/mineral/equipment_vendor/golem/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/circuitboard/mining_equipment_vendor/golem(null)
- component_parts += new /obj/item/stock_parts/matter_bin(null)
- component_parts += new /obj/item/stock_parts/matter_bin(null)
- component_parts += new /obj/item/stock_parts/matter_bin(null)
- component_parts += new /obj/item/stack/sheet/glass(null)
- RefreshParts()
-
-/obj/machinery/mineral/equipment_vendor/golem/Initialize()
- . = ..()
- desc += "\nIt seems a few selections have been added."
- prize_list += list(
- new /datum/data/mining_equipment("Extra Id", /obj/item/card/id/golem, 250),
- new /datum/data/mining_equipment("Science Backpack", /obj/item/storage/backpack/science, 250),
- new /datum/data/mining_equipment("Full Toolbelt", /obj/item/storage/belt/utility/full/multitool, 250),
- new /datum/data/mining_equipment("Monkey Cube", /obj/item/reagent_containers/food/snacks/monkeycube, 250),
- new /datum/data/mining_equipment("Royal Cape of the Liberator", /obj/item/bedsheet/rd/royal_cape, 500),
- new /datum/data/mining_equipment("Grey Slime Extract", /obj/item/slime_extract/grey, 1000),
- new /datum/data/mining_equipment("KA Trigger Modification Kit", /obj/item/borg/upgrade/modkit/trigger_guard, 1000),
- new /datum/data/mining_equipment("Shuttle Console Board", /obj/item/circuitboard/shuttle/golem_ship, 2000),
- new /datum/data/mining_equipment("The Liberator's Legacy", /obj/item/storage/box/rndboards, 2000)
-
- )
-
-/datum/data/mining_equipment
- var/equipment_name = "generic"
- var/equipment_path = null
- var/cost = 0
-
-/datum/data/mining_equipment/New(name, path, equipment_cost)
- equipment_name = name
- equipment_path = path
- cost = equipment_cost
+ var/list/prize_list // Initialized just below! (if you're wondering why - check CONTRIBUTING.md, look for: "hidden" init proc)
+ var/dirty_items = FALSE // Used to refresh the static/redundant data in case the machine gets VV'd
/obj/machinery/mineral/equipment_vendor/New()
..()
@@ -110,6 +27,72 @@
component_parts += new /obj/item/stack/sheet/glass(null)
RefreshParts()
+/obj/machinery/mineral/equipment_vendor/Initialize(mapload)
+ . = ..()
+ prize_list = list()
+ prize_list["Gear"] = list(
+ EQUIPMENT("Advanced Scanner", /obj/item/t_scanner/adv_mining_scanner, 800),
+ EQUIPMENT("Explorer's Webbing", /obj/item/storage/belt/mining, 500),
+ EQUIPMENT("Fulton Beacon", /obj/item/fulton_core, 400),
+ EQUIPMENT("Mining Conscription Kit", /obj/item/storage/backpack/duffel/mining_conscript, 1500),
+ EQUIPMENT("Jetpack Upgrade", /obj/item/tank/jetpack/suit, 2000),
+ EQUIPMENT("Jump Boots", /obj/item/clothing/shoes/bhop, 2500),
+ EQUIPMENT("Lazarus Capsule", /obj/item/mobcapsule, 800),
+ EQUIPMENT("Lazarus Capsule belt", /obj/item/storage/belt/lazarus, 200),
+ EQUIPMENT("Mining Hardsuit", /obj/item/clothing/suit/space/hardsuit/mining, 2000),
+ EQUIPMENT("Tracking Implant Kit", /obj/item/storage/box/minertracker, 600),
+ )
+ prize_list["Consumables"] = list(
+ EQUIPMENT("10 Marker Beacons", /obj/item/stack/marker_beacon/ten, 100),
+ EQUIPMENT("Brute First-Aid Kit", /obj/item/storage/firstaid/brute, 600),
+ EQUIPMENT("Fulton Pack", /obj/item/extraction_pack, 1000),
+ EQUIPMENT("Jaunter", /obj/item/wormhole_jaunter, 750),
+ EQUIPMENT("Lazarus Injector", /obj/item/lazarus_injector, 1000),
+ EQUIPMENT("Point Transfer Card", /obj/item/card/mining_point_card, 500),
+ EQUIPMENT("Shelter Capsule", /obj/item/survivalcapsule, 400),
+ EQUIPMENT("Stabilizing Serum", /obj/item/hivelordstabilizer, 400),
+ EQUIPMENT("Survival Medipen", /obj/item/reagent_containers/hypospray/autoinjector/survival, 500),
+ )
+ prize_list["Kinetic Accelerator"] = list(
+ EQUIPMENT("Kinetic Accelerator", /obj/item/gun/energy/kinetic_accelerator, 750),
+ EQUIPMENT("KA Adjustable Tracer Rounds", /obj/item/borg/upgrade/modkit/tracer/adjustable, 150),
+ EQUIPMENT("KA AoE Damage", /obj/item/borg/upgrade/modkit/aoe/mobs, 2000),
+ EQUIPMENT("KA Cooldown Decrease", /obj/item/borg/upgrade/modkit/cooldown, 1000),
+ EQUIPMENT("KA Damage Increase", /obj/item/borg/upgrade/modkit/damage, 1000),
+ EQUIPMENT("KA Hyper Chassis", /obj/item/borg/upgrade/modkit/chassis_mod/orange, 300),
+ EQUIPMENT("KA Minebot Passthrough", /obj/item/borg/upgrade/modkit/minebot_passthrough, 100),
+ EQUIPMENT("KA Range Increase", /obj/item/borg/upgrade/modkit/range, 1000),
+ EQUIPMENT("KA Super Chassis", /obj/item/borg/upgrade/modkit/chassis_mod, 250),
+ EQUIPMENT("KA White Tracer Rounds", /obj/item/borg/upgrade/modkit/tracer, 100),
+ )
+ prize_list["Digging Tools"] = list(
+ EQUIPMENT("Diamond Pickaxe", /obj/item/pickaxe/diamond, 2000),
+ EQUIPMENT("Kinetic Accelerator", /obj/item/gun/energy/kinetic_accelerator, 750),
+ EQUIPMENT("Kinetic Crusher", /obj/item/twohanded/kinetic_crusher, 750),
+ EQUIPMENT("Resonator", /obj/item/resonator, 800),
+ EQUIPMENT("Silver Pickaxe", /obj/item/pickaxe/silver, 1000),
+ EQUIPMENT("Super Resonator", /obj/item/resonator/upgraded, 2500),
+ )
+ prize_list["Minebot"] = list(
+ EQUIPMENT("Nanotrasen Minebot", /obj/item/mining_drone_cube, 800),
+ EQUIPMENT("Minebot AI Upgrade", /obj/item/slimepotion/sentience/mining, 1000),
+ EQUIPMENT("Minebot Armor Upgrade", /obj/item/mine_bot_upgrade/health, 400),
+ EQUIPMENT("Minebot Cooldown Upgrade", /obj/item/borg/upgrade/modkit/cooldown/minebot, 600),
+ EQUIPMENT("Minebot Melee Upgrade", /obj/item/mine_bot_upgrade, 400),
+ )
+ prize_list["Miscellaneous"] = list(
+ EQUIPMENT("Absinthe", /obj/item/reagent_containers/food/drinks/bottle/absinthe/premium, 100),
+ EQUIPMENT("Alien Toy", /obj/item/clothing/mask/facehugger/toy, 300),
+ EQUIPMENT("Cigar", /obj/item/clothing/mask/cigarette/cigar/havana, 150),
+ EQUIPMENT("GAR Meson Scanners", /obj/item/clothing/glasses/meson/gar, 500),
+ EQUIPMENT("Laser Pointer", /obj/item/laser_pointer, 300),
+ EQUIPMENT("Luxury Shelter Capsule", /obj/item/survivalcapsule/luxury, 3000),
+ EQUIPMENT("Soap", /obj/item/soap/nanotrasen, 200),
+ EQUIPMENT("Space Cash", /obj/item/stack/spacecash/c1000, 2000),
+ EQUIPMENT("Whiskey", /obj/item/reagent_containers/food/drinks/bottle/whiskey, 100),
+ )
+ prize_list["Extra"] = list() // Used in child vendors
+
/obj/machinery/mineral/equipment_vendor/power_change()
..()
update_icon()
@@ -126,90 +109,126 @@
/obj/machinery/mineral/equipment_vendor/attack_hand(mob/user)
if(..())
return
- interact(user)
+ tgui_interact(user)
/obj/machinery/mineral/equipment_vendor/attack_ghost(mob/user)
- interact(user)
+ tgui_interact(user)
-/obj/machinery/mineral/equipment_vendor/interact(mob/user)
- user.set_machine(src)
+/obj/machinery/mineral/equipment_vendor/tgui_data(mob/user)
+ var/list/data[0]
- var/dat
- dat +="
"
- if(istype(inserted_id))
- dat += "You have [inserted_id.mining_points] mining points collected.
Eject ID."
+ // ID
+ if(inserted_id)
+ data["has_id"] = TRUE
+ data["id"] = list(
+ "name" = inserted_id.registered_name,
+ "points" = inserted_id.mining_points,
+ )
else
- dat += "No ID inserted.
Insert ID."
- dat += "
"
- dat += "
Equipment point cost list:
"
- for(var/datum/data/mining_equipment/prize in prize_list)
- dat += "| [prize.equipment_name] | [prize.cost] | Purchase |
"
- dat += "
"
- var/datum/browser/popup = new(user, "miningvendor", "Mining Equipment Vendor", 400, 350)
- popup.set_content(dat)
- popup.open()
+ data["has_id"] = FALSE
-/obj/machinery/mineral/equipment_vendor/Topic(href, href_list)
+ return data
+
+/obj/machinery/mineral/equipment_vendor/tgui_static_data(mob/user)
+ var/list/static_data[0]
+
+ // Available items - in static data because we don't wanna compute this list every time! It hardly changes.
+ static_data["items"] = list()
+ for(var/cat in prize_list)
+ var/list/cat_items = list()
+ for(var/prize_name in prize_list[cat])
+ var/datum/data/mining_equipment/prize = prize_list[cat][prize_name]
+ cat_items[prize_name] = list("name" = prize_name, "price" = prize.cost)
+ static_data["items"][cat] = cat_items
+
+ return static_data
+
+/obj/machinery/mineral/equipment_vendor/vv_edit_var(var_name, var_value)
+ // Gotta update the static data in case an admin VV's the items for some reason..!
+ if(var_name == "prize_list")
+ dirty_items = TRUE
+ return ..()
+
+/obj/machinery/mineral/equipment_vendor/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
+ // Update static data if need be
+ if(dirty_items)
+ if(!ui)
+ ui = SStgui.get_open_ui(user, src, ui_key)
+ if(ui) // OK so ui?. somehow breaks the implied src so this is needed
+ ui.initial_static_data = tgui_static_data(user)
+ dirty_items = FALSE
+
+ // Open the window
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "MiningVendor", name, 400, 450)
+ ui.open()
+ ui.set_autoupdate(FALSE)
+
+/obj/machinery/mineral/equipment_vendor/tgui_act(action, params)
if(..())
- return 1
+ return
- if(href_list["choice"])
- if(istype(inserted_id))
- if(href_list["choice"] == "eject")
- inserted_id.loc = loc
- inserted_id.verb_pickup()
- inserted_id = null
- else if(href_list["choice"] == "insert")
- var/obj/item/card/id/I = usr.get_active_hand()
- if(istype(I))
- if(!usr.drop_item())
- return
- I.loc = src
- inserted_id = I
- else
- to_chat(usr, "No valid ID.")
-
- if(href_list["purchase"])
- if(istype(inserted_id))
- var/datum/data/mining_equipment/prize = locate(href_list["purchase"])
- if(!prize || !(prize in prize_list) || prize.cost > inserted_id.mining_points)
+ . = TRUE
+ switch(action)
+ if("logoff")
+ if(!inserted_id)
+ return
+ usr.put_in_hands(inserted_id)
+ inserted_id = null
+ if("purchase")
+ if(!inserted_id)
+ return
+ var/category = params["cat"] // meow
+ var/name = params["name"]
+ if(!(category in prize_list) || !(name in prize_list[category])) // Not trying something that's not in the list, are you?
+ return
+ var/datum/data/mining_equipment/prize = prize_list[category][name]
+ if(prize.cost > inserted_id.mining_points) // shouldn't be able to access this since the button is greyed out, but..
+ to_chat(usr, "You have insufficient points.")
return
inserted_id.mining_points -= prize.cost
- new prize.equipment_path(src.loc)
- updateUsrDialog()
+ new prize.equipment_path(loc)
+ else
+ return FALSE
+ add_fingerprint()
/obj/machinery/mineral/equipment_vendor/attackby(obj/item/I, mob/user, params)
if(default_deconstruction_screwdriver(user, "mining-open", "mining", I))
- updateUsrDialog()
return
if(panel_open)
if(istype(I, /obj/item/crowbar))
if(inserted_id)
inserted_id.forceMove(loc) //Prevents deconstructing the ORM from deleting whatever ID was inside it.
default_deconstruction_crowbar(user, I)
- return 1
+ return TRUE
if(istype(I, /obj/item/mining_voucher))
if(!powered())
return
- else
- RedeemVoucher(I, user)
+ redeem_voucher(I, user)
return
- if(istype(I,/obj/item/card/id))
+ if(istype(I, /obj/item/card/id))
if(!powered())
return
- else
- var/obj/item/card/id/C = usr.get_active_hand()
- if(istype(C) && !istype(inserted_id))
- if(!usr.drop_item())
- return
- C.forceMove(src)
- inserted_id = C
- interact(user)
+ var/obj/item/card/id/C = user.get_active_hand()
+ if(istype(C) && !istype(inserted_id))
+ if(!user.drop_item())
+ return
+ C.forceMove(src)
+ inserted_id = C
+ tgui_interact(user)
return
return ..()
-/obj/machinery/mineral/equipment_vendor/proc/RedeemVoucher(obj/item/mining_voucher/voucher, mob/redeemer)
+/**
+ * Called when someone slaps the machine with a mining voucher
+ *
+ * Arguments:
+ * * voucher - The voucher card item
+ * * redeemer - The person holding it
+ */
+/obj/machinery/mineral/equipment_vendor/proc/redeem_voucher(obj/item/mining_voucher/voucher, mob/redeemer)
var/items = list("Survival Capsule and Explorer's Webbing", "Resonator Kit", "Minebot Kit", "Extraction and Rescue Kit", "Crusher Kit", "Mining Conscription Kit")
var/selection = input(redeemer, "Pick your equipment", "Mining Voucher Redemption") as null|anything in items
@@ -240,11 +259,51 @@
qdel(voucher)
/obj/machinery/mineral/equipment_vendor/ex_act(severity, target)
- do_sparks(5, 1, src)
+ do_sparks(5, TRUE, src)
if(prob(50 / severity) && severity < 3)
qdel(src)
-/**********************Mining Equipment Locker Items**************************/
+/**********************Mining Equiment Vendor (Golem)**************************/
+
+/obj/machinery/mineral/equipment_vendor/golem
+ name = "golem ship equipment vendor"
+
+/obj/machinery/mineral/equipment_vendor/golem/New()
+ ..()
+ component_parts = list()
+ component_parts += new /obj/item/circuitboard/mining_equipment_vendor/golem(null)
+ component_parts += new /obj/item/stock_parts/matter_bin(null)
+ component_parts += new /obj/item/stock_parts/matter_bin(null)
+ component_parts += new /obj/item/stock_parts/matter_bin(null)
+ component_parts += new /obj/item/stack/sheet/glass(null)
+ RefreshParts()
+
+/obj/machinery/mineral/equipment_vendor/golem/Initialize()
+ . = ..()
+ desc += "\nIt seems a few selections have been added."
+ prize_list["Extra"] += list(
+ EQUIPMENT("Extra ID", /obj/item/card/id/golem, 250),
+ EQUIPMENT("Science Backpack", /obj/item/storage/backpack/science, 250),
+ EQUIPMENT("Full Toolbelt", /obj/item/storage/belt/utility/full/multitool, 250),
+ EQUIPMENT("Monkey Cube", /obj/item/reagent_containers/food/snacks/monkeycube, 250),
+ EQUIPMENT("Royal Cape of the Liberator", /obj/item/bedsheet/rd/royal_cape, 500),
+ EQUIPMENT("Grey Slime Extract", /obj/item/slime_extract/grey, 1000),
+ EQUIPMENT("KA Trigger Modification Kit", /obj/item/borg/upgrade/modkit/trigger_guard, 1000),
+ EQUIPMENT("Shuttle Console Board", /obj/item/circuitboard/shuttle/golem_ship, 2000),
+ EQUIPMENT("The Liberator's Legacy", /obj/item/storage/box/rndboards, 2000),
+ )
+
+/**********************Mining Equipment Datum**************************/
+
+/datum/data/mining_equipment
+ var/equipment_name = "generic"
+ var/equipment_path = null
+ var/cost = 0
+
+/datum/data/mining_equipment/New(name, path, equipment_cost)
+ equipment_name = name
+ equipment_path = path
+ cost = equipment_cost
/**********************Mining Equipment Voucher**********************/
@@ -300,3 +359,5 @@
/obj/item/storage/backpack/duffel/mining_conscript/full/New()
..()
new /obj/item/card/id/mining_access_card(src)
+
+#undef EQUIPMENT
diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm
index c01d04beba8..54c23c89b5d 100644
--- a/code/modules/mining/ores_coins.dm
+++ b/code/modules/mining/ores_coins.dm
@@ -220,6 +220,7 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
var/datum/wires/explosive/gibtonite/wires
/obj/item/twohanded/required/gibtonite/Destroy()
+ SStgui.close_uis(wires)
QDEL_NULL(wires)
return ..()
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 60891563ad2..3739e337542 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -301,14 +301,13 @@
else if(nutrition >= NUTRITION_LEVEL_FAT)
msg += "[p_they(TRUE)] [p_are()] quite chubby.\n"
- if(!ismachineperson(src) && blood_volume < BLOOD_VOLUME_SAFE)
+ if(blood_volume < BLOOD_VOLUME_SAFE)
msg += "[p_they(TRUE)] [p_have()] pale skin.\n"
if(bleedsuppress)
msg += "[p_they(TRUE)] [p_are()] bandaged with something.\n"
else if(bleed_rate)
- var/bleed_message = !ismachineperson(src) ? "bleeding" : "leaking"
- msg += "[p_they(TRUE)] [p_are()] [bleed_message]!\n"
+ msg += "[p_they(TRUE)] [p_are()] bleeding!\n"
if(reagents.has_reagent("teslium"))
msg += "[p_they(TRUE)] [p_are()] emitting a gentle blue glow!\n"
diff --git a/code/modules/mob/living/carbon/human/species/machine.dm b/code/modules/mob/living/carbon/human/species/machine.dm
index ec37d3c6c9f..a1cab2ea466 100644
--- a/code/modules/mob/living/carbon/human/species/machine.dm
+++ b/code/modules/mob/living/carbon/human/species/machine.dm
@@ -22,7 +22,7 @@
death_message = "gives a short series of shrill beeps, their chassis shuddering before falling limp, nonfunctional."
death_sounds = list('sound/voice/borg_deathsound.ogg') //I've made this a list in the event we add more sounds for dead robots.
- species_traits = list(IS_WHITELISTED, NO_BREATHE, NO_SCAN, NO_INTORGANS, NO_PAIN, NO_DNA, RADIMMUNE, VIRUSIMMUNE, NO_GERMS, NO_DECAY, NOTRANSSTING) //Computers that don't decay? What a lie!
+ species_traits = list(IS_WHITELISTED, NO_BREATHE, NO_BLOOD, NO_SCAN, NO_INTORGANS, NO_PAIN, NO_DNA, RADIMMUNE, VIRUSIMMUNE, NO_GERMS, NO_DECAY, NOTRANSSTING) //Computers that don't decay? What a lie!
clothing_flags = HAS_UNDERWEAR | HAS_UNDERSHIRT | HAS_SOCKS
bodyflags = HAS_SKIN_COLOR | HAS_HEAD_MARKINGS | HAS_HEAD_ACCESSORY | ALL_RPARTS
dietflags = 0 //IPCs can't eat, so no diet
@@ -30,10 +30,6 @@
blood_color = "#1F181F"
flesh_color = "#AAAAAA"
- blood_color = "#3C3C3C"
- exotic_blood = "oil"
- blood_damage_type = STAMINA
-
//Default styles for created mobs.
default_hair = "Blue IPC Screen"
dies_at_threshold = TRUE
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 670088fd0bc..a5a9269d63b 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -50,7 +50,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
var/list/connected_robots = list()
var/aiRestorePowerRoutine = 0
//var/list/laws = list()
- var/alarms = list("Motion" = list(), "Fire" = list(), "Atmosphere" = list(), "Power" = list(), "Camera" = list())
+ alarms_listend_for = list("Motion", "Fire", "Atmosphere", "Power", "Camera", "Burglar")
var/viewalerts = 0
var/icon/holo_icon//Default is assigned when AI is created.
var/obj/mecha/controlled_mech //For controlled_mech a mech, to determine whether to relaymove or use the AI eye.
@@ -242,6 +242,46 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
return
show_borg_info()
+/mob/living/silicon/ai/proc/ai_alerts()
+ var/list/dat = list("Current Station Alerts\n")
+ dat += "Close
"
+ var/list/list/temp_alarm_list = SSalarm.alarms.Copy()
+ for(var/cat in temp_alarm_list)
+ if(!(cat in alarms_listend_for))
+ continue
+ dat += text("[]
\n", cat)
+ var/list/list/L = temp_alarm_list[cat].Copy()
+ for(var/alarm in L)
+ var/list/list/alm = L[alarm].Copy()
+ var/area_name = alm[1]
+ var/C = alm[2]
+ var/list/list/sources = alm[3].Copy()
+ for(var/thing in sources)
+ var/atom/A = locateUID(thing)
+ if(A && A.z != z)
+ L -= alarm
+ continue
+ dat += ""
+ if(C && islist(C))
+ var/dat2 = ""
+ for(var/cam in C)
+ var/obj/machinery/camera/I = locateUID(cam)
+ if(!QDELETED(I))
+ dat2 += text("[][]", (dat2 == "") ? "" : " | ", I.c_tag)
+ dat += text("-- [] ([])", area_name, (dat2 != "") ? dat2 : "No Camera")
+ else
+ dat += text("-- [] (No Camera)", area_name)
+ if(sources.len > 1)
+ dat += text("- [] sources", sources.len)
+ dat += "
\n"
+ if(!L.len)
+ dat += "-- All Systems Nominal
\n"
+ dat += "
\n"
+
+ viewalerts = TRUE
+ var/dat_text = dat.Join("")
+ src << browse(dat_text, "window=aialerts&can_close=0")
+
/mob/living/silicon/ai/proc/show_borg_info()
stat(null, text("Connected cyborgs: [connected_robots.len]"))
for(var/thing in connected_robots)
@@ -612,7 +652,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
if(href_list["switchcamera"])
switchCamera(locate(href_list["switchcamera"])) in GLOB.cameranet.cameras
if(href_list["showalerts"])
- subsystem_alarm_monitor()
+ ai_alerts()
if(href_list["show_paper"])
if(last_paper_seen)
src << browse(last_paper_seen, "window=show_paper")
@@ -787,12 +827,49 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
Bot.call_bot(src, waypoint)
+/mob/living/silicon/ai/alarm_triggered(src, class, area/A, list/O, obj/alarmsource)
+ if(!(class in alarms_listend_for))
+ return
+ if(alarmsource.z != z)
+ return
+ if(stat == DEAD)
+ return TRUE
+ if(O)
+ var/obj/machinery/camera/C = locateUID(O[1])
+ if(O.len == 1 && !QDELETED(C) && C.can_use())
+ queueAlarm("--- [class] alarm detected in [A.name]! ([C.c_tag])", class)
+ else if(O && O.len)
+ var/foo = 0
+ var/dat2 = ""
+ for(var/thing in O)
+ var/obj/machinery/camera/I = locateUID(thing)
+ if(!QDELETED(I))
+ dat2 += text("[][]", (!foo) ? "" : " | ", I.c_tag) //I'm not fixing this shit...
+ foo = 1
+ queueAlarm(text ("--- [] alarm detected in []! ([])", class, A.name, dat2), class)
+ else
+ queueAlarm(text("--- [] alarm detected in []! (No Camera)", class, A.name), class)
+ else
+ queueAlarm(text("--- [] alarm detected in []! (No Camera)", class, A.name), class)
+ if(viewalerts)
+ ai_alerts()
+
+/mob/living/silicon/ai/alarm_cancelled(src, class, area/A, obj/origin, cleared)
+ if(cleared)
+ if(!(class in alarms_listend_for))
+ return
+ if(origin.z != z)
+ return
+ queueAlarm("--- [class] alarm in [A.name] has been cleared.", class, 0)
+ if(viewalerts)
+ ai_alerts()
+
/mob/living/silicon/ai/proc/switchCamera(obj/machinery/camera/C)
if(!tracking)
cameraFollow = null
- if(!C || stat == DEAD) //C.can_use())
+ if(QDELETED(C) || stat == DEAD) //C.can_use())
return FALSE
if(!eyeobj)
diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm
index 61151e35c92..106eaf86d37 100644
--- a/code/modules/mob/living/silicon/ai/life.dm
+++ b/code/modules/mob/living/silicon/ai/life.dm
@@ -132,8 +132,6 @@
sleep(50)
theAPC = null
- process_queued_alarms()
-
/mob/living/silicon/ai/updatehealth(reason = "none given")
if(status_flags & GODMODE)
health = 100
diff --git a/code/modules/mob/living/silicon/robot/component.dm b/code/modules/mob/living/silicon/robot/component.dm
index 2a1662b064d..52d58ad659d 100644
--- a/code/modules/mob/living/silicon/robot/component.dm
+++ b/code/modules/mob/living/silicon/robot/component.dm
@@ -312,8 +312,3 @@ proc/robot_healthscan(mob/user, mob/living/M)
to_chat(user, "[capitalize(O.name)]: [O.damage]")
if(!organ_found)
to_chat(user, "No prosthetics located.")
-
- if(ismachineperson(H))
- to_chat(user, "Internal Fluid Level:[H.blood_volume]/[H.max_blood]")
- if(H.bleed_rate)
- to_chat(user, "Warning:External component leak detected!")
diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm
index 5cc6e50fd06..270606361cb 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone.dm
@@ -59,7 +59,7 @@
// Disable the microphone wire on Drones
if(radio)
- radio.wires.CutWireIndex(RADIO_WIRE_TRANSMIT)
+ radio.wires.cut(WIRE_RADIO_TRANSMIT)
if(camera && ("Robots" in camera.network))
camera.network.Add("Engineering")
diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm
index 07080e694bf..a183a8fc455 100644
--- a/code/modules/mob/living/silicon/robot/life.dm
+++ b/code/modules/mob/living/silicon/robot/life.dm
@@ -13,7 +13,6 @@
handle_robot_cell()
process_locks()
update_items()
- process_queued_alarms()
/mob/living/silicon/robot/proc/handle_robot_cell()
@@ -46,7 +45,7 @@
/mob/living/silicon/robot/proc/handle_equipment()
if(camera && !scrambledcodes)
- if(stat == DEAD || wires.IsCameraCut())
+ if(stat == DEAD || wires.is_cut(WIRE_BORG_CAMERA))
camera.status = 0
else
camera.status = 1
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 37fc2d0ad6f..b1b520b55ff 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -71,7 +71,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
var/list/req_access
var/ident = 0
//var/list/laws = list()
- var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list())
var/viewalerts = 0
var/modtype = "Default"
var/lower_mod = 0
@@ -112,7 +111,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
/mob/living/silicon/robot/get_cell()
return cell
-/mob/living/silicon/robot/New(loc, syndie = FALSE, unfinished = FALSE, alien = FALSE, mob/living/silicon/ai/ai_to_sync_to = null)
+/mob/living/silicon/robot/New(loc, syndie = FALSE, unfinished = FALSE, alien = FALSE, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null)
spark_system = new /datum/effect_system/spark_spread()
spark_system.set_up(5, 0, src)
spark_system.attach(src)
@@ -134,13 +133,13 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
radio = new /obj/item/radio/borg(src)
common_radio = radio
- init(ai_to_sync_to = ai_to_sync_to)
+ init(alien, connect_to_AI, ai_to_sync_to)
if(has_camera && !camera)
camera = new /obj/machinery/camera(src)
camera.c_tag = real_name
camera.network = list("SS13","Robots")
- if(wires.IsCameraCut()) // 5 = BORG CAMERA
+ if(wires.is_cut(WIRE_BORG_CAMERA)) // 5 = BORG CAMERA
camera.status = 0
if(mmi == null)
@@ -172,18 +171,20 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
scanner = new(src)
scanner.Grant(src)
-/mob/living/silicon/robot/proc/init(alien = FALSE, mob/living/silicon/ai/ai_to_sync_to = null)
+/mob/living/silicon/robot/proc/init(alien, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null)
aiCamera = new/obj/item/camera/siliconcam/robot_camera(src)
make_laws()
additional_law_channels["Binary"] = ":b "
+ if(!connect_to_AI)
+ return
var/found_ai = ai_to_sync_to
if(!found_ai)
found_ai = select_active_ai_with_fewest_borgs()
if(found_ai)
- lawupdate = 1
+ lawupdate = TRUE
connect_to_ai(found_ai)
else
- lawupdate = 0
+ lawupdate = FALSE
playsound(loc, 'sound/voice/liveagain.ogg', 75, 1)
@@ -270,6 +271,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
//If there's an MMI in the robot, have it ejected when the mob goes away. --NEO
//Improved /N
/mob/living/silicon/robot/Destroy()
+ SStgui.close_uis(wires)
if(mmi && mind)//Safety for when a cyborg gets dust()ed. Or there is no MMI inside.
var/turf/T = get_turf(loc)//To hopefully prevent run time errors.
if(T) mmi.loc = T
@@ -543,6 +545,43 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
src.verbs -= GLOB.robot_verbs_default
src.verbs -= silicon_subsystems
+/mob/living/silicon/robot/verb/cmd_robot_alerts()
+ set category = "Robot Commands"
+ set name = "Show Alerts"
+ if(usr.stat == DEAD)
+ to_chat(src, "Alert: You are dead.")
+ return //won't work if dead
+ robot_alerts()
+
+/mob/living/silicon/robot/proc/robot_alerts()
+ var/list/dat = list()
+ var/list/list/temp_alarm_list = SSalarm.alarms.Copy()
+ for(var/cat in temp_alarm_list)
+ if(!(cat in alarms_listend_for))
+ continue
+ dat += text("[cat]
\n")
+ var/list/list/L = temp_alarm_list[cat].Copy()
+ for(var/alarm in L)
+ var/list/list/alm = L[alarm].Copy()
+ var/list/list/sources = alm[3].Copy()
+ var/area_name = alm[1]
+ for(var/thing in sources)
+ var/atom/A = locateUID(thing)
+ if(A && A.z != z)
+ L -= alarm
+ continue
+ dat += ""
+ dat += text("-- [area_name]")
+ dat += "
\n"
+ if(!L.len)
+ dat += "-- All Systems Nominal
\n"
+ dat += "
\n"
+
+ var/datum/browser/alerts = new(usr, "robotalerts", "Current Station Alerts", 400, 410)
+ var/dat_text = dat.Join("")
+ alerts.set_content(dat_text)
+ alerts.open()
+
/mob/living/silicon/robot/proc/ionpulse()
if(!ionpulse_on)
return
@@ -604,6 +643,23 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
/mob/living/silicon/robot/InCritical()
return low_power_mode
+/mob/living/silicon/robot/alarm_triggered(src, class, area/A, list/O, obj/alarmsource)
+ if(!(class in alarms_listend_for))
+ return
+ if(alarmsource.z != z)
+ return
+ if(stat == DEAD)
+ return
+ queueAlarm(text("--- [class] alarm detected in [A.name]!"), class)
+
+/mob/living/silicon/robot/alarm_cancelled(src, class, area/A, obj/origin, cleared)
+ if(cleared)
+ if(!(class in alarms_listend_for))
+ return
+ if(origin.z != z)
+ return
+ queueAlarm("--- [class] alarm in [A.name] has been cleared.", class, 0)
+
/mob/living/silicon/robot/ex_act(severity)
switch(severity)
if(1.0)
@@ -796,7 +852,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
opened = FALSE
update_icons()
return
- else if(wiresexposed && wires.IsAllCut())
+ else if(wiresexposed && wires.is_all_cut())
//Cell is out, wires are exposed, remove MMI, produce damaged chassis, baleet original mob.
if(!mmi)
to_chat(user, "[src] has no brain to remove.")
@@ -1032,10 +1088,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
src << browse(null, t1)
return 1
- if(href_list["showalerts"])
- subsystem_alarm_monitor()
- return 1
-
if(href_list["mod"])
var/obj/item/O = locate(href_list["mod"])
if(istype(O) && (O.loc == src))
@@ -1050,6 +1102,11 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
activate_module(O)
installed_modules()
+ //Show alerts window if user clicked on "Show alerts" in chat
+ if(href_list["showalerts"])
+ robot_alerts()
+ return TRUE
+
if(href_list["deact"])
var/obj/item/O = locate(href_list["deact"])
if(activated(O))
@@ -1242,7 +1299,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
/mob/living/silicon/robot/proc/SetLockdown(var/state = 1)
// They stay locked down if their wire is cut.
- if(wires.LockedCut())
+ if(wires.is_cut(WIRE_BORG_LOCKED))
state = 1
if(state)
throw_alert("locked", /obj/screen/alert/locked)
@@ -1359,7 +1416,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
can_lock_cover = TRUE
default_cell_type = /obj/item/stock_parts/cell/bluespace
-/mob/living/silicon/robot/deathsquad/init(alien = FALSE, mob/living/silicon/ai/ai_to_sync_to = null)
+/mob/living/silicon/robot/deathsquad/init(alien = FALSE, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null)
laws = new /datum/ai_laws/deathsquad
module = new /obj/item/robot_module/deathsquad(src)
aiCamera = new/obj/item/camera/siliconcam/robot_camera(src)
@@ -1390,7 +1447,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
var/eprefix = "Amber"
-/mob/living/silicon/robot/ert/init(alien = FALSE, mob/living/silicon/ai/ai_to_sync_to = null)
+/mob/living/silicon/robot/ert/init(alien = FALSE, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null)
laws = new /datum/ai_laws/ert_override
radio = new /obj/item/radio/borg/ert(src)
radio.recalculateChannels()
@@ -1445,7 +1502,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
can_lock_cover = TRUE
default_cell_type = /obj/item/stock_parts/cell/bluespace
-/mob/living/silicon/robot/destroyer/init(alien = FALSE, mob/living/silicon/ai/ai_to_sync_to = null)
+/mob/living/silicon/robot/destroyer/init(alien = FALSE, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null)
aiCamera = new/obj/item/camera/siliconcam/robot_camera(src)
additional_law_channels["Binary"] = ":b "
laws = new /datum/ai_laws/deathsquad
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index c923e0912b7..7f9c0849d9c 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -11,9 +11,11 @@
var/list/stating_laws = list()// Channels laws are currently being stated on
var/list/alarms_to_show = list()
var/list/alarms_to_clear = list()
+ var/list/alarm_types_show = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0)
+ var/list/alarm_types_clear = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0)
+ var/list/alarms_listend_for = list("Motion", "Fire", "Atmosphere", "Power", "Camera")
//var/list/hud_list[10]
var/list/speech_synthesizer_langs = list() //which languages can be vocalized by the speech synthesizer
- var/list/alarm_handlers = list() // List of alarm handlers this silicon is registered to
var/designation = ""
var/obj/item/camera/siliconcam/aiCamera = null //photography
//Used in say.dm, allows for pAIs to have different say flavor text, as well as silicons, although the latter is not implemented.
@@ -25,9 +27,6 @@
//var/sensor_mode = 0 //Determines the current HUD.
- var/next_alarm_notice
- var/list/datum/alarm/queued_alarms = new()
-
hud_possible = list(SPECIALROLE_HUD, DIAG_STAT_HUD, DIAG_HUD)
@@ -46,6 +45,8 @@
diag_hud_set_health()
add_language("Galactic Common")
init_subsystems()
+ RegisterSignal(SSalarm, COMSIG_TRIGGERED_ALARM, .proc/alarm_triggered)
+ RegisterSignal(SSalarm, COMSIG_CANCELLED_ALARM, .proc/alarm_cancelled)
/mob/living/silicon/med_hud_set_health()
return //we use a different hud
@@ -55,10 +56,93 @@
/mob/living/silicon/Destroy()
GLOB.silicon_mob_list -= src
- for(var/datum/alarm_handler/AH in alarm_handlers)
- AH.unregister(src)
return ..()
+/mob/living/silicon/proc/alarm_triggered(src, class, area/A, list/O, obj/alarmsource)
+ return
+
+/mob/living/silicon/proc/alarm_cancelled(src, class, area/A, obj/origin, cleared)
+ return
+
+/mob/living/silicon/proc/queueAlarm(message, type, incoming = TRUE)
+ var/in_cooldown = (alarms_to_show.len > 0 || alarms_to_clear.len > 0)
+ if(incoming)
+ alarms_to_show += message
+ alarm_types_show[type] += 1
+ else
+ alarms_to_clear += message
+ alarm_types_clear[type] += 1
+
+ if(in_cooldown)
+ return
+
+ addtimer(CALLBACK(src, .proc/show_alarms), 3 SECONDS)
+
+/mob/living/silicon/proc/show_alarms()
+ if(alarms_to_show.len < 5)
+ for(var/msg in alarms_to_show)
+ to_chat(src, msg)
+ else if(length(alarms_to_show))
+
+ var/list/msg = list("--- ")
+
+ if(alarm_types_show["Burglar"])
+ msg += "BURGLAR: [alarm_types_show["Burglar"]] alarms detected. - "
+
+ if(alarm_types_show["Motion"])
+ msg += "MOTION: [alarm_types_show["Motion"]] alarms detected. - "
+
+ if(alarm_types_show["Fire"])
+ msg += "FIRE: [alarm_types_show["Fire"]] alarms detected. - "
+
+ if(alarm_types_show["Atmosphere"])
+ msg += "ATMOSPHERE: [alarm_types_show["Atmosphere"]] alarms detected. - "
+
+ if(alarm_types_show["Power"])
+ msg += "POWER: [alarm_types_show["Power"]] alarms detected. - "
+
+ if(alarm_types_show["Camera"])
+ msg += "CAMERA: [alarm_types_show["Camera"]] alarms detected. - "
+
+ msg += "\[Show Alerts\]"
+ var/msg_text = msg.Join("")
+ to_chat(src, msg_text)
+
+ if(alarms_to_clear.len < 3)
+ for(var/msg in alarms_to_clear)
+ to_chat(src, msg)
+
+ else if(alarms_to_clear.len)
+ var/list/msg = list("--- ")
+
+ if(alarm_types_clear["Motion"])
+ msg += "MOTION: [alarm_types_clear["Motion"]] alarms cleared. - "
+
+ if(alarm_types_clear["Fire"])
+ msg += "FIRE: [alarm_types_clear["Fire"]] alarms cleared. - "
+
+ if(alarm_types_clear["Atmosphere"])
+ msg += "ATMOSPHERE: [alarm_types_clear["Atmosphere"]] alarms cleared. - "
+
+ if(alarm_types_clear["Power"])
+ msg += "POWER: [alarm_types_clear["Power"]] alarms cleared. - "
+
+ if(alarm_types_show["Camera"])
+ msg += "CAMERA: [alarm_types_clear["Camera"]] alarms cleared. - "
+
+ msg += "\[Show Alerts\]"
+
+ var/msg_text = msg.Join("")
+ to_chat(src, msg_text)
+
+
+ alarms_to_show.Cut()
+ alarms_to_clear.Cut()
+ for(var/key in alarm_types_show)
+ alarm_types_show[key] = 0
+ for(var/key in alarm_types_clear)
+ alarm_types_clear[key] = 0
+
/mob/living/silicon/rename_character(oldname, newname)
// we actually don't want it changing minds and stuff
if(!newname)
@@ -283,63 +367,6 @@
if("Disable")
to_chat(src, "Sensor augmentations disabled.")
-/mob/living/silicon/proc/receive_alarm(var/datum/alarm_handler/alarm_handler, var/datum/alarm/alarm, was_raised)
- if(!next_alarm_notice)
- next_alarm_notice = world.time + 10 SECONDS
-
- var/list/alarms = queued_alarms[alarm_handler]
- if(was_raised)
- // Raised alarms are always set
- alarms[alarm] = 1
- else
- // Alarms that were raised but then cleared before the next notice are instead removed
- if(alarm in alarms)
- alarms -= alarm
- // And alarms that have only been cleared thus far are set as such
- else
- alarms[alarm] = -1
-
-/mob/living/silicon/proc/process_queued_alarms()
- if(next_alarm_notice && (world.time > next_alarm_notice))
- next_alarm_notice = 0
-
- var/alarm_raised = 0
- for(var/datum/alarm_handler/AH in queued_alarms)
- var/list/alarms = queued_alarms[AH]
- var/reported = 0
- for(var/datum/alarm/A in alarms)
- if(alarms[A] == 1)
- if(!reported)
- reported = 1
- to_chat(src, "--- [AH.category] Detected ---")
- raised_alarm(A)
-
- for(var/datum/alarm_handler/AH in queued_alarms)
- var/list/alarms = queued_alarms[AH]
- var/reported = 0
- for(var/datum/alarm/A in alarms)
- if(alarms[A] == -1)
- if(!reported)
- reported = 1
- to_chat(src, "--- [AH.category] Cleared ---")
- to_chat(src, "\The [A.alarm_name()].")
-
- if(alarm_raised)
- to_chat(src, "\[Show Alerts\]")
-
- for(var/datum/alarm_handler/AH in queued_alarms)
- var/list/alarms = queued_alarms[AH]
- alarms.Cut()
-
-/mob/living/silicon/proc/raised_alarm(var/datum/alarm/A)
- to_chat(src, "[A.alarm_name()]!")
-
-/mob/living/silicon/ai/raised_alarm(var/datum/alarm/A)
- var/cameratext = ""
- for(var/obj/machinery/camera/C in A.cameras())
- cameratext += "[(cameratext == "")? "" : "|"][C.c_tag]"
- to_chat(src, "[A.alarm_name()]! ([(cameratext)? cameratext : "No Camera"])")
-
/mob/living/silicon/adjustToxLoss(var/amount)
return STATUS_UPDATE_NONE
diff --git a/code/modules/mob/living/silicon/subsystems.dm b/code/modules/mob/living/silicon/subsystems.dm
index d18d41a40cf..65a92d07008 100644
--- a/code/modules/mob/living/silicon/subsystems.dm
+++ b/code/modules/mob/living/silicon/subsystems.dm
@@ -8,13 +8,11 @@
/mob/living/silicon
var/list/silicon_subsystems = list(
- /mob/living/silicon/proc/subsystem_alarm_monitor,
/mob/living/silicon/proc/subsystem_law_manager
)
/mob/living/silicon/ai
silicon_subsystems = list(
- /mob/living/silicon/proc/subsystem_alarm_monitor,
/mob/living/silicon/proc/subsystem_atmos_control,
/mob/living/silicon/proc/subsystem_crew_monitor,
/mob/living/silicon/proc/subsystem_law_manager,
@@ -23,7 +21,6 @@
/mob/living/silicon/robot/drone
silicon_subsystems = list(
- /mob/living/silicon/proc/subsystem_alarm_monitor,
/mob/living/silicon/proc/subsystem_law_manager,
/mob/living/silicon/proc/subsystem_power_monitor
)
@@ -32,30 +29,11 @@
register_alarms = 0
/mob/living/silicon/proc/init_subsystems()
- alarm_monitor = new(src)
atmos_control = new(src)
crew_monitor = new(src)
law_manager = new(src)
power_monitor = new(src)
- if(!register_alarms)
- return
-
- var/list/register_to = list(SSalarms.atmosphere_alarm, SSalarms.burglar_alarm, SSalarms.camera_alarm, SSalarms.fire_alarm, SSalarms.motion_alarm, SSalarms.power_alarm)
- for(var/datum/alarm_handler/AH in register_to)
- AH.register(src, /mob/living/silicon/proc/receive_alarm)
- queued_alarms[AH] = list() // Makes sure alarms remain listed in consistent order
- alarm_handlers |= AH
-
-/********************
-* Alarm Monitor *
-********************/
-/mob/living/silicon/proc/subsystem_alarm_monitor()
- set name = "Alarm Monitor"
- set category = "Subsystems"
-
- alarm_monitor.ui_interact(usr, state = GLOB.self_state)
-
/********************
* Atmos Control *
********************/
diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm
index f1278918898..dbd8ae6033a 100644
--- a/code/modules/mob/living/simple_animal/bot/mulebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm
@@ -66,6 +66,7 @@
RegisterSignal(src, COMSIG_CROSSED_MOVABLE, .proc/human_squish_check)
/mob/living/simple_animal/bot/mulebot/Destroy()
+ SStgui.close_uis(wires)
unload(0)
QDEL_NULL(wires)
QDEL_NULL(cell)
@@ -142,7 +143,7 @@
if(open)
icon_state="mulebot-hatch"
else
- icon_state = "mulebot[!wires.MobAvoid()]"
+ icon_state = "mulebot[wires.is_cut(WIRE_MOB_AVOIDANCE)]"
overlays.Cut()
if(load && !ismob(load))//buckling handles the mob offsets
load.pixel_y = initial(load.pixel_y) + 9
@@ -158,9 +159,9 @@
qdel(src)
if(2)
for(var/i = 1; i < 3; i++)
- wires.RandomCut()
+ wires.cut_random()
if(3)
- wires.RandomCut()
+ wires.cut_random()
return
/mob/living/simple_animal/bot/mulebot/bullet_act(obj/item/projectile/Proj)
@@ -169,7 +170,7 @@
unload(0)
if(prob(25))
visible_message("Something shorts out inside [src]!")
- wires.RandomCut()
+ wires.cut_random()
/mob/living/simple_animal/bot/mulebot/Topic(href, list/href_list)
if(..())
@@ -318,7 +319,7 @@
// returns true if the bot has power
/mob/living/simple_animal/bot/mulebot/proc/has_power()
- return !open && cell && cell.charge > 0 && wires.HasPower()
+ return !open && cell && cell.charge > 0 && !wires.is_cut(WIRE_MAIN_POWER1) && !wires.is_cut(WIRE_MAIN_POWER2)
/mob/living/simple_animal/bot/mulebot/proc/buzz(type)
switch(type)
@@ -362,7 +363,7 @@
if(istype(AM,/obj/structure/closet/crate))
CRATE = AM
else
- if(wires.LoadCheck())
+ if(!wires.is_cut(WIRE_LOADCHECK))
buzz(SIGH)
return // if not hacked, only allow crates to be loaded
@@ -459,8 +460,7 @@
on = 0
return
if(on)
- var/speed = (wires.Motor1() ? 1 : 0) + (wires.Motor2() ? 2 : 0)
-// to_chat(world, "speed: [speed]")
+ var/speed = (wires.is_cut(WIRE_MOTOR1) ? 1 : 0) + (wires.is_cut(WIRE_MOTOR2) ? 2 : 0)
var/num_steps = 0
switch(speed)
if(0)
@@ -624,7 +624,7 @@
// not loaded
if(auto_pickup) // find a crate
var/atom/movable/AM
- if(wires.LoadCheck()) // if hacked, load first unanchored thing we find
+ if(wires.is_cut(WIRE_LOADCHECK)) // if hacked, load first unanchored thing we find
for(var/atom/movable/A in get_step(loc, loaddir))
if(!A.anchored)
AM = A
@@ -672,7 +672,7 @@
// called when bot bumps into anything
/mob/living/simple_animal/bot/mulebot/Bump(atom/obs)
- if(!wires.MobAvoid()) // usually just bumps, but if avoidance disabled knock over mobs
+ if(wires.is_cut(WIRE_MOB_AVOIDANCE)) // usually just bumps, but if avoidance disabled knock over mobs
var/mob/M = obs
if(ismob(M))
if(istype(M,/mob/living/silicon/robot))
@@ -736,8 +736,8 @@
..()
/mob/living/simple_animal/bot/mulebot/receive_signal(datum/signal/signal)
- if(!wires.RemoteRX() || ..())
- return 1
+ if(wires.is_cut(WIRE_REMOTE_RX) || ..())
+ return TRUE
var/recv = signal.data["command"]
@@ -772,7 +772,7 @@
// send a radio signal with multiple data key/values
/mob/living/simple_animal/bot/mulebot/post_signal_multiple(var/freq, var/list/keyval)
- if(!wires.RemoteTX())
+ if(wires.is_cut(WIRE_REMOTE_TX))
return
..()
@@ -803,7 +803,7 @@
//Update navigation data. Called when commanded to deliver, return home, or a route update is needed...
/mob/living/simple_animal/bot/mulebot/proc/get_nav()
- if(!on || !wires.BeaconRX())
+ if(!on || wires.is_cut(WIRE_BEACON_RX))
return
for(var/obj/machinery/navbeacon/NB in GLOB.deliverybeacons)
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index 8e7adea666b..d151a98309f 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -44,26 +44,37 @@
-//human -> robot
-/mob/living/carbon/human/proc/Robotize()
+/**
+ For transforming humans into robots (cyborgs).
+
+ Arguments:
+ * cell_type: A type path of the cell the new borg should receive.
+ * connect_to_default_AI: TRUE if you want /robot/New() to handle connecting the borg to the AI with the least borgs.
+ * AI: A reference to the AI we want to connect to.
+*/
+/mob/living/carbon/human/proc/Robotize(cell_type = null, connect_to_default_AI = TRUE, mob/living/silicon/ai/AI = null)
if(notransform)
return
for(var/obj/item/W in src)
unEquip(W)
- regenerate_icons()
+
notransform = 1
canmove = 0
icon = null
invisibility = 101
- for(var/t in bodyparts)
- qdel(t)
- for(var/i in internal_organs)
- qdel(i)
- var/mob/living/silicon/robot/O = new /mob/living/silicon/robot( loc )
+ // Creating a new borg here will connect them to a default AI and notify that AI, if `connect_to_default_AI` is TRUE.
+ var/mob/living/silicon/robot/O = new /mob/living/silicon/robot(loc, connect_to_AI = connect_to_default_AI)
- // cyborgs produced by Robotize get an automatic power cell
- O.cell = new /obj/item/stock_parts/cell/high(O)
+ // If `AI` is passed in, we want to connect to that AI specifically.
+ if(AI)
+ O.lawupdate = TRUE
+ O.connect_to_ai(AI)
+
+ if(!cell_type)
+ O.cell = new /obj/item/stock_parts/cell/high(O)
+ else
+ O.cell = new cell_type(O)
O.gender = gender
O.invisibility = 0
@@ -77,9 +88,8 @@
else
O.key = key
- O.loc = loc
+ O.forceMove(loc)
O.job = "Cyborg"
- O.notify_ai(1)
if(O.mind && O.mind.assigned_role == "Cyborg")
if(O.mind.role_alt_title == "Robot")
diff --git a/code/modules/modular_computers/computers/machinery/console_presets.dm b/code/modules/modular_computers/computers/machinery/console_presets.dm
index 4f1bd269337..a2357fd9ebe 100644
--- a/code/modules/modular_computers/computers/machinery/console_presets.dm
+++ b/code/modules/modular_computers/computers/machinery/console_presets.dm
@@ -35,7 +35,7 @@
/obj/machinery/modular_computer/console/preset/engineering/install_programs()
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
hard_drive.store_file(new/datum/computer_file/program/power_monitor())
- hard_drive.store_file(new/datum/computer_file/program/alarm_monitor())
+// hard_drive.store_file(new/datum/computer_file/program/alarm_monitor()) //TO-DO:TGUI--Uncomment Modular computers
hard_drive.store_file(new/datum/computer_file/program/supermatter_monitor())
// ===== RESEARCH CONSOLE =====
diff --git a/code/modules/modular_computers/file_system/programs/engineering/alarm.dm b/code/modules/modular_computers/file_system/programs/engineering/alarm.dm
index 8cb47337a6d..2f2f4a08232 100644
--- a/code/modules/modular_computers/file_system/programs/engineering/alarm.dm
+++ b/code/modules/modular_computers/file_system/programs/engineering/alarm.dm
@@ -7,65 +7,71 @@
requires_ntnet = 1
network_destination = "alarm monitoring network"
size = 5
- var/list/datum/alarm_handler/alarm_handlers
+ var/tgui_id = "NtosStationAlertConsole"
+ var/ui_x = 315
+ var/ui_y = 500
+ var/has_alert = 0
+ var/list/alarms_listend_for = list("Fire", "Atmosphere", "Power")
-/datum/computer_file/program/alarm_monitor/New()
+/datum/computer_file/program/alarm_monitor/process_tick()
..()
- alarm_handlers = list(SSalarms.atmosphere_alarm, SSalarms.fire_alarm, SSalarms.power_alarm)
- for(var/datum/alarm_handler/AH in alarm_handlers)
- AH.register(src, /datum/computer_file/program/alarm_monitor/proc/update_icon)
-/datum/computer_file/program/alarm_monitor/Destroy()
- for(var/datum/alarm_handler/AH in alarm_handlers)
- AH.unregister(src)
- QDEL_NULL(alarm_handlers)
- return ..()
+ if(has_alert)
+ program_icon_state = "alert-red"
+ ui_header = "alarm_red.gif"
+ update_computer_icon()
+ else
+ program_icon_state = "alert-green"
+ ui_header = "alarm_green.gif"
+ update_computer_icon()
+ return TRUE
-/datum/computer_file/program/alarm_monitor/proc/update_icon()
- for(var/datum/alarm_handler/AH in alarm_handlers)
- if(AH.has_major_alarms())
- program_icon_state = "alert-red"
- ui_header = "alarm_red.gif"
- update_computer_icon()
- return 1
- program_icon_state = "alert-green"
- ui_header = "alarm_green.gif"
- update_computer_icon()
- return 0
-
-/datum/computer_file/program/alarm_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
- assets.send(user)
- ui = new(user, src, ui_key, "alarm_monitor.tmpl", "Alarm Monitoring", 575, 700)
- ui.set_auto_update(1)
- ui.set_layout_key("program")
- ui.open()
-
-/datum/computer_file/program/alarm_monitor/ui_data(mob/user)
+/datum/computer_file/program/alarm_monitor/tgui_data(mob/user)
var/list/data = get_header_data()
- var/categories[0]
- for(var/datum/alarm_handler/AH in alarm_handlers)
- categories[++categories.len] = list("category" = AH.category, "alarms" = list())
- for(var/datum/alarm/A in AH.major_alarms())
- var/cameras[0]
- var/lost_sources[0]
-
- if(isAI(user))
- for(var/obj/machinery/camera/C in A.cameras())
- cameras[++cameras.len] = C.nano_structure()
- for(var/datum/alarm_source/AS in A.sources)
- if(!AS.source)
- lost_sources[++lost_sources.len] = AS.source_name
-
- categories[categories.len]["alarms"] += list(list(
- "name" = sanitize(A.alarm_name()),
- "origin_lost" = A.origin == null,
- "has_cameras" = cameras.len,
- "cameras" = cameras,
- "lost_sources" = lost_sources.len ? sanitize(english_list(lost_sources, nothing_text = "", and_text = ", ")) : ""))
- data["categories"] = categories
+ data["alarms"] = list()
+ for(var/class in SSalarm.alarms)
+ if(!(class in alarms_listend_for))
+ continue
+ data["alarms"][class] = list()
+ for(var/area in alarms[class])
+ data["alarms"][class] += area
return data
+
+/datum/computer_file/program/alarm_monitor/proc/alarm_triggered(src, class, area/A, list/O, obj/alarmsource)
+ if(is_station_level(alarmsource.z))
+ if(!(A.type in GLOB.the_station_areas))
+ return
+ else if(!is_mining_level(alarmsource.z) || istype(A, /area/ruin))
+ return
+ update_alarm_display()
+
+/datum/computer_file/program/alarm_monitor/proc/alarm_cancelled(src, class, area/A, obj/origin, cleared)
+ if(is_station_level(origin.z))
+ if(!(A.type in GLOB.the_station_areas))
+ return
+ else if(!is_mining_level(origin.z) || istype(A, /area/ruin))
+ return
+ update_alarm_display()
+
+/datum/computer_file/program/alarm_monitor/proc/update_alarm_display()
+ has_alert = FALSE
+ for(var/cat in alarms)
+ if(!(cat in alarms_listend_for))
+ continue
+ var/list/L = alarms[cat]
+ if(length(L))
+ has_alert = TRUE
+
+/datum/computer_file/program/alarm_monitor/run_program(mob/user)
+ . = ..(user)
+ GLOB.alarmdisplay += src
+ RegisterSignal(SSalarm, COMSIG_TRIGGERED_ALARM, .proc/alarm_triggered)
+ RegisterSignal(SSalarm, COMSIG_CANCELLED_ALARM, .proc/alarm_cancelled)
+
+/datum/computer_file/program/alarm_monitor/kill_program(forced = FALSE)
+ GLOB.alarmdisplay -= src
+ UnregisterSignal(SSalarm, COMSIG_TRIGGERED_ALARM)
+ UnregisterSignal(SSalarm, COMSIG_CANCELLED_ALARM)
+ ..()
diff --git a/code/modules/nano/modules/alarm_monitor.dm b/code/modules/nano/modules/alarm_monitor.dm
deleted file mode 100644
index cee3820b102..00000000000
--- a/code/modules/nano/modules/alarm_monitor.dm
+++ /dev/null
@@ -1,90 +0,0 @@
-/datum/nano_module/alarm_monitor
- name = "Alarm monitor"
- var/list_cameras = 0 // Whether or not to list camera references. A future goal would be to merge this with the enginering/security camera console. Currently really only for AI-use.
- var/list/datum/alarm_handler/alarm_handlers // The particular list of alarm handlers this alarm monitor should present to the user.
-
-/datum/nano_module/alarm_monitor/all/New()
- ..()
- alarm_handlers = list(SSalarms.atmosphere_alarm, SSalarms.burglar_alarm, SSalarms.camera_alarm, SSalarms.fire_alarm, SSalarms.motion_alarm, SSalarms.power_alarm)
-
-/datum/nano_module/alarm_monitor/engineering/New()
- ..()
- alarm_handlers = list(SSalarms.atmosphere_alarm, SSalarms.fire_alarm, SSalarms.power_alarm)
-
-/datum/nano_module/alarm_monitor/security/New()
- ..()
- alarm_handlers = list(SSalarms.burglar_alarm, SSalarms.camera_alarm, SSalarms.motion_alarm)
-
-/datum/nano_module/alarm_monitor/proc/register(var/object, var/procName)
- for(var/datum/alarm_handler/AH in alarm_handlers)
- AH.register(object, procName)
-
-/datum/nano_module/alarm_monitor/proc/unregister(var/object)
- for(var/datum/alarm_handler/AH in alarm_handlers)
- AH.unregister(object)
-
-/datum/nano_module/alarm_monitor/proc/all_alarms()
- var/list/all_alarms = new()
- for(var/datum/alarm_handler/AH in alarm_handlers)
- all_alarms += AH.alarms
-
- return all_alarms
-
-/datum/nano_module/alarm_monitor/proc/major_alarms()
- var/list/all_alarms = new()
- for(var/datum/alarm_handler/AH in alarm_handlers)
- all_alarms += AH.major_alarms()
-
- return all_alarms
-
-/datum/nano_module/alarm_monitor/proc/minor_alarms()
- var/list/all_alarms = new()
- for(var/datum/alarm_handler/AH in alarm_handlers)
- all_alarms += AH.minor_alarms()
-
- return all_alarms
-
-/datum/nano_module/alarm_monitor/Topic(ref, href_list)
- if(..())
- return 1
- if(href_list["switchTo"])
- var/obj/machinery/camera/C = locate(href_list["switchTo"]) in GLOB.cameranet.cameras
- if(!C || !isAI(usr))
- return
-
- usr.switch_to_camera(C)
- return 1
-
-/datum/nano_module/alarm_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state)
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "alarm_monitor.tmpl", "Alarm Monitoring Console", 800, 800, state = state)
- ui.open()
- ui.set_auto_update(1)
-
-/datum/nano_module/alarm_monitor/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
- var/data[0]
-
- var/categories[0]
- for(var/datum/alarm_handler/AH in alarm_handlers)
- categories[++categories.len] = list("category" = AH.category, "alarms" = list())
- for(var/datum/alarm/A in AH.major_alarms())
- var/cameras[0]
- var/lost_sources[0]
-
- if(isAI(user))
- for(var/obj/machinery/camera/C in A.cameras())
- cameras[++cameras.len] = C.nano_structure()
- for(var/datum/alarm_source/AS in A.sources)
- if(!AS.source)
- lost_sources[++lost_sources.len] = AS.source_name
-
- categories[categories.len]["alarms"] += list(list(
- "name" = sanitize(A.alarm_name()),
- "origin_lost" = A.origin == null,
- "has_cameras" = cameras.len,
- "cameras" = cameras,
- "lost_sources" = lost_sources.len ? sanitize(english_list(lost_sources, nothing_text = "", and_text = ", ")) : ""))
- data["categories"] = categories
-
- return data
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 409abe3d724..cc3fccb2a01 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -170,6 +170,7 @@
addtimer(CALLBACK(src, .proc/update), 5)
/obj/machinery/power/apc/Destroy()
+ SStgui.close_uis(wires)
GLOB.apcs -= src
if(malfai && operating)
malfai.malf_picker.processing_time = clamp(malfai.malf_picker.processing_time - 10,0,1000)
@@ -216,8 +217,7 @@
area = A
name = "\improper [area.name] APC"
else
- area = get_area_name(areastring)
- name = "\improper [area.name] APC"
+ name = "\improper [get_area_name(area, TRUE)] APC"
area.apc |= src
update_icon()
@@ -648,7 +648,7 @@
else if(stat & (BROKEN|MAINT))
to_chat(user, "Nothing happens!")
else
- if(allowed(usr) && !isWireCut(APC_WIRE_IDSCAN) && !malfhack)
+ if(allowed(usr) && !wires.is_cut(WIRE_IDSCAN) && !malfhack)
locked = !locked
to_chat(user, "You [ locked ? "lock" : "unlock"] the APC interface.")
update_icon()
@@ -853,10 +853,6 @@
// to_chat(world, "[area.power_equip]")
area.power_change()
-/obj/machinery/power/apc/proc/isWireCut(var/wireIndex)
- return wires.IsIndexCut(wireIndex)
-
-
/obj/machinery/power/apc/proc/can_use(var/mob/user, var/loud = 0) //used by attack_hand() and Topic()
if(user.can_admin_interact())
return 1
@@ -1192,31 +1188,31 @@
lighting = autoset(lighting, 1)
environ = autoset(environ, 1)
autoflag = 3
- if(report_power_alarm && is_station_contact(z))
- SSalarms.power_alarm.clearAlarm(loc, src)
+ if(report_power_alarm)
+ area.poweralert(TRUE, src)
else if(cell.charge < 1250 && cell.charge > 750 && longtermpower < 0) // <30%, turn off equipment
if(autoflag != 2)
equipment = autoset(equipment, 2)
lighting = autoset(lighting, 1)
environ = autoset(environ, 1)
- if(report_power_alarm && is_station_contact(z))
- SSalarms.power_alarm.triggerAlarm(loc, src)
+ if(report_power_alarm)
+ area.poweralert(FALSE, src)
autoflag = 2
else if(cell.charge < 750 && cell.charge > 10) // <15%, turn off lighting & equipment
if((autoflag > 1 && longtermpower < 0) || (autoflag > 1 && longtermpower >= 0))
equipment = autoset(equipment, 2)
lighting = autoset(lighting, 2)
environ = autoset(environ, 1)
- if(report_power_alarm && is_station_contact(z))
- SSalarms.power_alarm.triggerAlarm(loc, src)
+ if(report_power_alarm)
+ area.poweralert(FALSE, src)
autoflag = 1
else if(cell.charge <= 0) // zero charge, turn all off
if(autoflag != 0)
equipment = autoset(equipment, 0)
lighting = autoset(lighting, 0)
environ = autoset(environ, 0)
- if(report_power_alarm && is_station_contact(z))
- SSalarms.power_alarm.triggerAlarm(loc, src)
+ if(report_power_alarm)
+ area.poweralert(FALSE, src)
autoflag = 0
// now trickle-charge the cell
@@ -1271,8 +1267,8 @@
equipment = autoset(equipment, 0)
lighting = autoset(lighting, 0)
environ = autoset(environ, 0)
- if(report_power_alarm && is_station_contact(z))
- SSalarms.power_alarm.triggerAlarm(loc, src)
+ if(report_power_alarm)
+ area.poweralert(FALSE, src)
autoflag = 0
// update icon & area power if anything changed
@@ -1372,4 +1368,18 @@
L.update(FALSE)
CHECK_TICK
+/obj/machinery/power/apc/proc/relock_callback()
+ locked = TRUE
+ updateDialog()
+
+/obj/machinery/power/apc/proc/check_main_power_callback()
+ if(!wires.is_cut(WIRE_MAIN_POWER1) && !wires.is_cut(WIRE_MAIN_POWER2))
+ shorted = FALSE
+ updateDialog()
+
+/obj/machinery/power/apc/proc/check_ai_control_callback()
+ if(!wires.is_cut(WIRE_AI_CONTROL))
+ aidisabled = FALSE
+ updateDialog()
+
#undef APC_UPDATE_ICON_COOLDOWN
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index df457111704..9305faf6637 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -177,6 +177,8 @@
var/nightshift_light_power = 0.45
var/nightshift_light_color = "#FFDDCC"
+ var/bulb_emergency_colour = "#FF3232" // determines the colour of the light while it's in emergency mode
+
// the smaller bulb light fixture
/obj/machinery/light/small
@@ -238,7 +240,11 @@
switch(status) // set icon_states
if(LIGHT_OK)
- icon_state = "[base_state][on]"
+ var/area/A = get_area(src)
+ if(A && A.fire)
+ icon_state = "[base_state]_emergency"
+ else
+ icon_state = "[base_state][on]"
if(LIGHT_EMPTY)
icon_state = "[base_state]-empty"
on = FALSE
@@ -260,10 +266,20 @@
on = FALSE
update_icon()
if(on)
- var/BR = nightshift_enabled ? nightshift_light_range : brightness_range
- var/PO = nightshift_enabled ? nightshift_light_power : brightness_power
- var/CO = nightshift_enabled ? nightshift_light_color : brightness_color
- var/matching = light_range == BR && light_power == PO && light_color == CO
+ var/BR = brightness_range
+ var/PO = brightness_power
+ var/CO = brightness_color
+ if(color)
+ CO = color
+ var/area/A = get_area(src)
+ if(A && A.fire)
+ CO = bulb_emergency_colour
+ else if(nightshift_enabled)
+ BR = nightshift_light_range
+ PO = nightshift_light_power
+ if(!color)
+ CO = nightshift_light_color
+ var/matching = light && BR == light.light_range && PO == light.light_power && CO == light.light_color
if(!matching)
switchcount++
if(rigged)
diff --git a/code/modules/power/singularity/investigate.dm b/code/modules/power/singularity/investigate.dm
index 43e8c9f8a8b..4835e09411c 100644
--- a/code/modules/power/singularity/investigate.dm
+++ b/code/modules/power/singularity/investigate.dm
@@ -1,4 +1,4 @@
-/area/engine/engineering/power_alert(var/alarming)
- if(alarming)
- investigate_log("has a power alarm!","singulo")
+/area/engine/engineering/poweralert(state, source)
+ if(state != poweralm)
+ investigate_log("has a power alarm!", "singulo")
..()
diff --git a/code/modules/power/singularity/particle_accelerator/particle_control.dm b/code/modules/power/singularity/particle_accelerator/particle_control.dm
index b8ba53ae432..3ad96050123 100644
--- a/code/modules/power/singularity/particle_accelerator/particle_control.dm
+++ b/code/modules/power/singularity/particle_accelerator/particle_control.dm
@@ -27,6 +27,7 @@
use_log = list()
/obj/machinery/particle_accelerator/control_box/Destroy()
+ SStgui.close_uis(wires)
if(active)
toggle_power()
QDEL_NULL(wires)
@@ -41,6 +42,11 @@
else if(construction_state == 2) // Wires exposed
wires.Interact(user)
+/obj/machinery/particle_accelerator/control_box/multitool_act(mob/living/user, obj/item/I)
+ if(construction_state == 2) // Wires exposed
+ wires.Interact(user)
+ return TRUE
+
/obj/machinery/particle_accelerator/control_box/update_state()
if(construction_state < 3)
use_power = NO_POWER_USE
@@ -93,18 +99,18 @@
usr.unset_machine()
return
if(href_list["togglep"])
- if(!wires.IsIndexCut(PARTICLE_TOGGLE_WIRE))
+ if(!wires.is_cut(WIRE_PARTICLE_POWER))
toggle_power()
else if(href_list["scan"])
part_scan()
else if(href_list["strengthup"])
- if(!wires.IsIndexCut(PARTICLE_STRENGTH_WIRE))
+ if(!wires.is_cut(WIRE_PARTICLE_STRENGTH))
add_strength()
else if(href_list["strengthdown"])
- if(!wires.IsIndexCut(PARTICLE_STRENGTH_WIRE))
+ if(!wires.is_cut(WIRE_PARTICLE_STRENGTH))
remove_strength()
updateDialog()
diff --git a/code/modules/power/tesla/coil.dm b/code/modules/power/tesla/coil.dm
index 5f58bcb5dd4..5743bea8475 100644
--- a/code/modules/power/tesla/coil.dm
+++ b/code/modules/power/tesla/coil.dm
@@ -21,6 +21,7 @@
RefreshParts()
/obj/machinery/power/tesla_coil/Destroy()
+ SStgui.close_uis(wires)
QDEL_NULL(wires)
return ..()
diff --git a/code/modules/station_goals/bsa.dm b/code/modules/station_goals/bsa.dm
index 426af9a97ac..4e9b5e57630 100644
--- a/code/modules/station_goals/bsa.dm
+++ b/code/modules/station_goals/bsa.dm
@@ -91,7 +91,7 @@
/obj/machinery/bsa/middle/proc/check_completion()
if(!front || !back)
- return "No linked parts detected!"
+ return "No multitool-linked parts detected!"
if(!front.anchored || !back.anchored || !anchored)
return "Linked parts unwrenched!"
if(front.y != y || back.y != y || !(front.x > x && back.x < x || front.x < x && back.x > x) || front.z != z || back.z != z)
@@ -305,51 +305,45 @@
/obj/machinery/computer/bsa_control/attack_hand(mob/user)
if(..())
return 1
- ui_interact(user)
+ tgui_interact(user)
-/obj/machinery/computer/bsa_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/computer/bsa_control/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
- ui = new(user, src, ui_key, "bsa.tmpl", name, 400, 305)
+ ui = new(user, src, ui_key, "BlueSpaceArtilleryControl", name, 400, 155, master_ui, state)
ui.open()
- ui.set_auto_update(1)
-/obj/machinery/computer/bsa_control/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
+/obj/machinery/computer/bsa_control/tgui_data(mob/user)
var/list/data = list()
data["connected"] = cannon
data["notice"] = notice
if(target)
data["target"] = get_target_name()
-
if(cannon)
var/reload_cooldown = cannon.reload_cooldown
var/last_fire_time = cannon.last_fire_time
var/time_to_wait = max(0, round(reload_cooldown - ((world.time / 10) - last_fire_time)))
var/minutes = max(0, round(time_to_wait / 60))
var/seconds = max(0, time_to_wait - (60 * minutes))
-
- data["reloadtime_mins"] = minutes
- data["reloadtime_secs"] = (seconds < 10) ? "0[seconds]" : seconds
+ var/seconds2 = (seconds < 10) ? "0[seconds]" : seconds
+ data["reloadtime_text"] = "[minutes]:[seconds2]"
data["ready"] = minutes == 0 && seconds == 0
else
data["ready"] = FALSE
-
return data
-/obj/machinery/computer/bsa_control/Topic(href, href_list)
+/obj/machinery/computer/bsa_control/tgui_act(action, params)
if(..())
- return 1
-
- if(href_list["build"])
- cannon = deploy()
- . = TRUE
- else if(href_list["fire"])
- fire(usr)
- . = TRUE
- else if(href_list["recalibrate"])
- calibrate(usr)
- . = TRUE
+ return
+ switch(action)
+ if("build")
+ cannon = deploy()
+ if("fire")
+ fire(usr)
+ if("recalibrate")
+ calibrate(usr)
update_icon()
+ return TRUE
/obj/machinery/computer/bsa_control/proc/calibrate(mob/user)
var/list/gps_locators = list()
diff --git a/code/modules/surgery/organs/blood.dm b/code/modules/surgery/organs/blood.dm
index b0403d8ae49..837c6e0d056 100644
--- a/code/modules/surgery/organs/blood.dm
+++ b/code/modules/surgery/organs/blood.dm
@@ -54,7 +54,7 @@
var/obj/item/organ/external/BP = X
var/brutedamage = BP.brute_dam
- if(BP.is_robotic() && !ismachineperson(src))
+ if(BP.is_robotic())
continue
//We want an accurate reading of .len
diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm
index 1b205f957ce..59385ff85a3 100644
--- a/code/modules/surgery/organs/eyes.dm
+++ b/code/modules/surgery/organs/eyes.dm
@@ -8,7 +8,7 @@
var/eye_colour = "#000000" // Should never be null
var/list/colourmatrix = null
var/list/colourblind_matrix = MATRIX_GREYSCALE //Special colourblindness parameters. By default, it's black-and-white.
- var/list/replace_colours = LIST_GREYSCALE_REPLACE
+ var/list/replace_colours = GREYSCALE_COLOR_REPLACE
var/dependent_disabilities = list() //Gets set by eye-dependent disabilities such as colourblindness so the eyes can transfer the disability during transplantation.
var/weld_proof = null //If set, the eyes will not take damage during welding. eg. IPC optical sensors do not take damage when they weld things while all other eyes will.
diff --git a/code/modules/surgery/organs/organ.dm b/code/modules/surgery/organs/organ.dm
index 3dab4065f7d..5b9b5056604 100644
--- a/code/modules/surgery/organs/organ.dm
+++ b/code/modules/surgery/organs/organ.dm
@@ -236,35 +236,6 @@
status &= ~ORGAN_SPLINTED
status |= ORGAN_ROBOT
-/obj/item/organ/external/emp_act(severity)
- if(!is_robotic() || emp_proof)
- return
- if(tough)
- switch(severity)
- if(1)
- receive_damage(0, 5.5)
- if(owner)
- owner.Stun(10)
- if(2)
- receive_damage(0, 2.8)
- if(owner)
- owner.Stun(5)
- else
- switch(severity)
- if(1)
- receive_damage(0, 20)
- if(2)
- receive_damage(0, 7)
-
-/obj/item/organ/internal/emp_act(severity)
- if(!is_robotic() || emp_proof)
- return
- switch(severity)
- if(1)
- receive_damage(20, 1)
- if(2)
- receive_damage(7, 1)
-
/obj/item/organ/proc/shock_organ(intensity)
return
diff --git a/code/modules/surgery/organs/organ_external.dm b/code/modules/surgery/organs/organ_external.dm
index 143bf1d1ed6..5fdf95f09a9 100644
--- a/code/modules/surgery/organs/organ_external.dm
+++ b/code/modules/surgery/organs/organ_external.dm
@@ -41,6 +41,9 @@
var/list/obj/item/organ/external/children
var/list/convertable_children = list()
+ // Does the organ take reduce damage from EMPs? IPC limbs get this by default
+ var/emp_resistant = FALSE
+
// Internal organs of this body part
var/list/internal_organs = list()
@@ -256,6 +259,34 @@
return update_icon()
+/obj/item/organ/external/emp_act(severity)
+ if(!is_robotic() || emp_proof)
+ return
+ if(tough) // Augmented limbs
+ switch(severity)
+ if(1)
+ receive_damage(0, 5.5)
+ if(owner)
+ owner.Stun(10)
+ if(2)
+ receive_damage(0, 2.8)
+ if(owner)
+ owner.Stun(5)
+ else if(emp_resistant) // IPC limbs
+ switch(severity)
+ if(1)
+ // 5.28 (9 * 0.66 burn_mod) burn damage, 65.34 damage with 11 limbs.
+ receive_damage(0, 9)
+ if(2)
+ // 3.63 (5 * 0.66 burn_mod) burn damage, 39.93 damage with 11 limbs.
+ receive_damage(0, 5.5)
+ else // Basic prosthetic limbs
+ switch(severity)
+ if(1)
+ receive_damage(0, 20)
+ if(2)
+ receive_damage(0, 7)
+
/*
This function completely restores a damaged organ to perfect condition.
*/
diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm
index 53283ada95e..5151b347f4d 100644
--- a/code/modules/surgery/organs/organ_internal.dm
+++ b/code/modules/surgery/organs/organ_internal.dm
@@ -73,6 +73,15 @@
A.Remove(M)
return src
+/obj/item/organ/internal/emp_act(severity)
+ if(!is_robotic() || emp_proof)
+ return
+ switch(severity)
+ if(1)
+ receive_damage(20, 1)
+ if(2)
+ receive_damage(7, 1)
+
/obj/item/organ/internal/replaced(var/mob/living/carbon/human/target)
insert(target)
diff --git a/code/modules/surgery/organs/subtypes/machine.dm b/code/modules/surgery/organs/subtypes/machine.dm
index 52cad684e11..415cdb7875d 100644
--- a/code/modules/surgery/organs/subtypes/machine.dm
+++ b/code/modules/surgery/organs/subtypes/machine.dm
@@ -5,6 +5,7 @@
min_broken_damage = 30
encased = null
status = ORGAN_ROBOT
+ emp_resistant = TRUE
/obj/item/organ/external/head/ipc/New(mob/living/carbon/holder, datum/species/species_override = null)
..(holder, /datum/species/machine) // IPC heads need to be explicitly set to this since you can print them
@@ -13,6 +14,7 @@
/obj/item/organ/external/chest/ipc
encased = null
status = ORGAN_ROBOT
+ emp_resistant = TRUE
/obj/item/organ/external/chest/ipc/New()
..()
@@ -21,6 +23,7 @@
/obj/item/organ/external/groin/ipc
encased = null
status = ORGAN_ROBOT
+ emp_resistant = TRUE
/obj/item/organ/external/groin/ipc/New()
..()
@@ -29,6 +32,7 @@
/obj/item/organ/external/arm/ipc
encased = null
status = ORGAN_ROBOT
+ emp_resistant = TRUE
/obj/item/organ/external/arm/ipc/New()
..()
@@ -37,6 +41,7 @@
/obj/item/organ/external/arm/right/ipc
encased = null
status = ORGAN_ROBOT
+ emp_resistant = TRUE
/obj/item/organ/external/arm/right/ipc/New()
..()
@@ -45,6 +50,7 @@
/obj/item/organ/external/leg/ipc
encased = null
status = ORGAN_ROBOT
+ emp_resistant = TRUE
/obj/item/organ/external/leg/ipc/New()
..()
@@ -53,6 +59,7 @@
/obj/item/organ/external/leg/right/ipc
encased = null
status = ORGAN_ROBOT
+ emp_resistant = TRUE
/obj/item/organ/external/leg/right/ipc/New()
..()
@@ -61,6 +68,7 @@
/obj/item/organ/external/foot/ipc
encased = null
status = ORGAN_ROBOT
+ emp_resistant = TRUE
/obj/item/organ/external/foot/ipc/New()
..()
@@ -69,6 +77,7 @@
/obj/item/organ/external/foot/right/ipc
encased = null
status = ORGAN_ROBOT
+ emp_resistant = TRUE
/obj/item/organ/external/foot/right/ipc/New()
..()
@@ -77,6 +86,7 @@
/obj/item/organ/external/hand/ipc
encased = null
status = ORGAN_ROBOT
+ emp_resistant = TRUE
/obj/item/organ/external/hand/ipc/New()
..()
@@ -85,6 +95,7 @@
/obj/item/organ/external/hand/right/ipc
encased = null
status = ORGAN_ROBOT
+ emp_resistant = TRUE
/obj/item/organ/external/hand/right/ipc/New()
..()
diff --git a/code/modules/surgery/organs/subtypes/tajaran.dm b/code/modules/surgery/organs/subtypes/tajaran.dm
index e8d87b55b89..226bc82dd2d 100644
--- a/code/modules/surgery/organs/subtypes/tajaran.dm
+++ b/code/modules/surgery/organs/subtypes/tajaran.dm
@@ -7,14 +7,14 @@
icon = 'icons/obj/species_organs/tajaran.dmi'
name = "tajaran eyeballs"
colourblind_matrix = MATRIX_TAJ_CBLIND //The colour matrix and darksight parameters that the mob will recieve when they get the disability.
- replace_colours = LIST_TAJ_REPLACE
+ replace_colours = TRITANOPIA_COLOR_REPLACE
see_in_dark = 8
/obj/item/organ/internal/eyes/tajaran/farwa //Being the lesser form of Tajara, Farwas have an utterly incurable version of their colourblindness.
name = "farwa eyeballs"
colourmatrix = MATRIX_TAJ_CBLIND
see_in_dark = 8
- replace_colours = LIST_TAJ_REPLACE
+ replace_colours = TRITANOPIA_COLOR_REPLACE
/obj/item/organ/internal/heart/tajaran
name = "tajaran heart"
diff --git a/code/modules/surgery/organs/subtypes/vulpkanin.dm b/code/modules/surgery/organs/subtypes/vulpkanin.dm
index a2815d32dc6..bd56532ebd9 100644
--- a/code/modules/surgery/organs/subtypes/vulpkanin.dm
+++ b/code/modules/surgery/organs/subtypes/vulpkanin.dm
@@ -7,14 +7,14 @@
name = "vulpkanin eyeballs"
icon = 'icons/obj/species_organs/vulpkanin.dmi'
colourblind_matrix = MATRIX_VULP_CBLIND //The colour matrix and darksight parameters that the mob will recieve when they get the disability.
- replace_colours = LIST_VULP_REPLACE
+ replace_colours = PROTANOPIA_COLOR_REPLACE
see_in_dark = 8
/obj/item/organ/internal/eyes/vulpkanin/wolpin //Being the lesser form of Vulpkanin, Wolpins have an utterly incurable version of their colourblindness.
name = "wolpin eyeballs"
colourmatrix = MATRIX_VULP_CBLIND
see_in_dark = 8
- replace_colours = LIST_VULP_REPLACE
+ replace_colours = PROTANOPIA_COLOR_REPLACE
/obj/item/organ/internal/heart/vulpkanin
name = "vulpkanin heart"
diff --git a/icons/obj/lighting.dmi b/icons/obj/lighting.dmi
index f8943c2c39b..49b594c1656 100644
Binary files a/icons/obj/lighting.dmi and b/icons/obj/lighting.dmi differ
diff --git a/nano/templates/alarm_monitor.tmpl b/nano/templates/alarm_monitor.tmpl
deleted file mode 100644
index 5dae051a576..00000000000
--- a/nano/templates/alarm_monitor.tmpl
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-{{for data.categories}}
- {{:value.category}}
- {{for value.alarms :alarmValue:alarmIndex}}
- {{if alarmValue.origin_lost}}
- {{:alarmValue.name}} Alarm Origin Lost
- {{else}}
- {{:alarmValue.name}}
- {{/if}}
- {{if alarmValue.has_cameras || alarmValue.lost_sources != ""}}
-
- {{if alarmValue.has_cameras}}
-
- {{for alarmValue.cameras :cameraValue:cameraIndex}}
- {{if cameraValue.deact}}
- {{:helper.link(cameraValue.name + " (deactivated)", '', {}, 'inactive')}}
- {{else}}
- {{:helper.link(cameraValue.name, '', {'switchTo' : cameraValue.camera})}}
- {{/if}}
- {{/for}}
-
- {{else}}
- No cameras found.
- {{/if}}
- {{if alarmValue.lost_sources != ""}}
-
-
Lost Alarm Sources: {{:alarmValue.lost_sources}}
-
- {{/if}}
-
- {{/if}}
- {{empty}}
- --All Systems Nominal
- {{/for}}
-{{/for}}
\ No newline at end of file
diff --git a/nano/templates/atmos_alert.tmpl b/nano/templates/atmos_alert.tmpl
deleted file mode 100644
index bdb6c2c872b..00000000000
--- a/nano/templates/atmos_alert.tmpl
+++ /dev/null
@@ -1,18 +0,0 @@
-Priority Alerts
-{{for data.priority_alarms}}
-
- {{:value.name}} {{:helper.link('Reset', null, {'clear_alarm' : value.ref})}}
-
-{{empty}}
- No priority alerts detected.
-{{/for}}
-
-Minor Alerts
-{{for data.minor_alarms}}
-
- {{:value.name}} {{:helper.link('Reset', null, {'clear_alarm' : value.ref})}}
-
-{{empty}}
- No minor alerts detected.
-{{/for}}
-
diff --git a/nano/templates/bsa.tmpl b/nano/templates/bsa.tmpl
deleted file mode 100644
index a0e8a60deb5..00000000000
--- a/nano/templates/bsa.tmpl
+++ /dev/null
@@ -1,51 +0,0 @@
-
-{{if data.notice}}
- {{:data.notice}}
-{{/if}}
-Bluespace Artillery Control
-
-
- Target:
-
-
- {{:helper.link(data.target ? data.target : "None", 'crosshairs', {'recalibrate' : 1})}}
-
-
-
-
- Reload Cooldown:
-
-
- {{if data.ready}}
- Ready
- {{else data.reloadtime_mins || data.reloadtime_secs}}
- {{:data.reloadtime_mins}}:{{:data.reloadtime_secs}}
- {{else}}
- No cannon connected!
- {{/if}}
-
-
-
-
- Controls:
-
-
- {{:helper.link('FIRE!', 'warning', {'fire' : 1}, data.ready && data.target ? null : 'disabled')}}
-
-
-{{if !data.connected}}
-
-
- Maintenance:
-
-
- {{:helper.link('Complete Deployment', 'wrench', {'build' : 1})}}
-
-
-{{else}}
-
-Deployment of weapon authorized by Nanotrasen Naval Command. Remember, friendly fire is grounds for termination of your contract and life.
-{{/if}}
\ No newline at end of file
diff --git a/nano/templates/wires.tmpl b/nano/templates/wires.tmpl
deleted file mode 100644
index 2702d97d7dc..00000000000
--- a/nano/templates/wires.tmpl
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
- {{for data.wires}}
-
- | {{:value.colour_name}} {{if value.index}}({{:value.index}}){{/if}} |
-
- {{:helper.link(value.cut ? 'Mend' : 'Cut', null, {'action' : 'cut', 'wire' : value.colour})}}
- {{:helper.link('Pulse', null, {'action' : 'pulse', 'wire' : value.colour})}}
- {{:helper.link(value.attached ? 'Detach' : 'Attach', null, {'action' : 'attach', 'wire' : value.colour})}}
- |
-
- {{/for}}
-
-
-{{if data.status_len}}
-
-
-
- {{for data.status}}
-
{{:value}}
- {{/for}}
-
-
-{{/if}}
diff --git a/paradise.dme b/paradise.dme
index 0f53fc613ba..644b3583414 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -74,6 +74,7 @@
#include "code\__DEFINES\tools.dm"
#include "code\__DEFINES\typeids.dm"
#include "code\__DEFINES\vv.dm"
+#include "code\__DEFINES\wires.dm"
#include "code\__DEFINES\zlevel.dm"
#include "code\__DEFINES\dcs\flags.dm"
#include "code\__DEFINES\dcs\helpers.dm"
@@ -1242,14 +1243,6 @@
#include "code\modules\admin\verbs\SDQL2\SDQL_2.dm"
#include "code\modules\admin\verbs\SDQL2\SDQL_2_parser.dm"
#include "code\modules\admin\verbs\SDQL2\useful_procs.dm"
-#include "code\modules\alarm\alarm.dm"
-#include "code\modules\alarm\alarm_handler.dm"
-#include "code\modules\alarm\atmosphere_alarm.dm"
-#include "code\modules\alarm\burglar_alarm.dm"
-#include "code\modules\alarm\camera_alarm.dm"
-#include "code\modules\alarm\fire_alarm.dm"
-#include "code\modules\alarm\motion_alarm.dm"
-#include "code\modules\alarm\power_alarm.dm"
#include "code\modules\antagonists\_common\antag_datum.dm"
#include "code\modules\antagonists\_common\antag_helpers.dm"
#include "code\modules\antagonists\_common\antag_hud.dm"
@@ -2067,7 +2060,6 @@
#include "code\modules\modular_computers\file_system\programs\antagonist\revelation.dm"
#include "code\modules\modular_computers\file_system\programs\command\card.dm"
#include "code\modules\modular_computers\file_system\programs\command\comms.dm"
-#include "code\modules\modular_computers\file_system\programs\engineering\alarm.dm"
#include "code\modules\modular_computers\file_system\programs\engineering\power_monitor.dm"
#include "code\modules\modular_computers\file_system\programs\engineering\sm_monitor.dm"
#include "code\modules\modular_computers\file_system\programs\generic\configurator.dm"
@@ -2105,7 +2097,6 @@
#include "code\modules\nano\interaction\physical.dm"
#include "code\modules\nano\interaction\self.dm"
#include "code\modules\nano\interaction\zlevel.dm"
-#include "code\modules\nano\modules\alarm_monitor.dm"
#include "code\modules\nano\modules\atmos_control.dm"
#include "code\modules\nano\modules\ert_manager.dm"
#include "code\modules\nano\modules\human_appearance.dm"
diff --git a/tgui/packages/tgui/components/Collapsible.js b/tgui/packages/tgui/components/Collapsible.js
index 84af070fe18..080074e48ef 100644
--- a/tgui/packages/tgui/components/Collapsible.js
+++ b/tgui/packages/tgui/components/Collapsible.js
@@ -22,7 +22,7 @@ export class Collapsible extends Component {
...rest
} = props;
return (
-
+