Skip to content

Commit

Permalink
Move morale and related functions to Character
Browse files Browse the repository at this point in the history
  • Loading branch information
ifreund committed Oct 22, 2019
1 parent 920844e commit f0e1e1b
Show file tree
Hide file tree
Showing 7 changed files with 250 additions and 242 deletions.
177 changes: 177 additions & 0 deletions src/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "bionics.h"
#include "cata_utility.h"
#include "construction.h"
#include "coordinate_conversions.h"
#include "debug.h"
#include "effect.h"
#include "event_bus.h"
Expand All @@ -32,6 +33,8 @@
#include "messages.h"
#include "mission.h"
#include "monster.h"
#include "morale.h"
#include "morale_types.h"
#include "mtype.h"
#include "mutation.h"
#include "options.h"
Expand Down Expand Up @@ -107,6 +110,8 @@ const efftype_id effect_riding( "riding" );
const efftype_id effect_sleep( "sleep" );
const efftype_id effect_slept_through_alarm( "slept_through_alarm" );
const efftype_id effect_tied( "tied" );
const efftype_id effect_took_prozac( "took_prozac" );
const efftype_id effect_took_xanax( "took_xanax" );
const efftype_id effect_webbed( "webbed" );
const efftype_id effect_winded( "winded" );

Expand All @@ -129,13 +134,17 @@ static const trait_id trait_PROF_FOODP( "PROF_FOODP" );
static const trait_id trait_GILLS( "GILLS" );
static const trait_id trait_GILLS_CEPH( "GILLS_CEPH" );
static const trait_id trait_GLASSJAW( "GLASSJAW" );
static const trait_id trait_HOARDER( "HOARDER" );
static const trait_id trait_HOLLOW_BONES( "HOLLOW_BONES" );
static const trait_id trait_LIGHT_BONES( "LIGHT_BONES" );
static const trait_id trait_MEMBRANE( "MEMBRANE" );
static const trait_id trait_MYOPIC( "MYOPIC" );
static const trait_id trait_NIGHTVISION2( "NIGHTVISION2" );
static const trait_id trait_NIGHTVISION3( "NIGHTVISION3" );
static const trait_id trait_NIGHTVISION( "NIGHTVISION" );
static const trait_id trait_NOMAD( "NOMAD" );
static const trait_id trait_NOMAD2( "NOMAD2" );
static const trait_id trait_NOMAD3( "NOMAD3" );
static const trait_id trait_PACKMULE( "PACKMULE" );
static const trait_id trait_PER_SLIME_OK( "PER_SLIME_OK" );
static const trait_id trait_PER_SLIME( "PER_SLIME" );
Expand Down Expand Up @@ -3529,6 +3538,21 @@ bool Character::made_of_any( const std::set<material_id> &ms ) const
} );
}

tripoint Character::global_square_location() const
{
return g->m.getabs( position );
}

tripoint Character::global_sm_location() const
{
return ms_to_sm_copy( global_square_location() );
}

tripoint Character::global_omt_location() const
{
return ms_to_omt_copy( global_square_location() );
}

