Split pet ranged attack into separate function

This commit is contained in:
Pasi Kallinen
2023-01-25 11:27:14 +02:00
parent 84c14982bd
commit 5b8dc1eff7

View File

@@ -18,6 +18,7 @@ static int dog_goal(struct monst *, struct edog *, int, int, int);
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);
@@ -854,6 +855,81 @@ best_target(struct monst *mtmp) /* Pet */
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.
@@ -1130,76 +1206,8 @@ dog_move(register struct monst *mtmp,
* 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) {