OSDN Git Service

no E-word
[nethackexpress/trunk.git] / src / dothrow.c
1 /*      SCCS Id: @(#)dothrow.c  3.4     2003/12/04      */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 /* Contains code for 't' (throw) */
6
7 #include "hack.h"
8 #include "edog.h"
9
10 STATIC_DCL int FDECL(throw_obj, (struct obj *,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 *));
14 STATIC_DCL int FDECL(throw_gold, (struct obj *));
15 STATIC_DCL void FDECL(check_shop_obj, (struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P));
16 STATIC_DCL void FDECL(breakobj, (struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P,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 boolean FDECL(throwing_weapon, (struct obj *));
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
24 static NEARDATA const char toss_objs[] =
25         { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, WEAPON_CLASS, 0 };
26 /* different default choices when wielding a sling (gold must be included) */
27 static NEARDATA const char bullets[] =
28         { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, GEM_CLASS, 0 };
29
30 struct obj *thrownobj = 0;      /* tracks an object until it lands */
31
32 extern boolean notonhead;       /* for long worms */
33
34
35 /* Throw the selected object, asking for direction */
36 STATIC_OVL int
37 throw_obj(obj, shotlimit)
38 struct obj *obj;
39 int shotlimit;
40 {
41         struct obj *otmp;
42         int multishot = 1;
43         schar skill;
44         long wep_mask;
45         boolean twoweap;
46
47         /* ask "in what direction?" */
48 #ifndef GOLDOBJ
49         if (!getdir((char *)0)) {
50                 if (obj->oclass == COIN_CLASS) {
51                     u.ugold += obj->quan;
52                     flags.botl = 1;
53                     dealloc_obj(obj);
54                 }
55                 return(0);
56         }
57
58         if(obj->oclass == COIN_CLASS) return(throw_gold(obj));
59 #else
60         if (!getdir((char *)0)) {
61             /* obj might need to be merged back into the singular gold object */
62             freeinv(obj);
63             addinv(obj);
64             return(0);
65         }
66
67         /*
68           Throwing money is usually for getting rid of it when
69           a leprechaun approaches, or for bribing an oncoming 
70           angry monster.  So throw the whole object.
71
72           If the money is in quiver, throw one coin at a time,
73           possibly using a sling.
74         */
75         if(obj->oclass == COIN_CLASS && obj != uquiver) return(throw_gold(obj));
76 #endif
77
78         if(!canletgo(obj,"throw"))
79                 return(0);
80         if (obj->oartifact == ART_MJOLLNIR && obj != uwep) {
81             pline("%s must be wielded before it can be thrown.",
82                 The(xname(obj)));
83                 return(0);
84         }
85         if ((obj->oartifact == ART_MJOLLNIR && ACURR(A_STR) < STR19(25))
86            || (obj->otyp == BOULDER && !throws_rocks(youmonst.data))) {
87                 pline("It's too heavy.");
88                 return(1);
89         }
90         if(!u.dx && !u.dy && !u.dz) {
91                 You("cannot throw an object at yourself.");
92                 return(0);
93         }
94         u_wipe_engr(2);
95         if (!uarmg && !Stone_resistance && (obj->otyp == CORPSE &&
96                     touch_petrifies(&mons[obj->corpsenm]))) {
97                 You("throw the %s corpse with your bare %s.",
98                     mons[obj->corpsenm].mname, body_part(HAND));
99                 Sprintf(killer_buf, "%s corpse", an(mons[obj->corpsenm].mname));
100                 instapetrify(killer_buf);
101         }
102         if (welded(obj)) {
103                 weldmsg(obj);
104                 return 1;
105         }
106
107         /* Multishot calculations
108          */
109         skill = objects[obj->otyp].oc_skill;
110         if ((ammo_and_launcher(obj, uwep) || skill == P_DAGGER ||
111                         skill == -P_DART || skill == -P_SHURIKEN) &&
112                 !(Confusion || Stunned)) {
113             /* Bonus if the player is proficient in this weapon... */
114             switch (P_SKILL(weapon_type(obj))) {
115             default:    break; /* No bonus */
116             case P_SKILLED:     multishot++; break;
117             case P_EXPERT:      multishot += 2; break;
118             }
119             /* ...or is using a special weapon for their role... */
120             switch (Role_switch) {
121             case PM_RANGER:
122                 multishot++;
123                 break;
124             case PM_ROGUE:
125                 if (skill == P_DAGGER) multishot++;
126                 break;
127             case PM_SAMURAI:
128                 if (obj->otyp == YA && uwep && uwep->otyp == YUMI) multishot++;
129                 break;
130             default:
131                 break;  /* No bonus */
132             }
133             /* ...or using their race's special bow */
134             switch (Race_switch) {
135             case PM_ELF:
136                 if (obj->otyp == ELVEN_ARROW && uwep &&
137                                 uwep->otyp == ELVEN_BOW) multishot++;
138                 break;
139             case PM_ORC:
140                 if (obj->otyp == ORCISH_ARROW && uwep &&
141                                 uwep->otyp == ORCISH_BOW) multishot++;
142                 break;
143             default:
144                 break;  /* No bonus */
145             }
146         }
147
148         if ((long)multishot > obj->quan) multishot = (int)obj->quan;
149         multishot = rnd(multishot);
150         if (shotlimit > 0 && multishot > shotlimit) multishot = shotlimit;
151
152         m_shot.s = ammo_and_launcher(obj,uwep) ? TRUE : FALSE;
153         /* give a message if shooting more than one, or if player
154            attempted to specify a count */
155         if (multishot > 1 || shotlimit > 0) {
156             /* "You shoot N arrows." or "You throw N daggers." */
157             You("%s %d %s.",
158                 m_shot.s ? "shoot" : "throw",
159                 multishot,      /* (might be 1 if player gave shotlimit) */
160                 (multishot == 1) ? singular(obj, xname) :  xname(obj));
161         }
162
163         wep_mask = obj->owornmask;
164         m_shot.o = obj->otyp;
165         m_shot.n = multishot;
166         for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
167             twoweap = u.twoweap;
168             /* split this object off from its slot if necessary */
169             if (obj->quan > 1L) {
170                 otmp = splitobj(obj, 1L);
171             } else {
172                 otmp = obj;
173                 if (otmp->owornmask)
174                     remove_worn_item(otmp, FALSE);
175             }
176             freeinv(otmp);
177             throwit(otmp, wep_mask, twoweap);
178         }
179         m_shot.n = m_shot.i = 0;
180         m_shot.o = STRANGE_OBJECT;
181         m_shot.s = FALSE;
182
183         return 1;
184 }
185
186
187 int
188 dothrow()
189 {
190         register struct obj *obj;
191         int shotlimit;
192
193         /*
194          * Since some characters shoot multiple missiles at one time,
195          * allow user to specify a count prefix for 'f' or 't' to limit
196          * number of items thrown (to avoid possibly hitting something
197          * behind target after killing it, or perhaps to conserve ammo).
198          *
199          * Prior to 3.3.0, command ``3t'' meant ``t(shoot) t(shoot) t(shoot)''
200          * and took 3 turns.  Now it means ``t(shoot at most 3 missiles)''.
201          */
202         /* kludge to work around parse()'s pre-decrement of `multi' */
203         shotlimit = (multi || save_cm) ? multi + 1 : 0;
204         multi = 0;              /* reset; it's been used up */
205
206         if (notake(youmonst.data)) {
207             You("are physically incapable of throwing anything.");
208             return 0;
209         }
210
211         if(check_capacity((char *)0)) return(0);
212         obj = getobj(uslinging() ? bullets : toss_objs, "throw");
213         /* it is also possible to throw food */
214         /* (or jewels, or iron balls... ) */
215
216         if (!obj) return(0);
217         return throw_obj(obj, shotlimit);
218 }
219
220
221 /* KMH -- Automatically fill quiver */
222 /* Suggested by Jeffrey Bay <jbay@convex.hp.com> */
223 static void
224 autoquiver()
225 {
226         struct obj *otmp, *oammo = 0, *omissile = 0, *omisc = 0, *altammo = 0;
227
228         if (uquiver)
229             return;
230
231         /* Scan through the inventory */
232         for (otmp = invent; otmp; otmp = otmp->nobj) {
233             if (otmp->owornmask || otmp->oartifact || !otmp->dknown) {
234                 ;       /* Skip it */
235             } else if (otmp->otyp == ROCK ||
236                         /* seen rocks or known flint or known glass */
237                         (objects[otmp->otyp].oc_name_known &&
238                          otmp->otyp == FLINT) ||
239                         (objects[otmp->otyp].oc_name_known &&
240                          otmp->oclass == GEM_CLASS &&
241                          objects[otmp->otyp].oc_material == GLASS)) {
242                 if (uslinging())
243                     oammo = otmp;
244                 else if (ammo_and_launcher(otmp, uswapwep))
245                     altammo = otmp;
246                 else if (!omisc)
247                     omisc = otmp;
248             } else if (otmp->oclass == GEM_CLASS) {
249                 ;       /* skip non-rock gems--they're ammo but
250                            player has to select them explicitly */
251             } else if (is_ammo(otmp)) {
252                 if (ammo_and_launcher(otmp, uwep))
253                     /* Ammo matched with launcher (bow and arrow, crossbow and bolt) */
254                     oammo = otmp;
255                 else if (ammo_and_launcher(otmp, uswapwep))
256                     altammo = otmp;
257                 else
258                     /* Mismatched ammo (no better than an ordinary weapon) */
259                     omisc = otmp;
260             } else if (is_missile(otmp)) {
261                 /* Missile (dart, shuriken, etc.) */
262                 omissile = otmp;
263             } else if (otmp->oclass == WEAPON_CLASS && throwing_weapon(otmp)) {
264                 /* Ordinary weapon */
265                 if (objects[otmp->otyp].oc_skill == P_DAGGER
266                         && !omissile) 
267                     omissile = otmp;
268                 else
269                     omisc = otmp;
270             }
271         }
272
273         /* Pick the best choice */
274         if (oammo)
275             setuqwep(oammo);
276         else if (omissile)
277             setuqwep(omissile);
278         else if (altammo)
279             setuqwep(altammo);
280         else if (omisc)
281             setuqwep(omisc);
282
283         return;
284 }
285
286
287 /* Throw from the quiver */
288 int
289 dofire()
290 {
291         int shotlimit;
292
293         if (notake(youmonst.data)) {
294             You("are physically incapable of doing that.");
295             return 0;
296         }
297
298         if(check_capacity((char *)0)) return(0);
299         if (!uquiver) {
300                 if (!flags.autoquiver) {
301                         /* Don't automatically fill the quiver */
302                         You("have no ammunition readied!");
303                         return(dothrow());
304                 }
305                 autoquiver();
306                 if (!uquiver) {
307                         You("have nothing appropriate for your quiver!");
308                         return(dothrow());
309                 } else {
310                         You("fill your quiver:");
311                         prinv((char *)0, uquiver, 0L);
312                 }
313         }
314
315         /*
316          * Since some characters shoot multiple missiles at one time,
317          * allow user to specify a count prefix for 'f' or 't' to limit
318          * number of items thrown (to avoid possibly hitting something
319          * behind target after killing it, or perhaps to conserve ammo).
320          *
321          * The number specified can never increase the number of missiles.
322          * Using ``5f'' when the shooting skill (plus RNG) dictates launch
323          * of 3 projectiles will result in 3 being shot, not 5.
324          */
325         /* kludge to work around parse()'s pre-decrement of `multi' */
326         shotlimit = (multi || save_cm) ? multi + 1 : 0;
327         multi = 0;              /* reset; it's been used up */
328
329         return throw_obj(uquiver, shotlimit);
330 }
331
332
333 /*
334  * Object hits floor at hero's feet.  Called from drop() and throwit().
335  */
336 void
337 hitfloor(obj)
338 register struct obj *obj;
339 {
340         if (IS_SOFT(levl[u.ux][u.uy].typ) || u.uinwater) {
341                 dropy(obj);
342                 return;
343         }
344         if (IS_ALTAR(levl[u.ux][u.uy].typ))
345                 doaltarobj(obj);
346         else
347                 pline("%s hit%s the %s.", Doname2(obj),
348                       (obj->quan == 1L) ? "s" : "", surface(u.ux,u.uy));
349
350         if (hero_breaks(obj, u.ux, u.uy, TRUE)) return;
351         if (ship_object(obj, u.ux, u.uy, FALSE)) return;
352         dropy(obj);
353         if (!u.uswallow) container_impact_dmg(obj);
354 }
355
356 /*
357  * Walk a path from src_cc to dest_cc, calling a proc for each location
358  * except the starting one.  If the proc returns FALSE, stop walking
359  * and return FALSE.  If stopped early, dest_cc will be the location
360  * before the failed callback.
361  */
362 boolean
363 walk_path(src_cc, dest_cc, check_proc, arg)
364     coord *src_cc;
365     coord *dest_cc;
366     boolean FDECL((*check_proc), (genericptr_t, int, int));
367     genericptr_t arg;
368 {
369     int x, y, dx, dy, x_change, y_change, err, i, prev_x, prev_y;
370     boolean keep_going = TRUE;
371
372     /* Use Bresenham's Line Algorithm to walk from src to dest */
373     dx = dest_cc->x - src_cc->x;
374     dy = dest_cc->y - src_cc->y;
375     prev_x = x = src_cc->x;
376     prev_y = y = src_cc->y;
377
378     if (dx < 0) {
379         x_change = -1;
380         dx = -dx;
381     } else
382         x_change = 1;
383     if (dy < 0) {
384         y_change = -1;
385         dy = -dy;
386     } else
387         y_change = 1;
388
389     i = err = 0;
390     if (dx < dy) {
391         while (i++ < dy) {
392             prev_x = x;
393             prev_y = y;
394             y += y_change;
395             err += dx;
396             if (err >= dy) {
397                 x += x_change;
398                 err -= dy;
399             }
400         /* check for early exit condition */
401         if (!(keep_going = (*check_proc)(arg, x, y)))
402             break;
403         }
404     } else {
405         while (i++ < dx) {
406             prev_x = x;
407             prev_y = y;
408             x += x_change;
409             err += dy;
410             if (err >= dx) {
411                 y += y_change;
412                 err -= dx;
413             }
414         /* check for early exit condition */
415         if (!(keep_going = (*check_proc)(arg, x, y)))
416             break;
417         }
418     }
419
420     if (keep_going)
421         return TRUE;    /* successful */
422
423     dest_cc->x = prev_x;
424     dest_cc->y = prev_y;
425     return FALSE;
426 }
427
428 /*
429  * Single step for the hero flying through the air from jumping, flying,
430  * etc.  Called from hurtle() and jump() via walk_path().  We expect the
431  * argument to be a pointer to an integer -- the range -- which is
432  * used in the calculation of points off if we hit something.
433  *
434  * Bumping into monsters won't cause damage but will wake them and make
435  * them angry.  Auto-pickup isn't done, since you don't have control over
436  * your movements at the time.
437  *
438  * Possible additions/changes:
439  *      o really attack monster if we hit one
440  *      o set stunned if we hit a wall or door
441  *      o reset nomul when we stop
442  *      o creepy feeling if pass through monster (if ever implemented...)
443  *      o bounce off walls
444  *      o let jumps go over boulders
445  */
446 boolean
447 hurtle_step(arg, x, y)
448     genericptr_t arg;
449     int x, y;
450 {
451     int ox, oy, *range = (int *)arg;
452     struct obj *obj;
453     struct monst *mon;
454     boolean may_pass = TRUE;
455     struct trap *ttmp;
456     
457     if (!isok(x,y)) {
458         You_feel("the spirits holding you back.");
459         return FALSE;
460     } else if (!in_out_region(x, y)) {
461         return FALSE;
462     } else if (*range == 0) {
463         return FALSE;                   /* previous step wants to stop now */
464     }
465
466     if (!Passes_walls || !(may_pass = may_passwall(x, y))) {
467         if (IS_ROCK(levl[x][y].typ) || closed_door(x,y)) {
468             const char *s;
469
470             pline("Ouch!");
471             if (IS_TREE(levl[x][y].typ))
472                 s = "bumping into a tree";
473             else if (IS_ROCK(levl[x][y].typ))
474                 s = "bumping into a wall";
475             else
476                 s = "bumping into a door";
477             losehp(rnd(2+*range), s, KILLED_BY);
478             return FALSE;
479         }
480         if (levl[x][y].typ == IRONBARS) {
481             You("crash into some iron bars.  Ouch!");
482             losehp(rnd(2+*range), "crashing into iron bars", KILLED_BY);
483             return FALSE;
484         }
485         if ((obj = sobj_at(BOULDER,x,y)) != 0) {
486             You("bump into a %s.  Ouch!", xname(obj));
487             losehp(rnd(2+*range), "bumping into a boulder", KILLED_BY);
488             return FALSE;
489         }
490         if (!may_pass) {
491             /* did we hit a no-dig non-wall position? */
492             You("smack into something!");
493             losehp(rnd(2+*range), "touching the edge of the universe", KILLED_BY);
494             return FALSE;
495         }
496         if ((u.ux - x) && (u.uy - y) &&
497                 bad_rock(youmonst.data,u.ux,y) && bad_rock(youmonst.data,x,u.uy)) {
498             boolean too_much = (invent && (inv_weight() + weight_cap() > 600));
499             /* Move at a diagonal. */
500             if (bigmonst(youmonst.data) || too_much) {
501                 You("%sget forcefully wedged into a crevice.",
502                         too_much ? "and all your belongings " : "");
503                 losehp(rnd(2+*range), "wedging into a narrow crevice", KILLED_BY);
504                 return FALSE;
505             }
506         }
507     }
508
509     if ((mon = m_at(x, y)) != 0) {
510         You("bump into %s.", a_monnam(mon));
511         wakeup(mon);
512         return FALSE;
513     }
514     if ((u.ux - x) && (u.uy - y) &&
515         bad_rock(youmonst.data,u.ux,y) && bad_rock(youmonst.data,x,u.uy)) {
516         /* Move at a diagonal. */
517         if (In_sokoban(&u.uz)) {
518             You("come to an abrupt halt!");
519             return FALSE;
520         }
521     }
522
523     ox = u.ux;
524     oy = u.uy;
525     u.ux = x;
526     u.uy = y;
527     newsym(ox, oy);             /* update old position */
528     vision_recalc(1);           /* update for new position */
529     flush_screen(1);
530     /* FIXME:
531      * Each trap should really trigger on the recoil if
532      * it would trigger during normal movement. However,
533      * not all the possible side-effects of this are
534      * tested [as of 3.4.0] so we trigger those that
535      * we have tested, and offer a message for the
536      * ones that we have not yet tested.
537      */
538     if ((ttmp = t_at(x, y)) != 0) {
539         if (ttmp->ttyp == MAGIC_PORTAL) {
540                 dotrap(ttmp,0);
541                 return FALSE;
542         } else if (ttmp->ttyp == FIRE_TRAP) {
543                 dotrap(ttmp,0);
544         } else if ((ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT ||
545                     ttmp->ttyp == HOLE || ttmp->ttyp == TRAPDOOR) &&
546                    In_sokoban(&u.uz)) {
547                 /* Air currents overcome the recoil */
548                 dotrap(ttmp,0);
549                 *range = 0;
550                 return TRUE;
551         } else {
552                 if (ttmp->tseen)
553                     You("pass right over %s %s.",
554                         (ttmp->ttyp == ARROW_TRAP) ? "an" : "a",
555                         defsyms[trap_to_defsym(ttmp->ttyp)].explanation);
556         }
557     }
558     if (--*range < 0)           /* make sure our range never goes negative */
559         *range = 0;
560     if (*range != 0)
561         delay_output();
562     return TRUE;
563 }
564
565 STATIC_OVL boolean
566 mhurtle_step(arg, x, y)
567     genericptr_t arg;
568     int x, y;
569 {
570         struct monst *mon = (struct monst *)arg;
571
572         /* TODO: Treat walls, doors, iron bars, pools, lava, etc. specially
573          * rather than just stopping before.
574          */
575         if (goodpos(x, y, mon, 0) && m_in_out_region(mon, x, y)) {
576             remove_monster(mon->mx, mon->my);
577             newsym(mon->mx, mon->my);
578             place_monster(mon, x, y);
579             newsym(mon->mx, mon->my);
580             set_apparxy(mon);
581             (void) mintrap(mon);
582             return TRUE;
583         }
584         return FALSE;
585 }
586
587 /*
588  * The player moves through the air for a few squares as a result of
589  * throwing or kicking something.
590  *
591  * dx and dy should be the direction of the hurtle, not of the original
592  * kick or throw and be only.
593  */
594 void
595 hurtle(dx, dy, range, verbose)
596     int dx, dy, range;
597     boolean verbose;
598 {
599     coord uc, cc;
600
601     /* The chain is stretched vertically, so you shouldn't be able to move
602      * very far diagonally.  The premise that you should be able to move one
603      * spot leads to calculations that allow you to only move one spot away
604      * from the ball, if you are levitating over the ball, or one spot
605      * towards the ball, if you are at the end of the chain.  Rather than
606      * bother with all of that, assume that there is no slack in the chain
607      * for diagonal movement, give the player a message and return.
608      */
609     if(Punished && !carried(uball)) {
610         You_feel("a tug from the iron ball.");
611         nomul(0);
612         return;
613     } else if (u.utrap) {
614         You("are anchored by the %s.",
615             u.utraptype == TT_WEB ? "web" : u.utraptype == TT_LAVA ? "lava" :
616                 u.utraptype == TT_INFLOOR ? surface(u.ux,u.uy) : "trap");
617         nomul(0);
618         return;
619     }
620
621     /* make sure dx and dy are [-1,0,1] */
622     dx = sgn(dx);
623     dy = sgn(dy);
624
625     if(!range || (!dx && !dy) || u.ustuck) return; /* paranoia */
626
627     nomul(-range);
628     if (verbose)
629         You("%s in the opposite direction.", range > 1 ? "hurtle" : "float");
630     /* if we're in the midst of shooting multiple projectiles, stop */
631     if (m_shot.i < m_shot.n) {
632         /* last message before hurtling was "you shoot N arrows" */
633         You("stop %sing after the first %s.",
634             m_shot.s ? "shoot" : "throw", m_shot.s ? "shot" : "toss");
635         m_shot.n = m_shot.i;    /* make current shot be the last */
636     }
637     if (In_sokoban(&u.uz))
638         change_luck(-1);        /* Sokoban guilt */
639     uc.x = u.ux;
640     uc.y = u.uy;
641     /* this setting of cc is only correct if dx and dy are [-1,0,1] only */
642     cc.x = u.ux + (dx * range);
643     cc.y = u.uy + (dy * range);
644     (void) walk_path(&uc, &cc, hurtle_step, (genericptr_t)&range);
645 }
646
647 /* Move a monster through the air for a few squares.
648  */
649 void
650 mhurtle(mon, dx, dy, range)
651         struct monst *mon;
652         int dx, dy, range;
653 {
654     coord mc, cc;
655
656         /* At the very least, debilitate the monster */
657         mon->movement = 0;
658         mon->mstun = 1;
659
660         /* Is the monster stuck or too heavy to push?
661          * (very large monsters have too much inertia, even floaters and flyers)
662          */
663         if (mon->data->msize >= MZ_HUGE || mon == u.ustuck || mon->mtrapped)
664             return;
665
666     /* Make sure dx and dy are [-1,0,1] */
667     dx = sgn(dx);
668     dy = sgn(dy);
669     if(!range || (!dx && !dy)) return; /* paranoia */
670
671         /* Send the monster along the path */
672         mc.x = mon->mx;
673         mc.y = mon->my;
674         cc.x = mon->mx + (dx * range);
675         cc.y = mon->my + (dy * range);
676         (void) walk_path(&mc, &cc, mhurtle_step, (genericptr_t)mon);
677         return;
678 }
679
680 STATIC_OVL void
681 check_shop_obj(obj, x, y, broken)
682 register struct obj *obj;
683 register xchar x, y;
684 register boolean broken;
685 {
686         struct monst *shkp = shop_keeper(*u.ushops);
687
688         if(!shkp) return;
689
690         if(broken) {
691                 if (obj->unpaid) {
692                     (void)stolen_value(obj, u.ux, u.uy,
693                                        (boolean)shkp->mpeaceful, FALSE);
694                     subfrombill(obj, shkp);
695                 }
696                 obj->no_charge = 1;
697                 return;
698         }
699
700         if (!costly_spot(x, y) || *in_rooms(x, y, SHOPBASE) != *u.ushops) {
701                 /* thrown out of a shop or into a different shop */
702                 if (obj->unpaid) {
703                     (void)stolen_value(obj, u.ux, u.uy,
704                                        (boolean)shkp->mpeaceful, FALSE);
705                     subfrombill(obj, shkp);
706                 }
707         } else {
708                 if (costly_spot(u.ux, u.uy) && costly_spot(x, y)) {
709                     if(obj->unpaid) subfrombill(obj, shkp);
710                     else if(!(x == shkp->mx && y == shkp->my))
711                             sellobj(obj, x, y);
712                 }
713         }
714 }
715
716 /*
717  * Hero tosses an object upwards with appropriate consequences.
718  *
719  * Returns FALSE if the object is gone.
720  */
721 STATIC_OVL boolean
722 toss_up(obj, hitsroof)
723 struct obj *obj;
724 boolean hitsroof;
725 {
726     const char *almost;
727     /* note: obj->quan == 1 */
728
729     if (hitsroof) {
730         if (breaktest(obj)) {
731                 pline("%s hits the %s.", Doname2(obj), ceiling(u.ux, u.uy));
732                 breakmsg(obj, !Blind);
733                 breakobj(obj, u.ux, u.uy, TRUE, TRUE);
734                 return FALSE;
735         }
736         almost = "";
737     } else {
738         almost = " almost";
739     }
740     pline("%s%s hits the %s, then falls back on top of your %s.",
741           Doname2(obj), almost, ceiling(u.ux,u.uy), body_part(HEAD));
742
743     /* object now hits you */
744
745     if (obj->oclass == POTION_CLASS) {
746         potionhit(&youmonst, obj, TRUE);
747     } else if (breaktest(obj)) {
748         int otyp = obj->otyp, ocorpsenm = obj->corpsenm;
749         int blindinc;
750
751         /* need to check for blindness result prior to destroying obj */
752         blindinc = (otyp == CREAM_PIE || otyp == BLINDING_VENOM) &&
753                    /* AT_WEAP is ok here even if attack type was AT_SPIT */
754                    can_blnd(&youmonst, &youmonst, AT_WEAP, obj) ? rnd(25) : 0;
755
756         breakmsg(obj, !Blind);
757         breakobj(obj, u.ux, u.uy, TRUE, TRUE);
758         obj = 0;        /* it's now gone */
759         switch (otyp) {
760         case EGG:
761                 if (touch_petrifies(&mons[ocorpsenm]) &&
762                     !uarmh && !Stone_resistance &&
763                     !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)))
764                 goto petrify;
765         case CREAM_PIE:
766         case BLINDING_VENOM:
767                 pline("You've got it all over your %s!", body_part(FACE));
768                 if (blindinc) {
769                     if (otyp == BLINDING_VENOM && !Blind)
770                         pline("It blinds you!");
771                     u.ucreamed += blindinc;
772                     make_blinded(Blinded + (long)blindinc, FALSE);
773                     if (!Blind) Your(vision_clears);
774                 }
775                 break;
776         default:
777                 break;
778         }
779         return FALSE;
780     } else {            /* neither potion nor other breaking object */
781         boolean less_damage = uarmh && is_metallic(uarmh), artimsg = FALSE;
782         int dmg = dmgval(obj, &youmonst);
783
784         if (obj->oartifact)
785             /* need a fake die roll here; rn1(18,2) avoids 1 and 20 */
786             artimsg = artifact_hit((struct monst *)0, &youmonst,
787                                    obj, &dmg, rn1(18,2));
788
789         if (!dmg) {     /* probably wasn't a weapon; base damage on weight */
790             dmg = (int) obj->owt / 100;
791             if (dmg < 1) dmg = 1;
792             else if (dmg > 6) dmg = 6;
793             if (youmonst.data == &mons[PM_SHADE] &&
794                     objects[obj->otyp].oc_material != SILVER)
795                 dmg = 0;
796         }
797         if (dmg > 1 && less_damage) dmg = 1;
798         if (dmg > 0) dmg += u.udaminc;
799         if (dmg < 0) dmg = 0;   /* beware negative rings of increase damage */
800         if (Half_physical_damage) dmg = (dmg + 1) / 2;
801
802         if (uarmh) {
803             if (less_damage && dmg < (Upolyd ? u.mh : u.uhp)) {
804                 if (!artimsg)
805                     pline("Fortunately, you are wearing a hard helmet.");
806             } else if (flags.verbose &&
807                     !(obj->otyp == CORPSE && touch_petrifies(&mons[obj->corpsenm])))
808                 Your("%s does not protect you.", xname(uarmh));
809         } else if (obj->otyp == CORPSE && touch_petrifies(&mons[obj->corpsenm])) {
810             if (!Stone_resistance &&
811                     !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) {
812  petrify:
813                 killer_format = KILLED_BY;
814                 killer = "elementary physics";  /* "what goes up..." */
815                 You("turn to stone.");
816                 if (obj) dropy(obj);    /* bypass most of hitfloor() */
817                 done(STONING);
818                 return obj ? TRUE : FALSE;
819             }
820         }
821         hitfloor(obj);
822         losehp(dmg, "falling object", KILLED_BY_AN);
823     }
824     return TRUE;
825 }
826
827 /* return true for weapon meant to be thrown; excludes ammo */
828 STATIC_OVL boolean
829 throwing_weapon(obj)
830 struct obj *obj;
831 {
832         return (is_missile(obj) || is_spear(obj) ||
833                 /* daggers and knife (excludes scalpel) */
834                 (is_blade(obj) && !is_sword(obj) &&
835                  (objects[obj->otyp].oc_dir & PIERCE)) ||
836                 /* special cases [might want to add AXE] */
837                 obj->otyp == WAR_HAMMER || obj->otyp == AKLYS);
838 }
839
840 /* the currently thrown object is returning to you (not for boomerangs) */
841 STATIC_OVL void
842 sho_obj_return_to_u(obj)
843 struct obj *obj;
844 {
845     /* might already be our location (bounced off a wall) */
846     if (bhitpos.x != u.ux || bhitpos.y != u.uy) {
847         int x = bhitpos.x - u.dx, y = bhitpos.y - u.dy;
848
849         tmp_at(DISP_FLASH, obj_to_glyph(obj));
850         while(x != u.ux || y != u.uy) {
851             tmp_at(x, y);
852             delay_output();
853             x -= u.dx; y -= u.dy;
854         }
855         tmp_at(DISP_END, 0);
856     }
857 }
858
859 void
860 throwit(obj, wep_mask, twoweap)
861 register struct obj *obj;
862 long wep_mask;  /* used to re-equip returning boomerang */
863 boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */
864 {
865         register struct monst *mon;
866         register int range, urange;
867         boolean impaired = (Confusion || Stunned || Blind ||
868                            Hallucination || Fumbling);
869
870         if ((obj->cursed || obj->greased) && (u.dx || u.dy) && !rn2(7)) {
871             boolean slipok = TRUE;
872             if (ammo_and_launcher(obj, uwep))
873                 pline("%s!", Tobjnam(obj, "misfire"));
874             else {
875                 /* only slip if it's greased or meant to be thrown */
876                 if (obj->greased || throwing_weapon(obj))
877                     /* BUG: this message is grammatically incorrect if obj has
878                        a plural name; greased gloves or boots for instance. */
879                     pline("%s as you throw it!", Tobjnam(obj, "slip"));
880                 else slipok = FALSE;
881             }
882             if (slipok) {
883                 u.dx = rn2(3)-1;
884                 u.dy = rn2(3)-1;
885                 if (!u.dx && !u.dy) u.dz = 1;
886                 impaired = TRUE;
887             }
888         }
889
890         if ((u.dx || u.dy || (u.dz < 1)) &&
891             calc_capacity((int)obj->owt) > SLT_ENCUMBER &&
892             (Upolyd ? (u.mh < 5 && u.mh != u.mhmax)
893              : (u.uhp < 10 && u.uhp != u.uhpmax)) &&
894             obj->owt > (unsigned)((Upolyd ? u.mh : u.uhp) * 2) &&
895             !Is_airlevel(&u.uz)) {
896             You("have so little stamina, %s drops from your grasp.",
897                 the(xname(obj)));
898             exercise(A_CON, FALSE);
899             u.dx = u.dy = 0;
900             u.dz = 1;
901         }
902
903         thrownobj = obj;
904
905         if(u.uswallow) {
906                 mon = u.ustuck;
907                 bhitpos.x = mon->mx;
908                 bhitpos.y = mon->my;
909         } else if(u.dz) {
910             if (u.dz < 0 && Role_if(PM_VALKYRIE) &&
911                     obj->oartifact == ART_MJOLLNIR && !impaired) {
912                 pline("%s the %s and returns to your hand!",
913                       Tobjnam(obj, "hit"), ceiling(u.ux,u.uy));
914                 obj = addinv(obj);
915                 (void) encumber_msg();
916                 setuwep(obj);
917                 u.twoweap = twoweap;
918             } else if (u.dz < 0 && !Is_airlevel(&u.uz) &&
919                     !Underwater && !Is_waterlevel(&u.uz)) {
920                 (void) toss_up(obj, rn2(5));
921             } else {
922                 hitfloor(obj);
923             }
924             thrownobj = (struct obj*)0;
925             return;
926
927         } else if(obj->otyp == BOOMERANG && !Underwater) {
928                 if(Is_airlevel(&u.uz) || Levitation)
929                     hurtle(-u.dx, -u.dy, 1, TRUE);
930                 mon = boomhit(u.dx, u.dy);
931                 if(mon == &youmonst) {          /* the thing was caught */
932                         exercise(A_DEX, TRUE);
933                         obj = addinv(obj);
934                         (void) encumber_msg();
935                         if (wep_mask && !(obj->owornmask & wep_mask)) {
936                             setworn(obj, wep_mask);
937                             u.twoweap = twoweap;
938                         }
939                         thrownobj = (struct obj*)0;
940                         return;
941                 }
942         } else {
943                 urange = (int)(ACURRSTR)/2;
944                 /* balls are easy to throw or at least roll */
945                 /* also, this insures the maximum range of a ball is greater
946                  * than 1, so the effects from throwing attached balls are
947                  * actually possible
948                  */
949                 if (obj->otyp == HEAVY_IRON_BALL)
950                         range = urange - (int)(obj->owt/100);
951                 else
952                         range = urange - (int)(obj->owt/40);
953                 if (obj == uball) {
954                         if (u.ustuck) range = 1;
955                         else if (range >= 5) range = 5;
956                 }
957                 if (range < 1) range = 1;
958
959                 if (is_ammo(obj)) {
960                     if (ammo_and_launcher(obj, uwep))
961                         range++;
962                     else if (obj->oclass != GEM_CLASS)
963                         range /= 2;
964                 }
965
966                 if (Is_airlevel(&u.uz) || Levitation) {
967                     /* action, reaction... */
968                     urange -= range;
969                     if(urange < 1) urange = 1;
970                     range -= urange;
971                     if(range < 1) range = 1;
972                 }
973
974                 if (obj->otyp == BOULDER)
975                     range = 20;         /* you must be giant */
976                 else if (obj->oartifact == ART_MJOLLNIR)
977                     range = (range + 1) / 2;    /* it's heavy */
978                 else if (obj == uball && u.utrap && u.utraptype == TT_INFLOOR)
979                     range = 1;
980
981                 if (Underwater) range = 1;
982
983                 mon = bhit(u.dx, u.dy, range, THROWN_WEAPON,
984                            (int FDECL((*),(MONST_P,OBJ_P)))0,
985                            (int FDECL((*),(OBJ_P,OBJ_P)))0,
986                            obj);
987
988                 /* have to do this after bhit() so u.ux & u.uy are correct */
989                 if(Is_airlevel(&u.uz) || Levitation)
990                     hurtle(-u.dx, -u.dy, urange, TRUE);
991         }
992
993         if (mon) {
994                 boolean obj_gone;
995
996                 if (mon->isshk &&
997                     obj->where == OBJ_MINVENT && obj->ocarry == mon) {
998                     thrownobj = (struct obj*)0;
999                     return;             /* alert shk caught it */
1000                 }
1001                 (void) snuff_candle(obj);
1002                 notonhead = (bhitpos.x != mon->mx || bhitpos.y != mon->my);
1003                 obj_gone = thitmonst(mon, obj);
1004                 /* Monster may have been tamed; this frees old mon */
1005                 mon = m_at(bhitpos.x, bhitpos.y);
1006
1007                 /* [perhaps this should be moved into thitmonst or hmon] */
1008                 if (mon && mon->isshk &&
1009                         (!inside_shop(u.ux, u.uy) ||
1010                          !index(in_rooms(mon->mx, mon->my, SHOPBASE), *u.ushops)))
1011                     hot_pursuit(mon);
1012
1013                 if (obj_gone) return;
1014         }
1015
1016         if (u.uswallow) {
1017                 /* ball is not picked up by monster */
1018                 if (obj != uball) (void) mpickobj(u.ustuck,obj);
1019         } else {
1020                 /* the code following might become part of dropy() */
1021                 if (obj->oartifact == ART_MJOLLNIR &&
1022                         Role_if(PM_VALKYRIE) && rn2(100)) {
1023                     /* we must be wearing Gauntlets of Power to get here */
1024                     sho_obj_return_to_u(obj);       /* display its flight */
1025
1026                     if (!impaired && rn2(100)) {
1027                         pline("%s to your hand!", Tobjnam(obj, "return"));
1028                         obj = addinv(obj);
1029                         (void) encumber_msg();
1030                         setuwep(obj);
1031                         u.twoweap = twoweap;
1032                         if(cansee(bhitpos.x, bhitpos.y))
1033                             newsym(bhitpos.x,bhitpos.y);
1034                     } else {
1035                         int dmg = rn2(2);
1036                         if (!dmg) {
1037                             pline(Blind ? "%s lands %s your %s." :
1038                                         "%s back to you, landing %s your %s.",
1039                                   Blind ? Something : Tobjnam(obj, "return"),
1040                                   Levitation ? "beneath" : "at",
1041                                   makeplural(body_part(FOOT)));
1042                         } else {
1043                             dmg += rnd(3);
1044                             pline(Blind ? "%s your %s!" :
1045                                         "%s back toward you, hitting your %s!",
1046                                   Tobjnam(obj, Blind ? "hit" : "fly"),
1047                                   body_part(ARM));
1048                             (void) artifact_hit((struct monst *)0,
1049                                                 &youmonst, obj, &dmg, 0);
1050                             losehp(dmg, xname(obj),
1051                                 obj_is_pname(obj) ? KILLED_BY : KILLED_BY_AN);
1052                         }
1053                         if (ship_object(obj, u.ux, u.uy, FALSE)) {
1054                             thrownobj = (struct obj*)0;
1055                             return;
1056                         }
1057                         dropy(obj);
1058                     }
1059                     thrownobj = (struct obj*)0;
1060                     return;
1061                 }
1062
1063                 if (!IS_SOFT(levl[bhitpos.x][bhitpos.y].typ) &&
1064                         breaktest(obj)) {
1065                     tmp_at(DISP_FLASH, obj_to_glyph(obj));
1066                     tmp_at(bhitpos.x, bhitpos.y);
1067                     delay_output();
1068                     tmp_at(DISP_END, 0);
1069                     breakmsg(obj, cansee(bhitpos.x, bhitpos.y));
1070                     breakobj(obj, bhitpos.x, bhitpos.y, TRUE, TRUE);
1071                     return;
1072                 }
1073                 if(flooreffects(obj,bhitpos.x,bhitpos.y,"fall")) return;
1074                 obj_no_longer_held(obj);
1075                 if (mon && mon->isshk && is_pick(obj)) {
1076                     if (cansee(bhitpos.x, bhitpos.y))
1077                         pline("%s snatches up %s.",
1078                               Monnam(mon), the(xname(obj)));
1079                     if(*u.ushops)
1080                         check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE);
1081                     (void) mpickobj(mon, obj);  /* may merge and free obj */
1082                     thrownobj = (struct obj*)0;
1083                     return;
1084                 }
1085                 (void) snuff_candle(obj);
1086                 if (!mon && ship_object(obj, bhitpos.x, bhitpos.y, FALSE)) {
1087                     thrownobj = (struct obj*)0;
1088                     return;
1089                 }
1090                 thrownobj = (struct obj*)0;
1091                 place_object(obj, bhitpos.x, bhitpos.y);
1092                 if(*u.ushops && obj != uball)
1093                     check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE);
1094
1095                 stackobj(obj);
1096                 if (obj == uball)
1097                     drop_ball(bhitpos.x, bhitpos.y);
1098                 if (cansee(bhitpos.x, bhitpos.y))
1099                     newsym(bhitpos.x,bhitpos.y);
1100                 if (obj_sheds_light(obj))
1101                     vision_full_recalc = 1;
1102                 if (!IS_SOFT(levl[bhitpos.x][bhitpos.y].typ))
1103                     container_impact_dmg(obj);
1104         }
1105 }
1106
1107 /* an object may hit a monster; various factors adjust the chance of hitting */
1108 int
1109 omon_adj(mon, obj, mon_notices)
1110 struct monst *mon;
1111 struct obj *obj;
1112 boolean mon_notices;
1113 {
1114         int tmp = 0;
1115
1116         /* size of target affects the chance of hitting */
1117         tmp += (mon->data->msize - MZ_MEDIUM);          /* -2..+5 */
1118         /* sleeping target is more likely to be hit */
1119         if (mon->msleeping) {
1120             tmp += 2;
1121             if (mon_notices) mon->msleeping = 0;
1122         }
1123         /* ditto for immobilized target */
1124         if (!mon->mcanmove || !mon->data->mmove) {
1125             tmp += 4;
1126             if (mon_notices && mon->data->mmove && !rn2(10)) {
1127                 mon->mcanmove = 1;
1128                 mon->mfrozen = 0;
1129             }
1130         }
1131         /* some objects are more likely to hit than others */
1132         switch (obj->otyp) {
1133         case HEAVY_IRON_BALL:
1134             if (obj != uball) tmp += 2;
1135             break;
1136         case BOULDER:
1137             tmp += 6;
1138             break;
1139         default:
1140             if (obj->oclass == WEAPON_CLASS || is_weptool(obj) ||
1141                     obj->oclass == GEM_CLASS)
1142                 tmp += hitval(obj, mon);
1143             break;
1144         }
1145         return tmp;
1146 }
1147
1148 /* thrown object misses target monster */
1149 STATIC_OVL void
1150 tmiss(obj, mon)
1151 struct obj *obj;
1152 struct monst *mon;
1153 {
1154     const char *missile = mshot_xname(obj);
1155
1156     /* If the target can't be seen or doesn't look like a valid target,
1157        avoid "the arrow misses it," or worse, "the arrows misses the mimic."
1158        An attentive player will still notice that this is different from
1159        an arrow just landing short of any target (no message in that case),
1160        so will realize that there is a valid target here anyway. */
1161     if (!canseemon(mon) || (mon->m_ap_type && mon->m_ap_type != M_AP_MONSTER))
1162         pline("%s %s.", The(missile), otense(obj, "miss"));
1163     else
1164         miss(missile, mon);
1165     if (!rn2(3)) wakeup(mon);
1166     return;
1167 }
1168
1169 #define quest_arti_hits_leader(obj,mon) \
1170   (obj->oartifact && is_quest_artifact(obj) && (mon->data->msound == MS_LEADER))
1171
1172 /*
1173  * Object thrown by player arrives at monster's location.
1174  * Return 1 if obj has disappeared or otherwise been taken care of,
1175  * 0 if caller must take care of it.
1176  */
1177 int
1178 thitmonst(mon, obj)
1179 register struct monst *mon;
1180 register struct obj   *obj;
1181 {
1182         register int    tmp; /* Base chance to hit */
1183         register int    disttmp; /* distance modifier */
1184         int otyp = obj->otyp;
1185         boolean guaranteed_hit = (u.uswallow && mon == u.ustuck);
1186
1187         /* Differences from melee weapons:
1188          *
1189          * Dex still gives a bonus, but strength does not.
1190          * Polymorphed players lacking attacks may still throw.
1191          * There's a base -1 to hit.
1192          * No bonuses for fleeing or stunned targets (they don't dodge
1193          *    melee blows as readily, but dodging arrows is hard anyway).
1194          * Not affected by traps, etc.
1195          * Certain items which don't in themselves do damage ignore tmp.
1196          * Distance and monster size affect chance to hit.
1197          */
1198         tmp = -1 + Luck + find_mac(mon) + u.uhitinc +
1199                         maybe_polyd(youmonst.data->mlevel, u.ulevel);
1200         if (ACURR(A_DEX) < 4) tmp -= 3;
1201         else if (ACURR(A_DEX) < 6) tmp -= 2;
1202         else if (ACURR(A_DEX) < 8) tmp -= 1;
1203         else if (ACURR(A_DEX) >= 14) tmp += (ACURR(A_DEX) - 14);
1204
1205         /* Modify to-hit depending on distance; but keep it sane.
1206          * Polearms get a distance penalty even when wielded; it's
1207          * hard to hit at a distance.
1208          */
1209         disttmp = 3 - distmin(u.ux, u.uy, mon->mx, mon->my);
1210         if(disttmp < -4) disttmp = -4;
1211         tmp += disttmp;
1212
1213         /* gloves are a hinderance to proper use of bows */
1214         if (uarmg && uwep && objects[uwep->otyp].oc_skill == P_BOW) {
1215             switch (uarmg->otyp) {
1216             case GAUNTLETS_OF_POWER:    /* metal */
1217                 tmp -= 2;
1218                 break;
1219             case GAUNTLETS_OF_FUMBLING:
1220                 tmp -= 3;
1221                 break;
1222             case LEATHER_GLOVES:
1223             case GAUNTLETS_OF_DEXTERITY:
1224                 break;
1225             default:
1226                 impossible("Unknown type of gloves (%d)", uarmg->otyp);
1227                 break;
1228             }
1229         }
1230
1231         tmp += omon_adj(mon, obj, TRUE);
1232         if (is_orc(mon->data) && maybe_polyd(is_elf(youmonst.data),
1233                         Race_if(PM_ELF)))
1234             tmp++;
1235         if (guaranteed_hit) {
1236             tmp += 1000; /* Guaranteed hit */
1237         }
1238
1239         if (obj->oclass == GEM_CLASS && is_unicorn(mon->data)) {
1240             if (mon->mtame) {
1241                 pline("%s catches and drops %s.", Monnam(mon), the(xname(obj)));
1242                 return 0;
1243             } else {
1244                 pline("%s catches %s.", Monnam(mon), the(xname(obj)));
1245                 return gem_accept(mon, obj);
1246             }
1247         }
1248
1249         /* don't make game unwinnable if naive player throws artifact
1250            at leader.... */
1251         if (quest_arti_hits_leader(obj, mon)) {
1252             /* not wakeup(), which angers non-tame monsters */
1253             mon->msleeping = 0;
1254             mon->mstrategy &= ~STRAT_WAITMASK;
1255
1256             if (mon->mcanmove) {
1257                 pline("%s catches %s.", Monnam(mon), the(xname(obj)));
1258                 if (mon->mpeaceful) {
1259                     boolean next2u = monnear(mon, u.ux, u.uy);
1260
1261                     finish_quest(obj);  /* acknowledge quest completion */
1262                     pline("%s %s %s back to you.", Monnam(mon),
1263                           (next2u ? "hands" : "tosses"), the(xname(obj)));
1264                     if (!next2u) sho_obj_return_to_u(obj);
1265                     obj = addinv(obj);  /* back into your inventory */
1266                     (void) encumber_msg();
1267                 } else {
1268                     /* angry leader caught it and isn't returning it */
1269                     (void) mpickobj(mon, obj);
1270                 }
1271                 return 1;               /* caller doesn't need to place it */
1272             }
1273             return(0);
1274         }
1275
1276         if (obj->oclass == WEAPON_CLASS || is_weptool(obj) ||
1277                 obj->oclass == GEM_CLASS) {
1278             if (is_ammo(obj)) {
1279                 if (!ammo_and_launcher(obj, uwep)) {
1280                     tmp -= 4;
1281                 } else {
1282                     tmp += uwep->spe - greatest_erosion(uwep);
1283                     tmp += weapon_hit_bonus(uwep);
1284                     if (uwep->oartifact) tmp += spec_abon(uwep, mon);
1285                     /*
1286                      * Elves and Samurais are highly trained w/bows,
1287                      * especially their own special types of bow.
1288                      * Polymorphing won't make you a bow expert.
1289                      */
1290                     if ((Race_if(PM_ELF) || Role_if(PM_SAMURAI)) &&
1291                                 (!Upolyd || your_race(youmonst.data)) &&
1292                                 objects[uwep->otyp].oc_skill == P_BOW) {
1293                         tmp++;
1294                         if (Race_if(PM_ELF) && uwep->otyp == ELVEN_BOW)
1295                             tmp++;
1296                         else if (Role_if(PM_SAMURAI) && uwep->otyp == YUMI)
1297                             tmp++;
1298                     }
1299                 }
1300             } else {
1301                 if (otyp == BOOMERANG)          /* arbitrary */
1302                     tmp += 4;
1303                 else if (throwing_weapon(obj))  /* meant to be thrown */
1304                     tmp += 2;
1305                 else                            /* not meant to be thrown */
1306                     tmp -= 2;
1307                 /* we know we're dealing with a weapon or weptool handled
1308                    by WEAPON_SKILLS once ammo objects have been excluded */
1309                 tmp += weapon_hit_bonus(obj);
1310             }
1311
1312             if (tmp >= rnd(20)) {
1313                 if (hmon(mon,obj,1)) {  /* mon still alive */
1314                     cutworm(mon, bhitpos.x, bhitpos.y, obj);
1315                 }
1316                 exercise(A_DEX, TRUE);
1317                 /* projectiles other than magic stones
1318                    sometimes disappear when thrown */
1319                 if (objects[otyp].oc_skill < P_NONE &&
1320                                 objects[otyp].oc_skill > -P_BOOMERANG &&
1321                                 !objects[otyp].oc_magic) {
1322                     /* we were breaking 2/3 of everything unconditionally.
1323                      * we still don't want anything to survive unconditionally,
1324                      * but we need ammo to stay around longer on average.
1325                      */
1326                     int broken, chance;
1327                     chance = 3 + greatest_erosion(obj) - obj->spe;
1328                     if (chance > 1)
1329                         broken = rn2(chance);
1330                     else
1331                         broken = !rn2(4);
1332                     if (obj->blessed && !rnl(4))
1333                         broken = 0;
1334
1335                     if (broken) {
1336                         if (*u.ushops)
1337                             check_shop_obj(obj, bhitpos.x,bhitpos.y, TRUE);
1338                         obfree(obj, (struct obj *)0);
1339                         return 1;
1340                     }
1341                 }
1342                 passive_obj(mon, obj, (struct attack *)0);
1343             } else {
1344                 tmiss(obj, mon);
1345             }
1346
1347         } else if (otyp == HEAVY_IRON_BALL) {
1348             exercise(A_STR, TRUE);
1349             if (tmp >= rnd(20)) {
1350                 int was_swallowed = guaranteed_hit;
1351
1352                 exercise(A_DEX, TRUE);
1353                 if (!hmon(mon,obj,1)) {         /* mon killed */
1354                     if (was_swallowed && !u.uswallow && obj == uball)
1355                         return 1;       /* already did placebc() */
1356                 }
1357             } else {
1358                 tmiss(obj, mon);
1359             }
1360
1361         } else if (otyp == BOULDER) {
1362             exercise(A_STR, TRUE);
1363             if (tmp >= rnd(20)) {
1364                 exercise(A_DEX, TRUE);
1365                 (void) hmon(mon,obj,1);
1366             } else {
1367                 tmiss(obj, mon);
1368             }
1369
1370         } else if ((otyp == EGG || otyp == CREAM_PIE ||
1371                     otyp == BLINDING_VENOM || otyp == ACID_VENOM) &&
1372                 (guaranteed_hit || ACURR(A_DEX) > rnd(25))) {
1373             (void) hmon(mon, obj, 1);
1374             return 1;   /* hmon used it up */
1375
1376         } else if (obj->oclass == POTION_CLASS &&
1377                 (guaranteed_hit || ACURR(A_DEX) > rnd(25))) {
1378             potionhit(mon, obj, TRUE);
1379             return 1;
1380
1381         } else if (befriend_with_obj(mon->data, obj) ||
1382                    (mon->mtame && dogfood(mon, obj) <= ACCFOOD)) {
1383             if (tamedog(mon, obj))
1384                 return 1;               /* obj is gone */
1385             else {
1386                 /* not tmiss(), which angers non-tame monsters */
1387                 miss(xname(obj), mon);
1388                 mon->msleeping = 0;
1389                 mon->mstrategy &= ~STRAT_WAITMASK;
1390             }
1391         } else if (guaranteed_hit) {
1392             /* this assumes that guaranteed_hit is due to swallowing */
1393             wakeup(mon);
1394             if (obj->otyp == CORPSE && touch_petrifies(&mons[obj->corpsenm])) {
1395                 if (is_animal(u.ustuck->data)) {
1396                         minstapetrify(u.ustuck, TRUE);
1397                         /* Don't leave a cockatrice corpse available in a statue */
1398                         if (!u.uswallow) {
1399                                 delobj(obj);
1400                                 return 1;
1401                         }
1402                 }
1403             }
1404             pline("%s into %s %s.",
1405                 Tobjnam(obj, "vanish"), s_suffix(mon_nam(mon)),
1406                 is_animal(u.ustuck->data) ? "entrails" : "currents");
1407         } else {
1408             tmiss(obj, mon);
1409         }
1410
1411         return 0;
1412 }
1413
1414 STATIC_OVL int
1415 gem_accept(mon, obj)
1416 register struct monst *mon;
1417 register struct obj *obj;
1418 {
1419         char buf[BUFSZ];
1420         boolean is_buddy = sgn(mon->data->maligntyp) == sgn(u.ualign.type);
1421         boolean is_gem = objects[obj->otyp].oc_material == GEMSTONE;
1422         int ret = 0;
1423         static NEARDATA const char nogood[] = " is not interested in your junk.";
1424         static NEARDATA const char acceptgift[] = " accepts your gift.";
1425         static NEARDATA const char maybeluck[] = " hesitatingly";
1426         static NEARDATA const char noluck[] = " graciously";
1427         static NEARDATA const char addluck[] = " gratefully";
1428
1429         Strcpy(buf,Monnam(mon));
1430         mon->mpeaceful = 1;
1431         mon->mavenge = 0;
1432
1433         /* object properly identified */
1434         if(obj->dknown && objects[obj->otyp].oc_name_known) {
1435                 if(is_gem) {
1436                         if(is_buddy) {
1437                                 Strcat(buf,addluck);
1438                                 change_luck(5);
1439                         } else {
1440                                 Strcat(buf,maybeluck);
1441                                 change_luck(rn2(7)-3);
1442                         }
1443                 } else {
1444                         Strcat(buf,nogood);
1445                         goto nopick;
1446                 }
1447         /* making guesses */
1448         } else if(obj->onamelth || objects[obj->otyp].oc_uname) {
1449                 if(is_gem) {
1450                         if(is_buddy) {
1451                                 Strcat(buf,addluck);
1452                                 change_luck(2);
1453                         } else {
1454                                 Strcat(buf,maybeluck);
1455                                 change_luck(rn2(3)-1);
1456                         }
1457                 } else {
1458                         Strcat(buf,nogood);
1459                         goto nopick;
1460                 }
1461         /* value completely unknown to @ */
1462         } else {
1463                 if(is_gem) {
1464                         if(is_buddy) {
1465                                 Strcat(buf,addluck);
1466                                 change_luck(1);
1467                         } else {
1468                                 Strcat(buf,maybeluck);
1469                                 change_luck(rn2(3)-1);
1470                         }
1471                 } else {
1472                         Strcat(buf,noluck);
1473                 }
1474         }
1475         Strcat(buf,acceptgift);
1476         if(*u.ushops) check_shop_obj(obj, mon->mx, mon->my, TRUE);
1477         (void) mpickobj(mon, obj);      /* may merge and free obj */
1478         ret = 1;
1479
1480 nopick:
1481         if(!Blind) pline("%s", buf);
1482         if (!tele_restrict(mon)) (void) rloc(mon, FALSE);
1483         return(ret);
1484 }
1485
1486 /*
1487  * Comments about the restructuring of the old breaks() routine.
1488  *
1489  * There are now three distinct phases to object breaking:
1490  *     breaktest() - which makes the check/decision about whether the
1491  *                   object is going to break.
1492  *     breakmsg()  - which outputs a message about the breakage,
1493  *                   appropriate for that particular object. Should
1494  *                   only be called after a positve breaktest().
1495  *                   on the object and, if it going to be called,
1496  *                   it must be called before calling breakobj().
1497  *                   Calling breakmsg() is optional.
1498  *     breakobj()  - which actually does the breakage and the side-effects
1499  *                   of breaking that particular object. This should
1500  *                   only be called after a positive breaktest() on the
1501  *                   object.
1502  *
1503  * Each of the above routines is currently static to this source module.
1504  * There are two routines callable from outside this source module which
1505  * perform the routines above in the correct sequence.
1506  *
1507  *   hero_breaks() - called when an object is to be broken as a result
1508  *                   of something that the hero has done. (throwing it,
1509  *                   kicking it, etc.)
1510  *   breaks()      - called when an object is to be broken for some
1511  *                   reason other than the hero doing something to it.
1512  */
1513
1514 /*
1515  * The hero causes breakage of an object (throwing, dropping it, etc.)
1516  * Return 0 if the object didn't break, 1 if the object broke.
1517  */
1518 int
1519 hero_breaks(obj, x, y, from_invent)
1520 struct obj *obj;
1521 xchar x, y;             /* object location (ox, oy may not be right) */
1522 boolean from_invent;    /* thrown or dropped by player; maybe on shop bill */
1523 {
1524         boolean in_view = !Blind;
1525         if (!breaktest(obj)) return 0;
1526         breakmsg(obj, in_view);
1527         breakobj(obj, x, y, TRUE, from_invent);
1528         return 1;
1529 }
1530
1531 /*
1532  * The object is going to break for a reason other than the hero doing
1533  * something to it.
1534  * Return 0 if the object doesn't break, 1 if the object broke.
1535  */
1536 int
1537 breaks(obj, x, y)
1538 struct obj *obj;
1539 xchar x, y;             /* object location (ox, oy may not be right) */
1540 {
1541         boolean in_view = Blind ? FALSE : cansee(x, y);
1542
1543         if (!breaktest(obj)) return 0;
1544         breakmsg(obj, in_view);
1545         breakobj(obj, x, y, FALSE, FALSE);
1546         return 1;
1547 }
1548
1549 /*
1550  * Unconditionally break an object. Assumes all resistance checks
1551  * and break messages have been delivered prior to getting here.
1552  */
1553 STATIC_OVL void
1554 breakobj(obj, x, y, hero_caused, from_invent)
1555 struct obj *obj;
1556 xchar x, y;             /* object location (ox, oy may not be right) */
1557 boolean hero_caused;    /* is this the hero's fault? */
1558 boolean from_invent;
1559 {
1560         switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) {
1561                 case MIRROR:
1562                         if (hero_caused)
1563                             change_luck(-2);
1564                         break;
1565                 case POT_WATER:         /* really, all potions */
1566                         if (obj->otyp == POT_OIL && obj->lamplit) {
1567                             splatter_burning_oil(x,y);
1568                         } else if (distu(x,y) <= 2) {
1569                             if (!breathless(youmonst.data) || haseyes(youmonst.data)) {
1570                                 if (obj->otyp != POT_WATER) {
1571                                         if (!breathless(youmonst.data))
1572                                              /* [what about "familiar odor" when known?] */
1573                                             You("smell a peculiar odor...");
1574                                         else {
1575                                             int numeyes = eyecount(youmonst.data);
1576                                             Your("%s water%s.",
1577                                                  (numeyes == 1) ? body_part(EYE) :
1578                                                         makeplural(body_part(EYE)),
1579                                                  (numeyes == 1) ? "s" : "");
1580                                         }
1581                                 }
1582                                 potionbreathe(obj);
1583                             }
1584                         }
1585                         /* monster breathing isn't handled... [yet?] */
1586                         break;
1587                 case EGG:
1588                         /* breaking your own eggs is bad luck */
1589                         if (hero_caused && obj->spe && obj->corpsenm >= LOW_PM)
1590                             change_luck((schar) -min(obj->quan, 5L));
1591                         break;
1592         }
1593         if (hero_caused) {
1594             if (from_invent) {
1595                 if (*u.ushops)
1596                         check_shop_obj(obj, x, y, TRUE);
1597             } else if (!obj->no_charge && costly_spot(x, y)) {
1598                 /* it is assumed that the obj is a floor-object */
1599                 char *o_shop = in_rooms(x, y, SHOPBASE);
1600                 struct monst *shkp = shop_keeper(*o_shop);
1601
1602                 if (shkp) {             /* (implies *o_shop != '\0') */
1603                     static NEARDATA long lastmovetime = 0L;
1604                     static NEARDATA boolean peaceful_shk = FALSE;
1605                     /*  We want to base shk actions on her peacefulness
1606                         at start of this turn, so that "simultaneous"
1607                         multiple breakage isn't drastically worse than
1608                         single breakage.  (ought to be done via ESHK)  */
1609                     if (moves != lastmovetime)
1610                         peaceful_shk = shkp->mpeaceful;
1611                     if (stolen_value(obj, x, y, peaceful_shk, FALSE) > 0L &&
1612                         (*o_shop != u.ushops[0] || !inside_shop(u.ux, u.uy)) &&
1613                         moves != lastmovetime) make_angry_shk(shkp, x, y);
1614                     lastmovetime = moves;
1615                 }
1616             }
1617         }
1618         delobj(obj);
1619 }
1620
1621 /*
1622  * Check to see if obj is going to break, but don't actually break it.
1623  * Return 0 if the object isn't going to break, 1 if it is.
1624  */
1625 boolean
1626 breaktest(obj)
1627 struct obj *obj;
1628 {
1629         if (obj_resists(obj, 1, 99)) return 0;
1630         if (objects[obj->otyp].oc_material == GLASS && !obj->oartifact &&
1631                 obj->oclass != GEM_CLASS)
1632             return 1;
1633         switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) {
1634 #ifdef TOURIST
1635                 case EXPENSIVE_CAMERA:
1636 #endif
1637                 case POT_WATER:         /* really, all potions */
1638                 case EGG:
1639                 case CREAM_PIE:
1640                 case MELON:
1641                 case ACID_VENOM:
1642                 case BLINDING_VENOM:
1643                         return 1;
1644                 default:
1645                         return 0;
1646         }
1647 }
1648
1649 STATIC_OVL void
1650 breakmsg(obj, in_view)
1651 struct obj *obj;
1652 boolean in_view;
1653 {
1654         const char *to_pieces;
1655
1656         to_pieces = "";
1657         switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) {
1658                 default: /* glass or crystal wand */
1659                     if (obj->oclass != WAND_CLASS)
1660                         impossible("breaking odd object?");
1661                 case CRYSTAL_PLATE_MAIL:
1662                 case LENSES:
1663                 case MIRROR:
1664                 case CRYSTAL_BALL:
1665 #ifdef TOURIST
1666                 case EXPENSIVE_CAMERA:
1667 #endif
1668                         to_pieces = " into a thousand pieces";
1669                         /*FALLTHRU*/
1670                 case POT_WATER:         /* really, all potions */
1671                         if (!in_view)
1672                             You_hear("%s shatter!", something);
1673                         else
1674                             pline("%s shatter%s%s!", Doname2(obj),
1675                                 (obj->quan==1) ? "s" : "", to_pieces);
1676                         break;
1677                 case EGG:
1678                 case MELON:
1679                         pline("Splat!");
1680                         break;
1681                 case CREAM_PIE:
1682                         if (in_view) pline("What a mess!");
1683                         break;
1684                 case ACID_VENOM:
1685                 case BLINDING_VENOM:
1686                         pline("Splash!");
1687                         break;
1688         }
1689 }
1690
1691 STATIC_OVL int
1692 throw_gold(obj)
1693 struct obj *obj;
1694 {
1695         int range, odx, ody;
1696 #ifndef GOLDOBJ
1697         long zorks = obj->quan;
1698 #endif
1699         register struct monst *mon;
1700
1701         if(!u.dx && !u.dy && !u.dz) {
1702 #ifndef GOLDOBJ
1703                 u.ugold += obj->quan;
1704                 flags.botl = 1;
1705                 dealloc_obj(obj);
1706 #endif
1707                 You("cannot throw gold at yourself.");
1708                 return(0);
1709         }
1710 #ifdef GOLDOBJ
1711         freeinv(obj);
1712 #endif
1713         if(u.uswallow) {
1714                 pline(is_animal(u.ustuck->data) ?
1715                         "%s in the %s's entrails." : "%s into %s.",
1716 #ifndef GOLDOBJ
1717                         "The gold disappears", mon_nam(u.ustuck));
1718                 u.ustuck->mgold += zorks;
1719                 dealloc_obj(obj);
1720 #else
1721                         "The money disappears", mon_nam(u.ustuck));
1722                 add_to_minv(u.ustuck, obj);
1723 #endif
1724                 return(1);
1725         }
1726
1727         if(u.dz) {
1728                 if (u.dz < 0 && !Is_airlevel(&u.uz) &&
1729                                         !Underwater && !Is_waterlevel(&u.uz)) {
1730         pline_The("gold hits the %s, then falls back on top of your %s.",
1731                     ceiling(u.ux,u.uy), body_part(HEAD));
1732                     /* some self damage? */
1733                     if(uarmh) pline("Fortunately, you are wearing a helmet!");
1734                 }
1735                 bhitpos.x = u.ux;
1736                 bhitpos.y = u.uy;
1737         } else {
1738                 /* consistent with range for normal objects */
1739                 range = (int)((ACURRSTR)/2 - obj->owt/40);
1740
1741                 /* see if the gold has a place to move into */
1742                 odx = u.ux + u.dx;
1743                 ody = u.uy + u.dy;
1744                 if(!ZAP_POS(levl[odx][ody].typ) || closed_door(odx, ody)) {
1745                         bhitpos.x = u.ux;
1746                         bhitpos.y = u.uy;
1747                 } else {
1748                         mon = bhit(u.dx, u.dy, range, THROWN_WEAPON,
1749                                    (int FDECL((*),(MONST_P,OBJ_P)))0,
1750                                    (int FDECL((*),(OBJ_P,OBJ_P)))0,
1751                                    obj);
1752                         if(mon) {
1753                             if (ghitm(mon, obj))        /* was it caught? */
1754                                 return 1;
1755                         } else {
1756                             if(ship_object(obj, bhitpos.x, bhitpos.y, FALSE))
1757                                 return 1;
1758                         }
1759                 }
1760         }
1761
1762         if(flooreffects(obj,bhitpos.x,bhitpos.y,"fall")) return(1);
1763         if(u.dz > 0)
1764                 pline_The("gold hits the %s.", surface(bhitpos.x,bhitpos.y));
1765         place_object(obj,bhitpos.x,bhitpos.y);
1766         if(*u.ushops) sellobj(obj, bhitpos.x, bhitpos.y);
1767         stackobj(obj);
1768         newsym(bhitpos.x,bhitpos.y);
1769         return(1);
1770 }
1771
1772 /*dothrow.c*/