buglist - full level triggers impossible() from migrating mons

<email deleted> wrote:
> If more monsters fall through a trap door than can fit on the
> level below, when you go down the stairs, you get the following
> message:
>  "Program in disorder - perhaps you'd better #quit.
>  rloc(): couldn't relocate monster"
> This message seems to appear once for every monster-too-many that
> fell through the hole. I originally found this while
> intentionally completely filling a level with black puddings
> (there was a trap door I didn't know about). I also confirmed it
> in a wiz-mode test using gremlins and water.

[confirmed: moveloop -> deferred_goto -> goto_level ->
 losedogs -> mon_arrive -> rloc -> impossible]

This patch:
- causes rloc() to return TRUE if successful,
  or FALSE if it wasn't.
- adds code to mon_arrive() in dog.c to deal with
  the failed rloc()
- allows the x,y parameters to mkcorpstat() to
  be 0,0 in order to trigger random placement of the
  corpse on the level
- if you define DEBUG_MIGRATING_MONS when you build cmd.c
  then you'll have a debug-mode command #migratemons to
  store the number of random monsters that you specify
  on the migrating monsters chain.
This commit is contained in:
nethack.allison
2003-09-13 05:30:43 +00:00
parent 32b2af4abf
commit cc830fb311
24 changed files with 134 additions and 53 deletions

View File

@@ -711,7 +711,7 @@ struct obj *obj;
setnotworn(obj); /* in case mirror was wielded */
freeinv(obj);
(void) mpickobj(mtmp,obj);
if (!tele_restrict(mtmp)) rloc(mtmp);
if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
} else if (!is_unicorn(mtmp->data) && !humanoid(mtmp->data) &&
(!mtmp->minvis || perceives(mtmp->data)) && rn2(5)) {
if (vis)

View File

@@ -126,6 +126,9 @@ STATIC_PTR int NDECL(wiz_show_wmodes);
#if defined(__BORLANDC__) && !defined(_WIN32)
extern void FDECL(show_borlandc_stats, (winid));
#endif
#ifdef DEBUG_MIGRATING_MONS
STATIC_PTR int NDECL(wiz_migrate_mons);
#endif
STATIC_DCL void FDECL(count_obj, (struct obj *, long *, long *, BOOLEAN_P, BOOLEAN_P));
STATIC_DCL void FDECL(obj_chain, (winid, const char *, struct obj *, long *, long *));
STATIC_DCL void FDECL(mon_invent_chain, (winid, const char *, struct monst *, long *, long *));
@@ -1492,6 +1495,9 @@ struct ext_func_tab extcmdlist[] = {
*/
{(char *)0, (char *)0, donull, TRUE},
{(char *)0, (char *)0, donull, TRUE},
#ifdef DEBUG_MIGRATING_MONS
{(char *)0, (char *)0, donull, TRUE},
#endif
{(char *)0, (char *)0, donull, TRUE},
{(char *)0, (char *)0, donull, TRUE},
{(char *)0, (char *)0, donull, TRUE},
@@ -1514,6 +1520,9 @@ struct ext_func_tab extcmdlist[] = {
static const struct ext_func_tab debug_extcmdlist[] = {
{"levelchange", "change experience level", wiz_level_change, TRUE},
{"lightsources", "show mobile light sources", wiz_light_sources, TRUE},
#ifdef DEBUG_MIGRATING_MONS
{"migratemons", "migrate n random monsters", wiz_migrate_mons, TRUE},
#endif
{"monpolycontrol", "control monster polymorphs", wiz_mon_polycontrol, TRUE},
{"panic", "test panic routine (fatal to game)", wiz_panic, TRUE},
{"polyself", "polymorph self", wiz_polyself, TRUE},
@@ -1742,6 +1751,35 @@ sanity_check()
timer_sanity_check();
}
#ifdef DEBUG_MIGRATING_MONS
static int
wiz_migrate_mons()
{
int mcount = 0;
char inbuf[BUFSZ];
struct permonst *ptr;
struct monst *mtmp;
d_level tolevel;
getlin("How many random monsters to migrate? [0]", inbuf);
if (*inbuf == '\033') return 0;
mcount = atoi(inbuf);
if (mcount < 0 || mcount > (COLNO * ROWNO) || Is_botlevel(&u.uz))
return 0;
while (mcount > 0) {
if (Is_stronghold(&u.uz))
assign_level(&tolevel, &valley_level);
else
get_level(&tolevel, depth(&u.uz) + 1);
ptr = rndmonst();
mtmp = makemon(ptr, 0, 0, NO_MM_FLAGS);
if (mtmp) migrate_to_level(mtmp, ledger_no(&tolevel),
MIGR_RANDOM, (coord *)0);
mcount--;
}
return 0;
}
#endif
#endif /* WIZARD */
#define unctrl(c) ((c) <= C('z') ? (0x60 | (c)) : (c))

View File

@@ -59,7 +59,7 @@ mkcavepos(x, y, dist, waslit, rockit)
if(IS_ROCK(lev->typ)) return;
if(t_at(x, y)) return; /* don't cover the portal */
if ((mtmp = m_at(x, y)) != 0) /* make sure crucial monsters survive */
if(!passes_walls(mtmp->data)) rloc(mtmp);
if(!passes_walls(mtmp->data)) (void) rloc(mtmp, FALSE);
} else if(lev->typ == ROOM) return;
unblock_point(x,y); /* make sure vision knows this location is open */

View File

@@ -1212,7 +1212,7 @@ boolean at_stairs, falling, portal;
if ((mtmp = m_at(u.ux, u.uy)) != 0) {
impossible("mnexto failed (do.c)?");
rloc(mtmp);
(void) rloc(mtmp, FALSE);
}
}

View File

@@ -356,8 +356,41 @@ boolean with_you;
mtmp->my = xyflags;
if (xlocale)
(void) mnearto(mtmp, xlocale, ylocale, FALSE);
else
rloc(mtmp);
else {
if (!rloc(mtmp,TRUE)) {
/*
* Failed to place migrating monster,
* probably because the level is full.
* Dump the monster's cargo and leave the monster dead.
*/
struct obj *obj, *corpse;
while ((obj = mtmp->minvent) != 0) {
obj_extract_self(obj);
obj_no_longer_held(obj);
if (obj->owornmask & W_WEP)
setmnotwielded(mtmp,obj);
obj->owornmask = 0L;
if (xlocale && ylocale)
place_object(obj, xlocale, ylocale);
else {
rloco(obj);
get_obj_location(obj, &xlocale, &ylocale, 0);
}
}
corpse = mkcorpstat(CORPSE, (struct monst *)0, mtmp->data,
xlocale, ylocale, FALSE);
#ifndef GOLDOBJ
if (mtmp->mgold) {
if (xlocale == 0 && ylocale == 0 && corpse) {
(void) get_obj_location(corpse, &xlocale, &ylocale, 0);
(void) mkgold(mtmp->mgold, xlocale, ylocale);
}
mtmp->mgold = 0L;
}
#endif
mongone(mtmp);
}
}
}
/* heal monster for time spent elsewhere */

