-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
[WIP] Create cardio #50339
[WIP] Create cardio #50339
Conversation
Co-authored-by: George Karfakis <[email protected]>
What are the expected values of Cardio/stamina at different stages of the game? Eg, an out of chargen survivor with 0 athletics, or a midgame survivor with athletics 5 and a good diet? |
See #44370 for original issue and design. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a max cardio stat, and per some of Kevin's concerns, perhaps we should change the general name to 'cardiofit' for 'cardio fitness' to keep meanings clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good! (There do not appear to be any effects of health on NPC stamina, but I doubt it matters.)
src/character.cpp
Outdated
|
||
return string_format( "Weariness: %s Max Full Exert: %s Mult: %g\nBMR: %d %s Thresh: %d At: %d\nCal: %d/%d Fatigue: %d Morale: %d Wgt: %d (BMI %.1f)", | ||
amt, max_act, move_mult, bmr, weary_internals, thresh, current, get_stored_kcal(), | ||
get_healthy_kcal(), fatigue, morale, weight, bmi ); | ||
return string_format( "Weariness: %s Max Exertion: %s Mult: %g\nCARDIO FITNESS: %d %s Thresh: %d At: %d\n Calories: %d/%d Fatigue: %d Morale: %d Wgt: %d (BMI %.1f)", | ||
amt, max_act, move_mult, cardio_mult, activity_history.debug_weary_info(), thresh, current, | ||
get_stored_kcal(), get_healthy_kcal(), fatigue, morale, weight, bmi ); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After finishing testing cardio, could the original information be restored in addition to cardio (ideally in lines that aren't too terribly long)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably have both I would think, I added both back last time. Would you be willing to post a suggestion? My screen time is at an end.
The test failure for the Basic Build is that, when it tries to access metabolic_rate_base() for base_bmr(), via a float option, something goes wrong (and causes a coredump, so I don't think it's just it not able to find something). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple of places where base_bmr()
, possibly modified, may be what is needed instead of get_bmr()
, which includes effects from the current activity level.
Co-authored-by: actual-nh <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's a preliminary suggestion.
Co-authored-by: actual-nh <[email protected]>
Co-authored-by: actual-nh <[email protected]>
Those seem reasonable to me for now. It's a debug line so if it's a bit hard to read it's not the end of the world. |
This allows it to scale differently than base stamina so it doesn't always take 6 minutes to catch your breath.
OK. This is intense, I think this actually works. I had to adjust how the stamina regeneration equation works from my initial proposal, which actually simplifies this PR. your stamina regeneration rate now starts at 20 as before, but is multiplied by (get_cardiofitness()/base_bmr()), so that as your cardio fitness exceeds BMR your regen increases, or vice versa. This means if you suddenly get bigger your regeneration drops. With the present balance, I did three tests:
The previous standard has a newly generated character running for 1:10 and recovering to full stamina in 7:30, which means I may need to slightly adjust the default stamina regeneration as I don't want to buff starting characters too strongly. Otherwise this seems to be working properly and well. The magnitude of effect might be low, if anything. With further debug tools to directly set cardio it would be easier to test but I do not think play balance will tank if we merge this as is. |
Co-authored-by: Eric Pierce <[email protected]>
I am sure there will be some CI tests very angry about this. From my perspective aside from solving the upcoming failed tests, this PR is ready to merge. I think we need a follow up PR relatively soon with:
|
The "Custom" sidebar stamina graphs aren't quite accurate now with the flexible maximum - but the fix is easy, just remove the "var_max" field from both "stamina_graph" and "stamina_graph_classic", and the graphs will default to using Cataclysm-DDA/data/json/ui/sidebar.json Line 240 in 6b325a9
Cataclysm-DDA/data/json/ui/sidebar.json Line 251 in 6b325a9
P.S. This is resolved now |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Barring unexpected errors, I have the first stage of accommodating sleep better with weariness (as in not in 5-minute blocks of "sleeping" or "not sleeping"). The next stage will be intermediate effects between LIGHT_EXERCISE, NO_EXERCISE, and SLEEP_EXERCISE. After that, mutations.
Co-authored-by: Eric Pierce <[email protected]>
Co-authored-by: actual-nh <[email protected]>
void avatar::update_cardio_acc() | ||
{ | ||
const int prev_cardio_acc = get_cardio_acc(); | ||
const int last_24h_kcal = calorie_diary.begin()->spent; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const int last_24h_kcal = calorie_diary.begin()->spent; | |
const int last_24h_kcal = calorie_diary.front().spent; |
Since you don't need an iterator here, front()
would be more appropriate I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, if I'm not mistaken, the front of this array is only the spent calories since midnight - not the previous 24 hours.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so:
if( is_avatar() && ticks_between( from, to, 24_hours ) > 0 ) {
as_avatar()->advance_daily_calories();
}
in character_body.cpp and:
void avatar::advance_daily_calories()
{
calorie_diary.push_front( daily_calories{} );
if( calorie_diary.size() > 30 ) {
calorie_diary.pop_back();
}
}
in avatar.cpp.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what I mean - every 24 hours, the front of this list gets a new (empty) calorie log. In order for this update_cardio_acc
to work properly, I think it would need to be invoked from Character::update_body
just before advance_daily_calories()
, to capture the previous day's cardio level.
@@ -1461,6 +1461,19 @@ bool avatar::invoke_item( item *used, const std::string &method ) | |||
return Character::invoke_item( used, method ); | |||
} | |||
|
|||
void avatar::update_cardio_acc() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this function ever called? I don't see any invocations; this looks like dead code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Afaict that's an error if so, I wonder if it got missed during one of the conflict merges
As I recall the first implementation wasn't going to include the accumulator so I wonder if it's not fully done. Seems like it would be easy to fix
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see now the comment from gkarfakis19 on the previous unfinished PR (repeated several times):
I do NOT plan on adding the exercise (cardio_acc) aspect of Cardio in this PR. It will come later.
It looks like it was implemented as requested, just not hooked up to anything. As noted in my other comment on this function, I think it would make sense to invoke it from Character::update_body
just before the advance_daily_calories()
call; that way it ought to include the previous 24 hours of activity from the diary.
I have been doing some playtesting with this using #51701 to see what's going on with I believe this large random value may be because After saving and loading, the values are much more reasonable: |
I just saw this pull request. It's great to see my old code (hopefully it wasn't too messy!) get used by someone more experienced that is able to properly support such a game-changing feature. Excited to see where this leads! |
@@ -482,6 +482,7 @@ Character::Character() : | |||
} | |||
// Only call these if game is initialized | |||
if( !!g && json_flag::is_ready() ) { | |||
set_cardio_acc( base_bmr() / 2 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Following up on my comment:
I believe this large random value may be because
cardio_acc
is uninitialized in theCharacter
constructor.
Here is where the cardio_acc
initialization should occur - but it is gated by json_flag::is_ready()
, which for whatever reason is false when the Character
constructor is called. I believe the reason for stipulating this condition is that base_bmr()
needs metabolic_rate_base()
, which reads from game_balance.json
the setting for PLAYER_HUNGER_RATE
(default 1.0) - so it needs this is_ready()
flag to be true in order to read that balance setting.
If we can find a way to initialize cardio_acc
to a reasonable value without depending on base_bmr()
, that should resolve the problem with new characters having wildly random cardio values. Or, find a way to ensure json_flag::is_ready()
is true before we reach this constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will figure out a solution for this in the new PR.
After consulting with @KorGgenT and @I-am-Erk , I went ahead and started another fresh pull request with a clean rebase from a more recent point in master, including everything from this PR as well as some test cases and new sidebar widgets: #51880 Sorry to play musical chairs on everyone following this feature, but let us continue the review and conversation over there. |
Summary
Features "Implements cardio to adjust weariness and stamina based on fitness"
see #44506 for all relevant discussion and original PR.
Closes #44506