The current system for food temperatures is flawed


#1

Disclaimer: I am don’t know much c++. Anything I say about the code may be wrong. There may be some typos and such in the math too. If it doesn’t seem to make sense it may be wrong.

The current temperature system has issues.

  • Items of different size/mass change temperature at same rate.
  • Items of different size/mass freeze at same rate.
  • Freezing happens instantly once freezing temperature is reached.

The last one in particular is a big problem. Items freeze and unfreeze too easily.

For example freezing 1 kg of water requires taking 333 kJ of energy from it.
Cooling water from 79 °C to 0 °C also removes 333 kJ of energy from it (and the nergy is removed much much faster due to higher temperature difference). Freezing water takes much much longer than cooling the water but currently the game seems to completely ignore this.

As far as I understood the code the game works by tracking the temperature of the item. This approach is flawed and can never give satisfactory results.

The proper way to do it is to track the energy in the item and then calculating the temperature from the energy when needed.

Physics:

Rate of heat flow (Q) tells how much the item gains/loses energy. From there we can use approximation

Q = -ΔT × I × A × Δt

where Q is the ammount of energy transferred, ΔT is the temperature difference (kelvin or celcius. But we need everything to be in kelvin later so just use kelvin), I is insulation term, A is surface area and Δt is the time interval.

The proper way to do this would be to use integrals instead. In certain cases this approach may cool/heat the item below/above enviroment temperature incorrectly so there needs to be a small extra check. This approach also ignores that the insulation term is temperature dependant (mostly due to convection but also radiation). But this should be good enough for a game.

To get the surface area we can just assume all items are qubes and use the volume.

A = V2/3

After we know the ammount of energy change the energy in the item (E) is trivial.

E = E + Q

Now we can calculate the temperature of the item (T). First with naive assumption that the item is not frozen. Note that all the temperatures from now on must be in kelvins.

T = E / (cliquid×m)

where cliquid is the specific heat of the item (in not frozen state) and m is the mass of the item. This isn’t the “proper” way to calculate it as this is same as saying that at 0 K the item has 0 J of energy and then calculate temperature from there but it is good enough for a game.

Now if the above temperature is greater than the freezing temperature of the item everything is OK. But if it is less than the freezing temperature we need to check how frozen the item is and calculate the real temperature.

Lets check first if the item is completely frozen.

Tf × m+ csolid × m × Tfreezing > E

where Tf is the enthalpy of fusion, csolid is the specific heat of the solid and Tfreezing is the freezing temperature. If the above equation is true then the item is completely frozen.

And the temperature of a completely frozen item is

T = (E - Tf × mass) / (csolid×m)

If the term is negative then the item is partially frozen. Partially frozen items always have temperature exactly the freezing temperature.

T = Tfreezing

I would suggest that if the item is less than 50% frozen (arbitrary percentage that could be changed) then it can be used normally as if it was not frozen. To check if the item is 50% frozen use this equation

Tf × m × 0.5 + csolid × m × Tfreezing × 0.5 + cliquid × m × 0.5 > E

If the above equation is true the item is more than 50% frozen.

After all this has been done you would need to check if the item is being cooled below enviroment temperature/heated above enviroment temperature. If that is happening just set the temperature of the item to enviroment temperature and calculate the energy from there.

Mixing together items of different temperatures would be simply adding together the energies in them and then recalculating the temperature with above equations.

When consuming part of an item simply remove energy stored in the consumed mass. The temperature would not change in this.

E = T × m × c

Implementing this system would require all temperature tracked items to have their specific heats for frozen and not frozen states and also enthalpy of fusion. Easiest way for foods would probably be to use something based on water % of the food or some quesstimation for different kind of foods. The insulation term would also need to be determined.

Probably all items (non insulated) could use same insulation term. About 0.0025 would seem ok based on this study on water bottles (I just took the slope of the fig. 3 at 35 °C in gimp and calculated from that). Some much smaller value for thermos and other insulated items.

Now some pseudo code:

temperature_difference = item_temperature - enviroment_temperature

if temperature_difference == 0
    //There is nothing to do. No energy will flow. No temperature will change. No phase change will occur.
    //Don't waste time for the math in this case. Nothing has changed.

surface_area = volume^(2/3)

energy_change = - temperature_difference * insulation_term * surface_area * duration

theremal_energy += energy_change

