From 614d01c1f792dee657bdf4e9e80014d307885279 Mon Sep 17 00:00:00 2001
From: SkyratBot <59378654+SkyratBot@users.noreply.github.com>
Date: Mon, 26 Apr 2021 13:01:21 +0200
Subject: [PATCH] [MIRROR] Thermomachine heat exploit fix (#5216)
* Thermomachine heat exploit fix (#58390)
Stops thermomachines from going over the fusion max temperature with the safeties on (safeties can only be disabled after emag or EMP).
Without the safeties on the machine has a chance of explosion (0, 0, 3)
* Thermomachine heat exploit fix
Co-authored-by: Ghilker <42839747+Ghilker@users.noreply.github.com>
---
code/__DEFINES/atmospherics.dm | 8 ++
.../binary_devices/thermomachine.dm | 91 ++++++++++++++++++-
.../components/fusion/hfr_defines.dm | 6 --
.../packages/tgui/interfaces/ThermoMachine.js | 7 ++
4 files changed, 104 insertions(+), 8 deletions(-)
diff --git a/code/__DEFINES/atmospherics.dm b/code/__DEFINES/atmospherics.dm
index 696af2ffe6e..fc7255140bf 100644
--- a/code/__DEFINES/atmospherics.dm
+++ b/code/__DEFINES/atmospherics.dm
@@ -142,6 +142,14 @@
#define REACTING 1
#define STOP_REACTIONS 2
+//Fusion
+///Max amount of radiation that can be emitted per reaction cycle
+#define FUSION_RAD_MAX 5000
+///Maximum instability before the reaction goes endothermic
+#define FUSION_INSTABILITY_ENDOTHERMALITY 4
+///Maximum reachable fusion temperature
+#define FUSION_MAXIMUM_TEMPERATURE 1e8
+
// Pressure limits.
/// This determins at what pressure the ultra-high pressure red icon is displayed. (This one is set as a constant)
#define HAZARD_HIGH_PRESSURE 550
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/thermomachine.dm b/code/modules/atmospherics/machinery/components/binary_devices/thermomachine.dm
index f2a4ca01855..557aa1e9dd6 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/thermomachine.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/thermomachine.dm
@@ -1,3 +1,5 @@
+#define THERMOMACHINE_SAFE_TEMPERATURE 500000
+
/obj/machinery/atmospherics/components/binary/thermomachine
icon = 'icons/obj/atmospherics/components/thermomachine.dmi'
icon_state = "freezer"
@@ -33,6 +35,8 @@
var/use_enviroment_heat = FALSE
var/skipping_work = FALSE
var/auto_thermal_regulator = FALSE
+ var/safeties = TRUE
+ var/lastwarning
var/color_index = 1
/obj/machinery/atmospherics/components/binary/thermomachine/Initialize()
@@ -104,6 +108,8 @@
/obj/machinery/atmospherics/components/binary/thermomachine/examine(mob/user)
. = ..()
+ if(obj_flags & EMAGGED)
+ . += "Something seems wrong with [src]'s thermal safeties."
. += "With the panel open:"
. += "-use a wrench with left-click to rotate [src] and right-click to unanchor it."
. += "-use a multitool with left-click to change the piping layer and right-click to change the piping color."
@@ -156,13 +162,25 @@
var/temperature_difference = 0
var/skip_tick = TRUE
if(!use_enviroment_heat && main_port.total_moles() > 0.01)
- if(cooling && thermal_exchange_port.total_moles() > 0.01 && nodes[2])
+ if(cooling && thermal_exchange_port.total_moles() > 0.01 && nodes[2] && (thermal_exchange_port.temperature <= THERMOMACHINE_SAFE_TEMPERATURE || !safeties))
thermal_exchange_port.temperature = max(thermal_exchange_port.temperature + heat_amount / thermal_heat_capacity + motor_heat / thermal_heat_capacity, TCMB)
else if(cooling && (!thermal_exchange_port.total_moles() || !nodes[2]))
skipping_work = skip_tick
update_appearance()
update_parents()
return
+ if(thermal_exchange_port.temperature > THERMOMACHINE_SAFE_TEMPERATURE && safeties)
+ on = FALSE
+ visible_message("The thermal exchange port's temperature has reached critical levels, shutting down...")
+ update_appearance()
+ return
+ else if(thermal_exchange_port.temperature > THERMOMACHINE_SAFE_TEMPERATURE && !safeties)
+ if((REALTIMEOFDAY - lastwarning) / 5 >= WARNING_DELAY)
+ lastwarning = REALTIMEOFDAY
+ visible_message("The thermal exchange port's temperature has reached critical levels!")
+ if(check_explosion(thermal_exchange_port.temperature))
+ explode()
+ return PROCESS_KILL //we dying anyway, so let's stop processing
temperature_difference = thermal_exchange_port.temperature - main_port.temperature
temperature_difference = cooling ? temperature_difference : 0
if(temperature_difference > 0)
@@ -171,7 +189,7 @@
skip_tick = FALSE
if(use_enviroment_heat && main_port.total_moles() > 0.01)
var/enviroment_efficiency = 1
- if(cooling && enviroment.total_moles() > 0.01)
+ if(cooling && enviroment.total_moles() > 0.01 && (thermal_exchange_port.temperature <= THERMOMACHINE_SAFE_TEMPERATURE || !safeties))
var/enviroment_heat_capacity = enviroment.heat_capacity()
if(enviroment.total_moles())
enviroment_efficiency = clamp(log(1.55, enviroment.total_moles()) * 0.15, 0.65, 1)
@@ -182,6 +200,18 @@
update_appearance()
update_parents()
return
+ if(enviroment.temperature > THERMOMACHINE_SAFE_TEMPERATURE && safeties)
+ on = FALSE
+ visible_message("The enviroment's temperature has reached critical levels, shutting down...")
+ update_appearance()
+ return
+ else if(enviroment.temperature > THERMOMACHINE_SAFE_TEMPERATURE && !safeties)
+ if((REALTIMEOFDAY - lastwarning) / 5 >= WARNING_DELAY)
+ lastwarning = REALTIMEOFDAY
+ visible_message("The enviroment's temperature has reached critical levels!")
+ if(check_explosion(enviroment.temperature))
+ explode()
+ return PROCESS_KILL //we dying anyway, so let's stop processing
temperature_difference = enviroment.temperature - main_port.temperature
temperature_difference = cooling ? temperature_difference : 0
if(temperature_difference > 0)
@@ -297,6 +327,37 @@
return TRUE
return FALSE
+/obj/machinery/atmospherics/components/binary/thermomachine/multitool_act(mob/living/user, obj/item/multitool/multitool)
+ if(!istype(multitool))
+ return
+ if(panel_open && !anchored)
+ piping_layer = (piping_layer >= PIPING_LAYER_MAX) ? PIPING_LAYER_MIN : (piping_layer + 1)
+ to_chat(user, "You change the circuitboard to layer [piping_layer].")
+ update_appearance()
+
+/obj/machinery/atmospherics/components/binary/thermomachine/emag_act(mob/user)
+ . = ..()
+ if(!(obj_flags & EMAGGED))
+ if(!do_after(user, 1 SECONDS, src))
+ return
+ var/datum/effect_system/spark_spread/sparks = new
+ sparks.set_up(5, 0, src)
+ sparks.attach(src)
+ sparks.start()
+ obj_flags |= EMAGGED
+ user.visible_message("You emag [src], overwriting thermal safety restrictions.")
+ log_game("[key_name(user)] emagged [src] at [AREACOORD(src)], overwriting thermal safety restrictions.")
+
+/obj/machinery/atmospherics/components/binary/thermomachine/emp_act()
+ . = ..()
+ if(!(obj_flags & EMAGGED))
+ var/datum/effect_system/spark_spread/sparks = new
+ sparks.set_up(5, 0, src)
+ sparks.attach(src)
+ sparks.start()
+ obj_flags |= EMAGGED
+ safeties = FALSE
+
/obj/machinery/atmospherics/components/binary/thermomachine/proc/replace_tank(mob/living/user, obj/item/tank/new_tank)
if(!user)
return FALSE
@@ -308,6 +369,23 @@
update_appearance()
return TRUE
+/obj/machinery/atmospherics/components/binary/thermomachine/proc/check_explosion(temperature)
+ if(temperature < THERMOMACHINE_SAFE_TEMPERATURE + 2000)
+ return FALSE
+ if(prob(log(6, temperature) * 10)) //75% at 500000, 100% at 1e8
+ return TRUE
+
+/obj/machinery/atmospherics/components/binary/thermomachine/proc/explode()
+ explosion(loc, 0, 0, 3, 3, TRUE)
+ var/datum/gas_mixture/main_port = airs[1]
+ var/datum/gas_mixture/thermal_exchange_port = airs[2]
+ if(main_port)
+ loc.assume_air(main_port.remove_ratio(1))
+ if(thermal_exchange_port)
+ loc.assume_air(thermal_exchange_port.remove_ratio(1))
+ air_update_turf(FALSE, FALSE)
+ qdel(src)
+
/obj/machinery/atmospherics/components/binary/thermomachine/ui_status(mob/user)
if(interactive)
return ..()
@@ -342,6 +420,9 @@
data["use_env_heat"] = use_enviroment_heat
data["skipping_work"] = skipping_work
data["auto_thermal_regulator"] = auto_thermal_regulator
+ data["safeties"] = safeties
+ var/hacked = (obj_flags & EMAGGED) ? TRUE : FALSE
+ data["hacked"] = hacked
return data
/obj/machinery/atmospherics/components/binary/thermomachine/ui_act(action, params)
@@ -391,6 +472,10 @@
if("auto_thermal_regulator")
auto_thermal_regulator = !auto_thermal_regulator
. = TRUE
+ if("safeties")
+ safeties = !safeties
+ investigate_log("[key_name(usr)] turned off the [src] safeties", INVESTIGATE_ATMOS)
+ . = TRUE
update_appearance()
@@ -437,3 +522,5 @@
/obj/machinery/atmospherics/components/binary/thermomachine/heater/on
on = TRUE
icon_state = "heater_1"
+
+#undef THERMOMACHINE_SAFE_TEMPERATURE
diff --git a/code/modules/atmospherics/machinery/components/fusion/hfr_defines.dm b/code/modules/atmospherics/machinery/components/fusion/hfr_defines.dm
index 0f9478ec6ce..8294546d0f1 100644
--- a/code/modules/atmospherics/machinery/components/fusion/hfr_defines.dm
+++ b/code/modules/atmospherics/machinery/components/fusion/hfr_defines.dm
@@ -1,9 +1,3 @@
-///Max amount of radiation that can be emitted per reaction cycle
-#define FUSION_RAD_MAX 5000
-///Maximum instability before the reaction goes endothermic
-#define FUSION_INSTABILITY_ENDOTHERMALITY 4
-///Maximum reachable fusion temperature
-#define FUSION_MAXIMUM_TEMPERATURE 1e8
///Speed of light, in m/s
#define LIGHT_SPEED 299792458
///Calculation between the plank constant and the lambda of the lightwave
diff --git a/tgui/packages/tgui/interfaces/ThermoMachine.js b/tgui/packages/tgui/interfaces/ThermoMachine.js
index 7863ce888b1..49536c95511 100644
--- a/tgui/packages/tgui/interfaces/ThermoMachine.js
+++ b/tgui/packages/tgui/interfaces/ThermoMachine.js
@@ -48,6 +48,13 @@ export const ThermoMachine = (props, context) => {
onClick={() => act('power')} />
)}>
+
+