1 /**
2  * @file
3  * @brief Tracks monsters the player has killed.
4 **/
5 
6 #pragma once
7 
8 #include <cstdio>
9 #include <map>
10 #include <string>
11 #include <vector>
12 
13 #include "enum.h"
14 
15 class monster;
16 struct monster_info;
17 class reader;
18 class writer;
19 
20 // Not intended for external use!
21 struct kill_monster_desc
22 {
23     kill_monster_desc(const monster*);
24     kill_monster_desc(const monster_info&);
kill_monster_desckill_monster_desc25     kill_monster_desc() { }
26 
27     void save(writer&) const;
28     void load(reader&);
29 
30     enum name_modifier
31     {
32         M_NORMAL, M_ZOMBIE, M_SKELETON, M_SIMULACRUM, M_SPECTRE,
33         M_SHAPESHIFTER, // A shapeshifter pretending to be 'monnum'
34     };
35 
36     monster_type monnum;        // Number of the beast
37     name_modifier modifier;     // Nature of the beast
38 
39     struct less_than
40     {
operatorkill_monster_desc::less_than41         bool operator () (const kill_monster_desc &m1,
42                           const kill_monster_desc &m2) const
43         {
44             return m1.monnum < m2.monnum
45                    || (m1.monnum == m2.monnum && m1.modifier < m2.modifier);
46         }
47     };
48 };
49 
50 #define PLACE_LIMIT 5   // How many unique kill places we're prepared to track
51 class kill_def
52 {
53 public:
54     kill_def(const monster* mon);
kill_def()55     kill_def() : kills(0), exp(0)
56     {
57         // This object just says to the world that it's uninitialised
58     }
59 
60     void save(writer&) const;
61     void load(reader&);
62 
63     void add_kill(const monster* mon, level_id place);
64     void add_place(level_id place, bool force = false);
65 
66     void merge(const kill_def &k, bool unique_monster);
67 
68     string info(const kill_monster_desc &md) const;
69     string base_name(const kill_monster_desc &md) const;
70 
71     unsigned short kills;    // How many kills does the player have?
72     int            exp;      // Experience gained for slaying the beast.
73                              // Only set *once*, even for shapeshifters.
74 
75     vector<level_id> places; // Places where we've killed the beast.
76 private:
77     string append_places(const kill_monster_desc &md, const string &name) const;
78 };
79 
80 // Ghosts and random Pandemonium demons.
81 class kill_ghost
82 {
83 public:
84     kill_ghost(const monster* mon);
kill_ghost()85     kill_ghost() { }
86 
87     void save(writer&) const;
88     void load(reader&);
89 
90     string info() const;
91 
92     string ghost_name;
93     int exp;
94     level_id place;
95 };
96 
97 // This is the structure that Lua sees.
98 struct kill_exp
99 {
100     int nkills;
101     int exp;
102     string base_name;
103     string desc;
104 
105     monster_type monnum; // Number of the beast
106     int modifier;        // Nature of the beast
107 
108     vector<level_id> places;
109 
kill_expkill_exp110     kill_exp(const kill_def &k, const kill_monster_desc &md)
111         : nkills(k.kills), exp(k.exp), base_name(k.base_name(md)),
112           desc(k.info(md)),
113           monnum(md.monnum), modifier(md.modifier), places(k.places)
114     {
115     }
116 
kill_expkill_exp117     kill_exp(const kill_ghost &kg)
118         : nkills(1), exp(kg.exp), base_name(), desc(kg.info()),
119           monnum(MONS_PROGRAM_BUG), modifier(0)
120     {
121         places.push_back(kg.place);
122     }
123 
124     // operator< is implemented for a descending sort.
125     bool operator < (const kill_exp &b) const
126     {
127         return exp == b.exp? (base_name < b.base_name) : (exp > b.exp);
128     }
129 };
130 
131 class Kills
132 {
133 public:
134     void record_kill(const monster* mon);
135     void merge(const Kills &k);
136 
137     bool empty() const;
138     void save(writer&) const;
139     void load(reader&);
140 
141     int get_kills(vector<kill_exp> &v) const;
142     int num_kills(const monster* mon) const;
143     int num_kills(const monster_info& mon) const;
144 private:
145     int num_kills(kill_monster_desc desc) const;
146 
147     typedef map<kill_monster_desc, kill_def,
148                 kill_monster_desc::less_than> kill_map;
149     typedef vector<kill_ghost> ghost_vec;
150 
151     kill_map    kills;
152     ghost_vec   ghosts;
153 
154     void record_ghost_kill(const monster* mon);
155 };
156 
157 class KillMaster
158 {
159 public:
160     void record_kill(const monster* mon, int killer, bool ispet);
161 
162     bool empty() const;
163     void save(writer&) const;
164     void load(reader&);
165 
166     // Number of kills, by category.
167     int num_kills(const monster* mon, kill_category cat) const;
168     int num_kills(const monster_info& mon, kill_category cat) const;
169     // Number of kills, any category.
170     int num_kills(const monster* mon) const;
171     int num_kills(const monster_info& mon) const;
172 
173     int total_kills() const;
174 
175     string kill_info() const;
176 private:
177     const char *category_name(kill_category kc) const;
178 
179     Kills categorized_kills[KC_NCATEGORIES];
180 private:
181     void add_kill_info(string &, vector<kill_exp> &,
182                        int count, const char *c, bool separator) const;
183 };
184 
185 enum KILL_DUMP_OPTIONS
186 {
187     KDO_NO_PLACES,          // Don't dump places at all
188     KDO_ONE_PLACE,          // Show places only for single kills and uniques.
189     KDO_ALL_PLACES,         // Show all available place information
190 };
191