Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hot air from fires and direct heat radiation applies to tile temperatures #24956

Merged
merged 7 commits into from
Aug 27, 2018
4 changes: 2 additions & 2 deletions src/field.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1217,10 +1217,10 @@ bool map::process_fields_in_submap( submap *const current_submap,
dirty_transparency_cache = true; // Smoke affects transparency
}

// Hot air is a heavy load on the CPU and it doesn't do much
// Hot air is a load on the CPU
// Don't produce too much of it if we have a lot fires nearby, they produce
// radiant heat which does what hot air would do anyway
if( rng( 0, adjacent_fires ) > 2 ) {
if( adjacent_fires < 5 && rng( 0, 4 - adjacent_fires ) ) {
create_hot_air( p, cur.getFieldDensity() );
}
}
Expand Down
75 changes: 74 additions & 1 deletion src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1789,10 +1789,83 @@ void game::update_weather()
}
}

int game::get_heat_radiation( const tripoint &location, bool direct )
{
// Direct heat from fire sources
// Cache fires to avoid scanning the map around us bp times
// Stored as intensity-distance pairs
int temp_mod = 0;
std::vector<std::pair<int, int>> fires;
fires.reserve( 13 * 13 );
int best_fire = 0;
for( const tripoint &dest : g->m.points_in_radius( location, 6 ) ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whether function is moved from class game to be a free function, or remains as is, can shorten all instances of g->m.__func__ to just m.__func__
Other lines impacted:

  • 1804
  • 1807
  • 1810

Function is only called currently as g->get_heat_radiation so it already has access to the global-g's map.

int heat_intensity = 0;

int ffire = g->m.get_field_strength( dest, fd_fire );
if( ffire > 0 ) {
heat_intensity = ffire;
} else if( g->m.tr_at( dest ).loadid == tr_lava ) {
heat_intensity = 3;
}
if( heat_intensity == 0 || !g->m.sees( location, dest, -1 ) ) {
// No heat source here
continue;
}
// Ensure fire_dist >= 1 to avoid divide-by-zero errors.
const int fire_dist = std::max( 1, square_dist( dest, location ) );
fires.emplace_back( std::make_pair( heat_intensity, fire_dist ) );
if( fire_dist <= 1 ) {
// Extend limbs/lean over a single adjacent fire to warm up
best_fire = std::max( best_fire, heat_intensity );
}
}

for( const auto &intensity_dist : fires ) {
const int intensity = intensity_dist.first;
const int distance = intensity_dist.second;
temp_mod += 6 * intensity * intensity / distance;
}
if( direct ) {
return best_fire;
}
return temp_mod;
}

