abstract
| - Below is the full text to detect.c from the source code of NetHack 3.4.0. To link to a particular line, write [[NetHack 3.4.0/detect.c#line123]], for example. Warning! This is the source code from an old release. For the latest release, see Source code 1. /* SCCS Id: @(#)detect.c 3.4 1999/12/06 */ 2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3. /* NetHack may be freely redistributed. See license for details. */ 4. 5. /* 6. * Detection routines, including crystal ball, magic mapping, and search 7. * command. 8. */ 9. 10. #include "hack.h" 11. #include "artifact.h" 12. 13. extern boolean known; /* from read.c */ 14. 15. STATIC_DCL void FDECL(do_dknown_of, (struct obj *)); 16. STATIC_DCL boolean FDECL(check_map_spot, (int,int,CHAR_P,unsigned)); 17. STATIC_DCL boolean FDECL(clear_stale_map, (CHAR_P,unsigned)); 18. STATIC_DCL void FDECL(sense_trap, (struct trap *,XCHAR_P,XCHAR_P,int)); 19. STATIC_DCL void FDECL(show_map_spot, (int,int)); 20. STATIC_PTR void FDECL(findone,(int,int,genericptr_t)); 21. STATIC_PTR void FDECL(openone,(int,int,genericptr_t)); 22. 23. /* Recursively search obj for an object in class oclass and return 1st found */ 24. struct obj * 25. o_in(obj, oclass) 26. struct obj* obj; 27. char oclass; 28. { 29. register struct obj* otmp; 30. struct obj *temp; 31. 32. if (obj->oclass == oclass) return obj; 33. 34. if (Has_contents(obj)) { 35. for (otmp = obj->cobj; otmp; otmp = otmp->nobj) 36. if (otmp->oclass == oclass) return otmp; 37. else if (Has_contents(otmp) && (temp = o_in(otmp, oclass))) 38. return temp; 39. } 40. return (struct obj *) 0; 41. } 42. 43. /* Recursively search obj for an object made of specified material and return 1st found */ 44. struct obj * 45. o_material(obj, material) 46. struct obj* obj; 47. unsigned material; 48. { 49. register struct obj* otmp; 50. struct obj *temp; 51. 52. if (objects[obj->otyp].oc_material == material) return obj; 53. 54. if (Has_contents(obj)) { 55. for (otmp = obj->cobj; otmp; otmp = otmp->nobj) 56. if (objects[otmp->otyp].oc_material == material) return otmp; 57. else if (Has_contents(otmp) && (temp = o_material(otmp, material))) 58. return temp; 59. } 60. return (struct obj *) 0; 61. } 62. 63. STATIC_OVL void 64. do_dknown_of(obj) 65. struct obj *obj; 66. { 67. struct obj *otmp; 68. 69. obj->dknown = 1; 70. if (Has_contents(obj)) { 71. for(otmp = obj->cobj; otmp; otmp = otmp->nobj) 72. do_dknown_of(otmp); 73. } 74. } 75. 76. /* Check whether the location has an outdated object displayed on it. */ 77. STATIC_OVL boolean 78. check_map_spot(x, y, oclass, material) 79. int x, y; 80. register char oclass; 81. unsigned material; 82. { 83. register int glyph; 84. register struct obj *otmp; 85. register struct monst *mtmp; 86. 87. glyph = glyph_at(x,y); 88. if (glyph_is_object(glyph)) { 89. /* there's some object shown here */ 90. if (oclass == ALL_CLASSES) { 91. return((boolean)( !(level.objects[x][y] || /* stale if nothing here */ 92. ((mtmp = m_at(x,y)) != 0 && 93. ( 94. #ifndef GOLDOBJ 95. mtmp->mgold || 96. #endif 97. mtmp->minvent))))); 98. } else { 99. if (material && objects[glyph_to_obj(glyph)].oc_material == material) { 100. /* the object shown here is of interest because material matches */ 101. for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) 102. if (o_material(otmp, GOLD)) return FALSE; 103. /* didn't find it; perhaps a monster is carrying it */ 104. if ((mtmp = m_at(x,y)) != 0) { 105. for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) 106. if (o_material(otmp, GOLD)) return FALSE; 107. } 108. /* detection indicates removal of this object from the map */ 109. return TRUE; 110. } 111. if (oclass && objects[glyph_to_obj(glyph)].oc_class == oclass) { 112. /* the object shown here is of interest because its class matches */ 113. for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) 114. if (o_in(otmp, oclass)) return FALSE; 115. /* didn't find it; perhaps a monster is carrying it */ 116. #ifndef GOLDOBJ 117. if ((mtmp = m_at(x,y)) != 0) { 118. if (oclass == GOLD_CLASS && mtmp->mgold) 119. return FALSE; 120. else for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) 121. if (o_in(otmp, oclass)) return FALSE; 122. } 123. #else 124. if ((mtmp = m_at(x,y)) != 0) { 125. for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) 126. if (o_in(otmp, oclass)) return FALSE; 127. } 128. #endif 129. /* detection indicates removal of this object from the map */ 130. return TRUE; 131. } 132. } 133. } 134. return FALSE; 135. } 136. 137. /* 138. When doing detection, remove stale data from the map display (corpses 139. rotted away, objects carried away by monsters, etc) so that it won't 140. reappear after the detection has completed. Return true if noticeable 141. change occurs. 142. */ 143. STATIC_OVL boolean 144. clear_stale_map(oclass, material) 145. register char oclass; 146. unsigned material; 147. { 148. register int zx, zy; 149. register boolean change_made = FALSE; 150. 151. for (zx = 1; zx < COLNO; zx++) 152. for (zy = 0; zy < ROWNO; zy++) 153. if (check_map_spot(zx, zy, oclass,material)) { 154. unmap_object(zx, zy); 155. change_made = TRUE; 156. } 157. 158. return change_made; 159. } 160. 161. /* look for gold, on the floor or in monsters' possession */ 162. int 163. gold_detect(sobj) 164. register struct obj *sobj; 165. { 166. register struct obj *obj; 167. register struct monst *mtmp; 168. int uw = u.uinwater; 169. struct obj *temp; 170. boolean stale; 171. 172. known = stale = clear_stale_map(GOLD_CLASS, 173. (unsigned)(sobj->blessed ? GOLD : 0)); 174. 175. /* look for gold carried by monsters (might be in a container) */ 176. for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { 177. if (DEADMONSTER(mtmp)) continue; /* probably not needed in this case but... */ 178. #ifndef GOLDOBJ 179. if (mtmp->mgold || monsndx(mtmp->data) == PM_GOLD_GOLEM) { 180. #else 181. if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) { 182. #endif 183. known = TRUE; 184. goto outgoldmap; /* skip further searching */ 185. } else for (obj = mtmp->minvent; obj; obj = obj->nobj) 186. if (sobj->blessed && o_material(obj, GOLD)) { 187. known = TRUE; 188. goto outgoldmap; 189. } else if (o_in(obj, GOLD_CLASS)) { 190. known = TRUE; 191. goto outgoldmap; /* skip further searching */ 192. } 193. } 194. 195. /* look for gold objects */ 196. for (obj = fobj; obj; obj = obj->nobj) { 197. if (sobj->blessed && o_material(obj, GOLD)) { 198. known = TRUE; 199. if (obj->ox != u.ux || obj->oy != u.uy) goto outgoldmap; 200. } else if (o_in(obj, GOLD_CLASS)) { 201. known = TRUE; 202. if (obj->ox != u.ux || obj->oy != u.uy) goto outgoldmap; 203. } 204. } 205. 206. if (!known) { 207. /* no gold found on floor or monster's inventory. 208. adjust message if you have gold in your inventory */ 209. if (sobj) { 210. char buf[BUFSZ]; 211. if (youmonst.data == &mons[PM_GOLD_GOLEM]) { 212. Sprintf(buf, "You feel like a million %s!", 213. currency(2L)); 214. } else if (hidden_gold() || 215. #ifndef GOLDOBJ 216. u.ugold) 217. #else 218. money_cnt(invent)) 219. #endif 220. Strcpy(buf, 221. "You feel worried about your future financial situation."); 222. else 223. Strcpy(buf, "You feel materially poor."); 224. strange_feeling(sobj, buf); 225. } 226. return(1); 227. } 228. /* only under me - no separate display required */ 229. if (stale) docrt(); 230. You("notice some gold between your %s.", makeplural(body_part(FOOT))); 231. return(0); 232. 233. outgoldmap: 234. cls(); 235. 236. u.uinwater = 0; 237. /* Discover gold locations. */ 238. for (obj = fobj; obj; obj = obj->nobj) { 239. if (sobj->blessed && (temp = o_material(obj, GOLD))) { 240. if (temp != obj) { 241. temp->ox = obj->ox; 242. temp->oy = obj->oy; 243. } 244. map_object(temp,1); 245. } else if ((temp = o_in(obj, GOLD_CLASS))) { 246. if (temp != obj) { 247. temp->ox = obj->ox; 248. temp->oy = obj->oy; 249. } 250. map_object(temp,1); 251. } 252. } 253. for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { 254. if (DEADMONSTER(mtmp)) continue; /* probably overkill here */ 255. #ifndef GOLDOBJ 256. if (mtmp->mgold || monsndx(mtmp->data) == PM_GOLD_GOLEM) { 257. #else 258. if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) { 259. #endif 260. struct obj gold; 261. 262. gold.otyp = GOLD_PIECE; 263. gold.ox = mtmp->mx; 264. gold.oy = mtmp->my; 265. map_object(&gold,1); 266. } else for (obj = mtmp->minvent; obj; obj = obj->nobj) 267. if (sobj->blessed && (temp = o_material(obj, GOLD))) { 268. temp->ox = mtmp->mx; 269. temp->oy = mtmp->my; 270. map_object(temp,1); 271. break; 272. } else if ((temp = o_in(obj, GOLD_CLASS))) { 273. temp->ox = mtmp->mx; 274. temp->oy = mtmp->my; 275. map_object(temp,1); 276. break; 277. } 278. } 279. 280. newsym(u.ux,u.uy); 281. You_feel("very greedy, and sense gold!"); 282. exercise(A_WIS, TRUE); 283. display_nhwindow(WIN_MAP, TRUE); 284. docrt(); 285. u.uinwater = uw; 286. if (Underwater) under_water(2); 287. if (u.uburied) under_ground(2); 288. return(0); 289. } 290. 291. /* returns 1 if nothing was detected */ 292. /* returns 0 if something was detected */ 293. int 294. food_detect(sobj) 295. register struct obj *sobj; 296. { 297. register struct obj *obj; 298. register struct monst *mtmp; 299. register int ct = 0, ctu = 0; 300. boolean confused = (Confusion || (sobj && sobj->cursed)), stale; 301. char oclass = confused ? POTION_CLASS : FOOD_CLASS; 302. const char *what = confused ? something : "food"; 303. int uw = u.uinwater; 304. 305. stale = clear_stale_map(oclass, 0); 306. 307. for (obj = fobj; obj; obj = obj->nobj) 308. if (o_in(obj, oclass)) { 309. if (obj->ox == u.ux && obj->oy == u.uy) ctu++; 310. else ct++; 311. } 312. for (mtmp = fmon; mtmp && !ct; mtmp = mtmp->nmon) { 313. /* no DEADMONSTER(mtmp) check needed since dmons never have inventory */ 314. for (obj = mtmp->minvent; obj; obj = obj->nobj) 315. if (o_in(obj, oclass)) { 316. ct++; 317. break; 318. } 319. } 320. 321. if (!ct && !ctu) { 322. known = stale && !confused; 323. if (stale) { 324. docrt(); 325. You("sense a lack of %s nearby.", what); 326. if (sobj && sobj->blessed) { 327. if (!u.uedibility) Your("%s starts to tingle.", body_part(NOSE)); 328. u.uedibility = 1; 329. } 330. } else if (sobj) { 331. char buf[BUFSZ]; 332. Sprintf(buf, "Your %s twitches%s.", body_part(NOSE), 333. (sobj->blessed && !u.uedibility) ? " then starts to tingle" : ""); 334. if (sobj->blessed && !u.uedibility) { 335. boolean savebeginner = flags.beginner; /* prevent non-delivery of */ 336. flags.beginner = FALSE; /* message */ 337. strange_feeling(sobj, buf); 338. flags.beginner = savebeginner; 339. u.uedibility = 1; 340. } else 341. strange_feeling(sobj, buf); 342. } 343. return !stale; 344. } else if (!ct) { 345. known = TRUE; 346. You("%s %s nearby.", sobj ? "smell" : "sense", what); 347. if (sobj && sobj->blessed) { 348. if (!u.uedibility) pline("Your %s starts to tingle.", body_part(NOSE)); 349. u.uedibility = 1; 350. } 351. } else { 352. struct obj *temp; 353. known = TRUE; 354. cls(); 355. u.uinwater = 0; 356. for (obj = fobj; obj; obj = obj->nobj) 357. if ((temp = o_in(obj, oclass)) != 0) { 358. if (temp != obj) { 359. temp->ox = obj->ox; 360. temp->oy = obj->oy; 361. } 362. map_object(temp,1); 363. } 364. for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) 365. /* no DEADMONSTER(mtmp) check needed since dmons never have inventory */ 366. for (obj = mtmp->minvent; obj; obj = obj->nobj) 367. if ((temp = o_in(obj, oclass)) != 0) { 368. temp->ox = mtmp->mx; 369. temp->oy = mtmp->my; 370. map_object(temp,1); 371. break; /* skip rest of this monster's inventory */ 372. } 373. newsym(u.ux,u.uy); 374. if (sobj) { 375. if (sobj->blessed) { 376. Your("%s %s to tingle and you smell %s.", body_part(NOSE), 377. u.uedibility ? "continues" : "starts", what); 378. u.uedibility = 1; 379. } else 380. Your("%s tingles and you smell %s.", body_part(NOSE), what); 381. } 382. else You("sense %s.", what); 383. display_nhwindow(WIN_MAP, TRUE); 384. exercise(A_WIS, TRUE); 385. docrt(); 386. u.uinwater = uw; 387. if (Underwater) under_water(2); 388. if (u.uburied) under_ground(2); 389. } 390. return(0); 391. } 392. 393. /* 394. * Used for scrolls, potions, and crystal balls. Returns: 395. * 396. * 1 - nothing was detected 397. * 0 - something was detected 398. */ 399. int 400. object_detect(detector, class) 401. struct obj *detector; /* object doing the detecting */ 402. int class; /* an object class, 0 for all */ 403. { 404. register int x, y; 405. int is_cursed = (detector && detector->cursed); 406. int do_dknown = 407. (detector && detector->oclass == POTION_CLASS && detector->blessed); 408. int ct = 0, ctu = 0; 409. register struct obj *obj, *otmp = (struct obj *)0; 410. register struct monst *mtmp; 411. int uw = u.uinwater; 412. const char *stuff; 413. 414. if (class < 0 || class >= MAXOCLASSES) { 415. impossible("object_detect: illegal class %d", class); 416. class = 0; 417. } 418. 419. if (Hallucination || (Confusion && class == SCROLL_CLASS)) 420. stuff = something; 421. else 422. stuff = class ? oclass_names[class] : "objects"; 423. 424. if (do_dknown) for(obj = invent; obj; obj = obj->nobj) do_dknown_of(obj); 425. 426. for (obj = fobj; obj; obj = obj->nobj) { 427. if (!class || o_in(obj, class)) { 428. if (obj->ox == u.ux && obj->oy == u.uy) ctu++; 429. else ct++; 430. } 431. if (do_dknown) do_dknown_of(obj); 432. } 433. 434. for (obj = level.buriedobjlist; obj; obj = obj->nobj) { 435. if (!class || o_in(obj, class)) { 436. if (obj->ox == u.ux && obj->oy == u.uy) ctu++; 437. else ct++; 438. } 439. if (do_dknown) do_dknown_of(obj); 440. } 441. 442. for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { 443. if (DEADMONSTER(mtmp)) continue; 444. for (obj = mtmp->minvent; obj; obj = obj->nobj) { 445. if (!class || o_in(obj, class)) ct++; 446. if (do_dknown) do_dknown_of(obj); 447. } 448. if ((is_cursed && mtmp->m_ap_type == M_AP_OBJECT && 449. (!class || class == objects[mtmp->mappearance].oc_class)) || 450. #ifndef GOLDOBJ 451. (mtmp->mgold && (!class || class == GOLD_CLASS))) { 452. #else 453. (findgold(mtmp->minvent) && (!class || class == GOLD_CLASS))) { 454. #endif 455. ct++; 456. break; 457. } 458. } 459. 460. if (!clear_stale_map(!class ? ALL_CLASSES : class, 0) && !ct) { 461. if (!ctu) { 462. if (detector) 463. strange_feeling(detector, "You feel a lack of something."); 464. return 1; 465. } 466. 467. You("sense %s nearby.", stuff); 468. return 0; 469. } 470. 471. cls(); 472. 473. u.uinwater = 0; 474. /* 475. * Map all buried objects first. 476. */ 477. for (obj = level.buriedobjlist; obj; obj = obj->nobj) 478. if (!class || (otmp = o_in(obj, class))) { 479. if (class) { 480. if (otmp != obj) { 481. otmp->ox = obj->ox; 482. otmp->oy = obj->oy; 483. } 484. map_object(otmp, 1); 485. } else 486. map_object(obj, 1); 487. } 488. /* 489. * If we are mapping all objects, map only the top object of a pile or 490. * the first object in a monster's inventory. Otherwise, go looking 491. * for a matching object class and display the first one encountered 492. * at each location. 493. * 494. * Objects on the floor override buried objects. 495. */ 496. for (x = 1; x < COLNO; x++) 497. for (y = 0; y < ROWNO; y++) 498. for (obj = level.objects[x][y]; obj; obj = obj->nexthere) 499. if (!class || (otmp = o_in(obj, class))) { 500. if (class) { 501. if (otmp != obj) { 502. otmp->ox = obj->ox; 503. otmp->oy = obj->oy; 504. } 505. map_object(otmp, 1); 506. } else 507. map_object(obj, 1); 508. break; 509. } 510. 511. /* Objects in the monster's inventory override floor objects. */ 512. for (mtmp = fmon ; mtmp ; mtmp = mtmp->nmon) { 513. if (DEADMONSTER(mtmp)) continue; 514. for (obj = mtmp->minvent; obj; obj = obj->nobj) 515. if (!class || (otmp = o_in(obj, class))) { 516. if (!class) otmp = obj; 517. otmp->ox = mtmp->mx; /* at monster location */ 518. otmp->oy = mtmp->my; 519. map_object(otmp, 1); 520. break; 521. } 522. /* Allow a mimic to override the detected objects it is carrying. */ 523. if (is_cursed && mtmp->m_ap_type == M_AP_OBJECT && 524. (!class || class == objects[mtmp->mappearance].oc_class)) { 525. struct obj temp; 526. 527. temp.otyp = mtmp->mappearance; /* needed for obj_to_glyph() */ 528. temp.ox = mtmp->mx; 529. temp.oy = mtmp->my; 530. temp.corpsenm = PM_TENGU; /* if mimicing a corpse */ 531. map_object(&temp, 1); 532. #ifndef GOLDOBJ 533. } else if (mtmp->mgold && (!class || class == GOLD_CLASS)) { 534. #else 535. } else if (findgold(mtmp->minvent) && (!class || class == GOLD_CLASS)) { 536. #endif 537. struct obj gold; 538. 539. gold.otyp = GOLD_PIECE; 540. gold.ox = mtmp->mx; 541. gold.oy = mtmp->my; 542. map_object(&gold, 1); 543. } 544. } 545. 546. newsym(u.ux,u.uy); 547. You("detect the %s of %s.", ct ? "presence" : "absence", stuff); 548. display_nhwindow(WIN_MAP, TRUE); 549. /* 550. * What are we going to do when the hero does an object detect while blind 551. * and the detected object covers a known pool? 552. */ 553. docrt(); /* this will correctly reset vision */ 554. 555. u.uinwater = uw; 556. if (Underwater) under_water(2); 557. if (u.uburied) under_ground(2); 558. return 0; 559. } 560. 561. /* 562. * Used by: crystal balls, potions, fountains 563. * 564. * Returns 1 if nothing was detected. 565. * Returns 0 if something was detected. 566. */ 567. int 568. monster_detect(otmp, mclass) 569. register struct obj *otmp; /* detecting object (if any) */ 570. int mclass; /* monster class, 0 for all */ 571. { 572. register struct monst *mtmp; 573. int mcnt = 0; 574. 575. 576. /* Note: This used to just check fmon for a non-zero value 577. * but in versions since 3.3.0 fmon can test TRUE due to the 578. * presence of dmons, so we have to find at least one 579. * with positive hit-points to know for sure. 580. */ 581. for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) 582. if (!DEADMONSTER(mtmp)) { 583. mcnt++; 584. break; 585. } 586. 587. if (!mcnt) { 588. if (otmp) 589. strange_feeling(otmp, Hallucination ? 590. "You get the heebie jeebies." : 591. "You feel threatened."); 592. return 1; 593. } else { 594. boolean woken = FALSE; 595. 596. cls(); 597. for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { 598. if (DEADMONSTER(mtmp)) continue; 599. if (!mclass || mtmp->data->mlet == mclass) 600. if (mtmp->mx > 0) 601. show_glyph(mtmp->mx,mtmp->my,mon_to_glyph(mtmp)); 602. if (otmp && otmp->cursed && 603. (mtmp->msleeping || !mtmp->mcanmove)) { 604. mtmp->msleeping = mtmp->mfrozen = 0; 605. mtmp->mcanmove = 1; 606. woken = TRUE; 607. } 608. } 609. display_self(); 610. You("sense the presence of monsters."); 611. if (woken) 612. pline("Monsters sense the presence of you."); 613. display_nhwindow(WIN_MAP, TRUE); 614. docrt(); 615. if (Underwater) under_water(2); 616. if (u.uburied) under_ground(2); 617. } 618. return 0; 619. } 620. 621. STATIC_OVL void 622. sense_trap(trap, x, y, src_cursed) 623. struct trap *trap; 624. xchar x, y; 625. int src_cursed; 626. { 627. if (Hallucination || src_cursed) { 628. struct obj obj; /* fake object */ 629. if (trap) { 630. obj.ox = trap->tx; 631. obj.oy = trap->ty; 632. } else { 633. obj.ox = x; 634. obj.oy = y; 635. } 636. obj.otyp = (src_cursed) ? GOLD_PIECE : random_object(); 637. obj.corpsenm = random_monster(); /* if otyp == CORPSE */ 638. map_object(&obj,1); 639. } else if (trap) { 640. map_trap(trap,1); 641. trap->tseen = 1; 642. } else { 643. struct trap temp_trap; /* fake trap */ 644. temp_trap.tx = x; 645. temp_trap.ty = y; 646. temp_trap.ttyp = BEAR_TRAP; /* some kind of trap */ 647. map_trap(&temp_trap,1); 648. } 649. 650. } 651. 652. /* the detections are pulled out so they can */ 653. /* also be used in the crystal ball routine */ 654. /* returns 1 if nothing was detected */ 655. /* returns 0 if something was detected */ 656. int 657. trap_detect(sobj) 658. register struct obj *sobj; 659. /* sobj is null if crystal ball, *scroll if gold detection scroll */ 660. { 661. register struct trap *ttmp; 662. register struct obj *obj; 663. register int door; 664. int uw = u.uinwater; 665. boolean found = FALSE; 666. coord cc; 667. 668. for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) { 669. if (ttmp->tx != u.ux || ttmp->ty != u.uy) 670. goto outtrapmap; 671. else found = TRUE; 672. } 673. for (obj = fobj; obj; obj = obj->nobj) { 674. if ((obj->otyp==LARGE_BOX || obj->otyp==CHEST) && obj->otrapped) { 675. if (obj->ox != u.ux || obj->oy != u.uy) 676. goto outtrapmap; 677. else found = TRUE; 678. } 679. } 680. for (door = 0; door < doorindex; door++) { 681. cc = doors[door]; 682. if (levl[cc.x][cc.y].doormask & D_TRAPPED) { 683. if (cc.x != u.ux || cc.y != u.uy) 684. goto outtrapmap; 685. else found = TRUE; 686. } 687. } 688. if (!found) { 689. char buf[42]; 690. Sprintf(buf, "Your %s stop itching.", makeplural(body_part(TOE))); 691. strange_feeling(sobj,buf); 692. return(1); 693. } 694. /* traps exist, but only under me - no separate display required */ 695. Your("%s itch.", makeplural(body_part(TOE))); 696. return(0); 697. outtrapmap: 698. cls(); 699. 700. u.uinwater = 0; 701. for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) 702. sense_trap(ttmp, 0, 0, sobj && sobj->cursed); 703. 704. for (obj = fobj; obj; obj = obj->nobj) 705. if ((obj->otyp==LARGE_BOX || obj->otyp==CHEST) && obj->otrapped) 706. sense_trap((struct trap *)0, obj->ox, obj->oy, sobj && sobj->cursed); 707. 708. for (door = 0; door < doorindex; door++) { 709. cc = doors[door]; 710. if (levl[cc.x][cc.y].doormask & D_TRAPPED) 711. sense_trap((struct trap *)0, cc.x, cc.y, sobj && sobj->cursed); 712. } 713. 714. newsym(u.ux,u.uy); 715. You_feel("%s.", sobj && sobj->cursed ? "very greedy" : "entrapped"); 716. display_nhwindow(WIN_MAP, TRUE); 717. docrt(); 718. u.uinwater = uw; 719. if (Underwater) under_water(2); 720. if (u.uburied) under_ground(2); 721. return(0); 722. } 723. 724. const char * 725. level_distance(where) 726. d_level *where; 727. { 728. register schar ll = depth(&u.uz) - depth(where); 729. register boolean indun = (u.uz.dnum == where->dnum); 730. 731. if (ll < 0) { 732. if (ll < (-8 - rn2(3))) 733. if (!indun) return "far away"; 734. else return "far below"; 735. else if (ll < -1) 736. if (!indun) return "away below you"; 737. else return "below you"; 738. else 739. if (!indun) return "in the distance"; 740. else return "just below"; 741. } else if (ll > 0) { 742. if (ll > (8 + rn2(3))) 743. if (!indun) return "far away"; 744. else return "far above"; 745. else if (ll > 1) 746. if (!indun) return "away above you"; 747. else return "above you"; 748. else 749. if (!indun) return "in the distance"; 750. else return "just above"; 751. } else 752. if (!indun) return "in the distance"; 753. else return "near you"; 754. } 755. 756. static struct { 757. const char *what; 758. d_level *where; 759. } level_detects[] = { 760. { "Delphi", &oracle_level }, 761. { "Medusa's lair", &medusa_level }, 762. { "a castle", &stronghold_level }, 763. { "the Wizard of Yendor's tower", &wiz1_level }, 764. }; 765. 766. void 767. use_crystal_ball(obj) 768. struct obj *obj; 769. { 770. char ch; 771. int oops; 772. 773. if (Blind) { 774. pline("Too bad you can't see %s.", the(xname(obj))); 775. return; 776. } 777. oops = (rnd(20) > ACURR(A_INT) || obj->cursed); 778. if (oops && (obj->spe > 0)) { 779. switch (rnd(obj->oartifact ? 4 : 5)) { 780. case 1 : pline("%s too much to comprehend!", Tobjnam(obj, "are")); 781. break; 782. case 2 : pline("%s you!", Tobjnam(obj, "confuse")); 783. make_confused(HConfusion + rnd(100),FALSE); 784. break; 785. case 3 : if (!resists_blnd(&youmonst)) { 786. pline("%s your vision!", Tobjnam(obj, "damage")); 787. make_blinded(Blinded + rnd(100),FALSE); 788. if (!Blind) Your(vision_clears); 789. } else { 790. pline("%s your vision.", Tobjnam(obj, "assault")); 791. You("are unaffected!"); 792. } 793. break; 794. case 4 : pline("%s your mind!", Tobjnam(obj, "zap")); 795. make_hallucinated(HHallucination + rnd(100),FALSE,0L); 796. break; 797. case 5 : pline("%s!", Tobjnam(obj, "explode")); 798. useup(obj); 799. losehp(rnd(30), "exploding crystal ball", KILLED_BY_AN); 800. break; 801. } 802. check_unpaid(obj); 803. obj->spe--; 804. return; 805. } 806. 807. if (Hallucination) { 808. if (!obj->spe) { 809. pline("All you see is funky %s haze.", hcolor((char *)0)); 810. } else { 811. switch(rnd(6)) { 812. case 1 : You("grok some groovy globs of incandescent lava."); 813. break; 814. case 2 : pline("Whoa! Psychedelic colors, %s!", 815. poly_gender() == 1 ? "babe" : "dude"); 816. break; 817. case 3 : pline_The("crystal pulses with sinister %s light!", 818. hcolor((char *)0)); 819. break; 820. case 4 : You("see goldfish swimming above fluorescent rocks."); 821. break; 822. case 5 : You("see tiny snowflakes spinning around a miniature farmhouse."); 823. break; 824. default: pline("Oh wow... like a kaleidoscope!"); 825. break; 826. } 827. check_unpaid(obj); 828. obj->spe--; 829. } 830. return; 831. } 832. 833. /* read a single character */ 834. if (flags.verbose) You("may look for an object or monster symbol."); 835. ch = yn_function("What do you look for?", (char *)0, '\0'); 836. if (index(quitchars,ch)) { 837. if (flags.verbose) pline(Never_mind); 838. return; 839. } 840. You("peer into %s...", the(xname(obj))); 841. nomul(-rnd(10)); 842. nomovemsg = ""; 843. if (obj->spe <= 0) 844. pline_The("vision is unclear."); 845. else { 846. int class; 847. int ret = 0; 848. 849. makeknown(CRYSTAL_BALL); 850. check_unpaid(obj); 851. obj->spe--; 852. 853. if ((class = def_char_to_objclass(ch)) != MAXOCLASSES) 854. ret = object_detect((struct obj *)0, class); 855. else if ((class = def_char_to_monclass(ch)) != MAXMCLASSES) 856. ret = monster_detect((struct obj *)0, class); 857. else switch(ch) { 858. case '^': 859. ret = trap_detect((struct obj *)0); 860. break; 861. default: 862. { 863. int i = rn2(SIZE(level_detects)); 864. You("see %s, %s.", 865. level_detects[i].what, 866. level_distance(level_detects[i].where)); 867. } 868. ret = 0; 869. break; 870. } 871. 872. if (ret) { 873. if (!rn2(100)) /* make them nervous */ 874. You("see the Wizard of Yendor gazing out at you."); 875. else pline_The("vision is unclear."); 876. } 877. } 878. return; 879. } 880. 881. STATIC_OVL void 882. show_map_spot(x, y) 883. register int x, y; 884. { 885. register struct rm *lev; 886. 887. if (Confusion && rn2(7)) return; 888. lev = &levl[x][y]; 889. 890. lev->seenv = SVALL; 891. 892. /* Secret corridors are found, but not secret doors. */ 893. if (lev->typ == SCORR) { 894. lev->typ = CORR; 895. unblock_point(x,y); 896. } 897. 898. /* if we don't remember an object or trap there, map it */ 899. if (lev->typ == ROOM ? 900. (glyph_is_cmap(lev->glyph) && !glyph_is_trap(lev->glyph) && 901. glyph_to_cmap(lev->glyph) != ROOM) : 902. (!glyph_is_object(lev->glyph) && !glyph_is_trap(lev->glyph))) { 903. if (level.flags.hero_memory) { 904. magic_map_background(x,y,0); 905. newsym(x,y); /* show it, if not blocked */ 906. } else { 907. magic_map_background(x,y,1); /* display it */ 908. } 909. } 910. } 911. 912. void 913. do_mapping() 914. { 915. register int zx, zy; 916. int uw = u.uinwater; 917. 918. u.uinwater = 0; 919. for (zx = 1; zx < COLNO; zx++) 920. for (zy = 0; zy < ROWNO; zy++) 921. show_map_spot(zx, zy); 922. exercise(A_WIS, TRUE); 923. u.uinwater = uw; 924. if (!level.flags.hero_memory || Underwater) { 925. flush_screen(1); /* flush temp screen */ 926. display_nhwindow(WIN_MAP, TRUE); /* wait */ 927. docrt(); 928. } 929. } 930. 931. void 932. do_vicinity_map() 933. { 934. register int zx, zy; 935. int lo_y = (u.uy-5 < 0 ? 0 : u.uy-5), 936. hi_y = (u.uy+6 > ROWNO ? ROWNO : u.uy+6), 937. lo_x = (u.ux-9 < 1 ? 1 : u.ux-9), /* avoid column 0 */ 938. hi_x = (u.ux+10 > COLNO ? COLNO : u.ux+10); 939. 940. for (zx = lo_x; zx < hi_x; zx++) 941. for (zy = lo_y; zy < hi_y; zy++) 942. show_map_spot(zx, zy); 943. 944. if (!level.flags.hero_memory || Underwater) { 945. flush_screen(1); /* flush temp screen */ 946. display_nhwindow(WIN_MAP, TRUE); /* wait */ 947. docrt(); 948. } 949. } 950. 951. /* convert a secret door into a normal door */ 952. void 953. cvt_sdoor_to_door(lev) 954. struct rm *lev; 955. { 956. int newmask = lev->doormask & ~WM_MASK; 957. 958. #ifdef REINCARNATION 959. if (Is_rogue_level(&u.uz)) 960. /* rogue didn't have doors, only doorways */ 961. newmask = D_NODOOR; 962. else 963. #endif 964. /* newly exposed door is closed */ 965. if (!(newmask & D_LOCKED)) newmask |= D_CLOSED; 966. 967. lev->typ = DOOR; 968. lev->doormask = newmask; 969. } 970. 971. 972. STATIC_PTR void 973. findone(zx,zy,num) 974. int zx,zy; 975. genericptr_t num; 976. { 977. register struct trap *ttmp; 978. register struct monst *mtmp; 979. 980. if(levl[zx][zy].typ == SDOOR) { 981. cvt_sdoor_to_door(&levl[zx][zy]); /* .typ = DOOR */ 982. magic_map_background(zx, zy, 0); 983. newsym(zx, zy); 984. (*(int*)num)++; 985. } else if(levl[zx][zy].typ == SCORR) { 986. levl[zx][zy].typ = CORR; 987. unblock_point(zx,zy); 988. magic_map_background(zx, zy, 0); 989. newsym(zx, zy); 990. (*(int*)num)++; 991. } else if ((ttmp = t_at(zx, zy)) != 0) { 992. if(!ttmp->tseen && ttmp->ttyp != STATUE_TRAP) { 993. ttmp->tseen = 1; 994. newsym(zx,zy); 995. (*(int*)num)++; 996. } 997. } else if ((mtmp = m_at(zx, zy)) != 0) { 998. if(mtmp->m_ap_type) { 999. seemimic(mtmp); 1000. (*(int*)num)++; 1001. } 1002. if (mtmp->mundetected && 1003. (is_hider(mtmp->data) || mtmp->data->mlet == S_EEL)) { 1004. mtmp->mundetected = 0; 1005. newsym(zx, zy); 1006. (*(int*)num)++; 1007. } 1008. if (!canspotmon(mtmp) && 1009. !glyph_is_invisible(levl[zx][zy].glyph)) 1010. map_invisible(zx, zy); 1011. } else if (glyph_is_invisible(levl[zx][zy].glyph)) { 1012. unmap_object(zx, zy); 1013. newsym(zx, zy); 1014. (*(int*)num)++; 1015. } 1016. } 1017. 1018. STATIC_PTR void 1019. openone(zx,zy,num) 1020. int zx,zy; 1021. genericptr_t num; 1022. { 1023. register struct trap *ttmp; 1024. register struct obj *otmp; 1025. 1026. if(OBJ_AT(zx, zy)) { 1027. for(otmp = level.objects[zx][zy]; 1028. otmp; otmp = otmp->nexthere) { 1029. if(Is_box(otmp) && otmp->olocked) { 1030. otmp->olocked = 0; 1031. (*(int*)num)++; 1032. } 1033. } 1034. /* let it fall to the next cases. could be on trap. */ 1035. } 1036. if(levl[zx][zy].typ == SDOOR || (levl[zx][zy].typ == DOOR && 1037. (levl[zx][zy].doormask & (D_CLOSED|D_LOCKED)))) { 1038. if(levl[zx][zy].typ == SDOOR) 1039. cvt_sdoor_to_door(&levl[zx][zy]); /* .typ = DOOR */ 1040. if(levl[zx][zy].doormask & D_TRAPPED) { 1041. if(distu(zx, zy) < 3) b_trapped("door", 0); 1042. else Norep("You %s an explosion!", 1043. cansee(zx, zy) ? "see" : 1044. (flags.soundok ? "hear" : 1045. "feel the shock of")); 1046. wake_nearto(zx, zy, 11*11); 1047. levl[zx][zy].doormask = D_NODOOR; 1048. } else 1049. levl[zx][zy].doormask = D_ISOPEN; 1050. unblock_point(zx, zy); 1051. newsym(zx, zy); 1052. (*(int*)num)++; 1053. } else if(levl[zx][zy].typ == SCORR) { 1054. levl[zx][zy].typ = CORR; 1055. unblock_point(zx, zy); 1056. newsym(zx, zy); 1057. (*(int*)num)++; 1058. } else if ((ttmp = t_at(zx, zy)) != 0) { 1059. if (!ttmp->tseen && ttmp->ttyp != STATUE_TRAP) { 1060. ttmp->tseen = 1; 1061. newsym(zx,zy); 1062. (*(int*)num)++; 1063. } 1064. } else if (find_drawbridge(&zx, &zy)) { 1065. /* make sure it isn't an open drawbridge */ 1066. open_drawbridge(zx, zy); 1067. (*(int*)num)++; 1068. } 1069. } 1070. 1071. int 1072. findit() /* returns number of things found */ 1073. { 1074. int num = 0; 1075. 1076. if(u.uswallow) return(0); 1077. do_clear_area(u.ux, u.uy, BOLT_LIM, findone, (genericptr_t) &num); 1078. return(num); 1079. } 1080. 1081. int 1082. openit() /* returns number of things found and opened */ 1083. { 1084. int num = 0; 1085. 1086. if(u.uswallow) { 1087. if (is_animal(u.ustuck->data)) { 1088. if (Blind) pline("Its mouth opens!"); 1089. else pline("%s opens its mouth!", Monnam(u.ustuck)); 1090. } 1091. expels(u.ustuck, u.ustuck->data, TRUE); 1092. return(-1); 1093. } 1094. 1095. do_clear_area(u.ux, u.uy, BOLT_LIM, openone, (genericptr_t) &num); 1096. return(num); 1097. } 1098. 1099. void 1100. find_trap(trap) 1101. struct trap *trap; 1102. { 1103. int tt = what_trap(trap->ttyp); 1104. boolean cleared = FALSE; 1105. 1106. trap->tseen = 1; 1107. exercise(A_WIS, TRUE); 1108. if (Blind) 1109. feel_location(trap->tx, trap->ty); 1110. else 1111. newsym(trap->tx, trap->ty); 1112. 1113. if (levl[trap->tx][trap->ty].glyph != trap_to_glyph(trap)) { 1114. /* There's too much clutter to see your find otherwise */ 1115. cls(); 1116. map_trap(trap, 1); 1117. display_self(); 1118. cleared = TRUE; 1119. } 1120. 1121. You("find %s.", an(defsyms[trap_to_defsym(tt)].explanation)); 1122. 1123. if (cleared) { 1124. display_nhwindow(WIN_MAP, TRUE); /* wait */ 1125. docrt(); 1126. } 1127. } 1128. 1129. int 1130. dosearch0(aflag) 1131. register int aflag; 1132. { 1133. #ifdef GCC_BUG 1134. /* some versions of gcc seriously muck up nested loops. if you get strange 1135. crashes while searching in a version compiled with gcc, try putting 1136. #define GCC_BUG in *conf.h (or adding -DGCC_BUG to CFLAGS in the 1137. makefile). 1138. */ 1139. volatile xchar x, y; 1140. #else 1141. register xchar x, y; 1142. #endif 1143. register struct trap *trap; 1144. register struct monst *mtmp; 1145. 1146. if(u.uswallow) { 1147. if (!aflag) 1148. pline("What are you looking for? The exit?"); 1149. } else { 1150. int fund = (uwep && uwep->oartifact && 1151. spec_ability(uwep, SPFX_SEARCH)) ? 1152. uwep->spe : 0; 1153. if (ublindf && ublindf->otyp == LENSES && !Blind) 1154. fund += 2; /* JDS: lenses help searching */ 1155. if (fund > 5) fund = 5; 1156. for(x = u.ux-1; x < u.ux+2; x++) 1157. for(y = u.uy-1; y < u.uy+2; y++) { 1158. if(!isok(x,y)) continue; 1159. if(x != u.ux || y != u.uy) { 1160. if (Blind && !aflag) feel_location(x,y); 1161. if(levl[x][y].typ == SDOOR) { 1162. if(rnl(7-fund)) continue; 1163. cvt_sdoor_to_door(&levl[x][y]); /* .typ = DOOR */ 1164. exercise(A_WIS, TRUE); 1165. nomul(0); 1166. if (Blind && !aflag) 1167. feel_location(x,y); /* make sure it shows up */ 1168. else 1169. newsym(x,y); 1170. } else if(levl[x][y].typ == SCORR) { 1171. if(rnl(7-fund)) continue; 1172. levl[x][y].typ = CORR; 1173. unblock_point(x,y); /* vision */ 1174. exercise(A_WIS, TRUE); 1175. nomul(0); 1176. newsym(x,y); 1177. } else { 1178. /* Be careful not to find anything in an SCORR or SDOOR */ 1179. if((mtmp = m_at(x, y)) && !aflag) { 1180. if(mtmp->m_ap_type) { 1181. seemimic(mtmp); 1182. find: exercise(A_WIS, TRUE); 1183. if (!canspotmon(mtmp)) { 1184. if (glyph_is_invisible(levl[x][y].glyph)) { 1185. /* found invisible monster in a square 1186. * which already has an 'I' in it. 1187. * Logically, this should still take 1188. * time and lead to a return(1), but if 1189. * we did that the player would keep 1190. * finding the same monster every turn. 1191. */ 1192. continue; 1193. } else { 1194. You_feel("an unseen monster!"); 1195. map_invisible(x, y); 1196. } 1197. } else if (!sensemon(mtmp)) 1198. You("find %s.", a_monnam(mtmp)); 1199. return(1); 1200. } 1201. if(!canspotmon(mtmp)) { 1202. if (mtmp->mundetected && 1203. (is_hider(mtmp->data) || mtmp->data->mlet == S_EEL)) 1204. mtmp->mundetected = 0; 1205. newsym(x,y); 1206. goto find; 1207. } 1208. } 1209. 1210. /* see if an invisible monster has moved--if Blind, 1211. * feel_location() already did it 1212. */ 1213. if (!aflag && !mtmp && !Blind && 1214. glyph_is_invisible(levl[x][y].glyph)) { 1215. unmap_object(x,y); 1216. newsym(x,y); 1217. } 1218. 1219. if ((trap = t_at(x,y)) && !trap->tseen && !rnl(8)) { 1220. nomul(0); 1221. 1222. if (trap->ttyp == STATUE_TRAP) { 1223. if (activate_statue_trap(trap, x, y, FALSE)) 1224. exercise(A_WIS, TRUE); 1225. return(1); 1226. } else { 1227. find_trap(trap); 1228. } 1229. } 1230. } 1231. } 1232. } 1233. } 1234. return(1); 1235. } 1236. 1237. int 1238. dosearch() 1239. { 1240. return(dosearch0(0)); 1241. } 1242. 1243. /* Pre-map the sokoban levels */ 1244. void 1245. sokoban_detect() 1246. { 1247. register int x, y; 1248. register struct trap *ttmp; 1249. register struct obj *obj; 1250. 1251. /* Map the background and boulders */ 1252. for (x = 1; x < COLNO; x++) 1253. for (y = 0; y < ROWNO; y++) { 1254. levl[x][y].seenv = SVALL; 1255. levl[x][y].waslit = TRUE; 1256. map_background(x, y, 1); 1257. for (obj = level.objects[x][y]; obj; obj = obj->nexthere) 1258. if (obj->otyp == BOULDER) 1259. map_object(obj, 1); 1260. } 1261. 1262. /* Map the traps */ 1263. for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) { 1264. ttmp->tseen = 1; 1265. map_trap(ttmp, 1); 1266. } 1267. } 1268. 1269. 1270. /*detect.c*/
|