Source:NetHack 3.0.0/mthrowu.c

Below is the full text to mthrowu.c from the source code of NetHack 3.0.0. To link to a particular line, write [[NetHack 3.0.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.0	88/04/13 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 int movedist; 8.    9.    #define URETREATING(x,y) (movedist(u.ux,u.uy,x,y) > movedist(u.ux0,u.uy0,x,y)) 10.   11.   boolean lined_up; 12.   13.   schar	tbx = 0, tby = 0;	/* used for direction of throw, buzz, etc. */ 14.   15.   const char *breathwep[] = {	"fragments", 16.  				"fire", 17.  				"sleep gas", 18.  				"frost", 19.  				"death", 20.  				"lightning", 21.  				"poison gas", 22.  				"acid" 23.  };  24.    25.   int 26.  thitu(tlev, dam, name)	/* u is hit by sth, but not a monster */ 27.  	register int tlev, dam; 28.  	register char *name; 29.  {  30.   	char buf[BUFSZ]; 31.  	boolean acidic = (!strcmp(name, "splash of venom") && dam); 32.  	/* A horrible kludge... the problem is that we want to do something 33.  	 * special--and we can't do it after returning since we might die and 34.  	 * not return, but the special stuff should be done anyway...  35. */ 36.    37.   	setan(name, buf); 38.  	if(u.uac + tlev <= rnd(20)) { 39.  		if(Blind || !flags.verbose) pline("It misses."); 40.  		else You("are almost hit by %s!", buf); 41.  		return(0); 42.  	} else { 43.  		if(Blind || !flags.verbose) You("are hit!"); 44.  		else You("are hit by %s!", buf); 45.  		Strcpy(buf,name); 46.  		/* If name came from xname we must copy it, otherwise if  47. * you die, the possession identify will call xname, 48.  		 * overwriting xname's buffer, and your tombstone will say 49.  		 * you were killed by a green gem or some such. 50.  		 */  51.   #ifdef POLYSELF 52.  		if (acidic && resists_acid(uasmon)) 53.  			pline("It doesn't seem to hurt you."); 54.  		else { 55.  #endif 56.  			if (acidic) pline("It burns!"); 57.  			losehp(dam, buf); 58.  #ifdef POLYSELF 59.  		}  60.   #endif 61.  		return(1); 62.  	}  63.   }  64.    65.   /* Be sure this corresponds with what happens to player-thrown objects in  66. * dothrow.c (for consistency). --KAA 67.   */  68.   static void 69.  drop_throw(obj, ohit, x, y)  70. register struct obj *obj; 71.  boolean ohit; 72.  int x,y; 73.  {  74.   	int create; 75.   76.   	if (obj->otyp == CREAM_PIE || obj->olet == VENOM_SYM) 77.  		create = 0; 78.  	else if (ohit &&  79.   		 ((obj->otyp >= ARROW && obj->otyp <= SHURIKEN) || 80.  		  obj->otyp == ROCK)) 81.  		create = !rn2(3); 82.  	else create = 1; 83.  	if (create && !flooreffects(obj,x,y)) { 84.  		obj->ox = x;  85. obj->oy = y; 86. obj->nobj = fobj; 87.  		fobj = obj; 88.  		stackobj(fobj); 89.  		levl[x][y].omask = 1; 90.  	} else free((genericptr_t)obj); 91.  }  92.    93.   static void 94.  m_throw(x, y, dx, dy, range, obj) 95.  	register int x,y,dx,dy,range;		/* direction and range */ 96.  	register struct obj *obj; 97.  {  98.   	register struct monst *mtmp; 99.  	struct obj *singleobj; 100. 	char sym = obj->olet; 101. 	int damage; 102. 	int hitu, blindinc=0; 103.  104.  	bhitpos.x = x;  105. bhitpos.y = y; 106. 107. 	singleobj = splitobj(obj, (int)obj->quan-1); 108. 	/* splitobj leaves the new object in the chain (i.e. the monster's  109.  	 * inventory). Remove it. We can do this in 1 line, but it's highly 110. 	 * dependent on the fact that we know splitobj places it immediately 111. 	 * after obj. 112. 	 */  113.  	obj->nobj = singleobj->nobj; 114.  115.  	if(sym) { 116. 		tmp_at(-1, sym);	/* open call */ 117. 		tmp_at(-3, (int)AT_OBJ); 118. 	}  119.  	while(range-- > 0) { /* Actually the loop is always exited by break */ 120. 		bhitpos.x += dx; 121. 		bhitpos.y += dy; 122. 		if(levl[bhitpos.x][bhitpos.y].mmask) { 123. 		    mtmp = m_at(bhitpos.x,bhitpos.y); 124.  125.  		    if(mtmp->data->ac + 8 + obj->spe <= rnd(20)) { 126. 			miss(distant_name(singleobj,xname), mtmp); 127. 			if (!range) { /* Last position; object drops */ 128. 			    drop_throw(singleobj, 0, mtmp->mx, mtmp->my); 129. 			    break; 130. 			}  131.  		    } else { 132. 			damage = dmgval(obj, mtmp->data); 133. 			if (damage < 1) damage = 1; 134. 			if (obj->otyp==ACID_VENOM && resists_acid(mtmp->data)) 135. 			    damage = 0; 136. 			hit(distant_name(singleobj,xname), mtmp,exclam(damage)); 137. 			if (obj->opoisoned) { 138. 			    if (resists_poison(mtmp->data)) 139. 				kludge("The poison doesn't seem to affect %s.",  140.  								mon_nam(mtmp)); 141. 			    else { 142. 				if (rn2(10)) damage += rnd(6); 143. 				else { 144. 				    pline("The poison was deadly..."); 145. 				    damage = mtmp->mhp; 146. 				}  147.  			    }  148.  			}  149.  			if (obj->otyp==ACID_VENOM && cansee(mtmp->mx,mtmp->my)){ 150. 			    if (resists_acid(mtmp->data)) { 151. 				pline("%s is unaffected.", Monnam(mtmp)); 152. 				damage = 0; 153. 			    } else pline("The acid burns %s!", mon_nam(mtmp)); 154. 			}  155.  			mtmp->mhp -= damage; 156. 			if(mtmp->mhp < 1) { 157. 			    if (cansee(mtmp->mx, mtmp->my)) 158. 				pline("%s is killed!", Monnam(mtmp)); 159. 			    mondied(mtmp); 160. 			}  161.   162.  			if((obj->otyp == CREAM_PIE) ||  163.  			   (obj->otyp == BLINDING_VENOM)) { 164. 			    if (cansee(mtmp->mx, mtmp->my)) 165. 				pline("%s is blinded by the %s.",  166.  				      Monnam(mtmp), xname(singleobj)); 167. 			    if(mtmp->msleep) mtmp->msleep = 0; 168. 			    mtmp->mcansee = 0; 169. 			    {  170.  				register unsigned rnd_tmp = rnd(25) + 20; 171. 				if((mtmp->mblinded + rnd_tmp) > 127) 172. 					mtmp->mblinded = 127; 173. 				else mtmp->mblinded += rnd_tmp; 174. 			    }  175.  			}  176.  			drop_throw(singleobj, 1, bhitpos.x, bhitpos.y); 177. 			break; 178. 		    }  179.  		}  180.  		if (bhitpos.x == u.ux && bhitpos.y == u.uy) { 181. 			if (multi) nomul(0); 182.  183.  			switch(obj->otyp) { 184. 			    int dam; 185. 			    case CREAM_PIE: 186. 			    case BLINDING_VENOM: 187. 				hitu = thitu(8, 0, xname(singleobj)); 188. 				break; 189. 			    default: 190. 				dam = dmgval(obj, uasmon); 191. 				if (dam < 1) dam = 1; 192. 				hitu = thitu(8+obj->spe, dam, xname(singleobj)); 193. 			}  194.  			if (obj->opoisoned) 195. 			    /* it's safe to call xname twice because it's the 196. 			       same object both times... */ 197.  			    poisoned(xname(singleobj), A_STR, xname(singleobj)); 198. 			if(hitu && (obj->otyp == CREAM_PIE || 199. 				     obj->otyp == BLINDING_VENOM)) { 200. 			    blindinc = rnd(25); 201. 			    if(obj->otyp == CREAM_PIE) { 202. 				if(!Blind) pline("Yecch!  You've been creamed."); 203. 				else	pline("There's something sticky all over your %s.", body_part(FACE)); 204. 			    } else {	/* venom in the eyes */ 205. 				if(Blindfolded) /* nothing */ ; 206. 				else if(!Blind) pline("The venom blinds you."); 207. 				else	Your("%s sting.",  208.  					makeplural(body_part(EYE))); 209. 			    }  210.  			}  211.  			if (hitu || !range) { 212. 			    drop_throw(singleobj, hitu, u.ux, u.uy); 213. 			    break; 214. 			}  215.  		} else if (!range	/* reached end of path */  216.  			/* missile hits edge of screen */  217.  			|| !isok(bhitpos.x+dx,bhitpos.y+dy)  218.  			/* missile hits the wall */  219.  			|| IS_WALL(levl[bhitpos.x+dx][bhitpos.y+dy].typ)  220.  			|| levl[bhitpos.x+dx][bhitpos.y+dy].typ == SDOOR  221.  			|| levl[bhitpos.x+dx][bhitpos.y+dy].typ == SCORR  222.  #ifdef SINKS  223.  			/* Thrown objects "sink" */  224.  			|| IS_SINK(levl[bhitpos.x][bhitpos.y].typ)  225.  #endif  226.  								) { 227. 		    drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); 228. 		    break; 229. 		}  230.  		tmp_at(bhitpos.x, bhitpos.y); 231. 	}  232.  	tmp_at(bhitpos.x, bhitpos.y); 233. 	tmp_at(-1, -1); 234. 	/* blindfold keeps substances out of your eyes */ 235. 	if (blindinc && !Blindfolded) { 236. 		u.ucreamed += blindinc; 237. 		make_blinded(Blinded + blindinc,FALSE); 238. 	}  239.  }  240.   241.  /* Remove an item from the monster's inventory. 242.  */  243.  void 244. m_useup(mon, obj) 245. struct monst *mon; 246. struct obj *obj; 247. {  248.  	struct obj *otmp, *prev; 249.  250.  	prev = ((struct obj *) 0); 251. 	for (otmp = mon->minvent; otmp; otmp = otmp->nobj) { 252. 		if (otmp == obj) { 253. 			if (prev) 254. 				prev->nobj = obj->nobj; 255. 			else 256. 				mon->minvent = obj->nobj; 257. 			free((genericptr_t) obj); 258. 			break; 259. 		}  260.  		prev = otmp; 261. 	}  262.  }  263.   264.  /* Always returns 0??? -SAC */ 265. int 266. thrwmu(mtmp)	/* monster throws item at you */ 267. register struct monst *mtmp; 268. {  269.  	struct obj *otmp, *select_rwep; 270. 	register xchar x, y;  271. 272. 	if(lined_up(mtmp)) { 273.  274.  	    if((otmp = select_rwep(mtmp))) { 275.  276.  		/* If you are coming toward the monster, the monster 277. 		 * should try to soften you up with missiles. If you are 278. 		 * going away, you are probably hurt or running. Give 279. 		 * chase, but if you are getting too far away, throw. 280. 		 */  281.  		x = mtmp->mx; 282. 		y = mtmp->my; 283. 		if(!URETREATING(x,y) ||  284.  		   !rn2(BOLT_LIM-movedist(x,mtmp->mux,y,mtmp->muy))) 285. 		{  286.  		    m_throw(mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),  287.  			movedist(mtmp->mx,mtmp->mux,mtmp->my,mtmp->muy), otmp); 288. 		    if (!otmp->quan) m_useup(mtmp, otmp); 289. 		    nomul(0); 290. 		    return 0; 291. 		}  292.  	    }  293.  	}  294.  	return 0; 295. }  296.   297.  int 298. spitmu(mtmp)			/* monster spits substance at you */ 299. register struct monst *mtmp; 300. {  301.  	register struct obj *otmp; 302.  303.  	if(mtmp->mcan) { 304.  305.  	    if(flags.soundok) 306. 		pline("A dry rattle comes from %s's throat", mon_nam(mtmp)); 307. 	    return 0; 308. 	}  309.  	if(lined_up(mtmp)) { 310. 		otmp = mksobj(mtmp->data==&mons[PM_COBRA] ?  311.  			BLINDING_VENOM : ACID_VENOM, FALSE); 312. 		/* really incorrect; should check the attack type; this might 313. 		 * fail if someone introduces another monster with a venom 314. 		 * attack...  315. */ 316.  		if(!rn2(BOLT_LIM-movedist(mtmp->mx,mtmp->mux,mtmp->my,mtmp->muy))) { 317.  318.  		    m_throw(mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),  319.  			movedist(mtmp->mx,mtmp->mux,mtmp->my,mtmp->muy), otmp); 320. 		    nomul(0); 321. 		    return 0; 322. 		}  323.  	}  324.  	return 0; 325. }  326.   327.  int 328. breamu(mtmp, mattk)			/* monster breathes at you (ranged) */ 329. 	register struct monst *mtmp; 330. 	register struct attack  *mattk; 331. {  332.  	if(lined_up(mtmp)) { 333.  334.  	    if(mtmp->mcan) { 335. 		if(flags.soundok) { 336. 		    if(canseemon(mtmp)) 337. 			pline("%s coughs.", Monnam(mtmp)); 338. 		    else 339. 			You("hear a cough."); 340. 		}  341.  		return(0); 342. 	    }  343.  	    if(rn2(3)) { 344.  345.  		if((mattk->adtyp >= 1) && (mattk->adtyp < 11)) { 346.  347.  		    if(canseemon(mtmp)) 348. 			pline("%s breathes %s!", Monnam(mtmp),  349.  			      breathwep[mattk->adtyp-1]); 350. 		    buzz((int) (-20 - (mattk->adtyp-1)), (int)mattk->damn,  351.  			 mtmp->mx, mtmp->my, sgn(tbx), sgn(tby)); 352. 		    nomul(0); 353. 		} else impossible("Breath weapon %d used", mattk->adtyp-1); 354. 	    }  355.  	}  356.  	return(1); 357. }  358.   359.  boolean 360. linedup(ax, ay, bx, by) 361. register xchar ax, ay, bx, by; 362. {  363.  	register xchar x, y;  364. 365. 	tbx = ax - bx;	/* These two values are set for use */ 366. 	tby = ay - by;	/* after successful return. */ 367.   368.  	if((!tbx || !tby || abs(tbx) == abs(tby)) /* straight line or diagonal */  369.  	   && movedist(tbx, 0,  tby, 0) < BOLT_LIM) { 370.  371.  		/* Check if there are any dead squares between. If so, 372. 		 * it will not be possible to shoot. 373. 		 */  374.  		x = bx; y = by; 375. 		while(x != ax || y != ay) { 376.  377.  		    if (!ACCESSIBLE(levl[x][y].typ) ||  378.  			  (IS_DOOR(levl[x][y].typ) && 379. 				(levl[x][y].doormask & (D_LOCKED | D_CLOSED)))) 380. 			return FALSE; 381. 		    x += sgn(tbx), y += sgn(tby); 382. 		}  383.  		return TRUE; 384. 	}  385.  	return FALSE; 386. }  387.   388.  boolean 389. lined_up(mtmp)		/* is mtmp in position to use ranged attack? */ 390.  	register struct monst *mtmp; 391. {  392.  	return(linedup(mtmp->mux,mtmp->muy,mtmp->mx,mtmp->my)); 393. }  394.   395.  /* Check if a monster is carrying a particular item. 396.  */  397.  struct obj * 398. m_carrying(mtmp, type) 399. struct monst *mtmp; 400. int type; 401. {  402.  	register struct obj *otmp; 403.  404.  	for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj) 405. 		if(otmp->otyp == type) 406. 			return(otmp); 407. 	return((struct obj *) 0); 408. }  409.   410.  static int 411. movedist(x0, x1, y0, y1) 412. {  413.  	register int absdx, absdy; 414.  415.  	absdx = abs(x1 - x0); 416. 	absdy = abs(y1 - y0); 417.  418.  	return (max(absdx,absdy)); 419. }