summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref/source')
-rw-r--r--crawl-ref/source/acr.cc29
-rw-r--r--crawl-ref/source/beam.cc2
-rw-r--r--crawl-ref/source/dat/bazaar.des67
-rw-r--r--crawl-ref/source/dat/clua/dungeon.lua1
-rw-r--r--crawl-ref/source/dat/clua/loadmaps.lua8
-rw-r--r--crawl-ref/source/dat/hells.des3
-rw-r--r--crawl-ref/source/dat/lab.des11
-rw-r--r--crawl-ref/source/debug.cc7
-rw-r--r--crawl-ref/source/defines.h5
-rw-r--r--crawl-ref/source/dgnevent.cc133
-rw-r--r--crawl-ref/source/dgnevent.h105
-rw-r--r--crawl-ref/source/direct.cc235
-rw-r--r--crawl-ref/source/direct.h12
-rw-r--r--crawl-ref/source/dungeon.cc255
-rw-r--r--crawl-ref/source/dungeon.h47
-rw-r--r--crawl-ref/source/effects.cc5
-rw-r--r--crawl-ref/source/enum.h33
-rw-r--r--crawl-ref/source/externs.h8
-rw-r--r--crawl-ref/source/files.cc37
-rw-r--r--crawl-ref/source/hiscores.cc4
-rw-r--r--crawl-ref/source/hiscores.h2
-rw-r--r--crawl-ref/source/it_use3.cc5
-rw-r--r--crawl-ref/source/itemprop.cc12
-rw-r--r--crawl-ref/source/itemprop.h3
-rw-r--r--crawl-ref/source/items.cc10
-rw-r--r--crawl-ref/source/lev-pand.cc2
-rw-r--r--crawl-ref/source/libutil.cc66
-rw-r--r--crawl-ref/source/libutil.h6
-rw-r--r--crawl-ref/source/luadgn.cc10
-rw-r--r--crawl-ref/source/makefile.obj2
-rw-r--r--crawl-ref/source/makeitem.cc2
-rw-r--r--crawl-ref/source/mapdef.cc92
-rw-r--r--crawl-ref/source/mapdef.h8
-rw-r--r--crawl-ref/source/mapmark.cc395
-rw-r--r--crawl-ref/source/mapmark.h101
-rw-r--r--crawl-ref/source/maps.h2
-rw-r--r--crawl-ref/source/misc.cc307
-rw-r--r--crawl-ref/source/misc.h9
-rw-r--r--crawl-ref/source/mon-util.cc2
-rw-r--r--crawl-ref/source/monplace.cc2
-rw-r--r--crawl-ref/source/ouch.cc2
-rw-r--r--crawl-ref/source/player.cc2
-rw-r--r--crawl-ref/source/shopping.cc8
-rw-r--r--crawl-ref/source/shopping.h1
-rw-r--r--crawl-ref/source/spells3.cc2
-rw-r--r--crawl-ref/source/stash.cc1
-rw-r--r--crawl-ref/source/stuff.cc81
-rw-r--r--crawl-ref/source/stuff.h10
-rw-r--r--crawl-ref/source/tags.cc10
-rw-r--r--crawl-ref/source/travel.cc29
-rw-r--r--crawl-ref/source/travel.h1
-rw-r--r--crawl-ref/source/view.cc13
-rw-r--r--crawl-ref/source/view.h1
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);