abstract
| - 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. }
|