]> granicus.if.org Git - nethack/commitdiff
`spestudied' manipulation for polymorphed spellbooks (trunk only)
authornethack.rankin <nethack.rankin>
Sat, 4 Feb 2006 06:11:44 +0000 (06:11 +0000)
committernethack.rankin <nethack.rankin>
Sat, 4 Feb 2006 06:11:44 +0000 (06:11 +0000)
     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.

doc/fixes35.0
include/hack.h
src/spell.c
src/zap.c

index 1b56640b5b6aac2b1684339e26218a5eed15dd76..319252efd752dcc9076cdbd43c75be7689a11189 100644 (file)
@@ -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
index 8ba14a8b5e76d46b1c1f0be0846315d38b81dd5f..61be33621d9b7c099dd24d68af6ceecf17f436e9 100644 (file)
@@ -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
index a0bb838d94571a5b82416844aa799c8eb6130a4a..b11118ca9d6541ac2dcda519d8ae6b06dcc0814b 100644 (file)
@@ -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);
index f76c606bcf3d4f32229d9f4c6c380d96f7dc9753..e1ad88622d6a1e6dfc491a19fbad7208c9ef3614 100644 (file)
--- 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: