1 #pragma once
2 
3 #include <functional>
4 #include <vector>
5 
6 #include "enchant-type.h"
7 #include "mon-util.h"
8 #include "tag-version.h"
9 
10 using std::vector;
11 
12 #define SPECIAL_WEAPON_KEY "special_weapon_name"
13 #define CLOUD_IMMUNE_MB_KEY "cloud_immune"
14 
15 enum monster_info_flags
16 {
17     MB_STABBABLE,
18     MB_DISTRACTED,
19     MB_BERSERK,
20     MB_DORMANT,
21     MB_SLEEPING,
22     MB_UNAWARE,
23     MB_WANDERING,
24     MB_HASTED,
25     MB_STRONG,
26     MB_SLOWED,
27     MB_FLEEING,
28     MB_CONFUSED,
29     MB_INVISIBLE,
30     MB_POISONED,
31     MB_MORE_POISONED,
32     MB_MAX_POISONED,
33 #if TAG_MAJOR_VERSION == 34
34     MB_ROTTING,
35 #endif
36     MB_SUMMONED,
37     MB_HALOED,
38     MB_GLOWING,
39     MB_CHARMED,
40     MB_BURNING,
41     MB_PARALYSED,
42     MB_SICK,
43     MB_CAUGHT,
44     MB_WEBBED,
45 #if TAG_MAJOR_VERSION == 34
46     MB_OLD_FRENZIED,
47 #endif
48     MB_PETRIFYING,
49     MB_PETRIFIED,
50     MB_LOWERED_WL,
51     MB_POSSESSABLE,
52     MB_ENSLAVED,
53     MB_SWIFT,
54     MB_INSANE,
55     MB_SILENCING,
56     MB_MESMERIZING,
57 #if TAG_MAJOR_VERSION == 34
58     MB_EVIL_ATTACK,
59 #endif
60     MB_SHAPESHIFTER,
61     MB_CHAOTIC,
62     MB_SUBMERGED,
63 #if TAG_MAJOR_VERSION == 34
64     MB_BLEEDING,
65 #endif
66 #if TAG_MAJOR_VERSION == 34
67     MB_PREP_RESURRECT,
68 #endif
69     MB_REGENERATION,
70     MB_STRONG_WILLED,
71     MB_MIRROR_DAMAGE,
72     MB_SAFE,
73     MB_UNSAFE,
74     MB_NAME_SUFFIX, // [art] rat foo does...
75     MB_NAME_ADJECTIVE, // [art] foo rat does...
76     MB_NAME_REPLACE, // [art] foo does
77     MB_NAME_UNQUALIFIED, // Foo does...
78     MB_NAME_THE, // The foo does....
79 #if TAG_MAJOR_VERSION == 34
80     MB_FADING_AWAY,
81     MB_MOSTLY_FADED,
82 #endif
83     MB_FEAR_INSPIRING,
84 #if TAG_MAJOR_VERSION == 34
85     MB_WITHDRAWN,
86     MB_ATTACHED,
87 #endif
88     MB_DAZED,
89     MB_MUTE,
90     MB_BLIND,
91     MB_DUMB,
92     MB_MAD,
93 #if TAG_MAJOR_VERSION == 34
94     MB_CLINGING,
95 #endif
96     MB_NAME_ZOMBIE,
97     MB_PERM_SUMMON,
98     MB_INNER_FLAME,
99     MB_UMBRAED,
100 #if TAG_MAJOR_VERSION == 34
101     MB_OLD_ROUSED,
102 #endif
103     MB_BREATH_WEAPON,
104 #if TAG_MAJOR_VERSION == 34
105     MB_DEATHS_DOOR,
106 #endif
107     MB_FIREWOOD,
108     MB_TWO_WEAPONS,
109     MB_NO_REGEN,
110 #if TAG_MAJOR_VERSION == 34
111     MB_SUPPRESSED,
112 #endif
113     MB_ROLLING,
114     MB_RANGED_ATTACK,
115     MB_NO_NAME_TAG,
116 #if TAG_MAJOR_VERSION == 34
117     MB_MAGIC_ARMOUR,
118 #endif
119     MB_WRETCHED,
120     MB_SCREAMED,
121     MB_WORD_OF_RECALL,
122     MB_INJURY_BOND,
123     MB_WATER_HOLD,
124     MB_WATER_HOLD_DROWN,
125     MB_FLAYED,
126 #if TAG_MAJOR_VERSION == 34
127     MB_RETCHING,
128 #endif
129     MB_WEAK,
130     MB_DIMENSION_ANCHOR,
131 #if TAG_MAJOR_VERSION == 34
132     MB_CONTROL_WINDS,
133     MB_WIND_AIDED,
134     MB_SUMMONED_NO_STAIRS, // Temp. summoned and capped monsters
135 #endif
136     MB_SUMMONED_CAPPED,    // Expiring due to summons cap
137     MB_TOXIC_RADIANCE,
138     MB_GRASPING_ROOTS,
139     MB_FIRE_VULN,
140     MB_VORTEX,
141     MB_VORTEX_COOLDOWN,
142     MB_BARBS,
143     MB_POISON_VULN,
144     MB_ICEMAIL,
145     MB_AGILE,
146     MB_FROZEN,
147     MB_BLACK_MARK,
148     MB_SAP_MAGIC,
149     MB_SHROUD,
150     MB_CORROSION,
151     MB_SPECTRALISED,
152     MB_SLOW_MOVEMENT,
153     MB_LIGHTLY_DRAINED,
154     MB_HEAVILY_DRAINED,
155     MB_REPEL_MSL,
156 #if TAG_MAJOR_VERSION == 34
157     MB_NEGATIVE_VULN,
158     MB_CONDENSATION_SHIELD,
159 #endif
160     MB_RESISTANCE,
161     MB_HEXED,
162 #if TAG_MAJOR_VERSION == 34
163     MB_BONE_ARMOUR,
164     MB_CHANT_FIRE_STORM,
165     MB_CHANT_WORD_OF_ENTROPY,
166 #endif
167     MB_AIRBORNE,
168     MB_BRILLIANCE_AURA,
169     MB_EMPOWERED_SPELLS,
170     MB_READY_TO_HOWL,
171     MB_PARTIALLY_CHARGED,
172     MB_FULLY_CHARGED,
173     MB_GOZAG_INCITED,
174     MB_PAIN_BOND,
175     MB_IDEALISED,
176     MB_BOUND_SOUL,
177     MB_INFESTATION,
178     MB_NO_REWARD,
179     MB_STILL_WINDS,
180     MB_SLOWLY_DYING,
181 #if TAG_MAJOR_VERSION == 34
182     MB_PINNED,
183 #endif
184     MB_VILE_CLUTCH,
185     MB_WATERLOGGED,
186     MB_CLOUD_RING_THUNDER,
187     MB_CLOUD_RING_FLAMES,
188     MB_CLOUD_RING_CHAOS,
189     MB_CLOUD_RING_MUTATION,
190     MB_CLOUD_RING_FOG,
191     MB_CLOUD_RING_ICE,
192     MB_CLOUD_RING_DRAINING,
193     MB_CLOUD_RING_ACID,
194     MB_CLOUD_RING_MIASMA,
195     MB_WITHERING,
196     MB_CRUMBLING,
197     MB_ALLY_TARGET,
198     MB_CANT_DRAIN,
199     MB_CONCENTRATE_VENOM,
200     NUM_MB_FLAGS
201 };
202 
203 struct monster_info_base
204 {
205     coord_def pos;
206     FixedBitVector<NUM_MB_FLAGS> mb;
207     string mname;
208     monster_type type;
209     monster_type base_type;
210     union
211     {
212         // These must all be the same size!
213         unsigned number; ///< General purpose number variable
214         int num_heads;   ///< # of hydra heads
215         int slime_size;  ///< # of slimes in this one
216         int is_active;   ///< Whether this ballisto is active or not
217     };
218     int _colour;
219     mon_attitude_type attitude;
220     mon_threat_level_type threat;
221     mon_dam_level_type dam;
222     // TODO: maybe we should store the position instead
223     dungeon_feature_type fire_blocker;
224     string description;
225     string quote;
226     mon_holy_type holi;
227     mon_intel_type mintel;
228     int hd;
229     int ac;
230     int ev;
231     int base_ev;
232     int mr;
233     resists_t mresists;
234     bool can_see_invis;
235     mon_itemuse_type mitemuse;
236     int mbase_speed;
237     mon_energy_usage menergy;
238     CrawlHashTable props;
239     string constrictor_name;
240     vector<string> constricting_name;
241     monster_spells spells;
242     mon_attack_def attack[MAX_NUM_ATTACKS];
243     bool can_go_frenzy;
244     bool can_feel_fear;
245 
246     uint32_t client_id;
247 };
248 
249 // Monster info used by the pane; precomputes some data
250 // to help with sorting and rendering.
251 struct monster_info : public monster_info_base
252 {
253     static bool less_than(const monster_info& m1,
254                           const monster_info& m2, bool zombified = true,
255                           bool fullname = true);
256 
257     static bool less_than_wrapper(const monster_info& m1,
258                                   const monster_info& m2);
259 
260 #define MILEV_ALL 0
261 #define MILEV_SKIP_SAFE -1
262 #define MILEV_NAME -2
monster_infomonster_info263     monster_info() { client_id = 0; }
264     explicit monster_info(const monster* m, int level = MILEV_ALL);
265     explicit monster_info(monster_type p_type,
266                           monster_type p_base_type = MONS_NO_MONSTER);
267 
monster_infomonster_info268     monster_info(const monster_info& mi)
269     : monster_info_base(mi), i_ghost(mi.i_ghost)
270     {
271         for (unsigned i = 0; i <= MSLOT_LAST_VISIBLE_SLOT; ++i)
272         {
273             if (mi.inv[i])
274                 inv[i].reset(new item_def(*mi.inv[i]));
275         }
276     }
277 
278     monster_info& operator=(const monster_info& p)
279     {
280         if (this != &p)
281         {
282             this->~monster_info();
283             new (this) monster_info(p);
284         }
285         return *this;
286     }
287 
288     void to_string(int count, string& desc, int& desc_colour,
289                    bool fullname = true, const char *adjective = nullptr,
290                    bool verbose = true) const;
291 
292     /* only real equipment is visible, miscellany is for mimic items */
293     unique_ptr<item_def> inv[MSLOT_LAST_VISIBLE_SLOT + 1];
294 
295     struct
296     {
297         species_type species;
298         job_type job;
299         god_type religion;
300         skill_type best_skill;
301         short best_skill_rank;
302         short xl_rank;
303         short damage;
304         short ac;
305     } i_ghost;
306 
ismonster_info307     inline bool is(unsigned mbflag) const
308     {
309         return mb[mbflag];
310     }
311 
damage_descmonster_info312     inline string damage_desc() const
313     {
314         return get_damage_level_string(holi, dam);
315     }
316     string get_max_hp_desc() const;
317 
neutralmonster_info318     inline bool neutral() const
319     {
320         return attitude == ATT_NEUTRAL || attitude == ATT_GOOD_NEUTRAL || attitude == ATT_STRICT_NEUTRAL;
321     }
322 
323     string db_name() const;
324     bool has_proper_name() const;
325     string pluralised_name(bool fullname = true) const;
326     string common_name(description_level_type desc = DESC_PLAIN) const;
327     string proper_name(description_level_type desc = DESC_PLAIN) const;
328     string full_name(description_level_type desc = DESC_PLAIN) const;
329 
330     vector<string> attributes() const;
331 
332     const char *pronoun(pronoun_type variant) const;
333     bool pronoun_plurality() const;
334 
335     string wounds_description_sentence() const;
336     string wounds_description(bool colour = false) const;
337 
338     string constriction_description() const;
339 
340     monster_type draco_or_demonspawn_subspecies() const;
341 
intelmonster_info342     mon_intel_type intel() const
343     {
344         return mintel;
345     }
346 
resistsmonster_info347     resists_t resists() const
348     {
349         return mresists;
350     }
351 
itemusemonster_info352     mon_itemuse_type itemuse() const
353     {
354         return mitemuse;
355     }
356 
357     int randarts(artefact_prop_type ra_prop) const;
358     bool can_see_invisible() const;
359     bool nightvision() const;
360     int willpower() const;
361     int lighting_modifiers() const;
362 
base_speedmonster_info363     int base_speed() const
364     {
365         return mbase_speed;
366     }
367 
368     string speed_description() const;
369 
370     bool wields_two_weapons() const;
371     bool can_regenerate() const;
372     reach_type reach_range() const;
373 
374     size_type body_size() const;
375 
376     // These should be kept in sync with the actor equivalents
377     // (Maybe unify somehow?)
378     bool cannot_move() const;
379     bool airborne() const;
380     bool ground_level() const;
381 
is_namedmonster_info382     bool is_named() const
383     {
384         return !mname.empty() || mons_is_unique(type);
385     }
386 
is_actual_spellcastermonster_info387     bool is_actual_spellcaster() const
388     {
389         return props.exists("actual_spellcaster");
390     }
391 
is_priestmonster_info392     bool is_priest() const
393     {
394         return props.exists("priest");
395     }
396 
397     bool has_spells() const;
398     int spell_hd(spell_type spell = SPELL_NO_SPELL) const;
399     unsigned colour(bool base_colour = false) const;
400     void set_colour(int colour);
401 
402     bool has_trivial_ench(enchant_type ench) const;
403     bool debuffable() const;
404 
405 protected:
406     string _core_name() const;
407     string _base_name() const;
408     string _apply_adjusted_description(description_level_type desc, const string& s) const;
409 };
410 
411 // Colour should be between -1 and 15 inclusive!
412 bool set_monster_list_colour(string key, int colour);
413 void clear_monster_list_colours();
414 
415 void get_monster_info(vector<monster_info>& mons);
416 
417 void mons_to_string_pane(string& desc, int& desc_colour, bool fullname,
418                            const vector<monster_info>& mi, int start,
419                            int count);
420 void mons_conditions_string(string& desc, const vector<monster_info>& mi,
421                             int start, int count, bool equipment);
422