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

Adjust body part hit difficulty to make critical hits matter for NPCs #3139

Merged
merged 5 commits into from
Sep 16, 2023

Conversation

chaosvolt
Copy link
Member

@chaosvolt chaosvolt commented Sep 14, 2023

Summary

SUMMARY: Balance "Adjust hit_difficulty to that critical hits will target vital body parts more often than limbs"

Purpose of change

So, I'd been meaning to look into how melee attacks decide how a limb to target when fighting PCs and NPCs, having noticed that even after we fixed blocking with disabled limbs, it seemed like the game was picking what limb to hit completely at random. I figured that, since ranged attacks do try to gravitate towards the head the better your aim is, wouldn't it be nice to have it do something like that but for melee attacks?

Good news, that already exists in the code: https://github.com/cataclysmbnteam/Cataclysm-BN/blob/upload/src/anatomy.cpp#L139 Relevant bit is:

            weight *= std::pow( hit_roll, bp->hit_difficulty );

In a nutshell, the weight for each body part's size is further increased based on how solid the hit is as well as an exponential modifier provided for each part, separate from its basic relative size data. Problem is, exponential modifiers being fiddly as they are, the existing values don't really do all that much.

These shows the weight values for a few different hits ranging from "if it was any worse it'd probably be a miss" to "this was literally the most solid crit I could get without buffing my stats" with a middle of the road value in between:

before 1 before 2 before 3

And here's a table that summarizes the weights being worked with, in particular your odds of hitting a vital part (torso, head, or eyes which carry damage over to the head) vs. those unnecessary noodly things, and your overall odds of hitting a vital:

Type of hit Weight of vitals Weight of limbs Total weight Chance of hitting vitals
Miserable (<10 hit roll) 172.225 242.016 414.241 ~41.58%
Solid (60s hit roll) 2907.019 3567.534 6474.553 ~44.9%
Stellar (120s hit roll) 5880.82 6637.034 12517.854 ~46.98%

Doesn't improve much, needless to say. I got a hit roll up into the 130s once when I re-tested with 20 dexterity but even with 50 DEX hit rolls are all over the place, and you don't start getting triple-digit numbers consistently until you're well past 100 DEX. End result is, you need absurdly good hit (and rare with anything resembling a normal character) rolls before it even reaches 50/50.

So it's actively a tad WORSE than a purely even distribution like I first assumed it to be!

Describe the solution

In data/json/body_parts.json:

  1. Changed the hit_difficulty setting for the head from 1.35 to 1.4
  2. Changed the hit_difficulty setting for the eyes from 1.15 to 1.2
  3. Changed the hit_difficulty setting for both arms from 0.95 to 0.75
  4. Changed the hit_difficulty setting for both legs from 0.975 to 0.9

This increases the gap between the parts with higher than 1 difficulty and the ones with less than 1 diff, along with also making arms and legs less identical in terms of hit rate (so long as they have HP, they'll already soak up tons of hits so that'll more than make up for it). Also does so without buffing the exponents that're already above 1 by more than 0.05, so they won't get too out of hand. Aim is, more solid hits widen the gap and as a result make essential bodyparts a higher proportion of the total hit weight.

Well, also the eyes, but those are essential by proxy since a hit there damages the head instead, plus as can be seen below the weights still stay pretty low due to their diminutive base hit size.

Describe alternatives you've considered

  1. Using a more extreme spread of hit difficulties. 1.5/1.25/0.75/0.875 also got interesting results, leaning towards 65% chance of hitting vitals on a solid hit and 75% with a top-rate crit. Would depend on how extreme we want to skew things.
  2. Another idea that came up was halving the hit weights for any disabled parts. Main thing with this is that if we do that without doing this, critical hits would still be wasted on limbs a lot of the time, and you'd have to cripple all your target's limbs before they'd finally push 60% chance of taking shots to the vitals.
  3. Adjusting the hit difficulty of the other bodyparts too for consistently. They can't seem to take hits in this function and hit_difficulty isn't even used in any other function in the code it seems, so this seems like it'd be purely a flavor change in practice.
  4. Tweaking the math in some way to more consistently tie targeted body part to how much better the attacker's stats are. This I assume would fall under making hit rolls less janky in the first place, as right now even demigods generate low hit rolls too.
  5. Removing the test that I'm also having trouble with because it only exists to enforce hit spread math that was presumably made deliberately limb-hit-heavy on purpose given they wrote a test for it, since it's a convoluted shitshow that takes several values with no clear labeling, feeds them to a binomial map function, then outputs test logs that don't tell you which numbers are generated by the game's code and which numbers were generated by the test config.

Testing

  1. Checked affected file for syntax and lint errors.
  2. Repeated the original tests to generate some similar values and did the math.

After 1 After 2 After 3

Type of hit Weight of vitals Weight of limbs Total weight Chance of hitting vitals
Miserable (<10 hit roll) 231.439 277.724 509.163 ~45.46%
Solid (60s hit roll) 3071.834 1968.068 5039.902 ~60.95%
Stellar (120s hit roll) 6283.825 3346.45 9630.275 ~65.25%

Hit roll varies a fuckton even with maxed skills and high stats, so the main take here is that just-good-in-general hits will start to hit vitals more often than they hit limbs. Slight impact on bottom-tier hits but you still have higher odds of scoring a non-lethal hit than you do a lethal one, keeping in mind also that the arms are an automatic sword magnet as long as they have HP.

Additional context

Note: during testing I noticed sometimes the game would just abruptly closed. I decided to test this with the original hit difficulties and it still happened, so it doesn't seem to be caused by hit weight math. My guess is either it was because I had debug mode on, or because I gave both of us Debug Invincibility for safe, almost-sane, still-non-consensual brawling. Or maybe combining both, no idea.

It may even happen in normal gameplay too, but the crash seems to have low enough odds of triggering that it's hard to test that without going through NPCs like popcorn, spongy as they may be science is too rough on them so they break eventually.

Call_It_A_Draw_Template_3

@github-actions github-actions bot added the JSON related to game datas in JSON format. label Sep 14, 2023
I hope I got the math right on this...
@github-actions github-actions bot added the tests changes related to tests label Sep 14, 2023
Copy link
Member

@scarf005 scarf005 left a comment

Choose a reason for hiding this comment

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

image

  1. refactored tests/creature_test.cpp because it was using array as a poor man's std::map
  2. made info print all values of histogram, so you can just copy-paste it to expected_<size> struct

image

also, it works on my machine.

@chaosvolt
Copy link
Member Author

chaosvolt commented Sep 15, 2023

@olanti-p did bring up one other thing in the discord admittedly: this also applies to monsters hitting the player. From testing it seems that a basic zombie tends to peak at mid-high 40s hit roll for a basic survivor, observed peak of 50 so far. I'd roughly estimate given the jankiness of hit rolls that the net effect most likely averages out to making basic hits 50/50 vitals instead of 40/60, which isn't too bad I feel. The monsters that benefit from it the most are the late-game ones with high melee skill that're intended to be dangerous in a straight fight, and those are already not very challenging for a late-game survivor anyway.

The vague estimate I gave on how this may affect an absolutely unprepared survivor's odds against basic no-to-low-skill zeds:
image

A far cry from DDA making no-melee-skill zombies able to completely fold a player-character in half with a single grab, but it is something.

@scarf005 scarf005 merged commit 36f687b into cataclysmbnteam:upload Sep 16, 2023
18 checks passed
@chaosvolt chaosvolt deleted the tis-but-a-scratch branch September 16, 2023 15:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
JSON related to game datas in JSON format. tests changes related to tests
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants