]> granicus.if.org Git - nethack/commitdiff
opening magic vs holding monster
authorPatR <rankin@nethack.org>
Tue, 13 Apr 2021 20:51:57 +0000 (13:51 -0700)
committerPatR <rankin@nethack.org>
Tue, 13 Apr 2021 20:51:57 +0000 (13:51 -0700)
Zapping wand of opening or spell of knock at engulfer while swallowed
would make the engulfer expel the hero; this change makes zapping
other holders release their hold.  Zapping self now achieves the same
effect, as does breaking a non-empty wand of opening.  When poly'd
hero is holding a monster rather than being held, that monster will
be released.

Engulfers can't re-engulf for 1 or 2 turns after releasing the hero
in order to prevent hero from being immediately re-engulfed.  Impose
the same limitation on other holders.

doc/fixes37.0
include/extern.h
src/apply.c
src/mhitu.c
src/mon.c
src/uhitm.c
src/zap.c

index 97365e89136e087aea68c0d997c5a8d31534ebf9..59452ef65098df23cb37b8857e04d3d03aa98631 100644 (file)
@@ -452,6 +452,8 @@ turn off input autocompletion for '#twoweapon' since simple 'X' invokes it;
 if a branch has only one level (Fort Ludios), prevent creation of any level
        teleporters there (level definition doesn't have any but wizard mode
        wishing could attempt to place one)
+opening/unlocking magic zapped at monster holding the hero will release hold
+       (zap at engulfer already expels hero); zapping at self has same effect
 
 
 Fixes to 3.7.0-x Problems that Were Exposed Via git Repository
index 3da9d738ec218e9fa751cafcaaa5dcfba8d79c0b..fc3a7a14e0088ef735fd272cc1127b8e30d8bd65 100644 (file)
@@ -3123,6 +3123,7 @@ extern int dowrite(struct obj *);
 
 extern void learnwand(struct obj *);
 extern int bhitm(struct monst *, struct obj *);
+extern void release_hold(void);
 extern void probe_monster(struct monst *);
 extern boolean get_obj_location(struct obj *, xchar *, xchar *, int);
 extern boolean get_mon_location(struct monst *, xchar *, xchar *, int);
index d6eeb80f512477620e1cbc4727ce2362c0ba841d..7d27cd92102228ae7d428fa45b31a92d0a37143a 100644 (file)
@@ -3480,12 +3480,19 @@ do_break_wand(struct obj *obj)
     affects_objects = FALSE;
 
     switch (obj->otyp) {
+    case WAN_OPENING:
+        if (u.ustuck) {
+            release_hold();
+            if (obj->dknown)
+                makeknown(WAN_OPENING);
+            goto discard_broken_wand;
+        }
+        /*FALLTHRU*/
     case WAN_WISHING:
     case WAN_NOTHING:
     case WAN_LOCKING:
     case WAN_PROBING:
     case WAN_ENLIGHTENMENT:
-    case WAN_OPENING:
     case WAN_SECRET_DOOR_DETECTION:
         pline(nothing_else_happens);
         goto discard_broken_wand;
@@ -3502,7 +3509,7 @@ do_break_wand(struct obj *obj)
         dmg *= 2;
         /*FALLTHRU*/
     case WAN_MAGIC_MISSILE:
   wanexpl:
+ wanexpl:
         explode(u.ux, u.uy, -(obj->otyp), dmg, WAND_CLASS, expltype);
         makeknown(obj->otyp); /* explode describes the effect */
         goto discard_broken_wand;
@@ -3633,7 +3640,7 @@ do_break_wand(struct obj *obj)
     if (obj->otyp == WAN_LIGHT)
         litroom(TRUE, obj); /* only needs to be done once */
 
-discard_broken_wand:
+ discard_broken_wand:
     obj = g.current_wand; /* [see dozap() and destroy_item()] */
     g.current_wand = 0;
     if (obj)
index faf177388dbc865c3f03b5244cab94d0bd4495b6..f548dca0f78720111e9dbb58a3b54b878e1fc0f1 100644 (file)
@@ -298,8 +298,14 @@ getmattk(struct monst *magr, struct monst *mdef,
             /* note: 3d9 is slightly higher than previous 4d6 */
         }
 
-    } else if (attk->aatyp == AT_ENGL && magr->mspec_used) {
-        /* can't re-engulf yet; switch to simpler attack */
+    /* holders/engulfers who release the hero have mspec_used set to rnd(2)
+       and can't re-hold/re-engulf until it has been decremented to zero */
+    } else if (magr->mspec_used && (attk->aatyp == AT_ENGL
+                                    || attk->aatyp == AT_HUGS
+                                    || attk->adtyp == AD_STCK)) {
+        boolean wimpy = (attk->damd == 0); /* lichen, violet fungus */
+
+        /* can't re-engulf or re-grab yet; switch to simpler attack */
         *alt_attk_buf = *attk;
         attk = alt_attk_buf;
         if (attk->adtyp == AD_ACID || attk->adtyp == AD_ELEC
@@ -311,6 +317,10 @@ getmattk(struct monst *magr, struct monst *mdef,
         }
         attk->damn = 1; /* relatively weak: 1d6 */
         attk->damd = 6;
+        if (wimpy && attk->aatyp == AT_CLAW) {
+            attk->aatyp = AT_TUCH;
+            attk->damn = attk->damd = 0;
+        }
 
     /* barrow wight, Nazgul, erinys have weapon attack for non-physical
        damage; force physical damage if attacker has been cancelled or
index 7e740e696d4cc18b8becf114b8291d4ce53dcb82..0aef9dda5a1d59297c2501307302e5ff1b839124 100644 (file)
--- a/src/mon.c
+++ b/src/mon.c
@@ -2725,6 +2725,8 @@ void
 unstuck(struct monst* mtmp)
 {
     if (u.ustuck == mtmp) {
+        struct permonst *ptr = mtmp->data;
+
         /* do this first so that docrt()'s botl update is accurate;
            safe to do as long as u.uswallow is also cleared before docrt() */
         set_ustuck((struct monst *) 0);
@@ -2738,11 +2740,16 @@ unstuck(struct monst* mtmp)
                 placebc();
             g.vision_full_recalc = 1;
             docrt();
-            /* prevent swallower (mtmp might have just poly'd into something
-               without an engulf attack) from immediately re-engulfing */
-            if (attacktype(mtmp->data, AT_ENGL) && !mtmp->mspec_used)
-                mtmp->mspec_used = rnd(2);
         }
+
+        /* prevent holder/engulfer from immediately re-holding/re-engulfing
+           [note: this call to unstuck() might be because u.ustuck has just
+           changed shape and doesn't have a holding attack any more, hence
+           don't set mspec_used uncondtionally] */
+        if (!mtmp->mspec_used && (dmgtype(ptr, AD_STCK)
+                                  || attacktype(ptr, AT_ENGL)
+                                  || attacktype(ptr, AT_HUGS)))
+            mtmp->mspec_used = rnd(2);
     }
 }
 
