Shoes' Temperature mod

Uh… mine did this from the get go. It was built into the original formula. And it didn’t have any of the weird fixed offsets/fixed values or strange logic. I mean, do you have a random heating/cooling element there? Whats that for? :P[/quote]

I see the gap size change now! I still prefer the model of having weather effects change the max/min possible body temp, and each so many turns have the bodytemp increment towards that, instead of having weather directly affect body temp. It does not reflect reality, but it is easier to balance. We can set hard caps on min/max bodytemps or play with the mins and maxes without playing with the rate of temperature change.

However! I’ve successfully compiled the game! Now I can start experimenting to see if this actually works!

edit : and now I see some flaws in my code to fix :3 mostly mathematical, and the fun-wise

In an effort to make my code reflect Gryph’s, I think I am causing the game to slow down. Here is what I have now :

void game::update_bodytemp()
{
 // NOTE I didn't do anything with levz, bionics, or diseases
 double Ctemperature = (temperature - 32) * 5/9; // Converts temperature to Celsius!(Wito plans on using degrees Kelvin later)
 double temp_gap = Ctemperature - 22;  // distance actual temp and room temp (22C) ; this value is negative when it is colder than 22C
 double warmth = u.warmth(bp_head) + u.warmth(bp_eyes) + u.warmth(bp_mouth) + u.warmth(bp_torso); // At the moment, warmth is only head/face and torso
  
 // Calculating bodywetness. I don't know how to access the bodywetness values found in the morale screen ; ideally, I would just use that.
 if (weather_type(4) == true && bodywetness < 30) {bodywetness += 1;}
 else if (weather_type(5) == true && bodywetness < 50) {bodywetness += 1;}
 else if (bodywetness > 0) {bodywetness -= 1;}
  
 // Determine max bodytemp
 int impact = 0;
 if (!m.is_outside(u.posx, u.posy)) {impact = 0.1;}
 if ( m.is_outside(u.posx, u.posy)) {impact = 0.5;}
 
 converging_bodytemp = 37 
			+ temp_gap*impact 
			+ 0.30*(1 - 0.20*bodywetness)*warmth 
			- 0.10*(bodywetness);
 
 double body_temp_gap = bodytemp - converging_bodytemp;

 // Actually change bodytemp
 if (bodytemp != converging_bodytemp){
   if      (bodytemp > converging_bodytemp && converging_bodytemp < 37) {bodytemp -= 0.1*pow(2,abs(body_temp_gap)/4);} // It is cold, you are getting cold
   else if (bodytemp > converging_bodytemp && converging_bodytemp > 37) {bodytemp -= 0.1;}                        // It is warm, you are getting cold
   else if (bodytemp < converging_bodytemp && converging_bodytemp < 37) {bodytemp += 0.1;}                        // It is cold, you are getting warm
   else if (bodytemp < converging_bodytemp && converging_bodytemp > 37) {bodytemp += 0.1*pow(2,abs(body_temp_gap)/4);} // It is warm, you are getting warm
 } 
}

Major changes : my bodytemp converging code never converged ;p so now it just checks the conditions, and applies it to 37C. I am using doubles with everything, because I don’t know how to code :smiley: I want one decimal place, and int can’t do that… so I use double. I wouldn’t be surprised if this is what is slowing the game down…

After noticing that my 4 ifs about converging temps were all the same, except for the temp_gap, I decided to go with a multiplier like Gryph. At the moment, it just sets a multipler if the player is outdoors or not. I want to be able to tweak things individually according to certain parameters.

So yeah. If someone could suggest a better way to do the math, I’d love to hear it :slight_smile: Maybe multiply everything by 10 and work with 370 instead of 37.0.

If it’s your code causing the slowdown, it should be very obvious that every 30th or so turn is longer than the others. (unless you’re actually running this every turn?)

When working with floats, you need to make very sure that all of the variables and literals involved are also floats, whenever you do an operation with a float and an int, the float is truncated to an integer value to perform the operation, and the result is also an int, to the truncation propagates.

I see at the very beginning you have integer literals in your operations. You can force a literal to be a float by adding useless precision e.g. 32.0 instead of 32.

Alternately yes, you can just use ints and multiply everything by a constant factor to get the precision you want. I think storing temp in tenths of a degree is a good precision to have.

This can wait until later, but the warmth from different body parts should probably be weighted, with torso >> head > mouth > eyes

Accessing the morale value would be something like:
int wetness = 0;
for (int i = 0; wetness == 0 && i < g->u.morale.size(); i++)
if( g->u.morale[i].type == MORALE_WET ) {
wetness = g->u.morale[i].bonus;
}
}

Don’t use floats for this. There is literally no reason not to use unsigned ints. The internal representation does not have to mirror the external appearance, and in fact it shouldn’t if another representation would be more efficient.

you should also be able to increase efficiency by not recalculating all these variables unless you need to. Outside temperature shouldn’t be changing every call, nor should the player total warmth.

And yeah, how often is this being called? Do you only have slowdown on those turns?

I am cutting down on some redundancies, and I notice the game is playing like it should. I have update_bodytemp() being called every 10 turns. I would like to keep it short like that, so if you jump in water during a blizzard, you will feel the effects almost instantly. However, I could make jumping in the water have an immediate effect… maybe small.

I also decided to multiply everything by 10 to avoid the headache of unsigned/signed ints and floats and whatnot.

At the moment, I am fixing the bugs from multiplying everything by 10. After that, I will work wetness in (thanks kevin :)).

For the warmth thing being calculated, I think I will reinstate the check_warmth() function, but not put the penalties in it. I will put the penalties in the body warmth code.

Maybe I will move the temp_gap variable to the update_weather() function too.

It is taking shape! I can’t wait to actually add gameplay impacts like getting cold from having -100C body temp…

edit : I am using unsigned int, but my 370 degrees keeps looping around to 114 (370 - 255). I thought unsigned int went from 0 to 4294967295. Even as a long unsigned int it’s not working :x I am confused big time. And I know it’s not my math, because I commented out all the variation. It’s just converging_bodytemp = 370;. I am outputting on the screen as char, which is only 1 byte. :slight_smile:

