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

melee: Make sure that melee weapon accuracy improves hit rates #39564

Merged
merged 8 commits into from
Apr 19, 2020

Conversation

mlangsdorf
Copy link
Contributor

@mlangsdorf mlangsdorf commented Apr 14, 2020

Summary

SUMMARY: Bugfixes "melee: Make sure that melee weapon accuracy improves hit rates"

Purpose of change

jtbw suggested in #39362 that unit tests would be helpful for ensuring that the simplified DPS
calculation would match the actual DPS values observed by going through the melee attack code.

In the process of implementing that suggestion, it became apparent that melee weapon accuracy
had little or no bearing on the chance to hit with a weapon. weapon.type->m_to_hit was only being applied via mod_hit_bonus() in avatar::reset_stats() which was called from avatar::reset(), so it seemed unlikely that changing weapons would necessarily change the
hit bonus.

Fix that bug, so that melee weapon accuracy clearly effects hit rates, and add unit test cases to make sure that future regressions will be caught. Then go back to the original point of the exercise and add unit test cases for effective dps, and fix effective_dps to match the results of those test cases. Finally, extend effective_dps so that NPCs will use it to value weapons.

Describe the solution

There are a lot of moving parts here:
wapcaplet wrote the initial effective DPS test cases based on some pseudo-code I wrote. Those are in #39476 and this PR includes and supersedes that one.

The melee weapon accuracy fix moves weapon.type->m_to_hit out of get_hit_bonus() and into get_hit_weapon() as a static bonus after calculating skill bonuses. Adding unit tests cases for that required the ability to easily count the number of successful attacks, and after considering the options, I decided that adding an out-of-band set of statistic counters was easier than rewriting the melee attack sequence to be accessible for test cases.

The effective DPS test cases demonstrated that the algorithm for effective_dps had a lot of problems, so parts of it were rewritten to correctly calculate critical hit chances and the damage calculation was rewritten to more closely match the melee code. At the same time, the code was adjusted so that callers could specify if they wanted monsters for display or monsters for evaluation, and calculations for unneeded monsters were skipped.

The DPS unit tests repeat running trials in blocks of 1000 until 100 crits occur in an effort to reduce the burstiness of the results without requiring that the tests run for 90 seconds.

Finally, there was no reason to keep an alternate set of melee DPS calculations in weapon_value(), so that got removed and replaced by using the effective_dps() infrastructure.

Describe alternatives you've considered

player::melee_attack() has an extremely weird structure, with code flow jumping back and forth between the attacker and defender in weird ways. Restructuring it to have a more logical flow and to be easier to test would be great, but it would also be a large project. It should be easier now that there are unit test cases to confirm that changes are just refactors and don't have accidental semantic changes.

Testing

I spent hours and hours running test cases to make all this work. The proof is that the test cases mostly work. Actual calculated dps over 1000s of trials can still vary by more than 20% in extreme cases, and I'm not sure what to do about that.

@mlangsdorf mlangsdorf added <Bugfix> This is a fix for a bug (or closes open issue) <Exploit> Unintended interactions or behavior, usually breaking how the game is balanced [C++] Changes (can be) made in C++. Previously named `Code` Code: Tests Measurement, self-control, statistics, balancing. Info / User Interface Game - player communication, menus, etc. Melee Melee weapons, tactics, techniques, reach attack labels Apr 14, 2020
/*
* statistics data for melee attacks, used for test purposes
*/
struct melee_statistic_data {
Copy link
Contributor

Choose a reason for hiding this comment

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

These melee stats are a good candidate to migrate to the event bus, then the tests can hook in to the hit events that way. I'm not asking you to do that in this PR, because melee events aren't a thing yet; this is more of a note-to-self.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds great =)

@mlangsdorf
Copy link
Contributor Author

clang-tidy errors are not my fault; code had them already.

@kevingranade
Copy link
Member

Yep, that's pending #39562

@lgtm-com
Copy link

lgtm-com bot commented Apr 14, 2020

This pull request fixes 1 alert when merging 0b459de into 32e6aab - view on LGTM.com

fixed alerts:

  • 1 for Use of c-style math functions

@lgtm-com
Copy link

lgtm-com bot commented Apr 15, 2020

This pull request fixes 1 alert when merging b9463f9 into 5db5df0 - view on LGTM.com

fixed alerts:

  • 1 for Use of c-style math functions

@mlangsdorf
Copy link
Contributor Author

