/* ------------------------------------------------------------------------ * Map redraw. * ------------------------------------------------------------------------ */ //#if 0 //static void trace_map_updates(game_event_type type, game_event_data *data, void *user) //{ // if (data.point.x == -1 && data.point.y == -1) // { // printf("Redraw whole map\n"); // } // else // { // printf("Redraw (%i, %i)\n", data.point.x, data.point.y); // } //} //#endif public static void update_maps(Game_Event.Event_Type type, Game_Event data, object user) { Term t = user as Term; /* This signals a whole-map redraw. */ if (data.point.x == -1 && data.point.y == -1) { Cave.prt_map(); } /* Single point to be redrawn */ else { Grid_Data g = new Grid_Data(); ConsoleColor a = ConsoleColor.White, ta = ConsoleColor.White; char c = ' ', tc = ' '; int ky, kx; int vy, vx; /* Location relative to panel */ ky = data.point.y - t.offset_y; kx = data.point.x - t.offset_x; if (t == Misc.angband_term[0]) { /* Verify location */ if ((ky < 0) || (ky >= Misc.SCREEN_HGT)) { return; } /* Verify location */ if ((kx < 0) || (kx >= Misc.SCREEN_WID)) { return; } /* Location in window */ vy = ky + Misc.ROW_MAP; vx = kx + Misc.COL_MAP; if (Term.tile_width > 1) { vx += (Term.tile_width - 1) * kx; } if (Term.tile_height > 1) { vy += (Term.tile_height - 1) * ky; } } else { if (Term.tile_width > 1) { kx += (Term.tile_width - 1) * kx; } if (Term.tile_height > 1) { ky += (Term.tile_height - 1) * ky; } /* Verify location */ if ((ky < 0) || (ky >= t.hgt)) { return; } if ((kx < 0) || (kx >= t.wid)) { return; } /* Location in window */ vy = ky; vx = kx; } /* Redraw the grid spot */ Cave.map_info(data.point.y, data.point.x, ref g); Cave.grid_data_as_text(ref g, ref a, ref c, ref ta, ref tc); t.queue_char(vx, vy, a, c, ta, tc); //#if 0 // /* Plot 'spot' updates in light green to make them visible */ // Term_queue_char(t, vx, vy, TERM_L_GREEN, c, ta, tc); //#endif if ((Term.tile_width > 1) || (Term.tile_height > 1)) { t.big_queue_char(vx, vy, a, c, ConsoleColor.White, ' '); } } }
static void prt_map_aux() { ConsoleColor a = ConsoleColor.White; char c = '\0'; ConsoleColor ta = ConsoleColor.White; char tc = '\0'; Grid_Data g = new Grid_Data(); int y, x; int vy, vx; int ty, tx; int j; /* Scan windows */ for (j = 0; j < Misc.ANGBAND_TERM_MAX; j++) { Term t = Misc.angband_term[j]; /* No window */ if (t == null) continue; /* No relevant flags */ if ((Player_Other.instance.window_flag[j] & (Misc.PW_MAP)) == 0) continue; /* Assume screen */ ty = t.offset_y + (t.hgt / Term.tile_height); tx = t.offset_x + (t.wid / Term.tile_width); /* Dump the map */ for (y = t.offset_y, vy = 0; y < ty; vy++, y++) { if (vy + Term.tile_height - 1 >= t.hgt) continue; for (x = t.offset_x, vx = 0; x < tx; vx++, x++) { /* Check bounds */ if (!in_bounds(y, x)) continue; if (vx + Term.tile_width - 1 >= t.wid) continue; /* Determine what is there */ Cave.map_info(y, x, ref g); Cave.grid_data_as_text(ref g, ref a, ref c, ref ta, ref tc); t.queue_char(vx, vy, a, c, ta, tc); if((Term.tile_width > 1) || (Term.tile_height > 1)) throw new NotImplementedException(); //t.big_queue_char(vx, vy, 255, -1, 0, 0); } } } }
/** * Apply text lighting effects */ static void grid_get_text(Grid_Data g, ref ConsoleColor a, ref char c) { /* Trap detect edge, but don't colour traps themselves, or treasure */ if (g.trapborder && !feat_is_known_trap((int)g.f_idx) && !feat_is_treasure((int)g.f_idx)) { if (g.in_view) a = ConsoleColor.Green; else a = ConsoleColor.DarkGreen; } else if (g.f_idx == FEAT_FLOOR) { if (g.lighting == Grid_Data.grid_light_level.FEAT_LIGHTING_BRIGHT) { if (a == ConsoleColor.White) a = ConsoleColor.Yellow; } else if (g.lighting == Grid_Data.grid_light_level.FEAT_LIGHTING_DARK) { if (a == ConsoleColor.White) a = ConsoleColor.DarkGray; //Light dark...??? Maybe make this black... } } else if (g.f_idx > FEAT_INVIS) { if (g.lighting == Grid_Data.grid_light_level.FEAT_LIGHTING_DARK) { if (a == ConsoleColor.White) a = ConsoleColor.Gray; //SLATE } } }
/* * Redraw (on the screen) the current map panel * * Note the inline use of "light_spot()" for efficiency. * * The main screen will always be at least 24x80 in size. */ public static void prt_map() { ConsoleColor a = ConsoleColor.White; char c = '\0'; ConsoleColor ta = ConsoleColor.White; char tc = '\0'; Grid_Data g = new Grid_Data(); int y, x; int vy, vx; int ty, tx; /* Redraw map sub-windows */ prt_map_aux(); /* Assume screen */ ty = Term.instance.offset_y + Misc.SCREEN_HGT; tx = Term.instance.offset_x + Misc.SCREEN_WID; /* Dump the map */ for (y = Term.instance.offset_y, vy = Misc.ROW_MAP; y < ty; vy++, y++) { for (x = Term.instance.offset_x, vx = Misc.COL_MAP; x < tx; vx++, x++) { /* Check bounds */ if (!in_bounds(y, x)) continue; /* Determine what is there */ Cave.map_info(y, x, ref g); Cave.grid_data_as_text(ref g, ref a, ref c, ref ta, ref tc); /* Hack -- Queue it */ Term.instance.queue_char(vx, vy, a, c, ta, tc); if ((Term.tile_width > 1) || (Term.tile_height > 1)) { Term.instance.big_queue_char(vx, vy, a, c, ConsoleColor.White, ' '); if (Term.tile_width > 1) { vx += Term.tile_width - 1; } } } if (Term.tile_height > 1) vy += Term.tile_height - 1; } }
/* * This function takes a grid location (x, y) and extracts information the * player is allowed to know about it, filling in the grid_data structure * passed in 'g'. * * The information filled in is as follows: * - g.f_idx is filled in with the terrain's feature type, or FEAT_NONE * if the player doesn't know anything about the grid. The function * makes use of the "mimic" field in terrain in order to allow one * feature to look like another (hiding secret doors, invisible traps, * etc). This will return the terrain type the player "Knows" about, * not necessarily the real terrain. * - g.m_idx is set to the monster index, or 0 if there is none (or the * player doesn't know it). * - g.first_kind is set to the object_kind of the first object in a grid * that the player knows about, or null for no objects. * - g.muliple_objects is true if there is more than one object in the * grid that the player knows and cares about (to facilitate any special * floor stack symbol that might be used). * - g.in_view is true if the player can currently see the grid - this can * be used to indicate field-of-view, such as through the OPT(view_bright_light) * option. * - g.lighting is set to indicate the lighting level for the grid: * FEAT_LIGHTING_DARK for unlit grids, FEAT_LIGHTING_LIT for those lit by the player's * light source, and FEAT_LIGHTING_BRIGHT for inherently light grids (lit rooms, etc). * Note that lighting is always FEAT_LIGHTING_BRIGHT for known "interesting" grids * like walls. * - g.is_player is true if the player is on the given grid. * - g.hallucinate is true if the player is hallucinating something "strange" * for this grid - this should pick a random monster to show if the m_idx * is non-zero, and a random object if first_kind is non-zero. * * NOTES: * This is called pretty frequently, whenever a grid on the map display * needs updating, so don't overcomplicate it. * * Terrain is remembered separately from objects and monsters, so can be * shown even when the player can't "see" it. This leads to things like * doors out of the player's view still change from closed to open and so on. * * TODO: * Hallucination is currently disabled (it was a display-level hack before, * and we need it to be a knowledge-level hack). The idea is that objects * may turn into different objects, monsters into different monsters, and * terrain may be objects, monsters, or stay the same. */ public static void map_info(int y, int x, ref Grid_Data g) { Object.Object o_ptr; short info; Misc.assert(x < DUNGEON_WID); Misc.assert(y < DUNGEON_HGT); info = Cave.cave.info[y][x]; /* Default "clear" values, others will be set later where appropriate. */ g.first_kind = null; g.multiple_objects = false; g.lighting = Grid_Data.grid_light_level.FEAT_LIGHTING_DARK; g.f_idx = cave.feat[y][x]; if (Misc.f_info[g.f_idx].mimic != 0) g.f_idx = Misc.f_info[g.f_idx].mimic; g.in_view = (info & CAVE_SEEN) != 0 ? true : false; g.is_player = (cave.m_idx[y][x] < 0) ? true : false; g.m_idx = (uint)((g.is_player) ? 0 : cave.m_idx[y][x]); g.hallucinate = Misc.p_ptr.timed[(int)Timed_Effect.IMAGE] != 0 ? true : false; g.trapborder = (dtrap_edge(y, x)) ? true : false; if (g.in_view) { g.lighting = Grid_Data.grid_light_level.FEAT_LIGHTING_LIT; if ((info & CAVE_GLOW) == 0 && Option.view_yellow_light.value) g.lighting = Grid_Data.grid_light_level.FEAT_LIGHTING_BRIGHT; } else if ((info & CAVE_MARK) == 0) { g.f_idx = FEAT_NONE; } /* Objects */ for (o_ptr = Object.Object.get_first_object(y, x); o_ptr != null; o_ptr = Object.Object.get_next_object(o_ptr)) { if(o_ptr.kind == null) { continue; } /* Memorized objects */ if (o_ptr.marked != 0 && !Squelch.item_ok(o_ptr)) { /* First item found */ if (g.first_kind == null) { g.first_kind = o_ptr.kind; } else { g.multiple_objects = true; /* And we know all we need to know. */ break; } } } /* Monsters */ if (g.m_idx > 0) { /* If the monster isn't "visible", make sure we don't list it.*/ Monster.Monster m_ptr = cave_monster(Cave.cave, (int)g.m_idx); if (!m_ptr.ml) g.m_idx = 0; } /* Rare random hallucination on non-outer walls */ if (g.hallucinate && g.m_idx == 0 && g.first_kind == null) { if (Random.one_in_(128) && g.f_idx < FEAT_PERM_SOLID) g.m_idx = 1; else if (Random.one_in_(128) && g.f_idx < FEAT_PERM_SOLID) /* if hallucinating, we just need first_kind to not be null */ g.first_kind = Misc.k_info[0]; else g.hallucinate = false; } Misc.assert(g.f_idx <= FEAT_PERM_SOLID); if (!g.hallucinate) Misc.assert((int)g.m_idx < cave.mon_max); /* All other g fields are 'flags', mostly booleans. */ }
/* * This function takes a pointer to a grid info struct describing the * contents of a grid location (as obtained through the function map_info) * and fills in the character and attr pairs for display. * * ap and cp are filled with the attr/char pair for the monster, object or * floor tile that is at the "top" of the grid (monsters covering objects, * which cover floor, assuming all are present). * * tap and tcp are filled with the attr/char pair for the floor, regardless * of what is on it. This can be used by graphical displays with * transparency to place an object onto a floor tile, is desired. * * Any lighting effects are also applied to these pairs, clear monsters allow * the underlying colour or feature to show through (ATTR_CLEAR and * CHAR_CLEAR), multi-hued colour-changing (ATTR_MULTI) is applied, and so on. * Technically, the flag "CHAR_MULTI" is supposed to indicate that a monster * looks strange when examined, but this flag is currently ignored. * * NOTES: * This is called pretty frequently, whenever a grid on the map display * needs updating, so don't overcomplicate it. * * 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 "pile" * attr/char, and "feature zero" being used for the "darkness" attr/char. * * TODO: * The transformations for tile colors, or brightness for the 16x16 * tiles should be handled differently. One possibility would be to * extend feature_type with attr/char definitions for the different states. * This will probably be done outside of the current text.graphics mappings * though. */ public static void grid_data_as_text(ref Grid_Data g, ref ConsoleColor ap, ref char cp, ref ConsoleColor tap, ref char tcp) { Feature f_ptr = Misc.f_info[g.f_idx]; ConsoleColor a = f_ptr.x_attr[(int)g.lighting]; char c = f_ptr.x_char[(int)g.lighting]; /* Check for trap detection boundaries */ if (Misc.use_graphics == Misc.GRAPHICS_NONE || Misc.use_graphics == Misc.GRAPHICS_PSEUDO) grid_get_text(g, ref a, ref c); /* Save the terrain info for the transparency effects */ tap = a; tcp = c; /* If there's an object, deal with that. */ if (g.first_kind != null) { if (g.hallucinate) { /* Just pick a random object to display. */ hallucinatory_object(ref a, ref c); } else if (g.multiple_objects) { /* Get the "pile" feature instead */ a = Object.Object.object_kind_attr(Misc.k_info[0]); c = Object.Object.object_kind_char(Misc.k_info[0]); } else { /* Normal attr and char */ a = Object.Object.object_kind_attr(g.first_kind); c = Object.Object.object_kind_char(g.first_kind); } } /* If there's a monster */ if (g.m_idx > 0 && !Monster.Monster.is_mimicking((int)g.m_idx)) { if (g.hallucinate) { throw new NotImplementedException(); /* Just pick a random monster to display. */ //hallucinatory_monster(&a, &c); } else { Monster.Monster m_ptr = cave_monster(cave, (int)g.m_idx); Monster_Race r_ptr = Misc.r_info[m_ptr.r_idx]; ConsoleColor da; char dc; /* Desired attr & char */ da = r_ptr.x_attr; dc = r_ptr.x_char; /* Special attr/char codes */ if (((int)da & 0x80) != 0 && (dc & 0x80) != 0) { /* Use attr */ a = da; /* Use char */ c = dc; } /* Turn uniques purple if desired (violet, actually) */ else if (Option.purple_uniques.value && r_ptr.flags.has(Monster_Flag.UNIQUE.value)) { /* Use (light) violet attr */ a = ConsoleColor.Magenta; /* Use char */ c = dc; } /* Multi-hued monster */ else if (r_ptr.flags.has(Monster_Flag.ATTR_MULTI.value) || r_ptr.flags.has(Monster_Flag.ATTR_FLICKER.value) || r_ptr.flags.has(Monster_Flag.ATTR_RAND.value)) { /* Multi-hued attr */ a = ((int)m_ptr.attr) != 0 ? m_ptr.attr : da; /* Normal char */ c = dc; } /* Normal monster (not "clear" in any way) */ else if (!r_ptr.flags.test(Monster_Flag.ATTR_CLEAR.value, Monster_Flag.CHAR_CLEAR.value)) { /* Use attr */ a = da; /* Desired attr & char */ da = r_ptr.x_attr; dc = r_ptr.x_char; /* Use char */ c = dc; } /* Hack -- Bizarre grid under monster */ else if (((int)a & 0x80) != 0 || (c & 0x80) != 0) { /* Use attr */ a = da; /* Use char */ c = dc; } /* Normal char, Clear attr, monster */ else if (!r_ptr.flags.has(Monster_Flag.CHAR_CLEAR.value)) { /* Normal char */ c = dc; } /* Normal attr, Clear char, monster */ else if (!r_ptr.flags.has(Monster_Flag.ATTR_CLEAR.value)) { /* Normal attr */ a = da; } /* Store the drawing attr so we can use it elsewhere */ m_ptr.attr = a; } } /* Handle "player" */ else if (g.is_player) { Monster_Race r_ptr = Misc.r_info[0]; //Is 0 supposed to be player?? /* Get the "player" attr */ a = r_ptr.x_attr; if ((Option.hp_changes_color.value) && ((int)a & 0x80) == 0){ switch(Misc.p_ptr.chp * 10 / Misc.p_ptr.mhp) { case 10: case 9: { a = ConsoleColor.White; break; } case 8: case 7: { a = ConsoleColor.Yellow; break; } case 6: case 5: { a = ConsoleColor.DarkYellow; break; } case 4: case 3: { a = ConsoleColor.Red; break; } case 2: case 1: case 0: { a = ConsoleColor.Red; break; } default: { a = ConsoleColor.White; break; } } } /* Get the "player" char */ c = r_ptr.x_char; } /* Result */ ap = a; cp = c; }