Skip to content

Commit

Permalink
Merge pull request #53603 from wapcaplet/w-cardio-workout
Browse files Browse the repository at this point in the history
Allow mutations to affect cardio
  • Loading branch information
kevingranade authored Jan 1, 2022
2 parents d4d82f8 + 2d4a90c commit 0d20a08
Show file tree
Hide file tree
Showing 7 changed files with 393 additions and 36 deletions.
20 changes: 10 additions & 10 deletions data/json/mutations/mutations.json
Original file line number Diff line number Diff line change
Expand Up @@ -232,26 +232,26 @@
"id": "GOODCARDIO",
"name": { "str": "Indefatigable" },
"points": 2,
"description": "Whether due to exercise and good diet, or due to a natural propensity to physical endurance, you tire due to physical exertion much less readily than others. Your maximum stamina is higher than usual.",
"description": "Whether due to exercise and good diet, or due to a natural propensity to physical endurance, you tire due to physical exertion much less readily than others. Your cardio fitness and maximum stamina are higher than usual.",
"starting_trait": true,
"valid": false,
"cancels": [ "BADCARDIO" ],
"changes_to": [ "GOODCARDIO2" ],
"category": [ "FISH", "LUPINE", "MOUSE", "INSECT" ],
"max_stamina_modifier": 1.25
"cardio_multiplier": 1.3
},
{
"type": "mutation",
"id": "GOODCARDIO2",
"name": { "str": "Hyperactive" },
"points": 4,
"description": "Your body's efficiency is like that of a tiny furnace, greatly increasing your maximum stamina",
"description": "Your body's efficiency is like that of a tiny furnace, greatly increasing your cardio and stamina.",
"valid": false,
"prereqs": [ "GOODCARDIO" ],
"cancels": [ "BADCARDIO" ],
"threshreq": [ "THRESH_MOUSE", "THRESH_RABBIT" ],
"category": [ "MOUSE", "RABBIT" ],
"max_stamina_modifier": 1.4
"cardio_multiplier": 1.6
},
{
"type": "mutation",
Expand Down Expand Up @@ -1024,11 +1024,11 @@
"id": "BADCARDIO",
"name": { "str": "Languorous" },
"points": -2,
"description": "Whether due to lack of exercise and poor diet, or due to a natural disinclination to physical endurance, you tire due to physical exertion much more readily than others. Your maximum stamina is lower than usual.",
"description": "Whether due to lack of exercise and poor diet, or due to a natural disinclination to physical endurance, you tire due to physical exertion much more readily than others. Your total cardio fitness and stamina are lower than normal.",
"starting_trait": true,
"valid": false,
"cancels": [ "GOODCARDIO" ],
"max_stamina_modifier": 0.75
"cardio_multiplier": 0.7
},
{
"type": "mutation",
Expand Down Expand Up @@ -7467,12 +7467,12 @@
},
{
"type": "mutation",
"id": "DEBUG_STAMINA",
"name": { "str": "Debug Stamina" },
"id": "DEBUG_CARDIO",
"name": { "str": "Debug Cardio" },
"points": 99,
"valid": false,
"max_stamina_modifier": 999999,
"description": "You can't run from the bugs, but you have enough stamina to at least try to.",
"cardio_multiplier": 999999,
"description": "You can run, but you'll never run out of breath.",
"debug": true
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
"threshreq": [ "THRESH_SYLVAN" ],
"category": [ "SYLVAN" ],
"cancels": [ "BADCARDIO" ],
"max_stamina_modifier": 1.5,
"cardio_multiplier": 1.8,
"stamina_regen_modifier": 0.25
}
]
2 changes: 2 additions & 0 deletions doc/JSON_INFO.md
Original file line number Diff line number Diff line change
Expand Up @@ -2173,6 +2173,8 @@ The `id` must be exact as it is hardcoded to look for that.
"metabolism_modifier": 0.333, // Extra metabolism rate multiplier. 1.0 doubles usage, -0.5 halves.
"fatigue_modifier": 0.5, // Extra fatigue rate multiplier. 1.0 doubles usage, -0.5 halves.
"fatigue_regen_modifier": 0.333, // Modifier for the rate at which fatigue and sleep deprivation drops when resting.
"stamina_regen_modifier": 0.1, // Increase stamina regen by this proportion (1.0 being 100% of normal regen)
"cardio_multiplier": 1.5, // Multiply total cardio fitness by this amount
"healing_awake": 1.0, // Healing rate per turn while awake.
"healing_resting": 0.5, // Healing rate per turn while resting.
"mending_modifier": 1.2 // Multiplier on how fast your limbs mend - This value would make your limbs mend 20% faster
Expand Down
65 changes: 42 additions & 23 deletions src/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5704,7 +5704,7 @@ mutation_value_map = {
{ "movecost_flatground_modifier", calc_mutation_value_multiplicative<&mutation_branch::movecost_flatground_modifier> },
{ "movecost_obstacle_modifier", calc_mutation_value_multiplicative<&mutation_branch::movecost_obstacle_modifier> },
{ "attackcost_modifier", calc_mutation_value_multiplicative<&mutation_branch::attackcost_modifier> },
{ "max_stamina_modifier", calc_mutation_value_multiplicative<&mutation_branch::max_stamina_modifier> },
{ "cardio_multiplier", calc_mutation_value_multiplicative<&mutation_branch::cardio_multiplier> },
{ "weight_capacity_modifier", calc_mutation_value_multiplicative<&mutation_branch::weight_capacity_modifier> },
{ "hearing_modifier", calc_mutation_value_multiplicative<&mutation_branch::hearing_modifier> },
{ "movecost_swim_modifier", calc_mutation_value_multiplicative<&mutation_branch::movecost_swim_modifier> },
Expand Down Expand Up @@ -6192,12 +6192,13 @@ int Character::get_stamina_max() const
// Default base maximum stamina and cardio scaling are defined in data/core/game_balance.json
static const std::string player_max_stamina( "PLAYER_MAX_STAMINA_BASE" );
static const std::string player_cardiofit_stamina_scale( "PLAYER_CARDIOFIT_STAMINA_SCALING" );
static const std::string max_stamina_modifier( "max_stamina_modifier" );

// Cardiofit stamina mod defaults to 3, and get_cardiofit() should return a value in the vicinity
// of 1000-4000, so this should add somewhere between 3000 to 12000 stamina.
int max_stamina = get_option<int>( player_max_stamina ) +
get_option<int>( player_cardiofit_stamina_scale ) * get_cardiofit();
max_stamina = enchantment_cache->modify_value( enchant_vals::mod::MAX_STAMINA, max_stamina );

return max_stamina;
}

Expand Down Expand Up @@ -6261,18 +6262,23 @@ void Character::burn_move_stamina( int moves )
void Character::update_stamina( int turns )
{
static const std::string player_base_stamina_regen_rate( "PLAYER_BASE_STAMINA_REGEN_RATE" );
static const std::string stamina_regen_modifier( "stamina_regen_modifier" );
const float base_regen_rate = get_option<float>( player_base_stamina_regen_rate );
// Your stamina regen rate works as a function of how fit you are compared to your body size. This allows it to scale more quickly
// than your stamina, so that at higher fitness levels you recover stamina faster.
// Your stamina regen rate works as a function of how fit you are compared to your body size.
// This allows it to scale more quickly than your stamina, so that at higher fitness levels you
// recover stamina faster.
const float effective_regen_rate = base_regen_rate * get_cardiofit() / base_bmr();
const int current_stim = get_stim();
float stamina_recovery = 0.0f;
// Recover some stamina every turn.
// Mutations can affect stamina regen via stamina_regen_modifier (0.0 is normal)
// Values above or below normal will increase or decrease stamina regen
const float mod_regen = mutation_value( "stamina_regen_modifier" );
// Mutated stamina works even when winded
// max stamina modifers from mutation also affect stamina multi
float stamina_multiplier = std::max<float>( 0.1f, ( !has_effect( effect_winded ) ? 1.0f : 0.1f ) +
mutation_value( stamina_regen_modifier ) + ( mutation_value( "max_stamina_modifier" ) - 1.0f ) );
const float base_multiplier = mod_regen + ( has_effect( effect_winded ) ? 0.1f : 1.0f );
// Ensure multiplier is at least 0.1
const float stamina_multiplier = std::max<float>( 0.1f, base_multiplier );

// Recover some stamina every turn. Start with zero, then increase recovery factor based on
// mutations, stimulants, and bionics before rolling random recovery based on this factor.
float stamina_recovery = 0.0f;
// But mouth encumbrance interferes, even with mutated stamina.
stamina_recovery += stamina_multiplier * std::max( 1.0f,
effective_regen_rate * get_modifier( character_modifier_stamina_recovery_breathing_mod ) );
Expand Down Expand Up @@ -6308,9 +6314,11 @@ void Character::update_stamina( int turns )
}
}