View File

@@ -1470,7 +1470,7 @@ register struct obj *obj;
nopick:
if(!Blind) pline("%s", buf);
if (!tele_restrict(mon)) rloc(mon);
if (!tele_restrict(mon)) (void) rloc(mon, FALSE);
return(ret);
}

View File

@@ -839,7 +839,7 @@ mdamagem(magr, mdef, mattk)
we'll get "it" in the suddenly disappears message */
if (vis) Strcpy(mdef_Monnam, Monnam(mdef));
mdef->mstrategy &= ~STRAT_WAITFORU;
rloc(mdef);
(void) rloc(mdef, FALSE);
if (vis && !canspotmon(mdef)
#ifdef STEED
&& mdef != u.usteed
@@ -967,7 +967,7 @@ mdamagem(magr, mdef, mattk)
pline("%s steals some gold from %s.", buf, mon_nam(mdef));
}
if (!tele_restrict(magr)) {
rloc(magr);
(void) rloc(magr, FALSE);
if (vis && !canspotmon(magr))
pline("%s suddenly disappears!", buf);
}
@@ -1034,7 +1034,7 @@ mdamagem(magr, mdef, mattk)
0 : MM_AGR_DIED));
if (magr->data->mlet == S_NYMPH &&
!tele_restrict(magr)) {
rloc(magr);
(void) rloc(magr, FALSE);
if (vis && !canspotmon(magr))
pline("%s suddenly disappears!", buf);
}

