summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2008-12-04 06:38:17 +0000
committerzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2008-12-04 06:38:17 +0000
commitcc0f9b2965e5298577253965c8819636985ac2db (patch)
treef586194693a2b6e0ff63411ddd6b136d137e9032
parentfccc5c8dd647216dc3ad7faff107a8ffc77acfb8 (diff)
downloadcrawl-ref-cc0f9b2965e5298577253965c8819636985ac2db.tar.gz
crawl-ref-cc0f9b2965e5298577253965c8819636985ac2db.zip
Savefile compatibility breakage from keeping track of which spells have been
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
-rw-r--r--crawl-ref/source/acr.cc28
-rw-r--r--crawl-ref/source/command.cc60
-rw-r--r--crawl-ref/source/dat/descript/spells.txt4
-rw-r--r--crawl-ref/source/describe.cc2
-rw-r--r--crawl-ref/source/effects.cc4
-rw-r--r--crawl-ref/source/enum.h2
-rw-r--r--crawl-ref/source/externs.h3
-rw-r--r--crawl-ref/source/items.cc55
-rw-r--r--crawl-ref/source/items.h20
-rw-r--r--crawl-ref/source/newgame.cc2
-rw-r--r--crawl-ref/source/randart.cc118
-rw-r--r--crawl-ref/source/religion.cc116
-rw-r--r--crawl-ref/source/religion.h5
-rw-r--r--crawl-ref/source/spl-book.cc286
-rw-r--r--crawl-ref/source/spl-book.h11
-rw-r--r--crawl-ref/source/spl-cast.cc14
-rw-r--r--crawl-ref/source/spl-cast.h35
-rw-r--r--crawl-ref/source/spl-data.h62
-rw-r--r--crawl-ref/source/spl-util.cc27
-rw-r--r--crawl-ref/source/spl-util.h1
-rw-r--r--crawl-ref/source/tags.cc9
-rw-r--r--crawl-ref/source/xom.cc2
22 files changed, 688 insertions, 178 deletions
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index b0a88dccfe..90d5d14411 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -514,7 +514,9 @@ static void _do_wizard_command(int wiz_command, bool silent_fail)
if (prompt_failed(i))
break;
- if (!_item_type_can_be_artefact(you.inv[i].base_type))
+ item_def &item(you.inv[i]);
+
+ if (!_item_type_can_be_artefact(item.base_type))
{
mpr("That item cannot be turned into an artefact.");
break;
@@ -529,13 +531,29 @@ static void _do_wizard_command(int wiz_command, bool silent_fail)
if (j == EQ_WEAPON)
you.wield_change = true;
- if (is_random_artefact( you.inv[i] ))
+ if (is_random_artefact( item ))
unuse_randart( i );
break;
}
}
- 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 ))
{
mpr("Failed to turn item into randart.");
break;
@@ -543,7 +561,7 @@ static void _do_wizard_command(int wiz_command, bool silent_fail)
if (Options.autoinscribe_randarts)
{
- add_autoinscription(you.inv[i],
+ add_autoinscription(item,
randart_auto_inscription(you.inv[i]));
}
@@ -551,7 +569,7 @@ static void _do_wizard_command(int wiz_command, bool silent_fail)
if (j != NUM_EQUIP)
use_randart( i );
- mpr( you.inv[i].name(DESC_INVENTORY_EQUIP).c_str() );
+ mpr( item.name(DESC_INVENTORY_EQUIP).c_str() );
break;
}
case '|':
diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc
index 00188b7a77..cdc00ca7cf 100644
--- a/crawl-ref/source/command.cc
+++ b/crawl-ref/source/command.cc
@@ -1050,7 +1050,22 @@ static bool _monster_filter(std::string key, std::string body)
static bool _spell_filter(std::string key, std::string body)
{
- 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);
}
static bool _item_filter(std::string key, std::string body)
@@ -1107,6 +1122,44 @@ static void _recap_feat_keys(std::vector<std::string> &keys)
}
}
+// 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.";
+ }
+}
+
// Adds a list of all books/rods that contain a given spell (by name)
// to a description string.
static bool _append_books(std::string &desc, item_def &item, std::string key)
@@ -1163,9 +1216,6 @@ static bool _append_books(std::string &desc, item_def &item, std::string key)
rods.push_back(item.name(DESC_PLAIN));
}
- if (books.empty() && rods.empty())
- return (false);
-
if (!books.empty())
{
desc += "$$This spell can be found in the following book";
@@ -1359,6 +1409,8 @@ static bool _do_description(std::string key, std::string footer = "")
if (!_append_books(desc, mitm[thing_created], key))
_append_spells(desc, mitm[thing_created]);
}
+ else
+ _append_non_item(desc, key);
// Now we don't need the item anymore.
destroy_item(thing_created);
diff --git a/crawl-ref/source/dat/descript/spells.txt b/crawl-ref/source/dat/descript/spells.txt
index 31dd72eb29..49eb9e63e5 100644
--- a/crawl-ref/source/dat/descript/spells.txt
+++ b/crawl-ref/source/dat/descript/spells.txt
@@ -175,6 +175,10 @@ Death's Door
This spell is extremely powerful, but carries a degree of risk. It renders living casters nigh invulnerable to harm for a brief period, but can bring them dangerously close to death (how close depends on one's necromantic abilities). The spell can be cancelled at any time by any healing effect, and the caster will receive one warning shortly before the spell expires. Undead cannot use this spell.
%%%%
+Debugging Ray
+
+A ray which does massive damage (1500 hp) and always hits.
+%%%%
Deflect Missiles
This spell protects the caster from any kind of projectile attack, although particularly powerful attacks (lightning bolts, etc.) are deflected to a lesser extent than lighter missiles.
diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc
index c9aba5ab84..821000775d 100644
--- a/crawl-ref/source/describe.cc
+++ b/crawl-ref/source/describe.cc
@@ -2068,7 +2068,7 @@ static bool _describe_spells(const item_def &item)
const int spell_index = letter_to_index(c);
spell_type nthing =
- which_spell_in_book(item.book_number(), spell_index);
+ which_spell_in_book(item, spell_index);
if (nthing == SPELL_NO_SPELL)
return (false);
diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc
index 7bbe08c462..fdc3f628a7 100644
--- a/crawl-ref/source/effects.cc
+++ b/crawl-ref/source/effects.cc
@@ -1577,7 +1577,7 @@ bool acquirement(object_class_type class_wanted, int agent,
do_uncurse_item(thing);
if (thing.base_type == OBJ_BOOKS)
- mark_had_book(thing.sub_type);
+ mark_had_book(thing);
else if (thing.base_type == OBJ_JEWELLERY)
{
switch (thing.sub_type)
@@ -1702,7 +1702,7 @@ bool acquirement(object_class_type class_wanted, int agent,
}
}
- if (agent > AQ_SCROLL && agent == you.religion)
+ if (agent > GOD_NO_GOD && agent < NUM_GODS && agent == you.religion)
{
thing.inscription = "god gift";
if (is_random_artefact(thing))
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index b15edfa7da..6ed738ef2f 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -165,6 +165,8 @@ enum attribute_type
ATTR_PURCHASES, // Gold amount spent at shops.
ATTR_DONATIONS, // Gold amount donated to Zin.
ATTR_MISC_SPENDING, // Spending for things like ziggurats.
+ ATTR_RND_LVL_BOOKS, // Bitfield of level-type randart spellbooks
+ // player has seen.
NUM_ATTRIBUTES
};
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index f73d24df6c..08114ea0f0 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -876,7 +876,8 @@ public:
FixedVector<unsigned char, NUM_MUTATIONS> demon_pow;
unsigned char magic_contamination;
- FixedVector<bool, NUM_BOOKS> had_book;
+ FixedVector<bool, NUM_BOOKS> had_book;
+ FixedVector<bool, NUM_SPELLS> seen_spell;
unsigned char normal_vision; // how far the species gets to see
unsigned char current_vision; // current sight radius (cells)
diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc
index 75151e4d9e..f92a14d34f 100644
--- a/crawl-ref/source/items.cc
+++ b/crawl-ref/source/items.cc
@@ -872,7 +872,7 @@ void origin_set_startequip(item_def &item)
if (!origin_known(item))
{
item.orig_place = 0xFFFF;
- item.orig_monnum = -1;
+ item.orig_monnum = -IT_SRC_START;
}
}
@@ -900,8 +900,7 @@ void origin_purchased(item_def &item)
// We don't need to check origin_known if it's a shop purchase
item.orig_place = get_packed_place();
_origin_set_portal_vault(item);
- // Hackiness
- item.orig_monnum = -1;
+ item.orig_monnum = -IT_SRC_SHOP;
}
void origin_acquired(item_def &item, int agent)
@@ -909,8 +908,7 @@ void origin_acquired(item_def &item, int agent)
// We don't need to check origin_known if it's a divine gift
item.orig_place = get_packed_place();
_origin_set_portal_vault(item);
- // Hackiness
- item.orig_monnum = -2 - agent;
+ item.orig_monnum = -agent;
}
void origin_set_inventory(void (*oset)(item_def &item))
@@ -1066,22 +1064,42 @@ static std::string _article_it(const item_def &item)
static bool _origin_is_original_equip(const item_def &item)
{
- return (item.orig_place == 0xFFFFU && item.orig_monnum == -1);
+ return (item.orig_place == 0xFFFFU && item.orig_monnum == -IT_SRC_START);
}
-bool origin_is_god_gift(const item_def& item)
+bool origin_is_god_gift(const item_def& item, god_type *god)
{
- if (!origin_describable(item))
- return false;
+ god_type junk;
+ if (god == NULL)
+ god = &junk;
+ *god = GOD_NO_GOD;
- if (_origin_is_original_equip(item))
- return false;
+ const int iorig = -item.orig_monnum;
+ if (iorig > GOD_NO_GOD && iorig < NUM_GODS)
+ {
+ *god = static_cast<god_type>(iorig);
+ return(true);
+ }
+
+ return (false);
+}
- if (item.orig_monnum >= 0)
- return false;
+bool origin_is_acquirement(const item_def& item, item_source_type *type)
+{
+ item_source_type junk;
+ if (type == NULL)
+ type = &junk;
+ *type = IT_SRC_NONE;
- const int iorig = -item.orig_monnum - 2;
- return (iorig > AQ_SCROLL && iorig < AQ_CARD_GENIE);
+ const int iorig = -item.orig_monnum;
+ if (iorig == AQ_SCROLL || iorig == AQ_CARD_GENIE
+ || iorig == AQ_WIZMODE)
+ {
+ *type = static_cast<item_source_type>(iorig);
+ return (true);
+ }
+
+ return (false);
}
std::string origin_desc(const item_def &item)
@@ -1097,12 +1115,15 @@ std::string origin_desc(const item_def &item)
{
if (item.orig_monnum < 0)
{
- int iorig = -item.orig_monnum - 2;
+ int iorig = -item.orig_monnum;
switch (iorig)
{
- case -1:
+ case IT_SRC_SHOP:
desc += "You bought " + _article_it(item) + " in a shop ";
break;
+ case IT_SRC_START:
+ desc += "Buggy Original Equipment: ";
+ break;
case AQ_SCROLL:
desc += "You acquired " + _article_it(item) + " ";
break;
diff --git a/crawl-ref/source/items.h b/crawl-ref/source/items.h
index fa892313c4..a56f625c17 100644
--- a/crawl-ref/source/items.h
+++ b/crawl-ref/source/items.h
@@ -12,16 +12,22 @@
#include "externs.h"
-// Various ways to get the acquirement effect.
-enum acquirement_agent_type
+// Ways to get items, other than finding them on the ground or looting them
+// from slain monsters.
+enum item_source_type
{
- AQ_SCROLL = 0,
+ IT_SRC_NONE = 0,
// Empty space for the gods
- AQ_CARD_GENIE = 100,
+ AQ_SCROLL = 100,
+ AQ_CARD_GENIE,
+ IT_SRC_START,
+ IT_SRC_SHOP,
- AQ_WIZMODE = 200
+ // Empty space for new non-wizmode acquisition methods
+
+ AQ_WIZMODE = 200
};
bool is_valid_item( const item_def &item );
@@ -135,7 +141,9 @@ void origin_acquired(item_def &item, int agent);
void origin_set_startequip(item_def &item);
void origin_set_unknown(item_def &item);
void origin_set_inventory( void (*oset)(item_def &item) );
-bool origin_is_god_gift(const item_def& item);
+bool origin_is_god_gift(const item_def& item, god_type *god = NULL);
+bool origin_is_acquirement(const item_def& item,
+ item_source_type *type = NULL);
std::string origin_monster_name(const item_def &item);
bool item_needs_autopickup(const item_def &);
diff --git a/crawl-ref/source/newgame.cc b/crawl-ref/source/newgame.cc
index 8f62376770..4126748058 100644
--- a/crawl-ref/source/newgame.cc
+++ b/crawl-ref/source/newgame.cc
@@ -859,7 +859,7 @@ static void _mark_starting_books()
{
for (int i = 0; i < ENDOFPACK; i++)
if (is_valid_item(you.inv[i]) && you.inv[i].base_type == OBJ_BOOKS)
- mark_had_book(you.inv[i].sub_type);
+ mark_had_book(you.inv[i]);
}
static void _racialise_starting_equipment()
diff --git a/crawl-ref/source/randart.cc b/crawl-ref/source/randart.cc
index 93c13f7646..af02f12708 100644
--- a/crawl-ref/source/randart.cc
+++ b/crawl-ref/source/randart.cc
@@ -26,8 +26,6 @@
#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"
@@ -35,6 +33,9 @@
#define RANDART_NAME_KEY "randart_name"
#define RANDART_APPEAR_KEY "randart_appearance"
+#define SPELL_LIST_KEY "spell_list"
+#define SPELLBOOK_SIZE 8
+
static const char* _get_fixedart_name(const item_def &item);
// The initial generation of a randart is very simple - it occurs in
@@ -78,7 +79,12 @@ static bool _god_fits_artefact(const god_type which_god, const item_def &item,
type_bad = true;
break;
- case GOD_TROG: // hates anything enhancing magic
+ case GOD_TROG:
+ // Trog hates spell use.
+ if (item.base_type == OBJ_BOOKS)
+ type_bad = true;
+
+ // hates anything enhancing magic
if (item.base_type == OBJ_JEWELLERY && (item.sub_type == RING_WIZARDRY
|| item.sub_type == RING_FIRE || item.sub_type == RING_ICE
|| item.sub_type == RING_MAGICAL_POWER))
@@ -171,27 +177,13 @@ static bool _god_fits_artefact(const god_type which_god, const item_def &item,
return (true);
}
-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;
-}
-
static std::string _replace_name_parts(const std::string name_in,
- const item_def item)
+ const item_def& item)
{
std::string name = name_in;
- god_type god_gift = _gift_from_god(item);
+ god_type god_gift;
+ (void) origin_is_god_gift(item, &god_gift);
// Don't allow "player's Death" type names for god gifts (except Xom!)
if (name.find("@player_death@", 0) != std::string::npos
@@ -1130,67 +1122,12 @@ void static _get_randart_properties(const item_def &item,
}
}
-static bool _compare_spell_dificulties(spell_type a, spell_type b)
+static bool _init_randart_book(item_def &book)
{
- return (spell_difficulty(a) < spell_difficulty(b));
+ return make_book_level_randart(book, -1, 8);
}
-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];
-}
-
-void static _init_randart_properties(item_def &item)
+static bool _init_randart_properties(item_def &item)
{
ASSERT( is_random_artefact( item ) );
CrawlHashTable &props = item.props;
@@ -1210,20 +1147,19 @@ void static _init_randart_properties(item_def &item)
for (int i = 0; i < RA_PROPERTIES; i++)
rap[i] = (short) unrand->prpty[i];
- return;
+ return (true);
}
if (item.base_type == OBJ_BOOKS)
- {
- _init_randart_book(item);
- return;
- }
+ return _init_randart_book(item);
randart_properties_t prop;
_get_randart_properties(item, prop);
for (int i = 0; i < RA_PROPERTIES; i++)
rap[i] = (short) prop[i];
+
+ return (true);
}
void randart_wpn_properties( const item_def &item,
@@ -1432,7 +1368,7 @@ std::string artefact_name(const item_def &item, bool appearance)
// for actually naming an item.
item_orig = item.orig_monnum;
if (item_orig < 0)
- item_orig = -item_orig - 2;
+ item_orig = -item_orig;
else
item_orig = 0;
@@ -2111,13 +2047,23 @@ bool make_item_randart( item_def &item )
item.flags |= ISFLAG_RANDART;
- god_type god_gift = _gift_from_god(item);
+ god_type god_gift;
+ (void) origin_is_god_gift(item, &god_gift);
do
{
item.special = (random_int() & RANDART_SEED_MASK);
// Now that we found something, initialize the props array.
- _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);
+ }
}
while (randart_is_bad(item)
|| god_gift != GOD_NO_GOD && !_god_fits_artefact(god_gift, item));
diff --git a/crawl-ref/source/religion.cc b/crawl-ref/source/religion.cc
index 491e0f2639..7b8cb4f726 100644
--- a/crawl-ref/source/religion.cc
+++ b/crawl-ref/source/religion.cc
@@ -62,6 +62,7 @@
#include "spells3.h"
#include "spells4.h"
#include "spl-book.h"
+#include "spl-cast.h"
#include "spl-mis.h"
#include "spl-util.h"
#include "stash.h"
@@ -3442,6 +3443,121 @@ bool god_dislikes_item_handling(const item_def &item)
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))
+ {
+ return (true);
+ }
+
+ // 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;
+ }
+
+ return (false);
+}
+
+bool god_dislikes_spell_school(int school, god_type god)
+{
+ if (god == GOD_NO_GOD)
+ return (false);
+
+ if (is_good_god(god) && school == SPTYP_NECROMANCY)
+ return (true);
+
+ 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);
+}
+
// Is the destroyed weapon valuable enough to gain piety by doing so?
// Evil weapons are handled specially.
static bool _destroyed_valuable_weapon(int value, int type)
diff --git a/crawl-ref/source/religion.h b/crawl-ref/source/religion.h
index 99f585b283..0fa38d2d9c 100644
--- a/crawl-ref/source/religion.h
+++ b/crawl-ref/source/religion.h
@@ -108,8 +108,13 @@ bool is_evil_item(const item_def& item);
bool is_chaotic_item(const item_def& item);
bool good_god_dislikes_item_handling(const item_def &item);
bool god_dislikes_item_handling(const item_def &item);
+
+bool god_dislikes_spell_type(spell_type spell, god_type god = you.religion);
+bool god_dislikes_spell_school(int school, god_type god = you.religion);
+
bool trog_burn_spellbooks();
bool ely_destroy_weapons();
+
bool tso_unchivalric_attack_safe_monster(const monsters *mon);
void mons_make_god_gift(monsters *mon, god_type god = you.religion);
diff --git a/crawl-ref/source/spl-book.cc b/crawl-ref/source/spl-book.cc
index 957a5027e2..f4f4eac6cd 100644
--- a/crawl-ref/source/spl-book.cc
+++ b/crawl-ref/source/spl-book.cc
@@ -12,6 +12,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <algorithm>
#ifdef DOS
#include <conio.h>
@@ -38,6 +39,14 @@
#include "state.h"
#include "stuff.h"
+#define SPELL_LIST_KEY "spell_list"
+
+#define RANDART_BOOK_TYPE_KEY "randart_book_type"
+#define RANDART_BOOK_LEVEL_KEY "randart_book_level"
+
+#define RANDART_BOOK_TYPE_LEVEL "level"
+#define RANDART_BOOK_TYPE_THEME "theme"
+
#define SPELLBOOK_SIZE 8
#define NUMBER_SPELLBOOKS 61
@@ -1032,9 +1041,38 @@ bool player_can_read_spellbook( const item_def &book )
return (true);
}
+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;
+ }
+
+ if (!book.props.exists( SPELL_LIST_KEY ))
+ mark_had_book(book.book_number());
+}
void mark_had_book(int booktype)
{
+ ASSERT(booktype >= 0 && booktype < NUM_BOOKS);
+
+ if (booktype == BOOK_MANUAL || booktype == BOOK_DESTRUCTION)
+ {
+ return;
+ }
+
you.had_book[booktype] = true;
if ( booktype == BOOK_MINOR_MAGIC_I
@@ -1065,8 +1103,8 @@ 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 && !book.props.exists( SPELL_LIST_KEY ))
- mark_had_book(book.sub_type);
+ if (book.base_type == OBJ_BOOKS)
+ mark_had_book(book);
redraw_screen();
@@ -1557,3 +1595,247 @@ int staff_spell( int staff )
return (roll_dice( 1, 1 + spell_difficulty(spell) / 2 ));
}
+
+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);
+}
diff --git a/crawl-ref/source/spl-book.h b/crawl-ref/source/spl-book.h
index d156f7e977..f61432d83d 100644
--- a/crawl-ref/source/spl-book.h
+++ b/crawl-ref/source/spl-book.h
@@ -13,9 +13,6 @@
#include "externs.h"
#include "FixVec.h"
-#define SPELLBOOK_SIZE 8
-#define SPELL_LIST_KEY "spell_list"
-
class formatted_string;
enum read_book_action_type
@@ -35,8 +32,9 @@ 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 );
-
+void mark_had_book(const item_def &book);
void mark_had_book(int booktype);
+
// updated 24may2000 {dlb}
/* ***********************************************************************
* called from: it_use3 - item_use - spl-book
@@ -67,4 +65,9 @@ int spellbook_contents( item_def &book, read_book_action_type action,
int count_staff_spells(const item_def &item, bool need_id);
int rod_shield_leakage();
+bool make_book_level_randart(item_def &book, int level = -1,
+ int num_spells = -1);
+bool make_book_theme_randart(item_def &book,
+ int school_one = 0, int school_two = 0,
+ int num_spells = -1, int max_levels = -1);
#endif
diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc
index 4dbd7654d1..c1ac0e90ad 100644
--- a/crawl-ref/source/spl-cast.cc
+++ b/crawl-ref/source/spl-cast.cc
@@ -976,17 +976,27 @@ int _setup_evaporate_cast()
// Others are currently unused or unimplemented.
spret_type your_spells(spell_type spell, int powc, bool allow_fail)
{
+ const bool wiz_cast = (crawl_state.prev_cmd == CMD_WIZARD && !allow_fail);
+
dist spd;
bolt beam;
// [dshaligram] Any action that depends on the spellcasting attempt to have
// succeeded must be performed after the switch().
-
- if (_spell_is_uncastable(spell))
+ if (!wiz_cast && _spell_is_uncastable(spell))
return (SPRET_ABORT);
const unsigned int flags = get_spell_flags(spell);
+ ASSERT(wiz_cast || !(flags & SPFLAG_TESTING));
+ if ((flags & SPFLAG_TESTING) && !wiz_cast)
+ {
+ mprf(MSGCH_ERROR, "Spell %s is a testing spell, but you didn't use "
+ "the &Z wizard command; please file a bug report.",
+ spell_title(spell));
+ return (SPRET_ABORT);
+ }
+
int potion = -1;
// XXX: This handles only some of the cases where spells need targeting...
diff --git a/crawl-ref/source/spl-cast.h b/crawl-ref/source/spl-cast.h
index 8023305048..eaee3478a0 100644
--- a/crawl-ref/source/spl-cast.h
+++ b/crawl-ref/source/spl-cast.h
@@ -14,21 +14,26 @@
enum spflag_type
{
- 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
};
enum spret_type
diff --git a/crawl-ref/source/spl-data.h b/crawl-ref/source/spl-data.h
index 5f2a45fce5..e16c6f7abd 100644
--- a/crawl-ref/source/spl-data.h
+++ b/crawl-ref/source/spl-data.h
@@ -240,7 +240,7 @@
{
SPELL_TWIST, "Twist",
SPTYP_TRANSLOCATION,
- SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF,
+ SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF | SPFLAG_BATTLE,
1,
25,
LOS_RADIUS, LOS_RADIUS,
@@ -252,7 +252,7 @@
{
SPELL_FAR_STRIKE, "Far Strike",
SPTYP_TRANSLOCATION,
- SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF,
+ SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF | SPFLAG_BATTLE,
3,
100,
LOS_RADIUS, LOS_RADIUS,
@@ -276,7 +276,7 @@
{
SPELL_STRIKING, "Striking",
0,
- SPFLAG_DIR_OR_TARGET,
+ SPFLAG_DIR_OR_TARGET | SPFLAG_BATTLE,
1,
25,
5, 5,
@@ -734,7 +734,7 @@
{
SPELL_ABJURATION_I, "Abjuration",
SPTYP_SUMMONING,
- SPFLAG_AREA | SPFLAG_NEUTRAL,
+ SPFLAG_AREA | SPFLAG_NEUTRAL | SPFLAG_ESCAPE,
3,
200,
-1, -1,
@@ -940,7 +940,7 @@
{
SPELL_PAIN, "Pain",
SPTYP_NECROMANCY,
- SPFLAG_DIR_OR_TARGET,
+ SPFLAG_DIR_OR_TARGET | SPFLAG_BATTLE,
1,
25,
6, 6,
@@ -987,7 +987,7 @@
{
SPELL_VAMPIRIC_DRAINING, "Vampiric Draining",
SPTYP_NECROMANCY,
- SPFLAG_DIR | SPFLAG_NOT_SELF,
+ SPFLAG_DIR | SPFLAG_NOT_SELF | SPFLAG_BATTLE,
3,
200,
1, 1,
@@ -1035,7 +1035,7 @@
{
SPELL_BURN, "Burn", // used by wanderers
SPTYP_FIRE,
- SPFLAG_DIR | SPFLAG_NOT_SELF,
+ SPFLAG_DIR | SPFLAG_NOT_SELF | SPFLAG_BATTLE,
1,
25,
1, 1,
@@ -1047,7 +1047,7 @@
{
SPELL_FREEZE, "Freeze",
SPTYP_ICE,
- SPFLAG_DIR | SPFLAG_NOT_SELF,
+ SPFLAG_DIR | SPFLAG_NOT_SELF | SPFLAG_BATTLE,
1,
25,
1, 1,
@@ -1240,7 +1240,7 @@
{
SPELL_ABJURATION_II, "Abjuration",
SPTYP_HOLY,
- SPFLAG_AREA | SPFLAG_NEUTRAL,
+ SPFLAG_AREA | SPFLAG_NEUTRAL | SPFLAG_ESCAPE,
4,
200,
-1, -1,
@@ -1432,7 +1432,7 @@
{
SPELL_TUKIMAS_VORPAL_BLADE, "Tukima's Vorpal Blade",
SPTYP_ENCHANTMENT,
- SPFLAG_NONE,
+ SPFLAG_HELPFUL | SPFLAG_BATTLE,
2,
200,
-1, -1,
@@ -1444,7 +1444,7 @@
{
SPELL_FIRE_BRAND, "Fire Brand",
SPTYP_ENCHANTMENT | SPTYP_FIRE,
- SPFLAG_NONE,
+ SPFLAG_HELPFUL | SPFLAG_BATTLE,
2,
200,
-1, -1,
@@ -1456,7 +1456,7 @@
{
SPELL_FREEZING_AURA, "Freezing Aura",
SPTYP_ENCHANTMENT | SPTYP_ICE,
- SPFLAG_NONE,
+ SPFLAG_HELPFUL | SPFLAG_BATTLE,
2,
200,
-1, -1,
@@ -1468,7 +1468,7 @@
{
SPELL_LETHAL_INFUSION, "Lethal Infusion",
SPTYP_ENCHANTMENT | SPTYP_NECROMANCY,
- SPFLAG_NONE,
+ SPFLAG_HELPFUL | SPFLAG_BATTLE,
2,
200,
-1, -1,
@@ -1480,7 +1480,7 @@
{
SPELL_CRUSH, "Crush",
SPTYP_EARTH,
- SPFLAG_DIR | SPFLAG_NOT_SELF,
+ SPFLAG_DIR | SPFLAG_NOT_SELF | SPFLAG_DEVEL | SPFLAG_BATTLE,
1,
25,
1, 1,
@@ -1516,7 +1516,7 @@
{
SPELL_TOMB_OF_DOROKLOHE, "Tomb of Doroklohe",
SPTYP_CONJURATION | SPTYP_EARTH, // conj makes more sense than tmig -- bwr
- SPFLAG_NONE,
+ SPFLAG_CARD,
7,
0,
-1, -1,
@@ -1637,7 +1637,7 @@
{
SPELL_POISON_AMMUNITION, "Poison Ammunition",
SPTYP_ENCHANTMENT | SPTYP_POISON,
- SPFLAG_HELPFUL,
+ SPFLAG_HELPFUL | SPFLAG_BATTLE,
4,
0,
-1, -1,
@@ -1649,7 +1649,7 @@
{
SPELL_POISON_WEAPON, "Poison Weapon",
SPTYP_ENCHANTMENT | SPTYP_POISON,
- SPFLAG_HELPFUL,
+ SPFLAG_HELPFUL | SPFLAG_BATTLE,
2,
0,
-1, -1,
@@ -1697,7 +1697,7 @@
{
SPELL_DEBUGGING_RAY, "Debugging Ray",
SPTYP_CONJURATION,
- SPFLAG_DIR_OR_TARGET,
+ SPFLAG_DIR_OR_TARGET | SPFLAG_TESTING,
7,
100,
LOS_RADIUS, LOS_RADIUS,
@@ -1757,7 +1757,7 @@
{
SPELL_DISRUPT, "Disrupt",
SPTYP_TRANSMIGRATION,
- SPFLAG_DIR_OR_TARGET,
+ SPFLAG_DIR_OR_TARGET | SPFLAG_BATTLE | SPFLAG_DEVEL,
1,
25,
7, 7,
@@ -1769,7 +1769,7 @@
{
SPELL_DISINTEGRATE, "Disintegrate",
SPTYP_TRANSMIGRATION,
- SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF,
+ SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF | SPFLAG_CARD,
6,
200,
6, 6,
@@ -1781,7 +1781,7 @@
{
SPELL_BLADE_HANDS, "Blade Hands",
SPTYP_TRANSMIGRATION,
- SPFLAG_HELPFUL,
+ SPFLAG_HELPFUL | SPFLAG_BATTLE,
5, // only removes weapon, so I raised this from 4 -- bwr
200,
-1, -1,
@@ -1913,7 +1913,7 @@
{
SPELL_ARC, "Arc",
SPTYP_AIR,
- SPFLAG_DIR | SPFLAG_NOT_SELF,
+ SPFLAG_DIR | SPFLAG_NOT_SELF | SPFLAG_BATTLE,
1,
25,
1, 1,
@@ -1925,7 +1925,7 @@
{
SPELL_AIRSTRIKE, "Airstrike",
SPTYP_AIR,
- SPFLAG_TARGET | SPFLAG_NOT_SELF,
+ SPFLAG_TARGET | SPFLAG_NOT_SELF | SPFLAG_BATTLE,
4,
200,
LOS_RADIUS, LOS_RADIUS,
@@ -1961,7 +1961,7 @@
{
SPELL_SURE_BLADE, "Sure Blade",
SPTYP_ENCHANTMENT,
- SPFLAG_HELPFUL,
+ SPFLAG_HELPFUL | SPFLAG_BATTLE,
2,
200,
-1, -1,
@@ -1996,7 +1996,7 @@
{
SPELL_IGNITE_POISON, "Ignite Poison",
- SPTYP_FIRE | SPTYP_TRANSMIGRATION,
+ SPTYP_FIRE | SPTYP_TRANSMIGRATION | SPFLAG_BATTLE,
SPFLAG_AREA,
6,
200,
@@ -2081,7 +2081,7 @@
{
SPELL_DETECT_MAGIC, "Detect Magic",
SPTYP_DIVINATION,
- SPFLAG_NONE,
+ SPFLAG_DEVEL,
1,
0,
-1, -1,
@@ -2141,7 +2141,7 @@
{
SPELL_WARP_BRAND, "Warp Weapon",
SPTYP_ENCHANTMENT | SPTYP_TRANSLOCATION,
- SPFLAG_HELPFUL,
+ SPFLAG_HELPFUL | SPFLAG_BATTLE,
7, // this is high for a reason - Warp brands are very powerful.
0,
-1, -1,
@@ -2201,7 +2201,7 @@
{
SPELL_BEND, "Bend",
SPTYP_TRANSLOCATION,
- SPFLAG_DIR,
+ SPFLAG_DIR | SPFLAG_BATTLE,
1,
100,
1, 1,
@@ -2285,7 +2285,7 @@
{
SPELL_SANDBLAST, "Sandblast",
SPTYP_TRANSMIGRATION | SPTYP_EARTH,
- SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF,
+ SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF | SPFLAG_BATTLE,
1,
50,
1, 2,
@@ -2309,7 +2309,7 @@
{
SPELL_MAXWELLS_SILVER_HAMMER, "Maxwell's Silver Hammer",
SPTYP_TRANSMIGRATION | SPTYP_EARTH,
- SPFLAG_HELPFUL,
+ SPFLAG_HELPFUL | SPFLAG_BATTLE,
2,
200,
-1, -1,
@@ -2393,7 +2393,7 @@
{
SPELL_EXCRUCIATING_WOUNDS, "Excruciating Wounds",
SPTYP_ENCHANTMENT | SPTYP_NECROMANCY,
- SPFLAG_HELPFUL,
+ SPFLAG_HELPFUL | SPFLAG_BATTLE,
5, // fairly high level - potentially one of the best brands
200,
-1, -1,
diff --git a/crawl-ref/source/spl-util.cc b/crawl-ref/source/spl-util.cc
index 087a78474f..f31b56a552 100644
--- a/crawl-ref/source/spl-util.cc
+++ b/crawl-ref/source/spl-util.cc
@@ -827,6 +827,33 @@ int spell_type2skill(unsigned int spelltype)
}
} // end spell_type2skill()
+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()
+
/*
**************************************************
* *
diff --git a/crawl-ref/source/spl-util.h b/crawl-ref/source/spl-util.h
index 2b8196c8b4..ec0bbd105d 100644
--- a/crawl-ref/source/spl-util.h
+++ b/crawl-ref/source/spl-util.h
@@ -136,5 +136,6 @@ void apply_area_cloud(cloud_func func, const coord_def& where,
const char *spelltype_name(unsigned int which_spelltype);
int spell_type2skill (unsigned int which_spelltype);
+int spell_skill2type (unsigned int which_skill);
#endif
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index 8cdb33306c..a1004bf4be 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -1082,6 +1082,10 @@ static void tag_construct_you_items(writer &th)
for (j = 0; j < NUM_BOOKS; ++j)
marshallByte(th,you.had_book[j]);
+ marshallShort(th, NUM_SPELLS);
+ for (j = 0; j < NUM_SPELLS; ++j)
+ marshallByte(th,you.seen_spell[j]);
+
// how many unrandarts?
marshallShort(th, NO_UNRANDARTS);
@@ -1522,6 +1526,11 @@ static void tag_read_you_items(reader &th, char minorVersion)
for (j = 0; j < count_c; ++j)
you.had_book[j] = unmarshallByte(th);
+ // how many spells?
+ count_s = unmarshallShort(th);
+ for (j = 0; j < count_s; ++j)
+ you.seen_spell[j] = unmarshallByte(th);
+
// how many unrandarts?
count_s = unmarshallShort(th);
for (j = 0; j < count_s; ++j)
diff --git a/crawl-ref/source/xom.cc b/crawl-ref/source/xom.cc
index 63ecd54eb0..54b797c3d5 100644
--- a/crawl-ref/source/xom.cc
+++ b/crawl-ref/source/xom.cc
@@ -466,7 +466,7 @@ static bool _is_chaos_upgradeable(const item_def &item,
// the other gods so he'll protect his gifts as well.
if (item.orig_monnum < 0)
{
- god_type iorig = static_cast<god_type>(-item.orig_monnum - 2);
+ god_type iorig = static_cast<god_type>(-item.orig_monnum);
if ((iorig > GOD_NO_GOD && iorig < NUM_GODS)
&& (is_good_god(iorig) || iorig == GOD_BEOGH))
{