1 /**
2  * @file
3  * @brief Misc functions.
4 **/
5 
6 #include "AppHdr.h"
7 
8 #include "item-prop.h"
9 
10 #include <algorithm>
11 #include <cctype>
12 #include <cstdio>
13 #include <cstdlib>
14 #include <cstring>
15 
16 #include "artefact.h"
17 #include "art-enum.h"
18 #include "describe.h"
19 #include "god-passive.h"
20 #include "invent.h"
21 #include "items.h"
22 #include "item-status-flag-type.h"
23 #include "item-use.h"
24 #include "libutil.h" // map_find
25 #include "message.h"
26 #include "notes.h"
27 #include "orb-type.h"
28 #include "potion-type.h"
29 #include "random.h"
30 #include "religion.h"
31 #include "shopping.h"
32 #include "skills.h"
33 #include "spl-wpnench.h"
34 #include "stringutil.h"
35 #include "tag-version.h"
36 #include "terrain.h"
37 #include "xom.h"
38 #include "xp-evoker-data.h"
39 
40 static iflags_t _full_ident_mask(const item_def& item);
41 
42 // XXX: Name strings in most of the following are currently unused!
43 struct armour_def
44 {
45     /// The armour_type enum of this armour type.
46     armour_type         id;
47     /// The name of the armour. (E.g. "robe".)
48     const char         *name;
49     /// The base AC value provided by the armour, before skill & enchant.
50     int                 ac;
51     /// The base EV penalty of the armour; used for EV, stealth, spell %, &c.
52     int                 ev;
53     /// The base price of the item in shops.
54     int                 price;
55 
56     /// The slot the armour is equipped into; e.g. EQ_BOOTS.
57     equipment_type      slot;
58     /// The smallest size creature the armour will fit.
59     size_type           fit_min;
60     /// The largest size creature the armour will fit.
61     size_type           fit_max;
62     /// Whether this armour is mundane or inherently 'special', for acq.
63     bool                mundane; // (special armour doesn't need egos etc)
64     /// The resists, vulns, &c that this armour type gives when worn.
65     armflags_t          flags;
66     /// Used in body armour 'acquirement' code; higher = generated more.
67     int                 acquire_weight;
68 };
69 
70 // would be nice to lookup the name from monster_for_armour, but that
71 // leads to static initialization races (plus 'gold' special case)
72 #if TAG_MAJOR_VERSION == 34
73 #define DRAGON_ARMOUR(id, name, ac, evp, prc, res)                          \
74     { ARM_ ## id ## _DRAGON_HIDE, "removed " name " dragon hide", 0, 0, 0,  \
75       EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT, false, res, 0 },             \
76     { ARM_ ## id ## _DRAGON_ARMOUR, name " dragon scales",  ac, evp, prc,   \
77       EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT, false, res, 25 }
78 #else
79 #define DRAGON_ARMOUR(id, name, ac, evp, prc, res)                          \
80     { ARM_ ## id ## _DRAGON_ARMOUR, name " dragon scales",  ac, evp, prc,   \
81       EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT, false, res, 25 }
82 #endif
83 
84 // Note: the Little-Giant range is used to make armours which are very
85 // flexible and adjustable and can be worn by any player character...
86 // providing they also pass the shape test, of course.
87 static int Armour_index[NUM_ARMOURS];
88 static const armour_def Armour_prop[] =
89 {
90     { ARM_ANIMAL_SKIN,          "animal skin",            2,   0,     3,
91         EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT, true, ARMF_NO_FLAGS, 333 },
92     { ARM_ROBE,                 "robe",                   2,   0,     7,
93         EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_BIG, true, ARMF_NO_FLAGS, 1000 },
94     { ARM_LEATHER_ARMOUR,       "leather armour",         3,  -40,   20,
95         EQ_BODY_ARMOUR, SIZE_SMALL,  SIZE_MEDIUM, true },
96 
97     { ARM_RING_MAIL,            "ring mail",              5,  -70,   40,
98         EQ_BODY_ARMOUR, SIZE_SMALL,  SIZE_MEDIUM, true, ARMF_NO_FLAGS, 1000 },
99     { ARM_SCALE_MAIL,           "scale mail",             6, -100,   40,
100         EQ_BODY_ARMOUR, SIZE_SMALL,  SIZE_MEDIUM, true, ARMF_NO_FLAGS, 1000 },
101     { ARM_CHAIN_MAIL,           "chain mail",             8, -150,   45,
102         EQ_BODY_ARMOUR, SIZE_SMALL,  SIZE_MEDIUM, true, ARMF_NO_FLAGS, 1000 },
103     { ARM_PLATE_ARMOUR,         "plate armour",          10, -180,   230,
104         EQ_BODY_ARMOUR, SIZE_SMALL, SIZE_MEDIUM, true, ARMF_NO_FLAGS, 1000 },
105     { ARM_CRYSTAL_PLATE_ARMOUR, "crystal plate armour",  14, -230,   800,
106         EQ_BODY_ARMOUR, SIZE_SMALL, SIZE_MEDIUM, false, ARMF_NO_FLAGS, 500 },
107 
108 #if TAG_MAJOR_VERSION == 34
109     { ARM_TROLL_HIDE, "removed troll hide",              0,    0,      0,
110        EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT, false, ARMF_REGENERATION, 0 },
111 #endif
112     { ARM_TROLL_LEATHER_ARMOUR, "troll leather armour",  4,  -40,    150,
113        EQ_BODY_ARMOUR, SIZE_LITTLE, SIZE_GIANT, false, ARMF_REGENERATION, 50 },
114 
115     { ARM_CLOAK,                "cloak",                  1,   0,   45,
116         EQ_CLOAK,       SIZE_LITTLE, SIZE_BIG, true },
117     { ARM_SCARF,                "scarf",                  0,   0,   50,
118         EQ_CLOAK,       SIZE_LITTLE, SIZE_BIG, true },
119 
120     { ARM_GLOVES,               "gloves",                 1,   0,   45,
121         EQ_GLOVES,      SIZE_SMALL,  SIZE_MEDIUM, true },
122 
123     { ARM_HELMET,               "helmet",                 1,   0,   45,
124         EQ_HELMET,      SIZE_SMALL,  SIZE_MEDIUM, true },
125 
126 #if TAG_MAJOR_VERSION == 34
127     { ARM_CAP,                  "cap",                    0,   0,   45,
128         EQ_HELMET,      SIZE_LITTLE, SIZE_LARGE, true },
129 #endif
130 
131     { ARM_HAT,                  "hat",                    0,   0,   40,
132         EQ_HELMET,      SIZE_TINY, SIZE_LARGE, true },
133 
134     // Note that barding size is compared against torso so it currently
135     // needs to fit medium, but that doesn't matter as much as race
136     // and shapeshift status.
137     { ARM_BOOTS,                "boots",                  1,   0,   45,
138         EQ_BOOTS,       SIZE_SMALL,  SIZE_MEDIUM, true },
139     // Changed max. barding size to large to allow for the appropriate
140     // monster types (monsters don't differentiate between torso and general).
141 #if TAG_MAJOR_VERSION == 34
142     { ARM_CENTAUR_BARDING,      "centaur barding",        4,  -60,  230,
143         EQ_BOOTS,       SIZE_MEDIUM, SIZE_LARGE, true },
144 #endif
145     { ARM_BARDING,         "barding",           4,  -60,  230,
146         EQ_BOOTS,       SIZE_MEDIUM, SIZE_LARGE, true },
147 
148     // Note: shields use ac-value as sh-value, EV pen is used as the basis
149     // to calculate adjusted shield penalty.
150     { ARM_BUCKLER,              "buckler",                3,  -8,   45,
151         EQ_SHIELD,      SIZE_LITTLE, SIZE_MEDIUM, true },
152     { ARM_KITE_SHIELD,               "kite shield",                 8,  -30,  45,
153         EQ_SHIELD,      SIZE_SMALL,  SIZE_BIG, true    },
154     { ARM_TOWER_SHIELD,         "tower shield",          13,  -50,  45,
155         EQ_SHIELD,      SIZE_MEDIUM, SIZE_GIANT, true  },
156 
157     // Following all ARM_ entries for the benefit of util/gather_items
158     DRAGON_ARMOUR(STEAM,       "steam",                   5,   0,   400,
159         ARMF_RES_STEAM),
160     DRAGON_ARMOUR(ACID,        "acid",                    6,  -50,  400,
161         ARMF_RES_CORR),
162     DRAGON_ARMOUR(QUICKSILVER, "quicksilver",             9,  -70,  600,
163         ARMF_WILLPOWER),
164     DRAGON_ARMOUR(SWAMP,       "swamp",                   7,  -70,  500,
165         ARMF_RES_POISON),
166     DRAGON_ARMOUR(FIRE,        "fire",                    8, -110,  600,
167         ard(ARMF_RES_FIRE, 2) | ARMF_VUL_COLD),
168     DRAGON_ARMOUR(ICE,         "ice",                     9, -110,  600,
169         ard(ARMF_RES_COLD, 2) | ARMF_VUL_FIRE),
170     DRAGON_ARMOUR(PEARL,       "pearl",                  10, -110, 1000,
171         ARMF_RES_NEG),
172     DRAGON_ARMOUR(STORM,       "storm",                  10, -150,  800,
173         ARMF_RES_ELEC),
174     DRAGON_ARMOUR(SHADOW,      "shadow",                 10, -150,  800,
175         ard(ARMF_STEALTH, 4)),
176     DRAGON_ARMOUR(GOLD,        "gold",                   12, -230,  800,
177         ARMF_RES_FIRE | ARMF_RES_COLD | ARMF_RES_POISON),
178 
179 #undef DRAGON_ARMOUR
180 };
181 
182 typedef pair<brand_type, int> brand_weight_tuple;
183 
184 /// The standard properties for a given weapon type. (E.g. falchions)
185 struct weapon_def
186 {
187     /// The weapon_type enum for this weapon type.
188     int                 id;
189     /// The name of this weapon type. (E.g. "club".)
190     const char         *name;
191     /// The base damage of the weapon. (Later multiplied by skill, etc)
192     int                 dam;
193     /// The base to-hit bonus of the weapon.
194     int                 hit;
195     /// The number of aut it takes to swing the weapon with 0 skill.
196     int                 speed;
197 
198     /// The weapon skill corresponding to this weapon's use.
199     skill_type          skill;
200     /// The size of the smallest creature that can wield the weapon.
201     size_type           min_2h_size;
202     /// The smallest creature that can wield the weapon one-handed.
203     size_type           min_1h_size;
204     /// The ammo fired by the weapon; MI_NONE for non-launchers.
205     missile_type        ammo;
206 
207     /// A union of vorpal_damage_type flags (slash, crush, etc)
208     int                 dam_type;
209     /// Used in *some* item generation code; higher = generated more often.
210     int                 commonness;
211     /// Used in *some* item 'acquirement' code; higher = generated more.
212     int                 acquire_weight;
213     /// Base pricing for shops, before egos, enchantment, etc.
214     int                 price;
215     /// Used in non-artefact ego item generation. If empty, default to NORMAL.
216     vector<brand_weight_tuple> brand_weights;
217 };
218 
219 /**
220   * "Why do we have all these ridiculous brand tables?"
221 
222   1) The main purpose of weapon brand distribution varying across weapon type
223      is to help to balance the different weapon skills against each other -
224      staves and short blades getting better brands as partial compensation for
225      their other drawbacks, for instance. It is true that we have other knobs
226      that we also use to balance different weapon types, but they don't all
227      affect things in the same way. For instance, lajatangs having very good
228      brands on average partially compensates for the rarity of good staves in a
229      different way from how raising their base damage would - it means that
230      finding a really great staff is of more comparable rarity to finding a
231      really great axe. (This is important because finding a really great weapon
232      like a lajatang of speed or elec or pain is one of the ways that players
233      decide to use a weapon type in the first place.) Having this knob isn't
234      redundant with having base damage and delay to modify - it is similar to
235      being able to adjust the rarity of different base types of weapons.
236 
237  2)  The secondary purpose of varying weapon brand distribution is to give
238      different weapon skills more individual feel. For instance, if you play a
239      lot of maces chars in a row, then you will get used to using a lot of
240      protection weapons and you'll never see vamp except on rare randarts, and
241      then when you switch to axes for a few games you'll actually find vamp
242      axes with some regularity and use them and be excited about that.
243 
244      This isn't a particularly strong effect with the current distributions -
245      among the four "normal" weapon skills (axes/maces/polearms/longblades),
246      only the m&f distribution is particularly distinctive. But it is
247      definitely a noticeable effect if you play 5 non-maces games in a row and
248      follow up with 5 maces games, and it contributes to making maces feel more
249      distinct.
250 
251      They could probably be simplified to a certain extent (only one set of
252      brands per weapon skill, for example), but there is a reason not to
253      simplify them down to just one table.
254  */
255 
256 /// brand weights for non-dagger shortblades (short sword & rapier)
257 static const vector<brand_weight_tuple> SBL_BRANDS = {
258     { SPWPN_NORMAL, 33 },
259     { SPWPN_VENOM, 17 },
260     { SPWPN_SPEED, 10 },
261     { SPWPN_DRAINING, 9 },
262     { SPWPN_PROTECTION, 6 },
263     { SPWPN_ELECTROCUTION, 6 },
264     { SPWPN_HOLY_WRATH, 5 },
265     { SPWPN_VAMPIRISM, 4 },
266     { SPWPN_FLAMING, 4 },
267     { SPWPN_FREEZING, 4 },
268     { SPWPN_DISTORTION, 1 },
269     { SPWPN_ANTIMAGIC, 1 },
270 };
271 
272 /// brand weights for most m&f weapons
273 static const vector<brand_weight_tuple> M_AND_F_BRANDS = {
274     { SPWPN_PROTECTION,     30 },
275     { SPWPN_NORMAL,         28 },
276     { SPWPN_HOLY_WRATH,     15 },
277     { SPWPN_VORPAL,         14 },
278     { SPWPN_DRAINING,       10 },
279     { SPWPN_VENOM,           5 },
280     { SPWPN_DISTORTION,      1 },
281     { SPWPN_ANTIMAGIC,       1 },
282     { SPWPN_PAIN,            1 },
283 };
284 
285 /// brand weights for club-type weapons
286 static const vector<brand_weight_tuple> CLUB_BRANDS = {
287     { SPWPN_NORMAL,          9 },
288     { SPWPN_SPECTRAL,        1 },
289 };
290 
291 /// brand weights for demon weapons (whip, blade, trident)
292 static const vector<brand_weight_tuple> DEMON_BRANDS = {
293     { SPWPN_NORMAL,         27 },
294     { SPWPN_VENOM,          19 },
295     { SPWPN_ELECTROCUTION,  16 },
296     { SPWPN_DRAINING,       10 },
297     { SPWPN_FLAMING,         7 },
298     { SPWPN_FREEZING,        7 },
299     { SPWPN_VAMPIRISM,       7 },
300     { SPWPN_PAIN,            4 },
301     { SPWPN_ANTIMAGIC,       3 },
302 };
303 
304 /// brand weights for long blades.
305 static const vector<brand_weight_tuple> LBL_BRANDS = {
306     { SPWPN_HOLY_WRATH,     23 },
307     { SPWPN_NORMAL,         19 },
308     { SPWPN_VORPAL,         15 },
309     { SPWPN_ELECTROCUTION,  10 },
310     { SPWPN_PROTECTION,      8 },
311     { SPWPN_FREEZING,        5 },
312     { SPWPN_FLAMING,         5 },
313     { SPWPN_DRAINING,        5 },
314     { SPWPN_VAMPIRISM,       4 },
315     { SPWPN_VENOM,           2 },
316     { SPWPN_DISTORTION,      2 },
317     { SPWPN_PAIN,            1 },
318     { SPWPN_ANTIMAGIC,       1 },
319 };
320 
321 /// brand weights for axes.
322 static const vector<brand_weight_tuple> AXE_BRANDS = {
323     { SPWPN_NORMAL,         31 },
324     { SPWPN_VORPAL,         16 },
325     { SPWPN_ELECTROCUTION,  11 },
326     { SPWPN_FLAMING,        10 },
327     { SPWPN_FREEZING,       10 },
328     { SPWPN_VENOM,           8 },
329     { SPWPN_VAMPIRISM,       5 },
330     { SPWPN_DRAINING,        3 },
331     { SPWPN_DISTORTION,      2 },
332     { SPWPN_ANTIMAGIC,       2 },
333     { SPWPN_PAIN,            1 },
334     { SPWPN_HOLY_WRATH,      1 },
335 };
336 
337 /// brand weights for most polearms.
338 static const vector<brand_weight_tuple> POLEARM_BRANDS = {
339     { SPWPN_NORMAL,     36 },
340     { SPWPN_VENOM,      17 },
341     { SPWPN_PROTECTION, 12 },
342     { SPWPN_VORPAL,      9 },
343     { SPWPN_FLAMING,     7 },
344     { SPWPN_FREEZING,    7 },
345     { SPWPN_VAMPIRISM,   5 },
346     { SPWPN_DISTORTION,  2 },
347     { SPWPN_PAIN,        2 },
348     { SPWPN_ANTIMAGIC,   2 },
349     { SPWPN_HOLY_WRATH,  1 },
350 };
351 
352 /// brand weights for most ranged weapons.
353 static const vector<brand_weight_tuple> RANGED_BRANDS = {
354     { SPWPN_NORMAL,   58 },
355     { SPWPN_FLAMING,  16 },
356     { SPWPN_FREEZING, 16 },
357     { SPWPN_VORPAL,   10 },
358 };
359 
360 /// brand weights for holy (TSO-blessed) weapons.
361 static const vector<brand_weight_tuple> HOLY_BRANDS = {
362     { SPWPN_HOLY_WRATH, 100 },
363 };
364 
365 
366 static int Weapon_index[NUM_WEAPONS];
367 static const weapon_def Weapon_prop[] =
368 {
369     // Maces & Flails
370     { WPN_CLUB,              "club",                5,  3, 13,
371         SK_MACES_FLAILS, SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
372         DAMV_CRUSHING, 10, 0, 10, CLUB_BRANDS },
373 #if TAG_MAJOR_VERSION == 34
374     { WPN_SPIKED_FLAIL,      "spiked flail",        5,  3, 13,
375         SK_MACES_FLAILS, SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
376         DAMV_CRUSHING, 0, 0, 0, {} },
377 #endif
378     { WPN_WHIP,              "whip",                6,  2, 11,
379         SK_MACES_FLAILS, SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
380         DAMV_SLASHING, 4, 0, 25, {
381             { SPWPN_NORMAL,        34 },
382             { SPWPN_VENOM,         16 },
383             { SPWPN_ELECTROCUTION, 16 },
384             { SPWPN_DRAINING,       7 },
385             { SPWPN_FREEZING,       6 },
386             { SPWPN_FLAMING,        6 },
387             { SPWPN_VAMPIRISM,      5 },
388             { SPWPN_PAIN,           4 },
389             { SPWPN_HOLY_WRATH,     3 },
390             { SPWPN_DISTORTION,     2 },
391             { SPWPN_ANTIMAGIC,      1 },
392         }},
393 #if TAG_MAJOR_VERSION == 34
394     { WPN_HAMMER,            "hammer",              7,  3, 13,
395         SK_MACES_FLAILS, SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
396         DAMV_CRUSHING, 0, 0, 0, M_AND_F_BRANDS },
397 #endif
398     { WPN_MACE,              "mace",                8,  3, 14,
399         SK_MACES_FLAILS, SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
400         DAMV_CRUSHING, 9, 10, 30, M_AND_F_BRANDS },
401     { WPN_FLAIL,             "flail",              10,  0, 14,
402         SK_MACES_FLAILS, SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
403         DAMV_CRUSHING, 8, 10, 35, M_AND_F_BRANDS },
404     { WPN_MORNINGSTAR,       "morningstar",        13, -2, 15,
405         SK_MACES_FLAILS, SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
406         DAMV_CRUSHING | DAM_PIERCE, 7, 10, 40, {
407             { SPWPN_PROTECTION,     30 },
408             { SPWPN_NORMAL,         15 },
409             { SPWPN_HOLY_WRATH,     15 },
410             { SPWPN_DRAINING,       10 },
411             { SPWPN_VORPAL,          9 },
412             { SPWPN_VENOM,           5 },
413             { SPWPN_FLAMING,         4 },
414             { SPWPN_FREEZING,        4 },
415             { SPWPN_DISTORTION,      2 },
416             { SPWPN_ANTIMAGIC,       2 },
417             { SPWPN_PAIN,            2 },
418             { SPWPN_VAMPIRISM,       2 },
419         }},
420     { WPN_DEMON_WHIP,        "demon whip",         11,  1, 11,
421         SK_MACES_FLAILS, SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
422         DAMV_SLASHING, 0, 2, 150, DEMON_BRANDS },
423     { WPN_SACRED_SCOURGE,    "sacred scourge",     12,  0, 11,
424         SK_MACES_FLAILS, SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
425         DAMV_SLASHING, 0, 0, 200, HOLY_BRANDS },
426     { WPN_DIRE_FLAIL,        "dire flail",         13, -3, 13,
427         SK_MACES_FLAILS, SIZE_MEDIUM, NUM_SIZE_LEVELS, MI_NONE,
428         DAMV_CRUSHING | DAM_PIERCE, 2, 10, 40, M_AND_F_BRANDS },
429     { WPN_EVENINGSTAR,       "eveningstar",        15, -1, 15,
430         SK_MACES_FLAILS, SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
431         DAMV_CRUSHING | DAM_PIERCE, 0, 2, 150, {
432             { SPWPN_PROTECTION,     30 },
433             { SPWPN_DRAINING,       19 },
434             { SPWPN_HOLY_WRATH,     15 },
435             { SPWPN_NORMAL,          8 },
436             { SPWPN_VORPAL,          6 },
437             { SPWPN_VENOM,           6 },
438             { SPWPN_FLAMING,         6 },
439             { SPWPN_FREEZING,        6 },
440             { SPWPN_DISTORTION,      2 },
441             { SPWPN_ANTIMAGIC,       2 },
442             { SPWPN_PAIN,            2 },
443             { SPWPN_VAMPIRISM,       2 },
444         }},
445     { WPN_GREAT_MACE,        "great mace",         17, -4, 17,
446         SK_MACES_FLAILS, SIZE_MEDIUM, NUM_SIZE_LEVELS, MI_NONE,
447         DAMV_CRUSHING, 3, 10, 65, M_AND_F_BRANDS },
448     { WPN_GIANT_CLUB,        "giant club",         20, -6, 16,
449         SK_MACES_FLAILS, SIZE_LARGE, NUM_SIZE_LEVELS, MI_NONE,
450         DAMV_CRUSHING, 1, 10, 17, CLUB_BRANDS },
451     { WPN_GIANT_SPIKED_CLUB, "giant spiked club",  22, -7, 18,
452         SK_MACES_FLAILS, SIZE_LARGE, NUM_SIZE_LEVELS, MI_NONE,
453         DAMV_CRUSHING | DAM_PIERCE, 1, 10, 19, CLUB_BRANDS },
454 
455     // Short Blades
456     { WPN_DAGGER,            "dagger",              4,  6, 10,
457         SK_SHORT_BLADES, SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
458         DAMV_PIERCING, 10, 10, 20, {
459             { SPWPN_VENOM,          28 },
460             { SPWPN_NORMAL,         20 },
461             { SPWPN_SPEED,          10 },
462             { SPWPN_DRAINING,        9 },
463             { SPWPN_PROTECTION,      6 },
464             { SPWPN_ELECTROCUTION,   6 },
465             { SPWPN_HOLY_WRATH,      5 },
466             { SPWPN_VAMPIRISM,       4 },
467             { SPWPN_FLAMING,         4 },
468             { SPWPN_FREEZING,        4 },
469             { SPWPN_PAIN,            2 },
470             { SPWPN_DISTORTION,      1 },
471             { SPWPN_ANTIMAGIC,       1 },
472         }},
473     { WPN_QUICK_BLADE,       "quick blade",         5,  6,  7,
474         SK_SHORT_BLADES, SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
475         DAMV_PIERCING, 0, 2, 150, {} },
476     { WPN_SHORT_SWORD,       "short sword",         6,  4, 11,
477         SK_SHORT_BLADES, SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
478         DAMV_PIERCING, 8, 10, 30, SBL_BRANDS },
479     { WPN_RAPIER,           "rapier",               8,  4, 12,
480         SK_SHORT_BLADES, SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
481         DAMV_PIERCING, 8, 10, 40, SBL_BRANDS },
482 #if TAG_MAJOR_VERSION == 34
483     { WPN_CUTLASS,          "cutlass",              8,  4, 12,
484         SK_SHORT_BLADES, SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
485         DAMV_SLICING | DAM_PIERCE, 0, 0, 0, {}},
486 #endif
487 
488 
489     // Long Blades
490     { WPN_FALCHION,              "falchion",               7,  2, 13,
491         SK_LONG_BLADES,  SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
492         DAMV_SLICING, 7, 10, 30, LBL_BRANDS }, // DAMV_CHOPPING...?
493     { WPN_LONG_SWORD,            "long sword",            9,  1, 14,
494         SK_LONG_BLADES,  SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
495         DAMV_SLICING, 7, 10, 35, LBL_BRANDS },
496     { WPN_SCIMITAR,              "scimitar",              11, 0, 14,
497         SK_LONG_BLADES,  SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
498         DAMV_SLICING, 6, 10, 40, LBL_BRANDS },
499     { WPN_DEMON_BLADE,           "demon blade",           12, -1, 13,
500         SK_LONG_BLADES,  SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
501         DAMV_SLICING, 0, 2, 150, DEMON_BRANDS },
502     { WPN_EUDEMON_BLADE,         "eudemon blade",         13, -2, 12,
503         SK_LONG_BLADES,  SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
504         DAMV_SLICING, 0, 0, 200, HOLY_BRANDS },
505     { WPN_DOUBLE_SWORD,          "double sword",          14, -1, 15,
506         SK_LONG_BLADES,  SIZE_LITTLE, SIZE_MEDIUM, MI_NONE,
507         DAMV_SLICING, 0, 2, 150, LBL_BRANDS },
508     { WPN_GREAT_SWORD,           "great sword",           15, -3, 17,
509         SK_LONG_BLADES,  SIZE_MEDIUM, NUM_SIZE_LEVELS, MI_NONE,
510         DAMV_SLICING, 6, 10, 65, LBL_BRANDS },
511     { WPN_TRIPLE_SWORD,          "triple sword",          17, -4, 19,
512         SK_LONG_BLADES,  SIZE_MEDIUM, NUM_SIZE_LEVELS, MI_NONE,
513         DAMV_SLICING, 0, 2, 100, LBL_BRANDS },
514 #if TAG_MAJOR_VERSION == 34
515     { WPN_BLESSED_FALCHION,      "old falchion",         7,  2, 13,
516         SK_LONG_BLADES,  SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
517         DAMV_SLICING, 0, 0, 0, {} },
518     { WPN_BLESSED_LONG_SWORD,    "old long sword",      9,  1, 14,
519         SK_LONG_BLADES,  SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
520         DAMV_SLICING, 0, 0, 0, {} },
521     { WPN_BLESSED_SCIMITAR,      "old scimitar",        11, -2, 14,
522         SK_LONG_BLADES,  SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
523         DAMV_SLICING, 0, 0, 0, {} },
524     { WPN_BLESSED_DOUBLE_SWORD, "old double sword",     14, -1, 15,
525         SK_LONG_BLADES,  SIZE_LITTLE, SIZE_MEDIUM, MI_NONE,
526         DAMV_SLICING, 0, 0, 0, {} },
527     { WPN_BLESSED_GREAT_SWORD,   "old great sword",     14, -3, 16,
528         SK_LONG_BLADES,  SIZE_MEDIUM, NUM_SIZE_LEVELS,  MI_NONE,
529         DAMV_SLICING, 0, 0, 0, {} },
530     { WPN_BLESSED_TRIPLE_SWORD,      "old triple sword", 17, -4, 19,
531         SK_LONG_BLADES,  SIZE_MEDIUM, NUM_SIZE_LEVELS,  MI_NONE,
532         DAMV_SLICING, 0, 0, 0, {} },
533 #endif
534 
535     // Axes
536     { WPN_HAND_AXE,          "hand axe",            7,  3, 13,
537         SK_AXES,       SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
538         DAMV_CHOPPING, 9, 10, 30, AXE_BRANDS },
539     { WPN_WAR_AXE,           "war axe",            11,  0, 15,
540         SK_AXES,       SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
541         DAMV_CHOPPING, 7, 10, 35, AXE_BRANDS },
542     { WPN_BROAD_AXE,         "broad axe",          13, -2, 16,
543         SK_AXES,       SIZE_LITTLE, SIZE_MEDIUM, MI_NONE,
544         DAMV_CHOPPING, 4, 10, 40, AXE_BRANDS },
545     { WPN_BATTLEAXE,         "battleaxe",          15, -4, 17,
546         SK_AXES,       SIZE_MEDIUM, NUM_SIZE_LEVELS, MI_NONE,
547         DAMV_CHOPPING, 6, 10, 65, AXE_BRANDS },
548     { WPN_EXECUTIONERS_AXE,  "executioner's axe",  18, -6, 20,
549         SK_AXES,       SIZE_MEDIUM, NUM_SIZE_LEVELS, MI_NONE,
550         DAMV_CHOPPING, 0, 2, 100, AXE_BRANDS },
551 
552     // Polearms
553     { WPN_SPEAR,             "spear",               6,  4, 11,
554         SK_POLEARMS,     SIZE_LITTLE, SIZE_LITTLE, MI_NONE,
555         DAMV_PIERCING, 8, 10, 30, {
556             { SPWPN_NORMAL,     46 },
557             { SPWPN_VENOM,      17 },
558             { SPWPN_VORPAL,     12 },
559             { SPWPN_FLAMING,     7 },
560             { SPWPN_FREEZING,    7 },
561             { SPWPN_VAMPIRISM,   5 },
562             { SPWPN_DISTORTION,  2 },
563             { SPWPN_PAIN,        2 },
564             { SPWPN_ANTIMAGIC,   2 },
565         }},
566     { WPN_TRIDENT,           "trident",             9,  1, 13,
567         SK_POLEARMS,     SIZE_LITTLE, SIZE_MEDIUM, MI_NONE,
568         DAMV_PIERCING, 6, 10, 35, POLEARM_BRANDS },
569     { WPN_HALBERD,           "halberd",            13, -3, 15,
570         SK_POLEARMS,     SIZE_MEDIUM, NUM_SIZE_LEVELS,  MI_NONE,
571         DAMV_CHOPPING | DAM_PIERCE, 5, 10, 40, POLEARM_BRANDS },
572     { WPN_SCYTHE,            "scythe",             14, -4, 20,
573         SK_POLEARMS,     SIZE_MEDIUM, NUM_SIZE_LEVELS, MI_NONE,
574         DAMV_SLICING, 2, 0, 30, POLEARM_BRANDS },
575     { WPN_DEMON_TRIDENT,     "demon trident",      12,  1, 13,
576         SK_POLEARMS,     SIZE_LITTLE, SIZE_MEDIUM, MI_NONE,
577         DAMV_PIERCING, 0, 2, 150, DEMON_BRANDS },
578     { WPN_TRISHULA,          "trishula",           13,  0, 13,
579         SK_POLEARMS,     SIZE_LITTLE, SIZE_MEDIUM, MI_NONE,
580         DAMV_PIERCING, 0, 0, 200, HOLY_BRANDS },
581     { WPN_GLAIVE,            "glaive",             15, -3, 17,
582         SK_POLEARMS,     SIZE_MEDIUM, NUM_SIZE_LEVELS, MI_NONE,
583         DAMV_CHOPPING, 5, 10, 65, POLEARM_BRANDS },
584     { WPN_BARDICHE,          "bardiche",           18, -6, 20,
585         SK_POLEARMS,     SIZE_MEDIUM, NUM_SIZE_LEVELS, MI_NONE,
586         DAMV_CHOPPING, 1, 2, 90, POLEARM_BRANDS },
587 
588     // Staves
589     // WPN_STAFF is for weapon stats for magical staves only.
590     { WPN_STAFF,             "staff",               5,  5, 12,
591         SK_STAVES,       SIZE_LITTLE, SIZE_MEDIUM, MI_NONE,
592         DAMV_CRUSHING, 0, 0, 15, {} },
593     { WPN_QUARTERSTAFF,      "quarterstaff",        10, 3, 13,
594         SK_STAVES,       SIZE_LITTLE, NUM_SIZE_LEVELS,  MI_NONE,
595         DAMV_CRUSHING, 8, 10, 40, {
596             { SPWPN_NORMAL,     50 },
597             { SPWPN_SPECTRAL,   18 },
598             { SPWPN_DRAINING,    8 },
599             { SPWPN_VORPAL,      8 },
600             { SPWPN_SPEED,       8 },
601             { SPWPN_DISTORTION,  2 },
602             { SPWPN_PAIN,        2 },
603             { SPWPN_HOLY_WRATH,  2 },
604             { SPWPN_ANTIMAGIC,   2 },
605         }},
606     { WPN_LAJATANG,          "lajatang",            16,-3, 14,
607         SK_STAVES,       SIZE_LITTLE, NUM_SIZE_LEVELS, MI_NONE,
608         DAMV_SLICING, 2, 2, 150, {
609             { SPWPN_NORMAL,         34 },
610             { SPWPN_SPEED,          12 },
611             { SPWPN_ELECTROCUTION,  12 },
612             { SPWPN_VAMPIRISM,      12 },
613             { SPWPN_SPECTRAL,        9 },
614             { SPWPN_VENOM,           7 },
615             { SPWPN_PAIN,            7 },
616             { SPWPN_ANTIMAGIC,       4 },
617             { SPWPN_DISTORTION,      3 },
618         }},
619 
620     // Range weapons
621 #if TAG_MAJOR_VERSION == 34
622     { WPN_BLOWGUN,           "blowgun",             0,  2, 10,
623         SK_THROWING,     SIZE_LITTLE, SIZE_LITTLE, MI_NEEDLE,
624         DAMV_NON_MELEE, 0, 0, 0, {}, },
625 #endif
626 
627     { WPN_HUNTING_SLING,     "hunting sling",       5,  2, 12,
628         SK_SLINGS,       SIZE_LITTLE, SIZE_LITTLE, MI_STONE,
629         DAMV_NON_MELEE, 8, 10, 15, RANGED_BRANDS },
630     { WPN_FUSTIBALUS,        "fustibalus",          8, -1, 14,
631         SK_SLINGS,       SIZE_LITTLE, SIZE_LITTLE, MI_STONE,
632         DAMV_NON_MELEE, 2, 2, 150, RANGED_BRANDS },
633 
634     { WPN_HAND_CROSSBOW,     "hand crossbow",      12,  5, 15,
635         SK_CROSSBOWS,    SIZE_LITTLE, SIZE_LITTLE, MI_BOLT,
636         DAMV_NON_MELEE, 7, 10, 35, RANGED_BRANDS },
637     { WPN_ARBALEST,          "arbalest",           18,  2, 19,
638         SK_CROSSBOWS,    SIZE_LITTLE, NUM_SIZE_LEVELS, MI_BOLT,
639         DAMV_NON_MELEE, 5, 10, 45, RANGED_BRANDS },
640     { WPN_TRIPLE_CROSSBOW,   "triple crossbow",    22,  0, 23,
641         SK_CROSSBOWS,    SIZE_LITTLE, NUM_SIZE_LEVELS, MI_BOLT,
642         DAMV_NON_MELEE, 0, 2, 100, RANGED_BRANDS },
643 
644     { WPN_SHORTBOW,          "shortbow",            9,  2, 13,
645         SK_BOWS,         SIZE_LITTLE, NUM_SIZE_LEVELS, MI_ARROW,
646         DAMV_NON_MELEE, 8, 10, 30, RANGED_BRANDS },
647     { WPN_LONGBOW,           "longbow",            15,  0, 17,
648         SK_BOWS,         SIZE_MEDIUM, NUM_SIZE_LEVELS, MI_ARROW,
649         DAMV_NON_MELEE, 2, 10, 45, RANGED_BRANDS },
650 };
651 
652 struct missile_def
653 {
654     int         id;
655     const char *name;
656     int         dam;
657     int         mulch_rate;
658     int         price;
659     bool        throwable;
660 };
661 
662 static int Missile_index[NUM_MISSILES];
663 static const missile_def Missile_prop[] =
664 {
665     { MI_DART,          "dart",          0, 12, 2,  true  },
666 #if TAG_MAJOR_VERSION == 34
667     { MI_NEEDLE,        "needle",        0, 12, 2,  false },
668 #endif
669     { MI_STONE,         "stone",         2, 8,  1,  true  },
670     { MI_ARROW,         "arrow",         0, 8,  2,  false },
671     { MI_BOLT,          "bolt",          0, 8,  2,  false },
672     { MI_LARGE_ROCK,    "large rock",   20, 25, 7,  true  },
673     { MI_SLING_BULLET,  "sling bullet",  4, 8,  5,  false },
674     { MI_JAVELIN,       "javelin",      10, 20, 8,  true  },
675     { MI_THROWING_NET,  "throwing net",  0, 0,  30, true  },
676     { MI_BOOMERANG,     "boomerang",     6, 20, 5,  true  },
677 };
678 
679 #if TAG_MAJOR_VERSION == 34
680 struct food_def
681 {
682     int         id;
683     const char *name;
684     int         normal_nutr;
685     int         carn_nutr;
686     int         herb_nutr;
687 };
688 
689 static int Food_index[NUM_FOODS];
690 static const food_def Food_prop[] =
691 {
692     { FOOD_RATION,       "buggy ration", 3400,  1900,  1900 },
693     { FOOD_CHUNK,        "buggy chunk",        1000,  1300,     0 },
694 
695     // is_real_food assumes we list FOOD_ROYAL_JELLY as the first removed
696     // food here, after all the unremoved foods.
697     { FOOD_UNUSED,       "buggy pizza",     0,     0,     0 },
698     { FOOD_ROYAL_JELLY,  "buggy jelly",  2000,  2000,  2000 },
699     { FOOD_BREAD_RATION, "buggy ration", 4400,     0,  5900 },
700     { FOOD_FRUIT,        "buggy fruit",   850,     0,  1000 },
701     { FOOD_AMBROSIA,     "buggy fruit",     0,     0,     0 },
702     { FOOD_ORANGE,       "buggy fruit",  1000,  -300,   300 },
703     { FOOD_BANANA,       "buggy fruit",  1000,  -300,   300 },
704     { FOOD_LEMON,        "buggy fruit",  1000,  -300,   300 },
705     { FOOD_PEAR,         "buggy fruit",   700,  -200,   200 },
706     { FOOD_APPLE,        "buggy fruit",   700,  -200,   200 },
707     { FOOD_APRICOT,      "buggy fruit",   700,  -200,   200 },
708     { FOOD_CHOKO,        "buggy fruit",   600,  -200,   200 },
709     { FOOD_RAMBUTAN,     "buggy fruit",   600,  -200,   200 },
710     { FOOD_LYCHEE,       "buggy fruit",   600,  -200,   200 },
711     { FOOD_STRAWBERRY,   "buggy fruit",   200,   -50,    50 },
712     { FOOD_GRAPE,        "buggy fruit",   100,   -20,    20 },
713     { FOOD_SULTANA,      "buggy fruit",    70,   -20,    20 },
714     { FOOD_CHEESE,       "buggy fruit",  1200,     0,     0 },
715     { FOOD_SAUSAGE,      "buggy fruit",  1200,   150,  -400 },
716     { FOOD_BEEF_JERKY,   "buggy fruit",  1500,   200,  -200 },
717     { FOOD_PIZZA,        "buggy fruit",  1500,     0,     0 },
718 };
719 #endif
720 
721 // Must call this functions early on so that the above tables can
722 // be accessed correctly.
init_properties()723 void init_properties()
724 {
725     // The compiler would complain about too many initializers but not
726     // about too few, so we check this ourselves.
727     COMPILE_CHECK(NUM_ARMOURS  == ARRAYSZ(Armour_prop));
728     COMPILE_CHECK(NUM_WEAPONS  == ARRAYSZ(Weapon_prop));
729     COMPILE_CHECK(NUM_MISSILES == ARRAYSZ(Missile_prop));
730 #if TAG_MAJOR_VERSION == 34
731     COMPILE_CHECK(NUM_FOODS    == ARRAYSZ(Food_prop));
732 #endif
733 
734     for (int i = 0; i < NUM_ARMOURS; i++)
735         Armour_index[ Armour_prop[i].id ] = i;
736 
737     for (int i = 0; i < NUM_WEAPONS; i++)
738         Weapon_index[ Weapon_prop[i].id ] = i;
739 
740     for (int i = 0; i < NUM_MISSILES; i++)
741         Missile_index[ Missile_prop[i].id ] = i;
742 
743 #if TAG_MAJOR_VERSION == 34
744     for (int i = 0; i < NUM_FOODS; i++)
745         Food_index[ Food_prop[i].id ] = i;
746 #endif
747 }
748 
749 const set<pair<object_class_type, int> > removed_items =
750 {
751 #if TAG_MAJOR_VERSION == 34
752     { OBJ_JEWELLERY, AMU_CONTROLLED_FLIGHT },
753     { OBJ_JEWELLERY, AMU_CONSERVATION },
754     { OBJ_JEWELLERY, AMU_THE_GOURMAND },
755     { OBJ_JEWELLERY, AMU_HARM },
756     { OBJ_JEWELLERY, AMU_RAGE },
757     { OBJ_JEWELLERY, AMU_INACCURACY },
758     { OBJ_JEWELLERY, RING_REGENERATION },
759     { OBJ_JEWELLERY, RING_SUSTAIN_ATTRIBUTES },
760     { OBJ_JEWELLERY, RING_TELEPORT_CONTROL },
761     { OBJ_JEWELLERY, RING_TELEPORTATION },
762     { OBJ_JEWELLERY, RING_ATTENTION },
763     { OBJ_JEWELLERY, RING_STEALTH },
764     { OBJ_STAVES,    STAFF_ENCHANTMENT },
765     { OBJ_STAVES,    STAFF_CHANNELING },
766     { OBJ_STAVES,    STAFF_POWER },
767     { OBJ_STAVES,    STAFF_ENERGY },
768     { OBJ_STAVES,    STAFF_SUMMONING },
769     { OBJ_STAVES,    STAFF_WIZARDRY },
770     { OBJ_POTIONS,   POT_GAIN_STRENGTH },
771     { OBJ_POTIONS,   POT_GAIN_DEXTERITY },
772     { OBJ_POTIONS,   POT_GAIN_INTELLIGENCE },
773     { OBJ_POTIONS,   POT_WATER },
774     { OBJ_POTIONS,   POT_STRONG_POISON },
775     { OBJ_POTIONS,   POT_BLOOD_COAGULATED },
776     { OBJ_POTIONS,   POT_BLOOD },
777     { OBJ_POTIONS,   POT_PORRIDGE },
778     { OBJ_POTIONS,   POT_SLOWING },
779     { OBJ_POTIONS,   POT_DECAY },
780     { OBJ_POTIONS,   POT_POISON },
781     { OBJ_POTIONS,   POT_RESTORE_ABILITIES },
782     { OBJ_POTIONS,   POT_CURE_MUTATION },
783     { OBJ_POTIONS,   POT_BENEFICIAL_MUTATION },
784     { OBJ_POTIONS,   POT_DUMMY_AGILITY },
785     { OBJ_BOOKS,     BOOK_WIZARDRY },
786     { OBJ_BOOKS,     BOOK_CONTROL },
787     { OBJ_BOOKS,     BOOK_BUGGY_DESTRUCTION },
788     { OBJ_BOOKS,     BOOK_ENVENOMATIONS },
789     { OBJ_BOOKS,     BOOK_AKASHIC_RECORD },
790     { OBJ_BOOKS,     BOOK_BATTLE },
791     { OBJ_RODS,      ROD_VENOM },
792     { OBJ_RODS,      ROD_WARDING },
793     { OBJ_RODS,      ROD_DESTRUCTION },
794     { OBJ_RODS,      ROD_SWARM },
795     { OBJ_RODS,      ROD_LIGHTNING },
796     { OBJ_RODS,      ROD_IGNITION },
797     { OBJ_RODS,      ROD_CLOUDS },
798     { OBJ_RODS,      ROD_INACCURACY },
799     { OBJ_RODS,      ROD_SHADOWS },
800     { OBJ_RODS,      ROD_IRON },
801     { OBJ_SCROLLS,   SCR_ENCHANT_WEAPON_II },
802     { OBJ_SCROLLS,   SCR_ENCHANT_WEAPON_III },
803     { OBJ_SCROLLS,   SCR_RECHARGING },
804     { OBJ_SCROLLS,   SCR_CURSE_WEAPON },
805     { OBJ_SCROLLS,   SCR_CURSE_ARMOUR },
806     { OBJ_SCROLLS,   SCR_CURSE_JEWELLERY },
807     { OBJ_SCROLLS,   SCR_REMOVE_CURSE },
808     { OBJ_SCROLLS,   SCR_RANDOM_USELESSNESS },
809     { OBJ_WANDS,     WAND_MAGIC_DARTS_REMOVED },
810     { OBJ_WANDS,     WAND_FROST_REMOVED },
811     { OBJ_WANDS,     WAND_FIRE_REMOVED },
812     { OBJ_WANDS,     WAND_COLD_REMOVED },
813     { OBJ_WANDS,     WAND_INVISIBILITY_REMOVED },
814     { OBJ_WANDS,     WAND_HEAL_WOUNDS_REMOVED },
815     { OBJ_WANDS,     WAND_HASTING_REMOVED },
816     { OBJ_WANDS,     WAND_TELEPORTATION_REMOVED },
817     { OBJ_WANDS,     WAND_SLOWING_REMOVED },
818     { OBJ_WANDS,     WAND_CONFUSION_REMOVED },
819     { OBJ_WANDS,     WAND_LIGHTNING_REMOVED },
820     { OBJ_WANDS,     WAND_SCATTERSHOT_REMOVED },
821     { OBJ_WANDS,     WAND_CLOUDS_REMOVED },
822     { OBJ_WANDS,     WAND_RANDOM_EFFECTS_REMOVED },
823     { OBJ_FOOD,      FOOD_CHUNK},
824     { OBJ_FOOD,      FOOD_BREAD_RATION },
825     { OBJ_FOOD,      FOOD_ROYAL_JELLY },
826     { OBJ_FOOD,      FOOD_UNUSED },
827     { OBJ_FOOD,      FOOD_FRUIT },
828     { OBJ_FOOD,      FOOD_RATION },
829 #endif
830     { OBJ_JEWELLERY, AMU_NOTHING }, // These should only spawn as uniques
831 };
832 
item_type_removed(object_class_type base,int subtype)833 bool item_type_removed(object_class_type base, int subtype)
834 {
835     return removed_items.count({ base, subtype }) != 0;
836 }
837 
838 // If item is a new unrand, takes a note of it and returns true.
839 // Otherwise, takes no action and returns false.
_maybe_note_found_unrand(const item_def & item)840 static bool _maybe_note_found_unrand(const item_def &item)
841 {
842     if (is_unrandom_artefact(item) && !(item.flags & ISFLAG_SEEN))
843     {
844         take_note(Note(NOTE_FOUND_UNRAND, 0, 0, item.name(DESC_THE),
845                        origin_desc(item)));
846         return true;
847     }
848     return false;
849 }
850 
851 /**
852  * Is the provided item cursable?
853  *
854  * @param item  The item under consideration.
855  * @return      Whether the given item is cursable.
856  */
item_is_cursable(const item_def & item)857 bool item_is_cursable(const item_def &item)
858 {
859     if (!item_type_has_curses(item.base_type))
860         return false;
861     if (item.cursed())
862         return false;
863     return true;
864 }
865 
auto_id_inventory()866 void auto_id_inventory()
867 {
868     for (int slot = 0; slot < ENDOFPACK; ++slot)
869     {
870         item_def &item = you.inv[slot];
871         if (item.defined() && !fully_identified(item))
872         {
873             god_id_item(item, false);
874             item_def * moved = auto_assign_item_slot(item);
875             // We moved the item to later in the pack, so don't
876             // miss what we swapped with.
877             if (moved != nullptr && moved->link > slot)
878                 --slot;
879         }
880     }
881 }
882 
883 /**
884  * Make a net stationary (because it currently traps a victim).
885  *
886  * @param item The net item.
887 */
set_net_stationary(item_def & item)888 void set_net_stationary(item_def &item)
889 {
890     if (item.is_type(OBJ_MISSILES, MI_THROWING_NET))
891         item.net_placed = true;
892 }
893 
894 /**
895  * Is the item stationary (unmovable)?
896  *
897  * Currently only carrion and nets with a trapped victim are stationary.
898  * @param item The item.
899  * @return  True iff the item is stationary.
900 */
item_is_stationary(const item_def & item)901 bool item_is_stationary(const item_def &item)
902 {
903     return item.base_type == OBJ_CORPSES || item_is_stationary_net(item);
904 }
905 
906 /**
907  * Is the item a stationary net?
908  *
909  * @param item The item.
910  * @return  True iff the item is a stationary net.
911 */
item_is_stationary_net(const item_def & item)912 bool item_is_stationary_net(const item_def &item)
913 {
914     return item.is_type(OBJ_MISSILES, MI_THROWING_NET) && item.net_placed;
915 }
916 
_is_affordable(const item_def & item)917 static bool _is_affordable(const item_def &item)
918 {
919     // Temp items never count.
920     if (item.flags & ISFLAG_SUMMONED)
921         return false;
922 
923     // Already in our grubby mitts.
924     if (in_inventory(item))
925         return true;
926 
927     // Disregard shop stuff above your reach.
928     if (is_shop_item(item))
929         return (int)item_value(item) <= you.gold;
930 
931     // Explicitly marked by a vault.
932     if (item.flags & ISFLAG_UNOBTAINABLE)
933         return false;
934 
935     // On the ground or a monster has it. Violence is the answer.
936     return true;
937 }
938 
939 //
940 // Item identification status:
941 //
item_ident(const item_def & item,iflags_t flags)942 bool item_ident(const item_def &item, iflags_t flags)
943 {
944     return (item.flags & flags) == flags;
945 }
946 
set_ident_flags(item_def & item,iflags_t flags)947 void set_ident_flags(item_def &item, iflags_t flags)
948 {
949     if ((item.flags & flags) != flags)
950     {
951         item.flags |= flags;
952         request_autoinscribe();
953 
954         if (in_inventory(item))
955         {
956             shopping_list.cull_identical_items(item);
957             item_skills(item, you.skills_to_show);
958         }
959     }
960 
961     if (fully_identified(item))
962     {
963         if (notes_are_active() && !(item.flags & ISFLAG_NOTED_ID)
964             && !get_ident_type(item)
965             && is_interesting_item(item))
966         {
967             if (!_maybe_note_found_unrand(item))
968             {
969                 // Make a note of this non-unrand item
970                 take_note(Note(NOTE_ID_ITEM, 0, 0, item.name(DESC_A),
971                                origin_desc(item)));
972             }
973 
974             // Sometimes (e.g. shops) you can ID an item before you get it;
975             // don't note twice in those cases.
976             item.flags |= (ISFLAG_NOTED_ID | ISFLAG_NOTED_GET);
977         }
978     }
979 
980     if (item.flags & ISFLAG_KNOW_TYPE && !is_artefact(item)
981         && _is_affordable(item))
982     {
983         if (item.base_type == OBJ_WEAPONS)
984             you.seen_weapon[item.sub_type] |= 1 << item.brand;
985         if (item.base_type == OBJ_ARMOUR)
986             you.seen_armour[item.sub_type] |= 1 << item.brand;
987         if (item.base_type == OBJ_MISCELLANY)
988             you.seen_misc.set(item.sub_type);
989     }
990 }
991 
unset_ident_flags(item_def & item,iflags_t flags)992 void unset_ident_flags(item_def &item, iflags_t flags)
993 {
994     item.flags &= (~flags);
995 }
996 
997 // Returns the mask of interesting identify bits for this item
998 // (e.g., missiles don't have know-type).
_full_ident_mask(const item_def & item)999 static iflags_t _full_ident_mask(const item_def& item)
1000 {
1001     // KNOW_PROPERTIES is only relevant for artefacts, handled later.
1002     iflags_t flagset = ISFLAG_IDENT_MASK & ~ISFLAG_KNOW_PROPERTIES;
1003     switch (item.base_type)
1004     {
1005     case OBJ_CORPSES:
1006     case OBJ_MISSILES:
1007     case OBJ_ORBS:
1008     case OBJ_RUNES:
1009     case OBJ_GOLD:
1010     case OBJ_BOOKS:
1011 #if TAG_MAJOR_VERSION == 34
1012     case OBJ_FOOD:
1013     case OBJ_RODS:
1014 #endif
1015         flagset = 0;
1016         break;
1017     case OBJ_SCROLLS:
1018     case OBJ_POTIONS:
1019     case OBJ_WANDS:
1020     case OBJ_STAVES:
1021     case OBJ_JEWELLERY:
1022         flagset = ISFLAG_KNOW_TYPE;
1023         break;
1024     case OBJ_MISCELLANY:
1025         flagset = 0;
1026         break;
1027     case OBJ_WEAPONS:
1028     case OBJ_ARMOUR:
1029         // All flags necessary for full identification.
1030     default:
1031         break;
1032     }
1033 
1034     if (item_type_known(item.base_type, item.sub_type) && !is_artefact(item))
1035         flagset &= (~ISFLAG_KNOW_TYPE);
1036 
1037     if (is_artefact(item))
1038         flagset |= ISFLAG_KNOW_PROPERTIES;
1039 
1040     return flagset;
1041 }
1042 
fully_identified(const item_def & item)1043 bool fully_identified(const item_def& item)
1044 {
1045     return item_ident(item, _full_ident_mask(item));
1046 }
1047 
1048 //
1049 // Equipment description:
1050 //
get_equip_desc(const item_def & item)1051 iflags_t get_equip_desc(const item_def &item)
1052 {
1053     return item.flags & ISFLAG_COSMETIC_MASK;
1054 }
1055 
set_equip_desc(item_def & item,iflags_t flags)1056 void set_equip_desc(item_def &item, iflags_t flags)
1057 {
1058     ASSERT((flags & ~ISFLAG_COSMETIC_MASK) == 0);
1059 
1060     item.flags &= ~ISFLAG_COSMETIC_MASK; // delete previous
1061     item.flags |= flags;
1062 }
1063 
is_helmet(const item_def & item)1064 bool is_helmet(const item_def& item)
1065 {
1066     return item.base_type == OBJ_ARMOUR && get_armour_slot(item) == EQ_HELMET;
1067 }
1068 
is_hard_helmet(const item_def & item)1069 bool is_hard_helmet(const item_def &item)
1070 {
1071     return item.is_type(OBJ_ARMOUR, ARM_HELMET);
1072 }
1073 
1074 //
1075 // Ego item functions:
1076 //
1077 
1078 /**
1079  * For a given weapon type, randomly choose an appropriate brand.
1080  *
1081  * @param wpn_type  The type of weapon in question.
1082  * @return          An appropriate brand. (e.g. fire, pain, venom, etc)
1083  *                  May be SPWPN_NORMAL.
1084  */
choose_weapon_brand(weapon_type wpn_type)1085 brand_type choose_weapon_brand(weapon_type wpn_type)
1086 {
1087     const vector<brand_weight_tuple> weights
1088         = Weapon_prop[ Weapon_index[wpn_type] ].brand_weights;
1089     if (!weights.size())
1090         return SPWPN_NORMAL;
1091 
1092     const brand_type *brand = random_choose_weighted(weights);
1093     ASSERT(brand);
1094     return *brand;
1095 }
1096 
set_item_ego_type(item_def & item,object_class_type item_type,int ego_type)1097 bool set_item_ego_type(item_def &item, object_class_type item_type,
1098                        int ego_type)
1099 {
1100     if (item.base_type == item_type && !is_artefact(item))
1101     {
1102         item.brand = ego_type;
1103         return true;
1104     }
1105 
1106     return false;
1107 }
1108 
get_weapon_brand(const item_def & item)1109 brand_type get_weapon_brand(const item_def &item)
1110 {
1111     // Weapon ego types are "brands", so we do the randart lookup here.
1112 
1113     // Staves "brands" handled specially
1114     if (item.base_type != OBJ_WEAPONS)
1115         return SPWPN_NORMAL;
1116 
1117     if (is_artefact(item))
1118         return static_cast<brand_type>(artefact_property(item, ARTP_BRAND));
1119 
1120     return static_cast<brand_type>(item.brand);
1121 }
1122 
get_ammo_brand(const item_def & item)1123 special_missile_type get_ammo_brand(const item_def &item)
1124 {
1125     // No artefact arrows yet. -- bwr
1126     if (item.base_type != OBJ_MISSILES || is_artefact(item))
1127         return SPMSL_NORMAL;
1128 
1129     return static_cast<special_missile_type>(item.brand);
1130 }
1131 
get_armour_ego_type(const item_def & item)1132 special_armour_type get_armour_ego_type(const item_def &item)
1133 {
1134     // Armour ego types are "brands", so we do the randart lookup here.
1135     if (item.base_type != OBJ_ARMOUR)
1136         return SPARM_NORMAL;
1137 
1138     if (is_artefact(item))
1139     {
1140         return static_cast<special_armour_type>(
1141                    artefact_property(item, ARTP_BRAND));
1142     }
1143 
1144     return static_cast<special_armour_type>(item.brand);
1145 }
1146 
1147 /// A map between monster species & their hides.
1148 static map<monster_type, armour_type> _monster_hides = {
1149     { MONS_TROLL,               ARM_TROLL_LEATHER_ARMOUR },
1150     { MONS_DEEP_TROLL,          ARM_TROLL_LEATHER_ARMOUR },
1151     { MONS_IRON_TROLL,          ARM_TROLL_LEATHER_ARMOUR },
1152 
1153     { MONS_FIRE_DRAGON,         ARM_FIRE_DRAGON_ARMOUR },
1154     { MONS_ICE_DRAGON,          ARM_ICE_DRAGON_ARMOUR },
1155     { MONS_STEAM_DRAGON,        ARM_STEAM_DRAGON_ARMOUR },
1156     { MONS_ACID_DRAGON,         ARM_ACID_DRAGON_ARMOUR },
1157     { MONS_STORM_DRAGON,        ARM_STORM_DRAGON_ARMOUR },
1158     { MONS_GOLDEN_DRAGON,       ARM_GOLD_DRAGON_ARMOUR },
1159     { MONS_SWAMP_DRAGON,        ARM_SWAMP_DRAGON_ARMOUR },
1160     { MONS_PEARL_DRAGON,        ARM_PEARL_DRAGON_ARMOUR },
1161     { MONS_SHADOW_DRAGON,       ARM_SHADOW_DRAGON_ARMOUR },
1162     { MONS_QUICKSILVER_DRAGON,  ARM_QUICKSILVER_DRAGON_ARMOUR },
1163 };
1164 
1165 /**
1166  * If a monster of the given type dies, what kind of armour can it leave?
1167  *
1168  * @param mc    The class of monster in question.
1169  * @return      The armour_type of the given monster's armour, or NUM_ARMOURS
1170  *              if the monster does not leave armour.
1171  */
hide_for_monster(monster_type mc)1172 armour_type hide_for_monster(monster_type mc)
1173 {
1174     return lookup(_monster_hides, mons_species(mc), NUM_ARMOURS);
1175 }
1176 
1177 /**
1178  * Return whether a piece of armour is enchantable.
1179  *
1180  * This function ignores the current enchantment level, so is still
1181  * true for maximally-enchanted items.
1182  *
1183  * @param item      The item being considered.
1184  * @return          True if the armour can have a +X enchantment.
1185  */
armour_is_enchantable(const item_def & item)1186 bool armour_is_enchantable(const item_def &item)
1187 {
1188     ASSERT(item.base_type == OBJ_ARMOUR);
1189     return item.sub_type != ARM_QUICKSILVER_DRAGON_ARMOUR
1190         && item.sub_type != ARM_SCARF;
1191 }
1192 
1193 /**
1194  * Return the enchantment limit of a piece of armour.
1195  *
1196  * @param item      The item being considered.
1197  * @return          The maximum enchantment the item can hold.
1198  */
armour_max_enchant(const item_def & item)1199 int armour_max_enchant(const item_def &item)
1200 {
1201     ASSERT(item.base_type == OBJ_ARMOUR);
1202 
1203     // Unenchantables.
1204     if (!armour_is_enchantable(item))
1205         return 0;
1206 
1207     const int eq_slot = get_armour_slot(item);
1208 
1209     int max_plus = MAX_SEC_ENCHANT;
1210     if (eq_slot == EQ_BODY_ARMOUR || item.sub_type == ARM_BARDING)
1211         max_plus = property(item, PARM_AC);
1212     else if (eq_slot == EQ_SHIELD)
1213         // 3 / 5 / 8 for bucklers/shields/lg. shields
1214         max_plus = (property(item, PARM_AC) - 3)/2 + 3;
1215 
1216     return max_plus;
1217 }
1218 
1219 /**
1220  * Find the set of all armours made from monsters.
1221  */
_make_hide_armour_set()1222 static set<armour_type> _make_hide_armour_set()
1223 {
1224     set<armour_type> _hide_armour_set;
1225     // iter over armours created from monsters
1226     for (auto it: _monster_hides)
1227         _hide_armour_set.insert(it.second);
1228     return _hide_armour_set;
1229 }
1230 static set<armour_type> _hide_armour_set = _make_hide_armour_set();
1231 
1232 /**
1233  * Is the given armour a type that drops from dead monsters (i.e. dragon or
1234  * troll armour)?
1235  *
1236  * @param item      The armour in question.
1237  * @return          Whether the given item comes from a monster corpse.
1238  *                  (Note that ARM_ANIMAL_SKIN doesn't come from in-game
1239 *                    monsters (these days) and so doesn't count.)
1240  */
armour_is_hide(const item_def & item)1241 bool armour_is_hide(const item_def &item)
1242 {
1243     return item.base_type == OBJ_ARMOUR
1244            && armour_type_is_hide(static_cast<armour_type>(item.sub_type));
1245 }
1246 
1247 /**
1248  * Is the given armour a type that drops from dead monsters (i.e. dragon or
1249  * troll armour)?
1250  *
1251  * @param type      The armour_type in question.
1252  * @return          Whether the given item comes from a monster corpse.
1253  *                  (Note that ARM_ANIMAL_SKIN doesn't come from in-game
1254  *                   monsters (these days) and so doesn't count.)
1255  */
armour_type_is_hide(armour_type type)1256 bool armour_type_is_hide(armour_type type)
1257 {
1258     return _hide_armour_set.count(type);
1259 }
1260 
1261 /**
1262  * Generate a map from monster armours to the monsters that drop them.
1263  */
_make_hide_monster_map()1264 static map<armour_type, monster_type> _make_hide_monster_map()
1265 {
1266     map<armour_type, monster_type> hide_to_mons;
1267     for (auto monster_data : _monster_hides)
1268     {
1269         const armour_type hide = monster_data.second;
1270         const monster_type mon = monster_data.first;
1271         hide_to_mons[hide] = mon;
1272     }
1273 
1274     // troll hides are generated by multiple monsters, so set a canonical troll
1275     // by hand
1276     hide_to_mons[ARM_TROLL_LEATHER_ARMOUR] = MONS_TROLL;
1277 
1278     return hide_to_mons;
1279 }
1280 
1281 static map<armour_type, monster_type> hide_to_mons = _make_hide_monster_map();
1282 
1283 /**
1284  * Find the monster that the given type of dragon/troll armour came from.
1285  *
1286  * @param arm   The type of armour in question.
1287  * @return      The corresponding monster type; e.g. MONS_FIRE_DRAGON for
1288  *              ARM_FIRE_DRAGON_ARMOUR,
1289  *              MONS_TROLL for ARM_TROLL_LEATHER_ARMOUR...
1290  */
monster_for_hide(armour_type arm)1291 monster_type monster_for_hide(armour_type arm)
1292 {
1293     monster_type *mon = map_find(hide_to_mons, arm);
1294     ASSERT(mon);
1295     return *mon;
1296 }
1297 
1298 /**
1299  * Is this armour considered inherently 'special' for acquirement?
1300  *
1301  * @param arm   The armour item in question.
1302  * @return      Whether that type of armour is considered 'special'.
1303  */
armour_is_special(const item_def & item)1304 bool armour_is_special(const item_def &item)
1305 {
1306     ASSERT(item.base_type == OBJ_ARMOUR);
1307 
1308     return !Armour_prop[ Armour_index[item.sub_type] ].mundane;
1309 }
1310 
1311 /**
1312  * What weight does this armour type have for acquirement? (Higher = appears
1313  * more often.)
1314  *
1315  * @param arm   The armour item in question.
1316  * @return      The base weight the armour should have in acquirement, before
1317  *              skills & other effects are factored in.
1318  */
armour_acq_weight(const armour_type armour)1319 int armour_acq_weight(const armour_type armour)
1320 {
1321     return Armour_prop[ Armour_index[armour] ].acquire_weight;
1322 }
1323 
get_armour_slot(const item_def & item)1324 equipment_type get_armour_slot(const item_def &item)
1325 {
1326     ASSERT(item.base_type == OBJ_ARMOUR);
1327 
1328     return Armour_prop[ Armour_index[item.sub_type] ].slot;
1329 }
1330 
get_armour_slot(armour_type arm)1331 equipment_type get_armour_slot(armour_type arm)
1332 {
1333     return Armour_prop[ Armour_index[arm] ].slot;
1334 }
1335 
jewellery_is_amulet(const item_def & item)1336 bool jewellery_is_amulet(const item_def &item)
1337 {
1338     ASSERT(item.base_type == OBJ_JEWELLERY);
1339 
1340     return jewellery_is_amulet(item.sub_type);
1341 }
1342 
jewellery_is_amulet(int sub_type)1343 bool jewellery_is_amulet(int sub_type)
1344 {
1345     return sub_type >= AMU_FIRST_AMULET;
1346 }
1347 
1348 /**
1349  * How many size categories away is the given type of armour from fitting a
1350  * creature of the given size - and in what direction?
1351  *
1352  * @param sub_type  The type of armour in question.
1353  * @param size      The size of the creature in question.
1354  * @return          The difference between the size of the creature and the
1355  *                  closest size of creature that might wear the armour.
1356  *                  Negative if the creature is too small.
1357  *                  Positive if the creature is too large.
1358  *                  0 if the creature is just right.
1359  */
_fit_armour_size(armour_type sub_type,size_type size)1360 static int _fit_armour_size(armour_type sub_type, size_type size)
1361 {
1362     const size_type min = Armour_prop[ Armour_index[sub_type] ].fit_min;
1363     const size_type max = Armour_prop[ Armour_index[sub_type] ].fit_max;
1364 
1365     if (size < min)
1366         return min - size;    // negative means levels too small
1367     else if (size > max)
1368         return max - size;    // positive means levels too large
1369 
1370     return 0;
1371 }
1372 
1373 /**
1374  * How many size categories away is the given armour from fitting a creature of
1375  * the given size - and in what direction?
1376  *
1377  * @param item      The armour in question.
1378  * @param size      The size of the creature in question.
1379  * @return          The difference between the size of the creature and the
1380  *                  closest size of creature that might wear the armour.
1381  *                  Negative if the creature is too small.
1382  *                  Positive if the creature is too large.
1383  *                  0 if the creature is just right.
1384  */
fit_armour_size(const item_def & item,size_type size)1385 int fit_armour_size(const item_def &item, size_type size)
1386 {
1387     ASSERT(item.base_type == OBJ_ARMOUR);
1388     return _fit_armour_size(static_cast<armour_type>(item.sub_type), size);
1389 }
1390 
1391 /**
1392  * Does the given type of armour fit a creature of the given size?
1393  *
1394  * @param sub_type  The type of armour in question.
1395  * @param size      The size of the creature that might wear the armour.
1396  * @return          Whether the armour fits based on size. (It might still not
1397  *                  fit for other reasons, e.g. mutations...)
1398  */
check_armour_size(armour_type sub_type,size_type size)1399 bool check_armour_size(armour_type sub_type, size_type size)
1400 {
1401     return _fit_armour_size(sub_type, size) == 0;
1402 }
1403 
1404 /**
1405  * Does the given armour fit a creature of the given size?
1406  *
1407  * @param item      The armour in question.
1408  * @param size      The size of the creature that might wear the armour.
1409  * @return          Whether the armour fits based on size. (It might still not
1410  *                  fit for other reasons, e.g. mutations...)
1411  */
check_armour_size(const item_def & item,size_type size)1412 bool check_armour_size(const item_def &item, size_type size)
1413 {
1414     ASSERT(item.base_type == OBJ_ARMOUR);
1415 
1416     return check_armour_size(static_cast<armour_type>(item.sub_type), size);
1417 }
1418 
wand_charge_value(int type)1419 int wand_charge_value(int type)
1420 {
1421     switch (type)
1422     {
1423     case WAND_DIGGING:
1424         return 9;
1425 
1426     case WAND_ICEBLAST:
1427     case WAND_ACID:
1428     case WAND_CHARMING:
1429     case WAND_PARALYSIS:
1430     case WAND_POLYMORPH:
1431         return 15;
1432 
1433     default:
1434         return 24;
1435 
1436     case WAND_FLAME:
1437         return 32;
1438     }
1439 }
1440 
1441 
1442 #if TAG_MAJOR_VERSION == 34
1443 /**
1444  * Is the given item a wand which is empty? Wands are normally destroyed when
1445  * their charges are exhausted, but empty wands can still happen through
1446  * transfered games.
1447  *
1448  * @param item  The item in question.
1449  * @return      Whether the wand is empty.
1450  */
is_known_empty_wand(const item_def & item)1451 bool is_known_empty_wand(const item_def &item)
1452 {
1453     if (item.base_type != OBJ_WANDS)
1454         return false;
1455 
1456     return item_ident(item, ISFLAG_KNOW_TYPE) && item.charges <= 0;
1457 }
1458 #endif
1459 
1460 /**
1461  * What wands could a monster use to directly harm the player?
1462  *
1463  * @param item      The wand to be examined.
1464  * @return          True if the wand could harm the player, false otherwise.
1465  */
is_offensive_wand(const item_def & item)1466 bool is_offensive_wand(const item_def& item)
1467 {
1468     switch (item.sub_type)
1469     {
1470     // Monsters use it, but it's not an offensive wand
1471     case WAND_DIGGING:
1472         return false;
1473 
1474     case WAND_ACID:
1475     case WAND_MINDBURST:
1476     case WAND_CHARMING:
1477     case WAND_FLAME:
1478     case WAND_ICEBLAST:
1479     case WAND_PARALYSIS:
1480     case WAND_POLYMORPH:
1481         return true;
1482     }
1483     return false;
1484 }
1485 
1486 // Returns whether a piece of armour can be enchanted further.
1487 // If unknown is true, unidentified armour will return true.
is_enchantable_armour(const item_def & arm,bool unknown)1488 bool is_enchantable_armour(const item_def &arm, bool unknown)
1489 {
1490     if (arm.base_type != OBJ_ARMOUR)
1491         return false;
1492 
1493     // Armour types that can never be enchanted.
1494     if (!armour_is_enchantable(arm))
1495         return false;
1496 
1497     // If we don't know the plusses, assume enchanting is possible.
1498     if (unknown && !is_artefact(arm) && !item_ident(arm, ISFLAG_KNOW_PLUSES))
1499         return true;
1500 
1501     // Artefacts or highly enchanted armour cannot be enchanted.
1502     if (is_artefact(arm) || arm.plus >= armour_max_enchant(arm))
1503         return false;
1504 
1505     return true;
1506 }
1507 
1508 //
1509 // Weapon information and checking functions:
1510 //
1511 
1512 // Checks how rare a weapon is. Many of these have special routines for
1513 // placement, especially those with a rarity of zero. Chance is out of 10.
1514 // ^^^ vvv "rarity" is exactly the wrong term - inverted...
weapon_rarity(int w_type)1515 int weapon_rarity(int w_type)
1516 {
1517     return Weapon_prop[Weapon_index[w_type]].commonness;
1518 }
1519 
get_vorpal_type(const item_def & item)1520 int get_vorpal_type(const item_def &item)
1521 {
1522     int ret = DVORP_NONE;
1523 
1524     if (item.base_type == OBJ_WEAPONS)
1525         ret = (Weapon_prop[Weapon_index[item.sub_type]].dam_type & DAMV_MASK);
1526 
1527     return ret;
1528 }
1529 
get_damage_type(const item_def & item)1530 int get_damage_type(const item_def &item)
1531 {
1532     if (item.base_type == OBJ_WEAPONS)
1533         return Weapon_prop[Weapon_index[item.sub_type]].dam_type & DAM_MASK;
1534 
1535     return DAM_BASH;
1536 }
1537 
_does_damage_type(const item_def & item,int dam_type)1538 static bool _does_damage_type(const item_def &item, int dam_type)
1539 {
1540     return get_damage_type(item) & dam_type;
1541 }
1542 
single_damage_type(const item_def & item)1543 int single_damage_type(const item_def &item)
1544 {
1545     int ret = get_damage_type(item);
1546 
1547     if (ret > 0)
1548     {
1549         int count = 0;
1550 
1551         for (int i = 1; i <= DAM_MAX_TYPE; i <<= 1)
1552         {
1553             if (!_does_damage_type(item, i))
1554                 continue;
1555 
1556             if (one_chance_in(++count))
1557                 ret = i;
1558         }
1559     }
1560 
1561     return ret;
1562 }
1563 
1564 // Give hands required to wield weapon for a torso of "size".
1565 // Not adjusted by species or anything, which is why it's "basic".
basic_hands_reqd(const item_def & item,size_type size)1566 hands_reqd_type basic_hands_reqd(const item_def &item, size_type size)
1567 {
1568     const auto wpn_type = [&item]() {
1569         if (item.base_type == OBJ_WEAPONS)
1570             return static_cast<weapon_type>(item.sub_type);
1571         if (item.base_type == OBJ_STAVES)
1572             return WPN_STAFF;
1573         return WPN_UNKNOWN;
1574     }();
1575 
1576     // Non-weapons.
1577     if (wpn_type == WPN_UNKNOWN)
1578         return HANDS_ONE;
1579     if (is_unrandom_artefact(item, UNRAND_GYRE))
1580         return HANDS_TWO;
1581     return size >= Weapon_prop[Weapon_index[wpn_type]].min_1h_size ? HANDS_ONE
1582                                                                    : HANDS_TWO;
1583 }
1584 
hands_reqd(const actor * ac,object_class_type base_type,int sub_type)1585 hands_reqd_type hands_reqd(const actor* ac, object_class_type base_type, int sub_type)
1586 {
1587     item_def item;
1588     item.base_type = base_type;
1589     item.sub_type  = sub_type;
1590     // This function is used for item generation only, so use the actor's
1591     // (player's) base size, not its current form.
1592     return ac->hands_reqd(item, true);
1593 }
1594 
1595 /**
1596  * Is the provided type a kind of giant club?
1597  *
1598  * @param wpn_type  The weapon_type under consideration.
1599  * @return          Whether it's a kind of giant club.
1600  */
is_giant_club_type(int wpn_type)1601 bool is_giant_club_type(int wpn_type)
1602 {
1603     return wpn_type == WPN_GIANT_CLUB
1604            || wpn_type == WPN_GIANT_SPIKED_CLUB;
1605 }
1606 
1607 /**
1608  * Is the provided type a kind of ranged weapon?
1609  *
1610  * @param wpn_type  The weapon_type under consideration.
1611  * @return          Whether it's a kind of launcher.
1612  */
is_ranged_weapon_type(int wpn_type)1613 bool is_ranged_weapon_type(int wpn_type)
1614 {
1615     return Weapon_prop[Weapon_index[wpn_type]].ammo != MI_NONE;
1616 }
1617 
1618 /**
1619  * Is the provided type a kind of demon weapon?
1620  *
1621  * @param wpn_type  The weapon_type under consideration.
1622  * @return          Whether it's a kind of demon weapon.
1623  */
is_demonic_weapon_type(int wpn_type)1624 bool is_demonic_weapon_type(int wpn_type)
1625 {
1626     return wpn_type == WPN_DEMON_BLADE
1627            || wpn_type == WPN_DEMON_WHIP
1628            || wpn_type == WPN_DEMON_TRIDENT;
1629 }
1630 
1631 /**
1632  * Is the provided type a kind of blessed weapon?
1633  *
1634  * @param wpn_type  The weapon_type under consideration.
1635  * @return          Whether it's a kind of blessed weapon.
1636  */
is_blessed_weapon_type(int wpn_type)1637 bool is_blessed_weapon_type(int wpn_type)
1638 {
1639     return wpn_type == WPN_EUDEMON_BLADE
1640            || wpn_type == WPN_SACRED_SCOURGE
1641            || wpn_type == WPN_TRISHULA;
1642 }
1643 
is_melee_weapon(const item_def & weapon)1644 bool is_melee_weapon(const item_def &weapon)
1645 {
1646     return is_weapon(weapon) && !is_range_weapon(weapon);
1647 }
1648 
1649 /**
1650  * Is the provided item a demon weapon?
1651  *
1652  * @param item  The item under consideration.
1653  * @return      Whether the given item is a demon weapon.
1654  */
is_demonic(const item_def & item)1655 bool is_demonic(const item_def &item)
1656 {
1657     return item.base_type == OBJ_WEAPONS
1658            && is_demonic_weapon_type(item.sub_type);
1659 }
1660 
1661 /**
1662  * Is the provided item a blessed weapon? (Not just holy wrath.)
1663  *
1664  * @param item  The item under consideration.
1665  * @return      Whether the given item is a blessed weapon.
1666  */
is_blessed(const item_def & item)1667 bool is_blessed(const item_def &item)
1668 {
1669     return item.base_type == OBJ_WEAPONS
1670             && is_blessed_weapon_type(item.sub_type);
1671 }
1672 
is_blessed_convertible(const item_def & item)1673 bool is_blessed_convertible(const item_def &item)
1674 {
1675     return !is_artefact(item)
1676            && (item.base_type == OBJ_WEAPONS
1677                && (is_demonic(item)
1678                    || is_blessed(item)));
1679 }
1680 
1681 static map<weapon_type, weapon_type> _holy_upgrades =
1682 {
1683     { WPN_DEMON_BLADE, WPN_EUDEMON_BLADE },
1684     { WPN_DEMON_WHIP, WPN_SACRED_SCOURGE },
1685     { WPN_DEMON_TRIDENT, WPN_TRISHULA },
1686 };
1687 
convert2good(item_def & item)1688 bool convert2good(item_def &item)
1689 {
1690     if (item.base_type != OBJ_WEAPONS)
1691         return false;
1692 
1693     if (auto repl = map_find(_holy_upgrades, (weapon_type) item.sub_type))
1694     {
1695         item.sub_type = *repl;
1696         return true;
1697     }
1698 
1699     return false;
1700 }
1701 
convert2bad(item_def & item)1702 bool convert2bad(item_def &item)
1703 {
1704     if (item.base_type != OBJ_WEAPONS)
1705         return false;
1706 
1707     auto it = find_if(begin(_holy_upgrades), end(_holy_upgrades),
1708                       [&item](const pair<const weapon_type, weapon_type> elt)
1709                       {
1710                           return elt.second == item.sub_type;
1711                       });
1712     if  (it != end(_holy_upgrades))
1713     {
1714         item.sub_type = it->first;
1715         return true;
1716     }
1717 
1718     return false;
1719 }
1720 
is_brandable_weapon(const item_def & wpn,bool allow_ranged,bool divine)1721 bool is_brandable_weapon(const item_def &wpn, bool allow_ranged, bool divine)
1722 {
1723     if (wpn.base_type != OBJ_WEAPONS)
1724         return false;
1725 
1726     if (is_artefact(wpn))
1727         return false;
1728 
1729     if (!allow_ranged && is_range_weapon(wpn)
1730 #if TAG_MAJOR_VERSION == 34
1731         || wpn.sub_type == WPN_BLOWGUN
1732 #endif
1733        )
1734     {
1735         return false;
1736     }
1737 
1738     // Only gods can rebrand blessed weapons, and they revert back to their
1739     // old base type in the process.
1740     if (is_blessed(wpn) && !divine)
1741         return false;
1742 
1743     return true;
1744 }
1745 
1746 /**
1747  * Returns the skill used by the given item to attack.
1748  *
1749  * @param item  The item under consideration.
1750  * @return      The skill used to attack with the given item; defaults to
1751  *              SK_FIGHTING if no melee or ranged skill applies.
1752  */
item_attack_skill(const item_def & item)1753 skill_type item_attack_skill(const item_def &item)
1754 {
1755     if (item.base_type == OBJ_WEAPONS)
1756         return Weapon_prop[ Weapon_index[item.sub_type] ].skill;
1757     else if (item.base_type == OBJ_STAVES)
1758         return SK_STAVES;
1759     else if (item.base_type == OBJ_MISSILES && (!has_launcher(item)
1760                 || item.is_type(OBJ_MISSILES, MI_STONE)))
1761     {
1762         return SK_THROWING;
1763     }
1764     // don't return skills for non-throwable ammo: without the launcher they're
1765     // just chaff. (Or at least, I think this is the motivation.)
1766 
1767     // This is used to mark that only fighting applies.
1768     return SK_FIGHTING;
1769 }
1770 
1771 /**
1772  * Returns the skill used by the given item type to attack.
1773  *
1774  * @param wclass  The item base type under consideration.
1775  * @param wtype   The item subtype under consideration.
1776  * @return      The skill used to attack with the given item type; defaults to
1777  *              SK_FIGHTING if no melee skill applies.
1778  */
item_attack_skill(object_class_type wclass,int wtype)1779 skill_type item_attack_skill(object_class_type wclass, int wtype)
1780 {
1781     item_def    wpn;
1782 
1783     wpn.base_type = wclass;
1784     wpn.sub_type = wtype;
1785 
1786     return item_attack_skill(wpn);
1787 }
1788 
1789 // True if item is a staff that deals extra damage based on Evocations skill,
1790 // or has an evocations-based passive effect (staff of Wucad Mu).
staff_uses_evocations(const item_def & item)1791 bool staff_uses_evocations(const item_def &item)
1792 {
1793     if (is_unrandom_artefact(item, UNRAND_ELEMENTAL_STAFF)
1794         || is_unrandom_artefact(item, UNRAND_OLGREB)
1795         || is_unrandom_artefact(item, UNRAND_WUCAD_MU))
1796     {
1797         return true;
1798     }
1799 
1800     return item.base_type == OBJ_STAVES;
1801 }
1802 
staff_skill(stave_type s)1803 skill_type staff_skill(stave_type s)
1804 {
1805     switch (s)
1806     {
1807     case STAFF_AIR:
1808         return SK_AIR_MAGIC;
1809     case STAFF_COLD:
1810         return SK_ICE_MAGIC;
1811     case STAFF_EARTH:
1812         return SK_EARTH_MAGIC;
1813     case STAFF_FIRE:
1814         return SK_FIRE_MAGIC;
1815     case STAFF_POISON:
1816         return SK_POISON_MAGIC;
1817     case STAFF_DEATH:
1818         return SK_NECROMANCY;
1819     case STAFF_CONJURATION:
1820         return SK_CONJURATIONS;
1821     default:
1822         return SK_NONE;
1823     }
1824 }
1825 
item_skills(const item_def & item,set<skill_type> & skills)1826 bool item_skills(const item_def &item, set<skill_type> &skills)
1827 {
1828     if (item.is_type(OBJ_BOOKS, BOOK_MANUAL))
1829     {
1830         const skill_type skill = static_cast<skill_type>(item.plus);
1831         if (!skill_default_shown(skill))
1832             skills.insert(skill);
1833     }
1834 
1835     // Jewellery with evokable abilities, wands and similar unwielded
1836     // evokers allow training.
1837     if (item_is_evokable(item, false, false, true)
1838         || item.base_type == OBJ_JEWELLERY
1839            && gives_ability(item))
1840     {
1841         skills.insert(SK_EVOCATIONS);
1842     }
1843 
1844     // Shields and abilities on armours allow training as long as your species
1845     // can wear them.
1846     if (item.base_type == OBJ_ARMOUR && can_wear_armour(item, false, true))
1847     {
1848         if (is_shield(item))
1849             skills.insert(SK_SHIELDS);
1850 
1851         if (gives_ability(item))
1852             skills.insert(SK_EVOCATIONS);
1853     }
1854 
1855     // Weapons and staves allow training as long as your species can wield them.
1856     if (!you.could_wield(item, true, true))
1857         return !skills.empty();
1858 
1859     if (item_is_evokable(item, false, false, false)
1860         || staff_uses_evocations(item)
1861         || item.base_type == OBJ_WEAPONS && gives_ability(item))
1862     {
1863         skills.insert(SK_EVOCATIONS);
1864     }
1865 
1866     if (item.base_type == OBJ_STAVES)
1867     {
1868         const skill_type staff_sk
1869                     = staff_skill(static_cast<stave_type>(item.sub_type));
1870         if (staff_sk != SK_NONE)
1871             skills.insert(staff_sk);
1872     }
1873 
1874     if (item.base_type == OBJ_WEAPONS && get_weapon_brand(item) == SPWPN_PAIN)
1875         skills.insert(SK_NECROMANCY);
1876 
1877     const skill_type sk = item_attack_skill(item);
1878     if (sk != SK_FIGHTING)
1879         skills.insert(sk);
1880 
1881     return !skills.empty();
1882 }
1883 
1884 /**
1885  * Checks if the provided weapon is wieldable by a creature of the given size.
1886  *
1887  * @param item      The weapon in question.
1888  * @param size      The size of the creature trying to wield the weapon.
1889  * @return          Whether a creature of the given size can wield the weapon.
1890  */
is_weapon_wieldable(const item_def & item,size_type size)1891 bool is_weapon_wieldable(const item_def &item, size_type size)
1892 {
1893     ASSERT(is_weapon(item));
1894 
1895     const int subtype = OBJ_STAVES == item.base_type ? int{WPN_STAFF}
1896                                                      : item.sub_type;
1897     return Weapon_prop[Weapon_index[subtype]].min_2h_size <= size;
1898 }
1899 
1900 //
1901 // Launcher and ammo functions:
1902 //
fires_ammo_type(const item_def & item)1903 missile_type fires_ammo_type(const item_def &item)
1904 {
1905     if (item.base_type != OBJ_WEAPONS)
1906         return MI_NONE;
1907 
1908     return Weapon_prop[Weapon_index[item.sub_type]].ammo;
1909 }
1910 
is_range_weapon(const item_def & item)1911 bool is_range_weapon(const item_def &item)
1912 {
1913     return is_weapon(item) && is_ranged_weapon_type(item.sub_type);
1914 }
1915 
ammo_name(missile_type ammo)1916 const char *ammo_name(missile_type ammo)
1917 {
1918     return ammo < 0 || ammo >= NUM_MISSILES ? "eggplant"
1919            : Missile_prop[ Missile_index[ammo] ].name;
1920 }
1921 
ammo_name(const item_def & bow)1922 const char *ammo_name(const item_def &bow)
1923 {
1924     ASSERT(is_range_weapon(bow));
1925     return ammo_name(fires_ammo_type(bow));
1926 }
1927 
ammo_name(const weapon_type bow)1928 const char *ammo_name(const weapon_type bow)
1929 {
1930     missile_type mi = Weapon_prop[Weapon_index[bow]].ammo;
1931     ASSERT(mi != MI_NONE);
1932     return ammo_name(mi);
1933 }
1934 
1935 // Returns true if item has an associated launcher.
has_launcher(const item_def & ammo)1936 bool has_launcher(const item_def &ammo)
1937 {
1938     ASSERT(ammo.base_type == OBJ_MISSILES);
1939     return ammo.sub_type != MI_LARGE_ROCK
1940 #if TAG_MAJOR_VERSION == 34
1941            && ammo.sub_type != MI_DART
1942 #endif
1943            && ammo.sub_type != MI_JAVELIN
1944            && ammo.sub_type != MI_BOOMERANG
1945            && ammo.sub_type != MI_THROWING_NET;
1946 }
1947 
1948 // Returns true if item can be reasonably thrown without a launcher.
is_throwable(const actor * actor,const item_def & wpn)1949 bool is_throwable(const actor *actor, const item_def &wpn)
1950 {
1951     if (wpn.base_type != OBJ_MISSILES)
1952         return false;
1953 
1954     if (actor)
1955     {
1956         const size_type bodysize = actor->body_size();
1957 
1958         if (wpn.sub_type == MI_LARGE_ROCK)
1959             return actor->can_throw_large_rocks();
1960 
1961         if (bodysize < SIZE_MEDIUM
1962             && wpn.sub_type == MI_JAVELIN)
1963         {
1964             return false;
1965         }
1966     }
1967 
1968     return Missile_prop[Missile_index[wpn.sub_type]].throwable;
1969 }
1970 
1971 // Decide if something is launched or thrown.
is_launched(const actor * actor,const item_def * launcher,const item_def & missile)1972 launch_retval is_launched(const actor *actor, const item_def *launcher,
1973                           const item_def &missile)
1974 {
1975     if (missile.base_type != OBJ_MISSILES)
1976         return launch_retval::FUMBLED;
1977 
1978     if (launcher && missile.launched_by(*launcher))
1979         return launch_retval::LAUNCHED;
1980 
1981     return is_throwable(actor, missile) ? launch_retval::THROWN : launch_retval::FUMBLED;
1982 }
1983 
1984 
1985 /**
1986  * Returns whether a given missile will always destroyed on impact.
1987  *
1988  * @param missile      The missile in question.
1989  * @return             Whether the missile should always be destroyed on
1990  *                     impact.
1991  */
ammo_always_destroyed(const item_def & missile)1992 bool ammo_always_destroyed(const item_def &missile)
1993 {
1994     const int brand = get_ammo_brand(missile);
1995     return brand == SPMSL_CHAOS
1996            || brand == SPMSL_DISPERSAL
1997            || brand == SPMSL_EXPLODING;
1998 }
1999 
2000 /**
2001  * Returns whether a given missile will never destroyed on impact.
2002  *
2003  * @param missile      The missile in question.
2004  * @return             Whether the missile should never be destroyed on impact.
2005  */
ammo_never_destroyed(const item_def & missile)2006 bool ammo_never_destroyed(const item_def &missile)
2007 {
2008     return missile.sub_type == MI_THROWING_NET;
2009 }
2010 
2011 /**
2012  * Returns the one_chance_in for a missile type for be destroyed on impact.
2013  *
2014  * @param missile_type      The missile type to get the mulch chance for.
2015  * @return                  The inverse of the missile type's mulch chance.
2016  */
ammo_type_destroy_chance(int missile_type)2017 int ammo_type_destroy_chance(int missile_type)
2018 {
2019     return Missile_prop[ Missile_index[missile_type] ].mulch_rate;
2020 }
2021 
2022 /**
2023  * Returns the base damage of a given item type.
2024  *
2025  * @param missile_type      The missile type to get the damage for.
2026  * @return                  The base damage of the given missile type.
2027  */
ammo_type_damage(int missile_type)2028 int ammo_type_damage(int missile_type)
2029 {
2030     return Missile_prop[ Missile_index[missile_type] ].dam;
2031 }
2032 
2033 
2034 //
2035 // Reaching functions:
2036 //
weapon_reach(const item_def & item)2037 reach_type weapon_reach(const item_def &item)
2038 {
2039     if (is_unrandom_artefact(item, UNRAND_RIFT))
2040         return REACH_THREE;
2041     if (item_attack_skill(item) == SK_POLEARMS)
2042         return REACH_TWO;
2043     return REACH_NONE;
2044 }
2045 
2046 //
2047 // Macguffins
2048 //
item_is_unique_rune(const item_def & item)2049 bool item_is_unique_rune(const item_def &item)
2050 {
2051     return item.base_type == OBJ_RUNES
2052            && item.sub_type != RUNE_DEMONIC
2053            && item.sub_type != RUNE_ABYSSAL;
2054 }
2055 
item_is_orb(const item_def & item)2056 bool item_is_orb(const item_def &item)
2057 {
2058     return item.is_type(OBJ_ORBS, ORB_ZOT);
2059 }
2060 
item_is_horn_of_geryon(const item_def & item)2061 bool item_is_horn_of_geryon(const item_def &item)
2062 {
2063     return item.is_type(OBJ_MISCELLANY, MISC_HORN_OF_GERYON);
2064 }
2065 
item_is_spellbook(const item_def & item)2066 bool item_is_spellbook(const item_def &item)
2067 {
2068     return item.base_type == OBJ_BOOKS
2069 #if TAG_MAJOR_VERSION == 34
2070            && item.sub_type != BOOK_BUGGY_DESTRUCTION
2071 #endif
2072            && item.sub_type != NUM_BOOKS
2073            && item.sub_type != BOOK_MANUAL;
2074 }
2075 
2076 //
2077 // Ring functions:
2078 
2079 // Returns whether jewellery has plusses.
jewellery_has_pluses(const item_def & item)2080 bool jewellery_has_pluses(const item_def &item)
2081 {
2082     ASSERT(item.base_type == OBJ_JEWELLERY);
2083 
2084     // not known -> no plusses
2085     if (!item_type_known(item))
2086         return false;
2087 
2088     return jewellery_type_has_plusses(item.sub_type);
2089 }
2090 
jewellery_type_has_plusses(int jewel_type)2091 bool jewellery_type_has_plusses(int jewel_type)
2092 {
2093     switch (jewel_type)
2094     {
2095     case RING_SLAYING:
2096     case RING_PROTECTION:
2097     case RING_EVASION:
2098     case RING_STRENGTH:
2099     case RING_INTELLIGENCE:
2100     case RING_DEXTERITY:
2101         return true;
2102 
2103     default:
2104         break;
2105     }
2106 
2107     return false;
2108 }
2109 
2110 // Returns true if having two rings of the same type on at the same
2111 // has more effect than just having one on.
ring_has_stackable_effect(const item_def & item)2112 bool ring_has_stackable_effect(const item_def &item)
2113 {
2114     ASSERT(item.base_type == OBJ_JEWELLERY);
2115     ASSERT(!jewellery_is_amulet(item));
2116 
2117     if (!item_type_known(item))
2118         return false;
2119 
2120     if (jewellery_has_pluses(item))
2121         return true;
2122 
2123     switch (item.sub_type)
2124     {
2125     case RING_PROTECTION_FROM_FIRE:
2126     case RING_PROTECTION_FROM_COLD:
2127     case RING_LIFE_PROTECTION:
2128     case RING_STEALTH:
2129     case RING_WIZARDRY:
2130     case RING_FIRE:
2131     case RING_ICE:
2132     case RING_WILLPOWER:
2133     case RING_MAGICAL_POWER:
2134         return true;
2135 
2136     default:
2137         break;
2138     }
2139 
2140     return false;
2141 }
2142 #if TAG_MAJOR_VERSION == 34
2143 
2144 //
2145 // Food functions:
2146 //
is_real_food(food_type)2147 bool is_real_food(food_type /*food*/)
2148 {
2149     return false;
2150 }
2151 #endif
2152 
2153 //
2154 // Generic item functions:
2155 //
get_armour_res_fire(const item_def & arm,bool check_artp)2156 int get_armour_res_fire(const item_def &arm, bool check_artp)
2157 {
2158     ASSERT(arm.base_type == OBJ_ARMOUR);
2159 
2160     int res = 0;
2161 
2162     // intrinsic armour abilities
2163     res += armour_type_prop(arm.sub_type, ARMF_RES_FIRE);
2164 
2165     // check ego resistance
2166     const int ego = get_armour_ego_type(arm);
2167     if (ego == SPARM_FIRE_RESISTANCE || ego == SPARM_RESISTANCE)
2168         res += 1;
2169 
2170     if (check_artp && is_artefact(arm))
2171         res += artefact_property(arm, ARTP_FIRE);
2172 
2173     return res;
2174 }
2175 
get_armour_res_cold(const item_def & arm,bool check_artp)2176 int get_armour_res_cold(const item_def &arm, bool check_artp)
2177 {
2178     ASSERT(arm.base_type == OBJ_ARMOUR);
2179 
2180     int res = 0;
2181 
2182     // intrinsic armour abilities
2183     res += armour_type_prop(arm.sub_type, ARMF_RES_COLD);
2184 
2185     // check ego resistance
2186     const int ego = get_armour_ego_type(arm);
2187     if (ego == SPARM_COLD_RESISTANCE || ego == SPARM_RESISTANCE)
2188         res += 1;
2189 
2190     if (check_artp && is_artefact(arm))
2191         res += artefact_property(arm, ARTP_COLD);
2192 
2193     return res;
2194 }
2195 
get_armour_res_poison(const item_def & arm,bool check_artp)2196 int get_armour_res_poison(const item_def &arm, bool check_artp)
2197 {
2198     ASSERT(arm.base_type == OBJ_ARMOUR);
2199 
2200     int res = 0;
2201 
2202     // intrinsic armour abilities
2203     res += armour_type_prop(arm.sub_type, ARMF_RES_POISON);
2204 
2205     // check ego resistance
2206     if (get_armour_ego_type(arm) == SPARM_POISON_RESISTANCE)
2207         res += 1;
2208 
2209     if (check_artp && is_artefact(arm))
2210         res += artefact_property(arm, ARTP_POISON);
2211 
2212     return res;
2213 }
2214 
get_armour_res_elec(const item_def & arm,bool check_artp)2215 int get_armour_res_elec(const item_def &arm, bool check_artp)
2216 {
2217     ASSERT(arm.base_type == OBJ_ARMOUR);
2218 
2219     int res = 0;
2220 
2221     // intrinsic armour abilities
2222     res += armour_type_prop(arm.sub_type, ARMF_RES_ELEC);
2223 
2224     if (check_artp && is_artefact(arm))
2225         res += artefact_property(arm, ARTP_ELECTRICITY);
2226 
2227     return res;
2228 }
2229 
get_armour_life_protection(const item_def & arm,bool check_artp)2230 int get_armour_life_protection(const item_def &arm, bool check_artp)
2231 {
2232     ASSERT(arm.base_type == OBJ_ARMOUR);
2233 
2234     int res = 0;
2235 
2236     // intrinsic armour abilities
2237     res += armour_type_prop(arm.sub_type, ARMF_RES_NEG);
2238 
2239     // check for ego resistance
2240     if (get_armour_ego_type(arm) == SPARM_POSITIVE_ENERGY)
2241         res += 1;
2242 
2243     if (check_artp && is_artefact(arm))
2244         res += artefact_property(arm, ARTP_NEGATIVE_ENERGY);
2245 
2246     return res;
2247 }
2248 
get_armour_willpower(const item_def & arm,bool check_artp)2249 int get_armour_willpower(const item_def &arm, bool check_artp)
2250 {
2251     ASSERT(arm.base_type == OBJ_ARMOUR);
2252 
2253     int res = 0;
2254 
2255     // intrinsic armour abilities
2256     res += armour_type_prop(arm.sub_type, ARMF_WILLPOWER) * WL_PIP;
2257 
2258     // check for ego resistance
2259     if (get_armour_ego_type(arm) == SPARM_WILLPOWER)
2260         res += WL_PIP;
2261 
2262     if (check_artp && is_artefact(arm))
2263         res += WL_PIP * artefact_property(arm, ARTP_WILLPOWER);
2264 
2265     return res;
2266 }
2267 
get_armour_see_invisible(const item_def & arm,bool check_artp)2268 bool get_armour_see_invisible(const item_def &arm, bool check_artp)
2269 {
2270     ASSERT(arm.base_type == OBJ_ARMOUR);
2271 
2272     // check for ego resistance
2273     if (get_armour_ego_type(arm) == SPARM_SEE_INVISIBLE)
2274         return true;
2275 
2276     if (check_artp && is_artefact(arm))
2277         return artefact_property(arm, ARTP_SEE_INVISIBLE);
2278 
2279     return false;
2280 }
2281 
get_armour_res_corr(const item_def & arm)2282 int get_armour_res_corr(const item_def &arm)
2283 {
2284     ASSERT(arm.base_type == OBJ_ARMOUR);
2285 
2286     // intrinsic armour abilities
2287     return get_armour_ego_type(arm) == SPARM_PRESERVATION
2288            || armour_type_prop(arm.sub_type, ARMF_RES_CORR);
2289 }
2290 
get_armour_repel_missiles(const item_def & arm,bool check_artp)2291 int get_armour_repel_missiles(const item_def &arm, bool check_artp)
2292 {
2293     ASSERT(arm.base_type == OBJ_ARMOUR);
2294 
2295     // check for ego resistance
2296     if (get_armour_ego_type(arm) == SPARM_REPULSION)
2297         return true;
2298 
2299     if (check_artp && is_artefact(arm))
2300         return artefact_property(arm, ARTP_RMSL);
2301 
2302     return false;
2303 }
2304 
get_armour_rampaging(const item_def & arm,bool check_artp)2305 bool get_armour_rampaging(const item_def &arm, bool check_artp)
2306 {
2307     ASSERT(arm.base_type == OBJ_ARMOUR);
2308 
2309     if (is_unrandom_artefact(arm, UNRAND_SEVEN_LEAGUE_BOOTS))
2310         return true;
2311 
2312     // check for ego resistance
2313     if (get_armour_ego_type(arm) == SPARM_RAMPAGING)
2314         return true;
2315 
2316     if (check_artp && is_artefact(arm))
2317         return artefact_property(arm, ARTP_RAMPAGING);
2318 
2319     return false;
2320 }
2321 
get_jewellery_res_fire(const item_def & ring,bool check_artp)2322 int get_jewellery_res_fire(const item_def &ring, bool check_artp)
2323 {
2324     ASSERT(ring.base_type == OBJ_JEWELLERY);
2325 
2326     int res = 0;
2327 
2328     // intrinsic jewellery abilities
2329     switch (ring.sub_type)
2330     {
2331     case RING_PROTECTION_FROM_FIRE:
2332     case RING_FIRE:
2333         res += 1;
2334         break;
2335     case RING_ICE:
2336         res -= 1;
2337         break;
2338     default:
2339         break;
2340     }
2341 
2342     if (check_artp && is_artefact(ring))
2343         res += artefact_property(ring, ARTP_FIRE);
2344 
2345     return res;
2346 }
2347 
get_jewellery_res_cold(const item_def & ring,bool check_artp)2348 int get_jewellery_res_cold(const item_def &ring, bool check_artp)
2349 {
2350     ASSERT(ring.base_type == OBJ_JEWELLERY);
2351 
2352     int res = 0;
2353 
2354     // intrinsic jewellery abilities
2355     switch (ring.sub_type)
2356     {
2357     case RING_PROTECTION_FROM_COLD:
2358     case RING_ICE:
2359         res += 1;
2360         break;
2361     case RING_FIRE:
2362         res -= 1;
2363         break;
2364     default:
2365         break;
2366     }
2367 
2368     if (check_artp && is_artefact(ring))
2369         res += artefact_property(ring, ARTP_COLD);
2370 
2371     return res;
2372 }
2373 
get_jewellery_res_poison(const item_def & ring,bool check_artp)2374 int get_jewellery_res_poison(const item_def &ring, bool check_artp)
2375 {
2376     ASSERT(ring.base_type == OBJ_JEWELLERY);
2377 
2378     int res = 0;
2379 
2380     if (ring.sub_type == RING_POISON_RESISTANCE)
2381         res += 1;
2382 
2383     if (check_artp && is_artefact(ring))
2384         res += artefact_property(ring, ARTP_POISON);
2385 
2386     return res;
2387 }
2388 
get_jewellery_res_elec(const item_def & ring,bool check_artp)2389 int get_jewellery_res_elec(const item_def &ring, bool check_artp)
2390 {
2391     ASSERT(ring.base_type == OBJ_JEWELLERY);
2392 
2393     int res = 0;
2394 
2395     if (check_artp && is_artefact(ring))
2396         res += artefact_property(ring, ARTP_ELECTRICITY);
2397 
2398     return res;
2399 }
2400 
get_jewellery_life_protection(const item_def & ring,bool check_artp)2401 int get_jewellery_life_protection(const item_def &ring, bool check_artp)
2402 {
2403     ASSERT(ring.base_type == OBJ_JEWELLERY);
2404 
2405     int res = 0;
2406 
2407     // check for ego resistance
2408     if (ring.sub_type == RING_LIFE_PROTECTION)
2409         res += 1;
2410 
2411     if (check_artp && is_artefact(ring))
2412         res += artefact_property(ring, ARTP_NEGATIVE_ENERGY);
2413 
2414     return res;
2415 }
2416 
get_jewellery_willpower(const item_def & ring,bool check_artp)2417 int get_jewellery_willpower(const item_def &ring, bool check_artp)
2418 {
2419     ASSERT(ring.base_type == OBJ_JEWELLERY);
2420 
2421     int res = 0;
2422 
2423     if (ring.sub_type == RING_WILLPOWER)
2424         res += WL_PIP;
2425 
2426     if (check_artp && is_artefact(ring))
2427         res += WL_PIP * artefact_property(ring, ARTP_WILLPOWER);
2428 
2429     return res;
2430 }
2431 
get_jewellery_see_invisible(const item_def & ring,bool check_artp)2432 bool get_jewellery_see_invisible(const item_def &ring, bool check_artp)
2433 {
2434     ASSERT(ring.base_type == OBJ_JEWELLERY);
2435 
2436     if (ring.sub_type == RING_SEE_INVISIBLE)
2437         return true;
2438 
2439     if (check_artp && is_artefact(ring))
2440         return artefact_property(ring, ARTP_SEE_INVISIBLE);
2441 
2442     return false;
2443 }
2444 
property(const item_def & item,int prop_type)2445 int property(const item_def &item, int prop_type)
2446 {
2447     weapon_type weapon_sub;
2448 
2449     switch (item.base_type)
2450     {
2451     case OBJ_ARMOUR:
2452         return armour_prop(item.sub_type, prop_type);
2453 
2454     case OBJ_WEAPONS:
2455         if (is_unrandom_artefact(item))
2456         {
2457             switch (prop_type)
2458             {
2459             case PWPN_DAMAGE:
2460                 return Weapon_prop[ Weapon_index[item.sub_type] ].dam
2461                        + artefact_property(item, ARTP_BASE_DAM);
2462             case PWPN_HIT:
2463                 return Weapon_prop[ Weapon_index[item.sub_type] ].hit
2464                        + artefact_property(item, ARTP_BASE_ACC);
2465             case PWPN_SPEED:
2466                 return Weapon_prop[ Weapon_index[item.sub_type] ].speed
2467                        + artefact_property(item, ARTP_BASE_DELAY);
2468             }
2469         }
2470         if (prop_type == PWPN_DAMAGE)
2471             return Weapon_prop[ Weapon_index[item.sub_type] ].dam;
2472         else if (prop_type == PWPN_HIT)
2473             return Weapon_prop[ Weapon_index[item.sub_type] ].hit;
2474         else if (prop_type == PWPN_SPEED)
2475             return Weapon_prop[ Weapon_index[item.sub_type] ].speed;
2476         else if (prop_type == PWPN_ACQ_WEIGHT)
2477             return Weapon_prop[ Weapon_index[item.sub_type] ].acquire_weight;
2478         break;
2479 
2480     case OBJ_MISSILES:
2481         if (prop_type == PWPN_DAMAGE)
2482             return Missile_prop[ Missile_index[item.sub_type] ].dam;
2483         break;
2484 
2485     case OBJ_STAVES:
2486         weapon_sub = WPN_STAFF;
2487 
2488         if (prop_type == PWPN_DAMAGE)
2489             return Weapon_prop[ Weapon_index[weapon_sub] ].dam;
2490         else if (prop_type == PWPN_HIT)
2491             return Weapon_prop[ Weapon_index[weapon_sub] ].hit;
2492         else if (prop_type == PWPN_SPEED)
2493             return Weapon_prop[ Weapon_index[weapon_sub] ].speed;
2494         break;
2495 
2496     default:
2497         break;
2498     }
2499 
2500     return 0;
2501 }
2502 
2503 /**
2504  * Find a given property of a given armour_type.
2505  *
2506  * @param armour        The armour_type in question (e.g. ARM_ROBE)
2507  * @param prop_type     The property being requested (e.g. PARM_AC)
2508  * @return              The property value, if the prop_type is valid.
2509  *                      Otherwise, 0 (!?)
2510  *                      ^ hopefully never comes up...
2511  */
armour_prop(int armour,int prop_type)2512 int armour_prop(int armour, int prop_type)
2513 {
2514     switch (prop_type)
2515     {
2516         case PARM_AC:
2517             return Armour_prop[ Armour_index[armour] ].ac;
2518         case PARM_EVASION:
2519             return Armour_prop[ Armour_index[armour] ].ev;
2520         default:
2521             return 0; // !?
2522     }
2523 }
2524 
2525 // Returns true if item is evokable.
gives_ability(const item_def & item)2526 bool gives_ability(const item_def &item)
2527 {
2528     if (!item_type_known(item))
2529         return false;
2530 
2531     switch (item.base_type)
2532     {
2533     case OBJ_WEAPONS:
2534         break;
2535     case OBJ_ARMOUR:
2536     {
2537         const equipment_type eq = get_armour_slot(item);
2538         if (eq == EQ_NONE)
2539             return false;
2540         const special_armour_type ego = get_armour_ego_type(item);
2541 
2542         if (ego == SPARM_INVISIBILITY || ego == SPARM_FLYING)
2543             return true;
2544         break;
2545     }
2546     default:
2547         return false;
2548     }
2549 
2550     if (!is_artefact(item))
2551         return false;
2552 
2553     // Check for evokable randart properties.
2554     if (artefact_property(item, ARTP_INVISIBLE)
2555         || artefact_property(item, ARTP_BLINK)
2556         || artefact_property(item, ARTP_BERSERK))
2557     {
2558         return true;
2559     }
2560 
2561     // Unrands that grant an evokable ability.
2562     if (is_unrandom_artefact(item, UNRAND_RCLOUDS))
2563         return true;
2564 
2565     return false;
2566 }
2567 
2568 // Returns true if the item confers a resistance that is shown on the % screen,
2569 // for the purposes of giving information in hints mode.
gives_resistance(const item_def & item)2570 bool gives_resistance(const item_def &item)
2571 {
2572     if (!item_type_known(item))
2573         return false;
2574 
2575     switch (item.base_type)
2576     {
2577     case OBJ_WEAPONS:
2578         break;
2579     case OBJ_JEWELLERY:
2580         if (!jewellery_is_amulet(item))
2581         {
2582             if (item.sub_type == RING_PROTECTION_FROM_FIRE
2583                 || item.sub_type == RING_POISON_RESISTANCE
2584                 || item.sub_type == RING_PROTECTION_FROM_COLD
2585                 || item.sub_type == RING_RESIST_CORROSION
2586                 || item.sub_type == RING_LIFE_PROTECTION
2587                 || item.sub_type == RING_WILLPOWER
2588                 || item.sub_type == RING_FIRE
2589                 || item.sub_type == RING_ICE
2590                 || item.sub_type == RING_FLIGHT)
2591             {
2592                 return true;
2593             }
2594         }
2595         break;
2596     case OBJ_ARMOUR:
2597     {
2598         const equipment_type eq = get_armour_slot(item);
2599         if (eq == EQ_NONE)
2600             return false;
2601 
2602         const int ego = get_armour_ego_type(item);
2603         if (ego == SPARM_FIRE_RESISTANCE
2604             || ego == SPARM_COLD_RESISTANCE
2605             || ego == SPARM_POISON_RESISTANCE
2606             || ego == SPARM_WILLPOWER
2607             || ego == SPARM_RESISTANCE
2608             || ego == SPARM_PRESERVATION
2609             || ego == SPARM_POSITIVE_ENERGY)
2610         {
2611             return true;
2612         }
2613         break;
2614     }
2615     case OBJ_STAVES:
2616         if (item.sub_type == STAFF_FIRE
2617             || item.sub_type == STAFF_COLD
2618             || item.sub_type == STAFF_POISON
2619             || item.sub_type == STAFF_AIR
2620             || item.sub_type == STAFF_DEATH)
2621         {
2622             return true;
2623         }
2624         return false;
2625     default:
2626         return false;
2627     }
2628 
2629     if (!is_artefact(item))
2630         return false;
2631 
2632     // Check for randart resistances.
2633     for (int rap = 0; rap < ARTP_NUM_PROPERTIES; rap++)
2634     {
2635         if (artefact_property(item, static_cast<artefact_prop_type>(rap))
2636             && (rap == ARTP_FIRE
2637                 || rap == ARTP_COLD
2638                 || rap == ARTP_ELECTRICITY
2639                 || rap == ARTP_POISON
2640                 || rap == ARTP_NEGATIVE_ENERGY
2641                 || rap == ARTP_WILLPOWER
2642                 || rap == ARTP_RCORR
2643                 || rap == ARTP_RMUT))
2644         {
2645             return true;
2646         }
2647     }
2648 
2649     return false;
2650 }
2651 
item_is_jelly_edible(const item_def & item)2652 bool item_is_jelly_edible(const item_def &item)
2653 {
2654     if (item_is_stationary_net(item))
2655         return false;
2656 
2657     // Don't eat artefacts or the horn of Geryon.
2658     if (is_artefact(item) || item_is_horn_of_geryon(item))
2659         return false;
2660 
2661     // Don't eat zigfigs. (They're artefact-like, and Jiyvaites shouldn't worry
2662     // about losing them.)
2663     if (item.base_type == OBJ_MISCELLANY && item.sub_type == MISC_ZIGGURAT)
2664         return false;
2665 
2666     // Don't eat mimics.
2667     if (item.flags & ISFLAG_MIMIC)
2668         return false;
2669 
2670     // Don't eat special game items.
2671     if (item_is_orb(item) || item.base_type == OBJ_RUNES)
2672         return false;
2673 
2674     return true;
2675 }
2676 
get_item_slot(const item_def & item)2677 equipment_type get_item_slot(const item_def& item)
2678 {
2679     return get_item_slot(item.base_type, item.sub_type);
2680 }
2681 
get_item_slot(object_class_type type,int sub_type)2682 equipment_type get_item_slot(object_class_type type, int sub_type)
2683 {
2684     switch (type)
2685     {
2686     case OBJ_WEAPONS:
2687     case OBJ_STAVES:
2688 #if TAG_MAJOR_VERSION == 34
2689     case OBJ_RODS:
2690 #endif
2691     case OBJ_MISCELLANY:
2692         return EQ_WEAPON;
2693 
2694     case OBJ_ARMOUR:
2695         return get_armour_slot(static_cast<armour_type>(sub_type));
2696 
2697     case OBJ_JEWELLERY:
2698         return jewellery_is_amulet(sub_type) ? EQ_AMULET : EQ_RINGS;
2699 
2700     default:
2701         break;
2702     }
2703 
2704     return EQ_NONE;
2705 }
2706 
is_shield(const item_def & item)2707 bool is_shield(const item_def &item)
2708 {
2709     return item.base_type == OBJ_ARMOUR
2710            && get_armour_slot(item) == EQ_SHIELD;
2711 }
2712 
2713 // Returns true if the given item cannot be wielded _by you_ with the given shield.
2714 // The currently equipped shield is used if no shield is passed in.
is_shield_incompatible(const item_def & weapon,const item_def * shield)2715 bool is_shield_incompatible(const item_def &weapon, const item_def *shield)
2716 {
2717     // If there's no shield, there's no problem.
2718     if (!shield && !(shield = you.shield()))
2719         return false;
2720 
2721     hands_reqd_type hand = you.hands_reqd(weapon);
2722     return hand == HANDS_TWO;
2723 }
2724 
shield_reflects(const item_def & shield)2725 bool shield_reflects(const item_def &shield)
2726 {
2727     ASSERT(is_shield(shield));
2728 
2729     return get_armour_ego_type(shield) == SPARM_REFLECTION;
2730 }
2731 
ident_reflector(item_def * item)2732 void ident_reflector(item_def *item)
2733 {
2734     if (!is_artefact(*item))
2735         set_ident_flags(*item, ISFLAG_KNOW_TYPE);
2736 }
2737 
item_base_name(const item_def & item)2738 string item_base_name(const item_def &item)
2739 {
2740     return item_base_name(item.base_type, item.sub_type);
2741 }
2742 
item_base_name(object_class_type type,int sub_type)2743 string item_base_name(object_class_type type, int sub_type)
2744 {
2745     switch (type)
2746     {
2747     case OBJ_WEAPONS:
2748         return Weapon_prop[Weapon_index[sub_type]].name;
2749     case OBJ_MISSILES:
2750         return Missile_prop[Missile_index[sub_type]].name;
2751     case OBJ_ARMOUR:
2752         return Armour_prop[Armour_index[sub_type]].name;
2753     case OBJ_JEWELLERY:
2754         return jewellery_is_amulet(sub_type) ? "amulet" : "ring";
2755     default:
2756         return "";
2757     }
2758 }
2759 
weapon_base_name(weapon_type subtype)2760 const char* weapon_base_name(weapon_type subtype)
2761 {
2762     return Weapon_prop[Weapon_index[subtype]].name;
2763 }
2764 
remove_whitespace(string & str)2765 void remove_whitespace(string &str)
2766 {
2767     str.erase(remove_if(str.begin(), str.end(),
2768         static_cast<int(*)(int)>(isspace)), str.end());
2769 }
2770 
2771 /**
2772  * Try to find a weapon, given the weapon's name without whitespace.
2773  *
2774  * @param name_nospace  The weapon's base name, with all whitespace removed.
2775  * @return              The id of the weapon, or WPN_UNKNOWN if nothing matches.
2776  */
name_nospace_to_weapon(string name_nospace)2777 weapon_type name_nospace_to_weapon(string name_nospace)
2778 {
2779     for (const weapon_def &wpn : Weapon_prop)
2780     {
2781         string weap_nospace = wpn.name;
2782         remove_whitespace(weap_nospace);
2783 
2784         if (name_nospace == weap_nospace)
2785             return (weapon_type) wpn.id;
2786     }
2787 
2788     // No match found
2789     return WPN_UNKNOWN;
2790 }
2791 
seen_item(const item_def & item)2792 void seen_item(const item_def &item)
2793 {
2794     if (!is_artefact(item) && _is_affordable(item))
2795     {
2796         // Known brands will be set in set_item_flags().
2797         if (item.base_type == OBJ_WEAPONS)
2798             you.seen_weapon[item.sub_type] |= 1U << SP_UNKNOWN_BRAND;
2799         if (item.base_type == OBJ_ARMOUR)
2800             you.seen_armour[item.sub_type] |= 1U << SP_UNKNOWN_BRAND;
2801         if (item.base_type == OBJ_MISCELLANY)
2802             you.seen_misc.set(item.sub_type);
2803     }
2804 
2805     _maybe_note_found_unrand(item);
2806 
2807     // major hack. Deconstify should be safe here, but it's still repulsive.
2808     item_def& malleable_item = const_cast<item_def &>(item);
2809 
2810     malleable_item.flags |= ISFLAG_SEEN;
2811     if (item.base_type == OBJ_GOLD && !item.tithe_state)
2812     {
2813         malleable_item.plus = (you_worship(GOD_ZIN)) ? TS_FULL_TITHE
2814                                                      : TS_NO_PIETY;
2815     }
2816 
2817     if (item_type_has_ids(item.base_type) && !is_artefact(item)
2818         && item_ident(item, ISFLAG_KNOW_TYPE)
2819         && !you.type_ids[item.base_type][item.sub_type])
2820     {
2821         // Can't cull shop items here -- when called from view, we shouldn't
2822         // access the UI. Old ziggurat prompts are a very minor case of what
2823         // could go wrong.
2824         set_ident_type(item.base_type, item.sub_type, true);
2825     }
2826 }
2827 
2828 /**
2829  * Is the given item an xp-charged evocable? (That is, one that recharges as
2830  * the player gains xp.)
2831  *
2832  * @param item      The item in question.
2833  * @return          Whether the given item is an xp evocable. (One of the
2834  *                  elemental evocables or the Horn of Geryon.)
2835  */
is_xp_evoker(const item_def & item)2836 bool is_xp_evoker(const item_def &item)
2837 {
2838     return item.base_type == OBJ_MISCELLANY
2839            && map_find(xp_evoker_data,
2840                        static_cast<misc_item_type>(item.sub_type));
2841 }
2842 
2843 /**
2844  * Return the xp debt corresponding to the given type of evoker.
2845  * Asserts that the given evoker type actually corresponds to an xp evoker.
2846  *
2847  * @param evoker_type       The misc_item_type of the evoker in question.
2848  * @return                  The level of xp debt the given evoker type has
2849  *                          before it can be used again.
2850  */
evoker_debt(int evoker_type)2851 int &evoker_debt(int evoker_type)
2852 {
2853     const evoker_data* edata = map_find(xp_evoker_data,
2854                                    static_cast<misc_item_type>(evoker_type));
2855     ASSERT(edata);
2856     return you.props[edata->key].get_int();
2857 }
2858 
2859 /**
2860  * How many max charges can the given XP evoker have?
2861  *
2862  * @param evoker_type The type of evoker.
2863  * @returns The max number of charges.
2864  */
evoker_max_charges(int evoker_type)2865 int evoker_max_charges(int evoker_type)
2866 {
2867     const evoker_data* edata = map_find(xp_evoker_data,
2868                                    static_cast<misc_item_type>(evoker_type));
2869     ASSERT(edata);
2870     return edata->max_charges;
2871 }
2872 
2873 /**
2874  * What is the XP debt of using one charge of the given XP evoker type? This
2875  * debt represents a cost after scaling by a level-based XP factor.
2876  *
2877  * @params evoker_type The item sub type of the evoker
2878  * @returns The debt of using a charge.
2879  */
evoker_charge_xp_debt(int evoker_type)2880 int evoker_charge_xp_debt(int evoker_type)
2881 {
2882     const evoker_data* edata = map_find(xp_evoker_data,
2883                                         static_cast<misc_item_type>(evoker_type));
2884     ASSERT(edata);
2885     return edata->charge_xp_debt;
2886 }
2887 
2888 /**
2889  * How many remaining charges does the given XP evoker have?
2890  *
2891  * @param evoker_type The item subtype of the evoker.
2892  * @returns The number of remaining charges.
2893  */
evoker_charges(int evoker_type)2894 int evoker_charges(int evoker_type)
2895 {
2896     const int max_charges = evoker_max_charges(evoker_type);
2897     const int charge_xp_debt = evoker_charge_xp_debt(evoker_type);
2898     const int debt = evoker_debt(evoker_type);
2899     return min(max_charges,
2900             max_charges - debt / charge_xp_debt - (debt % charge_xp_debt > 0));
2901 }
2902 
expend_xp_evoker(int evoker_type)2903 void expend_xp_evoker(int evoker_type)
2904 {
2905     evoker_debt(evoker_type) += evoker_charge_xp_debt(evoker_type);
2906 }
2907 
2908 /// witchcraft. copied from mon-util.h's get_resist
_get_armour_flag(armflags_t all,armour_flag res)2909 static inline int _get_armour_flag(armflags_t all, armour_flag res)
2910 {
2911     if (res > ARMF_LAST_MULTI)
2912         return all & res ? 1 : 0;
2913     int v = (all / res) & 7;
2914     if (v > 4)
2915         return v - 8;
2916     return v;
2917 }
2918 
2919 /**
2920  * What inherent special properties does the given armour type have?
2921  *
2922  * @param arm   The given armour type.
2923  * @return      A bitfield of special properties.
2924  */
_armour_type_flags(const uint8_t arm)2925 static armflags_t _armour_type_flags(const uint8_t arm)
2926 {
2927     return Armour_prop[ Armour_index[arm] ].flags;
2928 }
2929 
2930 /**
2931  * What value does the given armour type have for the innate special property?
2932  *
2933  * @param arm   The given armour type.
2934  * @param prop  The property in question.
2935  * @return      A value for that property; ranges -3 to 4.
2936  */
armour_type_prop(const uint8_t arm,const armour_flag prop)2937 int armour_type_prop(const uint8_t arm, const armour_flag prop)
2938 {
2939     return _get_armour_flag(_armour_type_flags(arm), prop);
2940 }
2941 
2942 /**
2943  * For store pricing purposes, how much is the given type of weapon worth,
2944  * before curses, egos, etc are taken into account?
2945  *
2946  * @param type      The type of weapon in question; e.g. WPN_DAGGER.
2947  * @return          A value in gold; e.g. 20.
2948  */
weapon_base_price(weapon_type type)2949 int weapon_base_price(weapon_type type)
2950 {
2951     return Weapon_prop[ Weapon_index[type] ].price;
2952 }
2953 
2954 /**
2955  * For store pricing purposes, how much is the given type of missile worth?
2956  *
2957  * @param type      The type of missile in question; e.g. MI_ARROW.
2958  * @return          A value in gold for each missile; e.g. 20.
2959  */
missile_base_price(missile_type type)2960 int missile_base_price(missile_type type)
2961 {
2962     return Missile_prop[ Missile_index[type] ].price;
2963 }
2964 
2965 /**
2966  * For store pricing purposes, how much is the given type of armour worth,
2967  * before curses, egos, etc are taken into account?
2968  *
2969  * @param type      The type of weapon in question; e.g. ARM_RING_MAIL, or
2970  *                  ARM_BUCKLER.
2971  * @return          A value in gold; e.g. 45.
2972  */
armour_base_price(armour_type type)2973 int armour_base_price(armour_type type)
2974 {
2975     return Armour_prop[ Armour_index[type] ].price;
2976 }
2977