// Assume it is not frozen
new_item_temperature = thermal_energy / ( specific_heat_liquid * mass )


if new_item_temperature < freezing_temperature
    // It is at least partially frozen
    if entalpy_of_fusion * mass + specific_heat_solid * mass * freezing_temperature > theremal_energy 
        // Completely frozen
        item_tags.insert( "FROZEN" );
        new_item_temperature = (thermal_energy - entalpy_of_fusion * mass ) / ( specific_heat_solid * mass )
    if entalpy_of_fusion * mass * 0.5 + specific_heat_solid * mass * freezing_temperature * 0.5 + freezing_temperature * specific_heat_liquid * mass  > theremal_energy 
        //Not fully frozen but more than half frozen. Same use limits as frozen items.
        item_tags.insert( "FROZEN" );
        new_item_temperature = freezing_temperature
    else
        //Partially frozen but still useable as if it was not frozen
        new_item_temperature = freezing_temperature

//Prevent cooling below enviroment temperature
if energy_change < 0 && new_item_temperature < enviroment_temperature
    new_item_temperature = enviroment_temperature
    if enviroment_temperature > freezing_temperature
        //Not frozen even if the above would say it is
        theremal_energy = specific_heat_liquid * mass * enviroment_temperature
        item_tags.erase( "FROZEN" );
//Prevent heating above enviroment temperature
elif energy_change > 0 && new_item_temperature > enviroment_temperature
    new_item_temperature = enviroment_temperature
    if enviroment_temperature < freezing_temperature
        //Is frozen even if above says it is not
        theremal_energy = specific_heat_solid * mass * enviroment_temperature
        item_tags.insert( "FROZEN" );


if new_item_temperature  < cold_temperature && not frozen
    //It is cold
elif new_item_temperature  > hot_temperature
    //It is hot
elif new_item_temperature  > warm_temperature
    //It is warm

#2

Not a programmer either but I do have an engineering background, and at a cursory inspection your approximation technique looks pretty good. But there is one caveat:

One significant drawback to implementing more sophisticated temperature and state tracking is the increase in processor demand for checking the state of everything in the reality bubble at each time increment. I played a lot of Dwarf Fortress in college, and they have a fairly sophisticated temperature/phase state tracking system in that game, similar to what you are proposing. I can tell you from experience that having large discrete quantities (stacks or individual containers) of food or liquids present and large map areas would cause massive lag in that game. I suspect that being in or near a deathmobile stuffed with food and liquids will make CDDA lag like a motherfucker if the temperature/state simulation is too sophisticated, not to mention moving through areas with rapidly varying environmental temperatures (driving near a lava rift in winter at 50 mph for example).

I could be wrong though, or overestimating the impact, or there could be differences in the game’s architecture compared to Dwarf Fortress that will mitigate this issue. Someone with programming expertise should try to implement this and see how it performs.

I can definitely agree that the current temperature system for freezing/unfreezing foods and liquids needs some work. Especially liquids in vehicle tanks for example. 200L of water in a metal tank should not freeze solid easily. Especially if adjacent to a part that would generate heat during operation, such as a combustion engine, microreactor, or storage battery. That way you could mount vehicle tanks around the microreactor or engine to keep their contents liquid. Alternatively, you could set the insulation value sky high for installed tanks, or have a “tank heater” and “tank insulation” that could be installed.


#3

Tricky and sticky enough to make most of the devs not want to touch it…making me sigh that we have it in the first place when it is unlikely to be solved =/

I really like that adjacent heat idea and thought of that as well. But it may not be fixed any time soon.


#4

If nobody wants to build a new temperature system, would it be possible to just adapt the coding for temperature from Dwarf Fortress to work with CDDA? I mean, its open source, and they already have an existing system that works pretty damn good as far as I know. Modifying something off the shelf beats building new from the ground up any day of the week.


#5

In a simulation like this you don’t need NASA grade calculation that would fry your CPU and plunge FPS to 1 per second to simulate basic concept. If you are up to the task however the gates are open, it’s an open project. But from my experience such discussion where someone says “I cannot code but I have this brilliant idea, here are 100 pages outline for that” or say “how hard would it be to to do this or do a port from other game” end up in dead end, because the answer is: hard. Very hard. I’m not discouraging anyone, but I doubt anyone would pick up a project that is too big for the end results that don’t need to be that sophisticated, detailed or accurate. Programming such things is a bit like magic tricks and illusions. You don’t need to code a V8 engine to “fake” the movement of a car. Unless like CDDA you need V8 engie to build a car. But then you don’t need to code engine parts. And so on.


