diff options
Diffstat (limited to 'src/cave.c')
-rw-r--r-- | src/cave.c | 5055 |
1 files changed, 0 insertions, 5055 deletions
diff --git a/src/cave.c b/src/cave.c deleted file mode 100644 index d23fc44c..00000000 --- a/src/cave.c +++ /dev/null @@ -1,5055 +0,0 @@ -/* File: cave.c */ - -/* Purpose: low level dungeon routines -BEN- */ - - -#include "angband.h" - - -/* - * Support for Adam Bolt's tileset, lighting and transparency effects - * by Robert Ruehlmann (rr9@angband.org) - */ - - -/* - * Approximate Distance between two points. - * - * When either the X or Y component dwarfs the other component, - * this function is almost perfect, and otherwise, it tends to - * over-estimate about one grid per fifteen grids of distance. - * - * Algorithm: hypot(dy,dx) = max(dy,dx) + min(dy,dx) / 2 - */ -int distance(int y1, int x1, int y2, int x2) -{ - int dy, dx, d; - - - /* Find the absolute y/x distance components */ - dy = (y1 > y2) ? (y1 - y2) : (y2 - y1); - dx = (x1 > x2) ? (x1 - x2) : (x2 - x1); - - /* Hack -- approximate the distance */ - d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1)); - - /* Return the distance */ - return (d); -} - - -/* - * Returns TRUE if a grid is considered to be a wall for the purpose - * of magic mapping / clairvoyance - */ -static bool_ is_wall(cave_type *c_ptr) -{ - byte feat; - - - /* Handle feature mimics */ - if (c_ptr->mimic) feat = c_ptr->mimic; - else feat = c_ptr->feat; - - /* Paranoia */ - if (feat >= max_f_idx) return FALSE; - - /* Vanilla floors and doors aren't considered to be walls */ - if (feat < FEAT_SECRET) return FALSE; - - /* Exception #1: a glass wall is a wall but doesn't prevent LOS */ - if (feat == FEAT_GLASS_WALL) return FALSE; - - /* Exception #2: an illusion wall is not a wall but obstructs view */ - if (feat == FEAT_ILLUS_WALL) return TRUE; - - /* Exception #3: a small tree is a floor but obstructs view */ - if (feat == FEAT_SMALL_TREES) return TRUE; - - /* Normal cases: use the WALL flag in f_info.txt */ - return (f_info[feat].flags1 & FF1_WALL) ? TRUE : FALSE; -} - - -/* - * A simple, fast, integer-based line-of-sight algorithm. By Joseph Hall, - * 4116 Brewster Drive, Raleigh NC 27606. Email to jnh@ecemwl.ncsu.edu. - * - * Returns TRUE if a line of sight can be traced from (x1,y1) to (x2,y2). - * - * The LOS begins at the center of the tile (x1,y1) and ends at the center of - * the tile (x2,y2). If los() is to return TRUE, all of the tiles this line - * passes through must be floor tiles, except for (x1,y1) and (x2,y2). - * - * We assume that the "mathematical corner" of a non-floor tile does not - * block line of sight. - * - * Because this function uses (short) ints for all calculations, overflow may - * occur if dx and dy exceed 90. - * - * Once all the degenerate cases are eliminated, the values "qx", "qy", and - * "m" are multiplied by a scale factor "f1 = abs(dx * dy * 2)", so that - * we can use integer arithmetic. - * - * We travel from start to finish along the longer axis, starting at the border - * between the first and second tiles, where the y offset = .5 * slope, taking - * into account the scale factor. See below. - * - * Also note that this function and the "move towards target" code do NOT - * share the same properties. Thus, you can see someone, target them, and - * then fire a bolt at them, but the bolt may hit a wall, not them. However, - * by clever choice of target locations, you can sometimes throw a "curve". - * - * Note that "line of sight" is not "reflexive" in all cases. - * - * Use the "projectable()" routine to test "spell/missile line of sight". - * - * Use the "update_view()" function to determine player line-of-sight. - */ -bool_ los(int y1, int x1, int y2, int x2) -{ - /* Delta */ - int dx, dy; - - /* Absolute */ - int ax, ay; - - /* Signs */ - int sx, sy; - - /* Fractions */ - int qx, qy; - - /* Scanners */ - int tx, ty; - - /* Scale factors */ - int f1, f2; - - /* Slope, or 1/Slope, of LOS */ - int m; - - - /* Extract the offset */ - dy = y2 - y1; - dx = x2 - x1; - - /* Extract the absolute offset */ - ay = ABS(dy); - ax = ABS(dx); - - - /* Handle adjacent (or identical) grids */ - if ((ax < 2) && (ay < 2)) return (TRUE); - - - /* Paranoia -- require "safe" origin */ - /* if (!in_bounds(y1, x1)) return (FALSE); */ - - - /* Directly South/North */ - if (!dx) - { - /* South -- check for walls */ - if (dy > 0) - { - for (ty = y1 + 1; ty < y2; ty++) - { - if (!cave_sight_bold(ty, x1)) return (FALSE); - } - } - - /* North -- check for walls */ - else - { - for (ty = y1 - 1; ty > y2; ty--) - { - if (!cave_sight_bold(ty, x1)) return (FALSE); - } - } - - /* Assume los */ - return (TRUE); - } - - /* Directly East/West */ - if (!dy) - { - /* East -- check for walls */ - if (dx > 0) - { - for (tx = x1 + 1; tx < x2; tx++) - { - if (!cave_sight_bold(y1, tx)) return (FALSE); - } - } - - /* West -- check for walls */ - else - { - for (tx = x1 - 1; tx > x2; tx--) - { - if (!cave_sight_bold(y1, tx)) return (FALSE); - } - } - - /* Assume los */ - return (TRUE); - } - - - /* Extract some signs */ - sx = (dx < 0) ? -1 : 1; - sy = (dy < 0) ? -1 : 1; - - - /* Vertical "knights" */ - if (ax == 1) - { - if (ay == 2) - { - if (cave_sight_bold(y1 + sy, x1)) return (TRUE); - } - } - - /* Horizontal "knights" */ - else if (ay == 1) - { - if (ax == 2) - { - if (cave_sight_bold(y1, x1 + sx)) return (TRUE); - } - } - - - /* Calculate scale factor div 2 */ - f2 = (ax * ay); - - /* Calculate scale factor */ - f1 = f2 << 1; - - - /* Travel horizontally */ - if (ax >= ay) - { - /* Let m = dy / dx * 2 * (dy * dx) = 2 * dy * dy */ - qy = ay * ay; - m = qy << 1; - - tx = x1 + sx; - - /* Consider the special case where slope == 1. */ - if (qy == f2) - { - ty = y1 + sy; - qy -= f1; - } - else - { - ty = y1; - } - - /* Note (below) the case (qy == f2), where */ - /* the LOS exactly meets the corner of a tile. */ - while (x2 - tx) - { - if (!cave_sight_bold(ty, tx)) return (FALSE); - - qy += m; - - if (qy < f2) - { - tx += sx; - } - else if (qy > f2) - { - ty += sy; - if (!cave_sight_bold(ty, tx)) return (FALSE); - qy -= f1; - tx += sx; - } - else - { - ty += sy; - qy -= f1; - tx += sx; - } - } - } - - /* Travel vertically */ - else - { - /* Let m = dx / dy * 2 * (dx * dy) = 2 * dx * dx */ - qx = ax * ax; - m = qx << 1; - - ty = y1 + sy; - - if (qx == f2) - { - tx = x1 + sx; - qx -= f1; - } - else - { - tx = x1; - } - - /* Note (below) the case (qx == f2), where */ - /* the LOS exactly meets the corner of a tile. */ - while (y2 - ty) - { - if (!cave_sight_bold(ty, tx)) return (FALSE); - - qx += m; - - if (qx < f2) - { - ty += sy; - } - else if (qx > f2) - { - tx += sx; - if (!cave_sight_bold(ty, tx)) return (FALSE); - qx -= f1; - ty += sy; - } - else - { - tx += sx; - qx -= f1; - ty += sy; - } - } - } - - /* Assume los */ - return (TRUE); -} - - - -/* - * Returns true if the player's grid is dark - */ -bool_ no_lite(void) -{ - return (!player_can_see_bold(p_ptr->py, p_ptr->px)); -} - - - -/* - * Determine if a given location may be "destroyed" - * - * Used by destruction spells, and for placing stairs, etc. - */ -bool_ cave_valid_bold(int y, int x) -{ - cave_type *c_ptr = &cave[y][x]; - - s16b this_o_idx, next_o_idx = 0; - - - /* Forbid perma-grids */ - if (cave_perma_grid(c_ptr)) return (FALSE); - - /* Check objects */ - for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) - { - object_type * o_ptr; - - /* Acquire object */ - o_ptr = &o_list[this_o_idx]; - - /* Acquire next object */ - next_o_idx = o_ptr->next_o_idx; - - /* Forbid artifact grids */ - if ((o_ptr->art_name) || artifact_p(o_ptr)) return (FALSE); - } - - /* Accept */ - return (TRUE); -} - - - - -/* - * Hack -- Legal monster codes - */ -static cptr image_monster_hack = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - -/* - * Hack -- Legal monster codes for IBM pseudo-graphics - * - * Dropped. Although this option has long left unmaintained, hardcoding - * code points makes it impossible to update the font and prf files - * flexibly. And the normal graphics code still works with it -- pelpel - */ - -/* - * Mega-Hack -- Hallucinatory monster - */ -static void image_monster(byte *ap, char *cp) -{ - int n; - - switch (graphics_mode) - { - /* Text mode */ - case GRAPHICS_NONE: - { - n = strlen(image_monster_hack); - - /* Random symbol from set above */ - *cp = (image_monster_hack[rand_int(n)]); - - /* Random color */ - *ap = randint(15); - - break; - } - - /* Normal graphics */ - default: - { - /* Avoid player ghost */ - n = randint(max_r_idx); - - *cp = r_info[n].x_char; - - *ap = r_info[n].x_attr; - - break; - } - } -} - - - - -/* - * Hack -- Legal object codes - */ -static cptr image_object_hack = "?/|\\\"!$()_-=[]{},~"; - -/* - * Hardcoded IBM pseudo-graphics code points have been removed - * for the same reason as stated above -- pelpel - */ - -/* - * Mega-Hack -- Hallucinatory object - */ -static void image_object(byte *ap, char *cp) -{ - int n; - - switch (graphics_mode) - { - /* Text mode */ - case GRAPHICS_NONE: - { - n = strlen(image_object_hack); - - /* Random symbol from set above */ - *cp = (image_object_hack[rand_int(n)]); - - /* Random color */ - *ap = randint(15); - - /* Done */ - break; - } - - /* Normal graphics */ - default: - { - n = randint(max_k_idx - 1); - - *cp = k_info[n].x_char; - *ap = k_info[n].x_attr; - - break; - } - } -} - - -/* - * Hack -- Random hallucination - */ -static void image_random(byte *ap, char *cp) -{ - /* Normally, assume monsters */ - if (rand_int(100) < 75) - { - image_monster(ap, cp); - } - - /* Otherwise, assume objects */ - else - { - image_object(ap, cp); - } -} - - -/* - * The 16x16 tile of the terrain supports lighting - */ -#if 1 - -#define feat_supports_lighting(F) \ -((f_info[F].flags1 & FF1_SUPPORT_LIGHT) != 0) - -#else - -static bool_ feat_supports_lighting(byte feat) -{ - if (f_info[feat].flags1 & FF1_SUPPORT_LIGHT) return TRUE; - else return FALSE; -} - -#endif - - -char get_shimmer_color() -{ - switch (randint(7)) - { - case 1: - return (TERM_RED); - case 2: - return (TERM_L_RED); - case 3: - return (TERM_WHITE); - case 4: - return (TERM_L_GREEN); - case 5: - return (TERM_BLUE); - case 6: - return (TERM_L_DARK); - case 7: - return (TERM_GREEN); - } - - return (TERM_VIOLET); -} - - -/* - * Table of breath colors. Must match listings in a single set of - * monster spell flags. - * - * The value "255" is special. Monsters with that kind of breath - * may be any color. - */ -static byte breath_to_attr[32][2] = -{ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { TERM_SLATE, TERM_L_DARK }, /* RF4_BRTH_ACID */ - { TERM_BLUE, TERM_L_BLUE }, /* RF4_BRTH_ELEC */ - { TERM_RED, TERM_L_RED }, /* RF4_BRTH_FIRE */ - { TERM_WHITE, TERM_L_WHITE }, /* RF4_BRTH_COLD */ - { TERM_GREEN, TERM_L_GREEN }, /* RF4_BRTH_POIS */ - { TERM_L_GREEN, TERM_GREEN }, /* RF4_BRTH_NETHR */ - { TERM_YELLOW, TERM_ORANGE }, /* RF4_BRTH_LITE */ - { TERM_L_DARK, TERM_SLATE }, /* RF4_BRTH_DARK */ - { TERM_L_UMBER, TERM_UMBER }, /* RF4_BRTH_CONFU */ - { TERM_YELLOW, TERM_L_UMBER }, /* RF4_BRTH_SOUND */ - { 255, 255 }, /* (any color) */ /* RF4_BRTH_CHAOS */ - { TERM_VIOLET, TERM_VIOLET }, /* RF4_BRTH_DISEN */ - { TERM_L_RED, TERM_VIOLET }, /* RF4_BRTH_NEXUS */ - { TERM_L_BLUE, TERM_L_BLUE }, /* RF4_BRTH_TIME */ - { TERM_L_WHITE, TERM_SLATE }, /* RF4_BRTH_INER */ - { TERM_L_WHITE, TERM_SLATE }, /* RF4_BRTH_GRAV */ - { TERM_UMBER, TERM_L_UMBER }, /* RF4_BRTH_SHARD */ - { TERM_ORANGE, TERM_RED }, /* RF4_BRTH_PLAS */ - { TERM_UMBER, TERM_L_UMBER }, /* RF4_BRTH_FORCE */ - { TERM_L_BLUE, TERM_WHITE }, /* RF4_BRTH_MANA */ - { 0, 0 }, /* */ - { TERM_GREEN, TERM_L_GREEN }, /* RF4_BRTH_NUKE */ - { 0, 0 }, /* */ - { TERM_WHITE, TERM_L_RED }, /* RF4_BRTH_DISINT */ -}; - - -/* - * Multi-hued monsters shimmer acording to their breaths. - * - * If a monster has only one kind of breath, it uses both colors - * associated with that breath. Otherwise, it just uses the first - * color for any of its breaths. - * - * If a monster does not breath anything, it can be any color. - */ -static byte multi_hued_attr(monster_race *r_ptr) -{ - byte allowed_attrs[15]; - - int i, j; - - int stored_colors = 0; - - int breaths = 0; - - int first_color = 0; - - int second_color = 0; - - - /* Monsters with no ranged attacks can be any color */ - if (!r_ptr->freq_inate) return (get_shimmer_color()); - - /* Check breaths */ - for (i = 0; i < 32; i++) - { - bool_ stored = FALSE; - - /* Don't have that breath */ - if (!(r_ptr->flags4 & (1L << i))) continue; - - /* Get the first color of this breath */ - first_color = breath_to_attr[i][0]; - - /* Breath has no color associated with it */ - if (first_color == 0) continue; - - /* Monster can be of any color */ - if (first_color == 255) return (randint(15)); - - - /* Increment the number of breaths */ - breaths++; - - /* Monsters with lots of breaths may be any color. */ - if (breaths == 6) return (randint(15)); - - - /* Always store the first color */ - for (j = 0; j < stored_colors; j++) - { - /* Already stored */ - if (allowed_attrs[j] == first_color) stored = TRUE; - } - if (!stored) - { - allowed_attrs[stored_colors] = first_color; - stored_colors++; - } - - /* - * Remember (but do not immediately store) the second color - * of the first breath. - */ - if (breaths == 1) - { - second_color = breath_to_attr[i][1]; - } - } - - /* Monsters with no breaths may be of any color. */ - if (breaths == 0) return (get_shimmer_color()); - - /* If monster has one breath, store the second color too. */ - if (breaths == 1) - { - allowed_attrs[stored_colors] = second_color; - stored_colors++; - } - - /* Pick a color at random */ - return (allowed_attrs[rand_int(stored_colors)]); -} - - -/* - * Extract the attr/char to display at the given (legal) map location - * - * Note that this function, since it is called by "lite_spot()" which - * is called by "update_view()", is a major efficiency concern. - * - * Basically, we examine each "layer" of the world (terrain, objects, - * monsters/players), from the bottom up, extracting a new attr/char - * if necessary at each layer, and defaulting to "darkness". This is - * not the fastest method, but it is very simple, and it is about as - * fast as it could be for grids which contain no "marked" objects or - * "visible" monsters. - * - * We apply the effects of hallucination during each layer. Objects will - * always appear as random "objects", monsters will always appear as random - * "monsters", and normal grids occasionally appear as random "monsters" or - * "objects", but note that these random "monsters" and "objects" are really - * just "colored ascii symbols" (which may look silly on some machines). - * - * The hallucination functions avoid taking any pointers to local variables - * because some compilers refuse to use registers for any local variables - * whose address is taken anywhere in the function. - * - * As an optimization, we can handle the "player" grid as a special case. - * - * Note that the memorization of "objects" and "monsters" is not related - * to the memorization of "terrain". This allows the player to memorize - * the terrain of a grid without memorizing any objects in that grid, and - * to detect monsters without detecting anything about the terrain of the - * grid containing the monster. - * - * The fact that all interesting "objects" and "terrain features" are - * memorized as soon as they become visible for the first time means - * that we only have to check the "CAVE_SEEN" flag for "boring" grids. - * - * Note that bizarre things must be done when the "attr" and/or "char" - * codes have the "high-bit" set, since these values are used to encode - * various "special" pictures in some versions, and certain situations, - * such as "multi-hued" or "clear" monsters, cause the attr/char codes - * to be "scrambled" in various ways. - * - * Note that the "zero" entry in the feature/object/monster arrays are - * used to provide "special" attr/char codes, with "monster zero" being - * used for the player attr/char, "object zero" being used for the "stack" - * attr/char, and "feature zero" being used for the "nothing" attr/char. - * - * Note that eventually we may want to use the "&" symbol for embedded - * treasure, and use the "*" symbol to indicate multiple objects, but - * currently, we simply use the attr/char of the first "marked" object - * in the stack, if any, and so "object zero" is unused. XXX XXX XXX - * - * Note the assumption that doing "x_ptr = &x_info[x]" plus a few of - * "x_ptr->xxx", is quicker than "x_info[x].xxx", even if "x" is a fixed - * constant. If this is incorrect then a lot of code should be changed. - * - * - * Some comments on the "terrain" layer... - * - * Note that "boring" grids (floors, invisible traps, and any illegal grids) - * are very different from "interesting" grids (all other terrain features), - * and the two types of grids are handled completely separately. The most - * important distinction is that "boring" grids may or may not be memorized - * when they are first encountered, and so we must use the "CAVE_SEEN" flag - * to see if they are "see-able". - * - * - * Some comments on the "terrain" layer (boring grids)... - * - * Note that "boring" grids are always drawn using the picture for "empty - * floors", which is stored in "f_info[FEAT_FLOOR]". Sometimes, special - * lighting effects may cause this picture to be modified. - * - * Note that "invisible traps" are always displayes exactly like "empty - * floors", which prevents various forms of "cheating", with no loss of - * efficiency. There are still a few ways to "guess" where traps may be - * located, for example, objects will never fall into a grid containing - * an invisible trap. XXX XXX - * - * To determine if a "boring" grid should be displayed, we simply check to - * see if it is either memorized ("CAVE_MARK"), or currently "see-able" by - * the player ("CAVE_SEEN"). Note that "CAVE_SEEN" is now maintained by the - * "update_view()" function. - * - * Note the "special lighting effects" which can be activated for "boring" - * grids using the "view_special_lite" option, causing certain such grids - * to be displayed using special colors. If the grid is "see-able" by - * the player, we will use the normal (except that, if the "view_yellow_lite" - * option is set, and the grid is *only* "see-able" because of the player's - * torch, then we will use "yellow"), else if the player is "blind", we will - * use greyscale, else if the grid is not "illuminated", we will use "dark - * gray", if the "view_bright_lite" option is set, we will use "darker" colour - * else we will use the normal colour. - * - * - * Some comments on the "terrain" layer (non-boring grids)... - * - * Note the use of the "mimic" field in the "terrain feature" processing, - * which allows any feature to "pretend" to be another feature. This is - * used to "hide" secret doors, and to make all "doors" appear the same, - * and all "walls" appear the same, and "hidden" treasure stay hidden. - * Note that it is possible to use this field to make a feature "look" - * like a floor, but the "view_special_lite" flag only affects actual - * "boring" grids. - * - * Since "interesting" grids are always memorized as soon as they become - * "see-able" by the player ("CAVE_SEEN"), such a grid only needs to be - * displayed if it is memorized ("CAVE_MARK"). Most "interesting" grids - * are in fact non-memorized, non-see-able, wall grids, so the fact that - * we do not have to check the "CAVE_SEEN" flag adds some efficiency, at - * the cost of *forcing* the memorization of all "interesting" grids when - * they are first seen. Since the "CAVE_SEEN" flag is now maintained by - * the "update_view()" function, this efficiency is not as significant as - * it was in previous versions, and could perhaps be removed. - * (so I removed this to simplify the terrain feature handling -- pelpel) - * - * Note the "special lighting effects" which can be activated for "wall" - * grids using the "view_granite_lite" option, causing certain such grids - * to be displayed using special colors. - * If the grid is "see-able" by the player, we will use the normal colour - * else if the player is "blind", we will use grey scale, else if the - * "view_bright_lite" option is set, we will use reduced colour, else we - * will use the normal one. - * - * Note that "wall" grids are more complicated than "boring" grids, due to - * the fact that "CAVE_GLOW" for a "wall" grid means that the grid *might* - * be glowing, depending on where the player is standing in relation to the - * wall. In particular, the wall of an illuminated room should look just - * like any other (dark) wall unless the player is actually inside the room. - * - * Thus, we do not support as many visual special effects for "wall" grids - * as we do for "boring" grids, since many of them would give the player - * information about the "CAVE_GLOW" flag of the wall grid, in particular, - * it would allow the player to notice the walls of illuminated rooms from - * a dark hallway that happened to run beside the room. - * - * - * Some comments on the "object" layer... - * - * Currently, we do nothing with multi-hued objects, because there are - * not any. If there were, they would have to set "shimmer_objects" - * when they were created, and then new "shimmer" code in "dungeon.c" - * would have to be created handle the "shimmer" effect, and the code - * in "cave.c" would have to be updated to create the shimmer effect. - * This did not seem worth the effort. XXX XXX - * - * - * Some comments on the "monster"/"player" layer... - * - * Note that monsters can have some "special" flags, including "ATTR_MULTI", - * which means their color changes, and "ATTR_CLEAR", which means they take - * the color of whatever is under them, and "CHAR_CLEAR", which means that - * they take the symbol of whatever is under them. Technically, the flag - * "CHAR_MULTI" is supposed to indicate that a monster looks strange when - * examined, but this flag is currently ignored. All of these flags are - * ignored if the "avoid_other" option is set, since checking for these - * conditions is expensive (and annoying) on some systems. - * - * Normally, players could be handled just like monsters, except that the - * concept of the "torch lite" of others player would add complications. - * For efficiency, however, we handle the (only) player first, since the - * "player" symbol always "pre-empts" any other facts about the grid. - * - * The "hidden_player" efficiency option, which only makes sense with a - * single player, allows the player symbol to be hidden while running. - */ - -/* - * Alternative colours for unseen grids - * - * Reduced colours - remembered interesting grids and perma-lit floors - * B&W - currently only used by blindness effect - */ - -/* Colour */ -static byte dark_attrs[16] = -{ - TERM_DARK, TERM_L_WHITE, TERM_L_DARK, TERM_ORANGE, - TERM_RED, TERM_GREEN, TERM_BLUE, TERM_UMBER, - TERM_L_DARK, TERM_SLATE, TERM_VIOLET, TERM_YELLOW, - TERM_RED, TERM_GREEN, TERM_BLUE, TERM_UMBER -}; - -/* B&W */ -static byte darker_attrs[16] = -{ - TERM_DARK, TERM_L_WHITE, TERM_L_DARK, TERM_SLATE, - TERM_L_DARK, TERM_L_DARK, TERM_L_DARK, TERM_L_DARK, - TERM_L_DARK, TERM_SLATE, TERM_L_DARK, TERM_SLATE, - TERM_SLATE, TERM_SLATE, TERM_SLATE, TERM_SLATE -}; - - -void map_info(int y, int x, byte *ap, char *cp, byte *tap, char *tcp, - byte *eap, char *ecp) -{ - cave_type *c_ptr; - - feature_type *f_ptr; - - s16b this_o_idx, next_o_idx = 0; - - u16b info; - - s16b t_idx; - - byte feat; - - byte a; - - byte c; - - /* - * This means that a port supports graphics overlay as well as lighting - * effects. See the step 3 below for the detailed information about - * lighting. Basically, it requires "darker" tiles for those terrain - * features with SUPPORT_LIGHT flag set, and they must be arranged - * this way: - * col col+1 col+2 - * row base darker brighter - */ - bool_ graf_new = ((graphics_mode == GRAPHICS_ISO) || - (graphics_mode == GRAPHICS_NEW)); - - /* - * I never understand why some coders like shimmering so much. - * It just serves to hurt my eyes, IMHO. If one feels like to show off, - * go for better graphics support... Anyway this means a port allows - * changing attr independently from its char -- pelpel - */ - bool_ attr_mutable = (!use_graphics || - (graphics_mode == GRAPHICS_IBM)); - - - /**** Preparation ****/ - - /* Access the grid */ - c_ptr = &cave[y][x]; - - - /* Cache some frequently used values */ - - /* Grid info */ - info = c_ptr->info; - - /* Feature code */ - feat = c_ptr->feat; - - /* Apply "mimic" field */ - if (c_ptr->mimic) - { - feat = c_ptr->mimic; - } - else - { - feat = f_info[feat].mimic; - } - - /* Access floor */ - f_ptr = &f_info[feat]; - - - /* Reset attr/char */ - *eap = 0; - *ecp = 0; - - - /**** Layer 1 -- Terrain feature ****/ - - /* Only memorised or visible grids are displayed */ - if (info & (CAVE_MARK | CAVE_SEEN)) - { - /**** Step 1 -- Retrieve base attr/char ****/ - - /* 'Sane' terrain features */ - if (feat != FEAT_SHOP) - { - /* Normal char */ - c = f_ptr->x_char; - - /* Normal attr */ - a = f_ptr->x_attr; - } - - /* Mega-Hack 1 -- Building don't conform to f_info */ - else - { - c = st_info[c_ptr->special].x_char; - a = st_info[c_ptr->special].x_attr; - } - - /* Mega-Hack 2 -- stair to dungeon branch are purple */ - if (c_ptr->special && attr_mutable && - ((feat == FEAT_MORE) || (feat == FEAT_LESS))) - { - a = TERM_VIOLET; - } - - /* Mega-Hack 3 -- Traps don't have f_info entries either */ - if ((info & (CAVE_TRDT)) && (feat != FEAT_ILLUS_WALL)) - { - /* Trap index */ - t_idx = c_ptr->t_idx; - - if (use_graphics && - (t_info[t_idx].g_attr != 0) && - (t_info[t_idx].g_char != 0)) - { - - if (graf_new) - { - *eap = t_info[t_idx].g_attr; - *ecp = t_info[t_idx].g_char; - } - else - { - a = t_info[t_idx].g_attr; - c = t_info[t_idx].g_char; - } - - } - else - { - /* - * If trap is set on a floor grid that is not - * one of "interesting" features, use a special - * symbol to display it. Check for doors is no longer - * necessary because they have REMEMBER flag now. - * - * Cave macros cannot be used safely here, because of - * c_ptr->mimic XXX XXX - */ - if (!attr_mutable) - { - a = f_info[FEAT_TRAP].x_attr; - c = f_info[FEAT_TRAP].x_char; - } - else - { - if ((f_ptr->flags1 & (FF1_FLOOR | FF1_REMEMBER)) == FF1_FLOOR) - { - c = f_info[FEAT_TRAP].x_char; - } - - /* Add attr XXX XXX XXX */ - a = t_info[t_idx].color; - - /* Get a new color with a strange formula :) XXX XXX XXX */ - if (t_info[t_idx].flags & FTRAP_CHANGE) - { - s32b tmp; - - tmp = dun_level + dungeon_type + feat; - - a = tmp % 16; - } - } - } - } - - - /**** Step 2 -- Apply special random effects ****/ - if (!avoid_other && !avoid_shimmer && attr_mutable) - { - /* Special terrain effect */ - if (c_ptr->effect) - { - a = spell_color(effects[c_ptr->effect].type); - } - - /* Multi-hued attr */ - else if (f_ptr->flags1 & FF1_ATTR_MULTI) - { - a = f_ptr->shimmer[rand_int(7)]; - } - } - - - /* - * Step 3 - * - * Special lighting effects, if specified and applicable - * This will never happen for - * - any grids in the overhead map - * - traps - * - (graphics modes) terrain features without corresponding - * "darker" tiles. - * - * Note the use of f_ptr->flags1 to avoid problems with - * c_ptr->mimic. - */ - - /* view_special_lite: lighting effects for boring features */ - if (view_special_lite && - ((f_ptr->flags1 & (FF1_FLOOR | FF1_REMEMBER)) == FF1_FLOOR)) - { - if (!p_ptr->wild_mode && !(info & (CAVE_TRDT)) && - (attr_mutable || (graf_new && feat_supports_lighting(feat)))) - { - /* Handle "seen" grids */ - if (info & (CAVE_SEEN)) - { - /* Only lit by "torch" light */ - if (view_yellow_lite && !(info & (CAVE_GLOW))) - { - if (graf_new) - { - /* Use a brightly lit tile */ - c += 2; - } - else - { - /* Use "yellow" */ - a = TERM_YELLOW; - } - } - } - - /* Handle "blind" */ - else if (p_ptr->blind) - { - if (graf_new) - { - /* Use a dark tile */ - c++; - } - else - { - /* Use darker colour */ - a = darker_attrs[a & 0xF]; - } - } - - /* Handle "dark" grids */ - else if (!(info & (CAVE_GLOW))) - { - if (graf_new) - { - /* Use a dark tile */ - c++; - } - else - { - /* Use darkest colour */ - a = TERM_L_DARK; - } - } - - /* "Out-of-sight" glowing grids -- handle "view_bright_lite" */ - else if (view_bright_lite) - { - if (graf_new) - { - /* Use a dark tile */ - c++; - } - else - { - /* Use darker colour */ - a = dark_attrs[a & 0xF]; - } - } - } - } - - /* view_granite_lite: lighting effects for walls and doors */ - else if (view_granite_lite && - (f_ptr->flags1 & (FF1_NO_VISION | FF1_DOOR))) - { - if (!p_ptr->wild_mode && !(info & (CAVE_TRDT)) && - (attr_mutable || (graf_new && feat_supports_lighting(feat)))) - { - /* Handle "seen" grids */ - if (info & (CAVE_SEEN)) - { - /* Do nothing */ - } - - /* Handle "blind" */ - else if (p_ptr->blind) - { - if (graf_new) - { - /* Use a dark tile */ - c++; - } - else - { - /* Use darker colour */ - a = darker_attrs[a & 0xF]; - } - } - - /* Handle "view_bright_lite" */ - else if (view_bright_lite) - { - if (graf_new) - { - /* Use a dark tile */ - c++; - } - else - { - /* Use darker colour */ - a = dark_attrs[a & 0xF]; - } - } - - else - { - if (graf_new) - { - /* Use a brightly lit tile */ - c += 2; - } - else - { - /* Use normal colour */ - } - } - } - } - } - - /* Unknown grids */ - else - { - /* Access darkness */ - f_ptr = &f_info[FEAT_NONE]; - - /* Normal attr */ - a = f_ptr->x_attr; - - /* Normal char */ - c = f_ptr->x_char; - } - - /* - * Hack -- rare random hallucination - * Because we cannot be sure which is outer dungeon walls, - * the check for 'feat' has been removed - */ - if (p_ptr->image && (rand_int(256) == 0)) - { - /* Hallucinate */ - image_random(ap, cp); - } - - /* Save the terrain info for the transparency effects */ - *tap = a; - *tcp = c; - - /* Save the info */ - *ap = a; - *cp = c; - - - /**** Layer 2 -- Objects ****/ - - if (feat != FEAT_MON_TRAP) - { - for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) - { - object_type * o_ptr; - - /* Acquire object */ - o_ptr = &o_list[this_o_idx]; - - /* Acquire next object */ - next_o_idx = o_ptr->next_o_idx; - - /* Memorized objects */ - if (o_ptr->marked) - { - /* Normal char */ - *cp = object_char(o_ptr); - - /* Normal attr */ - *ap = object_attr(o_ptr); - - /* Multi-hued attr */ - if (!avoid_other && attr_mutable && - (k_info[o_ptr->k_idx].flags5 & TR5_ATTR_MULTI)) - { - *ap = get_shimmer_color(); - } - - /* Hack -- hallucination */ - if (p_ptr->image) image_object(ap, cp); - - /* Done */ - break; - } - } - } - - - /**** Layer 3 -- Handle monsters ****/ - - if (c_ptr->m_idx) - { - monster_type *m_ptr = &m_list[c_ptr->m_idx]; - monster_race *r_ptr = race_inf(m_ptr); - - if (r_ptr->flags9 & RF9_MIMIC) - { - object_type *o_ptr; - - /* Acquire object */ - o_ptr = &o_list[m_ptr->hold_o_idx]; - - /* Memorized objects */ - if (o_ptr->marked) - { - /* Normal char */ - *cp = object_char(o_ptr); - - /* Normal attr */ - *ap = object_attr(o_ptr); - - /* Multi-hued attr */ - if (!avoid_other && attr_mutable && - (k_info[o_ptr->k_idx].flags5 & TR5_ATTR_MULTI)) - { - *ap = get_shimmer_color(); - } - - /* Hack -- hallucination */ - if (p_ptr->image) image_object(ap, cp); - } - } - else - { - /* Visible monster */ - if (m_ptr->ml) - { - monster_race *r_ptr = race_inf(m_ptr); - - /* Reset attr/char */ - *eap = 0; - *ecp = 0; - - if (use_graphics) - { - - if (graf_new) - { - monster_ego *re_ptr = &re_info[m_ptr->ego]; - - /* Desired attr */ - *eap = re_ptr->g_attr; - - /* Desired char */ - *ecp = re_ptr->g_char; - } - - /* Use base monster */ - r_ptr = &r_info[m_ptr->r_idx]; - } - - /* Desired attr/char */ - c = r_ptr->x_char; - a = r_ptr->x_attr; - - /* Ignore weird codes */ - if (avoid_other) - { - /* Use char */ - *cp = c; - - /* Use attr */ - *ap = a; - } - - /* Special attr/char codes */ - else if (!attr_mutable) - { - /* Use char */ - *cp = c; - - /* Use attr */ - *ap = a; - } - - /* Multi-hued monster */ - else if (r_ptr->flags1 & (RF1_ATTR_MULTI)) - { - /* Is it a shapechanger? */ - if (r_ptr->flags2 & (RF2_SHAPECHANGER)) - { - image_random(ap, cp); - } - else - *cp = c; - - /* Multi-hued attr */ - if (r_ptr->flags2 & (RF2_ATTR_ANY)) - { - *ap = randint(15); - } - else - { - *ap = multi_hued_attr(r_ptr); - } - } - - /* Normal monster (not "clear" in any way) */ - else if (!(r_ptr->flags1 & (RF1_ATTR_CLEAR | RF1_CHAR_CLEAR))) - { - /* Use char */ - *cp = c; - - /* Use attr */ - *ap = a; - } - - /* - * Hack -- Bizarre grid under monster - * WAS: else if (*ap & 0x80) || (*cp & 0x80) -- pelpel - */ - else if (*ap & 0x80) - { - /* Use char */ - *cp = c; - - /* Use attr */ - *ap = a; - } - - /* Normal */ - else - { - /* Normal (non-clear char) monster */ - if (!(r_ptr->flags1 & (RF1_CHAR_CLEAR))) - { - /* Normal char */ - *cp = c; - } - - /* Normal (non-clear attr) monster */ - else if (!(r_ptr->flags1 & (RF1_ATTR_CLEAR))) - { - /* Normal attr */ - *ap = a; - } - } - - /* Hack -- hallucination */ - if (p_ptr->image) - { - /* Hallucinatory monster */ - image_monster(ap, cp); - } - } - } - } - - /* Handle "player" */ - if ((y == p_ptr->py) && (x == p_ptr->px) && - (!p_ptr->invis || p_ptr->see_inv)) - { - monster_race *r_ptr = &r_info[p_ptr->body_monster]; - - /* Reset attr/char */ - *eap = 0; - *ecp = 0; - - /* Get the "player" attr */ - if (!avoid_other && attr_mutable && (r_ptr->flags1 & RF1_ATTR_MULTI)) - { - a = get_shimmer_color(); - } - else - { - a = r_ptr->x_attr; - } - - /* Get the "player" char */ - c = r_ptr->x_char; - - - /* Mega-Hack -- Apply modifications to player graphics XXX XXX XXX */ - switch (graphics_mode) - { - case GRAPHICS_NONE: - case GRAPHICS_IBM: - { - if (player_char_health) - { - int percent = p_ptr->chp * 10 / p_ptr->mhp; - - if (percent < 7) - { - c = I2D(percent); - if (percent < 3) a = TERM_L_RED; - } - } - - break; - } - - case GRAPHICS_OLD: - { - if (player_symbols) - { - a = BMP_FIRST_PC_CLASS + p_ptr->pclass; - c = BMP_FIRST_PC_RACE + p_ptr->prace; - } - - break; - } - - case GRAPHICS_ISO: - case GRAPHICS_NEW: - { - if (p_ptr->pracem) - { - player_race_mod *rmp_ptr = &race_mod_info[p_ptr->pracem]; - - /* Desired attr */ - *eap = rmp_ptr->g_attr; - - /* Desired char */ - *ecp = rmp_ptr->g_char; - } - - /* +AKH 20020421 - Health dispay for graphics, too */ - if (player_char_health && (graphics_mode == GRAPHICS_NEW)) - { - int percent = p_ptr->chp * 14 / p_ptr->mhp; - - if (percent < 10) - { - *eap = 10; - *ecp = 32 + 14 - percent; - } - } - - break; - } - - } - - /* Save the info */ - *ap = a; - *cp = c; - - } -} - - -/* - * Special version of map_info, for use by cmovie and HTML converter - * to obtain pure-ASCII image of dungeon map - */ -void map_info_default(int y, int x, byte *ap, char *cp) -{ - cave_type *c_ptr; - - feature_type *f_ptr; - - s16b this_o_idx, next_o_idx = 0; - - u16b info; - - s16b t_idx; - - byte feat; - - byte a; - - byte c; - - bool_ use_graphics_hack = use_graphics; - byte graphics_mode_hack = graphics_mode; - - - /* Temporarily disable graphics mode -- for some random effects XXX */ - use_graphics = FALSE; - graphics_mode = GRAPHICS_NONE; - - /**** Preparation ****/ - - /* Access the grid */ - c_ptr = &cave[y][x]; - - - /* Cache some frequently used values */ - - /* Grid info */ - info = c_ptr->info; - - /* Feature code */ - feat = c_ptr->feat; - - /* Apply "mimic" field */ - if (c_ptr->mimic) - { - feat = c_ptr->mimic; - } - else - { - feat = f_info[feat].mimic; - } - - /* Access floor */ - f_ptr = &f_info[feat]; - - - /**** Layer 1 -- Terrain feature ****/ - - /* Only memorised or visible grids are displayed */ - if (info & (CAVE_MARK | CAVE_SEEN)) - { - /**** Step 1 -- Retrieve base attr/char ****/ - - /* 'Sane' terrain features */ - if (feat != FEAT_SHOP) - { - /* Default char */ - c = f_ptr->d_char; - - /* Default attr */ - a = f_ptr->d_attr; - } - - /* Mega-Hack 1 -- Building don't conform to f_info */ - else - { - c = st_info[c_ptr->special].d_char; - a = st_info[c_ptr->special].d_attr; - } - - /* Mega-Hack 2 -- stair to dungeon branch are purple */ - if (c_ptr->special && - ((feat == FEAT_MORE) || (feat == FEAT_LESS))) - { - a = TERM_VIOLET; - } - - /* Mega-Hack 3 -- Traps don't have f_info entries either */ - if ((info & (CAVE_TRDT)) && (feat != FEAT_ILLUS_WALL)) - { - /* Trap index */ - t_idx = c_ptr->t_idx; - - /* - * If trap is set on a floor grid that is not - * one of "interesting" features, use a special - * symbol to display it. Check for doors is no longer - * necessary because they have REMEMBER flag now. - * - * Cave macros cannot be used safely here, because of - * c_ptr->mimic XXX XXX - */ - if ((f_ptr->flags1 & (FF1_FLOOR | FF1_REMEMBER)) == FF1_FLOOR) - { - c = f_info[FEAT_TRAP].d_char; - } - - /* Add attr */ - a = t_info[t_idx].color; - - /* Get a new color with a strange formula :) */ - if (t_info[t_idx].flags & FTRAP_CHANGE) - { - s32b tmp; - - tmp = dun_level + dungeon_type + feat; - - a = tmp % 16; - } - } - - - /**** Step 2 -- Apply special random effects ****/ - if (!avoid_other) - { - /* Special terrain effect */ - if (c_ptr->effect) - { - a = spell_color(effects[c_ptr->effect].type); - } - - /* Multi-hued attr */ - else if (f_ptr->flags1 & FF1_ATTR_MULTI) - { - a = f_ptr->shimmer[rand_int(7)]; - } - } - - - /* - * Step 3 - * - * Special lighting effects, if specified and applicable - * This will never happen for - * - any grids in the overhead map - * - traps - * - (graphics modes) terrain features without corresponding - * "darker" tiles. - * - * All the if's here are flag checks, so changed order shouldn't - * affect performance a lot, I hope... - */ - - /* view_special_lite: lighting effects for boring features */ - if (view_special_lite && - ((f_ptr->flags1 & (FF1_FLOOR | FF1_REMEMBER)) == FF1_FLOOR)) - { - if (!p_ptr->wild_mode && !(info & (CAVE_TRDT))) - { - /* Handle "seen" grids */ - if (info & (CAVE_SEEN)) - { - /* Only lit by "torch" light */ - if (view_yellow_lite && !(info & (CAVE_GLOW))) - { - /* Use "yellow" */ - a = TERM_YELLOW; - } - } - - /* Handle "blind" */ - else if (p_ptr->blind) - { - /* Use darker colour */ - a = darker_attrs[a & 0xF]; - } - - /* Handle "dark" grids */ - else if (!(info & (CAVE_GLOW))) - { - /* Use darkest colour */ - a = TERM_L_DARK; - } - - /* "Out-of-sight" glowing grids -- handle "view_bright_lite" */ - else if (view_bright_lite) - { - /* Use darker colour */ - a = dark_attrs[a & 0xF]; - } - } - } - - /* view_granite_lite: lighting effects for walls and doors */ - else if (view_granite_lite && - (f_ptr->flags1 & (FF1_NO_VISION | FF1_DOOR))) - { - if (!p_ptr->wild_mode && !(info & (CAVE_TRDT))) - { - /* Handle "seen" grids */ - if (info & (CAVE_SEEN)) - { - /* Do nothing */ - } - - /* Handle "blind" */ - else if (p_ptr->blind) - { - /* Use darker colour */ - a = darker_attrs[a & 0xF]; - } - - /* Handle "view_bright_lite" */ - else if (view_bright_lite) - { - /* Use darker colour */ - a = dark_attrs[a & 0xF]; - } - } - } - } - - /* Unknown grids */ - else - { - /* Access darkness */ - f_ptr = &f_info[FEAT_NONE]; - - /* Default attr */ - a = f_ptr->d_attr; - - /* Default char */ - c = f_ptr->d_char; - } - - /* - * Hack -- rare random hallucination - * Because we cannot be sure which is outer dungeon walls, - * the check for 'feat' has been removed - */ - if (p_ptr->image && (rand_int(256) == 0)) - { - /* Hallucinate */ - image_random(ap, cp); - } - - /* Save the info */ - *ap = a; - *cp = c; - - - /**** Layer 2 -- Objects ****/ - - if (feat != FEAT_MON_TRAP) - { - for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) - { - object_type * o_ptr; - - /* Acquire object */ - o_ptr = &o_list[this_o_idx]; - - /* Acquire next object */ - next_o_idx = o_ptr->next_o_idx; - - /* Memorized objects */ - if (o_ptr->marked) - { - /* Normal char */ - *cp = object_char_default(o_ptr); - - /* Normal attr */ - *ap = object_attr_default(o_ptr); - - /* Multi-hued attr */ - if (!avoid_other && - (k_info[o_ptr->k_idx].flags5 & TR5_ATTR_MULTI)) - { - *ap = get_shimmer_color(); - } - - /* Hack -- hallucination */ - if (p_ptr->image) image_object(ap, cp); - - /* Done */ - break; - } - } - } - - - /**** Layer 3 -- Handle monsters ****/ - - if (c_ptr->m_idx) - { - monster_type *m_ptr = &m_list[c_ptr->m_idx]; - monster_race *r_ptr = race_inf(m_ptr); - - if (r_ptr->flags9 & RF9_MIMIC) - { - object_type *o_ptr; - - /* Acquire object */ - o_ptr = &o_list[m_ptr->hold_o_idx]; - - /* Memorized objects */ - if (o_ptr->marked) - { - /* Normal char */ - *cp = object_char_default(o_ptr); - - /* Normal attr */ - *ap = object_attr_default(o_ptr); - - /* Multi-hued attr */ - if (!avoid_other && !use_graphics && - (k_info[o_ptr->k_idx].flags5 & TR5_ATTR_MULTI)) - { - *ap = get_shimmer_color(); - } - - /* Hack -- hallucination */ - if (p_ptr->image) image_object(ap, cp); - } - } - else - { - /* Visible monster */ - if (m_ptr->ml) - { - monster_race *r_ptr = race_inf(m_ptr); - - /* Default attr/char */ - c = r_ptr->d_char; - a = r_ptr->d_attr; - - /* Ignore weird codes */ - if (avoid_other) - { - /* Use char */ - *cp = c; - - /* Use attr */ - *ap = a; - } - - /* Multi-hued monster */ - else if (r_ptr->flags1 & (RF1_ATTR_MULTI)) - { - /* Is it a shapechanger? */ - if (r_ptr->flags2 & (RF2_SHAPECHANGER)) - { - image_random(ap, cp); - } - else - *cp = c; - - /* Multi-hued attr */ - if (r_ptr->flags2 & (RF2_ATTR_ANY)) - { - *ap = randint(15); - } - else - { - *ap = multi_hued_attr(r_ptr); - } - } - - /* Normal monster (not "clear" in any way) */ - else if (!(r_ptr->flags1 & (RF1_ATTR_CLEAR | RF1_CHAR_CLEAR))) - { - /* Use char */ - *cp = c; - - /* Use attr */ - *ap = a; - } - - /* Hack -- Bizarre grid under monster */ - else if ((*ap & 0x80) || (*cp & 0x80)) - { - /* Use char */ - *cp = c; - - /* Use attr */ - *ap = a; - } - - /* Normal */ - else - { - /* Normal (non-clear char) monster */ - if (!(r_ptr->flags1 & (RF1_CHAR_CLEAR))) - { - /* Normal char */ - *cp = c; - } - - /* Normal (non-clear attr) monster */ - else if (!(r_ptr->flags1 & (RF1_ATTR_CLEAR))) - { - /* Normal attr */ - *ap = a; - } - } - - /* Hack -- hallucination */ - if (p_ptr->image) - { - /* Hallucinatory monster */ - image_monster(ap, cp); - } - } - } - } - - - /* Handle "player" */ - if ((y == p_ptr->py) && (x == p_ptr->px) && - (!p_ptr->invis || - (p_ptr->invis && p_ptr->see_inv))) - { - monster_race *r_ptr = &r_info[p_ptr->body_monster]; - - /* Get the "player" attr */ - if (!avoid_other && (r_ptr->flags1 & RF1_ATTR_MULTI)) - { - a = get_shimmer_color(); - } - else - { - a = r_ptr->d_attr; - } - - /* Get the "player" char */ - c = r_ptr->d_char; - - /* Save the info */ - *ap = a; - *cp = c; - - } - - /* XXX Restore the graphics mode */ - use_graphics = use_graphics_hack; - graphics_mode = graphics_mode_hack; -} - - -/* - * Calculate panel colum of a location in the map - */ -static int panel_col_of(int col) -{ - col -= panel_col_min; - if (use_bigtile) col *= 2; - return col + COL_MAP; -} - - - -/* - * Moves the cursor to a given MAP (y,x) location - */ -void move_cursor_relative(int row, int col) -{ - /* Real co-ords convert to screen positions */ - row -= panel_row_prt; - - /* Go there */ - Term_gotoxy(panel_col_of(col), row); -} - - - -/* - * Place an attr/char pair at the given map coordinate, if legal. - */ -void print_rel(char c, byte a, int y, int x) -{ - /* Paranoia -- Only do "legal" locations */ - if (!panel_contains(y, x)) return; - - /* Draw the char using the attr */ - Term_draw(panel_col_of(x), y - panel_row_prt, a, c); - - if (use_bigtile) - { - char c2; - byte a2; - - if (a & 0x80) - { - a2 = 255; - c2 = 255; - } - else - { - a2 = TERM_WHITE; - c2 = ' '; - } - Term_draw(panel_col_of(x) + 1, y - panel_row_prt, a2, c2); - } -} - - - - - -/* - * Memorize interesting viewable object/features in the given grid - * - * This function should only be called on "legal" grids. - * - * This function will memorize the object and/or feature in the given - * grid, if they are (1) viewable and (2) interesting. Note that all - * objects are interesting, all terrain features except floors (and - * invisible traps) are interesting, and floors (and invisible traps) - * are interesting sometimes (depending on various options involving - * the illumination of floor grids). - * - * The automatic memorization of all objects and non-floor terrain - * features as soon as they are displayed allows incredible amounts - * of optimization in various places, especially "map_info()". - * - * Note that the memorization of objects is completely separate from - * the memorization of terrain features, preventing annoying floor - * memorization when a detected object is picked up from a dark floor, - * and object memorization when an object is dropped into a floor grid - * which is memorized but out-of-sight. - * - * This function should be called every time the "memorization" of - * a grid (or the object in a grid) is called into question, such - * as when an object is created in a grid, when a terrain feature - * "changes" from "floor" to "non-floor", when any grid becomes - * "illuminated" or "viewable", and when a "floor" grid becomes - * "torch-lit". - * - * Note the relatively efficient use of this function by the various - * "update_view()" and "update_lite()" calls, to allow objects and - * terrain features to be memorized (and drawn) whenever they become - * viewable or illuminated in any way, but not when they "maintain" - * or "lose" their previous viewability or illumination. - * - * Note the butchered "internal" version of "player_can_see_bold()", - * optimized primarily for the most common cases, that is, for the - * non-marked floor grids. - */ -void note_spot(int y, int x) -{ - cave_type *c_ptr = &cave[y][x]; - - u16b info = c_ptr->info; - - s16b this_o_idx, next_o_idx = 0; - - - /* Require "seen" flag */ - if (!(info & (CAVE_SEEN))) return; - - - /* Hack -- memorize objects */ - for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) - { - object_type * o_ptr = &o_list[this_o_idx]; - - /* Acquire next object */ - next_o_idx = o_ptr->next_o_idx; - - /* Memorize objects */ - o_ptr->marked = TRUE; - } - - if (c_ptr->m_idx) - { - monster_type *m_ptr = &m_list[c_ptr->m_idx]; - monster_race *r_ptr = race_inf(m_ptr); - - if (r_ptr->flags9 & RF9_MIMIC) - { - object_type *o_ptr = &o_list[m_ptr->hold_o_idx]; - - o_ptr->marked = TRUE; - } - } - - - /* Hack -- memorize grids */ - if (!(info & (CAVE_MARK))) - { - /* Memorise some "boring" grids */ - if (cave_plain_floor_grid(c_ptr)) - { - /* Option -- memorise certain floors */ - if ((info & (CAVE_TRDT)) || - ((info & (CAVE_GLOW)) && view_perma_grids ) || - view_torch_grids) - { - /* Memorize */ - c_ptr->info |= (CAVE_MARK); - } - } - - /* Memorise all "interesting" grids */ - else - { - /* Memorize */ - c_ptr->info |= (CAVE_MARK); - } - } -} - - -/* - * Redraw (on the screen) a given MAP location - * - * This function should only be called on "legal" grids - */ -void lite_spot(int y, int x) -{ - byte a, a2; - byte c, c2; - - byte ta; - char tc; - - byte ea; - char ec; - - - /* Redraw if on screen */ - if (panel_contains(y, x)) - { - /* Examine the grid */ - map_info(y, x, &a, (char*)&c, &ta, &tc, &ea, &ec); - - /* Hack -- Queue it */ - Term_queue_char(panel_col_of(x), y - panel_row_prt, a, c, ta, tc, ea, ec); - if (use_bigtile) - { - if (a & 0x80) - { - a2 = 255; - c2 = 255; - } - else - { - a2 = TERM_WHITE; - c2 = ' '; - } - Term_queue_char(panel_col_of(x) + 1, y - panel_row_prt, a2, c2, 0, 0, 0, 0); - } - - } -} - - - - -/* - * Prints the map of the dungeon - * - * Note that, for efficiency, we contain an "optimized" version - * of both "lite_spot()" and "print_rel()", and that we use the - * "lite_spot()" function to display the player grid, if needed. - */ -void prt_map(void) -{ - int x, y; - - int v; - - /* Access the cursor state */ - (void)Term_get_cursor(&v); - - /* Hide the cursor */ - (void)Term_set_cursor(0); - - /* Dump the map */ - for (y = panel_row_min; y <= panel_row_max; y++) - { - /* Scan the columns of row "y" */ - for (x = panel_col_min; x <= panel_col_max; x++) - { - byte a, a2; - char c, c2; - - byte ta; - char tc; - byte ea; - char ec; - - /* Determine what is there */ - map_info(y, x, &a, &c, &ta, &tc, &ea, &ec); - - /* Efficiency -- Redraw that grid of the map */ - Term_queue_char(panel_col_of(x), y - panel_row_prt, a, c, ta, tc, ea, ec); - if (use_bigtile) - { - if (a & 0x80) - { - a2 = 255; - c2 = 255; - } - else - { - a2 = TERM_WHITE; - c2 = ' '; - } - Term_queue_char(panel_col_of(x) + 1, y - panel_row_prt, a2, c2, 0, 0, 0, 0); - } - } - } - - /* Display player */ - lite_spot(p_ptr->py, p_ptr->px); - - /* Restore the cursor */ - (void)Term_set_cursor(v); -} - - - - - -/* - * Display highest priority object in the RATIO by RATIO area - */ - -/* - * Display the entire map - */ -#define MAP_HGT (MAX_HGT / RATIO) -#define MAP_WID (MAX_WID / RATIO) - -/* - * Hack -- priority array (see below) - * - * Note that all "walls" always look like "secret doors" (see "map_info()"). - */ -static byte priority_table[][2] = -{ - /* Dark */ - { FEAT_NONE, 2 }, - - /* Floors */ - { FEAT_FLOOR, 5 }, - - /* Walls */ - { FEAT_SECRET, 10 }, - - /* Quartz */ - { FEAT_QUARTZ, 11 }, - - /* Magma */ - { FEAT_MAGMA, 12 }, - - /* Rubble */ - { FEAT_RUBBLE, 13 }, - - /* Sandwall */ - { FEAT_SANDWALL, 14 }, - - /* Open doors */ - { FEAT_OPEN, 15 }, - { FEAT_BROKEN, 15 }, - - /* Closed doors */ - { FEAT_DOOR_HEAD + 0x00, 17 }, - - /* Hidden gold */ - { FEAT_QUARTZ_K, 19 }, - { FEAT_MAGMA_K, 19 }, - { FEAT_SANDWALL_K, 19 }, - - /* water, lava, & trees oh my! -KMW- */ - { FEAT_DEEP_WATER, 20 }, - { FEAT_SHAL_WATER, 20 }, - { FEAT_DEEP_LAVA, 20 }, - { FEAT_SHAL_LAVA, 20 }, - { FEAT_DIRT, 20 }, - { FEAT_GRASS, 20 }, - { FEAT_DARK_PIT, 20 }, - { FEAT_TREES, 20 }, - { FEAT_MOUNTAIN, 20 }, - { FEAT_ICE, 20}, - { FEAT_SAND, 20}, - { FEAT_DEAD_TREE, 20}, - { FEAT_ASH, 20}, - { FEAT_MUD, 20}, - - /* Fountain */ - { FEAT_FOUNTAIN, 22 }, - { FEAT_EMPTY_FOUNTAIN, 22 }, - - /* Stairs */ - { FEAT_LESS, 25 }, - { FEAT_MORE, 25 }, - - /* Stairs */ - { FEAT_WAY_LESS, 25 }, - { FEAT_WAY_MORE, 25 }, - - { FEAT_SHAFT_UP, 25 }, - { FEAT_SHAFT_DOWN, 25 }, - - /* End */ - { 0, 0 } -}; - - -/* - * Hack -- a priority function (see below) - */ -static byte priority(byte a, char c) -{ - int i, p0, p1; - - feature_type *f_ptr; - - /* Scan the table */ - for (i = 0; TRUE; i++) - { - /* Priority level */ - p1 = priority_table[i][1]; - - /* End of table */ - if (!p1) break; - - /* Feature index */ - p0 = priority_table[i][0]; - - /* Access the feature */ - f_ptr = &f_info[p0]; - - /* Check character and attribute, accept matches */ - if ((f_ptr->x_char == c) && (f_ptr->x_attr == a)) return (p1); - } - - /* Default */ - return (20); -} - - -/* - * Display a "small-scale" map of the dungeon in the active Term - * - * Note that the "map_info()" function must return fully colorized - * data or this function will not work correctly. - * - * Note that this function must "disable" the special lighting - * effects so that the "priority" function will work. - * - * Note the use of a specialized "priority" function to allow this - * function to work with any graphic attr/char mappings, and the - * attempts to optimize this function where possible. - */ -void display_map(int *cy, int *cx) -{ - int i, j, x, y; - - byte ta; - char tc; - - byte tp; - - byte **ma; - char **mc; - - byte **mp; - - bool_ old_view_special_lite; - bool_ old_view_granite_lite; - - int hgt, wid, yrat, xrat, yfactor, xfactor; - - - /* Obtain current size of the Angband window */ - Term_get_size(&wid, &hgt); - - /* Use two characters as one tile in Bigtile mode */ - if (use_bigtile) wid /= 2; - - /* - * Calculate the size of the dungeon map area - */ - hgt -= ROW_MAP + 2; - wid -= COL_MAP + 1; - - /* Paranoia */ - if ((hgt < 3) || (wid < 3)) - { - /* Map is too small, but place the player anyway */ - *cy = ROW_MAP; - *cx = COL_MAP; - - return; - } - - - /* Save lighting effects */ - old_view_special_lite = view_special_lite; - old_view_granite_lite = view_granite_lite; - - /* Disable lighting effects */ - view_special_lite = FALSE; - view_granite_lite = FALSE; - - - /* Allocate temporary memory for the maps */ - C_MAKE(ma, hgt + 2, byte *); - C_MAKE(mc, hgt + 2, char *); - C_MAKE(mp, hgt + 2, byte *); - - /* Allocate each line in the maps */ - for (i = 0; i < hgt + 2; i++) - { - C_MAKE(ma[i], wid + 2, byte); - C_MAKE(mc[i], wid + 2, char); - C_MAKE(mp[i], wid + 2, byte); - } - - /* Clear the chars and attributes */ - for (y = 0; y < hgt + 2; ++y) - { - for (x = 0; x < wid + 2; ++x) - { - /* Nothing here */ - ma[y][x] = TERM_WHITE; - mc[y][x] = ' '; - - /* No priority */ - mp[y][x] = 0; - } - } - - /* Calculate scaling factors */ - yfactor = ((cur_hgt / hgt < 4) && (cur_hgt > hgt)) ? 10 : 1; - xfactor = ((cur_wid / wid < 4) && (cur_wid > wid)) ? 10 : 1; - - yrat = (cur_hgt * yfactor + (hgt - 1)) / hgt; - xrat = (cur_wid * xfactor + (wid - 1)) / wid; - - /* Fill in the map */ - for (j = 0; j < cur_hgt; ++j) - { - for (i = 0; i < cur_wid; ++i) - { - /* Location */ - y = j * yfactor / yrat + 1; - x = i * xfactor / xrat + 1; - - /* Extract the current attr/char at that map location */ - map_info(j, i, &ta, &tc, &ta, &tc, &ta, &tc); - - /* Extract the priority of that attr/char */ - tp = priority(ta, tc); - - /* Player location has the highest priority */ - if ((p_ptr->py == j) && (p_ptr->px == i)) tp = 255; - - /* Save "best" */ - if (mp[y][x] < tp) - { - /* Save the char */ - mc[y][x] = tc; - - /* Save the attr */ - ma[y][x] = ta; - - /* Save priority */ - mp[y][x] = tp; - } - } - } - - - /* Corners */ - y = hgt + 1; - x = wid + 1; - - /* Draw the corners */ - mc[0][0] = mc[0][x] = mc[y][0] = mc[y][x] = '+'; - - /* Draw the horizontal edges */ - for (x = 1; x <= wid; x++) mc[0][x] = mc[y][x] = '-'; - - /* Draw the vertical edges */ - for (y = 1; y <= hgt; y++) mc[y][0] = mc[y][x] = '|'; - - - /* Display each map line in order */ - for (y = 0; y < hgt + 2; ++y) - { - /* Start a new line */ - Term_gotoxy(COL_MAP - 1, y); - - /* Display the line */ - for (x = 0; x < wid + 2; ++x) - { - ta = ma[y][x]; - tc = mc[y][x]; - - /* Add the character */ - Term_addch(ta, tc); - - /* Double width tile mode requires filler */ - if (use_bigtile) - { - byte a2; - char c2; - - if (ta & 0x80) - { - /* Mega-Hack */ - a2 = 255; - c2 = 255; - } - else - { - a2 = TERM_WHITE; - c2 = ' '; - } - - Term_addch(a2, c2); - } - } - } - - /* Player location in dungeon */ - *cy = p_ptr->py * yfactor / yrat + ROW_MAP; - if (!use_bigtile) - { - *cx = p_ptr->px * xfactor / xrat + COL_MAP; - } - else - { - *cx = (p_ptr->px * xfactor / xrat + 1) * 2 - 1 + COL_MAP; - } - - /* Free each line in the maps */ - for (i = 0; i < hgt + 2; i++) - { - C_FREE(ma[i], wid + 2, byte); - C_FREE(mc[i], wid + 2, char); - C_FREE(mp[i], wid + 2, byte); - } - - /* Allocate temporary memory for the maps */ - C_FREE(ma, hgt + 2, byte *); - C_FREE(mc, hgt + 2, char *); - C_FREE(mp, hgt + 2, byte *); - - - /* Restore lighting effects */ - view_special_lite = old_view_special_lite; - view_granite_lite = old_view_granite_lite; -} - - -/* - * Display a "small-scale" map of the dungeon for the player - * - * Currently, the "player" is displayed on the map. XXX XXX XXX - */ -void do_cmd_view_map(void) -{ - int cy, cx; - int wid, hgt; - - /* Retrive current screen size */ - Term_get_size(&wid, &hgt); - - /* Enter "icky" mode */ - character_icky = TRUE; - - /* Save the screen */ - Term_save(); - - /* Note */ - prt("Please wait...", 0, 0); - - /* Flush */ - Term_fresh(); - - /* Clear the screen */ - Term_clear(); - - /* Display the map */ - display_map(&cy, &cx); - - /* Wait for it */ - put_str("Hit any key to continue", hgt - 1, (wid - COL_MAP) / 2); - - /* Hilite the player */ - move_cursor(cy, cx); - - /* Get any key */ - inkey(); - - /* Restore the screen */ - Term_load(); - - /* Leave "icky" mode */ - character_icky = FALSE; -} - - - - - - -/* - * Some comments on the dungeon related data structures and functions... - * - * Angband is primarily a dungeon exploration game, and it should come as - * no surprise that the internal representation of the dungeon has evolved - * over time in much the same way as the game itself, to provide semantic - * changes to the game itself, to make the code simpler to understand, and - * to make the executable itself faster or more efficient in various ways. - * - * There are a variety of dungeon related data structures, and associated - * functions, which store information about the dungeon, and provide methods - * by which this information can be accessed or modified. - * - * Some of this information applies to the dungeon as a whole, such as the - * list of unique monsters which are still alive. Some of this information - * only applies to the current dungeon level, such as the current depth, or - * the list of monsters currently inhabiting the level. And some of the - * information only applies to a single grid of the current dungeon level, - * such as whether the grid is illuminated, or whether the grid contains a - * monster, or whether the grid can be seen by the player. If Angband was - * to be turned into a multi-player game, some of the information currently - * associated with the dungeon should really be associated with the player, - * such as whether a given grid is viewable by a given player. - * - * One of the major bottlenecks in ancient versions of Angband was in the - * calculation of "line of sight" from the player to various grids, such - * as those containing monsters, using the relatively expensive "los()" - * function. This was such a nasty bottleneck that a lot of silly things - * were done to reduce the dependancy on "line of sight", for example, you - * could not "see" any grids in a lit room until you actually entered the - * room, at which point every grid in the room became "illuminated" and - * all of the grids in the room were "memorized" forever. Other major - * bottlenecks involved the determination of whether a grid was lit by the - * player's torch, and whether a grid blocked the player's line of sight. - * These bottlenecks led to the development of special new functions to - * optimize issues involved with "line of sight" and "torch lit grids". - * These optimizations led to entirely new additions to the game, such as - * the ability to display the player's entire field of view using different - * colors than were used for the "memorized" portions of the dungeon, and - * the ability to memorize dark floor grids, but to indicate by the way in - * which they are displayed that they are not actually illuminated. And - * of course many of them simply made the game itself faster or more fun. - * Also, over time, the definition of "line of sight" has been relaxed to - * allow the player to see a wider "field of view", which is slightly more - * realistic, and only slightly more expensive to maintain. - * - * Currently, a lot of the information about the dungeon is stored in ways - * that make it very efficient to access or modify the information, while - * still attempting to be relatively conservative about memory usage, even - * if this means that some information is stored in multiple places, or in - * ways which require the use of special code idioms. For example, each - * monster record in the monster array contains the location of the monster, - * and each cave grid has an index into the monster array, or a zero if no - * monster is in the grid. This allows the monster code to efficiently see - * where the monster is located, while allowing the dungeon code to quickly - * determine not only if a monster is present in a given grid, but also to - * find out which monster. The extra space used to store the information - * twice is inconsequential compared to the speed increase. - * - * Some of the information about the dungeon is used by functions which can - * constitute the "critical efficiency path" of the game itself, and so the - * way in which they are stored and accessed has been optimized in order to - * optimize the game itself. For example, the "update_view()" function was - * originally created to speed up the game itself (when the player was not - * running), but then it took on extra responsibility as the provider of the - * new "special effects lighting code", and became one of the most important - * bottlenecks when the player was running. So many rounds of optimization - * were performed on both the function itself, and the data structures which - * it uses, resulting eventually in a function which not only made the game - * faster than before, but which was responsible for even more calculations - * (including the determination of which grids are "viewable" by the player, - * which grids are illuminated by the player's torch, and which grids can be - * "seen" in some way by the player), as well as for providing the guts of - * the special effects lighting code, and for the efficient redisplay of any - * grids whose visual representation may have changed. - * - * Several pieces of information about each cave grid are stored in various - * two dimensional arrays, with one unit of information for each grid in the - * dungeon. Some of these arrays have been intentionally expanded by a small - * factor to make the two dimensional array accesses faster by allowing the - * use of shifting instead of multiplication. - * - * Several pieces of information about each cave grid are stored in the - * "cave_info" array, which is a special two dimensional array of bytes, - * one for each cave grid, each containing eight separate "flags" which - * describe some property of the cave grid. These flags can be checked and - * modified extremely quickly, especially when special idioms are used to - * force the compiler to keep a local register pointing to the base of the - * array. Special location offset macros can be used to minimize the number - * of computations which must be performed at runtime. Note that using a - * byte for each flag set may be slightly more efficient than using a larger - * unit, so if another flag (or two) is needed later, and it must be fast, - * then the two existing flags which do not have to be fast should be moved - * out into some other data structure and the new flags should take their - * place. This may require a few minor changes in the savefile code. - * - * The "CAVE_ROOM" flag is saved in the savefile and is used to determine - * which grids are part of "rooms", and thus which grids are affected by - * "illumination" spells. This flag does not have to be very fast. - * - * The "CAVE_ICKY" flag is saved in the savefile and is used to determine - * which grids are part of "vaults", and thus which grids cannot serve as - * the destinations of player teleportation. This flag does not have to - * be very fast. - * - * The "CAVE_MARK" flag is saved in the savefile and is used to determine - * which grids have been "memorized" by the player. This flag is used by - * the "map_info()" function to determine if a grid should be displayed. - * This flag is used in a few other places to determine if the player can - * "know" about a given grid. This flag must be very fast. - * - * The "CAVE_GLOW" flag is saved in the savefile and is used to determine - * which grids are "permanently illuminated". This flag is used by the - * "update_view()" function to help determine which viewable flags may - * be "seen" by the player. This flag is used by the "map_info" function - * to determine if a grid is only lit by the player's torch. This flag - * has special semantics for wall grids (see "update_view()"). This flag - * must be very fast. - * - * The "CAVE_WALL" flag is used to determine which grids block the player's - * line of sight. This flag is used by the "update_view()" function to - * determine which grids block line of sight, and to help determine which - * grids can be "seen" by the player. This flag must be very fast. - * - * The "CAVE_VIEW" flag is used to determine which grids are currently in - * line of sight of the player. This flag is set by (and used by) the - * "update_view()" function. This flag is used by any code which needs to - * know if the player can "view" a given grid. This flag is used by the - * "map_info()" function for some optional special lighting effects. The - * "player_has_los_bold()" macro wraps an abstraction around this flag, but - * certain code idioms are much more efficient. This flag is used to check - * if a modification to a terrain feature might affect the player's field of - * view. This flag is used to see if certain monsters are "visible" to the - * player. This flag is used to allow any monster in the player's field of - * view to "sense" the presence of the player. This flag must be very fast. - * - * The "CAVE_SEEN" flag is used to determine which grids are currently in - * line of sight of the player and also illuminated in some way. This flag - * is set by the "update_view()" function, using computations based on the - * "CAVE_VIEW" and "CAVE_WALL" and "CAVE_GLOW" flags of various grids. This - * flag is used by any code which needs to know if the player can "see" a - * given grid. This flag is used by the "map_info()" function both to see - * if a given "boring" grid can be seen by the player, and for some optional - * special lighting effects. The "player_can_see_bold()" macro wraps an - * abstraction around this flag, but certain code idioms are much more - * efficient. This flag is used to see if certain monsters are "visible" to - * the player. This flag is never set for a grid unless "CAVE_VIEW" is also - * set for the grid. Whenever the "CAVE_WALL" or "CAVE_GLOW" flag changes - * for a grid which has the "CAVE_VIEW" flag set, the "CAVE_SEEN" flag must - * be recalculated. The simplest way to do this is to call "forget_view()" - * and "update_view()" whenever the "CAVE_WALL" or "CAVE_GLOW" flags change - * for a grid which has "CAVE_VIEW" set. This flag must be very fast. - * - * The "CAVE_TEMP" flag is used for a variety of temporary purposes. This - * flag is used to determine if the "CAVE_SEEN" flag for a grid has changed - * during the "update_view()" function. This flag is used to "spread" light - * or darkness through a room. This flag is used by the "monster flow code". - * This flag must always be cleared by any code which sets it, often, this - * can be optimized by the use of the special "temp_g", "temp_y", "temp_x" - * arrays (and the special "temp_n" global). This flag must be very fast. - * - * Note that the "CAVE_MARK" flag is used for many reasons, some of which - * are strictly for optimization purposes. The "CAVE_MARK" flag means that - * even if the player cannot "see" the grid, he "knows" about the terrain in - * that grid. This is used to "memorize" grids when they are first "seen" by - * the player, and to allow certain grids to be "detected" by certain magic. - * Note that most grids are always memorized when they are first "seen", but - * "boring" grids (floor grids) are only memorized if the "view_torch_grids" - * option is set, or if the "view_perma_grids" option is set, and the grid - * in question has the "CAVE_GLOW" flag set. - * - * Objects are "memorized" in a different way, using a special "marked" flag - * on the object itself, which is set when an object is observed or detected. - * This allows objects to be "memorized" independant of the terrain features. - * - * The "update_view()" function is an extremely important function. It is - * called only when the player moves, significant terrain changes, or the - * player's blindness or torch radius changes. Note that when the player - * is resting, or performing any repeated actions (like digging, disarming, - * farming, etc), there is no need to call the "update_view()" function, so - * even if it was not very efficient, this would really only matter when the - * player was "running" through the dungeon. It sets the "CAVE_VIEW" flag - * on every cave grid in the player's field of view, and maintains an array - * of all such grids in the global "view_g" array. It also checks the torch - * radius of the player, and sets the "CAVE_SEEN" flag for every grid which - * is in the "field of view" of the player and which is also "illuminated", - * either by the players torch (if any) or by any permanent light source. - * It could use and help maintain information about multiple light sources, - * which would be helpful in a multi-player version of Angband. - * - * The "update_view()" function maintains the special "view_g" array, which - * contains exactly those grids which have the "CAVE_VIEW" flag set. This - * array is used by "update_view()" to (only) memorize grids which become - * newly "seen", and to (only) redraw grids whose "seen" value changes, which - * allows the use of some interesting (and very efficient) "special lighting - * effects". In addition, this array could be used elsewhere to quickly scan - * through all the grids which are in the player's field of view. - * - * Note that the "update_view()" function allows, among other things, a room - * to be "partially" seen as the player approaches it, with a growing cone - * of floor appearing as the player gets closer to the door. Also, by not - * turning on the "memorize perma-lit grids" option, the player will only - * "see" those floor grids which are actually in line of sight. And best - * of all, you can now activate the special lighting effects to indicate - * which grids are actually in the player's field of view by using dimmer - * colors for grids which are not in the player's field of view, and/or to - * indicate which grids are illuminated only by the player's torch by using - * the color yellow for those grids. - * - * The old "update_view()" algorithm uses the special "CAVE_EASY" flag as a - * temporary internal flag to mark those grids which are not only in view, - * but which are also "easily" in line of sight of the player. This flag - * is actually just the "CAVE_SEEN" flag, and the "update_view()" function - * makes sure to clear it for all old "CAVE_SEEN" grids, and then use it in - * the algorithm as "CAVE_EASY", and then clear it for all "CAVE_EASY" grids, - * and then reset it as appropriate for all new "CAVE_SEEN" grids. This is - * kind of messy, but it works. The old algorithm may disappear eventually. - * - * The new "update_view()" algorithm uses a faster and more mathematically - * correct algorithm, assisted by a large machine generated static array, to - * determine the "CAVE_VIEW" and "CAVE_SEEN" flags simultaneously. See below. - * - * It seems as though slight modifications to the "update_view()" functions - * would allow us to determine "reverse" line-of-sight as well as "normal" - * line-of-sight", which would allow monsters to have a more "correct" way - * to determine if they can "see" the player, since right now, they "cheat" - * somewhat and assume that if the player has "line of sight" to them, then - * they can "pretend" that they have "line of sight" to the player. But if - * such a change was attempted, the monsters would actually start to exhibit - * some undesirable behavior, such as "freezing" near the entrances to long - * hallways containing the player, and code would have to be added to make - * the monsters move around even if the player was not detectable, and to - * "remember" where the player was last seen, to avoid looking stupid. - * - * Note that the "CAVE_GLOW" flag means that a grid is permanently lit in - * some way. However, for the player to "see" the grid, as determined by - * the "CAVE_SEEN" flag, the player must not be blind, the grid must have - * the "CAVE_VIEW" flag set, and if the grid is a "wall" grid, and it is - * not lit by the player's torch, then it must touch a grid which does not - * have the "CAVE_WALL" flag set, but which does have both the "CAVE_GLOW" - * and "CAVE_VIEW" flags set. This last part about wall grids is induced - * by the semantics of "CAVE_GLOW" as applied to wall grids, and checking - * the technical requirements can be very expensive, especially since the - * grid may be touching some "illegal" grids. Luckily, it is more or less - * correct to restrict the "touching" grids from the eight "possible" grids - * to the (at most) three grids which are touching the grid, and which are - * closer to the player than the grid itself, which eliminates more than - * half of the work, including all of the potentially "illegal" grids, if - * at most one of the three grids is a "diagonal" grid. In addition, in - * almost every situation, it is possible to ignore the "CAVE_VIEW" flag - * on these three "touching" grids, for a variety of technical reasons. - * Finally, note that in most situations, it is only necessary to check - * a single "touching" grid, in fact, the grid which is strictly closest - * to the player of all the touching grids, and in fact, it is normally - * only necessary to check the "CAVE_GLOW" flag of that grid, again, for - * various technical reasons. However, one of the situations which does - * not work with this last reduction is the very common one in which the - * player approaches an illuminated room from a dark hallway, in which the - * two wall grids which form the "entrance" to the room would not be marked - * as "CAVE_SEEN", since of the three "touching" grids nearer to the player - * than each wall grid, only the farthest of these grids is itself marked - * "CAVE_GLOW". - * - * - * Here are some pictures of the legal "light source" radius values, in - * which the numbers indicate the "order" in which the grids could have - * been calculated, if desired. Note that the code will work with larger - * radiuses, though currently yields such a radius, and the game would - * become slower in some situations if it did. - * - * Rad=0 Rad=1 Rad=2 Rad=3 - * No-Lite Torch,etc Lantern Artifacts - * - * 333 - * 333 43334 - * 212 32123 3321233 - * @ 1@1 31@13 331@133 - * 212 32123 3321233 - * 333 43334 - * 333 - * - * - * Here is an illustration of the two different "update_view()" algorithms, - * in which the grids marked "%" are pillars, and the grids marked "?" are - * not in line of sight of the player. - * - * - * Sample situation - * - * ##################### - * ############.%.%.%.%# - * #...@..#####........# - * #............%.%.%.%# - * #......#####........# - * ############........# - * ##################### - * - * - * New Algorithm Old Algorithm - * - * ########????????????? ########????????????? - * #...@..#????????????? #...@..#????????????? - * #...........????????? #.........??????????? - * #......#####.....???? #......####?????????? - * ########?????????...# ########????????????? - * - * ########????????????? ########????????????? - * #.@....#????????????? #.@....#????????????? - * #............%??????? #...........????????? - * #......#####........? #......#####????????? - * ########??????????..# ########????????????? - * - * ########????????????? ########?????%??????? - * #......#####........# #......#####..??????? - * #.@..........%??????? #.@..........%??????? - * #......#####........# #......#####..??????? - * ########????????????? ########????????????? - * - * ########??????????..# ########????????????? - * #......#####........? #......#####????????? - * #............%??????? #...........????????? - * #.@....#????????????? #.@....#????????????? - * ########????????????? ########????????????? - * - * ########?????????%??? ########????????????? - * #......#####.....???? #......####?????????? - * #...........????????? #.........??????????? - * #...@..#????????????? #...@..#????????????? - * ########????????????? ########????????????? - */ - - - - -/* - * Maximum number of grids in a single octant - */ -#define VINFO_MAX_GRIDS 161 - - -/* - * Maximum number of slopes in a single octant - */ -#define VINFO_MAX_SLOPES 126 - - -/* - * Mask of bits used in a single octant - */ -#define VINFO_BITS_3 0x3FFFFFFF -#define VINFO_BITS_2 0xFFFFFFFF -#define VINFO_BITS_1 0xFFFFFFFF -#define VINFO_BITS_0 0xFFFFFFFF - - -/* - * Forward declare - */ -typedef struct vinfo_type vinfo_type; - - -/* - * The 'vinfo_type' structure - */ -struct vinfo_type -{ - s16b grid_y[8]; - s16b grid_x[8]; - - u32b bits_3; - u32b bits_2; - u32b bits_1; - u32b bits_0; - - vinfo_type *next_0; - vinfo_type *next_1; - - byte y; - byte x; - byte d; - byte r; -}; - - - -/* - * The array of "vinfo" objects, initialized by "vinfo_init()" - */ -static vinfo_type vinfo[VINFO_MAX_GRIDS]; - - - - -/* - * Slope scale factor - */ -#define SCALE 100000L - - -/* - * The actual slopes (for reference) - */ - -/* Bit : Slope Grids */ -/* --- : ----- ----- */ -/* 0 : 2439 21 */ -/* 1 : 2564 21 */ -/* 2 : 2702 21 */ -/* 3 : 2857 21 */ -/* 4 : 3030 21 */ -/* 5 : 3225 21 */ -/* 6 : 3448 21 */ -/* 7 : 3703 21 */ -/* 8 : 4000 21 */ -/* 9 : 4347 21 */ -/* 10 : 4761 21 */ -/* 11 : 5263 21 */ -/* 12 : 5882 21 */ -/* 13 : 6666 21 */ -/* 14 : 7317 22 */ -/* 15 : 7692 20 */ -/* 16 : 8108 21 */ -/* 17 : 8571 21 */ -/* 18 : 9090 20 */ -/* 19 : 9677 21 */ -/* 20 : 10344 21 */ -/* 21 : 11111 20 */ -/* 22 : 12000 21 */ -/* 23 : 12820 22 */ -/* 24 : 13043 22 */ -/* 25 : 13513 22 */ -/* 26 : 14285 20 */ -/* 27 : 15151 22 */ -/* 28 : 15789 22 */ -/* 29 : 16129 22 */ -/* 30 : 17241 22 */ -/* 31 : 17647 22 */ -/* 32 : 17948 23 */ -/* 33 : 18518 22 */ -/* 34 : 18918 22 */ -/* 35 : 20000 19 */ -/* 36 : 21212 22 */ -/* 37 : 21739 22 */ -/* 38 : 22580 22 */ -/* 39 : 23076 22 */ -/* 40 : 23809 22 */ -/* 41 : 24137 22 */ -/* 42 : 24324 23 */ -/* 43 : 25714 23 */ -/* 44 : 25925 23 */ -/* 45 : 26315 23 */ -/* 46 : 27272 22 */ -/* 47 : 28000 23 */ -/* 48 : 29032 23 */ -/* 49 : 29411 23 */ -/* 50 : 29729 24 */ -/* 51 : 30434 23 */ -/* 52 : 31034 23 */ -/* 53 : 31428 23 */ -/* 54 : 33333 18 */ -/* 55 : 35483 23 */ -/* 56 : 36000 23 */ -/* 57 : 36842 23 */ -/* 58 : 37142 24 */ -/* 59 : 37931 24 */ -/* 60 : 38461 24 */ -/* 61 : 39130 24 */ -/* 62 : 39393 24 */ -/* 63 : 40740 24 */ -/* 64 : 41176 24 */ -/* 65 : 41935 24 */ -/* 66 : 42857 23 */ -/* 67 : 44000 24 */ -/* 68 : 44827 24 */ -/* 69 : 45454 23 */ -/* 70 : 46666 24 */ -/* 71 : 47368 24 */ -/* 72 : 47826 24 */ -/* 73 : 48148 24 */ -/* 74 : 48387 24 */ -/* 75 : 51515 25 */ -/* 76 : 51724 25 */ -/* 77 : 52000 25 */ -/* 78 : 52380 25 */ -/* 79 : 52941 25 */ -/* 80 : 53846 25 */ -/* 81 : 54838 25 */ -/* 82 : 55555 24 */ -/* 83 : 56521 25 */ -/* 84 : 57575 26 */ -/* 85 : 57894 25 */ -/* 86 : 58620 25 */ -/* 87 : 60000 23 */ -/* 88 : 61290 25 */ -/* 89 : 61904 25 */ -/* 90 : 62962 25 */ -/* 91 : 63636 25 */ -/* 92 : 64705 25 */ -/* 93 : 65217 25 */ -/* 94 : 65517 25 */ -/* 95 : 67741 26 */ -/* 96 : 68000 26 */ -/* 97 : 68421 26 */ -/* 98 : 69230 26 */ -/* 99 : 70370 26 */ -/* 100 : 71428 25 */ -/* 101 : 72413 26 */ -/* 102 : 73333 26 */ -/* 103 : 73913 26 */ -/* 104 : 74193 27 */ -/* 105 : 76000 26 */ -/* 106 : 76470 26 */ -/* 107 : 77777 25 */ -/* 108 : 78947 26 */ -/* 109 : 79310 26 */ -/* 110 : 80952 26 */ -/* 111 : 81818 26 */ -/* 112 : 82608 26 */ -/* 113 : 84000 26 */ -/* 114 : 84615 26 */ -/* 115 : 85185 26 */ -/* 116 : 86206 27 */ -/* 117 : 86666 27 */ -/* 118 : 88235 27 */ -/* 119 : 89473 27 */ -/* 120 : 90476 27 */ -/* 121 : 91304 27 */ -/* 122 : 92000 27 */ -/* 123 : 92592 27 */ -/* 124 : 93103 28 */ -/* 125 : 100000 13 */ - - - -/* - * Forward declare - */ -typedef struct vinfo_hack vinfo_hack; - - -/* - * Temporary data used by "vinfo_init()" - * - * - Number of grids - * - * - Number of slopes - * - * - Slope values - * - * - Slope range per grid - */ -struct vinfo_hack -{ - - int num_slopes; - - long slopes[VINFO_MAX_SLOPES]; - - long slopes_min[MAX_SIGHT + 1][MAX_SIGHT + 1]; - long slopes_max[MAX_SIGHT + 1][MAX_SIGHT + 1]; -}; - - - -/* - * Sorting hook -- comp function -- array of long's (see below) - * - * We use "u" to point to an array of long integers. - */ -static bool_ ang_sort_comp_hook_longs(vptr u, vptr v, int a, int b) -{ - long *x = (long*)(u); - - return (x[a] <= x[b]); -} - - -/* - * Sorting hook -- comp function -- array of long's (see below) - * - * We use "u" to point to an array of long integers. - */ -static void ang_sort_swap_hook_longs(vptr u, vptr v, int a, int b) -{ - long *x = (long*)(u); - - long temp; - - /* Swap */ - temp = x[a]; - x[a] = x[b]; - x[b] = temp; -} - - - -/* - * Save a slope - */ -static void vinfo_init_aux(vinfo_hack *hack, int y, int x, long m) -{ - int i; - - /* Handle "legal" slopes */ - if ((m > 0) && (m <= SCALE)) - { - /* Look for that slope */ - for (i = 0; i < hack->num_slopes; i++) - { - if (hack->slopes[i] == m) break; - } - - /* New slope */ - if (i == hack->num_slopes) - { - /* Paranoia */ - if (hack->num_slopes >= VINFO_MAX_SLOPES) - { - quit_fmt("Too many slopes (%d)!", - VINFO_MAX_SLOPES); - } - - /* Save the slope, and advance */ - hack->slopes[hack->num_slopes++] = m; - } - } - - /* Track slope range */ - if (hack->slopes_min[y][x] > m) hack->slopes_min[y][x] = m; - if (hack->slopes_max[y][x] < m) hack->slopes_max[y][x] = m; -} - - - -/* - * Initialize the "vinfo" array - * - * Full Octagon (radius 20), Grids=1149 - * - * Quadrant (south east), Grids=308, Slopes=251 - * - * Octant (east then south), Grids=161, Slopes=126 - * - * This function assumes that VINFO_MAX_GRIDS and VINFO_MAX_SLOPES - * have the correct values, which can be derived by setting them to - * a number which is too high, running this function, and using the - * error messages to obtain the correct values. - */ -errr vinfo_init(void) -{ - int i, y, x; - - long m; - - vinfo_hack *hack; - - int num_grids = 0; - - int queue_head = 0; - int queue_tail = 0; - vinfo_type *queue[VINFO_MAX_GRIDS*2]; - - - /* Make hack */ - MAKE(hack, vinfo_hack); - - - /* Analyze grids */ - for (y = 0; y <= MAX_SIGHT; ++y) - { - for (x = y; x <= MAX_SIGHT; ++x) - { - /* Skip grids which are out of sight range */ - if (distance(0, 0, y, x) > MAX_SIGHT) continue; - - /* Default slope range */ - hack->slopes_min[y][x] = 999999999; - hack->slopes_max[y][x] = 0; - - /* Paranoia */ - if (num_grids >= VINFO_MAX_GRIDS) - { - quit_fmt("Too many grids (%d >= %d)!", - num_grids, VINFO_MAX_GRIDS); - } - - /* Count grids */ - num_grids++; - - /* Slope to the top right corner */ - m = SCALE * (1000L * y - 500) / (1000L * x + 500); - - /* Handle "legal" slopes */ - vinfo_init_aux(hack, y, x, m); - - /* Slope to top left corner */ - m = SCALE * (1000L * y - 500) / (1000L * x - 500); - - /* Handle "legal" slopes */ - vinfo_init_aux(hack, y, x, m); - - /* Slope to bottom right corner */ - m = SCALE * (1000L * y + 500) / (1000L * x + 500); - - /* Handle "legal" slopes */ - vinfo_init_aux(hack, y, x, m); - - /* Slope to bottom left corner */ - m = SCALE * (1000L * y + 500) / (1000L * x - 500); - - /* Handle "legal" slopes */ - vinfo_init_aux(hack, y, x, m); - } - } - - - /* Enforce maximal efficiency */ - if (num_grids < VINFO_MAX_GRIDS) - { - quit_fmt("Too few grids (%d < %d)!", - num_grids, VINFO_MAX_GRIDS); - } - - /* Enforce maximal efficiency */ - if (hack->num_slopes < VINFO_MAX_SLOPES) - { - quit_fmt("Too few slopes (%d < %d)!", - hack->num_slopes, VINFO_MAX_SLOPES); - } - - - /* Sort slopes numerically */ - ang_sort_comp = ang_sort_comp_hook_longs; - - /* Sort slopes numerically */ - ang_sort_swap = ang_sort_swap_hook_longs; - - /* Sort the (unique) slopes */ - ang_sort(hack->slopes, NULL, hack->num_slopes); - - - - /* Enqueue player grid */ - queue[queue_tail++] = &vinfo[0]; - - /* Process queue */ - while (queue_head < queue_tail) - { - int e; - - /* Index */ - e = queue_head; - - /* Dequeue next grid */ - queue_head++; - - /* Location of main grid */ - y = vinfo[e].grid_y[0]; - x = vinfo[e].grid_x[0]; - - - /* Compute grid offsets */ - vinfo[e].grid_y[0] = + y; - vinfo[e].grid_x[0] = + x; - vinfo[e].grid_y[1] = + x; - vinfo[e].grid_x[1] = + y; - vinfo[e].grid_y[2] = + x; - vinfo[e].grid_x[2] = -y; - vinfo[e].grid_y[3] = + y; - vinfo[e].grid_x[3] = -x; - vinfo[e].grid_y[4] = -y; - vinfo[e].grid_x[4] = -x; - vinfo[e].grid_y[5] = -x; - vinfo[e].grid_x[5] = -y; - vinfo[e].grid_y[6] = -x; - vinfo[e].grid_x[6] = + y; - vinfo[e].grid_y[7] = -y; - vinfo[e].grid_x[7] = + x; - - - /* Analyze slopes */ - for (i = 0; i < hack->num_slopes; ++i) - { - m = hack->slopes[i]; - - /* Memorize intersection slopes (for non-player-grids) */ - if ((e > 0) && - (hack->slopes_min[y][x] < m) && - (m < hack->slopes_max[y][x])) - { - switch (i / 32) - { - case 3: - vinfo[e].bits_3 |= (1L << (i % 32)); - break; - case 2: - vinfo[e].bits_2 |= (1L << (i % 32)); - break; - case 1: - vinfo[e].bits_1 |= (1L << (i % 32)); - break; - case 0: - vinfo[e].bits_0 |= (1L << (i % 32)); - break; - } - } - } - - - /* Default */ - vinfo[e].next_0 = &vinfo[0]; - - /* Grid next child */ - if (distance(0, 0, y, x + 1) <= MAX_SIGHT) - { - if ((queue[queue_tail - 1]->grid_y[0] != y) || - (queue[queue_tail - 1]->grid_x[0] != x + 1)) - { - vinfo[queue_tail].grid_y[0] = y; - vinfo[queue_tail].grid_x[0] = x + 1; - queue[queue_tail] = &vinfo[queue_tail]; - queue_tail++; - } - - vinfo[e].next_0 = &vinfo[queue_tail - 1]; - } - - - /* Default */ - vinfo[e].next_1 = &vinfo[0]; - - /* Grid diag child */ - if (distance(0, 0, y + 1, x + 1) <= MAX_SIGHT) - { - if ((queue[queue_tail - 1]->grid_y[0] != y + 1) || - (queue[queue_tail - 1]->grid_x[0] != x + 1)) - { - vinfo[queue_tail].grid_y[0] = y + 1; - vinfo[queue_tail].grid_x[0] = x + 1; - queue[queue_tail] = &vinfo[queue_tail]; - queue_tail++; - } - - vinfo[e].next_1 = &vinfo[queue_tail - 1]; - } - - - /* Hack -- main diagonal has special children */ - if (y == x) vinfo[e].next_0 = vinfo[e].next_1; - - - /* Extra values */ - vinfo[e].y = y; - vinfo[e].x = x; - vinfo[e].d = ((y > x) ? (y + x / 2) : (x + y / 2)); - vinfo[e].r = ((!y) ? x : (!x) ? y : (y == x) ? y : 0); - } - - - /* Verify maximal bits XXX XXX XXX */ - if (((vinfo[1].bits_3 | vinfo[2].bits_3) != VINFO_BITS_3) || - ((vinfo[1].bits_2 | vinfo[2].bits_2) != VINFO_BITS_2) || - ((vinfo[1].bits_1 | vinfo[2].bits_1) != VINFO_BITS_1) || - ((vinfo[1].bits_0 | vinfo[2].bits_0) != VINFO_BITS_0)) - { - quit("Incorrect bit masks!"); - } - - - /* Kill hack */ - KILL(hack, vinfo_hack); - - - /* Success */ - return (0); -} - - - -/* - * Forget the "CAVE_VIEW" grids, redrawing as needed - */ -void forget_view(void) -{ - int i; - - int fast_view_n = view_n; - - cave_type *c_ptr; - - - /* None to forget */ - if (!fast_view_n) return; - - /* Clear them all */ - for (i = 0; i < fast_view_n; i++) - { - int y = view_y[i]; - int x = view_x[i]; - - /* Access the grid */ - c_ptr = &cave[y][x]; - - /* Clear "CAVE_VIEW", "CAVE_SEEN" and player torch flags */ - c_ptr->info &= ~(CAVE_VIEW | CAVE_SEEN | CAVE_PLIT); - - /* Redraw */ - lite_spot(y, x); - } - - /* None left */ - view_n = 0; -} - - - -/* - * Calculate the complete field of view using a new algorithm - * - * If "view_y/x" and "temp_y/x" were global pointers to arrays of grids, as - * opposed to actual arrays of grids, then we could be more efficient by - * using "pointer swapping". - * - * Normally, vision along the major axes is more likely than vision - * along the diagonal axes, so we check the bits corresponding to - * the lines of sight near the major axes first. - * - * We use the "temp_y/x" array (and the "CAVE_TEMP" flag) to keep track of - * which grids were previously marked "CAVE_SEEN", since only those grids - * whose "CAVE_SEEN" value changes during this routine must be redrawn. - * - * This function is now responsible for maintaining the "CAVE_SEEN" - * flags as well as the "CAVE_VIEW" flags, which is good, because - * the only grids which normally need to be memorized and/or redrawn - * are the ones whose "CAVE_SEEN" flag changes during this routine. - * - * Basically, this function divides the "octagon of view" into octants of - * grids (where grids on the main axes and diagonal axes are "shared" by - * two octants), and processes each octant one at a time, processing each - * octant one grid at a time, processing only those grids which "might" be - * viewable, and setting the "CAVE_VIEW" flag for each grid for which there - * is an (unobstructed) line of sight from the center of the player grid to - * any internal point in the grid (and collecting these "CAVE_VIEW" grids - * into the "view_y/x" array), and setting the "CAVE_SEEN" flag for the grid - * if, in addition, the grid is "illuminated" in some way. - * - * This function relies on a theorem (suggested and proven by Mat Hostetter) - * which states that in each octant of a field of view, a given grid will - * be "intersected" by one or more unobstructed "lines of sight" from the - * center of the player grid if and only if it is "intersected" by at least - * one such unobstructed "line of sight" which passes directly through some - * corner of some grid in the octant which is not shared by any other octant. - * The proof is based on the fact that there are at least three significant - * lines of sight involving any non-shared grid in any octant, one which - * intersects the grid and passes though the corner of the grid closest to - * the player, and two which "brush" the grid, passing through the "outer" - * corners of the grid, and that any line of sight which intersects a grid - * without passing through the corner of a grid in the octant can be "slid" - * slowly towards the corner of the grid closest to the player, until it - * either reaches it or until it brushes the corner of another grid which - * is closer to the player, and in either case, the existanc of a suitable - * line of sight is thus demonstrated. - * - * It turns out that in each octant of the radius 20 "octagon of view", - * there are 161 grids (with 128 not shared by any other octant), and there - * are exactly 126 distinct "lines of sight" passing from the center of the - * player grid through any corner of any non-shared grid in the octant. To - * determine if a grid is "viewable" by the player, therefore, you need to - * simply show that one of these 126 lines of sight intersects the grid but - * does not intersect any wall grid closer to the player. So we simply use - * a bit vector with 126 bits to represent the set of interesting lines of - * sight which have not yet been obstructed by wall grids, and then we scan - * all the grids in the octant, moving outwards from the player grid. For - * each grid, if any of the lines of sight which intersect that grid have not - * yet been obstructed, then the grid is viewable. Furthermore, if the grid - * is a wall grid, then all of the lines of sight which intersect the grid - * should be marked as obstructed for future reference. Also, we only need - * to check those grids for whom at least one of the "parents" was a viewable - * non-wall grid, where the parents include the two grids touching the grid - * but closer to the player grid (one adjacent, and one diagonal). For the - * bit vector, we simply use 4 32-bit integers. All of the static values - * which are needed by this function are stored in the large "vinfo" array - * (above), which is machine generated by another program. XXX XXX XXX - * - * Hack -- The queue must be able to hold more than VINFO_MAX_GRIDS grids - * because the grids at the edge of the field of view use "grid zero" as - * their children, and the queue must be able to hold several of these - * special grids. Because the actual number of required grids is bizarre, - * we simply allocate twice as many as we would normally need. XXX XXX XXX - */ -void update_view(void) -{ - int i, o; - int y, x; - - int radius; - - int fast_view_n = view_n; - - int fast_temp_n = 0; - - cave_type *c_ptr; - - u16b info; - - - /*** Step 0 -- Begin ***/ - - /* Save the old "view" grids for later */ - for (i = 0; i < fast_view_n; i++) - { - /* Location */ - y = view_y[i]; - x = view_x[i]; - - /* Grid */ - c_ptr = &cave[y][x]; - - /* Get grid info */ - info = c_ptr->info; - ; - - /* Save "CAVE_SEEN" grids */ - if (info & (CAVE_SEEN)) - { - /* Set "CAVE_TEMP" flag */ - info |= (CAVE_TEMP); - - /* Save grid for later */ - temp_y[fast_temp_n] = y; - temp_x[fast_temp_n++] = x; - } - - /* Clear "CAVE_VIEW", "CAVE_SEEN" and player torch flags */ - info &= ~(CAVE_VIEW | CAVE_SEEN | CAVE_PLIT); - - /* Save cave info */ - c_ptr->info = info; - } - - /* Reset the "view" array */ - fast_view_n = 0; - - /* Extract "radius" value */ - radius = p_ptr->cur_lite; - - /* Handle real light */ - if (radius > 0) ++radius; - - - /*** Step 1 -- player grid ***/ - - /* Player grid */ - c_ptr = &cave[p_ptr->py][p_ptr->px]; - - /* Get grid info */ - info = c_ptr->info; - - /* Assume viewable */ - info |= (CAVE_VIEW); - - /* Torch-lit grid */ - if (0 < radius) - { - /* Mark as "CAVE_SEEN" and torch-lit */ - info |= (CAVE_SEEN | CAVE_PLIT); - } - - - /* Perma-lit grid */ - else if (info & (CAVE_GLOW)) - { - /* Mark as "CAVE_SEEN" */ - info |= (CAVE_SEEN); - } - - /* Save cave info */ - c_ptr->info = info; - - /* Save in array */ - view_y[fast_view_n] = p_ptr->py; - view_x[fast_view_n++] = p_ptr->px; - - - /*** Step 2 -- octants ***/ - - /* Scan each octant */ - for (o = 0; o < 8; o++) - { - vinfo_type *p; - - /* Last added */ - vinfo_type *last = &vinfo[0]; - - /* Grid queue */ - int queue_head = 0; - int queue_tail = 0; - vinfo_type *queue[VINFO_MAX_GRIDS*2]; - - /* Slope bit vector */ - u32b bits0 = VINFO_BITS_0; - u32b bits1 = VINFO_BITS_1; - u32b bits2 = VINFO_BITS_2; - u32b bits3 = VINFO_BITS_3; - - /* Reset queue */ - queue_head = queue_tail = 0; - - /* Initial grids */ - queue[queue_tail++] = &vinfo[1]; - queue[queue_tail++] = &vinfo[2]; - - /* Process queue */ - while (queue_head < queue_tail) - { - /* Dequeue next grid */ - p = queue[queue_head++]; - - /* Check bits */ - if ((bits0 & (p->bits_0)) || - (bits1 & (p->bits_1)) || - (bits2 & (p->bits_2)) || - (bits3 & (p->bits_3))) - { - /* Extract coordinate value */ - y = p_ptr->py + p->grid_y[o]; - x = p_ptr->px + p->grid_x[o]; - - /* Access the grid */ - c_ptr = &cave[y][x]; - - /* Get grid info */ - info = c_ptr->info; - - /* Handle wall */ - if (info & (CAVE_WALL)) - { - /* Clear bits */ - bits0 &= ~(p->bits_0); - bits1 &= ~(p->bits_1); - bits2 &= ~(p->bits_2); - bits3 &= ~(p->bits_3); - - /* Newly viewable wall */ - if (!(info & (CAVE_VIEW))) - { - /* Mark as viewable */ - info |= (CAVE_VIEW); - - /* Torch-lit grids */ - if (p->d < radius) - { - /* Mark as "CAVE_SEEN" and torch-lit */ - info |= (CAVE_SEEN | CAVE_PLIT); - } - - /* Monster-lit grids */ - else if (info & (CAVE_MLIT)) - { - /* Mark as "CAVE_SEEN" */ - info |= (CAVE_SEEN); - } - - /* Perma-lit grids */ - else if (info & (CAVE_GLOW)) - { - /* Hack -- move towards player */ - int yy = (y < p_ptr->py) ? (y + 1) : (y > p_ptr->py) ? (y - 1) : y; - int xx = (x < p_ptr->px) ? (x + 1) : (x > p_ptr->px) ? (x - 1) : x; - -#ifdef UPDATE_VIEW_COMPLEX_WALL_ILLUMINATION - - /* Check for "complex" illumination */ - if ((!(cave[yy][xx].info & (CAVE_WALL)) && - (cave[yy][xx].info & (CAVE_GLOW))) || - (!(cave[y][xx].info & (CAVE_WALL)) && - (cave[y][xx].info & (CAVE_GLOW))) || - (!(cave[yy][x].info & (CAVE_WALL)) && - (cave[yy][x].info & (CAVE_GLOW)))) - { - /* Mark as seen */ - info |= (CAVE_SEEN); - } - -#else /* UPDATE_VIEW_COMPLEX_WALL_ILLUMINATION */ - - /* Check for "simple" illumination */ - if (cave[yy][xx].info & (CAVE_GLOW)) - { - /* Mark as seen */ - info |= (CAVE_SEEN); - } - -#endif /* UPDATE_VIEW_COMPLEX_WALL_ILLUMINATION */ - - } - - /* Save cave info */ - c_ptr->info = info; - - /* Save in array */ - view_y[fast_view_n] = y; - view_x[fast_view_n++] = x; - } - } - - /* Handle non-wall */ - else - { - /* Enqueue child */ - if (last != p->next_0) - { - queue[queue_tail++] = last = p->next_0; - } - - /* Enqueue child */ - if (last != p->next_1) - { - queue[queue_tail++] = last = p->next_1; - } - - /* Newly viewable non-wall */ - if (!(info & (CAVE_VIEW))) - { - /* Mark as "viewable" */ - info |= (CAVE_VIEW); - - /* Torch-lit grids */ - if (p->d < radius) - { - /* Mark as "CAVE_SEEN" and torch-lit */ - info |= (CAVE_SEEN | CAVE_PLIT); - } - - /* Perma-lit or monster-lit grids */ - else if (info & (CAVE_GLOW | CAVE_MLIT)) - { - /* Mark as "CAVE_SEEN" */ - info |= (CAVE_SEEN); - } - - /* Save cave info */ - c_ptr->info = info; - - /* Save in array */ - view_y[fast_view_n] = y; - view_x[fast_view_n++] = x; - } - } - } - } - } - - - /*** Step 3 -- Complete the algorithm ***/ - - /* Handle blindness */ - if (p_ptr->blind) - { - /* Process "new" grids */ - for (i = 0; i < fast_view_n; i++) - { - /* Location */ - y = view_y[i]; - x = view_x[i]; - - /* Grid cannot be "CAVE_SEEN" */ - cave[y][x].info &= ~(CAVE_SEEN); - } - } - - /* Process "new" grids */ - for (i = 0; i < fast_view_n; i++) - { - /* Location */ - y = view_y[i]; - x = view_x[i]; - - /* Get grid info */ - info = cave[y][x].info; - - /* Was not "CAVE_SEEN", is now "CAVE_SEEN" */ - if ((info & (CAVE_SEEN)) && !(info & (CAVE_TEMP))) - { - /* Note */ - note_spot(y, x); - - /* Redraw */ - lite_spot(y, x); - } - } - - /* Process "old" grids */ - for (i = 0; i < fast_temp_n; i++) - { - /* Location */ - y = temp_y[i]; - x = temp_x[i]; - - /* Grid */ - c_ptr = &cave[y][x]; - - /* Get grid info */ - info = c_ptr->info; - - /* Clear "CAVE_TEMP" flag */ - info &= ~(CAVE_TEMP); - - /* Save cave info */ - c_ptr->info = info; - - /* Was "CAVE_SEEN", is now not "CAVE_SEEN" */ - if (!(info & (CAVE_SEEN))) - { - /* Redraw */ - lite_spot(y, x); - } - } - - - /* Save 'view_n' */ - view_n = fast_view_n; -} - - -/* - * Clear monster light - */ -void forget_mon_lite(void) -{ - int i, y, x; - - /* Process all the monster-lit grids */ - for (i = 0; i < lite_n; i++) - { - /* Access location */ - y = lite_y[i]; - x = lite_x[i]; - - /* Clear monster light flag */ - cave[y][x].info &= ~(CAVE_MLIT); - } - - /* Forget light array */ - lite_n = 0; -} - - -/* - * Update squares illuminated by monsters - * - * Code taken from Steven Fuerst's work for ZAngband, without support - * for multiple lite radii, and with necessary modifications for different - * internal representation of dungeon/wilderness. Other minor changes - * are mine... - * - * I'm not sure if I can handle wide radius well. Consider the following - * example, with p carrying a radius 3 light source: - * - * ##%# - * .x.. - * p##@ - * - * % should be illuminated, although the beam path is entirely out of - * player's los (because of grid-based nature of cave representation)... - * And I'm extremely reluctant to introduce symmetrical los. The current - * asymmetrical system has its own merit, and all the rules of games are - * asymmetrical, in some way or another... - * - * The code below exploits special characteristics of radius one light - * where one can fairly safely use light source's visibility (in terms of los) - * to determine if we can illuminate walls XXX - * - * This function works within the current player's field of view - * calculated by update_view(), so it should normally be called - * whenever FoV is updated (== PU_VIEW | PU_MON_LITE). The other - * case is when RF9_HAS_LITE monsters have moved or dead. Monster - * creation occurs out of LoS, so I chose not to take this into - * consideration. - * - * The CAVE_TEMP flag is used by the function to remember "old" monster-lit - * grids so that it can only redraw squares whose visibility has changed. - * - * Doing this in the update_view() order (update "new" grids, then "old") - * would result in bizarre lighting effects XXX XXX - * - * It has been made possible again to draw torch/monster-lit grids in - * different colours, even when they are in permanently lit locations - * by using (CAVE_PLIT|CAVE_MLIT) as if it were old CAVE_LITE, but I don't - * think it's appropriate for torch lights to be visible under the Sun :) - * or brighter light, and it doesn't work well with PernAngband's already - * colourful terrain features in aesthetically pleasing ways... -- pelpel - */ -void update_mon_lite(void) -{ - int i, y, x, d; - int fy, fx; - - cave_type *c_ptr; - u16b info; - - bool_ invis; - - s16b fast_lite_n = lite_n; - s16b fast_temp_n; - - - /* Mega-Hack -- It's unnecessary there */ - if (p_ptr->wild_mode) return; - - /* Handle special case -- Blindness */ - if (p_ptr->blind) - { - for (i = 0; i < fast_lite_n; i++) - { - /* Light location */ - y = lite_y[i]; - x = lite_x[i]; - - /* Forget monster light and view */ - cave[y][x].info &= ~(CAVE_MLIT | CAVE_SEEN); - - /* Redraw spot */ - /* lite_spot(y, x); */ - } - - /* Clear the light list */ - lite_n = 0; - - /* Done */ - return; - } - - - /* Remember and clear all monster-lit grids */ - for (i = 0; i < fast_lite_n; i++) - { - /* Lit location */ - y = lite_y[i]; - x = lite_x[i]; - - /* Access grid */ - c_ptr = &cave[y][x]; - - /* Access cave info of the grid */ - info = c_ptr->info; - - /* Remember it, by setting the CAVE_TEMP flag */ - info |= (CAVE_TEMP); - - /* Forget monster light */ - info &= ~(CAVE_MLIT); - - /* Unseen unless it's glowing or illuminated by player light source */ - if (!(info & (CAVE_GLOW | CAVE_PLIT))) - { - info &= ~(CAVE_SEEN); - } - - /* Save cave info flags */ - c_ptr->info = info; - } - - - /* Clear the temp list */ - fast_temp_n = 0; - - /* Loop through monsters, adding newly lit grids to changes list */ - for (i = 1; i < m_max; i++) - { - monster_type *m_ptr = &m_list[i]; - monster_race *r_ptr; - - /* Skip dead monsters */ - if (!m_ptr->r_idx) continue; - - /* Skip out-of-sight monsters (MAX_SIGHT + max radius) */ - if (m_ptr->cdis > MAX_SIGHT + 1) continue; - - /* Access monster race info (with possible ego mods) */ - r_ptr = race_info_idx(m_ptr->r_idx, m_ptr->ego); - - /* Skip monsters not carrying light source */ - if (!(r_ptr->flags9 & RF9_HAS_LITE)) continue; - - /* Access the location */ - fy = m_ptr->fy; - fx = m_ptr->fx; - - /* Extract monster grid visibility */ - invis = !player_has_los_bold(fy, fx); - - /* Nested loops may be a bad idea here XXX */ - for (d = 0; d < 9; d++) - { - y = fy + ddy_ddd[d]; - x = fx + ddx_ddd[d]; - - /* Paranoia */ - /* if (!in_bounds(y, x)) continue; */ - - /* Access the grid */ - c_ptr = &cave[y][x]; - - /* Access cave info flags */ - info = c_ptr->info; - - /* Don't care grids out of player's los */ - if (!(info & (CAVE_VIEW))) continue; - - /* - * Avoid processing already monster-lit grids, - * for efficiency and to avoid temp array overflow - */ - if (info & (CAVE_MLIT)) continue; - - /* - * Hack XXX XXX -- light shouldn't penetrate walls - * - * OK NG - * .#. p#. | p. .p. p.. - * p.@ ..@ | .# .#. .#. - * | .@ .@. ..@ - * - * So if a monster carrying light source is out of player LoS, - * walls aren't illuminated. - * - * CAVEAT: % will be illuminated in cases like this: - * - * #%..@ - * p.... - * - * We don't have four sides for a wall grid, so... - */ - if (invis && (f_info[c_ptr->feat].flags1 & FF1_NO_VISION)) continue; - - /* Give monster light to the location */ - c_ptr->info |= (CAVE_MLIT | CAVE_SEEN); - - /* Save the location */ - temp_y[fast_temp_n] = y; - temp_x[fast_temp_n] = x; - fast_temp_n++; - } - } - - /* Process old grids */ - for (i = 0; i < fast_lite_n; i++) - { - /* Access location */ - y = lite_y[i]; - x = lite_x[i]; - - /* Access grid */ - c_ptr = &cave[y][x]; - - /* Was lit, is no longer lit */ - if (!(c_ptr->info & (CAVE_MLIT))) - { - /* Clear the temp flag */ - c_ptr->info &= ~(CAVE_TEMP); - - /* See if there was a visible monster */ - if (player_has_los_bold(y, x) && c_ptr->m_idx) - { - /* Hide the monster */ - update_mon(c_ptr->m_idx, FALSE); - } - else - { - /* Redraw */ - lite_spot(y, x); - } - } - } - - /* Copy the temp array into the light array */ - for (i = 0; i < fast_temp_n; i++) - { - /* Access location */ - y = temp_y[i]; - x = temp_x[i]; - - /* Access grid */ - c_ptr = &cave[y][x]; - - - /* No changes in illumination */ - if (c_ptr->info & (CAVE_TEMP)) - { - /* Clear the temp flag */ - c_ptr->info &= ~(CAVE_TEMP); - } - - /* Was not lit, is now lit */ - else - { - /* Remember the location, if appropriate */ - note_spot(y, x); - - /* See if there is a monster */ - if (c_ptr->m_idx) - { - /* Show it */ - update_mon(c_ptr->m_idx, FALSE); - } - else - { - /* Redraw */ - lite_spot(y, x); - } - } - - - /* Save the location */ - lite_y[i] = y; - lite_x[i] = x; - } - - /* Save lite_n */ - lite_n = fast_temp_n; - - /* Forget temp */ - temp_n = 0; -} - - - - - - -/* - * Hack -- provide some "speed" for the "flow" code - * This entry is the "current index" for the "when" field - * Note that a "when" value of "zero" means "not used". - * - * Note that the "cost" indexes from 1 to 127 are for - * "old" data, and from 128 to 255 are for "new" data. - * - * This means that as long as the player does not "teleport", - * then any monster up to 128 + MONSTER_FLOW_DEPTH will be - * able to track down the player, and in general, will be - * able to track down either the player or a position recently - * occupied by the player. - */ -static int flow_n = 0; - - -/* - * Hack -- forget the "flow" information - */ -void forget_flow(void) -{ - int x, y; - - /* Nothing to forget */ - if (!flow_n) return; - - /* Check the entire dungeon */ - for (y = 0; y < cur_hgt; y++) - { - for (x = 0; x < cur_wid; x++) - { - /* Forget the old data */ - cave[y][x].cost = 0; - cave[y][x].when = 0; - } - } - - /* Start over */ - flow_n = 0; -} - - -/* - * Hack -- Allow us to treat the "seen" array as a queue - */ -static int flow_head = 0; -static int flow_tail = 0; - - -/* - * Take note of a reachable grid. Assume grid is legal. - */ -static void update_flow_aux(int y, int x, int n) -{ - cave_type *c_ptr; - - int old_head = flow_head; - - - /* Get the grid */ - c_ptr = &cave[y][x]; - - /* Ignore "pre-stamped" entries */ - if (c_ptr->when == flow_n) return; - - /* Ignore "walls" and "rubble" */ - if (c_ptr->feat >= FEAT_RUBBLE) return; - - /* Save the time-stamp */ - c_ptr->when = flow_n; - - /* Save the flow cost */ - c_ptr->cost = n; - - /* Hack -- limit flow depth */ - if (n == MONSTER_FLOW_DEPTH) return; - - /* Enqueue that entry */ - temp_y[flow_head] = y; - temp_x[flow_head] = x; - - /* Advance the queue */ - if (++flow_head == TEMP_MAX) flow_head = 0; - - /* Hack -- notice overflow by forgetting new entry */ - if (flow_head == flow_tail) flow_head = old_head; -} - - -/* - * Hack -- fill in the "cost" field of every grid that the player - * can "reach" with the number of steps needed to reach that grid. - * This also yields the "distance" of the player from every grid. - * - * In addition, mark the "when" of the grids that can reach - * the player with the incremented value of "flow_n". - * - * Hack -- use the "seen" array as a "circular queue". - * - * We do not need a priority queue because the cost from grid - * to grid is always "one" and we process them in order. - */ -void update_flow(void) -{ - int x, y, d; - - /* Hack -- disabled */ - if (!flow_by_sound) return; - - /* Paranoia -- make sure the array is empty */ - if (temp_n) return; - - /* Cycle the old entries (once per 128 updates) */ - if (flow_n == 255) - { - /* Rotate the time-stamps */ - for (y = 0; y < cur_hgt; y++) - { - for (x = 0; x < cur_wid; x++) - { - int w = cave[y][x].when; - cave[y][x].when = (w > 128) ? (w - 128) : 0; - } - } - - /* Restart */ - flow_n = 127; - } - - /* Start a new flow (never use "zero") */ - flow_n++; - - - /* Reset the "queue" */ - flow_head = flow_tail = 0; - - /* Add the player's grid to the queue */ - update_flow_aux(p_ptr->py, p_ptr->px, 0); - - /* Now process the queue */ - while (flow_head != flow_tail) - { - /* Extract the next entry */ - y = temp_y[flow_tail]; - x = temp_x[flow_tail]; - - /* Forget that entry */ - if (++flow_tail == TEMP_MAX) flow_tail = 0; - - /* Add the "children" */ - for (d = 0; d < 8; d++) - { - /* Add that child if "legal" */ - update_flow_aux(y + ddy_ddd[d], x + ddx_ddd[d], cave[y][x].cost + 1); - } - } - - /* Forget the flow info */ - flow_head = flow_tail = 0; -} - - - - - - - -/* - * Hack -- map the current panel (plus some) ala "magic mapping" - */ -void map_area(void) -{ - int i, x, y, y1, y2, x1, x2; - - cave_type *c_ptr; - - - /* Pick an area to map */ - y1 = panel_row_min - randint(10); - y2 = panel_row_max + randint(10); - x1 = panel_col_min - randint(20); - x2 = panel_col_max + randint(20); - - /* Speed -- shrink to fit legal bounds */ - if (y1 < 1) y1 = 1; - if (y2 > cur_hgt - 2) y2 = cur_hgt - 2; - if (x1 < 1) x1 = 1; - if (x2 > cur_wid - 2) x2 = cur_wid - 2; - - /* Scan that area */ - for (y = y1; y <= y2; y++) - { - for (x = x1; x <= x2; x++) - { - c_ptr = &cave[y][x]; - - /* All non-walls are "checked" */ - if (!is_wall(c_ptr)) - { - /* Memorize normal features */ - if (!cave_plain_floor_grid(c_ptr)) - { - /* Memorize the object */ - c_ptr->info |= (CAVE_MARK); - } - - /* Memorize known walls */ - for (i = 0; i < 8; i++) - { - c_ptr = &cave[y + ddy_ddd[i]][x + ddx_ddd[i]]; - - /* Memorize walls (etc) */ - if (is_wall(c_ptr)) - { - /* Memorize the walls */ - c_ptr->info |= (CAVE_MARK); - } - } - } - } - } - - /* Redraw map */ - p_ptr->redraw |= (PR_MAP); - - /* Window stuff */ - p_ptr->window |= (PW_OVERHEAD); -} - - - -/* - * Light up the dungeon using "clairvoyance" - * - * This function "illuminates" every grid in the dungeon, memorizes all - * "objects", memorizes all grids as with magic mapping, and, under the - * standard option settings (view_perma_grids but not view_torch_grids) - * memorizes all floor grids too. - * - * Note that if "view_perma_grids" is not set, we do not memorize floor - * grids, since this would defeat the purpose of "view_perma_grids", not - * that anyone seems to play without this option. - * - * Note that if "view_torch_grids" is set, we do not memorize floor grids, - * since this would prevent the use of "view_torch_grids" as a method to - * keep track of what grids have been observed directly. - */ -void wiz_lite(void) -{ - int i, y, x; - - - /* Memorize objects */ - for (i = 1; i < o_max; i++) - { - object_type *o_ptr = &o_list[i]; - - /* Skip dead objects */ - if (!o_ptr->k_idx) continue; - - /* Skip held objects */ - if (o_ptr->held_m_idx) continue; - - /* Memorize */ - o_ptr->marked = TRUE; - } - - /* Scan all normal grids */ - for (y = 1; y < cur_hgt - 1; y++) - { - /* Scan all normal grids */ - for (x = 1; x < cur_wid - 1; x++) - { - cave_type *c_ptr = &cave[y][x]; - - if (c_ptr->m_idx) - { - monster_type *m_ptr = &m_list[c_ptr->m_idx]; - monster_race *r_ptr = race_inf(m_ptr); - - if (r_ptr->flags9 & RF9_MIMIC) - { - object_type *o_ptr = &o_list[m_ptr->hold_o_idx]; - - o_ptr->marked = TRUE; - } - } - - /* Process all non-walls */ - /* if (c_ptr->feat < FEAT_SECRET) */ - { - /* Scan all neighbors */ - for (i = 0; i < 9; i++) - { - int yy = y + ddy_ddd[i]; - int xx = x + ddx_ddd[i]; - - /* Get the grid */ - c_ptr = &cave[yy][xx]; - - /* Perma-lite the grid */ - c_ptr->info |= (CAVE_GLOW); - - /* Memorize normal features */ - if (!cave_plain_floor_grid(c_ptr)) - { - /* Memorize the grid */ - c_ptr->info |= (CAVE_MARK); - } - - /* Normally, memorize floors (see above) */ - if (view_perma_grids && !view_torch_grids) - { - /* Memorize the grid */ - c_ptr->info |= (CAVE_MARK); - } - } - } - } - } - - /* Fully update the visuals */ - p_ptr->update |= (PU_UN_VIEW | PU_VIEW | PU_MONSTERS | PU_MON_LITE); - - /* Redraw map */ - p_ptr->redraw |= (PR_MAP); - - /* Window stuff */ - p_ptr->window |= (PW_OVERHEAD); -} - -void wiz_lite_extra(void) -{ - int y, x; - for (y = 0; y < cur_hgt; y++) - { - for (x = 0; x < cur_wid; x++) - { - cave[y][x].info |= (CAVE_GLOW | CAVE_MARK); - } - } - wiz_lite(); -} - -/* - * Forget the dungeon map (ala "Thinking of Maud..."). - */ -void wiz_dark(void) -{ - int i, y, x; - - - /* Forget every grid */ - for (y = 0; y < cur_hgt; y++) - { - for (x = 0; x < cur_wid; x++) - { - cave_type *c_ptr = &cave[y][x]; - - /* Process the grid */ - c_ptr->info &= ~(CAVE_MARK); - } - } - - /* Forget all objects */ - for (i = 1; i < o_max; i++) - { - object_type *o_ptr = &o_list[i]; - - /* Skip dead objects */ - if (!o_ptr->k_idx) continue; - - /* Skip held objects */ - if (o_ptr->held_m_idx) continue; - - /* Forget the object */ - o_ptr->marked = FALSE; - } - - /* Fully update the visuals */ - p_ptr->update |= (PU_UN_VIEW | PU_VIEW | PU_MONSTERS | PU_MON_LITE); - - /* Redraw map */ - p_ptr->redraw |= (PR_MAP); - - /* Window stuff */ - p_ptr->window |= (PW_OVERHEAD); -} - - - - - -/* - * Change the "feat" flag for a grid, and notice/redraw the grid - */ -void cave_set_feat(int y, int x, int feat) -{ - cave_type *c_ptr = &cave[y][x]; - - /* Change the feature */ - c_ptr->feat = feat; - - /* - * Handle "wall/door" grids - * - * XXX XXX XXX This assumes c_ptr->mimic doesn't mimic terrain - * features whose LoS behaviour is different from its own, in - * most cases. Level boundaries are the most notable exception, - * where "real" terrain is always FEAT_PERM_SOLID, and the fact - * is (ab)used to prevent out-of-range access to the cave array. - * If we were going to implement an evil dungeon type in which - * everything is mimicked, then this function, los(), projectable(), - * project_path() and maybe some functions in melee2.c might - * better use c_ptr->mimic when it's set -- pelpel - */ - if (!cave_sight_grid(c_ptr)) - { - c_ptr->info |= (CAVE_WALL); - } - - /* Handle "floor"/etc grids */ - else - { - c_ptr->info &= ~(CAVE_WALL); - } - - /* Notice & Redraw */ - if (character_dungeon) - { - /* Notice */ - note_spot(y, x); - - /* Redraw */ - lite_spot(y, x); - } -} - - -/* - * Place floor terrain at (y, x) according to dungeon info - */ -void place_floor(int y, int x) -{ - cave_set_feat(y, x, floor_type[rand_int(100)]); -} - -/* - * This routine is used when the current feature gets convert to a floor and - * the possible floor types include glass which is permanent. An unpassable - * feature is undesirable, so the glass gets convert to molten glass which - * is passable. - */ -void place_floor_convert_glass(int y, int x) -{ - place_floor(y, x); - - if (cave[y][x].feat == 188) cave[y][x].feat = 103; -} - -/* - * Place a cave filler at (y, x) - */ -void place_filler(int y, int x) -{ - cave_set_feat(y, x, fill_type[rand_int(100)]); -} - - -/* - * Calculate "incremental motion". Used by project() and shoot(). - * Assumes that (*y,*x) lies on the path from (y1,x1) to (y2,x2). - */ -void mmove2(int *y, int *x, int y1, int x1, int y2, int x2) -{ - int dy, dx, dist, shift; - - /* Extract the distance travelled */ - dy = (*y < y1) ? y1 - *y : *y - y1; - dx = (*x < x1) ? x1 - *x : *x - x1; - - /* Number of steps */ - dist = (dy > dx) ? dy : dx; - - /* We are calculating the next location */ - dist++; - - - /* Calculate the total distance along each axis */ - dy = (y2 < y1) ? (y1 - y2) : (y2 - y1); - dx = (x2 < x1) ? (x1 - x2) : (x2 - x1); - - /* Paranoia -- Hack -- no motion */ - if (!dy && !dx) return; - - - /* Move mostly vertically */ - if (dy > dx) - { - /* Extract a shift factor */ - shift = (dist * dx + (dy - 1) / 2) / dy; - - /* Sometimes move along the minor axis */ - (*x) = (x2 < x1) ? (x1 - shift) : (x1 + shift); - - /* Always move along major axis */ - (*y) = (y2 < y1) ? (y1 - dist) : (y1 + dist); - } - - /* Move mostly horizontally */ - else - { - /* Extract a shift factor */ - shift = (dist * dy + (dx - 1) / 2) / dx; - - /* Sometimes move along the minor axis */ - (*y) = (y2 < y1) ? (y1 - shift) : (y1 + shift); - - /* Always move along major axis */ - (*x) = (x2 < x1) ? (x1 - dist) : (x1 + dist); - } -} - - - -/* - * Determine if a bolt spell cast from (y1,x1) to (y2,x2) will arrive - * at the final destination, assuming no monster gets in the way. - * - * This is slightly (but significantly) different from "los(y1,x1,y2,x2)". - */ -bool_ projectable(int y1, int x1, int y2, int x2) -{ - int dist, y, x; - - /* Start at the initial location */ - y = y1, x = x1; - - /* See "project()" */ - for (dist = 0; dist <= MAX_RANGE; dist++) - { - /* Check for arrival at "final target" */ - /* - * NB: this check was AFTER the 'never pass - * thru walls' clause, below. Switching them - * lets monsters shoot a the player if s/he is - * visible but in a wall - */ - if ((x == x2) && (y == y2)) return (TRUE); - - /* Never pass through walls */ - if (dist && (!cave_sight_bold(y, x) || !cave_floor_bold(y, x))) break; - - /* Calculate the new location */ - mmove2(&y, &x, y1, x1, y2, x2); - } - - - /* Assume obstruction */ - return (FALSE); -} - - - - -/* - * Standard "find me a location" function - * - * Obtains a legal location within the given distance of the initial - * location, and with "los()" from the source to destination location. - * - * This function is often called from inside a loop which searches for - * locations while increasing the "d" distance. - * - * Currently the "m" parameter is unused. - */ -void scatter(int *yp, int *xp, int y, int x, int d) -{ - int nx, ny; - int attempts_left = 5000; - - /* Pick a location */ - while (--attempts_left) - { - /* Pick a new location */ - ny = rand_spread(y, d); - nx = rand_spread(x, d); - - /* Ignore illegal locations and outer walls */ - if (!in_bounds(ny, nx)) continue; - - /* Ignore "excessively distant" locations */ - if ((d > 1) && (distance(y, x, ny, nx) > d)) continue; - - /* Require "line of sight" */ - if (los(y, x, ny, nx)) break; - } - - if (attempts_left > 0) - { - /* Save the location */ - (*yp) = ny; - (*xp) = nx; - } -} - - - - -/* - * Track a new monster - */ -void health_track(int m_idx) -{ - /* Track a new guy */ - health_who = m_idx; - - /* Redraw (later) */ - p_ptr->redraw |= (PR_HEALTH); -} - - - -/* - * Hack -- track the given monster race - */ -void monster_race_track(int r_idx, int ego) -{ - /* Save this monster ID */ - monster_race_idx = r_idx; - monster_ego_idx = ego; - - /* Window stuff */ - p_ptr->window |= (PW_MONSTER); -} - - - -/* - * Hack -- track the given object kind - */ -void object_track(object_type *o_ptr) -{ - /* Save this monster ID */ - tracked_object = o_ptr; - - /* Window stuff */ - p_ptr->window |= (PW_OBJECT); -} - - - -/* - * Something has happened to disturb the player. - * - * The first arg indicates a major disturbance, which affects search. - * - * The second arg is currently unused, but could induce output flush. - * - * All disturbance cancels repeated commands, resting, and running. - */ -void disturb(int stop_search, int unused_flag) -{ - /* Unused */ - unused_flag = unused_flag; - - /* Cancel auto-commands */ - /* command_new = 0; */ - - /* Cancel repeated commands */ - if (command_rep) - { - /* Cancel */ - command_rep = 0; - - /* Redraw the state (later) */ - p_ptr->redraw |= (PR_STATE); - } - - /* Cancel Resting */ - if (resting) - { - /* Cancel */ - resting = 0; - - /* Redraw the state (later) */ - p_ptr->redraw |= (PR_STATE); - } - - /* Cancel running */ - if (running) - { - /* Cancel */ - running = 0; - - /* Calculate torch radius */ - p_ptr->update |= (PU_TORCH); - } - - /* Cancel searching if requested */ - if (stop_search && p_ptr->searching) - { - /* Cancel */ - p_ptr->searching = FALSE; - - /* Recalculate bonuses */ - p_ptr->update |= (PU_BONUS); - - /* Redraw the state */ - p_ptr->redraw |= (PR_STATE); - } - - /* Flush the input if requested */ - if (flush_disturb) flush(); -} - - -/* - * Hack -- Check if a level is a "quest" level - */ -int is_quest(int level) -{ - int i = random_quest_number(); - - /* Check quests */ - if (p_ptr->inside_quest) - return (p_ptr->inside_quest); - - if (i) return (QUEST_RANDOM); - - /* Nope */ - return (0); -} - - -/* - * Return the index of the random quest on this level - * (or zero) - */ -int random_quest_number() -{ - if ((dun_level >= 1) && (dun_level < MAX_RANDOM_QUEST) && - (dungeon_flags1 & DF1_PRINCIPAL) && - (random_quests[dun_level].type) && - (!random_quests[dun_level].done) && - (!is_randhero(dun_level))) - { - return dun_level; - } - - /* Nope */ - return 0; -} - - -/* - * handle spell effects - */ -int effect_pop() -{ - int i; - - for (i = 1; i < MAX_EFFECTS; i++) - if (!effects[i].time) - return i; - return -1; -} - -int new_effect(int type, int dam, int time, int cy, int cx, int rad, s32b flags) -{ - int i; - - if ((i = effect_pop()) == -1) return -1; - - effects[i].type = type; - effects[i].dam = dam; - effects[i].time = time; - effects[i].flags = flags; - effects[i].cx = cx; - effects[i].cy = cy; - effects[i].rad = rad; - return i; -} |