]> granicus.if.org Git - nethack/commitdiff
digging conjoined pits (trunk only)
authornethack.allison <nethack.allison>
Sun, 19 Mar 2006 23:59:03 +0000 (23:59 +0000)
committernethack.allison <nethack.allison>
Sun, 19 Mar 2006 23:59:03 +0000 (23:59 +0000)
This one turned out to be more effort than I had
originally anticipated.

We had a bug report requesting that zapping a wand of digging
laterally while in a pit should dig beside you. That seemed
like a reasonable enough request, but this ended up with
the following results:
- needed to check where this should not be permitted, or at
  least where there should be special-case code because there is
  something such as furniture on the surface above the dig
  point.
- now tracks conjoined pits through new fields in the trap
  structure, hence the pathlevel increment. The array of
  8 boolean values represents each of the 8 directions
  around a pit.
- Previously, pits could be adjacent to each other as two
  individual pits, in which case moving between them
  results in a fall as you went into the next pit. That
  behavior is preserved.
- Pits created either by zapping a wand of digging
  laterally while in a pit, or by "clearing debris"
  between two adjacent pits via a pick-axe, sets the
  conjoined fields for those two pits. You cannot
  create a brand new adjacent pit via pick-axe, only
  with the wand.
- The hero can pass between conjoined pits without
  falling.
- dighole() was hijacked for adjacent pit digging,
  so the ability to pass coordinates to it and
  its downstream functions was added (dig_up_grave()
  for example). dighole() does pretty much everything
  appropriately for this adjacent digging, more so
  than calling digactualhole() directly.
- moving into a conjoined pit that has spikes still
  does damage, but less so that "falling" into the
  spiked pit, and you "step on" the spikes rather
  than falling into them.
- Not done: should pits with the conjoined fields
  set be referred to as 'trenches' rather than pits
  in messages and identifications?

doc/fixes35.0
include/extern.h
include/patchlevel.h
include/trap.h
src/apply.c
src/dig.c
src/hack.c
src/music.c
src/trap.c

index 4cfe9acd1f7073045dc0f848cb5114e129f7550d..c350a109d570e46b8fa1b5eea2e5e1733bb0e869 100644 (file)
@@ -187,6 +187,7 @@ number_pad:-1 to swap function of y and z keys; z to move NW, y to zap wands
 display spell retention information in the spell menu
 tame ghouls can eat old eggs
 new effect for reading a scroll of light while confused
+allow digging an adjacent pit with wand of digging while trapped in a pit
 
 
 Platform- and/or Interface-Specific New Features
index 8330cd989dfd56857509f11133a8e1b4a842be04..bb23cbafa4f64b93ba4650825c61554ef8a6f276 100644 (file)
@@ -254,7 +254,7 @@ E int NDECL(dig);
 E int NDECL(holetime);
 E boolean FDECL(dig_check, (struct monst *, BOOLEAN_P, int, int));
 E void FDECL(digactualhole, (int,int,struct monst *,int));
-E boolean FDECL(dighole, (BOOLEAN_P));
+E boolean FDECL(dighole, (BOOLEAN_P, coord *));
 E int FDECL(use_pick_axe, (struct obj *));
 E int FDECL(use_pick_axe2, (struct obj *));
 E boolean FDECL(mdig_tunnel, (struct monst *));
@@ -268,8 +268,9 @@ E void FDECL(rot_corpse, (genericptr_t, long));
 E struct obj *FDECL(buried_ball, (coord *));
 E void NDECL(buried_ball_to_punishment);
 E void NDECL(buried_ball_to_freedom);
-E schar FDECL(fillholetyp, (int, int));
+E schar FDECL(fillholetyp, (int,int,BOOLEAN_P));
 E void FDECL(liquid_flow, (XCHAR_P,XCHAR_P,SCHAR_P,struct trap *, const char *));
+E boolean FDECL(conjoined_pits, (struct trap *,struct trap *,BOOLEAN_P));
 #if 0
 E void FDECL(bury_monst, (struct monst *));
 E void NDECL(bury_you);
index ffa059e7b6c97357d6dc9428dbf73d9a81953372..0ecea015a68a6a1e1faa69f7d546332919d05abd 100644 (file)
@@ -13,7 +13,7 @@
  * Incrementing EDITLEVEL can be used to force invalidation of old bones
  * and save files.
  */
-#define EDITLEVEL      26
+#define EDITLEVEL      27
 
 #define COPYRIGHT_BANNER_A \
 "NetHack, Copyright 1985-2006"
