1 #pragma once
2 #ifndef CATA_SRC_MORALE_H
3 #define CATA_SRC_MORALE_H
4 
5 #include <algorithm>
6 #include <functional>
7 #include <iosfwd>
8 #include <map>
9 #include <vector>
10 
11 #include "calendar.h"
12 #include "morale_types.h"
13 #include "type_id.h"
14 
15 class JsonIn;
16 class JsonObject;
17 class JsonOut;
18 class item;
19 struct itype;
20 struct morale_mult;
21 
22 class player_morale
23 {
24     public:
25         player_morale();
26 
27         player_morale( player_morale && ) noexcept = default;
28         player_morale( const player_morale & ) = default;
29         player_morale &operator =( player_morale && ) = default;
30         player_morale &operator =( const player_morale & ) = default;
31 
32         /** Adds morale to existing or creates one */
33         void add( const morale_type &type, int bonus, int max_bonus = 0,
34                   const time_duration &duration = 6_minutes, const time_duration &decay_start = 3_minutes,
35                   bool capped = false, const itype *item_type = nullptr );
36         /** Sets the new level for the permanent morale, or creates one */
37         void set_permanent( const morale_type &type, int bonus, const itype *item_type = nullptr );
38         /** Returns bonus from specified morale */
39         int has( const morale_type &type, const itype *item_type = nullptr ) const;
40         /** Removes specified morale */
41         void remove( const morale_type &type, const itype *item_type = nullptr );
42         /** Clears up all morale points */
43         void clear();
44         /** Returns overall morale level */
45         int get_level() const;
46         /** Ticks down morale counters and removes them */
47         void decay( const time_duration &ticks = 1_turns );
48         /** Displays morale screen */
49         void display( int focus_eq, int pain_penalty, int fatigue_penalty );
50         /** Returns false whether morale is inconsistent with the argument.
51          *  Only permanent morale is checked */
52         bool consistent_with( const player_morale &morale ) const;
53 
54         /**calculates the percentage contribution for each morale point*/
55         void calculate_percentage();
56 
57         int get_total_positive_value() const;
58         int get_total_negative_value() const;
59 
60         /** Returns perceived pain. Only used in morale_test.cpp*/
61         int get_perceived_pain() const;
62 
63         void on_mutation_gain( const trait_id &mid );
64         void on_mutation_loss( const trait_id &mid );
65         void on_stat_change( const std::string &stat, int value );
66         void on_item_wear( const item &it );
67         void on_item_takeoff( const item &it );
68         void on_worn_item_transform( const item &old_it, const item &new_it );
69         void on_worn_item_washed( const item &it );
70         void on_effect_int_change( const efftype_id &eid, int intensity,
71                                    const bodypart_id &bp = bodypart_id( "bp_null" ) );
72 
73         void store( JsonOut &jsout ) const;
74         void load( const JsonObject &jsin );
75 
76     private:
77 
78         class morale_point
79         {
80             public:
81                 explicit morale_point(
82                     const morale_type &type = MORALE_NULL,
83                     const itype *item_type = nullptr,
84                     int bonus = 0,
85                     int max_bonus = 0,
86                     time_duration duration = 6_minutes,
87                     time_duration decay_start = 3_minutes,
88                     bool capped = false ) :
89 
type(type)90                     type( type ),
91                     item_type( item_type ),
92                     bonus( normalize_bonus( bonus, max_bonus, capped ) ),
93                     duration( std::max( duration, 0_turns ) ),
94                     decay_start( std::max( decay_start, 0_turns ) ),
95                     age( 0_turns ) {}
96 
97                 void deserialize( JsonIn &jsin );
98                 void serialize( JsonOut &json ) const;
99 
100                 std::string get_name() const;
101                 int get_net_bonus() const;
102                 int get_net_bonus( const morale_mult &mult ) const;
103                 bool is_expired() const;
104                 bool is_permanent() const;
105                 bool matches( const morale_type &_type, const itype *_item_type = nullptr ) const;
106                 bool matches( const morale_point &mp ) const;
107 
108                 void add( int new_bonus, int new_max_bonus, time_duration new_duration,
109                           time_duration new_decay_start, bool new_cap );
110                 void decay( const time_duration &ticks = 1_turns );
111                 /*
112                  *contribution should be between [0,100] (inclusive)
113                  */
114                 void set_percent_contribution( double contribution );
115                 double get_percent_contribution() const;
116             private:
117                 morale_type type;
118                 const itype *item_type;
119 
120                 int bonus = 0;
121                 time_duration duration = 0_turns;   // Zero duration == infinity
122                 time_duration decay_start = 0_turns;
123                 time_duration age = 0_turns;
124                 /**
125                  *this point's percent contribution to the total positive or total negative morale effect
126                  */
127                 double percent_contribution = 0;
128 
129                 /**
130                  * Returns either new_time or remaining time (which one is greater).
131                  * Only returns new time if same_sign is true
132                  */
133                 time_duration pick_time( const time_duration &current_time, const time_duration &new_time,
134                                          bool same_sign ) const;
135                 /**
136                  * Returns normalized bonus if either max_bonus != 0 or capped == true
137                  */
138                 int normalize_bonus( int bonus, int max_bonus, bool capped ) const;
139         };
140     protected:
141         morale_mult get_temper_mult() const;
142 
143         void set_prozac( bool new_took_prozac );
144         void set_prozac_bad( bool new_took_prozac_bad );
145         void set_stylish( bool new_stylish );
146         void set_worn( const item &it, bool worn );
147         void set_mutation( const trait_id &mid, bool active );
148         bool has_mutation( const trait_id &mid );
149         bool has_flag( const json_character_flag &flag );
150 
151         void remove_if( const std::function<bool( const morale_point & )> &func );
152         void remove_expired();
153         void invalidate();
154 
155         void update_stylish_bonus();
156         void update_squeamish_penalty();
157         void update_masochist_bonus();
158         void update_bodytemp_penalty( const time_duration &ticks );
159         void update_constrained_penalty();
160 
161     private:
162         std::vector<morale_point> points;
163 
164         struct body_part_data {
165             unsigned int covered;
166             unsigned int fancy;
167             unsigned int filthy;
168             int hot;
169             int cold;
170 
body_part_databody_part_data171             body_part_data() :
172                 covered( 0 ),
173                 fancy( 0 ),
174                 filthy( 0 ),
175                 hot( 0 ),
176                 cold( 0 ) {}
177         };
178         std::map<bodypart_id, body_part_data> body_parts;
179         body_part_data no_body_part;
180 
181         using mutation_handler = std::function<void ( player_morale * )>;
182         struct mutation_data {
183             public:
184                 mutation_data() = default;
mutation_datamutation_data185                 explicit mutation_data( const mutation_handler &on_gain_and_loss ) :
186                     on_gain( on_gain_and_loss ),
187                     on_loss( on_gain_and_loss ) {}
mutation_datamutation_data188                 mutation_data( const mutation_handler &on_gain, const mutation_handler &on_loss ) :
189                     on_gain( on_gain ),
190                     on_loss( on_loss ) {}
191                 void set_active( player_morale *sender, bool new_active );
192                 bool get_active() const;
193                 void clear();
194             private:
195                 mutation_handler on_gain;
196                 mutation_handler on_loss;
197                 bool active = false;
198         };
199         std::map<trait_id, mutation_data> mutations;
200 
201         std::map<itype_id, int> super_fancy_items;
202 
203         // Mutability is required for lazy initialization
204         mutable int level;
205         mutable bool level_is_valid;
206 
207         bool took_prozac;
208         bool took_prozac_bad;
209         bool stylish;
210         int perceived_pain;
211 };
212 
213 #endif // CATA_SRC_MORALE_H
214