Some reformatting of the recently added pet ranged attack code.
The redundant--but different--multishot volley code has been replaced
so that there are only two versions (hero and monster) instead of
three (hero and monster vs hero and pet vs other monster). The monst
version was out of date relative to post-3.4.3 changes to the hero one.
The pet version was way out of date and had some bugs: wielding an
elven bow gave a +1 multishot increment to volley count for fast weapon
even when throwing something rather than shooting arrows, wielding any
weapon which had at least +2 enchantment gave 1/3 enchantment bonus to
volley count when throwing instead of shooting shoot ammo, and a pet
which got killed in the midst of a multishot volley--perhaps by a gas
spore explosion or some other passive counterattack--would keep on
shooting/throwing until the volley count was exhausted.
Pet use of ranged weapons is not ready for prime-time. Pets don't
hang on to missiles or launchers+ammo, they just drop them if there is
no target immediately available.
STATIC_DCL boolean FDECL(dog_hunger, (struct monst *, struct edog *));
STATIC_DCL int FDECL(dog_invent, (struct monst *, struct edog *, int));
STATIC_DCL int FDECL(dog_goal, (struct monst *, struct edog *, int, int, int));
-STATIC_DCL struct monst* FDECL(find_targ, (struct monst *, int, int, int));
+STATIC_DCL struct monst *FDECL(find_targ, (struct monst *, int, int, int));
STATIC_OVL int FDECL(find_friends, (struct monst *, struct monst *, int));
-STATIC_DCL struct monst* FDECL(best_target, (struct monst *));
+STATIC_DCL struct monst *FDECL(best_target, (struct monst *));
STATIC_DCL long FDECL(score_targ, (struct monst *, struct monst *));
STATIC_DCL boolean FDECL(can_reach_location, (struct monst *, XCHAR_P,
XCHAR_P, XCHAR_P, XCHAR_P));
Strcpy(objnambuf, xname(obj));
iflags.suppress_price--;
}
- /* It's a reward if it's DOGFOOD and the player dropped/threw it. */
- /* We know the player had it if invlet is set -dlc */
+ /* It's a reward if it's DOGFOOD and the player dropped/threw it.
+ We know the player had it if invlet is set. -dlc */
if (dogfood(mtmp, obj) == DOGFOOD && obj->invlet)
#ifdef LINT
edog->apport = 0;
/* hunger effects -- returns TRUE on starvation */
STATIC_OVL boolean
dog_hunger(mtmp, edog)
-register struct monst *mtmp;
-register struct edog *edog;
+struct monst *mtmp;
+struct edog *edog;
{
if (monstermoves > edog->hungrytime + 500) {
if (!carnivorous(mtmp->data) && !herbivorous(mtmp->data)) {
edog->droptime = monstermoves;
}
} else {
- if ((obj = level.objects[omx][omy]) && !index(nofetch, obj->oclass)
+ if ((obj = level.objects[omx][omy]) != 0
+ && !index(nofetch, obj->oclass)
#ifdef MAIL
&& obj->otyp != SCR_MAIL
#endif
appr = 1;
}
/* if you have dog food it'll follow you more closely */
- if (appr == 0) {
- obj = invent;
- while (obj) {
+ if (appr == 0)
+ for (obj = invent; obj; obj = obj->nobj)
if (dogfood(mtmp, obj) == DOGFOOD) {
appr = 1;
break;
}
- obj = obj->nobj;
- }
- }
} else
appr = 1; /* gtyp != UNDEF */
if (mtmp->mconf)
} else {
/* assume master hasn't moved far, and reuse previous goal */
if (edog && edog->ogoal.x
- && ((edog->ogoal.x != omx) || (edog->ogoal.y != omy))) {
+ && (edog->ogoal.x != omx || edog->ogoal.y != omy)) {
gx = edog->ogoal.x;
gy = edog->ogoal.y;
edog->ogoal.x = 0;
return 0;
}
-
STATIC_OVL long
score_targ(mtmp, mtarg)
struct monst *mtmp, *mtarg;
/* Give 1 in 3 chance of safe breathing even if pet is confused or
* if you're on the quest start level */
if (!mtmp->mconf || !rn2(3) || Is_qstart(&u.uz)) {
- aligntyp align1, align2; /* For priests, minions */
+ aligntyp align1 = A_NONE, align2 = A_NONE; /* For priests, minions */
boolean faith1 = TRUE, faith2 = TRUE;
- if (mtmp->isminion) align1 = EMIN(mtmp)->min_align;
- else if (mtmp->ispriest) align1 = EPRI(mtmp)->shralign;
- else faith1 = FALSE;
- if (mtarg->isminion) align2 = EMIN(mtarg)->min_align; /* MAR */
- else if (mtarg->ispriest) align2 = EPRI(mtarg)->shralign; /* MAR */
- else faith2 = FALSE;
+ if (mtmp->isminion)
+ align1 = EMIN(mtmp)->min_align;
+ else if (mtmp->ispriest)
+ align1 = EPRI(mtmp)->shralign;
+ else
+ faith1 = FALSE;
+ if (mtarg->isminion)
+ align2 = EMIN(mtarg)->min_align; /* MAR */
+ else if (mtarg->ispriest)
+ align2 = EPRI(mtarg)->shralign; /* MAR */
+ else
+ faith2 = FALSE;
/* Never target quest friendlies */
if (mtarg->data->msound == MS_LEADER
|| mtarg->data->msound == MS_GUARDIAN)
return -5000L;
-
/* D: Fixed angelic beings using gaze attacks on coaligned priests */
if (faith1 && faith2 && align1 == align2 && mtarg->mpeaceful) {
score -= 5000L;
return score;
}
-
/* Is monster adjacent? */
if (distmin(mtmp->mx, mtmp->my, mtarg->mx, mtarg->my) <= 1) {
score -= 3000L;
return score;
}
-
/* Is the monster peaceful or tame? */
if (/*mtarg->mpeaceful ||*/ mtarg->mtame || mtarg == &youmonst) {
/* Pets will never be targeted */
score -= 3000L;
return score;
}
-
- /* Is master/pet behind monster? Check up to 15 squares beyond
- * pet.
- */
+ /* Is master/pet behind monster? Check up to 15 squares beyond pet. */
if (find_friends(mtmp, mtarg, 15)) {
score -= 3000L;
return score;
}
-
/* Target hostile monsters in preference to peaceful ones */
if (!mtarg->mpeaceful)
score += 10;
-
/* Is the monster passive? Don't waste energy on it, if so */
if (mtarg->data->mattk[0].aatyp == AT_NONE)
score -= 1000;
-
/* Even weak pets with breath attacks shouldn't take on very
- * low-level monsters. Wasting breath on lichens is ridiculous.
- */
+ low-level monsters. Wasting breath on lichens is ridiculous. */
if ((mtarg->m_lev < 2 && mtmp->m_lev > 5)
|| (mtmp->m_lev > 12 && mtarg->m_lev < mtmp->m_lev - 9
&& u.ulevel > 8 && mtarg->m_lev < u.ulevel - 7))
score -= 25;
-
/* And pets will hesitate to attack vastly stronger foes.
- * This penalty will be discarded if master's in trouble.
- */
+ This penalty will be discarded if master's in trouble. */
if (mtarg->m_lev > mtmp->m_lev + 4L)
score -= (mtarg->m_lev - mtmp->m_lev) * 20L;
-
/* All things being the same, go for the beefiest monster. This
- * bonus should not be large enough to override the pet's aversion
- * to attacking much stronger monsters.
- */
+ bonus should not be large enough to override the pet's aversion
+ to attacking much stronger monsters. */
score += mtarg->m_lev * 2 + mtarg->mhp / 3;
}
-
/* Fuzz factor to make things less predictable when very
- * similar targets are abundant
- */
+ similar targets are abundant. */
score += rnd(5);
-
/* Pet may decide not to use ranged attack when confused */
if (mtmp->mconf && !rn2(3))
score -= 1000;
-
return score;
}
}
/* Pet hasn't attacked anything but is considering moving -
- * now's the time for ranged attacks. Note that the pet can
- * move after it performs its ranged attack. Should this be
- * changed?
+ * 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;
mstatus = mattackm(mtmp, mtarg);
/* Shouldn't happen, really */
- if (mstatus & MM_AGR_DIED) return 2;
+ if (mstatus & MM_AGR_DIED)
+ return 2;
/* Allow the targeted nasty to strike back - if
* the targeted beast doesn't have a ranged attack,
*/
if (mtarg->mcansee && haseyes(mtarg->data)) {
mstatus = mattackm(mtarg, mtmp);
- if (mstatus & MM_DEF_DIED) return 2;
+ if (mstatus & MM_DEF_DIED)
+ return 2;
}
}
}
/* describe top item of pile, not necessarily cursed item itself;
don't use glyph_at() here--it would return the pet but we want
to know whether an object is remembered at this map location */
- struct obj *o = (!Hallucination
+ struct obj *o = (!Hallucination && level.flags.hero_memory
&& glyph_is_object(levl[nix][niy].glyph))
? vobj_at(nix, niy) : 0;
const char *what = o ? distant_name(o, doname) : something;
int x, y;
genericptr_t distance;
{
- int ndist;
+ int ndist, *dist_ptr = (int *) distance;
- if (*(int *) distance > (ndist = distu(x, y))) {
+ if (*dist_ptr > (ndist = distu(x, y))) {
gx = x;
gy = y;
- *(int *) distance = ndist;
+ *dist_ptr = ndist;
}
}
u.ugrave_arise = NON_PM;
HUnchanging = 0L;
curs_on_u();
+ if (!context.mon_moving)
+ endmultishot(FALSE);
}
/*
attk = 1;
switch (mattk->aatyp) {
case AT_WEAP: /* "hand to hand" attacks */
- if (distmin(magr->mx,magr->my,mdef->mx,mdef->my) > 1) {
+ if (distmin(magr->mx, magr->my, mdef->mx, mdef->my) > 1) {
/* D: Do a ranged attack here! */
strike = thrwmm(magr, mdef);
if (DEADMONSTER(mdef))
res[i] = MM_DEF_DIED;
-
if (DEADMONSTER(magr))
res[i] |= MM_AGR_DIED;
-
break;
}
if (magr->weapon_check == NEED_WEAPON || !MON_WEP(magr)) {
case AT_TENT:
/* Nymph that teleported away on first attack? */
if (distmin(magr->mx, magr->my, mdef->mx, mdef->my) > 1)
- /* Continue because the monster may have a ranged
- * attack */
+ /* Continue because the monster may have a ranged attack. */
continue;
/* Monsters won't attack cockatrices physically if they
* have a weapon instead. This instinct doesn't work for
break;
case AT_ENGL:
- if (u.usteed && (mdef == u.usteed)) {
+ if (u.usteed && mdef == u.usteed) {
strike = 0;
break;
}
/* D: Prevent engulf from a distance */
- if (distmin(magr->mx,magr->my,mdef->mx,mdef->my) > 1)
+ if (distmin(magr->mx, magr->my, mdef->mx, mdef->my) > 1)
continue;
- /* Engulfing attacks are directed at the hero if
- * possible. -dlc
- */
+ /* Engulfing attacks are directed at the hero if possible. -dlc */
if (u.uswallow && magr == u.ustuck)
strike = 0;
- else {
- if ((strike = (tmp > rnd(20 + i))))
- res[i] = gulpmm(magr, mdef, mattk);
- else
- missmm(magr, mdef, mattk);
- }
+ else if ((strike = (tmp > rnd(20 + i))) != 0)
+ res[i] = gulpmm(magr, mdef, mattk);
+ else
+ missmm(magr, mdef, mattk);
break;
case AT_BREA:
if (!monnear(magr, mdef->mx, mdef->my)) {
strike = breamm(magr, mattk, mdef);
- /* We don't really know if we hit or not, but pretend
- * we did */
- if (strike) res[i] |= MM_HIT;
- if (DEADMONSTER(mdef)) res[i] = MM_DEF_DIED;
- if (DEADMONSTER(magr)) res[i] |= MM_AGR_DIED;
+ /* We don't really know if we hit or not; pretend we did. */
+ if (strike)
+ res[i] |= MM_HIT;
+ if (DEADMONSTER(mdef))
+ res[i] = MM_DEF_DIED;
+ if (DEADMONSTER(magr))
+ res[i] |= MM_AGR_DIED;
}
else
strike = 0;
break;
+
case AT_SPIT:
if (!monnear(magr, mdef->mx, mdef->my)) {
strike = spitmm(magr, mattk, mdef);
- /* We don't really know if we hit or not, but pretend
- * we did */
- if (strike) res[i] |= MM_HIT;
- if (DEADMONSTER(mdef)) res[i] = MM_DEF_DIED;
- if (DEADMONSTER(magr)) res[i] |= MM_AGR_DIED;
+ /* We don't really know if we hit or not; pretend we did. */
+ if (strike)
+ res[i] |= MM_HIT;
+ if (DEADMONSTER(mdef))
+ res[i] = MM_DEF_DIED;
+ if (DEADMONSTER(magr))
+ res[i] |= MM_AGR_DIED;
}
break;
+
default: /* no attack */
strike = 0;
attk = 0;
}
if (attk && !(res[i] & MM_AGR_DIED)
- && distmin(magr->mx,magr->my,mdef->mx,mdef->my) <= 1)
+ && distmin(magr->mx, magr->my, mdef->mx, mdef->my) <= 1)
res[i] = passivemm(magr, mdef, strike, res[i] & MM_DEF_DIED);
if (res[i] & MM_DEF_DIED)
return res[i];
-
if (res[i] & MM_AGR_DIED)
return res[i];
/* return if aggressor can no longer attack */
pline("%s %s...", buf, mon_nam(mdef));
}
- if (magr->mcan || !magr->mcansee
- || (magr->minvis && !perceives(mdef->data)) || !mdef->mcansee
- || mdef->msleeping) {
+ if (magr->mcan || !magr->mcansee || !mdef->mcansee
+ || (magr->minvis && !perceives(mdef->data)) || mdef->msleeping) {
if (vis)
pline("but nothing happens.");
return MM_MISS;
if (mdef->mcansee) {
if (mon_reflects(magr, (char *) 0)) {
if (canseemon(magr))
- (void) mon_reflects(
- magr, "The gaze is reflected away by %s %s.");
+ (void) mon_reflects(magr,
+ "The gaze is reflected away by %s %s.");
return MM_MISS;
}
if (mdef->minvis && !perceives(magr->data)) {
} else if (status & MM_AGR_DIED) { /* aggressor died */
place_monster(mdef, dx, dy);
newsym(dx, dy);
- } else { /* both alive, put them back */
+ } else { /* both alive, put them back */
if (cansee(dx, dy))
pline("%s is regurgitated!", Monnam(mdef));
*/
{
struct obj *gold = findgold(mdef->minvent);
+
if (!gold)
break;
obj_extract_self(gold);
STATIC_VAR NEARDATA struct obj *otmp;
STATIC_DCL boolean FDECL(u_slip_free, (struct monst *, struct attack *));
-STATIC_DCL int FDECL(passiveum,
- (struct permonst *, struct monst *, struct attack *));
-
+STATIC_DCL int FDECL(passiveum, (struct permonst *, struct monst *,
+ struct attack *));
STATIC_DCL void FDECL(mayberem, (struct obj *, const char *));
-
STATIC_DCL boolean FDECL(diseasemu, (struct permonst *));
STATIC_DCL int FDECL(hitmu, (struct monst *, struct attack *));
STATIC_DCL int FDECL(gulpmu, (struct monst *, struct attack *));
STATIC_DCL void FDECL(missmu, (struct monst *, BOOLEAN_P, struct attack *));
STATIC_DCL void FDECL(mswings, (struct monst *, struct obj *));
STATIC_DCL void FDECL(wildmiss, (struct monst *, struct attack *));
-
STATIC_DCL void FDECL(hitmsg, (struct monst *, struct attack *));
/* See comment in mhitm.c. If we use this a lot it probably should be */
register struct attack *mattk;
{
int compat;
+ const char *pfmt = 0;
+ char *Monst_name = Monnam(mtmp);
/* Note: if opposite gender, "seductively" */
/* If same gender, "engagingly" for nymph, normal msg for others */
- if ((compat = could_seduce(mtmp, &youmonst, mattk)) && !mtmp->mcan
- && !mtmp->mspec_used) {
- pline("%s %s you %s.", Monnam(mtmp), Blind ? "talks to" : "smiles at",
- compat == 2 ? "engagingly" : "seductively");
- } else
+ if ((compat = could_seduce(mtmp, &youmonst, mattk)) != 0
+ && !mtmp->mcan && !mtmp->mspec_used) {
+ pline("%s %s you %s.", Monst_name,
+ Blind ? "talks to" : "smiles at",
+ (compat == 2) ? "engagingly" : "seductively");
+ } else {
switch (mattk->aatyp) {
case AT_BITE:
- pline("%s bites!", Monnam(mtmp));
+ pfmt = "%s bites!";
break;
case AT_KICK:
- pline("%s kicks%c", Monnam(mtmp),
+ pline("%s kicks%c", Monst_name,
thick_skinned(youmonst.data) ? '.' : '!');
break;
case AT_STNG:
- pline("%s stings!", Monnam(mtmp));
+ pfmt = "%s stings!";
break;
case AT_BUTT:
- pline("%s butts!", Monnam(mtmp));
+ pfmt = "%s butts!";
break;
case AT_TUCH:
- pline("%s touches you!", Monnam(mtmp));
+ pfmt = "%s touches you!";
break;
case AT_TENT:
- pline("%s tentacles suck you!", s_suffix(Monnam(mtmp)));
+ pfmt = "%s tentacles suck you!";
+ Monst_name = s_suffix(Monst_name);
break;
case AT_EXPL:
case AT_BOOM:
- pline("%s explodes!", Monnam(mtmp));
+ pfmt = "%s explodes!";
break;
default:
- pline("%s hits!", Monnam(mtmp));
+ pfmt = "%s hits!";
}
+ if (pfmt)
+ pline(pfmt, Monst_name);
+ }
}
/* monster missed you */
register struct attack *mattk;
{
int compat;
+ const char *Monst_name; /* Monnam(mtmp) */
/* no map_invisible() -- no way to tell where _this_ is coming from */
compat = ((mattk->adtyp == AD_SEDU || mattk->adtyp == AD_SSEX)
&& could_seduce(mtmp, &youmonst, (struct attack *) 0));
+ Monst_name = Monnam(mtmp);
if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) {
- const char *swings =
- mattk->aatyp == AT_BITE
- ? "snaps"
- : mattk->aatyp == AT_KICK
- ? "kicks"
- : (mattk->aatyp == AT_STNG || mattk->aatyp == AT_BUTT
- || nolimbs(mtmp->data))
- ? "lunges"
- : "swings";
+ const char *swings = (mattk->aatyp == AT_BITE) ? "snaps"
+ : (mattk->aatyp == AT_KICK) ? "kicks"
+ : (mattk->aatyp == AT_STNG
+ || mattk->aatyp == AT_BUTT
+ || nolimbs(mtmp->data)) ? "lunges"
+ : "swings";
if (compat)
- pline("%s tries to touch you and misses!", Monnam(mtmp));
+ pline("%s tries to touch you and misses!", Monst_name);
else
switch (rn2(3)) {
case 0:
- pline("%s %s wildly and misses!", Monnam(mtmp), swings);
+ pline("%s %s wildly and misses!", Monst_name, swings);
break;
case 1:
- pline("%s attacks a spot beside you.", Monnam(mtmp));
+ pline("%s attacks a spot beside you.", Monst_name);
break;
case 2:
- pline("%s strikes at %s!", Monnam(mtmp),
- levl[mtmp->mux][mtmp->muy].typ == WATER ? "empty water"
- : "thin air");
+ pline("%s strikes at %s!", Monst_name,
+ (levl[mtmp->mux][mtmp->muy].typ == WATER)
+ ? "empty water"
+ : "thin air");
break;
default:
- pline("%s %s wildly!", Monnam(mtmp), swings);
+ pline("%s %s wildly!", Monst_name, swings);
break;
}
} else if (Displaced) {
if (compat)
- pline("%s smiles %s at your %sdisplaced image...", Monnam(mtmp),
- compat == 2 ? "engagingly" : "seductively",
+ pline("%s smiles %s at your %sdisplaced image...", Monst_name,
+ (compat == 2) ? "engagingly" : "seductively",
Invis ? "invisible " : "");
else
pline("%s strikes at your %sdisplaced image and misses you!",
* displaced image, since the displaced image is also
* invisible.
*/
- Monnam(mtmp), Invis ? "invisible " : "");
+ Monst_name, Invis ? "invisible " : "");
} else if (Underwater) {
/* monsters may miss especially on water level where
bubbles shake the player here and there */
if (compat)
- pline("%s reaches towards your distorted image.", Monnam(mtmp));
+ pline("%s reaches towards your distorted image.", Monst_name);
else
pline("%s is fooled by water reflections and misses!",
- Monnam(mtmp));
+ Monst_name);
} else
impossible("%s attacks you without knowing your location?",
- Monnam(mtmp));
+ Monst_name);
}
void
boolean message;
{
if (message) {
- if (is_animal(mdat))
+ if (is_animal(mdat)) {
You("get regurgitated!");
- else {
+ } else {
char blast[40];
register int i;
for (i = 0; i < NATTK; i++)
if (mdat->mattk[i].aatyp == AT_ENGL)
break;
- if (mdat->mattk[i].aatyp != AT_ENGL)
+ if (mdat->mattk[i].aatyp != AT_ENGL) {
impossible("Swallower has no engulfing attack?");
- else {
+ } else {
if (is_whirly(mdat)) {
switch (mdat->mattk[i].adtyp) {
case AD_ELEC:
&& !(mptr->mattk[1].aatyp == AT_WEAP
&& mptr->mattk[1].adtyp == AD_PHYS)
&& (magr->mcan
- || (weap
- && ((weap->otyp == CORPSE
- && touch_petrifies(&mons[weap->corpsenm]))
- || weap->oartifact == ART_STORMBRINGER
- || weap->oartifact == ART_VORPAL_BLADE)))) {
+ || (weap && ((weap->otyp == CORPSE
+ && touch_petrifies(&mons[weap->corpsenm]))
+ || weap->oartifact == ART_STORMBRINGER
+ || weap->oartifact == ART_VORPAL_BLADE)))) {
*alt_attk_buf = *attk;
attk = alt_attk_buf;
attk->adtyp = AD_PHYS;
break;
case AD_LEGS: {
register long side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE;
- const char *sidestr = (side == RIGHT_SIDE) ? "right" : "left";
+ const char *sidestr = (side == RIGHT_SIDE) ? "right" : "left",
+ *Monst_name = Monnam(mtmp), *leg = body_part(LEG);
/* This case is too obvious to ignore, but Nethack is not in
* general very good at considering height--most short monsters
* [FIXME: why can't a flying attacker overcome this?]
*/
if (u.usteed || Levitation || Flying) {
- pline("%s tries to reach your %s %s!", Monnam(mtmp), sidestr,
- body_part(LEG));
+ pline("%s tries to reach your %s %s!", Monst_name, sidestr, leg);
dmg = 0;
} else if (mtmp->mcan) {
- pline("%s nuzzles against your %s %s!", Monnam(mtmp), sidestr,
- body_part(LEG));
+ pline("%s nuzzles against your %s %s!", Monnam(mtmp),
+ sidestr, leg);
dmg = 0;
} else {
if (uarmf) {
if (rn2(2) && (uarmf->otyp == LOW_BOOTS
- || uarmf->otyp == IRON_SHOES))
+ || uarmf->otyp == IRON_SHOES)) {
pline("%s pricks the exposed part of your %s %s!",
- Monnam(mtmp), sidestr, body_part(LEG));
- else if (!rn2(5))
- pline("%s pricks through your %s boot!", Monnam(mtmp),
+ Monst_name, sidestr, leg);
+ } else if (!rn2(5)) {
+ pline("%s pricks through your %s boot!", Monst_name,
sidestr);
- else {
- pline("%s scratches your %s boot!", Monnam(mtmp),
+ } else {
+ pline("%s scratches your %s boot!", Monst_name,
sidestr);
dmg = 0;
break;
}
} else
- pline("%s pricks your %s %s!", Monnam(mtmp), sidestr,
- body_part(LEG));
+ pline("%s pricks your %s %s!", Monst_name, sidestr, leg);
+
set_wounded_legs(side, rnd(60 - ACURR(A_DEX)));
exercise(A_STR, FALSE);
exercise(A_DEX, FALSE);
(void) rloc(mtmp, TRUE);
return 3;
} else if (mtmp->mcan) {
- if (!Blind) {
+ if (!Blind)
pline("%s tries to %s you, but you seem %s.",
Adjmonnam(mtmp, "plain"),
flags.female ? "charm" : "seduce",
flags.female ? "unaffected" : "uninterested");
- }
if (rn2(3)) {
if (!tele_restrict(mtmp))
(void) rloc(mtmp, TRUE);
newsym(mtmp->mx, mtmp->my);
if (is_animal(mtmp->data) && u.usteed) {
char buf[BUFSZ];
+
/* Too many quirks presently if hero and steed
* are swallowed. Pretend purple worms don't
* like horses for now :-)
#include "hack.h"
+STATIC_DCL int FDECL(monmulti, (struct monst *, struct obj *, struct obj *));
+STATIC_DCL void FDECL(monshoot, (struct monst *, struct obj *, struct obj *));
STATIC_DCL int FDECL(drop_throw, (struct obj *, BOOLEAN_P, int, int));
STATIC_DCL boolean FDECL(m_lined_up, (struct monst *, struct monst *));
|| !strncmpi(name, "a ", 2))
kprefix = KILLED_BY;
}
- onm = (obj && obj_is_pname(obj)) ? the(name) : (obj && obj->quan > 1L)
- ? name
- : an(name);
+ onm = (obj && obj_is_pname(obj)) ? the(name)
+ : (obj && obj->quan > 1L) ? name
+ : an(name);
is_acid = (obj && obj->otyp == ACID_VENOM);
if (u.uac + tlev <= rnd(20)) {
pline_The("silver sears your flesh!");
exercise(A_CON, FALSE);
}
- if (is_acid && Acid_resistance)
+ if (is_acid && Acid_resistance) {
pline("It doesn't seem to hurt you.");
- else {
+ } else {
if (is_acid)
pline("It burns!");
losehp(dam, knm, kprefix); /* acid damage */
if (down_gate(x, y) != -1)
objgone = ship_object(obj, x, y, FALSE);
if (!objgone) {
- if (!flooreffects(obj, x, y,
- "fall")) { /* don't double-dip on damage */
+ if (!flooreffects(obj, x, y, "fall")) {
place_object(obj, x, y);
if (!mtmp && x == u.ux && y == u.uy)
mtmp = &youmonst;
/* The monster that's doing the shooting/throwing */
STATIC_OVL struct monst *archer = 0;
+/* calculate multishot volley count for mtmp throwing otmp (if not ammo) or
+ shooting otmp with mwep (if otmp is ammo and mwep appropriate launcher) */
+STATIC_OVL int
+monmulti(mtmp, otmp, mwep)
+struct monst *mtmp;
+struct obj *otmp, *mwep;
+{
+ int skill = (int) objects[otmp->otyp].oc_skill;
+ int multishot = 1;
+
+ if (otmp->quan > 1L /* no point checking if there's only 1 */
+ /* ammo requires corresponding launcher be wielded */
+ && (is_ammo(otmp)
+ ? matching_launcher(otmp, mwep)
+ /* otherwise any stackable (non-ammo) weapon */
+ : otmp->oclass == WEAPON_CLASS)
+ && !mtmp->mconf) {
+ /* Assumes lords are skilled, princes are expert */
+ if (is_prince(mtmp->data))
+ multishot += 2;
+ else if (is_lord(mtmp->data))
+ multishot++;
+ /* fake players treated as skilled (regardless of role limits) */
+ else if (is_mplayer(mtmp->data))
+ multishot++;
+
+ /* this portion is different from hero multishot; from slash'em?
+ */
+ /* Elven Craftsmanship makes for light, quick bows */
+ if (otmp->otyp == ELVEN_ARROW && !otmp->cursed)
+ multishot++;
+ if (ammo_and_launcher(otmp, uwep) && mwep->otyp == ELVEN_BOW
+ && !mwep->cursed)
+ multishot++;
+ /* 1/3 of launcher enchantment */
+ if (ammo_and_launcher(otmp, mwep) && mwep->spe > 1)
+ multishot += (long) rounddiv(mwep->spe, 3);
+ /* Some randomness */
+ multishot = (long) rnd((int) multishot);
+
+ /* class bonus */
+ switch (monsndx(mtmp->data)) {
+ case PM_CAVEMAN: /* give bonus for low-tech gear */
+ if (skill == -P_SLING || skill == P_SPEAR)
+ multishot++;
+ break;
+ case PM_MONK: /* allow higher volley count */
+ if (skill == -P_SHURIKEN)
+ multishot++;
+ break;
+ case PM_RANGER:
+ if (skill != P_DAGGER)
+ multishot++;
+ break;
+ case PM_ROGUE:
+ if (skill == P_DAGGER)
+ multishot++;
+ break;
+ case PM_NINJA:
+ if (skill == -P_SHURIKEN || skill == -P_DART)
+ multishot++;
+ /*FALLTHRU*/
+ case PM_SAMURAI:
+ if (otmp->otyp == YA && mwep->otyp == YUMI)
+ multishot++;
+ break;
+ default:
+ break;
+ }
+ /* racial bonus */
+ if ((is_elf(mtmp->data) && otmp->otyp == ELVEN_ARROW
+ && mwep->otyp == ELVEN_BOW)
+ || (is_orc(mtmp->data) && otmp->otyp == ORCISH_ARROW
+ && mwep->otyp == ORCISH_BOW)
+ || (is_gnome(mtmp->data) && otmp->otyp == CROSSBOW_BOLT
+ && mwep->otyp == CROSSBOW))
+ multishot++;
+ }
+
+ if (otmp->quan < multishot)
+ multishot = (int) otmp->quan;
+ if (multishot < 1)
+ multishot = 1;
+ return multishot;
+}
+
+/* mtmp throws otmp, or shoots otmp with mwep, at hero or at monster mtarg */
+STATIC_OVL void
+monshoot(mtmp, otmp, mwep)
+struct monst *mtmp;
+struct obj *otmp, *mwep;
+{
+ struct monst *mtarg = target;
+ int dm = distmin(mtmp->mx, mtmp->my,
+ mtarg ? mtarg->mx : mtmp->mux,
+ mtarg ? mtarg->my : mtmp->muy),
+ multishot = monmulti(mtmp, otmp, mwep);
+ /*
+ * Caller must have called linedup() to set up tbx, tby.
+ */
+
+ if (canseemon(mtmp)) {
+ const char *onm;
+ char onmbuf[BUFSZ], trgbuf[BUFSZ];
+
+ if (multishot > 1) {
+ /* "N arrows"; multishot > 1 implies otmp->quan > 1, so
+ xname()'s result will already be pluralized */
+ Sprintf(onmbuf, "%d %s", multishot, xname(otmp));
+ onm = onmbuf;
+ } else {
+ /* "an arrow" */
+ onm = singular(otmp, xname);
+ onm = obj_is_pname(otmp) ? the(onm) : an(onm);
+ }
+ m_shot.s = ammo_and_launcher(otmp, mwep) ? TRUE : FALSE;
+ Strcpy(trgbuf, mtarg ? mon_nam(mtarg) : "");
+ if (!strcmp(trgbuf, "it"))
+ Strcpy(trgbuf, humanoid(mtmp->data) ? "someone" : something);
+ pline("%s %s %s%s%s!", Monnam(mtmp),
+ m_shot.s ? "shoots" : "throws", onm,
+ mtarg ? " at " : "", trgbuf);
+ m_shot.o = otmp->otyp;
+ } else {
+ m_shot.o = STRANGE_OBJECT; /* don't give multishot feedback */
+ }
+ m_shot.n = multishot;
+ for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
+ m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), dm, otmp);
+ /* conceptually all N missiles are in flight at once, but
+ if mtmp gets killed (shot kills adjacent gas spore and
+ triggers explosion, perhaps), inventory will be dropped
+ and otmp might go away via merging into another stack */
+ if (mtmp->mhp <= 0 && m_shot.i < m_shot.n)
+ /* cancel pending shots (perhaps ought to give a message here
+ since we gave one above about throwing/shooting N missiles) */
+ break; /* endmultishot(FALSE); */
+ }
+ /* reset 'm_shot' */
+ m_shot.n = m_shot.i = 0;
+ m_shot.o = STRANGE_OBJECT;
+ m_shot.s = FALSE;
+}
+
/* an object launched by someone/thing other than player attacks a monster;
return 1 if the object has stopped moving (hit or its range used up) */
int
if (vis || (verbose && !target))
pline("%s is %s!", Monnam(mtmp),
(nonliving(mtmp->data) || is_vampshifter(mtmp)
- || !canspotmon(mtmp))
- ? "destroyed"
- : "killed");
+ || !canspotmon(mtmp)) ? "destroyed" : "killed");
/* don't blame hero for unknown rolling boulder trap */
if (!context.mon_moving
&& (otmp->otyp != BOULDER || range >= 0 || otmp->otrapped))
}
if (can_blnd((struct monst *) 0, mtmp,
- (uchar) (otmp->otyp == BLINDING_VENOM ? AT_SPIT
- : AT_WEAP),
+ (uchar) ((otmp->otyp == BLINDING_VENOM) ? AT_SPIT
+ : AT_WEAP),
otmp)) {
if (vis && mtmp->mcansee)
pline("%s is blinded by %s.", Monnam(mtmp), the(xname(otmp)));
struct monst *mtmp;
struct obj *singleobj;
char sym = obj->oclass;
- int hitu, oldumort, blindinc = 0;
+ int hitu = 0, oldumort, blindinc = 0;
bhitpos.x = x;
bhitpos.y = y;
You(
"accept %s gift in the spirit in which it was intended.",
s_suffix(mon_nam(mon)));
- (void) hold_another_object(
- singleobj, "You catch, but drop, %s.",
- xname(singleobj), "You catch:");
+ (void) hold_another_object(singleobj,
+ "You catch, but drop, %s.",
+ xname(singleobj),
+ "You catch:");
}
break;
}
(u.umortality > oldumort) ? 0 : 10, TRUE);
}
if (hitu && can_blnd((struct monst *) 0, &youmonst,
- (uchar) (singleobj->otyp == BLINDING_VENOM
+ (uchar) ((singleobj->otyp == BLINDING_VENOM)
? AT_SPIT
: AT_WEAP),
singleobj)) {
}
}
stop_occupation();
- if (hitu || !range) {
- (void) drop_throw(singleobj, hitu, u.ux, u.uy);
+ if (hitu) {
+ range = 0;
break;
}
}
!rn2(5), 0))
/* Thrown objects "sink" */
|| IS_SINK(levl[bhitpos.x][bhitpos.y].typ)) {
- if (singleobj) /* hits_bars might have destroyed it */
+ if (singleobj) { /* hits_bars might have destroyed it */
+ if (m_shot.n > 1 && (cansee(bhitpos.x, bhitpos.y)
+ || (archer && canseemon(archer))))
+ pline("%s misses.", The(mshot_xname(singleobj)));
(void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
+ }
break;
}
tmp_at(bhitpos.x, bhitpos.y);
}
}
+/* Monster throws item at another monster */
int
-thrwmm(mtmp, mtarg) /* Monster throws item at monster */
+thrwmm(mtmp, mtarg)
struct monst *mtmp, *mtarg;
{
struct obj *otmp, *mwep;
register xchar x, y;
boolean ispole;
- schar skill;
- int multishot = 1;
/* Polearms won't be applied by monsters against other monsters */
if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
mtmp->weapon_check = NEED_RANGED_WEAPON;
/* mon_wield_item resets weapon_check as appropriate */
- if(mon_wield_item(mtmp) != 0) return 0;
+ if (mon_wield_item(mtmp) != 0)
+ return 0;
}
/* Pick a weapon */
otmp = select_rwep(mtmp);
- if (!otmp) return 0;
+ if (!otmp)
+ return 0;
ispole = is_pole(otmp);
- skill = objects[otmp->otyp].oc_skill;
x = mtmp->mx;
y = mtmp->my;
mwep = MON_WEP(mtmp); /* wielded weapon */
- if(!ispole && m_lined_up(mtarg, mtmp)) {
- /* WAC Catch this since rn2(0) is illegal */
- int chance = (BOLT_LIM-distmin(x,y,mtarg->mx,mtarg->my) > 0) ?
- BOLT_LIM-distmin(x,y,mtarg->mx,mtarg->my) : 1;
-
- if(!mtarg->mflee || !rn2(chance)) {
- const char *verb = "throws";
-
- if (otmp->otyp == ARROW
- || otmp->otyp == ELVEN_ARROW
- || otmp->otyp == ORCISH_ARROW
- || otmp->otyp == YA
- || otmp->otyp == CROSSBOW_BOLT) verb = "shoots";
-
- if (ammo_and_launcher(otmp, mwep) && is_launcher(mwep)) {
- if (dist2(mtmp->mx, mtmp->my, mtarg->mx, mtarg->my) >
- PET_MISSILE_RANGE2)
- return 0; /* Out of range */
- }
-
- if (canseemon(mtmp)) {
- pline("%s %s %s!", Monnam(mtmp), verb,
- obj_is_pname(otmp) ?
- the(singular(otmp, xname)) :
- an(singular(otmp, xname)));
- }
-
- /* Multishot calculations */
- if ((ammo_and_launcher(otmp, mwep) || skill == P_DAGGER
- || skill == -P_DART || skill == -P_SHURIKEN)
- && !mtmp->mconf) {
- /* Assumes lords are skilled, princes are expert */
- if (is_lord(mtmp->data)) multishot++;
- if (is_prince(mtmp->data)) multishot += 2;
-
- /* Elven Craftsmanship makes for light, quick bows */
- if (otmp->otyp == ELVEN_ARROW && !otmp->cursed)
- multishot++;
- if (mwep && mwep->otyp == ELVEN_BOW &&
- !mwep->cursed) multishot++;
- /* 1/3 of object enchantment */
- if (mwep && mwep->spe > 1)
- multishot += (long) rounddiv(mwep->spe,3);
- /* Some randomness */
- if (multishot > 1L)
- multishot = (long) rnd((int) multishot);
-
- switch (monsndx(mtmp->data)) {
- case PM_RANGER:
- multishot++;
- break;
- case PM_ROGUE:
- if (skill == P_DAGGER) multishot++;
- break;
- case PM_SAMURAI:
- if (otmp->otyp == YA && mwep &&
- mwep->otyp == YUMI) multishot++;
- break;
- default:
- break;
- }
- { /* racial bonus */
- if (is_elf(mtmp->data) &&
- otmp->otyp == ELVEN_ARROW &&
- mwep && mwep->otyp == ELVEN_BOW)
- multishot++;
- else if (is_orc(mtmp->data) &&
- otmp->otyp == ORCISH_ARROW &&
- mwep && mwep->otyp == ORCISH_BOW)
- multishot++;
- }
-
- }
- if (otmp->quan < multishot) multishot = (int)otmp->quan;
- if (multishot < 1) multishot = 1;
+ if (!ispole && m_lined_up(mtarg, mtmp)) {
+ int chance = max(BOLT_LIM - distmin(x, y, mtarg->mx, mtarg->my), 1);
+ if (!mtarg->mflee || !rn2(chance)) {
+ if (ammo_and_launcher(otmp, mwep)
+ && dist2(mtmp->mx, mtmp->my, mtarg->mx, mtarg->my)
+ > PET_MISSILE_RANGE2)
+ return 0; /* Out of range */
/* Set target monster */
target = mtarg;
archer = mtmp;
- while (multishot-- > 0)
- m_throw(mtmp, mtmp->mx, mtmp->my,
- sgn(tbx), sgn(tby),
- distmin(mtmp->mx, mtmp->my,
- mtarg->mx, mtarg->my),
- otmp);
- archer = (struct monst *)0;
- target = (struct monst *)0;
+ monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */
+ archer = target = (struct monst *) 0;
nomul(0);
return 1;
}
return 0;
}
-
/* monster spits substance at monster */
int
spitmm(mtmp, mattk, mtarg)
return 0;
}
+/* monster breathes at monster (ranged) */
int
-breamm(mtmp, mattk, mtarg) /* monster breathes at monster (ranged) */
+breamm(mtmp, mattk, mtarg)
struct monst *mtmp, *mtarg;
struct attack *mattk;
{
else
You_hear("a cough.");
}
- return(0);
+ return 0;
}
if (!mtmp->mspec_used && rn2(3)) {
if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
if (canseemon(mtmp))
- pline("%s breathes %s!", Monnam(mtmp),
- breathwep[typ-1]);
- dobuzz((int) (-20 - (typ-1)), (int)mattk->damn,
+ pline("%s breathes %s!", Monnam(mtmp), breathwep[typ - 1]);
+ dobuzz((int) (-20 - (typ - 1)), (int)mattk->damn,
mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), FALSE);
nomul(0);
/* breath runs out sometimes. Also, give monster some
* cunning; don't breath if the target fell asleep.
*/
- mtmp->mspec_used = 6+rn2(18);
+ mtmp->mspec_used = 6 + rn2(18);
/* If this is a pet, it'll get hungry. Minions and
* spell beings won't hunger */
}
} else impossible("Breath weapon %d used", typ-1);
} else
- return (0);
+ return 0;
}
- return(1);
+ return 1;
}
{
struct obj *otmp, *mwep;
xchar x, y;
- int multishot;
const char *onm;
/* Rearranged beginning so monsters can use polearms not in a line */
return;
mwep = MON_WEP(mtmp); /* wielded weapon */
-
- /* Multishot calculations */
- multishot = 1;
- if (otmp->quan > 1L /* no point checking if there's only 1 */
- /* ammo requires corresponding launcher be wielded */
- && (is_ammo(otmp)
- ? matching_launcher(otmp, mwep)
- /* otherwise any stackable (non-ammo) weapon */
- : otmp->oclass == WEAPON_CLASS)
- && !mtmp->mconf) {
- int skill = (int) objects[otmp->otyp].oc_skill;
-
- /* Assumes lords are skilled, princes are expert */
- if (is_prince(mtmp->data))
- multishot += 2;
- else if (is_lord(mtmp->data))
- multishot++;
- /* fake players treated as skilled (regardless of role limits) */
- else if (is_mplayer(mtmp->data))
- multishot++;
-
- /* class bonus */
- switch (monsndx(mtmp->data)) {
- case PM_MONK:
- if (skill == -P_SHURIKEN)
- multishot++;
- break;
- case PM_RANGER:
- multishot++;
- break;
- case PM_ROGUE:
- if (skill == P_DAGGER)
- multishot++;
- break;
- case PM_NINJA:
- if (skill == -P_SHURIKEN || skill == -P_DART)
- multishot++;
- /*FALLTHRU*/
- case PM_SAMURAI:
- if (otmp->otyp == YA && mwep && mwep->otyp == YUMI)
- multishot++;
- break;
- default:
- break;
- }
- /* racial bonus */
- if ((is_elf(mtmp->data) && otmp->otyp == ELVEN_ARROW && mwep
- && mwep->otyp == ELVEN_BOW)
- || (is_orc(mtmp->data) && otmp->otyp == ORCISH_ARROW && mwep
- && mwep->otyp == ORCISH_BOW))
- multishot++;
-
- multishot = rnd(multishot);
- if ((long) multishot > otmp->quan)
- multishot = (int) otmp->quan;
- }
-
- if (canseemon(mtmp)) {
- char onmbuf[BUFSZ];
-
- if (multishot > 1) {
- /* "N arrows"; multishot > 1 implies otmp->quan > 1, so
- xname()'s result will already be pluralized */
- Sprintf(onmbuf, "%d %s", multishot, xname(otmp));
- onm = onmbuf;
- } else {
- /* "an arrow" */
- onm = singular(otmp, xname);
- onm = obj_is_pname(otmp) ? the(onm) : an(onm);
- }
- m_shot.s = ammo_and_launcher(otmp, mwep) ? TRUE : FALSE;
- pline("%s %s %s!", Monnam(mtmp), m_shot.s ? "shoots" : "throws", onm);
- m_shot.o = otmp->otyp;
- } else {
- m_shot.o = STRANGE_OBJECT; /* don't give multishot feedback */
- }
-
- m_shot.n = multishot;
- for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
- m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
- distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp);
- /* conceptually all N missiles are in flight at once, but
- if mtmp gets killed (shot kills adjacent gas spore and
- triggers explosion, perhaps), inventory will be dropped
- and otmp might go away via merging into another stack */
- if (mtmp->mhp <= 0 && m_shot.i < m_shot.n) {
- /* cancel pending shots (ought to give a message here since
- we gave one above about throwing/shooting N missiles) */
- break; /* endmultishot(FALSE); */
- }
- }
- m_shot.n = m_shot.i = 0;
- m_shot.o = STRANGE_OBJECT;
- m_shot.s = FALSE;
-
+ monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */
nomul(0);
}