]> granicus.if.org Git - nethack/commitdiff
buried punishment ball
authornethack.allison <nethack.allison>
Tue, 11 Mar 2003 03:40:17 +0000 (03:40 +0000)
committernethack.allison <nethack.allison>
Tue, 11 Mar 2003 03:40:17 +0000 (03:40 +0000)
Prevent burying a ball from ending your punishment.

When you bury the ball, internally NetHack Punishment
ceases, but a new trap type of TT_BURIEDBALL  immediately
kicks in (acting similar to TT_INFLOOR in some ways).
You can eventually work the ball free (or teleport, etc.),
but that will just return you back to normal Punishment.

14 files changed:
include/extern.h
include/you.h
src/apply.c
src/ball.c
src/cmd.c
src/dig.c
src/do_wear.c
src/dothrow.c
src/hack.c
src/polyself.c
src/pray.c
src/read.c
src/sit.c
src/teleport.c

index e8623fe2b681b06126303e5f5126df0ddb63c61f..1e1e5170026cdf21b511f5fcef28e7db31419f3b 100644 (file)
@@ -241,6 +241,9 @@ E void FDECL(bury_objs, (int,int));
 E void FDECL(unearth_objs, (int,int));
 E void FDECL(rot_organic, (genericptr_t, long));
 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);
 #if 0
 E void FDECL(bury_monst, (struct monst *));
 E void NDECL(bury_you);
index 2ca496df9596e4a10155b174dca405156ca33127..ed347a7136a36eba0f8dd34b13b8b75c750a837c 100644 (file)
@@ -250,6 +250,7 @@ struct you {
 #define TT_WEB         2
 #define TT_LAVA                3
 #define TT_INFLOOR     4
+#define TT_BURIEDBALL  5
        char    urooms[5];      /* rooms (roomno + 3) occupied now */
        char    urooms0[5];     /* ditto, for previous position */
        char    uentered[5];    /* rooms (roomno + 3) entered this turn */
index caea685d3d572c207f66ea379685f149d051b59d..d90beaac0c5673d6af828729ad377ddd5a46e1f6 100644 (file)
@@ -817,6 +817,10 @@ struct obj **optr;
                    unpunish();
                    res = 1;
                }
