From: nethack.rankin Date: Sat, 4 Feb 2006 06:11:44 +0000 (+0000) Subject: `spestudied' manipulation for polymorphed spellbooks (trunk only) X-Git-Tag: MOVE2GIT~1137 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=98685ea23479afe732a9047fe5e55b059adc0795;p=nethack `spestudied' manipulation for polymorphed spellbooks (trunk only) From a bug report... some special case handling for polymorph of spellbooks never worked as intended. It's possible to polymorph a spellbook, use it to learn a new spell, and then repeat as many times as you like unless/until you run out of polymorph magic or the small chance of "object shuddering" causes it to be destroyed. Polymorph was incrementing the book's ``number of times read'' field with the intent that it would fade to blank after being read 3 times (which turns out to the 4 times since the check is actually for re-reading 3 times after the first). That didn't work because the spestudied field was ignored when learning a new spell, only checked when relearning a known spell. Now it will be checked when learning a new spell, and also the book tweaking during polymorph is slightly more elaborate. If you happen to get a blank book during the item selection, it will have a read counter of 0 and can be re-polymorphed into something readable. But if you get some other book, its read counter will be set to one greater than than the original book's (same as before). And then the counter will be checked to see if it has gone over the limit, in which case the book will be made blank and its counter will be reset to a random value. Re-polymorphing that blank book again has 1/4 chance apiece among the following cases book gets blanked again; goto step 1... book is non-blank but too faint to read; reading attempt will fail book can be read normally and then re-read once book can be read normally and then re-read twice which is more inline with the intent of the original special case code. It's actually slightly nastier since you'll occasionally get a book for a spell you don't know yet but then not be able to learn it from that book. --- 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; - } + for (i = 0; i < MAXSPELL; i++) + if (spellid(i) == booktype || spellid(i) == NO_SPELL) break; + + 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 (i == MAXSPELL) impossible("Too many spells memorized!"); - if (context.spbook.book->cursed) { /* maybe a demon cursed it */ - if (cursed_book(context.spbook.book)) { - useup(context.spbook.book); + 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: