[MDB Ignore] General maintenance for SMES (#91587)

## About The Pull Request
- SMES now directly gives/takes charge to the power cells stored inside
its component parts instead of modifying a `charge` variable whose value
was set from the total charge of its stored cells
- Removed `capacity` var. It's now derived from the total cells
`max_charge`. Even then its value was set to this so manually setting it
was a waste
- Fixes #71918. Because of point 1, this also means if you install
rigged cells in the SMES it now explodes
- Adds examines & screentips for installing terminal & other tool acts
- Smes can be connected to the powernet with a multitool with the panel
open after construction.
- General maintenance for portable smes as well. Repaths it to machine
subtype instead of power cause all it's functionality wasn't used
- Removed a bunch of unused defines, autodoc and shuffled around other
code

## Changelog
🆑
qol: SMES has examines and screentips for various stuff
code: Improved code of SMES in general
fix: smes can be connected to the powernet with a multitool with the
panel open after construction
refactor: SMES now functions consistently with its power cells & the
RPED.
/🆑
This commit is contained in:
SyncIt21
2025-07-12 16:21:58 +02:00
committed by GitHub
parent 3b91e3270b
commit f57f95aa95
10 changed files with 525 additions and 475 deletions
-1
View File
@@ -1134,7 +1134,6 @@
/area/awaymission/research/interior/security)
"fw" = (
/obj/machinery/power/smes{
capacity = 1.8e+008;
charge = 2e+005
},
/obj/structure/cable,
@@ -55060,7 +55060,6 @@
/area/station/cargo/bitrunning/den)
"pBI" = (
/obj/machinery/power/smes{
capacity = 1.8e+008;
charge = 2e+005
},
/obj/effect/decal/cleanable/cobweb/cobweb2,
@@ -51361,7 +51361,6 @@
/area/station/engineering/gravity_generator)
"rMT" = (
/obj/machinery/power/smes{
capacity = 1.8e+008;
charge = 2e+005
},
/obj/effect/decal/cleanable/dirt,
@@ -46243,7 +46243,6 @@
"pts" = (
/obj/machinery/power/smes{
charge = 10000;
capacity = 9e+06
},
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+2 -2
View File
@@ -54,7 +54,7 @@
for(var/obj/machinery/power/smes/smes as anything in all_smes)
if(!is_station_level(smes.z))
continue
smes.charge = smes.capacity
smes.adjust_charge(INFINITY)
smes.output_level = smes.output_level_max
smes.output_attempt = TRUE
smes.update_appearance()
@@ -86,7 +86,7 @@
for(var/obj/machinery/power/smes/smes as anything in all_smes)
if(!is_station_level(smes.z))
continue
smes.charge = smes.capacity
smes.adjust_charge(INFINITY)
smes.output_level = smes.output_level_max
smes.output_attempt = TRUE
smes.update_appearance()
@@ -363,7 +363,7 @@
name = "portable SMES"
greyscale_colors = CIRCUIT_COLOR_ENGINEERING
needs_anchored = FALSE
build_path = /obj/machinery/power/smesbank
build_path = /obj/machinery/smesbank
req_components = list(
/obj/item/stack/cable_coil = 5,
/obj/item/stock_parts/power_store/battery = 5,)
+323 -291
View File
@@ -1,18 +1,6 @@
// the SMES
// stores power
//Cache defines
#define SMES_CLEVEL_1 1
#define SMES_CLEVEL_2 2
#define SMES_CLEVEL_3 3
#define SMES_CLEVEL_4 4
#define SMES_CLEVEL_5 5
#define SMES_OUTPUTTING 6
#define SMES_NOT_OUTPUTTING 7
#define SMES_INPUTTING 8
#define SMES_INPUT_ATTEMPT 9
/obj/machinery/power/smes
name = "power storage unit"
desc = "A high-capacity superconducting magnetic energy storage (SMES) unit."
@@ -22,43 +10,53 @@
circuit = /obj/item/circuitboard/machine/smes
can_change_cable_layer = TRUE
/// The charge capacity.
var/capacity = 50 * STANDARD_BATTERY_CHARGE // The board defaults with 5 high capacity batteries.
/// The current charge.
/// The initial charge of this smes.
var/charge = 0
/// Max capacity of all cells in this smes
VAR_PROTECTED/total_capacity = 0
var/input_attempt = TRUE // TRUE = attempting to charge, FALSE = not attempting to charge
var/inputting = TRUE // TRUE = actually inputting, FALSE = not inputting
var/input_level = 50 KILO WATTS // amount of power the SMES attempts to charge by
var/input_level_max = 200 KILO WATTS // cap on input_level
var/input_available = 0 // amount of charge available from input last tick
/// TRUE = attempting to charge, FALSE = not attempting to charge
var/input_attempt = TRUE
/// TRUE = actually inputting, FALSE = not inputting
var/inputting = TRUE
/// amount of power the SMES attempts to charge by
var/input_level = 50 KILO WATTS
/// cap on input_level
var/input_level_max = 200 KILO WATTS
/// amount of charge available from input last tick
var/input_available = 0
var/output_attempt = TRUE // TRUE = attempting to output, FALSE = not attempting to output
var/outputting = TRUE // TRUE = actually outputting, FALSE = not outputting
var/output_level = 50 KILO WATTS // amount of power the SMES attempts to output
var/output_level_max = 200 KILO WATTS // 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
/// TRUE = attempting to output, FALSE = not attempting to output
var/output_attempt = TRUE
/// TRUE = actually outputting, FALSE = not outputting
var/outputting = TRUE
/// amount of power the SMES attempts to output
var/output_level = 50 KILO WATTS
/// cap on output_level
var/output_level_max = 200 KILO WATTS
/// amount of power actually outputted. may be less than output_level if the powernet returns excess power
var/output_used = 0
/// does this SMES show its input/output lights?
///Should we show display lights
var/show_display_lights = TRUE
/// Terminal for charging this smes
var/obj/machinery/power/terminal/terminal = null
/obj/machinery/power/smes/examine(user)
. = ..()
if(!terminal)
. += span_warning("This [src] has no power terminal!")
/obj/machinery/power/smes/get_save_vars()
. = ..()
. += NAMEOF(src, charge)
. += NAMEOF(src, capacity)
. += NAMEOF(src, input_level)
. += NAMEOF(src, output_level)
return .
/obj/machinery/power/smes/Initialize(mapload)
. = ..()
//screentips
register_context()
///initial charge
if(charge)
for(var/obj/item/stock_parts/power_store/power_cell in component_parts)
power_cell.use(power_cell.charge())
if(charge)
charge -= power_cell.give(charge)
charge = 0
//locate terminal
dir_loop:
for(var/direction in GLOB.cardinals)
var/turf/turf = get_step(src, direction)
@@ -66,124 +64,141 @@
if(term && term.dir == REVERSE_DIR(direction))
terminal = term
break dir_loop
if(!terminal)
atom_break()
return
terminal.master = src
update_appearance()
update_appearance(UPDATE_OVERLAYS)
/obj/machinery/power/smes/disconnect_terminal()
if(terminal)
terminal.master = null
terminal = null
atom_break()
/obj/machinery/power/smes/Destroy()
if(SSticker.IsRoundInProgress())
var/turf/turf = get_turf(src)
message_admins("[src] deleted at [ADMIN_VERBOSEJMP(turf)]")
log_game("[src] deleted at [AREACOORD(turf)]")
investigate_log("deleted at [AREACOORD(turf)]", INVESTIGATE_ENGINE)
disconnect_terminal()
return ..()
/obj/machinery/power/smes/add_context(atom/source, list/context, obj/item/held_item, mob/user)
. = NONE
if(isnull(held_item))
return
if(istype(held_item, /obj/item/stack/cable_coil) && !terminal && can_place_terminal(user, held_item, silent = TRUE))
context[SCREENTIP_CONTEXT_LMB] = "Install terminal"
return CONTEXTUAL_SCREENTIP_SET
if(held_item.tool_behaviour == TOOL_SCREWDRIVER)
context[SCREENTIP_CONTEXT_LMB] = "[panel_open ? "Close" : "Open"] panel"
return CONTEXTUAL_SCREENTIP_SET
if(held_item.tool_behaviour == TOOL_WRENCH && panel_open)
context[SCREENTIP_CONTEXT_LMB] = "Rotate"
return CONTEXTUAL_SCREENTIP_SET
else if(held_item.tool_behaviour == TOOL_WIRECUTTER && terminal && panel_open)
context[SCREENTIP_CONTEXT_LMB] = "Cut terminal"
return CONTEXTUAL_SCREENTIP_SET
else if(held_item.tool_behaviour == TOOL_CROWBAR && !terminal && panel_open)
context[SCREENTIP_CONTEXT_LMB] = "Deconstruct"
return CONTEXTUAL_SCREENTIP_SET
/obj/machinery/power/smes/examine(user)
. = ..()
. += span_notice("it's maintainence panel can be [EXAMINE_HINT("screwed")] [panel_open ? "closed" : "opened"]")
if(panel_open)
if(!terminal)
. += span_notice("It can be [EXAMINE_HINT("pried")] apart.")
. += span_notice("It can [EXAMINE_HINT("wrenched")] to rotate.")
if(!terminal)
. += span_warning("A terminal that requires [EXAMINE_HINT("10 cable pieces")] needs to be installed!.")
else if(panel_open)
. += span_notice("The terminal can be [EXAMINE_HINT("cut")] apart.")
/obj/machinery/power/smes/update_overlays()
. = ..()
if(panel_open || !is_operational)
return
if(show_display_lights)
. += "smes-op[outputting ? 1 : 0]"
. += "smes-oc[inputting ? 1 : 0]"
var/clevel = chargedisplay()
if(clevel > 0)
. += "smes-og[clevel]"
/obj/machinery/power/smes/get_save_vars()
. = ..()
charge = total_charge()
. += NAMEOF(src, charge)
. += NAMEOF(src, input_level)
. += NAMEOF(src, output_level)
/// Returns the total charge of this smes
/obj/machinery/power/smes/proc/total_charge()
PROTECTED_PROC(TRUE)
SHOULD_NOT_OVERRIDE(TRUE)
for(var/obj/item/stock_parts/power_store/power_cell in component_parts)
. += power_cell.charge()
/**
* Adjusts the total charge of this smes
* Arguments
*
* * charge_adjust - the amount of give/take from this smes
*/
/obj/machinery/power/smes/proc/adjust_charge(charge_adjust)
var/give = charge_adjust > 0
charge_adjust = abs(charge_adjust)
for(var/obj/item/stock_parts/power_store/power_cell in component_parts)
var/amount_adjusted
if(give)
amount_adjusted = power_cell.give(charge_adjust)
else
amount_adjusted = power_cell.use(charge_adjust, TRUE)
. += amount_adjusted
charge_adjust -= amount_adjusted
if(!charge_adjust)
return
/obj/machinery/power/smes/RefreshParts()
SHOULD_CALL_PARENT(FALSE)
var/power_coefficient = 0
var/max_charge = 0
var/new_charge = 0
for(var/datum/stock_part/capacitor/capacitor in component_parts)
power_coefficient += capacitor.tier
input_level_max = initial(input_level_max) * power_coefficient
output_level_max = initial(output_level_max) * power_coefficient
total_capacity = 0
for(var/obj/item/stock_parts/power_store/power_cell in component_parts)
max_charge += power_cell.maxcharge
new_charge += power_cell.charge
capacity = max_charge
if(!initial(charge) && !charge)
charge = new_charge
total_capacity += power_cell.max_charge()
update_static_data_for_all_viewers()
/obj/machinery/power/smes/should_have_node()
return TRUE
// adapted from APC item interacts for cable act handling
/obj/machinery/power/smes/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
. = NONE
if(istype(tool, /obj/item/stack/cable_coil))
. = cable_act(user, tool, LAZYACCESS(modifiers, RIGHT_CLICK))
if(.)
return .
return .
/obj/machinery/power/smes/cable_layer_act(mob/living/user, obj/item/tool)
if(!QDELETED(terminal))
balloon_alert(user, "cut the terminal first!")
return ITEM_INTERACT_BLOCKING
return ..()
//opening using screwdriver
/obj/machinery/power/smes/screwdriver_act(mob/living/user, obj/item/tool)
. = ITEM_INTERACT_BLOCKING
if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-o", initial(icon_state), tool))
update_appearance()
return ITEM_INTERACT_SUCCESS
//changing direction using wrench
/obj/machinery/power/smes/wrench_act(mob/living/user, obj/item/tool)
. = ITEM_INTERACT_BLOCKING
if(default_change_direction_wrench(user, tool))
terminal = null
var/turf/turf = get_step(src, dir)
for(var/obj/machinery/power/terminal/term in turf)
if(term && term.dir == REVERSE_DIR(dir))
terminal = term
terminal.master = src
to_chat(user, span_notice("Terminal found."))
break
if(!terminal)
to_chat(user, span_alert("No power terminal found."))
return ITEM_INTERACT_SUCCESS
set_machine_stat(machine_stat & ~BROKEN)
update_appearance()
return ITEM_INTERACT_SUCCESS
//building and linking a terminal
/obj/machinery/power/smes/proc/cable_act(mob/living/user, obj/item/stack/cable_coil/installing_cable, is_right_clicking)
. = ITEM_INTERACT_BLOCKING
if(!can_place_terminal(user, installing_cable, silent = FALSE))
return ITEM_INTERACT_BLOCKING
var/terminal_cable_layer
if(is_right_clicking)
var/choice = tgui_input_list(user, "Select Power Input Cable Layer", "Select Cable Layer", GLOB.cable_name_to_layer)
if(isnull(choice) \
|| !user.is_holding(installing_cable) \
|| !user.Adjacent(src) \
|| user.incapacitated \
|| !can_place_terminal(user, installing_cable, silent = TRUE) \
)
return ITEM_INTERACT_BLOCKING
terminal_cable_layer = GLOB.cable_name_to_layer[choice]
user.visible_message(span_notice("[user.name] starts adding cables to [src]."))
balloon_alert(user, "adding cables...")
playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE)
if(!do_after(user, 2 SECONDS, target = src))
return ITEM_INTERACT_BLOCKING
if(!can_place_terminal(user, installing_cable, silent = TRUE))
return ITEM_INTERACT_BLOCKING
var/obj/item/stack/cable_coil/cable = installing_cable
var/turf/turf = get_turf(user)
var/obj/structure/cable/connected_cable = turf.get_cable_node(terminal_cable_layer) //get the connecting node cable, if there's one
if (prob(50) && electrocute_mob(user, connected_cable, connected_cable, 1, TRUE)) //animate the electrocution if uncautious and unlucky
do_sparks(5, TRUE, src)
return ITEM_INTERACT_BLOCKING
cable.use(10)
user.visible_message(span_notice("[user.name] adds cables to [src]."))
balloon_alert(user, "cables added")
//build the terminal and link it to the network
make_terminal(turf, terminal_cable_layer)
terminal.connect_to_network()
return ITEM_INTERACT_SUCCESS
//crowbarring it!
/obj/machinery/power/smes/crowbar_act(mob/living/user, obj/item/tool)
if(!panel_open)
return
var/turf/turf = get_turf(src)
if(default_deconstruction_crowbar(tool))
message_admins("[src] has been deconstructed by [ADMIN_LOOKUPFLW(user)] in [ADMIN_VERBOSEJMP(turf)].")
user.log_message("deconstructed [src]", LOG_GAME)
investigate_log("deconstructed by [key_name(user)] at [AREACOORD(src)].", INVESTIGATE_ENGINE)
return
/// Checks if we're in a valid state to place a terminal
/**
* Can we place the terminal based on the players position
*
* Arguments
* * mob/living/user - the player attempting to install the cable
* * obj/item/stack/cable_coil/installing_cable - the cable coil used to install the terminal
* * silent - should we display error messages
*/
/obj/machinery/power/smes/proc/can_place_terminal(mob/living/user, obj/item/stack/cable_coil/installing_cable, silent = TRUE)
PRIVATE_PROC(TRUE)
var/set_dir = get_dir(user, src)
if(set_dir & (set_dir - 1))//we don't want diagonal click
return FALSE
@@ -207,141 +222,168 @@
return FALSE
return TRUE
// adapted from APC item interacts for cable act handling
/obj/machinery/power/smes/item_interaction(mob/living/user, obj/item/stack/cable_coil/installing_cable, list/modifiers)
. = NONE
if(istype(installing_cable))
. = ITEM_INTERACT_BLOCKING
if(!can_place_terminal(user, installing_cable, silent = FALSE))
return ITEM_INTERACT_BLOCKING
//select cable layer
var/terminal_cable_layer
if(LAZYACCESS(modifiers, RIGHT_CLICK))
var/choice = tgui_input_list(user, "Select Power Input Cable Layer", "Select Cable Layer", GLOB.cable_name_to_layer)
if(isnull(choice) \
|| !user.is_holding(installing_cable) \
|| !user.Adjacent(src) \
|| user.incapacitated \
|| !can_place_terminal(user, installing_cable, silent = TRUE) \
)
return ITEM_INTERACT_BLOCKING
terminal_cable_layer = GLOB.cable_name_to_layer[choice]
user.visible_message(span_notice("[user.name] starts adding cables to [src]."))
balloon_alert(user, "adding cables...")
playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE)
//use cable
if(!do_after(user, 2 SECONDS, target = src))
return ITEM_INTERACT_BLOCKING
if(!can_place_terminal(user, installing_cable, silent = TRUE))
return ITEM_INTERACT_BLOCKING
var/obj/item/stack/cable_coil/cable = installing_cable
var/turf/turf = get_turf(user)
var/obj/structure/cable/connected_cable = turf.get_cable_node(terminal_cable_layer) //get the connecting node cable, if there's one
if (prob(50) && electrocute_mob(user, connected_cable, connected_cable, 1, TRUE)) //animate the electrocution if uncautious and unlucky
do_sparks(5, TRUE, src)
return ITEM_INTERACT_BLOCKING
cable.use(10)
user.visible_message(span_notice("[user.name] adds cables to [src]."))
balloon_alert(user, "cables added")
//build the terminal and link it to the network
terminal = new(turf)
terminal.master = src
terminal.cable_layer = terminal_cable_layer
terminal.setDir(get_dir(turf, src))
terminal.connect_to_network()
set_machine_stat(machine_stat & ~BROKEN)
return ITEM_INTERACT_SUCCESS
//opening using screwdriver
/obj/machinery/power/smes/screwdriver_act(mob/living/user, obj/item/tool)
. = ITEM_INTERACT_BLOCKING
if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-o", initial(icon_state), tool))
update_appearance(UPDATE_OVERLAYS)
return ITEM_INTERACT_SUCCESS
/obj/machinery/power/smes/wirecutter_act(mob/living/user, obj/item/item)
//disassembling the terminal
. = ..()
. = ITEM_INTERACT_FAILURE
if(terminal && panel_open)
terminal.dismantle(user, item)
return TRUE
return ITEM_INTERACT_SUCCESS
/obj/machinery/power/smes/default_deconstruction_crowbar(obj/item/crowbar/crowbar)
if(istype(crowbar) && terminal)
balloon_alert(usr, "remove the power terminal!")
return FALSE
return ..()
/obj/machinery/power/smes/on_deconstruction(disassembled)
for(var/obj/item/stock_parts/power_store/cell in component_parts)
cell.charge = (charge / capacity) * cell.maxcharge
/obj/machinery/power/smes/Destroy()
if(SSticker.IsRoundInProgress())
var/turf/turf = get_turf(src)
message_admins("[src] deleted at [ADMIN_VERBOSEJMP(turf)]")
log_game("[src] deleted at [AREACOORD(turf)]")
investigate_log("deleted at [AREACOORD(turf)]", INVESTIGATE_ENGINE)
//crowbarring it!
/obj/machinery/power/smes/crowbar_act(mob/living/user, obj/item/tool)
. = ITEM_INTERACT_FAILURE
if(terminal)
disconnect_terminal()
return ..()
// create a terminal object pointing towards the SMES
// wires will attach to this
/obj/machinery/power/smes/proc/make_terminal(turf/turf, terminal_cable_layer = cable_layer)
terminal = new/obj/machinery/power/terminal(turf)
terminal.cable_layer = terminal_cable_layer
terminal.setDir(get_dir(turf,src))
terminal.master = src
set_machine_stat(machine_stat & ~BROKEN)
/obj/machinery/power/smes/disconnect_terminal()
if(terminal)
terminal.master = null
terminal = null
atom_break()
/// is this SMES in a suitable state to display overlays?
/obj/machinery/power/smes/proc/display_ready()
if(machine_stat & BROKEN)
return FALSE
if(panel_open)
return FALSE
return TRUE
/obj/machinery/power/smes/update_overlays()
. = ..()
if(!display_ready())
balloon_alert(user, "remove the power terminal!")
return
if(show_display_lights)
. += "smes-op[outputting ? 1 : 0]"
. += "smes-oc[inputting ? 1 : 0]"
if(default_deconstruction_crowbar(tool))
var/turf/ground = get_turf(src)
message_admins("[src] has been deconstructed by [ADMIN_LOOKUPFLW(user)] in [ADMIN_VERBOSEJMP(ground)].")
user.log_message("deconstructed [src]", LOG_GAME)
investigate_log("deconstructed by [key_name(user)] at [AREACOORD(src)].", INVESTIGATE_ENGINE)
return ITEM_INTERACT_SUCCESS
var/clevel = chargedisplay()
if(clevel > 0)
. += "smes-og[clevel]"
//changing direction using wrench
/obj/machinery/power/smes/wrench_act(mob/living/user, obj/item/tool)
. = ITEM_INTERACT_FAILURE
if(default_change_direction_wrench(user, tool))
disconnect_terminal()
for(var/obj/machinery/power/terminal/term in get_step(src, dir))
if(term && term.dir == REVERSE_DIR(dir))
terminal = term
terminal.master = src
to_chat(user, span_notice("Terminal found."))
set_machine_stat(machine_stat & ~BROKEN)
update_appearance(UPDATE_OVERLAYS)
return ITEM_INTERACT_SUCCESS
to_chat(user, span_alert("No power terminal found."))
/obj/machinery/power/smes/cable_layer_act(mob/living/user, obj/item/tool)
if(!panel_open)
balloon_alert(user, "open panel first!")
return ITEM_INTERACT_BLOCKING
return ..()
/obj/machinery/power/smes/multitool_act(mob/living/user, obj/item/tool)
. = ..()
if(. == ITEM_INTERACT_SUCCESS)
connect_to_network()
///Returns the charge level this smes is at 0->5 for display purposes
/obj/machinery/power/smes/proc/chargedisplay()
if(capacity <= 0)
return 0
return clamp(round(5.5*charge/capacity),0,5)
SHOULD_BE_PURE(TRUE)
return clamp(round(5 * (total_charge() / total_capacity)), 0, 5)
/obj/machinery/power/smes/process(seconds_per_tick)
if(machine_stat & BROKEN)
if(!is_operational)
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
var/input_energy = power_to_energy(input_level)
var/output_energy = power_to_energy(output_level)
//outputting
if(output_attempt)
if(outputting)
output_used = min(charge, output_energy) //limit output to that stored
if(output_attempt && powernet)
var/output_energy = power_to_energy(output_level)
if (add_avail(output_used)) // add output to powernet if it exists (smes side)
adjust_charge(-output_used) // reduce the storage (may be recovered in /restore() if excessive)
output_used = 0
if(output_energy <= 0)
outputting = FALSE
else
outputting = TRUE
// reduce the storage (may be recovered in /restore() if excessive)
output_used = adjust_charge(-output_energy)
if(output_used)
add_avail(output_used)
// either from no charge or set to 0
if(output_used < 0.1)
outputting = FALSE
investigate_log("lost power and turned off", INVESTIGATE_ENGINE)
else
outputting = FALSE
if(output_used < 0.1) // either from no charge or set to 0
outputting = FALSE
investigate_log("lost power and turned off", INVESTIGATE_ENGINE)
else if(output_attempt && charge > output_energy && output_level > 0)
outputting = TRUE
else
output_used = 0
else
outputting = FALSE
//inputting
if(terminal && input_attempt)
if(input_attempt && terminal)
var/input_energy = power_to_energy(input_level)
input_available = terminal.surplus()
if(inputting)
if(input_available > 0) // if there's power available, try to charge
var/load = min((capacity-charge), input_energy, input_available) // charge at set rate, limited to spare capacity
adjust_charge(load) // increase the charge
terminal.add_load(load) // add the load to the terminal side network
else // if not enough capcity
inputting = FALSE // stop inputting
if(input_energy <= 0)
inputting = FALSE
else
if(input_attempt && input_available > 0)
inputting = TRUE
inputting = TRUE
// increase the charge
var/load = adjust_charge(min(input_energy, input_available))
if(load)
terminal.add_load(load) // add the load to the terminal side network
else
inputting = FALSE
else
inputting = FALSE
// only update icon if state changed
if(last_disp != chargedisplay() || last_chrg != inputting || last_onln != outputting)
update_appearance()
/// Adjusts the charge in this SMES, used instead of directly adjusting the charge value. Mainly for the benefit of the power connector/portable SMES system.
/obj/machinery/power/smes/proc/adjust_charge(charge_adjust)
charge += charge_adjust
/// Sets the charge in this SMES, used instead of directly adjusting the charge value. Mainly for the benefit of the power connector/portable SMES system.
/obj/machinery/power/smes/proc/set_charge(charge_set)
charge = charge_set
update_appearance(UPDATE_OVERLAYS)
// called after all power processes are finished
// restores charge level to smes if there was excess this ptick
@@ -353,25 +395,18 @@
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), excess) // for safety, also limit recharge by space capacity of SMES (shouldn't happen)
var/excess = min(output_used, powernet.netexcess) // clamp it to how much was actually output by this SMES last ptick
// now recharge this amount
var/clev = chargedisplay()
adjust_charge(excess) // restore unused power
excess = adjust_charge(excess) // restore unused power
powernet.netexcess -= excess // remove the excess from the powernet, so later SMESes don't try to use it
output_used -= excess
if(clev != chargedisplay() ) //if needed updates the icons overlay
update_appearance()
return
if(clev != chargedisplay()) //if needed updates the icons overlay
update_appearance(UPDATE_OVERLAYS)
/obj/machinery/power/smes/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
@@ -379,41 +414,44 @@
ui = new(user, src, "Smes", name)
ui.open()
/obj/machinery/power/smes/ui_static_data(mob/user)
. = list(
"capacity" = total_capacity,
"inputLevelMax" = input_level_max,
"outputLevelMax" = output_level_max,
)
/obj/machinery/power/smes/ui_data()
var/list/data = list(
"capacity" = capacity,
"capacityPercent" = round(100*charge/capacity, 0.1),
"charge" = charge,
. = list(
"charge" = total_charge(),
"inputAttempt" = input_attempt,
"inputting" = inputting,
"inputLevel" = input_level,
"inputLevel_text" = display_power(input_level, convert = FALSE),
"inputLevelMax" = input_level_max,
"inputAvailable" = energy_to_power(input_available),
"outputAttempt" = output_attempt,
"outputting" = energy_to_power(outputting),
"outputLevel" = output_level,
"outputLevel_text" = display_power(output_level, convert = FALSE),
"outputLevelMax" = output_level_max,
"outputUsed" = energy_to_power(output_used),
"outputting" = outputting,
)
return data
/obj/machinery/power/smes/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
switch(action)
if("tryinput")
input_attempt = !input_attempt
log_smes(usr)
update_appearance()
. = TRUE
log_smes(ui.user)
update_appearance(UPDATE_OVERLAYS)
return TRUE
if("tryoutput")
output_attempt = !output_attempt
log_smes(usr)
update_appearance()
. = TRUE
log_smes(ui.user)
update_appearance(UPDATE_OVERLAYS)
return TRUE
if("input")
var/target = params["target"]
var/adjust = text2num(params["adjust"])
@@ -431,7 +469,9 @@
. = TRUE
if(.)
input_level = clamp(target, 0, input_level_max)
log_smes(usr)
log_smes(ui.user)
return
if("output")
var/target = params["target"]
var/adjust = text2num(params["adjust"])
@@ -449,25 +489,26 @@
. = TRUE
if(.)
output_level = clamp(target, 0, output_level_max)
log_smes(usr)
log_smes(ui.user)
///Logs the current state of this smes
/obj/machinery/power/smes/proc/log_smes(mob/user)
investigate_log("Input/Output: [input_level]/[output_level] | Charge: [charge] | Output-mode: [output_attempt?"ON":"OFF"] | Input-mode: [input_attempt?"AUTO":"OFF"] by [user ? key_name(user) : "outside forces"]", INVESTIGATE_ENGINE)
PRIVATE_PROC(TRUE)
investigate_log("Input/Output: [input_level]/[output_level] | Charge: [total_charge()] | Output-mode: [output_attempt?"ON":"OFF"] | Input-mode: [input_attempt?"AUTO":"OFF"] by [user ? key_name(user) : "outside forces"]", INVESTIGATE_ENGINE)
/obj/machinery/power/smes/emp_act(severity)
. = ..()
if(. & EMP_PROTECT_SELF)
return
input_attempt = rand(0,1)
input_attempt = rand(0, 1)
inputting = input_attempt
output_attempt = rand(0,1)
output_attempt = rand(0, 1)
outputting = output_attempt
output_level = rand(0, output_level_max)
input_level = rand(0, input_level_max)
adjust_charge(-STANDARD_BATTERY_CHARGE/severity)
if (charge < 0)
set_charge(0)
update_appearance()
adjust_charge(-STANDARD_BATTERY_CHARGE / severity)
update_appearance(UPDATE_OVERLAYS)
log_smes()
// Variant of SMES that starts with super power cells for higher longevity
@@ -475,7 +516,6 @@
name = "super capacity power storage unit"
desc = "A super-capacity superconducting magnetic energy storage (SMES) unit. Relatively rare, and typically installed in long-range outposts where minimal maintenance is expected."
circuit = /obj/item/circuitboard/machine/smes/super
capacity = 100 * STANDARD_BATTERY_CHARGE
/obj/machinery/power/smes/super/full
charge = 100 * STANDARD_BATTERY_CHARGE
@@ -494,17 +534,9 @@
name = "magical power storage unit"
desc = "A high-capacity superconducting magnetic energy storage (SMES) unit. Magically produces power."
/obj/machinery/power/smes/magical/process()
capacity = INFINITY
charge = INFINITY
..()
#undef SMES_CLEVEL_1
#undef SMES_CLEVEL_2
#undef SMES_CLEVEL_3
#undef SMES_CLEVEL_4
#undef SMES_CLEVEL_5
#undef SMES_OUTPUTTING
#undef SMES_NOT_OUTPUTTING
#undef SMES_INPUTTING
#undef SMES_INPUT_ATTEMPT
/obj/machinery/power/smes/magical/adjust_charge(charge_adjust)
//give charge without consuming anything
if(charge_adjust < 0)
return abs(charge_adjust)
//no point charging this already infinite smes
return 0
+161 -157
View File
@@ -8,31 +8,13 @@
density = FALSE
input_attempt = FALSE
output_attempt = FALSE
show_display_lights = FALSE
capacity = 1 // solely to avoid div by zero
charge = 0
var/obj/machinery/power/smesbank/connected_smes
///The smes this connector is connected with
var/obj/machinery/smesbank/connected_smes
/obj/machinery/power/smes/connector/RefreshParts()
SHOULD_CALL_PARENT(FALSE)
var/power_coefficient = 0
for(var/datum/stock_part/capacitor/capacitor in component_parts)
power_coefficient += capacitor.tier
input_level_max = initial(input_level_max) * power_coefficient
output_level_max = initial(output_level_max) * power_coefficient
/obj/machinery/power/smes/connector/ui_act(action, params)
// prevent UI interactions if there's no SMES
if(!connected_smes)
balloon_alert(usr, "needs a connected SMES!")
return FALSE
return ..()
/obj/machinery/power/smes/connector/display_ready()
if(!connected_smes)
return FALSE
/obj/machinery/power/smes/connector/Destroy()
connected_smes?.disconnect_port() // in the unlikely but possible case a SMES is connected and this explodes
return ..()
/obj/machinery/power/smes/connector/update_appearance(updates)
@@ -41,20 +23,23 @@
/obj/machinery/power/smes/connector/update_overlays()
. = ..()
if(connected_smes && inputting)
if(!connected_smes)
return
if(inputting)
. += "bp-c"
else
if(connected_smes)
if(charge > 0)
. += "bp-o"
else
. += "bp-d"
connected_smes?.update_appearance(UPDATE_OVERLAYS)
if(total_charge() > 0)
. += "bp-o"
else
. += "bp-d"
/obj/machinery/power/smes/connector/crowbar_act(mob/living/user, obj/item/tool)
if(!connector_free(user))
return ITEM_INTERACT_BLOCKING
return ..()
/obj/machinery/power/smes/connector/RefreshParts()
. = ..()
//happens if the terminal gets rped without a bank attached. No division by zero error
if(!total_capacity)
total_capacity = 1
/obj/machinery/power/smes/connector/wrench_act(mob/living/user, obj/item/tool)
if(!connector_free(user))
@@ -66,119 +51,139 @@
return ITEM_INTERACT_BLOCKING
return ..()
/obj/machinery/power/smes/connector/crowbar_act(mob/living/user, obj/item/tool)
if(!connector_free(user))
return ITEM_INTERACT_BLOCKING
return ..()
/// checks if the connector is free; if not, alerts a user and returns FALSE
/obj/machinery/power/smes/connector/proc/connector_free(mob/living/user)
PRIVATE_PROC(TRUE)
if(connected_smes)
balloon_alert(user, "disconnect SMES first!")
return FALSE
return TRUE
/// connects the actual portable SMES once it's assigned, adjusting charge/maxcharge
/obj/machinery/power/smes/connector/proc/on_connect_smes()
charge = connected_smes.charge
capacity = connected_smes.capacity
update_appearance()
/**
* Connects the power bank to the smes
* Arguments
*
* * obj/machinery/power/smesbank/bank - the bank to connect
*/
/obj/machinery/power/smes/connector/proc/connect_smes(obj/machinery/smesbank/bank)
SHOULD_NOT_OVERRIDE(TRUE)
/// disconnects the portable SMES, resetting internal charge + capacity
/obj/machinery/power/smes/connector/proc/on_disconnect_smes()
input_attempt = FALSE
output_attempt = FALSE
charge = initial(charge)
capacity = initial(capacity)
update_appearance()
connected_smes = bank
if(connected_smes)
total_capacity = 0
for(var/obj/item/stock_parts/power_store/power_cell in connected_smes.component_parts)
component_parts += power_cell
total_capacity += power_cell.max_charge()
else
inputting = FALSE
outputting = FALSE
total_capacity = 1
for(var/obj/item/stock_parts/power_store/power_cell in component_parts)
component_parts -= power_cell
update_appearance(UPDATE_OVERLAYS)
// we really should only be adjusting charge when there's a connected SMES bank.
/obj/machinery/power/smes/connector/adjust_charge(charge_adjust)
. = ..()
connected_smes?.charge += charge_adjust
// same as above - if we have to set charge, affect the connected SMES bank as well
/obj/machinery/power/smes/connector/set_charge(charge_set)
. = ..()
connected_smes?.charge = charge_set
/obj/machinery/power/smes/connector/Destroy()
connected_smes?.disconnect_port() // in the unlikely but possible case a SMES is connected and this explodes
/obj/machinery/power/smes/connector/ui_act(action, params)
// prevent UI interactions if there's no SMES
if(!connected_smes)
balloon_alert(usr, "needs a connected SMES!")
return FALSE
return ..()
/// The actual portable part of the portable SMES system. Pretty useless without an actual connector.
/obj/machinery/power/smesbank
/obj/machinery/smesbank
name = "portable power storage unit"
desc = "A portable, high-capacity superconducting magnetic energy storage (SMES) unit. Requires a separate power connector port to actually interface with power networks."
icon = 'icons/obj/machines/engine/other.dmi'
icon_state = "port_smes"
circuit = /obj/item/circuitboard/machine/smesbank
use_power = NO_POWER_USE // well, technically
density = TRUE
anchored = FALSE
can_change_cable_layer = FALSE // cable layering is handled via connector port
/// The charge capacity.
var/capacity = 50 * STANDARD_BATTERY_CHARGE // The board defaults with 5 high capacity batteries.
/// The current charge.
/// The initial charge of this smes charge.
var/charge = 0
/// The port this is connected to.
var/obj/machinery/power/smes/connector/connected_port
/obj/machinery/power/smesbank/on_construction(mob/user)
/obj/machinery/smesbank/Initialize(mapload)
. = ..()
///Initial connection for mapload
if(mapload)
var/obj/machinery/power/smes/connector/possible_connector = locate(/obj/machinery/power/smes/connector) in loc
if(!possible_connector)
return
if(!connect_port(possible_connector))
return
possible_connector.input_attempt = TRUE
possible_connector.output_attempt = TRUE
///Initial charge
if(charge)
for(var/obj/item/stock_parts/power_store/power_cell in component_parts)
power_cell.use(power_cell.charge())
if(charge)
charge -= power_cell.give(charge)
charge = 0
register_context()
/obj/machinery/smesbank/on_construction(mob/user)
set_anchored(FALSE)
/obj/machinery/power/smesbank/Initialize(mapload)
. = ..()
if(mapload)
mapped_setup()
/obj/machinery/smesbank/add_context(atom/source, list/context, obj/item/held_item, mob/user)
. = NONE
if(isnull(held_item))
return
/obj/machinery/power/smesbank/interact(mob/user)
if(held_item.tool_behaviour == TOOL_WRENCH)
context[SCREENTIP_CONTEXT_LMB] = "[connected_port ? "Disconnect" : "Connect"]"
return CONTEXTUAL_SCREENTIP_SET
if(held_item.tool_behaviour == TOOL_SCREWDRIVER)
context[SCREENTIP_CONTEXT_LMB] = "[panel_open ? "Close" : "Open"] Panel"
return CONTEXTUAL_SCREENTIP_SET
if(held_item.tool_behaviour == TOOL_CROWBAR && panel_open && !connected_port)
context[SCREENTIP_CONTEXT_LMB] = "Deconstruct"
return CONTEXTUAL_SCREENTIP_SET
/obj/machinery/smesbank/examine(user)
. = ..()
. += span_notice("its maintenance panel can be [EXAMINE_HINT("screwed")] [panel_open ? "closed" : "open"].")
if(connected_port)
. += span_notice("You need to [EXAMINE_HINT("unwrench")] from the port before deconstructing.")
else
if(panel_open)
. += span_notice("It can be [EXAMINE_HINT("pried")] apart.")
. += span_notice("It should be [EXAMINE_HINT("wrenched")] onto a connector port to operate.")
/obj/machinery/smesbank/Destroy()
disconnect_port()
return ..()
/obj/machinery/smesbank/update_overlays()
. = ..()
if(panel_open || !is_operational)
return
if(connected_port)
. += "smes-op[connected_port.outputting ? 1 : 0]"
. += "smes-oc[connected_port.inputting ? 1 : 0]"
var/clevel = connected_port.chargedisplay()
if(clevel > 0)
. += "smes-og[clevel]"
/obj/machinery/smesbank/interact(mob/user)
. = ..()
connected_port?.interact(user)
/obj/machinery/power/smesbank/examine(user)
. = ..()
if(!connected_port)
. += span_warning("This SMES has no connector port!")
//opening using screwdriver
/obj/machinery/power/smesbank/screwdriver_act(mob/living/user, obj/item/tool)
. = ITEM_INTERACT_BLOCKING
if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-o", initial(icon_state), tool))
update_appearance()
return ITEM_INTERACT_SUCCESS
/obj/machinery/power/smesbank/RefreshParts()
SHOULD_CALL_PARENT(FALSE)
var/max_charge = 0
var/new_charge = 0
for(var/obj/item/stock_parts/power_store/power_cell in component_parts)
max_charge += power_cell.maxcharge
new_charge += power_cell.charge
capacity = max_charge
if(!initial(charge) && !charge)
charge = new_charge
/obj/machinery/power/smesbank/update_overlays()
. = ..()
if(machine_stat & BROKEN)
return
if(panel_open)
return
. += "smes-op[connected_port?.outputting ? 1 : 0]"
. += "smes-oc[connected_port?.inputting ? 1 : 0]"
var/clevel = chargedisplay()
if(clevel > 0)
. += "smes-og[clevel]"
/obj/machinery/power/smesbank/proc/chargedisplay()
return clamp(round(5.5*charge/capacity),0,5)
/obj/machinery/power/smesbank/default_deconstruction_crowbar(obj/item/crowbar/crowbar)
if(istype(crowbar) && connected_port)
balloon_alert(usr, "disconnect from [connected_port] first!")
return FALSE
return ..()
// adapted from portable atmos connection code
/obj/machinery/power/smesbank/wrench_act(mob/living/user, obj/item/wrench)
/obj/machinery/smesbank/wrench_act(mob/living/user, obj/item/wrench)
if(connected_port)
wrench.play_tool_sound(src)
if(!wrench.use_tool(src, user, 8 SECONDS))
@@ -189,7 +194,7 @@
span_hear("You hear a ratchet."))
investigate_log("was disconnected from [connected_port] by [key_name(user)].", INVESTIGATE_ENGINE)
disconnect_port()
update_appearance()
update_appearance(UPDATE_OVERLAYS)
return ITEM_INTERACT_SUCCESS
var/obj/machinery/power/smes/connector/possible_connector = locate(/obj/machinery/power/smes/connector) in loc
@@ -206,12 +211,31 @@
"[user] connects [src].", \
span_notice("You fasten [src] to [possible_connector]."), \
span_hear("You hear a ratchet."))
update_appearance()
update_appearance(UPDATE_OVERLAYS)
investigate_log("was connected to [possible_connector] by [key_name(user)].", INVESTIGATE_ENGINE)
return ITEM_INTERACT_SUCCESS
/// Attempt to connect the portable SMES to a given connector. Adapted from portable atmos connection code.
/obj/machinery/power/smesbank/proc/connect_port(obj/machinery/power/smes/connector/possible_connector)
/obj/machinery/smesbank/screwdriver_act(mob/living/user, obj/item/tool)
. = ITEM_INTERACT_FAILURE
if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-o", initial(icon_state), tool))
update_appearance(UPDATE_OVERLAYS)
return ITEM_INTERACT_SUCCESS
/obj/machinery/smesbank/default_deconstruction_crowbar(obj/item/crowbar/crowbar)
if(istype(crowbar) && connected_port)
balloon_alert(usr, "disconnect from [connected_port] first!")
return ITEM_INTERACT_FAILURE
return ..()
/**
* Attempt to connect the portable SMES to a given connector. Adapted from portable atmos connection code.
*
* Arguments
* * obj/machinery/power/smes/connector/possible_connector - the connector we are trying to link with
*/
/obj/machinery/smesbank/proc/connect_port(obj/machinery/power/smes/connector/possible_connector)
PRIVATE_PROC(TRUE)
//Make sure not already connected to something else
if(connected_port || !possible_connector || possible_connector.connected_smes || possible_connector.panel_open)
return FALSE
@@ -222,59 +246,39 @@
//Perform the connection
connected_port = possible_connector
connected_port.connected_smes = src
possible_connector.on_connect_smes()
set_anchored(TRUE) //Prevent movement
connected_port.update_appearance()
update_appearance()
connected_port.connect_smes(src)
set_anchored(TRUE)
update_appearance(UPDATE_OVERLAYS)
return TRUE
/// Disconnects the portable SMES from its assigned connector, if it has any. Also adapted from portable atmos connection code.
/obj/machinery/power/smesbank/proc/disconnect_port()
/obj/machinery/smesbank/proc/disconnect_port()
SHOULD_NOT_OVERRIDE(TRUE)
if(!connected_port)
return
connected_port.on_disconnect_smes()
connected_port.connected_smes = null
connected_port.connect_smes(null)
connected_port = null
set_anchored(FALSE)
update_appearance()
update_appearance(UPDATE_OVERLAYS)
/obj/machinery/power/smesbank/Destroy()
disconnect_port()
return ..()
/// Adjusts the charge of the portable SMES. See SMES code.
/obj/machinery/power/smesbank/proc/adjust_charge(charge_adjust)
charge += charge_adjust
/// Sets the charge of the portable SMES. See SMES code.
/obj/machinery/power/smesbank/proc/set_charge(charge_set)
charge = charge_set
/obj/machinery/power/smesbank/emp_act(severity)
/obj/machinery/smesbank/emp_act(severity)
. = ..()
if(. & EMP_PROTECT_SELF)
return
adjust_charge(-STANDARD_BATTERY_CHARGE/severity) // EMP'd banks double-dip on draining if connected. too bad, i guess
if (charge < 0)
set_charge(0)
update_appearance()
/// Attempt to locate, connect to, and activate a portable connector, for pre-mapped portable SMESes.
/obj/machinery/power/smesbank/proc/mapped_setup()
var/obj/machinery/power/smes/connector/possible_connector = locate(/obj/machinery/power/smes/connector) in loc
if(!possible_connector)
return
if(!connect_port(possible_connector))
return
possible_connector.input_attempt = TRUE
possible_connector.output_attempt = TRUE
///Drain the charge
var/charge_adjust = STANDARD_BATTERY_CHARGE / severity
for(var/obj/item/stock_parts/power_store/power_cell in component_parts)
charge_adjust -= power_cell.use(charge_adjust, TRUE)
if(!charge_adjust)
break
/obj/machinery/power/smesbank/super
/obj/machinery/smesbank/super
name = "super capacity power storage unit"
desc = "A portable, super-capacity, superconducting magnetic energy storage (SMES) unit. Relatively rare, and typically installed in long-range outposts where minimal maintenance is expected."
circuit = /obj/item/circuitboard/machine/smesbank/super
capacity = 100 * STANDARD_BATTERY_CHARGE
/obj/machinery/power/smesbank/super/full
/obj/machinery/smesbank/super/full
charge = 100 * STANDARD_BATTERY_CHARGE
@@ -1,24 +1,39 @@
import {
Box,
Button,
Flex,
LabeledList,
ProgressBar,
Section,
Slider,
Stack,
} from 'tgui-core/components';
import { formatPower } from 'tgui-core/format';
import { round } from 'tgui-core/math';
import { useBackend } from '../backend';
import { Window } from '../layouts';
type Data = {
capacity: number;
charge: number;
inputAttempt: number;
inputting: number;
inputLevel: number;
inputLevelMax: number;
inputAvailable: number;
outputAttempt: number;
outputting: number;
outputLevel: number;
outputLevelMax: number;
outputUsed: number;
};
// Common power multiplier
const POWER_MUL = 1e3;
export const Smes = (props) => {
const { act, data } = useBackend();
export const Smes = () => {
const { act, data } = useBackend<Data>();
const {
capacityPercent,
capacity,
charge,
inputAttempt,
@@ -32,6 +47,8 @@ export const Smes = (props) => {
outputLevelMax,
outputUsed,
} = data;
const capacityPercent = round(100 * (charge / capacity), 0.1);
const inputState =
(capacityPercent >= 100 && 'good') || (inputting && 'average') || 'bad';
const outputState =
@@ -70,8 +87,8 @@ export const Smes = (props) => {
</Box>
</LabeledList.Item>
<LabeledList.Item label="Target Input">
<Flex width="100%">
<Flex.Item>
<Stack fill>
<Stack.Item>
<Button
icon="fast-backward"
disabled={inputLevel === 0}
@@ -90,8 +107,8 @@ export const Smes = (props) => {
})
}
/>
</Flex.Item>
<Flex.Item grow={1} mx={1}>
</Stack.Item>
<Stack.Item grow={1} mx={1}>
<Slider
value={inputLevel / POWER_MUL}
fillValue={inputAvailable / POWER_MUL}
@@ -106,8 +123,8 @@ export const Smes = (props) => {
})
}
/>
</Flex.Item>
<Flex.Item>
</Stack.Item>
<Stack.Item>
<Button
icon="forward"
disabled={inputLevel === inputLevelMax}
@@ -126,8 +143,8 @@ export const Smes = (props) => {
})
}
/>
</Flex.Item>
</Flex>
</Stack.Item>
</Stack>
</LabeledList.Item>
<LabeledList.Item label="Available">
{formatPower(inputAvailable)}
@@ -157,8 +174,8 @@ export const Smes = (props) => {
</Box>
</LabeledList.Item>
<LabeledList.Item label="Target Output">
<Flex width="100%">
<Flex.Item>
<Stack fill>
<Stack.Item>
<Button
icon="fast-backward"
disabled={outputLevel === 0}
@@ -177,8 +194,8 @@ export const Smes = (props) => {
})
}
/>
</Flex.Item>
<Flex.Item grow={1} mx={1}>
</Stack.Item>
<Stack.Item grow={1} mx={1}>
<Slider
value={outputLevel / POWER_MUL}
minValue={0}
@@ -192,8 +209,8 @@ export const Smes = (props) => {
})
}
/>
</Flex.Item>
<Flex.Item>
</Stack.Item>
<Stack.Item>
<Button
icon="forward"
disabled={outputLevel === outputLevelMax}
@@ -212,8 +229,8 @@ export const Smes = (props) => {
})
}
/>
</Flex.Item>
</Flex>
</Stack.Item>
</Stack>
</LabeledList.Item>
<LabeledList.Item label="Outputting">
{formatPower(outputUsed)}
@@ -0,0 +1 @@
/obj/machinery/power/smesbank : /obj/machinery/smesbank