+               else if (u.utrap && u.utraptype == TT_BURIEDBALL) {
+                   buried_ball_to_freedom();
+                   res = 1;
+               }
                res += openit();
                switch (res) {
                  case 0:  pline(nothing_happens); break;
@@ -1315,9 +1319,12 @@ int magic; /* 0=Physical, otherwise skill level */
                    You("pull yourself above the lava!");
                    u.utrap = 0;
                    return 1;
+               case TT_BURIEDBALL:
                case TT_INFLOOR:
-                   You("strain your %s, but you're still stuck in the floor.",
-                       makeplural(body_part(LEG)));
+                   You("strain your %s, but you're still %s.",
+                       makeplural(body_part(LEG)),
+                       (u.utraptype == TT_INFLOOR) ? "stuck in the floor" :
+                       "attached to the buried ball");
                    set_wounded_legs(LEFT_SIDE, rn1(10, 11));
                    set_wounded_legs(RIGHT_SIDE, rn1(10, 11));
                    return 1;
index b2a05e00119f40ac4500e981383a17e2f755e755..8cc7b473cc95a08c9841e624d44e505e2cd0b905 100644 (file)
@@ -653,7 +653,7 @@ xchar x, y;
        struct trap *t;
        const char *pullmsg = "The ball pulls you out of the %s!";
 
-       if (u.utrap && u.utraptype != TT_INFLOOR) {
+       if (u.utrap && u.utraptype != TT_INFLOOR && u.utraptype != TT_BURIEDBALL) {
            switch(u.utraptype) {
            case TT_PIT:
                pline(pullmsg, "pit");
index d89b5aebf198f1f0b93739a0593d53494d5b0cc4..3384d758c5b0e48c532a4ddb523fa5b4aaeb137a 100644 (file)
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -1039,6 +1039,7 @@ int final;        /* 0 => still in progress; 1 => over, survived; 2 => dead */
        if (Lifesaved)
                enl_msg("Your life ", "will be", "would have been", " saved");
        if (u.twoweap) you_are("wielding two weapons at once");
+       if (u.utraptype == TT_BURIEDBALL) you_are("fastened to a buried ball");
 
        /*** Miscellany ***/
        if (Luck) {
index a484f2c392981d2ff5be2715c536d14f9576cbcc..beaff70054e38298baf67893e57669ad963f5e5a 100644 (file)
--- a/src/dig.c
+++ b/src/dig.c
@@ -492,6 +492,9 @@ int ttyp;
        boolean at_u = (x == u.ux) && (y == u.uy);
        boolean wont_fall = Levitation || Flying;
 
+       if (u.utrap && u.utraptype == TT_BURIEDBALL)
+               buried_ball_to_punishment();
+
        /* these furniture checks were in dighole(), but wand
           breaking bypasses that routine and calls us directly */
        if (IS_FOUNTAIN(lev->typ)) {
@@ -1277,6 +1280,84 @@ zap_dig()
        return;
 }
 
+struct obj *
+buried_ball(cc)
+coord *cc;
+{
+       xchar check_x, check_y;
+       struct obj *otmp, *otmp2;
+       if (u.utraptype == TT_BURIEDBALL)
+           for (otmp = level.buriedobjlist; otmp; otmp = otmp2) {
+               otmp2 = otmp->nobj;
+               if (otmp->otyp != HEAVY_IRON_BALL) continue;
+               /* try the exact location first */
+               if (otmp->ox == cc->x && otmp->oy == cc->y)
+                   return otmp;
+               /* Now try the vicinity */
+               /*
+                * (x-2,y-2)       (x+2,y-2)
+                *           (x,y)
+                * (x-2,y+2)       (x+2,y+2)
+                */
+               for (check_x = cc->x-2; check_x <= cc->x+2; ++check_x)
+                   for (check_y = cc->y-2; check_y <= cc->y+2; ++check_y) {
+                       if (check_x == cc->x && check_y == cc->y) continue;
+                       if (isok(check_x, check_y) &&
+                           (otmp->ox == check_x && otmp->oy == check_y)) {
+                               cc->x = check_x;
+                               cc->y = check_y;
+                               return otmp;
+                       }
+                   }
+           }
+       return (struct obj *)0;
+}
+
+void
+buried_ball_to_punishment()
+{
+       coord cc;
+       struct obj *ball;
+       cc.x = u.ux; cc.y = u.uy;
+       ball = buried_ball(&cc);
+       if (ball) {
+               obj_extract_self(ball);
+#if 0
+               /* rusting buried metallic objects is not implemented yet */
+               if (ball->timed)
+                       (void) stop_timer(RUST_METAL, (genericptr_t)ball);
+#endif
+               punish(ball);   /* use ball as flag for unearthed buried ball */
+               u.utrap = 0;
+               u.utraptype = 0;
+               del_engr_at(cc.x, cc.y);
+               newsym(cc.x, cc.y);
+       }
+}
+
+void
+buried_ball_to_freedom()
+{
+       coord cc;
+       struct obj *ball;
+       cc.x = u.ux; cc.y = u.uy;
+       ball = buried_ball(&cc);
+       if (ball) {
+               obj_extract_self(ball);
+#if 0
+               /* rusting buried metallic objects is not implemented yet */
+               if (ball->timed)
+                       (void) stop_timer(RUST_METAL, (genericptr_t)ball);
+#endif
+               place_object(ball, cc.x, cc.y);
+               stackobj(ball);
+               u.utrap = 0;
+               u.utraptype = 0;
+               del_engr_at(cc.x, cc.y);
+               newsym(cc.x, cc.y);
+       }
+}
+
 /* move objects from fobj/nexthere lists to buriedobjlist, keeping position */
 /* information */
 struct obj *
@@ -1289,8 +1370,12 @@ bury_an_obj(otmp)
 #ifdef DEBUG
        pline("bury_an_obj: %s", xname(otmp));
 #endif
-       if (otmp == uball)
+       if (otmp == uball) {
                unpunish();
+               u.utrap = rn1(50,20);
+               u.utraptype = TT_BURIEDBALL;
+               pline_The("iron ball gets buried!");
+       }
        /* after unpunish(), or might get deallocated chain */
        otmp2 = otmp->nexthere;
        /*
@@ -1329,6 +1414,13 @@ bury_an_obj(otmp)
            (void) start_timer((under_ice ? 0L : 250L) + (long)rnd(250),
                               TIMER_OBJECT, ROT_ORGANIC, (genericptr_t)otmp);
        }
+#if 0
+       /* rusting of buried metal not yet implemented */
+       else if (is_rustprone(otmp)) {
+           (void) start_timer((long)rnd(otmp->otyp == HEAVY_IRON_BALL ? 1500 : 250),
+                              TIMER_OBJECT, RUST_METAL, (genericptr_t)otmp);
+       }
+#endif
        add_to_buried(otmp);
        return(otmp2);
 }
@@ -1356,19 +1448,26 @@ void
 unearth_objs(x, y)
 int x, y;
 {
-       struct obj *otmp, *otmp2;
+       struct obj *otmp, *otmp2, *bball;
+       coord cc;
 
 #ifdef DEBUG
        pline("unearth_objs: at %d, %d", x, y);
 #endif
+       cc.x = x; cc.y = y;
+       bball = buried_ball(&cc);
        for (otmp = level.buriedobjlist; otmp; otmp = otmp2) {
                otmp2 = otmp->nobj;
                if (otmp->ox == x && otmp->oy == y) {
-                   obj_extract_self(otmp);
-                   if (otmp->timed)
-                       (void) stop_timer(ROT_ORGANIC, (genericptr_t)otmp);
-                   place_object(otmp, x, y);
-                   stackobj(otmp);
+                   if (bball && otmp == bball && u.utraptype == TT_BURIEDBALL)
+                       buried_ball_to_punishment();
+                   else {
+                       obj_extract_self(otmp);
+                       if (otmp->timed)
+                           (void) stop_timer(ROT_ORGANIC, (genericptr_t)otmp);
+                       place_object(otmp, x, y);
+                       stackobj(otmp);
+                   }
                }
        }
        del_engr_at(x, y);
index 5d25d621c04bc8cee2552f1f394549bc5b74159a..5caca22d1396650b440050d8703cd2d2c80aa9d3 100644 (file)
@@ -1243,13 +1243,17 @@ boolean noisy;
                                           "rear hooves" which sounds odd */
            err++;
        } else if (u.utrap && (u.utraptype == TT_BEARTRAP ||
-                               u.utraptype == TT_INFLOOR)) {
+                               u.utraptype == TT_INFLOOR ||
+                               u.utraptype == TT_BURIEDBALL)) {
            if (u.utraptype == TT_BEARTRAP) {
                if (noisy) Your("%s is trapped!", body_part(FOOT));
-           } else {
+           } else if (u.utraptype == TT_INFLOOR) {
                if (noisy) Your("%s are stuck in the %s!",
                                makeplural(body_part(FOOT)),
                                surface(u.ux, u.uy));
+           } else { /*TT_BURIEDBALL*/
+               if (noisy) Your("%s is attached to the buried ball!",
+                               body_part(LEG));
            }
            err++;
        } else
index b12c91d9537ee1ff0ba9bcb257e07d63d4d8fb46..7a3f109c6cb8e255341b06fb2ff4d9f2659a5efd 100644 (file)
@@ -598,7 +598,8 @@ hurtle(dx, dy, range, verbose)
     } else if (u.utrap) {
        You("are anchored by the %s.",
            u.utraptype == TT_WEB ? "web" : u.utraptype == TT_LAVA ? "lava" :
-               u.utraptype == TT_INFLOOR ? surface(u.ux,u.uy) : "trap");
+               u.utraptype == TT_INFLOOR ? surface(u.ux,u.uy) :
+               u.utraptype == TT_BURIEDBALL ? "buried ball" : "trap");
        nomul(0);
        return;
     }
index 594c523fa134ace67e029080387383f06a34f6dd..8620d3c330922b3340817abf361018c04c4755a5 100644 (file)
@@ -1178,19 +1178,24 @@ domove()
 #endif
                        You("disentangle yourself.");
                    }
