From 64c38d95bfd6b24e34bc86f7d4ce7ba345c5a963 Mon Sep 17 00:00:00 2001 From: Robert Vollmert Date: Wed, 4 Nov 2009 22:45:50 +0100 Subject: Split up view.cc. --- crawl-ref/source/acr.cc | 3 + crawl-ref/source/arena.cc | 1 + crawl-ref/source/beam.cc | 3 + crawl-ref/source/chardump.cc | 1 + crawl-ref/source/cio.cc | 1 + crawl-ref/source/cloud.cc | 1 + crawl-ref/source/colour.cc | 129 +++ crawl-ref/source/colour.h | 8 + crawl-ref/source/command.cc | 1 + crawl-ref/source/coord.cc | 2 +- crawl-ref/source/debug.cc | 1 + crawl-ref/source/delay.cc | 1 + crawl-ref/source/directn.cc | 3 + crawl-ref/source/directn.h | 138 --- crawl-ref/source/dungeon.cc | 1 + crawl-ref/source/effects.cc | 2 + crawl-ref/source/env.h | 1 + crawl-ref/source/envmap.cc | 348 ++++++ crawl-ref/source/envmap.h | 83 ++ crawl-ref/source/exclude.cc | 1 + crawl-ref/source/fight.cc | 2 + crawl-ref/source/files.cc | 1 + crawl-ref/source/format.cc | 1 + crawl-ref/source/initfile.cc | 1 + crawl-ref/source/item_use.cc | 5 +- crawl-ref/source/items.cc | 1 + crawl-ref/source/libgui.cc | 1 + crawl-ref/source/libunix.cc | 1 + crawl-ref/source/libutil.cc | 3 +- crawl-ref/source/los.cc | 2 +- crawl-ref/source/makefile.obj | 4 + crawl-ref/source/mapcell.h | 22 + crawl-ref/source/message.cc | 2 + crawl-ref/source/misc.cc | 2 + crawl-ref/source/mon-abil.cc | 2 + crawl-ref/source/mon-act.cc | 2 + crawl-ref/source/mon-behv.cc | 1 + crawl-ref/source/mon-cast.cc | 2 + crawl-ref/source/mon-util.cc | 1 + crawl-ref/source/monplace.cc | 1 + crawl-ref/source/monstuff.cc | 2 + crawl-ref/source/output.cc | 2 + crawl-ref/source/overmap.cc | 1 + crawl-ref/source/player.cc | 2 + crawl-ref/source/religion.cc | 1 + crawl-ref/source/show.cc | 2 + crawl-ref/source/show.h | 16 +- crawl-ref/source/spells1.cc | 1 + crawl-ref/source/spells2.cc | 1 + crawl-ref/source/spells3.cc | 2 + crawl-ref/source/spells4.cc | 1 + crawl-ref/source/spl-cast.cc | 1 + crawl-ref/source/spl-mis.cc | 1 + crawl-ref/source/stash.cc | 1 + crawl-ref/source/stuff.cc | 2 + crawl-ref/source/tags.cc | 1 + crawl-ref/source/teleport.cc | 1 + crawl-ref/source/terrain.cc | 1 + crawl-ref/source/tilepick.cc | 2 + crawl-ref/source/tilereg.cc | 2 + crawl-ref/source/tilesdl.cc | 2 + crawl-ref/source/traps.cc | 1 + crawl-ref/source/travel.cc | 1 + crawl-ref/source/tutorial.cc | 2 + crawl-ref/source/view.cc | 2367 +++-------------------------------------- crawl-ref/source/view.h | 86 +- crawl-ref/source/viewchar.cc | 103 ++ crawl-ref/source/viewchar.h | 13 + crawl-ref/source/viewgeom.cc | 382 +++++++ crawl-ref/source/viewgeom.h | 145 +++ crawl-ref/source/viewmap.cc | 1188 +++++++++++++++++++++ crawl-ref/source/viewmap.h | 10 + crawl-ref/source/xom.cc | 2 + 73 files changed, 2667 insertions(+), 2464 deletions(-) create mode 100644 crawl-ref/source/envmap.cc create mode 100644 crawl-ref/source/envmap.h create mode 100644 crawl-ref/source/mapcell.h create mode 100644 crawl-ref/source/viewchar.cc create mode 100644 crawl-ref/source/viewchar.h create mode 100644 crawl-ref/source/viewgeom.cc create mode 100644 crawl-ref/source/viewgeom.h create mode 100644 crawl-ref/source/viewmap.cc create mode 100644 crawl-ref/source/viewmap.h diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index 7ced21d0a1..4af8c5263f 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -62,6 +62,7 @@ #include "directn.h" #include "dungeon.h" #include "effects.h" +#include "envmap.h" #include "fight.h" #include "files.h" #include "food.h" @@ -118,6 +119,8 @@ #include "travel.h" #include "tutorial.h" #include "view.h" +#include "viewchar.h" +#include "viewgeom.h" #include "stash.h" #include "xom.h" diff --git a/crawl-ref/source/arena.cc b/crawl-ref/source/arena.cc index 0c18e8d33d..3dbcfa9c28 100644 --- a/crawl-ref/source/arena.cc +++ b/crawl-ref/source/arena.cc @@ -30,6 +30,7 @@ #include "spl-util.h" #include "state.h" #include "view.h" +#include "viewgeom.h" #define DEBUG_DIAGNOSTICS 1 diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc index a566852a21..af3c262bf8 100644 --- a/crawl-ref/source/beam.cc +++ b/crawl-ref/source/beam.cc @@ -32,6 +32,7 @@ #include "dgnevent.h" #include "effects.h" #include "enum.h" +#include "envmap.h" #include "fight.h" #include "item_use.h" #include "it_use2.h" @@ -59,6 +60,8 @@ #include "transfor.h" #include "traps.h" #include "view.h" +#include "viewchar.h" +#include "viewgeom.h" #include "xom.h" #include "tiles.h" diff --git a/crawl-ref/source/chardump.cc b/crawl-ref/source/chardump.cc index 0787629f40..86f8a2df61 100644 --- a/crawl-ref/source/chardump.cc +++ b/crawl-ref/source/chardump.cc @@ -54,6 +54,7 @@ #include "stuff.h" #include "transfor.h" #include "view.h" +#include "viewchar.h" #include "xom.h" struct dump_params; diff --git a/crawl-ref/source/cio.cc b/crawl-ref/source/cio.cc index 59f460b0ec..6f95297d84 100644 --- a/crawl-ref/source/cio.cc +++ b/crawl-ref/source/cio.cc @@ -12,6 +12,7 @@ #include "macro.h" #include "message.h" #include "state.h" +#include "viewgeom.h" #include diff --git a/crawl-ref/source/cloud.cc b/crawl-ref/source/cloud.cc index 04736fc968..52df81690c 100644 --- a/crawl-ref/source/cloud.cc +++ b/crawl-ref/source/cloud.cc @@ -16,6 +16,7 @@ #include "cloud.h" #include "colour.h" #include "coord.h" +#include "envmap.h" #include "mapmark.h" #include "ouch.h" #include "player.h" diff --git a/crawl-ref/source/colour.cc b/crawl-ref/source/colour.cc index 896075b8d4..9bca86e7de 100644 --- a/crawl-ref/source/colour.cc +++ b/crawl-ref/source/colour.cc @@ -4,6 +4,7 @@ #include "env.h" #include "mon-util.h" +#include "options.h" #include "player.h" #include "random.h" @@ -392,3 +393,131 @@ int str_to_colour( const std::string &str, int default_colour, return ((ret == 16) ? default_colour : ret); } + +#if defined(TARGET_OS_WINDOWS) || defined(TARGET_OS_DOS) || defined(USE_TILE) +static unsigned short _dos_reverse_brand(unsigned short colour) +{ + if (Options.dos_use_background_intensity) + { + // If the console treats the intensity bit on background colours + // correctly, we can do a very simple colour invert. + + // Special casery for shadows. + if (colour == BLACK) + colour = (DARKGREY << 4); + else + colour = (colour & 0xF) << 4; + } + else + { + // If we're on a console that takes its DOSness very seriously the + // background high-intensity bit is actually a blink bit. Blinking is + // evil, so we strip the background high-intensity bit. This, sadly, + // limits us to 7 background colours. + + // Strip off high-intensity bit. Special case DARKGREY, since it's the + // high-intensity counterpart of black, and we don't want black on + // black. + // + // We *could* set the foreground colour to WHITE if the background + // intensity bit is set, but I think we've carried the + // angry-fruit-salad theme far enough already. + + if (colour == DARKGREY) + colour |= (LIGHTGREY << 4); + else if (colour == BLACK) + colour = LIGHTGREY << 4; + else + { + // Zap out any existing background colour, and the high + // intensity bit. + colour &= 7; + + // And swap the foreground colour over to the background + // colour, leaving the foreground black. + colour <<= 4; + } + } + + return (colour); +} + +static unsigned short _dos_hilite_brand(unsigned short colour, + unsigned short hilite) +{ + if (!hilite) + return (colour); + + if (colour == hilite) + colour = 0; + + colour |= (hilite << 4); + return (colour); +} + +unsigned short dos_brand( unsigned short colour, + unsigned brand) +{ + if ((brand & CHATTR_ATTRMASK) == CHATTR_NORMAL) + return (colour); + + colour &= 0xFF; + + if ((brand & CHATTR_ATTRMASK) == CHATTR_HILITE) + return _dos_hilite_brand(colour, (brand & CHATTR_COLMASK) >> 8); + else + return _dos_reverse_brand(colour); +} +#endif + +#if defined(TARGET_OS_WINDOWS) || defined(TARGET_OS_DOS) || defined(USE_TILE) +static unsigned _colflag2brand(int colflag) +{ + switch (colflag) + { + case COLFLAG_ITEM_HEAP: + return (Options.heap_brand); + case COLFLAG_FRIENDLY_MONSTER: + return (Options.friend_brand); + case COLFLAG_NEUTRAL_MONSTER: + return (Options.neutral_brand); + case COLFLAG_WILLSTAB: + return (Options.stab_brand); + case COLFLAG_MAYSTAB: + return (Options.may_stab_brand); + case COLFLAG_FEATURE_ITEM: + return (Options.feature_item_brand); + case COLFLAG_TRAP_ITEM: + return (Options.trap_item_brand); + default: + return (CHATTR_NORMAL); + } +} +#endif + +unsigned real_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. + const int colflags = raw_colour & 0xFF00; + + // Evaluate any elemental colours to guarantee vanilla colour is returned + if (is_element_colour( raw_colour )) + raw_colour = colflags | element_colour( raw_colour ); + +#if defined(TARGET_OS_WINDOWS) || defined(TARGET_OS_DOS) || defined(USE_TILE) + if (colflags) + { + unsigned brand = _colflag2brand(colflags); + raw_colour = dos_brand(raw_colour & 0xFF, brand); + } +#endif + +#ifndef USE_COLOUR_OPTS + // Strip COLFLAGs for systems that can't do anything meaningful with them. + raw_colour &= 0xFF; +#endif + + return (raw_colour); +} diff --git a/crawl-ref/source/colour.h b/crawl-ref/source/colour.h index 8c896d9148..c13aa973df 100644 --- a/crawl-ref/source/colour.h +++ b/crawl-ref/source/colour.h @@ -62,4 +62,12 @@ unsigned char make_high_colour(unsigned char colour); bool is_element_colour(int col); int element_colour(int element, bool no_random = false); +#if defined(TARGET_OS_WINDOWS) || defined(TARGET_OS_DOS) || defined(USE_TILE) +unsigned short dos_brand( unsigned short colour, + unsigned brand = CHATTR_REVERSE); +#endif + +// Applies ETC_ colour substitutions and brands. +unsigned real_colour(unsigned raw_colour); + #endif diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc index 0b117625df..ed7a181af5 100644 --- a/crawl-ref/source/command.cc +++ b/crawl-ref/source/command.cc @@ -51,6 +51,7 @@ #include "terrain.h" #include "transfor.h" #include "view.h" +#include "viewchar.h" static void _adjust_item(void); static void _adjust_spells(void); diff --git a/crawl-ref/source/coord.cc b/crawl-ref/source/coord.cc index 59a75cf888..576c71bd27 100644 --- a/crawl-ref/source/coord.cc +++ b/crawl-ref/source/coord.cc @@ -2,9 +2,9 @@ #include "coord.h" -#include "directn.h" #include "random.h" #include "state.h" +#include "viewgeom.h" ////////////////////////////////////////////////////////////////////////// // coord_def diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc index 0f2fb2f966..d2c57506a9 100644 --- a/crawl-ref/source/debug.cc +++ b/crawl-ref/source/debug.cc @@ -39,6 +39,7 @@ #include "directn.h" #include "dungeon.h" #include "effects.h" +#include "envmap.h" #include "fight.h" #include "files.h" #include "food.h" diff --git a/crawl-ref/source/delay.cc b/crawl-ref/source/delay.cc index 9ca25fabf5..5914aa4e5d 100644 --- a/crawl-ref/source/delay.cc +++ b/crawl-ref/source/delay.cc @@ -21,6 +21,7 @@ #include "describe.h" #include "directn.h" #include "enum.h" +#include "envmap.h" #include "exclude.h" #include "food.h" #include "invent.h" diff --git a/crawl-ref/source/directn.cc b/crawl-ref/source/directn.cc index 9a981ded71..033924fc89 100644 --- a/crawl-ref/source/directn.cc +++ b/crawl-ref/source/directn.cc @@ -31,6 +31,7 @@ #include "debug.h" #include "describe.h" #include "dungeon.h" +#include "envmap.h" #include "initfile.h" #include "invent.h" #include "itemname.h" @@ -59,6 +60,8 @@ #include "travel.h" #include "tutorial.h" #include "view.h" +#include "viewchar.h" +#include "viewgeom.h" #include "output.h" #include "macro.h" diff --git a/crawl-ref/source/directn.h b/crawl-ref/source/directn.h index d7bbd68656..08d5fd60ca 100644 --- a/crawl-ref/source/directn.h +++ b/crawl-ref/source/directn.h @@ -25,94 +25,6 @@ private: bool do_anything; }; -class crawl_view_buffer -{ -public: - crawl_view_buffer(); - ~crawl_view_buffer(); - void size(const coord_def &size); - operator screen_buffer_t * () { return (buffer); } - - void draw(); -private: - screen_buffer_t *buffer; -}; - -struct crawl_view_geometry -{ -public: - coord_def termp; // Left-top pos of terminal. - coord_def termsz; // Size of the terminal. - coord_def viewp; // Left-top pos of viewport. - coord_def viewsz; // Size of the viewport (play area). - coord_def hudp; // Left-top pos of status area. - coord_def hudsz; // Size of the status area. - coord_def msgp; // Left-top pos of the message pane. - coord_def msgsz; // Size of the message pane. - coord_def mlistp; // Left-top pos of the monster list. - coord_def mlistsz; // Size of the monster list. - - crawl_view_buffer vbuf; // Buffer for drawing the main game map. - - coord_def vgrdc; // What grid pos is at the centre of the view - // usually you.pos(). - - coord_def viewhalfsz; - - coord_def glos1, glos2; // LOS limit grid coords (inclusive) - coord_def vlos1, vlos2; // LOS limit viewport coords (inclusive) - - coord_def mousep; // Where the mouse is. - -private: - coord_def last_player_pos; - -public: - crawl_view_geometry(); - void init_geometry(); - - void init_view(); - void set_player_at(const coord_def &c, bool force_centre = false); - // Set new location, but preserve scrolling as if the player didn't move. - void shift_player_to(const coord_def &c); - - coord_def view_centre() const - { - return viewp + viewhalfsz; - } - - coord_def glosc() const - { - return (glos1 + glos2) / 2; - } - - bool in_grid_los(const coord_def &c) const - { - return (c.x >= glos1.x && c.x <= glos2.x - && c.y >= glos1.y && c.y <= glos2.y); - } - - bool in_view_los(const coord_def &c) const - { - return (c.x >= vlos1.x && c.x <= vlos2.x - && c.y >= vlos1.y && c.y <= vlos2.y); - } - - bool in_view_viewport(const coord_def &c) const - { - return (c.x >= viewp.x && c.y >= viewp.y - && c.x < viewp.x + viewsz.x - && c.y < viewp.y + viewsz.y); - } - - bool in_grid_viewport(const coord_def &c) const - { - return in_view_viewport(c - vgrdc + view_centre()); - } -}; - -extern crawl_view_geometry crawl_view; - // An object that modifies the behaviour of the direction prompt. class targetting_behaviour { @@ -206,56 +118,6 @@ std::vector features_by_desc(const base_pattern &pattern); void full_describe_view(void); -inline int view2gridX(int vx) -{ - return (crawl_view.vgrdc.x + vx - crawl_view.view_centre().x); -} - -inline int view2gridY(int vy) -{ - return (crawl_view.vgrdc.y + vy - crawl_view.view_centre().y); -} - -inline coord_def view2grid(const coord_def &pos) -{ - return pos - crawl_view.view_centre() + crawl_view.vgrdc; -} - -inline int grid2viewX(int gx) -{ - return (gx - crawl_view.vgrdc.x + crawl_view.view_centre().x); -} - -inline int grid2viewY(int gy) -{ - return (gy - crawl_view.vgrdc.y + crawl_view.view_centre().y); -} - -inline coord_def grid2view(const coord_def &pos) -{ - return (pos - crawl_view.vgrdc + crawl_view.view_centre()); -} - -inline coord_def view2show(const coord_def &pos) -{ - return (pos - crawl_view.vlos1); -} - -inline coord_def show2view(const coord_def &pos) -{ - return (pos + crawl_view.vlos1); -} - -inline coord_def grid2show(const coord_def &pos) -{ - return (view2show(grid2view(pos))); -} - -inline coord_def show2grid(const coord_def &pos) -{ - return (view2grid(show2view(pos))); -} - extern const struct coord_def Compass[8]; #endif diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc index 9c0bf853a3..4d16c46348 100644 --- a/crawl-ref/source/dungeon.cc +++ b/crawl-ref/source/dungeon.cc @@ -22,6 +22,7 @@ #include "defines.h" #include "effects.h" #include "enum.h" +#include "envmap.h" #include "externs.h" #include "options.h" #include "directn.h" diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc index 1630dab32a..26289f2616 100644 --- a/crawl-ref/source/effects.cc +++ b/crawl-ref/source/effects.cc @@ -27,6 +27,7 @@ #include "delay.h" #include "directn.h" #include "dgnevent.h" +#include "envmap.h" #include "food.h" #include "hiscores.h" #include "invent.h" @@ -62,6 +63,7 @@ #include "traps.h" #include "tutorial.h" #include "view.h" +#include "viewchar.h" #include "xom.h" int holy_word_player(int pow, int caster, actor *attacker) diff --git a/crawl-ref/source/env.h b/crawl-ref/source/env.h index 32ce82e92a..fd9abf7720 100644 --- a/crawl-ref/source/env.h +++ b/crawl-ref/source/env.h @@ -1,6 +1,7 @@ #ifndef ENV_H #define ENV_H +#include "mapcell.h" #include "monster.h" #include "show.h" diff --git a/crawl-ref/source/envmap.cc b/crawl-ref/source/envmap.cc new file mode 100644 index 0000000000..fb0f948183 --- /dev/null +++ b/crawl-ref/source/envmap.cc @@ -0,0 +1,348 @@ +/* + * File: envmap.cc + * Summary: Functions dealing with env.map. + */ + +#include "AppHdr.h" + +#include "envmap.h" + +#include "coord.h" +#include "coordit.h" +#include "dgnevent.h" +#include "directn.h" +#include "env.h" +#include "notes.h" +#include "overmap.h" +#include "stuff.h" +#include "terrain.h" +#include "view.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 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 MC_ITEM 0x01 +#define MC_MONS 0x02 + +unsigned map_cell::glyph() const +{ + if (!object) + return (' '); + return get_symbol(object, NULL, !(flags & MAP_SEEN_FLAG)); +} + +bool map_cell::known() const +{ + return (object && (flags & MAP_GRID_KNOWN)); +} + +bool map_cell::seen() const +{ + return (object && (flags & MAP_SEEN_FLAG)); +} + +static int _get_viewobj_flags(show_type object) +{ + // Check for monster glyphs. + if (object.cls == SH_MONSTER) + return (MC_MONS); + + // Check for item glyphs. + if (object.cls == SH_ITEM) + return (MC_ITEM); + + // We don't care to look further; we could check for + // clouds here as well. + return (0); +} + +unsigned get_envmap_char(int x, int y) +{ + return env.map[x][y].glyph(); +} + +show_type get_envmap_obj(int x, int y) +{ + return (env.map[x][y].object); +} + +void set_envmap_detected_item(int x, int y, bool detected) +{ + if (detected) + env.map[x][y].flags |= MAP_DETECTED_ITEM; + else + env.map[x][y].flags &= ~MAP_DETECTED_ITEM; +} + +bool is_envmap_detected_item(int x, int y) +{ + return (env.map[x][y].flags & MAP_DETECTED_ITEM); +} + +void set_envmap_detected_mons(int x, int y, bool detected) +{ + if (detected) + env.map[x][y].flags |= MAP_DETECTED_MONSTER; + else + env.map[x][y].flags &= ~MAP_DETECTED_MONSTER; +} + +bool is_envmap_detected_mons(int x, int y) +{ + return (env.map[x][y].flags & MAP_DETECTED_MONSTER); +} + +void set_envmap_glyph(int x, int y, show_type object, int col) +{ + map_cell &c = env.map[x][y]; + c.object = object; + c.colour = col; +#ifdef USE_TILE + tiles.update_minimap(x, y); +#endif +} + +void set_envmap_glyph(const coord_def& c, show_type object, int col) +{ + set_envmap_glyph(c.x, c.y, object, col); +} + +void set_envmap_obj(const coord_def& where, show_type obj) +{ + env.map(where).object = obj; +#ifdef USE_TILE + tiles.update_minimap(where.x, where.y); +#endif +} + +void set_envmap_col( int x, int y, int colour ) +{ + env.map[x][y].colour = colour; +} + +bool is_sanctuary(const coord_def& p) +{ + if (!map_bounds(p)) + return (false); + return (testbits(env.map(p).property, FPROP_SANCTUARY_1) + || testbits(env.map(p).property, FPROP_SANCTUARY_2)); +} + +bool is_bloodcovered(const coord_def& p) +{ + return (testbits(env.map(p).property, FPROP_BLOODY)); +} + +bool is_envmap_item(int x, int y) +{ + return (_get_viewobj_flags(env.map[x][y].object) & MC_ITEM); +} + +bool is_envmap_mons(int x, int y) +{ + return (_get_viewobj_flags(env.map[x][y].object) & MC_MONS); +} + +int get_envmap_col(const coord_def& p) +{ + return (env.map[p.x][p.y].colour); +} + +bool is_terrain_known( int x, int y ) +{ + return (env.map[x][y].known()); +} + +bool is_terrain_known(const coord_def &p) +{ + return (env.map(p).known()); +} + +bool is_terrain_seen( int x, int y ) +{ + return (env.map[x][y].flags & MAP_SEEN_FLAG); +} + +bool is_terrain_changed( int x, int y ) +{ + return (env.map[x][y].flags & MAP_CHANGED_FLAG); +} + +bool is_terrain_mapped(const coord_def &p) +{ + return (env.map(p).flags & MAP_MAGIC_MAPPED_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][y].flags |= MAP_CHANGED_FLAG; + + dungeon_events.fire_position_event(DET_FEAT_CHANGE, coord_def(x, y)); +} + +void set_terrain_mapped( int x, int y ) +{ + env.map[x][y].flags &= (~MAP_CHANGED_FLAG); + env.map[x][y].flags |= MAP_MAGIC_MAPPED_FLAG; +#ifdef USE_TILE + tiles.update_minimap(x, y); +#endif +} + +int count_detected_mons() +{ + int count = 0; + for (rectangle_iterator ri(BOUNDARY_BORDER - 1); ri; ++ri) + { + // 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(*ri)) + continue; + + if (is_envmap_detected_mons(*ri)) + count++; + } + + return (count); +} + +void clear_map(bool clear_detected_items, bool clear_detected_monsters) +{ + for (rectangle_iterator ri(BOUNDARY_BORDER - 1); ri; ++ri) + { + const coord_def p = *ri; + // 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). + + // This reasoning doesn't make sense when it comes to *clearing* + // the map! (jpeg) + + if (get_envmap_char(p) == 0) + continue; + + if (is_envmap_item(p)) + continue; + + if (!clear_detected_items && is_envmap_detected_item(p)) + continue; + + if (!clear_detected_monsters && is_envmap_detected_mons(p)) + continue; + +#ifdef USE_TILE + if (is_terrain_mapped(p) && !is_envmap_detected_mons(p)) + continue; +#endif + + set_envmap_obj(p, show_type(is_terrain_seen(p) || is_terrain_mapped(p) + ? grd(p) : DNGN_UNSEEN)); + set_envmap_detected_mons(p, false); + set_envmap_detected_item(p, false); + +#ifdef USE_TILE + if (is_terrain_mapped(p)) + { + dungeon_feature_type feature = grd(p); + + unsigned int feat_symbol; + unsigned short feat_colour; + get_show_symbol(show_type(feature), &feat_symbol, &feat_colour); + + unsigned int fg; + unsigned int bg; + tileidx_unseen(fg, bg, feat_symbol, p); + env.tile_bk_bg(p) = bg; + env.tile_bk_fg(p) = fg; + } + else + { + env.tile_bk_bg(p) = is_terrain_seen(p) ? + tile_idx_unseen_terrain(p.x, p.y, grd(p)) : + tileidx_feature(DNGN_UNSEEN, p.x, p.y); + env.tile_bk_fg(p) = 0; + } +#endif + } +} + +static void _automap_from( int x, int y, int mutated ) +{ + if (mutated) + magic_mapping(8 * mutated, 25, true, false, + true, true, coord_def(x,y)); +} + +void reautomap_level( ) +{ + int passive = player_mutation_level(MUT_PASSIVE_MAPPING); + + for (int x = X_BOUND_1; x <= X_BOUND_2; ++x) + for (int y = Y_BOUND_1; y <= Y_BOUND_2; ++y) + if (env.map[x][y].flags & MAP_SEEN_FLAG) + _automap_from(x, y, passive); +} + +void set_terrain_seen( int x, int y ) +{ + const dungeon_feature_type feat = grd[x][y]; + + // First time we've seen a notable feature. + if (!(env.map[x][y].flags & MAP_SEEN_FLAG)) + { + _automap_from(x, y, player_mutation_level(MUT_PASSIVE_MAPPING)); + + const bool boring = !is_notable_terrain(feat) + // A portal deeper into the Zigguart is boring. + || (feat == DNGN_ENTER_PORTAL_VAULT + && you.level_type == LEVEL_PORTAL_VAULT) + // Altars in the temple are boring. + || (feat_is_altar(feat) + && player_in_branch(BRANCH_ECUMENICAL_TEMPLE)) + // Only note the first entrance to the Abyss/Pan/Hell + // which is found. + || ((feat == DNGN_ENTER_ABYSS || feat == DNGN_ENTER_PANDEMONIUM + || feat == DNGN_ENTER_HELL) + && overmap_knows_num_portals(feat) > 1) + // There are at least three Zot entrances, and they're always + // on D:27, so ignore them. + || feat == DNGN_ENTER_ZOT; + + if (!boring) + { + coord_def pos(x, y); + std::string desc = + feature_description(pos, false, DESC_NOCAP_A); + + take_note(Note(NOTE_SEEN_FEAT, 0, 0, desc.c_str())); + } + } + +#ifdef USE_TILE + env.map[x][y].flags &= ~(MAP_DETECTED_ITEM); + env.map[x][y].flags &= ~(MAP_DETECTED_MONSTER); +#endif + + env.map[x][y].flags &= (~MAP_CHANGED_FLAG); + env.map[x][y].flags |= MAP_SEEN_FLAG; +} + +void clear_envmap_grid( const coord_def& p ) +{ + env.map(p).clear(); +} + +void clear_envmap_grid( int x, int y ) +{ + env.map[x][y].clear(); +} diff --git a/crawl-ref/source/envmap.h b/crawl-ref/source/envmap.h new file mode 100644 index 0000000000..f7352eab8d --- /dev/null +++ b/crawl-ref/source/envmap.h @@ -0,0 +1,83 @@ +#ifndef ENVMAP_H +#define ENVMAP_H + +#include "show.h" + +struct coord_def; + +void set_envmap_obj(const coord_def& where, show_type object); +unsigned get_envmap_char(int x, int y); +inline unsigned get_envmap_char(const coord_def& c) { + return get_envmap_char(c.x, c.y); +} +show_type get_envmap_obj(int x, int y); +inline show_type get_envmap_obj(const coord_def& c) { + return get_envmap_obj(c.x, c.y); +} +void set_envmap_detected_item(int x, int y, bool detected = true); +inline void set_envmap_detected_item(const coord_def& c, bool detected = true) { + set_envmap_detected_item(c.x, c.y, detected); +} + +void set_envmap_detected_mons(int x, int y, bool detected = true); +inline void set_envmap_detected_mons(const coord_def& c, bool detected = true) { + set_envmap_detected_mons(c.x, c.y, detected); +} +void set_envmap_col( int x, int y, int colour, int flags ); +void set_envmap_col( int x, int y, int colour ); +bool is_sanctuary( const coord_def& p ); +bool is_bloodcovered( const coord_def& p ); + +bool is_envmap_detected_item(int x, int y); +inline bool is_envmap_detected_item(const coord_def& c) { + return is_envmap_detected_item(c.x, c.y); +} + +bool is_envmap_detected_mons(int x, int y); +inline bool is_envmap_detected_mons(const coord_def& c) { + return is_envmap_detected_mons(c.x, c.y); +} +bool is_envmap_item(int x, int y); +inline bool is_envmap_item(const coord_def& c) { + return is_envmap_item(c.x, c.y); +} +void set_terrain_mapped( int x, int y ); +inline void set_terrain_mapped( const coord_def& c ) { + set_terrain_mapped(c.x,c.y); +} +void set_terrain_seen( int x, int y ); +inline void set_terrain_seen( const coord_def& c ) { + set_terrain_seen(c.x, c.y); +} +void set_terrain_changed( int x, int y ); +bool is_terrain_known( int x, int y ); +bool is_terrain_seen( int x, int y ); +bool is_terrain_changed( int x, int y ); +inline bool is_terrain_changed( const coord_def& c ) { + return is_terrain_changed(c.x,c.y); +} +bool is_terrain_known(const coord_def &p); +bool is_terrain_mapped(const coord_def &p); +bool is_notable_terrain(dungeon_feature_type ftype); + +inline bool is_terrain_seen(const coord_def &c) +{ + return (is_terrain_seen(c.x, c.y)); +} + +inline void set_terrain_changed(const coord_def &c) +{ + set_terrain_changed(c.x, c.y); +} + +int count_detected_mons(void); +void clear_map(bool clear_items = true, bool clear_mons = true); + +int get_envmap_col(const coord_def& p); + +void set_envmap_glyph(const coord_def& c, show_type object, int col); + +void clear_envmap_grid(const coord_def& p); + +#endif + diff --git a/crawl-ref/source/exclude.cc b/crawl-ref/source/exclude.cc index f9deb58f8b..1c91a673d4 100644 --- a/crawl-ref/source/exclude.cc +++ b/crawl-ref/source/exclude.cc @@ -8,6 +8,7 @@ #include "exclude.h" #include "coord.h" +#include "envmap.h" #include "mon-util.h" #include "options.h" #include "overmap.h" diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc index e15100a12e..94c765a305 100644 --- a/crawl-ref/source/fight.cc +++ b/crawl-ref/source/fight.cc @@ -27,6 +27,7 @@ #include "debug.h" #include "delay.h" #include "effects.h" +#include "envmap.h" #include "food.h" #include "goditem.h" #include "invent.h" @@ -60,6 +61,7 @@ #include "traps.h" #include "tutorial.h" #include "view.h" +#include "viewgeom.h" #include "xom.h" #ifdef NOTE_DEBUG_CHAOS_BRAND diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc index e989cac4a2..a1bfab56dc 100644 --- a/crawl-ref/source/files.cc +++ b/crawl-ref/source/files.cc @@ -79,6 +79,7 @@ #include "travel.h" #include "tutorial.h" #include "view.h" +#include "viewgeom.h" #ifdef TARGET_COMPILER_VC #include diff --git a/crawl-ref/source/format.cc b/crawl-ref/source/format.cc index c982501178..265100bd26 100644 --- a/crawl-ref/source/format.cc +++ b/crawl-ref/source/format.cc @@ -8,6 +8,7 @@ #include "colour.h" #include "format.h" #include "view.h" +#include "viewchar.h" formatted_string::formatted_string(int init_colour) : ops() diff --git a/crawl-ref/source/initfile.cc b/crawl-ref/source/initfile.cc index dc9c95b21a..85b3105c38 100644 --- a/crawl-ref/source/initfile.cc +++ b/crawl-ref/source/initfile.cc @@ -44,6 +44,7 @@ #include "travel.h" #include "items.h" #include "view.h" +#include "viewchar.h" // For finding the executable's path #ifdef TARGET_OS_WINDOWS diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc index 52ef8bbba3..50119d4f55 100644 --- a/crawl-ref/source/item_use.cc +++ b/crawl-ref/source/item_use.cc @@ -14,7 +14,6 @@ #include #include "externs.h" -#include "options.h" #include "abl-show.h" #include "artefact.h" @@ -29,6 +28,7 @@ #include "describe.h" #include "directn.h" #include "effects.h" +#include "envmap.h" #include "fight.h" #include "food.h" #include "godabil.h" @@ -48,6 +48,7 @@ #include "monplace.h" #include "monstuff.h" #include "notes.h" +#include "options.h" #include "ouch.h" #include "player.h" #include "quiver.h" @@ -70,6 +71,8 @@ #include "traps.h" #include "tutorial.h" #include "view.h" +#include "viewchar.h" +#include "viewgeom.h" #include "xom.h" static bool _drink_fountain(); diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc index 34245418e8..1a63f10c87 100644 --- a/crawl-ref/source/items.cc +++ b/crawl-ref/source/items.cc @@ -60,6 +60,7 @@ #include "terrain.h" #include "tutorial.h" #include "view.h" +#include "viewgeom.h" #include "xom.h" #define PORTAL_VAULT_ORIGIN_KEY "portal_vault_origin" diff --git a/crawl-ref/source/libgui.cc b/crawl-ref/source/libgui.cc index e00eb851e1..93102cb775 100644 --- a/crawl-ref/source/libgui.cc +++ b/crawl-ref/source/libgui.cc @@ -28,6 +28,7 @@ #include "tilesdl.h" #include "travel.h" #include "view.h" +#include "viewgeom.h" #include #include "tilesdl.h" diff --git a/crawl-ref/source/libunix.cc b/crawl-ref/source/libunix.cc index 84597617fb..1479396951 100644 --- a/crawl-ref/source/libunix.cc +++ b/crawl-ref/source/libunix.cc @@ -35,6 +35,7 @@ #include "state.h" #include "stuff.h" #include "view.h" +#include "viewgeom.h" #ifdef DGL_ENABLE_CORE_DUMP #include diff --git a/crawl-ref/source/libutil.cc b/crawl-ref/source/libutil.cc index 898e1a8b83..7a0726b134 100644 --- a/crawl-ref/source/libutil.cc +++ b/crawl-ref/source/libutil.cc @@ -6,12 +6,13 @@ #include "AppHdr.h" #include "defines.h" -#include "directn.h" #include "itemname.h" // is_vowel() #include "libutil.h" #include "externs.h" #include "macro.h" #include "stuff.h" +#include "viewgeom.h" + #include #include #include diff --git a/crawl-ref/source/los.cc b/crawl-ref/source/los.cc index 6c0eb0936a..5d93a9ef90 100644 --- a/crawl-ref/source/los.cc +++ b/crawl-ref/source/los.cc @@ -51,7 +51,6 @@ #include "coord.h" #include "coordit.h" #include "debug.h" -#include "directn.h" #include "externs.h" #include "geom2d.h" #include "losparam.h" @@ -60,6 +59,7 @@ #include "state.h" #include "stuff.h" #include "terrain.h" +#include "viewgeom.h" // This determines which cells are considered out of range during // precalculations (only positive quadrant used). diff --git a/crawl-ref/source/makefile.obj b/crawl-ref/source/makefile.obj index fff4ef0229..9ebecb6531 100644 --- a/crawl-ref/source/makefile.obj +++ b/crawl-ref/source/makefile.obj @@ -28,6 +28,7 @@ directn.o \ dlua.o \ dungeon.o \ effects.o \ +envmap.o \ exclude.o \ feature.o \ fight.o \ @@ -141,4 +142,7 @@ traps.o \ travel.o \ tutorial.o \ view.o \ +viewchar.o \ +viewgeom.o \ +viewmap.o \ xom.o diff --git a/crawl-ref/source/mapcell.h b/crawl-ref/source/mapcell.h new file mode 100644 index 0000000000..45ef60f62e --- /dev/null +++ b/crawl-ref/source/mapcell.h @@ -0,0 +1,22 @@ +#ifndef MAPCELL_H +#define MAPCELL_H + +#include "show.h" + +struct map_cell +{ + show_type object; // The object: monster, item, feature, or cloud. + unsigned short flags; // Flags describing the mappedness of this square. + unsigned short colour; + unsigned long property; // Flags for blood, sanctuary, ... + + map_cell() : object(), flags(0), colour(0), property(0) { } + void clear() { flags = colour = 0; object = show_type(); } + + unsigned glyph() const; + bool known() const; + bool seen() const; +}; + +#endif + diff --git a/crawl-ref/source/message.cc b/crawl-ref/source/message.cc index 5ee5792081..fc1c802f17 100644 --- a/crawl-ref/source/message.cc +++ b/crawl-ref/source/message.cc @@ -38,6 +38,8 @@ #include "travel.h" #include "tutorial.h" #include "view.h" +#include "viewchar.h" +#include "viewgeom.h" #include "menu.h" class message_item { diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc index cf6f450c24..4e4e1cc76f 100644 --- a/crawl-ref/source/misc.cc +++ b/crawl-ref/source/misc.cc @@ -43,6 +43,7 @@ #include "dgnevent.h" #include "directn.h" #include "dungeon.h" +#include "envmap.h" #include "fight.h" #include "files.h" #include "food.h" @@ -80,6 +81,7 @@ #include "travel.h" #include "tutorial.h" #include "view.h" +#include "viewchar.h" #include "xom.h" static void _create_monster_hide(const item_def corpse) diff --git a/crawl-ref/source/mon-abil.cc b/crawl-ref/source/mon-abil.cc index 3defd6aed2..b6e430ca40 100644 --- a/crawl-ref/source/mon-abil.cc +++ b/crawl-ref/source/mon-abil.cc @@ -18,6 +18,7 @@ #include "beam.h" #include "colour.h" #include "directn.h" +#include "envmap.h" #include "ghost.h" #include "misc.h" #include "mon-act.h" @@ -32,6 +33,7 @@ #include "state.h" #include "stuff.h" #include "view.h" +#include "viewchar.h" bool ugly_thing_mutate(monsters *ugly, bool proximity) { diff --git a/crawl-ref/source/mon-act.cc b/crawl-ref/source/mon-act.cc index daa4a50577..2ad17e09a2 100644 --- a/crawl-ref/source/mon-act.cc +++ b/crawl-ref/source/mon-act.cc @@ -16,6 +16,7 @@ #include "cloud.h" #include "delay.h" #include "directn.h" +#include "envmap.h" #include "fight.h" #include "itemname.h" #include "itemprop.h" @@ -41,6 +42,7 @@ #include "traps.h" #include "tutorial.h" #include "view.h" +#include "viewchar.h" static bool _handle_pickup(monsters *monster); static void _mons_in_cloud(monsters *monster); diff --git a/crawl-ref/source/mon-behv.cc b/crawl-ref/source/mon-behv.cc index 4335854400..d3eff47330 100644 --- a/crawl-ref/source/mon-behv.cc +++ b/crawl-ref/source/mon-behv.cc @@ -12,6 +12,7 @@ #include "coord.h" #include "coordit.h" +#include "envmap.h" #include "exclude.h" #include "los.h" #include "monplace.h" diff --git a/crawl-ref/source/mon-cast.cc b/crawl-ref/source/mon-cast.cc index e16d901f69..95c911cc93 100644 --- a/crawl-ref/source/mon-cast.cc +++ b/crawl-ref/source/mon-cast.cc @@ -15,6 +15,7 @@ #include "colour.h" #include "database.h" #include "effects.h" +#include "envmap.h" #include "fight.h" #include "ghost.h" #include "los.h" @@ -32,6 +33,7 @@ #include "spells3.h" #include "stuff.h" #include "view.h" +#include "viewchar.h" static void _scale_draconian_breath(bolt& beam, int drac_type) { diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index fdf8bac529..4c44cc83b1 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -15,6 +15,7 @@ #include "colour.h" #include "database.h" #include "directn.h" +#include "envmap.h" #include "fight.h" #include "ghost.h" #include "goditem.h" diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc index 33850d50c5..c461144c9a 100644 --- a/crawl-ref/source/monplace.cc +++ b/crawl-ref/source/monplace.cc @@ -13,6 +13,7 @@ #include "arena.h" #include "branch.h" #include "directn.h" // for the Compass +#include "envmap.h" #include "externs.h" #include "options.h" #include "ghost.h" diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc index 00181a28ba..ff2eddd821 100644 --- a/crawl-ref/source/monstuff.cc +++ b/crawl-ref/source/monstuff.cc @@ -22,6 +22,7 @@ #include "delay.h" #include "dgnevent.h" #include "directn.h" +#include "envmap.h" #include "files.h" #include "food.h" #include "godabil.h" @@ -46,6 +47,7 @@ #include "traps.h" #include "tutorial.h" #include "view.h" +#include "viewchar.h" #include "stash.h" #include "xom.h" diff --git a/crawl-ref/source/output.cc b/crawl-ref/source/output.cc index 276e14edd6..6447463859 100644 --- a/crawl-ref/source/output.cc +++ b/crawl-ref/source/output.cc @@ -51,6 +51,8 @@ #include "transfor.h" #include "travel.h" #include "view.h" +#include "viewchar.h" +#include "viewgeom.h" // Color for captions like 'Health:', 'Str:', etc. #define HUD_CAPTION_COLOUR Options.status_caption_colour diff --git a/crawl-ref/source/overmap.cc b/crawl-ref/source/overmap.cc index 55cbbd2f05..cd928e8505 100644 --- a/crawl-ref/source/overmap.cc +++ b/crawl-ref/source/overmap.cc @@ -25,6 +25,7 @@ #include "dgnevent.h" #include "directn.h" #include "dungeon.h" +#include "envmap.h" #include "feature.h" #include "files.h" #include "initfile.h" diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc index d3dd1d6829..34ca28d9f9 100644 --- a/crawl-ref/source/player.cc +++ b/crawl-ref/source/player.cc @@ -29,6 +29,7 @@ #include "delay.h" #include "dgnevent.h" #include "effects.h" +#include "envmap.h" #include "fight.h" #include "food.h" #include "godabil.h" @@ -68,6 +69,7 @@ #include "travel.h" #include "tutorial.h" #include "view.h" +#include "viewgeom.h" #include "tiles.h" #include "xom.h" diff --git a/crawl-ref/source/religion.cc b/crawl-ref/source/religion.cc index 7ac3e27811..4247dbbae3 100644 --- a/crawl-ref/source/religion.cc +++ b/crawl-ref/source/religion.cc @@ -33,6 +33,7 @@ #include "describe.h" #include "effects.h" #include "enum.h" +#include "envmap.h" #include "fight.h" #include "files.h" #include "food.h" diff --git a/crawl-ref/source/show.cc b/crawl-ref/source/show.cc index 35f2fb1a0f..b75a90a13c 100644 --- a/crawl-ref/source/show.cc +++ b/crawl-ref/source/show.cc @@ -3,6 +3,7 @@ #include "show.h" #include "cloud.h" +#include "colour.h" #include "coordit.h" #include "directn.h" #include "feature.h" @@ -12,6 +13,7 @@ #include "state.h" #include "terrain.h" #include "view.h" +#include "viewgeom.h" void get_show_symbol(show_type object, unsigned *ch, unsigned short *colour) diff --git a/crawl-ref/source/show.h b/crawl-ref/source/show.h index a6162e23fa..7ee086b520 100644 --- a/crawl-ref/source/show.h +++ b/crawl-ref/source/show.h @@ -57,19 +57,11 @@ struct show_type bool operator < (const show_type &other) const; }; -struct map_cell +struct show_info { - show_type object; // The object: monster, item, feature, or cloud. - unsigned short flags; // Flags describing the mappedness of this square. - unsigned short colour; - unsigned long property; // Flags for blood, sanctuary, ... - - map_cell() : object(), flags(0), colour(0), property(0) { } - void clear() { flags = colour = 0; object = show_type(); } - - unsigned glyph() const; - bool known() const; - bool seen() const; + dungeon_feature_type feat; + show_item_type item; + monster_type mons; }; // Replaces get_item_symbol. diff --git a/crawl-ref/source/spells1.cc b/crawl-ref/source/spells1.cc index e56b9c763a..fa95cae514 100644 --- a/crawl-ref/source/spells1.cc +++ b/crawl-ref/source/spells1.cc @@ -49,6 +49,7 @@ #include "transfor.h" #include "traps.h" #include "view.h" +#include "viewchar.h" static bool _abyss_blocks_teleport(bool cblink) { diff --git a/crawl-ref/source/spells2.cc b/crawl-ref/source/spells2.cc index 8d857c3f10..02a3cd72c3 100644 --- a/crawl-ref/source/spells2.cc +++ b/crawl-ref/source/spells2.cc @@ -24,6 +24,7 @@ #include "directn.h" #include "dungeon.h" #include "effects.h" +#include "envmap.h" #include "goditem.h" #include "invent.h" #include "itemname.h" diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc index 36d60ea032..8451322adb 100644 --- a/crawl-ref/source/spells3.cc +++ b/crawl-ref/source/spells3.cc @@ -25,6 +25,7 @@ #include "debug.h" #include "delay.h" #include "effects.h" +#include "envmap.h" #include "food.h" #include "goditem.h" #include "itemname.h" @@ -49,6 +50,7 @@ #include "traps.h" #include "travel.h" #include "view.h" +#include "viewgeom.h" #include "xom.h" bool cast_selective_amnesia(bool force) diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc index 39f1be7c52..863acda3d5 100644 --- a/crawl-ref/source/spells4.cc +++ b/crawl-ref/source/spells4.cc @@ -51,6 +51,7 @@ #include "transfor.h" #include "traps.h" #include "view.h" +#include "viewchar.h" enum DEBRIS // jmf: add for shatter, dig, and Giants to throw { diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc index 468ac4cfb1..c2cbaa6971 100644 --- a/crawl-ref/source/spl-cast.cc +++ b/crawl-ref/source/spl-cast.cc @@ -19,6 +19,7 @@ #include "coordit.h" #include "describe.h" #include "effects.h" +#include "envmap.h" #include "food.h" #include "format.h" #include "godabil.h" diff --git a/crawl-ref/source/spl-mis.cc b/crawl-ref/source/spl-mis.cc index 4b349054c6..8dd1bc14b1 100644 --- a/crawl-ref/source/spl-mis.cc +++ b/crawl-ref/source/spl-mis.cc @@ -30,6 +30,7 @@ #include "terrain.h" #include "transfor.h" #include "view.h" +#include "viewchar.h" #include "xom.h" // This determines how likely it is that more powerful wild magic diff --git a/crawl-ref/source/stash.cc b/crawl-ref/source/stash.cc index 22a021e0fc..0bc84dbb6f 100644 --- a/crawl-ref/source/stash.cc +++ b/crawl-ref/source/stash.cc @@ -40,6 +40,7 @@ #include "traps.h" #include "travel.h" #include "tutorial.h" +#include "viewgeom.h" #include #include diff --git a/crawl-ref/source/stuff.cc b/crawl-ref/source/stuff.cc index 3fefb11e7b..fa7c276f68 100644 --- a/crawl-ref/source/stuff.cc +++ b/crawl-ref/source/stuff.cc @@ -18,6 +18,8 @@ #include "state.h" #include "stuff.h" #include "view.h" +#include "viewchar.h" +#include "viewgeom.h" #include #include diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc index a05a0bd18a..8fa8ceaef9 100644 --- a/crawl-ref/source/tags.cc +++ b/crawl-ref/source/tags.cc @@ -64,6 +64,7 @@ #include "describe.h" #include "dungeon.h" #include "enum.h" +#include "envmap.h" #include "externs.h" #include "files.h" #include "ghost.h" diff --git a/crawl-ref/source/teleport.cc b/crawl-ref/source/teleport.cc index 5db62261b2..c2c1829d4a 100644 --- a/crawl-ref/source/teleport.cc +++ b/crawl-ref/source/teleport.cc @@ -9,6 +9,7 @@ #include "cloud.h" #include "coord.h" +#include "envmap.h" #include "los.h" #include "player.h" #include "random.h" diff --git a/crawl-ref/source/terrain.cc b/crawl-ref/source/terrain.cc index 47b66af04a..92d4c750f7 100644 --- a/crawl-ref/source/terrain.cc +++ b/crawl-ref/source/terrain.cc @@ -15,6 +15,7 @@ #include "cloud.h" #include "dgnevent.h" #include "directn.h" +#include "envmap.h" #include "godabil.h" #include "itemprop.h" #include "items.h" diff --git a/crawl-ref/source/tilepick.cc b/crawl-ref/source/tilepick.cc index 8b696a0ae5..d356481fa7 100644 --- a/crawl-ref/source/tilepick.cc +++ b/crawl-ref/source/tilepick.cc @@ -13,6 +13,7 @@ #include "coord.h" #include "coordit.h" #include "directn.h" +#include "envmap.h" #include "externs.h" #include "options.h" #include "food.h" @@ -39,6 +40,7 @@ #include "traps.h" #include "travel.h" #include "view.h" +#include "viewgeom.h" void TileNewLevel(bool first_time) { diff --git a/crawl-ref/source/tilereg.cc b/crawl-ref/source/tilereg.cc index 4d988e4dc5..903187da19 100644 --- a/crawl-ref/source/tilereg.cc +++ b/crawl-ref/source/tilereg.cc @@ -11,6 +11,7 @@ #include "cio.h" #include "coord.h" +#include "envmap.h" #include "debug.h" #include "describe.h" #include "files.h" @@ -40,6 +41,7 @@ #include "transfor.h" #include "travel.h" #include "view.h" +#include "viewgeom.h" #include "tilereg.h" #include "tiles.h" diff --git a/crawl-ref/source/tilesdl.cc b/crawl-ref/source/tilesdl.cc index 59dae41a82..ce00292b20 100644 --- a/crawl-ref/source/tilesdl.cc +++ b/crawl-ref/source/tilesdl.cc @@ -5,6 +5,7 @@ #include "artefact.h" #include "cio.h" #include "coord.h" +#include "envmap.h" #include "itemname.h" #include "items.h" #include "itemprop.h" @@ -22,6 +23,7 @@ #include "tilesdl.h" #include "travel.h" #include "view.h" +#include "viewgeom.h" #include "tiledef-dngn.h" #include "tilefont.h" diff --git a/crawl-ref/source/traps.cc b/crawl-ref/source/traps.cc index 362859a06b..40ad762116 100644 --- a/crawl-ref/source/traps.cc +++ b/crawl-ref/source/traps.cc @@ -18,6 +18,7 @@ #include "delay.h" #include "describe.h" #include "directn.h" +#include "envmap.h" #include "itemname.h" #include "itemprop.h" #include "items.h" diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc index f7fd190d05..62f9b9ba46 100644 --- a/crawl-ref/source/travel.cc +++ b/crawl-ref/source/travel.cc @@ -22,6 +22,7 @@ #include "describe.h" #include "dgnevent.h" #include "directn.h" +#include "envmap.h" #include "exclude.h" #include "itemname.h" #include "itemprop.h" diff --git a/crawl-ref/source/tutorial.cc b/crawl-ref/source/tutorial.cc index 2965d15190..d011841572 100644 --- a/crawl-ref/source/tutorial.cc +++ b/crawl-ref/source/tutorial.cc @@ -56,6 +56,8 @@ #include "tiles.h" #endif #include "view.h" +#include "viewchar.h" +#include "viewgeom.h" static species_type _get_tutorial_species(unsigned int type); static job_type _get_tutorial_job(unsigned int type); diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc index 2a64183fda..1ac2a47d78 100644 --- a/crawl-ref/source/view.cc +++ b/crawl-ref/source/view.cc @@ -20,7 +20,11 @@ #endif #include "externs.h" -#include "options.h" + +#include "envmap.h" +#include "viewchar.h" +#include "viewgeom.h" +#include "viewmap.h" #include "branch.h" #include "command.h" @@ -51,6 +55,7 @@ #include "monstuff.h" #include "mon-util.h" #include "newgame.h" +#include "options.h" #include "jobs.h" #include "notes.h" #include "output.h" @@ -75,50 +80,14 @@ #define DEBUG_PANE_BOUNDS 0 -// 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 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 MC_ITEM 0x01 -#define MC_MONS 0x02 - crawl_view_geometry crawl_view; extern int stealth; // defined in acr.cc -screen_buffer_t colour_code_map( const coord_def& p, bool item_colour = false, - bool travel_colour = false, bool on_level = true ); - static void _get_symbol( const coord_def& where, show_type object, unsigned *ch, unsigned short *colour, bool magic_mapped = false ); -static unsigned _get_symbol(show_type object, unsigned short *colour = NULL, - bool magic_mapped = false); - -static int _get_viewobj_flags(show_type viewobj); - -unsigned map_cell::glyph() const -{ - if (!object) - return (' '); - return _get_symbol(object, NULL, !(flags & MAP_SEEN_FLAG)); -} - -bool map_cell::known() const -{ - return (object && (flags & MAP_GRID_KNOWN)); -} - -bool map_cell::seen() const -{ - return (object && (flags & MAP_SEEN_FLAG)); -} bool inside_level_bounds(int x, int y) { @@ -130,298 +99,19 @@ bool inside_level_bounds(const coord_def &p) return (inside_level_bounds(p.x, p.y)); } -unsigned get_envmap_char(int x, int y) -{ - return env.map[x][y].glyph(); -} - -show_type get_envmap_obj(int x, int y) -{ - return (env.map[x][y].object); -} - -void set_envmap_detected_item(int x, int y, bool detected) -{ - if (detected) - env.map[x][y].flags |= MAP_DETECTED_ITEM; - else - env.map[x][y].flags &= ~MAP_DETECTED_ITEM; -} - -bool is_envmap_detected_item(int x, int y) -{ - return (env.map[x][y].flags & MAP_DETECTED_ITEM); -} - -void set_envmap_detected_mons(int x, int y, bool detected) -{ - if (detected) - env.map[x][y].flags |= MAP_DETECTED_MONSTER; - else - env.map[x][y].flags &= ~MAP_DETECTED_MONSTER; -} - -bool is_envmap_detected_mons(int x, int y) -{ - return (env.map[x][y].flags & MAP_DETECTED_MONSTER); -} - -void set_envmap_glyph(int x, int y, show_type object, int col) -{ - map_cell &c = env.map[x][y]; - c.object = object; - c.colour = col; -#ifdef USE_TILE - tiles.update_minimap(x, y); -#endif -} - -void set_envmap_glyph(const coord_def& c, show_type object, int col) -{ - set_envmap_glyph(c.x, c.y, object, col); -} - -void set_envmap_obj(const coord_def& where, show_type obj) -{ - env.map(where).object = obj; -#ifdef USE_TILE - tiles.update_minimap(where.x, where.y); -#endif -} - -void set_envmap_col( int x, int y, int colour ) -{ - env.map[x][y].colour = colour; -} - -bool is_sanctuary(const coord_def& p) -{ - if (!map_bounds(p)) - return (false); - return (testbits(env.map(p).property, FPROP_SANCTUARY_1) - || testbits(env.map(p).property, FPROP_SANCTUARY_2)); -} - -bool is_bloodcovered(const coord_def& p) -{ - return (testbits(env.map(p).property, FPROP_BLOODY)); -} - -bool is_envmap_item(int x, int y) -{ - return (_get_viewobj_flags(env.map[x][y].object) & MC_ITEM); -} - -bool is_envmap_mons(int x, int y) -{ - return (_get_viewobj_flags(env.map[x][y].object) & MC_MONS); -} - -int get_envmap_col(const coord_def& p) -{ - return (env.map[p.x][p.y].colour); -} - -bool is_terrain_known( int x, int y ) -{ - return (env.map[x][y].known()); -} - -bool is_terrain_known(const coord_def &p) -{ - return (env.map(p).known()); -} - -bool is_terrain_seen( int x, int y ) -{ - return (env.map[x][y].flags & MAP_SEEN_FLAG); -} - -bool is_terrain_changed( int x, int y ) -{ - return (env.map[x][y].flags & MAP_CHANGED_FLAG); -} - -bool is_terrain_mapped(const coord_def &p) -{ - return (env.map(p).flags & MAP_MAGIC_MAPPED_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][y].flags |= MAP_CHANGED_FLAG; - - dungeon_events.fire_position_event(DET_FEAT_CHANGE, coord_def(x, y)); -} - -void set_terrain_mapped( int x, int y ) -{ - env.map[x][y].flags &= (~MAP_CHANGED_FLAG); - env.map[x][y].flags |= MAP_MAGIC_MAPPED_FLAG; -#ifdef USE_TILE - tiles.update_minimap(x, y); -#endif -} - -static void _automap_from( int x, int y, int mutated ) -{ - if (mutated) - magic_mapping(8 * mutated, 25, true, false, - true, true, coord_def(x,y)); -} - -void reautomap_level( ) -{ - int passive = player_mutation_level(MUT_PASSIVE_MAPPING); - - for (int x = X_BOUND_1; x <= X_BOUND_2; ++x) - for (int y = Y_BOUND_1; y <= Y_BOUND_2; ++y) - if (env.map[x][y].flags & MAP_SEEN_FLAG) - _automap_from(x, y, passive); -} - -void set_terrain_seen( int x, int y ) -{ - const dungeon_feature_type feat = grd[x][y]; - - // First time we've seen a notable feature. - if (!(env.map[x][y].flags & MAP_SEEN_FLAG)) - { - _automap_from(x, y, player_mutation_level(MUT_PASSIVE_MAPPING)); - - const bool boring = !is_notable_terrain(feat) - // A portal deeper into the Zigguart is boring. - || (feat == DNGN_ENTER_PORTAL_VAULT - && you.level_type == LEVEL_PORTAL_VAULT) - // Altars in the temple are boring. - || (feat_is_altar(feat) - && player_in_branch(BRANCH_ECUMENICAL_TEMPLE)) - // Only note the first entrance to the Abyss/Pan/Hell - // which is found. - || ((feat == DNGN_ENTER_ABYSS || feat == DNGN_ENTER_PANDEMONIUM - || feat == DNGN_ENTER_HELL) - && overmap_knows_num_portals(feat) > 1) - // There are at least three Zot entrances, and they're always - // on D:27, so ignore them. - || feat == DNGN_ENTER_ZOT; - - if (!boring) - { - coord_def pos(x, y); - std::string desc = - feature_description(pos, false, DESC_NOCAP_A); - - take_note(Note(NOTE_SEEN_FEAT, 0, 0, desc.c_str())); - } - } - -#ifdef USE_TILE - env.map[x][y].flags &= ~(MAP_DETECTED_ITEM); - env.map[x][y].flags &= ~(MAP_DETECTED_MONSTER); -#endif - - env.map[x][y].flags &= (~MAP_CHANGED_FLAG); - env.map[x][y].flags |= MAP_SEEN_FLAG; -} - -void clear_envmap_grid( const coord_def& p ) -{ - env.map(p).clear(); -} - -void clear_envmap_grid( int x, int y ) -{ - env.map[x][y].clear(); -} - bool is_notable_terrain(dungeon_feature_type ftype) { return (get_feature_def(ftype).is_notable()); } -#if defined(TARGET_OS_WINDOWS) || defined(TARGET_OS_DOS) || defined(USE_TILE) -static unsigned _colflag2brand(int colflag) -{ - switch (colflag) - { - case COLFLAG_ITEM_HEAP: - return (Options.heap_brand); - case COLFLAG_FRIENDLY_MONSTER: - return (Options.friend_brand); - case COLFLAG_NEUTRAL_MONSTER: - return (Options.neutral_brand); - case COLFLAG_WILLSTAB: - return (Options.stab_brand); - case COLFLAG_MAYSTAB: - return (Options.may_stab_brand); - case COLFLAG_FEATURE_ITEM: - return (Options.feature_item_brand); - case COLFLAG_TRAP_ITEM: - return (Options.trap_item_brand); - default: - return (CHATTR_NORMAL); - } -} -#endif - -unsigned real_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. - const int colflags = raw_colour & 0xFF00; - - // Evaluate any elemental colours to guarantee vanilla colour is returned - if (is_element_colour( raw_colour )) - raw_colour = colflags | element_colour( raw_colour ); - -#if defined(TARGET_OS_WINDOWS) || defined(TARGET_OS_DOS) || defined(USE_TILE) - if (colflags) - { - unsigned brand = _colflag2brand(colflags); - raw_colour = dos_brand(raw_colour & 0xFF, brand); - } -#endif - -#ifndef USE_COLOUR_OPTS - // Strip COLFLAGs for systems that can't do anything meaningful with them. - raw_colour &= 0xFF; -#endif - - return (raw_colour); -} - -static int _get_viewobj_flags(show_type object) -{ - // Check for monster glyphs. - if (object.cls == SH_MONSTER) - return (MC_MONS); - - // Check for item glyphs. - if (object.cls == SH_ITEM) - return (MC_ITEM); - - // We don't care to look further; we could check for - // clouds here as well. - return (0); -} - -static unsigned _get_symbol(show_type object, unsigned short *colour, - bool magic_mapped) +unsigned get_symbol(show_type object, unsigned short *colour, + bool magic_mapped) { unsigned ch; _get_symbol(coord_def(0,0), object, &ch, NULL, magic_mapped); return (ch); } -static bool _emphasise(const coord_def& where, dungeon_feature_type feat) -{ - return (is_unknown_stair(where, feat) - && (you.your_level || feat_stair_direction(feat) == CMD_GO_DOWNSTAIRS) - && you.where_are_you != BRANCH_VESTIBULE_OF_HELL); -} - static bool _show_bloodcovered(const coord_def& where) { if (!is_bloodcovered(where)) @@ -521,7 +211,7 @@ static void _get_symbol( const coord_def& where, *colour = _tree_colour(where) | colmask; if (fdef.em_colour && fdef.em_colour != fdef.colour && - _emphasise(where, feat)) + emphasise(where, feat)) { *colour = (fdef.em_colour | colmask); } @@ -574,349 +264,73 @@ dungeon_char_type get_feature_dchar(dungeon_feature_type feat) return (get_feature_def(feat).dchar); } -unsigned get_sightmap_char(dungeon_feature_type feat) -{ - return (get_feature_def(feat).symbol); -} - -unsigned get_magicmap_char(dungeon_feature_type feat) -{ - return (get_feature_def(feat).magic_symbol); -} - -static char _get_travel_colour( const coord_def& p ) +int get_mons_colour(const monsters *mons) { - if (is_waypoint(p)) - return LIGHTGREEN; - - short dist = travel_point_distance[p.x][p.y]; - 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; -} + int col = mons->colour; -#if defined(TARGET_OS_WINDOWS) || defined(TARGET_OS_DOS) || defined(USE_TILE) -static unsigned short _dos_reverse_brand(unsigned short colour) -{ - if (Options.dos_use_background_intensity) - { - // If the console treats the intensity bit on background colours - // correctly, we can do a very simple colour invert. + if (mons->has_ench(ENCH_BERSERK)) + col = RED; - // Special casery for shadows. - if (colour == BLACK) - colour = (DARKGREY << 4); - else - colour = (colour & 0xF) << 4; - } - else + if (mons_friendly_real(mons)) { - // If we're on a console that takes its DOSness very seriously the - // background high-intensity bit is actually a blink bit. Blinking is - // evil, so we strip the background high-intensity bit. This, sadly, - // limits us to 7 background colours. - - // Strip off high-intensity bit. Special case DARKGREY, since it's the - // high-intensity counterpart of black, and we don't want black on - // black. - // - // We *could* set the foreground colour to WHITE if the background - // intensity bit is set, but I think we've carried the - // angry-fruit-salad theme far enough already. - - if (colour == DARKGREY) - colour |= (LIGHTGREY << 4); - else if (colour == BLACK) - colour = LIGHTGREY << 4; - else - { - // Zap out any existing background colour, and the high - // intensity bit. - colour &= 7; - - // And swap the foreground colour over to the background - // colour, leaving the foreground black. - colour <<= 4; - } + col |= COLFLAG_FRIENDLY_MONSTER; } - - return (colour); -} - -static unsigned short _dos_hilite_brand(unsigned short colour, - unsigned short hilite) -{ - if (!hilite) - return (colour); - - if (colour == hilite) - colour = 0; - - colour |= (hilite << 4); - return (colour); -} - -unsigned short dos_brand( unsigned short colour, - unsigned brand) -{ - if ((brand & CHATTR_ATTRMASK) == CHATTR_NORMAL) - return (colour); - - colour &= 0xFF; - - if ((brand & CHATTR_ATTRMASK) == CHATTR_HILITE) - return _dos_hilite_brand(colour, (brand & CHATTR_COLMASK) >> 8); - else - return _dos_reverse_brand(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(const coord_def& p, bool item_colour, - bool travel_colour, bool on_level) -{ - const unsigned short map_flags = env.map(p).flags; - if (!(map_flags & MAP_GRID_KNOWN)) - return (BLACK); - -#ifdef WIZARD - if (travel_colour && you.wizard - && testbits(env.map(p).property, FPROP_HIGHLIGHT)) + else if (mons_neutral(mons)) { - return (LIGHTGREEN); + col |= COLFLAG_NEUTRAL_MONSTER; } -#endif - - dungeon_feature_type feat_value = grd(p); - if (!see_cell(p)) + else if (Options.stab_brand != CHATTR_NORMAL + && mons_looks_stabbable(mons)) { - const show_type remembered = get_envmap_obj(p); - if (remembered.cls == SH_FEATURE) - feat_value = remembered.feat; + col |= COLFLAG_WILLSTAB; } - - unsigned tc = travel_colour ? _get_travel_colour(p) : DARKGREY; - - if (map_flags & MAP_DETECTED_ITEM) - return real_colour(Options.detected_item_colour); - - if (map_flags & MAP_DETECTED_MONSTER) + else if (Options.may_stab_brand != CHATTR_NORMAL + && mons_looks_distracted(mons)) { - tc = Options.detected_monster_colour; - return real_colour(tc); + col |= COLFLAG_MAYSTAB; } - - // If this is an important travel square, don't allow the colour - // to be overridden. - if (is_waypoint(p) || travel_point_distance[p.x][p.y] == PD_EXCLUDED) - return real_colour(tc); - - if (item_colour && is_envmap_item(p)) - return get_envmap_col(p); - - int feature_colour = DARKGREY; - const bool terrain_seen = is_terrain_seen(p); - const feature_def &fdef = get_feature_def(feat_value); - feature_colour = terrain_seen ? fdef.seen_colour : fdef.map_colour; - - if (terrain_seen && fdef.seen_em_colour && _emphasise(p, feat_value)) - feature_colour = fdef.seen_em_colour; - - if (feature_colour != DARKGREY) - tc = feature_colour; - else if (you.duration[DUR_MESMERISED] && on_level) + else if (mons_is_stationary(mons)) { - // If mesmerised, colour the few grids that can be reached anyway - // lightgrey. - const monsters *blocker = monster_at(p); - const bool seen_blocker = blocker && you.can_see(blocker); - if (grd(p) >= DNGN_MINMOVE && !seen_blocker) + if (Options.feature_item_brand != CHATTR_NORMAL + && is_critical_feature(grd(mons->pos())) + && feat_stair_direction(grd(mons->pos())) != CMD_NO_CMD) { - bool blocked_movement = false; - for (unsigned int i = 0; i < you.mesmerised_by.size(); i++) - { - const monsters& mon = menv[you.mesmerised_by[i]]; - const int olddist = grid_distance(you.pos(), mon.pos()); - const int newdist = grid_distance(p, mon.pos()); - - if (olddist < newdist || !see_cell(env.show_los, p, mon.pos())) - { - blocked_movement = true; - break; - } - } - if (!blocked_movement) - tc = LIGHTGREY; + col |= COLFLAG_FEATURE_ITEM; + } + else if (Options.heap_brand != CHATTR_NORMAL + && igrd(mons->pos()) != NON_ITEM + && !crawl_state.arena) + { + col |= COLFLAG_ITEM_HEAP; } } - if (Options.feature_item_brand - && is_critical_feature(feat_value) - && igrd(p) != NON_ITEM) - { - tc |= COLFLAG_FEATURE_ITEM; - } - else if (Options.trap_item_brand - && feat_is_trap(feat_value) && igrd(p) != NON_ITEM) + // Backlit monsters are fuzzy and override brands. + if (!you.can_see_invisible() && mons->has_ench(ENCH_INVIS) + && mons->backlit()) { - // FIXME: this uses the real igrd, which the player shouldn't - // be aware of. - tc |= COLFLAG_TRAP_ITEM; + col = DARKGREY; } - return real_colour(tc); + return (col); } -int count_detected_mons() +static void _good_god_follower_attitude_change(monsters *monster) { - int count = 0; - for (rectangle_iterator ri(BOUNDARY_BORDER - 1); ri; ++ri) - { - // 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(*ri)) - continue; - - if (is_envmap_detected_mons(*ri)) - count++; - } - - return (count); -} + if (you.is_unholy() || crawl_state.arena) + return; -void clear_map(bool clear_detected_items, bool clear_detected_monsters) -{ - for (rectangle_iterator ri(BOUNDARY_BORDER - 1); ri; ++ri) + // For followers of good gods, decide whether holy beings will be + // good neutral towards you. + if (is_good_god(you.religion) + && monster->foe == MHITYOU + && mons_is_holy(monster) + && !testbits(monster->flags, MF_ATT_CHANGE_ATTEMPT) + && !mons_wont_attack(monster) + && you.visible_to(monster) && !monster->asleep() + && !mons_is_confused(monster) && !mons_is_paralysed(monster)) { - const coord_def p = *ri; - // 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). - - // This reasoning doesn't make sense when it comes to *clearing* - // the map! (jpeg) - - if (get_envmap_char(p) == 0) - continue; - - if (is_envmap_item(p)) - continue; - - if (!clear_detected_items && is_envmap_detected_item(p)) - continue; - - if (!clear_detected_monsters && is_envmap_detected_mons(p)) - continue; - -#ifdef USE_TILE - if (is_terrain_mapped(p) && !is_envmap_detected_mons(p)) - continue; -#endif - - set_envmap_obj(p, show_type(is_terrain_seen(p) || is_terrain_mapped(p) - ? grd(p) : DNGN_UNSEEN)); - set_envmap_detected_mons(p, false); - set_envmap_detected_item(p, false); - -#ifdef USE_TILE - if (is_terrain_mapped(p)) - { - dungeon_feature_type feature = grd(p); - - unsigned int feat_symbol; - unsigned short feat_colour; - get_show_symbol(show_type(feature), &feat_symbol, &feat_colour); - - unsigned int fg; - unsigned int bg; - tileidx_unseen(fg, bg, feat_symbol, p); - env.tile_bk_bg(p) = bg; - env.tile_bk_fg(p) = fg; - } - else - { - env.tile_bk_bg(p) = is_terrain_seen(p) ? - tile_idx_unseen_terrain(p.x, p.y, grd(p)) : - tileidx_feature(DNGN_UNSEEN, p.x, p.y); - env.tile_bk_fg(p) = 0; - } -#endif - } -} - -int get_mons_colour(const monsters *mons) -{ - int col = mons->colour; - - if (mons->has_ench(ENCH_BERSERK)) - col = RED; - - if (mons_friendly_real(mons)) - { - col |= COLFLAG_FRIENDLY_MONSTER; - } - else if (mons_neutral(mons)) - { - col |= COLFLAG_NEUTRAL_MONSTER; - } - else if (Options.stab_brand != CHATTR_NORMAL - && mons_looks_stabbable(mons)) - { - col |= COLFLAG_WILLSTAB; - } - else if (Options.may_stab_brand != CHATTR_NORMAL - && mons_looks_distracted(mons)) - { - col |= COLFLAG_MAYSTAB; - } - else if (mons_is_stationary(mons)) - { - if (Options.feature_item_brand != CHATTR_NORMAL - && is_critical_feature(grd(mons->pos())) - && feat_stair_direction(grd(mons->pos())) != CMD_NO_CMD) - { - col |= COLFLAG_FEATURE_ITEM; - } - else if (Options.heap_brand != CHATTR_NORMAL - && igrd(mons->pos()) != NON_ITEM - && !crawl_state.arena) - { - col |= COLFLAG_ITEM_HEAP; - } - } - - // Backlit monsters are fuzzy and override brands. - if (!you.can_see_invisible() && mons->has_ench(ENCH_INVIS) - && mons->backlit()) - { - col = DARKGREY; - } - - return (col); -} - -static void _good_god_follower_attitude_change(monsters *monster) -{ - if (you.is_unholy() || crawl_state.arena) - return; - - // For followers of good gods, decide whether holy beings will be - // good neutral towards you. - if (is_good_god(you.religion) - && monster->foe == MHITYOU - && mons_is_holy(monster) - && !testbits(monster->flags, MF_ATT_CHANGE_ATTEMPT) - && !mons_wont_attack(monster) - && you.visible_to(monster) && !monster->asleep() - && !mons_is_confused(monster) && !mons_is_paralysed(monster)) - { - monster->flags |= MF_ATT_CHANGE_ATTEMPT; + monster->flags |= MF_ATT_CHANGE_ATTEMPT; if (x_chance_in_y(you.piety, MAX_PIETY) && !you.penance[you.religion]) { @@ -1492,6 +906,26 @@ void get_mons_glyph(const monsters *mons, unsigned *glych, _get_symbol(coord_def(0,0), show_type(mons), glych, glycol); } +unsigned get_screen_glyph( int x, int y ) +{ + return get_screen_glyph(coord_def(x,y)); +} + +unsigned get_screen_glyph(const coord_def& p) +{ + const coord_def ep = view2show(grid2view(p)); + + show_type object = env.show(ep); + unsigned short colour = object.colour; + unsigned ch; + + if (!object) + return get_envmap_char(p.x, p.y); + + _get_symbol(p, object, &ch, &colour); + return (ch); +} + // Noisy now has a messenging service for giving messages to the // player is appropriate. // @@ -1607,1131 +1041,100 @@ void blood_smell( int strength, const coord_def& where ) { int vamp_range = vamp_strength * vamp_strength; - const int player_distance = distance( you.pos(), where ); - - if (player_distance <= vamp_range) - { -#ifdef DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, - "Player smells blood, pos: (%d, %d), dist = %d)", - you.pos().x, you.pos().y, player_distance); -#endif - you.check_awaken(range - player_distance); - // Don't message if you can see the square. - if (!see_cell(where)) - { - mprf("You smell fresh blood%s.", - _player_vampire_smells_blood(player_distance)); - } - } - } - } - - for (int p = 0; p < MAX_MONSTERS; p++) - { - monster = &menv[p]; - - if (monster->type < 0) - continue; - - if (!mons_class_flag(monster->type, M_BLOOD_SCENT)) - continue; - - if (distance(monster->pos(), where) <= range) - { - // Let sleeping hounds lie. - if (monster->asleep() - && mons_species(monster->type) != MONS_VAMPIRE - && monster->type != MONS_SHARK) - { - // 33% chance of sleeping on - // 33% of being disturbed (start BEH_WANDER) - // 33% of being alerted (start BEH_SEEK) - if (!one_chance_in(3)) - { - if (coinflip()) - { -#ifdef DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, "disturbing %s (%d, %d)", - monster->name(DESC_PLAIN).c_str(), - monster->pos().x, monster->pos().y); -#endif - behaviour_event(monster, ME_DISTURB, MHITNOT, where); - } - continue; - } - } -#ifdef DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, "alerting %s (%d, %d)", - monster->name(DESC_PLAIN).c_str(), - monster->pos().x, monster->pos().y); -#endif - behaviour_event( monster, ME_ALERT, MHITNOT, where ); - - if (monster->type == MONS_SHARK) - { - // Sharks go into a battle frenzy if they smell blood. - monster_pathfind mp; - if (mp.init_pathfind(monster, where)) - { - mon_enchant ench = monster->get_ench(ENCH_BATTLE_FRENZY); - const int dist = 15 - (monster->pos() - where).rdist(); - const int dur = random_range(dist, dist*2) - * speed_to_duration(monster->speed); - - if (ench.ench != ENCH_NONE) - { - int level = ench.degree; - if (level < 4 && one_chance_in(2*level)) - ench.degree++; - ench.duration = std::max(ench.duration, dur); - monster->update_ench(ench); - } - else - { - monster->add_ench(mon_enchant(ENCH_BATTLE_FRENZY, 1, - KC_OTHER, dur)); - simple_monster_message(monster, " is consumed with " - "blood-lust!"); - } - } - } - } - } -} - - -// Determines if the given feature is present at (x, y) in _feat_ coordinates. -// If you have map coords, add (1, 1) to get grid coords. -// Use one of -// 1. '<' and '>' to look for stairs -// 2. '\t' or '\\' for shops, portals. -// 3. '^' for traps -// 4. '_' for altars -// 5. Anything else will look for the exact same character in the level map. -bool is_feature(int feature, const coord_def& where) -{ - if (!env.map(where).object && !see_cell(where)) - return (false); - - dungeon_feature_type grid = grd(where); - - switch (feature) - { - case 'E': - return (travel_point_distance[where.x][where.y] == PD_EXCLUDED); - case 'F': - case 'W': - return is_waypoint(where); - case 'I': - return is_stash(where.x, where.y); - case '_': - switch (grid) - { - 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: - case DNGN_ALTAR_LUGONU: - case DNGN_ALTAR_BEOGH: - case DNGN_ALTAR_JIYVA: - case DNGN_ALTAR_FEAWN: - case DNGN_ALTAR_CHEIBRIADOS: - return (true); - default: - return (false); - } - case '\t': - case '\\': - switch (grid) - { - case DNGN_ENTER_HELL: - case DNGN_EXIT_HELL: - case DNGN_ENTER_LABYRINTH: - case DNGN_ENTER_PORTAL_VAULT: - case DNGN_EXIT_PORTAL_VAULT: - 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_ENTER_PANDEMONIUM: - case DNGN_EXIT_PANDEMONIUM: - case DNGN_TRANSIT_PANDEMONIUM: - case DNGN_ENTER_ZOT: - case DNGN_RETURN_FROM_ZOT: - return (true); - default: - return (false); - } - case '<': - switch (grid) - { - case DNGN_ESCAPE_HATCH_UP: - case DNGN_STONE_STAIRS_UP_I: - case DNGN_STONE_STAIRS_UP_II: - case DNGN_STONE_STAIRS_UP_III: - 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_FROM_SHOALS: - case DNGN_EXIT_PORTAL_VAULT: - return (true); - default: - return (false); - } - case '>': - switch (grid) - { - case DNGN_ESCAPE_HATCH_DOWN: - case DNGN_STONE_STAIRS_DOWN_I: - case DNGN_STONE_STAIRS_DOWN_II: - case DNGN_STONE_STAIRS_DOWN_III: - 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_SHOALS: - return (true); - default: - return (false); - } - case '^': - switch (grid) - { - case DNGN_TRAP_MECHANICAL: - case DNGN_TRAP_MAGICAL: - case DNGN_TRAP_NATURAL: - return (true); - default: - return (false); - } - default: - return get_envmap_char(where.x, where.y) == (unsigned) feature; - } -} - -static bool _is_feature_fudged(int feature, const coord_def& where) -{ - if (!env.map(where).object) - return (false); - - if (is_feature(feature, where)) - return (true); - - // 'grid' can fit in an unsigned char, but making this a short shuts up - // warnings about out-of-range case values. - short grid = grd(where); - - if (feature == '<') - { - switch (grid) - { - case DNGN_EXIT_HELL: - case DNGN_EXIT_PORTAL_VAULT: - case DNGN_EXIT_ABYSS: - case DNGN_EXIT_PANDEMONIUM: - case DNGN_RETURN_FROM_ZOT: - return (true); - default: - return (false); - } - } - else if (feature == '>') - { - switch (grid) - { - case DNGN_ENTER_DIS: - case DNGN_ENTER_GEHENNA: - case DNGN_ENTER_COCYTUS: - case DNGN_ENTER_TARTARUS: - case DNGN_TRANSIT_PANDEMONIUM: - case DNGN_ENTER_ZOT: - return (true); - default: - return (false); - } - } - - return (false); -} - -static int _find_feature(int feature, int curs_x, int curs_y, - int start_x, int start_y, int anchor_x, int anchor_y, - int ignore_count, int *move_x, int *move_y) -{ - int cx = anchor_x, - cy = anchor_y; - - int firstx = -1, firsty = -1; - int matchcount = 0; - - // Find the first occurrence of feature 'feature', spiralling around (x,y) - int maxradius = GXM > GYM ? GXM : GYM; - for (int radius = 1; radius < maxradius; ++radius) - for (int axis = -2; axis < 2; ++axis) - { - int rad = radius - (axis < 0); - for (int var = -rad; var <= rad; ++var) - { - int dx = radius, dy = var; - if (axis % 2) - dx = -dx; - if (axis < 0) - { - int temp = dx; - dx = dy; - dy = temp; - } - - int x = cx + dx, y = cy + dy; - if (!in_bounds(x, y)) - continue; - if (_is_feature_fudged(feature, coord_def(x, y))) - { - ++matchcount; - if (!ignore_count--) - { - // We want to cursor to (x,y) - *move_x = x - (start_x + curs_x - 1); - *move_y = y - (start_y + curs_y - 1); - return matchcount; - } - else if (firstx == -1) - { - firstx = x; - firsty = y; - } - } - } - } - - // We found something, but ignored it because of an ignorecount - if (firstx != -1) - { - *move_x = firstx - (start_x + curs_x - 1); - *move_y = firsty - (start_y + curs_y - 1); - return 1; - } - return 0; -} - -void find_features(const std::vector& features, - unsigned char feature, std::vector *found) -{ - for (unsigned feat = 0; feat < features.size(); ++feat) - { - const coord_def& coord = features[feat]; - if (is_feature(feature, coord)) - found->push_back(coord); - } -} - -static int _find_feature( const std::vector& features, - int feature, int curs_x, int curs_y, - int start_x, int start_y, - int ignore_count, - int *move_x, int *move_y, - bool forward) -{ - int firstx = -1, firsty = -1, firstmatch = -1; - int matchcount = 0; - - for (unsigned feat = 0; feat < features.size(); ++feat) - { - const coord_def& coord = features[feat]; - - if (_is_feature_fudged(feature, coord)) - { - ++matchcount; - if (forward? !ignore_count-- : --ignore_count == 1) - { - // We want to cursor to (x,y) - *move_x = coord.x - (start_x + curs_x - 1); - *move_y = coord.y - (start_y + curs_y - 1); - return matchcount; - } - else if (!forward || firstx == -1) - { - firstx = coord.x; - firsty = coord.y; - firstmatch = matchcount; - } - } - } - - // We found something, but ignored it because of an ignorecount - if (firstx != -1) - { - *move_x = firstx - (start_x + curs_x - 1); - *move_y = firsty - (start_y + curs_y - 1); - return firstmatch; - } - return 0; -} - -static int _get_number_of_lines_levelmap() -{ - return get_number_of_lines() - (Options.level_map_title ? 1 : 0); -} - -#ifndef USE_TILE -static std::string _level_description_string() -{ - if (you.level_type == LEVEL_PANDEMONIUM) - return "- Pandemonium"; - - if (you.level_type == LEVEL_ABYSS) - return "- The Abyss"; - - if (you.level_type == LEVEL_LABYRINTH) - return "- a Labyrinth"; - - if (you.level_type == LEVEL_PORTAL_VAULT) - { - if (!you.level_type_name.empty()) - return "- " + article_a(upcase_first(you.level_type_name)); - return "- a Portal Chamber"; - } - - // level_type == LEVEL_DUNGEON - char buf[200]; - const int youbranch = you.where_are_you; - if ( branches[youbranch].depth == 1 ) - snprintf(buf, sizeof buf, "- %s", branches[youbranch].longname); - else - { - const int curr_subdungeon_level = player_branch_depth(); - snprintf(buf, sizeof buf, "%d of %s", curr_subdungeon_level, - branches[youbranch].longname); - } - return buf; -} - -static void _draw_level_map(int start_x, int start_y, bool travel_mode, - bool on_level) -{ - int bufcount2 = 0; - screen_buffer_t buffer2[GYM * GXM * 2]; - - const int num_lines = std::min(_get_number_of_lines_levelmap(), GYM); - const int num_cols = std::min(get_number_of_cols(), GXM); - - cursor_control cs(false); - - int top = 1 + Options.level_map_title; - if (Options.level_map_title) - { - const formatted_string help = - formatted_string::parse_string("(Press ? for help)"); - const int helplen = std::string(help).length(); - - cgotoxy(1, 1); - textcolor(WHITE); - cprintf("%-*s", - get_number_of_cols() - helplen, - ("Level " + _level_description_string()).c_str()); - - textcolor(LIGHTGREY); - cgotoxy(get_number_of_cols() - helplen + 1, 1); - help.display(); - } - - cgotoxy(1, top); - - for (int screen_y = 0; screen_y < num_lines; screen_y++) - for (int screen_x = 0; screen_x < num_cols; screen_x++) - { - screen_buffer_t colour = DARKGREY; - - coord_def c(start_x + screen_x, start_y + screen_y); - - if (!map_bounds(c)) - { - buffer2[bufcount2 + 1] = DARKGREY; - buffer2[bufcount2] = 0; - } - else - { - colour = colour_code_map(c, - Options.item_colour, - travel_mode, - on_level); - - buffer2[bufcount2 + 1] = colour; - buffer2[bufcount2] = env.map(c).glyph(); - - if (c == you.pos() && !crawl_state.arena_suspended && on_level) - { - // [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]; - unsigned char ch = is_waypoint(c); - if (ch && (bc == get_sightmap_char(DNGN_FLOOR) - || bc == get_magicmap_char(DNGN_FLOOR))) - { - bc = ch; - } - } - } - - bufcount2 += 2; - } - - puttext(1, top, num_cols, top + num_lines - 1, buffer2); -} -#endif // USE_TILE - -static void _reset_travel_colours(std::vector &features, - bool on_level) -{ - // We now need to redo travel colours. - features.clear(); - - if (on_level) - { - find_travel_pos((on_level ? you.pos() : coord_def()), - NULL, NULL, &features); - } - else - { - travel_pathfind tp; - tp.set_feature_vector(&features); - tp.get_features(); - } - - // Sort features into the order the player is likely to prefer. - arrange_features(features); -} - -class levelview_excursion : public level_excursion -{ -public: - void go_to(const level_id& next) - { -#ifdef USE_TILE - tiles.clear_minimap(); - level_excursion::go_to(next); - TileNewLevel(false); -#else - level_excursion::go_to(next); -#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( level_pos &spec_place, bool travel_mode, bool allow_esc ) -{ - levelview_excursion le; - level_id original(level_id::current()); - - cursor_control ccon(!Options.use_fake_cursor); - int i, j; - - int move_x = 0, move_y = 0, scroll_y = 0; - - bool new_level = true; - - // Vector to track all features we can travel to, in order of distance. - std::vector features; - - int min_x = INT_MAX, max_x = INT_MIN, min_y = INT_MAX, max_y = INT_MIN; - const int num_lines = _get_number_of_lines_levelmap(); - const int half_screen = (num_lines - 1) / 2; - - const int top = 1 + Options.level_map_title; - - int map_lines = 0; - - int start_x = -1; // no x scrolling - const int block_step = Options.level_map_cursor_step; - int start_y; // y does scroll - - int screen_y = -1; - - int curs_x = -1, curs_y = -1; - int search_found = 0, anchor_x = -1, anchor_y = -1; - - bool map_alive = true; - bool redraw_map = true; - -#ifndef USE_TILE - clrscr(); -#endif - textcolor(DARKGREY); - - bool on_level = false; - - while (map_alive) - { - if (new_level) - { - on_level = (level_id::current() == original); - - move_x = 0, move_y = 0, scroll_y = 0; - - // Vector to track all features we can travel to, in order of distance. - if (travel_mode) - { - travel_init_new_level(); - travel_cache.update(); - - _reset_travel_colours(features, on_level); - } - - min_x = GXM, max_x = 0, min_y = 0, max_y = 0; - bool found_y = false; - - for (j = 0; j < GYM; j++) - for (i = 0; i < GXM; i++) - { - if (env.map[i][j].known()) - { - if (!found_y) - { - found_y = true; - min_y = j; - } - - max_y = j; - - if (i < min_x) - min_x = i; - - if (i > max_x) - max_x = i; - } - } - - map_lines = max_y - min_y + 1; - - start_x = min_x + (max_x - min_x + 1) / 2 - 40; // no x scrolling - start_y = 0; // y does scroll - - coord_def reg; - - if (on_level) - { - reg = you.pos(); - } - else - { - reg.y = min_y + (max_y - min_y + 1) / 2; - reg.x = min_x + (max_x - min_x + 1) / 2; - } - - screen_y = reg.y; - - // If close to top of known map, put min_y on top - // else if close to bottom of known map, put max_y on bottom. - // - // The num_lines comparisons are done to keep things neat, by - // keeping things at the top of the screen. By shifting an - // additional one in the num_lines > map_lines case, we can - // keep the top line clear... which makes things look a whole - // lot better for small maps. - if (num_lines > map_lines) - screen_y = min_y + half_screen - 1; - else if (num_lines == map_lines || screen_y - half_screen < min_y) - screen_y = min_y + half_screen; - else if (screen_y + half_screen > max_y) - screen_y = max_y - half_screen; - - curs_x = reg.x - start_x + 1; - curs_y = reg.y - screen_y + half_screen + 1; - search_found = 0, anchor_x = -1, anchor_y = -1; - - redraw_map = true; - new_level = false; - } - -#if defined(USE_UNIX_SIGNALS) && defined(SIGHUP_SAVE) && defined(USE_CURSES) - // If we've received a HUP signal then the user can't choose a - // location, so indicate this by returning an invalid position. - if (crawl_state.seen_hups) - { - spec_place = level_pos(); - break; - } -#endif - - start_y = screen_y - half_screen; - - move_x = move_y = 0; - - if (redraw_map) - { -#ifdef USE_TILE - // Note: Tile versions just center on the current cursor - // location. It silently ignores everything else going - // on in this function. --Enne - coord_def cen(start_x + curs_x - 1, start_y + curs_y - 1); - tiles.load_dungeon(cen); -#else - _draw_level_map(start_x, start_y, travel_mode, on_level); - -#ifdef WIZARD - if (you.wizard) - { - cgotoxy(get_number_of_cols() / 2, 1); - textcolor(WHITE); - cprintf("(%d, %d)", start_x + curs_x - 1, - start_y + curs_y - 1); - - textcolor(LIGHTGREY); - cgotoxy(curs_x, curs_y + top - 1); - } -#endif // WIZARD - -#endif // USE_TILE - } -#ifndef USE_TILE - cursorxy(curs_x, curs_y + top - 1); -#endif - redraw_map = true; - - c_input_reset(true); - int key = unmangle_direction_keys(getchm(KMC_LEVELMAP), KMC_LEVELMAP, - false, false); - command_type cmd = key_to_command(key, KMC_LEVELMAP); - if (cmd < CMD_MIN_OVERMAP || cmd > CMD_MAX_OVERMAP) - cmd = CMD_NO_CMD; - - if (key == CK_MOUSE_CLICK) - { - const c_mouse_event cme = get_mouse_event(); - const coord_def curp(start_x + curs_x - 1, start_y + curs_y - 1); - const coord_def grdp = - cme.pos + coord_def(start_x - 1, start_y - top); - - if (cme.left_clicked() && in_bounds(grdp)) - { - spec_place = level_pos(level_id::current(), grdp); - map_alive = false; - } - else if (cme.scroll_up()) - scroll_y = -block_step; - else if (cme.scroll_down()) - scroll_y = block_step; - else if (cme.right_clicked()) - { - const coord_def delta = grdp - curp; - move_y = delta.y; - move_x = delta.x; - } - } - - c_input_reset(false); - - switch (cmd) - { - case CMD_MAP_HELP: - show_levelmap_help(); - break; - - case CMD_MAP_CLEAR_MAP: - clear_map(); - break; - - case CMD_MAP_FORGET: - forget_map(100, true); - break; - - case CMD_MAP_ADD_WAYPOINT: - travel_cache.add_waypoint(start_x + curs_x - 1, - start_y + curs_y - 1); - // We need to do this all over again so that the user can jump - // to the waypoint he just created. - _reset_travel_colours(features, on_level); - break; - - // Cycle the radius of an exclude. - case CMD_MAP_EXCLUDE_AREA: - { - const coord_def p(start_x + curs_x - 1, start_y + curs_y - 1); - cycle_exclude_radius(p); - - _reset_travel_colours(features, on_level); - break; - } - - case CMD_MAP_CLEAR_EXCLUDES: - clear_excludes(); - _reset_travel_colours(features, on_level); - break; - - case CMD_MAP_MOVE_DOWN_LEFT: - move_x = -1; - move_y = 1; - break; - - case CMD_MAP_MOVE_DOWN: - move_y = 1; - move_x = 0; - break; - - case CMD_MAP_MOVE_UP_RIGHT: - move_x = 1; - move_y = -1; - break; - - case CMD_MAP_MOVE_UP: - move_y = -1; - move_x = 0; - break; - - case CMD_MAP_MOVE_UP_LEFT: - move_y = -1; - move_x = -1; - break; - - case CMD_MAP_MOVE_LEFT: - move_x = -1; - move_y = 0; - break; - - case CMD_MAP_MOVE_DOWN_RIGHT: - move_y = 1; - move_x = 1; - break; - - case CMD_MAP_MOVE_RIGHT: - move_x = 1; - move_y = 0; - break; - - case CMD_MAP_PREV_LEVEL: - case CMD_MAP_NEXT_LEVEL: { - level_id next; - - next = (cmd == CMD_MAP_PREV_LEVEL) - ? find_up_level(level_id::current()) - : find_down_level(level_id::current()); - - if (next.is_valid() && next != level_id::current() - && is_existing_level(next)) - { - le.go_to(next); - new_level = true; - } - break; - } - - case CMD_MAP_GOTO_LEVEL: { - std::string name; - const level_pos pos = - prompt_translevel_target(TPF_DEFAULT_OPTIONS, name).p; - - if (pos.id.depth < 1 || pos.id.depth > branches[pos.id.branch].depth - || !is_existing_level(pos.id)) - { - canned_msg(MSG_OK); - redraw_map = true; - break; - } - - le.go_to(pos.id); - new_level = true; - break; - } - - case CMD_MAP_JUMP_DOWN_LEFT: - move_x = -block_step; - move_y = block_step; - break; - - case CMD_MAP_JUMP_DOWN: - move_y = block_step; - move_x = 0; - break; - - case CMD_MAP_JUMP_UP_RIGHT: - move_x = block_step; - move_y = -block_step; - break; - - case CMD_MAP_JUMP_UP: - move_y = -block_step; - move_x = 0; - break; - - case CMD_MAP_JUMP_UP_LEFT: - move_y = -block_step; - move_x = -block_step; - break; - - case CMD_MAP_JUMP_LEFT: - move_x = -block_step; - move_y = 0; - break; - - case CMD_MAP_JUMP_DOWN_RIGHT: - move_y = block_step; - move_x = block_step; - break; - - case CMD_MAP_JUMP_RIGHT: - move_x = block_step; - move_y = 0; - break; - - case CMD_MAP_SCROLL_DOWN: - move_y = 20; - move_x = 0; - scroll_y = 20; - break; - - case CMD_MAP_SCROLL_UP: - move_y = -20; - move_x = 0; - scroll_y = -20; - break; - - case CMD_MAP_FIND_YOU: - if (on_level) - { - move_x = you.pos().x - (start_x + curs_x - 1); - move_y = you.pos().y - (start_y + curs_y - 1); - } - break; - - case CMD_MAP_FIND_UPSTAIR: - case CMD_MAP_FIND_DOWNSTAIR: - case CMD_MAP_FIND_PORTAL: - case CMD_MAP_FIND_TRAP: - case CMD_MAP_FIND_ALTAR: - case CMD_MAP_FIND_EXCLUDED: - case CMD_MAP_FIND_F: - case CMD_MAP_FIND_WAYPOINT: - case CMD_MAP_FIND_STASH: - case CMD_MAP_FIND_STASH_REVERSE: - { - bool forward = (cmd != CMD_MAP_FIND_STASH_REVERSE); - - int getty; - switch (cmd) - { - case CMD_MAP_FIND_UPSTAIR: - getty = '<'; - break; - case CMD_MAP_FIND_DOWNSTAIR: - getty = '>'; - break; - case CMD_MAP_FIND_PORTAL: - getty = '\t'; - break; - case CMD_MAP_FIND_TRAP: - getty = '^'; - break; - case CMD_MAP_FIND_ALTAR: - getty = '_'; - break; - case CMD_MAP_FIND_EXCLUDED: - getty = 'E'; - break; - case CMD_MAP_FIND_F: - getty = 'F'; - break; - case CMD_MAP_FIND_WAYPOINT: - getty = 'W'; - break; - default: - case CMD_MAP_FIND_STASH: - case CMD_MAP_FIND_STASH_REVERSE: - getty = 'I'; - break; - } - - if (anchor_x == -1) - { - anchor_x = start_x + curs_x - 1; - anchor_y = start_y + curs_y - 1; - } - if (travel_mode) - { - search_found = _find_feature(features, getty, curs_x, curs_y, - start_x, start_y, - search_found, - &move_x, &move_y, - forward); - } - else - { - search_found = _find_feature(getty, curs_x, curs_y, - start_x, start_y, - anchor_x, anchor_y, - search_found, &move_x, &move_y); - } - break; - } + const int player_distance = distance( you.pos(), where ); - case CMD_MAP_GOTO_TARGET: - { - int x = start_x + curs_x - 1, y = start_y + curs_y - 1; - if (travel_mode && on_level && x == you.pos().x && y == you.pos().y) + if (player_distance <= vamp_range) { - if (you.travel_x > 0 && you.travel_y > 0) +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, + "Player smells blood, pos: (%d, %d), dist = %d)", + you.pos().x, you.pos().y, player_distance); +#endif + you.check_awaken(range - player_distance); + // Don't message if you can see the square. + if (!see_cell(where)) { - move_x = you.travel_x - x; - move_y = you.travel_y - y; + mprf("You smell fresh blood%s.", + _player_vampire_smells_blood(player_distance)); } - break; - } - else - { - spec_place = level_pos(level_id::current(), coord_def(x, y)); - map_alive = false; - break; } } + } -#ifdef WIZARD - case CMD_MAP_WIZARD_TELEPORT: - { - if (!you.wizard) - break; - if (!on_level) - break; - const coord_def pos(start_x + curs_x - 1, start_y + curs_y - 1); - if (!in_bounds(pos)) - break; - you.moveto(pos); - map_alive = false; - break; - } -#endif + for (int p = 0; p < MAX_MONSTERS; p++) + { + monster = &menv[p]; - case CMD_MAP_EXIT_MAP: - if (allow_esc) - { - spec_place = level_pos(); - map_alive = false; - break; - } - default: - if (travel_mode) - { - map_alive = false; - break; - } - redraw_map = false; + if (monster->type < 0) continue; - } - - if (!map_alive) - break; - -#ifdef USE_TILE - { - int new_x = start_x + curs_x + move_x - 1; - int new_y = start_y + curs_y + move_y - 1; - - curs_x += (new_x < 1 || new_x > GXM) ? 0 : move_x; - curs_y += (new_y < 1 || new_y > GYM) ? 0 : move_y; - } -#else - if (curs_x + move_x < 1 || curs_x + move_x > crawl_view.termsz.x) - move_x = 0; - curs_x += move_x; + if (!mons_class_flag(monster->type, M_BLOOD_SCENT)) + continue; - if (num_lines < map_lines) + if (distance(monster->pos(), where) <= range) { - // Scrolling only happens when we don't have a large enough - // display to show the known map. - if (scroll_y != 0) - { - const int old_screen_y = screen_y; - screen_y += scroll_y; - if (scroll_y < 0) - screen_y = std::max(screen_y, min_y + half_screen); - else - screen_y = std::min(screen_y, max_y - half_screen); - curs_y -= (screen_y - old_screen_y); - scroll_y = 0; - } - - if (curs_y + move_y < 1) + // Let sleeping hounds lie. + if (monster->asleep() + && mons_species(monster->type) != MONS_VAMPIRE + && monster->type != MONS_SHARK) { - screen_y += move_y; - - if (screen_y < min_y + half_screen) + // 33% chance of sleeping on + // 33% of being disturbed (start BEH_WANDER) + // 33% of being alerted (start BEH_SEEK) + if (!one_chance_in(3)) { - move_y = screen_y - (min_y + half_screen); - screen_y = min_y + half_screen; + if (coinflip()) + { +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "disturbing %s (%d, %d)", + monster->name(DESC_PLAIN).c_str(), + monster->pos().x, monster->pos().y); +#endif + behaviour_event(monster, ME_DISTURB, MHITNOT, where); + } + continue; } - else - move_y = 0; } +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "alerting %s (%d, %d)", + monster->name(DESC_PLAIN).c_str(), + monster->pos().x, monster->pos().y); +#endif + behaviour_event( monster, ME_ALERT, MHITNOT, where ); - if (curs_y + move_y > num_lines) + if (monster->type == MONS_SHARK) { - screen_y += move_y; - - if (screen_y > max_y - half_screen) + // Sharks go into a battle frenzy if they smell blood. + monster_pathfind mp; + if (mp.init_pathfind(monster, where)) { - move_y = screen_y - (max_y - half_screen); - screen_y = max_y - half_screen; + mon_enchant ench = monster->get_ench(ENCH_BATTLE_FRENZY); + const int dist = 15 - (monster->pos() - where).rdist(); + const int dur = random_range(dist, dist*2) + * speed_to_duration(monster->speed); + + if (ench.ench != ENCH_NONE) + { + int level = ench.degree; + if (level < 4 && one_chance_in(2*level)) + ench.degree++; + ench.duration = std::max(ench.duration, dur); + monster->update_ench(ench); + } + else + { + monster->add_ench(mon_enchant(ENCH_BATTLE_FRENZY, 1, + KC_OTHER, dur)); + simple_monster_message(monster, " is consumed with " + "blood-lust!"); + } } - else - move_y = 0; } } - - if (curs_y + move_y < 1 || curs_y + move_y > num_lines) - move_y = 0; - - curs_y += move_y; -#endif } - - le.go_to(original); - - travel_init_new_level(); - travel_cache.update(); } + // We logically associate a difficulty parameter with each tile on each level, // to make deterministic magic mapping work. This function returns the // difficulty parameters for each tile on the current level, whose difficulty @@ -2994,122 +1397,6 @@ bool mon_enemies_around(const monsters *monster) } } -// For order and meaning of symbols, see dungeon_char_type in enum.h. -static const unsigned dchar_table[ NUM_CSET ][ NUM_DCHAR_TYPES ] = -{ - // CSET_ASCII - { - '#', '*', '.', ',', '\'', '+', '^', '>', '<', // wall .. stairs up - '_', '\\', '}', '{', '8', '~', '~', // altar .. item detect - '0', ')', '[', '/', '%', '?', '=', '!', '(', // orb .. missile - ':', '|', '}', '%', '$', '"', '#', '7', // book .. trees - ' ', '!', '#', '%', ':', ')', '*', '+', // space .. fired_burst - '/', '=', '?', 'X', '[', '`', '#' // fi_stick .. explosion - }, - - // 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 - '+', '\\', '}', '%', '$', '"', '#', 234, // book .. trees - ' ', '!', '#', '%', '+', ')', '*', '+', // space .. fired_burst - '/', '=', '?', 'X', '[', '`', '#' // fi_stick .. explosion - }, - - // 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 - '+', '\\', '}', '%', '$', '"', '#', '7', // book .. trees - ' ', '!', '#', '%', '+', ')', '*', '+', // space .. fired_burst - '/', '=', '?', 'X', '[', '`', '#' // fi_stick .. explosion - }, - - // CSET_UNICODE - { - 0x2592, 0x2591, 0xB7, 0x25E6, '\'', 0x25FC, '^', '>', '<', - '_', 0x2229, 0x2320, 0x2248, '8', '~', '~', - '0', ')', '[', '/', '%', '?', '=', '!', '(', - '+', '|', '}', '%', '$', '"', '#', 0x2663, - ' ', '!', '#', '%', '+', ')', '*', '+', // space .. fired_burst - '/', '=', '?', 'X', '[', '`', '#' // fi_stick .. explosion - }, -}; - -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", "trees", - }; - - 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); -} - -void init_char_table( char_set_type set ) -{ - for (int i = 0; i < NUM_DCHAR_TYPES; i++) - { - if (Options.cset_override[set][i]) - Options.char_table[i] = Options.cset_override[set][i]; - else - Options.char_table[i] = dchar_table[set][i]; - } -} - -unsigned dchar_glyph(dungeon_char_type dchar) -{ - return (Options.char_table[dchar]); -} - -unsigned get_screen_glyph( int x, int y ) -{ - return get_screen_glyph(coord_def(x,y)); -} - -unsigned get_screen_glyph(const coord_def& p) -{ - const coord_def ep = view2show(grid2view(p)); - - show_type object = env.show(ep); - unsigned short colour = object.colour; - unsigned ch; - - if (!object) - return get_envmap_char(p.x, p.y); - - _get_symbol(p, object, &ch, &colour); - return (ch); -} - -std::string stringize_glyph(unsigned glyph) -{ - if (crawl_state.glyph2strfn && Options.char_set == CSET_UNICODE) - return (*crawl_state.glyph2strfn)(glyph); - - return (std::string(1, glyph)); -} - -int multibyte_strlen(const std::string &s) -{ - if (crawl_state.multibyte_strlen) - return (*crawl_state.multibyte_strlen)(s); - - return (s.length()); -} - // 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 @@ -3631,378 +1918,6 @@ void viewwindow(bool draw_it, bool do_updates) _debug_pane_bounds(); } -////////////////////////////////////////////////////////////////////////////// -// crawl_view_buffer - -crawl_view_buffer::crawl_view_buffer() - : buffer(NULL) -{ -} - -crawl_view_buffer::~crawl_view_buffer() -{ - delete [] buffer; -} - -void crawl_view_buffer::size(const coord_def &sz) -{ - delete [] buffer; - buffer = new screen_buffer_t [ sz.x * sz.y * 2 ]; -} - -// ---------------------------------------------------------------------- -// Layout helper classes -// ---------------------------------------------------------------------- - -// Moved from directn.h, where they didn't need to be. -// define VIEW_MIN_HEIGHT defined elsewhere -// define VIEW_MAX_HEIGHT use Options.view_max_height -// define VIEW_MIN_WIDTH defined elsewhere -// define VIEW_MAX_WIDTH use Options.view_max_width -#define HUD_WIDTH 42 -#define HUD_HEIGHT 12 -// #define MSG_MIN_HEIGHT defined elsewhere -#define MSG_MAX_HEIGHT Options.msg_max_height -#define MLIST_MIN_HEIGHT Options.mlist_min_height -#define MLIST_MIN_WIDTH 25 // non-inline layout only -#define MLIST_MAX_WIDTH 42 -#define MLIST_GUTTER 1 -#define HUD_MIN_GUTTER 2 -#define HUD_MAX_GUTTER 4 - -// Helper for layouts. Tries to increment lvalue without overflowing it. -static void _increment(int& lvalue, int delta, int max_value) -{ - lvalue = std::min(lvalue+delta, max_value); -} - -class _layout -{ - public: - _layout(coord_def termsz_, coord_def hudsz_) : - termp(1,1), termsz(termsz_), - viewp(-1,-1), viewsz(VIEW_MIN_WIDTH, VIEW_MIN_HEIGHT), - hudp(-1,-1), hudsz(hudsz_), - msgp(-1,-1), msgsz(0, MSG_MIN_HEIGHT), - mlistp(-1,-1), mlistsz(MLIST_MIN_WIDTH, 0), - hud_gutter(HUD_MIN_GUTTER), - valid(false) {} - - protected: - void _assert_validity() const - { -#ifndef USE_TILE - // Check that all the panes fit in the view. - ASSERT( (viewp+viewsz - termp).x <= termsz.x ); - ASSERT( (viewp+viewsz - termp).y <= termsz.y ); - - ASSERT( (hudp+hudsz - termp).x <= termsz.x ); - ASSERT( (hudp+hudsz - termp).y <= termsz.y ); - - ASSERT( (msgp+msgsz - termp).x <= termsz.x ); - ASSERT( (msgp+msgsz - termp).y <= termsz.y ); - // Don't stretch message all the way to the bottom-right - // character; it causes scrolling and badness. - ASSERT( (msgp+msgsz - termp) != termsz ); - - ASSERT( (mlistp+mlistsz-termp).x <= termsz.x ); - ASSERT( (mlistp+mlistsz-termp).y <= termsz.y ); -#endif - } - public: - const coord_def termp, termsz; - coord_def viewp, viewsz; - coord_def hudp; - const coord_def hudsz; - coord_def msgp, msgsz; - coord_def mlistp, mlistsz; - int hud_gutter; - bool valid; -}; - -// vvvvvvghhh v=view, g=hud gutter, h=hud, l=list, m=msg -// vvvvvvghhh -// vvvvvv lll -// lll -// mmmmmmmmmm -class _inline_layout : public _layout -{ - public: - _inline_layout(coord_def termsz_, coord_def hudsz_) : - _layout(termsz_, hudsz_) - { - valid = _init(); - } - - bool _init() - { - // x: View gets leftover; then mlist; then hud gutter - if (leftover_x() < 0) - return (false); - - _increment(viewsz.x, leftover_x(), Options.view_max_width); - - if ((viewsz.x % 2) != 1) - --viewsz.x; - - mlistsz.x = hudsz.x; - _increment(mlistsz.x, leftover_x(), MLIST_MAX_WIDTH); - _increment(hud_gutter, leftover_x(), HUD_MAX_GUTTER); - _increment(mlistsz.x, leftover_x(), INT_MAX); - msgsz.x = termsz.x-1; // Can't use last character. - - // y: View gets as much as it wants. - // mlist tries to get at least its minimum. - // msg expands as much as it wants. - // mlist gets any leftovers. - if (leftover_y() < 0) - return (false); - - _increment(viewsz.y, leftover_leftcol_y(), Options.view_max_height); - if ((viewsz.y % 2) != 1) - --viewsz.y; - - if (Options.classic_hud) - { - mlistsz.y = 0; - _increment(msgsz.y, leftover_y(), MSG_MAX_HEIGHT); - } - else - { - if (mlistsz.y < MLIST_MIN_HEIGHT) - _increment(mlistsz.y, leftover_rightcol_y(), MLIST_MIN_HEIGHT); - _increment(msgsz.y, leftover_y(), MSG_MAX_HEIGHT); - _increment(mlistsz.y, leftover_rightcol_y(), INT_MAX); - } - - // Finish off by doing the positions. - viewp = termp; - msgp = termp + coord_def(0, std::max(viewsz.y, hudsz.y+mlistsz.y)); - hudp = viewp + coord_def(viewsz.x+hud_gutter, 0); - mlistp = hudp + coord_def(0, hudsz.y); - - _assert_validity(); - return (true); - } - - int leftover_x() const - { - int width = (viewsz.x + hud_gutter + std::max(hudsz.x, mlistsz.x)); - return (termsz.x - width); - } - int leftover_rightcol_y() const { return termsz.y-hudsz.y-mlistsz.y-msgsz.y; } - int leftover_leftcol_y() const { return termsz.y-viewsz.y-msgsz.y; } - int leftover_y() const - { - return std::min(leftover_rightcol_y(), leftover_leftcol_y()); - } -}; - -// ll vvvvvvghhh v=view, g=hud gutter, h=hud, l=list, m=msg -// ll vvvvvvghhh -// ll vvvvvv -// mmmmmmmmmmmmm -class _mlist_col_layout : public _layout -{ - public: - _mlist_col_layout(coord_def termsz_, coord_def hudsz_) - : _layout(termsz_, hudsz_) - { valid = _init(); } - bool _init() - { - // Don't let the mlist column steal all the width. Up front, - // take some for the view. If it makes the layout fail, that's fine. - _increment(viewsz.x, MLIST_MIN_WIDTH/2, Options.view_max_width); - - // x: View and mlist share leftover; then hud gutter. - if (leftover_x() < 0) - return (false); - - _increment(mlistsz.x, leftover_x()/2, MLIST_MAX_WIDTH); - _increment(viewsz.x, leftover_x(), Options.view_max_width); - - if ((viewsz.x % 2) != 1) - --viewsz.x; - - _increment(mlistsz.x, leftover_x(), MLIST_MAX_WIDTH); - _increment(hud_gutter, leftover_x(), HUD_MAX_GUTTER); - msgsz.x = termsz.x-1; // Can't use last character. - - // y: View gets leftover; then message. - if (leftover_y() < 0) - return (false); - - _increment(viewsz.y, leftover_y(), Options.view_max_height); - - if ((viewsz.y % 2) != 1) - --viewsz.y; - - _increment(msgsz.y, leftover_y(), INT_MAX); - mlistsz.y = viewsz.y; - - // Finish off by doing the positions. - mlistp = termp; - viewp = mlistp+ coord_def(mlistsz.x+MLIST_GUTTER, 0); - msgp = termp + coord_def(0, viewsz.y); - hudp = viewp + coord_def(viewsz.x+hud_gutter, 0); - - _assert_validity(); - return (true); - } - private: - int leftover_x() const - { - int width = (mlistsz.x + MLIST_GUTTER + viewsz.x + hud_gutter + hudsz.x); - return (termsz.x - width); - } - int leftover_y() const - { - const int top_y = std::max(std::max(viewsz.y, hudsz.y), mlistsz.y); - const int height = top_y + msgsz.y; - return (termsz.y - height); - } -}; - -// ---------------------------------------------------------------------- -// crawl_view_geometry -// ---------------------------------------------------------------------- - -crawl_view_geometry::crawl_view_geometry() - : termp(1, 1), termsz(80, 24), - viewp(1, 1), viewsz(33, 17), - hudp(40, 1), hudsz(-1, -1), - msgp(1, viewp.y + viewsz.y), msgsz(80, 7), - mlistp(hudp.x, hudp.y + hudsz.y), - mlistsz(hudsz.x, msgp.y - mlistp.y), - vbuf(), vgrdc(), viewhalfsz(), glos1(), glos2(), - vlos1(), vlos2(), mousep(), last_player_pos() -{ -} - -void crawl_view_geometry::init_view() -{ - viewhalfsz = viewsz / 2; - vbuf.size(viewsz); - set_player_at(you.pos(), true); -} - -void crawl_view_geometry::shift_player_to(const coord_def &c) -{ - // Preserve vgrdc offset after moving. - const coord_def offset = crawl_view.vgrdc - you.pos(); - crawl_view.vgrdc = offset + c; - last_player_pos = c; - - set_player_at(c); - - ASSERT(crawl_view.vgrdc == offset + c); - ASSERT(last_player_pos == c); -} - -void crawl_view_geometry::set_player_at(const coord_def &c, bool centre) -{ - if (centre) - { - vgrdc = c; - } - else - { - const coord_def oldc = vgrdc; - const int xmarg = Options.scroll_margin_x + LOS_RADIUS <= viewhalfsz.x - ? Options.scroll_margin_x - : viewhalfsz.x - LOS_RADIUS; - const int ymarg = Options.scroll_margin_y + LOS_RADIUS <= viewhalfsz.y - ? Options.scroll_margin_y - : viewhalfsz.y - LOS_RADIUS; - - if (Options.view_lock_x) - vgrdc.x = c.x; - else if (c.x - LOS_RADIUS < vgrdc.x - viewhalfsz.x + xmarg) - vgrdc.x = c.x - LOS_RADIUS + viewhalfsz.x - xmarg; - else if (c.x + LOS_RADIUS > vgrdc.x + viewhalfsz.x - xmarg) - vgrdc.x = c.x + LOS_RADIUS - viewhalfsz.x + xmarg; - - if (Options.view_lock_y) - vgrdc.y = c.y; - else if (c.y - LOS_RADIUS < vgrdc.y - viewhalfsz.y + ymarg) - vgrdc.y = c.y - LOS_RADIUS + viewhalfsz.y - ymarg; - else if (c.y + LOS_RADIUS > vgrdc.y + viewhalfsz.y - ymarg) - vgrdc.y = c.y + LOS_RADIUS - viewhalfsz.y + ymarg; - - if (vgrdc != oldc && Options.center_on_scroll) - vgrdc = c; - - if (!Options.center_on_scroll && Options.symmetric_scroll - && !Options.view_lock_x - && !Options.view_lock_y - && (c - last_player_pos).abs() == 2 - && (vgrdc - oldc).abs() == 1) - { - const coord_def dp = c - last_player_pos; - const coord_def dc = vgrdc - oldc; - if ((dc.x == dp.x) != (dc.y == dp.y)) - vgrdc = oldc + dp; - } - } - - glos1 = c - coord_def(LOS_RADIUS, LOS_RADIUS); - glos2 = c + coord_def(LOS_RADIUS, LOS_RADIUS); - - vlos1 = glos1 - vgrdc + view_centre(); - vlos2 = glos2 - vgrdc + view_centre(); - - last_player_pos = c; -} - -void crawl_view_geometry::init_geometry() -{ - termsz = coord_def( get_number_of_cols(), get_number_of_lines() ); - hudsz = coord_def(HUD_WIDTH, - HUD_HEIGHT + (Options.show_gold_turns ? 1 : 0)); - - const _inline_layout lay_inline(termsz, hudsz); - const _mlist_col_layout lay_mlist(termsz, hudsz); - - if (! lay_inline.valid) - { -#ifndef USE_TILE - // Terminal too small; exit with an error. - if (!crawl_state.need_save) - { - end(1, false, "Terminal too small (%d,%d); need at least (%d,%d)", - termsz.x, termsz.y, - termsz.x + std::max(0, -lay_inline.leftover_x()), - termsz.y + std::max(0, -lay_inline.leftover_y())); - } -#endif - } - - const _layout* winner = &lay_inline; - if (Options.mlist_allow_alternate_layout - && !Options.classic_hud - && lay_mlist.valid) - { - winner = &lay_mlist; - } - - msgp = winner->msgp; - msgsz = winner->msgsz; - viewp = winner->viewp; - viewsz = winner->viewsz; - hudp = winner->hudp; - hudsz = winner->hudsz; - mlistp = winner->mlistp; - mlistsz = winner->mlistsz; - -#ifdef USE_TILE - // libgui may redefine these based on its own settings. - gui_init_view_params(*this); -#endif - - init_view(); - return; -} - //////////////////////////////////////////////////////////////////////////// // Term resize handling (generic). diff --git a/crawl-ref/source/view.h b/crawl-ref/source/view.h index 978fcad050..148cd35fc6 100644 --- a/crawl-ref/source/view.h +++ b/crawl-ref/source/view.h @@ -11,7 +11,6 @@ #include "externs.h" #include "show.h" -void init_char_table(char_set_type set); void init_monsters_seens(); void beogh_follower_convert(monsters *monster, bool orc_hit = false); @@ -38,8 +37,6 @@ void handle_monster_shouts(monsters* monster, bool force = false); class level_pos; void show_map( level_pos &spec_place, bool travel_mode, bool allow_esc = false ); bool check_awaken(monsters* monster); -int count_detected_mons(void); -void clear_map(bool clear_items = true, bool clear_mons = true); bool is_feature(int feature, const coord_def& where); void get_item_glyph(const item_def *item, unsigned *glych, unsigned short *glycol); @@ -47,94 +44,20 @@ void get_mons_glyph(const monsters *mons, unsigned *glych, unsigned short *glycol); unsigned get_screen_glyph( int x, int y ); unsigned get_screen_glyph( const coord_def &p ); -std::string stringize_glyph(unsigned glyph); -int multibyte_strlen(const std::string &s); -// Applies ETC_ colour substitutions and brands. -unsigned real_colour(unsigned raw_colour); int get_mons_colour(const monsters *mons); -void set_envmap_obj(const coord_def& where, show_type object); -unsigned get_envmap_char(int x, int y); -inline unsigned get_envmap_char(const coord_def& c) { - return get_envmap_char(c.x, c.y); -} bool inside_level_bounds(int x, int y); bool inside_level_bounds(const coord_def &p); -show_type get_envmap_obj(int x, int y); -inline show_type get_envmap_obj(const coord_def& c) { - return get_envmap_obj(c.x, c.y); -} -void set_envmap_detected_item(int x, int y, bool detected = true); -inline void set_envmap_detected_item(const coord_def& c, bool detected = true) { - set_envmap_detected_item(c.x, c.y, detected); -} - -void set_envmap_detected_mons(int x, int y, bool detected = true); -inline void set_envmap_detected_mons(const coord_def& c, bool detected = true) { - set_envmap_detected_mons(c.x, c.y, detected); -} -void set_envmap_col( int x, int y, int colour, int flags ); -void set_envmap_col( int x, int y, int colour ); -bool is_sanctuary( const coord_def& p ); -bool is_bloodcovered( const coord_def& p ); - -bool is_envmap_detected_item(int x, int y); -inline bool is_envmap_detected_item(const coord_def& c) { - return is_envmap_detected_item(c.x, c.y); -} - -bool is_envmap_detected_mons(int x, int y); -inline bool is_envmap_detected_mons(const coord_def& c) { - return is_envmap_detected_mons(c.x, c.y); -} -bool is_envmap_item(int x, int y); -inline bool is_envmap_item(const coord_def& c) { - return is_envmap_item(c.x, c.y); -} -void set_terrain_mapped( int x, int y ); -inline void set_terrain_mapped( const coord_def& c ) { - set_terrain_mapped(c.x,c.y); -} -void set_terrain_seen( int x, int y ); -inline void set_terrain_seen( const coord_def& c ) { - set_terrain_seen(c.x, c.y); -} -void set_terrain_changed( int x, int y ); -bool is_terrain_known( int x, int y ); -bool is_terrain_seen( int x, int y ); -bool is_terrain_changed( int x, int y ); -inline bool is_terrain_changed( const coord_def& c ) { - return is_terrain_changed(c.x,c.y); -} -bool is_terrain_known(const coord_def &p); -bool is_terrain_mapped(const coord_def &p); -bool is_notable_terrain(dungeon_feature_type ftype); - -inline bool is_terrain_seen(const coord_def &c) -{ - return (is_terrain_seen(c.x, c.y)); -} - -inline void set_terrain_changed(const coord_def &c) -{ - set_terrain_changed(c.x, c.y); -} - void clear_feature_overrides(); void add_feature_override(const std::string &text); -void clear_cset_overrides(); -void add_cset_override(char_set_type set, const std::string &overrides); unsigned grid_character_at(const coord_def &c); +unsigned get_symbol(show_type object, unsigned short *colour = NULL, + bool magic_mapped = false); std::string screenshot(bool fullscreen = false); -dungeon_char_type get_feature_dchar( dungeon_feature_type feat ); -unsigned dchar_glyph(dungeon_char_type dchar); -unsigned get_sightmap_char(int feature); -unsigned get_magicmap_char(int feature); - bool view_update(); void view_update_at(const coord_def &pos); #ifndef USE_TILE @@ -150,9 +73,4 @@ dungeon_char_type dchar_by_name(const std::string &name); void handle_terminal_resize(bool redraw = true); -#if defined(TARGET_OS_WINDOWS) || defined(TARGET_OS_DOS) || defined(USE_TILE) -unsigned short dos_brand( unsigned short colour, - unsigned brand = CHATTR_REVERSE); -#endif - #endif diff --git a/crawl-ref/source/viewchar.cc b/crawl-ref/source/viewchar.cc new file mode 100644 index 0000000000..a0cef43408 --- /dev/null +++ b/crawl-ref/source/viewchar.cc @@ -0,0 +1,103 @@ +#include "AppHdr.h" + +#include "viewchar.h" + +#include "options.h" +#include "state.h" + +// For order and meaning of symbols, see dungeon_char_type in enum.h. +static const unsigned dchar_table[ NUM_CSET ][ NUM_DCHAR_TYPES ] = +{ + // CSET_ASCII + { + '#', '*', '.', ',', '\'', '+', '^', '>', '<', // wall .. stairs up + '_', '\\', '}', '{', '8', '~', '~', // altar .. item detect + '0', ')', '[', '/', '%', '?', '=', '!', '(', // orb .. missile + ':', '|', '}', '%', '$', '"', '#', '7', // book .. trees + ' ', '!', '#', '%', ':', ')', '*', '+', // space .. fired_burst + '/', '=', '?', 'X', '[', '`', '#' // fi_stick .. explosion + }, + + // 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 + '+', '\\', '}', '%', '$', '"', '#', 234, // book .. trees + ' ', '!', '#', '%', '+', ')', '*', '+', // space .. fired_burst + '/', '=', '?', 'X', '[', '`', '#' // fi_stick .. explosion + }, + + // 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 + '+', '\\', '}', '%', '$', '"', '#', '7', // book .. trees + ' ', '!', '#', '%', '+', ')', '*', '+', // space .. fired_burst + '/', '=', '?', 'X', '[', '`', '#' // fi_stick .. explosion + }, + + // CSET_UNICODE + { + 0x2592, 0x2591, 0xB7, 0x25E6, '\'', 0x25FC, '^', '>', '<', + '_', 0x2229, 0x2320, 0x2248, '8', '~', '~', + '0', ')', '[', '/', '%', '?', '=', '!', '(', + '+', '|', '}', '%', '$', '"', '#', 0x2663, + ' ', '!', '#', '%', '+', ')', '*', '+', // space .. fired_burst + '/', '=', '?', 'X', '[', '`', '#' // fi_stick .. explosion + }, +}; + +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", "trees", + }; + + 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); +} + +void init_char_table( char_set_type set ) +{ + for (int i = 0; i < NUM_DCHAR_TYPES; i++) + { + if (Options.cset_override[set][i]) + Options.char_table[i] = Options.cset_override[set][i]; + else + Options.char_table[i] = dchar_table[set][i]; + } +} + +unsigned dchar_glyph(dungeon_char_type dchar) +{ + return (Options.char_table[dchar]); +} + +std::string stringize_glyph(unsigned glyph) +{ + if (crawl_state.glyph2strfn && Options.char_set == CSET_UNICODE) + return (*crawl_state.glyph2strfn)(glyph); + + return (std::string(1, glyph)); +} + +int multibyte_strlen(const std::string &s) +{ + if (crawl_state.multibyte_strlen) + return (*crawl_state.multibyte_strlen)(s); + + return (s.length()); +} + diff --git a/crawl-ref/source/viewchar.h b/crawl-ref/source/viewchar.h new file mode 100644 index 0000000000..96412480ec --- /dev/null +++ b/crawl-ref/source/viewchar.h @@ -0,0 +1,13 @@ +#ifndef VIEWCHAR_H +#define VIEWCHAR_H + +void init_char_table(char_set_type set); + +dungeon_char_type get_feature_dchar( dungeon_feature_type feat ); +unsigned dchar_glyph(dungeon_char_type dchar); + +std::string stringize_glyph(unsigned glyph); +int multibyte_strlen(const std::string &s); + +#endif + diff --git a/crawl-ref/source/viewgeom.cc b/crawl-ref/source/viewgeom.cc new file mode 100644 index 0000000000..e013819a09 --- /dev/null +++ b/crawl-ref/source/viewgeom.cc @@ -0,0 +1,382 @@ +#include "AppHdr.h" + +#include "viewgeom.h" + +#include "options.h" +#include "player.h" +#include "state.h" +#include "stuff.h" + +// ---------------------------------------------------------------------- +// Layout helper classes +// ---------------------------------------------------------------------- + +// Moved from directn.h, where they didn't need to be. +// define VIEW_MIN_HEIGHT defined elsewhere +// define VIEW_MAX_HEIGHT use Options.view_max_height +// define VIEW_MIN_WIDTH defined elsewhere +// define VIEW_MAX_WIDTH use Options.view_max_width +#define HUD_WIDTH 42 +#define HUD_HEIGHT 12 +// #define MSG_MIN_HEIGHT defined elsewhere +#define MSG_MAX_HEIGHT Options.msg_max_height +#define MLIST_MIN_HEIGHT Options.mlist_min_height +#define MLIST_MIN_WIDTH 25 // non-inline layout only +#define MLIST_MAX_WIDTH 42 +#define MLIST_GUTTER 1 +#define HUD_MIN_GUTTER 2 +#define HUD_MAX_GUTTER 4 + +// Helper for layouts. Tries to increment lvalue without overflowing it. +static void _increment(int& lvalue, int delta, int max_value) +{ + lvalue = std::min(lvalue+delta, max_value); +} + +class _layout +{ + public: + _layout(coord_def termsz_, coord_def hudsz_) : + termp(1,1), termsz(termsz_), + viewp(-1,-1), viewsz(VIEW_MIN_WIDTH, VIEW_MIN_HEIGHT), + hudp(-1,-1), hudsz(hudsz_), + msgp(-1,-1), msgsz(0, MSG_MIN_HEIGHT), + mlistp(-1,-1), mlistsz(MLIST_MIN_WIDTH, 0), + hud_gutter(HUD_MIN_GUTTER), + valid(false) {} + + protected: + void _assert_validity() const + { +#ifndef USE_TILE + // Check that all the panes fit in the view. + ASSERT( (viewp+viewsz - termp).x <= termsz.x ); + ASSERT( (viewp+viewsz - termp).y <= termsz.y ); + + ASSERT( (hudp+hudsz - termp).x <= termsz.x ); + ASSERT( (hudp+hudsz - termp).y <= termsz.y ); + + ASSERT( (msgp+msgsz - termp).x <= termsz.x ); + ASSERT( (msgp+msgsz - termp).y <= termsz.y ); + // Don't stretch message all the way to the bottom-right + // character; it causes scrolling and badness. + ASSERT( (msgp+msgsz - termp) != termsz ); + + ASSERT( (mlistp+mlistsz-termp).x <= termsz.x ); + ASSERT( (mlistp+mlistsz-termp).y <= termsz.y ); +#endif + } + public: + const coord_def termp, termsz; + coord_def viewp, viewsz; + coord_def hudp; + const coord_def hudsz; + coord_def msgp, msgsz; + coord_def mlistp, mlistsz; + int hud_gutter; + bool valid; +}; + +// vvvvvvghhh v=view, g=hud gutter, h=hud, l=list, m=msg +// vvvvvvghhh +// vvvvvv lll +// lll +// mmmmmmmmmm +class _inline_layout : public _layout +{ + public: + _inline_layout(coord_def termsz_, coord_def hudsz_) : + _layout(termsz_, hudsz_) + { + valid = _init(); + } + + bool _init() + { + // x: View gets leftover; then mlist; then hud gutter + if (leftover_x() < 0) + return (false); + + _increment(viewsz.x, leftover_x(), Options.view_max_width); + + if ((viewsz.x % 2) != 1) + --viewsz.x; + + mlistsz.x = hudsz.x; + _increment(mlistsz.x, leftover_x(), MLIST_MAX_WIDTH); + _increment(hud_gutter, leftover_x(), HUD_MAX_GUTTER); + _increment(mlistsz.x, leftover_x(), INT_MAX); + msgsz.x = termsz.x-1; // Can't use last character. + + // y: View gets as much as it wants. + // mlist tries to get at least its minimum. + // msg expands as much as it wants. + // mlist gets any leftovers. + if (leftover_y() < 0) + return (false); + + _increment(viewsz.y, leftover_leftcol_y(), Options.view_max_height); + if ((viewsz.y % 2) != 1) + --viewsz.y; + + if (Options.classic_hud) + { + mlistsz.y = 0; + _increment(msgsz.y, leftover_y(), MSG_MAX_HEIGHT); + } + else + { + if (mlistsz.y < MLIST_MIN_HEIGHT) + _increment(mlistsz.y, leftover_rightcol_y(), MLIST_MIN_HEIGHT); + _increment(msgsz.y, leftover_y(), MSG_MAX_HEIGHT); + _increment(mlistsz.y, leftover_rightcol_y(), INT_MAX); + } + + // Finish off by doing the positions. + viewp = termp; + msgp = termp + coord_def(0, std::max(viewsz.y, hudsz.y+mlistsz.y)); + hudp = viewp + coord_def(viewsz.x+hud_gutter, 0); + mlistp = hudp + coord_def(0, hudsz.y); + + _assert_validity(); + return (true); + } + + int leftover_x() const + { + int width = (viewsz.x + hud_gutter + std::max(hudsz.x, mlistsz.x)); + return (termsz.x - width); + } + int leftover_rightcol_y() const { return termsz.y-hudsz.y-mlistsz.y-msgsz.y; } + int leftover_leftcol_y() const { return termsz.y-viewsz.y-msgsz.y; } + int leftover_y() const + { + return std::min(leftover_rightcol_y(), leftover_leftcol_y()); + } +}; + +// ll vvvvvvghhh v=view, g=hud gutter, h=hud, l=list, m=msg +// ll vvvvvvghhh +// ll vvvvvv +// mmmmmmmmmmmmm +class _mlist_col_layout : public _layout +{ + public: + _mlist_col_layout(coord_def termsz_, coord_def hudsz_) + : _layout(termsz_, hudsz_) + { valid = _init(); } + bool _init() + { + // Don't let the mlist column steal all the width. Up front, + // take some for the view. If it makes the layout fail, that's fine. + _increment(viewsz.x, MLIST_MIN_WIDTH/2, Options.view_max_width); + + // x: View and mlist share leftover; then hud gutter. + if (leftover_x() < 0) + return (false); + + _increment(mlistsz.x, leftover_x()/2, MLIST_MAX_WIDTH); + _increment(viewsz.x, leftover_x(), Options.view_max_width); + + if ((viewsz.x % 2) != 1) + --viewsz.x; + + _increment(mlistsz.x, leftover_x(), MLIST_MAX_WIDTH); + _increment(hud_gutter, leftover_x(), HUD_MAX_GUTTER); + msgsz.x = termsz.x-1; // Can't use last character. + + // y: View gets leftover; then message. + if (leftover_y() < 0) + return (false); + + _increment(viewsz.y, leftover_y(), Options.view_max_height); + + if ((viewsz.y % 2) != 1) + --viewsz.y; + + _increment(msgsz.y, leftover_y(), INT_MAX); + mlistsz.y = viewsz.y; + + // Finish off by doing the positions. + mlistp = termp; + viewp = mlistp+ coord_def(mlistsz.x+MLIST_GUTTER, 0); + msgp = termp + coord_def(0, viewsz.y); + hudp = viewp + coord_def(viewsz.x+hud_gutter, 0); + + _assert_validity(); + return (true); + } + private: + int leftover_x() const + { + int width = (mlistsz.x + MLIST_GUTTER + viewsz.x + hud_gutter + hudsz.x); + return (termsz.x - width); + } + int leftover_y() const + { + const int top_y = std::max(std::max(viewsz.y, hudsz.y), mlistsz.y); + const int height = top_y + msgsz.y; + return (termsz.y - height); + } +}; + +////////////////////////////////////////////////////////////////////////////// +// crawl_view_buffer + +crawl_view_buffer::crawl_view_buffer() + : buffer(NULL) +{ +} + +crawl_view_buffer::~crawl_view_buffer() +{ + delete [] buffer; +} + +void crawl_view_buffer::size(const coord_def &sz) +{ + delete [] buffer; + buffer = new screen_buffer_t [ sz.x * sz.y * 2 ]; +} + +// ---------------------------------------------------------------------- +// crawl_view_geometry +// ---------------------------------------------------------------------- + +crawl_view_geometry::crawl_view_geometry() + : termp(1, 1), termsz(80, 24), + viewp(1, 1), viewsz(33, 17), + hudp(40, 1), hudsz(-1, -1), + msgp(1, viewp.y + viewsz.y), msgsz(80, 7), + mlistp(hudp.x, hudp.y + hudsz.y), + mlistsz(hudsz.x, msgp.y - mlistp.y), + vbuf(), vgrdc(), viewhalfsz(), glos1(), glos2(), + vlos1(), vlos2(), mousep(), last_player_pos() +{ +} + +void crawl_view_geometry::init_view() +{ + viewhalfsz = viewsz / 2; + vbuf.size(viewsz); + set_player_at(you.pos(), true); +} + +void crawl_view_geometry::shift_player_to(const coord_def &c) +{ + // Preserve vgrdc offset after moving. + const coord_def offset = crawl_view.vgrdc - you.pos(); + crawl_view.vgrdc = offset + c; + last_player_pos = c; + + set_player_at(c); + + ASSERT(crawl_view.vgrdc == offset + c); + ASSERT(last_player_pos == c); +} + +void crawl_view_geometry::set_player_at(const coord_def &c, bool centre) +{ + if (centre) + { + vgrdc = c; + } + else + { + const coord_def oldc = vgrdc; + const int xmarg = Options.scroll_margin_x + LOS_RADIUS <= viewhalfsz.x + ? Options.scroll_margin_x + : viewhalfsz.x - LOS_RADIUS; + const int ymarg = Options.scroll_margin_y + LOS_RADIUS <= viewhalfsz.y + ? Options.scroll_margin_y + : viewhalfsz.y - LOS_RADIUS; + + if (Options.view_lock_x) + vgrdc.x = c.x; + else if (c.x - LOS_RADIUS < vgrdc.x - viewhalfsz.x + xmarg) + vgrdc.x = c.x - LOS_RADIUS + viewhalfsz.x - xmarg; + else if (c.x + LOS_RADIUS > vgrdc.x + viewhalfsz.x - xmarg) + vgrdc.x = c.x + LOS_RADIUS - viewhalfsz.x + xmarg; + + if (Options.view_lock_y) + vgrdc.y = c.y; + else if (c.y - LOS_RADIUS < vgrdc.y - viewhalfsz.y + ymarg) + vgrdc.y = c.y - LOS_RADIUS + viewhalfsz.y - ymarg; + else if (c.y + LOS_RADIUS > vgrdc.y + viewhalfsz.y - ymarg) + vgrdc.y = c.y + LOS_RADIUS - viewhalfsz.y + ymarg; + + if (vgrdc != oldc && Options.center_on_scroll) + vgrdc = c; + + if (!Options.center_on_scroll && Options.symmetric_scroll + && !Options.view_lock_x + && !Options.view_lock_y + && (c - last_player_pos).abs() == 2 + && (vgrdc - oldc).abs() == 1) + { + const coord_def dp = c - last_player_pos; + const coord_def dc = vgrdc - oldc; + if ((dc.x == dp.x) != (dc.y == dp.y)) + vgrdc = oldc + dp; + } + } + + glos1 = c - coord_def(LOS_RADIUS, LOS_RADIUS); + glos2 = c + coord_def(LOS_RADIUS, LOS_RADIUS); + + vlos1 = glos1 - vgrdc + view_centre(); + vlos2 = glos2 - vgrdc + view_centre(); + + last_player_pos = c; +} + +void crawl_view_geometry::init_geometry() +{ + termsz = coord_def( get_number_of_cols(), get_number_of_lines() ); + hudsz = coord_def(HUD_WIDTH, + HUD_HEIGHT + (Options.show_gold_turns ? 1 : 0)); + + const _inline_layout lay_inline(termsz, hudsz); + const _mlist_col_layout lay_mlist(termsz, hudsz); + + if (! lay_inline.valid) + { +#ifndef USE_TILE + // Terminal too small; exit with an error. + if (!crawl_state.need_save) + { + end(1, false, "Terminal too small (%d,%d); need at least (%d,%d)", + termsz.x, termsz.y, + termsz.x + std::max(0, -lay_inline.leftover_x()), + termsz.y + std::max(0, -lay_inline.leftover_y())); + } +#endif + } + + const _layout* winner = &lay_inline; + if (Options.mlist_allow_alternate_layout + && !Options.classic_hud + && lay_mlist.valid) + { + winner = &lay_mlist; + } + + msgp = winner->msgp; + msgsz = winner->msgsz; + viewp = winner->viewp; + viewsz = winner->viewsz; + hudp = winner->hudp; + hudsz = winner->hudsz; + mlistp = winner->mlistp; + mlistsz = winner->mlistsz; + +#ifdef USE_TILE + // libgui may redefine these based on its own settings. + gui_init_view_params(*this); +#endif + + init_view(); + return; +} + + diff --git a/crawl-ref/source/viewgeom.h b/crawl-ref/source/viewgeom.h new file mode 100644 index 0000000000..6913849679 --- /dev/null +++ b/crawl-ref/source/viewgeom.h @@ -0,0 +1,145 @@ +#ifndef VIEWGEOM_H +#define VIEWGEOM_H + +class crawl_view_buffer +{ +public: + crawl_view_buffer(); + ~crawl_view_buffer(); + void size(const coord_def &size); + operator screen_buffer_t * () { return (buffer); } + + void draw(); +private: + screen_buffer_t *buffer; +}; + +struct crawl_view_geometry +{ +public: + coord_def termp; // Left-top pos of terminal. + coord_def termsz; // Size of the terminal. + coord_def viewp; // Left-top pos of viewport. + coord_def viewsz; // Size of the viewport (play area). + coord_def hudp; // Left-top pos of status area. + coord_def hudsz; // Size of the status area. + coord_def msgp; // Left-top pos of the message pane. + coord_def msgsz; // Size of the message pane. + coord_def mlistp; // Left-top pos of the monster list. + coord_def mlistsz; // Size of the monster list. + + crawl_view_buffer vbuf; // Buffer for drawing the main game map. + + coord_def vgrdc; // What grid pos is at the centre of the view + // usually you.pos(). + + coord_def viewhalfsz; + + coord_def glos1, glos2; // LOS limit grid coords (inclusive) + coord_def vlos1, vlos2; // LOS limit viewport coords (inclusive) + + coord_def mousep; // Where the mouse is. + +private: + coord_def last_player_pos; + +public: + crawl_view_geometry(); + void init_geometry(); + + void init_view(); + void set_player_at(const coord_def &c, bool force_centre = false); + // Set new location, but preserve scrolling as if the player didn't move. + void shift_player_to(const coord_def &c); + + coord_def view_centre() const + { + return viewp + viewhalfsz; + } + + coord_def glosc() const + { + return (glos1 + glos2) / 2; + } + + bool in_grid_los(const coord_def &c) const + { + return (c.x >= glos1.x && c.x <= glos2.x + && c.y >= glos1.y && c.y <= glos2.y); + } + + bool in_view_los(const coord_def &c) const + { + return (c.x >= vlos1.x && c.x <= vlos2.x + && c.y >= vlos1.y && c.y <= vlos2.y); + } + + bool in_view_viewport(const coord_def &c) const + { + return (c.x >= viewp.x && c.y >= viewp.y + && c.x < viewp.x + viewsz.x + && c.y < viewp.y + viewsz.y); + } + + bool in_grid_viewport(const coord_def &c) const + { + return in_view_viewport(c - vgrdc + view_centre()); + } +}; + +extern crawl_view_geometry crawl_view; + +inline int view2gridX(int vx) +{ + return (crawl_view.vgrdc.x + vx - crawl_view.view_centre().x); +} + +inline int view2gridY(int vy) +{ + return (crawl_view.vgrdc.y + vy - crawl_view.view_centre().y); +} + +inline coord_def view2grid(const coord_def &pos) +{ + return pos - crawl_view.view_centre() + crawl_view.vgrdc; +} + +inline int grid2viewX(int gx) +{ + return (gx - crawl_view.vgrdc.x + crawl_view.view_centre().x); +} + +inline int grid2viewY(int gy) +{ + return (gy - crawl_view.vgrdc.y + crawl_view.view_centre().y); +} + +inline coord_def grid2view(const coord_def &pos) +{ + return (pos - crawl_view.vgrdc + crawl_view.view_centre()); +} + +inline coord_def view2show(const coord_def &pos) +{ + return (pos - crawl_view.vlos1); +} + +inline coord_def show2view(const coord_def &pos) +{ + return (pos + crawl_view.vlos1); +} + +inline coord_def grid2show(const coord_def &pos) +{ + return (view2show(grid2view(pos))); +} + +inline coord_def show2grid(const coord_def &pos) +{ + return (view2grid(show2view(pos))); +} + +#endif + + + diff --git a/crawl-ref/source/viewmap.cc b/crawl-ref/source/viewmap.cc new file mode 100644 index 0000000000..b7d2f066e1 --- /dev/null +++ b/crawl-ref/source/viewmap.cc @@ -0,0 +1,1188 @@ +/* + * File: viewmap.cc + * Summary: Showing the level map (X and background). + */ + +#include "AppHdr.h" + +#include "viewmap.h" + +#include "branch.h" +#include "cio.h" +#include "colour.h" +#include "command.h" +#include "coord.h" +#include "env.h" +#include "envmap.h" +#include "exclude.h" +#include "feature.h" +#include "files.h" +#include "format.h" +#include "macro.h" +#include "mon-util.h" +#include "options.h" +#include "place.h" +#include "player.h" +#include "stash.h" +#include "stuff.h" +#include "terrain.h" +#include "travel.h" +#include "viewgeom.h" + +unsigned get_sightmap_char(dungeon_feature_type feat) +{ + return (get_feature_def(feat).symbol); +} + +unsigned get_magicmap_char(dungeon_feature_type feat) +{ + return (get_feature_def(feat).magic_symbol); +} + +// Determines if the given feature is present at (x, y) in _feat_ coordinates. +// If you have map coords, add (1, 1) to get grid coords. +// Use one of +// 1. '<' and '>' to look for stairs +// 2. '\t' or '\\' for shops, portals. +// 3. '^' for traps +// 4. '_' for altars +// 5. Anything else will look for the exact same character in the level map. +bool is_feature(int feature, const coord_def& where) +{ + if (!env.map(where).object && !see_cell(where)) + return (false); + + dungeon_feature_type grid = grd(where); + + switch (feature) + { + case 'E': + return (travel_point_distance[where.x][where.y] == PD_EXCLUDED); + case 'F': + case 'W': + return is_waypoint(where); + case 'I': + return is_stash(where.x, where.y); + case '_': + switch (grid) + { + 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: + case DNGN_ALTAR_LUGONU: + case DNGN_ALTAR_BEOGH: + case DNGN_ALTAR_JIYVA: + case DNGN_ALTAR_FEAWN: + case DNGN_ALTAR_CHEIBRIADOS: + return (true); + default: + return (false); + } + case '\t': + case '\\': + switch (grid) + { + case DNGN_ENTER_HELL: + case DNGN_EXIT_HELL: + case DNGN_ENTER_LABYRINTH: + case DNGN_ENTER_PORTAL_VAULT: + case DNGN_EXIT_PORTAL_VAULT: + 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_ENTER_PANDEMONIUM: + case DNGN_EXIT_PANDEMONIUM: + case DNGN_TRANSIT_PANDEMONIUM: + case DNGN_ENTER_ZOT: + case DNGN_RETURN_FROM_ZOT: + return (true); + default: + return (false); + } + case '<': + switch (grid) + { + case DNGN_ESCAPE_HATCH_UP: + case DNGN_STONE_STAIRS_UP_I: + case DNGN_STONE_STAIRS_UP_II: + case DNGN_STONE_STAIRS_UP_III: + 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_FROM_SHOALS: + case DNGN_EXIT_PORTAL_VAULT: + return (true); + default: + return (false); + } + case '>': + switch (grid) + { + case DNGN_ESCAPE_HATCH_DOWN: + case DNGN_STONE_STAIRS_DOWN_I: + case DNGN_STONE_STAIRS_DOWN_II: + case DNGN_STONE_STAIRS_DOWN_III: + 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_SHOALS: + return (true); + default: + return (false); + } + case '^': + switch (grid) + { + case DNGN_TRAP_MECHANICAL: + case DNGN_TRAP_MAGICAL: + case DNGN_TRAP_NATURAL: + return (true); + default: + return (false); + } + default: + return get_envmap_char(where.x, where.y) == (unsigned) feature; + } +} + +static bool _is_feature_fudged(int feature, const coord_def& where) +{ + if (!env.map(where).object) + return (false); + + if (is_feature(feature, where)) + return (true); + + // 'grid' can fit in an unsigned char, but making this a short shuts up + // warnings about out-of-range case values. + short grid = grd(where); + + if (feature == '<') + { + switch (grid) + { + case DNGN_EXIT_HELL: + case DNGN_EXIT_PORTAL_VAULT: + case DNGN_EXIT_ABYSS: + case DNGN_EXIT_PANDEMONIUM: + case DNGN_RETURN_FROM_ZOT: + return (true); + default: + return (false); + } + } + else if (feature == '>') + { + switch (grid) + { + case DNGN_ENTER_DIS: + case DNGN_ENTER_GEHENNA: + case DNGN_ENTER_COCYTUS: + case DNGN_ENTER_TARTARUS: + case DNGN_TRANSIT_PANDEMONIUM: + case DNGN_ENTER_ZOT: + return (true); + default: + return (false); + } + } + + return (false); +} + +static int _find_feature(int feature, int curs_x, int curs_y, + int start_x, int start_y, int anchor_x, int anchor_y, + int ignore_count, int *move_x, int *move_y) +{ + int cx = anchor_x, + cy = anchor_y; + + int firstx = -1, firsty = -1; + int matchcount = 0; + + // Find the first occurrence of feature 'feature', spiralling around (x,y) + int maxradius = GXM > GYM ? GXM : GYM; + for (int radius = 1; radius < maxradius; ++radius) + for (int axis = -2; axis < 2; ++axis) + { + int rad = radius - (axis < 0); + for (int var = -rad; var <= rad; ++var) + { + int dx = radius, dy = var; + if (axis % 2) + dx = -dx; + if (axis < 0) + { + int temp = dx; + dx = dy; + dy = temp; + } + + int x = cx + dx, y = cy + dy; + if (!in_bounds(x, y)) + continue; + if (_is_feature_fudged(feature, coord_def(x, y))) + { + ++matchcount; + if (!ignore_count--) + { + // We want to cursor to (x,y) + *move_x = x - (start_x + curs_x - 1); + *move_y = y - (start_y + curs_y - 1); + return matchcount; + } + else if (firstx == -1) + { + firstx = x; + firsty = y; + } + } + } + } + + // We found something, but ignored it because of an ignorecount + if (firstx != -1) + { + *move_x = firstx - (start_x + curs_x - 1); + *move_y = firsty - (start_y + curs_y - 1); + return 1; + } + return 0; +} + +void find_features(const std::vector& features, + unsigned char feature, std::vector *found) +{ + for (unsigned feat = 0; feat < features.size(); ++feat) + { + const coord_def& coord = features[feat]; + if (is_feature(feature, coord)) + found->push_back(coord); + } +} + +static int _find_feature( const std::vector& features, + int feature, int curs_x, int curs_y, + int start_x, int start_y, + int ignore_count, + int *move_x, int *move_y, + bool forward) +{ + int firstx = -1, firsty = -1, firstmatch = -1; + int matchcount = 0; + + for (unsigned feat = 0; feat < features.size(); ++feat) + { + const coord_def& coord = features[feat]; + + if (_is_feature_fudged(feature, coord)) + { + ++matchcount; + if (forward? !ignore_count-- : --ignore_count == 1) + { + // We want to cursor to (x,y) + *move_x = coord.x - (start_x + curs_x - 1); + *move_y = coord.y - (start_y + curs_y - 1); + return matchcount; + } + else if (!forward || firstx == -1) + { + firstx = coord.x; + firsty = coord.y; + firstmatch = matchcount; + } + } + } + + // We found something, but ignored it because of an ignorecount + if (firstx != -1) + { + *move_x = firstx - (start_x + curs_x - 1); + *move_y = firsty - (start_y + curs_y - 1); + return firstmatch; + } + return 0; +} + +static int _get_number_of_lines_levelmap() +{ + return get_number_of_lines() - (Options.level_map_title ? 1 : 0); +} + +#ifndef USE_TILE +static std::string _level_description_string() +{ + if (you.level_type == LEVEL_PANDEMONIUM) + return "- Pandemonium"; + + if (you.level_type == LEVEL_ABYSS) + return "- The Abyss"; + + if (you.level_type == LEVEL_LABYRINTH) + return "- a Labyrinth"; + + if (you.level_type == LEVEL_PORTAL_VAULT) + { + if (!you.level_type_name.empty()) + return "- " + article_a(upcase_first(you.level_type_name)); + return "- a Portal Chamber"; + } + + // level_type == LEVEL_DUNGEON + char buf[200]; + const int youbranch = you.where_are_you; + if ( branches[youbranch].depth == 1 ) + snprintf(buf, sizeof buf, "- %s", branches[youbranch].longname); + else + { + const int curr_subdungeon_level = player_branch_depth(); + snprintf(buf, sizeof buf, "%d of %s", curr_subdungeon_level, + branches[youbranch].longname); + } + return buf; +} + +static void _draw_level_map(int start_x, int start_y, bool travel_mode, + bool on_level) +{ + int bufcount2 = 0; + screen_buffer_t buffer2[GYM * GXM * 2]; + + const int num_lines = std::min(_get_number_of_lines_levelmap(), GYM); + const int num_cols = std::min(get_number_of_cols(), GXM); + + cursor_control cs(false); + + int top = 1 + Options.level_map_title; + if (Options.level_map_title) + { + const formatted_string help = + formatted_string::parse_string("(Press ? for help)"); + const int helplen = std::string(help).length(); + + cgotoxy(1, 1); + textcolor(WHITE); + cprintf("%-*s", + get_number_of_cols() - helplen, + ("Level " + _level_description_string()).c_str()); + + textcolor(LIGHTGREY); + cgotoxy(get_number_of_cols() - helplen + 1, 1); + help.display(); + } + + cgotoxy(1, top); + + for (int screen_y = 0; screen_y < num_lines; screen_y++) + for (int screen_x = 0; screen_x < num_cols; screen_x++) + { + screen_buffer_t colour = DARKGREY; + + coord_def c(start_x + screen_x, start_y + screen_y); + + if (!map_bounds(c)) + { + buffer2[bufcount2 + 1] = DARKGREY; + buffer2[bufcount2] = 0; + } + else + { + colour = colour_code_map(c, + Options.item_colour, + travel_mode, + on_level); + + buffer2[bufcount2 + 1] = colour; + buffer2[bufcount2] = env.map(c).glyph(); + + if (c == you.pos() && !crawl_state.arena_suspended && on_level) + { + // [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]; + unsigned char ch = is_waypoint(c); + if (ch && (bc == get_sightmap_char(DNGN_FLOOR) + || bc == get_magicmap_char(DNGN_FLOOR))) + { + bc = ch; + } + } + } + + bufcount2 += 2; + } + + puttext(1, top, num_cols, top + num_lines - 1, buffer2); +} +#endif // USE_TILE + +static void _reset_travel_colours(std::vector &features, + bool on_level) +{ + // We now need to redo travel colours. + features.clear(); + + if (on_level) + { + find_travel_pos((on_level ? you.pos() : coord_def()), + NULL, NULL, &features); + } + else + { + travel_pathfind tp; + tp.set_feature_vector(&features); + tp.get_features(); + } + + // Sort features into the order the player is likely to prefer. + arrange_features(features); +} + + +class levelview_excursion : public level_excursion +{ +public: + void go_to(const level_id& next) + { +#ifdef USE_TILE + tiles.clear_minimap(); + level_excursion::go_to(next); + TileNewLevel(false); +#else + level_excursion::go_to(next); +#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( level_pos &spec_place, bool travel_mode, bool allow_esc ) +{ + levelview_excursion le; + level_id original(level_id::current()); + + cursor_control ccon(!Options.use_fake_cursor); + int i, j; + + int move_x = 0, move_y = 0, scroll_y = 0; + + bool new_level = true; + + // Vector to track all features we can travel to, in order of distance. + std::vector features; + + int min_x = INT_MAX, max_x = INT_MIN, min_y = INT_MAX, max_y = INT_MIN; + const int num_lines = _get_number_of_lines_levelmap(); + const int half_screen = (num_lines - 1) / 2; + + const int top = 1 + Options.level_map_title; + + int map_lines = 0; + + int start_x = -1; // no x scrolling + const int block_step = Options.level_map_cursor_step; + int start_y; // y does scroll + + int screen_y = -1; + + int curs_x = -1, curs_y = -1; + int search_found = 0, anchor_x = -1, anchor_y = -1; + + bool map_alive = true; + bool redraw_map = true; + +#ifndef USE_TILE + clrscr(); +#endif + textcolor(DARKGREY); + + bool on_level = false; + + while (map_alive) + { + if (new_level) + { + on_level = (level_id::current() == original); + + move_x = 0, move_y = 0, scroll_y = 0; + + // Vector to track all features we can travel to, in order of distance. + if (travel_mode) + { + travel_init_new_level(); + travel_cache.update(); + + _reset_travel_colours(features, on_level); + } + + min_x = GXM, max_x = 0, min_y = 0, max_y = 0; + bool found_y = false; + + for (j = 0; j < GYM; j++) + for (i = 0; i < GXM; i++) + { + if (env.map[i][j].known()) + { + if (!found_y) + { + found_y = true; + min_y = j; + } + + max_y = j; + + if (i < min_x) + min_x = i; + + if (i > max_x) + max_x = i; + } + } + + map_lines = max_y - min_y + 1; + + start_x = min_x + (max_x - min_x + 1) / 2 - 40; // no x scrolling + start_y = 0; // y does scroll + + coord_def reg; + + if (on_level) + { + reg = you.pos(); + } + else + { + reg.y = min_y + (max_y - min_y + 1) / 2; + reg.x = min_x + (max_x - min_x + 1) / 2; + } + + screen_y = reg.y; + + // If close to top of known map, put min_y on top + // else if close to bottom of known map, put max_y on bottom. + // + // The num_lines comparisons are done to keep things neat, by + // keeping things at the top of the screen. By shifting an + // additional one in the num_lines > map_lines case, we can + // keep the top line clear... which makes things look a whole + // lot better for small maps. + if (num_lines > map_lines) + screen_y = min_y + half_screen - 1; + else if (num_lines == map_lines || screen_y - half_screen < min_y) + screen_y = min_y + half_screen; + else if (screen_y + half_screen > max_y) + screen_y = max_y - half_screen; + + curs_x = reg.x - start_x + 1; + curs_y = reg.y - screen_y + half_screen + 1; + search_found = 0, anchor_x = -1, anchor_y = -1; + + redraw_map = true; + new_level = false; + } + +#if defined(USE_UNIX_SIGNALS) && defined(SIGHUP_SAVE) && defined(USE_CURSES) + // If we've received a HUP signal then the user can't choose a + // location, so indicate this by returning an invalid position. + if (crawl_state.seen_hups) + { + spec_place = level_pos(); + break; + } +#endif + + start_y = screen_y - half_screen; + + move_x = move_y = 0; + + if (redraw_map) + { +#ifdef USE_TILE + // Note: Tile versions just center on the current cursor + // location. It silently ignores everything else going + // on in this function. --Enne + coord_def cen(start_x + curs_x - 1, start_y + curs_y - 1); + tiles.load_dungeon(cen); +#else + _draw_level_map(start_x, start_y, travel_mode, on_level); + +#ifdef WIZARD + if (you.wizard) + { + cgotoxy(get_number_of_cols() / 2, 1); + textcolor(WHITE); + cprintf("(%d, %d)", start_x + curs_x - 1, + start_y + curs_y - 1); + + textcolor(LIGHTGREY); + cgotoxy(curs_x, curs_y + top - 1); + } +#endif // WIZARD + +#endif // USE_TILE + } +#ifndef USE_TILE + cursorxy(curs_x, curs_y + top - 1); +#endif + redraw_map = true; + + c_input_reset(true); + int key = unmangle_direction_keys(getchm(KMC_LEVELMAP), KMC_LEVELMAP, + false, false); + command_type cmd = key_to_command(key, KMC_LEVELMAP); + if (cmd < CMD_MIN_OVERMAP || cmd > CMD_MAX_OVERMAP) + cmd = CMD_NO_CMD; + + if (key == CK_MOUSE_CLICK) + { + const c_mouse_event cme = get_mouse_event(); + const coord_def curp(start_x + curs_x - 1, start_y + curs_y - 1); + const coord_def grdp = + cme.pos + coord_def(start_x - 1, start_y - top); + + if (cme.left_clicked() && in_bounds(grdp)) + { + spec_place = level_pos(level_id::current(), grdp); + map_alive = false; + } + else if (cme.scroll_up()) + scroll_y = -block_step; + else if (cme.scroll_down()) + scroll_y = block_step; + else if (cme.right_clicked()) + { + const coord_def delta = grdp - curp; + move_y = delta.y; + move_x = delta.x; + } + } + + c_input_reset(false); + + switch (cmd) + { + case CMD_MAP_HELP: + show_levelmap_help(); + break; + + case CMD_MAP_CLEAR_MAP: + clear_map(); + break; + + case CMD_MAP_FORGET: + forget_map(100, true); + break; + + case CMD_MAP_ADD_WAYPOINT: + travel_cache.add_waypoint(start_x + curs_x - 1, + start_y + curs_y - 1); + // We need to do this all over again so that the user can jump + // to the waypoint he just created. + _reset_travel_colours(features, on_level); + break; + + // Cycle the radius of an exclude. + case CMD_MAP_EXCLUDE_AREA: + { + const coord_def p(start_x + curs_x - 1, start_y + curs_y - 1); + cycle_exclude_radius(p); + + _reset_travel_colours(features, on_level); + break; + } + + case CMD_MAP_CLEAR_EXCLUDES: + clear_excludes(); + _reset_travel_colours(features, on_level); + break; + + case CMD_MAP_MOVE_DOWN_LEFT: + move_x = -1; + move_y = 1; + break; + + case CMD_MAP_MOVE_DOWN: + move_y = 1; + move_x = 0; + break; + + case CMD_MAP_MOVE_UP_RIGHT: + move_x = 1; + move_y = -1; + break; + + case CMD_MAP_MOVE_UP: + move_y = -1; + move_x = 0; + break; + + case CMD_MAP_MOVE_UP_LEFT: + move_y = -1; + move_x = -1; + break; + + case CMD_MAP_MOVE_LEFT: + move_x = -1; + move_y = 0; + break; + + case CMD_MAP_MOVE_DOWN_RIGHT: + move_y = 1; + move_x = 1; + break; + + case CMD_MAP_MOVE_RIGHT: + move_x = 1; + move_y = 0; + break; + + case CMD_MAP_PREV_LEVEL: + case CMD_MAP_NEXT_LEVEL: { + level_id next; + + next = (cmd == CMD_MAP_PREV_LEVEL) + ? find_up_level(level_id::current()) + : find_down_level(level_id::current()); + + if (next.is_valid() && next != level_id::current() + && is_existing_level(next)) + { + le.go_to(next); + new_level = true; + } + break; + } + + case CMD_MAP_GOTO_LEVEL: { + std::string name; + const level_pos pos = + prompt_translevel_target(TPF_DEFAULT_OPTIONS, name).p; + + if (pos.id.depth < 1 || pos.id.depth > branches[pos.id.branch].depth + || !is_existing_level(pos.id)) + { + canned_msg(MSG_OK); + redraw_map = true; + break; + } + + le.go_to(pos.id); + new_level = true; + break; + } + + case CMD_MAP_JUMP_DOWN_LEFT: + move_x = -block_step; + move_y = block_step; + break; + + case CMD_MAP_JUMP_DOWN: + move_y = block_step; + move_x = 0; + break; + + case CMD_MAP_JUMP_UP_RIGHT: + move_x = block_step; + move_y = -block_step; + break; + + case CMD_MAP_JUMP_UP: + move_y = -block_step; + move_x = 0; + break; + + case CMD_MAP_JUMP_UP_LEFT: + move_y = -block_step; + move_x = -block_step; + break; + + case CMD_MAP_JUMP_LEFT: + move_x = -block_step; + move_y = 0; + break; + + case CMD_MAP_JUMP_DOWN_RIGHT: + move_y = block_step; + move_x = block_step; + break; + + case CMD_MAP_JUMP_RIGHT: + move_x = block_step; + move_y = 0; + break; + + case CMD_MAP_SCROLL_DOWN: + move_y = 20; + move_x = 0; + scroll_y = 20; + break; + + case CMD_MAP_SCROLL_UP: + move_y = -20; + move_x = 0; + scroll_y = -20; + break; + + case CMD_MAP_FIND_YOU: + if (on_level) + { + move_x = you.pos().x - (start_x + curs_x - 1); + move_y = you.pos().y - (start_y + curs_y - 1); + } + break; + + case CMD_MAP_FIND_UPSTAIR: + case CMD_MAP_FIND_DOWNSTAIR: + case CMD_MAP_FIND_PORTAL: + case CMD_MAP_FIND_TRAP: + case CMD_MAP_FIND_ALTAR: + case CMD_MAP_FIND_EXCLUDED: + case CMD_MAP_FIND_F: + case CMD_MAP_FIND_WAYPOINT: + case CMD_MAP_FIND_STASH: + case CMD_MAP_FIND_STASH_REVERSE: + { + bool forward = (cmd != CMD_MAP_FIND_STASH_REVERSE); + + int getty; + switch (cmd) + { + case CMD_MAP_FIND_UPSTAIR: + getty = '<'; + break; + case CMD_MAP_FIND_DOWNSTAIR: + getty = '>'; + break; + case CMD_MAP_FIND_PORTAL: + getty = '\t'; + break; + case CMD_MAP_FIND_TRAP: + getty = '^'; + break; + case CMD_MAP_FIND_ALTAR: + getty = '_'; + break; + case CMD_MAP_FIND_EXCLUDED: + getty = 'E'; + break; + case CMD_MAP_FIND_F: + getty = 'F'; + break; + case CMD_MAP_FIND_WAYPOINT: + getty = 'W'; + break; + default: + case CMD_MAP_FIND_STASH: + case CMD_MAP_FIND_STASH_REVERSE: + getty = 'I'; + break; + } + + if (anchor_x == -1) + { + anchor_x = start_x + curs_x - 1; + anchor_y = start_y + curs_y - 1; + } + if (travel_mode) + { + search_found = _find_feature(features, getty, curs_x, curs_y, + start_x, start_y, + search_found, + &move_x, &move_y, + forward); + } + else + { + search_found = _find_feature(getty, curs_x, curs_y, + start_x, start_y, + anchor_x, anchor_y, + search_found, &move_x, &move_y); + } + break; + } + + case CMD_MAP_GOTO_TARGET: + { + int x = start_x + curs_x - 1, y = start_y + curs_y - 1; + if (travel_mode && on_level && x == you.pos().x && y == you.pos().y) + { + if (you.travel_x > 0 && you.travel_y > 0) + { + move_x = you.travel_x - x; + move_y = you.travel_y - y; + } + break; + } + else + { + spec_place = level_pos(level_id::current(), coord_def(x, y)); + map_alive = false; + break; + } + } + +#ifdef WIZARD + case CMD_MAP_WIZARD_TELEPORT: + { + if (!you.wizard) + break; + if (!on_level) + break; + const coord_def pos(start_x + curs_x - 1, start_y + curs_y - 1); + if (!in_bounds(pos)) + break; + you.moveto(pos); + map_alive = false; + break; + } +#endif + + case CMD_MAP_EXIT_MAP: + if (allow_esc) + { + spec_place = level_pos(); + map_alive = false; + break; + } + default: + if (travel_mode) + { + map_alive = false; + break; + } + redraw_map = false; + continue; + } + + if (!map_alive) + break; + +#ifdef USE_TILE + { + int new_x = start_x + curs_x + move_x - 1; + int new_y = start_y + curs_y + move_y - 1; + + curs_x += (new_x < 1 || new_x > GXM) ? 0 : move_x; + curs_y += (new_y < 1 || new_y > GYM) ? 0 : move_y; + } +#else + if (curs_x + move_x < 1 || curs_x + move_x > crawl_view.termsz.x) + move_x = 0; + + curs_x += move_x; + + if (num_lines < map_lines) + { + // Scrolling only happens when we don't have a large enough + // display to show the known map. + if (scroll_y != 0) + { + const int old_screen_y = screen_y; + screen_y += scroll_y; + if (scroll_y < 0) + screen_y = std::max(screen_y, min_y + half_screen); + else + screen_y = std::min(screen_y, max_y - half_screen); + curs_y -= (screen_y - old_screen_y); + scroll_y = 0; + } + + if (curs_y + move_y < 1) + { + screen_y += move_y; + + if (screen_y < min_y + half_screen) + { + move_y = screen_y - (min_y + half_screen); + screen_y = min_y + half_screen; + } + else + move_y = 0; + } + + if (curs_y + move_y > num_lines) + { + screen_y += move_y; + + if (screen_y > max_y - half_screen) + { + move_y = screen_y - (max_y - half_screen); + screen_y = max_y - half_screen; + } + else + move_y = 0; + } + } + + if (curs_y + move_y < 1 || curs_y + move_y > num_lines) + move_y = 0; + + curs_y += move_y; +#endif + } + + le.go_to(original); + + travel_init_new_level(); + travel_cache.update(); +} + +static char _get_travel_colour( const coord_def& p ) +{ + if (is_waypoint(p)) + return LIGHTGREEN; + + short dist = travel_point_distance[p.x][p.y]; + 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; +} + +bool emphasise(const coord_def& where, dungeon_feature_type feat) +{ + return (is_unknown_stair(where, feat) + && (you.your_level || feat_stair_direction(feat) == CMD_GO_DOWNSTAIRS) + && you.where_are_you != BRANCH_VESTIBULE_OF_HELL); +} + +screen_buffer_t colour_code_map(const coord_def& p, bool item_colour, + bool travel_colour, bool on_level) +{ + if (!is_terrain_known(p)) + return (BLACK); + +#ifdef WIZARD + if (travel_colour && you.wizard + && testbits(env.map(p).property, FPROP_HIGHLIGHT)) + { + return (LIGHTGREEN); + } +#endif + + dungeon_feature_type feat_value = grd(p); + if (!see_cell(p)) + { + const show_type remembered = get_envmap_obj(p); + if (remembered.cls == SH_FEATURE) + feat_value = remembered.feat; + } + + unsigned tc = travel_colour ? _get_travel_colour(p) : DARKGREY; + + if (is_envmap_detected_item(p)) + return real_colour(Options.detected_item_colour); + + if (is_envmap_detected_mons(p)) + { + tc = Options.detected_monster_colour; + return real_colour(tc); + } + + // If this is an important travel square, don't allow the colour + // to be overridden. + if (is_waypoint(p) || travel_point_distance[p.x][p.y] == PD_EXCLUDED) + return real_colour(tc); + + if (item_colour && is_envmap_item(p)) + return get_envmap_col(p); + + int feature_colour = DARKGREY; + const bool terrain_seen = is_terrain_seen(p); + const feature_def &fdef = get_feature_def(feat_value); + feature_colour = terrain_seen ? fdef.seen_colour : fdef.map_colour; + + if (terrain_seen && fdef.seen_em_colour && emphasise(p, feat_value)) + feature_colour = fdef.seen_em_colour; + + if (feature_colour != DARKGREY) + tc = feature_colour; + else if (you.duration[DUR_MESMERISED] && on_level) + { + // If mesmerised, colour the few grids that can be reached anyway + // lightgrey. + const monsters *blocker = monster_at(p); + const bool seen_blocker = blocker && you.can_see(blocker); + if (grd(p) >= DNGN_MINMOVE && !seen_blocker) + { + bool blocked_movement = false; + for (unsigned int i = 0; i < you.mesmerised_by.size(); i++) + { + const monsters& mon = menv[you.mesmerised_by[i]]; + const int olddist = grid_distance(you.pos(), mon.pos()); + const int newdist = grid_distance(p, mon.pos()); + + if (olddist < newdist || !see_cell(env.show_los, p, mon.pos())) + { + blocked_movement = true; + break; + } + } + if (!blocked_movement) + tc = LIGHTGREY; + } + } + + if (Options.feature_item_brand + && is_critical_feature(feat_value) + && igrd(p) != NON_ITEM) + { + tc |= COLFLAG_FEATURE_ITEM; + } + else if (Options.trap_item_brand + && feat_is_trap(feat_value) && igrd(p) != NON_ITEM) + { + // FIXME: this uses the real igrd, which the player shouldn't + // be aware of. + tc |= COLFLAG_TRAP_ITEM; + } + + return real_colour(tc); +} + + diff --git a/crawl-ref/source/viewmap.h b/crawl-ref/source/viewmap.h new file mode 100644 index 0000000000..c5ab21e394 --- /dev/null +++ b/crawl-ref/source/viewmap.h @@ -0,0 +1,10 @@ +#ifndef VIEWMAP_H +#define VIEWMAP_H + +screen_buffer_t colour_code_map(const coord_def& p, bool item_colour = false, + bool travel_colour = false, bool on_level = true); + +bool emphasise(const coord_def& where, dungeon_feature_type feat); + +#endif + diff --git a/crawl-ref/source/xom.cc b/crawl-ref/source/xom.cc index e20073681f..a1f0b98fcc 100644 --- a/crawl-ref/source/xom.cc +++ b/crawl-ref/source/xom.cc @@ -15,6 +15,7 @@ #include "delay.h" #include "directn.h" #include "effects.h" +#include "envmap.h" #include "feature.h" #include "goditem.h" #include "it_use2.h" @@ -51,6 +52,7 @@ #include "transfor.h" #include "traps.h" #include "view.h" +#include "viewchar.h" #include "xom.h" #ifdef DEBUG_XOM -- cgit v1.2.3-54-g00ecf