#6

Jeez, I love dwarf fortress but a simple look at what happens to framerate when you toggle temperature tracking on and off should be a quick nail in the coffin of this idea.


#7

It strongly depends on map size and number of items present. The reality bubble on CDDA is smaller than a dwarf fortress map in terms of tiles I think, so it may be less of an issue. Also, I believe dwarf fortress is calculating heat transfer of moving portions of liquids too, (ie, bits of water moving through the map and mixing) so there may be some saved framerate there as well.


#8

Unfortunately, I don’t think DF is open source. Tarn has repeatedly stated that he wants to keep the project closed source, and while I haven’t been active in the community in over a year, I can’t imagine that’s changed. That being said, he’s a good guy and I’ve gotten advice about implementing mechanics from him in the past. If someone wanted to shoot him a email he’d probably respond.


#9

Before I get to parts of discussion, let me explain that I was chemical related university dropout(who did study at least basic chemistry as well as heat transfer) as well as a programmer who did glance over how comestibles are working and freezing right now. So let me try to convert this into more manageable, programmable form of realistic freezing system quick and dirty.

But first, what is freezing of an item? I am going to say it is liquid in whatever we are talking froze.
So if we are ever going to make multiple types of liquid freeze, liquid type must be defined first.

Assuming 1 ATM environment,
Property of liquid(it can be liquid or solid):
Name (we will use “Water”)
Liquid ID (l_water)
Freezing/melting Temperature (0 degrees celcius)
Heat capacity (energy it takes to change a degree celcius/kelvin per kilogram, and for liquid water it is 4.187 kJ/kgK )
Latent heat for freezing/thawing the liquid (AKA Enthalpy of fusion. this is amount of energy change for freezing or thawing, for water it is 334KJ/kg)

Name (we will use “Frozen water”)
Liquid ID (s_water)
Freezing/melting Temperature (0 degrees celcius)
Heat capacity (energy it takes to change a degree celcius/kelvin per kilogram, and for solid water it is 2.108 kJ/kg K )
Latent heat for freezing/thawing the liquid (AKA Enthalpy of fusion. this is amount of energy change for freezing or thawing, for water it is 334KJ/kg)

Above can all be hard coded if we are never going to deal with other liquids freezing.
identification if something is liquid or solid can also be hard coded.
weight of water or other properties should not matter as long as every value in every entries are realistic.

New property of comestibles:
Liquid ID (primary liquid of comestible - say, a bread. And for bread majority of liquid is liquid water, so this will be l_water)
Percentage value of liquid in comestible (Wikipedia says about 40%, so 0.4 it is)

We are going to ignore every other property of this bread to make calculations quick and faster.
We are also assuming that there is no such thing as “Half frozen” item, since such things do not exist in the game yet.
I have seen frozen item acting differently from liquid items, so I am also going to assume that frozen items are completely different item that are just switched out into solid ones with expiration date.

To sum up every value so far, we only need track Temperature of the item. Temperature of the item can be calculated from how much energy it currently has, Every other values can be calculated from it. We already have tickers that tracks how thawed items are(I think it was experimented with shelf thawing experiment) we do not need additional value. Now let’s see how much simplification we can get out of OP’s equations.

Incredibly quick, dirty and unrealistic way:
We ignore everything unless temperature is below freezing point for liquid, and above freezing point for solid.

OP’s equation from above.
Q = -ΔT × I × A × Δt

Let me simplify this because that is easier thing to do. Using a bread which has value of
Weight of bread = 0.06 kg
Percentage value of liquid in comestible = 0.4
Bread area = A = V^2/3 = 0.094L^2/3 = 0.0096 m^2

Q = -ΔT × I(some constant, fixed value) × 0.0096 m^2 × (Δt is 6 seconds, assuming single tick)

-ΔT is temperature difference, so how can this be calculated? Simple.
In current “Quick and dirty calculation” method we will just always assume bread is at 0 degrees Celsius.
We don’t even need to convert to kelvin because they cancel out. Yay.
ΔT = (0 for water’s current temperature - environment temperature in celcius) + (kelvin conversion - kelvin conversion)
Therefore ΔT = environment temperature in celcius

