diff --git a/include/monst.h b/include/monst.h index a94bf2bc7..3a9bf151a 100644 --- a/include/monst.h +++ b/include/monst.h @@ -55,16 +55,17 @@ enum m_ap_types { M_AP_MONSTER = 3 /* a monster; mostly used for cloned Wizard */ }; -#define MON_FLOOR 0x00 -#define MON_OFFMAP 0x01 -#define MON_DETACH 0x02 -#define MON_MIGRATING 0x04 -#define MON_LIMBO 0x08 -#define MON_BUBBLEMOVE 0x10 -#define MON_ENDGAME_FREE 0x20 -#define MON_ENDGAME_MIGR 0x40 -#define MON_OBLITERATE 0x80 -#define MON_STILL_ARRIVING 0x100 +#define MON_FLOOR 0x0000 +#define MON_OFFMAP 0x0001 +#define MON_DETACH 0x0002 +#define MON_MIGRATING 0x0004 +#define MON_LIMBO 0x0008 +#define MON_BUBBLEMOVE 0x0010 +#define MON_ENDGAME_FREE 0x0020 +#define MON_ENDGAME_MIGR 0x0040 +#define MON_OBLITERATE 0x0080 +#define MON_STILL_ARRIVING 0x0100 +#define MON_PARKED 0x0200 #define M_AP_TYPMASK 0x7 #define M_AP_F_DKNOWN 0x8 @@ -212,6 +213,10 @@ struct monst { /* dead monsters stay on the fmon list until dmonsfree() at end of turn */ #define DEADMONSTER(mon) ((mon)->mhp < 1) +/* vault guards intentionally remain on the fmon list at 0,0 until + the temporary corridor is dealt with */ +#define PARKEDMONSTER(mon) ((mon)->isgd && (mon)->mx == 0) +/* eventually, we'll be able to use (((mon)->mstate & MON_PARKED) != 0) */ #define is_starting_pet(mon) ((mon)->m_id == svc.context.startingpet_mid) #define is_vampshifter(mon) \ diff --git a/src/detect.c b/src/detect.c index 11c370a05..ef9348001 100644 --- a/src/detect.c +++ b/src/detect.c @@ -345,7 +345,7 @@ gold_detect(struct obj *sobj) /* look for gold carried by monsters (might be in a container) */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp) || (mtmp->isgd && !mtmp->mx)) + if (DEADMONSTER(mtmp) || PARKEDMONSTER(mtmp)) continue; if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) { if (mtmp == u.usteed) { @@ -433,7 +433,7 @@ gold_detect(struct obj *sobj) ugold = TRUE; } for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp) || (mtmp->isgd && !mtmp->mx)) + if (DEADMONSTER(mtmp) || PARKEDMONSTER(mtmp)) continue; temp = 0; if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) { @@ -497,7 +497,7 @@ food_detect(struct obj *sobj) ct++; } for (mtmp = fmon; mtmp && (!ct || !ctu); mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp) || (mtmp->isgd && !mtmp->mx)) + if (DEADMONSTER(mtmp) || PARKEDMONSTER(mtmp)) continue; for (obj = mtmp->minvent; obj; obj = obj->nobj) if (o_in(obj, oclass)) { @@ -561,7 +561,7 @@ food_detect(struct obj *sobj) map_object(temp, 1); } for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp) || (mtmp->isgd && !mtmp->mx)) + if (DEADMONSTER(mtmp) || PARKEDMONSTER(mtmp)) continue; for (obj = mtmp->minvent; obj; obj = obj->nobj) if ((temp = o_in(obj, oclass)) != 0) { @@ -666,7 +666,7 @@ object_detect(struct obj *detector, /* object doing the detecting */ u.usteed->mx = u.ux, u.usteed->my = u.uy; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp) || (mtmp->isgd && !mtmp->mx)) + if (DEADMONSTER(mtmp) || PARKEDMONSTER(mtmp)) continue; for (obj = mtmp->minvent; obj; obj = obj->nobj) { if ((!class && !boulder) || o_in(obj, class) @@ -736,7 +736,7 @@ object_detect(struct obj *detector, /* object doing the detecting */ /* Objects in the monster's inventory override floor objects. */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp) || (mtmp->isgd && !mtmp->mx)) + if (DEADMONSTER(mtmp) || PARKEDMONSTER(mtmp)) continue; for (obj = mtmp->minvent; obj; obj = obj->nobj) if ((!class && !boulder) || (otmp = o_in(obj, class)) != 0 @@ -807,7 +807,7 @@ monster_detect(struct obj *otmp, /* detecting object (if any) */ * with positive hit-points to know for sure. */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp) || (mtmp->isgd && !mtmp->mx)) + if (DEADMONSTER(mtmp) || PARKEDMONSTER(mtmp)) continue; ++mcnt; break; /* no need for full count, just 1 or more vs 0 */ @@ -826,7 +826,7 @@ monster_detect(struct obj *otmp, /* detecting object (if any) */ cls(); unconstrained = unconstrain_map(); for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp) || (mtmp->isgd && !mtmp->mx)) + if (DEADMONSTER(mtmp) || PARKEDMONSTER(mtmp)) continue; if (!mclass || mtmp->data->mlet == mclass || (mtmp->data == &mons[PM_LONG_WORM] @@ -969,7 +969,7 @@ display_trap_map(int cursed_src) (void) detect_obj_traps(svl.level.buriedobjlist, TRUE, cursed_src, NULL); (void) detect_obj_traps(fobj, TRUE, cursed_src, NULL); for (mon = fmon; mon; mon = mon->nmon) { - if (DEADMONSTER(mon) || (mon->isgd && !mon->mx)) + if (DEADMONSTER(mon) || PARKEDMONSTER(mon)) continue; (void) detect_obj_traps(mon->minvent, TRUE, cursed_src, NULL); } @@ -1046,7 +1046,7 @@ trap_detect( found = TRUE; } for (mon = fmon; mon; mon = mon->nmon) { - if (DEADMONSTER(mon) || (mon->isgd && !mon->mx)) + if (DEADMONSTER(mon) || PARKEDMONSTER(mon)) continue; if ((tr = detect_obj_traps(mon->minvent, FALSE, 0, NULL)) != OTRAP_NONE) { @@ -1643,7 +1643,7 @@ findone(coordxy zx, coordxy zy, genericptr_t whatfound) struct monst *mtmp = m_at(zx, zy); struct found_things *found_p = (struct found_things *) whatfound; - if (mtmp && (DEADMONSTER(mtmp) || (mtmp->isgd && !mtmp->mx))) + if (mtmp && (DEADMONSTER(mtmp) || PARKEDMONSTER(mtmp))) mtmp = (struct monst *) NULL; found_p->ft_cc.x = zx; /* needed by detect_obj_traps() */ found_p->ft_cc.y = zy; diff --git a/src/display.c b/src/display.c index ffb9b2cbc..76daaa30b 100644 --- a/src/display.c +++ b/src/display.c @@ -1544,7 +1544,7 @@ see_monsters(void) /* loop through level.monsters (aka fmon) */ for (mon = fmon; mon; mon = mon->nmon) { - if (DEADMONSTER(mon)) + if (DEADMONSTER(mon) || PARKEDMONSTER(mon)) continue; if ((mon->mstate & MON_STILL_ARRIVING) != 0) continue; diff --git a/src/light.c b/src/light.c index fd41acd73..48f3671b1 100644 --- a/src/light.c +++ b/src/light.c @@ -303,7 +303,7 @@ show_transient_light(struct obj *obj, coordxy x, coordxy y) radius_squared = ls->range * ls->range; for (mon = fmon; mon; mon = mon->nmon) { - if (DEADMONSTER(mon) || (mon->isgd && !mon->mx)) + if (DEADMONSTER(mon) || PARKEDMONSTER(mon)) continue; /* light range is the radius of a circle and we're limiting canseemon() to a square enclosing that circle, but setting @@ -343,7 +343,7 @@ transient_light_cleanup(void) so need to be replaced by "remembered, unseen monster" glyph */ mtempcount = 0; for (mon = fmon; mon; mon = mon->nmon) { - if (DEADMONSTER(mon)) + if (DEADMONSTER(mon) || PARKEDMONSTER(mon)) continue; if (mon->mtemplit) { mon->mtemplit = 0; diff --git a/src/minion.c b/src/minion.c index b161f928d..03a782727 100644 --- a/src/minion.c +++ b/src/minion.c @@ -43,9 +43,7 @@ monster_census(boolean spotted) /* seen|sensed vs all */ int count = 0; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp)) - continue; - if (mtmp->isgd && mtmp->mx == 0) + if (DEADMONSTER(mtmp) || PARKEDMONSTER(mtmp)) continue; if (spotted && !canspotmon(mtmp)) continue; diff --git a/src/mon.c b/src/mon.c index a69a1aedf..3e86cb730 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1230,7 +1230,7 @@ movemon_singlemon(struct monst *mtmp) off the map too; gd_move() decides whether the temporary corridor can be removed and guard discarded (via clearing mon->isgd flag so that dmonsfree() will get rid of mon) */ - if (mtmp->isgd && !mtmp->mx && !(mtmp->mstate & MON_MIGRATING)) { + if (PARKEDMONSTER(mtmp) && !(mtmp->mstate & MON_MIGRATING)) { /* parked at <0,0>; eventually isgd should get set to false */ if (svm.moves > mtmp->mlstmv) { (void) gd_move(mtmp); diff --git a/src/monmove.c b/src/monmove.c index 340c2f628..10a97675a 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -922,7 +922,7 @@ dochug(struct monst *mtmp) /*FALLTHRU*/ case MMOVE_NOTHING: /* no movement, but it can still attack you */ case MMOVE_DONE: /* absolutely no movement */ - /* vault guard might have vanished */ + /* vault guard might have vanished; PARKEDMONSTER(mtmp) */ if (mtmp->isgd && (DEADMONSTER(mtmp) || mtmp->mx == 0)) return 1; /* behave as if it died */ /* During hallucination, monster appearance should diff --git a/src/restore.c b/src/restore.c index 0cc82f30f..2c9a01a75 100644 --- a/src/restore.c +++ b/src/restore.c @@ -448,6 +448,13 @@ restmonchn(NHFILE *nhfp) restshk(mtmp, ghostly); if (mtmp->ispriest) restpriest(mtmp, ghostly); + if (mtmp->isgd) { + /* fixup for new bit MON_PARKED added post 5.0.0 */ + if (!mtmp->mx + && (mtmp->mstate & MON_PARKED) == 0L + && (mtmp->mstate & MON_MIGRATING) == 0L) + mtmp->mstate |= MON_PARKED; + } if (!ghostly) { if (mtmp->m_id == svc.context.polearm.m_id) diff --git a/src/steed.c b/src/steed.c index a9c1ad7d0..536feec6f 100644 --- a/src/steed.c +++ b/src/steed.c @@ -903,8 +903,10 @@ place_monster(struct monst *mon, coordxy x, coordxy y) buf[0] = '\0'; /* normal map bounds are <1..COLNO-1,0..ROWNO-1> but sometimes - vault guards (either living or dead) are parked at <0,0> */ - if (!isok(x, y) && (x != 0 || y != 0 || !mon->isgd)) { + vault guards (either living or dead) are parked at <0,0>; + their mstate should have the MON_PARKED bit set (post-5.0.0) */ + if (!isok(x, y) + && !(((mon->mstate & MON_PARKED) != 0) || PARKEDMONSTER(mon))) { describe_level(buf, 0); impossible("trying to place %s at <%d,%d> mstate:%lx on %s", minimal_monnam(mon, TRUE), x, y, mon->mstate, buf); @@ -912,7 +914,7 @@ place_monster(struct monst *mon, coordxy x, coordxy y) } if ((mon == u.usteed && !gi.in_steed_dismounting) /* special case is for convoluted vault guard handling */ - || (DEADMONSTER(mon) && !(mon->isgd && x == 0 && y == 0))) { + || (DEADMONSTER(mon) && !PARKEDMONSTER(mon))) { describe_level(buf, 0); impossible("placing %s onto map, mstate:%lx, on %s?", (mon == u.usteed) ? "steed" : "defunct monster", @@ -928,7 +930,17 @@ place_monster(struct monst *mon, coordxy x, coordxy y) } mon->mx = x, mon->my = y; svl.level.monsters[x][y] = mon; - mon->mstate = MON_FLOOR; + /* even though MON_FLOOR is not actually a bit currently + (MON_FLOOR == 0) we want to preserve some of the other + bits that may be set. We'll probably make MON_FLOOR an + actual bit one day */ + + mon->mstate &= ~(MON_OFFMAP | MON_DETACH | MON_LIMBO | MON_MIGRATING); + + /* We don't mess with these bits above: + MON_BUBBLEMOVE | MON_ENDGAME_FREE | MON_ENDGAME_MIGR + | MON_OBLITERATE | MON_STILL_ARRIVING | MON_PARKED + */ } /*steed.c*/ diff --git a/src/vault.c b/src/vault.c index 32d9e84b0..94f50d909 100644 --- a/src/vault.c +++ b/src/vault.c @@ -146,6 +146,7 @@ restfakecorr(struct monst *grd) /* it seems you left the corridor - let the guard disappear */ if (clear_fcorr(grd, FALSE)) { grd->isgd = 0; /* dmonsfree() should delete this mon */ + grd->mstate &= ~MON_PARKED; mongone(grd); } } @@ -162,8 +163,10 @@ parkguard(struct monst *grd) remove_monster(grd->mx, grd->my); newsym(grd->mx, grd->my); } - if (m_at(0, 0) != grd) + if (m_at(0, 0) != grd) { + grd->mstate |= MON_PARKED; place_monster(grd, 0, 0); + } /* [grd->mx,my just got set to 0,0 by place_monster(), so this just sets EGD(grd)->ogx,ogy to 0,0 too; is that what we want?] */ EGD(grd)->ogx = grd->mx; diff --git a/src/wizcmds.c b/src/wizcmds.c index 60b991db9..e7fda43ea 100644 --- a/src/wizcmds.c +++ b/src/wizcmds.c @@ -98,6 +98,7 @@ makemap_unmakemon(struct monst *mtmp, boolean migratory) mongone() -> m_detach() -> mon_leaving_level() copes with that */ mtmp->mstate |= MON_OFFMAP; mtmp->mstate &= ~(MON_MIGRATING | MON_LIMBO | MON_ENDGAME_MIGR); + /* FIXME: will post-5.0.0 MON_PARKED need to be dealt with here? */ mtmp->nmon = fmon; fmon = mtmp; }