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

Improving muscle strain repetitive use mechanics #59864

Open
I-am-Erk opened this issue Aug 3, 2022 · 26 comments
Open

Improving muscle strain repetitive use mechanics #59864

I-am-Erk opened this issue Aug 3, 2022 · 26 comments
Labels
Game: Balance Balancing of (existing) in-game features. Game: Mechanics Change Code that changes how major features work Mechanics: Character / Player Character / Player mechanics Mechanics: Effects / Skills / Stats Effects / Skills / Stats (P3 - Medium) Medium (normal) priority <Suggestion / Discussion> Talk it out before implementing

Comments

@I-am-Erk
Copy link
Member

I-am-Erk commented Aug 3, 2022

Is your feature request related to a problem? Please describe.

#59862 adds a mechanic, "strain", which tracks the use and overuse of muscles during strenuous activity as a new physical resource you can exhaust, replacing stamina (now called "breath") in places where we're talking more about contractility than aerobic sustainability. However, "strain" on its own recovers very quickly. It is designed to require a secondary not-quite-as-short-term complementary mechanic that makes it recover a bit less quickly in the short term the more times you exhaust it.

Solution you would like.

"Lactate" is a nickname for "building up strain until muscle failure". I have called it this more because of the colloquial understanding that lactic acid buildup gives you that muscle burn feeling, even though the mechanic itself doesn't just model that. Note that the name should not be mentioned in game and whoever codes this can call it whatever they want, that's just what I'm calling it in this issue for brevity. Please stop debating what it should be called in the comments.

If you let lactate accumulate it slows strain recovery and increases weariness. However this will also increase muscle gains a lot when we have a system for that.

  • When strain reaches 50%, every time strain increases further, add lactate equal to L * strain_change / base_strength, where L=1. Note lactate is a float.
    • Increase L by 1 at 75%, 90%, and 100%.
    • lactate does not increase if your net strain decreased this turn.
  • Every turn, if your strain is not increasing, decrease lactate by std::min( base_strength/current_strain, 1) or 1 if current_strain = 0.
    • Before reducing lactate, add a number of kcal equal to std::round(lactate) to the weariness tracker. Note that this does not add more calories to dietary needs, it's a surrogate to represent your muscles wearing out.
Math check and notes

If you are swinging a light weapon and building 5 strain per turn, at str8, you'll hit 50% strain after 8 swings, then swing 4 more times gaining 4*(5/8)=2.5 lactate to hit 75%, then swing 3 more times gaining 6*(5/8)=3.75 lactate to hit >90%, then your last swing will gain you 4*(5/8)=2.5 lactate and put you at 100% strain (you can force four more increasingly weak swings in for a total of 16*(5/8)=10 more lactate). This puts you at 2.5+3.75+2.5=8.75 lactate to reach full strain, and 18.75 if going all the way to failure. These correspond roughly to 45 weariness or 171 weariness each. The recovery will need some formulae to calculate because it's multivariate.

  • Your strain, the first fight-through, will recover pretty much every second, and go down by 8. That means it will take 10 seconds to recover. In that 10 seconds, most of the time you'll be recovering lactate equal to: (1+2+3+4+5+6+7+8+9+10)*8/80 = 5.5 lactate. That leaves you with another 2.25 to recover, which takes another 3 seconds. This may be a bit too quick, although also this isn't pushing yourself to extremes... a few swings at max strain will drive that number much higher.

Note that because your lactate doesn't decrease if your strain increases, and decreases quite slowly if you are strained until your strain gets low. At half strain, for example, you're losing 0.2 lactate per second, which is not insignificant but still pretty low. This will generally cause lactate to build up over time, even as strain recovers, because the general strategy is going to be to let your strain recover, then start fighting again. This also means that the generally good tactic of moving around and not doing strenuous things every turn will keep your strain from getting too high, but won't let all your lactate recover as readily. Once your strain drops to 10%, your lactate recovers pretty fast.

Old system - changed due to issues noted in comments

