Skip to content

Commit

Permalink
Fix character volume calculation (#74348)
Browse files Browse the repository at this point in the history
* Provide body volume calculation based on body density

* Simplify calculations

* Adjust test cases to the volume calculation

* Adjust volumes for baseline tests too

* Make checks for volume pass within reasaonable ranges

Relying on volumes down to the ml allows us to make changes to volume
calculations, and keep the tests withing reasaonable boundaries.

references #74263

* Make checks for volume less dependent on exact volumes

Make tests more flexible

* Make tests exact, set character to exact calorie count

This strategy makes the test repeatable

* Remove unused header units.h
  • Loading branch information
feinorgh authored Jun 15, 2024
1 parent d5efb05 commit 175eae4
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 18 deletions.
26 changes: 17 additions & 9 deletions src/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3108,15 +3108,23 @@ units::volume Character::get_total_volume() const

units::volume Character::get_base_volume() const
{
const int your_height = height(); // avg 175cm
// Arbitrary number picked relative to aisle (100L), not necessarily accurate
const units::volume avg_human_volume = 70_liter;

// Very scientific video game size to metric human volume calculation. Avg height == avg_human_volume;
units::volume your_base_volume = units::from_liter( static_cast<double>( your_height ) / 2.5 );
double volume_proport = units::to_liter( your_base_volume ) / units::to_liter( avg_human_volume );

return std::pow( volume_proport, 3.0 ) * avg_human_volume;
// The formula used here to calculate base volume for a human body is
// BV = W / BD
// Where:
// * BV is the body volume in liters
// * W is the weight in kilograms
// * BD is the body density (kg/L), estimated using the Brozek formula:
// BD = 1.097 – 0.00046971 * W + 0.00000056 * W^2 – 0.00012828 * H
// See
// https://en.wikipedia.org/wiki/Body_fat_percentage
// https://calculator.academy/body-volume-calculator/
const int your_height = height();
const double your_weight = units::to_kilogram( bodyweight() );
const double your_density = 1.097 - 0.00046971 * your_weight
+ 0.00000056 * std::pow( your_weight, 2 )
- 0.00012828 * your_height;
units::volume your_base_volume = units::from_liter( your_weight / your_density );
return your_base_volume;
}

units::mass Character::weight_carried() const
Expand Down
18 changes: 9 additions & 9 deletions tests/char_volume_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,23 @@ TEST_CASE( "character_baseline_volumes", "[volume]" )
{
clear_avatar();
Character &you = get_player_character();
you.set_stored_kcal( you.get_healthy_kcal() );
REQUIRE( you.get_mutations().empty() );
REQUIRE( you.height() == 175 );
CHECK( you.get_base_volume() == 70_liter );
REQUIRE( you.bodyweight() == 76562390_milligram );
CHECK( you.get_base_volume() == 73485_ml );

REQUIRE( your_height_with_trait( trait_SMALL2 ) == 70 );
CHECK( your_volume_with_trait( trait_SMALL2 ) == 4480_ml );
CHECK( your_volume_with_trait( trait_SMALL2 ) == 23326_ml );

REQUIRE( your_height_with_trait( trait_SMALL ) == 122 );
CHECK( your_volume_with_trait( trait_SMALL ) == 23717_ml );
CHECK( your_volume_with_trait( trait_SMALL ) == 42476_ml );

REQUIRE( your_height_with_trait( trait_LARGE ) == 227 );
CHECK( your_volume_with_trait( trait_LARGE ) == 152778_ml );
CHECK( your_volume_with_trait( trait_LARGE ) == 116034_ml );

REQUIRE( your_height_with_trait( trait_HUGE ) == 280 );
CHECK( your_volume_with_trait( trait_HUGE ) == 286720_ml );
CHECK( your_volume_with_trait( trait_HUGE ) == 156228_ml );
}

TEST_CASE( "character_at_volume_can_or_cannot_enter_vehicle", "[volume]" )
Expand All @@ -66,8 +68,6 @@ TEST_CASE( "character_at_volume_can_or_cannot_enter_vehicle", "[volume]" )
map &here = get_map();
Character &you = get_player_character();
REQUIRE( you.get_mutations().empty() );
REQUIRE( you.get_base_volume() == 70_liter );
REQUIRE( you.get_total_volume() == 70_liter );

tripoint test_pos = tripoint{10, 10, 0 };

Expand Down Expand Up @@ -107,15 +107,15 @@ TEST_CASE( "character_at_volume_can_or_cannot_enter_vehicle", "[volume]" )
cramped = false;

// Try the cramped aisle with a rock again, but now we are tiny, so it is easy.
CHECK( your_volume_with_trait( trait_SMALL2 ) == 4480_ml );
CHECK( your_volume_with_trait( trait_SMALL2 ) == 23326_ml );
you.setpos( test_pos ); // set our position again, clear_avatar() moved us
dest_loc = dest_loc + tripoint_north;
CHECK( you.can_move_to_vehicle_tile( dest_loc, cramped ) );
CHECK( !cramped );
dest_loc = you.get_location(); //reset

// Same aisle, but now we have HUGE GUTS. We will never fit.
CHECK( your_volume_with_trait( trait_HUGE ) == 286720_ml );
CHECK( your_volume_with_trait( trait_HUGE ) == 156228_ml );
you.setpos( test_pos ); // set our position again, clear_avatar() moved us
dest_loc = dest_loc + tripoint_north;
CHECK( !you.can_move_to_vehicle_tile( dest_loc ) );
Expand Down

0 comments on commit 175eae4

Please sign in to comment.