void game::update_bodytemp()
{
 // NOTE I didn't do anything with levz, bionics, or diseases
 int Ctemperature = (temperature - 32) * 5/9; // Converts temperature to Celsius!(Wito plans on using degrees Kelvin later)
 int temp_gap = 10*(Ctemperature - 22);  // distance actual temp and room temp (22C) ; this value is negative when it is colder than 22C
 int warmth = u.warmth(bp_head) + u.warmth(bp_eyes) + u.warmth(bp_mouth) + u.warmth(bp_torso); // At the moment, warmth is only head/face and torso
  
 // Determine max bodytemp
 int impact = 0;
 if (!m.is_outside(u.posx, u.posy)) {impact = 1;}
 if ( m.is_outside(u.posx, u.posy)) {impact = 4;}
 
 /* Fetch the morale value of wetness for bodywetness 
 for (int i = 0; bodywetness == 0 && i < u.morale.size(); i++)
 if( u.morale.type == MORALE_WET ) {
  bodywetness = u.morale.bonus;
 }
 */

 int warmth_bonus = 0;
 if      (temp_gap > 0) {warmth_bonus = 3*warmth/2;}
 else if (temp_gap < 0) {warmth_bonus = 3*warmth*2;}
 
 converging_bodytemp = 370 
						+ temp_gap*impact/10 
						+ warmth_bonus
						//- bodywetness
						;
 
  unsigned int body_temp_gap = bodytemp - converging_bodytemp;
   
 // Actually change bodytemp
 if (bodytemp != converging_bodytemp){
   if      (bodytemp > converging_bodytemp && converging_bodytemp < 370) {bodytemp -= 1*abs(body_temp_gap)/4;} // It is cold, you are getting cold
   else if (bodytemp > converging_bodytemp && converging_bodytemp > 370) {bodytemp -= 1;}                      // It is warm, you are getting cold
   else if (bodytemp < converging_bodytemp && converging_bodytemp < 370) {bodytemp += 1;}                      // It is cold, you are getting warm
   else if (bodytemp < converging_bodytemp && converging_bodytemp > 370) {bodytemp += 1*abs(body_temp_gap)/4;} // It is warm, you are getting warm
 }
 
 // Diseases
 if (bodytemp < 350) {
    if (u.has_disease(DI_COLD) == false) {add_msg("You have mild hypothermia.");}
	u.add_disease(DI_COLD, 11, this, 1, 1); 
} else if (bodytemp < 325) {
	add_msg("You have moderate hypothermia.");
	u.add_disease(DI_COLD, 11, this, 2, 2); 
} else if (bodytemp < 300) {
	add_msg("You have severe hypothermia.");
	u.add_disease(DI_COLD, 11, this, 3, 3); 
} else if (bodytemp > 390) {
    add_msg("You have mild hyperthermia.");
} else if (bodytemp > 410) {
    add_msg("You have moderate hyperthermia.");
} else if (bodytemp > 430) {
    add_msg("You have severe hyperthermia.");
} else if (bodytemp < 280 || bodytemp > 460) {
    add_msg("You die from too much thermia.");	// This kills the player
}

When running the wetness code, I got this error. It seems morale isn’t detailed enough at the moment.

g++   -g   -c game.cpp -o obj/game.o
game.cpp: In member function ‘void game::update_bodytemp()’:
game.cpp:720:15: erreur: ‘class std::vector<morale_point>’ has no member named ‘type’
game.cpp:721:26: erreur: ‘class std::vector<morale_point>’ has no member named ‘bonus’
game.cpp:725:2: erreur: expected ‘,’ or ‘;’ before ‘if’
game.cpp:726:2: erreur: ‘else’ without a previous ‘if’
game.cpp:777:38: erreur: expected primary-expression before ‘const’
Makefile:125: recipe for target `obj/game.o' failed
make: *** [obj/game.o] Error 1

Also! The disease section works :slight_smile: The only issue is that the message for -thermias play every ten turns. The u.has_disease() doesn’t recognize intensity (I don’t think), which is what I would really want. If the DI_COLD gets worse, tell the player ; if not, don’t say anything.

I cleaned up the converging_bodytemp stuff, it was more complicated than it needed to be. I also added the fact that strong at resisting cold but weak and increasing heat. I still have to play with the numbers though.

What I would like specific advice on is on how to clean up the bodytemp increment code. There are four different cases, and I want the bodytemp to increment differently for each. For example, if it is super cold out, the bodytemp should drop a lot, but if you layer up a ton, you shouldn’t suddenly gain heat like mad.

I ramble a lot in these posts, so don’t think you have to comment or solve everything ;p anyway, movie time.

edit: I find myself wishing I could use exponents. Should I, or is that bad? Because I really want this to be exponential…

You’re probably going to have to max dozens of diseases of different severities, for each possibility, and then only change it if it SHOULD be something different, yaknow?

u.morale is a container of items of type morale_data, your code is trying to access a member of the container, when what it needs to do is access a member of an element of the container.

In short, what you want is u.morale[i].type instead of u.morale.type.

It turns out there is a wet “disease”, but nothing causes it and it’s missing other parts of the definition too, I think I’ll be adding that to enable something I want to do.

So I pushed my changes to my repo. A few of your suggestions I didn’t follow kevingranade, but if you insist I will :

I declare bodywetness at the same place as bodytemp, and it gets saved too. converging_bodytemp I didn’t move; if I put it in the update_bodytemp() function, it will get reset to 500-- and then recalculated, which is NBD. I’ll make that change in a moment ;p

The indentation issues with the case / switch / case 1, 2, 3, I followed the same scheme as the viper_combo cases.
I see what you mean now. I guess I pretty much did all your suggestions except bodywetness ;p

The code is much nicer now, 2 lines for all body temps, and 2 lines to increment them all. I have to figure out a pleasant way to add the hot/cold diseases for each body part. Again, I want to avoir having 7 chunks of simliar code if I can. It might require reworking diseases too.

At the moment, I think I will look into revamping clothing warmth. It seems like very little code uses the warmth value, so changing it would reuiqre updating very little code. (I think there is an artifact that talks to warmth, and the weather type drizzle talks to warmth.)

I am thinking of having a 0 to 100 scale. Perhaps this could be a percentage of insulation, and at 100% you can withstand practically anything natural. This would also require very little change to my present calcualtions, because at the moment it seems like a warmth value of 10 is already the highest possible.

To do this, I will think of outfits in my heads the player should wear for each weathing condition. Example ; fur coat and sweater should be the pinnacle of torso heat, being more than enough. Or perhaps I will add extreme items like Arctic Parka to really drive the point home. Eventually, I also want to add “fur lined” craftable versions of current clothing. Fur lined trench coat, fur lined arm sleeves, fur lined gloves.

Most of the ideas came from people on the IRC :slight_smile:

:3 rawr I’m a lion.

Also is fire warmth in? And how frequent are heat checks?

no. once a minute.

Bodytemp now converges on ideal bodytemps asymptotically. The half-life, if you will, is about 60 minutes. This can be easily changed if 60 minutes is too long, or not long enough.

Well if its proving difficult why not add an 'e’xamine option to fire to warm up, kind of half assed but isn’t most code like that?

Not that it’s difficult or not, it’s that I haven’t gotten that far yet. As for now, I have only just implemented code that would assign a seperate “cold” or “hot” disease to each limb. I want to flesh out being hot and cold, and then I will look into fires and other ways of keeping warm.

Warming up from a fire would simply be a matter of checking to see if there’re fires in range when we do temp calculations and factoring them in to the results, not complicated, just a matter of getting around to it.

Bumped with updates and such :slight_smile:

I noticed food being Hot or Cold maybe in a LP. Is this your doing?

Food being hot is something else. I want to eventually work drinking cold water or hot tea to affect body temps, but I am not too sure how to do that at the moment. Especially tracking heat of an item…

Food being labelled hot or cold actually indicates “fresh” or “stale/old”, it’ll take a decent amount of work to update those to better labels specific to each food type.