- Lactate increases by 1 when strain reaches 50%, 75%, 90%, and 100% of base_strain_cap.
- After a number of seconds equal to lactate*5, max 30 seconds, decrease lactate by 1. Reset this timer every time you gain or lose a point of lactate, up until lactate 5+... you should always lose a lactate after 5 minutes even if you're still doing stuff. This means that if you work your lactate up to 4 (the normal max), you'll need to wait 20+15+10+5=50 seconds to recover all your lactate. However, you will probably want to start fighting again before your lactate goes all the way down, unless your enemies are dead, so in a fight you presumably may be pushing it quite a lot harder.
- Just before you lose a lactate, add lactate^2 * 2 kcal (max 100) to the weariness tracker - so at 4 lactate getting back to 0 will give you 80+45+20+5=150kcal, or 1/4 of a weariness level for a baseline character. Note that this does not add more calories to dietary needs, it's a surrogate to represent your muscles wearing out.

Effect on strain recovery

Strain_recovery runs every second if lactate=0. If lactate>0, strain_recovery runs every n seconds where n is std::min(std::max(std::round(lactate/5),1), 5). This timer resets every time lactate increases. The cap prevents you from getting an impossibly high lactate and never being able to recover muscle strain. Note that the messy min-max stuff translates to "run at least every 1 second and at most every 5 seconds".

Game Balance

