diff options
Diffstat (limited to 'crawl-ref/source')
53 files changed, 1649 insertions, 557 deletions
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index 0af35133f6..2cd7011704 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -101,6 +101,7 @@ #include "luadgn.h" #include "macro.h" #include "makeitem.h" +#include "mapmark.h" #include "maps.h" #include "message.h" #include "misc.h" @@ -236,6 +237,10 @@ int main( int argc, char *argv[] ) << " " << you.class_name << "." << std::endl; + // Activate markers only after the welcome message, so the + // player can see any resulting messages. + env_activate_markers(); + // Starting messages can go here as this should only happen // at the start of a new game -- bwr // This message isn't appropriate for Options.always_greet @@ -983,7 +988,7 @@ static bool toggle_flag( bool* flag, const char* flagname ) static void go_downstairs(); static void go_upstairs() { - const int ygrd = grd(you.pos()); + const dungeon_feature_type ygrd = grd(you.pos()); // Allow both < and > to work for Abyss exits. if (ygrd == DNGN_EXIT_ABYSS) @@ -1000,10 +1005,7 @@ static void go_upstairs() shop(); return; } - else if ((ygrd < DNGN_STONE_STAIRS_UP_I - || ygrd > DNGN_ROCK_STAIRS_UP) - && (ygrd < DNGN_RETURN_FROM_ORCISH_MINES - || ygrd >= 150)) + else if (grid_stair_direction(ygrd) != CMD_GO_UPSTAIRS) { mpr( "You can't go up here!" ); return; @@ -1016,14 +1018,7 @@ static void go_upstairs() static void go_downstairs() { - if ((grd[you.x_pos][you.y_pos] < DNGN_ENTER_LABYRINTH - || grd[you.x_pos][you.y_pos] > DNGN_ROCK_STAIRS_DOWN) - && grd[you.x_pos][you.y_pos] != DNGN_ENTER_HELL - && ((grd[you.x_pos][you.y_pos] < DNGN_ENTER_DIS - || grd[you.x_pos][you.y_pos] > DNGN_TRANSIT_PANDEMONIUM) - && grd[you.x_pos][you.y_pos] != DNGN_STONE_ARCH) - && !(grd[you.x_pos][you.y_pos] >= DNGN_ENTER_ORCISH_MINES - && grd[you.x_pos][you.y_pos] < DNGN_RETURN_FROM_ORCISH_MINES)) + if (grid_stair_direction(grd(you.pos())) != CMD_GO_DOWNSTAIRS) { mpr( "You can't go down here!" ); return; @@ -2247,13 +2242,13 @@ static void world_reacts() // place normal dungeon monsters, but not in player LOS if (you.level_type == LEVEL_DUNGEON && !player_in_branch( BRANCH_ECUMENICAL_TEMPLE ) - && one_chance_in((you.char_direction == DIR_DESCENDING) ? 240 : 8)) + && one_chance_in((you.char_direction == GDT_DESCENDING) ? 240 : 8)) { proximity_type prox = (one_chance_in(10) ? PROX_NEAR_STAIRS : PROX_AWAY_FROM_PLAYER); // The rules change once the player has picked up the Orb... - if (you.char_direction == DIR_ASCENDING) + if (you.char_direction == GDT_ASCENDING) prox = (one_chance_in(6) ? PROX_CLOSE_TO_PLAYER : PROX_ANYWHERE); mons_place( WANDERING_MONSTER, BEH_HOSTILE, MHITNOT, false, @@ -2276,7 +2271,7 @@ static void world_reacts() viewwindow(true, false); } - // No monsters in the Labyrinth, or the Ecumenical Temple + // No monsters in the Labyrinth, or the Ecumenical Temple, or in Bazaars. return; } @@ -2866,7 +2861,7 @@ static bool initialise(void) } #ifdef CLUA_BINDINGS - clua.runhook("chk_startgame", "%b", newc); + clua.runhook("chk_startgame", "b", newc); std::string yname = you.your_name; read_init_file(true); strncpy(you.your_name, yname.c_str(), kNameLen); diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc index 38985e7100..fbd4c8407f 100644 --- a/crawl-ref/source/beam.cc +++ b/crawl-ref/source/beam.cc @@ -2383,7 +2383,7 @@ void beam_drop_object( bolt &beam, item_def *item, int x, int y ) if ( grid_destroys_items(grd[x][y]) ) { // Too much message spam otherwise - if ( YOU_KILL(beam.thrower) ) + if ( YOU_KILL(beam.thrower) && player_can_hear(x, y) ) mprf(MSGCH_SOUND, grid_item_destruction_message(grd[x][y])); return; } diff --git a/crawl-ref/source/dat/bazaar.des b/crawl-ref/source/dat/bazaar.des new file mode 100644 index 0000000000..94eb6a33ad --- /dev/null +++ b/crawl-ref/source/dat/bazaar.des @@ -0,0 +1,67 @@ +############################################################################### +# bazaar.des - Bazaar entry vaults and bazaar layouts. +############################################################################### + +############################################################################### +# Bazaar entries + +# Utility functions + +lua {{ + function check_expire_marker(e) + if not crawl.one_chance_in(3) then + e.marker("O = timer: 1000") + end + end +}} + +default-depth: D:10-27 + +############################################################################### +# Dummy entry + +NAME: bzr_entry_dummy +TAGS: bzr_entry transparent +ORIENT: float +: check_expire_marker(_G) +MAP +O +ENDMAP + +############################################################################### +# A simple water entry. +NAME: bzr_entry_001 +TAGS: bzr_entry no_pool_fixup +ORIENT: float +SHUFFLE: wwl +: check_expire_marker(_G) +MAP + www +w.w.w +wwOww +w.w.w + www +ENDMAP + +############################################################################### +# Bazaar layouts. +# +# "encompass" levels are recommended, and can be as small or large as you like. +# No monsters are pre-placed in bazaars, and monsters do not spawn in bazaars, +# but you can place monsters in your maps if you know what you're doing. + +NAME: bazaar_001 +TAGS: bazaar +ORIENT: encompass +KFEAT: A = any shop +MAP +xxxxxxxxx +xxxx>xxxx +xxx...xxx +xx..A..xx +x<.A.A.>x +xx..A..xx +xxx...xxx +xxxx>xxxx +xxxxxxxxx +ENDMAP diff --git a/crawl-ref/source/dat/clua/dungeon.lua b/crawl-ref/source/dat/clua/dungeon.lua index 281e181931..c7b585952d 100644 --- a/crawl-ref/source/dat/clua/dungeon.lua +++ b/crawl-ref/source/dat/clua/dungeon.lua @@ -32,6 +32,7 @@ function dgn_map_meta_wrap(map, tab) return crawl.err_trace(val, map, ...) end end + meta['_G'] = meta meta.wrapped_instance = map return meta end diff --git a/crawl-ref/source/dat/clua/loadmaps.lua b/crawl-ref/source/dat/clua/loadmaps.lua index 7d652d7c81..daefb3e0bb 100644 --- a/crawl-ref/source/dat/clua/loadmaps.lua +++ b/crawl-ref/source/dat/clua/loadmaps.lua @@ -7,11 +7,11 @@ ------------------------------------------------------------------------------ local des_files = { - "entry.des", "elf.des", "float.des", "hells.des", "hive.des", "lab.des", - "lair.des", "large.des", "mini.des", "orc.des", "pan.des", "portal.des", - "temple.des", "vaults.des", "zot.des" + "bazaar.des", "entry.des", "elf.des", "float.des", "hells.des", "hive.des", + "lab.des", "lair.des", "large.des", "mini.des", "orc.des", "pan.des", + "portal.des", "temple.des", "vaults.des", "zot.des" } for _, file in ipairs(des_files) do dgn.load_des_file(file) -end
\ No newline at end of file +end diff --git a/crawl-ref/source/dat/hells.des b/crawl-ref/source/dat/hells.des index 81a0ae24c3..05e7d75db8 100644 --- a/crawl-ref/source/dat/hells.des +++ b/crawl-ref/source/dat/hells.des @@ -111,7 +111,8 @@ ENDMAP NAME: vestibule_of_hell PLACE: Hell ORIENT: encompass -MARKER: D=enter_dis, G=enter_gehenna, C=enter_cocytus, T=enter_tartarus +MARKER: D=feat:enter_dis, G=feat:enter_gehenna, C=feat:enter_cocytus +MARKER: T=feat:enter_tartarus SUBST: D=A, G=A, C=A, T=A MONS: Geryon diff --git a/crawl-ref/source/dat/lab.des b/crawl-ref/source/dat/lab.des index f716deb1cf..552846a74f 100644 --- a/crawl-ref/source/dat/lab.des +++ b/crawl-ref/source/dat/lab.des @@ -4,6 +4,17 @@ # flavour vaults (tagged by 'lab'). ############################################################################### +############################################################################# +# Labyrinth entry vaults + +NAME: lab_entry_generic +TAGS: lab_entry transparent +DEPTH: 12-26 +ORIENT: float +MARKER: O = timer:400-600 +MAP +O +ENDMAP ############################################################################# # Labyrinth exit minivaults diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc index 23c023d66c..4e3c27ffe2 100644 --- a/crawl-ref/source/debug.cc +++ b/crawl-ref/source/debug.cc @@ -2271,7 +2271,11 @@ static void mg_build_levels(int niters) if (!mg_do_build_level(niters)) return; you.level_type = LEVEL_PANDEMONIUM; - mg_do_build_level(niters); + if (!mg_do_build_level(niters)) + return; + you.level_type = LEVEL_BAZAAR; + if (!mg_do_build_level(niters)) + return; } void mapgen_report_map_try(const map_def &map) @@ -2333,6 +2337,7 @@ static void write_mapgen_stats() check_mapless(level_id(LEVEL_ABYSS), mapless); check_mapless(level_id(LEVEL_PANDEMONIUM), mapless); check_mapless(level_id(LEVEL_LABYRINTH), mapless); + check_mapless(level_id(LEVEL_BAZAAR), mapless); if (!mapless.empty()) { diff --git a/crawl-ref/source/defines.h b/crawl-ref/source/defines.h index 81611699fb..03269ebd62 100644 --- a/crawl-ref/source/defines.h +++ b/crawl-ref/source/defines.h @@ -121,7 +121,10 @@ #define MAX_TRAPS 100 // max shops per level -#define MAX_SHOPS 5 +#define MAX_SHOPS 15 + +// max shops randomly generated in a level. +#define MAX_RANDOM_SHOPS 5 // lowest grid value which can be passed by walking etc. #define MINMOVE 31 diff --git a/crawl-ref/source/dgnevent.cc b/crawl-ref/source/dgnevent.cc new file mode 100644 index 0000000000..0109c0090a --- /dev/null +++ b/crawl-ref/source/dgnevent.cc @@ -0,0 +1,133 @@ +/* + * File: dgnevent.cc + * Summary: General dungeon events. + * + * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-07-20T11:40:25.964128Z $ + * + */ + +#include "AppHdr.h" +#include "dgnevent.h" +#include "stuff.h" + +dgn_event_dispatcher dungeon_events; + +void dgn_event_dispatcher::clear() +{ + global_event_mask = 0; + listeners.clear(); + for (int y = 0; y < GYM; ++y) + for (int x = 0; x < GXM; ++x) + grid_triggers[x][y].reset(NULL); +} + +void dgn_event_dispatcher::fire_position_event( + dgn_event_type event, const coord_def &pos) +{ + dgn_square_alarm *alarm = grid_triggers[pos.x][pos.y].get(); + if (alarm && (alarm->eventmask & event)) + { + dgn_square_alarm alcopy = *alarm; + const dgn_event et(event, pos); + for (std::list<dgn_event_listener*>::iterator + i = alcopy.listeners.begin(); + i != alcopy.listeners.end(); ++i) + { + (*i)->notify_dgn_event(et); + } + } +} + +void dgn_event_dispatcher::fire_event(const dgn_event &e) +{ + if (global_event_mask & e.type) + { + std::list<dgn_listener_def> lcopy = listeners; + for (std::list<dgn_listener_def>::iterator i = lcopy.begin(); + i != lcopy.end(); ++i) + { + if (i->eventmask & e.type) + i->listener->notify_dgn_event(e); + } + } +} + +void dgn_event_dispatcher::fire_event(dgn_event_type et) +{ + fire_event(dgn_event(et)); +} + +void dgn_event_dispatcher::register_listener(unsigned mask, + dgn_event_listener *listener, + const coord_def &pos) +{ + if (in_bounds(pos)) + register_listener_at(mask, pos, listener); + else + { + global_event_mask |= mask; + for (std::list<dgn_listener_def>::iterator i = listeners.begin(); + i != listeners.end(); ++i) + { + if (i->listener == listener) + { + i->eventmask |= mask; + return; + } + } + listeners.push_back(dgn_listener_def(mask, listener)); + } +} + +void dgn_event_dispatcher::register_listener_at(unsigned mask, + const coord_def &c, + dgn_event_listener *listener) +{ + if (!grid_triggers[c.x][c.y].get()) + grid_triggers[c.x][c.y].reset(new dgn_square_alarm); + + dgn_square_alarm *alarm = grid_triggers[c.x][c.y].get(); + alarm->eventmask |= mask; + if (std::find(alarm->listeners.begin(), alarm->listeners.end(), + listener) == alarm->listeners.end()) + alarm->listeners.push_back(listener); +} + +void dgn_event_dispatcher::remove_listener(dgn_event_listener *listener, + const coord_def &pos) +{ + if (in_bounds(pos)) + remove_listener_at(pos, listener); + else + { + for (std::list<dgn_listener_def>::iterator i = listeners.begin(); + i != listeners.end(); ++i) + { + if (i->listener == listener) + { + listeners.erase(i); + return; + } + } + } +} + +void dgn_event_dispatcher::remove_listener_at(const coord_def &pos, + dgn_event_listener *listener) +{ + if (dgn_square_alarm *alarm = grid_triggers[pos.x][pos.y].get()) + { + std::list<dgn_event_listener*>::iterator i = + std::find(alarm->listeners.begin(), alarm->listeners.end(), + listener); + if (i != alarm->listeners.end()) + alarm->listeners.erase(i); + } +} + +///////////////////////////////////////////////////////////////////////////// +// dgn_event_listener + +dgn_event_listener::~dgn_event_listener() +{ +} diff --git a/crawl-ref/source/dgnevent.h b/crawl-ref/source/dgnevent.h new file mode 100644 index 0000000000..9b22d8c477 --- /dev/null +++ b/crawl-ref/source/dgnevent.h @@ -0,0 +1,105 @@ +/* + * File: dgnevent.h + * Summary: General dungeon events. + * + * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-07-20T11:40:25.964128Z $ + * + */ + +#ifndef __DGNEVENT_H__ +#define __DGNEVENT_H__ + +#include "externs.h" +#include <list> + +enum dgn_event_type +{ + DET_NONE = 0x0000, + + DET_TURN_ELAPSED = 0x0001, + DET_MONSTER_MOVED = 0x0002, + DET_PLAYER_MOVED = 0x0004, + DET_LEAVING_LEVEL = 0x0008, + DET_ENTERING_LEVEL = 0x0010 +}; + +class dgn_event +{ +public: + dgn_event_type type; + coord_def place; + int elapsed_ticks; + +public: + dgn_event(dgn_event_type t, const coord_def &p = coord_def(), + int ticks = you.time_taken) + : type(t), place(p), elapsed_ticks(ticks) + { + } +}; + +class dgn_event_listener +{ +public: + virtual ~dgn_event_listener(); + virtual void notify_dgn_event(const dgn_event &e) = 0; +}; + +// Alarm goes off when something enters this square. +struct dgn_square_alarm +{ +public: + dgn_square_alarm() : eventmask(0), listeners() { } + +public: + unsigned eventmask; + std::list<dgn_event_listener*> listeners; +}; + +struct dgn_listener_def +{ +public: + dgn_listener_def(unsigned mask, dgn_event_listener *l) + : eventmask(mask), listener(l) + { + } + +public: + unsigned eventmask; + dgn_event_listener *listener; +}; + +// Listeners are not saved here. Map markers have their own +// persistence and activation mechanisms. Other listeners must make +// their own persistence arrangements. +class dgn_event_dispatcher +{ +public: + dgn_event_dispatcher() : global_event_mask(0), grid_triggers() + { + } + + void clear(); + + void fire_position_event(dgn_event_type et, const coord_def &pos); + void fire_event(dgn_event_type et); + void fire_event(const dgn_event &e); + + void register_listener(unsigned evmask, dgn_event_listener *, + const coord_def &pos = coord_def()); + void remove_listener(dgn_event_listener *, + const coord_def &pos = coord_def()); +private: + void register_listener_at(unsigned mask, const coord_def &pos, + dgn_event_listener *l); + void remove_listener_at(const coord_def &pos, dgn_event_listener *l); + +private: + unsigned global_event_mask; + std::auto_ptr<dgn_square_alarm> grid_triggers[GXM][GYM]; + std::list<dgn_listener_def> listeners; +}; + +extern dgn_event_dispatcher dungeon_events; + +#endif diff --git a/crawl-ref/source/direct.cc b/crawl-ref/source/direct.cc index 745f662aea..962bc0f82f 100644 --- a/crawl-ref/source/direct.cc +++ b/crawl-ref/source/direct.cc @@ -38,6 +38,7 @@ #include "describe.h" #include "dungeon.h" #include "itemname.h" +#include "mapmark.h" #include "monstuff.h" #include "mon-util.h" #include "player.h" @@ -1190,13 +1191,9 @@ void describe_floor() break; } - feat = feature_description(you.x_pos, you.y_pos); + feat = feature_description(you.x_pos, you.y_pos, DESC_NOCAP_A, false); if (feat.empty()) return; - if (grid != DNGN_ENTER_SHOP) - feat[0] = tolower(feat[0]); - if (ends_with(feat, ".")) - feat = feat.substr(0, feat.length() - 1); mpr((prefix + feat + suffix).c_str()); if (grid == DNGN_ENTER_LABYRINTH) @@ -1204,218 +1201,258 @@ void describe_floor() } std::string feature_description(dungeon_feature_type grid, - trap_type trap) + trap_type trap, + bool temporary, + description_level_type dtype, + bool add_stop) +{ + std::string desc = + raw_feature_description(grid, trap, temporary); + if (add_stop) + desc += "."; + if (dtype == DESC_PLAIN || (!grid_is_trap(grid) && isupper(desc[0]))) + return (desc); + + switch (dtype) + { + case DESC_CAP_THE: + return "The " + desc; + case DESC_NOCAP_THE: + return "the " + desc; + case DESC_CAP_A: + return article_a(desc, false); + case DESC_NOCAP_A: + return article_a(desc, true); + default: + return (desc); + } +} + +std::string raw_feature_description(dungeon_feature_type grid, + trap_type trap, + bool temporary) { if (grid_is_trap(grid) && trap != NUM_TRAPS) { switch (trap) { case TRAP_DART: - return ("A dart trap."); + return ("dart trap"); case TRAP_ARROW: - return ("An arrow trap."); + return ("arrow trap"); case TRAP_SPEAR: - return ("A spear trap."); + return ("spear trap"); case TRAP_AXE: - return ("An axe trap."); + return ("axe trap"); case TRAP_TELEPORT: - return ("A teleportation trap."); + return ("teleportation trap"); case TRAP_AMNESIA: - return ("An amnesia trap."); + return ("amnesia trap"); case TRAP_BLADE: - return ("A blade trap."); + return ("blade trap"); case TRAP_BOLT: - return ("A bolt trap."); + return ("bolt trap"); case TRAP_ZOT: - return ("A Zot trap."); + return ("Zot trap"); case TRAP_NEEDLE: - return ("A needle trap."); + return ("needle trap"); default: error_message_to_player(); - return ("An undefined trap."); + return ("undefined trap"); } } switch (grid) { case DNGN_STONE_WALL: - return ("A stone wall."); + return ("stone wall"); case DNGN_ROCK_WALL: case DNGN_SECRET_DOOR: if (you.level_type == LEVEL_PANDEMONIUM) - return ("A wall of the weird stuff which makes up Pandemonium."); + return ("wall of the weird stuff which makes up Pandemonium"); else - return ("A rock wall."); + return ("rock wall"); case DNGN_PERMAROCK_WALL: - return ("An unnaturally hard rock wall."); + return ("unnaturally hard rock wall"); case DNGN_CLOSED_DOOR: - return ("A closed door."); + return ("closed door"); case DNGN_METAL_WALL: - return ("A metal wall."); + return ("metal wall"); case DNGN_GREEN_CRYSTAL_WALL: - return ("A wall of green crystal."); + return ("wall of green crystal"); case DNGN_ORCISH_IDOL: if (you.species == SP_HILL_ORC) { - return ("An idol of Beogh."); + return ("idol of Beogh"); } - return ("An orcish idol."); + return ("orcish idol"); case DNGN_WAX_WALL: - return ("A wall of solid wax."); + return ("wall of solid wax"); case DNGN_SILVER_STATUE: - return ("A silver statue."); + return ("silver statue"); case DNGN_GRANITE_STATUE: - return ("A granite statue."); + return ("granite statue"); case DNGN_ORANGE_CRYSTAL_STATUE: - return ("An orange crystal statue."); + return ("orange crystal statue"); case DNGN_LAVA: - return ("Some lava."); + return ("Some lava"); case DNGN_DEEP_WATER: - return ("Some deep water."); + return ("Some deep water"); case DNGN_SHALLOW_WATER: - return ("Some shallow water."); + return ("Some shallow water"); case DNGN_UNDISCOVERED_TRAP: case DNGN_FLOOR: - return ("Floor."); + return ("Floor"); case DNGN_OPEN_DOOR: - return ("An open door."); + return ("open door"); case DNGN_ROCK_STAIRS_DOWN: - return ("A rock staircase leading down."); + return ("rock staircase leading down"); case DNGN_STONE_STAIRS_DOWN_I: case DNGN_STONE_STAIRS_DOWN_II: case DNGN_STONE_STAIRS_DOWN_III: - return ("A stone staircase leading down."); + return ("stone staircase leading down"); case DNGN_ROCK_STAIRS_UP: - return ("A rock staircase leading up."); + return ("rock staircase leading up"); case DNGN_STONE_STAIRS_UP_I: case DNGN_STONE_STAIRS_UP_II: case DNGN_STONE_STAIRS_UP_III: - return ("A stone staircase leading up."); + return ("stone staircase leading up"); case DNGN_ENTER_HELL: - return ("A gateway to Hell."); + return ("gateway to Hell"); case DNGN_TRAP_MECHANICAL: - return ("A mechanical trap."); + return ("mechanical trap"); case DNGN_TRAP_MAGICAL: - return ("A magical trap."); + return ("magical trap"); case DNGN_TRAP_III: - return ("A trap."); + return ("trap"); case DNGN_ENTER_SHOP: - return ("A shop."); + return ("shop"); case DNGN_ENTER_LABYRINTH: - return ("A labyrinth entrance."); + if (temporary) + return ("slowly fading labyrinth entrance"); + else + return ("labyrinth entrance"); + case DNGN_ENTER_BAZAAR: + if (temporary) + return ("gently fading gateway to a fabulous bazaar"); + else + return ("gateway to a fabulous bazaar"); + case DNGN_EXIT_BAZAAR: + return ("exit from the bazaar"); case DNGN_ENTER_DIS: - return ("A gateway to the Iron City of Dis."); + return ("gateway to the Iron City of Dis"); case DNGN_ENTER_GEHENNA: - return ("A gateway to Gehenna."); + return ("gateway to Gehenna"); case DNGN_ENTER_COCYTUS: - return ("A gateway to the freezing wastes of Cocytus."); + return ("gateway to the freezing wastes of Cocytus"); case DNGN_ENTER_TARTARUS: - return ("A gateway to the decaying netherworld of Tartarus."); + return ("gateway to the decaying netherworld of Tartarus"); case DNGN_ENTER_ABYSS: - return ("A one-way gate to the infinite horrors of the Abyss."); + return ("one-way gate to the infinite horrors of the Abyss"); case DNGN_EXIT_ABYSS: - return ("A gateway leading out of the Abyss."); + return ("gateway leading out of the Abyss"); case DNGN_STONE_ARCH: - return ("An empty arch of ancient stone."); + return ("empty arch of ancient stone"); case DNGN_ENTER_PANDEMONIUM: - return ("A gate leading to the halls of Pandemonium."); + return ("gate leading to the halls of Pandemonium"); case DNGN_EXIT_PANDEMONIUM: - return ("A gate leading out of Pandemonium."); + return ("gate leading out of Pandemonium"); case DNGN_TRANSIT_PANDEMONIUM: - return ("A gate leading to another region of Pandemonium."); + return ("gate leading to another region of Pandemonium"); case DNGN_ENTER_ORCISH_MINES: - return ("A staircase to the Orcish Mines."); + return ("staircase to the Orcish Mines"); case DNGN_ENTER_HIVE: - return ("A staircase to the Hive."); + return ("staircase to the Hive"); case DNGN_ENTER_LAIR: - return ("A staircase to the Lair."); + return ("staircase to the Lair"); case DNGN_ENTER_SLIME_PITS: - return ("A staircase to the Slime Pits."); + return ("staircase to the Slime Pits"); case DNGN_ENTER_VAULTS: - return ("A staircase to the Vaults."); + return ("staircase to the Vaults"); case DNGN_ENTER_CRYPT: - return ("A staircase to the Crypt."); + return ("staircase to the Crypt"); case DNGN_ENTER_HALL_OF_BLADES: - return ("A staircase to the Hall of Blades."); + return ("staircase to the Hall of Blades"); case DNGN_ENTER_ZOT: - return ("A gate to the Realm of Zot."); + return ("gate to the Realm of Zot"); case DNGN_ENTER_TEMPLE: - return ("A staircase to the Ecumenical Temple."); + return ("staircase to the Ecumenical Temple"); case DNGN_ENTER_SNAKE_PIT: - return ("A staircase to the Snake Pit."); + return ("staircase to the Snake Pit"); case DNGN_ENTER_ELVEN_HALLS: - return ("A staircase to the Elven Halls."); + return ("staircase to the Elven Halls"); case DNGN_ENTER_TOMB: - return ("A staircase to the Tomb."); + return ("staircase to the Tomb"); case DNGN_ENTER_SWAMP: - return ("A staircase to the Swamp."); + return ("staircase to the Swamp"); case DNGN_ENTER_SHOALS: - return ("A staircase to the Shoals."); + return ("staircase to the Shoals"); case DNGN_RETURN_FROM_ORCISH_MINES: case DNGN_RETURN_FROM_HIVE: case DNGN_RETURN_FROM_LAIR: case DNGN_RETURN_FROM_VAULTS: case DNGN_RETURN_FROM_TEMPLE: - return ("A staircase back to the Dungeon."); + return ("staircase back to the Dungeon"); case DNGN_RETURN_FROM_SLIME_PITS: case DNGN_RETURN_FROM_SNAKE_PIT: case DNGN_RETURN_FROM_SWAMP: case DNGN_RETURN_FROM_SHOALS: - return ("A staircase back to the Lair."); + return ("staircase back to the Lair"); case DNGN_RETURN_FROM_CRYPT: case DNGN_RETURN_FROM_HALL_OF_BLADES: - return ("A staircase back to the Vaults."); + return ("staircase back to the Vaults"); case DNGN_RETURN_FROM_ELVEN_HALLS: - return ("A staircase back to the Mines."); + return ("staircase back to the Mines"); case DNGN_RETURN_FROM_TOMB: - return ("A staircase back to the Crypt."); + return ("staircase back to the Crypt"); case DNGN_RETURN_FROM_ZOT: - return ("A gate leading back out of this place."); + return ("gate leading back out of this place"); case DNGN_ALTAR_ZIN: - return ("A glowing white marble altar of Zin."); + return ("glowing white marble altar of Zin"); case DNGN_ALTAR_SHINING_ONE: - return ("A glowing golden altar of the Shining One."); + return ("glowing golden altar of the Shining One"); case DNGN_ALTAR_KIKUBAAQUDGHA: - return ("An ancient bone altar of Kikubaaqudgha."); + return ("ancient bone altar of Kikubaaqudgha"); case DNGN_ALTAR_YREDELEMNUL: - return ("A basalt altar of Yredelemnul."); + return ("basalt altar of Yredelemnul"); case DNGN_ALTAR_XOM: - return ("A shimmering altar of Xom."); + return ("shimmering altar of Xom"); case DNGN_ALTAR_VEHUMET: - return ("A shining altar of Vehumet."); + return ("shining altar of Vehumet"); case DNGN_ALTAR_OKAWARU: - return ("An iron altar of Okawaru."); + return ("iron altar of Okawaru"); case DNGN_ALTAR_MAKHLEB: - return ("A burning altar of Makhleb."); + return ("burning altar of Makhleb"); case DNGN_ALTAR_SIF_MUNA: - return ("A deep blue altar of Sif Muna."); + return ("deep blue altar of Sif Muna"); case DNGN_ALTAR_TROG: - return ("A bloodstained altar of Trog."); + return ("bloodstained altar of Trog"); case DNGN_ALTAR_NEMELEX_XOBEH: - return ("A sparkling altar of Nemelex Xobeh."); + return ("sparkling altar of Nemelex Xobeh"); case DNGN_ALTAR_ELYVILON: - return ("A silver altar of Elyvilon."); + return ("silver altar of Elyvilon"); case DNGN_ALTAR_LUGONU: - return ("A corrupted altar of Lugonu."); + return ("corrupted altar of Lugonu"); case DNGN_ALTAR_BEOGH: - return ("A roughly hewn altar of Beogh."); + return ("roughly hewn altar of Beogh"); case DNGN_BLUE_FOUNTAIN: - return ("A fountain of clear blue water."); + return ("fountain of clear blue water"); case DNGN_SPARKLING_FOUNTAIN: - return ("A fountain of sparkling water."); + return ("fountain of sparkling water"); case DNGN_DRY_FOUNTAIN_I: case DNGN_DRY_FOUNTAIN_II: case DNGN_DRY_FOUNTAIN_IV: case DNGN_DRY_FOUNTAIN_VI: case DNGN_DRY_FOUNTAIN_VIII: case DNGN_PERMADRY_FOUNTAIN: - return ("A dry fountain."); + return ("dry fountain"); default: return (""); } } -std::string feature_description(int mx, int my) +std::string feature_description(int mx, int my, description_level_type dtype, + bool add_stop) { const dungeon_feature_type grid = grd[mx][my]; switch (grid) @@ -1423,11 +1460,15 @@ std::string feature_description(int mx, int my) case DNGN_TRAP_MECHANICAL: case DNGN_TRAP_MAGICAL: case DNGN_TRAP_III: - return feature_description(grid, trap_type_at_xy(mx, my)); + return (feature_description(grid, trap_type_at_xy(mx, my), false, + dtype, add_stop)); case DNGN_ENTER_SHOP: - return (shop_name(mx, my)); + return (shop_name(mx, my, add_stop)); default: - return (feature_description(grid)); + return (feature_description( + grid, NUM_TRAPS, + env_find_marker(coord_def(mx, my), MAT_TIMED_FEATURE), + dtype, add_stop)); } } @@ -1661,7 +1702,7 @@ static void describe_cell(int mx, int my) std::string feature_desc = feature_description(mx, my); #ifdef DEBUG_DIAGNOSTICS std::string marker; - if (map_marker *mark = env.find_marker(coord_def(mx, my), MAT_ANY)) + if (map_marker *mark = env_find_marker(coord_def(mx, my), MAT_ANY)) marker = " (" + mark->describe() + ")"; const std::string traveldest = stair_destination_description(coord_def(mx, my)); diff --git a/crawl-ref/source/direct.h b/crawl-ref/source/direct.h index 9541e23825..5a71ce68c0 100644 --- a/crawl-ref/source/direct.h +++ b/crawl-ref/source/direct.h @@ -56,9 +56,17 @@ void describe_floor(); int dos_direction_unmunge(int doskey); -std::string feature_description(int mx, int my); +std::string feature_description(int mx, int my, + description_level_type dtype = DESC_CAP_A, + bool add_stop = true); +std::string raw_feature_description(dungeon_feature_type grid, + trap_type tr = NUM_TRAPS, + bool temporary = false); std::string feature_description(dungeon_feature_type grid, - trap_type tr = NUM_TRAPS); + trap_type trap = NUM_TRAPS, + bool temporary = false, + description_level_type dtype = DESC_CAP_A, + bool add_stop = true); std::vector<dungeon_feature_type> features_by_desc(const base_pattern &pattern); diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc index 311ea74805..176fa6f714 100644 --- a/crawl-ref/source/dungeon.cc +++ b/crawl-ref/source/dungeon.cc @@ -45,6 +45,7 @@ #include "items.h" #include "makeitem.h" #include "mapdef.h" +#include "mapmark.h" #include "maps.h" #include "misc.h" #include "mon-util.h" @@ -116,10 +117,13 @@ static void builder_items(int level_number, char level_type, int items_wanted); static void builder_monsters(int level_number, char level_type, int mon_wanted); static void place_specific_stair(dungeon_feature_type stair, const std::string &tag = "", - int dl = 0); + int dl = 0, + bool vault_only = false); static void place_branch_entrances(int dlevel, char level_type); static void place_extra_vaults(); -static void place_minivaults(int level_number, int level_type); +static void place_minivaults(const std::string &tag = "", + int fewest = -1, int most = -1, + bool force = false); static void place_traps( int level_number ); static void prepare_swamp(); static void prepare_shoals( int level_number ); @@ -147,7 +151,7 @@ static void build_lake(dungeon_feature_type lake_type); //mv static void spotty_level(bool seeded, int iterations, bool boxy); static void bigger_room(); -static void plan_main(int level_number, char force_plan); +static void plan_main(int level_number, int force_plan); static char plan_1(); static char plan_2(); static char plan_3(); @@ -157,6 +161,7 @@ static char plan_5(); static char plan_6(int level_number); static bool octa_room(spec_room &sr, int oblique_max, dungeon_feature_type type_floor); +static void bazaar_level(int level_number); static void labyrinth_level(int level_number); static void box_room(int bx1, int bx2, int by1, int by2, dungeon_feature_type wall_type); @@ -169,7 +174,7 @@ static void pick_float_exits(vault_placement &place, static void connect_vault(const vault_placement &vp); // ITEM & SHOP FUNCTIONS -static void place_shops(int level_number); +static void place_shops(int level_number, int nshops = 0); static object_class_type item_in_shop(unsigned char shop_type); static bool treasure_area(int level_number, unsigned char ta1_x, unsigned char ta2_x, unsigned char ta1_y, @@ -296,7 +301,7 @@ static inline bool dgn_grid_is_passable(dungeon_feature_type grid) static inline bool dgn_square_is_passable(const coord_def &c) { - return (dgn_map_mask(c) && dgn_grid_is_passable(grd(c))); + return ((dgn_map_mask(c) & MMT_OPAQUE) && dgn_grid_is_passable(grd(c))); } static inline void dgn_point_record_stub(const coord_def &) { } @@ -363,10 +368,8 @@ static int dgn_count_disconnected_zones() { for (int x = 0; x < GXM; ++x) { - if (travel_point_distance[x][y] || dgn_map_mask[x][y]) - continue; - - if (!dgn_grid_is_passable(grd[x][y])) + if (travel_point_distance[x][y] + || !dgn_square_is_passable(coord_def(x, y))) continue; dgn_fill_zone(coord_def(x, y), ++nzones, dgn_point_record_stub); @@ -421,6 +424,9 @@ static void register_place(const vault_placement &place) if (place.map.has_tag("no_pool_fixup")) mask_vault(place, MMT_NO_POOL); + + if (!place.map.has_tag("transparent")) + mask_vault(place, MMT_OPAQUE); } static bool ensure_vault_placed(bool vault_success) @@ -510,11 +516,11 @@ static void reset_level() } // reset all shops - for (unsigned char shcount = 0; shcount < 5; shcount++) + for (int shcount = 0; shcount < MAX_SHOPS; shcount++) env.shop[shcount].type = SHOP_UNASSIGNED; // clear all markers - env.clear_markers(); + env_clear_markers(); } static void build_layout_skeleton(int level_number, int level_type, @@ -628,7 +634,7 @@ static void fixup_branch_stairs() && grd[x][y] <= DNGN_ROCK_STAIRS_UP) { if (grd[x][y] == DNGN_STONE_STAIRS_UP_I) - env.add_marker( + env_add_marker( new map_feature_marker(coord_def(x,y), grd[x][y])); grd[x][y] = exit; @@ -699,7 +705,8 @@ static void build_dungeon_level(int level_number, int level_type) build_layout_skeleton(level_number, level_type, sr); - if (you.level_type == LEVEL_LABYRINTH || dgn_level_vetoed) + if (you.level_type == LEVEL_LABYRINTH || you.level_type == LEVEL_BAZAAR + || dgn_level_vetoed) return; // hook up the special room (if there is one, and it hasn't @@ -737,7 +744,7 @@ static void build_dungeon_level(int level_number, int level_type) // Try to place minivaults that really badly want to be placed. Still // no guarantees, seeing this is a minivault. if (!player_in_branch(BRANCH_SHOALS)) - place_minivaults(level_number, level_type); + place_minivaults(); place_branch_entrances( level_number, level_type ); place_extra_vaults(); dgn_verify_connectivity(nvaults); @@ -1242,16 +1249,22 @@ static bool make_box(int room_x1, int room_y1, int room_x2, int room_y2, // -1 if we should immediately quit, and 0 otherwise. static builder_rc_type builder_by_type(int level_number, char level_type) { + if (level_type == LEVEL_BAZAAR) + { + bazaar_level(level_number); + return (BUILD_QUIT); + } + if (level_type == LEVEL_LABYRINTH) { labyrinth_level(level_number); - return BUILD_QUIT; + return (BUILD_QUIT); } if (level_type == LEVEL_ABYSS) { generate_abyss(); - return BUILD_SKIP; + return (BUILD_SKIP); } if (level_type == LEVEL_PANDEMONIUM) @@ -1311,6 +1324,50 @@ static builder_rc_type builder_by_type(int level_number, char level_type) return BUILD_CONTINUE; } +static void fixup_bazaar_stairs() +{ + for (int y = 0; y < GYM; ++y) + { + for (int x = 0; x < GXM; ++x) + { + const dungeon_feature_type feat = grd[x][y]; + if (grid_is_stone_stair(feat) || grid_is_rock_stair(feat)) + { + if (grid_stair_direction(feat) == CMD_GO_DOWNSTAIRS) + grd[x][y] = DNGN_EXIT_BAZAAR; + else + grd[x][y] = DNGN_STONE_ARCH; + } + } + } +} + +static void bazaar_level(int level_number) +{ + int vault = random_map_for_place(level_id::current(), false); + if (vault == -1) + vault = random_map_for_tag("bazaar", false); + + if (vault != -1) + { + ensure_vault_placed( build_vaults(level_number, vault) ); + link_items(); + fixup_bazaar_stairs(); + return; + } + + // No primary Bazaar vaults (ugh). + plan_main(level_number, 0); + place_minivaults("bazaar", 1, 1, true); + + // No vaults placed yet? Place some shops of our own. + if (level_vaults.empty()) + place_shops(level_number, random_range(5, MAX_SHOPS)); + + link_items(); + fixup_bazaar_stairs(); +} + static int random_portal_vault(const std::string &tag) { return random_map_for_tag(tag, false, true); @@ -1371,11 +1428,28 @@ static builder_rc_type builder_by_branch(int level_number) return BUILD_CONTINUE; } -static void place_minivaults(int level_number, int level_type) +static void place_minivaults(const std::string &tag, int lo, int hi, bool force) { + const level_id curr = level_id::current(); // Dungeon-style branches only, thankyouverymuch. - if (level_type != LEVEL_DUNGEON) + if (curr.level_type != LEVEL_DUNGEON && !force) + return; + + if (lo == -1) + lo = hi = 1; + + int nvaults = random_range(lo, hi); + if (!tag.empty()) + { + for (int i = 0; i < nvaults; ++i) + { + const int vault = random_map_for_tag(tag, true); + if (vault == -1) + return; + build_minivaults(you.your_level, vault); + } return; + } std::set<int> used; if (use_random_maps && minivault_chance && one_chance_in(minivault_chance)) @@ -1383,13 +1457,13 @@ static void place_minivaults(int level_number, int level_type) const int vault = random_map_in_depth(level_id::current(), true); if (vault != -1) { - build_minivaults(level_number, vault); + build_minivaults(you.your_level, vault); used.insert(vault); } } - int chance = level_number == 0? 50 : 100; - while (chance && random2(100) < chance) + int chance = you.your_level == 0? 50 : 100; + while ((chance && random2(100) < chance) || nvaults-- > 0) { const int vault = dgn_random_map_for_place(true); if (vault == -1) @@ -1403,7 +1477,7 @@ static void place_minivaults(int level_number, int level_type) break; } - build_minivaults(level_number, vault); + build_minivaults(you.your_level, vault); used.insert(vault); chance /= 4; } @@ -1616,8 +1690,13 @@ static void builder_extras( int level_number, int level_type ) { UNUSED( level_type ); - if (level_number >= 11 && level_number <= 23 && one_chance_in(15)) - place_specific_stair(DNGN_ENTER_LABYRINTH); + if (one_chance_in(15)) + place_specific_stair(DNGN_ENTER_LABYRINTH, "lab_entry", + level_number, true); + + if (one_chance_in(20)) + place_specific_stair(DNGN_ENTER_BAZAAR, "bzr_entry", + level_number, true); if (level_number > 6 && one_chance_in(10)) { @@ -1747,10 +1826,14 @@ static void place_specific_feature(dungeon_feature_type feat) static void place_specific_stair(dungeon_feature_type stair, const std::string &tag, - int dlevel) + int dlevel, + bool vault_only) { - if (tag.empty() || !place_portal_vault(stair, tag, dlevel)) + if ((tag.empty() || !place_portal_vault(stair, tag, dlevel)) + && !vault_only) + { place_specific_feature(stair); + } } static void place_extra_vaults() @@ -3178,7 +3261,12 @@ static void pick_float_exits(vault_placement &place, pick_internal_float_exits(place, possible_exits); if (possible_exits.empty()) + { +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_WARN, "Unable to find exit from %s", place.map.name.c_str()); +#endif return; + } const int npoints = possible_exits.size(); int nexits = npoints < 6? npoints : npoints / 8 + 1; @@ -4295,29 +4383,31 @@ static void place_altar() } } // end place_altar() -static void place_shops(int level_number) +static void place_shops(int level_number, int nshops) { int temp_rand = 0; // probability determination {dlb} int timeout = 0; - unsigned char no_shops = 0; unsigned char shop_place_x = 0; unsigned char shop_place_y = 0; temp_rand = random2(125); + if (!nshops) + { #if DEBUG_SHOPS - no_shops = MAX_SHOPS; + nshops = MAX_SHOPS; #else - no_shops = ((temp_rand > 28) ? 0 : // 76.8% - (temp_rand > 4) ? 1 // 19.2% - : 1 + random2( MAX_SHOPS )); // 4.0% + nshops = ((temp_rand > 28) ? 0 : // 76.8% + (temp_rand > 4) ? 1 // 19.2% + : random_range(1, MAX_RANDOM_SHOPS)); // 4.0% - if (no_shops == 0 || level_number < 3) - return; + if (nshops == 0 || level_number < 3) + return; #endif + } - for (int i = 0; i < no_shops; i++) + for (int i = 0; i < nshops; i++) { timeout = 0; @@ -4624,14 +4714,14 @@ static void bigger_room() } // end bigger_room() // various plan_xxx functions -static void plan_main(int level_number, char force_plan) +static void plan_main(int level_number, int force_plan) { // possible values for do_stairs: // 0 - stairs already done // 1 - stairs already done, do spotty // 2 - no stairs // 3 - no stairs, do spotty - char do_stairs = 0; + int do_stairs = 0; dungeon_feature_type special_grid = (one_chance_in(3) ? DNGN_METAL_WALL : DNGN_STONE_WALL); int i,j; @@ -4999,11 +5089,11 @@ static char plan_6(int level_number) // Note, that although "level_number > 20" will work for most // trips to pandemonium (through regular portals), it won't work // for demonspawn who gate themselves there. -- bwr - if (((player_in_branch( BRANCH_MAIN_DUNGEON ) && level_number > 20) - || you.level_type == LEVEL_PANDEMONIUM) + if (((player_in_branch( BRANCH_MAIN_DUNGEON ) && level_number > 20) + || you.level_type == LEVEL_PANDEMONIUM) && (coinflip() || you.mutation[ MUT_PANDEMONIUM ])) { - grd[40][36] = DNGN_ENTER_ABYSS; + grd[40][36] = DNGN_ENTER_ABYSS; grd[41][36] = DNGN_ENTER_ABYSS; } @@ -6520,7 +6610,7 @@ coord_def dgn_find_nearby_stair(int stair_to_find, bool find_closest) if (grd[xpos][ypos] == stair_to_find && (!branch_exit - || env.find_marker(coord_def(xpos, ypos), + || env_find_marker(coord_def(xpos, ypos), MAT_FEATURE))) { found++; @@ -6680,86 +6770,3 @@ coord_def dgn_region::random_point() const { return coord_def( pos.x + random2(size.x), pos.y + random2(size.y) ); } - -//////////////////////////////////////////////////////////////////////// -// Dungeon markers - -map_marker::marker_reader -map_marker::readers[NUM_MAP_MARKER_TYPES] = -{ - &map_feature_marker::read, -}; - -map_marker::map_marker(map_marker_type t, const coord_def &p) - : pos(p), type(t) -{ -} - -map_marker::~map_marker() -{ -} - -void map_marker::write(tagHeader &outf) const -{ - marshallShort(outf, type); - marshallCoord(outf, pos); -} - -void map_marker::read(tagHeader &inf) -{ - // Don't read type! The type has to be read by someone who knows how - // to look up the unmarshall function. - unmarshallCoord(inf, pos); -} - -map_marker *map_marker::read_marker(tagHeader &inf) -{ - const map_marker_type type = - static_cast<map_marker_type>(unmarshallShort(inf)); - return readers[type]? (*readers[type])(inf, type) : NULL; -} - -//////////////////////////////////////////////////////////////////////////// -// map_feature_marker - -map_feature_marker::map_feature_marker( - const coord_def &p, - dungeon_feature_type _feat) - : map_marker(MAT_FEATURE, p), feat(_feat) -{ -} - -map_feature_marker::map_feature_marker( - const map_feature_marker &other) - : map_marker(MAT_FEATURE, other.pos), feat(other.feat) -{ -} - -void map_feature_marker::write(tagHeader &outf) const -{ - this->map_marker::write(outf); - marshallShort(outf, feat); -} - -void map_feature_marker::read(tagHeader &inf) -{ - map_marker::read(inf); - feat = static_cast<dungeon_feature_type>(unmarshallShort(inf)); -} - -map_marker *map_feature_marker::read(tagHeader &inf, map_marker_type) -{ - map_marker *mapf = new map_feature_marker(); - mapf->read(inf); - return (mapf); -} - -map_marker *map_feature_marker::clone() const -{ - return new map_feature_marker(pos, feat); -} - -std::string map_feature_marker::describe() const -{ - return make_stringf("feature (%s)", dungeon_feature_name(feat)); -} diff --git a/crawl-ref/source/dungeon.h b/crawl-ref/source/dungeon.h index 457705e4b3..cd637213f2 100644 --- a/crawl-ref/source/dungeon.h +++ b/crawl-ref/source/dungeon.h @@ -43,7 +43,8 @@ enum map_mask_type MMT_NO_ITEM = 0x02, // Random items should not be placed here. MMT_NO_MONS = 0x04, // Random monsters should not be placed here. MMT_NO_POOL = 0x08, // Pool fixup should not be applied here. - MMT_NO_DOOR = 0x10 // No secret-doorisation. + MMT_NO_DOOR = 0x10, // No secret-doorisation. + MMT_OPAQUE = 0x20 // Vault may impede connectivity. }; class dgn_region; @@ -120,50 +121,6 @@ bool unforbidden(const coord_def &c, unsigned mask); coord_def dgn_find_nearby_stair(int stair_to_find, bool find_closest); ////////////////////////////////////////////////////////////////////////// -// Map markers - -class map_marker -{ -public: - map_marker(map_marker_type type, const coord_def &pos); - virtual ~map_marker(); - - map_marker_type get_type() const { return type; } - - virtual void write(tagHeader &) const; - virtual void read(tagHeader &); - virtual map_marker *clone() const = 0; - virtual std::string describe() const = 0; - - static map_marker *read_marker(tagHeader&); - -public: - coord_def pos; - -protected: - map_marker_type type; - - typedef map_marker *(*marker_reader)(tagHeader &, map_marker_type); - static marker_reader readers[NUM_MAP_MARKER_TYPES]; -}; - -class map_feature_marker : public map_marker -{ -public: - map_feature_marker(const coord_def &pos = coord_def(0, 0), - dungeon_feature_type feat = DNGN_UNSEEN); - map_feature_marker(const map_feature_marker &other); - void write(tagHeader &) const; - void read(tagHeader &); - map_marker *clone() const; - std::string describe() const; - static map_marker *read(tagHeader &, map_marker_type); - -public: - dungeon_feature_type feat; -}; - -////////////////////////////////////////////////////////////////////////// template <typename fgrd, typename bound_check> class flood_find : public travel_pathfind { diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc index 481f513bac..9c840ec29e 100644 --- a/crawl-ref/source/effects.cc +++ b/crawl-ref/source/effects.cc @@ -1137,8 +1137,9 @@ bool acquirement(object_class_type class_wanted, int agent) if (grid_destroys_items(grd[you.x_pos][you.y_pos])) { // how sad (and stupid) - mprf(MSGCH_SOUND, - grid_item_destruction_message(grd[you.x_pos][you.y_pos])); + if (!silenced(you.pos())) + mprf(MSGCH_SOUND, + grid_item_destruction_message(grd[you.x_pos][you.y_pos])); } else { diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index 6945bb8ced..61c7ba0de2 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -937,8 +937,9 @@ enum dragon_class_type enum game_direction_type { - DIR_DESCENDING = 0, - DIR_ASCENDING = 1 + GDT_NONE, + GDT_DESCENDING, + GDT_ASCENDING }; // NOTE: The order of these is very important to their usage! @@ -992,6 +993,17 @@ enum drop_mode_type // lowest grid value which can be seen through #define MINSEE 11 +// When adding: +// +// * New stairs/portals: update grid_stair_direction. +// * Any: edit view.cc and add a glyph and colour for the feature. +// * Any: edit direct.cc and add a description for the feature. +// * Any: edit dat/descript.txt and add a long description if appropriate. +// * Any: check the grid_* functions in misc.cc and make sure +// they return sane values for your new feature. +// +// Also take note of MINMOVE and MINSEE above. +// enum dungeon_feature_type { DNGN_UNSEEN, // 0 @@ -1086,7 +1098,11 @@ enum dungeon_feature_type DNGN_RETURN_FROM_SHOALS, DNGN_RETURN_RESERVED_2, DNGN_RETURN_RESERVED_3, - DNGN_RETURN_RESERVED_4, // 146 + DNGN_RETURN_RESERVED_4, // 146 + + // Portals to various places unknown. + DNGN_ENTER_BAZAAR = 160, + DNGN_EXIT_BAZAAR, DNGN_ALTAR_ZIN = 180, // 180 DNGN_ALTAR_SHINING_ONE, @@ -1114,6 +1130,7 @@ enum dungeon_feature_type DNGN_DRY_FOUNTAIN_VII, DNGN_DRY_FOUNTAIN_VIII, DNGN_PERMADRY_FOUNTAIN = 210, // added (from dungeon.cc/maps.cc) 22jan2000 {dlb} + NUM_REAL_FEATURES, // Real terrain must all occur before 256 to guarantee it fits @@ -1238,6 +1255,7 @@ enum element_type EC_ROCK, // colour of the area's rock EC_STONE, // colour of the area's stone EC_MIST, // colour of mist + EC_SHIMMER_BLUE, // shimmering colours of blue. EC_RANDOM // any colour (except BLACK) }; @@ -1744,6 +1762,7 @@ enum level_area_type // you.level_type LEVEL_LABYRINTH, LEVEL_ABYSS, LEVEL_PANDEMONIUM, + LEVEL_BAZAAR, NUM_LEVEL_AREA_TYPES }; @@ -1755,14 +1774,6 @@ enum load_mode_type LOAD_ENTER_LEVEL }; -// Can't change this order without breaking saves. -enum map_marker_type -{ - MAT_FEATURE, // Stock marker. - NUM_MAP_MARKER_TYPES, - MAT_ANY -}; - // [dshaligram] Maps can be mirrored; for every orientation, there must be // a suitable mirror. enum map_section_type // see maps.cc and dungeon.cc {dlb} diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index 7f9653ef4c..67138455c0 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -1273,14 +1273,6 @@ public: // Number of turns the player has spent on this level. int turns_on_level; - -public: - void add_marker(map_marker *); - void remove_marker(map_marker *); - void remove_markers_at(const coord_def &c); - map_marker *find_marker(const coord_def &c, map_marker_type) const; - std::vector<map_marker*> get_markers(const coord_def &c) const; - void clear_markers(); }; extern struct crawl_environment env; diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc index ad8baf87c1..d2ec409aca 100644 --- a/crawl-ref/source/files.cc +++ b/crawl-ref/source/files.cc @@ -65,6 +65,7 @@ #include "itemprop.h" #include "items.h" #include "libutil.h" +#include "mapmark.h" #include "message.h" #include "misc.h" #include "monstuff.h" @@ -552,6 +553,8 @@ static std::string get_level_suffix(int level, branch_type where, return ("abs"); case LEVEL_PANDEMONIUM: return ("pan"); + case LEVEL_BAZAAR: + return ("bzr"); } } @@ -700,6 +703,14 @@ static void place_player_on_stair(branch_type old_branch, int stair_taken) // when entering a hell or pandemonium stair_taken = DNGN_STONE_STAIRS_UP_I; } + else if (stair_taken == DNGN_ENTER_BAZAAR) + { + stair_taken = DNGN_STONE_ARCH; + } + else if (stair_taken == DNGN_EXIT_BAZAAR) + { + stair_taken = DNGN_STONE_STAIRS_DOWN_I; + } else // Note: stair_taken can equal things like DNGN_FLOOR { // just find a nice empty square @@ -718,14 +729,13 @@ static void close_level_gates() { for ( int j = 0; j < GYM; ++j ) { - if (you.char_direction == DIR_ASCENDING + if (you.char_direction == GDT_ASCENDING && you.level_type != LEVEL_PANDEMONIUM) { - if (grd[i][j] == DNGN_ENTER_HELL - || grd[i][j] == DNGN_ENTER_ABYSS - || grd[i][j] == DNGN_ENTER_PANDEMONIUM) + if (grid_sealable_portal(grd[i][j])) { grd[i][j] = DNGN_STONE_ARCH; + env_remove_markers_at(coord_def(i,j), MAT_ANY); } } } @@ -744,6 +754,11 @@ static void clear_clouds() env.cgrid.init(EMPTY_CLOUD); } +static bool level_type_allows_followers(level_area_type type) +{ + return (type == LEVEL_DUNGEON || type == LEVEL_PANDEMONIUM); +} + static void grab_followers() { for (int i = you.x_pos - 1; i < you.x_pos + 2; i++) @@ -815,6 +830,9 @@ bool load( dungeon_feature_type stair_taken, load_mode_type load_mode, if (load_mode != LOAD_RESTART_GAME) clear_clouds(); + // Lose all listeners. + dungeon_events.clear(); + // This block is to grab followers and save the old level to disk. if (load_mode == LOAD_ENTER_LEVEL && old_level != -1) { @@ -873,7 +891,7 @@ bool load( dungeon_feature_type stair_taken, load_mode_type load_mode, } // closes all the gates if you're on the way out - if (you.char_direction == DIR_ASCENDING && + if (you.char_direction == GDT_ASCENDING && you.level_type != LEVEL_PANDEMONIUM) close_level_gates(); @@ -898,8 +916,7 @@ bool load( dungeon_feature_type stair_taken, load_mode_type load_mode, monster_teleport(&menv[mgrd[you.x_pos][you.y_pos]], true, true); // actually "move" the followers if applicable - if ((you.level_type == LEVEL_DUNGEON - || you.level_type == LEVEL_PANDEMONIUM) + if (level_type_allows_followers(you.level_type) && load_mode == LOAD_ENTER_LEVEL) { place_followers(); @@ -916,6 +933,12 @@ bool load( dungeon_feature_type stair_taken, load_mode_type load_mode, // Things to update for player entering level if (load_mode == LOAD_ENTER_LEVEL) { + // Activate markers that want activating, but only when + // entering a new level in an existing game. If we're starting + // a new game, or reloading an existing game, + // env_activate_markers() is done in acr.cc. + env_activate_markers(); + // update corpses and fountains if (env.elapsed_time != 0.0) update_level( you.elapsed_time - env.elapsed_time ); diff --git a/crawl-ref/source/hiscores.cc b/crawl-ref/source/hiscores.cc index 350d336075..31784f4707 100644 --- a/crawl-ref/source/hiscores.cc +++ b/crawl-ref/source/hiscores.cc @@ -573,10 +573,10 @@ static const char *short_branch_name(int branch) static const char *level_type_names[] = { - "D", "Lab", "Abyss", "Pan" + "D", "Lab", "Abyss", "Pan", "Bzr" }; -static const char *level_area_type_name(int level_type) +const char *level_area_type_name(int level_type) { if (level_type >= 0 && level_type < NUM_LEVEL_AREA_TYPES) return level_type_names[level_type]; diff --git a/crawl-ref/source/hiscores.h b/crawl-ref/source/hiscores.h index 89cfb7fdb0..108e8ec723 100644 --- a/crawl-ref/source/hiscores.h +++ b/crawl-ref/source/hiscores.h @@ -41,6 +41,8 @@ std::string hiscores_format_single( const scorefile_entry &se ); std::string hiscores_format_single_long( const scorefile_entry &se, bool verbose = false ); +const char *level_area_type_name(int level_type); + #ifdef DGL_MILESTONES void mark_milestone(const std::string &type, const std::string &milestone); #endif diff --git a/crawl-ref/source/it_use3.cc b/crawl-ref/source/it_use3.cc index 15296e5a3e..68d39d60fe 100644 --- a/crawl-ref/source/it_use3.cc +++ b/crawl-ref/source/it_use3.cc @@ -32,6 +32,7 @@ #include "it_use2.h" #include "itemname.h" #include "itemprop.h" +#include "mapmark.h" #include "misc.h" #include "monplace.h" #include "monstuff.h" @@ -571,7 +572,7 @@ bool evoke_wielded( void ) opened_gates++; map_marker *marker = - env.find_marker(coord_def(count_x, count_y), + env_find_marker(coord_def(count_x, count_y), MAT_FEATURE); if (marker) @@ -579,7 +580,7 @@ bool evoke_wielded( void ) map_feature_marker *featm = dynamic_cast<map_feature_marker*>(marker); grd[count_x][count_y] = featm->feat; - env.remove_marker(marker); + env_remove_marker(marker); } } } diff --git a/crawl-ref/source/itemprop.cc b/crawl-ref/source/itemprop.cc index 8162a4cd88..c38ad41534 100644 --- a/crawl-ref/source/itemprop.cc +++ b/crawl-ref/source/itemprop.cc @@ -458,6 +458,18 @@ bool item_ident( const item_def &item, unsigned long flags ) return ((item.flags & flags) == flags); } +// The Orb of Zot and unique runes are considered critical. +bool item_is_critical(const item_def &item) +{ + if (item.base_type == OBJ_ORBS) + return (true); + + return (item.base_type == OBJ_MISCELLANY + && item.sub_type == MISC_RUNE_OF_ZOT + && (item.plus != RUNE_DEMONIC + && item.plus != RUNE_ABYSSAL)); +} + void set_ident_flags( item_def &item, unsigned long flags ) { item.flags |= flags; diff --git a/crawl-ref/source/itemprop.h b/crawl-ref/source/itemprop.h index 002cf22293..5904722a4a 100644 --- a/crawl-ref/source/itemprop.h +++ b/crawl-ref/source/itemprop.h @@ -16,6 +16,9 @@ void init_properties(void); +// Returns true if this item should be preserved as far as possible. +bool item_is_critical(const item_def &item); + // cursed: bool item_cursed( const item_def &item ); bool item_known_cursed( const item_def &item ); diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc index 5357ea43a6..73b85bb880 100644 --- a/crawl-ref/source/items.cc +++ b/crawl-ref/source/items.cc @@ -38,6 +38,7 @@ #include "debug.h" #include "delay.h" #include "direct.h" +#include "dgnevent.h" #include "effects.h" #include "hiscores.h" #include "invent.h" @@ -1407,11 +1408,11 @@ int move_item_to_player( int obj, int quant_got, bool quiet ) } if (item.base_type == OBJ_ORBS - && you.char_direction == DIR_DESCENDING) + && you.char_direction == GDT_DESCENDING) { if (!quiet) mpr("Now all you have to do is get back out of the dungeon!"); - you.char_direction = DIR_ASCENDING; + you.char_direction = GDT_ASCENDING; } you.turn_is_over = true; @@ -1651,7 +1652,7 @@ bool drop_item( int item_dropped, int quant_drop, bool try_offer ) mprf("You drop %s.", quant_name(you.inv[item_dropped], quant_drop, DESC_NOCAP_A).c_str()); - if ( grid_destroys_items(my_grid) ) + if ( grid_destroys_items(my_grid) && !silenced(you.pos()) ) mprf(MSGCH_SOUND, grid_item_destruction_message(my_grid)); dec_inv_item_quantity( item_dropped, quant_drop ); @@ -1949,6 +1950,9 @@ void update_level( double elapsedTime ) update_corpses( elapsedTime ); + dungeon_events.fire_event( + dgn_event(DET_TURN_ELAPSED, coord_def(0, 0), turns * 10)); + for (m = 0; m < MAX_MONSTERS; m++) { struct monsters *mon = &menv[m]; diff --git a/crawl-ref/source/lev-pand.cc b/crawl-ref/source/lev-pand.cc index b152da62d4..9587135e7a 100644 --- a/crawl-ref/source/lev-pand.cc +++ b/crawl-ref/source/lev-pand.cc @@ -164,5 +164,5 @@ void pandemonium_mons(void) while (!mons_pan(pan_mons)); } mons_place(pan_mons, BEH_HOSTILE, MHITNOT, false, 50,50, - LEVEL_PANDEMONIUM); + LEVEL_PANDEMONIUM); } // end pandemonium_mons() diff --git a/crawl-ref/source/libutil.cc b/crawl-ref/source/libutil.cc index 09f86ce2fd..e3c68f87bb 100644 --- a/crawl-ref/source/libutil.cc +++ b/crawl-ref/source/libutil.cc @@ -129,6 +129,72 @@ int ends_with(const std::string &s, const char *suffixes[]) return (0); } +// Returns true if s contains tag 'tag', and strips out tag from s. +bool strip_tag(std::string &s, const std::string &tag, bool skip_padding) +{ + if (s == tag) + { + s.clear(); + return (true); + } + + std::string::size_type pos; + + if (skip_padding) + { + if ((pos = s.find(tag)) != std::string::npos) + { + s.erase(pos, tag.length()); + trim_string(s); + return (true); + } + return (false); + } + + if ((pos = s.find(" " + tag + " ")) != std::string::npos) + { + // Leave one space intact. + s.erase(pos, tag.length() + 1); + trim_string(s); + return (true); + } + + if ((pos = s.find(tag + " ")) != std::string::npos + || (pos = s.find(" " + tag)) != std::string::npos) + { + s.erase(pos, tag.length() + 1); + trim_string(s); + return (true); + } + + return (false); +} + +std::string strip_tag_prefix(std::string &s, const std::string &tagprefix) +{ + const std::string::size_type pos = s.find(tagprefix); + if (pos == std::string::npos) + return (""); + + std::string::size_type ns = s.find(" ", pos); + if (ns == std::string::npos) + ns = s.length(); + + const std::string argument = + s.substr(pos + tagprefix.length(), ns - pos - tagprefix.length()); + + s.erase(pos, ns - pos + 1); + trim_string(s); + + return (argument); +} + +int strip_number_tag(std::string &s, const std::string &tagprefix) +{ + const std::string num = strip_tag_prefix(s, tagprefix); + return (num.empty()? TAG_UNFOUND : atoi(num.c_str())); +} + // Naively prefix A/an to a noun. std::string article_a(const std::string &name, bool lowercase) { diff --git a/crawl-ref/source/libutil.h b/crawl-ref/source/libutil.h index 0f425ff7cd..990463852f 100644 --- a/crawl-ref/source/libutil.h +++ b/crawl-ref/source/libutil.h @@ -26,6 +26,12 @@ std::string &lowercase(std::string &s); std::string &uppercase(std::string &s); bool ends_with(const std::string &s, const std::string &suffix); +// String "tags" +#define TAG_UNFOUND -20404 +bool strip_tag(std::string &s, const std::string &tag, bool nopad = false); +int strip_number_tag(std::string &s, const std::string &tagprefix); +std::string strip_tag_prefix(std::string &s, const std::string &tagprefix); + std::string article_a(const std::string &name, bool lowercase = true); std::string pluralise(const std::string &name, const char *stock_plural_quals[] = standard_plural_qualifiers, diff --git a/crawl-ref/source/luadgn.cc b/crawl-ref/source/luadgn.cc index 0b4682daa1..6f3d75a7a5 100644 --- a/crawl-ref/source/luadgn.cc +++ b/crawl-ref/source/luadgn.cc @@ -10,6 +10,7 @@ #include "files.h" #include "luadgn.h" #include "mapdef.h" +#include "mapmark.h" #include "maps.h" #include "stuff.h" #include "dungeon.h" @@ -633,16 +634,7 @@ static int dgn_marker(lua_State *ls) std::string err = map->map.add_feature_marker(luaL_checkstring(ls, 2)); if (!err.empty()) luaL_error(ls, err.c_str()); - return (0); } - - const coord_def pos(luaL_checkint(ls, 2), luaL_checkint(ls, 3)); - dungeon_feature_type feat = DNGN_UNSEEN; - if (lua_isnumber(ls, 4)) - feat = static_cast<dungeon_feature_type>( luaL_checkint(ls, 4) ); - else - feat = dungeon_feature_by_name( luaL_checkstring(ls, 4) ); - map->map.add_marker( new map_feature_marker(pos, feat) ); return (0); } diff --git a/crawl-ref/source/makefile.obj b/crawl-ref/source/makefile.obj index 40d159c842..eaa7f8f55a 100644 --- a/crawl-ref/source/makefile.obj +++ b/crawl-ref/source/makefile.obj @@ -15,6 +15,7 @@ debug.o \ delay.o \ decks.o \ describe.o \ +dgnevent.o \ direct.o \ dungeon.o \ effects.o \ @@ -39,6 +40,7 @@ luadgn.o \ macro.o \ makeitem.o \ mapdef.o \ +mapmark.o \ maps.o \ menu.o \ message.o \ diff --git a/crawl-ref/source/makeitem.cc b/crawl-ref/source/makeitem.cc index 99a2542278..9f7d79b6bc 100644 --- a/crawl-ref/source/makeitem.cc +++ b/crawl-ref/source/makeitem.cc @@ -1861,7 +1861,7 @@ int items( int allow_uniques, // not just true-false, && coinflip()) { if ((you.level_type != LEVEL_ABYSS - && you.level_type != LEVEL_PANDEMONIUM) + && you.level_type != LEVEL_PANDEMONIUM) && one_chance_in(50)) { icky = find_okay_unrandart(OBJ_ARMOUR); diff --git a/crawl-ref/source/mapdef.cc b/crawl-ref/source/mapdef.cc index aaae6b209a..a5854ae236 100644 --- a/crawl-ref/source/mapdef.cc +++ b/crawl-ref/source/mapdef.cc @@ -20,6 +20,7 @@ #include "items.h" #include "libutil.h" #include "mapdef.h" +#include "mapmark.h" #include "maps.h" #include "misc.h" #include "monplace.h" @@ -49,52 +50,6 @@ const char *map_section_name(int msect) return map_section_names[msect]; } -// Returns true if s contains tag 'tag', and strips out tag from s. -bool strip_tag(std::string &s, const std::string &tag) -{ - if (s == tag) - { - s.clear(); - return (true); - } - - std::string::size_type pos; - if ((pos = s.find(" " + tag + " ")) != std::string::npos) - { - // Leave one space intact. - s.erase(pos, tag.length() + 1); - return (true); - } - - if ((pos = s.find(tag + " ")) != std::string::npos - || (pos = s.find(" " + tag)) != std::string::npos) - { - s.erase(pos, tag.length() + 1); - return (true); - } - - return (false); -} - -#define TAG_UNFOUND -20404 -int strip_number_tag(std::string &s, const std::string &tagprefix) -{ - std::string::size_type pos = s.find(tagprefix); - if (pos == std::string::npos) - return (TAG_UNFOUND); - - std::string::size_type ns = s.find(" ", pos); - if (ns == std::string::npos) - ns = s.length(); - - std::string argument = - s.substr(pos + tagprefix.length(), ns - pos - tagprefix.length()); - - s.erase(pos, ns - pos + 1); - - return atoi(argument.c_str()); -} - static int find_weight(std::string &s) { int weight = strip_number_tag(s, "weight:"); @@ -383,6 +338,7 @@ map_lines::~map_lines() void map_lines::init_from(const map_lines &map) { + // Transforms and markers have to be regenerated, they will not be copied. clear_transforms(); clear_markers(); lines = map.lines; @@ -392,12 +348,6 @@ void map_lines::init_from(const map_lines &map) solid_south = map.solid_south; solid_west = map.solid_west; solid_checked = map.solid_checked; - - for (int i = 0, size = map.transforms.size(); i < size; ++i) - transforms.push_back( map.transforms[i]->clone() ); - - for (int i = 0, size = map.markers.size(); i < size; ++i) - markers.push_back( map.markers[i]->clone() ); } template <typename V> @@ -431,11 +381,7 @@ std::string map_lines::add_feature_marker(const std::string &s) if (!err.empty()) return (err); - const dungeon_feature_type feat = dungeon_feature_by_name(arg); - if (feat == DNGN_UNSEEN) - return make_stringf("unknown feature: %s", arg.c_str()); - - transforms.push_back(new map_feat_marker_spec(key[0], feat)); + transforms.push_back(new map_marker_spec(key[0], arg)); return (""); } @@ -444,7 +390,7 @@ void map_lines::apply_markers(const coord_def &c) for (int i = 0, size = markers.size(); i < size; ++i) { markers[i]->pos += c; - env.add_marker(markers[i]); + env_add_marker(markers[i]); } // *not* clear_markers() since we've offloaded marker ownership to // the crawl env. @@ -2355,15 +2301,27 @@ std::string shuffle_spec::describe() const } ////////////////////////////////////////////////////////////////////////// -// map_feat_marker_spec +// map_marker_spec -std::string map_feat_marker_spec::apply_transform(map_lines &map) +std::string map_marker_spec::apply_transform(map_lines &map) { std::vector<coord_def> positions = map.find_glyph(key); if (positions.size() == 1) { - map.add_marker(new map_feature_marker(positions[0], feat)); - return (""); + try + { + map_marker *mark = map_marker::parse_marker(marker); + if (!mark) + return make_stringf("Unable to parse marker from %s", + marker.c_str()); + mark->pos = positions[0]; + map.add_marker(mark); + return (""); + } + catch (const std::string &err) + { + return (err); + } } else if (positions.empty()) return make_stringf("cant find key '%c' for marker", key); @@ -2371,19 +2329,19 @@ std::string map_feat_marker_spec::apply_transform(map_lines &map) return make_stringf("too many matches for key '%c' for marker", key); } -map_transformer::transform_type map_feat_marker_spec::type() const +map_transformer::transform_type map_marker_spec::type() const { return (TT_MARKER); } -std::string map_feat_marker_spec::describe() const +std::string map_marker_spec::describe() const { - return map_feature_marker(coord_def(), feat).describe(); + return ("unimplemented"); } -map_transformer *map_feat_marker_spec::clone() const +map_transformer *map_marker_spec::clone() const { - return new map_feat_marker_spec(key, feat); + return new map_marker_spec(key, marker); } ////////////////////////////////////////////////////////////////////////// diff --git a/crawl-ref/source/mapdef.h b/crawl-ref/source/mapdef.h index 85dca6f0ce..9ff325bcca 100644 --- a/crawl-ref/source/mapdef.h +++ b/crawl-ref/source/mapdef.h @@ -154,13 +154,13 @@ struct shuffle_spec : public map_transformer } }; -struct map_feat_marker_spec : public map_transformer +struct map_marker_spec : public map_transformer { int key; - dungeon_feature_type feat; + std::string marker; - map_feat_marker_spec(int _key, dungeon_feature_type _feat) - : key(_key), feat(_feat) { } + map_marker_spec(int _key, const std::string &mark) + : key(_key), marker(mark) { } std::string apply_transform(map_lines &map); transform_type type() const; std::string describe() const; diff --git a/crawl-ref/source/mapmark.cc b/crawl-ref/source/mapmark.cc new file mode 100644 index 0000000000..696f042b4c --- /dev/null +++ b/crawl-ref/source/mapmark.cc @@ -0,0 +1,395 @@ +/* + * File: mapmark.cc + * Summary: Level markers (annotations). + * + * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-07-20T11:40:25.964128Z $ + * + */ + +#include "AppHdr.h" +#include "mapmark.h" + +#include "direct.h" +#include "libutil.h" +#include "luadgn.h" +#include "stuff.h" +#include "tags.h" +#include "view.h" + +//////////////////////////////////////////////////////////////////////// +// Dungeon markers + +map_marker::marker_reader map_marker::readers[NUM_MAP_MARKER_TYPES] = +{ + &map_feature_marker::read, + &map_timed_feature_marker::read, +}; + +map_marker::marker_parser map_marker::parsers[NUM_MAP_MARKER_TYPES] = +{ + &map_feature_marker::parse, + &map_timed_feature_marker::parse, +}; + +map_marker::map_marker(map_marker_type t, const coord_def &p) + : pos(p), type(t) +{ +} + +map_marker::~map_marker() +{ +} + +void map_marker::activate() +{ +} + +void map_marker::write(tagHeader &outf) const +{ + marshallShort(outf, type); + marshallCoord(outf, pos); +} + +void map_marker::read(tagHeader &inf) +{ + // Don't read type! The type has to be read by someone who knows how + // to look up the unmarshall function. + unmarshallCoord(inf, pos); +} + +map_marker *map_marker::read_marker(tagHeader &inf) +{ + const map_marker_type type = + static_cast<map_marker_type>(unmarshallShort(inf)); + return readers[type]? (*readers[type])(inf, type) : NULL; +} + +map_marker *map_marker::parse_marker(const std::string &s) throw (std::string) +{ + for (int i = 0; i < NUM_MAP_MARKER_TYPES; ++i) + { + if (parsers[i]) + { + if (map_marker *m = parsers[i](s)) + return (m); + } + } + return (NULL); +} + +//////////////////////////////////////////////////////////////////////////// +// map_feature_marker + +map_feature_marker::map_feature_marker( + const coord_def &p, + dungeon_feature_type _feat) + : map_marker(MAT_FEATURE, p), feat(_feat) +{ +} + +map_feature_marker::map_feature_marker( + const map_feature_marker &other) + : map_marker(MAT_FEATURE, other.pos), feat(other.feat) +{ +} + +void map_feature_marker::write(tagHeader &outf) const +{ + this->map_marker::write(outf); + marshallShort(outf, feat); +} + +void map_feature_marker::read(tagHeader &inf) +{ + map_marker::read(inf); + feat = static_cast<dungeon_feature_type>(unmarshallShort(inf)); +} + +map_marker *map_feature_marker::read(tagHeader &inf, map_marker_type) +{ + map_marker *mapf = new map_feature_marker(); + mapf->read(inf); + return (mapf); +} + +map_marker *map_feature_marker::parse(const std::string &s) throw (std::string) +{ + if (s.find("feat:") != 0) + return (NULL); + std::string raw = s; + strip_tag(raw, "feat:", true); + + const dungeon_feature_type ft = dungeon_feature_by_name(raw); + if (ft == DNGN_UNSEEN) + throw make_stringf("Bad feature marker: %s (unknown feature '%s')", + s.c_str(), raw.c_str()); + return new map_feature_marker(coord_def(0, 0), ft); +} + +std::string map_feature_marker::describe() const +{ + return make_stringf("feature (%s)", dungeon_feature_name(feat)); +} + +//////////////////////////////////////////////////////////////////////////// +// map_feature_marker + +map_timed_feature_marker::map_timed_feature_marker( + const coord_def &_pos, + int duration_turns, + dungeon_feature_type _feat) + : map_feature_marker(_pos, _feat), duration_ticks(duration_turns * 10), + warn_threshold(-1000) +{ + type = MAT_TIMED_FEATURE; +} + +void map_timed_feature_marker::activate() +{ + dungeon_events.register_listener(DET_TURN_ELAPSED, this); + + if (player_can_hear(pos)) + { + const dungeon_feature_type ft = grd(pos); + switch (ft) + { + case DNGN_ENTER_BAZAAR: + mprf(MSGCH_SOUND, "You %shear coins being counted.", + duration_ticks < 1000? "can faintly " : ""); + break; + case DNGN_ENTER_LABYRINTH: + mprf(MSGCH_SOUND, "You hear a faint echoing snort."); + break; + default: + break; + } + } +} + +void map_timed_feature_marker::write(tagHeader &th) const +{ + map_feature_marker::write(th); + marshallShort(th, duration_ticks); + marshallShort(th, warn_threshold); +} + +void map_timed_feature_marker::read(tagHeader &th) +{ + map_feature_marker::read(th); + duration_ticks = unmarshallShort(th); + warn_threshold = unmarshallShort(th); +} + +std::string map_timed_feature_marker::describe() const +{ + return make_stringf("timer: %d ticks (%s)", + duration_ticks, dungeon_feature_name(feat)); +} + +const char *map_timed_feature_marker::bell_urgency(int ticks) const +{ + if (ticks > 5000) + return "stately "; + else if (ticks > 4000) + return ""; + else if (ticks > 2500) + return "brisk "; + else if (ticks > 1500) + return "urgent "; + else if (ticks > 0) + return "frantic "; + else + return "last, dying notes of the "; +} + +const char *map_timed_feature_marker::noise_maker(int ticks) const +{ + switch (grd(pos)) + { + case DNGN_ENTER_LABYRINTH: + return (ticks > 0? "tolling of a bell" : "bell"); + case DNGN_ENTER_BAZAAR: + return (ticks > 0? "ticking of an ancient clock" : "clock"); + default: + return (ticks > 0? + "trickling of a stream filled with giant, killer bugs." + : "stream"); + } +} + +void map_timed_feature_marker::notify_dgn_event(const dgn_event &e) +{ + if (!e.elapsed_ticks || e.type != DET_TURN_ELAPSED) + return; + + if (warn_threshold == -1000) + warn_threshold = std::max(50, duration_ticks - 500); + + duration_ticks -= e.elapsed_ticks; + + if (duration_ticks < warn_threshold || duration_ticks <= 0) + { + if (duration_ticks > 900) + warn_threshold = duration_ticks - 500; + else + warn_threshold = duration_ticks - 250; + + if (duration_ticks > 0 && player_can_hear(pos)) + mprf(MSGCH_SOUND, "You hear the %s%s.", + bell_urgency(duration_ticks), + noise_maker(duration_ticks)); + + if (duration_ticks <= 0) + timeout(true); + } +} + +void map_timed_feature_marker::timeout(bool verbose) +{ + if (verbose) + { + if (see_grid(pos)) + mprf("%s disappears!", + feature_description(grd(pos), NUM_TRAPS, false, + DESC_CAP_THE, false).c_str()); + else + mpr("The walls and floor vibrate strangely for a moment."); + } + + // And it's gone forever. + grd(pos) = feat; + + dungeon_terrain_changed(pos); + + // Stop listening for further ticks. + dungeon_events.remove_listener(this); + + // Kill this marker. + env_remove_marker(this); +} + +map_marker *map_timed_feature_marker::read(tagHeader &th, map_marker_type) +{ + map_marker *mt = new map_timed_feature_marker(); + mt->read(th); + return (mt); +} + +map_marker *map_timed_feature_marker::parse(const std::string &s) + throw (std::string) +{ + if (s.find("timer:") != 0) + return (NULL); + std::string raw = s; + strip_tag(raw, "timer:", true); + + int navg = strip_number_tag(raw, "avg:"); + if (navg == TAG_UNFOUND) + navg = 1; + + if (navg < 1 || navg > 20) + throw make_stringf("Bad marker spec '%s' (avg out of bounds)", + s.c_str()); + + dungeon_feature_type feat = DNGN_FLOOR; + std::string fname = strip_tag_prefix(raw, "feat:"); + if (!fname.empty() + && (feat = dungeon_feature_by_name(fname)) == DNGN_UNSEEN) + { + throw make_stringf("Bad feature name (%s) in marker spec '%s'", + fname.c_str(), s.c_str()); + } + + std::vector<std::string> limits = split_string("-", raw); + const int nlims = limits.size(); + if (nlims < 1 || nlims > 2) + throw make_stringf("Malformed turn range (%s) in marker '%s'", + raw.c_str(), s.c_str()); + + const int low = atoi(limits[0].c_str()); + const int high = nlims == 1? low : atoi(limits[1].c_str()); + + if (low == 0 || high < low) + throw make_stringf("Malformed turn range (%s) in marker '%s'", + raw.c_str(), s.c_str()); + + const int duration = low == high? low : random_range(low, high, navg); + return new map_timed_feature_marker(coord_def(0, 0), + duration, feat); +} + +////////////////////////////////////////////////////////////////////////// +// Map markers in env. + +void env_activate_markers() +{ + for (dgn_marker_map::iterator i = env.markers.begin(); + i != env.markers.end(); ++i) + { + i->second->activate(); + } +} + +void env_add_marker(map_marker *marker) +{ + env.markers.insert(dgn_pos_marker(marker->pos, marker)); +} + +void env_remove_marker(map_marker *marker) +{ + std::pair<dgn_marker_map::iterator, dgn_marker_map::iterator> + els = env.markers.equal_range(marker->pos); + for (dgn_marker_map::iterator i = els.first; i != els.second; ++i) + { + if (i->second == marker) + { + env.markers.erase(i); + break; + } + } + delete marker; +} + +void env_remove_markers_at(const coord_def &c, + map_marker_type type) +{ + std::pair<dgn_marker_map::iterator, dgn_marker_map::iterator> + els = env.markers.equal_range(c); + for (dgn_marker_map::iterator i = els.first; i != els.second; ) + { + dgn_marker_map::iterator todel = i++; + if (type == MAT_ANY || todel->second->get_type() == type) + { + delete todel->second; + env.markers.erase(todel); + } + } +} + +map_marker *env_find_marker(const coord_def &c, map_marker_type type) +{ + std::pair<dgn_marker_map::const_iterator, dgn_marker_map::const_iterator> + els = env.markers.equal_range(c); + for (dgn_marker_map::const_iterator i = els.first; i != els.second; ++i) + if (type == MAT_ANY || i->second->get_type() == type) + return (i->second); + return (NULL); +} + +std::vector<map_marker*> env_get_markers(const coord_def &c) +{ + std::pair<dgn_marker_map::const_iterator, dgn_marker_map::const_iterator> + els = env.markers.equal_range(c); + std::vector<map_marker*> rmarkers; + for (dgn_marker_map::const_iterator i = els.first; i != els.second; ++i) + rmarkers.push_back(i->second); + return (rmarkers); +} + +void env_clear_markers() +{ + for (dgn_marker_map::iterator i = env.markers.begin(); + i != env.markers.end(); ++i) + delete i->second; + env.markers.clear(); +} diff --git a/crawl-ref/source/mapmark.h b/crawl-ref/source/mapmark.h new file mode 100644 index 0000000000..31d0b74e29 --- /dev/null +++ b/crawl-ref/source/mapmark.h @@ -0,0 +1,101 @@ +#ifndef __MAPMARK_H__ +#define __MAPMARK_H__ + +#include "dungeon.h" +#include "dgnevent.h" + +////////////////////////////////////////////////////////////////////////// +// Map markers + +// Can't change this order without breaking saves. +enum map_marker_type +{ + MAT_FEATURE, // Stock marker. + MAT_TIMED_FEATURE, + NUM_MAP_MARKER_TYPES, + MAT_ANY +}; + +class map_marker +{ +public: + map_marker(map_marker_type type, const coord_def &pos); + virtual ~map_marker(); + + map_marker_type get_type() const { return type; } + + virtual void activate(); + virtual void write(tagHeader &) const; + virtual void read(tagHeader &); + virtual std::string describe() const = 0; + + static map_marker *read_marker(tagHeader&); + static map_marker *parse_marker(const std::string &text) + throw (std::string); + +public: + coord_def pos; + +protected: + map_marker_type type; + + typedef map_marker *(*marker_reader)(tagHeader &, map_marker_type); + typedef map_marker *(*marker_parser)(const std::string &); + static marker_reader readers[NUM_MAP_MARKER_TYPES]; + static marker_parser parsers[NUM_MAP_MARKER_TYPES]; +}; + +class map_feature_marker : public map_marker +{ +public: + map_feature_marker(const coord_def &pos = coord_def(0, 0), + dungeon_feature_type feat = DNGN_UNSEEN); + map_feature_marker(const map_feature_marker &other); + void write(tagHeader &) const; + void read(tagHeader &); + std::string describe() const; + static map_marker *read(tagHeader &, map_marker_type); + static map_marker *parse(const std::string &s) throw (std::string); + +public: + dungeon_feature_type feat; +}; + +class map_timed_feature_marker : public map_feature_marker, dgn_event_listener +{ +public: + map_timed_feature_marker(const coord_def &pos = coord_def(), + int duration_turns = 0, + dungeon_feature_type feat = DNGN_FLOOR); + void activate(); + void write(tagHeader &) const; + void read(tagHeader &); + std::string describe() const; + + void notify_dgn_event(const dgn_event &e); + + // Expires this marker *now* and cleans it up. + void timeout(bool verbose); + + static map_marker *read(tagHeader &, map_marker_type); + static map_marker *parse(const std::string &s) throw (std::string); + +private: + const char *bell_urgency(int ticks) const; + const char *noise_maker(int ticks) const; + +public: + // Ticks are a tenth of a turn. + int duration_ticks; + int warn_threshold; +}; + +void env_activate_markers(); +void env_add_marker(map_marker *); +void env_remove_marker(map_marker *); +void env_remove_markers_at(const coord_def &c, map_marker_type); +map_marker *env_find_marker(const coord_def &c, map_marker_type); +std::vector<map_marker*> env_get_markers(const coord_def &c); +void env_clear_markers(); + +#endif diff --git a/crawl-ref/source/maps.h b/crawl-ref/source/maps.h index 2e3eb244e7..0d9df7319b 100644 --- a/crawl-ref/source/maps.h +++ b/crawl-ref/source/maps.h @@ -64,6 +64,6 @@ extern depth_ranges lc_default_depths; extern dlua_chunk lc_global_prelude; extern bool lc_run_global_prelude; -const int MAP_CACHE_VERSION = 1006; +const int MAP_CACHE_VERSION = 1007; #endif diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc index be7d8d1e1f..44360b0b07 100644 --- a/crawl-ref/source/misc.cc +++ b/crawl-ref/source/misc.cc @@ -41,6 +41,7 @@ #include "chardump.h" #include "cloud.h" #include "delay.h" +#include "dgnevent.h" #include "fight.h" #include "files.h" #include "food.h" @@ -51,9 +52,11 @@ #include "lev-pand.h" #include "macro.h" #include "makeitem.h" +#include "mapmark.h" #include "monplace.h" #include "mon-util.h" #include "monstuff.h" +#include "mstuff2.h" #include "notes.h" #include "ouch.h" #include "overmap.h" @@ -175,6 +178,104 @@ bool grid_is_stone_stair(dungeon_feature_type grid) } } +bool grid_is_rock_stair(dungeon_feature_type grid) +{ + switch (grid) + { + case DNGN_ROCK_STAIRS_UP: + case DNGN_ROCK_STAIRS_DOWN: + return (true); + default: + return (false); + } +} + +bool grid_sealable_portal(dungeon_feature_type grid) +{ + switch (grid) + { + case DNGN_ENTER_HELL: + case DNGN_ENTER_ABYSS: + case DNGN_ENTER_PANDEMONIUM: + case DNGN_ENTER_LABYRINTH: + case DNGN_ENTER_BAZAAR: + return (true); + default: + return (false); + } +} + + +command_type grid_stair_direction(dungeon_feature_type grid) +{ + switch (grid) + { + case DNGN_STONE_STAIRS_UP_I: + case DNGN_STONE_STAIRS_UP_II: + case DNGN_STONE_STAIRS_UP_III: + case DNGN_ROCK_STAIRS_UP: + case DNGN_RETURN_FROM_ORCISH_MINES: + case DNGN_RETURN_FROM_HIVE: + case DNGN_RETURN_FROM_LAIR: + case DNGN_RETURN_FROM_SLIME_PITS: + case DNGN_RETURN_FROM_VAULTS: + case DNGN_RETURN_FROM_CRYPT: + case DNGN_RETURN_FROM_HALL_OF_BLADES: + case DNGN_RETURN_FROM_ZOT: + 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_RETURN_RESERVED_2: + case DNGN_RETURN_RESERVED_3: + case DNGN_RETURN_RESERVED_4: + case DNGN_ENTER_SHOP: + case DNGN_EXIT_HELL: + case DNGN_EXIT_BAZAAR: + return (CMD_GO_UPSTAIRS); + + case DNGN_ENTER_BAZAAR: + case DNGN_ENTER_HELL: + case DNGN_ENTER_LABYRINTH: + case DNGN_STONE_STAIRS_DOWN_I: + case DNGN_STONE_STAIRS_DOWN_II: + case DNGN_STONE_STAIRS_DOWN_III: + case DNGN_ROCK_STAIRS_DOWN: + case DNGN_ENTER_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_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_ZOT: + 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: + case DNGN_ENTER_RESERVED_2: + case DNGN_ENTER_RESERVED_3: + case DNGN_ENTER_RESERVED_4: + return (CMD_GO_DOWNSTAIRS); + + default: + return (CMD_NO_CMD); + } +} + bool grid_is_opaque( dungeon_feature_type grid ) { return (grid < MINSEE && grid != DNGN_ORCISH_IDOL); @@ -273,7 +374,18 @@ const char *grid_item_destruction_message( dungeon_feature_type grid ) { return grid == DNGN_DEEP_WATER? "You hear a splash." : grid == DNGN_LAVA ? "You hear a sizzling splash." - : "You hear an empty echo."; + : "You hear a crunching noise."; +} + +// Returns true if exits from this type of level involve going upstairs. +bool level_type_exits_up(level_area_type type) +{ + return (type == LEVEL_LABYRINTH || type == LEVEL_BAZAAR); +} + +bool level_type_exits_down(level_area_type type) +{ + return (type == LEVEL_PANDEMONIUM || type == LEVEL_ABYSS); } void search_around( bool only_adjacent ) @@ -339,6 +451,106 @@ void search_around( bool only_adjacent ) return; } // end search_around() +static bool dgn_shift_item_around(const coord_def &pos, item_def &item) +{ + std::list<coord_def> points; + for (int yi = -1; yi <= 1; ++yi) + { + for (int xi = -1; xi <= 1; ++xi) + { + if (!xi && !yi) + continue; + + const coord_def np(pos.x + xi, pos.y + yi); + if (!in_bounds(np) || travel_point_distance[np.x][np.y]) + continue; + + travel_point_distance[np.x][np.y] = 1; + + const dungeon_feature_type feat = grd(np); + if (!grid_is_solid(feat) && !grid_destroys_items(feat)) + { + int index = item.index(); + move_item_to_grid(&index, np.x, np.y); + return (true); + } + + points.push_back(np); + } + } + + for (std::list<coord_def>::iterator i = points.begin(); i != points.end(); + ++i) + { + if (dgn_shift_item_around(*i, item)) + return (true); + } + return (false); +} + +// Moves an item on the floor to the nearest adjacent floor-space. +static bool dgn_shift_item(const coord_def &pos, item_def &item) +{ + memset(travel_point_distance, 0, sizeof(travel_distance_grid_t)); + travel_point_distance[pos.x][pos.y] = 0; + return (dgn_shift_item_around(pos, item)); +} + +static void dgn_check_terrain_items(const coord_def &pos) +{ + const dungeon_feature_type grid = grd(pos); + if (grid_is_solid(grid) || grid_destroys_items(grid)) + { + int item = igrd(pos); + bool did_destroy = false; + while (item != NON_ITEM) + { + const int curr = item; + item = mitm[item].link; + + // Game-critical item. + if (true || item_is_critical(mitm[curr])) + dgn_shift_item(pos, mitm[curr]); + else + { + destroy_item(curr); + did_destroy = true; + } + } + if (did_destroy && player_can_hear(pos)) + mprf(MSGCH_SOUND, grid_item_destruction_message(grid)); + } +} + +static void dgn_check_terrain_monsters(const coord_def &pos) +{ + const int mindex = mgrd(pos); + if (mindex != NON_MONSTER) + { + monsters *mons = &menv[mindex]; + if (grid_is_solid(grd(pos))) + monster_teleport(mons, true, false); + else + mons_check_pool(mons, KILL_MISC, -1); + } +} + +void dungeon_terrain_changed(const coord_def &pos) +{ + dgn_check_terrain_items(pos); + if (pos == you.pos()) + { + if (!grid_is_solid(grd(pos))) + { + if (!you.flies()) + move_player_to_grid(pos.x, pos.y, false, true, false); + } + else + you_teleport_now(true, false); + } + dgn_check_terrain_monsters(pos); +} + void in_a_cloud() { int cl = env.cgrid[you.x_pos][you.y_pos]; @@ -558,9 +770,7 @@ void up_stairs(void) } // probably still need this check here (teleportation) -- bwr - if ((stair_find < DNGN_STONE_STAIRS_UP_I - || stair_find > DNGN_ROCK_STAIRS_UP) - && (stair_find < DNGN_RETURN_FROM_ORCISH_MINES || stair_find >= 150)) + if (grid_stair_direction(stair_find) != CMD_GO_UPSTAIRS) { mpr("You can't go up here."); return; @@ -601,9 +811,7 @@ void up_stairs(void) int old_level = you.your_level; // Interlevel travel data: - const bool collect_travel_data = you.level_type != LEVEL_LABYRINTH - && you.level_type != LEVEL_ABYSS - && you.level_type != LEVEL_PANDEMONIUM; + const bool collect_travel_data = can_travel_interlevel(); level_id old_level_id = level_id::current(); LevelInfo &old_level_info = travel_cache.get_level_info(old_level_id); @@ -614,7 +822,7 @@ void up_stairs(void) // Make sure we return to our main dungeon level... labyrinth entrances // in the abyss or pandemonium a bit trouble (well the labyrinth does // provide a way out of those places, its really not that bad I suppose) - if (you.level_type == LEVEL_LABYRINTH) + if (level_type_exits_up(you.level_type)) you.level_type = LEVEL_DUNGEON; you.your_level--; @@ -701,9 +909,7 @@ void up_stairs(void) // down stairs we're currently on. level_id new_level_id = level_id::current(); - if (you.level_type != LEVEL_PANDEMONIUM && - you.level_type != LEVEL_ABYSS && - you.level_type != LEVEL_LABYRINTH) + if (can_travel_interlevel()) { LevelInfo &new_level_info = travel_cache.get_level_info(new_level_id); @@ -756,12 +962,11 @@ void up_stairs(void) void down_stairs( int old_level, dungeon_feature_type force_stair ) { int i; - char old_level_type = you.level_type; + const level_area_type old_level_type = you.level_type; const bool was_a_labyrinth = you.level_type != LEVEL_DUNGEON; const dungeon_feature_type stair_find = force_stair? force_stair : grd[you.x_pos][you.y_pos]; - bool leave_abyss_pan = false; branch_type old_where = you.where_are_you; #ifdef SHUT_LABYRINTH @@ -774,14 +979,7 @@ void down_stairs( int old_level, dungeon_feature_type force_stair ) #endif // probably still need this check here (teleportation) -- bwr - if ((stair_find < DNGN_ENTER_LABYRINTH - || stair_find > DNGN_ROCK_STAIRS_DOWN) - && stair_find != DNGN_ENTER_HELL - && ((stair_find < DNGN_ENTER_DIS - || stair_find > DNGN_TRANSIT_PANDEMONIUM) - && stair_find != DNGN_STONE_ARCH) - && !(stair_find >= DNGN_ENTER_ORCISH_MINES - && stair_find < DNGN_RETURN_FROM_ORCISH_MINES)) + if (grid_stair_direction(stair_find) != CMD_GO_DOWNSTAIRS) { mpr( "You can't go down here!" ); return; @@ -824,7 +1022,7 @@ void down_stairs( int old_level, dungeon_feature_type force_stair ) // downstairs from a labyrinth implies that you've been banished (or been // sent to Pandemonium somehow). Decrementing your_level here is needed // to fix this buggy sequence: D:n -> Labyrinth -> Abyss -> D:(n+1). - if (you.level_type == LEVEL_LABYRINTH) + if (level_type_exits_up(you.level_type)) you.your_level--; if (stair_find == DNGN_ENTER_ZOT) @@ -858,9 +1056,7 @@ void down_stairs( int old_level, dungeon_feature_type force_stair ) } // Interlevel travel data: - bool collect_travel_data = you.level_type != LEVEL_LABYRINTH - && you.level_type != LEVEL_ABYSS - && you.level_type != LEVEL_PANDEMONIUM; + bool collect_travel_data = can_travel_interlevel(); level_id old_level_id = level_id::current(); LevelInfo &old_level_info = travel_cache.get_level_info(old_level_id); @@ -914,12 +1110,20 @@ void down_stairs( int old_level, dungeon_feature_type force_stair ) } } - if (stair_find == DNGN_ENTER_LABYRINTH) + if (stair_find == DNGN_ENTER_LABYRINTH || stair_find == DNGN_ENTER_BAZAAR) { // no longer a feature - unnotice_labyrinth_portal(); - you.level_type = LEVEL_LABYRINTH; + if (stair_find == DNGN_ENTER_LABYRINTH) + unnotice_labyrinth_portal(); grd[you.x_pos][you.y_pos] = DNGN_FLOOR; + // remove any markers that were going to expire this labyrinth. + if (map_marker *marker = env_find_marker(you.pos(), MAT_TIMED_FEATURE)) + dynamic_cast<map_timed_feature_marker*>(marker)->timeout(false); + } + + if (stair_find == DNGN_ENTER_LABYRINTH) + { + you.level_type = LEVEL_LABYRINTH; } else if (stair_find == DNGN_ENTER_ABYSS) { @@ -929,12 +1133,14 @@ void down_stairs( int old_level, dungeon_feature_type force_stair ) { you.level_type = LEVEL_PANDEMONIUM; } + else if (stair_find == DNGN_ENTER_BAZAAR) + { + you.level_type = LEVEL_BAZAAR; + } // When going downstairs into a special level, delete any previous // instances of it - if (you.level_type == LEVEL_LABYRINTH || - you.level_type == LEVEL_ABYSS || - you.level_type == LEVEL_PANDEMONIUM) + if (you.level_type != LEVEL_DUNGEON) { std::string lname = make_filename(you.your_name, you.your_level, you.where_are_you, @@ -947,7 +1153,6 @@ void down_stairs( int old_level, dungeon_feature_type force_stair ) if (stair_find == DNGN_EXIT_ABYSS || stair_find == DNGN_EXIT_PANDEMONIUM) { - leave_abyss_pan = true; mpr("You pass through the gate."); more(); } @@ -999,6 +1204,10 @@ void down_stairs( int old_level, dungeon_feature_type force_stair ) } break; + case LEVEL_BAZAAR: + mpr("You enter an inter-dimensional bazaar!"); + break; + default: mpr("You climb downwards."); break; @@ -1014,18 +1223,17 @@ void down_stairs( int old_level, dungeon_feature_type force_stair ) unsigned char pc = 0; unsigned char pt = random2avg(28, 3); + if (level_type_exits_up(you.level_type)) + you.your_level++; + else if (level_type_exits_down(you.level_type) + && !level_type_exits_down(old_level_type)) + you.your_level--; + switch (you.level_type) { - case LEVEL_LABYRINTH: - you.your_level++; - break; - case LEVEL_ABYSS: grd[you.x_pos][you.y_pos] = DNGN_FLOOR; - if (old_level_type != LEVEL_PANDEMONIUM) - you.your_level--; // Linley-suggested addition 17jan2000 {dlb} - init_pandemonium(); /* colours only */ if (player_in_hell()) @@ -1044,10 +1252,6 @@ void down_stairs( int old_level, dungeon_feature_type force_stair ) } else { - // Linley-suggested addition 17jan2000 {dlb} - if (old_level_type != LEVEL_ABYSS) - you.your_level--; - init_pandemonium(); for (pc = 0; pc < pt; pc++) @@ -1084,9 +1288,7 @@ void down_stairs( int old_level, dungeon_feature_type force_stair ) // upstairs we're currently on. level_id new_level_id = level_id::current(); - if (you.level_type != LEVEL_PANDEMONIUM && - you.level_type != LEVEL_ABYSS && - you.level_type != LEVEL_LABYRINTH) + if (can_travel_interlevel()) { LevelInfo &new_level_info = travel_cache.get_level_info(new_level_id); @@ -1143,6 +1345,9 @@ std::string level_description_string() if (you.level_type == LEVEL_LABYRINTH) return "- a Labyrinth"; + if (you.level_type == LEVEL_BAZAAR) + return "- a Bazaar"; + // level_type == LEVEL_DUNGEON char buf[200]; const int youbranch = you.where_are_you; @@ -1974,8 +2179,7 @@ unsigned short get_packed_place( branch_type branch, int subdepth, { unsigned short place = (unsigned short) ( (static_cast<int>(branch) << 8) | (subdepth & 0xFF) ); - if (level_type == LEVEL_ABYSS || level_type == LEVEL_PANDEMONIUM - || level_type == LEVEL_LABYRINTH) + if (level_type != LEVEL_DUNGEON) place = (unsigned short) ( (static_cast<int>(level_type) << 8) | 0xFF ); return place; } @@ -2012,6 +2216,8 @@ std::string place_name( unsigned short place, bool long_name, return ( long_name ? "Pandemonium" : "Pan" ); case LEVEL_LABYRINTH: return ( long_name ? "a Labyrinth" : "Lab" ); + case LEVEL_BAZAAR: + return ( long_name ? "a Bazaar" : "Bzr" ); default: return ( long_name ? "Buggy Badlands" : "Bug" ); } @@ -2248,6 +2454,8 @@ void run_environment_effects() if (!you.time_taken) return; + dungeon_events.fire_event(DET_TURN_ELAPSED); + // Each square in sfx_seeds has this chance of doing something special // per turn. const int sfx_chance = Base_Sfx_Chance * you.time_taken / 10; @@ -2255,7 +2463,7 @@ void run_environment_effects() // If there are a large number of seeds, speed things up by fudging the // numbers. - if (nseeds > 100) + if (nseeds > 50) { int nsels = div_rand_round( sfx_seeds.size() * sfx_chance, 100 ); if (one_chance_in(5)) @@ -2316,3 +2524,4 @@ int speed_to_duration(int speed) return div_rand_round(100, speed); } + diff --git a/crawl-ref/source/misc.h b/crawl-ref/source/misc.h index 46cc63cbf4..37477745fd 100644 --- a/crawl-ref/source/misc.h +++ b/crawl-ref/source/misc.h @@ -138,9 +138,12 @@ bool grid_is_wall(dungeon_feature_type grid); bool grid_is_opaque(dungeon_feature_type grid); bool grid_is_solid(dungeon_feature_type grid); bool grid_is_stone_stair(dungeon_feature_type grid); +bool grid_is_rock_stair(dungeon_feature_type grid); bool grid_is_solid(int x, int y); bool grid_is_solid(const coord_def &c); bool grid_is_trap(dungeon_feature_type grid); +command_type grid_stair_direction(dungeon_feature_type grid); +bool grid_sealable_portal(dungeon_feature_type grid); bool grid_is_water(dungeon_feature_type grid); bool grid_is_watery(dungeon_feature_type grid); @@ -150,6 +153,9 @@ bool grid_is_branch_stairs( dungeon_feature_type grid ); int grid_secret_door_appearance( int gx, int gy ); bool grid_destroys_items( dungeon_feature_type grid ); +bool level_type_exits_up(level_area_type type); +bool level_type_exits_down(level_area_type type); + std::string cloud_name(cloud_type type); bool is_damaging_cloud(cloud_type type); @@ -164,6 +170,9 @@ void setup_environment_effects(); // Lava smokes, swamp water mists. void run_environment_effects(); +// Terrain changed under 'pos', perform necessary effects. +void dungeon_terrain_changed(const coord_def &pos); + ////////////////////////////////////////////////////////////////////// // Places and names // diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index 5a8842e967..b88e6ff9af 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -3158,7 +3158,7 @@ void monsters::pandemon_init() ev = ghost->values[ GVAL_EV ]; speed = (one_chance_in(3) ? 10 : 6 + roll_dice(2, 9)); speed_increment = 70; - if (you.char_direction == DIR_ASCENDING && you.level_type == LEVEL_DUNGEON) + if (you.char_direction == GDT_ASCENDING && you.level_type == LEVEL_DUNGEON) colour = LIGHTRED; else colour = random_colour(); // demon's colour diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc index 115a9c28ab..b26aac753a 100644 --- a/crawl-ref/source/monplace.cc +++ b/crawl-ref/source/monplace.cc @@ -1289,7 +1289,7 @@ int mons_place( int mon_type, beh_type behaviour, int target, bool summoned, // this gives a slight challenge to the player as they ascend the // dungeon with the Orb - if (you.char_direction == DIR_ASCENDING && mon_type == RANDOM_MONSTER + if (you.char_direction == GDT_ASCENDING && mon_type == RANDOM_MONSTER && you.level_type == LEVEL_DUNGEON) { mon_type = pick_zot_exit_defender(); diff --git a/crawl-ref/source/ouch.cc b/crawl-ref/source/ouch.cc index d3ae812e33..88355d3166 100644 --- a/crawl-ref/source/ouch.cc +++ b/crawl-ref/source/ouch.cc @@ -921,6 +921,8 @@ void end_game( struct scorefile_entry &se ) LEVEL_PANDEMONIUM, false ).c_str() ); unlink( make_filename( you.your_name, 0, BRANCH_MAIN_DUNGEON, LEVEL_LABYRINTH, false ).c_str() ); + unlink( make_filename( you.your_name, 0, BRANCH_MAIN_DUNGEON, + LEVEL_BAZAAR, false ).c_str() ); // create base file name std::string basename = get_savedir_filename( you.your_name, "", "" ); diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc index 5c3d25b1a6..7458104d64 100644 --- a/crawl-ref/source/player.cc +++ b/crawl-ref/source/player.cc @@ -4769,7 +4769,7 @@ void player::init() your_level = 0; level_type = LEVEL_DUNGEON; where_are_you = BRANCH_MAIN_DUNGEON; - char_direction = DIR_DESCENDING; + char_direction = GDT_DESCENDING; prev_targ = MHITNOT; pet_target = MHITNOT; diff --git a/crawl-ref/source/shopping.cc b/crawl-ref/source/shopping.cc index d90e8d636d..627874cd5d 100644 --- a/crawl-ref/source/shopping.cc +++ b/crawl-ref/source/shopping.cc @@ -1500,6 +1500,14 @@ const shop_struct *get_shop(int sx, int sy) return (NULL); } +std::string shop_name(int sx, int sy, bool add_stop) +{ + std::string name(shop_name(sx, sy)); + if (add_stop) + name += "."; + return (name); +} + std::string shop_name(int sx, int sy) { const shop_struct *cshop = get_shop(sx, sy); diff --git a/crawl-ref/source/shopping.h b/crawl-ref/source/shopping.h index c1f044eefe..b558fed97b 100644 --- a/crawl-ref/source/shopping.h +++ b/crawl-ref/source/shopping.h @@ -27,6 +27,7 @@ void shop(); const shop_struct *get_shop(int sx, int sy); std::string shop_name(int sx, int sy); +std::string shop_name(int sx, int sy, bool add_stop); bool shoptype_identifies_stock(shop_type type); diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc index a01c3867f7..bd5687d5f1 100644 --- a/crawl-ref/source/spells3.cc +++ b/crawl-ref/source/spells3.cc @@ -557,7 +557,7 @@ bool allow_control_teleport( bool silent ) case BRANCH_HALL_OF_ZOT: // Cannot control teleport until the Orb is picked up if (player_branch_depth() == branches[BRANCH_HALL_OF_ZOT].depth - && you.char_direction != DIR_ASCENDING) + && you.char_direction != GDT_ASCENDING) { ret = false; } diff --git a/crawl-ref/source/stash.cc b/crawl-ref/source/stash.cc index 7cd5e28a81..b93a231f6d 100644 --- a/crawl-ref/source/stash.cc +++ b/crawl-ref/source/stash.cc @@ -44,6 +44,7 @@ void stash_init_new_level() { // If there's an existing stash level for Pan, blow it away. stashes.remove_level( level_id(LEVEL_PANDEMONIUM) ); + stashes.remove_level( level_id(LEVEL_BAZAAR) ); } std::string userdef_annotate_item(const char *s, const item_def *item, diff --git a/crawl-ref/source/stuff.cc b/crawl-ref/source/stuff.cc index 4bc380a939..a26a318c7a 100644 --- a/crawl-ref/source/stuff.cc +++ b/crawl-ref/source/stuff.cc @@ -193,6 +193,15 @@ int random_range(int low, int high) return (low + random2(high - low + 1)); } +int random_range(int low, int high, int nrolls) +{ + ASSERT(nrolls > 0); + int sum = 0; + for (int i = 0; i < nrolls; ++i) + sum += random_range(low, high); + return (sum / nrolls); +} + int random_choose(int first, ...) { va_list args; @@ -732,7 +741,7 @@ bool adjacent( int x, int y, int x2, int y2 ) return (abs(x - x2) <= 1 && abs(y - y2) <= 1); } -bool silenced(char x, char y) +bool silenced(int x, int y) { if (you.duration[DUR_SILENCE] > 0 && distance(x, y, you.x_pos, you.y_pos) <= 36) // (6 * 6) @@ -751,7 +760,7 @@ bool silenced(char x, char y) } } // end silenced() -bool player_can_hear(char x, char y) +bool player_can_hear(int x, int y) { return (!silenced(x, y) && !silenced(you.x_pos, you.y_pos)); } // end player_can_hear() @@ -1001,6 +1010,10 @@ int element_colour( int element, bool no_random ) ret = tmp_rand < 100? CYAN : BLUE; break; + case EC_SHIMMER_BLUE: + ret = random_choose_weighted(80, BLUE, 20, LIGHTBLUE, 5, CYAN, 0); + break; + case EC_RANDOM: ret = 1 + random2(15); // always random break; @@ -1136,67 +1149,3 @@ int coord_def::distance_from(const coord_def &other) const { return (grid_distance(x, y, other.x, other.y)); } - -////////////////////////////////////////////////////////////////////////// -// crawl_environment - -void crawl_environment::add_marker(map_marker *marker) -{ - markers.insert(dgn_pos_marker(marker->pos, marker)); -} - -void crawl_environment::remove_marker(map_marker *marker) -{ - std::pair<dgn_marker_map::iterator, dgn_marker_map::iterator> - els = markers.equal_range(marker->pos); - for (dgn_marker_map::iterator i = els.first; i != els.second; ++i) - { - if (i->second == marker) - { - markers.erase(i); - break; - } - } - delete marker; -} - -void crawl_environment::remove_markers_at(const coord_def &c) -{ - std::pair<dgn_marker_map::iterator, dgn_marker_map::iterator> - els = markers.equal_range(c); - for (dgn_marker_map::iterator i = els.first; i != els.second; ) - { - dgn_marker_map::iterator todel = i++; - delete todel->second; - markers.erase(todel); - } -} - -map_marker *crawl_environment::find_marker(const coord_def &c, - map_marker_type type) const -{ - std::pair<dgn_marker_map::const_iterator, dgn_marker_map::const_iterator> - els = markers.equal_range(c); - for (dgn_marker_map::const_iterator i = els.first; i != els.second; ++i) - if (type == MAT_ANY || i->second->get_type() == type) - return (i->second); - return (NULL); -} - -std::vector<map_marker*> crawl_environment::get_markers(const coord_def &c) - const -{ - std::pair<dgn_marker_map::const_iterator, dgn_marker_map::const_iterator> - els = markers.equal_range(c); - std::vector<map_marker*> rmarkers; - for (dgn_marker_map::const_iterator i = els.first; i != els.second; ++i) - rmarkers.push_back(i->second); - return (rmarkers); -} - -void crawl_environment::clear_markers() -{ - for (dgn_marker_map::iterator i = markers.begin(); i != markers.end(); ++i) - delete i->second; - markers.clear(); -} diff --git a/crawl-ref/source/stuff.h b/crawl-ref/source/stuff.h index 42009c228d..39fa0da021 100644 --- a/crawl-ref/source/stuff.h +++ b/crawl-ref/source/stuff.h @@ -34,6 +34,7 @@ int div_rand_round( int num, int den ); bool one_chance_in(int a_million); int random2(int randmax); int random_range(int low, int high); +int random_range(int low, int high, int nrolls); int random_choose(int first, ...); int random_choose_weighted(int weight, int first, ...); unsigned long random_int(); @@ -90,9 +91,14 @@ int grid_distance( int x, int y, int x2, int y2 ); int distance( int x, int y, int x2, int y2); bool adjacent( int x, int y, int x2, int y2 ); -bool silenced(char x, char y); +bool silenced(int x, int y); +inline bool silenced(const coord_def &p) { return silenced(p.x, p.y); } -bool player_can_hear(char x, char y); +bool player_can_hear(int x, int y); +inline bool player_can_hear(const coord_def &p) +{ + return player_can_hear(p.x, p.y); +} unsigned char random_colour(); unsigned char random_uncommon_colour(); diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc index 8b38c9f764..5748975294 100644 --- a/crawl-ref/source/tags.cc +++ b/crawl-ref/source/tags.cc @@ -77,6 +77,7 @@ #include "files.h" #include "itemname.h" #include "itemprop.h" +#include "mapmark.h" #include "monstuff.h" #include "mon-util.h" #include "mtransit.h" @@ -1360,8 +1361,8 @@ static void tag_construct_level(struct tagHeader &th) } // how many shops? - marshallByte(th, 5); - for (int i = 0; i < 5; i++) + marshallByte(th, MAX_SHOPS); + for (int i = 0; i < MAX_SHOPS; i++) { marshallByte(th, env.shop[i].keeper_name[0]); marshallByte(th, env.shop[i].keeper_name[1]); @@ -1588,6 +1589,7 @@ static void tag_read_level( struct tagHeader &th, char minorVersion ) // how many shops? const int num_shops = unmarshallByte(th); + ASSERT(num_shops <= MAX_SHOPS); for (int i = 0; i < num_shops; i++) { env.shop[i].keeper_name[0] = unmarshallByte(th); @@ -1600,12 +1602,12 @@ static void tag_read_level( struct tagHeader &th, char minorVersion ) env.shop[i].level = unmarshallByte(th); } - env.clear_markers(); + env_clear_markers(); const int nmarkers = unmarshallShort(th); for (int i = 0; i < nmarkers; ++i) { if (map_marker *mark = map_marker::read_marker(th)) - env.add_marker(mark); + env_add_marker(mark); } } diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc index 3bdd1219db..a12c48eca3 100644 --- a/crawl-ref/source/travel.cc +++ b/crawl-ref/source/travel.cc @@ -238,8 +238,7 @@ const char *run_mode_name(int runmode) unsigned char is_waypoint(int x, int y) { - if (you.level_type == LEVEL_LABYRINTH || you.level_type == LEVEL_ABYSS - || you.level_type == LEVEL_PANDEMONIUM) + if (!can_travel_interlevel()) return 0; return curr_waypoints[x][y]; } @@ -570,6 +569,8 @@ void initialise_travel() traversable_terrain[DNGN_RETURN_FROM_TOMB] = traversable_terrain[DNGN_RETURN_FROM_SWAMP] = traversable_terrain[DNGN_RETURN_FROM_SHOALS] = + traversable_terrain[DNGN_ENTER_BAZAAR] = + traversable_terrain[DNGN_EXIT_BAZAAR] = traversable_terrain[DNGN_ALTAR_ZIN] = traversable_terrain[DNGN_ALTAR_SHINING_ONE] = traversable_terrain[DNGN_ALTAR_KIKUBAAQUDGHA] = @@ -2267,18 +2268,9 @@ void start_translevel_travel(bool prompt_for_destination) } } -command_type stair_direction(dungeon_feature_type stair) -{ - return ((stair < DNGN_STONE_STAIRS_UP_I - || stair > DNGN_ROCK_STAIRS_UP) - && (stair < DNGN_RETURN_FROM_ORCISH_MINES - || stair > DNGN_RETURN_RESERVED_4)) - ? CMD_GO_DOWNSTAIRS : CMD_GO_UPSTAIRS; -} - command_type trans_negotiate_stairs() { - return stair_direction(grd[you.x_pos][you.y_pos]); + return grid_stair_direction(grd[you.x_pos][you.y_pos]); } static int target_distance_from(const coord_def &pos) @@ -2743,6 +2735,8 @@ level_id level_id::parse_level_id(const std::string &s) throw (std::string) return (level_id(LEVEL_PANDEMONIUM)); else if (branch == "Lab") return (level_id(LEVEL_LABYRINTH)); + else if (branch == "Bzr") + return (level_id(LEVEL_BAZAAR)); const branch_type br = str_to_branch(branch); if (br == NUM_BRANCHES) @@ -3317,8 +3311,7 @@ void TravelCache::delete_waypoint() void TravelCache::add_waypoint(int x, int y) { - if (you.level_type == LEVEL_LABYRINTH || you.level_type == LEVEL_ABYSS - || you.level_type == LEVEL_PANDEMONIUM) + if (!can_travel_interlevel()) { mpr("Sorry, you can't set a waypoint here."); return; @@ -3475,15 +3468,13 @@ void TravelCache::fixup_levels() bool can_travel_to(const level_id &id) { - return ((id.level_type == LEVEL_DUNGEON - && can_travel_interlevel()) - || (id.level_type == LEVEL_PANDEMONIUM - && you.level_type == LEVEL_PANDEMONIUM)); + return ((id.level_type == LEVEL_DUNGEON && can_travel_interlevel()) + || (id.level_type == you.level_type && player_in_mappable_area())); } bool can_travel_interlevel() { - return (player_in_mappable_area() && you.level_type != LEVEL_PANDEMONIUM); + return (you.level_type == LEVEL_DUNGEON); } ///////////////////////////////////////////////////////////////////////////// diff --git a/crawl-ref/source/travel.h b/crawl-ref/source/travel.h index a4e4317220..30455af20f 100644 --- a/crawl-ref/source/travel.h +++ b/crawl-ref/source/travel.h @@ -35,7 +35,6 @@ void update_excludes(); bool is_exclude_root(const coord_def &p); bool is_stair(dungeon_feature_type gridc); bool is_travelable_stair(dungeon_feature_type gridc); -command_type stair_direction(dungeon_feature_type stair_feat); command_type direction_to_command( char x, char y ); bool is_resting( void ); bool can_travel_interlevel(); diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc index c75cca84d2..37efba43b8 100644 --- a/crawl-ref/source/view.cc +++ b/crawl-ref/source/view.cc @@ -308,7 +308,7 @@ static int view_emphasised_colour(int x, int y, dungeon_feature_type feat, { if (is_travelable_stair(feat) && !travel_cache.know_stair(coord_def(x, y))) { - if ((you.your_level || stair_direction(feat) == CMD_GO_DOWNSTAIRS) + if ((you.your_level || grid_stair_direction(feat) == CMD_GO_DOWNSTAIRS) && you.where_are_you != BRANCH_VESTIBULE_OF_HELL) return (newcolour); } @@ -2228,6 +2228,8 @@ bool is_feature(int feature, int x, int y) { case DNGN_ENTER_HELL: case DNGN_ENTER_LABYRINTH: + case DNGN_ENTER_BAZAAR: + case DNGN_EXIT_BAZAAR: case DNGN_ENTER_SHOP: case DNGN_ENTER_DIS: case DNGN_ENTER_GEHENNA: @@ -3388,6 +3390,15 @@ void init_feature_table( void ) Feature[i].seen_colour = CYAN; break; + case DNGN_ENTER_BAZAAR: + case DNGN_EXIT_BAZAAR: + Feature[i].symbol = Options.char_table[ DCHAR_ARCH ]; + Feature[i].colour = EC_SHIMMER_BLUE; + Feature[i].notable = true; + Feature[i].map_colour = LIGHTGREY; + Feature[i].seen_colour = EC_SHIMMER_BLUE; + break; + case DNGN_ROCK_STAIRS_DOWN: Feature[i].symbol = Options.char_table[ DCHAR_STAIRS_DOWN ]; Feature[i].colour = BROWN; diff --git a/crawl-ref/source/view.h b/crawl-ref/source/view.h index eae097e772..5b6145d68b 100644 --- a/crawl-ref/source/view.h +++ b/crawl-ref/source/view.h @@ -150,6 +150,7 @@ void clear_cset_overrides(); void add_cset_override(char_set_type set, const std::string &overrides); bool see_grid( int grx, int gry ); +inline bool see_grid(const coord_def &p) { return see_grid(p.x, p.y); } std::string screenshot(bool fullscreen = false); |