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

Unit tests for character stamina functions #38936

Merged
merged 16 commits into from
Mar 22, 2020

Conversation

wapcaplet
Copy link
Contributor

@wapcaplet wapcaplet commented Mar 21, 2020

Summary

SUMMARY: Infrastructure "Unit tests for character stamina functions"

Purpose of change

To ensure the behavior of the lower-level character stamina functions are well-understood, documented, and automatically tested.

Describe the solution

Adds test cases exercising behaviors of these functions:

  • Character::stamina_move_cost_modifier
  • Character::burn_move_stamina
  • Character::mod_stamina
  • Character::update_stamina

Test cases cover the following:

  • stamina movement cost (stamina_move_cost_modifier)
    • running cost is double walking cost for the same stamina level
    • walking cost is double crouching cost for the same stamina level
    • running cost goes from 2.0 to 1.0 as stamina goes to zero
    • walking cost goes from 1.0 to 0.5 as stamina goes to zero
    • crouching cost goes from 0.5 to 0.25 as stamina goes to zero
  • modify character stamina (mod_stamina)
    • regain partial stamina
    • regain all stamina
    • regain more than all stamina (ceiling at max stamina)
    • lose partial stamina
    • lose all remaining stamina (not winded)
    • lose more than all remaining stamina (floored at 0; become winded)
  • stamina burn rate (burn_move_stamina)
    • carrying nothing: walking burns 1x, running 14x, crouching 1/2x normal stamina rate
    • carrying max weight: walking burns 1x, running 14x, crouching 1/2x normal stamina rate
    • overburdened: walking burns +1x, running +14x, crouching +1/2x per percent overburdened
  • moving while overburdened causing pain (burn_move_stamina)
    • with 0 stamina, or with "bad back" trait
  • stamina regeneration rate (update_stamina)
    • normal baseline when character is not winded
    • 10% of normal when character is winded
  • stamina regen in different movement modes (update_stamina)
  • stamina regen with mouth encumbrance (update_stamina)
    • wearing a scarf reduces stamina regen
    • wearing another scarf reduces it further

Depends (only a tiny bit) on #38926
Depends on #38945 for test data

Describe alternatives you've considered

Leaving the spoilers unspoiled

Testing

make && tests/cata_test [stamina]

Additional context

Total of 7 new test cases with 343 assertions, running in 0.002 seconds:

image

Regarding the regression test for #38877 , to be perfectly honest this entire PR was driven by my desire to test that aspect of stamina regeneration better - from my first commit testing the curious scaling function stamina_move_cost_modifier to the last, which aimed to expose the discrepancy between stamina regeneration rates in different movement modes.

To that end, I tested by reverting the fix made in #38891 , and running the same tests. Quite a few of them failed (as expected), including those relating to movement mode, but a couple others indicate that stamina regen rate overall is decreased now, particularly at lower stamina levels, since the stamina_move_cost_modifier scaling function gives bigger buffs at lower stamina (and the test case checks regen rate starting with stamina only 10% full).

For posterity, here's a condensed version of what those failures looked like before #38891

=====================
Given: character is not winded
Then: they regain stamina at the normal rate per turn
--------
  CHECK( actual_regen_rate( dummy ) == normal_regen_rate )
  37.0f == 20.0f

=====================
Given: character is winded
Then: they regain stamina at only 10%% the normal rate per turn
--------
  CHECK( actual_regen_rate( dummy ) == 0.1 * normal_regen_rate )
  4.0f == 2.0

=====================
Then: run and walk mode give the same stamina regen per turn
--------
  CHECK( run_regen_rate == walk_regen_rate )
  18.0f == 36.0f

=====================
Then: walk and crouch mode give the same stamina regen per turn
--------
  CHECK( walk_regen_rate == crouch_regen_rate )
  36.0f == 73.0f

=====================
Then: crouch and run mode give the same stamina regen per turn
--------
  CHECK( crouch_regen_rate == run_regen_rate )
  73.0f == 18.0f

=====================
Given: character has mouth encumbrance
Then: stamina regen is reduced
--------
  CHECK( actual_regen_rate( dummy ) == normal_regen_rate - 2 )
  33.0f == 18.0f

When: they have even more mouth encumbrance
Then: stamina regen is reduced further
--------
  CHECK( actual_regen_rate( dummy ) == normal_regen_rate - 6 )
  25.0f == 14.0f

This confirms the overall stamina-nerfing that resulted from the PR, especially for crouching. I hope by having these tests outlined now, we will be in a better position to understand how stamina burn and regen works now, and make any necessary rebalances.

@wapcaplet wapcaplet changed the title Unit tests for character stamina functions [WIP] Unit tests for character stamina functions Mar 21, 2020
Unexpected failure for running speed at zero stamina; speed drops to
0.5 instead of the expected 1.0
Using `get_stamina() > 0` in the `src/character.cpp` condition for
running causes a discontinuity in return value, where the running cost
modifier drops sharply from:

    stamina 0.001 => cost modifier 1.001
    stamina 0.000 => cost modifier 0.500

Making this condition `>= 0` eliminates the discontinuity:

    stamina 0.001 => cost modifier 1.001
    stamina 0.000 => cost modifier 1.000
Since the DEBUG_STORAGE mutation gives the character many billions of
metric tonnes of weight capacity, it was making it difficult to test
being overburdened for stamina (no backpack is big enough, nor any
material in the game dense enough, to make such a character
overburdened). So now it's a parameter to the helper function,
defaulting to true.
Also force-remove "winded" status in helper functions to ensure
`can_run()` succeeds.
Stub in a `data/mods/TEST_DATA` folder for fake/mockup test items and
other non-game data for use by test cases.
By using tin powder at increments of 2g, some tests were failing because
player capacity could not be exactly reached with 2g increments.

Cross-compilation on minGW (according to Travis CI) seems even more
susceptible to this, leading to some tests giving more off-by-1 results
there than they do on my Ubuntu box.

There appear to be no high-density, stackable in-game items with a unit size of
only 1g, so I created a new `test_platinum_bit` in the `TEST_DATA` mod
folder, and used it in the `burden_player` helper instead of 2g tin powder.
@wapcaplet wapcaplet changed the title [WIP] Unit tests for character stamina functions Unit tests for character stamina functions Mar 22, 2020
@kevingranade kevingranade merged commit 1cb3031 into CleverRaven:master Mar 22, 2020
@wapcaplet wapcaplet deleted the stamina-tests branch March 23, 2020 21:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants