From a1bfd1fb4632ea21dc8102f80a331eac6ec629f0 Mon Sep 17 00:00:00 2001 From: Leshana Date: Sun, 18 Feb 2018 21:21:50 -0500 Subject: [PATCH] Make gas turbine constructable and operational * Make gas turbine constructable, as well as modernizing its code. Borrowed some from /tg * Converted the gas turbine control computer to nano ui. --- code/_helpers/unsorted.dm | 10 + .../circuitboards/computer/computer.dm | 1 + code/modules/power/turbine.dm | 470 +++++++++++------- nano/templates/turbine_computer.tmpl | 56 +++ 4 files changed, 346 insertions(+), 191 deletions(-) create mode 100644 nano/templates/turbine_computer.tmpl diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index 3d3877ab5b..cd84d4cf2e 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -509,6 +509,16 @@ Turf and target are seperate in case you want to teleport some distance from a t // mob_list.Add(M) return moblist +// Format a power value in W, kW, MW, or GW. +/proc/DisplayPower(powerused) + if(powerused < 1000) //Less than a kW + return "[powerused] W" + else if(powerused < 1000000) //Less than a MW + return "[round((powerused * 0.001),0.01)] kW" + else if(powerused < 1000000000) //Less than a GW + return "[round((powerused * 0.000001),0.001)] MW" + return "[round((powerused * 0.000000001),0.0001)] GW" + //Forces a variable to be posative /proc/modulus(var/M) if(M >= 0) diff --git a/code/game/objects/items/weapons/circuitboards/computer/computer.dm b/code/game/objects/items/weapons/circuitboards/computer/computer.dm index 2b3631ddbf..71d6e2d867 100644 --- a/code/game/objects/items/weapons/circuitboards/computer/computer.dm +++ b/code/game/objects/items/weapons/circuitboards/computer/computer.dm @@ -100,6 +100,7 @@ /obj/item/weapon/circuitboard/turbine_control name = T_BOARD("turbine control console") build_path = /obj/machinery/computer/turbine_computer + origin_tech = list(TECH_DATA = 2, TECH_POWER = 2) /obj/item/weapon/circuitboard/solar_control name = T_BOARD("solar control console") diff --git a/code/modules/power/turbine.dm b/code/modules/power/turbine.dm index 08abf452f1..30668993a8 100644 --- a/code/modules/power/turbine.dm +++ b/code/modules/power/turbine.dm @@ -1,10 +1,34 @@ +// TURBINE v2 AKA rev4407 Engine reborn! + +// How to use it? - Mappers +// +// This is a very good power generating mechanism. All you need is a blast furnace with soaring flames and output. +// Not everything is included yet so the turbine can run out of fuel quiet quickly. The best thing about the turbine is that even +// though something is on fire that passes through it, it won't be on fire as it passes out of it. So the exhaust fumes can still +// containt unreacted fuel - plasma and oxygen that needs to be filtered out and re-routed back. This of course requires smart piping +// For a computer to work with the turbine the compressor requires a comp_id matching with the turbine computer's id. This will be +// subjected to a change in the near future mind you. Right now this method of generating power is a good backup but don't expect it +// become a main power source unless some work is done. Have fun. At 50k RPM it generates 60k power. So more than one turbine is needed! +// +// - Numbers +// +// Example setup S - sparker +// B - Blast doors into space for venting +// *BBB****BBB* C - Compressor +// S CT * T - Turbine +// * ^ * * V * D - Doors with firedoor +// **|***D**|** ^ - Fuel feed (Not vent, but a gas outlet) +// | | V - Suction vent (Like the ones in atmos +// + /obj/machinery/compressor name = "compressor" desc = "The compressor stage of a gas turbine generator." icon = 'icons/obj/pipes.dmi' icon_state = "compressor" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE + circuit = /obj/item/weapon/circuitboard/machine/power_compressor var/obj/machinery/power/turbine/turbine var/datum/gas_mixture/gas_contained var/turf/simulated/inturf @@ -13,69 +37,132 @@ var/rpmtarget = 0 var/capacity = 1e6 var/comp_id = 0 + var/efficiency /obj/machinery/power/turbine name = "gas turbine generator" desc = "A gas turbine used for backup power generation." icon = 'icons/obj/pipes.dmi' icon_state = "turbine" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE + circuit = /obj/item/weapon/circuitboard/machine/power_turbine var/obj/machinery/compressor/compressor var/turf/simulated/outturf var/lastgen + var/productivity = 1 /obj/machinery/computer/turbine_computer - name = "Gas turbine control computer" - desc = "A computer to remotely control a gas turbine" + name = "gas turbine control computer" + desc = "A computer to remotely control a gas turbine." icon_keyboard = "tech_key" icon_screen = "turbinecomp" circuit = /obj/item/weapon/circuitboard/turbine_control - anchored = 1 - density = 1 var/obj/machinery/compressor/compressor var/list/obj/machinery/door/blast/doors var/id = 0 var/door_status = 0 +/obj/item/weapon/circuitboard/machine/power_compressor + name = T_BOARD("power compressor") + build_path = /obj/machinery/compressor + board_type = new /datum/frame/frame_types/machine + origin_tech = list(TECH_MATERIAL = 4, TECH_POWER = 2) + req_components = list(/obj/item/stack/cable_coil = 5, /obj/item/weapon/stock_parts/manipulator = 6) + +/obj/item/weapon/circuitboard/machine/power_turbine + name = T_BOARD("power turbine") + build_path = /obj/machinery/power/turbine + board_type = new /datum/frame/frame_types/machine + origin_tech = list(TECH_ENGINEERING = 2, TECH_POWER = 4) + req_components = list(/obj/item/stack/cable_coil = 5, /obj/item/weapon/stock_parts/capacitor = 6) + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Compressor // the inlet stage of the gas turbine electricity generator - -/obj/machinery/compressor/New() - ..() - - gas_contained = new - inturf = get_step(src, dir) - - spawn(5) - turbine = locate() in get_step(src, get_dir(inturf, src)) - if(!turbine) - stat |= BROKEN - else - turbine.stat &= !BROKEN - turbine.compressor = src - +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define COMPFRICTION 5e5 #define COMPSTARTERLOAD 2800 +/obj/machinery/compressor/initialize() + . = ..() + default_apply_parts() + gas_contained = new() + inturf = get_step(src, dir) + locate_machinery() + if(!turbine) + stat |= BROKEN + +// When anchored, don't let air past us. +/obj/machinery/compressor/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0) + if(!height || air_group) + return !anchored + return !density + +/obj/machinery/compressor/proc/locate_machinery() + if(turbine) + return + turbine = locate() in get_step(src, get_dir(inturf, src)) + if(turbine) + turbine.locate_machinery() + +/obj/machinery/compressor/RefreshParts() + var/E = 0 + for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) + E += M.rating + efficiency = E / 6 + +/obj/machinery/compressor/attackby(obj/item/W, mob/user) + src.add_fingerprint(user) + + if(default_deconstruction_screwdriver(user, W)) + return + if(default_part_replacement(user, W)) + return + if(default_unfasten_wrench(user, W)) + return + if(default_deconstruction_crowbar(user, W)) + return + if(ismultitool(W)) + var/new_ident = input("Enter a new ident tag.", name, comp_id) as null|text + if(new_ident && user.Adjacent(src)) + comp_id = new_ident + return + return ..() + +/obj/machinery/compressor/default_unfasten_wrench(var/mob/user, var/obj/item/weapon/wrench/W, var/time = 20) + if((. = ..())) + turbine = null + if(anchored) + inturf = get_step(src, dir) + locate_machinery() + if(turbine) + to_chat(user, "Turbine connected.") + stat &= ~BROKEN + else + to_chat(user, "Turbine not connected.") + stat |= BROKEN + /obj/machinery/compressor/process() + if(!turbine) + stat = BROKEN + if(stat & BROKEN || panel_open) + return if(!starter) return overlays.Cut() - if(stat & BROKEN) - return - if(!turbine) - stat |= BROKEN - return + rpm = 0.9* rpm + 0.1 * rpmtarget var/datum/gas_mixture/environment = inturf.return_air() + + // It's a simplified version taking only 1/10 of the moles from the turf nearby. It should be later changed into a better version var/transfer_moles = environment.total_moles / 10 - //var/transfer_moles = rpm/10000*capacity var/datum/gas_mixture/removed = inturf.remove_air(transfer_moles) gas_contained.merge(removed) - rpm = max(0, rpm - (rpm*rpm)/COMPFRICTION) - + // RPM function to include compression friction - be advised that too low/high of a compfriction value can make things screwy + rpm = max(0, rpm - (rpm*rpm)/(COMPFRICTION*efficiency)) if(starter && !(stat & NOPOWER)) use_power(2800) @@ -85,8 +172,6 @@ if(rpm<1000) rpmtarget = 0 - - if(rpm>50000) overlays += image('icons/obj/pipes.dmi', "comp-o4", FLY_LAYER) else if(rpm>10000) @@ -97,38 +182,84 @@ overlays += image('icons/obj/pipes.dmi', "comp-o1", FLY_LAYER) //TODO: DEFERRED -/obj/machinery/power/turbine/New() - ..() - outturf = get_step(src, dir) - - spawn(5) - - compressor = locate() in get_step(src, get_dir(outturf, src)) - if(!compressor) - stat |= BROKEN - else - compressor.stat &= !BROKEN - compressor.turbine = src +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Turbine +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// These are crucial to working of a turbine - the stats modify the power output. TurbGenQ modifies how much raw energy can you get from +// rpms, TurbGenG modifies the shape of the curve - the lower the value the less straight the curve is. #define TURBPRES 9000000 -#define TURBGENQ 20000 +#define TURBGENQ 100000 #define TURBGENG 0.8 +/obj/machinery/power/turbine/initialize() + . = ..() + default_apply_parts() + // The outlet is pointed at the direction of the turbine component + outturf = get_step(src, dir) + locate_machinery() + if(!compressor) + stat |= BROKEN + +/obj/machinery/power/turbine/RefreshParts() + var/P = 0 + for(var/obj/item/weapon/stock_parts/capacitor/C in component_parts) + P += C.rating + productivity = P / 6 + +/obj/machinery/power/turbine/proc/locate_machinery() + if(compressor) + return + compressor = locate() in get_step(src, get_dir(outturf, src)) + if(compressor) + compressor.locate_machinery() + +/obj/machinery/power/turbine/attackby(obj/item/W, mob/user) + src.add_fingerprint(user) + + if(default_deconstruction_screwdriver(user, W)) + return + if(default_part_replacement(user, W)) + return + if(default_unfasten_wrench(user, W)) + return + if(default_deconstruction_crowbar(user, W)) + return + return ..() + +/obj/machinery/power/turbine/default_unfasten_wrench(var/mob/user, var/obj/item/weapon/wrench/W, var/time = 20) + if((. = ..())) + compressor = null + if(anchored) + outturf = get_step(src, dir) + locate_machinery() + if(compressor) + to_chat(user, "Compressor connected.") + stat &= ~BROKEN + else + to_chat(user, "Compressor not connected.") + stat |= BROKEN + /obj/machinery/power/turbine/process() + if(!compressor) + stat = BROKEN + if((stat & BROKEN) || panel_open) + return if(!compressor.starter) return overlays.Cut() - if(stat & BROKEN) - return - if(!compressor) - stat |= BROKEN - return - lastgen = ((compressor.rpm / TURBGENQ)**TURBGENG) *TURBGENQ + + // This is the power generation function. If anything is needed it's good to plot it in EXCEL before modifying + // the TURBGENQ and TURBGENG values + lastgen = ((compressor.rpm / TURBGENQ)**TURBGENG) * TURBGENQ * productivity add_avail(lastgen) + + // Weird function but it works. Should be something else... var/newrpm = ((compressor.gas_contained.temperature) * compressor.gas_contained.total_moles)/4 + newrpm = max(0, newrpm) if(!compressor.starter || newrpm > 1000) @@ -139,181 +270,138 @@ var/datum/gas_mixture/removed = compressor.gas_contained.remove(oamount) outturf.assume_air(removed) + // If it works, put an overlay that it works! if(lastgen > 100) overlays += image('icons/obj/pipes.dmi', "turb-o", FLY_LAYER) + updateDialog() - for(var/mob/M in viewers(1, src)) - if ((M.client && M.machine == src)) - src.interact(M) - AutoUpdateAI(src) +/obj/machinery/power/turbine/attack_hand(var/mob/user as mob) + if((. = ..())) + return + src.interact(user) /obj/machinery/power/turbine/interact(mob/user) - - if ( (get_dist(src, user) > 1 ) || (stat & (NOPOWER|BROKEN)) && (!istype(user, /mob/living/silicon/ai)) ) - user.machine = null + if(!Adjacent(user) || (stat & (NOPOWER|BROKEN)) && !issilicon(user)) + user.unset_machine(src) user << browse(null, "window=turbine") return - - user.machine = src + user.set_machine(src) var/t = "Gas Turbine Generator
"
-
-	t += "Generated power : [round(lastgen)] W