-               } else if (u.utraptype == TT_INFLOOR) {
+               } else if (u.utraptype == TT_INFLOOR ||
+                          u.utraptype == TT_BURIEDBALL) {
                    if(--u.utrap) {
                        if(flags.verbose) {
-                           predicament = "stuck in the";
+                           predicament = (u.utraptype == TT_INFLOOR) ?
+                                       "stuck in the" : "attached to the";
 #ifdef STEED
                            if (u.usteed)
                                Norep("%s is %s %s.",
                                      upstart(y_monnam(u.usteed)),
-                                     predicament, surface(u.ux, u.uy));
+                                     predicament,
+                                     (u.utraptype == TT_INFLOOR) ?
+                                       surface(u.ux, u.uy) : "buried ball");
                            else
 #endif
                            Norep("You are %s %s.", predicament,
-                                 surface(u.ux, u.uy));
+                                 (u.utraptype == TT_INFLOOR) ?
+                                 surface(u.ux, u.uy) : "buried ball");
                        }
                    } else {
 #ifdef STEED
@@ -1199,7 +1204,11 @@ domove()
                                  upstart(y_monnam(u.usteed)));
                        else
 #endif
-                       You("finally wiggle free.");
+                       You("finally wiggle %s.",
+                               u.utraptype == TT_INFLOOR ?
+                               "free" : "the ball free");
+                       if (u.utraptype == TT_BURIEDBALL)
+                               buried_ball_to_punishment();
                    }
                } else {
                    if(flags.verbose) {
index 01bc49efaf738b2f423c68248050c8b2a7e69205..71336ee093062ddf10df494436aff0fdf876a392 100644 (file)
@@ -524,9 +524,15 @@ int        mntmp;
            (is_pool(u.ux,u.uy) || is_lava(u.ux,u.uy))) ||
           (Underwater && !Swimming))
            spoteffects(TRUE);
