diff --git a/baystation12.dme b/baystation12.dme
index 62e10d20980..1777674580c 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -164,6 +164,8 @@
#include "code\datums\spells\trigger.dm"
#include "code\datums\spells\turf_teleport.dm"
#include "code\datums\spells\wizard.dm"
+#include "code\datums\wires\apc.dm"
+#include "code\datums\wires\wires.dm"
#include "code\defines\obj.dm"
#include "code\defines\obj\weapon.dm"
#include "code\defines\procs\admin.dm"
@@ -1136,7 +1138,6 @@
#include "code\modules\power\breaker_box.dm"
#include "code\modules\power\cable.dm"
#include "code\modules\power\cable_heavyduty.dm"
-#include "code\modules\power\cable_logic.dm"
#include "code\modules\power\cell.dm"
#include "code\modules\power\engine.dm"
#include "code\modules\power\fractal_reactor.dm"
diff --git a/code/WorkInProgress/Cael_Aislinn/Rust/core_gen.dm b/code/WorkInProgress/Cael_Aislinn/Rust/core_gen.dm
index 88cf6fd4414..7697fe17d4c 100644
--- a/code/WorkInProgress/Cael_Aislinn/Rust/core_gen.dm
+++ b/code/WorkInProgress/Cael_Aislinn/Rust/core_gen.dm
@@ -61,7 +61,6 @@ max volume of phoron storeable by the field = the total volume of a number of ti
idle_power_usage = 50
active_power_usage = 500 //multiplied by field strength
var/cached_power_avail = 0
- directwired = 1
anchored = 0
var/state = 0
@@ -120,7 +119,6 @@ max volume of phoron storeable by the field = the total volume of a number of ti
state = 2
user << "You weld the [src] to the floor."
connect_to_network()
- src.directwired = 1
else
user << "\red You need more welding fuel to complete this task."
if(2)
@@ -134,7 +132,6 @@ max volume of phoron storeable by the field = the total volume of a number of ti
state = 1
user << "You cut the [src] free from the floor."
disconnect_from_network()
- src.directwired = 0
else
user << "\red You need more welding fuel to complete this task."
return
diff --git a/code/WorkInProgress/Cael_Aislinn/Rust/fuel_injector.dm b/code/WorkInProgress/Cael_Aislinn/Rust/fuel_injector.dm
index 5047ab1a5d1..e3441dafd86 100644
--- a/code/WorkInProgress/Cael_Aislinn/Rust/fuel_injector.dm
+++ b/code/WorkInProgress/Cael_Aislinn/Rust/fuel_injector.dm
@@ -19,7 +19,6 @@
use_power = 1
idle_power_usage = 10
active_power_usage = 500
- directwired = 0
var/remote_access_enabled = 1
var/cached_power_avail = 0
var/emergency_insert_ready = 0
diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm
index 8654fb89a12..bad82b9e8e0 100644
--- a/code/controllers/master_controller.dm
+++ b/code/controllers/master_controller.dm
@@ -363,7 +363,7 @@ datum/controller/game_controller/proc/process_powernets()
while(i<=powernets.len)
var/datum/powernet/Powernet = powernets[i]
if(Powernet)
- Powernet.process()
+ Powernet.reset()
i++
continue
powernets.Cut(i,i+1)
diff --git a/code/datums/wires/apc.dm b/code/datums/wires/apc.dm
new file mode 100644
index 00000000000..7e48809af9a
--- /dev/null
+++ b/code/datums/wires/apc.dm
@@ -0,0 +1,78 @@
+/datum/wires/apc
+ holder_type = /obj/machinery/power/apc
+ wire_count = 4
+
+var/const/APC_WIRE_IDSCAN = 1
+var/const/APC_WIRE_MAIN_POWER1 = 2
+var/const/APC_WIRE_MAIN_POWER2 = 4
+var/const/APC_WIRE_AI_CONTROL = 8
+
+/datum/wires/apc/GetInteractWindow()
+ 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.")]")
+
+
+/datum/wires/apc/CanUse(var/mob/living/L)
+ var/obj/machinery/power/apc/A = holder
+ if(A.wiresexposed)
+ return 1
+ return 0
+
+/datum/wires/apc/UpdatePulsed(var/index)
+
+ var/obj/machinery/power/apc/A = holder
+
+ switch(index)
+
+ if(APC_WIRE_IDSCAN)
+ A.locked = 0
+
+ spawn(300)
+ if(A)
+ A.locked = 1
+ A.updateDialog()
+
+ if (APC_WIRE_MAIN_POWER1, APC_WIRE_MAIN_POWER2)
+ if(A.shorted == 0)
+ A.shorted = 1
+
+ spawn(1200)
+ if(A && !IsIndexCut(APC_WIRE_MAIN_POWER1) && !IsIndexCut(APC_WIRE_MAIN_POWER2))
+ A.shorted = 0
+ A.updateDialog()
+
+ if (APC_WIRE_AI_CONTROL)
+ if (A.aidisabled == 0)
+ A.aidisabled = 1
+
+ spawn(10)
+ if(A && !IsIndexCut(APC_WIRE_AI_CONTROL))
+ A.aidisabled = 0
+ A.updateDialog()
+
+ A.updateDialog()
+
+/datum/wires/apc/UpdateCut(var/index, var/mended)
+ var/obj/machinery/power/apc/A = holder
+
+ switch(index)
+ if(APC_WIRE_MAIN_POWER1, APC_WIRE_MAIN_POWER2)
+
+ if(!mended)
+ A.shock(usr, 50)
+ A.shorted = 1
+
+ else if(!IsIndexCut(APC_WIRE_MAIN_POWER1) && !IsIndexCut(APC_WIRE_MAIN_POWER2))
+ A.shorted = 0
+ 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
+ A.updateDialog()
diff --git a/code/datums/wires/wires.dm b/code/datums/wires/wires.dm
new file mode 100644
index 00000000000..6204c90325e
--- /dev/null
+++ b/code/datums/wires/wires.dm
@@ -0,0 +1,293 @@
+// 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()
+// 12 colours, if you're adding more than 12 wires then add more colours here
+var/list/wireColours = list("red", "blue", "green", "black", "orange", "brown", "gold", "gray", "cyan", "navy", "purple", "pink")
+
+/datum/wires
+
+ 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)
+ ..()
+ src.holder = holder
+ if(!istype(holder, holder_type))
+ CRASH("Our holder is null/the wrong type!")
+ return
+
+ // Generate new wires
+ if(random)
+ GenerateWires()
+ // Get the same wires
+ 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.
+
+/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.
+
+ while(colours_to_pick.len && indexes_to_pick.len)
+ // Pick and remove a colour
+ var/colour = pick_n_take(colours_to_pick)
+
+ // Pick and remove an index
+ var/index = pick_n_take(indexes_to_pick)
+
+ src.wires[colour] = index
+ //wires = shuffle(wires)
+
+
+/datum/wires/proc/Interact(var/mob/living/user)
+
+ var/html = null
+ if(holder && CanUse(user))
+ html = GetInteractWindow()
+ if(html)
+ user.set_machine(holder)
+ else
+ user.unset_machine()
+ // No content means no window.
+ user << browse(null, "window=wires")
+ return
+
+ var/datum/browser/popup = new(user, "wires", holder.name, window_x, window_y)
+ popup.set_content(html)
+ popup.set_title_image(user.browse_rsc_icon(holder.icon, holder.icon_state))
+ popup.open()
+
+/datum/wires/proc/GetInteractWindow()
+ var/html = "
"
+ html += "
Exposed Wires
"
+ html += "
"
+ html += "
"
+
+ 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(istype(I, /obj/item/weapon/wirecutters))
+ var/colour = href_list["cut"]
+ CutWireColour(colour)
+ else
+ L << "You need wirecutters!"
+
+ else if(href_list["pulse"])
+ if(istype(I, /obj/item/device/multitool))
+ var/colour = href_list["pulse"]
+ PulseColour(colour)
+ else
+ 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/device/assembly/signaler))
+ L.drop_item()
+ Attach(colour, I)
+ else
+ L << "You need a remote signaller!"
+
+
+
+
+ // 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)
+ return
+
+// Called when wire pulsed. Add code here.
+/datum/wires/proc/UpdatePulsed(var/index)
+ return
+
+/datum/wires/proc/CanUse(var/mob/living/L)
+ return 1
+
+// Example of use:
+/*
+
+var/const/BOLTED= 1
+var/const/SHOCKED = 2
+var/const/SAFETY = 4
+var/const/POWER = 8
+
+/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()
+
+*/
+
+
+//
+// Helper Procs
+//
+
+/datum/wires/proc/PulseColour(var/colour)
+ PulseIndex(GetIndex(colour))
+
+/datum/wires/proc/PulseIndex(var/index)
+ if(IsIndexCut(index))
+ return
+ UpdatePulsed(index)
+
+/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/device/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/device/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/device/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/CutAll()
+ for(var/i = 1; i < MAX_FLAG && i < (1 << wire_count); i += i)
+ CutWireIndex(i)
+
+/datum/wires/proc/IsAllCut()
+ if(wires_status == (1 << wire_count) - 1)
+ return 1
+ return 0
+
+//
+//Shuffle and Mend
+//
+
+/datum/wires/proc/Shuffle()
+ wires_status = 0
+ GenerateWires()
diff --git a/code/game/objects/items/devices/powersink.dm b/code/game/objects/items/devices/powersink.dm
index 019422b617a..72e39b70631 100644
--- a/code/game/objects/items/devices/powersink.dm
+++ b/code/game/objects/items/devices/powersink.dm
@@ -97,10 +97,7 @@
SetLuminosity(12)
// found a powernet, so drain up to max power from it
-
- var/drained = min ( drain_rate, PN.avail )
- PN.newload += drained
- power_drained += drained
+ var/drained = PN.draw_power(drain_rate)
// if tried to drain more than available on powernet
// now look for APCs and drain their cells
diff --git a/code/global.dm b/code/global.dm
index 514fdcf5acd..318fc15803a 100644
--- a/code/global.dm
+++ b/code/global.dm
@@ -262,3 +262,24 @@ var/DBConnection/dbcon_old = new() //Tgstation database (Old database) - See the
//added for Xenoarchaeology, might be useful for other stuff
var/global/list/alphabet_uppercase = list("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z")
+
+// TODO: Replace
+/proc/RandomAPCWires()
+ //to make this not randomize the wires, just set index to 1 and increment it in the flag for loop (after doing everything else).
+ var/list/apcwires = list(0, 0, 0, 0)
+ APCIndexToFlag = list(0, 0, 0, 0)
+ APCIndexToWireColor = list(0, 0, 0, 0)
+ APCWireColorToIndex = list(0, 0, 0, 0)
+ var/flagIndex = 1
+ for (var/flag=1, flag<16, flag+=flag)
+ var/valid = 0
+ while (!valid)
+ var/colorIndex = rand(1, 4)
+ if (apcwires[colorIndex]==0)
+ valid = 1
+ apcwires[colorIndex] = flag
+ APCIndexToFlag[flagIndex] = flag
+ APCIndexToWireColor[flagIndex] = colorIndex
+ APCWireColorToIndex[colorIndex] = flagIndex
+ flagIndex+=1
+ return apcwires
\ No newline at end of file
diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm
index 963081404f6..2c9c26fceba 100644
--- a/code/modules/assembly/signaler.dm
+++ b/code/modules/assembly/signaler.dm
@@ -13,6 +13,7 @@
var/frequency = 1457
var/delay = 0
var/airlock_wire = null
+ var/datum/wires/connected = null
var/datum/radio_frequency/radio_connection
var/deadman = 0
@@ -118,7 +119,9 @@
pulse(var/radio = 0)
- if(istype(src.loc, /obj/machinery/door/airlock) && src.airlock_wire && src.wires)
+ if(src.connected && src.wires)
+ connected.Pulse(src)
+ else if(istype(src.loc, /obj/machinery/door/airlock) && src.airlock_wire && src.wires)
var/obj/machinery/door/airlock/A = src.loc
A.pulse(src.airlock_wire)
else if(holder)
diff --git a/code/modules/mining/coins.dm b/code/modules/mining/coins.dm
index c9942112b73..6a0d7c5c3cf 100644
--- a/code/modules/mining/coins.dm
+++ b/code/modules/mining/coins.dm
@@ -63,7 +63,7 @@
var/obj/item/stack/cable_coil/CC = new/obj/item/stack/cable_coil(user.loc)
CC.amount = 1
- CC.updateicon()
+ CC.update_icon()
overlays = list()
string_attached = null
user << "\blue You detach the string from the coin."
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index e3b758e6b2c..a3a7486648c 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -29,11 +29,11 @@
#define APC_UPOVERLAY_LOCKED 4096
#define APC_UPOVERLAY_OPERATING 8192
+
#define APC_UPDATE_ICON_COOLDOWN 100 // 10 seconds
-
// the Area Power Controller (APC), formerly Power Distribution Unit (PDU)
-// one per area, needs wire conection to power network
+// one per area, needs wire conection to power network through a terminal
// controls power to devices in that area
// may be opened to change power cell
@@ -42,6 +42,7 @@
//NOTE: STUFF STOLEN FROM AIRLOCK.DM thx
+
/obj/machinery/power/apc/high
cell_type = /obj/item/weapon/cell/high
@@ -53,6 +54,8 @@
/obj/machinery/power/apc
name = "area power controller"
+ desc = "A control terminal for the area electrical systems."
+
icon_state = "apc0"
anchored = 1
use_power = 0
@@ -61,7 +64,7 @@
var/areastring = null
var/obj/item/weapon/cell/cell
var/start_charge = 90 // initial cell charge %
- var/cell_type = /obj/item/weapon/cell/apc // 0=no cell, 1=regular, 2=high-cap (x5) <- old, now it's just 0=no cell, otherwise dictate cellcapacity by changing this value. 1 used to be 1000, 2 was 2500
+ var/cell_type = /obj/item/weapon/cell/apc
var/opened = 0 //0=closed, 1=opened, 2=cover removed
var/shorted = 0
var/lighting = 3
@@ -82,24 +85,16 @@
var/lastused_total = 0
var/main_status = 0
var/wiresexposed = 0
- var/apcwires = 15
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/mob/living/silicon/ai/malfai = null //See above --NeoFite
- var/debug= 0
- var/autoflag= 0 // 0 = off, 1= eqp and lights off, 2 = eqp off, 3 = all on.
// luminosity = 1
var/has_electronics = 0 // 0 - none, 1 - plugged in, 2 - secured by screwdriver
var/overload = 1 //used for the Blackout malf module
var/beenhit = 0 // used for counting how many times it has been hit, used for Aliens at the moment
- var/mob/living/silicon/ai/occupant = null
- var/list/apcwirelist = list(
- "Orange" = 1,
- "Dark red" = 2,
- "White" = 3,
- "Yellow" = 4,
- )
+ var/mob/living/silicon/ai/occupier = null
var/longtermpower = 10
+ var/datum/wires/apc/wires = null
var/update_state = -1
var/update_overlay = -1
var/global/status_overlays = 0
@@ -110,35 +105,22 @@
var/global/list/status_overlays_lighting
var/global/list/status_overlays_environ
-
-/proc/RandomAPCWires()
- //to make this not randomize the wires, just set index to 1 and increment it in the flag for loop (after doing everything else).
- var/list/apcwires = list(0, 0, 0, 0)
- APCIndexToFlag = list(0, 0, 0, 0)
- APCIndexToWireColor = list(0, 0, 0, 0)
- APCWireColorToIndex = list(0, 0, 0, 0)
- var/flagIndex = 1
- for (var/flag=1, flag<16, flag+=flag)
- var/valid = 0
- while (!valid)
- var/colorIndex = rand(1, 4)
- if (apcwires[colorIndex]==0)
- valid = 1
- apcwires[colorIndex] = flag
- APCIndexToFlag[flagIndex] = flag
- APCIndexToWireColor[flagIndex] = colorIndex
- APCWireColorToIndex[colorIndex] = flagIndex
- flagIndex+=1
- return apcwires
-
/obj/machinery/power/apc/updateDialog()
if (stat & (BROKEN|MAINT))
return
..()
+/obj/machinery/power/apc/connect_to_network()
+ //Override because the APC does not directly connect to the network; it goes through a terminal.
+ //The terminal is what the power computer looks for anyway.
+ if(!terminal)
+ make_terminal()
+ if(terminal)
+ terminal.connect_to_network()
+
/obj/machinery/power/apc/New(turf/loc, var/ndir, var/building=0)
..()
-
+ wires = new(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)
@@ -161,6 +143,24 @@
spawn(5)
src.update()
+/obj/machinery/power/apc/Del()
+ if(malfai && operating)
+ if (ticker.mode.config_tag == "malfunction")
+ if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas))
+ ticker.mode:apcs--
+ area.power_light = 0
+ area.power_equip = 0
+ area.power_environ = 0
+ area.power_change()
+ if(occupier)
+ malfvacate(1)
+ del(wires)
+ if(cell)
+ del(cell) // qdel
+ if(terminal)
+ disconnect_terminal()
+ ..()
+
/obj/machinery/power/apc/proc/make_terminal()
// create a terminal object at the same position as original turf loc
// wires will attach to this
@@ -177,7 +177,6 @@
var/area/A = src.loc.loc
-
//if area isn't specified use current
if(isarea(A) && src.areastring == null)
src.area = A
@@ -198,6 +197,7 @@
if(usr /*&& !usr.stat*/)
usr << "A control terminal for the area electrical systems."
+ ..()
if(stat & BROKEN)
usr << "Looks broken."
return
@@ -219,10 +219,10 @@
else
usr << "The cover is closed."
+
// update the APC icon to show the three base states
// also add overlays for indicator lights
/obj/machinery/power/apc/update_icon()
-
if (!status_overlays)
status_overlays = 1
status_overlays_lock = new
@@ -244,7 +244,7 @@
status_overlays_charging[2] = image(icon, "apco3-1")
status_overlays_charging[3] = image(icon, "apco3-2")
- status_overlays_equipment[1] = image(icon, "apco0-0") // 0=red, 1=green, 2=blue
+ status_overlays_equipment[1] = image(icon, "apco0-0")
status_overlays_equipment[2] = image(icon, "apco0-1")
status_overlays_equipment[3] = image(icon, "apco0-2")
status_overlays_equipment[4] = image(icon, "apco0-3")
@@ -259,8 +259,6 @@
status_overlays_environ[3] = image(icon, "apco2-2")
status_overlays_environ[4] = image(icon, "apco2-3")
-
-
var/update = check_updates() //returns 0 if no need to update icons.
// 1 if we need to update the icon_state
// 2 if we need to update the overlays
@@ -286,20 +284,14 @@
else if(update_state & UPSTATE_WIREEXP)
icon_state = "apcewires"
-
-
if(!(update_state & UPSTATE_ALLGOOD))
if(overlays.len)
overlays = 0
return
-
-
if(update & 2)
-
if(overlays.len)
- overlays = 0
-
+ overlays.len = 0
if(!(stat & (BROKEN|MAINT)) && update_state & UPSTATE_ALLGOOD)
overlays += status_overlays_lock[locked+1]
overlays += status_overlays_charging[charging+1]
@@ -369,15 +361,17 @@
else if(environ==2)
update_overlay |= APC_UPOVERLAY_ENVIRON2
+
var/results = 0
if(last_update_state == update_state && last_update_overlay == update_overlay)
return 0
if(last_update_state != update_state)
results += 1
- if(last_update_overlay != update_overlay && update_overlay != 0)
+ if(last_update_overlay != update_overlay)
results += 2
return results
+// Used in process so it doesn't update the icon too much
/obj/machinery/power/apc/proc/queue_icon_update()
if(!updating_icon)
@@ -387,7 +381,6 @@
update_icon()
updating_icon = 0
-
//attack with an item - open/close cover, insert cell, or (un)lock interface
/obj/machinery/power/apc/attackby(obj/item/W, mob/user)
@@ -478,7 +471,7 @@
else if(stat & (BROKEN|MAINT))
user << "Nothing happens."
else
- if(src.allowed(usr))
+ if(src.allowed(usr) && !isWireCut(APC_WIRE_IDSCAN))
locked = !locked
user << "You [ locked ? "lock" : "unlock"] the APC interface."
update_icon()
@@ -501,25 +494,26 @@
update_icon()
else
user << "You fail to [ locked ? "unlock" : "lock"] the APC interface."
- else if (istype(W, /obj/item/stack/cable_coil) && !terminal && opened && has_electronics != 2)
+ else if (istype(W, /obj/item/stack/cable_coil) && !terminal && opened && has_electronics!=2)
if (src.loc:intact)
- user << "\red You must remove the floor plating in front of the APC first."
+ user << "You must remove the floor plating in front of the APC first."
return
var/obj/item/stack/cable_coil/C = W
if(C.get_amount() < 10)
- user << "You need more wires."
+ user << "You need ten lengths of cable for APC."
return
user << "You start adding cables to the APC frame..."
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
- if(do_after(user, 20) && !terminal && opened && has_electronics != 2)
- var/turf/T = get_turf(src)
- var/obj/structure/cable/N = T.get_cable_node()
- if (prob(50) && electrocute_mob(usr, N, N))
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
- s.set_up(5, 1, src)
- s.start()
- return
- if (C.use(10))
+ if(do_after(user, 20))
+ if (C.amount >= 10 && !terminal && opened && has_electronics != 2)
+ var/turf/T = get_turf(src)
+ var/obj/structure/cable/N = T.get_cable_node()
+ if (prob(50) && electrocute_mob(usr, N, N))
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(5, 1, src)
+ s.start()
+ return
+ C.use(10)
user.visible_message(\
"\red [user.name] has added cables to the APC frame!",\
"You add cables to the APC frame.")
@@ -541,14 +535,14 @@
user.visible_message(\
"\red [user.name] cut the cables and dismantled the power terminal.",\
"You cut the cables and dismantle the power terminal.")
- del(terminal)
+ del(terminal) // qdel
else if (istype(W, /obj/item/weapon/module/power_control) && opened && has_electronics==0 && !((stat & BROKEN) || malfhack))
user << "You trying to insert the power control board into the frame..."
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
if(do_after(user, 10))
has_electronics = 1
user << "You place the power control board inside the frame."
- del(W)
+ del(W) // qdel
else if (istype(W, /obj/item/weapon/module/power_control) && opened && has_electronics==0 && ((stat & BROKEN) || malfhack))
user << "\red You cannot put the board inside, the frame is damaged."
return
@@ -573,7 +567,7 @@
"\red [src] has been cut from the wall by [user.name] with the weldingtool.",\
"You cut the APC frame from the wall.",\
"\red You hear welding.")
- del(src)
+ del(src) // qdel
return
else if (istype(W, /obj/item/apc_frame) && opened && emagged)
emagged = 0
@@ -582,7 +576,7 @@
user.visible_message(\
"\red [user.name] has replaced the damaged APC frontal panel with a new one.",\
"You replace the damaged APC frontal panel with a new one.")
- del(W)
+ del(W) // qdel
update_icon()
else if (istype(W, /obj/item/apc_frame) && opened && ((stat & BROKEN) || malfhack))
if (has_electronics)
@@ -593,7 +587,7 @@
user.visible_message(\
"\red [user.name] has replaced the damaged APC frame with new one.",\
"You replace the damaged APC frame with new one.")
- del(W)
+ del(W) // qdel
stat &= ~BROKEN
malfai = null
malfhack = 0
@@ -616,7 +610,7 @@
return src.attack_hand(user)
if (!opened && wiresexposed && \
(istype(W, /obj/item/device/multitool) || \
- istype(W, /obj/item/weapon/wirecutters)))
+ istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/device/assembly/signaler)))
return src.attack_hand(user)
user.visible_message("\red The [src.name] has been hit with the [W.name] by [user.name]!", \
"\red You hit the [src.name] with your [W.name]!", \
@@ -625,10 +619,10 @@
// attack with hand - remove cell (if cover open) or interact with the APC
/obj/machinery/power/apc/attack_hand(mob/user)
-
+// if (!can_use(user)) This already gets called in interact() and in topic()
+// return
if(!user)
return
-
src.add_fingerprint(user)
//Human mob special interaction goes here.
@@ -665,26 +659,22 @@
else if(H.species.can_shred(H))
user.visible_message("\red [user.name] slashes at the [src.name]!", "\blue You slash at the [src.name]!")
playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1)
- var/allcut = 1
- for(var/wire in apcwirelist)
- if(!isWireCut(apcwirelist[wire]))
- allcut = 0
- break
+
+ var/allcut = wires.IsAllCut()
+
if(beenhit >= pick(3, 4) && wiresexposed != 1)
wiresexposed = 1
src.update_icon()
src.visible_message("\red The [src.name]'s cover flies open, exposing the wires!")
else if(wiresexposed == 1 && allcut == 0)
- for(var/wire in apcwirelist)
- cut(apcwirelist[wire])
+ wires.CutAll()
src.update_icon()
src.visible_message("\red The [src.name]'s wires are shredded!")
else
beenhit += 1
return
-
if(usr == user && opened && (!issilicon(user)))
if(cell)
user.put_in_hands(cell)
@@ -699,9 +689,7 @@
return
if(stat & (BROKEN|MAINT))
return
-
// do APC interaction
- //user.set_machine(src)
src.interact(user)
/obj/machinery/power/apc/interact(mob/user)
@@ -709,30 +697,15 @@
return
if(wiresexposed /*&& (!istype(user, /mob/living/silicon))*/) //Commented out the typecheck to allow engiborgs to repair damaged apcs.
- var/t1 = text("[area.name] APC wiresAccess Panel
\n")
+ wires.Interact(user)
- for(var/wiredesc in apcwirelist)
- var/is_uncut = src.apcwires & APCWireColorToFlag[apcwirelist[wiredesc]]
- t1 += "[wiredesc] wire: "
- if(!is_uncut)
- t1 += "Mend"
- else
- t1 += "Cut "
- t1 += "Pulse "
- t1 += "
"
- t1 += text("
\n[(src.locked ? "The APC is locked." : "The APC is unlocked.")]
\n[(src.shorted ? "The APCs power has been shorted." : "The APC is working properly!")]
\n[(src.aidisabled ? "The 'AI control allowed' light is off." : "The 'AI control allowed' light is on.")]")
- t1 += text("Close
")
- user << browse(t1, "window=apcwires")
- onclose(user, "apcwires")
+ return ui_interact(user)
- // Open the APC NanoUI
- ui_interact(user)
- return
/obj/machinery/power/apc/proc/get_malf_status(mob/user)
if (ticker && ticker.mode && (user.mind in ticker.mode.malf_ai) && istype(user, /mob/living/silicon/ai))
if (src.malfai == (user:parent ? user:parent : user))
- if (src.occupant == user)
+ if (src.occupier == user)
return 3 // 3 = User is shunted in this APC
else if (istype(user.loc, /obj/machinery/power/apc))
return 4 // 4 = User is shunted in another APC
@@ -743,6 +716,7 @@
else
return 0 // 0 = User is not a Malf AI
+
/obj/machinery/power/apc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(!user)
return
@@ -762,7 +736,7 @@
"powerChannels" = list(
list(
"title" = "Equipment",
- "powerLoad" = round(lastused_equip),
+ "powerLoad" = lastused_equip,
"status" = equipment,
"topicParams" = list(
"auto" = list("eqp" = 3),
@@ -772,7 +746,7 @@
),
list(
"title" = "Lighting",
- "powerLoad" = round(lastused_light),
+ "powerLoad" = round(lastused_equip),
"status" = lighting,
"topicParams" = list(
"auto" = list("lgt" = 3),
@@ -782,7 +756,7 @@
),
list(
"title" = "Environment",
- "powerLoad" = round(lastused_environ),
+ "powerLoad" = round(lastused_light),
"status" = environ,
"topicParams" = list(
"auto" = list("env" = 3),
@@ -825,87 +799,9 @@
// world << "[area.power_equip]"
area.power_change()
-/obj/machinery/power/apc/proc/isWireColorCut(var/wireColor)
- var/wireFlag = APCWireColorToFlag[wireColor]
- return ((src.apcwires & wireFlag) == 0)
-
/obj/machinery/power/apc/proc/isWireCut(var/wireIndex)
- var/wireFlag = APCIndexToFlag[wireIndex]
- return ((src.apcwires & wireFlag) == 0)
+ return wires.IsIndexCut(wireIndex)
-/obj/machinery/power/apc/proc/cut(var/wireColor)
- var/wireFlag = APCWireColorToFlag[wireColor]
- var/wireIndex = APCWireColorToIndex[wireColor]
- apcwires &= ~wireFlag
- switch(wireIndex)
- if(APC_WIRE_MAIN_POWER1)
- src.shock(usr, 50)
- src.shorted = 1
- src.updateDialog()
- if(APC_WIRE_MAIN_POWER2)
- src.shock(usr, 50)
- src.shorted = 1
- src.updateDialog()
- if (APC_WIRE_AI_CONTROL)
- if (src.aidisabled == 0)
- src.aidisabled = 1
- src.updateDialog()
-// if(APC_WIRE_IDSCAN) nothing happens when you cut this wire, add in something if you want whatever
-
-/obj/machinery/power/apc/proc/mend(var/wireColor)
- var/wireFlag = APCWireColorToFlag[wireColor]
- var/wireIndex = APCWireColorToIndex[wireColor] //not used in this function
- apcwires |= wireFlag
- switch(wireIndex)
- if(APC_WIRE_MAIN_POWER1)
- if ((!src.isWireCut(APC_WIRE_MAIN_POWER1)) && (!src.isWireCut(APC_WIRE_MAIN_POWER2)))
- src.shorted = 0
- src.shock(usr, 50)
- src.updateDialog()
- if(APC_WIRE_MAIN_POWER2)
- if ((!src.isWireCut(APC_WIRE_MAIN_POWER1)) && (!src.isWireCut(APC_WIRE_MAIN_POWER2)))
- src.shorted = 0
- src.shock(usr, 50)
- src.updateDialog()
- if (APC_WIRE_AI_CONTROL)
- //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.
- //aidisabledDisabled: 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 (src.aidisabled == 1)
- src.aidisabled = 0
- src.updateDialog()
-// if(APC_WIRE_IDSCAN) nothing happens when you cut this wire, add in something if you want whatever
-
-/obj/machinery/power/apc/proc/pulse(var/wireColor)
- //var/wireFlag = apcWireColorToFlag[wireColor] //not used in this function
- var/wireIndex = APCWireColorToIndex[wireColor]
- switch(wireIndex)
- if(APC_WIRE_IDSCAN) //unlocks the APC for 30 seconds, if you have a better way to hack an APC I'm all ears
- src.locked = 0
- spawn(300)
- src.locked = 1
- src.updateDialog()
- if (APC_WIRE_MAIN_POWER1)
- if(shorted == 0)
- shorted = 1
- spawn(1200)
- if(shorted == 1)
- shorted = 0
- src.updateDialog()
- if (APC_WIRE_MAIN_POWER2)
- if(shorted == 0)
- shorted = 1
- spawn(1200)
- if(shorted == 1)
- shorted = 0
- src.updateDialog()
- if (APC_WIRE_AI_CONTROL)
- if (src.aidisabled == 0)
- src.aidisabled = 1
- src.updateDialog()
- spawn(10)
- if (src.aidisabled == 1)
- src.aidisabled = 0
- src.updateDialog()
/obj/machinery/power/apc/proc/can_use(mob/user as mob, var/loud = 0) //used by attack_hand() and Topic()
if (user.stat)
@@ -917,8 +813,6 @@
istype(user, /mob/living/silicon) || \
istype(user, /mob/living/carbon/monkey)) )
user << "\red You don't have the dexterity to use this [src]!"
- nanomanager.close_user_uis(user, src)
-
return 0
if(user.restrained())
user << "\red You must have free hands to use this [src]"
@@ -926,7 +820,6 @@
if(user.lying)
user << "\red You must stand to use this [src]!"
return 0
- autoflag = 5
if (istype(user, /mob/living/silicon))
var/mob/living/silicon/ai/AI = user
var/mob/living/silicon/robot/robot = user
@@ -940,13 +833,9 @@
)
if(!loud)
user << "\red \The [src] have AI control disabled!"
- nanomanager.close_user_uis(user, src)
-
return 0
else
if ((!in_range(src, user) || !istype(src.loc, /turf)))
- nanomanager.close_user_uis(user, src)
-
return 0
var/mob/living/carbon/human/H = user
@@ -960,43 +849,18 @@
return 0
return 1
-/obj/machinery/power/apc/Topic(href, href_list, var/usingUI = 1)
- if(!(isrobot(usr) && (href_list["apcwires"] || href_list["pulse"])))
- if(!can_use(usr, 1))
- return 0
- src.add_fingerprint(usr)
+/obj/machinery/power/apc/Topic(href, href_list)
+ if(..())
+ return 0
- if (href_list["apcwires"])
- var/t1 = text2num(href_list["apcwires"])
- if (!( istype(usr.get_active_hand(), /obj/item/weapon/wirecutters) ))
- usr << "You need wirecutters!"
- return 0
- if (src.isWireColorCut(t1))
- src.mend(t1)
- else
- src.cut(t1)
- else if (href_list["pulse"])
- var/t1 = text2num(href_list["pulse"])
- if (!istype(usr.get_active_hand(), /obj/item/device/multitool))
- usr << "You need a multitool!"
- return 0
- if (src.isWireColorCut(t1))
- usr << "You can't pulse a cut wire."
- return 0
- else
- src.pulse(t1)
- else if (href_list["lock"])
+ if(!can_use(usr, 1))
+ return 0
+
+ if (href_list["lock"])
coverlocked = !coverlocked
else if (href_list["breaker"])
- operating = !operating
- if(malfai)
- if (ticker.mode.config_tag == "malfunction")
- if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas))
- operating ? ticker.mode:apcs++ : ticker.mode:apcs--
-
- src.update()
- update_icon()
+ toggle_breaker()
else if (href_list["cmode"])
chargemode = !chargemode
@@ -1006,45 +870,32 @@
else if (href_list["eqp"])
var/val = text2num(href_list["eqp"])
-
- equipment = (val==1) ? 0 : val
-
+ equipment = setsubsystem(val)
update_icon()
update()
else if (href_list["lgt"])
var/val = text2num(href_list["lgt"])
-
- lighting = (val==1) ? 0 : val
-
+ lighting = setsubsystem(val)
update_icon()
update()
+
else if (href_list["env"])
var/val = text2num(href_list["env"])
-
- environ = (val==1) ? 0 :val
-
+ environ = setsubsystem(val)
update_icon()
update()
- else if( href_list["close"] )
- nanomanager.close_user_uis(usr, src)
-
- return 0
- else if (href_list["close2"])
- usr << browse(null, "window=apcwires")
-
- return 0
else if (href_list["overload"])
- if( istype(usr, /mob/living/silicon) && !src.aidisabled )
+ if(istype(usr, /mob/living/silicon))
src.overload_lighting()
else if (href_list["malfhack"])
var/mob/living/silicon/ai/malfai = usr
- if( istype(malfai, /mob/living/silicon/ai) && !src.aidisabled )
+ if(get_malf_status(malfai)==1)
if (malfai.malfhacking)
malfai << "You are already hacking an APC."
- return 0
+ return 1
malfai << "Beginning override of APC systems. This takes some time, and you cannot perform other actions during the process."
malfai.malfhack = src
malfai.malfhacking = 1
@@ -1053,6 +904,7 @@
if (!src.aidisabled)
malfai.malfhack = null
malfai.malfhacking = 0
+ locked = 1
if (ticker.mode.config_tag == "malfunction")
if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas))
ticker.mode:apcs++
@@ -1063,57 +915,91 @@
malfai << "Hack complete. The APC is now under your exclusive control."
update_icon()
- /*else if (href_list["occupyapc"])
- malfoccupy(usr)
-
+ else if (href_list["occupyapc"])
+ if(get_malf_status(usr))
+ malfoccupy(usr)
else if (href_list["deoccupyapc"])
- malfvacate()*/
+ if(get_malf_status(usr))
+ malfvacate()
- if(usingUI)
- src.updateDialog()
+ else if (href_list["toggleaccess"])
+ if(istype(usr, /mob/living/silicon))
+ if(emagged || (stat & (BROKEN|MAINT)))
+ usr << "The APC does not respond to the command."
+ else
+ locked = !locked
+ update_icon()
return 1
-/*/obj/machinery/power/apc/proc/malfoccupy(var/mob/living/silicon/ai/malf)
+/obj/machinery/power/apc/proc/toggle_breaker()
+ operating = !operating
+
+ if(malfai)
+ if (ticker.mode.config_tag == "malfunction")
+ if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas))
+ operating ? ticker.mode:apcs++ : ticker.mode:apcs--
+
+ src.update()
+ update_icon()
+
+/obj/machinery/power/apc/proc/malfoccupy(var/mob/living/silicon/ai/malf)
+ return
+
if(!istype(malf))
return
if(istype(malf.loc, /obj/machinery/power/apc)) // Already in an APC
malf << "You must evacuate your current apc first."
return
+ /*if(!malf.can_shunt)
+ malf << "You cannot shunt."
+ return*/
if(src.z != 1)
return
- src.occupant = new /mob/living/silicon/ai(src,malf.laws,null,1)
- src.occupant.adjustOxyLoss(malf.getOxyLoss())
- if(!findtext(src.occupant.name,"APC Copy"))
- src.occupant.name = "[malf.name] APC Copy"
+ src.occupier = new /mob/living/silicon/ai(src,malf.laws,null,1)
+ src.occupier.adjustOxyLoss(malf.getOxyLoss())
+ if(!findtext(src.occupier.name,"APC Copy"))
+ src.occupier.name = "[malf.name] APC Copy"
if(malf.parent)
- src.occupant.parent = malf.parent
+ src.occupier.parent = malf.parent
else
- src.occupant.parent = malf
- malf.mind.transfer_to(src.occupant)
- src.occupant.eyeobj.name = "[src.occupant.name] (AI Eye)"
+ src.occupier.parent = malf
+ malf.mind.transfer_to(src.occupier)
+ src.occupier.eyeobj.name = "[src.occupier.name] (AI Eye)"
if(malf.parent)
- del(malf)
- src.occupant.verbs += /mob/living/silicon/ai/proc/corereturn
- src.occupant.verbs += /datum/game_mode/malfunction/proc/takeover
- src.occupant.cancel_camera()
+ del(malf) // qdel
+ // src.occupier.verbs += /mob/living/silicon/ai/proc/corereturn
+ src.occupier.verbs += /datum/game_mode/malfunction/proc/takeover
+ src.occupier.cancel_camera()
+ if (seclevel2num(get_security_level()) == SEC_LEVEL_DELTA)
+ for(var/obj/item/weapon/pinpointer/point in world)
+ point.the_disk = src //the pinpointer will detect the shunted AI
+
/obj/machinery/power/apc/proc/malfvacate(var/forced)
- if(!src.occupant)
+ if(!src.occupier)
return
- if(src.occupant.parent && src.occupant.parent.stat != 2)
- src.occupant.mind.transfer_to(src.occupant.parent)
- src.occupant.parent.adjustOxyLoss(src.occupant.getOxyLoss())
- src.occupant.parent.cancel_camera()
- del(src.occupant)
+ if(src.occupier.parent && src.occupier.parent.stat != 2)
+ src.occupier.mind.transfer_to(src.occupier.parent)
+ src.occupier.parent.adjustOxyLoss(src.occupier.getOxyLoss())
+ src.occupier.parent.cancel_camera()
+ del(src.occupier) // qdel
+ if (seclevel2num(get_security_level()) == SEC_LEVEL_DELTA)
+ for(var/obj/item/weapon/pinpointer/point in world)
+ for(var/datum/mind/AI_mind in ticker.mode.malf_ai)
+ var/mob/living/silicon/ai/A = AI_mind.current // the current mob the mind owns
+ if(A.stat != DEAD)
+ point.the_disk = A //The pinpointer tracks the AI back into its core.
else
- src.occupant << "\red Primary core damaged, unable to return core processes."
+ src.occupier << "\red Primary core damaged, unable to return core processes."
if(forced)
- src.occupant.loc = src.loc
- src.occupant.death()
- src.occupant.gib()*/
+ src.occupier.loc = src.loc
+ src.occupier.death()
+ src.occupier.gib()
+ for(var/obj/item/weapon/pinpointer/point in world)
+ point.the_disk = null //the pinpointer will go back to pointing at the nuke disc.
/obj/machinery/power/apc/proc/ion_act()
@@ -1144,20 +1030,9 @@
else
return 0
-/obj/machinery/power/apc/proc/last_surplus()
- if(terminal && terminal.powernet)
- return terminal.powernet.last_surplus()
- else
- return 0
-
-//Returns 1 if the APC should attempt to charge
-/obj/machinery/power/apc/proc/attempt_charging()
- return (chargemode && charging == 1 && operating)
-
/obj/machinery/power/apc/add_load(var/amount)
if(terminal && terminal.powernet)
- return terminal.powernet.draw_power(amount)
- return 0
+ terminal.powernet.load += amount
/obj/machinery/power/apc/avail()
if(terminal)
@@ -1173,9 +1048,20 @@
return
+ /*
+ if (equipment > 1) // off=0, off auto=1, on=2, on auto=3
+ use_power(src.equip_consumption, EQUIP)
+ if (lighting > 1) // off=0, off auto=1, on=2, on auto=3
+ use_power(src.light_consumption, LIGHT)
+ if (environ > 1) // off=0, off auto=1, on=2, on auto=3
+ use_power(src.environ_consumption, ENVIRON)
+
+ area.calc_lighting() */
+
lastused_light = area.usage(LIGHT)
lastused_equip = area.usage(EQUIP)
lastused_environ = area.usage(ENVIRON)
+ area.clear_usage()
lastused_total = lastused_light + lastused_equip + lastused_environ
@@ -1186,61 +1072,48 @@
var/last_ch = charging
var/excess = surplus()
- var/power_excess = 0
- var/perapc = 0
- if(terminal && terminal.powernet)
- perapc = terminal.powernet.perapc
+ if(!src.avail())
+ main_status = 0
+ else if(excess < 0)
+ main_status = 1
+ else
+ main_status = 2
- if(debug)
- log_debug( "Status: [main_status] - Excess: [excess] - Last Equip: [lastused_equip] - Last Light: [lastused_light]")
-
- if(area.powerupdate)
- log_debug("power update in [area.name] / [name]")
+ //if(debug)
+ // world.log << "Status: [main_status] - Excess: [excess] - Last Equip: [lastused_equip] - Last Light: [lastused_light] - Longterm: [longtermpower]"
if(cell && !shorted)
- //var/cell_charge = cell.charge
- var/cell_maxcharge = cell.maxcharge
- // Calculate how much power the APC will try to get from the grid.
- var/target_draw = lastused_total
- if (src.attempt_charging())
- target_draw += min((cell_maxcharge - cell.charge), (cell_maxcharge*CHARGELEVEL))/CELLRATE
- target_draw = min(target_draw, perapc) //limit power draw by perapc
- // try to draw power from the grid
- var/power_drawn = 0
- if (src.avail())
- power_drawn = add_load(target_draw) //get some power from the powernet
+ // draw power from cell as before to power the area
+ var/cellused = min(cell.charge, CELLRATE * lastused_total) // clamp deduction to a max, amount left in cell
+ cell.use(cellused)
- //figure out how much power is left over after meeting demand
- power_excess = power_drawn - lastused_total
+ if(excess > lastused_total) // if power excess recharge the cell
+ // by the same amount just used
+ cell.give(cellused)
+ add_load(cellused/CELLRATE) // add the load used to recharge the cell
- if (power_excess < 0) //couldn't get enough power from the grid, we will need to take from the power cell.
- charging = 0
+ else // no excess, and not enough per-apc
- var/required_power = -power_excess
- if(cell.charge >= required_power*CELLRATE) // can we draw enough from cell to cover what's left over?
- cell.use(required_power*CELLRATE)
+ if( (cell.charge/CELLRATE + excess) >= lastused_total) // can we draw enough from cell+grid to cover last usage?
- else if (autoflag != 0) // not enough power available to run the last tick!
+ cell.charge = min(cell.maxcharge, cell.charge + CELLRATE * excess) //recharge with what we can
+ add_load(excess) // so draw what we can from the grid
+ charging = 0
+
+ else // not enough power available to run the last tick!
+ charging = 0
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, 0)
lighting = autoset(lighting, 0)
environ = autoset(environ, 0)
- autoflag = 0
- //Set external power status
- if (!power_drawn)
- main_status = 0
- else if (power_excess < 0)
- main_status = 1
- else
- main_status = 2
- // Set channels depending on how much charge we have left
+ // set channels depending on how much charge we have left
// Allow the APC to operate as normal if the cell can charge
if(charging && longtermpower < 10)
@@ -1248,61 +1121,56 @@
else if(longtermpower > -10)
longtermpower -= 2
-
- if(cell.charge >= 1250 || longtermpower > 0) // Put most likely at the top so we don't check it last, effeciency 101
- if(autoflag != 3)
- equipment = autoset(equipment, 1)
- lighting = autoset(lighting, 1)
- environ = autoset(environ, 1)
- autoflag = 3
+ 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)
+ 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 equipment
+ equipment = autoset(equipment, 2)
+ lighting = autoset(lighting, 1)
+ 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)
- if(cell.charge >= 4000)
- area.poweralert(1, src)
- else if(cell.charge < 1250 && cell.charge > 750 && longtermpower < 0) // <30%, turn off equipment
- if(autoflag != 2)
- equipment = autoset(equipment, 2)
- lighting = autoset(lighting, 1)
- environ = autoset(environ, 1)
- area.poweralert(0, src)
- autoflag = 2
- else if(cell.charge < 750 && cell.charge > 10) // <15%, turn off lighting & equipment
- if((autoflag > 1 && longtermpower < 0) || (autoflag > 1 && longtermpower >= 0))
- equipment = autoset(equipment, 2)
- lighting = autoset(lighting, 2)
- environ = autoset(environ, 1)
- area.poweralert(0, src)
- autoflag = 1
- else if(cell.charge <= 0) // zero charge, turn all off
- if(autoflag != 0)
- equipment = autoset(equipment, 0)
- lighting = autoset(lighting, 0)
- environ = autoset(environ, 0)
- area.poweralert(0, src)
- autoflag = 0
// now trickle-charge the cell
- if(src.attempt_charging())
- if (power_excess > 0) // check to make sure we have enough to charge
- cell.give(power_excess*CELLRATE) // actually recharge the cell
+
+ if(chargemode && charging == 1 && 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*CELLRATE, cell.maxcharge*CHARGELEVEL)
+ add_load(ch/CELLRATE) // Removes the power we're taking from the grid
+ cell.give(ch) // actually recharge the cell
+
else
charging = 0 // stop charging
chargecount = 0
// show cell as fully charged if so
- if(cell.charge >= cell_maxcharge)
+ if(cell.charge >= cell.maxcharge)
+ cell.charge = cell.maxcharge
charging = 2
- //if we have excess power for long enough, think about re-enable charging.
if(chargemode)
if(!charging)
- //last_surplus() overestimates the amount of power available for charging, but it's equivalent to what APCs were doing before.
- if(src.last_surplus()*CELLRATE >= cell_maxcharge*CHARGELEVEL)
+ if(excess > cell.maxcharge*CHARGELEVEL)
chargecount++
else
chargecount = 0
- charging = 0
if(chargecount >= 10)
+
chargecount = 0
charging = 1
@@ -1318,8 +1186,6 @@
lighting = autoset(lighting, 0)
environ = autoset(environ, 0)
area.poweralert(0, src)
- autoflag = 0
-
// update icon & area power if anything changed
@@ -1328,41 +1194,34 @@
update()
else if (last_ch != charging)
queue_icon_update()
- src.updateDialog()
// val 0=off, 1=off(auto) 2=on 3=on(auto)
-// on 0=off, 1=auto-on, 2=auto-off
+// on 0=off, 1=on, 2=autooff
-/proc/autoset(var/val, var/on)
-
- if(on==0) // turn things off
+obj/machinery/power/apc/proc/autoset(var/val, var/on)
+ if(on==0)
if(val==2) // if on, return off
return 0
else if(val==3) // if auto-on, return auto-off
return 1
- else if(on==1) // turn things auto-on
+ else if(on==1)
if(val==1) // if auto-off, return auto-on
return 3
- else if(on==2) // turn things auto-off
+ else if(on==2)
if(val==3) // if auto-on, return auto-off
return 1
return val
+
// damage and destruction acts
-
-/obj/machinery/power/apc/meteorhit(var/obj/O as obj)
-
- set_broken()
- return
-
/obj/machinery/power/apc/emp_act(severity)
if(cell)
cell.emp_act(severity)
- if(occupant)
- occupant.emp_act(severity)
+ if(occupier)
+ occupier.emp_act(severity)
lighting = 0
equipment = 0
environ = 0
@@ -1378,7 +1237,7 @@
//set_broken() //now Del() do what we need
if (cell)
cell.ex_act(1.0) // more lags woohoo
- del(src)
+ del(src) // qdel
return
if(2.0)
if (prob(50))
@@ -1398,12 +1257,16 @@
if (cell && prob(5))
cell.blob_act()
+/obj/machinery/power/apc/disconnect_terminal()
+ if(terminal)
+ terminal.master = null
+ terminal = null
+
/obj/machinery/power/apc/proc/set_broken()
if(malfai && operating)
if (ticker.mode.config_tag == "malfunction")
if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas))
ticker.mode:apcs--
-
// Aesthetically much better!
src.visible_message("[src]'s screen flickers with warnings briefly!")
spawn(rand(2,5))
@@ -1412,6 +1275,8 @@
operating = 0
update_icon()
update()
+ if(occupier)
+ malfvacate(1)
// overload all the lights in this APC area
@@ -1427,17 +1292,12 @@
L.broken()
sleep(1)
-/obj/machinery/power/apc/Del()
- if(malfai && operating)
- if (ticker.mode.config_tag == "malfunction")
- if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas))
- ticker.mode:apcs--
- area.power_light = 0
- area.power_equip = 0
- area.power_environ = 0
- area.power_change()
- /*if(occupant)
- malfvacate(1)*/
- ..()
+/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
#undef APC_UPDATE_ICON_COOLDOWN
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 4ec599d6371..6fd3cf785d2 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -1,29 +1,27 @@
-// attach a wire to a power machine - leads from the turf you are standing on
+///////////////////////////////
+//CABLE STRUCTURE
+///////////////////////////////
-/obj/machinery/power/attackby(obj/item/weapon/W, mob/user)
- if(istype(W, /obj/item/stack/cable_coil))
+////////////////////////////////
+// Definitions
+////////////////////////////////
- var/obj/item/stack/cable_coil/coil = W
+/* Cable directions (d1 and d2)
- var/turf/T = user.loc
- if(T.intact || !istype(T, /turf/simulated/floor))
- return
+ 9 1 5
+ \ | /
+ 8 - 0 - 4
+ / | \
+ 10 2 6
- if(get_dist(src, user) > 1)
- return
+If d1 = 0 and d2 = 0, there's no cable
+If d1 = 0 and d2 = dir, it's a O-X cable, getting from the center of the tile to dir (knot cable)
+If d1 = dir1 and d2 = dir2, it's a full X-X cable, getting from dir1 to dir2
+By design, d1 is the smallest direction and d2 is the highest
+*/
- if(!directwired) // only for attaching to directwired machines
- return
-
- coil.turf_place(T, user)
- return
- else
- ..()
- return
-
-// the power cable object
/obj/structure/cable
level = 1
anchored =1
@@ -74,17 +72,20 @@
var/turf/T = src.loc // hide if turf is not intact
if(level==1) hide(T.intact)
- cable_list += src
- update_icon()
+ cable_list += src //add it to the global cable list
-/obj/structure/cable/Del() // called when a cable is deleted
- if(!defer_powernet_rebuild) // set if network will be rebuilt manually
- if(powernet)
- powernet.cut_cable(src) // update the powernets
- cable_list -= src
- ..() // then go ahead and delete the cable
+/obj/structure/cable/Del() // called when a cable is deleted
+ if(powernet)
+ cut_cable_from_powernet() // update the powernets
+ cable_list -= src //remove it from global cable list
+ ..() // then go ahead and delete the cable
+///////////////////////////////////
+// General procedures
+///////////////////////////////////
+
+//If underfloor, hide the cable
/obj/structure/cable/hide(var/i)
if(level == 1 && istype(loc, /turf))
@@ -92,17 +93,25 @@
updateicon()
/obj/structure/cable/proc/updateicon()
- icon_state = "[d1]-[d2]"
- alpha = invisibility ? 127 : 255
+ if(invisibility)
+ icon_state = "[d1]-[d2]-f"
+ else
+ icon_state = "[d1]-[d2]"
// returns the powernet this cable belongs to
/obj/structure/cable/proc/get_powernet() //TODO: remove this as it is obsolete
return powernet
+//Telekinesis has no effect on a cable
/obj/structure/cable/attack_tk(mob/user)
return
+// Items usable on a cable :
+// - Wirecutters : cut it duh !
+// - Cable coil : merge cables
+// - Multitool : get the power currently passing through the cable
+//
/obj/structure/cable/attackby(obj/item/W, mob/user)
var/turf/T = src.loc
@@ -110,13 +119,11 @@
return
if(istype(W, /obj/item/weapon/wirecutters))
-
///// Z-Level Stuff
if(src.d1 == 12 || src.d2 == 12)
user << "You must cut this cable from above."
return
///// Z-Level Stuff
-
if(breaker_box)
user << "\red This cable is connected to nearby breaker box. Use breaker box to interact with it."
return
@@ -142,22 +149,23 @@
if(c.d1 == 12 || c.d2 == 12)
c.Del()
///// Z-Level Stuff
+ investigate_log("was cut by [key_name(usr, usr.client)] in [user.loc.loc]","wires")
- del(src)
-
- return // not needed, but for clarity
+ del(src) // qdel
+ return
else if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/coil = W
+ if (coil.get_amount() < 1)
+ user << "Not enough cable"
+ return
coil.cable_join(src, user)
else if(istype(W, /obj/item/device/multitool))
- var/datum/powernet/PN = get_powernet() // find the powernet
-
- if(PN && (PN.avail > 0)) // is it powered?
- user << "[PN.avail]W in power network."
+ if(powernet && (powernet.avail > 0)) // is it powered?
+ user << "[powernet.avail]W in power network."
else
user << "The cable is not powered."
@@ -171,7 +179,6 @@
src.add_fingerprint(user)
// shock the user with probability prb
-
/obj/structure/cable/proc/shock(mob/user, prb, var/siemens_coeff = 1.0)
if(!prob(prb))
return 0
@@ -183,24 +190,296 @@
else
return 0
+//explosion handling
/obj/structure/cable/ex_act(severity)
switch(severity)
if(1.0)
- del(src)
+ del(src) // qdel
if(2.0)
if (prob(50))
new/obj/item/stack/cable_coil(src.loc, src.d1 ? 2 : 1, color)
- del(src)
+ del(src) // qdel
if(3.0)
if (prob(25))
new/obj/item/stack/cable_coil(src.loc, src.d1 ? 2 : 1, color)
- del(src)
+ del(src) // qdel
return
-// the cable coil object, used for laying cable
+obj/structure/cable/proc/cableColor(var/colorC)
+ var/color_n = "#DD0000"
+ if(colorC)
+ color_n = colorC
+ color = color_n
+
+////////////////////////////////////////////
+// Power related
+///////////////////////////////////////////
+
+obj/structure/cable/proc/add_avail(var/amount)
+ if(powernet)
+ powernet.newavail += amount
+
+obj/structure/cable/proc/add_load(var/amount)
+ if(powernet)
+ powernet.load += amount
+
+obj/structure/cable/proc/surplus()
+ if(powernet)
+ return powernet.avail-powernet.load
+ else
+ return 0
+
+obj/structure/cable/proc/avail()
+ if(powernet)
+ return powernet.avail
+ else
+ return 0
+
+/////////////////////////////////////////////////
+// Cable laying helpers
+////////////////////////////////////////////////
+
+//handles merging diagonally matching cables
+//for info : direction^3 is flipping horizontally, direction^12 is flipping vertically
+/obj/structure/cable/proc/mergeDiagonalsNetworks(var/direction)
+
+ //search for and merge diagonally matching cables from the first direction component (north/south)
+ var/turf/T = get_step(src, direction&3)//go north/south
+
+ for(var/obj/structure/cable/C in T)
+
+ if(!C)
+ continue
+
+ if(src == C)
+ continue
+
+ if(C.d1 == (direction^3) || C.d2 == (direction^3)) //we've got a diagonally matching cable
+ if(!C.powernet) //if the matching cable somehow got no powernet, make him one (should not happen for cables)
+ var/datum/powernet/newPN = new()
+ newPN.add_cable(C)
+
+ if(powernet) //if we already have a powernet, then merge the two powernets
+ merge_powernets(powernet,C.powernet)
+ else
+ C.powernet.add_cable(src) //else, we simply connect to the matching cable powernet
+
+ //the same from the second direction component (east/west)
+ T = get_step(src, direction&12)//go east/west
+
+ for(var/obj/structure/cable/C in T)
+
+ if(!C)
+ continue
+
+ if(src == C)
+ continue
+ if(C.d1 == (direction^12) || C.d2 == (direction^12)) //we've got a diagonally matching cable
+ if(!C.powernet) //if the matching cable somehow got no powernet, make him one (should not happen for cables)
+ var/datum/powernet/newPN = new()
+ newPN.add_cable(C)
+
+ if(powernet) //if we already have a powernet, then merge the two powernets
+ merge_powernets(powernet,C.powernet)
+ else
+ C.powernet.add_cable(src) //else, we simply connect to the matching cable powernet
+
+// merge with the powernets of power objects in the given direction
+/obj/structure/cable/proc/mergeConnectedNetworks(var/direction)
+
+ var/fdir = (!direction)? 0 : turn(direction, 180) //flip the direction, to match with the source position on its turf
+
+ if(!(d1 == direction || d2 == direction)) //if the cable is not pointed in this direction, do nothing
+ return
+
+ var/turf/TB = get_step(src, direction)
+
+ for(var/obj/structure/cable/C in TB)
+
+ if(!C)
+ continue
+
+ if(src == C)
+ continue
+
+ if(C.d1 == fdir || C.d2 == fdir) //we've got a matching cable in the neighbor turf
+ if(!C.powernet) //if the matching cable somehow got no powernet, make him one (should not happen for cables)
+ var/datum/powernet/newPN = new()
+ newPN.add_cable(C)
+
+ if(powernet) //if we already have a powernet, then merge the two powernets
+ merge_powernets(powernet,C.powernet)
+ else
+ C.powernet.add_cable(src) //else, we simply connect to the matching cable powernet
+
+// merge with the powernets of power objects in the source turf
+/obj/structure/cable/proc/mergeConnectedNetworksOnTurf()
+ var/list/to_connect = list()
+
+ if(!powernet) //if we somehow have no powernet, make one (should not happen for cables)
+ var/datum/powernet/newPN = new()
+ newPN.add_cable(src)
+
+ //first let's add turf cables to our powernet
+ //then we'll connect machines on turf with a node cable is present
+ for(var/AM in loc)
+ if(istype(AM,/obj/structure/cable))
+ var/obj/structure/cable/C = AM
+ if(C.d1 == d1 || C.d2 == d1 || C.d1 == d2 || C.d2 == d2) //only connected if they have a common direction
+ if(C.powernet == powernet) continue
+ if(C.powernet)
+ merge_powernets(powernet, C.powernet)
+ else
+ powernet.add_cable(C) //the cable was powernetless, let's just add it to our powernet
+
+ else if(istype(AM,/obj/machinery/power/apc))
+ var/obj/machinery/power/apc/N = AM
+ if(!N.terminal) continue // APC are connected through their terminal
+
+ if(N.terminal.powernet == powernet)
+ continue
+
+ to_connect += N.terminal //we'll connect the machines after all cables are merged
+
+ else if(istype(AM,/obj/machinery/power)) //other power machines
+ var/obj/machinery/power/M = AM
+
+ if(M.powernet == powernet)
+ continue
+
+ to_connect += M //we'll connect the machines after all cables are merged
+
+ //now that cables are done, let's connect found machines
+ for(var/obj/machinery/power/PM in to_connect)
+ if(!PM.connect_to_network())
+ PM.disconnect_from_network() //if we somehow can't connect the machine to the new powernet, remove it from the old nonetheless
+
+//////////////////////////////////////////////
+// Powernets handling helpers
+//////////////////////////////////////////////
+
+//if powernetless_only = 1, will only get connections without powernet
+/obj/structure/cable/proc/get_connections(var/powernetless_only = 0)
+ . = list() // this will be a list of all connected power objects
+ var/turf/T
+
+///// Z-Level Stuff
+ if (d1 == 11 || d1 == 12)
+ var/turf/controllerlocation = locate(1, 1, z)
+ for(var/obj/effect/landmark/zcontroller/controller in controllerlocation)
+ if(controller.up && d1 == 12)
+ T = locate(src.x, src.y, controller.up_target)
+ if(T)
+ . += power_list(T, src, 11, 1)
+ if(controller.down && d1 == 11)
+ T = locate(src.x, src.y, controller.down_target)
+ if(T)
+ . += power_list(T, src, 12, 1)
+///// Z-Level Stuff
+ //get matching cables from the first direction
+ else if(d1) //if not a node cable
+ T = get_step(src, d1)
+ if(T)
+ . += power_list(T, src, turn(d1, 180), powernetless_only) //get adjacents matching cables
+
+ if(d1&(d1-1)) //diagonal direction, must check the 4 possibles adjacents tiles
+ T = get_step(src,d1&3) // go north/south
+ if(T)
+ . += power_list(T, src, d1 ^ 3, powernetless_only) //get diagonally matching cables
+ T = get_step(src,d1&12) // go east/west
+ if(T)
+ . += power_list(T, src, d1 ^ 12, powernetless_only) //get diagonally matching cables
+
+ . += power_list(loc, src, d1, powernetless_only) //get on turf matching cables
+
+///// Z-Level Stuff
+ if(d2 == 11 || d2 == 12)
+ var/turf/controllerlocation = locate(1, 1, z)
+ for(var/obj/effect/landmark/zcontroller/controller in controllerlocation)
+ if(controller.up && d2 == 12)
+ T = locate(src.x, src.y, controller.up_target)
+ if(T)
+ . += power_list(T, src, 11, 1)
+ if(controller.down && d2 == 11)
+ T = locate(src.x, src.y, controller.down_target)
+ if(T)
+ . += power_list(T, src, 12, 1)
+///// Z-Level Stuff
+ else
+ //do the same on the second direction (which can't be 0)
+ T = get_step(src, d2)
+ if(T)
+ . += power_list(T, src, turn(d2, 180), powernetless_only) //get adjacents matching cables
+
+ if(d2&(d2-1)) //diagonal direction, must check the 4 possibles adjacents tiles
+ T = get_step(src,d2&3) // go north/south
+ if(T)
+ . += power_list(T, src, d2 ^ 3, powernetless_only) //get diagonally matching cables
+ T = get_step(src,d2&12) // go east/west
+ if(T)
+ . += power_list(T, src, d2 ^ 12, powernetless_only) //get diagonally matching cables
+ . += power_list(loc, src, d2, powernetless_only) //get on turf matching cables
+
+ return .
+
+//should be called after placing a cable which extends another cable, creating a "smooth" cable that no longer terminates in the centre of a turf.
+//needed as this can, unlike other placements, disconnect cables
+/obj/structure/cable/proc/denode()
+ var/turf/T1 = loc
+ if(!T1) return
+
+ var/list/powerlist = power_list(T1,src,0,0) //find the other cables that ended in the centre of the turf, with or without a powernet
+ if(powerlist.len>0)
+ var/datum/powernet/PN = new()
+ propagate_network(powerlist[1],PN) //propagates the new powernet beginning at the source cable
+
+ if(PN.is_empty()) //can happen with machines made nodeless when smoothing cables
+ del(PN) // qdel
+
+// cut the cable's powernet at this cable and updates the powergrid
+/obj/structure/cable/proc/cut_cable_from_powernet()
+ var/turf/T1 = loc
+ var/list/P_list
+ if(!T1) return
+ if(d1)
+ T1 = get_step(T1, d1)
+ P_list = power_list(T1, src, turn(d1,180),0,cable_only = 1) // what adjacently joins on to cut cable...
+
+ P_list += power_list(loc, src, d1, 0, cable_only = 1)//... and on turf
+
+
+ if(P_list.len == 0)//if nothing in both list, then the cable was a lone cable, just delete it and its powernet
+ powernet.remove_cable(src)
+
+ for(var/obj/machinery/power/P in T1)//check if it was powering a machine
+ if(!P.connect_to_network()) //can't find a node cable on a the turf to connect to
+ P.disconnect_from_network() //remove from current network (and delete powernet)
+ return
+
+ // remove the cut cable from its turf and powernet, so that it doesn't get count in propagate_network worklist
+ loc = null
+ powernet.remove_cable(src) //remove the cut cable from its powernet
+
+ var/datum/powernet/newPN = new()// creates a new powernet...
+ propagate_network(P_list[1], newPN)//... and propagates it to the other side of the cable
+
+ // Disconnect machines connected to nodes
+ if(d1 == 0) // if we cut a node (O-X) cable
+ for(var/obj/machinery/power/P in T1)
+ if(!P.connect_to_network()) //can't find a node cable on a the turf to connect to
+ P.disconnect_from_network() //remove from current network
+
+///////////////////////////////////////////////
+// The cable coil object, used for laying cable
+///////////////////////////////////////////////
+
+////////////////////////////////
+// Definitions
+////////////////////////////////
#define MAXCOIL 30
+
/obj/item/stack/cable_coil
name = "cable coil"
icon = 'icons/obj/power.dmi'
@@ -219,10 +498,12 @@
item_state = "coil"
attack_verb = list("whipped", "lashed", "disciplined", "flogged")
- suicide_act(mob/user)
- viewers(user) << "[user] is strangling \himself with the [src.name]! It looks like \he's trying to commit suicide."
- return(OXYLOSS)
-
+/obj/item/stack/cable_coil/suicide_act(mob/user)
+ if(locate(/obj/structure/stool) in user.loc)
+ user.visible_message("[user] is making a noose with the [src.name]! It looks like \he's trying to commit suicide.")
+ else
+ user.visible_message("[user] is strangling \himself with the [src.name]! It looks like \he's trying to commit suicide.")
+ return(OXYLOSS)
/obj/item/stack/cable_coil/New(loc, length = MAXCOIL, var/param_color = null)
..()
@@ -233,10 +514,38 @@
color = item_color
pixel_x = rand(-2,2)
pixel_y = rand(-2,2)
- updateicon()
+ update_icon()
update_wclass()
-/obj/item/stack/cable_coil/proc/updateicon()
+///////////////////////////////////
+// General procedures
+///////////////////////////////////
+
+//you can use wires to heal robotics
+/obj/item/stack/cable_coil/attack(mob/M as mob, mob/user as mob)
+ if(istype(M,/mob/living/carbon/human))
+ var/mob/living/carbon/human/H = M
+ var/datum/organ/external/S = H.get_organ(user.zone_sel.selecting)
+ if(!(S.status & ORGAN_ROBOT) || user.a_intent != "help")
+ return ..()
+
+ if(H.species.flags & IS_SYNTHETIC)
+ if(M == user)
+ user << "\red You can't repair damage to your own body - it's against OH&S."
+ return
+
+ if(S.burn_dam > 0 && use(1))
+ S.heal_damage(0,15,0,1)
+ user.visible_message("\red \The [user] repairs some burn damage on \the [M]'s [S.display_name] with \the [src].")
+ return
+ else
+ user << "Nothing to fix!"
+
+ else
+ return ..()
+
+
+/obj/item/stack/cable_coil/update_icon()
if (!color)
color = pick(COLOR_RED, COLOR_BLUE, COLOR_GREEN, COLOR_ORANGE, COLOR_WHITE, COLOR_PINK, COLOR_YELLOW, COLOR_CYAN)
item_color = color
@@ -259,12 +568,13 @@
/obj/item/stack/cable_coil/examine()
set src in view(1)
- if(amount == 1)
+ if(get_amount() == 1)
usr << "A short piece of power cable."
- else if(amount == 2)
+ else if(get_amount() == 2)
usr << "A piece of power cable."
else
- usr << "A coil of power cable. There are [amount] lengths of cable in the coil."
+ usr << "A coil of power cable. There are [get_amount()] lengths of cable in the coil."
+
/obj/item/stack/cable_coil/verb/make_restraint()
set name = "Make Cable Restraints"
@@ -274,26 +584,28 @@
if(ishuman(M) && !M.restrained() && !M.stat && !M.paralysis && ! M.stunned)
if(!istype(usr.loc,/turf)) return
if(src.amount <= 14)
- usr << "You need at least 15 lengths to make restraints!"
+ usr << "\red You need at least 15 lengths to make restraints!"
return
var/obj/item/weapon/handcuffs/cable/B = new /obj/item/weapon/handcuffs/cable(usr.loc)
- B.color = item_color
- usr << "You wind some cable together to make some restraints."
+ B.icon_state = "cuff_[item_color]"
+ usr << "\blue You wind some cable together to make some restraints."
src.use(15)
else
- usr << "\blue You cannot do that."
+ usr << "\blue You cannot do that."
..()
+// Items usable on a cable coil :
+// - Wirecutters : cut them duh !
+// - Cable coil : merge cables
/obj/item/stack/cable_coil/attackby(obj/item/weapon/W, mob/user)
+ ..()
if( istype(W, /obj/item/weapon/wirecutters) && src.amount > 1)
src.amount--
new/obj/item/stack/cable_coil(user.loc, 1,item_color)
- user << "You cut a piece off the cable coil."
- src.updateicon()
- src.update_wclass()
+ user << "You cut a piece off the cable coil."
+ src.update_icon()
return
-
- else if( istype(W, /obj/item/stack/cable_coil) )
+ else if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = W
if(C.amount >= MAXCOIL)
user << "The coil is too long, you cannot add any more cable to it."
@@ -301,54 +613,65 @@
if( (C.amount + src.amount <= MAXCOIL) )
user << "You join the cable coils together."
- C.add(src.amount) // give it cable
+ C.give(src.amount) // give it cable
src.use(src.amount) // make sure this one cleans up right
+ return
else
var/amt = MAXCOIL - C.amount
user << "You transfer [amt] length\s of cable from one coil to the other."
- C.add(amt)
+ C.give(amt)
src.use(amt)
- return
- ..()
+ return
-/obj/item/stack/cable_coil/attack_hand(mob/user as mob)
- if (user.get_inactive_hand() == src)
- var/obj/item/stack/cable_coil/F = new /obj/item/stack/cable_coil(user, 1, color)
- F.copy_evidences(src)
- user.put_in_hands(F)
- src.add_fingerprint(user)
- F.add_fingerprint(user)
- use(1)
+//remove cables from the stack
+/* This is probably reduntant
+/obj/item/stack/cable_coil/use(var/used)
+ if(src.amount < used)
+ return 0
+ else if (src.amount == used)
+ if(ismob(loc)) //handle mob icon update
+ var/mob/M = loc
+ M.unEquip(src)
+ qdel(src)
+ return 1
else
- ..()
- return
-
+ amount -= used
+ update_icon()
+ return 1
+*/
/obj/item/stack/cable_coil/use(var/used)
. = ..()
- updateicon()
- update_wclass()
+ update_icon()
return
-/obj/item/stack/cable_coil/add(var/extra)
- . = ..()
- updateicon()
- update_wclass()
- return
+//add cables to the stack
+/obj/item/stack/cable_coil/proc/give(var/extra)
+ if(amount + extra > MAXCOIL)
+ amount = MAXCOIL
+ else
+ amount += extra
+ update_icon()
+
+///////////////////////////////////////////////
+// Cable laying procedures
+//////////////////////////////////////////////
// called when cable_coil is clicked on a turf/simulated/floor
-
/obj/item/stack/cable_coil/proc/turf_place(turf/simulated/floor/F, mob/user)
-
if(!isturf(user.loc))
return
- if(get_dist(F,user) > 1)
- user << "You can't lay cable at a place that far away."
+ if(get_amount() < 1) // Out of cable
+ user << "There is no cable left."
return
- if(F.intact) // if floor is intact, complain
- user << "You can't lay cable there unless the floor tiles are removed."
+ if(get_dist(F,user) > 1) // Too far
+ user << "You can't lay cable at a place that far away."
+ return
+
+ if(F.intact) // Ff floor is intact, complain
+ user << "You can't lay cable there unless the floor tiles are removed."
return
else
@@ -396,49 +719,47 @@
D.updateicon()
PN.add_cable(D)
-
D.mergeConnectedNetworksOnTurf()
// do the normal stuff
else
///// Z-Level Stuff
-
for(var/obj/structure/cable/LC in F)
if((LC.d1 == dirn && LC.d2 == 0 ) || ( LC.d2 == dirn && LC.d1 == 0))
user << "There's already a cable at that position."
return
- var/obj/structure/cable/C = new(F)
+ var/obj/structure/cable/C = new(F)
- C.cableColor(item_color)
+ C.cableColor(item_color)
- C.d1 = 0
- C.d2 = dirn
- C.add_fingerprint(user)
- C.updateicon()
+ //set up the new cable
+ C.d1 = 0 //it's a O-X node cable
+ C.d2 = dirn
+ C.add_fingerprint(user)
+ C.updateicon()
- var/datum/powernet/PN = new()
- PN.add_cable(C)
+ //create a new powernet with the cable, if needed it will be merged later
+ var/datum/powernet/PN = new()
+ PN.add_cable(C)
- C.mergeConnectedNetworks(C.d2)
- C.mergeConnectedNetworksOnTurf()
+ C.mergeConnectedNetworks(C.d2) //merge the powernet with adjacents powernets
+ C.mergeConnectedNetworksOnTurf() //merge the powernet with on turf powernets
- if(C.d2 & (C.d2 - 1))// if the cable is layed diagonally, check the others 2 possible directions
- C.mergeDiagonalsNetworks(C.d2)
+ if(C.d2 & (C.d2 - 1))// if the cable is layed diagonally, check the others 2 possible directions
+ C.mergeDiagonalsNetworks(C.d2)
- use(1)
- if (C.shock(user, 50))
- if (prob(50)) //fail
- new/obj/item/stack/cable_coil(C.loc, 1, C.color)
- del(C)
- //src.laying = 1
- //last = C
+ use(1)
+
+ if (C.shock(user, 50))
+ if (prob(50)) //fail
+ new/obj/item/stack/cable_coil(C.loc, 1, C.color)
+ del(C) // qdel
// called when cable_coil is click on an installed obj/cable
-
+// or click on a turf that already contains a "node" cable
/obj/item/stack/cable_coil/proc/cable_join(obj/structure/cable/C, mob/user)
-
var/turf/U = user.loc
if(!isturf(U))
return
@@ -449,7 +770,7 @@
return
if(get_dist(C, user) > 1) // make sure it's close enough
- user << "You can't lay cable at a place that far away."
+ user << "You can't lay cable at a place that far away."
return
@@ -459,9 +780,10 @@
var/dirn = get_dir(C, user)
- if(C.d1 == dirn || C.d2 == dirn) // one end of the clicked cable is pointing towards us
+ // one end of the clicked cable is pointing towards us
+ if(C.d1 == dirn || C.d2 == dirn)
if(U.intact) // can't place a cable if the floor is complete
- user << "You can't lay cable there unless the floor tiles are removed."
+ user << "You can't lay cable there unless the floor tiles are removed."
return
else
// cable is pointing at us, we're standing on an open tile
@@ -471,7 +793,7 @@
for(var/obj/structure/cable/LC in U) // check to make sure there's not a cable there already
if(LC.d1 == fdirn || LC.d2 == fdirn)
- user << "There's already a cable at that position."
+ user << "There's already a cable at that position."
return
var/obj/structure/cable/NC = new(U)
@@ -493,13 +815,16 @@
NC.mergeDiagonalsNetworks(NC.d2)
use(1)
+
if (NC.shock(user, 50))
if (prob(50)) //fail
new/obj/item/stack/cable_coil(NC.loc, 1, NC.color)
- del(NC)
+ del(NC) // qdel
return
- else if(C.d1 == 0) // exisiting cable doesn't point at our position, so see if it's a stub
+
+ // exisiting cable doesn't point at our position, so see if it's a stub
+ else if(C.d1 == 0)
// if so, make it a full cable pointing from it's old direction to our dirn
var/nd1 = C.d2 // these will be the new directions
var/nd2 = dirn
@@ -514,7 +839,7 @@
if(LC == C) // skip the cable we're interacting with
continue
if((LC.d1 == nd1 && LC.d2 == nd2) || (LC.d1 == nd2 && LC.d2 == nd1) ) // make sure no cable matches either direction
- user << "There's already a cable at that position."
+ user << "There's already a cable at that position."
return
@@ -527,8 +852,8 @@
C.updateicon()
- C.mergeConnectedNetworks(C.d1)
- C.mergeConnectedNetworks(C.d2)
+ C.mergeConnectedNetworks(C.d1) //merge the powernets...
+ C.mergeConnectedNetworks(C.d2) //...in the two new cable directions
C.mergeConnectedNetworksOnTurf()
if(C.d1 & (C.d1 - 1))// if the cable is layed diagonally, check the others 2 possible directions
@@ -538,148 +863,19 @@
C.mergeDiagonalsNetworks(C.d2)
use(1)
+
if (C.shock(user, 50))
if (prob(50)) //fail
new/obj/item/stack/cable_coil(C.loc, 2, C.color)
- del(C)
+ del(C) // qdel
return
C.denode()// this call may have disconnected some cables that terminated on the centre of the turf, if so split the powernets.
return
-//handles merging diagonally matching cables
-//for info : direction^3 is flipping horizontally, direction^12 is flipping vertically
-/obj/structure/cable/proc/mergeDiagonalsNetworks(var/direction)
-
- //search for and merge diagonally matching cables from the first direction component (north/south)
- var/turf/T = get_step(src, direction&3)//go north/south
-
- for(var/obj/structure/cable/C in T)
-
- if(!C)
- continue
-
- if(src == C)
- continue
-
- if(C.d1 == (direction^3) || C.d2 == (direction^3)) //we've got a diagonally matching cable
- if(!C.powernet) //if the matching cable somehow got no powernet, make him one (should not happen for cables)
- var/datum/powernet/newPN = new()
- newPN.add_cable(C)
-
- if(powernet) //if we already have a powernet, then merge the two powernets
- merge_powernets(powernet,C.powernet)
- else
- C.powernet.add_cable(src) //else, we simply connect to the matching cable powernet
-
- //the same from the second direction component (east/west)
- T = get_step(src, direction&12)//go east/west
-
- for(var/obj/structure/cable/C in T)
-
- if(!C)
- continue
-
- if(src == C)
- continue
- if(C.d1 == (direction^12) || C.d2 == (direction^12)) //we've got a diagonally matching cable
- if(!C.powernet) //if the matching cable somehow got no powernet, make him one (should not happen for cables)
- var/datum/powernet/newPN = new()
- newPN.add_cable(C)
-
- if(powernet) //if we already have a powernet, then merge the two powernets
- merge_powernets(powernet,C.powernet)
- else
- C.powernet.add_cable(src) //else, we simply connect to the matching cable powernet
-
-/obj/structure/cable/proc/mergeConnectedNetworks(var/direction)
- var/turf/TB
- if(!(d1 == direction || d2 == direction))
- return
- TB = get_step(src, direction)
-
- for(var/obj/structure/cable/TC in TB)
-
- if(!TC)
- continue
-
- if(src == TC)
- continue
-
- var/fdir = (!direction)? 0 : turn(direction, 180)
-
- if(TC.d1 == fdir || TC.d2 == fdir)
-
- if(!TC.powernet)
- var/datum/powernet/PN = new()
- PN.add_cable(TC)
-
- if(powernet)
- merge_powernets(powernet,TC.powernet)
- else
- TC.powernet.add_cable(src)
-
-// merge with the powernets of power objects in the source turf
-/obj/structure/cable/proc/mergeConnectedNetworksOnTurf()
- var/list/to_connect = list()
-
- if(!powernet) //if we somehow have no powernet, make one (should not happen for cables)
- var/datum/powernet/newPN = new()
- newPN.add_cable(src)
-
- //first let's add turf cables to our powernet
- //then we'll connect machines on turf with a node cable is present
- for(var/AM in loc)
- if(istype(AM,/obj/structure/cable))
- var/obj/structure/cable/C = AM
- if(C.d1 == d1 || C.d2 == d1 || C.d1 == d2 || C.d2 == d2) //only connected if they have a common direction
- if(C.powernet == powernet) continue
- if(C.powernet)
- merge_powernets(powernet, C.powernet)
- else
- powernet.add_cable(C) //the cable was powernetless, let's just add it to our powernet
-
- else if(istype(AM,/obj/machinery/power/apc))
- var/obj/machinery/power/apc/N = AM
- if(!N.terminal) continue // APC are connected through their terminal
-
- if(N.terminal.powernet == powernet)
- continue
-
- to_connect += N.terminal //we'll connect the machines after all cables are merged
-
- else if(istype(AM,/obj/machinery/power)) //other power machines
- var/obj/machinery/power/M = AM
-
- if(M.powernet == powernet)
- continue
-
- to_connect += M //we'll connect the machines after all cables are merged
-
- //now that cables are done, let's connect found machines
- for(var/obj/machinery/power/PM in to_connect)
- if(!PM.connect_to_network())
- PM.disconnect_from_network() //if we somehow can't connect the machine to the new powernet, remove it from the old nonetheless
-
-//should be called after placing a cable which extends another cable, creating a "smooth" cable that no longer terminates in the centre of a turf.
-//needed as this can, unlike other placements, disconnect cables
-/obj/structure/cable/proc/denode()
- var/turf/T1 = loc
- if(!T1) return
-
- var/list/powerlist = power_list(T1,src,0,0) //find the other cables that ended in the centre of the turf, with or without a powernet
- if(powerlist.len>0)
- var/datum/powernet/PN = new()
- propagate_network(powerlist[1],PN) //propagates the new powernet beginning at the source cable
-
- if(PN.is_empty()) //can happen with machines made nodeless when smoothing cables
- del(PN)
-
-obj/structure/cable/proc/cableColor(var/colorC)
- var/color_n = "#DD0000"
- if(colorC)
- color_n = colorC
- color = color_n
+//////////////////////////////
+// Misc.
+/////////////////////////////
/obj/item/stack/cable_coil/cut
item_state = "coil2"
@@ -689,7 +885,7 @@ obj/structure/cable/proc/cableColor(var/colorC)
src.amount = rand(1,2)
pixel_x = rand(-2,2)
pixel_y = rand(-2,2)
- updateicon()
+ update_icon()
update_wclass()
/obj/item/stack/cable_coil/yellow
@@ -716,27 +912,3 @@ obj/structure/cable/proc/cableColor(var/colorC)
/obj/item/stack/cable_coil/random/New()
item_color = pick(COLOR_RED, COLOR_BLUE, COLOR_GREEN, COLOR_WHITE, COLOR_PINK, COLOR_YELLOW, COLOR_CYAN)
..()
-
-/obj/item/stack/cable_coil/attack(mob/M as mob, mob/user as mob)
- if(hasorgans(M))
-
- var/datum/organ/external/S = M:get_organ(user.zone_sel.selecting)
- if(!(S.status & ORGAN_ROBOT) || user.a_intent != "help")
- return ..()
-
- if(istype(M,/mob/living/carbon/human))
- var/mob/living/carbon/human/H = M
- if(H.species.flags & IS_SYNTHETIC)
- if(M == user)
- user << "\red You can't repair damage to your own body - it's against OH&S."
- return
-
- if(S.burn_dam > 0 && use(1))
- S.heal_damage(0,15,0,1)
- user.visible_message("\red \The [user] repairs some burn damage on \the [M]'s [S.display_name] with \the [src].")
- return
- else
- user << "Nothing to fix!"
-
- else
- return ..()
diff --git a/code/modules/power/fractal_reactor.dm b/code/modules/power/fractal_reactor.dm
index 261dc970bb0..51b39bec77f 100644
--- a/code/modules/power/fractal_reactor.dm
+++ b/code/modules/power/fractal_reactor.dm
@@ -10,7 +10,6 @@
icon_state = "tracker" //ICON stolen from solar tracker. There is no need to make new texture for debug item
anchored = 1
density = 1
- directwired = 1
var/power_generation_rate = 2000000 //Defaults to 2MW of power. Should be enough to run SMES charging on full 2 times.
var/powernet_connection_failed = 0
diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm
index 55f95624fb2..f7de023e419 100644
--- a/code/modules/power/port_gen.dm
+++ b/code/modules/power/port_gen.dm
@@ -48,7 +48,6 @@ display round(lastgen) and phorontank amount
icon_state = "portgen0"
density = 1
anchored = 0
- directwired = 0
use_power = 0
var/active = 0
diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm
index c28a786698f..75328dfd3d5 100644
--- a/code/modules/power/power.dm
+++ b/code/modules/power/power.dm
@@ -1,10 +1,16 @@
+//////////////////////////////
+// POWER MACHINERY BASE CLASS
+//////////////////////////////
+
+/////////////////////////////
+// Definitions
+/////////////////////////////
+
/obj/machinery/power
name = null
icon = 'icons/obj/power.dmi'
anchored = 1.0
var/datum/powernet/powernet = null
- var/directwired = 1 // by default, power machines are connected by a cable in a neighbouring turf
- // if set to 0, requires a 0-X cable on this turf
use_power = 0
idle_power_usage = 0
active_power_usage = 0
@@ -13,6 +19,10 @@
disconnect_from_network()
..()
+///////////////////////////////
+// General procedures
+//////////////////////////////
+
// common helper procs for all power machines
/obj/machinery/power/proc/add_avail(var/amount)
if(powernet)
@@ -25,7 +35,7 @@
/obj/machinery/power/proc/surplus()
if(powernet)
- return powernet.surplus()
+ return powernet.avail-powernet.load
else
return 0
@@ -35,18 +45,18 @@
else
return 0
+/obj/machinery/power/proc/disconnect_terminal() // machines without a terminal will just return, no harm no fowl.
+ return
+
// returns true if the area has power on given channel (or doesn't require power).
// defaults to power_channel
-
-/obj/machinery/proc/powered(var/chan = -1)
+/obj/machinery/proc/powered(var/chan = -1) // defaults to power_channel
if(!src.loc)
return 0
- //This is bad. This makes machines which are switched off not update their stat flag correctly when power_change() is called.
- //If use_power is 0, then you probably shouldn't be checking power to begin with.
- //if(!use_power)
- // return 1
+ if(!use_power)
+ return 1
var/area/A = src.loc.loc // make sure it's in an area
if(!A || !isarea(A) || !A.master)
@@ -56,179 +66,23 @@
return A.master.powered(chan) // return power status of the area
// increment the power usage stats for an area
-
-/obj/machinery/proc/use_power(var/amount, var/chan = -1, var/autocalled = 0) // defaults to power_channel
- var/area/A = src.loc.loc // make sure it's in an area
+/obj/machinery/proc/use_power(var/amount, var/chan = -1) // defaults to power_channel
+ var/area/A = get_area(src) // make sure it's in an area
if(!A || !isarea(A) || !A.master)
return
if(chan == -1)
chan = power_channel
A.master.use_power(amount, chan)
- if(!autocalled)
- log_power_update_request(A.master, src)
- A.master.powerupdate = 2 // Decremented by 2 each GC tick, since it's not auto power change we're going to update power twice.
- return 1
-//The master_area optional argument can be used to save on a lot of processing if the master area is already known. This is mainly intended for when this proc is called by the master controller.
-/obj/machinery/proc/power_change(var/area/master_area = null) // called whenever the power settings of the containing area change
+/obj/machinery/proc/power_change() // called whenever the power settings of the containing area change
// by default, check equipment channel & set flag
// can override if needed
- var/has_power
- if (master_area)
- has_power = master_area.powered(power_channel)
- else
- has_power = powered(power_channel)
-
- if(has_power)
+ if(powered(power_channel))
stat &= ~NOPOWER
else
+
stat |= NOPOWER
-
-// the powernet datum
-// each contiguous network of cables & nodes
-
-
-// rebuild all power networks from scratch
-
-/hook/startup/proc/buildPowernets()
- return makepowernets()
-
-/proc/makepowernets()
- for(var/datum/powernet/PN in powernets)
- del(PN)
- powernets.Cut()
-
- for(var/obj/structure/cable/PC in cable_list)
- if(!PC.powernet)
- PC.powernet = new()
-// if(Debug) world.log << "Starting mpn at [PC.x],[PC.y] ([PC.d1]/[PC.d2])"
- powernet_nextlink(PC,PC.powernet)
-
-// if(Debug) world.log << "[powernets.len] powernets found"
-
- for(var/obj/structure/cable/C in cable_list)
- if(!C.powernet) continue
- C.powernet.cables += C
-
- for(var/obj/machinery/power/M in machines)
- if(!M.powernet) continue // APCs have powernet=0 so they don't count as network nodes directly
- M.powernet.nodes[M] = M
-
- return 1
-
-
-// returns a list of all power-related objects (nodes, cable, junctions) in turf,
-// excluding source, that match the direction d
-// if unmarked==1, only return those with no powernet
-/proc/power_list(var/turf/T, var/source, var/d, var/unmarked=0)
- . = list()
- var/fdir = (!d)? 0 : turn(d, 180)
- // the opposite direction to d (or 0 if d==0)
-///// Z-Level Stuff
- var/Zdir
- if(d==11)
- Zdir = 11
- else if (d==12)
- Zdir = 12
- else
- Zdir = 999
-///// Z-Level Stuff
-// world.log << "d=[d] fdir=[fdir]"
- for(var/AM in T)
- if(AM == source) continue //we don't want to return source
-
- if(istype(AM,/obj/machinery/power))
- var/obj/machinery/power/P = AM
- if(P.powernet == 0) continue // exclude APCs which have powernet=0
-
- if(!unmarked || !P.powernet) //if unmarked=1 we only return things with no powernet
- if(P.directwired || (d == 0))
- . += P
-
- else if(istype(AM,/obj/structure/cable))
- var/obj/structure/cable/C = AM
-
- if(!unmarked || !C.powernet)
-///// Z-Level Stuff
- if(C.d1 == fdir || C.d2 == fdir || C.d1 == Zdir || C.d2 == Zdir)
-///// Z-Level Stuff
- . += C
- else if(C.d1 == turn(C.d2, 180))
- . += C
- return .
-
-
-/obj/structure/cable/proc/get_connections()
- . = list() // this will be a list of all connected power objects
- var/turf/T = loc
-
-///// Z-Level Stuff
- if(d1)
- if(d1 <= 10)
- T = get_step(src, d1)
- if(T)
- . += power_list(T, src, d1, 1)
- else if (d1 == 11 || d1 == 12)
- var/turf/controllerlocation = locate(1, 1, z)
- for(var/obj/effect/landmark/zcontroller/controller in controllerlocation)
- if(controller.up && d1 == 12)
- T = locate(src.x, src.y, controller.up_target)
- if(T)
- . += power_list(T, src, 11, 1)
- if(controller.down && d1 == 11)
- T = locate(src.x, src.y, controller.down_target)
- if(T)
- . += power_list(T, src, 12, 1)
- else if(!d1)
- if(T)
- . += power_list(T, src, d1, 1)
-
- if(d2 == 11 || d2 == 12)
- var/turf/controllerlocation = locate(1, 1, z)
- for(var/obj/effect/landmark/zcontroller/controller in controllerlocation)
- if(controller.up && d2 == 12)
- T = locate(src.x, src.y, controller.up_target)
- if(T)
- . += power_list(T, src, 11, 1)
- if(controller.down && d2 == 11)
- T = locate(src.x, src.y, controller.down_target)
- if(T)
- . += power_list(T, src, 12, 1)
- else
- T = get_step(src, d2)
- if(T)
- . += power_list(T, src, d2, 1)
-///// Z-Level Stuff
-
- return .
-
-
-/obj/machinery/power/proc/get_connections()
-
- . = list()
-
- if(!directwired)
- return get_indirect_connections()
-
- var/cdir
-
- for(var/card in cardinal)
- var/turf/T = get_step(loc,card)
- cdir = get_dir(T,loc)
-
- for(var/obj/structure/cable/C in T)
- if(C.powernet) continue
- if(C.d1 == cdir || C.d2 == cdir)
- . += C
- return .
-
-/obj/machinery/power/proc/get_indirect_connections()
- . = list()
- for(var/obj/structure/cable/C in loc)
- if(C.powernet) continue
- if(C.d1 == 0)
- . += C
- return .
+ return
// connect the machine to a powernet if a node cable is present on the turf
/obj/machinery/power/proc/connect_to_network()
@@ -250,20 +104,193 @@
powernet.remove_machine(src)
return 1
-/turf/proc/get_cable_node()
- if(!istype(src, /turf/simulated/floor))
- return null
- for(var/obj/structure/cable/C in src)
- if(C.d1 == 0)
- return C
- return null
+// attach a wire to a power machine - leads from the turf you are standing on
+//almost never called, overwritten by all power machines but terminal and generator
+/obj/machinery/power/attackby(obj/item/weapon/W, mob/user)
-/area/proc/get_apc()
- for(var/area/RA in src.related)
- var/obj/machinery/power/apc/FINDME = locate() in RA
- if (FINDME)
- return FINDME
+ if(istype(W, /obj/item/stack/cable_coil))
+ var/obj/item/stack/cable_coil/coil = W
+
+ var/turf/T = user.loc
+
+ if(T.intact || !istype(T, /turf/simulated/floor))
+ return
+
+ if(get_dist(src, user) > 1)
+ return
+
+ coil.turf_place(T, user)
+ return
+ else
+ ..()
+ return
+
+///////////////////////////////////////////
+// Powernet handling helpers
+//////////////////////////////////////////
+
+//returns all the cables WITHOUT a powernet in neighbors turfs,
+//pointing towards the turf the machine is located at
+/obj/machinery/power/proc/get_connections()
+
+ . = list()
+
+ var/cdir
+ var/turf/T
+
+ for(var/card in cardinal)
+ T = get_step(loc,card)
+ cdir = get_dir(T,loc)
+
+ for(var/obj/structure/cable/C in T)
+ if(C.powernet) continue
+ if(C.d1 == cdir || C.d2 == cdir)
+ . += C
+ return .
+
+//returns all the cables in neighbors turfs,
+//pointing towards the turf the machine is located at
+/obj/machinery/power/proc/get_marked_connections()
+
+ . = list()
+
+ var/cdir
+ var/turf/T
+
+ for(var/card in cardinal)
+ T = get_step(loc,card)
+ cdir = get_dir(T,loc)
+
+ for(var/obj/structure/cable/C in T)
+ if(C.d1 == cdir || C.d2 == cdir)
+ . += C
+ return .
+
+//returns all the NODES (O-X) cables WITHOUT a powernet in the turf the machine is located at
+/obj/machinery/power/proc/get_indirect_connections()
+ . = list()
+ for(var/obj/structure/cable/C in loc)
+ if(C.powernet) continue
+ if(C.d1 == 0) // the cable is a node cable
+ . += C
+ return .
+
+///////////////////////////////////////////
+// GLOBAL PROCS for powernets handling
+//////////////////////////////////////////
+
+
+// returns a list of all power-related objects (nodes, cable, junctions) in turf,
+// excluding source, that match the direction d
+// if unmarked==1, only return those with no powernet
+/proc/power_list(var/turf/T, var/source, var/d, var/unmarked=0, var/cable_only = 0)
+ . = list()
+ var/fdir = (!d)? 0 : turn(d, 180) // the opposite direction to d (or 0 if d==0)
+///// Z-Level Stuff
+ var/Zdir
+ if(d==11)
+ Zdir = 11
+ else if (d==12)
+ Zdir = 12
+ else
+ Zdir = 999
+///// Z-Level Stuff
+ for(var/AM in T)
+ if(AM == source) continue //we don't want to return source
+
+ if(!cable_only && istype(AM,/obj/machinery/power))
+ var/obj/machinery/power/P = AM
+ if(P.powernet == 0) continue // exclude APCs which have powernet=0
+
+ if(!unmarked || !P.powernet) //if unmarked=1 we only return things with no powernet
+ if(d == 0)
+ . += P
+
+ else if(istype(AM,/obj/structure/cable))
+ var/obj/structure/cable/C = AM
+
+ if(!unmarked || !C.powernet)
+///// Z-Level Stuff
+ if(C.d1 == fdir || C.d2 == fdir || C.d1 == Zdir || C.d2 == Zdir)
+///// Z-Level Stuff
+ . += C
+ else if(C.d1 == d || C.d2 == d)
+ . += C
+ return .
+
+/hook/startup/proc/buildPowernets()
+ return makepowernets()
+
+// rebuild all power networks from scratch - only called at world creation or by the admin verb
+/proc/makepowernets()
+ for(var/datum/powernet/PN in powernets)
+ del(PN)
+ powernets.Cut()
+
+ for(var/obj/structure/cable/PC in cable_list)
+ if(!PC.powernet)
+ var/datum/powernet/NewPN = new()
+ NewPN.add_cable(PC)
+ propagate_network(PC,PC.powernet)
+ return 1
+
+//remove the old powernet and replace it with a new one throughout the network.
+/proc/propagate_network(var/obj/O, var/datum/powernet/PN)
+ //world.log << "propagating new network"
+ var/list/worklist = list()
+ var/list/found_machines = list()
+ var/index = 1
+ var/obj/P = null
+
+ worklist+=O //start propagating from the passed object
+
+ while(index<=worklist.len) //until we've exhausted all power objects
+ P = worklist[index] //get the next power object found
+ index++
+
+ if( istype(P,/obj/structure/cable))
+ var/obj/structure/cable/C = P
+ if(C.powernet != PN) //add it to the powernet, if it isn't already there
+ PN.add_cable(C)
+ worklist |= C.get_connections() //get adjacents power objects, with or without a powernet
+
+ else if(P.anchored && istype(P,/obj/machinery/power))
+ var/obj/machinery/power/M = P
+ found_machines |= M //we wait until the powernet is fully propagates to connect the machines
+
+ else
+ continue
+
+ //now that the powernet is set, connect found machines to it
+ for(var/obj/machinery/power/PM in found_machines)
+ if(!PM.connect_to_network()) //couldn't find a node on its turf...
+ PM.disconnect_from_network() //... so disconnect if already on a powernet
+
+
+//Merge two powernets, the bigger (in cable length term) absorbing the other
+/proc/merge_powernets(var/datum/powernet/net1, var/datum/powernet/net2)
+ if(!net1 || !net2) //if one of the powernet doesn't exist, return
+ return
+
+ if(net1 == net2) //don't merge same powernets
+ return
+
+ //We assume net1 is larger. If net2 is in fact larger we are just going to make them switch places to reduce on code.
+ if(net1.cables.len < net2.cables.len) //net2 is larger than net1. Let's switch them around
+ var/temp = net1
+ net1 = net2
+ net2 = temp
+
+ //merge net2 into net1
+ for(var/obj/structure/cable/Cable in net2.cables) //merge cables
+ net1.add_cable(Cable)
+
+ for(var/obj/machinery/power/Node in net2.nodes) //merge power machines
+ if(!Node.connect_to_network())
+ Node.disconnect_from_network() //if somehow we can't connect the machine to the new powernet, disconnect it from the old nonetheless
+
+ return net1
//Determines how strong could be shock, deals damage to mob, uses power.
//M is a mob who touched wire/whatever
@@ -272,17 +299,11 @@
//No animations will be performed by this proc.
/proc/electrocute_mob(mob/living/carbon/M as mob, var/power_source, var/obj/source, var/siemens_coeff = 1.0)
if(istype(M.loc,/obj/mecha)) return 0 //feckin mechs are dumb
-
- //This is for performance optimization only.
- //DO NOT modify siemens_coeff here. That is checked in human/electrocute_act()
if(istype(M,/mob/living/carbon/human))
var/mob/living/carbon/human/H = M
- if(H.species.insulated)
- return 0
- else if(H.gloves)
+ if(H.gloves)
var/obj/item/clothing/gloves/G = H.gloves
- if(G.siemens_coefficient == 0)
- return 0 //to avoid spamming with insulated glvoes on
+ if(G.siemens_coefficient == 0) return 0 //to avoid spamming with insulated glvoes on
var/area/source_area
if(istype(power_source,/area))
@@ -328,11 +349,10 @@
var/drained_energy = drained_hp*20
if (source_area)
- source_area.use_power(drained_energy)
+ source_area.use_power(drained_energy/CELLRATE)
else if (istype(power_source,/datum/powernet))
- //var/drained_power = drained_energy/CELLRATE //convert from "joules" to "watts" <<< NO. THIS IS WRONG. CELLRATE DOES NOT CONVERT TO OR FROM JOULES.
- PN.draw_power(drained_energy)
+ var/drained_power = drained_energy/CELLRATE //convert from "joules" to "watts"
+ PN.load+=drained_power
else if (istype(power_source, /obj/item/weapon/cell))
- cell.use(drained_energy*CELLRATE) //convert to units of charge.
+ cell.use(drained_energy)
return drained_energy
-
diff --git a/code/modules/power/powernet.dm b/code/modules/power/powernet.dm
index 72635968f6b..f321c52a3ff 100644
--- a/code/modules/power/powernet.dm
+++ b/code/modules/power/powernet.dm
@@ -1,17 +1,13 @@
/datum/powernet
var/list/cables = list() // all cables & junctions
- var/list/nodes = list() // all APCs & sources
+ var/list/nodes = list() // all connected machines
- var/newload = 0
- var/load = 0
- var/newavail = 0
- var/avail = 0
- var/viewload = 0
- var/number = 0
-
- var/perapc = 0 // per-apc avilability
- var/perapc_excess = 0
- var/netexcess = 0
+ var/load = 0 // the current load on the powernet, increased by each machine at processing
+ var/newavail = 0 // what available power was gathered last tick, then becomes...
+ var/avail = 0 //...the current available power in the powernet
+ var/viewload = 0 // the load as it appears on the power console (gradually updated)
+ var/number = 0 // Unused //TODEL
+ var/netexcess = 0 // excess power on the powernet (typically avail-load)
/datum/powernet/New()
powernets += src
@@ -19,9 +15,34 @@
/datum/powernet/Del()
powernets -= src
+/datum/powernet/proc/draw_power(var/amount)
+ var/drained = min(amount, avail)
+ load += drained
+ return drained
+
/datum/powernet/proc/is_empty()
return !cables.len && !nodes.len
+//remove a cable from the current powernet
+//if the powernet is then empty, delete it
+//Warning : this proc DON'T check if the cable exists
+/datum/powernet/proc/remove_cable(var/obj/structure/cable/C)
+ cables -= C
+ C.powernet = null
+ if(is_empty())//the powernet is now empty...
+ del(src)///... delete it - qdel
+
+//add a cable to the current powernet
+//Warning : this proc DON'T check if the cable exists
+/datum/powernet/proc/add_cable(var/obj/structure/cable/C)
+ if(C.powernet)// if C already has a powernet...
+ if(C.powernet == src)
+ return
+ else
+ C.powernet.remove_cable(C) //..remove it
+ C.powernet = src
+ cables +=C
+
//remove a power machine from the current powernet
//if the powernet is then empty, delete it
//Warning : this proc DON'T check if the machine exists
@@ -43,211 +64,28 @@
M.powernet = src
nodes[M] = M
-//remove a cable from the current powernet
-//if the powernet is then empty, delete it
-//Warning : this proc DON'T check if the cable exists
-/datum/powernet/proc/remove_cable(var/obj/structure/cable/C)
- cables -= C
- C.powernet = null
- if(is_empty())//the powernet is now empty...
- del(src)///... delete it - qdel
+//handles the power changes in the powernet
+//called every ticks by the powernet controller
+/datum/powernet/proc/reset()
-//add a cable to the current powernet
-//Warning : this proc DON'T check if the cable exists
-/datum/powernet/proc/add_cable(var/obj/structure/cable/C)
- if(C.powernet)// if C already has a powernet...
- if(C.powernet == src)
- return
- else
- C.powernet.remove_cable(C) //..remove it
- C.powernet = src
- cables +=C
+ //see if there's a surplus of power remaining in the powernet and stores unused power in the SMES
+ netexcess = avail - load
-/datum/powernet/proc/process()
- load = newload
- newload = 0
+ if(netexcess > 100 && nodes && nodes.len) // if there was excess power last cycle
+ for(var/obj/machinery/power/smes/S in nodes) // find the SMESes in the network
+ S.restore() // and restore some of the power that was used
+
+ //updates the viewed load (as seen on power computers)
+ viewload = 0.8*viewload + 0.2*load
+ viewload = round(viewload)
+
+ //reset the powernet
+ load = 0
avail = newavail
newavail = 0
-
- viewload = 0.8*viewload + 0.2*load
-
- viewload = round(viewload)
-
- var/numapc = 0
-
- if(nodes && nodes.len) // Added to fix a bad list bug -- TLE
- for(var/obj/machinery/power/terminal/term in nodes)
- if( istype( term.master, /obj/machinery/power/apc ) )
- numapc++
-
- netexcess = avail - load
-
- if(numapc)
- //very simple load balancing. If there was a net excess this tick then it must have been that some APCs used less than perapc, since perapc*numapc = avail
- //Therefore we can raise the amount of power rationed out to APCs on the assumption that those APCs that used less than perapc will continue to do so.
- //If that assumption fails, then some APCs will miss out on power next tick, however it will be rebalanced for the tick after.
- if (netexcess >= 0)
- perapc_excess += min(netexcess/numapc, (avail - perapc) - perapc_excess)
- else
- perapc_excess = 0
-
- perapc = avail/numapc + perapc_excess
-
- if( netexcess > 100) // if there was excess power last cycle
- if(nodes && nodes.len)
- for(var/obj/machinery/power/smes/S in nodes) // find the SMESes in the network
- if(S.powernet == src)
- S.restore() // and restore some of the power that was used
- else
- error("[S.name] (\ref[S]) had a [S.powernet ? "different (\ref[S.powernet])" : "null"] powernet to our powernet (\ref[src]).")
- nodes.Remove(S)
-
-
-
-
-//Returns the amount of available power
-/datum/powernet/proc/surplus()
- return max(avail - newload, 0)
-
-//Returns the amount of excess power (before refunding to SMESs) from last tick.
-//This is for machines that might adjust their power consumption using this data.
-/datum/powernet/proc/last_surplus()
- return max(avail - load, 0)
-
-//Attempts to draw power from a powernet. Returns the actual amount of power drawn
-/datum/powernet/proc/draw_power(var/requested_amount)
- var/surplus = max(avail - newload, 0)
- var/actual_draw = min(requested_amount, surplus)
- newload += actual_draw
-
- return actual_draw
-
-// cut a powernet at this cable object
-/datum/powernet/proc/cut_cable(var/obj/structure/cable/C)
- var/turf/T1 = C.loc
- if(!T1) return
- var/node = 0
- if(C.d1 == 0)
- node = 1
-
- var/turf/T2
- if(C.d2) T2 = get_step(T1, C.d2)
- if(C.d1) T1 = get_step(T1, C.d1)
-
-
- var/list/P1 = power_list(T1, C, C.d1) // what joins on to cut cable in dir1
- var/list/P2 = power_list(T2, C, C.d2) // what joins on to cut cable in dir2
-
-// if(Debug)
-// for(var/obj/O in P1)
-// world.log << "P1: [O] at [O.x] [O.y] : [istype(O, /obj/structure/cable) ? "[O:d1]/[O:d2]" : null] "
-// for(var/obj/O in P2)
-// world.log << "P2: [O] at [O.x] [O.y] : [istype(O, /obj/structure/cable) ? "[O:d1]/[O:d2]" : null] "
-
-
- if(P1.len == 0 || P2.len == 0)//if nothing in either list, then the cable was an endpoint no need to rebuild the powernet,
- cables -= C //just remove cut cable from the list
-// if(Debug) world.log << "Was end of cable"
- return
-
- //null the powernet reference of all cables & nodes in this powernet
- var/i=1
- while(i<=cables.len)
- var/obj/structure/cable/Cable = cables[i]
- if(Cable)
- Cable.powernet = null
- if(Cable == C)
- cables.Cut(i,i+1)
- continue
- i++
- i=1
- while(i<=nodes.len)
- var/obj/machinery/power/Node = nodes[i]
- if(Node)
- Node.powernet = null
- i++
-
- // remove the cut cable from the network
-// C.netnum = -1
-
- C.loc = null
-
- powernet_nextlink(P1[1], src) // propagate network from 1st side of cable, using current netnum //TODO?
-
- // now test to see if propagation reached to the other side
- // if so, then there's a loop in the network
- var/notlooped = 0
- for(var/O in P2)
- if( istype(O, /obj/machinery/power) )
- var/obj/machinery/power/Machine = O
- if(Machine.powernet != src)
- notlooped = 1
- break
- else if( istype(O, /obj/structure/cable) )
- var/obj/structure/cable/Cable = O
- if(Cable.powernet != src)
- notlooped = 1
- break
-
- if(notlooped)
- // not looped, so make a new powernet
- var/datum/powernet/PN = new()
- powernets += PN
-
-// if(Debug) world.log << "Was not looped: spliting PN#[number] ([cables.len];[nodes.len])"
-
- i=1
- while(i<=cables.len)
- var/obj/structure/cable/Cable = cables[i]
- if(Cable && !Cable.powernet) // non-connected cables will have powernet=null, since they weren't reached by propagation
- PN.add_cable(Cable)
- continue
- i++
-
- i=1
- while(i<=nodes.len)
- var/obj/machinery/power/Node = nodes[i]
- if(Node && !Node.powernet)
- Node.powernet = PN
- nodes.Cut(i,i+1)
- PN.nodes[Node] = Node
- continue
- i++
-
- // Disconnect machines connected to nodes
- if(node)
- for(var/obj/machinery/power/P in T1)
- if(P.powernet && !P.powernet.nodes[src])
- P.disconnect_from_network()
-// if(Debug)
-// world.log << "Old PN#[number] : ([cables.len];[nodes.len])"
-// world.log << "New PN#[PN.number] : ([PN.cables.len];[PN.nodes.len])"
-//
-// else
-// if(Debug)
-// world.log << "Was looped."
-// //there is a loop, so nothing to be done
-// return
-
/datum/powernet/proc/get_electrocute_damage()
- switch(avail)/*
- if (1300000 to INFINITY)
- return min(rand(70,150),rand(70,150))
- if (750000 to 1300000)
- return min(rand(50,115),rand(50,115))
- if (100000 to 750000-1)
- return min(rand(35,101),rand(35,101))
- if (75000 to 100000-1)
- return min(rand(30,95),rand(30,95))
- if (50000 to 75000-1)
- return min(rand(25,80),rand(25,80))
- if (25000 to 50000-1)
- return min(rand(20,70),rand(20,70))
- if (10000 to 25000-1)
- return min(rand(20,65),rand(20,65))
- if (1000 to 10000-1)
- return min(rand(10,20),rand(10,20))*/
+ switch(avail)
if (1000000 to INFINITY)
return min(rand(50,160),rand(50,160))
if (200000 to 1000000)
@@ -261,84 +99,23 @@
else
return 0
-/proc/powernet_nextlink(var/obj/O, var/datum/powernet/PN)
- var/list/P
+////////////////////////////////////////////////
+// Misc.
+///////////////////////////////////////////////
- while(1)
- if( istype(O,/obj/structure/cable) )
- var/obj/structure/cable/C = O
- C.powernet = PN
- P = C.get_connections()
- else if(O.anchored && istype(O,/obj/machinery/power))
- var/obj/machinery/power/M = O
- M.powernet = PN
- P = M.get_connections()
+// return a knot cable (O-X) if one is present in the turf
+// null if there's none
+/turf/proc/get_cable_node()
+ if(!istype(src, /turf/simulated/floor))
+ return null
+ for(var/obj/structure/cable/C in src)
+ if(C.d1 == 0)
+ return C
+ return null
- else
- return
-
- if(P.len == 0) return
-
- O = P[1]
-
- for(var/L = 2 to P.len)
- powernet_nextlink(P[L], PN)
-
-//The powernet that calls this proc will consume the other powernet - Rockdtben
-//TODO: rewrite so the larger net absorbs the smaller net
-/proc/merge_powernets(var/datum/powernet/net1, var/datum/powernet/net2)
- if(!net1 || !net2) return
- if(net1 == net2) return
-
- //We assume net1 is larger. If net2 is in fact larger we are just going to make them switch places to reduce on code.
- if(net1.cables.len < net2.cables.len) //net2 is larger than net1. Let's switch them around
- var/temp = net1
- net1 = net2
- net2 = temp
-
- for(var/i=1,i<=net2.nodes.len,i++) //merge net2 into net1
- var/obj/machinery/power/Node = net2.nodes[i]
- if(Node)
- Node.powernet = net1
- net1.nodes[Node] = Node
-
- for(var/i=1,i<=net2.cables.len,i++)
- var/obj/structure/cable/Cable = net2.cables[i]
- if(Cable)
- net1.add_cable(Cable)
-
- del(net2)
- return net1
-
-//remove the old powernet and replace it with a new one throughout the network.
-/proc/propagate_network(var/obj/O, var/datum/powernet/PN)
- //world.log << "propagating new network"
- var/list/worklist = list()
- var/list/found_machines = list()
- var/index = 1
- var/obj/P = null
-
- worklist+=O //start propagating from the passed object
-
- while(index<=worklist.len) //until we've exhausted all power objects
- P = worklist[index] //get the next power object found
- index++
-
- if(istype(P,/obj/structure/cable))
- var/obj/structure/cable/C = P
- if(C.powernet != PN) //add it to the powernet, if it isn't already there
- PN.add_cable(C)
- worklist |= C.get_connections() //get adjacents power objects, with or without a powernet
-
- else if(P.anchored && istype(P,/obj/machinery/power))
- var/obj/machinery/power/M = P
- found_machines |= M //we wait until the powernet is fully propagates to connect the machines
-
- else
- continue
-
- //now that the powernet is set, connect found machines to it
- for(var/obj/machinery/power/PM in found_machines)
- if(!PM.connect_to_network()) //couldn't find a node on its turf...
- PM.disconnect_from_network() //... so disconnect if already on a powernet
\ No newline at end of file
+/area/proc/get_apc()
+ for(var/area/RA in src.related)
+ var/obj/machinery/power/apc/FINDME = locate() in RA
+ if (FINDME)
+ return FINDME
\ No newline at end of file
diff --git a/code/modules/power/singularity/collector.dm b/code/modules/power/singularity/collector.dm
index 37c7b5cf869..d99ec8e681f 100644
--- a/code/modules/power/singularity/collector.dm
+++ b/code/modules/power/singularity/collector.dm
@@ -8,7 +8,6 @@ var/global/list/rad_collectors = list()
icon_state = "ca"
anchored = 0
density = 1
- directwired = 1
req_access = list(access_engine_equip)
// use_power = 0
var/obj/item/weapon/tank/phoron/P = null
@@ -30,7 +29,7 @@ var/global/list/rad_collectors = list()
//so that we don't zero out the meter if the SM is processed first.
last_power = last_power_new
last_power_new = 0
-
+
if(P)
if(P.air_contents.gas["phoron"] == 0)
diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm
index d05b0820579..6958c63d584 100644
--- a/code/modules/power/singularity/emitter.dm
+++ b/code/modules/power/singularity/emitter.dm
@@ -40,7 +40,6 @@
..()
if(state == 2 && anchored)
connect_to_network()
- src.directwired = 1
/obj/machinery/power/emitter/Del()
message_admins("Emitter deleted at ([x],[y],[z] - JMP)",0,1)
@@ -125,13 +124,13 @@
else
src.fire_delay = rand(min_burst_delay, max_burst_delay)
src.shot_number = 0
-
+
//need to calculate the power per shot as the emitter doesn't fire continuously.
var/burst_time = (min_burst_delay + max_burst_delay)/2 + 2*(burst_shots-1)
var/power_per_shot = active_power_usage * (burst_time/10) / burst_shots
var/obj/item/projectile/beam/emitter/A = new /obj/item/projectile/beam/emitter( src.loc )
A.damage = round(power_per_shot/EMITTER_DAMAGE_POWER_TRANSFER)
-
+
playsound(src.loc, 'sound/weapons/emitter.ogg', 25, 1)
if(prob(35))
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
@@ -198,7 +197,6 @@
state = 2
user << "You weld the [src] to the floor."
connect_to_network()
- src.directwired = 1
else
user << "\red You need more welding fuel to complete this task."
if(2)
@@ -212,7 +210,6 @@
state = 1
user << "You cut the [src] free from the floor."
disconnect_from_network()
- src.directwired = 0
else
user << "\red You need more welding fuel to complete this task."
return
diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm
index 768cdfc205e..a7b2ddb70cc 100644
--- a/code/modules/power/solar.dm
+++ b/code/modules/power/solar.dm
@@ -22,7 +22,6 @@ var/list/solars_list = list()
icon_state = "sp_base"
anchored = 1
density = 1
- directwired = 1
use_power = 0
idle_power_usage = 0
active_power_usage = 0
@@ -270,8 +269,6 @@ var/list/solars_list = list()
icon_state = "solar"
anchored = 1
density = 1
- directwired = 1
- use_power = 1
idle_power_usage = 5
active_power_usage = 20
var/id = 0
diff --git a/code/modules/power/terminal.dm b/code/modules/power/terminal.dm
index f739ba93fda..230850fa86e 100644
--- a/code/modules/power/terminal.dm
+++ b/code/modules/power/terminal.dm
@@ -11,7 +11,6 @@
layer = TURF_LAYER
var/obj/machinery/power/master = null
anchored = 1
- directwired = 0 // must have a cable on same turf connecting to terminal
layer = 2.6 // a bit above wires
@@ -21,6 +20,10 @@
if(level==1) hide(T.intact)
return
+/obj/machinery/power/terminal/Del()
+ if(master)
+ master.disconnect_terminal()
+ return ..()
/obj/machinery/power/terminal/hide(var/i)
if(i)
diff --git a/code/modules/power/tracker.dm b/code/modules/power/tracker.dm
index bb8762dad25..94a8b6967f3 100644
--- a/code/modules/power/tracker.dm
+++ b/code/modules/power/tracker.dm
@@ -10,7 +10,6 @@
icon_state = "tracker"
anchored = 1
density = 1
- directwired = 1
use_power = 0 // doesn't use APC power
var/power_usage = 500 //W
diff --git a/code/modules/power/turbine.dm b/code/modules/power/turbine.dm
index fd25e71df1f..35b5dfa6b01 100644
--- a/code/modules/power/turbine.dm
+++ b/code/modules/power/turbine.dm
@@ -22,7 +22,6 @@
anchored = 1
density = 1
var/obj/machinery/compressor/compressor
- directwired = 1
var/turf/simulated/outturf
var/lastgen
diff --git a/code/modules/shieldgen/sheldwallgen.dm b/code/modules/shieldgen/sheldwallgen.dm
index 0c084abdef8..bf30e649e74 100644
--- a/code/modules/shieldgen/sheldwallgen.dm
+++ b/code/modules/shieldgen/sheldwallgen.dm
@@ -70,12 +70,12 @@
var/shieldload = between(500, max_stored_power - storedpower, power_draw) //what we try to draw
shieldload = PN.draw_power(shieldload) //what we actually get
storedpower += shieldload
-
+
//If we're still in the red, then there must not be enough available power to cover our load.
if(storedpower <= 0)
power = 0
return 0
-
+
power = 1 // IVE GOT THE POWER!
return 1
diff --git a/code/modules/shieldgen/shield_capacitor.dm b/code/modules/shieldgen/shield_capacitor.dm
index 6bfc5b664fb..ed68d6ce813 100644
--- a/code/modules/shieldgen/shield_capacitor.dm
+++ b/code/modules/shieldgen/shield_capacitor.dm
@@ -107,14 +107,14 @@
/obj/machinery/shield_capacitor/process()
if (!anchored)
active = 0
-
+
//see if we can connect to a power net.
var/datum/powernet/PN
var/turf/T = src.loc
var/obj/structure/cable/C = T.get_cable_node()
if (C)
PN = C.powernet
-
+
if (PN)
var/power_draw = between(0, max_charge - stored_charge, charge_rate) //what we are trying to draw
power_draw = PN.draw_power(power_draw) //what we actually get
@@ -138,7 +138,7 @@
active = !active
if( href_list["charge_rate"] )
charge_rate = between(10000, charge_rate + text2num(href_list["charge_rate"]), max_charge_rate)
-
+
updateDialog()
/obj/machinery/shield_capacitor/power_change()