So currently,
Q = environment temperature in celcius x I(some constant, fixed value) × Bread area x 6 seconds
Now let’s tweak the equation so it calculate the temperature change.
Since we only need to calculate how much energy is needed to Freeze this bread, we just need to freeze all water inside the bread.
So Q = energy needed to freeze bread, so:
Q = Latent heat for l_water x Bread weight x liquid percentage =
Now I am going to cheat here. Since I want to keep only single value for calculation we will just track energy of water in temperature, so we will just assume at certain temperature of water, it is suddenly all freeze to ice. This temperature can easily be calculated by Latent heat/Heat capacity, and for l_water it is (334KJ/kg) / (4.187 kJ/kgK) = approximately 80 degrees. This means -80 degree liquid water have same energy as 0 degrees ice, and we will assume at -80 degrees liquid water will suddenly turn to ice(item temperature is always assumed to be 0 so calculation should not matter much for this equation).
Temperature change for bread assuming state does not change = Q/(Heat capacity x Bread weight x liquid percentage)
Temperature change for bread assuming state does not change = Q/(Heat capacity x Bread weight x liquid percentage) = -(environment temperature in celcius) x I(some constant, fixed value) × (Bread area x 6 seconds, also fixed) / (Heat capacity for liquid water x Bread weight x liquid percentage)
Well that was easy.

Unit calculation = K = K * (W/(m^2 K)) * s * m^2 / (J/kgK * kg) = K

In programming terms, C++(rusty and therefore could be wrong):

double tempdiff =  comestibles.getliquid().getfreemeltpoint() - environment temperature in celcius;
// if liquid 
if (comestibles.getliquid().substr(0,1) = 'l')
{
	//calculation for liquid -> solid
	
	if (tempdiff > 0)
	{
		comestibles.addtemp(-tempdiff * I(some constant, fixed value) * pow (comestibles.getarea(), 0.666) * 6 / (comestibles.getliquid().getheatcap()) / comestibles.getweight() / comestibles.getliquidpercent());
		// change state if calculation says sufficient energy/temperature point is reached.
		if (comestibles.gettemp() < -(comestibles.getliquid().getlatantheat()/comestibles.getliquid().getheatcap()))
		{
			item_tags.insert( "FROZEN" );
		}
	}
	else 
	{
		comestibles.settemp(comestibles.getliquid().getfreemeltpoint());
	}
}
else 
{
	//calculation for solid -> liquid
	if (tempdiff < 0)
	{
		comestibles.addtemp(-tempdiff * I(some constant, fixed value) * pow (comestibles.getarea(), 0.666) * 6 / (comestibles.getliquid().getheatcap()) / comestibles.getweight() / comestibles.getliquidpercent());
		// change state if calculation says sufficient energy/temperature point is reached.
		if (comestibles.gettemp() > comestibles.getliquid().getlatantheat()/comestibles.getliquid().getheatcap())
		{
			item_tags.delete( "FROZEN" );
		}
	}
	else 
	{
		comestibles.settemp(comestibles.getliquid().getfreemeltpoint());
	}

}

So by few multiplication and division and few if statements, status change proposed by OP can be easily implemented with lots of cut corners, although this code will make 200L melt a lot less quick than 1L, make freezing temperature dependent as well as more realistic.
I was going to write longer ones but I got too tired at this point. We will see how this one goes


#10

Approximating “item temperature = freezing temperature” has some bad consequences.

If the enviroment is warmer than freezing temperature then the item will keep gaining energy without limit. And in colder than freezing point it will keep losing energy without limit.

Since the temperature needs to be calculated at some point it would probably be best to save both temperature and energy in the item. This way it can be instantly checked if item temperature = enviroment temperature to see if anything needs be even done.


#11

Frankly I am not keeping track for temperature of items unless they(or their primary liquid) are on freezing/thawing temperature, because that is the only time that temperature matters, and I am here to propose the script for freezing and only freezing that would not eat the CPU alive with every tick.
“Not caring about temperature” as in:
Item temperature is always considered to be at freezing point.
Item spoilage will use background temperature.
If background temperature > freezing point then item have zero energy.(or energy of 0 degrees Celsius liquid/solid)
If background temperature > freezing point then item not have any heat transfer at all.

In conclusion, for above script’s heat transfer equation will only be used if background temperature < freezing point(vice versa for solid), under the assumption that tracking individual item temperature when background temperature is low or high enough to not cause a change of state(freezing or thawing) and is unnecessary and costly with processing power needed to run heat transfer equation every turn.