index def0b1a404f294bc19c78f98a921e50f0a892c2a..2e2cb5c4731b9ec8560268ead57983ed5d320e62 100644 (file)
@@ -10,6 +10,7 @@
 union vlaunchinfo {
        short v_launch_otyp;    /* type of object to be triggered */
        coord v_launch2;        /* secondary launch point (for boulders) */
+       boolean v_conjoined[8]; /* conjoined pit locations */
 };
 
 struct trap {
@@ -30,6 +31,7 @@ struct trap {
        union vlaunchinfo vl;
 #define launch_otyp    vl.v_launch_otyp
 #define launch2                vl.v_launch2
+#define conjoined       vl.v_conjoined
 };
 
 extern struct trap *ftrap;
index 2db4a03aa6d0151cc7c332395378cca654d7c202..7a5c8d3237983eba3f09f962077a203081b35b18 100644 (file)
@@ -2843,7 +2843,7 @@ do_break_wand(obj)
                 * Adjust corresponding code in music.c for
                 * drum of earthquake if you alter this sequence.
                 */
-               typ = fillholetyp(x,y); 
+               typ = fillholetyp(x,y,FALSE); 
                if (typ != ROOM) {
                        levl[x][y].typ = typ;
                        liquid_flow(x, y, typ, t_at(x,y),
index 0533523f0abb977db5b501080bcb7d842adfcadb..2b3dc3a2b9cf3e1e18737ccd2d53e69a28497451 100644 (file)
--- a/src/dig.c
+++ b/src/dig.c
@@ -13,7 +13,9 @@ STATIC_DCL void FDECL(mkcavepos, (XCHAR_P,XCHAR_P,int,BOOLEAN_P,BOOLEAN_P));
 STATIC_DCL void FDECL(mkcavearea, (BOOLEAN_P));
 STATIC_DCL int FDECL(dig_typ, (struct obj *,XCHAR_P,XCHAR_P));
 STATIC_DCL int NDECL(dig);
-STATIC_DCL void NDECL(dig_up_grave);
+STATIC_DCL void FDECL(dig_up_grave, (coord *));
+STATIC_DCL int FDECL(adj_pit_checks, (coord *,char *));
+STATIC_DCL void FDECL(pit_flow, (struct trap *,SCHAR_P));
 
 /* Indices returned by dig_typ() */
 #define DIGTYP_UNDIGGABLE 0
@@ -274,7 +276,7 @@ dig()
 
                if (context.digging.effort > 250 ||
                        (ttmp && ttmp->ttyp == HOLE)) {
-                   (void) dighole(FALSE);
+                   (void) dighole(FALSE, (coord *)0);
                    (void) memset((genericptr_t)&context.digging, 0,
                                        sizeof (struct dig_info));
                    return(0);  /* done with digging */
@@ -290,7 +292,7 @@ dig()
                    angry_priest();
                }
 
-               if (dighole(TRUE)) {    /* make pit at <u.ux,u.uy> */
+               if (dighole(TRUE, (coord *)0)) {        /* make pit at <u.ux,u.uy> */
                    context.digging.level.dnum = 0;
                    context.digging.level.dlevel = -1;
                }
@@ -439,8 +441,9 @@ holetime()
 
 /* Return typ of liquid to fill a hole with, or ROOM, if no liquid nearby */
 schar
-fillholetyp(x,y)
+fillholetyp(x,y,fill_if_any)
 int x, y;
+boolean fill_if_any;   /* force filling if it exists at all */
 {
     register int x1, y1;
     int lo_x = max(1,x-1), hi_x = min(x+1,COLNO-1),
@@ -459,13 +462,16 @@ int x, y;
                    (levl[x1][y1].typ == DRAWBRIDGE_UP &&
                        (levl[x1][y1].drawbridgemask & DB_UNDER) == DB_LAVA))
                lava_cnt++;
-    pool_cnt /= 3;             /* not as much liquid as the others */
+    if (!fill_if_any) pool_cnt /= 3;           /* not as much liquid as the others */
 
-    if (lava_cnt > moat_cnt + pool_cnt && rn2(lava_cnt + 1))
+    if ((lava_cnt > moat_cnt + pool_cnt && rn2(lava_cnt + 1)) ||
+       (lava_cnt && fill_if_any))
        return LAVAPOOL;
-    else if (moat_cnt > 0 && rn2(moat_cnt + 1))
+    else if ((moat_cnt > 0 && rn2(moat_cnt + 1)) ||
+           (moat_cnt && fill_if_any))
        return MOAT;
-    else if (pool_cnt > 0 && rn2(pool_cnt + 1))
+    else if ((pool_cnt > 0 && rn2(pool_cnt + 1)) ||
+           (pool_cnt && fill_if_any))
        return POOL;
     else
        return ROOM;
@@ -538,7 +544,10 @@ int ttyp;
        if (ttyp == PIT) {
 
            if(madeby_u) {
-               You("dig a pit in the %s.", surface_type);
+               if (x != u.ux || y != u.uy)
+                       You("dig an adjacent pit.");
+               else
+                       You("dig a pit in the %s.", surface_type);
                if (shopdoor) pay_for_damage("ruin", FALSE);
            } else if (!madeby_obj && canseemon(madeby))
                pline("%s digs a pit in the %s.", Monnam(madeby), surface_type);
@@ -670,27 +679,44 @@ const char *fillmsg;
 
 /* return TRUE if digging succeeded, FALSE otherwise */
 boolean
-dighole(pit_only)
+dighole(pit_only, cc)
 boolean pit_only;
+coord *cc;
 {
-       register struct trap *ttmp = t_at(u.ux, u.uy);
-       struct rm *lev = &levl[u.ux][u.uy];
+       register struct trap *ttmp;
+       struct rm *lev;
        struct obj *boulder_here;
        schar typ;
-       boolean nohole = (!Can_dig_down(&u.uz) && !lev->candig);
+       xchar dig_x,dig_y;
+       boolean nohole;
+
+       if (!cc) {
+               dig_x = u.ux;
+               dig_y = u.uy;
+       } else {
+               dig_x = cc->x;
+               dig_y = cc->y;
+               if (!isok(dig_x,dig_y)) return FALSE;
+       }
+
+       ttmp = t_at(dig_x, dig_y);
+       lev = &levl[dig_x][dig_y];
+       nohole = (!Can_dig_down(&u.uz) && !lev->candig);
 
        if ((ttmp && (ttmp->ttyp == MAGIC_PORTAL || nohole)) ||
           (IS_ROCK(lev->typ) && lev->typ != SDOOR &&
            (lev->wall_info & W_NONDIGGABLE) != 0)) {
-               pline_The("%s here is too hard to dig in.", surface(u.ux,u.uy));
+               pline_The("%s %shere is too hard to dig in.",
+                               surface(dig_x,dig_y),
+                               (dig_x != u.ux || dig_y != u.uy) ? "t" : "");
 
-       } else if (is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) {
+       } else if (is_pool(dig_x, dig_y) || is_lava(dig_x, dig_y)) {
                pline_The("%s sloshes furiously for a moment, then subsides.",
-                       is_lava(u.ux, u.uy) ? "lava" : "water");
+                       is_lava(dig_x, dig_y) ? "lava" : "water");
                wake_nearby();  /* splashing */
 
        } else if (lev->typ == DRAWBRIDGE_DOWN ||
-                  (is_drawbridge_wall(u.ux, u.uy) >= 0)) {
+                  (is_drawbridge_wall(dig_x, dig_y) >= 0)) {
                /* drawbridge_down is the platform crossing the moat when the
                   bridge is extended; drawbridge_wall is the open "doorway" or
                   closed "door" where the portcullis/mechanism is located */
@@ -698,17 +724,19 @@ boolean pit_only;
                    pline_The("drawbridge seems too hard to dig through.");
                    return FALSE;
                } else {
-                   int x = u.ux, y = u.uy;
+                   int x = dig_x, y = dig_y;
                    /* if under the portcullis, the bridge is adjacent */
                    (void) find_drawbridge(&x, &y);
                    destroy_drawbridge(x, y);
                    return TRUE;
                }
 
-       } else if ((boulder_here = sobj_at(BOULDER, u.ux, u.uy)) != 0) {
+       } else if ((boulder_here = sobj_at(BOULDER, dig_x, dig_y)) != 0) {
                if (ttmp && (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) &&
                    rn2(2)) {
-                       pline_The("boulder settles into the pit.");
+                       pline_The("boulder settles into the %spit.",
+                               (dig_x != u.ux || dig_y != u.uy) ?
+                                       "adjacent " : "");
                        ttmp->ttyp = PIT;        /* crush spikes */
                } else {
                        /*
@@ -722,27 +750,28 @@ boolean pit_only;
                return TRUE;
 
        } else if (IS_GRAVE(lev->typ)) {        
-           digactualhole(u.ux, u.uy, BY_YOU, PIT);
-           dig_up_grave();
+           digactualhole(dig_x, dig_y, BY_YOU, PIT);
+           dig_up_grave(cc);
            return TRUE;
        } else if (lev->typ == DRAWBRIDGE_UP) {
                /* must be floor or ice, other cases handled above */
                /* dig "pit" and let fluid flow in (if possible) */
-               typ = fillholetyp(u.ux,u.uy);
+               typ = fillholetyp(dig_x,dig_y,FALSE);
 
                if (typ == ROOM) {
                        /*
                         * We can't dig a hole here since that will destroy
                         * the drawbridge.  The following is a cop-out. --dlc
                         */
-                       pline_The("%s here is too hard to dig in.",
-                             surface(u.ux, u.uy));
+                       pline_The("%s %shere is too hard to dig in.",
+                             surface(dig_x, dig_y),
+                             (dig_x != u.ux || dig_y != u.uy) ? "t" : "");
                        return FALSE;
                }
 
                lev->drawbridgemask &= ~DB_UNDER;
                lev->drawbridgemask |= (typ == LAVAPOOL) ? DB_LAVA : DB_MOAT;
-               liquid_flow(u.ux, u.uy, typ, ttmp,
+               liquid_flow(dig_x, dig_y, typ, ttmp,
                                "As you dig, the hole fills with %s!");
                return TRUE;
 
@@ -754,20 +783,20 @@ boolean pit_only;
                pline_The("altar is too hard to break apart.");
 
        } else {
-               typ = fillholetyp(u.ux,u.uy);
+               typ = fillholetyp(dig_x,dig_y,FALSE);
 
                if (typ != ROOM) {
                        lev->typ = typ;
-                       liquid_flow(u.ux, u.uy, typ, ttmp,
+                       liquid_flow(dig_x, dig_y, typ, ttmp,
                                "As you dig, the hole fills with %s!");
                        return TRUE;
                }
 
                /* finally we get to make a hole */
                if (nohole || pit_only)
-                       digactualhole(u.ux, u.uy, BY_YOU, PIT);
+                       digactualhole(dig_x, dig_y, BY_YOU, PIT);
                else
-                       digactualhole(u.ux, u.uy, BY_YOU, HOLE);
+                       digactualhole(dig_x, dig_y, BY_YOU, HOLE);
 
                return TRUE;
        }
@@ -776,9 +805,21 @@ boolean pit_only;
 }
 
 STATIC_OVL void
-dig_up_grave()
+dig_up_grave(cc)
+coord *cc;
 {
        struct obj *otmp;
+       xchar dig_x, dig_y;
+
+       if (!cc) {
+               dig_x = u.ux;
+               dig_y = u.uy;
+       } else {
+               dig_x = cc->x;
+               dig_y = cc->y;
+               if (!isok(dig_x,dig_y)) return ;
+       }
+
 
        /* Grave-robbing is frowned upon... */
        exercise(A_WIS, FALSE);
@@ -797,27 +838,27 @@ dig_up_grave()
        case 0:
        case 1:
            You("unearth a corpse.");
-           if (!!(otmp = mk_tt_object(CORPSE, u.ux, u.uy)))
+           if (!!(otmp = mk_tt_object(CORPSE, dig_x, dig_y)))
                otmp->age -= 100;               /* this is an *OLD* corpse */;
            break;
        case 2:
            if (!Blind) pline(Hallucination ? "Dude!  The living dead!" :
                        "The grave's owner is very upset!");
-           (void) makemon(mkclass(S_ZOMBIE,0), u.ux, u.uy, NO_MM_FLAGS);
+           (void) makemon(mkclass(S_ZOMBIE,0), dig_x, dig_y, NO_MM_FLAGS);
            break;
        case 3:
            if (!Blind) pline(Hallucination ? "I want my mummy!" :
                        "You've disturbed a tomb!");
-           (void) makemon(mkclass(S_MUMMY,0), u.ux, u.uy, NO_MM_FLAGS);
+           (void) makemon(mkclass(S_MUMMY,0), dig_x, dig_y, NO_MM_FLAGS);
            break;
        default:
            /* No corpse */
            pline_The("grave seems unused.  Strange....");
            break;
        }
-       levl[u.ux][u.uy].typ = ROOM;
-       del_engr_at(u.ux, u.uy);
-       newsym(u.ux,u.uy);
+       levl[dig_x][dig_y].typ = ROOM;
+       del_engr_at(dig_x, dig_y);
+       newsym(dig_x,dig_y);
        return;
 }
 
@@ -878,7 +919,7 @@ struct obj *obj;
 {
        register int rx, ry;
        register struct rm *lev;
-       struct trap *trap;
+       struct trap *trap, *trap_with_u;
        int dig_target;
        boolean ispick = is_pick(obj);
        const char *verbing = ispick ? "digging" : "chopping";
@@ -946,6 +987,29 @@ struct obj *obj;
                            if (vibrate) losehp(Maybe_Half_Phys(2),
                                                "axing a hard object", KILLED_BY);
                        }
+                       else if (u.utrap && u.utraptype == TT_PIT && trap &&
+                                (trap_with_u = t_at(u.ux, u.uy)) &&
+                                (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) &&
+                                 !conjoined_pits(trap, trap_with_u, FALSE)) {
+                               int idx;
+                               for (idx = 0; idx < 8; idx++) {
+                                   if (xdir[idx] == u.dx && ydir[idx] == u.dy)
+                                       break;
+                               }
+                               /* idx is valid if < 8 */
+                               if (idx < 8) {
+                                       int adjidx = (idx + 4) % 8;
+                                       trap_with_u->conjoined[idx] = TRUE;
+                                       trap->conjoined[adjidx] = TRUE;
+                                       pline(
+                                 "You clear some debris from between the pits.");
+                               }
+                       }
+                       else if (u.utrap && u.utraptype == TT_PIT &&
+                                (trap_with_u = t_at(u.ux, u.uy))) {
+                           You("swing %s, but the rubble has no place to go.",
+                               yobjnam(obj, (char *)0));
+                       }
                        else
                            You("swing %s through thin air.",
                                yobjnam(obj, (char *)0));
@@ -1159,8 +1223,10 @@ zap_dig()
        struct rm *room;
        struct monst *mtmp;
        struct obj *otmp;
-       int zx, zy, digdepth;
-       boolean shopdoor, shopwall, maze_dig;
+       struct trap *trap_with_u = (struct trap *)0;
+       int zx, zy, diridx, digdepth, flow_x, flow_y;
+       boolean shopdoor, shopwall, maze_dig, pitdig = FALSE, pitflow = FALSE;
+
        /*
         * Original effect (approximately):
         * from CORR: dig until we pierce a wall
@@ -1168,6 +1234,7 @@ zap_dig()
         * an ACCESSIBLE place.
         * Currently: dig for digdepth positions;
         * also down on request of Lennart Augustsson.
+        * 3.5.0: from a PIT: dig one adjacent pit.
         */
 
        if (u.uswallow) {
@@ -1204,7 +1271,7 @@ zap_dig()
                    newsym(u.ux, u.uy);
                } else {
                    watch_dig((struct monst *)0, u.ux, u.uy, TRUE);
-                   (void) dighole(FALSE);
+                   (void) dighole(FALSE, (coord *)0);
                }
            }
            return;
@@ -1215,6 +1282,14 @@ zap_dig()
        maze_dig = level.flags.is_maze_lev && !Is_earthlevel(&u.uz);
        zx = u.ux + u.dx;
        zy = u.uy + u.dy;
+       if(u.utrap && u.utraptype == TT_PIT && (trap_with_u = t_at(u.ux, u.uy))) {
+               pitdig = TRUE;
+               for (diridx = 0; diridx < 8; diridx++) {
+                   if (xdir[diridx] == u.dx && ydir[diridx] == u.dy)
+                       break;
+                   /* diridx is valid if < 8 */
+               }
+       }
        digdepth = rn1(18, 8);
        tmp_at(DISP_BEAM, cmap_to_glyph(S_digbeam));
        while (--digdepth >= 0) {
@@ -1222,7 +1297,42 @@ zap_dig()
            room = &levl[zx][zy];
            tmp_at(zx,zy);
            delay_output();     /* wait a little bit */
-           if (closed_door(zx, zy) || room->typ == SDOOR) {
+
+           if (pitdig) {       /* we are already in a pit if this is true */
+               coord cc;
+               struct trap *adjpit = t_at(zx,zy);
+               if ((diridx < 8) &&
+                       !conjoined_pits(adjpit, trap_with_u, FALSE)) {
+                   digdepth = 0;  /* limited to the adjacent location only */
+                   if (!(adjpit && (adjpit->ttyp == PIT ||
+                                    adjpit->ttyp == SPIKED_PIT))) {
+                       char buf[BUFSZ];
+                       cc.x = zx; cc.y = zy;
+                       if (!adj_pit_checks(&cc, buf)) {
+                               if (buf[0]) pline("%s", buf);
+                       } else {
+                               /* this can also result in a pool at zx,zy */
+                               dighole(TRUE, &cc);
+                               adjpit = t_at(zx,zy);
+                       }
+                   }
+                   if (adjpit && (adjpit->ttyp == PIT ||
+                                  adjpit->ttyp == SPIKED_PIT)) {
+                               int adjidx = (diridx + 4) % 8;
+                               trap_with_u->conjoined[diridx] = TRUE;
+                               adjpit->conjoined[adjidx] = TRUE;
+                               flow_x = zx;
+                               flow_y = zy;
+                               pitflow = TRUE;
+                   }
+                   if (is_pool(zx,zy) || is_lava(zx,zy)) {
+                               flow_x = zx - u.dx;
+                               flow_y = zy - u.dy;
+                               pitflow = TRUE;
+                   }
+                   break;
+               }
+           } else if (closed_door(zx, zy) || room->typ == SDOOR) {
                if (*in_rooms(zx,zy,SHOPBASE)) {
                    add_damage(zx, zy, 400L);
                    shopdoor = TRUE;
@@ -1291,11 +1401,149 @@ zap_dig()
            zy += u.dy;
        } /* while */
        tmp_at(DISP_END,0);     /* closing call */
+
+       if (pitflow) {
+               struct trap *ttmp  = t_at(flow_x, flow_y);
+               if (ttmp && (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT)) {
+                       schar filltyp = fillholetyp(ttmp->tx, ttmp->ty, TRUE);
+                       if (filltyp != ROOM)
+                               pit_flow(ttmp, filltyp);
+               }
+       }
+
        if (shopdoor || shopwall)
            pay_for_damage(shopdoor ? "destroy" : "dig into", FALSE);
        return;
 }
 
+/*
+ * This checks what is on the surface above the
+ * location where an adjacent pit might be created if
+ * you're zapping a wand of digging laterally while
+ * down in the pit.
+ */
+STATIC_OVL int
+adj_pit_checks(cc, msg)
+coord *cc;
+char *msg;
+{
+       int ltyp;
+       struct rm *room;
+       const char *foundation_msg =
+               "The foundation is too hard to dig through from this angle.";
+
+       if (!cc) return FALSE;
+       if (!isok(cc->x,cc->y)) return FALSE;
+       if (msg) *msg = '\0';
+       room = &levl[cc->x][cc->y];
+       ltyp = room->typ;
+
+
+       if (is_pool(cc->x, cc->y) || is_lava(cc->x, cc->y)) {
+               /* this is handled by the caller after we return FALSE */
+               return FALSE;
+       } else if (closed_door(cc->x, cc->y) || room->typ == SDOOR) {
+               /* We reject this here because dighole() isn't
+                  prepared to deal with this case */
+               Strcpy(msg, foundation_msg);
+               return FALSE;
+       } else if (IS_WALL(ltyp)) {
+               /* if (room->wall_info & W_NONDIGGABLE) */
+               Strcpy(msg, foundation_msg);
+               return FALSE;
+       } else if (IS_TREE(ltyp)) { /* check trees before stone */
+               /* if (room->wall_info & W_NONDIGGABLE) */
+               Strcpy(msg, "The tree's roots glow then fade.");
+               return FALSE;
+       } else if (ltyp == STONE || ltyp == SCORR) {
+               if (room->wall_info & W_NONDIGGABLE) {
+                       Strcpy(msg, "The rock glows then fades.");
+                       return FALSE;
+               }
+       } else if (ltyp == IRONBARS) {
+               /* "set of iron bars" */
+               Strcpy(msg, "The bars go much deeper than your pit.");
+#if 0
+       } else if (is_lava(cc->x,cc->y)) {
+       } else if (is_ice(cc->x,cc->y)) {
+       } else if (is_pool(cc->x,cc->y)) {
+       } else if (IS_GRAVE(ltyp)) {
+#endif
+#ifdef SINKS
+       } else if (IS_SINK(ltyp)) {
+               Strcpy(msg, "A tangled mass of plumbing remains below the sink.");
+               return FALSE;           
+#endif
+       } else if ((cc->x == xupladder && cc->y == yupladder) || /* "ladder up" */
+                  (cc->x == xdnladder && cc->y == ydnladder)) { /* "ladder down" */
+               Strcpy(msg, "The ladder is unaffected.");
+               return FALSE;
+       } else  {
+               const char *supporting = (const char *)0;
+               if (IS_FOUNTAIN(ltyp)) supporting = "fountain";
+               else if (IS_THRONE(ltyp)) supporting = "throne";
+               else if (IS_ALTAR(ltyp)) supporting = "altar";
+               else if ((cc->x == xupstair && cc->y == yupstair) ||
+                (cc->x == sstairs.sx && cc->y == sstairs.sy && sstairs.up))
+                       /* "staircase up" */
+                       supporting = "stairs";
+               else if ((cc->x == xdnstair && cc->y == ydnstair) ||
+                (cc->x == sstairs.sx && cc->y == sstairs.sy && !sstairs.up))
+                       /* "staircase down" */
+                       supporting = "stairs";
+               else if ((ltyp == DRAWBRIDGE_DOWN)  || /* "lowered drawbridge" */
+                        (ltyp == DBWALL))           /* "raised drawbridge" */
+                       supporting = "drawbridge";
+               if (supporting) {
+                   Sprintf(msg,
+                               "The %s%ssupporting structures remain intact.",
+                               supporting ? s_suffix(supporting) : "",
+                               supporting ? " " : "");
+                   return FALSE;
+               }
+       }
+       return TRUE;
+}
+
+/*
+ * Ensure that all conjoined pits fill up.
+ */
+STATIC_OVL void
+pit_flow(trap, filltyp)
+struct trap *trap;
+schar filltyp;
+{
+       int idx;
+       if (trap && (filltyp != ROOM) &&
+           (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) {
+               struct trap t;
+               t = *trap;
+               levl[trap->tx][trap->ty].typ = filltyp;
+               liquid_flow(trap->tx, trap->ty, filltyp, trap,
+                           (trap->tx == u.ux && trap->ty == u.uy) ?
+                           "Suddenly %s flows in from the adjacent pit!":
+                           (char *)0);
+               for(idx = 0; idx < 8; ++idx) {
+                       if (t.conjoined[idx]) {
+                               int x, y;
+                               struct trap *t2;
+                               x = t.tx + xdir[idx];
+                               y = t.ty + ydir[idx];
+                               t2 = t_at(x,y);
+#if 0
+                               /* cannot do this back-check; liquid_flow()
+                                * called deltrap() which cleaned up the
+                                * conjoined fields on both pits.
+                                */
+                               if (t2 && t2->conjoined[(idx + 4) % 8])
+#endif
+                               /* recursion */
+                               pit_flow(t2, filltyp);
+                       }
+               }
+       }
+}
+
 struct obj *
 buried_ball(cc)
 coord *cc;
@@ -1651,7 +1899,7 @@ escape_tomb()
                         "ooze" : "phase", surface(u.ux, u.uy));
 
                    if(tunnels(youmonst.data) && !needspick(youmonst.data))
-                       good = dighole(TRUE);
+                       good = dighole(TRUE, (coord *)0);
                    else good = TRUE;
                    if(good) unearth_you();
                }
index 11a1beb0e976dee80b9b5d50f907fcf7874fe0c0..93f83ef5ee0ec616b734d9d8dd5305ecc17ff061 100644 (file)
@@ -915,7 +915,7 @@ domove()
        register xchar x,y;
        struct trap *trap;
        int wtcap;
-       boolean on_ice;
+       boolean on_ice, adj_pit = FALSE;
        xchar chainx, chainy, ballx, bally;     /* ball&chain new positions */
        int bc_control;                         /* control for ball&chain */
        boolean cause_delay = FALSE;    /* dragging ball will skip a move */
@@ -1184,7 +1184,10 @@ domove()
        }
        if(u.utrap) {
                if(u.utraptype == TT_PIT) {
-                   climb_pit();
+                   if (trap && trap->tseen &&
+                       (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT))
+                       adj_pit = TRUE;
+                   if (!adj_pit) climb_pit();
                } else if (u.utraptype == TT_LAVA) {
                    if(flags.verbose) {
                        predicament = "stuck in the lava";
@@ -1281,7 +1284,7 @@ domove()
                    }
                    if((u.dx && u.dy) || !rn2(5)) u.utrap--;
                }
-               return;
+               if (!adj_pit) return;
        }
 
        if (!test_move(u.ux, u.uy, x-u.ux, y-u.uy, DO_MOVE)) {
index 5704ea71823b5b09af2452e100d9aff0ee098f2a..da90daab13add749842ada715f8f3ba7be0fe487 100644 (file)
@@ -284,7 +284,7 @@ do_pit:                 chasm = maketrap(x,y,PIT);
                     * Adjust corresponding code in apply.c for
                     * exploding wand of digging if you alter this sequence.
                     */
-                   filltype = fillholetyp(x,y);
+                   filltype = fillholetyp(x,y,FALSE);
                    if (filltype != ROOM) {
                        levl[x][y].typ = filltype;
                        liquid_flow(x, y, filltype, chasm, (char *)0);
index 9b757ea8d7dc578d1752a15ce0c65fc80c43d449..718ea9a599f6b01adbc36f07b7823a3b4553e22c 100644 (file)
@@ -25,6 +25,10 @@ STATIC_DCL void FDECL(launch_drop_spot, (struct obj *, XCHAR_P, XCHAR_P));
 STATIC_DCL int FDECL(mkroll_launch,
                        (struct trap *,XCHAR_P,XCHAR_P,SHORT_P,long));
 STATIC_DCL boolean FDECL(isclearpath,(coord *, int, SCHAR_P, SCHAR_P));
+#if 0
+STATIC_DCL void FDECL(join_adjacent_pits, (struct trap *));
+#endif
+STATIC_DCL void FDECL(clear_conjoined_pits, (struct trap *));
 #ifdef STEED
 STATIC_OVL int FDECL(steedintrap, (struct trap *, struct obj *));
 STATIC_OVL boolean FDECL(keep_saddle_with_steedcorpse,
@@ -223,6 +227,7 @@ register int x, y, typ;
        register struct trap *ttmp;
        register struct rm *lev;
        register boolean oldplace;
+       int idx;
 
        if ((ttmp = t_at(x,y)) != 0) {
            if (ttmp->ttyp == MAGIC_PORTAL) return (struct trap *)0;
@@ -267,6 +272,8 @@ register int x, y, typ;
            case PIT:
            case SPIKED_PIT:
            case TRAPDOOR:
+               for (idx = 0; idx < 8; ++idx)
+                   ttmp->conjoined[idx] = FALSE;
                lev = &levl[x][y];
                if (*in_rooms(x, y, SHOPBASE) &&
                        ((typ == HOLE || typ == TRAPDOOR) ||
@@ -629,6 +636,7 @@ unsigned trflags;
        boolean webmsgok = (!(trflags & NOWEBMSG));
        boolean forcebungle = (trflags & FORCEBUNGLE);
        boolean plunged = (trflags & TOOKPLUNGE);
+       boolean adj_pit = conjoined_pits(trap, t_at(u.ux0,u.uy0), TRUE);
 #ifdef STEED
        int steed_article = ARTICLE_THE;
 #endif
@@ -659,9 +667,9 @@ unsigned trflags;
                return;
            }
            if(!Fumbling && ttype != MAGIC_PORTAL &&
-               ttype != ANTI_MAGIC && !forcebungle && !plunged &&
+               ttype != ANTI_MAGIC && !forcebungle && !plunged && !adj_pit &&
                (!rn2(5) ||
-           ((ttype == PIT || ttype == SPIKED_PIT) && is_clinger(youmonst.data)))) {
+    ((ttype == PIT || ttype == SPIKED_PIT) && is_clinger(youmonst.data)))) {
                You("escape %s %s.",
                    (ttype == ARROW_TRAP && !trap->madeby_u) ? "an" :
                        a_your[trap->madeby_u],
@@ -938,8 +946,12 @@ glovecheck:                (void) rust_dmg(uarmg, "gauntlets", 1, TRUE, &youmonst);
                                           "poor", SUPPRESS_SADDLE, FALSE));
                    } else
 #endif
-                   Strcpy(verbbuf, plunged ? "plunge" : "fall");
-                   You("%s into %s pit!", verbbuf, a_your[trap->madeby_u]);
+                   if (adj_pit) {
+                       You("move into an adjacent pit.");
+                   } else {
+                       Strcpy(verbbuf, plunged ? "plunge" : "fall");
+                       You("%s into %s pit!", verbbuf, a_your[trap->madeby_u]);
+                   }
                }
                /* wumpus reference */
                if (Role_if(PM_RANGER) && !trap->madeby_u && !trap->once &&
@@ -953,13 +965,14 @@ glovecheck:               (void) rust_dmg(uarmg, "gauntlets", 1, TRUE, &youmonst);
                    const char *predicament = "on a set of sharp iron spikes";
 #ifdef STEED
                    if (u.usteed) {
-                       pline("%s lands %s!",
+                       pline("%s %s %s!",
                              upstart(x_monnam(u.usteed, steed_article,
                                               "poor", SUPPRESS_SADDLE, FALSE)),
+                             adj_pit ? "steps" : "lands",
                              predicament);
                    } else
 #endif
-                   You("land %s!", predicament);
+                   You("%s %s!", adj_pit ? "step" : "land", predicament);
                }
                u.utrap = rn1(6,2);
                u.utraptype = TT_PIT;
@@ -967,24 +980,29 @@ glovecheck:               (void) rust_dmg(uarmg, "gauntlets", 1, TRUE, &youmonst);
                if (!steedintrap(trap, (struct obj *)0)) {
 #endif
                if (ttype == SPIKED_PIT) {
-                   losehp(Maybe_Half_Phys(rnd(10)),
+                   losehp(Maybe_Half_Phys(rnd(adj_pit ? 6 : 10)),
                        plunged ? "deliberately plunged into a pit of iron spikes" :
+                       adj_pit ? "stepped into a pit of iron spikes" :
                                  "fell into a pit of iron spikes",
                        NO_KILLER_PREFIX);
                    if (!rn2(6))
-                       poisoned("spikes", A_STR, "fall onto poison spikes",
+                       poisoned("spikes", A_STR,
+                               adj_pit ? "stepping on poison spikes" :
+                                         "fall onto poison spikes",
                                 8, FALSE);
-               } else
-                   losehp(Maybe_Half_Phys(rnd(6)),
-                       plunged ? "deliberately plunged into a pit" :
-                                 "fell into a pit",
-                       NO_KILLER_PREFIX);
+               } else {
+                   if (!adj_pit)
+                       losehp(Maybe_Half_Phys(rnd(6)),
+                               plunged ? "deliberately plunged into a pit" :
+                                         "fell into a pit",
+                               NO_KILLER_PREFIX);
+               }
                if (Punished && !carried(uball)) {
                    unplacebc();
                    ballfall();
                    placebc();
                }
-               selftouch("Falling, you");
+               if (!adj_pit) selftouch("Falling, you");
                vision_full_recalc = 1; /* vision limits change */
                exercise(A_STR, FALSE);
                exercise(A_DEX, FALSE);
@@ -3956,6 +3974,7 @@ register struct trap *trap;
 {
        register struct trap *ttmp;
 
+       clear_conjoined_pits(trap);
        if(trap == ftrap)
                ftrap = ftrap->ntrap;
        else {
@@ -3965,6 +3984,81 @@ register struct trap *trap;
        dealloc_trap(trap);
 }
 
+boolean
+conjoined_pits(trap2, trap1, u_entering_trap2)
+struct trap *trap2, *trap1;
+boolean u_entering_trap2;
+{
+       int dx, dy, diridx, adjidx;
+       if (!trap1 || !trap2) return FALSE;
+       if (!isok(trap2->tx,trap2->ty) || !isok(trap1->tx,trap1->ty) ||
+           !(trap2->ttyp == PIT || trap2->ttyp == SPIKED_PIT) ||
+           !(trap1->ttyp == PIT || trap1->ttyp == SPIKED_PIT) ||
+           (u_entering_trap2 && !(u.utrap && u.utraptype == TT_PIT)))
+               return FALSE;
+       dx = sgn(trap2->tx - trap1->tx);
+       dy = sgn(trap2->ty - trap1->ty);
+       for (diridx = 0; diridx < 8; diridx++)
+               if (xdir[diridx] == dx && ydir[diridx] == dy)
+                       break;
+       /* diridx is valid if < 8 */
+       if (diridx < 8) {
+               adjidx = (diridx + 4) % 8;
+               if (trap1->conjoined[diridx] && trap2->conjoined[adjidx])
+                       return TRUE;
+       }
+       return FALSE;
+}
+
+void
+clear_conjoined_pits(trap)
+struct trap *trap;
+{
+       int tmp, adj, x, y;
+       struct trap *t;
+       if (trap && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) {
+               for(tmp = 0; tmp < 8; ++tmp) {
+                   if (trap->conjoined[tmp]) {
+                       x = trap->tx + xdir[tmp];
+                       y = trap->ty + ydir[tmp];
+                       t = t_at(x,y);
+                       if (isok(x,y) && t &&
+                           (t->ttyp == PIT || t->ttyp == SPIKED_PIT)) {
+                               adj = (tmp + 4) % 8;
+                               t->conjoined[adj] = FALSE;
+                       }
+                       trap->conjoined[tmp] = FALSE;
+                   }
+               }
+       }       
+}
+
+#if 0
+/*
+ * Mark all neighboring pits as conjoined pits.
+ * (currently not called from anywhere)
+ */
+STATIC_OVL void
+join_adjacent_pits(trap)
+struct trap *trap;
+{
+       struct trap *t;
+       int tmp, x, y;
+       if (!trap) return;
+       for(tmp = 0; tmp < 8; ++tmp) {
+               x = trap->tx + xdir[tmp];
+               y = trap->ty + ydir[tmp];
+               if (isok(x,y)) {
+                   if (((t = t_at(x,y)) != 0) &&
+                         (t->ttyp == PIT || t->ttyp == SPIKED_PIT)) {
+                       trap->conjoined[tmp] = TRUE;
+                       join_adjacent_pits(t);
+                   } else trap->conjoined[tmp] = FALSE;
+               }
+       }
+}
+#endif
+
 /*
  * Returns TRUE if you escaped a pit and are standing on the precipice.
  */