summaryrefslogtreecommitdiffstats
path: root/crawl-ref
diff options
context:
space:
mode:
authorcjo <cjo@ulyco.com>2013-07-18 19:56:49 -0700
committerNeil Moore <neil@s-z.org>2013-08-24 13:47:01 -0400
commit2774ec9060c4295fa4dd60553dbd72c375f7f0bd (patch)
treefaf33a08e67a02581d98b1fed520cfd344cdc0c8 /crawl-ref
parent27b40443b5753db20c10c793f161485d1fe422ef (diff)
downloadcrawl-ref-2774ec9060c4295fa4dd60553dbd72c375f7f0bd.tar.gz
crawl-ref-2774ec9060c4295fa4dd60553dbd72c375f7f0bd.zip
Display monster spells and magical abilities with x-v
Decrease the need for spoilers by showing monster spells and magical abilities when examining a monster with the command x-v. If monsters have multiple possible spellbooks, all of them are listed.
Diffstat (limited to 'crawl-ref')
-rw-r--r--crawl-ref/source/Makefile4
-rw-r--r--crawl-ref/source/describe.cc63
-rw-r--r--crawl-ref/source/describe.h1
-rw-r--r--crawl-ref/source/mon-data.h5
-rw-r--r--crawl-ref/source/mon-spll.h5
-rw-r--r--crawl-ref/source/mon-util.cc134
-rw-r--r--crawl-ref/source/mon-util.h17
7 files changed, 142 insertions, 87 deletions
diff --git a/crawl-ref/source/Makefile b/crawl-ref/source/Makefile
index e4b96c548f..7365f0d9aa 100644
--- a/crawl-ref/source/Makefile
+++ b/crawl-ref/source/Makefile
@@ -1083,8 +1083,8 @@ LIBS += $(CONTRIB_LIBS) $(EXTRA_LIBS)
DOC_BASE := ../docs
DOC_TEMPLATES := $(DOC_BASE)/template
GENERATED_DOCS := $(DOC_BASE)/aptitudes.txt $(DOC_BASE)/FAQ.html $(DOC_BASE)/crawl_manual.txt
-GENERATED_HEADERS := art-enum.h config.h #the rest are private
-GENERATED_FILES := $(GENERATED_HEADERS) art-data.h mon-mst.h mi-enum.h \
+GENERATED_HEADERS := art-enum.h config.h mon-mst.h #the rest are private
+GENERATED_FILES := $(GENERATED_HEADERS) art-data.h mi-enum.h \
$(RLTILES)/dc-unrand.txt build.h compflag.h dat/dlua/tags.lua \
cmd-name.h
diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc
index 88e5a7ea65..509bf827b8 100644
--- a/crawl-ref/source/describe.cc
+++ b/crawl-ref/source/describe.cc
@@ -45,6 +45,7 @@
#include "message.h"
#include "mon-chimera.h"
#include "mon-stuff.h"
+#include "mon-util.h"
#include "output.h"
#include "player.h"
#include "quiver.h"
@@ -3261,6 +3262,68 @@ static string _monster_stat_description(const monster_info& mi)
else if (mons_class_flag(mi.type, M_SENSE_INVIS))
result << uppercase_first(pronoun) << " can sense the presence of invisible creatures.\n";
+ // Show monster spells and spell-like abilities.
+ if (mons_class_flag(mi.type, M_SPELLCASTER))
+ {
+ monster* mon = monster_at(mi.pos);
+ const monsterentry *m = get_monster_data(mon->type);
+ mon_spellbook_type book = (m->sec);
+ result << uppercase_first(pronoun);
+ // The combination of M_ACTUAL_SPELLS with MST_NO_SPELLS means multiple spellbooks
+ if (mons_class_flag(mi.type, M_ACTUAL_SPELLS) && book == MST_NO_SPELLS)
+ result << " has mastered one of the following spellbooks:\n";
+ // cjo: the division here gets really arbitrary. For example, wretched stars
+ // cast mystic blast, but are not flagged with M_ACTUAL_SPELLS. Possibly
+ // these should be combined.
+ else if (mons_class_flag(mi.type, M_ACTUAL_SPELLS) && book != MST_NO_SPELLS)
+ result << " has mastered the following spells: ";
+ else if (mons_class_flag(mi.type, M_SPELLCASTER) && book != MST_NO_SPELLS)
+ result << " possesses the following magical abilities: ";
+
+ vector<mon_spellbook_type> books = _get_spellbook_list(mon);
+
+ // Loop through books and display spells/abilities for each of them
+ int num_books = books.size();
+ for (int i = 0; i < num_books; ++i)
+ {
+ // Create spell list containing no duplicate or irrelevant entries
+ book = books[i];
+ vector<spell_type> book_spells;
+ for (int j = 0; j < NUM_MONSTER_SPELL_SLOTS; ++j)
+ {
+ const spell_type &spell = mspell_list[book].spells[j];
+ bool match = false;
+ for (unsigned int k = 0; k < book_spells.size(); ++k)
+ {
+ if(book_spells[k] == spell)
+ match = true;
+ }
+ if(!match && spell != SPELL_NO_SPELL && spell != SPELL_MELEE
+ && spell != SPELL_CANTRIP)
+ {
+ book_spells.push_back(spell);
+ }
+ }
+
+ // Special casing for Ogre Mages (they always get their first spell
+ // changed to Haste Other).
+ if (mi.type == MONS_OGRE_MAGE)
+ book_spells[0] = SPELL_HASTE_OTHER;
+
+ // Display spells for this book
+ if (num_books > 1)
+ result << "Book " << i+1 << ": ";
+ for (unsigned int j = 0; j < book_spells.size(); ++j)
+ {
+ const spell_type spell = book_spells[j];
+ if(j > 0)
+ result << ", ";
+ result << spell_title(spell);
+ }
+ result << "\n";
+ }
+ } // end if(mons_class_flag(mi.type, M_SPELLCASTER))
+
// Unusual monster speed.
const int speed = mi.base_speed();
if (speed != 10 && speed != 0)
diff --git a/crawl-ref/source/describe.h b/crawl-ref/source/describe.h
index 7f6b42c26c..c24127605d 100644
--- a/crawl-ref/source/describe.h
+++ b/crawl-ref/source/describe.h
@@ -10,6 +10,7 @@
#include <sstream>
#include "externs.h"
#include "enum.h"
+#include "mon-util.h"
struct monster_info;
diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h
index bc49c2d30d..054a57f454 100644
--- a/crawl-ref/source/mon-data.h
+++ b/crawl-ref/source/mon-data.h
@@ -67,6 +67,11 @@
105 < hp < 165
hp will be around 135 each time.
+ sec: if the monster has only one possible spellbook, sec is set to that book.
+ If a monster has multiple possible books, sec is set to MST_NO_SPELLS. Then
+ the function _get_spellbook_list in mon-util.cc checks for the flag
+ M_SPELLCASTER, and handles the books.
+
corpse_thingy
- err, bad name. Describes effects of eating corpses.
CE_NOCORPSE, leaves no corpse (mass == 0)
diff --git a/crawl-ref/source/mon-spll.h b/crawl-ref/source/mon-spll.h
index 135edf2c25..54c0681c98 100644
--- a/crawl-ref/source/mon-spll.h
+++ b/crawl-ref/source/mon-spll.h
@@ -4,9 +4,13 @@
/* *********************************************************************
+ This file determines which spells are contained in monster spellbooks.
+ It is used by /util/gen-mst.pl to generate spellbook enums, which are
+ listed in mon-mst.h.
Template Format:
+ { mon_spellbook_type type
{
bolt spell,
enchantment,
@@ -15,6 +19,7 @@
misc(2) spell, // SPELL_DIG must be here to work!
emergency spell // only when fleeing
}
+ }
********************************************************************* */
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 1c8dad2138..4501fa8cb9 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -77,19 +77,6 @@ static bool initialised_randmons = false;
static vector<monster_type> monsters_by_habitat[NUM_HABITATS];
static vector<monster_type> species_by_habitat[NUM_HABITATS];
-#include "mon-mst.h"
-
-struct mon_spellbook
-{
- mon_spellbook_type type;
- spell_type spells[NUM_MONSTER_SPELL_SLOTS];
-};
-
-static const mon_spellbook mspell_list[] =
-{
-#include "mon-spll.h"
-};
-
#include "mon-data.h"
#define MONDATASIZE ARRAYSZ(mondata)
@@ -2097,103 +2084,98 @@ monster_type random_draconian_monster_species()
// contains the unholy and chaotic Banishment spell, but the other
// MST_WIZARD-type spellbooks contain no unholy, evil, unclean or
// chaotic spells.
-static bool _get_spellbook_list(mon_spellbook_type book[6],
- monster* mon)
+//
+// If a monster has only one spellbook, it is specified in mon-data.h.
+// If it has multiple books, mon-data.h sets the book to MST_NO_SPELLS,
+// and the books are accounted for here.
+vector<mon_spellbook_type> _get_spellbook_list(monster* mon)
{
- bool retval = true;
- int mon_type = mon->type;
-
- book[0] = MST_NO_SPELLS;
- book[1] = MST_NO_SPELLS;
- book[2] = MST_NO_SPELLS;
- book[3] = MST_NO_SPELLS;
- book[4] = MST_NO_SPELLS;
- book[5] = MST_NO_SPELLS;
+ vector<mon_spellbook_type> books;
+ const monsterentry *m = get_monster_data(mon->type);
+ mon_spellbook_type book = (m->sec);
+ int mon_type = mon->type;
switch (mon_type)
{
case MONS_HELL_KNIGHT:
- book[0] = MST_HELL_KNIGHT_I;
- book[1] = MST_HELL_KNIGHT_II;
+ books.push_back(MST_HELL_KNIGHT_I);
+ books.push_back(MST_HELL_KNIGHT_II);
break;
case MONS_LICH:
case MONS_ANCIENT_LICH:
- book[0] = MST_LICH_I;
- book[1] = MST_LICH_II;
- book[2] = MST_LICH_III;
- book[3] = MST_LICH_IV;
+ books.push_back(MST_LICH_I);
+ books.push_back(MST_LICH_II);
+ books.push_back(MST_LICH_III);
+ books.push_back(MST_LICH_IV);
break;
case MONS_NECROMANCER:
- book[0] = MST_NECROMANCER_I;
- book[1] = MST_NECROMANCER_II;
+ books.push_back(MST_NECROMANCER_I);
+ books.push_back(MST_NECROMANCER_II);
break;
case MONS_ORC_WIZARD:
+ case MONS_DEEP_ELF_SOLDIER:
case MONS_DEEP_ELF_FIGHTER:
case MONS_DEEP_ELF_KNIGHT:
- book[0] = MST_ORC_WIZARD_I;
- book[1] = MST_ORC_WIZARD_II;
- book[2] = MST_ORC_WIZARD_III;
+ books.push_back(MST_ORC_WIZARD_I);
+ books.push_back(MST_ORC_WIZARD_II);
+ books.push_back(MST_ORC_WIZARD_III);
break;
case MONS_WIZARD:
case MONS_OGRE_MAGE:
case MONS_EROLCHA:
- book[0] = MST_WIZARD_I;
- book[1] = MST_WIZARD_II;
- book[2] = MST_WIZARD_III;
- book[3] = MST_WIZARD_IV;
- book[4] = MST_WIZARD_V;
+ case MONS_DEEP_ELF_MAGE:
+ books.push_back(MST_WIZARD_I);
+ books.push_back(MST_WIZARD_II);
+ books.push_back(MST_WIZARD_III);
+ books.push_back(MST_WIZARD_IV);
+ books.push_back(MST_WIZARD_V);
break;
case MONS_DRACONIAN_KNIGHT:
- book[0] = MST_DEEP_ELF_CONJURER;
- book[1] = MST_HELL_KNIGHT_I;
- book[2] = MST_HELL_KNIGHT_II;
- book[3] = MST_NECROMANCER_I;
- book[4] = MST_NECROMANCER_II;
+ books.push_back(MST_DEEP_ELF_CONJURER);
+ books.push_back(MST_HELL_KNIGHT_I);
+ books.push_back(MST_HELL_KNIGHT_II);
+ books.push_back(MST_NECROMANCER_I);
+ books.push_back(MST_NECROMANCER_II);
break;
case MONS_ANCIENT_CHAMPION:
- book[0] = MST_ANCIENT_CHAMPION_I;
- book[1] = MST_ANCIENT_CHAMPION_II;
- book[2] = MST_ANCIENT_CHAMPION_III;
- book[3] = MST_ANCIENT_CHAMPION_IV;
+ books.push_back(MST_ANCIENT_CHAMPION_I);
+ books.push_back(MST_ANCIENT_CHAMPION_II);
+ books.push_back(MST_ANCIENT_CHAMPION_III);
+ books.push_back(MST_ANCIENT_CHAMPION_IV);
break;
case MONS_TENGU_CONJURER:
- book[0] = MST_TENGU_CONJURER_I;
- book[1] = MST_TENGU_CONJURER_II;
- book[2] = MST_TENGU_CONJURER_III;
- book[3] = MST_TENGU_CONJURER_IV;
+ books.push_back(MST_TENGU_CONJURER_I);
+ books.push_back(MST_TENGU_CONJURER_II);
+ books.push_back(MST_TENGU_CONJURER_III);
+ books.push_back(MST_TENGU_CONJURER_IV);
break;
case MONS_TENGU_REAVER:
- book[0] = MST_TENGU_REAVER_I;
- book[1] = MST_TENGU_REAVER_II;
- book[2] = MST_TENGU_REAVER_III;
- break;
-
- case MONS_DEEP_ELF_MAGE:
- book[0] = MST_DEEP_ELF_MAGE_I;
- book[1] = MST_DEEP_ELF_MAGE_II;
- book[2] = MST_DEEP_ELF_MAGE_III;
- book[3] = MST_DEEP_ELF_MAGE_IV;
- book[4] = MST_DEEP_ELF_MAGE_V;
+ books.push_back(MST_TENGU_REAVER_I);
+ books.push_back(MST_TENGU_REAVER_II);
+ books.push_back(MST_TENGU_REAVER_III);
break;
default:
- retval = false;
+ books.push_back(book);
break;
}
- return retval;
+ return books;
}
-static void _mons_load_spells(monster* mon, mon_spellbook_type book)
+static void _mons_load_spells(monster* mon)
{
+ vector<mon_spellbook_type> books = _get_spellbook_list(mon);
+ mon_spellbook_type book = books[random2(books.size())];
+
if (book == MST_GHOST)
return mon->load_ghost_spells();
@@ -2213,22 +2195,6 @@ static void _mons_load_spells(monster* mon, mon_spellbook_type book)
break;
}
}
-}
-
-static void _get_spells(mon_spellbook_type book, monster* mon)
-{
- if (book == MST_NO_SPELLS && mons_class_flag(mon->type, M_SPELLCASTER))
- {
- mon_spellbook_type multi_book[6];
- if (_get_spellbook_list(multi_book, mon))
- {
- do
- book = multi_book[random2(6)];
- while (book == MST_NO_SPELLS);
- }
- }
-
- _mons_load_spells(mon, book);
// (Dumb) special casing to give ogre mages Haste Other. -cao
if (mon->type == MONS_OGRE_MAGE)
@@ -2442,7 +2408,7 @@ void define_monster(monster* mons)
mons->bind_melee_flags();
- _get_spells((mon_spellbook_type)m->sec, mons);
+ _mons_load_spells(mons);
mons->bind_spell_flags();
// Reset monster enchantments.
diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h
index 020b7cfa2f..d9733833a9 100644
--- a/crawl-ref/source/mon-util.h
+++ b/crawl-ref/source/mon-util.h
@@ -11,6 +11,7 @@
#include "enum.h"
#include "mon-enum.h"
#include "player.h"
+#include "mon-mst.h"
struct bolt;
@@ -96,6 +97,20 @@ private:
}
};
+vector<mon_spellbook_type> _get_spellbook_list(monster* mon);
+
+struct mon_spellbook
+{
+ mon_spellbook_type type;
+ spell_type spells[NUM_MONSTER_SPELL_SLOTS];
+};
+
+static const mon_spellbook mspell_list[] =
+{
+#include "mon-spll.h"
+};
+
+
struct monsterentry
{
short mc; // monster number
@@ -134,7 +149,7 @@ struct monsterentry
int8_t AC; // armour class
int8_t ev; // evasion
- int sec; // spellbook
+ mon_spellbook_type sec;
corpse_effect_type corpse_thingy;
zombie_size_type zombie_size;
shout_type shouts;