The basic math (assuming no weariness) for a strength 8 character should have you able to make about 16 unarmed melee attacks in a row before strain starts reducing their effectiveness, and 20 before they can't swing any more. At 16 attacks the strain meter will show as full and they'll have built up 4 lactate. It will then take 20 seconds to get all their strain back down half, but then their lactate drops to 3 so they start recovering faster and in the next 15 seconds they should recover the rest of it, as well as another level of lactate, taking it down to 1. If they continue fighting to their strain cap again then the lactate will continue rising. If they push back to their strain cap again immediately, their lactate goes up to 5, and now it takes a bit longer to get their strain back. (Note that pushing strain past the cap doesn't add more lactate. My initial plan had that in here but it made a model that requires a lot of micromanagement at the higher end of strain.)

  • This number stuff will need rechecking now that I have reformulated lactate.

A strength 10 character will be able to make significantly more attacks, and will recover more strain per second, so higher strength leads to exponentially higher amounts of strain and longer fights. Ideally we should get a graph set up for this, who likes graphing?

Obviously the player and character can both extend this, eg. by maneuvering in combat - at low strain, spending a single turn to reposition would drop your strain by 8, for example, which in turn has cascading ramifications on your endurance.

  • We may wish to review these numbers under the assumption that players are always going to drive their strength to the absolute limit every time. Boxing match times would be a good thing to examine. See bottom of this post.

Display in UI

I do not want lactate to be another stat players track independently. It should be treated as a sub-element of strain. If strain is represented as a bar in the UI, I suggest lactate be represented as blocks on the bar, adding a new block every 5 lactate to a max of 3 blocks. EG:

Strain: |||.. - player is 50% of the way to strain cap but has no lactate
Strain: █||.. - player has 5-9 lactate and is 50% of the way to strain cap
Strain: ███|. - player has 15-19 lactate and is 50% of the way to strain cap.

Describe alternatives you have considered.

It would be possible to devise other systems to slow down strain recovery, probably using weariness, but I think this is slick.

Additional context

When we add muscle gains through exercise, building and dropping lactate will be the primary way to get exercise gains.

Lactate should allow you to build and burn strain quickly for a little while but eventually forces you to take a longer break.

Using RL statistics

  • A pro boxing match is 12 rounds at 3 minutes each with 1 minute break. An amateur boxing match is usually 3 rounds at 3 minutes each with 1 minute break
    • This tells us that a character should be able to get their lactate down to zero in a 1 minute break, even if it's quite high. The difference between pro and amateur can be accounted for with weariness thresholds and cardio, and at some point perhaps skill or proficiency can also reduce the impact of extended activity.
  • A pro heavyweight boxer throws about 30 punches in a 3 minute round, a lightweight throws around 100.
    • Since we are currently assuming all punches are equal force, we can say we're averaging that out to about 60 punches per round, conveniently about 1 per 3 seconds.
    • This is an upper limit of human normal stat, not what we expect an average player to accomplish initially.
@I-am-Erk I-am-Erk added Game: Mechanics Change Code that changes how major features work Game: Balance Balancing of (existing) in-game features. <Suggestion / Discussion> Talk it out before implementing Mechanics: Effects / Skills / Stats Effects / Skills / Stats (P3 - Medium) Medium (normal) priority Mechanics: Character / Player Character / Player mechanics labels Aug 3, 2022
@chrispikula
Copy link
Contributor

I don't like the use of the word Lactate, Anaerobic Buildup, or ATP Depletion would be better, imo.

@I-am-Erk
Copy link
Member Author

I-am-Erk commented Aug 3, 2022

Since it's a stat that will only exist in the C++ code, the implementer can name it whatever they enjoy most.

@PatrikLundell
Copy link
Contributor

PatrikLundell commented Aug 4, 2022

I can't say I'm a fan of making strength even more of an all important stat. It already has far too much weight, in my opinion.

DEX ought to come into play when it comes to the number of swings you can make, and skill should increase it as well, since you're not wasting as much energy in doing unnecessary movements and tightening muscles too much. People good at doing things not only perform the tasks better, but also with less effort.

@chrispikula
Copy link
Contributor

Since it's a stat that will only exist in the C++ code, the implementer can name it whatever they enjoy most.

Fair, but we've already got animals that produce milk, aka, lactate. It just seems that it's going to end up in confusion.

@I-am-Erk
Copy link
Member Author

I-am-Erk commented Aug 4, 2022

I can't say I'm a fan of making strength even more of an all important stat. It already has far too much weight, in my opinion.

DEX ought to come into play when it comes to the number of swings you can make, and skill should increase it as well, since you're not wasting as much energy in doing unnecessary movements and tightening muscles too much. People good at doing things not only perform the tasks better, but also with less effort.

This begins the process of making strength not a stat anymore.

@I-am-Erk
Copy link
Member Author

I-am-Erk commented Aug 4, 2022

Since it's a stat that will only exist in the C++ code, the implementer can name it whatever they enjoy most.

Fair, but we've already got animals that produce milk, aka, lactate. It just seems that it's going to end up in confusion.

Again, this is not a player facing word. You can call it Steve if you like

@PatrikLundell
Copy link
Contributor

I fail to see how making STR even more dominant begins the process of eliminating it. It's of course possible there is some road map I'm not aware of.

I agree with @chrispikula. Even if it's not player facing, it's presumably not core developer specific either, and so would benefit from having a name that newcomers might recognize (it also doesn't help that it probably is a word many don't understand, both native English speakers and second language users). "lactic_acid" is less bad than lactate, but not good.

@I-am-Erk
Copy link
Member Author

I-am-Erk commented Aug 4, 2022

If strength is something you can build up over time, rather than a static element, then it becomes less dominant in character generation. The process of making strength something you build up over time is also tied to splitting various strength roles into sub elements, like tracking endurance and toughness separately.

@PatrikLundell
Copy link
Contributor

If strength is something you can build up over time to essentially the same level regardless of where you started, yes. If, however, you can build up only a certain amount on top of your starting point it doesn't change the extreme importance of STR. If you had strongly diminishing returns on your starting investment it could make a difference (e.g. a starting STR of 14 allowed you to add 4 points of STR, a starting STR of 8 allowed you to add 8 or 9, and a starting STR of 4 allowed you to add 10 or 12). That said, unless there are significant changes elsewhere to make the points "freed up" useful, STR would still be the absolute king.
I'm hoping for a more balanced value of stats eventually, though.

@I-am-Erk
Copy link
Member Author

I-am-Erk commented Aug 4, 2022

Wait for the next issue post for more informatoin, but basically it isn't going to work like that. or rather it is going to work like some of htat but not all of that.

@zachary-kaelan
Copy link
Contributor

I can't say I'm a fan of making strength even more of an all important stat. It already has far too much weight, in my opinion.

DEX ought to come into play when it comes to the number of swings you can make, and skill should increase it as well, since you're not wasting as much energy in doing unnecessary movements and tightening muscles too much. People good at doing things not only perform the tasks better, but also with less effort.

Dexterity and skills already make you waste less energy doing unnecessary movements, by making up most of your probability to hit.
base = (weapon_skill / 3) + (melee / 2) + dex / 4 + to-hit

@zachary-kaelan
Copy link
Contributor

I like graphing!

Looking up punching bag workouts and the recommendations there might also provide a lot of good information, especially for lactate build-up varying by strength level.

@I-am-Erk
Copy link
Member Author

I-am-Erk commented Aug 5, 2022

I would love some graphs. I am sure my numbers will need some tweaks.

@Zireael07
Copy link
Contributor

On the topic of naming: not a native speaker of English and not anywhere close to physically fit, but "lactic acid" is something I am familiar with, even if in passing, while "lactate" only brought to mind the verb, "to produce milk" (and that's me being an English major)

And I believe c++ variables should be named such that people know what they mean at first, at most second glance - Cata is already a huge project and we've had more than a handful of instances of people misunderstanding what this variable or function do...

@I-am-Erk
Copy link
Member Author

I-am-Erk commented Aug 5, 2022

Guys I truly don't care what the c++ variable is named, but would really enjoy discussing the balance of the mechanic in question.

@zachary-kaelan
Copy link
Contributor

Why are you fighting so hard against it being named muscle_gainz_temp, Erk? It's just a variable name, calm down. /s

I did a bit of research and also found a website called CompuBox. Lighter weight boxers can be throwing up to 93 punches per round. But it can also vary based on how many of the punches were power throws, how many were jabs, how many missed, and how many punches they themselves took. I could scrape everything and try and find some correlations and such.

@zachary-kaelan
Copy link
Contributor

zachary-kaelan commented Aug 6, 2022

I don't get exactly how lactate increases. If you are at 52% strain, wait a second and recover to 47% strain, then swing and go back up to 52% strain, and repeat, do you get 1 lactate every second? And if not, how do you get more than 4 lactate, or how do you keep lactate from going back to 0 while exercising at above 100% strain?

@I-am-Erk
Copy link
Member Author

I-am-Erk commented Aug 6, 2022

Hmm, that's a good argument about the risk of increasing repeatedly in the lower levels. We might need to adjust the mechanic somewhat to track that, I have some ideas but need coffee first

@I-am-Erk
Copy link
Member Author

I-am-Erk commented Aug 9, 2022

I have reformulated it, it is not as simple as before but now it doesn't game people by lingering at a threshold. Numbers need some rechecking but I think they may be better now.

@zachary-kaelan
Copy link
Contributor

If you're swinging for 5 strain per turn, aren't you also recovering 3 strain per turn, for a net strain of 2 per turn, taking 20 swings to get to 50% strain?

@zachary-kaelan
Copy link
Contributor

I ran a little script to swing until fatigue (can't swing any more) and graph it out: https://imgur.com/a/efbjV2R

@I-am-Erk
Copy link
Member Author

If you're swinging for 5 strain per turn, aren't you also recovering 3 strain per turn, for a net strain of 2 per turn, taking 20 swings to get to 50% strain?

You should only lose strain if you didn't gain strain that turn. Added that caveat to avoid having to do a ton of math.

@zachary-kaelan
Copy link
Contributor

Ah, here are the new graphs then:

@I-am-Erk
Copy link
Member Author

Those numbers seem really good to me. Can you do one where you pause and recover every third turn?

@zachary-kaelan
Copy link
Contributor

Here are the results:

Strength: 8
Swings to 50% strain: 29
Swings to 100% strain: 69
Lactate peak: 39.882
Turns to recover strain: 11
Lactate at strain recovery: 35.228
Turns to recover lactate: 47
Weariness: 1323 (1)

For a Strength of 10, the two swings give 10 strain, and then the break recovers 10 strain, so it goes on forever.

@I-am-Erk
Copy link
Member Author

Technically it goes on until you gain at least one level of weariness. I'll have to consider if that needs tweaking or if it's ok.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Game: Balance Balancing of (existing) in-game features. Game: Mechanics Change Code that changes how major features work Mechanics: Character / Player Character / Player mechanics Mechanics: Effects / Skills / Stats Effects / Skills / Stats (P3 - Medium) Medium (normal) priority <Suggestion / Discussion> Talk it out before implementing
Projects
None yet
Development

No branches or pull requests

5 participants