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

item: improve the calculation and display of DPS #39362

Merged
merged 1 commit into from
Apr 9, 2020

Conversation

mlangsdorf
Copy link
Contributor

@mlangsdorf mlangsdorf commented Apr 8, 2020

Summary

SUMMARY: Interface "item: improve the calculation and display of DPS"

Purpose of change

The current DPS value displayed in item info is extremely misleading: it is technically a raw damage per second and doesn't account for misses, weapon speed, user encumbrance, user stats, user skill, critical hits, or the defenses of potential targets. This makes it difficult to compare weapons with widely different stats, such as a trench knife (acc +1, 83 moves/attack, 14 pierce damage) and a sledgehammer (acc +0, 180 moves/attack, 40 bash damage). The knife does 14 damage every 83 moves and the sledgehammer does 40 damage every 180 moves, and that works out to DPS 19 versus DP 22, but the knife hits more often and is stopped by thinner armor.

Display typical damage per second values instead, based on simulated attacks against some reference monsters and accounting for missed strikes, critical hits, and armor.

Also, the help file for items is very out of date, so bring parts of it up to reflect the post 0.E game.

This also lays the ground work for improved NPC evaluation of weapons.

Describe the solution

Calculate and display typical damage per second values based on the avatar's actual stats and encumbrance, factoring in misses, critical hits, and the effects of armor. Display typical DPS in the best case scenario (against an debug monster with no armor or dodge), against agile targets (a smoker zombie with no armor but Dodge 7), and against armored targets (a soldier zombie with bash resistance 20 and cut resistance 25).

Update the help file to reflect these changes.

Describe alternatives you've considered

This adds a stripped down version of the combat calculations, which means there are two things that need to be kept in sync now. I considered spawning a fake NPC and making it fake fight a sample monster through 1000 attacks and recording the results, but there are a lot of problems with that solution.

To hit rolls are a normal distribution, and there's no easy way to convert the input values of CDDA's normal rng function to a percentage success that I am aware of. I used a quick monte carlo simulation to get the values, but number of hits varied by +/- 5% in my testing. I'd use a better solution if I knew of one. The need to get consistent values for unit test cases means the monte carlo simulation was abandoned in favor of a look-up table.

I considered caching the results of the monte carlo simulation but didn't do it at this time; it'd be fairly straightforward to add if people think that is worthwhile.

The initial implementation displayed the results against the survivor zombie and the average of the scores, but that was rejected because it made things too cluttered.

Other reference monsters could be used, but the soldier zombie and the smoker zombie are familiar to most players.

Testing

Loaded a game and looked at a variety of weapons, modifying my character to have different stats.

Additional context

better_dps_data
This is the new melee information display.

@mlangsdorf mlangsdorf added [C++] Changes (can be) made in C++. Previously named `Code` Info / User Interface Game - player communication, menus, etc. Items / Item Actions / Item Qualities Items and how they work and interact labels Apr 8, 2020
@mlangsdorf mlangsdorf force-pushed the effective_dps branch 2 times, most recently from 7e6c874 to 917f9e1 Compare April 8, 2020 14:00
@jbytheway
Copy link
Contributor

jbytheway commented Apr 8, 2020

If there are now two things to be kept in sync, can we have a unit test to verify that they are in sync? We already have unit tests which involve creating a monster and having it fight the avatar (which I would hope was the hard part) and can provide some inspiration.

@mlangsdorf
Copy link
Contributor Author

I'll look into that after I get the existing test cases to pass.

src/item.cpp Outdated Show resolved Hide resolved
base_hit *= std::max( 0.25f, 1.0f - guy.encumb( bp_torso ) / 100.0f );
float mon_defense = mon_dodge + mon.size_melee_penalty();
double num_hits = 0;
constexpr double hit_trials = 1000.0;
Copy link
Contributor

Choose a reason for hiding this comment

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

I feel like hit_trials ought to be an integer type, but it's not a big problem.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Legacy of the original implementation, but I don't think it matters either.

src/item.cpp Show resolved Hide resolved
src/item.cpp Show resolved Hide resolved
src/item.cpp Outdated
}
info.push_back( iteminfo( "BASE", _( "Damage per second: " ), "",
iteminfo::is_decimal, dps ) );
info.emplace_back( "BASE", _( "Typical damage per second: " ), "" );
Copy link
Contributor

Choose a reason for hiding this comment

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

If you can find a succinct way to express it, I think it would help avoid confusion to clarify that these values are:

  • Specific to current circumstances (e.g. encumbrance, temporary stat changes) and thus only meaningful if the avatar is currently in a "combat-ready state".
  • Random, and thus likely to differ slightly on each observation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried to express that in the help file. There's not enough space in the info planel to put in a long explanation and caveats.

@mlangsdorf mlangsdorf force-pushed the effective_dps branch 2 times, most recently from d7a46c0 to e0c5dc5 Compare April 8, 2020 20:53
Calculate and display typical damage per second values based on the
avatar's actual stats and encumbrance, factoring in misses, critical
hits, and the effects of armor.  Display typical DPS in the best
case scenario (against an debug monster with no armor or dodge),
against agile targets (a smoker zombie with no armor but Dodge 7),
and against armored targets (a soldier zombie with bash resistance
20 and cut resistance 25).

Fix a bug in tests/player_helpers.cpp where clear_avatar() is not
guaranteed to result in all stats being 8.

Update the help file to reflect these changes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[C++] Changes (can be) made in C++. Previously named `Code` Info / User Interface Game - player communication, menus, etc. Items / Item Actions / Item Qualities Items and how they work and interact
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants