summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-07-21 12:17:29 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-07-21 12:17:29 +0000
commit9843737e73a47ef6f1da0554b7ca73018d52d345 (patch)
tree9381ef8b914bc801386f62ce2713c59c17b6a9e8
parentb27a757b68bf8a1dcbcb9b3a5cfea5c1278c9bb4 (diff)
downloadcrawl-ref-9843737e73a47ef6f1da0554b7ca73018d52d345.tar.gz
crawl-ref-9843737e73a47ef6f1da0554b7ca73018d52d345.zip
Updated level-design.txt.
Moved map markers to mapmark.cc. Added support for timer markers that remove a feature after a certain timeout. Need to hook up messaging to Lua. Added bazaars (need more bazaar layouts). git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1899 c06c8d41-db1a-0410-9941-cceddc491573
-rw-r--r--crawl-ref/docs/level-design.txt50
-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
54 files changed, 1681 insertions, 575 deletions
diff --git a/crawl-ref/docs/level-design.txt b/crawl-ref/docs/level-design.txt
index b37006cb44..9071f5f2b8 100644
--- a/crawl-ref/docs/level-design.txt
+++ b/crawl-ref/docs/level-design.txt
@@ -343,7 +343,7 @@ PLACE: Used to specify certain special levels. Existing special levels are:
PLACE can be used with random vaults and minivaults for testing them.
TAGS: generate_awake, no_item_gen, no_monster_gen, no_pool_fixup, orc_entry,
- mini_float
+ mini_float, uniq, uniq_BAR
Tags go an a TAGS: line and are space-separated. Valid tags are:
* "dummy": this tag indicates that the vault is a stub; if the dungeon
@@ -362,17 +362,20 @@ TAGS: generate_awake, no_item_gen, no_monster_gen, no_pool_fixup, orc_entry,
* "no_pool_fixup": prevents water squares next to land from being
randomly converted from deep water (the default) to shallow.
* "branch_entry" eg. "orc_entry", "lair_entry" etc.
- If chosen, these maps will contain the stairs for that branch.
- Use "O" to place the stairs. Branch entries should go to
- ebranch.des. If a branch has very few entries, a dummy entry is
- advisable to make sure the player doesn't get bored of the same
- few entries recycled ad nauseam.
+ If chosen, these maps will contain the stairs for that
+ branch. Use "O" to place the stairs. If a branch has very
+ few entries, a dummy entry is advisable to make sure the
+ player doesn't get bored of the same few entries recycled
+ ad nauseam.
* "mini_float": applicable only to minivaults, requests that
the dungeon builder pick random exits from the minivault and
connect it to the rest of the level, similar to the exit
behaviour for floating vaults.
* "mnoleg" or the name of some other pandemonium lord. This makes
the map eligible for said pan lord's lair.
+ * "uniq": specifies that this vault should be used only once in a game.
+ * "uniq_BAR": (uniq_ with any suffix) specifies that only one vault
+ with this tag can be used in a game.
FLAGS: no_rotate, no_hmirror, no_vmirror
Flags go on a FLAGS: line and are space-separated. Valid flags are:
@@ -520,10 +523,18 @@ KFEAT: Z = C / needle trap / antique armour shop / altar of Zin
with C (random altar), a needle trap, an antique armour shop, or
an altar of Zin. Different instances of Z may receive different
replacements. To force a single replacement for all Z, use:
+
KFEAT: Z : C / needle trap / antique armour shop
+
You'll notice that 'Z' is the symbol of the Orb of Zot. Kxxx
directives allow you to assign arbitrary definitions to any symbol.
+ KFEAT features are specified as a unique substring of the in-game
+ description of the feature; simple * and ? wildcards can also be
+ used. For instance, to place a portal to the Abyss, you can use:
+
+ KFEAT: A = gate to the * Abyss
+
If you want no feature as an option in a KFEAT line, use 'floor'.
If you do not want to specify the type of shop, use 'any shop' or
'random shop'.
@@ -558,12 +569,13 @@ KITEM: ? = potion of healing / potion of restore abilities
placeholder. It can be combined with KFEAT: and KMONS: lines for
the same placeholder.
- For items like gold, you have to use the description of items
- instead of their shortcuts. For example,
+ You can use "gold" or "$" to place gold:
KITEM: ? = nothing / gold
- works but the following does not:
KITEM: ? = nothing / $
+ You can use q: to specify quantities:
+ KITEM: ? = q:100 gold
+
KITEM: allows you to place multiple items on the same square:
KITEM: ? = bread ration, potion of water, potion of porridge
@@ -697,7 +709,8 @@ map." (to compound the confusion, the line number for this error will
be the first line number of the map following the buggy map).
This error is because although the map is Elf or Orc only, at compile
-time, the branch is *neither* Elf nor Orc.
+time, the branch is *neither* Elf nor Orc, so the level-compiler
+thinks you've neglected to define a map.
Lua code can detect the compile phase using crawl.game_started() which
returns true only when the player has started a game (and will return
@@ -1050,9 +1063,10 @@ Lua API - global game state
The "crawl" module provides functions that describe the game state or
provide utility methods.
-mpr, mesclr, random2, redraw_screen, input_line, c_input_line, getch, kbhit,
-flush_input, sendkeys, playsound, runmacro, bindkey, setopt, msgch_num,
-msgch_name, regex, message_filter, trim, split, game_started, err_trace, args
+mpr, mesclr, random2, coinflip, one_chance_in, redraw_screen,
+input_line, c_input_line, getch, kbhit, flush_input, sendkeys,
+playsound, runmacro, bindkey, setopt, msgch_num, msgch_name, regex,
+message_filter, trim, split, game_started, err_trace, args
Lua API - character information
@@ -1060,8 +1074,8 @@ Lua API - character information
The "you" module provides functions that describe the player character.
-turn_is_over, spells, abilities, name, race, class, god, hp, mp, hunger,
-strength, intelligence, dexterity, xl, exp, res_poison, res_fire, res_cold,
-res_draining, res_shock, res_statdrain, res_mutation, res_slowing, gourmand,
-levitating, flying, transform, stop_activity, floor_items, where, branch,
-subdepth, absdepth
+turn_is_over, spells, abilities, name, race, class, god, hp, mp,
+hunger, strength, intelligence, dexterity, xl, exp, res_poison,
+res_fire, res_cold, res_draining, res_shock, res_statdrain,
+res_mutation, res_slowing, gourmand, levitating, flying, transform,
+stop_activity, floor_items, where, branch, subdepth, absdepth
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);