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