" - + t += "Generated power : [DisplayPower(lastgen)]

" t += "Turbine: [round(compressor.rpm)] RPM
" - t += "Starter: [ compressor.starter ? "Off On" : "Off On"]" - t += "

Close" - t += "
" - user << browse(t, "window=turbine") - onclose(user, "turbine") + var/datum/browser/popup = new(user, "turbine", name, 700, 500, src) + popup.set_content(t) + popup.open() return /obj/machinery/power/turbine/Topic(href, href_list) - ..() - if(stat & BROKEN) + if(..()) return - if (usr.stat || usr.restrained() ) - return - if (!(istype(usr, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") - if(!istype(usr, /mob/living/silicon/ai)) - usr << "You don't have the dexterity to do this!" - return - if (( usr.machine==src && ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon/ai))) - - - if( href_list["close"] ) - usr << browse(null, "window=turbine") - usr.machine = null - return - - else if( href_list["str"] ) - compressor.starter = !compressor.starter - - spawn(0) - for(var/mob/M in viewers(1, src)) - if ((M.client && M.machine == src)) - src.interact(M) - - else + if(href_list["close"]) usr << browse(null, "window=turbine") - usr.machine = null - - return - - - + usr.unset_machine(src) + return + else if(href_list["str"]) + if(compressor) + compressor.starter = !compressor.starter + updateDialog() ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Turbine Computer ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/obj/machinery/computer/turbine_computer/initialize() + . = ..() + return INITIALIZE_HINT_LATELOAD +/obj/machinery/computer/turbine_computer/LateInitialize() + locate_machinery() -/obj/machinery/computer/turbine_computer/New() - ..() - spawn(5) - for(var/obj/machinery/compressor/C in machines) - if(id == C.comp_id) - compressor = C - doors = new /list() - for(var/obj/machinery/door/blast/P in machines) - if(P.id == id) - doors += P +/obj/machinery/computer/turbine_computer/proc/locate_machinery() + if(!id) + return + for(var/obj/machinery/compressor/C in machines) + if(C.comp_id == id) + compressor = C + LAZYINITLIST(doors) + for(var/obj/machinery/door/blast/P in machines) + if(P.id == id) + doors += P -/* -/obj/machinery/computer/turbine_computer/attackby(I as obj, user as mob) - if(istype(I, /obj/item/weapon/screwdriver)) - playsound(src.loc, I.usesound, 50, 1) - if(do_after(user, 20)) - if (src.stat & BROKEN) - user << "The broken glass falls out." - var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc ) - new /obj/item/weapon/material/shard( src.loc ) - var/obj/item/weapon/circuitboard/turbine_control/M = new /obj/item/weapon/circuitboard/turbine_control( A ) - for (var/obj/C in src) - C.loc = src.loc - M.id = src.id - A.circuit = M - A.state = 3 - A.icon_state = "3" - A.anchored = 1 - qdel(src) - else - user << "You disconnect the monitor." - var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc ) - var/obj/item/weapon/circuitboard/turbine_control/M = new /obj/item/weapon/circuitboard/turbine_control( A ) - for (var/obj/C in src) - C.loc = src.loc - M.id = src.id - A.circuit = M - A.state = 4 - A.icon_state = "4" - A.anchored = 1 - qdel(src) - else - src.attack_hand(user) - return -*/ +/obj/machinery/computer/turbine_computer/attackby(obj/item/W, mob/user) + if(ismultitool(W)) + var/new_ident = input("Enter a new ident tag.", name, id) as null|text + if(new_ident && user.Adjacent(src)) + id = new_ident + return /obj/machinery/computer/turbine_computer/attack_hand(var/mob/user as mob) - user.machine = src - var/dat - if(src.compressor) - dat += {"
Gas turbine remote control system
- \nTurbine status: [ src.compressor.starter ? "Off On" : "Off On"] - \n
- \nTurbine speed: [src.compressor.rpm]rpm
- \nPower currently being generated: [src.compressor.turbine.lastgen]W
- \nInternal gas temperature: [src.compressor.gas_contained.temperature]K
- \nVent doors: [ src.door_status ? "Closed Open" : "Closed Open"] - \n
View - \n
Close - \n
- \n"} - else - dat += "No compatible attached compressor found." + if((. = ..())) + return + src.interact(user) - user << browse(dat, "window=computer;size=400x500") - onclose(user, "computer") - return +/obj/machinery/computer/turbine_computer/interact(mob/user) + return ui_interact(user) +/obj/machinery/computer/turbine_computer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/list/data = list() + data["connected"] = (compressor && compressor.turbine) ? TRUE : FALSE + data["compressor_broke"] = (!compressor || (compressor.stat & BROKEN)) ? TRUE : FALSE + data["turbine_broke"] = (!compressor || !compressor.turbine || (compressor.turbine.stat & BROKEN)) ? TRUE : FALSE + data["broken"] = (data["compressor_broke"] || data["turbine_broke"]) + data["door_status"] = door_status ? TRUE : FALSE + if(compressor && compressor.turbine) + data["online"] = compressor.starter + data["power"] = DisplayPower(compressor.turbine.lastgen) + data["rpm"] = compressor.rpm + data["temp"] = compressor.gas_contained.temperature + // update the ui if it exists, returns null if no ui is passed/found + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "turbine_computer.tmpl", name, 520, 440) + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + // open the new ui window + ui.open() + // auto update every Master Controller tick + ui.set_auto_update(TRUE) /obj/machinery/computer/turbine_computer/Topic(href, href_list) if(..()) return - if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) - usr.machine = src + if(href_list["power-on"]) + if(compressor && compressor.turbine) + compressor.starter = TRUE + . = TRUE + else if(href_list["power-off"]) + if(compressor && compressor.turbine) + compressor.starter = FALSE + . = TRUE + else if(href_list["reconnect"]) + locate_machinery() + . = TRUE + else if(href_list["doors"]) + door_status = !door_status + for(var/obj/machinery/door/blast/D in src.doors) + if (door_status) + spawn(0) D.close() + else + spawn(0)D.open() + . = TRUE - if( href_list["view"] ) - usr.client.eye = src.compressor - else if( href_list["str"] ) - src.compressor.starter = !src.compressor.starter - else if (href_list["doors"]) - for(var/obj/machinery/door/blast/D in src.doors) - if (door_status == 0) - spawn( 0 ) - D.open() - door_status = 1 - else - spawn( 0 ) - D.close() - door_status = 0 - else if( href_list["close"] ) - usr << browse(null, "window=computer") - usr.machine = null - return - - src.add_fingerprint(usr) - src.updateUsrDialog() - return - -/obj/machinery/computer/turbine_computer/process() - src.updateDialog() - return \ No newline at end of file +#undef COMPFRICTION +#undef COMPSTARTERLOAD +#undef TURBPRES +#undef TURBGENQ +#undef TURBGENG diff --git a/nano/templates/turbine_computer.tmpl b/nano/templates/turbine_computer.tmpl new file mode 100644 index 0000000000..a1bc50f2bd --- /dev/null +++ b/nano/templates/turbine_computer.tmpl @@ -0,0 +1,56 @@ + +

Turbine Controller

+
+
Status
+
+ {{if data.broken}} + Broken + {{:helper.link('Reconnect', 'refresh', {'reconnect' : 1})}} + {{else}} + + {{:data.online && !(data.compressor_broke || data.turbine_broke) ? "Online" : "Offline"}} + + {{/if}} +
+
+
+
Compressor
+
+ {{if data.compressor_broke}} +
+ [ Compressor is inoperable ] + {{/if}} + {{if data.turbine_broke}} +
+ [ Turbine is inoperable ] + {{/if}} + {{if (!data.broken)}} + {{:helper.link('On', 'power', {'power-on' : 1}, data.online ? 'selected' : null)}} + {{:helper.link('Off', 'close', {'power-off' : 1}, data.online ? null : 'selected')}} + {{/if}} +
+
+ +

Readout

+
+
Turbine Speed
+
{{:data.broken ? "--" : data.rpm}} RPM
+
+
+
Internal Temperature
+
{{:data.broken ? "--" : data.temp}} K
+
+
+
Generated Power
+
{{:data.broken ? "--" : data.power}}
+
+
+
Vent doors
+
+ {{:helper.link('Closed', 'locked', {'doors' : 1}, data.door_status ? 'selected' : null)}} + {{:helper.link('Open', 'unlocked', {'doors' : 1}, data.door_status ? null : 'selected')}} +
+