Source:Mthrowu.c

Below is the full text to src/mthrowu.c from NetHack 3.4.3. To link to a particular line, write [[mthrowu.c#line123 ]], for example. 1.   /*	SCCS Id: @(#)mthrowu.c	3.4	2003/05/09	*/ 2.   /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3.    /* NetHack may be freely redistributed. See license for details. */ 4.

5.   #include "hack.h"  6. 7.   STATIC_DCL int FDECL(drop_throw,(struct obj *,BOOLEAN_P,int,int)); 8.    9.    #define URETREATING(x,y) (distmin(u.ux,u.uy,x,y) > distmin(u.ux0,u.uy0,x,y)) 10.   11.   #define POLE_LIM 5	/* How far monsters can use pole-weapons */ 12.   13.   #ifndef OVLB 14.   15.   STATIC_DCL const char *breathwep[]; 16.   17.   #else /* OVLB */ 18.   19.   /*  20.    * Keep consistent with breath weapons in zap.c, and AD_* in monattk.h.  21. */ 22.   STATIC_OVL NEARDATA const char *breathwep[] = { 23.  				"fragments", 24.  				"fire", 25.  				"frost", 26.  				"sleep gas", 27.  				"a disintegration blast", 28.  				"lightning", 29.  				"poison gas", 30.  				"acid", 31.  				"strange breath #8", 32.  				"strange breath #9" 33.  };  34.    35.   /* hero is hit by something other than a monster */ 36.  int 37.  thitu(tlev, dam, obj, name) 38.  int tlev, dam; 39.  struct obj *obj; 40.  const char *name;	/* if null, then format `obj' */ 41.  {  42.   	const char *onm, *knm; 43.  	boolean is_acid; 44.  	int kprefix = KILLED_BY_AN; 45.  	char onmbuf[BUFSZ], knmbuf[BUFSZ]; 46.   47.   	if (!name) { 48.  	    if (!obj) panic("thitu: name & obj both null?"); 49.  	    name = strcpy(onmbuf,  50.   			 (obj->quan > 1L) ? doname(obj) : mshot_xname(obj)); 51.  	    knm = strcpy(knmbuf, killer_xname(obj)); 52.  	    kprefix = KILLED_BY;  /* killer_name supplies "an" if warranted */ 53.  	} else { 54.  	    knm = name; 55.  	    /* [perhaps ought to check for plural here to] */ 56.  	    if (!strncmpi(name, "the ", 4) ||  57.   		    !strncmpi(name, "an ", 3) ||  58.   		    !strncmpi(name, "a ", 2)) kprefix = KILLED_BY; 59.  	}  60.   	onm = (obj && obj_is_pname(obj)) ? the(name) : 61.  			    (obj && obj->quan > 1L) ? name : an(name); 62.  	is_acid = (obj && obj->otyp == ACID_VENOM); 63.   64.   	if(u.uac + tlev <= rnd(20)) { 65.  		if(Blind || !flags.verbose) pline("It misses."); 66.  		else You("are almost hit by %s.", onm); 67.  		return(0); 68.  	} else { 69.  		if(Blind || !flags.verbose) You("are hit!"); 70.  		else You("are hit by %s%s", onm, exclam(dam)); 71.   72.   		if (obj && objects[obj->otyp].oc_material == SILVER  73.   				&& hates_silver(youmonst.data)) { 74.  			dam += rnd(20); 75.  			pline_The("silver sears your flesh!"); 76.  			exercise(A_CON, FALSE); 77.  		}  78.   		if (is_acid && Acid_resistance) 79.  			pline("It doesn't seem to hurt you."); 80.  		else { 81.  			if (is_acid) pline("It burns!"); 82.  			if (Half_physical_damage) dam = (dam+1) / 2; 83.  			losehp(dam, knm, kprefix); 84.  			exercise(A_STR, FALSE); 85.  		}  86.   		return(1); 87.  	}  88.   }  89.    90.   /* Be sure this corresponds with what happens to player-thrown objects in  91. * dothrow.c (for consistency). --KAA 92.   * Returns 0 if object still exists (not destroyed). 93.   */  94.    95.   STATIC_OVL int 96.  drop_throw(obj, ohit, x, y)  97. register struct obj *obj; 98.  boolean ohit; 99.  int x,y; 100. {  101.  	int retvalu = 1; 102. 	int create; 103. 	struct monst *mtmp; 104. 	struct trap *t; 105.  106.  	if (obj->otyp == CREAM_PIE || obj->oclass == VENOM_CLASS ||  107.  		    (ohit && obj->otyp == EGG)) 108. 		create = 0; 109. 	else if (ohit && (is_multigen(obj) || obj->otyp == ROCK)) 110. 		create = !rn2(3); 111. 	else create = 1; 112.  113.  	if (create && !((mtmp = m_at(x, y)) && (mtmp->mtrapped) && 114. 			(t = t_at(x, y)) && ((t->ttyp == PIT) ||  115.  			(t->ttyp == SPIKED_PIT)))) { 116. 		int objgone = 0; 117.  118.  		if (down_gate(x, y) != -1) 119. 			objgone = ship_object(obj, x, y, FALSE); 120. 		if (!objgone) { 121. 			if (!flooreffects(obj,x,y,"fall")) { /* don't double-dip on damage */ 122. 			    place_object(obj, x, y); 123. 			    if (!mtmp && x == u.ux && y == u.uy) 124. 				mtmp = &youmonst; 125. 			    if (mtmp && ohit) 126. 				passive_obj(mtmp, obj, (struct attack *)0); 127. 			    stackobj(obj); 128. 			    retvalu = 0; 129. 			}  130.  		}  131.  	} else obfree(obj, (struct obj*) 0); 132. 	return retvalu; 133. }  134.   135.  #endif /* OVLB */ 136. #ifdef OVL1 137.  138.  /* an object launched by someone/thing other than player attacks a monster; 139.    return 1 if the object has stopped moving (hit or its range used up) */ 140. int 141. ohitmon(mtmp, otmp, range, verbose) 142. struct monst *mtmp;	/* accidental target */ 143. struct obj *otmp;	/* missile; might be destroyed by drop_throw */ 144. int range;		/* how much farther will object travel if it misses */ 145. 			/* Use -1 to signify to keep going even after hit, */ 146. 			/* unless its gone (used for rolling_boulder_traps) */ 147. boolean verbose;  /* give message(s) even when you can't see what happened */ 148. {  149.  	int damage, tmp; 150. 	boolean vis, ismimic; 151. 	int objgone = 1; 152.  153.  	ismimic = mtmp->m_ap_type && mtmp->m_ap_type != M_AP_MONSTER; 154. 	vis = cansee(bhitpos.x, bhitpos.y); 155.  156.  	tmp = 5 + find_mac(mtmp) + omon_adj(mtmp, otmp, FALSE); 157. 	if (tmp < rnd(20)) { 158. 	    if (!ismimic) { 159. 		if (vis) miss(distant_name(otmp, mshot_xname), mtmp); 160. 		else if (verbose) pline("It is missed."); 161. 	    }  162.  	    if (!range) { /* Last position; object drops */ 163. 		(void) drop_throw(otmp, 0, mtmp->mx, mtmp->my); 164. 		return 1; 165. 	    }  166.  	} else if (otmp->oclass == POTION_CLASS) { 167. 	    if (ismimic) seemimic(mtmp); 168. 	    mtmp->msleeping = 0; 169. 	    if (vis) otmp->dknown = 1; 170. 	    potionhit(mtmp, otmp, FALSE); 171. 	    return 1; 172. 	} else { 173. 	    damage = dmgval(otmp, mtmp); 174. 	    if (otmp->otyp == ACID_VENOM && resists_acid(mtmp)) 175. 		damage = 0; 176. 	    if (ismimic) seemimic(mtmp); 177. 	    mtmp->msleeping = 0; 178. 	    if (vis) hit(distant_name(otmp,mshot_xname), mtmp, exclam(damage)); 179. 	    else if (verbose) pline("%s is hit%s", Monnam(mtmp), exclam(damage)); 180.  181.  	    if (otmp->opoisoned && is_poisonable(otmp)) { 182. 		if (resists_poison(mtmp)) { 183. 		    if (vis) pline_The("poison doesn't seem to affect %s.",  184.  				   mon_nam(mtmp)); 185. 		} else { 186. 		    if (rn2(30)) { 187. 			damage += rnd(6); 188. 		    } else { 189. 			if (vis) pline_The("poison was deadly..."); 190. 			damage = mtmp->mhp; 191. 		    }  192.  		}  193.  	    }  194.  	    if (objects[otmp->otyp].oc_material == SILVER &&  195.  		    hates_silver(mtmp->data)) { 196. 		if (vis) pline_The("silver sears %s flesh!",  197.  				s_suffix(mon_nam(mtmp))); 198. 		else if (verbose) pline("Its flesh is seared!"); 199. 	    }  200.  	    if (otmp->otyp == ACID_VENOM && cansee(mtmp->mx,mtmp->my)) { 201. 		if (resists_acid(mtmp)) { 202. 		    if (vis || verbose) 203. 			pline("%s is unaffected.", Monnam(mtmp)); 204. 		    damage = 0; 205. 		} else { 206. 		    if (vis) pline_The("acid burns %s!", mon_nam(mtmp)); 207. 		    else if (verbose) pline("It is burned!"); 208. 		}  209.  	    }  210.  	    mtmp->mhp -= damage; 211. 	    if (mtmp->mhp < 1) { 212. 		if (vis || verbose) 213. 		    pline("%s is %s!", Monnam(mtmp),  214.  			(nonliving(mtmp->data) || !canspotmon(mtmp))  215.  			? "destroyed" : "killed"); 216. 		/* don't blame hero for unknown rolling boulder trap */ 217. 		if (!flags.mon_moving &&  218.  		    (otmp->otyp != BOULDER || range >= 0 || !otmp->otrapped)) 219. 		    xkilled(mtmp,0); 220. 		else mondied(mtmp); 221. 	    }  222.   223.  	    if (can_blnd((struct monst*)0, mtmp, 224. 		    (uchar)(otmp->otyp == BLINDING_VENOM ? AT_SPIT : AT_WEAP), 225. 		    otmp)) { 226. 		if (vis && mtmp->mcansee) 227. 		    pline("%s is blinded by %s.", Monnam(mtmp), the(xname(otmp))); 228. 		mtmp->mcansee = 0; 229. 		tmp = (int)mtmp->mblinded + rnd(25) + 20; 230. 		if (tmp > 127) tmp = 127; 231. 		mtmp->mblinded = tmp; 232. 	    }  233.   234.  	    objgone = drop_throw(otmp, 1, bhitpos.x, bhitpos.y); 235. 	    if (!objgone && range == -1) {  /* special case */ 236. 		    obj_extract_self(otmp); /* free it for motion again */ 237. 		    return 0; 238. 	    }  239.  	    return 1; 240. 	}  241.  	return 0; 242. }  243.   244.  void 245. m_throw(mon, x, y, dx, dy, range, obj) 246. 	register struct monst *mon; 247. 	register int x,y,dx,dy,range;		/* direction and range */ 248. 	register struct obj *obj; 249. {  250.  	register struct monst *mtmp; 251. 	struct obj *singleobj; 252. 	char sym = obj->oclass; 253. 	int hitu, blindinc = 0; 254.  255.  	bhitpos.x = x;  256. bhitpos.y = y; 257. 258. 	if (obj->quan == 1L) { 259. 	    /*  260.  	     * Remove object from minvent. This cannot be done later on; 261. 	     * what if the player dies before then, leaving the monster 262. 	     * with 0 daggers? (This caused the infamous 2^32-1 orcish 263.  	     * dagger bug). 264. 	     *  265.  	     * VENOM is not in minvent - it should already be OBJ_FREE. 266. 	     * The extract below does nothing. 267. 	     */  268.   269.  	    /* not possibly_unwield, which checks the object's */ 270. 	    /* location, not its existence */ 271. 	    if (MON_WEP(mon) == obj) { 272. 		    setmnotwielded(mon,obj); 273. 		    MON_NOWEP(mon); 274. 	    }  275.  	    obj_extract_self(obj); 276. 	    singleobj = obj; 277. 	    obj = (struct obj *) 0; 278. 	} else { 279. 	    singleobj = splitobj(obj, 1L); 280. 	    obj_extract_self(singleobj); 281. 	}  282.   283.  	singleobj->owornmask = 0; /* threw one of multiple weapons in hand? */ 284.   285.  	if (singleobj->cursed && (dx || dy) && !rn2(7)) { 286. 	    if(canseemon(mon) && flags.verbose) { 287. 		if(is_ammo(singleobj)) 288. 		    pline("%s misfires!", Monnam(mon)); 289. 		else 290. 		    pline("%s as %s throws it!",  291.  			  Tobjnam(singleobj, "slip"), mon_nam(mon)); 292. 	    }  293.  	    dx = rn2(3)-1; 294. 	    dy = rn2(3)-1; 295. 	    /* check validity of new direction */ 296. 	    if (!dx && !dy) { 297. 		(void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); 298. 		return; 299. 	    }  300.  	}  301.   302.  	/* pre-check for doors, walls and boundaries. 303. 	   Also need to pre-check for bars regardless of direction; 304. 	   the random chance for small objects hitting bars is  305. skipped when reaching them at point blank range */ 306. 	if (!isok(bhitpos.x+dx,bhitpos.y+dy)  307.  	    || IS_ROCK(levl[bhitpos.x+dx][bhitpos.y+dy].typ)  308.  	    || closed_door(bhitpos.x+dx, bhitpos.y+dy)  309.  	    || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS && 310. 		hits_bars(&singleobj, bhitpos.x, bhitpos.y, 0, 0))) { 311. 	    (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); 312. 	    return; 313. 	}  314.   315.  	/* Note: drop_throw may destroy singleobj. Since obj must be destroyed 316. 	 * early to avoid the dagger bug, anyone who modifies this code should 317. 	 * be careful not to use either one after it's been freed. 318. 	 */  319.  	if (sym) tmp_at(DISP_FLASH, obj_to_glyph(singleobj)); 320. 	while(range-- > 0) { /* Actually the loop is always exited by break */ 321. 		bhitpos.x += dx; 322. 		bhitpos.y += dy; 323. 		if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) { 324. 		    if (ohitmon(mtmp, singleobj, range, TRUE)) 325. 			break; 326. 		} else if (bhitpos.x == u.ux && bhitpos.y == u.uy) { 327. 		    if (multi) nomul(0); 328.  329.  		    if (singleobj->oclass == GEM_CLASS &&  330.  			    singleobj->otyp <= LAST_GEM+9 /* 9 glass colors */  331.  			    && is_unicorn(youmonst.data)) { 332. 			if (singleobj->otyp > LAST_GEM) { 333. 			    You("catch the %s.", xname(singleobj)); 334. 			    You("are not interested in %s junk.",  335.  				s_suffix(mon_nam(mon))); 336. 			    makeknown(singleobj->otyp); 337. 			    dropy(singleobj); 338. 			} else { 339. 			    You("accept %s gift in the spirit in which it was intended.",  340.  				s_suffix(mon_nam(mon))); 341. 			    (void)hold_another_object(singleobj,  342.  				"You catch, but drop, %s.", xname(singleobj),  343.  				"You catch:"); 344. 			}  345.  			break; 346. 		    }  347.  		    if (singleobj->oclass == POTION_CLASS) { 348. 			if (!Blind) singleobj->dknown = 1; 349. 			potionhit(&youmonst, singleobj, FALSE); 350. 			break; 351. 		    }  352.  		    switch(singleobj->otyp) { 353. 			int dam, hitv; 354. 			case EGG: 355. 			    if (!touch_petrifies(&mons[singleobj->corpsenm])) { 356. 				impossible("monster throwing egg type %d",  357.  					singleobj->corpsenm); 358. 				hitu = 0; 359. 				break; 360. 			    }  361.  			    /* fall through */ 362. 			case CREAM_PIE: 363. 			case BLINDING_VENOM: 364. 			    hitu = thitu(8, 0, singleobj, (char *)0); 365. 			    break; 366. 			default: 367. 			    dam = dmgval(singleobj, &youmonst); 368. 			    hitv = 3 - distmin(u.ux,u.uy, mon->mx,mon->my); 369. 			    if (hitv < -4) hitv = -4; 370. 			    if (is_elf(mon->data) &&  371.  				objects[singleobj->otyp].oc_skill == P_BOW) { 372. 				hitv++; 373. 				if (MON_WEP(mon) &&  374.  				    MON_WEP(mon)->otyp == ELVEN_BOW) 375. 				    hitv++; 376. 				if(singleobj->otyp == ELVEN_ARROW) dam++; 377. 			    }  378.  			    if (bigmonst(youmonst.data)) hitv++; 379. 			    hitv += 8 + singleobj->spe; 380. 			    if (dam < 1) dam = 1; 381. 			    hitu = thitu(hitv, dam, singleobj, (char *)0); 382. 		    }  383.  		    if (hitu && singleobj->opoisoned &&  384.  			is_poisonable(singleobj)) { 385. 			char onmbuf[BUFSZ], knmbuf[BUFSZ]; 386.  387.  			Strcpy(onmbuf, xname(singleobj)); 388. 			Strcpy(knmbuf, killer_xname(singleobj)); 389. 			poisoned(onmbuf, A_STR, knmbuf, -10); 390. 		    }  391.  		    if(hitu &&  392.  		       can_blnd((struct monst*)0, &youmonst, 393. 				(uchar)(singleobj->otyp == BLINDING_VENOM ?  394.  					AT_SPIT : AT_WEAP), singleobj)) { 395. 			blindinc = rnd(25); 396. 			if(singleobj->otyp == CREAM_PIE) { 397. 			    if(!Blind) pline("Yecch!  You've been creamed."); 398. 			    else pline("There's %s sticky all over your %s.",  399.  				       something,  400.  				       body_part(FACE)); 401. 			} else if(singleobj->otyp == BLINDING_VENOM) { 402. 			    int num_eyes = eyecount(youmonst.data); 403. 			    /* venom in the eyes */ 404. 			    if(!Blind) pline_The("venom blinds you."); 405. 			    else Your("%s sting%s.",  406.  				      (num_eyes == 1) ? body_part(EYE) :  407.  						makeplural(body_part(EYE)),  408.  				      (num_eyes == 1) ? "s" : ""); 409. 			}  410.  		    }  411.  		    if (hitu && singleobj->otyp == EGG) { 412. 			if (!Stone_resistance  413.  			    && !(poly_when_stoned(youmonst.data) && 414. 				 polymon(PM_STONE_GOLEM))) { 415. 			    Stoned = 5; 416. 			    killer = (char *) 0; 417. 			}  418.  		    }  419.  		    stop_occupation; 420. 		    if (hitu || !range) { 421. 			(void) drop_throw(singleobj, hitu, u.ux, u.uy); 422. 			break; 423. 		    }  424.  		} else if (!range	/* reached end of path */  425.  			/* missile hits edge of screen */  426.  			|| !isok(bhitpos.x+dx,bhitpos.y+dy)  427.  			/* missile hits the wall */  428.  			|| IS_ROCK(levl[bhitpos.x+dx][bhitpos.y+dy].typ)  429.  			/* missile hit closed door */  430.  			|| closed_door(bhitpos.x+dx, bhitpos.y+dy)  431.  			/* missile might hit iron bars */  432.  			|| (levl[bhitpos.x+dx][bhitpos.y+dy].typ == IRONBARS && 433. 			hits_bars(&singleobj, bhitpos.x, bhitpos.y, !rn2(5), 0))  434.  #ifdef SINKS  435.  			/* Thrown objects "sink" */  436.  			|| IS_SINK(levl[bhitpos.x][bhitpos.y].typ)  437.  #endif  438.  								) { 439. 		    if (singleobj) /* hits_bars might have destroyed it */ 440. 			(void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); 441. 		    break; 442. 		}  443.  		tmp_at(bhitpos.x, bhitpos.y); 444. 		delay_output; 445. 	}  446.  	tmp_at(bhitpos.x, bhitpos.y); 447. 	delay_output; 448. 	tmp_at(DISP_END, 0); 449.  450.  	if (blindinc) { 451. 		u.ucreamed += blindinc; 452. 		make_blinded(Blinded + (long)blindinc, FALSE); 453. 		if (!Blind) Your(vision_clears); 454. 	}  455.  }  456.   457.  #endif /* OVL1 */ 458. #ifdef OVLB 459.  460.  /* Remove an item from the monster's inventory and destroy it. */ 461.  void 462. m_useup(mon, obj) 463. struct monst *mon; 464. struct obj *obj; 465. {  466.  	if (obj->quan > 1L) { 467. 		obj->quan--; 468. 		obj->owt = weight(obj); 469. 	} else { 470. 		obj_extract_self(obj); 471. 		possibly_unwield(mon, FALSE); 472. 		if (obj->owornmask) { 473. 		    mon->misc_worn_check &= ~obj->owornmask; 474. 		    update_mon_intrinsics(mon, obj, FALSE, FALSE); 475. 		}  476.  		obfree(obj, (struct obj*) 0); 477. 	}  478.  }  479.   480.  #endif /* OVLB */ 481. #ifdef OVL1 482.  483.  /* monster attempts ranged weapon attack against player */ 484. void 485. thrwmu(mtmp) 486. struct monst *mtmp; 487. {  488.  	struct obj *otmp, *mwep; 489. 	xchar x, y;  490. schar skill; 491. 	int multishot; 492. 	const char *onm; 493.  494.  	/* Rearranged beginning so monsters can use polearms not in a line */ 495. 	if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) { 496. 	    mtmp->weapon_check = NEED_RANGED_WEAPON; 497. 	    /* mon_wield_item resets weapon_check as appropriate */ 498. 	    if(mon_wield_item(mtmp) != 0) return; 499. 	}  500.   501.  	/* Pick a weapon */ 502. 	otmp = select_rwep(mtmp); 503. 	if (!otmp) return; 504.  505.  	if (is_pole(otmp)) { 506. 	    int dam, hitv; 507.  508.  	    if (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) > POLE_LIM ||  509.  		    !couldsee(mtmp->mx, mtmp->my)) 510. 		return;	/* Out of range, or intervening wall */ 511.  512.  	    if (canseemon(mtmp)) { 513. 		onm = xname(otmp); 514. 		pline("%s thrusts %s.", Monnam(mtmp),  515.  		      obj_is_pname(otmp) ? the(onm) : an(onm)); 516. 	    }  517.   518.  	    dam = dmgval(otmp, &youmonst); 519. 	    hitv = 3 - distmin(u.ux,u.uy, mtmp->mx,mtmp->my); 520. 	    if (hitv < -4) hitv = -4; 521. 	    if (bigmonst(youmonst.data)) hitv++; 522. 	    hitv += 8 + otmp->spe; 523. 	    if (dam < 1) dam = 1; 524.  525.  	    (void) thitu(hitv, dam, otmp, (char *)0); 526. 	    stop_occupation; 527. 	    return; 528. 	}  529.   530.  	x = mtmp->mx; 531. 	y = mtmp->my; 532. 	/* If you are coming toward the monster, the monster 533. 	 * should try to soften you up with missiles. If you are 534. 	 * going away, you are probably hurt or running. Give 535. 	 * chase, but if you are getting too far away, throw. 536. 	 */  537.  	if (!lined_up(mtmp) ||  538.  		(URETREATING(x,y) && 539. 			rn2(BOLT_LIM - distmin(x,y,mtmp->mux,mtmp->muy)))) 540. 	    return; 541.  542.  	skill = objects[otmp->otyp].oc_skill; 543. 	mwep = MON_WEP(mtmp);		/* wielded weapon */ 544.  545.  	/* Multishot calculations */ 546. 	multishot = 1; 547. 	if ((ammo_and_launcher(otmp, mwep) || skill == P_DAGGER || 548. 		skill == -P_DART || skill == -P_SHURIKEN) && !mtmp->mconf) { 549. 	    /* Assumes lords are skilled, princes are expert */ 550. 	    if (is_prince(mtmp->data)) multishot += 2; 551. 	    else if (is_lord(mtmp->data)) multishot++; 552.  553.  	    switch (monsndx(mtmp->data)) { 554. 	    case PM_RANGER: 555. 		    multishot++; 556. 		    break; 557. 	    case PM_ROGUE: 558. 		    if (skill == P_DAGGER) multishot++; 559. 		    break; 560. 	    case PM_NINJA: 561. 	    case PM_SAMURAI: 562. 		    if (otmp->otyp == YA && mwep &&  563.  			mwep->otyp == YUMI) multishot++; 564. 		    break; 565. 	    default: 566. 		break; 567. 	    }  568.  	    /* racial bonus */ 569. 	    if ((is_elf(mtmp->data) && 570. 		    otmp->otyp == ELVEN_ARROW && 571. 		    mwep && mwep->otyp == ELVEN_BOW) ||  572.  		(is_orc(mtmp->data) && 573. 		    otmp->otyp == ORCISH_ARROW && 574. 		    mwep && mwep->otyp == ORCISH_BOW)) 575. 		multishot++; 576.  577.  	    if ((long)multishot > otmp->quan) multishot = (int)otmp->quan; 578. 	    if (multishot < 1) multishot = 1; 579. 	    else multishot = rnd(multishot); 580. 	}  581.   582.  	if (canseemon(mtmp)) { 583. 	    char onmbuf[BUFSZ]; 584.  585.  	    if (multishot > 1) { 586. 		/* "N arrows"; multishot > 1 implies otmp->quan > 1, so  587. xname's result will already be pluralized */ 588. 		Sprintf(onmbuf, "%d %s", multishot, xname(otmp)); 589. 		onm = onmbuf; 590. 	    } else { 591. 		/* "an arrow" */ 592. 		onm = singular(otmp, xname); 593. 		onm = obj_is_pname(otmp) ? the(onm) : an(onm); 594. 	    }  595.  	    m_shot.s = ammo_and_launcher(otmp,mwep) ? TRUE : FALSE; 596. 	    pline("%s %s %s!", Monnam(mtmp),  597.  		  m_shot.s ? "shoots" : "throws", onm); 598. 	    m_shot.o = otmp->otyp; 599. 	} else { 600. 	    m_shot.o = STRANGE_OBJECT;	/* don't give multishot feedback */ 601. 	}  602.   603.  	m_shot.n = multishot; 604. 	for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) 605. 	    m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),  606.  		    distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp); 607. 	m_shot.n = m_shot.i = 0; 608. 	m_shot.o = STRANGE_OBJECT; 609. 	m_shot.s = FALSE; 610.  611.  	nomul(0); 612. }  613.   614.  #endif /* OVL1 */ 615. #ifdef OVLB 616.  617.  int 618. spitmu(mtmp, mattk)		/* monster spits substance at you */ 619. register struct monst *mtmp; 620. register struct attack *mattk; 621. {  622.  	register struct obj *otmp; 623.  624.  	if(mtmp->mcan) { 625.  626.  	    if(flags.soundok) 627. 		pline("A dry rattle comes from %s throat.",  628.  		                      s_suffix(mon_nam(mtmp))); 629. 	    return 0; 630. 	}  631.  	if(lined_up(mtmp)) { 632. 		switch (mattk->adtyp) { 633. 		    case AD_BLND: 634. 		    case AD_DRST: 635. 			otmp = mksobj(BLINDING_VENOM, TRUE, FALSE); 636. 			break; 637. 		    default: 638. 			impossible("bad attack type in spitmu"); 639. 				/* fall through */ 640. 		    case AD_ACID: 641. 			otmp = mksobj(ACID_VENOM, TRUE, FALSE); 642. 			break; 643. 		}  644.  		if(!rn2(BOLT_LIM-distmin(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy))) { 645. 		    if (canseemon(mtmp)) 646. 			pline("%s spits venom!", Monnam(mtmp)); 647. 		    m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),  648.  			distmin(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy), otmp); 649. 		    nomul(0); 650. 		    return 0; 651. 		}  652.  	}  653.  	return 0; 654. }  655.   656.  #endif /* OVLB */ 657. #ifdef OVL1 658.  659.  int 660. breamu(mtmp, mattk)			/* monster breathes at you (ranged) */ 661. 	register struct monst *mtmp; 662. 	register struct attack  *mattk; 663. {  664.  	/* if new breath types are added, change AD_ACID to max type */ 665. 	int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp ; 666.  667.  	if(lined_up(mtmp)) { 668.  669.  	    if(mtmp->mcan) { 670. 		if(flags.soundok) { 671. 		    if(canseemon(mtmp)) 672. 			pline("%s coughs.", Monnam(mtmp)); 673. 		    else 674. 			You_hear("a cough."); 675. 		}  676.  		return(0); 677. 	    }  678.  	    if(!mtmp->mspec_used && rn2(3)) { 679.  680.  		if((typ >= AD_MAGM) && (typ <= AD_ACID)) { 681.  682.  		    if(canseemon(mtmp)) 683. 			pline("%s breathes %s!", Monnam(mtmp),  684.  			      breathwep[typ-1]); 685. 		    buzz((int) (-20 - (typ-1)), (int)mattk->damn,  686.  			 mtmp->mx, mtmp->my, sgn(tbx), sgn(tby)); 687. 		    nomul(0); 688. 		    /* breath runs out sometimes. Also, give monster some 689. 		     * cunning; don't breath if the player fell asleep. 690. 		     */  691.  		    if(!rn2(3)) 692. 			mtmp->mspec_used = 10+rn2(20); 693. 		    if(typ == AD_SLEE && !Sleep_resistance) 694. 			mtmp->mspec_used += rnd(20); 695. 		} else impossible("Breath weapon %d used", typ-1); 696. 	    }  697.  	}  698.  	return(1); 699. }  700.   701.  boolean 702. linedup(ax, ay, bx, by) 703. register xchar ax, ay, bx, by; 704. {  705.  	tbx = ax - bx;	/* These two values are set for use */ 706. 	tby = ay - by;	/* after successful return. */ 707.   708.  	/* sometimes displacement makes a monster think that you're at its 709. 	   own location; prevent it from throwing and zapping in that case */ 710. 	if (!tbx && !tby) return FALSE; 711.  712.  	if((!tbx || !tby || abs(tbx) == abs(tby)) /* straight line or diagonal */  713.  	   && distmin(tbx, tby, 0, 0) < BOLT_LIM) { 714. 	    if(ax == u.ux && ay == u.uy) return((boolean)(couldsee(bx,by))); 715. 	    else if(clear_path(ax,ay,bx,by)) return TRUE; 716. 	}  717.  	return FALSE; 718. }  719.   720.  boolean 721. lined_up(mtmp)		/* is mtmp in position to use ranged attack? */ 722.  	register struct monst *mtmp; 723. {  724.  	return(linedup(mtmp->mux,mtmp->muy,mtmp->mx,mtmp->my)); 725. }  726.   727.  #endif /* OVL1 */ 728. #ifdef OVL0 729.  730.  /* Check if a monster is carrying a particular item. 731.  */  732.  struct obj * 733. m_carrying(mtmp, type) 734. struct monst *mtmp; 735. int type; 736. {  737.  	register struct obj *otmp; 738.  739.  	for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj) 740. 		if(otmp->otyp == type) 741. 			return(otmp); 742. 	return((struct obj *) 0); 743. }  744.   745.  /* TRUE iff thrown/kicked/rolled object doesn't pass through iron bars */ 746. boolean 747. hits_bars(obj_p, x, y, always_hit, whodidit) 748. struct obj **obj_p;	/* *obj_p will be set to NULL if object breaks */ 749. int x, y;  750. int always_hit;	/* caller can force a hit for items which would fit through */ 751. int whodidit;	/* 1==hero, 0=other, -1==just check whether it'll pass thru */ 752. {  753.      struct obj *otmp = *obj_p; 754.     int obj_type = otmp->otyp; 755.     boolean hits = always_hit; 756.  757.      if (!hits) 758. 	switch (otmp->oclass) { 759. 	case WEAPON_CLASS: 760. 	    {  761.  		int oskill = objects[obj_type].oc_skill; 762.  763.  		hits = (oskill != -P_BOW  && oskill != -P_CROSSBOW &&  764.  			oskill != -P_DART && oskill != -P_SHURIKEN &&  765.  			oskill != P_SPEAR && oskill != P_JAVELIN &&  766.  			oskill != P_KNIFE);	/* but not dagger */ 767. 		break; 768. 	    }  769.  	case ARMOR_CLASS: 770. 		hits = (objects[obj_type].oc_armcat != ARM_GLOVES); 771. 		break; 772. 	case TOOL_CLASS: 773. 		hits = (obj_type != SKELETON_KEY &&  774.  			obj_type != LOCK_PICK &&  775.  #ifdef TOURIST  776.  			obj_type != CREDIT_CARD &&  777.  #endif  778.  			obj_type != TALLOW_CANDLE &&  779.  			obj_type != WAX_CANDLE &&  780.  			obj_type != LENSES &&  781.  			obj_type != TIN_WHISTLE &&  782.  			obj_type != MAGIC_WHISTLE); 783. 		break; 784. 	case ROCK_CLASS:	/* includes boulder */ 785. 		if (obj_type != STATUE ||  786.  			mons[otmp->corpsenm].msize > MZ_TINY) hits = TRUE; 787. 		break; 788. 	case FOOD_CLASS: 789. 		if (obj_type == CORPSE &&  790.  			mons[otmp->corpsenm].msize > MZ_TINY) hits = TRUE; 791. 		else 792. 		    hits = (obj_type == MEAT_STICK ||  793.  			    obj_type == HUGE_CHUNK_OF_MEAT); 794. 		break; 795. 	case SPBOOK_CLASS: 796. 	case WAND_CLASS: 797. 	case BALL_CLASS: 798. 	case CHAIN_CLASS: 799. 		hits = TRUE; 800. 		break; 801. 	default: 802. 		break; 803. 	}  804.   805.      if (hits && whodidit != -1) { 806. 	if (whodidit ? hero_breaks(otmp, x, y, FALSE) : breaks(otmp, x, y)) 807. 	    *obj_p = otmp = 0;		/* object is now gone */ 808. 	    /* breakage makes its own noises */ 809. 	else if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL) 810. 	    pline("Whang!"); 811. 	else if (otmp->oclass == COIN_CLASS ||  812.  		objects[obj_type].oc_material == GOLD ||  813.  		objects[obj_type].oc_material == SILVER) 814. 	    pline("Clink!"); 815. 	else 816. 	    pline("Clonk!"); 817.     }  818.   819.      return hits; 820. }  821.   822.  #endif /* OVL0 */ 823.  824.  /*mthrowu.c*/