CleverRaven / Cataclysm-DDA

Cataclysm - Dark Days Ahead. A turn-based survival game set in a post-apocalyptic world.
http://cataclysmdda.org
Other
10.7k stars 4.2k forks source link

Modeling muscle use through "strain" #59862

Open I-am-Erk opened 2 years ago

I-am-Erk commented 2 years ago

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

The model we've developed for improving cardiovascular fitness to increase stamina seems to be working quite well as a general representation of exercise, but we still can't exercise other stats. Notably, strength is fully static and should not be.

We need a cohesive model for physical strength. However, a rational model for increasing physical strength requires better representation to distinguish muscle contraction from aerobic exercise. This means breaking up stamina again to distinguish "I ran so I am tired" from "I have been lifting and my arms don't work anymore". This follows a preceding recommendation to change the term stamina into breath and fatigue into sleepiness to avoid confusion.

Solution you would like.

Once we have clarified our terminology we need to add a new short term stamina resource, muscle strain or strain for short. (Exertion has been suggested as a good alternative). Strain represents using your muscles until failure, and will cross paths with current stamina a lot at first. However part of the reason to change stamina to breath is to help clarify where we use the two.

Later we'll add a second hidden resource to track how many times you've maxed out your strain recently, but that will be skipped in this Issue to keep it simple.

Activities that affect strain

