diff --git a/code/__DEFINES/color/color.dm b/code/__DEFINES/color/color.dm
index 4c201a7401f..f3e1761dd08 100644
--- a/code/__DEFINES/color/color.dm
+++ b/code/__DEFINES/color/color.dm
@@ -11,6 +11,7 @@
#define COLOR_DARK_ORANGE "#B95A00"
#define COLOR_ORANGE "#FF9900"
#define COLOR_YELLOW "#FFFF00"
+#define COLOR_GOLD "#FFCC33"
#define COLOR_OLIVE "#808000"
#define COLOR_LIME "#00FF00"
#define COLOR_GREEN "#008000"
@@ -35,22 +36,22 @@
#define COLOR_DEEP_SKY_BLUE "#00e1ff"
// Color defines used by the assembly detailer.
-#define COLOR_ASSEMBLY_BLACK "#545454"
-#define COLOR_ASSEMBLY_BGRAY "#9497AB"
-#define COLOR_ASSEMBLY_WHITE "#E2E2E2"
-#define COLOR_ASSEMBLY_RED "#CC4242"
-#define COLOR_ASSEMBLY_ORANGE "#E39751"
-#define COLOR_ASSEMBLY_BEIGE "#AF9366"
-#define COLOR_ASSEMBLY_BROWN "#97670E"
-#define COLOR_ASSEMBLY_GOLD "#AA9100"
-#define COLOR_ASSEMBLY_YELLOW "#CECA2B"
-#define COLOR_ASSEMBLY_GURKHA "#999875"
-#define COLOR_ASSEMBLY_LGREEN "#789876"
-#define COLOR_ASSEMBLY_GREEN "#44843C"
-#define COLOR_ASSEMBLY_LBLUE "#5D99BE"
-#define COLOR_ASSEMBLY_BLUE "#38559E"
-#define COLOR_ASSEMBLY_PURPLE "#6F6192"
-#define COLOR_ASSEMBLY_HOT_PINK "#FF69B4"
+#define COLOR_ASSEMBLY_BLACK "#545454"
+#define COLOR_ASSEMBLY_BGRAY "#9497AB"
+#define COLOR_ASSEMBLY_WHITE "#E2E2E2"
+#define COLOR_ASSEMBLY_RED "#CC4242"
+#define COLOR_ASSEMBLY_ORANGE "#E39751"
+#define COLOR_ASSEMBLY_BEIGE "#AF9366"
+#define COLOR_ASSEMBLY_BROWN "#97670E"
+#define COLOR_ASSEMBLY_GOLD "#AA9100"
+#define COLOR_ASSEMBLY_YELLOW "#CECA2B"
+#define COLOR_ASSEMBLY_GURKHA "#999875"
+#define COLOR_ASSEMBLY_LGREEN "#789876"
+#define COLOR_ASSEMBLY_GREEN "#44843C"
+#define COLOR_ASSEMBLY_LBLUE "#5D99BE"
+#define COLOR_ASSEMBLY_BLUE "#38559E"
+#define COLOR_ASSEMBLY_PURPLE "#6F6192"
+#define COLOR_ASSEMBLY_HOT_PINK "#FF69B4"
///MISC
#define COLOR_ASTEROID_ROCK "#735555"
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 4d8a9fb7e80..4bbbda21728 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -136,6 +136,13 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s
// Area flags, possibly more to come
#define RAD_SHIELDED 1 // Shielded from radiation, clearly
+// OnTopic return values
+#define TOPIC_NOACTION 0
+#define TOPIC_HANDLED 1
+#define TOPIC_REFRESH 2
+#define TOPIC_UPDATE_PREVIEW 4
+#define TOPIC_REFRESH_UPDATE_PREVIEW (TOPIC_REFRESH|TOPIC_UPDATE_PREVIEW)
+
// Convoluted setup so defines can be supplied by Bay12 main server compile script.
// Should still work fine for people jamming the icons into their repo.
#ifndef CUSTOM_ITEM_OBJ
@@ -452,6 +459,89 @@ GLOBAL_LIST_EMPTY(##LIST_NAME);\
#define JOB_SILICON_AI 0x4
#define JOB_SILICON 0x6 // 2|4, probably don't set jobs to this, but good for checking
+/*
+ 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", \
+ "darkmagenta" = "dark magenta",\
+ "steelblue" = "blue", \
+ "goldenrod" = "gold" \
+ )
+
+/// 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" \
+ )
+
+/// Red colorblindness. Vulpkanins/Wolpins have this.
+#define PROTANOPIA_COLOR_REPLACE \
+ list( \
+ "red" = "darkolivegreen", \
+ "darkred" = "darkolivegreen", \
+ "green" = "yellow", \
+ "orange" = "goldenrod", \
+ "gold" = "goldenrod", \
+ "brown" = "darkolivegreen", \
+ "cyan" = "steelblue", \
+ "magenta" = "blue", \
+ "purple" = "darkslategrey", \
+ "pink" = "beige" \
+ )
+
+/// Green colorblindness.
+#define DEUTERANOPIA_COLOR_REPLACE \
+ list( \
+ "red" = "goldenrod", \
+ "green" = "tan", \
+ "yellow" = "tan", \
+ "orange" = "goldenrod", \
+ "gold" = "burlywood", \
+ "brown" = "saddlebrown",\
+ "cyan" = "lavender", \
+ "magenta" = "blue", \
+ "darkmagenta" = "darkslateblue", \
+ "purple" = "slateblue", \
+ "pink" = "thistle" \
+ )
+
+/// 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", \
+ "navy" = "darkslateblue", \
+ "purple" = "darkslateblue", \
+ "pink" = "lightgrey" \
+ )
+
#define SPAN_NOTICE(X) "[X]"
#define SPAN_WARNING(X) "[X]"
#define SPAN_DANGER(X) "[X]"
diff --git a/code/__DEFINES/shields.dm b/code/__DEFINES/shields.dm
new file mode 100644
index 00000000000..daf6d00a65b
--- /dev/null
+++ b/code/__DEFINES/shields.dm
@@ -0,0 +1,48 @@
+#define SHIELD_DAMTYPE_PHYSICAL 1 // Physical damage - bullets, meteors, various hand objects - aka. "brute" damtype.
+#define SHIELD_DAMTYPE_EM 2 // Electromagnetic damage - Ion weaponry, stun beams, ...
+#define SHIELD_DAMTYPE_HEAT 3 // Heat damage - Lasers, fire
+
+// TODO - Thats power not energy you silly goose! I think we mean 45 kilojoules
+#define ENERGY_PER_HP (45 KILOWATTS)// Base amount energy that will be deducted from the generator's internal reserve per 1 HP of damage taken
+#define ENERGY_UPKEEP_PER_TILE (4 KILOWATTS) // Base upkeep per tile protected. Multiplied by various enabled shield modes. Without them the field does literally nothing.
+#define ENERGY_UPKEEP_IDLE 45 // Base upkeep when idle; modified by other factors.
+
+// This shield model is slightly inspired by Sins of a Solar Empire series. In short, shields are designed to analyze what hits them, and adapt themselves against that type of damage.
+// This means shields will become increasingly effective against things like emitters - as they will adapt to heat damage, however they will be vulnerable to brute and EM damage.
+// In a theoretical assault scenario, it is best to combine all damage types, so mitigation can't build up. The value is capped to prevent full scale invulnerability.
+
+#define MAX_MITIGATION_BASE 40 // % Base maximal reachable mitigation.
+#define MAX_MITIGATION_RESEARCH 10 // % Added to MAX_MITIGATION_BASE when generator is built using more advanced components. This value is added for each "tier" of used component, ie. basic one has 1, the best one has 5. Actual maximum should be 90% in this case (with best components). Make sure you won't get above 100%!
+#define MITIGATION_HIT_GAIN 5 // Mitigation gain per hit of respective damage type.
+#define MITIGATION_HIT_LOSS 4 // Mitigation loss per hit. If we get hit once by EM damage type, EM mitigation will grow, while Physical and Heat mitigation values drop.
+#define MITIGATION_LOSS_PASSIVE 0.5 // Mitigation of all damage types will drop by this every tick, up to 0.
+
+// Shield modes allow you to calibrate the field to fit specific needs. It is, for example, possible to create a field that will block airflow, but let people pass.
+// Relevant mode bitflags (maximal of 16 flags due to current BYOND limitations)
+#define MODEFLAG_HYPERKINETIC 1
+#define MODEFLAG_PHOTONIC 2
+#define MODEFLAG_NONHUMANS 4
+#define MODEFLAG_HUMANOIDS 8
+#define MODEFLAG_ANORGANIC 16
+#define MODEFLAG_ATMOSPHERIC 32
+#define MODEFLAG_HULL 64
+#define MODEFLAG_BYPASS 128
+#define MODEFLAG_OVERCHARGE 256
+#define MODEFLAG_MODULATE 512
+#define MODEFLAG_MULTIZ 1024
+#define MODEFLAG_EM 2048
+
+// Return codes for shield hits.
+#define SHIELD_ABSORBED 1 // The shield has completely absorbed the hit
+#define SHIELD_BREACHED_MINOR 2 // The hit was absorbed, but a small gap will be created in the field (1-3 tiles)
+#define SHIELD_BREACHED_MAJOR 3 // Same as above, with 2-5 tile gap
+#define SHIELD_BREACHED_CRITICAL 4 // Same as above, with 4-8 tile gap
+#define SHIELD_BREACHED_FAILURE 5 // Same as above, with 8-16 tile gap. Occurs when the hit exhausts all remaining shield energy.
+
+#define SHIELD_OFF 0 // The shield is offline
+#define SHIELD_DISCHARGING 1 // The shield is shutting down and discharging.
+#define SHIELD_RUNNING 2 // The shield is running
+#define SHIELD_IDLE 3 // The shield is being kept at an idle state
+#define SHIELD_SPINNING_UP 4 // Going from idle to running
+
+#define SHIELD_SHUTDOWN_DISPERSION_RATE (10000 KILOWATTS) // The rate at which shield energy disperses when shutdown is initiated.
diff --git a/code/__DEFINES/wires.dm b/code/__DEFINES/wires.dm
new file mode 100644
index 00000000000..9fce2e8b870
--- /dev/null
+++ b/code/__DEFINES/wires.dm
@@ -0,0 +1,122 @@
+// 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_BACKUP_POWER2 "Secondary 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"
+#define WIRE_CAM_LIGHT "Camera Light"
+#define WIRE_CAM_ALARM "Camera Alarm"
+
+// Grid Check
+#define WIRE_REBOOT "Reboot"
+#define WIRE_LOCKOUT "Lockout"
+#define WIRE_ALLOW_MANUAL1 "Manual Override 1"
+#define WIRE_ALLOW_MANUAL2 "Manual Override 2"
+#define WIRE_ALLOW_MANUAL3 "Manual Override 3"
+
+// Jukebox
+#define WIRE_POWER "Power"
+#define WIRE_JUKEBOX_HACK "Hack"
+#define WIRE_SPEEDUP "Speedup"
+#define WIRE_SPEEDDOWN "Speeddown"
+#define WIRE_REVERSE "Reverse"
+#define WIRE_START "Start"
+#define WIRE_STOP "Stop"
+#define WIRE_PREV "Prev"
+#define WIRE_NEXT "Next"
+
+// 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_EXPLODE_DELAY "Explode Delay" // Explodes immediately if cut, explodes 3 seconds later if pulsed.
+#define WIRE_DISARM "Disarm" // Explicit "disarming" wire.
+#define WIRE_BADDISARM "Bad Disarm" // Disarming wire, except it blows up anyways.
+#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"
+
+// Seed Storage
+#define WIRE_SEED_SMART "Smart"
+#define WIRE_SEED_LOCKDOWN "Lockdown"
+
+// Shield Generator
+#define WIRE_SHIELD_CONTROL "Shield Controls" // Cut to lock most shield controls. Mend to unlock them. Pulse does nothing.
+
+// SMES
+#define WIRE_SMES_RCON "RCon" // Remote control (AI and consoles), cut to disable
+#define WIRE_SMES_INPUT "Input" // Input wire, cut to disable input, pulse to disable for 60s
+#define WIRE_SMES_OUTPUT "Output" // Output wire, cut to disable output, pulse to disable for 60s
+#define WIRE_SMES_GROUNDING "Grounding" // Cut to quickly discharge causing sparks, pulse to only create few sparks
+#define WIRE_SMES_FAILSAFES "Failsafes" // Cut to disable failsafes, mend to reenable
+
+// Suit storage unit
+#define WIRE_SSU_UV "UV wire"
+
+// Tesla coil
+#define WIRE_TESLACOIL_ZAP "Zap"
+
+// RIGsuits
+#define WIRE_RIG_SECURITY "Security"
+#define WIRE_RIG_AI_OVERRIDE "AI Override"
+#define WIRE_RIG_SYSTEM_CONTROL "System Control"
+#define WIRE_RIG_INTERFACE_LOCK "Interface Lock"
+#define WIRE_RIG_INTERFACE_SHOCK "Interface Shock"
diff --git a/code/_globalvars/lists/misc.dm b/code/_globalvars/lists/misc.dm
index 53fc0f01e42..b35405d3e06 100644
--- a/code/_globalvars/lists/misc.dm
+++ b/code/_globalvars/lists/misc.dm
@@ -1,2 +1,6 @@
GLOBAL_LIST_INIT(char_directory_tags, list("Pred", "Prey", "Switch", "Non-Vore", "Unset"))
GLOBAL_LIST_INIT(char_directory_erptags, list("Top", "Bottom", "Switch", "No ERP", "Unset"))
+GLOBAL_LIST_EMPTY(meteor_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/ai.dm b/code/_onclick/ai.dm
index fffd092696f..b41e005a3e0 100644
--- a/code/_onclick/ai.dm
+++ b/code/_onclick/ai.dm
@@ -164,7 +164,7 @@
if(..())
return
add_hiddenprint(user)
- if(wires.IsIndexCut(AIRLOCK_WIRE_LIGHT))
+ if(wires.is_cut(WIRE_BOLT_LIGHT))
to_chat(user, "The lights are not responsive to your command.")
return
lights = !lights
diff --git a/code/datums/supplypacks/engineering.dm b/code/datums/supplypacks/engineering.dm
index 69ea2a97cc9..1baf2df021b 100644
--- a/code/datums/supplypacks/engineering.dm
+++ b/code/datums/supplypacks/engineering.dm
@@ -35,48 +35,6 @@
containertype = /obj/structure/closet/crate/engineering
containername = "Superconducting Transmission Coil crate"
-/datum/supply_pack/eng/shield_capacitor
- name = "Shield Capacitor"
- contains = list(/obj/machinery/shield_capacitor)
- cost = 20
- containertype = /obj/structure/closet/crate/engineering
- containername = "shield capacitor crate"
-
-/datum/supply_pack/eng/shield_capacitor/advanced
- name = "Advanced Shield Capacitor"
- contains = list(/obj/machinery/shield_capacitor/advanced)
- cost = 30
- containertype = /obj/structure/closet/crate/engineering
- containername = "advanced shield capacitor crate"
-
-/datum/supply_pack/eng/bubble_shield
- name = "Bubble Shield Generator"
- contains = list(/obj/machinery/shield_gen)
- cost = 40
- containertype = /obj/structure/closet/crate/engineering
- containername = "shield bubble generator crate"
-
-/datum/supply_pack/eng/bubble_shield/advanced
- name = "Advanced Bubble Shield Generator"
- contains = list(/obj/machinery/shield_gen/advanced)
- cost = 60
- containertype = /obj/structure/closet/crate/engineering
- containername = "advanced bubble shield generator crate"
-
-/datum/supply_pack/eng/hull_shield
- name = "Hull Shield Generator"
- contains = list(/obj/machinery/shield_gen/external)
- cost = 80
- containertype = /obj/structure/closet/crate/engineering
- containername = "shield hull generator crate"
-
-/datum/supply_pack/eng/hull_shield/advanced
- name = "Advanced Hull Shield Generator"
- contains = list(/obj/machinery/shield_gen/external/advanced)
- cost = 120
- containertype = /obj/structure/closet/crate/engineering
- containername = "advanced hull shield generator crate"
-
/datum/supply_pack/eng/electrical
name = "Electrical maintenance crate"
contains = list(
@@ -175,30 +133,19 @@
containername = "Particle Accelerator crate"
access = access_ce
-/datum/supply_pack/eng/shield_gen
- contains = list(/obj/item/circuitboard/shield_gen)
- name = "Bubble shield generator circuitry"
- cost = 30
- containertype = /obj/structure/closet/crate/secure/engineering
- containername = "bubble shield generator circuitry crate"
- access = access_ce
-
-/datum/supply_pack/eng/shield_gen_ex
- contains = list(/obj/item/circuitboard/shield_gen_ex)
- name = "Hull shield generator circuitry"
- cost = 30
- containertype = /obj/structure/closet/crate/secure/engineering
- containername = "hull shield generator circuitry crate"
- access = access_ce
-
-/datum/supply_pack/eng/shield_cap
- contains = list(/obj/item/circuitboard/shield_cap)
- name = "Bubble shield capacitor circuitry"
- cost = 30
- containertype = /obj/structure/closet/crate/secure/engineering
- containername = "shield capacitor circuitry crate"
- access = access_ce
-
+/datum/supply_pack/eng/shield_generator
+ name = "Shield Generator Construction Kit"
+ contains = list(
+ /obj/item/circuitboard/shield_generator,
+ /obj/item/stock_parts/capacitor,
+ /obj/item/stock_parts/micro_laser,
+ /obj/item/smes_coil,
+ /obj/item/stock_parts/console_screen,
+ /obj/item/stock_parts/subspace/amplifier
+ )
+ cost = 80
+ containertype = /obj/structure/closet/crate/engineering
+ containername = "shield generator construction kit crate"
/datum/supply_pack/eng/smbig
name = "Supermatter Core"
contains = list(/obj/machinery/power/supermatter)
diff --git a/code/datums/uplink/tools.dm b/code/datums/uplink/tools.dm
index 4e932014785..854122e1893 100644
--- a/code/datums/uplink/tools.dm
+++ b/code/datums/uplink/tools.dm
@@ -53,6 +53,12 @@
name = "Black Ammunition Duffle Bag"
path = /obj/item/storage/backpack/dufflebag/syndie/ammo
+/datum/uplink_item/item/tools/shield_diffuser
+ name = "Handheld Shield Diffuser"
+ desc = "A small device used to disrupt energy barriers, and allow passage through them."
+ item_cost = 16
+ path = /obj/item/shield_diffuser
+
/datum/uplink_item/item/tools/space_suit
name = "Space Suit"
item_cost = 15
@@ -188,4 +194,3 @@
name = "Survival Capsule (Bar)"
item_cost = 80
path = /obj/item/survivalcapsule/luxurybar
-
diff --git a/code/datums/wires/airlock.dm b/code/datums/wires/airlock.dm
index 85546a79d75..60103b244a3 100644
--- a/code/datums/wires/airlock.dm
+++ b/code/datums/wires/airlock.dm
@@ -1,61 +1,53 @@
// Wires for airlocks
/datum/wires/airlock/secure
- random = 1
+ randomize = TRUE
wire_count = 14
/datum/wires/airlock
holder_type = /obj/machinery/door/airlock
wire_count = 12
- window_y = 570
+ proper_name = "Airlock"
-var/const/AIRLOCK_WIRE_IDSCAN = 1
-var/const/AIRLOCK_WIRE_MAIN_POWER1 = 2
-var/const/AIRLOCK_WIRE_MAIN_POWER2 = 4
-var/const/AIRLOCK_WIRE_DOOR_BOLTS = 8
-var/const/AIRLOCK_WIRE_BACKUP_POWER1 = 16
-var/const/AIRLOCK_WIRE_BACKUP_POWER2 = 32
-var/const/AIRLOCK_WIRE_OPEN_DOOR = 64
-var/const/AIRLOCK_WIRE_AI_CONTROL = 128
-var/const/AIRLOCK_WIRE_ELECTRIFY = 256
-var/const/AIRLOCK_WIRE_SAFETY = 512
-var/const/AIRLOCK_WIRE_SPEED = 1024
-var/const/AIRLOCK_WIRE_LIGHT = 2048
-
-/datum/wires/airlock/CanUse(var/mob/living/L)
+/datum/wires/airlock/interactable(mob/user)
var/obj/machinery/door/airlock/A = holder
- if(!istype(L, /mob/living/silicon))
+ if(!issilicon(user))
if(A.isElectrified())
- if(A.shock(L, 100))
- return 0
+ if(A.shock(user, 100))
+ return FALSE
if(A.p_open)
- return 1
- return 0
+ return TRUE
+ return FALSE
-/datum/wires/airlock/GetInteractWindow()
+/datum/wires/airlock/New(atom/_holder)
+ wires = list(
+ WIRE_IDSCAN, WIRE_MAIN_POWER1, WIRE_MAIN_POWER2, WIRE_DOOR_BOLTS,
+ WIRE_BACKUP_POWER1, WIRE_BACKUP_POWER2, WIRE_OPEN_DOOR, WIRE_AI_CONTROL,
+ WIRE_ELECTRIFY, WIRE_SAFETY, WIRE_SPEED, WIRE_BOLT_LIGHT
+ )
+ return ..()
+
+/datum/wires/airlock/get_status()
+ . = ..()
var/obj/machinery/door/airlock/A = holder
var/haspower = A.arePowerSystemsOn() //If there's no power, then no lights will be on.
- . += ..()
- . += text("
\n[]
\n[]
\n[]
\n[]
\n[]
\n[]
\n[]
\n[]",
- (A.locked ? "The door bolts have fallen!" : "The door bolts look up."),
- ((A.lights && haspower) ? "The door bolt lights are on." : "The door bolt lights are off!"),
- ((haspower) ? "The test light is on." : "The test light is off!"),
- ((A.backup_power_lost_until) ? "The backup power light is off!" : "The backup power light is on."),
- ((A.aiControlDisabled==0 && !A.emagged && haspower)? "The 'AI control allowed' light is on." : "The 'AI control allowed' light is off."),
- ((A.safe==0 && haspower)? "The 'Check Wiring' light is on." : "The 'Check Wiring' light is off."),
- ((A.normalspeed==0 && haspower)? "The 'Check Timing Mechanism' light is on." : "The 'Check Timing Mechanism' light is off."),
- ((A.aiDisabledIdScanner==0 && haspower)? "The IDScan light is on." : "The IDScan light is off."))
-
-/datum/wires/airlock/UpdateCut(var/index, var/mended)
+ . += "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 backup power light is [A.backup_power_lost_until ? "off!" : "on."]"
+ . += "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 IDScan light is [(A.aiDisabledIdScanner == 0 && haspower) ? "on" : "off."]"
+/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, AIRLOCK_WIRE_MAIN_POWER2)
-
- if(!mended)
+ switch(wire)
+ if(WIRE_IDSCAN)
+ A.aiDisabledIdScanner = !mend
+ if(WIRE_MAIN_POWER1, WIRE_MAIN_POWER2)
+ 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)
@@ -63,9 +55,8 @@ var/const/AIRLOCK_WIRE_LIGHT = 2048
A.regainMainPower()
A.shock(usr, 50)
- if(AIRLOCK_WIRE_BACKUP_POWER1, AIRLOCK_WIRE_BACKUP_POWER2)
-
- if(!mended)
+ if(WIRE_BACKUP_POWER1, WIRE_BACKUP_POWER2)
+ 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)
@@ -73,16 +64,14 @@ var/const/AIRLOCK_WIRE_LIGHT = 2048
A.regainBackupPower()
A.shock(usr, 50)
- if(AIRLOCK_WIRE_DOOR_BOLTS)
-
- if(!mended)
+ if(WIRE_DOOR_BOLTS)
+ 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(!mended)
+ if(WIRE_AI_CONTROL)
+ 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)
@@ -95,40 +84,41 @@ var/const/AIRLOCK_WIRE_LIGHT = 2048
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)
A.close()
- if(AIRLOCK_WIRE_LIGHT)
- A.lights = mended
+ if(WIRE_BOLT_LIGHT)
+ A.lights = mend
A.update_icon()
-/datum/wires/airlock/UpdatePulsed(var/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(AIRLOCK_WIRE_MAIN_POWER1, AIRLOCK_WIRE_MAIN_POWER2)
+
+ if(WIRE_MAIN_POWER1, WIRE_MAIN_POWER2)
//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)
@@ -136,10 +126,11 @@ var/const/AIRLOCK_WIRE_LIGHT = 2048
else
A.unlock()
- if(AIRLOCK_WIRE_BACKUP_POWER1, AIRLOCK_WIRE_BACKUP_POWER2)
+ if(WIRE_BACKUP_POWER1, WIRE_BACKUP_POWER2)
//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)
@@ -152,24 +143,26 @@ var/const/AIRLOCK_WIRE_LIGHT = 2048
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))
if(A.density) A.open()
else A.close()
- if(AIRLOCK_WIRE_SAFETY)
+
+ if(WIRE_SAFETY)
A.safe = !A.safe
if(!A.density)
A.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 7c2d4d65d09..383eb360c05 100644
--- a/code/datums/wires/alarm.dm
+++ b/code/datums/wires/alarm.dm
@@ -1,93 +1,87 @@
/datum/wires/alarm
holder_type = /obj/machinery/alarm
wire_count = 5
+ proper_name = "Air alarm"
-var/const/AALARM_WIRE_IDSCAN = 1
-var/const/AALARM_WIRE_POWER = 2
-var/const/AALARM_WIRE_SYPHON = 4
-var/const/AALARM_WIRE_AI_CONTROL = 8
-var/const/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/CanUse(var/mob/living/L)
+/datum/wires/alarm/interactable(mob/user)
var/obj/machinery/alarm/A = holder
if(A.panel_open)
- return 1
- return 0
+ return TRUE
+ return FALSE
-/datum/wires/alarm/GetInteractWindow()
+/datum/wires/alarm/get_status()
var/obj/machinery/alarm/A = holder
- . += ..()
- . += text("
\n[(A.locked ? "The Air Alarm is locked." : "The Air Alarm is unlocked.")]
\n[((A.shorted || (A.stat & (NOPOWER|BROKEN))) ? "The Air Alarm is offline." : "The Air Alarm is working properly!")]
\n[(A.aidisabled ? "The 'AI control allowed' light is off." : "The 'AI control allowed' light is on.")]")
+ . = ..()
+ . += "The Air Alarm is [A.locked ? "locked." : "unlocked."]"
+ . += "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(var/index, var/mended)
+/datum/wires/alarm/on_cut(wire, mend)
var/obj/machinery/alarm/A = holder
- switch(index)
- if(AALARM_WIRE_IDSCAN)
- if(!mended)
- A.locked = 1
- //to_chat(world, "Idscan wire cut")
+ switch(wire)
+ if(WIRE_IDSCAN)
+ if(!mend)
+ A.locked = TRUE
- 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)
- if (A.aidisabled == !mended)
- A.aidisabled = mended
- //to_chat(world, "AI Control Wire Cut")
+ if(WIRE_AI_CONTROL)
+ A.aidisabled = !mend
- if(AALARM_WIRE_SYPHON)
- if(!mended)
- A.mode = 3 // AALARM_MODE_PANIC
+ if(WIRE_SYPHON)
+ if(!mend)
+ A.mode = 3 // MODE_PANIC
A.apply_mode()
- //to_chat(world, "Syphon Wire Cut")
- if(AALARM_WIRE_AALARM)
- if (A.alarm_area.atmosalert(2, A))
+ if(WIRE_AALARM)
+ if(A.alarm_area.atmosalert(2, A))
A.post_alert(2)
A.update_icon()
+ ..()
-/datum/wires/alarm/UpdatePulsed(var/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()
spawn(12000)
- if(A.shorted == 1)
- A.shorted = 0
+ if(A.shorted)
+ A.shorted = FALSE
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
+ if(A.aidisabled)
+ A.aidisabled = FALSE
- if(AALARM_WIRE_SYPHON)
- // to_chat(world, "Syphon wire pulsed")
- if(A.mode == 1) // AALARM_MODE_SCRUB
- A.mode = 3 // AALARM_MODE_PANIC
+ if(WIRE_SYPHON)
+ if(A.mode == 1) // MODE_SCRUB
+ A.mode = 3 // MODE_PANIC
else
- A.mode = 1 // AALARM_MODE_SCRUB
+ A.mode = 1 // MODE_SCRUB
A.apply_mode()
- if(AALARM_WIRE_AALARM)
- // to_chat(world, "Aalarm wire pulsed")
- if (A.alarm_area.atmosalert(0, A))
+ if(WIRE_AALARM)
+ if(A.alarm_area.atmosalert(0, A))
A.post_alert(0)
A.update_icon()
diff --git a/code/datums/wires/apc.dm b/code/datums/wires/apc.dm
index 5bb5831d3ed..f4c71b87e84 100644
--- a/code/datums/wires/apc.dm
+++ b/code/datums/wires/apc.dm
@@ -1,74 +1,66 @@
/datum/wires/apc
holder_type = /obj/machinery/power/apc
wire_count = 4
+ proper_name = "APC"
-#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/New(atom/_holder)
+ wires = list(WIRE_IDSCAN, WIRE_MAIN_POWER1, WIRE_MAIN_POWER2, WIRE_AI_CONTROL)
+ return ..()
-/datum/wires/apc/GetInteractWindow()
+/datum/wires/apc/get_status()
+ . = ..()
var/obj/machinery/power/apc/A = holder
- . += ..()
- . += text("
\n[(A.locked ? "The APC is locked." : "The APC is unlocked.")]
\n[(A.shorted ? "The APCs power has been shorted." : "The APC is working properly!")]
\n[(A.aidisabled ? "The 'AI control allowed' light is off." : "The 'AI control allowed' light is on.")]")
+ . += "The APC is [A.locked ? "" : "un"]locked."
+ . += A.shorted ? "The APCs power has been shorted." : "The APC is working properly!"
+ . += "The 'AI control allowed' light is [A.aidisabled ? "off" : "on"]."
-
-/datum/wires/apc/CanUse(var/mob/living/L)
+/datum/wires/apc/interactable(mob/user)
var/obj/machinery/power/apc/A = holder
if(A.wiresexposed)
- return 1
- return 0
-
-/datum/wires/apc/UpdatePulsed(var/index)
+ return TRUE
+ return FALSE
+/datum/wires/apc/on_pulse(wire)
var/obj/machinery/power/apc/A = holder
- switch(index)
-
- if(APC_WIRE_IDSCAN)
- A.locked = 0
+ switch(wire)
+ if(WIRE_IDSCAN)
+ A.locked = FALSE
spawn(300)
if(A)
- A.locked = 1
+ A.locked = TRUE
- if (APC_WIRE_MAIN_POWER1, APC_WIRE_MAIN_POWER2)
- if(A.shorted == 0)
- A.shorted = 1
+ if(WIRE_MAIN_POWER1, WIRE_MAIN_POWER2)
+ if(!A.shorted)
+ A.shorted = TRUE
spawn(1200)
- if(A && !IsIndexCut(APC_WIRE_MAIN_POWER1) && !IsIndexCut(APC_WIRE_MAIN_POWER2))
- A.shorted = 0
+ if(A && !is_cut(WIRE_MAIN_POWER1) && !is_cut(WIRE_MAIN_POWER2))
+ A.shorted = FALSE
- if (APC_WIRE_AI_CONTROL)
- if (A.aidisabled == 0)
- A.aidisabled = 1
+ if(WIRE_AI_CONTROL)
+ if(!A.aidisabled)
+ A.aidisabled = TRUE
spawn(10)
- if(A && !IsIndexCut(APC_WIRE_AI_CONTROL))
- A.aidisabled = 0
+ if(A && !is_cut(WIRE_AI_CONTROL))
+ A.aidisabled = FALSE
-/datum/wires/apc/UpdateCut(var/index, var/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)
- if(istype(usr, /mob/living))
+ switch(wire)
+ if(WIRE_MAIN_POWER1, WIRE_MAIN_POWER2)
+ if(!mend)
+ if(isliving(usr))
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
- if(istype(usr, /mob/living))
+ else if(!is_cut(WIRE_MAIN_POWER1) && !is_cut(WIRE_MAIN_POWER2))
+ A.shorted = FALSE
+ if(isliving(usr))
A.shock(usr, 50)
- if(APC_WIRE_AI_CONTROL)
-
- if(!mended)
- if (A.aidisabled == 0)
- A.aidisabled = 1
- else
- if (A.aidisabled == 1)
- A.aidisabled = 0
+ if(WIRE_AI_CONTROL)
+ A.aidisabled = !mend
diff --git a/code/datums/wires/autolathe.dm b/code/datums/wires/autolathe.dm
index a703bfc0785..0de661bbf82 100644
--- a/code/datums/wires/autolathe.dm
+++ b/code/datums/wires/autolathe.dm
@@ -1,61 +1,54 @@
/datum/wires/autolathe
-
holder_type = /obj/machinery/autolathe
wire_count = 6
+ proper_name = "Autolathe"
-var/const/AUTOLATHE_HACK_WIRE = 1
-var/const/AUTOLATHE_SHOCK_WIRE = 2
-var/const/AUTOLATHE_DISABLE_WIRE = 4
+/datum/wires/autolathe/New(atom/_holder)
+ wires = list(WIRE_AUTOLATHE_HACK, WIRE_ELECTRIFY, WIRE_AUTOLATHE_DISABLE)
+ return ..()
-/datum/wires/autolathe/GetInteractWindow()
+/datum/wires/autolathe/get_status()
+ . = ..()
var/obj/machinery/autolathe/A = holder
- . += ..()
- . += "
The red light is [A.disabled ? "off" : "on"]."
- . += "
The green light is [A.shocked ? "off" : "on"]."
- . += "
The blue light is [A.hacked ? "off" : "on"].
"
+ . += "The red light is [A.disabled ? "off" : "on"]."
+ . += "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(A.panel_open)
- return 1
- return 0
+ return TRUE
+ return FALSE
-/*
-/datum/wires/autolathe/Interact(var/mob/living/user)
- if(CanUse(user))
- var/obj/machinery/autolathe/V = holder
- V.attack_hand(user)
-*/
-/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.hacked = !mended
- if(AUTOLATHE_SHOCK_WIRE)
- A.shocked = !mended
- if(AUTOLATHE_DISABLE_WIRE)
- A.disabled = !mended
+ switch(wire)
+ if(WIRE_AUTOLATHE_HACK)
+ A.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.hacked = !A.hacked
spawn(50)
- if(A && !IsIndexCut(index))
+ if(A && !is_cut(wire))
A.hacked = 0
- Interact(usr)
- if(AUTOLATHE_SHOCK_WIRE)
+ if(WIRE_ELECTRIFY)
A.shocked = !A.shocked
spawn(50)
- if(A && !IsIndexCut(index))
+ if(A && !is_cut(wire))
A.shocked = 0
- Interact(usr)
- if(AUTOLATHE_DISABLE_WIRE)
+ if(WIRE_AUTOLATHE_DISABLE)
A.disabled = !A.disabled
spawn(50)
- if(A && !IsIndexCut(index))
+ if(A && !is_cut(wire))
A.disabled = 0
- Interact(usr)
+ ..()
diff --git a/code/datums/wires/breaker.dm b/code/datums/wires/breaker.dm
index 90d059466ce..dfb79a7d124 100644
--- a/code/datums/wires/breaker.dm
+++ b/code/datums/wires/breaker.dm
@@ -1,27 +1,30 @@
/datum/wires/breakerbox
- wire_count = 2
holder_type = /obj/machinery/power/breakerbox
+ wire_count = 2
+ proper_name = "Breaker box"
-var/const/WIRE_TOGGLE = 1
-var/const/WIRE_LOCK = 2
+/datum/wires/breakerbox/New(atom/_holder)
+ wires = list(WIRE_POWER, WIRE_IDSCAN)
+ return ..()
-/datum/wires/breakerbox/UpdatePulsed(var/index)
- switch(index)
- if(WIRE_TOGGLE)
- var/obj/machinery/power/breakerbox/B= holder
- var/on = B.on
- B.set_state(!on)
-
-/datum/wires/breakerbox/UpdateCut(var/index, var/mended)
- var/obj/machinery/power/breakerbox/B = holder
- switch(index)
- if(WIRE_LOCK)
- if(!mended)
- B.update_locked = TRUE
- else
- B.update_locked = FALSE
-/datum/wires/breakerbox/CanUse(var/mob/living/L)
+/datum/wires/breakerbox/interactable(mob/user)
var/obj/machinery/power/breakerbox/B = holder
if(B.panel_open)
return TRUE
return FALSE
+
+/datum/wires/breakerbox/on_pulse(wire)
+ switch(wire)
+ if(WIRE_POWER)
+ var/obj/machinery/power/breakerbox/B= holder
+ var/on = B.on
+ B.set_state(!on)
+
+/datum/wires/breakerbox/on_cut(wire, mend)
+ var/obj/machinery/power/breakerbox/B = holder
+ switch(wire)
+ if(WIRE_IDSCAN)
+ if(!mend)
+ B.update_locked = TRUE
+ else
+ B.update_locked = FALSE
diff --git a/code/datums/wires/camera.dm b/code/datums/wires/camera.dm
index 4beeb384033..5ce48320b28 100644
--- a/code/datums/wires/camera.dm
+++ b/code/datums/wires/camera.dm
@@ -1,71 +1,62 @@
-// Wires for cameras.
-
/datum/wires/camera
- random = 1
+ randomize = TRUE
holder_type = /obj/machinery/camera
wire_count = 6
+ proper_name = "Camera"
-/datum/wires/camera/GetInteractWindow()
+/datum/wires/camera/New(atom/_holder)
+ wires = list(WIRE_FOCUS, WIRE_MAIN_POWER1, WIRE_CAM_LIGHT, WIRE_CAM_ALARM)
+ return ..()
+/datum/wires/camera/get_status()
. = ..()
var/obj/machinery/camera/C = holder
- . += "
\n[(C.view_range == initial(C.view_range) ? "The focus light is on." : "The focus light is off.")]"
- . += "
\n[(C.can_use() ? "The power link light is on." : "The power link light is off.")]"
- . += "
\n[(C.light_disabled ? "The camera light is off." : "The camera light is on.")]"
- . += "
\n[(C.alarm_on ? "The alarm light is on." : "The alarm light is off.")]"
- return .
+ . += "The focus light is [(C.view_range == initial(C.view_range)) ? "on" : "off"]."
+ . += "The power link light is [C.can_use() ? "on" : "off"]."
+ . += "The camera light is [C.light_disabled ? "off" : "on"]."
+ . += "The alarm light is [C.alarm_on ? "on" : "off"]."
-/datum/wires/camera/CanUse(var/mob/living/L)
+/datum/wires/camera/interactable(mob/user)
var/obj/machinery/camera/C = holder
return C.panel_open
-var/const/CAMERA_WIRE_FOCUS = 1
-var/const/CAMERA_WIRE_POWER = 2
-var/const/CAMERA_WIRE_LIGHT = 4
-var/const/CAMERA_WIRE_ALARM = 8
-var/const/CAMERA_WIRE_NOTHING1 = 16
-var/const/CAMERA_WIRE_NOTHING2 = 32
-
-/datum/wires/camera/UpdateCut(var/index, var/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.deactivate(usr, 1)
- if(CAMERA_WIRE_LIGHT)
- C.light_disabled = !mended
+ if(WIRE_CAM_LIGHT)
+ C.light_disabled = !mend
- if(CAMERA_WIRE_ALARM)
- if(!mended)
+ if(WIRE_CAM_ALARM)
+ if(!mend)
C.triggerCameraAlarm()
else
C.cancelCameraAlarm()
- return
+ ..()
-/datum/wires/camera/UpdatePulsed(var/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_LIGHT)
+ if(WIRE_CAM_LIGHT)
C.light_disabled = !C.light_disabled
- if(CAMERA_WIRE_ALARM)
+ if(WIRE_CAM_ALARM)
C.visible_message("[icon2html(thing = C, target = world)] *beep*", "[icon2html(thing = C, target = world)] *beep*")
- return
+ ..()
/datum/wires/camera/proc/CanDeconstruct()
- if(IsIndexCut(CAMERA_WIRE_POWER) && IsIndexCut(CAMERA_WIRE_FOCUS) && IsIndexCut(CAMERA_WIRE_LIGHT) && IsIndexCut(CAMERA_WIRE_NOTHING1) && IsIndexCut(CAMERA_WIRE_NOTHING2))
- return 1
- else
- return 0
+ return is_all_cut()
diff --git a/code/datums/wires/coinbank.dm b/code/datums/wires/coinbank.dm
index 503638b2dd0..4e24b1b5328 100644
--- a/code/datums/wires/coinbank.dm
+++ b/code/datums/wires/coinbank.dm
@@ -1,37 +1,39 @@
/datum/wires/coinbank
holder_type = /obj/machinery/coinbank
wire_count = 3
+ proper_name = "Coin Bank"
-var/const/COINBANK_WIRE_ELECTRIFY = 1
-var/const/COINBANK_WIRE_THROW = 2
+/datum/wires/coinbank/New(atom/_holder)
+ wires = list(WIRE_ELECTRIFY, WIRE_THROW_ITEM)
+ return ..()
-/datum/wires/coinbank/CanUse(var/mob/living/L)
+/datum/wires/coinbank/interactable(mob/user)
var/obj/machinery/coinbank/C = holder
if(C.panel_open)
- return 1
- return 0
+ return TRUE
+ return FALSE
-/datum/wires/coinbank/GetInteractWindow()
+/datum/wires/coinbank/get_status()
var/obj/machinery/coinbank/C = holder
- . += ..()
- . += "
The orange light is [C.seconds_electrified ? "off" : "on"].
"
- . += "The red light is [C.shoot_inventory ? "off" : "blinking"].
"
+ . = ..()
+ . += "The orange light is [C.seconds_electrified ? "off" : "on"]."
+ . += "The red light is [C.shoot_inventory ? "off" : "blinking"]."
-/datum/wires/coinbank/UpdatePulsed(var/index)
+/datum/wires/coinbank/on_pulse(wire)
var/obj/machinery/coinbank/C = holder
- switch(index)
- if(SMARTFRIDGE_WIRE_THROW)
+ switch(wire)
+ if(WIRE_THROW_ITEM)
C.shoot_inventory = !C.shoot_inventory
- if(SMARTFRIDGE_WIRE_ELECTRIFY)
+ if(WIRE_ELECTRIFY)
C.seconds_electrified = 30
-/datum/wires/coinbank/UpdateCut(var/index, var/mended)
+/datum/wires/coinbank/on_cut(wire, mend)
var/obj/machinery/coinbank/C = holder
- switch(index)
- if(COINBANK_WIRE_THROW)
- C.shoot_inventory = !mended
- if(COINBANK_WIRE_ELECTRIFY)
- if(mended)
+ switch(wire)
+ if(WIRE_THROW_ITEM)
+ C.shoot_inventory = !mend
+ if(WIRE_ELECTRIFY)
+ if(mend)
C.seconds_electrified = 0
else
C.seconds_electrified = -1
diff --git a/code/datums/wires/explosive.dm b/code/datums/wires/explosive.dm
index 97e2c8dd6f4..8267f05fcf6 100644
--- a/code/datums/wires/explosive.dm
+++ b/code/datums/wires/explosive.dm
@@ -1,30 +1,33 @@
/datum/wires/explosive
wire_count = 1
+ proper_name = "Explosive wires"
-var/const/WIRE_EXPLODE = 1
+/datum/wires/explosive/New(atom/_holder)
+ wires = list(WIRE_EXPLODE)
+ return ..()
/datum/wires/explosive/proc/explode()
return
-/datum/wires/explosive/UpdatePulsed(var/index)
- switch(index)
+/datum/wires/explosive/on_pulse(wire)
+ switch(wire)
if(WIRE_EXPLODE)
explode()
-/datum/wires/explosive/UpdateCut(var/index, var/mended)
- switch(index)
+/datum/wires/explosive/on_cut(wire, mend)
+ switch(wire)
if(WIRE_EXPLODE)
- if(!mended)
+ if(!mend)
explode()
/datum/wires/explosive/c4
holder_type = /obj/item/plastique
-/datum/wires/explosive/c4/CanUse(var/mob/living/L)
+/datum/wires/explosive/c4/interactable(mob/user)
var/obj/item/plastique/P = holder
if(P.open_panel)
- return 1
- return 0
+ return TRUE
+ return FALSE
/datum/wires/explosive/c4/explode()
var/obj/item/plastique/P = holder
diff --git a/code/datums/wires/grid_checker.dm b/code/datums/wires/grid_checker.dm
index 4143476e699..af31fec8ac2 100644
--- a/code/datums/wires/grid_checker.dm
+++ b/code/datums/wires/grid_checker.dm
@@ -1,66 +1,64 @@
/datum/wires/grid_checker
holder_type = /obj/machinery/power/grid_checker
wire_count = 8
+ proper_name = "Grid Checker"
-var/const/GRID_CHECKER_WIRE_REBOOT = 1 // This wire causes the grid-check to end, if pulsed.
-var/const/GRID_CHECKER_WIRE_LOCKOUT = 2 // If cut or pulsed, locks the user out for half a minute.
-var/const/GRID_CHECKER_WIRE_ALLOW_MANUAL_1 = 4 // Needs to be cut for REBOOT to be possible.
-var/const/GRID_CHECKER_WIRE_ALLOW_MANUAL_2 = 8 // Needs to be cut for REBOOT to be possible.
-var/const/GRID_CHECKER_WIRE_ALLOW_MANUAL_3 = 16 // Needs to be cut for REBOOT to be possible.
-var/const/GRID_CHECKER_WIRE_SHOCK = 32 // Shocks the user if not wearing gloves.
-var/const/GRID_CHECKER_WIRE_NOTHING_1 = 64 // Does nothing, but makes it a bit harder.
-var/const/GRID_CHECKER_WIRE_NOTHING_2 = 128 // Does nothing, but makes it a bit harder.
+/datum/wires/grid_checker/New(atom/_holder)
+ wires = list(
+ WIRE_REBOOT, WIRE_LOCKOUT, WIRE_ALLOW_MANUAL1,
+ WIRE_ALLOW_MANUAL2, WIRE_ALLOW_MANUAL3, WIRE_ELECTRIFY
+ )
+ return ..()
-
-/datum/wires/grid_checker/CanUse(var/mob/living/L)
+/datum/wires/grid_checker/interactable(mob/user)
var/obj/machinery/power/grid_checker/G = holder
if(G.opened)
return TRUE
return FALSE
-
-/datum/wires/grid_checker/GetInteractWindow()
+/datum/wires/grid_checker/get_status()
var/obj/machinery/power/grid_checker/G = holder
- . += ..()
- . += "The green light is [G.power_failing ? "off" : "on"].
"
- . += "The red light is [G.wire_locked_out ? "on" : "off"].
"
- . += "The blue light is [G.wire_allow_manual_1 && G.wire_allow_manual_2 && G.wire_allow_manual_3 ? "on" : "off"]."
+ . = ..()
+ . += "The green light is [G.power_failing ? "off." : "on."]"
+ . += "The red light is [G.wire_locked_out ? "on." : "off."]"
+ . += "The blue light is [(G.wire_allow_manual_1 && G.wire_allow_manual_2 && G.wire_allow_manual_3) ? "on." : "off."]"
-
-/datum/wires/grid_checker/UpdateCut(var/index, var/mended)
+/datum/wires/grid_checker/on_cut(wire, mend)
var/obj/machinery/power/grid_checker/G = holder
- switch(index)
- if(GRID_CHECKER_WIRE_LOCKOUT)
- G.wire_locked_out = !mended
- if(GRID_CHECKER_WIRE_ALLOW_MANUAL_1)
- G.wire_allow_manual_1 = !mended
- if(GRID_CHECKER_WIRE_ALLOW_MANUAL_2)
- G.wire_allow_manual_2 = !mended
- if(GRID_CHECKER_WIRE_ALLOW_MANUAL_3)
- G.wire_allow_manual_3 = !mended
- if(GRID_CHECKER_WIRE_SHOCK)
+ switch(wire)
+ if(WIRE_LOCKOUT)
+ G.wire_locked_out = !mend
+ if(WIRE_ALLOW_MANUAL1)
+ G.wire_allow_manual_1 = !mend
+ if(WIRE_ALLOW_MANUAL2)
+ G.wire_allow_manual_2 = !mend
+ if(WIRE_ALLOW_MANUAL3)
+ G.wire_allow_manual_3 = !mend
+ if(WIRE_ELECTRIFY)
if(G.wire_locked_out)
return
G.shock(usr, 70)
+ ..()
-
-/datum/wires/grid_checker/UpdatePulsed(var/index)
+/datum/wires/grid_checker/on_pulse(wire)
var/obj/machinery/power/grid_checker/G = holder
- switch(index)
- if(GRID_CHECKER_WIRE_REBOOT)
+ switch(wire)
+ if(WIRE_REBOOT)
if(G.wire_locked_out)
return
-
if(G.power_failing && G.wire_allow_manual_1 && G.wire_allow_manual_2 && G.wire_allow_manual_3)
G.end_power_failure(TRUE)
- if(GRID_CHECKER_WIRE_LOCKOUT)
+
+ if(WIRE_LOCKOUT)
if(G.wire_locked_out)
return
G.wire_locked_out = TRUE
spawn(30 SECONDS)
G.wire_locked_out = FALSE
- if(GRID_CHECKER_WIRE_SHOCK)
+
+ if(WIRE_ELECTRIFY)
if(G.wire_locked_out)
return
G.shock(usr, 70)
+ ..()
diff --git a/code/datums/wires/jukebox.dm b/code/datums/wires/jukebox.dm
index e8541abebdb..bbc176bb7ea 100644
--- a/code/datums/wires/jukebox.dm
+++ b/code/datums/wires/jukebox.dm
@@ -1,42 +1,39 @@
/datum/wires/jukebox
- random = 1
+ randomize = TRUE
holder_type = /obj/machinery/media/jukebox
wire_count = 11
+ proper_name = "Jukebox"
-var/const/WIRE_POWER = 1
-var/const/WIRE_HACK = 2
-var/const/WIRE_SPEEDUP = 4
-var/const/WIRE_SPEEDDOWN = 8
-var/const/WIRE_REVERSE = 16
-var/const/WIRE_NOTHING1 = 32
-var/const/WIRE_NOTHING2 = 64
-var/const/WIRE_START = 128
-var/const/WIRE_STOP = 256
-var/const/WIRE_PREV = 512
-var/const/WIRE_NEXT = 1024
+/datum/wires/jukebox/New(atom/_holder)
+ wires = list(
+ WIRE_MAIN_POWER1, WIRE_JUKEBOX_HACK,
+ WIRE_SPEEDUP, WIRE_SPEEDDOWN, WIRE_REVERSE,
+ WIRE_START, WIRE_STOP, WIRE_PREV, WIRE_NEXT
+ )
+ return ..()
-/datum/wires/jukebox/CanUse(var/mob/living/L)
+/datum/wires/jukebox/interactable(mob/user)
var/obj/machinery/media/jukebox/A = holder
if(A.panel_open)
- return 1
- return 0
+ return TRUE
+ return FALSE
// Show the status of lights as a hint to the current state
-/datum/wires/jukebox/GetInteractWindow()
+/datum/wires/jukebox/get_status()
var/obj/machinery/media/jukebox/A = holder
- . += ..()
- . += "
The power light is [(A.stat & (BROKEN|NOPOWER)) ? "off" : "on"].
"
- . += "The parental guidance light is [A.hacked ? "off" : "on"].
"
- . += "The data light is [IsIndexCut(WIRE_REVERSE) ? "hauntingly dark" : "glowing sloftly"].
"
+ . = ..()
+ . += "The power light is [A.stat & (BROKEN|NOPOWER) ? "off." : "on."]"
+ . += "The parental guidance light is [A.hacked ? "off." : "on."]"
+ . += "The data light is [is_cut(WIRE_REVERSE) ? "hauntingly dark." : "glowing softly."]"
// Give a hint as to what each wire does
-/datum/wires/jukebox/UpdatePulsed(var/index)
+/datum/wires/jukebox/on_pulse(wire)
var/obj/machinery/media/jukebox/A = holder
- switch(index)
- if(WIRE_POWER)
+ switch(wire)
+ if(WIRE_MAIN_POWER1)
holder.visible_message("[icon2html(thing = holder, target = world)] The power light flickers.")
A.shock(usr, 90)
- if(WIRE_HACK)
+ if(WIRE_JUKEBOX_HACK)
holder.visible_message("[icon2html(thing = holder, target = world)] The parental guidance light flickers.")
if(WIRE_REVERSE)
holder.visible_message("[icon2html(thing = holder, target = world)] The data light blinks ominously.")
@@ -55,24 +52,21 @@ var/const/WIRE_NEXT = 1024
else
A.shock(usr, 10) // The nothing wires give a chance to shock just for fun
-/datum/wires/jukebox/UpdateCut(var/index, var/mended)
+/datum/wires/jukebox/on_cut(wire, mend)
var/obj/machinery/media/jukebox/A = holder
- switch(index)
- if(WIRE_POWER)
+ switch(wire)
+ if(WIRE_MAIN_POWER1)
// TODO - Actually make machine electrified or something.
A.shock(usr, 90)
- if(WIRE_HACK)
- if(mended)
- A.set_hacked(0)
- else
- A.set_hacked(1)
+ if(WIRE_JUKEBOX_HACK)
+ A.set_hacked(!mend)
if(WIRE_SPEEDUP, WIRE_SPEEDDOWN, WIRE_REVERSE)
- var/newfreq = IsIndexCut(WIRE_REVERSE) ? -1 : 1;
- if (IsIndexCut(WIRE_SPEEDUP))
+ var/newfreq = is_cut(WIRE_REVERSE) ? -1 : 1;
+ if(is_cut(WIRE_SPEEDUP))
newfreq *= 2
- if (IsIndexCut(WIRE_SPEEDDOWN))
+ if(is_cut(WIRE_SPEEDDOWN))
newfreq *= 0.5
A.freq = newfreq
diff --git a/code/datums/wires/mines.dm b/code/datums/wires/mines.dm
index efc67292752..0bc1fbbb1cf 100644
--- a/code/datums/wires/mines.dm
+++ b/code/datums/wires/mines.dm
@@ -1,32 +1,29 @@
/datum/wires/mines
+ randomize = TRUE
wire_count = 6
- random = 1
holder_type = /obj/effect/mine
+ proper_name = "Explosive Wires"
-#define WIRE_DETONATE 1
-#define WIRE_TIMED_DET 2
-#define WIRE_DISARM 4
-#define WIRE_DUMMY_1 8
-#define WIRE_DUMMY_2 16
-#define WIRE_BADDISARM 32
+/datum/wires/mines/New(atom/_holder)
+ wires = list(WIRE_EXPLODE, WIRE_EXPLODE_DELAY, WIRE_DISARM, WIRE_BADDISARM)
+ return ..()
-/datum/wires/mines/GetInteractWindow()
+/datum/wires/mines/get_status()
. = ..()
- . += "
\n["Warning: detonation may occur even with proper equipment."]"
- return .
+ . += "\[Warning: detonation may occur even with proper equipment.]"
/datum/wires/mines/proc/explode()
return
-/datum/wires/mines/UpdateCut(var/index, var/mended)
+/datum/wires/mines/on_cut(wire, mend)
var/obj/effect/mine/C = holder
- switch(index)
- if(WIRE_DETONATE)
+ switch(wire)
+ if(WIRE_EXPLODE)
C.visible_message("[icon2html(thing = C, target = world)] *BEEE-*", "[icon2html(thing = C, target = world)] *BEEE-*")
C.explode()
- if(WIRE_TIMED_DET)
+ if(WIRE_EXPLODE_DELAY)
C.visible_message("[icon2html(thing = C, target = world)] *BEEE-*", "[icon2html(thing = C, target = world)] *BEEE-*")
C.explode()
@@ -35,30 +32,22 @@
new C.mineitemtype(get_turf(C))
spawn(0)
qdel(C)
- return
-
- if(WIRE_DUMMY_1)
- return
-
-
- if(WIRE_DUMMY_2)
- return
if(WIRE_BADDISARM)
C.visible_message("[icon2html(thing = C, target = world)] *BEEPBEEPBEEP*", "[icon2html(thing = C, target = world)] *BEEPBEEPBEEP*")
spawn(20)
C.explode()
- return
+ ..()
-/datum/wires/mines/UpdatePulsed(var/index)
+/datum/wires/mines/on_pulse(wire)
var/obj/effect/mine/C = holder
- if(IsIndexCut(index))
+ if(is_cut(wire))
return
- switch(index)
- if(WIRE_DETONATE)
+ switch(wire)
+ if(WIRE_EXPLODE)
C.visible_message("[icon2html(thing = C, target = world)] *beep*", "[icon2html(thing = C, target = world)] *beep*")
- if(WIRE_TIMED_DET)
+ if(WIRE_EXPLODE_DELAY)
C.visible_message("[icon2html(thing = C, target = world)] *BEEPBEEPBEEP*", "[icon2html(thing = C, target = world)] *BEEPBEEPBEEP*")
spawn(20)
C.explode()
@@ -66,16 +55,10 @@
if(WIRE_DISARM)
C.visible_message("[icon2html(thing = C, target = world)] *ping*", "[icon2html(thing = C, target = world)] *ping*")
- if(WIRE_DUMMY_1)
- C.visible_message("[icon2html(thing = C, target = world)] *ping*", "[icon2html(thing = C, target = world)] *ping*")
-
- if(WIRE_DUMMY_2)
- C.visible_message("[icon2html(thing = C, target = world)] *beep*", "[icon2html(thing = C, target = world)] *beep*")
-
if(WIRE_BADDISARM)
C.visible_message("[icon2html(thing = C, target = world)] *ping*", "[icon2html(thing = C, target = world)] *ping*")
- return
+ ..()
-/datum/wires/mines/CanUse(var/mob/living/L)
+/datum/wires/mines/interactable(mob/user)
var/obj/effect/mine/M = holder
return M.panel_open
diff --git a/code/datums/wires/particle_accelerator.dm b/code/datums/wires/particle_accelerator.dm
index 15ff67b7a49..e71da1a79ca 100644
--- a/code/datums/wires/particle_accelerator.dm
+++ b/code/datums/wires/particle_accelerator.dm
@@ -1,52 +1,48 @@
/datum/wires/particle_acc/control_box
wire_count = 5
holder_type = /obj/machinery/particle_accelerator/control_box
+ proper_name = "Particle accelerator control"
-var/const/PARTICLE_TOGGLE_WIRE = 1 // Toggles whether the PA is on or not.
-var/const/PARTICLE_STRENGTH_WIRE = 2 // Determines the strength of the PA.
-var/const/PARTICLE_INTERFACE_WIRE = 4 // Determines the interface showing up.
-var/const/PARTICLE_LIMIT_POWER_WIRE = 8 // Determines how strong the PA can be.
-//var/const/PARTICLE_NOTHING_WIRE = 16 // Blank wire
+/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/CanUse(var/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(var/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("[icon2html(thing = C, target = world)][C] makes a large whirring noise.")
-/datum/wires/particle_acc/control_box/UpdateCut(var/index, var/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)
-
+ if(WIRE_PARTICLE_STRENGTH)
for(var/i = 1; i < 3; i++)
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 b86897a93ee..892058c612d 100644
--- a/code/datums/wires/radio.dm
+++ b/code/datums/wires/radio.dm
@@ -1,41 +1,42 @@
/datum/wires/radio
- holder_type = /obj/item/radio
wire_count = 3
+ holder_type = /obj/item/radio
+ proper_name = "Radio"
-var/const/WIRE_SIGNAL = 1
-var/const/WIRE_RECEIVE = 2
-var/const/WIRE_TRANSMIT = 4
+/datum/wires/radio/New(atom/_holder)
+ wires = list(WIRE_RADIO_SIGNAL, WIRE_RADIO_RECEIVER, WIRE_RADIO_TRANSMIT)
+ return ..()
-/datum/wires/radio/CanUse(var/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(var/index)
+/datum/wires/radio/on_pulse(wire)
var/obj/item/radio/R = holder
- switch(index)
- if(WIRE_SIGNAL)
- R.listening = !R.listening && !IsIndexCut(WIRE_RECEIVE)
- R.broadcasting = R.listening && !IsIndexCut(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(WIRE_RECEIVE)
- R.listening = !R.listening && !IsIndexCut(WIRE_SIGNAL)
+ if(WIRE_RADIO_RECEIVER)
+ R.listening = !R.listening && !is_cut(WIRE_RADIO_SIGNAL)
- if(WIRE_TRANSMIT)
- R.broadcasting = !R.broadcasting && !IsIndexCut(WIRE_SIGNAL)
- SSnanoui.update_uis(holder)
+ if(WIRE_RADIO_TRANSMIT)
+ R.broadcasting = !R.broadcasting && !is_cut(WIRE_RADIO_SIGNAL)
+ ..()
-/datum/wires/radio/UpdateCut(var/index, var/mended)
+/datum/wires/radio/on_cut(wire, mend)
var/obj/item/radio/R = holder
- switch(index)
- if(WIRE_SIGNAL)
- R.listening = mended && !IsIndexCut(WIRE_RECEIVE)
- R.broadcasting = mended && !IsIndexCut(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(WIRE_RECEIVE)
- R.listening = mended && !IsIndexCut(WIRE_SIGNAL)
+ if(WIRE_RADIO_RECEIVER)
+ R.listening = mend && !is_cut(WIRE_RADIO_SIGNAL)
- if(WIRE_TRANSMIT)
- R.broadcasting = mended && !IsIndexCut(WIRE_SIGNAL)
- SSnanoui.update_uis(holder)
+ 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 9d2fce9ac38..85ac73a4afe 100644
--- a/code/datums/wires/robot.dm
+++ b/code/datums/wires/robot.dm
@@ -1,77 +1,63 @@
/datum/wires/robot
- random = 1
- holder_type = /mob/living/silicon/robot
+ randomize = TRUE
wire_count = 5
+ holder_type = /mob/living/silicon/robot
+ proper_name = "Cyborg"
-var/const/BORG_WIRE_LAWCHECK = 1
-var/const/BORG_WIRE_MAIN_POWER = 2 // The power wires do nothing whyyyyyyyyyyyyy
-var/const/BORG_WIRE_LOCKED_DOWN = 4
-var/const/BORG_WIRE_AI_CONTROL = 8
-var/const/BORG_WIRE_CAMERA = 16
-
-/datum/wires/robot/GetInteractWindow()
+/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()
. = ..()
var/mob/living/silicon/robot/R = holder
- . += text("
\n[(R.lawupdate ? "The LawSync light is on." : "The LawSync light is off.")]")
- . += text("
\n[(R.connected_ai ? "The AI link light is on." : "The AI link light is off.")]")
- . += text("
\n[((!isnull(R.camera) && R.camera.status == 1) ? "The Camera light is on." : "The Camera light is off.")]")
- . += text("
\n[(R.lockdown ? "The lockdown light is on." : "The lockdown light is off.")]")
- return .
-
-/datum/wires/robot/UpdateCut(var/index, var/mended)
+ . += "The LawSync light is [R.lawupdate ? "on" : "off"]."
+ . += "The AI link light is [R.connected_ai ? "on" : "off"]."
+ . += "The Camera light is [(R.camera && R.camera.status == 1) ? "on" : "off"]."
+ . += "The lockdown light is [R.lockcharge ? "on" : "off"]."
+/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)
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
- 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(WIRE_BORG_LOCKED)
+ R.SetLockdown(!mend)
+ ..()
- if(BORG_WIRE_LOCKED_DOWN)
- R.SetLockdown(!mended)
-
-
-/datum/wires/robot/UpdatePulsed(var/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)
- var/mob/living/silicon/ai/new_ai = select_active_ai(R)
- R.connect_to_ai(new_ai)
+ R.connect_to_ai(select_active_ai(R))
- if (BORG_WIRE_CAMERA)
+ if(WIRE_BORG_CAMERA)
if(!isnull(R.camera) && R.camera.can_use() && !R.scrambledcodes)
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.lockdown) // Toggle
-/datum/wires/robot/CanUse(var/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
+ return TRUE
+ return FALSE
diff --git a/code/datums/wires/seedstorage.dm b/code/datums/wires/seedstorage.dm
index 8268d936b04..890cccfc2fa 100644
--- a/code/datums/wires/seedstorage.dm
+++ b/code/datums/wires/seedstorage.dm
@@ -1,56 +1,58 @@
-#define SEED_WIRE_SMART 1
-#define SEED_WIRE_CONTRABAND 2
-#define SEED_WIRE_ELECTRIFY 4
-#define SEED_WIRE_LOCKDOWN 8
-
/datum/wires/seedstorage
- holder_type = /obj/machinery/seed_storage
+ randomize = TRUE
wire_count = 4
- random = 1
+ holder_type = /obj/machinery/seed_storage
+ proper_name = "Seed Storage"
-/datum/wires/seedstorage/CanUse(var/mob/living/L)
+/datum/wires/seedstorage/New(atom/_holder)
+ wires = list(WIRE_SEED_SMART, WIRE_CONTRABAND, WIRE_ELECTRIFY, WIRE_SEED_LOCKDOWN)
+ return ..()
+
+/datum/wires/seedstorage/interactable(mob/user)
var/obj/machinery/seed_storage/V = holder
if(V.panel_open)
- return 1
- return 0
+ return TRUE
+ return FALSE
-/datum/wires/seedstorage/GetInteractWindow()
+/datum/wires/seedstorage/get_status()
var/obj/machinery/seed_storage/V = holder
- . += ..()
- . += "
The orange light is [V.seconds_electrified ? "off" : "on"].
"
- . += "The red light is [V.smart ? "off" : "blinking"].
"
- . += "The green light is [(V.hacked || V.emagged) ? "on" : "off"].
"
- . += "The keypad lock is [V.lockdown ? "deployed" : "retracted"].
"
+ . = ..()
+ . += "The orange light is [V.seconds_electrified ? "off." : "on."]"
+ . += "The red light is [V.smart ? "off." : "blinking."]"
+ . += "The green light is [(V.hacked || V.emagged) ? "on." : "off."]"
+ . += "The keypad lock light is [V.lockdown ? "deployed." : "retracted."]"
-/datum/wires/seedstorage/UpdatePulsed(var/index)
+/datum/wires/seedstorage/on_pulse(wire)
var/obj/machinery/seed_storage/V = holder
- switch(index)
- if(SEED_WIRE_SMART)
+ switch(wire)
+ if(WIRE_SEED_SMART)
V.smart = !V.smart
- if(SEED_WIRE_CONTRABAND)
+ if(WIRE_CONTRABAND)
V.hacked = !V.hacked
- if(SEED_WIRE_ELECTRIFY)
+ if(WIRE_ELECTRIFY)
V.seconds_electrified = 30
- if(SEED_WIRE_LOCKDOWN)
+ if(WIRE_SEED_LOCKDOWN)
V.lockdown = !V.lockdown
+ ..()
-/datum/wires/seedstorage/UpdateCut(var/index, var/mended)
+/datum/wires/seedstorage/on_cut(wire, mend)
var/obj/machinery/seed_storage/V = holder
- switch(index)
- if(SEED_WIRE_SMART)
- V.smart = 0
- if(SEED_WIRE_CONTRABAND)
- V.hacked = !mended
- if(SEED_WIRE_ELECTRIFY)
- if(mended)
+ switch(wire)
+ if(WIRE_SEED_SMART)
+ V.smart = FALSE
+ if(WIRE_CONTRABAND)
+ V.hacked = !mend
+ if(WIRE_ELECTRIFY)
+ if(mend)
V.seconds_electrified = 0
else
V.seconds_electrified = -1
- if(SEED_WIRE_LOCKDOWN)
- if(mended)
- V.lockdown = 1
+ if(WIRE_SEED_LOCKDOWN)
+ if(mend)
+ V.lockdown = TRUE
V.req_access = list()
V.req_one_access = list()
else
V.req_access = initial(V.req_access)
V.req_one_access = initial(V.req_one_access)
+ ..()
diff --git a/code/datums/wires/shield_generator.dm b/code/datums/wires/shield_generator.dm
new file mode 100644
index 00000000000..82f083ecfe1
--- /dev/null
+++ b/code/datums/wires/shield_generator.dm
@@ -0,0 +1,47 @@
+/datum/wires/shield_generator
+ wire_count = 5
+ holder_type = /obj/machinery/power/shield_generator
+ proper_name = "Shield Generator"
+
+/datum/wires/shield_generator/New(atom/_holder)
+ wires = list(WIRE_MAIN_POWER1, WIRE_CONTRABAND, WIRE_AI_CONTROL, WIRE_SHIELD_CONTROL)
+ return ..()
+
+/datum/wires/shield_generator/interactable(mob/user)
+ var/obj/machinery/power/shield_generator/S = holder
+ if(S.panel_open)
+ return TRUE
+ return FALSE
+
+/datum/wires/shield_generator/get_status()
+ var/obj/machinery/power/shield_generator/S = holder
+ . = ..()
+ . += "The orange light is [S.mode_changes_locked ? "on." : "off."]"
+ . += "The blue light is [S.ai_control_disabled ? "off." : "blinking."]"
+ . += "The violet light is [S.hacked ? "pulsing." : "steady."]"
+ . += "The red light is [S.input_cut ? "off." : "on."]"
+
+/datum/wires/shield_generator/on_cut(wire, mend)
+ var/obj/machinery/power/shield_generator/S = holder
+ switch(wire)
+ if(WIRE_MAIN_POWER1)
+ S.input_cut = !mend
+ if(WIRE_CONTRABAND)
+ if(!mend)
+ S.hacked = FALSE
+ if(S.check_flag(MODEFLAG_BYPASS))
+ S.toggle_flag(MODEFLAG_BYPASS)
+ if(S.check_flag(MODEFLAG_OVERCHARGE))
+ S.toggle_flag(MODEFLAG_OVERCHARGE)
+ if(WIRE_SHIELD_CONTROL)
+ S.mode_changes_locked = !mend
+ if(WIRE_AI_CONTROL)
+ S.ai_control_disabled = !mend
+ ..()
+
+/datum/wires/shield_generator/on_pulse(wire)
+ var/obj/machinery/power/shield_generator/S = holder
+ switch(wire)
+ if(WIRE_CONTRABAND)
+ S.hacked = TRUE
+ ..()
diff --git a/code/datums/wires/smartfridge.dm b/code/datums/wires/smartfridge.dm
index 15f10cd8005..1b5ce38777a 100644
--- a/code/datums/wires/smartfridge.dm
+++ b/code/datums/wires/smartfridge.dm
@@ -1,47 +1,52 @@
/datum/wires/smartfridge
- holder_type = /obj/machinery/smartfridge
wire_count = 3
+ holder_type = /obj/machinery/smartfridge
+ proper_name = "Smartfridge"
+
+/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.
-var/const/SMARTFRIDGE_WIRE_ELECTRIFY = 1
-var/const/SMARTFRIDGE_WIRE_THROW = 2
-var/const/SMARTFRIDGE_WIRE_IDSCAN = 4
-
-/datum/wires/smartfridge/CanUse(var/mob/living/L)
+/datum/wires/smartfridge/interactable(mob/user)
var/obj/machinery/smartfridge/S = holder
+ 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/GetInteractWindow()
+/datum/wires/smartfridge/get_status()
+ . = ..()
var/obj/machinery/smartfridge/S = holder
- . += ..()
- . += "
The orange light is [S.seconds_electrified ? "off" : "on"].
"
- . += "The red light is [S.shoot_inventory ? "off" : "blinking"].
"
- . += "A [S.scan_id ? "purple" : "yellow"] light is on.
"
+ . += "The orange light is [S.seconds_electrified ? "off" : "on"]."
+ . += "The red light is [S.shoot_inventory ? "off" : "blinking"]."
+ . += "A [S.scan_id ? "purple" : "yellow"] light is on."
-/datum/wires/smartfridge/UpdatePulsed(var/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(var/index, var/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/smes.dm b/code/datums/wires/smes.dm
index 4ac0fd51ece..ab7677dcc29 100644
--- a/code/datums/wires/smes.dm
+++ b/code/datums/wires/smes.dm
@@ -1,60 +1,57 @@
/datum/wires/smes
- holder_type = /obj/machinery/power/smes/buildable
wire_count = 5
+ holder_type = /obj/machinery/power/smes/buildable
+ proper_name = "SMES"
-var/const/SMES_WIRE_RCON = 1 // Remote control (AI and consoles), cut to disable
-var/const/SMES_WIRE_INPUT = 2 // Input wire, cut to disable input, pulse to disable for 60s
-var/const/SMES_WIRE_OUTPUT = 4 // Output wire, cut to disable output, pulse to disable for 60s
-var/const/SMES_WIRE_GROUNDING = 8 // Cut to quickly discharge causing sparks, pulse to only create few sparks
-var/const/SMES_WIRE_FAILSAFES = 16 // Cut to disable failsafes, mend to reenable
+/datum/wires/smes/New(atom/_holder)
+ wires = list(WIRE_SMES_RCON, WIRE_SMES_INPUT, WIRE_SMES_OUTPUT, WIRE_SMES_GROUNDING, WIRE_SMES_FAILSAFES)
+ return ..()
-
-/datum/wires/smes/CanUse(var/mob/living/L)
+/datum/wires/smes/interactable(mob/user)
var/obj/machinery/power/smes/buildable/S = holder
if(S.open_hatch)
- return 1
- return 0
+ return TRUE
+ return FALSE
-
-/datum/wires/smes/GetInteractWindow()
+/datum/wires/smes/get_status()
var/obj/machinery/power/smes/buildable/S = holder
- . += ..()
- . += "The green light is [(S.input_cut || S.input_pulsed || S.output_cut || S.output_pulsed) ? "off" : "on"]
"
- . += "The red light is [(S.safeties_enabled || S.grounding) ? "off" : "blinking"]
"
- . += "The blue light is [S.RCon ? "on" : "off"]"
+ . = ..()
+ . += "The green light is [(S.input_cut || S.input_pulsed || S.output_cut || S.output_pulsed) ? "off" : "on"]."
+ . += "The red light is [(S.safeties_enabled || S.grounding) ? "off" : "blinking"]."
+ . += "The blue light is [S.RCon ? "on" : "off"]."
-
-/datum/wires/smes/UpdateCut(var/index, var/mended)
+/datum/wires/smes/on_cut(wire, mend)
var/obj/machinery/power/smes/buildable/S = holder
- switch(index)
- if(SMES_WIRE_RCON)
- S.RCon = mended
- if(SMES_WIRE_INPUT)
- S.input_cut = !mended
- if(SMES_WIRE_OUTPUT)
- S.output_cut = !mended
- if(SMES_WIRE_GROUNDING)
- S.grounding = mended
- if(SMES_WIRE_FAILSAFES)
- S.safeties_enabled = mended
+ switch(wire)
+ if(WIRE_SMES_RCON)
+ S.RCon = mend
+ if(WIRE_SMES_INPUT)
+ S.input_cut = !mend
+ if(WIRE_SMES_OUTPUT)
+ S.output_cut = !mend
+ if(WIRE_SMES_GROUNDING)
+ S.grounding = mend
+ if(WIRE_SMES_FAILSAFES)
+ S.safeties_enabled = mend
+ ..()
-
-/datum/wires/smes/UpdatePulsed(var/index)
+/datum/wires/smes/on_pulse(wire)
var/obj/machinery/power/smes/buildable/S = holder
- switch(index)
- if(SMES_WIRE_RCON)
+ switch(wire)
+ if(WIRE_SMES_RCON)
if(S.RCon)
S.RCon = 0
spawn(10)
S.RCon = 1
- if(SMES_WIRE_INPUT)
+ if(WIRE_SMES_INPUT)
S.toggle_input()
- if(SMES_WIRE_OUTPUT)
+ if(WIRE_SMES_OUTPUT)
S.toggle_output()
- if(SMES_WIRE_GROUNDING)
+ if(WIRE_SMES_GROUNDING)
S.grounding = 0
- if(SMES_WIRE_FAILSAFES)
+ if(WIRE_SMES_FAILSAFES)
if(S.safeties_enabled)
S.safeties_enabled = 0
spawn(10)
S.safeties_enabled = 1
+ ..()
diff --git a/code/datums/wires/suit_storage_unit.dm b/code/datums/wires/suit_storage_unit.dm
index c2d1a130d79..97d3f98c841 100644
--- a/code/datums/wires/suit_storage_unit.dm
+++ b/code/datums/wires/suit_storage_unit.dm
@@ -1,47 +1,46 @@
/datum/wires/suit_storage_unit
holder_type = /obj/machinery/suit_cycler
wire_count = 3
+ proper_name = "Suit storage unit"
-var/const/SUIT_STORAGE_WIRE_ELECTRIFY = 1
-var/const/SUIT_STORAGE_WIRE_SAFETY = 2
-var/const/SUIT_STORAGE_WIRE_LOCKED = 4
+/datum/wires/suit_storage_unit/New(atom/_holder)
+ wires = list(WIRE_IDSCAN, WIRE_ELECTRIFY, WIRE_SAFETY)
+ return ..()
-/datum/wires/suit_storage_unit/CanUse(var/mob/living/L)
+/datum/wires/suit_storage_unit/interactable(mob/user)
var/obj/machinery/suit_cycler/S = holder
- if(!istype(L, /mob/living/silicon))
- if(S.electrified)
- if(S.shock(L, 100))
- return 0
+ if(iscarbon(user) && S.Adjacent(user) && S.electrified)
+ return !S.shock(user, 100)
if(S.panel_open)
- return 1
- return 0
+ return TRUE
+ return FALSE
-/datum/wires/suit_storage_unit/GetInteractWindow()
- var/obj/machinery/suit_cycler/S = holder
- . += ..()
- . += "
The orange light is [S.electrified ? "off" : "on"].
"
- . += "The red light is [S.safeties ? "off" : "blinking"].
"
- . += "The yellow light is [S.locked ? "on" : "off"].
"
+/datum/wires/suit_storage_unit/get_status()
+ . = ..()
+ var/obj/machinery/suit_cycler/A = holder
+ . += "The orange light is [A.electrified ? "off" : "on"]."
+ . += "The red light is [A.safeties ? "off" : "blinking"]."
+ . += "The yellow light is [A.locked ? "on" : "off"]."
-/datum/wires/suit_storage_unit/UpdatePulsed(var/index)
+/datum/wires/suit_storage_unit/on_pulse(wire)
var/obj/machinery/suit_cycler/S = holder
- switch(index)
- if(SUIT_STORAGE_WIRE_SAFETY)
+ switch(wire)
+ if(WIRE_SAFETY)
S.safeties = !S.safeties
- if(SUIT_STORAGE_WIRE_ELECTRIFY)
+ if(WIRE_ELECTRIFY)
S.electrified = 30
- if(SUIT_STORAGE_WIRE_LOCKED)
+ if(WIRE_IDSCAN)
S.locked = !S.locked
-/datum/wires/suit_storage_unit/UpdateCut(var/index, var/mended)
+/datum/wires/suit_storage_unit/on_cut(wire, mend)
var/obj/machinery/suit_cycler/S = holder
- switch(index)
- if(SUIT_STORAGE_WIRE_SAFETY)
- S.safeties = mended
- if(SUIT_STORAGE_WIRE_LOCKED)
- S.locked = mended
- if(SUIT_STORAGE_WIRE_ELECTRIFY)
- if(mended)
+ switch(wire)
+ if(WIRE_SAFETY)
+ S.safeties = mend
+ if(WIRE_IDSCAN)
+ S.locked = mend
+ if(WIRE_ELECTRIFY)
+ if(mend)
S.electrified = 0
else
S.electrified = -1
diff --git a/code/datums/wires/tesla_coil.dm b/code/datums/wires/tesla_coil.dm
index f176b8f1397..f2292f8ce88 100644
--- a/code/datums/wires/tesla_coil.dm
+++ b/code/datums/wires/tesla_coil.dm
@@ -1,18 +1,21 @@
/datum/wires/tesla_coil
- wire_count = 1
holder_type = /obj/machinery/power/tesla_coil
+ wire_count = 1
+ proper_name = "Tesla coil"
-var/const/WIRE_ZAP = 1
+/datum/wires/tesla_coil/New(atom/_holder)
+ wires = list(WIRE_TESLACOIL_ZAP)
+ return ..()
-/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(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 bad3a0078b4..4667080bf1c 100644
--- a/code/datums/wires/vending.dm
+++ b/code/datums/wires/vending.dm
@@ -1,49 +1,53 @@
/datum/wires/vending
holder_type = /obj/machinery/vending
wire_count = 4
+ proper_name = "Vending machine"
-var/const/VENDING_WIRE_THROW = 1
-var/const/VENDING_WIRE_CONTRABAND = 2
-var/const/VENDING_WIRE_ELECTRIFY = 4
-var/const/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/CanUse(var/mob/living/L)
+/datum/wires/vending/interactable(mob/user)
var/obj/machinery/vending/V = holder
+ if(iscarbon(user) && V.seconds_electrified && V.shock(user, 100))
+ return FALSE
if(V.panel_open)
- return 1
- return 0
+ return TRUE
+ return FALSE
-/datum/wires/vending/GetInteractWindow()
+/datum/wires/vending/get_status()
var/obj/machinery/vending/V = holder
- . += ..()
- . += "
The orange light is [V.seconds_electrified ? "off" : "on"].
"
- . += "The red light is [V.shoot_inventory ? "off" : "blinking"].
"
- . += "The green light is [(V.categories & CAT_HIDDEN) ? "on" : "off"].
"
- . += "The [V.scan_id ? "purple" : "yellow"] light is on.
"
+ . = ..()
+ . += "The orange light is [V.seconds_electrified ? "on" : "off"]."
+ . += "The red light is [V.shoot_inventory ? "off" : "blinking"]."
+ . += "The green light is [(V.categories & CAT_HIDDEN) ? "on" : "off"]."
+ . += "A [V.scan_id ? "purple" : "yellow"] light is on."
-/datum/wires/vending/UpdatePulsed(var/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.categories ^= CAT_HIDDEN
- 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(var/index, var/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.categories &= ~CAT_HIDDEN
- if(VENDING_WIRE_ELECTRIFY)
- if(mended)
+ if(WIRE_ELECTRIFY)
+ if(mend)
V.seconds_electrified = 0
else
V.seconds_electrified = -1
- if(VENDING_WIRE_IDSCAN)
+ if(WIRE_IDSCAN)
V.scan_id = 1
+ ..()
diff --git a/code/datums/wires/wires.dm b/code/datums/wires/wires.dm
index 964ec98448a..12cef9d2a70 100644
--- a/code/datums/wires/wires.dm
+++ b/code/datums/wires/wires.dm
@@ -1,220 +1,461 @@
-// 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
-
-var/list/same_wires = list()
-// 14 colours, if you're adding more than 14 wires then add more colours here
-var/list/wireColours = list("red", "blue", "green", "darkred", "orange", "brown", "gold", "gray", "cyan", "navy", "purple", "pink", "black", "yellow")
-
/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
- 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(var/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()
+
+ 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(!same_wires[holder_type])
- GenerateWires()
- same_wires[holder_type] = src.wires.Copy()
- else
- var/list/wires = same_wires[holder_type]
- src.wires = wires // Reference the wires list.
+ colors = GLOB.wire_color_directory[holder_type]
/datum/wires/Destroy()
holder = null
- signallers.Cut()
+ for(var/color in colors)
+ detach_assembly(color)
return ..()
-/datum/wires/proc/GenerateWires()
- var/list/colours_to_pick = 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", "darkmagenta", "orange", "brown", "gold", "grey", "cyan", "white", "purple", "pink", "darkslategrey", "yellow")
+ 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)
+ for(var/wire in shuffle(wires))
+ colors[pick_n_take(my_possible_colors)] = wire
- // Pick and remove an index
- var/index = pick_n_take(indexes_to_pick)
+/**
+ * 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 && interactable(user))
+ ui_interact(user)
- src.wires[colour] = index
- //wires = shuffle(wires)
+/**
+ * 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/ui_host()
+ return holder
-/datum/wires/proc/Interact(var/mob/living/user)
+/datum/wires/ui_interact(mob/user, datum/tgui/ui = null)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "Wires", "[proper_name] wires")
+ ui.open()
- var/html = null
- if(holder && CanUse(user))
- html = GetInteractWindow()
- if(html)
- user.set_machine(holder)
+/datum/wires/ui_state(mob/user)
+ return GLOB.physical_state
+
+/datum/wires/ui_data(mob/user)
+ var/list/data = list()
+ var/list/replace_colors
+
+ if(isliving(user))
+ var/mob/living/L = user
+ for(var/datum/modifier/M in L.modifiers)
+ if(!isnull(M.wire_colors_replace))
+ replace_colors = M.wire_colors_replace
+ break
+
+ var/list/wires_list = list()
+
+ 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
+ color_name = replaced_color // Else just keep the normal color name
+
+ if(color in LIST_COLOR_RENAME)
+ color_name = LIST_COLOR_RENAME[color]
+
+ 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_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/ui_act(action, list/params)
+ if(..())
+ return
+
+ 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(!I.is_wirecutter() && !user.can_admin_interact())
+ if(!istype(I) || !I.is_wirecutter())
+ to_chat(user, "You need wirecutters!")
+ return
+
+ playsound(holder, I.usesound, 20, 1)
+ cut_color(color)
+ return TRUE
+
+ // Pulse a wire.
+ if("pulse")
+ // if(!I.is_multitool() && !user.can_admin_interact())
+ if(!istype(I) || !I.is_multitool())
+ 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.unEquip(I))
+ attach_assembly(color, I)
+ return TRUE
+ else
+ to_chat(user, "[I] 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)
+ // TODO: Reimplement this if we ever get Advanced Admin Interaction.
+ // if(user.can_admin_interact())
+ // return TRUE
+ var/obj/item/I = user.get_active_hand()
+ if(istype(I, /obj/item/multitool/alien))
+ return TRUE
+ return FALSE
+
+/**
+ * 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()
+
+/**
+ * Clears the `colors` list, and randomizes it to a new set of color-to-wire relations.
+ */
+/datum/wires/proc/shuffle_wires()
+ colors.Cut()
+ randomize()
+
+/**
+ * Repairs all cut wires.
+ */
+/datum/wires/proc/repair()
+ cut_wires.Cut()
+
+/**
+ * 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
+
+/**
+ * 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)
+
+/**
+ * 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))
+
+/**
+ * Gets the wire associated with the color passed in.
+ *
+ * Arugments:
+ * * color - a wire color.
+ */
+/datum/wires/proc/get_wire(color)
+ return colors[color]
+
+/**
+ * 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)
+
+/**
+ * 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))
+
+/**
+ * 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))
+
+/**
+ * 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
- user.unset_machine()
- // No content means no window.
- user << browse(null, "window=wires")
- return
+ cut_wires += wire
+ on_cut(wire, mend = FALSE)
- var/datum/browser/popup = new(user, "wires", holder.name, window_x, window_y)
- popup.set_content(html)
- popup.open()
+/**
+ * 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))
-/datum/wires/proc/GetInteractWindow()
- var/html = "Rename" //kicking off the html with this set of buttons that will affect any object with the wires interface
- html += "Describe"
- html += "
"
- html += "
Exposed Wires
"
- html += "
"
- html += "
"
+/**
+ * Cuts a random wire.
+ */
+/datum/wires/proc/cut_random()
+ cut(wires[rand(1, length(wires))])
- if (random)
- html += "\The [holder] appears to have tamper-resistant electronics installed.
" //maybe this could be more generic?
+/**
+ * Cuts all wires.
+ */
+/datum/wires/proc/cut_all()
+ for(var/wire in wires)
+ cut(wire)
- return html
-
-/datum/wires/Topic(href, href_list)
- ..()
- if(in_range(holder, usr) && isliving(usr))
-
- var/mob/living/L = usr
- if(CanUse(L) && href_list["action"])
- var/obj/item/I = L.get_active_hand()
- holder.add_hiddenprint(L)
- if(href_list["cut"]) // Toggles the cut/mend status
- if(I.is_wirecutter())
- var/colour = href_list["cut"]
- CutWireColour(colour)
- playsound(holder, I.usesound, 20, 1)
- else
- to_chat(L, "You need wirecutters!")
-
- else if(href_list["pulse"])
- if(I.is_multitool())
- var/colour = href_list["pulse"]
- PulseColour(colour)
- playsound(holder, 'sound/weapons/empty.ogg', 20, 1)
- else
- to_chat(L, "You need a multitool!")
-
- else if(href_list["attach"])
- var/colour = href_list["attach"]
- // Detach
- if(IsAttached(colour))
- var/obj/item/O = Detach(colour)
- if(O)
- L.put_in_hands(O)
-
- // Attach
- else
- if(istype(I, /obj/item/assembly/signaler))
- L.drop_item()
- Attach(colour, I)
- else
- to_chat(L, "You need a remote signaller!")
-
- else if(href_list["rename"]) //add the ability to rename doors via multitool
- if(I.is_multitool())
- RenameDoor(src)
- else
- to_chat(L, "You need a multitool!")
-
- else if(href_list["description"]) // and describe them!
- if(I.is_multitool())
- DescribeDoor(src)
- else
- to_chat(L, "You need a multitool!")
-
-
- // Update Window
- Interact(usr)
-
- if(href_list["close"])
- usr << browse(null, "window=wires")
- usr.unset_machine(holder)
-
-//
-// Overridable Procs
-//
-
-// Called when wires cut/mended.
-/datum/wires/proc/UpdateCut(var/index, var/mended)
+/**
+ * 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
-// Called when wire pulsed. Add code here.
-/datum/wires/proc/UpdatePulsed(var/index)
+/**
+ * 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)
+
+/**
+ * Pulses the wire associated with the given color.
+ *
+ * Arugments:
+ * * wire - a wire color.
+ */
+/datum/wires/proc/pulse_color(color)
+ pulse(get_wire(color))
+
+/**
+ * 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
-/datum/wires/proc/CanUse(var/mob/living/L)
- return 1
+/**
+ * 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
-// Example of use:
-/*
+/**
+ * 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
-var/const/BOLTED= 1
-var/const/SHOCKED = 2
-var/const/SAFETY = 4
-var/const/POWER = 8
+/**
+ * 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
-/datum/wires/door/UpdateCut(var/index, var/mended)
- var/obj/machinery/door/airlock/A = holder
- switch(index)
- if(BOLTED)
- if(!mended)
- A.bolt()
- if(SHOCKED)
- A.shock()
- if(SAFETY )
- A.safety()
+/**
+ * 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
-*/
-
-
-//
-// Helper Procs
-//
-
-/datum/wires/proc/PulseColour(var/colour)
- PulseIndex(GetIndex(colour))
-
-/datum/wires/proc/PulseIndex(var/index)
- if(IsIndexCut(index))
- return
- UpdatePulsed(index)
+/**
+ * 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
/datum/wires/proc/RenameDoor(var/obj/machinery/door/airlock/A = holder)
var/t = sanitizeSafe(input(usr, "Enter a new name.", holder.name), MAX_NAME_LEN)
@@ -229,107 +470,3 @@ var/const/POWER = 8
holder.update_icon()
message_admins("[usr]([usr.key]) described a door as ''[t]'' at [holder.x],[holder.y],[holder.z].")
log_admin("([usr]([usr.ckey]) described a door as ''[t]'' at [holder.x],[holder.y],[holder.z].")
-
-/datum/wires/proc/GetIndex(var/colour)
- if(wires[colour])
- var/index = wires[colour]
- return index
- else
- CRASH("[colour] is not a key in wires.")
-
-//
-// Is Index/Colour Cut procs
-//
-
-/datum/wires/proc/IsColourCut(var/colour)
- var/index = GetIndex(colour)
- return IsIndexCut(index)
-
-/datum/wires/proc/IsIndexCut(var/index)
- return (index & wires_status)
-
-//
-// Signaller Procs
-//
-
-/datum/wires/proc/IsAttached(var/colour)
- if(signallers[colour])
- return 1
- return 0
-
-/datum/wires/proc/GetAttached(var/colour)
- if(signallers[colour])
- return signallers[colour]
- return null
-
-/datum/wires/proc/Attach(var/colour, var/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(var/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(var/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(var/colour)
- var/index = GetIndex(colour)
- CutWireIndex(index)
-
-/datum/wires/proc/CutWireIndex(var/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/RandomCutAll(var/probability = 10)
- for(var/i = 1; i < MAX_FLAG && i < (1 << wire_count); i += i)
- if(prob(probability))
- CutWireIndex(i)
-
-/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
-
-/datum/wires/proc/MendAll()
- for(var/i = 1; i < MAX_FLAG && i < (1 << wire_count); i += i)
- if(IsIndexCut(i))
- CutWireIndex(i)
-
-//
-//Shuffle and Mend
-//
-
-/datum/wires/proc/Shuffle()
- wires_status = 0
- GenerateWires()
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 90c8c264f49..a3091dddad5 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -402,6 +402,20 @@
/atom/proc/relaymove()
return
+// Called to set the atom's density and used to add behavior to density changes.
+/atom/proc/set_density(var/new_density)
+ if(density == new_density)
+ return FALSE
+ density = !!new_density // Sanitize to be strictly 0 or 1
+ return TRUE
+
+// Called to set the atom's invisibility and usd to add behavior to invisibility changes.
+/atom/proc/set_invisibility(var/new_invisibility)
+ if(invisibility == new_invisibility)
+ return FALSE
+ invisibility = new_invisibility
+ return TRUE
+
/atom/proc/ex_act()
return
diff --git a/code/game/gamemodes/meteor/meteors.dm b/code/game/gamemodes/meteor/meteors.dm
index 565679e25ac..397e5393d1a 100644
--- a/code/game/gamemodes/meteor/meteors.dm
+++ b/code/game/gamemodes/meteor/meteors.dm
@@ -110,6 +110,7 @@
/obj/effect/meteor/Initialize(mapload)
. = ..()
z_original = z
+ GLOB.meteor_list += src
/obj/effect/meteor/Move()
if(z != z_original || loc == dest)
@@ -129,6 +130,7 @@
/obj/effect/meteor/Destroy()
walk(src,0) //this cancels the walk_towards() proc
+ GLOB.meteor_list -= src
return ..()
/obj/effect/meteor/Initialize(mapload)
@@ -162,6 +164,8 @@
var/turf/simulated/wall/W = T
W.take_damage(wall_power) // Stronger walls can halt asteroids.
+/obj/effect/meteor/proc/get_shield_damage()
+ return max(((max(hits, 2)) * (heavy + 1) * rand(6, 12)) / hitpwr , 0)
//process getting 'hit' by colliding with a dense object
//or randomly when ramming turfs
@@ -285,6 +289,9 @@
// Worst case scenario: Comparable to a standard yield EMP grenade.
empulse(src, rand(1, 3), rand(2, 4), rand(3, 7), rand(5, 10))
+/obj/effect/meteor/emp/get_shield_damage()
+ return ..() * rand(2,4)
+
//Station buster Tunguska
/obj/effect/meteor/tunguska
name = "tunguska meteor"
diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm
index f284b87da8c..0a32496f624 100644
--- a/code/game/machinery/alarm.dm
+++ b/code/game/machinery/alarm.dm
@@ -771,7 +771,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.")
else
@@ -782,7 +782,7 @@
//Altclick airalarms to toggle the controlls
/obj/machinery/alarm/AltClick(mob/user)
if(user.Adjacent(src))
- 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.")
else
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index 85d482f0627..207b62e0ad0 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -40,24 +40,6 @@
var/list/camera_computers_using_this = list()
-/obj/machinery/camera/apply_visual(mob/living/carbon/human/M)
- if(!M.client)
- return
- M.overlay_fullscreen("fishbed",/atom/movable/screen/fullscreen/fishbed)
- M.overlay_fullscreen("scanlines",/atom/movable/screen/fullscreen/scanline)
- M.overlay_fullscreen("whitenoise",/atom/movable/screen/fullscreen/noise)
- M.machine_visual = src
- return 1
-
-/obj/machinery/camera/remove_visual(mob/living/carbon/human/M)
- if(!M.client)
- return
- M.clear_fullscreen("fishbed",0)
- M.clear_fullscreen("scanlines")
- M.clear_fullscreen("whitenoise")
- M.machine_visual = null
- return 1
-
/obj/machinery/camera/Initialize(mapload)
if (dir == NORTH)
layer = ABOVE_MOB_LAYER
@@ -288,7 +270,7 @@
//Used when someone breaks a camera
/obj/machinery/camera/proc/destroy()
stat |= BROKEN
- wires.RandomCutAll()
+ wires.cut_all()
triggerCameraAlarm()
update_icon()
@@ -323,7 +305,7 @@
SSalarms.camera_alarm.triggerAlarm(loc, src, duration)
/obj/machinery/camera/proc/cancelCameraAlarm()
- if(wires.IsIndexCut(CAMERA_WIRE_ALARM))
+ if(wires.is_cut(WIRE_CAM_ALARM))
return
alarm_on = 0
@@ -332,10 +314,10 @@
//if false, then the camera is listed as DEACTIVATED and cannot be used
/obj/machinery/camera/proc/can_use()
if(!status)
- return 0
+ return FALSE
if(stat & (EMPED|BROKEN))
- return 0
- return 1
+ return FALSE
+ return TRUE
/obj/machinery/camera/proc/can_see()
var/list/see = null
@@ -485,7 +467,6 @@
return
if (stat & BROKEN) // Fix the camera
stat &= ~BROKEN
- wires.CutAll()
- wires.MendAll()
+ wires.repair()
update_icon()
update_coverage()
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 37f6f2a983b..85b73fbce65 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -641,10 +641,6 @@ About the new airlock wires panel:
return 1
return 0
-/obj/machinery/door/airlock/proc/isWireCut(var/wireIndex)
- // You can find the wires in the datum folder.
- return wires.IsIndexCut(wireIndex)
-
/obj/machinery/door/airlock/proc/canAIControl()
return ((src.aiControlDisabled!=1) && (!src.isAllPowerLoss()));
@@ -657,7 +653,7 @@ About the new airlock wires panel:
return (src.main_power_lost_until==0 || src.backup_power_lost_until==0)
/obj/machinery/door/airlock/requiresID()
- return !(src.isWireCut(AIRLOCK_WIRE_IDSCAN) || aiDisabledIdScanner)
+ return !(wires.is_cut(WIRE_IDSCAN) || aiDisabledIdScanner)
/obj/machinery/door/airlock/proc/isAllPowerLoss()
if(stat & (NOPOWER|BROKEN))
@@ -667,10 +663,10 @@ About the new airlock wires panel:
return 0
/obj/machinery/door/airlock/proc/mainPowerCablesCut()
- return src.isWireCut(AIRLOCK_WIRE_MAIN_POWER1) || src.isWireCut(AIRLOCK_WIRE_MAIN_POWER2)
+ return wires.is_cut(WIRE_MAIN_POWER1) || wires.is_cut(WIRE_MAIN_POWER2)
/obj/machinery/door/airlock/proc/backupPowerCablesCut()
- return src.isWireCut(AIRLOCK_WIRE_BACKUP_POWER1) || src.isWireCut(AIRLOCK_WIRE_BACKUP_POWER2)
+ return wires.is_cut(WIRE_BACKUP_POWER1) || wires.is_cut(WIRE_BACKUP_POWER2)
/obj/machinery/door/airlock/proc/loseMainPower()
main_power_lost_until = mainPowerCablesCut() ? -1 : world.time + SecondsToTicks(60)
@@ -718,7 +714,7 @@ About the new airlock wires panel:
/obj/machinery/door/airlock/proc/electrify(var/duration, var/feedback = 0)
var/message = ""
- if(src.isWireCut(AIRLOCK_WIRE_ELECTRIFY) && arePowerSystemsOn())
+ if(wires.is_cut(WIRE_ELECTRIFY) && arePowerSystemsOn())
message = text("The electrification wire is cut - Door permanently electrified.")
src.electrified_until = -1
else if(duration && !arePowerSystemsOn())
@@ -744,7 +740,7 @@ About the new airlock wires panel:
/obj/machinery/door/airlock/proc/set_idscan(var/activate, var/feedback = 0)
var/message = ""
- if(src.isWireCut(AIRLOCK_WIRE_IDSCAN))
+ if(wires.is_cut(WIRE_IDSCAN))
message = "The IdScan wire is cut - IdScan feature permanently disabled."
else if(activate && src.aiDisabledIdScanner)
src.aiDisabledIdScanner = 0
@@ -759,7 +755,7 @@ About the new airlock wires panel:
/obj/machinery/door/airlock/proc/set_safeties(var/activate, var/feedback = 0)
var/message = ""
// Safeties! We don't need no stinking safeties!
- if (src.isWireCut(AIRLOCK_WIRE_SAFETY))
+ if (wires.is_cut(WIRE_SAFETY))
message = text("The safety wire is cut - Cannot enable safeties.")
else if (!activate && src.safe)
safe = 0
@@ -979,7 +975,7 @@ About the new airlock wires panel:
if(!backup_power_lost_until)
src.loseBackupPower()
if("bolts")
- if(src.isWireCut(AIRLOCK_WIRE_DOOR_BOLTS))
+ if(wires.is_cut(WIRE_DOOR_BOLTS))
to_chat(usr, "The door bolt control wire is cut - Door bolts permanently dropped.")
else if(activate && src.lock())
to_chat(usr, "The door bolts have been dropped.")
@@ -1002,7 +998,7 @@ About the new airlock wires panel:
set_safeties(!activate, 1)
if("timing")
// Door speed control
- if(src.isWireCut(AIRLOCK_WIRE_SPEED))
+ if(wires.is_cut(WIRE_SPEED))
to_chat(usr, "The timing wire is cut - Cannot alter timing.")
else if (activate && src.normalspeed)
normalspeed = 0
@@ -1010,7 +1006,7 @@ About the new airlock wires panel:
normalspeed = 1
if("lights")
// Bolt lights
- if(src.isWireCut(AIRLOCK_WIRE_LIGHT))
+ if(wires.is_cut(WIRE_BOLT_LIGHT))
to_chat(usr, "The bolt lights wire is cut - The door bolt lights are permanently disabled.")
else if (!activate && src.lights)
lights = 0
@@ -1176,7 +1172,7 @@ About the new airlock wires panel:
/obj/machinery/door/airlock/close(var/forced=0)
if(!can_close(forced))
- return 0
+ return FALSE
if(safe)
for(var/turf/turf in locs)
@@ -1207,7 +1203,7 @@ About the new airlock wires panel:
/obj/machinery/door/airlock/can_open(var/forced=0)
if(!forced)
- if(!arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_OPEN_DOOR))
+ if(!arePowerSystemsOn() || wires.is_cut(WIRE_OPEN_DOOR))
return 0
if(locked || welded)
@@ -1220,7 +1216,7 @@ About the new airlock wires panel:
if(!forced)
//despite the name, this wire is for general door control.
- if(!arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_OPEN_DOOR))
+ if(!arePowerSystemsOn() || wires.is_cut(WIRE_OPEN_DOOR))
return 0
return ..()
@@ -1294,7 +1290,7 @@ About the new airlock wires panel:
return
if (!forced)
- if(operating || !src.arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) return
+ if(operating || !src.arePowerSystemsOn() || wires.is_cut(WIRE_DOOR_BOLTS)) return
src.locked = 0
playsound(src, bolt_up_sound, 30, 0, 3)
diff --git a/code/game/machinery/pointdefense.dm b/code/game/machinery/pointdefense.dm
index 45b9c833093..13d1f63da50 100644
--- a/code/game/machinery/pointdefense.dm
+++ b/code/game/machinery/pointdefense.dm
@@ -17,12 +17,12 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
circuit = /obj/item/circuitboard/pointdefense_control
var/list/targets = list() // Targets being engaged by associated batteries
var/id_tag = null
-/*
+
/obj/machinery/pointdefense_control/Initialize(mapload)
. = ..()
if(id_tag)
//No more than 1 controller please.
- for(var/thing in pointdefense_controllers)
+ for(var/thing in GLOB.pointdefense_controllers)
var/obj/machinery/pointdefense_control/PC = thing
if(PC != src && PC.id_tag == id_tag)
warning("Two [src] with the same id_tag of [id_tag]")
@@ -37,7 +37,7 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
if(!id_tag)
. += "[desc_panel_image("multitool")]to set ident tag"
-/obj/machinery/pointdefense_control/tgui_interact(mob/user, datum/tgui/ui)
+/obj/machinery/pointdefense_control/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "PointDefenseControl") // 400, 600
@@ -46,10 +46,10 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
/obj/machinery/pointdefense_control/attack_hand(mob/user)
if(..())
return TRUE
- tgui_interact(user)
+ ui_interact(user)
return TRUE
-/obj/machinery/pointdefense_control/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
+/obj/machinery/pointdefense_control/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
if(..())
return TRUE
@@ -70,14 +70,14 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
PD.Deactivate()
return TRUE
-/obj/machinery/pointdefense_control/tgui_data(mob/user)
+/obj/machinery/pointdefense_control/ui_data(mob/user)
var/list/data = list()
data["id"] = id_tag
var/list/turrets = list()
if(id_tag)
var/list/connected_z_levels = GetConnectedZlevels(get_z(src))
- for(var/i = 1 to LAZYLEN(pointdefense_turrets))
- var/obj/machinery/power/pointdefense/PD = pointdefense_turrets[i]
+ for(var/i = 1 to LAZYLEN(GLOB.pointdefense_turrets))
+ var/obj/machinery/power/pointdefense/PD = GLOB.pointdefense_turrets[i]
if(!(PD.id_tag == id_tag && (get_z(PD) in connected_z_levels)))
continue
var/list/turret = list()
@@ -96,9 +96,9 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
/obj/machinery/pointdefense_control/attackby(var/obj/item/W, var/mob/user)
if(W?.is_multitool())
var/new_ident = input(user, "Enter a new ident tag.", "[src]", id_tag) as null|text
- if(new_ident && new_ident != id_tag && user.Adjacent(src) && CanInteract(user, GLOB.tgui_physical_state))
+ if(new_ident && new_ident != id_tag && user.Adjacent(src) && CanInteract(user, GLOB.physical_state))
// Check for duplicate controllers with this ID
- for(var/thing in pointdefense_controllers)
+ for(var/thing in GLOB.pointdefense_controllers)
var/obj/machinery/pointdefense_control/PC = thing
if(PC != src && PC.id_tag == id_tag)
to_chat(user, "The [new_ident] network already has a controller.")
@@ -113,7 +113,7 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
if(default_part_replacement(user, W))
return
return ..()
-*/
+
//
// The acutal point defense battery
//
@@ -137,7 +137,7 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
var/rotation_speed = 0.25 SECONDS //How quickly we turn to face threats
var/engaging = null // The meteor we're shooting at
var/id_tag = null
-/*
+
/obj/machinery/power/pointdefense/Initialize()
. = ..()
// TODO - Remove this bit once machines are converted to Initialize
@@ -167,7 +167,7 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
else
icon_state = initial(icon_state)
-/obj/machinery/power/pointdefense/default_unfasten_wrench(var/mob/user, var/obj/item/weapon/W, var/time)
+/obj/machinery/power/pointdefense/default_unfasten_wrench(var/mob/user, var/obj/item/W, var/time)
if((. = ..()))
src.transform = null // Reset rotation if we're anchored/unanchored
@@ -207,7 +207,7 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
if(!id_tag)
return null
var/list/connected_z_levels = GetConnectedZlevels(get_z(src))
- for(var/thing in pointdefense_controllers)
+ for(var/thing in GLOB.pointdefense_controllers)
var/obj/machinery/pointdefense_control/PDC = thing
if(PDC.id_tag == id_tag && (get_z(PDC) in connected_z_levels))
return PDC
@@ -215,7 +215,7 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
/obj/machinery/power/pointdefense/attackby(var/obj/item/W, var/mob/user)
if(W?.is_multitool())
var/new_ident = input(user, "Enter a new ident tag.", "[src]", id_tag) as null|text
- if(new_ident && new_ident != id_tag && user.Adjacent(src) && CanInteract(user, GLOB.tgui_physical_state))
+ if(new_ident && new_ident != id_tag && user.Adjacent(src) && CanInteract(user, GLOB.physical_state))
to_chat(user, "You register [src] with the [new_ident] network.")
id_tag = new_ident
return
@@ -236,7 +236,7 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
return FALSE
return TRUE
-/obj/machinery/power/pointdefense/proc/Shoot(var/target)
+/obj/machinery/power/pointdefense/proc/Shoot(var/datum/weakref/target)
var/obj/effect/meteor/M = target.resolve()
if(!istype(M))
engaging = null
@@ -248,9 +248,9 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
addtimer(CALLBACK(src, .proc/finish_shot, target), rotation_speed)
animate(src, transform = rot_matrix, rotation_speed, easing = SINE_EASING)
- set_dir(ATAN2(transform.b, transform.a) > 0 ? NORTH : SOUTH)
+ setDir(arctan(transform.b, transform.a) > 0 ? NORTH : SOUTH)
-/obj/machinery/power/pointdefense/proc/finish_shot(var/target)
+/obj/machinery/power/pointdefense/proc/finish_shot(var/datum/weakref/target)
var/obj/machinery/pointdefense_control/PC = get_controller()
engaging = null
@@ -261,7 +261,7 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
if(!istype(M))
return
if(use_power_oneoff(active_power_usage) < active_power_usage)
- var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread
+ var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(5, 1, src)
s.start()
visible_message("[src] sputters as browns out while attempting to fire.")
@@ -279,9 +279,9 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
if(!active)
return
/*
- var/desiredir = ATAN2(transform.b, transform.a) > 0 ? NORTH : SOUTH
+ var/desiredir = arctan(transform.b, transform.a) > 0 ? NORTH : SOUTH
if(dir != desiredir)
- set_dir(desiredir)
+ setDir(desiredir)
*/
if(LAZYLEN(GLOB.meteor_list) > 0)
@@ -301,12 +301,12 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
// Compile list of known targets
var/list/existing_targets = list()
- for(var/WR in PC.targets)
+ for(var/datum/weakref/WR in PC.targets)
var/obj/effect/meteor/M = WR.resolve()
existing_targets += M
// First, try and acquire new targets
- var/list/potential_targets = meteor_list.Copy() - existing_targets
+ var/list/potential_targets = GLOB.meteor_list.Copy() - existing_targets
for(var/obj/effect/meteor/M in potential_targets)
if(targeting_check(M))
var/target = M
@@ -370,4 +370,3 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
active = FALSE
update_icon()
return TRUE
-*/
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index 31c785fba1f..0d1baf643ee 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -148,8 +148,8 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
data["freq"] = format_frequency(frequency)
data["rawfreq"] = num2text(frequency)
- data["mic_cut"] = (wires.IsIndexCut(WIRE_TRANSMIT) || wires.IsIndexCut(WIRE_SIGNAL))
- data["spk_cut"] = (wires.IsIndexCut(WIRE_RECEIVE) || wires.IsIndexCut(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)
@@ -203,12 +203,6 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
/mob/observer/dead/has_internal_radio_channel_access(var/list/req_one_accesses)
return can_admin_interact()
-/obj/item/radio/proc/text_wires()
- if (b_stat)
- return wires.GetInteractWindow()
- return
-
-
/obj/item/radio/proc/text_sec_channel(var/chan_name, var/chan_stat)
var/list = !!(chan_stat&FREQ_LISTENING)!=0
return {"
@@ -217,10 +211,10 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
"}
/obj/item/radio/proc/ToggleBroadcast()
- broadcasting = !broadcasting && !(wires.IsIndexCut(WIRE_TRANSMIT) || wires.IsIndexCut(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(WIRE_RECEIVE) || wires.IsIndexCut(WIRE_SIGNAL))
+ listening = !listening && !(wires.is_cut(WIRE_RADIO_RECEIVER) || wires.is_cut(WIRE_RADIO_SIGNAL))
/obj/item/radio/CanUseTopic()
if(!on)
@@ -321,7 +315,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(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 FALSE
if(!radio_connection)
@@ -540,7 +534,7 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
// what the range is in which mobs will hear the radio
// returns: -1 if can't receive, range otherwise
- if (wires.IsIndexCut(WIRE_RECEIVE))
+ if(wires.is_cut(WIRE_RADIO_RECEIVER))
return -1
if(!listening)
return -1
diff --git a/code/game/objects/items/weapons/circuitboards/machinery/shieldgen.dm b/code/game/objects/items/weapons/circuitboards/machinery/shieldgen.dm
index f876ad96f58..cc33f90553f 100644
--- a/code/game/objects/items/weapons/circuitboards/machinery/shieldgen.dm
+++ b/code/game/objects/items/weapons/circuitboards/machinery/shieldgen.dm
@@ -2,6 +2,37 @@
#error T_BOARD macro is not defined but we need it!
#endif
+//
+// New shield generator
+//
+
+/obj/item/circuitboard/shield_generator
+ name = T_BOARD("advanced shield generator")
+ board_type = new /datum/frame/frame_types/machine
+ build_path = /obj/machinery/power/shield_generator
+ origin_tech = list(TECH_MAGNET = 3, TECH_POWER = 4, TECH_BLUESPACE = 2, TECH_ENGINEERING = 3)
+ req_components = list(
+ /obj/item/stock_parts/capacitor = 1,
+ /obj/item/stock_parts/micro_laser = 1,
+ /obj/item/smes_coil = 1,
+ /obj/item/stock_parts/console_screen = 1,
+ /obj/item/stock_parts/subspace/amplifier = 1,
+ /obj/item/stack/cable_coil = 5)
+
+/obj/item/circuitboard/shield_diffuser
+ name = T_BOARD("shield diffuser")
+ board_type = new /datum/frame/frame_types/machine
+ build_path = /obj/machinery/shield_diffuser
+ origin_tech = list(TECH_MAGNET = 4, TECH_POWER = 2, TECH_ILLEGAL = 1)
+ req_components = list(
+ /obj/item/stock_parts/capacitor = 1,
+ /obj/item/stock_parts/micro_laser = 1,
+ /obj/item/stock_parts/console_screen = 1)
+
+//
+// Legacy shield generators
+//
+
/obj/item/circuitboard/shield_gen_ex
name = T_BOARD("hull shield generator")
board_type = new /datum/frame/frame_types/machine
diff --git a/code/game/objects/items/weapons/circuitboards/machinery/ships.dm b/code/game/objects/items/weapons/circuitboards/machinery/ships.dm
index 5019a8fa11c..a46ad717f6f 100644
--- a/code/game/objects/items/weapons/circuitboards/machinery/ships.dm
+++ b/code/game/objects/items/weapons/circuitboards/machinery/ships.dm
@@ -4,16 +4,20 @@
/obj/item/circuitboard/pointdefense
name = T_BOARD("point defense battery")
+ board_type = new /datum/frame/frame_types/machine
desc = "Control systems for a Kuiper pattern point defense battery. Aim away from vessel."
build_path = /obj/machinery/power/pointdefense
origin_tech = list(TECH_ENGINEERING = 3, TECH_COMBAT = 2)
req_components = list(
- /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser = 1,
- /obj/item/stock_parts/manipulator = 2,
- /obj/item/stock_parts/capacitor = 2)
+ /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser = 1,
+ /obj/item/stock_parts/manipulator = 2,
+ /obj/item/stock_parts/capacitor = 2,
+ )
/obj/item/circuitboard/pointdefense_control
name = T_BOARD("fire assist mainframe")
+ board_type = new /datum/frame/frame_types/machine
desc = "A control computer to synchronize point defense batteries."
build_path = /obj/machinery/pointdefense_control
origin_tech = list(TECH_ENGINEERING = 3, TECH_COMBAT = 2)
+ req_components = list()
diff --git a/code/modules/ai/ai_holder_combat.dm b/code/modules/ai/ai_holder_combat.dm
index 2d7f1c59eb2..0b6d1882f3a 100644
--- a/code/modules/ai/ai_holder_combat.dm
+++ b/code/modules/ai/ai_holder_combat.dm
@@ -315,6 +315,12 @@
ai_log("destroy_surroundings() : Attacking hull shield.", AI_LOG_INFO)
return holder.IAttack(shield)
+ // Kill energy shields in the way.
+ for(var/obj/effect/shield/S in problem_turf)
+ if(S.density) // Don't attack shields that are already down.
+ ai_log("destroy_surroundings() : Attacking energy shield.", AI_LOG_INFO)
+ return melee_attack(S)
+
// Kill common obstacle in the way like tables.
var/obj/structure/obstacle = locate(/obj/structure, problem_turf)
if(istype(obstacle, /obj/structure/window) || istype(obstacle, /obj/structure/closet) || istype(obstacle, /obj/structure/table) || istype(obstacle, /obj/structure/grille))
diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm
index 749aa1c968a..f51fe59a78c 100644
--- a/code/modules/assembly/signaler.dm
+++ b/code/modules/assembly/signaler.dm
@@ -127,8 +127,8 @@ Code:
/obj/item/assembly/signaler/pulse(var/radio = 0)
if(is_jammed(src))
return FALSE
- if(src.connected && src.wires)
- connected.Pulse(src)
+ if(connected && wires)
+ connected.pulse_assembly(src)
else if(holder)
holder.process_activation(src, 1, 0)
else
diff --git a/code/modules/client/preference_setup/preference_setup.dm b/code/modules/client/preference_setup/preference_setup.dm
index 4f7c4ed817a..1fd18f8d95f 100644
--- a/code/modules/client/preference_setup/preference_setup.dm
+++ b/code/modules/client/preference_setup/preference_setup.dm
@@ -1,9 +1,3 @@
-#define TOPIC_NOACTION 0
-#define TOPIC_HANDLED 1
-#define TOPIC_REFRESH 2
-#define TOPIC_UPDATE_PREVIEW 4
-#define TOPIC_REFRESH_UPDATE_PREVIEW (TOPIC_REFRESH|TOPIC_UPDATE_PREVIEW)
-
#define PREF_FBP_CYBORG "cyborg"
#define PREF_FBP_POSI "posi"
#define PREF_FBP_SOFTWARE "software"
diff --git a/code/modules/clothing/spacesuits/rig/rig_wiring.dm b/code/modules/clothing/spacesuits/rig/rig_wiring.dm
index f435b434451..211e85d1e19 100644
--- a/code/modules/clothing/spacesuits/rig/rig_wiring.dm
+++ b/code/modules/clothing/spacesuits/rig/rig_wiring.dm
@@ -1,13 +1,11 @@
/datum/wires/rig
- random = 1
+ randomize = TRUE
holder_type = /obj/item/rig
wire_count = 5
-#define RIG_SECURITY 1
-#define RIG_AI_OVERRIDE 2
-#define RIG_SYSTEM_CONTROL 4
-#define RIG_INTERFACE_LOCK 8
-#define RIG_INTERFACE_SHOCK 16
+/datum/wires/rig/New(atom/_holder)
+ wires = list(WIRE_RIG_SECURITY, WIRE_RIG_AI_OVERRIDE, WIRE_RIG_SYSTEM_CONTROL, WIRE_RIG_INTERFACE_LOCK, WIRE_RIG_INTERFACE_SHOCK)
+ return ..()
/*
* Rig security can be snipped to disable ID access checks on rig.
* Rig AI override can be pulsed to toggle whether or not the AI can take control of the suit.
@@ -15,50 +13,48 @@
* Interface lock can be pulsed to toggle whether or not the interface can be accessed.
*/
-/datum/wires/rig/UpdateCut(var/index, var/mended)
-
+/datum/wires/rig/on_cut(wire, mend)
var/obj/item/rig/rig = holder
- switch(index)
- if(RIG_SECURITY)
- if(mended)
+ switch(wire)
+ if(WIRE_RIG_SECURITY)
+ if(mend)
rig.req_access = initial(rig.req_access)
rig.req_one_access = initial(rig.req_one_access)
- if(RIG_SYSTEM_CONTROL)
- if(!mended)
+ if(WIRE_RIG_SYSTEM_CONTROL)
+ if(!mend)
rig.shock(usr,100) // Intended to keep players from trying to mend in the middle of combat. Second way of getting shocked as pulsing this wire ALSO shocks you.
- else if(mended)
+ else if(mend)
rig.malfunctioning = 0
rig.malfunction_delay = 0
- if(RIG_INTERFACE_SHOCK)
- rig.electrified = mended ? 0 : -1
+ if(WIRE_RIG_INTERFACE_SHOCK)
+ rig.electrified = mend ? 0 : -1
rig.shock(usr,100)
-/datum/wires/rig/UpdatePulsed(var/index)
-
+/datum/wires/rig/on_pulse(wire)
var/obj/item/rig/rig = holder
- switch(index)
- if(RIG_SECURITY)
+ switch(wire)
+ if(WIRE_RIG_SECURITY)
rig.security_check_enabled = !rig.security_check_enabled
rig.visible_message("\The [rig] twitches as several suit locks [rig.security_check_enabled?"close":"open"].")
- if(RIG_AI_OVERRIDE)
+ if(WIRE_RIG_AI_OVERRIDE)
rig.ai_override_enabled = !rig.ai_override_enabled
rig.visible_message("A small red light on [rig] [rig.ai_override_enabled?"goes dead":"flickers on"].")
- if(RIG_SYSTEM_CONTROL)
+ if(WIRE_RIG_SYSTEM_CONTROL)
rig.malfunctioning += 10
if(rig.malfunction_delay <= 0)
rig.malfunction_delay = 20
rig.shock(usr,100)
rig.visible_message("\The [rig] beeps stridently as a surge of power runs through it.") // Hints to the fact that if you pulse this while wearing it you get zappoed.
- if(RIG_INTERFACE_LOCK)
+ if(WIRE_RIG_INTERFACE_LOCK)
rig.interface_locked = !rig.interface_locked
rig.visible_message("\The [rig] clicks audibly as the software interface [rig.interface_locked?"darkens":"brightens"].")
- if(RIG_INTERFACE_SHOCK)
+ if(WIRE_RIG_INTERFACE_SHOCK)
if(rig.electrified != -1)
rig.electrified = 30
rig.shock(usr,100)
-/datum/wires/rig/CanUse(var/mob/living/L)
+/datum/wires/rig/interactable(mob/user)
var/obj/item/rig/rig = holder
if(rig.open)
- return 1
- return 0
+ return TRUE
+ return FALSE
diff --git a/code/modules/events/camera_damage.dm b/code/modules/events/camera_damage.dm
index 01a940375e0..c92cd965ed3 100644
--- a/code/modules/events/camera_damage.dm
+++ b/code/modules/events/camera_damage.dm
@@ -17,9 +17,9 @@
if(prob(2*severity))
cam.destroy()
else
- cam.wires.UpdateCut(CAMERA_WIRE_POWER, 0)
+ cam.wires.cut(WIRE_MAIN_POWER1)
if(prob(5*severity))
- cam.wires.UpdateCut(CAMERA_WIRE_ALARM, 0)
+ cam.wires.cut(WIRE_CAM_ALARM)
/datum/event/camera_damage/proc/acquire_random_camera(var/remaining_attempts = 5)
if(!cameranet.cameras.len)
diff --git a/code/modules/events/electrical_storm.dm b/code/modules/events/electrical_storm.dm
index 49334e7ae82..870705079ac 100644
--- a/code/modules/events/electrical_storm.dm
+++ b/code/modules/events/electrical_storm.dm
@@ -35,8 +35,16 @@
/datum/event/electrical_storm/tick()
..()
- // See if shields can stop it first (It would be nice to port baystation's cooler shield gens perhaps)
- // TODO - We need a better shield generator system to handle this properly.
+ // See if shields can stop it first
+ var/list/shields = list()
+ for(var/obj/machinery/power/shield_generator/G in global.machines)
+ if((G.z in affecting_z) && G.running && G.check_flag(MODEFLAG_EM))
+ shields += G
+ if(shields.len)
+ var/obj/machinery/power/shield_generator/shield_gen = pick(shields)
+ //Minor breaches aren't enough to let through frying amounts of power
+ if(shield_gen.deal_shield_damage(30 * severity, SHIELD_DAMTYPE_EM) <= SHIELD_BREACHED_MINOR)
+ return
if(!valid_apcs.len)
log_debug("No valid APCs found for electrical storm event ship=[victim]!")
return
diff --git a/code/modules/events/meteors.dm b/code/modules/events/meteors.dm
index 0a58ba7563c..d87fa15b502 100644
--- a/code/modules/events/meteors.dm
+++ b/code/modules/events/meteors.dm
@@ -2,7 +2,8 @@
startWhen = 30 // About one minute early warning
endWhen = 60 // Adjusted automatically in tick()
has_skybox_image = TRUE
- var/next_meteor = 6
+ var/alarmWhen = 30
+ var/next_meteor = 40
var/waves = 1
var/start_side
var/next_meteor_lower = 10
@@ -31,6 +32,12 @@
command_announcement.Announce("\The [location_name()] is now in a meteor shower.", "Meteor Alert")
/datum/event/meteor_wave/tick()
+ // Begin sending the alarm signals to shield diffusers so the field is already regenerated (if it exists) by the time actual meteors start flying around.
+ if(activeFor >= alarmWhen)
+ for(var/obj/machinery/shield_diffuser/SD in global.machines)
+ if(SD.z in affecting_z)
+ SD.meteor_alarm(10)
+
if(waves && activeFor >= next_meteor)
send_wave()
@@ -69,6 +76,7 @@
next_meteor_lower = 5
next_meteor_upper = 10
next_meteor = 0
+ alarmWhen = 0
/datum/event/meteor_wave/overmap/announce()
command_announcement.Announce("Meteors have been detected on collision course with \the [location_name()].", "Meteor Alert", new_sound = 'sound/AI/meteors.ogg')
diff --git a/code/modules/gamemaster/actions/camera_damage.dm b/code/modules/gamemaster/actions/camera_damage.dm
index 293c20e7eaf..c13b81702d9 100644
--- a/code/modules/gamemaster/actions/camera_damage.dm
+++ b/code/modules/gamemaster/actions/camera_damage.dm
@@ -28,9 +28,9 @@
if(prob(2*severity))
cam.destroy()
else
- cam.wires.UpdateCut(CAMERA_WIRE_POWER, 0)
+ cam.wires.cut(WIRE_MAIN_POWER1)
if(prob(5*severity))
- cam.wires.UpdateCut(CAMERA_WIRE_ALARM, 0)
+ cam.wires.cut(WIRE_CAM_ALARM)
/datum/gm_action/camera_damage/proc/acquire_random_camera(var/remaining_attempts = 5)
if(!cameranet.cameras.len)
diff --git a/code/modules/mob/_modifiers/modifiers.dm b/code/modules/mob/_modifiers/modifiers.dm
index 2bcb0ce0ac8..7d1de3088e9 100644
--- a/code/modules/mob/_modifiers/modifiers.dm
+++ b/code/modules/mob/_modifiers/modifiers.dm
@@ -20,6 +20,7 @@
var/light_intensity = null // Ditto. Not implemented yet.
var/mob_overlay_state = null // Icon_state for an overlay to apply to a (human) mob while this exists. This is actually implemented.
var/client_color = null // If set, the client will have the world be shown in this color, from their perspective.
+ var/wire_colors_replace = null // If set, the client will have wires replaced by the given replacement list. For colorblindness.
// Now for all the different effects.
// Percentage modifiers are expressed as a multipler. (e.g. +25% damage should be written as 1.25)
diff --git a/code/modules/mob/_modifiers/traits.dm b/code/modules/mob/_modifiers/traits.dm
index b15ece941e3..aebfaa893a3 100644
--- a/code/modules/mob/_modifiers/traits.dm
+++ b/code/modules/mob/_modifiers/traits.dm
@@ -127,33 +127,39 @@
desc = "You have a form of red-green colorblindness. You cannot see reds, and have trouble distinguishing them from yellows and greens."
client_color = MATRIX_Protanopia
+ wire_colors_replace = PROTANOPIA_COLOR_REPLACE
/datum/modifier/trait/colorblind_deuteranopia
name = "Deuteranopia"
desc = "You have a form of red-green colorblindness. You cannot see greens, and have trouble distinguishing them from yellows and reds."
client_color = MATRIX_Deuteranopia
+ wire_colors_replace = DEUTERANOPIA_COLOR_REPLACE
/datum/modifier/trait/colorblind_tritanopia
name = "Tritanopia"
desc = "You have a form of blue-yellow colorblindness. You have trouble distinguishing between blues, greens, and yellows, and see blues and violets as dim."
client_color = MATRIX_Tritanopia
+ wire_colors_replace = TRITANOPIA_COLOR_REPLACE
/datum/modifier/trait/colorblind_taj
name = "Colorblind - Blue-red"
desc = "You are colorblind. You have a minor issue with blue colors and have difficulty recognizing them from red colors."
client_color = MATRIX_Taj_Colorblind
+ wire_colors_replace = TRITANOPIA_COLOR_REPLACE
/datum/modifier/trait/colorblind_vulp
name = "Colorblind - Red-green"
desc = "You are colorblind. You have a severe issue with green colors and have difficulty recognizing them from red colors."
client_color = MATRIX_Vulp_Colorblind
+ wire_colors_replace = PROTANOPIA_COLOR_REPLACE
/datum/modifier/trait/colorblind_monochrome
name = "Monochromacy"
desc = "You are fully colorblind. Your condition is rare, but you can see no colors at all."
client_color = MATRIX_Monochromia
+ wire_colors_replace = GREYSCALE_COLOR_REPLACE
diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm
index 86064ce2340..a6de7c63427 100644
--- a/code/modules/mob/inventory.dm
+++ b/code/modules/mob/inventory.dm
@@ -270,9 +270,9 @@ var/list/slot_equipment_priority = list( \
//This differs from remove_from_mob() in that it checks if the item can be unequipped first.
/mob/proc/unEquip(obj/item/I, force = 0, target) //Force overrides NODROP for things like wizarditis and admin undress.
if(!(force || canUnEquip(I)))
- return
+ return FALSE
drop_from_inventory(I, target)
- return 1
+ return TRUE
//Attemps to remove an object on a mob.
diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm
index d7b48f37fdb..03187e45df6 100644
--- a/code/modules/mob/living/silicon/robot/life.dm
+++ b/code/modules/mob/living/silicon/robot/life.dm
@@ -69,7 +69,7 @@
/mob/living/silicon/robot/handle_regular_UI_updates()
if(src.camera && !scrambledcodes)
- if(src.stat == 2 || wires.IsIndexCut(BORG_WIRE_CAMERA))
+ if(src.stat == 2 || wires.is_cut(WIRE_BORG_CAMERA))
src.camera.set_status(0)
else
src.camera.set_status(1)
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 2be258fad0b..e0577db8a3a 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -161,7 +161,7 @@
camera = new /obj/machinery/camera(src)
camera.c_tag = real_name
camera.replace_networks(list(NETWORK_DEFAULT,NETWORK_ROBOTS))
- if(wires.IsIndexCut(BORG_WIRE_CAMERA))
+ if(wires.is_cut(WIRE_BORG_CAMERA))
camera.status = 0
init()
@@ -569,7 +569,7 @@
to_chat(user, "You close the cover.")
opened = 0
updateicon()
- 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, "\The [src] has no brain to remove.")
@@ -1014,7 +1014,7 @@
/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
lockdown = state
lockcharge = state
diff --git a/code/modules/nifsoft/nif_softshop.dm b/code/modules/nifsoft/nif_softshop.dm
index bdbe5c2ded6..0d0c0b6d5c5 100644
--- a/code/modules/nifsoft/nif_softshop.dm
+++ b/code/modules/nifsoft/nif_softshop.dm
@@ -21,6 +21,10 @@
/obj/machinery/vending/nifsoft_shop/Initialize(mapload)
. = ..()
+
+ if(wires)
+ qdel(wires)
+ wires = new /datum/wires/vending/no_contraband(src) //These wires can't be hacked for contraband.
entopic = new(aholder = src, aicon = icon, aicon_state = "beacon")
/obj/machinery/vending/nifsoft_shop/Destroy()
@@ -72,9 +76,9 @@
list(premium, CAT_COIN))
for(var/current_list in all_products)
- var/category = current_list[2]
+ var/category = current_list[CAT_HIDDEN]
- for(var/entry in current_list[1])
+ for(var/entry in current_list[CAT_NORMAL])
var/datum/nifsoft/NS = entry
var/applies_to = initial(NS.applies_to)
var/context = ""
@@ -141,7 +145,7 @@
if(initial(path.access))
var/list/soft_access = list(initial(path.access))
var/list/usr_access = usr.GetAccess()
- if(!has_access(soft_access, list(), usr_access) && !emagged)
+ if(scan_id && !has_access(soft_access, list(), usr_access) && !emagged)
to_chat(usr, "You aren't authorized to buy [initial(path.name)].")
flick(icon_deny,entopic.my_image)
return
@@ -217,3 +221,21 @@
currently_vending = null
SSnanoui.update_uis(src)
return 1
+
+//Can't throw intangible software at people.
+/obj/machinery/vending/nifsoft_shop/throw_item()
+ //TODO: Make it throw disks at people with random software? That might be fun. EVEN THE ILLEGAL ONES? ;o
+ return 0
+
+/datum/wires/vending/no_contraband
+
+/datum/wires/vending/no_contraband/on_pulse(index) //Can't hack for contraband, need emag.
+ if(index != WIRE_CONTRABAND)
+ ..(index)
+
+/obj/machinery/vending/nifsoft_shop/emag_act(remaining_charges, mob/user) //Yeees, YEEES! Give me that black market tech.
+ if(!emagged || !(categories & CAT_HIDDEN))
+ emagged = 1
+ categories |= CAT_HIDDEN
+ to_chat(user, "You short out [src]'s access lock & stock restrictions.")
+ return 1
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 91744fa1f49..6f497b752ae 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -547,7 +547,7 @@
else if(hacker)
to_chat(user,"Access denied.")
else
- if(src.allowed(usr) && !isWireCut(APC_WIRE_IDSCAN))
+ if(src.allowed(usr) && !wires.is_cut(WIRE_IDSCAN))
locked = !locked
to_chat(user,"You [ locked ? "lock" : "unlock"] the APC interface.")
update_icon()
@@ -691,15 +691,13 @@
//Altclick APCs to toggle the controlls
/obj/machinery/power/apc/AltClick(mob/user)
if(user.Adjacent(src))
- if(src.allowed(usr) && !isWireCut(APC_WIRE_IDSCAN))
+ if(src.allowed(usr) && !wires.is_cut(WIRE_IDSCAN))
locked = !locked
to_chat(user,"You [ locked ? "lock" : "unlock"] the APC interface.")
update_icon()
else
to_chat(user,"Access denied.")
-
-
/obj/machinery/power/apc/emag_act(var/remaining_charges, var/mob/user)
if (!(emagged || hacker)) // trying to unlock with an emag card
if(opened)
@@ -718,9 +716,9 @@
return 1
/obj/machinery/power/apc/blob_act()
- if(!wires.IsAllCut())
+ if(!wires.is_all_cut())
wiresexposed = TRUE
- wires.CutAll()
+ wires.cut_all()
update_icon()
/obj/machinery/power/apc/attack_hand(mob/user)
@@ -739,7 +737,7 @@
user.visible_message("[user.name] slashes at the [src.name]!", "You slash at the [src.name]!")
playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1)
- var/allcut = wires.IsAllCut()
+ var/allcut = wires.is_all_cut()
if(beenhit >= pick(3, 4) && wiresexposed != 1)
wiresexposed = 1
@@ -747,7 +745,7 @@
src.visible_message("The [src.name]'s cover flies open, exposing the wires!")
else if(wiresexposed == 1 && allcut == 0)
- wires.CutAll()
+ wires.cut_all()
src.update_icon()
src.visible_message("The [src.name]'s wires are shredded!")
else
@@ -900,73 +898,7 @@
if("overload")
if(locked_exception) // Reusing for simplicity!
overload_lighting()
-/*
-/obj/machinery/power/apc/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- if(!user)
- return
- var/list/data = list(
- "locked" = locked,
- "emagged" = emagged,
- "isOperating" = operating,
- "externalPower" = main_status,
- "powerCellStatus" = cell ? cell.percent() : null,
- "chargeMode" = chargemode,
- "chargingStatus" = charging,
- "totalLoad" = round(lastused_total),
- "totalCharging" = round(lastused_charging),
- "failTime" = failure_timer * 2,
- "gridCheck" = grid_check,
- "coverLocked" = coverlocked,
- "siliconUser" = issilicon(user) || isobserver(user), //I add observer here so admins can have more control, even if it makes 'siliconUser' seem inaccurate.
-
- "powerChannels" = list(
- list(
- "title" = "Equipment",
- "powerLoad" = lastused_equip,
- "status" = equipment,
- "topicParams" = list(
- "auto" = list("eqp" = 3),
- "on" = list("eqp" = 2),
- "off" = list("eqp" = 1)
- )
- ),
- list(
- "title" = "Lighting",
- "powerLoad" = round(lastused_light),
- "status" = lighting,
- "topicParams" = list(
- "auto" = list("lgt" = 3),
- "on" = list("lgt" = 2),
- "off" = list("lgt" = 1)
- )
- ),
- list(
- "title" = "Environment",
- "powerLoad" = round(lastused_environ),
- "status" = environ,
- "topicParams" = list(
- "auto" = list("env" = 3),
- "on" = list("env" = 2),
- "off" = list("env" = 1)
- )
- )
- )
- )
-
- // update the ui if it exists, returns null if no ui is passed/found
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- // the ui does not exist, so we'll create a new() one
- // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
- ui = new(user, src, ui_key, "apc.tmpl", "[area.name] - APC", 520, data["siliconUser"] ? 465 : 440)
- // when the ui is first opened this is the data it will use
- ui.set_initial_data(data)
- // open the new ui window
- ui.open()
- // auto update every Master Controller tick
- ui.set_auto_update(1)
-*/
/obj/machinery/power/apc/proc/report()
return "[area.name] : [equipment]/[lighting]/[environ] ([lastused_equip+lastused_light+lastused_environ]) : [cell? cell.percent() : "N/C"] ([charging])"
@@ -986,9 +918,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(mob/user as mob, var/loud = 0) //used by attack_hand() and Topic()
if(!user.client)
return 0
diff --git a/code/modules/power/singularity/particle_accelerator/particle_control.dm b/code/modules/power/singularity/particle_accelerator/particle_control.dm
index 6faf7c5216b..f07e0641b65 100644
--- a/code/modules/power/singularity/particle_accelerator/particle_control.dm
+++ b/code/modules/power/singularity/particle_accelerator/particle_control.dm
@@ -91,17 +91,17 @@
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/research/designs/circuits/circuits.dm b/code/modules/research/designs/circuits/circuits.dm
index 9a3f9c635cf..d78b4ca324e 100644
--- a/code/modules/research/designs/circuits/circuits.dm
+++ b/code/modules/research/designs/circuits/circuits.dm
@@ -614,36 +614,6 @@ CIRCUITS BELOW
build_path = /obj/item/circuitboard/telecomms/exonet_node
sort_string = "PAAAH"
-/datum/design/circuit/shield
- req_tech = list(TECH_BLUESPACE = 4, TECH_PHORON = 3)
- materials = list("glass" = 2000, "gold" = 1000)
-
-/datum/design/circuit/shield/AssembleDesignName()
- name = "Shield generator circuit design ([name])"
-/datum/design/circuit/shield/AssembleDesignDesc()
- if(!desc)
- desc = "Allows for the construction of \a [name] shield generator."
-
-/datum/design/circuit/shield/bubble
- name = "bubble"
- id = "shield_gen"
- build_path = /obj/item/circuitboard/shield_gen
- sort_string = "VAAAZ" // Duplicate string, really need to redo this whole thing
-
-/datum/design/circuit/shield/hull
- name = "hull"
- id = "shield_gen_ex"
- build_path = /obj/item/circuitboard/shield_gen_ex
- sort_string = "VAAAB"
-
-/datum/design/circuit/shield/capacitor
- name = "capacitor"
- desc = "Allows for the construction of a shield capacitor circuit board."
- id = "shield_cap"
- req_tech = list(TECH_MAGNET = 3, TECH_POWER = 4)
- build_path = /obj/item/circuitboard/shield_cap
- sort_string = "VAAAC"
-
/datum/design/circuit/ntnet_relay
name = "NTNet Quantum Relay"
id = "ntnet_relay"
@@ -664,6 +634,21 @@ CIRCUITS BELOW
req_tech = list(TECH_DATA = 4, TECH_BIO = 3)
build_path = /obj/item/circuitboard/dnarevive
sort_string = "ZAAAA"
+
+/datum/design/circuit/shield_generator
+ name = "shield generator"
+ id = "shield_generator"
+ req_tech = list(TECH_MAGNET = 3, TECH_POWER = 4, TECH_BLUESPACE = 2, TECH_ENGINEERING = 3)
+ build_path = /obj/item/circuitboard/shield_generator
+ sort_string = "OAAAA"
+
+/datum/design/circuit/shield_diffuser
+ name = "shield diffuser"
+ id = "shield_diffuser"
+ req_tech = list(TECH_MAGNET = 4, TECH_POWER = 2, TECH_ENGINEERING = 5)
+ build_path = /obj/item/circuitboard/shield_diffuser
+ sort_string = "OAAAB"
+
/datum/design/circuit/pointdefense
name = "point defense battery"
id = "pointdefense"
diff --git a/code/modules/shieldgen/energy_field.dm b/code/modules/shieldgen/energy_field.dm
index 549162333a0..323bcc44733 100644
--- a/code/modules/shieldgen/energy_field.dm
+++ b/code/modules/shieldgen/energy_field.dm
@@ -14,10 +14,10 @@
icon = 'icons/obj/machines/shielding.dmi'
icon_state = "shield"
alpha = 100
- anchored = 1
+ anchored = TRUE
plane = MOB_PLANE
layer = ABOVE_MOB_LAYER
- density = 0
+ density = FALSE
can_atmos_pass = ATMOS_PASS_YES
var/obj/machinery/shield_gen/my_gen = null
var/strength = 0 // in Renwicks
@@ -146,4 +146,3 @@
for(var/obj/effect/energy_field/F in T)
if(!(F in affected_shields))
F.impact_effect(i, affected_shields) // Spread the effect to them.
-
diff --git a/code/modules/shieldgen/energy_shield.dm b/code/modules/shieldgen/energy_shield.dm
new file mode 100644
index 00000000000..2fb3048f600
--- /dev/null
+++ b/code/modules/shieldgen/energy_shield.dm
@@ -0,0 +1,339 @@
+//
+// This is the shield effect object for the supercool shield gens.
+//
+/obj/effect/shield
+ name = "energy shield"
+ desc = "An impenetrable field of energy, capable of blocking anything as long as it's active."
+ icon = 'icons/obj/machines/shielding_vr.dmi'
+ icon_state = "shield_normal"
+ anchored = TRUE
+ plane = MOB_PLANE
+ layer = ABOVE_MOB_LAYER
+ density = FALSE
+ invisibility = 0
+ var/obj/machinery/power/shield_generator/gen = null // Owning generator
+ var/disabled_for = 0
+ var/diffused_for = 0
+ can_atmos_pass = ATMOS_PASS_YES
+
+/obj/effect/shield/update_icon()
+ if(gen && gen.check_flag(MODEFLAG_PHOTONIC) && !disabled_for && !diffused_for)
+ set_opacity(1)
+ else
+ set_opacity(0)
+
+ if(gen && gen.check_flag(MODEFLAG_OVERCHARGE))
+ icon_state = "shield_overcharged"
+ else
+ icon_state = "shield_normal"
+
+ if(density)
+ set_light(3, 3, "#66FFFF")
+ else
+ set_light(0)
+
+
+// Prevents singularities and pretty much everything else from moving the field segments away.
+// The only thing that is allowed to move us is the Destroy() proc.
+/obj/effect/shield/forceMove()
+ if(QDELING(src))
+ return ..()
+ return 0
+
+/obj/effect/shield/Destroy()
+ if(can_atmos_pass != ATMOS_PASS_YES)
+ update_nearby_tiles()
+ . = ..()
+ if(gen)
+ if(src in gen.field_segments)
+ gen.field_segments -= src
+ if(src in gen.damaged_segments)
+ gen.damaged_segments -= src
+ gen = null
+
+// Temporarily collapses this shield segment.
+/obj/effect/shield/proc/fail(var/duration)
+ if(duration <= 0)
+ return
+
+ if(gen)
+ gen.damaged_segments |= src
+ disabled_for += duration
+ set_density(0)
+ set_invisibility(INVISIBILITY_MAXIMUM)
+ update_nearby_tiles()
+ update_icon()
+ update_explosion_resistance()
+
+
+// Regenerates this shield segment.
+/obj/effect/shield/proc/regenerate()
+ if(!gen)
+ return
+
+ disabled_for = max(0, disabled_for - 1)
+ diffused_for = max(0, diffused_for - 1)
+
+ if(!disabled_for && !diffused_for)
+ set_density(1)
+ set_invisibility(0)
+ update_nearby_tiles()
+ update_icon()
+ update_explosion_resistance()
+ gen.damaged_segments -= src
+
+
+/obj/effect/shield/proc/diffuse(var/duration)
+ // The shield is trying to counter diffusers. Cause lasting stress on the shield.
+ if(gen.check_flag(MODEFLAG_BYPASS) && !disabled_for)
+ take_damage(duration * rand(8, 12), SHIELD_DAMTYPE_EM)
+ return
+
+ diffused_for = max(duration, 0)
+ gen.damaged_segments |= src
+ set_density(0)
+ set_invisibility(INVISIBILITY_MAXIMUM)
+ update_nearby_tiles()
+ update_icon()
+ update_explosion_resistance()
+
+/obj/effect/shield/attack_generic(var/source, var/damage, var/emote)
+ take_damage(damage, SHIELD_DAMTYPE_PHYSICAL)
+ if(gen.check_flag(MODEFLAG_OVERCHARGE) && istype(source, /mob/living/))
+ overcharge_shock(source)
+ ..(source, damage, emote)
+
+
+// Fails shield segments in specific range. Range of 1 affects the shielded turf only.
+/obj/effect/shield/proc/fail_adjacent_segments(var/range, var/hitby = null)
+ if(hitby)
+ visible_message("\The [src] flashes a bit as \the [hitby] collides with it, eventually fading out in a rain of sparks!")
+ else
+ visible_message("\The [src] flashes a bit as it eventually fades out in a rain of sparks!")
+ fail(range * 2)
+
+ for(var/obj/effect/shield/S in range(range, src))
+ // Don't affect shields owned by other shield generators
+ if(S.gen != src.gen)
+ continue
+ // The closer we are to impact site, the longer it takes for shield to come back up.
+ S.fail(-(-range + get_dist(src, S)) * 2)
+
+// Small visual effect, makes the shield tiles brighten up by becoming more opaque for a moment, and spreads to nearby shields.
+/obj/effect/shield/proc/flash_adjacent_segments(var/range)
+ range = between(1, range, 10) // Sanity check
+ for(var/obj/effect/shield/S in range(range, src))
+ // Don't affect shields owned by other shield generators
+ if(S.gen != src.gen || S == src)
+ continue
+ // Note: Range is a non-exact aproximation of the spread effect. If it doesn't look good
+ // we'll need to switch to actually walking along the shields to get exact number of steps away.
+ addtimer(CALLBACK(S, .proc/impact_flash), get_dist(src, S) * 2)
+ impact_flash()
+
+// Small visual effect, makes the shield tiles brighten up by becoming more opaque for a moment
+/obj/effect/shield/proc/impact_flash()
+ alpha = 100
+ animate(src, alpha = initial(alpha), time = 1 SECOND)
+
+// Just for fun
+/obj/effect/shield/attack_hand(var/user)
+ flash_adjacent_segments(3)
+
+/obj/effect/shield/take_damage(var/damage, var/damtype, var/hitby)
+ if(!gen)
+ qdel(src)
+ return
+
+ if(!damtype)
+ crash_with("CANARY: shield.take_damage() callled without damtype.")
+
+ if(!damage)
+ return
+
+ damage = round(damage)
+
+ new /obj/effect/temp_visual/shield_impact_effect(get_turf(src))
+
+ switch(gen.deal_shield_damage(damage, damtype))
+ if(SHIELD_ABSORBED)
+ flash_adjacent_segments(round(damage/10)) // Nice visual effect only.
+ return
+ if(SHIELD_BREACHED_MINOR)
+ fail_adjacent_segments(rand(1, 3), hitby)
+ return
+ if(SHIELD_BREACHED_MAJOR)
+ fail_adjacent_segments(rand(2, 5), hitby)
+ return
+ if(SHIELD_BREACHED_CRITICAL)
+ fail_adjacent_segments(rand(4, 8), hitby)
+ return
+ if(SHIELD_BREACHED_FAILURE)
+ fail_adjacent_segments(rand(8, 16), hitby)
+ return
+
+
+// As we have various shield modes, this handles whether specific things can pass or not.
+/obj/effect/shield/CanAllowThrough(var/atom/movable/mover, var/turf/target)
+ . = ..()
+ // Somehow we don't have a generator. This shouldn't happen. Delete the shield.
+ if(!gen)
+ qdel(src)
+ return 1
+
+ if(disabled_for || diffused_for)
+ return 1
+
+ if(mover)
+ return mover.can_pass_shield(gen)
+ return 1
+
+/obj/effect/shield/proc/set_can_atmos_pass(var/new_value)
+ if(new_value == can_atmos_pass)
+ return
+ can_atmos_pass = new_value
+ update_nearby_tiles()
+
+
+// EMP. It may seem weak but keep in mind that multiple shield segments are likely to be affected.
+/obj/effect/shield/emp_act(var/severity)
+ if(!disabled_for)
+ take_damage(rand(30,60) / severity, SHIELD_DAMTYPE_EM)
+
+
+// Explosions
+/obj/effect/shield/ex_act(var/severity)
+ if(!disabled_for)
+ take_damage(rand(10,15) / severity, SHIELD_DAMTYPE_PHYSICAL)
+
+
+// Fire
+/obj/effect/shield/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ if(!disabled_for)
+ take_damage(rand(5,10), SHIELD_DAMTYPE_HEAT)
+
+
+// Projectiles
+/obj/effect/shield/bullet_act(var/obj/item/projectile/proj)
+ if(proj.damage_type == BURN)
+ take_damage(proj.get_structure_damage(), SHIELD_DAMTYPE_HEAT)
+ else if (proj.damage_type == BRUTE)
+ take_damage(proj.get_structure_damage(), SHIELD_DAMTYPE_PHYSICAL)
+ else
+ take_damage(proj.get_structure_damage(), SHIELD_DAMTYPE_EM)
+
+
+// Attacks with hand tools. Blocked by Hyperkinetic flag.
+/obj/effect/shield/attackby(var/obj/item/I as obj, var/mob/user as mob)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.do_attack_animation(src)
+
+ if(gen.check_flag(MODEFLAG_HYPERKINETIC))
+ user.visible_message("\The [user] hits \the [src] with \the [I]!")
+ if(I.damtype == BURN)
+ take_damage(I.force, SHIELD_DAMTYPE_HEAT)
+ else if (I.damtype == BRUTE)
+ take_damage(I.force, SHIELD_DAMTYPE_PHYSICAL)
+ else
+ take_damage(I.force, SHIELD_DAMTYPE_EM)
+ else
+ user.visible_message("\The [user] tries to attack \the [src] with \the [I], but it passes through!")
+
+
+// Special treatment for meteors because they would otherwise penetrate right through the shield.
+/obj/effect/shield/Bumped(var/atom/movable/mover)
+ if(!gen)
+ qdel(src)
+ return 0
+ mover.shield_impact(src)
+ return ..()
+
+// Meteors call this instad of Bumped for some reason
+/obj/effect/shield/handle_meteor_impact(var/obj/effect/meteor/meteor)
+ meteor.shield_impact(src)
+ return !QDELETED(meteor) // If it was stopped it will have been deleted
+
+/obj/effect/shield/proc/overcharge_shock(var/mob/living/M)
+ M.adjustFireLoss(rand(20, 40))
+ M.Weaken(5)
+ to_chat(M, "As you come into contact with \the [src] a surge of energy paralyses you!")
+ take_damage(10, SHIELD_DAMTYPE_EM)
+
+// Called when a flag is toggled. Can be used to add on-toggle behavior, such as visual changes.
+/obj/effect/shield/proc/flags_updated()
+ if(!gen)
+ qdel(src)
+ return
+
+ // Update airflow - If atmospheric we block air as long as we're enabled (density works for this)
+ set_can_atmos_pass(gen.check_flag(MODEFLAG_ATMOSPHERIC) ? ATMOS_PASS_DENSITY : ATMOS_PASS_YES)
+ update_icon()
+ update_explosion_resistance()
+
+/obj/effect/shield/proc/update_explosion_resistance()
+ if(gen && gen.check_flag(MODEFLAG_HYPERKINETIC))
+ explosion_resistance = INFINITY
+ else
+ explosion_resistance = 0
+
+//
+// Visual effect of shield taking impact
+//
+/obj/effect/temp_visual/shield_impact_effect
+ name = "shield impact"
+ icon = 'icons/obj/machines/shielding_vr.dmi'
+ icon_state = "shield_impact"
+ plane = MOB_PLANE
+ layer = ABOVE_MOB_LAYER
+ duration = 2 SECONDS
+ randomdir = FALSE
+
+//
+// Shield collision checks below
+//
+
+// Called only if shield is active/not destroyed etc.
+/atom/movable/proc/can_pass_shield(var/obj/machinery/power/shield_generator/gen)
+ return 1
+
+
+// Other mobs
+/mob/living/can_pass_shield(var/obj/machinery/power/shield_generator/gen)
+ return !gen.check_flag(MODEFLAG_NONHUMANS)
+
+// Human mobs
+/mob/living/carbon/human/can_pass_shield(var/obj/machinery/power/shield_generator/gen)
+ if(isSynthetic())
+ return !gen.check_flag(MODEFLAG_ANORGANIC)
+ return !gen.check_flag(MODEFLAG_HUMANOIDS)
+
+// Silicon mobs
+/mob/living/silicon/can_pass_shield(var/obj/machinery/power/shield_generator/gen)
+ return !gen.check_flag(MODEFLAG_ANORGANIC)
+
+
+// Generic objects. Also applies to bullets and meteors.
+/obj/can_pass_shield(var/obj/machinery/power/shield_generator/gen)
+ return !gen.check_flag(MODEFLAG_HYPERKINETIC)
+
+// Beams
+/obj/item/projectile/beam/can_pass_shield(var/obj/machinery/power/shield_generator/gen)
+ return !gen.check_flag(MODEFLAG_PHOTONIC)
+
+
+// Shield on-impact logic here. This is called only if the object is actually blocked by the field (can_pass_shield applies first)
+/atom/movable/proc/shield_impact(var/obj/effect/shield/S)
+ return
+
+/mob/living/shield_impact(var/obj/effect/shield/S)
+ if(!S.gen.check_flag(MODEFLAG_OVERCHARGE))
+ return
+ S.overcharge_shock(src)
+
+/obj/effect/meteor/shield_impact(var/obj/effect/shield/S)
+ if(!S.gen.check_flag(MODEFLAG_HYPERKINETIC))
+ return
+ S.take_damage(get_shield_damage(), SHIELD_DAMTYPE_PHYSICAL, src)
+ visible_message("\The [src] breaks into dust!")
+ make_debris()
+ qdel(src)
diff --git a/code/modules/shieldgen/handheld_defuser.dm b/code/modules/shieldgen/handheld_defuser.dm
index de395d769ac..4fadd6a77c9 100644
--- a/code/modules/shieldgen/handheld_defuser.dm
+++ b/code/modules/shieldgen/handheld_defuser.dm
@@ -1,9 +1,10 @@
/obj/item/shield_diffuser
name = "portable shield diffuser"
- desc = "A small handheld device designed to disrupt energy barriers"
+ desc = "A small handheld device designed to disrupt energy barriers."
description_info = "This device disrupts shields on directly adjacent tiles (in a + shaped pattern), in a similar way the floor mounted variant does. It is, however, portable and run by an internal battery. Can be recharged with a regular recharger."
icon = 'icons/obj/machines/shielding.dmi'
icon_state = "hdiffuser_off"
+ origin_tech = list(TECH_MAGNET = 5, TECH_POWER = 5, TECH_ILLEGAL = 2)
w_class = ITEMSIZE_SMALL
var/obj/item/cell/device/cell = /obj/item/cell/device
var/enabled = 0
@@ -25,10 +26,15 @@
/obj/item/shield_diffuser/process(delta_time)
if(!enabled)
- return
+ return PROCESS_KILL
for(var/direction in GLOB.cardinal)
var/turf/simulated/shielded_tile = get_step(get_turf(src), direction)
+ for(var/obj/effect/shield/S in shielded_tile)
+ // 10kJ per pulse, but gap in the shield lasts for longer than regular diffusers.
+ if(istype(S) && !S.diffused_for && !S.disabled_for && cell.checked_use(10 KILOWATTS * CELLRATE))
+ S.diffuse(20)
+ // Legacy shield support
for(var/obj/effect/energy_field/S in shielded_tile)
if(istype(S) && cell.checked_use(10 KILOWATTS * CELLRATE))
qdel(S)
@@ -39,19 +45,19 @@
else
icon_state = "hdiffuser_off"
-/obj/item/shield_diffuser/attack_self()
+/obj/item/shield_diffuser/attack_self(mob/user)
enabled = !enabled
update_icon()
if(enabled)
START_PROCESSING(SSobj, src)
else
STOP_PROCESSING(SSobj, src)
- to_chat(usr, "You turn \the [src] [enabled ? "on" : "off"].")
+ to_chat(user, "You turn \the [src] [enabled ? "on" : "off"].")
-/obj/item/shield_diffuser/examine()
+/obj/item/shield_diffuser/examine(mob/user)
. = ..()
- to_chat(usr, "The charge meter reads [cell ? cell.percent() : 0]%")
- to_chat(usr, "It is [enabled ? "enabled" : "disabled"].")
+ to_chat(user, "The charge meter reads [cell ? cell.percent() : 0]%")
+ to_chat(user, "It is [enabled ? "enabled" : "disabled"].")
/obj/item/shield_diffuser/attack_hand(mob/user as mob)
if(user.get_inactive_hand() == src)
diff --git a/code/modules/shieldgen/shield_diffuser.dm b/code/modules/shieldgen/shield_diffuser.dm
index 44e96e1a5f7..94344b4f401 100644
--- a/code/modules/shieldgen/shield_diffuser.dm
+++ b/code/modules/shieldgen/shield_diffuser.dm
@@ -4,28 +4,34 @@
description_info = "This device disrupts shields on directly adjacent tiles (in a + shaped pattern). They are commonly installed around exterior airlocks to prevent shields from blocking EVA access."
icon = 'icons/obj/machines/shielding.dmi'
icon_state = "fdiffuser_on"
+ circuit = /obj/item/circuitboard/shield_diffuser
use_power = USE_POWER_ACTIVE
idle_power_usage = 25 // Previously 100.
active_power_usage = 500 // Previously 2000
- anchored = 1
- density = 0
+ anchored = TRUE
+ density = FALSE
level = 1
- var/alarm = 0
- var/enabled = 1
+ var/alarm = FALSE
+ var/enabled = TRUE
/obj/machinery/shield_diffuser/Initialize(mapload)
. = ..()
+ // TODO - Remove this bit once machines are converted to Initialize
+ if(ispath(circuit))
+ circuit = new circuit(src)
+ default_apply_parts()
+
var/turf/T = get_turf(src)
hide(!T.is_plating())
-//If underfloor, hide the cable
+//If underfloor, hide the cable^H^H diffuser
/obj/machinery/shield_diffuser/hide(var/i)
if(istype(loc, /turf))
invisibility = i ? 101 : 0
update_icon()
/obj/machinery/shield_diffuser/hides_under_flooring()
- return 1
+ return TRUE
/obj/machinery/shield_diffuser/process(delta_time)
if(alarm)
@@ -38,6 +44,9 @@
return
for(var/direction in GLOB.cardinal)
var/turf/simulated/shielded_tile = get_step(get_turf(src), direction)
+ for(var/obj/effect/shield/S in shielded_tile)
+ S.diffuse(5)
+ // Legacy shield support
for(var/obj/effect/energy_field/S in shielded_tile)
qdel(S)
@@ -50,16 +59,27 @@
else
icon_state = "fdiffuser_on"
-/obj/machinery/shield_diffuser/attack_hand()
+/obj/machinery/shield_diffuser/attack_hand(mob/user as mob)
+ if((. = ..()))
+ return
if(alarm)
- to_chat(usr, "You press an override button on \the [src], re-enabling it.")
+ to_chat(user, "You press an override button on \the [src], re-enabling it.")
alarm = 0
update_icon()
return
enabled = !enabled
update_use_power(enabled ? USE_POWER_ACTIVE : USE_POWER_IDLE)
update_icon()
- to_chat(usr, "You turn \the [src] [enabled ? "on" : "off"].")
+ to_chat(user, "You turn \the [src] [enabled ? "on" : "off"].")
+
+/obj/machinery/shield_diffuser/attackby(var/obj/item/W, var/mob/user)
+ if(default_deconstruction_screwdriver(user, W))
+ return
+ if(default_deconstruction_crowbar(user, W))
+ return
+ if(default_part_replacement(user, W))
+ return
+ return ..()
/obj/machinery/shield_diffuser/proc/meteor_alarm(var/duration)
if(!duration)
@@ -69,6 +89,6 @@
/obj/machinery/shield_diffuser/examine(var/mob/user)
. = ..()
- . += "It is [enabled ? "enabled" : "disabled"]."
+ to_chat(user, "It is [enabled ? "enabled" : "disabled"].")
if(alarm)
- . += "A red LED labeled \"Proximity Alarm\" is blinking on the control panel."
+ to_chat(user, "A red LED labeled \"Proximity Alarm\" is blinking on the control panel.")
diff --git a/code/modules/shieldgen/shield_generator.dm b/code/modules/shieldgen/shield_generator.dm
new file mode 100644
index 00000000000..cced3108303
--- /dev/null
+++ b/code/modules/shieldgen/shield_generator.dm
@@ -0,0 +1,562 @@
+//
+// This generator is for the supercool big shields intended for ships that do nice stuff with overmaps.
+//
+/obj/machinery/power/shield_generator
+ name = "advanced shield generator"
+ desc = "A heavy-duty shield generator and capacitor, capable of generating energy shields at large distances."
+ icon = 'icons/obj/machines/shielding_vr.dmi'
+ icon_state = "generator0"
+ circuit = /obj/item/circuitboard/shield_generator
+ density = TRUE
+ var/datum/wires/shield_generator/wires = null
+ var/list/field_segments = list() // List of all shield segments owned by this generator.
+ var/list/damaged_segments = list() // List of shield segments that have failed and are currently regenerating.
+ var/shield_modes = 0 // Enabled shield mode flags
+ var/mitigation_em = 0 // Current EM mitigation
+ var/mitigation_physical = 0 // Current Physical mitigation
+ var/mitigation_heat = 0 // Current Burn mitigation
+ var/mitigation_max = 0 // Maximal mitigation reachable with this generator. Set by RefreshParts()
+ var/max_energy = 0 // Maximal stored energy. In joules. Depends on the type of used SMES coil when constructing this generator.
+ var/current_energy = 0 // Current stored energy.
+ var/field_radius = 1 // Current field radius.
+ var/target_radius = 1 // Desired field radius.
+ var/running = SHIELD_OFF // Whether the generator is enabled or not.
+ var/input_cap = 1 MEGAWATTS // Currently set input limit. Set to 0 to disable limits altogether. The shield will try to input this value per tick at most
+ var/upkeep_power_usage = 0 // Upkeep power usage last tick.
+ var/upkeep_multiplier = 1 // Multiplier of upkeep values.
+ var/power_coefficient = 1 // Multiplier of overall power usage (for mappers, subtypes, etc)
+ var/power_usage = 0 // Total power usage last tick.
+ var/overloaded = 0 // Whether the field has overloaded and shut down to regenerate.
+ var/hacked = 0 // Whether the generator has been hacked by cutting the safety wire.
+ var/offline_for = 0 // The generator will be inoperable for this duration in ticks.
+ var/input_cut = 0 // Whether the input wire is cut.
+ var/mode_changes_locked = 0 // Whether the control wire is cut, locking out changes.
+ var/ai_control_disabled = 0 // Whether the AI control is disabled.
+ var/list/mode_list = null // A list of shield_mode datums.
+ var/full_shield_strength = 0 // The amount of power shields need to be at full operating strength.
+ var/initial_shield_modes = MODEFLAG_HYPERKINETIC|MODEFLAG_EM|MODEFLAG_ATMOSPHERIC|MODEFLAG_HUMANOIDS
+
+ var/idle_multiplier = 1 // Trades off cost vs. spin-up time from idle to running
+ var/idle_valid_values = list(1, 2, 5, 10)
+ var/spinup_delay = 20
+ var/spinup_counter = 0
+
+/obj/machinery/power/shield_generator/update_icon()
+ if(running)
+ icon_state = "generator1"
+ set_light(1, 2, "#66FFFF")
+ else
+ icon_state = "generator0"
+ set_light(0)
+
+
+/obj/machinery/power/shield_generator/Initialize()
+ . = ..()
+ if(!wires)
+ wires = new(src)
+ // TODO - Remove this bit once machines are converted to Initialize
+ if(ispath(circuit))
+ circuit = new circuit(src)
+ default_apply_parts()
+ connect_to_network()
+
+ mode_list = list()
+ for(var/st in subtypesof(/datum/shield_mode))
+ var/datum/shield_mode/SM = new st()
+ mode_list.Add(SM)
+ toggle_flag(initial_shield_modes)
+
+/obj/machinery/power/shield_generator/Destroy()
+ shutdown_field()
+ field_segments = null
+ damaged_segments = null
+ mode_list = null
+ . = ..()
+
+
+/obj/machinery/power/shield_generator/RefreshParts()
+ max_energy = 0
+ full_shield_strength = 0
+ for(var/obj/item/smes_coil/S in component_parts)
+ full_shield_strength += (S.ChargeCapacity * 5)
+ max_energy = full_shield_strength * 20
+ current_energy = between(0, current_energy, max_energy)
+
+ mitigation_max = MAX_MITIGATION_BASE + MAX_MITIGATION_RESEARCH * total_component_rating_of_type(/obj/item/stock_parts/capacitor)
+ mitigation_em = between(0, mitigation_em, mitigation_max)
+ mitigation_physical = between(0, mitigation_physical, mitigation_max)
+ mitigation_heat = between(0, mitigation_heat, mitigation_max)
+ ..()
+
+
+// Shuts down the shield, removing all shield segments and unlocking generator settings.
+/obj/machinery/power/shield_generator/proc/shutdown_field()
+ for(var/obj/effect/shield/S in field_segments)
+ qdel(S)
+
+ running = SHIELD_OFF
+ current_energy = 0
+ mitigation_em = 0
+ mitigation_physical = 0
+ mitigation_heat = 0
+ update_icon()
+
+
+// Generates the field objects. Deletes existing field, if applicable.
+/obj/machinery/power/shield_generator/proc/regenerate_field()
+ if(field_segments.len)
+ for(var/obj/effect/shield/S in field_segments)
+ qdel(S)
+
+ // The generator is not turned on, so don't generate any new tiles.
+ if(!running)
+ return
+
+ var/list/shielded_turfs
+
+ if(check_flag(MODEFLAG_HULL))
+ shielded_turfs = fieldtype_hull()
+ else
+ shielded_turfs = fieldtype_square()
+
+ for(var/turf/T in shielded_turfs)
+ var/obj/effect/shield/S = new(T)
+ S.gen = src
+ S.flags_updated()
+ field_segments |= S
+ update_icon()
+
+
+// Recalculates and updates the upkeep multiplier
+/obj/machinery/power/shield_generator/proc/update_upkeep_multiplier()
+ var/new_upkeep = 1.0
+ for(var/datum/shield_mode/SM in mode_list)
+ if(check_flag(SM.mode_flag))
+ new_upkeep *= SM.multiplier
+
+ upkeep_multiplier = new_upkeep * power_coefficient
+
+
+/obj/machinery/power/shield_generator/process()
+ upkeep_power_usage = 0
+ power_usage = 0
+
+ if(offline_for)
+ offline_for = max(0, offline_for - 1)
+ // We're turned off.
+ if(running == SHIELD_OFF)
+ return
+
+ if(target_radius != field_radius && running != SHIELD_RUNNING) // Do not recalculate the field while it's running; that's extremely laggy.
+ field_radius += (target_radius > field_radius) ? 1 : -1
+
+ // We are shutting down, therefore our stored energy disperses faster than usual.
+ else if(running == SHIELD_DISCHARGING)
+ current_energy -= SHIELD_SHUTDOWN_DISPERSION_RATE
+ else if(running == SHIELD_SPINNING_UP)
+ spinup_counter--
+ if(spinup_counter <= 0)
+ running = SHIELD_RUNNING
+ regenerate_field()
+
+ mitigation_em = between(0, mitigation_em - MITIGATION_LOSS_PASSIVE, mitigation_max)
+ mitigation_heat = between(0, mitigation_heat - MITIGATION_LOSS_PASSIVE, mitigation_max)
+ mitigation_physical = between(0, mitigation_physical - MITIGATION_LOSS_PASSIVE, mitigation_max)
+
+ if(running == SHIELD_RUNNING)
+ upkeep_power_usage = round((field_segments.len - damaged_segments.len) * ENERGY_UPKEEP_PER_TILE * upkeep_multiplier)
+ else if(running > SHIELD_RUNNING)
+ upkeep_power_usage = round(ENERGY_UPKEEP_IDLE * idle_multiplier * (field_radius * 8) * upkeep_multiplier) // Approximates number of turfs.
+
+ if(powernet && (running >= SHIELD_RUNNING) && !input_cut)
+ var/energy_buffer = 0
+ energy_buffer = draw_power(min(upkeep_power_usage, input_cap))
+ power_usage += round(energy_buffer)
+
+ if(energy_buffer < upkeep_power_usage)
+ current_energy -= round(upkeep_power_usage - energy_buffer) // If we don't have enough energy from the grid, take it from the internal battery instead.
+
+ // Now try to recharge our internal energy.
+ var/energy_to_demand
+ if(input_cap)
+ energy_to_demand = between(0, max_energy - current_energy, input_cap - energy_buffer)
+ else
+ energy_to_demand = max(0, max_energy - current_energy)
+ energy_buffer = draw_power(energy_to_demand)
+ power_usage += energy_buffer
+ current_energy += round(energy_buffer)
+ else
+ current_energy -= round(upkeep_power_usage) // We are shutting down, or we lack external power connection. Use energy from internal source instead.
+
+ if(current_energy <= 0)
+ energy_failure()
+
+ if(!overloaded)
+ for(var/obj/effect/shield/S in damaged_segments)
+ S.regenerate()
+ else if (field_integrity() > 25)
+ overloaded = 0
+
+/obj/machinery/power/shield_generator/attackby(obj/item/O as obj, mob/user as mob)
+ if(panel_open && (O?.is_multitool() || O?.is_wirecutter()))
+ wires.Interact(user)
+ return TRUE
+ if(default_deconstruction_screwdriver(user, O))
+ return
+ if(O?.is_crowbar() || O?.is_wrench() || istype(O, /obj/item/storage/part_replacer))
+ if(offline_for)
+ to_chat(user, "Wait until \the [src] cools down from emergency shutdown first!")
+ return
+ if(running)
+ to_chat(user, "Turn off \the [src] first!")
+ return
+ if(default_deconstruction_crowbar(user, O))
+ return
+ if(default_part_replacement(user, O))
+ return
+ if(default_unfasten_wrench(user, O, 40))
+ return
+ return ..()
+
+/obj/machinery/power/shield_generator/proc/energy_failure()
+ if(running == SHIELD_DISCHARGING)
+ shutdown_field()
+ else
+ current_energy = 0
+ overloaded = 1
+ for(var/obj/effect/shield/S in field_segments)
+ S.fail(1)
+
+/obj/machinery/power/shield_generator/proc/set_idle(var/new_state)
+ if(new_state)
+ if(running == SHIELD_IDLE)
+ return
+ running = SHIELD_IDLE
+ for(var/obj/effect/shield/S in field_segments)
+ qdel(S)
+ else
+ if(running != SHIELD_IDLE)
+ return
+ running = SHIELD_SPINNING_UP
+ spinup_counter = round(spinup_delay / idle_multiplier)
+ update_icon()
+
+/obj/machinery/power/shield_generator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
+ var/data[0]
+
+ data["running"] = running
+ data["modes"] = get_flag_descriptions()
+ data["overloaded"] = overloaded
+ data["mitigation_max"] = mitigation_max
+ data["mitigation_physical"] = round(mitigation_physical, 0.1)
+ data["mitigation_em"] = round(mitigation_em, 0.1)
+ data["mitigation_heat"] = round(mitigation_heat, 0.1)
+ data["field_integrity"] = field_integrity()
+ data["max_energy"] = round(max_energy / 1000000, 0.1)
+ data["current_energy"] = round(current_energy / 1000000, 0.1)
+ data["percentage_energy"] = round(data["current_energy"] / data["max_energy"] * 100)
+ data["total_segments"] = field_segments ? field_segments.len : 0
+ data["functional_segments"] = damaged_segments ? data["total_segments"] - damaged_segments.len : data["total_segments"]
+ data["field_radius"] = field_radius
+ data["target_radius"] = target_radius
+ data["input_cap_kw"] = round(input_cap / 1000)
+ data["upkeep_power_usage"] = round(upkeep_power_usage / 1000, 0.1)
+ data["power_usage"] = round(power_usage / 1000)
+ data["hacked"] = hacked
+ data["offline_for"] = offline_for * 2
+ data["idle_multiplier"] = idle_multiplier
+ data["idle_valid_values"] = idle_valid_values
+ data["spinup_counter"] = spinup_counter
+
+ ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
+ if (!ui)
+ ui = new(user, src, ui_key, "shield_generator.tmpl", src.name, 500, 800)
+ ui.set_initial_data(data)
+ ui.open()
+ ui.set_auto_update(1)
+
+/obj/machinery/power/shield_generator/attack_hand(mob/user)
+ if((. = ..()))
+ return
+ if(panel_open && Adjacent(user))
+ wires.Interact(user)
+ return
+ if(CanUseTopic(user, global.default_state) > UI_CLOSE)
+ ui_interact(user)
+ return TRUE
+
+/obj/machinery/power/shield_generator/CanUseTopic(var/mob/user)
+ if(issilicon(user) && !Adjacent(user) && ai_control_disabled)
+ return UI_UPDATE
+ if(panel_open)
+ return min(..(), UI_DISABLED)
+ return ..()
+
+/obj/machinery/power/shield_generator/Topic(href, href_list, datum/topic_state/state = default_state)
+ if((. = ..()))
+ return
+
+ if(href_list["begin_shutdown"])
+ if(running < SHIELD_RUNNING) // Discharging or off
+ return
+ var/alert = alert(usr, "Are you sure you wish to do this? It will drain the power inside the internal storage rapidly.", "Are you sure?", "Yes", "No")
+ if(!CanInteract(usr, state))
+ return
+ if(running < SHIELD_RUNNING)
+ return
+ if(alert == "Yes")
+ set_idle(TRUE) // do this first to clear the field
+ running = SHIELD_DISCHARGING
+ return TOPIC_REFRESH
+
+ if(href_list["start_generator"])
+ if(offline_for)
+ return
+ set_idle(TRUE)
+ return TOPIC_REFRESH
+
+ if(href_list["toggle_idle"])
+ if(running < SHIELD_RUNNING)
+ return TOPIC_HANDLED
+ set_idle(text2num(href_list["toggle_idle"]))
+ return TOPIC_REFRESH
+
+ // Instantly drops the shield, but causes a cooldown before it may be started again. Also carries a risk of EMP at high charge.
+ if(href_list["emergency_shutdown"])
+ if(!running)
+ return TOPIC_HANDLED
+
+ var/choice = input(usr, "Are you sure that you want to initiate an emergency shield shutdown? This will instantly drop the shield, and may result in unstable release of stored electromagnetic energy. Proceed at your own risk.") in list("Yes", "No")
+ if((choice != "Yes") || !running)
+ return TOPIC_HANDLED
+
+ // If the shield would take 5 minutes to disperse and shut down using regular methods, it will take x1.5 (7 minutes and 30 seconds) of this time to cool down after emergency shutdown
+ offline_for = round(current_energy / (SHIELD_SHUTDOWN_DISPERSION_RATE / 1.5))
+ var/old_energy = current_energy
+ shutdown_field()
+ log_and_message_admins("has triggered \the [src]'s emergency shutdown!", usr)
+ spawn()
+ empulse(src, old_energy / 60000000, old_energy / 32000000, 1) // If shields are charged at 450 MJ, the EMP will be 7.5, 14.0625. 90 MJ, 1.5, 2.8125
+ old_energy = 0
+
+ return TOPIC_REFRESH
+
+ if(mode_changes_locked)
+ return TOPIC_REFRESH
+
+ if(href_list["set_range"])
+ var/new_range = input(usr, "Enter new field range (1-[world.maxx]). Leave blank to cancel.", "Field Radius Control", field_radius) as num
+ if(!new_range)
+ return TOPIC_HANDLED
+ target_radius = between(1, new_range, world.maxx)
+ return TOPIC_REFRESH
+
+ if(href_list["set_input_cap"])
+ var/new_cap = round(input(usr, "Enter new input cap (in kW). Enter 0 or nothing to disable input cap.", "Generator Power Control", round(input_cap / 1000)) as num)
+ if(!new_cap)
+ input_cap = 0
+ return
+ input_cap = max(0, new_cap) * 1000
+ return TOPIC_REFRESH
+
+ if(href_list["toggle_mode"])
+ // Toggling hacked-only modes requires the hacked var to be set to 1
+ if((text2num(href_list["toggle_mode"]) & (MODEFLAG_BYPASS | MODEFLAG_OVERCHARGE)) && !hacked)
+ return TOPIC_HANDLED
+
+ toggle_flag(text2num(href_list["toggle_mode"]))
+ return TOPIC_REFRESH
+
+ if(href_list["switch_idle"])
+ if(running == SHIELD_SPINNING_UP)
+ return TOPIC_REFRESH
+ var/new_idle = text2num(href_list["switch_idle"])
+ if(new_idle in idle_valid_values)
+ idle_multiplier = new_idle
+ return TOPIC_REFRESH
+
+/obj/machinery/power/shield_generator/proc/field_integrity()
+ if(full_shield_strength)
+ return round(CLAMP01(current_energy / full_shield_strength) * 100)
+ return 0
+
+
+// Takes specific amount of damage
+/obj/machinery/power/shield_generator/proc/deal_shield_damage(var/damage, var/shield_damtype)
+ var/energy_to_use = damage * ENERGY_PER_HP
+ if(check_flag(MODEFLAG_MODULATE))
+ mitigation_em -= MITIGATION_HIT_LOSS
+ mitigation_heat -= MITIGATION_HIT_LOSS
+ mitigation_physical -= MITIGATION_HIT_LOSS
+
+ switch(shield_damtype)
+ if(SHIELD_DAMTYPE_PHYSICAL)
+ mitigation_physical += MITIGATION_HIT_LOSS + MITIGATION_HIT_GAIN
+ energy_to_use *= 1 - (mitigation_physical / 100)
+ if(SHIELD_DAMTYPE_EM)
+ mitigation_em += MITIGATION_HIT_LOSS + MITIGATION_HIT_GAIN
+ energy_to_use *= 1 - (mitigation_em / 100)
+ if(SHIELD_DAMTYPE_HEAT)
+ mitigation_heat += MITIGATION_HIT_LOSS + MITIGATION_HIT_GAIN
+ energy_to_use *= 1 - (mitigation_heat / 100)
+
+ mitigation_em = between(0, mitigation_em, mitigation_max)
+ mitigation_heat = between(0, mitigation_heat, mitigation_max)
+ mitigation_physical = between(0, mitigation_physical, mitigation_max)
+
+ current_energy -= energy_to_use
+
+ // Overload the shield, which will shut it down until we recharge above 25% again
+ if(current_energy < 0)
+ energy_failure()
+ return SHIELD_BREACHED_FAILURE
+
+ if(prob(10 - field_integrity()))
+ return SHIELD_BREACHED_CRITICAL
+ if(prob(20 - field_integrity()))
+ return SHIELD_BREACHED_MAJOR
+ if(prob(35 - field_integrity()))
+ return SHIELD_BREACHED_MINOR
+ return SHIELD_ABSORBED
+
+
+// Checks whether specific flags are enabled
+/obj/machinery/power/shield_generator/proc/check_flag(var/flag)
+ return (shield_modes & flag)
+
+
+/obj/machinery/power/shield_generator/proc/toggle_flag(var/flag)
+ shield_modes ^= flag
+ update_upkeep_multiplier()
+ for(var/obj/effect/shield/S in field_segments)
+ S.flags_updated()
+
+ if((flag & (MODEFLAG_HULL|MODEFLAG_MULTIZ)) && (running == SHIELD_RUNNING))
+ regenerate_field()
+
+ if(flag & MODEFLAG_MODULATE)
+ mitigation_em = 0
+ mitigation_physical = 0
+ mitigation_heat = 0
+
+
+/obj/machinery/power/shield_generator/proc/get_flag_descriptions()
+ var/list/all_flags = list()
+ for(var/datum/shield_mode/SM in mode_list)
+ if(SM.hacked_only && !hacked)
+ continue
+ all_flags.Add(list(list(
+ "name" = SM.mode_name,
+ "desc" = SM.mode_desc,
+ "flag" = SM.mode_flag,
+ "status" = check_flag(SM.mode_flag),
+ "hacked" = SM.hacked_only,
+ "multiplier" = SM.multiplier
+ )))
+ return all_flags
+
+
+// These two procs determine tiles that should be shielded given the field range. They are quite CPU intensive and may trigger BYOND infinite loop checks, therefore they are set
+// as background procs to prevent locking up the server. They are only called when the field is generated, or when hull mode is toggled on/off.
+/obj/machinery/power/shield_generator/proc/fieldtype_square()
+ set background = 1
+ var/list/out = list()
+ var/list/base_turfs = get_base_turfs()
+
+ for(var/turf/gen_turf in base_turfs)
+ var/turf/T
+ for (var/x_offset = -field_radius; x_offset <= field_radius; x_offset++)
+ T = locate(gen_turf.x + x_offset, gen_turf.y - field_radius, gen_turf.z)
+ if(T)
+ out += T
+ T = locate(gen_turf.x + x_offset, gen_turf.y + field_radius, gen_turf.z)
+ if(T)
+ out += T
+
+ for (var/y_offset = -field_radius+1; y_offset < field_radius; y_offset++)
+ T = locate(gen_turf.x - field_radius, gen_turf.y + y_offset, gen_turf.z)
+ if(T)
+ out += T
+ T = locate(gen_turf.x + field_radius, gen_turf.y + y_offset, gen_turf.z)
+ if(T)
+ out += T
+ return out
+
+
+/obj/machinery/power/shield_generator/proc/fieldtype_hull()
+ set background = 1
+ . = list()
+ var/list/base_turfs = get_base_turfs()
+
+ // Old code found all space turfs and added them if it had a non-space neighbor.
+ // This one finds all non-space turfs and adds all its non-space neighbors.
+ for(var/turf/gen_turf in base_turfs)
+ var/area/TA = null // Variable for area checking. Defining it here so memory does not have to be allocated repeatedly.
+ for(var/turf/T in trange(field_radius, gen_turf))
+ // Don't expand to space or on shuttle areas.
+ if(istype(T, /turf/space) || istype(T, /turf/simulated/open))
+ continue
+
+ // Find adjacent space/shuttle tiles and cover them. Shuttles won't be blocked if shield diffuser is mapped in and turned on.
+ for(var/turf/TN in orange(1, T))
+ TA = get_area(TN)
+ //if ((istype(TN, /turf/space) || (istype(TN, /turf/simulated/open) && (istype(TA, /area/space) || TA.area_flags & AREA_FLAG_EXTERNAL))))
+ if((istype(TN, /turf/space) || (istype(TN, /turf/simulated/open) && (istype(TA, /area/space)))))
+ . |= TN
+ continue
+
+// Returns a list of turfs from which a field will propagate. If multi-Z mode is enabled, this will return a "column" of turfs above and below the generator.
+/obj/machinery/power/shield_generator/proc/get_base_turfs()
+ var/list/turfs = list()
+ var/turf/T = get_turf(src)
+
+ if(!istype(T))
+ return
+
+ turfs.Add(T)
+
+ // Multi-Z mode is disabled
+ if(!check_flag(MODEFLAG_MULTIZ))
+ return turfs
+
+ while(HasAbove(T.z))
+ T = GetAbove(T)
+ if(istype(T))
+ turfs.Add(T)
+
+ T = get_turf(src)
+
+ while(HasBelow(T.z))
+ T = GetBelow(T)
+ if(istype(T))
+ turfs.Add(T)
+
+ return turfs
+
+
+// Starts fully charged
+/obj/machinery/power/shield_generator/charged/Initialize()
+ . = ..()
+ current_energy = max_energy
+
+// Starts with the best SMES coil and capacitor (and fully charged)
+/obj/machinery/power/shield_generator/upgraded/Initialize()
+ . = ..()
+ for(var/obj/item/smes_coil/sc in component_parts)
+ component_parts -= sc
+ qdel(sc)
+
+ for(var/obj/item/stock_parts/capacitor/cap in component_parts)
+ component_parts -= cap
+ qdel(cap)
+
+ component_parts += new /obj/item/stock_parts/capacitor/omni(src)
+ component_parts += new /obj/item/smes_coil/super_capacity(src)
+ RefreshParts()
+ current_energy = max_energy
+
+// Only uses 20% as much power (and starts upgraded and charged and hacked)
+/obj/machinery/power/shield_generator/upgraded/admin
+ name = "experimental shield generator"
+ power_coefficient = 0.2
+ hacked = TRUE
diff --git a/code/modules/shieldgen/shield_modes.dm b/code/modules/shieldgen/shield_modes.dm
new file mode 100644
index 00000000000..5a889b4c080
--- /dev/null
+++ b/code/modules/shieldgen/shield_modes.dm
@@ -0,0 +1,83 @@
+// Definitions for shield modes. Names, descriptions and power usage multipliers can be changed here.
+// Do not change the mode_flag variables without a good reason!
+
+/datum/shield_mode
+ var/mode_name // User-friendly name of this mode.
+ var/mode_desc // A short description of what the mode does.
+ var/mode_flag // Mode bitflag. See defines file.
+ var/multiplier // Energy usage multiplier. Each enabled mode multiplies upkeep power usage by this number. Values between 1-2 are good balance-wise. Hacked modes can go up to 3-4
+ var/hacked_only = 0 // Set to 1 to allow usage of this shield mode only on hacked generators.
+
+/datum/shield_mode/hyperkinetic
+ mode_name = "Hyperkinetic Projectiles"
+ mode_desc = "This mode blocks various fast moving physical objects, such as bullets, blunt weapons, meteors and other."
+ mode_flag = MODEFLAG_HYPERKINETIC
+ multiplier = 1.2
+
+/datum/shield_mode/photonic
+ mode_name = "Photonic Dispersion"
+ mode_desc = "This mode blocks majority of light. This includes beam weaponry and most of the visible light spectrum."
+ mode_flag = MODEFLAG_PHOTONIC
+ multiplier = 1.3
+
+/datum/shield_mode/em
+ mode_name = "Electro-Magnetic Shielding"
+ mode_desc = "This mode blocks various high-power emissions like electrical storms."
+ mode_flag = MODEFLAG_EM
+ multiplier = 1.3
+
+/datum/shield_mode/humanoids
+ mode_name = "Humanoid Lifeforms"
+ mode_desc = "This mode blocks various humanoid lifeforms. Does not affect fully synthetic humanoids."
+ mode_flag = MODEFLAG_HUMANOIDS
+ multiplier = 1.5
+
+/datum/shield_mode/silicon
+ mode_name = "Silicon Lifeforms"
+ mode_desc = "This mode blocks various silicon based lifeforms."
+ mode_flag = MODEFLAG_ANORGANIC
+ multiplier = 1.5
+
+/datum/shield_mode/mobs
+ mode_name = "Unknown Lifeforms"
+ mode_desc = "This mode blocks various other non-humanoid and non-silicon lifeforms. Typical uses include blocking carps."
+ mode_flag = MODEFLAG_NONHUMANS
+ multiplier = 1.5
+
+/datum/shield_mode/atmosphere
+ mode_name = "Atmospheric Containment"
+ mode_desc = "This mode blocks air flow and acts as atmosphere containment."
+ mode_flag = MODEFLAG_ATMOSPHERIC
+ multiplier = 1.3
+
+/datum/shield_mode/hull
+ mode_name = "Hull Shielding"
+ mode_desc = "This mode recalibrates the field to cover surface of the installation instead of projecting a bubble shaped field."
+ mode_flag = MODEFLAG_HULL
+ multiplier = 1
+
+/datum/shield_mode/adaptive
+ mode_name = "Adaptive Field Harmonics"
+ mode_desc = "This mode modulates the shield harmonic frequencies, allowing the field to adapt to various damage types."
+ mode_flag = MODEFLAG_MODULATE
+ multiplier = 2
+
+/datum/shield_mode/bypass
+ mode_name = "Diffuser Bypass"
+ mode_desc = "This mode disables the built-in safeties which allows the generator to counter effect of various shield diffusers. This tends to create a very large strain on the generator. Does not work with enabled safety protocols."
+ mode_flag = MODEFLAG_BYPASS
+ multiplier = 3
+ hacked_only = 1
+
+/datum/shield_mode/overcharge
+ mode_name = "Field Overcharge"
+ mode_desc = "This mode polarises the field, causing damage on contact. Does not work with enabled safety protocols."
+ mode_flag = MODEFLAG_OVERCHARGE
+ multiplier = 3
+ hacked_only = 1
+
+/datum/shield_mode/multiz
+ mode_name = "Multi-Dimensional Field Warp"
+ mode_desc = "Recalibrates the field projection array to increase the vertical height of the field, allowing it's usage on multi-deck stations or ships."
+ mode_flag = MODEFLAG_MULTIZ
+ multiplier = 1
diff --git a/nano/templates/shield_generator.tmpl b/nano/templates/shield_generator.tmpl
new file mode 100644
index 00000000000..d5714a29ab0
--- /dev/null
+++ b/nano/templates/shield_generator.tmpl
@@ -0,0 +1,158 @@
+{{if data.offline_for}}
+ EMERGENCY SHUTDOWN
+ An emergency shutdown has been initiated - generator cooling down
+ Please wait until the generator cools down before resuming operation. Estimated time left: {{:data.offline_for}} seconds.
+{{else}}
+ SYSTEM STATUS
+
+
+ Generator is:
+
+
+ {{if data.running == 2}}
+ {{if data.overloaded}}
+ Recovering
+ {{else}}
+ Active
+ {{/if}}
+ {{else data.running == 1}}
+ Shutting Down
+ {{else data.running == 3}}
+ Inactive
+ {{else data.running == 4}}
+ Spinning Up
+ {{if data.target_radius != data.field_radius}}
+ (Adjusting Radius)
+ {{else}}
+ ({{:data.spinup_counter * 2}}s)
+ {{/if}}
+ {{else}}
+ Offline
+ {{/if}}
+
+
+
+
+ Energy Storage:
+
+
+ {{:data.current_energy}}/{{:data.max_energy}} MJ ({{:data.percentage_energy}}%)
+
+
+
+
+ Shield Integrity:
+
+
+ {{:data.field_integrity}}%
+
+
+
+
+ Mitigation:
+
+
+ {{:data.mitigation_em}}% EM / {{:data.mitigation_physical}}% PH / {{:data.mitigation_heat}}% HE / {{:data.mitigation_max}}% MAX
+
+
+
+
+ Upkeep Energy Use:
+
+
+ {{:data.upkeep_power_usage}} kW
+
+
+
+
+ Total Energy Use:
+
+
+ {{if data.input_cap_kw}}
+ {{:data.power_usage}} / {{:data.input_cap_kw}} kW
+ {{else}}
+ {{:data.power_usage}} kW (No Limit)
+ {{/if}}
+
+
+
+
+ Field Size:
+
+
+ {{:data.functional_segments}} / {{:data.total_segments}} m2 (radius {{:data.field_radius}}, target {{:data.target_radius}})
+
+
+ CONTROLS
+
+
+ {{if (data.running >= 2)}}
+ | {{:helper.link('Turn off', null, {'begin_shutdown' : '1'})}}
+ {{if (data.running == 3)}}
+ | {{:helper.link('Activate', null, {'toggle_idle' : '0'})}} |
+ {{else}}
+ {{:helper.link('Deactivate', null, {'toggle_idle' : '1'})}} |
+ {{/if}}
+ {{else}}
+ {{:helper.link('Turn on', null, {'start_generator' : '1'})}}
+ {{/if}}
+ {{if data.running}}
+ {{if data.hacked}}
+ | {{:helper.link('EMERGENCY SHUTDOWN', null, {'emergency_shutdown' : '1'}, null, 'redButton')}}
+ {{/if}}
+ {{/if}}
+
+ |
+ | {{:helper.link('Set Field Range', null, {'set_range' : '1'})}}
+ | {{:helper.link('Set Input Cap', null, {'set_input_cap' : '1'})}}
+ |
+ | Set inactive power use intensity: |
+
+ {{for data.idle_valid_values}}
+ {{:helper.link(value, null, {'switch_idle' : value}, (value == data.idle_multiplier) ? 'selected' : (data.running == 4 ? 'disabled' : null))}}
+ {{/for}}
+ |
+
+ FIELD CALIBRATION
+
+ {{for data.modes}}
+
+
+ Mode:
+
+
+ {{:value.name}}
+
+
+
+
+ Description:
+
+
+ {{:value.desc}}
+
+
+
+
+ Status:
+
+
+ {{if value.status}}
+ Enabled
+ {{else}}
+ Disabled
+ {{/if}}
+ {{:helper.link('Toggle', null, {'toggle_mode' : value.flag})}}
+
+
+
+
+ Multiplier:
+
+
+ {{:value.multiplier}}
+
+
+
+ {{/for}}
+{{/if}}
diff --git a/sound/machines/apc_nopower.ogg b/sound/machines/apc_nopower.ogg
new file mode 100644
index 00000000000..b73c50d9b07
Binary files /dev/null and b/sound/machines/apc_nopower.ogg differ
diff --git a/sound/machines/buttonbeep.ogg b/sound/machines/buttonbeep.ogg
new file mode 100644
index 00000000000..347ea135440
Binary files /dev/null and b/sound/machines/buttonbeep.ogg differ
diff --git a/sound/machines/clawmachine_play.ogg b/sound/machines/clawmachine_play.ogg
new file mode 100644
index 00000000000..2f72abfbe0b
Binary files /dev/null and b/sound/machines/clawmachine_play.ogg differ
diff --git a/sound/machines/clawmachine_win.ogg b/sound/machines/clawmachine_win.ogg
new file mode 100644
index 00000000000..3a2269e03cf
Binary files /dev/null and b/sound/machines/clawmachine_win.ogg differ
diff --git a/sound/machines/door/airlock_tear_apart.ogg b/sound/machines/door/airlock_tear_apart.ogg
new file mode 100644
index 00000000000..aba517475f1
Binary files /dev/null and b/sound/machines/door/airlock_tear_apart.ogg differ
diff --git a/sound/machines/door/knock_glass.ogg b/sound/machines/door/knock_glass.ogg
new file mode 100644
index 00000000000..8878dda8013
Binary files /dev/null and b/sound/machines/door/knock_glass.ogg differ
diff --git a/sound/machines/door/knock_wood.wav b/sound/machines/door/knock_wood.wav
new file mode 100644
index 00000000000..dae7b95b995
Binary files /dev/null and b/sound/machines/door/knock_wood.wav differ
diff --git a/sound/machines/hatch_close.ogg b/sound/machines/hatch_close.ogg
new file mode 100644
index 00000000000..7676a73f2b7
Binary files /dev/null and b/sound/machines/hatch_close.ogg differ
diff --git a/sound/machines/honkbot_evil_laugh.ogg b/sound/machines/honkbot_evil_laugh.ogg
new file mode 100644
index 00000000000..7b12edf8a32
Binary files /dev/null and b/sound/machines/honkbot_evil_laugh.ogg differ
diff --git a/sound/machines/id_swipe.ogg b/sound/machines/id_swipe.ogg
new file mode 100644
index 00000000000..4f00bb3610b
Binary files /dev/null and b/sound/machines/id_swipe.ogg differ
diff --git a/sound/machines/machine_die_short.ogg b/sound/machines/machine_die_short.ogg
new file mode 100644
index 00000000000..6aac3e93564
Binary files /dev/null and b/sound/machines/machine_die_short.ogg differ
diff --git a/sound/machines/pda_click.ogg b/sound/machines/pda_click.ogg
new file mode 100644
index 00000000000..bed5b691f55
Binary files /dev/null and b/sound/machines/pda_click.ogg differ
diff --git a/sound/machines/rig/rigdown.ogg b/sound/machines/rig/rigdown.ogg
new file mode 100644
index 00000000000..21207573322
Binary files /dev/null and b/sound/machines/rig/rigdown.ogg differ
diff --git a/sound/machines/rig/rigerror.ogg b/sound/machines/rig/rigerror.ogg
new file mode 100644
index 00000000000..909d6a19e2f
Binary files /dev/null and b/sound/machines/rig/rigerror.ogg differ
diff --git a/sound/machines/rig/rigonline.ogg b/sound/machines/rig/rigonline.ogg
new file mode 100644
index 00000000000..dae104f9656
Binary files /dev/null and b/sound/machines/rig/rigonline.ogg differ
diff --git a/sound/machines/rig/rigservo.ogg b/sound/machines/rig/rigservo.ogg
new file mode 100644
index 00000000000..3193acaff44
Binary files /dev/null and b/sound/machines/rig/rigservo.ogg differ
diff --git a/sound/machines/rig/rigstarted.ogg b/sound/machines/rig/rigstarted.ogg
new file mode 100644
index 00000000000..d7bb9716f42
Binary files /dev/null and b/sound/machines/rig/rigstarted.ogg differ
diff --git a/sound/machines/rig/rigstep.ogg b/sound/machines/rig/rigstep.ogg
new file mode 100644
index 00000000000..02d3eff5125
Binary files /dev/null and b/sound/machines/rig/rigstep.ogg differ
diff --git a/sound/machines/roulette.ogg b/sound/machines/roulette.ogg
new file mode 100644
index 00000000000..2a80d802990
Binary files /dev/null and b/sound/machines/roulette.ogg differ
diff --git a/sound/machines/shutdown.ogg b/sound/machines/shutdown.ogg
new file mode 100644
index 00000000000..c0e24827e40
Binary files /dev/null and b/sound/machines/shutdown.ogg differ
diff --git a/sound/machines/slotmachine.ogg b/sound/machines/slotmachine.ogg
new file mode 100644
index 00000000000..366d9857215
Binary files /dev/null and b/sound/machines/slotmachine.ogg differ
diff --git a/sound/machines/slotmachine_pull.ogg b/sound/machines/slotmachine_pull.ogg
new file mode 100644
index 00000000000..d97a815bf80
Binary files /dev/null and b/sound/machines/slotmachine_pull.ogg differ
diff --git a/sound/machines/synth_alert.ogg b/sound/machines/synth_alert.ogg
new file mode 100644
index 00000000000..1fe5dd4a3ba
Binary files /dev/null and b/sound/machines/synth_alert.ogg differ
diff --git a/sound/machines/turrets/turret_deploy.ogg b/sound/machines/turrets/turret_deploy.ogg
new file mode 100644
index 00000000000..0b2376901b6
Binary files /dev/null and b/sound/machines/turrets/turret_deploy.ogg differ
diff --git a/sound/machines/turrets/turret_retract.ogg b/sound/machines/turrets/turret_retract.ogg
new file mode 100644
index 00000000000..11d1eecad8c
Binary files /dev/null and b/sound/machines/turrets/turret_retract.ogg differ
diff --git a/sound/machines/turrets/turret_rotate.ogg b/sound/machines/turrets/turret_rotate.ogg
new file mode 100644
index 00000000000..8699fa33168
Binary files /dev/null and b/sound/machines/turrets/turret_rotate.ogg differ
diff --git a/sound/machines/vending/vending_cans.ogg b/sound/machines/vending/vending_cans.ogg
new file mode 100644
index 00000000000..84b9d520b8e
Binary files /dev/null and b/sound/machines/vending/vending_cans.ogg differ
diff --git a/sound/machines/vending/vending_coffee.ogg b/sound/machines/vending/vending_coffee.ogg
new file mode 100644
index 00000000000..31edabc50ab
Binary files /dev/null and b/sound/machines/vending/vending_coffee.ogg differ
diff --git a/sound/machines/vending/vending_drop.ogg b/sound/machines/vending/vending_drop.ogg
new file mode 100644
index 00000000000..4e0ed7dd6d8
Binary files /dev/null and b/sound/machines/vending/vending_drop.ogg differ
diff --git a/vorestation.dme b/vorestation.dme
index 03a18528948..abb01d707c1 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -67,6 +67,7 @@
#include "code\__DEFINES\research.dm"
#include "code\__DEFINES\roguemining_vr.dm"
#include "code\__DEFINES\rust_g.dm"
+#include "code\__DEFINES\shields.dm"
#include "code\__DEFINES\shuttle.dm"
#include "code\__DEFINES\shuttles.dm"
#include "code\__DEFINES\sound.dm"
@@ -90,6 +91,7 @@
#include "code\__DEFINES\variable_settings.dm"
#include "code\__DEFINES\vote.dm"
#include "code\__DEFINES\vv.dm"
+#include "code\__DEFINES\wires.dm"
#include "code\__DEFINES\xenoarcheaology.dm"
#include "code\__DEFINES\_flags\_flags.dm"
#include "code\__DEFINES\_flags\do_after.dm"
@@ -471,6 +473,7 @@
#include "code\datums\wires\radio.dm"
#include "code\datums\wires\robot.dm"
#include "code\datums\wires\seedstorage.dm"
+#include "code\datums\wires\shield_generator.dm"
#include "code\datums\wires\smartfridge.dm"
#include "code\datums\wires\smes.dm"
#include "code\datums\wires\suit_storage_unit.dm"
@@ -3392,12 +3395,15 @@
#include "code\modules\shieldgen\directional_shield.dm"
#include "code\modules\shieldgen\emergency_shield.dm"
#include "code\modules\shieldgen\energy_field.dm"
+#include "code\modules\shieldgen\energy_shield.dm"
#include "code\modules\shieldgen\handheld_defuser.dm"
#include "code\modules\shieldgen\sheldwallgen.dm"
#include "code\modules\shieldgen\shield_capacitor.dm"
#include "code\modules\shieldgen\shield_diffuser.dm"
#include "code\modules\shieldgen\shield_gen.dm"
#include "code\modules\shieldgen\shield_gen_external.dm"
+#include "code\modules\shieldgen\shield_generator.dm"
+#include "code\modules\shieldgen\shield_modes.dm"
#include "code\modules\shuttles\antagonist.dm"
#include "code\modules\shuttles\crashes.dm"
#include "code\modules\shuttles\departmental.dm"