at what point does our ZAS implementation become sunk cost (#4409)

* begin

* wip

* stuff

* aough

* stuff

* fix

* fix

* ayo?

* space

* fix

* more

* aough

* sigh

* maybe

* a

* a

* don't need that

* that

* fix

* fix_maybe

Co-authored-by: VM_USER <VM_USER>
This commit is contained in:
silicons
2022-09-15 14:37:26 -07:00
committed by GitHub
parent 39a9b2fb79
commit bffcb7810d
41 changed files with 388 additions and 219 deletions

View File

@@ -70,6 +70,8 @@
#define MINIMUM_MEANINGFUL_MOLES_DELTA 0.01
/// minimum temperature difference before we can stop ticking/just equalize
#define MINIMUM_MEANINGFUL_TEMPERATURE_DELTA 0.5
/// minimum pressure difference before we can stop ticking/just equalize
#define MINIMUM_MEANINGFUL_PRESSURE_DELTA 0.5
/// when checking for vacuum we're fine with pressure as long as it's below this
#define MINIMUM_MEANINGFUL_PRESSURE_VACUUM 5
/// ZAS: if a sharer and our moles are below this, we nuke both to 0 because we consider it a vacuum

View File

@@ -1,11 +1,13 @@
// CANATMOSPASS
// make sure it's in this order so we cann use min()
//! these are actual return values, using them in CanAtmosPass results in it always be returned.
/// lets everything through
#define ATMOS_PASS_NOT_BLOCKED 2
/// block zone merging through this but not air
#define ATMOS_PASS_ZONE_BLOCKED 1
/// blocks everything
#define ATMOS_PASS_AIR_BLOCKED 0
//! these are hints we can use in CanAtmosPass
/// ask CanAtmosPass()
#define ATMOS_PASS_PROC -1
/// if dense, air blocked, else, not blocked
@@ -13,8 +15,8 @@
/// ONLY FOR VERTICAL ATMOS PASS - check normal CanAtmosPass
#define ATMOS_PASS_VERTICAL_DEFAULT -3
#define CANATMOSPASS(A, O, D) ( A.CanAtmosPass == ATMOS_PASS_PROC ? A.CanAtmosPass(O, D) : ( A.CanAtmosPass == ATMOS_PASS_DENSITY ? (A.density? ATMOS_PASS_AIR_BLOCKED : ATMOS_PASS_NOT_BLOCKED) : A.CanAtmosPass ) )
#define CANVERTICALATMOSPASS(A, O, D) (A.CanAtmosPassVertical == ATMOS_PASS_VERTICAL_DEFAULT? CANATMOSPASS(A, O, D) : ( A.CanAtmosPassVertical == ATMOS_PASS_PROC ? A.CanAtmosPass(O, D) : ( A.CanAtmosPassVertical == ATMOS_PASS_DENSITY ? (A.density? ATMOS_PASS_AIR_BLOCKED : ATMOS_PASS_NOT_BLOCKED) : A.CanAtmosPassVertical ) ))
#define CANATMOSPASS(A, O, D) (A.CanAtmosPass > -1? A.CanAtmosPass : (A.CanAtmosPass == ATMOS_PASS_PROC? A.CanAtmosPass(O, D) : (A.density? ATMOS_PASS_AIR_BLOCKED : ATMOS_PASS_NOT_BLOCKED)))
#define CANVERTICALATMOSPASS(A, O, D) (A.CanAtmosPassVertical == ATMOS_PASS_VERTICAL_DEFAULT? CANATMOSPASS(A, O, D) : (A.CanAtmosPassVertical > -1? A.CanAtmosPassVertical : (A.CanAtmosPassVertical == ATMOS_PASS_PROC? A.CanAtmosPass(O, D) : (A.density? ATMOS_PASS_AIR_BLOCKED : ATMOS_PASS_NOT_BLOCKED))))
/**
* LEGACY BELOW

View File

@@ -71,21 +71,24 @@
#warn Consider switching to VSCode editor instead, where you can press Ctrl+Shift+B to build.
#endif
// A reasonable number of maximum overlays an object needs
// If you think you need more, rethink it
#define MAX_ATOM_OVERLAYS 100
//! Atmospherics
//! ZAS
//? Gasmixtures
/// enable general assertions
#define GASMIXTURE_ASSERTIONS
// debugging
// if you touch anything #if'd behind a block for any of these you better make sure this works or I will bean you with a shoe .
//? ZAS (Environmental)
/// Uncomment to turn on Multi-Z ZAS Support!
#define MULTIZAS
/// uncomment to enable laggy as sin ZAS debugging systems coded in for when doing bugfixes or major systems overhaulling.
#define ZAS_DEBUG
#define ZAS_ASSERTIONS
/// uncomment to enable *actually* laggy as sin ZAS debugging, like "list in contents". don't do this without a major reason.
// #define ZAS_DEBUG_EXPENSIVE
// #define ZAS_ASSERTIONS_EXPENSIVE
/// uncomment to enable debugging graphics. you probably want to keep this off in live!
// #define ZAS_DEBUG_GRAPHICS
// features
/// Uncomment to turn on Multi-Z ZAS Support!
#define MULTIZAS
//! Overlays
// A reasonable number of maximum overlays an object needs
// If you think you need more, rethink it
#define MAX_ATOM_OVERLAYS 100

View File

@@ -39,7 +39,7 @@
var/thermal_power = 300 * adjusted_power
removed.add_thermal_energy(thermal_power)
removed.adjust_thermal_energy(thermal_power)
removed.temperature = clamp( removed.temperature, 0, 10000)
env.merge(removed)

View File

@@ -241,7 +241,7 @@
if(gas.temperature <= target_temperature) //gas heating
var/energy_used = min(gas.get_thermal_energy_change(target_temperature) , active_power_usage)
gas.add_thermal_energy(energy_used)
gas.adjust_thermal_energy(energy_used)
//use_power(energy_used, ENVIRON) //handle by update_use_power instead
else //gas cooling
var/heat_transfer = min(abs(gas.get_thermal_energy_change(target_temperature)), active_power_usage)
@@ -253,7 +253,7 @@
heat_transfer = min(heat_transfer, cop * active_power_usage) //this ensures that we don't use more than active_power_usage amount of power
heat_transfer = -gas.add_thermal_energy(-heat_transfer) //get the actual heat transfer
heat_transfer = -gas.adjust_thermal_energy(-heat_transfer) //get the actual heat transfer
//use_power(heat_transfer / cop, ENVIRON) //handle by update_use_power instead

View File

@@ -272,7 +272,7 @@
simulation_results += "<br>Initial gas tank status:<br>[format_gas_for_results(faketank)]"
faketank.add_thermal_energy(15000)
faketank.adjust_thermal_energy(15000)
var/intervals = 0
while(intervals < 10)

View File

@@ -106,7 +106,7 @@ obj/machinery/airlock_sensor/phoron/airlock_exterior
var/datum/gas_mixture/removed = env.remove_ratio(0.99)
if(removed)
var/heat_transfer = removed.get_thermal_energy_change(target_temp)
removed.add_thermal_energy(clamp(heat_transfer,-heating_power,heating_power))
removed.adjust_thermal_energy(clamp(heat_transfer,-heating_power,heating_power))
env.merge(removed)
var/transfer_moles = min(1, volume_rate/env.volume)*env.total_moles

View File

@@ -158,7 +158,7 @@
if(heat_transfer > 0) //heating air
heat_transfer = min(heat_transfer, heating_power) //limit by the power rating of the heater
removed.add_thermal_energy(heat_transfer)
removed.adjust_thermal_energy(heat_transfer)
cell.use(DYNAMIC_W_TO_CELL_UNITS(heat_transfer * SPACE_HEATER_CHEAT_FACTOR, 1))
else //cooling air
heat_transfer = abs(heat_transfer)
@@ -167,7 +167,7 @@
var/cop = removed.temperature/T20C //coefficient of performance from thermodynamics -> power used = heat_transfer/cop
heat_transfer = min(heat_transfer, cop * heating_power) //limit heat transfer by available power
heat_transfer = removed.add_thermal_energy(-heat_transfer) //get the actual heat transfer
heat_transfer = removed.adjust_thermal_energy(-heat_transfer) //get the actual heat transfer
var/power_used = abs(heat_transfer)/cop
cell.use(DYNAMIC_W_TO_CELL_UNITS(power_used * SPACE_HEATER_CHEAT_FACTOR, 1))
@@ -276,7 +276,7 @@
else if(heat_transfer > 0)
change_mode(MODE_HEATING)
power_avail = draw_power(min(heat_transfer, active_power_usage) * 0.001) * 1000
removed.add_thermal_energy(min(power_avail * THERMOREGULATOR_CHEAT_FACTOR, heat_transfer))
removed.adjust_thermal_energy(min(power_avail * THERMOREGULATOR_CHEAT_FACTOR, heat_transfer))
else
change_mode(MODE_COOLING)
heat_transfer = abs(heat_transfer)
@@ -284,7 +284,7 @@
var/actual_heat_transfer = heat_transfer
heat_transfer = min(heat_transfer, active_power_usage * cop)
power_avail = draw_power((heat_transfer/cop) * 0.001) * 1000
removed.add_thermal_energy(-min(power_avail * THERMOREGULATOR_CHEAT_FACTOR * cop, actual_heat_transfer))
removed.adjust_thermal_energy(-min(power_avail * THERMOREGULATOR_CHEAT_FACTOR * cop, actual_heat_transfer))
env.merge(removed)
/obj/machinery/power/thermoregulator/update_icon()
@@ -325,7 +325,7 @@
var/datum/gas_mixture/removed = env.remove_ratio(0.99)
if(removed)
// OH BOY!
removed.add_thermal_energy(power_avail * 1000 * THERMOREGULATOR_CHEAT_FACTOR)
removed.adjust_thermal_energy(power_avail * 1000 * THERMOREGULATOR_CHEAT_FACTOR)
env.merge(removed)
var/turf/T = get_turf(src)
new /obj/effect/debris/cleanable/liquid_fuel(T, 5)

View File

@@ -239,7 +239,7 @@
if (traffic <= 0)
heat_produced *= 0.30 //if idle, produce less heat.
removed.add_thermal_energy(heat_produced)
removed.adjust_thermal_energy(heat_produced)
env.merge(removed)
/*

View File

@@ -204,7 +204,7 @@ var/list/global/tank_gauge_cache = list()
to_chat(user, "<span class='danger'>You accidentally rake \the [W] across \the [src]!</span>")
max_integrity -= rand(2,6)
integrity = min(integrity,max_integrity)
src.air_contents.add_thermal_energy(rand(2000,50000))
src.air_contents.adjust_thermal_energy(rand(2000,50000))
WT.eyecheck(user)
else
to_chat(user, "<span class='notice'>The emergency pressure relief valve has already been welded.</span>")
@@ -329,7 +329,7 @@ var/list/global/tank_gauge_cache = list()
. = ..()
START_PROCESSING(SSobj, src)
/obj/item/tank/add_thermal_energy(joules)
/obj/item/tank/adjust_thermal_energy(joules)
. = ..()
START_PROCESSING(SSobj, src)
@@ -657,7 +657,7 @@ var/list/global/tank_gauge_cache = list()
src.update_icon()
src.update_gauge()
air_contents.add_thermal_energy(15000)
air_contents.adjust_thermal_energy(15000)
/obj/item/tankassemblyproxy/update_icon()

View File

@@ -237,7 +237,7 @@
if(heat_transfer > 0)
heat_transfer = min(heat_transfer , heating_power)
removed.add_thermal_energy(heat_transfer)
removed.adjust_thermal_energy(heat_transfer)
env.merge(removed)
@@ -403,7 +403,7 @@
if(heat_transfer > 0)
heat_transfer = min(heat_transfer , heating_power)
removed.add_thermal_energy(heat_transfer)
removed.adjust_thermal_energy(heat_transfer)
env.merge(removed)

View File

@@ -34,8 +34,6 @@
var/const/OPEN_DURATION = 6
var/const/CLOSE_DURATION = 6
/obj/structure/transit_tube_pod
icon = 'icons/obj/pipes/transit_tube_pod.dmi'
icon_state = "pod"
@@ -43,8 +41,7 @@
anchored = 1.0
density = 1
var/moving = 0
var/datum/gas_mixture/air_contents = new()
var/datum/gas_mixture/air_contents = new(CELL_VOLUME)
/obj/structure/transit_tube_pod/Destroy()
@@ -355,7 +352,7 @@
//note that share_ratio assumes both gas mixes have the same volume,
//so if the volume is changed this may need to be changed as well.
air_contents.share_ratio(environment, 1)
air_contents.default_share_ratio(environment, 1)
// When the player moves, check if the pos is currently stopped at a station.
// if it is, check the direction. If the direction matches the direction of

View File

@@ -17,7 +17,8 @@ var/list/flooring_cache = list()
/turf/simulated/floor/update_icon()
cut_overlays()
// lol
add_overlay(zone?.turf_graphics)
if(flooring)
// Set initial icon and strings.
name = flooring.name

View File

@@ -11,6 +11,28 @@
else
return CanAtmosPass
/**
* call when we ourselves need to update our air pass
*/
/atom/proc/air_update_turf()
/turf/air_update_turf()
queue_zone_update()
/atom/movable/air_update_turf()
update_nearby_tiles()
/**
* call when we move to update our air pass
*/
/atom/proc/air_update_turf_moved(turf/oldLoc)
/turf/air_update_turf_moved()
queue_zone_update()
/atom/movable/air_update_turf_moved()
update_nearby_tiles()
/**
* superconduction - not yet implemented
*/

View File

@@ -53,8 +53,8 @@
/**
* add/remove thermal energy from air
*/
/atom/proc/add_thermal_energy(joules)
return return_air()?.add_thermal_energy(joules)
/atom/proc/adjust_thermal_energy(joules)
return return_air()?.adjust_thermal_energy(joules)
/**
* get thermal energy needed for our air to be x temperature

View File

@@ -12,27 +12,35 @@
/turf/CanAtmosPass(turf/T, d)
if(blocks_air)
return ATMOS_PASS_AIR_BLOCKED
var/v = d & (UP|DOWN)
switch(v)
if(UP)
if(!(z_flags & Z_AIR_UP))
return ATMOS_PASS_AIR_BLOCKED
if(DOWN)
if(!(z_flags & Z_AIR_DOWN))
return ATMOS_PASS_AIR_BLOCKED
if(T == src)
// at this point nothing should be blocking us --> us
//! warning: this does break some ZAS functionality but honestly blocking self to self is a stupid and expensive concept to maintain.
return ATMOS_PASS_NOT_BLOCKED
// we only care about objects, compiler fastpath
// plus, wtf are you doing using /atom/movable to block atmos??
. = ATMOS_PASS_NOT_BLOCKED
for(var/obj/O in contents)
. = min(., v? CANVERTICALATMOSPASS(O, T, d) : CANATMOSPASS(O, T, d))
if(. == ATMOS_PASS_AIR_BLOCKED)
// can't go lower than this
return
var/v = d & (UP|DOWN)
if(v)
switch(d)
if(UP)
if(!(z_flags & Z_AIR_UP))
return ATMOS_PASS_AIR_BLOCKED
if(DOWN)
if(!(z_flags & Z_AIR_DOWN))
return ATMOS_PASS_AIR_BLOCKED
. = ATMOS_PASS_NOT_BLOCKED
for(var/atom/movable/AM as anything in contents)
. = min(., CANVERTICALATMOSPASS(AM, T, d))
if(. == ATMOS_PASS_AIR_BLOCKED)
// can't go lower than this
return
else
. = ATMOS_PASS_NOT_BLOCKED
for(var/atom/movable/AM as anything in contents)
. = min(., CANATMOSPASS(AM, T, d))
if(. == ATMOS_PASS_AIR_BLOCKED)
// can't go lower than this
return
/turf/proc/CheckAirBlock(turf/other)
if(other == src)
return CanAtmosPass(src, NONE)
var/d = other.z == z? get_dir(src, other) : get_dir_multiz(src, other)
var/o = REVERSE_DIR(d)
return min(CanAtmosPass(other, d), other.CanAtmosPass(src, o))

View File

@@ -58,7 +58,7 @@ Class Procs:
var/state = 0
/datum/zas_connection/New(turf/simulated/A, turf/simulated/B)
#ifdef ZAS_DEBUG
#ifdef ZAS_ASSERTIONS
ASSERT(A.has_valid_zone())
//ASSERT(air_master.has_valid_zone(B))
#endif

View File

@@ -90,7 +90,7 @@ Class Procs:
zones_to_update.Remove(z)
/datum/controller/subsystem/air/proc/merge(datum/zas_zone/A, datum/zas_zone/B)
#ifdef ZAS_DEBUG
#ifdef ZAS_ASSERTIONS
ASSERT(istype(A))
ASSERT(istype(B))
ASSERT(!A.invalid)
@@ -105,7 +105,7 @@ Class Procs:
mark_zone_update(A)
/datum/controller/subsystem/air/proc/connect(turf/simulated/A, turf/simulated/B, given_block, given_dir)
#ifdef ZAS_DEBUG
#ifdef ZAS_ASSERTIONS
ASSERT(istype(A))
ASSERT(isturf(B))
ASSERT(A.has_valid_zone())
@@ -153,7 +153,7 @@ Class Procs:
c.mark_direct()
/datum/controller/subsystem/air/proc/mark_for_update(turf/T)
#ifdef ZAS_DEBUG
#ifdef ZAS_ASSERTIONS
ASSERT(isturf(T))
#endif
tiles_to_update += T
@@ -162,7 +162,7 @@ Class Procs:
#endif
/datum/controller/subsystem/air/proc/mark_zone_update(datum/zas_zone/Z)
#ifdef ZAS_DEBUG
#ifdef ZAS_ASSERTIONS
ASSERT(istype(Z))
#endif
if(Z.needs_update)
@@ -171,7 +171,7 @@ Class Procs:
Z.needs_update = 1
/datum/controller/subsystem/air/proc/mark_edge_sleeping(datum/zas_edge/E)
#ifdef ZAS_DEBUG
#ifdef ZAS_ASSERTIONS
ASSERT(istype(E))
#endif
if(E.sleeping)
@@ -180,7 +180,7 @@ Class Procs:
E.sleeping = 1
/datum/controller/subsystem/air/proc/mark_edge_active(datum/zas_edge/E)
#ifdef ZAS_DEBUG
#ifdef ZAS_ASSERTIONS
ASSERT(istype(E))
#endif
if(!E.sleeping)

View File

@@ -159,7 +159,7 @@ Class Procs:
erase()
return
var/equiv = A.air.share_ratio(B.air, coefficient)
var/equiv = A.air.default_share_ratio(B.air, coefficient)
var/differential = A.air.return_pressure() - B.air.return_pressure()
if(abs(differential) >= lightest_pressure)
@@ -233,7 +233,7 @@ Class Procs:
CACHE_VSC_PROP(atmos_vsc, /atmos/airflow/lightest_pressure, lightest_pressure)
var/equiv = A.air.share_space(air)
var/equiv = A.air.default_share_unsimulated(air)
var/differential = A.air.return_pressure() - air.return_pressure()
if(abs(differential) >= lightest_pressure)

View File

@@ -207,7 +207,7 @@
dbg(created)
#endif
#ifdef ZAS_DEBUG
#ifdef ZAS_ASSERTIONS
ASSERT(zone)
#endif

View File

@@ -49,7 +49,7 @@ Class Procs:
var/list/edges = list()
var/datum/gas_mixture/air = new
var/list/turf_graphics = list()
var/list/turf_graphics
/datum/zas_zone/New()
air_master.add_zone(src)
@@ -58,7 +58,7 @@ Class Procs:
air.volume = CELL_VOLUME
/datum/zas_zone/proc/add(turf/simulated/T)
#ifdef ZAS_DEBUG
#ifdef ZAS_ASSERTIONS
ASSERT(!invalid)
ASSERT(istype(T))
ASSERT(!T.has_valid_zone())
@@ -67,39 +67,41 @@ Class Procs:
var/datum/gas_mixture/turf_air = T.return_air()
add_tile_air(turf_air)
T.zone = src
contents.Add(T)
contents += T
if(T.fire)
var/obj/effect/debris/cleanable/liquid_fuel/fuel = locate() in T
fire_tiles.Add(T)
fire_tiles += T
air_master.active_fire_zones |= src
if(fuel) fuel_objs += fuel
if(fuel)
fuel_objs += fuel
if(T.allow_gas_overlays && !T.outdoors)
T.vis_contents += turf_graphics
T.add_overlay(turf_graphics)
/datum/zas_zone/proc/remove(turf/simulated/T)
#ifdef ZAS_DEBUG
#ifdef ZAS_ASSERTIONS
ASSERT(!invalid)
ASSERT(istype(T))
ASSERT(T.zone == src)
#endif
#ifdef ZAS_DEBUG_EXPENSIVE
#ifdef ZAS_ASSERTIONS_EXPENSIVE
if(!(T in contents))
stack_trace("Turf was not in contents.")
#endif
contents.Remove(T)
fire_tiles.Remove(T)
contents -= T
if(T.fire)
var/obj/effect/debris/cleanable/liquid_fuel/fuel = locate() in T
fuel_objs -= fuel
fire_tiles -= T
if(fuel)
fuel_objs -= fuel
T.zone = null
T.vis_contents -= turf_graphics
T.cut_overlay(turf_graphics)
if(contents.len)
air.group_multiplier = contents.len
else
c_invalidate()
/datum/zas_zone/proc/c_merge(datum/zas_zone/into)
#ifdef ZAS_DEBUG
#ifdef ZAS_ASSERTIONS
ASSERT(!invalid)
ASSERT(istype(into))
ASSERT(into != src)
@@ -154,14 +156,23 @@ Class Procs:
T.create_fire(firelevel_multiplier)
var/list/returned = air.get_turf_graphics()
if(!(returned ~= turf_graphics))
var/list/removed = turf_graphics - returned
var/list/added = returned - turf_graphics
for(var/turf/simulated/T in contents)
T.vis_contents -= removed
if(T.allow_gas_overlays && !T.outdoors)
T.vis_contents += added
turf_graphics = returned
if(returned)
if(turf_graphics)
for(var/turf/simulated/T in contents)
T.cut_overlay(turf_graphics)
if(T.allow_gas_overlays && !T.outdoors)
T.add_overlay(returned)
turf_graphics = returned
else
for(var/turf/simulated/T in contents)
if(T.allow_gas_overlays && !T.outdoors)
T.add_overlay(returned)
turf_graphics = returned
else
if(turf_graphics)
for(var/turf/simulated/T in contents)
T.cut_overlay(turf_graphics)
turf_graphics = null
for(var/datum/zas_edge/E in edges)
if(E.sleeping)

View File

@@ -11,7 +11,6 @@
//Volume of this mix.
var/volume = CELL_VOLUME
//Size of the group this gas_mixture is representing. 1 for singletons.
// ATMOS_TODO : this needs to be removed for auxmos
var/group_multiplier = 1
//List of active tile overlays for this gas_mixture. Updated by check_tile_graphic()
@@ -123,38 +122,53 @@
return 1
// todo: check above
//Returns the heat capacity of the gas mix based on the specific heat of the gases.
//! Thermodynamics
/**
* Returns the heat capacity of the gas mix based on the specific heat of the gases and their moles.
*
* takes group_multiplier into account.
*/
/datum/gas_mixture/proc/heat_capacity()
. = 0
for(var/g in gas)
. += GLOB.meta_gas_specific_heats[g] * gas[g]
. *= group_multiplier
/**
* gets total thermal energy, taking into account group multiplier
*/
/datum/gas_mixture/proc/thermal_energy()
return heat_capacity() * temperature
//Adds or removes thermal energy. Returns the actual thermal energy change, as in the case of removing energy we can't go below TCMB.
/datum/gas_mixture/proc/add_thermal_energy(var/thermal_energy)
if (total_moles == 0)
/**
* adjusts thermal energy in joules
*
* returns amount changed, so we can't go below TCMB; **amount changed is not absolute value**, e.g. inputting -10 will net you returned -10.
*/
/datum/gas_mixture/proc/adjust_thermal_energy(joules)
if(!total_moles)
return 0
var/capacity = heat_capacity()
if(joules < 0)
joules = max(joules, -(temperature - TCMB) * capacity)
temperature += joules / capacity
return joules
var/heat_capacity = heat_capacity()
if (thermal_energy < 0)
if (temperature < TCMB)
return 0
var/thermal_energy_limit = -(temperature - TCMB)*heat_capacity //ensure temperature does not go below TCMB
thermal_energy = max( thermal_energy, thermal_energy_limit ) //thermal_energy and thermal_energy_limit are negative here.
temperature += thermal_energy/heat_capacity
return thermal_energy
/**
* returns thermal energy change in joules to get to a certain temperature
*/
/datum/gas_mixture/proc/get_thermal_energy_change(target)
return heat_capacity() * (max(target, 0) - temperature)
// todo: check below
//Returns the thermal energy change required to get to a new temperature
/datum/gas_mixture/proc/get_thermal_energy_change(var/new_temperature)
return heat_capacity()*(max(new_temperature, 0) - temperature)
//Technically vacuum doesn't have a specific entropy. Just use a really big number (infinity would be ideal) here so that it's easy to add gas to vacuum and hard to take gas out.
#define SPECIFIC_ENTROPY_VACUUM 150000
//Returns the ideal gas specific entropy of the whole mix. This is the entropy per mole of /mixed/ gas.
/datum/gas_mixture/proc/specific_entropy()
if (!gas.len || total_moles == 0)
@@ -198,11 +212,10 @@
//Returns the pressure of the gas mix. Only accurate if there have been no gas modifications since update_values() has been called.
/datum/gas_mixture/proc/return_pressure()
if(volume)
var/total
TOTAL_MOLES(gas, total)
return (total * R_IDEAL_GAS_EQUATION * temperature) / volume
return 0
#ifdef GASMIXTURE_ASSERTIONS
ASSERT(volume > 0)
#endif
return (total_moles * R_IDEAL_GAS_EQUATION * temperature) / volume
//Removes moles from the gas mixture and returns a gas_mixture containing the removed air.
/datum/gas_mixture/proc/remove(amount)
@@ -297,46 +310,43 @@
if(!sample)
return FALSE
// check vacuum exception bullshit
if(vacuum_exception && ((!total_moles) ^ (!sample.total_moles)))
return FALSE
if(abs(temperature - sample.temperature) > MINIMUM_MEANINGFUL_TEMPERATURE_DELTA)
// check temperature
if(abs(temperature - sample.temperature) >= MINIMUM_MEANINGFUL_TEMPERATURE_DELTA)
return FALSE
var/list/us = list()
// man.
// check moles
for(var/id in gas)
us[id] = gas[id]
for(var/id in sample.gas)
if(abs(sample.gas[id] - us[id]) > MINIMUM_MEANINGFUL_MOLES_DELTA)
if(abs(gas[id] - sample.gas[id]) >= MINIMUM_MEANINGFUL_MOLES_DELTA)
return FALSE
return TRUE
/*
// this is the old code
var/list/marked = list()
for(var/g in gas)
if((abs(gas[g] - sample.gas[g]) > MINIMUM_AIR_TO_SUSPEND) && \
((gas[g] < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g]) || \
(gas[g] > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g])))
return 0
marked[g] = 1
// check pressure
return abs(return_pressure() - sample.return_pressure()) < MINIMUM_MEANINGFUL_PRESSURE_DELTA
for(var/g in sample.gas)
if(!marked[g])
if((abs(gas[g] - sample.gas[g]) > MINIMUM_AIR_TO_SUSPEND) && \
((gas[g] < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g]) || \
(gas[g] > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g])))
return 0
/**
* checks if we are within acceptable like-ness of a virtual gas data struct to suspend processing or merge
*
* @return TRUE if we are equal enough, otherwise FALSE
*/
/datum/gas_mixture/proc/compare_virtual(list/gases, volume, temperature)
// check temperature
if(abs(src.temperature - temperature) > MINIMUM_MEANINGFUL_TEMPERATURE_DELTA)
return FALSE
if(total_moles > MINIMUM_AIR_TO_SUSPEND)
if((abs(temperature - sample.temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) && \
((temperature < (1 - MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature) || \
(temperature > (1 + MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature)))
return 0
// check moles
for(var/id in gas)
if(abs(gases[id] - gas[id]) > MINIMUM_MEANINGFUL_MOLES_DELTA)
return FALSE
return 1
*/
// check pressure
var/their_pressure = 0
for(var/id in gases)
their_pressure += gases[id]
their_pressure = (their_pressure * R_IDEAL_GAS_EQUATION * temperature) / volume
return abs(return_pressure() - their_pressure) < MINIMUM_MEANINGFUL_PRESSURE_DELTA
/datum/gas_mixture/proc/react()
zburn(null, force_burn=0, no_check=0) //could probably just call zburn() here with no args but I like being explicit.
@@ -355,57 +365,7 @@
var/list/gas_overlays = GLOB.meta_gas_overlays[id]
if(gas_overlays && moles > GLOB.meta_gas_visibility[id])
. += gas_overlays[min(FACTOR_GAS_VISIBLE_MAX, CEILING(moles / MOLES_GAS_VISIBLE_STEP, 1))]
//Shares gas with another gas_mixture based on the amount of connecting tiles and a fixed lookup table.
/datum/gas_mixture/proc/share_ratio(datum/gas_mixture/other, connecting_tiles, share_size = null, one_way = 0)
var/static/list/sharing_lookup_table = list(0.30, 0.40, 0.48, 0.54, 0.60, 0.66)
//Shares a specific ratio of gas between mixtures using simple weighted averages.
var/ratio = sharing_lookup_table[6]
var/size = max(1, group_multiplier)
if(isnull(share_size))
share_size = max(1, other.group_multiplier)
var/full_heat_capacity = heat_capacity()
var/s_full_heat_capacity = other.heat_capacity()
var/list/avg_gas = list()
for(var/g in gas)
avg_gas[g] += gas[g] * size
for(var/g in other.gas)
avg_gas[g] += other.gas[g] * share_size
for(var/g in avg_gas)
avg_gas[g] /= (size + share_size)
var/temp_avg = 0
if(full_heat_capacity + s_full_heat_capacity)
temp_avg = (temperature * full_heat_capacity + other.temperature * s_full_heat_capacity) / (full_heat_capacity + s_full_heat_capacity)
//WOOT WOOT TOUCH THIS AND YOU ARE AN IDIOT.
if(sharing_lookup_table.len >= connecting_tiles) //6 or more interconnecting tiles will max at 42% of air moved per tick.
ratio = sharing_lookup_table[connecting_tiles]
//WOOT WOOT TOUCH THIS AND YOU ARE AN IDIOT
for(var/g in avg_gas)
gas[g] = max(0, (gas[g] - avg_gas[g]) * (1 - ratio) + avg_gas[g])
if(!one_way)
other.gas[g] = max(0, (other.gas[g] - avg_gas[g]) * (1 - ratio) + avg_gas[g])
temperature = max(0, (temperature - temp_avg) * (1-ratio) + temp_avg)
if(!one_way)
other.temperature = max(0, (other.temperature - temp_avg) * (1-ratio) + temp_avg)
update_values()
other.update_values()
return compare(other)
//A wrapper around share_ratio for spacing gas at the same rate as if it were going into a large airless room.
/datum/gas_mixture/proc/share_space(datum/gas_mixture/unsim_air)
return share_ratio(unsim_air, unsim_air.group_multiplier, max(1, max(group_multiplier + 3, 1) + unsim_air.group_multiplier), one_way = 1)
return length(.)? . : null
//Equalizes a list of gas mixtures. Used for pipe networks.
/proc/equalize_gases(list/datum/gas_mixture/gases)
@@ -495,6 +455,14 @@
update_values()
return 1
/datum/gas_mixture/proc/get_mass()
for(var/g in gas)
. += gas[g] * GLOB.meta_gas_molar_mass[g] * group_multiplier
// todo: sort above
//! Gas Strings
/**
* Copies from a specially formatted gas string, taking on its gas values as our own as well as their temperature.
*/
@@ -525,10 +493,7 @@
qdel(temp)
return TRUE
/datum/gas_mixture/proc/get_mass()
for(var/g in gas)
. += gas[g] * GLOB.meta_gas_molar_mass[g] * group_multiplier
//! Tile Operations
/**
* get the equivalent of a single tile of this gas mixture
*
@@ -540,3 +505,156 @@
GM.copy_from(src)
GM.group_multiplier = 1
return GM
//! Sharing; usually used for environmental systems.
/**
* Default share gas implementation - shares with another gas_mixture non-canonically
* based on connecting tiles. Is just a wrapper to use a lookup table.
*/
/datum/gas_mixture/proc/default_share_ratio(datum/gas_mixture/other, tiles)
#ifdef GASMIXTURE_ASSERTIONS
ASSERT(tiles > 0)
#endif
var/static/list/lookup_table = list(
0.3,
0.4,
0.48,
0.54,
0.6,
0.66
)
if(tiles <= 0)
CRASH("sharing with tiles < 0 is a waste of time")
return share_ratio(other, lookup_table[min(tiles, 6)])
/**
* Shares a ratio of the combined gas of two gas mixtures
*
* non canonical, e.g. A shares with B --> A shares with C != A shares with C --> A shares with B
*
* this also assumes equal
*/
/datum/gas_mixture/proc/share_ratio(datum/gas_mixture/other, ratio)
#ifdef GASMIXTURE_ASSERTIONS
ASSERT(ratio > 0 && ratio <= 1)
// todo: volume based, not group multiplier based. is it worth it?
ASSERT(volume == other.volume)
#endif
// collect
var/list/their_gas = other.gas
var/list/our_gas = gas
var/our_size = src.group_multiplier
var/their_size = other.group_multiplier
var/total_size = our_size + their_size
var/our_capacity = heat_capacity()
var/their_capacity = heat_capacity()
// compute
var/list/avg_gas = list()
for(var/id in our_gas)
avg_gas[id] += our_gas[id] * our_size
for(var/id in their_gas)
avg_gas[id] += their_gas[id] * their_size
for(var/id in avg_gas)
avg_gas[id] /= total_size
var/avg_temperature = (temperature * our_capacity + other.temperature * their_capacity) / (our_capacity + their_capacity)
// equalize
var/intact_ratio = 1 - ratio
var/avg_amt
for(var/id in avg_gas)
// set moles by ratio
// lists are cached, so directly set
avg_amt = avg_gas[id]
// i don't know what these do but they work (probably)
our_gas[id] = (our_gas[id] - avg_amt) * intact_ratio + avg_amt
their_gas[id] = (their_gas[id] - avg_amt) * intact_ratio + avg_amt
// thermodynamics:
// i don't know what these do but they work (probably)
temperature = (temperature - avg_temperature) * intact_ratio + avg_temperature
other.temperature = (other.temperature - avg_temperature) * intact_ratio + avg_temperature
// update
update_values()
other.update_values()
// return if we equalized fully
return compare(other)
/**
* default implementation to equalize with an unsimulated space
* by default, this will ramp up equalization to match our room, so we can't
* overpower say, 1 tile of unsimulated with a massive room.
*/
/datum/gas_mixture/proc/default_share_unsimulated(datum/gas_mixture/unsimulated)
var/static/list/sharing_lookup_table = list(0.30, 0.40, 0.48, 0.54, 0.60, 0.66)
var/computed_multiplier = max(group_multiplier, unsimulated.group_multiplier)
return share_virtual(unsimulated.gas, computed_multiplier, unsimulated.temperature, sharing_lookup_table[min(unsimulated.group_multiplier, 6)])
/**
* equalizes x% of our gas with an unsimulated mixture.
*
* ! warning: this assumes the virtual mixture is the same volume as us, for optimization
*
* @params
* - gases - gases of the other mixture
* - group_multiplier - how big the other mixture is pretending to be
* - temperature - how hot the other mixture is
* - ratio - how much of the **total** mixture will be equalized
*/
/datum/gas_mixture/proc/share_virtual(list/gases, group_multiplier, temperature, ratio)
#ifdef GASMIXTURE_ASSERTIONS
ASSERT(ratio > 0 && ratio <= 1)
ASSERT(temperature >= TCMB)
ASSERT(group_multiplier >= 1)
#endif
// let's not break the input list
//! IF YOU DO NOT KNOW WHY WE ARE COPYING, DO NOT TAKE THIS OUT.
gases = gases.Copy()
// collect
var/list/our_gas = gas
var/our_capacity = heat_capacity()
// compute
var/their_capacity = 0
for(var/id in gases)
// in the same loop, we'll calculate their total capacity, at the same time expanding their moles to the true value
their_capacity += GLOB.meta_gas_specific_heats[id] * gases[id] * group_multiplier
gases[id] *= group_multiplier
for(var/id in our_gas)
// now add ours
gases[id] += our_gas[id] * src.group_multiplier
for(var/id in gases)
// now shrink to the average
gases[id] /= (src.group_multiplier + group_multiplier)
// calculate avg temperature
var/avg_temperature = (src.temperature * our_capacity + temperature * their_capacity) / (our_capacity + their_capacity)
// equalize
var/intact_ratio = 1 - ratio
var/avg_amt
for(var/id in gases)
// set moles by ratio
// lists are cached, so directly set
avg_amt = gases[id]
// i don't know what these do but they work (probably)
our_gas[id] = (our_gas[id] - avg_amt) * intact_ratio + avg_amt
// thermodynamics:
// i don't know what these do but they work (probably)
src.temperature = (src.temperature - avg_temperature) * intact_ratio + avg_temperature
// update
update_values()
// return if we equalized fully
return compare_virtual(gases, src.volume, temperature)

View File

@@ -53,7 +53,10 @@ GLOBAL_LIST_INIT(meta_gas_typecache_no_overlays, meta_gas_typecache_no_overlays_
if(initial(gas.moles_visible) != null)
.[gas_path] = new /list(FACTOR_GAS_VISIBLE_MAX)
for(var/i in 1 to FACTOR_GAS_VISIBLE_MAX)
.[gas_path][i] = new /obj/effect/overlay/gas(initial(gas.gas_overlay), i * 255 / FACTOR_GAS_VISIBLE_MAX)
var/image/I = image('icons/effects/atmospherics.dmi', icon_state = initial(gas.gas_overlay), layer = FLY_LAYER)
I.plane = MOB_PLANE
I.alpha = i * 255 / FACTOR_GAS_VISIBLE_MAX
.[gas_path][i] = I
/proc/meta_gas_danger_list()
. = subtypesof(/datum/gas)
@@ -117,6 +120,7 @@ GLOBAL_LIST_INIT(meta_gas_typecache_no_overlays, meta_gas_typecache_no_overlays_
.[gastype] = TRUE
// Visual overlay
/*
/obj/effect/overlay/gas
icon = 'icons/effects/atmospherics.dmi'
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
@@ -129,6 +133,7 @@ GLOBAL_LIST_INIT(meta_gas_typecache_no_overlays, meta_gas_typecache_no_overlays_
. = ..()
icon_state = state
alpha = alph
*/
/*||||||||||||||/----------\||||||||||||||*\
||||||||||||||||[GAS DATUMS]||||||||||||||||

View File

@@ -146,7 +146,7 @@
energy_transfered = clamp(air2.get_thermal_energy_change(target_temp),performance_factor*power_rating,-performance_factor*power_rating)
var/power_draw = abs(energy_transfered/performance_factor)
air2.add_thermal_energy(-air1.add_thermal_energy(-energy_transfered*efficiency))//only adds the energy actually removed from air one to air two(- infront of air1 because energy was removed)
air2.adjust_thermal_energy(-air1.adjust_thermal_energy(-energy_transfered*efficiency))//only adds the energy actually removed from air one to air two(- infront of air1 because energy was removed)
if (power_draw >= 0)
last_power_draw = power_draw
use_power(power_draw)

View File

@@ -90,7 +90,7 @@
energy_transfered = clamp(air2.get_thermal_energy_change(target_temp),performance_factor*power_rating,-performance_factor*power_rating)
power_draw = abs(energy_transfered/performance_factor)
air2.add_thermal_energy(-air1.add_thermal_energy(-energy_transfered*efficiency))//only adds the energy actually removed from air one to air two(- infront of air1 because energy was removed)
air2.adjust_thermal_energy(-air1.adjust_thermal_energy(-energy_transfered*efficiency))//only adds the energy actually removed from air one to air two(- infront of air1 because energy was removed)
if (power_draw >= 0)
last_power_draw = power_draw

View File

@@ -125,7 +125,7 @@
var/cop = THERMOMACHINE_CHEAT_FACTOR * air_contents.temperature/heatsink_temperature //heatpump coefficient of performance from thermodynamics -> power used = heat_transfer/cop
heat_transfer = min(heat_transfer, cop * power_rating) //limit heat transfer by available power
var/removed = -air_contents.add_thermal_energy(-heat_transfer) //remove the heat
var/removed = -air_contents.adjust_thermal_energy(-heat_transfer) //remove the heat
if(debug)
visible_message("[src]: Removing [removed] W.")

View File

@@ -63,7 +63,7 @@
if(network && air_contents.total_moles && air_contents.temperature < set_temperature)
var/limit = clamp(air_contents.heat_capacity() * (set_temperature - air_contents.temperature), 0, power_rating * THERMOMACHINE_CHEAT_FACTOR)
air_contents.add_thermal_energy(limit)
air_contents.adjust_thermal_energy(limit)
use_power(power_rating)
heating = 1

View File

@@ -157,7 +157,7 @@
var/delta_temp = modeled_location.special_temperature - air.temperature//2200C - 20C = 2180K
//assuming aluminium with thermal conductivity 235 W * K / m, Copper (400), Silver (430), steel (50), gold (320)
var/heat_gain = thermal_conductivity_setting * 100 * delta_temp//assuming 1 cm wall thickness, so delta_temp isnt multiplied
air.add_thermal_energy(heat_gain)
air.adjust_thermal_energy(heat_gain)
if(network)
network.update = 1
if(modeled_location.blocks_air)
@@ -227,6 +227,6 @@
// It currently should stabilise at 129.6K or -143.6C
heat_gain -= surface * STEFAN_BOLTZMANN_CONSTANT * thermal_conductivity * (air.temperature - COSMIC_RADIATION_TEMPERATURE) ** 4
air.add_thermal_energy(heat_gain)
air.adjust_thermal_energy(heat_gain)
if(network)
network.update = 1

View File

@@ -166,7 +166,7 @@
return
var/datum/gas_mixture/env = T.return_air()
if(env)
env.add_thermal_energy(10 * 1000)
env.adjust_thermal_energy(10 * 1000)
// Mostly a classic blob. No nodes, no other blob types.
@@ -440,7 +440,7 @@
T.freeze_floor()
var/datum/gas_mixture/env = T.return_air()
if(env)
env.add_thermal_energy(-10 * 1000)
env.adjust_thermal_energy(-10 * 1000)
// Electric blob that stuns.
/datum/blob_type/energized_jelly

View File

@@ -222,12 +222,12 @@
var/heat_transfer = removed.get_thermal_energy_change(set_temperature)
if(heat_transfer > 0 && env.temperature < T0C) //This should start heating the room at a moderate pace up to 0 celsius.
heat_transfer = min(heat_transfer , heating_power) //limit by the power rating of the heater
removed.add_thermal_energy(heat_transfer)
removed.adjust_thermal_energy(heat_transfer)
else if(heat_transfer > 0 && env.temperature < set_temperature) //Set temperature is 450 degrees celsius. Heating rate should increase between 200 and 450 C.
heating_power = original_temp*100
heat_transfer = min(heat_transfer , heating_power) //limit by the power rating of the heater. Except it's hot, so yeah.
removed.add_thermal_energy(heat_transfer)
removed.adjust_thermal_energy(heat_transfer)
else
return

View File

@@ -261,7 +261,7 @@
var/turf/T = get_turf(src)
var/datum/gas_mixture/env = T.return_air()
if(env)
env.add_thermal_energy(-10 * 1000)
env.adjust_thermal_energy(-10 * 1000)
/mob/living/simple_mob/slime/xenobio/dark_blue/apply_melee_effects(atom/A)
..()

View File

@@ -114,12 +114,12 @@
var/heat_transfer = removed.get_thermal_energy_change(set_temperature)
if(heat_transfer > 0 && env.temperature < T0C + 200) //This should start heating the room at a moderate pace up to 200 degrees celsius.
heat_transfer = min(heat_transfer , heating_power) //limit by the power rating of the heater
removed.add_thermal_energy(heat_transfer)
removed.adjust_thermal_energy(heat_transfer)
else if(heat_transfer > 0 && env.temperature < set_temperature) //Set temperature is 450 degrees celsius. Heating rate should increase between 200 and 450 C.
heating_power = original_temp*100
heat_transfer = min(heat_transfer , heating_power) //limit by the power rating of the heater. Except it's hot, so yeah.
removed.add_thermal_energy(heat_transfer)
removed.adjust_thermal_energy(heat_transfer)
else
return
@@ -182,12 +182,12 @@
var/heat_transfer = removed.get_thermal_energy_change(set_temperature)
if(heat_transfer > 0 && env.temperature > T0C - 275)
heat_transfer = min(heat_transfer , heating_power)
removed.add_thermal_energy(heat_transfer)
removed.adjust_thermal_energy(heat_transfer)
else if(heat_transfer < 0 && env.temperature > set_temperature)
heating_power = original_temp*100
heat_transfer = min(heat_transfer , heating_power)
removed.add_thermal_energy(heat_transfer)
removed.adjust_thermal_energy(heat_transfer)
else
return

View File

@@ -94,7 +94,7 @@ GLOBAL_VAR_INIT(power_per_point, 1000 KILOWATTS)
if(temperature_damage < 100)
temperature_damage++
return
env.add_thermal_energy(power_used)
env.adjust_thermal_energy(power_used)
/obj/machinery/power/crypto_miner/proc/process_thermal_properties()
var/datum/gas_mixture/env = loc.return_air()

View File

@@ -87,7 +87,7 @@
announce_warning(meltedrods, meltingrods, temperature >= max_temp ? 1 : 0)
decay_archived = decay_heat
add_thermal_energy(decay_heat * activerods)
adjust_thermal_energy(decay_heat * activerods)
equalize(loc.return_air(), envefficiency)
equalize_all()
@@ -321,7 +321,7 @@
removed.temperature = clamp( removed.temperature, 0, REACTOR_TEMPERATURE_CUTOFF)
env.merge(removed)
/obj/machinery/power/fission/add_thermal_energy(var/thermal_energy)
/obj/machinery/power/fission/adjust_thermal_energy(var/thermal_energy)
if(mass < 1)
return 0

View File

@@ -41,7 +41,7 @@
if(integrity == 0)
insertion_multiplier = 1
var/power = (tick_life(0, insertion_multiplier) / REACTOR_RADS_TO_MJ)
add_thermal_energy(power)
adjust_thermal_energy(power)
SSradiation.radiate(src, max(power * ROD_RADIATION_MULTIPLIER, 0))
/obj/item/fuelrod/proc/equalize(var/E, var/efficiency)
@@ -78,7 +78,7 @@
if(integrity == 0 && integrity_lost > 0) // Meltdown time.
meltdown()
/obj/item/fuelrod/add_thermal_energy(var/thermal_energy)
/obj/item/fuelrod/adjust_thermal_energy(var/thermal_energy)
if(mass < 1)
return 0

View File

@@ -518,7 +518,7 @@ GLOBAL_VAR_INIT(max_fusion_air_heat, INFINITY)
if(owned_core && owned_core.loc)
var/datum/gas_mixture/environment = owned_core.loc.return_air()
if(environment && environment.temperature < (GLOB.max_fusion_air_heat))
environment.add_thermal_energy(plasma_temperature*5000)
environment.adjust_thermal_energy(plasma_temperature*5000)
check_instability()
//Temperature changes depending on color. Now, the visibility of the field increases with temperature, along with the glow.

View File

@@ -346,7 +346,7 @@
visible_message("[src]: Releasing [round(thermal_power)] W.")
visible_message("[src]: Releasing additional [round((heat_capacity_new - heat_capacity)*removed.temperature)] W with exhaust gasses.")
removed.add_thermal_energy(thermal_power)
removed.adjust_thermal_energy(thermal_power)
removed.temperature = clamp( removed.temperature, 0, 10000)
env.merge(removed)

View File

@@ -186,7 +186,7 @@
if (environment && environment.temperature > min_temperature) // Abstracted as steam or something
var/removed_heat = between(0, volume * WATER_LATENT_HEAT, -environment.get_thermal_energy_change(min_temperature))
environment.add_thermal_energy(-removed_heat)
environment.adjust_thermal_energy(-removed_heat)
if (prob(5))
T.visible_message("<span class='warning'>The water sizzles as it lands on \the [T]!</span>")

View File

@@ -1583,7 +1583,7 @@
if (environment && environment.temperature > min_temperature) // Abstracted as steam or something
var/removed_heat = between(0, volume * 19000, -environment.get_thermal_energy_change(min_temperature))
environment.add_thermal_energy(-removed_heat)
environment.adjust_thermal_energy(-removed_heat)
if(prob(5))
T.visible_message("<span class='warning'>The foam sizzles as it lands on \the [T]!</span>")

View File

@@ -106,7 +106,7 @@
if(removed)
var/heat_produced = idle_power_usage //obviously can't produce more heat than the machine draws from it's power source
removed.add_thermal_energy(heat_produced)
removed.adjust_thermal_energy(heat_produced)
env.merge(removed)

View File

@@ -526,7 +526,7 @@
var/datum/gas_mixture/env = T.return_air()
if(env)
// This is most likely physically impossible but when has that stopped slimes before?
env.add_thermal_energy(-10 * 1000 * 1000) // For a moderately sized room this doesn't actually lower it that much.
env.adjust_thermal_energy(-10 * 1000 * 1000) // For a moderately sized room this doesn't actually lower it that much.
playsound(T, 'sound/effects/phasein.ogg', 75, 1)