]> granicus.if.org Git - nethack/commitdiff
fix #H1816 - polearm/grapnel/whip fixes (trunk only)
authornethack.rankin <nethack.rankin>
Mon, 23 Feb 2009 01:20:32 +0000 (01:20 +0000)
committernethack.rankin <nethack.rankin>
Mon, 23 Feb 2009 01:20:32 +0000 (01:20 +0000)
     From a bug report, applying a polearm to make a
short-range ranged attack didn't scuff any engraving you were standing on,
unlike ordinary melee and throwing/shooting attacks.  Grappling hooks had
the same omission.  Fixing it led to several other minor bugs.  Attempting
to target an unseen monster's spot with polearm or grapnel would yield some
permutation of "wait, there's something there" but draw the 'I' glyph at
the wrong spot.  It used <u.ux+u.dx,u.uy+u.dy> instead of the actual target,
so put the 'I' one step in front of your most recent move (or throw or zap
or whatever last set u.dx and u.dy).  Giving ESC when prompted for target
spot failed to use up a turn even when the polearm or grappling hook had
just been auto-wielded for use.  Neither use_pole() nor use_grapple() set
`notonhead' for hmon() (called via thitmonst() in their cases; this was
academic since plain physical damage attacks don't actually care about it).
[The bad 'I' placement was a post-3.4.3 bug.]

     Applying a bullwhip to attack an adjacent monster didn't have any of
those issues but did have the possibility of targetting off the edge of
the map when standing at that edge while confused or stunned.

     Applying a polearm to target an 'I' would yield "nothing happens" if
the unseen monster wasn't there anymore, and it didn't bother to remove
that 'I' from the map.  After changing it to do so, the phrasing no longer
made any sense.  This led to a slightly bigger change than I intended:
since statues are now shown as gray monsters (does that work for tiles?)
instead of as chunks of stone, they are likely to be intentional targets
sometimes, so polearm attacks now handle them differently from other
non-monster locations.  [I hope that other attack forms don't need
similar handling.  Melee certainly doesn't, since walking onto the spot
is enough to distinguish statues from monsters.  Having the missile pass
right through a statue's location probably suffices for ranged attacks.]

doc/fixes35.0
src/apply.c
src/uhitm.c

index 4021ae6beeaf1ece84d04ade3744717121df3867..d6e80d968249c08eb3c747217a175706d86a6243 100644 (file)
@@ -310,6 +310,10 @@ poly'd or mimicking hero who was hidden from monsters would still be treated
        as a normal target for their ranged attacks
 hero would remain stuck to an adjacent monster after rehumanizing if he had
        been attacked while hiding via #monster when poly'd into a small mimic
+attacking via applied polearm never scuffed engraving underneath hero
+auto-wielding a polearm took no time if ESC was used to cancel target choice
+applying a bullwhip while at very edge of map could target beyond edge when
+       hero was stunned or confused, potentially leading to a panic or crash
 
 
 Platform- and/or Interface-Specific Fixes
index 20f7350940a1b52dbc5b0f1b8fdc83ac78d97a5c..0f874899e8a72591a0375687ed6f8df9e74a2d7f 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)apply.c    3.5     2008/10/14      */
+/*     SCCS Id: @(#)apply.c    3.5     2009/02/21      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -2328,10 +2328,20 @@ struct obj *obj;
     }
     if (!getdir((char *)0)) return res;
 
-    if (Stunned || (Confusion && !rn2(5))) confdir();
-    rx = u.ux + u.dx;
-    ry = u.uy + u.dy;
-    mtmp = m_at(rx, ry);
+    if (u.uswallow) {
+       mtmp = u.ustuck;
+       rx = mtmp->mx;
+       ry = mtmp->my;
+    } else {
+       if (Stunned || (Confusion && !rn2(5))) confdir();
+       rx = u.ux + u.dx;
+       ry = u.uy + u.dy;
+       if (!isok(rx, ry)) {
+           You("miss.");
+           return res;
+       }
+       mtmp = m_at(rx, ry);
+    }
 
     /* fake some proficiency checks */
     proficient = 0;
@@ -2571,11 +2581,10 @@ STATIC_OVL int
 use_pole(obj)
        struct obj *obj;
 {
-       int res = 0, typ, max_range = 4, min_range = 4;
+       int res = 0, typ, max_range, min_range, glyph;
        coord cc;
        struct monst *mtmp;
 
-
        /* Are you allowed to use the pole? */
        if (u.uswallow) {
            pline(not_enough_room);
@@ -2592,13 +2601,29 @@ use_pole(obj)
        cc.x = u.ux;
        cc.y = u.uy;
        if (getpos(&cc, TRUE, "the spot to hit") < 0)
-           return 0;   /* user pressed ESC */
+           return res; /* ESC; uses turn iff polearm became wielded */
 
-       /* Calculate range */
+       glyph = glyph_at(cc.x, cc.y);
+       /*
+        * Calculate allowable range (pole's reach is always 2 steps):
+        *      unskilled and basic: orthogonal direction, 4..4;
+        *      skilled: as basic, plus knight's jump position, 4..5;
+        *      expert: as skilled, plus diagonal, 4..8.
+        *              ...9...
+        *              .85458.
+        *              .52125.
+        *              9410149
+        *              .52125.
+        *              .85458.
+        *              ...9...
+        *      (Note: no roles in nethack can become expert or better
+        *      for polearm skill; Yeoman in slash'em can become expert.)
+        */
+       min_range = 4;
        typ = uwep_skill_type();
        if (typ == P_NONE || P_SKILL(typ) <= P_BASIC) max_range = 4;
        else if (P_SKILL(typ) == P_SKILLED) max_range = 5;
-       else max_range = 8;
+       else max_range = 8;     /* (P_SKILL(typ) >= P_EXPERT) */
        if (distu(cc.x, cc.y) > max_range) {
            pline("Too far!");
            return (res);
@@ -2606,8 +2631,9 @@ use_pole(obj)
            pline("Too close!");
            return (res);
        } else if (!cansee(cc.x, cc.y) &&
-                  ((mtmp = m_at(cc.x, cc.y)) == (struct monst *)0 ||
-                   !canseemon(mtmp))) {
+                  !glyph_is_monster(glyph) &&
+                  !glyph_is_invisible(glyph) &&
+                  !glyph_is_statue(glyph)) {
            You(cant_see_spot);
            return (res);
        } else if (!couldsee(cc.x, cc.y)) { /* Eyes of the Overworld */
@@ -2616,14 +2642,38 @@ use_pole(obj)
        }
 
        /* Attack the monster there */
-       if ((mtmp = m_at(cc.x, cc.y)) != (struct monst *)0) {
-           bhitpos = cc;
+       bhitpos = cc;
+       if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != (struct monst *)0) {
            if (attack_checks(mtmp, uwep)) return res;
            check_caitiff(mtmp);
+           notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
            (void) thitmonst(mtmp, uwep);
-       } else
-           /* Now you know that nothing is there... */
-           pline(nothing_happens);
+       } else if (glyph_is_statue(glyph) && /* might be hallucinatory */
+                   sobj_at(STATUE, bhitpos.x, bhitpos.y)) {
+           struct trap *t = t_at(bhitpos.x, bhitpos.y);
+
+           if (t && t->ttyp == STATUE_TRAP &&
+                   activate_statue_trap(t, t->tx, t->ty, FALSE)) {
+               ;       /* feedback has been give by animate_statue() */
+           } else {
+               /* Since statues look like monsters now, we say something
+                  different from "you miss" or "there's nobody there".
+                  Note:  we only do this when a statue is displayed here,
+                  because the player is probably attempting to attack it;
+                  other statues obscured by anything are just ignored. */
+               pline("Thump!  Your blow bounces harmlessly off the statue.");
+               wake_nearto(bhitpos.x, bhitpos.y, 25);
+           }
+       } else {
+           /* no monster here and no statue seen or remembered here */
+           if (glyph_is_invisible(glyph)) {
+               /* now you know that nothing is there... */
+               unmap_object(bhitpos.x, bhitpos.y);
+               newsym(bhitpos.x, bhitpos.y);
+           }
+           You("miss; there is no one there to hit.");
+       }
+       u_wipe_engr(2);         /* same as for melee or throwing */
        return (1);
 }
 
@@ -2667,7 +2717,7 @@ struct obj *obj;
 }
 
 STATIC_OVL int
-use_grapple (obj)
+use_grapple(obj)
        struct obj *obj;
 {
        int res = 0, typ, max_range = 4, tohit;
@@ -2692,9 +2742,9 @@ use_grapple (obj)
        cc.x = u.ux;
        cc.y = u.uy;
        if (getpos(&cc, TRUE, "the spot to hit") < 0)
-           return 0;   /* user pressed ESC */
+           return res; /* ESC; uses turn iff grapnel became wielded */
 
-       /* Calculate range */
+       /* Calculate range; unlike use_pole(), there's no minimum for range */
        typ = uwep_skill_type();
        if (typ == P_NONE || P_SKILL(typ) <= P_BASIC) max_range = 4;
        else if (P_SKILL(typ) == P_SKILLED) max_range = 5;
@@ -2741,6 +2791,10 @@ use_grapple (obj)
            destroy_nhwindow(tmpwin);
        }
 
+       /* possibly scuff engraving at your feet;
+          any engraving at the target location is unaffected */
+       if (tohit == 2 || !rn2(2)) u_wipe_engr(rnd(2));
+
        /* What did you hit? */
        switch (tohit) {
        case 0: /* Trap */
@@ -2758,6 +2812,7 @@ use_grapple (obj)
        case 2: /* Monster */
            bhitpos = cc;
            if ((mtmp = m_at(cc.x, cc.y)) == (struct monst *)0) break;
+           notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
            save_confirm = flags.confirm;
            if (verysmall(mtmp->data) && !rn2(4) &&
                        enexto(&cc, u.ux, u.uy, (struct permonst *)0)) {
index 1bcab9479076ddb2d899d5658d230a6548f0d16b..8bccd02fd39636d5419a3c94d04575c6b915bbfc 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)uhitm.c    3.5     2007/12/19      */
+/*     SCCS Id: @(#)uhitm.c    3.5     2009/02/21      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -116,8 +116,8 @@ struct obj *wep;    /* uwep for attack(), null for kick_monster() */
                 * not stay there, so the player will have suddenly forgotten
                 * the square's contents for no apparent reason.
                if (!canspotmon(mtmp) &&
-                   !glyph_is_invisible(levl[u.ux+u.dx][u.uy+u.dy].glyph))
-                       map_invisible(u.ux+u.dx, u.uy+u.dy);
+                   !glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph))
+                       map_invisible(bhitpos.x, bhitpos.y);
                 */
                return FALSE;
        }
@@ -131,12 +131,12 @@ struct obj *wep;  /* uwep for attack(), null for kick_monster() */
         * the screen, so you know something is there.
         */
        if (!canspotmon(mtmp) &&
-                   !glyph_is_warning(glyph_at(u.ux+u.dx,u.uy+u.dy)) &&
-                   !glyph_is_invisible(levl[u.ux+u.dx][u.uy+u.dy].glyph) &&
+                   !glyph_is_warning(glyph_at(bhitpos.x,bhitpos.y)) &&
+                   !glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph) &&
                    !(!Blind && mtmp->mundetected && hides_under(mtmp->data))) {
                pline("Wait!  There's %s there you can't see!",
                        something);
-               map_invisible(u.ux+u.dx, u.uy+u.dy);
+               map_invisible(bhitpos.x, bhitpos.y);
                /* if it was an invisible mimic, treat it as if we stumbled
                 * onto a visible mimic
                 */
@@ -152,7 +152,7 @@ struct obj *wep;    /* uwep for attack(), null for kick_monster() */
 
        if (mtmp->m_ap_type && !Protection_from_shape_changers &&
           !sensemon(mtmp) &&
-          !glyph_is_warning(glyph_at(u.ux+u.dx,u.uy+u.dy))) {
+          !glyph_is_warning(glyph_at(bhitpos.x,bhitpos.y))) {
                /* If a hidden mimic was in a square where a player remembers
                 * some (probably different) unseen monster, the player is in
                 * luck--he attacks it even though it's hidden.
@@ -166,7 +166,7 @@ struct obj *wep;    /* uwep for attack(), null for kick_monster() */
        }
 
        if (mtmp->mundetected && !canseemon(mtmp) &&
-               !glyph_is_warning(glyph_at(u.ux+u.dx,u.uy+u.dy)) &&
+               !glyph_is_warning(glyph_at(bhitpos.x,bhitpos.y)) &&
                (hides_under(mtmp->data) || mtmp->data->mlet == S_EEL)) {
            mtmp->mundetected = mtmp->msleeping = 0;
            newsym(mtmp->mx, mtmp->my);
@@ -360,6 +360,10 @@ register struct monst *mtmp;
        /* possibly set in attack_checks;
           examined in known_hitum, called via hitum or hmonas below */
        override_confirmation = FALSE;
+       /* attack_checks() used to use <u.ux+u.dx,u.uy+u.dy> directly, now
+          it uses bhitpos instead; it might map an invisible monster there */
+       bhitpos.x = u.ux + u.dx;
+       bhitpos.y = u.uy + u.dy;
        if (attack_checks(mtmp, uwep)) return(TRUE);
 
        if (Upolyd) {