fix #K3802 - sanity_check: boulder not on top
This should fix the problem of polymorphing or stone-to-fleshing a pile of multiple boulders and having some underneath ones which get changed resist and not get changed, producing a pile with one or more non-boulders above one or more boulders. If that situation arises, re-stack the pile so that boulders are moved to the top. This also revises zapping up or down while hiding under something (if that is even possible; the types of creatures which can hide under things can't zap wands or cast spells; maybe there are some exceptions?). Zapping up used to hit only the top item, but zapping down hit the whole stack. Now up still hits only the top, but down skips the top and hits the rest. Caveat: not adquately tested.
This commit is contained in:
@@ -1481,6 +1481,7 @@ extern void set_bknown(struct obj *, unsigned);
|
||||
extern boolean is_flammable(struct obj *);
|
||||
extern boolean is_rottable(struct obj *);
|
||||
extern void place_object(struct obj *, coordxy, coordxy);
|
||||
extern void recreate_pile_at(coordxy, coordxy);
|
||||
extern void remove_object(struct obj *);
|
||||
extern void discard_minvent(struct monst *, boolean);
|
||||
extern void obj_extract_self(struct obj *);
|
||||
|
||||
23
src/mkobj.c
23
src/mkobj.c
@@ -2159,6 +2159,29 @@ place_object(struct obj *otmp, coordxy x, coordxy y)
|
||||
obj_timer_checks(otmp, x, y, 0);
|
||||
}
|
||||
|
||||
/* tear down the object pile at <x,y> and create it again, so that any
|
||||
boulders which are present get forced to the top */
|
||||
void
|
||||
recreate_pile_at(coordxy x, coordxy y)
|
||||
{
|
||||
struct obj *otmp, *next_obj, *reversed = 0;
|
||||
|
||||
/* remove all objects at <x,y>, saving a reversed temporary list */
|
||||
for (otmp = gl.level.objects[x][y]; otmp; otmp = next_obj) {
|
||||
next_obj = otmp->nexthere;
|
||||
remove_object(otmp); /* obj_extract_self() for floor */
|
||||
otmp->nobj = reversed;
|
||||
reversed = otmp;
|
||||
}
|
||||
/* pile at <tx,ty> is now empty; create new one, re-reversing to restore
|
||||
original order; place_object() handles making boulders be on top */
|
||||
for (otmp = reversed; otmp; otmp = next_obj) {
|
||||
next_obj = otmp->nobj;
|
||||
otmp->nobj = 0; /* obj->where is OBJ_FREE */
|
||||
place_object(otmp, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
#define ROT_ICE_ADJUSTMENT 2 /* rotting on ice takes 2 times as long */
|
||||
|
||||
/* If ice was affecting any objects correct that now
|
||||
|
||||
58
src/zap.c
58
src/zap.c
@@ -1853,12 +1853,12 @@ poly_obj(struct obj *obj, int id)
|
||||
static int
|
||||
stone_to_flesh_obj(struct obj *obj)
|
||||
{
|
||||
int res = 1; /* affected object by default */
|
||||
struct permonst *ptr;
|
||||
struct monst *mon, *shkp;
|
||||
struct obj *item;
|
||||
coordxy oox, ooy;
|
||||
boolean smell = FALSE, golem_xform = FALSE;
|
||||
int res = 1; /* affected object by default */
|
||||
|
||||
if (objects[obj->otyp].oc_material != MINERAL
|
||||
&& objects[obj->otyp].oc_material != GEMSTONE)
|
||||
@@ -2263,16 +2263,26 @@ bhito(struct obj *obj, struct obj *otmp)
|
||||
/* returns nonzero if something was hit */
|
||||
int
|
||||
bhitpile(
|
||||
struct obj *obj, /* wand or fake spellbook for type of zap */
|
||||
struct obj *obj, /* wand or fake spellbook for type of zap */
|
||||
int (*fhito)(OBJ_P, OBJ_P), /* callback for each object being hit */
|
||||
coordxy tx, coordxy ty, /* target location */
|
||||
schar zz) /* direction for up/down zaps */
|
||||
coordxy tx, coordxy ty, /* target location */
|
||||
schar zz) /* direction for up/down zaps */
|
||||
{
|
||||
int hitanything = 0;
|
||||
register struct obj *otmp, *next_obj;
|
||||
boolean hidingunder, first;
|
||||
int prevotyp, hitanything = 0;
|
||||
|
||||
if (!gl.level.objects[tx][ty])
|
||||
return 0;
|
||||
|
||||
/* if hiding underneath an object and zapping up or down, the top item
|
||||
is either the only thing hit (up) or is skipped (down) */
|
||||
hidingunder = (zz != 0 && u.uundetected && hides_under(gy.youmonst.data));
|
||||
first = TRUE;
|
||||
|
||||
if (obj->otyp == SPE_FORCE_BOLT || obj->otyp == WAN_STRIKING) {
|
||||
struct trap *t = t_at(tx, ty);
|
||||
struct obj *topofpile = gl.level.objects[tx][ty];
|
||||
|
||||
/* We can't settle for the default calling sequence of
|
||||
bhito(otmp) -> break_statue(otmp) -> activate_statue_trap(ox,oy)
|
||||
@@ -2282,21 +2292,49 @@ bhitpile(
|
||||
if (t && t->ttyp == STATUE_TRAP
|
||||
&& activate_statue_trap(t, tx, ty, TRUE))
|
||||
learnwand(obj);
|
||||
/* assume zapping up or down while hiding under the top item can
|
||||
still activate the trap even if it's below (when zapping up)
|
||||
or above (when zapping down) */
|
||||
if (gl.level.objects[tx][ty] != topofpile)
|
||||
first = FALSE; /* top item was statue which activated */
|
||||
}
|
||||
|
||||
gp.poly_zapped = -1;
|
||||
for (otmp = gl.level.objects[tx][ty]; otmp; otmp = next_obj) {
|
||||
next_obj = otmp->nexthere;
|
||||
/* for zap downwards, don't hit object poly'd hero is hiding under */
|
||||
if (zz > 0 && u.uundetected && otmp == gl.level.objects[u.ux][u.uy]
|
||||
&& hides_under(gy.youmonst.data))
|
||||
continue;
|
||||
|
||||
if (hidingunder) {
|
||||
if (first) {
|
||||
first = FALSE; /* reset for next item */
|
||||
if (zz < 0) /* down when hiding-under skips first item */
|
||||
continue;
|
||||
} else {
|
||||
/* !first */
|
||||
if (zz > 0) /* up when hiding-under skips rest of pile */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
hitanything += (*fhito)(otmp, obj);
|
||||
}
|
||||
|
||||
if (gp.poly_zapped >= 0)
|
||||
create_polymon(gl.level.objects[tx][ty], gp.poly_zapped);
|
||||
|
||||
/* when boulders are present they're expected to be on top; with
|
||||
multiple boulders it's possible for some to have been changed into
|
||||
non-boulders (polymorph, stone-to-flesh) while ones beneath resist,
|
||||
so re-stack pile if there are any non-boulders above boulders */
|
||||
prevotyp = BOULDER;
|
||||
for (otmp = gl.level.objects[tx][ty]; otmp; otmp = otmp->nexthere) {
|
||||
if (otmp->otyp == BOULDER && prevotyp != BOULDER) {
|
||||
recreate_pile_at(tx, ty);
|
||||
break;
|
||||
}
|
||||
prevotyp = otmp->otyp;
|
||||
}
|
||||
|
||||
if (hidingunder) /* pile might have been destroyed or dispersed */
|
||||
maybe_unhide_at(tx, ty);
|
||||
|
||||
return hitanything;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user