Powernet Refactor

This commit is contained in:
Fox McCloud
2019-04-27 02:06:04 -04:00
parent 0fb164d041
commit d0a077f9d5
18 changed files with 415 additions and 428 deletions
@@ -13,10 +13,10 @@
if(battery_module && battery_module.battery && battery_module.battery.charge)
var/obj/item/stock_parts/cell/cell = battery_module.battery
if(cell.use(amount * CELLRATE))
if(cell.use(amount * GLOB.CELLRATE))
return TRUE
else // Discharge the cell anyway.
cell.use(min(amount*CELLRATE, cell.charge))
cell.use(min(amount*GLOB.CELLRATE, cell.charge))
return FALSE
return FALSE
@@ -39,7 +39,7 @@
data["powermonitor"] = attached ? TRUE : FALSE
if(attached)
var/datum/powernet/powernet = attached.get_powernet()
var/datum/powernet/powernet = attached.powernet
data["poweravail"] = powernet.avail
data["powerload"] = powernet.viewload
data["powerdemand"] = powernet.load
@@ -20,7 +20,7 @@
return
if(use_power(charge_rate, charging=1))
holder.give_power(charge_rate * CELLRATE)
holder.give_power(charge_rate * GLOB.CELLRATE)
/obj/item/computer_hardware/recharger/APC
+17 -22
View File
@@ -1084,14 +1084,9 @@
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/draw_power(var/amount)
/obj/machinery/power/apc/add_load(amount)
if(terminal && terminal.powernet)
return terminal.powernet.draw_power(amount)
return 0
terminal.add_load(amount)
/obj/machinery/power/apc/avail()
if(terminal)
@@ -1100,7 +1095,6 @@
return 0
/obj/machinery/power/apc/process()
if(stat & (BROKEN|MAINT))
return
if(!area.requires_power)
@@ -1136,18 +1130,21 @@
if(cell && !shorted)
// 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
var/cellused = min(cell.charge, GLOB.CELLRATE * lastused_total) // clamp deduction to a max, amount left in cell
cell.use(cellused)
if(excess > lastused_total) // if power excess recharge the cell
// by the same amount just used
var/draw = draw_power(cellused/CELLRATE) // draw the power needed to charge this cell
cell.give(draw * CELLRATE)
cell.give(cellused)
add_load(cellused/GLOB.CELLRATE) // add the load used to recharge the cell
else // no excess, and not enough per-apc
if( (cell.charge/CELLRATE + excess) >= lastused_total) // can we draw enough from cell+grid to cover last usage?
var/draw = draw_power(excess)
cell.charge = min(cell.maxcharge, cell.charge + CELLRATE * draw) //recharge with what we can
if((cell.charge/GLOB.CELLRATE + excess) >= lastused_total) // can we draw enough from cell+grid to cover last usage?
cell.charge = min(cell.maxcharge, cell.charge + GLOB.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
@@ -1200,14 +1197,12 @@
autoflag = 0
// now trickle-charge the cell
if(src.attempt_charging())
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)
ch = draw_power(ch/CELLRATE) // Removes the power we're taking from the grid
cell.give(ch*CELLRATE) // actually recharge the cell
var/ch = min(excess*GLOB.CELLRATE, cell.maxcharge*GLOB.CHARGELEVEL)
add_load(ch/GLOB.CELLRATE) // Removes the power we're taking from the grid
cell.give(ch) // actually recharge the cell
else
charging = 0 // stop charging
@@ -1220,12 +1215,12 @@
if(chargemode)
if(!charging)
if(excess > cell.maxcharge*CHARGELEVEL)
if(excess > cell.maxcharge*GLOB.CHARGELEVEL)
chargecount++
else
chargecount = 0
if(chargecount >= 10)
if(chargecount == 10)
chargecount = 0
charging = 1
+70 -48
View File
@@ -59,9 +59,8 @@ By design, d1 is the smallest direction and d2 is the highest
/obj/structure/cable/white
color = COLOR_WHITE
/obj/structure/cable/New()
..()
/obj/structure/cable/Initialize(mapload)
. = ..()
// ensure d1 & d2 reflect the icon_state for entering and exiting cable
@@ -101,9 +100,49 @@ By design, d1 is the smallest direction and d2 is the highest
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
////////////////////////////////////////////
// Power related
///////////////////////////////////////////
// All power generation handled in add_avail()
// Machines should use add_load(), surplus(), avail()
// Non-machines should use add_delayedload(), delayed_surplus(), newavail()
/obj/structure/cable/proc/add_avail(amount)
if(powernet)
powernet.newavail += amount
/obj/structure/cable/proc/add_load(amount)
if(powernet)
powernet.load += amount
/obj/structure/cable/proc/surplus()
if(powernet)
return Clamp(powernet.avail-powernet.load, 0, powernet.avail)
else
return 0
/obj/structure/cable/proc/avail()
if(powernet)
return powernet.avail
else
return 0
/obj/structure/cable/proc/add_delayedload(amount)
if(powernet)
powernet.delayedload += amount
/obj/structure/cable/proc/delayed_surplus()
if(powernet)
return Clamp(powernet.newavail - powernet.delayedload, 0, powernet.newavail)
else
return 0
/obj/structure/cable/proc/newavail()
if(powernet)
return powernet.newavail
else
return 0
//Telekinesis has no effect on a cable
/obj/structure/cable/attack_tk(mob/user)
@@ -235,7 +274,7 @@ obj/structure/cable/proc/cable_color(var/colorC)
//handles merging diagonally matching cables
//for info : direction^3 is flipping horizontally, direction^12 is flipping vertically
/obj/structure/cable/proc/mergeDiagonalsNetworks(var/direction)
/obj/structure/cable/proc/mergeDiagonalsNetworks(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
@@ -279,7 +318,7 @@ obj/structure/cable/proc/cable_color(var/colorC)
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)
/obj/structure/cable/proc/mergeConnectedNetworks(direction)
var/fdir = (!direction)? 0 : turn(direction, 180) //flip the direction, to match with the source position on its turf
@@ -317,25 +356,27 @@ obj/structure/cable/proc/cable_color(var/colorC)
//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))
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 == 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))
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)
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
else if(istype(AM, /obj/machinery/power)) //other power machines
var/obj/machinery/power/M = AM
if(M.powernet == powernet)
@@ -353,23 +394,10 @@ obj/structure/cable/proc/cable_color(var/colorC)
//////////////////////////////////////////////
//if powernetless_only = 1, will only get connections without powernet
/obj/structure/cable/proc/get_connections(var/powernetless_only = 0)
/obj/structure/cable/proc/get_connections(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
if(d1) //if not a node cable
T = get_step(src, d1)
@@ -386,20 +414,6 @@ obj/structure/cable/proc/cable_color(var/colorC)
. += 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)
@@ -420,7 +434,8 @@ obj/structure/cable/proc/cable_color(var/colorC)
//needed as this can, unlike other placements, disconnect cables
/obj/structure/cable/proc/denode()
var/turf/T1 = loc
if(!T1) return
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)
@@ -428,13 +443,19 @@ obj/structure/cable/proc/cable_color(var/colorC)
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
qdel(PN) // qdel
qdel(PN)
/obj/structure/cable/proc/auto_propogate_cut_cable(obj/O)
if(O && !QDELETED(O))
var/datum/powernet/newPN = new()// creates a new powernet...
propagate_network(O, newPN)//... and propagates it to the other side of the cable
// cut the cable's powernet at this cable and updates the powergrid
/obj/structure/cable/proc/cut_cable_from_powernet()
/obj/structure/cable/proc/cut_cable_from_powernet(remove=TRUE)
var/turf/T1 = loc
var/list/P_list
if(!T1) return
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...
@@ -452,11 +473,11 @@ obj/structure/cable/proc/cable_color(var/colorC)
var/obj/O = P_list[1]
// remove the cut cable from its turf and powernet, so that it doesn't get count in propagate_network worklist
loc = null
if(remove)
loc = null
powernet.remove_cable(src) //remove the cut cable from its powernet
// queue it to rebuild
SSmachines.deferred_powernet_rebuilds += O
addtimer(CALLBACK(O, .proc/auto_propogate_cut_cable, O), 0) //so we don't rebuild the network X times when singulo/explosion destroys a line of X cables
// Disconnect machines connected to nodes
if(d1 == 0) // if we cut a node (O-X) cable
@@ -464,6 +485,7 @@ obj/structure/cable/proc/cable_color(var/colorC)
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
///////////////////////////////////////////////
+73 -57
View File
@@ -25,18 +25,20 @@
//////////////////////////////
// common helper procs for all power machines
/obj/machinery/power/proc/add_avail(var/amount)
/obj/machinery/power/proc/add_avail(amount)
if(powernet)
powernet.newavail += amount
return TRUE
else
return FALSE
/obj/machinery/power/proc/draw_power(var/amount)
/obj/machinery/power/proc/add_load(amount)
if(powernet)
return powernet.draw_power(amount)
return 0
powernet.load += amount
/obj/machinery/power/proc/surplus()
if(powernet)
return powernet.avail-powernet.load
return Clamp(powernet.avail-powernet.load, 0, powernet.avail)
else
return 0
@@ -46,9 +48,19 @@
else
return 0
/obj/machinery/power/proc/load()
/obj/machinery/power/proc/add_delayedload(amount)
if(powernet)
return powernet.load
powernet.delayedload += amount
/obj/machinery/power/proc/delayed_surplus()
if(powernet)
return Clamp(powernet.newavail - powernet.delayedload, 0, powernet.newavail)
else
return 0
/obj/machinery/power/proc/newavail()
if(powernet)
return powernet.newavail
else
return 0
@@ -58,15 +70,14 @@
// 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) // defaults to power_channel
if(!loc)
return 0
return FALSE
if(!use_power)
return 1
return TRUE
var/area/A = get_area(src) // make sure it's in an area
if(!A)
return 0 // if not, then not powered
return FALSE // if not, then not powered
if(chan == -1)
chan = power_channel
return A.powered(chan) // return power status of the area
@@ -103,21 +114,21 @@
/obj/machinery/power/proc/connect_to_network()
var/turf/T = src.loc
if(!T || !istype(T))
return 0
return FALSE
var/obj/structure/cable/C = T.get_cable_node() //check if we have a node cable on the machine turf, the first found is picked
if(!C || !C.powernet)
return 0
return FALSE
C.powernet.add_machine(src)
return 1
return TRUE
// remove and disconnect the machine from its current powernet
/obj/machinery/power/proc/disconnect_from_network()
if(!powernet)
return 0
return FALSE
powernet.remove_machine(src)
return 1
return TRUE
// 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
@@ -159,7 +170,8 @@
cdir = get_dir(T,loc)
for(var/obj/structure/cable/C in T)
if(C.powernet) continue
if(C.powernet)
continue
if(C.d1 == cdir || C.d2 == cdir)
. += C
return .
@@ -186,7 +198,8 @@
/obj/machinery/power/proc/get_indirect_connections()
. = list()
for(var/obj/structure/cable/C in loc)
if(C.powernet) continue
if(C.powernet)
continue
if(C.d1 == 0) // the cable is a node cable
. += C
return .
@@ -195,48 +208,35 @@
// 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)
/proc/power_list(turf/T, source, d, unmarked=0, 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))
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(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))
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)
if(C.d1 == d || C.d2 == d)
. += C
return .
//remove the old powernet and replace it with a new one throughout the network.
/proc/propagate_network(var/obj/O, var/datum/powernet/PN)
//log_world("propagating new network")
/proc/propagate_network(obj/O, datum/powernet/PN)
var/list/worklist = list()
var/list/found_machines = list()
var/index = 1
@@ -248,13 +248,13 @@
P = worklist[index] //get the next power object found
index++
if( istype(P,/obj/structure/cable))
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))
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
@@ -268,7 +268,7 @@
//Merge two powernets, the bigger (in cable length term) absorbing the other
/proc/merge_powernets(var/datum/powernet/net1, var/datum/powernet/net2)
/proc/merge_powernets(datum/powernet/net1, datum/powernet/net2)
if(!net1 || !net2) //if one of the powernet doesn't exist, return
return
@@ -285,8 +285,6 @@
for(var/obj/structure/cable/Cable in net2.cables) //merge cables
net1.add_cable(Cable)
if(!net2) return net1
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
@@ -299,14 +297,12 @@
//source is an object caused electrocuting (airlock, grille, etc)
//No animations will be performed by this proc.
/proc/electrocute_mob(mob/living/M, power_source, obj/source, siemens_coeff = 1, dist_check = FALSE)
if(!istype(M))
return FALSE
if(istype(M.loc,/obj/mecha))
if(!M || ismecha(M.loc))
return FALSE //feckin mechs are dumb
if(dist_check)
if(!in_range(source, M))
return FALSE
if(istype(M,/mob/living/carbon/human))
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(H.gloves)
var/obj/item/clothing/gloves/G = H.gloves
@@ -326,7 +322,7 @@
if(istype(power_source, /datum/powernet))
PN = power_source
else if(istype(power_source,/obj/item/stock_parts/cell))
else if(istype(power_source, /obj/item/stock_parts/cell))
cell = power_source
else if(istype(power_source, /obj/machinery/power/apc))
var/obj/machinery/power/apc/apc = power_source
@@ -357,10 +353,30 @@
var/drained_energy = drained_hp*20
if(source_area)
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"
drained_power = PN.draw_power(drained_power)
else if(istype(power_source, /obj/item/stock_parts/cell))
source_area.use_power(drained_energy/GLOB.CELLRATE)
else if(istype(power_source, /datum/powernet))
var/drained_power = drained_energy/GLOB.CELLRATE //convert from "joules" to "watts"
PN.delayedload += (min(drained_power, max(PN.newavail - PN.delayedload, 0)))
else if (istype(power_source, /obj/item/stock_parts/cell))
cell.use(drained_energy)
return drained_energy
////////////////////////////////////////////////
// Misc.
///////////////////////////////////////////////
// return a knot cable (O-X) if one is present in the turf
// null if there's none
/turf/proc/get_cable_node()
if(!can_have_cabling())
return null
for(var/obj/structure/cable/C in src)
if(C.d1 == 0)
return C
return null
/area/proc/get_apc()
for(var/obj/machinery/power/apc/APC in GLOB.apcs)
if(APC.area == src)
return APC
+21 -76
View File
@@ -1,19 +1,19 @@
////////////////////////////////////////////
// POWERNET DATUM
// each contiguous network of cables & nodes
/////////////////////////////////////
/datum/powernet
var/number // unique id
var/list/cables = list() // all cables & junctions
var/list/nodes = list() // all connected machines
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/viewavail = 0 // the available power as it appears on the power console (gradually updated)
var/viewload = 0 // the load as it appears on the power console (gradually updated)
var/number = 0 // Unused //TODEL
var/perapc = 0 // per-apc avilability
var/perapc_excess = 0
var/netexcess = 0 // excess power on the powernet (typically avail-load)
var/problem = 0 // If either of these is set to 1 there is some sort of issue at the powernet.
var/netexcess = 0 // excess power on the powernet (typically avail-load)///////
var/delayedload = 0 // load applied to powernet between power ticks.
/datum/powernet/New()
SSmachines.powernets += src
@@ -31,31 +31,21 @@
SSmachines.powernets -= src
return ..()
//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)
/datum/powernet/proc/draw_power(var/amount)
var/draw = between(0, amount, avail - load)
load += draw
return draw
/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)
/datum/powernet/proc/remove_cable(obj/structure/cable/C)
cables -= C
C.powernet = null
if(is_empty())//the powernet is now empty...
qdel(src)///... delete it - qdel
qdel(src)///... delete it
//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)
/datum/powernet/proc/add_cable(obj/structure/cable/C)
if(C.powernet)// if C already has a powernet...
if(C.powernet == src)
return
@@ -67,7 +57,7 @@
//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
/datum/powernet/proc/remove_machine(var/obj/machinery/power/M)
/datum/powernet/proc/remove_machine(obj/machinery/power/M)
nodes -=M
M.powernet = null
if(is_empty())//the powernet is now empty...
@@ -76,7 +66,7 @@
//add a power machine to the current powernet
//Warning : this proc DON'T check if the machine exists
/datum/powernet/proc/add_machine(var/obj/machinery/power/M)
/datum/powernet/proc/add_machine(obj/machinery/power/M)
if(M.powernet)// if M already has a powernet...
if(M.powernet == src)
return
@@ -85,45 +75,23 @@
M.powernet = src
nodes[M] = M
// Triggers warning for certain amount of ticks
/datum/powernet/proc/trigger_warning(var/duration_ticks = 20)
problem = max(duration_ticks, problem)
//handles the power changes in the powernet
//called every ticks by the powernet controller
/datum/powernet/proc/reset()
var/numapc = 0
if(problem > 0)
problem = max(problem - 1, 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++
//see if there's a surplus of power remaining in the powernet and stores unused power in the SMES
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 && 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 = round(load)
// update power consoles
viewavail = round(0.8 * viewavail + 0.2 * avail)
viewload = round(0.8 * viewload + 0.2 * load)
//reset the powernet
load = 0
// reset the powernet
load = delayedload
delayedload = 0
avail = newavail
newavail = 0
@@ -131,27 +99,4 @@
if(avail >= 1000)
return Clamp(20 + round(avail / 25000), 20, 195) + rand(-5, 5)
else
return 0
////////////////////////////////////////////////
// Misc.
///////////////////////////////////////////////
// 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
/area/proc/get_apc()
// This was a simple locate() in src, but an unresolved BYOND bug causes trying to locate() in an
// area to take an inconceivably long time, especially for large areas.
// See: http://www.byond.com/forum/?post=1860571
var/obj/machinery/power/apc/FINDME
for(FINDME in src)
return FINDME
return 0
+59 -40
View File
@@ -23,18 +23,24 @@
var/frequency = 0
var/id_tag = null
var/projectile_type = /obj/item/projectile/beam/emitter
var/projectile_sound = 'sound/weapons/emitter.ogg'
var/datum/radio_frequency/radio_connection
var/datum/effect_system/spark_spread/sparks
/obj/machinery/power/emitter/New()
..()
/obj/machinery/power/emitter/Initialize(mapload)
. = ..()
component_parts = list()
component_parts += new /obj/item/circuitboard/emitter(null)
component_parts += new /obj/item/stock_parts/micro_laser(null)
component_parts += new /obj/item/stock_parts/manipulator(null)
RefreshParts()
if(state == 2 && anchored)
connect_to_network()
sparks = new
sparks.set_up(5, 1, src)
if(frequency)
set_frequency(frequency)
/obj/machinery/power/emitter/RefreshParts()
var/max_firedelay = 120
@@ -79,13 +85,6 @@
return
rotate()
/obj/machinery/power/emitter/Initialize()
..()
if(state == 2 && anchored)
connect_to_network()
if(frequency)
set_frequency(frequency)
/obj/machinery/power/emitter/multitool_menu(var/mob/user,var/obj/item/multitool/P)
return {"
<ul>
@@ -182,10 +181,9 @@
src.active = 0
update_icon()
return
if(((src.last_shot + src.fire_delay) <= world.time) && (src.active == 1))
var/actual_load = draw_power(active_power_usage)
if(actual_load >= active_power_usage) //does the laser have enough power to shoot?
if(active == TRUE)
if(!active_power_usage || surplus() >= active_power_usage)
add_load(active_power_usage)
if(!powered)
powered = 1
update_icon()
@@ -197,36 +195,57 @@
investigate_log("lost power and turned <font color='red'>off</font>","singulo")
return
src.last_shot = world.time
if(src.shot_number < 3)
src.fire_delay = 2
src.shot_number++
else
src.fire_delay = rand(minimum_fire_delay,maximum_fire_delay)
src.shot_number = 0
if(!check_delay())
return FALSE
fire_beam()
var/obj/item/projectile/beam/emitter/A = new /obj/item/projectile/beam/emitter(src.loc)
/obj/machinery/power/emitter/proc/check_delay()
if((last_shot + fire_delay) <= world.time)
return TRUE
return FALSE
A.dir = src.dir
playsound(get_turf(src), 'sound/weapons/emitter.ogg', 25, 1)
if(prob(35))
sparks.start()
switch(dir)
if(NORTH)
A.yo = 20
A.xo = 0
if(EAST)
A.yo = 0
A.xo = 20
if(WEST)
A.yo = 0
A.xo = -20
else // Any other
A.yo = -20
A.xo = 0
A.fire() //TODO: Carn: check this out
/obj/machinery/power/emitter/proc/fire_beam()
var/obj/item/projectile/P = new projectile_type(get_turf(src))
playsound(get_turf(src), projectile_sound, 50, TRUE)
if(prob(35))
sparks.start()
switch(dir)
if(NORTH)
P.yo = 20
P.xo = 0
if(NORTHEAST)
P.yo = 20
P.xo = 20
if(EAST)
P.yo = 0
P.xo = 20
if(SOUTHEAST)
P.yo = -20
P.xo = 20
if(WEST)
P.yo = 0
P.xo = -20
if(SOUTHWEST)
P.yo = -20
P.xo = -20
if(NORTHWEST)
P.yo = 20
P.xo = -20
else // Any other
P.yo = -20
P.xo = 0
last_shot = world.time
if(shot_number < 3)
fire_delay = 20
shot_number ++
else
fire_delay = rand(minimum_fire_delay, maximum_fire_delay)
shot_number = 0
P.setDir(dir)
P.starting = loc
P.fire()
return P
/obj/machinery/power/emitter/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/multitool))
+61 -57
View File
@@ -11,20 +11,21 @@
name = "power storage unit"
desc = "A high-capacity superconducting magnetic energy storage (SMES) unit."
icon_state = "smes"
density = 1
anchored = 1
density = TRUE
anchored = TRUE
use_power = NO_POWER_USE
var/capacity = 5e6 // maximum charge
var/charge = 0 // actual charge
var/input_attempt = 0 // 1 = attempting to charge, 0 = not attempting to charge
var/inputting = 0 // 1 = actually inputting, 0 = not inputting
var/input_attempt = TRUE // 1 = attempting to charge, 0 = not attempting to charge
var/inputting = TRUE // 1 = actually inputting, 0 = not inputting
var/input_level = 50000 // amount of power the SMES attempts to charge by
var/input_level_max = 200000 // cap on input_level
var/input_available = 0 // amount of charge available from input last tick
var/output_attempt = 1 // 1 = attempting to output, 0 = not attempting to output
var/outputting = 1 // 1 = actually outputting, 0 = not outputting
var/output_attempt = TRUE // 1 = attempting to output, 0 = not attempting to output
var/outputting = TRUE // 1 = actually outputting, 0 = not outputting
var/output_level = 50000 // amount of power the SMES attempts to output
var/output_level_max = 200000 // cap on output_level
var/output_used = 0 // amount of power actually outputted. may be less than output_level if the powernet returns excess power
@@ -39,8 +40,8 @@
var/building_terminal = 0 //Suggestions about how to avoid clickspam building several terminals accepted!
var/obj/machinery/power/terminal/terminal = null
/obj/machinery/power/smes/New()
..()
/obj/machinery/power/smes/Initialize(mapload)
. = ..()
component_parts = list()
component_parts += new /obj/item/circuitboard/smes(null)
component_parts += new /obj/item/stock_parts/cell/high(null)
@@ -52,28 +53,22 @@
component_parts += new /obj/item/stack/cable_coil(null, 5)
RefreshParts()
spawn(5)
if(!powernet)
connect_to_network()
dir_loop:
for(var/d in cardinal)
var/turf/T = get_step(src, d)
for(var/obj/machinery/power/terminal/term in T)
if(term && term.dir == turn(d, 180))
terminal = term
break dir_loop
dir_loop:
for(var/d in cardinal)
var/turf/T = get_step(src, d)
for(var/obj/machinery/power/terminal/term in T)
if(term && term.dir == turn(d, 180))
terminal = term
break dir_loop
if(!terminal)
stat |= BROKEN
return
terminal.master = src
if(!terminal.powernet)
terminal.connect_to_network()
update_icon()
return
if(!terminal)
stat |= BROKEN
return
terminal.master = src
update_icon()
/obj/machinery/power/smes/upgraded/New()
..()
/obj/machinery/power/smes/upgraded/Initialize(mapload)
. = ..()
component_parts = list()
component_parts += new /obj/item/circuitboard/smes(null)
component_parts += new /obj/item/stock_parts/cell/hyper(null)
@@ -222,8 +217,8 @@
return round(5.5*charge/(capacity ? capacity : 5e6))
/obj/machinery/power/smes/process()
if(stat & BROKEN) return
if(stat & BROKEN)
return
//store machine state to see if we need to update the icon overlays
var/last_disp = chargedisplay()
@@ -231,33 +226,46 @@
var/last_onln = outputting
//inputting
if(input_attempt)
var/target_load = min((capacity-charge)/SMESRATE, input_level) // charge at set rate, limited to spare capacity
var/actual_load = draw_power(target_load) // add the load to the terminal side network
charge += actual_load * SMESRATE // increase the charge
if(terminal && input_attempt)
input_available = terminal.surplus()
if(actual_load >= target_load) // Did we charge at full rate?
inputting = 2
else if(actual_load) // If not, did we charge at least partially?
inputting = 1
else // Or not at all?
inputting = 0
if(inputting)
if(input_available > 0) // if there's power available, try to charge
var/load = min(min((capacity-charge)/SMESRATE, input_level), input_available) // charge at set rate, limited to spare capacity
charge += load * SMESRATE // increase the charge
terminal.add_load(load) // add the load to the terminal side network
else // if not enough capcity
inputting = FALSE // stop inputting
else
if(input_attempt && input_available > 0)
inputting = TRUE
else
inputting = FALSE
//outputting
if(outputting)
output_used = min( charge/SMESRATE, output_level) //limit output to that stored
if(output_attempt)
if(outputting)
output_used = min( charge/SMESRATE, output_level) //limit output to that stored
charge -= output_used*SMESRATE // reduce the storage (may be recovered in /restore() if excessive)
if (add_avail(output_used)) // add output to powernet if it exists (smes side)
charge -= output_used*SMESRATE // reduce the storage (may be recovered in /restore() if excessive)
else
outputting = FALSE
add_avail(output_used) // add output to powernet (smes side)
if(output_used < 0.0001) // either from no charge or set to 0
outputting = 0
investigate_log("lost power and turned <font color='red'>off</font>","singulo")
else if(output_attempt && charge > output_level && output_level > 0)
outputting = 1
if(output_used < 0.0001) // either from no charge or set to 0
outputting = FALSE
investigate_log("lost power and turned <font color='red'>off</font>", "singulo")
else if(output_attempt && charge > output_level && output_level > 0)
outputting = TRUE
else
output_used = 0
else
output_used = 0
outputting = FALSE
// only update icon if state changed
if(last_disp != chargedisplay() || last_chrg != inputting || last_onln != outputting)
@@ -333,11 +341,6 @@
return 0
return 1
/obj/machinery/power/smes/draw_power(var/amount)
if(terminal && terminal.powernet)
return terminal.powernet.draw_power(amount)
return 0
/obj/machinery/power/smes/attack_ai(mob/user)
add_hiddenprint(user)
ui_interact(user)
@@ -483,7 +486,8 @@
output_level = 250000
/obj/machinery/power/smes/magical/process()
charge = 5000000
capacity = INFINITY
charge = INFINITY
..()
#undef SMESRATE
+4 -3
View File
@@ -14,15 +14,16 @@
layer = 2.6 // a bit above wires
/obj/machinery/power/terminal/New()
..()
/obj/machinery/power/terminal/Initialize(mapload)
. = ..()
var/turf/T = src.loc
if(level==1) hide(T.intact)
return
/obj/machinery/power/terminal/Destroy()
if(master)
master.disconnect_terminal()
master = null
return ..()
+1 -1
View File
@@ -77,7 +77,7 @@
var/coeff = (20 - ((input_power_multiplier - 1) * 3))
coeff = max(coeff, 10)
var/power = (powernet.avail/2)
draw_power(power)
add_load(power)
playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, 1, extrarange = 5)
tesla_zap(src, 10, power/(coeff/2))