From 5db905615d4c4e78c449f972a11b1de1fee8c2e0 Mon Sep 17 00:00:00 2001 From: Cody Brittain <1779662+Generalcamo@users.noreply.github.com> Date: Sat, 28 Dec 2024 13:30:31 -0500 Subject: [PATCH] Re-added the Turbine (#19828) ![image](https://github.com/user-attachments/assets/8cf5c42a-0f36-49ae-b34e-19567c747a28) This is intended for future use. This is a direct port from Paradise, modified to work with our code. ### Asset Licenses The following assets that **have not** been created by myself are included in this PR: | Path | Original Author | License | | --- | --- | --- | | sound/effects/electheart.ogg | tigercat2000 (Paradise) | CC-BY-SA | | icons/obj/pipeturbine.dmi | [PestoVerde322](https://github.com/PestoVerde322) (Beestation) | CC-BY-SA | --------- Co-authored-by: Cody Brittain --- aurorastation.dme | 1 + code/modules/power/turbine.dm | 446 ++++++++++++++++++ html/changelogs/GeneralCamo - Turbine 2.0.yml | 58 +++ icons/obj/pipeturbine.dmi | Bin 5660 -> 10193 bytes sound/effects/electheart.ogg | Bin 0 -> 22162 bytes .../tgui/interfaces/TurbineComputer.js | 79 ++++ 6 files changed, 584 insertions(+) create mode 100644 code/modules/power/turbine.dm create mode 100644 html/changelogs/GeneralCamo - Turbine 2.0.yml create mode 100644 sound/effects/electheart.ogg create mode 100644 tgui/packages/tgui/interfaces/TurbineComputer.js diff --git a/aurorastation.dme b/aurorastation.dme index 0a3735b9ec5..0c08262c02b 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -3187,6 +3187,7 @@ #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\antimatter\containment_jar.dm" #include "code\modules\power\antimatter\control.dm" #include "code\modules\power\antimatter\shielding.dm" diff --git a/code/modules/power/turbine.dm b/code/modules/power/turbine.dm new file mode 100644 index 00000000000..31b4fb30467 --- /dev/null +++ b/code/modules/power/turbine.dm @@ -0,0 +1,446 @@ +// 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 quite 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. +// +// - 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) +// + +#define OVERDRIVE 4 +#define VERY_FAST 3 +#define FAST 2 +#define SLOW 1 + +//below defines the time between an overheat event and next startup +#define OVERHEAT_TIME 120 SECONDS +#define OVERHEAT_THRESHOLD 200 //measured in cycles of 2 seconds +#define OVERHEAT_MESSAGE "Alert! The gas turbine generator's bearings have overheated. Initiating automatic cooling procedures. Manual restart is required." + +/obj/machinery/power/compressor + name = "gas turbine compressor" + desc = "The compressor stage of a gas turbine generator. A data panel for linking with a to a computer can be accessed with a screwdriver." + icon = 'icons/obj/pipeturbine.dmi' + icon_state = "compressor" + anchored = TRUE + density = TRUE + atmos_canpass = CANPASS_DENSITY + var/obj/machinery/power/turbine/turbine + var/datum/gas_mixture/gas_contained + var/turf/simulated/inturf + var/starter = FALSE + /// Current RPM value of the compressor + var/rpm = 0 + /// Current rpm threshold, used to change sprites + var/rpm_threshold = NONE + /// Target RPM to aim for + var/rpmtarget = 0 + /// Capacity in moles that the compressor can fit + var/capacity = 1e6 + /// ID of computer to link to. + var/comp_id = 0 + /// How efficient the compressor is. Modified by amount and tier of manipulators installed. + var/efficiency + /// value that dertermines the amount of overheat "damage" on the turbine. + var/overheat = 0 + /// This value needs to be zero. It represents seconds since the last overheat event + var/last_overheat = 0 + /// Internal radio, used to alert engineers of turbine trip! + var/obj/item/device/radio/radio + + component_types = list( + /obj/item/stock_parts/manipulator = 6, + /obj/item/stack/cable_coil = 5 + ) + +/obj/machinery/power/turbine + name = "gas turbine generator" + desc = "A gas turbine used for backup power generation." + icon = 'icons/obj/pipeturbine.dmi' + icon_state = "turbine" + anchored = TRUE + density = TRUE + atmos_canpass = CANPASS_DENSITY + /// Linked [/obj/machinery/power/compressor]. Should not be manipulated directly. + var/obj/machinery/power/compressor/compressor + /// Turf to output air to. Should not be manipulated directly + var/turf/simulated/outturf + /// Last value of power the generator outputted + var/lastgen + /// If the turbine is outputing enough to visibly affect its sprite + var/generator_threshold = FALSE + /// Productivity value of turbine. Modified by amount and tier of capacitors installed. + var/productivity = 1 + component_types = list( + /obj/item/stock_parts/capacitor = 6, + /obj/item/stack/cable_coil = 5 + ) + +/obj/machinery/computer/terminal/turbine_computer + name = "gas turbine control computer" + desc = "A computer to remotely control a gas turbine. Link it to a turbine via use of a multitool." + icon_screen = "turbinecomp" + icon_keyboard = "tech_key" + /// Linked [/obj/machinery/power/compressor]. Should not be manipulated directly. + var/obj/machinery/power/compressor/compressor + /// Linked blast doors, currently unused. Should not be manipulated directly + var/list/obj/machinery/door/blast/doors + /// ID of the computer. Tied to var/comp_id in [/obj/machinery/power/compressor] + var/id = 0 + /// Currently unused. Intended for control of blast doors in a fully functional turbine setup + var/door_status = 0 + +// the inlet stage of the gas turbine electricity generator + +/obj/machinery/power/compressor/Initialize(mapload) + . = ..() +// The inlet of the compressor is the direction it faces + gas_contained = new + inturf = get_step(src, dir) + locate_machinery() + if(!turbine) + stat |= BROKEN + else + turbine.compressor = src + + //Radio for screaming about overheats + radio = new(src) + radio.set_listening(FALSE) + radio.config(list("Engineering" = 0)) + +#define COMPFRICTION 5e5 +#define COMPSTARTERLOAD 2800 + + +// Crucial to make things work!!!! +// OLD FIX - explanation given down below. +// /obj/machinery/power/compressor/CanPass(atom/movable/mover, turf/target, height=0) +// return !density + +/obj/machinery/power/compressor/proc/locate_machinery() + if(turbine) + return + turbine = locate() in get_step(src, get_dir(inturf, src)) + if(turbine) + turbine.locate_machinery() + +/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 + +/obj/machinery/power/compressor/attackby(obj/item/attacking_item, mob/user, params) + if(attacking_item.iswrench()) + turbine = null + inturf = get_step(src, dir) + locate_machinery() + if(turbine) + to_chat(user, SPAN_NOTICE("Turbine connected.")) + stat &= ~BROKEN + else + FEEDBACK_FAILURE(user, "Compressor not connected.") + stat |= BROKEN + return + + if(default_deconstruction_crowbar(user, attacking_item)) + return TRUE + + if(default_deconstruction_screwdriver(user, attacking_item)) + return TRUE + + return ..() + +/obj/machinery/power/compressor/proc/trigger_overheat() + starter = FALSE + last_overheat = world.time + overheat -= 50 + radio.autosay(OVERHEAT_MESSAGE, name, "Engineering") + playsound(src, 'sound/machines/buzz-two.ogg', 100, FALSE, 40, 30, falloff_distance = 10) + +/obj/machinery/power/compressor/proc/time_until_overheat_done() + return max(last_overheat + OVERHEAT_TIME - world.time, 0) + +/obj/machinery/power/compressor/process(seconds_per_tick) + if(!turbine) + stat |= BROKEN + if(!starter) + return + ClearOverlays() + if(stat & BROKEN || panel_open) + return + + if(rpm_threshold == OVERDRIVE) + overheat += 2 + if(overheat >= OVERHEAT_THRESHOLD) + trigger_overheat() + else if(overheat > 0) + overheat -= 2 + rpm = 0.9 * rpm + 0.1 * rpmtarget + var/datum/gas_mixture/environment = inturf.return_air() + var/transfer_moles = environment.total_moles/10 * seconds_per_tick + var/datum/gas_mixture/removed = environment.remove(transfer_moles) + gas_contained.merge(removed) + + // 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(!(stat & NOPOWER)) + draw_power(2800) + if(rpm < 1000) + rpmtarget = 1000 + else + if(rpm < 1000) + rpmtarget = 0 + + var/new_rpm_threshold + switch(rpm) + if(50001 to INFINITY) + new_rpm_threshold = OVERDRIVE + if(10001 to 50000) + new_rpm_threshold = VERY_FAST + if(2001 to 10000) + new_rpm_threshold = FAST + if(501 to 2000) + new_rpm_threshold = SLOW + else + new_rpm_threshold = NONE + + if(rpm_threshold != new_rpm_threshold) + rpm_threshold = new_rpm_threshold + AddOverlays(overlay_image(icon, "comp_o[rpm_threshold]", FLY_LAYER)) + AddOverlays(emissive_appearance(icon, "comp_o[rpm_threshold]", FLY_LAYER)) + update_icon() + +// These are crucial to working of a turbine - the stats modify the power output. +// TURBPOWER modifies how much raw energy can you get from rpms, +// TURBCURVESHAPE modifies the shape of the curve - the lower the value the less straight the curve is. + +#define TURBPOWER 500000 +#define TURBCURVESHAPE 0.5 +#define POWER_CURVE_MOD 1.7 // Used to form the turbine power generation curve + +/obj/machinery/power/turbine/Initialize(mapload) + . = ..() +// The outlet is pointed at the direction of the turbine component + outturf = get_step(src, dir) + locate_machinery() + + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/power/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/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/process(seconds_per_tick) + if(!compressor) + stat |= BROKEN + + if((stat & BROKEN) || panel_open) + return + + if(!compressor.starter) + return + + // This is the power generation function. If anything is needed it's good to plot it in EXCEL before modifying + // the TURBPOWER and TURBCURVESHAPE values + if(compressor.gas_contained.temperature < 500) + lastgen = 0 + else + lastgen = ((compressor.rpm / TURBPOWER) ** TURBCURVESHAPE) * TURBPOWER * productivity * POWER_CURVE_MOD + + add_avail(lastgen) + + var/newrpm = (compressor.gas_contained.temperature * compressor.gas_contained.total_moles) / 4 + + newrpm = max(0, newrpm) + + if(!compressor.starter || newrpm > 1000) + compressor.rpmtarget = newrpm + + if(compressor.gas_contained.total_moles>0) + var/oamount = min(compressor.gas_contained.total_moles, (compressor.rpm + 100) / 35000 * compressor.capacity * seconds_per_tick) + var/datum/gas_mixture/removed = compressor.gas_contained.remove(oamount) + outturf.assume_air(removed) + + if((lastgen > 100) != generator_threshold) + generator_threshold = !generator_threshold + AddOverlays(overlay_image(icon, "turb-o", FLY_LAYER)) + + updateDialog() + +/obj/machinery/power/turbine/attackby(obj/item/attacking_item, mob/user, params) + if(default_deconstruction_screwdriver(user, attacking_item)) + return + + if(attacking_item.iswrench()) + compressor = null + outturf = get_step(src, dir) + locate_machinery() + if(compressor) + to_chat(user, SPAN_NOTICE("Compressor connected.")) + stat &= ~BROKEN + else + FEEDBACK_FAILURE(user, "Compressor not connected.") + stat |= BROKEN + return + + if(default_deconstruction_crowbar(user, attacking_item)) + return + + return ..() + +/obj/machinery/power/turbine/attack_hand(mob/user) + . = ..() + ui_interact(user) + +/obj/machinery/power/turbine/ui_state(mob/user) + return GLOB.default_state + +/obj/machinery/power/turbine/ui_interact(mob/user, datum/tgui/ui = null) + 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) + var/list/data = list() + data["compressor"] = !isnull(compressor) + data["compressor_broken"] = (!compressor || (compressor.stat & BROKEN)) + data["turbine"] = !isnull(compressor?.turbine) + data["turbine_broken"] = (compressor?.turbine?.stat & BROKEN) + + if(compressor && compressor.turbine) + data["online"] = compressor.starter + data["power"] = compressor.turbine.lastgen + data["rpm"] = compressor.rpm + data["temperature"] = compressor.gas_contained.temperature + return data + +/obj/machinery/power/turbine/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + if(..()) + return + + switch(action) + if("toggle_power") + var/time_until_done = compressor.time_until_overheat_done() + if(time_until_done) + compressor.starter = FALSE + to_chat(usr, SPAN_ALERT("The turbine is overheating, please wait [time_until_done / 10] seconds for cooldown procedures to complete.")) + playsound(src, 'sound/effects/electheart.ogg', 100, FALSE, 40, 30, falloff_distance = 10) + else if(compressor?.turbine) + compressor.starter = !compressor.starter + . = TRUE + playsound(src, 'sound/mecha/powerup.ogg', 100, FALSE, 40, 30, falloff_distance = 10) + + if("reconnect") + locate_machinery() + . = TRUE + +////////////////// +/////COMPUTER///// +///////////////// + +/obj/machinery/computer/terminal/turbine_computer/Initialize() + ..() + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/computer/terminal/turbine_computer/LateInitialize() + for(var/obj/machinery/power/compressor/C in SSmachinery.machinery) + if(id == C.comp_id) + compressor = C + doors = list() + for(var/obj/machinery/door/blast/P in SSmachinery.machinery) + if(P.id == id) + doors += P + +/obj/machinery/computer/terminal/turbine_computer/proc/disconnect() + //this disconnects the computer from the turbine, good for resets. + compressor = null + +/obj/machinery/computer/terminal/turbine_computer/attack_hand(mob/user) + . = ..() + ui_interact(user) + +/obj/machinery/computer/terminal/turbine_computer/ui_state(mob/user) + return GLOB.default_state + +/obj/machinery/computer/terminal/turbine_computer/ui_interact(mob/user, datum/tgui/ui = null) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "TurbineComputer", name) + ui.open() + +/obj/machinery/computer/terminal/turbine_computer/ui_data(mob/user) + var/list/data = list() + data["compressor"] = !isnull(compressor) + data["compressor_broken"] = (compressor?.stat & BROKEN) + data["turbine"] = !isnull(compressor?.turbine) + data["turbine_broken"] = (compressor?.turbine?.stat & BROKEN) + + if(compressor?.turbine) + data["online"] = compressor.starter + data["power"] = compressor.turbine.lastgen + data["rpm"] = compressor.rpm + data["temperature"] = compressor.gas_contained.temperature + data["bearing_heat"] = clamp((compressor.overheat / OVERHEAT_THRESHOLD) * 100, 0, 100) + return data + +/obj/machinery/computer/terminal/turbine_computer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + if(..()) + return + + switch(action) + if("toggle_power") + var/time_until_done = compressor.time_until_overheat_done() + if(time_until_done) + compressor.starter = FALSE + to_chat(usr, SPAN_ALERT("The turbine is overheating, please wait [time_until_done / 10] seconds for cooldown procedures to complete.")) + playsound(src, 'sound/effects/electheart.ogg', 100, FALSE, 40, 30, falloff_distance = 10) + . = TRUE + else if(compressor?.turbine) + if(!compressor.starter) + playsound(compressor, 'sound/mecha/powerup.ogg', 100, FALSE, 40, 30, falloff_distance = 10) + compressor.starter = !compressor.starter + . = TRUE + +/obj/machinery/computer/terminal/turbine_computer/process(seconds_per_tick) + src.updateDialog() + return + +#undef OVERDRIVE +#undef VERY_FAST +#undef FAST +#undef SLOW + +#undef OVERHEAT_TIME +#undef OVERHEAT_THRESHOLD +#undef OVERHEAT_MESSAGE +#undef COMPFRICTION +#undef COMPSTARTERLOAD +#undef TURBPOWER +#undef TURBCURVESHAPE +#undef POWER_CURVE_MOD diff --git a/html/changelogs/GeneralCamo - Turbine 2.0.yml b/html/changelogs/GeneralCamo - Turbine 2.0.yml new file mode 100644 index 00000000000..6bcc73aa1b1 --- /dev/null +++ b/html/changelogs/GeneralCamo - Turbine 2.0.yml @@ -0,0 +1,58 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# - (fixes bugs) +# wip +# - (work in progress) +# qol +# - (quality of life) +# soundadd +# - (adds a sound) +# sounddel +# - (removes a sound) +# rscadd +# - (adds a feature) +# rscdel +# - (removes a feature) +# imageadd +# - (adds an image or sprite) +# imagedel +# - (removes an image or sprite) +# spellcheck +# - (fixes spelling or grammar) +# experiment +# - (experimental change) +# balance +# - (balance changes) +# code_imp +# - (misc internal code change) +# refactor +# - (refactors code) +# config +# - (makes a change to the config files) +# admin +# - (makes changes to administrator tools) +# server +# - (miscellaneous changes to server) +################################# + +# Your name. +author: GeneralCamo + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit. +# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog. +changes: + - rscadd: "Re-added the turbine, a generator which takes in hot gasses from one end, outputs exhaust the other, and produces power from the resulting RPM." diff --git a/icons/obj/pipeturbine.dmi b/icons/obj/pipeturbine.dmi index fccec4c9ddfdae476e0020b7d316ba6bc62bf492..92f03d94eb755699197606c915b947ea7cd3a293 100644 GIT binary patch literal 10193 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 IwqxY~0FC|G*8l(j diff --git a/sound/effects/electheart.ogg b/sound/effects/electheart.ogg new file mode 100644 index 0000000000000000000000000000000000000000..5bf86a858cb93719913233f060bda68b6698ace4 GIT binary patch literal 22162 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 { + const { act, data } = useBackend(context); + const { compressor, compressor_broken, turbine, turbine_broken, online } = + data; + const operational = Boolean( + compressor && !compressor_broken && turbine && !turbine_broken + ); + return ( + + +
act('toggle_power')} + /> + }> + {operational ? : } +
+
+
+ ); +}; + +// Element Tree for if the turbine is broken +const TurbineBroken = (props, context) => { + const { data } = useBackend(context); + const { compressor, compressor_broken, turbine, turbine_broken, online } = + data; + return ( + + + {compressor_broken ? (compressor ? 'Offline' : 'Missing') : 'Online'} + + + {turbine_broken ? (turbine ? 'Offline' : 'Missing') : 'Online'} + + + ); +}; + +// Element Tree for if the turbine is working +const TurbineWorking = (props, context) => { + const { data } = useBackend(context); + const { rpm, temperature, power, bearing_heat } = data; + return ( + + {rpm} RPM + {temperature} K + {power} W + + + {toFixed(bearing_heat) + '%'} + + + + ); +};