static struct monst *find_targ(struct monst *, int, int, int);
static int find_friends(struct monst *, struct monst *, int);
static struct monst *best_target(struct monst *);
+static int pet_ranged_attk(struct monst *);
static long score_targ(struct monst *, struct monst *);
static boolean can_reach_location(struct monst *, coordxy, coordxy, coordxy,
coordxy);
return best_targ;
}
+/* Pet considers and maybe executes a ranged attack */
+static int
+pet_ranged_attk(struct monst *mtmp)
+{
+ struct monst *mtarg;
+ int hungry = 0;
+
+ /* How hungry is the pet? */
+ if (!mtmp->isminion) {
+ struct edog *dog = EDOG(mtmp);
+
+ hungry = (gm.moves > (dog->hungrytime + DOG_HUNGRY));
+ }
+
+ /* Identify the best target in a straight line from the pet;
+ * if there is such a target, we'll let the pet attempt an attack.
+ */
+ mtarg = best_target(mtmp);
+
+ /* Hungry pets are unlikely to use breath/spit attacks */
+ if (mtarg && (!hungry || !rn2(5))) {
+ int mstatus = MM_MISS;
+
+ if (mtarg == &gy.youmonst) {
+ if (mattacku(mtmp))
+ return MMOVE_DIED;
+ /* Treat this as the pet having initiated an attack even if it
+ * didn't, so it will lose its move. This isn't entirely fair,
+ * but mattacku doesn't distinguish between "did not attack"
+ * and "attacked but didn't die" cases, and this is preferable
+ * to letting the pet attack the player and continuing to move.
+ */
+ mstatus = MM_HIT;
+ } else {
+ mstatus = mattackm(mtmp, mtarg);
+
+ /* Shouldn't happen, really */
+ if (mstatus & MM_AGR_DIED)
+ return MMOVE_DIED;
+
+ /* Allow the targeted nasty to strike back - if
+ * the targeted beast doesn't have a ranged attack,
+ * nothing will happen.
+ */
+ if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED)
+ && rn2(4) && mtarg != &gy.youmonst) {
+
+ /* Can monster see? If it can, it can retaliate
+ * even if the pet is invisible, since it'll see
+ * the direction from which the ranged attack came;
+ * if it's blind or unseeing, it can't retaliate
+ */
+ if (mtarg->mcansee && haseyes(mtarg->data)) {
+ mstatus = mattackm(mtarg, mtmp);
+ if (mstatus & MM_DEF_DIED)
+ return MMOVE_DIED;
+ }
+ }
+ }
+ /* Only return 3 if the pet actually made a ranged attack, and
+ * thus should lose the rest of its move.
+ * There's a chain of assumptions here:
+ * 1. score_targ and best_target will never select a monster
+ * that can be attacked in melee, so the mattackm call can
+ * only ever try ranged options
+ * 2. if the only attacks available to mattackm are ranged
+ * options, and the monster cannot make a ranged attack, it
+ * will return MM_MISS.
+ */
+ if (mstatus != MM_MISS)
+ return MMOVE_DONE;
+ }
+ return MMOVE_NOTHING;
+}
+
/* Return values (same as m_move):
* 0: did not move, but can still attack and do other stuff.
* 1: moved, possibly can attack.
* now's the time for ranged attacks. Note that the pet can move
* after it performs its ranged attack. Should this be changed?
*/
- {
- struct monst *mtarg;
- int hungry = 0;
-
- /* How hungry is the pet? */
- if (!mtmp->isminion) {
- struct edog *dog = EDOG(mtmp);
-
- hungry = (gm.moves > (dog->hungrytime + DOG_HUNGRY));
- }
-
- /* Identify the best target in a straight line from the pet;
- * if there is such a target, we'll let the pet attempt an attack.
- */
- mtarg = best_target(mtmp);
-
- /* Hungry pets are unlikely to use breath/spit attacks */
- if (mtarg && (!hungry || !rn2(5))) {
- int mstatus = MM_MISS;
-
- if (mtarg == &gy.youmonst) {
- if (mattacku(mtmp))
- return MMOVE_DIED;
- /* Treat this as the pet having initiated an attack even if it
- * didn't, so it will lose its move. This isn't entirely fair,
- * but mattacku doesn't distinguish between "did not attack"
- * and "attacked but didn't die" cases, and this is preferable
- * to letting the pet attack the player and continuing to move.
- */
- mstatus = MM_HIT;
- } else {
- mstatus = mattackm(mtmp, mtarg);
-
- /* Shouldn't happen, really */
- if (mstatus & MM_AGR_DIED)
- return MMOVE_DIED;
-
- /* Allow the targeted nasty to strike back - if
- * the targeted beast doesn't have a ranged attack,
- * nothing will happen.
- */
- if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED)
- && rn2(4) && mtarg != &gy.youmonst) {
-
- /* Can monster see? If it can, it can retaliate
- * even if the pet is invisible, since it'll see
- * the direction from which the ranged attack came;
- * if it's blind or unseeing, it can't retaliate
- */
- if (mtarg->mcansee && haseyes(mtarg->data)) {
- mstatus = mattackm(mtarg, mtmp);
- if (mstatus & MM_DEF_DIED)
- return MMOVE_DIED;
- }
- }
- }
- /* Only return 3 if the pet actually made a ranged attack, and
- * thus should lose the rest of its move.
- * There's a chain of assumptions here:
- * 1. score_targ and best_target will never select a monster
- * that can be attacked in melee, so the mattackm call can
- * only ever try ranged options
- * 2. if the only attacks available to mattackm are ranged
- * options, and the monster cannot make a ranged attack, it
- * will return MM_MISS.
- */
- if (mstatus != MM_MISS)
- return MMOVE_DONE;
- }
- }
+ if ((i = pet_ranged_attk(mtmp)) != MMOVE_NOTHING)
+ return i;
newdogpos:
if (nix != omx || niy != omy) {