]> granicus.if.org Git - nethack/commitdiff
spellcasting bug fix: confusion duration
authorPatR <rankin@nethack.org>
Wed, 4 Nov 2015 10:27:59 +0000 (02:27 -0800)
committerPatR <rankin@nethack.org>
Wed, 4 Nov 2015 10:27:59 +0000 (02:27 -0800)
Fix the reported bug that attempting to cast an expired spell, which
causes confusion and/or stun, was replacing the duration of any existing
confusion or stun with the new amount rather than increasing it by that
amount.

Attempting to cast any spell while stunned will now fail immediately,
and casting an expired spell while confused will increase confusion
duration (and/or set stun duration) rather than override it.

doc/fixes36.0
src/spell.c

index 81ac18b62af23399f848d9e2c2749605df04764c..07d92f96a179f2a9cd08526376c84507c8250fe7 100644 (file)
@@ -932,6 +932,9 @@ remaining monsters continued to move after hero conceptually left the level
 #turn for non-priest/non-knight attempts to cast "turn undead" spell, but
        was forcing the spell to target self rather than choose a direction
 potions of gain energy are more useful for recovering hero's spell energy
+spellcasting attempt of any spell while stunned now always fails
+spellcasting attempt of expired spell while confused will increase confusion
+       duration rather than replace it
 
 
 Platform- and/or Interface-Specific Fixes
index 83054c7bf178abd2bd52b7c2238dbfa8f858b2e3..cbe06065d082e24144014a3c85a84e5363e1af62 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 spell.c $NHDT-Date: 1446191879 2015/10/30 07:57:59 $  $NHDT-Branch: master $:$NHDT-Revision: 1.67 $ */
+/* NetHack 3.6 spell.c $NHDT-Date: 1446632870 2015/11/04 10:27:50 $  $NHDT-Branch: master $:$NHDT-Revision: 1.68 $ */
 /*      Copyright (c) M. Stephenson 1988                          */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -30,9 +30,10 @@ STATIC_DCL boolean FDECL(cursed_book, (struct obj * bp));
 STATIC_DCL boolean FDECL(confused_book, (struct obj *));
 STATIC_DCL void FDECL(deadbook, (struct obj *));
 STATIC_PTR int NDECL(learn);
+STATIC_DCL boolean NDECL(rejectcasting);
 STATIC_DCL boolean FDECL(getspell, (int *));
-STATIC_PTR int FDECL(CFDECLSPEC spell_cmp,
-                     (const genericptr, const genericptr));
+STATIC_PTR int FDECL(CFDECLSPEC spell_cmp, (const genericptr,
+                                            const genericptr));
 STATIC_DCL void NDECL(sortspells);
 STATIC_DCL boolean NDECL(spellsortmenu);
 STATIC_DCL boolean FDECL(dospellmenu, (const char *, int, int *));
@@ -617,6 +618,29 @@ age_spells()
     return;
 }
 
