]> granicus.if.org Git - nethack/commitdiff
fix bz16 - book becoming cursed while being read
authorPatR <rankin@nethack.org>
Mon, 1 Feb 2016 02:22:31 +0000 (18:22 -0800)
committerPatR <rankin@nethack.org>
Mon, 1 Feb 2016 02:22:31 +0000 (18:22 -0800)
Attempting to read a cursed spellbook fails with a nasty effect.  But
a non-cursed book can become cursed while being read (malignant aura
after Wizard has been killed).  Assuming no interruption for other
reasons, the read would finish, the spell be learned, and then the
nasty effect would be given.  This changes things so that if the book
being read becomes cursed and the hero notices (book's bknown flag is
set), the read-in-progress will be interrupted.  Resuming will take
the attempting-to-read-a-cursed-book path.  Unfortunately, if the
hero doesn't notice, the old behavior still applies.  Maybe the new
behavior should happen even if bknown isn't set (but then player
won't be told why the interruption occurred).

doc/fixes36.1
include/extern.h
src/mkobj.c
src/spell.c

index bf9cc0be983bd06da26d0db7e68dd731f6845a15..051820f47b822c25d4f4bbae12e1b828cb4886dd 100644 (file)
@@ -139,6 +139,11 @@ monsters fleeing up the upstairs on level 1 were supposed to escape the
 monster hitting fire-dealing monster with weapon triggered passive damage to
        weapon every time, when hero doing so only had 1/6 chance per hit
 hitting steam vortex with flammable weapon would damage the weapon with fire
+if a non-cursed spellbook being read becomes cursed and hero recognizes that
+       (bknown is set), interrupt reading
+if a non-cursed spellbook being read becomes cursed and hero doesn't notice,
+       don't leave it flagged as in-use (hence to be deleted during the
+       next save/restore cycle) if contact-poison cursed book effect occurs
 
 
 Platform- and/or Interface-Specific Fixes
index 3c0abfaab3c6e540f1bcf16fbc3778b92a3fcf08..7b6fe3d0ca782eec19de0165e5396863bbae3f3f 100644 (file)
@@ -2197,6 +2197,7 @@ E boolean FDECL(load_special, (const char *));
 
 /* ### spell.c ### */
 
+E void FDECL(book_cursed, (struct obj *));
 #ifdef USE_TRAMPOLI
 E int NDECL(learn);
 #endif
index 277fe8b4622da1e330d715812fdb8ee453c5ae50..ef0af3eec851aa780d64525c0c36465ace1e1252 100644 (file)
@@ -1247,12 +1247,14 @@ void
 curse(otmp)
 register struct obj *otmp;
 {
+    unsigned already_cursed;
     int old_light = 0;
 
     if (otmp->oclass == COIN_CLASS)
         return;
     if (otmp->lamplit)
         old_light = arti_light_radius(otmp);
+    already_cursed = otmp->cursed;
     otmp->blessed = 0;
     otmp->cursed = 1;
     /* welded two-handed weapon interferes with some armor removal */
@@ -1263,14 +1265,18 @@ register struct obj *otmp;
     if (otmp == uswapwep && u.twoweap)
         drop_uswapwep();
     /* some cursed items need immediate updating */
-    if (carried(otmp) && confers_luck(otmp))
+    if (carried(otmp) && confers_luck(otmp)) {
         set_moreluck();
-    else if (otmp->otyp == BAG_OF_HOLDING)
+    } else if (otmp->otyp == BAG_OF_HOLDING) {
         otmp->owt = weight(otmp);
-    else if (otmp->otyp == FIGURINE) {
+    else if (otmp->otyp == FIGURINE) {
         if (otmp->corpsenm != NON_PM && !dead_species(otmp->corpsenm, TRUE)
             && (carried(otmp) || mcarried(otmp)))
             attach_fig_transform_timeout(otmp);
+    } else if (otmp->oclass == SPBOOK_CLASS) {
+        /* if book hero is reading becomes cursed, interrupt */
+        if (!already_cursed)
+            book_cursed(otmp);
     }
     if (otmp->lamplit)
         maybe_adjust_light(otmp, old_light);
index 4369192766fb2785bfb981c2a28e9f69c6299d6e..6110a8472e850b7a5d95d9f4b72134c8e216dc55 100644 (file)
@@ -120,6 +120,7 @@ STATIC_OVL boolean
 cursed_book(bp)
 struct obj *bp;
 {
+    boolean was_in_use;
     int lev = objects[bp->otyp].oc_level;
     int dmg = 0;
 
@@ -149,11 +150,12 @@ struct obj *bp;
             break;
         }
         /* temp disable in_use; death should not destroy the book */
+        was_in_use = bp->in_use;
         bp->in_use = FALSE;
         losestr(Poison_resistance ? rn1(2, 1) : rn1(4, 3));
         losehp(rnd(Poison_resistance ? 6 : 10), "contact-poisoned spellbook",
                KILLED_BY_AN);
-        bp->in_use = TRUE;
+        bp->in_use = was_in_use;
         break;
     case 6:
         if (Antimagic) {
@@ -322,6 +324,17 @@ struct obj *book2;
     return;
 }
 
+/* 'book' has just become cursed; if we're reading it and realize it is
+   now cursed, interrupt */
+void
+book_cursed(book)
+struct obj *book;
+{
+    if (occupation == learn && context.spbook.book == book
+        && book->cursed && book->bknown && multi >= 0)
+        stop_occupation();
+}
+
 STATIC_PTR int
 learn(VOID_ARGS)
 {
@@ -344,9 +357,8 @@ learn(VOID_ARGS)
         context.spbook.delay = 0;
         return 0;
     }
-    if (context
-            .spbook.delay) { /* not if (context.spbook.delay++), so at end
-                                delay == 0 */
+    if (context.spbook.delay) {
+        /* not if (context.spbook.delay++), so at end delay == 0 */
         context.spbook.delay++;
         return 1; /* still busy */
     }
@@ -516,15 +528,16 @@ register struct obj *spellbook;
                 too_hard = TRUE;
             } else {
                 /* uncursed - chance to fail */
-                int read_ability =
-                    ACURR(A_INT) + 4 + u.ulevel / 2
-                    - 2 * objects[booktype].oc_level
-                    + ((ublindf && ublindf->otyp == LENSES) ? 2 : 0);
+                int read_ability = ACURR(A_INT) + 4 + u.ulevel / 2
+                                   - 2 * objects[booktype].oc_level
+                             + ((ublindf && ublindf->otyp == LENSES) ? 2 : 0);
+
                 /* only wizards know if a spell is too difficult */
                 if (Role_if(PM_WIZARD) && read_ability < 20 && !confused) {
                     char qbuf[QBUFSZ];
+
                     Sprintf(qbuf,
-                     "This spellbook is %sdifficult to comprehend. Continue?",
+                    "This spellbook is %sdifficult to comprehend.  Continue?",
                             (read_ability < 12 ? "very " : ""));
                     if (yn(qbuf) != 'y') {
                         spellbook->in_use = FALSE;