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