WTF, Xcode on MacOS 10.1, why are you consistently failing the accuracy tests:

effective_dps_test.cpp:90: FAILED:
  CHECK( wpn2_hit_rate > wpn1_hit_rate )
with expansion:
  0.566 > 0.5725
2.357 s: soldier zombie
2.358 s: accuracy increases success
-------------------------------------------------------------------------------
accuracy increases success
  smoker zombie
-------------------------------------------------------------------------------
effective_dps_test.cpp:207
...............................................................................
effective_dps_test.cpp:90: FAILED:
  CHECK( wpn2_hit_rate > wpn1_hit_rate )
with expansion:
  0.3316 > 0.3365
effective_dps_test.cpp:92: FAILED:
  CHECK( dps_wpn2 > dps_wpn1 )
with expansion:
  12.4415197372 > 12.4911880493
5.160 s: smoker zombie
5.161 s: accuracy increases success
-------------------------------------------------------------------------------
accuracy increases success
  survivor zombie
-------------------------------------------------------------------------------
effective_dps_test.cpp:211
...............................................................................
effective_dps_test.cpp:91: FAILED:
  CHECK( wpn3_hit_rate > wpn2_hit_rate )
with expansion:
  0.4173333333 > 0.4226666667

@lgtm-com
Copy link

lgtm-com bot commented Apr 17, 2020

This pull request fixes 1 alert when merging 93296d2 into 5dd7e74 - view on LGTM.com

fixed alerts:

  • 1 for Use of c-style math functions

@mlangsdorf mlangsdorf force-pushed the melee_accuracy_fix branch 4 times, most recently from 72770fb to 977e3fb Compare April 18, 2020 01:48
@lgtm-com
Copy link

lgtm-com bot commented Apr 18, 2020

This pull request fixes 1 alert when merging e20aa3a into 5dd7e74 - view on LGTM.com

fixed alerts:

  • 1 for Use of c-style math functions

@mlangsdorf
Copy link
Contributor Author

fris0uman inadvertently added a regression with his recent refactoring of melee.cpp to move things from player:: to Character::, which the test caught erratically. A bugfix was added.

@lgtm-com
Copy link

lgtm-com bot commented Apr 18, 2020

This pull request fixes 1 alert when merging 0e7c596 into f94cfe1 - view on LGTM.com

fixed alerts:

  • 1 for Use of c-style math functions

Results are closer to expectations now, though not quite there yet.

ex. trench knife vs. debug monster: Actual 13.0157, Expected 20.160
commit 8ef3706 moved a bunch of melee related functions out of
player:: and into Character::, but failed to call the new renamed
version of get_hit() correctly.
Fix some long lines and use std:: functions in place of math.h functions
in a few places.
Move the accuracy bonus out of the avatar's hit bonuses where they may or
may not be set correctly via reset() and into get_hit_weapon() where they
are definitely set and applied correctly.

Add some statistics counters to the melee code to make writing test cases
easier.

Add unit tests to verify that increase a weapon's accuracy increases to
hit rates and DPS.
Don't calculate dps for monsters that aren't going to be displayed.

Adjust the unit tests based on relative values (epsilon) instead of
fixed values (margin).
use average of effective dps against evaluation monsters in melee_value(),
with an additional bonus for reach weapons and for weapons that work with
a martial art the NPC knows.
Include the Melee Evaluation spreadsheet and a description of it, and
update GAME_BALANCE.md with the new formulas.
@lgtm-com
Copy link

lgtm-com bot commented Apr 18, 2020

This pull request fixes 1 alert when merging cedb55f into 074dd18 - view on LGTM.com

fixed alerts:

  • 1 for Use of c-style math functions

@kevingranade kevingranade merged commit 61d262e into CleverRaven:master Apr 19, 2020
@mlangsdorf
Copy link
Contributor Author

Yay!

@mlangsdorf mlangsdorf deleted the melee_accuracy_fix branch April 19, 2020 00:11
@TealcOneill TealcOneill mentioned this pull request Feb 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
<Bugfix> This is a fix for a bug (or closes open issue) [C++] Changes (can be) made in C++. Previously named `Code` Code: Tests Measurement, self-control, statistics, balancing. <Exploit> Unintended interactions or behavior, usually breaking how the game is balanced Info / User Interface Game - player communication, menus, etc. Melee Melee weapons, tactics, techniques, reach attack
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants