seen.
Implemented fixed-level randart spell books, which is all randart spellbooks as of now. All my attempts at sorting the spell list so that spells with the same schools group together have utterly failed.
Got rid of the hackish "non-monster origin is stored in item.orig_monnum as (-origin - 2)" logic, replaced with the slightly less hackish "-origin". Added the two enumerations IT_SRC_START and IT_SRC_SHOP to do it. Also, origin_is_god_gift() and origin_is_acquirement() can retrieve the god/source of the item so that you don't have to do the negation and typecasting yourself.
Added some new spell flags:
SPFLAG_BATTLE for non-conjuration spells which are still combat/battle related (branding spells and single school attack spells like "Pain"),
SPFLAG_CARD for spells which are card-type effects which don't show up in ordinary spellbooks (Tomb of Doroklohe and (I assume) Disintigrate)
SPFLAG_TESTING for spells which are only used for testing (Debugging Ray)
SPFLAG_DEVEL for spells that are still under development (Crush, Disrupt, and Detect Magic).
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7742 c06c8d41-db1a-0410-9941-cceddc491573
FWNNTOEERPUKXPE4OC52UABFZLKIU3O5GRNNLDK4QI4HR2IOU36QC
N3BAL7TTPTEKB2UOP2YWD7HOBR3735RPRECJOPC647TVFSRFYHNAC
3UTZR7L3VTFUCGNE7HROHQDVGUVI2QI64BNL7SDC5AWHVW2FD6EQC
5VZWOTCDNCSSWVT2ILO6XCR75LBGFREHOR2WC2CJ4WE7NHVPDEMQC
EYYWIH7377INOKPRABJUATNQ2YWKLOVHZKQIY55POX2YXVMDDWAAC
RIGGVFYNCRFDUUCMIAN7SDEOUL4VMMZI6OYXZW72BVNI4WXJQXWQC
46MRRHVYJ3BS74R2BEVUWEWJCI4FCRBSLZ3NWMQCE6FUCNE5P73QC
JJVROJMJVKS7VN5HJNB4ZNCG7Y6EMHJQZR3MDN2VZCFTZC73HOZQC
JYEEOUYQ7ZPKOGWUV7VCORBVSOLF2UCBFBH3TR75RGOSS6PNKYUAC
KFULGQQOHWUTXOM3BXCCYPGGVGGY4Z6265XUFRCBPNLTZAEHJZSQC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
CHO4U5JC3RNTLXVIDXXJYZMOBZJ4VXW2GVJWDOTBRKK3AJ36LDLQC
7BREK7U6OWZ6YU3JDSJSH4CMNNULDYABCKCAUHGZIUJZBIRJS5WQC
NQMXQ6OQVUSC7Y7F7IL252QW4A5JED224EECNHWAM4ZZYVNY745AC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
DDU4A3JGN5IUIPP5IASOODKPR2WBHSDSV4FITZ6HNXNSXXQACWAQC
7QVPQYSZJODY6Z7TW6ZHRCOVS2FBPTAU7SREICKO5LMH4IB3SGVQC
KHVK7HH7OIYOBZY52WQGGLC2O4SXTWQS2XAHNJZZ7JZ3QTOUTLNAC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
YYC7LBS5AYZQNLGKCYSFECSA6M6CHR7SRV2GTY7DON6XZKZJ3MJQC
PMODADA7C3BWOFCPU37626DKMWENG6FAR5I6TOIQU5OBJBUJTSAQC
ZGUJWUFJ4NFFJ6PGXLFGQWCWBCZHPWGWI44NJHJEVPRG5L36PADQC
JCWJWGMQIKQGSSFJUQRKNIWW3HBOJSHYDTOPPE5BWOJTIJTDYUTAC
IJ4GH6RYJYT4METQIJYT3IITJEHZ4IAF4WBPA5RH6RSYX4KHXMYAC
4NBPZKMZBKB3QYX4FFUAKDXQS43NJCBDLMHKDJFVXHQLX4MQDINAC
BSI5DB3LVY42ZHOS46X2CAPPVOSOTTQWFGLTMAKRFTROI5BQWFDQC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
E6JXIMRH2TX5WHZ6BT2QZ3EANM3PWCHCVYC4XWRJGRBDSP42X2RAC
4GYZYBY7FFORRNPIEFTV4ZM2C7Z6D2KTQOM537ZCC2YBXT2TNSHAC
V4DWL5WBO2JCODVS5QQNWXDH4DAYZN3D5V3UDCHM2KKOMADOTEDQC
WZNB427K3EUNV3FMVXLQTM4UIHER4FIKQXWLUUXRNQC3OQ33VQYAC
3DQXSE4YGFBBDUWK4YEOFWW4UPWILWELFSLP37SL6BERGAZJC5YAC
NDKS43E4XVAU3FDY276OF5JW7E5SF6F5EJD2XLV5JLKZ5W6N554QC
V4F3SDV2H4HBH6G6W5M3REN3BDSSE4IDF2RNM7PJMKRW3IDJ7PNAC
XI7X6SNTHG67D4NQWM75HWB6TVRXVFDPGNSQLTXN6JAZBZIVZXIQC
LY7DLLD7IKL6ZQPVROLDJ46XRM5CMAAEBRFDKJ4M53CPC5GFCGSQC
EJKHYV2Z6UPRVYUAL4WRW33GBNHYBFPMPA57HMBX2LQKXHIUO5VQC
SRQJVKQVUY7QGCEBA2VQTWEJ7ADIUSY7L46HJQSQNM5DXYRRH5KAC
6FYEYTS5NRD5JAFIBSFHPBCQOKZBMWPWEI26USCI6OBUDGLJQKAAC
LDBTCT5WIPLJPZWXS2RUQ26QKISCUUTLO77M464WOE6VSYSNPKYAC
KU5FY6KSLTGH44KEZT4SFANRKCTWCQC7VABCMNYJRZNJSYSOXAKQC
ZMYKMHWEU26FOUTD26Q4GTAZMI6RNO3K6NHQ2VGTESE3E73GQVCQC
5UXWZHJ23JEPCI7QAF3R7JWV37LHH7I2FEWCFD4JPC5HC7YQQJ2AC
6LT6USGJOTDMRJGXLAN2NSZXK2GKWEXDKKUV6SVV7ZC6WI6EKMDQC
VIFZ6DO6GWJGYMXJZKFZ2JYNPHNE74H3OFAOCPISQG7M7A4LCOHAC
6F2J5HCYTKKIGZD4O6FETFA4WOUI4A5VHPVD4U37JPLX6SYX6DQQC
FU663V7RFZNSMG5P2E7TZJZWSGXWLCCFXSVGH4Z222FIJTH4R3KAC
CI2RMLJLIAZMEGNN6LJN6PSHXHLPG7PXFIDYRGFPVMDPJ2R4S4NQC
MV5USMLTBKVRWBAD67UFJ2BS4Y5HEOMYASRSB44DS24BBMRP75RQC
O6ZMFKDI3XO2SWPNEYHIPYFDWJR4TVDP5BAATK6LVCVETQID6E7AC
I2B33Z7NZGC33AMDSSK446AZZYWKPHWLAGULVHKKZU4MVB4BNJOAC
BMKL2AB2HBBBVAHWDYXPYZHSCO345QWOQHFSICFRN5BCYZ3UEK3AC
45CXZWWXI7SGKLHVSRP2U6KNXJBT2XADNLIIHQQJYL2E6QWNURKQC
2DORUQ4B574MDOOMRYWGU5I72AKHMCSTZ6B3VSHQBUQOZYHRC7FAC
JVSCP4FTW2G57C6YD5HZOZXTODGZH7TR75JQGFJBEPX3LCZH236QC
I7QLYOTE6DLQZM7YWUWYLKHRJRB2A3STQ42ALSRGQICEWKD2QTEQC
ZIFFVCQ72K35WGIUMZYN3KOXIUXF2CNXWKG6ZWEZ6LT3NSF3XOQAC
PAYI4UTJCR3XZSFOX5L35EURHRXQ6STO4Z7AQ3525QPNL3QYLNBAC
VCG3BRIYRTNNWYC3LOXD6KFGXOX37HAFW2HNV7WXVG2V7EUHLDZQC
KNO4TZR76DMOYJCF24PSVQW7FUZOTMOJTL7I7J74SM4IHOGDX6TAC
HNPSSHGZFQ3E2I6X6VTKZ3WBBM2G25P2D7SIL2SZYKV2CCEA2ADAC
36DYXIWAQTBOCZBCUPYWDKAXVWDU3TRMSM3OCQZGGMWE2KPERJMAC
Y2NYY7HWFZ2LQDK3ACSLGS37F2J2IJ5LRGCIMZYXLEOSVPD3A4DAC
YFIVTYI7PMVAXV23DUPXPAQNEY3YSFIXQGSN32I3WVHMMD5XS5DQC
CIPVRZGLOZHCERK6YPOBV3P2E4IAB4H6D5EHLRQE2O5E4P4VCBUAC
int spell_skill2type(unsigned int skill)
{
switch (skill)
{
case SK_CONJURATIONS: return (SPTYP_CONJURATION);
case SK_ENCHANTMENTS: return (SPTYP_ENCHANTMENT);
case SK_FIRE_MAGIC: return (SPTYP_FIRE);
case SK_ICE_MAGIC: return (SPTYP_ICE);
case SK_TRANSMIGRATION: return (SPTYP_TRANSMIGRATION);
case SK_NECROMANCY: return (SPTYP_NECROMANCY);
case SK_SUMMONINGS: return (SPTYP_SUMMONING);
case SK_DIVINATIONS: return (SPTYP_DIVINATION);
case SK_TRANSLOCATIONS: return (SPTYP_TRANSLOCATION);
case SK_POISON_MAGIC: return (SPTYP_POISON);
case SK_EARTH_MAGIC: return (SPTYP_EARTH);
case SK_AIR_MAGIC: return (SPTYP_AIR);
default:
case SPTYP_HOLY:
#ifdef DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS, "spell_skill2type: called with skill %u",
spelltype );
#endif
return (-1);
}
} // end spell_type2skill()
SPFLAG_NONE = 0x0000,
SPFLAG_DIR_OR_TARGET = 0x0001, // use DIR_NONE targeting
SPFLAG_TARGET = 0x0002, // use DIR_TARGET targeting
SPFLAG_GRID = 0x0004, // use DIR_GRID targeting
SPFLAG_DIR = 0x0008, // use DIR_DIR targeting
SPFLAG_TARGETING_MASK = 0x000f, // used to test for targeting
SPFLAG_HELPFUL = 0x0010, // TARG_FRIENDS used
SPFLAG_NEUTRAL = 0x0020, // TARG_ANY used
SPFLAG_NOT_SELF = 0x0040, // aborts on isMe
SPFLAG_UNHOLY = 0x0080, // counts at "unholy"
SPFLAG_MAPPING = 0x0100, // a mapping spell of some kind
SPFLAG_ESCAPE = 0x0200, // useful for running away
SPFLAG_RECOVERY = 0x0400, // healing or recovery spell
SPFLAG_AREA = 0x0800, // area affect
SPFLAG_MONSTER = 0x1000 // monster-only spell
SPFLAG_NONE = 0x00000,
SPFLAG_DIR_OR_TARGET = 0x00001, // use DIR_NONE targeting
SPFLAG_TARGET = 0x00002, // use DIR_TARGET targeting
SPFLAG_GRID = 0x00004, // use DIR_GRID targeting
SPFLAG_DIR = 0x00008, // use DIR_DIR targeting
SPFLAG_TARGETING_MASK = 0x0000f, // used to test for targeting
SPFLAG_HELPFUL = 0x00010, // TARG_FRIENDS used
SPFLAG_NEUTRAL = 0x00020, // TARG_ANY used
SPFLAG_NOT_SELF = 0x00040, // aborts on isMe
SPFLAG_UNHOLY = 0x00080, // counts at "unholy"
SPFLAG_MAPPING = 0x00100, // a mapping spell of some kind
SPFLAG_ESCAPE = 0x00200, // useful for running away
SPFLAG_RECOVERY = 0x00400, // healing or recovery spell
SPFLAG_AREA = 0x00800, // area affect
SPFLAG_BATTLE = 0x01000, // a non-Conjuration spell that
// is still a battle spell
SPFLAG_CARD = 0x02000, // a card effect spell
SPFLAG_MONSTER = 0x04000, // monster-only spell
SPFLAG_TESTING = 0x08000, // a testing/debugging spell
SPFLAG_DEVEL = 0x10000 // a spell under development
void mark_had_book(const item_def &book)
{
ASSERT(book.base_type == OBJ_BOOKS);
if (book.book_number() == BOOK_MANUAL
|| book.book_number() == BOOK_DESTRUCTION)
{
return;
}
for (int i = 0; i < SPELLBOOK_SIZE; i++)
{
spell_type stype = which_spell_in_book(book, i);
if (stype == SPELL_NO_SPELL)
continue;
you.seen_spell[stype] = true;
}
}
static bool _compare_spells(spell_type a, spell_type b)
{
if (a == SPELL_NO_SPELL && b == SPELL_NO_SPELL)
return (false);
else if (a != SPELL_NO_SPELL && b == SPELL_NO_SPELL)
return (true);
else if (a == SPELL_NO_SPELL && b != SPELL_NO_SPELL)
return (false);
int level_a = spell_difficulty(a);
int level_b = spell_difficulty(b);
if (level_a != level_b)
return (level_a < level_b);
unsigned int schools_a = get_spell_disciplines(a);
unsigned int schools_b = get_spell_disciplines(b);
if (schools_a != schools_b && schools_a != 0 && schools_b != 0)
{
const char* a_type = NULL;
const char* b_type = NULL;
// Find lowest/earliest school for each spell.
for (int i = 0; i <= SPTYP_LAST_EXPONENT; i++)
{
int mask = 1 << i;
if (a_type == NULL && (schools_a & mask))
a_type = spelltype_name(mask);
if (b_type == NULL && (schools_b & mask))
b_type = spelltype_name(mask);
}
ASSERT(a_type != NULL && b_type != NULL);
return (strcmp(a_type, b_type));
}
return (strcmp(spell_title(a), spell_title(b)));
}
static bool _is_memorized(spell_type spell)
{
for (int i = 0; i < 25; i++)
{
if (you.spells[i] == spell)
return (true);
}
return (false);
}
bool make_book_level_randart(item_def &book, int level,
int num_spells)
{
ASSERT(book.base_type == OBJ_BOOKS);
ASSERT(book.book_number() != BOOK_MANUAL
&& book.book_number() != BOOK_DESTRUCTION);
ASSERT(is_random_artefact(book));
ASSERT(!book.props.exists(SPELL_LIST_KEY));
god_type god;
(void) origin_is_god_gift(book, &god);
const bool avoid_uncastable = (god != GOD_NO_GOD && god != GOD_XOM)
|| origin_is_acquirement(book);
const bool track_levels_had = origin_is_acquirement(book)
|| god == GOD_SIF_MUNA;
if (level == -1)
{
int max_level =
avoid_uncastable ? std::min(9, you.get_experience_level())
: 9;
level = random_range(1, max_level);
// Give a book of a level not seen before, preferably one with
// spells of a low enough level for the player to cast, or the
// lowest aviable level if all levels which the player can cast
// have already been given.
if (track_levels_had)
{
unsigned int seen_levels = you.attribute[ATTR_RND_LVL_BOOKS];
std::vector<int> vec;
for (int i = 1; i <= 9 && (vec.empty() || i <= max_level); i++)
{
if (!(seen_levels & (1 << i)))
vec.push_back(i);
}
if (vec.size() > 0)
level = vec[random2(vec.size())];
}
}
ASSERT(level > 0 && level <= 9);
if (num_spells == -1)
num_spells = SPELLBOOK_SIZE;
ASSERT(num_spells > 0 && num_spells <= SPELLBOOK_SIZE);
int god_discard = 0;
int uncastable_discard = 0;
std::vector<spell_type> spell_list;
for (int i = 0; i < NUM_SPELLS; i++)
{
const spell_type spell = (spell_type) i;
if (!is_valid_spell(spell))
continue;
if (spell_difficulty(spell) != level)
continue;
const unsigned int flags = get_spell_flags(spell);
const unsigned int schools = get_spell_disciplines(spell);
// Don't include schoolless spells, like Smiting.
if (schools == 0)
continue;
// Holy spells don't show up in books.
if (schools & SPTYP_HOLY)
continue;
if (flags & (SPFLAG_MONSTER | SPFLAG_CARD | SPFLAG_TESTING))
continue;
// Only wizards gets spells still under development.
if (flags & SPFLAG_DEVEL)
{
#ifdef WIZARD
if (!you.wizard)
continue;
#else
continue;
#endif
}
if (avoid_uncastable && undead_cannot_memorise(spell, you.is_undead))
{
uncastable_discard++;
continue;
}
if (god_dislikes_spell_type(spell, god))
{
god_discard++;
continue;
}
// Passed all tests.
spell_list.push_back(spell);
}
if (spell_list.empty())
{
char buf[80];
if (god_discard > 0 && uncastable_discard == 0)
sprintf(buf, "%s disliked all level %d spells",
god_name(god).c_str(), level);
else if (god_discard == 0 && uncastable_discard > 0)
sprintf(buf, "No level %d spells can be cast by you", level);
else if (god_discard > 0 && uncastable_discard > 0)
sprintf(buf, "All level %d spells are either disliked by %s "
"or cannot be cast by you.",
level, god_name(god).c_str());
else
sprintf(buf, "No level %d spells?!?!?!", level);
mprf(MSGCH_ERROR, "Could not create fixed level randart spellbook: %s",
buf);
return (false);
}
random_shuffle(spell_list.begin(), spell_list.end());
if (num_spells > (int) spell_list.size())
{
num_spells = spell_list.size();
#if DEBUG || DEBUG_DIAGNOSTICS
// Not many level 8 or 9 spells
if (level < 8)
{
mprf(MSGCH_WARN, "More spells requested for fixed level (%d) "
"randart spellbook than there are valid spells.",
level);
mprf(MSGCH_WARN, "Discarded %d spells due to being uncastable and "
"%d spells due to being disliked by %s.",
uncastable_discard, god_discard, god_name(god).c_str());
}
#endif
}
std::vector<bool> spell_used(spell_list.size(), false);
std::vector<bool> avoid_memorised(spell_list.size(), true);
spell_type chosen_spells[SPELLBOOK_SIZE];
for (int i = 0; i < SPELLBOOK_SIZE; i++)
{
chosen_spells[i] = SPELL_NO_SPELL;
}
int book_pos = 0;
while (book_pos < num_spells)
{
int spell_pos = random2(spell_list.size());
if (spell_used[spell_pos])
continue;
spell_type spell = spell_list[spell_pos];
ASSERT(spell != SPELL_NO_SPELL);
if (avoid_memorised[spell_pos] && _is_memorized(spell))
{
// Only once.
avoid_memorised[spell_pos] = false;
continue;
}
spell_used[spell_pos] = true;
chosen_spells[book_pos++] = spell;
}
std::sort(chosen_spells, chosen_spells + SPELLBOOK_SIZE,
_compare_spells);
ASSERT(chosen_spells[0] != SPELL_NO_SPELL);
CrawlHashTable &props = book.props;
if (!props.exists( SPELL_LIST_KEY ))
props[SPELL_LIST_KEY].new_vector(SV_LONG).resize(SPELLBOOK_SIZE);
CrawlVector &spell_vec = props[SPELL_LIST_KEY];
spell_vec.set_max_size(SPELLBOOK_SIZE);
for (int i = 0; i < SPELLBOOK_SIZE; i++)
spell_vec[i] = (long) chosen_spells[i];
if (track_levels_had)
you.attribute[ATTR_RND_LVL_BOOKS] |= (1 << level);
return (true);
return (true);
}
return (false);
}
bool god_dislikes_spell_type(spell_type spell, god_type god)
{
if (god == GOD_NO_GOD)
return (false);
unsigned int flags = get_spell_flags(spell);
unsigned int schools = get_spell_disciplines(spell);
if (is_good_god(god))
{
if ((flags & SPFLAG_UNHOLY) || (schools & SPTYP_NECROMANCY))
return (true);
}
switch(god)
{
case GOD_ZIN:
if (spell == SPELL_POLYMORPH_OTHER || spell == SPELL_ALTER_SELF)
return (true);
break;
case GOD_SHINING_ONE:
// TSO dislikes using poison, but is fine with curing it, resisting
// it or destroying it.
if ((schools & SPTYP_POISON) && spell != SPELL_CURE_POISON_I
&& spell != SPELL_CURE_POISON_II && spell != SPELL_RESIST_POISON
&& spell != SPELL_IGNITE_POISON)
{
return (true);
}
// He probably also 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_SLEEP || spell == SPELL_MASS_SLEEP)
{
return (true);
}
break;
case GOD_YREDELEMNUL:
if (schools & SPTYP_HOLY)
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))
{
}
// Things are more fun for Xom the less the player knows in
// advance.
if (schools & SPTYP_DIVINATION)
return (true);
// Holy spells are probably too useful for Xom to find them
// interesting.
if (schools & SPTYP_HOLY)
return (true);
break;
case GOD_ELYVILON:
// A peaceful god of healing wouldn't like combat spells.
if (schools & SPTYP_CONJURATION)
return (true);
// Also doesn't like battle spells of the non-conjuration type.
if (flags & SPFLAG_BATTLE)
return true;
break;
default:
break;
switch(god)
{
case GOD_SHINING_ONE:
return (school == SPTYP_POISON);
case GOD_YREDELEMNUL:
return (school == SPTYP_HOLY);
case GOD_XOM:
return (school == SPTYP_DIVINATION || school == SPTYP_HOLY);
case GOD_ELYVILON:
return (school == SPTYP_CONJURATION);
default:
break;
}
return (false);
}
}
static god_type _gift_from_god(const item_def item)
{
// maybe god gift?
god_type god_gift = GOD_NO_GOD;
if (item.orig_monnum < 0)
{
int help = -item.orig_monnum - 2;
if (help > GOD_NO_GOD && help < NUM_GODS)
god_gift = static_cast<god_type>(help);
}
return god_gift;
return (spell_difficulty(a) < spell_difficulty(b));
}
static void _init_randart_book(item_def &book)
{
spell_type spells[SPELLBOOK_SIZE];
int spell_count = 0;
while(spell_count < SPELLBOOK_SIZE)
{
spell_type spl = static_cast<spell_type>(random2(NUM_SPELLS));
if (!is_valid_spell(spl))
continue;
// Skip monster only spells.
if (get_spell_flags(spl) & SPFLAG_MONSTER)
continue;
// Holy spells don't show up in books.
if (spell_typematch(spl, SPTYP_HOLY))
continue;
// Don't include schoolless spells, like Smiting.
if (get_spell_disciplines(spl) == 0)
continue;
// This spell passes all of the other checks.
if (spl == SPELL_DEBUGGING_RAY)
continue;
// No duplicate spells.
bool present = false;
for (int i = 0; i < spell_count; i++)
if (spells[i] == spl)
{
present = true;
break;
}
if (present)
continue;
spells[spell_count++] = spl;
}
std::sort(spells, spells + SPELLBOOK_SIZE, _compare_spell_dificulties);
CrawlHashTable &props = book.props;
if (!props.exists( SPELL_LIST_KEY ))
props[SPELL_LIST_KEY].new_vector(SV_LONG).resize(SPELLBOOK_SIZE);
CrawlVector &spell_vec = props[SPELL_LIST_KEY];
spell_vec.set_max_size(SPELLBOOK_SIZE);
for (int i = 0; i < SPELLBOOK_SIZE; i++)
spell_vec[i] = (long) spells[i];
return make_book_level_randart(book, -1, 8);
_init_randart_properties(item);
if (!_init_randart_properties(item))
{
// Something went wrong that no amount of changing
// item.special will fix.
item.special = 0;
item.props.erase(RANDART_PROPS_KEY);
item.props.erase(KNOWN_PROPS_KEY);
item.flags &= ~ISFLAG_RANDART;
return (false);
}
return (spell_by_name(key) == SPELL_NO_SPELL);
spell_type spell = spell_by_name(key);
if (spell == SPELL_NO_SPELL)
return (true);
if (get_spell_flags(spell) & (SPFLAG_MONSTER | SPFLAG_TESTING
| SPFLAG_DEVEL))
{
#ifdef WIZARD
return (!you.wizard);
#else
return (true);
#endif
}
return (false);
}
}
// Extra info on this item wasn't found anywhere else.
static void _append_non_item(std::string &desc, std::string key)
{
spell_type type = spell_by_name(key, true);
if (type == SPELL_NO_SPELL)
return;
unsigned int flags = get_spell_flags(type);
if (flags & SPFLAG_DEVEL)
desc += "$This spell is still being developped, and is only avaible "
"via the &Z wizard command.";
else if (flags & SPFLAG_TESTING)
desc += "$This is a testing spell, only avaible via the "
"&Z wizard command.";
else if (flags & SPFLAG_MONSTER)
desc += "$This is a monster-only spell, only avaible via the "
"&Z wizard command.";
else if (flags & SPFLAG_CARD)
desc += "$This is a card-effect spell, unavailable in ordinary "
"spellbooks.";
else
desc += "$Odd, this spell can't be found anywhere. Please "
"file a bug report.";
#ifdef WIZARD
if (!you.wizard)
#else
if (true)
#endif
{
if (flags & (SPFLAG_TESTING | SPFLAG_MONSTER | SPFLAG_DEVEL))
desc += "$$You aren't in wizard mode, so you shouldn't be "
"seeing this entry. Please file a bug report.";
if (!make_item_randart( you.inv[i] ))
if (is_random_artefact(item))
{
if (!yesno("Is already a randart; wipe and re-use?"))
{
canned_msg( MSG_OK );
// If equipped, re-apply benefits.
if (j != NUM_EQUIP)
use_randart( i );
return;
}
item.special = 0;
item.flags &= ~ISFLAG_RANDART;
item.props.clear();
}
if (!make_item_randart( item ))