int game::get_convection_temperature( const tripoint &location )
{
// Heat from hot air (fields)
int temp_mod = 0;
const trap &trap_at_pos = g->m.tr_at( location );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whether function is moved from class game to be a free function, or remains as is, can shorten all instances of g->m.__func__ to just m.__func__
Other lines impacted:

  • 1840
  • 1846

Function is only called currently as g->get_convection_temperature so it already has access to the global-g's map.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's freed from game class it losses access to m which is member of this class so g->m within free functions have to stay.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a map-reference is added as a parameter to the free function you can get rid of the g-> part. You are correct that if the parameter isn't added g->m is the only way you will keep access to the map.

// directly on fire/lava tiles
int tile_strength = g->m.get_field_strength( location, fd_fire );
if( tile_strength > 0 || trap_at_pos.loadid == tr_lava ) {
temp_mod += 300;
}
// hot air of a fire/lava
auto tile_strength_mod = []( const tripoint &loc, field_id fld, int case_1, int case_2, int case_3 ){
int strength = g->m.get_field_strength( loc, fld );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to changing from g->m.get_field_strength to just m.get_field_strength, if the function is made a free function and its function signature modified to pass in the map may need to modify the lamda to capture the passed in map variable: [&m]( const tripoint &loc, ... ){

int cases[3] = { case_1, case_2, case_3 };
return ( strength > 0 && strength < 4 ) ? cases[ strength - 1 ] : 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having looked into things more carefully the condition isn't necessary. Can be modified to just return cases[ strength - 1 ];

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...and it sends the game into infinite loop with insane temperatures, stamina loss, and inevitable death. No, just no...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh I'm dumb. I was making an assumption and not validating that assumption. If the field does not exist at the location it's not going to be returning a value in range [1, 3]. Sorry for the bad suggestion.

};

temp_mod += tile_strength_mod( location, fd_hot_air1, 2, 6, 10 );
temp_mod += tile_strength_mod( location, fd_hot_air2, 6, 16, 20 );
temp_mod += tile_strength_mod( location, fd_hot_air3, 16, 40, 70 );
temp_mod += tile_strength_mod( location, fd_hot_air4, 70, 100, 160 );

return temp_mod;
}

int game::get_temperature( const tripoint &location )
{
int temp_mod = 0; // local modifier

if( !new_game ) {
temp_mod += g->get_heat_radiation( location, false );
temp_mod += g->get_convection_temperature( location );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If game::get_heat_radiation and game::get_convection_temperature are made into free functions change calls to get_heat_radiation( g->m, location, false ); and get_convection_temperature( g->m, location );

}
//underground temperature = average New England temperature = 43F/6C rounded to int
return ( location.z < 0 ? AVERAGE_ANNUAL_TEMPERATURE : temperature ) + ( new_game ? 0 : m.temperature( location ) );
return ( location.z < 0 ? AVERAGE_ANNUAL_TEMPERATURE : temperature ) + ( new_game ? 0 : ( m.temperature( location ) + temp_mod ) );
}

int game::assign_mission_id()
Expand Down
7 changes: 7 additions & 0 deletions src/game.h
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,13 @@ class game
int get_user_action_counter() const;

signed char temperature; // The air temperature
// Returns temperature modifier from direct heat radiation of nearby sources
// @param location Location affected by heat sources
// @param direct forces return of heat intensity (and not temperature modifier) of
// adjacent hottest heat source
int get_heat_radiation( const tripoint &location, bool direct );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does not need to be in class game. Only uses the map m member of game. Extract from class game and modify declaration to int get_heat_radiation( const map& m, const tripoint &location, bool direct);

// Returns temperature modifier from hot air fields of given location
int get_convection_temperature( const tripoint &location );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oes not need to be in class game. Only uses the map m member of game. Extract from class game and modify declaration to int get_convection_temperature( const map& m, const tripoint &location );

// Returns outdoor or indoor temperature of given location (in absolute (@ref map::getabs))
int get_temperature( const tripoint &location );
weather_type weather; // Weather pattern--SEE weather.h
Expand Down
123 changes: 11 additions & 112 deletions src/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1032,35 +1032,10 @@ void player::update_bodytemp()
// Sunlight
const int sunlight_warmth = g->is_in_sunlight( pos() ) ? 0 :
( g->weather == WEATHER_SUNNY ? 1000 : 500 );
// Fire at our tile
const int fire_warmth = bodytemp_modifier_fire();

// Cache fires to avoid scanning the map around us bp times
// Stored as intensity-distance pairs
std::vector<std::pair<int, int>> fires;
fires.reserve( 13 * 13 );
int best_fire = 0;
for( const tripoint &dest : g->m.points_in_radius( pos(), 6 ) ) {
int heat_intensity = 0;

int ffire = g->m.get_field_strength( dest, fd_fire );
if( ffire > 0 ) {
heat_intensity = ffire;
} else if( g->m.tr_at( dest ).loadid == tr_lava ) {
heat_intensity = 3;
}
if( heat_intensity == 0 || !g->m.sees( pos(), dest, -1 ) ) {
// No heat source here
continue;
}
// Ensure fire_dist >= 1 to avoid divide-by-zero errors.
const int fire_dist = std::max( 1, square_dist( dest, pos() ) );
fires.emplace_back( std::make_pair( heat_intensity, fire_dist ) );
if( fire_dist <= 1 ) {
// Extend limbs/lean over a single adjacent fire to warm up
best_fire = std::max( best_fire, heat_intensity );
}
}
// Hot air from a heat source
// times 50 to convert to weather.h BODYTEMP scale
const int fire_warmth = g->get_convection_temperature( pos() ) * 50;
const int best_fire = g->get_heat_radiation( pos(), true );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If game::get_heat_radiation and game::get_convection_temperature are made into free functions change calls to get_heat_radiation( g->m, pos(), true ); and get_convection_temperature( g->m, pos() );


const int lying_warmth = use_floor_warmth ? floor_warmth( pos() ) : 0;
const int water_temperature =
Expand Down Expand Up @@ -1122,16 +1097,14 @@ void player::update_bodytemp()
// CONVECTION HEAT SOURCES (generates body heat, helps fight frostbite)
// Bark : lowers blister count to -10; harder to get blisters
int blister_count = ( has_bark ? -10 : 0 ); // If the counter is high, your skin starts to burn
for( const auto &intensity_dist : fires ) {
const int intensity = intensity_dist.first;
const int distance = intensity_dist.second;
if( frostbite_timer[bp] > 0 ) {
frostbite_timer[bp] -= std::max( 0, intensity - distance / 2 );
}
const int heat_here = intensity * intensity / distance;
temp_conv[bp] += 300 * heat_here;
blister_count += heat_here;

const int h_radiation = g->get_heat_radiation( pos(), false );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If game::get_heat_radiation is made into a free function change call to get_heat_radiation( g->m, pos(), false );

temp_conv[bp] += h_radiation * 50; // conversion to BODYTEMP see weather.h
if( frostbite_timer[bp] > 0 ) {
frostbite_timer[bp] -= std::max( 5, h_radiation );
}
blister_count += h_radiation - 111 > 0 ? std::max( h_radiation - 111, 0) : 0;

// Bionic "Thermal Dissipation" says it prevents fire damage up to 2000F.
// But it's kinda hard to get the balance right, let's go with 20 blisters
if( has_heatsink ) {
Expand Down Expand Up @@ -1569,80 +1542,6 @@ int player::floor_warmth( const tripoint &pos ) const
return ( item_warmth + bedding_warmth + floor_mut_warmth );
}

int player::bodytemp_modifier_fire() const
{
int temp_conv = 0;
// Being on fire increases very intensely the convergent temperature.
if( has_effect( effect_onfire ) ) {
temp_conv += 15000;
}

const trap &trap_at_pos = g->m.tr_at( pos() );
// Same with standing on fire.
int tile_strength = g->m.get_field_strength( pos(), fd_fire );
if( tile_strength > 2 || trap_at_pos.loadid == tr_lava ) {
temp_conv += 15000;
}
// Standing in the hot air of a fire is nice.
tile_strength = g->m.get_field_strength( pos(), fd_hot_air1 );
switch( tile_strength ) {
case 3:
temp_conv += 500;
break;
case 2:
temp_conv += 300;
break;
case 1:
temp_conv += 100;
break;
default:
break;
}
tile_strength = g->m.get_field_strength( pos(), fd_hot_air2 );
switch( tile_strength ) {
case 3:
temp_conv += 1000;
break;
case 2:
temp_conv += 800;
break;
case 1:
temp_conv += 300;
break;
default:
break;
}
tile_strength = g->m.get_field_strength( pos(), fd_hot_air3 );
switch( tile_strength ) {
case 3:
temp_conv += 3500;
break;
case 2:
temp_conv += 2000;
break;
case 1:
temp_conv += 800;
break;
default:
break;
}
tile_strength = g->m.get_field_strength( pos(), fd_hot_air4 );
switch( tile_strength ) {
case 3:
temp_conv += 8000;
break;
case 2:
temp_conv += 5000;
break;
case 1:
temp_conv += 3500;
break;
default:
break;
}
return temp_conv;
}

int player::bodytemp_modifier_traits( bool overheated ) const
{
int mod = 0;
Expand Down
2 changes: 0 additions & 2 deletions src/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -1631,8 +1631,6 @@ class player : public Character
static int floor_item_warmth( const tripoint &pos );
/** Final warmth from the floor **/
int floor_warmth( const tripoint &pos ) const;
/** Correction factor of the body temperature due to fire **/
int bodytemp_modifier_fire() const;
/** Correction factor of the body temperature due to traits and mutations **/
int bodytemp_modifier_traits( bool overheated ) const;
/** Correction factor of the body temperature due to traits and mutations for player lying on the floor **/
Expand Down