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