Still, change of script itself should be easy.(also I am not going to store energy of the item, because energy of the item is just Q = Heat capacity x Item temperature x item weight x item liquid percentage)


#12

The temperature calculation doesn’t need to run anywhere near every tick.

If the enviroment temperature does not change then the calculation can be done maube twice in an in-game hour. Since player may move to an area with different temperature faster than that the calculations could maybe be done once every few in-game minutes.

I put the my code into matlab. Here is example of 1 liter water bottle at 100 °C being placed in -100 °C enviroment (while doing this I also realized that kelvins are not needed and everything can be done with celcius). Each plot is done with different time delta. You can see that until the delta is over one hour the values are close enough that the differences don’t matter. This is just to demonstrate how slowly this happens so the temperature does not need to be recalculated very often.


(the insulation term 0.0025 is probably a bit too small since in this example it took 36 hours for the water to go from completely liquid to completely solid. Though the plan would be to consider 50% frozen as frozen already so it wouldn’t be full 36 hours until you wouldn’t be able to drink it).

It seems that items already run each on their own timer on when to recalculate the temperature. If we wanted to be fancy then items carried by player could be calculated every few minutes while items on ground are caculated once every 20 minutes or something like that.

We can also simplify the situation slightly by using same specific heat for frozen and not frozen item. This will make the frozen item cool down too fast but it will also heat up too fast so the resulting behavior should be close enough.

New pseudocode with some fixes:

    temperature_difference = item_temperature - enviroment_temperature
    
    if temperature_difference  == 0
        // No need to calculate anything
        return    
    
    surface_area = volume^(2/3);

    
    energy_change = - temperature_difference * insulation_term * surface_area * duration
    
    new_energy += energy_change;
    
    // Temperature assuming item was and still is not frozen
    new_item_temperature = new_energy / ( specific_heat * mass )
    
    if new_item_temperature < freezing_temperature
        // Item is partially frozen or completely frozen
        completely_frozen_energy = mass * ( specific_heat * freezing_temperature - entalpy_of_fusion )

        if completely_frozen_energy > new_energy
            // Item is completely frozen
            new_item_temperature = (new_energy + entalpy_of_fusion * mass ) / ( specific_heat * mass )
        else
            // Item is partially frozen
            new_item_temperature = freezing_temperature
            
            not_frozen_energy = specific_heat * mass * freezing_temperature
            
            freeze_percentage = (new_energy - completely_frozen_energy) / not_frozen_energy
            
            if freeze_percentage > 0.5
                // item is frozen enough that it is tagged as frozen

    //Prevent cooling below enviroment temperature
    if energy_change < 0 && new_item_temperature < env_temperature
        new_item_temperature = env_temperature
        if env_temperature >= freezing_temperature
            // Not frozen even if the above would say it is
            new_energy = specific_heat * mass * env_temperature;
    // Prevent heating above enviroment temperature too
    elif energy_change > 0 && new_item_temperature > env_temperature
        new_item_temperature = env_temperature
        if env_temperature <= freezing_temperature
            // Is frozen even if above says it is not
            new_energy = specific_heat * mass * env_temperature
        end
    end
    
    if new_item_temperature  > hot_temperature
        // Tag as hot
    elif new_item_temperature  > warm_temperature
        // Tag as warm
    elif new_item_temperature  < cold_temperature && not_frozen
        // Tag as cold

So single temperature check will have following calculations:

surface_area = volume^(2/3);
energy_change = - temperature_difference * insulation_term * surface_area * duration
new_energy += energy_change;
new_item_temperature = new_energy / ( specific_heat * mass )

Then some if statements.
If the item was not frozen and still is not frozen no more math is done.

If item is freezing/frozen then following math is also done

completely_frozen_energy = mass * ( specific_heat * freezing_temperature - entalpy_of_fusion )

if is frozen

new_item_temperature = (new_energy + entalpy_of_fusion * mass ) / ( specific_heat * mass )

if is partially frozen

not_frozen_energy = specific_heat * mass * freezing_temperature
freeze_percentage = (new_energy - completely_frozen_energy) / not_frozen_energy

Then some if statements and the edge cases that would happen rarely.

I don’t think doing this every few in-game minute for every item would have too big impact on performance.


#13

