diff --git a/code/__DEFINES/power.dm b/code/__DEFINES/power.dm
index 78d942d78b..8cd3e7d525 100644
--- a/code/__DEFINES/power.dm
+++ b/code/__DEFINES/power.dm
@@ -1,3 +1,8 @@
#define SOLAR_TRACK_OFF 0
#define SOLAR_TRACK_TIMED 1
#define SOLAR_TRACK_AUTO 2
+
+///conversion ratio from joules to watts
+#define WATTS / 0.002
+///conversion ratio from watts to joules
+#define JOULES * 0.002
diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm
index 10ab6923eb..133fec28b3 100644
--- a/code/game/machinery/_machinery.dm
+++ b/code/game/machinery/_machinery.dm
@@ -154,6 +154,10 @@ Class Procs:
occupant_typecache = typecacheof(occupant_typecache)
return INITIALIZE_HINT_LATELOAD
+/obj/machinery/LateInitialize()
+ . = ..()
+ power_change()
+
/obj/machinery/Destroy()
GLOB.machines.Remove(src)
if(!speed_process)
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index e874a2713c..9ff03cd387 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -9,6 +9,7 @@
layer = OPEN_DOOR_LAYER
power_channel = ENVIRON
max_integrity = 350
+ damage_deflection = 10
armor = list("melee" = 30, "bullet" = 30, "laser" = 20, "energy" = 20, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 70)
CanAtmosPass = ATMOS_PASS_DENSITY
flags_1 = PREVENT_CLICK_UNDER_1|DEFAULT_RICOCHET_1
@@ -38,7 +39,7 @@
var/locked = FALSE //whether the door is bolted or not.
var/assemblytype //the type of door frame to drop during deconstruction
var/datum/effect_system/spark_spread/spark_system
- var/damage_deflection = 10
+
var/real_explosion_block //ignore this, just use explosion_block
var/red_alert_access = FALSE //if TRUE, this door will always open on red alert
var/poddoor = FALSE
@@ -223,11 +224,6 @@
return 1
return ..()
-/obj/machinery/door/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir)
- if(damage_flag == "melee" && damage_amount < damage_deflection)
- return 0
- . = ..()
-
/obj/machinery/door/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
. = ..()
if(. && obj_integrity > 0)
diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm
index cc2e6412eb..78a5c9ece9 100644
--- a/code/game/objects/obj_defense.dm
+++ b/code/game/objects/obj_defense.dm
@@ -22,6 +22,8 @@
//returns the damage value of the attack after processing the obj's various armor protections
/obj/proc/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir, armour_penetration = 0)
+ if(damage_flag == MELEE && damage_amount < damage_deflection)
+ return 0
switch(damage_type)
if(BRUTE)
if(BURN)
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index ca4428db57..58c571d9e6 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -20,6 +20,9 @@
var/max_integrity = 500
var/integrity_failure = 0 //0 if we have no special broken behavior, otherwise is a percentage of at what point the obj breaks. 0.5 being 50%
+ ///Damage under this value will be completely ignored
+ var/damage_deflection = 0
+
var/resistance_flags = NONE // INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ON_FIRE | UNACIDABLE | ACID_PROOF
var/persistence_replacement //have something WAY too amazing to live to the next round? Set a new path here. Overuse of this var will make me upset.
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 429c7557b6..ace1e4d5c4 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -1,44 +1,101 @@
-//update_state
-#define UPSTATE_CELL_IN (1<<0)
-#define UPSTATE_OPENED1 (1<<1)
-#define UPSTATE_OPENED2 (1<<2)
-#define UPSTATE_MAINT (1<<3)
-#define UPSTATE_BROKE (1<<4)
-#define UPSTATE_BLUESCREEN (1<<5)
-#define UPSTATE_WIREEXP (1<<6)
-#define UPSTATE_ALLGOOD (1<<7)
-
-#define APC_RESET_EMP "emp"
-
-//update_overlay
-#define APC_UPOVERLAY_CHARGEING0 (1<<0)
-#define APC_UPOVERLAY_CHARGEING1 (1<<1)
-#define APC_UPOVERLAY_CHARGEING2 (1<<2)
-#define APC_UPOVERLAY_EQUIPMENT0 (1<<3)
-#define APC_UPOVERLAY_EQUIPMENT1 (1<<4)
-#define APC_UPOVERLAY_EQUIPMENT2 (1<<5)
-#define APC_UPOVERLAY_LIGHTING0 (1<<6)
-#define APC_UPOVERLAY_LIGHTING1 (1<<7)
-#define APC_UPOVERLAY_LIGHTING2 (1<<8)
-#define APC_UPOVERLAY_ENVIRON0 (1<<9)
-#define APC_UPOVERLAY_ENVIRON1 (1<<10)
-#define APC_UPOVERLAY_ENVIRON2 (1<<11)
-#define APC_UPOVERLAY_LOCKED (1<<12)
-#define APC_UPOVERLAY_OPERATING (1<<13)
-
-#define APC_ELECTRONICS_MISSING 0 // None
-#define APC_ELECTRONICS_INSTALLED 1 // Installed but not secured
-#define APC_ELECTRONICS_SECURED 2 // Installed and secured
+// APC electronics status:
+/// There are no electronics in the APC.
+#define APC_ELECTRONICS_MISSING 0
+/// The electronics are installed but not secured.
+#define APC_ELECTRONICS_INSTALLED 1
+/// The electronics are installed and secured.
+#define APC_ELECTRONICS_SECURED 2
+// APC cover status:
+/// The APCs cover is closed.
#define APC_COVER_CLOSED 0
+/// The APCs cover is open.
#define APC_COVER_OPENED 1
+/// The APCs cover is missing.
#define APC_COVER_REMOVED 2
+// APC charging status:
+/// The APC is not charging.
#define APC_NOT_CHARGING 0
+/// The APC is charging.
#define APC_CHARGING 1
+/// The APC is fully charged.
#define APC_FULLY_CHARGED 2
#define MAXIMUM_COG_REGAIN 100 //How much charge drained by an integration cog can be priority-recharged in one processing-tick
+// APC channel status:
+/// The APCs power channel is manually set off.
+#define APC_CHANNEL_OFF 0
+/// The APCs power channel is automatically off.
+#define APC_CHANNEL_AUTO_OFF 1
+/// The APCs power channel is manually set on.
+#define APC_CHANNEL_ON 2
+/// The APCs power channel is automatically on.
+#define APC_CHANNEL_AUTO_ON 3
+
+// APC autoset enums:
+/// The APC turns automated and manual power channels off.
+#define AUTOSET_FORCE_OFF 0
+/// The APC turns automated power channels off.
+#define AUTOSET_OFF 2
+/// The APC turns automated power channels on.
+#define AUTOSET_ON 1
+
+// External power status:
+/// The APC either isn't attached to a powernet or there is no power on the external powernet.
+#define APC_NO_POWER 0
+/// The APCs external powernet does not have enough power to charge the APC.
+#define APC_LOW_POWER 1
+/// The APCs external powernet has enough power to charge the APC.
+#define APC_HAS_POWER 2
+
+// Ethereals:
+/// How long it takes an ethereal to drain or charge APCs. Also used as a spam limiter.
+#define APC_DRAIN_TIME (7.5 SECONDS)
+/// How much power ethereals gain/drain from APCs.
+#define APC_POWER_GAIN 200
+
+// Wires & EMPs:
+/// The wire value used to reset the APCs wires after one's EMPed.
+#define APC_RESET_EMP "emp"
+
+// update_state
+// Bitshifts: (If you change the status values to be something other than an int or able to exceed 3 you will need to change these too)
+/// The bit shift for the APCs cover status.
+#define UPSTATE_COVER_SHIFT (0)
+ /// The bitflag representing the APCs cover being open for icon purposes.
+ #define UPSTATE_OPENED1 (APC_COVER_OPENED << UPSTATE_COVER_SHIFT)
+ /// The bitflag representing the APCs cover being missing for icon purposes.
+ #define UPSTATE_OPENED2 (APC_COVER_REMOVED << UPSTATE_COVER_SHIFT)
+
+// Bitflags:
+/// The APC has a power cell.
+#define UPSTATE_CELL_IN (1<<2)
+/// The APC is broken or damaged.
+#define UPSTATE_BROKE (1<<3)
+/// The APC is undergoing maintenance.
+#define UPSTATE_MAINT (1<<4)
+/// The APC is emagged or malfed.
+#define UPSTATE_BLUESCREEN (1<<5)
+/// The APCs wires are exposed.
+#define UPSTATE_WIREEXP (1<<6)
+
+// update_overlay
+// Bitflags:
+/// Bitflag indicating that the APCs operating status overlay should be shown.
+#define UPOVERLAY_OPERATING (1<<0)
+/// Bitflag indicating that the APCs locked status overlay should be shown.
+#define UPOVERLAY_LOCKED (1<<1)
+
+// Bitshifts: (If you change the status values to be something other than an int or able to exceed 3 you will need to change these too)
+/// Bit shift for the charging status of the APC.
+#define UPOVERLAY_CHARGING_SHIFT (2)
+/// Bit shift for the equipment status of the APC.
+#define UPOVERLAY_EQUIPMENT_SHIFT (4)
+/// Bit shift for the lighting channel status of the APC.
+#define UPOVERLAY_LIGHTING_SHIFT (6)
+/// Bit shift for the environment channel status of the APC.
+#define UPOVERLAY_ENVIRON_SHIFT (8)
// the Area Power Controller (APC), formerly Power Distribution Unit (PDU)
// one per area, needs wire connection to power network through a terminal
@@ -51,12 +108,13 @@
name = "area power controller"
desc = "A control terminal for the area's electrical systems."
plane = ABOVE_WALL_PLANE
+
icon_state = "apc0"
use_power = NO_POWER_USE
req_access = null
max_integrity = 300
integrity_failure = 0.17
- var/damage_deflection = 10
+ damage_deflection = 10
resistance_flags = FIRE_PROOF
armor = list("melee" = 40, "bullet" = 40, "laser" = 40, "energy" = 100, "bomb" = 30, "bio" = 100, "rad" = 100, "fire" = 90, "acid" = 50)
req_access = list(ACCESS_ENGINE_EQUIP)
@@ -66,29 +124,29 @@
var/area/area
var/areastring = null
var/obj/item/stock_parts/cell/cell
- var/start_charge = 90 // initial cell charge %
- var/cell_type = /obj/item/stock_parts/cell/upgraded //Base cell has 2500 capacity. Enter the path of a different cell you want to use. cell determines charge rates, max capacity, ect. These can also be changed with other APC vars, but isn't recommended to minimize the risk of accidental usage of dirty editted APCs
+ var/start_charge = 90 // initial cell charge %
+ var/cell_type = /obj/item/stock_parts/cell/upgraded //Base cell has 2500 capacity. Enter the path of a different cell you want to use. cell determines charge rates, max capacity, ect. These can also be changed with other APC vars, but isn't recommended to minimize the risk of accidental usage of dirty editted APCs
var/opened = APC_COVER_CLOSED
- var/shorted = 0
- var/lighting = 3
- var/equipment = 3
- var/environ = 3
+ var/shorted = FALSE
+ var/lighting = APC_CHANNEL_AUTO_ON
+ var/equipment = APC_CHANNEL_AUTO_ON
+ var/environ = APC_CHANNEL_AUTO_ON
var/operating = TRUE
var/charging = APC_NOT_CHARGING
var/chargemode = 1
var/chargecount = 0
var/locked = TRUE
var/coverlocked = TRUE
- var/aidisabled = 0
+ var/aidisabled = FALSE
var/tdir = null
var/obj/machinery/power/terminal/terminal = null
var/lastused_light = 0
var/lastused_equip = 0
var/lastused_environ = 0
var/lastused_total = 0
- var/main_status = 0 // Whether or not there's external power. 0 is "none", 1 is "insufficient", 2 is "charging".
- powernet = 0 // set so that APCs aren't found as powernet nodes //Hackish, Horrible, was like this before I changed it :(
- var/malfhack = 0 //New var for my changes to AI malf. --NeoFite
+ var/main_status = 0
+ powernet = FALSE // set so that APCs aren't found as powernet nodes //Hackish, Horrible, was like this before I changed it :(
+ var/malfhack = FALSE //New var for my changes to AI malf. --NeoFite
var/mob/living/silicon/ai/malfai = null //See above --NeoFite
var/has_electronics = APC_ELECTRONICS_MISSING // 0 - none, 1 - plugged in, 2 - secured by screwdriver
var/overload = 1 //used for the Blackout malf module
@@ -98,9 +156,9 @@
var/obj/item/clockwork/integration_cog/integration_cog //Is there a cog siphoning power?
var/cog_drained = 0 //How much of the cell's charge was drained by an integration cog, recovering this amount takes priority over the normal APC cell recharge calculations, but comes after powering Essentials.
var/longtermpower = 10
- var/auto_name = 0
+ var/auto_name = FALSE
var/failure_timer = 0
- var/force_update = 0
+ var/force_update = FALSE
var/emergency_lights = FALSE
var/nightshift_lights = FALSE
var/nightshift_requires_auth = FALSE
@@ -119,6 +177,9 @@
/obj/machinery/power/apc/syndicate //general syndicate access
req_access = list(ACCESS_SYNDICATE)
+/obj/machinery/power/apc/away //general away mission access
+ req_access = list(ACCESS_AWAY_GENERAL)
+
/obj/machinery/power/apc/highcap/five_k
cell_type = /obj/item/stock_parts/cell/upgraded/plus
@@ -177,7 +238,6 @@
area = A
if(auto_name)
name = "\improper [A.name] APC"
- update_icon()
make_terminal()
update_nightshift_auth_requirement()
@@ -188,7 +248,8 @@
operating = FALSE
name = "\improper [A.name] APC"
stat |= MAINT
- update_icon()
+
+ update_appearance()
addtimer(CALLBACK(src, .proc/update), 5)
GLOB.apcs_list += src
@@ -196,21 +257,36 @@
wires = new /datum/wires/apc(src)
// offset 24 pixels in direction of dir
// this allows the APC to be embedded in a wall, yet still inside an area
+ if (building)
+ setDir(ndir)
+ tdir = dir // to fix Vars bug
setDir(SOUTH)
switch(tdir)
if(NORTH)
- pixel_x = 0
+ if((pixel_y != initial(pixel_y)) && (pixel_y != 23))
+ log_mapping("APC: ([src]) at [AREACOORD(src)] with dir ([tdir] | [uppertext(dir2text(tdir))]) has pixel_y value ([pixel_y] - should be 23.)")
pixel_y = 23
if(SOUTH)
- pixel_x = 0
+ if((pixel_y != initial(pixel_y)) && (pixel_y != -23))
+ log_mapping("APC: ([src]) at [AREACOORD(src)] with dir ([tdir] | [uppertext(dir2text(tdir))]) has pixel_y value ([pixel_y] - should be -23.)")
pixel_y = -23
if(EAST)
- pixel_y = 0
+ if((pixel_y != initial(pixel_x)) && (pixel_x != 24))
+ log_mapping("APC: ([src]) at [AREACOORD(src)] with dir ([tdir] | [uppertext(dir2text(tdir))]) has pixel_x value ([pixel_x] - should be 24.)")
pixel_x = 24
if(WEST)
- pixel_y = 0
+ if((pixel_y != initial(pixel_x)) && (pixel_x != -25))
+ log_mapping("APC: ([src]) at [AREACOORD(src)] with dir ([tdir] | [uppertext(dir2text(tdir))]) has pixel_x value ([pixel_x] - should be -25.)")
pixel_x = -25
+ if (building)
+ area = get_area(src)
+ opened = APC_COVER_OPENED
+ operating = FALSE
+ name = "\improper [get_area_name(area, TRUE)] APC"
+ stat |= MAINT
+ update_appearance()
+ addtimer(CALLBACK(src, .proc/update), 5)
/obj/machinery/power/apc/Destroy()
GLOB.apcs_list -= src
@@ -221,6 +297,7 @@
area.power_equip = FALSE
area.power_environ = FALSE
area.power_change()
+ area.poweralert(FALSE, src)
if(occupier)
malfvacate(1)
qdel(wires)
@@ -234,7 +311,7 @@
/obj/machinery/power/apc/handle_atom_del(atom/A)
if(A == cell)
cell = null
- update_icon()
+ update_appearance()
updateUsrDialog()
/obj/machinery/power/apc/proc/make_terminal()
@@ -345,65 +422,51 @@
. += mutable_appearance(icon, "apco2-[environ]")
. += emissive_appearance(icon, "apco2-[environ]")
+/// Checks for what icon updates we will need to handle
/obj/machinery/power/apc/proc/check_updates()
+ SIGNAL_HANDLER
+ . = NONE
var/last_update_state = update_state
var/last_update_overlay = update_overlay
- update_state = 0
- update_overlay = 0
- if(cell)
- update_state |= UPSTATE_CELL_IN
+ // Handle icon status:
+ var/new_update_state = NONE
if(stat & BROKEN)
- update_state |= UPSTATE_BROKE
+ new_update_state |= UPSTATE_BROKE
if(stat & MAINT)
- update_state |= UPSTATE_MAINT
+ new_update_state |= UPSTATE_MAINT
+
if(opened)
- if(opened==APC_COVER_OPENED)
- update_state |= UPSTATE_OPENED1
- if(opened==APC_COVER_REMOVED)
- update_state |= UPSTATE_OPENED2
+ new_update_state |= (opened << UPSTATE_COVER_SHIFT)
+ if(cell)
+ new_update_state |= UPSTATE_CELL_IN
+
else if((obj_flags & EMAGGED) || malfai)
- update_state |= UPSTATE_BLUESCREEN
+ new_update_state |= UPSTATE_BLUESCREEN
else if(panel_open)
- update_state |= UPSTATE_WIREEXP
- if(update_state <= 1)
- update_state |= UPSTATE_ALLGOOD
+ new_update_state |= UPSTATE_WIREEXP
+ if(new_update_state != update_state)
+ update_state = new_update_state
+ . |= UPDATE_ICON_STATE
+
+ // Handle overlay status:
+ var/new_update_overlay = NONE
if(operating)
- update_overlay |= APC_UPOVERLAY_OPERATING
+ new_update_overlay |= UPOVERLAY_OPERATING
- if(update_state & UPSTATE_ALLGOOD)
+ if(!update_state)
if(locked)
- update_overlay |= APC_UPOVERLAY_LOCKED
+ new_update_overlay |= UPOVERLAY_LOCKED
- if(!charging)
- update_overlay |= APC_UPOVERLAY_CHARGEING0
- else if(charging == APC_CHARGING)
- update_overlay |= APC_UPOVERLAY_CHARGEING1
- else if(charging == APC_FULLY_CHARGED)
- update_overlay |= APC_UPOVERLAY_CHARGEING2
-
- if (!equipment)
- update_overlay |= APC_UPOVERLAY_EQUIPMENT0
- else if(equipment == 1)
- update_overlay |= APC_UPOVERLAY_EQUIPMENT1
- else if(equipment == 2)
- update_overlay |= APC_UPOVERLAY_EQUIPMENT2
-
- if(!lighting)
- update_overlay |= APC_UPOVERLAY_LIGHTING0
- else if(lighting == 1)
- update_overlay |= APC_UPOVERLAY_LIGHTING1
- else if(lighting == 2)
- update_overlay |= APC_UPOVERLAY_LIGHTING2
-
- if(!environ)
- update_overlay |= APC_UPOVERLAY_ENVIRON0
- else if(environ==1)
- update_overlay |= APC_UPOVERLAY_ENVIRON1
- else if(environ==2)
- update_overlay |= APC_UPOVERLAY_ENVIRON2
+ new_update_overlay |= (charging << UPOVERLAY_CHARGING_SHIFT)
+ new_update_overlay |= (equipment << UPOVERLAY_EQUIPMENT_SHIFT)
+ new_update_overlay |= (lighting << UPOVERLAY_LIGHTING_SHIFT)
+ new_update_overlay |= (environ << UPOVERLAY_ENVIRON_SHIFT)
+ if(new_update_overlay != update_overlay)
+ update_overlay = new_update_overlay
+ . |= UPDATE_OVERLAYS
var/results = 0
var/hijackerreturn
if (hijacker)
@@ -475,7 +538,7 @@
else if (opened!=APC_COVER_REMOVED)
opened = APC_COVER_CLOSED
coverlocked = TRUE //closing cover relocks it
- update_icon()
+ update_appearance()
return
else if (!(stat & BROKEN))
if(coverlocked && !(stat & MAINT)) // locked...
@@ -486,7 +549,7 @@
return
else
opened = APC_COVER_OPENED
- update_icon()
+ update_appearance()
return
/obj/machinery/power/apc/screwdriver_act(mob/living/user, obj/item/W)
@@ -498,11 +561,11 @@
user.visible_message("[user] removes \the [cell] from [src]!","You remove \the [cell].")
var/turf/T = get_turf(user)
cell.forceMove(T)
- cell.update_icon()
+ cell.update_appearance()
cell = null
cog_drained = 0 //No more cell means no more averting celldrain
charging = APC_NOT_CHARGING
- update_icon()
+ update_appearance()
return
else
switch (has_electronics)
@@ -519,7 +582,7 @@
else
to_chat(user, "There is nothing to secure!")
return
- update_icon()
+ update_appearance()
else if(obj_flags & EMAGGED)
to_chat(user, "The interface is broken!")
return
@@ -529,12 +592,14 @@
update_icon()
/obj/machinery/power/apc/wirecutter_act(mob/living/user, obj/item/W)
+ . = ..()
if (terminal && opened)
terminal.dismantle(user, W)
return TRUE
/obj/machinery/power/apc/welder_act(mob/living/user, obj/item/W)
+ . = ..()
if (opened && !has_electronics && !terminal)
if(!W.tool_start_check(user, amount=3))
return
@@ -560,12 +625,12 @@
if(area.hasSiliconAccessInArea(user) && get_dist(src,user)>1)
return attack_hand(user)
- if (istype(W, /obj/item/stock_parts/cell) && opened)
+ if(istype(W, /obj/item/stock_parts/cell) && opened)
if(cell)
to_chat(user, "There is a power cell already installed!")
return
else
- if (stat & MAINT)
+ if(stat & MAINT)
to_chat(user, "There is no connector for your power cell!")
return
if(!user.transferItemToLoc(W, src))
@@ -575,7 +640,7 @@
"[user.name] has inserted the power cell to [src.name]!",\
"You insert the power cell.")
chargecount = 0
- update_icon()
+ update_appearance()
else if (W.GetID())
togglelock(user)
else if (istype(W, /obj/item/stack/cable_coil) && opened)
@@ -598,16 +663,20 @@
return
user.visible_message("[user.name] adds cables to the APC frame.", \
"You start adding cables to the APC frame...")
- playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
- if(C.use_tool(src, user, 20, 10) && !terminal && opened && has_electronics)
- var/turf/T = get_turf(src)
- var/obj/structure/cable/N = T.get_cable_node()
- if (prob(50) && electrocute_mob(usr, N, N, 1, TRUE))
- do_sparks(5, TRUE, src)
+ playsound(src.loc, 'sound/items/deconstruct.ogg', 50, TRUE)
+ if(do_after(user, 20, target = src))
+ if (C.get_amount() < 10 || !C)
return
- to_chat(user, "You add cables to the APC frame.")
- make_terminal()
- terminal.connect_to_network()
+ if (C.get_amount() >= 10 && !terminal && opened && has_electronics)
+ var/turf/T = get_turf(src)
+ var/obj/structure/cable/N = T.get_cable_node()
+ if (prob(50) && electrocute_mob(usr, N, N, 1, TRUE))
+ do_sparks(5, TRUE, src)
+ return
+ C.use(10)
+ to_chat(user, "You add cables to the APC frame.")
+ make_terminal()
+ terminal.connect_to_network()
else if (istype(W, /obj/item/electronics/apc) && opened)
if (has_electronics)
to_chat(user, "There is already a board inside the [src]!")
@@ -618,7 +687,7 @@
user.visible_message("[user.name] inserts the power control board into [src].", \
"You start to insert the power control board into the frame...")
- playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
+ playsound(src.loc, 'sound/items/deconstruct.ogg', 50, TRUE)
if(do_after(user, 10, target = src))
if(!has_electronics)
has_electronics = APC_ELECTRONICS_INSTALLED
@@ -649,7 +718,7 @@
chargecount = 0
user.visible_message("[user] fabricates a weak power cell and places it into [src].", \
"Your [P.name] whirrs with strain as you create a weak power cell and place it into [src]!")
- update_icon()
+ update_appearance()
else
to_chat(user, "[src] has both electronics and a cell.")
return
@@ -664,7 +733,7 @@
to_chat(user, "You replace missing APC's cover.")
qdel(W)
opened = APC_COVER_OPENED
- update_icon()
+ update_appearance()
return
if (has_electronics)
to_chat(user, "You cannot repair this APC until you remove the electronics still inside!")
@@ -678,7 +747,7 @@
obj_integrity = max_integrity
if (opened==APC_COVER_REMOVED)
opened = APC_COVER_OPENED
- update_icon()
+ update_appearance()
else if(istype(W, /obj/item/clockwork/integration_cog) && is_servant_of_ratvar(user))
if(integration_cog)
to_chat(user, "This APC already has a cog.")
@@ -742,7 +811,7 @@
return TRUE
else if(!cell)
if(stat & MAINT)
- to_chat(user, "There's no connector for a power cell.")
+ to_chat(user, span_warning("There's no connector for a power cell."))
return FALSE
var/obj/item/stock_parts/cell/crap/empty/C = new(src)
C.forceMove(src)
@@ -750,7 +819,7 @@
chargecount = 0
user.visible_message("[user] fabricates a weak power cell and places it into [src].", \
"Your [the_rcd.name] whirrs with strain as you create a weak power cell and place it into [src]!")
- update_icon()
+ update_appearance()
return TRUE
else
to_chat(user, "[src] has both electronics and a cell.")
@@ -774,10 +843,10 @@
else if(stat & (BROKEN|MAINT))
to_chat(user, "Nothing happens!")
else
- if((allowed(usr) || area.hasSiliconAccessInArea(usr)) && !wires.is_cut(WIRE_IDSCAN) && !malfhack)
+ if(allowed(usr) && !wires.is_cut(WIRE_IDSCAN) && !malfhack)
locked = !locked
to_chat(user, "You [ locked ? "lock" : "unlock"] the APC interface.")
- update_icon()
+ update_appearance()
updateUsrDialog()
else
to_chat(user, "Access denied.")
@@ -796,13 +865,9 @@
/obj/machinery/power/apc/obj_break(damage_flag)
- if(!(flags_1 & NODECONSTRUCT_1))
- set_broken()
-
-/obj/machinery/power/apc/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir)
- if(damage_flag == "melee" && damage_amount < damage_deflection)
- return 0
. = ..()
+ if(.)
+ set_broken()
/obj/machinery/power/apc/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
@@ -812,7 +877,7 @@
opened = APC_COVER_REMOVED
coverlocked = FALSE
visible_message("The APC cover is knocked down!")
- update_icon()
+ update_appearance()
/obj/machinery/power/apc/emag_act(mob/user)
. = ..()
@@ -880,10 +945,10 @@
if(cell)
user.visible_message("[user] removes \the [cell] from [src]!","You remove \the [cell].")
user.put_in_hands(cell)
- cell.update_icon()
+ cell.update_appearance()
src.cell = null
charging = APC_NOT_CHARGING
- src.update_icon()
+ src.update_appearance()
return
if((stat & MAINT) && !opened) //no board; no interface
return
@@ -972,19 +1037,15 @@
return "[area.name] : [equipment]/[lighting]/[environ] ([lastused_equip+lastused_light+lastused_environ]) : [cell? cell.percent() : "N/C"] ([charging])"
/obj/machinery/power/apc/proc/update()
- var/old_light = area.power_light
- var/old_equip = area.power_equip
- var/old_environ = area.power_environ
if(operating && !shorted && !failure_timer)
- area.power_light = (lighting > 1)
- area.power_equip = (equipment > 1)
- area.power_environ = (environ > 1)
+ area.power_light = (lighting > APC_CHANNEL_AUTO_OFF)
+ area.power_equip = (equipment > APC_CHANNEL_AUTO_OFF)
+ area.power_environ = (environ > APC_CHANNEL_AUTO_OFF)
else
area.power_light = FALSE
area.power_equip = FALSE
area.power_environ = FALSE
- if(old_light != area.power_light || old_equip != area.power_equip || old_environ != area.power_environ)
- area.power_change()
+ area.power_change()
/obj/machinery/power/apc/proc/can_use(mob/user, loud = 0) //used by attack_hand() and Topic()
if(IsAdminGhost(user))
@@ -1029,7 +1090,7 @@
to_chat(usr, "The APC does not respond to the command!")
else
locked = !locked
- update_icon()
+ update_appearance()
. = TRUE
if("cover")
coverlocked = !coverlocked
@@ -1044,20 +1105,20 @@
chargemode = !chargemode
if(!chargemode)
charging = APC_NOT_CHARGING
- update_icon()
+ update_appearance()
. = TRUE
if("channel")
if(params["eqp"])
equipment = setsubsystem(text2num(params["eqp"]))
- update_icon()
+ update_appearance()
update()
else if(params["lgt"])
lighting = setsubsystem(text2num(params["lgt"]))
- update_icon()
+ update_appearance()
update()
else if(params["env"])
environ = setsubsystem(text2num(params["env"]))
- update_icon()
+ update_appearance()
update()
. = TRUE
if("overload")
@@ -1095,7 +1156,7 @@
malfvacate()
if("reboot")
failure_timer = 0
- update_icon()
+ update_appearance()
update()
if("emergency_lighting")
emergency_lights = !emergency_lights
@@ -1113,7 +1174,7 @@
add_hiddenprint(user) //delete when runtime
log_game("[key_name(user)] turned [operating ? "on" : "off"] the [src] in [AREACOORD(src)]")
update()
- update_icon()
+ update_appearance()
/obj/machinery/power/apc/proc/hijack(mob/living/L)
if (!istype(L))
@@ -1204,7 +1265,6 @@
add_verb(occupier, /mob/living/silicon/ai/proc/corereturn)
occupier.cancel_camera()
-
/obj/machinery/power/apc/proc/malfvacate(forced)
if(!occupier)
return
@@ -1248,11 +1308,11 @@
return
transfer_in_progress = TRUE
user.visible_message("[user] slots [card] into [src]...", "Transfer process initiated. Sending request for AI approval...")
- playsound(src, 'sound/machines/click.ogg', 50, 1)
+ playsound(src, 'sound/machines/click.ogg', 50, TRUE)
SEND_SOUND(occupier, sound('sound/misc/notice2.ogg')) //To alert the AI that someone's trying to card them if they're tabbed out
if(alert(occupier, "[user] is attempting to transfer you to \a [card.name]. Do you consent to this?", "APC Transfer", "Yes - Transfer Me", "No - Keep Me Here") == "No - Keep Me Here")
to_chat(user, "AI denied transfer request. Process terminated.")
- playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 1)
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 50, TRUE)
transfer_in_progress = FALSE
return
if(user.loc != T)
@@ -1297,16 +1357,16 @@
/obj/machinery/power/apc/process()
if(icon_update_needed)
- update_icon()
+ update_appearance()
if(stat & (BROKEN|MAINT))
return
- if(!area.requires_power)
+ if(!area || !area.requires_power)
return
if(failure_timer)
update()
queue_icon_update()
failure_timer--
- force_update = 1
+ force_update = TRUE
return
lastused_light = area.usage(STATIC_LIGHT)
@@ -1324,110 +1384,117 @@
var/last_eq = equipment
var/last_en = environ
var/last_ch = charging
+
var/excess = surplus()
+
if(!avail())
- main_status = 0
+ main_status = APC_NO_POWER
else if(excess < 0)
- main_status = 1
+ main_status = APC_LOW_POWER
else
- main_status = 2
+ main_status = APC_HAS_POWER
- var/cur_excess = excess
- var/cur_used = lastused_total
-
- // first: if we have enough power, power the essentials DIRECTLY
-
- var/environ_satisfied = FALSE
- var/equipment_satisfied = FALSE
- var/lighting_satisfied = FALSE
-
- if(cur_excess >= lastused_environ)
- autoset(environ, 1)
- add_load(lastused_environ)
- cur_excess -= lastused_environ
- cur_used -= lastused_environ
- environ_satisfied = TRUE
-
- if(cur_excess >= lastused_equip)
- autoset(equipment, 1)
- add_load(lastused_equip)
- cur_excess -= lastused_equip
- cur_used -= lastused_equip
- equipment_satisfied = TRUE
-
- if(cur_excess >= lastused_light)
- autoset(lighting, 1)
- add_load(lastused_light)
- cur_excess -= lastused_light
- cur_used -= lastused_light
- lighting_satisfied = TRUE
-
- //If drained by an integration cog: Forcefully avert as much of the powerdrain as possible, though a maximum of MAXIMUM_COG_REGAIN
- if(cur_excess && cog_drained && cell)
- var/cog_regain = cell.give(min(min(cog_drained, cur_excess), MAXIMUM_COG_REGAIN))
- cur_excess -= cog_regain
- cog_drained = max(0, cog_drained - cog_regain)
-
- // next: take from or charge to the cell, depending on how much is left
if(cell && !shorted)
- if(cur_excess > 0)
- var/charging_cell = min(min(cur_excess*GLOB.CELLRATE, cell.maxcharge * GLOB.CHARGELEVEL), cell.maxcharge - cell.charge)
- cell.give(charging_cell)
- add_load(charging_cell/GLOB.CELLRATE)
- lastused_total += charging_cell
- longtermpower = min(10,longtermpower + 1)
- if(chargemode && !charging)
- chargecount++
- if(chargecount == 10)
+ // draw power from cell as before to power the area
+ var/cellused = min(cell.charge, lastused_total JOULES) // clamp deduction to a max, amount left in cell
+ cell.use(cellused)
+ //If drained by an integration cog: Forcefully avert as much of the powerdrain as possible, though a maximum of MAXIMUM_COG_REGAIN
+ if(excess && cog_drained)
+ var/cog_regain = cell.give(min(min(cog_drained, excess), MAXIMUM_COG_REGAIN))
+ excess -= cog_regain
+ cog_drained = max(0, cog_drained - cog_regain)
- chargecount = 0
- charging = APC_CHARGING
- else // not enough power available to run the last tick!
- charging = APC_NOT_CHARGING
- chargecount = 0
- longtermpower = max(-10,longtermpower - 2)
- cell.use(min(GLOB.CELLRATE * cur_used, cell.charge))
+ if(excess > lastused_total) // if power excess recharge the cell
+ // by the same amount just used
+ cell.give(cellused)
+ add_load(cellused WATTS) // add the load used to recharge the cell
+ else // no excess, and not enough per-apc
+ if((cell.charge WATTS + excess) >= lastused_total) // can we draw enough from cell+grid to cover last usage?
+ cell.charge = min(cell.maxcharge, cell.charge + excess JOULES) //recharge with what we can
+ add_load(excess) // so draw what we can from the grid
+ charging = APC_NOT_CHARGING
- // set channels based on remaining charge
+ else // not enough power available to run the last tick!
+ charging = APC_NOT_CHARGING
+ chargecount = 0
+ // This turns everything off in the case that there is still a charge left on the battery, just not enough to run the room.
+ equipment = autoset(equipment, AUTOSET_FORCE_OFF)
+ lighting = autoset(lighting, AUTOSET_FORCE_OFF)
+ environ = autoset(environ, AUTOSET_FORCE_OFF)
- var/cell_percent = cell.percent()
- if(cell.charge <= 0) // zero charge, turn all off
- equipment = autoset(equipment, 0)
- lighting = autoset(lighting, 0)
- environ = autoset(environ, 0)
- area.poweralert(0, src)
+ // set channels depending on how much charge we have left
- else if(cell_percent < 15 && longtermpower < 0) // <15%, turn off lighting & equipment
- equipment = autoset(equipment, 2)
- lighting = autoset(lighting, 2)
- environ = autoset(environ, 1)
- area.poweralert(0, src)
- else if(cell_percent < 30 && longtermpower < 0) // <30%, turn off lighting
- equipment = autoset(equipment, 1)
- lighting = autoset(lighting, 2)
- environ = autoset(environ, 1)
- area.poweralert(0, src)
- else // otherwise all can be on
- equipment = autoset(equipment, 1)
- lighting = autoset(lighting, 1)
- environ = autoset(environ, 1)
- area.poweralert(1, src)
- if(cell_percent > 75)
- area.poweralert(1, src)
+ // Allow the APC to operate as normal if the cell can charge
+ if(charging && longtermpower < 10)
+ longtermpower += 1
+ else if(longtermpower > -10)
+ longtermpower -= 2
+ if(cell.charge <= 0) // zero charge, turn all off
+ equipment = autoset(equipment, AUTOSET_FORCE_OFF)
+ lighting = autoset(lighting, AUTOSET_FORCE_OFF)
+ environ = autoset(environ, AUTOSET_FORCE_OFF)
+ area.poweralert(TRUE, src)
+ else if(cell.percent() < 15 && longtermpower < 0) // <15%, turn off lighting & equipment
+ equipment = autoset(equipment, AUTOSET_OFF)
+ lighting = autoset(lighting, AUTOSET_OFF)
+ environ = autoset(environ, AUTOSET_ON)
+ area.poweralert(TRUE, src)
+ else if(cell.percent() < 30 && longtermpower < 0) // <30%, turn off equipment
+ equipment = autoset(equipment, AUTOSET_OFF)
+ lighting = autoset(lighting, AUTOSET_ON)
+ environ = autoset(environ, AUTOSET_ON)
+ area.poweralert(TRUE, src)
+ else // otherwise all can be on
+ equipment = autoset(equipment, AUTOSET_ON)
+ lighting = autoset(lighting, AUTOSET_ON)
+ environ = autoset(environ, AUTOSET_ON)
+ area.poweralert(FALSE, src)
+ if(cell.percent() > 75)
+ area.poweralert(FALSE, src)
+
+ // now trickle-charge the cell
+ if(chargemode && charging == APC_CHARGING && operating)
+ if(excess > 0) // check to make sure we have enough to charge
+ // Max charge is capped to % per second constant
+ var/ch = min(excess JOULES, cell.maxcharge JOULES)
+ add_load(ch WATTS) // Removes the power we're taking from the grid
+ cell.give(ch) // actually recharge the cell
+
+ else
+ charging = APC_NOT_CHARGING // stop charging
+ chargecount = 0
// show cell as fully charged if so
if(cell.charge >= cell.maxcharge)
cell.charge = cell.maxcharge
charging = APC_FULLY_CHARGED
- else // no cell, can still run but not very well
+ if(chargemode)
+ if(!charging)
+ if(excess > cell.maxcharge*GLOB.CHARGELEVEL)
+ chargecount++
+ else
+ chargecount = 0
+
+ if(chargecount == 10)
+
+ chargecount = 0
+ charging = APC_CHARGING
+
+ else // chargemode off
+ charging = APC_NOT_CHARGING
+ chargecount = 0
+
+ else // no cell, switch everything off
+
charging = APC_NOT_CHARGING
chargecount = 0
- environ = autoset(environ, environ_satisfied)
- equipment = autoset(equipment, equipment_satisfied)
- lighting = autoset(lighting, lighting_satisfied)
+ equipment = autoset(equipment, AUTOSET_FORCE_OFF)
+ lighting = autoset(lighting, AUTOSET_FORCE_OFF)
+ environ = autoset(environ, AUTOSET_FORCE_OFF)
+ area.poweralert(TRUE, src)
// update icon & area power if anything changed
@@ -1438,19 +1505,54 @@
else if (last_ch != charging)
queue_icon_update()
-// val 0=off, 1=off(auto) 2=on 3=on(auto)
-// on 0=off, 1=on, 2=autooff
-
+/**
+ * Returns the new status value for an APC channel.
+ *
+ * // val 0=off, 1=off(auto) 2=on 3=on(auto)
+ * // on 0=off, 1=on, 2=autooff
+ * TODO: Make this use bitflags instead. It should take at most three lines, but it's out of scope for now.
+ *
+ * Arguments:
+ * - val: The current status of the power channel.
+ * - [APC_CHANNEL_OFF]: The APCs channel has been manually set to off. This channel will not automatically change.
+ * - [APC_CHANNEL_AUTO_OFF]: The APCs channel is running on automatic and is currently off. Can be automatically set to [APC_CHANNEL_AUTO_ON].
+ * - [APC_CHANNEL_ON]: The APCs channel has been manually set to on. This will be automatically changed only if the APC runs completely out of power or is disabled.
+ * - [APC_CHANNEL_AUTO_ON]: The APCs channel is running on automatic and is currently on. Can be automatically set to [APC_CHANNEL_AUTO_OFF].
+ * - on: An enum dictating how to change the channel's status.
+ * - [AUTOSET_FORCE_OFF]: The APC forces the channel to turn off. This includes manually set channels.
+ * - [AUTOSET_ON]: The APC allows automatic channels to turn back on.
+ * - [AUTOSET_OFF]: The APC turns automatic channels off.
+ */
/obj/machinery/power/apc/proc/autoset(val, on)
- if(val == 3 && (on == 2 || !on)) // if auto-on, return auto-off
- return 1
- else if(val == 2 && !on) // if on, return off
- return 0
- else if(on == 1 && val == 1) // if auto-off, return auto-on
- return 3
- // no, i don't understand these comments either
+ if(on == AUTOSET_FORCE_OFF)
+ if(val == APC_CHANNEL_ON) // if on, return off
+ return APC_CHANNEL_OFF
+ else if(val == APC_CHANNEL_AUTO_ON) // if auto-on, return auto-off
+ return APC_CHANNEL_AUTO_OFF
+ else if(on == AUTOSET_ON)
+ if(val == APC_CHANNEL_AUTO_OFF) // if auto-off, return auto-on
+ return APC_CHANNEL_AUTO_ON
+ else if(on == AUTOSET_OFF)
+ if(val == APC_CHANNEL_AUTO_ON) // if auto-on, return auto-off
+ return APC_CHANNEL_AUTO_OFF
return val
+/**
+ * Used by external forces to set the APCs channel status's.
+ *
+ * Arguments:
+ * - val: The desired value of the subsystem:
+ * - 1: Manually sets the APCs channel to be [APC_CHANNEL_OFF].
+ * - 2: Manually sets the APCs channel to be [APC_CHANNEL_AUTO_ON]. If the APC doesn't have any power this defaults to [APC_CHANNEL_OFF] instead.
+ * - 3: Sets the APCs channel to be [APC_CHANNEL_AUTO_ON]. If the APC doesn't have enough power this defaults to [APC_CHANNEL_AUTO_OFF] instead.
+ */
+/obj/machinery/power/apc/proc/setsubsystem(val)
+ if(cell && cell.charge > 0)
+ return (val == 1) ? APC_CHANNEL_OFF : val
+ if(val == 3)
+ return APC_CHANNEL_AUTO_OFF
+ return APC_CHANNEL_OFF
+
/obj/machinery/power/apc/proc/reset(wire)
switch(wire)
if(WIRE_IDSCAN)
@@ -1458,14 +1560,13 @@
if(WIRE_POWER1, WIRE_POWER2)
if(!wires.is_cut(WIRE_POWER1) && !wires.is_cut(WIRE_POWER2))
shorted = FALSE
- update()
if(WIRE_AI)
if(!wires.is_cut(WIRE_AI))
aidisabled = FALSE
if(APC_RESET_EMP)
- equipment = 3
- environ = 3
- update_icon()
+ equipment = APC_CHANNEL_AUTO_ON
+ environ = APC_CHANNEL_AUTO_ON
+ update_appearance()
update()
// damage and destruction acts
@@ -1478,12 +1579,12 @@
occupier.emp_act(severity)
if(. & EMP_PROTECT_SELF)
return
- lighting = 0
- equipment = 0
- environ = 0
- update_icon()
+ lighting = APC_CHANNEL_OFF
+ equipment = APC_CHANNEL_OFF
+ environ = APC_CHANNEL_OFF
+ update_appearance()
update()
- addtimer(CALLBACK(src, .proc/reset, APC_RESET_EMP), severity*8)
+ addtimer(CALLBACK(src, .proc/reset, APC_RESET_EMP), 600)
/obj/machinery/power/apc/blob_act(obj/structure/blob/B)
set_broken()
@@ -1496,11 +1597,10 @@
/obj/machinery/power/apc/proc/set_broken()
if(malfai && operating)
malfai.malf_picker.processing_time = clamp(malfai.malf_picker.processing_time - 10,0,1000)
- stat |= BROKEN
operating = FALSE
+ obj_break()
if(occupier)
malfvacate(1)
- update_icon()
update()
// overload all the lights in this APC area
@@ -1521,23 +1621,14 @@
/obj/machinery/power/apc/proc/shock(mob/user, prb)
if(!prob(prb))
- return 0
+ return FALSE
do_sparks(5, TRUE, src)
if(isalien(user))
- return 0
+ return FALSE
if(electrocute_mob(user, src, src, 1, TRUE))
- return 1
+ return TRUE
else
- return 0
-
-/obj/machinery/power/apc/proc/setsubsystem(val)
- if(cell && cell.charge > 0)
- return (val==1) ? 0 : val
- else if(val == 3)
- return 1
- else
- return 0
-
+ return FALSE
/obj/machinery/power/apc/proc/energy_fail(duration)
for(var/obj/machinery/M in area.contents)
@@ -1584,16 +1675,19 @@
var/normal_requires_auth = CONFIG_GET(flag/nightshift_toggle_requires_auth)
return (configured_level && our_level && ((our_level <= configured_level)? public_requires_auth : normal_requires_auth))
-#undef UPSTATE_CELL_IN
-#undef UPSTATE_OPENED1
-#undef UPSTATE_OPENED2
-#undef UPSTATE_MAINT
-#undef UPSTATE_BROKE
-#undef UPSTATE_BLUESCREEN
-#undef UPSTATE_WIREEXP
-#undef UPSTATE_ALLGOOD
-#undef APC_RESET_EMP
+#undef APC_CHANNEL_OFF
+#undef APC_CHANNEL_AUTO_OFF
+#undef APC_CHANNEL_ON
+#undef APC_CHANNEL_AUTO_ON
+
+#undef AUTOSET_FORCE_OFF
+#undef AUTOSET_OFF
+#undef AUTOSET_ON
+
+#undef APC_NO_POWER
+#undef APC_LOW_POWER
+#undef APC_HAS_POWER
#undef APC_ELECTRONICS_MISSING
#undef APC_ELECTRONICS_INSTALLED
@@ -1607,22 +1701,26 @@
#undef APC_CHARGING
#undef APC_FULLY_CHARGED
-//update_overlay
-#undef APC_UPOVERLAY_CHARGEING0
-#undef APC_UPOVERLAY_CHARGEING1
-#undef APC_UPOVERLAY_CHARGEING2
-#undef APC_UPOVERLAY_EQUIPMENT0
-#undef APC_UPOVERLAY_EQUIPMENT1
-#undef APC_UPOVERLAY_EQUIPMENT2
-#undef APC_UPOVERLAY_LIGHTING0
-#undef APC_UPOVERLAY_LIGHTING1
-#undef APC_UPOVERLAY_LIGHTING2
-#undef APC_UPOVERLAY_ENVIRON0
-#undef APC_UPOVERLAY_ENVIRON1
-#undef APC_UPOVERLAY_ENVIRON2
-#undef APC_UPOVERLAY_LOCKED
-#undef APC_UPOVERLAY_OPERATING
+#undef APC_DRAIN_TIME
+#undef APC_POWER_GAIN
+#undef APC_RESET_EMP
+
+// update_state
+#undef UPSTATE_CELL_IN
+#undef UPSTATE_COVER_SHIFT
+#undef UPSTATE_BROKE
+#undef UPSTATE_MAINT
+#undef UPSTATE_BLUESCREEN
+#undef UPSTATE_WIREEXP
+
+//update_overlay
+#undef UPOVERLAY_OPERATING
+#undef UPOVERLAY_LOCKED
+#undef UPOVERLAY_CHARGING_SHIFT
+#undef UPOVERLAY_EQUIPMENT_SHIFT
+#undef UPOVERLAY_LIGHTING_SHIFT
+#undef UPOVERLAY_ENVIRON_SHIFT
#undef MAXIMUM_COG_REGAIN
/*Power module, used for APC construction*/