From d1b842356ec4fd773a1e7092197e7f094cc4d36d Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Sun, 15 Dec 2024 08:57:37 +0530 Subject: [PATCH] More maintenance for turbine (#88254) ## About The Pull Request **1. Fixes** - Fixes #88231. This is a 2 part fix as in - For the UI side we first convert energy to power in the back end via `energy_to_power()` proc & then use `formatPower()` proc in the client side UI to display the correct SI units instead of always using KW - The turbine now uses `SSMachines` subsytem for processing instead of `SSAir`. This is because energy which is [power x delta time] requires `seconds_per_tick` which isn't supplied by `process_atmos()` so for correct conversion we have to switch over to the machine subsystem ![Screenshot (452)](https://github.com/user-attachments/assets/94fc207b-37d4-4f10-a984-b5d15e0644c6) **2. Refactor** - Merged procs like `power_on()` & `power_off()` both into `toggle_power()` proc - Converted `attackby()` attack chain into `item_interaction()` - `ui_data()` now won't update the UI if it encounters invalid data & sends very little data if it's not connected to the turbine to reduce bandwidth - Removes redundant vars, autodoc procs & much more ## Changelog :cl: fix: Turbine converts energy to power correctly & shows correct reading with multitool refactor: turbine code has been overall improved. report bugs on github /:cl: --- code/game/machinery/_machinery.dm | 1 - code/modules/power/turbine/turbine.dm | 282 +++++++++--------- .../modules/power/turbine/turbine_computer.dm | 86 ++++-- code/modules/power/turbine/turbine_parts.dm | 129 ++++---- code/modules/unit_tests/unit_test.dm | 2 + icons/obj/machines/engine/turbine.dmi | Bin 5513 -> 5492 bytes .../tgui/interfaces/TurbineComputer.tsx | 170 ++++++----- 7 files changed, 333 insertions(+), 337 deletions(-) diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 656ece7f8ee..b962a902f17 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -493,7 +493,6 @@ ///internal proc that removes all static power usage from the current area /obj/machinery/proc/unset_static_power() - PRIVATE_PROC(TRUE) SHOULD_NOT_OVERRIDE(TRUE) var/old_usage = static_power_usage diff --git a/code/modules/power/turbine/turbine.dm b/code/modules/power/turbine/turbine.dm index e839800158f..2112002e507 100644 --- a/code/modules/power/turbine/turbine.dm +++ b/code/modules/power/turbine/turbine.dm @@ -1,11 +1,18 @@ +///Minimum pressure of gases pumped through the turbine #define MINIMUM_TURBINE_PRESSURE 0.01 +///Returns the minimum pressure if it falls below the value #define PRESSURE_MAX(value)(max((value), MINIMUM_TURBINE_PRESSURE)) +///Use emissive for overlays +#define EMISSIVE_OVERLAY (1 << 0) +///No turned off overlay +#define NO_INACTIVE_OVERLAY (1 << 1) /obj/machinery/power/turbine + icon = 'icons/obj/machines/engine/turbine.dmi' density = TRUE resistance_flags = FIRE_PROOF can_atmos_pass = ATMOS_PASS_DENSITY - processing_flags = NONE + processing_flags = START_PROCESSING_MANUALLY ///Checks if the machine is processing or not var/active = FALSE @@ -17,15 +24,8 @@ var/obj/item/turbine_parts/part_path ///The gas mixture this turbine part is storing var/datum/gas_mixture/machine_gasmix - - ///Our overlay when active - var/active_overlay = "" - ///Our overlay when off - var/off_overlay = "" - ///Our overlay when open - var/open_overlay = "" - ///Should we use emissive appearance? - var/emissive = FALSE + ///Flags for our overlays + var/overlay_flags = NONE /obj/machinery/power/turbine/Initialize(mapload, gas_theoretical_volume) . = ..() @@ -59,41 +59,6 @@ deactivate_parts() return ..() -/** - * Handles all the calculations needed for the gases, work done, temperature increase/decrease - * - * Arguments - * * datum/gas_mixture/input_mix - the gas from the environment or from another part of the turbine - * * datum/gas_mixture/output_mix - the gas that got pumped into this part from the input mix. - * ideally should be same as input mix but varying texmperatur & pressures can cause varying results - * * work_amount_to_remove - the amount of work to subtract from the actual work done to pump in the input mixture. - * For e.g. if gas was transfered from the inlet compressor to the rotor we want to subtract the work done - * by the inlet from the rotor to get the true work done - * * intake_size - the percentage of gas to be fed into an turbine part, controlled by turbine computer for inlet compressor only - */ -/obj/machinery/power/turbine/proc/transfer_gases(datum/gas_mixture/input_mix, datum/gas_mixture/output_mix, work_amount_to_remove, intake_size = 1) - //pump gases. if no gases were transferred then no work was done - var/output_pressure = PRESSURE_MAX(output_mix.return_pressure()) - var/datum/gas_mixture/transferred_gases = input_mix.pump_gas_to(output_mix, input_mix.return_pressure() * intake_size) - if(!transferred_gases) - return 0 - - //compute work done - var/work_done = QUANTIZE(transferred_gases.total_moles()) * R_IDEAL_GAS_EQUATION * transferred_gases.temperature * log((transferred_gases.volume * PRESSURE_MAX(transferred_gases.return_pressure())) / (output_mix.volume * output_pressure)) * TURBINE_WORK_CONVERSION_MULTIPLIER - if(work_amount_to_remove) - work_done = work_done - work_amount_to_remove - - //compute temperature & work from temperature if that is a lower value - var/output_mix_heat_capacity = output_mix.heat_capacity() - if(!output_mix_heat_capacity) - return 0 - work_done = min(work_done, (output_mix_heat_capacity * output_mix.temperature - output_mix_heat_capacity * TCMB) / TURBINE_HEAT_CONVERSION_MULTIPLIER) - output_mix.temperature = max((output_mix.temperature * output_mix_heat_capacity + work_done * TURBINE_HEAT_CONVERSION_MULTIPLIER) / output_mix_heat_capacity, TCMB) - return work_done - -/obj/machinery/power/turbine/block_superconductivity() - return TRUE - /obj/machinery/power/turbine/add_context(atom/source, list/context, obj/item/held_item, mob/user) if(isnull(held_item)) return NONE @@ -128,7 +93,7 @@ . = ..() if(installed_part) . += span_notice("Currently at tier [installed_part.current_tier].") - if(installed_part.current_tier + 1 < installed_part.max_tier) + if(installed_part.current_tier + 1 < TURBINE_PART_TIER_FOUR) . += span_notice("Can be upgraded by using a tier [installed_part.current_tier + 1] part.") . += span_notice("The [installed_part.name] can be [EXAMINE_HINT("pried")] out.") else @@ -140,15 +105,54 @@ /obj/machinery/power/turbine/update_overlays() . = ..() + if(panel_open) - . += open_overlay + . += "[base_icon_state]_open" if(active) - . += active_overlay - if(emissive) - . += emissive_appearance(icon, active_overlay, src) - else - . += off_overlay + . += "[base_icon_state]_on" + if(overlay_flags & EMISSIVE_OVERLAY) + . += emissive_appearance(icon, "[base_icon_state]_on", src) + else if(!(overlay_flags & NO_INACTIVE_OVERLAY)) + . += "[base_icon_state]_off" + + +/** + * Handles all the calculations needed for the gases, work done, temperature increase/decrease + * + * Arguments + * * datum/gas_mixture/input_mix - the gas from the environment or from another part of the turbine + * * datum/gas_mixture/output_mix - the gas that got pumped into this part from the input mix. + * ideally should be same as input mix but varying texmperatur & pressures can cause varying results + * * work_amount_to_remove - the amount of work to subtract from the actual work done to pump in the input mixture. + * For e.g. if gas was transfered from the inlet compressor to the rotor we want to subtract the work done + * by the inlet from the rotor to get the true work done + * * intake_size - the percentage of gas to be fed into an turbine part, controlled by turbine computer for inlet compressor only + */ +/obj/machinery/power/turbine/proc/transfer_gases(datum/gas_mixture/input_mix, datum/gas_mixture/output_mix, work_amount_to_remove, intake_size = 1) + PROTECTED_PROC(TRUE) + + //pump gases. if no gases were transferred then no work was done + var/output_pressure = PRESSURE_MAX(output_mix.return_pressure()) + var/datum/gas_mixture/transferred_gases = input_mix.pump_gas_to(output_mix, input_mix.return_pressure() * intake_size) + if(!transferred_gases) + return 0 + + //compute work done + var/work_done = QUANTIZE(transferred_gases.total_moles()) * R_IDEAL_GAS_EQUATION * transferred_gases.temperature * log((transferred_gases.volume * PRESSURE_MAX(transferred_gases.return_pressure())) / (output_mix.volume * output_pressure)) * TURBINE_WORK_CONVERSION_MULTIPLIER + if(work_amount_to_remove) + work_done = work_done - work_amount_to_remove + + //compute temperature & work from temperature if that is a lower value + var/output_mix_heat_capacity = output_mix.heat_capacity() + if(!output_mix_heat_capacity) + return 0 + work_done = min(work_done, (output_mix_heat_capacity * output_mix.temperature - output_mix_heat_capacity * TCMB) / TURBINE_HEAT_CONVERSION_MULTIPLIER) + output_mix.temperature = max((output_mix.temperature * output_mix_heat_capacity + work_done * TURBINE_HEAT_CONVERSION_MULTIPLIER) / output_mix_heat_capacity, TCMB) + return work_done + +/obj/machinery/power/turbine/block_superconductivity() + return TRUE /obj/machinery/power/turbine/screwdriver_act(mob/living/user, obj/item/tool) . = ITEM_INTERACT_BLOCKING @@ -165,7 +169,7 @@ deactivate_parts(user) else activate_parts(user) - update_appearance() + update_appearance(UPDATE_OVERLAYS) return ITEM_INTERACT_SUCCESS @@ -229,22 +233,22 @@ if(gone == installed_part) installed_part = null -/obj/machinery/power/turbine/attackby(obj/item/turbine_parts/object, mob/user, params) - //not the correct part +/obj/machinery/power/turbine/item_interaction(mob/living/user, obj/item/turbine_parts/object, list/modifiers) + . = NONE if(!istype(object, part_path)) return ..() //not in a state to accep the part. return TRUE so we don't bash the machine and damage it if(active) balloon_alert(user, "turn off the machine first!") - return TRUE + return ITEM_INTERACT_BLOCKING if(!panel_open) balloon_alert(user, "open the maintenance hatch first!") - return TRUE + return ITEM_INTERACT_BLOCKING //install the part if(!do_after(user, 2 SECONDS, src)) - return TRUE + return ITEM_INTERACT_BLOCKING if(installed_part) user.put_in_hands(installed_part) balloon_alert(user, "replaced part with the one in hand") @@ -252,22 +256,21 @@ balloon_alert(user, "installed new part") user.transferItemToLoc(object, src) installed_part = object - return TRUE + return ITEM_INTERACT_SUCCESS /// Gets the efficiency of the installed part, returns 0 if no part is installed /obj/machinery/power/turbine/proc/get_efficiency() + SHOULD_BE_PURE(TRUE) + return installed_part?.part_efficiency || 0 /obj/machinery/power/turbine/inlet_compressor name = "inlet compressor" desc = "The input side of a turbine generator, contains the compressor." - icon = 'icons/obj/machines/engine/turbine.dmi' icon_state = "inlet_compressor" + base_icon_state = "inlet" circuit = /obj/item/circuitboard/machine/turbine_compressor part_path = /obj/item/turbine_parts/compressor - active_overlay = "inlet_animation" - off_overlay = "inlet_off" - open_overlay = "inlet_open" /// The rotor this inlet is linked to var/obj/machinery/power/turbine/core_rotor/rotor @@ -296,6 +299,8 @@ * Returns temperature of the gas mix absorbed only if some work was done */ /obj/machinery/power/turbine/inlet_compressor/proc/compress_gases() + SHOULD_NOT_OVERRIDE(TRUE) + compressor_work = 0 compressor_pressure = MINIMUM_TURBINE_PRESSURE if(QDELETED(input_turf)) @@ -314,16 +319,14 @@ return input_turf_mixture.temperature +//===========================OUTLET============================================== /obj/machinery/power/turbine/turbine_outlet name = "turbine outlet" desc = "The output side of a turbine generator, contains the turbine and the stator." - icon = 'icons/obj/machines/engine/turbine.dmi' icon_state = "turbine_outlet" + base_icon_state = "outlet" circuit = /obj/item/circuitboard/machine/turbine_stator part_path = /obj/item/turbine_parts/stator - active_overlay = "outlet_animation" - off_overlay = "outlet_off" - open_overlay = "outlet_open" /// The rotor this outlet is linked to var/obj/machinery/power/turbine/core_rotor/rotor @@ -343,6 +346,8 @@ /// push gases from its gas mix to output turf /obj/machinery/power/turbine/turbine_outlet/proc/expel_gases() + SHOULD_NOT_OVERRIDE(TRUE) + if(QDELETED(output_turf)) output_turf = get_step(loc, dir) //turf is blocked don't eject gases @@ -358,18 +363,16 @@ //return ejected gases return ejected_gases +//===========================================CORE ROTOR========================================= /obj/machinery/power/turbine/core_rotor name = "core rotor" desc = "The middle part of a turbine generator, contains the rotor and the main computer." - icon = 'icons/obj/machines/engine/turbine.dmi' icon_state = "core_rotor" - active_overlay = "core_light" - open_overlay = "core_open" - active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION - emissive = TRUE + base_icon_state = "core" can_change_cable_layer = TRUE circuit = /obj/item/circuitboard/machine/turbine_rotor part_path = /obj/item/turbine_parts/rotor + overlay_flags = EMISSIVE_OVERLAY | NO_INACTIVE_OVERLAY ///ID to easily connect the main part of the turbine to the computer var/mapping_id @@ -378,9 +381,9 @@ ///Reference to the turbine var/obj/machinery/power/turbine/turbine_outlet/turbine ///Rotation per minute the machine is doing - var/rpm + var/rpm = 0 ///Amount of power the machine is producing - var/produced_energy + var/produced_energy = 0 ///Check to see if all parts are connected to the core var/all_parts_connected = FALSE ///Max rmp that the installed parts can handle, limits the rpms @@ -462,16 +465,21 @@ //works same as regular left click return multitool_act(user, tool) -/// convinience proc for balloon alert which returns if viewer is null +/** + * convinience proc for balloon alert which returns if viewer is null + * Arguments + * + * * mob/viewer - the player receiving the message + * * text - the message + */ /obj/machinery/power/turbine/core_rotor/proc/feedback(mob/viewer, text) + PRIVATE_PROC(TRUE) + if(isnull(viewer)) return balloon_alert(viewer, text) -/** - * Called to activate the complete machine, checks for part presence, correct orientation and installed parts - * Registers the input/output turfs - */ +///Called to activate the complete machine, checks for part presence, correct orientation and installed parts /obj/machinery/power/turbine/core_rotor/activate_parts(mob/user, check_only = FALSE) //if this is not a checkup and all parts are connected then we have nothing to do if(!check_only && all_parts_connected) @@ -479,13 +487,18 @@ //locate compressor & turbine, when checking we simply check to see if they are still there if(!check_only) - compressor = locate(/obj/machinery/power/turbine/inlet_compressor) in get_step(src, REVERSE_DIR(dir)) - turbine = locate(/obj/machinery/power/turbine/turbine_outlet) in get_step(src, dir) + compressor = locate() in get_step(src, REVERSE_DIR(dir)) + turbine = locate() in get_step(src, dir) - //maybe look for them the other way around. we want the rotor to allign with them either way for player convinience - if(!compressor && !turbine) - compressor = locate(/obj/machinery/power/turbine/inlet_compressor) in get_step(src, dir) - turbine = locate(/obj/machinery/power/turbine/turbine_outlet) in get_step(src, REVERSE_DIR(dir)) + //maybe look for them the other way around. this means the rotor is facing the wrong way + if(QDELETED(compressor) && QDELETED(turbine)) + compressor = locate() in get_step(src, dir) + turbine = locate() in get_step(src, REVERSE_DIR(dir)) + + //show corrective actions + if(!QDELETED(compressor) || !QDELETED(turbine)) + feedback(user, "rotor is facing the wrong way!") + return (all_parts_connected = FALSE) //sanity checks for compressor if(QDELETED(compressor)) @@ -505,17 +518,17 @@ if(QDELETED(turbine)) feedback(user, "missing turbine!") return (all_parts_connected = FALSE) - if(turbine.dir != dir && turbine.dir != REVERSE_DIR(dir)) + if(turbine.dir != dir && turbine.dir != REVERSE_DIR(dir)) //make sure it's not perpendicular to the rotor feedback(user, "turbine not aligned with rotor!") return (all_parts_connected = FALSE) if(!turbine.can_connect) - feedback(user, "turbine panel is either open or is misplaced!") //we say misplaced because can_connect becomes FALSE when this turbine is moved + feedback(user, "close turbine panel!") //we say misplaced because can_connect becomes FALSE when this turbine is moved return (all_parts_connected = FALSE) if(!turbine.installed_part) feedback(user, "turbine is missing stator part!") return (all_parts_connected = FALSE) - //final sanity check to make sure turbine & compressor are facing the same direction. From an visual perspective they will appear facing away from each other actually. I know blame spriter's + //sanity check to make sure turbine & compressor are facing the same direction. From an visual perspective they will appear facing away from each other actually. I know blame spriter's if(compressor.dir != turbine.dir) feedback(user, "turbine & compressor are not facing away from each other!") return (all_parts_connected = FALSE) @@ -537,85 +550,60 @@ * Allows to null the various machines and references from the main core */ /obj/machinery/power/turbine/core_rotor/deactivate_parts() - if(all_parts_connected) - power_off() + toggle_power(force_off = TRUE) compressor?.rotor = null compressor = null turbine?.rotor = null turbine = null all_parts_connected = FALSE disconnect_from_network() - SSair.stop_processing_machine(src) /obj/machinery/power/turbine/core_rotor/on_deconstruction(disassembled) deactivate_parts() return ..() /// Toggle power on and off, not safe -/obj/machinery/power/turbine/core_rotor/proc/toggle_power() +/obj/machinery/power/turbine/core_rotor/proc/toggle_power(force_off) + SHOULD_NOT_OVERRIDE(TRUE) + + //toggle status + if(force_off) + if(!active) //was already off + return + active = FALSE + else + active = !active + + //update operation status of parts + update_appearance(UPDATE_OVERLAYS) + if(!QDELETED(compressor)) + compressor.active = active + compressor.update_appearance(UPDATE_OVERLAYS) + if(!QDELETED(turbine)) + turbine.active = active + turbine.update_appearance(UPDATE_OVERLAYS) + + //start or stop processing if(active) - power_off() - return - power_on() - -/** - * Activate all three parts, not safe, it assumes the machine already connected and properly working - * It does a minimun check to ensure the parts still exist - */ -/obj/machinery/power/turbine/core_rotor/proc/power_on() - if(active || QDELETED(compressor) || QDELETED(turbine)) - return - active = TRUE - compressor.active = TRUE - turbine.active = TRUE - call_parts_update_appearance() - SSair.start_processing_machine(src) - -/// Calls all parts update appearance proc. -/obj/machinery/power/turbine/core_rotor/proc/call_parts_update_appearance() - update_appearance() - if(!QDELETED(compressor)) - compressor.update_appearance() - if(!QDELETED(turbine)) - turbine.update_appearance() - -/** - * Deactivate all three parts, not safe, it assumes the machine already connected and properly working - * will try to turn off whatever components are left of this machine - */ -/obj/machinery/power/turbine/core_rotor/proc/power_off() - if(!active) - return - active = FALSE - if(!QDELETED(compressor)) - compressor.active = FALSE - if(!QDELETED(turbine)) - turbine.active = FALSE - call_parts_update_appearance() - SSair.stop_processing_machine(src) - -/// Returns true if all parts have their panel closed -/obj/machinery/power/turbine/core_rotor/proc/all_parts_ready() - if(QDELETED(compressor)) - return FALSE - if(QDELETED(turbine)) - return FALSE - return !panel_open && !compressor.panel_open && !turbine.panel_open + update_mode_power_usage(ACTIVE_POWER_USE, active_power_usage) + begin_processing() + else + unset_static_power() + end_processing() /// Getter for turbine integrity, return the amount in % /obj/machinery/power/turbine/core_rotor/proc/get_turbine_integrity() + SHOULD_NOT_OVERRIDE(TRUE) + var/integrity = damage / 500 integrity = max(round(100 - integrity * 100, 0.01), 0) return integrity -/obj/machinery/power/turbine/core_rotor/process_atmos() +/obj/machinery/power/turbine/core_rotor/process(seconds_per_tick) if(!active || !activate_parts(check_only = TRUE) || (machine_stat & BROKEN) || !powered(ignore_use_power = TRUE)) - power_off() + deactivate_parts() return PROCESS_KILL - //use power to operate internal electronics & stuff - update_mode_power_usage(ACTIVE_POWER_USE, active_power_usage) - //===============COMPRESSOR WORKING========// //Transfer gases from turf to compressor var/temperature = compressor.compress_gases() @@ -668,9 +656,9 @@ work_done = max(work_done - compressor.compressor_work * TURBINE_COMPRESSOR_STATOR_INTERACTION_MULTIPLIER - turbine_work, 0) //calculate final acheived rpm rpm = ((work_done * compressor.get_efficiency()) ** turbine.get_efficiency()) * get_efficiency() / TURBINE_RPM_CONVERSION - rpm = FLOOR(min(rpm, max_allowed_rpm), 1) + rpm = min(ROUND_UP(rpm), max_allowed_rpm) //add energy into the grid, also use part of it for turbine operation - produced_energy = rpm * TURBINE_ENERGY_RECTIFICATION_MULTIPLIER * TURBINE_RPM_CONVERSION + produced_energy = rpm * TURBINE_ENERGY_RECTIFICATION_MULTIPLIER * TURBINE_RPM_CONVERSION * seconds_per_tick add_avail(produced_energy) /obj/item/paper/guides/jobs/atmos/turbine @@ -686,3 +674,5 @@ #undef PRESSURE_MAX #undef MINIMUM_TURBINE_PRESSURE +#undef EMISSIVE_OVERLAY +#undef NO_INACTIVE_OVERLAY diff --git a/code/modules/power/turbine/turbine_computer.dm b/code/modules/power/turbine/turbine_computer.dm index 36a556daefb..7771bda03f8 100644 --- a/code/modules/power/turbine/turbine_computer.dm +++ b/code/modules/power/turbine/turbine_computer.dm @@ -20,8 +20,8 @@ register_machine(main) break -/obj/machinery/computer/turbine_computer/multitool_act(mob/living/user, obj/item/tool) - var/obj/item/multitool/multitool = tool +/obj/machinery/computer/turbine_computer/multitool_act(mob/living/user, obj/item/multitool/multitool) + . = ITEM_INTERACT_FAILURE if(!istype(multitool.buffer, /obj/machinery/power/turbine/core_rotor)) to_chat(user, span_notice("Wrong machine type in [multitool] buffer...")) return @@ -29,12 +29,21 @@ to_chat(user, span_notice("Changing [src] bluespace network...")) if(!do_after(user, 0.2 SECONDS, src)) return + playsound(get_turf(user), 'sound/machines/click.ogg', 10, TRUE) register_machine(multitool.buffer) to_chat(user, span_notice("You link [src] to the console in [multitool]'s buffer.")) - return TRUE + return ITEM_INTERACT_SUCCESS + +/** + * Links the rotor with this computer + * Arguments + * + * * obj/machinery/power/turbine/core_rotor/machine - the machine to link + */ +/obj/machinery/computer/turbine_computer/proc/register_machine(obj/machinery/power/turbine/core_rotor/machine) + PRIVATE_PROC(TRUE) -/obj/machinery/computer/turbine_computer/proc/register_machine(machine) turbine_core = WEAKREF(machine) /obj/machinery/computer/turbine_computer/ui_interact(mob/user, datum/tgui/ui) @@ -45,26 +54,27 @@ ui.open() /obj/machinery/computer/turbine_computer/ui_data(mob/user) - var/list/data = list() + . = list() + //do we have the main rotor with all parts connected var/obj/machinery/power/turbine/core_rotor/main_control = turbine_core?.resolve() - data["connected"] = !!QDELETED(main_control) - if(!main_control) + if(QDELETED(main_control) || !main_control.all_parts_connected) + .["connected"] = FALSE return + else + .["connected"] = TRUE - data["active"] = main_control.active - data["rpm"] = main_control.rpm ? main_control.rpm : 0 - data["power"] = main_control.produced_energy ? main_control.produced_energy : 0 - data["integrity"] = main_control.get_turbine_integrity() - data["parts_linked"] = main_control.all_parts_connected - data["parts_ready"] = main_control.all_parts_ready() + //operation status + .["active"] = main_control.active + .["rpm"] = main_control.rpm + .["power"] = energy_to_power(main_control.produced_energy) + .["integrity"] = main_control.get_turbine_integrity() - data["max_rpm"] = main_control.max_allowed_rpm - data["max_temperature"] = main_control.max_allowed_temperature - data["temp"] = main_control.compressor?.input_turf?.air.temperature || 0 - data["regulator"] = QDELETED(main_control.compressor) ? 0 : main_control.compressor.intake_regulator - - return data + //running parameters + .["max_rpm"] = main_control.max_allowed_rpm + .["max_temperature"] = main_control.max_allowed_temperature + .["temp"] = main_control.compressor.input_turf?.air.temperature || 0 + .["regulator"] = main_control.compressor.intake_regulator /obj/machinery/computer/turbine_computer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() @@ -74,19 +84,35 @@ switch(action) if("toggle_power") var/obj/machinery/power/turbine/core_rotor/main_control = turbine_core?.resolve() - if(!main_control || !main_control.all_parts_connected || main_control.rpm > 1000) - return TRUE - if(!main_control.activate_parts(usr, check_only = TRUE)) - return TRUE + if(!main_control) + return FALSE + + if(!main_control.active) //turning on the machine requires all part to be linked + if(!main_control.activate_parts(ui.user, check_only = TRUE)) + return FALSE + else if(main_control.rpm > 1000) //turning off requires rpm to be less than 1000 + return FALSE + main_control.toggle_power() main_control.rpm = 0 main_control.produced_energy = 0 - . = TRUE + return TRUE + if("regulate") - var/intake_size = text2num(params["regulate"]) + var/intake_size = params["regulate"] + if(isnull(intake_size)) + return FALSE + + intake_size = text2num(intake_size) + if(isnull(intake_size)) + return FALSE + var/obj/machinery/power/turbine/core_rotor/main_control = turbine_core?.resolve() - if(intake_size == null || !main_control) - return - if(!QDELETED(main_control.compressor)) - main_control.compressor.intake_regulator = clamp(intake_size, 0.01, 1) - . = TRUE + if(!main_control) + return FALSE + + if(QDELETED(main_control.compressor)) + return FALSE + + main_control.compressor.intake_regulator = clamp(intake_size, 0.01, 1) + return TRUE diff --git a/code/modules/power/turbine/turbine_parts.dm b/code/modules/power/turbine/turbine_parts.dm index 4215fccf39f..e568f9e0964 100644 --- a/code/modules/power/turbine/turbine_parts.dm +++ b/code/modules/power/turbine/turbine_parts.dm @@ -1,3 +1,8 @@ +///String to access turbine part typepath to upgrade +#define TURBINE_UPGRADE_PART "part" +///String to access turbine part required amount to upgrade +#define TURBINE_UPGRADE_AMOUNT "amount" + /obj/item/turbine_parts name = "turbine parts" desc = "you really should call an admin" @@ -8,90 +13,62 @@ var/part_efficiency = 0 ///Efficiency increase amount for each tier var/part_efficiency_increase_amount = 0 - ///Current part tier var/current_tier = TURBINE_PART_TIER_ONE - ///Max part tier - var/max_tier = TURBINE_PART_TIER_FOUR - - ///Stores the path of the material for the second tier upgrade - var/obj/item/stack/sheet/second_tier_material = /obj/item/stack/sheet/plasteel - ///Amount of second tier material for the upgrade - var/second_tier_material_amount = 10 - - ///Stores the path of the material for the third tier upgrade - var/obj/item/stack/sheet/third_tier_material = /obj/item/stack/sheet/mineral/titanium - ///Amount of third tier material for the upgrade - var/third_tier_material_amount = 10 - - ///Stores the path of the material for the fourth tier upgrade - var/obj/item/stack/sheet/fourth_tier_material = /obj/item/stack/sheet/mineral/metal_hydrogen - ///Amount of fourth tier material for the upgrade - var/fourth_tier_material_amount = 5 - ///Max rpm reachable by the part var/max_rpm = 35000 - ///Multiplier to increase the max rpm per tier, max should be around 500000 rpm - var/max_rpm_tier_multiplier = 2.5 - ///Max temperature achievable by the part before the turbine starts to take damage var/max_temperature = 50000 - ///Max temperature exponential value per tier - var/max_temperature_tier_exponential = 1.2 /obj/item/turbine_parts/examine(mob/user) . = ..() - . += "This is a tier [current_tier] turbine part, rated for [max_rpm] rpm and [max_temperature] K." - var/upgrade_material_name_amount - switch(current_tier) - if(TURBINE_PART_TIER_ONE) - upgrade_material_name_amount = "[second_tier_material_amount] [initial(second_tier_material.name)] sheets" - if(TURBINE_PART_TIER_TWO) - upgrade_material_name_amount = "[third_tier_material_amount] [initial(third_tier_material.name)] sheets" - if(TURBINE_PART_TIER_THREE) - upgrade_material_name_amount = "[fourth_tier_material_amount] [initial(fourth_tier_material.name)] sheets" + . += span_notice("This is a tier [current_tier] turbine part, rated for [max_rpm] rpm and [max_temperature] K.") - if(upgrade_material_name_amount) - . += "Can be upgraded with [upgrade_material_name_amount]." + var/list/required_parts = get_tier_upgrades() + if(length(required_parts)) + var/obj/item/stack/material = required_parts[TURBINE_UPGRADE_PART] + . += span_notice("Can be upgraded with [required_parts[TURBINE_UPGRADE_AMOUNT]] [initial(material.name)] sheets.") else - . += "Is already at max tier." + . += span_notice("Is already at max tier.") + +///Returns a list containing the typepath & amount of it required to upgrade to the next tier +/obj/item/turbine_parts/proc/get_tier_upgrades() + PROTECTED_PROC(TRUE) + SHOULD_BE_PURE(TRUE) + RETURN_TYPE(/list) -/obj/item/turbine_parts/attackby(obj/item/attacking_item, mob/user, params) - if(current_tier >= max_tier) - return FALSE switch(current_tier) if(TURBINE_PART_TIER_ONE) - if(!istype(attacking_item, second_tier_material)) - return - var/obj/item/stack/sheet/second_tier = attacking_item - if(do_after(user, 1 SECONDS, src) && second_tier.use(second_tier_material_amount)) - current_tier = 2 - part_efficiency += part_efficiency_increase_amount - max_rpm *= max_rpm_tier_multiplier - max_temperature = max_temperature ** max_temperature_tier_exponential - return TRUE + return list(TURBINE_UPGRADE_PART = /obj/item/stack/sheet/plasteel, TURBINE_UPGRADE_AMOUNT = 10) if(TURBINE_PART_TIER_TWO) - if(!istype(attacking_item, third_tier_material)) - return - var/obj/item/stack/sheet/third_tier = attacking_item - if(do_after(user, 2 SECONDS, src) && third_tier.use(third_tier_material_amount)) - current_tier = 3 - part_efficiency += part_efficiency_increase_amount - max_rpm *= max_rpm_tier_multiplier - max_temperature = max_temperature ** max_temperature_tier_exponential - return TRUE + return list(TURBINE_UPGRADE_PART = /obj/item/stack/sheet/mineral/titanium, TURBINE_UPGRADE_AMOUNT = 10) if(TURBINE_PART_TIER_THREE) - if(!istype(attacking_item, fourth_tier_material)) - return - var/obj/item/stack/sheet/fourth_tier = attacking_item - if(do_after(user, 3 SECONDS, src) && fourth_tier.use(fourth_tier_material_amount)) - current_tier = 4 - part_efficiency += part_efficiency_increase_amount - max_rpm *= max_rpm_tier_multiplier - max_temperature = max_temperature ** max_temperature_tier_exponential - return TRUE + return list(TURBINE_UPGRADE_PART = /obj/item/stack/sheet/mineral/metal_hydrogen, TURBINE_UPGRADE_AMOUNT = 5) - return ..() +/obj/item/turbine_parts/item_interaction(mob/living/user, obj/item/attacking_item, list/modifiers) + . = NONE + + var/list/required_parts = get_tier_upgrades() + if(!length(required_parts)) + balloon_alert(user, "already at max tier!") + return ITEM_INTERACT_FAILURE + + var/obj/item/stack/sheet/material = attacking_item + if(!istype(material, required_parts[TURBINE_UPGRADE_PART])) + balloon_alert(user, "incorrect part!") + return ITEM_INTERACT_FAILURE + + var/amount = required_parts[TURBINE_UPGRADE_AMOUNT] + if(material.amount < amount) + balloon_alert(user, "requires [amount] sheets!") + return ITEM_INTERACT_FAILURE + + if(do_after(user, current_tier SECONDS, src) && material.use(amount)) + current_tier += 1 + part_efficiency += part_efficiency_increase_amount + max_rpm *= 2.5 + max_temperature = max_temperature ** 1.2 + return ITEM_INTERACT_SUCCESS /obj/item/turbine_parts/compressor name = "compressor part" @@ -113,9 +90,15 @@ icon_state = "stator_part" part_efficiency = 0.85 part_efficiency_increase_amount = 0.015 - second_tier_material = /obj/item/stack/sheet/mineral/titanium - third_tier_material = /obj/item/stack/sheet/mineral/metal_hydrogen - fourth_tier_material = /obj/item/stack/sheet/mineral/zaukerite - second_tier_material_amount = 15 - third_tier_material_amount = 15 - fourth_tier_material_amount = 10 + +/obj/item/turbine_parts/stator/get_tier_upgrades() + switch(current_tier) + if(TURBINE_PART_TIER_ONE) + return list(TURBINE_UPGRADE_PART = /obj/item/stack/sheet/mineral/titanium, TURBINE_UPGRADE_AMOUNT = 15) + if(TURBINE_PART_TIER_TWO) + return list(TURBINE_UPGRADE_PART = /obj/item/stack/sheet/mineral/metal_hydrogen, TURBINE_UPGRADE_AMOUNT = 15) + if(TURBINE_PART_TIER_THREE) + return list(TURBINE_UPGRADE_PART = /obj/item/stack/sheet/mineral/zaukerite, TURBINE_UPGRADE_AMOUNT = 10) + +#undef TURBINE_UPGRADE_PART +#undef TURBINE_UPGRADE_AMOUNT diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm index 6a2bda4ee25..241d7b54c39 100644 --- a/code/modules/unit_tests/unit_test.dm +++ b/code/modules/unit_tests/unit_test.dm @@ -254,6 +254,8 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests()) //Yet more templates /obj/machinery/restaurant_portal, //Template type + /obj/machinery/power/turbine, + //Template type /obj/effect/mob_spawn, //Template type /obj/structure/holosign/robot_seat, diff --git a/icons/obj/machines/engine/turbine.dmi b/icons/obj/machines/engine/turbine.dmi index 1ae45eb2a1b1f7a28a0bea8f3ed600e29cb29bff..afd9839af1341893312eb208bde380df4ff5e64b 100644 GIT binary patch delta 5370 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 KcBQ7>v;P5V-}M*( delta 5392 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 { +const TurbineDisplay = (props) => { const { act, data } = useBackend(); - const parts_not_connected = !data.parts_linked && ( + + return ( +
= 1000)} + onClick={() => act('toggle_power')} + > + {data.active ? 'Online' : 'Offline'} + + } + > + + + + act('regulate', { + regulate: value * 0.01, + }) + } + /> + + + + + + {data.rpm} RPM + + + {data.max_rpm} RPM + + + {data.temp} K + + + {data.max_temperature} K + + + {formatPower(data.power)} + + +
+ ); +}; + +const OutOfService = (props) => { + return ( - - { - 'Parts not connected, use a multitool on the core rotor before trying again' - } - - - ); - const parts_not_ready = data.parts_linked && !data.parts_ready && ( - - - { - 'Some parts have open maintenance hatchet, please close them before starting' - } - + + + + { + 'Parts not connected, close all mantainence panels/use a multitool on the rotor before trying again' + } + + + ); +}; + +export const TurbineComputer = (props) => { + const { data } = useBackend(); + return ( -
= 1000) || !data.parts_linked} - onClick={() => act('toggle_power')} - /> - } - > - {parts_not_connected} - {parts_not_ready} - - - - act('regulate', { - regulate: value * 0.01, - }) - } - /> - - - - - - {data.rpm} RPM - - - {data.max_rpm} RPM - - - {data.temp} K - - - {data.max_temperature} K - - - {data.power * 4 * 0.001} kW - - -
+ {data.connected ? : }
);