And THIS is where I have issue with this. My character happen to have weather detector and know that temperature does change every 2 hours or so on average day, because CDDA have day and night temperature change and it is pretty smooth(+ or - 1 degree every hour or 2 hours).

So let’s say I have a van, and I have 15 trunks, and each trunks have 30 edible item stacks(which is an understatement considering I could have at least 10 types of drink per trunk). This is very average van that I am sure most people have. I will be generous and say only 50% of those items will freeze.
Let us also assume temperature change happens almost instantaneously and it only take 3 ticks - something that is very unrealistic and conservative considering small temperature difference from small day/night temperature mean more ticks for complete temperature change.

Of course, I also have a bed in this van, so I would sleep here. Let’s say I do it for 8 hours per day.
How many times the calculation must be done?

15 trunks * 30 food/trunk * 0.5 frozen food/food * 8 hours * 0.5 temperature change/hour * 3 calculations/temperature change per food = 2700 times of temperature changing equation need to be ran

By just sleeping in my van.
And not including outside world.
With very conservative values on everything. The real thing would easily be over 5 times that.

Also that is where I spend most of time crafting stuff.


#14

Seems like when I have a few hundred items of various food + on board water tanks + heat source + whatever else I can’t think of. This will be a fps hit I’m thinking should be simplified…this coming from a stern believer in realism =/

Not that I wouldn’t be interested. I just don’t think the game would handle well when the game then added several hundred more items in a dense city area.


#15

The main concern seems to be about performance. Well I tested it.

To test this I edited the temperature calculation code and compiled a test version of CDDA. I added some dummy calculations in it to simulate proper temperature calculations. The code doesn’t calculate anything real.

I am not sure what files to share if someone else wants to test this. Just copy the code below in right place in item.cpp and follow building instructions in github.

Edits done in item.cpp

