From 6ef8efcefb98ba725bb6927f88581bcc6fdc1201 Mon Sep 17 00:00:00 2001 From: "nethack.allison" Date: Sun, 19 Mar 2006 23:59:03 +0000 Subject: [PATCH] digging conjoined pits (trunk only) 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 | 1 + include/extern.h | 5 +- include/patchlevel.h | 2 +- include/trap.h | 2 + src/apply.c | 2 +- src/dig.c | 334 +++++++++++++++++++++++++++++++++++++------ src/hack.c | 9 +- src/music.c | 2 +- src/trap.c | 122 ++++++++++++++-- 9 files changed, 414 insertions(+), 65 deletions(-) diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 4cfe9acd1..c350a109d 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -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 diff --git a/include/extern.h b/include/extern.h index 8330cd989..bb23cbafa 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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); diff --git a/include/patchlevel.h b/include/patchlevel.h index ffa059e7b..0ecea015a 100644 --- a/include/patchlevel.h +++ b/include/patchlevel.h @@ -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" diff --git a/include/trap.h b/include/trap.h index def0b1a40..2e2cb5c47 100644 --- a/include/trap.h +++ b/include/trap.h @@ -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; diff --git a/src/apply.c b/src/apply.c index 2db4a03aa..7a5c8d323 100644 --- a/src/apply.c +++ b/src/apply.c @@ -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), diff --git a/src/dig.c b/src/dig.c index 0533523f0..2b3dc3a2b 100644 --- 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 */ + if (dighole(TRUE, (coord *)0)) { /* make pit at */ 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(); } diff --git a/src/hack.c b/src/hack.c index 11a1beb0e..93f83ef5e 100644 --- a/src/hack.c +++ b/src/hack.c @@ -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)) { diff --git a/src/music.c b/src/music.c index 5704ea718..da90daab1 100644 --- a/src/music.c +++ b/src/music.c @@ -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); diff --git a/src/trap.c b/src/trap.c index 9b757ea8d..718ea9a59 100644 --- a/src/trap.c +++ b/src/trap.c @@ -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. */ -- 2.40.0