diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 2ad652f36..c83806f8d 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -205,6 +205,17 @@ successfully paying for shop damage with shop credit would be followed by if a migrating monster was killed off because there was no room on the destination level, it would leave a corpse even if it was a type which should never leave one (demon, golem, blob, &c) +monsters accompanying hero during level change (usually pets) who failed to + arrive and tried to re-migrate were being removed from the map after + already having been removed [impossible "no monster to remove" if + compiled with EXTRA_SANITY_CHECKS enabled] during migration handling +monsters accompanying hero during level change (usually pets) who failed to + arrive and tried to re-migrate (for hero's next visit to the level) + ended up being killed because the migration attempt happened right + away (same visit by hero, so level still full) and they weren't + accompanying hero on the second attempt +fix for above (all failed arrivals will re-migrate) makes the earlier fix (for + invalid corpse being left by monst killed upon migration failure) moot end of game while carrying Schroedinger's Box would reveal cat-or-corpse for inventory disclosure or put that info into dumplog, but not both attempting to untrap an adjacent trap while on the edge of--not in--a pit diff --git a/include/rm.h b/include/rm.h index b6cf36d54..080677e15 100644 --- a/include/rm.h +++ b/include/rm.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 rm.h $NHDT-Date: 1432512776 2015/05/25 00:12:56 $ $NHDT-Branch: master $:$NHDT-Revision: 1.41 $ */ +/* NetHack 3.6 rm.h $NHDT-Date: 1543052680 2018/11/24 09:44:40 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.59 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2017. */ /* NetHack may be freely redistributed. See license for details. */ @@ -631,13 +631,17 @@ extern dlevel_t level; /* structure describing the current level */ (level.monsters[x][y] != (struct monst *) 0 \ && (level.monsters[x][y])->mburied) #ifdef EXTRA_SANITY_CHECKS -#define place_worm_seg(m, x, y) do { \ - if (level.monsters[x][y] && level.monsters[x][y] != m) impossible("place_worm_seg over mon"); \ - level.monsters[x][y] = m; \ +#define place_worm_seg(m, x, y) \ + do { \ + if (level.monsters[x][y] && level.monsters[x][y] != m) \ + impossible("place_worm_seg over mon"); \ + level.monsters[x][y] = m; \ } while(0) -#define remove_monster(x, y) do { \ - if (!level.monsters[x][y]) impossible("no monster to remove"); \ - level.monsters[x][y] = (struct monst *) 0; \ +#define remove_monster(x, y) \ + do { \ + if (!level.monsters[x][y]) \ + impossible("no monster to remove"); \ + level.monsters[x][y] = (struct monst *) 0; \ } while(0) #else #define place_worm_seg(m, x, y) level.monsters[x][y] = m diff --git a/src/do.c b/src/do.c index 4bb739254..4817d150a 100644 --- a/src/do.c +++ b/src/do.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do.c $NHDT-Date: 1542765356 2018/11/21 01:55:56 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.174 $ */ +/* NetHack 3.6 do.c $NHDT-Date: 1543052696 2018/11/24 09:44:56 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.175 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1446,10 +1446,9 @@ boolean at_stairs, falling, portal; with the situation, so only say something when debugging */ if (wizard) pline("(monster in hero's way)"); - if (!rloc(mtmp, TRUE) || m_at(u.ux, u.uy)) + if (!rloc(mtmp, TRUE) || (mtmp = m_at(u.ux, u.uy)) != 0) /* no room to move it; send it away, to return later */ - migrate_to_level(mtmp, ledger_no(&u.uz), MIGR_RANDOM, - (coord *) 0); + m_into_limbo(mtmp); } } diff --git a/src/dog.c b/src/dog.c index 0d967195e..93a33716e 100644 --- a/src/dog.c +++ b/src/dog.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dog.c $NHDT-Date: 1502753406 2017/08/14 23:30:06 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.60 $ */ +/* NetHack 3.6 dog.c $NHDT-Date: 1543052701 2018/11/24 09:45:01 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.84 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -224,7 +224,7 @@ update_mlstmv() void losedogs() { - register struct monst *mtmp, *mtmp0 = 0, *mtmp2; + register struct monst *mtmp, *mtmp0, *mtmp2; int dismissKops = 0; /* @@ -279,17 +279,26 @@ losedogs() mon_arrive(mtmp, TRUE); } - /* time for migrating monsters to arrive */ + /* time for migrating monsters to arrive; + monsters who belong on this level but fail to arrive get put + back onto the list (at head), so traversing it is tricky */ for (mtmp = migrating_mons; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; if (mtmp->mux == u.uz.dnum && mtmp->muy == u.uz.dlevel) { - if (mtmp == migrating_mons) + /* remove mtmp from migrating_mons list */ + if (mtmp == migrating_mons) { migrating_mons = mtmp->nmon; - else - mtmp0->nmon = mtmp->nmon; + } else { + for (mtmp0 = migrating_mons; mtmp0; mtmp0 = mtmp0->nmon) + if (mtmp0->nmon == mtmp) { + mtmp0->nmon = mtmp->nmon; + break; + } + if (!mtmp0) + panic("losedogs: can't find migrating mon"); + } mon_arrive(mtmp, FALSE); - } else - mtmp0 = mtmp; + } } } @@ -300,9 +309,9 @@ struct monst *mtmp; boolean with_you; { struct trap *t; - struct obj *obj; xchar xlocale, ylocale, xyloc, xyflags, wander; int num_segs; + boolean failed_to_place = FALSE; mtmp->nmon = fmon; fmon = mtmp; @@ -328,7 +337,7 @@ boolean with_you; xyflags = mtmp->mtrack[0].y; xlocale = mtmp->mtrack[1].x; ylocale = mtmp->mtrack[1].y; - memset(mtmp->mtrack, 0, sizeof(mtmp->mtrack)); + memset(mtmp->mtrack, 0, sizeof mtmp->mtrack); if (mtmp == u.usteed) return; /* don't place steed on the map */ @@ -447,47 +456,13 @@ boolean with_you; mtmp->mx = 0; /*(already is 0)*/ mtmp->my = xyflags; - if (xlocale) { - if (!mnearto(mtmp, xlocale, ylocale, FALSE)) - goto fail_mon_placement; - } 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. - * - * TODO? Put back on migrating_mons list instead so - * that if hero leaves this level and then returns, - * monster will have another chance to arrive. - */ -fail_mon_placement: - 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 if (rloco(obj)) { - if (!get_obj_location(obj, &xlocale, &ylocale, 0)) - impossible("Can't find relocated object."); - } - } - /* - * TODO? Maybe switch to make_corpse() [won't be needed if - * we re-migrate as suggested above], probably with new - * CORPSTAT_NOOBJS flag to suppress dragon scales and such. - */ - if (!(mvitals[monsndx(mtmp->data)].mvflags & G_NOCORPSE) - && !LEVEL_SPECIFIC_NOCORPSE(mtmp->data)) - (void) mkcorpstat(CORPSE, mtmp, mtmp->data, - xlocale, ylocale, CORPSTAT_NONE); - mtmp->mx = mtmp->my = 0; /* for mongone, mon is not anywhere */ - mongone(mtmp); - } - } + if (xlocale) + failed_to_place = !mnearto(mtmp, xlocale, ylocale, FALSE); + else + failed_to_place = !rloc(mtmp, TRUE); + + if (failed_to_place) + m_into_limbo(mtmp); /* try again next time hero comes to this level */ } /* heal monster for time spent elsewhere */ @@ -708,7 +683,7 @@ xchar tolev; /* destination level */ xchar xyloc; /* MIGR_xxx destination xy location: */ coord *cc; /* optional destination coordinates */ { - register struct obj *obj; + struct obj *obj; d_level new_lev; xchar xyflags; int num_segs = 0; /* count of worm segments */ @@ -717,12 +692,12 @@ coord *cc; /* optional destination coordinates */ set_residency(mtmp, TRUE); if (mtmp->wormno) { - register int cnt; + int cnt = count_wsegs(mtmp); + /* **** NOTE: worm is truncated to # segs = max wormno size **** */ - cnt = count_wsegs(mtmp); - num_segs = min(cnt, MAX_NUM_WORMS - 1); - wormgone(mtmp); - place_monster(mtmp, mtmp->mx, mtmp->my); + num_segs = min(cnt, MAX_NUM_WORMS - 1); /* used below */ + wormgone(mtmp); /* destroys tail and takes head off map */ + place_monster(mtmp, mtmp->mx, mtmp->my); /* put head back for relmon */ } /* set minvent's obj->no_charge to 0 */ @@ -755,7 +730,7 @@ coord *cc; /* optional destination coordinates */ mtmp->muy = new_lev.dlevel; mtmp->mx = mtmp->my = 0; /* this implies migration */ if (mtmp == context.polearm.hitmon) - context.polearm.hitmon = NULL; + context.polearm.hitmon = (struct monst *) 0; } /* return quality of food; the lower the better */ diff --git a/src/mon.c b/src/mon.c index 043b22e89..03cd1eb9c 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mon.c $NHDT-Date: 1539479657 2018/10/14 01:14:17 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.260 $ */ +/* NetHack 3.6 mon.c $NHDT-Date: 1543052701 2018/11/24 09:45:01 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.270 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1618,8 +1618,9 @@ struct monst *mon; struct monst **monst_list; /* &migrating_mons or &mydogs or null */ { struct monst *mtmp; - boolean unhide = (monst_list != 0); int mx = mon->mx, my = mon->my; + boolean on_map = (m_at(mx, my) == mon), + unhide = (monst_list != 0); if (!fmon) panic("relmon: no fmon available."); @@ -1633,10 +1634,12 @@ struct monst **monst_list; /* &migrating_mons or &mydogs or null */ seemimic(mon); } - if (mon->wormno) - remove_worm(mon); - else - remove_monster(mx, my); + if (on_map) { + if (mon->wormno) + remove_worm(mon); + else + remove_monster(mx, my); + } if (mon == fmon) { fmon = fmon->nmon; @@ -1652,7 +1655,8 @@ struct monst **monst_list; /* &migrating_mons or &mydogs or null */ } if (unhide) { - newsym(mx, my); + if (on_map) + newsym(mx, my); /* insert into mydogs or migrating_mons */ mon->nmon = *monst_list; *monst_list = mon; @@ -2515,7 +2519,7 @@ struct monst *mtmp; { unstuck(mtmp); mdrop_special_objs(mtmp); - migrate_to_level(mtmp, ledger_no(&u.uz), MIGR_APPROX_XY, NULL); + migrate_to_level(mtmp, ledger_no(&u.uz), MIGR_APPROX_XY, (coord *) 0); } /* make monster mtmp next to you (if possible);