1 /* NetHack 3.6 mthrowu.c $NHDT-Date: 1573688695 2019/11/13 23:44:55 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.86 $ */
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-2020 */
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 /* for arrow, we checked bow&arrow when entering block, but for
233 bow, so far we've only validated that otmp is a weapon stack;
234 need to verify that it's a stack of arrows rather than darts */
235 if (mwep && mwep->otyp == ELVEN_BOW && ammo_and_launcher(otmp, mwep)
238 /* 1/3 of launcher enchantment */
239 if (ammo_and_launcher(otmp, mwep) && mwep->spe > 1)
240 multishot += (long) rounddiv(mwep->spe, 3);
241 /* Some randomness */
242 multishot = (long) rnd((int) multishot);
245 switch (monsndx(mtmp->data)) {
246 case PM_CAVEMAN: /* give bonus for low-tech gear */
247 if (skill == -P_SLING || skill == P_SPEAR)
250 case PM_MONK: /* allow higher volley count */
251 if (skill == -P_SHURIKEN)
255 if (skill != P_DAGGER)
259 if (skill == P_DAGGER)
263 if (skill == -P_SHURIKEN || skill == -P_DART)
267 if (otmp->otyp == YA && mwep->otyp == YUMI)
274 if ((is_elf(mtmp->data) && otmp->otyp == ELVEN_ARROW
275 && mwep->otyp == ELVEN_BOW)
276 || (is_orc(mtmp->data) && otmp->otyp == ORCISH_ARROW
277 && mwep->otyp == ORCISH_BOW)
278 || (is_gnome(mtmp->data) && otmp->otyp == CROSSBOW_BOLT
279 && mwep->otyp == CROSSBOW))
283 if (otmp->quan < multishot)
284 multishot = (int) otmp->quan;
290 /* mtmp throws otmp, or shoots otmp with mwep, at hero or at monster mtarg */
292 monshoot(mtmp, otmp, mwep)
294 struct obj *otmp, *mwep;
296 struct monst *mtarg = target;
297 int dm = distmin(mtmp->mx, mtmp->my,
298 mtarg ? mtarg->mx : mtmp->mux,
299 mtarg ? mtarg->my : mtmp->muy),
300 multishot = monmulti(mtmp, otmp, mwep);
302 * Caller must have called linedup() to set up tbx, tby.
305 if (canseemon(mtmp)) {
307 char onmbuf[BUFSZ], trgbuf[BUFSZ];
310 /* "N arrows"; multishot > 1 implies otmp->quan > 1, so
311 xname()'s result will already be pluralized */
313 Sprintf(onmbuf, "%d %s", multishot, xname(otmp));
315 Sprintf(onmbuf, "%d%s
\82Ì%s", multishot, numeral(otmp), xname(otmp));
319 onm = singular(otmp, xname);
320 onm = obj_is_pname(otmp) ? the(onm) : an(onm);
322 m_shot.s = ammo_and_launcher(otmp, mwep) ? TRUE : FALSE;
323 Strcpy(trgbuf, mtarg ? mon_nam(mtarg) : "");
324 #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*/
325 if (!strcmp(trgbuf, "it"))
326 Strcpy(trgbuf, humanoid(mtmp->data) ? "someone" : something);
329 pline("%s %s %s%s%s!", Monnam(mtmp),
330 m_shot.s ? "shoots" : "throws", onm,
331 mtarg ? " at " : "", trgbuf);
333 pline("%s
\82Í%s
\82ð%s
\82É%s
\81I", Monnam(mtmp),
336 m_shot.s ? "
\8c\82\82Á
\82½" : "
\93\8a\82°
\82½");
338 m_shot.o = otmp->otyp;
340 m_shot.o = STRANGE_OBJECT; /* don't give multishot feedback */
342 m_shot.n = multishot;
343 for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
344 m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), dm, otmp);
345 /* conceptually all N missiles are in flight at once, but
346 if mtmp gets killed (shot kills adjacent gas spore and
347 triggers explosion, perhaps), inventory will be dropped
348 and otmp might go away via merging into another stack */
349 if (DEADMONSTER(mtmp) && m_shot.i < m_shot.n)
350 /* cancel pending shots (perhaps ought to give a message here
351 since we gave one above about throwing/shooting N missiles) */
352 break; /* endmultishot(FALSE); */
355 m_shot.n = m_shot.i = 0;
356 m_shot.o = STRANGE_OBJECT;
360 /* an object launched by someone/thing other than player attacks a monster;
361 return 1 if the object has stopped moving (hit or its range used up) */
363 ohitmon(mtmp, otmp, range, verbose)
364 struct monst *mtmp; /* accidental target, located at <bhitpos.x,.y> */
365 struct obj *otmp; /* missile; might be destroyed by drop_throw */
366 int range; /* how much farther will object travel if it misses;
367 use -1 to signify to keep going even after hit,
368 unless it's gone (used for rolling_boulder_traps) */
369 boolean verbose; /* give message(s) even when you can't see what happened */
372 boolean vis, ismimic;
374 struct obj *mon_launcher = archer ? MON_WEP(archer) : NULL;
376 notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
377 ismimic = M_AP_TYPE(mtmp) && M_AP_TYPE(mtmp) != M_AP_MONSTER;
378 vis = cansee(bhitpos.x, bhitpos.y);
380 tmp = 5 + find_mac(mtmp) + omon_adj(mtmp, otmp, FALSE);
381 /* High level monsters will be more likely to hit */
382 /* This check applies only if this monster is the target
383 * the archer was aiming at. */
384 if (archer && target == mtmp) {
385 if (archer->m_lev > 5)
386 tmp += archer->m_lev - 5;
387 if (mon_launcher && mon_launcher->oartifact)
388 tmp += spec_abon(mon_launcher, mtmp);
393 miss(distant_name(otmp, mshot_xname), mtmp);
394 else if (verbose && !target)
396 pline("It is missed.");
398 pline("
\89½
\82©
\82ª
\82©
\82·
\82ß
\82½
\81D");
400 if (!range) { /* Last position; object drops */
401 (void) drop_throw(otmp, 0, mtmp->mx, mtmp->my);
404 } else if (otmp->oclass == POTION_CLASS) {
410 /* probably thrown by a monster rather than 'other', but the
411 distinction only matters when hitting the hero */
412 potionhit(mtmp, otmp, POTHIT_OTHER_THROW);
415 damage = dmgval(otmp, mtmp);
416 if (otmp->otyp == ACID_VENOM && resists_acid(mtmp))
418 #if 0 /* can't use this because we don't have the attacker */
419 if (is_orc(mtmp->data) && is_elf(?magr?))
426 if (otmp->otyp == EGG)
428 pline("Splat! %s is hit with %s egg!", Monnam(mtmp),
429 otmp->known ? an(mons[otmp->corpsenm].mname) : "an");
431 pline("
\83r
\83`
\83\83\83b
\81I%s
\82Í%s
\97\91\82É
\93\96\82½
\82Á
\82½
\81I", Monnam(mtmp),
432 otmp->known ? s_suffix(mons[otmp->corpsenm].mname) : "");
435 hit(distant_name(otmp, mshot_xname), mtmp, exclam(damage));
436 } else if (verbose && !target)
438 pline("%s%s is hit%s", (otmp->otyp == EGG) ? "Splat! " : "",
439 Monnam(mtmp), exclam(damage));
441 pline("%s%s
\82É
\96½
\92\86\82µ
\82½%s", (otmp->otyp == EGG) ? "
\83r
\83`
\83\83\83b
\81I" : "",
442 Monnam(mtmp), exclam(damage));
445 if (otmp->opoisoned && is_poisonable(otmp)) {
446 if (resists_poison(mtmp)) {
449 pline_The("poison doesn't seem to affect %s.",
451 pline("%s
\82Í
\93Å
\82Ì
\89e
\8b¿
\82ð
\8eó
\82¯
\82È
\82¢
\82æ
\82¤
\82¾
\81D",
459 pline_The("poison was deadly...");
461 pline("
\93Å
\82Í
\92v
\8e\80\97Ê
\82¾
\82Á
\82½
\81D
\81D
\81D");
466 if (objects[otmp->otyp].oc_material == SILVER
467 && mon_hates_silver(mtmp)) {
468 boolean flesh = (!noncorporeal(mtmp->data)
469 && !amorphous(mtmp->data));
471 /* note: extra silver damage is handled by dmgval() */
473 char *m_name = mon_nam(mtmp);
475 if (flesh) /* s_suffix returns a modifiable buffer */
477 m_name = strcat(s_suffix(m_name), " flesh");
479 m_name = strcat(s_suffix(m_name), "
\82Ì
\91Ì");
481 pline_The("silver sears %s!", m_name);
483 pline("%s
\82Í
\8bâ
\82Å
\8fÄ
\82©
\82ê
\82½
\81I", m_name);
484 } else if (verbose && !target) {
486 pline("%s is seared!", flesh ? "Its flesh" : "It");
488 pline("
\89½%s
\82Í
\8fÄ
\82©
\82ê
\82½
\81I", flesh ? "
\8eÒ
\82©
\82Ì
\91Ì" : "
\82©");
491 if (otmp->otyp == ACID_VENOM && cansee(mtmp->mx, mtmp->my)) {
492 if (resists_acid(mtmp)) {
493 if (vis || (verbose && !target))
495 pline("%s is unaffected.", Monnam(mtmp));
497 pline("%s
\82Í
\89e
\8b¿
\82ð
\8eó
\82¯
\82È
\82¢
\81D", Monnam(mtmp));
501 pline_The("%s burns %s!", hliquid("acid"), mon_nam(mtmp));
503 pline_The("%s
\82Í%s
\82Å
\8fÄ
\82©
\82ê
\82½
\81I", mon_nam(mtmp), hliquid("
\8e_"));
504 else if (verbose && !target)
506 pline("It is burned!");
508 pline("
\89½
\82©
\82Í
\8fÄ
\82©
\82ê
\82½
\81I");
511 if (otmp->otyp == EGG && touch_petrifies(&mons[otmp->corpsenm])) {
512 if (!munstone(mtmp, TRUE))
513 minstapetrify(mtmp, TRUE);
514 if (resists_ston(mtmp))
518 if (!DEADMONSTER(mtmp)) { /* might already be dead (if petrified) */
520 if (DEADMONSTER(mtmp)) {
521 if (vis || (verbose && !target))
523 pline("%s is %s!", Monnam(mtmp),
524 (nonliving(mtmp->data) || is_vampshifter(mtmp)
525 || !canspotmon(mtmp)) ? "destroyed" : "killed");
527 pline("%s
\82Í%s
\81I", Monnam(mtmp),
528 (nonliving(mtmp->data) || is_vampshifter(mtmp)
529 || !canspotmon(mtmp)) ? "
\93|
\82³
\82ê
\82½" : "
\8e\80\82ñ
\82¾");
531 /* don't blame hero for unknown rolling boulder trap */
532 if (!context.mon_moving && (otmp->otyp != BOULDER
533 || range >= 0 || otmp->otrapped))
534 xkilled(mtmp, XKILL_NOMSG);
540 /* blinding venom and cream pie do 0 damage, but verify
541 that the target is still alive anyway */
542 if (!DEADMONSTER(mtmp)
543 && can_blnd((struct monst *) 0, mtmp,
544 (uchar) ((otmp->otyp == BLINDING_VENOM) ? AT_SPIT
547 if (vis && mtmp->mcansee)
549 pline("%s is blinded by %s.", Monnam(mtmp), the(xname(otmp)));
551 pline("%s
\82Í%s
\82É
\82æ
\82Á
\82Ä
\96Ú
\82ª
\8c©
\82¦
\82È
\82
\82È
\82Á
\82½
\81D", Monnam(mtmp), the(xname(otmp)));
553 tmp = (int) mtmp->mblinded + rnd(25) + 20;
556 mtmp->mblinded = tmp;
559 objgone = drop_throw(otmp, 1, bhitpos.x, bhitpos.y);
560 if (!objgone && range == -1) { /* special case */
561 obj_extract_self(otmp); /* free it for motion again */
569 #define MT_FLIGHTCHECK(pre) \
570 (/* missile hits edge of screen */ \
571 !isok(bhitpos.x + dx, bhitpos.y + dy) \
572 /* missile hits the wall */ \
573 || IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ) \
574 /* missile hit closed door */ \
575 || closed_door(bhitpos.x + dx, bhitpos.y + dy) \
576 /* missile might hit iron bars */ \
577 /* the random chance for small objects hitting bars is */ \
578 /* skipped when reaching them at point blank range */ \
579 || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS \
580 && hits_bars(&singleobj, \
581 bhitpos.x, bhitpos.y, \
582 bhitpos.x + dx, bhitpos.y + dy, \
583 ((pre) ? 0 : !rn2(5)), 0)) \
584 /* Thrown objects "sink" */ \
585 || (!(pre) && IS_SINK(levl[bhitpos.x][bhitpos.y].typ)))
588 m_throw(mon, x, y, dx, dy, range, obj)
589 struct monst *mon; /* launching monster */
590 int x, y, dx, dy, range; /* launch point, direction, and range */
591 struct obj *obj; /* missile (or stack providing it) */
594 struct obj *singleobj;
595 char sym = obj->oclass;
596 int hitu = 0, oldumort, blindinc = 0;
600 notonhead = FALSE; /* reset potentially stale value */
602 if (obj->quan == 1L) {
604 * Remove object from minvent. This cannot be done later on;
605 * what if the player dies before then, leaving the monster
606 * with 0 daggers? (This caused the infamous 2^32-1 orcish
609 * VENOM is not in minvent - it should already be OBJ_FREE.
610 * The extract below does nothing.
613 /* not possibly_unwield, which checks the object's */
614 /* location, not its existence */
615 if (MON_WEP(mon) == obj)
616 setmnotwielded(mon, obj);
617 obj_extract_self(obj);
619 obj = (struct obj *) 0;
621 singleobj = splitobj(obj, 1L);
622 obj_extract_self(singleobj);
625 singleobj->owornmask = 0; /* threw one of multiple weapons in hand? */
627 if ((singleobj->cursed || singleobj->greased) && (dx || dy) && !rn2(7)) {
628 if (canseemon(mon) && flags.verbose) {
629 if (is_ammo(singleobj))
631 pline("%s misfires!", Monnam(mon));
633 pline("%s
\82Í
\82Í
\82¸
\82µ
\82½
\81I", Monnam(mon));
636 pline("%s as %s throws it!", Tobjnam(singleobj, "slip"),
639 pline("%s
\82ª
\93\8a\82°
\82æ
\82¤
\82Æ
\82µ
\82½
\82Æ
\82½
\82ñ%s
\82ª
\8a\8a\82Á
\82½
\81I",
640 mon_nam(mon), xname(singleobj));
645 /* check validity of new direction */
647 (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
652 if (MT_FLIGHTCHECK(TRUE)) {
653 (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
656 mesg_given = 0; /* a 'missile misses' message has not yet been shown */
658 /* Note: drop_throw may destroy singleobj. Since obj must be destroyed
659 * early to avoid the dagger bug, anyone who modifies this code should
660 * be careful not to use either one after it's been freed.
663 tmp_at(DISP_FLASH, obj_to_glyph(singleobj, rn2_on_display_rng));
664 while (range-- > 0) { /* Actually the loop is always exited by break */
667 mtmp = m_at(bhitpos.x, bhitpos.y);
668 if (mtmp && shade_miss(mon, mtmp, singleobj, TRUE, TRUE)) {
669 /* if mtmp is a shade and missile passes harmlessly through it,
670 give message and skip it in order to keep going */
671 mtmp = (struct monst *) 0;
673 if (ohitmon(mtmp, singleobj, range, TRUE))
675 } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
679 if (singleobj->oclass == GEM_CLASS
680 && singleobj->otyp <= LAST_GEM + 9 /* 9 glass colors */
681 && is_unicorn(youmonst.data)) {
682 if (singleobj->otyp > LAST_GEM) {
684 You("catch the %s.", xname(singleobj));
686 You("%s
\82ð
\82Â
\82©
\82Ü
\82¦
\82½
\81D", xname(singleobj));
688 You("are not interested in %s junk.",
689 s_suffix(mon_nam(mon)));
691 You("%s
\82Ì
\83K
\83\89\83N
\83^
\82É
\8b»
\96¡
\82Í
\82È
\82¢
\81D",
694 makeknown(singleobj->otyp);
699 "accept %s gift in the spirit in which it was intended.",
701 "
\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",
702 s_suffix(mon_nam(mon)));
704 (void) hold_another_object(singleobj,
705 "You catch, but drop, %s.",
709 (void) hold_another_object(singleobj,
710 "
\82 \82È
\82½
\82Í%s
\82ð
\82Â
\82©
\82Ü
\82¦
\82½
\82ª
\81C
\97\8e\82µ
\82½
\81D",
712 "
\82ð
\82Â
\82©
\82Ü
\82¦
\82½
\81D");
717 if (singleobj->oclass == POTION_CLASS) {
719 singleobj->dknown = 1;
720 potionhit(&youmonst, singleobj, POTHIT_MONST_THROW);
723 oldumort = u.umortality;
724 switch (singleobj->otyp) {
727 if (!touch_petrifies(&mons[singleobj->corpsenm])) {
728 impossible("monster throwing egg type %d",
729 singleobj->corpsenm);
736 hitu = thitu(8, 0, &singleobj, (char *) 0);
739 dam = dmgval(singleobj, &youmonst);
740 hitv = 3 - distmin(u.ux, u.uy, mon->mx, mon->my);
743 if (is_elf(mon->data)
744 && objects[singleobj->otyp].oc_skill == P_BOW) {
746 if (MON_WEP(mon) && MON_WEP(mon)->otyp == ELVEN_BOW)
748 if (singleobj->otyp == ELVEN_ARROW)
751 if (bigmonst(youmonst.data))
753 hitv += 8 + singleobj->spe;
756 hitu = thitu(hitv, dam, &singleobj, (char *) 0);
758 if (hitu && singleobj->opoisoned && is_poisonable(singleobj)) {
759 char onmbuf[BUFSZ], knmbuf[BUFSZ];
761 Strcpy(onmbuf, xname(singleobj));
762 Strcpy(knmbuf, killer_xname(singleobj));
763 poisoned(onmbuf, A_STR, knmbuf,
764 /* if damage triggered life-saving,
765 poison is limited to attrib loss */
766 (u.umortality > oldumort) ? 0 : 10, TRUE);
768 if (hitu && can_blnd((struct monst *) 0, &youmonst,
769 (uchar) ((singleobj->otyp == BLINDING_VENOM)
774 if (singleobj->otyp == CREAM_PIE) {
777 pline("Yecch! You've been creamed.");
779 pline("
\83E
\83F
\81[
\81D
\83N
\83\8a\81[
\83\80\82ð
\82©
\82Ô
\82Á
\82½
\81D");
782 pline("There's %s sticky all over your %s.",
783 something, body_part(FACE));
785 pline("
\82 \82È
\82½
\82Í%s
\82É
\82×
\82Æ
\82Â
\82
\82à
\82Ì
\82ð
\8a´
\82¶
\82½
\81D",
788 } else if (singleobj->otyp == BLINDING_VENOM) {
790 const char *eyes = body_part(EYE);
792 if (eyecount(youmonst.data) != 1)
793 eyes = makeplural(eyes);
794 /* venom in the eyes */
796 pline_The("venom blinds you.");
798 Your("%s %s.", eyes, vtense(eyes, "sting"));
801 pline("
\93Å
\82Å
\96Ú
\82ª
\8c©
\82¦
\82È
\82
\82È
\82Á
\82½
\81D");
803 Your("%s
\82Í
\82¿
\82
\82¿
\82
\82µ
\82½
\81D", body_part(EYE));
807 if (hitu && singleobj->otyp == EGG) {
808 if (!Stoned && !Stone_resistance
809 && !(poly_when_stoned(youmonst.data)
810 && polymon(PM_STONE_GOLEM))) {
811 make_stoned(5L, (char *) 0, KILLED_BY, "");
816 (void) drop_throw(singleobj, hitu, u.ux, u.uy);
820 if (!range /* reached end of path */
821 || MT_FLIGHTCHECK(FALSE)) {
822 if (singleobj) { /* hits_bars might have destroyed it */
824 && (!mesg_given || bhitpos.x != u.ux || bhitpos.y != u.uy)
825 && (cansee(bhitpos.x, bhitpos.y)
826 || (archer && canseemon(archer))))
828 pline("%s misses.", The(mshot_xname(singleobj)));
830 pline("%s
\82Í
\82Í
\82¸
\82ê
\82½
\81D", mshot_xname(singleobj));
831 (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
835 tmp_at(bhitpos.x, bhitpos.y);
838 tmp_at(bhitpos.x, bhitpos.y);
841 mesg_given = 0; /* reset */
844 u.ucreamed += blindinc;
845 make_blinded(Blinded + (long) blindinc, FALSE);
847 Your1(vision_clears);
851 #undef MT_FLIGHTCHECK
853 /* Monster throws item at another monster */
856 struct monst *mtmp, *mtarg;
858 struct obj *otmp, *mwep;
862 /* Polearms won't be applied by monsters against other monsters */
863 if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
864 mtmp->weapon_check = NEED_RANGED_WEAPON;
865 /* mon_wield_item resets weapon_check as appropriate */
866 if (mon_wield_item(mtmp) != 0)
871 otmp = select_rwep(mtmp);
874 ispole = is_pole(otmp);
879 mwep = MON_WEP(mtmp); /* wielded weapon */
881 if (!ispole && m_lined_up(mtarg, mtmp)) {
882 int chance = max(BOLT_LIM - distmin(x, y, mtarg->mx, mtarg->my), 1);
884 if (!mtarg->mflee || !rn2(chance)) {
885 if (ammo_and_launcher(otmp, mwep)
886 && dist2(mtmp->mx, mtmp->my, mtarg->mx, mtarg->my)
887 > PET_MISSILE_RANGE2)
888 return 0; /* Out of range */
889 /* Set target monster */
892 monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */
893 archer = target = (struct monst *) 0;
901 /* monster spits substance at monster */
903 spitmm(mtmp, mattk, mtarg)
904 struct monst *mtmp, *mtarg;
905 struct attack *mattk;
912 pline("A dry rattle comes from %s throat.",
913 s_suffix(mon_nam(mtmp)));
915 pline("%s
\82Ì
\8dA
\82ª
\83K
\83\89\83K
\83\89\82Æ
\96Â
\82Á
\82½
\81D",
920 if (m_lined_up(mtarg, mtmp)) {
921 switch (mattk->adtyp) {
924 otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
927 impossible("bad attack type in spitmu");
930 otmp = mksobj(ACID_VENOM, TRUE, FALSE);
933 if (!rn2(BOLT_LIM-distmin(mtmp->mx,mtmp->my,mtarg->mx,mtarg->my))) {
936 pline("%s spits venom!", Monnam(mtmp));
938 pline("%s
\82Í
\93Å
\82ð
\93f
\82¢
\82½
\81I", Monnam(mtmp));
940 m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
941 distmin(mtmp->mx,mtmp->my,mtarg->mx,mtarg->my), otmp);
942 target = (struct monst *)0;
945 /* If this is a pet, it'll get hungry. Minions and
946 * spell beings won't hunger */
947 if (mtmp->mtame && !mtmp->isminion) {
948 struct edog *dog = EDOG(mtmp);
950 /* Hunger effects will catch up next move */
951 if (dog->hungrytime > 1)
952 dog->hungrytime -= 5;
961 /* monster breathes at monster (ranged) */
963 breamm(mtmp, mattk, mtarg)
964 struct monst *mtmp, *mtarg;
965 struct attack *mattk;
967 /* if new breath types are added, change AD_ACID to max type */
968 int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp ;
970 if (m_lined_up(mtarg, mtmp)) {
975 pline("%s coughs.", Monnam(mtmp));
977 pline("%s
\82Í
\82¹
\82«
\82ð
\82µ
\82½
\81D", Monnam(mtmp));
980 You_hear("a cough.");
982 You_hear("
\82¹
\82«
\82Ì
\89¹
\82ð
\95·
\82¢
\82½
\81D");
986 if (!mtmp->mspec_used && rn2(3)) {
987 if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
990 pline("%s breathes %s!", Monnam(mtmp), breathwep[typ - 1]);
992 pline("%s
\82Í%s
\82ð
\82Í
\82¢
\82½
\81I", Monnam(mtmp), breathwep[typ - 1]);
993 dobuzz((int) (-20 - (typ - 1)), (int) mattk->damn,
994 mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), FALSE);
996 /* breath runs out sometimes. Also, give monster some
997 * cunning; don't breath if the target fell asleep.
999 mtmp->mspec_used = 6 + rn2(18);
1001 /* If this is a pet, it'll get hungry. Minions and
1002 * spell beings won't hunger */
1003 if (mtmp->mtame && !mtmp->isminion) {
1004 struct edog *dog = EDOG(mtmp);
1006 /* Hunger effects will catch up next move */
1007 if (dog->hungrytime >= 10)
1008 dog->hungrytime -= 10;
1010 } else impossible("Breath weapon %d used", typ-1);
1019 /* remove an entire item from a monster's inventory; destroy that item */
1021 m_useupall(mon, obj)
1025 obj_extract_self(obj);
1026 if (obj->owornmask) {
1027 if (obj == MON_WEP(mon))
1029 mon->misc_worn_check &= ~obj->owornmask;
1030 update_mon_intrinsics(mon, obj, FALSE, FALSE);
1031 obj->owornmask = 0L;
1033 obfree(obj, (struct obj *) 0);
1036 /* remove one instance of an item from a monster's inventory */
1042 if (obj->quan > 1L) {
1044 obj->owt = weight(obj);
1046 m_useupall(mon, obj);
1050 /* monster attempts ranged weapon attack against player */
1055 struct obj *otmp, *mwep;
1059 /* Rearranged beginning so monsters can use polearms not in a line */
1060 if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
1061 mtmp->weapon_check = NEED_RANGED_WEAPON;
1062 /* mon_wield_item resets weapon_check as appropriate */
1063 if (mon_wield_item(mtmp) != 0)
1068 otmp = select_rwep(mtmp);
1072 if (is_pole(otmp)) {
1075 if (otmp != MON_WEP(mtmp))
1076 return; /* polearm must be wielded */
1077 if (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) > POLE_LIM
1078 || !couldsee(mtmp->mx, mtmp->my))
1079 return; /* Out of range, or intervening wall */
1081 if (canseemon(mtmp)) {
1084 pline("%s thrusts %s.", Monnam(mtmp),
1085 obj_is_pname(otmp) ? the(onm) : an(onm));
1087 pline("%s
\82Í%s
\82ð
\93Ë
\82«
\8eh
\82µ
\82½
\81D", Monnam(mtmp), onm);
1091 dam = dmgval(otmp, &youmonst);
1092 hitv = 3 - distmin(u.ux, u.uy, mtmp->mx, mtmp->my);
1095 if (bigmonst(youmonst.data))
1097 hitv += 8 + otmp->spe;
1101 (void) thitu(hitv, dam, &otmp, (char *) 0);
1108 /* If you are coming toward the monster, the monster
1109 * should try to soften you up with missiles. If you are
1110 * going away, you are probably hurt or running. Give
1111 * chase, but if you are getting too far away, throw.
1114 || (URETREATING(x, y)
1115 && rn2(BOLT_LIM - distmin(x, y, mtmp->mux, mtmp->muy))))
1118 mwep = MON_WEP(mtmp); /* wielded weapon */
1119 monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */
1123 /* monster spits substance at you */
1127 struct attack *mattk;
1134 pline("A dry rattle comes from %s throat.",
1135 s_suffix(mon_nam(mtmp)));
1137 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",
1142 if (lined_up(mtmp)) {
1143 switch (mattk->adtyp) {
1146 otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
1149 impossible("bad attack type in spitmu");
1152 otmp = mksobj(ACID_VENOM, TRUE, FALSE);
1156 - distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy))) {
1157 if (canseemon(mtmp))
1159 pline("%s spits venom!", Monnam(mtmp));
1161 pline("%s
\82Í
\93Å
\89t
\82ð
\93f
\82¢
\82½
\81I", Monnam(mtmp));
1162 m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
1163 distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp);
1167 obj_extract_self(otmp);
1168 obfree(otmp, (struct obj *) 0);
1174 /* monster breathes at you (ranged) */
1178 struct attack *mattk;
1180 /* if new breath types are added, change AD_ACID to max type */
1181 int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp;
1183 if (lined_up(mtmp)) {
1186 if (canseemon(mtmp))
1188 pline("%s coughs.", Monnam(mtmp));
1190 pline("%s
\82Í
\82¹
\82«
\82ð
\82µ
\82½
\81D", Monnam(mtmp));
1193 You_hear("a cough.");
1195 You_hear("
\82¹
\82«
\82Ì
\89¹
\82ð
\95·
\82¢
\82½
\81D");
1199 if (!mtmp->mspec_used && rn2(3)) {
1200 if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
1201 if (canseemon(mtmp))
1203 pline("%s breathes %s!", Monnam(mtmp),
1204 breathwep[typ - 1]);
1206 pline("%s
\82Í%s
\82ð
\93f
\82¢
\82½
\81I", Monnam(mtmp),
1207 breathwep[typ - 1]);
1209 buzz((int) (-20 - (typ - 1)), (int) mattk->damn, mtmp->mx,
1210 mtmp->my, sgn(tbx), sgn(tby));
1212 /* breath runs out sometimes. Also, give monster some
1213 * cunning; don't breath if the player fell asleep.
1216 mtmp->mspec_used = 10 + rn2(20);
1217 if (typ == AD_SLEE && !Sleep_resistance)
1218 mtmp->mspec_used += rnd(20);
1220 impossible("Breath weapon %d used", typ - 1);
1227 linedup(ax, ay, bx, by, boulderhandling)
1228 register xchar ax, ay, bx, by;
1229 int boulderhandling; /* 0=block, 1=ignore, 2=conditionally block */
1231 int dx, dy, boulderspots;
1233 /* These two values are set for use after successful return. */
1237 /* sometimes displacement makes a monster think that you're at its
1238 own location; prevent it from throwing and zapping in that case */
1242 if ((!tbx || !tby || abs(tbx) == abs(tby)) /* straight line or diagonal */
1243 && distmin(tbx, tby, 0, 0) < BOLT_LIM) {
1244 if ((ax == u.ux && ay == u.uy) ? (boolean) couldsee(bx, by)
1245 : clear_path(ax, ay, bx, by))
1247 /* don't have line of sight, but might still be lined up
1248 if that lack of sight is due solely to boulders */
1249 if (boulderhandling == 0)
1251 dx = sgn(ax - bx), dy = sgn(ay - by);
1254 /* <bx,by> is guaranteed to eventually converge with <ax,ay> */
1256 if (IS_ROCK(levl[bx][by].typ) || closed_door(bx, by))
1258 if (sobj_at(BOULDER, bx, by))
1260 } while (bx != ax || by != ay);
1261 /* reached target position without encountering obstacle */
1262 if (boulderhandling == 1 || rn2(2 + boulderspots) < 2)
1269 m_lined_up(mtarg, mtmp)
1270 struct monst *mtarg, *mtmp;
1272 return (linedup(mtarg->mx, mtarg->my, mtmp->mx, mtmp->my, 0));
1276 /* is mtmp in position to use ranged attack? */
1279 register struct monst *mtmp;
1281 boolean ignore_boulders;
1283 /* hero concealment usually trumps monst awareness of being lined up */
1284 if (Upolyd && rn2(25)
1285 && (u.uundetected || (U_AP_TYPE != M_AP_NOTHING
1286 && U_AP_TYPE != M_AP_MONSTER)))
1289 ignore_boulders = (throws_rocks(mtmp->data)
1290 || m_carrying(mtmp, WAN_STRIKING));
1291 return linedup(mtmp->mux, mtmp->muy, mtmp->mx, mtmp->my,
1292 ignore_boulders ? 1 : 2);
1295 /* check if a monster is carrying a particular item */
1297 m_carrying(mtmp, type)
1301 register struct obj *otmp;
1303 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
1304 if (otmp->otyp == type)
1306 return (struct obj *) 0;
1310 hit_bars(objp, objx, objy, barsx, barsy, your_fault, from_invent)
1311 struct obj **objp; /* *objp will be set to NULL if object breaks */
1312 int objx, objy, barsx, barsy;
1313 boolean your_fault, from_invent;
1315 struct obj *otmp = *objp;
1316 int obj_type = otmp->otyp;
1317 boolean unbreakable = (levl[barsx][barsy].wall_info & W_NONDIGGABLE) != 0;
1320 ? hero_breaks(otmp, objx, objy, from_invent)
1321 : breaks(otmp, objx, objy)) {
1322 *objp = 0; /* object is now gone */
1323 /* breakage makes its own noises */
1324 if (obj_type == POT_ACID) {
1325 if (cansee(barsx, barsy) && !unbreakable)
1327 pline_The("iron bars are dissolved!");
1329 pline_The("
\93S
\82Ì
\96_
\82Í
\97Z
\82¯
\82½
\81I");
1332 You_hear(Hallucination ? "angry snakes!" : "a hissing noise.");
1334 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");
1336 dissolve_bars(barsx, barsy);
1339 else if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL)
1343 pline("
\82®
\82í
\81[
\82ñ
\81I");
1344 else if (otmp->oclass == COIN_CLASS
1345 || objects[obj_type].oc_material == GOLD
1346 || objects[obj_type].oc_material == SILVER)
1350 pline("
\83`
\83\83\83\8a\83\93\81I");
1355 pline("
\83S
\83c
\83\93\81I");
1358 /* TRUE iff thrown/kicked/rolled object doesn't pass through iron bars */
1360 hits_bars(obj_p, x, y, barsx, barsy, always_hit, whodidit)
1361 struct obj **obj_p; /* *obj_p will be set to NULL if object breaks */
1362 int x, y, barsx, barsy;
1363 int always_hit; /* caller can force a hit for items which would fit through */
1364 int whodidit; /* 1==hero, 0=other, -1==just check whether it'll pass thru */
1366 struct obj *otmp = *obj_p;
1367 int obj_type = otmp->otyp;
1368 boolean hits = always_hit;
1371 switch (otmp->oclass) {
1372 case WEAPON_CLASS: {
1373 int oskill = objects[obj_type].oc_skill;
1375 hits = (oskill != -P_BOW && oskill != -P_CROSSBOW
1376 && oskill != -P_DART && oskill != -P_SHURIKEN
1377 && oskill != P_SPEAR
1378 && oskill != P_KNIFE); /* but not dagger */
1382 hits = (objects[obj_type].oc_armcat != ARM_GLOVES);
1385 hits = (obj_type != SKELETON_KEY && obj_type != LOCK_PICK
1386 && obj_type != CREDIT_CARD && obj_type != TALLOW_CANDLE
1387 && obj_type != WAX_CANDLE && obj_type != LENSES
1388 && obj_type != TIN_WHISTLE && obj_type != MAGIC_WHISTLE);
1390 case ROCK_CLASS: /* includes boulder */
1391 if (obj_type != STATUE || mons[otmp->corpsenm].msize > MZ_TINY)
1395 if (obj_type == CORPSE && mons[otmp->corpsenm].msize > MZ_TINY)
1398 hits = (obj_type == MEAT_STICK
1399 || obj_type == HUGE_CHUNK_OF_MEAT);
1411 if (hits && whodidit != -1) {
1412 hit_bars(obj_p, x,y, barsx,barsy, whodidit, FALSE);