View File

@@ -1232,7 +1232,7 @@ dopois:
pline("%s %s.", Monnam(mtmp), mtmp->minvent ?
"brags about the goods some dungeon explorer provided" :
"makes some remarks about how difficult theft is lately");
if (!tele_restrict(mtmp)) rloc(mtmp);
if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
return 3;
} else if (mtmp->mcan) {
if (!Blind) {
@@ -1242,7 +1242,7 @@ dopois:
flags.female ? "unaffected" : "uninterested");
}
if(rn2(3)) {
if (!tele_restrict(mtmp)) rloc(mtmp);
if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
return 3;
}
break;
@@ -1255,7 +1255,7 @@ dopois:
break;
default:
if (!is_animal(mtmp->data) && !tele_restrict(mtmp))
rloc(mtmp);
(void) rloc(mtmp, FALSE);
if (is_animal(mtmp->data) && *buf) {
if (canseemon(mtmp))
pline("%s tries to %s away with %s.",
@@ -1359,7 +1359,7 @@ dopois:
mongone(mtmp);
return 2;
} else if (!rn2(33)) {
if (!tele_restrict(mtmp)) rloc(mtmp);
if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
monflee(mtmp, d(3, 6), TRUE, FALSE);
return 3;
}
@@ -2219,7 +2219,7 @@ register struct monst *mon;
if (uarm || uarmc) {
verbalize("You're such a %s; I wish...",
flags.female ? "sweet lady" : "nice guy");
if (!tele_restrict(mon)) rloc(mon);
if (!tele_restrict(mon)) (void) rloc(mon, FALSE);
return 1;
}
if (u.ualign.type == A_CHAOTIC)
@@ -2351,7 +2351,7 @@ register struct monst *mon;
#endif
}
if (!rn2(25)) mon->mcan = 1; /* monster is worn out */
if (!tele_restrict(mon)) rloc(mon);
if (!tele_restrict(mon)) (void) rloc(mon, FALSE);
return 1;
}

View File

@@ -161,7 +161,7 @@ register struct monst *mtmp;
if (youmonst.data->mlet == S_DEMON) { /* Won't blackmail their own. */
pline("%s says, \"Good hunting, %s.\"",
Amonnam(mtmp), flags.female ? "Sister" : "Brother");
if (!tele_restrict(mtmp)) rloc(mtmp);
if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
return(1);
}
#ifndef GOLDOBJ

View File

@@ -308,7 +308,7 @@ d_level *lev;
/* "something" means the player in this case */
if(MON_AT(x, y)) {
/* move the monster if no choice, or just try again */
if(oneshot) rloc(m_at(x,y));
if(oneshot) (void) rloc(m_at(x,y), FALSE);
else return(FALSE);
}
u_on_newpos(x, y);

View File

