]> granicus.if.org Git - nethack/commitdiff
forgetting spells due to amnesia (trunk only)
authornethack.rankin <nethack.rankin>
Tue, 27 Jul 2010 03:08:04 +0000 (03:08 +0000)
committernethack.rankin <nethack.rankin>
Tue, 27 Jul 2010 03:08:04 +0000 (03:08 +0000)
     From the newsgroup, losing spells to amnesia always took away the
last 'N' spells after choosing a random N.  That kept casting letters
sane, since letters for lost spells became invalid and those for non-lost
ones stayed the same as they were before amnesia.  But 3.4.x gave the
player the ability to swap pairs of spells, so he could make his favorites
to be the first spells, and only lose them if the random number of spells
being affected was as large as the whole list.  (Also, divine spellbook
gifts give preference to books for unknown spells; in theory, you could
use spell letter manipulation plus deliberate amnesia to make a particular
spell revert to unknown in order to improve the chance of getting a new
spellbook for it.  A bit of cleverness by a determined player but it
makes the game and/or its patron deities seem a bit dumb in the process.)

     I first implemented losing spells throughout the list, with later
spells moved forward to fill any gaps.  But that results in new casting
letters for every spell past the first lost one, potentially wreaking
havoc if a player chooses a casting letter from his own memory of the
pre-amnesia list.  So, instead of losing some spells entirely, either
from the end of the list or spread throughout, I've changed amnesia to
set the retention amount (of N spells from throughout the list) to zero,
the same as happens when it's been 20000 turns since the spell was last
learned.  Letters for all known spells stay unchanged, and forgetting
due to amnesia becomes the same as the other way of forgetting spells.
(So now a different potential clever use of amnesia occurs; a player who's
trying to a make speed ascension could get access to expired spells--to
cast in order to become confused--without waiting for 20000 turns after
reading the first book.)

doc/fixes35.0
src/spell.c

index 5a65e7e62e971c0cfa8fa99bd30817ea50b7d826..4fe7480223795b8ef4e566181a32258a0d42df5b 100644 (file)
@@ -331,6 +331,8 @@ grammar fixes for vault guard messages given after player assigns guard a name
 wearing cloak of displacement auto-discovered it even when hero couldn't see
 wearing elven cloak auto-discovered it even when already stealthy
 putting on ring of stealth never auto-discovered it
+forgetting spells due to amnesia now sets memory retention to zero instead
+       of removing them from hero's list of known spells
 
 
 Platform- and/or Interface-Specific Fixes
index ea324327e2b8250cc6aae98c97b2ec483f71cd2a..d1ae58c8b1d36dde384563165904eae3e6e6f9c0 100644 (file)
@@ -1083,24 +1083,72 @@ throwspell()
        return 1;
 }
 
+/* forget a random selection of known spells due to amnesia;
+   they used to be lost entirely, as if never learned, but now we
+   just set the memory retention to zero so that they can't be cast */
 void
 losespells()
 {
-       boolean confused = (Confusion != 0);
-       int  n, nzap, i;
+    int n, nzap, i;
+
+    /* in case reading has been interrupted earlier, discard context */
+    context.spbook.book = 0;
+    context.spbook.o_id = 0;
+    /* count the number of known spells */
+    for (n = 0; n < MAXSPELL; ++n)
+       if (spellid(n) == NO_SPELL) break;
+
+    /* lose anywhere from zero to all known spells;
+       if confused, use the worse of two die rolls */
+    nzap = rn2(n + 1);
+    if (Confusion) {
+       i = rn2(n + 1);
+       if (i > nzap) nzap = i;
+    }
+    /* good Luck might ameliorate spell loss */
+    if (nzap > 1 && !rnl(7))
+       nzap = rnd(nzap);
 
-       context.spbook.book = 0;
-       context.spbook.o_id = 0;
-       for (n = 0; n < MAXSPELL && spellid(n) != NO_SPELL; n++)
-               continue;
-       if (n) {
-               nzap = rnd(n) + confused ? 1 : 0;
-               if (nzap > n) nzap = n;
-               for (i = n - nzap; i < n; i++) {
-                   spellid(i) = NO_SPELL;
-                   exercise(A_WIS, FALSE);     /* ouch! */
-               }
+    /*
+     * Forget 'nzap' out of 'n' known spells by setting their memory
+     * retention to zero.  Every spell has the same probability to be
+     * forgotten, even if its retention is already zero.
+     *
+     * Perhaps we should forget the corresponding book too?
+     *
+     * (3.4.3 removed spells entirely from the list, but always did
+     * so from its end, so the 'nzap' most recently learned spells
+     * were the ones lost by default.  Player had sort control over
+     * the list, so could move the most useful spells to front and
+     * only lose them if 'nzap' turned out to be a large value.
+     *
+     * Discarding from the end of the list had the virtue of making
+     * casting letters for lost spells become invalid and retaining
+     * the original letter for the ones which weren't lost, so there
+     * was no risk to the player of accidentally casting the wrong
+     * spell when using a letter that was in use prior to amnesia.
+     * That wouldn't be the case if we implemented spell loss spread
+     * throughout the list of known spells; every spell located past
+     * the first lost spell would end up with new letter assigned.)
+     */
+    for (i = 0; nzap > 0; ++i) {
+       /* when nzap is small relative to the number of spells left,
+          the chance to lose spell [i] is small; as the number of
+          remaining candidates shrinks, the chance per candidate
+          gets bigger; overall, exactly nzap entries are affected */
+       if (rn2(n - i) < nzap) {
+           /* lose access to spell [i] */
+           spellknow(i) = 0;
+#if 0
+           /* also forget its book */
+           forget_single_object(spellid(i));
+#endif
+           /* and abuse wisdom */
+           exercise(A_WIS, FALSE);
+           /* there's now one less spell slated to be forgotten */
+           --nzap;
        }
+    }
 }
 
 /*