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