diff --git a/_maps/RandomRuins/SandRuins/whitesands_surface_waterplant.dmm b/_maps/RandomRuins/SandRuins/whitesands_surface_waterplant.dmm
index 0babadd59a8d..fe95fca0e82b 100644
--- a/_maps/RandomRuins/SandRuins/whitesands_surface_waterplant.dmm
+++ b/_maps/RandomRuins/SandRuins/whitesands_surface_waterplant.dmm
@@ -1482,7 +1482,7 @@
/turf/open/floor/plating,
/area/ruin/powered)
"LM" = (
-/obj/machinery/power/turbine,
+/obj/machinery/power/shuttle/engine/turbine,
/turf/open/floor/plating/asteroid/whitesands,
/area/overmap_encounter/planetoid/sand/explored)
"LN" = (
diff --git a/code/game/machinery/shuttle/shuttle_engine.dm b/code/game/machinery/shuttle/shuttle_engine.dm
index 267c8d102918..c4fd424d4076 100644
--- a/code/game/machinery/shuttle/shuttle_engine.dm
+++ b/code/game/machinery/shuttle/shuttle_engine.dm
@@ -12,7 +12,7 @@
var/enabled = TRUE
///How much thrust this engine generates when burned fully.
var/thrust = 0
- ///I don't really know what this is but it's used a lot
+ ///Whether this engine is actively providing thrust to the ship
var/thruster_active = FALSE
/**
diff --git a/code/modules/power/turbine.dm b/code/game/machinery/shuttle/turbine.dm
similarity index 54%
rename from code/modules/power/turbine.dm
rename to code/game/machinery/shuttle/turbine.dm
index ba390b1cf873..7d310d37cd30 100644
--- a/code/modules/power/turbine.dm
+++ b/code/game/machinery/shuttle/turbine.dm
@@ -25,48 +25,60 @@
/obj/machinery/power/compressor
name = "compressor"
desc = "The compressor stage of a gas turbine generator."
- icon = 'icons/obj/atmospherics/pipes/simple.dmi'
+ icon = 'icons/obj/atmospherics/components/turbine.dmi'
icon_state = "compressor"
density = TRUE
resistance_flags = FIRE_PROOF
CanAtmosPass = ATMOS_PASS_DENSITY
+ use_power = NO_POWER_USE // powered by gas flow
+ interacts_with_air = TRUE
circuit = /obj/item/circuitboard/machine/power_compressor
- var/obj/machinery/power/turbine/turbine
+ var/obj/machinery/power/shuttle/engine/turbine/turbine
var/datum/gas_mixture/gas_contained
- var/turf/inturf
var/starter = 0
var/rpm = 0
var/rpmtarget = 0
var/capacity = 1e6
var/comp_id = 0
- var/efficiency
+ var/efficiency = 1
+ var/intake_ratio = 0.1 // might add a way to adjust this in-game later
-/obj/machinery/power/turbine/lavaland
+/obj/machinery/power/shuttle/engine/turbine/lavaland
destroy_output = TRUE
/obj/machinery/power/compressor/Destroy()
+ SSair.stop_processing_machine(src)
if (turbine && turbine.compressor == src)
turbine.compressor = null
+ if(isopenturf(loc))
+ loc.assume_air(gas_contained)
+ loc.air_update_turf()
turbine = null
return ..()
-/obj/machinery/power/turbine
+/obj/machinery/power/shuttle/engine/turbine
name = "gas turbine generator"
desc = "A gas turbine used for backup power generation."
- icon = 'icons/obj/atmospherics/pipes/simple.dmi'
+ icon = 'icons/obj/atmospherics/components/turbine.dmi'
icon_state = "turbine"
density = TRUE
resistance_flags = FIRE_PROOF
CanAtmosPass = ATMOS_PASS_DENSITY
+ use_power = NO_POWER_USE // powered by gas flow
+ interacts_with_air = TRUE
circuit = /obj/item/circuitboard/machine/power_turbine
+ thrust = 0 // no thrust by default
+ icon_state_closed = "turbine"
+ icon_state_open = "turbine"
+ icon_state_off = "turbine"
var/opened = 0
var/obj/machinery/power/compressor/compressor
- var/turf/outturf
- var/lastgen
+ var/lastgen = 0
var/productivity = 1
var/destroy_output = FALSE //Destroy the output gas instead of actually outputting it. Used on lavaland to prevent cooking the zlevel
-/obj/machinery/power/turbine/Destroy()
+/obj/machinery/power/shuttle/engine/turbine/Destroy()
+ SSair.stop_processing_machine(src)
if (compressor && compressor.turbine == src)
compressor.turbine = null
compressor = null
@@ -74,29 +86,39 @@
// the inlet stage of the gas turbine electricity generator
-/obj/machinery/power/compressor/Initialize()
+/obj/machinery/power/compressor/Initialize(mapload)
. = ..()
// The inlet of the compressor is the direction it faces
gas_contained = new
- inturf = get_step(src, dir)
+ SSair.start_processing_machine(src, mapload)
locate_machinery()
if(!turbine)
obj_break()
+ return INITIALIZE_HINT_LATELOAD
+
+/obj/machinery/power/compressor/LateInitialize()
+ . = ..()
+ var/turf/comp_turf = get_turf(src)
+ comp_turf.ImmediateCalculateAdjacentTurfs() // turbine blocks atmos so update the turf it's on or stuff breaks
#define COMPFRICTION 5e5
/obj/machinery/power/compressor/locate_machinery()
if(turbine)
return
- turbine = locate() in get_step(src, get_dir(inturf, src))
+ turbine = locate() in get_step(src, turn(dir, 180))
if(turbine)
+ set_machine_stat(machine_stat & ~BROKEN)
turbine.locate_machinery()
+ else
+ turbine = null
+ obj_break()
/obj/machinery/power/compressor/RefreshParts()
var/E = 0
for(var/obj/item/stock_parts/manipulator/M in component_parts)
E += M.rating
- efficiency = E / 6
+ efficiency = max(E / 6, 1)
/obj/machinery/power/compressor/examine(mob/user)
. = ..()
@@ -108,49 +130,63 @@
return
if(default_change_direction_wrench(user, I))
- turbine = null
- inturf = get_step(src, dir)
- locate_machinery()
if(turbine)
to_chat(user, "Turbine connected.")
set_machine_stat(machine_stat & ~BROKEN)
else
to_chat(user, "Turbine not connected.")
- obj_break()
return
default_deconstruction_crowbar(I)
-/obj/machinery/power/compressor/process()
- if(!starter)
- return
- if(!turbine || (turbine.machine_stat & BROKEN))
- starter = FALSE
- if(machine_stat & BROKEN || panel_open)
- starter = FALSE
- return
- cut_overlays()
-
- rpm = 0.9* rpm + 0.1 * rpmtarget
+/obj/machinery/power/compressor/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/I)
+ . = ..()
+ if(panel_open)
+ set_machine_stat(machine_stat | MAINT)
+ else
+ set_machine_stat(machine_stat & ~MAINT)
- // 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
- // above todo 7 years and counting
+//update when moved or changing direction
+/obj/machinery/power/compressor/setDir(newdir)
+ . = ..()
+ locate_machinery()
- inturf.transfer_air_ratio(gas_contained, 0.1)
+/obj/machinery/power/compressor/Move(atom/newloc, direct, glide_size_override)
+ . = ..()
+ locate_machinery()
-// RPM function to include compression friction - be advised that too low/high of a compfriction value can make things screwy
+/obj/machinery/power/compressor/process(delta_time)
+ return
+/obj/machinery/power/compressor/process_atmos(delta_time)
+ // RPM function to include compression friction - be advised that too low/high of a compfriction value can make things screwy
+ rpm -= 1
+ rpm = (0.9 * rpm) + (0.1 * rpmtarget)
rpm = min(rpm, (COMPFRICTION*efficiency)/2)
- rpm = max(0, rpm - (rpm*rpm)/(COMPFRICTION*efficiency))
+ rpm = max(0, rpm - (rpm**2)/(COMPFRICTION*efficiency))
- if(starter && !(machine_stat & NOPOWER))
- use_power(2800)
- if(rpm<1000)
- rpmtarget = 1000
- else
- if(rpm<1000)
- rpmtarget = 0
+ update_overlays()
+
+ if(!turbine || (turbine.machine_stat & BROKEN))
+ locate_machinery() // try to find the other part if we somehow got disconnected
+
+ if((machine_stat & (BROKEN|MAINT)) || !starter) // if we didn't find it...
+ rpmtarget = 0
+ return
+
+ var/turf/inturf = get_step(src, dir)
+ var/datum/gas_mixture/environment = inturf.return_air()
+ var/external_pressure = environment.return_pressure()
+ var/pressure_delta = external_pressure - gas_contained.return_pressure()
+
+ // Equalize the gas between the environment and the internal gas mix
+ if(pressure_delta > 0)
+ var/datum/gas_mixture/removed = environment.remove_ratio((1 - ((1 - intake_ratio)**delta_time)) * pressure_delta / (external_pressure * 2)) // silly math to keep it consistent with delta_time
+ gas_contained.merge(removed)
+ inturf.air_update_turf()
+/obj/machinery/power/compressor/update_overlays()
+ . = ..()
if(rpm>50000)
add_overlay(mutable_appearance(icon, "comp-o4", FLY_LAYER))
else if(rpm>10000)
@@ -159,91 +195,122 @@
add_overlay(mutable_appearance(icon, "comp-o2", FLY_LAYER))
else if(rpm>500)
add_overlay(mutable_appearance(icon, "comp-o1", FLY_LAYER))
- //TODO: DEFERRED
// 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 TURBGENQ 100000
#define TURBGENG 0.5
+#define POWER_TO_THRUST 0.001 // power production to thrust ratio
-/obj/machinery/power/turbine/Initialize()
+/obj/machinery/power/shuttle/engine/turbine/Initialize(mapload)
. = ..()
-// The outlet is pointed at the direction of the turbine component
- outturf = get_step(src, dir)
+ SSair.start_processing_machine(src, mapload)
locate_machinery()
if(!compressor)
obj_break()
connect_to_network()
+ return INITIALIZE_HINT_LATELOAD
+
+/obj/machinery/power/shuttle/engine/turbine/LateInitialize()
+ . = ..()
+ var/turf/comp_turf = get_turf(src)
+ comp_turf.ImmediateCalculateAdjacentTurfs() // turbine blocks atmos so update the turf it's on or stuff breaks
-/obj/machinery/power/turbine/RefreshParts()
+/obj/machinery/power/shuttle/engine/turbine/RefreshParts()
var/P = 0
for(var/obj/item/stock_parts/capacitor/C in component_parts)
P += C.rating
productivity = P / 6
-/obj/machinery/power/turbine/examine(mob/user)
+/obj/machinery/power/shuttle/engine/turbine/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
. += "The status display reads: Productivity at [productivity*100]%."
-/obj/machinery/power/turbine/locate_machinery()
+/obj/machinery/power/shuttle/engine/turbine/locate_machinery()
if(compressor)
return
- compressor = locate() in get_step(src, get_dir(outturf, src))
+ compressor = locate() in get_step(src, turn(dir, 180))
if(compressor)
+ set_machine_stat(machine_stat & ~BROKEN)
compressor.locate_machinery()
+ else
+ compressor = null
+ obj_break()
-/obj/machinery/power/turbine/process()
+/obj/machinery/power/shuttle/engine/turbine/process(delta_time)
+ add_avail(lastgen) // add power in process() so it doesn't update power output separately from the rest of the powernet (bad)
+ update_overlays()
+/obj/machinery/power/shuttle/engine/turbine/process_atmos(delta_time)
if(!compressor)
set_machine_stat(BROKEN)
+ locate_machinery() // try to find the missing piece
- if((machine_stat & BROKEN) || panel_open)
+ if(machine_stat & (BROKEN|MAINT)) // we're only running half a turbine, don't continue
return
- if(!compressor.starter)
- return
- cut_overlays()
// 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
+ thrust = lastgen * POWER_TO_THRUST // second law
- add_avail(lastgen)
-
- // Weird function but it works. Should be something else...
-
- var/newrpm = ((compressor.gas_contained.return_temperature()) * compressor.gas_contained.total_moles())/4
+ var/turf/outturf = get_step(src, dir)
+ if(!LAZYLEN(outturf.atmos_adjacent_turfs))
+ compressor.rpmtarget = 0
+ return
- newrpm = max(0, newrpm)
+ // Move gas from the compressor to the outlet
+ var/datum/gas_mixture/environment = outturf.return_air()
+ var/internal_pressure = compressor.gas_contained.return_pressure()
+ var/pressure_delta = internal_pressure - environment.return_pressure()
- if(!compressor.starter || newrpm > 1000)
- compressor.rpmtarget = newrpm
+ // Now set the compressor's RPM target based on how much gas is flowing through
+ compressor.rpmtarget = max(0, pressure_delta * compressor.gas_contained.return_volume() / (R_IDEAL_GAS_EQUATION * 4))
- if(compressor.gas_contained.total_moles()>0)
- var/oamount = min(compressor.gas_contained.total_moles(), (compressor.rpm+100)/35000*compressor.capacity)
+ // Equalize the gas between the internal gas mix and the environment
+ if(pressure_delta > 0)
+ var/datum/gas_mixture/removed = compressor.gas_contained.remove_ratio(pressure_delta / (internal_pressure * 2))
if(destroy_output)
- compressor.gas_contained.set_moles(compressor.gas_contained.get_moles() - oamount)
- else
- outturf.assume_air_moles(compressor.gas_contained, oamount)
+ qdel(removed)
+ return
+ outturf.assume_air(removed)
+ outturf.air_update_turf()
+
+// Return the current thrust amount
+/obj/machinery/power/shuttle/engine/turbine/burn_engine(percentage, deltatime)
+ return thrust * deltatime * (percentage / 100)
+
+// Return the current power output
+/obj/machinery/power/shuttle/engine/turbine/return_fuel()
+ return lastgen
+
+// Return the maximum power output
+/obj/machinery/power/shuttle/engine/turbine/return_fuel_cap()
+ return ((COMPFRICTION*(compressor ? compressor.efficiency : 1) / (TURBGENQ*4))**TURBGENG) * TURBGENQ * productivity
+
+// Return the maximum power output
+/obj/machinery/power/shuttle/engine/turbine/update_engine()
+ if(!(flags_1 & INITIALIZED_1))
+ return FALSE
+ thruster_active = !panel_open && compressor
+ return thruster_active
// If it works, put an overlay that it works!
-
+/obj/machinery/power/shuttle/engine/turbine/update_overlays()
+ . = ..()
if(lastgen > 100)
add_overlay(mutable_appearance(icon, "turb-o", FLY_LAYER))
-/obj/machinery/power/turbine/attackby(obj/item/I, mob/user, params)
+/obj/machinery/power/shuttle/engine/turbine/attackby(obj/item/I, mob/user, params)
if(default_deconstruction_screwdriver(user, initial(icon_state), initial(icon_state), I))
return
if(default_change_direction_wrench(user, I))
- compressor = null
- outturf = get_step(src, dir)
- locate_machinery()
if(compressor)
to_chat(user, "Compressor connected.")
- set_machine_stat(machine_stat & ~BROKEN)
else
to_chat(user, "Compressor not connected.")
obj_break()
@@ -251,25 +318,42 @@
default_deconstruction_crowbar(I)
-/obj/machinery/power/turbine/ui_interact(mob/user, datum/tgui/ui)
+/obj/machinery/power/shuttle/engine/turbine/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/I)
+ . = ..()
+ if(panel_open)
+ set_machine_stat(machine_stat | MAINT)
+ else
+ set_machine_stat(machine_stat & ~MAINT)
+
+// update if it moves or changes direction
+/obj/machinery/power/shuttle/engine/turbine/setDir(newdir)
+ . = ..()
+ locate_machinery()
+
+/obj/machinery/power/shuttle/engine/turbine/Move(atom/newloc, direct, glide_size_override)
+ . = ..()
+ locate_machinery()
+
+/obj/machinery/power/shuttle/engine/turbine/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "TurbineComputer", name)
ui.open()
-/obj/machinery/power/turbine/ui_data(mob/user)
+/obj/machinery/power/shuttle/engine/turbine/ui_data(mob/user)
var/list/data = list()
data["compressor"] = compressor ? TRUE : FALSE
- data["compressor_broke"] = (!compressor || (compressor.machine_stat & BROKEN)) ? TRUE : FALSE
+ data["compressor_broke"] = (!compressor || (compressor.machine_stat & (BROKEN|MAINT))) ? TRUE : FALSE
data["turbine"] = compressor?.turbine ? TRUE : FALSE
- data["turbine_broke"] = (!compressor || !compressor.turbine || (compressor.turbine.machine_stat & BROKEN)) ? TRUE : FALSE
+ data["turbine_broke"] = (!compressor || !compressor.turbine || (compressor.turbine.machine_stat & (BROKEN|MAINT))) ? TRUE : FALSE
data["online"] = compressor?.starter
data["power"] = DisplayPower(compressor?.turbine?.lastgen)
data["rpm"] = compressor?.rpm
data["temp"] = compressor?.gas_contained.return_temperature()
+ data["pressure"] = compressor?.gas_contained.return_pressure()
return data
-/obj/machinery/power/turbine/ui_act(action, params)
+/obj/machinery/power/shuttle/engine/turbine/ui_act(action, params)
. = ..()
if(.)
return
@@ -306,7 +390,7 @@
/obj/machinery/computer/turbine_computer/locate_machinery()
if(id)
- for(var/obj/machinery/power/compressor/C in GLOB.machines)
+ for(var/obj/machinery/power/compressor/C in SSair.atmos_air_machinery)
if(C.comp_id == id)
compressor = C
return
@@ -322,13 +406,14 @@
/obj/machinery/computer/turbine_computer/ui_data(mob/user)
var/list/data = list()
data["compressor"] = compressor ? TRUE : FALSE
- data["compressor_broke"] = (!compressor || (compressor.machine_stat & BROKEN)) ? TRUE : FALSE
+ data["compressor_broke"] = (!compressor || (compressor.machine_stat & (BROKEN|MAINT))) ? TRUE : FALSE
data["turbine"] = compressor?.turbine ? TRUE : FALSE
- data["turbine_broke"] = (!compressor || !compressor.turbine || (compressor.turbine.machine_stat & BROKEN)) ? TRUE : FALSE
+ data["turbine_broke"] = (!compressor || !compressor.turbine || (compressor.turbine.machine_stat & (BROKEN|MAINT))) ? TRUE : FALSE
data["online"] = compressor?.starter
data["power"] = DisplayPower(compressor?.turbine?.lastgen)
data["rpm"] = compressor?.rpm
data["temp"] = compressor?.gas_contained.return_temperature()
+ data["pressure"] = compressor?.gas_contained.return_pressure()
return data
/obj/machinery/computer/turbine_computer/ui_act(action, params)
@@ -345,6 +430,7 @@
locate_machinery()
. = TRUE
+#undef POWER_TO_THRUST
#undef COMPFRICTION
#undef TURBGENQ
#undef TURBGENG
diff --git a/code/game/objects/items/circuitboards/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machine_circuitboards.dm
index 306634a639fc..13576abf2f43 100644
--- a/code/game/objects/items/circuitboards/machine_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/machine_circuitboards.dm
@@ -257,7 +257,7 @@
/obj/item/circuitboard/machine/power_turbine
name = "Power Turbine (Machine Board)"
icon_state = "engineering"
- build_path = /obj/machinery/power/turbine
+ build_path = /obj/machinery/power/shuttle/engine/turbine
req_components = list(
/obj/item/stack/cable_coil = 5,
/obj/item/stock_parts/capacitor = 6)
diff --git a/icons/obj/atmospherics/components/turbine.dmi b/icons/obj/atmospherics/components/turbine.dmi
new file mode 100644
index 000000000000..6e499911a75b
Binary files /dev/null and b/icons/obj/atmospherics/components/turbine.dmi differ
diff --git a/shiptest.dme b/shiptest.dme
index 9840f4d4cc9c..80ff9340a083 100644
--- a/shiptest.dme
+++ b/shiptest.dme
@@ -956,6 +956,7 @@
#include "code\game\machinery\shuttle\shuttle_engine.dm"
#include "code\game\machinery\shuttle\shuttle_engine_types.dm"
#include "code\game\machinery\shuttle\shuttle_heater.dm"
+#include "code\game\machinery\shuttle\turbine.dm"
#include "code\game\machinery\telecomms\broadcasting.dm"
#include "code\game\machinery\telecomms\machine_interactions.dm"
#include "code\game\machinery\telecomms\telecomunications.dm"
@@ -2915,7 +2916,6 @@
#include "code\modules\power\solar.dm"
#include "code\modules\power\terminal.dm"
#include "code\modules\power\tracker.dm"
-#include "code\modules\power\turbine.dm"
#include "code\modules\power\singularity\boh_tear.dm"
#include "code\modules\power\singularity\collector.dm"
#include "code\modules\power\singularity\containment_field.dm"
diff --git a/tgui/packages/tgui/interfaces/TurbineComputer.js b/tgui/packages/tgui/interfaces/TurbineComputer.js
index f11eb9880728..f8c9e2677ff3 100644
--- a/tgui/packages/tgui/interfaces/TurbineComputer.js
+++ b/tgui/packages/tgui/interfaces/TurbineComputer.js
@@ -1,5 +1,6 @@
import { useBackend } from '../backend';
import { Button, LabeledList, Section } from '../components';
+import { formatSiUnit } from '../format';
import { Window } from '../layouts';
export const TurbineComputer = (props, context) => {
@@ -11,7 +12,7 @@ export const TurbineComputer = (props, context) => {
!data.turbine_broke
);
return (
-
+
{
{data.temp} K
+
+ {formatSiUnit(data.pressure * 1000, 1, 'Pa')}
+
{data.power}