mon interaction with terrain was postponed
Fix #576 Reported initially by @copperwater for polymorphed monsters: "observe how the [polymorphed-monster] hovers placidly above the water for several turns like Wile E. Coyote before it gets a move, realizes it's above water, and drowns. Ditto for lava." A comment in the GitHub issue thread by @Tomsod pointed out that a revived corpse could do the same. This should set things up for other terrain fallout if discovered or implemented in the future. - consume an additional bit in enum mon_terrain_effects (hack.h) - include the additional bit in TERRAIN_FALLOUT_MASK (monst.h) - add detection to maybe_set_terrain_effects (mon.c) - add action to terrain_effects (mon.c) Implemented by stealing some upper unused mstate bits to avoid invalidating existing save and bones.
This commit is contained in:
@@ -85,6 +85,8 @@ don't refer to pet as "Your pet" until after the taming process has finished
|
||||
checkpoint fixes (pr #1660 by k21971)
|
||||
upon return to a level, catch up on remaining nutrition value by the same
|
||||
percentage as the catch up for the weight
|
||||
after polymorph or revival from corpse, monsters were not interacting with
|
||||
the terrain until that monster's next move
|
||||
|
||||
|
||||
Platform- and/or Interface-Specific Fixes
|
||||
|
||||
@@ -786,6 +786,9 @@ struct instance_globals_p {
|
||||
unsigned pline_flags;
|
||||
char prevmsg[BUFSZ];
|
||||
|
||||
/* mon.c */
|
||||
enum mon_terrain_effects pending_terrain_effects;
|
||||
|
||||
/* potion.c */
|
||||
int potion_nothing;
|
||||
int potion_unkn;
|
||||
|
||||
@@ -1869,6 +1869,9 @@ extern void see_monster_closeup(struct monst *, boolean) NONNULLARG1;
|
||||
extern void see_nearby_monsters(void);
|
||||
extern void shieldeff_mon(struct monst *) NONNULLARG1;
|
||||
extern void flash_mon(struct monst *) NONNULLARG1;
|
||||
extern boolean maybe_set_terrain_effects(struct monst *,
|
||||
struct permonst *) NONNULLARG1;
|
||||
extern void terrain_effects(void);
|
||||
|
||||
/* ### mondata.c ### */
|
||||
|
||||
|
||||
@@ -725,6 +725,14 @@ struct plinemsg_type {
|
||||
/* bitmask for callers of hide_unhide_msgtypes() */
|
||||
#define MSGTYP_MASK_REP_SHOW ((1 << MSGTYP_NOREP) | (1 << MSGTYP_NOSHOW))
|
||||
|
||||
enum mon_terrain_effects {
|
||||
no_terrain_effects = 0x00000000,
|
||||
/* these bit values must be beyond the MON_ ranges in monst.h
|
||||
since they get set on mon->mstate */
|
||||
nonflyer_vs_liquid = 0x10000000,
|
||||
candrown_vs_liquid = 0x20000000,
|
||||
};
|
||||
|
||||
/* polyself flags */
|
||||
enum polyself_flags {
|
||||
POLY_NOFLAGS = 0x00,
|
||||
|
||||
+17
-11
@@ -55,17 +55,23 @@ enum m_ap_types {
|
||||
M_AP_MONSTER = 3 /* a monster; mostly used for cloned Wizard */
|
||||
};
|
||||
|
||||
#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 MON_FLOOR 0x00000000
|
||||
#define MON_OFFMAP 0x00000001
|
||||
#define MON_DETACH 0x00000002
|
||||
#define MON_MIGRATING 0x00000004
|
||||
#define MON_LIMBO 0x00000008
|
||||
#define MON_BUBBLEMOVE 0x00000010
|
||||
#define MON_ENDGAME_FREE 0x00000020
|
||||
#define MON_ENDGAME_MIGR 0x00000040
|
||||
#define MON_OBLITERATE 0x00000080
|
||||
#define MON_STILL_ARRIVING 0x00000100
|
||||
#define MON_PARKED 0x00000200
|
||||
/* 0x10000000 through 0x40000000 match enum pending_terrain_effects */
|
||||
/* 0x10000000 */ /* nonflyer_vs_liquid */
|
||||
/* 0x20000000 */ /* candrown_vs_liquid */
|
||||
/* 0x40000000 */
|
||||
#define TERRAIN_FALLOUT_MASK 0x70000000
|
||||
|
||||
|
||||
#define M_AP_TYPMASK 0x7
|
||||
#define M_AP_F_DKNOWN 0x8
|
||||
|
||||
@@ -204,6 +204,11 @@ moveloop_core(void)
|
||||
encumber_msg();
|
||||
|
||||
svc.context.mon_moving = TRUE;
|
||||
/* call terrain_effects during mon_moving phase */
|
||||
if (gp.pending_terrain_effects) {
|
||||
terrain_effects();
|
||||
gp.pending_terrain_effects = no_terrain_effects;
|
||||
}
|
||||
do {
|
||||
monscanmove = movemon();
|
||||
if (u.umovement >= NORMAL_SPEED)
|
||||
|
||||
@@ -637,6 +637,8 @@ static const struct instance_globals_p g_init_p = {
|
||||
/* pline.c */
|
||||
0U, /* pline_flags */
|
||||
UNDEFINED_VALUES, /* prevmsg */
|
||||
/* mon.c */
|
||||
no_terrain_effects, /* pending_terrain_effects */
|
||||
/* potion.c */
|
||||
UNDEFINED_VALUE, /* potion_nothing */
|
||||
UNDEFINED_VALUE, /* potion_unkn */
|
||||
|
||||
@@ -2185,6 +2185,7 @@ revive_corpse(struct obj *corpse)
|
||||
pline("%s disappears%s!", The(cname), effect);
|
||||
}
|
||||
}
|
||||
(void) maybe_set_terrain_effects(mtmp, 0);
|
||||
break;
|
||||
|
||||
case OBJ_MINVENT: /* probably a nymph's */
|
||||
|
||||
@@ -427,6 +427,7 @@ mon_arrive(struct monst *mtmp, int when)
|
||||
stairway *stway;
|
||||
d_level fromdlev;
|
||||
|
||||
mtmp->mstate &= ~TERRAIN_FALLOUT_MASK; /* shouldn't be set anyway */
|
||||
mtmp->mstate |= MON_STILL_ARRIVING;
|
||||
mtmp->nmon = fmon;
|
||||
fmon = mtmp;
|
||||
@@ -905,6 +906,7 @@ migrate_to_level(
|
||||
/* prepare to take mtmp off the map */
|
||||
num_segs = mon_leave(mtmp);
|
||||
/* take off map and move mtmp from fmon list to migrating_mons */
|
||||
mtmp->mstate &= ~TERRAIN_FALLOUT_MASK;
|
||||
relmon(mtmp, &gm.migrating_mons); /* mtmp->mx,my retain their value */
|
||||
mtmp->mstate |= MON_MIGRATING;
|
||||
|
||||
|
||||
@@ -2790,9 +2790,9 @@ m_detach(
|
||||
shkgone(mtmp);
|
||||
if (mtmp->wormno)
|
||||
wormgone(mtmp);
|
||||
mtmp->mstate &= ~TERRAIN_FALLOUT_MASK;
|
||||
if (In_endgame(&u.uz))
|
||||
mtmp->mstate |= MON_ENDGAME_FREE;
|
||||
|
||||
if ((mtmp->mstate & MON_DETACH) != 0) {
|
||||
impossible("m_detach: %s is already detached?",
|
||||
minimal_monnam(mtmp, FALSE));
|
||||
@@ -3936,6 +3936,7 @@ elemental_clog(struct monst *mon)
|
||||
if (mtmp) {
|
||||
int mx = mtmp->mx, my = mtmp->my;
|
||||
|
||||
mtmp->mstate &= ~TERRAIN_FALLOUT_MASK;
|
||||
mtmp->mstate |= MON_OBLITERATE;
|
||||
mongone(mtmp);
|
||||
/* places in the code might still reference mtmp->mx, mtmp->my */
|
||||
@@ -4055,6 +4056,7 @@ mnearto(
|
||||
but for the moment it is leaving */
|
||||
mon_leaving_level(othermon);
|
||||
othermon->mx = othermon->my = 0; /* 'othermon' is not on the map */
|
||||
othermon->mstate &= ~TERRAIN_FALLOUT_MASK;
|
||||
othermon->mstate |= MON_OFFMAP;
|
||||
}
|
||||
|
||||
@@ -5493,6 +5495,7 @@ newcham(
|
||||
if (!(mtmp->misc_worn_check & W_ARMG))
|
||||
mselftouch(mtmp, "No longer petrify-resistant, ",
|
||||
!svc.context.mon_moving);
|
||||
(void) maybe_set_terrain_effects(mtmp, olddata);
|
||||
check_gear_next_turn(mtmp);
|
||||
|
||||
/* This ought to re-test can_carry() on each item in the inventory
|
||||
@@ -5541,6 +5544,64 @@ newcham(
|
||||
return 1;
|
||||
}
|
||||
|
||||
boolean
|
||||
maybe_set_terrain_effects(struct monst *mtmp, struct permonst *oldmdat)
|
||||
{
|
||||
struct permonst *mdat = mtmp->data;
|
||||
boolean changed = FALSE;
|
||||
|
||||
/* mtmp is in liquid */
|
||||
if (is_pool(mtmp->mx, mtmp->my) || Is_waterlevel(&u.uz)
|
||||
|| is_lava(mtmp->mx, mtmp->my)
|
||||
|| IS_FOUNTAIN(levl[mtmp->mx][mtmp->my].typ)) {
|
||||
|
||||
/* mtmp is a non-flyer/floater/levitator */
|
||||
if (!is_flyer(mdat)) {
|
||||
changed = (!oldmdat ||
|
||||
(((is_flyer(oldmdat) != is_flyer(mdat))
|
||||
|| (is_floater(oldmdat) != is_floater(mdat)))
|
||||
&& !(mtmp == u.usteed && (Flying || Levitation))));
|
||||
gp.pending_terrain_effects |= nonflyer_vs_liquid;
|
||||
mtmp->mstate |= (long) nonflyer_vs_liquid;
|
||||
}
|
||||
|
||||
/* swimmer/amphibious/breathless to something that is not */
|
||||
if (!cant_drown(mdat)) {
|
||||
changed = (!oldmdat || ((cant_drown(oldmdat) != cant_drown(mdat))));
|
||||
gp.pending_terrain_effects |= candrown_vs_liquid;
|
||||
mtmp->mstate |= (long) candrown_vs_liquid;
|
||||
}
|
||||
}
|
||||
/* TODO: handle other terrains that could be harmful to a
|
||||
revived mon or polymorphed mon */
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/*
|
||||
* The terrain is what it is, but the monster changed
|
||||
* in some way (polymorphed or newly revived), and has
|
||||
* been flagged as problematic with the terrain.
|
||||
*/
|
||||
void
|
||||
terrain_effects(void)
|
||||
{
|
||||
struct monst *mtmp, *mtmp2;
|
||||
|
||||
for (mtmp = fmon; mtmp; mtmp = mtmp2) {
|
||||
mtmp2 = mtmp->nmon;
|
||||
if ((mtmp->mstate & TERRAIN_FALLOUT_MASK) != 0) {
|
||||
/* nonflyer_vs_liquid */
|
||||
if (!DEADMONSTER(mtmp)
|
||||
&& ((mtmp->mstate & (long) (nonflyer_vs_liquid | candrown_vs_liquid)) != 0))
|
||||
(void) minliquid(mtmp);
|
||||
|
||||
/* always clear these bits, even if DEADMONSTER */
|
||||
mtmp->mstate &= ~TERRAIN_FALLOUT_MASK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* sometimes an egg will be special */
|
||||
#define BREEDER_EGG (!rn2(77))
|
||||
|
||||
|
||||
+6
-3
@@ -450,10 +450,11 @@ restmonchn(NHFILE *nhfp)
|
||||
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)
|
||||
if (!mtmp->mx && (mtmp->mstate & MON_PARKED) == 0L
|
||||
&& (mtmp->mstate & MON_MIGRATING) == 0L) {
|
||||
mtmp->mstate &= ~TERRAIN_FALLOUT_MASK;
|
||||
mtmp->mstate |= MON_PARKED;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ghostly) {
|
||||
@@ -1210,6 +1211,8 @@ getlev(NHFILE *nhfp, int pid, xint8 lev)
|
||||
for (y = 0; y < ROWNO; y++)
|
||||
svl.level.monsters[x][y] = (struct monst *) 0;
|
||||
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
|
||||
if ((mtmp->mstate & TERRAIN_FALLOUT_MASK) != 0)
|
||||
gp.pending_terrain_effects |= (mtmp->mstate & TERRAIN_FALLOUT_MASK);
|
||||
if (mtmp->isshk)
|
||||
set_residency(mtmp, FALSE);
|
||||
/* set some monst fields to sane values when coming from a bones file */
|
||||
|
||||
@@ -164,6 +164,7 @@ parkguard(struct monst *grd)
|
||||
newsym(grd->mx, grd->my);
|
||||
}
|
||||
if (m_at(0, 0) != grd) {
|
||||
grd->mstate &= ~TERRAIN_FALLOUT_MASK;
|
||||
grd->mstate |= MON_PARKED;
|
||||
place_monster(grd, 0, 0);
|
||||
}
|
||||
|
||||
+2
-1
@@ -97,7 +97,8 @@ makemap_unmakemon(struct monst *mtmp, boolean migratory)
|
||||
monsters won't get out of sync; it is not on the map but
|
||||
mongone() -> m_detach() -> mon_leaving_level() copes with that */
|
||||
mtmp->mstate |= MON_OFFMAP;
|
||||
mtmp->mstate &= ~(MON_MIGRATING | MON_LIMBO | MON_ENDGAME_MIGR);
|
||||
mtmp->mstate &= ~(MON_MIGRATING | MON_LIMBO | MON_ENDGAME_MIGR
|
||||
| TERRAIN_FALLOUT_MASK);
|
||||
/* FIXME: will post-5.0.0 MON_PARKED need to be dealt with here? */
|
||||
mtmp->nmon = fmon;
|
||||
fmon = mtmp;
|
||||
|
||||
Reference in New Issue
Block a user