Note that your current strength isn't used to calculate strain. Instead your current strength determines how much strain you can tolerate, but the amounts of strain a given activity causes should be pretty constant.

  1. Swinging a melee weapon: Inflicts strain at a rate of std::min( 5 * weapon_weight_kg, 5 ) (at some point we may wish to figure weapon type and length in here as well, swinging a sledgehammer is harder than swinging a balanced sword - but for now this should allow us to get a reasonable system going.)
  2. Drawing a bow or crossbow, holding a drawn bow: Inflicts strain at a rate of weapon_strength_requirement to draw, and every turn you hold it drawn.
  3. Throwing an object: Inflicts strain equal to swinging it in melee.
  4. Carrying: Carrying more than 100% of your max carry weight should inflict 1 strain per minute for every kg over carry limit even if holding still.
  5. Moving while overburdened: If you are over your carry weight, every time you move, inflict the amount of strain calculated in 4 above.
  6. Climbing: Climbing up or down a z-level (not just transitioning but specifically climbing) inflicts strain equal to current_carry_weight_kg
  7. Dragging objects/vehicles: Adds strain equal to the strength required to move the object.
  8. Inventory actions (picking up or dropping objects, moving between containers eg): Add an amount of strain equal to `std::min( (weight_in_kg - 5), 0 ) - this means that items below 5kg (about 10 lbs) never add strain.
  9. Other activities: Eventually certain high-energy activities may add strain, so that if you suddenly drop your shovel from digging trenches and start wailing on a zombie, you aren't fresh as if you've been resting. Eventually we should add the ability to intentionally strain yourself with an exercise activity. These can wait.

Strain tolerance

base_strain_cap = base_strength * ( 10 - current_weariness_level )

if(current_strain>base_strain_cap): effective_strength = base_strength * (base_strain_cap/current_strain) ^ 2

In melee combat, discounting weariness/recovery, this model lets you swing a light weapon a number of times equal to double your strength, without breaks, before hitting your cap. Then your damage starts to rapidly fall off, assuming your weapon doesn't have a minimum strength to wield. At strength 8, you'd be unable to keep swinging when your current_strain reaches about 100, or about 20 swings of a light weapon - remember this is assuming you're taking no breaks and recovering no strain. That's about 20 seconds of protracted swinging, and it would then take about 12 seconds to recover all your strength (until we add lactate buildup). Those last four swings are going to get weaker each time. Weapons that weigh more than 5kg will allow fewer swings, assuming an equal attack speed, but bear in mind that if something takes longer to swing, it won't necessarily accrue strain as quickly because of the time gap. This will need some playtesting to sort out fully.

Notable exceptions:

Strain recovery

Strain_recovery runs every second in this simple model. Later we will add things that can slow this down over time.

Each time strain_recovery runs, reduce strain by std::max( base_strength - current_weariness_level ), 1 ) if strain has not increased since last recovery. If strain has increased since last recovery, do not decrease strain this time.

We use base_strength here because your strain increases proportional to your strength and it shouldn't take longer to recover when you are stronger. At higher strengths your weariness won't impact your recovery quite as much.

Impact on weariness

We should make sure that for any action where strain is calculated, weariness does not have any impact on speed. Most notably, your weapon attacks should not be slowed by weariness, because we're instead representing that by encouraging you to take short breaks and recover muscle function.

Every point of strain you gain should also count as 1 kcal burned for the purposes of increasing weariness - this should not increase dietary needs though. Later, the lactate system will also give ways for strain to increase weariness if you push yourself to your limits.

Changes to current stamina (renamed Breath)

With strain implemented, stamina should have less of a role in the systems that now implement strain. I suggest we just flat reduce stamina costs in any affected combat area by 1/2, to start. The target balance should be that melee combat is at roughly the same setpoint as before strain was added, for a starting average character, but the limiting resource is strain rather than breath. When you run out of strain you should still have a little energy to run with.

Ultimately this will probably be seen as a nerf to melee but I'd like it to be a small buff mechanically, even before we get to improving your strength, due to that extra ability to still run away.

Describe alternatives you have considered.

It would be possible to use our current stamina as a catchall for both aerobic and resistance exercise, but it leads to a lot less reasonable physical management, where doing anything that trains cardio also gains strength, and it makes for a more boring game where you have only a single improvable physical stat that improves with all the same actions.

It would be worth considering having current breath impact strain recovery, if you're out of breath it takes longer to clear your muscles.

Additional context

Next up is adding lactate, without which this mechanic is mostly vestigial. Without lactate it is almost trivially easy to continually recover all your strain in a few seconds. Lactate will make it so that you can initially recover your strain very fast, but the more you do that, the longer you have to wait the next time, until your arms become noodles.

I would like to review and balance the numbers here based on boxing match information at various levels of skill. If someone can get more numbers and hlep me out that'd be awesome

zachary-kaelan commented 2 years ago

Problem with the weapon strain amounts (std::min( 5 * weapon_weight_kg, 5 )): with a maximum of 5 strain per swing and recovery of strength - strain gained, a strength of 10 or above lets you swing any weapon infinitely.

I-am-Erk commented 2 years ago

Ah, I see the confusion, I seem to have accidently reverted a change and kept an older model of strain recovery here. I noticed this flaw in that math a while back. Fixedit.

x-qq commented 2 years ago

Can you explain how implementation of this improves the average player's gameplay compared to its current state?

zachary-kaelan commented 2 years ago

Can you explain how implementation of this improves the average player's gameplay compared to its current state?

Currently, if you swing a big weapon at something too many times, your arms get tired... and you lose the ability to sprint. You are simultaneously unable to defend yourself and unable to run away.

gvlasov commented 1 year ago

I'm an amateur lifting/workout enthusiast, so here are my two cents.

When doing heavy physical labor, there are two factors that limit you: muscle tissue failure and cardiovascular +respiratory failure. The latter is well modelled by current stamina model in 0.G, lets call it stamina. Stamina is a single factor, and muscle failure is per muscle group. Muscle failure comes from short-term strain, and given too much strain in short term, it should cause muscle pain for a couple of days.

Strain could be per body part. I see it could be an overkill, but overstraining your arms shouldn't affect your running.

I imagine

I suggest the following strain areas:

If you don't overstrain (strain meter doesn't exceed some limit), you don't get sore muscles the next day. The more you overstrain, the longer the sore muscles effect. Sore muscles would decrease your strength temporarily and increase the baseline level of pain. Myorelaxants like marijuana could decrease the sore muscles pain, but not the strength loss. Strain limit should grow after you have overreached it and then took some rest (this could just be a hook on waking up event), and decay as you don't go over your strain limit in some sort of moving average manner over a couple of months.

Displaying strain could be in status effects:

Strain would be the required factor in muscule growth, but muscules would only grow during relaxation period after strain given steady calory intake and good health. Ectomorph/mesomorph/endomorph somatotypes as character traits would be great additions.

Overall base strength could be modeled as median of body part strengths after working out. Consult supercompensation model on muscle growth patterns:

Supercompensation ![image](https://github.com/CleverRaven/Cataclysm-DDA/assets/4467948/61a13384-5ffa-4d92-be9e-ce4afee75085)

I-am-Erk commented 1 year ago

Tracking strain on body parts is something we considered in discussion, but the game has very few areas where it will make a meaningful difference to track legs and back separately from arms and shoulders. It just makes for a more convoluted display, and a lot of debating over how much arm strength Vs upper torso strength influences damage from a bow, or whether upper torso should determine carry limits.

The rest of what you've described is pretty much what we're looking at here, running it as a moving average over weeks to months like cardio does