@@ -894,7 +894,11 @@ boolean init;
if (objtype != CORPSE && objtype != STATUE)
impossible("making corpstat type %d", objtype);
otmp = mksobj_at(objtype, x, y, init, FALSE);
if (x == 0 && y == 0) { /* special case - random placement */
otmp = mksobj(objtype, init, FALSE);
if (otmp) rloco(otmp);
} else
otmp = mksobj_at(objtype, x, y, init, FALSE);
if (otmp) {
if (mtmp) {
struct obj *otmp2;

View File

@@ -428,7 +428,7 @@ register struct monst *mtmp;
if (mtmp->mhp > 0) {
(void) fire_damage(mtmp->minvent, FALSE, FALSE,
mtmp->mx, mtmp->my);
rloc(mtmp);
(void) rloc(mtmp, FALSE);
return 0;
}
return (1);
@@ -451,7 +451,7 @@ register struct monst *mtmp;
}
mondead(mtmp);
if (mtmp->mhp > 0) {
rloc(mtmp);
(void) rloc(mtmp, FALSE);
water_damage(mtmp->minvent, FALSE, FALSE);
return 0;
}

View File

@@ -327,7 +327,7 @@ register struct monst *mtmp;
/* some monsters teleport */
if (mtmp->mflee && !rn2(40) && can_teleport(mdat) && !mtmp->iswiz &&
!level.flags.noteleport) {
rloc(mtmp);
(void) rloc(mtmp, FALSE);
return(0);
}
if (mdat->msound == MS_SHRIEK && !um_dist(mtmp->mx, mtmp->my, 1))
@@ -370,7 +370,7 @@ register struct monst *mtmp;
if (is_demon(youmonst.data)) {
/* "Good hunting, brother" */
if (!tele_restrict(mtmp)) rloc(mtmp);
if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
} else {
mtmp->minvis = mtmp->perminvis = 0;
/* Why? For the same reason in real demon talk */
@@ -680,7 +680,7 @@ register int after;
if(ptr == &mons[PM_TENGU] && !rn2(5) && !mtmp->mcan &&
!tele_restrict(mtmp)) {
if(mtmp->mhp < 7 || mtmp->mpeaceful || rn2(2))
rloc(mtmp);
(void) rloc(mtmp, FALSE);
else
mnexto(mtmp);
mmoved = 1;
@@ -1014,7 +1014,7 @@ not_special:
if (mtmp->wormno) worm_move(mtmp);
} else {
if(is_unicorn(ptr) && rn2(2) && !tele_restrict(mtmp)) {
rloc(mtmp);
(void) rloc(mtmp, FALSE);
return(1);
}
if(mtmp->wormno) worm_nomove(mtmp);

View File

@@ -121,7 +121,7 @@ register boolean special;
return((struct monst *)0);
if(MON_AT(x, y))
rloc(m_at(x, y)); /* insurance */
(void) rloc(m_at(x, y), FALSE); /* insurance */
if(!In_endgame(&u.uz)) special = FALSE;

View File

@@ -592,7 +592,7 @@ mon_tele:
return 2;
}
if (oseen && how) makeknown(how);
rloc(mtmp);
(void) rloc(mtmp, FALSE);
return 2;
case MUSE_WAN_TELEPORTATION:
zap_oseen = oseen;
@@ -1148,7 +1148,7 @@ register struct obj *otmp;
mtmp->msleeping = 0;
if(mtmp->m_ap_type) seemimic(mtmp);
} else if (!tele_restrict(mtmp))
rloc(mtmp);
(void) rloc(mtmp, FALSE);
}
break;
case WAN_CANCELLATION:

View File

@@ -186,7 +186,7 @@ boolean sanctum; /* is it the seat of the high priest? */
int cnt;
if(MON_AT(sx+1, sy))
rloc(m_at(sx+1, sy)); /* insurance */
(void) rloc(m_at(sx+1, sy), FALSE); /* insurance */
priest = makemon(&mons[sanctum ? PM_HIGH_PRIEST : PM_ALIGNED_PRIEST],
sx + 1, sy, NO_MM_FLAGS);
@@ -532,7 +532,7 @@ boolean peaceful;
if (ptr != &mons[PM_ALIGNED_PRIEST] && ptr != &mons[PM_ANGEL])
return((struct monst *)0);
if (MON_AT(x, y)) rloc(m_at(x, y)); /* insurance */
if (MON_AT(x, y)) (void) rloc(m_at(x, y), FALSE); /* insurance */
if (!(roamer = makemon(ptr, x, y, NO_MM_FLAGS)))
return((struct monst *)0);

