diff --git a/src/dogmove.c b/src/dogmove.c index e59e7e801..321deb0af 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -11,9 +11,9 @@ extern boolean notonhead; 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)); @@ -284,8 +284,8 @@ boolean devour; 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; @@ -351,8 +351,8 @@ boolean devour; /* 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)) { @@ -423,7 +423,8 @@ int udist; 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 @@ -561,16 +562,12 @@ int after, udist, whappr; 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) @@ -589,7 +586,7 @@ int after, udist, whappr; } 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; @@ -707,7 +704,6 @@ int maxdist; return 0; } - STATIC_OVL long score_targ(mtmp, mtarg) struct monst *mtmp, *mtarg; @@ -721,86 +717,74 @@ 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; } @@ -1121,9 +1105,8 @@ int after; /* this is extra fast monster movement */ } /* 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; @@ -1152,7 +1135,8 @@ int after; /* this is extra fast monster movement */ 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, @@ -1168,7 +1152,8 @@ int after; /* this is extra fast monster movement */ */ if (mtarg->mcansee && haseyes(mtarg->data)) { mstatus = mattackm(mtarg, mtmp); - if (mstatus & MM_DEF_DIED) return 2; + if (mstatus & MM_DEF_DIED) + return 2; } } } @@ -1201,7 +1186,7 @@ newdogpos: /* 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; @@ -1319,12 +1304,12 @@ wantdoor(x, y, distance) 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; } } diff --git a/src/end.c b/src/end.c index 57f8425bc..d097292fb 100644 --- a/src/end.c +++ b/src/end.c @@ -781,6 +781,8 @@ int how; u.ugrave_arise = NON_PM; HUnchanging = 0L; curs_on_u(); + if (!context.mon_moving) + endmultishot(FALSE); } /* diff --git a/src/mhitm.c b/src/mhitm.c index e4c05897b..3c6965fd0 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -356,15 +356,13 @@ register struct monst *magr, *mdef; 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)) { @@ -390,8 +388,7 @@ register struct monst *magr, *mdef; 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 @@ -454,50 +451,52 @@ register struct monst *magr, *mdef; 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; @@ -505,12 +504,11 @@ register struct monst *magr, *mdef; } 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 */ @@ -595,9 +593,8 @@ struct attack *mattk; 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; @@ -609,8 +606,8 @@ struct attack *mattk; 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)) { @@ -723,7 +720,7 @@ register struct attack *mattk; } 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)); @@ -1174,6 +1171,7 @@ register struct attack *mattk; */ { struct obj *gold = findgold(mdef->minvent); + if (!gold) break; obj_extract_self(gold); diff --git a/src/mhitu.c b/src/mhitu.c index 6ab8481cc..e9ec5a9e0 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -8,11 +8,9 @@ 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 *)); @@ -20,7 +18,6 @@ STATIC_DCL int FDECL(explmu, (struct monst *, struct attack *, BOOLEAN_P)); 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 */ @@ -33,41 +30,48 @@ register struct monst *mtmp; 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 */ @@ -139,6 +143,7 @@ register struct monst *mtmp; register struct attack *mattk; { int compat; + const char *Monst_name; /* Monnam(mtmp) */ /* no map_invisible() -- no way to tell where _this_ is coming from */ @@ -150,42 +155,41 @@ register struct attack *mattk; 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!", @@ -194,20 +198,20 @@ register struct attack *mattk; * 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 @@ -217,9 +221,9 @@ struct permonst *mdat; /* if mtmp is polymorphed, mdat != mtmp->data */ boolean message; { if (message) { - if (is_animal(mdat)) + if (is_animal(mdat)) { You("get regurgitated!"); - else { + } else { char blast[40]; register int i; @@ -227,9 +231,9 @@ boolean message; 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: @@ -306,11 +310,10 @@ struct attack *alt_attk_buf; && !(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; @@ -1157,7 +1160,8 @@ register struct attack *mattk; 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 @@ -1165,31 +1169,30 @@ register struct attack *mattk; * [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); @@ -1308,12 +1311,11 @@ register struct attack *mattk; (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); @@ -1705,6 +1707,7 @@ register struct attack *mattk; 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 :-) diff --git a/src/mthrowu.c b/src/mthrowu.c index 1d9477f7c..7c5f297d7 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -4,6 +4,8 @@ #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 *)); @@ -51,9 +53,9 @@ const char *name; /* if null, then format `obj' */ || !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)) { @@ -73,9 +75,9 @@ const char *name; /* if null, then format `obj' */ 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 */ @@ -116,8 +118,7 @@ int x, y; 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; @@ -137,6 +138,150 @@ STATIC_OVL struct monst *target = 0; /* 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 @@ -237,9 +382,7 @@ boolean verbose; /* give message(s) even when you can't see what happened */ 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)) @@ -249,8 +392,8 @@ boolean verbose; /* give message(s) even when you can't see what happened */ } 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))); @@ -280,7 +423,7 @@ struct obj *obj; /* missile (or stack providing it) */ 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; @@ -372,9 +515,10 @@ struct obj *obj; /* missile (or stack providing it) */ 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; } @@ -430,7 +574,7 @@ struct obj *obj; /* missile (or stack providing it) */ (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)) { @@ -461,8 +605,8 @@ struct obj *obj; /* missile (or stack providing it) */ } } stop_occupation(); - if (hitu || !range) { - (void) drop_throw(singleobj, hitu, u.ux, u.uy); + if (hitu) { + range = 0; break; } } @@ -481,8 +625,12 @@ struct obj *obj; /* missile (or stack providing it) */ !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); @@ -500,121 +648,47 @@ struct obj *obj; /* missile (or stack providing it) */ } } +/* 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; } @@ -622,7 +696,6 @@ struct monst *mtmp, *mtarg; return 0; } - /* monster spits substance at monster */ int spitmm(mtmp, mattk, mtarg) @@ -675,8 +748,9 @@ struct attack *mattk; 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; { @@ -691,20 +765,19 @@ 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 */ @@ -717,9 +790,9 @@ struct attack *mattk; } } else impossible("Breath weapon %d used", typ-1); } else - return (0); + return 0; } - return(1); + return 1; } @@ -762,7 +835,6 @@ struct monst *mtmp; { struct obj *otmp, *mwep; xchar x, y; - int multishot; const char *onm; /* Rearranged beginning so monsters can use polearms not in a line */ @@ -821,101 +893,7 @@ struct monst *mtmp; 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); }