diff --git a/src/character.cpp b/src/character.cpp index a372590232e03..0327f59d0df4f 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -3102,15 +3102,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( 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 diff --git a/tests/char_volume_test.cpp b/tests/char_volume_test.cpp index 3c90e01a0c214..82cca754a9494 100644 --- a/tests/char_volume_test.cpp +++ b/tests/char_volume_test.cpp @@ -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]" ) @@ -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 }; @@ -107,7 +107,7 @@ 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 ) ); @@ -115,7 +115,7 @@ TEST_CASE( "character_at_volume_can_or_cannot_enter_vehicle", "[volume]" ) 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 ) );