index ee5d3dfa0c36f26631e4204868db77474aa75f9b..45ddb0450d62a74ddae5edf64c6dc6e5c95c69c0 100644 (file)
@@ -2689,7 +2689,7 @@ mhitm_ad_stck(struct monst *magr, struct attack *mattk, struct monst *mdef,
         boolean negated = !(rn2(10) >= 3 * armpro);
 
         if (!negated && !sticks(pd) && distu(mdef->mx, mdef->my) <= 2)
-            u.ustuck = mdef; /* it's now stuck to you */
+            set_ustuck(mdef); /* it's now stuck to you */
     } else if (mdef == &g.youmonst) {
         /* mhitu */
         int armpro = magic_negation(mdef);
index ea78ea23dbe3c0802cea39d53bc2dc81f4ed074c..a3fb0884a6fb8687e1b3bf85410589d33d83b181 100644 (file)
--- a/src/zap.c
+++ b/src/zap.c
@@ -318,17 +318,15 @@ bhitm(struct monst *mtmp, struct obj *otmp)
     case WAN_OPENING:
     case SPE_KNOCK:
         wake = FALSE; /* don't want immediate counterattack */
-        if (u.uswallow && mtmp == u.ustuck) {
-            if (is_animal(mtmp->data)) {
-                if (Blind)
-                    You_feel("a sudden rush of air!");
-                else
-                    pline("%s opens its mouth!", Monnam(mtmp));
-            }
-            expels(mtmp, mtmp->data, TRUE);
-            /* zap which hits steed will only release saddle if it
-               doesn't hit a holding or falling trap; playability
-               here overrides the more logical target ordering */
+        if (mtmp == u.ustuck) {
+            /* zapping either holder/holdee or self [zapyourself()] will
+               release hero from holder's grasp or holdee from hero's grasp */
+            release_hold();
+            learn_it = TRUE;
+
+        /* zap which hits steed will only release saddle if it
+           doesn't hit a holding or falling trap; playability
+           here overrides the more logical target ordering */
         } else if (openholdingtrap(mtmp, &learn_it)) {
             break;
         } else if (openfallingtrap(mtmp, TRUE, &learn_it)) {
@@ -471,6 +469,42 @@ bhitm(struct monst *mtmp, struct obj *otmp)
     return 0;
 }
 
+/* hero is held by a monster or engulfed or holding a monster and has zapped
+   opening/unlocking magic at holder/engulfer/holdee or at self */
+void
+release_hold()
+{
+    struct monst *mtmp = u.ustuck;
+
+    if (!mtmp) {
+        impossible("release_hold when not held?");
+    } else if (sticks(g.youmonst.data)) {
+        /* order matters if 'holding' status condition is enabled;
+           set_ustuck() will set flag for botl update, You() pline will
+           trigger a status update with "UHold" removed */
+        set_ustuck((struct monst *) 0);
+        You("release %s.", mon_nam(mtmp));
+    } else if (u.uswallow) {
+        if (is_animal(mtmp->data)) {
+            if (!Blind)
+                pline("%s opens its mouth!", Monnam(mtmp));
+            else
+                You_feel("a sudden rush of air!");
+        }
+        /* gives "you get regurgitated" or "you get expelled from <mon>" */
+        expels(mtmp, mtmp->data, TRUE);
+    } else { /* held but not swallowed */
+        char relbuf[BUFSZ];
+
+        unstuck(u.ustuck);
+        if (!nohands(mtmp->data))
+            Sprintf(relbuf, "from %s grasp", s_suffix(mon_nam(mtmp)));
+        else
+            Sprintf(relbuf, "by %s", mon_nam(mtmp));
+        You("are released %s.", relbuf);
+    }
+}
+
 void
 probe_monster(struct monst *mtmp)
 {
@@ -2577,6 +2611,12 @@ zapyourself(struct obj *obj, boolean ordinary)
         break;
     case WAN_OPENING:
     case SPE_KNOCK:
+        if (u.ustuck) {
+            /* zapping either self or holder/holdee [bhitm()] will release
+               holder's grasp from the hero or hero's grasp from holdee */
+            release_hold();
+            learn_it = TRUE;
+        }
         if (Punished) {
             learn_it = TRUE;
             unpunish();