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.
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);
#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 */
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;
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;
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");
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) {
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)) {
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 *
#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;
/*
(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);
}
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);
"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
} 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;
}
#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
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) {
(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.");
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) &&
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);
}
/*
* 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;
*/
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))
}
}
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;
}
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) */
/*
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++;
}
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
}
}
+ if (u.utrap && u.utraptype == TT_BURIEDBALL)
+ buried_ball_to_punishment();
+
if (!next_to_u()) {
You(shudder_for_moment);
return;
{
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;