Skip to content

Commit

Permalink
Encapsulate Stamina (#34861)
Browse files Browse the repository at this point in the history
  • Loading branch information
Fris0uman authored and kevingranade committed Oct 26, 2019
1 parent 04dc7c1 commit 8f0b78f
Show file tree
Hide file tree
Showing 19 changed files with 180 additions and 157 deletions.
20 changes: 10 additions & 10 deletions src/activity_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1770,7 +1770,7 @@ void activity_handlers::pulp_do_turn( player_activity *act, player *p )
p->practice( skill_survival, 2, 2 );
}

float stamina_ratio = static_cast<float>( p->stamina ) / p->get_stamina_max();
float stamina_ratio = static_cast<float>( p->get_stamina() ) / p->get_stamina_max();
moves += 100 / std::max( 0.25f, stamina_ratio );
if( stamina_ratio < 0.33 || p->is_npc() ) {
p->moves = std::min( 0, p->moves - moves );
Expand Down Expand Up @@ -2884,10 +2884,10 @@ void activity_handlers::read_do_turn( player_activity *act, player *p )
if( p->is_player() ) {
if( !act->str_values.empty() && act->str_values[0] == "martial_art" && one_in( 3 ) ) {
if( act->values.empty() ) {
act->values.push_back( p->stamina );
act->values.push_back( p->get_stamina() );
}
p->stamina = act->values[0] - 1;
act->values[0] = p->stamina;
p->set_stamina( act->values[0] - 1 );
act->values[0] = p->get_stamina();
}
} else {
p->moves = 0;
Expand Down Expand Up @@ -2979,10 +2979,10 @@ void activity_handlers::wait_stamina_do_turn( player_activity *act, player *p )
stamina_threshold = act->values[0];
// remember initial stamina, only for waiting-with-threshold
if( act->values.size() == 1 ) {
act->values.push_back( p->stamina );
act->values.push_back( p->get_stamina() );
}
}
if( p->stamina >= stamina_threshold ) {
if( p->get_stamina() >= stamina_threshold ) {
wait_stamina_finish( act, p );
}
}
Expand All @@ -2991,12 +2991,12 @@ void activity_handlers::wait_stamina_finish( player_activity *act, player *p )
{
if( !act->values.empty() ) {
const int stamina_threshold = act->values[0];
const int stamina_initial = ( act->values.size() > 1 ) ? act->values[1] : p->stamina;
if( p->stamina < stamina_threshold && p->stamina <= stamina_initial ) {
const int stamina_initial = ( act->values.size() > 1 ) ? act->values[1] : p->get_stamina();
if( p->get_stamina() < stamina_threshold && p->get_stamina() <= stamina_initial ) {
debugmsg( "Failed to wait until stamina threshold %d reached, only at %d. You may not be regaining stamina.",
act->values.front(), p->stamina );
act->values.front(), p->get_stamina() );
}
} else if( p->stamina < p->get_stamina_max() ) {
} else if( p->get_stamina() < p->get_stamina_max() ) {
p->add_msg_if_player( _( "You are bored of waiting, so you stop." ) );
} else {
p->add_msg_if_player( _( "You finish waiting and feel refreshed." ) );
Expand Down
2 changes: 1 addition & 1 deletion src/avatar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ bool avatar::read( int inventory_position, const bool continuous )
// push an indentifier of martial art book to the action handling
if( it.type->use_methods.count( "MA_MANUAL" ) ) {

if( g->u.stamina < g->u.get_stamina_max() / 10 ) {
if( g->u.get_stamina() < g->u.get_stamina_max() / 10 ) {
add_msg( m_info, _( "You are too exhausted to train martial arts." ) );
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion src/avatar_action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,7 @@ bool avatar_action::fire( avatar &you, map &m )
you.mod_stat( "stamina", gun->get_min_str() * static_cast<int>( 0.002f *
get_option<int>( "PLAYER_MAX_STAMINA" ) ) );
// At low stamina levels, firing starts getting slow.
int sta_percent = ( 100 * you.stamina ) / you.get_stamina_max();
int sta_percent = ( 100 * you.get_stamina() ) / you.get_stamina_max();
reload_time += ( sta_percent < 25 ) ? ( ( 25 - sta_percent ) * 2 ) : 0;

// Update targeting data to include ammo's range bonus
Expand Down
108 changes: 107 additions & 1 deletion src/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ static const bionic_id bio_armor_head( "bio_armor_head" );
static const bionic_id bio_armor_legs( "bio_armor_legs" );
static const bionic_id bio_armor_torso( "bio_armor_torso" );
static const bionic_id bio_carbon( "bio_carbon" );
static const bionic_id bio_gills( "bio_gills" );
static const bionic_id bio_laser( "bio_laser" );
static const bionic_id bio_lighter( "bio_lighter" );
static const bionic_id bio_tools( "bio_tools" );
Expand Down Expand Up @@ -120,6 +121,7 @@ const skill_id skill_throw( "throw" );

static const trait_id trait_ACIDBLOOD( "ACIDBLOOD" );
static const trait_id trait_ADRENALINE( "ADRENALINE" );
static const trait_id trait_BADBACK( "BADBACK" );
static const trait_id trait_BIRD_EYE( "BIRD_EYE" );
static const trait_id trait_CEPH_EYES( "CEPH_EYES" );
static const trait_id trait_CEPH_VISION( "CEPH_VISION" );
Expand Down Expand Up @@ -193,6 +195,7 @@ Character::Character() :
fatigue = 0;
sleep_deprivation = 0;
set_stim( 0 );
set_stamina( 10000 ); //Temporary value for stamina. It will be reset later from external json option.
pkill = 0;
// 45 days to starve to death
healthy_calories = 55000;
Expand Down Expand Up @@ -716,7 +719,7 @@ bool Character::is_limb_broken( hp_part limb ) const

bool Character::can_run()
{
return stamina > 0 && !has_effect( effect_winded ) && get_working_leg_count() >= 2;
return get_stamina() > 0 && !has_effect( effect_winded ) && get_working_leg_count() >= 2;
}

bool Character::move_effects( bool attacking )
Expand Down Expand Up @@ -4222,6 +4225,109 @@ void Character::mod_stim( int mod )
stim += mod;
}

int Character::get_stamina() const
{
return stamina;
}

int Character::get_stamina_max() const
{
int maxStamina = get_option< int >( "PLAYER_MAX_STAMINA" );
maxStamina *= Character::mutation_value( "max_stamina_modifier" );
return maxStamina;
}

void Character::set_stamina( int new_stamina )
{
stamina = new_stamina;
}

void Character::mod_stamina( int mod )
{
stamina += mod;
}

void Character::burn_move_stamina( int moves )
{
int overburden_percentage = 0;
units::mass current_weight = weight_carried();
units::mass max_weight = weight_capacity();
if( current_weight > max_weight ) {
overburden_percentage = ( current_weight - max_weight ) * 100 / max_weight;
}

int burn_ratio = get_option<int>( "PLAYER_BASE_STAMINA_BURN_RATE" );
for( const bionic_id &bid : get_bionic_fueled_with( item( "muscle" ) ) ) {
if( has_active_bionic( bid ) ) {
burn_ratio = burn_ratio * 2 - 3;
}
}
burn_ratio += overburden_percentage;
if( move_mode == CMM_RUN ) {
burn_ratio = burn_ratio * 7;
}
mod_stat( "stamina", -( ( moves * burn_ratio ) / 100.0 ) );
add_msg( m_debug, "Stamina burn: %d", -( ( moves * burn_ratio ) / 100 ) );
// Chance to suffer pain if overburden and stamina runs out or has trait BADBACK
// Starts at 1 in 25, goes down by 5 for every 50% more carried
if( ( current_weight > max_weight ) && ( has_trait( trait_BADBACK ) || get_stamina() == 0 ) &&
one_in( 35 - 5 * current_weight / ( max_weight / 2 ) ) ) {
add_msg_if_player( m_bad, _( "Your body strains under the weight!" ) );
// 1 more pain for every 800 grams more (5 per extra STR needed)
if( ( ( current_weight - max_weight ) / 800_gram > get_pain() && get_pain() < 100 ) ) {
mod_pain( 1 );
}
}
}

void Character::update_stamina( int turns )
{
const int current_stim = get_stim();
float stamina_recovery = 0.0f;
// Recover some stamina every turn.
// Mutated stamina works even when winded
float stamina_multiplier = ( !has_effect( effect_winded ) ? 1.0f : 0.1f ) +
mutation_value( "stamina_regen_modifier" );
// But mouth encumbrance interferes, even with mutated stamina.
stamina_recovery += stamina_multiplier * std::max( 1.0f,
get_option<float>( "PLAYER_BASE_STAMINA_REGEN_RATE" ) - ( encumb( bp_mouth ) / 5.0f ) );
// TODO: recovering stamina causes hunger/thirst/fatigue.
// TODO: Tiredness slowing recovery

// stim recovers stamina (or impairs recovery)
if( current_stim > 0 ) {
// TODO: Make stamina recovery with stims cost health
stamina_recovery += std::min( 5.0f, current_stim / 15.0f );
} else if( current_stim < 0 ) {
// Affect it less near 0 and more near full
// Negative stim kill at -200
// At -100 stim it inflicts -20 malus to regen at 100% stamina,
// effectivly countering stamina gain of default 20,
// at 50% stamina its -10 (50%), cuts by 25% at 25% stamina
stamina_recovery += current_stim / 5.0f * get_stamina() / get_stamina_max();
}

const int max_stam = get_stamina_max();
if( get_power_level() >= 3_kJ && has_active_bionic( bio_gills ) ) {
int bonus = std::min<int>( units::to_kilojoule( get_power_level() ) / 3,
max_stam - get_stamina() - stamina_recovery * turns );
// so the effective recovery is up to 5x default
bonus = std::min( bonus, 4 * static_cast<int>
( get_option<float>( "PLAYER_BASE_STAMINA_REGEN_RATE" ) ) );
if( bonus > 0 ) {
stamina_recovery += bonus;
bonus /= 10;
bonus = std::max( bonus, 1 );
mod_power_level( units::from_kilojoule( -bonus ) );
}
}

mod_stamina( roll_remainder( stamina_recovery * turns ) );
add_msg( m_debug, "Stamina recovery: %d", roll_remainder( stamina_recovery * turns ) );
// Cap at max
set_stamina( std::min( std::max( get_stamina(), 0 ), max_stam ) );
}

int Character::item_handling_cost( const item &it, bool penalties, int base_cost ) const
{
int mv = base_cost;
Expand Down
10 changes: 9 additions & 1 deletion src/character.h
Original file line number Diff line number Diff line change
Expand Up @@ -1092,7 +1092,6 @@ class Character : public Creature, public visitable<Character>
stomach_contents guts;

int oxygen;
int stamina;
int radiation;

std::shared_ptr<monster> mounted_creature;
Expand Down Expand Up @@ -1166,6 +1165,14 @@ class Character : public Creature, public visitable<Character>
void set_stim( int new_stim );
void mod_stim( int mod );

int get_stamina() const;
int get_stamina_max() const;
void set_stamina( int new_stamina );
void mod_stamina( int mod );
void burn_move_stamina( int moves );
/** Regenerates stamina */
void update_stamina( int turns );

protected:
void on_stat_change( const std::string &, int ) override {}
void on_damage_of_type( int adjusted_damage, damage_type type, body_part bp ) override;
Expand Down Expand Up @@ -1378,6 +1385,7 @@ class Character : public Creature, public visitable<Character>

int hunger;
int thirst;
int stamina;

int fatigue;
int sleep_deprivation;
Expand Down
4 changes: 2 additions & 2 deletions src/debug_menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -566,10 +566,10 @@ void character_edit_menu()
break;
case D_STAMINA:
int value;
if( query_int( value, _( "Set stamina to? Current: %d. Max: %d." ), p.stamina,
if( query_int( value, _( "Set stamina to? Current: %d. Max: %d." ), p.get_stamina(),
p.get_stamina_max() ) ) {
if( value >= 0 && value <= p.get_stamina_max() ) {
p.stamina = value;
p.set_stamina( value );
} else {
add_msg( m_bad, _( "Target stamina value out of bounds!" ) );
}
Expand Down
4 changes: 2 additions & 2 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,7 @@ bool game::start_game()

u.moves = 0;
u.process_turn(); // process_turn adds the initial move points
u.stamina = u.get_stamina_max();
u.set_stamina( u.get_stamina_max() );
weather.temperature = SPRING_TEMPERATURE;
weather.update_weather();
u.next_climate_control_check = calendar::before_time_starts; // Force recheck at startup
Expand Down Expand Up @@ -9974,7 +9974,7 @@ void game::on_move_effects()
if( !u.can_run() ) {
u.toggle_run_mode();
}
if( u.stamina < u.get_stamina_max() / 5 && one_in( u.stamina ) ) {
if( u.get_stamina() < u.get_stamina_max() / 5 && one_in( u.get_stamina() ) ) {
u.add_effect( effect_winded, 10_turns );
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/handle_action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,7 @@ static void wait()
}

} else {
if( g->u.stamina < g->u.get_stamina_max() ) {
if( g->u.get_stamina() < g->u.get_stamina_max() ) {
as_m.addentry( 12, true, 'w', _( "Wait until you catch your breath" ) );
durations.emplace( 12, 15_minutes ); // to hide it from showing
}
Expand Down
4 changes: 2 additions & 2 deletions src/iuse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5400,7 +5400,7 @@ int iuse::artifact( player *p, item *it, bool, const tripoint & )

case AEA_STAMINA_EMPTY:
p->add_msg_if_player( m_bad, _( "Your body feels like jelly." ) );
p->stamina = p->stamina * 1 / ( rng( 3, 8 ) );
p->set_stamina( p->get_stamina() * 1 / ( rng( 3, 8 ) ) );
break;

case AEA_FUN:
Expand Down Expand Up @@ -5744,7 +5744,7 @@ int iuse::stimpack( player *p, item *it, bool, const tripoint & )
p->mod_painkiller( 2 );
p->mod_stim( 20 );
p->mod_fatigue( -100 );
p->stamina = p->get_stamina_max();
p->set_stamina( p->get_stamina_max() );
}
return it->type->charges_to_use();
}
Expand Down
6 changes: 3 additions & 3 deletions src/magic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,7 @@ bool spell::can_cast( const player &p ) const
case mana_energy:
return p.magic.available_mana() >= energy_cost( p );
case stamina_energy:
return p.stamina >= energy_cost( p );
return p.get_stamina() >= energy_cost( p );
case hp_energy: {
for( int i = 0; i < num_hp_parts; i++ ) {
if( energy_cost( p ) < p.hp_cur[i] ) {
Expand Down Expand Up @@ -812,7 +812,7 @@ std::string spell::energy_cur_string( const player &p ) const
return colorize( to_string( p.magic.available_mana() ), c_light_blue );
}
if( energy_source() == stamina_energy ) {
auto pair = get_hp_bar( p.stamina, p.get_stamina_max() );
auto pair = get_hp_bar( p.get_stamina(), p.get_stamina_max() );
return colorize( pair.first, pair.second );
}
if( energy_source() == hp_energy ) {
Expand Down Expand Up @@ -1388,7 +1388,7 @@ bool known_magic::has_enough_energy( const player &p, spell &sp ) const
case bionic_energy:
return p.get_power_level() >= units::from_kilojoule( cost );
case stamina_energy:
return p.stamina >= cost;
return p.get_stamina() >= cost;
case hp_energy:
for( int i = 0; i < num_hp_parts; i++ ) {
if( p.hp_cur[i] > cost ) {
Expand Down
9 changes: 5 additions & 4 deletions src/melee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1405,7 +1405,7 @@ void player::perform_technique( const ma_technique &technique, Creature &t, dama
// Remember out moves and stamina
// We don't want to consume them for every attack!
const int temp_moves = moves;
const int temp_stamina = stamina;
const int temp_stamina = get_stamina();

std::vector<Creature *> targets;

Expand All @@ -1428,7 +1428,7 @@ void player::perform_technique( const ma_technique &technique, Creature &t, dama
t.add_msg_if_player( m_good, ngettext( "%d enemy hit!", "%d enemies hit!", count_hit ), count_hit );
// Extra attacks are free of charge (otherwise AoE attacks would SUCK)
moves = temp_moves;
stamina = temp_stamina;
set_stamina( temp_stamina );
}

//player has a very small chance, based on their intelligence, to learn a style whilst using the CQB bionic
Expand Down Expand Up @@ -1646,7 +1646,7 @@ bool player::block_hit( Creature *source, body_part &bp_hit, damage_instance &da
matec_id tec = pick_technique( *source, shield, false, false, true );

if( tec != tec_none && !is_dead_state() ) {
if( stamina < get_stamina_max() / 3 ) {
if( get_stamina() < get_stamina_max() / 3 ) {
add_msg( m_bad, _( "You try to counterattack but you are too exhausted!" ) );
} else {
melee_attack( *source, false, tec );
Expand Down Expand Up @@ -2114,7 +2114,8 @@ int player::attack_speed( const item &weap ) const
const int encumbrance_penalty = encumb( bp_torso ) +
( encumb( bp_hand_l ) + encumb( bp_hand_r ) ) / 2;
const int ma_move_cost = mabuff_attack_cost_penalty();
const float stamina_ratio = static_cast<float>( stamina ) / static_cast<float>( get_stamina_max() );
const float stamina_ratio = static_cast<float>( get_stamina() ) / static_cast<float>
( get_stamina_max() );
// Increase cost multiplier linearly from 1.0 to 2.0 as stamina goes from 25% to 0%.
const float stamina_penalty = 1.0 + std::max( ( 0.25f - stamina_ratio ) * 4.0f, 0.0f );
const float ma_mult = mabuff_attack_cost_mult();
Expand Down
Loading

0 comments on commit 8f0b78f

Please sign in to comment.