+/* return True if spellcasting is inhibited;
+   only covers a small subset of reasons why casting won't work */
+STATIC_OVL boolean
+rejectcasting()
+{
+    /* rejections which take place before selecting a particular spell */
+    if (Stunned) {
+        You("are too impaired to cast a spell.");
+        return TRUE;
+    } else if (!freehand()) {
+        /* Note: !freehand() occurs when weapon and shield (or two-handed
+         * weapon) are welded to hands, so "arms" probably doesn't need
+         * to be makeplural(bodypart(ARM)).
+         *
+         * But why isn't lack of free arms (for gesturing) an issue when
+         * poly'd hero has no limbs?
+         */
+        Your("arms are not free to cast!");
+        return TRUE;
+    }
+    return FALSE;
+}
+
 /*
  * Return TRUE if a spell was picked, with the spell index in the return
  * parameter.  Otherwise return FALSE.
@@ -632,6 +656,9 @@ int *spell_no;
         You("don't know any spells right now.");
         return FALSE;
     }
+    if (rejectcasting())
+        return FALSE; /* no spell chosen */
+
     if (flags.menu_style == MENU_TRADITIONAL) {
         /* we know there is at least 1 known spell */
         for (nspells = 1; nspells < MAXSPELL && spellid(nspells) != NO_SPELL;
@@ -796,29 +823,37 @@ STATIC_OVL void
 spell_backfire(spell)
 int spell;
 {
-    long duration = (long) ((spellev(spell) + 1) * 3); /* 6..24 */
+    long duration = (long) ((spellev(spell) + 1) * 3), /* 6..24 */
+         old_stun = (HStun & TIMEOUT), old_conf = (HConfusion & TIMEOUT);
 
-    /* prior to 3.4.1, the only effect was confusion; it still predominates */
+    /* Prior to 3.4.1, only effect was confusion; it still predominates.
+     *
+     * 3.6.0: this used to override pre-existing confusion duration
+     * (cases 0..8) and pre-existing stun duration (cases 4..9);
+     * increase them instead.   (Hero can no longer cast spells while
+     * Stunned, so the potential increment to stun duration here is
+     * just hypothetical.)
+     */
     switch (rn2(10)) {
     case 0:
     case 1:
     case 2:
     case 3:
-        make_confused(duration, FALSE); /* 40% */
+        make_confused(old_conf + duration, FALSE); /* 40% */
         break;
     case 4:
     case 5:
     case 6:
-        make_confused(2L * duration / 3L, FALSE); /* 30% */
-        make_stunned(duration / 3L, FALSE);
+        make_confused(old_conf + 2L * duration / 3L, FALSE); /* 30% */
+        make_stunned(old_stun + duration / 3L, FALSE);
         break;
     case 7:
     case 8:
-        make_stunned(2L * duration / 3L, FALSE); /* 20% */
-        make_confused(duration / 3L, FALSE);
+        make_stunned(old_conf + 2L * duration / 3L, FALSE); /* 20% */
+        make_confused(old_stun + duration / 3L, FALSE);
         break;
     case 9:
-        make_stunned(duration, FALSE); /* 10% */
+        make_stunned(old_stun + duration, FALSE); /* 10% */
         break;
     }
     return;
@@ -836,6 +871,19 @@ boolean atme;
     struct obj *pseudo;
     coord cc;
 
+    /*
+     * Reject attempting to cast while stunned or with no free hands.
+     * Already done in getspell() to stop casting before choosing
+     * which spell, but duplicated here for cases where spelleffects()
+     * gets called directly for ^T without intrinsic teleport capability
+     * or #turn for non-priest/non-knight.
+     * (There's no duplication of messages; when the rejection takes
+     * place in getspell(), we don't get called.)
+     */
+    if (rejectcasting()) {
+        return 0; /* no time elapses */
+    }
+
     /*
      * Spell casting no longer affects knowledge of the spell. A
      * decrement of spell knowledge is done every turn.
@@ -844,7 +892,7 @@ boolean atme;
         Your("knowledge of this spell is twisted.");
         pline("It invokes nightmarish images in your mind...");
         spell_backfire(spell);
-        return 0;
+        return 1;
     } else if (spellknow(spell) <= KEEN / 200) { /* 100 turns left */
         You("strain to recall the spell.");
     } else if (spellknow(spell) <= KEEN / 40) { /* 500 turns left */
@@ -862,12 +910,9 @@ boolean atme;
     } else if (ACURR(A_STR) < 4 && spellid(spell) != SPE_RESTORE_ABILITY) {
         You("lack the strength to cast spells.");
         return 0;
-    } else if (check_capacity("Your concentration falters while carrying so "
-                              "much stuff.")) {
+    } else if (check_capacity(
+                "Your concentration falters while carrying so much stuff.")) {
         return 1;
-    } else if (!freehand()) {
-        Your("arms are not free to cast!");
-        return 0;
     }
 
     if (u.uhave.amulet) {