diff options
29 files changed, 542 insertions, 418 deletions
diff --git a/crawl-ref/INSTALL b/crawl-ref/INSTALL index c962fd36c6..4114224a28 100644 --- a/crawl-ref/INSTALL +++ b/crawl-ref/INSTALL @@ -32,6 +32,7 @@ Crawl can be built with some optional features: * Sounds * Regular expressions * Lua support +* Unicode characters for the map (Unix only). Crawl Stone Soup also uses a level compiler to compile special level definitions; to make changes to the level compiler, you'll need the @@ -76,6 +77,11 @@ on some Unixes. flex and bison are optional but highly recommended. Recent versions of byacc are also fine (edit your makefile appropriately). +If you have ncursesw and the development headers (usually in the +/usr/include/ncursesw directory) you can build Crawl with support for +Unicode display characters in the map by setting UNICODE_GLYPHS = y +in makefile.unix. + Building: * cd to the source directory (you can safely ignore the dolinks.sh and @@ -339,3 +345,22 @@ http://gnuwin32.sourceforge.net/packages/pcre.htm On DOS you get the joy of building PCRE yourself. It's a little more annoying than building Lua (you have to roll your own makefile), but not by much. + + +Unicode +------- + +Modern Unixes may support Unicode terminals (particularly xterms). If +you have a terminal that can display Unicode characters, and an +ncurses library that can handle Unicode (libncursesw, and its devel +headers), you can build Crawl to display Unicode in the map: set +UNICODE_GLYPHS = y in makefile.unix. + +NOTE: You may have libncursesw, but not have the header files; check +that you have the header files installed as well, or you'll get a lot +of errors. Crawl expects the ncursesw headers to be in +/usr/include/ncursesw. + +After compiling Crawl with Unicode support, you still need to add the +line "char_set = unicode" in your .crawlrc to tell Crawl to use +Unicode.
\ No newline at end of file diff --git a/crawl-ref/docs/crawl_manual.txt b/crawl-ref/docs/crawl_manual.txt index 65b1245cd5..1514bc8106 100644 --- a/crawl-ref/docs/crawl_manual.txt +++ b/crawl-ref/docs/crawl_manual.txt @@ -1035,7 +1035,7 @@ newsgroup rec.games.roguelike.misc. Flag queries with -crawl- as other games are also discussed there. All topics related to this game usually meet a warm response, including tales of victories (going under 'YAVP', i.e. 'Yet Another Victory Post'), especially first victories (YAFVP) as -well as sad stories of deceasedcharacters (being 'YAAD' or 'YASD', i.e. +well as sad stories of deceased characters (being 'YAAD' or 'YASD', i.e. 'Yet Another Annoying/Stupid Death'). Some players, especially those on crawl.akrasiac.org, also frequent ##crawl on IRC's freenode network. diff --git a/crawl-ref/docs/crawl_options.txt b/crawl-ref/docs/crawl_options.txt index 5be8d756c9..01b894bcd4 100644 --- a/crawl-ref/docs/crawl_options.txt +++ b/crawl-ref/docs/crawl_options.txt @@ -1167,12 +1167,12 @@ wiz_mode = (no | never | yes) no -- still allows player to enter wizard mode after start of game never -- never allow a wizard command to be used -char_set = (ascii | ibm | dec) +char_set = (ascii | ibm | dec | unicode) Chooses different character sets for the game play screen. DOS and Windows users will want to use the IBM character set, Unix users will prefer DEC or plain ASCII. -cset_ascii, cset_ibm, cset_dec, cset_any +cset_ascii, cset_ibm, cset_dec, cset_unicode, cset_any Can be used to change individual characters in a specific character set (the character set used for display is determined by the char_set option). The syntax is the same for all of these; cset_any changes @@ -1194,10 +1194,13 @@ cset_XXX = <dungeon_character_name : symbol> for water creatures submerged in shallow water, or invisible creatures wading in shallow water. - Symbols can be specified using a letter, or by a number (decimal code). + Symbols can be specified using a letter, or by a number (decimal code), + or a hexadecimal number (prefixed with x): + For an example on IBM displays, - cset_ibm = wall:219, arch:0 - shows walls as solid blocks and shops and portals as '0'. + cset_ibm = wall:219, arch:0, wavy:x7E + shows walls as solid blocks, shops and portals as '0', and water as + '~'. feature = <regex> { <symbol>, <magicmap symbol>, <view colour>, <levelmap_magic_colour>, <levelmap_seen_colour> } @@ -1223,8 +1226,16 @@ feature = <regex> { <symbol>, <magicmap symbol>, <view colour>, descriptions strung together on the same line separated by semicolons. Examples: - feature = rock wall { , , red } # shows rock walls in red - feature = metal wall {#} # use '#' for metal walls + * Colour rock walls red: + feature = rock wall { , , red } + * Use # for metal walls in all character sets: + feature = metal wall {#} + + Symbols can be specified as with cset: + feature = metal wall {#} + feature = metal wall {35} + feature = metal wall {x23} + all do the same thing. classic_item_colours = false Crawl uses 4.0 b26/0.1.x-like item colours if classic_item_colours is diff --git a/crawl-ref/source/AppHdr.h b/crawl-ref/source/AppHdr.h index 01ff994e96..fa6ad69293 100644 --- a/crawl-ref/source/AppHdr.h +++ b/crawl-ref/source/AppHdr.h @@ -54,6 +54,14 @@ // // #define CLUA_BINDINGS +// Enable support for Unicode character glyphs. Note that this needs +// to be accompanied by changes to linker and compiler options and may +// not be available on all platforms. In most cases you want to set +// this option from your makefile, not directly in AppHdr.h (See +// INSTALL for more details.) +// +// #define UNICODE_GLYPHS + // Uncomment to prevent Crawl from looking for a list of saves when // asking the player to enter a name. This can speed up startup // considerably if you have a lot of saves lying around (even more so diff --git a/crawl-ref/source/abyss.cc b/crawl-ref/source/abyss.cc index 6dbf138ada..2b881855ba 100644 --- a/crawl-ref/source/abyss.cc +++ b/crawl-ref/source/abyss.cc @@ -71,14 +71,7 @@ static void generate_area(unsigned char gx1, unsigned char gy1, FixedVector < unsigned char, 5 > replaced; // nuke map - for (i = 0; i < GXM; i++) - { - for (j = 0; j < GYM; j++) - { - env.map[i][j] = 0; - env.map_col[i][j].clear(); - } - } + env.map.init(map_cell()); // generate level composition vector for (i = 0; i < 5; i++) diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index 25757b00fa..716b02ed66 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -2860,11 +2860,7 @@ static bool initialise(void) igrd.init(NON_ITEM); mgrd.init(NON_MONSTER); - env.map.init(0); - - for (int i = 0; i < GXM; i++) - for (int j = 0; j < GYM; j++) - env.map_col[i][j].clear(); + env.map.init(map_cell()); you.unique_creatures.init(false); you.unique_items.init(UNIQ_NOT_EXISTS); diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc index 1101d4362c..eedeb15cef 100644 --- a/crawl-ref/source/command.cc +++ b/crawl-ref/source/command.cc @@ -1028,7 +1028,8 @@ void list_tutorial_help() // Page size is number of lines - one line for --more-- prompt. cols.set_pagesize(get_number_of_lines()); - unsigned short ch, colour; + unsigned ch; + unsigned short colour; std::ostringstream text; text << diff --git a/crawl-ref/source/defines.h b/crawl-ref/source/defines.h index 5b8bb6200c..9f8beea1ba 100644 --- a/crawl-ref/source/defines.h +++ b/crawl-ref/source/defines.h @@ -88,11 +88,11 @@ // Note: these boundaries are exclusive for the zone the player can move/dig, // and are inclusive for the area that we display on the map. // Note: that the right (bottom) boundary is one smaller here. -#define X_BOUND_1 BOUNDARY_BORDER +#define X_BOUND_1 (-1 + BOUNDARY_BORDER) #define X_BOUND_2 (GXM - BOUNDARY_BORDER) #define X_WIDTH (X_BOUND_2 - X_BOUND_1 + 1) -#define Y_BOUND_1 BOUNDARY_BORDER +#define Y_BOUND_1 (-1 + BOUNDARY_BORDER) #define Y_BOUND_2 (GYM - BOUNDARY_BORDER) #define Y_WIDTH (Y_BOUND_2 - Y_BOUND_1 + 1) @@ -112,26 +112,9 @@ #define LOS_RADIUS 8 #define ENV_SHOW_OFFSET (LOS_RADIUS + 1) #define ENV_SHOW_DIAMETER (ENV_SHOW_OFFSET * 2 + 1) -#define LOS_SX 8 -#define LOS_EX 25 -#define LOS_SY 1 -#define LOS_EY 17 - -#define VIEW_SX 1 -#define VIEW_EX 33 -#define VIEW_SY 1 -#define VIEW_EY 17 - -#define VIEW_WIDTH (VIEW_EX - VIEW_SX + 1) -#define VIEW_HEIGHT (VIEW_EY - VIEW_SY + 1) - -#define VIEW_Y_DIFF (((VIEW_EX - VIEW_SX + 1) - (VIEW_EY - VIEW_SY + 1)) / 2) - -// View centre must be the same as LOS centre. -// VIEW_CX == 17 -#define VIEW_CX ((VIEW_SX + VIEW_EX) / 2) -// VIEW_CY == 9 -#define VIEW_CY ((VIEW_SY + VIEW_EY) / 2) + +#define VIEW_MIN_WIDTH 33 +#define VIEW_MIN_HEIGHT 17 // max traps per level #define MAX_TRAPS 30 diff --git a/crawl-ref/source/direct.cc b/crawl-ref/source/direct.cc index 5bf61db694..c7177ead30 100644 --- a/crawl-ref/source/direct.cc +++ b/crawl-ref/source/direct.cc @@ -96,11 +96,6 @@ static int targeting_cmd_to_compass( command_type command ); static void describe_oos_square(int x, int y); static void extend_move_to_edge(dist &moves); -static bool is_mapped(int x, int y) -{ - return (is_player_mapped(x, y)); -} - static command_type read_direction_key(bool just_looking = false) { flush_input_buffer( FLUSH_BEFORE_COMMAND ); @@ -818,7 +813,7 @@ static void describe_oos_square(int x, int y) { mpr("You can't see that place."); - if (!in_bounds(x, y) || !is_mapped(x, y)) + if (!in_bounds(x, y) || !is_terrain_seen(x, y)) return; describe_stash(x, y); @@ -861,7 +856,7 @@ static bool find_monster( int x, int y, int mode ) static bool find_feature( int x, int y, int mode ) { // The stair need not be in LOS if the square is mapped. - if (!in_los(x, y) && (!Options.target_oos || !is_mapped(x, y))) + if (!in_los(x, y) && (!Options.target_oos || !is_terrain_seen(x, y))) return (false); return is_feature(mode, x, y); @@ -873,7 +868,8 @@ static bool find_object(int x, int y, int mode) // The square need not be in LOS if the stash tracker knows this item. return (item != NON_ITEM && (in_los(x, y) - || (Options.target_oos && is_mapped(x, y) && is_stash(x, y)))); + || (Options.target_oos && is_terrain_seen(x, y) + && is_stash(x, y)))); } static int next_los(int dir, int los, bool wrap) diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index 06415f0a76..739482db13 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -542,6 +542,7 @@ enum char_set_type CSET_ASCII, // flat 7-bit ASCII CSET_IBM, // 8-bit ANSI/Code Page 437 CSET_DEC, // 8-bit DEC, 0xE0-0xFF shifted for line drawing chars + CSET_UNICODE, // Unicode. NUM_CSET }; diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index 635d853f6a..d0ffac011f 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -1132,13 +1132,18 @@ struct trap_struct unsigned char type; }; -struct map_colour +struct map_cell { - short colour; - short flags; + short object; // The object: monster, item, feature, or cloud. + unsigned short flags; // Flags describing the mappedness of this square. + unsigned short colour; - operator short () const { return colour; } - void clear() { colour = flags = 0; } + map_cell() : object(0), flags(0), colour(0) { } + void clear() { flags = object = colour = 0; } + + unsigned glyph() const; + bool known() const; + bool seen() const; }; struct crawl_environment @@ -1154,8 +1159,7 @@ struct crawl_environment FixedArray< int, GXM, GYM > igrid; // item grid FixedArray< unsigned char, GXM, GYM > cgrid; // cloud grid - FixedArray< unsigned short, GXM, GYM > map; // discovered terrain - FixedArray< map_colour, GXM, GYM > map_col; // map colours + FixedArray< map_cell, GXM, GYM > map; // discovered terrain FixedArray<unsigned, ENV_SHOW_DIAMETER, ENV_SHOW_DIAMETER> show; // view window char @@ -1188,8 +1192,11 @@ struct game_state int seen_hups; // Set to true if SIGHUP received. + bool unicode_ok; // Is unicode support available? + game_state() : need_save(false), saving_game(false), - updating_scores(false), shopping(false), seen_hups(0) + updating_scores(false), shopping(false), seen_hups(0), + unicode_ok(false) { } }; @@ -1352,8 +1359,8 @@ struct message_colour_mapping struct feature_def { - unsigned short symbol; // symbol used for seen terrain - unsigned short magic_symbol; // symbol used for magic-mapped terrain + unsigned symbol; // symbol used for seen terrain + unsigned 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() @@ -1508,7 +1515,7 @@ public: bool lowercase_invocations; // prefer lowercase invocations char_set_type char_set; - FixedVector<unsigned char, NUM_DCHAR_TYPES> char_table; + FixedVector<unsigned, NUM_DCHAR_TYPES> char_table; int num_colours; // used for setting up curses colour table (8 or 16) @@ -1689,7 +1696,7 @@ private: void clear_cset_overrides(); void add_cset_override(char_set_type set, const std::string &overrides); void add_cset_override(char_set_type set, dungeon_char_type dc, - unsigned char symbol); + unsigned symbol); void add_feature_override(const std::string &); void add_message_colour_mappings(const std::string &); diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc index 2e4ec6c9d9..68dc9424b2 100644 --- a/crawl-ref/source/files.cc +++ b/crawl-ref/source/files.cc @@ -835,23 +835,14 @@ static void close_level_gates() static void clear_env_map() { - for (int i = 0; i < GXM; i++) - { - for (int j = 0; j < GYM; j++) - { - env.map[i][j] = 0; - env.map_col[i][j].clear(); - } - } + env.map.init(map_cell()); } static void clear_clouds() { for (int clouty = 0; clouty < MAX_CLOUDS; ++clouty) delete_cloud( clouty ); - for (int i = 0; i < GXM; i++) - for (int j = 0; j < GYM; j++) - env.cgrid[i][j] = EMPTY_CLOUD; + env.cgrid.init(EMPTY_CLOUD); } static void grab_followers(std::vector<follower>& followers) diff --git a/crawl-ref/source/format.cc b/crawl-ref/source/format.cc index d8942e5d08..390133f3d5 100644 --- a/crawl-ref/source/format.cc +++ b/crawl-ref/source/format.cc @@ -236,7 +236,8 @@ int formatted_string::find_last_colour() const void formatted_string::add_glyph(const item_def *item) { const int last_col = find_last_colour(); - unsigned short ch, col; + unsigned ch; + unsigned short col; get_item_glyph(item, &ch, &col); this->textcolor(col); this->cprintf("%c", ch); @@ -246,7 +247,8 @@ void formatted_string::add_glyph(const item_def *item) void formatted_string::add_glyph(const monsters *mons) { const int last_col = find_last_colour(); - unsigned short ch, col; + unsigned ch; + unsigned short col; get_mons_glyph(mons, &ch, &col); this->textcolor(col); this->cprintf("%c", ch); diff --git a/crawl-ref/source/initfile.cc b/crawl-ref/source/initfile.cc index 30e9619699..05c437455f 100644 --- a/crawl-ref/source/initfile.cc +++ b/crawl-ref/source/initfile.cc @@ -555,8 +555,8 @@ void game_options::reset_options() messaging = true; #endif - view_max_width = VIEW_EX; - view_max_height = VIEW_EY; + view_max_width = VIEW_MIN_WIDTH; + view_max_height = VIEW_MIN_HEIGHT; view_lock_x = true; view_lock_y = true; @@ -805,20 +805,29 @@ void game_options::clear_feature_overrides() feature_overrides.clear(); } -static unsigned short read_symbol(std::string s) +static unsigned read_symbol(std::string s) { if (s.empty()) return (0); + if (s.length() == 1) return s[0]; - if (s[0] == '\\') + if (s.length() > 1 && s[0] == '\\') s = s.substr(1); - - int feat = atoi(s.c_str()); + + int base = 10; + if (s.length() > 1 && s[0] == 'x') + { + s = s.substr(1); + base = 16; + } + + char *tail; + int feat = strtol(s.c_str(), &tail, base); if (feat < 0) feat = 0; - return static_cast<unsigned short>(feat); + return static_cast<unsigned>(feat); } void game_options::add_feature_override(const std::string &text) @@ -875,8 +884,8 @@ void game_options::add_cset_override( if (dc == NUM_DCHAR_TYPES) continue; - unsigned char symbol = - static_cast<unsigned char>(read_symbol(mapping[1])); + unsigned symbol = + static_cast<unsigned>(read_symbol(mapping[1])); if (set == NUM_CSET) for (int c = 0; c < NUM_CSET; ++c) @@ -887,7 +896,7 @@ void game_options::add_cset_override( } void game_options::add_cset_override(char_set_type set, dungeon_char_type dc, - unsigned char symbol) + unsigned symbol) { cset_override[set][dc] = symbol; } @@ -1483,7 +1492,9 @@ void game_options::read_option_line(const std::string &str, bool runscript) char_set = CSET_IBM; else if (field == "dec") char_set = CSET_DEC; - else + else if (field == "utf" || field == "unicode") + char_set = CSET_UNICODE; + else { fprintf( stderr, "Bad character set: %s\n", field.c_str() ); valid = false; @@ -1640,6 +1651,8 @@ void game_options::read_option_line(const std::string &str, bool runscript) cs = CSET_IBM; else if (cset == "dec") cs = CSET_DEC; + else if (cset == "utf" || cset == "unicode") + cs = CSET_UNICODE; add_cset_override(cs, field); } @@ -1869,16 +1882,19 @@ void game_options::read_option_line(const std::string &str, bool runscript) else if (key == "view_max_width") { view_max_width = atoi(field.c_str()); - if (view_max_width < VIEW_EX) - view_max_width = VIEW_EX; + if (view_max_width < VIEW_MIN_WIDTH) + view_max_width = VIEW_MIN_WIDTH; + + // Allow the view to be one larger than GXM because the view width + // needs to be odd, and GXM is even. else if (view_max_width > GXM + 1) view_max_width = GXM + 1; } else if (key == "view_max_height") { view_max_height = atoi(field.c_str()); - if (view_max_height < VIEW_EY) - view_max_height = VIEW_EY; + if (view_max_height < VIEW_MIN_HEIGHT) + view_max_height = VIEW_MIN_HEIGHT; else if (view_max_height > GYM + 1) view_max_height = GYM + 1; } diff --git a/crawl-ref/source/libdos.h b/crawl-ref/source/libdos.h index 1b8ae87e75..6e2d3f16a6 100644 --- a/crawl-ref/source/libdos.h +++ b/crawl-ref/source/libdos.h @@ -15,5 +15,13 @@ void clear_to_end_of_line(); void message_out(int mline, int colour, const char *str, int firstcol = 0, bool newline = true); void clear_message_window(); +inline void update_screen() +{ +} + +inline void putwch(unsigned c) +{ + putch(static_cast<char>(c)); +} #endif diff --git a/crawl-ref/source/libunix.cc b/crawl-ref/source/libunix.cc index b9d9342e92..b245ccdbab 100644 --- a/crawl-ref/source/libunix.cc +++ b/crawl-ref/source/libunix.cc @@ -47,6 +47,10 @@ #include "externs.h" #include "files.h" +#ifdef UNICODE_GLYPHS +#include <locale.h> +#endif + #include <termios.h> static struct termios def_term; @@ -64,11 +68,12 @@ static struct termios game_term; #endif // Character set variable -int Character_Set = CHARACTER_SET; +static int Character_Set = CHARACTER_SET; // Globals holding current text/backg. colors -short FG_COL = WHITE; -short BG_COL = BLACK; +static short FG_COL = WHITE; +static short BG_COL = BLACK; +static int Current_Colour = COLOR_PAIR(BG_COL * 8 + FG_COL); static int curs_fg_attr(int col); static int curs_bg_attr(int col); @@ -180,6 +185,10 @@ static void termio_init() #endif tcsetattr(0, TCSAFLUSH, &game_term); + +#ifdef UNICODE_GLYPHS + crawl_state.unicode_ok = !!setlocale(LC_ALL, ""); +#endif } @@ -410,6 +419,18 @@ int putch(unsigned char chr) return (addch(chr)); } +int putwch(unsigned chr) +{ +#ifdef UNICODE_GLYPHS + if (chr <= 127) + return (putch(chr)); + + wchar_t c = chr; + return (addnwstr(&c, 1)); +#else + return (putch(static_cast<unsigned char>(chr))); +#endif +} char getche() { @@ -570,7 +591,7 @@ static int curs_fg_attr(int col) void textcolor(int col) { - attrset( curs_fg_attr(col) ); + attrset( Current_Colour = curs_fg_attr(col) ); } static int curs_bg_attr(int col) @@ -629,7 +650,7 @@ static int curs_bg_attr(int col) void textbackground(int col) { - attrset( curs_bg_attr(col) ); + attrset( Current_Colour = curs_bg_attr(col) ); } @@ -638,28 +659,57 @@ int gotoxy(int x, int y) return (move(y - 1, x - 1)); } -static unsigned oldch, oldmangledch; -static int faked_x = -1, faked_y; - -void fakecursorxy(int x, int y) +#ifdef UNICODE_GLYPHS +typedef cchar_t char_info; +inline bool operator == (const cchar_t &a, const cchar_t &b) { - if (oldch && faked_x != -1 - && mvinch(faked_y, faked_x) == oldmangledch) + return (a.attr == b.attr && *a.chars == *b.chars); +} +inline char_info character_at(int y, int x) +{ + cchar_t c; + mvin_wch(y, x, &c); + return (c); +} +inline bool valid_char(const cchar_t &c) +{ + return *c.chars; +} +inline void write_char_at(int y, int x, const cchar_t &ch) +{ + move(y, x); + add_wchnstr(&ch, 1); +} +static void flip_colour(cchar_t &ch) +{ + const unsigned colour = (ch.attr & A_COLOR); + const int pair = PAIR_NUMBER(colour); + + int fg = pair & 7; + int bg = (pair >> 3) & 7; + + if (pair == 63) { - if (faked_x != x - 1 || faked_y != y - 1) - mvaddch(faked_y, faked_x, oldch); - else - return; + fg = COLOR_WHITE; + bg = COLOR_BLACK; } - - const unsigned c = mvinch(y - 1, x - 1); - const int ch = c & A_CHARTEXT; - const unsigned colour = c & A_COLOR; - const int pair = PAIR_NUMBER(colour); - faked_x = x - 1; - faked_y = y - 1; - oldch = c; + const int newpair = (fg * 8 + bg); + ch.attr = COLOR_PAIR(newpair); +} +#else // ! UNICODE_GLYPHS +typedef unsigned char_info; +#define character_at(y,x) mvinch(y,x) +#define valid_char(x) (x) +#define write_char_at(y,x,c) mvaddch(y, x, c) + +#define char_info_character(c) ((c) & A_CHARTEXT) +#define char_info_colour(c) ((c) & A_COLOR) + +static void flip_colour(unsigned &ch) +{ + const unsigned colour = char_info_colour(ch); + const int pair = PAIR_NUMBER(colour); int fg = pair & 7; int bg = (pair >> 3) & 7; @@ -671,9 +721,30 @@ void fakecursorxy(int x, int y) } const int newpair = (fg * 8 + bg); - - mvaddch( y - 1, x - 1, oldmangledch = ((ch & 127) | COLOR_PAIR(newpair)) ); + ch = ((ch & 127) | COLOR_PAIR(newpair)); +} +#endif + +static char_info oldch, oldmangledch; +static int faked_x = -1, faked_y; +void fakecursorxy(int x, int y) +{ + if (valid_char(oldch) && faked_x != -1 + && character_at(faked_y, faked_x) == oldmangledch) + { + if (faked_x != x - 1 || faked_y != y - 1) + write_char_at(faked_y, faked_x, oldch); + else + return; + } + + char_info c = character_at(y - 1, x - 1); + oldch = c; + faked_x = x - 1; + faked_y = y - 1; + flip_colour(c); + write_char_at( y - 1, x - 1, oldmangledch = c); move(y - 1, x - 1); } diff --git a/crawl-ref/source/libunix.h b/crawl-ref/source/libunix.h index 19cd2674e3..42d9ba9449 100644 --- a/crawl-ref/source/libunix.h +++ b/crawl-ref/source/libunix.h @@ -25,6 +25,7 @@ void fakecursorxy(int x, int y); int itoa(int value, char *strptr, int radix); int kbhit(void); int putch(unsigned char chr); +int putwch(unsigned chr); int stricmp(const char *str1, const char *str2); int translate_keypad(int keyin); int wherex(void); diff --git a/crawl-ref/source/libw32c.cc b/crawl-ref/source/libw32c.cc index dd0822deee..055471351d 100644 --- a/crawl-ref/source/libw32c.cc +++ b/crawl-ref/source/libw32c.cc @@ -711,6 +711,11 @@ void putch(char c) writeChar(c); } +void putwch(unsigned c) +{ + putch((char) c); +} + // translate virtual keys #define VKEY_MAPPINGS 10 @@ -961,6 +966,11 @@ int getConsoleString(char *buf, int maxlen) return (int)nread; } +void update_screen() +{ + bFlush(); +} + bool setBuffering( bool value ) { bool oldValue = buffering; diff --git a/crawl-ref/source/libw32c.h b/crawl-ref/source/libw32c.h index 9e01a44fd7..70c038c49e 100644 --- a/crawl-ref/source/libw32c.h +++ b/crawl-ref/source/libw32c.h @@ -37,6 +37,7 @@ void window(int x, int y, int lx, int ly); int wherex(void); int wherey(void); void putch(char c); +void putwch(unsigned c); int getch(void); int getch_ck(void); int key_to_command(int); @@ -44,6 +45,7 @@ int getche(void); int kbhit(void); void delay(int ms); void textbackground(int c); +void update_screen(); void enable_smart_cursor(bool cursor); bool is_smart_cursor_enabled(); diff --git a/crawl-ref/source/makefile.unix b/crawl-ref/source/makefile.unix index f67953792c..199bc302b3 100644 --- a/crawl-ref/source/makefile.unix +++ b/crawl-ref/source/makefile.unix @@ -17,8 +17,9 @@ DELETE = rm -f COPY = cp OS_TYPE = UNIX -# Include path for curses or ncurses. -INCLUDES = -I/usr/include/ncurses +# Change this to y if you want to use Unicode glyphs in the map, and you have +# libncursesw available. +UNICODE_GLYPHS = n # If you have lex and yacc, set DOYACC to y (lowercase y). DOYACC := y @@ -44,6 +45,17 @@ INSTALLDIR := /usr/games LEX := flex YACC := bison -y +ifeq ($(UNICODE_GLYPHS),y) +# Include path for (n)curses with Unicode support. +INCLUDES = -I/usr/include/ncursesw +LIBCURS = ncursesw +EXTRA_FLAGS += -DUNICODE_GLYPHS +else +# Include path for curses or ncurses (non-Unicode). +INCLUDES = -I/usr/include/ncurses +LIBCURS = ncurses +endif + ifeq ($(LUASRC),) LUASRC := util/lua/src endif @@ -82,7 +94,7 @@ EXTRA_INCLUDES += -I$(SQLSRC) EXTRA_DEPENDS += $(FSQLLIBA) endif -LIB = -lncurses -L$(LUASRC) -l$(LUALIB) $(LIBDBM) +LIB = -l$(LIBCURS) -L$(LUASRC) -l$(LUALIB) $(LIBDBM) INCLUDES := $(INCLUDES) -Iutil -I. -I$(LUASRC) $(EXTRA_INCLUDES) diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc index 175db38a74..258fefa122 100644 --- a/crawl-ref/source/player.cc +++ b/crawl-ref/source/player.cc @@ -299,7 +299,7 @@ bool move_player_to_grid( int x, int y, bool stepped, bool allow_shift, const int type = trap_category( env.trap[id].type ); grd[you.x_pos][you.y_pos] = type; - set_envmap_char(you.x_pos, you.y_pos, get_sightmap_char(type)); + set_envmap_obj(you.x_pos, you.y_pos, type); } // not easy to blink onto a trap without setting it off: @@ -2193,10 +2193,7 @@ void forget_map(unsigned char chance_forgotten) for (ycount = 0; ycount < GYM; ycount++) { if (random2(100) < chance_forgotten) - { - env.map[xcount][ycount] = 0; - env.map_col[xcount][ycount].clear(); - } + env.map[xcount][ycount].clear(); } } } // end forget_map() diff --git a/crawl-ref/source/spells2.cc b/crawl-ref/source/spells2.cc index abd620955c..6708c9b42b 100644 --- a/crawl-ref/source/spells2.cc +++ b/crawl-ref/source/spells2.cc @@ -76,7 +76,7 @@ unsigned char detect_traps( int pow ) traps_found++; grd[ etx ][ ety ] = trap_category( env.trap[count_x].type ); - set_envmap_char(etx, ety, get_magicmap_char(grd[etx][ety])); + set_envmap_obj(etx, ety, grd[etx][ety]); set_terrain_mapped(etx, ety); } } @@ -104,7 +104,7 @@ unsigned char detect_items( int pow ) if (igrd[i][j] != NON_ITEM) { - set_envmap_char(i, j, get_magicmap_char(DNGN_ITEM_DETECTED)); + set_envmap_obj(i, j, DNGN_ITEM_DETECTED); set_envmap_detected_item(i, j); } } @@ -159,7 +159,7 @@ static void mark_detected_creature(int gridx, int gridy, const monsters *mon, } } - set_envmap_char(gridx, gridy, mons_char(mon->type)); + set_envmap_obj(gridx, gridy, mon->type + DNGN_START_OF_MONSTERS); set_envmap_detected_mons(gridx, gridy); } diff --git a/crawl-ref/source/stuff.cc b/crawl-ref/source/stuff.cc index e948dbbcdd..baf3058dfc 100644 --- a/crawl-ref/source/stuff.cc +++ b/crawl-ref/source/stuff.cc @@ -333,10 +333,15 @@ void cio_init() #ifdef DOS init_libdos(); #endif - - crawl_view.init_geometry(); io_inited = true; + + crawl_view.init_geometry(); + + if (Options.char_set == CSET_UNICODE && !crawl_state.unicode_ok) + end(1, false, + "Unicode glyphs are not available, please change your " + "char_set option"); } void cio_cleanup() diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc index bbfc298549..e492b338aa 100644 --- a/crawl-ref/source/tags.cc +++ b/crawl-ref/source/tags.cc @@ -1301,9 +1301,9 @@ static void tag_construct_level(struct tagHeader &th) for (count_y = 0; count_y < GYM; count_y++) { marshallByte(th, grd[count_x][count_y]); - marshallShort(th, env.map[count_x][count_y]); - marshallShort(th, env.map_col[count_x][count_y].colour); - marshallShort(th, env.map_col[count_x][count_y].flags); + marshallShort(th, env.map[count_x][count_y].object); + marshallShort(th, env.map[count_x][count_y].colour); + marshallShort(th, env.map[count_x][count_y].flags); marshallByte(th, env.cgrid[count_x][count_y]); } } @@ -1522,13 +1522,9 @@ static void tag_read_level( struct tagHeader &th, char minorVersion ) { grd[i][j] = unmarshallByte(th); - env.map[i][j] = (unsigned short) unmarshallShort(th); - - if ((env.map[i][j] & 0xFF) == 201) // what is this?? - env.map[i][j] = (env.map[i][j] & 0xFF00U) | 239; - - env.map_col[i][j].colour = unmarshallShort(th); - env.map_col[i][j].flags = unmarshallShort(th); + env.map[i][j].object = unmarshallShort(th); + env.map[i][j].colour = unmarshallShort(th); + env.map[i][j].flags = unmarshallShort(th); mgrd[i][j] = NON_MONSTER; env.cgrid[i][j] = (unsigned char) unmarshallByte(th); diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc index 0bc14a2134..6e6f817208 100644 --- a/crawl-ref/source/travel.cc +++ b/crawl-ref/source/travel.cc @@ -92,7 +92,7 @@ static unsigned char curr_waypoints[GXM][GYM]; static signed char curr_traps[GXM][GYM]; #endif -static FixedArray< unsigned short, GXM, GYM > mapshadow; +static FixedArray< map_cell, GXM, GYM > mapshadow; const signed char TRAVERSABLE = 1; const signed char IMPASSABLE = 0; @@ -109,26 +109,9 @@ static void populate_stair_distances(const level_pos &target); static bool is_greed_inducing_square(const LevelStashes *ls, const coord_def &c); -bool is_player_mapped(int grid_x, int grid_y) +bool is_player_seen(int grid_x, int grid_y) { - return (is_player_mapped( env.map[grid_x - 1][grid_y - 1] )); -} - -// Determines whether the player has seen this square, given the user-visible -// character. -// -// The player is assumed to have seen the square if: -// a. The square is mapped (the env map char is not zero) -// b. The square was *not* magic-mapped. -// -// FIXME: There's better ways of doing this with the new view.cc. -bool is_player_mapped(unsigned char envch) -{ - // Note that we're relying here on mapch(DNGN_FLOOR) != mapch2(DNGN_FLOOR) - // and that no *other* dungeon feature renders as mapch(DNGN_FLOOR). - // The check for a ~ is to ensure explore stops for items turned up by - // detect items. - return envch && envch != get_magicmap_char(DNGN_FLOOR) && envch != '~'; + return (is_terrain_seen(grid_x, grid_y)); } // Returns true if there is a known trap at (x,y). Returns false for non-trap @@ -169,14 +152,6 @@ inline bool is_player_altar(const coord_def &c) return is_player_altar(grd[c.x][c.y]); } -// Copies FixedArray src to FixedArray dest. -// -inline void copy(const FixedArray<unsigned short, GXM, GYM> &src, - FixedArray<unsigned short, GXM, GYM> &dest) -{ - dest = src; -} - #ifdef CLUA_BINDINGS static void init_traps() { @@ -297,8 +272,11 @@ void toggle_exclude(int x, int y) if (you.level_type == LEVEL_LABYRINTH || you.level_type == LEVEL_ABYSS) return; - if (x <= 0 || x >= GXM || y <= 0 || y >= GYM) return; - if (!env.map[x - 1][y - 1]) return; + if (!in_bounds(x, y)) + return; + + if (!is_terrain_known(x, y)) + return; if (is_exclude_root(x, y)) { @@ -374,10 +352,9 @@ bool is_travelsafe_square(int x, int y, bool ignore_hostile, if ((grid == DNGN_OPEN_DOOR || grid == DNGN_CLOSED_DOOR) && is_terrain_changed(x, y)) { - const int c = get_envmap_char(x, y); + const int c = get_envmap_obj(x, y); const int secret_door = grid_secret_door_appearance(x, y); - return (c != get_sightmap_char(secret_door) - && c != get_magicmap_char(secret_door)); + return (c != secret_door); } if (!ignore_hostile && is_monster_blocked(x, y)) @@ -686,7 +663,7 @@ bool prompt_stop_explore(int es_why) inline static void check_interesting_square(int x, int y, explore_discoveries &ed) { - const coord_def pos(x + 1, y + 1); + const coord_def pos(x, y); if (ES_item) { @@ -760,7 +737,7 @@ static bool is_valid_explore_target(int x, int y) const int ax = x + xi, ay = y + yi; if (!in_bounds(ax, ay)) continue; - if (!is_player_mapped( get_envmap_char(ax, ay) )) + if (!is_terrain_seen(ax, ay)) return (true); } } @@ -883,12 +860,11 @@ command_type travel() // feature, stop exploring. explore_discoveries discoveries; - for (int y = 0; y < GYM - 1; ++y) + for (int y = 0; y < GYM; ++y) { - for (int x = 0; x < GXM - 1; ++x) + for (int x = 0; x < GXM; ++x) { - if (!is_player_mapped(mapshadow[x][y]) - && is_player_mapped((unsigned char) env.map[x][y])) + if (!mapshadow[x][y].seen() && is_terrain_seen(x, y)) { check_interesting_square(x, y, discoveries); } @@ -898,7 +874,7 @@ command_type travel() if (discoveries.prompt_stop()) stop_running(); - copy(env.map, mapshadow); + mapshadow = env.map; } if (you.running.is_explore()) @@ -2546,7 +2522,7 @@ void start_explore(bool grab_items) } // Clone shadow array off map - copy(env.map, mapshadow); + mapshadow = env.map; you.running.x = you.running.y = 0; start_running(); @@ -2903,23 +2879,22 @@ int LevelInfo::distance_between(const stair_info *s1, const stair_info *s2) void LevelInfo::get_stairs(std::vector<coord_def> &st) { - // These are env map coords, not grid coordinates. - for (int y = 0; y < GYM - 1; ++y) + for (int y = 0; y < GYM; ++y) { - for (int x = 0; x < GXM - 1; ++x) + for (int x = 0; x < GXM; ++x) { - int grid = grd[x + 1][y + 1]; - int envc = env.map[x][y]; + int grid = grd[x][y]; + int envc = env.map[x][y].object; - if ((x + 1 == you.x_pos && y + 1 == you.y_pos) + if ((x == you.x_pos && y == you.y_pos) || (envc && is_travelable_stair(grid) - && (is_terrain_seen(x + 1, y + 1) - || !is_branch_stair(x + 1, y + 1)))) + && (is_terrain_seen(x, y) + || !is_branch_stair(x, y)))) { // Convert to grid coords, because that's what we use // everywhere else. - const coord_def stair(x + 1, y + 1); + const coord_def stair(x, y); st.push_back(stair); } } diff --git a/crawl-ref/source/travel.h b/crawl-ref/source/travel.h index ecda8e5a12..d6fb9c62f1 100644 --- a/crawl-ref/source/travel.h +++ b/crawl-ref/source/travel.h @@ -32,13 +32,10 @@ void update_excludes(); bool is_stair(unsigned gridc); bool is_travelable_stair(unsigned gridc); command_type stair_direction(int stair_feat); -bool is_player_mapped(unsigned char envch); command_type direction_to_command( char x, char y ); bool is_resting( void ); bool can_travel_interlevel(); -bool is_player_mapped(int grid_x, int grid_y); - void find_travel_pos(int you_x, int you_y, char *move_x, char *move_y, std::vector<coord_def>* coords = NULL); diff --git a/crawl-ref/source/tutorial.cc b/crawl-ref/source/tutorial.cc index 4c6310ae92..798c3c10c1 100644 --- a/crawl-ref/source/tutorial.cc +++ b/crawl-ref/source/tutorial.cc @@ -802,7 +802,8 @@ void tutorial_first_monster(const monsters& mon) if (!Options.tutorial_events[TUT_SEEN_MONSTER]) return; - unsigned short ch, col; + unsigned ch; + unsigned short col; get_mons_glyph(&mon, &ch, &col); std::string text = "<magenta>That "; @@ -849,10 +850,14 @@ void tutorial_first_monster(const monsters& mon) void tutorial_first_item(const item_def& item) { - if (!Options.tutorial_events[TUT_SEEN_FIRST_OBJECT] || Options.tut_just_triggered) + if (!Options.tutorial_events[TUT_SEEN_FIRST_OBJECT] + || Options.tut_just_triggered) + { return; + } - unsigned short ch, col; + unsigned ch; + unsigned short col; get_item_glyph(&item, &ch, &col); std::string text = "<magenta>That "; @@ -882,7 +887,8 @@ void learned_something_new(tutorial_event_type seen_what, int x, int y) return; std::ostringstream text; - unsigned short ch, colour; + unsigned ch; + unsigned short colour; const int ex = x - you.x_pos + 9; const int ey = y - you.y_pos + 9; int object; diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc index 13679f290a..b65d2c8ede 100644 --- a/crawl-ref/source/view.cc +++ b/crawl-ref/source/view.cc @@ -61,164 +61,170 @@ // 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_GRID_KNOWN 0xFF00 +#define MAP_MAGIC_MAPPED_FLAG 0x01 +#define MAP_SEEN_FLAG 0x02 +#define MAP_CHANGED_FLAG 0x04 +#define MAP_DETECTED_MONSTER 0x08 +#define MAP_DETECTED_ITEM 0x10 +#define MAP_GRID_KNOWN 0xFF -#define MAP_CHARACTER_MASK 0x00ff - -// Flags that define what the player remembers on this square. -#define MC_ITEM 0x01 -#define MC_MONS 0x02 +#define MC_ITEM 0x01 +#define MC_MONS 0x02 static FixedVector<feature_def, NUM_FEATURES> Feature; +#ifdef UNICODE_GLYPHS +typedef unsigned int screen_buffer_t; +#else typedef unsigned short screen_buffer_t; +#endif crawl_view_geometry crawl_view; -FixedArray < unsigned int, 20, 19 > Show_Backup; +FixedArray < unsigned int, ENV_SHOW_DIAMETER, ENV_SHOW_DIAMETER > Show_Backup; unsigned char show_green; extern int stealth; // 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 ); + bool travel_colour = false ); void cloud_grid(void); void monster_grid(bool do_updates); +static void get_symbol( int x, int y, + int object, unsigned *ch, + unsigned short *colour, + bool magic_mapped = false ); +static unsigned get_symbol(int object, unsigned short *colour = NULL, + bool magic_mapped = false); + static int get_item_dngn_code(const item_def &item); static void set_show_backup( int ex, int ey ); static int get_viewobj_flags(int viewobj); -unsigned get_envmap_char(int x, int y) +unsigned map_cell::glyph() const { - return static_cast<unsigned char>( - env.map[x - 1][y - 1] & MAP_CHARACTER_MASK); + if (!object) + return (' '); + return get_symbol(object, NULL, !(flags & MAP_SEEN_FLAG)); } -void set_envmap_detected_item(int x, int y, bool detected) +bool map_cell::known() const { - if (detected) - env.map[x - 1][y - 1] |= MAP_DETECTED_ITEM; - else - env.map[x - 1][y - 1] &= ~MAP_DETECTED_ITEM; + return (object && (flags & (MAP_SEEN_FLAG | MAP_MAGIC_MAPPED_FLAG))); } -bool is_envmap_detected_item(int x, int y) +bool map_cell::seen() const { - return (env.map[x - 1][y - 1] & MAP_DETECTED_ITEM); + return (object && (flags & MAP_SEEN_FLAG)); } -void set_envmap_detected_mons(int x, int y, bool detected) +inline unsigned get_envmap_char(int x, int y) { - if (detected) - env.map[x - 1][y - 1] |= MAP_DETECTED_MONSTER; - else - env.map[x - 1][y - 1] &= ~MAP_DETECTED_MONSTER; + return env.map[x][y].glyph(); } -bool is_envmap_detected_mons(int x, int y) +int get_envmap_obj(int x, int y) { - return (env.map[x - 1][y - 1] & MAP_DETECTED_MONSTER); + return (env.map[x][y].object); } -void set_envmap_glyph(int x, int y, int chr, int col, int object) +void set_envmap_detected_item(int x, int y, bool detected) { - set_envmap_char(x, y, chr); - set_envmap_col(x, y, col, get_viewobj_flags(object)); + if (detected) + env.map[x][y].flags |= MAP_DETECTED_ITEM; + else + env.map[x][y].flags &= ~MAP_DETECTED_ITEM; } -void set_envmap_char( int x, int y, unsigned char chr ) +bool is_envmap_detected_item(int x, int y) { - env.map[x - 1][y - 1] &= (~MAP_CHARACTER_MASK); // clear old first - env.map[x - 1][y - 1] |= chr; + return (env.map[x][y].flags & MAP_DETECTED_ITEM); } -void set_envmap_col( int x, int y, int colour ) +void set_envmap_detected_mons(int x, int y, bool detected) { - env.map_col[x - 1][y - 1].colour = colour; - env.map_col[x - 1][y - 1].flags = 0; + if (detected) + env.map[x][y].flags |= MAP_DETECTED_MONSTER; + else + env.map[x][y].flags &= ~MAP_DETECTED_MONSTER; } -void set_envmap_col( int x, int y, int colour, int flags ) +bool is_envmap_detected_mons(int x, int y) { - env.map_col[x - 1][y - 1].colour = colour; - env.map_col[x - 1][y - 1].flags = flags; + return (env.map[x][y].flags & MAP_DETECTED_MONSTER); } -inline void set_envmap_item(int x, int y, bool isitem) +void set_envmap_glyph(int x, int y, int object, int col) { - if (isitem) - env.map_col[x - 1][y - 1].flags |= MC_ITEM; - else - env.map_col[x - 1][y - 1].flags &= ~MC_ITEM; + map_cell &c = env.map[x][y]; + c.object = object; + c.colour = col; } -inline void set_envmap_mons(int x, int y, bool ismons) +void set_envmap_obj( int x, int y, int obj ) { - if (ismons) - env.map_col[x - 1][y - 1].flags |= MC_MONS; - else - env.map_col[x - 1][y - 1].flags &= ~MC_MONS; + env.map[x][y].object = obj; +} + +void set_envmap_col( int x, int y, int colour ) +{ + env.map[x][y].colour = colour; } bool is_envmap_item(int x, int y) { - return (env.map_col[x - 1][y - 1].flags & MC_ITEM); + return (get_viewobj_flags(env.map[x][y].object) & MC_ITEM); } bool is_envmap_mons(int x, int y) { - return (env.map_col[x - 1][y - 1].flags & MC_MONS); + return (get_viewobj_flags(env.map[x][y].object) & MC_MONS); } int get_envmap_col(int x, int y) { - return (env.map_col[x - 1][y - 1].colour); + return (env.map[x][y].colour); } bool is_terrain_known( int x, int y ) { - return (env.map[x - 1][y - 1] & (MAP_MAGIC_MAPPED_FLAG | MAP_SEEN_FLAG)); + return (env.map[x][y].flags + & (MAP_MAGIC_MAPPED_FLAG | MAP_SEEN_FLAG)); } bool is_terrain_seen( int x, int y ) { - return (env.map[x - 1][y - 1] & MAP_SEEN_FLAG); + return (env.map[x][y].flags & MAP_SEEN_FLAG); } bool is_terrain_changed( int x, int y ) { - return (env.map[x - 1][y - 1] & MAP_CHANGED_FLAG); + return (env.map[x][y].flags & MAP_CHANGED_FLAG); } // used to mark dug out areas, unset when terrain is seen or mapped again. void set_terrain_changed( int x, int y ) { - env.map[x - 1][y - 1] |= MAP_CHANGED_FLAG; + env.map[x][y].flags |= MAP_CHANGED_FLAG; } 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; + env.map[x][y].flags &= (~MAP_CHANGED_FLAG); + env.map[x][y].flags |= MAP_MAGIC_MAPPED_FLAG; } 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; + env.map[x][y].flags &= (~MAP_CHANGED_FLAG); + env.map[x][y].flags |= MAP_SEEN_FLAG; } void clear_envmap_grid( int x, int y ) { - env.map[x - 1][y - 1] = 0; - env.map_col[x - 1][y - 1].clear(); + env.map[x][y].clear(); } #if defined(WIN32CONSOLE) || defined(DOS) @@ -284,24 +290,36 @@ static int get_viewobj_flags(int object) return (0); } +static unsigned get_symbol(int object, unsigned short *colour, + bool magic_mapped) +{ + unsigned ch; + get_symbol(0, 0, object, &ch, NULL, magic_mapped); + return (ch); +} + static void get_symbol( int x, int y, - unsigned int object, unsigned short *ch, - unsigned short *colour ) + int object, unsigned *ch, + unsigned short *colour, + bool magic_mapped ) { ASSERT( ch != NULL ); - ASSERT( colour != NULL ); if (object < NUM_FEATURES) { *ch = Feature[object].symbol; - const int colmask = *colour & COLFLAG_MASK; - // Don't clobber with BLACK, because the colour should be already set. - if (Feature[object].colour != BLACK) - *colour = Feature[object].colour | colmask; + if (colour) + { + const int colmask = *colour & COLFLAG_MASK; + // Don't clobber with BLACK, because the colour should be + // already set. + if (Feature[object].colour != BLACK) + *colour = Feature[object].colour | colmask; + } // Note anything we see that's notable - if (Feature[object].notable) + if ((x || y) && Feature[object].notable) seen_notable_thing( object, x, y ); } else @@ -310,10 +328,11 @@ static void get_symbol( int x, int y, *ch = mons_char( object - DNGN_START_OF_MONSTERS ); } - *colour = real_colour(*colour); + if (colour) + *colour = real_colour(*colour); } -void get_item_symbol(unsigned int object, unsigned short *ch, +void get_item_symbol(unsigned int object, unsigned *ch, unsigned short *colour) { if (object < NUM_FEATURES) @@ -328,7 +347,7 @@ void get_item_symbol(unsigned int object, unsigned short *ch, } -unsigned char get_sightmap_char( int feature ) +unsigned get_sightmap_char( int feature ) { if (feature < NUM_FEATURES) return (Feature[feature].symbol); @@ -336,7 +355,7 @@ unsigned char get_sightmap_char( int feature ) return (0); } -unsigned char get_magicmap_char( int feature ) +unsigned get_magicmap_char( int feature ) { if (feature < NUM_FEATURES) return (Feature[feature].magic_symbol); @@ -346,10 +365,10 @@ unsigned char get_magicmap_char( int feature ) static char get_travel_colour( int x, int y ) { - if (is_waypoint(x + 1, y + 1)) + if (is_waypoint(x, y)) return LIGHTGREEN; - short dist = travel_point_distance[x + 1][y + 1]; + short dist = travel_point_distance[x][y]; return dist > 0? Options.tc_reachable : dist == PD_EXCLUDED? Options.tc_excluded : dist == PD_EXCLUDED_RADIUS? Options.tc_exclude_circle : @@ -439,12 +458,11 @@ unsigned short dos_brand( unsigned short colour, screen_buffer_t colour_code_map( int x, int y, bool item_colour, bool travel_colour ) { - const unsigned short map_flags = env.map[x][y]; + const unsigned short map_flags = env.map[x][y].flags; if (!(map_flags & MAP_GRID_KNOWN)) return (BLACK); - // XXX: Yes, the map array and the grid array are off by one. -- bwr - const int grid_value = grd[x + 1][y + 1]; + const int grid_value = grd[x][y]; unsigned tc = travel_colour? get_travel_colour(x, y) @@ -464,19 +482,19 @@ screen_buffer_t colour_code_map( int x, int y, bool item_colour, if (tc == LIGHTGREEN || tc == LIGHTMAGENTA) return real_colour(tc); - if (item_colour && is_envmap_item(x + 1, y + 1)) - return get_envmap_col(x + 1, y + 1); + if (item_colour && is_envmap_item(x, y)) + return get_envmap_col(x, y); int feature_colour = DARKGREY; feature_colour = - is_terrain_seen(x + 1, y + 1)? Feature[grid_value].seen_colour + is_terrain_seen(x, y)? Feature[grid_value].seen_colour : Feature[grid_value].map_colour; if (feature_colour != DARKGREY) tc = feature_colour; if (Options.stair_item_brand - && is_stair(grid_value) && igrd[x + 1][y + 1] != NON_ITEM) + && is_stair(grid_value) && igrd[x][y] != NON_ITEM) { tc |= COLFLAG_STAIR_ITEM; } @@ -497,7 +515,7 @@ void clear_map(bool clear_detected_items, bool clear_detected_monsters) if (is_terrain_changed(x, y)) continue; - unsigned short envc = get_envmap_char(x, y); + unsigned envc = get_envmap_char(x, y); if (!envc) continue; @@ -510,11 +528,9 @@ void clear_map(bool clear_detected_items, bool clear_detected_monsters) if (!clear_detected_monsters && is_envmap_detected_mons(x, y)) continue; - 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_obj(x, y, is_terrain_known(x, y)? grd[x][y] : 0); set_envmap_detected_mons(x, y, false); + set_envmap_detected_item(x, y, false); } } } @@ -875,14 +891,14 @@ void item_grid() } } // end item() -void get_item_glyph( const item_def *item, unsigned short *glych, +void get_item_glyph( const item_def *item, unsigned *glych, unsigned short *glycol ) { *glycol = item->colour; get_symbol( 0, 0, get_item_dngn_code( *item ), glych, glycol ); } -void get_mons_glyph( const monsters *mons, unsigned short *glych, +void get_mons_glyph( const monsters *mons, unsigned *glych, unsigned short *glycol ) { *glycol = get_mons_colour( mons ); @@ -2009,8 +2025,7 @@ void draw_border(void) // 5. Anything else will look for the exact same character in the level map. bool is_feature(int feature, int x, int y) { - unsigned char envfeat = (unsigned char) env.map[x - 1][y - 1]; - if (!envfeat) + if (!env.map[x][y].object) return false; // 'grid' can fit in an unsigned char, but making this a short shuts up @@ -2128,7 +2143,7 @@ bool is_feature(int feature, int x, int y) return false; } default: - return envfeat == feature; + return get_envmap_char(x, y) == (unsigned) feature; } } @@ -2162,9 +2177,9 @@ static int find_feature(unsigned char feature, int curs_x, int curs_y, } int x = cx + dx, y = cy + dy; - if (x < 0 || y < 0 || x >= GXM || y >= GYM) + if (!in_bounds(x, y)) continue; - if (is_feature(feature, x + 1, y + 1)) + if (is_feature(feature, x, y + 1)) { ++matchcount; if (!ignore_count--) @@ -2255,7 +2270,7 @@ static int find_feature( const std::vector<coord_def>& features, // static int cset_adjust(int raw) { - if (Options.char_set != CSET_ASCII) + if (Options.char_set != CSET_ASCII && Options.char_set != CSET_UNICODE) { // switch to alternate char set for 8-bit characters: set_altcharset( raw > 127 ); @@ -2317,65 +2332,63 @@ static void draw_level_map(int start_x, int start_y, bool travel_mode) coord_def c(start_x + screen_x, start_y + screen_y); - if (!in_bounds(c + coord_def(1, 1))) + if (!in_bounds(c)) { buffer2[bufcount2 + 1] = DARKGREY; buffer2[bufcount2] = 0; - bufcount2 += 2; - - goto print_it; } + else + { + colour = colour_code_map(c.x, c.y, + Options.item_colour, + travel_mode && Options.travel_colour); - colour = colour_code_map(c.x, c.y, - Options.item_colour, - travel_mode && Options.travel_colour); - - buffer2[bufcount2 + 1] = colour; - buffer2[bufcount2] = (unsigned char) env.map(c); + buffer2[bufcount2 + 1] = colour; + buffer2[bufcount2] = env.map(c).glyph(); - if (c.x + 1 == you.x_pos && c.y + 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 (c == you.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. - if (Options.show_waypoints) - { - // XXX: This is a horrible hack. - screen_buffer_t &bc = buffer2[bufcount2]; - const coord_def gridc = c + coord_def(1, 1); - - unsigned char ch = is_waypoint(gridc.x, gridc.y); - if (ch && (bc == get_sightmap_char(DNGN_FLOOR) || - bc == get_magicmap_char(DNGN_FLOOR))) - bc = ch; + // 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. + if (Options.show_waypoints) + { + // XXX: This is a horrible hack. + screen_buffer_t &bc = buffer2[bufcount2]; + unsigned char ch = is_waypoint(c.x, c.y); + if (ch && (bc == get_sightmap_char(DNGN_FLOOR) || + bc == get_magicmap_char(DNGN_FLOOR))) + bc = ch; + } } bufcount2 += 2; - print_it: // newline if (screen_x == 0 && screen_y > 0) gotoxy( 1, screen_y + top ); - int ch = buffer2[bufcount2 - 2]; + unsigned ch = buffer2[bufcount2 - 2]; #ifdef USE_CURSES ch = cset_adjust( ch ); #endif textcolor( buffer2[bufcount2 - 1] ); - putch(ch); + putwch(ch); } } #ifdef USE_CURSES set_altcharset(false); #endif + + update_screen(); } // show_map() now centers the known map along x or y. This prevents @@ -2414,7 +2427,7 @@ void show_map( FixedVector<int, 2> &spec_place, bool travel_mode ) { for (i = 0; i < GXM; i++) { - if (env.map[i][j]) + if (env.map[i][j].known()) { if (!found_y) { @@ -2456,8 +2469,8 @@ void show_map( FixedVector<int, 2> &spec_place, bool travel_mode ) else if (screen_y + half_screen > max_y) screen_y = max_y - half_screen; - int curs_x = you.x_pos - start_x; - int curs_y = you.y_pos - screen_y + half_screen; + int curs_x = you.x_pos - start_x + 1; + int curs_y = you.y_pos - screen_y + half_screen + 1; int search_feat = 0, search_found = 0, anchor_x = -1, anchor_y = -1; bool map_alive = true; @@ -2476,7 +2489,8 @@ void show_map( FixedVector<int, 2> &spec_place, bool travel_mode ) redraw_map = true; cursorxy(curs_x, curs_y + top - 1); - getty = unmangle_direction_keys(getchm(KC_LEVELMAP), KC_LEVELMAP); + getty = unmangle_direction_keys(getchm(KC_LEVELMAP), KC_LEVELMAP, + false, false); switch (getty) { @@ -2614,6 +2628,12 @@ void show_map( FixedVector<int, 2> &spec_place, bool travel_mode ) move_y = -20; move_x = 0; break; + case '!': + mprf("Terrain seen: %s", + is_terrain_seen(start_x + curs_x - 1, + start_y + curs_y - 1)? "yes" : "no"); + more(); + break; case '<': case '>': case '@': @@ -2667,7 +2687,7 @@ void show_map( FixedVector<int, 2> &spec_place, bool travel_mode ) case ',': case ';': { - int x = start_x + curs_x, y = start_y + curs_y; + int x = start_x + curs_x - 1, y = start_y + curs_y - 1; if (travel_mode && x == you.x_pos && y == you.y_pos) { if (you.travel_x > 0 && you.travel_y > 0) @@ -2700,7 +2720,7 @@ void show_map( FixedVector<int, 2> &spec_place, bool travel_mode ) if (!map_alive) break; - if (curs_x + move_x < 1 || curs_x + move_x > 80) + if (curs_x + move_x < 1 || curs_x + move_x > crawl_view.termsz.x) move_x = 0; curs_x += move_x; @@ -2826,15 +2846,8 @@ void magic_mapping(int map_radius, int proportion) if (empty_count > 0) { - if (!get_envmap_char(i, j)) - { - set_envmap_char(i, j, get_magicmap_char(grd[i][j])); - -#ifdef WIZARD - if (map_radius == 1000 && you.wizard) - set_envmap_char(i, j, get_sightmap_char(grd[i][j])); -#endif - } + if (!get_envmap_obj(i, j)) + set_envmap_obj(i, j, grd[i][j]); // Hack to give demonspawn Pandemonium mutation the ability // to detect exits magically. @@ -2909,7 +2922,7 @@ bool see_grid( int grx, int gry ) return (false); } // end see_grid() -static const unsigned char table[ NUM_CSET ][ NUM_DCHAR_TYPES ] = +static const unsigned table[ NUM_CSET ][ NUM_DCHAR_TYPES ] = { // CSET_ASCII { @@ -2934,6 +2947,14 @@ static const unsigned char table[ NUM_CSET ][ NUM_DCHAR_TYPES ] = '0', ')', '[', '/', '%', '?', '=', '!', '(', // orb, missile '+', '\\', '}', '%', '$', '"', '#', // book, cloud }, + + // CSET_UNICODE + { + 0x2592, 0x2591, 0xB7, 0x25E6, '\'', 0x25FC, '^', '>', '<', + '_', 0x22C2, 0x2320, 0x2248, '8', '~', '~', + '0', ')', '[', '/', '%', '?', '=', '!', '(', + '+', '|', '}', '%', '$', '"', '#', + }, }; dungeon_char_type dchar_by_name(const std::string &name) @@ -3530,7 +3551,7 @@ int get_screen_glyph( int x, int y ) int object = env.show[ex][ey]; unsigned short colour = env.show_col[ex][ey]; - unsigned short ch; + unsigned ch; if (!object) return get_envmap_char(x, y); @@ -3552,7 +3573,7 @@ std::string screenshot( bool fullscreen ) // [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; + FixedVector<unsigned, NUM_DCHAR_TYPES> char_table_bk; char_table_bk = Options.char_table; init_char_table(CSET_ASCII); @@ -3582,7 +3603,8 @@ std::string screenshot( bool fullscreen ) { // [ds] Evil hack time again. Peek at grid, use that character. int object = grd(gc); - unsigned short glych, glycol = 0; + unsigned glych; + unsigned short glycol = 0; if (object == DNGN_SECRET_DOOR) object = grid_secret_door_appearance( gc.x, gc.y ); @@ -3667,9 +3689,9 @@ void viewwindow(bool draw_it, bool do_updates) losight( env.show, grd, you.x_pos, you.y_pos ); // must be done first - for (count_x = 0; count_x < 18; count_x++) + for (count_x = 0; count_x < ENV_SHOW_DIAMETER; count_x++) { - for (count_y = 0; count_y < 18; count_y++) + for (count_y = 0; count_y < ENV_SHOW_DIAMETER; count_y++) { env.show_col[count_x][count_y] = LIGHTGREY; Show_Backup[count_x][count_y] = 0; @@ -3691,70 +3713,65 @@ void viewwindow(bool draw_it, bool do_updates) if (flash_colour == BLACK) flash_colour = viewmap_flash_colour(); - for (count_y = 1; count_y <= crawl_view.viewsz.y; count_y++) + for (count_y = crawl_view.viewp.y; count_y <= crawl_view.viewsz.y; + count_y++) { - for (count_x = 1; count_x <= crawl_view.viewsz.x; count_x++) + for (count_x = crawl_view.viewp.x; count_x <= crawl_view.viewsz.x; + count_x++) { // in grid coords - const int gx = view2gridX(count_x); - const int gy = view2gridY(count_y); + const coord_def gc(view2grid(coord_def(count_x, count_y))); + const coord_def ep = view2show(grid2view(gc)); - if (Options.tutorial_left && in_bounds(gx, gy) - && crawl_view.in_grid_los(coord_def(gx, gy))) + if (Options.tutorial_left && in_bounds(gc) + && crawl_view.in_grid_los(gc)) { - const int ex = gx - you.x_pos + 9; - const int ey = gy - you.y_pos + 9; - - const int object = env.show[ex][ey]; + const int object = env.show(ep); if (object) { - if (is_feature('>',gx,gy)) - learned_something_new(TUT_SEEN_STAIRS,gx,gy); - else if (is_feature('_',gx,gy)) - learned_something_new(TUT_SEEN_ALTAR,gx,gy); - else if (grd[gx][gy] == DNGN_CLOSED_DOOR - && see_grid( gx, gy )) - learned_something_new(TUT_SEEN_DOOR,gx,gy); - else if (grd[gx][gy] == DNGN_ENTER_SHOP - && see_grid( gx, gy )) - learned_something_new(TUT_SEEN_SHOP,gx,gy); + if (is_feature('>', gc.x, gc.y)) + learned_something_new(TUT_SEEN_STAIRS, gc.x, gc.y); + else if (is_feature('_', gc.x, gc.y)) + learned_something_new(TUT_SEEN_ALTAR, gc.x, gc.y); + else if (grd(gc) == DNGN_CLOSED_DOOR + && see_grid( gc.x, gc.y )) + learned_something_new(TUT_SEEN_DOOR, gc.x, gc.y); + else if (grd(gc) == DNGN_ENTER_SHOP + && see_grid( gc.x, gc.y )) + learned_something_new(TUT_SEEN_SHOP, gc.x, gc.y); } } // order is important here - if (!map_bounds( gx, gy )) + if (!map_bounds(gc)) { // off the map buffy[bufcount] = 0; buffy[bufcount + 1] = DARKGREY; } - else if (!crawl_view.in_grid_los(coord_def(gx, gy))) + else if (!crawl_view.in_grid_los(gc)) { // outside the env.show area - buffy[bufcount] = get_envmap_char( gx, gy ); + buffy[bufcount] = get_envmap_char( gc.x, gc.y ); buffy[bufcount + 1] = DARKGREY; if (Options.colour_map) buffy[bufcount + 1] = - colour_code_map(gx - 1, gy - 1, - Options.item_colour); + colour_code_map(gc.x, gc.y, Options.item_colour); } - else if (gx == you.x_pos && gy == you.y_pos) + else if (gc == you.pos()) { - const int ex = gx - you.x_pos + 9; - const int ey = gy - you.y_pos + 9; - - int object = env.show[ex][ey]; - unsigned short colour = env.show_col[ex][ey]; - unsigned short ch; - get_symbol( gx, gy, object, &ch, &colour ); + int object = env.show(ep); + unsigned short colour = env.show_col(ep); + unsigned ch; + get_symbol( gc.x, gc.y, object, &ch, &colour ); if (map) { - set_envmap_glyph( gx, gy, ch, colour, object ); - set_terrain_seen( gx, gy ); - set_envmap_detected_mons(gx, gy, false); - set_envmap_detected_item(gx, gy, false); + set_envmap_glyph( gc.x, gc.y, object, colour ); + set_terrain_seen( gc.x, gc.y ); + set_envmap_detected_mons(gc.x, gc.y, false); + set_envmap_detected_item(gc.x, gc.y, false); } // player overrides everything in cell @@ -3763,7 +3780,7 @@ void viewwindow(bool draw_it, bool do_updates) if (player_is_swimming()) { - if (grd[gx][gy] == DNGN_DEEP_WATER) + if (grd(gc) == DNGN_DEEP_WATER) buffy[bufcount + 1] = BLUE; else buffy[bufcount + 1] = CYAN; @@ -3771,19 +3788,14 @@ void viewwindow(bool draw_it, bool do_updates) } else { - // 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; - - int object = env.show[ex][ey]; - unsigned short colour = env.show_col[ex][ey]; - unsigned short ch; + int object = env.show(ep); + unsigned short colour = env.show_col(ep); + unsigned ch; if (object == DNGN_SECRET_DOOR) - object = grid_secret_door_appearance( gx, gy ); + object = grid_secret_door_appearance( gc.x, gc.y ); - get_symbol( gx, gy, object, &ch, &colour ); + get_symbol( gc.x, gc.y, object, &ch, &colour ); buffy[bufcount] = ch; buffy[bufcount + 1] = colour; @@ -3798,10 +3810,10 @@ void viewwindow(bool draw_it, bool do_updates) if (buffy[bufcount] != 0) { // ... map that we've seen this - set_envmap_glyph( gx, gy, ch, colour, object ); - set_terrain_seen( gx, gy ); - set_envmap_detected_mons(gx, gy, false); - set_envmap_detected_item(gx, gy, false); + set_envmap_glyph( gc.x, gc.y, object, colour ); + set_terrain_seen( gc.x, gc.y ); + set_envmap_detected_mons(gc.x, gc.y, false); + set_envmap_detected_item(gc.x, gc.y, false); } // Check if we're looking to clean_map... @@ -3816,13 +3828,13 @@ void viewwindow(bool draw_it, bool do_updates) // to the grid before monsters and clouds were // added otherwise. if (Options.clean_map - && Show_Backup[ex][ey] - && is_terrain_seen( gx, gy )) + && Show_Backup(ep) + && is_terrain_seen( gc.x, gc.y )) { - get_symbol( gx, gy, - Show_Backup[ex][ey], &ch, &colour ); - set_envmap_glyph( gx, gy, ch, colour, - Show_Backup[ex][ey] ); + get_symbol( gc.x, gc.y, + Show_Backup(ep), &ch, &colour ); + set_envmap_glyph( gc.x, gc.y, Show_Backup(ep), + colour ); } // Now we get to filling in both the unseen @@ -3838,12 +3850,12 @@ void viewwindow(bool draw_it, bool do_updates) if (buffy[bufcount] == 0) { // show map - buffy[bufcount] = get_envmap_char( gx, gy ); + buffy[bufcount] = get_envmap_char( gc.x, gc.y ); buffy[bufcount + 1] = DARKGREY; if (Options.colour_map) buffy[bufcount + 1] = - colour_code_map(gx - 1, gy - 1, + colour_code_map(gc.x, gc.y, Options.item_colour); } } @@ -3877,7 +3889,7 @@ void viewwindow(bool draw_it, bool do_updates) buffy[bufcount] = cset_adjust( buffy[bufcount] ); #endif textcolor( buffy[bufcount + 1] ); - putch( buffy[bufcount] ); + putwch( buffy[bufcount] ); bufcount += 2; } } @@ -3886,6 +3898,7 @@ void viewwindow(bool draw_it, bool do_updates) #ifdef USE_CURSES set_altcharset( false ); #endif + update_screen(); } } // end viewwindow() diff --git a/crawl-ref/source/view.h b/crawl-ref/source/view.h index ce31141055..38bdc47b61 100644 --- a/crawl-ref/source/view.h +++ b/crawl-ref/source/view.h @@ -110,19 +110,20 @@ void clear_map(bool clear_items = true, bool clear_mons = true); bool is_feature(int feature, int x, int y); -void get_item_glyph(const item_def *item, unsigned short *glych, +void get_item_glyph(const item_def *item, unsigned *glych, unsigned short *glycol); -void get_mons_glyph(const monsters *mons, unsigned short *glych, +void get_mons_glyph(const monsters *mons, unsigned *glych, unsigned short *glycol); int get_screen_glyph( int x, int y ); -void get_item_symbol(unsigned int object, unsigned short *ch, +void get_item_symbol(unsigned int object, unsigned *ch, unsigned short *colour); // Applies EC_ colour substitutions and brands. unsigned real_colour(unsigned raw_colour); -void set_envmap_char( int x, int y, unsigned char chr ); +void set_envmap_obj( int x, int y, int object ); unsigned get_envmap_char(int x, int y); +int get_envmap_obj(int x, int y); void set_envmap_detected_item(int x, int y, bool detected = true); void set_envmap_detected_mons(int x, int y, bool detected = true); void set_envmap_col( int x, int y, int colour, int flags ); @@ -150,8 +151,8 @@ bool see_grid( int grx, int gry ); std::string screenshot(bool fullscreen = false); -unsigned char get_sightmap_char(int feature); -unsigned char get_magicmap_char(int feature); +unsigned get_sightmap_char(int feature); +unsigned get_magicmap_char(int feature); void viewwindow(bool draw_it, bool do_updates); void fire_monster_alerts(); |