diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm
index bb5a3e48b04..25cccde7710 100644
--- a/code/controllers/master_controller.dm
+++ b/code/controllers/master_controller.dm
@@ -328,6 +328,11 @@ datum/controller/game_controller/proc/process_pipenets()
for(var/datum/powernet/Powernet in powernets)
Powernet.reset()
+ // This is necessary to ensure powersinks are always the first devices that drain power from powernet.
+ // Otherwise APCs or other stuff go first, resulting in bad things happening.
+ for(var/obj/item/device/powersink/S in processing_objects)
+ S.drain()
+
datum/controller/game_controller/proc/process_nano()
last_thing_processed = /datum/nanoui
var/i = 1
diff --git a/code/game/objects/items/devices/powersink.dm b/code/game/objects/items/devices/powersink.dm
index 8b2469d2dd4..4acd673ca60 100644
--- a/code/game/objects/items/devices/powersink.dm
+++ b/code/game/objects/items/devices/powersink.dm
@@ -14,108 +14,109 @@
matter = list("metal" = 750,"waste" = 750)
origin_tech = "powerstorage=3;syndicate=5"
- var/drain_rate = 1000000 // amount of power to drain per tick
- var/dissipation_rate = 20000
- var/power_drained = 0 // has drained this much power
- var/max_power = 5e9 // maximum power that can be drained before exploding
- var/mode = 0 // 0 = off, 1=clamped (off), 2=operating
-
+ var/drain_rate = 1500000 // amount of power to drain per tick
+ var/apc_drain_rate = 5000 // Max. amount drained from single APC. In Watts.
+ var/dissipation_rate = 20000 // Passive dissipation of drained power. In Watts.
+ var/power_drained = 0 // Amount of power drained.
+ var/max_power = 5e9 // Detonation point.
+ var/mode = 0 // 0 = off, 1=clamped (off), 2=operating
+ var/drained_this_tick = 0 // This is unfortunately necessary to ensure we process powersinks BEFORE other machinery such as APCs.
+ var/datum/powernet/PN // Our powernet
var/obj/structure/cable/attached // the attached cable
- attackby(var/obj/item/I, var/mob/user)
- if(istype(I, /obj/item/weapon/screwdriver))
- if(mode == 0)
- var/turf/T = loc
- if(isturf(T) && !T.intact)
- attached = locate() in T
- if(!attached)
- user << "No exposed cable here to attach to."
- return
- else
- anchored = 1
- mode = 1
- user << "You attach the device to the cable."
- for(var/mob/M in viewers(user))
- if(M == user) continue
- M << "[user] attaches the power sink to the cable."
- return
+/obj/item/device/powersink/attackby(var/obj/item/I, var/mob/user)
+ if(istype(I, /obj/item/weapon/screwdriver))
+ if(mode == 0)
+ var/turf/T = loc
+ if(isturf(T) && !T.intact)
+ attached = locate() in T
+ if(!attached)
+ user << "No exposed cable here to attach to."
+ return
else
- user << "Device must be placed over an exposed cable to attach to it."
+ anchored = 1
+ mode = 1
+ src.visible_message("[user] attaches [src] to the cable!")
return
else
- if (mode == 2)
- processing_objects.Remove(src) // Now the power sink actually stops draining the station's power if you unhook it. --NeoFite
- anchored = 0
- mode = 0
- user << "You detach the device from the cable."
- for(var/mob/M in viewers(user))
- if(M == user) continue
- M << "[user] detaches the power sink from the cable."
- SetLuminosity(0)
- icon_state = "powersink0"
-
+ user << "Device must be placed over an exposed cable to attach to it."
return
else
- ..()
+ if (mode == 2)
+ processing_objects.Remove(src) // Now the power sink actually stops draining the station's power if you unhook it. --NeoFite
+ anchored = 0
+ mode = 0
+ src.visible_message("[user] detaches [src] from the cable!")
+ SetLuminosity(0)
+ icon_state = "powersink0"
- attack_ai()
+ return
+ else
+ ..()
+
+/obj/item/device/powersink/attack_ai()
+ return
+
+/obj/item/device/powersink/attack_hand(var/mob/user)
+ switch(mode)
+ if(0)
+ ..()
+ if(1)
+ src.visible_message("[user] activates [src]!")
+ mode = 2
+ icon_state = "powersink1"
+ processing_objects.Add(src)
+ if(2) //This switch option wasn't originally included. It exists now. --NeoFite
+ src.visible_message("[user] deactivates [src]!")
+ mode = 1
+ SetLuminosity(0)
+ icon_state = "powersink0"
+ processing_objects.Remove(src)
+
+/obj/item/device/powersink/proc/drain()
+ if(!attached)
return
- attack_hand(var/mob/user)
- switch(mode)
- if(0)
- ..()
+ if(drained_this_tick)
+ return
- if(1)
- user << "You activate the device!"
- for(var/mob/M in viewers(user))
- if(M == user) continue
- M << "[user] activates the power sink!"
- mode = 2
- icon_state = "powersink1"
- processing_objects.Add(src)
+ var/drained = 0
- if(2) //This switch option wasn't originally included. It exists now. --NeoFite
- user << "You deactivate the device!"
- for(var/mob/M in viewers(user))
- if(M == user) continue
- M << "[user] deactivates the power sink!"
- mode = 1
- SetLuminosity(0)
- icon_state = "powersink0"
- processing_objects.Remove(src)
+ if(!PN)
+ return
- process()
- power_drained -= min(dissipation_rate, power_drained)
- if(attached)
- var/datum/powernet/PN = attached.get_powernet()
- if(PN)
- SetLuminosity(12)
- PN.trigger_warning()
- // found a powernet, so drain up to max power from it
- var/drained = PN.draw_power(drain_rate)
-
- // if tried to drain more than available on powernet
- // now look for APCs and drain their cells
- if(drained < drain_rate)
- for(var/obj/machinery/power/terminal/T in PN.nodes)
- // Enough power drained this tick, no need to torture more APCs
- if(drained >= drain_rate)
- break
- if(istype(T.master, /obj/machinery/power/apc))
- var/obj/machinery/power/apc/A = T.master
- if(A.operating && A.cell)
- var/cur_charge = A.cell.charge / CELLRATE
- var/drain_val = min(2000, cur_charge)
-
- A.cell.use(drain_val * CELLRATE)
- drained += drain_val
+ SetLuminosity(12)
+ PN.trigger_warning()
+ // found a powernet, so drain up to max power from it
+ drained = PN.draw_power(drain_rate)
+ // if tried to drain more than available on powernet
+ // now look for APCs and drain their cells
+ if(drained < drain_rate)
+ for(var/obj/machinery/power/terminal/T in PN.nodes)
+ // Enough power drained this tick, no need to torture more APCs
+ if(drained >= drain_rate)
+ break
+ if(istype(T.master, /obj/machinery/power/apc))
+ var/obj/machinery/power/apc/A = T.master
+ if(A.operating && A.cell)
+ var/cur_charge = A.cell.charge / CELLRATE
+ var/drain_val = min(apc_drain_rate, cur_charge)
+ A.cell.use(drain_val * CELLRATE)
+ drained += drain_val
+ power_drained += drained
- if(power_drained > max_power * 0.95)
- playsound(src, 'sound/effects/screech.ogg', 100, 1, 1)
- if(power_drained >= max_power)
- processing_objects.Remove(src)
- explosion(src.loc, 3,6,9,12)
- del(src)
+/obj/item/device/powersink/process()
+ drained_this_tick = 0
+ power_drained -= min(dissipation_rate, power_drained)
+ if(power_drained > max_power * 0.95)
+ playsound(src, 'sound/effects/screech.ogg', 100, 1, 1)
+ if(power_drained >= max_power)
+ processing_objects.Remove(src)
+ explosion(src.loc, 3,6,9,12)
+ del(src)
+ if(attached && attached.powernet)
+ PN = attached.powernet
+ else
+ PN = null
\ No newline at end of file