I replaced if( dur > 10_turns ) { with if( dur > 100_turns ) {. I think this results in temperature being recalculated every 100 turn (10 minutes) instead of every 10 turn (1 minute). 1 minute is just too often to make any sense for temperature calculations.

Then I replaced the contents of void item::calc_temp( const int temp, const float insulation, const time_duration &time ) with some dummy math.

void item::calc_temp( const int temp, const float insulation, const time_duration &time )
{
    //The parts here are only to get rid of warnings about unused parameters and fuctions. They don't do anything.
    const int freeze_point = type->comestible->freeze_point;
    
    if ( temp > 999 ) {
        return;
    }
    else if ( insulation > 999 ) {
        return;
    }
    else if ( time < 0 ) {
        return;
    }
    else if ( temp_difference_ratio( temp, freeze_point ) > 999 ) {
        return;
    }
    
    // Just define some test values
    float insulation_term = 0.0025;
    float volume = 1.25;
    float item_temperature = 273.16; //0.01 C
    float specific_heat_liquid = 4.186; // kJ/kg K
    float specific_heat_solid = 2.108; // kJ/kg K
    float latent_heat = 333; //kJ/kg
    float mass = 1.25;
    float energy = 1240.65025; // 273.15 * 2.108 * 1.25 + 333 * 1.25 + 20 * 4.186 * 1.25
    float freezing_temperature = 273.15; // 0 C
    float enviroment_temperature = 243.16; // -30 C
    int duration = 600; //100 turns = 600 seconds
    
    //Do some dummy math that would be similar to calculating the real deal
    float temperature_difference = item_temperature - enviroment_temperature;
    
    float surface_area = pow(volume, 0.66);
    float energy_change = - temperature_difference * insulation_term * surface_area * duration;
    energy += energy_change;
        
    // Temperature assuming item was and still is liquid
    float new_item_temperature = freezing_temperature + ( energy - mass * ( latent_heat - specific_heat_solid * freezing_temperature ) ) / specific_heat_liquid;
    
    //Lets assume quess was wrong and item is actually partially frozen now (too lazy to add the check. Just a simple if x>y comparison)
    //The assumption is wrong only if the item freezes/melts.
    new_item_temperature = freezing_temperature;
    
    //Calculate how partially frozen it is
    //completely frozen energy = mass * specific_heat_solid * freezing_temperature
    //Completely not frozen energy = completely frozen energy + mass * latent_heat
    float completely_frozen_energy = mass * specific_heat_solid * freezing_temperature;
    float freeze_percentage = ( energy - completely_frozen_energy ) / (completely_frozen_energy + mass * latent_heat );
    
    //More things to avoid warnings about unused parameters
    if ( new_item_temperature < 10 ) {
        return;
    }
    
    if ( freeze_percentage > 50) {
        //"fully" frozen.
        return;
    }
    
    return;
}

Then I loaded the same save in normal CDDA and thest CDDA. In the save I am standing in my car with food and other junk in the cargo space (not insanely big wares of items but something). I waited for 19 hours and timed how long the wait took.

Normal CDDA took 30 seconds to wait 19 hours.

With the test code it took 30 seconds to wait 19 hours.

The test wasn’t very well controlled. The saves were identical but the game doesn’t seem to be deterministic. Sometimes I would get attacked by zombies while waiting. But the time differences were still very small.

The test case in the code is worse than what would usually be calculated. The test case here assumes that the item is not-frozen and then becomes frozen. So it needs to calculate the energy and frozen percentage as extra. In most cases doing the temperature calculation once would be enough.

The real code would also have few if-else statements but I don’t believe those would have big impact on performance. The dummy code just has the calculations that would be inside those if-else statements.

The temperature being calculated every 10 minutes is not optimal. Items that just sit on ground could calculate their temperatures once every hour (or even less frequently) while items carried by player may need to calculate temperature a bit more frequently to avoid edge cases and since player will interact with them. (for example player steps in fire for one second, temperatures get calculated as if the item had been in fire for past 10 minutes. Or water in bottle would freeze in 10 minutes but next update happens 1 hour later).

But I am now confident that doing proper temperature calculations would not cause noticeable performance problems.

I don’t know how to actually implement anything like this in the game. This is just to show that it could be done.


#16

So to sum it up. Large volumes of items won’t drag on the fps?


#17

Seems so. If you have a save with humogonous ammount of temperature tracked items stacks I could test that. Just move into a location where I can wait for a very long time without being interrupted.


#18

Well nobody seems interested in implementing this.

So I guess I try. How hard could it be (I may regret this).

Things that I don’t really know about:

Add temperature and thermal energy to items
I looked at how the temperature is currently saved in an item (I may be wrong here). Items have tem_counter that is used to store whatever information about the item. For foodstuff it stores information on the temperature in some format I don’t get (it is clearly not using any real temperature unit). It wouldn’t be used anymore but it would probably be good to at least understand how it works so I could adjust the other item temperature based systems.

The temperature of the item could probably be just stored in the item_counter like it is now (though maybe using int instead of float for it could add problems). Just using “real” temperature units like farenheits (I would really prefer doing it with celcius or kelvin but it seems that farenheit is used everywhere so mixed units would just be mess. Heat capacity would still be per celcius/kelvin and the math would be in celcius/kelvin, just convert before math or add constants to convert on the fly).

But I am not sure how add the thermal energy to items. Would I just add float thermal_energy = 0 under std::set<std::string> item_tags in item.h and all items would have thermal_energy in them? Of course only temperature tracked items would need it so adding it to all items isn’t the optimal case… (probably just makes save files a bit bigger)

Edit: Monkey see, monkey do. Adding float thermal_energy = 0 adds it to items and adding archive.io( "thermal_energy", thermal_energy, 0 ); in savegame_json.cpp makes it save the value in saves.

Add new “partially frozen” and “completely frozen” tags to items
Could I just use item_tags.insert( "PARTIALLY_FROZEN" ); and item_tags.insert( "COMPLETELY_FROZEN" );without any edits or do the tags need to be defined somewhere?


#19

Umm…you’ve obviously got c++ experience and seem comfortable with playing with the code. Why don’t you get on github and submit a PR? That’s the only way this is going to get any traction. You know the changes you want to see and where the changes need to be made, you’re the best person to implement them. I can’t even follow what you’re trying to do. You’ll get a lot more help on github as well, most of the people there are capable coders.


#20

My c++ experience is that I made a very very simple tick-tack-toe some five years ago. Don’t know how to make pull requests so I’ll get to that later…

I think I have managed to add latent heat, specific heat liquid and specific heat solid to items so that if they are in the json then they get used (and if they are not in there then the values of water are used).

Joys of c++
src/item.cpp:6433:8: error: variable 'new_item_temperature' set but not used [-Werror=unused-but-set-variable]

I remove it

src/item.cpp:6440:3: error: 'new_item_temperature' was not declared in this scope

Edit: There was an extra } that somehow didn’t cause errors on its own