Also pass raw printed texts to the msghandler
[aNetHack.git] / src / dothrow.c
blob70496ef7a0369ebfa72985f7dedee3a1ce358fbf
1 /* NetHack 3.6 dothrow.c $NHDT-Date: 1455140444 2016/02/10 21:40:44 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-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);
612 wake_nearto(x,y, 10);
613 return FALSE;
615 if ((u.ux - x) && (u.uy - y) && bad_rock(youmonst.data, u.ux, y)
616 && bad_rock(youmonst.data, x, u.uy)) {
617 /* Move at a diagonal. */
618 if (Sokoban) {
619 You("come to an abrupt halt!");
620 return FALSE;
624 /* Caller has already determined that dragging the ball is allowed */
625 if (Punished && uball->where == OBJ_FLOOR) {
626 int bc_control;
627 xchar ballx, bally, chainx, chainy;
628 boolean cause_delay;
630 if (drag_ball(x, y, &bc_control, &ballx, &bally, &chainx,
631 &chainy, &cause_delay, TRUE))
632 move_bc(0, bc_control, ballx, bally, chainx, chainy);
635 ox = u.ux;
636 oy = u.uy;
637 u_on_newpos(x, y); /* set u.<ux,uy>, u.usteed-><mx,my>; cliparound(); */
638 newsym(ox, oy); /* update old position */
639 vision_recalc(1); /* update for new position */
640 flush_screen(1);
642 if (levl[x][y].typ == WATER && Is_waterlevel(&u.uz)) {
643 multi = 0;
644 drown();
645 return FALSE;
648 /* FIXME:
649 * Each trap should really trigger on the recoil if
650 * it would trigger during normal movement. However,
651 * not all the possible side-effects of this are
652 * tested [as of 3.4.0] so we trigger those that
653 * we have tested, and offer a message for the
654 * ones that we have not yet tested.
656 if ((ttmp = t_at(x, y)) != 0) {
657 if (ttmp->ttyp == MAGIC_PORTAL) {
658 dotrap(ttmp, 0);
659 return FALSE;
660 } else if (ttmp->ttyp == VIBRATING_SQUARE) {
661 pline("The ground vibrates as you pass it.");
662 dotrap(ttmp, 0); /* doesn't print messages */
663 } else if (ttmp->ttyp == FIRE_TRAP) {
664 dotrap(ttmp, 0);
665 } else if ((ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT
666 || ttmp->ttyp == HOLE || ttmp->ttyp == TRAPDOOR)
667 && Sokoban) {
668 /* Air currents overcome the recoil */
669 dotrap(ttmp, 0);
670 *range = 0;
671 return TRUE;
672 } else {
673 if (ttmp->tseen)
674 You("pass right over %s.",
675 an(defsyms[trap_to_defsym(ttmp->ttyp)].explanation));
678 if (--*range < 0) /* make sure our range never goes negative */
679 *range = 0;
680 if (*range != 0)
681 delay_output();
682 return TRUE;
685 STATIC_OVL boolean
686 mhurtle_step(arg, x, y)
687 genericptr_t arg;
688 int x, y;
690 struct monst *mon = (struct monst *) arg;
692 /* TODO: Treat walls, doors, iron bars, pools, lava, etc. specially
693 * rather than just stopping before.
695 if (goodpos(x, y, mon, 0) && m_in_out_region(mon, x, y)) {
696 remove_monster(mon->mx, mon->my);
697 newsym(mon->mx, mon->my);
698 place_monster(mon, x, y);
699 newsym(mon->mx, mon->my);
700 set_apparxy(mon);
701 (void) mintrap(mon);
702 return TRUE;
704 return FALSE;
708 * The player moves through the air for a few squares as a result of
709 * throwing or kicking something.
711 * dx and dy should be the direction of the hurtle, not of the original
712 * kick or throw and be only.
714 void
715 hurtle(dx, dy, range, verbose)
716 int dx, dy, range;
717 boolean verbose;
719 coord uc, cc;
721 /* The chain is stretched vertically, so you shouldn't be able to move
722 * very far diagonally. The premise that you should be able to move one
723 * spot leads to calculations that allow you to only move one spot away
724 * from the ball, if you are levitating over the ball, or one spot
725 * towards the ball, if you are at the end of the chain. Rather than
726 * bother with all of that, assume that there is no slack in the chain
727 * for diagonal movement, give the player a message and return.
729 if (Punished && !carried(uball)) {
730 You_feel("a tug from the iron ball.");
731 nomul(0);
732 return;
733 } else if (u.utrap) {
734 You("are anchored by the %s.",
735 u.utraptype == TT_WEB
736 ? "web"
737 : u.utraptype == TT_LAVA
738 ? hliquid("lava")
739 : u.utraptype == TT_INFLOOR
740 ? surface(u.ux, u.uy)
741 : u.utraptype == TT_BURIEDBALL ? "buried ball"
742 : "trap");
743 nomul(0);
744 return;
747 /* make sure dx and dy are [-1,0,1] */
748 dx = sgn(dx);
749 dy = sgn(dy);
751 if (!range || (!dx && !dy) || u.ustuck)
752 return; /* paranoia */
754 nomul(-range);
755 multi_reason = "moving through the air";
756 nomovemsg = ""; /* it just happens */
757 if (verbose)
758 You("%s in the opposite direction.", range > 1 ? "hurtle" : "float");
759 /* if we're in the midst of shooting multiple projectiles, stop */
760 endmultishot(TRUE);
761 sokoban_guilt();
762 uc.x = u.ux;
763 uc.y = u.uy;
764 /* this setting of cc is only correct if dx and dy are [-1,0,1] only */
765 cc.x = u.ux + (dx * range);
766 cc.y = u.uy + (dy * range);
767 (void) walk_path(&uc, &cc, hurtle_step, (genericptr_t) &range);
770 /* Move a monster through the air for a few squares.
772 void
773 mhurtle(mon, dx, dy, range)
774 struct monst *mon;
775 int dx, dy, range;
777 coord mc, cc;
779 /* At the very least, debilitate the monster */
780 mon->movement = 0;
781 mon->mstun = 1;
783 /* Is the monster stuck or too heavy to push?
784 * (very large monsters have too much inertia, even floaters and flyers)
786 if (mon->data->msize >= MZ_HUGE || mon == u.ustuck || mon->mtrapped)
787 return;
789 /* Make sure dx and dy are [-1,0,1] */
790 dx = sgn(dx);
791 dy = sgn(dy);
792 if (!range || (!dx && !dy))
793 return; /* paranoia */
794 /* don't let grid bugs be hurtled diagonally */
795 if (dx && dy && NODIAG(monsndx(mon->data)))
796 return;
798 /* Send the monster along the path */
799 mc.x = mon->mx;
800 mc.y = mon->my;
801 cc.x = mon->mx + (dx * range);
802 cc.y = mon->my + (dy * range);
803 (void) walk_path(&mc, &cc, mhurtle_step, (genericptr_t) mon);
804 return;
807 STATIC_OVL void
808 check_shop_obj(obj, x, y, broken)
809 struct obj *obj;
810 xchar x, y;
811 boolean broken;
813 struct monst *shkp = shop_keeper(*u.ushops);
815 if (!shkp)
816 return;
818 if (broken || !costly_spot(x, y)
819 || *in_rooms(x, y, SHOPBASE) != *u.ushops) {
820 /* thrown out of a shop or into a different shop */
821 if (is_unpaid(obj))
822 (void) stolen_value(obj, u.ux, u.uy, (boolean) shkp->mpeaceful,
823 FALSE);
824 if (broken)
825 obj->no_charge = 1;
826 } else {
827 if (costly_spot(u.ux, u.uy) && costly_spot(x, y)) {
828 if (is_unpaid(obj))
829 subfrombill(obj, shkp);
830 else if (x != shkp->mx || y != shkp->my)
831 sellobj(obj, x, y);
837 * Hero tosses an object upwards with appropriate consequences.
839 * Returns FALSE if the object is gone.
841 STATIC_OVL boolean
842 toss_up(obj, hitsroof)
843 struct obj *obj;
844 boolean hitsroof;
846 const char *action;
847 boolean petrifier = ((obj->otyp == EGG || obj->otyp == CORPSE)
848 && touch_petrifies(&mons[obj->corpsenm]));
849 /* note: obj->quan == 1 */
851 if (!has_ceiling(&u.uz)) {
852 action = "flies up into"; /* into "the sky" or "the water above" */
853 } else if (hitsroof) {
854 if (breaktest(obj)) {
855 pline("%s hits the %s.", Doname2(obj), ceiling(u.ux, u.uy));
856 breakmsg(obj, !Blind);
857 breakobj(obj, u.ux, u.uy, TRUE, TRUE);
858 return FALSE;
860 action = "hits";
861 } else {
862 action = "almost hits";
864 pline("%s %s the %s, then falls back on top of your %s.", Doname2(obj),
865 action, ceiling(u.ux, u.uy), body_part(HEAD));
867 /* object now hits you */
869 if (obj->oclass == POTION_CLASS) {
870 potionhit(&youmonst, obj, TRUE);
871 } else if (breaktest(obj)) {
872 int otyp = obj->otyp;
873 int blindinc;
875 /* need to check for blindness result prior to destroying obj */
876 blindinc = ((otyp == CREAM_PIE || otyp == BLINDING_VENOM)
877 /* AT_WEAP is ok here even if attack type was AT_SPIT */
878 && can_blnd(&youmonst, &youmonst, AT_WEAP, obj))
879 ? rnd(25)
880 : 0;
881 breakmsg(obj, !Blind);
882 breakobj(obj, u.ux, u.uy, TRUE, TRUE);
883 obj = 0; /* it's now gone */
884 switch (otyp) {
885 case EGG:
886 if (petrifier && !Stone_resistance
887 && !(poly_when_stoned(youmonst.data)
888 && polymon(PM_STONE_GOLEM))) {
889 /* egg ends up "all over your face"; perhaps
890 visored helmet should still save you here */
891 if (uarmh)
892 Your("%s fails to protect you.", helm_simple_name(uarmh));
893 goto petrify;
895 case CREAM_PIE:
896 case BLINDING_VENOM:
897 pline("You've got it all over your %s!", body_part(FACE));
898 if (blindinc) {
899 if (otyp == BLINDING_VENOM && !Blind)
900 pline("It blinds you!");
901 u.ucreamed += blindinc;
902 make_blinded(Blinded + (long) blindinc, FALSE);
903 if (!Blind)
904 Your1(vision_clears);
906 break;
907 default:
908 break;
910 return FALSE;
911 } else { /* neither potion nor other breaking object */
912 boolean less_damage = uarmh && is_metallic(uarmh), artimsg = FALSE;
913 int dmg = dmgval(obj, &youmonst);
915 if (obj->oartifact)
916 /* need a fake die roll here; rn1(18,2) avoids 1 and 20 */
917 artimsg = artifact_hit((struct monst *) 0, &youmonst, obj, &dmg,
918 rn1(18, 2));
920 if (!dmg) { /* probably wasn't a weapon; base damage on weight */
921 dmg = (int) obj->owt / 100;
922 if (dmg < 1)
923 dmg = 1;
924 else if (dmg > 6)
925 dmg = 6;
926 if (youmonst.data == &mons[PM_SHADE]
927 && objects[obj->otyp].oc_material != SILVER)
928 dmg = 0;
930 if (dmg > 1 && less_damage)
931 dmg = 1;
932 if (dmg > 0)
933 dmg += u.udaminc;
934 if (dmg < 0)
935 dmg = 0; /* beware negative rings of increase damage */
936 dmg = Maybe_Half_Phys(dmg);
938 if (uarmh) {
939 if (less_damage && dmg < (Upolyd ? u.mh : u.uhp)) {
940 if (!artimsg)
941 pline("Fortunately, you are wearing a hard helmet.");
942 /* helmet definitely protects you when it blocks petrification
944 } else if (!petrifier) {
945 if (flags.verbose)
946 Your("%s does not protect you.", helm_simple_name(uarmh));
948 } else if (petrifier && !Stone_resistance
949 && !(poly_when_stoned(youmonst.data)
950 && polymon(PM_STONE_GOLEM))) {
951 petrify:
952 killer.format = KILLED_BY;
953 Strcpy(killer.name, "elementary physics"); /* "what goes up..." */
954 You("turn to stone.");
955 if (obj)
956 dropy(obj); /* bypass most of hitfloor() */
957 thrownobj = 0; /* now either gone or on floor */
958 done(STONING);
959 return obj ? TRUE : FALSE;
961 hitfloor(obj);
962 thrownobj = 0;
963 losehp(Maybe_Half_Phys(dmg), "falling object", KILLED_BY_AN);
965 return TRUE;
968 /* return true for weapon meant to be thrown; excludes ammo */
969 boolean
970 throwing_weapon(obj)
971 struct obj *obj;
973 return (boolean) (is_missile(obj) || is_spear(obj)
974 /* daggers and knife (excludes scalpel) */
975 || (is_blade(obj) && !is_sword(obj)
976 && (objects[obj->otyp].oc_dir & PIERCE))
977 /* special cases [might want to add AXE] */
978 || obj->otyp == WAR_HAMMER || obj->otyp == AKLYS);
981 /* the currently thrown object is returning to you (not for boomerangs) */
982 STATIC_OVL void
983 sho_obj_return_to_u(obj)
984 struct obj *obj;
986 /* might already be our location (bounced off a wall) */
987 if (bhitpos.x != u.ux || bhitpos.y != u.uy) {
988 int x = bhitpos.x - u.dx, y = bhitpos.y - u.dy;
990 tmp_at(DISP_FLASH, obj_to_glyph(obj));
991 while (x != u.ux || y != u.uy) {
992 tmp_at(x, y);
993 delay_output();
994 x -= u.dx;
995 y -= u.dy;
997 tmp_at(DISP_END, 0);
1001 /* throw an object, NB: obj may be consumed in the process */
1002 void
1003 throwit(obj, wep_mask, twoweap)
1004 struct obj *obj;
1005 long wep_mask; /* used to re-equip returning boomerang */
1006 boolean
1007 twoweap; /* used to restore twoweapon mode if wielded weapon returns */
1009 register struct monst *mon;
1010 register int range, urange;
1011 boolean crossbowing, impaired = (Confusion || Stunned || Blind
1012 || Hallucination || Fumbling);
1014 notonhead = FALSE; /* reset potentially stale value */
1015 if ((obj->cursed || obj->greased) && (u.dx || u.dy) && !rn2(7)) {
1016 boolean slipok = TRUE;
1017 if (ammo_and_launcher(obj, uwep))
1018 pline("%s!", Tobjnam(obj, "misfire"));
1019 else {
1020 /* only slip if it's greased or meant to be thrown */
1021 if (obj->greased || throwing_weapon(obj))
1022 /* BUG: this message is grammatically incorrect if obj has
1023 a plural name; greased gloves or boots for instance. */
1024 pline("%s as you throw it!", Tobjnam(obj, "slip"));
1025 else
1026 slipok = FALSE;
1028 if (slipok) {
1029 u.dx = rn2(3) - 1;
1030 u.dy = rn2(3) - 1;
1031 if (!u.dx && !u.dy)
1032 u.dz = 1;
1033 impaired = TRUE;
1037 if ((u.dx || u.dy || (u.dz < 1))
1038 && calc_capacity((int) obj->owt) > SLT_ENCUMBER
1039 && (Upolyd ? (u.mh < 5 && u.mh != u.mhmax)
1040 : (u.uhp < 10 && u.uhp != u.uhpmax))
1041 && obj->owt > (unsigned) ((Upolyd ? u.mh : u.uhp) * 2)
1042 && !Is_airlevel(&u.uz)) {
1043 You("have so little stamina, %s drops from your grasp.",
1044 the(xname(obj)));
1045 exercise(A_CON, FALSE);
1046 u.dx = u.dy = 0;
1047 u.dz = 1;
1050 thrownobj = obj;
1051 thrownobj->was_thrown = 1;
1053 if (u.uswallow) {
1054 mon = u.ustuck;
1055 bhitpos.x = mon->mx;
1056 bhitpos.y = mon->my;
1057 } else if (u.dz) {
1058 if (u.dz < 0 && Role_if(PM_VALKYRIE) && obj->oartifact == ART_MJOLLNIR
1059 && !impaired) {
1060 pline("%s the %s and returns to your hand!", Tobjnam(obj, "hit"),
1061 ceiling(u.ux, u.uy));
1062 obj = addinv(obj);
1063 (void) encumber_msg();
1064 setuwep(obj);
1065 u.twoweap = twoweap;
1066 } else if (u.dz < 0) {
1067 (void) toss_up(obj, rn2(5) && !Underwater);
1068 } else if (u.dz > 0 && u.usteed && obj->oclass == POTION_CLASS
1069 && rn2(6)) {
1070 /* alternative to prayer or wand of opening/spell of knock
1071 for dealing with cursed saddle: throw holy water > */
1072 potionhit(u.usteed, obj, TRUE);
1073 } else {
1074 hitfloor(obj);
1076 thrownobj = (struct obj *) 0;
1077 return;
1079 } else if (obj->otyp == BOOMERANG && !Underwater) {
1080 if (Is_airlevel(&u.uz) || Levitation)
1081 hurtle(-u.dx, -u.dy, 1, TRUE);
1082 mon = boomhit(obj, u.dx, u.dy);
1083 if (mon == &youmonst) { /* the thing was caught */
1084 exercise(A_DEX, TRUE);
1085 obj = addinv(obj);
1086 (void) encumber_msg();
1087 if (wep_mask && !(obj->owornmask & wep_mask)) {
1088 setworn(obj, wep_mask);
1089 u.twoweap = twoweap;
1091 thrownobj = (struct obj *) 0;
1092 return;
1094 } else {
1095 /* crossbow range is independent of strength */
1096 crossbowing =
1097 (ammo_and_launcher(obj, uwep) && weapon_type(uwep) == P_CROSSBOW);
1098 urange = (crossbowing ? 18 : (int) ACURRSTR) / 2;
1099 /* balls are easy to throw or at least roll;
1100 * also, this insures the maximum range of a ball is greater
1101 * than 1, so the effects from throwing attached balls are
1102 * actually possible
1104 if (obj->otyp == HEAVY_IRON_BALL)
1105 range = urange - (int) (obj->owt / 100);
1106 else
1107 range = urange - (int) (obj->owt / 40);
1108 if (obj == uball) {
1109 if (u.ustuck)
1110 range = 1;
1111 else if (range >= 5)
1112 range = 5;
1114 if (range < 1)
1115 range = 1;
1117 if (is_ammo(obj)) {
1118 if (ammo_and_launcher(obj, uwep)) {
1119 if (crossbowing)
1120 range = BOLT_LIM;
1121 else
1122 range++;
1123 } else if (obj->oclass != GEM_CLASS)
1124 range /= 2;
1127 if (Is_airlevel(&u.uz) || Levitation) {
1128 /* action, reaction... */
1129 urange -= range;
1130 if (urange < 1)
1131 urange = 1;
1132 range -= urange;
1133 if (range < 1)
1134 range = 1;
1137 if (obj->otyp == BOULDER)
1138 range = 20; /* you must be giant */
1139 else if (obj->oartifact == ART_MJOLLNIR)
1140 range = (range + 1) / 2; /* it's heavy */
1141 else if (obj == uball && u.utrap && u.utraptype == TT_INFLOOR)
1142 range = 1;
1144 if (Underwater)
1145 range = 1;
1147 mon = bhit(u.dx, u.dy, range, THROWN_WEAPON,
1148 (int FDECL((*), (MONST_P, OBJ_P))) 0,
1149 (int FDECL((*), (OBJ_P, OBJ_P))) 0, &obj);
1150 thrownobj = obj; /* obj may be null now */
1152 /* have to do this after bhit() so u.ux & u.uy are correct */
1153 if (Is_airlevel(&u.uz) || Levitation)
1154 hurtle(-u.dx, -u.dy, urange, TRUE);
1156 if (!obj)
1157 return;
1160 if (mon) {
1161 boolean obj_gone;
1163 if (mon->isshk && obj->where == OBJ_MINVENT && obj->ocarry == mon) {
1164 thrownobj = (struct obj *) 0;
1165 return; /* alert shk caught it */
1167 (void) snuff_candle(obj);
1168 notonhead = (bhitpos.x != mon->mx || bhitpos.y != mon->my);
1169 obj_gone = thitmonst(mon, obj);
1170 /* Monster may have been tamed; this frees old mon */
1171 mon = m_at(bhitpos.x, bhitpos.y);
1173 /* [perhaps this should be moved into thitmonst or hmon] */
1174 if (mon && mon->isshk
1175 && (!inside_shop(u.ux, u.uy)
1176 || !index(in_rooms(mon->mx, mon->my, SHOPBASE), *u.ushops)))
1177 hot_pursuit(mon);
1179 if (obj_gone)
1180 thrownobj = 0;
1183 if (!thrownobj) {
1184 ; /* missile has already been handled */
1185 } else if (u.uswallow) {
1186 /* ball is not picked up by monster */
1187 if (obj != uball)
1188 (void) mpickobj(u.ustuck, obj);
1189 thrownobj = (struct obj *) 0;
1190 } else {
1191 /* the code following might become part of dropy() */
1192 if (obj->oartifact == ART_MJOLLNIR && Role_if(PM_VALKYRIE)
1193 && rn2(100)) {
1194 /* we must be wearing Gauntlets of Power to get here */
1195 sho_obj_return_to_u(obj); /* display its flight */
1197 if (!impaired && rn2(100)) {
1198 pline("%s to your hand!", Tobjnam(obj, "return"));
1199 obj = addinv(obj);
1200 (void) encumber_msg();
1201 setuwep(obj);
1202 u.twoweap = twoweap;
1203 if (cansee(bhitpos.x, bhitpos.y))
1204 newsym(bhitpos.x, bhitpos.y);
1205 } else {
1206 int dmg = rn2(2);
1207 if (!dmg) {
1208 pline(Blind ? "%s lands %s your %s."
1209 : "%s back to you, landing %s your %s.",
1210 Blind ? Something : Tobjnam(obj, "return"),
1211 Levitation ? "beneath" : "at",
1212 makeplural(body_part(FOOT)));
1213 } else {
1214 dmg += rnd(3);
1215 pline(Blind ? "%s your %s!"
1216 : "%s back toward you, hitting your %s!",
1217 Tobjnam(obj, Blind ? "hit" : "fly"),
1218 body_part(ARM));
1219 (void) artifact_hit((struct monst *) 0, &youmonst, obj,
1220 &dmg, 0);
1221 losehp(Maybe_Half_Phys(dmg), killer_xname(obj),
1222 KILLED_BY);
1224 if (ship_object(obj, u.ux, u.uy, FALSE)) {
1225 thrownobj = (struct obj *) 0;
1226 return;
1228 dropy(obj);
1230 thrownobj = (struct obj *) 0;
1231 return;
1234 if (!IS_SOFT(levl[bhitpos.x][bhitpos.y].typ) && breaktest(obj)) {
1235 tmp_at(DISP_FLASH, obj_to_glyph(obj));
1236 tmp_at(bhitpos.x, bhitpos.y);
1237 delay_output();
1238 tmp_at(DISP_END, 0);
1239 breakmsg(obj, cansee(bhitpos.x, bhitpos.y));
1240 breakobj(obj, bhitpos.x, bhitpos.y, TRUE, TRUE);
1241 thrownobj = (struct obj *) 0;
1242 return;
1244 if (flooreffects(obj, bhitpos.x, bhitpos.y, "fall")) {
1245 thrownobj = (struct obj *) 0;
1246 return;
1248 obj_no_longer_held(obj);
1249 if (mon && mon->isshk && is_pick(obj)) {
1250 if (cansee(bhitpos.x, bhitpos.y))
1251 pline("%s snatches up %s.", Monnam(mon), the(xname(obj)));
1252 if (*u.ushops || obj->unpaid)
1253 check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE);
1254 (void) mpickobj(mon, obj); /* may merge and free obj */
1255 thrownobj = (struct obj *) 0;
1256 return;
1258 (void) snuff_candle(obj);
1259 if (!mon && ship_object(obj, bhitpos.x, bhitpos.y, FALSE)) {
1260 thrownobj = (struct obj *) 0;
1261 return;
1263 thrownobj = (struct obj *) 0;
1264 place_object(obj, bhitpos.x, bhitpos.y);
1265 /* container contents might break;
1266 do so before turning ownership of thrownobj over to shk
1267 (container_impact_dmg handles item already owned by shop) */
1268 if (!IS_SOFT(levl[bhitpos.x][bhitpos.y].typ))
1269 /* <x,y> is spot where you initiated throw, not bhitpos */
1270 container_impact_dmg(obj, u.ux, u.uy);
1271 /* charge for items thrown out of shop;
1272 shk takes possession for items thrown into one */
1273 if ((*u.ushops || obj->unpaid) && obj != uball)
1274 check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE);
1276 stackobj(obj);
1277 if (obj == uball)
1278 drop_ball(bhitpos.x, bhitpos.y);
1279 if (cansee(bhitpos.x, bhitpos.y))
1280 newsym(bhitpos.x, bhitpos.y);
1281 if (obj_sheds_light(obj))
1282 vision_full_recalc = 1;
1286 /* an object may hit a monster; various factors adjust the chance of hitting
1289 omon_adj(mon, obj, mon_notices)
1290 struct monst *mon;
1291 struct obj *obj;
1292 boolean mon_notices;
1294 int tmp = 0;
1296 /* size of target affects the chance of hitting */
1297 tmp += (mon->data->msize - MZ_MEDIUM); /* -2..+5 */
1298 /* sleeping target is more likely to be hit */
1299 if (mon->msleeping) {
1300 tmp += 2;
1301 if (mon_notices)
1302 mon->msleeping = 0;
1304 /* ditto for immobilized target */
1305 if (!mon->mcanmove || !mon->data->mmove) {
1306 tmp += 4;
1307 if (mon_notices && mon->data->mmove && !rn2(10)) {
1308 mon->mcanmove = 1;
1309 mon->mfrozen = 0;
1312 /* some objects are more likely to hit than others */
1313 switch (obj->otyp) {
1314 case HEAVY_IRON_BALL:
1315 if (obj != uball)
1316 tmp += 2;
1317 break;
1318 case BOULDER:
1319 tmp += 6;
1320 break;
1321 default:
1322 if (obj->oclass == WEAPON_CLASS || is_weptool(obj)
1323 || obj->oclass == GEM_CLASS)
1324 tmp += hitval(obj, mon);
1325 break;
1327 return tmp;
1330 /* thrown object misses target monster */
1331 STATIC_OVL void
1332 tmiss(obj, mon, maybe_wakeup)
1333 struct obj *obj;
1334 struct monst *mon;
1335 boolean maybe_wakeup;
1337 const char *missile = mshot_xname(obj);
1339 /* If the target can't be seen or doesn't look like a valid target,
1340 avoid "the arrow misses it," or worse, "the arrows misses the mimic."
1341 An attentive player will still notice that this is different from
1342 an arrow just landing short of any target (no message in that case),
1343 so will realize that there is a valid target here anyway. */
1344 if (!canseemon(mon) || (mon->m_ap_type && mon->m_ap_type != M_AP_MONSTER))
1345 pline("%s %s.", The(missile), otense(obj, "miss"));
1346 else
1347 miss(missile, mon);
1348 if (maybe_wakeup && !rn2(3))
1349 wakeup(mon);
1350 return;
1353 #define quest_arti_hits_leader(obj, mon) \
1354 (obj->oartifact && is_quest_artifact(obj) \
1355 && mon->m_id == quest_status.leader_m_id)
1358 * Object thrown by player arrives at monster's location.
1359 * Return 1 if obj has disappeared or otherwise been taken care of,
1360 * 0 if caller must take care of it.
1361 * Also used for kicked objects and for polearms/grapnel applied at range.
1364 thitmonst(mon, obj)
1365 register struct monst *mon;
1366 register struct obj *obj; /* thrownobj or kickedobj or uwep */
1368 register int tmp; /* Base chance to hit */
1369 register int disttmp; /* distance modifier */
1370 int otyp = obj->otyp, hmode;
1371 boolean guaranteed_hit = (u.uswallow && mon == u.ustuck);
1373 hmode = (obj == uwep) ? HMON_APPLIED
1374 : (obj == kickedobj) ? HMON_KICKED
1375 : HMON_THROWN;
1377 /* Differences from melee weapons:
1379 * Dex still gives a bonus, but strength does not.
1380 * Polymorphed players lacking attacks may still throw.
1381 * There's a base -1 to hit.
1382 * No bonuses for fleeing or stunned targets (they don't dodge
1383 * melee blows as readily, but dodging arrows is hard anyway).
1384 * Not affected by traps, etc.
1385 * Certain items which don't in themselves do damage ignore tmp.
1386 * Distance and monster size affect chance to hit.
1388 tmp = -1 + Luck + find_mac(mon) + u.uhitinc
1389 + maybe_polyd(youmonst.data->mlevel, u.ulevel);
1390 if (ACURR(A_DEX) < 4)
1391 tmp -= 3;
1392 else if (ACURR(A_DEX) < 6)
1393 tmp -= 2;
1394 else if (ACURR(A_DEX) < 8)
1395 tmp -= 1;
1396 else if (ACURR(A_DEX) >= 14)
1397 tmp += (ACURR(A_DEX) - 14);
1399 /* Modify to-hit depending on distance; but keep it sane.
1400 * Polearms get a distance penalty even when wielded; it's
1401 * hard to hit at a distance.
1403 disttmp = 3 - distmin(u.ux, u.uy, mon->mx, mon->my);
1404 if (disttmp < -4)
1405 disttmp = -4;
1406 tmp += disttmp;
1408 /* gloves are a hindrance to proper use of bows */
1409 if (uarmg && uwep && objects[uwep->otyp].oc_skill == P_BOW) {
1410 switch (uarmg->otyp) {
1411 case GAUNTLETS_OF_POWER: /* metal */
1412 tmp -= 2;
1413 break;
1414 case GAUNTLETS_OF_FUMBLING:
1415 tmp -= 3;
1416 break;
1417 case LEATHER_GLOVES:
1418 case GAUNTLETS_OF_DEXTERITY:
1419 break;
1420 default:
1421 impossible("Unknown type of gloves (%d)", uarmg->otyp);
1422 break;
1426 tmp += omon_adj(mon, obj, TRUE);
1427 if (is_orc(mon->data)
1428 && maybe_polyd(is_elf(youmonst.data), Race_if(PM_ELF)))
1429 tmp++;
1430 if (guaranteed_hit) {
1431 tmp += 1000; /* Guaranteed hit */
1434 if (obj->oclass == GEM_CLASS && is_unicorn(mon->data)) {
1435 if (mon->msleeping || !mon->mcanmove) {
1436 tmiss(obj, mon, FALSE);
1437 return 0;
1438 } else if (mon->mtame) {
1439 pline("%s catches and drops %s.", Monnam(mon), the(xname(obj)));
1440 return 0;
1441 } else {
1442 pline("%s catches %s.", Monnam(mon), the(xname(obj)));
1443 return gem_accept(mon, obj);
1447 /* don't make game unwinnable if naive player throws artifact
1448 at leader... (kicked artifact is ok too; HMON_APPLIED could
1449 occur if quest artifact polearm or grapnel ever gets added) */
1450 if (hmode != HMON_APPLIED && quest_arti_hits_leader(obj, mon)) {
1451 /* not wakeup(), which angers non-tame monsters */
1452 mon->msleeping = 0;
1453 mon->mstrategy &= ~STRAT_WAITMASK;
1455 if (mon->mcanmove) {
1456 pline("%s catches %s.", Monnam(mon), the(xname(obj)));
1457 if (mon->mpeaceful) {
1458 boolean next2u = monnear(mon, u.ux, u.uy);
1460 finish_quest(obj); /* acknowledge quest completion */
1461 pline("%s %s %s back to you.", Monnam(mon),
1462 (next2u ? "hands" : "tosses"), the(xname(obj)));
1463 if (!next2u)
1464 sho_obj_return_to_u(obj);
1465 obj = addinv(obj); /* back into your inventory */
1466 (void) encumber_msg();
1467 } else {
1468 /* angry leader caught it and isn't returning it */
1469 if (*u.ushops || obj->unpaid) /* not very likely... */
1470 check_shop_obj(obj, mon->mx, mon->my, FALSE);
1471 (void) mpickobj(mon, obj);
1473 return 1; /* caller doesn't need to place it */
1475 return 0;
1478 if (obj->oclass == WEAPON_CLASS || is_weptool(obj)
1479 || obj->oclass == GEM_CLASS) {
1480 if (hmode == HMON_KICKED) {
1481 /* throwing adjustments and weapon skill bonus don't apply */
1482 tmp -= (is_ammo(obj) ? 5 : 3);
1483 } else if (is_ammo(obj)) {
1484 if (!ammo_and_launcher(obj, uwep)) {
1485 tmp -= 4;
1486 } else {
1487 tmp += uwep->spe - greatest_erosion(uwep);
1488 tmp += weapon_hit_bonus(uwep);
1489 if (uwep->oartifact)
1490 tmp += spec_abon(uwep, mon);
1492 * Elves and Samurais are highly trained w/bows,
1493 * especially their own special types of bow.
1494 * Polymorphing won't make you a bow expert.
1496 if ((Race_if(PM_ELF) || Role_if(PM_SAMURAI))
1497 && (!Upolyd || your_race(youmonst.data))
1498 && objects[uwep->otyp].oc_skill == P_BOW) {
1499 tmp++;
1500 if (Race_if(PM_ELF) && uwep->otyp == ELVEN_BOW)
1501 tmp++;
1502 else if (Role_if(PM_SAMURAI) && uwep->otyp == YUMI)
1503 tmp++;
1506 } else { /* thrown non-ammo or applied polearm/grapnel */
1507 if (otyp == BOOMERANG) /* arbitrary */
1508 tmp += 4;
1509 else if (throwing_weapon(obj)) /* meant to be thrown */
1510 tmp += 2;
1511 else if (obj == thrownobj) /* not meant to be thrown */
1512 tmp -= 2;
1513 /* we know we're dealing with a weapon or weptool handled
1514 by WEAPON_SKILLS once ammo objects have been excluded */
1515 tmp += weapon_hit_bonus(obj);
1518 if (tmp >= rnd(20)) {
1519 boolean wasthrown = (thrownobj != 0);
1521 /* attack hits mon */
1522 if (hmode == HMON_APPLIED)
1523 u.uconduct.weaphit++;
1524 if (hmon(mon, obj, hmode)) { /* mon still alive */
1525 cutworm(mon, bhitpos.x, bhitpos.y, obj);
1527 exercise(A_DEX, TRUE);
1528 /* if hero was swallowed and projectile killed the engulfer,
1529 'obj' got added to engulfer's inventory and then dropped,
1530 so we can't safely use that pointer anymore; it escapes
1531 the chance to be used up here... */
1532 if (wasthrown && !thrownobj)
1533 return 1;
1535 /* projectiles other than magic stones
1536 sometimes disappear when thrown */
1537 if (objects[otyp].oc_skill < P_NONE
1538 && objects[otyp].oc_skill > -P_BOOMERANG
1539 && !objects[otyp].oc_magic) {
1540 /* we were breaking 2/3 of everything unconditionally.
1541 * we still don't want anything to survive unconditionally,
1542 * but we need ammo to stay around longer on average.
1544 int broken, chance;
1546 chance = 3 + greatest_erosion(obj) - obj->spe;
1547 if (chance > 1)
1548 broken = rn2(chance);
1549 else
1550 broken = !rn2(4);
1551 if (obj->blessed && !rnl(4))
1552 broken = 0;
1554 if (broken) {
1555 if (*u.ushops || obj->unpaid)
1556 check_shop_obj(obj, bhitpos.x, bhitpos.y, TRUE);
1557 obfree(obj, (struct obj *) 0);
1558 return 1;
1561 passive_obj(mon, obj, (struct attack *) 0);
1562 } else {
1563 tmiss(obj, mon, TRUE);
1564 if (hmode == HMON_APPLIED)
1565 wakeup(mon);
1568 } else if (otyp == HEAVY_IRON_BALL) {
1569 exercise(A_STR, TRUE);
1570 if (tmp >= rnd(20)) {
1571 int was_swallowed = guaranteed_hit;
1573 exercise(A_DEX, TRUE);
1574 if (!hmon(mon, obj, hmode)) { /* mon killed */
1575 if (was_swallowed && !u.uswallow && obj == uball)
1576 return 1; /* already did placebc() */
1578 } else {
1579 tmiss(obj, mon, TRUE);
1582 } else if (otyp == BOULDER) {
1583 exercise(A_STR, TRUE);
1584 if (tmp >= rnd(20)) {
1585 exercise(A_DEX, TRUE);
1586 (void) hmon(mon, obj, hmode);
1587 } else {
1588 tmiss(obj, mon, TRUE);
1591 } else if ((otyp == EGG || otyp == CREAM_PIE || otyp == BLINDING_VENOM
1592 || otyp == ACID_VENOM)
1593 && (guaranteed_hit || ACURR(A_DEX) > rnd(25))) {
1594 (void) hmon(mon, obj, hmode);
1595 return 1; /* hmon used it up */
1597 } else if (obj->oclass == POTION_CLASS
1598 && (guaranteed_hit || ACURR(A_DEX) > rnd(25))) {
1599 potionhit(mon, obj, TRUE);
1600 return 1;
1602 } else if (befriend_with_obj(mon->data, obj)
1603 || (mon->mtame && dogfood(mon, obj) <= ACCFOOD)) {
1604 if (tamedog(mon, obj)) {
1605 return 1; /* obj is gone */
1606 } else {
1607 tmiss(obj, mon, FALSE);
1608 mon->msleeping = 0;
1609 mon->mstrategy &= ~STRAT_WAITMASK;
1611 } else if (guaranteed_hit) {
1612 /* this assumes that guaranteed_hit is due to swallowing */
1613 wakeup(mon);
1614 if (obj->otyp == CORPSE && touch_petrifies(&mons[obj->corpsenm])) {
1615 if (is_animal(u.ustuck->data)) {
1616 minstapetrify(u.ustuck, TRUE);
1617 /* Don't leave a cockatrice corpse available in a statue */
1618 if (!u.uswallow) {
1619 delobj(obj);
1620 return 1;
1624 pline("%s into %s %s.", Tobjnam(obj, "vanish"),
1625 s_suffix(mon_nam(mon)),
1626 is_animal(u.ustuck->data) ? "entrails" : "currents");
1627 } else {
1628 tmiss(obj, mon, TRUE);
1631 return 0;
1634 STATIC_OVL int
1635 gem_accept(mon, obj)
1636 register struct monst *mon;
1637 register struct obj *obj;
1639 char buf[BUFSZ];
1640 boolean is_buddy = sgn(mon->data->maligntyp) == sgn(u.ualign.type);
1641 boolean is_gem = objects[obj->otyp].oc_material == GEMSTONE;
1642 int ret = 0;
1643 static NEARDATA const char nogood[] = " is not interested in your junk.";
1644 static NEARDATA const char acceptgift[] = " accepts your gift.";
1645 static NEARDATA const char maybeluck[] = " hesitatingly";
1646 static NEARDATA const char noluck[] = " graciously";
1647 static NEARDATA const char addluck[] = " gratefully";
1649 Strcpy(buf, Monnam(mon));
1650 mon->mpeaceful = 1;
1651 mon->mavenge = 0;
1653 /* object properly identified */
1654 if (obj->dknown && objects[obj->otyp].oc_name_known) {
1655 if (is_gem) {
1656 if (is_buddy) {
1657 Strcat(buf, addluck);
1658 change_luck(5);
1659 } else {
1660 Strcat(buf, maybeluck);
1661 change_luck(rn2(7) - 3);
1663 } else {
1664 Strcat(buf, nogood);
1665 goto nopick;
1667 /* making guesses */
1668 } else if (has_oname(obj) || objects[obj->otyp].oc_uname) {
1669 if (is_gem) {
1670 if (is_buddy) {
1671 Strcat(buf, addluck);
1672 change_luck(2);
1673 } else {
1674 Strcat(buf, maybeluck);
1675 change_luck(rn2(3) - 1);
1677 } else {
1678 Strcat(buf, nogood);
1679 goto nopick;
1681 /* value completely unknown to @ */
1682 } else {
1683 if (is_gem) {
1684 if (is_buddy) {
1685 Strcat(buf, addluck);
1686 change_luck(1);
1687 } else {
1688 Strcat(buf, maybeluck);
1689 change_luck(rn2(3) - 1);
1691 } else {
1692 Strcat(buf, noluck);
1695 Strcat(buf, acceptgift);
1696 if (*u.ushops || obj->unpaid)
1697 check_shop_obj(obj, mon->mx, mon->my, TRUE);
1698 (void) mpickobj(mon, obj); /* may merge and free obj */
1699 ret = 1;
1701 nopick:
1702 if (!Blind)
1703 pline1(buf);
1704 if (!tele_restrict(mon))
1705 (void) rloc(mon, TRUE);
1706 return ret;
1710 * Comments about the restructuring of the old breaks() routine.
1712 * There are now three distinct phases to object breaking:
1713 * breaktest() - which makes the check/decision about whether the
1714 * object is going to break.
1715 * breakmsg() - which outputs a message about the breakage,
1716 * appropriate for that particular object. Should
1717 * only be called after a positive breaktest().
1718 * on the object and, if it going to be called,
1719 * it must be called before calling breakobj().
1720 * Calling breakmsg() is optional.
1721 * breakobj() - which actually does the breakage and the side-effects
1722 * of breaking that particular object. This should
1723 * only be called after a positive breaktest() on the
1724 * object.
1726 * Each of the above routines is currently static to this source module.
1727 * There are two routines callable from outside this source module which
1728 * perform the routines above in the correct sequence.
1730 * hero_breaks() - called when an object is to be broken as a result
1731 * of something that the hero has done. (throwing it,
1732 * kicking it, etc.)
1733 * breaks() - called when an object is to be broken for some
1734 * reason other than the hero doing something to it.
1738 * The hero causes breakage of an object (throwing, dropping it, etc.)
1739 * Return 0 if the object didn't break, 1 if the object broke.
1742 hero_breaks(obj, x, y, from_invent)
1743 struct obj *obj;
1744 xchar x, y; /* object location (ox, oy may not be right) */
1745 boolean from_invent; /* thrown or dropped by player; maybe on shop bill */
1747 boolean in_view = Blind ? FALSE : (from_invent || cansee(x, y));
1748 if (!breaktest(obj))
1749 return 0;
1750 breakmsg(obj, in_view);
1751 breakobj(obj, x, y, TRUE, from_invent);
1752 return 1;
1756 * The object is going to break for a reason other than the hero doing
1757 * something to it.
1758 * Return 0 if the object doesn't break, 1 if the object broke.
1761 breaks(obj, x, y)
1762 struct obj *obj;
1763 xchar x, y; /* object location (ox, oy may not be right) */
1765 boolean in_view = Blind ? FALSE : cansee(x, y);
1767 if (!breaktest(obj))
1768 return 0;
1769 breakmsg(obj, in_view);
1770 breakobj(obj, x, y, FALSE, FALSE);
1771 return 1;
1774 void
1775 release_camera_demon(obj, x, y)
1776 struct obj *obj;
1777 xchar x, y;
1779 struct monst *mtmp;
1780 if (!rn2(3)
1781 && (mtmp = makemon(&mons[rn2(3) ? PM_HOMUNCULUS : PM_IMP], x, y,
1782 NO_MM_FLAGS)) != 0) {
1783 if (canspotmon(mtmp))
1784 pline("%s is released!", Hallucination
1785 ? An(rndmonnam(NULL))
1786 : "The picture-painting demon");
1787 mtmp->mpeaceful = !obj->cursed;
1788 set_malign(mtmp);
1793 * Unconditionally break an object. Assumes all resistance checks
1794 * and break messages have been delivered prior to getting here.
1796 void
1797 breakobj(obj, x, y, hero_caused, from_invent)
1798 struct obj *obj;
1799 xchar x, y; /* object location (ox, oy may not be right) */
1800 boolean hero_caused; /* is this the hero's fault? */
1801 boolean from_invent;
1803 boolean fracture = FALSE;
1805 switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) {
1806 case MIRROR:
1807 if (hero_caused)
1808 change_luck(-2);
1809 break;
1810 case POT_WATER: /* really, all potions */
1811 obj->in_use = 1; /* in case it's fatal */
1812 if (obj->otyp == POT_OIL && obj->lamplit) {
1813 explode_oil(obj, x, y);
1814 } else if (distu(x, y) <= 2) {
1815 if (!breathless(youmonst.data) || haseyes(youmonst.data)) {
1816 if (obj->otyp != POT_WATER) {
1817 if (!breathless(youmonst.data)) {
1818 /* [what about "familiar odor" when known?] */
1819 You("smell a peculiar odor...");
1820 } else {
1821 const char *eyes = body_part(EYE);
1823 if (eyecount(youmonst.data) != 1)
1824 eyes = makeplural(eyes);
1825 Your("%s %s.", eyes, vtense(eyes, "water"));
1828 potionbreathe(obj);
1831 /* monster breathing isn't handled... [yet?] */
1832 break;
1833 case EXPENSIVE_CAMERA:
1834 release_camera_demon(obj, x, y);
1835 break;
1836 case EGG:
1837 /* breaking your own eggs is bad luck */
1838 if (hero_caused && obj->spe && obj->corpsenm >= LOW_PM)
1839 change_luck((schar) -min(obj->quan, 5L));
1840 break;
1841 case BOULDER:
1842 case STATUE:
1843 /* caller will handle object disposition;
1844 we're just doing the shop theft handling */
1845 fracture = TRUE;
1846 break;
1847 default:
1848 break;
1851 if (hero_caused) {
1852 if (from_invent || obj->unpaid) {
1853 if (*u.ushops || obj->unpaid)
1854 check_shop_obj(obj, x, y, TRUE);
1855 } else if (!obj->no_charge && costly_spot(x, y)) {
1856 /* it is assumed that the obj is a floor-object */
1857 char *o_shop = in_rooms(x, y, SHOPBASE);
1858 struct monst *shkp = shop_keeper(*o_shop);
1860 if (shkp) { /* (implies *o_shop != '\0') */
1861 static NEARDATA long lastmovetime = 0L;
1862 static NEARDATA boolean peaceful_shk = FALSE;
1863 /* We want to base shk actions on her peacefulness
1864 at start of this turn, so that "simultaneous"
1865 multiple breakage isn't drastically worse than
1866 single breakage. (ought to be done via ESHK) */
1867 if (moves != lastmovetime)
1868 peaceful_shk = shkp->mpeaceful;
1869 if (stolen_value(obj, x, y, peaceful_shk, FALSE) > 0L
1870 && (*o_shop != u.ushops[0] || !inside_shop(u.ux, u.uy))
1871 && moves != lastmovetime)
1872 make_angry_shk(shkp, x, y);
1873 lastmovetime = moves;
1877 if (!fracture)
1878 delobj(obj);
1882 * Check to see if obj is going to break, but don't actually break it.
1883 * Return 0 if the object isn't going to break, 1 if it is.
1885 boolean
1886 breaktest(obj)
1887 struct obj *obj;
1889 if (obj_resists(obj, 1, 99))
1890 return 0;
1891 if (objects[obj->otyp].oc_material == GLASS && !obj->oartifact
1892 && obj->oclass != GEM_CLASS)
1893 return 1;
1894 switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) {
1895 case EXPENSIVE_CAMERA:
1896 case POT_WATER: /* really, all potions */
1897 case EGG:
1898 case CREAM_PIE:
1899 case MELON:
1900 case ACID_VENOM:
1901 case BLINDING_VENOM:
1902 return 1;
1903 default:
1904 return 0;
1908 STATIC_OVL void
1909 breakmsg(obj, in_view)
1910 struct obj *obj;
1911 boolean in_view;
1913 const char *to_pieces;
1915 to_pieces = "";
1916 switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) {
1917 default: /* glass or crystal wand */
1918 if (obj->oclass != WAND_CLASS)
1919 impossible("breaking odd object?");
1920 case CRYSTAL_PLATE_MAIL:
1921 case LENSES:
1922 case MIRROR:
1923 case CRYSTAL_BALL:
1924 case EXPENSIVE_CAMERA:
1925 to_pieces = " into a thousand pieces";
1926 /*FALLTHRU*/
1927 case POT_WATER: /* really, all potions */
1928 if (!in_view)
1929 You_hear("%s shatter!", something);
1930 else
1931 pline("%s shatter%s%s!", Doname2(obj),
1932 (obj->quan == 1L) ? "s" : "", to_pieces);
1933 break;
1934 case EGG:
1935 case MELON:
1936 pline("Splat!");
1937 break;
1938 case CREAM_PIE:
1939 if (in_view)
1940 pline("What a mess!");
1941 break;
1942 case ACID_VENOM:
1943 case BLINDING_VENOM:
1944 pline("Splash!");
1945 break;
1949 STATIC_OVL int
1950 throw_gold(obj)
1951 struct obj *obj;
1953 int range, odx, ody;
1954 register struct monst *mon;
1956 if (!u.dx && !u.dy && !u.dz) {
1957 You("cannot throw gold at yourself.");
1958 return 0;
1960 freeinv(obj);
1961 if (u.uswallow) {
1962 pline(is_animal(u.ustuck->data) ? "%s in the %s's entrails."
1963 : "%s into %s.",
1964 "The money disappears", mon_nam(u.ustuck));
1965 add_to_minv(u.ustuck, obj);
1966 return 1;
1969 if (u.dz) {
1970 if (u.dz < 0 && !Is_airlevel(&u.uz) && !Underwater
1971 && !Is_waterlevel(&u.uz)) {
1972 pline_The("gold hits the %s, then falls back on top of your %s.",
1973 ceiling(u.ux, u.uy), body_part(HEAD));
1974 /* some self damage? */
1975 if (uarmh)
1976 pline("Fortunately, you are wearing %s!",
1977 an(helm_simple_name(uarmh)));
1979 bhitpos.x = u.ux;
1980 bhitpos.y = u.uy;
1981 } else {
1982 /* consistent with range for normal objects */
1983 range = (int) ((ACURRSTR) / 2 - obj->owt / 40);
1985 /* see if the gold has a place to move into */
1986 odx = u.ux + u.dx;
1987 ody = u.uy + u.dy;
1988 if (!ZAP_POS(levl[odx][ody].typ) || closed_door(odx, ody)) {
1989 bhitpos.x = u.ux;
1990 bhitpos.y = u.uy;
1991 } else {
1992 mon = bhit(u.dx, u.dy, range, THROWN_WEAPON,
1993 (int FDECL((*), (MONST_P, OBJ_P))) 0,
1994 (int FDECL((*), (OBJ_P, OBJ_P))) 0, &obj);
1995 if (!obj)
1996 return 1; /* object is gone */
1997 if (mon) {
1998 if (ghitm(mon, obj)) /* was it caught? */
1999 return 1;
2000 } else {
2001 if (ship_object(obj, bhitpos.x, bhitpos.y, FALSE))
2002 return 1;
2007 if (flooreffects(obj, bhitpos.x, bhitpos.y, "fall"))
2008 return 1;
2009 if (u.dz > 0)
2010 pline_The("gold hits the %s.", surface(bhitpos.x, bhitpos.y));
2011 place_object(obj, bhitpos.x, bhitpos.y);
2012 if (*u.ushops)
2013 sellobj(obj, bhitpos.x, bhitpos.y);
2014 stackobj(obj);
2015 newsym(bhitpos.x, bhitpos.y);
2016 return 1;
2019 /*dothrow.c*/