Jump to content

Grass's Extremely Technical guide to Heat Source Mechanics


Recommended Posts

Here I will walk through the code and explain how to calculate the exact temperature any combination of any number of heating and/or cooling sources, on the ground or in your inventory, at any distance, wet or dry, in any world ambient temperature, etc, can warm players and/or thermal stones.

So first, it's important to understand the "self.delta" variable in the temperature.lua script. It's calculated every frame and can be almost any number. It starts as the ambient temperature subtracted by the player temp with possibly a couple other modifiers, and then the game goes through every single nearby heat source and cooling source within a 10 unit (2.5 tile) radius and each of these add or subtract to the self.delta. It will often end up with some crazy number but more or less all that matters to the game at the moment is if it's positive or negative. The delta mostly just determines whether the player will be warmed, cooled, or stay about the same temperature. But I've figured out an easy way to use it to calculate how much the nearby heat sources can warm/cool the player to, too.

Before nearby heat sources are calculated or when there aren't any, this is what self.delta is:

self.delta = ambient_temperature + self.totalmodifiers + self:GetMoisturePenalty() - self.current

Unless you're wet or under the effect of fire nettles, you can ignore self.totalmodifiers and self:GetMoisturePenalty() to simplify it to just the ambient temperature minus the player temperature. With fire nettles, add 60.

I'm doing a simple example in winter. Let's say ambient temp is -20 degrees and the player's temperature is currently 0 degrees.

self.delta = -20 + 0 + 0 - 0
self.delta = -20

Every warming and cooling source has a "heat" in the code. You can also find them on the wiki pages for freezing and overheating or asking me. I'm using the scaled furnace which has a "heat" of 115 degrees.

local heat = v.components.heater:GetHeat() --Get the heat of the heat source
heat = 115

Next, heatfactor is calculated based on the distance to the center of the heat source. A player standing right next to a scaled furnace is 1 unit (wall unit) away from it's center. This distance is squared so if you were 2 units away the DistanceSquared would be 4. But 1 squared is still 1.

local heatfactor = 1 - DistanceSquared_To_Player / 100 
heatfactor = 1 - 1 / 100
heatfactor = 0.99

Next the heatfactor is multiplied by the heat of the heat source. In this case the heatfactor only reduces the heat by 1% but if you were, say, 7 units away it would be a 49% reduction.

local warmingtemp = heat * heatfactor --multiply the heat factor and the heat
warmingtemp = 115 * 0.99
warmingtemp = 113.85

Things are slightly different with a cooling source, however, because it has to be based around the overheat temperature of 70 degrees. This doesn't have to be done with warming because the freezing temp is 0 degrees.

local coolingtemp = (heat - self.overheattemp) * heatfactor + self.overheattemp
--selfoverheattemp = 70

Back to the scaled furnace. The warmingtemp of 113.85 is definitely higher than the player temperature of 10 degrees so this next "if" statement is passed. Of course with a coolingtemp, it has to be less than the player temp.

if warmingtemp > self.current then --If the warming temperature is higher than the current player temperature, do this
--  113.85 > 0
  
-- Endothermic heat sources
  if coolingtemp < self.current then

But now self.delta is being warmed by warmingtemp subtracted again by self.current. Thermal stones in your inventory also have a 2.1x multiplier, and scorching sunfish a 2x multiplier to (warmingtemp - currenttemp) in the form of carriedmult. But for a scaled furnace, we ignore this value. And the formula is the exact same for a coolingtemp, by the way.

self.delta = self.delta + (warmingtemp - self.current) * carriedmult --carriedmult only for heat sources in your inventory, ignore it otherwise
self.delta = -20 + (113.85 - 0)
self.delta = 93.85

So with just 1 scaled furnace nearby, self.delta is 93.85 degrees. Obviously a scaled furnace can't warm you that high during winter. So what we have to do is divide it by 2. That's because the player temperature is actually being subtracted from self.delta twice in total; once in the beginning calculation and once subtracted from the scaled furnace's warmingtemp here. With a second valid heat source, we'd divide by 3.

93.85 / 2 = 46.93 degrees

But what if there was also say, a level 1 (small) endothermic fire nearby? It has a heat of -10 degrees. It's 3 units away from the player so the heatfactor would look like this:

local heatfactor = 1 - DistanceSquared_To_Player / 100 
heatfactor = 1 - 9 / 100
heatfactor = 0.91

This heatfactor is used to calculate the coolingtemp like so.

local coolingtemp = (heat - self.overheattemp) * heatfactor + self.overheattemp
coolingtemp = (-10 - 70) * 0.91 + 70
coolingtemp = -2.8

And this is added to self.delta along with the players temperature being subtracted--self.delta starts equal to 83.85 because of the scaled furnace

--self.delta starts equal to 93.85 because of the scaled furnace
self.delta = self.delta + coolingtemp - self.current
self.delta = 93.85 + (-2.8 - 0)
self.delta = 91.05

The delta only decreased by like 2 degrees, but that's misleading. Now, the player is only warmed to about 30 degrees instead of 47. For every additional valid heat source, increase the number you're dividing by, by 1. For thermal stones and scorching sunfish in your inventory, this number is actually instead increased by 2.1 and 2 respectively. So with a scaled furnace + thermal in inventory, you'd divide the self.delta by 3.1.

91.05 / 3 = 30.35 --max temp a scaled furnace + small endo fire can warm you to in winter

NOTE: If a heat source's warming temp is less than the temperature that the other nearby heat sources can warm you to, or if a cooling temp is greater than this temperature, IGNORE it. For example, a thermal stone has a "heat" of 60 degrees. If other nearby heat sources can warm you past 60 degrees, the thermal stone does nothing.

if warmingtemp > self.current then
	self.delta = self.delta + warmingtemp - self.current
end

if coolingtemp < self.current then
	self.delta = self.delta + coolingtemp - self.current
end

WETNESS is actually pretty straightforward???

When the player is wet, self.delta is decreased by up to 30 based on the wetness level. It's just the percentage of your wetness as a decimal multiplied by -30. So 100 wetness is -30 and 50 wetness is -15. When there aren't any heat sources nearby, this effectively decreases the world temp for the player by (up to) 30 degrees.

The heatfactor (the decimal value reducing the effectiveness of the heat source) is multiplied by 0.75 if the heat source player is wet. So if a wet player is 4 units away from a heat source, the heatfactor is 0.63. Thank you for correction hornet.

local heatfactor = 1 - self.inst:GetDistanceSqToInst(v) / ZERO_DISTSQ
heatfactor = 1 - 16/100 --4 unit distance
heatfactor = 0.84 * 0.75 --wetness penalty
heatfactor = 0.63

 

OTHER NOTES for the 3 people that made it to the end of this in one piece...

  • Ambient temp and world temp are the same thing and I used them interchangeably
  • I said "player temp" but what would be more accurate is "player or thermal stone temp". Thermal stone's internal temperature works exactly like a player's. And this can be used to calculate how high heat source(s) raise a thermal stone's temperature as well. The only difference is that thermal stones can NOT warm other thermal stones for obvious reasons. So ignore those heat sources when calculating a thermal stone's temperature.
  • @Hornete is evil but thanks for explaining things to me even through your 3+ mental breakdowns :grin:
  • If you actually find this useful or are curious about it for some reason feel free to ask any questions here or on the discord
  • Definitely good that I'm making this into a seperate post instead of a giant spoiler on my winter warmth strat post

Archived

This topic is now archived and is closed to further replies.

Please be aware that the content of this thread may be outdated and no longer applicable.

×
  • Create New...