NHDT->ANH, in most cases
[aNetHack.git] / src / dothrow.c
blob2f5cb220fe827214d3938b4929cf76c7f8bd1c6e
1 /* NetHack 3.6 dothrow.c $ANH-Date: 1455140444 2016/02/10 21:40:44 $ $ANH-Branch: master $:$ANH-Revision: 1.118 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* Contains code for 't' (throw) */
7 #include "hack.h"
9 STATIC_DCL int FDECL(throw_obj, (struct obj *, int));
10 STATIC_DCL boolean FDECL(ok_to_throw, (int *));
11 STATIC_DCL void NDECL(autoquiver);
12 STATIC_DCL int FDECL(gem_accept, (struct monst *, struct obj *));
13 STATIC_DCL void FDECL(tmiss, (struct obj *, struct monst *, BOOLEAN_P));
14 STATIC_DCL int FDECL(throw_gold, (struct obj *));
15 STATIC_DCL void FDECL(check_shop_obj, (struct obj *, XCHAR_P, XCHAR_P,
16 BOOLEAN_P));
17 STATIC_DCL void FDECL(breakmsg, (struct obj *, BOOLEAN_P));
18 STATIC_DCL boolean FDECL(toss_up, (struct obj *, BOOLEAN_P));
19 STATIC_DCL void FDECL(sho_obj_return_to_u, (struct obj * obj));
20 STATIC_DCL boolean FDECL(mhurtle_step, (genericptr_t, int, int));
22 static NEARDATA const char toss_objs[] = { ALLOW_COUNT, COIN_CLASS,
23 ALL_CLASSES, WEAPON_CLASS, 0 };
24 /* different default choices when wielding a sling (gold must be included) */
25 static NEARDATA const char bullets[] = { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES,
26 GEM_CLASS, 0 };
28 /* thrownobj (decl.c) tracks an object until it lands */
30 extern boolean notonhead; /* for long worms */
32 /* Throw the selected object, asking for direction */
33 STATIC_OVL int
34 throw_obj(obj, shotlimit)
35 struct obj *obj;
36 int shotlimit;
38 struct obj *otmp;
39 int multishot;
40 schar skill;
41 long wep_mask;
42 boolean twoweap, weakmultishot;
44 /* ask "in what direction?" */
45 if (!getdir((char *) 0)) {
46 /* No direction specified, so cancel the throw;
47 * might need to undo an object split.
48 * We used to use freeinv(obj),addinv(obj) here, but that can
49 * merge obj into another stack--usually quiver--even if it hadn't
50 * been split from there (possibly triggering a panic in addinv),
51 * and freeinv+addinv potentially has other side-effects.
53 if (obj->o_id == context.objsplit.parent_oid
54 || obj->o_id == context.objsplit.child_oid)
55 (void) unsplitobj(obj);
56 return 0; /* no time passes */
60 * Throwing money is usually for getting rid of it when
61 * a leprechaun approaches, or for bribing an oncoming
62 * angry monster. So throw the whole object.
64 * If the money is in quiver, throw one coin at a time,
65 * possibly using a sling.
67 if (obj->oclass == COIN_CLASS && obj != uquiver)
68 return throw_gold(obj);
70 if (!canletgo(obj, "throw"))
71 return 0;
72 if (obj->oartifact == ART_MJOLLNIR && obj != uwep) {
73 pline("%s must be wielded before it can be thrown.", The(xname(obj)));
74 return 0;
76 if ((obj->oartifact == ART_MJOLLNIR && ACURR(A_STR) < STR19(25))
77 || (obj->otyp == BOULDER && !throws_rocks(youmonst.data))) {
78 pline("It's too heavy.");
79 return 1;
81 if (!u.dx && !u.dy && !u.dz) {
82 You("cannot throw an object at yourself.");
83 return 0;
85 u_wipe_engr(2);
86 if (!uarmg && obj->otyp == CORPSE && touch_petrifies(&mons[obj->corpsenm])
87 && !Stone_resistance) {
88 You("throw %s with your bare %s.",
89 corpse_xname(obj, (const char *) 0, CXN_PFX_THE),
90 /* throwing with one hand, but pluralize since the
91 expression "with your bare hands" sounds better */
92 makeplural(body_part(HAND)));
93 Sprintf(killer.name, "throwing %s bare-handed", killer_xname(obj));
94 instapetrify(killer.name);
96 if (welded(obj)) {
97 weldmsg(obj);
98 return 1;
100 if (is_wet_towel(obj))
101 dry_a_towel(obj, -1, FALSE);
103 /* Multishot calculations
104 * (potential volley of up to N missiles; default for N is 1)
106 multishot = 1;
107 skill = objects[obj->otyp].oc_skill;
108 if (obj->quan > 1L /* no point checking if there's only 1 */
109 /* ammo requires corresponding launcher be wielded */
110 && (is_ammo(obj) ? matching_launcher(obj, uwep)
111 /* otherwise any stackable (non-ammo) weapon */
112 : obj->oclass == WEAPON_CLASS)
113 && !(Confusion || Stunned)) {
114 /* some roles don't get a volley bonus until becoming expert */
115 weakmultishot = (Role_if(PM_WIZARD) || Role_if(PM_PRIEST)
116 || (Role_if(PM_HEALER) && skill != P_KNIFE)
117 || (Role_if(PM_TOURIST) && skill != -P_DART)
118 /* poor dexterity also inhibits multishot */
119 || Fumbling || ACURR(A_DEX) <= 6);
121 /* Bonus if the player is proficient in this weapon... */
122 switch (P_SKILL(weapon_type(obj))) {
123 case P_EXPERT:
124 multishot++;
125 /*FALLTHRU*/
126 case P_SKILLED:
127 if (!weakmultishot)
128 multishot++;
129 break;
130 default: /* basic or unskilled: no bonus */
131 break;
133 /* ...or is using a special weapon for their role... */
134 switch (Role_switch) {
135 case PM_CAVEMAN:
136 /* give bonus for low-tech gear */
137 if (skill == -P_SLING || skill == P_SPEAR)
138 multishot++;
139 break;
140 case PM_MONK:
141 /* allow higher volley count despite skill limitation */
142 if (skill == -P_SHURIKEN)
143 multishot++;
144 break;
145 case PM_RANGER:
146 /* arbitrary; encourage use of other missiles beside daggers */
147 if (skill != P_DAGGER)
148 multishot++;
149 break;
150 case PM_ROGUE:
151 /* possibly should add knives... */
152 if (skill == P_DAGGER)
153 multishot++;
154 break;
155 case PM_SAMURAI:
156 /* role-specific launcher and its ammo */
157 if (obj->otyp == YA && uwep && uwep->otyp == YUMI)
158 multishot++;
159 break;
160 default:
161 break; /* No bonus */
163 /* ...or using their race's special bow; no bonus for spears */
164 if (!weakmultishot)
165 switch (Race_switch) {
166 case PM_ELF:
167 if (obj->otyp == ELVEN_ARROW && uwep
168 && uwep->otyp == ELVEN_BOW)
169 multishot++;
170 break;
171 case PM_ORC:
172 if (obj->otyp == ORCISH_ARROW && uwep
173 && uwep->otyp == ORCISH_BOW)
174 multishot++;
175 break;
176 case PM_GNOME:
177 /* arbitrary; there isn't any gnome-specific gear */
178 if (skill == -P_CROSSBOW)
179 multishot++;
180 break;
181 case PM_HUMAN:
182 case PM_DWARF:
183 default:
184 break; /* No bonus */
187 /* crossbows are slow to load and probably shouldn't allow multiple
188 shots at all, but that would result in players never using them;
189 instead, high strength is necessary to load and shoot quickly */
190 if (multishot > 1 && skill == -P_CROSSBOW
191 && ammo_and_launcher(obj, uwep)
192 && (int) ACURRSTR < (Race_if(PM_GNOME) ? 16 : 18))
193 multishot = rnd(multishot);
195 multishot = rnd(multishot);
196 if ((long) multishot > obj->quan)
197 multishot = (int) obj->quan;
198 if (shotlimit > 0 && multishot > shotlimit)
199 multishot = shotlimit;
202 m_shot.s = ammo_and_launcher(obj, uwep) ? TRUE : FALSE;
203 /* give a message if shooting more than one, or if player
204 attempted to specify a count */
205 if (multishot > 1 || shotlimit > 0) {
206 /* "You shoot N arrows." or "You throw N daggers." */
207 You("%s %d %s.", m_shot.s ? "shoot" : "throw",
208 multishot, /* (might be 1 if player gave shotlimit) */
209 (multishot == 1) ? singular(obj, xname) : xname(obj));
212 wep_mask = obj->owornmask;
213 m_shot.o = obj->otyp;
214 m_shot.n = multishot;
215 for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
216 twoweap = u.twoweap;
217 /* split this object off from its slot if necessary */
218 if (obj->quan > 1L) {
219 otmp = splitobj(obj, 1L);
220 } else {
221 otmp = obj;
222 if (otmp->owornmask)
223 remove_worn_item(otmp, FALSE);
225 freeinv(otmp);
226 throwit(otmp, wep_mask, twoweap);
228 m_shot.n = m_shot.i = 0;
229 m_shot.o = STRANGE_OBJECT;
230 m_shot.s = FALSE;
232 return 1;
235 /* common to dothrow() and dofire() */
236 STATIC_OVL boolean
237 ok_to_throw(shotlimit_p)
238 int *shotlimit_p; /* (see dothrow()) */
240 /* kludge to work around parse()'s pre-decrement of `multi' */
241 *shotlimit_p = (multi || save_cm) ? multi + 1 : 0;
242 multi = 0; /* reset; it's been used up */
244 if (notake(youmonst.data)) {
245 You("are physically incapable of throwing or shooting anything.");
246 return FALSE;
247 } else if (nohands(youmonst.data)) {
248 You_cant("throw or shoot without hands."); /* not body_part(HAND) */
249 return FALSE;
250 /*[what about !freehand(), aside from cursed missile launcher?]*/
252 if (check_capacity((char *) 0))
253 return FALSE;
254 return TRUE;
257 /* t command - throw */
259 dothrow()
261 register struct obj *obj;
262 int shotlimit;
265 * Since some characters shoot multiple missiles at one time,
266 * allow user to specify a count prefix for 'f' or 't' to limit
267 * number of items thrown (to avoid possibly hitting something
268 * behind target after killing it, or perhaps to conserve ammo).
270 * Prior to 3.3.0, command ``3t'' meant ``t(shoot) t(shoot) t(shoot)''
271 * and took 3 turns. Now it means ``t(shoot at most 3 missiles)''.
273 * [3.6.0: shot count setup has been moved into ok_to_throw().]
275 if (!ok_to_throw(&shotlimit))
276 return 0;
278 obj = getobj(uslinging() ? bullets : toss_objs, "throw");
279 /* it is also possible to throw food */
280 /* (or jewels, or iron balls... ) */
282 return obj ? throw_obj(obj, shotlimit) : 0;
285 /* KMH -- Automatically fill quiver */
286 /* Suggested by Jeffrey Bay <jbay@convex.hp.com> */
287 static void
288 autoquiver()
290 struct obj *otmp, *oammo = 0, *omissile = 0, *omisc = 0, *altammo = 0;
292 if (uquiver)
293 return;
295 /* Scan through the inventory */
296 for (otmp = invent; otmp; otmp = otmp->nobj) {
297 if (otmp->owornmask || otmp->oartifact || !otmp->dknown) {
298 ; /* Skip it */
299 } else if (otmp->otyp == ROCK
300 /* seen rocks or known flint or known glass */
301 || (otmp->otyp == FLINT
302 && objects[otmp->otyp].oc_name_known)
303 || (otmp->oclass == GEM_CLASS
304 && objects[otmp->otyp].oc_material == GLASS
305 && objects[otmp->otyp].oc_name_known)) {
306 if (uslinging())
307 oammo = otmp;
308 else if (ammo_and_launcher(otmp, uswapwep))
309 altammo = otmp;
310 else if (!omisc)
311 omisc = otmp;
312 } else if (otmp->oclass == GEM_CLASS) {
313 ; /* skip non-rock gems--they're ammo but
314 player has to select them explicitly */
315 } else if (is_ammo(otmp)) {
316 if (ammo_and_launcher(otmp, uwep))
317 /* Ammo matched with launcher (bow+arrow, crossbow+bolt) */
318 oammo = otmp;
319 else if (ammo_and_launcher(otmp, uswapwep))
320 altammo = otmp;
321 else
322 /* Mismatched ammo (no better than an ordinary weapon) */
323 omisc = otmp;
324 } else if (is_missile(otmp)) {
325 /* Missile (dart, shuriken, etc.) */
326 omissile = otmp;
327 } else if (otmp->oclass == WEAPON_CLASS && throwing_weapon(otmp)) {
328 /* Ordinary weapon */
329 if (objects[otmp->otyp].oc_skill == P_DAGGER && !omissile)
330 omissile = otmp;
331 else
332 omisc = otmp;
336 /* Pick the best choice */
337 if (oammo)
338 setuqwep(oammo);
339 else if (omissile)
340 setuqwep(omissile);
341 else if (altammo)
342 setuqwep(altammo);
343 else if (omisc)
344 setuqwep(omisc);
346 return;
349 /* f command -- fire: throw from the quiver */
351 dofire()
353 int shotlimit;
354 struct obj *obj;
357 * Same as dothrow(), except we use quivered missile instead
358 * of asking what to throw/shoot.
360 * If quiver is empty, we use autoquiver to fill it when the
361 * corresponding option is on. If the option is off or if
362 * autoquiver doesn't select anything, we ask what to throw.
363 * For the last, if player's response is a stack, we put
364 * that stack into quiver slot provided it's not wielded.
366 if (!ok_to_throw(&shotlimit))
367 return 0;
369 if ((obj = uquiver) == 0) {
370 if (!flags.autoquiver) {
371 You("have no ammunition readied.");
372 } else {
373 autoquiver();
374 if ((obj = uquiver) == 0)
375 You("have nothing appropriate for your quiver.");
377 /* if autoquiver is disabled or has failed, prompt for missile;
378 fill quiver with it if it's not wielded */
379 if (!obj) {
380 obj = getobj(uslinging() ? bullets : toss_objs, "throw");
381 /* Q command doesn't allow gold in quiver */
382 if (obj && !obj->owornmask && obj->oclass != COIN_CLASS)
383 setuqwep(obj); /* demi-autoquiver */
385 /* give feedback if quiver has now been filled */
386 if (uquiver) {
387 uquiver->owornmask &= ~W_QUIVER; /* less verbose */
388 prinv("You ready:", uquiver, 0L);
389 uquiver->owornmask |= W_QUIVER;
393 return obj ? throw_obj(obj, shotlimit) : 0;
396 /* if in midst of multishot shooting/throwing, stop early */
397 void
398 endmultishot(verbose)
399 boolean verbose;
401 if (m_shot.i < m_shot.n) {
402 if (verbose && !context.mon_moving) {
403 You("stop %s after the %d%s %s.",
404 m_shot.s ? "firing" : "throwing", m_shot.i, ordin(m_shot.i),
405 m_shot.s ? "shot" : "toss");
407 m_shot.n = m_shot.i; /* make current shot be the last */
412 * Object hits floor at hero's feet. Called from drop() and throwit().
414 void
415 hitfloor(obj)
416 register struct obj *obj;
418 if (IS_SOFT(levl[u.ux][u.uy].typ) || u.uinwater) {
419 dropy(obj);
420 return;
422 if (IS_ALTAR(levl[u.ux][u.uy].typ))
423 doaltarobj(obj);
424 else
425 pline("%s hit%s the %s.", Doname2(obj), (obj->quan == 1L) ? "s" : "",
426 surface(u.ux, u.uy));
428 if (hero_breaks(obj, u.ux, u.uy, TRUE))
429 return;
430 if (ship_object(obj, u.ux, u.uy, FALSE))
431 return;
432 dropz(obj, TRUE);
436 * Walk a path from src_cc to dest_cc, calling a proc for each location
437 * except the starting one. If the proc returns FALSE, stop walking
438 * and return FALSE. If stopped early, dest_cc will be the location
439 * before the failed callback.
441 boolean
442 walk_path(src_cc, dest_cc, check_proc, arg)
443 coord *src_cc;
444 coord *dest_cc;
445 boolean FDECL((*check_proc), (genericptr_t, int, int));
446 genericptr_t arg;
448 int x, y, dx, dy, x_change, y_change, err, i, prev_x, prev_y;
449 boolean keep_going = TRUE;
451 /* Use Bresenham's Line Algorithm to walk from src to dest */
452 dx = dest_cc->x - src_cc->x;
453 dy = dest_cc->y - src_cc->y;
454 prev_x = x = src_cc->x;
455 prev_y = y = src_cc->y;
457 if (dx < 0) {
458 x_change = -1;
459 dx = -dx;
460 } else
461 x_change = 1;
462 if (dy < 0) {
463 y_change = -1;
464 dy = -dy;
465 } else
466 y_change = 1;
468 i = err = 0;
469 if (dx < dy) {
470 while (i++ < dy) {
471 prev_x = x;
472 prev_y = y;
473 y += y_change;
474 err += dx << 1;
475 if (err > dy) {
476 x += x_change;
477 err -= dy << 1;
479 /* check for early exit condition */
480 if (!(keep_going = (*check_proc)(arg, x, y)))
481 break;
483 } else {
484 while (i++ < dx) {
485 prev_x = x;
486 prev_y = y;
487 x += x_change;
488 err += dy << 1;
489 if (err > dx) {
490 y += y_change;
491 err -= dx << 1;
493 /* check for early exit condition */
494 if (!(keep_going = (*check_proc)(arg, x, y)))
495 break;
499 if (keep_going)
500 return TRUE; /* successful */
502 dest_cc->x = prev_x;
503 dest_cc->y = prev_y;
504 return FALSE;
508 * Single step for the hero flying through the air from jumping, flying,
509 * etc. Called from hurtle() and jump() via walk_path(). We expect the
510 * argument to be a pointer to an integer -- the range -- which is
511 * used in the calculation of points off if we hit something.
513 * Bumping into monsters won't cause damage but will wake them and make
514 * them angry. Auto-pickup isn't done, since you don't have control over
515 * your movements at the time.
517 * Possible additions/changes:
518 * o really attack monster if we hit one
519 * o set stunned if we hit a wall or door
520 * o reset nomul when we stop
521 * o creepy feeling if pass through monster (if ever implemented...)
522 * o bounce off walls
523 * o let jumps go over boulders
525 boolean
526 hurtle_step(arg, x, y)
527 genericptr_t arg;
528 int x, y;
530 int ox, oy, *range = (int *) arg;
531 struct obj *obj;
532 struct monst *mon;
533 boolean may_pass = TRUE;
534 struct trap *ttmp;
535 int dmg = 0;
537 if (!isok(x, y)) {
538 You_feel("the spirits holding you back.");
539 return FALSE;
540 } else if (!in_out_region(x, y)) {
541 return FALSE;
542 } else if (*range == 0) {
543 return FALSE; /* previous step wants to stop now */
546 if (!Passes_walls || !(may_pass = may_passwall(x, y))) {
547 boolean odoor_diag = (IS_DOOR(levl[x][y].typ)
548 && (levl[x][y].doormask & D_ISOPEN)
549 && (u.ux - x) && (u.uy - y));
551 if (IS_ROCK(levl[x][y].typ) || closed_door(x, y) || odoor_diag) {
552 const char *s;
554 if (odoor_diag)
555 You("hit the door edge!");
556 pline("Ouch!");
557 if (IS_TREE(levl[x][y].typ))
558 s = "bumping into a tree";
559 else if (IS_ROCK(levl[x][y].typ))
560 s = "bumping into a wall";
561 else
562 s = "bumping into a door";
563 dmg = rnd(2 + *range);
564 losehp(Maybe_Half_Phys(dmg), s, KILLED_BY);
565 wake_nearto(x,y, 10);
566 return FALSE;
568 if (levl[x][y].typ == IRONBARS) {
569 You("crash into some iron bars. Ouch!");
570 dmg = rnd(2 + *range);
571 losehp(Maybe_Half_Phys(dmg), "crashing into iron bars",
572 KILLED_BY);
573 wake_nearto(x,y, 20);
574 return FALSE;
576 if ((obj = sobj_at(BOULDER, x, y)) != 0) {
577 You("bump into a %s. Ouch!", xname(obj));
578 dmg = rnd(2 + *range);
579 losehp(Maybe_Half_Phys(dmg), "bumping into a boulder", KILLED_BY);
580 wake_nearto(x,y, 10);
581 return FALSE;
583 if (!may_pass) {
584 /* did we hit a no-dig non-wall position? */
585 You("smack into something!");
586 dmg = rnd(2 + *range);
587 losehp(Maybe_Half_Phys(dmg), "touching the edge of the universe",
588 KILLED_BY);
589 wake_nearto(x,y, 10);
590 return FALSE;
592 if ((u.ux - x) && (u.uy - y) && bad_rock(youmonst.data, u.ux, y)
593 && bad_rock(youmonst.data, x, u.uy)) {
594 boolean too_much =
595 (invent && (inv_weight() + weight_cap() > 600));
596 /* Move at a diagonal. */
597 if (bigmonst(youmonst.data) || too_much) {
598 You("%sget forcefully wedged into a crevice.",
599 too_much ? "and all your belongings " : "");
600 dmg = rnd(2 + *range);
601 losehp(Maybe_Half_Phys(dmg), "wedging into a narrow crevice",
602 KILLED_BY);
603 wake_nearto(x,y, 10);
604 return FALSE;
609 if ((mon = m_at(x, y)) != 0) {
610 You("bump into %s.", a_monnam(mon));
611 wakeup(mon, FALSE);
612 setmangry(mon, FALSE);
613 wake_nearto(x,y, 10);
614 return FALSE;
616 if ((u.ux - x) && (u.uy - y) && bad_rock(youmonst.data, u.ux, y)
617 && bad_rock(youmonst.data, x, u.uy)) {
618 /* Move at a diagonal. */
619 if (Sokoban) {
620 You("come to an abrupt halt!");
621 return FALSE;
625 /* Caller has already determined that dragging the ball is allowed */
626 if (Punished && uball->where == OBJ_FLOOR) {
627 int bc_control;
628 xchar ballx, bally, chainx, chainy;
629 boolean cause_delay;
631 if (drag_ball(x, y, &bc_control, &ballx, &bally, &chainx,
632 &chainy, &cause_delay, TRUE))
633 move_bc(0, bc_control, ballx, bally, chainx, chainy);
636 ox = u.ux;
637 oy = u.uy;
638 u_on_newpos(x, y); /* set u.<ux,uy>, u.usteed-><mx,my>; cliparound(); */
639 newsym(ox, oy); /* update old position */
640 vision_recalc(1); /* update for new position */
641 flush_screen(1);
643 if (levl[x][y].typ == WATER && Is_waterlevel(&u.uz)) {
644 multi = 0;
645 drown();
646 return FALSE;
649 /* FIXME:
650 * Each trap should really trigger on the recoil if
651 * it would trigger during normal movement. However,
652 * not all the possible side-effects of this are
653 * tested [as of 3.4.0] so we trigger those that
654 * we have tested, and offer a message for the
655 * ones that we have not yet tested.
657 if ((ttmp = t_at(x, y)) != 0) {
658 if (ttmp->ttyp == MAGIC_PORTAL) {
659 dotrap(ttmp, 0);
660 return FALSE;
661 } else if (ttmp->ttyp == VIBRATING_SQUARE) {
662 pline("The ground vibrates as you pass it.");
663 dotrap(ttmp, 0); /* doesn't print messages */
664 } else if (ttmp->ttyp == FIRE_TRAP) {
665 dotrap(ttmp, 0);
666 } else if ((ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT
667 || ttmp->ttyp == HOLE || ttmp->ttyp == TRAPDOOR)
668 && Sokoban) {
669 /* Air currents overcome the recoil */
670 dotrap(ttmp, 0);
671 *range = 0;
672 return TRUE;
673 } else {
674 if (ttmp->tseen)
675 You("pass right over %s.",
676 an(defsyms[trap_to_defsym(ttmp->ttyp)].explanation));
679 if (--*range < 0) /* make sure our range never goes negative */
680 *range = 0;
681 if (*range != 0)
682 delay_output();
683 return TRUE;
686 STATIC_OVL boolean
687 mhurtle_step(arg, x, y)
688 genericptr_t arg;
689 int x, y;
691 struct monst *mon = (struct monst *) arg;
693 /* TODO: Treat walls, doors, iron bars, pools, lava, etc. specially
694 * rather than just stopping before.
696 if (goodpos(x, y, mon, 0) && m_in_out_region(mon, x, y)) {
697 remove_monster(mon->mx, mon->my);
698 newsym(mon->mx, mon->my);
699 place_monster(mon, x, y);
700 newsym(mon->mx, mon->my);
701 set_apparxy(mon);
702 (void) mintrap(mon);
703 return TRUE;
705 return FALSE;
709 * The player moves through the air for a few squares as a result of
710 * throwing or kicking something.
712 * dx and dy should be the direction of the hurtle, not of the original
713 * kick or throw and be only.
715 void
716 hurtle(dx, dy, range, verbose)
717 int dx, dy, range;
718 boolean verbose;
720 coord uc, cc;
722 /* The chain is stretched vertically, so you shouldn't be able to move
723 * very far diagonally. The premise that you should be able to move one
724 * spot leads to calculations that allow you to only move one spot away
725 * from the ball, if you are levitating over the ball, or one spot
726 * towards the ball, if you are at the end of the chain. Rather than
727 * bother with all of that, assume that there is no slack in the chain
728 * for diagonal movement, give the player a message and return.
730 if (Punished && !carried(uball)) {
731 You_feel("a tug from the iron ball.");
732 nomul(0);
733 return;
734 } else if (u.utrap) {
735 You("are anchored by the %s.",
736 u.utraptype == TT_WEB
737 ? "web"
738 : u.utraptype == TT_LAVA
739 ? hliquid("lava")
740 : u.utraptype == TT_INFLOOR
741 ? surface(u.ux, u.uy)
742 : u.utraptype == TT_BURIEDBALL ? "buried ball"
743 : "trap");
744 nomul(0);
745 return;
748 /* make sure dx and dy are [-1,0,1] */
749 dx = sgn(dx);
750 dy = sgn(dy);
752 if (!range || (!dx && !dy) || u.ustuck)
753 return; /* paranoia */
755 nomul(-range);
756 multi_reason = "moving through the air";
757 nomovemsg = ""; /* it just happens */
758 if (verbose)
759 You("%s in the opposite direction.", range > 1 ? "hurtle" : "float");
760 /* if we're in the midst of shooting multiple projectiles, stop */
761 endmultishot(TRUE);
762 sokoban_guilt();
763 uc.x = u.ux;
764 uc.y = u.uy;
765 /* this setting of cc is only correct if dx and dy are [-1,0,1] only */
766 cc.x = u.ux + (dx * range);
767 cc.y = u.uy + (dy * range);
768 (void) walk_path(&uc, &cc, hurtle_step, (genericptr_t) &range);
771 /* Move a monster through the air for a few squares.
773 void
774 mhurtle(mon, dx, dy, range)
775 struct monst *mon;
776 int dx, dy, range;
778 coord mc, cc;
780 /* At the very least, debilitate the monster */
781 mon->movement = 0;
782 mon->mstun = 1;
784 /* Is the monster stuck or too heavy to push?
785 * (very large monsters have too much inertia, even floaters and flyers)
787 if (mon->data->msize >= MZ_HUGE || mon == u.ustuck || mon->mtrapped)
788 return;
790 /* Make sure dx and dy are [-1,0,1] */
791 dx = sgn(dx);
792 dy = sgn(dy);
793 if (!range || (!dx && !dy))
794 return; /* paranoia */
795 /* don't let grid bugs be hurtled diagonally */
796 if (dx && dy && NODIAG(monsndx(mon->data)))
797 return;
799 /* Send the monster along the path */
800 mc.x = mon->mx;
801 mc.y = mon->my;
802 cc.x = mon->mx + (dx * range);
803 cc.y = mon->my + (dy * range);
804 (void) walk_path(&mc, &cc, mhurtle_step, (genericptr_t) mon);
805 return;
808 STATIC_OVL void
809 check_shop_obj(obj, x, y, broken)
810 struct obj *obj;
811 xchar x, y;
812 boolean broken;
814 struct monst *shkp = shop_keeper(*u.ushops);
816 if (!shkp)
817 return;
819 if (broken || !costly_spot(x, y)
820 || *in_rooms(x, y, SHOPBASE) != *u.ushops) {
821 /* thrown out of a shop or into a different shop */
822 if (is_unpaid(obj))
823 (void) stolen_value(obj, u.ux, u.uy, (boolean) shkp->mpeaceful,
824 FALSE);
825 if (broken)
826 obj->no_charge = 1;
827 } else {
828 if (costly_spot(u.ux, u.uy) && costly_spot(x, y)) {
829 if (is_unpaid(obj))
830 subfrombill(obj, shkp);
831 else if (x != shkp->mx || y != shkp->my)
832 sellobj(obj, x, y);
838 * Hero tosses an object upwards with appropriate consequences.
840 * Returns FALSE if the object is gone.
842 STATIC_OVL boolean
843 toss_up(obj, hitsroof)
844 struct obj *obj;
845 boolean hitsroof;
847 const char *action;
848 boolean petrifier = ((obj->otyp == EGG || obj->otyp == CORPSE)
849 && touch_petrifies(&mons[obj->corpsenm]));
850 /* note: obj->quan == 1 */
852 if (!has_ceiling(&u.uz)) {
853 action = "flies up into"; /* into "the sky" or "the water above" */
854 } else if (hitsroof) {
855 if (breaktest(obj)) {
856 pline("%s hits the %s.", Doname2(obj), ceiling(u.ux, u.uy));
857 breakmsg(obj, !Blind);
858 breakobj(obj, u.ux, u.uy, TRUE, TRUE);
859 return FALSE;
861 action = "hits";
862 } else {
863 action = "almost hits";
865 pline("%s %s the %s, then falls back on top of your %s.", Doname2(obj),
866 action, ceiling(u.ux, u.uy), body_part(HEAD));
868 /* object now hits you */
870 if (obj->oclass == POTION_CLASS) {
871 potionhit(&youmonst, obj, TRUE);
872 } else if (breaktest(obj)) {
873 int otyp = obj->otyp;
874 int blindinc;
876 /* need to check for blindness result prior to destroying obj */
877 blindinc = ((otyp == CREAM_PIE || otyp == BLINDING_VENOM)
878 /* AT_WEAP is ok here even if attack type was AT_SPIT */
879 && can_blnd(&youmonst, &youmonst, AT_WEAP, obj))
880 ? rnd(25)
881 : 0;
882 breakmsg(obj, !Blind);
883 breakobj(obj, u.ux, u.uy, TRUE, TRUE);
884 obj = 0; /* it's now gone */
885 switch (otyp) {
886 case EGG:
887 if (petrifier && !Stone_resistance
888 && !(poly_when_stoned(youmonst.data)
889 && polymon(PM_STONE_GOLEM))) {
890 /* egg ends up "all over your face"; perhaps
891 visored helmet should still save you here */
892 if (uarmh)
893 Your("%s fails to protect you.", helm_simple_name(uarmh));
894 goto petrify;
896 case CREAM_PIE:
897 case BLINDING_VENOM:
898 pline("You've got it all over your %s!", body_part(FACE));
899 if (blindinc) {
900 if (otyp == BLINDING_VENOM && !Blind)
901 pline("It blinds you!");
902 u.ucreamed += blindinc;
903 make_blinded(Blinded + (long) blindinc, FALSE);
904 if (!Blind)
905 Your1(vision_clears);
907 break;
908 default:
909 break;
911 return FALSE;
912 } else { /* neither potion nor other breaking object */
913 boolean less_damage = uarmh && is_metallic(uarmh), artimsg = FALSE;
914 int dmg = dmgval(obj, &youmonst);
916 if (obj->oartifact)
917 /* need a fake die roll here; rn1(18,2) avoids 1 and 20 */
918 artimsg = artifact_hit((struct monst *) 0, &youmonst, obj, &dmg,
919 rn1(18, 2));
921 if (!dmg) { /* probably wasn't a weapon; base damage on weight */
922 dmg = (int) obj->owt / 100;
923 if (dmg < 1)
924 dmg = 1;
925 else if (dmg > 6)
926 dmg = 6;
927 if (youmonst.data == &mons[PM_SHADE]
928 && objects[obj->otyp].oc_material != SILVER)
929 dmg = 0;
931 if (dmg > 1 && less_damage)
932 dmg = 1;
933 if (dmg > 0)
934 dmg += u.udaminc;
935 if (dmg < 0)
936 dmg = 0; /* beware negative rings of increase damage */
937 dmg = Maybe_Half_Phys(dmg);
939 if (uarmh) {
940 if (less_damage && dmg < (Upolyd ? u.mh : u.uhp)) {
941 if (!artimsg)
942 pline("Fortunately, you are wearing a hard helmet.");
943 /* helmet definitely protects you when it blocks petrification
945 } else if (!petrifier) {
946 if (flags.verbose)
947 Your("%s does not protect you.", helm_simple_name(uarmh));
949 } else if (petrifier && !Stone_resistance
950 && !(poly_when_stoned(youmonst.data)
951 && polymon(PM_STONE_GOLEM))) {
952 petrify:
953 killer.format = KILLED_BY;
954 Strcpy(killer.name, "elementary physics"); /* "what goes up..." */
955 You("turn to stone.");
956 if (obj)
957 dropy(obj); /* bypass most of hitfloor() */
958 thrownobj = 0; /* now either gone or on floor */
959 done(STONING);
960 return obj ? TRUE : FALSE;
962 hitfloor(obj);
963 thrownobj = 0;
964 losehp(Maybe_Half_Phys(dmg), "falling object", KILLED_BY_AN);
966 return TRUE;
969 /* return true for weapon meant to be thrown; excludes ammo */
970 boolean
971 throwing_weapon(obj)
972 struct obj *obj;
974 return (boolean) (is_missile(obj) || is_spear(obj)
975 /* daggers and knife (excludes scalpel) */
976 || (is_blade(obj) && !is_sword(obj)
977 && (objects[obj->otyp].oc_dir & PIERCE))
978 /* special cases [might want to add AXE] */
979 || obj->otyp == WAR_HAMMER || obj->otyp == AKLYS);
982 /* the currently thrown object is returning to you (not for boomerangs) */
983 STATIC_OVL void
984 sho_obj_return_to_u(obj)
985 struct obj *obj;
987 /* might already be our location (bounced off a wall) */
988 if ((u.dx || u.dy) && (bhitpos.x != u.ux || bhitpos.y != u.uy)) {
989 int x = bhitpos.x - u.dx, y = bhitpos.y - u.dy;
991 tmp_at(DISP_FLASH, obj_to_glyph(obj));
992 while (isok(x,y) && (x != u.ux || y != u.uy)) {
993 tmp_at(x, y);
994 delay_output();
995 x -= u.dx;
996 y -= u.dy;
998 tmp_at(DISP_END, 0);
1002 /* throw an object, NB: obj may be consumed in the process */
1003 void
1004 throwit(obj, wep_mask, twoweap)
1005 struct obj *obj;
1006 long wep_mask; /* used to re-equip returning boomerang */
1007 boolean
1008 twoweap; /* used to restore twoweapon mode if wielded weapon returns */
1010 register struct monst *mon;
1011 register int range, urange;
1012 boolean crossbowing, impaired = (Confusion || Stunned || Blind
1013 || Hallucination || Fumbling);
1015 notonhead = FALSE; /* reset potentially stale value */
1016 if ((obj->cursed || obj->greased) && (u.dx || u.dy) && !rn2(7)) {
1017 boolean slipok = TRUE;
1018 if (ammo_and_launcher(obj, uwep))
1019 pline("%s!", Tobjnam(obj, "misfire"));
1020 else {
1021 /* only slip if it's greased or meant to be thrown */
1022 if (obj->greased || throwing_weapon(obj))
1023 /* BUG: this message is grammatically incorrect if obj has
1024 a plural name; greased gloves or boots for instance. */
1025 pline("%s as you throw it!", Tobjnam(obj, "slip"));
1026 else
1027 slipok = FALSE;
1029 if (slipok) {
1030 u.dx = rn2(3) - 1;
1031 u.dy = rn2(3) - 1;
1032 if (!u.dx && !u.dy)
1033 u.dz = 1;
1034 impaired = TRUE;
1038 if ((u.dx || u.dy || (u.dz < 1))
1039 && calc_capacity((int) obj->owt) > SLT_ENCUMBER
1040 && (Upolyd ? (u.mh < 5 && u.mh != u.mhmax)
1041 : (u.uhp < 10 && u.uhp != u.uhpmax))
1042 && obj->owt > (unsigned) ((Upolyd ? u.mh : u.uhp) * 2)
1043 && !Is_airlevel(&u.uz)) {
1044 You("have so little stamina, %s drops from your grasp.",
1045 the(xname(obj)));
1046 exercise(A_CON, FALSE);
1047 u.dx = u.dy = 0;
1048 u.dz = 1;
1051 thrownobj = obj;
1052 thrownobj->was_thrown = 1;
1054 if (u.uswallow) {
1055 mon = u.ustuck;
1056 bhitpos.x = mon->mx;
1057 bhitpos.y = mon->my;
1058 } else if (u.dz) {
1059 if (u.dz < 0 && Role_if(PM_VALKYRIE) && obj->oartifact == ART_MJOLLNIR
1060 && !impaired) {
1061 pline("%s the %s and returns to your hand!", Tobjnam(obj, "hit"),
1062 ceiling(u.ux, u.uy));
1063 obj = addinv(obj);
1064 (void) encumber_msg();
1065 setuwep(obj);
1066 u.twoweap = twoweap;
1067 } else if (u.dz < 0) {
1068 (void) toss_up(obj, rn2(5) && !Underwater);
1069 } else if (u.dz > 0 && u.usteed && obj->oclass == POTION_CLASS
1070 && rn2(6)) {
1071 /* alternative to prayer or wand of opening/spell of knock
1072 for dealing with cursed saddle: throw holy water > */
1073 potionhit(u.usteed, obj, TRUE);
1074 } else {
1075 hitfloor(obj);
1077 thrownobj = (struct obj *) 0;
1078 return;
1080 } else if (obj->otyp == BOOMERANG && !Underwater) {
1081 if (Is_airlevel(&u.uz) || Levitation)
1082 hurtle(-u.dx, -u.dy, 1, TRUE);
1083 mon = boomhit(obj, u.dx, u.dy);
1084 if (mon == &youmonst) { /* the thing was caught */
1085 exercise(A_DEX, TRUE);
1086 obj = addinv(obj);
1087 (void) encumber_msg();
1088 if (wep_mask && !(obj->owornmask & wep_mask)) {
1089 setworn(obj, wep_mask);
1090 u.twoweap = twoweap;
1092 thrownobj = (struct obj *) 0;
1093 return;
1095 } else {
1096 /* crossbow range is independent of strength */
1097 crossbowing =
1098 (ammo_and_launcher(obj, uwep) && weapon_type(uwep) == P_CROSSBOW);
1099 urange = (crossbowing ? 18 : (int) ACURRSTR) / 2;
1100 /* balls are easy to throw or at least roll;
1101 * also, this insures the maximum range of a ball is greater
1102 * than 1, so the effects from throwing attached balls are
1103 * actually possible
1105 if (obj->otyp == HEAVY_IRON_BALL)
1106 range = urange - (int) (obj->owt / 100);
1107 else
1108 range = urange - (int) (obj->owt / 40);
1109 if (obj == uball) {
1110 if (u.ustuck)
1111 range = 1;
1112 else if (range >= 5)
1113 range = 5;
1115 if (range < 1)
1116 range = 1;
1118 if (is_ammo(obj)) {
1119 if (ammo_and_launcher(obj, uwep)) {
1120 if (crossbowing)
1121 range = BOLT_LIM;
1122 else
1123 range++;
1124 } else if (obj->oclass != GEM_CLASS)
1125 range /= 2;
1128 if (Is_airlevel(&u.uz) || Levitation) {
1129 /* action, reaction... */
1130 urange -= range;
1131 if (urange < 1)
1132 urange = 1;
1133 range -= urange;
1134 if (range < 1)
1135 range = 1;
1138 if (obj->otyp == BOULDER)
1139 range = 20; /* you must be giant */
1140 else if (obj->oartifact == ART_MJOLLNIR)
1141 range = (range + 1) / 2; /* it's heavy */
1142 else if (obj == uball && u.utrap && u.utraptype == TT_INFLOOR)
1143 range = 1;
1145 if (Underwater)
1146 range = 1;
1148 mon = bhit(u.dx, u.dy, range, THROWN_WEAPON,
1149 (int FDECL((*), (MONST_P, OBJ_P))) 0,
1150 (int FDECL((*), (OBJ_P, OBJ_P))) 0, &obj);
1151 thrownobj = obj; /* obj may be null now */
1153 /* have to do this after bhit() so u.ux & u.uy are correct */
1154 if (Is_airlevel(&u.uz) || Levitation)
1155 hurtle(-u.dx, -u.dy, urange, TRUE);
1157 if (!obj)
1158 return;
1161 if (mon) {
1162 boolean obj_gone;
1164 if (mon->isshk && obj->where == OBJ_MINVENT && obj->ocarry == mon) {
1165 thrownobj = (struct obj *) 0;
1166 return; /* alert shk caught it */
1168 (void) snuff_candle(obj);
1169 notonhead = (bhitpos.x != mon->mx || bhitpos.y != mon->my);
1170 obj_gone = thitmonst(mon, obj);
1171 /* Monster may have been tamed; this frees old mon */
1172 mon = m_at(bhitpos.x, bhitpos.y);
1174 /* [perhaps this should be moved into thitmonst or hmon] */
1175 if (mon && mon->isshk
1176 && (!inside_shop(u.ux, u.uy)
1177 || !index(in_rooms(mon->mx, mon->my, SHOPBASE), *u.ushops)))
1178 hot_pursuit(mon);
1180 if (obj_gone)
1181 thrownobj = 0;
1184 if (!thrownobj) {
1185 ; /* missile has already been handled */
1186 } else if (u.uswallow) {
1187 /* ball is not picked up by monster */
1188 if (obj != uball)
1189 (void) mpickobj(u.ustuck, obj);
1190 thrownobj = (struct obj *) 0;
1191 } else {
1192 /* the code following might become part of dropy() */
1193 if (obj->oartifact == ART_MJOLLNIR && Role_if(PM_VALKYRIE)
1194 && rn2(100)) {
1195 /* we must be wearing Gauntlets of Power to get here */
1196 sho_obj_return_to_u(obj); /* display its flight */
1198 if (!impaired && rn2(100)) {
1199 pline("%s to your hand!", Tobjnam(obj, "return"));
1200 obj = addinv(obj);
1201 (void) encumber_msg();
1202 setuwep(obj);
1203 u.twoweap = twoweap;
1204 if (cansee(bhitpos.x, bhitpos.y))
1205 newsym(bhitpos.x, bhitpos.y);
1206 } else {
1207 int dmg = rn2(2);
1208 if (!dmg) {
1209 pline(Blind ? "%s lands %s your %s."
1210 : "%s back to you, landing %s your %s.",
1211 Blind ? Something : Tobjnam(obj, "return"),
1212 Levitation ? "beneath" : "at",
1213 makeplural(body_part(FOOT)));
1214 } else {
1215 dmg += rnd(3);
1216 pline(Blind ? "%s your %s!"
1217 : "%s back toward you, hitting your %s!",
1218 Tobjnam(obj, Blind ? "hit" : "fly"),
1219 body_part(ARM));
1220 (void) artifact_hit((struct monst *) 0, &youmonst, obj,
1221 &dmg, 0);
1222 losehp(Maybe_Half_Phys(dmg), killer_xname(obj),
1223 KILLED_BY);
1225 if (ship_object(obj, u.ux, u.uy, FALSE)) {
1226 thrownobj = (struct obj *) 0;
1227 return;
1229 dropy(obj);
1231 thrownobj = (struct obj *) 0;
1232 return;
1235 if (!IS_SOFT(levl[bhitpos.x][bhitpos.y].typ) && breaktest(obj)) {
1236 tmp_at(DISP_FLASH, obj_to_glyph(obj));
1237 tmp_at(bhitpos.x, bhitpos.y);
1238 delay_output();
1239 tmp_at(DISP_END, 0);
1240 breakmsg(obj, cansee(bhitpos.x, bhitpos.y));
1241 breakobj(obj, bhitpos.x, bhitpos.y, TRUE, TRUE);
1242 thrownobj = (struct obj *) 0;
1243 return;
1245 if (flooreffects(obj, bhitpos.x, bhitpos.y, "fall")) {
1246 thrownobj = (struct obj *) 0;
1247 return;
1249 obj_no_longer_held(obj);
1250 if (mon && mon->isshk && is_pick(obj)) {
1251 if (cansee(bhitpos.x, bhitpos.y))
1252 pline("%s snatches up %s.", Monnam(mon), the(xname(obj)));
1253 if (*u.ushops || obj->unpaid)
1254 check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE);
1255 (void) mpickobj(mon, obj); /* may merge and free obj */
1256 thrownobj = (struct obj *) 0;
1257 return;
1259 (void) snuff_candle(obj);
1260 if (!mon && ship_object(obj, bhitpos.x, bhitpos.y, FALSE)) {
1261 thrownobj = (struct obj *) 0;
1262 return;
1264 thrownobj = (struct obj *) 0;
1265 place_object(obj, bhitpos.x, bhitpos.y);
1266 /* container contents might break;
1267 do so before turning ownership of thrownobj over to shk
1268 (container_impact_dmg handles item already owned by shop) */
1269 if (!IS_SOFT(levl[bhitpos.x][bhitpos.y].typ))
1270 /* <x,y> is spot where you initiated throw, not bhitpos */
1271 container_impact_dmg(obj, u.ux, u.uy);
1272 /* charge for items thrown out of shop;
1273 shk takes possession for items thrown into one */
1274 if ((*u.ushops || obj->unpaid) && obj != uball)
1275 check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE);
1277 stackobj(obj);
1278 if (obj == uball)
1279 drop_ball(bhitpos.x, bhitpos.y);
1280 if (cansee(bhitpos.x, bhitpos.y))
1281 newsym(bhitpos.x, bhitpos.y);
1282 if (obj_sheds_light(obj))
1283 vision_full_recalc = 1;
1287 /* an object may hit a monster; various factors adjust the chance of hitting
1290 omon_adj(mon, obj, mon_notices)
1291 struct monst *mon;
1292 struct obj *obj;
1293 boolean mon_notices;
1295 int tmp = 0;
1297 /* size of target affects the chance of hitting */
1298 tmp += (mon->data->msize - MZ_MEDIUM); /* -2..+5 */
1299 /* sleeping target is more likely to be hit */
1300 if (mon->msleeping) {
1301 tmp += 2;
1302 if (mon_notices)
1303 mon->msleeping = 0;
1305 /* ditto for immobilized target */
1306 if (!mon->mcanmove || !mon->data->mmove) {
1307 tmp += 4;
1308 if (mon_notices && mon->data->mmove && !rn2(10)) {
1309 mon->mcanmove = 1;
1310 mon->mfrozen = 0;
1313 /* some objects are more likely to hit than others */
1314 switch (obj->otyp) {
1315 case HEAVY_IRON_BALL:
1316 if (obj != uball)
1317 tmp += 2;
1318 break;
1319 case BOULDER:
1320 tmp += 6;
1321 break;
1322 default:
1323 if (obj->oclass == WEAPON_CLASS || is_weptool(obj)
1324 || obj->oclass == GEM_CLASS)
1325 tmp += hitval(obj, mon);
1326 break;
1328 return tmp;
1331 /* thrown object misses target monster */
1332 STATIC_OVL void
1333 tmiss(obj, mon, maybe_wakeup)
1334 struct obj *obj;
1335 struct monst *mon;
1336 boolean maybe_wakeup;
1338 const char *missile = mshot_xname(obj);
1340 /* If the target can't be seen or doesn't look like a valid target,
1341 avoid "the arrow misses it," or worse, "the arrows misses the mimic."
1342 An attentive player will still notice that this is different from
1343 an arrow just landing short of any target (no message in that case),
1344 so will realize that there is a valid target here anyway. */
1345 if (!canseemon(mon) || (mon->m_ap_type && mon->m_ap_type != M_AP_MONSTER))
1346 pline("%s %s.", The(missile), otense(obj, "miss"));
1347 else
1348 miss(missile, mon);
1349 if (maybe_wakeup && !rn2(3))
1350 wakeup(mon, TRUE);
1351 return;
1354 #define quest_arti_hits_leader(obj, mon) \
1355 (obj->oartifact && is_quest_artifact(obj) \
1356 && mon->m_id == quest_status.leader_m_id)
1359 * Object thrown by player arrives at monster's location.
1360 * Return 1 if obj has disappeared or otherwise been taken care of,
1361 * 0 if caller must take care of it.
1362 * Also used for kicked objects and for polearms/grapnel applied at range.
1365 thitmonst(mon, obj)
1366 register struct monst *mon;
1367 register struct obj *obj; /* thrownobj or kickedobj or uwep */
1369 register int tmp; /* Base chance to hit */
1370 register int disttmp; /* distance modifier */
1371 int otyp = obj->otyp, hmode;
1372 boolean guaranteed_hit = (u.uswallow && mon == u.ustuck);
1374 hmode = (obj == uwep) ? HMON_APPLIED
1375 : (obj == kickedobj) ? HMON_KICKED
1376 : HMON_THROWN;
1378 /* Differences from melee weapons:
1380 * Dex still gives a bonus, but strength does not.
1381 * Polymorphed players lacking attacks may still throw.
1382 * There's a base -1 to hit.
1383 * No bonuses for fleeing or stunned targets (they don't dodge
1384 * melee blows as readily, but dodging arrows is hard anyway).
1385 * Not affected by traps, etc.
1386 * Certain items which don't in themselves do damage ignore tmp.
1387 * Distance and monster size affect chance to hit.
1389 tmp = -1 + Luck + find_mac(mon) + u.uhitinc
1390 + maybe_polyd(youmonst.data->mlevel, u.ulevel);
1391 if (ACURR(A_DEX) < 4)
1392 tmp -= 3;
1393 else if (ACURR(A_DEX) < 6)
1394 tmp -= 2;
1395 else if (ACURR(A_DEX) < 8)
1396 tmp -= 1;
1397 else if (ACURR(A_DEX) >= 14)
1398 tmp += (ACURR(A_DEX) - 14);
1400 /* Modify to-hit depending on distance; but keep it sane.
1401 * Polearms get a distance penalty even when wielded; it's
1402 * hard to hit at a distance.
1404 disttmp = 3 - distmin(u.ux, u.uy, mon->mx, mon->my);
1405 if (disttmp < -4)
1406 disttmp = -4;
1407 tmp += disttmp;
1409 /* gloves are a hindrance to proper use of bows */
1410 if (uarmg && uwep && objects[uwep->otyp].oc_skill == P_BOW) {
1411 switch (uarmg->otyp) {
1412 case GAUNTLETS_OF_POWER: /* metal */
1413 tmp -= 2;
1414 break;
1415 case GAUNTLETS_OF_FUMBLING:
1416 tmp -= 3;
1417 break;
1418 case LEATHER_GLOVES:
1419 case GAUNTLETS_OF_DEXTERITY:
1420 break;
1421 default:
1422 impossible("Unknown type of gloves (%d)", uarmg->otyp);
1423 break;
1427 tmp += omon_adj(mon, obj, TRUE);
1428 if (is_orc(mon->data)
1429 && maybe_polyd(is_elf(youmonst.data), Race_if(PM_ELF)))
1430 tmp++;
1431 if (guaranteed_hit) {
1432 tmp += 1000; /* Guaranteed hit */
1435 if (obj->oclass == GEM_CLASS && is_unicorn(mon->data)) {
1436 if (mon->msleeping || !mon->mcanmove) {
1437 tmiss(obj, mon, FALSE);
1438 return 0;
1439 } else if (mon->mtame) {
1440 pline("%s catches and drops %s.", Monnam(mon), the(xname(obj)));
1441 return 0;
1442 } else {
1443 pline("%s catches %s.", Monnam(mon), the(xname(obj)));
1444 return gem_accept(mon, obj);
1448 /* don't make game unwinnable if naive player throws artifact
1449 at leader... (kicked artifact is ok too; HMON_APPLIED could
1450 occur if quest artifact polearm or grapnel ever gets added) */
1451 if (hmode != HMON_APPLIED && quest_arti_hits_leader(obj, mon)) {
1452 /* AIS: changes to wakeup() means that it's now less inappropriate here
1453 than it used to be, but the manual version works just as well */
1454 mon->msleeping = 0;
1455 mon->mstrategy &= ~STRAT_WAITMASK;
1457 if (mon->mcanmove) {
1458 pline("%s catches %s.", Monnam(mon), the(xname(obj)));
1459 if (mon->mpeaceful) {
1460 boolean next2u = monnear(mon, u.ux, u.uy);
1462 finish_quest(obj); /* acknowledge quest completion */
1463 pline("%s %s %s back to you.", Monnam(mon),
1464 (next2u ? "hands" : "tosses"), the(xname(obj)));
1465 if (!next2u)
1466 sho_obj_return_to_u(obj);
1467 obj = addinv(obj); /* back into your inventory */
1468 (void) encumber_msg();
1469 } else {
1470 /* angry leader caught it and isn't returning it */
1471 if (*u.ushops || obj->unpaid) /* not very likely... */
1472 check_shop_obj(obj, mon->mx, mon->my, FALSE);
1473 (void) mpickobj(mon, obj);
1475 return 1; /* caller doesn't need to place it */
1477 return 0;
1480 if (obj->oclass == WEAPON_CLASS || is_weptool(obj)
1481 || obj->oclass == GEM_CLASS) {
1482 if (hmode == HMON_KICKED) {
1483 /* throwing adjustments and weapon skill bonus don't apply */
1484 tmp -= (is_ammo(obj) ? 5 : 3);
1485 } else if (is_ammo(obj)) {
1486 if (!ammo_and_launcher(obj, uwep)) {
1487 tmp -= 4;
1488 } else {
1489 tmp += uwep->spe - greatest_erosion(uwep);
1490 tmp += weapon_hit_bonus(uwep);
1491 if (uwep->oartifact)
1492 tmp += spec_abon(uwep, mon);
1494 * Elves and Samurais are highly trained w/bows,
1495 * especially their own special types of bow.
1496 * Polymorphing won't make you a bow expert.
1498 if ((Race_if(PM_ELF) || Role_if(PM_SAMURAI))
1499 && (!Upolyd || your_race(youmonst.data))
1500 && objects[uwep->otyp].oc_skill == P_BOW) {
1501 tmp++;
1502 if (Race_if(PM_ELF) && uwep->otyp == ELVEN_BOW)
1503 tmp++;
1504 else if (Role_if(PM_SAMURAI) && uwep->otyp == YUMI)
1505 tmp++;
1508 } else { /* thrown non-ammo or applied polearm/grapnel */
1509 if (otyp == BOOMERANG) /* arbitrary */
1510 tmp += 4;
1511 else if (throwing_weapon(obj)) /* meant to be thrown */
1512 tmp += 2;
1513 else if (obj == thrownobj) /* not meant to be thrown */
1514 tmp -= 2;
1515 /* we know we're dealing with a weapon or weptool handled
1516 by WEAPON_SKILLS once ammo objects have been excluded */
1517 tmp += weapon_hit_bonus(obj);
1520 if (tmp >= rnd(20)) {
1521 boolean wasthrown = (thrownobj != 0);
1523 /* attack hits mon */
1524 if (hmode == HMON_APPLIED)
1525 u.uconduct.weaphit++;
1526 if (hmon(mon, obj, hmode)) { /* mon still alive */
1527 cutworm(mon, bhitpos.x, bhitpos.y, obj);
1529 exercise(A_DEX, TRUE);
1530 /* if hero was swallowed and projectile killed the engulfer,
1531 'obj' got added to engulfer's inventory and then dropped,
1532 so we can't safely use that pointer anymore; it escapes
1533 the chance to be used up here... */
1534 if (wasthrown && !thrownobj)
1535 return 1;
1537 /* projectiles other than magic stones
1538 sometimes disappear when thrown */
1539 if (objects[otyp].oc_skill < P_NONE
1540 && objects[otyp].oc_skill > -P_BOOMERANG
1541 && !objects[otyp].oc_magic) {
1542 /* we were breaking 2/3 of everything unconditionally.
1543 * we still don't want anything to survive unconditionally,
1544 * but we need ammo to stay around longer on average.
1546 int broken, chance;
1548 chance = 3 + greatest_erosion(obj) - obj->spe;
1549 if (chance > 1)
1550 broken = rn2(chance);
1551 else
1552 broken = !rn2(4);
1553 if (obj->blessed && !rnl(4))
1554 broken = 0;
1556 if (broken) {
1557 if (*u.ushops || obj->unpaid)
1558 check_shop_obj(obj, bhitpos.x, bhitpos.y, TRUE);
1559 obfree(obj, (struct obj *) 0);
1560 return 1;
1563 passive_obj(mon, obj, (struct attack *) 0);
1564 } else {
1565 tmiss(obj, mon, TRUE);
1566 if (hmode == HMON_APPLIED)
1567 wakeup(mon, TRUE);
1570 } else if (otyp == HEAVY_IRON_BALL) {
1571 exercise(A_STR, TRUE);
1572 if (tmp >= rnd(20)) {
1573 int was_swallowed = guaranteed_hit;
1575 exercise(A_DEX, TRUE);
1576 if (!hmon(mon, obj, hmode)) { /* mon killed */
1577 if (was_swallowed && !u.uswallow && obj == uball)
1578 return 1; /* already did placebc() */
1580 } else {
1581 tmiss(obj, mon, TRUE);
1584 } else if (otyp == BOULDER) {
1585 exercise(A_STR, TRUE);
1586 if (tmp >= rnd(20)) {
1587 exercise(A_DEX, TRUE);
1588 (void) hmon(mon, obj, hmode);
1589 } else {
1590 tmiss(obj, mon, TRUE);
1593 } else if ((otyp == EGG || otyp == CREAM_PIE || otyp == BLINDING_VENOM
1594 || otyp == ACID_VENOM)
1595 && (guaranteed_hit || ACURR(A_DEX) > rnd(25))) {
1596 (void) hmon(mon, obj, hmode);
1597 return 1; /* hmon used it up */
1599 } else if (obj->oclass == POTION_CLASS
1600 && (guaranteed_hit || ACURR(A_DEX) > rnd(25))) {
1601 potionhit(mon, obj, TRUE);
1602 return 1;
1604 } else if (befriend_with_obj(mon->data, obj)
1605 || (mon->mtame && dogfood(mon, obj) <= ACCFOOD)) {
1606 if (tamedog(mon, obj)) {
1607 return 1; /* obj is gone */
1608 } else {
1609 tmiss(obj, mon, FALSE);
1610 mon->msleeping = 0;
1611 mon->mstrategy &= ~STRAT_WAITMASK;
1613 } else if (guaranteed_hit) {
1614 /* this assumes that guaranteed_hit is due to swallowing */
1615 wakeup(mon, TRUE);
1616 if (obj->otyp == CORPSE && touch_petrifies(&mons[obj->corpsenm])) {
1617 if (is_animal(u.ustuck->data)) {
1618 minstapetrify(u.ustuck, TRUE);
1619 /* Don't leave a cockatrice corpse available in a statue */
1620 if (!u.uswallow) {
1621 delobj(obj);
1622 return 1;
1626 pline("%s into %s %s.", Tobjnam(obj, "vanish"),
1627 s_suffix(mon_nam(mon)),
1628 is_animal(u.ustuck->data) ? "entrails" : "currents");
1629 } else {
1630 tmiss(obj, mon, TRUE);
1633 return 0;
1636 STATIC_OVL int
1637 gem_accept(mon, obj)
1638 register struct monst *mon;
1639 register struct obj *obj;
1641 char buf[BUFSZ];
1642 boolean is_buddy = sgn(mon->data->maligntyp) == sgn(u.ualign.type);
1643 boolean is_gem = objects[obj->otyp].oc_material == GEMSTONE;
1644 int ret = 0;
1645 static NEARDATA const char nogood[] = " is not interested in your junk.";
1646 static NEARDATA const char acceptgift[] = " accepts your gift.";
1647 static NEARDATA const char maybeluck[] = " hesitatingly";
1648 static NEARDATA const char noluck[] = " graciously";
1649 static NEARDATA const char addluck[] = " gratefully";
1651 Strcpy(buf, Monnam(mon));
1652 mon->mpeaceful = 1;
1653 mon->mavenge = 0;
1655 /* object properly identified */
1656 if (obj->dknown && objects[obj->otyp].oc_name_known) {
1657 if (is_gem) {
1658 if (is_buddy) {
1659 Strcat(buf, addluck);
1660 change_luck(5);
1661 } else {
1662 Strcat(buf, maybeluck);
1663 change_luck(rn2(7) - 3);
1665 } else {
1666 Strcat(buf, nogood);
1667 goto nopick;
1669 /* making guesses */
1670 } else if (has_oname(obj) || objects[obj->otyp].oc_uname) {
1671 if (is_gem) {
1672 if (is_buddy) {
1673 Strcat(buf, addluck);
1674 change_luck(2);
1675 } else {
1676 Strcat(buf, maybeluck);
1677 change_luck(rn2(3) - 1);
1679 } else {
1680 Strcat(buf, nogood);
1681 goto nopick;
1683 /* value completely unknown to @ */
1684 } else {
1685 if (is_gem) {
1686 if (is_buddy) {
1687 Strcat(buf, addluck);
1688 change_luck(1);
1689 } else {
1690 Strcat(buf, maybeluck);
1691 change_luck(rn2(3) - 1);
1693 } else {
1694 Strcat(buf, noluck);
1697 Strcat(buf, acceptgift);
1698 if (*u.ushops || obj->unpaid)
1699 check_shop_obj(obj, mon->mx, mon->my, TRUE);
1700 (void) mpickobj(mon, obj); /* may merge and free obj */
1701 ret = 1;
1703 nopick:
1704 if (!Blind)
1705 pline1(buf);
1706 if (!tele_restrict(mon))
1707 (void) rloc(mon, TRUE);
1708 return ret;
1712 * Comments about the restructuring of the old breaks() routine.
1714 * There are now three distinct phases to object breaking:
1715 * breaktest() - which makes the check/decision about whether the
1716 * object is going to break.
1717 * breakmsg() - which outputs a message about the breakage,
1718 * appropriate for that particular object. Should
1719 * only be called after a positive breaktest().
1720 * on the object and, if it going to be called,
1721 * it must be called before calling breakobj().
1722 * Calling breakmsg() is optional.
1723 * breakobj() - which actually does the breakage and the side-effects
1724 * of breaking that particular object. This should
1725 * only be called after a positive breaktest() on the
1726 * object.
1728 * Each of the above routines is currently static to this source module.
1729 * There are two routines callable from outside this source module which
1730 * perform the routines above in the correct sequence.
1732 * hero_breaks() - called when an object is to be broken as a result
1733 * of something that the hero has done. (throwing it,
1734 * kicking it, etc.)
1735 * breaks() - called when an object is to be broken for some
1736 * reason other than the hero doing something to it.
1740 * The hero causes breakage of an object (throwing, dropping it, etc.)
1741 * Return 0 if the object didn't break, 1 if the object broke.
1744 hero_breaks(obj, x, y, from_invent)
1745 struct obj *obj;
1746 xchar x, y; /* object location (ox, oy may not be right) */
1747 boolean from_invent; /* thrown or dropped by player; maybe on shop bill */
1749 boolean in_view = Blind ? FALSE : (from_invent || cansee(x, y));
1750 if (!breaktest(obj))
1751 return 0;
1752 breakmsg(obj, in_view);
1753 breakobj(obj, x, y, TRUE, from_invent);
1754 return 1;
1758 * The object is going to break for a reason other than the hero doing
1759 * something to it.
1760 * Return 0 if the object doesn't break, 1 if the object broke.
1763 breaks(obj, x, y)
1764 struct obj *obj;
1765 xchar x, y; /* object location (ox, oy may not be right) */
1767 boolean in_view = Blind ? FALSE : cansee(x, y);
1769 if (!breaktest(obj))
1770 return 0;
1771 breakmsg(obj, in_view);
1772 breakobj(obj, x, y, FALSE, FALSE);
1773 return 1;
1776 void
1777 release_camera_demon(obj, x, y)
1778 struct obj *obj;
1779 xchar x, y;
1781 struct monst *mtmp;
1782 if (!rn2(3)
1783 && (mtmp = makemon(&mons[rn2(3) ? PM_HOMUNCULUS : PM_IMP], x, y,
1784 NO_MM_FLAGS)) != 0) {
1785 if (canspotmon(mtmp))
1786 pline("%s is released!", Hallucination
1787 ? An(rndmonnam(NULL))
1788 : "The picture-painting demon");
1789 mtmp->mpeaceful = !obj->cursed;
1790 set_malign(mtmp);
1795 * Unconditionally break an object. Assumes all resistance checks
1796 * and break messages have been delivered prior to getting here.
1798 void
1799 breakobj(obj, x, y, hero_caused, from_invent)
1800 struct obj *obj;
1801 xchar x, y; /* object location (ox, oy may not be right) */
1802 boolean hero_caused; /* is this the hero's fault? */
1803 boolean from_invent;
1805 boolean fracture = FALSE;
1807 switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) {
1808 case MIRROR:
1809 if (hero_caused)
1810 change_luck(-2);
1811 break;
1812 case POT_WATER: /* really, all potions */
1813 obj->in_use = 1; /* in case it's fatal */
1814 if (obj->otyp == POT_OIL && obj->lamplit) {
1815 explode_oil(obj, x, y);
1816 } else if (distu(x, y) <= 2) {
1817 if (!breathless(youmonst.data) || haseyes(youmonst.data)) {
1818 if (obj->otyp != POT_WATER) {
1819 if (!breathless(youmonst.data)) {
1820 /* [what about "familiar odor" when known?] */
1821 You("smell a peculiar odor...");
1822 } else {
1823 const char *eyes = body_part(EYE);
1825 if (eyecount(youmonst.data) != 1)
1826 eyes = makeplural(eyes);
1827 Your("%s %s.", eyes, vtense(eyes, "water"));
1830 potionbreathe(obj);
1833 /* monster breathing isn't handled... [yet?] */
1834 break;
1835 case EXPENSIVE_CAMERA:
1836 release_camera_demon(obj, x, y);
1837 break;
1838 case EGG:
1839 /* breaking your own eggs is bad luck */
1840 if (hero_caused && obj->spe && obj->corpsenm >= LOW_PM)
1841 change_luck((schar) -min(obj->quan, 5L));
1842 break;
1843 case BOULDER:
1844 case STATUE:
1845 /* caller will handle object disposition;
1846 we're just doing the shop theft handling */
1847 fracture = TRUE;
1848 break;
1849 default:
1850 break;
1853 if (hero_caused) {
1854 if (from_invent || obj->unpaid) {
1855 if (*u.ushops || obj->unpaid)
1856 check_shop_obj(obj, x, y, TRUE);
1857 } else if (!obj->no_charge && costly_spot(x, y)) {
1858 /* it is assumed that the obj is a floor-object */
1859 char *o_shop = in_rooms(x, y, SHOPBASE);
1860 struct monst *shkp = shop_keeper(*o_shop);
1862 if (shkp) { /* (implies *o_shop != '\0') */
1863 static NEARDATA long lastmovetime = 0L;
1864 static NEARDATA boolean peaceful_shk = FALSE;
1865 /* We want to base shk actions on her peacefulness
1866 at start of this turn, so that "simultaneous"
1867 multiple breakage isn't drastically worse than
1868 single breakage. (ought to be done via ESHK) */
1869 if (moves != lastmovetime)
1870 peaceful_shk = shkp->mpeaceful;
1871 if (stolen_value(obj, x, y, peaceful_shk, FALSE) > 0L
1872 && (*o_shop != u.ushops[0] || !inside_shop(u.ux, u.uy))
1873 && moves != lastmovetime)
1874 make_angry_shk(shkp, x, y);
1875 lastmovetime = moves;
1879 if (!fracture)
1880 delobj(obj);
1884 * Check to see if obj is going to break, but don't actually break it.
1885 * Return 0 if the object isn't going to break, 1 if it is.
1887 boolean
1888 breaktest(obj)
1889 struct obj *obj;
1891 if (obj_resists(obj, 1, 99))
1892 return 0;
1893 if (objects[obj->otyp].oc_material == GLASS && !obj->oartifact
1894 && obj->oclass != GEM_CLASS)
1895 return 1;
1896 switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) {
1897 case EXPENSIVE_CAMERA:
1898 case POT_WATER: /* really, all potions */
1899 case EGG:
1900 case CREAM_PIE:
1901 case MELON:
1902 case ACID_VENOM:
1903 case BLINDING_VENOM:
1904 return 1;
1905 default:
1906 return 0;
1910 STATIC_OVL void
1911 breakmsg(obj, in_view)
1912 struct obj *obj;
1913 boolean in_view;
1915 const char *to_pieces;
1917 to_pieces = "";
1918 switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) {
1919 default: /* glass or crystal wand */
1920 if (obj->oclass != WAND_CLASS)
1921 impossible("breaking odd object?");
1922 case CRYSTAL_PLATE_MAIL:
1923 case LENSES:
1924 case MIRROR:
1925 case CRYSTAL_BALL:
1926 case EXPENSIVE_CAMERA:
1927 to_pieces = " into a thousand pieces";
1928 /*FALLTHRU*/
1929 case POT_WATER: /* really, all potions */
1930 if (!in_view)
1931 You_hear("%s shatter!", something);
1932 else
1933 pline("%s shatter%s%s!", Doname2(obj),
1934 (obj->quan == 1L) ? "s" : "", to_pieces);
1935 break;
1936 case EGG:
1937 case MELON:
1938 pline("Splat!");
1939 break;
1940 case CREAM_PIE:
1941 if (in_view)
1942 pline("What a mess!");
1943 break;
1944 case ACID_VENOM:
1945 case BLINDING_VENOM:
1946 pline("Splash!");
1947 break;
1951 STATIC_OVL int
1952 throw_gold(obj)
1953 struct obj *obj;
1955 int range, odx, ody;
1956 register struct monst *mon;
1958 if (!u.dx && !u.dy && !u.dz) {
1959 You("cannot throw gold at yourself.");
1960 return 0;
1962 freeinv(obj);
1963 if (u.uswallow) {
1964 pline(is_animal(u.ustuck->data) ? "%s in the %s's entrails."
1965 : "%s into %s.",
1966 "The money disappears", mon_nam(u.ustuck));
1967 add_to_minv(u.ustuck, obj);
1968 return 1;
1971 if (u.dz) {
1972 if (u.dz < 0 && !Is_airlevel(&u.uz) && !Underwater
1973 && !Is_waterlevel(&u.uz)) {
1974 pline_The("gold hits the %s, then falls back on top of your %s.",
1975 ceiling(u.ux, u.uy), body_part(HEAD));
1976 /* some self damage? */
1977 if (uarmh)
1978 pline("Fortunately, you are wearing %s!",
1979 an(helm_simple_name(uarmh)));
1981 bhitpos.x = u.ux;
1982 bhitpos.y = u.uy;
1983 } else {
1984 /* consistent with range for normal objects */
1985 range = (int) ((ACURRSTR) / 2 - obj->owt / 40);
1987 /* see if the gold has a place to move into */
1988 odx = u.ux + u.dx;
1989 ody = u.uy + u.dy;
1990 if (!ZAP_POS(levl[odx][ody].typ) || closed_door(odx, ody)) {
1991 bhitpos.x = u.ux;
1992 bhitpos.y = u.uy;
1993 } else {
1994 mon = bhit(u.dx, u.dy, range, THROWN_WEAPON,
1995 (int FDECL((*), (MONST_P, OBJ_P))) 0,
1996 (int FDECL((*), (OBJ_P, OBJ_P))) 0, &obj);
1997 if (!obj)
1998 return 1; /* object is gone */
1999 if (mon) {
2000 if (ghitm(mon, obj)) /* was it caught? */
2001 return 1;
2002 } else {
2003 if (ship_object(obj, bhitpos.x, bhitpos.y, FALSE))
2004 return 1;
2009 if (flooreffects(obj, bhitpos.x, bhitpos.y, "fall"))
2010 return 1;
2011 if (u.dz > 0)
2012 pline_The("gold hits the %s.", surface(bhitpos.x, bhitpos.y));
2013 place_object(obj, bhitpos.x, bhitpos.y);
2014 if (*u.ushops)
2015 sellobj(obj, bhitpos.x, bhitpos.y);
2016 stackobj(obj);
2017 newsym(bhitpos.x, bhitpos.y);
2018 return 1;
2021 /*dothrow.c*/