mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-08-27 22:18:27 +01:00
Merge pull request #7010 from atlantiscze/2020_04_17_LoadBalancing
Ports over power-related enhancements and tweaks i coded for Bay a while back
This commit is contained in:
@@ -2,6 +2,7 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called
|
||||
|
||||
#define CELLRATE 0.002 // Multiplier for watts per tick <> cell storage (e.g., 0.02 means if there is a load of 1000 watts, 20 units will be taken from a cell per second)
|
||||
// It's a conversion constant. power_used*CELLRATE = charge_provided, or charge_used/CELLRATE = power_provided
|
||||
#define SMESRATE 0.03333 // Same for SMESes. A different number for some reason.
|
||||
|
||||
#define KILOWATTS *1000
|
||||
#define MEGAWATTS *1000000
|
||||
|
||||
@@ -11,7 +11,7 @@ var/const/SMES_WIRE_FAILSAFES = 16 // Cut to disable failsafes, mend to reenable
|
||||
|
||||
/datum/wires/smes/CanUse(var/mob/living/L)
|
||||
var/obj/machinery/power/smes/buildable/S = holder
|
||||
if(S.open_hatch)
|
||||
if(S.panel_open)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
@@ -230,13 +230,6 @@
|
||||
desc = "Heavy-duty switching circuits for power control."
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50)
|
||||
|
||||
/obj/item/weapon/module/power_control/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
|
||||
if (istype(W, /obj/item/device/multitool))
|
||||
var/obj/item/weapon/circuitboard/ghettosmes/newcircuit = new/obj/item/weapon/circuitboard/ghettosmes(user.loc)
|
||||
qdel(src)
|
||||
user.put_in_hands(newcircuit)
|
||||
|
||||
|
||||
/obj/item/weapon/module/id_auth
|
||||
name = "\improper ID authentication module"
|
||||
icon_state = "id_mod"
|
||||
|
||||
@@ -18,14 +18,7 @@
|
||||
build_path = /obj/machinery/power/smes/batteryrack
|
||||
board_type = new /datum/frame/frame_types/machine
|
||||
origin_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 2)
|
||||
req_components = list(/obj/item/weapon/cell = 3)
|
||||
|
||||
/obj/item/weapon/circuitboard/ghettosmes
|
||||
name = T_BOARD("makeshift PSU")
|
||||
desc = "An APC circuit repurposed into some power storage device controller"
|
||||
build_path = /obj/machinery/power/smes/batteryrack/makeshift
|
||||
board_type = new /datum/frame/frame_types/machine
|
||||
req_components = list(/obj/item/weapon/cell = 3)
|
||||
req_components = list(/obj/item/weapon/stock_parts/capacitor/ = 3, /obj/item/weapon/stock_parts/matter_bin/ = 1)
|
||||
|
||||
/obj/item/weapon/circuitboard/grid_checker
|
||||
name = T_BOARD("power grid checker")
|
||||
|
||||
@@ -351,8 +351,8 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh
|
||||
/obj/item/weapon/circuitboard/atmos_alert,
|
||||
/obj/item/weapon/circuitboard/airalarm,
|
||||
/obj/item/weapon/circuitboard/fax,
|
||||
/obj/item/weapon/circuitboard/ghettosmes,
|
||||
/obj/item/weapon/circuitboard/jukebox,
|
||||
/obj/item/weapon/circuitboard/batteryrack,
|
||||
/obj/item/weapon/circuitboard/message_monitor,
|
||||
/obj/item/weapon/circuitboard/rcon_console,
|
||||
/obj/item/weapon/smes_coil,
|
||||
|
||||
@@ -1255,7 +1255,7 @@ obj/machinery/power/apc/proc/autoset(var/cur_state, var/on)
|
||||
cell.ex_act(3)
|
||||
return
|
||||
|
||||
/obj/machinery/power/apc/disconnect_terminal()
|
||||
/obj/machinery/power/apc/disconnect_terminal(var/obj/machinery/power/terminal/term)
|
||||
if(terminal)
|
||||
terminal.master = null
|
||||
terminal = null
|
||||
|
||||
+279
-200
@@ -1,234 +1,313 @@
|
||||
//The one that works safely.
|
||||
// Cell rack PSU, similar to SMES, but uses power cells to store power.
|
||||
// Lacks detailed control of input/output values, and has generally much worse capacity.
|
||||
#define PSU_OFFLINE 0
|
||||
#define PSU_OUTPUT 1
|
||||
#define PSU_INPUT 2
|
||||
#define PSU_AUTO 3
|
||||
|
||||
#define PSU_MAXCELLS 9 // Capped to 9 cells due to sprite limitation
|
||||
|
||||
/obj/machinery/power/smes/batteryrack
|
||||
name = "power cell rack PSU"
|
||||
desc = "A rack of power cells working as a PSU."
|
||||
charge = 0 //you dont really want to make a potato PSU which already is overloaded
|
||||
output_attempt = 0
|
||||
input_level = 0
|
||||
output_level = 0
|
||||
input_level_max = 0
|
||||
output_level_max = 0
|
||||
icon_state = "gsmes"
|
||||
circuit = /obj/item/weapon/circuitboard/batteryrack
|
||||
var/cells_amount = 0
|
||||
var/capacitors_amount = 0
|
||||
var/global/list/br_cache = null
|
||||
icon = 'icons/obj/cellrack.dmi'
|
||||
icon_state = "rack"
|
||||
capacity = 0
|
||||
charge = 0
|
||||
output_attempt = FALSE
|
||||
input_attempt = FALSE
|
||||
|
||||
var/max_transfer_rate = 0 // Maximal input/output rate. Determined by used capacitors when building the device.
|
||||
var/mode = PSU_OFFLINE // Current inputting/outputting mode
|
||||
var/list/internal_cells = list() // Cells stored in this PSU
|
||||
var/max_cells = 3 // Maximal amount of stored cells at once. Capped at 9.
|
||||
var/previous_charge = 0 // Charge previous tick.
|
||||
var/equalise = 0 // If true try to equalise charge between cells
|
||||
var/icon_update = 0 // Timer in ticks for icon update.
|
||||
var/ui_tick = 0
|
||||
|
||||
|
||||
/obj/machinery/power/smes/batteryrack/New()
|
||||
..()
|
||||
add_parts()
|
||||
RefreshParts()
|
||||
return
|
||||
|
||||
//Maybe this should be moved up to obj/machinery
|
||||
/obj/machinery/power/smes/batteryrack/proc/add_parts()
|
||||
component_parts = list()
|
||||
component_parts += new /obj/item/weapon/cell/high
|
||||
component_parts += new /obj/item/weapon/cell/high
|
||||
component_parts += new /obj/item/weapon/cell/high
|
||||
return
|
||||
component_parts += new /obj/item/weapon/circuitboard/batteryrack
|
||||
component_parts += new /obj/item/weapon/stock_parts/capacitor/ // Capacitors: Maximal I/O
|
||||
component_parts += new /obj/item/weapon/stock_parts/capacitor/
|
||||
component_parts += new /obj/item/weapon/stock_parts/capacitor/
|
||||
component_parts += new /obj/item/weapon/stock_parts/matter_bin/ // Matter Bin: Max. amount of cells.
|
||||
|
||||
|
||||
/obj/machinery/power/smes/batteryrack/RefreshParts()
|
||||
capacitors_amount = 0
|
||||
cells_amount = 0
|
||||
var/max_level = 0 //for both input and output
|
||||
var/capacitor_efficiency = 0
|
||||
var/maxcells = 0
|
||||
for(var/obj/item/weapon/stock_parts/capacitor/CP in component_parts)
|
||||
max_level += CP.rating
|
||||
capacitors_amount++
|
||||
input_level_max = 50000 + max_level * 20000
|
||||
output_level_max = 50000 + max_level * 20000
|
||||
capacitor_efficiency += CP.rating
|
||||
|
||||
var/C = 0
|
||||
for(var/obj/item/weapon/cell/PC in component_parts)
|
||||
C += PC.maxcharge
|
||||
cells_amount++
|
||||
capacity = C * 40 //Basic cells are such crap. Hyper cells needed to get on normal SMES levels.
|
||||
for(var/obj/item/weapon/stock_parts/matter_bin/MB in component_parts)
|
||||
maxcells += MB.rating * 3
|
||||
|
||||
max_transfer_rate = 10000 * capacitor_efficiency // 30kw - 90kw depending on used capacitors.
|
||||
max_cells = min(PSU_MAXCELLS, maxcells)
|
||||
input_level = max_transfer_rate
|
||||
output_level = max_transfer_rate
|
||||
|
||||
/obj/machinery/power/smes/batteryrack/Destroy()
|
||||
for(var/obj/item/weapon/cell/C in internal_cells)
|
||||
qdel(C)
|
||||
internal_cells = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/power/smes/batteryrack/update_icon()
|
||||
overlays.Cut()
|
||||
if(stat & BROKEN) return
|
||||
icon_update = 0
|
||||
|
||||
if(!br_cache)
|
||||
br_cache = list()
|
||||
br_cache.len = 7
|
||||
br_cache[1] = image('icons/obj/power.dmi', "gsmes_outputting")
|
||||
br_cache[2] = image('icons/obj/power.dmi', "gsmes_charging")
|
||||
br_cache[3] = image('icons/obj/power.dmi', "gsmes_overcharge")
|
||||
br_cache[4] = image('icons/obj/power.dmi', "gsmes_og1")
|
||||
br_cache[5] = image('icons/obj/power.dmi', "gsmes_og2")
|
||||
br_cache[6] = image('icons/obj/power.dmi', "gsmes_og3")
|
||||
br_cache[7] = image('icons/obj/power.dmi', "gsmes_og4")
|
||||
|
||||
if (output_attempt)
|
||||
overlays += br_cache[1]
|
||||
if(inputting)
|
||||
overlays += br_cache[2]
|
||||
|
||||
var/clevel = chargedisplay()
|
||||
if(clevel>0)
|
||||
overlays += br_cache[3+clevel]
|
||||
return
|
||||
var/cellcount = 0
|
||||
var/charge_level = between(0, round(Percentage() / 12), 7)
|
||||
|
||||
|
||||
/obj/machinery/power/smes/batteryrack/chargedisplay()
|
||||
return round(4 * charge/(capacity ? capacity : 5e6))
|
||||
overlays += "charge[charge_level]"
|
||||
|
||||
for(var/obj/item/weapon/cell/C in internal_cells)
|
||||
cellcount++
|
||||
overlays += "cell[cellcount]"
|
||||
if(C.fully_charged())
|
||||
overlays += "cell[cellcount]f"
|
||||
else if(!C.charge)
|
||||
overlays += "cell[cellcount]e"
|
||||
|
||||
// Recalculate maxcharge and similar variables.
|
||||
/obj/machinery/power/smes/batteryrack/proc/update_maxcharge()
|
||||
var/newmaxcharge = 0
|
||||
for(var/obj/item/weapon/cell/C in internal_cells)
|
||||
newmaxcharge += C.maxcharge
|
||||
|
||||
newmaxcharge /= CELLRATE // Convert to Joules
|
||||
newmaxcharge *= SMESRATE // And to SMES charge units (which are for some reason different than CELLRATE)
|
||||
capacity = newmaxcharge
|
||||
charge = between(0, charge, newmaxcharge)
|
||||
|
||||
|
||||
/obj/machinery/power/smes/batteryrack/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) //these can only be moved by being reconstructed, solves having to remake the powernet.
|
||||
..() //SMES attackby for now handles screwdriver, cable coils and wirecutters, no need to repeat that here
|
||||
if(open_hatch)
|
||||
if(W.is_crowbar())
|
||||
if (charge < (capacity / 100))
|
||||
if (!output_attempt && !input_attempt)
|
||||
playsound(src, W.usesound, 50, 1)
|
||||
var/obj/structure/frame/M = new /obj/structure/frame(src.loc)
|
||||
M.frame_type = "machine"
|
||||
M.state = 2
|
||||
M.icon_state = "machine_1"
|
||||
for(var/obj/I in component_parts)
|
||||
I.loc = src.loc
|
||||
qdel(src)
|
||||
return 1
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Turn off the [src] before dismantling it.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Better let [src] discharge before dismantling it.</span>")
|
||||
else if ((istype(W, /obj/item/weapon/stock_parts/capacitor) && (capacitors_amount < 5)) || (istype(W, /obj/item/weapon/cell) && (cells_amount < 5)))
|
||||
if (charge < (capacity / 100))
|
||||
if (!output_attempt && !input_attempt)
|
||||
user.drop_item()
|
||||
component_parts += W
|
||||
W.loc = src
|
||||
RefreshParts()
|
||||
to_chat(user, "<span class='notice'>You upgrade the [src] with [W.name].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Turn off the [src] before dismantling it.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Better let [src] discharge before putting your hand inside it.</span>")
|
||||
else
|
||||
user.set_machine(src)
|
||||
interact(user)
|
||||
return 1
|
||||
return
|
||||
// Sets input/output depending on our "mode" var.
|
||||
/obj/machinery/power/smes/batteryrack/proc/update_io(var/newmode)
|
||||
mode = newmode
|
||||
switch(mode)
|
||||
if(PSU_OFFLINE)
|
||||
input_attempt = 0
|
||||
output_attempt = 0
|
||||
if(PSU_INPUT)
|
||||
input_attempt = 1
|
||||
output_attempt = 0
|
||||
if(PSU_OUTPUT)
|
||||
input_attempt = 0
|
||||
output_attempt = 1
|
||||
if(PSU_AUTO)
|
||||
input_attempt = 1
|
||||
output_attempt = 1
|
||||
|
||||
// Store charge in the power cells, instead of using the charge var. Amount is in joules.
|
||||
/obj/machinery/power/smes/batteryrack/add_charge(var/amount)
|
||||
amount *= CELLRATE // Convert to CELLRATE first.
|
||||
if(equalise)
|
||||
// Now try to get least charged cell and use the power from it.
|
||||
var/obj/item/weapon/cell/CL = get_least_charged_cell()
|
||||
amount -= CL.give(amount)
|
||||
if(!amount)
|
||||
return
|
||||
// We're still here, so it means the least charged cell was full OR we don't care about equalising the charge. Give power to other cells instead.
|
||||
for(var/obj/item/weapon/cell/C in internal_cells)
|
||||
amount -= C.give(amount)
|
||||
// No more power to input so return.
|
||||
if(!amount)
|
||||
return
|
||||
|
||||
|
||||
//The shitty one that will blow up.
|
||||
/obj/machinery/power/smes/batteryrack/makeshift
|
||||
name = "makeshift PSU"
|
||||
desc = "A rack of batteries connected by a mess of wires posing as a PSU."
|
||||
circuit = /obj/item/weapon/circuitboard/ghettosmes
|
||||
var/overcharge_percent = 0
|
||||
/obj/machinery/power/smes/batteryrack/remove_charge(var/amount)
|
||||
amount *= CELLRATE // Convert to CELLRATE first.
|
||||
if(equalise)
|
||||
// Now try to get most charged cell and use the power from it.
|
||||
var/obj/item/weapon/cell/CL = get_most_charged_cell()
|
||||
amount -= CL.use(amount)
|
||||
if(!amount)
|
||||
return
|
||||
// We're still here, so it means the most charged cell didn't have enough power OR we don't care about equalising the charge. Use power from other cells instead.
|
||||
for(var/obj/item/weapon/cell/C in internal_cells)
|
||||
amount -= C.use(amount)
|
||||
// No more power to output so return.
|
||||
if(!amount)
|
||||
return
|
||||
|
||||
// Helper procs to get most/least charged cells.
|
||||
/obj/machinery/power/smes/batteryrack/proc/get_most_charged_cell()
|
||||
var/obj/item/weapon/cell/CL = null
|
||||
for(var/obj/item/weapon/cell/C in internal_cells)
|
||||
if(CL == null)
|
||||
CL = C
|
||||
else if(CL.percent() < C.percent())
|
||||
CL = C
|
||||
return CL
|
||||
/obj/machinery/power/smes/batteryrack/proc/get_least_charged_cell()
|
||||
var/obj/item/weapon/cell/CL = null
|
||||
for(var/obj/item/weapon/cell/C in internal_cells)
|
||||
if(CL == null)
|
||||
CL = C
|
||||
else if(CL.percent() > C.percent())
|
||||
CL = C
|
||||
return CL
|
||||
|
||||
/obj/machinery/power/smes/batteryrack/proc/insert_cell(var/obj/item/weapon/cell/C, var/mob/user)
|
||||
if(!istype(C))
|
||||
return 0
|
||||
|
||||
if(internal_cells.len >= max_cells)
|
||||
return 0
|
||||
|
||||
internal_cells.Add(C)
|
||||
if(user)
|
||||
user.drop_from_inventory(C)
|
||||
C.forceMove(src)
|
||||
RefreshParts()
|
||||
update_maxcharge()
|
||||
update_icon()
|
||||
return 1
|
||||
|
||||
|
||||
/obj/machinery/power/smes/batteryrack/makeshift/add_parts()
|
||||
component_parts = list()
|
||||
component_parts += new /obj/item/weapon/cell/high
|
||||
component_parts += new /obj/item/weapon/cell/high
|
||||
component_parts += new /obj/item/weapon/cell/high
|
||||
return
|
||||
/obj/machinery/power/smes/batteryrack/process()
|
||||
charge = 0
|
||||
for(var/obj/item/weapon/cell/C in internal_cells)
|
||||
charge += C.charge
|
||||
charge /= CELLRATE // Convert to Joules
|
||||
charge *= SMESRATE // And to SMES charge units (which are for some reason different than CELLRATE)
|
||||
|
||||
|
||||
/obj/machinery/power/smes/batteryrack/makeshift/update_icon()
|
||||
overlays.Cut()
|
||||
if(stat & BROKEN) return
|
||||
..()
|
||||
ui_tick = !ui_tick
|
||||
icon_update++
|
||||
|
||||
if (output_attempt)
|
||||
overlays += br_cache[1]
|
||||
if(inputting)
|
||||
overlays += br_cache[2]
|
||||
if (overcharge_percent > 100)
|
||||
overlays += br_cache[3]
|
||||
else
|
||||
var/clevel = chargedisplay()
|
||||
if(clevel>0)
|
||||
overlays += br_cache[3+clevel]
|
||||
return
|
||||
|
||||
//This mess of if-elses and magic numbers handles what happens if the engies don't pay attention and let it eat too much charge
|
||||
//What happens depends on how much capacity has the ghetto smes and how much it is overcharged.
|
||||
//Under 1.2M: 5% of ion_act() per process() tick from 125% and higher overcharges. 1.2M is achieved with 3 high cells.
|
||||
//[1.2M-2.4M]: 6% ion_act from 120%. 1% of EMP from 140%.
|
||||
//(2.4M-3.6M] :7% ion_act from 115%. 1% of EMP from 130%. 1% of non-hull-breaching explosion at 150%.
|
||||
//(3.6M-INFI): 8% ion_act from 115%. 2% of EMP from 125%. 1% of Hull-breaching explosion from 140%.
|
||||
/obj/machinery/power/smes/batteryrack/makeshift/proc/overcharge_consequences()
|
||||
switch (capacity)
|
||||
if (0 to (1.2e6-1))
|
||||
if (overcharge_percent >= 125)
|
||||
if (prob(5))
|
||||
ion_act()
|
||||
if (1.2e6 to 2.4e6)
|
||||
if (overcharge_percent >= 120)
|
||||
if (prob(6))
|
||||
ion_act()
|
||||
else
|
||||
return
|
||||
if (overcharge_percent >= 140)
|
||||
if (prob(1))
|
||||
empulse(src.loc, 2, 3, 6, 8, 1)
|
||||
if ((2.4e6+1) to 3.6e6)
|
||||
if (overcharge_percent >= 115)
|
||||
if (prob(7))
|
||||
ion_act()
|
||||
else
|
||||
return
|
||||
if (overcharge_percent >= 130)
|
||||
if (prob(1))
|
||||
empulse(src.loc, 2, 3, 6, 8, 1)
|
||||
if (overcharge_percent >= 150)
|
||||
if (prob(1))
|
||||
explosion(src.loc, 0, 1, 3, 5)
|
||||
if ((3.6e6+1) to INFINITY)
|
||||
if (overcharge_percent >= 115)
|
||||
if (prob(8))
|
||||
ion_act()
|
||||
else
|
||||
return
|
||||
if (overcharge_percent >= 125)
|
||||
if (prob(2))
|
||||
empulse(src.loc, 2, 4, 7, 10, 1)
|
||||
if (overcharge_percent >= 140)
|
||||
if (prob(1))
|
||||
explosion(src.loc, 1, 3, 5, 8)
|
||||
else //how the hell was this proc called for negative charge
|
||||
charge = 0
|
||||
|
||||
|
||||
#define SMESRATE 0.05 // rate of internal charge to external power
|
||||
/obj/machinery/power/smes/batteryrack/makeshift/process()
|
||||
if(stat & BROKEN) return
|
||||
|
||||
//store machine state to see if we need to update the icon overlays
|
||||
var/last_disp = chargedisplay()
|
||||
var/last_chrg = inputting
|
||||
var/last_onln = output_attempt
|
||||
var/last_overcharge = overcharge_percent
|
||||
|
||||
if(terminal)
|
||||
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 (actual_load >= target_load) // did the powernet have enough power available for us?
|
||||
inputting = 1
|
||||
else
|
||||
inputting = 0
|
||||
|
||||
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)
|
||||
add_avail(output_used) // add output to powernet (smes side)
|
||||
if(charge < 0.0001)
|
||||
outputting(0) // stop output if charge falls to zero
|
||||
|
||||
overcharge_percent = round((charge / capacity) * 100)
|
||||
if (overcharge_percent > 115) //115% is the minimum overcharge for anything to happen
|
||||
overcharge_consequences()
|
||||
|
||||
// only update icon if state changed
|
||||
if(last_disp != chargedisplay() || last_chrg != inputting || last_onln != output_attempt || ((overcharge_percent > 100) ^ (last_overcharge > 100)))
|
||||
// Don't update icon too much, prevents unnecessary processing.
|
||||
if(icon_update >= 10)
|
||||
update_icon()
|
||||
// Try to balance charge between stored cells. Capped at max_transfer_rate per tick.
|
||||
// Take power from most charged cell, and give it to least charged cell.
|
||||
if(equalise)
|
||||
var/obj/item/weapon/cell/least = get_least_charged_cell()
|
||||
var/obj/item/weapon/cell/most = get_most_charged_cell()
|
||||
// Don't bother equalising charge between two same cells. Also ensure we don't get NULLs or wrong types. Don't bother equalising when difference between charges is tiny.
|
||||
if(least == most || !istype(least) || !istype(most) || least.percent() == most.percent())
|
||||
return
|
||||
var/percentdiff = (most.percent() - least.percent()) / 2 // Transfer only 50% of power. The reason is that it could lead to situations where least and most charged cells would "swap places" (45->50% and 50%->45%)
|
||||
var/celldiff
|
||||
// Take amount of power to transfer from the cell with smaller maxcharge
|
||||
if(most.maxcharge > least.maxcharge)
|
||||
celldiff = (least.maxcharge / 100) * percentdiff
|
||||
else
|
||||
celldiff = (most.maxcharge / 100) * percentdiff
|
||||
celldiff = between(0, celldiff, max_transfer_rate * CELLRATE)
|
||||
// Ensure we don't transfer more energy than the most charged cell has, and that the least charged cell can input.
|
||||
celldiff = min(min(celldiff, most.charge), least.maxcharge - least.charge)
|
||||
least.give(most.use(celldiff))
|
||||
|
||||
/obj/machinery/power/smes/batteryrack/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
var/data[0]
|
||||
|
||||
data["mode"] = mode
|
||||
data["transfer_max"] = max_transfer_rate
|
||||
data["output_load"] = round(output_used)
|
||||
data["input_load"] = round(input_available)
|
||||
data["equalise"] = equalise
|
||||
data["blink_tick"] = ui_tick
|
||||
data["cells_max"] = max_cells
|
||||
data["cells_cur"] = internal_cells.len
|
||||
var/list/cells = list()
|
||||
var/cell_index = 0
|
||||
for(var/obj/item/weapon/cell/C in internal_cells)
|
||||
var/list/cell[0]
|
||||
cell["slot"] = cell_index + 1
|
||||
cell["used"] = 1
|
||||
cell["percentage"] = round(C.percent(), 0.01)
|
||||
cell["id"] = C.c_uid
|
||||
cell_index++
|
||||
cells += list(cell)
|
||||
while(cell_index < PSU_MAXCELLS)
|
||||
var/list/cell[0]
|
||||
cell["slot"] = cell_index + 1
|
||||
cell["used"] = 0
|
||||
cell_index++
|
||||
cells += list(cell)
|
||||
data["cells_list"] = cells
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "psu.tmpl", "Cell Rack PSU", 500, 430)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/power/smes/batteryrack/dismantle()
|
||||
for(var/obj/item/weapon/cell/C in internal_cells)
|
||||
C.forceMove(get_turf(src))
|
||||
internal_cells -= C
|
||||
return ..()
|
||||
|
||||
/obj/machinery/power/smes/batteryrack/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
|
||||
if(!..())
|
||||
return 0
|
||||
if(default_deconstruction_crowbar(user, W))
|
||||
return
|
||||
if(default_part_replacement(user, W))
|
||||
return
|
||||
if(istype(W, /obj/item/weapon/cell)) // ID Card, try to insert it.
|
||||
if(insert_cell(W, user))
|
||||
to_chat(user, "<span class='filter_notice'>You insert \the [W] into \the [src].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='filter_notice'>\The [src] has no empty slot for \the [W]</span>")
|
||||
|
||||
/obj/machinery/power/smes/batteryrack/attack_hand(var/mob/user)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/power/smes/batteryrack/inputting()
|
||||
return
|
||||
|
||||
#undef SMESRATE
|
||||
/obj/machinery/power/smes/batteryrack/outputting()
|
||||
return
|
||||
|
||||
/obj/machinery/power/smes/batteryrack/Topic(href, href_list)
|
||||
// ..() would respond to those topic calls, but we don't want to use them at all.
|
||||
// Calls to these shouldn't occur anyway, due to usage of different nanoUI, but
|
||||
// it's here in case someone decides to try hrefhacking/modified templates.
|
||||
if(href_list["input"] || href_list["output"])
|
||||
return 1
|
||||
|
||||
if(..())
|
||||
return 1
|
||||
if( href_list["disable"] )
|
||||
update_io(0)
|
||||
return 1
|
||||
else if( href_list["enable"] )
|
||||
update_io(between(1, text2num(href_list["enable"]), 3))
|
||||
return 1
|
||||
else if( href_list["equaliseon"] )
|
||||
equalise = 1
|
||||
return 1
|
||||
else if( href_list["equaliseoff"] )
|
||||
equalise = 0
|
||||
return 1
|
||||
else if( href_list["ejectcell"] )
|
||||
var/obj/item/weapon/cell/C
|
||||
for(var/obj/item/weapon/cell/CL in internal_cells)
|
||||
if(CL.c_uid == text2num(href_list["ejectcell"]))
|
||||
C = CL
|
||||
break
|
||||
|
||||
if(!istype(C))
|
||||
return 1
|
||||
|
||||
C.forceMove(get_turf(src))
|
||||
internal_cells -= C
|
||||
update_icon()
|
||||
RefreshParts()
|
||||
update_maxcharge()
|
||||
return 1
|
||||
@@ -116,7 +116,7 @@ var/list/possible_cable_coil_colours = list(
|
||||
user.examinate(src)
|
||||
// following code taken from attackby (multitool)
|
||||
if(powernet && (powernet.avail > 0))
|
||||
to_chat(user, "<span class='warning'>[powernet.avail]W in power network.</span>")
|
||||
to_chat(user, "<span class='warning'>[DisplayPower(powernet.avail)] in power network.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>The cable is not powered.</span>")
|
||||
return
|
||||
@@ -230,7 +230,7 @@ var/list/possible_cable_coil_colours = list(
|
||||
else if(istype(W, /obj/item/device/multitool))
|
||||
|
||||
if(powernet && (powernet.avail > 0)) // is it powered?
|
||||
to_chat(user, "<span class='warning'>[powernet.avail]W in power network.</span>")
|
||||
to_chat(user, "<span class='warning'>[DisplayPower(powernet.avail)] in power network.</span>")
|
||||
|
||||
else
|
||||
to_chat(user, "<span class='warning'>The cable is not powered.</span>")
|
||||
@@ -617,6 +617,13 @@ obj/structure/cable/proc/cableColor(var/colorC)
|
||||
else if(Adjacent(user))
|
||||
. += "There are [get_amount()] lengths of cable in the coil."
|
||||
|
||||
/obj/item/stack/cable_coil/attackby(obj/item/W, mob/user)
|
||||
if(istype(W, /obj/item/device/multitool))
|
||||
var/selected_type = input("Pick new colour.", "Cable Colour", null, null) as null|anything in possible_cable_coil_colours
|
||||
set_cable_color(selected_type, usr)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/item/stack/cable_coil/verb/make_restraint()
|
||||
set name = "Make Cable Restraints"
|
||||
set category = "Object"
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
w_class = ITEMSIZE_NORMAL
|
||||
var/static/cell_uid = 1 // Unique ID of this power cell. Used to reduce bunch of uglier code in nanoUI.
|
||||
var/c_uid
|
||||
var/charge = 0 // note %age conveted to actual charge in New
|
||||
var/maxcharge = 1000
|
||||
var/rigged = 0 // true if rigged to explode
|
||||
@@ -31,6 +33,7 @@
|
||||
|
||||
/obj/item/weapon/cell/New()
|
||||
..()
|
||||
c_uid = cell_uid++
|
||||
charge = maxcharge
|
||||
update_icon()
|
||||
if(self_recharge)
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/obj/machinery/power/debug_items/
|
||||
icon = 'icons/obj/power.dmi'
|
||||
icon_state = "tracker"
|
||||
anchored = 1
|
||||
density = 1
|
||||
var/show_extended_information = 1 // Set to 0 to disable extra information on examining (for example, when used on admin events)
|
||||
|
||||
/obj/machinery/power/debug_items/examine(mob/user)
|
||||
. = ..()
|
||||
if(show_extended_information)
|
||||
show_info(user)
|
||||
|
||||
/obj/machinery/power/debug_items/proc/show_info(var/mob/user)
|
||||
if(!powernet)
|
||||
to_chat(user, "<span class='filter_notice'>This device is not connected to a powernet</span>")
|
||||
return
|
||||
|
||||
to_chat(user, "<span class='filter_notice'>Connected to powernet: [powernet]</span>")
|
||||
to_chat(user, "<span class='filter_notice'>Available power: [num2text(powernet.avail, 20)] W</span>")
|
||||
to_chat(user, "<span class='filter_notice'>Load: [num2text(powernet.viewload, 20)] W</span>")
|
||||
to_chat(user, "<span class='filter_notice'>Has alert: [powernet.problem ? "YES" : "NO"]</span>")
|
||||
to_chat(user, "<span class='filter_notice'>Cables: [powernet.cables.len]</span>")
|
||||
to_chat(user, "<span class='filter_notice'>Nodes: [powernet.nodes.len]</span>")
|
||||
|
||||
|
||||
// An infinite power generator. Adds energy to connected cable.
|
||||
/obj/machinery/power/debug_items/infinite_generator
|
||||
name = "fractal energy reactor"
|
||||
desc = "An experimental power generator capable of generating massive amounts of energy from subspace vacuum."
|
||||
var/power_generation_rate = 1000000
|
||||
|
||||
/obj/machinery/power/debug_items/infinite_generator/process()
|
||||
add_avail(power_generation_rate)
|
||||
|
||||
/obj/machinery/power/debug_items/infinite_generator/show_info(var/mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='filter_notice'>Generator is providing [num2text(power_generation_rate, 20)] W</span>")
|
||||
|
||||
|
||||
// A cable powersink, without the explosion/network alarms normal powersink causes.
|
||||
/obj/machinery/power/debug_items/infinite_cable_powersink
|
||||
name = "null point core"
|
||||
desc = "An experimental device that disperses energy, used for grid stress-testing purposes."
|
||||
var/power_usage_rate = 0
|
||||
var/last_used = 0
|
||||
|
||||
/obj/machinery/power/debug_items/infinite_cable_powersink/process()
|
||||
last_used = draw_power(power_usage_rate)
|
||||
|
||||
/obj/machinery/power/debug_items/infinite_cable_powersink/show_info(var/mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='filter_notice'>Power sink is demanding [num2text(power_usage_rate, 20)] W</span>")
|
||||
to_chat(user, "<span class='filter_notice'>[num2text(last_used, 20)] W was actually used last tick</span>")
|
||||
|
||||
|
||||
/obj/machinery/power/debug_items/infinite_apc_powersink
|
||||
name = "APC dummy load"
|
||||
desc = "A dummy load that connects to an APC, used for load testing purposes."
|
||||
use_power = USE_POWER_ACTIVE
|
||||
active_power_usage = 0
|
||||
|
||||
/obj/machinery/power/debug_items/infinite_apc_powersink/show_info(var/mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='filter_notice'>Dummy load is using [num2text(active_power_usage, 20)] W</span>")
|
||||
to_chat(user, "<span class='filter_notice'>Powered: [powered() ? "YES" : "NO"]</span>")
|
||||
@@ -1,29 +0,0 @@
|
||||
// ###############################################################################
|
||||
// # ITEM: FRACTAL ENERGY REACTOR #
|
||||
// # FUNCTION: Generate infinite electricity. Used for map testing. #
|
||||
// ###############################################################################
|
||||
|
||||
/obj/machinery/power/fractal_reactor
|
||||
name = "Fractal Energy Reactor"
|
||||
desc = "This thing drains power from fractal-subspace." // (DEBUG ITEM: INFINITE POWERSOURCE FOR MAP TESTING. CONTACT DEVELOPERS IF FOUND.)"
|
||||
icon = 'icons/obj/power.dmi'
|
||||
icon_state = "tracker" //ICON stolen from solar tracker. There is no need to make new texture for debug item
|
||||
anchored = 1
|
||||
density = 1
|
||||
var/power_generation_rate = 1000000 //Defaults to 1MW of power.
|
||||
var/powernet_connection_failed = 0
|
||||
var/mapped_in = 0 //Do not announce creation when it's mapped in.
|
||||
|
||||
// This should be only used on Dev for testing purposes.
|
||||
/obj/machinery/power/fractal_reactor/New()
|
||||
..()
|
||||
if(!mapped_in)
|
||||
to_world("<b><font color='red'>WARNING:</font><font color='black'> Map testing power source activated at: X:[src.loc.x] Y:[src.loc.y] Z:[src.loc.z]</font></b>")
|
||||
|
||||
/obj/machinery/power/fractal_reactor/process()
|
||||
if(!powernet && !powernet_connection_failed)
|
||||
if(!connect_to_network())
|
||||
powernet_connection_failed = 1
|
||||
spawn(150) // Error! Check again in 15 seconds.
|
||||
powernet_connection_failed = 0
|
||||
add_avail(power_generation_rate)
|
||||
@@ -17,8 +17,6 @@
|
||||
|
||||
/obj/machinery/power/Destroy()
|
||||
disconnect_from_network()
|
||||
disconnect_terminal()
|
||||
|
||||
return ..()
|
||||
|
||||
///////////////////////////////
|
||||
@@ -37,6 +35,8 @@
|
||||
/obj/machinery/power/proc/add_avail(var/amount)
|
||||
if(powernet)
|
||||
powernet.newavail += amount
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/power/proc/draw_power(var/amount)
|
||||
if(powernet)
|
||||
@@ -61,7 +61,7 @@
|
||||
else
|
||||
return 0
|
||||
|
||||
/obj/machinery/power/proc/disconnect_terminal() // machines without a terminal will just return, no harm no fowl.
|
||||
/obj/machinery/power/proc/disconnect_terminal(var/obj/machinery/power/terminal/term) // machines without a terminal will just return, no harm no fowl.
|
||||
return
|
||||
|
||||
// connect the machine to a powernet if a node cable is present on the turf
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
var/viewload = 0 // the load as it appears on the power console (gradually updated)
|
||||
var/number = 0 // Unused //TODEL
|
||||
|
||||
var/smes_demand = 0 // Amount of power demanded by all SMESs from this network. Needed for load balancing.
|
||||
var/list/inputting = list() // List of SMESs that are demanding power from this network. Needed for load balancing.
|
||||
var/smes_avail = 0 // Amount of power (avail) from SMESes. Used by SMES load balancing
|
||||
var/smes_newavail = 0 // As above, just for newavail
|
||||
|
||||
var/perapc = 0 // per-apc avilability
|
||||
var/perapc_excess = 0
|
||||
var/netexcess = 0 // excess power on the powernet (typically avail-load)
|
||||
@@ -113,9 +118,20 @@
|
||||
|
||||
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
|
||||
|
||||
// At this point, all other machines have finished using power. Anything left over may be used up to charge SMESs.
|
||||
if(inputting.len && smes_demand)
|
||||
var/smes_input_percentage = between(0, (netexcess / smes_demand) * 100, 100)
|
||||
for(var/obj/machinery/power/terminal/T in inputting)
|
||||
var/obj/machinery/power/smes/S = T.master
|
||||
if(istype(S))
|
||||
S.input_power(smes_input_percentage, T)
|
||||
|
||||
netexcess = avail - load
|
||||
if(netexcess)
|
||||
var/perc = get_percent_load(1)
|
||||
for(var/obj/machinery/power/smes/S in nodes)
|
||||
S.restore(perc)
|
||||
|
||||
//updates the viewed load (as seen on power computers)
|
||||
viewload = round(load)
|
||||
@@ -123,7 +139,22 @@
|
||||
//reset the powernet
|
||||
load = 0
|
||||
avail = newavail
|
||||
smes_avail = smes_newavail
|
||||
inputting.Cut()
|
||||
smes_demand = 0
|
||||
newavail = 0
|
||||
smes_newavail = 0
|
||||
|
||||
/datum/powernet/proc/get_percent_load(var/smes_only = 0)
|
||||
if(smes_only)
|
||||
var/smes_used = load - (avail - smes_avail) // SMESs are always last to provide power
|
||||
if(!smes_used || smes_used < 0 || !smes_avail) // SMES power isn't available or being used at all, SMES load is therefore 0%
|
||||
return 0
|
||||
return between(0, (smes_used / smes_avail) * 100, 100) // Otherwise return percentage load of SMESs.
|
||||
else
|
||||
if(!load)
|
||||
return 0
|
||||
return between(0, (load / avail) * 100, 100)
|
||||
|
||||
/datum/powernet/proc/get_electrocute_damage()
|
||||
switch(avail)
|
||||
|
||||
+207
-167
@@ -1,7 +1,6 @@
|
||||
// the SMES
|
||||
// stores power
|
||||
|
||||
#define SMESRATE 0.03333 //translates Watt into Kilowattminutes with respect to machinery schedule_interval ~(2s*1W*1min/60s)
|
||||
#define SMESMAXCHARGELEVEL 250000
|
||||
#define SMESMAXOUTPUT 250000
|
||||
|
||||
@@ -25,7 +24,7 @@
|
||||
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/outputting = 0 // 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
|
||||
@@ -35,15 +34,23 @@
|
||||
var/last_input_attempt = 0
|
||||
var/last_charge = 0
|
||||
|
||||
//For icon overlay updates
|
||||
var/last_disp
|
||||
var/last_chrg
|
||||
var/last_onln
|
||||
|
||||
var/damage = 0
|
||||
var/maxdamage = 500 // Relatively resilient, given how expensive it is, but once destroyed produces small explosion.
|
||||
|
||||
var/input_cut = 0
|
||||
var/input_pulsed = 0
|
||||
var/output_cut = 0
|
||||
var/output_pulsed = 0
|
||||
var/target_load = 0
|
||||
|
||||
var/open_hatch = 0
|
||||
var/name_tag = null
|
||||
var/building_terminal = 0 //Suggestions about how to avoid clickspam building several terminals accepted!
|
||||
var/obj/machinery/power/terminal/terminal = null
|
||||
var/list/terminals = list()
|
||||
var/should_be_mapped = 0 // If this is set to 0 it will send out warning on New()
|
||||
var/grid_check = FALSE // If true, suspends all I/O.
|
||||
|
||||
@@ -58,38 +65,38 @@
|
||||
|
||||
/obj/machinery/power/smes/Initialize()
|
||||
. = ..()
|
||||
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
|
||||
if(!terminal)
|
||||
for(var/d in GLOB.cardinal)
|
||||
var/turf/T = get_step(src, d)
|
||||
for(var/obj/machinery/power/terminal/term in T)
|
||||
if(term && term.dir == turn(d, 180) && !term.master)
|
||||
terminals |= term
|
||||
term.master = src
|
||||
term.connect_to_network()
|
||||
if(!terminals.len)
|
||||
stat |= BROKEN
|
||||
return
|
||||
terminal.master = src
|
||||
if(!terminal.powernet)
|
||||
terminal.connect_to_network()
|
||||
update_icon()
|
||||
|
||||
if(!powernet)
|
||||
connect_to_network()
|
||||
if(!should_be_mapped)
|
||||
warning("Non-buildable or Non-magical SMES at [src.x]X [src.y]Y [src.z]Z")
|
||||
|
||||
/obj/machinery/power/smes/Destroy()
|
||||
terminal = null
|
||||
for(var/obj/machinery/power/terminal/T in terminals)
|
||||
T.master = null
|
||||
terminals = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/power/smes/disconnect_terminal()
|
||||
if(terminal)
|
||||
terminal.master = null
|
||||
terminal = null
|
||||
/obj/machinery/power/smes/add_avail(var/amount)
|
||||
if(..(amount))
|
||||
powernet.smes_newavail += amount
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/machinery/power/smes/disconnect_terminal(var/obj/machinery/power/terminal/term)
|
||||
terminals -= term
|
||||
term.master = null
|
||||
|
||||
/obj/machinery/power/smes/update_icon()
|
||||
cut_overlays()
|
||||
if(stat & BROKEN) return
|
||||
@@ -113,48 +120,67 @@
|
||||
/obj/machinery/power/smes/proc/chargedisplay()
|
||||
return round(5.5*charge/(capacity ? capacity : 5e6))
|
||||
|
||||
/obj/machinery/power/smes/proc/input_power(var/percentage, var/obj/machinery/power/terminal/term)
|
||||
var/to_input = target_load * (percentage/100)
|
||||
to_input = between(0, to_input, target_load)
|
||||
if(percentage == 100)
|
||||
inputting = 2
|
||||
else if(percentage)
|
||||
inputting = 1
|
||||
// else inputting = 0, as set in process()
|
||||
|
||||
var/inputted = term.powernet.draw_power(min(to_input, input_level - input_available))
|
||||
add_charge(inputted)
|
||||
input_available += inputted
|
||||
|
||||
// Mostly in place due to child types that may store power in other way (PSUs)
|
||||
/obj/machinery/power/smes/proc/add_charge(var/amount)
|
||||
charge += amount*SMESRATE
|
||||
|
||||
/obj/machinery/power/smes/proc/remove_charge(var/amount)
|
||||
charge -= amount*SMESRATE
|
||||
|
||||
/obj/machinery/power/smes/process()
|
||||
if(stat & BROKEN) return
|
||||
|
||||
//store machine state to see if we need to update the icon overlays
|
||||
var/last_disp = chargedisplay()
|
||||
var/last_chrg = inputting
|
||||
var/last_onln = outputting
|
||||
|
||||
//inputting
|
||||
if(input_attempt && (!input_pulsed && !input_cut) && !grid_check)
|
||||
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 (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
|
||||
|
||||
//outputting
|
||||
if(outputting && (!output_pulsed && !output_cut) && !grid_check)
|
||||
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)
|
||||
|
||||
add_avail(output_used) // add output to powernet (smes side)
|
||||
else if(output_attempt && output_level > 0)
|
||||
outputting = 1
|
||||
else
|
||||
output_used = 0
|
||||
|
||||
// only update icon if state changed
|
||||
if(last_disp != chargedisplay() || last_chrg != inputting || last_onln != outputting)
|
||||
update_icon()
|
||||
//store machine state to see if we need to update the icon overlays
|
||||
last_disp = chargedisplay()
|
||||
last_chrg = inputting
|
||||
last_onln = outputting
|
||||
input_available = 0
|
||||
|
||||
//inputting
|
||||
if(input_attempt && (!input_pulsed && !input_cut) && !grid_check)
|
||||
target_load = min((capacity-charge)/SMESRATE, input_level) // Amount we will request from the powernet.
|
||||
var/input_available = FALSE
|
||||
for(var/obj/machinery/power/terminal/term in terminals)
|
||||
if(!term.powernet)
|
||||
continue
|
||||
input_available = TRUE
|
||||
term.powernet.smes_demand += target_load
|
||||
term.powernet.inputting.Add(term)
|
||||
if(!input_available)
|
||||
target_load = 0 // We won't input any power without powernet connection.
|
||||
inputting = 0
|
||||
|
||||
output_used = 0
|
||||
//outputting
|
||||
if(output_attempt && (!output_pulsed && !output_cut) && powernet && charge && !grid_check)
|
||||
output_used = min( charge/SMESRATE, output_level) //limit output to that stored
|
||||
remove_charge(output_used) // reduce the storage (may be recovered in /restore() if excessive)
|
||||
add_avail(output_used) // add output to powernet (smes side)
|
||||
outputting = 2
|
||||
else if(!powernet || !charge)
|
||||
outputting = 1
|
||||
else
|
||||
output_used = 0
|
||||
|
||||
// called after all power processes are finished
|
||||
// restores charge level to smes if there was excess this ptick
|
||||
/obj/machinery/power/smes/proc/restore()
|
||||
/obj/machinery/power/smes/proc/restore(var/percent_load)
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
|
||||
@@ -162,20 +188,17 @@
|
||||
output_used = 0
|
||||
return
|
||||
|
||||
var/excess = powernet.netexcess // this was how much wasn't used on the network last ptick, minus any removed by other SMESes
|
||||
|
||||
excess = min(output_used, excess) // clamp it to how much was actually output by this SMES last ptick
|
||||
|
||||
excess = min((capacity-charge)/SMESRATE, excess) // for safety, also limit recharge by space capacity of SMES (shouldn't happen)
|
||||
var/total_restore = output_used * (percent_load / 100) // First calculate amount of power used from our output
|
||||
total_restore = between(0, total_restore, output_used) // Now clamp the value between 0 and actual output, just for clarity.
|
||||
total_restore = output_used - total_restore // And, at last, subtract used power from outputted power, to get amount of power we will give back to the SMES.
|
||||
|
||||
// now recharge this amount
|
||||
|
||||
var/clev = chargedisplay()
|
||||
|
||||
charge += excess * SMESRATE // restore unused power
|
||||
powernet.netexcess -= excess // remove the excess from the powernet, so later SMESes don't try to use it
|
||||
add_charge(total_restore) // restore unused power
|
||||
powernet.netexcess -= total_restore // remove the excess from the powernet, so later SMESes don't try to use it
|
||||
|
||||
output_used -= excess
|
||||
output_used -= total_restore
|
||||
|
||||
if(clev != chargedisplay() ) //if needed updates the icons overlay
|
||||
update_icon()
|
||||
@@ -184,7 +207,7 @@
|
||||
//Will return 1 on failure
|
||||
/obj/machinery/power/smes/proc/make_terminal(const/mob/user)
|
||||
if (user.loc == loc)
|
||||
to_chat(user, "<span class='warning'>You must not be on the same tile as the [src].</span>")
|
||||
to_chat(user, "<span class='filter_notice'><span class='warning'>You must not be on the same tile as the [src].</span></span>")
|
||||
return 1
|
||||
|
||||
//Direction the terminal will face to
|
||||
@@ -196,26 +219,42 @@
|
||||
tempDir = WEST
|
||||
var/turf/tempLoc = get_step(src, reverse_direction(tempDir))
|
||||
if (istype(tempLoc, /turf/space))
|
||||
to_chat(user, "<span class='warning'>You can't build a terminal on space.</span>")
|
||||
to_chat(user, "<span class='filter_notice'><span class='warning'>You can't build a terminal on space.</span></span>")
|
||||
return 1
|
||||
else if (istype(tempLoc))
|
||||
if(!tempLoc.is_plating())
|
||||
to_chat(user, "<span class='warning'>You must remove the floor plating first.</span>")
|
||||
to_chat(user, "<span class='filter_notice'><span class='warning'>You must remove the floor plating first.</span></span>")
|
||||
return 1
|
||||
to_chat(user, "<span class='notice'>You start adding cable to the [src].</span>")
|
||||
if(check_terminal_exists(tempLoc, user, tempDir))
|
||||
return 1
|
||||
to_chat(user, "<span class='filter_notice'><span class='notice'>You start adding cable to the [src].</span></span>")
|
||||
if(do_after(user, 50))
|
||||
terminal = new /obj/machinery/power/terminal(tempLoc)
|
||||
terminal.set_dir(tempDir)
|
||||
terminal.master = src
|
||||
terminal.connect_to_network()
|
||||
if(check_terminal_exists(tempLoc, user, tempDir))
|
||||
return 1
|
||||
var/obj/machinery/power/terminal/term = new/obj/machinery/power/terminal(tempLoc)
|
||||
term.set_dir(tempDir)
|
||||
term.master = src
|
||||
term.connect_to_network()
|
||||
terminals |= term
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/machinery/power/smes/proc/check_terminal_exists(var/turf/location, var/mob/user, var/direction)
|
||||
for(var/obj/machinery/power/terminal/term in location)
|
||||
if(term.dir == direction)
|
||||
to_chat(user, "<span class='filter_notice'><span class='notice'>There is already a terminal here.</span></span>")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/machinery/power/smes/draw_power(var/amount)
|
||||
if(terminal && terminal.powernet)
|
||||
return terminal.powernet.draw_power(amount)
|
||||
return 0
|
||||
var/drained = 0
|
||||
for(var/obj/machinery/power/terminal/term in terminals)
|
||||
if(!term.powernet)
|
||||
continue
|
||||
if((amount - drained) <= 0)
|
||||
return 0
|
||||
drained += term.powernet.draw_power(amount - drained)
|
||||
return drained
|
||||
|
||||
|
||||
/obj/machinery/power/smes/attack_ai(mob/user)
|
||||
@@ -228,65 +267,78 @@
|
||||
|
||||
|
||||
/obj/machinery/power/smes/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
|
||||
if(W.is_screwdriver())
|
||||
if(!open_hatch)
|
||||
open_hatch = 1
|
||||
to_chat(user, "<span class='notice'>You open the maintenance hatch of [src].</span>")
|
||||
playsound(src, W.usesound, 50, 1)
|
||||
return 0
|
||||
else
|
||||
open_hatch = 0
|
||||
to_chat(user, "<span class='notice'>You close the maintenance hatch of [src].</span>")
|
||||
playsound(src, W.usesound, 50, 1)
|
||||
return 0
|
||||
if(default_deconstruction_screwdriver(user, W))
|
||||
return FALSE
|
||||
|
||||
if (!open_hatch)
|
||||
to_chat(user, "<span class='warning'>You need to open access hatch on [src] first!</span>")
|
||||
return 0
|
||||
if (!panel_open)
|
||||
to_chat(user, "<span class='filter_notice'><span class='warning'>You need to open access hatch on [src] first!</span></span>")
|
||||
return FALSE
|
||||
|
||||
if(istype(W, /obj/item/stack/cable_coil) && !terminal && !building_terminal)
|
||||
if(istype(W, /obj/item/weapon/weldingtool))
|
||||
var/obj/item/weapon/weldingtool/WT = W
|
||||
if(!WT.isOn())
|
||||
to_chat(user, "<span class='filter_notice'>Turn on \the [WT] first!</span>")
|
||||
return FALSE
|
||||
if(!damage)
|
||||
to_chat(user, "<span class='filter_notice'>\The [src] is already fully repaired.</span>")
|
||||
return FALSE
|
||||
if(WT.remove_fuel(0,user) && do_after(user, damage, src))
|
||||
to_chat(user, "<span class='filter_notice'>You repair all structural damage to \the [src]</span>")
|
||||
damage = 0
|
||||
return FALSE
|
||||
else if(istype(W, /obj/item/stack/cable_coil) && !building_terminal)
|
||||
building_terminal = 1
|
||||
var/obj/item/stack/cable_coil/CC = W
|
||||
if (CC.get_amount() < 10)
|
||||
to_chat(user, "<span class='warning'>You need more cables.</span>")
|
||||
to_chat(user, "<span class='filter_notice'><span class='warning'>You need more cables.</span></span>")
|
||||
building_terminal = 0
|
||||
return 0
|
||||
return FALSE
|
||||
if (make_terminal(user))
|
||||
building_terminal = 0
|
||||
return 0
|
||||
return FALSE
|
||||
building_terminal = 0
|
||||
CC.use(10)
|
||||
user.visible_message(\
|
||||
"<span class='notice'>[user.name] has added cables to the [src].</span>",\
|
||||
"<span class='notice'>You added cables to the [src].</span>")
|
||||
"<span class='filter_notice'><span class='notice'>[user.name] has added cables to the [src].</span></span>",\
|
||||
"<span class='filter_notice'><span class='notice'>You added cables to the [src].</span></span>")
|
||||
stat = 0
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
else if(W.is_wirecutter() && terminal && !building_terminal)
|
||||
building_terminal = 1
|
||||
var/turf/tempTDir = terminal.loc
|
||||
else if(W.is_wirecutter() && !building_terminal)
|
||||
building_terminal = TRUE
|
||||
var/obj/machinery/power/terminal/term
|
||||
for(var/obj/machinery/power/terminal/T in get_turf(user))
|
||||
if(T.master == src)
|
||||
term = T
|
||||
break
|
||||
if(!term)
|
||||
to_chat(user, "<span class='filter_notice'><span class='warning'>There is no terminal on this tile.</span></span>")
|
||||
building_terminal = FALSE
|
||||
return FALSE
|
||||
var/turf/tempTDir = get_turf(term)
|
||||
if (istype(tempTDir))
|
||||
if(!tempTDir.is_plating())
|
||||
to_chat(user, "<span class='warning'>You must remove the floor plating first.</span>")
|
||||
to_chat(user, "<span class='filter_notice'><span class='warning'>You must remove the floor plating first.</span></span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You begin to cut the cables...</span>")
|
||||
to_chat(user, "<span class='filter_notice'><span class='notice'>You begin to cut the cables...</span></span>")
|
||||
playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
if(do_after(user, 50 * W.toolspeed))
|
||||
if (prob(50) && electrocute_mob(usr, terminal.powernet, terminal))
|
||||
if (prob(50) && electrocute_mob(usr, term.powernet, term))
|
||||
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
|
||||
s.set_up(5, 1, src)
|
||||
s.start()
|
||||
building_terminal = 0
|
||||
building_terminal = FALSE
|
||||
if(usr.stunned)
|
||||
return 0
|
||||
return FALSE
|
||||
new /obj/item/stack/cable_coil(loc,10)
|
||||
user.visible_message(\
|
||||
"<span class='notice'>[user.name] cut the cables and dismantled the power terminal.</span>",\
|
||||
"<span class='notice'>You cut the cables and dismantle the power terminal.</span>")
|
||||
qdel(terminal)
|
||||
building_terminal = 0
|
||||
return 0
|
||||
return 1
|
||||
"<span class='filter_notice'><span class='notice'>[user.name] cut the cables and dismantled the power terminal.</span></span>",\
|
||||
"<span class='filter_notice'><span class='notice'>You cut the cables and dismantle the power terminal.</span></span>")
|
||||
terminals -= term
|
||||
qdel(term)
|
||||
building_terminal = FALSE
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/power/smes/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
|
||||
@@ -303,21 +355,12 @@
|
||||
data["chargeMode"] = input_attempt
|
||||
data["chargeLevel"] = round(input_level/1000, 0.1)
|
||||
data["chargeMax"] = round(input_level_max/1000)
|
||||
if (terminal && terminal.powernet)
|
||||
data["chargeLoad"] = round(terminal.powernet.avail/1000, 0.1)
|
||||
else
|
||||
data["chargeLoad"] = 0
|
||||
data["chargeLoad"] = round(input_available/1000, 0.1)
|
||||
data["outputOnline"] = output_attempt
|
||||
data["outputLevel"] = round(output_level/1000, 0.1)
|
||||
data["outputMax"] = round(output_level_max/1000)
|
||||
data["outputLoad"] = round(output_used/1000, 0.1)
|
||||
|
||||
if(outputting)
|
||||
data["outputting"] = 2 // smes is outputting
|
||||
else if(!outputting && output_attempt)
|
||||
data["outputting"] = 1 // smes is online but not outputting because it's charge level is too low
|
||||
else
|
||||
data["outputting"] = 0 // smes is not outputting
|
||||
data["outputting"] = outputting
|
||||
|
||||
// update the ui if it exists, returns null if no ui is passed/found
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
@@ -333,6 +376,8 @@
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/power/smes/proc/Percentage()
|
||||
if(!capacity)
|
||||
return 0
|
||||
return round(100.0*charge/capacity, 0.1)
|
||||
|
||||
/obj/machinery/power/smes/Topic(href, href_list)
|
||||
@@ -342,10 +387,11 @@
|
||||
if( href_list["cmode"] )
|
||||
inputting(!input_attempt)
|
||||
update_icon()
|
||||
|
||||
return 1
|
||||
else if( href_list["online"] )
|
||||
outputting(!output_attempt)
|
||||
update_icon()
|
||||
return 1
|
||||
else if( href_list["input"] )
|
||||
switch( href_list["input"] )
|
||||
if("min")
|
||||
@@ -355,7 +401,7 @@
|
||||
if("set")
|
||||
input_level = (input(usr, "Enter new input level (0-[input_level_max/1000] kW)", "SMES Input Power Control", input_level/1000) as num) * 1000
|
||||
input_level = max(0, min(input_level_max, input_level)) // clamp to range
|
||||
|
||||
return 1
|
||||
else if( href_list["output"] )
|
||||
switch( href_list["output"] )
|
||||
if("min")
|
||||
@@ -365,42 +411,7 @@
|
||||
if("set")
|
||||
output_level = (input(usr, "Enter new output level (0-[output_level_max/1000] kW)", "SMES Output Power Control", output_level/1000) as num) * 1000
|
||||
output_level = max(0, min(output_level_max, output_level)) // clamp to range
|
||||
|
||||
investigate_log("input/output; <font color='[input_level>output_level?"green":"red"][input_level]/[output_level]</font> | Output-mode: [output_attempt?"<font color='green'>on</font>":"<font color='red'>off</font>"] | Input-mode: [input_attempt?"<font color='green'>auto</font>":"<font color='red'>off</font>"] by [usr.key]","singulo")
|
||||
log_game("SMES([x],[y],[z]) [key_name(usr)] changed settings: I:[input_level]([input_attempt]), O:[output_level]([output_attempt])")
|
||||
return 1
|
||||
|
||||
|
||||
/obj/machinery/power/smes/proc/ion_act()
|
||||
if(src.z in using_map.station_levels)
|
||||
if(prob(1)) //explosion
|
||||
for(var/mob/M in viewers(src))
|
||||
M.show_message("<font color='red'>The [src.name] is making strange noises!</font>", 3, "<font color='red'>You hear sizzling electronics.</font>", 2)
|
||||
sleep(10*pick(4,5,6,7,10,14))
|
||||
var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread()
|
||||
smoke.set_up(3, 0, src.loc)
|
||||
smoke.attach(src)
|
||||
smoke.start()
|
||||
explosion(src.loc, -1, 0, 1, 3, 1, 0)
|
||||
qdel(src)
|
||||
return
|
||||
if(prob(15)) //Power drain
|
||||
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
if(prob(25))
|
||||
emp_act(1)
|
||||
else if(prob(25))
|
||||
emp_act(2)
|
||||
else if(prob(25))
|
||||
emp_act(3)
|
||||
else
|
||||
emp_act(4)
|
||||
if(prob(5)) //smoke only
|
||||
var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread()
|
||||
smoke.set_up(3, 0, src.loc)
|
||||
smoke.attach(src)
|
||||
smoke.start()
|
||||
return 1
|
||||
|
||||
/obj/machinery/power/smes/proc/inputting(var/do_input)
|
||||
input_attempt = do_input
|
||||
@@ -412,6 +423,21 @@
|
||||
if(!output_attempt)
|
||||
outputting = 0
|
||||
|
||||
/obj/machinery/power/smes/take_damage(var/amount)
|
||||
amount = max(0, round(amount))
|
||||
damage += amount
|
||||
if(damage > maxdamage)
|
||||
visible_message("<span class='filter_notice'><span class='danger'>\The [src] explodes in large shower of sparks and smoke!</span></span>")
|
||||
// Depending on stored charge percentage cause damage.
|
||||
switch(Percentage())
|
||||
if(75 to INFINITY)
|
||||
explosion(get_turf(src), 1, 2, 4)
|
||||
if(40 to 74)
|
||||
explosion(get_turf(src), 0, 2, 3)
|
||||
if(5 to 39)
|
||||
explosion(get_turf(src), 0, 1, 2)
|
||||
qdel(src) // Either way we want to ensure the SMES is deleted.
|
||||
|
||||
/obj/machinery/power/smes/emp_act(severity)
|
||||
inputting(rand(0,1))
|
||||
outputting(rand(0,1))
|
||||
@@ -423,13 +449,27 @@
|
||||
update_icon()
|
||||
..()
|
||||
|
||||
/obj/machinery/power/smes/magical
|
||||
name = "magical power storage unit"
|
||||
desc = "A high-capacity superconducting magnetic energy storage (SMES) unit. Magically produces power."
|
||||
capacity = 9000000
|
||||
output_level = 250000
|
||||
should_be_mapped = 1
|
||||
/obj/machinery/power/smes/bullet_act(var/obj/item/projectile/Proj)
|
||||
if(Proj.damage_type == BRUTE || Proj.damage_type == BURN)
|
||||
take_damage(Proj.damage)
|
||||
|
||||
/obj/machinery/power/smes/magical/process()
|
||||
charge = 5000000
|
||||
/obj/machinery/power/smes/ex_act(var/severity)
|
||||
// Two strong explosions will destroy a SMES.
|
||||
// Given the SMES creates another explosion on it's destruction it sounds fairly reasonable.
|
||||
take_damage(250 / severity)
|
||||
|
||||
/obj/machinery/power/smes/examine(var/mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='filter_notice'>The service hatch is [panel_open ? "open" : "closed"].</span>")
|
||||
if(!damage)
|
||||
return
|
||||
var/damage_percentage = round((damage / maxdamage) * 100)
|
||||
switch(damage_percentage)
|
||||
if(75 to INFINITY)
|
||||
to_chat(user, "<span class='filter_notice'><span class='danger'>It's casing is severely damaged, and sparking circuitry may be seen through the holes!</span></span>")
|
||||
if(50 to 74)
|
||||
to_chat(user, "<span class='filter_notice'><span class='notice'>It's casing is considerably damaged, and some of the internal circuits appear to be exposed!</span></span>")
|
||||
if(25 to 49)
|
||||
to_chat(user, "<span class='filter_notice'><span class='notice'>It's casing is quite seriously damaged.</span></span>")
|
||||
if(0 to 24)
|
||||
to_chat(user, "<span class='filter_notice'>It's casing has some minor damage.</span>")
|
||||
@@ -113,7 +113,7 @@
|
||||
to_chat(usr, "<span class='warning'>Connection error: Destination Unreachable.</span>")
|
||||
|
||||
// Cyborgs standing next to the SMES can play with the wiring.
|
||||
if(istype(usr, /mob/living/silicon/robot) && Adjacent(usr) && open_hatch)
|
||||
if(istype(usr, /mob/living/silicon/robot) && Adjacent(usr) && panel_open)
|
||||
wires.Interact(usr)
|
||||
|
||||
// Proc: New()
|
||||
@@ -136,7 +136,7 @@
|
||||
// Description: Opens the UI as usual, and if cover is removed opens the wiring panel.
|
||||
/obj/machinery/power/smes/buildable/attack_hand()
|
||||
..()
|
||||
if(open_hatch)
|
||||
if(panel_open)
|
||||
wires.Interact(usr)
|
||||
|
||||
// Proc: recalc_coils()
|
||||
@@ -329,7 +329,7 @@
|
||||
|
||||
// Crowbar - Disassemble the SMES.
|
||||
if(W.is_crowbar())
|
||||
if (terminal)
|
||||
if (terminals.len)
|
||||
to_chat(user, "<span class='warning'>You have to disassemble the terminal first!</span>")
|
||||
return
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
/obj/machinery/power/terminal/Destroy()
|
||||
if(master)
|
||||
master.disconnect_terminal()
|
||||
master.disconnect_terminal(src)
|
||||
master = null
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
author: atlantiscze
|
||||
delete-after: True
|
||||
|
||||
changes:
|
||||
- rscadd: "SMES units now have automatic load balancing both on inputs and outputs"
|
||||
- rscadd: "SMES units (and derived objects, such as PSUs) can now have more than one input terminal. This allows for input from more otherwise isolated power networks."
|
||||
- tweak: "Completely redesigned cell rack PSUs, removed ghetto variant. Cell rack PSUs now support multiple power cells and hot-swapping of cells during operation. This allows for either charging multiple cells at once in one device (directly from power cable) or for powering up various machinery with only a power cell. They are still inferior to SMESes in pretty much all aspects."
|
||||
- tweak: "Multitool on a cable now shows nicer results with large currents (uses kW or MW accordingly)"
|
||||
- tweak: "Multitool may be now used to change colour of cable coils."
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 819 B |
@@ -24,7 +24,7 @@
|
||||
"x" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -22},/obj/machinery/light{icon_state = "tube1"; dir = 8},/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{ icon_state = "pipe-t"; dir = 1},/turf/simulated/floor/tiled/dark,/area/aisat_interior)
|
||||
"y" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled/dark,/area/aisat_interior)
|
||||
"z" = (/obj/machinery/light_switch,/turf/simulated/wall,/area/aisat_interior)
|
||||
"A" = (/obj/machinery/power/fractal_reactor,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/floor/tiled/dark,/area/aisat_interior)
|
||||
"A" = (/obj/machinery/power/debug_items/infinite_generator,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/floor/tiled/dark,/area/aisat_interior)
|
||||
"B" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/dark,/area/aisat_interior)
|
||||
"C" = (/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled/dark,/area/aisat_interior)
|
||||
"D" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/corner/lime/diagonal,/turf/simulated/floor/tiled/dark,/area/aisat_interior)
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<div class='item'>
|
||||
<div class='itemLabel'>
|
||||
Current mode:
|
||||
</div>
|
||||
<div class='itemContent'>
|
||||
{{if data.mode == 1}}
|
||||
OUTPUT ONLY
|
||||
{{else data.mode == 2}}
|
||||
INPUT ONLY
|
||||
{{else data.mode == 3}}
|
||||
INPUT AND OUTPUT
|
||||
{{else}}
|
||||
OFFLINE
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class='itemLabel'>
|
||||
Input status:
|
||||
</div>
|
||||
<div class='itemContent'>
|
||||
{{:data.input_load}} / {{:data.transfer_max}} W
|
||||
</div>
|
||||
<div class='itemLabel'>
|
||||
Output status:
|
||||
</div>
|
||||
<div class='itemContent'>
|
||||
{{:data.output_load}} / {{:data.transfer_max}} W
|
||||
</div>
|
||||
<div class='itemLabel'>
|
||||
Control panel:
|
||||
</div>
|
||||
<div class='itemContent'>
|
||||
{{:helper.link('OFF', null, { "disable" : 1 }, (data.mode == 0) ? 'disabled' : null)}}
|
||||
{{:helper.link('OUT', null, { "enable" : 1 }, (data.mode == 1) ? 'disabled' : null)}}
|
||||
{{:helper.link('IN', null, { "enable" : 2 }, (data.mode == 2) ? 'disabled' : null)}}
|
||||
{{:helper.link('IN/OUT', null, { "enable" : 3 }, (data.mode == 3) ? 'disabled' : null)}}
|
||||
{{if data.equalise}}
|
||||
{{:helper.link('EQ', null, { "equaliseoff" : 1 }, null, data.blink_tick ? 'yellowButton' : 'redButton')}}
|
||||
{{else}}
|
||||
{{:helper.link('EQ', null, { "equaliseon" : 1 })}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<table>
|
||||
{{for data.cells_list}}
|
||||
<tr>
|
||||
<td>Cell {{:value.slot}}
|
||||
{{if value.used}}
|
||||
<td>{{:helper.displayBar(value.percentage, 0, 100, 'good')}}
|
||||
<td>{{:value.percentage}} %
|
||||
<td>{{:helper.link('E', null, { "ejectcell" : value.id })}}
|
||||
{{else}}
|
||||
<td>{{:helper.displayBar(100, 0, 100, 'bad')}}
|
||||
<td>N/C
|
||||
<td>{{:helper.link('E', null, {}, 'disabled')}}
|
||||
{{/if}}
|
||||
{{/for}}
|
||||
</table>
|
||||
+1
-1
@@ -2983,7 +2983,7 @@
|
||||
#include "code\modules\power\cable_ender.dm"
|
||||
#include "code\modules\power\cable_heavyduty.dm"
|
||||
#include "code\modules\power\cell.dm"
|
||||
#include "code\modules\power\fractal_reactor.dm"
|
||||
#include "code\modules\power\debug_items.dm"
|
||||
#include "code\modules\power\generator.dm"
|
||||
#include "code\modules\power\generator_type2.dm"
|
||||
#include "code\modules\power\gravitygenerator_vr.dm"
|
||||
|
||||
Reference in New Issue
Block a user