65e9888fa6
Cables now autoconnect on cardinal directions. All cable placement has been completely stripped out and replaced with simple single cable per tile logic. Low effort demo: https://www.youtube.com/watch?v=fXp8s6ORWbA Yes I am aware that cutting it is not dropping wire, that version was bugged. Cables no longer need a knot specifically placed to link to power objects. The sprite is automatically changed to represent this. The only exception to this logic is that on smes units, due to the terminal being next to the output, they will not link there. On a technical powernet side, this is the same as old cables once actually placed. They still use the existing powernet system, just the placement and connection works differently. Old cables have been turned into "pipe cleaners" for wire art purposes. they work just like the old ones, just missing all the powernet functionality, and also you can put them on top of the floor. Why It's Good For The Game How obnoxious cables were to both map and work with in game has been something that has annoyed me for a really long time now. This is both easier for new players to learn, and easier for experienced players to work with. Along with making in game much more intuitive and easier, it makes mapping much easier as well. Mad lad wjohn was able to rip out all the mapping conversion in one day because of how much faster it is to work with. cl actioninja and wjohn add: Cables have been completely reworked. Simple per tile connection logic, automatically connects to things above it. Think minecraft redstone. add: Old cables have been kept as pipe cleaner. They are non-functional in terms of power, but otherwise have the same connection logic. Also can go on top of tiles. remove: mech cable layer has been removed because it was terrible shitcode nobody used tweak: (sort of balance) cable stack sized has been reduced to 15. /cl
451 lines
13 KiB
Plaintext
451 lines
13 KiB
Plaintext
// the SMES
|
|
// stores power
|
|
|
|
#define SMESRATE 0.05 // rate of internal charge to external 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."
|
|
icon_state = "smes"
|
|
density = TRUE
|
|
use_power = NO_POWER_USE
|
|
circuit = /obj/item/circuitboard/machine/smes
|
|
var/capacity = 5e6 // maximum charge
|
|
var/charge = 0 // actual charge
|
|
|
|
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 = 50000 // amount of power the SMES attempts to charge by
|
|
var/input_level_max = 200000 // cap on input_level
|
|
var/input_available = 0 // amount of charge available from input last tick
|
|
|
|
var/output_attempt = TRUE // TRUE = attempting to output, FALSE = not attempting to output
|
|
var/outputting = TRUE // TRUE = actually outputting, FALSE = 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
|
|
|
|
var/obj/machinery/power/terminal/terminal = null
|
|
|
|
/obj/machinery/power/smes/examine(user)
|
|
. = ..()
|
|
if(!terminal)
|
|
. += "<span class='warning'>This SMES has no power terminal!</span>"
|
|
|
|
/obj/machinery/power/smes/Initialize()
|
|
. = ..()
|
|
dir_loop:
|
|
for(var/d in GLOB.cardinals)
|
|
var/turf/T = get_step(src, d)
|
|
for(var/obj/machinery/power/terminal/term in T)
|
|
if(term && term.dir == turn(d, 180))
|
|
terminal = term
|
|
break dir_loop
|
|
|
|
if(!terminal)
|
|
stat |= BROKEN
|
|
return
|
|
terminal.master = src
|
|
update_icon()
|
|
|
|
/obj/machinery/power/smes/RefreshParts()
|
|
var/IO = 0
|
|
var/MC = 0
|
|
var/C
|
|
for(var/obj/item/stock_parts/capacitor/CP in component_parts)
|
|
IO += CP.rating
|
|
input_level_max = initial(input_level_max) * IO
|
|
output_level_max = initial(output_level_max) * IO
|
|
for(var/obj/item/stock_parts/cell/PC in component_parts)
|
|
MC += PC.maxcharge
|
|
C += PC.charge
|
|
capacity = MC / (15000) * 1e6
|
|
if(!initial(charge) && !charge)
|
|
charge = C / 15000 * 1e6
|
|
|
|
/obj/machinery/power/smes/should_have_node()
|
|
return TRUE
|
|
|
|
/obj/machinery/power/smes/attackby(obj/item/I, mob/user, params)
|
|
//opening using screwdriver
|
|
if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-o", initial(icon_state), I))
|
|
update_icon()
|
|
return
|
|
|
|
//changing direction using wrench
|
|
if(default_change_direction_wrench(user, I))
|
|
terminal = null
|
|
var/turf/T = get_step(src, dir)
|
|
for(var/obj/machinery/power/terminal/term in T)
|
|
if(term && term.dir == turn(dir, 180))
|
|
terminal = term
|
|
terminal.master = src
|
|
to_chat(user, "<span class='notice'>Terminal found.</span>")
|
|
break
|
|
if(!terminal)
|
|
to_chat(user, "<span class='alert'>No power terminal found.</span>")
|
|
return
|
|
stat &= ~BROKEN
|
|
update_icon()
|
|
return
|
|
|
|
//building and linking a terminal
|
|
if(istype(I, /obj/item/stack/cable_coil))
|
|
var/dir = get_dir(user,src)
|
|
if(dir & (dir-1))//we don't want diagonal click
|
|
return
|
|
|
|
if(terminal) //is there already a terminal ?
|
|
to_chat(user, "<span class='warning'>This SMES already has a power terminal!</span>")
|
|
return
|
|
|
|
if(!panel_open) //is the panel open ?
|
|
to_chat(user, "<span class='warning'>You must open the maintenance panel first!</span>")
|
|
return
|
|
|
|
var/turf/T = get_turf(user)
|
|
if (T.intact) //is the floor plating removed ?
|
|
to_chat(user, "<span class='warning'>You must first remove the floor plating!</span>")
|
|
return
|
|
|
|
|
|
var/obj/item/stack/cable_coil/C = I
|
|
if(C.get_amount() < 10)
|
|
to_chat(user, "<span class='warning'>You need more wires!</span>")
|
|
return
|
|
|
|
to_chat(user, "<span class='notice'>You start building the power terminal...</span>")
|
|
playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
|
|
|
|
if(do_after(user, 20, target = src))
|
|
if(C.get_amount() < 10 || !C)
|
|
return
|
|
var/obj/structure/cable/N = T.get_cable_node() //get the connecting node cable, if there's one
|
|
if (prob(50) && electrocute_mob(usr, N, N, 1, TRUE)) //animate the electrocution if uncautious and unlucky
|
|
do_sparks(5, TRUE, src)
|
|
return
|
|
if(!terminal)
|
|
C.use(10)
|
|
user.visible_message(\
|
|
"[user.name] has built a power terminal.",\
|
|
"<span class='notice'>You build the power terminal.</span>")
|
|
|
|
//build the terminal and link it to the network
|
|
make_terminal(T)
|
|
terminal.connect_to_network()
|
|
connect_to_network()
|
|
return
|
|
|
|
//crowbarring it !
|
|
var/turf/T = get_turf(src)
|
|
if(default_deconstruction_crowbar(I))
|
|
message_admins("[src] has been deconstructed by [ADMIN_LOOKUPFLW(user)] in [ADMIN_VERBOSEJMP(T)]")
|
|
log_game("[src] has been deconstructed by [key_name(user)] at [AREACOORD(src)]")
|
|
investigate_log("SMES deconstructed by [key_name(user)] at [AREACOORD(src)]", INVESTIGATE_SINGULO)
|
|
return
|
|
else if(panel_open && I.tool_behaviour == TOOL_CROWBAR)
|
|
return
|
|
|
|
return ..()
|
|
|
|
/obj/machinery/power/smes/wirecutter_act(mob/living/user, obj/item/I)
|
|
//disassembling the terminal
|
|
if(terminal && panel_open)
|
|
terminal.dismantle(user, I)
|
|
return TRUE
|
|
|
|
|
|
/obj/machinery/power/smes/default_deconstruction_crowbar(obj/item/crowbar/C)
|
|
if(istype(C) && terminal)
|
|
to_chat(usr, "<span class='warning'>You must first remove the power terminal!</span>")
|
|
return FALSE
|
|
|
|
return ..()
|
|
|
|
/obj/machinery/power/smes/on_deconstruction()
|
|
for(var/obj/item/stock_parts/cell/cell in component_parts)
|
|
cell.charge = (charge / capacity) * cell.maxcharge
|
|
|
|
/obj/machinery/power/smes/Destroy()
|
|
if(SSticker.IsRoundInProgress())
|
|
var/turf/T = get_turf(src)
|
|
message_admins("SMES deleted at [ADMIN_VERBOSEJMP(T)]")
|
|
log_game("SMES deleted at [AREACOORD(T)]")
|
|
investigate_log("<font color='red'>deleted</font> at [AREACOORD(T)]", INVESTIGATE_SINGULO)
|
|
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/T)
|
|
terminal = new/obj/machinery/power/terminal(T)
|
|
terminal.setDir(get_dir(T,src))
|
|
terminal.master = src
|
|
stat &= ~BROKEN
|
|
|
|
/obj/machinery/power/smes/disconnect_terminal()
|
|
if(terminal)
|
|
terminal.master = null
|
|
terminal = null
|
|
stat |= BROKEN
|
|
|
|
|
|
/obj/machinery/power/smes/update_icon()
|
|
cut_overlays()
|
|
if(stat & BROKEN)
|
|
return
|
|
|
|
if(panel_open)
|
|
return
|
|
|
|
if(outputting)
|
|
add_overlay("smes-op1")
|
|
else
|
|
add_overlay("smes-op0")
|
|
|
|
if(inputting)
|
|
add_overlay("smes-oc1")
|
|
else
|
|
if(input_attempt)
|
|
add_overlay("smes-oc0")
|
|
|
|
var/clevel = chargedisplay()
|
|
if(clevel>0)
|
|
add_overlay("smes-og[clevel]")
|
|
|
|
|
|
/obj/machinery/power/smes/proc/chargedisplay()
|
|
return CLAMP(round(5.5*charge/capacity),0,5)
|
|
|
|
/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(terminal && input_attempt)
|
|
input_available = terminal.surplus()
|
|
|
|
if(inputting)
|
|
if(input_available > 0) // if there's power available, try to charge
|
|
|
|
var/load = min(min((capacity-charge)/SMESRATE, input_level), input_available) // charge at set rate, limited to spare capacity
|
|
|
|
charge += load * SMESRATE // increase the charge
|
|
|
|
terminal.add_load(load) // add the load to the terminal side network
|
|
|
|
else // if not enough capcity
|
|
inputting = FALSE // stop inputting
|
|
|
|
else
|
|
if(input_attempt && input_available > 0)
|
|
inputting = TRUE
|
|
else
|
|
inputting = FALSE
|
|
|
|
//outputting
|
|
if(output_attempt)
|
|
if(outputting)
|
|
output_used = min( charge/SMESRATE, output_level) //limit output to that stored
|
|
|
|
if (add_avail(output_used)) // add output to powernet if it exists (smes side)
|
|
charge -= output_used*SMESRATE // reduce the storage (may be recovered in /restore() if excessive)
|
|
else
|
|
outputting = FALSE
|
|
|
|
if(output_used < 0.0001) // either from no charge or set to 0
|
|
outputting = FALSE
|
|
investigate_log("lost power and turned <font color='red'>off</font>", INVESTIGATE_SINGULO)
|
|
else if(output_attempt && charge > output_level && output_level > 0)
|
|
outputting = TRUE
|
|
else
|
|
output_used = 0
|
|
else
|
|
outputting = FALSE
|
|
|
|
// only update icon if state changed
|
|
if(last_disp != chargedisplay() || last_chrg != inputting || last_onln != outputting)
|
|
update_icon()
|
|
|
|
|
|
|
|
// called after all power processes are finished
|
|
// restores charge level to smes if there was excess this ptick
|
|
/obj/machinery/power/smes/proc/restore()
|
|
if(stat & BROKEN)
|
|
return
|
|
|
|
if(!outputting)
|
|
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)
|
|
|
|
// 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
|
|
|
|
output_used -= excess
|
|
|
|
if(clev != chargedisplay() ) //if needed updates the icons overlay
|
|
update_icon()
|
|
return
|
|
|
|
|
|
/obj/machinery/power/smes/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
|
|
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
|
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
|
if(!ui)
|
|
ui = new(user, src, ui_key, "smes", name, 340, 440, master_ui, state)
|
|
ui.open()
|
|
|
|
/obj/machinery/power/smes/ui_data()
|
|
var/list/data = list(
|
|
"capacityPercent" = round(100*charge/capacity, 0.1),
|
|
"capacity" = capacity,
|
|
"charge" = charge,
|
|
|
|
"inputAttempt" = input_attempt,
|
|
"inputting" = inputting,
|
|
"inputLevel" = input_level,
|
|
"inputLevel_text" = DisplayPower(input_level),
|
|
"inputLevelMax" = input_level_max,
|
|
"inputAvailable" = DisplayPower(input_available),
|
|
|
|
"outputAttempt" = output_attempt,
|
|
"outputting" = outputting,
|
|
"outputLevel" = output_level,
|
|
"outputLevel_text" = DisplayPower(output_level),
|
|
"outputLevelMax" = output_level_max,
|
|
"outputUsed" = DisplayPower(output_used)
|
|
)
|
|
return data
|
|
|
|
/obj/machinery/power/smes/ui_act(action, params)
|
|
if(..())
|
|
return
|
|
switch(action)
|
|
if("tryinput")
|
|
input_attempt = !input_attempt
|
|
log_smes(usr)
|
|
update_icon()
|
|
. = TRUE
|
|
if("tryoutput")
|
|
output_attempt = !output_attempt
|
|
log_smes(usr)
|
|
update_icon()
|
|
. = TRUE
|
|
if("input")
|
|
var/target = params["target"]
|
|
var/adjust = text2num(params["adjust"])
|
|
if(target == "input")
|
|
target = input("New input target (0-[input_level_max]):", name, input_level) as num|null
|
|
if(!isnull(target) && !..())
|
|
. = TRUE
|
|
else if(target == "min")
|
|
target = 0
|
|
. = TRUE
|
|
else if(target == "max")
|
|
target = input_level_max
|
|
. = TRUE
|
|
else if(adjust)
|
|
target = input_level + adjust
|
|
. = TRUE
|
|
else if(text2num(target) != null)
|
|
target = text2num(target)
|
|
. = TRUE
|
|
if(.)
|
|
input_level = CLAMP(target, 0, input_level_max)
|
|
log_smes(usr)
|
|
if("output")
|
|
var/target = params["target"]
|
|
var/adjust = text2num(params["adjust"])
|
|
if(target == "input")
|
|
target = input("New output target (0-[output_level_max]):", name, output_level) as num|null
|
|
if(!isnull(target) && !..())
|
|
. = TRUE
|
|
else if(target == "min")
|
|
target = 0
|
|
. = TRUE
|
|
else if(target == "max")
|
|
target = output_level_max
|
|
. = TRUE
|
|
else if(adjust)
|
|
target = output_level + adjust
|
|
. = TRUE
|
|
else if(text2num(target) != null)
|
|
target = text2num(target)
|
|
. = TRUE
|
|
if(.)
|
|
output_level = CLAMP(target, 0, output_level_max)
|
|
log_smes(usr)
|
|
|
|
/obj/machinery/power/smes/proc/log_smes(mob/user)
|
|
investigate_log("input/output; [input_level>output_level?"<font color='green'>":"<font color='red'>"][input_level]/[output_level]</font> | Charge: [charge] | 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 [user ? key_name(user) : "outside forces"]", INVESTIGATE_SINGULO)
|
|
|
|
|
|
/obj/machinery/power/smes/emp_act(severity)
|
|
. = ..()
|
|
if(. & EMP_PROTECT_SELF)
|
|
return
|
|
input_attempt = rand(0,1)
|
|
inputting = input_attempt
|
|
output_attempt = rand(0,1)
|
|
outputting = output_attempt
|
|
output_level = rand(0, output_level_max)
|
|
input_level = rand(0, input_level_max)
|
|
charge -= 1e6/severity
|
|
if (charge < 0)
|
|
charge = 0
|
|
update_icon()
|
|
log_smes()
|
|
|
|
/obj/machinery/power/smes/engineering
|
|
charge = 1.5e6 // Engineering starts with some charge for singulo
|
|
|
|
/obj/machinery/power/smes/magical
|
|
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 SMESRATE
|
|
|
|
#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
|