-       if (Passes_walls && u.utrap && u.utraptype == TT_INFLOOR) {
+       if (Passes_walls && u.utrap &&
+           (u.utraptype == TT_INFLOOR || u.utraptype == TT_BURIEDBALL)) {
            u.utrap = 0;
-           pline_The("rock seems to no longer trap you.");
+           if (u.utraptype == TT_INFLOOR)
+               pline_The("rock seems to no longer trap you.");
+           else {
+               pline_The("buried ball is no longer bound to you.");
+               buried_ball_to_freedom();
+           }
        } else if (likes_lava(youmonst.data) && u.utrap && u.utraptype == TT_LAVA) {
            u.utrap = 0;
            pline_The("lava now feels soothing.");
@@ -535,6 +541,9 @@ int mntmp;
            if (Punished) {
                You("slip out of the iron chain.");
                unpunish();
+           } else if (u.utrap && u.utraptype == TT_BURIEDBALL) {
+               You("slip free of the buried ball and chain.");
+               buried_ball_to_freedom();
            }
        }
        if (u.utrap && (u.utraptype == TT_WEB || u.utraptype == TT_BEARTRAP) &&
@@ -771,6 +780,11 @@ int
 doremove()
 {
        if (!Punished) {
+               if (u.utrap && u.utraptype == TT_BURIEDBALL) {
+                   pline_The("ball and chain are buried firmly in the %s.",
+                               surface(u.ux, u.uy));
+                   return(0);
+               }
                You("are not chained to anything!");
                return(0);
        }
index 1c26474cb5cda6545586907548b92d581198f3a3..0a51cdfca8894f00e9028c0c8dfbc3d63d046266 100644 (file)
@@ -174,7 +174,8 @@ in_trouble()
        /*
         * minor troubles
         */
-       if(Punished) return(TROUBLE_PUNISHED);
+       if(Punished || (u.utrap && u.utraptype == TT_BURIEDBALL))
+               return(TROUBLE_PUNISHED);
        if (Cursed_obj(uarmg, GAUNTLETS_OF_FUMBLING) ||
                Cursed_obj(uarmf, FUMBLE_BOOTS))
            return TROUBLE_FUMBLING;
@@ -372,7 +373,10 @@ register int trouble;
         */
            case TROUBLE_PUNISHED:
                    Your("chain disappears.");
-                   unpunish();
+                   if(u.utrap && u.utraptype == TT_BURIEDBALL)
+                       buried_ball_to_freedom();
+                   else
+                       unpunish();
                    break;
            case TROUBLE_FUMBLING:
                    if (Cursed_obj(uarmg, GAUNTLETS_OF_FUMBLING))
index bc7a46ac62fe785675a43b5b58f4f4e641ba1106..2e087c0b9dd0f1baad86615669dd3ea2604a308d 100644 (file)
@@ -944,6 +944,11 @@ register struct obj        *sobj;
                    }
                }
                if(Punished && !confused) unpunish();
+               if(u.utrap && u.utraptype == TT_BURIEDBALL) {
+                       buried_ball_to_freedom();
+                       pline_The("clasp on your %s vanishes.",
+                               body_part(LEG));
+               }
                update_inventory();
                break;
            }
