summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/kills.h
blob: 812364e4a7772dad443bda5217fb166b0a844651 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/*
 *  File:       kills.h
 *  Summary:    Tracks monsters the player has killed.
 *  Written by: Darshan Shaligram
 */

#ifndef KILLS_H
#define KILLS_H

#include <vector>
#include <string>
#include <map>
#include <stdio.h>
#include "enum.h"

std::string apostrophise(const std::string &name);
std::string apostrophise_fixup(const std::string &sentence);

class monsters;
class reader;
class writer;

// Not intended for external use!
struct kill_monster_desc
{
    kill_monster_desc(const monsters *);
    kill_monster_desc() { }

    void save(writer&) const;
    void load(reader&);

    enum name_modifier
    {
        M_NORMAL, M_ZOMBIE, M_SKELETON, M_SIMULACRUM, M_SPECTRE,
        M_SHAPESHIFTER  // A shapeshifter pretending to be 'monnum'
    };

    int monnum;                 // Number of the beast
    name_modifier modifier;     // Nature of the beast

    struct less_than
    {
        bool operator () (const kill_monster_desc &m1,
                          const kill_monster_desc &m2) const
        {
            return (m1.monnum < m2.monnum
                    || (m1.monnum == m2.monnum && m1.modifier < m2.modifier));
        }
    };
};

#define PLACE_LIMIT 5   // How many unique kill places we're prepared to track
class kill_def
{
public:
    kill_def(const monsters *mon);
    kill_def() : kills(0), exp(0)
    {
        // This object just says to the world that it's uninitialised
    }

    void save(writer&) const;
    void load(reader&);

    void add_kill(const monsters *mon, unsigned short place);
    void add_place(unsigned short place, bool force = false);

    void merge(const kill_def &k, bool unique_monster);

    std::string info(const kill_monster_desc &md) const;
    std::string base_name(const kill_monster_desc &md) const;

    unsigned short kills;           // How many kills does the player have?
    int            exp;             // Experience gained for slaying the beast.
                                    // Only set *once*, even for shapeshifters.

    std::vector<unsigned short> places; // Places where we've killed the beast.
private:
    std::string append_places(const kill_monster_desc &md,
            const std::string &name) const;
};

// Ghosts and random Pandemonium demons.
class kill_ghost
{
public:
    kill_ghost(const monsters *mon);
    kill_ghost() { }

    void save(writer&) const;
    void load(reader&);

    std::string info() const;

    std::string ghost_name;
    int exp;
    unsigned short place;
};

// This is the structure that Lua sees.
struct kill_exp
{
    int nkills;
    int exp;
    std::string base_name;
    std::string desc;

    int monnum;       // Number of the beast
    int modifier;     // Nature of the beast

    std::vector<unsigned short> places;

    kill_exp(const kill_def &k, const kill_monster_desc &md)
        : nkills(k.kills), exp(k.exp), base_name(k.base_name(md)),
          desc(k.info(md)),
          monnum(md.monnum), modifier(md.modifier)
    {
        places = k.places;
    }

    kill_exp(const kill_ghost &kg)
        : nkills(1), exp(kg.exp), base_name(), desc(kg.info()),
          monnum(-1), modifier(0)
    {
        places.push_back(kg.place);
    }

    // operator< is implemented for a descending sort.
    bool operator < ( const kill_exp &b) const
    {
        return exp == b.exp? (base_name < b.base_name) : (exp > b.exp);
    }
};

class Kills
{
public:
    void record_kill(const monsters *mon);
    void merge(const Kills &k);

    bool empty() const;
    void save(writer&) const;
    void load(reader&);

    long get_kills(std::vector<kill_exp> &v) const;
    int num_kills(const monsters *mon) const;
private:
    typedef std::map<kill_monster_desc,
                     kill_def,
                     kill_monster_desc::less_than> kill_map;
    typedef std::vector<kill_ghost> ghost_vec;

    kill_map    kills;
    ghost_vec   ghosts;

    void record_ghost_kill(const monsters *mon);
};

class KillMaster
{
public:
    KillMaster();
    KillMaster(const KillMaster& other);
    ~KillMaster();

    void record_kill(const monsters *mon, int killer, bool ispet);

    bool empty() const;
    void save(writer&) const;
    void load(reader&);

    // Number of kills, by category.
    long num_kills(const monsters *mon, kill_category cat) const;
    // Number of kills, any category.
    long num_kills(const monsters *mon) const;

    long total_kills() const;

    std::string kill_info() const;
private:
    const char *category_name(kill_category kc) const;

    Kills categorized_kills[KC_NCATEGORIES];
private:
    void add_kill_info(std::string &, std::vector<kill_exp> &,
                       long count, const char *c, bool separator)
        const;
};

enum KILL_DUMP_OPTIONS
{
    KDO_NO_PLACES,          // Don't dump places at all
    KDO_ONE_PLACE,          // Show places only for single kills and uniques.
    KDO_ALL_PLACES          // Show all available place information
};

#endif