1 /**
2 * @file
3 * @brief Gods' attitude towards items.
4 **/
5
6 #include "AppHdr.h"
7
8 #include "god-item.h"
9
10 #include <algorithm>
11 #include <cmath>
12 #include <cstdio>
13 #include <cstdlib>
14 #include <cstring>
15 #include <sstream>
16
17 #include "artefact.h"
18 #include "art-enum.h"
19 #include "god-conduct.h"
20 #include "god-passive.h"
21 #include "item-name.h"
22 #include "item-prop.h"
23 #include "item-status-flag-type.h"
24 #include "items.h"
25 #include "libutil.h"
26 #include "potion-type.h"
27 #include "skills.h"
28 #include "spl-book.h"
29 #include "spl-util.h"
30
_is_book_type(const item_def & item,bool (* matches)(spell_type spell))31 static bool _is_book_type(const item_def& item,
32 bool (*matches)(spell_type spell))
33 {
34 if (!item.defined())
35 return false;
36
37 // Return false for item_defs of unknown subtype
38 // (== NUM_BOOKS in most cases, OBJ_RANDOM for acquirement)
39 if (item.sub_type == get_max_subtype(item.base_type)
40 || item.sub_type == OBJ_RANDOM)
41 {
42 return false;
43 }
44
45 if (!item_is_spellbook(item))
46 return false;
47
48 // Book matches only if all the spells match
49 for (spell_type spell : spells_in_book(item))
50 {
51 if (!matches(spell))
52 return false;
53 }
54 return true;
55 }
56
is_holy_item(const item_def & item,bool calc_unid)57 bool is_holy_item(const item_def& item, bool calc_unid)
58 {
59 bool retval = false;
60
61 if (is_unrandom_artefact(item))
62 {
63 const unrandart_entry* entry = get_unrand_entry(item.unrand_idx);
64
65 if (entry->flags & UNRAND_FLAG_HOLY)
66 return true;
67 }
68
69 if (item.base_type == OBJ_WEAPONS)
70 {
71 if (is_blessed(item))
72 return true;
73 if (calc_unid || item_brand_known(item))
74 return get_weapon_brand(item) == SPWPN_HOLY_WRATH;
75 }
76
77 if (!calc_unid && !item_type_known(item))
78 return false;
79
80 switch (item.base_type)
81 {
82 case OBJ_SCROLLS:
83 retval = (item.sub_type == SCR_HOLY_WORD);
84 break;
85 default:
86 break;
87 }
88
89 return retval;
90 }
91
is_potentially_evil_item(const item_def & item,bool calc_unid)92 bool is_potentially_evil_item(const item_def& item, bool calc_unid)
93 {
94 if (item.base_type == OBJ_WEAPONS
95 && item_brand_known(item)
96 && get_weapon_brand(item) == SPWPN_CHAOS)
97 {
98 return true;
99 }
100
101 if (!calc_unid && !item_type_known(item))
102 return false;
103
104 switch (item.base_type)
105 {
106 case OBJ_MISSILES:
107 {
108 const int item_brand = get_ammo_brand(item);
109 if (item_brand == SPMSL_CHAOS)
110 return true;
111 }
112 break;
113 case OBJ_MISCELLANY:
114 return item.sub_type == MISC_CONDENSER_VANE;
115 default:
116 break;
117 }
118
119 return false;
120 }
121
122 /**
123 * Do good gods always hate use of this item?
124 *
125 * @param item The item in question.
126 * @param calc_unid Whether to take into account facts the player does not know.
127 * @return Whether the Good Gods will always frown on this item's use.
128 */
is_evil_item(const item_def & item,bool calc_unid)129 bool is_evil_item(const item_def& item, bool calc_unid)
130 {
131 if (is_unrandom_artefact(item))
132 {
133 const unrandart_entry* entry = get_unrand_entry(item.unrand_idx);
134
135 if (entry->flags & UNRAND_FLAG_EVIL)
136 return true;
137 }
138
139 if (item.base_type == OBJ_WEAPONS)
140 {
141 if (is_demonic(item))
142 return true;
143 if (calc_unid || item_brand_known(item))
144 {
145 const int item_brand = get_weapon_brand(item);
146 return item_brand == SPWPN_DRAINING
147 || item_brand == SPWPN_PAIN
148 || item_brand == SPWPN_VAMPIRISM
149 || item_brand == SPWPN_REAPING;
150 }
151 }
152
153 if (!calc_unid && !item_type_known(item))
154 return false;
155
156 switch (item.base_type)
157 {
158 case OBJ_SCROLLS:
159 return item.sub_type == SCR_TORMENT;
160 case OBJ_STAVES:
161 return item.sub_type == STAFF_DEATH;
162 case OBJ_BOOKS:
163 return _is_book_type(item, is_evil_spell);
164 case OBJ_MISCELLANY:
165 return item.sub_type == MISC_HORN_OF_GERYON;
166 default:
167 return false;
168 }
169 }
170
is_unclean_item(const item_def & item,bool calc_unid)171 bool is_unclean_item(const item_def& item, bool calc_unid)
172 {
173 if (is_unrandom_artefact(item))
174 {
175 const unrandart_entry* entry = get_unrand_entry(item.unrand_idx);
176
177 if (entry->flags & UNRAND_FLAG_UNCLEAN)
178 return true;
179 }
180
181 if (item.has_spells() && (item_type_known(item) || calc_unid))
182 return _is_book_type(item, is_unclean_spell);
183
184 return false;
185 }
186
is_chaotic_item(const item_def & item,bool calc_unid)187 bool is_chaotic_item(const item_def& item, bool calc_unid)
188 {
189 bool retval = false;
190
191 if (is_unrandom_artefact(item))
192 {
193 const unrandart_entry* entry = get_unrand_entry(item.unrand_idx);
194
195 if (entry->flags & UNRAND_FLAG_CHAOTIC)
196 return true;
197 }
198
199 if (item.base_type == OBJ_WEAPONS
200 && (calc_unid || item_brand_known(item)))
201 {
202 return get_weapon_brand(item) == SPWPN_CHAOS;
203 }
204
205 if (!calc_unid && !item_type_known(item))
206 return false;
207
208 switch (item.base_type)
209 {
210 case OBJ_MISSILES:
211 {
212 const int item_brand = get_ammo_brand(item);
213 retval = (item_brand == SPMSL_CHAOS);
214 }
215 break;
216 case OBJ_WANDS:
217 retval = (item.sub_type == WAND_POLYMORPH);
218 break;
219 case OBJ_POTIONS:
220 retval = (item.sub_type == POT_MUTATION
221 && !have_passive(passive_t::cleanse_mut_potions))
222 || item.sub_type == POT_LIGNIFY;
223 break;
224 case OBJ_BOOKS:
225 retval = _is_book_type(item, is_chaotic_spell);
226 break;
227 case OBJ_MISCELLANY:
228 retval = (item.sub_type == MISC_BOX_OF_BEASTS
229 || item.sub_type == MISC_XOMS_CHESSBOARD);
230 break;
231 default:
232 break;
233 }
234
235 return retval;
236 }
237
_is_potentially_hasty_item(const item_def & item)238 static bool _is_potentially_hasty_item(const item_def& item)
239 {
240 if (item.base_type == OBJ_WEAPONS
241 && item_brand_known(item)
242 && get_weapon_brand(item) == SPWPN_CHAOS)
243 {
244 return true;
245 }
246
247 if (!item_type_known(item))
248 return false;
249
250 switch (item.base_type)
251 {
252 case OBJ_MISSILES:
253 {
254 const int item_brand = get_ammo_brand(item);
255 if (item_brand == SPMSL_CHAOS || item_brand == SPMSL_FRENZY)
256 return true;
257 }
258 break;
259 case OBJ_MISCELLANY:
260 if (item.sub_type == MISC_XOMS_CHESSBOARD)
261 return true;
262 break;
263 default:
264 break;
265 }
266
267 return false;
268 }
269
is_hasty_item(const item_def & item,bool calc_unid)270 bool is_hasty_item(const item_def& item, bool calc_unid)
271 {
272
273 if (is_artefact(item) && item.base_type != OBJ_BOOKS)
274 {
275 if ((calc_unid || item_ident(item, ISFLAG_KNOW_PROPERTIES)))
276 {
277 if (artefact_property(item, ARTP_RAMPAGING)
278 || artefact_property(item, ARTP_ANGRY))
279 {
280 return true;
281 }
282 // intentionally continue to other hasty checks
283 }
284 }
285
286 if (item.base_type == OBJ_WEAPONS)
287 {
288 if (calc_unid || item_brand_known(item))
289 return get_weapon_brand(item) == SPWPN_SPEED;
290 }
291
292 if (!calc_unid && !item_type_known(item))
293 return false;
294
295 switch (item.base_type)
296 {
297 case OBJ_ARMOUR:
298 return get_armour_rampaging(item, true)
299 || is_unrandom_artefact(item, UNRAND_LIGHTNING_SCALES);
300 case OBJ_POTIONS:
301 return item.sub_type == POT_HASTE
302 || item.sub_type == POT_BERSERK_RAGE;
303 case OBJ_BOOKS:
304 return _is_book_type(item, is_hasty_spell);
305 default:
306 break;
307 }
308
309 return false;
310 }
311
is_wizardly_item(const item_def & item,bool calc_unid)312 bool is_wizardly_item(const item_def& item, bool calc_unid)
313 {
314 if ((calc_unid || item_brand_known(item))
315 && get_weapon_brand(item) == SPWPN_PAIN)
316 {
317 return true;
318 }
319
320 if (is_unrandom_artefact(item, UNRAND_WUCAD_MU)
321 || is_unrandom_artefact(item, UNRAND_MAJIN)
322 || is_unrandom_artefact(item, UNRAND_BATTLE)
323 || is_unrandom_artefact(item, UNRAND_ELEMENTAL_STAFF)
324 || is_unrandom_artefact(item, UNRAND_OLGREB))
325 {
326 return true;
327 }
328
329 return item.base_type == OBJ_STAVES;
330 }
331
332 /**
333 * Do the good gods hate use of this spell?
334 *
335 * @param spell The spell in question; e.g. SPELL_CORPSE_ROT.
336 * @return Whether the Good Gods hate this spell.
337 */
is_evil_spell(spell_type spell)338 bool is_evil_spell(spell_type spell)
339 {
340 const spschools_type disciplines = get_spell_disciplines(spell);
341 spell_flags flags = get_spell_flags(spell);
342
343 if (flags & spflag::unholy)
344 return true;
345 return bool(disciplines & spschool::necromancy)
346 && !bool(flags & spflag::not_evil);
347 }
348
is_unclean_spell(spell_type spell)349 bool is_unclean_spell(spell_type spell)
350 {
351 spell_flags flags = get_spell_flags(spell);
352
353 return bool(flags & spflag::unclean);
354 }
355
is_chaotic_spell(spell_type spell)356 bool is_chaotic_spell(spell_type spell)
357 {
358 spell_flags flags = get_spell_flags(spell);
359
360 return bool(flags & spflag::chaotic);
361 }
362
is_hasty_spell(spell_type spell)363 bool is_hasty_spell(spell_type spell)
364 {
365 spell_flags flags = get_spell_flags(spell);
366
367 return bool(flags & spflag::hasty);
368 }
369
370 /**
371 * What conducts can one violate using this item?
372 * This should only be based on the player's knowledge.
373 *
374 * @param item The item in question.
375 * @return List of conducts that can be violated with this; empty if none.
376 */
item_conducts(const item_def & item)377 vector<conduct_type> item_conducts(const item_def &item)
378 {
379 vector<conduct_type> conducts;
380
381 if (is_evil_item(item, false))
382 conducts.push_back(DID_EVIL);
383
384 if (is_unclean_item(item, false))
385 conducts.push_back(DID_UNCLEAN);
386
387 if (is_chaotic_item(item, false))
388 conducts.push_back(DID_CHAOS);
389
390 if (is_holy_item(item, false))
391 conducts.push_back(DID_HOLY);
392
393 if (item_is_spellbook(item))
394 conducts.push_back(DID_SPELL_MEMORISE);
395
396 if ((item.sub_type == BOOK_MANUAL && item_type_known(item)
397 && is_magic_skill((skill_type)item.plus)))
398 {
399 conducts.push_back(DID_SPELL_PRACTISE);
400 }
401
402 if (is_wizardly_item(item, false))
403 conducts.push_back(DID_WIZARDLY_ITEM);
404
405 if (_is_potentially_hasty_item(item) || is_hasty_item(item, false))
406 conducts.push_back(DID_HASTY);
407
408 if (is_potentially_evil_item(item, false))
409 conducts.push_back(DID_EVIL);
410
411 return conducts;
412 }
413
god_hates_item(const item_def & item)414 bool god_hates_item(const item_def &item)
415 {
416 return god_hates_item_handling(item) != DID_NOTHING;
417 }
418
419 /**
420 * Does the given god like items of the given kind enough to make artefacts
421 * from them? (Thematically.)
422 *
423 * @param item The item which may be the basis for an artefact.
424 * @param which_god The god in question.
425 * @return Whether it makes sense for the given god to make an
426 * artefact out of the given item. Thematically.
427 * (E.g., Ely shouldn't be forging swords.)
428 */
god_likes_item_type(const item_def & item,god_type which_god)429 bool god_likes_item_type(const item_def &item, god_type which_god)
430 {
431 // XXX: also check god_hates_item()?
432 switch (which_god)
433 {
434 case GOD_ELYVILON: // Peaceful healer god: no weapons.
435 case GOD_SIF_MUNA: // The magic gods: no weapons.
436 case GOD_VEHUMET:
437 if (item.base_type == OBJ_WEAPONS)
438 return false;
439 break;
440
441 case GOD_TROG:
442 // Berserker god: weapons only.
443 if (item.base_type != OBJ_WEAPONS)
444 return false;
445 break;
446
447 default:
448 break;
449 }
450
451 return true;
452 }
453