@@ -1733,20 +1738,29 @@ void
 punish(sobj)
 register struct obj    *sobj;
 {
+       struct obj *reuse_ball = (sobj && sobj->otyp == HEAVY_IRON_BALL) ?
+                                sobj : (struct obj *)0;
        /* KMH -- Punishment is still okay when you are riding */
-       You("are being punished for your misbehavior!");
+       if (!reuse_ball) You("are being punished for your misbehavior!");
        if(Punished){
                Your("iron ball gets heavier.");
                uball->owt += 160 * (1 + sobj->cursed);
                return;
        }
        if (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data)) {
-               pline("A ball and chain appears, then falls away.");
-               dropy(mkobj(BALL_CLASS, TRUE));
+               if (!reuse_ball) {
+                       pline("A ball and chain appears, then falls away.");
+                       dropy(mkobj(BALL_CLASS, TRUE));
+               } else {
+                       dropy(reuse_ball);
+               }
                return;
        }
        setworn(mkobj(CHAIN_CLASS, TRUE), W_CHAIN);
-       setworn(mkobj(BALL_CLASS, TRUE), W_BALL);
+       if (!reuse_ball)
+               setworn(mkobj(BALL_CLASS, TRUE), W_BALL);
+       else
+               setworn(reuse_ball, W_BALL);
        uball->spe = 1;         /* special ball (see save) */
 
        /*
index be76665dec16a0f2ef059a0f5a93704f63ff78dd..0770340c1d7c8969418117a7db1b16fd525661d2 100644 (file)
--- a/src/sit.c
+++ b/src/sit.c
@@ -91,7 +91,7 @@ dosit()
                    You("sit in the lava!");
                    u.utrap += rnd(4);
                    losehp(d(2,10), "sitting in lava", KILLED_BY);
-               } else if(u.utraptype == TT_INFLOOR) {
+               } else if(u.utraptype == TT_INFLOOR || u.utraptype == TT_BURIEDBALL) {
                    You_cant("maneuver to sit!");
                    u.utrap++;
                }
index 8bded74053640cb837d6603b410c09328e874810..503c96a1ad5f9c2599d286e041450cad2e8f86fc 100644 (file)
@@ -231,9 +231,15 @@ teleds(nux, nuy, allow_drag)
 register int nux,nuy;
 boolean allow_drag;
 {
-       boolean ball_active = (Punished && uball->where != OBJ_FREE),
-               ball_still_in_range = FALSE;
+       boolean ball_active, ball_still_in_range;
 
+       if (u.utraptype == TT_BURIEDBALL) {
+               /* unearth it */
+               buried_ball_to_punishment();
+       }
+       ball_active = (Punished && uball->where != OBJ_FREE),
+               ball_still_in_range = FALSE;
+       
        /* If they have to move the ball, then drag if allow_drag is true;
         * otherwise they are teleporting, so unplacebc().  
         * If they don't have to move the ball, then always "drag" whether or
@@ -646,6 +652,9 @@ level_tele()
            }
        }
 
+       if (u.utrap && u.utraptype == TT_BURIEDBALL)
+               buried_ball_to_punishment();
+
        if (!next_to_u()) {
                You(shudder_for_moment);
                return;
@@ -766,6 +775,9 @@ register struct trap *ttmp;
 {
        struct d_level target_level;
 
+       if (u.utrap && u.utraptype == TT_BURIEDBALL)
+               buried_ball_to_punishment();
+
        if (!next_to_u()) {
                You(shudder_for_moment);
                return;