PropertyValue
rdfs:label
  • Source:NetHack 3.4.0/display.c
rdfs:comment
  • Below is the full text to display.c from the source code of NetHack 3.4.0. To link to a particular line, write [[NetHack 3.4.0/display.c#line123]], for example. Warning! This is the source code from an old release. For the latest release, see Source code
dcterms:subject
dbkwik:nethack/property/wikiPageUsesTemplate
abstract
  • Below is the full text to display.c from the source code of NetHack 3.4.0. To link to a particular line, write [[NetHack 3.4.0/display.c#line123]], for example. Warning! This is the source code from an old release. For the latest release, see Source code 1. /* SCCS Id: @(#)display.c 3.4 2000/07/27 */ 2. /* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */ 3. /* and Dave Cohrs, 1990. */ 4. /* NetHack may be freely redistributed. See license for details. */ 5. 6. /* 7. * THE NEW DISPLAY CODE 8. * 9. * The old display code has been broken up into three parts: vision, display, 10. * and drawing. Vision decides what locations can and cannot be physically 11. * seen by the hero. Display decides _what_ is displayed at a given location. 12. * Drawing decides _how_ to draw a monster, fountain, sword, etc. 13. * 14. * The display system uses information from the vision system to decide 15. * what to draw at a given location. The routines for the vision system 16. * can be found in vision.c and vision.h. The routines for display can 17. * be found in this file (display.c) and display.h. The drawing routines 18. * are part of the window port. See doc/window.doc for the drawing 19. * interface. 20. * 21. * The display system deals with an abstraction called a glyph. Anything 22. * that could possibly be displayed has a unique glyph identifier. 23. * 24. * What is seen on the screen is a combination of what the hero remembers 25. * and what the hero currently sees. Objects and dungeon features (walls 26. * doors, etc) are remembered when out of sight. Monsters and temporary 27. * effects are not remembered. Each location on the level has an 28. * associated glyph. This is the hero's _memory_ of what he or she has 29. * seen there before. 30. * 31. * Display rules: 32. * 33. * If the location is in sight, display in order: 34. * visible (or sensed) monsters 35. * visible objects 36. * known traps 37. * background 38. * 39. * If the location is out of sight, display in order: 40. * sensed monsters (telepathy) 41. * memory 42. * 43. * 44. * 45. * Here is a list of the major routines in this file to be used externally: 46. * 47. * newsym 48. * 49. * Possibly update the screen location (x,y). This is the workhorse routine. 50. * It is always correct --- where correct means following the in-sight/out- 51. * of-sight rules. **Most of the code should use this routine.** This 52. * routine updates the map and displays monsters. 53. * 54. * 55. * map_background 56. * map_object 57. * map_trap 58. * map_invisible 59. * unmap_object 60. * 61. * If you absolutely must override the in-sight/out-of-sight rules, there 62. * are two possibilities. First, you can mess with vision to force the 63. * location in sight then use newsym(), or you can use the map_* routines. 64. * The first has not been tried [no need] and the second is used in the 65. * detect routines --- detect object, magic mapping, etc. The map_* 66. * routines *change* what the hero remembers. All changes made by these 67. * routines will be sticky --- they will survive screen redraws. Do *not* 68. * use these for things that only temporarily change the screen. These 69. * routines are also used directly by newsym(). unmap_object is used to 70. * clear a remembered object when/if detection reveals it isn't there. 71. * 72. * 73. * show_glyph 74. * 75. * This is direct (no processing in between) buffered access to the screen. 76. * Temporary screen effects are run through this and its companion, 77. * flush_screen(). There is yet a lower level routine, print_glyph(), 78. * but this is unbuffered and graphic dependent (i.e. it must be surrounded 79. * by graphic set-up and tear-down routines). Do not use print_glyph(). 80. * 81. * 82. * see_monsters 83. * see_objects 84. * see_traps 85. * 86. * These are only used when something affects all of the monsters or 87. * objects or traps. For objects and traps, the only thing is hallucination. 88. * For monsters, there are hallucination and changing from/to blindness, etc. 89. * 90. * 91. * tmp_at 92. * 93. * This is a useful interface for displaying temporary items on the screen. 94. * Its interface is different than previously, so look at it carefully. 95. * 96. * 97. * 98. * Parts of the rm structure that are used: 99. * 100. * typ - What is really there. 101. * glyph - What the hero remembers. This will never be a monster. 102. * Monsters "float" above this. 103. * lit - True if the position is lit. An optimization for 104. * lit/unlit rooms. 105. * waslit - True if the position was *remembered* as lit. 106. * seenv - A vector of bits representing the directions from which the 107. * hero has seen this position. The vector's primary use is 108. * determining how walls are seen. E.g. a wall sometimes looks 109. * like stone on one side, but is seen as a wall from the other. 110. * Other uses are for unmapping detected objects and felt 111. * locations, where we need to know if the hero has ever 112. * seen the location. 113. * flags - Additional information for the typ field. Different for 114. * each typ. 115. * horizontal - Indicates whether the wall or door is horizontal or 116. * vertical. 117. */ 118. #include "hack.h" 119. #include "region.h" 120. 121. STATIC_DCL void FDECL(display_monster,(XCHAR_P,XCHAR_P,struct monst *,int,XCHAR_P)); 122. STATIC_DCL int FDECL(swallow_to_glyph, (int, int)); 123. STATIC_DCL void FDECL(display_warning,(struct monst *)); 124. 125. STATIC_DCL int FDECL(check_pos, (int, int, int)); 126. #ifdef WA_VERBOSE 127. STATIC_DCL boolean FDECL(more_than_one, (int, int, int, int, int)); 128. #endif 129. STATIC_DCL int FDECL(set_twall, (int,int, int,int, int,int, int,int)); 130. STATIC_DCL int FDECL(set_wall, (int, int, int)); 131. STATIC_DCL int FDECL(set_corn, (int,int, int,int, int,int, int,int)); 132. STATIC_DCL int FDECL(set_crosswall, (int, int)); 133. STATIC_DCL void FDECL(set_seenv, (struct rm *, int, int, int, int)); 134. STATIC_DCL void FDECL(t_warn, (struct rm *)); 135. STATIC_DCL int FDECL(wall_angle, (struct rm *)); 136. 137. #ifdef INVISIBLE_OBJECTS 138. /* 139. * vobj_at() 140. * 141. * Returns a pointer to an object if the hero can see an object at the 142. * given location. This takes care of invisible objects. NOTE, this 143. * assumes that the hero is not blind and on top of the object pile. 144. * It does NOT take into account that the location is out of sight, or, 145. * say, one can see blessed, etc. 146. */ 147. struct obj * 148. vobj_at(x,y) 149. xchar x,y; 150. { 151. register struct obj *obj = level.objects[x][y]; 152. 153. while (obj) { 154. if (!obj->oinvis || See_invisible) return obj; 155. obj = obj->nexthere; 156. } 157. return ((struct obj *) 0); 158. } 159. #endif /* else vobj_at() is defined in display.h */ 160. 161. /* 162. * magic_map_background() 163. * 164. * This function is similar to map_background (see below) except we pay 165. * attention to and correct unexplored, lit ROOM and CORR spots. 166. */ 167. void 168. magic_map_background(x, y, show) 169. xchar x,y; 170. int show; 171. { 172. int glyph = back_to_glyph(x,y); /* assumes hero can see x,y */ 173. struct rm *lev = &levl[x][y]; 174. 175. /* 176. * Correct for out of sight lit corridors and rooms that the hero 177. * doesn't remember as lit. 178. */ 179. if (!cansee(x,y) && !lev->waslit) { 180. /* Floor spaces are dark if unlit. Corridors are dark if unlit. */ 181. if (lev->typ == ROOM && glyph == cmap_to_glyph(S_room)) 182. glyph = cmap_to_glyph(S_stone); 183. else if (lev->typ == CORR && glyph == cmap_to_glyph(S_litcorr)) 184. glyph = cmap_to_glyph(S_corr); 185. } 186. if (level.flags.hero_memory) 187. lev->glyph = glyph; 188. if (show) show_glyph(x,y, glyph); 189. } 190. 191. /* 192. * The routines map_background(), map_object(), and map_trap() could just 193. * as easily be: 194. * 195. * map_glyph(x,y,glyph,show) 196. * 197. * Which is called with the xx_to_glyph() in the call. Then I can get 198. * rid of 3 routines that don't do very much anyway. And then stop 199. * having to create fake objects and traps. However, I am reluctant to 200. * make this change. 201. */ 202. /* FIXME: some of these use xchars for x and y, and some use ints. Make 203. * this consistent. 204. */ 205. 206. /* 207. * map_background() 208. * 209. * Make the real background part of our map. This routine assumes that 210. * the hero can physically see the location. Update the screen if directed. 211. */ 212. void 213. map_background(x, y, show) 214. register xchar x,y; 215. register int show; 216. { 217. register int glyph = back_to_glyph(x,y); 218. 219. if (level.flags.hero_memory) 220. levl[x][y].glyph = glyph; 221. if (show) show_glyph(x,y, glyph); 222. } 223. 224. /* 225. * map_trap() 226. * 227. * Map the trap and print it out if directed. This routine assumes that the 228. * hero can physically see the location. 229. */ 230. void 231. map_trap(trap, show) 232. register struct trap *trap; 233. register int show; 234. { 235. register int x = trap->tx, y = trap->ty; 236. register int glyph = trap_to_glyph(trap); 237. 238. if (level.flags.hero_memory) 239. levl[x][y].glyph = glyph; 240. if (show) show_glyph(x, y, glyph); 241. } 242. 243. /* 244. * map_object() 245. * 246. * Map the given object. This routine assumes that the hero can physically 247. * see the location of the object. Update the screen if directed. 248. */ 249. void 250. map_object(obj, show) 251. register struct obj *obj; 252. register int show; 253. { 254. register int x = obj->ox, y = obj->oy; 255. register int glyph = obj_to_glyph(obj); 256. 257. if (level.flags.hero_memory) 258. levl[x][y].glyph = glyph; 259. if (show) show_glyph(x, y, glyph); 260. } 261. 262. /* 263. * map_invisible() 264. * 265. * Make the hero remember that a square contains an invisible monster. 266. * This is a special case in that the square will continue to be displayed 267. * this way even when the hero is close enough to see it. To get rid of 268. * this and display the square's actual contents, use unmap_object() followed 269. * by newsym() if necessary. 270. */ 271. void 272. map_invisible(x, y) 273. register xchar x, y; 274. { 275. if (level.flags.hero_memory) 276. levl[x][y].glyph = GLYPH_INVISIBLE; 277. show_glyph(x, y, GLYPH_INVISIBLE); 278. } 279. 280. /* 281. * unmap_object() 282. * 283. * Remove something from the map when the hero realizes it's not there any 284. * more. Replace it with background or known trap, but not with any other 285. * If this is used for detection, a full screen update is imminent anyway; 286. * if this is used to get rid of an invisible monster notation, we might have 287. * to call newsym(). 288. */ 289. void 290. unmap_object(x, y) 291. register int x, y; 292. { 293. register struct trap *trap; 294. 295. if (!level.flags.hero_memory) return; 296. 297. if ((trap = t_at(x,y)) != 0 && trap->tseen && !covers_traps(x,y)) 298. map_trap(trap, 0); 299. else if (levl[x][y].seenv) { 300. struct rm *lev = &levl[x][y]; 301. 302. map_background(x, y, 0); 303. 304. /* turn remembered dark room squares dark */ 305. if (!lev->waslit && lev->glyph == cmap_to_glyph(S_room) && 306. lev->typ == ROOM) 307. lev->glyph = cmap_to_glyph(S_stone); 308. } else 309. levl[x][y].glyph = cmap_to_glyph(S_stone); /* default val */ 310. } 311. 312. 313. /* 314. * map_location() 315. * 316. * Make whatever at this location show up. This is only for non-living 317. * things. This will not handle feeling invisible objects correctly. 318. * 319. * Internal to display.c, this is a #define for speed. 320. */ 321. #define _map_location(x,y,show) \ 322. { \ 323. register struct obj *obj; \ 324. register struct trap *trap; \ 325. \ 326. if ((obj = vobj_at(x,y)) && !covers_objects(x,y)) \ 327. map_object(obj,show); \ 328. else if ((trap = t_at(x,y)) && trap->tseen && !covers_traps(x,y)) \ 329. map_trap(trap,show); \ 330. else \ 331. map_background(x,y,show); \ 332. } 333. 334. void map_location(x,y,show) 335. int x, y, show; 336. { 337. _map_location(x,y,show); 338. } 339. 340. #define DETECTED 2 341. #define PHYSICALLY_SEEN 1 342. #define is_worm_tail(mon) ((mon) && ((x != (mon)->mx) || (y != (mon)->my))) 343. 344. /* 345. * display_monster() 346. * 347. * Note that this is *not* a map_XXXX() function! Monsters sort of float 348. * above everything. 349. * 350. * Yuck. Display body parts by recognizing that the display position is 351. * not the same as the monster position. Currently the only body part is 352. * a worm tail. 353. * 354. */ 355. STATIC_OVL void 356. display_monster(x, y, mon, sightflags, worm_tail) 357. register xchar x, y; /* display position */ 358. register struct monst *mon; /* monster to display */ 359. int sightflags; /* 1 if the monster is physically seen */ 360. /* 2 if detected using Detect_monsters */ 361. register xchar worm_tail; /* mon is actually a worm tail */ 362. { 363. register boolean mon_mimic = (mon->m_ap_type != M_AP_NOTHING); 364. register int sensed = mon_mimic && 365. (Protection_from_shape_changers || sensemon(mon)); 366. /* 367. * We must do the mimic check first. If the mimic is mimicing something, 368. * and the location is in sight, we have to change the hero's memory 369. * so that when the position is out of sight, the hero remembers what 370. * the mimic was mimicing. 371. */ 372. 373. if (mon_mimic && sightflags) { 374. switch (mon->m_ap_type) { 375. default: 376. impossible("display_monster: bad m_ap_type value [ = %d ]", 377. (int) mon->m_ap_type); 378. case M_AP_NOTHING: 379. show_glyph(x, y, mon_to_glyph(mon)); 380. break; 381. 382. case M_AP_FURNITURE: { 383. /* 384. * This is a poor man's version of map_background(). I can't 385. * use map_background() because we are overriding what is in 386. * the 'typ' field. Maybe have map_background()'s parameters 387. * be (x,y,glyph) instead of just (x,y). 388. * 389. * mappearance is currently set to an S_ index value in 390. * makemon.c. 391. */ 392. register int glyph = cmap_to_glyph(mon->mappearance); 393. levl[x][y].glyph = glyph; 394. if (!sensed) show_glyph(x,y, glyph); 395. break; 396. } 397. 398. case M_AP_OBJECT: { 399. struct obj obj; /* Make a fake object to send */ 400. /* to map_object(). */ 401. obj.ox = x; 402. obj.oy = y; 403. obj.otyp = mon->mappearance; 404. obj.corpsenm = PM_TENGU; /* if mimicing a corpse */ 405. map_object(&obj,!sensed); 406. break; 407. } 408. 409. case M_AP_MONSTER: 410. show_glyph(x,y, monnum_to_glyph(what_mon((int)mon->mappearance))); 411. break; 412. } 413. 414. } 415. 416. /* If the mimic is unsucessfully mimicing something, display the monster */ 417. if (!mon_mimic || sensed) { 418. int num; 419. 420. /* [ALI] Only use detected glyphs when monster wouldn't be 421. * visible by any other means. 422. */ 423. if (sightflags == DETECTED) { 424. if (worm_tail) 425. num = detected_monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)); 426. else 427. num = detected_mon_to_glyph(mon); 428. } else if (mon->mtame && !Hallucination) { 429. if (worm_tail) 430. num = petnum_to_glyph(PM_LONG_WORM_TAIL); 431. else 432. num = pet_to_glyph(mon); 433. } else { 434. if (worm_tail) 435. num = monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)); 436. else 437. num = mon_to_glyph(mon); 438. } 439. show_glyph(x,y,num); 440. } 441. } 442. 443. /* 444. * display_warning() 445. * 446. * This is also *not* a map_XXXX() function! Monster warnings float 447. * above everything just like monsters do, but only if the monster 448. * is not showing. 449. * 450. * Do not call for worm tails. 451. */ 452. STATIC_OVL void 453. display_warning(mon) 454. register struct monst *mon; 455. { 456. int x = mon->mx, y = mon->my; 457. int wl = (int) (mon->m_lev / 4); 458. int glyph; 459. 460. if (mon_warning(mon)) { 461. if (wl > WARNCOUNT - 1) wl = WARNCOUNT - 1; 462. glyph = warning_to_glyph(wl); 463. } else if (MATCH_WARN_OF_MON(mon)) { 464. glyph = mon_to_glyph(mon); 465. } else { 466. impossible("display_warning did not match warning type?"); 467. return; 468. } 469. show_glyph(x, y, glyph); 470. } 471. 472. /* 473. * feel_location() 474. * 475. * Feel the given location. This assumes that the hero is blind and that 476. * the given position is either the hero's or one of the eight squares 477. * adjacent to the hero (except for a boulder push). 478. * If an invisible monster has gone away, that will be discovered. If an 479. * invisible monster has appeared, this will _not_ be discovered since 480. * searching only finds one monster per turn so we must check that separately. 481. */ 482. void 483. feel_location(x, y) 484. xchar x, y; 485. { 486. struct rm *lev = &(levl[x][y]); 487. struct obj *boulder; 488. register struct monst *mon; 489. 490. /* If the hero's memory of an invisible monster is accurate, we want to keep 491. * him from detecting the same monster over and over again on each turn. 492. * We must return (so we don't erase the monster). (We must also, in the 493. * search function, be sure to skip over previously detected 'I's.) 494. */ 495. if (glyph_is_invisible(levl[x][y].glyph) && m_at(x,y)) return; 496. 497. /* The hero can't feel non pool locations while under water. */ 498. if (Underwater && !Is_waterlevel(&u.uz) && ! is_pool(x,y)) 499. return; 500. 501. /* Set the seen vector as if the hero had seen it. It doesn't matter */ 502. /* if the hero is levitating or not. */ 503. set_seenv(lev, u.ux, u.uy, x, y); 504. 505. if (Levitation && !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz)) { 506. /* 507. * Levitation Rules. It is assumed that the hero can feel the state 508. * of the walls around herself and can tell if she is in a corridor, 509. * room, or doorway. Boulders are felt because they are large enough. 510. * Anything else is unknown because the hero can't reach the ground. 511. * This makes things difficult. 512. * 513. * Check (and display) in order: 514. * 515. * + Stone, walls, and closed doors. 516. * + Boulders. [see a boulder before a doorway] 517. * + Doors. 518. * + Room/water positions 519. * + Everything else (hallways!) 520. */ 521. if (IS_ROCK(lev->typ) || (IS_DOOR(lev->typ) && 522. (lev->doormask & (D_LOCKED | D_CLOSED)))) { 523. map_background(x, y, 1); 524. } else if ((boulder = sobj_at(BOULDER,x,y)) != 0) { 525. map_object(boulder, 1); 526. } else if (IS_DOOR(lev->typ)) { 527. map_background(x, y, 1); 528. } else if (IS_ROOM(lev->typ) || IS_POOL(lev->typ)) { 529. /* 530. * An open room or water location. Normally we wouldn't touch 531. * this, but we have to get rid of remembered boulder symbols. 532. * This will only occur in rare occations when the hero goes 533. * blind and doesn't find a boulder where expected (something 534. * came along and picked it up). We know that there is not a 535. * boulder at this location. Show fountains, pools, etc. 536. * underneath if already seen. Otherwise, show the appropriate 537. * floor symbol. 538. * 539. * This isn't quite correct. If the boulder was on top of some 540. * other objects they should be seen once the boulder is removed. 541. * However, we have no way of knowing that what is there now 542. * was there then. So we let the hero have a lapse of memory. 543. * We could also just display what is currently on the top of the 544. * object stack (if anything). 545. */ 546. if (lev->glyph == objnum_to_glyph(BOULDER)) { 547. if (lev->typ != ROOM && lev->seenv) { 548. map_background(x, y, 1); 549. } else { 550. lev->glyph = lev->waslit ? cmap_to_glyph(S_room) : 551. cmap_to_glyph(S_stone); 552. show_glyph(x,y,lev->glyph); 553. } 554. } 555. } else { 556. /* We feel it (I think hallways are the only things left). */ 557. map_background(x, y, 1); 558. /* Corridors are never felt as lit (unless remembered that way) */ 559. /* (lit_corridor only). */ 560. if (lev->typ == CORR && 561. lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit) 562. show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr)); 563. } 564. } else { 565. _map_location(x, y, 1); 566. 567. if (Punished) { 568. /* 569. * A ball or chain is only felt if it is first on the object 570. * location list. Otherwise, we need to clear the felt bit --- 571. * something has been dropped on the ball/chain. If the bit is 572. * not cleared, then when the ball/chain is moved it will drop 573. * the wrong glyph. 574. */ 575. if (uchain->ox == x && uchain->oy == y) { 576. if (level.objects[x][y] == uchain) 577. u.bc_felt |= BC_CHAIN; 578. else 579. u.bc_felt &= ~BC_CHAIN; /* do not feel the chain */ 580. } 581. if (!carried(uball) && uball->ox == x && uball->oy == y) { 582. if (level.objects[x][y] == uball) 583. u.bc_felt |= BC_BALL; 584. else 585. u.bc_felt &= ~BC_BALL; /* do not feel the ball */ 586. } 587. } 588. 589. /* Floor spaces are dark if unlit. Corridors are dark if unlit. */ 590. if (lev->typ == ROOM && 591. lev->glyph == cmap_to_glyph(S_room) && !lev->waslit) 592. show_glyph(x,y, lev->glyph = cmap_to_glyph(S_stone)); 593. else if (lev->typ == CORR && 594. lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit) 595. show_glyph(x,y, lev->glyph = cmap_to_glyph(S_corr)); 596. } 597. /* draw monster on top if we can sense it */ 598. if ((x != u.ux || y != u.uy) && (mon = m_at(x,y)) && sensemon(mon)) 599. display_monster(x, y, mon, 600. (tp_sensemon(mon) || MATCH_WARN_OF_MON(mon)) ? PHYSICALLY_SEEN : DETECTED, 601. is_worm_tail(mon)); 602. } 603. 604. /* 605. * newsym() 606. * 607. * Possibly put a new glyph at the given location. 608. */ 609. void 610. newsym(x,y) 611. register int x,y; 612. { 613. register struct monst *mon; 614. register struct rm *lev = &(levl[x][y]); 615. register int see_it; 616. register xchar worm_tail; 617. 618. if (in_mklev) return; 619. 620. /* only permit updating the hero when swallowed */ 621. if (u.uswallow) { 622. if (x == u.ux && y == u.uy) display_self(); 623. return; 624. } 625. if (Underwater && !Is_waterlevel(&u.uz)) { 626. /* don't do anything unless (x,y) is an adjacent underwater position */ 627. int dx, dy; 628. if (!is_pool(x,y)) return; 629. dx = x - u.ux; if (dx < 0) dx = -dx; 630. dy = y - u.uy; if (dy < 0) dy = -dy; 631. if (dx > 1 || dy > 1) return; 632. } 633. 634. /* Can physically see the location. */ 635. if (cansee(x,y)) { 636. NhRegion* reg = visible_region_at(x,y); 637. /* 638. * Don't use templit here: E.g. 639. * 640. * lev->waslit = !!(lev->lit || templit(x,y)); 641. * 642. * Otherwise we have the "light pool" problem, where non-permanently 643. * lit areas just out of sight stay remembered as lit. They should 644. * re-darken. 645. * 646. * Perhaps ALL areas should revert to their "unlit" look when 647. * out of sight. 648. */ 649. lev->waslit = (lev->lit!=0); /* remember lit condition */ 650. 651. if (reg != NULL && ACCESSIBLE(lev->typ)) { 652. show_region(reg,x,y); 653. return; 654. } 655. if (x == u.ux && y == u.uy) { 656. if (canseeself()) { 657. _map_location(x,y,0); /* map *under* self */ 658. display_self(); 659. } else 660. /* we can see what is there */ 661. _map_location(x,y,1); 662. } 663. else { 664. mon = m_at(x,y); 665. worm_tail = is_worm_tail(mon); 666. see_it = mon && (worm_tail 667. ? (!mon->minvis || See_invisible) 668. : (mon_visible(mon)) || tp_sensemon(mon) || MATCH_WARN_OF_MON(mon)); 669. if (mon && (see_it || (!worm_tail && Detect_monsters))) { 670. if (mon->mtrapped) { 671. struct trap *trap = t_at(x, y); 672. int tt = trap ? trap->ttyp : NO_TRAP; 673. 674. /* if monster is in a physical trap, you see the trap too */ 675. if (tt == BEAR_TRAP || tt == PIT || 676. tt == SPIKED_PIT ||tt == WEB) { 677. trap->tseen = TRUE; 678. } 679. } 680. _map_location(x,y,0); /* map under the monster */ 681. /* also gets rid of any invisibility glyph */ 682. display_monster(x, y, mon, see_it ? PHYSICALLY_SEEN : DETECTED, worm_tail); 683. } 684. else if (mon && mon_warning(mon) && !is_worm_tail(mon)) 685. display_warning(mon); 686. else if (glyph_is_invisible(levl[x][y].glyph)) 687. map_invisible(x, y); 688. else 689. _map_location(x,y,1); /* map the location */ 690. } 691. } 692. 693. /* Can't see the location. */ 694. else { 695. if (x == u.ux && y == u.uy) { 696. feel_location(u.ux, u.uy); /* forces an update */ 697. 698. if (canseeself()) display_self(); 699. } 700. else if ((mon = m_at(x,y)) 701. && ((see_it = (tp_sensemon(mon) || MATCH_WARN_OF_MON(mon) 702. || (see_with_infrared(mon) && mon_visible(mon)))) 703. || Detect_monsters) 704. && !is_worm_tail(mon)) { 705. /* Monsters are printed every time. */ 706. /* This also gets rid of any invisibility glyph */ 707. display_monster(x, y, mon, see_it ? 0 : DETECTED, 0); 708. } 709. else if ((mon = m_at(x,y)) && mon_warning(mon) && 710. !is_worm_tail(mon)) { 711. display_warning(mon); 712. } 713. 714. /* 715. * If the location is remembered as being both dark (waslit is false) 716. * and lit (glyph is a lit room or lit corridor) then it was either: 717. * 718. * (1) A dark location that the hero could see through night 719. * vision. 720. * 721. * (2) Darkened while out of the hero's sight. This can happen 722. * when cursed scroll of light is read. 723. * 724. * In either case, we have to manually correct the hero's memory to 725. * match waslit. Deciding when to change waslit is non-trivial. 726. * 727. * Note: If flags.lit_corridor is set, then corridors act like room 728. * squares. That is, they light up if in night vision range. 729. * If flags.lit_corridor is not set, then corridors will 730. * remain dark unless lit by a light spell. 731. * 732. * These checks and changes must be here and not in back_to_glyph(). 733. * They are dependent on the position being out of sight. 734. */ 735. else if (!lev->waslit) { 736. if (flags.lit_corridor && lev->glyph == cmap_to_glyph(S_litcorr) && 737. lev->typ == CORR) 738. show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr)); 739. else if (lev->glyph == cmap_to_glyph(S_room) && lev->typ == ROOM) 740. show_glyph(x, y, lev->glyph = cmap_to_glyph(S_stone)); 741. else 742. goto show_mem; 743. } else { 744. show_mem: 745. show_glyph(x, y, lev->glyph); 746. } 747. } 748. } 749. 750. #undef is_worm_tail 751. 752. /* 753. * shieldeff() 754. * 755. * Put magic shield pyrotechnics at the given location. This *could* be 756. * pulled into a platform dependent routine for fancier graphics if desired. 757. */ 758. void 759. shieldeff(x,y) 760. xchar x,y; 761. { 762. register int i; 763. 764. if (!flags.sparkle) return; 765. if (cansee(x,y)) { /* Don't see anything if can't see the location */ 766. for (i = 0; i < SHIELD_COUNT; i++) { 767. show_glyph(x, y, cmap_to_glyph(shield_static[i])); 768. flush_screen(1); /* make sure the glyph shows up */ 769. delay_output(); 770. } 771. newsym(x,y); /* restore the old information */ 772. } 773. } 774. 775. 776. /* 777. * tmp_at() 778. * 779. * Temporarily place glyphs on the screen. Do not call delay_output(). It 780. * is up to the caller to decide if it wants to wait [presently, everyone 781. * but explode() wants to delay]. 782. * 783. * Call: 784. * (DISP_BEAM, glyph) open, initialize glyph 785. * (DISP_FLASH, glyph) open, initialize glyph 786. * (DISP_ALWAYS, glyph) open, initialize glyph 787. * (DISP_CHANGE, glyph) change glyph 788. * (DISP_END, 0) close & clean up (second argument doesn't 789. * matter) 790. * (DISP_FREEMEM, 0) only used to prevent memory leak during 791. * exit) 792. * (x, y) display the glyph at the location 793. * 794. * DISP_BEAM - Display the given glyph at each location, but do not erase 795. * any until the close call. 796. * DISP_FLASH - Display the given glyph at each location, but erase the 797. * previous location's glyph. 798. * DISP_ALWAYS- Like DISP_FLASH, but vision is not taken into account. 799. */ 800. 801. static struct tmp_glyph { 802. coord saved[COLNO]; /* previously updated positions */ 803. int sidx; /* index of next unused slot in saved[] */ 804. int style; /* either DISP_BEAM or DISP_FLASH or DISP_ALWAYS */ 805. int glyph; /* glyph to use when printing */ 806. struct tmp_glyph *prev; 807. } tgfirst; 808. 809. void 810. tmp_at(x, y) 811. int x, y; 812. { 813. static struct tmp_glyph *tglyph = (struct tmp_glyph *)0; 814. struct tmp_glyph *tmp; 815. 816. switch (x) { 817. case DISP_BEAM: 818. case DISP_FLASH: 819. case DISP_ALWAYS: 820. if (!tglyph) 821. tmp = &tgfirst; 822. else /* nested effect; we need dynamic memory */ 823. tmp = (struct tmp_glyph *)alloc(sizeof (struct tmp_glyph)); 824. tmp->prev = tglyph; 825. tglyph = tmp; 826. tglyph->sidx = 0; 827. tglyph->style = x; 828. tglyph->glyph = y; 829. flush_screen(0); /* flush buffered glyphs */ 830. return; 831. 832. case DISP_FREEMEM: /* in case game ends with tmp_at() in progress */ 833. while (tglyph) { 834. tmp = tglyph->prev; 835. if (tglyph != &tgfirst) free((genericptr_t)tglyph); 836. tglyph = tmp; 837. } 838. return; 839. 840. default: 841. break; 842. } 843. 844. if (!tglyph) panic("tmp_at: tglyph not initialized"); 845. 846. switch (x) { 847. case DISP_CHANGE: 848. tglyph->glyph = y; 849. break; 850. 851. case DISP_END: 852. if (tglyph->style == DISP_BEAM) { 853. register int i; 854. 855. /* Erase (reset) from source to end */ 856. for (i = 0; i < tglyph->sidx; i++) 857. newsym(tglyph->saved[i].x, tglyph->saved[i].y); 858. } else { /* DISP_FLASH or DISP_ALWAYS */ 859. if (tglyph->sidx) /* been called at least once */ 860. newsym(tglyph->saved[0].x, tglyph->saved[0].y); 861. } 862. /* tglyph->sidx = 0; -- about to be freed, so not necessary */ 863. tmp = tglyph->prev; 864. if (tglyph != &tgfirst) free((genericptr_t)tglyph); 865. tglyph = tmp; 866. break; 867. 868. default: /* do it */ 869. if (tglyph->style == DISP_BEAM) { 870. if (!cansee(x,y)) break; 871. /* save pos for later erasing */ 872. tglyph->saved[tglyph->sidx].x = x; 873. tglyph->saved[tglyph->sidx].y = y; 874. tglyph->sidx += 1; 875. } else { /* DISP_FLASH/ALWAYS */ 876. if (tglyph->sidx) { /* not first call, so reset previous pos */ 877. newsym(tglyph->saved[0].x, tglyph->saved[0].y); 878. tglyph->sidx = 0; /* display is presently up to date */ 879. } 880. if (!cansee(x,y) && tglyph->style != DISP_ALWAYS) break; 881. tglyph->saved[0].x = x; 882. tglyph->saved[0].y = y; 883. tglyph->sidx = 1; 884. } 885. 886. show_glyph(x, y, tglyph->glyph); /* show it */ 887. flush_screen(0); /* make sure it shows up */ 888. break; 889. } /* end case */ 890. } 891. 892. 893. /* 894. * swallowed() 895. * 896. * The hero is swallowed. Show a special graphics sequence for this. This 897. * bypasses all of the display routines and messes with buffered screen 898. * directly. This method works because both vision and display check for 899. * being swallowed. 900. */ 901. void 902. swallowed(first) 903. int first; 904. { 905. static xchar lastx, lasty; /* last swallowed position */ 906. int swallower, left_ok, rght_ok; 907. 908. if (first) 909. cls(); 910. else { 911. register int x, y; 912. 913. /* Clear old location */ 914. for (y = lasty-1; y <= lasty+1; y++) 915. for (x = lastx-1; x <= lastx+1; x++) 916. if (isok(x,y)) show_glyph(x,y,cmap_to_glyph(S_stone)); 917. } 918. 919. swallower = monsndx(u.ustuck->data); 920. /* assume isok(u.ux,u.uy) */ 921. left_ok = isok(u.ux-1,u.uy); 922. rght_ok = isok(u.ux+1,u.uy); 923. /* 924. * Display the hero surrounded by the monster's stomach. 925. */ 926. if(isok(u.ux, u.uy-1)) { 927. if (left_ok) 928. show_glyph(u.ux-1, u.uy-1, swallow_to_glyph(swallower, S_sw_tl)); 929. show_glyph(u.ux , u.uy-1, swallow_to_glyph(swallower, S_sw_tc)); 930. if (rght_ok) 931. show_glyph(u.ux+1, u.uy-1, swallow_to_glyph(swallower, S_sw_tr)); 932. } 933. 934. if (left_ok) 935. show_glyph(u.ux-1, u.uy , swallow_to_glyph(swallower, S_sw_ml)); 936. display_self(); 937. if (rght_ok) 938. show_glyph(u.ux+1, u.uy , swallow_to_glyph(swallower, S_sw_mr)); 939. 940. if(isok(u.ux, u.uy+1)) { 941. if (left_ok) 942. show_glyph(u.ux-1, u.uy+1, swallow_to_glyph(swallower, S_sw_bl)); 943. show_glyph(u.ux , u.uy+1, swallow_to_glyph(swallower, S_sw_bc)); 944. if (rght_ok) 945. show_glyph(u.ux+1, u.uy+1, swallow_to_glyph(swallower, S_sw_br)); 946. } 947. 948. /* Update the swallowed position. */ 949. lastx = u.ux; 950. lasty = u.uy; 951. } 952. 953. /* 954. * under_water() 955. * 956. * Similar to swallowed() in operation. Shows hero when underwater 957. * except when in water level. Special routines exist for that. 958. */ 959. void 960. under_water(mode) 961. int mode; 962. { 963. static xchar lastx, lasty; 964. static boolean dela; 965. register int x, y; 966. 967. /* swallowing has a higher precedence than under water */ 968. if (Is_waterlevel(&u.uz) || u.uswallow) return; 969. 970. /* full update */ 971. if (mode == 1 || dela) { 972. cls(); 973. dela = FALSE; 974. } 975. /* delayed full update */ 976. else if (mode == 2) { 977. dela = TRUE; 978. return; 979. } 980. /* limited update */ 981. else { 982. for (y = lasty-1; y <= lasty+1; y++) 983. for (x = lastx-1; x <= lastx+1; x++) 984. if (isok(x,y)) 985. show_glyph(x,y,cmap_to_glyph(S_stone)); 986. } 987. for (x = u.ux-1; x <= u.ux+1; x++) 988. for (y = u.uy-1; y <= u.uy+1; y++) 989. if (isok(x,y) && is_pool(x,y)) { 990. if (Blind && !(x == u.ux && y == u.uy)) 991. show_glyph(x,y,cmap_to_glyph(S_stone)); 992. else 993. newsym(x,y); 994. } 995. lastx = u.ux; 996. lasty = u.uy; 997. } 998. 999. /* 1000. * under_ground() 1001. * 1002. * Very restricted display. You can only see yourself. 1003. */ 1004. void 1005. under_ground(mode) 1006. int mode; 1007. { 1008. static boolean dela; 1009. 1010. /* swallowing has a higher precedence than under ground */ 1011. if (u.uswallow) return; 1012. 1013. /* full update */ 1014. if (mode == 1 || dela) { 1015. cls(); 1016. dela = FALSE; 1017. } 1018. /* delayed full update */ 1019. else if (mode == 2) { 1020. dela = TRUE; 1021. return; 1022. } 1023. /* limited update */ 1024. else 1025. newsym(u.ux,u.uy); 1026. } 1027. 1028. 1029. /* ========================================================================= */ 1030. 1031. /* 1032. * Loop through all of the monsters and update them. Called when: 1033. * + going blind & telepathic 1034. * + regaining sight & telepathic 1035. * + getting and losing infravision 1036. * + hallucinating 1037. * + doing a full screen redraw 1038. * + see invisible times out or a ring of see invisible is taken off 1039. * + when a potion of see invisible is quaffed or a ring of see 1040. * invisible is put on 1041. * + gaining telepathy when blind [givit() in eat.c, pleased() in pray.c] 1042. * + losing telepathy while blind [xkilled() in mon.c, attrcurse() in 1043. * sit.c] 1044. */ 1045. void 1046. see_monsters() 1047. { 1048. register struct monst *mon; 1049. for (mon = fmon; mon; mon = mon->nmon) { 1050. if (DEADMONSTER(mon)) continue; 1051. newsym(mon->mx,mon->my); 1052. if (mon->wormno) see_wsegs(mon); 1053. } 1054. } 1055. 1056. /* 1057. * Block/unblock light depending on what a mimic is mimicing and if it's 1058. * invisible or not. Should be called only when the state of See_invisible 1059. * changes. 1060. */ 1061. void 1062. set_mimic_blocking() 1063. { 1064. register struct monst *mon; 1065. for (mon = fmon; mon; mon = mon->nmon) 1066. if(!DEADMONSTER(mon) && mon->minvis && 1067. ((mon->m_ap_type == M_AP_FURNITURE && 1068. (mon->mappearance == S_vcdoor || mon->mappearance == S_hcdoor))|| 1069. (mon->m_ap_type == M_AP_OBJECT && mon->mappearance == BOULDER))) { 1070. if(See_invisible) 1071. block_point(mon->mx, mon->my); 1072. else 1073. unblock_point(mon->mx, mon->my); 1074. } 1075. } 1076. 1077. /* 1078. * Loop through all of the object *locations* and update them. Called when 1079. * + hallucinating. 1080. */ 1081. void 1082. see_objects() 1083. { 1084. register struct obj *obj; 1085. for(obj = fobj; obj; obj = obj->nobj) 1086. if (vobj_at(obj->ox,obj->oy) == obj) newsym(obj->ox, obj->oy); 1087. } 1088. 1089. /* 1090. * Update hallucinated traps. 1091. */ 1092. void 1093. see_traps() 1094. { 1095. struct trap *trap; 1096. int glyph; 1097. 1098. for (trap = ftrap; trap; trap = trap->ntrap) { 1099. glyph = glyph_at(trap->tx, trap->ty); 1100. if (glyph_is_trap(glyph)) 1101. newsym(trap->tx, trap->ty); 1102. } 1103. } 1104. 1105. /* 1106. * Put the cursor on the hero. Flush all accumulated glyphs before doing it. 1107. */ 1108. void 1109. curs_on_u() 1110. { 1111. flush_screen(1); /* Flush waiting glyphs & put cursor on hero */ 1112. } 1113. 1114. int 1115. doredraw() 1116. { 1117. docrt(); 1118. return 0; 1119. } 1120. 1121. void 1122. docrt() 1123. { 1124. register int x,y; 1125. register struct rm *lev; 1126. 1127. if (!u.ux) return; /* display isn't ready yet */ 1128. 1129. if (u.uswallow) { 1130. swallowed(1); 1131. return; 1132. } 1133. if (Underwater && !Is_waterlevel(&u.uz)) { 1134. under_water(1); 1135. return; 1136. } 1137. if (u.uburied) { 1138. under_ground(1); 1139. return; 1140. } 1141. 1142. /* shut down vision */ 1143. vision_recalc(2); 1144. 1145. /* 1146. * This routine assumes that cls() does the following: 1147. * + fills the physical screen with the symbol for rock 1148. * + clears the glyph buffer 1149. */ 1150. cls(); 1151. 1152. /* display memory */ 1153. for (x = 1; x < COLNO; x++) { 1154. lev = &levl[x][0]; 1155. for (y = 0; y < ROWNO; y++, lev++) 1156. if (lev->glyph != cmap_to_glyph(S_stone)) 1157. show_glyph(x,y,lev->glyph); 1158. } 1159. 1160. /* see what is to be seen */ 1161. vision_recalc(0); 1162. 1163. /* overlay with monsters */ 1164. see_monsters(); 1165. 1166. flags.botlx = 1; /* force a redraw of the bottom line */ 1167. } 1168. 1169. 1170. /* ========================================================================= */ 1171. /* Glyph Buffering (3rd screen) ============================================ */ 1172. 1173. typedef struct { 1174. xchar new; /* perhaps move this bit into the rm strucure. */ 1175. int glyph; 1176. } gbuf_entry; 1177. 1178. static gbuf_entry gbuf[ROWNO][COLNO]; 1179. static char gbuf_start[ROWNO]; 1180. static char gbuf_stop[ROWNO]; 1181. 1182. /* 1183. * Store the glyph in the 3rd screen for later flushing. 1184. */ 1185. void 1186. show_glyph(x,y,glyph) 1187. int x, y, glyph; 1188. { 1189. /* 1190. * Check for bad positions and glyphs. 1191. */ 1192. if (!isok(x, y)) { 1193. const char *text; 1194. int offset; 1195. 1196. /* column 0 is invalid, but it's often used as a flag, so ignore it */ 1197. if (x == 0) return; 1198. 1199. /* 1200. * This assumes an ordering of the offsets. See display.h for 1201. * the definition. 1202. */ 1203. 1204. if (glyph >= GLYPH_WARNING_OFF) { /* a warning */ 1205. text = "warning"; offset = glyph - GLYPH_WARNING_OFF; 1206. } else if (glyph >= GLYPH_SWALLOW_OFF) { /* swallow border */ 1207. text = "swallow border"; offset = glyph - GLYPH_SWALLOW_OFF; 1208. } else if (glyph >= GLYPH_ZAP_OFF) { /* zap beam */ 1209. text = "zap beam"; offset = glyph - GLYPH_ZAP_OFF; 1210. } else if (glyph >= GLYPH_EXPLODE_OFF) { /* explosion */ 1211. text = "explosion"; offset = glyph - GLYPH_EXPLODE_OFF; 1212. } else if (glyph >= GLYPH_CMAP_OFF) { /* cmap */ 1213. text = "cmap_index"; offset = glyph - GLYPH_CMAP_OFF; 1214. } else if (glyph >= GLYPH_OBJ_OFF) { /* object */ 1215. text = "object"; offset = glyph - GLYPH_OBJ_OFF; 1216. } else if (glyph >= GLYPH_RIDDEN_OFF) { /* ridden mon */ 1217. text = "ridden mon"; offset = glyph - GLYPH_RIDDEN_OFF; 1218. } else if (glyph >= GLYPH_BODY_OFF) { /* a corpse */ 1219. text = "corpse"; offset = glyph - GLYPH_BODY_OFF; 1220. } else if (glyph >= GLYPH_DETECT_OFF) { /* detected mon */ 1221. text = "detected mon"; offset = glyph - GLYPH_DETECT_OFF; 1222. } else if (glyph >= GLYPH_INVIS_OFF) { /* invisible mon */ 1223. text = "invisible mon"; offset = glyph - GLYPH_INVIS_OFF; 1224. } else if (glyph >= GLYPH_PET_OFF) { /* a pet */ 1225. text = "pet"; offset = glyph - GLYPH_PET_OFF; 1226. } else { /* a monster */ 1227. text = "monster"; offset = glyph; 1228. } 1229. 1230. impossible("show_glyph: bad pos %d %d with glyph %d [%s %d].", 1231. x, y, glyph, text, offset); 1232. return; 1233. } 1234. 1235. if (glyph >= MAX_GLYPH) { 1236. impossible("show_glyph: bad glyph %d [max %d] at (%d,%d).", 1237. glyph, MAX_GLYPH, x, y); 1238. return; 1239. } 1240. 1241. if (gbuf[y][x].glyph != glyph) { 1242. gbuf[y][x].glyph = glyph; 1243. gbuf[y][x].new = 1; 1244. if (gbuf_start[y] > x) gbuf_start[y] = x; 1245. if (gbuf_stop[y] < x) gbuf_stop[y] = x; 1246. } 1247. } 1248. 1249. 1250. /* 1251. * Reset the changed glyph borders so that none of the 3rd screen has 1252. * changed. 1253. */ 1254. #define reset_glyph_bbox() \ 1255. { \ 1256. int i; \ 1257. \ 1258. for (i = 0; i < ROWNO; i++) { \ 1259. gbuf_start[i] = COLNO-1; \ 1260. gbuf_stop[i] = 0; \ 1261. } \ 1262. } 1263. 1264. 1265. static gbuf_entry nul_gbuf = { 0, cmap_to_glyph(S_stone) }; 1266. /* 1267. * Turn the 3rd screen into stone. 1268. */ 1269. void 1270. clear_glyph_buffer() 1271. { 1272. register int x, y; 1273. register gbuf_entry *gptr; 1274. 1275. for (y = 0; y < ROWNO; y++) { 1276. gptr = &gbuf[y][0]; 1277. for (x = COLNO; x; x--) { 1278. *gptr++ = nul_gbuf; 1279. } 1280. } 1281. reset_glyph_bbox(); 1282. } 1283. 1284. /* 1285. * Assumes that the indicated positions are filled with S_stone glyphs. 1286. */ 1287. void 1288. row_refresh(start,stop,y) 1289. int start,stop,y; 1290. { 1291. register int x; 1292. 1293. for (x = start; x <= stop; x++) 1294. if (gbuf[y][x].glyph != cmap_to_glyph(S_stone)) 1295. print_glyph(WIN_MAP,x,y,gbuf[y][x].glyph); 1296. } 1297. 1298. void 1299. cls() 1300. { 1301. display_nhwindow(WIN_MESSAGE, FALSE); /* flush messages */ 1302. flags.botlx = 1; /* force update of botl window */ 1303. clear_nhwindow(WIN_MAP); /* clear physical screen */ 1304. 1305. clear_glyph_buffer(); /* this is sort of an extra effort, but OK */ 1306. } 1307. 1308. /* 1309. * Synch the third screen with the display. 1310. */ 1311. void 1312. flush_screen(cursor_on_u) 1313. int cursor_on_u; 1314. { 1315. /* Prevent infinite loops on errors: 1316. * flush_screen->print_glyph->impossible->pline->flush_screen 1317. */ 1318. static boolean flushing = 0; 1319. register int x,y; 1320. 1321. if (flushing) return; /* if already flushing then return */ 1322. flushing = 1; 1323. 1324. for (y = 0; y < ROWNO; y++) { 1325. register gbuf_entry *gptr = &gbuf[y][x = gbuf_start[y]]; 1326. for (; x <= gbuf_stop[y]; gptr++, x++) 1327. if (gptr->new) { 1328. print_glyph(WIN_MAP,x,y,gptr->glyph); 1329. gptr->new = 0; 1330. } 1331. } 1332. 1333. if (cursor_on_u) curs(WIN_MAP, u.ux,u.uy); /* move cursor to the hero */ 1334. display_nhwindow(WIN_MAP, FALSE); 1335. reset_glyph_bbox(); 1336. flushing = 0; 1337. if(flags.botl || flags.botlx) bot(); 1338. } 1339. 1340. /* ========================================================================= */ 1341. 1342. /* 1343. * back_to_glyph() 1344. * 1345. * Use the information in the rm structure at the given position to create 1346. * a glyph of a background. 1347. * 1348. * I had to add a field in the rm structure (horizontal) so that we knew 1349. * if open doors and secret doors were horizontal or vertical. Previously, 1350. * the screen symbol had the horizontal/vertical information set at 1351. * level generation time. 1352. * 1353. * I used the 'ladder' field (really doormask) for deciding if stairwells 1354. * were up or down. I didn't want to check the upstairs and dnstairs 1355. * variables. 1356. */ 1357. int 1358. back_to_glyph(x,y) 1359. xchar x,y; 1360. { 1361. int idx; 1362. struct rm *ptr = &(levl[x][y]); 1363. 1364. switch (ptr->typ) { 1365. case SCORR: 1366. case STONE: 1367. idx = level.flags.arboreal ? S_tree : S_stone; 1368. break; 1369. case ROOM: idx = S_room; break; 1370. case CORR: 1371. idx = (ptr->waslit || flags.lit_corridor) ? S_litcorr : S_corr; 1372. break; 1373. case HWALL: 1374. case VWALL: 1375. case TLCORNER: 1376. case TRCORNER: 1377. case BLCORNER: 1378. case BRCORNER: 1379. case CROSSWALL: 1380. case TUWALL: 1381. case TDWALL: 1382. case TLWALL: 1383. case TRWALL: 1384. case SDOOR: 1385. idx = ptr->seenv ? wall_angle(ptr) : S_stone; 1386. break; 1387. case DOOR: 1388. if (ptr->doormask) { 1389. if (ptr->doormask & D_BROKEN) 1390. idx = S_ndoor; 1391. else if (ptr->doormask & D_ISOPEN) 1392. idx = (ptr->horizontal) ? S_hodoor : S_vodoor; 1393. else /* else is closed */ 1394. idx = (ptr->horizontal) ? S_hcdoor : S_vcdoor; 1395. } else 1396. idx = S_ndoor; 1397. break; 1398. case IRONBARS: idx = S_bars; break; 1399. case TREE: idx = S_tree; break; 1400. case POOL: 1401. case MOAT: idx = S_pool; break; 1402. case STAIRS: 1403. idx = (ptr->ladder & LA_DOWN) ? S_dnstair : S_upstair; 1404. break; 1405. case LADDER: 1406. idx = (ptr->ladder & LA_DOWN) ? S_dnladder : S_upladder; 1407. break; 1408. case FOUNTAIN: idx = S_fountain; break; 1409. case SINK: idx = S_sink; break; 1410. case ALTAR: idx = S_altar; break; 1411. case GRAVE: idx = S_grave; break; 1412. case THRONE: idx = S_throne; break; 1413. case LAVAPOOL: idx = S_lava; break; 1414. case ICE: idx = S_ice; break; 1415. case AIR: idx = S_air; break; 1416. case CLOUD: idx = S_cloud; break; 1417. case WATER: idx = S_water; break; 1418. case DBWALL: 1419. idx = (ptr->horizontal) ? S_hcdbridge : S_vcdbridge; 1420. break; 1421. case DRAWBRIDGE_UP: 1422. switch(ptr->drawbridgemask & DB_UNDER) { 1423. case DB_MOAT: idx = S_pool; break; 1424. case DB_LAVA: idx = S_lava; break; 1425. case DB_ICE: idx = S_ice; break; 1426. case DB_FLOOR: idx = S_room; break; 1427. default: 1428. impossible("Strange db-under: %d", 1429. ptr->drawbridgemask & DB_UNDER); 1430. idx = S_room; /* something is better than nothing */ 1431. break; 1432. } 1433. break; 1434. case DRAWBRIDGE_DOWN: 1435. idx = (ptr->horizontal) ? S_hodbridge : S_vodbridge; 1436. break; 1437. default: 1438. impossible("back_to_glyph: unknown level type [ = %d ]",ptr->typ); 1439. idx = S_room; 1440. break; 1441. } 1442. 1443. return cmap_to_glyph(idx); 1444. } 1445. 1446. 1447. /* 1448. * swallow_to_glyph() 1449. * 1450. * Convert a monster number and a swallow location into the correct glyph. 1451. * If you don't want a patchwork monster while hallucinating, decide on 1452. * a random monster in swallowed() and don't use what_mon() here. 1453. */ 1454. STATIC_OVL int 1455. swallow_to_glyph(mnum, loc) 1456. int mnum; 1457. int loc; 1458. { 1459. if (loc < S_sw_tl || S_sw_br < loc) { 1460. impossible("swallow_to_glyph: bad swallow location"); 1461. loc = S_sw_br; 1462. } 1463. return ((int) (what_mon(mnum)<<3) | (loc - S_sw_tl)) + GLYPH_SWALLOW_OFF; 1464. } 1465. 1466. 1467. 1468. /* 1469. * zapdir_to_glyph() 1470. * 1471. * Change the given zap direction and beam type into a glyph. Each beam 1472. * type has four glyphs, one for each of the symbols below. The order of 1473. * the zap symbols [0-3] as defined in rm.h are: 1474. * 1475. * | S_vbeam ( 0, 1) or ( 0,-1) 1476. * - S_hbeam ( 1, 0) or (-1, 0) 1477. * \ S_lslant ( 1, 1) or (-1,-1) 1478. * / S_rslant (-1, 1) or ( 1,-1) 1479. */ 1480. int 1481. zapdir_to_glyph(dx, dy, beam_type) 1482. register int dx, dy; 1483. int beam_type; 1484. { 1485. if (beam_type >= NUM_ZAP) { 1486. impossible("zapdir_to_glyph: illegal beam type"); 1487. beam_type = 0; 1488. } 1489. dx = (dx == dy) ? 2 : (dx && dy) ? 3 : dx ? 1 : 0; 1490. 1491. return ((int) ((beam_type << 2) | dx)) + GLYPH_ZAP_OFF; 1492. } 1493. 1494. 1495. /* 1496. * Utility routine for dowhatis() used to find out the glyph displayed at 1497. * the location. This isn't necessarily the same as the glyph in the levl 1498. * structure, so we must check the "third screen". 1499. */ 1500. int 1501. glyph_at(x, y) 1502. xchar x,y; 1503. { 1504. if(x < 0 || y < 0 || x >= COLNO || y >= ROWNO) 1505. return cmap_to_glyph(S_room); /* XXX */ 1506. return gbuf[y][x].glyph; 1507. } 1508. 1509. 1510. /* ------------------------------------------------------------------------- */ 1511. /* Wall Angle -------------------------------------------------------------- */ 1512. 1513. /*#define WA_VERBOSE*/ /* give (x,y) locations for all "bad" spots */ 1514. 1515. #ifdef WA_VERBOSE 1516. 1517. static const char *FDECL(type_to_name, (int)); 1518. static void FDECL(error4, (int,int,int,int,int,int)); 1519. 1520. static int bad_count[MAX_TYPE]; /* count of positions flagged as bad */ 1521. static const char *type_names[MAX_TYPE] = { 1522. "STONE", "VWALL", "HWALL", "TLCORNER", 1523. "TRCORNER", "BLCORNER", "BRCORNER", "CROSSWALL", 1524. "TUWALL", "TDWALL", "TLWALL", "TRWALL", 1525. "DBWALL", "SDOOR", "SCORR", "POOL", 1526. "MOAT", "WATER", "DRAWBRIDGE_UP","LAVAPOOL", 1527. "DOOR", "CORR", "ROOM", "STAIRS", 1528. "LADDER", "FOUNTAIN", "THRONE", "SINK", 1529. "ALTAR", "ICE", "DRAWBRIDGE_DOWN","AIR", 1530. "CLOUD" 1531. }; 1532. 1533. 1534. static const char * 1535. type_to_name(type) 1536. int type; 1537. { 1538. return (type < 0 || type > MAX_TYPE) ? "unknown" : type_names[type]; 1539. } 1540. 1541. static void 1542. error4(x, y, a, b, c, dd) 1543. int x, y, a, b, c, dd; 1544. { 1545. pline("set_wall_state: %s @ (%d,%d) %s%s%s%s", 1546. type_to_name(levl[x][y].typ), x, y, 1547. a ? "1":"", b ? "2":"", c ? "3":"", dd ? "4":""); 1548. bad_count[levl[x][y].typ]++; 1549. } 1550. #endif /* WA_VERBOSE */ 1551. 1552. /* 1553. * Return 'which' if position is implies an unfinshed exterior. Return 1554. * zero otherwise. Unfinished implies outer area is rock or a corridor. 1555. * 1556. * Things that are ambigious: lava 1557. */ 1558. STATIC_OVL int 1559. check_pos(x, y, which) 1560. int x, y, which; 1561. { 1562. int type; 1563. if (!isok(x,y)) return which; 1564. type = levl[x][y].typ; 1565. if (IS_ROCK(type) || type == CORR || type == SCORR) return which; 1566. return 0; 1567. } 1568. 1569. /* Return TRUE if more than one is non-zero. */ 1570. /*ARGSUSED*/ 1571. #ifdef WA_VERBOSE 1572. STATIC_OVL boolean 1573. more_than_one(x, y, a, b, c) 1574. int x, y, a, b, c; 1575. { 1576. if ((a && (b|c)) || (b && (a|c)) || (c && (a|b))) { 1577. error4(x,y,a,b,c,0); 1578. return TRUE; 1579. } 1580. return FALSE; 1581. } 1582. #else 1583. #define more_than_one(x, y, a, b, c) (((a) && ((b)|(c))) || ((b) && ((a)|(c))) || ((c) && ((a)|(b)))) 1584. #endif 1585. 1586. /* Return the wall mode for a T wall. */ 1587. STATIC_OVL int 1588. set_twall(x0,y0, x1,y1, x2,y2, x3,y3) 1589. int x0,y0, x1,y1, x2,y2, x3,y3; 1590. { 1591. int wmode, is_1, is_2, is_3; 1592. 1593. is_1 = check_pos(x1, y1, WM_T_LONG); 1594. is_2 = check_pos(x2, y2, WM_T_BL); 1595. is_3 = check_pos(x3, y3, WM_T_BR); 1596. if (more_than_one(x0, y0, is_1, is_2, is_3)) { 1597. wmode = 0; 1598. } else { 1599. wmode = is_1 + is_2 + is_3; 1600. } 1601. return wmode; 1602. } 1603. 1604. /* Return wall mode for a horizontal or vertical wall. */ 1605. STATIC_OVL int 1606. set_wall(x, y, horiz) 1607. int x, y, horiz; 1608. { 1609. int wmode, is_1, is_2; 1610. 1611. if (horiz) { 1612. is_1 = check_pos(x,y-1, WM_W_TOP); 1613. is_2 = check_pos(x,y+1, WM_W_BOTTOM); 1614. } else { 1615. is_1 = check_pos(x-1,y, WM_W_LEFT); 1616. is_2 = check_pos(x+1,y, WM_W_RIGHT); 1617. } 1618. if (more_than_one(x, y, is_1, is_2, 0)) { 1619. wmode = 0; 1620. } else { 1621. wmode = is_1 + is_2; 1622. } 1623. return wmode; 1624. } 1625. 1626. 1627. /* Return a wall mode for a corner wall. (x4,y4) is the "inner" position. */ 1628. STATIC_OVL int 1629. set_corn(x1,y1, x2,y2, x3,y3, x4,y4) 1630. int x1, y1, x2, y2, x3, y3, x4, y4; 1631. { 1632. int wmode, is_1, is_2, is_3, is_4; 1633. 1634. is_1 = check_pos(x1, y1, 1); 1635. is_2 = check_pos(x2, y2, 1); 1636. is_3 = check_pos(x3, y3, 1); 1637. is_4 = check_pos(x4, y4, 1); /* inner location */ 1638. 1639. /* 1640. * All 4 should not be true. So if the inner location is rock, 1641. * use it. If all of the outer 3 are true, use outer. We currently 1642. * can't cover the case where only part of the outer is rock, so 1643. * we just say that all the walls are finished (if not overridden 1644. * by the inner section). 1645. */ 1646. if (is_4) { 1647. wmode = WM_C_INNER; 1648. } else if (is_1 && is_2 && is_3) 1649. wmode = WM_C_OUTER; 1650. else 1651. wmode = 0; /* finished walls on all sides */ 1652. 1653. return wmode; 1654. } 1655. 1656. /* Return mode for a crosswall. */ 1657. STATIC_OVL int 1658. set_crosswall(x, y) 1659. int x, y; 1660. { 1661. int wmode, is_1, is_2, is_3, is_4; 1662. 1663. is_1 = check_pos(x-1, y-1, 1); 1664. is_2 = check_pos(x+1, y-1, 1); 1665. is_3 = check_pos(x+1, y+1, 1); 1666. is_4 = check_pos(x-1, y+1, 1); 1667. 1668. wmode = is_1+is_2+is_3+is_4; 1669. if (wmode > 1) { 1670. if (is_1 && is_3 && (is_2+is_4 == 0)) { 1671. wmode = WM_X_TLBR; 1672. } else if (is_2 && is_4 && (is_1+is_3 == 0)) { 1673. wmode = WM_X_BLTR; 1674. } else { 1675. #ifdef WA_VERBOSE 1676. error4(x,y,is_1,is_2,is_3,is_4); 1677. #endif 1678. wmode = 0; 1679. } 1680. } else if (is_1) 1681. wmode = WM_X_TL; 1682. else if (is_2) 1683. wmode = WM_X_TR; 1684. else if (is_3) 1685. wmode = WM_X_BR; 1686. else if (is_4) 1687. wmode = WM_X_BL; 1688. 1689. return wmode; 1690. } 1691. 1692. /* Called from mklev. Scan the level and set the wall modes. */ 1693. void 1694. set_wall_state() 1695. { 1696. int x, y; 1697. int wmode; 1698. struct rm *lev; 1699. 1700. #ifdef WA_VERBOSE 1701. for (x = 0; x < MAX_TYPE; x++) bad_count[x] = 0; 1702. #endif 1703. 1704. for (x = 0; x < COLNO; x++) 1705. for (lev = &levl[x][0], y = 0; y < ROWNO; y++, lev++) { 1706. switch (lev->typ) { 1707. case SDOOR: 1708. wmode = set_wall(x, y, (int) lev->horizontal); 1709. break; 1710. case VWALL: 1711. wmode = set_wall(x, y, 0); 1712. break; 1713. case HWALL: 1714. wmode = set_wall(x, y, 1); 1715. break; 1716. case TDWALL: 1717. wmode = set_twall(x,y, x,y-1, x-1,y+1, x+1,y+1); 1718. break; 1719. case TUWALL: 1720. wmode = set_twall(x,y, x,y+1, x+1,y-1, x-1,y-1); 1721. break; 1722. case TLWALL: 1723. wmode = set_twall(x,y, x+1,y, x-1,y-1, x-1,y+1); 1724. break; 1725. case TRWALL: 1726. wmode = set_twall(x,y, x-1,y, x+1,y+1, x+1,y-1); 1727. break; 1728. case TLCORNER: 1729. wmode = set_corn(x-1,y-1, x,y-1, x-1,y, x+1,y+1); 1730. break; 1731. case TRCORNER: 1732. wmode = set_corn(x,y-1, x+1,y-1, x+1,y, x-1,y+1); 1733. break; 1734. case BLCORNER: 1735. wmode = set_corn(x,y+1, x-1,y+1, x-1,y, x+1,y-1); 1736. break; 1737. case BRCORNER: 1738. wmode = set_corn(x+1,y, x+1,y+1, x,y+1, x-1,y-1); 1739. break; 1740. case CROSSWALL: 1741. wmode = set_crosswall(x, y); 1742. break; 1743. 1744. default: 1745. wmode = -1; /* don't set wall info */ 1746. break; 1747. } 1748. 1749. if (wmode >= 0) 1750. lev->wall_info = (lev->wall_info & ~WM_MASK) | wmode; 1751. } 1752. 1753. #ifdef WA_VERBOSE 1754. /* check if any bad positions found */ 1755. for (x = y = 0; x < MAX_TYPE; x++) 1756. if (bad_count[x]) { 1757. if (y == 0) { 1758. y = 1; /* only print once */ 1759. pline("set_wall_type: wall mode problems with: "); 1760. } 1761. pline("%s %d;", type_names[x], bad_count[x]); 1762. } 1763. #endif /* WA_VERBOSE */ 1764. } 1765. 1766. /* ------------------------------------------------------------------------- */ 1767. /* This matrix is used here and in vision.c. */ 1768. unsigned char seenv_matrix[3][3] = { {SV2, SV1, SV0}, 1769. {SV3, SVALL, SV7}, 1770. {SV4, SV5, SV6} }; 1771. 1772. #define sign(z) ((z) < 0 ? -1 : ((z) > 0 ? 1 : 0)) 1773. 1774. /* Set the seen vector of lev as if seen from (x0,y0) to (x,y). */ 1775. STATIC_OVL void 1776. set_seenv(lev, x0, y0, x, y) 1777. struct rm *lev; 1778. int x0, y0, x, y; /* from, to */ 1779. { 1780. int dx = x-x0, dy = y0-y; 1781. lev->seenv |= seenv_matrix[sign(dy)+1][sign(dx)+1]; 1782. } 1783. 1784. /* ------------------------------------------------------------------------- */ 1785. 1786. /* T wall types, one for each row in wall_matrix[][]. */ 1787. #define T_d 0 1788. #define T_l 1 1789. #define T_u 2 1790. #define T_r 3 1791. 1792. /* 1793. * These are the column names of wall_matrix[][]. They are the "results" 1794. * of a tdwall pattern match. All T walls are rotated so they become 1795. * a tdwall. Then we do a single pattern match, but return the 1796. * correct result for the original wall by using different rows for 1797. * each of the wall types. 1798. */ 1799. #define T_stone 0 1800. #define T_tlcorn 1 1801. #define T_trcorn 2 1802. #define T_hwall 3 1803. #define T_tdwall 4 1804. 1805. static const int wall_matrix[4][5] = { 1806. { S_stone, S_tlcorn, S_trcorn, S_hwall, S_tdwall }, /* tdwall */ 1807. { S_stone, S_trcorn, S_brcorn, S_vwall, S_tlwall }, /* tlwall */ 1808. { S_stone, S_brcorn, S_blcorn, S_hwall, S_tuwall }, /* tuwall */ 1809. { S_stone, S_blcorn, S_tlcorn, S_vwall, S_trwall }, /* trwall */ 1810. }; 1811. 1812. 1813. /* Cross wall types, one for each "solid" quarter. Rows of cross_matrix[][]. */ 1814. #define C_bl 0 1815. #define C_tl 1 1816. #define C_tr 2 1817. #define C_br 3 1818. 1819. /* 1820. * These are the column names for cross_matrix[][]. They express results 1821. * in C_br (bottom right) terms. All crosswalls with a single solid 1822. * quarter are rotated so the solid section is at the bottom right. 1823. * We pattern match on that, but return the correct result depending 1824. * on which row we'ere looking at. 1825. */ 1826. #define C_trcorn 0 1827. #define C_brcorn 1 1828. #define C_blcorn 2 1829. #define C_tlwall 3 1830. #define C_tuwall 4 1831. #define C_crwall 5 1832. 1833. static const int cross_matrix[4][6] = { 1834. { S_brcorn, S_blcorn, S_tlcorn, S_tuwall, S_trwall, S_crwall }, 1835. { S_blcorn, S_tlcorn, S_trcorn, S_trwall, S_tdwall, S_crwall }, 1836. { S_tlcorn, S_trcorn, S_brcorn, S_tdwall, S_tlwall, S_crwall }, 1837. { S_trcorn, S_brcorn, S_blcorn, S_tlwall, S_tuwall, S_crwall }, 1838. }; 1839. 1840. 1841. /* Print out a T wall warning and all interesting info. */ 1842. STATIC_OVL void 1843. t_warn(lev) 1844. struct rm *lev; 1845. { 1846. static const char *warn_str = "wall_angle: %s: case %d: seenv = 0x%x"; 1847. const char *wname; 1848. 1849. if (lev->typ == TUWALL) wname = "tuwall"; 1850. else if (lev->typ == TLWALL) wname = "tlwall"; 1851. else if (lev->typ == TRWALL) wname = "trwall"; 1852. else if (lev->typ == TDWALL) wname = "tdwall"; 1853. else wname = "unknown"; 1854. impossible(warn_str, wname, lev->wall_info & WM_MASK, 1855. (unsigned int) lev->seenv); 1856. } 1857. 1858. 1859. /* 1860. * Return the correct graphics character index using wall type, wall mode, 1861. * and the seen vector. It is expected that seenv is non zero. 1862. * 1863. * All T-wall vectors are rotated to be TDWALL. All single crosswall 1864. * blocks are rotated to bottom right. All double crosswall are rotated 1865. * to W_X_BLTR. All results are converted back. 1866. * 1867. * The only way to understand this is to take out pen and paper and 1868. * draw diagrams. See rm.h for more details on the wall modes and 1869. * seen vector (SV). 1870. */ 1871. STATIC_OVL int 1872. wall_angle(lev) 1873. struct rm *lev; 1874. { 1875. register unsigned int seenv = lev->seenv & 0xff; 1876. const int *row; 1877. int col, idx; 1878. 1879. #define only(sv, bits) (((sv) & (bits)) && ! ((sv) & ~(bits))) 1880. switch (lev->typ) { 1881. case TUWALL: 1882. row = wall_matrix[T_u]; 1883. seenv = (seenv >> 4 | seenv << 4) & 0xff;/* rotate to tdwall */ 1884. goto do_twall; 1885. case TLWALL: 1886. row = wall_matrix[T_l]; 1887. seenv = (seenv >> 2 | seenv << 6) & 0xff;/* rotate to tdwall */ 1888. goto do_twall; 1889. case TRWALL: 1890. row = wall_matrix[T_r]; 1891. seenv = (seenv >> 6 | seenv << 2) & 0xff;/* rotate to tdwall */ 1892. goto do_twall; 1893. case TDWALL: 1894. row = wall_matrix[T_d]; 1895. do_twall: 1896. switch (lev->wall_info & WM_MASK) { 1897. case 0: 1898. if (seenv == SV4) { 1899. col = T_tlcorn; 1900. } else if (seenv == SV6) { 1901. col = T_trcorn; 1902. } else if (seenv & (SV3|SV5|SV7) || 1903. ((seenv & SV4) && (seenv & SV6))) { 1904. col = T_tdwall; 1905. } else if (seenv & (SV0|SV1|SV2)) { 1906. col = (seenv & (SV4|SV6) ? T_tdwall : T_hwall); 1907. } else { 1908. t_warn(lev); 1909. col = T_stone; 1910. } 1911. break; 1912. case WM_T_LONG: 1913. if (seenv & (SV3|SV4) && !(seenv & (SV5|SV6|SV7))) { 1914. col = T_tlcorn; 1915. } else if (seenv&(SV6|SV7) && !(seenv&(SV3|SV4|SV5))) { 1916. col = T_trcorn; 1917. } else if ((seenv & SV5) || 1918. ((seenv & (SV3|SV4)) && (seenv & (SV6|SV7)))) { 1919. col = T_tdwall; 1920. } else { 1921. /* only SV0|SV1|SV2 */ 1922. if (! only(seenv, SV0|SV1|SV2) ) 1923. t_warn(lev); 1924. col = T_stone; 1925. } 1926. break; 1927. case WM_T_BL: 1928. #if 0 /* older method, fixed */ 1929. if (only(seenv, SV4|SV5)) { 1930. col = T_tlcorn; 1931. } else if ((seenv & (SV0|SV1|SV2)) && 1932. only(seenv, SV0|SV1|SV2|SV6|SV7)) { 1933. col = T_hwall; 1934. } else if (seenv & SV3 || 1935. ((seenv & (SV0|SV1|SV2)) && (seenv & (SV4|SV5)))) { 1936. col = T_tdwall; 1937. } else { 1938. if (seenv != SV6) 1939. t_warn(lev); 1940. col = T_stone; 1941. } 1942. #endif /* 0 */ 1943. if (only(seenv, SV4|SV5)) 1944. col = T_tlcorn; 1945. else if ((seenv & (SV0|SV1|SV2|SV7)) && 1946. !(seenv & (SV3|SV4|SV5))) 1947. col = T_hwall; 1948. else if (only(seenv, SV6)) 1949. col = T_stone; 1950. else 1951. col = T_tdwall; 1952. break; 1953. case WM_T_BR: 1954. #if 0 /* older method, fixed */ 1955. if (only(seenv, SV5|SV6)) { 1956. col = T_trcorn; 1957. } else if ((seenv & (SV0|SV1|SV2)) && 1958. only(seenv, SV0|SV1|SV2|SV3|SV4)) { 1959. col = T_hwall; 1960. } else if (seenv & SV7 || 1961. ((seenv & (SV0|SV1|SV2)) && (seenv & (SV5|SV6)))) { 1962. col = T_tdwall; 1963. } else { 1964. if (seenv != SV4) 1965. t_warn(lev); 1966. col = T_stone; 1967. } 1968. #endif /* 0 */ 1969. if (only(seenv, SV5|SV6)) 1970. col = T_trcorn; 1971. else if ((seenv & (SV0|SV1|SV2|SV3)) && 1972. !(seenv & (SV5|SV6|SV7))) 1973. col = T_hwall; 1974. else if (only(seenv, SV4)) 1975. col = T_stone; 1976. else 1977. col = T_tdwall; 1978. 1979. break; 1980. default: 1981. impossible("wall_angle: unknown T wall mode %d", 1982. lev->wall_info & WM_MASK); 1983. col = T_stone; 1984. break; 1985. } 1986. idx = row[col]; 1987. break; 1988. 1989. case SDOOR: 1990. if (lev->horizontal) goto horiz; 1991. /* fall through */ 1992. case VWALL: 1993. switch (lev->wall_info & WM_MASK) { 1994. case 0: idx = seenv ? S_vwall : S_stone; break; 1995. case 1: idx = seenv & (SV1|SV2|SV3|SV4|SV5) ? S_vwall : 1996. S_stone; 1997. break; 1998. case 2: idx = seenv & (SV0|SV1|SV5|SV6|SV7) ? S_vwall : 1999. S_stone; 2000. break; 2001. default: 2002. impossible("wall_angle: unknown vwall mode %d", 2003. lev->wall_info & WM_MASK); 2004. idx = S_stone; 2005. break; 2006. } 2007. break; 2008. 2009. case HWALL: 2010. horiz: 2011. switch (lev->wall_info & WM_MASK) { 2012. case 0: idx = seenv ? S_hwall : S_stone; break; 2013. case 1: idx = seenv & (SV3|SV4|SV5|SV6|SV7) ? S_hwall : 2014. S_stone; 2015. break; 2016. case 2: idx = seenv & (SV0|SV1|SV2|SV3|SV7) ? S_hwall : 2017. S_stone; 2018. break; 2019. default: 2020. impossible("wall_angle: unknown hwall mode %d", 2021. lev->wall_info & WM_MASK); 2022. idx = S_stone; 2023. break; 2024. } 2025. break; 2026. 2027. #define set_corner(idx, lev, which, outer, inner, name) \ 2028. switch ((lev)->wall_info & WM_MASK) { \ 2029. case 0: idx = which; break; \ 2030. case WM_C_OUTER: idx = seenv & (outer) ? which : S_stone; break; \ 2031. case WM_C_INNER: idx = seenv & ~(inner) ? which : S_stone; break; \ 2032. default: \ 2033. impossible("wall_angle: unknown %s mode %d", name, \ 2034. (lev)->wall_info & WM_MASK); \ 2035. idx = S_stone; \ 2036. break; \ 2037. } 2038. 2039. case TLCORNER: 2040. set_corner(idx, lev, S_tlcorn, (SV3|SV4|SV5), SV4, "tlcorn"); 2041. break; 2042. case TRCORNER: 2043. set_corner(idx, lev, S_trcorn, (SV5|SV6|SV7), SV6, "trcorn"); 2044. break; 2045. case BLCORNER: 2046. set_corner(idx, lev, S_blcorn, (SV1|SV2|SV3), SV2, "blcorn"); 2047. break; 2048. case BRCORNER: 2049. set_corner(idx, lev, S_brcorn, (SV7|SV0|SV1), SV0, "brcorn"); 2050. break; 2051. 2052. 2053. case CROSSWALL: 2054. switch (lev->wall_info & WM_MASK) { 2055. case 0: 2056. if (seenv == SV0) 2057. idx = S_brcorn; 2058. else if (seenv == SV2) 2059. idx = S_blcorn; 2060. else if (seenv == SV4) 2061. idx = S_tlcorn; 2062. else if (seenv == SV6) 2063. idx = S_trcorn; 2064. else if (!(seenv & ~(SV0|SV1|SV2)) && 2065. (seenv & SV1 || seenv == (SV0|SV2))) 2066. idx = S_tuwall; 2067. else if (!(seenv & ~(SV2|SV3|SV4)) && 2068. (seenv & SV3 || seenv == (SV2|SV4))) 2069. idx = S_trwall; 2070. else if (!(seenv & ~(SV4|SV5|SV6)) && 2071. (seenv & SV5 || seenv == (SV4|SV6))) 2072. idx = S_tdwall; 2073. else if (!(seenv & ~(SV0|SV6|SV7)) && 2074. (seenv & SV7 || seenv == (SV0|SV6))) 2075. idx = S_tlwall; 2076. else 2077. idx = S_crwall; 2078. break; 2079. 2080. case WM_X_TL: 2081. row = cross_matrix[C_tl]; 2082. seenv = (seenv >> 4 | seenv << 4) & 0xff; 2083. goto do_crwall; 2084. case WM_X_TR: 2085. row = cross_matrix[C_tr]; 2086. seenv = (seenv >> 6 | seenv << 2) & 0xff; 2087. goto do_crwall; 2088. case WM_X_BL: 2089. row = cross_matrix[C_bl]; 2090. seenv = (seenv >> 2 | seenv << 6) & 0xff; 2091. goto do_crwall; 2092. case WM_X_BR: 2093. row = cross_matrix[C_br]; 2094. do_crwall: 2095. if (seenv == SV4) 2096. idx = S_stone; 2097. else { 2098. seenv = seenv & ~SV4; /* strip SV4 */ 2099. if (seenv == SV0) { 2100. col = C_brcorn; 2101. } else if (seenv & (SV2|SV3)) { 2102. if (seenv & (SV5|SV6|SV7)) 2103. col = C_crwall; 2104. else if (seenv & (SV0|SV1)) 2105. col = C_tuwall; 2106. else 2107. col = C_blcorn; 2108. } else if (seenv & (SV5|SV6)) { 2109. if (seenv & (SV1|SV2|SV3)) 2110. col = C_crwall; 2111. else if (seenv & (SV0|SV7)) 2112. col = C_tlwall; 2113. else 2114. col = C_trcorn; 2115. } else if (seenv & SV1) { 2116. col = seenv & SV7 ? C_crwall : C_tuwall; 2117. } else if (seenv & SV7) { 2118. col = seenv & SV1 ? C_crwall : C_tlwall; 2119. } else { 2120. impossible( 2121. "wall_angle: bottom of crwall check"); 2122. col = C_crwall; 2123. } 2124. 2125. idx = row[col]; 2126. } 2127. break; 2128. 2129. case WM_X_TLBR: 2130. if ( only(seenv, SV1|SV2|SV3) ) 2131. idx = S_blcorn; 2132. else if ( only(seenv, SV5|SV6|SV7) ) 2133. idx = S_trcorn; 2134. else if ( only(seenv, SV0|SV4) ) 2135. idx = S_stone; 2136. else 2137. idx = S_crwall; 2138. break; 2139. 2140. case WM_X_BLTR: 2141. if ( only(seenv, SV0|SV1|SV7) ) 2142. idx = S_brcorn; 2143. else if ( only(seenv, SV3|SV4|SV5) ) 2144. idx = S_tlcorn; 2145. else if ( only(seenv, SV2|SV6) ) 2146. idx = S_stone; 2147. else 2148. idx = S_crwall; 2149. break; 2150. 2151. default: 2152. impossible("wall_angle: unknown crosswall mode"); 2153. idx = S_stone; 2154. break; 2155. } 2156. break; 2157. 2158. default: 2159. impossible("wall_angle: unexpected wall type %d", lev->typ); 2160. idx = S_stone; 2161. } 2162. return idx; 2163. } 2164. 2165. /*display.c*/