View File

@@ -389,7 +389,7 @@ struct mkroom *sroom;
return(-1);
}
if(MON_AT(sx, sy)) rloc(m_at(sx, sy)); /* insurance */
if(MON_AT(sx, sy)) (void) rloc(m_at(sx, sy), FALSE); /* insurance */
/* now initialize the shopkeeper monster structure */
if(!(shk = makemon(&mons[PM_SHOPKEEPER], sx, sy, NO_MM_FLAGS)))

View File

@@ -49,7 +49,7 @@ register struct monst *mtmp;
pline("%s quickly snatches some gold from between your %s!",
Monnam(mtmp), makeplural(body_part(FOOT)));
if(!u.ugold || !rn2(5)) {
if (!tele_restrict(mtmp)) rloc(mtmp);
if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
/* do not set mtmp->mavenge here; gold on the floor is fair game */
monflee(mtmp, 0, FALSE, FALSE);
}
@@ -57,7 +57,7 @@ register struct monst *mtmp;
u.ugold -= (tmp = somegold());
Your("purse feels lighter.");
mtmp->mgold += tmp;
if (!tele_restrict(mtmp)) rloc(mtmp);
if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
mtmp->mavenge = 1;
monflee(mtmp, 0, FALSE, FALSE);
flags.botl = 1;
@@ -118,7 +118,7 @@ register struct monst *mtmp;
pline("%s quickly snatches some gold from between your %s!",
Monnam(mtmp), makeplural(body_part(FOOT)));
if(!ygold || !rn2(5)) {
if (!tele_restrict(mtmp)) rloc(mtmp);
if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
monflee(mtmp, 0, FALSE, FALSE);
}
} else if(ygold) {
@@ -129,7 +129,7 @@ register struct monst *mtmp;
freeinv(ygold);
add_to_minv(mtmp, ygold);
Your("purse feels lighter.");
if (!tele_restrict(mtmp)) rloc(mtmp);
if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
monflee(mtmp, 0, FALSE, FALSE);
flags.botl = 1;
}
@@ -161,7 +161,7 @@ stealarm()
/* Implies seduction, "you gladly hand over ..."
so we don't set mavenge bit here. */
monflee(mtmp, 0, FALSE, FALSE);
if (!tele_restrict(mtmp)) rloc(mtmp);
if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
break;
}
}
@@ -499,7 +499,7 @@ struct monst *mtmp;
(void) mpickobj(mtmp,otmp); /* may merge and free otmp */
pline("%s stole %s!", Monnam(mtmp), doname(otmp));
if (can_teleport(mtmp->data) && !tele_restrict(mtmp))
rloc(mtmp);
(void) rloc(mtmp, FALSE);
}
}

View File

