diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 1b56640b5..319252efd 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -115,6 +115,7 @@ zapping an unID'd wand of teleportation at self will discover it (usually) zapping unlocking magic at self while punished will remove attached chain don't see objects or read engraving when hero changes location (random teleport) or position (levitation timeout) while asleep or fainted +polymorphed spellbooks may turn blank or be too faint to read Platform- and/or Interface-Specific Fixes diff --git a/include/hack.h b/include/hack.h index 8ba14a8b5..61be33621 100644 --- a/include/hack.h +++ b/include/hack.h @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)hack.h 3.5 2005/12/10 */ +/* SCCS Id: @(#)hack.h 3.5 2006/02/03 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -85,6 +85,9 @@ #define CXN_ARTICLE 8 /* include a/an/the prefix */ #define CXN_NOCORPSE 16 /* suppress " corpse" suffix */ +/* spellbook re-use control; used when reading and when polymorphing */ +#define MAX_SPELL_STUDY 3 + /* * This is the way the game ends. If these are rearranged, the arrays * in end.c and topten.c will need to be changed. Some parts of the diff --git a/src/spell.c b/src/spell.c index a0bb838d9..b11118ca9 100644 --- a/src/spell.c +++ b/src/spell.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)spell.c 3.5 2004/06/12 */ +/* SCCS Id: @(#)spell.c 3.5 2006/02/03 */ /* Copyright (c) M. Stephenson 1988 */ /* NetHack may be freely redistributed. See license for details. */ @@ -9,7 +9,6 @@ #define SPELLMENU_VIEW (-1) #define KEEN 20000 -#define MAX_SPELL_STUDY 3 #define incrnknow(spell) spl_book[spell].sp_know = KEEN #define spellev(spell) spl_book[spell].sp_lev @@ -319,11 +318,13 @@ learn() short booktype; char splname[BUFSZ]; boolean costly = TRUE; + struct obj *book = context.spbook.book; /* JDS: lenses give 50% faster reading; 33% smaller read time */ - if (context.spbook.delay && ublindf && ublindf->otyp == LENSES && rn2(2)) context.spbook.delay++; + if (context.spbook.delay && ublindf && ublindf->otyp == LENSES && rn2(2)) + context.spbook.delay++; if (Confusion) { /* became confused while learning */ - (void) confused_book(context.spbook.book); + (void) confused_book(book); context.spbook.book = 0; /* no longer studying */ context.spbook.o_id = 0; nomul(context.spbook.delay); /* remaining delay is uninterrupted */ @@ -336,55 +337,65 @@ learn() return(1); /* still busy */ } exercise(A_WIS, TRUE); /* you're studying. */ - booktype = context.spbook.book->otyp; + booktype = book->otyp; if(booktype == SPE_BOOK_OF_THE_DEAD) { - deadbook(context.spbook.book); + deadbook(book); return(0); } Sprintf(splname, objects[booktype].oc_name_known ? "\"%s\"" : "the \"%s\" spell", OBJ_NAME(objects[booktype])); - for (i = 0; i < MAXSPELL; i++) { - if (spellid(i) == booktype) { - if (context.spbook.book->spestudied > MAX_SPELL_STUDY) { - pline("This spellbook is too faint to be read any more."); - context.spbook.book->otyp = booktype = SPE_BLANK_PAPER; - } else if (spellknow(i) <= 1000) { - Your("knowledge of %s is keener.", splname); - incrnknow(i); - context.spbook.book->spestudied++; - exercise(A_WIS,TRUE); /* extra study */ - } else { /* 1000 < spellknow(i) <= MAX_SPELL_STUDY */ - You("know %s quite well already.", splname); - costly = FALSE; - } - /* make book become known even when spell is already - known, in case amnesia made you forget the book */ - makeknown((int)booktype); - break; - } else if (spellid(i) == NO_SPELL) { - spl_book[i].sp_id = booktype; - spl_book[i].sp_lev = objects[booktype].oc_level; - incrnknow(i); - context.spbook.book->spestudied++; - You(i > 0 ? "add %s to your repertoire." : "learn %s.", - splname); - makeknown((int)booktype); - break; - } - } - if (i == MAXSPELL) impossible("Too many spells memorized!"); + for (i = 0; i < MAXSPELL; i++) + if (spellid(i) == booktype || spellid(i) == NO_SPELL) break; - if (context.spbook.book->cursed) { /* maybe a demon cursed it */ - if (cursed_book(context.spbook.book)) { - useup(context.spbook.book); + if (i == MAXSPELL) { + impossible("Too many spells memorized!"); + } else if (spellid(i) == booktype) { + /* normal book can be read and re-read a total of 4 times */ + if (book->spestudied > MAX_SPELL_STUDY) { + pline("This spellbook is too faint to be read any more."); + book->otyp = booktype = SPE_BLANK_PAPER; + } else if (spellknow(i) <= 1000) { + Your("knowledge of %s is keener.", splname); + incrnknow(i); + book->spestudied++; + exercise(A_WIS,TRUE); /* extra study */ + } else { /* 1000 < spellknow(i) <= KEEN */ + You("know %s quite well already.", splname); + costly = FALSE; + } + /* make book become known even when spell is already + known, in case amnesia made you forget the book */ + makeknown((int)booktype); + } else { /* (spellid(i) == NO_SPELL) */ + /* for a normal book, spestudied will be zero, but for + a polymorphed one, spestudied will be non-zero and + one less reading is available than when re-learning */ + if (book->spestudied >= MAX_SPELL_STUDY) { + /* pre-used due to being the product of polymorph */ + pline("This spellbook is too faint to read even once."); + book->otyp = booktype = SPE_BLANK_PAPER; + } else { + spl_book[i].sp_id = booktype; + spl_book[i].sp_lev = objects[booktype].oc_level; + incrnknow(i); + book->spestudied++; + You(i > 0 ? "add %s to your repertoire." : "learn %s.", + splname); + } + makeknown((int)booktype); + } + + if (book->cursed) { /* maybe a demon cursed it */ + if (cursed_book(book)) { + useup(book); context.spbook.book = 0; context.spbook.o_id = 0; return 0; } } - if (costly) check_unpaid(context.spbook.book); + if (costly) check_unpaid(book); context.spbook.book = 0; context.spbook.o_id = 0; return(0); diff --git a/src/zap.c b/src/zap.c index f76c606bc..e1ad88622 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1396,8 +1396,17 @@ poly_obj(obj, id) case SPBOOK_CLASS: while (otmp->otyp == SPE_POLYMORPH) otmp->otyp = rnd_class(SPE_DIG, SPE_BLANK_PAPER); - /* reduce spellbook abuse */ - otmp->spestudied = obj->spestudied + 1; + /* reduce spellbook abuse; non-blank books degrade */ + if (otmp->otyp != SPE_BLANK_PAPER) { + otmp->spestudied = obj->spestudied + 1; + if (otmp->spestudied > MAX_SPELL_STUDY) { + otmp->otyp = SPE_BLANK_PAPER; + /* writing a new book over it will yield an unstudied + one; re-polymorphing this one as-is may or may not + get something non-blank */ + otmp->spestudied = rn2(otmp->spestudied); + } + } break; case GEM_CLASS: