From 51d60d972149e7c6f20c92a0e391a74e523e7ae9 Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Sat, 8 Apr 2006 06:55:15 +0000 Subject: [PATCH] digging land mines & bear traps (trunk only) suggested that digging down on a land mine with a pick-axe ought to set if off. I agree; this implements that and also for bear traps. In the bear trap case, if you dig down once trapped, you will destroy that trap explicitly rather than replace it with a pit, so it's now possible to escape from one without leaving another trap in your wake. Once the bear trap is gone, further digging there will make a pit as usual. While stuck in one, digging down poses a modest risk of harming yourself. |You now wield a pick-axe. |You start digging downward. A bear trap closes on your foot! |You start digging downward. You destroy the bear trap with your pick-axe. |You continue digging downward. You dig a pit in the floor. |You start digging downward. You dig a hole through the floor. |You fall through... [It seems a bit strange that finishing a pit discards all digging context, so that resuming within the pit in order to make a hole "starts" digging rather than "continues" it.] Digging down with a wand or spell will disarm these two types of traps and then leave the corresponding object (which may or may not fall through the resulting hole, like any other object there). Digging to the side via magic while trapped in a pit will also disarm such traps when it encounters them. (When not in a pit, a digging beam which simply passes over an armed bear trap or land mine won't have any effect on the trap.) Digging to the side via tool behaves somewhat oddly ("no room for the rubble"?) and will probably need some tweaking before eventual release; at present it doesn't reach adjacent traps so didn't need any land mine or bear trap handling. I put the fixes entry in the new features section. --- doc/fixes35.0 | 1 + include/extern.h | 3 ++- include/hack.h | 11 ++++---- src/dig.c | 68 +++++++++++++++++++++++++++++++++++++++--------- src/trap.c | 46 ++++++++++++++++++-------------- 5 files changed, 92 insertions(+), 37 deletions(-) diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 91f5fbd35..6262b4e2c 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -197,6 +197,7 @@ 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 #terrain command for debug mode +digging can activate or disarm some types of traps Platform- and/or Interface-Specific New Features diff --git a/include/extern.h b/include/extern.h index 47f8962d7..4c7292b97 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, coord *)); +E boolean FDECL(dighole, (BOOLEAN_P,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 *)); @@ -2149,6 +2149,7 @@ E void FDECL(water_damage, (struct obj *,BOOLEAN_P,BOOLEAN_P)); E boolean NDECL(drown); E void FDECL(drain_en, (int)); E int NDECL(dountrap); +E void FDECL(cnv_trap_obj, (int,int,struct trap *,BOOLEAN_P)); E int FDECL(untrap, (BOOLEAN_P)); E boolean FDECL(chest_trap, (struct obj *,int,BOOLEAN_P)); E void FDECL(deltrap, (struct trap *)); diff --git a/include/hack.h b/include/hack.h index cd37508bf..1e3b31e34 100644 --- a/include/hack.h +++ b/include/hack.h @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)hack.h 3.5 2006/02/03 */ +/* SCCS Id: @(#)hack.h 3.5 2006/04/07 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -231,10 +231,11 @@ NEARDATA extern coord bhitpos; /* place where throw or zap hits or stops */ #define PICK_RIGID 1 /* Flags to control dotrap() in trap.c */ -#define NOWEBMSG 0x01 /* suppress stumble into web message */ -#define FORCEBUNGLE 0x02 /* adjustments appropriate for bungling */ -#define RECURSIVETRAP 0x04 /* trap changed into another type this same turn */ -#define TOOKPLUNGE 0x08 /* used '>' to enter pit below you */ +#define FORCETRAP 0x01 /* triggering not left to chance */ +#define NOWEBMSG 0x02 /* suppress stumble into web message */ +#define FORCEBUNGLE 0x04 /* adjustments appropriate for bungling */ +#define RECURSIVETRAP 0x08 /* trap changed into another type this same turn */ +#define TOOKPLUNGE 0x10 /* used '>' to enter pit below you */ /* Flags to control test_move in hack.c */ #define DO_MOVE 0 /* really doing the move */ diff --git a/src/dig.c b/src/dig.c index 022918d39..2f949923e 100644 --- a/src/dig.c +++ b/src/dig.c @@ -276,23 +276,54 @@ dig() if (context.digging.effort > 250 || (ttmp && ttmp->ttyp == HOLE)) { - (void) dighole(FALSE, (coord *)0); + (void) dighole(FALSE, FALSE, (coord *)0); (void) memset((genericptr_t)&context.digging, 0, - sizeof (struct dig_info)); + sizeof context.digging); return(0); /* done with digging */ } if (context.digging.effort <= 50 || (ttmp && (ttmp->ttyp == TRAPDOOR || - ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT))) + ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT))) { return(1); + } else if (ttmp && (ttmp->ttyp == LANDMINE || + (ttmp->ttyp == BEAR_TRAP && !u.utrap))) { + /* digging onto a set object trap triggers it; + hero should have used #untrap first */ + dotrap(ttmp, FORCETRAP); + /* restart completely from scratch if we resume digging */ + (void) memset((genericptr_t)&context.digging, 0, + sizeof context.digging); + return 0; + } else if (ttmp && ttmp->ttyp == BEAR_TRAP && u.utrap) { + if (rnl(7) > (Fumbling ? 1 : 4)) { + char kbuf[BUFSZ]; + int dmg = dmgval(uwep, &youmonst) + dbon(); + + if (dmg < 1) dmg = 1; + else if (uarmf) dmg = (dmg + 1) / 2; + You("hit yourself in the %s.", body_part(FOOT)); + Sprintf(kbuf, "chopping off %s own %s", + uhis(), body_part(FOOT)); + losehp(Maybe_Half_Phys(dmg), kbuf, KILLED_BY); + } else { + You("destroy the bear trap with %s.", + yobjnam(uwep, (const char *)0)); + u.utrap = 0; /* release from trap */ + deltrap(ttmp); + } + /* we haven't made any progress toward a pit yet */ + context.digging.effort = 0; + return 0; + } if (IS_ALTAR(lev->typ)) { altar_wrath(dpx, dpy); angry_priest(); } - if (dighole(TRUE, (coord *)0)) { /* make pit at */ + /* make pit at */ + if (dighole(TRUE, FALSE, (coord *)0)) { context.digging.level.dnum = 0; context.digging.level.dlevel = -1; } @@ -679,8 +710,8 @@ const char *fillmsg; /* return TRUE if digging succeeded, FALSE otherwise */ boolean -dighole(pit_only, cc) -boolean pit_only; +dighole(pit_only, by_magic, cc) +boolean pit_only, by_magic; coord *cc; { register struct trap *ttmp; @@ -792,6 +823,15 @@ coord *cc; return TRUE; } + /* magical digging disarms settable traps */ + if (by_magic && ttmp && + (ttmp->ttyp == LANDMINE || ttmp->ttyp == BEAR_TRAP)) { + int otyp = (ttmp->ttyp == LANDMINE) ? LAND_MINE : BEARTRAP; + + /* convert trap into buried object (deletes trap) */ + cnv_trap_obj(otyp, 1, ttmp, TRUE); + } + /* finally we get to make a hole */ if (nohole || pit_only) digactualhole(dig_x, dig_y, BY_YOU, PIT); @@ -1067,13 +1107,17 @@ struct obj *obj; dotrap(trap, FORCEBUNGLE); /* might escape trap and still be teetering at brink */ if (!u.utrap) cant_reach_floor(u.ux, u.uy, FALSE, TRUE); - } else if (!ispick) { + } else if (!ispick && + /* can only dig down with an axe if stuck in a bear trap */ + (!trap || !u.utrap || u.utraptype != TT_BEARTRAP)) { pline("%s merely scratches the %s.", Yobjnam2(obj, (char *)0), surface(u.ux,u.uy)); u_wipe_engr(3); } else { - if (context.digging.pos.x != u.ux || context.digging.pos.y != u.uy || - !on_level(&context.digging.level, &u.uz) || !context.digging.down) { + if (context.digging.pos.x != u.ux || + context.digging.pos.y != u.uy || + !on_level(&context.digging.level, &u.uz) || + !context.digging.down) { context.digging.chew = FALSE; context.digging.down = TRUE; context.digging.warned = FALSE; @@ -1271,7 +1315,7 @@ zap_dig() newsym(u.ux, u.uy); } else { watch_dig((struct monst *)0, u.ux, u.uy, TRUE); - (void) dighole(FALSE, (coord *)0); + (void) dighole(FALSE, TRUE, (coord *)0); } } return; @@ -1312,7 +1356,7 @@ zap_dig() if (buf[0]) pline("%s", buf); } else { /* this can also result in a pool at zx,zy */ - dighole(TRUE, &cc); + dighole(TRUE, TRUE, &cc); adjpit = t_at(zx,zy); } } @@ -1900,7 +1944,7 @@ escape_tomb() "ooze" : "phase", surface(u.ux, u.uy)); if(tunnels(youmonst.data) && !needspick(youmonst.data)) - good = dighole(TRUE, (coord *)0); + good = dighole(TRUE, FALSE, (coord *)0); else good = TRUE; if(good) unearth_you(); } diff --git a/src/trap.c b/src/trap.c index ea7e5f659..dc4d913f6 100644 --- a/src/trap.c +++ b/src/trap.c @@ -10,7 +10,6 @@ STATIC_DCL void FDECL(dofiretrap, (struct obj *)); STATIC_DCL void NDECL(domagictrap); STATIC_DCL boolean FDECL(emergency_disrobe,(boolean *)); STATIC_DCL int FDECL(untrap_prob, (struct trap *ttmp)); -STATIC_DCL void FDECL(cnv_trap_obj, (int, int, struct trap *)); STATIC_DCL void FDECL(move_into_trap, (struct trap *)); STATIC_DCL int FDECL(try_disarm, (struct trap *,BOOLEAN_P)); STATIC_DCL void FDECL(reward_untrap, (struct trap *, struct monst *)); @@ -631,11 +630,12 @@ unsigned trflags; { register int ttype = trap->ttyp; register struct obj *otmp; - boolean already_seen = trap->tseen; - 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); + boolean already_seen = trap->tseen, + forcetrap = (trflags & FORCETRAP) != 0, + webmsgok = (trflags & NOWEBMSG) == 0, + forcebungle = (trflags & FORCEBUNGLE) != 0, + plunged = (trflags & TOOKPLUNGE) != 0, + adj_pit = conjoined_pits(trap, t_at(u.ux0,u.uy0), TRUE); #ifdef STEED int steed_article = ARTICLE_THE; #endif @@ -655,7 +655,7 @@ unsigned trflags; a_your[trap->madeby_u], defsyms[trap_to_defsym(ttype)].explanation); /* then proceed to normal trap effect */ - } else if (already_seen) { + } else if (already_seen && !forcetrap) { if ((Levitation || Flying) && (ttype == PIT || ttype == SPIKED_PIT || ttype == HOLE || ttype == BEAR_TRAP)) { @@ -783,7 +783,7 @@ unsigned trflags; break; case SQKY_BOARD: /* stepped on a squeaky board */ - if (Levitation || Flying) { + if ((Levitation || Flying) && !forcetrap) { if (!Blind) { seetrap(trap); if (Hallucination) @@ -799,7 +799,7 @@ unsigned trflags; break; case BEAR_TRAP: - if(Levitation || Flying) break; + if ((Levitation || Flying) && !forcetrap) break; feeltrap(trap); if(amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data)) { @@ -1179,7 +1179,7 @@ glovecheck: (void) rust_dmg(uarmg, "gauntlets", 1, TRUE, &youmonst); unsigned steed_mid = 0; struct obj *saddle = 0; #endif - if (Levitation || Flying) { + if ((Levitation || Flying) && !forcetrap) { if (!already_seen && rn2(3)) break; feeltrap(trap); pline("%s %s in a pile of soil below you.", @@ -3205,23 +3205,31 @@ struct trap *ttmp; } /* Replace trap with object(s). Helge Hafting */ -STATIC_OVL void -cnv_trap_obj(otyp, cnt, ttmp) +void +cnv_trap_obj(otyp, cnt, ttmp, bury_it) int otyp; int cnt; struct trap *ttmp; +boolean bury_it; { struct obj *otmp = mksobj(otyp, TRUE, FALSE); - otmp->quan=cnt; + + otmp->quan = cnt; otmp->owt = weight(otmp); /* Only dart traps are capable of being poisonous */ if (otyp != DART) otmp->opoisoned = 0; place_object(otmp, ttmp->tx, ttmp->ty); - /* Sell your own traps only... */ - if (ttmp->madeby_u) sellobj(otmp, ttmp->tx, ttmp->ty); - stackobj(otmp); + if (bury_it) { + /* magical digging first disarms this trap, then will unearth it */ + (void) bury_an_obj(otmp); + } else { + /* Sell your own traps only... */ + if (ttmp->madeby_u) sellobj(otmp, ttmp->tx, ttmp->ty); + stackobj(otmp); + } newsym(ttmp->tx, ttmp->ty); + if (u.utrap && ttmp->tx == u.ux && ttmp->ty == u.uy) u.utrap = 0; deltrap(ttmp); } @@ -3389,7 +3397,7 @@ struct trap *ttmp; } else { if (ttmp->ttyp == BEAR_TRAP) { You("disarm %s bear trap.", the_your[ttmp->madeby_u]); - cnv_trap_obj(BEARTRAP, 1, ttmp); + cnv_trap_obj(BEARTRAP, 1, ttmp, FALSE); } else /* if (ttmp->ttyp == WEB) */ { You("succeed in removing %s web.", the_your[ttmp->madeby_u]); deltrap(ttmp); @@ -3407,7 +3415,7 @@ struct trap *ttmp; if (fails < 2) return fails; You("disarm %s land mine.", the_your[ttmp->madeby_u]); - cnv_trap_obj(LAND_MINE, 1, ttmp); + cnv_trap_obj(LAND_MINE, 1, ttmp, FALSE); return 1; } @@ -3458,7 +3466,7 @@ int otyp; if (fails < 2) return fails; You("disarm %s trap.", the_your[ttmp->madeby_u]); - cnv_trap_obj(otyp, 50-rnl(50), ttmp); + cnv_trap_obj(otyp, 50-rnl(50), ttmp, FALSE); return 1; }