From 021366461aba2e0504b2722d28d2b967778b3702 Mon Sep 17 00:00:00 2001 From: zelgadis Date: Tue, 2 Dec 2008 14:09:20 +0000 Subject: The start of randart spellbooks. Never randomly generated and only created via the wizard command &+, since there's no logic to how the random set of spells are selected and there's no valuation code in shopping.cc. No randart manuals or books of destruction, since I have no clue what they'd be like. The code allows for any book or spell to have its normal set of spells overridden by an arbitrary/customized set of spells, but this is only used by randart spellbooks as of now. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7722 c06c8d41-db1a-0410-9941-cceddc491573 --- crawl-ref/source/acr.cc | 10 +++- crawl-ref/source/command.cc | 4 +- crawl-ref/source/dat/database/randname.txt | 11 ++++ crawl-ref/source/describe.cc | 3 + crawl-ref/source/item_use.cc | 2 +- crawl-ref/source/itemname.cc | 11 +++- crawl-ref/source/randart.cc | 90 +++++++++++++++++++++++++++++- crawl-ref/source/spl-book.cc | 45 +++++++++++---- crawl-ref/source/spl-book.h | 5 ++ crawl-ref/source/spl-cast.cc | 4 +- crawl-ref/source/spl-cast.h | 3 +- crawl-ref/source/spl-data.h | 34 +++++------ 12 files changed, 182 insertions(+), 40 deletions(-) diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index 599a4cda5f..b0a88dccfe 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -429,7 +429,8 @@ static void _startup_tutorial() // Returns whether an item of this type can be an artefact, or cursed. static bool _item_type_can_be_artefact( int type) { - return (type == OBJ_WEAPONS || type == OBJ_ARMOUR || type == OBJ_JEWELLERY); + return (type == OBJ_WEAPONS || type == OBJ_ARMOUR || type == OBJ_JEWELLERY + || type == OBJ_BOOKS); } static void _do_wizard_command(int wiz_command, bool silent_fail) @@ -534,7 +535,12 @@ static void _do_wizard_command(int wiz_command, bool silent_fail) } } - make_item_randart( you.inv[i] ); + if (!make_item_randart( you.inv[i] )) + { + mpr("Failed to turn item into randart."); + break; + } + if (Options.autoinscribe_randarts) { add_autoinscription(you.inv[i], diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc index af1b764b6c..88c69e7ff0 100644 --- a/crawl-ref/source/command.cc +++ b/crawl-ref/source/command.cc @@ -1204,11 +1204,9 @@ static void _append_spells(std::string &desc, const item_def &item) desc += "$$Spells Type Level$"; - const int type = item.book_number(); - for (int j = 0; j < 8; j++) { - spell_type stype = which_spell_in_book(type, j); + spell_type stype = which_spell_in_book(item, j); if (stype == SPELL_NO_SPELL) continue; diff --git a/crawl-ref/source/dat/database/randname.txt b/crawl-ref/source/dat/database/randname.txt index d966e7a8fd..0e8dd2fbf2 100644 --- a/crawl-ref/source/dat/database/randname.txt +++ b/crawl-ref/source/dat/database/randname.txt @@ -800,3 +800,14 @@ amulet appearance @jewellery appearance@ @amulet material@ %%%% +###################################################### +# Books (NOTE: just a placeholder for now) +###################################################### +book + +@armour@ +%%%% +book appearance + +@armour appearance@ +%%%% diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc index 3aa735d7e5..c9aba5ab84 100644 --- a/crawl-ref/source/describe.cc +++ b/crawl-ref/source/describe.cc @@ -424,6 +424,9 @@ static void _trim_randart_inscrip( item_def& item ) std::string randart_auto_inscription( const item_def& item ) { + if (item.base_type == OBJ_BOOKS) + return(""); + const std::vector propnames = _randart_propnames(item); return comma_separated_line(propnames.begin(), propnames.end(), diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc index 6c6eaaedf3..bb053758d6 100644 --- a/crawl-ref/source/item_use.cc +++ b/crawl-ref/source/item_use.cc @@ -4295,7 +4295,7 @@ static void handle_read_book(int item_slot) return; } - const spell_type spell = which_spell_in_book(book.sub_type, + const spell_type spell = which_spell_in_book(book, letter_to_index(ltr)); if (spell == SPELL_NO_SPELL) { diff --git a/crawl-ref/source/itemname.cc b/crawl-ref/source/itemname.cc index 89a6d3c251..a76dc938ff 100644 --- a/crawl-ref/source/itemname.cc +++ b/crawl-ref/source/itemname.cc @@ -1466,6 +1466,14 @@ std::string item_def::name_aux( description_level_type desc, break; case OBJ_BOOKS: + if (is_random_artefact( *this ) && !dbname && !basename) + { + if (know_type) + buff << "book" << get_artefact_name(*this); + else + buff << get_artefact_name(*this) << "book"; + break; + } if (basename) buff << (item_typ == BOOK_MANUAL ? "manual" : "book"); else if (!know_type) @@ -1560,7 +1568,8 @@ std::string item_def::name_aux( description_level_type desc, buff.str( pluralise(buff.str()) ); // Disambiguation - if (!terse && !basename && !dbname && know_type) + if (!terse && !basename && !dbname && know_type && + !is_random_artefact( *this )) { switch (this->base_type) { diff --git a/crawl-ref/source/randart.cc b/crawl-ref/source/randart.cc index 500ee5ffa8..234ac1eff4 100644 --- a/crawl-ref/source/randart.cc +++ b/crawl-ref/source/randart.cc @@ -24,6 +24,9 @@ #include "place.h" #include "player.h" #include "religion.h" +#include "spl-book.h" +#include "spl-cast.h" +#include "spl-util.h" #include "stuff.h" #define KNOWN_PROPS_KEY "randart_known_props" @@ -361,6 +364,10 @@ void randart_desc_properties( const item_def &item, randart_known_props_t &known, bool force_fake_props) { + // Randart books have no randart properties. + if (item.base_type == OBJ_BOOKS) + return; + randart_wpn_properties( item, proprt, known); if (!force_fake_props && item_ident( item, ISFLAG_KNOW_PROPERTIES )) @@ -1090,6 +1097,66 @@ void static _get_randart_properties(const item_def &item, } } +static bool _compare_spell_dificulties(spell_type a, spell_type b) +{ + 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(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]; +} + void static _init_randart_properties(item_def &item) { ASSERT( is_random_artefact( item ) ); @@ -1113,6 +1180,12 @@ void static _init_randart_properties(item_def &item) return; } + if (item.base_type == OBJ_BOOKS) + { + _init_randart_book(item); + return; + } + randart_properties_t prop; _get_randart_properties(item, prop); @@ -1260,6 +1333,8 @@ static std::string _get_artefact_type(const item_def &item, { switch (item.base_type) { + case OBJ_BOOKS: + return "book"; case OBJ_WEAPONS: return "weapon"; case OBJ_ARMOUR: @@ -1298,7 +1373,8 @@ std::string artefact_name(const item_def &item, bool appearance) ASSERT(item.base_type == OBJ_WEAPONS || item.base_type == OBJ_ARMOUR - || item.base_type == OBJ_JEWELLERY); + || item.base_type == OBJ_JEWELLERY + || item.base_type == OBJ_BOOKS); if (is_fixed_artefact( item )) return _get_fixedart_name( item ); @@ -1908,6 +1984,9 @@ static bool _randart_is_conflicting( const item_def &item, bool randart_is_bad( const item_def &item, randart_properties_t &proprt ) { + if (item.base_type == OBJ_BOOKS) + return (false); + if (randart_wpn_num_props( proprt ) == 0) return (true); @@ -1970,11 +2049,18 @@ bool make_item_randart( item_def &item ) { if (item.base_type != OBJ_WEAPONS && item.base_type != OBJ_ARMOUR - && item.base_type != OBJ_JEWELLERY) + && item.base_type != OBJ_JEWELLERY + && item.base_type != OBJ_BOOKS) { return (false); } + if (item.base_type == OBJ_BOOKS) + { + if (item.sub_type == BOOK_MANUAL || item.sub_type == BOOK_DESTRUCTION) + return (false); + } + // already is a randart if (item.flags & ISFLAG_RANDART) return (true); diff --git a/crawl-ref/source/spl-book.cc b/crawl-ref/source/spl-book.cc index 1bcbbabc7a..957a5027e2 100644 --- a/crawl-ref/source/spl-book.cc +++ b/crawl-ref/source/spl-book.cc @@ -30,6 +30,7 @@ #include "it_use3.h" #include "message.h" #include "player.h" +#include "randart.h" #include "religion.h" #include "spl-cast.h" #include "spl-mis.h" @@ -686,6 +687,22 @@ static spell_type spellbook_template_array[NUMBER_SPELLBOOKS][SPELLBOOK_SIZE] = }, }; +spell_type which_spell_in_book(const item_def &book, int spl) +{ + ASSERT(book.base_type == OBJ_BOOKS || book.base_type == OBJ_STAVES); + + const CrawlHashTable &props = book.props; + if (!props.exists( SPELL_LIST_KEY )) + return which_spell_in_book(book.book_number(), spl); + + const CrawlVector &spells = props[SPELL_LIST_KEY].get_vector(); + + ASSERT( spells.get_type() == SV_LONG ); + ASSERT( spells.size() == SPELLBOOK_SIZE ); + + return static_cast(spells[spl].get_long()); +} + spell_type which_spell_in_book(int sbook_type, int spl) { ASSERT( sbook_type >= 0 ); @@ -703,7 +720,6 @@ int spellbook_contents( item_def &book, read_book_action_type action, bool update_screen = !fs; const int spell_levels = player_spell_levels(); - const int type = book.book_number(); bool spell_skills = false; @@ -727,7 +743,7 @@ int spellbook_contents( item_def &book, read_book_action_type action, for (j = 0; j < SPELLBOOK_SIZE; j++) { - spell_type stype = which_spell_in_book(type, j); + spell_type stype = which_spell_in_book(book, j); if (stype == SPELL_NO_SPELL) continue; @@ -936,6 +952,11 @@ int book_rarity(unsigned char which_book) } } +bool is_valid_spell_in_book( const item_def &book, int spell ) +{ + return which_spell_in_book(book, spell) != SPELL_NO_SPELL; +} + bool is_valid_spell_in_book( int splbook, int spell ) { return which_spell_in_book(splbook, spell) != SPELL_NO_SPELL; @@ -989,6 +1010,9 @@ bool player_can_read_spellbook( const item_def &book ) if (book.base_type != OBJ_BOOKS) return (true); + if (book.props.exists( SPELL_LIST_KEY )) + return (true); + if ((book.sub_type == BOOK_ANNIHILATIONS && you.religion != GOD_VEHUMET && (you.skills[SK_CONJURATIONS] < 10 @@ -1041,7 +1065,7 @@ int read_book( item_def &book, read_book_action_type action ) // Remember that this function is called from staff spells as well. const int keyin = spellbook_contents( book, action ); - if (book.base_type == OBJ_BOOKS) + if (book.base_type == OBJ_BOOKS && !book.props.exists( SPELL_LIST_KEY )) mark_had_book(book.sub_type); redraw_screen(); @@ -1150,7 +1174,7 @@ bool player_can_memorise(const item_def &book) for (int j = 0; j < SPELLBOOK_SIZE; j++) { - const spell_type stype = which_spell_in_book(book.book_number(), j); + const spell_type stype = which_spell_in_book(book, j); if (stype == SPELL_NO_SPELL) continue; @@ -1225,13 +1249,13 @@ bool learn_spell(int book) index = letter_to_index( spell ); if (index >= SPELLBOOK_SIZE - || !is_valid_spell_in_book( you.inv[book].sub_type, index )) + || !is_valid_spell_in_book( you.inv[book], index )) { canned_msg( MSG_HUH ); return (false); } - spell_type specspell = which_spell_in_book(you.inv[book].sub_type,index); + spell_type specspell = which_spell_in_book(you.inv[book], index); if (specspell == SPELL_NO_SPELL) { @@ -1373,7 +1397,7 @@ int count_staff_spells(const item_def &item, bool need_id) return (0); int nspel = 0; - while (nspel < SPELLBOOK_SIZE && is_valid_spell_in_book(type, nspel)) + while (nspel < SPELLBOOK_SIZE && is_valid_spell_in_book(item, nspel)) ++nspel; return (nspel); @@ -1468,16 +1492,13 @@ int staff_spell( int staff ) const int idx = letter_to_index( keyin ); - // converting sub_type into book index type - const int type = istaff.book_number(); - - if ((idx >= SPELLBOOK_SIZE) || !is_valid_spell_in_book(type, idx)) + if ((idx >= SPELLBOOK_SIZE) || !is_valid_spell_in_book(istaff, idx)) { canned_msg(MSG_HUH); return -1; } - const spell_type spell = which_spell_in_book( type, idx ); + const spell_type spell = which_spell_in_book( istaff, idx ); const int mana = spell_mana( spell ) * ROD_CHARGE_MULT; const int diff = spell_difficulty( spell ); diff --git a/crawl-ref/source/spl-book.h b/crawl-ref/source/spl-book.h index 4ccdc37f93..d156f7e977 100644 --- a/crawl-ref/source/spl-book.h +++ b/crawl-ref/source/spl-book.h @@ -13,6 +13,9 @@ #include "externs.h" #include "FixVec.h" +#define SPELLBOOK_SIZE 8 +#define SPELL_LIST_KEY "spell_list" + class formatted_string; enum read_book_action_type @@ -29,6 +32,7 @@ enum read_book_action_type int book_rarity(unsigned char which_book); +bool is_valid_spell_in_book( const item_def &book, int spell ); bool is_valid_spell_in_book( int splbook, int spell ); @@ -49,6 +53,7 @@ bool learn_spell(int book = -1); bool player_can_read_spellbook( const item_def &book ); +spell_type which_spell_in_book(const item_def &book, int spl); spell_type which_spell_in_book(int sbook_type, int spl); // returns amount practised (or -1 for abort) diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc index b16e8b3cd1..4dbd7654d1 100644 --- a/crawl-ref/source/spl-cast.cc +++ b/crawl-ref/source/spl-cast.cc @@ -2084,7 +2084,8 @@ spret_type your_spells(spell_type spell, int powc, bool allow_fail) default: #ifdef WIZARD - if (you.wizard && !allow_fail && is_valid_spell(spell)) + if (you.wizard && !allow_fail && is_valid_spell(spell) + && (flags & SPFLAG_MONSTER)) { _try_monster_cast(spell, powc, spd, beam); return (SPRET_SUCCESS); @@ -2097,6 +2098,7 @@ spret_type your_spells(spell_type spell, int powc, bool allow_fail) else mpr("Invalid spell!", MSGCH_ERROR); + return (SPRET_ABORT); break; } // end switch diff --git a/crawl-ref/source/spl-cast.h b/crawl-ref/source/spl-cast.h index b5e20c5403..8023305048 100644 --- a/crawl-ref/source/spl-cast.h +++ b/crawl-ref/source/spl-cast.h @@ -27,7 +27,8 @@ enum spflag_type 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_AREA = 0x0800, // area affect + SPFLAG_MONSTER = 0x1000 // monster-only spell }; enum spret_type diff --git a/crawl-ref/source/spl-data.h b/crawl-ref/source/spl-data.h index f301af2a9b..5f2a45fce5 100644 --- a/crawl-ref/source/spl-data.h +++ b/crawl-ref/source/spl-data.h @@ -2429,7 +2429,7 @@ { SPELL_HELLFIRE_BURST, "Hellfire Burst", SPTYP_CONJURATION | SPTYP_FIRE, - SPFLAG_DIR_OR_TARGET | SPFLAG_UNHOLY, + SPFLAG_DIR_OR_TARGET | SPFLAG_UNHOLY | SPFLAG_MONSTER, 9, 200, LOS_RADIUS, LOS_RADIUS, @@ -2441,7 +2441,7 @@ { SPELL_VAMPIRE_SUMMON, "Vampire Summon", SPTYP_SUMMONING, - SPFLAG_UNHOLY, + SPFLAG_UNHOLY | SPFLAG_MONSTER, 3, 0, -1, -1, @@ -2453,7 +2453,7 @@ { SPELL_BRAIN_FEED, "Brain Feed", SPTYP_NECROMANCY, - SPFLAG_UNHOLY | SPFLAG_TARGET, + SPFLAG_UNHOLY | SPFLAG_TARGET | SPFLAG_MONSTER, 3, 0, LOS_RADIUS, LOS_RADIUS, @@ -2465,7 +2465,7 @@ { SPELL_FAKE_RAKSHASA_SUMMON, "Rakshasa Summon", SPTYP_SUMMONING | SPTYP_NECROMANCY, - SPFLAG_UNHOLY, + SPFLAG_UNHOLY | SPFLAG_MONSTER, 3, 0, -1, -1, @@ -2477,7 +2477,7 @@ { SPELL_STEAM_BALL, "Steam Ball", SPTYP_CONJURATION | SPTYP_FIRE, - SPFLAG_DIR_OR_TARGET, + SPFLAG_DIR_OR_TARGET | SPFLAG_MONSTER, 4, 0, 7, 7, @@ -2489,7 +2489,7 @@ { SPELL_SUMMON_UFETUBUS, "Summon Ufetubus", SPTYP_SUMMONING, - SPFLAG_UNHOLY, + SPFLAG_UNHOLY | SPFLAG_MONSTER, 4, 0, -1, -1, @@ -2501,7 +2501,7 @@ { SPELL_SUMMON_BEAST, "Summon Beast", SPTYP_SUMMONING, - SPFLAG_UNHOLY, + SPFLAG_UNHOLY | SPFLAG_MONSTER, 4, 0, -1, -1, @@ -2513,7 +2513,7 @@ { SPELL_ENERGY_BOLT, "Energy Bolt", SPTYP_CONJURATION, - SPFLAG_DIR_OR_TARGET, + SPFLAG_DIR_OR_TARGET | SPFLAG_MONSTER, 4, 0, 8, 8, @@ -2525,7 +2525,7 @@ { SPELL_POISON_SPLASH, "Poison Splash", SPTYP_POISON, - SPFLAG_DIR_OR_TARGET, + SPFLAG_DIR_OR_TARGET | SPFLAG_MONSTER, 2, 0, 7, 7, @@ -2537,7 +2537,7 @@ { SPELL_SUMMON_UNDEAD, "Summon Undead", SPTYP_SUMMONING | SPTYP_NECROMANCY, - SPFLAG_NONE, + SPFLAG_MONSTER, 7, 0, -1, -1, @@ -2549,7 +2549,7 @@ { SPELL_CANTRIP, "Cantrip", SPTYP_NONE, - SPFLAG_NONE, + SPFLAG_MONSTER, 1, 0, -1, -1, @@ -2561,7 +2561,7 @@ { SPELL_QUICKSILVER_BOLT, "Quicksilver Bolt", SPTYP_CONJURATION, - SPFLAG_DIR_OR_TARGET, + SPFLAG_DIR_OR_TARGET | SPFLAG_MONSTER, 5, 0, 8, 8, @@ -2573,7 +2573,7 @@ { SPELL_METAL_SPLINTERS, "Metal Splinters", SPTYP_CONJURATION, - SPFLAG_DIR_OR_TARGET, + SPFLAG_DIR_OR_TARGET | SPFLAG_MONSTER, 5, 0, 5, 5, @@ -2585,7 +2585,7 @@ { SPELL_MIASMA, "Miasma", SPTYP_CONJURATION | SPTYP_NECROMANCY, - SPFLAG_DIR_OR_TARGET, + SPFLAG_DIR_OR_TARGET | SPFLAG_MONSTER, 6, 0, 6, 6, @@ -2597,7 +2597,7 @@ { SPELL_SUMMON_DRAKES, "Summon Drakes", SPTYP_SUMMONING, - SPFLAG_NONE, + SPFLAG_MONSTER, 6, 0, -1, -1, @@ -2609,7 +2609,7 @@ { SPELL_BLINK_OTHER, "Blink Other", SPTYP_TRANSLOCATION, - SPFLAG_ESCAPE | SPFLAG_DIR_OR_TARGET, + SPFLAG_ESCAPE | SPFLAG_DIR_OR_TARGET | SPFLAG_MONSTER, 2, 0, LOS_RADIUS, LOS_RADIUS, @@ -2621,7 +2621,7 @@ { SPELL_SUMMON_MUSHROOMS, "Summon Mushrooms", SPTYP_SUMMONING, - SPFLAG_NONE, + SPFLAG_MONSTER, 4, 0, -1, -1, -- cgit v1.2.3-54-g00ecf