From 176d31c980eb7ae449b1511895d6d84a934cf2b0 Mon Sep 17 00:00:00 2001 From: "nethack.allison" Date: Tue, 11 Mar 2003 03:40:17 +0000 Subject: [PATCH] buried punishment ball 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. --- include/extern.h | 3 ++ include/you.h | 1 + src/apply.c | 11 ++++- src/ball.c | 2 +- src/cmd.c | 1 + src/dig.c | 113 ++++++++++++++++++++++++++++++++++++++++++++--- src/do_wear.c | 8 +++- src/dothrow.c | 3 +- src/hack.c | 19 +++++--- src/polyself.c | 18 +++++++- src/pray.c | 8 +++- src/read.c | 22 +++++++-- src/sit.c | 2 +- src/teleport.c | 16 ++++++- 14 files changed, 198 insertions(+), 29 deletions(-) diff --git a/include/extern.h b/include/extern.h index e8623fe2b..1e1e51700 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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); diff --git a/include/you.h b/include/you.h index 2ca496df9..ed347a713 100644 --- a/include/you.h +++ b/include/you.h @@ -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 */ diff --git a/src/apply.c b/src/apply.c index caea685d3..d90beaac0 100644 --- a/src/apply.c +++ b/src/apply.c @@ -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; diff --git a/src/ball.c b/src/ball.c index b2a05e001..8cc7b473c 100644 --- a/src/ball.c +++ b/src/ball.c @@ -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"); diff --git a/src/cmd.c b/src/cmd.c index d89b5aebf..3384d758c 100644 --- 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) { diff --git a/src/dig.c b/src/dig.c index a484f2c39..beaff7005 100644 --- 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); diff --git a/src/do_wear.c b/src/do_wear.c index 5d25d621c..5caca22d1 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -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 diff --git a/src/dothrow.c b/src/dothrow.c index b12c91d95..7a3f109c6 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -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; } diff --git a/src/hack.c b/src/hack.c index 594c523fa..8620d3c33 100644 --- a/src/hack.c +++ b/src/hack.c @@ -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) { diff --git a/src/polyself.c b/src/polyself.c index 01bc49efa..71336ee09 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -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); } diff --git a/src/pray.c b/src/pray.c index 1c26474cb..0a51cdfca 100644 --- a/src/pray.c +++ b/src/pray.c @@ -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)) diff --git a/src/read.c b/src/read.c index bc7a46ac6..2e087c0b9 100644 --- a/src/read.c +++ b/src/read.c @@ -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) */ /* diff --git a/src/sit.c b/src/sit.c index be76665de..0770340c1 100644 --- 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++; } diff --git a/src/teleport.c b/src/teleport.c index 8bded7405..503c96a1a 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -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; -- 2.40.0