split 'postmov' of m_move() into separate function
This commit is contained in:
722
src/monmove.c
722
src/monmove.c
@@ -18,6 +18,8 @@ static int count_webbing_walls(coordxy, coordxy);
|
||||
static boolean soko_allow_web(struct monst *);
|
||||
static boolean m_search_items(struct monst *, coordxy *, coordxy *, schar *,
|
||||
int *);
|
||||
static int postmov(struct monst *, struct permonst *, int, int, schar, boolean,
|
||||
boolean, boolean, boolean);
|
||||
static boolean leppie_avoidance(struct monst *);
|
||||
static void leppie_stash(struct monst *);
|
||||
static boolean m_balks_at_approaching(struct monst *);
|
||||
@@ -1283,358 +1285,21 @@ finish_search:
|
||||
|
||||
#undef SQSRCHRADIUS
|
||||
|
||||
/* Handles the movement of a standard monster. */
|
||||
/* Return values:
|
||||
* 0: did not move, but can still attack and do other stuff.
|
||||
* 1: moved, possibly can attack.
|
||||
* 2: monster died.
|
||||
* 3: did not move, and can't do anything else either.
|
||||
*/
|
||||
int
|
||||
m_move(register struct monst *mtmp, int after)
|
||||
static int
|
||||
postmov(
|
||||
struct monst *mtmp,
|
||||
struct permonst *ptr,
|
||||
int omx,
|
||||
int omy,
|
||||
schar mmoved,
|
||||
boolean sawmon,
|
||||
boolean can_tunnel,
|
||||
boolean can_unlock,
|
||||
boolean can_open)
|
||||
{
|
||||
int appr, etmp;
|
||||
coordxy ggx, ggy, nix, niy;
|
||||
xint16 chcnt;
|
||||
int chi; /* could be schar except for stupid Sun-2 compiler */
|
||||
boolean can_tunnel = 0;
|
||||
boolean can_open = 0, can_unlock = 0 /*, doorbuster = 0 */;
|
||||
boolean getitems = FALSE;
|
||||
boolean avoid = FALSE;
|
||||
boolean better_with_displacing = FALSE;
|
||||
boolean sawmon = canspotmon(mtmp); /* before it moved */
|
||||
struct permonst *ptr;
|
||||
schar mmoved = MMOVE_NOTHING; /* not strictly nec.: chi >= 0 will do */
|
||||
long info[9];
|
||||
long flag;
|
||||
int omx = mtmp->mx, omy = mtmp->my;
|
||||
coordxy nix, niy;
|
||||
int etmp;
|
||||
|
||||
if (mtmp->mtrapped) {
|
||||
int i = mintrap(mtmp, NO_TRAP_FLAGS);
|
||||
|
||||
if (i == Trap_Killed_Mon) {
|
||||
newsym(mtmp->mx, mtmp->my);
|
||||
return MMOVE_DIED;
|
||||
} /* it died */
|
||||
if (i == Trap_Caught_Mon)
|
||||
return MMOVE_NOTHING; /* still in trap, so didn't move */
|
||||
}
|
||||
ptr = mtmp->data; /* mintrap() can change mtmp->data -dlc */
|
||||
|
||||
if (mtmp->meating) {
|
||||
mtmp->meating--;
|
||||
if (mtmp->meating <= 0)
|
||||
finish_meating(mtmp);
|
||||
return MMOVE_DONE; /* still eating */
|
||||
}
|
||||
if (hides_under(ptr) && OBJ_AT(mtmp->mx, mtmp->my)
|
||||
&& can_hide_under_obj(gl.level.objects[mtmp->mx][mtmp->my]) && rn2(10))
|
||||
return MMOVE_NOTHING; /* do not leave hiding place */
|
||||
|
||||
/* Where does 'mtmp' think you are? Not necessary if m_move() called
|
||||
from this file, but needed for other calls of m_move(). */
|
||||
set_apparxy(mtmp); /* set mtmp->mux, mtmp->muy */
|
||||
|
||||
if (!Is_rogue_level(&u.uz))
|
||||
can_tunnel = tunnels(ptr);
|
||||
can_open = !(nohands(ptr) || verysmall(ptr));
|
||||
can_unlock = ((can_open && monhaskey(mtmp, TRUE))
|
||||
|| mtmp->iswiz || is_rider(ptr));
|
||||
/* doorbuster = is_giant(ptr); */
|
||||
if (mtmp->wormno)
|
||||
goto not_special;
|
||||
/* my dog gets special treatment */
|
||||
if (mtmp->mtame) {
|
||||
mmoved = dog_move(mtmp, after);
|
||||
goto postmov;
|
||||
}
|
||||
|
||||
/* and the acquisitive monsters get special treatment */
|
||||
if (is_covetous(ptr)) { /* [should this include
|
||||
* '&& mtmp->mstrategy != STRAT_NONE'?] */
|
||||
int covetousattack;
|
||||
coordxy tx = STRAT_GOALX(mtmp->mstrategy),
|
||||
ty = STRAT_GOALY(mtmp->mstrategy);
|
||||
struct monst *intruder = isok(tx, ty) ? m_at(tx, ty) : NULL;
|
||||
/*
|
||||
* if there's a monster on the object or in possession of it,
|
||||
* attack it.
|
||||
*/
|
||||
if (intruder && intruder != mtmp
|
||||
/* 3.7: this used to use 'dist2() < 2' which meant that intended
|
||||
attack was disallowed if they were adjacent diagonally */
|
||||
&& dist2(mtmp->mx, mtmp->my, tx, ty) <= 2) {
|
||||
gb.bhitpos.x = tx, gb.bhitpos.y = ty;
|
||||
gn.notonhead = (intruder->mx != tx || intruder->my != ty);
|
||||
covetousattack = mattackm(mtmp, intruder);
|
||||
/* 3.7: this used to erroneously use '== 2' (M_ATTK_DEF_DIED) */
|
||||
if (covetousattack & M_ATTK_AGR_DIED)
|
||||
return MMOVE_DIED;
|
||||
mmoved = MMOVE_MOVED;
|
||||
} else {
|
||||
mmoved = MMOVE_NOTHING;
|
||||
}
|
||||
goto postmov;
|
||||
}
|
||||
|
||||
/* likewise for shopkeeper, guard, or priest */
|
||||
if (mtmp->isshk || mtmp->isgd || mtmp->ispriest) {
|
||||
int xm = mtmp->isshk ? shk_move(mtmp)
|
||||
: mtmp->isgd ? gd_move(mtmp)
|
||||
: pri_move(mtmp);
|
||||
|
||||
switch (xm) {
|
||||
case -2:
|
||||
return MMOVE_DIED;
|
||||
case -1:
|
||||
mmoved = MMOVE_NOTHING; /* shk follow hero outside shop */
|
||||
break;
|
||||
case 0:
|
||||
mmoved = MMOVE_NOTHING;
|
||||
goto postmov;
|
||||
case 1:
|
||||
mmoved = MMOVE_MOVED;
|
||||
goto postmov;
|
||||
default: impossible("unknown shk/gd/pri_move return value (%i)", xm);
|
||||
mmoved = MMOVE_NOTHING;
|
||||
goto postmov;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MAIL_STRUCTURES
|
||||
if (ptr == &mons[PM_MAIL_DAEMON]) {
|
||||
if (!Deaf && canseemon(mtmp)) {
|
||||
SetVoice(mtmp, 0, 80, 0);
|
||||
verbalize("I'm late!");
|
||||
}
|
||||
mongone(mtmp);
|
||||
return MMOVE_DIED;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* teleport if that lies in our nature */
|
||||
if (ptr == &mons[PM_TENGU] && !rn2(5) && !mtmp->mcan
|
||||
&& !tele_restrict(mtmp)) {
|
||||
if (mtmp->mhp < 7 || mtmp->mpeaceful || rn2(2))
|
||||
(void) rloc(mtmp, RLOC_MSG);
|
||||
else
|
||||
mnexto(mtmp, RLOC_MSG);
|
||||
mmoved = MMOVE_MOVED;
|
||||
goto postmov;
|
||||
}
|
||||
not_special:
|
||||
if (u.uswallow && !mtmp->mflee && u.ustuck != mtmp)
|
||||
return MMOVE_MOVED;
|
||||
omx = mtmp->mx;
|
||||
omy = mtmp->my;
|
||||
ggx = mtmp->mux;
|
||||
ggy = mtmp->muy;
|
||||
appr = mtmp->mflee ? -1 : 1;
|
||||
if (mtmp->mconf || engulfing_u(mtmp)) {
|
||||
appr = 0;
|
||||
} else {
|
||||
boolean should_see = (couldsee(omx, omy)
|
||||
&& (levl[ggx][ggy].lit || !levl[omx][omy].lit)
|
||||
&& (dist2(omx, omy, ggx, ggy) <= 36));
|
||||
|
||||
if (!mtmp->mcansee
|
||||
|| (should_see && Invis && !perceives(ptr) && rn2(11))
|
||||
|| is_obj_mappear(&gy.youmonst, STRANGE_OBJECT) || u.uundetected
|
||||
|| (is_obj_mappear(&gy.youmonst, GOLD_PIECE) && !likes_gold(ptr))
|
||||
|| (mtmp->mpeaceful && !mtmp->isshk) /* allow shks to follow */
|
||||
|| ((monsndx(ptr) == PM_STALKER || ptr->mlet == S_BAT
|
||||
|| ptr->mlet == S_LIGHT) && !rn2(3)))
|
||||
appr = 0;
|
||||
|
||||
if (appr == 1 && leppie_avoidance(mtmp))
|
||||
appr = -1;
|
||||
|
||||
/* hostiles with ranged weapon or attack try to stay away */
|
||||
if (m_balks_at_approaching(mtmp))
|
||||
appr = -1;
|
||||
|
||||
if (!should_see && can_track(ptr)) {
|
||||
register coord *cp;
|
||||
|
||||
cp = gettrack(omx, omy);
|
||||
if (cp) {
|
||||
ggx = cp->x;
|
||||
ggy = cp->y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((!mtmp->mpeaceful || !rn2(10)) && (!Is_rogue_level(&u.uz))) {
|
||||
boolean in_line = (lined_up(mtmp)
|
||||
&& (distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy)
|
||||
<= (throws_rocks(gy.youmonst.data) ? 20 : ACURRSTR / 2 + 1)));
|
||||
|
||||
if (appr != 1 || !in_line) {
|
||||
/* Monsters in combat won't pick stuff up, avoiding the
|
||||
* situation where you toss arrows at it and it has nothing
|
||||
* better to do than pick the arrows up.
|
||||
*/
|
||||
getitems = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (getitems && m_search_items(mtmp, &ggx, &ggy, &mmoved, &appr))
|
||||
goto postmov;
|
||||
|
||||
/* don't tunnel if hostile and close enough to prefer a weapon */
|
||||
if (can_tunnel && needspick(ptr)
|
||||
&& ((!mtmp->mpeaceful || Conflict)
|
||||
&& dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 8))
|
||||
can_tunnel = FALSE;
|
||||
|
||||
nix = omx;
|
||||
niy = omy;
|
||||
flag = mon_allowflags(mtmp);
|
||||
{
|
||||
int i, j, nx, ny, nearer;
|
||||
int jcnt, cnt;
|
||||
int ndist, nidist;
|
||||
coord *mtrk;
|
||||
coord poss[9];
|
||||
|
||||
cnt = mfndpos(mtmp, poss, info, flag);
|
||||
if (cnt == 0) {
|
||||
if (find_defensive(mtmp, TRUE) && use_defensive(mtmp))
|
||||
return MMOVE_DONE;
|
||||
return MMOVE_NOMOVES;
|
||||
}
|
||||
chcnt = 0;
|
||||
jcnt = min(MTSZ, cnt - 1);
|
||||
chi = -1;
|
||||
nidist = dist2(nix, niy, ggx, ggy);
|
||||
/* allow monsters be shortsighted on some levels for balance */
|
||||
if (!mtmp->mpeaceful && gl.level.flags.shortsighted
|
||||
&& nidist > (couldsee(nix, niy) ? 144 : 36) && appr == 1)
|
||||
appr = 0;
|
||||
if (is_unicorn(ptr) && noteleport_level(mtmp)) {
|
||||
/* on noteleport levels, perhaps we cannot avoid hero */
|
||||
for (i = 0; i < cnt; i++)
|
||||
if (!(info[i] & NOTONL))
|
||||
avoid = TRUE;
|
||||
}
|
||||
better_with_displacing =
|
||||
should_displace(mtmp, poss, info, cnt, ggx, ggy);
|
||||
for (i = 0; i < cnt; i++) {
|
||||
if (avoid && (info[i] & NOTONL))
|
||||
continue;
|
||||
nx = poss[i].x;
|
||||
ny = poss[i].y;
|
||||
|
||||
if (MON_AT(nx, ny) && (info[i] & ALLOW_MDISP)
|
||||
&& !(info[i] & ALLOW_M) && !better_with_displacing)
|
||||
continue;
|
||||
if (appr != 0) {
|
||||
mtrk = &mtmp->mtrack[0];
|
||||
for (j = 0; j < jcnt; mtrk++, j++)
|
||||
if (nx == mtrk->x && ny == mtrk->y)
|
||||
if (rn2(4 * (cnt - j)))
|
||||
goto nxti;
|
||||
}
|
||||
|
||||
nearer = ((ndist = dist2(nx, ny, ggx, ggy)) < nidist);
|
||||
|
||||
if ((appr == 1 && nearer) || (appr == -1 && !nearer)
|
||||
|| (!appr && !rn2(++chcnt)) || (mmoved == MMOVE_NOTHING)) {
|
||||
nix = nx;
|
||||
niy = ny;
|
||||
nidist = ndist;
|
||||
chi = i;
|
||||
mmoved = MMOVE_MOVED;
|
||||
}
|
||||
nxti:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if (mmoved != MMOVE_NOTHING) {
|
||||
if (mmoved == MMOVE_MOVED && !u_at(nix, niy) && itsstuck(mtmp))
|
||||
return MMOVE_DONE;
|
||||
|
||||
if (mmoved == MMOVE_MOVED && m_digweapon_check(mtmp, nix, niy))
|
||||
return MMOVE_DONE;
|
||||
|
||||
/* If ALLOW_U is set, either it's trying to attack you, or it
|
||||
* thinks it is. In either case, attack this spot in preference to
|
||||
* all others.
|
||||
*/
|
||||
/* Actually, this whole section of code doesn't work as you'd expect.
|
||||
* Most attacks are handled in dochug(). It calls distfleeck(), which
|
||||
* among other things sets nearby if the monster is near you--and if
|
||||
* nearby is set, we never call m_move unless it is a special case
|
||||
* (confused, stun, etc.) The effect is that this ALLOW_U (and
|
||||
* mfndpos) has no effect for normal attacks, though it lets a
|
||||
* confused monster attack you by accident.
|
||||
*/
|
||||
if (info[chi] & ALLOW_U) {
|
||||
nix = mtmp->mux;
|
||||
niy = mtmp->muy;
|
||||
}
|
||||
if (u_at(nix, niy)) {
|
||||
mtmp->mux = u.ux;
|
||||
mtmp->muy = u.uy;
|
||||
return MMOVE_NOTHING;
|
||||
}
|
||||
/* The monster may attack another based on 1 of 2 conditions:
|
||||
* 1 - It may be confused.
|
||||
* 2 - It may mistake the monster for your (displaced) image.
|
||||
* Pets get taken care of above and shouldn't reach this code.
|
||||
* Conflict gets handled even farther away (movemon()).
|
||||
*/
|
||||
if ((info[chi] & ALLOW_M) != 0
|
||||
|| (nix == mtmp->mux && niy == mtmp->muy))
|
||||
return m_move_aggress(mtmp, nix, niy);
|
||||
|
||||
if ((info[chi] & ALLOW_MDISP) != 0) {
|
||||
struct monst *mtmp2;
|
||||
int mstatus;
|
||||
|
||||
mtmp2 = m_at(nix, niy); /* ALLOW_MDISP implies m_at() is !Null */
|
||||
mstatus = mdisplacem(mtmp, mtmp2, FALSE);
|
||||
/*[if either dies, this reports mtmp has died; is that correct?]*/
|
||||
if (mstatus & (M_ATTK_AGR_DIED | M_ATTK_DEF_DIED))
|
||||
return MMOVE_DIED;
|
||||
if (mstatus & M_ATTK_HIT)
|
||||
return MMOVE_MOVED;
|
||||
return MMOVE_DONE;
|
||||
}
|
||||
|
||||
if (!m_in_out_region(mtmp, nix, niy))
|
||||
return MMOVE_DONE;
|
||||
|
||||
if ((info[chi] & ALLOW_ROCK) && m_can_break_boulder(mtmp)) {
|
||||
(void) m_break_boulder(mtmp, nix, niy);
|
||||
return MMOVE_DONE;
|
||||
}
|
||||
|
||||
/* move a normal monster; for a long worm, remove_monster() and
|
||||
place_monster() only manipulate the head; they leave tail as-is */
|
||||
remove_monster(omx, omy);
|
||||
place_monster(mtmp, nix, niy);
|
||||
/* for a long worm, insert a new segment to reconnect the head
|
||||
with the tail; worm_move() keeps the end of the tail if worm
|
||||
is scheduled to grow, removes that for move-without-growing */
|
||||
if (mtmp->wormno)
|
||||
worm_move(mtmp);
|
||||
|
||||
maybe_unhide_at(mtmp->mx, mtmp->my);
|
||||
|
||||
mon_track_add(mtmp, omx, omy);
|
||||
} else {
|
||||
if (is_unicorn(ptr) && rn2(2) && !tele_restrict(mtmp)) {
|
||||
(void) rloc(mtmp, RLOC_MSG);
|
||||
return MMOVE_MOVED;
|
||||
}
|
||||
/* for a long worm, shrink it (by discarding end of tail) when
|
||||
it has failed to move */
|
||||
if (mtmp->wormno)
|
||||
worm_nomove(mtmp);
|
||||
}
|
||||
postmov:
|
||||
if (mmoved == MMOVE_MOVED || mmoved == MMOVE_DONE) {
|
||||
boolean canseeit = cansee(mtmp->mx, mtmp->my),
|
||||
didseeit = canseeit;
|
||||
@@ -1869,6 +1534,363 @@ m_move(register struct monst *mtmp, int after)
|
||||
return mmoved;
|
||||
}
|
||||
|
||||
/* Handles the movement of a standard monster. */
|
||||
/* Return values:
|
||||
* 0: did not move, but can still attack and do other stuff.
|
||||
* 1: moved, possibly can attack.
|
||||
* 2: monster died.
|
||||
* 3: did not move, and can't do anything else either.
|
||||
*/
|
||||
int
|
||||
m_move(register struct monst *mtmp, int after)
|
||||
{
|
||||
int appr;
|
||||
coordxy ggx, ggy, nix, niy;
|
||||
xint16 chcnt;
|
||||
int chi; /* could be schar except for stupid Sun-2 compiler */
|
||||
boolean can_tunnel = 0;
|
||||
boolean can_open = 0, can_unlock = 0 /*, doorbuster = 0 */;
|
||||
boolean getitems = FALSE;
|
||||
boolean avoid = FALSE;
|
||||
boolean better_with_displacing = FALSE;
|
||||
boolean sawmon = canspotmon(mtmp); /* before it moved */
|
||||
struct permonst *ptr;
|
||||
schar mmoved = MMOVE_NOTHING; /* not strictly nec.: chi >= 0 will do */
|
||||
long info[9];
|
||||
long flag;
|
||||
int omx = mtmp->mx, omy = mtmp->my;
|
||||
|
||||
if (mtmp->mtrapped) {
|
||||
int i = mintrap(mtmp, NO_TRAP_FLAGS);
|
||||
|
||||
if (i == Trap_Killed_Mon) {
|
||||
newsym(mtmp->mx, mtmp->my);
|
||||
return MMOVE_DIED;
|
||||
} /* it died */
|
||||
if (i == Trap_Caught_Mon)
|
||||
return MMOVE_NOTHING; /* still in trap, so didn't move */
|
||||
}
|
||||
ptr = mtmp->data; /* mintrap() can change mtmp->data -dlc */
|
||||
|
||||
if (mtmp->meating) {
|
||||
mtmp->meating--;
|
||||
if (mtmp->meating <= 0)
|
||||
finish_meating(mtmp);
|
||||
return MMOVE_DONE; /* still eating */
|
||||
}
|
||||
if (hides_under(ptr) && OBJ_AT(mtmp->mx, mtmp->my)
|
||||
&& can_hide_under_obj(gl.level.objects[mtmp->mx][mtmp->my]) && rn2(10))
|
||||
return MMOVE_NOTHING; /* do not leave hiding place */
|
||||
|
||||
/* Where does 'mtmp' think you are? Not necessary if m_move() called
|
||||
from this file, but needed for other calls of m_move(). */
|
||||
set_apparxy(mtmp); /* set mtmp->mux, mtmp->muy */
|
||||
|
||||
if (!Is_rogue_level(&u.uz))
|
||||
can_tunnel = tunnels(ptr);
|
||||
can_open = !(nohands(ptr) || verysmall(ptr));
|
||||
can_unlock = ((can_open && monhaskey(mtmp, TRUE))
|
||||
|| mtmp->iswiz || is_rider(ptr));
|
||||
/* doorbuster = is_giant(ptr); */
|
||||
if (mtmp->wormno)
|
||||
goto not_special;
|
||||
/* my dog gets special treatment */
|
||||
if (mtmp->mtame) {
|
||||
return postmov(mtmp, ptr, omx, omy, dog_move(mtmp, after), sawmon,
|
||||
can_tunnel, can_unlock, can_open);
|
||||
}
|
||||
|
||||
/* and the acquisitive monsters get special treatment */
|
||||
if (is_covetous(ptr)) { /* [should this include
|
||||
* '&& mtmp->mstrategy != STRAT_NONE'?] */
|
||||
int covetousattack;
|
||||
coordxy tx = STRAT_GOALX(mtmp->mstrategy),
|
||||
ty = STRAT_GOALY(mtmp->mstrategy);
|
||||
struct monst *intruder = isok(tx, ty) ? m_at(tx, ty) : NULL;
|
||||
/*
|
||||
* if there's a monster on the object or in possession of it,
|
||||
* attack it.
|
||||
*/
|
||||
if (intruder && intruder != mtmp
|
||||
/* 3.7: this used to use 'dist2() < 2' which meant that intended
|
||||
attack was disallowed if they were adjacent diagonally */
|
||||
&& dist2(mtmp->mx, mtmp->my, tx, ty) <= 2) {
|
||||
gb.bhitpos.x = tx, gb.bhitpos.y = ty;
|
||||
gn.notonhead = (intruder->mx != tx || intruder->my != ty);
|
||||
covetousattack = mattackm(mtmp, intruder);
|
||||
/* 3.7: this used to erroneously use '== 2' (M_ATTK_DEF_DIED) */
|
||||
if (covetousattack & M_ATTK_AGR_DIED)
|
||||
return MMOVE_DIED;
|
||||
mmoved = MMOVE_MOVED;
|
||||
} else {
|
||||
mmoved = MMOVE_NOTHING;
|
||||
}
|
||||
return postmov(mtmp, ptr, omx, omy, mmoved, sawmon,
|
||||
can_tunnel, can_unlock, can_open);
|
||||
}
|
||||
|
||||
/* likewise for shopkeeper, guard, or priest */
|
||||
if (mtmp->isshk || mtmp->isgd || mtmp->ispriest) {
|
||||
int xm = mtmp->isshk ? shk_move(mtmp)
|
||||
: mtmp->isgd ? gd_move(mtmp)
|
||||
: pri_move(mtmp);
|
||||
|
||||
switch (xm) {
|
||||
case -2:
|
||||
return MMOVE_DIED;
|
||||
case -1:
|
||||
mmoved = MMOVE_NOTHING; /* shk follow hero outside shop */
|
||||
break;
|
||||
case 0:
|
||||
return postmov(mtmp, ptr, omx, omy, MMOVE_NOTHING, sawmon,
|
||||
can_tunnel, can_unlock, can_open);
|
||||
case 1:
|
||||
return postmov(mtmp, ptr, omx, omy, MMOVE_MOVED, sawmon,
|
||||
can_tunnel, can_unlock, can_open);
|
||||
default: impossible("unknown shk/gd/pri_move return value (%i)", xm);
|
||||
return postmov(mtmp, ptr, omx, omy, MMOVE_NOTHING, sawmon,
|
||||
can_tunnel, can_unlock, can_open);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MAIL_STRUCTURES
|
||||
if (ptr == &mons[PM_MAIL_DAEMON]) {
|
||||
if (!Deaf && canseemon(mtmp)) {
|
||||
SetVoice(mtmp, 0, 80, 0);
|
||||
verbalize("I'm late!");
|
||||
}
|
||||
mongone(mtmp);
|
||||
return MMOVE_DIED;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* teleport if that lies in our nature */
|
||||
if (ptr == &mons[PM_TENGU] && !rn2(5) && !mtmp->mcan
|
||||
&& !tele_restrict(mtmp)) {
|
||||
if (mtmp->mhp < 7 || mtmp->mpeaceful || rn2(2))
|
||||
(void) rloc(mtmp, RLOC_MSG);
|
||||
else
|
||||
mnexto(mtmp, RLOC_MSG);
|
||||
return postmov(mtmp, ptr, omx, omy, MMOVE_MOVED, sawmon,
|
||||
can_tunnel, can_unlock, can_open);
|
||||
}
|
||||
not_special:
|
||||
if (u.uswallow && !mtmp->mflee && u.ustuck != mtmp)
|
||||
return MMOVE_MOVED;
|
||||
omx = mtmp->mx;
|
||||
omy = mtmp->my;
|
||||
ggx = mtmp->mux;
|
||||
ggy = mtmp->muy;
|
||||
appr = mtmp->mflee ? -1 : 1;
|
||||
if (mtmp->mconf || engulfing_u(mtmp)) {
|
||||
appr = 0;
|
||||
} else {
|
||||
boolean should_see = (couldsee(omx, omy)
|
||||
&& (levl[ggx][ggy].lit || !levl[omx][omy].lit)
|
||||
&& (dist2(omx, omy, ggx, ggy) <= 36));
|
||||
|
||||
if (!mtmp->mcansee
|
||||
|| (should_see && Invis && !perceives(ptr) && rn2(11))
|
||||
|| is_obj_mappear(&gy.youmonst, STRANGE_OBJECT) || u.uundetected
|
||||
|| (is_obj_mappear(&gy.youmonst, GOLD_PIECE) && !likes_gold(ptr))
|
||||
|| (mtmp->mpeaceful && !mtmp->isshk) /* allow shks to follow */
|
||||
|| ((monsndx(ptr) == PM_STALKER || ptr->mlet == S_BAT
|
||||
|| ptr->mlet == S_LIGHT) && !rn2(3)))
|
||||
appr = 0;
|
||||
|
||||
if (appr == 1 && leppie_avoidance(mtmp))
|
||||
appr = -1;
|
||||
|
||||
/* hostiles with ranged weapon or attack try to stay away */
|
||||
if (m_balks_at_approaching(mtmp))
|
||||
appr = -1;
|
||||
|
||||
if (!should_see && can_track(ptr)) {
|
||||
register coord *cp;
|
||||
|
||||
cp = gettrack(omx, omy);
|
||||
if (cp) {
|
||||
ggx = cp->x;
|
||||
ggy = cp->y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((!mtmp->mpeaceful || !rn2(10)) && (!Is_rogue_level(&u.uz))) {
|
||||
boolean in_line = (lined_up(mtmp)
|
||||
&& (distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy)
|
||||
<= (throws_rocks(gy.youmonst.data) ? 20 : ACURRSTR / 2 + 1)));
|
||||
|
||||
if (appr != 1 || !in_line) {
|
||||
/* Monsters in combat won't pick stuff up, avoiding the
|
||||
* situation where you toss arrows at it and it has nothing
|
||||
* better to do than pick the arrows up.
|
||||
*/
|
||||
getitems = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (getitems && m_search_items(mtmp, &ggx, &ggy, &mmoved, &appr))
|
||||
return postmov(mtmp, ptr, omx, omy, mmoved, sawmon,
|
||||
can_tunnel, can_unlock, can_open);
|
||||
|
||||
/* don't tunnel if hostile and close enough to prefer a weapon */
|
||||
if (can_tunnel && needspick(ptr)
|
||||
&& ((!mtmp->mpeaceful || Conflict)
|
||||
&& dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 8))
|
||||
can_tunnel = FALSE;
|
||||
|
||||
nix = omx;
|
||||
niy = omy;
|
||||
flag = mon_allowflags(mtmp);
|
||||
{
|
||||
int i, j, nx, ny, nearer;
|
||||
int jcnt, cnt;
|
||||
int ndist, nidist;
|
||||
coord *mtrk;
|
||||
coord poss[9];
|
||||
|
||||
cnt = mfndpos(mtmp, poss, info, flag);
|
||||
if (cnt == 0) {
|
||||
if (find_defensive(mtmp, TRUE) && use_defensive(mtmp))
|
||||
return MMOVE_DONE;
|
||||
return MMOVE_NOMOVES;
|
||||
}
|
||||
chcnt = 0;
|
||||
jcnt = min(MTSZ, cnt - 1);
|
||||
chi = -1;
|
||||
nidist = dist2(nix, niy, ggx, ggy);
|
||||
/* allow monsters be shortsighted on some levels for balance */
|
||||
if (!mtmp->mpeaceful && gl.level.flags.shortsighted
|
||||
&& nidist > (couldsee(nix, niy) ? 144 : 36) && appr == 1)
|
||||
appr = 0;
|
||||
if (is_unicorn(ptr) && noteleport_level(mtmp)) {
|
||||
/* on noteleport levels, perhaps we cannot avoid hero */
|
||||
for (i = 0; i < cnt; i++)
|
||||
if (!(info[i] & NOTONL))
|
||||
avoid = TRUE;
|
||||
}
|
||||
better_with_displacing =
|
||||
should_displace(mtmp, poss, info, cnt, ggx, ggy);
|
||||
for (i = 0; i < cnt; i++) {
|
||||
if (avoid && (info[i] & NOTONL))
|
||||
continue;
|
||||
nx = poss[i].x;
|
||||
ny = poss[i].y;
|
||||
|
||||
if (MON_AT(nx, ny) && (info[i] & ALLOW_MDISP)
|
||||
&& !(info[i] & ALLOW_M) && !better_with_displacing)
|
||||
continue;
|
||||
if (appr != 0) {
|
||||
mtrk = &mtmp->mtrack[0];
|
||||
for (j = 0; j < jcnt; mtrk++, j++)
|
||||
if (nx == mtrk->x && ny == mtrk->y)
|
||||
if (rn2(4 * (cnt - j)))
|
||||
goto nxti;
|
||||
}
|
||||
|
||||
nearer = ((ndist = dist2(nx, ny, ggx, ggy)) < nidist);
|
||||
|
||||
if ((appr == 1 && nearer) || (appr == -1 && !nearer)
|
||||
|| (!appr && !rn2(++chcnt)) || (mmoved == MMOVE_NOTHING)) {
|
||||
nix = nx;
|
||||
niy = ny;
|
||||
nidist = ndist;
|
||||
chi = i;
|
||||
mmoved = MMOVE_MOVED;
|
||||
}
|
||||
nxti:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if (mmoved != MMOVE_NOTHING) {
|
||||
if (mmoved == MMOVE_MOVED && !u_at(nix, niy) && itsstuck(mtmp))
|
||||
return MMOVE_DONE;
|
||||
|
||||
if (mmoved == MMOVE_MOVED && m_digweapon_check(mtmp, nix, niy))
|
||||
return MMOVE_DONE;
|
||||
|
||||
/* If ALLOW_U is set, either it's trying to attack you, or it
|
||||
* thinks it is. In either case, attack this spot in preference to
|
||||
* all others.
|
||||
*/
|
||||
/* Actually, this whole section of code doesn't work as you'd expect.
|
||||
* Most attacks are handled in dochug(). It calls distfleeck(), which
|
||||
* among other things sets nearby if the monster is near you--and if
|
||||
* nearby is set, we never call m_move unless it is a special case
|
||||
* (confused, stun, etc.) The effect is that this ALLOW_U (and
|
||||
* mfndpos) has no effect for normal attacks, though it lets a
|
||||
* confused monster attack you by accident.
|
||||
*/
|
||||
if (info[chi] & ALLOW_U) {
|
||||
nix = mtmp->mux;
|
||||
niy = mtmp->muy;
|
||||
}
|
||||
if (u_at(nix, niy)) {
|
||||
mtmp->mux = u.ux;
|
||||
mtmp->muy = u.uy;
|
||||
return MMOVE_NOTHING;
|
||||
}
|
||||
/* The monster may attack another based on 1 of 2 conditions:
|
||||
* 1 - It may be confused.
|
||||
* 2 - It may mistake the monster for your (displaced) image.
|
||||
* Pets get taken care of above and shouldn't reach this code.
|
||||
* Conflict gets handled even farther away (movemon()).
|
||||
*/
|
||||
if ((info[chi] & ALLOW_M) != 0
|
||||
|| (nix == mtmp->mux && niy == mtmp->muy))
|
||||
return m_move_aggress(mtmp, nix, niy);
|
||||
|
||||
if ((info[chi] & ALLOW_MDISP) != 0) {
|
||||
struct monst *mtmp2;
|
||||
int mstatus;
|
||||
|
||||
mtmp2 = m_at(nix, niy); /* ALLOW_MDISP implies m_at() is !Null */
|
||||
mstatus = mdisplacem(mtmp, mtmp2, FALSE);
|
||||
/*[if either dies, this reports mtmp has died; is that correct?]*/
|
||||
if (mstatus & (M_ATTK_AGR_DIED | M_ATTK_DEF_DIED))
|
||||
return MMOVE_DIED;
|
||||
if (mstatus & M_ATTK_HIT)
|
||||
return MMOVE_MOVED;
|
||||
return MMOVE_DONE;
|
||||
}
|
||||
|
||||
if (!m_in_out_region(mtmp, nix, niy))
|
||||
return MMOVE_DONE;
|
||||
|
||||
if ((info[chi] & ALLOW_ROCK) && m_can_break_boulder(mtmp)) {
|
||||
(void) m_break_boulder(mtmp, nix, niy);
|
||||
return MMOVE_DONE;
|
||||
}
|
||||
|
||||
/* move a normal monster; for a long worm, remove_monster() and
|
||||
place_monster() only manipulate the head; they leave tail as-is */
|
||||
remove_monster(omx, omy);
|
||||
place_monster(mtmp, nix, niy);
|
||||
/* for a long worm, insert a new segment to reconnect the head
|
||||
with the tail; worm_move() keeps the end of the tail if worm
|
||||
is scheduled to grow, removes that for move-without-growing */
|
||||
if (mtmp->wormno)
|
||||
worm_move(mtmp);
|
||||
|
||||
maybe_unhide_at(mtmp->mx, mtmp->my);
|
||||
|
||||
mon_track_add(mtmp, omx, omy);
|
||||
} else {
|
||||
if (is_unicorn(ptr) && rn2(2) && !tele_restrict(mtmp)) {
|
||||
(void) rloc(mtmp, RLOC_MSG);
|
||||
return MMOVE_MOVED;
|
||||
}
|
||||
/* for a long worm, shrink it (by discarding end of tail) when
|
||||
it has failed to move */
|
||||
if (mtmp->wormno)
|
||||
worm_nomove(mtmp);
|
||||
}
|
||||
return postmov(mtmp, ptr, omx, omy, mmoved, sawmon,
|
||||
can_tunnel, can_unlock, can_open);
|
||||
}
|
||||
|
||||
/* The part of m_move that deals with a monster attacking another monster (and
|
||||
* that monster possibly retaliating).
|
||||
* Extracted into its own function so that it can be called with monsters that
|
||||
|
||||
Reference in New Issue
Block a user