bool Character::is_blind() const
{
return ( worn_with_flag( "BLIND" ) ||
Expand Down Expand Up @@ -5132,6 +5156,159 @@ double Character::footwear_factor() const
return ret;
}

void Character::update_morale()
{
morale->decay( 1_minutes );
apply_persistent_morale();
}

void Character::apply_persistent_morale()
{
// Hoarders get a morale penalty if they're not carrying a full inventory.
if( has_trait( trait_HOARDER ) ) {
int pen = ( volume_capacity() - volume_carried() ) / 125_ml;
if( pen > 70 ) {
pen = 70;
}
if( pen <= 0 ) {
pen = 0;
}
if( has_effect( effect_took_xanax ) ) {
pen = pen / 7;
} else if( has_effect( effect_took_prozac ) ) {
pen = pen / 2;
}
if( pen > 0 ) {
add_morale( MORALE_PERM_HOARDER, -pen, -pen, 1_minutes, 1_minutes, true );
}
}
// Nomads get a morale penalty if they stay near the same overmap tiles too long.
if( has_trait( trait_NOMAD ) || has_trait( trait_NOMAD2 ) || has_trait( trait_NOMAD3 ) ) {
const tripoint ompos = global_omt_location();
float total_time = 0;
// Check how long we've stayed in any overmap tile within 5 of us.
const int max_dist = 5;
for( const tripoint &pos : points_in_radius( ompos, max_dist ) ) {
const float dist = rl_dist( ompos, pos );
if( dist > max_dist ) {
continue;
}
const auto iter = overmap_time.find( pos.xy() );
if( iter == overmap_time.end() ) {
continue;
}
// Count time in own tile fully, tiles one away as 4/5, tiles two away as 3/5, etc.
total_time += to_moves<float>( iter->second ) * ( max_dist - dist ) / max_dist;
}
// Characters with higher tiers of Nomad suffer worse morale penalties, faster.
int max_unhappiness;
float min_time, max_time;
if( has_trait( trait_NOMAD ) ) {
max_unhappiness = 20;
min_time = to_moves<float>( 12_hours );
max_time = to_moves<float>( 1_days );
} else if( has_trait( trait_NOMAD2 ) ) {
max_unhappiness = 40;
min_time = to_moves<float>( 4_hours );
max_time = to_moves<float>( 8_hours );
} else { // traid_NOMAD3
max_unhappiness = 60;
min_time = to_moves<float>( 1_hours );
max_time = to_moves<float>( 2_hours );
}
// The penalty starts at 1 at min_time and scales up to max_unhappiness at max_time.
const float t = ( total_time - min_time ) / ( max_time - min_time );
const int pen = ceil( lerp_clamped( 0, max_unhappiness, t ) );
if( pen > 0 ) {
add_morale( MORALE_PERM_NOMAD, -pen, -pen, 1_minutes, 1_minutes, true );
}
}

if( has_trait( trait_PROF_FOODP ) ) {
// Loosing your face is distressing
if( !( is_wearing( itype_id( "foodperson_mask" ) ) ||
is_wearing( itype_id( "foodperson_mask_on" ) ) ) ) {
add_morale( MORALE_PERM_NOFACE, -20, -20, 1_minutes, 1_minutes, true );
} else if( is_wearing( itype_id( "foodperson_mask" ) ) ||
is_wearing( itype_id( "foodperson_mask_on" ) ) ) {
rem_morale( MORALE_PERM_NOFACE );
}

if( is_wearing( itype_id( "foodperson_mask_on" ) ) ) {
add_morale( MORALE_PERM_FPMODE_ON, 10, 10, 1_minutes, 1_minutes, true );
} else {
rem_morale( MORALE_PERM_FPMODE_ON );
}
}
}

int Character::get_morale_level() const
{
return morale->get_level();
}

void Character::add_morale( const morale_type &type, int bonus, int max_bonus,
const time_duration &duration, const time_duration &decay_start,
bool capped, const itype *item_type )
{
morale->add( type, bonus, max_bonus, duration, decay_start, capped, item_type );
}

int Character::has_morale( const morale_type &type ) const
{
return morale->has( type );
}

void Character::rem_morale( const morale_type &type, const itype *item_type )
{
morale->remove( type, item_type );
}

void Character::clear_morale()
{
morale->clear();
}

bool Character::has_morale_to_read() const
{
return get_morale_level() >= -40;
}

void Character::check_and_recover_morale()
{
player_morale test_morale;

for( const auto &wit : worn ) {
test_morale.on_item_wear( wit );
}

for( const auto &mut : my_mutations ) {
test_morale.on_mutation_gain( mut.first );
}

for( auto &elem : *effects ) {
for( auto &_effect_it : elem.second ) {
const effect &e = _effect_it.second;
test_morale.on_effect_int_change( e.get_id(), e.get_intensity(), e.get_bp() );
}
}

test_morale.on_stat_change( "hunger", get_hunger() );
test_morale.on_stat_change( "thirst", get_thirst() );
test_morale.on_stat_change( "fatigue", get_fatigue() );
test_morale.on_stat_change( "pain", get_pain() );
test_morale.on_stat_change( "pkill", get_painkiller() );
test_morale.on_stat_change( "perceived_pain", get_perceived_pain() );

apply_persistent_morale();

if( !morale->consistent_with( test_morale ) ) {
*morale = player_morale( test_morale ); // Recover consistency
add_msg( m_debug, "%s morale was recovered.", disp_name( true ) );
}
}


void Character::start_hauling()
{
add_msg( _( "You start hauling items along the ground." ) );
Expand Down
45 changes: 45 additions & 0 deletions src/character.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class JsonOut;
class vehicle;
struct mutation_branch;
class bionic_collection;
class player_morale;
struct points_left;
class faction;
struct construction;
Expand Down Expand Up @@ -569,6 +570,21 @@ class Character : public Creature, public visitable<Character>
inline void setpos( const tripoint &p ) override {
position = p;
}

/**
* Global position, expressed in map square coordinate system
* (the most detailed coordinate system), used by the @ref map.
*/
virtual tripoint global_square_location() const;
/**
* Returns the location of the player in global submap coordinates.
*/
tripoint global_sm_location() const;
/**
* Returns the location of the player in global overmap terrain coordinates.
*/
tripoint global_omt_location() const;

private:
/** Retrieves a stat mod of a mutation. */
int get_mod( const trait_id &mut, const std::string &arg ) const;
Expand Down Expand Up @@ -1227,6 +1243,29 @@ class Character : public Creature, public visitable<Character>
double footwear_factor() const;
/** Returns true if the player is wearing something on their feet that is not SKINTIGHT */
bool is_wearing_shoes( const side &which_side = side::BOTH ) const;

/** Ticks down morale counters and removes them */
void update_morale();
/** Ensures persistent morale effects are up-to-date */
void apply_persistent_morale();
/** Used to apply morale modifications from food and medication **/
void modify_morale( item &food, int nutr = 0 );
int get_morale_level() const; // Modified by traits, &c
void add_morale( const morale_type &type, int bonus, int max_bonus = 0,
const time_duration &duration = 1_hours,
const time_duration &decay_start = 30_minutes, bool capped = false,
const itype *item_type = nullptr );
int has_morale( const morale_type &type ) const;
void rem_morale( const morale_type &type, const itype *item_type = nullptr );
void clear_morale();
bool has_morale_to_read() const;
bool has_morale_to_craft() const;
/** Checks permanent morale for consistency and recovers it when an inconsistency is found. */
void check_and_recover_morale();

/** Handles the enjoyability value for a comestible. First value is enjoyability, second is cap. **/
std::pair<int, int> fun_for( const item &comest ) const;

protected:
Character();
Character( Character && );
Expand Down Expand Up @@ -1315,6 +1354,8 @@ class Character : public Creature, public visitable<Character>
/** Current deficiency/excess quantity for each vitamin */
std::map<vitamin_id, int> vitamin_levels;

pimpl<player_morale> morale;

private:
// a cache of all active enchantment values.
// is recalculated every turn in Character::recalculate_enchantment_cache
Expand All @@ -1339,6 +1380,10 @@ class Character : public Creature, public visitable<Character>

int stim;
int pkill;

protected:
/** Amount of time the player has spent in each overmap tile. */
std::unordered_map<point, time_duration> overmap_time;
};

template<>
Expand Down
4 changes: 2 additions & 2 deletions src/consumption.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ int player::nutrition_for( const item &comest ) const
return kcal_for( comest ) / islot_comestible::kcal_per_nutr;
}

std::pair<int, int> player::fun_for( const item &comest ) const
std::pair<int, int> Character::fun_for( const item &comest ) const
{
static const trait_id trait_GOURMAND( "GOURMAND" );
static const trait_id trait_SAPROPHAGE( "SAPROPHAGE" );
Expand Down Expand Up @@ -1007,7 +1007,7 @@ void player::modify_addiction( const islot_comestible &comest )
}
}

void player::modify_morale( item &food, const int nutr )
void Character::modify_morale( item &food, const int nutr )
{
time_duration morale_time = 2_hours;
if( food.has_flag( "HOT" ) && food.has_flag( "EATEN_HOT" ) ) {
Expand Down
2 changes: 1 addition & 1 deletion src/crafting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ float player::crafting_speed_multiplier( const item &craft, const tripoint &loc
return total_multi;
}

bool player::has_morale_to_craft() const
bool Character::has_morale_to_craft() const
{
return get_morale_level() >= -50;
}
Expand Down
Loading

0 comments on commit f0e1e1b

Please sign in to comment.