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-2023 */
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%s%s
\81I", Monnam(mtmp),
337 m_shot.s ? "
\8c\82\82Á
\82½" : "
\93\8a\82°
\82½");
339 m_shot.o = otmp->otyp;
341 m_shot.o = STRANGE_OBJECT; /* don't give multishot feedback */
343 m_shot.n = multishot;
344 for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
345 m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), dm, otmp);
346 /* conceptually all N missiles are in flight at once, but
347 if mtmp gets killed (shot kills adjacent gas spore and
348 triggers explosion, perhaps), inventory will be dropped
349 and otmp might go away via merging into another stack */
350 if (DEADMONSTER(mtmp) && m_shot.i < m_shot.n)
351 /* cancel pending shots (perhaps ought to give a message here
352 since we gave one above about throwing/shooting N missiles) */
353 break; /* endmultishot(FALSE); */
356 m_shot.n = m_shot.i = 0;
357 m_shot.o = STRANGE_OBJECT;
361 /* an object launched by someone/thing other than player attacks a monster;
362 return 1 if the object has stopped moving (hit or its range used up) */
364 ohitmon(mtmp, otmp, range, verbose)
365 struct monst *mtmp; /* accidental target, located at <bhitpos.x,.y> */
366 struct obj *otmp; /* missile; might be destroyed by drop_throw */
367 int range; /* how much farther will object travel if it misses;
368 use -1 to signify to keep going even after hit,
369 unless it's gone (used for rolling_boulder_traps) */
370 boolean verbose; /* give message(s) even when you can't see what happened */
373 boolean vis, ismimic;
375 struct obj *mon_launcher = archer ? MON_WEP(archer) : NULL;
377 notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
378 ismimic = M_AP_TYPE(mtmp) && M_AP_TYPE(mtmp) != M_AP_MONSTER;
379 vis = cansee(bhitpos.x, bhitpos.y);
381 tmp = 5 + find_mac(mtmp) + omon_adj(mtmp, otmp, FALSE);
382 /* High level monsters will be more likely to hit */
383 /* This check applies only if this monster is the target
384 * the archer was aiming at. */
385 if (archer && target == mtmp) {
386 if (archer->m_lev > 5)
387 tmp += archer->m_lev - 5;
388 if (mon_launcher && mon_launcher->oartifact)
389 tmp += spec_abon(mon_launcher, mtmp);
394 miss(distant_name(otmp, mshot_xname), mtmp);
395 else if (verbose && !target)
397 pline("It is missed.");
399 pline("
\89½
\82©
\82ª
\82©
\82·
\82ß
\82½
\81D");
401 if (!range) { /* Last position; object drops */
402 (void) drop_throw(otmp, 0, mtmp->mx, mtmp->my);
405 } else if (otmp->oclass == POTION_CLASS) {
411 /* probably thrown by a monster rather than 'other', but the
412 distinction only matters when hitting the hero */
413 potionhit(mtmp, otmp, POTHIT_OTHER_THROW);
416 damage = dmgval(otmp, mtmp);
417 if (otmp->otyp == ACID_VENOM && resists_acid(mtmp))
419 #if 0 /* can't use this because we don't have the attacker */
420 if (is_orc(mtmp->data) && is_elf(?magr?))
427 if (otmp->otyp == EGG)
429 pline("Splat! %s is hit with %s egg!", Monnam(mtmp),
430 otmp->known ? an(mons[otmp->corpsenm].mname) : "an");
432 pline("
\83r
\83`
\83\83\83b
\81I%s
\82Í%s
\97\91\82É
\93\96\82½
\82Á
\82½
\81I", Monnam(mtmp),
433 otmp->known ? s_suffix(mons[otmp->corpsenm].mname) : "");
436 hit(distant_name(otmp, mshot_xname), mtmp, exclam(damage));
437 } else if (verbose && !target)
439 pline("%s%s is hit%s", (otmp->otyp == EGG) ? "Splat! " : "",
440 Monnam(mtmp), exclam(damage));
442 pline("%s%s
\82É
\96½
\92\86\82µ
\82½%s", (otmp->otyp == EGG) ? "
\83r
\83`
\83\83\83b
\81I" : "",
443 Monnam(mtmp), exclam(damage));
446 if (otmp->opoisoned && is_poisonable(otmp)) {
447 if (resists_poison(mtmp)) {
450 pline_The("poison doesn't seem to affect %s.",
452 pline("%s
\82Í
\93Å
\82Ì
\89e
\8b¿
\82ð
\8eó
\82¯
\82È
\82¢
\82æ
\82¤
\82¾
\81D",
460 pline_The("poison was deadly...");
462 pline("
\93Å
\82Í
\92v
\8e\80\97Ê
\82¾
\82Á
\82½
\81D
\81D
\81D");
467 if (objects[otmp->otyp].oc_material == SILVER
468 && mon_hates_silver(mtmp)) {
469 boolean flesh = (!noncorporeal(mtmp->data)
470 && !amorphous(mtmp->data));
472 /* note: extra silver damage is handled by dmgval() */
474 char *m_name = mon_nam(mtmp);
476 if (flesh) /* s_suffix returns a modifiable buffer */
478 m_name = strcat(s_suffix(m_name), " flesh");
480 m_name = strcat(s_suffix(m_name), "
\82Ì
\91Ì");
482 pline_The("silver sears %s!", m_name);
484 pline("%s
\82Í
\8bâ
\82Å
\8fÄ
\82©
\82ê
\82½
\81I", m_name);
485 } else if (verbose && !target) {
487 pline("%s is seared!", flesh ? "Its flesh" : "It");
489 pline("
\89½%s
\82Í
\8fÄ
\82©
\82ê
\82½
\81I", flesh ? "
\8eÒ
\82©
\82Ì
\91Ì" : "
\82©");
492 if (otmp->otyp == ACID_VENOM && cansee(mtmp->mx, mtmp->my)) {
493 if (resists_acid(mtmp)) {
494 if (vis || (verbose && !target))
496 pline("%s is unaffected.", Monnam(mtmp));
498 pline("%s
\82Í
\89e
\8b¿
\82ð
\8eó
\82¯
\82È
\82¢
\81D", Monnam(mtmp));
502 pline_The("%s burns %s!", hliquid("acid"), mon_nam(mtmp));
504 pline_The("%s
\82Í%s
\82Å
\8fÄ
\82©
\82ê
\82½
\81I", mon_nam(mtmp), hliquid("
\8e_"));
505 else if (verbose && !target)
507 pline("It is burned!");
509 pline("
\89½
\82©
\82Í
\8fÄ
\82©
\82ê
\82½
\81I");
512 if (otmp->otyp == EGG && touch_petrifies(&mons[otmp->corpsenm])) {
513 if (!munstone(mtmp, TRUE))
514 minstapetrify(mtmp, TRUE);
515 if (resists_ston(mtmp))
519 if (!DEADMONSTER(mtmp)) { /* might already be dead (if petrified) */
521 if (DEADMONSTER(mtmp)) {
522 if (vis || (verbose && !target))
524 pline("%s is %s!", Monnam(mtmp),
525 (nonliving(mtmp->data) || is_vampshifter(mtmp)
526 || !canspotmon(mtmp)) ? "destroyed" : "killed");
528 pline("%s
\82Í%s
\81I", Monnam(mtmp),
529 (nonliving(mtmp->data) || is_vampshifter(mtmp)
530 || !canspotmon(mtmp)) ? "
\93|
\82³
\82ê
\82½" : "
\8e\80\82ñ
\82¾");
532 /* don't blame hero for unknown rolling boulder trap */
533 if (!context.mon_moving && (otmp->otyp != BOULDER
534 || range >= 0 || otmp->otrapped))
535 xkilled(mtmp, XKILL_NOMSG);
541 /* blinding venom and cream pie do 0 damage, but verify
542 that the target is still alive anyway */
543 if (!DEADMONSTER(mtmp)
544 && can_blnd((struct monst *) 0, mtmp,
545 (uchar) ((otmp->otyp == BLINDING_VENOM) ? AT_SPIT
548 if (vis && mtmp->mcansee)
550 pline("%s is blinded by %s.", Monnam(mtmp), the(xname(otmp)));
552 pline("%s
\82Í%s
\82É
\82æ
\82Á
\82Ä
\96Ú
\82ª
\8c©
\82¦
\82È
\82
\82È
\82Á
\82½
\81D", Monnam(mtmp), the(xname(otmp)));
554 tmp = (int) mtmp->mblinded + rnd(25) + 20;
557 mtmp->mblinded = tmp;
560 objgone = drop_throw(otmp, 1, bhitpos.x, bhitpos.y);
561 if (!objgone && range == -1) { /* special case */
562 obj_extract_self(otmp); /* free it for motion again */
570 #define MT_FLIGHTCHECK(pre) \
571 (/* missile hits edge of screen */ \
572 !isok(bhitpos.x + dx, bhitpos.y + dy) \
573 /* missile hits the wall */ \
574 || IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ) \
575 /* missile hit closed door */ \
576 || closed_door(bhitpos.x + dx, bhitpos.y + dy) \
577 /* missile might hit iron bars */ \
578 /* the random chance for small objects hitting bars is */ \
579 /* skipped when reaching them at point blank range */ \
580 || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS \
581 && hits_bars(&singleobj, \
582 bhitpos.x, bhitpos.y, \
583 bhitpos.x + dx, bhitpos.y + dy, \
584 ((pre) ? 0 : !rn2(5)), 0)) \
585 /* Thrown objects "sink" */ \
586 || (!(pre) && IS_SINK(levl[bhitpos.x][bhitpos.y].typ)))
589 m_throw(mon, x, y, dx, dy, range, obj)
590 struct monst *mon; /* launching monster */
591 int x, y, dx, dy, range; /* launch point, direction, and range */
592 struct obj *obj; /* missile (or stack providing it) */
595 struct obj *singleobj;
596 char sym = obj->oclass;
597 int hitu = 0, oldumort, blindinc = 0;
601 notonhead = FALSE; /* reset potentially stale value */
603 if (obj->quan == 1L) {
605 * Remove object from minvent. This cannot be done later on;
606 * what if the player dies before then, leaving the monster
607 * with 0 daggers? (This caused the infamous 2^32-1 orcish
610 * VENOM is not in minvent - it should already be OBJ_FREE.
611 * The extract below does nothing.
614 /* not possibly_unwield, which checks the object's */
615 /* location, not its existence */
616 if (MON_WEP(mon) == obj)
617 setmnotwielded(mon, obj);
618 obj_extract_self(obj);
620 obj = (struct obj *) 0;
622 singleobj = splitobj(obj, 1L);
623 obj_extract_self(singleobj);
626 singleobj->owornmask = 0; /* threw one of multiple weapons in hand? */
628 if ((singleobj->cursed || singleobj->greased) && (dx || dy) && !rn2(7)) {
629 if (canseemon(mon) && flags.verbose) {
630 if (is_ammo(singleobj))
632 pline("%s misfires!", Monnam(mon));
634 pline("%s
\82Í
\82Í
\82¸
\82µ
\82½
\81I", Monnam(mon));
637 pline("%s as %s throws it!", Tobjnam(singleobj, "slip"),
640 pline("%s
\82ª
\93\8a\82°
\82æ
\82¤
\82Æ
\82µ
\82½
\82Æ
\82½
\82ñ%s
\82ª
\8a\8a\82Á
\82½
\81I",
641 mon_nam(mon), xname(singleobj));
646 /* check validity of new direction */
648 (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
653 if (MT_FLIGHTCHECK(TRUE)) {
654 (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
657 mesg_given = 0; /* a 'missile misses' message has not yet been shown */
659 /* Note: drop_throw may destroy singleobj. Since obj must be destroyed
660 * early to avoid the dagger bug, anyone who modifies this code should
661 * be careful not to use either one after it's been freed.
664 tmp_at(DISP_FLASH, obj_to_glyph(singleobj, rn2_on_display_rng));
665 while (range-- > 0) { /* Actually the loop is always exited by break */
668 mtmp = m_at(bhitpos.x, bhitpos.y);
669 if (mtmp && shade_miss(mon, mtmp, singleobj, TRUE, TRUE)) {
670 /* if mtmp is a shade and missile passes harmlessly through it,
671 give message and skip it in order to keep going */
672 mtmp = (struct monst *) 0;
674 if (ohitmon(mtmp, singleobj, range, TRUE))
676 } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
680 if (singleobj->oclass == GEM_CLASS
681 && singleobj->otyp <= LAST_GEM + 9 /* 9 glass colors */
682 && is_unicorn(youmonst.data)) {
683 if (singleobj->otyp > LAST_GEM) {
685 You("catch the %s.", xname(singleobj));
687 You("%s
\82ð
\82Â
\82©
\82Ü
\82¦
\82½
\81D", xname(singleobj));
689 You("are not interested in %s junk.",
690 s_suffix(mon_nam(mon)));
692 You("%s
\82Ì
\83K
\83\89\83N
\83^
\82É
\8b»
\96¡
\82Í
\82È
\82¢
\81D",
695 makeknown(singleobj->otyp);
700 "accept %s gift in the spirit in which it was intended.",
702 "
\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",
703 s_suffix(mon_nam(mon)));
705 (void) hold_another_object(singleobj,
706 "You catch, but drop, %s.",
710 (void) hold_another_object(singleobj,
711 "
\82 \82È
\82½
\82Í%s
\82ð
\82Â
\82©
\82Ü
\82¦
\82½
\82ª
\81C
\97\8e\82µ
\82½
\81D",
713 "
\82ð
\82Â
\82©
\82Ü
\82¦
\82½
\81D");
718 if (singleobj->oclass == POTION_CLASS) {
720 singleobj->dknown = 1;
721 potionhit(&youmonst, singleobj, POTHIT_MONST_THROW);
724 oldumort = u.umortality;
725 switch (singleobj->otyp) {
728 if (!touch_petrifies(&mons[singleobj->corpsenm])) {
729 impossible("monster throwing egg type %d",
730 singleobj->corpsenm);
737 hitu = thitu(8, 0, &singleobj, (char *) 0);
740 dam = dmgval(singleobj, &youmonst);
741 hitv = 3 - distmin(u.ux, u.uy, mon->mx, mon->my);
744 if (is_elf(mon->data)
745 && objects[singleobj->otyp].oc_skill == P_BOW) {
747 if (MON_WEP(mon) && MON_WEP(mon)->otyp == ELVEN_BOW)
749 if (singleobj->otyp == ELVEN_ARROW)
752 if (bigmonst(youmonst.data))
754 hitv += 8 + singleobj->spe;
757 hitu = thitu(hitv, dam, &singleobj, (char *) 0);
759 if (hitu && singleobj->opoisoned && is_poisonable(singleobj)) {
760 char onmbuf[BUFSZ], knmbuf[BUFSZ];
762 Strcpy(onmbuf, xname(singleobj));
763 Strcpy(knmbuf, killer_xname(singleobj));
764 poisoned(onmbuf, A_STR, knmbuf,
765 /* if damage triggered life-saving,
766 poison is limited to attrib loss */
767 (u.umortality > oldumort) ? 0 : 10, TRUE);
769 if (hitu && can_blnd((struct monst *) 0, &youmonst,
770 (uchar) ((singleobj->otyp == BLINDING_VENOM)
775 if (singleobj->otyp == CREAM_PIE) {
778 pline("Yecch! You've been creamed.");
780 pline("
\83E
\83F
\81[
\81D
\83N
\83\8a\81[
\83\80\82ð
\82©
\82Ô
\82Á
\82½
\81D");
783 pline("There's %s sticky all over your %s.",
784 something, body_part(FACE));
786 pline("
\82 \82È
\82½
\82Í%s
\82É
\82×
\82Æ
\82Â
\82
\82à
\82Ì
\82ð
\8a´
\82¶
\82½
\81D",
789 } else if (singleobj->otyp == BLINDING_VENOM) {
791 const char *eyes = body_part(EYE);
793 if (eyecount(youmonst.data) != 1)
794 eyes = makeplural(eyes);
795 /* venom in the eyes */
797 pline_The("venom blinds you.");
799 Your("%s %s.", eyes, vtense(eyes, "sting"));
802 pline("
\93Å
\82Å
\96Ú
\82ª
\8c©
\82¦
\82È
\82
\82È
\82Á
\82½
\81D");
804 Your("%s
\82Í
\82¿
\82
\82¿
\82
\82µ
\82½
\81D", body_part(EYE));
808 if (hitu && singleobj->otyp == EGG) {
809 if (!Stoned && !Stone_resistance
810 && !(poly_when_stoned(youmonst.data)
811 && polymon(PM_STONE_GOLEM))) {
812 make_stoned(5L, (char *) 0, KILLED_BY, "");
817 (void) drop_throw(singleobj, hitu, u.ux, u.uy);
821 if (!range /* reached end of path */
822 || MT_FLIGHTCHECK(FALSE)) {
823 if (singleobj) { /* hits_bars might have destroyed it */
825 && (!mesg_given || bhitpos.x != u.ux || bhitpos.y != u.uy)
826 && (cansee(bhitpos.x, bhitpos.y)
827 || (archer && canseemon(archer))))
829 pline("%s misses.", The(mshot_xname(singleobj)));
831 pline("%s
\82Í
\82Í
\82¸
\82ê
\82½
\81D", mshot_xname(singleobj));
832 (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
836 tmp_at(bhitpos.x, bhitpos.y);
839 tmp_at(bhitpos.x, bhitpos.y);
842 mesg_given = 0; /* reset */
845 u.ucreamed += blindinc;
846 make_blinded(Blinded + (long) blindinc, FALSE);
848 Your1(vision_clears);
852 #undef MT_FLIGHTCHECK
854 /* Monster throws item at another monster */
857 struct monst *mtmp, *mtarg;
859 struct obj *otmp, *mwep;
863 /* Polearms won't be applied by monsters against other monsters */
864 if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
865 mtmp->weapon_check = NEED_RANGED_WEAPON;
866 /* mon_wield_item resets weapon_check as appropriate */
867 if (mon_wield_item(mtmp) != 0)
872 otmp = select_rwep(mtmp);
875 ispole = is_pole(otmp);
880 mwep = MON_WEP(mtmp); /* wielded weapon */
882 if (!ispole && m_lined_up(mtarg, mtmp)) {
883 int chance = max(BOLT_LIM - distmin(x, y, mtarg->mx, mtarg->my), 1);
885 if (!mtarg->mflee || !rn2(chance)) {
886 if (ammo_and_launcher(otmp, mwep)
887 && dist2(mtmp->mx, mtmp->my, mtarg->mx, mtarg->my)
888 > PET_MISSILE_RANGE2)
889 return 0; /* Out of range */
890 /* Set target monster */
893 monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */
894 archer = target = (struct monst *) 0;
902 /* monster spits substance at monster */
904 spitmm(mtmp, mattk, mtarg)
905 struct monst *mtmp, *mtarg;
906 struct attack *mattk;
913 pline("A dry rattle comes from %s throat.",
914 s_suffix(mon_nam(mtmp)));
916 pline("%s
\82Ì
\8dA
\82ª
\83K
\83\89\83K
\83\89\82Æ
\96Â
\82Á
\82½
\81D",
921 if (m_lined_up(mtarg, mtmp)) {
922 switch (mattk->adtyp) {
925 otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
928 impossible("bad attack type in spitmu");
931 otmp = mksobj(ACID_VENOM, TRUE, FALSE);
934 if (!rn2(BOLT_LIM-distmin(mtmp->mx,mtmp->my,mtarg->mx,mtarg->my))) {
937 pline("%s spits venom!", Monnam(mtmp));
939 pline("%s
\82Í
\93Å
\82ð
\93f
\82¢
\82½
\81I", Monnam(mtmp));
941 m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
942 distmin(mtmp->mx,mtmp->my,mtarg->mx,mtarg->my), otmp);
943 target = (struct monst *)0;
946 /* If this is a pet, it'll get hungry. Minions and
947 * spell beings won't hunger */
948 if (mtmp->mtame && !mtmp->isminion) {
949 struct edog *dog = EDOG(mtmp);
951 /* Hunger effects will catch up next move */
952 if (dog->hungrytime > 1)
953 dog->hungrytime -= 5;
962 /* monster breathes at monster (ranged) */
964 breamm(mtmp, mattk, mtarg)
965 struct monst *mtmp, *mtarg;
966 struct attack *mattk;
968 /* if new breath types are added, change AD_ACID to max type */
969 int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp ;
971 if (m_lined_up(mtarg, mtmp)) {
976 pline("%s coughs.", Monnam(mtmp));
978 pline("%s
\82Í
\82¹
\82«
\82ð
\82µ
\82½
\81D", Monnam(mtmp));
981 You_hear("a cough.");
983 You_hear("
\82¹
\82«
\82Ì
\89¹
\82ð
\95·
\82¢
\82½
\81D");
987 if (!mtmp->mspec_used && rn2(3)) {
988 if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
991 pline("%s breathes %s!", Monnam(mtmp), breathwep[typ - 1]);
993 pline("%s
\82Í%s
\82ð
\82Í
\82¢
\82½
\81I", Monnam(mtmp), breathwep[typ - 1]);
994 dobuzz((int) (-20 - (typ - 1)), (int) mattk->damn,
995 mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), FALSE);
997 /* breath runs out sometimes. Also, give monster some
998 * cunning; don't breath if the target fell asleep.
1000 mtmp->mspec_used = 6 + rn2(18);
1002 /* If this is a pet, it'll get hungry. Minions and
1003 * spell beings won't hunger */
1004 if (mtmp->mtame && !mtmp->isminion) {
1005 struct edog *dog = EDOG(mtmp);
1007 /* Hunger effects will catch up next move */
1008 if (dog->hungrytime >= 10)
1009 dog->hungrytime -= 10;
1011 } else impossible("Breath weapon %d used", typ-1);
1020 /* remove an entire item from a monster's inventory; destroy that item */
1022 m_useupall(mon, obj)
1026 obj_extract_self(obj);
1027 if (obj->owornmask) {
1028 if (obj == MON_WEP(mon))
1030 mon->misc_worn_check &= ~obj->owornmask;
1031 update_mon_intrinsics(mon, obj, FALSE, FALSE);
1032 obj->owornmask = 0L;
1034 obfree(obj, (struct obj *) 0);
1037 /* remove one instance of an item from a monster's inventory */
1043 if (obj->quan > 1L) {
1045 obj->owt = weight(obj);
1047 m_useupall(mon, obj);
1051 /* monster attempts ranged weapon attack against player */
1056 struct obj *otmp, *mwep;
1060 /* Rearranged beginning so monsters can use polearms not in a line */
1061 if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
1062 mtmp->weapon_check = NEED_RANGED_WEAPON;
1063 /* mon_wield_item resets weapon_check as appropriate */
1064 if (mon_wield_item(mtmp) != 0)
1069 otmp = select_rwep(mtmp);
1073 if (is_pole(otmp)) {
1076 if (otmp != MON_WEP(mtmp))
1077 return; /* polearm must be wielded */
1078 if (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) > POLE_LIM
1079 || !couldsee(mtmp->mx, mtmp->my))
1080 return; /* Out of range, or intervening wall */
1082 if (canseemon(mtmp)) {
1085 pline("%s thrusts %s.", Monnam(mtmp),
1086 obj_is_pname(otmp) ? the(onm) : an(onm));
1088 pline("%s
\82Í%s
\82ð
\93Ë
\82«
\8eh
\82µ
\82½
\81D", Monnam(mtmp), onm);
1092 dam = dmgval(otmp, &youmonst);
1093 hitv = 3 - distmin(u.ux, u.uy, mtmp->mx, mtmp->my);
1096 if (bigmonst(youmonst.data))
1098 hitv += 8 + otmp->spe;
1102 (void) thitu(hitv, dam, &otmp, (char *) 0);
1109 /* If you are coming toward the monster, the monster
1110 * should try to soften you up with missiles. If you are
1111 * going away, you are probably hurt or running. Give
1112 * chase, but if you are getting too far away, throw.
1115 || (URETREATING(x, y)
1116 && rn2(BOLT_LIM - distmin(x, y, mtmp->mux, mtmp->muy))))
1119 mwep = MON_WEP(mtmp); /* wielded weapon */
1120 monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */
1124 /* monster spits substance at you */
1128 struct attack *mattk;
1135 pline("A dry rattle comes from %s throat.",
1136 s_suffix(mon_nam(mtmp)));
1138 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",
1143 if (lined_up(mtmp)) {
1144 switch (mattk->adtyp) {
1147 otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
1150 impossible("bad attack type in spitmu");
1153 otmp = mksobj(ACID_VENOM, TRUE, FALSE);
1157 - distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy))) {
1158 if (canseemon(mtmp))
1160 pline("%s spits venom!", Monnam(mtmp));
1162 pline("%s
\82Í
\93Å
\89t
\82ð
\93f
\82¢
\82½
\81I", Monnam(mtmp));
1163 m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
1164 distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp);
1168 obj_extract_self(otmp);
1169 obfree(otmp, (struct obj *) 0);
1175 /* monster breathes at you (ranged) */
1179 struct attack *mattk;
1181 /* if new breath types are added, change AD_ACID to max type */
1182 int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp;
1184 if (lined_up(mtmp)) {
1187 if (canseemon(mtmp))
1189 pline("%s coughs.", Monnam(mtmp));
1191 pline("%s
\82Í
\82¹
\82«
\82ð
\82µ
\82½
\81D", Monnam(mtmp));
1194 You_hear("a cough.");
1196 You_hear("
\82¹
\82«
\82Ì
\89¹
\82ð
\95·
\82¢
\82½
\81D");
1200 if (!mtmp->mspec_used && rn2(3)) {
1201 if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
1202 if (canseemon(mtmp))
1204 pline("%s breathes %s!", Monnam(mtmp),
1205 breathwep[typ - 1]);
1207 pline("%s
\82Í%s
\82ð
\93f
\82¢
\82½
\81I", Monnam(mtmp),
1208 breathwep[typ - 1]);
1210 buzz((int) (-20 - (typ - 1)), (int) mattk->damn, mtmp->mx,
1211 mtmp->my, sgn(tbx), sgn(tby));
1213 /* breath runs out sometimes. Also, give monster some
1214 * cunning; don't breath if the player fell asleep.
1217 mtmp->mspec_used = 10 + rn2(20);
1218 if (typ == AD_SLEE && !Sleep_resistance)
1219 mtmp->mspec_used += rnd(20);
1221 impossible("Breath weapon %d used", typ - 1);
1228 linedup(ax, ay, bx, by, boulderhandling)
1229 register xchar ax, ay, bx, by;
1230 int boulderhandling; /* 0=block, 1=ignore, 2=conditionally block */
1232 int dx, dy, boulderspots;
1234 /* These two values are set for use after successful return. */
1238 /* sometimes displacement makes a monster think that you're at its
1239 own location; prevent it from throwing and zapping in that case */
1243 if ((!tbx || !tby || abs(tbx) == abs(tby)) /* straight line or diagonal */
1244 && distmin(tbx, tby, 0, 0) < BOLT_LIM) {
1245 if ((ax == u.ux && ay == u.uy) ? (boolean) couldsee(bx, by)
1246 : clear_path(ax, ay, bx, by))
1248 /* don't have line of sight, but might still be lined up
1249 if that lack of sight is due solely to boulders */
1250 if (boulderhandling == 0)
1252 dx = sgn(ax - bx), dy = sgn(ay - by);
1255 /* <bx,by> is guaranteed to eventually converge with <ax,ay> */
1257 if (IS_ROCK(levl[bx][by].typ) || closed_door(bx, by))
1259 if (sobj_at(BOULDER, bx, by))
1261 } while (bx != ax || by != ay);
1262 /* reached target position without encountering obstacle */
1263 if (boulderhandling == 1 || rn2(2 + boulderspots) < 2)
1270 m_lined_up(mtarg, mtmp)
1271 struct monst *mtarg, *mtmp;
1273 return (linedup(mtarg->mx, mtarg->my, mtmp->mx, mtmp->my, 0));
1277 /* is mtmp in position to use ranged attack? */
1280 register struct monst *mtmp;
1282 boolean ignore_boulders;
1284 /* hero concealment usually trumps monst awareness of being lined up */
1285 if (Upolyd && rn2(25)
1286 && (u.uundetected || (U_AP_TYPE != M_AP_NOTHING
1287 && U_AP_TYPE != M_AP_MONSTER)))
1290 ignore_boulders = (throws_rocks(mtmp->data)
1291 || m_carrying(mtmp, WAN_STRIKING));
1292 return linedup(mtmp->mux, mtmp->muy, mtmp->mx, mtmp->my,
1293 ignore_boulders ? 1 : 2);
1296 /* check if a monster is carrying a particular item */
1298 m_carrying(mtmp, type)
1302 register struct obj *otmp;
1304 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
1305 if (otmp->otyp == type)
1307 return (struct obj *) 0;
1311 hit_bars(objp, objx, objy, barsx, barsy, your_fault, from_invent)
1312 struct obj **objp; /* *objp will be set to NULL if object breaks */
1313 int objx, objy, barsx, barsy;
1314 boolean your_fault, from_invent;
1316 struct obj *otmp = *objp;
1317 int obj_type = otmp->otyp;
1318 boolean unbreakable = (levl[barsx][barsy].wall_info & W_NONDIGGABLE) != 0;
1321 ? hero_breaks(otmp, objx, objy, from_invent)
1322 : breaks(otmp, objx, objy)) {
1323 *objp = 0; /* object is now gone */
1324 /* breakage makes its own noises */
1325 if (obj_type == POT_ACID) {
1326 if (cansee(barsx, barsy) && !unbreakable)
1328 pline_The("iron bars are dissolved!");
1330 pline_The("
\93S
\82Ì
\96_
\82Í
\97Z
\82¯
\82½
\81I");
1333 You_hear(Hallucination ? "angry snakes!" : "a hissing noise.");
1335 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");
1337 dissolve_bars(barsx, barsy);
1340 else if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL)
1344 pline("
\82®
\82í
\81[
\82ñ
\81I");
1345 else if (otmp->oclass == COIN_CLASS
1346 || objects[obj_type].oc_material == GOLD
1347 || objects[obj_type].oc_material == SILVER)
1351 pline("
\83`
\83\83\83\8a\83\93\81I");
1356 pline("
\83S
\83c
\83\93\81I");
1359 /* TRUE iff thrown/kicked/rolled object doesn't pass through iron bars */
1361 hits_bars(obj_p, x, y, barsx, barsy, always_hit, whodidit)
1362 struct obj **obj_p; /* *obj_p will be set to NULL if object breaks */
1363 int x, y, barsx, barsy;
1364 int always_hit; /* caller can force a hit for items which would fit through */
1365 int whodidit; /* 1==hero, 0=other, -1==just check whether it'll pass thru */
1367 struct obj *otmp = *obj_p;
1368 int obj_type = otmp->otyp;
1369 boolean hits = always_hit;
1372 switch (otmp->oclass) {
1373 case WEAPON_CLASS: {
1374 int oskill = objects[obj_type].oc_skill;
1376 hits = (oskill != -P_BOW && oskill != -P_CROSSBOW
1377 && oskill != -P_DART && oskill != -P_SHURIKEN
1378 && oskill != P_SPEAR
1379 && oskill != P_KNIFE); /* but not dagger */
1383 hits = (objects[obj_type].oc_armcat != ARM_GLOVES);
1386 hits = (obj_type != SKELETON_KEY && obj_type != LOCK_PICK
1387 && obj_type != CREDIT_CARD && obj_type != TALLOW_CANDLE
1388 && obj_type != WAX_CANDLE && obj_type != LENSES
1389 && obj_type != TIN_WHISTLE && obj_type != MAGIC_WHISTLE);
1391 case ROCK_CLASS: /* includes boulder */
1392 if (obj_type != STATUE || mons[otmp->corpsenm].msize > MZ_TINY)
1396 if (obj_type == CORPSE && mons[otmp->corpsenm].msize > MZ_TINY)
1399 hits = (obj_type == MEAT_STICK
1400 || obj_type == HUGE_CHUNK_OF_MEAT);
1412 if (hits && whodidit != -1) {
1413 hit_bars(obj_p, x,y, barsx,barsy, whodidit, FALSE);