@@ -535,7 +535,7 @@ dismount_steed(reason)
if (enexto(&cc, u.ux, u.uy, mtmp->data))
rloc_to(mtmp, cc.x, cc.y);
else /* evidently no room nearby; move steed elsewhere */
rloc(mtmp);
(void) rloc(mtmp, FALSE);
return;
}
if (!DEADMONSTER(mtmp)) {

View File

@@ -953,16 +953,18 @@ register int x, y;
}
/* place a monster at a random location, typically due to teleport */
void
rloc(mtmp)
/* return TRUE if successful, FALSE if not */
boolean
rloc(mtmp, suppress_impossible)
struct monst *mtmp; /* mx==0 implies migrating monster arrival */
boolean suppress_impossible;
{
register int x, y, trycount;
#ifdef STEED
if (mtmp == u.usteed) {
tele();
return;
return TRUE;
}
#endif
@@ -996,11 +998,13 @@ struct monst *mtmp; /* mx==0 implies migrating monster arrival */
goto found_xy;
/* level either full of monsters or somehow faulty */
impossible("rloc(): couldn't relocate monster");
return;
if (!suppress_impossible)
impossible("rloc(): couldn't relocate monster");
return FALSE;
found_xy:
rloc_to(mtmp, x, y);
return TRUE;
}
STATIC_OVL void
@@ -1015,7 +1019,7 @@ struct monst *mtmp;
rloc_to(mtmp, c.x, c.y);
return;
}
rloc(mtmp);
(void) rloc(mtmp, FALSE);
}
boolean
@@ -1049,7 +1053,7 @@ int in_sight;
* the guard isn't going to come for it...
*/
if (trap->once) mvault_tele(mtmp);
else rloc(mtmp);
else (void) rloc(mtmp, FALSE);
if (in_sight) {
if (canseemon(mtmp))
@@ -1253,12 +1257,12 @@ boolean give_feedback;
if (give_feedback)
You("are no longer inside %s!", mon_nam(mtmp));
unstuck(mtmp);
rloc(mtmp);
(void) rloc(mtmp, FALSE);
} else if (is_rider(mtmp->data) && rn2(13) &&
enexto(&cc, u.ux, u.uy, mtmp->data))
rloc_to(mtmp, cc.x, cc.y);
else
rloc(mtmp);
(void) rloc(mtmp, FALSE);
return TRUE;
}

View File

@@ -42,7 +42,7 @@ register boolean forceshow;
if(mtmp->isgd) return(FALSE);
else if(!in_fcorridor(grd, u.ux, u.uy)) {
if(mtmp->mtame) yelp(mtmp);
rloc(mtmp);
(void) rloc(mtmp, FALSE);
}
}
levl[fcx][fcy].typ = EGD(grd)->fakecorr[fcbeg].ftyp;
@@ -380,7 +380,7 @@ struct monst *grd;
if (!IS_WALL(levl[x][y].typ) && !in_fcorridor(grd, x, y)) {
if ((mon = m_at(x, y)) != 0 && mon != grd) {
if (mon->mtame) yelp(mon);
rloc(mon);
(void) rloc(mon, FALSE);
}
if ((gold = g_at(x, y)) != 0) {
move_gold(gold, EGD(grd)->vroom);
@@ -461,7 +461,7 @@ register struct monst *grd;
(grd_in_vault ||
(in_fcorridor(grd, grd->mx, grd->my) &&
!in_fcorridor(grd, u.ux, u.uy)))) {
rloc(grd);
(void) rloc(grd, FALSE);
wallify_vault(grd);
(void) clear_fcorr(grd, TRUE);
goto letknow;
@@ -507,7 +507,7 @@ register struct monst *grd;
if (u_carry_gold) { /* player teleported */
m = grd->mx;
n = grd->my;
rloc(grd);
(void) rloc(grd, FALSE);
levl[m][n].typ = egrd->fakecorr[0].ftyp;
newsym(m,n);
grd->mpeaceful = 0;
@@ -583,7 +583,7 @@ letknow:
/* just for insurance... */
if (MON_AT(m, n) && m != grd->mx && n != grd->my) {
verbalize("Out of my way, scum!");
rloc(m_at(m, n));
(void) rloc(m_at(m, n), FALSE);
}
remove_monster(grd->mx, grd->my);
newsym(grd->mx, grd->my);

View File

@@ -303,7 +303,7 @@ tactics(mtmp)
mtmp->mavenge = 1; /* covetous monsters attack while fleeing */
if (In_W_tower(mtmp->mx, mtmp->my, &u.uz) ||
(mtmp->iswiz && !xupstair && !mon_has_amulet(mtmp))) {
if (!rn2(3 + mtmp->mhp/10)) rloc(mtmp);
if (!rn2(3 + mtmp->mhp/10)) (void) rloc(mtmp, FALSE);
} else if (xupstair &&
(mtmp->mx != xupstair || mtmp->my != yupstair)) {
(void) mnearto(mtmp, xupstair, yupstair, TRUE);