Source:NetHack 3.1.0/mthrowu.c

Below is the full text to mthrowu.c from the source code of NetHack 3.1.0. To link to a particular line, write [[NetHack 3.1.0/mthrowu.c#line123 ]], for example.

Warning! This is the source code from an old release. For the latest release, see Source code

1.   /*	SCCS Id: @(#)mthrowu.c	3.1	92/11/14	*/ 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 void FDECL(drop_throw,(struct obj *,BOOLEAN_P,int,int)); 8.   #ifndef MUSE 9.   STATIC_DCL void FDECL(m_throw,(struct monst *,int,int,int,int,int,struct obj *)); 10.  #endif 11.   12.   #define URETREATING(x,y) (distmin(u.ux,u.uy,x,y) > distmin(u.ux0,u.uy0,x,y)) 13.   14.   boolean FDECL(lined_up, (struct monst *)); 15.   16.   #ifndef OVLB 17.   18.   STATIC_DCL const char *breathwep[]; 19.   20.   #else /* OVLB */ 21.   22.   /*  23.    * Keep consistent with breath weapons in zap.c, and AD_* in monattk.h.  24. */ 25.   STATIC_OVL const char NEARDATA *breathwep[] = { 26.  				"fragments", 27.  				"fire", 28.  				"frost", 29.  				"sleep gas", 30.  				"death", 31.  				"lightning", 32.  				"poison gas", 33.  				"acid", 34.  				"strange breath #8", 35.  				"strange breath #9" 36.  };  37.    38.   int 39.  thitu(tlev, dam, obj, name)	/* u is hit by sth, but not a monster */ 40.  	register int tlev, dam; 41.  	struct obj *obj; 42.  	register const char *name; 43.  {  44.   	const char *onm = (obj && obj_is_pname(obj)) ? the(name) : an(name); 45.  	boolean is_acid = (obj && obj->otyp == ACID_VENOM); 46.   47.   	if(u.uac + tlev <= rnd(20)) { 48.  		if(Blind || !flags.verbose) pline("It misses."); 49.  		else You("are almost hit by %s!", onm); 50.  		return(0); 51.  	} else { 52.  		if(Blind || !flags.verbose) You("are hit!"); 53.  		else You("are hit by %s!", onm); 54.  #ifdef POLYSELF 55.  		if (obj && objects[obj->otyp].oc_material == SILVER  56.   				&& hates_silver(uasmon)) { 57.  			dam += rnd(20); 58.  			pline("The silver sears your flesh!"); 59.  			exercise(A_CON, FALSE); 60.  		}  61.   		if (is_acid && resists_acid(uasmon)) 62.  			pline("It doesn't seem to hurt you."); 63.  		else { 64.  #endif 65.  			if (is_acid) pline("It burns!"); 66.  			if (Half_physical_damage) dam = (dam+1) / 2; 67.  			losehp(dam, name, (obj && obj_is_pname(obj)) ?  68.   			       KILLED_BY : KILLED_BY_AN); 69.  			exercise(A_STR, FALSE); 70.  #ifdef POLYSELF 71.  		}  72.   #endif 73.  		return(1); 74.  	}  75.   }  76.    77.   /* Be sure this corresponds with what happens to player-thrown objects in  78. * dothrow.c (for consistency). --KAA 79.   */  80.    81.   STATIC_OVL void 82.  drop_throw(obj, ohit, x, y)  83. register struct obj *obj; 84.  boolean ohit; 85.  int x,y; 86.  {  87.   	int create; 88.  	struct monst *mtmp; 89.  	struct trap *t; 90.   91.   	if (obj->otyp == CREAM_PIE || obj->oclass == VENOM_CLASS) 92.  		create = 0; 93.  	else if (ohit &&  94.   		 ((obj->otyp >= ARROW && obj->otyp <= SHURIKEN) || 95.  		  obj->otyp == ROCK)) 96.  		create = !rn2(3); 97.  	else create = 1; 98.  	if (create && !((mtmp = m_at(x, y)) && (mtmp->mtrapped) && 99.  			(t = t_at(x, y)) && ((t->ttyp == PIT) ||  100.  			(t->ttyp == SPIKED_PIT))) &&  101.  	    !flooreffects(obj,x,y,"fall")) { /* don't double-dip on damage */ 102. 		place_object(obj, x, y); 103. 		obj->nobj = fobj; 104. 		fobj = obj; 105. 		stackobj(fobj); 106. 	} else obfree(obj, (struct obj*) 0); 107. }  108.   109.  #endif /* OVLB */ 110. #ifdef OVL1 111.  112.  #ifndef MUSE 113. STATIC_OVL 114. #endif 115. void 116. m_throw(mon, x, y, dx, dy, range, obj) 117. 	register struct monst *mon; 118. 	register int x,y,dx,dy,range;		/* direction and range */ 119. 	register struct obj *obj; 120. {  121.  	register struct monst *mtmp; 122. 	struct obj *singleobj; 123. 	char sym = obj->oclass; 124. 	int damage; 125. 	int hitu, blindinc=0; 126.  127.  	bhitpos.x = x;  128. bhitpos.y = y; 129. 130. 	singleobj = splitobj(obj, obj->quan - 1L); 131. 	/* splitobj leaves the new object in the chain (i.e. the monster's  132.  	 * inventory). Remove it. We can do this in 1 line, but it's highly 133. 	 * dependent on the fact that we know splitobj places it immediately 134. 	 * after obj. 135. 	 */  136.  	obj->nobj = singleobj->nobj; 137. 	/* Get rid of object. This cannot be done later on; what if the 138. 	 * player dies before then, leaving the monster with 0 daggers? 139. 	 * (This caused the infamous 2^32-1 orcish dagger bug). 140. 	 */  141.  	if (!obj->quan) { 142. 	    if(obj->oclass == VENOM_CLASS) { 143. 		/* venom is not in the monster's inventory chain */ 144. 		dealloc_obj(obj); 145. 	    } else { 146. #ifdef MUSE 147. 		/* not possibly_unwield, which checks the object's */ 148. 		/* location, not its existence */ 149. 		if (MON_WEP(mon) == obj) 150. 			MON_NOWEP(mon); 151. #endif 152. 		m_useup(mon, obj); 153. 	    }  154.  	}  155.   156.  	if (singleobj->cursed && (dx || dy) && !rn2(7)) { 157. 	    if(canseemon(mon) && flags.verbose) { 158. 		if((singleobj->oclass == WEAPON_CLASS || 159. 						singleobj->oclass == GEM_CLASS)  160.  		   && objects[singleobj->otyp].w_propellor) 161. 		    pline("%s misfires!", Monnam(mon)); 162. 		else 163. 		    pline("The %s slips as %s throws it!",  164.  			  xname(singleobj), mon_nam(mon)); 165. 	    }  166.  	    dx = rn2(3)-1; 167. 	    dy = rn2(3)-1; 168. 	    /* pre-check validity of new direction */ 169. 	    if((!dx && !dy)  170.  	       || !isok(bhitpos.x+dx,bhitpos.y+dy)  171.  	       /* missile hits the wall */  172.  	       || IS_WALL(levl[bhitpos.x+dx][bhitpos.y+dy].typ)  173.  	       || levl[bhitpos.x+dx][bhitpos.y+dy].typ == SDOOR  174.  	       || levl[bhitpos.x+dx][bhitpos.y+dy].typ == SCORR) { 175. 		drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); 176. 		return; 177. 	    }  178.  	}  179.   180.  	/* Note: drop_throw may destroy singleobj. Since obj must be destroyed 181. 	 * early to avoid the dagger bug, anyone who modifies this code should 182. 	 * be careful not to use either one after it's been freed. 183. 	 */  184.  	if (sym) tmp_at(DISP_FLASH, obj_to_glyph(singleobj)); 185. 	while(range-- > 0) { /* Actually the loop is always exited by break */ 186. 		boolean vis; 187.  188.  		bhitpos.x += dx; 189. 		bhitpos.y += dy; 190. 		vis = cansee(bhitpos.x, bhitpos.y); 191. 		if(MON_AT(bhitpos.x, bhitpos.y)) { 192. 		    boolean ismimic; 193.  194.  		    mtmp = m_at(bhitpos.x,bhitpos.y); 195. 		    ismimic = mtmp->m_ap_type && 196. 			mtmp->m_ap_type != M_AP_MONSTER; 197.  198.  		    /* don't use distance/size modifiers since target was u */ 199. 		    if(find_mac(mtmp) + 8 + singleobj->spe <= rnd(20)) { 200. 			if (!ismimic) { 201. 			    if (!vis) pline("It is missed."); 202. 			    else miss(distant_name(singleobj,xname), mtmp); 203. 			}  204.  			if (!range) { /* Last position; object drops */ 205. 			    drop_throw(singleobj, 0, mtmp->mx, mtmp->my); 206. 			    break; 207. 			}  208.  #ifdef MUSE 209. 		    } else if (singleobj->oclass == POTION_CLASS) { 210. 			if (ismimic) seemimic(mtmp); 211. 			if (vis) singleobj->dknown = 1; 212. 			potionhit(mtmp, singleobj); 213. 			break; 214. #endif 215. 		    } else { 216. 			damage = dmgval(singleobj, mtmp->data); 217. 			if (damage < 1) damage = 1; 218. 			if (singleobj->otyp==ACID_VENOM && resists_acid(mtmp->data)) 219. 			    damage = 0; 220. 			if (ismimic) seemimic(mtmp); 221. 			if (!vis) pline("It is hit%s", exclam(damage)); 222. 			else hit(distant_name(singleobj,xname),  223.  							mtmp,exclam(damage)); 224. 			if (singleobj->opoisoned) { 225. 			    if (resists_poison(mtmp->data)) { 226. 				if (vis) 227. 				  pline("The poison doesn't seem to affect %s.",  228.  								mon_nam(mtmp)); 229. 			    } else { 230. 				if (rn2(30)) damage += rnd(6); 231. 				else { 232. 				    if (vis) 233. 					pline("The poison was deadly..."); 234. 				    damage = mtmp->mhp; 235. 				}  236.  			    }  237.  			}  238.  			if (objects[singleobj->otyp].oc_material == SILVER  239.  				&& hates_silver(mtmp->data)) { 240. 			    if (vis) pline("The silver sears %s's flesh!",  241.  				mon_nam(mtmp)); 242. 			    else pline("Its flesh is seared!"); 243. 			}  244.  			if (singleobj->otyp==ACID_VENOM && cansee(mtmp->mx,mtmp->my)){ 245. 			    if (resists_acid(mtmp->data)) { 246. 				pline("%s is unaffected.", vis ? Monnam(mtmp)  247.  					: "It"); 248. 				damage = 0; 249. 			    } else if (vis) 250. 				pline("The acid burns %s!", mon_nam(mtmp)); 251. 			    else pline("It is burned!"); 252. 			}  253.  			mtmp->mhp -= damage; 254. 			if(mtmp->mhp < 1) { 255. 			    pline("%s is %s!", vis ? Monnam(mtmp) : "It",  256.  			       (is_demon(mtmp->data) || 257. 					is_undead(mtmp->data) || !vis) ?  258.  				 "destroyed" : "killed"); 259. 			    mondied(mtmp); 260. 			}  261.   262.  			if(((singleobj->otyp == CREAM_PIE) || 263. 			    (singleobj->otyp == BLINDING_VENOM))  264.  			   && haseyes(mtmp->data)) { 265. 			    if (vis) 266. 				pline("%s is blinded by %s.",  267.  				      Monnam(mtmp), the(xname(singleobj))); 268. 			    if(mtmp->msleep) mtmp->msleep = 0; 269. 			    mtmp->mcansee = 0; 270. 			    {  271.  				register unsigned rnd_tmp = rnd(25) + 20; 272. 				if((mtmp->mblinded + rnd_tmp) > 127) 273. 					mtmp->mblinded = 127; 274. 				else mtmp->mblinded += rnd_tmp; 275. 			    }  276.  			}  277.  			drop_throw(singleobj, 1, bhitpos.x, bhitpos.y); 278. 			break; 279. 		    }  280.  		}  281.  		if (bhitpos.x == u.ux && bhitpos.y == u.uy) { 282. 			if (multi) nomul(0); 283.  284.  #ifdef MUSE 285. 			if (singleobj->oclass == POTION_CLASS) { 286. 			    if (!Blind) singleobj->dknown = 1; 287. 			    potionhit(&youmonst, singleobj); 288. 			    break; 289. 			}  290.  #endif 291. 			switch(singleobj->otyp) { 292. 			    int dam, hitv; 293. 			    case CREAM_PIE: 294. 			    case BLINDING_VENOM: 295. 				hitu = thitu(8, 0, singleobj, xname(singleobj)); 296. 				break; 297. 			    default: 298. 				dam = dmgval(singleobj, uasmon); 299. 				hitv = 3 - distmin(u.ux,u.uy, mon->mx,mon->my); 300. 				if (hitv < -4) hitv = -4; 301. 				if (is_elf(mon->data) &&  302.  				    objects[singleobj->otyp].w_propellor  303.  								== WP_BOW) { 304. 				    hitv++; 305. #ifdef MUSE 306. 				    if (MON_WEP(mon) &&  307.  					MON_WEP(mon)->otyp == ELVEN_BOW) 308. 					hitv++; 309. #endif 310. 				    if(singleobj->otyp == ELVEN_ARROW) dam++; 311. 				}  312.  #ifdef POLYSELF 313. 				if (bigmonst(uasmon)) hitv++; 314. #endif 315. 				hitv += 8+singleobj->spe; 316.  317.  				if (dam < 1) dam = 1; 318. 				hitu = thitu(hitv, dam,  319.  					singleobj, xname(singleobj)); 320. 			}  321.  			if (hitu && singleobj->opoisoned) 322. 			    /* it's safe to call xname twice because it's the 323. 			       same object both times... */ 324.  			    poisoned(xname(singleobj), A_STR, xname(singleobj), 10); 325. 			if(hitu && (singleobj->otyp == CREAM_PIE || 326. 				     singleobj->otyp == BLINDING_VENOM)) { 327. 			    blindinc = rnd(25); 328. 			    if(singleobj->otyp == CREAM_PIE) { 329. 				if(!Blind) pline("Yecch!  You've been creamed."); 330. 				else	pline("There's something sticky all over your %s.", body_part(FACE)); 331. 			    } else {	/* venom in the eyes */ 332. 				if(Blindfolded) /* nothing */ ; 333. 				else if(!Blind) pline("The venom blinds you."); 334. 				else	Your("%s sting.",  335.  					makeplural(body_part(EYE))); 336. 			    }  337.  			}  338.  			stop_occupation; 339. 			if (hitu || !range) { 340. 			    drop_throw(singleobj, hitu, u.ux, u.uy); 341. 			    break; 342. 			}  343.  		} else if (!range	/* reached end of path */  344.  			/* missile hits edge of screen */  345.  			|| !isok(bhitpos.x+dx,bhitpos.y+dy)  346.  			/* missile hits the wall */  347.  			|| IS_WALL(levl[bhitpos.x+dx][bhitpos.y+dy].typ)  348.  			|| levl[bhitpos.x+dx][bhitpos.y+dy].typ == SDOOR  349.  			|| levl[bhitpos.x+dx][bhitpos.y+dy].typ == SCORR  350.  #ifdef SINKS  351.  			/* Thrown objects "sink" */  352.  			|| IS_SINK(levl[bhitpos.x][bhitpos.y].typ)  353.  #endif  354.  								) { 355. 		    drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); 356. 		    break; 357. 		}  358.  		tmp_at(bhitpos.x, bhitpos.y); 359. 		delay_output; 360. 	}  361.  	tmp_at(bhitpos.x, bhitpos.y); 362. 	delay_output; 363. 	tmp_at(DISP_END, 0); 364. 	/* blindfold keeps substances out of your eyes */ 365. 	if (blindinc && !Blindfolded) { 366. 		u.ucreamed += blindinc; 367. 		make_blinded(Blinded + blindinc,FALSE); 368. 	}  369.  }  370.   371.  #endif /* OVL1 */ 372. #ifdef OVLB 373.  374.  /* Remove an item from the monster's inventory. 375.  */  376.  void 377. m_useup(mon, obj) 378. struct monst *mon; 379. struct obj *obj; 380. {  381.  	struct obj *otmp, *prev; 382.  383.  	if (obj->quan > 1L) { 384. 		obj->quan--; 385. 		return; 386. 	}  387.  	prev = ((struct obj *) 0); 388. 	for (otmp = mon->minvent; otmp; otmp = otmp->nobj) { 389. 		if (otmp == obj) { 390. 			if (prev) 391. 				prev->nobj = obj->nobj; 392. 			else 393. 				mon->minvent = obj->nobj; 394. 			dealloc_obj(obj); 395. 			break; 396. 		}  397.  		prev = otmp; 398. 	}  399.  }  400.   401.  #endif /* OVLB */ 402. #ifdef OVL1 403.  404.  void 405. thrwmu(mtmp)	/* monster throws item at you */ 406. register struct monst *mtmp; 407. {  408.  	struct obj *otmp; 409. 	register xchar x, y;  410. 411. 	if(lined_up(mtmp)) { 412. #ifdef MUSE 413. 	    if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) { 414. 		mtmp->weapon_check = NEED_RANGED_WEAPON; 415. 		/* mon_wield_item resets weapon_check as appropriate */ 416. 		if(mon_wield_item(mtmp) != 0) return; 417. 	    }  418.  #endif 419. 	    if((otmp = select_rwep(mtmp))) { 420. 		/* If you are coming toward the monster, the monster 421. 		 * should try to soften you up with missiles. If you are 422. 		 * going away, you are probably hurt or running. Give 423. 		 * chase, but if you are getting too far away, throw. 424. 		 */  425.  		x = mtmp->mx; 426. 		y = mtmp->my; 427. 		if(!URETREATING(x,y) ||  428.  		   !rn2(BOLT_LIM-distmin(x,y,mtmp->mux,mtmp->muy))) 429. 		{  430.  		    const char *verb = "throws"; 431.  432.  		    if (otmp->otyp == ARROW  433.  			|| otmp->otyp == ELVEN_ARROW  434.  			|| otmp->otyp == ORCISH_ARROW  435.  			|| otmp->otyp == CROSSBOW_BOLT) verb = "shoots"; 436. 		    if (canseemon(mtmp)) { 437. 			pline("%s %s %s!", Monnam(mtmp), verb,  438.  			      obj_is_pname(otmp) ?  439.  			      the(singular(otmp, xname)) :  440.  			      an(singular(otmp, xname))); 441. 		    }  442.  		    m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),  443.  			distmin(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy), otmp); 444. 		    nomul(0); 445. 		    return; 446. 		}  447.  	    }  448.  	}  449.  }  450.   451.  #endif /* OVL1 */ 452. #ifdef OVLB 453.  454.  int 455. spitmu(mtmp, mattk)		/* monster spits substance at you */ 456. register struct monst *mtmp; 457. register struct attack *mattk; 458. {  459.  	register struct obj *otmp; 460.  461.  	if(mtmp->mcan) { 462.  463.  	    if(flags.soundok) 464. 		pline("A dry rattle comes from %s throat",  465.  		                      s_suffix(mon_nam(mtmp))); 466. 	    return 0; 467. 	}  468.  	if(lined_up(mtmp)) { 469. 		switch (mattk->adtyp) { 470. 		    case AD_BLND: 471. 		    case AD_DRST: 472. 			otmp = mksobj(BLINDING_VENOM, TRUE, FALSE); 473. 			break; 474. 		    default: 475. 			impossible("bad attack type in spitmu"); 476. 				/* fall through */ 477. 		    case AD_ACID: 478. 			otmp = mksobj(ACID_VENOM, TRUE, FALSE); 479. 			break; 480. 		}  481.  		if(!rn2(BOLT_LIM-distmin(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy))) { 482. 		    if (canseemon(mtmp)) 483. 			pline("%s spits venom!", Monnam(mtmp)); 484. 		    m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),  485.  			distmin(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy), otmp); 486. 		    nomul(0); 487. 		    return 0; 488. 		}  489.  	}  490.  	return 0; 491. }  492.   493.  #endif /* OVLB */ 494. #ifdef OVL1 495.  496.  int 497. breamu(mtmp, mattk)			/* monster breathes at you (ranged) */ 498. 	register struct monst *mtmp; 499. 	register struct attack  *mattk; 500. {  501.  	/* if new breath types are added, change AD_ACID to max type */ 502. 	int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp ; 503.  504.  	if(lined_up(mtmp)) { 505.  506.  	    if(mtmp->mcan) { 507. 		if(flags.soundok) { 508. 		    if(canseemon(mtmp)) 509. 			pline("%s coughs.", Monnam(mtmp)); 510. 		    else 511. 			You("hear a cough."); 512. 		}  513.  		return(0); 514. 	    }  515.  	    if(!mtmp->mspec_used && rn2(3)) { 516.  517.  		if((typ >= AD_MAGM) && (typ <= AD_ACID)) { 518.  519.  		    if(canseemon(mtmp)) 520. 			pline("%s breathes %s!", Monnam(mtmp),  521.  			      breathwep[typ-1]); 522. 		    buzz((int) (-20 - (typ-1)), (int)mattk->damn,  523.  			 mtmp->mx, mtmp->my, sgn(tbx), sgn(tby)); 524. 		    nomul(0); 525. 		    /* breath runs out sometimes. Also, give monster some 526. 		     * cunning; don't breath if the player fell asleep. 527. 		     */  528.  		    if(!rn2(3)) 529. 			mtmp->mspec_used = 10+rn2(20); 530. 		    if(typ == AD_SLEE && !Sleep_resistance) 531. 			mtmp->mspec_used += rnd(20); 532. 		} else impossible("Breath weapon %d used", typ-1); 533. 	    }  534.  	}  535.  	return(1); 536. }  537.   538.  boolean 539. linedup(ax, ay, bx, by) 540. register xchar ax, ay, bx, by; 541. {  542.  	tbx = ax - bx;	/* These two values are set for use */ 543. 	tby = ay - by;	/* after successful return. */ 544.   545.  	if((!tbx || !tby || abs(tbx) == abs(tby)) /* straight line or diagonal */  546.  	   && distmin(tbx, tby, 0, 0) < BOLT_LIM) { 547.  548.  	    if(ax == u.ux && ay == u.uy) return couldsee(bx,by); 549. 	    else if(clear_path(ax,ay,bx,by)) return TRUE; 550. 	}  551.  	return FALSE; 552. }  553.   554.  boolean 555. lined_up(mtmp)		/* is mtmp in position to use ranged attack? */ 556.  	register struct monst *mtmp; 557. {  558.  	return(linedup(mtmp->mux,mtmp->muy,mtmp->mx,mtmp->my)); 559. }  560.   561.  #endif /* OVL1 */ 562. #ifdef OVL0 563.  564.  /* Check if a monster is carrying a particular item. 565.  */  566.  struct obj * 567. m_carrying(mtmp, type) 568. struct monst *mtmp; 569. int type; 570. {  571.  	register struct obj *otmp; 572.  573.  	for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj) 574. 		if(otmp->otyp == type) 575. 			return(otmp); 576. 	return((struct obj *) 0); 577. }  578.   579.  #endif /* OVL0 */ 580.  581.  /*mthrowu.c*/