summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/view.cc
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2006-11-22 08:41:20 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2006-11-22 08:41:20 +0000
commit1d0f57cbceb778139ca215cc4fcfd1584951f6dd (patch)
treecafd60c944c51fcce778aa5d6912bc548c518339 /crawl-ref/source/view.cc
parent6f5e187a9e5cd348296dba2fd89d2e206e775a01 (diff)
downloadcrawl-ref-1d0f57cbceb778139ca215cc4fcfd1584951f6dd.tar.gz
crawl-ref-1d0f57cbceb778139ca215cc4fcfd1584951f6dd.zip
Merged stone_soup r15:451 into trunk.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@452 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/view.cc')
-rw-r--r--crawl-ref/source/view.cc4399
1 files changed, 1933 insertions, 2466 deletions
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc
index adfb1a62bd..fdbe60d9f3 100644
--- a/crawl-ref/source/view.cc
+++ b/crawl-ref/source/view.cc
@@ -34,10 +34,16 @@
#include "externs.h"
+#include "command.h"
#include "clua.h"
#include "debug.h"
+#include "delay.h"
+#include "direct.h"
+#include "initfile.h"
#include "insult.h"
+#include "itemprop.h"
#include "macro.h"
+#include "misc.h"
#include "monstuff.h"
#include "mon-util.h"
#include "overmap.h"
@@ -48,37 +54,61 @@
#include "stash.h"
#include "travel.h"
+// These are hidden from the rest of the world... use the functions
+// below to get information about the map grid.
+#define MAP_MAGIC_MAPPED_FLAG 0x0100
+#define MAP_SEEN_FLAG 0x0200
+#define MAP_CHANGED_FLAG 0x0400
+#define MAP_DETECTED_MONSTER 0x0800
+#define MAP_DETECTED_ITEM 0x1000
+
+#define MAP_CHARACTER_MASK 0x00ff
+
+struct feature_def
+{
+ unsigned short symbol; // symbol used for seen terrain
+ unsigned short magic_symbol; // symbol used for magic-mapped terrain
+ unsigned short colour; // normal in LoS colour
+ unsigned short map_colour; // colour when out of LoS on display
+ unsigned short seen_colour; // map_colour when is_terrain_seen()
+ bool notable; // gets noted when seen
+ bool seen_effect; // requires special handling when seen
+};
+
+struct feature_override
+{
+ dungeon_feature_type feat;
+ feature_def override;
+};
+
+static FixedVector< struct feature_def, NUM_FEATURES > Feature;
+static std::vector<feature_override> Feature_Overrides;
+
#if defined(DOS_TERM)
-typedef char screen_buffer_t;
+// DOS functions like gettext() and puttext() can only
+// work with arrays of characters, not shorts.
+typedef unsigned char screen_buffer_t;
#else
typedef unsigned short screen_buffer_t;
#endif
-unsigned char your_sign; // accessed as extern in transfor.cc and acr.cc
-unsigned char your_colour; // accessed as extern in transfor.cc and acr.cc
-
-FixedArray < unsigned int, 20, 19 > show_backup;
+FixedArray < unsigned int, 20, 19 > Show_Backup;
unsigned char show_green;
extern int stealth; // defined in acr.cc
-extern FixedVector<char, 10> Visible_Statue; // defined in acr.cc
// char colour_code_map(unsigned char map_value);
screen_buffer_t colour_code_map( int x, int y, bool item_colour = false,
bool travel_colour = false );
-extern void (*viewwindow) (char, bool);
-unsigned char (*mapch) (unsigned char);
-unsigned char (*mapch2) (unsigned char);
-unsigned char mapchar(unsigned char ldfk);
-unsigned char mapchar2(unsigned char ldfk);
-unsigned char mapchar3(unsigned char ldfk);
-unsigned char mapchar4(unsigned char ldfk);
void cloud_grid(void);
void monster_grid(bool do_updates);
-static int display_glyph(int env_glyph);
-static int item_env_glyph(const item_def &item);
+static int get_item_dngn_code(const item_def &item);
+static void set_show_backup( int ex, int ey );
+
+// Applies EC_ colour substitutions and brands.
+static unsigned fix_colour(unsigned raw_colour);
//---------------------------------------------------------------
//
@@ -105,710 +135,209 @@ int get_number_of_lines(void)
{
#ifdef UNIX
return (get_number_of_lines_from_curses());
-#elif MAC
- return (MAC_NUMBER_OF_LINES);
#else
return (25);
#endif
}
-
-//---------------------------------------------------------------
-//
-// get_ibm_symbol
-//
-// Returns the DOS character code and color for everything drawn
-// with the IBM graphics option.
-//
-//---------------------------------------------------------------
-static void get_ibm_symbol(unsigned int object, unsigned short *ch,
- unsigned short *color)
+int get_number_of_cols(void)
{
- ASSERT(color != NULL);
- ASSERT(ch != NULL);
-
- switch (object)
- {
- case DNGN_UNSEEN:
- *ch = 0;
- break;
-
- case DNGN_ROCK_WALL:
- case DNGN_PERMAROCK_WALL:
- *color = env.rock_colour;
- *ch = 177;
- break; // remember earth elementals
-
- // stone in the realm of Zot is coloured the same as rock
- case DNGN_STONE_WALL:
- *color = (player_in_branch( BRANCH_HALL_OF_ZOT ) ? env.rock_colour
- : LIGHTGREY);
- *ch = 177;
- break;
-
- case DNGN_CLOSED_DOOR:
- *ch = 254;
- break;
-
- case DNGN_METAL_WALL:
- *ch = 177;
- *color = CYAN;
- break;
-
- case DNGN_SECRET_DOOR:
- *ch = 177;
- *color = env.rock_colour;
- break;
-
- case DNGN_GREEN_CRYSTAL_WALL:
- *ch = 177;
- *color = GREEN;
- break;
-
- case DNGN_ORCISH_IDOL:
- *ch = '8';
- *color = DARKGREY;
- break;
-
- case DNGN_WAX_WALL:
- *ch = 177;
- *color = YELLOW;
- break; // wax wall
- /* Anything added here must also be added to the PLAIN_TERMINAL
- viewwindow2 below */
-
- case DNGN_SILVER_STATUE:
- *ch = '8';
- *color = WHITE;
- Visible_Statue[ STATUE_SILVER ] = 1;
- break;
-
- case DNGN_GRANITE_STATUE:
- *ch = '8';
- *color = LIGHTGREY;
- break;
-
- case DNGN_ORANGE_CRYSTAL_STATUE:
- *ch = '8';
- *color = LIGHTRED;
- Visible_Statue[ STATUE_ORANGE_CRYSTAL ] = 1;
- break;
-
- case DNGN_LAVA:
- *ch = 247;
- *color = RED;
- break;
-
- case DNGN_DEEP_WATER:
- *ch = 247; // this wavy thing also used for water elemental
- *color = BLUE;
- break;
-
- case DNGN_SHALLOW_WATER:
- *ch = 247; // this wavy thing also used for water elemental
- *color = CYAN;
- break;
-
- case DNGN_FLOOR:
- *color = env.floor_colour;
- *ch = 249;
- break;
-
- case DNGN_ENTER_HELL:
- *ch = 239;
- *color = RED;
- seen_other_thing(object);
- break;
-
- case DNGN_OPEN_DOOR:
- *ch = 39;
- break;
-
- case DNGN_BRANCH_STAIRS:
- *ch = 240;
- *color = BROWN;
- break;
-
- case DNGN_TRAP_MECHANICAL:
- *color = LIGHTCYAN;
- *ch = 94;
- break;
-
- case DNGN_TRAP_MAGICAL:
- *color = MAGENTA;
- *ch = 94;
- break;
-
- case DNGN_TRAP_III:
- *color = LIGHTGREY;
- *ch = 94;
- break;
-
- case DNGN_UNDISCOVERED_TRAP:
- *ch = 249;
- *color = env.floor_colour;
- break;
-
- case DNGN_ENTER_SHOP:
- *ch = 239;
- *color = YELLOW;
-
- seen_other_thing(object);
- break;
- // if I change anything above here, must also change magic mapping!
-
- case DNGN_ENTER_LABYRINTH:
- *ch = 239;
- *color = LIGHTGREY;
- seen_other_thing(object);
- break;
-
- // not sure why we have "odd" here, but "ladders" are special in
- // that they all lead to the first staircase of the next level
- // (and returning from there will take you somewhere different)
- // ... that's why they're brown... it's a warning -- bwr
- case DNGN_ROCK_STAIRS_DOWN:
- *color = BROWN; // ladder // odd {dlb}
- case DNGN_STONE_STAIRS_DOWN_I:
- case DNGN_STONE_STAIRS_DOWN_II:
- case DNGN_STONE_STAIRS_DOWN_III:
- *ch = '>';
- break;
-
- case DNGN_ROCK_STAIRS_UP:
- *color = BROWN; // ladder // odd {dlb}
- case DNGN_STONE_STAIRS_UP_I:
- case DNGN_STONE_STAIRS_UP_II:
- case DNGN_STONE_STAIRS_UP_III:
- *ch = '<';
- break;
-
- case DNGN_ENTER_DIS:
- *color = CYAN;
- *ch = 239;
- break;
-
- case DNGN_ENTER_GEHENNA:
- *color = RED;
- *ch = 239;
- break;
-
- case DNGN_ENTER_COCYTUS:
- *color = LIGHTCYAN;
- *ch = 239;
- break;
-
- case DNGN_ENTER_TARTARUS:
- *color = DARKGREY;
- *ch = 239;
- break;
-
- case DNGN_ENTER_ABYSS:
- *color = random2(16);
- *ch = 239;
- seen_other_thing(object);
- break;
-
- case DNGN_EXIT_ABYSS:
- *color = random2(16);
- *ch = 239;
- break;
-
- case DNGN_STONE_ARCH:
- *color = LIGHTGREY;
- *ch = 239;
- break;
-
- case DNGN_ENTER_PANDEMONIUM:
- *color = LIGHTBLUE;
- *ch = 239;
- seen_other_thing(object);
- break;
-
- case DNGN_EXIT_PANDEMONIUM:
- *color = LIGHTBLUE;
- *ch = 239;
- break;
-
- case DNGN_TRANSIT_PANDEMONIUM:
- *color = LIGHTGREEN;
- *ch = 239;
- break;
-
- case DNGN_ENTER_ORCISH_MINES:
- case DNGN_ENTER_HIVE:
- case DNGN_ENTER_LAIR:
- case DNGN_ENTER_SLIME_PITS:
- case DNGN_ENTER_VAULTS:
- case DNGN_ENTER_CRYPT:
- case DNGN_ENTER_HALL_OF_BLADES:
- case DNGN_ENTER_TEMPLE:
- case DNGN_ENTER_SNAKE_PIT:
- case DNGN_ENTER_ELVEN_HALLS:
- case DNGN_ENTER_TOMB:
- case DNGN_ENTER_SWAMP:
- case 123:
- case 124:
- case 125:
- case 126:
- *color = YELLOW;
- *ch = '>';
- seen_staircase(object);
- break;
-
- case DNGN_ENTER_ZOT:
- *color = MAGENTA;
- *ch = 239;
- seen_staircase(object);
- break;
-
- case DNGN_RETURN_FROM_ORCISH_MINES:
- case DNGN_RETURN_FROM_HIVE:
- case DNGN_RETURN_FROM_LAIR:
- case DNGN_RETURN_FROM_SLIME_PITS:
- case DNGN_RETURN_FROM_VAULTS:
- case DNGN_RETURN_FROM_CRYPT:
- case DNGN_RETURN_FROM_HALL_OF_BLADES:
- case DNGN_RETURN_FROM_TEMPLE:
- case DNGN_RETURN_FROM_SNAKE_PIT:
- case DNGN_RETURN_FROM_ELVEN_HALLS:
- case DNGN_RETURN_FROM_TOMB:
- case DNGN_RETURN_FROM_SWAMP:
- case 143:
- case 144:
- case 145:
- case 146:
- *color = YELLOW;
- *ch = '<';
- break;
-
- case DNGN_RETURN_FROM_ZOT:
- *color = MAGENTA;
- *ch = 239;
- break;
-
- case DNGN_ALTAR_ZIN:
- *color = WHITE;
- *ch = 220;
- seen_altar(GOD_ZIN);
- break;
-
- case DNGN_ALTAR_SHINING_ONE:
- *color = YELLOW;
- *ch = 220;
- seen_altar(GOD_SHINING_ONE);
- break;
-
- case DNGN_ALTAR_KIKUBAAQUDGHA:
- *color = DARKGREY;
- *ch = 220;
- seen_altar(GOD_KIKUBAAQUDGHA);
- break;
-
- case DNGN_ALTAR_YREDELEMNUL:
- *color = ((one_chance_in(3)) ? RED : DARKGREY);
- *ch = 220;
- seen_altar(GOD_YREDELEMNUL);
- break;
-
- case DNGN_ALTAR_XOM:
- *color = random_colour();
- *ch = 220;
- seen_altar(GOD_XOM);
- break;
-
- case DNGN_ALTAR_VEHUMET:
- *color = LIGHTBLUE;
- if (one_chance_in(3))
- *color = LIGHTMAGENTA;
- if (one_chance_in(3))
- *color = LIGHTRED;
- *ch = 220;
- seen_altar(GOD_VEHUMET);
- break;
-
- case DNGN_ALTAR_OKAWARU:
- *color = CYAN;
- *ch = 220;
- seen_altar(GOD_OKAWARU);
- break;
-
- case DNGN_ALTAR_MAKHLEB:
- *color = RED;
- if (one_chance_in(3))
- *color = LIGHTRED;
- if (one_chance_in(3))
- *color = YELLOW;
- *ch = 220;
- seen_altar(GOD_MAKHLEB);
- break;
-
- case DNGN_ALTAR_SIF_MUNA:
- *color = BLUE;
- *ch = 220;
- seen_altar(GOD_SIF_MUNA);
- break;
-
- case DNGN_ALTAR_TROG:
- *color = RED;
- *ch = 220;
- seen_altar(GOD_TROG);
- break;
-
- case DNGN_ALTAR_NEMELEX_XOBEH:
- *color = LIGHTMAGENTA;
- *ch = 220;
- seen_altar(GOD_NEMELEX_XOBEH);
- break;
-
- case DNGN_ALTAR_ELYVILON:
- *color = LIGHTGREY;
- *ch = 220;
- seen_altar(GOD_ELYVILON);
- break;
-
- case DNGN_BLUE_FOUNTAIN:
- *color = BLUE;
- *ch = 159;
- break;
-
- case DNGN_SPARKLING_FOUNTAIN:
- *color = LIGHTBLUE;
- *ch = 159;
- break;
-
- case DNGN_DRY_FOUNTAIN_I:
- case DNGN_DRY_FOUNTAIN_II:
- case DNGN_PERMADRY_FOUNTAIN:
- *color = LIGHTGREY;
- *ch = 159;
- break;
-
- case 256:
- *ch = '0';
- break;
-
- case 257:
- *color = CYAN;
- *ch = '~';
- break; /* Invis creature walking through water */
-
- case 258:
- *ch = ')';
- break; // weapon )
-
- case 259:
- *ch = '[';
- break; // armour [
-
- case 260:
- *ch = '/';
- break; // wands, etc.
-
- case 261:
- *ch = '%';
- break; // food
-
- case 262:
- *ch = '+';
- break; // books +
-
- case 263:
- *ch = '?';
- break; // scroll ?
-
- case 264:
- *ch = '=';
- break; // ring = etc
-
- case 265:
- *ch = '!';
- break; // potions !
+#ifdef UNIX
+ return (get_number_of_cols_from_curses());
+#else
+ return (80);
+#endif
+}
- case 266:
- *ch = '(';
- break; // stones
+unsigned get_envmap_char(int x, int y)
+{
+ return static_cast<unsigned char>(
+ env.map[x - 1][y - 1] & MAP_CHARACTER_MASK);
+}
- case 267:
- *ch = '+';
- break; // book +
+void set_envmap_detected_item(int x, int y, bool detected)
+{
+ if (detected)
+ env.map[x - 1][y - 1] |= MAP_DETECTED_ITEM;
+ else
+ env.map[x - 1][y - 1] &= ~MAP_DETECTED_ITEM;
+}
- case 268:
- *ch = '%';
- break; // corpses part 1
+bool is_envmap_detected_item(int x, int y)
+{
+ return (env.map[x - 1][y - 1] & MAP_DETECTED_ITEM);
+}
- case 269:
- *ch = '\\';
- break; // magical staves
+void set_envmap_detected_mons(int x, int y, bool detected)
+{
+ if (detected)
+ env.map[x - 1][y - 1] |= MAP_DETECTED_MONSTER;
+ else
+ env.map[x - 1][y - 1] &= ~MAP_DETECTED_MONSTER;
+}
- case 270:
- *ch = '}';
- break; // gems
+bool is_envmap_detected_mons(int x, int y)
+{
+ return (env.map[x - 1][y - 1] & MAP_DETECTED_MONSTER);
+}
- case 271:
- *ch = '%';
- break; // don't know ?
+void set_envmap_char( int x, int y, unsigned char chr )
+{
+ env.map[x - 1][y - 1] &= (~MAP_CHARACTER_MASK); // clear old first
+ env.map[x - 1][y - 1] |= chr;
+}
- case 272:
- *ch = '$';
- *color = YELLOW;
- break; // $ gold
+bool is_terrain_known( int x, int y )
+{
+ return (env.map[x - 1][y - 1] & (MAP_MAGIC_MAPPED_FLAG | MAP_SEEN_FLAG));
+}
- case 273:
- *ch = '"';
- break; // amulet
+bool is_terrain_seen( int x, int y )
+{
+ return (env.map[x - 1][y - 1] & MAP_SEEN_FLAG);
+}
- default:
- *ch = ((object >= 297) ? mons_char(object - 297) : object);
- break;
- }
-} // end get_ibm_symbol()
+bool is_terrain_changed( int x, int y )
+{
+ return (env.map[x - 1][y - 1] & MAP_CHANGED_FLAG);
+}
-//---------------------------------------------------------------
-//
-// viewwindow2
-//
-// Draws the main window using the extended IBM character set.
-//
-// This function should not interfer with the game condition,
-// unless do_updates is set (ie. stealth checks for visible
-// monsters).
-//
-//---------------------------------------------------------------
-void viewwindow2(char draw_it, bool do_updates)
+// used to mark dug out areas, unset when terrain is seen or mapped again.
+void set_terrain_changed( int x, int y )
{
- const long BUFFER_SIZE = 1550;
-#ifdef DOS_TERM
- // DOS functions like gettext() and puttext() can only
- // work with arrays of characters, not shorts.
- FixedVector < unsigned char, BUFFER_SIZE > buffy; //[800]; //392];
-#else
- FixedVector < unsigned short, BUFFER_SIZE > buffy; //[800]; //392];
-#endif
+ env.map[x - 1][y - 1] |= MAP_CHANGED_FLAG;
+}
- unsigned short ch, color;
+void set_terrain_mapped( int x, int y )
+{
+ env.map[x - 1][y - 1] &= (~MAP_CHANGED_FLAG);
+ env.map[x - 1][y - 1] |= MAP_MAGIC_MAPPED_FLAG;
+}
- losight(env.show, grd, you.x_pos, you.y_pos);
+void set_terrain_seen( int x, int y )
+{
+ env.map[x - 1][y - 1] &= (~MAP_CHANGED_FLAG);
+ env.map[x - 1][y - 1] |= MAP_SEEN_FLAG;
+}
- int count_x, count_y;
+void clear_envmap_grid( int x, int y )
+{
+ env.map[x - 1][y - 1] = 0;
+}
- for (count_x = 0; count_x < 18; count_x++)
+void clear_envmap( void )
+{
+ for (int i = 0; i < GXM; i++)
{
- for (count_y = 0; count_y < 18; count_y++)
+ for (int j = 0; j < GYM; j++)
{
- env.show_col[count_x][count_y] = LIGHTGREY;
- show_backup[count_x][count_y] = 0;
+ env.map[i][j] = 0;
}
}
+}
- item();
- cloud_grid();
- monster_grid(do_updates);
- int bufcount = 0;
-
- if (draw_it == 1)
+#if defined(WIN32CONSOLE) || defined(DOS) || defined(DOS_TERM)
+static unsigned colflag2brand(int colflag)
+{
+ switch (colflag)
{
- _setcursortype(_NOCURSOR);
- for (count_y = you.y_pos - 8; count_y < you.y_pos + 9; count_y++)
- {
- bufcount += 16;
-
- for (count_x = you.x_pos - 8; count_x < you.x_pos + 9; count_x++)
- {
- // may be overriden by the code below
- color = env.show_col[ count_x - you.x_pos + 9 ]
- [ count_y - you.y_pos + 9 ];
-
- unsigned int object = env.show[ count_x - you.x_pos + 9 ]
- [ count_y - you.y_pos + 9 ];
-
- get_ibm_symbol(object, &ch, &color);
-
- if (count_x == you.x_pos && count_y == you.y_pos)
- {
- ch = your_sign;
-
- if (player_is_swimming())
- {
- color = (grd[you.x_pos][you.y_pos] == DNGN_DEEP_WATER)
- ? BLUE : CYAN;
- }
- else
- {
- color = your_colour;
- }
- }
-
- ASSERT(bufcount + 1 < BUFFER_SIZE);
- buffy[bufcount] = ch;
- buffy[bufcount + 1] = color;
-
- bufcount += 2;
- }
-
- bufcount += 16;
- }
-
- if (you.level_type != LEVEL_LABYRINTH && you.level_type != LEVEL_ABYSS)
- {
- bufcount = 0;
-
- for (count_y = 0; count_y < 17; count_y++)
- {
- bufcount += 16;
-
- for (count_x = 0; count_x < 17; count_x++)
- {
- ASSERT(bufcount < BUFFER_SIZE);
+ case COLFLAG_ITEM_HEAP:
+ return (Options.heap_brand);
+ case COLFLAG_FRIENDLY_MONSTER:
+ return (Options.friend_brand);
+ case COLFLAG_WILLSTAB:
+ return (Options.stab_brand);
+ case COLFLAG_MAYSTAB:
+ return (Options.may_stab_brand);
+ default:
+ return (CHATTR_NORMAL);
+ }
+}
+#endif
- int mapx = count_x + you.x_pos - 9;
- int mapy = count_y + you.y_pos - 9;
- if (buffy[bufcount] != 0 && mapx >= 0 && mapx + 1 < GXM
- && mapy >= 0 && mapy + 1 < GYM)
- {
- unsigned short bch = buffy[bufcount];
- if (mgrd[mapx + 1][mapy + 1] != NON_MONSTER) {
- const monsters &m = menv[mgrd[mapx + 1][mapy + 1]];
- if (!mons_is_mimic(m.type)
- && mons_char(m.type) == bch)
- {
- bch |= mons_colour(m.type) << 12;
- }
- }
- env.map[mapx][mapy] = bch;
- }
+static unsigned fix_colour(unsigned raw_colour)
+{
+ // This order is important - is_element_colour() doesn't want to see the
+ // munged colours returned by dos_brand, so it should always be done
+ // before applying DOS brands.
+#if defined(WIN32CONSOLE) || defined(DOS) || defined(DOS_TERM)
+ const int colflags = raw_colour & 0xFF00;
+#endif
- if (Options.clean_map == 1
- && show_backup[count_x + 1][count_y + 1] != 0)
- {
- get_ibm_symbol(show_backup[count_x + 1][count_y + 1],
- &ch, &color);
- if (mapx >= 0 && mapx < GXM
- && mapy >= 0 && mapy < GYM)
- env.map[ count_x + you.x_pos - 9 ]
- [ count_y + you.y_pos - 9 ] = ch;
- }
- bufcount += 2;
- }
- bufcount += 16;
- }
- }
+ // Evaluate any elemental colours to guarantee vanilla colour is returned
+ if (is_element_colour( raw_colour ))
+ raw_colour = element_colour( raw_colour );
- bufcount = 0;
- for (count_y = 0; count_y < 17; count_y++)
- {
- for (count_x = 0; count_x < 33; count_x++)
- {
- if (count_x + you.x_pos - 17 < 3
- || count_y + you.y_pos - 9 < 3
- || count_x + you.x_pos - 14 > 77
- || count_y + you.y_pos - 9 > 67)
- {
- ASSERT(bufcount < BUFFER_SIZE);
- buffy[bufcount] = 0;
- bufcount++;
- buffy[bufcount] = 0;
- bufcount++;
- continue;
- }
+#if defined(WIN32CONSOLE) || defined(DOS) || defined(DOS_TERM)
+ if (colflags)
+ {
+ unsigned brand = colflag2brand(colflags);
+ raw_colour = dos_brand(raw_colour & 0xFF, brand);
+ }
+#endif
- if (count_x >= 8 && count_x <= 24 && count_y >= 0
- && count_y <= 16 && buffy[bufcount] != 0)
- {
- bufcount += 2;
- continue;
- }
+#ifndef USE_COLOUR_OPTS
+ // Strip COLFLAGs for systems that can't do anything meaningful with them.
+ raw_colour &= 0xFF;
+#endif
- ASSERT(bufcount + 1 < BUFFER_SIZE);
+ return (raw_colour);
+}
- buffy[bufcount] = (unsigned char)
- env.map[ count_x + you.x_pos - 17 ]
- [ count_y + you.y_pos - 9 ];
+static void get_symbol( unsigned int object, unsigned short *ch,
+ unsigned short *colour )
+{
+ ASSERT( ch != NULL );
+ ASSERT( colour != NULL );
- buffy[bufcount + 1] = DARKGREY;
- if (Options.colour_map)
- {
- if (env.map[ count_x + you.x_pos - 17 ]
- [ count_y + you.y_pos - 9 ] != 0)
- {
- buffy[bufcount + 1]
- = colour_code_map( count_x + you.x_pos - 17,
- count_y + you.y_pos - 9,
- Options.item_colour );
- }
- }
- bufcount += 2;
- }
- }
+ if (object < NUM_FEATURES)
+ {
+ *ch = Feature[object].symbol;
- if (you.berserker)
- {
- for (count_x = 1; count_x < 1400; count_x += 2)
- {
- if (buffy[count_x] != DARKGREY)
- buffy[count_x] = RED;
- }
- }
+ // Don't clobber with BLACK, because the colour should be already set.
+ if (Feature[object].colour != BLACK)
+ *colour = Feature[object].colour;
- if (show_green != BLACK)
- {
- for (count_x = 1; count_x < 1400; count_x += 2)
- {
- if (buffy[count_x] != DARKGREY)
- buffy[count_x] = show_green;
- }
+ // Note anything we see that's notable
+ if (Feature[object].notable)
+ seen_notable_thing( object );
+ }
+ else
+ {
+ ASSERT( object >= DNGN_START_OF_MONSTERS );
+ *ch = mons_char( object - DNGN_START_OF_MONSTERS );
+ }
- show_green = BLACK;
+ *colour = fix_colour(*colour);
+}
- if (you.special_wield == SPWLD_SHADOW)
- show_green = DARKGREY;
- }
+unsigned char get_sightmap_char( int feature )
+{
+ if (feature < NUM_FEATURES)
+ return (Feature[feature].symbol);
-#ifdef DOS_TERM
- puttext(2, 1, 34, 17, buffy.buffer());
-#endif
+ return (0);
+}
-#ifdef PLAIN_TERM
- gotoxy(2, 1);
- bufcount = 0;
+unsigned char get_magicmap_char( int feature )
+{
+ if (feature < NUM_FEATURES)
+ return (Feature[feature].magic_symbol);
- // following lines are purely optional.
- // if used, players will 'jump' move.
- // Resting will be a LOT faster too.
- if (you.running == 0 || (you.running < 0 && Options.travel_delay > -1))
- {
- for (count_x = 0; count_x < 1120; count_x += 2)
- { // 1056
- ch = buffy[count_x];
- color = buffy[count_x + 1];
-// ASSERT(color < 16);
- ASSERT(ch < 255);
-
- textcolor(color);
- putch(ch);
-
- if (count_x % 66 == 64 && count_x > 0)
- gotoxy(2, wherey() + 1);
- }
- // remember to comment out the line below if you comment out jump move.
- }
- _setcursortype(_NORMALCURSOR);
-#endif
- }
-} // end viewwindow2()
+ return (0);
+}
static char get_travel_colour( int x, int y )
{
if (is_waypoint(x + 1, y + 1))
return LIGHTGREEN;
- short dist = point_distance[x + 1]
- [y + 1];
- return dist > 0 ? BLUE :
- dist == PD_EXCLUDED ? LIGHTMAGENTA :
- dist == PD_EXCLUDED_RADIUS ? RED :
- dist < 0 ? CYAN :
- DARKGREY;
+ short dist = point_distance[x + 1][y + 1];
+ return dist > 0? Options.tc_reachable :
+ dist == PD_EXCLUDED? Options.tc_excluded :
+ dist == PD_EXCLUDED_RADIUS? Options.tc_exclude_circle :
+ dist < 0? Options.tc_dangerous :
+ Options.tc_disconnected;
}
#if defined(WIN32CONSOLE) || defined(DOS)
@@ -819,9 +348,7 @@ static unsigned short dos_reverse_brand(unsigned short colour)
// If the console treats the intensity bit on background colours
// correctly, we can do a very simple colour invert.
- // Special casery for shadows. Note this must be matched by the fix
- // to libw32c.cc (the unpatched libw32c.cc does not draw spaces of any
- // colour).
+ // Special casery for shadows.
if (colour == BLACK)
colour = (DARKGREY << 4);
else
@@ -874,8 +401,8 @@ static unsigned short dos_hilite_brand(unsigned short colour,
return (colour);
}
-static unsigned short dos_brand( unsigned short colour,
- unsigned brand = CHATTR_REVERSE )
+unsigned short dos_brand( unsigned short colour,
+ unsigned brand)
{
if ((brand & CHATTR_ATTRMASK) == CHATTR_NORMAL)
return (colour);
@@ -890,199 +417,98 @@ static unsigned short dos_brand( unsigned short colour,
}
#endif
+// FIXME: Rework this function to use the new terrain known/seen checks
+// These are still env.map coordinates, NOT grid coordinates!
screen_buffer_t colour_code_map( int x, int y, bool item_colour,
bool travel_colour )
{
// XXX: Yes, the map array and the grid array are off by one. -- bwr
const int map_value = (unsigned char) env.map[x][y];
- const unsigned short map_flags = env.map[x][y] & ENVF_FLAGS;
+ const unsigned short map_flags = env.map[x][y];
const int grid_value = grd[x + 1][y + 1];
- char tc = travel_colour? get_travel_colour(x, y) : DARKGREY;
+ unsigned tc = travel_colour?
+ get_travel_colour(x, y)
+ : DARKGREY;
- if (map_flags & ENVF_DETECT_ITEM)
+ if (map_flags & MAP_DETECTED_ITEM)
tc = Options.detected_item_colour;
- if (map_flags & ENVF_DETECT_MONS) {
+ if (map_flags & MAP_DETECTED_MONSTER)
+ {
tc = Options.detected_monster_colour;
- return (tc);
+ return fix_colour(tc);
}
- unsigned char ecol = ENVF_COLOR(map_flags);
- if (ecol) {
- unsigned rmc = Options.remembered_monster_colour & 0xFFFF;
- if (rmc == 0xFFFF) // Use real colour
- tc = ecol;
- else if (rmc == 0) // Don't colour
- ;
- else
- tc = rmc;
- }
-
// XXX: [ds] If we've an important colour, override other feature
// colouring. Yes, this is hacky. Story of my life.
if (tc == LIGHTGREEN || tc == LIGHTMAGENTA)
- return tc;
+ return fix_colour(tc);
// XXX: Yeah, this is ugly, but until we have stored layers in the
// map we can't tell if we've seen a square, detected it, or just
// detected the item or monster on top... giving colour here will
// result in detect creature/item detecting features like stairs. -- bwr
- if (map_value != mapch2( grid_value )) {
+ if (map_value != get_sightmap_char(grid_value))
+ {
// If there's an item on this square, change colour to indicate
// that, iff the item's glyph matches map_value. XXX: Potentially
// abusable? -- ds
int item = igrd[x + 1][y + 1];
if (item_colour && item != NON_ITEM
- && map_value == display_glyph(item_env_glyph(mitm[item])))
+ && map_value ==
+ get_sightmap_char(get_item_dngn_code(mitm[item])))
{
- screen_buffer_t ic = mitm[item].colour;
+ unsigned ic = mitm[item].colour;
-#if defined(WIN32CONSOLE) || defined(DOS) || defined(DOS_TERM)
- if (mitm[item].link != NON_ITEM
- && Options.heap_brand != CHATTR_NORMAL)
- {
- ic = dos_brand(ic, Options.heap_brand);
- }
-#elif defined(USE_COLOUR_OPTS)
if (mitm[item].link != NON_ITEM )
- {
ic |= COLFLAG_ITEM_HEAP;
- }
-#endif
+
// If the item colour is the background colour, tweak it to WHITE
// instead to catch the player's eye.
- return ic == tc? WHITE : ic;
+ return fix_colour( ic == tc? WHITE : ic );
}
-
- return tc;
}
- switch (grid_value)
- {
- case DNGN_TRAP_MECHANICAL:
- return (LIGHTCYAN);
-
- case DNGN_TRAP_MAGICAL:
- case DNGN_TRAP_III:
- return (MAGENTA);
-
- case DNGN_ENTER_SHOP:
- return (YELLOW);
-
- case DNGN_ENTER_DIS:
- return (CYAN);
-
- case DNGN_ENTER_HELL:
- case DNGN_ENTER_GEHENNA:
- return (RED);
-
- case DNGN_ENTER_COCYTUS:
- return (LIGHTCYAN);
-
- case DNGN_ENTER_ABYSS:
- return random2(16); // so it can be black - is this right? {dlb}
-
- case DNGN_ENTER_LABYRINTH:
- case DNGN_STONE_ARCH:
- return (LIGHTGREY);
+ int feature_colour = DARKGREY;
+ feature_colour =
+ is_terrain_seen(x + 1, y + 1)? Feature[grid_value].seen_colour
+ : Feature[grid_value].map_colour;
- case DNGN_ENTER_PANDEMONIUM:
- return (LIGHTBLUE);
+ if (feature_colour != DARKGREY)
+ tc = feature_colour;
- case DNGN_EXIT_PANDEMONIUM:
- // Exit pandemonium gates won't show up on the map as light blue
- // unless the character has the "gate to pandemonium" demonspawn
- // mutation. This is so that the player can't quickly use a
- // crystal ball to find their way out. -- bwr
- return (you.mutation[MUT_PANDEMONIUM] ? LIGHTBLUE : LIGHTGREEN);
-
- case DNGN_TRANSIT_PANDEMONIUM:
- return (LIGHTGREEN);
-
- case DNGN_ENTER_ZOT:
- case DNGN_RETURN_FROM_ZOT:
- return (MAGENTA);
-
- case DNGN_STONE_STAIRS_DOWN_I:
- case DNGN_STONE_STAIRS_DOWN_II:
- case DNGN_STONE_STAIRS_DOWN_III:
- case DNGN_ROCK_STAIRS_DOWN:
- return (RED);
-
- case DNGN_STONE_STAIRS_UP_I:
- case DNGN_STONE_STAIRS_UP_II:
- case DNGN_STONE_STAIRS_UP_III:
- case DNGN_ROCK_STAIRS_UP:
- return (GREEN);
-
- case DNGN_ENTER_ORCISH_MINES:
- case DNGN_ENTER_HIVE:
- case DNGN_ENTER_LAIR:
- case DNGN_ENTER_SLIME_PITS:
- case DNGN_ENTER_VAULTS:
- case DNGN_ENTER_CRYPT:
- case DNGN_ENTER_HALL_OF_BLADES:
- case DNGN_ENTER_TEMPLE:
- case DNGN_ENTER_SNAKE_PIT:
- case DNGN_ENTER_ELVEN_HALLS:
- case DNGN_ENTER_TOMB:
- case DNGN_ENTER_SWAMP:
- case 123:
- case 124:
- case 125:
- case 126:
- return (LIGHTRED);
-
- case DNGN_RETURN_FROM_ORCISH_MINES:
- case DNGN_RETURN_FROM_HIVE:
- case DNGN_RETURN_FROM_LAIR:
- case DNGN_RETURN_FROM_SLIME_PITS:
- case DNGN_RETURN_FROM_VAULTS:
- case DNGN_RETURN_FROM_CRYPT:
- case DNGN_RETURN_FROM_HALL_OF_BLADES:
- case DNGN_RETURN_FROM_TEMPLE:
- case DNGN_RETURN_FROM_SNAKE_PIT:
- case DNGN_RETURN_FROM_ELVEN_HALLS:
- case DNGN_RETURN_FROM_TOMB:
- case DNGN_RETURN_FROM_SWAMP:
- case 143:
- case 144:
- case 145:
- case 146:
- return (LIGHTBLUE);
-
- default:
- break;
- }
-
- return tc;
+ return fix_colour(tc);
}
void clear_map()
{
- for (int y = 0; y < GYM - 1; ++y)
+ for (int y = Y_BOUND_1; y <= Y_BOUND_2; ++y)
{
- for (int x = 0; x < GXM - 1; ++x)
+ for (int x = X_BOUND_1; x <= X_BOUND_2; ++x)
{
- unsigned short envc = env.map[x][y];
- if (!envc)
+ // Don't expose new dug out areas:
+ // Note: assumptions are being made here about how
+ // terrain can change (eg it used to be solid, and
+ // thus monster/item free).
+ if (is_terrain_changed(x, y))
continue;
- bool unmapped = (envc & ENVF_DETECTED) != 0;
- // Discard flags at this point.
- envc = (unsigned char) envc;
-
- const unsigned char &grdc = grd[x + 1][y + 1];
- if (envc == mapch(grdc) || envc == mapch2(grdc))
+ unsigned short envc = env.map[x][y] & MAP_CHARACTER_MASK;
+ if (!envc)
continue;
- int item = igrd[x + 1][y + 1];
+ const int item = igrd[x + 1][y + 1];
if (item != NON_ITEM
- && envc == display_glyph(item_env_glyph(mitm[item])))
+ && envc ==
+ get_sightmap_char(get_item_dngn_code(mitm[item])))
continue;
- env.map[x][y] = unmapped? 0 : mapch2(grdc);
+ set_envmap_char(x, y,
+ is_terrain_seen(x, y)? get_sightmap_char(grd[x][y]) :
+ is_terrain_known(x, y)? get_magicmap_char(grd[x][y]) :
+ 0);
+ set_envmap_detected_mons(x, y, false);
}
}
}
@@ -1104,7 +530,7 @@ void monster_grid(bool do_updates)
{
behaviour_event( monster, ME_ALERT, MHITYOU );
- if (you.turn_is_over == 1
+ if (you.turn_is_over
&& mons_shouts(monster->type) > 0
&& random2(30) >= you.skills[SK_STEALTH])
{
@@ -1194,127 +620,50 @@ void monster_grid(bool do_updates)
}
}
+ const int ex = monster->x - you.x_pos + 9;
+ const int ey = monster->y - you.y_pos + 9;
+
if (!player_monster_visible( monster ))
{
// ripple effect?
if (grd[monster->x][monster->y] == DNGN_SHALLOW_WATER
&& !mons_flies(monster))
{
- show_backup[ monster->x - you.x_pos + 9 ]
- [ monster->y - you.y_pos + 9]
- = env.show[ monster->x - you.x_pos + 9 ]
- [ monster->y - you.y_pos + 9 ];
- env.show[monster->x - you.x_pos + 9]
- [monster->y - you.y_pos + 9] = 257;
+ set_show_backup(ex, ey);
+ env.show[ex][ey] = DNGN_INVIS_EXPOSED;
+ env.show_col[ex][ey] = BLUE;
}
continue;
}
else if (!mons_friendly( monster )
&& !mons_is_mimic( monster->type )
- && !mons_flag( monster->type, M_NO_EXP_GAIN ))
+ && !mons_class_flag( monster->type, M_NO_EXP_GAIN ))
{
- interrupt_activity( AI_SEE_MONSTER );
- if (you.running != 0
-#ifdef CLUA_BINDINGS
- && clua.callbooleanfn(true, "ch_stop_run",
- "M", monster)
-#endif
- )
- {
- // Friendly monsters, mimics, or harmless monsters
- // don't disturb the player's running/resting.
- //
- // Doing it this way causes players in run mode 2
- // to move one square, and in mode 1 to stop. This
- // means that the character will run one square if
- // a monster is in sight... we automatically jump
- // to zero if we're resting. -- bwr
- if (you.run_x == 0 && you.run_y == 0)
- stop_running();
- else if (you.running > 1)
- you.running--;
- else
- stop_running();
- }
+ interrupt_activity( AI_SEE_MONSTER, monster );
+ seen_monster( monster );
}
// mimics are always left on map
if (!mons_is_mimic( monster->type ))
- {
- show_backup[monster->x - you.x_pos + 9]
- [monster->y - you.y_pos + 9]
- = env.show[monster->x - you.x_pos + 9]
- [monster->y - you.y_pos + 9];
- }
+ set_show_backup(ex, ey);
- env.show[monster->x - you.x_pos + 9]
- [monster->y - you.y_pos + 9] = monster->type + 297;
+ env.show[ex][ey] = monster->type + DNGN_START_OF_MONSTERS;
+ env.show_col[ex][ey] = monster->colour;
- env.show_col[monster->x - you.x_pos + 9]
- [monster->y - you.y_pos + 9]
- = ((mcolour[monster->type] == BLACK)
- ? monster->number : mcolour[monster->type]);
-#ifdef USE_COLOUR_OPTS
if (mons_friendly(monster))
{
- env.show_col[monster->x - you.x_pos + 9]
- [monster->y - you.y_pos + 9]
- |= COLFLAG_FRIENDLY_MONSTER;
+ env.show_col[ex][ey] |= COLFLAG_FRIENDLY_MONSTER;
}
else if (Options.stab_brand != CHATTR_NORMAL
- && !mons_is_mimic(monster->type)
- && monster->type != MONS_OKLOB_PLANT
- && mons_is_stabbable(monster))
+ && mons_looks_stabbable(monster))
{
- env.show_col[monster->x - you.x_pos + 9]
- [monster->y - you.y_pos + 9]
- |= COLFLAG_WILLSTAB;
+ env.show_col[ex][ey] |= COLFLAG_WILLSTAB;
}
else if (Options.may_stab_brand != CHATTR_NORMAL
- && !mons_is_mimic(monster->type)
- && monster->type != MONS_OKLOB_PLANT
- && mons_maybe_stabbable(monster))
- {
- env.show_col[monster->x - you.x_pos + 9]
- [monster->y - you.y_pos + 9]
- |= COLFLAG_MAYSTAB;
- }
-
-#elif defined(WIN32CONSOLE) || defined(DOS)
- if (Options.friend_brand != CHATTR_NORMAL
- && mons_friendly(monster))
+ && mons_looks_distracted(monster))
{
- // We munge the colours right here for DOS and Windows, because
- // we know exactly how the colours will be handled, and we don't
- // want to change both DOS and Windows port code to handle
- // friend branding.
- unsigned short &colour =
- env.show_col[monster->x - you.x_pos + 9]
- [monster->y - you.y_pos + 9];
- colour = dos_brand(colour, Options.friend_brand);
+ env.show_col[ex][ey] |= COLFLAG_MAYSTAB;
}
-
- if (Options.stab_brand != CHATTR_NORMAL
- && !mons_is_mimic(monster->type)
- && monster->type != MONS_OKLOB_PLANT
- && mons_is_stabbable(monster))
- {
- unsigned short &colour =
- env.show_col[monster->x - you.x_pos + 9]
- [monster->y - you.y_pos + 9];
- colour = dos_brand(colour, Options.stab_brand);
- }
- else if (Options.may_stab_brand != CHATTR_NORMAL
- && !mons_is_mimic(monster->type)
- && monster->type != MONS_OKLOB_PLANT
- && mons_maybe_stabbable(monster))
- {
- unsigned short &colour =
- env.show_col[monster->x - you.x_pos + 9]
- [monster->y - you.y_pos + 9];
- colour = dos_brand(colour, Options.may_stab_brand);
- }
-#endif
} // end "if (monster->type != -1 && mons_ner)"
} // end "for s"
} // end monster_grid()
@@ -1324,7 +673,7 @@ bool check_awaken(int mons_aw)
{
int mons_perc = 0;
struct monsters *monster = &menv[mons_aw];
- const int mon_holy = mons_holiness( monster->type );
+ const int mon_holy = mons_holiness(monster);
// berserkers aren't really concerned about stealth
if (you.berserker)
@@ -1344,9 +693,9 @@ bool check_awaken(int mons_aw)
+ mons_see_invis(monster) * 5;
// critters that are wandering still have MHITYOU as their foe are
- // still actively on guard for the player, even if they can't see
+ // still actively on guard for the player, even if they can't see
// him. Give them a large bonus (handle_behaviour() will nuke 'foe'
- // after a while, removing this bonus.
+ // after a while, removing this bonus.
if (monster->behaviour == BEH_WANDER && monster->foe == MHITYOU)
mons_perc += 15;
@@ -1380,58 +729,52 @@ bool check_awaken(int mons_aw)
return (random2(stealth) <= mons_perc);
} // end check_awaken()
-static int display_glyph(int env_glyph)
+static void set_show_backup( int ex, int ey )
{
- unsigned short ch, color;
- if (viewwindow == viewwindow2)
- get_ibm_symbol(env_glyph, &ch, &color);
- else
- get_non_ibm_symbol(env_glyph, &ch, &color);
- return ch;
+ // Must avoid double setting it.
+ // We want the base terrain/item, not the cloud or monster that replaced it.
+ if (!Show_Backup[ex][ey])
+ Show_Backup[ex][ey] = env.show[ex][ey];
}
-static int item_env_glyph(const item_def &item)
+static int get_item_dngn_code(const item_def &item)
{
switch (item.base_type)
{
case OBJ_ORBS:
- return 256;
- // need + 6 because show is 0 - 12, not -6 - +6
+ return (DNGN_ITEM_ORB);
case OBJ_WEAPONS:
+ return (DNGN_ITEM_WEAPON);
case OBJ_MISSILES:
- return 258;
+ return (DNGN_ITEM_MISSILE);
case OBJ_ARMOUR:
- return 259;
+ return (DNGN_ITEM_ARMOUR);
case OBJ_WANDS:
- return 260;
+ return (DNGN_ITEM_WAND);
case OBJ_FOOD:
- return 261;
- case OBJ_UNKNOWN_I:
- return 262;
+ return (DNGN_ITEM_FOOD);
case OBJ_SCROLLS:
- return 263;
+ return (DNGN_ITEM_SCROLL);
case OBJ_JEWELLERY:
- return item.sub_type >= AMU_RAGE? 273 : 264;
+ return (jewellery_is_amulet(item)? DNGN_ITEM_AMULET : DNGN_ITEM_RING);
case OBJ_POTIONS:
- return 265;
- case OBJ_UNKNOWN_II:
- return 266;
+ return (DNGN_ITEM_POTION);
case OBJ_BOOKS:
- return 267;
+ return (DNGN_ITEM_BOOK);
case OBJ_STAVES:
- return 269;
+ return (DNGN_ITEM_STAVE);
case OBJ_MISCELLANY:
- return 270;
+ return (DNGN_ITEM_MISCELLANY);
case OBJ_CORPSES:
- return 271;
+ return (DNGN_ITEM_CORPSE);
case OBJ_GOLD:
- return 272;
+ return (DNGN_ITEM_GOLD);
default:
- return '8';
+ return (DNGN_ITEM_ORB); // bad item character
}
}
-void item()
+void item_grid()
{
char count_x, count_y;
@@ -1443,34 +786,22 @@ void item()
{
if (igrd[count_x][count_y] != NON_ITEM)
{
- if (env.show[count_x - you.x_pos + 9]
- [count_y - you.y_pos + 9] != 0)
+ const int ix = count_x - you.x_pos + 9;
+ const int iy = count_y - you.y_pos + 9;
+ if (env.show[ix][iy])
{
const item_def &eitem = mitm[igrd[count_x][count_y]];
- unsigned short &ecol =
- env.show_col[count_x - you.x_pos + 9]
- [count_y - you.y_pos + 9];
+ unsigned short &ecol = env.show_col[ix][iy];
ecol = (grd[count_x][count_y] == DNGN_SHALLOW_WATER)?
CYAN
: eitem.colour;
-#ifdef USE_COLOUR_OPTS
if (eitem.link != NON_ITEM)
{
ecol |= COLFLAG_ITEM_HEAP;
}
-#elif defined(WIN32CONSOLE) || defined(DOS)
- if (eitem.link != NON_ITEM
- && Options.heap_brand != CHATTR_NORMAL)
- {
- // Yes, exact same code as friend-branding.
- ecol = dos_brand(ecol, Options.heap_brand);
- }
-#endif
- env.show[count_x - you.x_pos + 9]
- [count_y - you.y_pos + 9] =
- item_env_glyph( eitem );
+ env.show[ix][iy] = get_item_dngn_code( eitem );
}
}
}
@@ -1484,7 +815,7 @@ void cloud_grid(void)
int mnc = 0;
// btw, this is also the 'default' color {dlb}
- unsigned char which_color = LIGHTGREY;
+ unsigned char which_colour = LIGHTGREY;
for (int s = 0; s < MAX_CLOUDS; s++)
{
@@ -1499,94 +830,105 @@ void cloud_grid(void)
if (see_grid(env.cloud[s].x, env.cloud[s].y))
{
- show_backup[env.cloud[s].x - you.x_pos + 9]
- [env.cloud[s].y - you.y_pos + 9]
- = env.show[env.cloud[s].x - you.x_pos + 9]
- [env.cloud[s].y - you.y_pos + 9];
-
- env.show[env.cloud[s].x - you.x_pos + 9]
- [env.cloud[s].y - you.y_pos + 9] = '#';
-
+ const int ex = env.cloud[s].x - you.x_pos + 9;
+ const int ey = env.cloud[s].y - you.y_pos + 9;
+
switch (env.cloud[s].type)
{
case CLOUD_FIRE:
case CLOUD_FIRE_MON:
if (env.cloud[s].decay <= 20)
- which_color = RED;
+ which_colour = RED;
else if (env.cloud[s].decay <= 40)
- which_color = LIGHTRED;
+ which_colour = LIGHTRED;
else if (one_chance_in(4))
- which_color = RED;
+ which_colour = RED;
else if (one_chance_in(4))
- which_color = LIGHTRED;
+ which_colour = LIGHTRED;
else
- which_color = YELLOW;
+ which_colour = YELLOW;
break;
case CLOUD_STINK:
case CLOUD_STINK_MON:
- which_color = GREEN;
+ which_colour = GREEN;
break;
case CLOUD_COLD:
case CLOUD_COLD_MON:
if (env.cloud[s].decay <= 20)
- which_color = BLUE;
+ which_colour = BLUE;
else if (env.cloud[s].decay <= 40)
- which_color = LIGHTBLUE;
+ which_colour = LIGHTBLUE;
else if (one_chance_in(4))
- which_color = BLUE;
+ which_colour = BLUE;
else if (one_chance_in(4))
- which_color = LIGHTBLUE;
+ which_colour = LIGHTBLUE;
else
- which_color = WHITE;
+ which_colour = WHITE;
break;
case CLOUD_POISON:
case CLOUD_POISON_MON:
- which_color = (one_chance_in(3) ? LIGHTGREEN : GREEN);
+ which_colour = (one_chance_in(3) ? LIGHTGREEN : GREEN);
break;
case CLOUD_BLUE_SMOKE:
case CLOUD_BLUE_SMOKE_MON:
- which_color = LIGHTBLUE;
+ which_colour = LIGHTBLUE;
break;
case CLOUD_PURP_SMOKE:
case CLOUD_PURP_SMOKE_MON:
- which_color = MAGENTA;
+ which_colour = MAGENTA;
break;
case CLOUD_MIASMA:
case CLOUD_MIASMA_MON:
case CLOUD_BLACK_SMOKE:
case CLOUD_BLACK_SMOKE_MON:
- which_color = DARKGREY;
+ which_colour = DARKGREY;
break;
default:
- which_color = LIGHTGREY;
+ which_colour = LIGHTGREY;
break;
}
- env.show_col[env.cloud[s].x - you.x_pos + 9]
- [env.cloud[s].y - you.y_pos + 9] = which_color;
+ set_show_backup(ex, ey);
+ env.show[ex][ey] = DNGN_CLOUD;
+ env.show_col[ex][ey] = which_colour;
}
} // end 'if != CLOUD_NONE'
} // end 'for s' loop
} // end cloud_grid()
-
-void noisy( int loudness, int nois_x, int nois_y )
+// Noisy now has a messenging service for giving messages to the
+// player is appropriate.
+//
+// Returns true if the PC heard the noise.
+bool noisy( int loudness, int nois_x, int nois_y, const char *msg )
{
int p;
struct monsters *monster = 0; // NULL {dlb}
+ bool ret = false;
+ // If the origin is silenced there is no noise.
if (silenced( nois_x, nois_y ))
- return;
+ return (false);
- int dist = loudness * loudness;
+ const int dist = loudness * loudness;
+ // message the player
+ if (distance( you.x_pos, you.y_pos, nois_x, nois_y ) <= dist
+ && player_can_hear( nois_x, nois_y ))
+ {
+ if (msg)
+ mpr( msg, MSGCH_SOUND );
+
+ ret = true;
+ }
+
for (p = 0; p < MAX_MONSTERS; p++)
{
monster = &menv[p];
@@ -1605,21 +947,19 @@ void noisy( int loudness, int nois_x, int nois_y )
behaviour_event( monster, ME_DISTURB, MHITNOT, nois_x, nois_y );
}
}
+
+ return (ret);
} // end noisy()
-/* ========================================================================
- * brand new LOS code
- * ========================================================================
- * The new LOS works via a new (I think) shadow casting algorithm,
- * plus an esthetic tweak for more pleasing corner illumination. More
- * detail can be had by contacting its author, Gordon Lipford. */
+/* The LOS code now uses raycasting -- haranp */
-#define MAX_LIGHT_RADIUS 20
-#define CIRC_MAX 32000
-#define BIG_SHADOW 32000
+#define LONGSIZE (sizeof(unsigned long)*8)
+#define LOS_MAX_RANGE_X 9
+#define LOS_MAX_RANGE_Y 9
+#define LOS_MAX_RANGE 9
// the following two constants represent the 'middle' of the sh array.
-// since the current shown area is 19x19, centering the view at (9,9)
+// since the current shown area is 19x19, centering the view at (9,9)
// means it will be exactly centered.
// This is done to accomodate possible future changes in viewable screen
// area - simply change sh_xo and sh_yo to the new view center.
@@ -1627,340 +967,648 @@ void noisy( int loudness, int nois_x, int nois_y )
const int sh_xo = 9; // X and Y origins for the sh array
const int sh_yo = 9;
-// the Cell class, used in the shadow-casting LOS algorithm
-class Cell
-{
+// Data used for the LOS algorithm
+int los_radius_squared = 8*8 + 1;
-public:
- int up_count;
- int up_max;
- int low_count;
- int low_max;
- bool lit;
- bool lit_delay;
- bool visible; // for blockers only
- void init();
- bool reachedLower();
- bool reachedUpper();
-
- Cell()
- {
- init();
- };
-};
+unsigned long* los_blockrays = NULL;
+unsigned long* dead_rays = NULL;
+std::vector<short> ray_coord_x;
+std::vector<short> ray_coord_y;
+std::vector<short> compressed_ray_x;
+std::vector<short> compressed_ray_y;
+std::vector<int> raylengths;
+std::vector<ray_def> fullrays;
-void Cell::init()
+void setLOSRadius(int newLR)
{
- up_count = 0;
- up_max = 0;
- low_count = 0;
- low_max = 0;
- lit = true;
- visible = true;
- lit_delay = false;
+ los_radius_squared = newLR * newLR + 1*1;
}
-bool Cell::reachedLower()
+bool get_bit_in_long_array( const unsigned long* data, int where )
{
- // integer math: a 'step' has a value of 10
- // see if we're within a half step of the max. VERY important
- // to use 'half step' or else things look really stupid.
- if (low_max != 0 && low_count + 5 >= low_max && low_count - 5 < low_max)
- return true;
+ int wordloc = where / LONGSIZE;
+ int bitloc = where % LONGSIZE;
+ return ((data[wordloc] & (1UL << bitloc)) != 0);
+}
- return false;
+static void set_bit_in_long_array( unsigned long* data, int where ) {
+ int wordloc = where / LONGSIZE;
+ int bitloc = where % LONGSIZE;
+ data[wordloc] |= (1UL << bitloc);
}
-bool Cell::reachedUpper()
+#define EPSILON_VALUE 0.00001
+bool double_is_zero( const double x )
{
- // see if we're within a half step of the max. VERY important
- // to use 'half step' or else things look really stupid.
- if (up_max != 0 && up_count + 5 >= up_max && up_count - 5 < up_max)
- return true;
-
- return false;
+ return (x > -EPSILON_VALUE) && (x < EPSILON_VALUE);
}
-// the cell array
-static FixedVector < Cell, MAX_LIGHT_RADIUS + 1 > cells;
+// note that slope must be nonnegative!
+// returns 0 if the advance was in x, 1 if it was in y, 2 if it was
+// the diagonal
+static int find_next_intercept(double* accx, double* accy, const double slope)
+{
-// the 'circle' array. For any given row, we won't check higher than
-// this given cell.
-static FixedVector < int, MAX_LIGHT_RADIUS + 1 > circle;
+ // handle perpendiculars
+ if ( double_is_zero(slope) )
+ {
+ *accx += 1.0;
+ return 0;
+ }
+ if ( slope > 100.0 )
+ {
+ *accy += 1.0;
+ return 1;
+ }
-// current light radius
-static int LR = 0;
+ const double xtarget = (double)((int)(*accx) + 1);
+ const double ytarget = (double)((int)(*accy) + 1);
+ const double xdistance = xtarget - *accx;
+ const double ydistance = ytarget - *accy;
+ const double distdiff = (xdistance * slope - ydistance);
+
+ // exact corner
+ if ( double_is_zero( distdiff ) ) {
+ // move somewhat away from the corner
+ if ( slope > 1.0 ) {
+ *accx = xtarget + EPSILON_VALUE * 2;
+ *accy = ytarget + EPSILON_VALUE * 2 * slope;
+ }
+ else {
+ *accx = xtarget + EPSILON_VALUE * 2 / slope;
+ *accy = ytarget + EPSILON_VALUE * 2;
+ }
+ return 2;
+ }
+
+ double traveldist;
+ int rc = -1;
+ if ( distdiff > 0.0 ) {
+ traveldist = ydistance / slope;
+ rc = 1;
+ }
+ else {
+ traveldist = xdistance;
+ rc = 0;
+ }
-// View constant
-const int view = 2; // 1=widest LOS .. 5=narrowest
+ traveldist += EPSILON_VALUE * 10.0;
+
+ *accx += traveldist;
+ *accy += traveldist * slope;
+ return rc;
+}
-// initialize LOS code for a given light radius
-extern void setLOSRadius(int newLR)
+void ray_def::advance_and_bounce()
{
- int i, j;
+ // 0 = down-right, 1 = down-left, 2 = up-left, 3 = up-right
+ int bouncequad[4][3] = {
+ { 1, 3, 2 }, { 0, 2, 3 }, { 3, 1, 0 }, { 2, 0, 1 }
+ };
+ int oldx = x(), oldy = y();
+ int rc = advance();
+ int newx = x(), newy = y();
+ ASSERT( grid_is_solid(grd[newx][newy]) );
+ if ( double_is_zero(slope) || slope > 100.0 )
+ quadrant = bouncequad[quadrant][2];
+ else if ( rc != 2 )
+ quadrant = bouncequad[quadrant][rc];
+ else
+ {
+ ASSERT( (oldx != newx) && (oldy != newy) );
+ bool blocked_x = grid_is_solid(grd[oldx][newy]);
+ bool blocked_y = grid_is_solid(grd[newx][oldy]);
+ if ( blocked_x && blocked_y )
+ quadrant = bouncequad[quadrant][rc];
+ else if ( blocked_x )
+ quadrant = bouncequad[quadrant][1];
+ else
+ quadrant = bouncequad[quadrant][0];
+ }
+ advance();
+}
- // sanity check - also allows multiple calls w/out performance loss
- if (LR == newLR)
- return;
+void ray_def::regress()
+{
+ int opp_quadrant[4] = { 2, 3, 0, 1 };
+ quadrant = opp_quadrant[quadrant];
+ advance();
+ quadrant = opp_quadrant[quadrant];
+}
+
+int ray_def::advance()
+{
+ int rc;
+ switch ( quadrant )
+ {
+ case 0:
+ // going down-right
+ rc = find_next_intercept( &accx, &accy, slope );
+ return rc;
+ case 1:
+ // going down-left
+ accx = 100.0 - EPSILON_VALUE/10.0 - accx;
+ rc = find_next_intercept( &accx, &accy, slope );
+ accx = 100.0 - EPSILON_VALUE/10.0 - accx;
+ return rc;
+ case 2:
+ // going up-left
+ accx = 100.0 - EPSILON_VALUE/10.0 - accx;
+ accy = 100.0 - EPSILON_VALUE/10.0 - accy;
+ rc = find_next_intercept( &accx, &accy, slope );
+ accx = 100.0 - EPSILON_VALUE/10.0 - accx;
+ accy = 100.0 - EPSILON_VALUE/10.0 - accy;
+ return rc;
+ case 3:
+ // going up-right
+ accy = 100.0 - EPSILON_VALUE/10.0 - accy;
+ rc = find_next_intercept( &accx, &accy, slope );
+ accy = 100.0 - EPSILON_VALUE/10.0 - accy;
+ return rc;
+ default:
+ return -1;
+ }
+}
- LR = newLR;
- // cells should already be initted. calculate the circle array.
+// Shoot a ray from the given start point (accx, accy) with the given
+// slope, with a maximum distance (in either x or y coordinate) of
+// maxrange. Store the visited cells in xpos[] and ypos[], and
+// return the number of cells visited.
+static int shoot_ray( double accx, double accy, const double slope,
+ int maxrange, int xpos[], int ypos[] )
+{
+ int curx, cury;
+ int cellnum;
+ for ( cellnum = 0; true; ++cellnum )
+ {
+ find_next_intercept( &accx, &accy, slope );
+ curx = (int)(accx);
+ cury = (int)(accy);
+ if ( curx > maxrange || cury > maxrange )
+ break;
- // note that rows 0 and 1 will always go to infinity.
- circle[0] = circle[1] = CIRC_MAX;
+ // work with the new square
+ xpos[cellnum] = curx;
+ ypos[cellnum] = cury;
+ }
+ return cellnum;
+}
- // for the rest, simply calculate max height based on light rad.
- for (i = 2; i <= LR; i++)
+// check if the passed ray has already been created
+static bool is_duplicate_ray( int len, int xpos[], int ypos[] )
+{
+ int cur_offset = 0;
+ for ( unsigned int i = 0; i < raylengths.size(); ++i )
{
- // check top
- if (2 * i * i <= LR * LR)
+ // only compare equal-length rays
+ if ( raylengths[i] != len )
{
- circle[i] = CIRC_MAX;
+ cur_offset += raylengths[i];
continue;
}
- for (j = i - 1; j >= 0; j--)
+ int j;
+ for ( j = 0; j < len; ++j )
{
- // check that Distance (I^2 + J^2) is no more than (R+0.5)^2
- // this rounding allows for *much* better looking circles.
- if (i * i + j * j <= LR * LR + LR)
- {
- circle[i] = j;
+ if ( ray_coord_x[j + cur_offset] != xpos[j] ||
+ ray_coord_y[j + cur_offset] != ypos[j] )
break;
- }
}
+
+ // exact duplicate?
+ if ( j == len )
+ return true;
+
+ // move to beginning of next ray
+ cur_offset += raylengths[i];
}
+ return false;
}
-static int calcUpper(int bX, int bY)
+// is starta...lengtha a subset of startb...lengthb?
+static bool is_subset( int starta, int startb, int lengtha, int lengthb )
{
- // got a blocker at row bX, cell bY. do all values
- // and scale by a factor of 10 for the integer math.
- int upper;
+ int cura = starta, curb = startb;
+ int enda = starta + lengtha, endb = startb + lengthb;
+ while ( cura < enda && curb < endb )
+ {
+ if ( ray_coord_x[curb] > ray_coord_x[cura] )
+ return false;
+ if ( ray_coord_y[curb] > ray_coord_y[cura] )
+ return false;
+ if ( ray_coord_x[cura] == ray_coord_x[curb] &&
+ ray_coord_y[cura] == ray_coord_y[curb] )
+ ++cura;
- upper = (10 * (10 * bX - view)) / (10 * bY + view);
- if (upper < 10) // upper bound for blocker on diagonal
- upper = 10;
+ ++curb;
+ }
+ return ( cura == enda );
+}
- return upper;
+// return a vector which lists all the nonduped cellrays (by index)
+static std::vector<int> find_nonduped_cellrays()
+{
+ // a cellray c in a fullray f is duped if there is a fullray g
+ // such that g contains c and g[:c] is a subset of f[:c]
+ int raynum, cellnum, curidx, testidx, testray, testcell;
+ bool is_duplicate;
+
+ std::vector<int> result;
+ for (curidx=0, raynum=0;
+ raynum < (int)raylengths.size();
+ curidx += raylengths[raynum++])
+ {
+ for (cellnum = 0; cellnum < raylengths[raynum]; ++cellnum)
+ {
+ // is the cellray raynum[cellnum] duplicated?
+ is_duplicate = false;
+ // XXX We should really check everything up to now
+ // completely, and all further rays to see if they're
+ // proper subsets.
+ const int curx = ray_coord_x[curidx + cellnum];
+ const int cury = ray_coord_y[curidx + cellnum];
+ for (testidx = 0, testray = 0; testray < raynum;
+ testidx += raylengths[testray++])
+ {
+ // scan ahead to see if there's an intersect
+ for ( testcell = 0; testcell < raylengths[raynum]; ++testcell )
+ {
+ const int testx = ray_coord_x[testidx + testcell];
+ const int testy = ray_coord_y[testidx + testcell];
+ // we can short-circuit sometimes
+ if ( testx > curx || testy > cury )
+ break;
+ // bingo!
+ if ( testx == curx && testy == cury )
+ {
+ is_duplicate = is_subset(testidx, curidx,
+ testcell, cellnum);
+ break;
+ }
+ }
+ if ( is_duplicate )
+ break; // no point in checking further rays
+ }
+ if ( !is_duplicate )
+ result.push_back(curidx + cellnum);
+ }
+ }
+ return result;
}
-static int calcLower(int bX, int bY)
+// Create and register the ray defined by the arguments.
+// Return true if the ray was actually registered (i.e., not a duplicate.)
+static bool register_ray( double accx, double accy, double slope )
{
- // got a blocker at row bX, cell bY. do all values
- // and scale by a factor of 10 for the integer math.
+ int xpos[LOS_MAX_RANGE * 2 + 1], ypos[LOS_MAX_RANGE * 2 + 1];
+ int raylen = shoot_ray( accx, accy, slope, LOS_MAX_RANGE, xpos, ypos );
- if (bY == 0)
- return BIG_SHADOW;
+ // early out if ray already exists
+ if ( is_duplicate_ray(raylen, xpos, ypos) )
+ return false;
- return (10 * (10 * bX + view)) / (10 * bY - view);
-}
+ // not duplicate, register
+ for ( int i = 0; i < raylen; ++i )
+ {
+ // create the cellrays
+ ray_coord_x.push_back(xpos[i]);
+ ray_coord_y.push_back(ypos[i]);
+ }
-// for easy x,y octant translation
-static int xxcomp[8] = { 1, 0, 0, -1, -1, 0, 0, 1 };
-static int xycomp[8] = { 0, 1, -1, 0, 0, -1, 1, 0 };
-static int yxcomp[8] = { 0, 1, 1, 0, 0, -1, -1, 0 };
-static int yycomp[8] = { 1, 0, 0, 1, -1, 0, 0, -1 };
+ // register the fullray
+ raylengths.push_back(raylen);
+ ray_def ray;
+ ray.accx = accx;
+ ray.accy = accy;
+ ray.slope = slope;
+ ray.quadrant = 0;
+ fullrays.push_back(ray);
-static void los_octant(int o, FixedArray < unsigned int, 19, 19 > &sh,
- FixedArray < unsigned char, 80, 70 > &gr, int x_p,
- int y_p)
+ return true;
+}
+
+static void create_blockrays()
{
- int row, cell, top, south;
- int tx, ty; // translated x, y deltas for this octant
- unsigned char gv; // grid value
- bool row_dark, all_dark;
- bool blocker, vis_corner;
- int up_inc, low_inc;
-
- // leave [0,0] alone, because the old LOS code seems to.
-
- // init cell[0]. this is the only one that needs clearing.
- cells[0].init();
- all_dark = false;
- vis_corner = false;
-
- // loop through each row
- for (row = 1; row <= LR; row++)
+ // determine nonduplicated rays
+ std::vector<int> nondupe_cellrays = find_nonduped_cellrays();
+ const unsigned int num_nondupe_rays = nondupe_cellrays.size();
+ const unsigned int num_nondupe_words =
+ (num_nondupe_rays + LONGSIZE - 1) / LONGSIZE;
+ const unsigned int num_cellrays = ray_coord_x.size();
+ const unsigned int num_words = (num_cellrays + LONGSIZE - 1) / LONGSIZE;
+
+ // first build all the rays: easier to do blocking calculations there
+ unsigned long* full_los_blockrays;
+ full_los_blockrays = new unsigned long[num_words * (LOS_MAX_RANGE_X+1) *
+ (LOS_MAX_RANGE_Y+1)];
+ memset((void*)full_los_blockrays, 0, sizeof(unsigned long) * num_words *
+ (LOS_MAX_RANGE_X+1) * (LOS_MAX_RANGE_Y+1));
+
+ int cur_offset = 0;
+
+ for ( unsigned int ray = 0; ray < raylengths.size(); ++ray )
{
- row_dark = true;
-
- // loop through each cell, up to the max allowed by circle[]
- top = circle[row];
- if (top > row)
- top = row;
-
- for (cell = 0; cell <= top; cell++)
+ for ( int i = 0; i < raylengths[ray]; ++i )
{
- // translate X,Y co'ord + bounds check
- tx = row * xxcomp[o] + cell * xycomp[o];
- ty = row * yxcomp[o] + cell * yycomp[o];
+ // every cell blocks...
+ unsigned long* const inptr = full_los_blockrays +
+ (ray_coord_x[i + cur_offset] * (LOS_MAX_RANGE_Y + 1) +
+ ray_coord_y[i + cur_offset]) * num_words;
- if (x_p + tx < 0 || x_p + tx > 79 || y_p + ty < 0 || y_p + ty > 69)
- continue;
+ // ...all following cellrays
+ for ( int j = i+1; j < raylengths[ray]; ++j )
+ set_bit_in_long_array( inptr, j + cur_offset );
- // check for all_dark - we've finished the octant but
- // have yet to fill in '0' for the rest of the sight grid
- if (all_dark == true)
- {
- sh[sh_xo + tx][sh_yo + ty] = 0;
- continue;
- }
+ }
+ cur_offset += raylengths[ray];
+ }
- // get grid value.. see if it blocks LOS
- gv = gr[x_p + tx][y_p + ty];
- blocker = (gv < MINSEE);
+ // we've built the basic blockray array; now compress it, keeping
+ // only the nonduplicated cellrays.
- // init some other variables
- up_inc = 10;
- low_inc = 10;
- south = cell - 1;
+ // allocate and clear memory
+ los_blockrays = new unsigned long[num_nondupe_words * (LOS_MAX_RANGE_X+1) * (LOS_MAX_RANGE_Y + 1)];
+ memset((void*)los_blockrays, 0, sizeof(unsigned long) * num_nondupe_words *
+ (LOS_MAX_RANGE_X+1) * (LOS_MAX_RANGE_Y+1));
- // STEP 1 - inherit values from immediate West, if possible
- if (cell < row)
- {
- // check for delayed lighting
- if (cells[cell].lit_delay)
- {
- if (!blocker)
- { // blockers don't light up with lit_delay.
- if (cells[south].lit)
- {
- if (cells[south].low_max != 0)
- {
- cells[cell].lit = false;
- // steal lower values
- cells[cell].low_max = cells[south].low_max;
- cells[cell].low_count = cells[south].low_count;
- cells[south].low_count = 0;
- cells[south].low_max = 0;
- low_inc = 0; // avoid double-inc.
- }
- else
- cells[cell].lit = true;
- }
- }
- cells[cell].lit_delay = false;
- }
- }
- else
- {
- // initialize new cell.
- cells[cell].init();
- }
+ // we want to only keep the cellrays from nondupe_cellrays.
+ compressed_ray_x.resize(num_nondupe_rays);
+ compressed_ray_y.resize(num_nondupe_rays);
+ for ( unsigned int i = 0; i < num_nondupe_rays; ++i )
+ {
+ compressed_ray_x[i] = ray_coord_x[nondupe_cellrays[i]];
+ compressed_ray_y[i] = ray_coord_y[nondupe_cellrays[i]];
+ }
+ unsigned long* oldptr = full_los_blockrays;
+ unsigned long* newptr = los_blockrays;
+ for ( int x = 0; x <= LOS_MAX_RANGE_X; ++x )
+ {
+ for ( int y = 0; y <= LOS_MAX_RANGE_Y; ++y )
+ {
+ for ( unsigned int i = 0; i < num_nondupe_rays; ++i )
+ if ( get_bit_in_long_array(oldptr, nondupe_cellrays[i]) )
+ set_bit_in_long_array(newptr, i);
+ oldptr += num_words;
+ newptr += num_nondupe_words;
+ }
+ }
- // STEP 2 - check for blocker
- // a dark blocker in shadow's edge will be visible
- if (blocker)
- {
- if (cells[cell].lit || (cell != 0 && cells[south].lit)
- || vis_corner)
- {
- // hack: make 'corners' visible
- vis_corner = cells[cell].lit;
+ // we can throw away full_los_blockrays now
+ delete [] full_los_blockrays;
- cells[cell].lit = false;
- cells[cell].visible = true;
+ dead_rays = new unsigned long[num_nondupe_words];
+
+#ifdef DEBUG_DIAGNOSTICS
+ mprf( MSGCH_DIAGNOSTICS, "Cellrays: %d Fullrays: %u Compressed: %u",
+ num_cellrays, raylengths.size(), num_nondupe_rays );
+#endif
+}
- int upper = calcUpper(row, cell);
- int lower = calcLower(row, cell);
+static int gcd( int x, int y )
+{
+ int tmp;
+ while ( y != 0 )
+ {
+ x %= y;
+ tmp = x;
+ x = y;
+ y = tmp;
+ }
+ return x;
+}
- if (upper < cells[cell].up_max || cells[cell].up_max == 0)
- {
- // new upper shadow
- cells[cell].up_max = upper;
- cells[cell].up_count = 0;
- up_inc = 0;
- }
+// Cast all rays
+void raycast()
+{
+ static bool done_raycast = false;
+ if ( done_raycast )
+ return;
+
+ // Creating all rays for first quadrant
+ // We have a considerable amount of overkill.
+ done_raycast = true;
+
+ int xangle, yangle;
+
+ // register perpendiculars FIRST, to make them top choice
+ // when selecting beams
+ register_ray( 0.5, 0.5, 1000.0 );
+ register_ray( 0.5, 0.5, 0.0 );
+
+ // For a slope of M = y/x, every x we move on the X axis means
+ // that we move y on the y axis. We want to look at the resolution
+ // of x/y: in that case, every step on the X axis means an increase
+ // of 1 in the Y axis at the intercept point. We can assume gcd(x,y)=1,
+ // so we look at steps of 1/y.
+ for ( xangle = 1; xangle <= LOS_MAX_RANGE; ++xangle ) {
+ for ( yangle = 1; yangle <= LOS_MAX_RANGE; ++yangle ) {
+
+ if ( gcd(xangle, yangle) != 1 )
+ continue;
- if (lower > cells[cell].low_max || cells[cell].low_max == 0)
- {
- // new lower shadow
- cells[cell].low_max = lower;
- cells[cell].low_count = -10;
- low_inc = 0;
- if (lower <= 30) // somewhat arbitrary
- cells[cell].lit_delay = true;
- // set dark_delay if lower > 20?? how to decide?
- }
- }
- else
- {
- cells[cell].visible = false;
- }
- }
- else
- {
- cells[cell].visible = false; // special flags for blockers
+ const double slope = ((double)(yangle)) / xangle;
+ const double rslope = ((double)(xangle)) / yangle;
+ for ( int intercept = 0; intercept <= yangle; ++intercept ) {
+ double xstart = ((double)(intercept)) / yangle;
+ if ( intercept == 0 )
+ xstart += EPSILON_VALUE / 10.0;
+ if ( intercept == yangle )
+ xstart -= EPSILON_VALUE / 10.0;
+ // y should be "about to change"
+ register_ray( xstart, 1.0 - EPSILON_VALUE / 10.0, slope );
+ // also draw the identical ray in octant 2
+ register_ray( 1.0 - EPSILON_VALUE / 10.0, xstart, rslope );
}
+ }
+ }
- // STEP 3 - add increments to upper, lower counts
- cells[cell].up_count += up_inc;
- cells[cell].low_count += low_inc;
+ // Now create the appropriate blockrays array
+ create_blockrays();
+}
- // STEP 4 - check south for dark
- if (south >= 0)
- if (cells[south].reachedUpper() == true)
- {
- if (cells[cell].reachedUpper() == false)
+static void set_ray_quadrant( ray_def& ray, int sx, int sy, int tx, int ty )
+{
+ if ( tx >= sx && ty >= sy )
+ ray.quadrant = 0;
+ else if ( tx < sx && ty >= sy )
+ ray.quadrant = 1;
+ else if ( tx < sx && ty < sy )
+ ray.quadrant = 2;
+ else if ( tx >= sx && ty < sy )
+ ray.quadrant = 3;
+ else
+ mpr("Bad ray quadrant!", MSGCH_DIAGNOSTICS);
+}
+
+
+// Find a nonblocked ray from sx, sy to tx, ty. Return false if no
+// such ray could be found, otherwise return true and fill ray
+// appropriately.
+// If allow_fallback is true, fall back to a center-to-center ray
+// if range is too great or all rays are blocked.
+bool find_ray( int sourcex, int sourcey, int targetx, int targety,
+ bool allow_fallback, ray_def& ray )
+{
+
+ int cellray, inray;
+ const int signx = ((targetx - sourcex >= 0) ? 1 : -1);
+ const int signy = ((targety - sourcey >= 0) ? 1 : -1);
+ const int absx = signx * (targetx - sourcex);
+ const int absy = signy * (targety - sourcey);
+ int cur_offset = 0;
+ for ( unsigned int fullray = 0; fullray < fullrays.size();
+ cur_offset += raylengths[fullray++] ) {
+
+ for ( cellray = 0; cellray < raylengths[fullray]; ++cellray )
+ {
+ if ( ray_coord_x[cellray + cur_offset] == absx &&
+ ray_coord_y[cellray + cur_offset] == absy ) {
+
+ // check if we're blocked so far
+ bool blocked = false;
+ for ( inray = 0; inray < cellray; ++inray ) {
+ if (grid_is_solid(grd[sourcex + signx * ray_coord_x[inray + cur_offset]][sourcey + signy * ray_coord_y[inray + cur_offset]]))
{
- cells[cell].up_max = cells[south].up_max;
- cells[cell].up_count = cells[south].up_count;
- cells[cell].up_count -= cells[south].up_max;
+ blocked = true;
+ break;
}
- cells[cell].lit = false;
- cells[cell].visible = false;
- }
-
- // STEP 5 - nuke lower if south lower
- if (south >= 0)
- {
- if (cells[south].reachedLower())
- {
- cells[cell].low_max = cells[south].low_max;
- cells[cell].low_count = cells[south].low_count;
- cells[cell].low_count -= cells[south].low_max;
- cells[south].low_count = cells[south].low_max = 0;
}
- if (cells[south].low_max != 0
- || (cells[south].lit == false
- && cells[south].low_max == 0))
+ if ( !blocked )
{
- cells[cell].low_count = cells[cell].low_max + 10;
+ // success!
+ ray = fullrays[fullray];
+ if ( sourcex > targetx )
+ ray.accx = 1.0 - ray.accx;
+ if ( sourcey > targety )
+ ray.accy = 1.0 - ray.accy;
+ ray.accx += sourcex;
+ ray.accy += sourcey;
+ set_ray_quadrant(ray, sourcex, sourcey, targetx, targety);
+ return true;
}
}
-
- // STEP 6 - light up if we've reached lower bound
- if (cells[cell].reachedLower() == true)
- cells[cell].lit = true;
-
- // now place appropriate value in sh
- if (cells[cell].lit == true
- || (blocker == true && cells[cell].visible == true))
- {
- sh[sh_xo + tx][sh_yo + ty] = gv;
- }
- else
- sh[sh_xo + tx][sh_yo + ty] = 0;
-
- if (cells[cell].lit == true)
- row_dark = false;
- } // end for - cells
-
- vis_corner = false; // don't carry over to next row. :)
- if (row_dark == true)
- all_dark = true;
- } // end for - rows
+ }
+ }
+ if ( allow_fallback ) {
+ ray.accx = sourcex + 0.5;
+ ray.accy = sourcey + 0.5;
+ if ( targetx == sourcex )
+ ray.slope = 10000.0;
+ else {
+ ray.slope = targety - sourcey;
+ ray.slope /= targetx - sourcex;
+ if ( ray.slope < 0 )
+ ray.slope = -ray.slope;
+ }
+ set_ray_quadrant(ray, sourcex, sourcey, targetx, targety);
+ return true;
+ }
+ return false;
}
+// The rule behind LOS is:
+// Two cells can see each other if there is any line from some point
+// of the first to some point of the second ("generous" LOS.)
+//
+// We use raycasting. The algorithm:
+// PRECOMPUTATION:
+// Create a large bundle of rays and cast them.
+// Mark, for each one, which cells kill it (and where.)
+// Also, for each one, note which cells it passes.
+// ACTUAL LOS:
+// Unite the ray-killers for the given map; this tells you which rays
+// are dead.
+// Look up which cells the surviving rays have, and that's your LOS!
+// OPTIMIZATIONS:
+// WLOG, we can assume that we're in a specific quadrant - say the
+// first quadrant - and just mirror everything after that. We can
+// likely get away with a single octant, but we don't do that. (To
+// do...)
+// Rays are actually split by each cell they pass. So each "ray" only
+// identifies a single cell, and we can do logical ORs. Once a cell
+// kills a cellray, it will kill all remaining cellrays of that ray.
+// Also, rays are checked to see if they are duplicates of each
+// other. If they are, they're eliminated.
+// Some cellrays can also be eliminated. In general, a cellray is
+// unnecessary if there is another cellray with the same coordinates,
+// and whose path (up to those coordinates) is a subset, not necessarily
+// proper, of the original path. We still store the original cellrays
+// fully for beam detection and such.
+// PERFORMANCE:
+// With reasonable values we have around 6000 cellrays, meaning
+// around 600Kb (75 KB) of data. This gets cut down to 700 cellrays
+// after removing duplicates. That means that we need to do
+// around 22*100*4 ~ 9,000 memory reads + writes per LOS call on a
+// 32-bit system. Not too bad.
void losight(FixedArray < unsigned int, 19, 19 > &sh,
FixedArray < unsigned char, 80, 70 > &gr, int x_p, int y_p)
{
- int o;
+ raycast();
+ // go quadrant by quadrant
+ int quadrant_x[4] = { 1, -1, -1, 1 };
+ int quadrant_y[4] = { 1, 1, -1, -1 };
+
+ // clear out sh
+ for ( int i = 0; i < 19; ++i )
+ for ( int j = 0; j < 19; ++j )
+ sh[i][j] = 0;
+
+ const unsigned int num_cellrays = compressed_ray_x.size();
+ const unsigned int num_words = (num_cellrays + LONGSIZE - 1) / LONGSIZE;
+
+ for ( int quadrant = 0; quadrant < 4; ++quadrant ) {
+ const int xmult = quadrant_x[quadrant];
+ const int ymult = quadrant_y[quadrant];
+
+ // clear out the dead rays array
+ memset( (void*)dead_rays, 0, sizeof(unsigned long) * num_words);
+
+ // kill all blocked rays
+ const unsigned long* inptr = los_blockrays;
+ for ( int xdiff = 0; xdiff <= LOS_MAX_RANGE_X; ++xdiff ) {
+ for (int ydiff = 0; ydiff <= LOS_MAX_RANGE_Y;
+ ++ydiff, inptr += num_words ) {
+
+ const int realx = x_p + xdiff * xmult;
+ const int realy = y_p + ydiff * ymult;
+
+ if (realx < 0 || realx > 79 || realy < 0 || realy > 69)
+ continue;
+
+ // if this cell is opaque...
+ if ( grid_is_opaque(gr[realx][realy])) {
+ // then block the appropriate rays
+ for ( unsigned int i = 0; i < num_words; ++i )
+ dead_rays[i] |= inptr[i];
+ }
+ }
+ }
- for (o = 0; o < 8; o++)
- los_octant(o, sh, gr, x_p, y_p);
+ // ray calculation done, now work out which cells in this
+ // quadrant are visible
+ unsigned int rayidx = 0;
+ for ( unsigned int wordloc = 0; wordloc < num_words; ++wordloc ) {
+ const unsigned long curword = dead_rays[wordloc];
+ // Note: the last word may be incomplete
+ for ( unsigned int bitloc = 0; bitloc < LONGSIZE; ++bitloc) {
+ // make the cells seen by this ray at this point visible
+ if ( ((curword >> bitloc) & 1UL) == 0 ) {
+ // this ray is alive!
+ const int realx = xmult * compressed_ray_x[rayidx];
+ const int realy = ymult * compressed_ray_y[rayidx];
+ // update shadow map
+ if (x_p + realx >= 0 && x_p + realx < 80 &&
+ y_p + realy >= 0 && y_p + realy < 70 &&
+ realx * realx + realy * realy <= los_radius_squared )
+ sh[sh_xo+realx][sh_yo+realy]=gr[x_p+realx][y_p+realy];
+ }
+ ++rayidx;
+ if ( rayidx == num_cellrays )
+ break;
+ }
+ }
+ }
}
@@ -2206,11 +1854,34 @@ static int find_feature( const std::vector<coord_def>& features,
return 0;
}
+#ifdef USE_CURSES
+// NOTE: This affects libunix.cc draw state; use this just before setting
+// textcolour and drawing a character and call set_altcharset(false)
+// after you're done drawing.
+//
+static int cset_adjust(int raw)
+{
+ if (Options.char_set != CSET_ASCII)
+ {
+ // switch to alternate char set for 8-bit characters:
+ set_altcharset( raw > 127 );
+
+ // shift the DEC line drawing set:
+ if (Options.char_set == CSET_DEC
+ && raw >= 0xE0)
+ {
+ raw &= 0x7F;
+ }
+ }
+ return (raw);
+}
+#endif
+
// show_map() now centers the known map along x or y. This prevents
// the player from getting "artificial" location clues by using the
// map to see how close to the end they are. They'll need to explore
// to get that. This function is still a mess, though. -- bwr
-void show_map( FixedVector<int, 2> &spec_place )
+void show_map( FixedVector<int, 2> &spec_place, bool travel_mode )
{
int i, j;
@@ -2226,7 +1897,8 @@ void show_map( FixedVector<int, 2> &spec_place )
// Vector to track all features we can travel to, in order of distance.
std::vector<coord_def> features;
- if (!spec_place[0]) {
+ if (travel_mode)
+ {
travel_cache.update();
find_travel_pos(you.x_pos, you.y_pos, NULL, NULL, &features);
@@ -2336,16 +2008,21 @@ void show_map( FixedVector<int, 2> &spec_place )
colour = colour_code_map(start_x + i, start_y + j,
Options.item_colour,
- !spec_place[0] && Options.travel_colour);
+ travel_mode && Options.travel_colour);
buffer2[bufcount2 + 1] = colour;
-
- if (start_x + i + 1 == you.x_pos && start_y + j + 1 == you.y_pos)
- buffer2[bufcount2 + 1] = WHITE;
-
buffer2[bufcount2] =
(unsigned char) env.map[start_x + i][start_y + j];
+ if (start_x + i + 1 == you.x_pos && start_y + j + 1 == you.y_pos)
+ {
+ // [dshaligram] Draw the @ symbol on the level-map. It's no
+ // longer saved into the env.map, so we need to draw it
+ // directly.
+ buffer2[bufcount2 + 1] = WHITE;
+ buffer2[bufcount2] = you.symbol;
+ }
+
// If we've a waypoint on the current square, *and* the square is
// a normal floor square with nothing on it, show the waypoint
// number.
@@ -2355,8 +2032,8 @@ void show_map( FixedVector<int, 2> &spec_place )
screen_buffer_t &bc = buffer2[bufcount2];
int gridx = start_x + i + 1, gridy = start_y + j + 1;
unsigned char ch = is_waypoint(gridx, gridy);
- if (ch && (bc == mapch2(DNGN_FLOOR) ||
- bc == mapch(DNGN_FLOOR)))
+ if (ch && (bc == get_sightmap_char(DNGN_FLOOR) ||
+ bc == get_magicmap_char(DNGN_FLOOR)))
bc = ch;
}
@@ -2373,12 +2050,20 @@ void show_map( FixedVector<int, 2> &spec_place )
if (i == 0 && j > 0)
gotoxy( 1, j + 1 );
+ int ch = buffer2[bufcount2 - 2];
+#ifdef USE_CURSES
+ ch = cset_adjust( ch );
+#endif
textcolor( buffer2[bufcount2 - 1] );
- putch( buffer2[bufcount2 - 2] );
+ putch(ch);
#endif
}
}
+#ifdef USE_CURSES
+ set_altcharset(false);
+#endif
+
#ifdef DOS_TERM
puttext(1, 1, 80, 25, buffer2);
#endif
@@ -2389,7 +2074,7 @@ void show_map( FixedVector<int, 2> &spec_place )
gettything:
getty = getchm(KC_LEVELMAP);
- if (spec_place[0] == 0 && getty != 0 && getty != '+' && getty != '-'
+ if (travel_mode && getty != 0 && getty != '+' && getty != '-'
&& getty != 'h' && getty != 'j' && getty != 'k' && getty != 'l'
&& getty != 'y' && getty != 'u' && getty != 'b' && getty != 'n'
&& getty != 'H' && getty != 'J' && getty != 'K' && getty != 'L'
@@ -2406,12 +2091,13 @@ void show_map( FixedVector<int, 2> &spec_place )
&& getty != CONTROL('F')
&& getty != CONTROL('W')
&& getty != CONTROL('C')
+ && getty != '?'
&& getty != 'X' && getty != 'F' && getty != 'I' && getty != 'W')
{
goto putty;
}
- if (spec_place[0] == 1 && getty != 0 && getty != '+' && getty != '-'
+ if (!travel_mode && getty != 0 && getty != '+' && getty != '-'
&& getty != 'h' && getty != 'j' && getty != 'k' && getty != 'l'
&& getty != 'y' && getty != 'u' && getty != 'b' && getty != 'n'
&& getty != 'H' && getty != 'J' && getty != 'K' && getty != 'L'
@@ -2425,9 +2111,13 @@ void show_map( FixedVector<int, 2> &spec_place )
}
if (getty == 0)
+ {
getty = getchm(KC_LEVELMAP);
+ // [dshaligram] DOS madness.
+ getty = dos_direction_unmunge(getty);
+ }
-#ifdef WIN32CONSOLE
+#if defined(WIN32CONSOLE) || defined(DOS)
// Translate shifted numpad to shifted vi keys. Yes,
// this is horribly hacky.
{
@@ -2441,6 +2131,10 @@ void show_map( FixedVector<int, 2> &spec_place )
switch (getty)
{
+ case '?':
+ show_levelmap_help();
+ break;
+
case CONTROL('C'):
clear_map();
break;
@@ -2591,7 +2285,7 @@ void show_map( FixedVector<int, 2> &spec_place )
search_feat = getty;
search_found = 0;
}
- if (!spec_place[0])
+ if (travel_mode)
search_found = find_feature(features, getty, curs_x, curs_y,
start_x, start_y,
search_found, &move_x, &move_y);
@@ -2608,7 +2302,7 @@ void show_map( FixedVector<int, 2> &spec_place )
case ';':
{
int x = start_x + curs_x, y = start_y + curs_y;
- if (!spec_place[0] && x == you.x_pos && y == you.y_pos)
+ if (travel_mode && x == you.x_pos && y == you.y_pos)
{
if (you.travel_x > 0 && you.travel_y > 0) {
move_x = you.travel_x - x;
@@ -2701,1404 +2395,1177 @@ void magic_mapping(int map_radius, int proportion)
{
int i, j, k, l, empty_count;
- if (map_radius > 50)
+ if (map_radius > 50 && map_radius != 1000)
map_radius = 50;
+ else if (map_radius < 5)
+ map_radius = 5;
+
+ // now gradually weaker with distance:
+ const int pfar = (map_radius * 7) / 10;
+ const int very_far = (map_radius * 9) / 10;
for (i = you.x_pos - map_radius; i < you.x_pos + map_radius; i++)
{
for (j = you.y_pos - map_radius; j < you.y_pos + map_radius; j++)
{
- if (random2(100) > proportion)
+ if (proportion < 100 && random2(100) >= proportion)
continue; // note that proportion can be over 100
- if (i < 5 || j < 5 || i > (GXM - 5) || j > (GYM - 5))
+ if (!map_bounds(i, j))
continue;
- //if (env.map[i][j] == mapch2(grd[i + 1][j + 1]))
- // continue;
- if (env.map[i][j])
+ const int dist = grid_distance( you.x_pos, you.y_pos, i, j );
+
+ if (dist > pfar && one_chance_in(3))
+ continue;
+
+ if (dist > very_far && coinflip())
+ continue;
+
+ if (is_terrain_changed(i, j))
+ clear_envmap_grid(i, j);
+
+ if (is_terrain_known(i, j))
continue;
empty_count = 8;
- if (grd[i][j] < DNGN_LAVA && grd[i][j] != DNGN_CLOSED_DOOR)
+ if (grid_is_solid(grd[i][j]) && grd[i][j] != DNGN_CLOSED_DOOR)
{
- for (k = 0; k < 3; k++)
+ for (k = -1; k <= 1; k++)
{
- for (l = 0; l < 3; l++)
+ for (l = -1; l <= 1; l++)
{
- if (k == 1 && l == 1)
+ if (k == 0 && l == 0)
continue;
- if (grd[i + k][j + l] <= 60
- && grd[i + k][j + l] != DNGN_CLOSED_DOOR)
+ if (!map_bounds( i + k, j + l ))
{
- empty_count--;
+ --empty_count;
+ continue;
}
+
+ if (grid_is_solid( grd[i + k][j + l] )
+ && grd[i + k][j + l] != DNGN_CLOSED_DOOR)
+ empty_count--;
}
}
}
if (empty_count > 0)
- env.map[i][j] = mapch(grd[i + 1][j + 1]);
+ {
+ if (!get_envmap_char(i, j))
+ set_envmap_char(i, j, get_magicmap_char(grd[i][j]));
+
+ // Hack to give demonspawn Pandemonium mutation the ability
+ // to detect exits magically.
+ if ((you.mutation[MUT_PANDEMONIUM] > 1
+ && grd[i][j] == DNGN_EXIT_PANDEMONIUM)
+ // Wizmode
+ || map_radius == 1000)
+ set_terrain_seen( i, j );
+ else
+ set_terrain_mapped( i, j );
+ }
}
}
} // end magic_mapping()
-
-/* mapchars 3 & 4 are for non-ibm char sets */
-unsigned char mapchar(unsigned char ldfk)
+// realize that this is simply a repackaged version of
+// stuff::see_grid() -- make certain they correlate {dlb}:
+bool mons_near(struct monsters *monster, unsigned int foe)
{
- unsigned char showed = 0;
+ // early out -- no foe!
+ if (foe == MHITNOT)
+ return (false);
- switch (ldfk)
+ if (foe == MHITYOU)
{
- case DNGN_UNSEEN:
- showed = 0;
- break;
+ if (monster->x > you.x_pos - 9 && monster->x < you.x_pos + 9
+ && monster->y > you.y_pos - 9 && monster->y < you.y_pos + 9)
+ {
+ if (env.show[monster->x - you.x_pos + 9][monster->y - you.y_pos + 9])
+ return (true);
+ }
+ return (false);
+ }
- case DNGN_SECRET_DOOR:
- case DNGN_ROCK_WALL:
- case DNGN_PERMAROCK_WALL:
- case DNGN_STONE_WALL:
- case DNGN_METAL_WALL:
- case DNGN_GREEN_CRYSTAL_WALL:
- case DNGN_WAX_WALL:
- showed = 176;
- break;
+ // must be a monster
+ struct monsters *myFoe = &menv[foe];
+ if (myFoe->type >= 0)
+ {
+ if (monster->x > myFoe->x - 9 && monster->x < myFoe->x + 9
+ && monster->y > myFoe->y - 9 && monster->y < myFoe->y + 9)
+ {
+ return (true);
+ }
+ }
- case DNGN_CLOSED_DOOR:
- showed = 206;
- break;
+ return (false);
+} // end mons_near()
- case 20: // orcish idol
- case 24: // ???
- case 25: // ???
- case DNGN_SILVER_STATUE:
- case DNGN_GRANITE_STATUE:
- case DNGN_ORANGE_CRYSTAL_STATUE:
- showed = '8';
- break;
+// answers the question: "Is a grid within character's line of sight?"
+bool see_grid( int grx, int gry )
+{
+ // rare case: can player see self? (of course!)
+ if (grx == you.x_pos && gry == you.y_pos)
+ return (true);
- case DNGN_LAVA_X:
- case DNGN_WATER_X:
- case DNGN_LAVA:
- case DNGN_DEEP_WATER:
- case DNGN_SHALLOW_WATER:
- showed = 247;
- break;
+ // check env.show array
+ if (grid_distance( grx, gry, you.x_pos, you.y_pos ) < 9)
+ {
+ const int ex = grx - you.x_pos + 9;
+ const int ey = gry - you.y_pos + 9;
- case DNGN_FLOOR:
- case DNGN_UNDISCOVERED_TRAP:
- showed = 250;
- break;
+ if (env.show[ex][ey])
+ return (true);
+ }
- //case 68: showed = '>'; break; // < (60)
+ return (false);
+} // end see_grid()
- case DNGN_OPEN_DOOR:
- showed = 39;
- break;
+static const unsigned char table[ NUM_CSET ][ NUM_DCHAR_TYPES ] =
+{
+ // CSET_ASCII
+ {
+ '#', '*', '.', ',', '\'', '+', '^', '>', '<', // wall, stairs up
+ '_', '\\', '}', '{', '8', '~', '~', // altar, item detect
+ '0', ')', '[', '/', '%', '?', '=', '!', '(', // orb, missile
+ ':', '|', '}', '%', '$', '"', '#', // book, cloud
+ },
- //case 72: showed = '<'; break;
+ // CSET_IBM - this is ANSI 437
+ {
+ 177, 176, 249, 250, '\'', 254, '^', '>', '<', // wall, stairs up
+ 220, 239, 244, 247, '8', '~', '~', // altar, item detect
+ '0', ')', '[', '/', '%', '?', '=', '!', '(', // orb, missile
+ '+', '\\', '}', '%', '$', '"', '#', // book, cloud
+ },
- case DNGN_TRAP_MECHANICAL:
- case DNGN_TRAP_MAGICAL:
- case DNGN_TRAP_III:
- showed = '^';
- break;
+ // CSET_DEC - remember: 224-255 are mapped to shifted 96-127
+ {
+ 225, 224, 254, ':', '\'', 238, '^', '>', '<', // wall, stairs up
+ 251, 182, 167, 187, '8', 171, 168, // altar, item detect
+ '0', ')', '[', '/', '%', '?', '=', '!', '(', // orb, missile
+ '+', '\\', '}', '%', '$', '"', '#', // book, cloud
+ },
+};
- case DNGN_STONE_STAIRS_DOWN_I:
- case DNGN_STONE_STAIRS_DOWN_II:
- case DNGN_STONE_STAIRS_DOWN_III:
- case DNGN_ROCK_STAIRS_DOWN:
- case DNGN_ENTER_ORCISH_MINES:
- case DNGN_ENTER_HIVE:
- case DNGN_ENTER_LAIR:
- case DNGN_ENTER_SLIME_PITS:
- case DNGN_ENTER_VAULTS:
- case DNGN_ENTER_CRYPT:
- case DNGN_ENTER_HALL_OF_BLADES:
- case DNGN_ENTER_TEMPLE:
- case DNGN_ENTER_SNAKE_PIT:
- case DNGN_ENTER_ELVEN_HALLS:
- case DNGN_ENTER_TOMB:
- case DNGN_ENTER_SWAMP:
- case 123:
- case 124:
- case 125:
- case 126:
- showed = '>';
- break;
+static unsigned char cset_override[NUM_CSET][NUM_DCHAR_TYPES];
- case DNGN_STONE_STAIRS_UP_I:
- case DNGN_STONE_STAIRS_UP_II:
- case DNGN_STONE_STAIRS_UP_III:
- case DNGN_ROCK_STAIRS_UP:
- case DNGN_RETURN_FROM_ORCISH_MINES:
- case DNGN_RETURN_FROM_HIVE:
- case DNGN_RETURN_FROM_LAIR:
- case DNGN_RETURN_FROM_SLIME_PITS:
- case DNGN_RETURN_FROM_VAULTS:
- case DNGN_RETURN_FROM_CRYPT:
- case DNGN_RETURN_FROM_HALL_OF_BLADES:
- case DNGN_RETURN_FROM_TEMPLE:
- case DNGN_RETURN_FROM_SNAKE_PIT:
- case DNGN_RETURN_FROM_ELVEN_HALLS:
- case DNGN_RETURN_FROM_TOMB:
- case DNGN_RETURN_FROM_SWAMP:
- case 143:
- case 144:
- case 145:
- case 146:
- showed = '<';
- break;
+dungeon_char_type dchar_by_name(const std::string &name)
+{
+ const char *dchar_names[] =
+ {
+ "wall", "wall_magic", "floor", "floor_magic", "door_open",
+ "door_closed", "trap", "stairs_down", "stairs_up", "altar", "arch",
+ "fountain", "wavy", "statue", "invis_exposed", "item_detected",
+ "item_orb", "item_weapon", "item_armour", "item_wand", "item_food",
+ "item_scroll", "item_ring", "item_potion", "item_missile", "item_book",
+ "item_stave", "item_miscellany", "item_corpse", "item_gold",
+ "item_amulet", "cloud"
+ };
+ for (unsigned i = 0; i < sizeof(dchar_names) / sizeof(*dchar_names); ++i)
+ {
+ if (dchar_names[i] == name)
+ return dungeon_char_type(i);
+ }
+ return (NUM_DCHAR_TYPES);
+}
- case DNGN_ENTER_HELL:
- case DNGN_ENTER_LABYRINTH:
- case DNGN_ENTER_SHOP:
- case DNGN_ENTER_DIS:
- case DNGN_ENTER_GEHENNA:
- case DNGN_ENTER_COCYTUS:
- case DNGN_ENTER_TARTARUS:
- case DNGN_ENTER_ABYSS:
- case DNGN_EXIT_ABYSS:
- case DNGN_STONE_ARCH:
- case DNGN_ENTER_PANDEMONIUM:
- case DNGN_EXIT_PANDEMONIUM:
- case DNGN_TRANSIT_PANDEMONIUM:
- case DNGN_ENTER_ZOT:
- case DNGN_RETURN_FROM_ZOT:
- showed = 239;
- break;
+void clear_cset_overrides()
+{
+ memset(cset_override, 0, sizeof cset_override);
+}
- case DNGN_ALTAR_ZIN:
- case DNGN_ALTAR_SHINING_ONE:
- case DNGN_ALTAR_KIKUBAAQUDGHA:
- case DNGN_ALTAR_YREDELEMNUL:
- case DNGN_ALTAR_XOM:
- case DNGN_ALTAR_VEHUMET:
- case DNGN_ALTAR_OKAWARU:
- case DNGN_ALTAR_MAKHLEB:
- case DNGN_ALTAR_SIF_MUNA:
- case DNGN_ALTAR_TROG:
- case DNGN_ALTAR_NEMELEX_XOBEH:
- case DNGN_ALTAR_ELYVILON:
- showed = 220;
- break;
+static unsigned short read_symbol(std::string s)
+{
+ if (s.empty())
+ return (0);
+ if (s.length() == 1)
+ return s[0];
- case DNGN_BLUE_FOUNTAIN:
- case DNGN_DRY_FOUNTAIN_I:
- case DNGN_SPARKLING_FOUNTAIN:
- case DNGN_DRY_FOUNTAIN_II:
- case DNGN_DRY_FOUNTAIN_III:
- case DNGN_DRY_FOUNTAIN_IV:
- case DNGN_DRY_FOUNTAIN_V:
- case DNGN_DRY_FOUNTAIN_VI:
- case DNGN_DRY_FOUNTAIN_VII:
- case DNGN_DRY_FOUNTAIN_VIII:
- case DNGN_PERMADRY_FOUNTAIN:
- showed = 159;
- break;
+ if (s[0] == '\\')
+ s = s.substr(1);
+
+ int feat = atoi(s.c_str());
+ if (feat < 0)
+ feat = 0;
+ return static_cast<unsigned short>(feat);
+}
- default:
- showed = 0;
- break;
+void add_cset_override(char_set_type set, dungeon_char_type dc,
+ unsigned char symbol)
+{
+ cset_override[set][dc] = symbol;
+}
+
+void add_cset_override(char_set_type set, const std::string &overrides)
+{
+ std::vector<std::string> overs = split_string(",", overrides);
+ for (int i = 0, size = overs.size(); i < size; ++i)
+ {
+ std::vector<std::string> mapping = split_string(":", overs[i]);
+ if (mapping.size() != 2)
+ continue;
+
+ dungeon_char_type dc = dchar_by_name(mapping[0]);
+ if (dc == NUM_DCHAR_TYPES)
+ continue;
+
+ unsigned char symbol =
+ static_cast<unsigned char>(read_symbol(mapping[1]));
+
+ if (set == NUM_CSET)
+ for (int c = 0; c < NUM_CSET; ++c)
+ add_cset_override(char_set_type(c), dc, symbol);
+ else
+ add_cset_override(set, dc, symbol);
}
+}
- return showed;
+void init_char_table( char_set_type set )
+{
+ for (int i = 0; i < NUM_DCHAR_TYPES; i++)
+ {
+ if (cset_override[set][i])
+ Options.char_table[i] = cset_override[set][i];
+ else
+ Options.char_table[i] = table[set][i];
+ }
}
+void clear_feature_overrides()
+{
+ Feature_Overrides.clear();
+}
-unsigned char mapchar2(unsigned char ldfk)
+void add_feature_override(const std::string &text)
{
- unsigned char showed = 0;
+ std::string::size_type epos = text.rfind("}");
+ if (epos == std::string::npos)
+ return;
+
+ std::string::size_type spos = text.rfind("{", epos);
+ if (spos == std::string::npos)
+ return;
+
+ std::string fname = text.substr(0, spos);
+ std::string props = text.substr(spos + 1, epos - spos - 1);
+ std::vector<std::string> iprops = split_string(",", props, true, true);
+
+ if (iprops.size() < 1 || iprops.size() > 5)
+ return;
+
+ if (iprops.size() < 5)
+ iprops.resize(5);
+
+ trim_string(fname);
+ std::vector<dungeon_feature_type> feats = features_by_desc(fname);
+ if (feats.empty())
+ return;
- switch (ldfk)
+ for (int i = 0, size = feats.size(); i < size; ++i)
{
- case DNGN_UNSEEN:
- showed = 0;
- break;
+ feature_override fov;
+ fov.feat = feats[i];
+
+ fov.override.symbol = read_symbol(iprops[0]);
+ fov.override.magic_symbol = read_symbol(iprops[1]);
+ fov.override.colour = str_to_colour(iprops[2], BLACK);
+ fov.override.map_colour = str_to_colour(iprops[3], BLACK);
+ fov.override.seen_colour = str_to_colour(iprops[4], BLACK);
- case DNGN_SECRET_DOOR:
- case DNGN_ROCK_WALL:
- case DNGN_PERMAROCK_WALL:
- case DNGN_STONE_WALL:
- case DNGN_METAL_WALL:
- case DNGN_GREEN_CRYSTAL_WALL:
- case DNGN_WAX_WALL:
- showed = 177;
- break;
+ Feature_Overrides.push_back(fov);
+ }
+}
- case DNGN_CLOSED_DOOR:
- showed = 254;
- break;
+void apply_feature_overrides()
+{
+ for (int i = 0, size = Feature_Overrides.size(); i < size; ++i)
+ {
+ const feature_override &fov = Feature_Overrides[i];
+ const feature_def &ofeat = fov.override;
+ feature_def &feat = Feature[fov.feat];
+
+ if (ofeat.symbol)
+ feat.symbol = ofeat.symbol;
+ if (ofeat.magic_symbol)
+ feat.magic_symbol = ofeat.magic_symbol;
+ if (ofeat.colour)
+ feat.colour = ofeat.colour;
+ if (ofeat.map_colour)
+ feat.map_colour = ofeat.map_colour;
+ if (ofeat.seen_colour)
+ feat.seen_colour = ofeat.seen_colour;
+ }
+}
- //case DNGN_LAVA_X: showed = 247; break; // deprecated? {dlb}
- //case DNGN_WATER_X: showed = 247; break; // deprecated? {dlb}
+void init_feature_table( void )
+{
+ for (int i = 0; i < NUM_FEATURES; i++)
+ {
+ Feature[i].symbol = 0;
+ Feature[i].colour = BLACK; // means must be set some other way
+ Feature[i].notable = false;
+ Feature[i].seen_effect = false;
+ Feature[i].magic_symbol = 0; // made equal to symbol if untouched
+ Feature[i].map_colour = DARKGREY;
+ Feature[i].seen_colour = BLACK; // marks no special seen map handling
+
+ switch (i)
+ {
+ case DNGN_UNSEEN:
+ default:
+ break;
- case 20: // orcish idol
- case 24: // ???
- case 25: // ???
- case DNGN_SILVER_STATUE:
- case DNGN_GRANITE_STATUE:
- case DNGN_ORANGE_CRYSTAL_STATUE:
- showed = '8';
- break;
+ case DNGN_ROCK_WALL:
+ case DNGN_PERMAROCK_WALL:
+ Feature[i].symbol = Options.char_table[ DCHAR_WALL ];
+ Feature[i].colour = EC_ROCK;
+ Feature[i].magic_symbol = Options.char_table[ DCHAR_WALL_MAGIC ];
+ break;
- case DNGN_LAVA:
- case DNGN_DEEP_WATER:
- case DNGN_SHALLOW_WATER:
- showed = 247;
- break;
+ case DNGN_STONE_WALL:
+ Feature[i].symbol = Options.char_table[ DCHAR_WALL ];
+ Feature[i].colour = EC_STONE;
+ Feature[i].magic_symbol = Options.char_table[ DCHAR_WALL_MAGIC ];
+ break;
- case DNGN_FLOOR:
- case DNGN_UNDISCOVERED_TRAP:
- showed = 249;
- break;
+ case DNGN_OPEN_DOOR:
+ Feature[i].symbol = Options.char_table[ DCHAR_DOOR_OPEN ];
+ Feature[i].colour = LIGHTGREY;
+ break;
- case 68:
- showed = '>';
- break; // <
+ case DNGN_CLOSED_DOOR:
+ Feature[i].symbol = Options.char_table[ DCHAR_DOOR_CLOSED ];
+ Feature[i].colour = LIGHTGREY;
+ break;
- case DNGN_OPEN_DOOR:
- showed = 39;
- break;
+ case DNGN_METAL_WALL:
+ Feature[i].symbol = Options.char_table[ DCHAR_WALL ];
+ Feature[i].colour = CYAN;
+ Feature[i].magic_symbol = Options.char_table[ DCHAR_WALL_MAGIC ];
+ break;
- case 72:
- showed = '<';
- break; // <
+ case DNGN_SECRET_DOOR:
+ // Note: get_secret_door_appearance means this probably isn't used
+ Feature[i].symbol = Options.char_table[ DCHAR_WALL ];
+ Feature[i].colour = EC_ROCK;
+ Feature[i].magic_symbol = Options.char_table[ DCHAR_WALL_MAGIC ];
+ break;
- case DNGN_TRAP_MECHANICAL:
- case DNGN_TRAP_MAGICAL:
- case DNGN_TRAP_III:
- showed = '^';
- break;
+ case DNGN_GREEN_CRYSTAL_WALL:
+ Feature[i].symbol = Options.char_table[ DCHAR_WALL ];
+ Feature[i].colour = GREEN;
+ Feature[i].magic_symbol = Options.char_table[ DCHAR_WALL_MAGIC ];
+ break;
- case DNGN_STONE_STAIRS_DOWN_I:
- case DNGN_STONE_STAIRS_DOWN_II:
- case DNGN_STONE_STAIRS_DOWN_III:
- case DNGN_ROCK_STAIRS_DOWN:
- case DNGN_ENTER_ORCISH_MINES:
- case DNGN_ENTER_HIVE:
- case DNGN_ENTER_LAIR:
- case DNGN_ENTER_SLIME_PITS:
- case DNGN_ENTER_VAULTS:
- case DNGN_ENTER_CRYPT:
- case DNGN_ENTER_HALL_OF_BLADES:
- case DNGN_ENTER_TEMPLE:
- case DNGN_ENTER_SNAKE_PIT:
- case DNGN_ENTER_ELVEN_HALLS:
- case DNGN_ENTER_TOMB:
- case DNGN_ENTER_SWAMP:
- case 123:
- case 124:
- case 125:
- case 126:
- showed = '>';
- break;
+ case DNGN_ORCISH_IDOL:
+ Feature[i].symbol = Options.char_table[ DCHAR_STATUE ];
+ Feature[i].colour = DARKGREY;
+ break;
- case DNGN_STONE_STAIRS_UP_I:
- case DNGN_STONE_STAIRS_UP_II:
- case DNGN_STONE_STAIRS_UP_III:
- case DNGN_ROCK_STAIRS_UP:
- case DNGN_RETURN_FROM_ORCISH_MINES:
- case DNGN_RETURN_FROM_HIVE:
- case DNGN_RETURN_FROM_LAIR:
- case DNGN_RETURN_FROM_SLIME_PITS:
- case DNGN_RETURN_FROM_VAULTS:
- case DNGN_RETURN_FROM_CRYPT:
- case DNGN_RETURN_FROM_HALL_OF_BLADES:
- case DNGN_RETURN_FROM_TEMPLE:
- case DNGN_RETURN_FROM_SNAKE_PIT:
- case DNGN_RETURN_FROM_ELVEN_HALLS:
- case DNGN_RETURN_FROM_TOMB:
- case DNGN_RETURN_FROM_SWAMP:
- case 143:
- case 144:
- case 145:
- case 146:
- showed = '<';
- break;
+ case DNGN_WAX_WALL:
+ Feature[i].symbol = Options.char_table[ DCHAR_WALL ];
+ Feature[i].colour = YELLOW;
+ Feature[i].magic_symbol = Options.char_table[ DCHAR_WALL_MAGIC ];
+ break; // wax wall
- case DNGN_ENTER_HELL:
- case DNGN_ENTER_LABYRINTH:
- case DNGN_ENTER_SHOP:
- case DNGN_ENTER_DIS:
- case DNGN_ENTER_GEHENNA:
- case DNGN_ENTER_COCYTUS:
- case DNGN_ENTER_TARTARUS:
- case DNGN_ENTER_ABYSS:
- case DNGN_EXIT_ABYSS:
- case DNGN_STONE_ARCH:
- case DNGN_ENTER_PANDEMONIUM:
- case DNGN_EXIT_PANDEMONIUM:
- case DNGN_TRANSIT_PANDEMONIUM:
- case DNGN_ENTER_ZOT:
- case DNGN_RETURN_FROM_ZOT:
- showed = 239;
- break;
+ case DNGN_SILVER_STATUE:
+ Feature[i].symbol = Options.char_table[ DCHAR_STATUE ];
+ Feature[i].colour = WHITE;
+ Feature[i].seen_effect = true;
+ break;
- case DNGN_ALTAR_ZIN:
- case DNGN_ALTAR_SHINING_ONE:
- case DNGN_ALTAR_KIKUBAAQUDGHA:
- case DNGN_ALTAR_YREDELEMNUL:
- case DNGN_ALTAR_XOM:
- case DNGN_ALTAR_VEHUMET:
- case DNGN_ALTAR_OKAWARU:
- case DNGN_ALTAR_MAKHLEB:
- case DNGN_ALTAR_SIF_MUNA:
- case DNGN_ALTAR_TROG:
- case DNGN_ALTAR_NEMELEX_XOBEH:
- case DNGN_ALTAR_ELYVILON:
- showed = 220;
- break;
+ case DNGN_GRANITE_STATUE:
+ Feature[i].symbol = Options.char_table[ DCHAR_STATUE ];
+ Feature[i].colour = LIGHTGREY;
+ break;
- case DNGN_BLUE_FOUNTAIN:
- case DNGN_DRY_FOUNTAIN_I:
- case DNGN_SPARKLING_FOUNTAIN:
- case DNGN_DRY_FOUNTAIN_II:
- case DNGN_DRY_FOUNTAIN_III:
- case DNGN_DRY_FOUNTAIN_IV:
- case DNGN_DRY_FOUNTAIN_V:
- case DNGN_DRY_FOUNTAIN_VI:
- case DNGN_DRY_FOUNTAIN_VII:
- case DNGN_DRY_FOUNTAIN_VIII:
- case DNGN_PERMADRY_FOUNTAIN:
- showed = 159;
- break;
- default:
- showed = 0;
- break;
- }
+ case DNGN_ORANGE_CRYSTAL_STATUE:
+ Feature[i].symbol = Options.char_table[ DCHAR_STATUE ];
+ Feature[i].colour = LIGHTRED;
+ Feature[i].seen_effect = true;
+ break;
- return showed;
-}
+ case DNGN_LAVA:
+ Feature[i].symbol = Options.char_table[ DCHAR_WAVY ];
+ Feature[i].colour = RED;
+ break;
+ case DNGN_DEEP_WATER:
+ Feature[i].symbol = Options.char_table[ DCHAR_WAVY ];
+ Feature[i].colour = BLUE;
+ break;
-// realize that this is simply a repackaged version of
-// stuff::see_grid() -- make certain they correlate {dlb}:
-bool mons_near(struct monsters *monster, unsigned int foe)
-{
- // early out -- no foe!
- if (foe == MHITNOT)
- return (false);
+ case DNGN_SHALLOW_WATER:
+ Feature[i].symbol = Options.char_table[ DCHAR_WAVY ];
+ Feature[i].colour = CYAN;
+ break;
- if (foe == MHITYOU)
- {
- if (monster->x > you.x_pos - 9 && monster->x < you.x_pos + 9
- && monster->y > you.y_pos - 9 && monster->y < you.y_pos + 9)
- {
- if (env.show[monster->x - you.x_pos + 9][monster->y - you.y_pos + 9])
- return (true);
- }
- return (false);
- }
+ case DNGN_FLOOR:
+ Feature[i].symbol = Options.char_table[ DCHAR_FLOOR ];
+ Feature[i].colour = EC_FLOOR;
+ Feature[i].magic_symbol = Options.char_table[ DCHAR_FLOOR_MAGIC ];
+ break;
- // must be a monster
- struct monsters *myFoe = &menv[foe];
- if (myFoe->type >= 0)
- {
- if (monster->x > myFoe->x - 9 && monster->x < myFoe->x + 9
- && monster->y > myFoe->y - 9 && monster->y < myFoe->y + 9)
- {
- return (true);
- }
- }
+ case DNGN_EXIT_HELL:
+ Feature[i].symbol = Options.char_table[ DCHAR_ARCH ];
+ Feature[i].colour = LIGHTRED;
+ Feature[i].notable = false;
+ Feature[i].map_colour = LIGHTGREY;
+ Feature[i].seen_colour = LIGHTRED;
+ break;
- return (false);
-} // end mons_near()
+ case DNGN_ENTER_HELL:
+ Feature[i].symbol = Options.char_table[ DCHAR_ARCH ];
+ Feature[i].colour = RED;
+ Feature[i].notable = true;
+ Feature[i].map_colour = LIGHTGREY;
+ Feature[i].seen_colour = RED;
+ break;
+ case DNGN_TRAP_MECHANICAL:
+ Feature[i].colour = LIGHTCYAN;
+ Feature[i].symbol = Options.char_table[ DCHAR_TRAP ];
+ Feature[i].map_colour = LIGHTCYAN;
+ break;
-//---------------------------------------------------------------
-//
-// get_non_ibm_symbol
-//
-// Returns the character code and color for everything drawn
-// without the IBM graphics option.
-//
-//---------------------------------------------------------------
-void get_non_ibm_symbol(unsigned int object, unsigned short *ch,
- unsigned short *color)
-{
- ASSERT(color != NULL);
- ASSERT(ch != NULL);
+ case DNGN_TRAP_MAGICAL:
+ Feature[i].colour = MAGENTA;
+ Feature[i].symbol = Options.char_table[ DCHAR_TRAP ];
+ Feature[i].map_colour = MAGENTA;
+ break;
- switch (object)
- {
+ case DNGN_TRAP_III:
+ Feature[i].colour = LIGHTGREY;
+ Feature[i].symbol = Options.char_table[ DCHAR_TRAP ];
+ Feature[i].map_colour = LIGHTGREY;
+ break;
- case DNGN_UNSEEN:
- *ch = 0;
- break;
+ case DNGN_UNDISCOVERED_TRAP:
+ Feature[i].symbol = Options.char_table[ DCHAR_FLOOR ];
+ Feature[i].colour = EC_FLOOR;
+ Feature[i].magic_symbol = Options.char_table[ DCHAR_FLOOR_MAGIC ];
+ break;
- case DNGN_ROCK_WALL:
- case DNGN_PERMAROCK_WALL:
- *color = env.rock_colour;
- *ch = '#';
- break;
+ case DNGN_ENTER_SHOP:
+ Feature[i].symbol = Options.char_table[ DCHAR_ARCH ];
+ Feature[i].colour = YELLOW;
+ Feature[i].notable = true;
+ Feature[i].map_colour = LIGHTGREY;
+ Feature[i].seen_colour = YELLOW;
+ break;
- case DNGN_STONE_WALL:
- if (player_in_branch( BRANCH_HALL_OF_ZOT ))
- *color = env.rock_colour;
- else
- *color = LIGHTGREY;
- *ch = '#';
- break;
+ case DNGN_ENTER_LABYRINTH:
+ Feature[i].symbol = Options.char_table[ DCHAR_ARCH ];
+ Feature[i].colour = CYAN;
+ Feature[i].notable = true;
+ Feature[i].map_colour = LIGHTGREY;
+ Feature[i].seen_colour = CYAN;
+ break;
- case DNGN_CLOSED_DOOR:
- *ch = '+';
- break;
+ case DNGN_ROCK_STAIRS_DOWN:
+ case DNGN_STONE_STAIRS_DOWN_I:
+ case DNGN_STONE_STAIRS_DOWN_II:
+ case DNGN_STONE_STAIRS_DOWN_III:
+ Feature[i].symbol = Options.char_table[ DCHAR_STAIRS_DOWN ];
+ Feature[i].colour = ((i == DNGN_ROCK_STAIRS_DOWN) ? BROWN
+ : LIGHTGREY);
+ Feature[i].map_colour = RED;
+ break;
- case DNGN_METAL_WALL:
- *ch = '#';
- *color = CYAN;
- break;
+ case DNGN_ROCK_STAIRS_UP:
+ case DNGN_STONE_STAIRS_UP_I:
+ case DNGN_STONE_STAIRS_UP_II:
+ case DNGN_STONE_STAIRS_UP_III:
+ Feature[i].symbol = Options.char_table[ DCHAR_STAIRS_UP ];
+ Feature[i].colour = ((i == DNGN_ROCK_STAIRS_UP) ? BROWN
+ : LIGHTGREY);
+ Feature[i].map_colour = GREEN;
+ break;
- case DNGN_SECRET_DOOR:
- *ch = '#';
- *color = env.rock_colour;
- break;
+ case DNGN_ENTER_DIS:
+ Feature[i].colour = CYAN;
+ Feature[i].symbol = Options.char_table[ DCHAR_ARCH ];
+ Feature[i].notable = true;
+ Feature[i].map_colour = LIGHTGREY;
+ Feature[i].seen_colour = CYAN;
+ break;
- case DNGN_GREEN_CRYSTAL_WALL:
- *ch = '#';
- *color = GREEN;
- break;
+ case DNGN_ENTER_GEHENNA:
+ Feature[i].colour = RED;
+ Feature[i].symbol = Options.char_table[ DCHAR_ARCH ];
+ Feature[i].notable = true;
+ Feature[i].map_colour = LIGHTGREY;
+ Feature[i].seen_colour = RED;
+ break;
- case DNGN_ORCISH_IDOL:
- *ch = '8';
- *color = DARKGREY;
- break;
+ case DNGN_ENTER_COCYTUS:
+ Feature[i].colour = LIGHTCYAN;
+ Feature[i].symbol = Options.char_table[ DCHAR_ARCH ];
+ Feature[i].notable = true;
+ Feature[i].map_colour = LIGHTGREY;
+ Feature[i].seen_colour = LIGHTCYAN;
+ break;
- case DNGN_WAX_WALL:
- *ch = '#';
- *color = YELLOW;
- break;
+ case DNGN_ENTER_TARTARUS:
+ Feature[i].colour = DARKGREY;
+ Feature[i].symbol = Options.char_table[ DCHAR_ARCH ];
+ Feature[i].notable = true;
+ Feature[i].map_colour = LIGHTGREY;
+ Feature[i].seen_colour = DARKGREY;
+ break;
- case DNGN_SILVER_STATUE:
- *ch = '8';
- *color = WHITE;
- Visible_Statue[ STATUE_SILVER ] = 1;
- break;
+ case DNGN_ENTER_ABYSS:
+ Feature[i].colour = EC_RANDOM;
+ Feature[i].symbol = Options.char_table[ DCHAR_ARCH ];
+ Feature[i].notable = true;
+ Feature[i].map_colour = LIGHTGREY;
+ Feature[i].seen_colour = EC_RANDOM;
+ break;
- case DNGN_GRANITE_STATUE:
- *ch = '8';
- *color = LIGHTGREY;
- break;
+ case DNGN_EXIT_ABYSS:
+ Feature[i].colour = EC_RANDOM;
+ Feature[i].symbol = Options.char_table[ DCHAR_ARCH ];
+ Feature[i].map_colour = EC_RANDOM;
+ break;
- case DNGN_ORANGE_CRYSTAL_STATUE:
- *ch = '8';
- *color = LIGHTRED;
- Visible_Statue[ STATUE_ORANGE_CRYSTAL ] = 1;
- break;
+ case DNGN_STONE_ARCH:
+ Feature[i].colour = LIGHTGREY;
+ Feature[i].symbol = Options.char_table[ DCHAR_ARCH ];
+ Feature[i].map_colour = LIGHTGREY;
+ break;
- case DNGN_LAVA:
- *ch = '{';
- *color = RED;
- break;
+ case DNGN_ENTER_PANDEMONIUM:
+ Feature[i].colour = LIGHTBLUE;
+ Feature[i].symbol = Options.char_table[ DCHAR_ARCH ];
+ Feature[i].notable = true;
+ Feature[i].map_colour = LIGHTGREY;
+ Feature[i].seen_colour = LIGHTBLUE;
+ break;
- case DNGN_DEEP_WATER:
- *ch = '{';
- // this wavy thing also used for water elemental
- // note that some monsters which use IBM graphics aren't set
- // for this function - too tricky for now.
- *color = BLUE;
- break;
+ case DNGN_EXIT_PANDEMONIUM:
+ // Note: has special handling for colouring with mutation
+ Feature[i].colour = LIGHTBLUE;
+ Feature[i].symbol = Options.char_table[ DCHAR_ARCH ];
+ Feature[i].map_colour = LIGHTGREY;
+ Feature[i].seen_colour = LIGHTBLUE;
+ break;
- case DNGN_SHALLOW_WATER:
- *color = CYAN;
- *ch = '{';
- break;
+ case DNGN_TRANSIT_PANDEMONIUM:
+ Feature[i].colour = LIGHTGREEN;
+ Feature[i].symbol = Options.char_table[ DCHAR_ARCH ];
+ Feature[i].map_colour = LIGHTGREY;
+ Feature[i].seen_colour = LIGHTGREEN;
+ break;
- case DNGN_FLOOR:
- *color = env.floor_colour;
- *ch = '.';
- break;
+ case DNGN_ENTER_ORCISH_MINES:
+ case DNGN_ENTER_HIVE:
+ case DNGN_ENTER_LAIR:
+ case DNGN_ENTER_SLIME_PITS:
+ case DNGN_ENTER_VAULTS:
+ case DNGN_ENTER_CRYPT:
+ case DNGN_ENTER_HALL_OF_BLADES:
+ case DNGN_ENTER_TEMPLE:
+ case DNGN_ENTER_SNAKE_PIT:
+ case DNGN_ENTER_ELVEN_HALLS:
+ case DNGN_ENTER_TOMB:
+ case DNGN_ENTER_SWAMP:
+ case DNGN_ENTER_RESERVED_1:
+ case DNGN_ENTER_RESERVED_2:
+ case DNGN_ENTER_RESERVED_3:
+ case DNGN_ENTER_RESERVED_4:
+ Feature[i].colour = YELLOW;
+ Feature[i].symbol = Options.char_table[ DCHAR_STAIRS_DOWN ];
+ Feature[i].notable = true;
+ Feature[i].map_colour = RED;
+ Feature[i].seen_colour = LIGHTRED;
+ break;
- case DNGN_ENTER_HELL:
- *color = RED;
- *ch = '\\';
- seen_other_thing(DNGN_ENTER_HELL);
- break;
+ case DNGN_ENTER_ZOT:
+ Feature[i].colour = MAGENTA;
+ Feature[i].symbol = Options.char_table[ DCHAR_ARCH ];
+ Feature[i].notable = true;
+ Feature[i].map_colour = LIGHTGREY;
+ Feature[i].seen_colour = MAGENTA;
+ break;
- case DNGN_OPEN_DOOR:
- *ch = '\'';
- break;
+ case DNGN_RETURN_FROM_ORCISH_MINES:
+ case DNGN_RETURN_FROM_HIVE:
+ case DNGN_RETURN_FROM_LAIR:
+ case DNGN_RETURN_FROM_SLIME_PITS:
+ case DNGN_RETURN_FROM_VAULTS:
+ case DNGN_RETURN_FROM_CRYPT:
+ case DNGN_RETURN_FROM_HALL_OF_BLADES:
+ case DNGN_RETURN_FROM_TEMPLE:
+ case DNGN_RETURN_FROM_SNAKE_PIT:
+ case DNGN_RETURN_FROM_ELVEN_HALLS:
+ case DNGN_RETURN_FROM_TOMB:
+ case DNGN_RETURN_FROM_SWAMP:
+ case DNGN_RETURN_RESERVED_1:
+ case DNGN_RETURN_RESERVED_2:
+ case DNGN_RETURN_RESERVED_3:
+ case DNGN_RETURN_RESERVED_4:
+ Feature[i].colour = YELLOW;
+ Feature[i].symbol = Options.char_table[ DCHAR_STAIRS_UP ];
+ Feature[i].map_colour = BLUE;
+ Feature[i].seen_colour = LIGHTBLUE;
+ break;
- case DNGN_BRANCH_STAIRS:
- *color = BROWN;
- *ch = '>';
- break;
+ case DNGN_RETURN_FROM_ZOT:
+ Feature[i].colour = MAGENTA;
+ Feature[i].symbol = Options.char_table[ DCHAR_ARCH ];
+ Feature[i].map_colour = LIGHTGREY;
+ Feature[i].seen_colour = MAGENTA;
+ break;
- case DNGN_TRAP_MECHANICAL:
- *color = 11;
- *ch = '^';
- break;
+ case DNGN_ALTAR_ZIN:
+ Feature[i].colour = WHITE;
+ Feature[i].symbol = Options.char_table[ DCHAR_ALTAR ];
+ Feature[i].notable = true;
+ Feature[i].map_colour = DARKGREY;
+ Feature[i].seen_colour = WHITE;
+ break;
- case DNGN_TRAP_MAGICAL:
- *color = MAGENTA;
- *ch = '^';
- break;
+ case DNGN_ALTAR_SHINING_ONE:
+ Feature[i].colour = YELLOW;
+ Feature[i].symbol = Options.char_table[ DCHAR_ALTAR ];
+ Feature[i].notable = true;
+ Feature[i].map_colour = DARKGREY;
+ Feature[i].seen_colour = YELLOW;
+ break;
- case DNGN_TRAP_III:
- *color = LIGHTGREY;
- *ch = '^';
- break;
+ case DNGN_ALTAR_KIKUBAAQUDGHA:
+ Feature[i].colour = DARKGREY;
+ Feature[i].symbol = Options.char_table[ DCHAR_ALTAR ];
+ Feature[i].notable = true;
+ Feature[i].map_colour = DARKGREY;
+ Feature[i].seen_colour = DARKGREY;
+ break;
- case DNGN_UNDISCOVERED_TRAP:
- *color = env.floor_colour;
- *ch = '.';
- break;
+ case DNGN_ALTAR_YREDELEMNUL:
+ Feature[i].colour = EC_UNHOLY;
+ Feature[i].symbol = Options.char_table[ DCHAR_ALTAR ];
+ Feature[i].notable = true;
+ Feature[i].map_colour = DARKGREY;
+ Feature[i].seen_colour = EC_UNHOLY;
+ break;
- case DNGN_ENTER_SHOP:
- *color = YELLOW;
- *ch = '\\';
- seen_other_thing(DNGN_ENTER_SHOP);
- break;
-// if I change anything above here, must also change magic mapping!
+ case DNGN_ALTAR_XOM:
+ Feature[i].colour = EC_RANDOM;
+ Feature[i].symbol = Options.char_table[ DCHAR_ALTAR ];
+ Feature[i].notable = true;
+ Feature[i].map_colour = DARKGREY;
+ Feature[i].seen_colour = EC_RANDOM;
+ break;
- case DNGN_ENTER_LABYRINTH:
- *color = LIGHTGREY;
- *ch = '\\';
- seen_other_thing(DNGN_ENTER_LABYRINTH);
- break;
+ case DNGN_ALTAR_VEHUMET:
+ Feature[i].colour = EC_VEHUMET;
+ Feature[i].symbol = Options.char_table[ DCHAR_ALTAR ];
+ Feature[i].notable = true;
+ Feature[i].map_colour = DARKGREY;
+ Feature[i].seen_colour = EC_VEHUMET;
+ break;
- case DNGN_ROCK_STAIRS_DOWN:
- *color = BROWN; // ladder
- case DNGN_STONE_STAIRS_DOWN_I:
- case DNGN_STONE_STAIRS_DOWN_II:
- case DNGN_STONE_STAIRS_DOWN_III:
- *ch = '>';
- break;
+ case DNGN_ALTAR_OKAWARU:
+ Feature[i].colour = CYAN;
+ Feature[i].symbol = Options.char_table[ DCHAR_ALTAR ];
+ Feature[i].notable = true;
+ Feature[i].map_colour = DARKGREY;
+ Feature[i].seen_colour = CYAN;
+ break;
- case DNGN_ROCK_STAIRS_UP:
- *color = BROWN; // ladder
- case DNGN_STONE_STAIRS_UP_I:
- case DNGN_STONE_STAIRS_UP_II:
- case DNGN_STONE_STAIRS_UP_III:
- *ch = '<';
- break;
+ case DNGN_ALTAR_MAKHLEB:
+ Feature[i].colour = EC_FIRE;
+ Feature[i].symbol = Options.char_table[ DCHAR_ALTAR ];
+ Feature[i].notable = true;
+ Feature[i].map_colour = DARKGREY;
+ Feature[i].seen_colour = EC_FIRE;
+ break;
- case DNGN_ENTER_DIS:
- *color = CYAN;
- *ch = '\\';
- break;
+ case DNGN_ALTAR_SIF_MUNA:
+ Feature[i].colour = BLUE;
+ Feature[i].symbol = Options.char_table[ DCHAR_ALTAR ];
+ Feature[i].notable = true;
+ Feature[i].map_colour = DARKGREY;
+ Feature[i].seen_colour = BLUE;
+ break;
- case DNGN_ENTER_GEHENNA:
- *color = RED;
- *ch = '\\';
- break;
+ case DNGN_ALTAR_TROG:
+ Feature[i].colour = RED;
+ Feature[i].symbol = Options.char_table[ DCHAR_ALTAR ];
+ Feature[i].notable = true;
+ Feature[i].map_colour = DARKGREY;
+ Feature[i].seen_colour = RED;
+ break;
- case DNGN_ENTER_COCYTUS:
- *color = LIGHTCYAN;
- *ch = '\\';
- break;
+ case DNGN_ALTAR_NEMELEX_XOBEH:
+ Feature[i].colour = LIGHTMAGENTA;
+ Feature[i].symbol = Options.char_table[ DCHAR_ALTAR ];
+ Feature[i].notable = true;
+ Feature[i].map_colour = DARKGREY;
+ Feature[i].seen_colour = LIGHTMAGENTA;
+ break;
- case DNGN_ENTER_TARTARUS:
- *color = DARKGREY;
- *ch = '\\';
- break;
+ case DNGN_ALTAR_ELYVILON:
+ Feature[i].colour = LIGHTGREY;
+ Feature[i].symbol = Options.char_table[ DCHAR_ALTAR ];
+ Feature[i].notable = true;
+ Feature[i].map_colour = DARKGREY;
+ Feature[i].seen_colour = LIGHTGREY;
+ break;
- case DNGN_ENTER_ABYSS:
- *color = random2(16);
- *ch = '\\';
- seen_other_thing(DNGN_ENTER_ABYSS);
- break;
+ case DNGN_BLUE_FOUNTAIN:
+ Feature[i].colour = BLUE;
+ Feature[i].symbol = Options.char_table[ DCHAR_FOUNTAIN ];
+ break;
- case DNGN_EXIT_ABYSS:
- *color = random2(16);
- *ch = '\\';
- break;
+ case DNGN_SPARKLING_FOUNTAIN:
+ Feature[i].colour = LIGHTBLUE;
+ Feature[i].symbol = Options.char_table[ DCHAR_FOUNTAIN ];
+ break;
- case DNGN_STONE_ARCH:
- *color = LIGHTGREY;
- *ch = '\\';
- break;
+ case DNGN_DRY_FOUNTAIN_I:
+ case DNGN_DRY_FOUNTAIN_II:
+ case DNGN_PERMADRY_FOUNTAIN:
+ Feature[i].colour = LIGHTGREY;
+ Feature[i].symbol = Options.char_table[ DCHAR_FOUNTAIN ];
+ break;
- case DNGN_ENTER_PANDEMONIUM:
- *color = LIGHTBLUE;
- *ch = '\\';
- seen_other_thing(DNGN_ENTER_PANDEMONIUM);
- break;
+ case DNGN_INVIS_EXPOSED:
+ Feature[i].symbol = Options.char_table[ DCHAR_INVIS_EXPOSED ];
+ break;
- case DNGN_EXIT_PANDEMONIUM:
- *color = LIGHTBLUE;
- *ch = '\\';
- break;
+ case DNGN_ITEM_DETECTED:
+ Feature[i].magic_symbol = Options.char_table[ DCHAR_ITEM_DETECTED ];
+ break;
- case DNGN_TRANSIT_PANDEMONIUM:
- *color = LIGHTGREEN;
- *ch = '\\';
- break; // gate to other part of pandemonium
-
- case DNGN_ENTER_ORCISH_MINES:
- case DNGN_ENTER_HIVE:
- case DNGN_ENTER_LAIR:
- case DNGN_ENTER_SLIME_PITS:
- case DNGN_ENTER_VAULTS:
- case DNGN_ENTER_CRYPT:
- case DNGN_ENTER_HALL_OF_BLADES:
- case DNGN_ENTER_TEMPLE:
- case DNGN_ENTER_SNAKE_PIT:
- case DNGN_ENTER_ELVEN_HALLS:
- case DNGN_ENTER_TOMB:
- case DNGN_ENTER_SWAMP:
- case 123:
- case 124:
- case 125:
- case 126:
- *color = YELLOW;
- *ch = '>';
- seen_staircase(object);
- break;
+ case DNGN_ITEM_ORB:
+ Feature[i].symbol = Options.char_table[ DCHAR_ITEM_ORB ];
+ break;
- case DNGN_ENTER_ZOT:
- *color = MAGENTA;
- *ch = '\\';
- seen_staircase(object);
- break;
+ case DNGN_ITEM_WEAPON:
+ Feature[i].symbol = Options.char_table[ DCHAR_ITEM_WEAPON ];
+ break;
- case DNGN_RETURN_FROM_ORCISH_MINES:
- case DNGN_RETURN_FROM_HIVE:
- case DNGN_RETURN_FROM_LAIR:
- case DNGN_RETURN_FROM_SLIME_PITS:
- case DNGN_RETURN_FROM_VAULTS:
- case DNGN_RETURN_FROM_CRYPT:
- case DNGN_RETURN_FROM_HALL_OF_BLADES:
- case DNGN_RETURN_FROM_TEMPLE:
- case DNGN_RETURN_FROM_SNAKE_PIT:
- case DNGN_RETURN_FROM_ELVEN_HALLS:
- case DNGN_RETURN_FROM_TOMB:
- case DNGN_RETURN_FROM_SWAMP:
- case 143:
- case 144:
- case 145:
- case 146:
- *color = YELLOW;
- *ch = '<';
- break;
+ case DNGN_ITEM_ARMOUR:
+ Feature[i].symbol = Options.char_table[ DCHAR_ITEM_ARMOUR ];
+ break;
- case DNGN_RETURN_FROM_ZOT:
- *color = MAGENTA;
- *ch = '\\';
- break;
+ case DNGN_ITEM_WAND:
+ Feature[i].symbol = Options.char_table[ DCHAR_ITEM_WAND ];
+ break;
- case DNGN_ALTAR_ZIN:
- *color = WHITE;
- *ch = '_';
- seen_altar(GOD_ZIN);
- break;
+ case DNGN_ITEM_FOOD:
+ Feature[i].symbol = Options.char_table[ DCHAR_ITEM_FOOD ];
+ break;
- case DNGN_ALTAR_SHINING_ONE:
- *color = YELLOW;
- *ch = '_';
- seen_altar(GOD_SHINING_ONE);
- break;
+ case DNGN_ITEM_SCROLL:
+ Feature[i].symbol = Options.char_table[ DCHAR_ITEM_SCROLL ];
+ break;
- case DNGN_ALTAR_KIKUBAAQUDGHA:
- *color = DARKGREY;
- *ch = '_';
- seen_altar(GOD_KIKUBAAQUDGHA);
- break;
+ case DNGN_ITEM_RING:
+ Feature[i].symbol = Options.char_table[ DCHAR_ITEM_RING ];
+ break;
- case DNGN_ALTAR_YREDELEMNUL:
- *color = DARKGREY;
- if (one_chance_in(3))
- *color = RED;
- *ch = '_';
- seen_altar(GOD_YREDELEMNUL);
- break;
+ case DNGN_ITEM_POTION:
+ Feature[i].symbol = Options.char_table[ DCHAR_ITEM_POTION ];
+ break;
- case DNGN_ALTAR_XOM:
- *color = random_colour();
- *ch = '_';
- seen_altar(GOD_XOM);
- break;
+ case DNGN_ITEM_MISSILE:
+ Feature[i].symbol = Options.char_table[ DCHAR_ITEM_MISSILE ];
+ break;
- case DNGN_ALTAR_VEHUMET:
- *color = LIGHTBLUE;
- if (one_chance_in(3))
- *color = LIGHTMAGENTA;
- if (one_chance_in(3))
- *color = LIGHTRED;
- *ch = '_';
- seen_altar(GOD_VEHUMET);
- break;
+ case DNGN_ITEM_BOOK:
+ Feature[i].symbol = Options.char_table[ DCHAR_ITEM_BOOK ];
+ break;
- case DNGN_ALTAR_OKAWARU:
- *color = CYAN;
- *ch = '_';
- seen_altar(GOD_OKAWARU);
- break;
+ case DNGN_ITEM_STAVE:
+ Feature[i].symbol = Options.char_table[ DCHAR_ITEM_STAVE ];
+ break;
- case DNGN_ALTAR_MAKHLEB:
- *color = RED;
- if (one_chance_in(3))
- *color = LIGHTRED;
- if (one_chance_in(3))
- *color = YELLOW;
- *ch = '_';
- seen_altar(GOD_MAKHLEB);
- break;
+ case DNGN_ITEM_MISCELLANY:
+ Feature[i].symbol = Options.char_table[ DCHAR_ITEM_MISCELLANY ];
+ break;
- case DNGN_ALTAR_SIF_MUNA:
- *color = BLUE;
- *ch = '_';
- seen_altar(GOD_SIF_MUNA);
- break;
+ case DNGN_ITEM_CORPSE:
+ Feature[i].symbol = Options.char_table[ DCHAR_ITEM_CORPSE ];
+ break;
- case DNGN_ALTAR_TROG:
- *color = RED;
- *ch = '_';
- seen_altar(GOD_TROG);
- break;
+ case DNGN_ITEM_GOLD:
+ Feature[i].symbol = Options.char_table[ DCHAR_ITEM_GOLD ];
+ break;
- case DNGN_ALTAR_NEMELEX_XOBEH:
- *color = LIGHTMAGENTA;
- *ch = '_';
- seen_altar(GOD_NEMELEX_XOBEH);
- break;
+ case DNGN_ITEM_AMULET:
+ Feature[i].symbol = Options.char_table[ DCHAR_ITEM_AMULET ];
+ break;
- case DNGN_ALTAR_ELYVILON:
- *color = LIGHTGREY;
- *ch = '_';
- seen_altar(GOD_ELYVILON);
- break;
+ case DNGN_CLOUD:
+ Feature[i].symbol = Options.char_table[ DCHAR_CLOUD ];
+ break;
+ }
+ }
- case DNGN_BLUE_FOUNTAIN:
- *color = BLUE;
- *ch = '}';
- break;
+ apply_feature_overrides();
- case DNGN_SPARKLING_FOUNTAIN:
- *color = LIGHTBLUE;
- *ch = '}';
- break;
+ for (int i = 0; i < NUM_FEATURES; ++i)
+ {
+ if (!Feature[i].magic_symbol)
+ Feature[i].magic_symbol = Feature[i].symbol;
- case DNGN_DRY_FOUNTAIN_I:
- case DNGN_DRY_FOUNTAIN_II:
- case DNGN_PERMADRY_FOUNTAIN:
- *color = LIGHTGREY;
- *ch = '}';
- break;
+ if (Feature[i].seen_colour == BLACK)
+ Feature[i].seen_colour = Feature[i].map_colour;
+ }
+}
- case 256:
- *ch = '0';
- break;
+static int get_screen_glyph( int x, int y )
+{
+ const int ex = x - you.x_pos + 9;
+ const int ey = y - you.y_pos + 9;
- case 257:
- *color = CYAN;
- *ch = '~';
- break; /* Invis creature walking through water */
+ int object = env.show[ex][ey];
+ unsigned short colour = env.show_col[ex][ey];
+ unsigned short ch;
- case 258:
- *ch = ')';
- break; // weapon )
+ if (!object)
+ return get_envmap_char(x, y);
- case 259:
- *ch = '[';
- break; // armour [
+ if (object == DNGN_SECRET_DOOR)
+ object = grid_secret_door_appearance( x, y );
- case 260:
- *ch = '/';
- break; // wands, etc.
+ get_symbol( object, &ch, &colour );
+ return (ch);
+}
- case 261:
- *ch = '%';
- break; // food
+// Returns a string containing an ASCII representation of the map. If fullscreen
+// is set to false, only the viewable area is returned. Leading and trailing
+// spaces are trimmed from each line. Leading and trailing empty lines are also
+// snipped.
+std::string screenshot( bool fullscreen )
+{
+ UNUSED( fullscreen );
- case 262:
- *ch = '+';
- break; // books +
+ const int X_SIZE = VIEW_WIDTH;
+ const int Y_SIZE = VIEW_HEIGHT;
- case 263:
- *ch = '?';
- break; // scroll ?
+ // [ds] Screenshots need to be straight ASCII. We will now proceed to force
+ // the char and feature tables back to ASCII.
+ FixedVector<unsigned char, NUM_DCHAR_TYPES> char_table_bk;
+ char_table_bk = Options.char_table;
- case 264:
- *ch = '=';
- break; // ring = etc
+ init_char_table(CSET_ASCII);
+ init_feature_table();
+
+ int firstnonspace = -1;
+ int firstpopline = -1;
+ int lastpopline = -1;
- case 265:
- *ch = '!';
- break; // potions !
+ char lines[Y_SIZE][X_SIZE + 1];
+ for (int count_y = 0; count_y < Y_SIZE; count_y++)
+ {
+ int lastnonspace = -1;
+
+ for (int count_x = 0; count_x < X_SIZE; count_x++)
+ {
+ // in grid coords
+ const int gx = count_x + you.x_pos - 16;
+ const int gy = count_y + you.y_pos - 8;
+
+ int ch = (!map_bounds(gx, gy))
+ ? 0
+ : (count_x < 8 || count_x > 24)
+ ? get_envmap_char(gx, gy)
+ : (gx == you.x_pos && gy == you.y_pos)
+ ? you.symbol
+ : get_screen_glyph(gx, gy);
+
+ if (ch && !isprint(ch))
+ {
+ // [ds] Evil hack time again. Peek at grid, use that character.
+ int object = grd[gx][gy];
+ unsigned short glych, glycol;
- case 266:
- *ch = '(';
- break; // stones
+ if (object == DNGN_SECRET_DOOR)
+ object = grid_secret_door_appearance( gx, gy );
- case 267:
- *ch = ':';
- break; // book +
+ get_symbol( object, &glych, &glycol );
+ ch = glych;
+ }
+
+ // More mangling to accommodate C strings.
+ if (!ch)
+ ch = ' ';
- case 268:
- *ch = '%';
- break; // corpses part 1
+ if (ch != ' ')
+ {
+ lastnonspace = count_x;
+ lastpopline = count_y;
- case 269:
- *ch = '|';
- break; // magical staves
+ if (firstnonspace == -1 || firstnonspace > count_x)
+ firstnonspace = count_x;
- case 270:
- *ch = '}';
- break; // gems
+ if (firstpopline == -1)
+ firstpopline = count_y;
+ }
- case 271:
- *ch = '%';
- break; // don't know ?
+ lines[count_y][count_x] = ch;
+ }
- case 272:
- *ch = '$';
- *color = YELLOW;
- break; // $ gold
+ lines[count_y][lastnonspace + 1] = 0;
+ }
- case 273:
- *ch = '"';
- break; // amulet
+ // Restore char and feature tables
+ Options.char_table = char_table_bk;
+ init_feature_table();
- default:
- int mnr = object;
- *ch = ((mnr >= 297) ? mons_char(mnr - 297) : object); // yeah
- break;
+ std::string ss;
+ if (firstpopline != -1 && lastpopline != -1)
+ {
+ if (firstnonspace == -1)
+ firstnonspace = 0;
+
+ for (int i = firstpopline; i <= lastpopline; ++i)
+ {
+ char *curr = lines[i];
+
+ while (*curr && curr - lines[i] < firstnonspace)
+ curr++;
+
+ ss += curr;
+ ss += EOL;
+ }
}
-}
+ return (ss);
+}
-/*
- This is the viewwindow function for computers without IBM graphic displays.
- It is activated by a command line argument, which sets a function pointer.
- */
-void viewwindow3(char draw_it, bool do_updates)
+static int viewmap_flash_colour()
{
- int bufcount = 0;
- FixedVector < unsigned short, 1500 > buffy; //[800]; //392];
+ if (you.special_wield == SPWLD_SHADOW)
+ return (DARKGREY);
+ else if (you.berserker)
+ return (RED);
+
+ return (BLACK);
+}
- unsigned short ch, color;
+//---------------------------------------------------------------
+//
+// viewwindow -- now unified and rolled into a single pass
+//
+// Draws the main window using the character set returned
+// by get_symbol().
+//
+// This function should not interfere with the game condition,
+// unless do_updates is set (ie. stealth checks for visible
+// monsters).
+//
+//---------------------------------------------------------------
+void viewwindow(bool draw_it, bool do_updates)
+{
+ const int X_SIZE = VIEW_WIDTH;
+ const int Y_SIZE = VIEW_HEIGHT;
+ const int BUFFER_SIZE = 1550;
+ FixedVector < screen_buffer_t, BUFFER_SIZE > buffy;
int count_x, count_y;
- losight(env.show, grd, you.x_pos, you.y_pos);
+ losight( env.show, grd, you.x_pos, you.y_pos ); // must be done first
+
+ for (count_x = 0; count_x < NUM_STATUE_TYPES; count_x++)
+ you.visible_statue[count_x] = 0;
for (count_x = 0; count_x < 18; count_x++)
{
for (count_y = 0; count_y < 18; count_y++)
{
env.show_col[count_x][count_y] = LIGHTGREY;
- show_backup[count_x][count_y] = 0;
+ Show_Backup[count_x][count_y] = 0;
}
}
- item();
+ item_grid(); // must be done before cloud and monster
cloud_grid();
- monster_grid(do_updates);
- bufcount = 0;
+ monster_grid( do_updates );
- if (draw_it == 1)
+ if (draw_it)
{
_setcursortype(_NOCURSOR);
- for (count_y = (you.y_pos - 8); (count_y < you.y_pos + 9); count_y++)
- {
- bufcount += 16;
- for (count_x = (you.x_pos - 8); (count_x < you.x_pos + 9); count_x++)
+ const bool map = player_in_mappable_area();
+ int bufcount = 0;
+
+ int flash_colour = you.flash_colour;
+ if (flash_colour == BLACK)
+ flash_colour = viewmap_flash_colour();
+
+ for (count_y = 0; count_y < Y_SIZE; count_y++)
+ {
+ for (count_x = 0; count_x < X_SIZE; count_x++)
{
- color = env.show_col[count_x - you.x_pos + 9]
- [count_y - you.y_pos + 9];
+ // in grid coords
+ const int gx = count_x + you.x_pos - 16;
+ const int gy = count_y + you.y_pos - 8;
- if (count_x == you.x_pos && count_y == you.y_pos)
+ // order is important here
+ if (!map_bounds( gx, gy ))
{
- ch = your_sign;
+ // off the map
+ buffy[bufcount] = 0;
+ buffy[bufcount + 1] = DARKGREY;
+ }
+ else if (count_x < 8 || count_x > 24)
+ {
+ // outside the env.show area
+ buffy[bufcount] = get_envmap_char( gx, gy );
+ buffy[bufcount + 1] = DARKGREY;
+
+ if (Options.colour_map)
+ buffy[bufcount + 1] =
+ colour_code_map(gx - 1, gy - 1,
+ Options.item_colour);
+ }
+ else if (gx == you.x_pos && gy == you.y_pos)
+ {
+ // player overrides everything in cell
+ buffy[bufcount] = you.symbol;
+ buffy[bufcount + 1] = you.colour;
if (player_is_swimming())
{
- color = (grd[you.x_pos][you.y_pos] == DNGN_DEEP_WATER)
- ? BLUE : CYAN;
- }
- else
- {
- color = your_colour;
+ if (grd[gx][gy] == DNGN_DEEP_WATER)
+ buffy[bufcount + 1] = BLUE;
+ else
+ buffy[bufcount + 1] = CYAN;
}
}
else
{
- unsigned int object = env.show[count_x - you.x_pos + 9]
- [count_y - you.y_pos + 9];
+ // Note: env.show is set for grids in LoS
+ // get env coords
+ const int ex = gx - you.x_pos + 9;
+ const int ey = gy - you.y_pos + 9;
- get_non_ibm_symbol(object, &ch, &color);
- }
+ int object = env.show[ex][ey];
+ unsigned short colour = env.show_col[ex][ey];
+ unsigned short ch;
- buffy[bufcount] = ch; //showed;
- buffy[bufcount + 1] = color;
- bufcount += 2;
- }
+ if (object == DNGN_SECRET_DOOR)
+ object = grid_secret_door_appearance( gx, gy );
- bufcount += 16;
- }
+ get_symbol( object, &ch, &colour );
- bufcount = 0;
+ buffy[bufcount] = ch;
+ buffy[bufcount + 1] = colour;
- if (you.level_type != LEVEL_LABYRINTH
- && you.level_type != LEVEL_ABYSS)
- {
- for (count_y = 0; count_y < 17; count_y++)
- {
- bufcount += 16;
- for (count_x = 0; count_x < 17; count_x++)
- {
- int enx = count_x + you.x_pos - 9,
- eny = count_y + you.y_pos - 9;
- if (buffy[bufcount] != 0 && enx >= 0 && eny >= 0
- && enx + 1 < GXM && eny + 1 < GYM)
+ if (map)
{
- unsigned short bch = buffy[bufcount];
- if (mgrd[enx + 1][eny + 1] != NON_MONSTER) {
- const monsters &m = menv[ mgrd[enx + 1][eny + 1] ];
- if (!mons_is_mimic(m.type)
- && mons_char(m.type) == bch)
- {
- bch |= mons_colour(m.type) << 12;
- }
+ // This section is very tricky because it
+ // duplicates the old code (which was horrid).
+
+ // if the grid is in LoS env.show was set and
+ // we set the buffer already, so...
+ if (buffy[bufcount] != 0)
+ {
+ // ... map that we've seen this
+ set_envmap_char( gx, gy, buffy[bufcount] );
+ set_terrain_seen( gx, gy );
+ set_envmap_detected_mons(gx, gy, false);
+ set_envmap_detected_item(gx, gy, false);
}
- env.map[enx][eny] = bch;
- }
-
- if (Options.clean_map == 1
- && show_backup[count_x + 1][count_y + 1] != 0
- && enx >= 0
- && eny >= 0)
- {
- get_non_ibm_symbol( show_backup[count_x + 1]
- [count_y + 1],
- &ch, &color );
- env.map[enx][eny] = ch;
- }
- bufcount += 2;
- }
- bufcount += 16;
- }
- }
- bufcount = 0;
+ // Check if we're looking to clean_map...
+ // but don't touch the buffer to clean it,
+ // instead we modify the env.map itself so
+ // that the map stays clean as it moves out
+ // of the env.show radius.
+ //
+ // Note: show_backup is 0 on every square which
+ // is inside the env.show radius and doesn't
+ // have a monster or cloud on it, and is equal
+ // to the grid before monsters and clouds were
+ // added otherwise.
+ if (Options.clean_map
+ && Show_Backup[ex][ey]
+ && is_terrain_seen( gx, gy ))
+ {
+ get_symbol( Show_Backup[ex][ey], &ch, &colour );
+ set_envmap_char( gx, gy, ch );
+ }
- for (count_y = 0; count_y < 17; count_y++)
- {
- for (count_x = 0; count_x < 33; count_x++)
- {
- if (count_x + you.x_pos - 17 < 3
- || count_y + you.y_pos - 9 < 3
- || count_x + you.x_pos - 14 > (GXM - 3)
- || count_y + you.y_pos - 9 > (GYM - 3))
- {
- buffy[bufcount] = 0;
- bufcount++;
- buffy[bufcount] = 0;
- bufcount++;
- continue;
+ // Now we get to filling in both the unseen
+ // grids in the env.show radius area as
+ // well doing the clean_map. The clean_map
+ // is done by having the env.map set to the
+ // backup character above, and down here we
+ // procede to override that character if it's
+ // out of LoS! If it wasn't, buffy would have
+ // already been set (but we'd still have
+ // clobbered env.map... which is important
+ // to do for when we move away from the area!)
+ if (buffy[bufcount] == 0)
+ {
+ // show map
+ buffy[bufcount] = get_envmap_char( gx, gy );
+ buffy[bufcount + 1] = DARKGREY;
+
+ if (Options.colour_map)
+ buffy[bufcount + 1] =
+ colour_code_map(gx - 1, gy - 1,
+ Options.item_colour);
+ }
+ }
}
-
- if (count_x >= 8 && count_x <= 24 && count_y >= 0
- && count_y <= 16 && buffy[bufcount] != 0)
+
+ // alter colour if flashing the characters vision
+ if (flash_colour != BLACK
+ && buffy[bufcount + 1] != DARKGREY)
{
- bufcount += 2;
- continue;
- }
-
- buffy[bufcount] = (unsigned char)
- env.map[count_x + you.x_pos - 17]
- [count_y + you.y_pos - 9];
-
- buffy[bufcount + 1] = DARKGREY;
-
- if (Options.colour_map)
- {
- if (env.map[count_x + you.x_pos - 17]
- [count_y + you.y_pos - 9] != 0)
- {
- buffy[bufcount + 1]
- = colour_code_map( count_x + you.x_pos - 17,
- count_y + you.y_pos - 9,
- Options.item_colour );
- }
+ buffy[bufcount + 1] = flash_colour;
}
bufcount += 2;
}
}
- if (you.berserker)
- {
- for (count_x = 1; count_x < 1400; count_x += 2)
- {
- if (buffy[count_x] != DARKGREY)
- buffy[count_x] = RED;
- }
- }
-
- if (show_green != BLACK)
- {
- for (count_x = 1; count_x < 1400; count_x += 2)
- {
- if (buffy[count_x] != DARKGREY)
- buffy[count_x] = show_green;
- }
-
- show_green = ((you.special_wield == SPWLD_SHADOW) ? DARKGREY
- : BLACK);
- }
+ // Leaving it this way because short flashes can occur in long ones,
+ // and this simply works without requiring a stack.
+ you.flash_colour = BLACK;
#ifdef DOS_TERM
- puttext(2, 1, 34, 17, buffy.buffer());
+ puttext( 2, 1, X_SIZE + 1, Y_SIZE, buffy.buffer() );
#endif
#ifdef PLAIN_TERM
- gotoxy(2, 1);
- bufcount = 0;
-
- // this line is purely optional
- if (you.running == 0 || (you.running < 0 && Options.travel_delay > -1))
+ // avoiding unneeded draws when running
+ if (!you.running || (you.running < 0 && Options.travel_delay > -1))
{
- for (count_x = 0; count_x < 1120; count_x += 2) // 1056
- {
- textcolor(buffy[count_x + 1]);
- putch(buffy[count_x]);
+ gotoxy( 2, 1 );
- if (count_x % 66 == 64 && count_x > 0)
-#ifdef DOS_TERM
- cprintf(EOL " ");
+ bufcount = 0;
+ for (count_y = 0; count_y < Y_SIZE; count_y++)
+ {
+ for (count_x = 0; count_x < X_SIZE; count_x++)
+ {
+#ifdef USE_CURSES
+ buffy[bufcount] = cset_adjust( buffy[bufcount] );
#endif
+ textcolor( buffy[bufcount + 1] );
+ putch( buffy[bufcount] );
+ bufcount += 2;
+ }
-#ifdef PLAIN_TERM
- gotoxy(2, wherey() + 1);
-#endif
+ gotoxy( 2, count_y + 2 );
}
}
-#endif
- _setcursortype(_NORMALCURSOR);
- } // end of (if brek...)
-} // end viewwindow3()
-
-
-unsigned char mapchar3(unsigned char ldfk)
-{
- unsigned char showed = 0;
-
- switch (ldfk)
- {
- case DNGN_UNSEEN:
- showed = 0;
- break;
-
- case DNGN_SECRET_DOOR:
- case DNGN_ROCK_WALL:
- case DNGN_PERMAROCK_WALL:
- case DNGN_STONE_WALL:
- case DNGN_METAL_WALL:
- case DNGN_GREEN_CRYSTAL_WALL:
- case DNGN_WAX_WALL:
- showed = '*';
- break;
- case DNGN_CLOSED_DOOR:
- showed = '+';
- break;
-
- case 20: // orcish idol
- case 24: // ???
- case 25: // ???
- case DNGN_SILVER_STATUE:
- case DNGN_GRANITE_STATUE:
- case DNGN_ORANGE_CRYSTAL_STATUE:
- showed = '8';
- break;
-
- case DNGN_LAVA_X:
- case DNGN_WATER_X:
- case DNGN_LAVA:
- case DNGN_DEEP_WATER:
- case DNGN_SHALLOW_WATER:
- showed = '{';
- break;
-
- case DNGN_FLOOR:
- case DNGN_UNDISCOVERED_TRAP:
- showed = ',';
- break;
-
- //case 68: showed = '>'; break; // < (60)
-
- case DNGN_OPEN_DOOR:
- showed = 39;
- break; // open door
-
- //case 72: showed = '<'; break;
-
- case DNGN_TRAP_MECHANICAL:
- case DNGN_TRAP_MAGICAL:
- case DNGN_TRAP_III:
- showed = '^';
- break;
-
- case DNGN_STONE_STAIRS_DOWN_I:
- case DNGN_STONE_STAIRS_DOWN_II:
- case DNGN_STONE_STAIRS_DOWN_III:
- case DNGN_ROCK_STAIRS_DOWN:
- case DNGN_ENTER_ORCISH_MINES:
- case DNGN_ENTER_HIVE:
- case DNGN_ENTER_LAIR:
- case DNGN_ENTER_SLIME_PITS:
- case DNGN_ENTER_VAULTS:
- case DNGN_ENTER_CRYPT:
- case DNGN_ENTER_HALL_OF_BLADES:
- case DNGN_ENTER_TEMPLE:
- case DNGN_ENTER_SNAKE_PIT:
- case DNGN_ENTER_ELVEN_HALLS:
- case DNGN_ENTER_TOMB:
- case DNGN_ENTER_SWAMP:
- case 123:
- case 124:
- case 125:
- case 126:
- showed = '>';
- break;
-
- case DNGN_STONE_STAIRS_UP_I:
- case DNGN_STONE_STAIRS_UP_II:
- case DNGN_STONE_STAIRS_UP_III:
- case DNGN_ROCK_STAIRS_UP:
- case DNGN_RETURN_FROM_ORCISH_MINES:
- case DNGN_RETURN_FROM_HIVE:
- case DNGN_RETURN_FROM_LAIR:
- case DNGN_RETURN_FROM_SLIME_PITS:
- case DNGN_RETURN_FROM_VAULTS:
- case DNGN_RETURN_FROM_CRYPT:
- case DNGN_RETURN_FROM_HALL_OF_BLADES:
- case DNGN_RETURN_FROM_TEMPLE:
- case DNGN_RETURN_FROM_SNAKE_PIT:
- case DNGN_RETURN_FROM_ELVEN_HALLS:
- case DNGN_RETURN_FROM_TOMB:
- case DNGN_RETURN_FROM_SWAMP:
- case 143:
- case 144:
- case 145:
- case 146:
- showed = '<';
- break;
-
- case DNGN_ENTER_HELL:
- case DNGN_ENTER_LABYRINTH:
- case DNGN_ENTER_SHOP:
- case DNGN_ENTER_DIS:
- case DNGN_ENTER_GEHENNA:
- case DNGN_ENTER_COCYTUS:
- case DNGN_ENTER_TARTARUS:
- case DNGN_ENTER_ABYSS:
- case DNGN_EXIT_ABYSS:
- case DNGN_STONE_ARCH:
- case DNGN_ENTER_PANDEMONIUM:
- case DNGN_EXIT_PANDEMONIUM:
- case DNGN_TRANSIT_PANDEMONIUM:
- case DNGN_ENTER_ZOT:
- case DNGN_RETURN_FROM_ZOT:
- showed = '\\';
- break;
-
- case DNGN_ALTAR_ZIN:
- case DNGN_ALTAR_SHINING_ONE:
- case DNGN_ALTAR_KIKUBAAQUDGHA:
- case DNGN_ALTAR_YREDELEMNUL:
- case DNGN_ALTAR_XOM:
- case DNGN_ALTAR_VEHUMET:
- case DNGN_ALTAR_OKAWARU:
- case DNGN_ALTAR_MAKHLEB:
- case DNGN_ALTAR_SIF_MUNA:
- case DNGN_ALTAR_TROG:
- case DNGN_ALTAR_NEMELEX_XOBEH:
- case DNGN_ALTAR_ELYVILON:
- showed = '_';
- break;
-
- case DNGN_BLUE_FOUNTAIN:
- case DNGN_DRY_FOUNTAIN_I:
- case DNGN_SPARKLING_FOUNTAIN:
- case DNGN_DRY_FOUNTAIN_II:
- case DNGN_DRY_FOUNTAIN_III:
- case DNGN_DRY_FOUNTAIN_IV:
- case DNGN_DRY_FOUNTAIN_V:
- case DNGN_DRY_FOUNTAIN_VI:
- case DNGN_DRY_FOUNTAIN_VII:
- case DNGN_DRY_FOUNTAIN_VIII:
- case DNGN_PERMADRY_FOUNTAIN:
- showed = '}';
- break;
-
- default:
- showed = 0;
- break;
- }
-
- return showed;
-}
-
-
-unsigned char mapchar4(unsigned char ldfk)
-{
- unsigned char showed = 0;
-
- switch (ldfk)
- {
- case DNGN_UNSEEN:
- showed = 0;
- break;
-
- case DNGN_CLOSED_DOOR:
- showed = '+';
- break;
-
- case DNGN_SECRET_DOOR:
- case DNGN_ROCK_WALL:
- case DNGN_PERMAROCK_WALL:
- case DNGN_STONE_WALL:
- case DNGN_METAL_WALL:
- case DNGN_GREEN_CRYSTAL_WALL:
- case DNGN_WAX_WALL:
- showed = '#';
- break;
-
- case 20: // orcish idol
- case 24: // ???
- case 25: // ???
- case DNGN_SILVER_STATUE:
- case DNGN_GRANITE_STATUE:
- case DNGN_ORANGE_CRYSTAL_STATUE:
- showed = '8';
- break;
-
- case DNGN_LAVA_X:
- case DNGN_WATER_X:
- case DNGN_LAVA:
- case DNGN_DEEP_WATER:
- case DNGN_SHALLOW_WATER:
- showed = '{';
- break;
-
- case DNGN_FLOOR:
- case DNGN_UNDISCOVERED_TRAP:
- showed = '.';
- break;
-
- case 68:
- showed = '>'; // <
- break;
-
- case DNGN_OPEN_DOOR:
- showed = 39;
- break;
-
- case 72:
- showed = '<';
- break;
-
- case DNGN_TRAP_MECHANICAL:
- case DNGN_TRAP_MAGICAL:
- case DNGN_TRAP_III:
- showed = '^';
- break;
-
- case DNGN_STONE_STAIRS_DOWN_I:
- case DNGN_STONE_STAIRS_DOWN_II:
- case DNGN_STONE_STAIRS_DOWN_III:
- case DNGN_ROCK_STAIRS_DOWN:
- case DNGN_ENTER_ORCISH_MINES:
- case DNGN_ENTER_HIVE:
- case DNGN_ENTER_LAIR:
- case DNGN_ENTER_SLIME_PITS:
- case DNGN_ENTER_VAULTS:
- case DNGN_ENTER_CRYPT:
- case DNGN_ENTER_HALL_OF_BLADES:
- case DNGN_ENTER_TEMPLE:
- case DNGN_ENTER_SNAKE_PIT:
- case DNGN_ENTER_ELVEN_HALLS:
- case DNGN_ENTER_TOMB:
- case DNGN_ENTER_SWAMP:
- case 123:
- case 124:
- case 125:
- case 126:
- showed = '>';
- break;
-
- case DNGN_STONE_STAIRS_UP_I:
- case DNGN_STONE_STAIRS_UP_II:
- case DNGN_STONE_STAIRS_UP_III:
- case DNGN_ROCK_STAIRS_UP:
- case DNGN_RETURN_FROM_ORCISH_MINES:
- case DNGN_RETURN_FROM_HIVE:
- case DNGN_RETURN_FROM_LAIR:
- case DNGN_RETURN_FROM_SLIME_PITS:
- case DNGN_RETURN_FROM_VAULTS:
- case DNGN_RETURN_FROM_CRYPT:
- case DNGN_RETURN_FROM_HALL_OF_BLADES:
- case DNGN_RETURN_FROM_TEMPLE:
- case DNGN_RETURN_FROM_SNAKE_PIT:
- case DNGN_RETURN_FROM_ELVEN_HALLS:
- case DNGN_RETURN_FROM_TOMB:
- case DNGN_RETURN_FROM_SWAMP:
- case 143:
- case 144:
- case 145:
- case 146:
- showed = '<';
- break;
-
- case DNGN_ENTER_HELL:
- case DNGN_ENTER_LABYRINTH:
- case DNGN_ENTER_SHOP:
- case DNGN_ENTER_DIS:
- case DNGN_ENTER_GEHENNA:
- case DNGN_ENTER_COCYTUS:
- case DNGN_ENTER_TARTARUS:
- case DNGN_ENTER_ABYSS:
- case DNGN_EXIT_ABYSS:
- case DNGN_STONE_ARCH:
- case DNGN_ENTER_PANDEMONIUM:
- case DNGN_EXIT_PANDEMONIUM:
- case DNGN_TRANSIT_PANDEMONIUM:
- case DNGN_ENTER_ZOT:
- case DNGN_RETURN_FROM_ZOT:
- showed = '\\';
- break;
-
- case DNGN_ALTAR_ZIN:
- case DNGN_ALTAR_SHINING_ONE:
- case DNGN_ALTAR_KIKUBAAQUDGHA:
- case DNGN_ALTAR_YREDELEMNUL:
- case DNGN_ALTAR_XOM:
- case DNGN_ALTAR_VEHUMET:
- case DNGN_ALTAR_OKAWARU:
- case DNGN_ALTAR_MAKHLEB:
- case DNGN_ALTAR_SIF_MUNA:
- case DNGN_ALTAR_TROG:
- case DNGN_ALTAR_NEMELEX_XOBEH:
- case DNGN_ALTAR_ELYVILON:
- showed = '_';
- break;
-
- case DNGN_BLUE_FOUNTAIN:
- case DNGN_DRY_FOUNTAIN_I:
- case DNGN_SPARKLING_FOUNTAIN:
- case DNGN_DRY_FOUNTAIN_II:
- case DNGN_DRY_FOUNTAIN_III:
- case DNGN_DRY_FOUNTAIN_IV:
- case DNGN_DRY_FOUNTAIN_V:
- case DNGN_DRY_FOUNTAIN_VI:
- case DNGN_DRY_FOUNTAIN_VII:
- case DNGN_DRY_FOUNTAIN_VIII:
- case DNGN_PERMADRY_FOUNTAIN:
- showed = '}';
- break;
+#ifdef USE_CURSES
+ set_altcharset( false );
+#endif
- default:
- showed = 0;
- break;
+#endif
+ _setcursortype(_NORMALCURSOR);
}
-
- return showed;
-}
+} // end viewwindow()