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
throw_obj(obj,shotlimit)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
dothrow()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
autoquiver()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
dofire()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
hitfloor(obj)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
walk_path(src_cc,dest_cc,check_proc,arg)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
hurtle_step(arg,x,y)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
hurtle(dx,dy,range,verbose)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
check_shop_obj(obj,x,y,broken)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
toss_up(obj,hitsroof)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
throwing_weapon(obj)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
sho_obj_return_to_u(obj)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
throwit(obj,wep_mask)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
omon_adj(mon,obj,mon_notices)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
tmiss(obj,mon)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
thitmonst(mon,obj)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
gem_accept(mon,obj)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
hero_breaks(obj,x,y,from_invent)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
breaks(obj,x,y)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
breakobj(obj,x,y,heros_fault,from_invent)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
breaktest(obj)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
breakmsg(obj,in_view)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
throw_gold(obj)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*/
1472