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