PageRenderTime 79ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/src/cave.c

https://bitbucket.org/ekolis/jackband
C | 3993 lines | 1654 code | 736 blank | 1603 comment | 438 complexity | 427748e19cbc3ca6ac9a5ad570f643b5 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * File: cave.c
  3. * Purpose: Lighting and update functions
  4. *
  5. * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
  6. *
  7. * This work is free software; you can redistribute it and/or modify it
  8. * under the terms of either:
  9. *
  10. * a) the GNU General Public License as published by the Free Software
  11. * Foundation, version 2, or
  12. *
  13. * b) the "Angband licence":
  14. * This software may be copied and distributed for educational, research,
  15. * and not for profit purposes provided that this copyright and statement
  16. * are included in all such copies. Other copyrights may also apply.
  17. */
  18. #include "angband.h"
  19. #include "object/tvalsval.h"
  20. #include "game-event.h"
  21. #include "game-cmd.h"
  22. /*
  23. * Support for Adam Bolt's tileset, lighting and transparency effects
  24. * by Robert Ruehlmann (rr9@thangorodrim.net)
  25. */
  26. /*
  27. * Approximate distance between two points.
  28. *
  29. * When either the X or Y component dwarfs the other component,
  30. * this function is almost perfect, and otherwise, it tends to
  31. * over-estimate about one grid per fifteen grids of distance.
  32. *
  33. * Algorithm: hypot(dy,dx) = max(dy,dx) + min(dy,dx) / 2
  34. */
  35. int distance(int y1, int x1, int y2, int x2)
  36. {
  37. /* Find the absolute y/x distance components */
  38. int ay = abs(y2 - y1);
  39. int ax = abs(x2 - x1);
  40. /* Approximate the distance */
  41. return ay > ax ? ay + (ax>>1) : ax + (ay>>1);
  42. }
  43. /*
  44. * A simple, fast, integer-based line-of-sight algorithm. By Joseph Hall,
  45. * 4116 Brewster Drive, Raleigh NC 27606. Email to jnh@ecemwl.ncsu.edu.
  46. *
  47. * This function returns TRUE if a "line of sight" can be traced from the
  48. * center of the grid (x1,y1) to the center of the grid (x2,y2), with all
  49. * of the grids along this path (except for the endpoints) being non-wall
  50. * grids. Actually, the "chess knight move" situation is handled by some
  51. * special case code which allows the grid diagonally next to the player
  52. * to be obstructed, because this yields better gameplay semantics. This
  53. * algorithm is totally reflexive, except for "knight move" situations.
  54. *
  55. * Because this function uses (short) ints for all calculations, overflow
  56. * may occur if dx and dy exceed 90.
  57. *
  58. * Once all the degenerate cases are eliminated, we determine the "slope"
  59. * ("m"), and we use special "fixed point" mathematics in which we use a
  60. * special "fractional component" for one of the two location components
  61. * ("qy" or "qx"), which, along with the slope itself, are "scaled" by a
  62. * scale factor equal to "abs(dy*dx*2)" to keep the math simple. Then we
  63. * simply travel from start to finish along the longer axis, starting at
  64. * the border between the first and second tiles (where the y offset is
  65. * thus half the slope), using slope and the fractional component to see
  66. * when motion along the shorter axis is necessary. Since we assume that
  67. * vision is not blocked by "brushing" the corner of any grid, we must do
  68. * some special checks to avoid testing grids which are "brushed" but not
  69. * actually "entered".
  70. *
  71. * Angband three different "line of sight" type concepts, including this
  72. * function (which is used almost nowhere), the "project()" method (which
  73. * is used for determining the paths of projectables and spells and such),
  74. * and the "update_view()" concept (which is used to determine which grids
  75. * are "viewable" by the player, which is used for many things, such as
  76. * determining which grids are illuminated by the player's torch, and which
  77. * grids and monsters can be "seen" by the player, etc).
  78. */
  79. bool los(int y1, int x1, int y2, int x2)
  80. {
  81. /* Delta */
  82. int dx, dy;
  83. /* Absolute */
  84. int ax, ay;
  85. /* Signs */
  86. int sx, sy;
  87. /* Fractions */
  88. int qx, qy;
  89. /* Scanners */
  90. int tx, ty;
  91. /* Scale factors */
  92. int f1, f2;
  93. /* Slope, or 1/Slope, of LOS */
  94. int m;
  95. /* Extract the offset */
  96. dy = y2 - y1;
  97. dx = x2 - x1;
  98. /* Extract the absolute offset */
  99. ay = ABS(dy);
  100. ax = ABS(dx);
  101. /* Handle adjacent (or identical) grids */
  102. if ((ax < 2) && (ay < 2)) return (TRUE);
  103. /* Directly South/North */
  104. if (!dx)
  105. {
  106. /* South -- check for walls */
  107. if (dy > 0)
  108. {
  109. for (ty = y1 + 1; ty < y2; ty++)
  110. {
  111. if (!cave_floor_bold(ty, x1)) return (FALSE);
  112. }
  113. }
  114. /* North -- check for walls */
  115. else
  116. {
  117. for (ty = y1 - 1; ty > y2; ty--)
  118. {
  119. if (!cave_floor_bold(ty, x1)) return (FALSE);
  120. }
  121. }
  122. /* Assume los */
  123. return (TRUE);
  124. }
  125. /* Directly East/West */
  126. if (!dy)
  127. {
  128. /* East -- check for walls */
  129. if (dx > 0)
  130. {
  131. for (tx = x1 + 1; tx < x2; tx++)
  132. {
  133. if (!cave_floor_bold(y1, tx)) return (FALSE);
  134. }
  135. }
  136. /* West -- check for walls */
  137. else
  138. {
  139. for (tx = x1 - 1; tx > x2; tx--)
  140. {
  141. if (!cave_floor_bold(y1, tx)) return (FALSE);
  142. }
  143. }
  144. /* Assume los */
  145. return (TRUE);
  146. }
  147. /* Extract some signs */
  148. sx = (dx < 0) ? -1 : 1;
  149. sy = (dy < 0) ? -1 : 1;
  150. /* Vertical "knights" */
  151. if (ax == 1)
  152. {
  153. if (ay == 2)
  154. {
  155. if (cave_floor_bold(y1 + sy, x1)) return (TRUE);
  156. }
  157. }
  158. /* Horizontal "knights" */
  159. else if (ay == 1)
  160. {
  161. if (ax == 2)
  162. {
  163. if (cave_floor_bold(y1, x1 + sx)) return (TRUE);
  164. }
  165. }
  166. /* Calculate scale factor div 2 */
  167. f2 = (ax * ay);
  168. /* Calculate scale factor */
  169. f1 = f2 << 1;
  170. /* Travel horizontally */
  171. if (ax >= ay)
  172. {
  173. /* Let m = dy / dx * 2 * (dy * dx) = 2 * dy * dy */
  174. qy = ay * ay;
  175. m = qy << 1;
  176. tx = x1 + sx;
  177. /* Consider the special case where slope == 1. */
  178. if (qy == f2)
  179. {
  180. ty = y1 + sy;
  181. qy -= f1;
  182. }
  183. else
  184. {
  185. ty = y1;
  186. }
  187. /* Note (below) the case (qy == f2), where */
  188. /* the LOS exactly meets the corner of a tile. */
  189. while (x2 - tx)
  190. {
  191. if (!cave_floor_bold(ty, tx)) return (FALSE);
  192. qy += m;
  193. if (qy < f2)
  194. {
  195. tx += sx;
  196. }
  197. else if (qy > f2)
  198. {
  199. ty += sy;
  200. if (!cave_floor_bold(ty, tx)) return (FALSE);
  201. qy -= f1;
  202. tx += sx;
  203. }
  204. else
  205. {
  206. ty += sy;
  207. qy -= f1;
  208. tx += sx;
  209. }
  210. }
  211. }
  212. /* Travel vertically */
  213. else
  214. {
  215. /* Let m = dx / dy * 2 * (dx * dy) = 2 * dx * dx */
  216. qx = ax * ax;
  217. m = qx << 1;
  218. ty = y1 + sy;
  219. if (qx == f2)
  220. {
  221. tx = x1 + sx;
  222. qx -= f1;
  223. }
  224. else
  225. {
  226. tx = x1;
  227. }
  228. /* Note (below) the case (qx == f2), where */
  229. /* the LOS exactly meets the corner of a tile. */
  230. while (y2 - ty)
  231. {
  232. if (!cave_floor_bold(ty, tx)) return (FALSE);
  233. qx += m;
  234. if (qx < f2)
  235. {
  236. ty += sy;
  237. }
  238. else if (qx > f2)
  239. {
  240. tx += sx;
  241. if (!cave_floor_bold(ty, tx)) return (FALSE);
  242. qx -= f1;
  243. ty += sy;
  244. }
  245. else
  246. {
  247. tx += sx;
  248. qx -= f1;
  249. ty += sy;
  250. }
  251. }
  252. }
  253. /* Assume los */
  254. return (TRUE);
  255. }
  256. /*
  257. * Returns true if the player's grid is dark
  258. */
  259. bool no_light(void)
  260. {
  261. return (!player_can_see_bold(p_ptr->py, p_ptr->px));
  262. }
  263. /*
  264. * Determine if a given location may be "destroyed"
  265. *
  266. * Used by destruction spells, and for placing stairs, etc.
  267. */
  268. bool cave_valid_bold(int y, int x)
  269. {
  270. object_type *o_ptr;
  271. /* Forbid perma-grids */
  272. if (cave_perma_bold(y, x)) return (FALSE);
  273. /* Check objects */
  274. for (o_ptr = get_first_object(y, x); o_ptr; o_ptr = get_next_object(o_ptr))
  275. {
  276. /* Forbid artifact grids */
  277. if (artifact_p(o_ptr)) return (FALSE);
  278. }
  279. /* Accept */
  280. return (TRUE);
  281. }
  282. /*
  283. * Hack -- Hallucinatory monster
  284. */
  285. static u16b hallucinatory_monster(void)
  286. {
  287. monster_race *r_ptr;
  288. byte a;
  289. char c;
  290. while (1)
  291. {
  292. /* Select a random monster */
  293. r_ptr = &r_info[randint0(z_info->r_max)];
  294. /* Skip non-entries */
  295. if (!r_ptr->name) continue;
  296. /* Retrieve attr/char */
  297. a = r_ptr->x_attr;
  298. c = r_ptr->x_char;
  299. /* Encode */
  300. return (PICT(a,c));
  301. }
  302. }
  303. /*
  304. * Hack -- Hallucinatory object
  305. */
  306. static u16b hallucinatory_object(void)
  307. {
  308. object_kind *k_ptr;
  309. byte a;
  310. char c;
  311. while (1)
  312. {
  313. /* Select a random object */
  314. k_ptr = &k_info[randint0(z_info->k_max - 1) + 1];
  315. /* Skip non-entries */
  316. if (!k_ptr->name) continue;
  317. /* Retrieve attr/char (HACK - without flavors) */
  318. a = k_ptr->x_attr;
  319. c = k_ptr->x_char;
  320. /* HACK - Skip empty entries */
  321. if ((a == 0) || (c == 0)) continue;
  322. /* Encode */
  323. return (PICT(a,c));
  324. }
  325. }
  326. /*
  327. * The 16x16 tile of the terrain supports lighting
  328. */
  329. bool feat_supports_lighting(int feat)
  330. {
  331. /* Pseudo graphics don't support lighting */
  332. if (use_graphics == GRAPHICS_PSEUDO) return FALSE;
  333. if ((use_graphics != GRAPHICS_DAVID_GERVAIS) &&
  334. (feat >= FEAT_TRAP_HEAD) && (feat <= FEAT_TRAP_TAIL))
  335. {
  336. return TRUE;
  337. }
  338. switch (feat)
  339. {
  340. case FEAT_FLOOR:
  341. case FEAT_INVIS:
  342. case FEAT_SECRET:
  343. case FEAT_MAGMA:
  344. case FEAT_QUARTZ:
  345. case FEAT_MAGMA_H:
  346. case FEAT_QUARTZ_H:
  347. case FEAT_WALL_EXTRA:
  348. case FEAT_WALL_INNER:
  349. case FEAT_WALL_OUTER:
  350. case FEAT_WALL_SOLID:
  351. case FEAT_PERM_EXTRA:
  352. case FEAT_PERM_INNER:
  353. case FEAT_PERM_OUTER:
  354. case FEAT_PERM_SOLID:
  355. return TRUE;
  356. default:
  357. return FALSE;
  358. }
  359. }
  360. /*
  361. * Translate text colours.
  362. *
  363. * This translates a color based on the attribute. We use this to set terrain to
  364. * be lighter or darker, make metallic monsters shimmer, highlight text under the
  365. * mouse, and reduce the colours on mono colour or 16 colour terms to the correct
  366. * colour space.
  367. *
  368. * TODO: Honour the attribute for the term (full color, mono, 16 color) but ensure
  369. * that e.g. the lighter version of yellow becomes white in a 16 color term, but
  370. * light yellow in a full colour term.
  371. */
  372. byte get_color(byte a, int attr, int n)
  373. {
  374. /* Accept any graphical attr (high bit set) */
  375. if (a & (0x80)) return (a);
  376. /* TODO: Honour the attribute for the term (full color, mono, 16 color) */
  377. if (!attr) return(a);
  378. /* Translate the color N times */
  379. while (n > 0)
  380. {
  381. a = color_table[a].color_translate[attr];
  382. n--;
  383. }
  384. /* Return the modified color */
  385. return (a);
  386. }
  387. /*
  388. * This function modifies the attr/char pair for an empty floor space
  389. * to reflect the various lighting options available.
  390. *
  391. * For text, this means changing the colouring for OPT(view_yellow_light) or
  392. * OPT(view_bright_light), and for graphics it means modifying the char to
  393. * use a different tile in the tileset. These modifications are different
  394. * for different sets, depending on the tiles available, and their position
  395. * in the set.
  396. */
  397. static void special_lighting_floor(byte *a, char *c, enum grid_light_level lighting, bool in_view)
  398. {
  399. /* The floor starts off "lit" - i.e. rendered in white or the default
  400. * tile. */
  401. if (lighting == LIGHT_TORCH && OPT(view_yellow_light))
  402. {
  403. /*
  404. * OPT(view_yellow_light) distinguishes between torchlit and
  405. * permanently-lit areas
  406. */
  407. switch (use_graphics)
  408. {
  409. case GRAPHICS_NONE:
  410. case GRAPHICS_PSEUDO:
  411. /* Use "yellow" */
  412. if (*a == TERM_WHITE) *a = TERM_YELLOW;
  413. break;
  414. case GRAPHICS_ADAM_BOLT:
  415. *c += 2;
  416. break;
  417. case GRAPHICS_DAVID_GERVAIS:
  418. *c -= 1;
  419. break;
  420. }
  421. }
  422. else if (lighting == LIGHT_DARK)
  423. {
  424. /* Use a dark tile */
  425. switch (use_graphics)
  426. {
  427. case GRAPHICS_NONE:
  428. case GRAPHICS_PSEUDO:
  429. /* Use "dark gray" */
  430. if (*a == TERM_WHITE) *a = TERM_L_DARK;
  431. break;
  432. case GRAPHICS_ADAM_BOLT:
  433. case GRAPHICS_DAVID_GERVAIS:
  434. *c += 1;
  435. break;
  436. }
  437. }
  438. else
  439. {
  440. /*
  441. * OPT(view_bright_light) makes tiles that aren't in the "eyeline"
  442. * of the player show up dimmer than those that are.
  443. */
  444. if (OPT(view_bright_light) && !in_view)
  445. {
  446. switch (use_graphics)
  447. {
  448. case GRAPHICS_NONE:
  449. case GRAPHICS_PSEUDO:
  450. /* Use "gray" */
  451. if (*a == TERM_WHITE) *a = TERM_SLATE;
  452. else if (*a == TERM_L_GREEN) *a = TERM_GREEN;
  453. break;
  454. case GRAPHICS_ADAM_BOLT:
  455. case GRAPHICS_DAVID_GERVAIS:
  456. *c += 1;
  457. break;
  458. }
  459. }
  460. }
  461. }
  462. /*
  463. * This function modifies the attr/char pair for a wall (or other "interesting"
  464. * grids to show them as more-or-less lit. Note that how walls are drawn
  465. * isn't directly related to how they are lit - walls are always "lit".
  466. * The lighting effects we use are as a visual cue to emphasise blindness
  467. * and to show field-of-view (OPT(view_bright_light)).
  468. *
  469. * For text, we change the attr and for graphics we modify the char to
  470. * use a different tile in the tileset. These modifications are different
  471. * for different sets, depending on the tiles available, and their position
  472. * in the set.
  473. */
  474. static void special_wall_display(byte *a, char *c, bool in_view, int feat)
  475. {
  476. /* Grids currently in view are left alone, rendered as "white" */
  477. if (in_view) return;
  478. /* When blind, we make walls and other "white" things dark */
  479. if (p_ptr->timed[TMD_BLIND])
  480. {
  481. switch (use_graphics)
  482. {
  483. case GRAPHICS_NONE:
  484. case GRAPHICS_PSEUDO:
  485. /* Use "dark gray" */
  486. if (*a == TERM_WHITE) *a = TERM_L_DARK;
  487. break;
  488. case GRAPHICS_ADAM_BOLT:
  489. case GRAPHICS_DAVID_GERVAIS:
  490. if (feat_supports_lighting(feat)) *c += 1;
  491. break;
  492. }
  493. }
  494. /* Handle "OPT(view_bright_light)" by dimming walls not "in view" */
  495. else if (OPT(view_bright_light))
  496. {
  497. switch (use_graphics)
  498. {
  499. case GRAPHICS_NONE:
  500. case GRAPHICS_PSEUDO:
  501. /* Use "gray" */
  502. if (*a == TERM_WHITE) *a = TERM_SLATE;
  503. break;
  504. case GRAPHICS_ADAM_BOLT:
  505. case GRAPHICS_DAVID_GERVAIS:
  506. if (feat_supports_lighting(feat)) *c += 1;
  507. break;
  508. }
  509. }
  510. else
  511. {
  512. /* Use a brightly lit tile */
  513. switch (use_graphics)
  514. {
  515. case GRAPHICS_ADAM_BOLT:
  516. if (feat_supports_lighting(feat)) *c += 2;
  517. break;
  518. case GRAPHICS_DAVID_GERVAIS:
  519. if (feat_supports_lighting(feat)) *c -= 1;
  520. break;
  521. }
  522. }
  523. }
  524. /*
  525. * Checks if a square is at the (inner) edge of a trap detect area
  526. */
  527. bool dtrap_edge(int y, int x)
  528. {
  529. /* Check if the square is a dtrap in the first place */
  530. if (!cave_info2[y][x] & CAVE2_DTRAP) return FALSE;
  531. /* Check for non-dtrap adjacent grids */
  532. if (in_bounds_fully(y + 1, x ) && (!cave_info2[y + 1][x ] & CAVE2_DTRAP)) return TRUE;
  533. if (in_bounds_fully(y , x + 1) && (!cave_info2[y ][x + 1] & CAVE2_DTRAP)) return TRUE;
  534. if (in_bounds_fully(y - 1, x ) && (!cave_info2[y - 1][x ] & CAVE2_DTRAP)) return TRUE;
  535. if (in_bounds_fully(y , x - 1) && (!cave_info2[y ][x - 1] & CAVE2_DTRAP)) return TRUE;
  536. return FALSE;
  537. }
  538. /*
  539. * This function takes a pointer to a grid info struct describing the
  540. * contents of a grid location (as obtained through the function map_info)
  541. * and fills in the character and attr pairs for display.
  542. *
  543. * ap and cp are filled with the attr/char pair for the monster, object or
  544. * floor tile that is at the "top" of the grid (monsters covering objects,
  545. * which cover floor, assuming all are present).
  546. *
  547. * tap and tcp are filled with the attr/char pair for the floor, regardless
  548. * of what is on it. This can be used by graphical displays with
  549. * transparency to place an object onto a floor tile, is desired.
  550. *
  551. * Any lighting effects are also applied to these pairs, clear monsters allow
  552. * the underlying colour or feature to show through (ATTR_CLEAR and
  553. * CHAR_CLEAR), multi-hued colour-changing (ATTR_MULTI) is applied, and so on.
  554. * Technically, the flag "CHAR_MULTI" is supposed to indicate that a monster
  555. * looks strange when examined, but this flag is currently ignored.
  556. *
  557. * NOTES:
  558. * This is called pretty frequently, whenever a grid on the map display
  559. * needs updating, so don't overcomplicate it.
  560. *
  561. * The "zero" entry in the feature/object/monster arrays are
  562. * used to provide "special" attr/char codes, with "monster zero" being
  563. * used for the player attr/char, "object zero" being used for the "pile"
  564. * attr/char, and "feature zero" being used for the "darkness" attr/char.
  565. *
  566. * TODO:
  567. * The transformations for tile colors, or brightness for the 16x16
  568. * tiles should be handled differently. One possibility would be to
  569. * extend feature_type with attr/char definitions for the different states.
  570. * This will probably be done outside of the current text->graphics mappings
  571. * though.
  572. */
  573. void grid_data_as_text(grid_data *g, byte *ap, char *cp, byte *tap, char *tcp)
  574. {
  575. byte a;
  576. char c;
  577. feature_type *f_ptr = &f_info[g->f_idx];
  578. /* Normal attr and char */
  579. a = f_ptr->x_attr;
  580. c = f_ptr->x_char;
  581. /* Check for trap detection boundaries */
  582. if (g->trapborder && g->f_idx == FEAT_FLOOR &&
  583. (use_graphics == GRAPHICS_NONE ||
  584. use_graphics == GRAPHICS_PSEUDO))
  585. a = TERM_L_GREEN;
  586. /* Special lighting effects */
  587. if (g->f_idx <= FEAT_INVIS && OPT(view_special_light))
  588. special_lighting_floor(&a, &c, g->lighting, g->in_view);
  589. /* Special lighting effects (walls only) */
  590. if (g->f_idx > FEAT_INVIS && OPT(view_granite_light))
  591. special_wall_display(&a, &c, g->in_view, g->f_idx);
  592. /* Save the terrain info for the transparency effects */
  593. (*tap) = a;
  594. (*tcp) = c;
  595. /* If there's an object, deal with that. */
  596. if (g->first_k_idx)
  597. {
  598. if (g->hallucinate)
  599. {
  600. /* Just pick a random object to display. */
  601. int i = hallucinatory_object();
  602. a = PICT_A(i);
  603. c = PICT_C(i);
  604. }
  605. else
  606. {
  607. object_kind *k_ptr = &k_info[g->first_k_idx];
  608. /* Normal attr and char */
  609. a = object_kind_attr(g->first_k_idx);
  610. c = object_kind_char(g->first_k_idx);
  611. if (OPT(show_piles) && g->multiple_objects)
  612. {
  613. /* Get the "pile" feature instead */
  614. k_ptr = &k_info[0];
  615. a = k_ptr->x_attr;
  616. c = k_ptr->x_char;
  617. }
  618. }
  619. }
  620. /* If there's a monster */
  621. if (g->m_idx > 0)
  622. {
  623. if (g->hallucinate)
  624. {
  625. /* Just pick a random monster to display. */
  626. int i = hallucinatory_monster();
  627. a = PICT_A(i);
  628. c = PICT_C(i);
  629. }
  630. else
  631. {
  632. monster_type *m_ptr = &mon_list[g->m_idx];
  633. monster_race *r_ptr = &r_info[m_ptr->r_idx];
  634. byte da;
  635. char dc;
  636. /* Desired attr & char*/
  637. da = r_ptr->x_attr;
  638. dc = r_ptr->x_char;
  639. /* Special attr/char codes */
  640. if ((da & 0x80) && (dc & 0x80))
  641. {
  642. /* Use attr */
  643. a = da;
  644. /* Use char */
  645. c = dc;
  646. }
  647. /* Multi-hued monster */
  648. else if (rf_has(r_ptr->flags, RF_ATTR_MULTI) ||
  649. rf_has(r_ptr->flags, RF_ATTR_FLICKER))
  650. {
  651. /* Multi-hued attr */
  652. a = m_ptr->attr ? m_ptr->attr : 1;
  653. /* Normal char */
  654. c = dc;
  655. }
  656. /* Normal monster (not "clear" in any way) */
  657. else if (!flags_test(r_ptr->flags, RF_SIZE, RF_ATTR_CLEAR,
  658. RF_CHAR_CLEAR, FLAG_END))
  659. {
  660. /* Use attr */
  661. a = da;
  662. /* Desired attr & char */
  663. da = r_ptr->x_attr;
  664. dc = r_ptr->x_char;
  665. /* Use char */
  666. c = dc;
  667. }
  668. /* Hack -- Bizarre grid under monster */
  669. else if ((a & 0x80) || (c & 0x80))
  670. {
  671. /* Use attr */
  672. a = da;
  673. /* Use char */
  674. c = dc;
  675. }
  676. /* Normal char, Clear attr, monster */
  677. else if (!rf_has(r_ptr->flags, RF_CHAR_CLEAR))
  678. {
  679. /* Normal char */
  680. c = dc;
  681. }
  682. /* Normal attr, Clear char, monster */
  683. else if (!rf_has(r_ptr->flags, RF_ATTR_CLEAR))
  684. {
  685. /* Normal attr */
  686. a = da;
  687. }
  688. /* Store the drawing attr so we can use it other places too */
  689. m_ptr->attr = a;
  690. }
  691. }
  692. /* Handle "player" */
  693. else if (g->is_player)
  694. {
  695. monster_race *r_ptr = &r_info[0];
  696. /* Get the "player" attr */
  697. a = r_ptr->x_attr;
  698. if ((OPT(hp_changes_color)) && (arg_graphics == GRAPHICS_NONE))
  699. {
  700. switch(p_ptr->chp * 10 / p_get_mhp())
  701. {
  702. case 10:
  703. case 9:
  704. {
  705. a = TERM_WHITE;
  706. break;
  707. }
  708. case 8:
  709. case 7:
  710. {
  711. a = TERM_YELLOW;
  712. break;
  713. }
  714. case 6:
  715. case 5:
  716. {
  717. a = TERM_ORANGE;
  718. break;
  719. }
  720. case 4:
  721. case 3:
  722. {
  723. a = TERM_L_RED;
  724. break;
  725. }
  726. case 2:
  727. case 1:
  728. case 0:
  729. {
  730. a = TERM_RED;
  731. break;
  732. }
  733. default:
  734. {
  735. a = TERM_WHITE;
  736. break;
  737. }
  738. }
  739. }
  740. /* Get the "player" char */
  741. c = r_ptr->x_char;
  742. }
  743. /* Result */
  744. (*ap) = a;
  745. (*cp) = c;
  746. }
  747. /*
  748. * This function takes a grid location (x, y) and extracts information the
  749. * player is allowed to know about it, filling in the grid_data structure
  750. * passed in 'g'.
  751. *
  752. * The information filled in is as follows:
  753. * - g->f_idx is filled in with the terrain's feature type, or FEAT_NONE
  754. * if the player doesn't know anything about the grid. The function
  755. * makes use of the "mimic" field in terrain in order to allow one
  756. * feature to look like another (hiding secret doors, invisible traps,
  757. * etc). This will return the terrain type the player "Knows" about,
  758. * not necessarily the real terrain.
  759. * - g->m_idx is set to the monster index, or 0 if there is none (or the
  760. * player doesn't know it).
  761. * - g->first_k_idx is set to the index of the first object in a grid
  762. * that the player knows (and cares, as per OPT(hide_squelchable)) about,
  763. * or zero for no object in the grid.
  764. * - g->muliple_objects is TRUE if there is more than one object in the
  765. * grid that the player knows and cares about (to facilitate any special
  766. * floor stack symbol that might be used).
  767. * - g->in_view is TRUE if the player can currently see the grid - this can
  768. * be used to indicate field-of-view, such as through the OPT(view_bright_light)
  769. * option.
  770. * - g->lighting is set to indicate the lighting level for the grid:
  771. * LIGHT_DARK for unlit grids, LIGHT_TORCH for those lit by the player's
  772. * light source, and LIGHT_GLOW for inherently light grids (lit rooms, etc).
  773. * Note that lighting is always LIGHT_GLOW for known "interesting" grids
  774. * like walls.
  775. * - g->is_player is TRUE if the player is on the given grid.
  776. * - g->hallucinate is TRUE if the player is hallucinating something "strange"
  777. * for this grid - this should pick a random monster to show if the m_idx
  778. * is non-zero, and a random object if first_k_idx is non-zero.
  779. *
  780. * NOTES:
  781. * This is called pretty frequently, whenever a grid on the map display
  782. * needs updating, so don't overcomplicate it.
  783. *
  784. * Terrain is remembered separately from objects and monsters, so can be
  785. * shown even when the player can't "see" it. This leads to things like
  786. * doors out of the player's view still change from closed to open and so on.
  787. *
  788. * TODO:
  789. * Hallucination is currently disabled (it was a display-level hack before,
  790. * and we need it to be a knowledge-level hack). The idea is that objects
  791. * may turn into different objects, monsters into different monsters, and
  792. * terrain may be objects, monsters, or stay the same.
  793. */
  794. void map_info(unsigned y, unsigned x, grid_data *g)
  795. {
  796. object_type *o_ptr;
  797. byte info, info2;
  798. assert(x < DUNGEON_WID);
  799. assert(y < DUNGEON_HGT);
  800. info = cave_info[y][x];
  801. info2 = cave_info2[y][x];
  802. /* Default "clear" values, others will be set later where appropriate. */
  803. g->first_k_idx = 0;
  804. g->multiple_objects = FALSE;
  805. g->lighting = LIGHT_GLOW;
  806. /* Set things we can work out right now */
  807. g->f_idx = cave_feat[y][x];
  808. g->in_view = (info & CAVE_SEEN) ? TRUE : FALSE;
  809. g->is_player = (cave_m_idx[y][x] < 0) ? TRUE : FALSE;
  810. g->m_idx = (g->is_player) ? 0 : cave_m_idx[y][x];
  811. g->hallucinate = p_ptr->timed[TMD_IMAGE] ? TRUE : FALSE;
  812. g->trapborder = (dtrap_edge(y, x)) ? TRUE : FALSE;
  813. /* If the grid is memorised or can currently be seen */
  814. if ((info & CAVE_MARK) || (info & CAVE_SEEN))
  815. {
  816. /* Apply "mimic" field */
  817. g->f_idx = f_info[g->f_idx].mimic;
  818. /* Boring grids (floors, etc) */
  819. if (g->f_idx <= FEAT_INVIS)
  820. {
  821. /* Get the floor feature */
  822. g->f_idx = FEAT_FLOOR;
  823. /* Handle currently visible grids */
  824. if (info & CAVE_SEEN)
  825. {
  826. /* Only lit by "torch" light */
  827. if (info & CAVE_GLOW)
  828. g->lighting = LIGHT_GLOW;
  829. else
  830. g->lighting = LIGHT_TORCH;
  831. }
  832. /* Handle "dark" grids and "blindness" */
  833. else if (p_ptr->timed[TMD_BLIND] || !(info & CAVE_GLOW))
  834. g->lighting = LIGHT_DARK;
  835. }
  836. }
  837. /* Unknown */
  838. else
  839. {
  840. g->f_idx = FEAT_NONE;
  841. }
  842. /* Objects */
  843. for (o_ptr = get_first_object(y, x); o_ptr; o_ptr = get_next_object(o_ptr))
  844. {
  845. /* Memorized objects */
  846. if (o_ptr->marked && !squelch_hide_item(o_ptr))
  847. {
  848. /* First item found */
  849. if (g->first_k_idx == 0)
  850. {
  851. g->first_k_idx = o_ptr->k_idx;
  852. }
  853. else
  854. {
  855. g->multiple_objects = TRUE;
  856. /* And we know all we need to know. */
  857. break;
  858. }
  859. }
  860. }
  861. /* Monsters */
  862. if (g->m_idx > 0)
  863. {
  864. /* If the monster isn't "visible", make sure we don't list it.*/
  865. monster_type *m_ptr = &mon_list[g->m_idx];
  866. if (!m_ptr->ml) g->m_idx = 0;
  867. }
  868. /* Rare random hallucination on non-outer walls */
  869. if (g->hallucinate && g->m_idx == 0 && g->first_k_idx == 0)
  870. {
  871. if (one_in_(256) && (g->f_idx < FEAT_PERM_SOLID))
  872. {
  873. /* Normally, make an imaginary monster */
  874. if (randint0(100) < 75)
  875. {
  876. g->m_idx = 1;
  877. }
  878. /* Otherwise, an imaginary object */
  879. else
  880. {
  881. g->first_k_idx = 1;
  882. }
  883. }
  884. else
  885. {
  886. g->hallucinate = FALSE;
  887. }
  888. }
  889. assert(g->f_idx <= FEAT_PERM_SOLID);
  890. assert(g->m_idx < (u32b) mon_max);
  891. assert(g->first_k_idx < z_info->k_max);
  892. /* All other g fields are 'flags', mostly booleans. */
  893. }
  894. /*
  895. * Move the cursor to a given map location.
  896. */
  897. static void move_cursor_relative_map(int y, int x)
  898. {
  899. int ky, kx;
  900. term *old;
  901. int j;
  902. /* Scan windows */
  903. for (j = 0; j < ANGBAND_TERM_MAX; j++)
  904. {
  905. term *t = angband_term[j];
  906. /* No window */
  907. if (!t) continue;
  908. /* No relevant flags */
  909. if (!(op_ptr->window_flag[j] & (PW_MAP))) continue;
  910. /* Location relative to panel */
  911. ky = y - t->offset_y;
  912. /* Verify location */
  913. if ((ky < 0) || (ky >= t->hgt)) continue;
  914. /* Location relative to panel */
  915. kx = x - t->offset_x;
  916. if (use_bigtile) kx += kx;
  917. /* Verify location */
  918. if ((kx < 0) || (kx >= t->wid)) continue;
  919. /* Go there */
  920. old = Term;
  921. Term_activate(t);
  922. (void)Term_gotoxy(kx, ky);
  923. Term_activate(old);
  924. }
  925. }
  926. /*
  927. * Move the cursor to a given map location.
  928. *
  929. * The main screen will always be at least 24x80 in size.
  930. */
  931. void move_cursor_relative(int y, int x)
  932. {
  933. int ky, kx;
  934. int vy, vx;
  935. /* Move the cursor on map sub-windows */
  936. move_cursor_relative_map(y, x);
  937. /* Location relative to panel */
  938. ky = y - Term->offset_y;
  939. /* Verify location */
  940. if ((ky < 0) || (ky >= SCREEN_HGT)) return;
  941. /* Location relative to panel */
  942. kx = x - Term->offset_x;
  943. /* Verify location */
  944. if ((kx < 0) || (kx >= SCREEN_WID)) return;
  945. /* Location in window */
  946. vy = ky + ROW_MAP;
  947. /* Location in window */
  948. vx = kx + COL_MAP;
  949. if (use_bigtile) vx += kx;
  950. /* Go there */
  951. (void)Term_gotoxy(vx, vy);
  952. }
  953. /*
  954. * Display an attr/char pair at the given map location
  955. *
  956. * Note the inline use of "panel_contains()" for efficiency.
  957. *
  958. * Note the use of "Term_queue_char()" for efficiency.
  959. */
  960. static void print_rel_map(char c, byte a, int y, int x)
  961. {
  962. int ky, kx;
  963. int j;
  964. /* Scan windows */
  965. for (j = 0; j < ANGBAND_TERM_MAX; j++)
  966. {
  967. term *t = angband_term[j];
  968. /* No window */
  969. if (!t) continue;
  970. /* No relevant flags */
  971. if (!(op_ptr->window_flag[j] & (PW_MAP))) continue;
  972. /* Location relative to panel */
  973. ky = y - t->offset_y;
  974. /* Verify location */
  975. if ((ky < 0) || (ky >= t->hgt)) continue;
  976. /* Location relative to panel */
  977. kx = x - t->offset_x;
  978. if (use_bigtile)
  979. {
  980. kx += kx;
  981. if (kx + 1 >= t->wid) continue;
  982. }
  983. /* Verify location */
  984. if ((kx < 0) || (kx >= t->wid)) continue;
  985. /* Hack -- Queue it */
  986. Term_queue_char(t, kx, ky, a, c, 0, 0);
  987. if (use_bigtile)
  988. {
  989. /* Mega-Hack : Queue dummy char */
  990. if (a & 0x80)
  991. Term_queue_char(t, kx+1, ky, 255, -1, 0, 0);
  992. else
  993. Term_queue_char(t, kx+1, ky, TERM_WHITE, ' ', 0, 0);
  994. }
  995. }
  996. }
  997. /*
  998. * Display an attr/char pair at the given map location
  999. *
  1000. * Note the inline use of "panel_contains()" for efficiency.
  1001. *
  1002. * Note the use of "Term_queue_char()" for efficiency.
  1003. *
  1004. * The main screen will always be at least 24x80 in size.
  1005. */
  1006. void print_rel(char c, byte a, int y, int x)
  1007. {
  1008. int ky, kx;
  1009. int vy, vx;
  1010. /* Print on map sub-windows */
  1011. print_rel_map(c, a, y, x);
  1012. /* Location relative to panel */
  1013. ky = y - Term->offset_y;
  1014. /* Verify location */
  1015. if ((ky < 0) || (ky >= SCREEN_HGT)) return;
  1016. /* Location relative to panel */
  1017. kx = x - Term->offset_x;
  1018. /* Verify location */
  1019. if ((kx < 0) || (kx >= SCREEN_WID)) return;
  1020. /* Location in window */
  1021. vy = ky + ROW_MAP;
  1022. /* Location in window */
  1023. vx = kx + COL_MAP;
  1024. if (use_bigtile) vx += kx;
  1025. /* Hack -- Queue it */
  1026. Term_queue_char(Term, vx, vy, a, c, 0, 0);
  1027. if (use_bigtile)
  1028. {
  1029. /* Mega-Hack : Queue dummy char */
  1030. if (a & 0x80)
  1031. Term_queue_char(Term, vx+1, vy, 255, -1, 0, 0);
  1032. else
  1033. Term_queue_char(Term, vx+1, vy, TERM_WHITE, ' ', 0, 0);
  1034. }
  1035. }
  1036. /*
  1037. * Memorize interesting viewable object/features in the given grid
  1038. *
  1039. * This function should only be called on "legal" grids.
  1040. *
  1041. * This function will memorize the object and/or feature in the given grid,
  1042. * if they are (1) see-able and (2) interesting. Note that all objects are
  1043. * interesting, all terrain features except floors (and invisible traps) are
  1044. * interesting, and floors (and invisible traps) are interesting sometimes
  1045. * (depending on various options involving the illumination of floor grids).
  1046. *
  1047. * The automatic memorization of all objects and non-floor terrain features
  1048. * as soon as they are displayed allows incredible amounts of optimization
  1049. * in various places, especially "map_info()" and this function itself.
  1050. *
  1051. * Note that the memorization of objects is completely separate from the
  1052. * memorization of terrain features, preventing annoying floor memorization
  1053. * when a detected object is picked up from a dark floor, and object
  1054. * memorization when an object is dropped into a floor grid which is
  1055. * memorized but out-of-sight.
  1056. *
  1057. * This function should be called every time the "memorization" of a grid
  1058. * (or the object in a grid) is called into question, such as when an object
  1059. * is created in a grid, when a terrain feature "changes" from "floor" to
  1060. * "non-floor", and when any grid becomes "see-able" for any reason.
  1061. *
  1062. * This function is called primarily from the "update_view()" function, for
  1063. * each grid which becomes newly "see-able".
  1064. */
  1065. void note_spot(int y, int x)
  1066. {
  1067. byte info;
  1068. object_type *o_ptr;
  1069. /* Get cave info */
  1070. info = cave_info[y][x];
  1071. /* Require "seen" flag */
  1072. if (!(info & (CAVE_SEEN))) return;
  1073. /* Hack -- memorize objects */
  1074. for (o_ptr = get_first_object(y, x); o_ptr; o_ptr = get_next_object(o_ptr))
  1075. {
  1076. /* Memorize objects */
  1077. o_ptr->marked = TRUE;
  1078. }
  1079. /* Hack -- memorize grids */
  1080. if (!(info & (CAVE_MARK)))
  1081. {
  1082. /* Memorize some "boring" grids */
  1083. if (cave_feat[y][x] <= FEAT_INVIS)
  1084. {
  1085. /* Option -- memorize certain floors */
  1086. if (((info & (CAVE_GLOW)) && OPT(view_perma_grids)) ||
  1087. OPT(view_torch_grids))
  1088. {
  1089. /* Memorize */
  1090. cave_info[y][x] |= (CAVE_MARK);
  1091. }
  1092. }
  1093. /* Memorize all "interesting" grids */
  1094. else
  1095. {
  1096. /* Memorize */
  1097. cave_info[y][x] |= (CAVE_MARK);
  1098. }
  1099. }
  1100. }
  1101. /*
  1102. * Redraw (on the screen) a given map location
  1103. *
  1104. * This function should only be called on "legal" grids.
  1105. */
  1106. void light_spot(int y, int x)
  1107. {
  1108. event_signal_point(EVENT_MAP, x, y);
  1109. }
  1110. static void prt_map_aux(void)
  1111. {
  1112. byte a;
  1113. char c;
  1114. byte ta;
  1115. char tc;
  1116. grid_data g;
  1117. int y, x;
  1118. int vy, vx;
  1119. int ty, tx;
  1120. int j;
  1121. /* Scan windows */
  1122. for (j = 0; j < ANGBAND_TERM_MAX; j++)
  1123. {
  1124. term *t = angband_term[j];
  1125. /* No window */
  1126. if (!t) continue;
  1127. /* No relevant flags */
  1128. if (!(op_ptr->window_flag[j] & (PW_MAP))) continue;
  1129. /* Assume screen */
  1130. ty = t->offset_y + t->hgt;
  1131. tx = t->offset_x + t->wid;
  1132. if (use_bigtile) tx = t->offset_x + (t->wid / 2);
  1133. /* Dump the map */
  1134. for (y = t->offset_y, vy = 0; y < ty; vy++, y++)
  1135. {
  1136. for (x = t->offset_x, vx = 0; x < tx; vx++, x++)
  1137. {
  1138. /* Check bounds */
  1139. if (!in_bounds(y, x)) continue;
  1140. if (use_bigtile && (vx + 1 >= t->wid)) continue;
  1141. /* Determine what is there */
  1142. map_info(y, x, &g);
  1143. grid_data_as_text(&g, &a, &c, &ta, &tc);
  1144. Term_queue_char(t, vx, vy, a, c, ta, tc);
  1145. if (use_bigtile)
  1146. {
  1147. vx++;
  1148. /* Mega-Hack : Queue dummy char */
  1149. if (a & 0x80)
  1150. Term_queue_char(t, vx, vy, 255, -1, 0, 0);
  1151. else
  1152. Term_queue_char(t, vx, vy, TERM_WHITE, ' ', TERM_WHITE, ' ');
  1153. }
  1154. }
  1155. }
  1156. }
  1157. }
  1158. /*
  1159. * Redraw (on the screen) the current map panel
  1160. *
  1161. * Note the inline use of "light_spot()" for efficiency.
  1162. *
  1163. * The main screen will always be at least 24x80 in size.
  1164. */
  1165. void prt_map(void)
  1166. {
  1167. byte a;
  1168. char c;
  1169. byte ta;
  1170. char tc;
  1171. grid_data g;
  1172. int y, x;
  1173. int vy, vx;
  1174. int ty, tx;
  1175. /* Redraw map sub-windows */
  1176. prt_map_aux();
  1177. /* Assume screen */
  1178. ty = Term->offset_y + SCREEN_HGT;
  1179. tx = Term->offset_x + SCREEN_WID;
  1180. /* Dump the map */
  1181. for (y = Term->offset_y, vy = ROW_MAP; y < ty; vy++, y++)
  1182. {
  1183. for (x = Term->offset_x, vx = COL_MAP; x < tx; vx++, x++)
  1184. {
  1185. /* Check bounds */
  1186. if (!in_bounds(y, x)) continue;
  1187. /* Determine what is there */
  1188. map_info(y, x, &g);
  1189. grid_data_as_text(&g, &a, &c, &ta, &tc);
  1190. /* Hack -- Queue it */
  1191. Term_queue_char(Term, vx, vy, a, c, ta, tc);
  1192. if (use_bigtile)
  1193. {
  1194. vx++;
  1195. /* Mega-Hack : Queue dummy char */
  1196. if (a & 0x80)
  1197. Term_queue_char(Term, vx, vy, 255, -1, 0, 0);
  1198. else
  1199. Term_queue_char(Term, vx, vy, TERM_WHITE, ' ', TERM_WHITE, ' ');
  1200. }
  1201. }
  1202. }
  1203. }
  1204. /*
  1205. * Hack -- priority array (see below)
  1206. *
  1207. * Note that all "walls" always look like "secret doors" (see "map_info()").
  1208. */
  1209. static const int priority_table[14][2] =
  1210. {
  1211. /* Dark */
  1212. { FEAT_NONE, 2 },
  1213. /* Floors */
  1214. { FEAT_FLOOR, 5 },
  1215. /* Walls */
  1216. { FEAT_SECRET, 10 },
  1217. /* Quartz */
  1218. { FEAT_QUARTZ, 11 },
  1219. /* Magma */
  1220. { FEAT_MAGMA, 12 },
  1221. /* Rubble */
  1222. { FEAT_RUBBLE, 13 },
  1223. /* Open doors */
  1224. { FEAT_OPEN, 15 },
  1225. { FEAT_BROKEN, 15 },
  1226. /* Closed doors */
  1227. { FEAT_DOOR_HEAD + 0x00, 17 },
  1228. /* Hidden gold */
  1229. { FEAT_QUARTZ_K, 19 },
  1230. { FEAT_MAGMA_K, 19 },
  1231. /* Stairs */
  1232. { FEAT_LESS, 25 },
  1233. { FEAT_MORE, 25 },
  1234. /* End */
  1235. { 0, 0 }
  1236. };
  1237. /*
  1238. * Hack -- a priority function (see below)
  1239. */
  1240. static byte priority(byte a, char c)
  1241. {
  1242. int i, p0, p1;
  1243. feature_type *f_ptr;
  1244. /* Scan the table */
  1245. for (i = 0; TRUE; i++)
  1246. {
  1247. /* Priority level */
  1248. p1 = priority_table[i][1];
  1249. /* End of table */
  1250. if (!p1) break;
  1251. /* Feature index */
  1252. p0 = priority_table[i][0];
  1253. /* Get the feature */
  1254. f_ptr = &f_info[p0];
  1255. /* Check character and attribute, accept matches */
  1256. if ((f_ptr->x_char == c) && (f_ptr->x_attr == a)) return (p1);
  1257. }
  1258. /* Default */
  1259. return (20);
  1260. }
  1261. /*
  1262. * Display a "small-scale" map of the dungeon in the active Term.
  1263. *
  1264. * Note that this function must "disable" the special lighting effects so
  1265. * that the "priority" function will work.
  1266. *
  1267. * Note the use of a specialized "priority" function to allow this function
  1268. * to work with any graphic attr/char mappings, and the attempts to optimize
  1269. * this function where possible.
  1270. *
  1271. * If "cy" and "cx" are not NULL, then returns the screen location at which
  1272. * the player was displayed, so the cursor can be moved to that location,
  1273. * and restricts the horizontal map size to SCREEN_WID. Otherwise, nothing
  1274. * is returned (obviously), and no restrictions are enforced.
  1275. */
  1276. void display_map(int *cy, int *cx)
  1277. {
  1278. int py = p_ptr->py;
  1279. int px = p_ptr->px;
  1280. int map_hgt, map_wid;
  1281. int dungeon_hgt, dungeon_wid;
  1282. int row, col;
  1283. int x, y;
  1284. grid_data g;
  1285. byte ta;
  1286. char tc;
  1287. byte tp;
  1288. /* Large array on the stack */
  1289. byte mp[DUNGEON_HGT][DUNGEON_WID];
  1290. bool old_view_special_light;
  1291. bool old_view_granite_light;
  1292. monster_race *r_ptr = &r_info[0];
  1293. /* Desired map height */
  1294. map_hgt = Term->hgt - 2;
  1295. map_wid = Term->wid - 2;
  1296. dungeon_hgt = (p_ptr->depth == 0) ? TOWN_HGT : DUNGEON_HGT;
  1297. dungeon_wid = (p_ptr->depth == 0) ? TOWN_WID : DUNGEON_WID;
  1298. /* Prevent accidents */
  1299. if (map_hgt > dungeon_hgt) map_hgt = dungeon_hgt;
  1300. if (map_wid > dungeon_wid) map_wid = dungeon_wid;
  1301. /* Prevent accidents */
  1302. if ((map_wid < 1) || (map_hgt < 1)) return;
  1303. /* Save lighting effects */
  1304. old_view_special_light = OPT(view_special_light);
  1305. old_view_granite_light = OPT(view_granite_light);
  1306. /* Disable lighting effects */
  1307. OPT(view_special_light) = FALSE;
  1308. OPT(view_granite_light) = FALSE;
  1309. /* Nothing here */
  1310. ta = TERM_WHITE;
  1311. tc = ' ';
  1312. /* Clear the priorities */
  1313. for (y = 0; y < map_hgt; ++y)
  1314. {
  1315. for (x = 0; x < map_wid; ++x)
  1316. {
  1317. /* No priority */
  1318. mp[y][x] = 0;
  1319. }
  1320. }
  1321. /* Draw a box around the edge of the term */
  1322. window_make(0, 0, map_wid + 1, map_hgt + 1);
  1323. /* Analyze the actual map */
  1324. for (y = 0; y < dungeon_hgt; y++)
  1325. {
  1326. for (x = 0; x < dungeon_wid; x++)
  1327. {
  1328. row = (y * map_hgt / dungeon_hgt);
  1329. col = (x * map_wid / dungeon_wid);
  1330. if (use_bigtile)
  1331. col = col & ~1;
  1332. /* Get the attr/char at that map location */
  1333. map_info(y, x, &g);
  1334. grid_data_as_text(&g, &ta, &tc, &ta, &tc);
  1335. /* Get the priority of that attr/char */
  1336. tp = priority(ta, tc);
  1337. /* Save "best" */
  1338. if (mp[row][col] < tp)
  1339. {
  1340. /* Add the character */
  1341. Term_putch(col + 1, row + 1, ta, tc);
  1342. if (use_bigtile)
  1343. {
  1344. if (ta & 0x80)
  1345. Term_putch(col + 2, row + 1, 255, -1);
  1346. else
  1347. Term_putch(col + 2, row + 1, TERM_WHITE, ' ');
  1348. }
  1349. /* Save priority */
  1350. mp[row][col] = tp;
  1351. }
  1352. }
  1353. }
  1354. /* Player location */
  1355. row = (py * map_hgt / dungeon_hgt);
  1356. col = (px * map_wid / dungeon_wid);
  1357. if (use_bigtile)
  1358. col = col & ~1;
  1359. /*** Make sure the player is visible ***/
  1360. /* Get the "player" attr */
  1361. ta = r_ptr->x_attr;
  1362. /* Get the "player" char */
  1363. tc = r_ptr->x_char;
  1364. /* Draw the player */
  1365. Term_putch(col + 1, row + 1, ta, tc);
  1366. /* Return player location */
  1367. if (cy != NULL) (*cy) = row + 1;
  1368. if (cx != NULL) (*cx) = col + 1;
  1369. /* Restore lighting effects */
  1370. OPT(view_special_light) = old_view_special_light;
  1371. OPT(view_granite_light) = old_view_granite_light;
  1372. }
  1373. /*
  1374. * Display a "small-scale" map of the dungeon.
  1375. *
  1376. * Note that the "player" is always displayed on the map.
  1377. */
  1378. void do_cmd_view_map(void)
  1379. {
  1380. int cy, cx;
  1381. cptr prompt = "Hit any key to continue";
  1382. /* Save screen */
  1383. screen_save();
  1384. /* Note */
  1385. prt("Please wait...", 0, 0);
  1386. /* Flush */
  1387. Term_fresh();
  1388. /* Clear the screen */
  1389. Term_clear();
  1390. /* Display the map */
  1391. display_map(&cy, &cx);
  1392. /* Show the prompt */
  1393. put_str(prompt, Term->hgt - 1, Term->wid / 2 - strlen(prompt) / 2);
  1394. /* Highlight the player */
  1395. Term_gotoxy(cx, cy);
  1396. /* Get any key */
  1397. (void)anykey();
  1398. /* Load screen */
  1399. screen_load();
  1400. }
  1401. /*
  1402. * Some comments on the dungeon related data structures and functions...
  1403. *
  1404. * Angband is primarily a dungeon exploration game, and it should come as
  1405. * no surprise that the internal representation of the dungeon has evolved
  1406. * over time in much the same way as the game itself, to provide semantic
  1407. * changes to the game itself, to make the code simpler to understand, and
  1408. * to make the executable itself faster or more efficient in various ways.
  1409. *
  1410. * There are a variety of dungeon related data structures, and associated
  1411. * functions, which store information about the dungeon, and provide methods
  1412. * by which this information can be accessed or modified.
  1413. *
  1414. * Some of this information applies to the dungeon as a whole, such as the
  1415. * list of unique monsters which are still alive. Some of this information
  1416. * only applies to the current dungeon level, such as the current depth, or
  1417. * the list of monsters currently inhabiting the level. And some of the
  1418. * information only applies to a single grid of the current dungeon level,
  1419. * such as whether the grid is illuminated, or whether the grid contains a
  1420. * monster, or whether the grid can be seen by the player. If Angband was
  1421. * to be turned into a multi-player game, some of the information currently
  1422. * associated with the dungeon should really be associated with the player,
  1423. * such as whether a given grid is viewable by a given player.
  1424. *
  1425. * One of the major bottlenecks in ancient versions of Angband was in the
  1426. * calculation of "line of sight" from the player to various grids, such
  1427. * as those containing monsters, using the relatively expensive "los()"
  1428. * function. This was such a nasty bottleneck that a lot of silly things
  1429. * were done to reduce the dependancy on "line of sight", for example, you
  1430. * could not "see" any grids in a lit room until you actually entered the
  1431. * room, at which point every grid in the room became "illuminated" and
  1432. * all of the grids in the room were "memorized" forever. Other major
  1433. * bottlenecks involved the determination of whether a grid was lit by the
  1434. * player's torch, and whether a grid blocked the player's line of sight.
  1435. * These bottlenecks led to the development of special new functions to
  1436. * optimize issues involved with "line of sight" and "torch lit grids".
  1437. * These optimizations led to entirely new additions to the game, such as
  1438. * the ability to display the player's entire field of view using different
  1439. * colors than were used for the "memorized" portions of the dungeon, and
  1440. * the ability to memorize dark floor grids, but to indicate by the way in
  1441. * which they are displayed that they are not actually illuminated. And
  1442. * of course many of them simply made the game itself faster or more fun.
  1443. * Also, over time, the definition of "line of sight" has been relaxed to
  1444. * allow the player to see a wider "field of view", which is slightly more
  1445. * realistic, and only slightly more expensive to maintain.
  1446. *
  1447. * Currently, a lot of the information about the dungeon is stored in ways
  1448. * that make it very efficient to access or modify the information, while
  1449. * still attempting to be relatively conservative about memory usage, even
  1450. * if this means that some information is stored in multiple places, or in
  1451. * ways which require the use of special code idioms. For example, each
  1452. * monster record in the monster array contains the location of the monster,
  1453. * and each cave grid has an index into the monster array, or a zero if no
  1454. * monster is in the grid. This allows the monster code to efficiently see
  1455. * where the monster is located, while allowing the dungeon code to quickly
  1456. * determine not only if a monster is present in a given grid, but also to
  1457. * find out which monster. The extra space used to store the information
  1458. * twice is inconsequential compared to the speed increase.
  1459. *
  1460. * Some of the information about the dungeon is used by functions which can
  1461. * constitute the "critical efficiency path" of the game itself, and so the
  1462. * way in which they are stored and accessed has been optimized in order to
  1463. * optimize the game itself. For example, the "update_view()" function was
  1464. * originally created to speed up the game itself (when the player was not
  1465. * running), but then it took on extra responsibility as the provider of the
  1466. * new "special effects lighting code", and became one of the most important
  1467. * bottlenecks when the player was running. So many rounds of optimization
  1468. * were performed on both the function itself, and the data structures which
  1469. * it uses, resulting eventually in a function which not only made the game
  1470. * faster than before, but which was responsible for even more calculations
  1471. * (including the determination of which grids are "viewable" by the player,
  1472. * which grids are illuminated by the player's torch, and which grids can be
  1473. * "seen" in some way by the player), as well as for providing the guts of
  1474. * the special effects lighting code, and for the efficient redisplay of any
  1475. * grids whose visual representation may have changed.
  1476. *
  1477. * Several pieces of information about each cave grid are stored in various
  1478. * two dimensional arrays, with one unit of information for each grid in the
  1479. * dungeon. Some of these arrays have been intentionally expanded by a small
  1480. * factor to make the two dimensional array accesses faster by allowing the
  1481. * use of shifting instead of multiplication.
  1482. *
  1483. * Several pieces of information about each cave grid are stored in the
  1484. * "cave_info" array, which is a special two dimensional array of bytes,
  1485. * one for each cave grid, each containing eight separate "flags" which
  1486. * describe some property of the cave grid. These flags can be checked and
  1487. * modified extremely quickly, especially when special idioms are used to
  1488. * force the compiler to keep a local register pointing to the base of the
  1489. * array. Special location offset macros can be used to minimize the number
  1490. * of computations which must be performed at runtime. Note that using a
  1491. * byte for each flag set may be slightly more efficient than using a larger
  1492. * unit, so if another flag (or two) is needed later, and it must be fast,
  1493. * then the two existing flags which do not have to be fast should be moved
  1494. * out into some other data structure and the new flags should take their
  1495. * place. This may require a few minor changes in the savefile code.
  1496. *
  1497. * The "CAVE_ROOM" flag is saved in the savefile and is used to determine
  1498. * which grids are part of "rooms", and thus which grids are affected by
  1499. * "illumination" spells. This flag does not have to be very fast.
  1500. *
  1501. * The "CAVE_ICKY" flag is saved in the savefile and is used to determine
  1502. * which grids are part of "vaults", and thus which grids cannot serve as
  1503. * the destinations of player teleportation. This flag does not have to
  1504. * be very fast.
  1505. *
  1506. * The "CAVE_MARK" flag is saved in the savefile and is used to determine
  1507. * which grids have been "memorized" by the player. This flag is used by
  1508. * the "map_info()" function to determine if a grid should be displayed.
  1509. * This flag is used in a few other places to determine if the player can
  1510. * "know" about a given grid. This flag must be very fast.
  1511. *
  1512. * The "CAVE_GLOW" flag is saved in the savefile and is used to determine
  1513. * which grids are "permanently illuminated". This flag is used by the
  1514. * "update_view()" function to help determine which viewable flags may
  1515. * be "seen" by the player. This flag is used by the "map_info" function
  1516. * to determine if a grid is only lit by the player's torch. This flag
  1517. * has special semantics for wall grids (see "update_view()"). This flag
  1518. * must be very fast.
  1519. *
  1520. * The "CAVE_WALL" flag is used to determine which grids block the player's
  1521. * line of sight. This flag is used by the "update_view()" function to
  1522. * determine which grids block line of sight, and to help determine which
  1523. * grids can be "seen" by the player. This flag must be very fast.
  1524. *
  1525. * The "CAVE_VIEW" flag is used to determine which grids are currently in
  1526. * line of sight of the player. This flag is set by (and used by) the
  1527. * "update_view()" function. This flag is used by any code which needs to
  1528. * know if the player can "view" a given grid. This flag is used by the
  1529. * "map_info()" function for some optional special lighting effects. The
  1530. * "player_has_los_bold()" macro wraps an abstraction around this flag, but
  1531. * certain code idioms are much more efficient. This flag is used to check
  1532. * if a modification to a terrain feature might affect the player's field of
  1533. * view. This flag is used to see if certain monsters are "visible" to the
  1534. * player. This flag is used to allow any monster in the player's field of
  1535. * view to "sense" the presence of the player. This flag must be very fast.
  1536. *
  1537. * The "CAVE_SEEN" flag is used to determine which grids are currently in
  1538. * line of sight of the player and also illuminated in some way. This flag
  1539. * is set by the "update_view()" function, using computations based on the
  1540. * "CAVE_VIEW" and "CAVE_WALL" and "CAVE_GLOW" flags of various grids. This
  1541. * flag is used by any code which needs to know if the player can "see" a
  1542. * given grid. This flag is used by the "map_info()" function both to see
  1543. * if a given "boring" grid can be seen by the player, and for some optional
  1544. * special lighting effects. The "player_can_see_bold()" macro wraps an
  1545. * abstraction around this flag, but certain code idioms are much more
  1546. * efficient. This flag is used to see if certain monsters are "visible" to
  1547. * the player. This flag is never set for a grid unless "CAVE_VIEW" is also
  1548. * set for the grid. Whenever the "CAVE_WALL" or "CAVE_GLOW" flag changes
  1549. * for a grid which has the "CAVE_VIEW" flag set, the "CAVE_SEEN" flag must
  1550. * be recalculated. The simplest way to do this is to call "forget_view()"
  1551. * and "update_view()" whenever the "CAVE_WALL" or "CAVE_GLOW" flags change
  1552. * for a grid which has "CAVE_VIEW" set. This flag must be very fast.
  1553. *
  1554. * The "CAVE_TEMP" flag is used for a variety of temporary purposes. This
  1555. * flag is used to determine if the "CAVE_SEEN" flag for a grid has changed
  1556. * during the "update_view()" function. This flag is us…

Large files files are truncated, but you can click here to view the full file