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.