1 /* NetHack 3.6 mthrowu.c $NHDT-Date: 1542765360 2018/11/21 01:56:00 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.78 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Pasi Kallinen, 2016. */
4 /* NetHack may be freely redistributed. See license for details. */
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2019 */
9 /* JNetHack may be freely redistributed. See license for details. */
13 STATIC_DCL int FDECL(monmulti, (struct monst *, struct obj *, struct obj *));
14 STATIC_DCL void FDECL(monshoot, (struct monst *, struct obj *, struct obj *));
15 STATIC_DCL int FDECL(drop_throw, (struct obj *, BOOLEAN_P, int, int));
16 STATIC_DCL boolean FDECL(m_lined_up, (struct monst *, struct monst *));
18 #define URETREATING(x, y) \
19 (distmin(u.ux, u.uy, x, y) > distmin(u.ux0, u.uy0, x, y))
21 #define POLE_LIM 5 /* How far monsters can use pole-weapons */
23 #define PET_MISSILE_RANGE2 36 /* Square of distance within which pets shoot */
26 * Keep consistent with breath weapons in zap.c, and AD_* in monattk.h.
28 STATIC_OVL NEARDATA const char *breathwep[] = {
30 "fragments", "fire", "frost", "sleep gas", "a disintegration blast",
31 "lightning", "poison gas", "acid", "strange breath #8",
34 "
\94j
\95Ð", "
\89\8a", "
\97â
\8bC", "
\90\87\96°
\83K
\83X", "
\95ª
\89ð
\82Ì
\91§",
35 "
\88î
\8dÈ", "
\93Å
\82Ì
\91§", "
\8e_", "strange breath #8",
40 extern boolean notonhead; /* for long worms */
41 STATIC_VAR int mesg_given; /* for m_throw()/thitu() 'miss' message */
43 /* hero is hit by something other than a monster */
45 thitu(tlev, dam, objp, name)
48 const char *name; /* if null, then format `*objp' */
50 struct obj *obj = objp ? *objp : 0;
51 const char *onm, *knm;
53 int kprefix = KILLED_BY_AN, dieroll;
54 char onmbuf[BUFSZ], knmbuf[BUFSZ];
58 panic("thitu: name & obj both null?");
60 (obj->quan > 1L) ? doname(obj) : mshot_xname(obj));
61 knm = strcpy(knmbuf, killer_xname(obj));
62 kprefix = KILLED_BY; /* killer_name supplies "an" if warranted */
66 /* [perhaps ought to check for plural here to] */
67 if (!strncmpi(name, "the ", 4) || !strncmpi(name, "an ", 3)
68 || !strncmpi(name, "a ", 2))
70 #else /*
\93ú
\96{
\8cê
\82Å
\82Í
\82»
\82Ì
\82Ü
\82Ü */
71 knm = strcpy(knmbuf, name);
75 strcat(knmbuf, "
\82É
\93\96\82½
\82Á
\82Ä");
77 onm = (obj && obj_is_pname(obj)) ? the(name)
78 : (obj && obj->quan > 1L) ? name
80 is_acid = (obj && obj->otyp == ACID_VENOM);
82 if (u.uac + tlev <= (dieroll = rnd(20))) {
84 if (Blind || !flags.verbose) {
88 pline("
\82»
\82ê
\82Í
\82Í
\82¸
\82ê
\82½
\81D");
89 } else if (u.uac + tlev <= dieroll - 2) {
91 Strcpy(onmbuf, onm); /* [modifiable buffer for upstart()] */
93 pline("%s %s you.", upstart(onmbuf), vtense(onmbuf, "miss"));
95 pline("%s
\82Í
\8dU
\8c\82\82ð
\82Í
\82¸
\82µ
\82½
\81D", upstart(onmbuf));
98 You("are almost hit by %s.", onm);
100 pline("
\82à
\82¤
\8f
\82µ
\82Å%s
\82É
\96½
\92\86\82·
\82é
\82Æ
\82±
\82ë
\82¾
\82Á
\82½
\81I",onm);
103 if (Blind || !flags.verbose)
105 You("are hit%s", exclam(dam));
107 pline("
\89½
\82©
\82ª
\82 \82È
\82½
\82É
\96½
\92\86\82µ
\82½
\81I");
110 You("are hit by %s%s", onm, exclam(dam));
112 pline("%s
\82ª
\82 \82È
\82½
\82É
\96½
\92\86\82µ
\82½
\81I", onm);
114 if (is_acid && Acid_resistance) {
116 pline("It doesn't seem to hurt you.");
118 pline("
\82 \82È
\82½
\82Í
\8f\9d\82Â
\82©
\82È
\82©
\82Á
\82½
\81D");
119 } else if (obj && obj->oclass == POTION_CLASS) {
120 /* an explosion which scatters objects might hit hero with one
121 (potions deliberately thrown at hero are handled by m_throw) */
122 potionhit(&youmonst, obj, POTHIT_OTHER_THROW);
123 *objp = obj = 0; /* potionhit() uses up the potion */
125 if (obj && objects[obj->otyp].oc_material == SILVER
127 /* extra damage already applied by dmgval() */
129 pline_The("silver sears your flesh!");
131 pline("
\82 \82È
\82½
\82Ì
\91Ì
\82Í
\8bâ
\82Å
\8fÄ
\82©
\82ê
\82½
\81I");
132 exercise(A_CON, FALSE);
138 pline("
\8e_
\82Å
\8fÄ
\82©
\82ê
\82½
\81I");
139 losehp(dam, knm, kprefix); /* acid damage */
140 exercise(A_STR, FALSE);
146 /* Be sure this corresponds with what happens to player-thrown objects in
147 * dothrow.c (for consistency). --KAA
148 * Returns 0 if object still exists (not destroyed).
151 drop_throw(obj, ohit, x, y)
152 register struct obj *obj;
161 if (obj->otyp == CREAM_PIE || obj->oclass == VENOM_CLASS
162 || (ohit && obj->otyp == EGG))
164 else if (ohit && (is_multigen(obj) || obj->otyp == ROCK))
169 if (create && !((mtmp = m_at(x, y)) != 0 && mtmp->mtrapped
170 && (t = t_at(x, y)) != 0
171 && is_pit(t->ttyp))) {
174 if (down_gate(x, y) != -1)
175 objgone = ship_object(obj, x, y, FALSE);
178 if (!flooreffects(obj, x, y, "fall")) {
180 if (!flooreffects(obj, x, y, "
\97\8e\82¿
\82é")) {
182 place_object(obj, x, y);
183 if (!mtmp && x == u.ux && y == u.uy)
186 passive_obj(mtmp, obj, (struct attack *) 0);
192 obfree(obj, (struct obj *) 0);
196 /* The monster that's being shot at when one monster shoots at another */
197 STATIC_OVL struct monst *target = 0;
198 /* The monster that's doing the shooting/throwing */
199 STATIC_OVL struct monst *archer = 0;
201 /* calculate multishot volley count for mtmp throwing otmp (if not ammo) or
202 shooting otmp with mwep (if otmp is ammo and mwep appropriate launcher) */
204 monmulti(mtmp, otmp, mwep)
206 struct obj *otmp, *mwep;
208 int skill = (int) objects[otmp->otyp].oc_skill;
211 if (otmp->quan > 1L /* no point checking if there's only 1 */
212 /* ammo requires corresponding launcher be wielded */
214 ? matching_launcher(otmp, mwep)
215 /* otherwise any stackable (non-ammo) weapon */
216 : otmp->oclass == WEAPON_CLASS)
218 /* Assumes lords are skilled, princes are expert */
219 if (is_prince(mtmp->data))
221 else if (is_lord(mtmp->data))
223 /* fake players treated as skilled (regardless of role limits) */
224 else if (is_mplayer(mtmp->data))
227 /* this portion is different from hero multishot; from slash'em?
229 /* Elven Craftsmanship makes for light, quick bows */
230 if (otmp->otyp == ELVEN_ARROW && !otmp->cursed)
232 if (ammo_and_launcher(otmp, uwep) && mwep->otyp == ELVEN_BOW
235 /* 1/3 of launcher enchantment */
236 if (ammo_and_launcher(otmp, mwep) && mwep->spe > 1)
237 multishot += (long) rounddiv(mwep->spe, 3);
238 /* Some randomness */
239 multishot = (long) rnd((int) multishot);
242 switch (monsndx(mtmp->data)) {
243 case PM_CAVEMAN: /* give bonus for low-tech gear */
244 if (skill == -P_SLING || skill == P_SPEAR)
247 case PM_MONK: /* allow higher volley count */
248 if (skill == -P_SHURIKEN)
252 if (skill != P_DAGGER)
256 if (skill == P_DAGGER)
260 if (skill == -P_SHURIKEN || skill == -P_DART)
264 if (otmp->otyp == YA && mwep->otyp == YUMI)
271 if ((is_elf(mtmp->data) && otmp->otyp == ELVEN_ARROW
272 && mwep->otyp == ELVEN_BOW)
273 || (is_orc(mtmp->data) && otmp->otyp == ORCISH_ARROW
274 && mwep->otyp == ORCISH_BOW)
275 || (is_gnome(mtmp->data) && otmp->otyp == CROSSBOW_BOLT
276 && mwep->otyp == CROSSBOW))
280 if (otmp->quan < multishot)
281 multishot = (int) otmp->quan;
287 /* mtmp throws otmp, or shoots otmp with mwep, at hero or at monster mtarg */
289 monshoot(mtmp, otmp, mwep)
291 struct obj *otmp, *mwep;
293 struct monst *mtarg = target;
294 int dm = distmin(mtmp->mx, mtmp->my,
295 mtarg ? mtarg->mx : mtmp->mux,
296 mtarg ? mtarg->my : mtmp->muy),
297 multishot = monmulti(mtmp, otmp, mwep);
299 * Caller must have called linedup() to set up tbx, tby.
302 if (canseemon(mtmp)) {
304 char onmbuf[BUFSZ], trgbuf[BUFSZ];
307 /* "N arrows"; multishot > 1 implies otmp->quan > 1, so
308 xname()'s result will already be pluralized */
310 Sprintf(onmbuf, "%d %s", multishot, xname(otmp));
312 Sprintf(onmbuf, "%d%s
\82Ì%s", multishot, numeral(otmp), xname(otmp));
316 onm = singular(otmp, xname);
317 onm = obj_is_pname(otmp) ? the(onm) : an(onm);
319 m_shot.s = ammo_and_launcher(otmp, mwep) ? TRUE : FALSE;
320 Strcpy(trgbuf, mtarg ? mon_nam(mtarg) : "");
321 #if 0 /*JP*//*
\93ú
\96{
\8cê
\82Å
\82Ímon_nam
\82Í
\81u
\89½
\8eÒ
\82©
\81v
\82ð
\95Ô
\82·
\82Ì
\82Å
\95Ï
\8dX
\95s
\97v*/
322 if (!strcmp(trgbuf, "it"))
323 Strcpy(trgbuf, humanoid(mtmp->data) ? "someone" : something);
326 pline("%s %s %s%s%s!", Monnam(mtmp),
327 m_shot.s ? "shoots" : "throws", onm,
328 mtarg ? " at " : "", trgbuf);
330 pline("%s
\82Í%s
\82ð%s
\82É%s
\81I", Monnam(mtmp),
333 m_shot.s ? "
\8c\82\82Á
\82½" : "
\93\8a\82°
\82½");
335 m_shot.o = otmp->otyp;
337 m_shot.o = STRANGE_OBJECT; /* don't give multishot feedback */
339 m_shot.n = multishot;
340 for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
341 m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), dm, otmp);
342 /* conceptually all N missiles are in flight at once, but
343 if mtmp gets killed (shot kills adjacent gas spore and
344 triggers explosion, perhaps), inventory will be dropped
345 and otmp might go away via merging into another stack */
346 if (DEADMONSTER(mtmp) && m_shot.i < m_shot.n)
347 /* cancel pending shots (perhaps ought to give a message here
348 since we gave one above about throwing/shooting N missiles) */
349 break; /* endmultishot(FALSE); */
352 m_shot.n = m_shot.i = 0;
353 m_shot.o = STRANGE_OBJECT;
357 /* an object launched by someone/thing other than player attacks a monster;
358 return 1 if the object has stopped moving (hit or its range used up) */
360 ohitmon(mtmp, otmp, range, verbose)
361 struct monst *mtmp; /* accidental target, located at <bhitpos.x,.y> */
362 struct obj *otmp; /* missile; might be destroyed by drop_throw */
363 int range; /* how much farther will object travel if it misses;
364 use -1 to signify to keep going even after hit,
365 unless it's gone (used for rolling_boulder_traps) */
366 boolean verbose; /* give message(s) even when you can't see what happened */
369 boolean vis, ismimic;
371 struct obj *mon_launcher = archer ? MON_WEP(archer) : NULL;
373 notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
374 ismimic = M_AP_TYPE(mtmp) && M_AP_TYPE(mtmp) != M_AP_MONSTER;
375 vis = cansee(bhitpos.x, bhitpos.y);
377 tmp = 5 + find_mac(mtmp) + omon_adj(mtmp, otmp, FALSE);
378 /* High level monsters will be more likely to hit */
379 /* This check applies only if this monster is the target
380 * the archer was aiming at. */
381 if (archer && target == mtmp) {
382 if (archer->m_lev > 5)
383 tmp += archer->m_lev - 5;
384 if (mon_launcher && mon_launcher->oartifact)
385 tmp += spec_abon(mon_launcher, mtmp);
390 miss(distant_name(otmp, mshot_xname), mtmp);
391 else if (verbose && !target)
393 pline("It is missed.");
395 pline("
\89½
\82©
\82ª
\82©
\82·
\82ß
\82½
\81D");
397 if (!range) { /* Last position; object drops */
398 (void) drop_throw(otmp, 0, mtmp->mx, mtmp->my);
401 } else if (otmp->oclass == POTION_CLASS) {
407 /* probably thrown by a monster rather than 'other', but the
408 distinction only matters when hitting the hero */
409 potionhit(mtmp, otmp, POTHIT_OTHER_THROW);
412 damage = dmgval(otmp, mtmp);
413 if (otmp->otyp == ACID_VENOM && resists_acid(mtmp))
419 if (otmp->otyp == EGG)
421 pline("Splat! %s is hit with %s egg!", Monnam(mtmp),
422 otmp->known ? an(mons[otmp->corpsenm].mname) : "an");
424 pline("
\83r
\83`
\83\83\83b
\81I%s
\82Í%s
\97\91\82É
\93\96\82½
\82Á
\82½
\81I", Monnam(mtmp),
425 otmp->known ? s_suffix(mons[otmp->corpsenm].mname) : "");
428 hit(distant_name(otmp, mshot_xname), mtmp, exclam(damage));
429 } else if (verbose && !target)
431 pline("%s%s is hit%s", (otmp->otyp == EGG) ? "Splat! " : "",
432 Monnam(mtmp), exclam(damage));
434 pline("%s%s
\82É
\96½
\92\86\82µ
\82½%s", (otmp->otyp == EGG) ? "
\83r
\83`
\83\83\83b
\81I" : "",
435 Monnam(mtmp), exclam(damage));
438 if (otmp->opoisoned && is_poisonable(otmp)) {
439 if (resists_poison(mtmp)) {
442 pline_The("poison doesn't seem to affect %s.",
444 pline("%s
\82Í
\93Å
\82Ì
\89e
\8b¿
\82ð
\8eó
\82¯
\82È
\82¢
\82æ
\82¤
\82¾
\81D",
452 pline_The("poison was deadly...");
454 pline("
\93Å
\82Í
\92v
\8e\80\97Ê
\82¾
\82Á
\82½
\81D
\81D
\81D");
459 if (objects[otmp->otyp].oc_material == SILVER
460 && mon_hates_silver(mtmp)) {
463 pline_The("silver sears %s flesh!", s_suffix(mon_nam(mtmp)));
465 pline("%s
\82Ì
\91Ì
\82Í
\8bâ
\82Å
\8fÄ
\82©
\82ê
\82½
\81I", mon_nam(mtmp));
466 else if (verbose && !target)
468 pline("Its flesh is seared!");
470 pline("
\89½
\8eÒ
\82©
\82Ì
\91Ì
\82Í
\8fÄ
\82©
\82ê
\82½
\81I");
472 if (otmp->otyp == ACID_VENOM && cansee(mtmp->mx, mtmp->my)) {
473 if (resists_acid(mtmp)) {
474 if (vis || (verbose && !target))
476 pline("%s is unaffected.", Monnam(mtmp));
478 pline("%s
\82Í
\89e
\8b¿
\82ð
\8eó
\82¯
\82È
\82¢
\81D", Monnam(mtmp));
482 pline_The("%s burns %s!", hliquid("acid"), mon_nam(mtmp));
484 pline_The("%s
\82Í%s
\82Å
\8fÄ
\82©
\82ê
\82½
\81I", mon_nam(mtmp), hliquid("
\8e_"));
485 else if (verbose && !target)
487 pline("It is burned!");
489 pline("
\89½
\82©
\82Í
\8fÄ
\82©
\82ê
\82½
\81I");
492 if (otmp->otyp == EGG && touch_petrifies(&mons[otmp->corpsenm])) {
493 if (!munstone(mtmp, TRUE))
494 minstapetrify(mtmp, TRUE);
495 if (resists_ston(mtmp))
499 if (!DEADMONSTER(mtmp)) { /* might already be dead (if petrified) */
501 if (DEADMONSTER(mtmp)) {
502 if (vis || (verbose && !target))
504 pline("%s is %s!", Monnam(mtmp),
505 (nonliving(mtmp->data) || is_vampshifter(mtmp)
506 || !canspotmon(mtmp)) ? "destroyed" : "killed");
508 pline("%s
\82Í%s
\81I", Monnam(mtmp),
509 (nonliving(mtmp->data) || is_vampshifter(mtmp)
510 || !canspotmon(mtmp)) ? "
\93|
\82³
\82ê
\82½" : "
\8e\80\82ñ
\82¾");
512 /* don't blame hero for unknown rolling boulder trap */
513 if (!context.mon_moving && (otmp->otyp != BOULDER
514 || range >= 0 || otmp->otrapped))
515 xkilled(mtmp, XKILL_NOMSG);
521 /* blinding venom and cream pie do 0 damage, but verify
522 that the target is still alive anyway */
523 if (!DEADMONSTER(mtmp)
524 && can_blnd((struct monst *) 0, mtmp,
525 (uchar) ((otmp->otyp == BLINDING_VENOM) ? AT_SPIT
528 if (vis && mtmp->mcansee)
530 pline("%s is blinded by %s.", Monnam(mtmp), the(xname(otmp)));
532 pline("%s
\82Í%s
\82É
\82æ
\82Á
\82Ä
\96Ú
\82ª
\8c©
\82¦
\82È
\82
\82È
\82Á
\82½
\81D", Monnam(mtmp), the(xname(otmp)));
534 tmp = (int) mtmp->mblinded + rnd(25) + 20;
537 mtmp->mblinded = tmp;
540 objgone = drop_throw(otmp, 1, bhitpos.x, bhitpos.y);
541 if (!objgone && range == -1) { /* special case */
542 obj_extract_self(otmp); /* free it for motion again */
550 #define MT_FLIGHTCHECK(pre) \
551 (/* missile hits edge of screen */ \
552 !isok(bhitpos.x + dx, bhitpos.y + dy) \
553 /* missile hits the wall */ \
554 || IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ) \
555 /* missile hit closed door */ \
556 || closed_door(bhitpos.x + dx, bhitpos.y + dy) \
557 /* missile might hit iron bars */ \
558 /* the random chance for small objects hitting bars is */ \
559 /* skipped when reaching them at point blank range */ \
560 || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS \
561 && hits_bars(&singleobj, \
562 bhitpos.x, bhitpos.y, \
563 bhitpos.x + dx, bhitpos.y + dy, \
564 ((pre) ? 0 : !rn2(5)), 0)) \
565 /* Thrown objects "sink" */ \
566 || (!(pre) && IS_SINK(levl[bhitpos.x][bhitpos.y].typ)))
569 m_throw(mon, x, y, dx, dy, range, obj)
570 struct monst *mon; /* launching monster */
571 int x, y, dx, dy, range; /* launch point, direction, and range */
572 struct obj *obj; /* missile (or stack providing it) */
575 struct obj *singleobj;
576 char sym = obj->oclass;
577 int hitu = 0, oldumort, blindinc = 0;
581 notonhead = FALSE; /* reset potentially stale value */
583 if (obj->quan == 1L) {
585 * Remove object from minvent. This cannot be done later on;
586 * what if the player dies before then, leaving the monster
587 * with 0 daggers? (This caused the infamous 2^32-1 orcish
590 * VENOM is not in minvent - it should already be OBJ_FREE.
591 * The extract below does nothing.
594 /* not possibly_unwield, which checks the object's */
595 /* location, not its existence */
596 if (MON_WEP(mon) == obj)
597 setmnotwielded(mon, obj);
598 obj_extract_self(obj);
600 obj = (struct obj *) 0;
602 singleobj = splitobj(obj, 1L);
603 obj_extract_self(singleobj);
606 singleobj->owornmask = 0; /* threw one of multiple weapons in hand? */
608 if ((singleobj->cursed || singleobj->greased) && (dx || dy) && !rn2(7)) {
609 if (canseemon(mon) && flags.verbose) {
610 if (is_ammo(singleobj))
612 pline("%s misfires!", Monnam(mon));
614 pline("%s
\82Í
\82Í
\82¸
\82µ
\82½
\81I", Monnam(mon));
617 pline("%s as %s throws it!", Tobjnam(singleobj, "slip"),
620 pline("%s
\82ª
\93\8a\82°
\82æ
\82¤
\82Æ
\82µ
\82½
\82Æ
\82½
\82ñ%s
\82ª
\8a\8a\82Á
\82½
\81I",
621 mon_nam(mon), xname(singleobj));
626 /* check validity of new direction */
628 (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
633 if (MT_FLIGHTCHECK(TRUE)) {
634 (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
637 mesg_given = 0; /* a 'missile misses' message has not yet been shown */
639 /* Note: drop_throw may destroy singleobj. Since obj must be destroyed
640 * early to avoid the dagger bug, anyone who modifies this code should
641 * be careful not to use either one after it's been freed.
644 tmp_at(DISP_FLASH, obj_to_glyph(singleobj, rn2_on_display_rng));
645 while (range-- > 0) { /* Actually the loop is always exited by break */
648 if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
649 if (ohitmon(mtmp, singleobj, range, TRUE))
651 } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
655 if (singleobj->oclass == GEM_CLASS
656 && singleobj->otyp <= LAST_GEM + 9 /* 9 glass colors */
657 && is_unicorn(youmonst.data)) {
658 if (singleobj->otyp > LAST_GEM) {
660 You("catch the %s.", xname(singleobj));
662 You("%s
\82ð
\82Â
\82©
\82Ü
\82¦
\82½
\81D", xname(singleobj));
664 You("are not interested in %s junk.",
665 s_suffix(mon_nam(mon)));
667 You("%s
\82Ì
\83K
\83\89\83N
\83^
\82É
\8b»
\96¡
\82Í
\82È
\82¢
\81D",
670 makeknown(singleobj->otyp);
675 "accept %s gift in the spirit in which it was intended.",
677 "
\82±
\82ê
\82ª
\97~
\82µ
\82©
\82Á
\82½
\82ñ
\82¾
\82Æ
\8ev
\82¢
\82È
\82ª
\82ç%s
\82Ì
\91¡
\82è
\95¨
\82ð
\8eó
\82¯
\82Æ
\82Á
\82½
\81D",
678 s_suffix(mon_nam(mon)));
680 (void) hold_another_object(singleobj,
681 "You catch, but drop, %s.",
685 (void) hold_another_object(singleobj,
686 "
\82 \82È
\82½
\82Í%s
\82ð
\82Â
\82©
\82Ü
\82¦
\82½
\82ª
\81C
\97\8e\82µ
\82½
\81D",
688 "
\82ð
\82Â
\82©
\82Ü
\82¦
\82½
\81D");
693 if (singleobj->oclass == POTION_CLASS) {
695 singleobj->dknown = 1;
696 potionhit(&youmonst, singleobj, POTHIT_MONST_THROW);
699 oldumort = u.umortality;
700 switch (singleobj->otyp) {
703 if (!touch_petrifies(&mons[singleobj->corpsenm])) {
704 impossible("monster throwing egg type %d",
705 singleobj->corpsenm);
712 hitu = thitu(8, 0, &singleobj, (char *) 0);
715 dam = dmgval(singleobj, &youmonst);
716 hitv = 3 - distmin(u.ux, u.uy, mon->mx, mon->my);
719 if (is_elf(mon->data)
720 && objects[singleobj->otyp].oc_skill == P_BOW) {
722 if (MON_WEP(mon) && MON_WEP(mon)->otyp == ELVEN_BOW)
724 if (singleobj->otyp == ELVEN_ARROW)
727 if (bigmonst(youmonst.data))
729 hitv += 8 + singleobj->spe;
732 hitu = thitu(hitv, dam, &singleobj, (char *) 0);
734 if (hitu && singleobj->opoisoned && is_poisonable(singleobj)) {
735 char onmbuf[BUFSZ], knmbuf[BUFSZ];
737 Strcpy(onmbuf, xname(singleobj));
738 Strcpy(knmbuf, killer_xname(singleobj));
739 poisoned(onmbuf, A_STR, knmbuf,
740 /* if damage triggered life-saving,
741 poison is limited to attrib loss */
742 (u.umortality > oldumort) ? 0 : 10, TRUE);
744 if (hitu && can_blnd((struct monst *) 0, &youmonst,
745 (uchar) ((singleobj->otyp == BLINDING_VENOM)
750 if (singleobj->otyp == CREAM_PIE) {
753 pline("Yecch! You've been creamed.");
755 pline("
\83E
\83F
\81[
\81D
\83N
\83\8a\81[
\83\80\82ð
\82©
\82Ô
\82Á
\82½
\81D");
758 pline("There's %s sticky all over your %s.",
759 something, body_part(FACE));
761 pline("
\82 \82È
\82½
\82Í%s
\82É
\82×
\82Æ
\82Â
\82
\82à
\82Ì
\82ð
\8a´
\82¶
\82½
\81D",
764 } else if (singleobj->otyp == BLINDING_VENOM) {
766 const char *eyes = body_part(EYE);
768 if (eyecount(youmonst.data) != 1)
769 eyes = makeplural(eyes);
770 /* venom in the eyes */
772 pline_The("venom blinds you.");
774 Your("%s %s.", eyes, vtense(eyes, "sting"));
777 pline("
\93Å
\82Å
\96Ú
\82ª
\8c©
\82¦
\82È
\82
\82È
\82Á
\82½
\81D");
779 Your("%s
\82Í
\82¿
\82
\82¿
\82
\82µ
\82½
\81D", body_part(EYE));
783 if (hitu && singleobj->otyp == EGG) {
784 if (!Stoned && !Stone_resistance
785 && !(poly_when_stoned(youmonst.data)
786 && polymon(PM_STONE_GOLEM))) {
787 make_stoned(5L, (char *) 0, KILLED_BY, "");
792 (void) drop_throw(singleobj, hitu, u.ux, u.uy);
796 if (!range /* reached end of path */
797 || MT_FLIGHTCHECK(FALSE)) {
798 if (singleobj) { /* hits_bars might have destroyed it */
800 && (!mesg_given || bhitpos.x != u.ux || bhitpos.y != u.uy)
801 && (cansee(bhitpos.x, bhitpos.y)
802 || (archer && canseemon(archer))))
804 pline("%s misses.", The(mshot_xname(singleobj)));
806 pline("%s
\82Í
\82Í
\82¸
\82ê
\82½
\81D", mshot_xname(singleobj));
807 (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
811 tmp_at(bhitpos.x, bhitpos.y);
814 tmp_at(bhitpos.x, bhitpos.y);
817 mesg_given = 0; /* reset */
820 u.ucreamed += blindinc;
821 make_blinded(Blinded + (long) blindinc, FALSE);
823 Your1(vision_clears);
827 #undef MT_FLIGHTCHECK
829 /* Monster throws item at another monster */
832 struct monst *mtmp, *mtarg;
834 struct obj *otmp, *mwep;
838 /* Polearms won't be applied by monsters against other monsters */
839 if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
840 mtmp->weapon_check = NEED_RANGED_WEAPON;
841 /* mon_wield_item resets weapon_check as appropriate */
842 if (mon_wield_item(mtmp) != 0)
847 otmp = select_rwep(mtmp);
850 ispole = is_pole(otmp);
855 mwep = MON_WEP(mtmp); /* wielded weapon */
857 if (!ispole && m_lined_up(mtarg, mtmp)) {
858 int chance = max(BOLT_LIM - distmin(x, y, mtarg->mx, mtarg->my), 1);
860 if (!mtarg->mflee || !rn2(chance)) {
861 if (ammo_and_launcher(otmp, mwep)
862 && dist2(mtmp->mx, mtmp->my, mtarg->mx, mtarg->my)
863 > PET_MISSILE_RANGE2)
864 return 0; /* Out of range */
865 /* Set target monster */
868 monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */
869 archer = target = (struct monst *) 0;
877 /* monster spits substance at monster */
879 spitmm(mtmp, mattk, mtarg)
880 struct monst *mtmp, *mtarg;
881 struct attack *mattk;
888 pline("A dry rattle comes from %s throat.",
889 s_suffix(mon_nam(mtmp)));
891 pline("%s
\82Ì
\8dA
\82ª
\83K
\83\89\83K
\83\89\82Æ
\96Â
\82Á
\82½
\81D",
896 if (m_lined_up(mtarg, mtmp)) {
897 switch (mattk->adtyp) {
900 otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
903 impossible("bad attack type in spitmu");
906 otmp = mksobj(ACID_VENOM, TRUE, FALSE);
909 if (!rn2(BOLT_LIM-distmin(mtmp->mx,mtmp->my,mtarg->mx,mtarg->my))) {
912 pline("%s spits venom!", Monnam(mtmp));
914 pline("%s
\82Í
\93Å
\82ð
\93f
\82¢
\82½
\81I", Monnam(mtmp));
916 m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
917 distmin(mtmp->mx,mtmp->my,mtarg->mx,mtarg->my), otmp);
918 target = (struct monst *)0;
921 /* If this is a pet, it'll get hungry. Minions and
922 * spell beings won't hunger */
923 if (mtmp->mtame && !mtmp->isminion) {
924 struct edog *dog = EDOG(mtmp);
926 /* Hunger effects will catch up next move */
927 if (dog->hungrytime > 1)
928 dog->hungrytime -= 5;
937 /* monster breathes at monster (ranged) */
939 breamm(mtmp, mattk, mtarg)
940 struct monst *mtmp, *mtarg;
941 struct attack *mattk;
943 /* if new breath types are added, change AD_ACID to max type */
944 int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp ;
946 if (m_lined_up(mtarg, mtmp)) {
951 pline("%s coughs.", Monnam(mtmp));
953 pline("%s
\82Í
\82¹
\82«
\82ð
\82µ
\82½
\81D", Monnam(mtmp));
956 You_hear("a cough.");
958 You_hear("
\82¹
\82«
\82Ì
\89¹
\82ð
\95·
\82¢
\82½
\81D");
962 if (!mtmp->mspec_used && rn2(3)) {
963 if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
966 pline("%s breathes %s!", Monnam(mtmp), breathwep[typ - 1]);
968 pline("%s
\82Í%s
\82ð
\82Í
\82¢
\82½
\81I", Monnam(mtmp), breathwep[typ - 1]);
969 dobuzz((int) (-20 - (typ - 1)), (int) mattk->damn,
970 mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), FALSE);
972 /* breath runs out sometimes. Also, give monster some
973 * cunning; don't breath if the target fell asleep.
975 mtmp->mspec_used = 6 + rn2(18);
977 /* If this is a pet, it'll get hungry. Minions and
978 * spell beings won't hunger */
979 if (mtmp->mtame && !mtmp->isminion) {
980 struct edog *dog = EDOG(mtmp);
982 /* Hunger effects will catch up next move */
983 if (dog->hungrytime >= 10)
984 dog->hungrytime -= 10;
986 } else impossible("Breath weapon %d used", typ-1);
995 /* remove an entire item from a monster's inventory; destroy that item */
1001 obj_extract_self(obj);
1002 if (obj->owornmask) {
1003 if (obj == MON_WEP(mon))
1005 mon->misc_worn_check &= ~obj->owornmask;
1006 update_mon_intrinsics(mon, obj, FALSE, FALSE);
1007 obj->owornmask = 0L;
1009 obfree(obj, (struct obj *) 0);
1012 /* remove one instance of an item from a monster's inventory */
1018 if (obj->quan > 1L) {
1020 obj->owt = weight(obj);
1022 m_useupall(mon, obj);
1026 /* monster attempts ranged weapon attack against player */
1031 struct obj *otmp, *mwep;
1035 /* Rearranged beginning so monsters can use polearms not in a line */
1036 if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
1037 mtmp->weapon_check = NEED_RANGED_WEAPON;
1038 /* mon_wield_item resets weapon_check as appropriate */
1039 if (mon_wield_item(mtmp) != 0)
1044 otmp = select_rwep(mtmp);
1048 if (is_pole(otmp)) {
1051 if (otmp != MON_WEP(mtmp))
1052 return; /* polearm must be wielded */
1053 if (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) > POLE_LIM
1054 || !couldsee(mtmp->mx, mtmp->my))
1055 return; /* Out of range, or intervening wall */
1057 if (canseemon(mtmp)) {
1060 pline("%s thrusts %s.", Monnam(mtmp),
1061 obj_is_pname(otmp) ? the(onm) : an(onm));
1063 pline("%s
\82Í%s
\82ð
\93Ë
\82«
\8eh
\82µ
\82½
\81D", Monnam(mtmp), onm);
1067 dam = dmgval(otmp, &youmonst);
1068 hitv = 3 - distmin(u.ux, u.uy, mtmp->mx, mtmp->my);
1071 if (bigmonst(youmonst.data))
1073 hitv += 8 + otmp->spe;
1077 (void) thitu(hitv, dam, &otmp, (char *) 0);
1084 /* If you are coming toward the monster, the monster
1085 * should try to soften you up with missiles. If you are
1086 * going away, you are probably hurt or running. Give
1087 * chase, but if you are getting too far away, throw.
1090 || (URETREATING(x, y)
1091 && rn2(BOLT_LIM - distmin(x, y, mtmp->mux, mtmp->muy))))
1094 mwep = MON_WEP(mtmp); /* wielded weapon */
1095 monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */
1099 /* monster spits substance at you */
1103 struct attack *mattk;
1110 pline("A dry rattle comes from %s throat.",
1111 s_suffix(mon_nam(mtmp)));
1113 pline("
\8a£
\82¢
\82½
\83K
\83\89\83K
\83\89\89¹
\82ª%s
\82Ì
\82Ì
\82Ç
\82©
\82ç
\95·
\82±
\82¦
\82Ä
\82«
\82½
\81D",
1118 if (lined_up(mtmp)) {
1119 switch (mattk->adtyp) {
1122 otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
1125 impossible("bad attack type in spitmu");
1128 otmp = mksobj(ACID_VENOM, TRUE, FALSE);
1132 - distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy))) {
1133 if (canseemon(mtmp))
1135 pline("%s spits venom!", Monnam(mtmp));
1137 pline("%s
\82Í
\93Å
\89t
\82ð
\93f
\82¢
\82½
\81I", Monnam(mtmp));
1138 m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
1139 distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp);
1143 obj_extract_self(otmp);
1144 obfree(otmp, (struct obj *) 0);
1150 /* monster breathes at you (ranged) */
1154 struct attack *mattk;
1156 /* if new breath types are added, change AD_ACID to max type */
1157 int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp;
1159 if (lined_up(mtmp)) {
1162 if (canseemon(mtmp))
1164 pline("%s coughs.", Monnam(mtmp));
1166 pline("%s
\82Í
\82¹
\82«
\82ð
\82µ
\82½
\81D", Monnam(mtmp));
1169 You_hear("a cough.");
1171 You_hear("
\82¹
\82«
\82Ì
\89¹
\82ð
\95·
\82¢
\82½
\81D");
1175 if (!mtmp->mspec_used && rn2(3)) {
1176 if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
1177 if (canseemon(mtmp))
1179 pline("%s breathes %s!", Monnam(mtmp),
1180 breathwep[typ - 1]);
1182 pline("%s
\82Í%s
\82ð
\93f
\82¢
\82½
\81I", Monnam(mtmp),
1183 breathwep[typ - 1]);
1185 buzz((int) (-20 - (typ - 1)), (int) mattk->damn, mtmp->mx,
1186 mtmp->my, sgn(tbx), sgn(tby));
1188 /* breath runs out sometimes. Also, give monster some
1189 * cunning; don't breath if the player fell asleep.
1192 mtmp->mspec_used = 10 + rn2(20);
1193 if (typ == AD_SLEE && !Sleep_resistance)
1194 mtmp->mspec_used += rnd(20);
1196 impossible("Breath weapon %d used", typ - 1);
1203 linedup(ax, ay, bx, by, boulderhandling)
1204 register xchar ax, ay, bx, by;
1205 int boulderhandling; /* 0=block, 1=ignore, 2=conditionally block */
1207 int dx, dy, boulderspots;
1209 /* These two values are set for use after successful return. */
1213 /* sometimes displacement makes a monster think that you're at its
1214 own location; prevent it from throwing and zapping in that case */
1218 if ((!tbx || !tby || abs(tbx) == abs(tby)) /* straight line or diagonal */
1219 && distmin(tbx, tby, 0, 0) < BOLT_LIM) {
1220 if ((ax == u.ux && ay == u.uy) ? (boolean) couldsee(bx, by)
1221 : clear_path(ax, ay, bx, by))
1223 /* don't have line of sight, but might still be lined up
1224 if that lack of sight is due solely to boulders */
1225 if (boulderhandling == 0)
1227 dx = sgn(ax - bx), dy = sgn(ay - by);
1230 /* <bx,by> is guaranteed to eventually converge with <ax,ay> */
1232 if (IS_ROCK(levl[bx][by].typ) || closed_door(bx, by))
1234 if (sobj_at(BOULDER, bx, by))
1236 } while (bx != ax || by != ay);
1237 /* reached target position without encountering obstacle */
1238 if (boulderhandling == 1 || rn2(2 + boulderspots) < 2)
1245 m_lined_up(mtarg, mtmp)
1246 struct monst *mtarg, *mtmp;
1248 return (linedup(mtarg->mx, mtarg->my, mtmp->mx, mtmp->my, 0));
1252 /* is mtmp in position to use ranged attack? */
1255 register struct monst *mtmp;
1257 boolean ignore_boulders;
1259 /* hero concealment usually trumps monst awareness of being lined up */
1260 if (Upolyd && rn2(25)
1261 && (u.uundetected || (U_AP_TYPE != M_AP_NOTHING
1262 && U_AP_TYPE != M_AP_MONSTER)))
1265 ignore_boulders = (throws_rocks(mtmp->data)
1266 || m_carrying(mtmp, WAN_STRIKING));
1267 return linedup(mtmp->mux, mtmp->muy, mtmp->mx, mtmp->my,
1268 ignore_boulders ? 1 : 2);
1271 /* check if a monster is carrying a particular item */
1273 m_carrying(mtmp, type)
1277 register struct obj *otmp;
1279 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
1280 if (otmp->otyp == type)
1282 return (struct obj *) 0;
1286 hit_bars(objp, objx, objy, barsx, barsy, your_fault, from_invent)
1287 struct obj **objp; /* *objp will be set to NULL if object breaks */
1288 int objx, objy, barsx, barsy;
1289 boolean your_fault, from_invent;
1291 struct obj *otmp = *objp;
1292 int obj_type = otmp->otyp;
1293 boolean unbreakable = (levl[barsx][barsy].wall_info & W_NONDIGGABLE) != 0;
1296 ? hero_breaks(otmp, objx, objy, from_invent)
1297 : breaks(otmp, objx, objy)) {
1298 *objp = 0; /* object is now gone */
1299 /* breakage makes its own noises */
1300 if (obj_type == POT_ACID) {
1301 if (cansee(barsx, barsy) && !unbreakable)
1303 pline_The("iron bars are dissolved!");
1305 pline_The("
\93S
\82Ì
\96_
\82Í
\97Z
\82¯
\82½
\81I");
1308 You_hear(Hallucination ? "angry snakes!" : "a hissing noise.");
1310 You_hear(Hallucination ? "
\93{
\82Á
\82½
\82Ö
\82Ñ
\82Ì
\90º
\82ð
\95·
\82¢
\82½
\81I" : "
\83V
\81[
\83b
\82Æ
\82¢
\82¤
\89¹
\82ð
\95·
\82¢
\82½
\81D");
1312 dissolve_bars(barsx, barsy);
1315 else if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL)
1319 pline("
\82®
\82í
\81[
\82ñ
\81I");
1320 else if (otmp->oclass == COIN_CLASS
1321 || objects[obj_type].oc_material == GOLD
1322 || objects[obj_type].oc_material == SILVER)
1326 pline("
\83`
\83\83\83\8a\83\93\81I");
1331 pline("
\83S
\83c
\83\93\81I");
1334 /* TRUE iff thrown/kicked/rolled object doesn't pass through iron bars */
1336 hits_bars(obj_p, x, y, barsx, barsy, always_hit, whodidit)
1337 struct obj **obj_p; /* *obj_p will be set to NULL if object breaks */
1338 int x, y, barsx, barsy;
1339 int always_hit; /* caller can force a hit for items which would fit through */
1340 int whodidit; /* 1==hero, 0=other, -1==just check whether it'll pass thru */
1342 struct obj *otmp = *obj_p;
1343 int obj_type = otmp->otyp;
1344 boolean hits = always_hit;
1347 switch (otmp->oclass) {
1348 case WEAPON_CLASS: {
1349 int oskill = objects[obj_type].oc_skill;
1351 hits = (oskill != -P_BOW && oskill != -P_CROSSBOW
1352 && oskill != -P_DART && oskill != -P_SHURIKEN
1353 && oskill != P_SPEAR
1354 && oskill != P_KNIFE); /* but not dagger */
1358 hits = (objects[obj_type].oc_armcat != ARM_GLOVES);
1361 hits = (obj_type != SKELETON_KEY && obj_type != LOCK_PICK
1362 && obj_type != CREDIT_CARD && obj_type != TALLOW_CANDLE
1363 && obj_type != WAX_CANDLE && obj_type != LENSES
1364 && obj_type != TIN_WHISTLE && obj_type != MAGIC_WHISTLE);
1366 case ROCK_CLASS: /* includes boulder */
1367 if (obj_type != STATUE || mons[otmp->corpsenm].msize > MZ_TINY)
1371 if (obj_type == CORPSE && mons[otmp->corpsenm].msize > MZ_TINY)
1374 hits = (obj_type == MEAT_STICK
1375 || obj_type == HUGE_CHUNK_OF_MEAT);
1387 if (hits && whodidit != -1) {
1388 hit_bars(obj_p, x,y, barsx,barsy, whodidit, FALSE);