diff --git a/include/extern.h b/include/extern.h index 7eaa68e65..8422224f4 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1485,6 +1485,11 @@ extern int gazemu(struct monst *, struct attack *) NONNULLARG12; extern void mdamageu(struct monst *, int) NONNULLARG1; extern int could_seduce(struct monst *, struct monst *, struct attack *) NONNULLARG12; extern int doseduce(struct monst *) NONNULLARG1; +extern boolean mon_avoiding_this_attack(struct monst *, int) NONNULLARG1; +/* extern boolean ranged_attk_assessed(struct monst *mtmp, + boolean (*assessfunct)(struct monst *, int)) NONNULLARG1; +*/ +extern boolean ranged_attk_available(struct monst *mtmp) NONNULLARG1; /* ### minion.c ### */ diff --git a/src/mhitu.c b/src/mhitu.c index 14b453147..8a442faa1 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -2305,6 +2305,62 @@ assess_dmg(struct monst *mtmp, int tmp) return M_ATTK_HIT; } +#if 0 +/* returns True if monster has a range attack in its repertoire + that it will actually utilize. Caller provides the assessment + callback (optional). Callback returns 0 if the attack is + active */ + +boolean ranged_attk_assessed( +struct monst *mtmp, +boolean (*assessfunc)(struct monst *, int)) +{ + int i; + struct permonst *ptr = mtmp->data; + + for (i = 0; i < NATTK; i++) + if (DISTANCE_ATTK_TYPE(ptr->mattk[i].aatyp)) { + if (!assessfunc || (*assessfunc)(mtmp, i) == 0) + return TRUE; + } + return FALSE; +} +#endif + +/* can be used as ranged_attk_assessed() callback. + Returns TRUE if monster is avoiding use of this attack */ +boolean +mon_avoiding_this_attack(struct monst *mtmp, int attkidx) +{ + struct permonst *ptr = mtmp->data; + int typ = -1; + + if (attkidx >= 0 + && (typ = get_atkdam_type(ptr->mattk[attkidx].adtyp)) >= 0 + && m_seenres(mtmp, cvt_adtyp_to_mseenres(typ))) + return TRUE; + return FALSE; +} + +/* + * This would be equivalent to: + * ranged_attk_assessed(mtmp, mon_avoiding_this_attack) + * but without the added assessment function call overhead. + */ +boolean ranged_attk_available(struct monst *mtmp) +{ + int i, typ = -1; + struct permonst *ptr = mtmp->data; + + for (i = 0; i < NATTK; i++) { + if (DISTANCE_ATTK_TYPE(ptr->mattk[i].aatyp) + && (typ = get_atkdam_type(ptr->mattk[i].adtyp)) >= 0 + && m_seenres(mtmp, cvt_adtyp_to_mseenres(typ)) == 0) + return TRUE; + } + return FALSE; +} + /* FIXME: * sequencing issue: a monster's attack might cause poly'd hero * to revert to normal form. The messages for passive counterattack diff --git a/src/monmove.c b/src/monmove.c index a56b14fba..dc343d333 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -910,7 +910,8 @@ dochug(struct monst *mtmp) return 0; /* Monsters can move and then shoot on same turn; our hero can't. Is that fair? */ - if (!nearby && (ranged_attk(mdat) + if (!nearby + && (ranged_attk_available(mtmp) || attacktype(mdat, AT_WEAP) || find_offensive(mtmp))) break; @@ -1159,7 +1160,7 @@ m_balks_at_approaching(struct monst *mtmp) return TRUE; /* can attack from distance, and hp loss or attack not used */ - if (ranged_attk(mtmp->data) + if (ranged_attk_available(mtmp) && ((mtmp->mhp < (mtmp->mhpmax+1) / 3) || !mtmp->mspec_used)) return TRUE;