From 0ee120b9b5a0d3fefa54b55a8ccdcb7758640920 Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Tue, 27 Jul 2010 03:08:04 +0000 Subject: [PATCH] forgetting spells due to amnesia (trunk only) 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 | 2 ++ src/spell.c | 74 ++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 5a65e7e62..4fe748022 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -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 diff --git a/src/spell.c b/src/spell.c index ea324327e..d1ae58c8b 100644 --- a/src/spell.c +++ b/src/spell.c @@ -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; } + } } /* -- 2.40.0