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

Encapsulate Stamina #34861

Merged
merged 15 commits into from
Oct 26, 2019
20 changes: 10 additions & 10 deletions src/activity_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1769,7 +1769,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 @@ -2854,10 +2854,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 @@ -2949,10 +2949,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 @@ -2961,12 +2961,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 @@ -5757,7 +5757,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 @@ -620,7 +620,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 @@ -811,7 +811,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 @@ -1385,7 +1385,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