]> granicus.if.org Git - nethack/commitdiff
digging land mines & bear traps (trunk only)
authornethack.rankin <nethack.rankin>
Sat, 8 Apr 2006 06:55:15 +0000 (06:55 +0000)
committernethack.rankin <nethack.rankin>
Sat, 8 Apr 2006 06:55:15 +0000 (06:55 +0000)
     <Someone> 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
include/extern.h
include/hack.h
src/dig.c
src/trap.c

index 91f5fbd35f1ea9040b7bdbca212064cacd770a3e..6262b4e2c9a36dc9f9771127514e670c7ab635a8 100644 (file)
@@ -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
index 47f8962d70999dce06b37a5316545b98e9e5168d..4c7292b971ab1377f760168c3249dadae4533c59 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, 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 *));
index cd37508bf319848ef117b7c0b2360c06c895c3b4..1e3b31e34d1dfd8bd73d645e7137f6a07ddf51c4 100644 (file)
@@ -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 */
index 022918d3958edb41e2fa1aa6fd72e9bfbe4e86f9..2f949923ece46a4a55aa8bccb654ae3ce178de09 100644 (file)
--- 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 <u.ux,u.uy> */
+               /* make pit at <u.ux,u.uy> */
+               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();
                }
index ea7e5f6594649121468df2623d292b9c650d82a8..dc4d913f6facdebd2c43d723a992fb07753f28ea 100644 (file)
@@ -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;
 }