/*
* File: goditem.cc
* Summary: Gods' attitude towards items.
*/
#include "AppHdr.h"
#include "goditem.h"
#include <algorithm>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <cmath>
#include "itemname.h"
#include "itemprop.h"
#include "religion.h"
#include "spl-book.h"
#include "spl-cast.h"
#include "spl-util.h"
bool is_holy_item(const item_def& item)
{
bool retval = false;
if (is_unrandom_artefact(item))
{
unrandart_entry* entry = get_unrand_entry(item.special);
if (entry->flags & UNRAND_FLAG_HOLY)
return (true);
}
switch (item.base_type)
{
case OBJ_WEAPONS:
retval = (is_blessed(item)
|| get_weapon_brand(item) == SPWPN_HOLY_WRATH);
break;
case OBJ_SCROLLS:
retval = (item.sub_type == SCR_HOLY_WORD);
break;
case OBJ_BOOKS:
retval = is_holy_spellbook(item);
break;
case OBJ_STAVES:
retval = is_holy_rod(item);
break;
default:
break;
}
return (retval);
}
bool is_unholy_item(const item_def& item)
{
bool retval = false;
if (is_unrandom_artefact(item))
{
unrandart_entry* entry = get_unrand_entry(item.special);
if (entry->flags & UNRAND_FLAG_UNHOLY)
return (true);
}
switch (item.base_type)
{
case OBJ_WEAPONS:
retval = is_demonic(item);
break;
case OBJ_SCROLLS:
retval = (item.sub_type == SCR_SUMMONING);
break;
case OBJ_BOOKS:
retval = is_unholy_spellbook(item);
break;
case OBJ_STAVES:
retval = is_unholy_rod(item);
break;
case OBJ_MISCELLANY:
retval = (item.sub_type == MISC_BOTTLED_EFREET);
break;
default:
break;
}
return (retval);
}
bool is_potentially_evil_item(const item_def& item)
{
switch (item.base_type)
{
case OBJ_WEAPONS:
{
const int item_brand = get_weapon_brand(item);
if (item_brand == SPWPN_CHAOS)
return (true);
}
break;
case OBJ_MISSILES:
{
const int item_brand = get_ammo_brand(item);
if (item_brand == SPMSL_CHAOS)
return (true);
}
break;
case OBJ_WANDS:
if (item.sub_type == WAND_RANDOM_EFFECTS)
return (true);
break;
default:
break;
}
return (false);
}
bool is_evil_item(const item_def& item)
{
bool retval = false;
if (is_unrandom_artefact(item))
{
unrandart_entry* entry = get_unrand_entry(item.special);
if (entry->flags & UNRAND_FLAG_EVIL)
return (true);
}
switch (item.base_type)
{
case OBJ_WEAPONS:
{
const int item_brand = get_weapon_brand(item);
retval = (item_brand == SPWPN_DRAINING
|| item_brand == SPWPN_PAIN
|| item_brand == SPWPN_VAMPIRICISM
|| item_brand == SPWPN_REAPING);
}
break;
case OBJ_MISSILES:
{
const int item_brand = get_ammo_brand(item);
retval = (item_brand == SPMSL_REAPING);
break;
}
case OBJ_WANDS:
retval = (item.sub_type == WAND_DRAINING);
break;
case OBJ_POTIONS:
retval = is_blood_potion(item);
break;
case OBJ_SCROLLS:
retval = (item.sub_type == SCR_TORMENT);
break;
case OBJ_BOOKS:
retval = is_evil_spellbook(item);
break;
case OBJ_STAVES:
retval = (item.sub_type == STAFF_DEATH || is_evil_rod(item));
break;
case OBJ_MISCELLANY:
retval = (item.sub_type == MISC_LANTERN_OF_SHADOWS);
break;
default:
break;
}
return (retval);
}
bool is_unclean_item(const item_def& item)
{
bool retval = false;
if (is_unrandom_artefact(item))
{
unrandart_entry* entry = get_unrand_entry(item.special);
if (entry->flags & UNRAND_FLAG_UNCLEAN)
return (true);
}
switch (item.base_type)
{
case OBJ_BOOKS:
retval = is_unclean_spellbook(item);
case OBJ_STAVES:
retval = is_unclean_rod(item);
break;
default:
break;
}
return (retval);
}
bool is_chaotic_item(const item_def& item)
{
bool retval = false;
if (is_unrandom_artefact(item))
{
unrandart_entry* entry = get_unrand_entry(item.special);
if (entry->flags & UNRAND_FLAG_CHAOTIC)
return (true);
}
switch (item.base_type)
{
case OBJ_WEAPONS:
{
const int item_brand = get_weapon_brand(item);
retval = (item_brand == SPWPN_CHAOS);
}
break;
case OBJ_MISSILES:
{
const int item_brand = get_ammo_brand(item);
retval = (item_brand == SPMSL_CHAOS);
}
break;
case OBJ_WANDS:
retval = (item.sub_type == WAND_POLYMORPH_OTHER);
break;
case OBJ_POTIONS:
retval = (item.sub_type == POT_MUTATION);
break;
case OBJ_BOOKS:
retval = is_chaotic_spellbook(item);
break;
case OBJ_STAVES:
retval = is_chaotic_rod(item);
break;
default:
break;
}
if (is_artefact(item) && artefact_wpn_property(item, ARTP_MUTAGENIC))
retval = true;
return (retval);
}
bool is_hasty_item(const item_def& item)
{
bool retval = false;
switch (item.base_type)
{
case OBJ_WEAPONS:
{
const int item_brand = get_weapon_brand(item);
retval = (item_brand == SPWPN_SPEED
|| item.sub_type == WPN_QUICK_BLADE);
}
break;
case OBJ_ARMOUR:
{
const int item_brand = get_armour_ego_type(item);
retval = (item_brand == SPARM_RUNNING);
}
break;
case OBJ_WANDS:
retval = (item.sub_type == WAND_HASTING);
break;
case OBJ_JEWELLERY:
retval = (item.sub_type == AMU_RAGE);
break;
case OBJ_POTIONS:
retval = (item.sub_type == POT_SPEED
|| item.sub_type == POT_BERSERK_RAGE);
break;
case OBJ_BOOKS:
retval = is_hasty_spellbook(item);
break;
case OBJ_STAVES:
retval = is_hasty_rod(item);
break;
default:
break;
}
if (is_artefact(item)
&& (artefact_wpn_property(item, ARTP_ANGRY)
|| artefact_wpn_property(item, ARTP_BERSERK)))
{
retval = true;
}
return (retval);
}
bool is_holy_discipline(int discipline)
{
return (discipline & SPTYP_HOLY);
}
bool is_evil_discipline(int discipline)
{
return (discipline & SPTYP_NECROMANCY);
}
bool is_holy_spell(spell_type spell, god_type god)
{
UNUSED(god);
unsigned int disciplines = get_spell_disciplines(spell);
return (is_holy_discipline(disciplines));
}
bool is_unholy_spell(spell_type spell, god_type god)
{
UNUSED(god);
unsigned int flags = get_spell_flags(spell);
return (flags & SPFLAG_UNHOLY);
}
bool is_evil_spell(spell_type spell, god_type god)
{
UNUSED(god);
unsigned int disciplines = get_spell_disciplines(spell);
return (is_evil_discipline(disciplines));
}
bool is_unclean_spell(spell_type spell, god_type god)
{
UNUSED(god);
unsigned int flags = get_spell_flags(spell);
return (flags & SPFLAG_UNCLEAN);
}
bool is_chaotic_spell(spell_type spell, god_type god)
{
UNUSED(god);
unsigned int flags = get_spell_flags(spell);
return (flags & SPFLAG_CHAOTIC);
}
bool is_hasty_spell(spell_type spell, god_type god)
{
UNUSED(god);
unsigned int flags = get_spell_flags(spell);
return (flags & SPFLAG_HASTY);
}
// The default suitable() function for is_spellbook_type().
bool is_any_spell(spell_type spell, god_type god)
{
UNUSED(god);
return (true);
}
// If book_or_rod is false, only look at actual spellbooks. Otherwise,
// only look at rods.
bool is_spellbook_type(const item_def& item, bool book_or_rod,
bool (*suitable)(spell_type spell, god_type god),
god_type god)
{
const bool is_spellbook = (item.base_type == OBJ_BOOKS
&& item.sub_type != BOOK_MANUAL
&& item.sub_type != BOOK_DESTRUCTION);
const bool is_rod = item_is_rod(item);
if (!is_spellbook && !is_rod)
return (false);
if (!book_or_rod && is_rod)
return (false);
int total = 0;
int total_liked = 0;
for (int i = 0; i < SPELLBOOK_SIZE; ++i)
{
spell_type spell = which_spell_in_book(item, i);
if (spell == SPELL_NO_SPELL)
continue;
total++;
if (suitable(spell, god))
total_liked++;
}
// If at least half of the available spells are suitable, the whole
// spellbook or rod is, too.
return (total_liked >= (total / 2) + 1);
}
bool is_holy_spellbook(const item_def& item)
{
return (is_spellbook_type(item, false, is_holy_spell));
}
bool is_unholy_spellbook(const item_def& item)
{
return (is_spellbook_type(item, false, is_unholy_spell));
}
bool is_evil_spellbook(const item_def& item)
{
return (is_spellbook_type(item, false, is_evil_spell));
}
bool is_unclean_spellbook(const item_def& item)
{
return (is_spellbook_type(item, false, is_unclean_spell));
}
bool is_chaotic_spellbook(const item_def& item)
{
return (is_spellbook_type(item, false, is_chaotic_spell));
}
bool is_hasty_spellbook(const item_def& item)
{
return (is_spellbook_type(item, false, is_hasty_spell));
}
bool god_hates_spellbook(const item_def& item)
{
return (is_spellbook_type(item, false, god_hates_spell_type));
}
bool is_holy_rod(const item_def& item)
{
return (is_spellbook_type(item, true, is_holy_spell));
}
bool is_unholy_rod(const item_def& item)
{
return (is_spellbook_type(item, true, is_unholy_spell));
}
bool is_evil_rod(const item_def& item)
{
return (is_spellbook_type(item, true, is_evil_spell));
}
bool is_unclean_rod(const item_def& item)
{
return (is_spellbook_type(item, true, is_unclean_spell));
}
bool is_chaotic_rod(const item_def& item)
{
return (is_spellbook_type(item, true, is_chaotic_spell));
}
bool is_hasty_rod(const item_def& item)
{
return (is_spellbook_type(item, true, is_hasty_spell));
}
bool god_hates_rod(const item_def& item)
{
return (is_spellbook_type(item, true, god_hates_spell_type));
}
conduct_type good_god_hates_item_handling(const item_def &item)
{
if (!is_good_god(you.religion)
|| (!is_unholy_item(item) && !is_evil_item(item)))
{
return (DID_NOTHING);
}
if (item_type_known(item))
{
if (is_evil_item(item))
return (DID_NECROMANCY);
else
return (DID_UNHOLY);
}
if (is_demonic(item))
return (DID_UNHOLY);
return (DID_NOTHING);
}
conduct_type god_hates_item_handling(const item_def &item)
{
switch (you.religion)
{
case GOD_ZIN:
if (!item_type_known(item))
return (DID_NOTHING);
if (is_unclean_item(item))
return (DID_UNCLEAN);
if (is_chaotic_item(item))
return (DID_CHAOS);
break;
case GOD_SHINING_ONE:
{
if (!item_type_known(item))
return (DID_NOTHING);
switch (item.base_type)
{
case OBJ_WEAPONS:
{
const int item_brand = get_weapon_brand(item);
if (item_brand == SPWPN_VENOM)
return (DID_POISON);
break;
}
case OBJ_MISSILES:
{
const int item_brand = get_ammo_brand(item);
if (item_brand == SPMSL_POISONED || item_brand == SPMSL_CURARE)
return (DID_POISON);
break;
}
case OBJ_STAVES:
if (item.sub_type == STAFF_POISON)
return (DID_POISON);
break;
default:
break;
}
break;
}
case GOD_YREDELEMNUL:
if (item_type_known(item) && is_holy_item(item))
return (DID_HOLY);
break;
case GOD_TROG:
if (item.base_type == OBJ_BOOKS
&& item.sub_type != BOOK_MANUAL
&& item.sub_type != BOOK_DESTRUCTION)
{
return (DID_SPELL_MEMORISE);
}
break;
case GOD_FEDHAS:
if (item_type_known(item)
&& (is_potentially_evil_item(item) || is_evil_item(item)))
{
return (DID_NECROMANCY);
}
break;
case GOD_CHEIBRIADOS:
if (item_type_known(item) && is_hasty_item(item))
return (DID_HASTY);
break;
default:
break;
}
if (item_type_known(item) && is_potentially_evil_item(item)
&& is_good_god(you.religion))
{
return (DID_NECROMANCY);
}
if (item_type_known(item)
&& (god_hates_spellbook(item) || god_hates_rod(item)))
{
return (NUM_CONDUCTS); // FIXME: Get the specific reason, if it
} // will ever be needed for spellbooks.
return (DID_NOTHING);
}
bool god_hates_spell_type(spell_type spell, god_type god)
{
if (is_good_god(god) && (is_unholy_spell(spell) || is_evil_spell(spell)))
return (true);
unsigned int disciplines = get_spell_disciplines(spell);
switch (god)
{
case GOD_ZIN:
if (is_unclean_spell(spell) || is_chaotic_spell(spell))
return (true);
break;
case GOD_SHINING_ONE:
// TSO hates using poison, but is fine with curing it, resisting
// it, or destroying it.
if ((disciplines & SPTYP_POISON) && spell != SPELL_CURE_POISON
&& spell != SPELL_RESIST_POISON && spell != SPELL_IGNITE_POISON)
{
return (true);
}
case GOD_YREDELEMNUL:
if (is_holy_spell(spell))
return (true);
break;
case GOD_FEDHAS:
if (is_evil_spell(spell))
return (true);
break;
case GOD_CHEIBRIADOS:
if (is_hasty_spell(spell))
return (true);
break;
default:
break;
}
return (false);
}
bool god_dislikes_spell_type(spell_type spell, god_type god)
{
if (god_hates_spell_type(spell, god))
return (true);
unsigned int flags = get_spell_flags(spell);
unsigned int disciplines = get_spell_disciplines(spell);
switch (god)
{
case GOD_SHINING_ONE:
// TSO probably wouldn't like spells which would put enemies
// into a state where attacking them would be unchivalrous.
if (spell == SPELL_CAUSE_FEAR || spell == SPELL_PARALYSE
|| spell == SPELL_CONFUSE || spell == SPELL_MASS_CONFUSION
|| spell == SPELL_HIBERNATION || spell == SPELL_ENGLACIATION)
{
return (true);
}
break;
case GOD_XOM:
// Ideally, Xom would only like spells which have a random
// effect, are risky to use, or would otherwise amuse him, but
// that would be a really small number of spells.
// Xom would probably find these extra boring.
if (flags & (SPFLAG_HELPFUL | SPFLAG_NEUTRAL | SPFLAG_ESCAPE
| SPFLAG_RECOVERY | SPFLAG_MAPPING))
{
return (true);
}
// Holy spells are probably too useful for Xom to find them
// interesting.
if (is_holy_spell(spell))
return (true);
// Things are more fun for Xom the less the player knows in
// advance.
if (disciplines & SPTYP_DIVINATION)
return (true);
break;
case GOD_ELYVILON:
// A peaceful god of healing wouldn't like combat spells.
if (disciplines & SPTYP_CONJURATION)
return (true);
// Also doesn't like battle spells of the non-conjuration type.
if (flags & SPFLAG_BATTLE)
return (true);
break;
default:
break;
}
return (false);
}
bool god_dislikes_spell_discipline(int discipline, god_type god)
{
ASSERT(discipline < (1 << (SPTYP_LAST_EXPONENT + 1)));
if (is_good_god(god) && is_evil_discipline(discipline))
return (true);
switch (god)
{
case GOD_SHINING_ONE:
return (discipline & SPTYP_POISON);
case GOD_YREDELEMNUL:
return (is_holy_discipline(discipline));
case GOD_XOM:
return (is_holy_discipline(discipline)
|| (discipline & SPTYP_DIVINATION));
case GOD_ELYVILON:
return (discipline & (SPTYP_CONJURATION | SPTYP_SUMMONING));
case GOD_FEDHAS:
return (is_evil_discipline(discipline));
default:
break;
}
return (false);
}