]> granicus.if.org Git - nethack/commitdiff
skipping stones (trunk only)
authornethack.allison <nethack.allison>
Sun, 6 Jun 2004 18:37:46 +0000 (18:37 +0000)
committernethack.allison <nethack.allison>
Sun, 6 Jun 2004 18:37:46 +0000 (18:37 +0000)
Allow a chance of rocks thrown over water to skip
in such a way that they could bounce right over a water
creature.

doc/fixes35.0
src/zap.c

index 96cd23f6d008bc8f19bdae08c0057df149a6b417..69dd935b31b03af54266d33dfe9e0e847bc54560 100644 (file)
@@ -107,6 +107,7 @@ debug-mode wishing for random monster(s) via '*'
 health-food store that stocks monk-appropriate foods in mine town when monk
 give more information about your attributes in debug mode
 polywarn to give intrinsic monster detection of limited species while polymorphed
+rocks can skip on the water sometimes allowing them to pass over water creatures
 
 
 Platform- and/or Interface-Specific New Features
index fededb390a5fc5fbac00138fce142bd3a2af86fb..54d79d1aa93780a2f514e6101ef85c16dd90cd2b 100644 (file)
--- a/src/zap.c
+++ b/src/zap.c
@@ -29,6 +29,7 @@ STATIC_DCL void FDECL(revive_egg, (struct obj *));
 #ifdef STEED
 STATIC_DCL boolean FDECL(zap_steed, (struct obj *));
 #endif
+STATIC_DCL void FDECL(skiprange, (int,int *,int *));
 
 STATIC_DCL int FDECL(zap_hit, (int,int));
 STATIC_DCL void FDECL(backfire, (struct obj *));
@@ -50,6 +51,10 @@ STATIC_DCL int FDECL(spell_hit_bonus, (int));
 
 #define is_hero_spell(type)    ((type) >= 10 && (type) < 20)
 
+#define M_IN_WATER(ptr)                ((ptr)->mlet == S_EEL || \
+                                amphibious(ptr) || \
+                                is_swimmer(ptr))
+
 STATIC_VAR const char are_blinded_by_the_flash[] = "are blinded by the flash!";
 
 const char * const flash_types[] = {   /* also used in buzzmu(mcastu.c) */
@@ -2602,6 +2607,16 @@ register struct monst *mtmp;
              mon_nam(mtmp) : "it");
 }
 
+STATIC_OVL void
+skiprange(range, skipstart, skipend)
+int range, *skipstart, *skipend;
+{
+       int tmp = range - (rnd(range / 4));
+       *skipstart = tmp;
+       *skipend = tmp - ((tmp / 4) * rnd(3));
+       if (*skipend >= tmp) *skipend = tmp - 1;
+}
+
 /*
  *  Called for the following distance effects:
  *     when a weapon is thrown (weapon == THROWN_WEAPON)
@@ -2631,6 +2646,8 @@ struct obj *obj;                  /* object tossed/used */
        struct monst *mtmp;
        uchar typ;
        boolean shopdoor = FALSE, point_blank = TRUE;
+       boolean in_skip = FALSE, allow_skip = FALSE;
+       int skiprange_start = 0, skiprange_end = 0, skipcount = 0;
 
        if (weapon == KICKED_WEAPON) {
            /* object starts one square in front of player */
@@ -2642,6 +2659,11 @@ struct obj *obj;                 /* object tossed/used */
            bhitpos.y = u.uy;
        }
 
+       if (weapon == THROWN_WEAPON && obj && obj->otyp == ROCK) {
+               skiprange(range, &skiprange_start, &skiprange_end);
+               allow_skip = !rn2(3);
+       }
+
        if (weapon == FLASHED_LIGHT) {
            tmp_at(DISP_BEAM, cmap_to_glyph(S_flashbeam));
        } else if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM)
@@ -2704,7 +2726,39 @@ struct obj *obj;                 /* object tossed/used */
                        break;
                }
 
-           if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
+           mtmp = m_at(bhitpos.x, bhitpos.y);
+               
+           /*
+            * skipping rocks
+            *
+            * skiprange_start is only set if this is a thrown rock
+            */
+           if (skiprange_start && (range == skiprange_start) && allow_skip) {
+               if (is_pool(bhitpos.x, bhitpos.y) && !mtmp) {
+                       in_skip = TRUE;
+                       if (!Blind) pline("%s %s%s.", Yname2(obj),
+                                         otense(obj, "skip"),
+                                         skipcount ? " again" : "");
+                       else if (!Deaf) You_hear("%s skip.", Yname2(obj));
+                       skipcount++;
+               } else if (skiprange_start > skiprange_end + 1) {
+                       --skiprange_start;
+               }
+           }
+           if (in_skip) {
+               if (range <= skiprange_end) {
+                       in_skip = FALSE;
+                       if (range > 3)  /* another bounce? */
+                           skiprange(range, &skiprange_start, &skiprange_end);
+               } else if (mtmp && M_IN_WATER(mtmp->data)) {
+                       if ((!Blind && canseemon(mtmp)) || sensemon(mtmp))
+                               pline("%s %s over %s.",
+                                       Yname2(obj), otense(obj, "pass"),
+                                       mon_nam(mtmp));
+               }
+           }
+
+           if (mtmp && !(in_skip && M_IN_WATER(mtmp->data))) {
                notonhead = (bhitpos.x != mtmp->mx ||
                             bhitpos.y != mtmp->my);
                if (weapon != FLASHED_LIGHT) {