mod_stamina( roll_remainder( stamina_recovery * turns ) );
add_msg_debug( debugmode::DF_CHARACTER, "Stamina recovery: %d",
roll_remainder( stamina_recovery * turns ) );
// Roll to determine actual stamina recovery over this period
int recover_amount = roll_remainder( stamina_recovery * turns );
mod_stamina( recover_amount );
add_msg_debug( debugmode::DF_CHARACTER, "Stamina recovery: %d", recover_amount );

// Cap at max
set_stamina( std::min( std::max( get_stamina(), 0 ), max_stam ) );
}
Expand All @@ -6324,19 +6332,30 @@ int Character::get_cardiofit() const
const int bmr = base_bmr();
const int athletics_mod = get_skill_level( skill_swimming ) * 10;
const int health_effect = get_healthy();
// Traits now exclusively affect cardio, NOT max_stamina directly. In the future, make cardio_acc also be affected by cardio traits so that they don't become less impactful.
const int trait_mod = mutation_value( "max_stamina_modifier" );

// FIXME: Delete this untruth
// Traits now exclusively affect cardio, NOT max_stamina directly. In the future, make
// cardio_acc also be affected by cardio traits so that they don't become less impactful.
//const int trait_mod = 0;

// At some point we might have proficiencies that affect this.
const int prof_mod = 0;
const int cardio_acc_mod = get_cardio_acc();
int final_cardio_fitness = bmr / 2 + athletics_mod + health_effect + trait_mod + prof_mod +
cardio_acc_mod;
if( final_cardio_fitness > 3 * ( bmr + trait_mod ) ) {
// Set a large sane upper limit to cardio fitness. This could be done asymptotically instead of as a sharp cutoff, but the gradual
// growth rate of cardio_acc_mod should accomplish that naturally. The BMR will mostly determine this as it is based on the
// size of the character, but mutations might push it up.
final_cardio_fitness = 3 * ( bmr + trait_mod );
}

// Base formula for cardio fitness
int base_cardio_fitness = bmr / 2 + athletics_mod + health_effect + prof_mod + cardio_acc_mod;

// Apply trait modifier as a scaling factor to total cardio
// FIXME: Do this additively as a trait_mod using the original formula, somehow
const float scale = mutation_value( "cardio_multiplier" );
const float scaled_fitness = base_cardio_fitness * scale;

// Set a large sane upper limit to cardio fitness. This could be done asymptotically instead of
// as a sharp cutoff, but the gradual growth rate of cardio_acc_mod should accomplish that
// naturally. The BMR will mostly determine this as it is based on the size of the character,
// but mutations might push it up.
int final_cardio_fitness = static_cast<int>( std::min( scaled_fitness, 3 * bmr * scale ) );

return final_cardio_fitness;
}

Expand Down
2 changes: 1 addition & 1 deletion src/mutation.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ struct mutation_branch {
cata::optional<float> movecost_flatground_modifier = cata::nullopt;
cata::optional<float> movecost_obstacle_modifier = cata::nullopt;
cata::optional<float> attackcost_modifier = cata::nullopt;
cata::optional<float> max_stamina_modifier = cata::nullopt;
cata::optional<float> cardio_multiplier = cata::nullopt;
cata::optional<float> weight_capacity_modifier = cata::nullopt;
cata::optional<float> hearing_modifier = cata::nullopt;
cata::optional<float> movecost_swim_modifier = cata::nullopt;
Expand Down
2 changes: 1 addition & 1 deletion src/mutation_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ void mutation_branch::load( const JsonObject &jo, const std::string & )
optional( jo, was_loaded, "movecost_obstacle_modifier", movecost_obstacle_modifier, cata::nullopt );
optional( jo, was_loaded, "movecost_swim_modifier", movecost_swim_modifier, cata::nullopt );
optional( jo, was_loaded, "attackcost_modifier", attackcost_modifier, cata::nullopt );
optional( jo, was_loaded, "max_stamina_modifier", max_stamina_modifier, cata::nullopt );
optional( jo, was_loaded, "cardio_multiplier", cardio_multiplier, cata::nullopt );
optional( jo, was_loaded, "weight_capacity_modifier", weight_capacity_modifier, cata::nullopt );
optional( jo, was_loaded, "hearing_modifier", hearing_modifier, cata::nullopt );
optional( jo, was_loaded, "noise_modifier", noise_modifier, cata::nullopt );
Expand Down
Loading

0 comments on commit 0d20a08

Please sign in to comment.