summaryrefslogtreecommitdiffstats
path: root/crawl-ref
diff options
context:
space:
mode:
authorJude Brown <bookofjude@users.sourceforge.net>2009-12-28 11:31:01 +1000
committerJude Brown <bookofjude@users.sourceforge.net>2009-12-28 11:31:01 +1000
commit09f88ea76c06d310aa4b68ca9336a2522e47e13f (patch)
tree3f6cd25dcc4279464af774eef3630e54646c5cb7 /crawl-ref
parentd5382a4e13ed6d6298ea4912c74454147d27f93a (diff)
parentb29345dd9d85fb18ec21ad19db53636a7bbf68e2 (diff)
downloadcrawl-ref-09f88ea76c06d310aa4b68ca9336a2522e47e13f.tar.gz
crawl-ref-09f88ea76c06d310aa4b68ca9336a2522e47e13f.zip
Merge branch 'master' into wizlab
Conflicts: crawl-ref/source/rltiles/dc-mon.txt
Diffstat (limited to 'crawl-ref')
-rw-r--r--crawl-ref/source/actor.h8
-rw-r--r--crawl-ref/source/artefact.cc2
-rw-r--r--crawl-ref/source/beam.cc5
-rw-r--r--crawl-ref/source/cloud.cc113
-rw-r--r--crawl-ref/source/cloud.h24
-rw-r--r--crawl-ref/source/dat/clua/lm_fog.lua21
-rw-r--r--crawl-ref/source/dat/ossuary.des44
-rw-r--r--crawl-ref/source/dat/shoals.des8
-rw-r--r--crawl-ref/source/dbg-util.cc15
-rw-r--r--crawl-ref/source/delay.cc2
-rw-r--r--crawl-ref/source/dgn-shoals.cc692
-rw-r--r--crawl-ref/source/dgn-shoals.h7
-rw-r--r--crawl-ref/source/directn.cc12
-rw-r--r--crawl-ref/source/dungeon.cc477
-rw-r--r--crawl-ref/source/dungeon.h12
-rw-r--r--crawl-ref/source/effects.cc2
-rw-r--r--crawl-ref/source/env.h3
-rw-r--r--crawl-ref/source/externs.h12
-rw-r--r--crawl-ref/source/fight.cc4
-rw-r--r--crawl-ref/source/food.cc4
-rw-r--r--crawl-ref/source/godwrath.cc3
-rw-r--r--crawl-ref/source/invent.cc2
-rw-r--r--crawl-ref/source/item_use.cc42
-rw-r--r--crawl-ref/source/itemname.cc10
-rw-r--r--crawl-ref/source/itemprop.cc51
-rw-r--r--crawl-ref/source/itemprop.h7
-rw-r--r--crawl-ref/source/items.cc46
-rw-r--r--crawl-ref/source/l_dgn.cc18
-rw-r--r--crawl-ref/source/l_item.cc2
-rw-r--r--crawl-ref/source/main.cc4
-rw-r--r--crawl-ref/source/makefile.obj2
-rw-r--r--crawl-ref/source/makeitem.cc10
-rw-r--r--crawl-ref/source/mapdef.cc9
-rw-r--r--crawl-ref/source/maps.cc2
-rw-r--r--crawl-ref/source/message.cc15
-rw-r--r--crawl-ref/source/misc.cc7
-rw-r--r--crawl-ref/source/mislead.cc127
-rw-r--r--crawl-ref/source/mislead.h8
-rw-r--r--crawl-ref/source/mon-cast.cc103
-rw-r--r--crawl-ref/source/mon-place.cc4
-rw-r--r--crawl-ref/source/mon-stuff.cc2
-rw-r--r--crawl-ref/source/monster.cc6
-rw-r--r--crawl-ref/source/player.cc18
-rw-r--r--crawl-ref/source/player.h1
-rw-r--r--crawl-ref/source/religion.cc4
-rw-r--r--crawl-ref/source/rltiles/dc-mon.txt1
-rw-r--r--crawl-ref/source/rltiles/dc-mon/slave.pngbin0 -> 3395 bytes
-rw-r--r--crawl-ref/source/rltiles/dc-mon/unique/maurice.pngbin902 -> 1080 bytes
-rw-r--r--crawl-ref/source/show.cc3
-rw-r--r--crawl-ref/source/spells1.cc17
-rw-r--r--crawl-ref/source/spells1.h9
-rw-r--r--crawl-ref/source/spells2.cc4
-rw-r--r--crawl-ref/source/spells3.cc12
-rw-r--r--crawl-ref/source/spells4.cc5
-rw-r--r--crawl-ref/source/spells4.h3
-rw-r--r--crawl-ref/source/spl-util.cc19
-rw-r--r--crawl-ref/source/spl-util.h6
-rw-r--r--crawl-ref/source/tags.cc27
-rw-r--r--crawl-ref/source/tags.h6
-rw-r--r--crawl-ref/source/terrain.cc2
-rw-r--r--crawl-ref/source/tilepick.cc111
-rw-r--r--crawl-ref/source/tilereg.cc12
-rw-r--r--crawl-ref/source/tiles.h2
-rw-r--r--crawl-ref/source/tilesdl.cc2
-rw-r--r--crawl-ref/source/transfor.cc2
-rw-r--r--crawl-ref/source/trap_def.h1
-rw-r--r--crawl-ref/source/traps.cc73
-rw-r--r--crawl-ref/source/tutorial.cc6
-rw-r--r--crawl-ref/source/viewchar.cc14
-rw-r--r--crawl-ref/source/wiz-dgn.cc91
-rw-r--r--crawl-ref/source/wiz-dgn.h3
-rw-r--r--crawl-ref/source/wiz-item.cc2
-rw-r--r--crawl-ref/source/xom.cc2
73 files changed, 1524 insertions, 881 deletions
diff --git a/crawl-ref/source/actor.h b/crawl-ref/source/actor.h
index f8e920eb14..b29e826307 100644
--- a/crawl-ref/source/actor.h
+++ b/crawl-ref/source/actor.h
@@ -28,7 +28,15 @@ public:
virtual bool is_summoned(int* duration = NULL,
int* summon_type = NULL) const = 0;
+ // [ds] Low-level moveto() - moves the actor without updating relevant
+ // grids, such as mgrd.
virtual void moveto(const coord_def &c) = 0;
+
+ // High-level actor movement. If in doubt, use this. Returns true if the
+ // actor cannot be moved to the target, possibly because it is already
+ // occupied.
+ virtual bool move_to_pos(const coord_def &c) = 0;
+
virtual void set_position(const coord_def &c);
virtual const coord_def& pos() const { return position; }
diff --git a/crawl-ref/source/artefact.cc b/crawl-ref/source/artefact.cc
index 9b2cc6feed..71ae7b27cd 100644
--- a/crawl-ref/source/artefact.cc
+++ b/crawl-ref/source/artefact.cc
@@ -1923,7 +1923,7 @@ bool make_item_randart( item_def &item, bool force_mundane )
if (item.flags & ISFLAG_UNRANDART)
return (false);
- if (item_is_mundane(item) && !one_chance_in(5) && !force_mundane)
+ if (item.is_mundane() && !one_chance_in(5) && !force_mundane)
return (false);
ASSERT(!item.props.exists(KNOWN_PROPS_KEY));
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index cdeefc8204..8b05a833d9 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -3243,17 +3243,18 @@ void bolt::affect_place_clouds()
if (p == you.pos())
{
mprf("The %s you are in turns into %s!",
- cloud_name(ctype).c_str(), cloud_name(new_type).c_str());
+ cloud_name(cloudidx).c_str(), cloud_name(new_type).c_str());
obvious_effect = true;
}
else if (you.see_cell(p))
{
mprf("A cloud of %s turns into %s.",
- cloud_name(ctype).c_str(), cloud_name(new_type).c_str());
+ cloud_name(cloudidx).c_str(), cloud_name(new_type).c_str());
obvious_effect = true;
}
ctype = new_type;
+ env.cloud[cloudidx].name = "";
return;
}
diff --git a/crawl-ref/source/cloud.cc b/crawl-ref/source/cloud.cc
index 638432f504..58eb185c97 100644
--- a/crawl-ref/source/cloud.cc
+++ b/crawl-ref/source/cloud.cc
@@ -27,6 +27,11 @@
#include "stuff.h"
#include "env.h"
#include "terrain.h"
+#ifdef USE_TILE
+#include "tiles.h"
+#include "tiledef-gui.h"
+#include "tiledef-main.h"
+#endif
#include "mutation.h"
static int _actual_spread_rate(cloud_type type, int spread_rate)
@@ -70,7 +75,8 @@ static bool _killer_whose_match(kill_category whose, killer_type killer)
static void _new_cloud( int cloud, cloud_type type, const coord_def& p,
int decay, kill_category whose, killer_type killer,
- unsigned char spread_rate )
+ unsigned char spread_rate, int colour, std::string name,
+ std::string tile)
{
ASSERT( env.cloud[cloud].type == CLOUD_NONE );
ASSERT(_killer_whose_match(whose, killer));
@@ -83,13 +89,28 @@ static void _new_cloud( int cloud, cloud_type type, const coord_def& p,
c.whose = whose;
c.killer = killer;
c.spread_rate = spread_rate;
+ c.colour = colour;
+ c.name = name;
+#ifdef USE_TILE
+ if (!tile.empty())
+ {
+ unsigned int index;
+ if (!tile_main_index(tile.c_str(), index))
+ {
+ mprf(MSGCH_ERROR, "Invalid tile requested for cloud: '%s'.", tile.c_str());
+ tile = "";
+ }
+ }
+#endif
+ c.tile = tile;
env.cgrid(p) = cloud;
env.cloud_no++;
}
static void _place_new_cloud(cloud_type cltype, const coord_def& p, int decay,
kill_category whose, killer_type killer,
- int spread_rate)
+ int spread_rate, int colour, std::string name,
+ std::string tile)
{
if (env.cloud_no >= MAX_CLOUDS)
return;
@@ -99,7 +120,8 @@ static void _place_new_cloud(cloud_type cltype, const coord_def& p, int decay,
{
if (env.cloud[ci].type == CLOUD_NONE) // i.e., is empty
{
- _new_cloud( ci, cltype, p, decay, whose, killer, spread_rate );
+ _new_cloud( ci, cltype, p, decay, whose, killer, spread_rate, colour,
+ name, tile );
break;
}
}
@@ -129,7 +151,7 @@ static int _spread_cloud(const cloud_struct &cloud)
newdecay = cloud.decay - 1;
_place_new_cloud( cloud.type, *ai, newdecay, cloud.whose, cloud.killer,
- cloud.spread_rate );
+ cloud.spread_rate, cloud.colour, cloud.name, cloud.tile );
extra_decay += 8;
}
@@ -151,7 +173,8 @@ static void _spread_fire(const cloud_struct &cloud)
// burning trees produce flames all around
if (!cell_is_solid(*ai) && make_flames)
_place_new_cloud( CLOUD_FIRE, *ai, cloud.decay/2+1, cloud.whose,
- cloud.killer, cloud.spread_rate );
+ cloud.killer, cloud.spread_rate, cloud.colour,
+ cloud.name, cloud.tile );
// forest fire doesn't spread in all directions at once,
// every neighbouring square gets a separate roll
@@ -161,7 +184,8 @@ static void _spread_fire(const cloud_struct &cloud)
mpr("The forest fire spreads!");
grd(*ai) = DNGN_FLOOR;
_place_new_cloud( cloud.type, *ai, random2(30)+25, cloud.whose,
- cloud.killer, cloud.spread_rate );
+ cloud.killer, cloud.spread_rate, cloud.colour,
+ cloud.name, cloud.tile );
}
}
@@ -248,6 +272,9 @@ void delete_cloud( int cloud )
c.whose = KC_OTHER;
c.killer = KILL_NONE;
c.spread_rate = 0;
+ c.colour = -1;
+ c.name = "";
+ c.tile = "";
env.cgrid(c.pos) = EMPTY_CLOUD;
c.pos.reset();
@@ -271,32 +298,37 @@ void move_cloud( int cloud, const coord_def& newpos )
// Places a cloud with the given stats assuming one doesn't already
// exist at that point.
void check_place_cloud( cloud_type cl_type, const coord_def& p, int lifetime,
- kill_category whose, int spread_rate )
+ kill_category whose, int spread_rate, int colour,
+ std::string name, std::string tile)
{
check_place_cloud(cl_type, p, lifetime, whose,
- cloud_struct::whose_to_killer(whose), spread_rate);
+ cloud_struct::whose_to_killer(whose), spread_rate, colour,
+ name, tile);
}
// Places a cloud with the given stats assuming one doesn't already
// exist at that point.
void check_place_cloud( cloud_type cl_type, const coord_def& p, int lifetime,
- killer_type killer, int spread_rate )
+ killer_type killer, int spread_rate, int colour,
+ std::string name, std::string tile)
{
check_place_cloud(cl_type, p, lifetime,
cloud_struct::killer_to_whose(killer), killer,
- spread_rate);
+ spread_rate, colour, name, tile);
}
// Places a cloud with the given stats assuming one doesn't already
// exist at that point.
void check_place_cloud( cloud_type cl_type, const coord_def& p, int lifetime,
kill_category whose, killer_type killer,
- int spread_rate )
+ int spread_rate, int colour, std::string name,
+ std::string tile)
{
if (!in_bounds(p) || env.cgrid(p) != EMPTY_CLOUD)
return;
- place_cloud( cl_type, p, lifetime, whose, killer, spread_rate );
+ place_cloud( cl_type, p, lifetime, whose, killer, spread_rate, colour,
+ name, tile );
}
int steam_cloud_damage(const cloud_struct &cloud)
@@ -317,27 +349,32 @@ int steam_cloud_damage(int decay)
// make way if there are too many on level. Will overwrite an old
// cloud under some circumstances.
void place_cloud(cloud_type cl_type, const coord_def& ctarget, int cl_range,
- kill_category whose, int _spread_rate)
+ kill_category whose, int _spread_rate, int colour,
+ std::string name, std::string tile)
{
place_cloud(cl_type, ctarget, cl_range, whose,
- cloud_struct::whose_to_killer(whose), _spread_rate);
+ cloud_struct::whose_to_killer(whose), _spread_rate,
+ colour, name, tile);
}
// Places a cloud with the given stats. May delete old clouds to
// make way if there are too many on level. Will overwrite an old
// cloud under some circumstances.
void place_cloud(cloud_type cl_type, const coord_def& ctarget, int cl_range,
- killer_type killer, int _spread_rate)
+ killer_type killer, int _spread_rate, int colour,
+ std::string name, std::string tile)
{
place_cloud(cl_type, ctarget, cl_range,
- cloud_struct::killer_to_whose(killer), killer, _spread_rate);
+ cloud_struct::killer_to_whose(killer), killer, _spread_rate,
+ colour, name, tile);
}
// Places a cloud with the given stats. May delete old clouds to
// make way if there are too many on level. Will overwrite an old
// cloud under some circumstances.
void place_cloud(cloud_type cl_type, const coord_def& ctarget, int cl_range,
- kill_category whose, killer_type killer, int _spread_rate)
+ kill_category whose, killer_type killer, int _spread_rate,
+ int colour, std::string name, std::string tile)
{
if (is_sanctuary(ctarget) && !is_harmless_cloud(cl_type))
return;
@@ -393,7 +430,7 @@ void place_cloud(cloud_type cl_type, const coord_def& ctarget, int cl_range,
if (cl_new != -1)
{
_new_cloud( cl_new, cl_type, ctarget, cl_range * 10,
- whose, killer, spread_rate );
+ whose, killer, spread_rate, colour, name, tile );
}
else
{
@@ -403,7 +440,7 @@ void place_cloud(cloud_type cl_type, const coord_def& ctarget, int cl_range,
if (env.cloud[ci].type == CLOUD_NONE) // ie is empty
{
_new_cloud( ci, cl_type, ctarget, cl_range * 10,
- whose, killer, spread_rate );
+ whose, killer, spread_rate, colour, name, tile );
break;
}
}
@@ -609,6 +646,7 @@ void in_a_cloud()
int cl = env.cgrid(you.pos());
int hurted = 0;
int resist;
+ std::string name = env.cloud[cl].name;
if (you.duration[DUR_CONDENSATION_SHIELD] > 0)
remove_condensation_shield();
@@ -620,7 +658,7 @@ void in_a_cloud()
if (you.duration[DUR_FIRE_SHIELD])
return;
- mpr("You are engulfed in roaring flames!");
+ mprf("You are engulfed in %s!", !name.empty() ? name.c_str() : "roaring flames");
resist = player_res_fire();
@@ -650,7 +688,8 @@ void in_a_cloud()
case CLOUD_STINK:
// If you don't have to breathe, unaffected
- mpr("You are engulfed in noxious fumes!");
+ mprf("You are engulfed in %s!", !name.empty() ? name.c_str() : "noxious fumes");
+
if (player_res_poison())
break;
@@ -674,7 +713,7 @@ void in_a_cloud()
if (you.mutation[MUT_PASSIVE_FREEZE])
break;
- mpr("You are engulfed in freezing vapours!");
+ mprf("You are engulfed in %s!", !name.empty() ? name.c_str() : "freezing vapours");
resist = player_res_cold();
@@ -703,7 +742,8 @@ void in_a_cloud()
case CLOUD_POISON:
// If you don't have to breathe, unaffected
- mpr("You are engulfed in poison gas!");
+ mprf("You are engulfed in %s!", !name.empty() ? name.c_str() : "poison gas");
+
if (!player_res_poison())
{
ouch((random2(10) * you.time_taken) / 10, cl, KILLED_BY_CLOUD,
@@ -717,12 +757,14 @@ void in_a_cloud()
case CLOUD_TLOC_ENERGY:
case CLOUD_PURPLE_SMOKE:
case CLOUD_BLACK_SMOKE:
- mpr("You are engulfed in a cloud of smoke!");
+ mprf("You are engulfed in %s!", !name.empty() ? name.c_str() : "a cloud of smoke");
+
break;
case CLOUD_STEAM:
{
- mpr("You are engulfed in a cloud of scalding steam!");
+ mprf("You are engulfed in %s!", !name.empty() ? name.c_str() : "a cloud of scalding steam");
+
if (player_res_steam() > 0)
{
mpr("It doesn't seem to affect you.");
@@ -746,7 +788,7 @@ void in_a_cloud()
}
case CLOUD_MIASMA:
- mpr("You are engulfed in a dark miasma.");
+ mprf("You are engulfed in %s!", !name.empty() ? name.c_str() : "a dark miasma");
if (you.res_rotting())
return;
@@ -771,11 +813,15 @@ void in_a_cloud()
you.duration[DUR_MISLED] = 0;
}
- mpr("You are standing in the rain.");
+ if (name.empty() || name == "the rain")
+ mpr("You are standing in the rain.");
+ else
+ mprf("You are engulfed in %s.", name.c_str());
+
break;
case CLOUD_MUTAGENIC:
- mpr("You are engulfed in a mutagenic fog!");
+ mprf("You are engulfed in %s!", !name.empty() ? name.c_str() : "a mutagenic fog");
if (coinflip())
{
@@ -870,6 +916,14 @@ cloud_type in_what_cloud()
return (env.cloud[cl].type);
}
+std::string cloud_name(int cloudno)
+{
+ if (!env.cloud[cloudno].name.empty())
+ return (env.cloud[cloudno].name);
+ else
+ return cloud_name(env.cloud[cloudno].type);
+}
+
std::string cloud_name(cloud_type type)
{
switch (type)
@@ -975,6 +1029,9 @@ void cloud_struct::set_killer(killer_type _killer)
int get_cloud_colour(int cloudno)
{
int which_colour = LIGHTGREY;
+ if (env.cloud[cloudno].colour != -1)
+ return (env.cloud[cloudno].colour);
+
switch (env.cloud[cloudno].type)
{
case CLOUD_FIRE:
diff --git a/crawl-ref/source/cloud.h b/crawl-ref/source/cloud.h
index 9cd1ef249c..9bb5ba7f00 100644
--- a/crawl-ref/source/cloud.h
+++ b/crawl-ref/source/cloud.h
@@ -34,19 +34,30 @@ void delete_cloud( int cloud );
void move_cloud( int cloud, const coord_def& newpos );
void check_place_cloud( cloud_type cl_type, const coord_def& p, int lifetime,
- kill_category whose, int spread_rate = -1 );
+ kill_category whose, int spread_rate = -1,
+ int colour = -1, std::string name = "",
+ std::string tile = "");
void check_place_cloud( cloud_type cl_type, const coord_def& p, int lifetime,
- killer_type killer, int spread_rate = -1 );
+ killer_type killer, int spread_rate = -1,
+ int colour = -1, std::string name = "",
+ std::string tile = "");
void check_place_cloud( cloud_type cl_type, const coord_def& p, int lifetime,
kill_category whose, killer_type killer,
- int spread_rate = -1 );
+ int spread_rate = -1,
+ int colour = -1, std::string name = "",
+ std::string tile = "");
void place_cloud( cloud_type cl_type, const coord_def& ctarget,
- int cl_range, kill_category whose, int spread_rate = -1 );
+ int cl_range, kill_category whose, int spread_rate = -1,
+ int colour = -1, std::string name = "",
+ std::string tile = "");
void place_cloud( cloud_type cl_type, const coord_def& ctarget,
- int cl_range, killer_type killer, int spread_rate = -1 );
+ int cl_range, killer_type killer, int spread_rate = -1,
+ int colour = -1, std::string name = "",
+ std::string tile = "");
void place_cloud( cloud_type cl_type, const coord_def& ctarget,
int cl_range, kill_category whose, killer_type killer,
- int spread_rate = -1 );
+ int spread_rate = -1, int colour = -1, std::string name = "",
+ std::string tile = "");
void manage_clouds(void);
@@ -61,6 +72,7 @@ int resist_fraction(int resist, int bonus_res = 0);
int max_cloud_damage(cloud_type cl_type, int power = -1);
void in_a_cloud(void);
+std::string cloud_name(int cloudno);
std::string cloud_name(cloud_type type);
int get_cloud_colour(int cloudno);
diff --git a/crawl-ref/source/dat/clua/lm_fog.lua b/crawl-ref/source/dat/clua/lm_fog.lua
index 17b80e652e..ace95fec53 100644
--- a/crawl-ref/source/dat/clua/lm_fog.lua
+++ b/crawl-ref/source/dat/clua/lm_fog.lua
@@ -52,6 +52,10 @@
-- start_clouds: The number of clouds to lay when the level containing
-- the cloud machine is entered. This is necessary since clouds
-- are cleared when the player leaves a level.
+-- colour: A string value with which to recolour the cloud.
+-- name: A string value with which to rebrand (specifically, rename) the
+-- cloud in question.
+-- tile: A string value with which to retile the cloud.
-- listener: A table with a function field called 'func'. Will be called
-- whenever the countdown is activated, and whenever the fog
-- machine is reset. It will be called with a reference to the table,
@@ -100,6 +104,9 @@ function FogMachine:new(pars)
m.size_max = pars.size_max or pars.size
m.spread_rate = pars.spread_rate or -1
m.start_clouds = pars.start_clouds or 1
+ m.colour = pars.colour or ""
+ m.name = pars.name or ""
+ m.tile = pars.tile or ""
m.size_buildup_amnt = pars.size_buildup_amnt or 0
m.size_buildup_time = pars.size_buildup_time or 1
@@ -125,9 +132,10 @@ function FogMachine:new(pars)
end
function FogMachine:apply_cloud(point, pow_min, pow_max, pow_rolls,
- size, cloud_type, kill_cat, spread)
+ size, cloud_type, kill_cat, spread, colour,
+ name, tile)
dgn.apply_area_cloud(point.x, point.y, pow_min, pow_max, pow_rolls, size,
- cloud_type, kill_cat, spread)
+ cloud_type, kill_cat, spread, colour, name, tile)
end
function FogMachine:do_fog(point)
@@ -165,7 +173,8 @@ function FogMachine:do_fog(point)
self:apply_cloud(p, self.pow_min, self.pow_max, self.pow_rolls,
crawl.random_range(size_min, size_max, 1),
- self.cloud_type, self.kill_cat, spread)
+ self.cloud_type, self.kill_cat, spread, self.colour,
+ self.name, self.tile)
end
function FogMachine:do_trigger(triggerer, marker, ev)
@@ -225,6 +234,9 @@ function FogMachine:write(marker, th)
file.marshall(th, self.spread_buildup_amnt)
file.marshall(th, self.spread_buildup_time)
file.marshall(th, self.buildup_turns)
+ file.marshall(th, self.colour)
+ file.marshall(th, self.name)
+ file.marshall(th, self.tile)
end
function FogMachine:read(marker, th)
@@ -245,6 +257,9 @@ function FogMachine:read(marker, th)
self.spread_buildup_amnt = file.unmarshall_number(th)
self.spread_buildup_time = file.unmarshall_number(th)
self.buildup_turns = file.unmarshall_number(th)
+ self.colour = file.unmarshall_string(th)
+ self.name = file.unmarshall_string(th)
+ self.tile = file.unmarshall_string(th)
setmetatable(self, FogMachine)
diff --git a/crawl-ref/source/dat/ossuary.des b/crawl-ref/source/dat/ossuary.des
index f0e5e18580..89d9465766 100644
--- a/crawl-ref/source/dat/ossuary.des
+++ b/crawl-ref/source/dat/ossuary.des
@@ -476,11 +476,21 @@ TAGS: ossuary no_item_gen no_monster_gen
ITEM: any scroll / any potion
MONS: kobold skeleton / goblin skeleton / gnoll skeleton / \
orc skeleton
+MONS: mummy
# Loot: 10-19
+# Some random content.
+SHUFFLE: Bb/Zz, Dd/Ww, Ee/Vv
+SUBST: Z=c, z=c, W=c, w=c, V=c, v=c
+SUBST: B=X, D=X, E=X
+NSUBST: b = 1:= / c
+NSUBST: d = 1:= / c
+NSUBST: e = 1:= / c
+SUBST: X = x2
# Guaranteed 10 items and 10 mummies, two in hidden rooms.
# 50/50 chance of loot for each of the eleven rats in the rat room.
KITEM: x = any scroll / any potion
KMONS: x = mummy
+NSUBST: ' = 10:^ / *:.
KFEAT: ^ = dart trap / arrow trap
KITEM: y = any scroll w:5 / any potion w:5 / nothing w:10
KMONS: y = rat skeleton
@@ -489,23 +499,23 @@ KMONS: y = rat skeleton
MAP
ccc
cccxccccc
- ccc....+.^c cccccc
- cc.1.ccccc.c cc.+^.cc
- cc..ccc cc+cc cc..cc..cc
- cc.^cc cc...ccccc..cccc.1ccc
-ccc cc+cc c+.x.+...1.cc cc...cc
-cAccc...cc cc...cccxccc ccc.cc
-c..+.^1.+c cc+cc ccc ccc cc+cc
-c<ccc...cc cc..cc cccccxccc...c
-ccc cc+cc cc^1=cc cc..+.^..+.x.+
- c.cc cc..cc.cc c.1ccccccc...c
- c^cc cc..cccc.ccc.cc cc+cc
- c..cccc+cc cc.cc+cc ccc
- cc1.cc...cccccc=yyyccccc
- cc.+..x..+...+yyyyy+.^cc
- cccc...cccxcccyyyccc..cc
- cc=cc ccc cc+cc cc1.ccccc
- cxc ccc cc...=xc
+ ccc''''+''c cccccc
+ cc'''ccccc'c cc'+.1cc
+ cc1'ccc cc+cc cc''cc''cc
+ cc..cc cc...ccccc''cccc''ccc
+ccc cc+cc c+.x.+.1'''cc cc'''cc
+cAccc'''cc ccb...cccxccc cecc'cc
+c..+..1'+c cBcc+cc ccc cceEec+cc
+c<ccc'''cc ccb''cc cccccxccc...ccc
+ccc cc+cc cc''=cccccc''+''''+.x.+Xc
+ c.cc cc1'cc'cdDd.1ccccccc...ccc
+ c1cc cc..cccc'cdd.cc cc+cc
+ c''cccc+cc cc'cc+cc cXc
+ cc''cc...cccccc=yyyccccc ccc
+ cc'+..x..+'''+yyyyy+.1cc
+ cccc...cccxcccyyyccc''cc
+ cc=cc ccc cc+cc cc''ccccc
+ cxc ccc cc'''+Xc
ccc ccccccc
ENDMAP
diff --git a/crawl-ref/source/dat/shoals.des b/crawl-ref/source/dat/shoals.des
index 4983347ecd..2b52eb6ade 100644
--- a/crawl-ref/source/dat/shoals.des
+++ b/crawl-ref/source/dat/shoals.des
@@ -243,13 +243,13 @@ SHUFFLE: ABCD
SUBST: A:x, B:x, C:x=, D=+
LROCKTILE: wall_vines
MAP
-.xxCxx.
+ xxCxx
xx...xx
x.....x
B..O..D
x.....x
xx...xx
-.xxAxx
+ xxAxx
ENDMAP
################################################################################
@@ -262,11 +262,11 @@ TAGS: allow_dup water_ok shoal no_dump
SHUFFLE: ABCD
SUBST: A:x, B:x, C:x=, D=+
MAP
-.xxCxx.
+ xxCxx
xx...xx
x.....x
B..|..D
x.....x
xx...xx
-.xxAxx
+ xxAxx
ENDMAP
diff --git a/crawl-ref/source/dbg-util.cc b/crawl-ref/source/dbg-util.cc
index 57bf3b1b37..84e0f87a0e 100644
--- a/crawl-ref/source/dbg-util.cc
+++ b/crawl-ref/source/dbg-util.cc
@@ -129,12 +129,15 @@ void debug_dump_levgen()
else
{
const CrawlHashTable &vaults = props[TEMP_VAULTS_KEY].get_table();
- CrawlHashTable::const_iterator i = vaults.begin();
-
- for (; i != vaults.end(); ++i)
+ if (!vaults.empty())
{
- mprf(" %s: %s", i->first.c_str(),
- i->second.get_string().c_str());
+ CrawlHashTable::const_iterator i = vaults.begin();
+
+ for (; i != vaults.end(); ++i)
+ {
+ mprf(" %s: %s", i->first.c_str(),
+ i->second.get_string().c_str());
+ }
}
}
mpr("");
@@ -413,5 +416,3 @@ int debug_cap_stat(int stat)
stat > 127 ? 127
: stat);
}
-
-
diff --git a/crawl-ref/source/delay.cc b/crawl-ref/source/delay.cc
index a3a6ca6d5d..56c166fdec 100644
--- a/crawl-ref/source/delay.cc
+++ b/crawl-ref/source/delay.cc
@@ -1564,7 +1564,7 @@ void armour_wear_effects(const int item_slot)
use_artefact(arm, &show_msgs, melded);
}
- if (item_cursed(arm) && !melded)
+ if (arm.cursed() && !melded)
{
mpr("Oops, that feels deathly cold.");
learned_something_new(TUT_YOU_CURSED);
diff --git a/crawl-ref/source/dgn-shoals.cc b/crawl-ref/source/dgn-shoals.cc
new file mode 100644
index 0000000000..da0070239e
--- /dev/null
+++ b/crawl-ref/source/dgn-shoals.cc
@@ -0,0 +1,692 @@
+#include "AppHdr.h"
+
+#include "branch.h"
+#include "coord.h"
+#include "coordit.h"
+#include "dungeon.h"
+#include "dgn-shoals.h"
+#include "env.h"
+#include "items.h"
+#include "maps.h"
+#include "mon-place.h"
+#include "mon-util.h"
+#include "random.h"
+#include "terrain.h"
+
+#include <algorithm>
+#include <vector>
+#include <cmath>
+
+const char *ENVP_SHOALS_TIDE_KEY = "shoals-tide-height";
+const char *ENVP_SHOALS_TIDE_VEL = "shoals-tide-velocity";
+
+inline short &shoals_heights(const coord_def &c)
+{
+ return (*env.heightmap)(c);
+}
+
+static std::vector<coord_def> _shoals_islands;
+
+const int ISLAND_COLLIDE_DIST2 = 5 * 5;
+const int N_PERTURB_ISLAND_CENTER = 50;
+const int ISLAND_CENTER_RADIUS_LOW = 3;
+const int ISLAND_CENTER_RADIUS_HIGH = 10;
+
+const int N_PERTURB_OFFSET_LOW = 25;
+const int N_PERTURB_OFFSET_HIGH = 45;
+const int PERTURB_OFFSET_RADIUS_LOW = 2;
+const int PERTURB_OFFSET_RADIUS_HIGH = 7;
+
+const int _shoals_margin = 6;
+
+enum shoals_height_thresholds
+{
+ SHT_UNDEFINED = -10000,
+ SHT_STONE = 230,
+ SHT_ROCK = 170,
+ SHT_FLOOR = 0,
+ SHT_SHALLOW_WATER = -14
+};
+
+enum tide_direction
+{
+ TIDE_RISING,
+ TIDE_FALLING
+};
+
+static tide_direction _shoals_tide_direction;
+
+static double _to_radians(int degrees)
+{
+ return degrees * M_PI / 180;
+}
+
+static dungeon_feature_type _shoals_feature_by_height(int height)
+{
+ return height >= SHT_STONE ? DNGN_STONE_WALL :
+ height >= SHT_ROCK? DNGN_ROCK_WALL :
+ height >= SHT_FLOOR? DNGN_FLOOR :
+ height >= SHT_SHALLOW_WATER? DNGN_SHALLOW_WATER
+ : DNGN_DEEP_WATER;
+}
+
+static dungeon_feature_type _shoals_feature_at(const coord_def &c)
+{
+ const int height = shoals_heights(c);
+ return _shoals_feature_by_height(height);
+}
+
+static void _shoals_init_heights()
+{
+ env.heightmap.reset(new grid_heightmap);
+ for (rectangle_iterator ri(0); ri; ++ri)
+ shoals_heights(*ri) = SHT_SHALLOW_WATER - 3;
+}
+
+static double _angle_fuzz()
+{
+ double fuzz = _to_radians(random2(15));
+ return coinflip()? fuzz : -fuzz;
+}
+
+static coord_def _random_point_from(const coord_def &c, int radius,
+ int directed_angle = -1)
+{
+ const double directed_radians(
+ directed_angle == -1? 0.0 : _to_radians(directed_angle));
+ int attempts = 70;
+ while (attempts-- > 0)
+ {
+ const double angle =
+ directed_angle == -1? _to_radians(random2(360))
+ : ((coinflip()? directed_radians : -directed_radians)
+ + _angle_fuzz());
+ coord_def res = c + coord_def(radius * cos(angle),
+ radius * sin(angle));
+ if (res.x >= _shoals_margin && res.x < GXM - _shoals_margin
+ && res.y >= _shoals_margin && res.y < GYM - _shoals_margin)
+ {
+ return res;
+ }
+ }
+ return coord_def();
+}
+
+static coord_def _random_point(int offset = 0)
+{
+ return coord_def(random_range(offset, GXM - offset - 1),
+ random_range(offset, GYM - offset - 1));
+}
+
+static void _shoals_island_center(const coord_def &c, int n_perturb, int radius,
+ int bounce_low, int bounce_high)
+{
+ for (int i = 0; i < n_perturb; ++i) {
+ coord_def p = _random_point_from(c, random2(1 + radius));
+ if (!p.origin())
+ shoals_heights(p) += random_range(bounce_low, bounce_high);
+ }
+}
+
+static coord_def _shoals_pick_island_spot()
+{
+ coord_def c;
+ for (int i = 0; i < 15; ++i)
+ {
+ c = _random_point(_shoals_margin * 2);
+
+ bool collides = false;
+ for (int j = 0, size = _shoals_islands.size(); j < size; ++j)
+ {
+ const coord_def island = _shoals_islands[j];
+ const coord_def dist = island - c;
+ if (dist.abs() < ISLAND_COLLIDE_DIST2)
+ {
+ collides = true;
+ break;
+ }
+ }
+ if (!collides)
+ break;
+ }
+ _shoals_islands.push_back(c);
+ return c;
+}
+
+static void _shoals_build_island()
+{
+ coord_def c = _shoals_pick_island_spot();
+ _shoals_island_center(c, N_PERTURB_ISLAND_CENTER,
+ random_range(ISLAND_CENTER_RADIUS_LOW,
+ ISLAND_CENTER_RADIUS_HIGH),
+ 40, 60);
+ const int additional_heights = random2(4);
+ for (int i = 0; i < additional_heights; ++i) {
+ const int addition_offset = random_range(2, 10);
+
+ coord_def offsetC = _random_point_from(c, addition_offset);
+ if (!offsetC.origin())
+ _shoals_island_center(offsetC, random_range(N_PERTURB_OFFSET_LOW,
+ N_PERTURB_OFFSET_HIGH),
+ random_range(PERTURB_OFFSET_RADIUS_LOW,
+ PERTURB_OFFSET_RADIUS_HIGH),
+ 25, 35);
+ }
+}
+
+static void _shoals_init_islands(int depth)
+{
+ const int nislands = 20 - depth * 2;
+ for (int i = 0; i < nislands; ++i)
+ _shoals_build_island();
+}
+
+// Cliffs are usually constructed in shallow water adjacent to deep
+// water (for effect).
+static void _shoals_build_cliff()
+{
+ coord_def cliffc = _random_point(_shoals_margin * 2);
+ if (in_bounds(cliffc))
+ {
+ const int length = random_range(6, 15);
+ double angle = _to_radians(random2(360));
+ for (int i = 0; i < length; i += 3)
+ {
+ int distance = i - length / 2;
+ coord_def place = cliffc + coord_def(distance * cos(angle),
+ distance * sin(angle));
+ coord_def fuzz = coord_def(random_range(-2, 2),
+ random_range(-2, 2));
+ place += fuzz;
+ _shoals_island_center(place, random_range(40, 60), 3,
+ 100, 130);
+ }
+ }
+}
+
+static void _shoals_cliffs()
+{
+ const int ncliffs = random_range(0, 6, 2);
+ for (int i = 0; i < ncliffs; ++i)
+ _shoals_build_cliff();
+}
+
+static void _shoals_smooth_at(const coord_def &c, int radius,
+ int max_height = SHT_UNDEFINED)
+{
+ const int height = shoals_heights(c);
+ if (max_height != SHT_UNDEFINED && height > max_height)
+ return;
+
+ int max_delta = radius * radius * 2 + 2;
+ int divisor = 0;
+ int total = 0;
+ for (int y = c.y - radius; y <= c.y + radius; ++y) {
+ for (int x = c.x - radius; x <= c.x + radius; ++x) {
+ const coord_def p(x, y);
+ if (!in_bounds(p))
+ continue;
+ const int nheight = shoals_heights(p);
+ if (max_height != SHT_UNDEFINED && nheight > max_height)
+ continue;
+ const coord_def off = c - p;
+ int weight = max_delta - off.abs();
+ divisor += weight;
+ total += nheight * weight;
+ }
+ }
+ shoals_heights(c) = total / divisor;
+}
+
+static void _shoals_smooth()
+{
+ for (rectangle_iterator ri(0); ri; ++ri)
+ _shoals_smooth_at(*ri, 1);
+}
+
+static void _shoals_smooth_water()
+{
+ for (rectangle_iterator ri(0); ri; ++ri)
+ _shoals_smooth_at(*ri, 1, SHT_SHALLOW_WATER - 1);
+}
+
+static void _shoals_apply_level()
+{
+ for (rectangle_iterator ri(1); ri; ++ri)
+ grd(*ri) = _shoals_feature_at(*ri);
+}
+
+static bool _has_adjacent_feat(coord_def c, dungeon_feature_type feat)
+{
+ for (adjacent_iterator ai(c); ai; ++ai)
+ if (grd(*ai) == feat)
+ return true;
+ return false;
+}
+
+// Returns all points in deep water with an adjacent square in shallow water.
+static std::vector<coord_def> _shoals_water_depth_change_points()
+{
+ std::vector<coord_def> points;
+ for (rectangle_iterator ri(1); ri; ++ri)
+ {
+ coord_def c(*ri);
+ if (grd(c) == DNGN_DEEP_WATER
+ && _has_adjacent_feat(c, DNGN_SHALLOW_WATER))
+ points.push_back(c);
+ }
+ return points;
+}
+
+static inline void _shoals_deepen_water_at(coord_def p, int distance)
+{
+ shoals_heights(p) -= distance * 7;
+}
+
+static void _shoals_deepen_water()
+{
+ std::vector<coord_def> pages[2];
+ int current_page = 0;
+ pages[current_page] = _shoals_water_depth_change_points();
+ FixedArray<bool, GXM, GYM> seen_points(false);
+
+ for (int i = 0, size = pages[current_page].size(); i < size; ++i)
+ seen_points(pages[current_page][i]) = true;
+
+ int distance = 0;
+ while (!pages[current_page].empty())
+ {
+ const int next_page = !current_page;
+ std::vector<coord_def> &cpage(pages[current_page]);
+ std::vector<coord_def> &npage(pages[next_page]);
+ for (int i = 0, size = cpage.size(); i < size; ++i)
+ {
+ coord_def c(cpage[i]);
+ if (distance)
+ _shoals_deepen_water_at(c, distance);
+
+ for (adjacent_iterator ai(c); ai; ++ai)
+ {
+ coord_def adj(*ai);
+ if (!seen_points(adj) && grd(adj) == DNGN_DEEP_WATER)
+ {
+ npage.push_back(adj);
+ seen_points(adj) = true;
+ }
+ }
+ }
+ cpage.clear();
+ current_page = next_page;
+ distance++;
+ }
+}
+
+static coord_def _pick_shoals_island()
+{
+ const int lucky_island = random2(_shoals_islands.size());
+ const coord_def c = _shoals_islands[lucky_island];
+ _shoals_islands.erase(_shoals_islands.begin() + lucky_island);
+ return c;
+}
+
+struct point_sort_distance_from
+{
+ coord_def bad_place;
+ point_sort_distance_from(coord_def c) : bad_place(c) { }
+ bool operator () (coord_def a, coord_def b) const
+ {
+ const int dista = (a - bad_place).abs(), distb = (b - bad_place).abs();
+ return dista >= distb;
+ }
+};
+
+static coord_def _pick_shoals_island_distant_from(coord_def bad_place)
+{
+ ASSERT(!_shoals_islands.empty());
+
+ std::sort(_shoals_islands.begin(), _shoals_islands.end(),
+ point_sort_distance_from(bad_place));
+ const int top_picks = std::min(4, int(_shoals_islands.size()));
+ const int choice = random2(top_picks);
+ coord_def chosen = _shoals_islands[choice];
+ _shoals_islands.erase(_shoals_islands.begin() + choice);
+ return chosen;
+}
+
+static void _shoals_furniture(int margin)
+{
+ if (at_branch_bottom())
+ {
+ const coord_def c = _pick_shoals_island();
+ // Put all the stairs on one island.
+ grd(c) = DNGN_STONE_STAIRS_UP_I;
+ grd(c + coord_def(1, 0)) = DNGN_STONE_STAIRS_UP_II;
+ grd(c - coord_def(1, 0)) = DNGN_STONE_STAIRS_UP_III;
+
+ const coord_def p = _pick_shoals_island_distant_from(c);
+ // Place the rune
+ const map_def *vault = random_map_for_tag("shoal_rune");
+ dgn_place_map(vault, false, true, p);
+
+ const int nhuts = std::min(8, int(_shoals_islands.size()));
+ for (int i = 2; i < nhuts; ++i)
+ {
+ // Place (non-rune) minivaults on the other islands
+ do
+ vault = random_map_for_tag("shoal");
+ while (!vault);
+ dgn_place_map(vault, false, true, _pick_shoals_island());
+ }
+ }
+ else
+ {
+ // Place stairs randomly. No elevators.
+ for (int i = 0; i < 3; ++i)
+ {
+ int x, y;
+ do
+ {
+ x = margin + random2(GXM - 2*margin);
+ y = margin + random2(GYM - 2*margin);
+ }
+ while (grd[x][y] != DNGN_FLOOR);
+
+ grd[x][y]
+ = static_cast<dungeon_feature_type>(DNGN_STONE_STAIRS_DOWN_I + i);
+
+ do
+ {
+ x = margin + random2(GXM - 2*margin);
+ y = margin + random2(GYM - 2*margin);
+ }
+ while (grd[x][y] != DNGN_FLOOR);
+
+ grd[x][y]
+ = static_cast<dungeon_feature_type>(DNGN_STONE_STAIRS_UP_I + i);
+ }
+ }
+}
+
+static void _shoals_deepen_edges()
+{
+ const int edge = 2;
+ // Water of the edge of the screen is too deep to be exposed by tides.
+ for (int y = 1; y < GYM - 2; ++y)
+ {
+ for (int x = 1; x <= edge; ++x)
+ {
+ shoals_heights(coord_def(x, y)) -= 800;
+ shoals_heights(coord_def(GXM - 1 - x, y)) -= 800;
+ }
+ }
+ for (int x = 1; x < GXM - 2; ++x)
+ {
+ for (int y = 1; y <= edge; ++y)
+ {
+ shoals_heights(coord_def(x, y)) -= 800;
+ shoals_heights(coord_def(x, GYM - 1 - y)) -= 800;
+ }
+ }
+}
+
+void prepare_shoals(int level_number)
+{
+ dgn_Build_Method += make_stringf(" shoals+ [%d]", level_number);
+ dgn_Layout_Type = "shoals";
+
+ const int shoals_depth = level_id::current().depth - 1;
+ dgn_replace_area(0, 0, GXM-1, GYM-1, DNGN_ROCK_WALL, DNGN_OPEN_SEA);
+ _shoals_init_heights();
+ _shoals_islands.clear();
+ _shoals_init_islands(shoals_depth);
+ _shoals_cliffs();
+ _shoals_smooth();
+ _shoals_apply_level();
+ _shoals_deepen_water();
+ _shoals_deepen_edges();
+ _shoals_smooth_water();
+ _shoals_furniture(_shoals_margin);
+}
+
+// The raw tide height / TIDE_MULTIPLIER is the actual tide height. The higher
+// the tide multiplier, the slower the tide advances and recedes. A multiplier
+// of X implies that the tide will advance visibly about once in X turns.
+const int TIDE_MULTIPLIER = 30;
+
+const int LOW_TIDE = -18 * TIDE_MULTIPLIER;
+const int HIGH_TIDE = 25 * TIDE_MULTIPLIER;
+const int TIDE_DECEL_MARGIN = 8;
+const int START_TIDE_RISE = 2;
+
+static void _shoals_run_tide(int &tide, int &acc)
+{
+ tide += acc;
+ tide = std::max(std::min(tide, HIGH_TIDE), LOW_TIDE);
+ if ((tide == HIGH_TIDE && acc > 0)
+ || (tide == LOW_TIDE && acc < 0))
+ acc = -acc;
+ bool in_decel_margin =
+ (abs(tide - HIGH_TIDE) < TIDE_DECEL_MARGIN)
+ || (abs(tide - LOW_TIDE) < TIDE_DECEL_MARGIN);
+ if ((abs(acc) == 2) == in_decel_margin)
+ acc = in_decel_margin? acc / 2 : acc * 2;
+}
+
+static coord_def _shoals_escape_place_from(coord_def bad_place,
+ bool monster_free)
+{
+ int best_height = -1000;
+ coord_def chosen;
+ for (adjacent_iterator ai(bad_place); ai; ++ai)
+ {
+ coord_def p(*ai);
+ const dungeon_feature_type feat(grd(p));
+ if (!feat_is_solid(feat) && !feat_destroys_items(feat)
+ && (!monster_free || !actor_at(p)))
+ {
+ if (best_height == -1000 || shoals_heights(p) > best_height)
+ {
+ best_height = shoals_heights(p);
+ chosen = p;
+ }
+ }
+ }
+ return chosen;
+}
+
+static bool _shoals_tide_sweep_items_clear(coord_def c)
+{
+ int link = igrd(c);
+ if (link == NON_ITEM)
+ return true;
+
+ const coord_def target(_shoals_escape_place_from(c, false));
+ if (target.origin())
+ return false;
+
+ move_item_stack_to_grid(c, target);
+ return true;
+}
+
+static bool _shoals_tide_sweep_actors_clear(coord_def c)
+{
+ actor *victim = actor_at(c);
+ if (!victim || victim->airborne() || victim->swimming())
+ return true;
+
+ if (victim->atype() == ACT_MONSTER)
+ {
+ monsters *mvictim = dynamic_cast<monsters *>(victim);
+ // Plants and statues cannot be moved away; the tide cannot
+ // drown them.
+ if (mons_class_is_stationary(mvictim->type))
+ return false;
+
+ // If the monster doesn't need help, move along.
+ if (monster_habitable_grid(mvictim, DNGN_DEEP_WATER))
+ return true;
+ }
+ coord_def evacuation_point(_shoals_escape_place_from(c, true));
+ // The tide moves on even if we cannot evacuate the tile!
+ if (!evacuation_point.origin())
+ victim->move_to_pos(evacuation_point);
+ return true;
+}
+
+// The tide will attempt to push items and non-water-capable monsters to
+// adjacent squares.
+static bool _shoals_tide_sweep_clear(coord_def c)
+{
+ return _shoals_tide_sweep_items_clear(c)
+ && _shoals_tide_sweep_actors_clear(c);
+}
+
+static void _shoals_apply_tide_feature_at(coord_def c,
+ dungeon_feature_type feat)
+{
+ if (feat == DNGN_DEEP_WATER && !_shoals_tide_sweep_clear(c))
+ feat = DNGN_SHALLOW_WATER;
+
+ const dungeon_feature_type current_feat = grd(c);
+ if (feat == current_feat)
+ return;
+
+ dungeon_terrain_changed(c, feat, true, false, true);
+}
+
+static int _shoals_feature_height(dungeon_feature_type feat)
+{
+ switch (feat)
+ {
+ case DNGN_FLOOR:
+ return SHT_FLOOR;
+ case DNGN_SHALLOW_WATER:
+ return SHT_SHALLOW_WATER;
+ case DNGN_DEEP_WATER:
+ return SHT_SHALLOW_WATER - 1;
+ default:
+ return 0;
+ }
+}
+
+// Determines if the
+static tide_direction _shoals_feature_tide_height_change(
+ dungeon_feature_type oldfeat,
+ dungeon_feature_type newfeat)
+{
+ const int height_delta =
+ _shoals_feature_height(newfeat) - _shoals_feature_height(oldfeat);
+ // If the apparent height of the new feature is greater (floor vs water),
+ // the tide is receding.
+ return height_delta < 0? TIDE_RISING : TIDE_FALLING;
+}
+
+static void _shoals_apply_tide_at(coord_def c, int tide)
+{
+ const int effective_height = shoals_heights(c) - tide;
+ dungeon_feature_type newfeat =
+ _shoals_feature_by_height(effective_height);
+ // Make sure we're not sprouting new walls.
+ if (feat_is_wall(newfeat))
+ newfeat = DNGN_FLOOR;
+ const dungeon_feature_type oldfeat = grd(c);
+
+ if (oldfeat == newfeat
+ || (_shoals_feature_tide_height_change(oldfeat, newfeat) !=
+ _shoals_tide_direction))
+ {
+ return;
+ }
+
+ _shoals_apply_tide_feature_at(c, newfeat);
+}
+
+static void _shoals_apply_tide(int tide)
+{
+ std::vector<coord_def> pages[2];
+ int current_page = 0;
+
+ // Start from corners of the map.
+ pages[current_page].push_back(coord_def(1,1));
+ pages[current_page].push_back(coord_def(GXM - 2, 1));
+ pages[current_page].push_back(coord_def(1, GYM - 2));
+ pages[current_page].push_back(coord_def(GXM - 2, GYM - 2));
+
+ FixedArray<bool, GXM, GYM> seen_points(false);
+
+ while (!pages[current_page].empty())
+ {
+ int next_page = !current_page;
+ std::vector<coord_def> &cpage(pages[current_page]);
+ std::vector<coord_def> &npage(pages[next_page]);
+
+ for (int i = 0, size = cpage.size(); i < size; ++i)
+ {
+ coord_def c(cpage[i]);
+ const bool was_wet(feat_is_water(grd(c)));
+ seen_points(c) = true;
+ _shoals_apply_tide_at(c, tide);
+
+ // Only wet squares can propagate the tide onwards.
+ if (was_wet)
+ {
+ for (adjacent_iterator ai(c); ai; ++ai)
+ {
+ coord_def adj(*ai);
+ if (!in_bounds(adj))
+ continue;
+ if (!seen_points(adj))
+ {
+ const dungeon_feature_type feat = grd(adj);
+ if (feat_is_water(feat) || feat == DNGN_FLOOR)
+ {
+ npage.push_back(adj);
+ seen_points(adj) = true;
+ }
+ }
+ }
+ }
+ }
+
+ cpage.clear();
+ current_page = next_page;
+ }
+}
+
+static void _shoals_init_tide()
+{
+ if (!env.properties.exists(ENVP_SHOALS_TIDE_KEY))
+ {
+ env.properties[ENVP_SHOALS_TIDE_KEY] = short(0);
+ env.properties[ENVP_SHOALS_TIDE_VEL] = short(2);
+ }
+}
+
+void shoals_apply_tides(int turns_elapsed)
+{
+ if (!player_in_branch(BRANCH_SHOALS) || !turns_elapsed
+ || !env.heightmap.get())
+ {
+ return;
+ }
+
+ const int TIDE_UNIT = HIGH_TIDE - LOW_TIDE;
+ // If we've been gone a long time, eliminate some unnecessary math.
+ if (turns_elapsed > TIDE_UNIT * 2)
+ turns_elapsed = turns_elapsed % TIDE_UNIT + TIDE_UNIT;
+
+ _shoals_init_tide();
+ int tide = env.properties[ENVP_SHOALS_TIDE_KEY].get_short();
+ int acc = env.properties[ENVP_SHOALS_TIDE_VEL].get_short();
+ const int old_tide = tide;
+ while (turns_elapsed-- > 0)
+ _shoals_run_tide(tide, acc);
+ env.properties[ENVP_SHOALS_TIDE_KEY] = short(tide);
+ env.properties[ENVP_SHOALS_TIDE_VEL] = short(acc);
+ if (old_tide / TIDE_MULTIPLIER != tide / TIDE_MULTIPLIER)
+ {
+ _shoals_tide_direction =
+ tide > old_tide ? TIDE_RISING : TIDE_FALLING;
+ _shoals_apply_tide(tide / TIDE_MULTIPLIER);
+ }
+}
diff --git a/crawl-ref/source/dgn-shoals.h b/crawl-ref/source/dgn-shoals.h
new file mode 100644
index 0000000000..aae09ff653
--- /dev/null
+++ b/crawl-ref/source/dgn-shoals.h
@@ -0,0 +1,7 @@
+#ifndef DGN_SHOALS_H
+#define DGN_SHOALS_H
+
+void prepare_shoals(int level_number);
+void shoals_apply_tides(int turns_elapsed);
+
+#endif
diff --git a/crawl-ref/source/directn.cc b/crawl-ref/source/directn.cc
index 518d21b23c..3b0a1262b3 100644
--- a/crawl-ref/source/directn.cc
+++ b/crawl-ref/source/directn.cc
@@ -3418,10 +3418,9 @@ static void _describe_cell(const coord_def& where, bool in_range)
if (env.cgrid(where) != EMPTY_CLOUD)
{
const int cloud_inspected = env.cgrid(where);
- const cloud_type ctype = (cloud_type) env.cloud[cloud_inspected].type;
mprf(MSGCH_EXAMINE, "There is a cloud of %s here.",
- cloud_name(ctype).c_str());
+ cloud_name(cloud_inspected).c_str());
cloud_described = true;
}
@@ -3468,14 +3467,19 @@ static void _describe_cell(const coord_def& where, bool in_range)
marker = " (" + desc + ")";
}
const std::string traveldest = _stair_destination_description(where);
+ std::string height_desc;
+ if (env.heightmap.get())
+ height_desc = make_stringf(" (height: %d)", (*env.heightmap)(where));
const dungeon_feature_type feat = grd(where);
- mprf(MSGCH_DIAGNOSTICS, "(%d,%d): %s - %s (%d/%s)%s%s", where.x, where.y,
+ mprf(MSGCH_DIAGNOSTICS, "(%d,%d): %s - %s (%d/%s)%s%s%s",
+ where.x, where.y,
stringize_glyph(get_screen_glyph(where)).c_str(),
feature_desc.c_str(),
feat,
dungeon_feature_name(feat),
marker.c_str(),
- traveldest.c_str());
+ traveldest.c_str(),
+ height_desc.c_str());
#else
if (Tutorial.tutorial_left && tutorial_pos_interesting(where.x, where.y))
{
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index bef185979e..89e643a68b 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -23,6 +23,7 @@
#include "coord.h"
#include "coordit.h"
#include "defines.h"
+#include "dgn-shoals.h"
#include "effects.h"
#include "env.h"
#include "enum.h"
@@ -112,18 +113,6 @@ static bool _make_box(int room_x1, int room_y1, int room_x2, int room_y2,
dungeon_feature_type floor=DNGN_UNSEEN,
dungeon_feature_type wall=DNGN_UNSEEN,
dungeon_feature_type avoid=DNGN_UNSEEN);
-static void _replace_area(const coord_def& p1, const coord_def& p2,
- dungeon_feature_type replace,
- dungeon_feature_type feature,
- unsigned mmask = 0, bool needs_update = false);
-static void _replace_area(int sx, int sy, int ex, int ey,
- dungeon_feature_type replace,
- dungeon_feature_type feature,
- unsigned mmask = 0, bool needs_update = false)
-{
- _replace_area( coord_def(sx, sy), coord_def(ex, ey),
- replace, feature, mmask, needs_update );
-}
static builder_rc_type _builder_by_type(int level_number, char level_type);
static builder_rc_type _builder_by_branch(int level_number);
@@ -145,7 +134,6 @@ static int _place_uniques(int level_number, char level_type);
static void _place_traps( int level_number );
static void _place_fog_machines( int level_number );
static void _prepare_swamp();
-static void _prepare_shoals( int level_number );
static void _prepare_water( int level_number );
static void _check_doors();
static void _hide_doors();
@@ -835,7 +823,17 @@ void dgn_register_place(const vault_placement &place, bool register_vault)
dgn_register_vault(place.map);
if (!place.map.has_tag("layout"))
- _mask_vault(place, MMT_VAULT | MMT_NO_DOOR);
+ {
+ if (place.map.orient == MAP_ENCOMPASS)
+ {
+ for (rectangle_iterator ri(0); ri; ++ri)
+ dgn_Map_Mask(*ri) |= MMT_VAULT | MMT_NO_DOOR;
+ }
+ else
+ {
+ _mask_vault(place, MMT_VAULT | MMT_NO_DOOR);
+ }
+ }
if (place.map.has_tag("no_monster_gen"))
_mask_vault(place, MMT_NO_MONS);
@@ -987,6 +985,7 @@ void dgn_reset_level()
// Forget level properties.
env.properties.clear();
+ env.heightmap.reset(NULL);
// Set up containers for storing some level generation info.
env.properties[LEVEL_VAULTS_KEY].new_table();
@@ -1104,8 +1103,7 @@ static void _build_layout_skeleton(int level_number, int level_type,
if (!dgn_level_vetoed && skip_build == BUILD_CONTINUE)
{
- if (!player_in_branch(BRANCH_SHOALS))
- skip_build = _builder_basic(level_number);
+ skip_build = _builder_basic(level_number);
if (!dgn_level_vetoed && skip_build == BUILD_CONTINUE)
_builder_extras(level_number, level_type);
}
@@ -1172,8 +1170,8 @@ static void _fixup_walls()
else if (player_in_branch(BRANCH_CRYPT))
vault_wall = DNGN_STONE_WALL;
- _replace_area(0, 0, GXM-1, GYM-1, DNGN_ROCK_WALL, vault_wall,
- MMT_NO_WALL);
+ dgn_replace_area(0, 0, GXM-1, GYM-1, DNGN_ROCK_WALL, vault_wall,
+ MMT_NO_WALL);
}
}
@@ -1798,8 +1796,6 @@ static void _build_dungeon_level(int level_number, int level_type)
// Time to make the swamp or shoals {dlb}:
if (player_in_branch(BRANCH_SWAMP))
_prepare_swamp();
- else if (player_in_branch(BRANCH_SHOALS))
- _prepare_shoals(level_number);
if (dgn_level_vetoed)
return;
@@ -1810,9 +1806,10 @@ static void _build_dungeon_level(int level_number, int level_type)
_hide_doors();
// Change pre-rock to rock, and pre-floor to floor.
- _replace_area(0, 0, GXM-1, GYM-1, DNGN_BUILDER_SPECIAL_WALL,
- DNGN_ROCK_WALL);
- _replace_area(0, 0, GXM-1, GYM-1, DNGN_BUILDER_SPECIAL_FLOOR, DNGN_FLOOR);
+ dgn_replace_area(0, 0, GXM-1, GYM-1, DNGN_BUILDER_SPECIAL_WALL,
+ DNGN_ROCK_WALL);
+ dgn_replace_area(0, 0, GXM-1, GYM-1, DNGN_BUILDER_SPECIAL_FLOOR,
+ DNGN_FLOOR);
const unsigned nvaults = Level_Vaults.size();
@@ -2003,19 +2000,6 @@ static void _hide_doors()
}
}
-// Places a randomised ellipse with centre (x, y) and half axes a and b.
-static void _place_ellipse(int x, int y, int a, int b,
- dungeon_feature_type feat, int margin)
-{
- for (int i = std::max(x-a, margin); i < std::min(x+a, GXM-margin); ++i)
- for (int j = std::max(y-b, margin); j < std::min(y+b, GYM-margin); ++j)
- if ( (x-i)*(x-i)*b*b + (y-j)*(y-j)*a*a
- <= a*a*b*b/2 + roll_dice(2, a*a*b*b)/4 + random2(3) )
- {
- grd[i][j] = feat;
- }
-}
-
int count_feature_in_box(int x0, int y0, int x1, int y1,
dungeon_feature_type feat)
{
@@ -2042,18 +2026,6 @@ int count_neighbours(int x, int y, dungeon_feature_type feat)
return count_feature_in_box(x-1, y-1, x+2, y+2, feat);
}
-static void _replace_in_grid(int x1, int y1, int x2, int y2,
- dungeon_feature_type oldfeat,
- dungeon_feature_type newfeat)
-{
- for (int x = x1; x < x2; ++x)
- for (int y = y1; y < y2; ++y)
- {
- if (grd[x][y] == oldfeat)
- grd[x][y] = newfeat;
- }
-}
-
static void _connected_flood(int margin, int i, int j, bool taken[GXM][GYM])
{
if (i < margin || i >= GXM - margin || j < margin || j >= GYM - margin
@@ -2068,301 +2040,6 @@ static void _connected_flood(int margin, int i, int j, bool taken[GXM][GYM])
_connected_flood(margin, i + idelta, j + jdelta, taken);
}
-// Yes, yes, this can probably use travel to avoid duplicating code.
-static int _count_connected(int margin)
-{
- bool taken[GXM][GYM];
-
- for (int i = margin; i < GXM - margin; ++i)
- for (int j = margin; j < GYM - margin; ++j)
- taken[i][j] = feat_is_water(grd[i][j]);
-
- int count = 0;
-
- for (int i = margin; i < GXM - margin; ++i)
- for (int j = margin; j < GYM - margin; ++j)
- if (!taken[i][j])
- {
- ++count;
- _connected_flood(margin,i,j,taken);
- }
-
- return count;
-}
-
-static void _place_base_islands(int margin, int num_islands, int estradius,
- coord_def centres[10])
-{
- for (int i = 0; i < num_islands; ++i)
- {
- // smaller axis
- int b = (2 * estradius + roll_dice(3, estradius)) / 4;
- b = std::max(b, 4);
- b = std::min(b, (GYM - 2*margin - 2) / 2);
-
- int a = b + roll_dice(2, b)/3; // more wide than tall
- a = std::min(a, (GXM - 2*margin - 2) / 2);
-
- int island_distance = estradius*estradius * (2 + num_islands/3);
-
- // Make sure an island fits into the map without getting
- // cut off on the edges, i.e. leave margin + radius space
- // at each side.
- const int rnd_x_size = GXM - 2*(margin+a) - 1;
- const int rnd_y_size = GYM - 2*(margin+b) - 1;
- ASSERT(rnd_x_size > 0);
- ASSERT(rnd_y_size > 0);
-
- bool centre_ok = false;
- int tries = 1000;
- do
- {
- centre_ok = true;
-
- centres[i].x = margin + a + random2(rnd_x_size);
- centres[i].y = margin + b + random2(rnd_y_size);
-
- for (int j = 0; j < i; ++j)
- {
- // Calculate the distance from the centers of
- // previous islands.
- if (distance(centres[i].x, centres[i].y,
- centres[j].x, centres[j].y) < island_distance)
- {
- centre_ok = false;
- break;
- }
- }
- if (island_distance && !one_chance_in(num_islands))
- --island_distance;
- }
- while (!centre_ok && --tries > 0);
-
-#ifdef DEBUG_DIAGNOSTICS
- if (tries == 0)
- mprf(MSGCH_ERROR, "Failure to place island #%d!", i);
-#endif
- // Eventually, place an ellipse around the new coordinate.
- _place_ellipse( centres[i].x, centres[i].y, a, b, DNGN_FLOOR, margin);
- }
-}
-
-typedef std::pair<coord_def, dungeon_feature_type> located_feature;
-typedef std::list<located_feature> located_feature_list;
-
-bool _is_critical_feature(dungeon_feature_type feat)
-{
- return (feat == DNGN_ENTER_PORTAL_VAULT
- || feat == DNGN_ENTER_LABYRINTH
- || feat == DNGN_ENTER_SHOP);
-}
-
-static located_feature_list _save_critical_features()
-{
- located_feature_list result;
-
- for (rectangle_iterator ri(1); ri; ++ri)
- if (_is_critical_feature(grd(*ri)))
- result.push_back(located_feature(*ri, grd(*ri)));
-
- return result;
-}
-
-static void _restore_critical_features(const located_feature_list& lfl)
-{
- for (located_feature_list::const_iterator ci = lfl.begin();
- ci != lfl.end(); ++ci)
- {
- grd(ci->first) = ci->second;
- }
-}
-
-static void _prepare_shoals(int level_number)
-{
- // Don't destroy portals, etc.
- const located_feature_list lfl = _save_critical_features();
-
- dgn_Build_Method += make_stringf(" shoals [%d]", level_number);
- dgn_Layout_Type = "shoals";
-
- // dpeg's algorithm.
- // We could have just used spotty_level() and changed rock to
- // water, but this is much cooler. Right?
- const int margin = 6;
-
- int num_islands = player_branch_depth() + 1;
-
- if (at_branch_bottom())
- num_islands += random2(3);
-
- const int estradius = 50 / num_islands - (num_islands == 2 ? 5 : 0);
-
- int num_tries = 0;
- coord_def centres[10];
- do
- {
- for (int x = margin; x < GXM-margin; ++x)
- for (int y = margin; y < GYM-margin; ++y)
- grd[x][y] = DNGN_DEEP_WATER;
-
- _place_base_islands(margin, num_islands, estradius, centres);
- }
- while (++num_tries < 100 && _count_connected(margin) != num_islands);
-
-#ifdef DEBUG_DIAGNOSTICS
- mprf(MSGCH_DIAGNOSTICS, "Num tries: %d Connected components: %d",
- num_tries, _count_connected(margin));
-#endif
-
- // Adding shallow water at deep water adjacent to floor.
- // Randomisation: place shallow water if at least 1d(1d3) floor neighbours
- for (int i = margin; i < GXM - margin; ++i)
- for (int j = margin; j < GYM - margin; ++j)
- if (grd[i][j] == DNGN_DEEP_WATER
- && count_neighbours(i, j, DNGN_FLOOR) > random2(random2(3)+1))
- {
- grd[i][j] = DNGN_SHALLOW_WATER;
- }
-
- // Placing sandbanks.
- for (int banks = 0; banks < 8; ++banks)
- {
- int xsize = 3 + random2(3); // random rectangle
- int ysize = 3 + random2(3);
- int xb = margin + 2 + random2(GXM - 2 * margin - xsize - 2);
- int yb = margin + 2 + random2(GYM - 2 * margin - ysize - 2);
-
- bool ok_place = true;
- for (int i = xb; i < xb + xsize; ++i)
- for (int j = yb; j < yb + ysize; ++j)
- {
- if (grd[i][j] != DNGN_DEEP_WATER)
- {
- ok_place = false;
- break;
- }
- }
-
- if (ok_place)
- {
- for (int i = xb; i < xb + xsize; ++i)
- for (int j = yb; j < yb + ysize; ++j)
- {
- if (!one_chance_in(3))
- grd[i][j] = DNGN_SHALLOW_WATER;
- }
- }
- }
-
- // Fractalisation
-
- // LAVA is a placeholder for cells which will become shallow water
- // at the end of the current iteration.
- // WATER_RESERVED is a placeholder for last iteration's generated water.
- _replace_in_grid(margin, margin, GXM-margin, GYM-margin,
- DNGN_SHALLOW_WATER, DNGN_WATER_RESERVED);
-
- for (int iteration = 0; iteration < 6; ++iteration)
- {
- for (int x = margin; x < GXM - margin; ++x)
- for (int y = margin; y < GYM - margin; ++y)
- if (grd[x][y] == DNGN_DEEP_WATER)
- {
- int badness = count_neighbours(x, y, DNGN_WATER_RESERVED);
- if (random2(badness) >= 2 && coinflip())
- grd[x][y] = DNGN_LAVA;
- }
-
- _replace_in_grid(margin, margin, GXM-margin, GYM-margin,
- DNGN_LAVA, DNGN_WATER_RESERVED);
- }
- _replace_in_grid(margin, margin, GXM-margin, GYM-margin,
- DNGN_WATER_RESERVED, DNGN_SHALLOW_WATER);
-
- // Turn rock walls into deep water and "open sea". This must happen
- // before vaults are placed as those may contain rock as well.
- const int margin2 = margin - 1;
- _replace_in_grid(margin2, margin2, GXM-margin2, GYM-margin2,
- DNGN_ROCK_WALL, DNGN_DEEP_WATER);
-
- _replace_area(0, 0, GXM-1, GYM-1, DNGN_BUILDER_SPECIAL_WALL,
- DNGN_ROCK_WALL);
- _replace_area(0, 0, GXM-1, GYM-1, DNGN_ROCK_WALL, DNGN_OPEN_SEA);
-
- // Put important things back.
- _restore_critical_features(lfl);
-
- if (at_branch_bottom())
- {
- // Find an island to place the stairs up on.
- int j;
- const coord_def d1(1,0), d2(-1,0);
- for (j = 0; j < num_islands; ++j)
- {
- if (!_is_critical_feature(grd(centres[j]))
- && !_is_critical_feature(grd(centres[j] + d1))
- && !_is_critical_feature(grd(centres[j] + d2)))
- {
- break;
- }
- }
- if (j == num_islands)
- {
- // Oh well.
- j = 0;
- mprf(MSGCH_ERROR, "Clobbering critical features: %d %d %d.",
- grd(centres[j]), grd(centres[j] + d1), grd(centres[j] + d2));
- }
- // Put all the stairs on one island.
- grd[centres[j].x ][centres[j].y] = DNGN_STONE_STAIRS_UP_I;
- grd[centres[j].x+1][centres[j].y] = DNGN_STONE_STAIRS_UP_II;
- grd[centres[j].x-1][centres[j].y] = DNGN_STONE_STAIRS_UP_III;
-
- // Place the rune
- const map_def *vault = random_map_for_tag("shoal_rune");
- _build_secondary_vault(level_number, vault, -1, false, true,
- centres[1]);
-
- for (int i = 2; i < num_islands; ++i)
- {
- // Place (non-rune) minivaults on the other islands
- do
- vault = random_map_for_tag("shoal");
- while (!vault);
-
- _build_secondary_vault(level_number, vault, -1, false, true,
- centres[i]);
- }
- }
- else
- {
- // Place stairs randomly. No elevators.
- for (int i = 0; i < 3; ++i)
- {
- int x, y;
- do
- {
- x = margin + random2(GXM - 2*margin);
- y = margin + random2(GYM - 2*margin);
- }
- while (grd[x][y] != DNGN_FLOOR);
-
- grd[x][y]
- = static_cast<dungeon_feature_type>(DNGN_STONE_STAIRS_DOWN_I + i);
-
- do
- {
- x = margin + random2(GXM - 2*margin);
- y = margin + random2(GYM - 2*margin);
- }
- while (grd[x][y] != DNGN_FLOOR);
-
- grd[x][y]
- = static_cast<dungeon_feature_type>(DNGN_STONE_STAIRS_UP_I + i);
- }
- }
-}
-
static void _prepare_swamp()
{
dgn_Build_Method += " swamp";
@@ -2631,7 +2308,8 @@ static void _portal_vault_level(int level_number)
{
// XXX: This is pretty hackish, I confess.
if (vault->border_fill_type != DNGN_ROCK_WALL)
- _replace_area(0, 0, GXM-1, GYM-1, DNGN_ROCK_WALL, vault->border_fill_type);
+ dgn_replace_area(0, 0, GXM-1, GYM-1, DNGN_ROCK_WALL,
+ vault->border_fill_type);
_ensure_vault_placed( _build_vaults(level_number, vault), true );
}
@@ -2755,6 +2433,9 @@ static builder_rc_type _builder_by_branch(int level_number)
spotty_level(false, iterations, false);
return BUILD_SKIP;
}
+ case BRANCH_SHOALS:
+ prepare_shoals(level_number);
+ return BUILD_SKIP;
default:
break;
@@ -4056,8 +3737,8 @@ static void _build_rooms(const dgn_region_list &excluded,
}
const coord_def end = myroom.end();
- _replace_area(myroom.pos.x, myroom.pos.y, end.x, end.y,
- DNGN_ROCK_WALL, DNGN_FLOOR);
+ dgn_replace_area(myroom.pos.x, myroom.pos.y, end.x, end.y,
+ DNGN_ROCK_WALL, DNGN_FLOOR);
if (which_room > 0)
{
@@ -4421,7 +4102,7 @@ bool dgn_place_map(const map_def *mdef, bool clobber, bool make_no_exits,
}
}
- dungeon_feature_type rune_subst = DNGN_FLOOR;
+ int rune_subst = -1;
if (mdef->has_tag_suffix("_entry"))
rune_subst = _dgn_find_rune_subst_tags(mdef->tags);
did_map = _build_secondary_vault(you.your_level, mdef, rune_subst,
@@ -4852,6 +4533,11 @@ static void _dgn_give_mon_spec_items(mons_spec &mspec,
if (item_made != NON_ITEM && item_made != -1)
{
item_def &item(mitm[item_made]);
+
+ // Mark items on summoned monsters as such.
+ if (mspec.abjuration_duration != 0)
+ item.flags |= ISFLAG_SUMMONED;
+
if (!mon.pickup_item(item, 0, true))
destroy_item(item_made, true);
}
@@ -5374,10 +5060,19 @@ bool seen_replace_feat(dungeon_feature_type old_feat,
return (seen);
}
-static void _replace_area( const coord_def& p1, const coord_def& p2,
- dungeon_feature_type replace,
- dungeon_feature_type feature, unsigned mapmask,
- bool needs_update)
+void dgn_replace_area(int sx, int sy, int ex, int ey,
+ dungeon_feature_type replace,
+ dungeon_feature_type feature,
+ unsigned mmask, bool needs_update)
+{
+ dgn_replace_area( coord_def(sx, sy), coord_def(ex, ey),
+ replace, feature, mmask, needs_update );
+}
+
+void dgn_replace_area( const coord_def& p1, const coord_def& p2,
+ dungeon_feature_type replace,
+ dungeon_feature_type feature, unsigned mapmask,
+ bool needs_update)
{
for (rectangle_iterator ri(p1, p2); ri; ++ri)
{
@@ -6283,7 +5978,7 @@ static void _plan_main(int level_number, int force_plan)
}
if (one_chance_in(20))
- _replace_area(0, 0, GXM-1, GYM-1, DNGN_ROCK_WALL, special_grid);
+ dgn_replace_area(0, 0, GXM-1, GYM-1, DNGN_ROCK_WALL, special_grid);
}
static bool _plan_1(int level_number)
@@ -6364,7 +6059,8 @@ static bool _plan_4(char forbid_x1, char forbid_y1, char forbid_x2,
: DNGN_METAL_WALL); // odds: 3 in 18 {dlb}
}
- _replace_area(10, 10, (GXM - 10), (GYM - 10), DNGN_ROCK_WALL, DNGN_FLOOR);
+ dgn_replace_area(10, 10, (GXM - 10), (GYM - 10), DNGN_ROCK_WALL,
+ DNGN_FLOOR);
// replace_area can also be used to fill in:
for (i = 0; i < number_boxes; i++)
@@ -6410,7 +6106,7 @@ static bool _plan_4(char forbid_x1, char forbid_y1, char forbid_x2,
temp_rand = random2(210);
if (temp_rand > 71) // odds: 138 in 210 {dlb}
- _replace_area(b1x, b1y, b2x, b2y, DNGN_FLOOR, drawing);
+ dgn_replace_area(b1x, b1y, b2x, b2y, DNGN_FLOOR, drawing);
else // odds: 72 in 210 {dlb}
_box_room(b1x, b2x - 1, b1y, b2y - 1, drawing);
}
@@ -7223,12 +6919,12 @@ static void _box_room(int bx1, int bx2, int by1, int by2,
int temp_rand, new_doors, doors_placed;
// Do top & bottom walls.
- _replace_area(bx1, by1, bx2, by1, DNGN_FLOOR, wall_type);
- _replace_area(bx1, by2, bx2, by2, DNGN_FLOOR, wall_type);
+ dgn_replace_area(bx1, by1, bx2, by1, DNGN_FLOOR, wall_type);
+ dgn_replace_area(bx1, by2, bx2, by2, DNGN_FLOOR, wall_type);
// Do left & right walls.
- _replace_area(bx1, by1+1, bx1, by2-1, DNGN_FLOOR, wall_type);
- _replace_area(bx2, by1+1, bx2, by2-1, DNGN_FLOOR, wall_type);
+ dgn_replace_area(bx1, by1+1, bx1, by2-1, DNGN_FLOOR, wall_type);
+ dgn_replace_area(bx2, by1+1, bx2, by2-1, DNGN_FLOOR, wall_type);
// Sometimes we have to place doors, or else we shut in other
// buildings' doors.
@@ -7466,8 +7162,8 @@ static void _big_room(int level_number)
}
// Make the big room.
- _replace_area(sr.tl, sr.br, DNGN_ROCK_WALL, type_floor);
- _replace_area(sr.tl, sr.br, DNGN_CLOSED_DOOR, type_floor);
+ dgn_replace_area(sr.tl, sr.br, DNGN_ROCK_WALL, type_floor);
+ dgn_replace_area(sr.tl, sr.br, DNGN_CLOSED_DOOR, type_floor);
if (type_floor == DNGN_FLOOR)
{
@@ -7565,8 +7261,8 @@ static void _roguey_level(int level_number, spec_room &sr, bool make_stairs)
for (i = 0; i < 25; i++)
{
- _replace_area( rox1[i], roy1[i], rox2[i], roy2[i],
- DNGN_ROCK_WALL, DNGN_FLOOR );
+ dgn_replace_area( rox1[i], roy1[i], rox2[i], roy2[i],
+ DNGN_ROCK_WALL, DNGN_FLOOR );
// Inner room?
if (rox2[i] - rox1[i] > 5 && roy2[i] - roy1[i] > 5
@@ -7665,12 +7361,11 @@ static void _roguey_level(int level_number, spec_room &sr, bool make_stairs)
// Is one of them a special room?
const map_def *sroom = NULL;
-#ifdef DEBUG_SPECIAL_ROOMS
- if ((sroom = random_map_for_tag("special_room", true)) != NULL)
-#else
- if (one_chance_in(10)
- && (sroom = random_map_for_tag("special_room", true)) != NULL)
+ if (
+#ifndef DEBUG_SPECIAL_ROOMS
+ one_chance_in(10) &&
#endif
+ (sroom = random_map_for_tag("special_room", true)) != NULL)
{
int spec_room_done = random2(25);
@@ -7684,36 +7379,36 @@ static void _roguey_level(int level_number, spec_room &sr, bool make_stairs)
// by something else (or put monsters in walls, etc...)
// top
- _replace_area(sr.tl.x-1, sr.tl.y-1, sr.br.x+1,sr.tl.y-1,
- DNGN_ROCK_WALL, DNGN_BUILDER_SPECIAL_WALL);
- _replace_area(sr.tl.x-1, sr.tl.y-1, sr.br.x+1,sr.tl.y-1,
- DNGN_FLOOR, DNGN_BUILDER_SPECIAL_FLOOR);
- _replace_area(sr.tl.x-1, sr.tl.y-1, sr.br.x+1,sr.tl.y-1,
- DNGN_CLOSED_DOOR, DNGN_BUILDER_SPECIAL_FLOOR);
+ dgn_replace_area(sr.tl.x-1, sr.tl.y-1, sr.br.x+1,sr.tl.y-1,
+ DNGN_ROCK_WALL, DNGN_BUILDER_SPECIAL_WALL);
+ dgn_replace_area(sr.tl.x-1, sr.tl.y-1, sr.br.x+1,sr.tl.y-1,
+ DNGN_FLOOR, DNGN_BUILDER_SPECIAL_FLOOR);
+ dgn_replace_area(sr.tl.x-1, sr.tl.y-1, sr.br.x+1,sr.tl.y-1,
+ DNGN_CLOSED_DOOR, DNGN_BUILDER_SPECIAL_FLOOR);
// bottom
- _replace_area(sr.tl.x-1, sr.br.y+1, sr.br.x+1,sr.br.y+1,
- DNGN_ROCK_WALL, DNGN_BUILDER_SPECIAL_WALL);
- _replace_area(sr.tl.x-1, sr.br.y+1, sr.br.x+1,sr.br.y+1,
- DNGN_FLOOR, DNGN_BUILDER_SPECIAL_FLOOR);
- _replace_area(sr.tl.x-1, sr.br.y+1, sr.br.x+1,sr.br.y+1,
- DNGN_CLOSED_DOOR, DNGN_BUILDER_SPECIAL_FLOOR);
+ dgn_replace_area(sr.tl.x-1, sr.br.y+1, sr.br.x+1,sr.br.y+1,
+ DNGN_ROCK_WALL, DNGN_BUILDER_SPECIAL_WALL);
+ dgn_replace_area(sr.tl.x-1, sr.br.y+1, sr.br.x+1,sr.br.y+1,
+ DNGN_FLOOR, DNGN_BUILDER_SPECIAL_FLOOR);
+ dgn_replace_area(sr.tl.x-1, sr.br.y+1, sr.br.x+1,sr.br.y+1,
+ DNGN_CLOSED_DOOR, DNGN_BUILDER_SPECIAL_FLOOR);
// left
- _replace_area(sr.tl.x-1, sr.tl.y-1, sr.tl.x-1, sr.br.y+1,
- DNGN_ROCK_WALL, DNGN_BUILDER_SPECIAL_WALL);
- _replace_area(sr.tl.x-1, sr.tl.y-1, sr.tl.x-1, sr.br.y+1,
- DNGN_FLOOR, DNGN_BUILDER_SPECIAL_FLOOR);
- _replace_area(sr.tl.x-1, sr.tl.y-1, sr.tl.x-1, sr.br.y+1,
- DNGN_CLOSED_DOOR, DNGN_BUILDER_SPECIAL_FLOOR);
+ dgn_replace_area(sr.tl.x-1, sr.tl.y-1, sr.tl.x-1, sr.br.y+1,
+ DNGN_ROCK_WALL, DNGN_BUILDER_SPECIAL_WALL);
+ dgn_replace_area(sr.tl.x-1, sr.tl.y-1, sr.tl.x-1, sr.br.y+1,
+ DNGN_FLOOR, DNGN_BUILDER_SPECIAL_FLOOR);
+ dgn_replace_area(sr.tl.x-1, sr.tl.y-1, sr.tl.x-1, sr.br.y+1,
+ DNGN_CLOSED_DOOR, DNGN_BUILDER_SPECIAL_FLOOR);
// right
- _replace_area(sr.br.x+1, sr.tl.y-1, sr.br.x+1, sr.br.y+1,
- DNGN_ROCK_WALL, DNGN_BUILDER_SPECIAL_WALL);
- _replace_area(sr.br.x+1, sr.tl.y-1, sr.br.x+1, sr.br.y+1,
- DNGN_FLOOR, DNGN_BUILDER_SPECIAL_FLOOR);
- _replace_area(sr.br.x+1, sr.tl.y-1, sr.br.x+1, sr.br.y+1,
- DNGN_CLOSED_DOOR, DNGN_BUILDER_SPECIAL_FLOOR);
+ dgn_replace_area(sr.br.x+1, sr.tl.y-1, sr.br.x+1, sr.br.y+1,
+ DNGN_ROCK_WALL, DNGN_BUILDER_SPECIAL_WALL);
+ dgn_replace_area(sr.br.x+1, sr.tl.y-1, sr.br.x+1, sr.br.y+1,
+ DNGN_FLOOR, DNGN_BUILDER_SPECIAL_FLOOR);
+ dgn_replace_area(sr.br.x+1, sr.tl.y-1, sr.br.x+1, sr.br.y+1,
+ DNGN_CLOSED_DOOR, DNGN_BUILDER_SPECIAL_FLOOR);
}
if (!make_stairs)
diff --git a/crawl-ref/source/dungeon.h b/crawl-ref/source/dungeon.h
index 590a91b897..bc140c3f2e 100644
--- a/crawl-ref/source/dungeon.h
+++ b/crawl-ref/source/dungeon.h
@@ -163,6 +163,7 @@ public:
extern bool Generating_Level;
extern std::string dgn_Layout_Type;
+extern std::string dgn_Build_Method;
extern std::set<std::string> Level_Unique_Maps;
extern std::set<std::string> Level_Unique_Tags;
@@ -187,6 +188,7 @@ void dgn_set_grid_colour_at(const coord_def &c, int colour);
bool dgn_place_map(const map_def *map, bool clobber, bool make_no_exits,
const coord_def &pos = coord_def(-1, -1));
+
void level_clear_vault_memory();
void level_welcome_messages();
@@ -256,6 +258,16 @@ bool octa_room(spec_room &sr, int oblique_max,
int count_feature_in_box(int x0, int y0, int x1, int y1,
dungeon_feature_type feat);
+
+void dgn_replace_area(const coord_def& p1, const coord_def& p2,
+ dungeon_feature_type replace,
+ dungeon_feature_type feature,
+ unsigned mmask = 0, bool needs_update = false);
+void dgn_replace_area(int sx, int sy, int ex, int ey,
+ dungeon_feature_type replace,
+ dungeon_feature_type feature,
+ unsigned mmask = 0, bool needs_update = false);
+
inline int count_feature_in_box( const coord_def& p1, const coord_def& p2,
dungeon_feature_type feat )
{
diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc
index 30687dd58d..bede6d46c2 100644
--- a/crawl-ref/source/effects.cc
+++ b/crawl-ref/source/effects.cc
@@ -27,6 +27,7 @@
#include "coordit.h"
#include "decks.h"
#include "delay.h"
+#include "dgn-shoals.h"
#include "dungeon.h"
#include "directn.h"
#include "dgnevent.h"
@@ -4263,6 +4264,7 @@ void update_level(double elapsedTime)
#endif
update_corpses(elapsedTime);
+ shoals_apply_tides(turns);
if (env.sanctuary_time)
{
diff --git a/crawl-ref/source/env.h b/crawl-ref/source/env.h
index 1f3c02f142..aa78f2ac0f 100644
--- a/crawl-ref/source/env.h
+++ b/crawl-ref/source/env.h
@@ -6,6 +6,7 @@
#include "show.h"
#include "trap_def.h"
+typedef FixedArray<short, GXM, GYM> grid_heightmap;
struct crawl_environment
{
public:
@@ -22,6 +23,8 @@ public:
FixedArray< unsigned short, GXM, GYM > cgrid; // cloud grid
FixedArray< unsigned short, GXM, GYM > grid_colours; // colour overrides
+ std::auto_ptr<grid_heightmap> heightmap;
+
// Player-remembered terrain. TODO: move to class player.
FixedArray< map_cell, GXM, GYM > map_knowledge;
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index e1a8083ef3..5f4f5e7e40 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -257,9 +257,13 @@ struct cloud_struct
unsigned char spread_rate;
kill_category whose;
killer_type killer;
+ int colour;
+ std::string name;
+ std::string tile;
cloud_struct() : pos(), type(CLOUD_NONE), decay(0), spread_rate(0),
- whose(KC_OTHER), killer(KILL_NONE)
+ whose(KC_OTHER), killer(KILL_NONE), colour(-1),
+ name(""), tile("")
{
}
@@ -529,6 +533,12 @@ public:
bool is_valid() const;
+ // Returns true if this item should be preserved as far as possible.
+ bool is_critical() const;
+
+ // Returns true if this item should not normally be enchanted.
+ bool is_mundane() const;
+
private:
std::string name_aux(description_level_type desc,
bool terse, bool ident,
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index 1543ddabb1..b2237a92cb 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -374,7 +374,7 @@ void melee_attack::check_hand_half_bonus_eligible()
&& !can_do_unarmed
&& !shield
&& weapon
- && !item_cursed(*weapon)
+ && !weapon->cursed()
&& hands == HANDS_HALF);
}
@@ -3832,7 +3832,7 @@ int melee_attack::player_to_hit(bool random_factor)
&& !can_do_unarmed
&& !shield
&& weapon
- && !item_cursed( *weapon )
+ && !weapon ->cursed()
&& hands == HANDS_HALF;
int your_to_hit = 15 + (calc_stat_to_hit_base() / 2);
diff --git a/crawl-ref/source/food.cc b/crawl-ref/source/food.cc
index 112f9e1739..bd2db8d728 100644
--- a/crawl-ref/source/food.cc
+++ b/crawl-ref/source/food.cc
@@ -377,7 +377,7 @@ static void _terminate_butchery(bool wpn_switch, bool removed_gloves,
{
// Switch weapon back.
if (wpn_switch && you.equip[EQ_WEAPON] != old_weapon
- && (!you.weapon() || !item_cursed(*you.weapon())))
+ && (!you.weapon() || !you.weapon()->cursed()))
{
start_delay(DELAY_WEAPON_SWAP, 1, old_weapon);
}
@@ -479,7 +479,7 @@ bool butchery(int which_corpse)
&& !player_wearing_slot(EQ_GLOVES);
bool gloved_butcher = (you.has_claws() && player_wearing_slot(EQ_GLOVES)
- && !item_cursed(you.inv[you.equip[EQ_GLOVES]]));
+ && !you.inv[you.equip[EQ_GLOVES]].cursed());
bool can_butcher = (teeth_butcher || barehand_butcher
|| you.weapon() && can_cut_meat(*you.weapon()));
diff --git a/crawl-ref/source/godwrath.cc b/crawl-ref/source/godwrath.cc
index a94b0ec2c8..e3e87198ca 100644
--- a/crawl-ref/source/godwrath.cc
+++ b/crawl-ref/source/godwrath.cc
@@ -1249,7 +1249,8 @@ static void _tso_blasts_cleansing_flame(const char *message)
simple_god_message(" blasts you with cleansing flame!",
GOD_SHINING_ONE);
- cleansing_flame(20 + (you.experience_level * 7) / 3,
+ // damage is 2d(pow), *3/2 for undead and demonspawn
+ cleansing_flame(5 + (you.experience_level * 7) / 12,
CLEANSING_FLAME_TSO, you.pos());
}
}
diff --git a/crawl-ref/source/invent.cc b/crawl-ref/source/invent.cc
index 047a502467..887fbd436c 100644
--- a/crawl-ref/source/invent.cc
+++ b/crawl-ref/source/invent.cc
@@ -109,7 +109,7 @@ const std::string &InvEntry::get_fullname() const
bool InvEntry::is_item_cursed() const
{
- return (item_ident(*item, ISFLAG_KNOW_CURSE) && item_cursed(*item));
+ return (item_ident(*item, ISFLAG_KNOW_CURSE) && item->cursed());
}
bool InvEntry::is_item_glowing() const
diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc
index 38bf295a7a..fd01008e25 100644
--- a/crawl-ref/source/item_use.cc
+++ b/crawl-ref/source/item_use.cc
@@ -112,7 +112,7 @@ bool can_wield(item_def *weapon, bool say_reason,
if (!ignore_temporary_disability
&& you.weapon()
&& you.weapon()->base_type == OBJ_WEAPONS
- && item_cursed(*you.weapon()))
+ && you.weapon()->cursed())
{
SAY(mpr("You can't unwield your weapon to draw a new one!"));
return (false);
@@ -721,7 +721,7 @@ void wield_effects(int item_wield_2, bool showMsgs)
}
}
- if (item_cursed(item))
+ if (item.cursed())
{
mpr("It sticks to your hand!");
int amusement = 16;
@@ -1059,7 +1059,7 @@ bool do_wear_armour(int item, bool quiet)
&& you.equip[EQ_CLOAK] != -1 && !cloak_is_being_removed())
{
if (you.equip[EQ_BODY_ARMOUR] != -1
- && item_cursed(you.inv[you.equip[EQ_BODY_ARMOUR]]))
+ && you.inv[you.equip[EQ_BODY_ARMOUR]].cursed())
{
if (!quiet)
{
@@ -1069,7 +1069,7 @@ bool do_wear_armour(int item, bool quiet)
}
return (false);
}
- if (!item_cursed(you.inv[you.equip[EQ_CLOAK]]))
+ if (!you.inv[you.equip[EQ_CLOAK]].cursed())
{
cloak = you.equip[EQ_CLOAK];
if (!takeoff_armour(you.equip[EQ_CLOAK]))
@@ -1149,7 +1149,7 @@ bool takeoff_armour(int item)
}
// If we get here, we're wearing the item.
- if (item_cursed(invitem))
+ if (invitem.cursed())
{
mprf("%s is stuck to your body!", invitem.name(DESC_CAP_YOUR).c_str());
return (false);
@@ -1165,7 +1165,7 @@ bool takeoff_armour(int item)
{
if (you.equip[EQ_CLOAK] != -1 && !cloak_is_being_removed())
{
- if (!item_cursed(you.inv[you.equip[EQ_CLOAK]]))
+ if (!you.inv[you.equip[EQ_CLOAK]].cursed())
{
cloak = you.equip[ EQ_CLOAK ];
if (!takeoff_armour(you.equip[EQ_CLOAK]))
@@ -1453,7 +1453,7 @@ static bool _fire_validate_item(int slot, std::string &err)
{
if (slot == you.equip[EQ_WEAPON]
&& you.inv[slot].base_type == OBJ_WEAPONS
- && item_cursed(you.inv[slot]))
+ && you.inv[slot].cursed())
{
err = "That weapon is stuck to your hand!";
return (false);
@@ -3481,7 +3481,7 @@ void jewellery_wear_effects(item_def &item)
set_ident_flags(item, ISFLAG_EQ_JEWELLERY_MASK);
}
- if (item_cursed(item))
+ if (item.cursed())
{
mprf("Oops, that %s feels deathly cold.",
jewellery_is_amulet(item)? "amulet" : "ring");
@@ -3510,7 +3510,7 @@ static int _prompt_ring_to_remove(int new_ring)
const item_def *left = you.slot_item(EQ_LEFT_RING);
const item_def *right = you.slot_item(EQ_RIGHT_RING);
- if (item_cursed(*left) && item_cursed(*right))
+ if (left->cursed() && right->cursed())
{
mprf("You're already wearing two cursed rings!");
return (-1);
@@ -3730,7 +3730,7 @@ static bool _swap_rings(int ring_slot)
const item_def* lring = you.slot_item(EQ_LEFT_RING);
const item_def* rring = you.slot_item(EQ_RIGHT_RING);
- if (item_cursed(*lring) && item_cursed(*rring))
+ if (lring->cursed() && rring->cursed())
{
mprf("You're already wearing two cursed rings!");
return (false);
@@ -3744,7 +3744,7 @@ static bool _swap_rings(int ring_slot)
&& lring->plus2 == rring->plus2
&& !is_artefact(*lring) && !is_artefact(*rring))
{
- if (item_cursed(*lring))
+ if (lring->cursed())
unwanted = you.equip[EQ_RIGHT_RING];
else
unwanted = you.equip[EQ_LEFT_RING];
@@ -3811,7 +3811,7 @@ bool puton_item(int item_slot)
if (!is_amulet) // i.e. it's a ring
{
const item_def* gloves = you.slot_item(EQ_GLOVES);
- if (gloves && item_cursed(*gloves))
+ if (gloves && gloves->cursed())
{
mpr("You can't take your gloves off to put on a ring!");
return (false);
@@ -4025,7 +4025,7 @@ bool remove_ring(int slot, bool announce)
}
if (you.equip[EQ_GLOVES] != -1
- && item_cursed( you.inv[you.equip[EQ_GLOVES]] )
+ && you.inv[you.equip[EQ_GLOVES]] .cursed()
&& you.equip[EQ_AMULET] == -1)
{
mpr("You can't take your gloves off to remove any rings!");
@@ -4089,7 +4089,7 @@ bool remove_ring(int slot, bool announce)
}
if (you.equip[EQ_GLOVES] != -1
- && item_cursed( you.inv[you.equip[EQ_GLOVES]] )
+ && you.inv[you.equip[EQ_GLOVES]] .cursed()
&& (hand_used == EQ_LEFT_RING || hand_used == EQ_RIGHT_RING))
{
mpr("You can't take your gloves off to remove any rings!");
@@ -4102,7 +4102,7 @@ bool remove_ring(int slot, bool announce)
return (false);
}
- if (item_cursed( you.inv[you.equip[hand_used]] ))
+ if (you.inv[you.equip[hand_used]] .cursed())
{
if (announce)
{
@@ -4771,7 +4771,7 @@ bool enchant_weapon(enchant_stat_type which_stat, bool quiet, item_def &wpn)
return (false);
}
- const bool is_cursed = item_cursed(wpn);
+ const bool is_cursed = wpn.cursed();
// Missiles only have one stat.
if (wpn.base_type == OBJ_MISSILES)
@@ -4882,7 +4882,7 @@ bool enchant_armour(int &ac_change, bool quiet, item_def &arm)
return (false);
}
- const bool is_cursed = item_cursed(arm);
+ const bool is_cursed = arm.cursed();
// Turn hides into mails where applicable.
// NOTE: It is assumed that armour which changes in this way does
@@ -5355,7 +5355,7 @@ void read_scroll(int slot)
case SCR_CURSE_WEAPON:
if (!you.weapon()
|| you.weapon()->base_type != OBJ_WEAPONS
- || item_cursed(*you.weapon()))
+ || you.weapon()->cursed())
{
canned_msg(MSG_NOTHING_HAPPENS);
id_the_scroll = false;
@@ -5383,7 +5383,7 @@ void read_scroll(int slot)
{
item_def& wpn = *you.weapon();
- const bool is_cursed = item_cursed(wpn);
+ const bool is_cursed = wpn.cursed();
if (wpn.base_type != OBJ_WEAPONS && wpn.base_type != OBJ_MISSILES
|| !is_cursed
@@ -5491,7 +5491,7 @@ void read_scroll(int slot)
int affected = EQ_WEAPON;
for (int i = EQ_CLOAK; i <= EQ_BODY_ARMOUR; i++)
{
- if (you.equip[i] != -1 && !item_cursed(you.inv[you.equip[i]]))
+ if (you.equip[i] != -1 && !you.inv[you.equip[i]].cursed())
{
count++;
if (one_chance_in(count))
@@ -5695,7 +5695,7 @@ void use_artefact(item_def &item, bool *show_msgs, bool unmeld)
artefact_wpn_learn_prop(item, ARTP_BERSERK);
}
- if (!unmeld && !item_cursed(item) && proprt[ARTP_CURSED] > 0
+ if (!unmeld && !item.cursed() && proprt[ARTP_CURSED] > 0
&& one_chance_in(proprt[ARTP_CURSED]))
{
do_curse_item( item, false );
diff --git a/crawl-ref/source/itemname.cc b/crawl-ref/source/itemname.cc
index 8d487d2682..c8ce048107 100644
--- a/crawl-ref/source/itemname.cc
+++ b/crawl-ref/source/itemname.cc
@@ -1037,7 +1037,7 @@ std::string item_def::name_aux(description_level_type desc,
// this behaviour, *please* make it so that there is an option
// that maintains this behaviour. -- bwr
// Nor for artefacts. Again, the state should be obvious. --jpeg
- if (item_cursed(*this))
+ if (cursed())
buff << "cursed ";
else if (Options.show_uncursed && !know_pluses
&& (!know_type || !is_artefact(*this)))
@@ -1108,7 +1108,7 @@ std::string item_def::name_aux(description_level_type desc,
if (know_brand)
buff << weapon_brand_name(*this, terse);
- if (know_curse && item_cursed(*this) && terse)
+ if (know_curse && cursed() && terse)
buff << " (curse)";
break;
@@ -1197,7 +1197,7 @@ std::string item_def::name_aux(description_level_type desc,
case OBJ_ARMOUR:
if (know_curse && !terse)
{
- if (item_cursed(*this))
+ if (cursed())
buff << "cursed ";
else if (Options.show_uncursed && !know_pluses)
buff << "uncursed ";
@@ -1310,7 +1310,7 @@ std::string item_def::name_aux(description_level_type desc,
}
}
- if (know_curse && item_cursed(*this) && terse)
+ if (know_curse && cursed() && terse)
buff << " (curse)";
break;
@@ -1462,7 +1462,7 @@ std::string item_def::name_aux(description_level_type desc,
if (know_curse)
{
- if (item_cursed(*this))
+ if (cursed())
buff << "cursed ";
else if (Options.show_uncursed && !terse
&& (!is_randart || !know_type)
diff --git a/crawl-ref/source/itemprop.cc b/crawl-ref/source/itemprop.cc
index 720dfff844..bf47f3ab96 100644
--- a/crawl-ref/source/itemprop.cc
+++ b/crawl-ref/source/itemprop.cc
@@ -457,11 +457,6 @@ void init_properties()
//
// Item cursed status functions:
//
-bool item_cursed( const item_def &item )
-{
- return (item.flags & ISFLAG_CURSED);
-}
-
bool item_known_cursed( const item_def &item )
{
return ((item.flags & ISFLAG_KNOW_CURSE) && (item.flags & ISFLAG_CURSED));
@@ -567,48 +562,6 @@ 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.is_valid())
- return (false);
-
- 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);
-}
-
-// Is item something that no one would usually bother enchanting?
-bool item_is_mundane(const item_def &item)
-{
- switch (item.base_type)
- {
- case OBJ_WEAPONS:
- if (item.sub_type == WPN_CLUB
- || item.sub_type == WPN_GIANT_CLUB
- || item.sub_type == WPN_GIANT_SPIKED_CLUB
- || item.sub_type == WPN_KNIFE)
- {
- return (true);
- }
- break;
-
- case OBJ_ARMOUR:
- if (item.sub_type == ARM_ANIMAL_SKIN)
- return (true);
- break;
-
- default:
- break;
- }
-
- return (false);
-}
-
void set_ident_flags( item_def &item, unsigned long flags )
{
preserve_quiver_slots p;
@@ -1210,7 +1163,7 @@ bool is_enchantable_weapon(const item_def &wpn, bool uncurse, bool first)
|| first && wpn.plus >= MAX_WPN_ENCHANT
|| !first && wpn.plus2 >= MAX_WPN_ENCHANT)
{
- return (uncurse && item_cursed(wpn));
+ return (uncurse && wpn.cursed());
}
}
// Highly enchanted missiles, which have only one stat, cannot be
@@ -1243,7 +1196,7 @@ bool is_enchantable_armour(const item_def &arm, bool uncurse, bool unknown)
// Artefacts or highly enchanted armour cannot be enchanted, only
// uncursed.
if (is_artefact(arm) || arm.plus >= armour_max_enchant(arm))
- return (uncurse && item_cursed(arm));
+ return (uncurse && arm.cursed());
return (true);
}
diff --git a/crawl-ref/source/itemprop.h b/crawl-ref/source/itemprop.h
index a8f1eceabd..5604d352f5 100644
--- a/crawl-ref/source/itemprop.h
+++ b/crawl-ref/source/itemprop.h
@@ -14,14 +14,7 @@ struct bolt;
void init_properties(void);
-// Returns true if this item should be preserved as far as possible.
-bool item_is_critical(const item_def &item);
-
-// Returns true if this item should not normally be enchanted.
-bool item_is_mundane(const item_def &item);
-
// cursed:
-bool item_cursed( const item_def &item );
bool item_known_cursed( const item_def &item );
bool item_known_uncursed( const item_def &item );
void do_curse_item( item_def &item, bool quiet = true );
diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc
index a3418761d4..29b25a021b 100644
--- a/crawl-ref/source/items.cc
+++ b/crawl-ref/source/items.cc
@@ -1921,7 +1921,7 @@ bool drop_item( int item_dropped, int quant_drop, bool try_offer )
if (item_dropped == you.equip[EQ_WEAPON]
&& you.inv[item_dropped].base_type == OBJ_WEAPONS
- && item_cursed( you.inv[item_dropped] ))
+ && you.inv[item_dropped] .cursed())
{
mpr("That object is stuck to you!");
return (false);
@@ -2821,7 +2821,7 @@ int item_def::book_number() const
bool item_def::cursed() const
{
- return (item_cursed(*this));
+ return (flags & ISFLAG_CURSED);
}
bool item_def::launched_by(const item_def &launcher) const
@@ -2919,6 +2919,48 @@ bool item_def::is_valid() const
return (base_type != OBJ_UNASSIGNED && quantity > 0);
}
+// The Orb of Zot and unique runes are considered critical.
+bool item_def::is_critical() const
+{
+ if (!is_valid())
+ return (false);
+
+ if (base_type == OBJ_ORBS)
+ return (true);
+
+ return (base_type == OBJ_MISCELLANY
+ && sub_type == MISC_RUNE_OF_ZOT
+ && plus != RUNE_DEMONIC
+ && plus != RUNE_ABYSSAL);
+}
+
+// Is item something that no one would usually bother enchanting?
+bool item_def::is_mundane() const
+{
+ switch (base_type)
+ {
+ case OBJ_WEAPONS:
+ if (sub_type == WPN_CLUB
+ || sub_type == WPN_GIANT_CLUB
+ || sub_type == WPN_GIANT_SPIKED_CLUB
+ || sub_type == WPN_KNIFE)
+ {
+ return (true);
+ }
+ break;
+
+ case OBJ_ARMOUR:
+ if (sub_type == ARM_ANIMAL_SKIN)
+ return (true);
+ break;
+
+ default:
+ break;
+ }
+
+ return (false);
+}
+
static void _rune_from_specs(const char* _specs, item_def &item)
{
char specs[80];
diff --git a/crawl-ref/source/l_dgn.cc b/crawl-ref/source/l_dgn.cc
index 99035d37f0..dddb216da4 100644
--- a/crawl-ref/source/l_dgn.cc
+++ b/crawl-ref/source/l_dgn.cc
@@ -1173,14 +1173,16 @@ static int lua_cloud_pow_rolls;
static int make_a_lua_cloud(coord_def where, int garbage, int spread_rate,
cloud_type ctype, kill_category whose,
- killer_type killer)
+ killer_type killer, int colour, std::string name,
+ std::string tile)
{
UNUSED( garbage );
const int pow = random_range(lua_cloud_pow_min,
lua_cloud_pow_max,
lua_cloud_pow_rolls);
- place_cloud( ctype, where, pow, whose, killer, spread_rate );
+ place_cloud( ctype, where, pow, whose, killer, spread_rate, colour, name,
+ tile );
return 1;
}
@@ -1200,6 +1202,10 @@ static int dgn_apply_area_cloud(lua_State *ls)
const int spread_rate = lua_isnumber(ls, 9) ? luaL_checkint(ls, 9) : -1;
+ const int colour = lua_isstring(ls, 10) ? str_to_colour(luaL_checkstring(ls, 10)) : -1;
+ std::string name = lua_isstring(ls, 11) ? luaL_checkstring(ls, 11) : "";
+ std::string tile = lua_isstring(ls, 12) ? luaL_checkstring(ls, 12) : "";
+
if (!in_bounds(x, y))
{
char buf[80];
@@ -1265,7 +1271,7 @@ static int dgn_apply_area_cloud(lua_State *ls)
apply_area_cloud(make_a_lua_cloud, coord_def(x, y), 0, size,
ctype, kc, cloud_struct::whose_to_killer(kc),
- spread_rate);
+ spread_rate, colour, name, tile);
return (0);
}
@@ -1282,6 +1288,10 @@ static int dgn_place_cloud(lua_State *ls)
const int spread_rate = lua_isnumber(ls, 6) ? luaL_checkint(ls, 6) : -1;
+ const int colour = lua_isstring(ls, 7) ? str_to_colour(luaL_checkstring(ls, 7)) : -1;
+ std::string name = lua_isstring(ls, 8) ? luaL_checkstring(ls, 8) : "";
+ std::string tile = lua_isstring(ls, 9) ? luaL_checkstring(ls, 9) : "";
+
if (!in_bounds(x, y))
{
char buf[80];
@@ -1315,7 +1325,7 @@ static int dgn_place_cloud(lua_State *ls)
return (0);
}
- place_cloud(ctype, coord_def(x, y), cl_range, kc, spread_rate);
+ place_cloud(ctype, coord_def(x, y), cl_range, kc, spread_rate, colour, name, tile);
return (0);
}
diff --git a/crawl-ref/source/l_item.cc b/crawl-ref/source/l_item.cc
index c2248e1682..80bbc88df9 100644
--- a/crawl-ref/source/l_item.cc
+++ b/crawl-ref/source/l_item.cc
@@ -463,7 +463,7 @@ static int l_item_cursed(lua_State *ls)
{
LUA_ITEM(item, 1);
bool cursed = item && item_ident(*item, ISFLAG_KNOW_CURSE)
- && item_cursed(*item);
+ && item->cursed();
lua_pushboolean(ls, cursed);
return (1);
}
diff --git a/crawl-ref/source/main.cc b/crawl-ref/source/main.cc
index c1b4c6d615..9dcd774a00 100644
--- a/crawl-ref/source/main.cc
+++ b/crawl-ref/source/main.cc
@@ -533,8 +533,8 @@ static void _do_wizard_command(int wiz_command, bool silent_fail)
case 'I': wizard_unidentify_pack(); break;
case 'Z':
case 'z': wizard_cast_spec_spell(); break;
- case '(': wizard_create_feature_number(); break;
- case ')': wizard_create_feature_name(); break;
+ case '(':
+ case ')': wizard_create_feature(); break;
case ':': wizard_list_branches(); break;
case '{': wizard_map_level(); break;
case '}': wizard_reveal_traps(); break;
diff --git a/crawl-ref/source/makefile.obj b/crawl-ref/source/makefile.obj
index 8761eb11e7..1b1d038f31 100644
--- a/crawl-ref/source/makefile.obj
+++ b/crawl-ref/source/makefile.obj
@@ -34,6 +34,7 @@ dgnevent.o \
directn.o \
dlua.o \
dungeon.o \
+dgn-shoals.o \
effects.o \
exclude.o \
feature.o \
@@ -101,6 +102,7 @@ menu.o \
message.o \
mgen_data.o \
misc.o \
+mislead.o \
mon-abil.o \
mon-act.o \
mon-behv.o \
diff --git a/crawl-ref/source/makeitem.cc b/crawl-ref/source/makeitem.cc
index ee473f1a04..442b500112 100644
--- a/crawl-ref/source/makeitem.cc
+++ b/crawl-ref/source/makeitem.cc
@@ -1699,7 +1699,7 @@ brand_ok:
}
else if ((force_good || is_demonic(item) || forced_ego
|| x_chance_in_y(51 + item_level, 200))
- && (!item_is_mundane(item) || force_good))
+ && (!item.is_mundane() || force_good))
{
// Make a better item (possibly ego).
if (!no_brand)
@@ -2399,7 +2399,7 @@ static void _generate_armour_item(item_def& item, bool allow_uniques,
}
else if ((force_good || forced_ego || item.sub_type == ARM_WIZARD_HAT
|| x_chance_in_y(51 + item_level, 250))
- && (!item_is_mundane(item) || force_good))
+ && (!item.is_mundane() || force_good))
{
// Make a good item...
item.plus += random2(3);
@@ -2924,7 +2924,7 @@ static void _generate_jewellery_item(item_def& item, bool allow_uniques,
if (item.sub_type == RING_SLAYING ) // requires plus2 too
{
- if (item_cursed(item) && !one_chance_in(20))
+ if (item.cursed() && !one_chance_in(20))
item.plus2 = -1 - random2avg(6, 2);
else
{
@@ -3233,7 +3233,7 @@ static bool _weapon_is_visibly_special(const item_def &item)
if (visibly_branded || is_artefact(item))
return (true);
- if (item_is_mundane(item))
+ if (item.is_mundane())
return (false);
if ((item.plus || item.plus2)
@@ -3256,7 +3256,7 @@ static bool _armour_is_visibly_special(const item_def &item)
if (visibly_branded || is_artefact(item))
return (true);
- if (item_is_mundane(item))
+ if (item.is_mundane())
return (false);
if (item.plus && !one_chance_in(3))
diff --git a/crawl-ref/source/mapdef.cc b/crawl-ref/source/mapdef.cc
index 060ec78677..5eda9e7792 100644
--- a/crawl-ref/source/mapdef.cc
+++ b/crawl-ref/source/mapdef.cc
@@ -3898,20 +3898,17 @@ item_spec item_list::parse_single_spec(std::string s)
}
}
- if (s.find("damaged ") == 0)
+ if (strip_tag(s, "damaged"))
{
result.level = ISPEC_DAMAGED;
- s = s.substr(8);
}
- if (s.find("cursed ") == 0)
+ if (strip_tag(s, "cursed"))
{
result.level = ISPEC_BAD; // damaged + cursed, actually
- s = s.substr(7);
}
- if (s.find("randart ") == 0)
+ if (strip_tag(s, "randart"))
{
result.level = ISPEC_RANDART;
- s = s.substr(8);
}
if (strip_tag(s, "no_uniq"))
diff --git a/crawl-ref/source/maps.cc b/crawl-ref/source/maps.cc
index 07da121e02..072b7c8557 100644
--- a/crawl-ref/source/maps.cc
+++ b/crawl-ref/source/maps.cc
@@ -337,7 +337,7 @@ static bool _safe_vault_place(const map_def &map,
if (lines[dp.y][dp.x] == ' ')
continue;
- if (dgn_Map_Mask[cp.x][cp.y] == MMT_VAULT)
+ if (dgn_Map_Mask[cp.x][cp.y] & MMT_VAULT)
return (false);
const dungeon_feature_type dfeat = grd(cp);
diff --git a/crawl-ref/source/message.cc b/crawl-ref/source/message.cc
index 6a3d36c487..a6adba6847 100644
--- a/crawl-ref/source/message.cc
+++ b/crawl-ref/source/message.cc
@@ -413,12 +413,17 @@ int channel_to_colour( msg_channel_type channel, int param )
static void do_message_print( msg_channel_type channel, int param,
const char *format, va_list argp )
{
- // Is this limit intentional?
char buff[200];
- vsnprintf( buff, sizeof( buff ), format, argp );
- buff[199] = 0;
-
- mpr(buff, channel, param);
+ size_t len = vsnprintf( buff, sizeof( buff ), format, argp );
+ if (len < sizeof( buff )) {
+ mpr( buff, channel, param );
+ }
+ else {
+ char *heapbuf = (char*)malloc( len + 1 );
+ vsnprintf( heapbuf, len + 1, format, argp );
+ mpr( heapbuf, channel, param );
+ free( heapbuf );
+ }
}
void mprf( msg_channel_type channel, int param, const char *format, ... )
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index 5697133c4a..b5c9e6bb40 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -36,6 +36,7 @@
#include "coordit.h"
#include "database.h"
#include "delay.h"
+#include "dgn-shoals.h"
#include "directn.h"
#include "dgnevent.h"
#include "directn.h"
@@ -2888,14 +2889,15 @@ bool i_feel_safe(bool announce, bool want_move, bool just_monsters, int range)
// check clouds
if (in_bounds(you.pos()) && env.cgrid(you.pos()) != EMPTY_CLOUD)
{
- const cloud_type type = env.cloud[env.cgrid(you.pos())].type;
+ const int cloudidx = env.cgrid(you.pos());
+ const cloud_type type = env.cloud[cloudidx].type;
if (is_damaging_cloud(type, want_move))
{
if (announce)
{
mprf(MSGCH_WARN, "You're standing in a cloud of %s!",
- cloud_name(type).c_str());
+ cloud_name(cloudidx).c_str());
}
return (false);
}
@@ -3092,6 +3094,7 @@ void run_environment_effects()
}
run_corruption_effects(you.time_taken);
+ shoals_apply_tides(div_rand_round(you.time_taken, 10));
}
coord_def pick_adjacent_free_square(const coord_def& p)
diff --git a/crawl-ref/source/mislead.cc b/crawl-ref/source/mislead.cc
new file mode 100644
index 0000000000..64c574d97a
--- /dev/null
+++ b/crawl-ref/source/mislead.cc
@@ -0,0 +1,127 @@
+/* File: mislead.cc
+ * Summary: Handling of the Mislead spell and stats
+ */
+
+#include "AppHdr.h"
+#include "mislead.h"
+
+#include "enum.h"
+#include "env.h"
+#include "message.h"
+#include "monster.h"
+#include "mon-iter.h"
+#include "mon-util.h"
+#include "view.h"
+#include "random.h"
+#include "tutorial.h"
+#include "xom.h"
+
+bool unsuitable_misled_monster(monster_type mons)
+{
+ return (mons_is_unique(mons) || mons_is_mimic(mons)
+ || mons_class_is_stationary(mons) || mons_genus(mons) == MONS_DRACONIAN
+ || mons == MONS_DANCING_WEAPON || mons == MONS_UGLY_THING
+ || mons == MONS_VERY_UGLY_THING || mons == MONS_ZOMBIE_SMALL
+ || mons == MONS_ZOMBIE_LARGE || mons == MONS_SKELETON_SMALL
+ || mons == MONS_SKELETON_LARGE || mons == MONS_SIMULACRUM_SMALL
+ || mons == MONS_SIMULACRUM_LARGE || mons == MONS_SPECTRAL_THING
+ || mons == MONS_SLIME_CREATURE || mons == MONS_BALLISTOMYCETE
+ || mons == MONS_HYDRA || mons == MONS_PLAYER_GHOST
+ || mons == MONS_SHAPESHIFTER || mons == MONS_PANDEMONIUM_DEMON
+ || mons == MONS_KILLER_KLOWN || mons == MONS_KRAKEN
+ || mons == MONS_KRAKEN_TENTACLE
+ || mons == MONS_GLOWING_SHAPESHIFTER
+ || mons == MONS_GIANT_BAT);
+}
+
+monster_type get_misled_monster (monsters *monster)
+{
+ monster_type mons = random_monster_at_grid(monster->pos());
+ if (unsuitable_misled_monster(mons))
+ mons = random_monster_at_grid(monster->pos());
+
+ if (unsuitable_misled_monster(mons))
+ return (MONS_GIANT_BAT);
+
+ return mons;
+}
+
+bool update_mislead_monster(monsters* monster)
+{
+ // Don't affect uniques, named monsters, and monsters with special tiles.
+ if (mons_is_unique(monster->type) || !monster->mname.empty()
+ || monster->props.exists("monster_tile")
+ || monster->props.exists("mislead_as"))
+ {
+ return (false);
+ }
+
+ short misled_as = get_misled_monster(monster);
+ monster->props["mislead_as"] = misled_as;
+
+ if (misled_as == MONS_GIANT_BAT)
+ return (false);
+
+ return (true);
+}
+
+int update_mislead_monsters(monsters* caster)
+{
+ int count = 0;
+
+ for (monster_iterator mi; mi; ++mi)
+ if (*mi != caster && update_mislead_monster(*mi))
+ count++;
+
+ return count;
+}
+
+void mons_cast_mislead(monsters *monster)
+{
+ // This really only affects the player; it causes confusion when cast on
+ // non-player foes, but that is dealt with inside ye-great-Switch-of-Doom.
+ if (monster->foe != MHITYOU)
+ return;
+
+ // Prevents Mislead spam by Mara and co. {due}
+ if (you.duration[DUR_MISLED] > 10 && one_chance_in(3))
+ return;
+
+ if (wearing_amulet(AMU_CLARITY))
+ {
+ mpr("Your vision blurs momentarily.");
+ return;
+ }
+
+ update_mislead_monsters(monster);
+
+ const int old_value = you.duration[DUR_MISLED];
+ you.increase_duration(DUR_MISLED, monster->hit_dice * 12 / 3, 50);
+ if (you.duration[DUR_MISLED] > old_value)
+ {
+ you.check_awaken(500);
+
+ if (old_value <= 0)
+ {
+ mpr("But for a moment, strange images dance in front of your eyes.", MSGCH_WARN);
+#ifdef USE_TILE
+ tiles.add_overlay(you.pos(), tileidx_zap(MAGENTA));
+ update_screen();
+#else
+ flash_view(MAGENTA);
+#endif
+ more();
+ }
+ else
+ mpr("You are even more misled!", MSGCH_WARN);
+
+ learned_something_new(TUT_YOU_ENCHANTED);
+
+ xom_is_stimulated((you.duration[DUR_MISLED] - old_value)
+ / BASELINE_DELAY);
+ }
+
+ return;
+}
+
+
diff --git a/crawl-ref/source/mislead.h b/crawl-ref/source/mislead.h
new file mode 100644
index 0000000000..540ffea9b1
--- /dev/null
+++ b/crawl-ref/source/mislead.h
@@ -0,0 +1,8 @@
+/* File: mislead.h
+ * Summary: Handling of the Mislead spell and stats
+ */
+
+bool unsuitable_misled_monster(monster_type mons);
+monster_type get_misled_monster (monsters *monster);
+int update_mislead_monsters(monsters* caster);
+bool update_mislead_monster(monsters* monster);
diff --git a/crawl-ref/source/mon-cast.cc b/crawl-ref/source/mon-cast.cc
index 761521f7ab..7bbbd77862 100644
--- a/crawl-ref/source/mon-cast.cc
+++ b/crawl-ref/source/mon-cast.cc
@@ -24,6 +24,7 @@
#include "mon-place.h"
#include "terrain.h"
#include "tutorial.h"
+#include "mislead.h"
#include "mgen_data.h"
#include "coord.h"
#include "mon-speak.h"
@@ -1564,108 +1565,6 @@ int _count_mara_fakes()
return count;
}
-bool _unsuitable_misled_monster(monster_type mons)
-{
- return (mons_is_unique(mons) || mons_is_mimic(mons)
- || mons_class_is_stationary(mons) || mons_genus(mons) == MONS_DRACONIAN
- || mons == MONS_DANCING_WEAPON || mons == MONS_UGLY_THING
- || mons == MONS_VERY_UGLY_THING || mons == MONS_ZOMBIE_SMALL
- || mons == MONS_ZOMBIE_LARGE || mons == MONS_SKELETON_SMALL
- || mons == MONS_SKELETON_LARGE || mons == MONS_SIMULACRUM_SMALL
- || mons == MONS_SIMULACRUM_LARGE || mons == MONS_SPECTRAL_THING
- || mons == MONS_SLIME_CREATURE || mons == MONS_BALLISTOMYCETE
- || mons == MONS_HYDRA || mons == MONS_PLAYER_GHOST
- || mons == MONS_SHAPESHIFTER || mons == MONS_PANDEMONIUM_DEMON
- || mons == MONS_KILLER_KLOWN || mons == MONS_KRAKEN
- || mons == MONS_KRAKEN_TENTACLE
- || mons == MONS_GLOWING_SHAPESHIFTER);
-}
-
-monster_type _get_misled_monster (monsters *monster)
-{
- monster_type mons = random_monster_at_grid(monster->pos());
- if (_unsuitable_misled_monster(mons))
- mons = random_monster_at_grid(monster->pos());
-
- if (_unsuitable_misled_monster(mons))
- return (MONS_GIANT_BAT);
-
- return mons;
-}
-
-int _update_mislead_monsters(monsters* monster)
-{
- int count = 0;
-
- for (monster_iterator mi; mi; ++mi)
- {
- if (*mi == monster)
- continue;
-
- // Don't affect uniques, named monsters, and monsters with special tiles.
- if (mons_is_unique(mi->type) || !mi->mname.empty()
- || mi->props.exists("monster_tile") || mi->props.exists("mislead_as"))
- {
- continue;
- }
- else
- {
- mi->props["mislead_as"] = short(_get_misled_monster(*mi));
- count++;
- }
- }
-
- return count;
-}
-
-void mons_cast_mislead(monsters *monster)
-{
- // This really only affects the player; it causes confusion when cast on
- // non-player foes, but that is dealt with inside ye-great-Switch-of-Doom.
- if (monster->foe != MHITYOU)
- return;
-
- // Prevents Mislead spam by Mara and co. {due}
- if (you.duration[DUR_MISLED] > 10 && one_chance_in(3))
- return;
-
- if (wearing_amulet(AMU_CLARITY))
- {
- mpr("Your vision blurs momentarily.");
- return;
- }
-
- _update_mislead_monsters(monster);
-
- const int old_value = you.duration[DUR_MISLED];
- you.increase_duration(DUR_MISLED, monster->hit_dice * 12 / 3, 50);
- if (you.duration[DUR_MISLED] > old_value)
- {
- you.check_awaken(500);
-
- if (old_value <= 0)
- {
- mpr("But for a moment, strange images dance in front of your eyes.", MSGCH_WARN);
-#ifdef USE_TILE
- tiles.add_overlay(you.pos(), tileidx_zap(MAGENTA));
- update_screen();
-#else
- flash_view(MAGENTA);
-#endif
- more();
- }
- else
- mpr("You are even more misled!", MSGCH_WARN);
-
- learned_something_new(TUT_YOU_ENCHANTED);
-
- xom_is_stimulated((you.duration[DUR_MISLED] - old_value)
- / BASELINE_DELAY);
- }
-
- return;
-}
-
bool _find_players_ghost ()
{
bool found = false;
diff --git a/crawl-ref/source/mon-place.cc b/crawl-ref/source/mon-place.cc
index 9faa371cb8..3a88d27774 100644
--- a/crawl-ref/source/mon-place.cc
+++ b/crawl-ref/source/mon-place.cc
@@ -24,6 +24,7 @@
#include "lev-pand.h"
#include "makeitem.h"
#include "message.h"
+#include "mislead.h"
#include "mon-behv.h"
#include "mon-gear.h"
#include "mon-iter.h"
@@ -1242,6 +1243,9 @@ static int _place_monster_aux(const mgen_data &mg,
mon->add_ench(ENCH_SLOWLY_DYING);
}
+ if (!crawl_state.arena && you.misled())
+ update_mislead_monster(mon);
+
if (monster_can_submerge(mon, grd(fpos)) && !one_chance_in(5))
mon->add_ench(ENCH_SUBMERGED);
diff --git a/crawl-ref/source/mon-stuff.cc b/crawl-ref/source/mon-stuff.cc
index d8f0a8e7a2..730fb54ef2 100644
--- a/crawl-ref/source/mon-stuff.cc
+++ b/crawl-ref/source/mon-stuff.cc
@@ -198,7 +198,7 @@ bool curse_an_item( bool decay_potions, bool quiet )
|| you.inv[i].base_type == OBJ_JEWELLERY
|| you.inv[i].base_type == OBJ_POTIONS)
{
- if (item_cursed( you.inv[i] ))
+ if (you.inv[i] .cursed())
continue;
if (you.inv[i].base_type != OBJ_POTIONS
diff --git a/crawl-ref/source/monster.cc b/crawl-ref/source/monster.cc
index 4cefe30857..5285da7795 100644
--- a/crawl-ref/source/monster.cc
+++ b/crawl-ref/source/monster.cc
@@ -577,11 +577,11 @@ bool monsters::can_wield(const item_def& item, bool ignore_curse,
if (!ignore_curse)
{
int num_cursed = 0;
- if (weap1 && item_cursed(*weap1))
+ if (weap1 && weap1->cursed())
num_cursed++;
- if (weap2 && item_cursed(*weap2))
+ if (weap2 && weap2->cursed())
num_cursed++;
- if (_shield && item_cursed(*_shield))
+ if (_shield && _shield->cursed())
num_cursed++;
if (two_handed && num_cursed > 0 || num_cursed >= avail_slots)
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index 4e5cf2dc77..04c1498297 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -165,7 +165,7 @@ bool move_player_to_grid( const coord_def& p, bool stepped, bool allow_shift,
{
std::string prompt = make_stringf(
"Really step into that cloud of %s?",
- cloud_name(ctype).c_str());
+ cloud_name(cloud).c_str());
if (!yesno(prompt.c_str(), false, 'n'))
{
@@ -5732,7 +5732,7 @@ bool player::can_wield(const item_def& item, bool ignore_curse,
{
if (equip[EQ_WEAPON] != -1 && !ignore_curse)
{
- if (item_cursed(inv[equip[EQ_WEAPON]]))
+ if (inv[equip[EQ_WEAPON]].cursed())
return (false);
}
@@ -7031,6 +7031,17 @@ void player::moveto(const coord_def &c)
set_position(c);
}
+bool player::move_to_pos(const coord_def &c)
+{
+ actor *target = actor_at(c);
+ if (!target || target->submerged())
+ {
+ moveto(c);
+ return true;
+ }
+ return false;
+}
+
void player::shiftto(const coord_def &c)
{
crawl_view.shift_player_to(c);
@@ -7423,6 +7434,3 @@ void player::set_duration(duration_type dur, int turns,
you.duration[dur] = 0;
increase_duration(dur, turns, cap, msg);
}
-
-
-
diff --git a/crawl-ref/source/player.h b/crawl-ref/source/player.h
index d7f5306c08..a02e5f5c4c 100644
--- a/crawl-ref/source/player.h
+++ b/crawl-ref/source/player.h
@@ -314,6 +314,7 @@ public:
void set_position(const coord_def &c);
// Low-level move the player. Use this instead of changing pos directly.
void moveto(const coord_def &c);
+ bool move_to_pos(const coord_def &c);
// Move the player during an abyss shift.
void shiftto(const coord_def &c);
bool blink_to(const coord_def& c, bool quiet = false);
diff --git a/crawl-ref/source/religion.cc b/crawl-ref/source/religion.cc
index 395db6af89..763f1c0709 100644
--- a/crawl-ref/source/religion.cc
+++ b/crawl-ref/source/religion.cc
@@ -609,7 +609,7 @@ std::string get_god_likes(god_type which_god, bool verbose)
break;
}
- if (god_likes_fresh_corpses(which_god))
+ if (god_likes_fresh_corpses(which_god) && which_god != GOD_KIKUBAAQUDGHA)
{
snprintf(info, INFO_SIZE, "you sacrifice fresh corpses%s",
verbose ? " (by standing over them and <w>p</w>raying)" : "");
@@ -4230,7 +4230,7 @@ static bool _bless_weapon(god_type god, brand_type brand, int colour)
set_item_ego_type(wpn, OBJ_WEAPONS, brand);
wpn.colour = colour;
- const bool is_cursed = item_cursed(wpn);
+ const bool is_cursed = wpn.cursed();
enchant_weapon(ENCHANT_TO_HIT, true, wpn);
diff --git a/crawl-ref/source/rltiles/dc-mon.txt b/crawl-ref/source/rltiles/dc-mon.txt
index ef0836c80b..b4a0c59fdf 100644
--- a/crawl-ref/source/rltiles/dc-mon.txt
+++ b/crawl-ref/source/rltiles/dc-mon.txt
@@ -339,6 +339,7 @@ vault_guard MONS_VAULT_GUARD
shapeshifter MONS_SHAPESHIFTER
glowing_shapeshifter MONS_GLOWING_SHAPESHIFTER
killer_klown MONS_KILLER_KLOWN
+slave MONS_SLAVE
## From the Wucad Mu wizlab
human_monk_ghost MONS_HUMAN_MONK
## From the Cigotuvi wizlab
diff --git a/crawl-ref/source/rltiles/dc-mon/slave.png b/crawl-ref/source/rltiles/dc-mon/slave.png
new file mode 100644
index 0000000000..0f7e353e5c
--- /dev/null
+++ b/crawl-ref/source/rltiles/dc-mon/slave.png
Binary files differ
diff --git a/crawl-ref/source/rltiles/dc-mon/unique/maurice.png b/crawl-ref/source/rltiles/dc-mon/unique/maurice.png
index 284ad4645c..874963221c 100644
--- a/crawl-ref/source/rltiles/dc-mon/unique/maurice.png
+++ b/crawl-ref/source/rltiles/dc-mon/unique/maurice.png
Binary files differ
diff --git a/crawl-ref/source/show.cc b/crawl-ref/source/show.cc
index d6c3ff577a..c37901d7e0 100644
--- a/crawl-ref/source/show.cc
+++ b/crawl-ref/source/show.cc
@@ -273,8 +273,7 @@ void show_def::_update_cloud(int cloudno)
grid(e).colour = which_colour;
#ifdef USE_TILE
- tile_place_cloud(e.x, e.y, env.cloud[cloudno].type,
- env.cloud[cloudno].decay);
+ tile_place_cloud(e.x, e.y, env.cloud[cloudno]);
#endif
}
diff --git a/crawl-ref/source/spells1.cc b/crawl-ref/source/spells1.cc
index 647077f2f4..f6dd4009a3 100644
--- a/crawl-ref/source/spells1.cc
+++ b/crawl-ref/source/spells1.cc
@@ -661,29 +661,32 @@ bool stinking_cloud( int pow, bolt &beem )
int cast_big_c(int pow, cloud_type cty, kill_category whose, bolt &beam)
{
- big_cloud( cty, whose, beam.target, pow, 8 + random2(3) );
+ big_cloud( cty, whose, beam.target, pow, 8 + random2(3), -1 );
return (1);
}
void big_cloud(cloud_type cl_type, kill_category whose,
- const coord_def& where, int pow, int size, int spread_rate)
+ const coord_def& where, int pow, int size, int spread_rate,
+ int colour, std::string name, std::string tile)
{
big_cloud(cl_type, whose, cloud_struct::whose_to_killer(whose),
- where, pow, size, spread_rate);
+ where, pow, size, spread_rate, colour, name, tile);
}
void big_cloud(cloud_type cl_type, killer_type killer,
- const coord_def& where, int pow, int size, int spread_rate)
+ const coord_def& where, int pow, int size, int spread_rate,
+ int colour, std::string name, std::string tile)
{
big_cloud(cl_type, cloud_struct::killer_to_whose(killer), killer,
- where, pow, size, spread_rate);
+ where, pow, size, spread_rate, colour, name, tile);
}
void big_cloud(cloud_type cl_type, kill_category whose, killer_type killer,
- const coord_def& where, int pow, int size, int spread_rate)
+ const coord_def& where, int pow, int size, int spread_rate,
+ int colour, std::string name, std::string tile)
{
apply_area_cloud(make_a_normal_cloud, where, pow, size,
- cl_type, whose, killer, spread_rate);
+ cl_type, whose, killer, spread_rate, colour, name, tile);
}
static bool _mons_hostile(const monsters *mon)
diff --git a/crawl-ref/source/spells1.h b/crawl-ref/source/spells1.h
index 8368947f03..b342b71684 100644
--- a/crawl-ref/source/spells1.h
+++ b/crawl-ref/source/spells1.h
@@ -21,11 +21,14 @@ void remove_divine_stamina();
bool cast_vitalisation();
void big_cloud(cloud_type cl_type, kill_category whose, const coord_def& where,
- int pow, int size, int spread_rate = -1);
+ int pow, int size, int spread_rate = -1, int colour = -1,
+ std::string name = "", std::string tile = "");
void big_cloud(cloud_type cl_type, killer_type killer, const coord_def& where,
- int pow, int size, int spread_rate = -1);
+ int pow, int size, int spread_rate = -1, int colour = -1,
+ std::string name = "", std::string tile = "");
void big_cloud(cloud_type cl_type, kill_category whose, killer_type killer,
- const coord_def& where, int pow, int size, int spread_rate = -1);
+ const coord_def& where, int pow, int size, int spread_rate = -1,
+ int colour = -1, std::string name = "", std::string tile = "");
int blink(int pow, bool high_level_controlled_blink, bool wizard_blink = false);
diff --git a/crawl-ref/source/spells2.cc b/crawl-ref/source/spells2.cc
index 4902786aa6..d765d4db5f 100644
--- a/crawl-ref/source/spells2.cc
+++ b/crawl-ref/source/spells2.cc
@@ -1101,7 +1101,7 @@ bool cast_sticks_to_snakes(int pow, god_type god)
const int dur = std::min(3 + random2(pow) / 20, 5);
int how_many_max = 1 + random2(1 + you.skills[SK_TRANSMUTATIONS]) / 4;
- const bool friendly = (!item_cursed(wpn));
+ const bool friendly = (!wpn.cursed());
const beh_type beha = (friendly) ? BEH_FRIENDLY : BEH_HOSTILE;
int count = 0;
@@ -1712,7 +1712,7 @@ bool cast_tukimas_dance(int pow, god_type god, bool force_hostile)
if (success)
{
// Cursed weapons become hostile.
- const bool friendly = (!force_hostile && !item_cursed(you.inv[wpn]));
+ const bool friendly = (!force_hostile && !you.inv[wpn].cursed());
mgen_data mg(MONS_DANCING_WEAPON,
friendly ? BEH_FRIENDLY : BEH_HOSTILE,
diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc
index 26747c1f07..1a30607199 100644
--- a/crawl-ref/source/spells3.cc
+++ b/crawl-ref/source/spells3.cc
@@ -130,7 +130,7 @@ bool remove_curse(bool suppress_msg)
// Only cursed *weapons* in hand count as cursed. - bwr
if (you.weapon()
&& you.weapon()->base_type == OBJ_WEAPONS
- && item_cursed(*you.weapon()))
+ && you.weapon()->cursed())
{
// Also sets wield_change.
do_uncurse_item(*you.weapon());
@@ -142,7 +142,7 @@ bool remove_curse(bool suppress_msg)
for (int i = EQ_WEAPON + 1; i < NUM_EQUIP; i++)
{
// Melded equipment can also get uncursed this way.
- if (you.equip[i] != -1 && item_cursed(you.inv[you.equip[i]]))
+ if (you.equip[i] != -1 && you.inv[you.equip[i]].cursed())
{
do_uncurse_item(you.inv[you.equip[i]]);
success = true;
@@ -1528,13 +1528,15 @@ static bool _teleport_player(bool allow_control, bool new_abyss_area, bool wizar
if (is_controlled)
{
- mpr("You may choose your destination (press '.' or delete to select).");
- mpr("Expect minor deviation.");
check_ring_TC = true;
- // Only have the more prompt for non-wizard.
+ // Only have the messages and the more prompt for non-wizard.
if (!wizard_tele)
+ {
+ mpr("You may choose your destination (press '.' or delete to select).");
+ mpr("Expect minor deviation.");
more();
+ }
while (true)
{
diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc
index 6819599ee5..6fbb55f399 100644
--- a/crawl-ref/source/spells4.cc
+++ b/crawl-ref/source/spells4.cc
@@ -879,14 +879,15 @@ void cast_dispersal(int pow)
int make_a_normal_cloud(coord_def where, int pow, int spread_rate,
cloud_type ctype, kill_category whose,
- killer_type killer)
+ killer_type killer, int colour, std::string name,
+ std::string tile)
{
if (killer == KILL_NONE)
killer = cloud_struct::whose_to_killer(whose);
place_cloud( ctype, where,
(3 + random2(pow / 4) + random2(pow / 4) + random2(pow / 4)),
- whose, killer, spread_rate );
+ whose, killer, spread_rate, colour, name, tile );
return 1;
}
diff --git a/crawl-ref/source/spells4.h b/crawl-ref/source/spells4.h
index fbadac0203..cd977e3d01 100644
--- a/crawl-ref/source/spells4.h
+++ b/crawl-ref/source/spells4.h
@@ -16,7 +16,8 @@ struct bolt;
bool backlight_monsters(coord_def where, int pow, int garbage);
int make_a_normal_cloud(coord_def where, int pow, int spread_rate,
cloud_type ctype, kill_category,
- killer_type killer = KILL_NONE);
+ killer_type killer = KILL_NONE, int colour = -1,
+ std::string name = "", std::string tile = "");
int disperse_monsters(coord_def where, int pow);
void remove_condensation_shield();
diff --git a/crawl-ref/source/spl-util.cc b/crawl-ref/source/spl-util.cc
index 2f32ea67e1..75d7264e07 100644
--- a/crawl-ref/source/spl-util.cc
+++ b/crawl-ref/source/spl-util.cc
@@ -73,7 +73,8 @@ static struct spell_desc *_seekspell(spell_type spellid);
static bool _cloud_helper(cloud_func func, const coord_def& where,
int pow, int spread_rate,
cloud_type ctype, kill_category whose,
- killer_type killer);
+ killer_type killer, int colour,
+ std::string name, std::string tile);
//
// BEGIN PUBLIC FUNCTIONS
@@ -677,13 +678,14 @@ int apply_area_within_radius(cell_func cf, const coord_def& where,
void apply_area_cloud( cloud_func func, const coord_def& where,
int pow, int number, cloud_type ctype,
kill_category whose, killer_type killer,
- int spread_rate )
+ int spread_rate, int colour, std::string name,
+ std::string tile)
{
int good_squares = 0;
int neighbours[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
if (number && _cloud_helper(func, where, pow, spread_rate, ctype, whose,
- killer))
+ killer, colour, name, tile))
number--;
if (number == 0)
@@ -703,7 +705,8 @@ void apply_area_cloud( cloud_func func, const coord_def& where,
{
const int aux = arrs[m][i];
if ( _cloud_helper(func, where + Compass[aux],
- pow, spread_rate, ctype, whose, killer))
+ pow, spread_rate, ctype, whose, killer, colour,
+ name, tile))
{
number--;
good_squares++;
@@ -729,7 +732,7 @@ void apply_area_cloud( cloud_func func, const coord_def& where,
number -= spread;
good_squares--;
apply_area_cloud(func, where + Compass[j], pow, spread, ctype, whose,
- killer, spread_rate);
+ killer, spread_rate, colour, name, tile);
}
}
@@ -893,11 +896,13 @@ bool is_valid_spell(spell_type spell)
static bool _cloud_helper(cloud_func func, const coord_def& where,
int pow, int spread_rate,
cloud_type ctype, kill_category whose,
- killer_type killer)
+ killer_type killer, int colour, std::string name,
+ std::string tile)
{
if (!feat_is_solid(grd(where)) && env.cgrid(where) == EMPTY_CLOUD)
{
- func(where, pow, spread_rate, ctype, whose, killer);
+ func(where, pow, spread_rate, ctype, whose, killer, colour, name,
+ tile);
return (true);
}
diff --git a/crawl-ref/source/spl-util.h b/crawl-ref/source/spl-util.h
index 8ff8e4ceeb..eb44f4db07 100644
--- a/crawl-ref/source/spl-util.h
+++ b/crawl-ref/source/spl-util.h
@@ -80,7 +80,8 @@ const char* spelltype_long_name( int which_spelltype );
typedef int cell_func(coord_def where, int pow, int aux, actor *agent);
typedef int cloud_func(coord_def where, int pow, int spreadrate,
cloud_type type, kill_category whose,
- killer_type killer);
+ killer_type killer, int colour, std::string name,
+ std::string tile);
int apply_area_visible(cell_func cf, int power,
bool pass_through_trans = false, actor *agent = NULL);
@@ -104,7 +105,8 @@ int apply_area_within_radius(cell_func cf, const coord_def& where,
void apply_area_cloud(cloud_func func, const coord_def& where,
int pow, int number, cloud_type ctype,
kill_category kc, killer_type killer,
- int spread_rate = -1);
+ int spread_rate = -1, int colour = -1,
+ std::string name = "", std::string tile = "");
bool spell_direction( dist &spelld, bolt &pbolt,
targetting_type restrict = DIR_NONE,
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index ab60932b4f..6d12c323ab 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -61,6 +61,7 @@
#include "artefact.h"
#include "branch.h"
+#include "coordit.h"
#include "describe.h"
#include "dungeon.h"
#include "enum.h"
@@ -1802,6 +1803,9 @@ static void tag_construct_level(writer &th)
marshallByte(th, (char) env.cloud[i].spread_rate);
marshallByte(th, env.cloud[i].whose);
marshallByte(th, env.cloud[i].killer);
+ marshallShort(th, env.cloud[i].colour);
+ marshallString(th, env.cloud[i].name);
+ marshallString(th, env.cloud[i].tile);
}
// how many shops?
@@ -1825,6 +1829,15 @@ static void tag_construct_level(writer &th)
env.markers.write(th);
env.properties.write(th);
+
+ // Save heightmap, if present.
+ marshallByte(th, !!env.heightmap.get());
+ if (env.heightmap.get())
+ {
+ grid_heightmap &heightmap(*env.heightmap);
+ for (rectangle_iterator ri(0); ri; ++ri)
+ marshallShort(th, heightmap(*ri));
+ }
}
void marshallItem(writer &th, const item_def &item)
@@ -2191,6 +2204,9 @@ static void tag_read_level( reader &th, char minorVersion )
env.cloud[i].spread_rate = (unsigned char) unmarshallByte(th);
env.cloud[i].whose = static_cast<kill_category>(unmarshallByte(th));
env.cloud[i].killer = static_cast<killer_type>(unmarshallByte(th));
+ env.cloud[i].colour = unmarshallShort(th);
+ env.cloud[i].name = unmarshallString(th);
+ env.cloud[i].tile = unmarshallString(th);
}
// how many shops?
@@ -2217,6 +2233,17 @@ static void tag_read_level( reader &th, char minorVersion )
env.properties.clear();
env.properties.read(th);
+
+ // Restore heightmap
+ env.heightmap.reset(NULL);
+ const bool have_heightmap(unmarshallByte(th));
+ if (have_heightmap)
+ {
+ env.heightmap.reset(new grid_heightmap);
+ grid_heightmap &heightmap(*env.heightmap);
+ for (rectangle_iterator ri(0); ri; ++ri)
+ heightmap(*ri) = unmarshallShort(th);
+ }
}
static void tag_read_level_items(reader &th, char minorVersion)
diff --git a/crawl-ref/source/tags.h b/crawl-ref/source/tags.h
index 26ecf81233..f9c3959299 100644
--- a/crawl-ref/source/tags.h
+++ b/crawl-ref/source/tags.h
@@ -40,14 +40,14 @@ enum tag_file_type // file types supported by tag system
enum tag_major_version
{
TAG_MAJOR_START = 5,
- TAG_MAJOR_VERSION = 11
+ TAG_MAJOR_VERSION = 12
};
// Minor version will be reset to zero when major version changes.
enum tag_minor_version
{
- TAG_MINOR_RESET = 0, // Minor tags were reset
- TAG_MINOR_VERSION = 0 // Current version. (Keep equal to max.)
+ TAG_MINOR_RESET = 0, // Minor tags were reset
+ TAG_MINOR_VERSION = 0 // Current version. (Keep equal to max.)
};
struct enum_info
diff --git a/crawl-ref/source/terrain.cc b/crawl-ref/source/terrain.cc
index 05b3033e8e..9b2fe96deb 100644
--- a/crawl-ref/source/terrain.cc
+++ b/crawl-ref/source/terrain.cc
@@ -664,7 +664,7 @@ static void _dgn_check_terrain_items(const coord_def &pos, bool preserve_items)
item = mitm[item].link;
// Game-critical item.
- if (preserve_items || item_is_critical(mitm[curr]))
+ if (preserve_items || mitm[curr].is_critical())
_dgn_shift_item(pos, mitm[curr]);
else
{
diff --git a/crawl-ref/source/tilepick.cc b/crawl-ref/source/tilepick.cc
index 725947c13c..34cbf7eb7f 100644
--- a/crawl-ref/source/tilepick.cc
+++ b/crawl-ref/source/tilepick.cc
@@ -764,6 +764,8 @@ int tileidx_monster_base(const monsters *mon, bool detected)
return TILEP_MONS_GLOWING_SHAPESHIFTER;
case MONS_KILLER_KLOWN:
return TILEP_MONS_KILLER_KLOWN;
+ case MONS_SLAVE:
+ return TILEP_MONS_SLAVE;
// mimics
case MONS_GOLD_MIMIC:
@@ -2647,64 +2649,89 @@ int tileidx_feature(dungeon_feature_type feat, int gx, int gy)
}
}
-static int _tileidx_cloud(int type, int decay)
+static int _tileidx_cloud(cloud_struct cl)
{
+ int type = cl.type;
+ int decay = cl.decay;
+ std::string override = cl.tile;
+ int colour = cl.colour;
+
int ch = TILE_ERROR;
int dur = decay/20;
if (dur > 2)
dur = 2;
- switch (type)
+ if (!override.empty())
{
- case CLOUD_FIRE:
- ch = TILE_CLOUD_FIRE_0 + dur;
- break;
+ unsigned int index;
+ if (!tile_main_index(override.c_str(), index))
+ {
+ mprf(MSGCH_ERROR, "Invalid tile requested for cloud: '%s'.", override.c_str());
+ }
+ else
+ {
+ int offset = tile_main_count(index);
+ ch = index + offset;
+ }
+ }
+ else
+ {
+ switch (type)
+ {
+ case CLOUD_FIRE:
+ ch = TILE_CLOUD_FIRE_0 + dur;
+ break;
- case CLOUD_COLD:
- ch = TILE_CLOUD_COLD_0 + dur;
- break;
+ case CLOUD_COLD:
+ ch = TILE_CLOUD_COLD_0 + dur;
+ break;
- case CLOUD_STINK:
- case CLOUD_POISON:
- ch = TILE_CLOUD_POISON_0 + dur;
- break;
+ case CLOUD_STINK:
+ case CLOUD_POISON:
+ ch = TILE_CLOUD_POISON_0 + dur;
+ break;
- case CLOUD_BLUE_SMOKE:
- ch = TILE_CLOUD_BLUE_SMOKE;
- break;
+ case CLOUD_BLUE_SMOKE:
+ ch = TILE_CLOUD_BLUE_SMOKE;
+ break;
- case CLOUD_PURPLE_SMOKE:
- case CLOUD_TLOC_ENERGY:
- ch = TILE_CLOUD_TLOC_ENERGY;
- break;
+ case CLOUD_PURPLE_SMOKE:
+ case CLOUD_TLOC_ENERGY:
+ ch = TILE_CLOUD_TLOC_ENERGY;
+ break;
- case CLOUD_MIASMA:
- ch = TILE_CLOUD_MIASMA;
- break;
+ case CLOUD_MIASMA:
+ ch = TILE_CLOUD_MIASMA;
+ break;
- case CLOUD_BLACK_SMOKE:
- ch = TILE_CLOUD_BLACK_SMOKE;
- break;
+ case CLOUD_BLACK_SMOKE:
+ ch = TILE_CLOUD_BLACK_SMOKE;
+ break;
- case CLOUD_MUTAGENIC:
- ch = (dur == 0 ? TILE_CLOUD_MUTAGENIC_0 :
- dur == 1 ? TILE_CLOUD_MUTAGENIC_1
- : TILE_CLOUD_MUTAGENIC_2);
- ch += random2(tile_main_count(ch));
- break;
+ case CLOUD_MUTAGENIC:
+ ch = (dur == 0 ? TILE_CLOUD_MUTAGENIC_0 :
+ dur == 1 ? TILE_CLOUD_MUTAGENIC_1
+ : TILE_CLOUD_MUTAGENIC_2);
+ ch += random2(tile_main_count(ch));
+ break;
- case CLOUD_MIST:
- ch = TILE_CLOUD_MIST;
- break;
+ case CLOUD_MIST:
+ ch = TILE_CLOUD_MIST;
+ break;
- case CLOUD_RAIN:
- ch = TILE_CLOUD_RAIN + random2(tile_main_count(TILE_CLOUD_RAIN));
- break;
+ case CLOUD_RAIN:
+ ch = TILE_CLOUD_RAIN + random2(tile_main_count(TILE_CLOUD_RAIN));
+ break;
- default:
- ch = TILE_CLOUD_GREY_SMOKE;
- break;
+ default:
+ ch = TILE_CLOUD_GREY_SMOKE;
+ break;
+ }
}
+
+ if (colour != -1)
+ ch = tile_main_coloured(ch, colour);
+
return (ch | TILE_FLAG_FLYING);
}
@@ -4850,9 +4877,9 @@ void tile_place_monster(int gx, int gy, int idx, bool foreground, bool detected)
}
}
-void tile_place_cloud(int x, int y, int type, int decay)
+void tile_place_cloud(int x, int y, cloud_struct cl)
{
- env.tile_fg[x][y] = _tileidx_cloud(type, decay);
+ env.tile_fg[x][y] = _tileidx_cloud(cl);
}
unsigned int num_tile_rays = 0;
diff --git a/crawl-ref/source/tilereg.cc b/crawl-ref/source/tilereg.cc
index 753ea5be30..4490e3a59a 100644
--- a/crawl-ref/source/tilereg.cc
+++ b/crawl-ref/source/tilereg.cc
@@ -1541,10 +1541,8 @@ int DungeonRegion::handle_mouse(MouseEvent &event)
const int cloudidx = env.cgrid(gc);
if (cloudidx != EMPTY_CLOUD)
{
- cloud_type ctype = env.cloud[cloudidx].type;
-
std::string terrain_desc = desc;
- desc = cloud_name(ctype);
+ desc = cloud_name(cloudidx);
if (!terrain_desc.empty())
desc += "\n" + terrain_desc;
@@ -1937,9 +1935,7 @@ bool DungeonRegion::update_alt_text(std::string &alt)
const int cloudidx = env.cgrid(gc);
if (cloudidx != EMPTY_CLOUD)
{
- cloud_type ctype = env.cloud[cloudidx].type;
-
- inf.prefix = "There is a cloud of " + cloud_name(ctype)
+ inf.prefix = "There is a cloud of " + cloud_name(cloudidx)
+ " here.$$";
}
}
@@ -2488,7 +2484,7 @@ static bool _can_use_item(const item_def &item, bool equipped)
&& mons_has_blood(item.plus));
}
- if (equipped && item_cursed(item))
+ if (equipped && item.cursed())
{
// Misc. items/rods can always be evoked, cursed or not.
if (item.base_type == OBJ_MISCELLANY || item_is_rod(item))
@@ -2774,7 +2770,7 @@ bool InventoryRegion::update_tip_text(std::string& tip)
tip += "\n[R-Click] Info";
// Has to be non-equipped or non-cursed to drop.
if (!equipped || !_is_true_equipped_item(you.inv[idx])
- || !item_cursed(you.inv[idx]))
+ || !you.inv[idx].cursed())
{
tip += "\n[Shift-L-Click] Drop (d)";
}
diff --git a/crawl-ref/source/tiles.h b/crawl-ref/source/tiles.h
index d938715e55..2f1028b72d 100644
--- a/crawl-ref/source/tiles.h
+++ b/crawl-ref/source/tiles.h
@@ -74,7 +74,7 @@ void tile_place_monster(int gx, int gy, int idx, bool foreground = true,
bool detected = false);
void tile_place_item(int x, int y, int idx);
void tile_place_item_marker(int x, int y, int idx);
-void tile_place_cloud(int x, int y, int type, int decay);
+void tile_place_cloud(int x, int y, cloud_struct cl);
void tile_place_ray(const coord_def& gc, bool in_range);
void tile_draw_rays(bool resetCount);
void tile_clear_buf();
diff --git a/crawl-ref/source/tilesdl.cc b/crawl-ref/source/tilesdl.cc
index e3c1e978fd..50dbb83f58 100644
--- a/crawl-ref/source/tilesdl.cc
+++ b/crawl-ref/source/tilesdl.cc
@@ -1433,7 +1433,7 @@ static void _fill_item_info(InventoryTile &desc, const item_def &item)
desc.special = tile_known_weapon_brand(item);
desc.flag = 0;
- if (item_cursed(item) && item_ident(item, ISFLAG_KNOW_CURSE))
+ if (item.cursed() && item_ident(item, ISFLAG_KNOW_CURSE))
desc.flag |= TILEI_FLAG_CURSE;
if (item_type_tried(item))
desc.flag |= TILEI_FLAG_TRIED;
diff --git a/crawl-ref/source/transfor.cc b/crawl-ref/source/transfor.cc
index 39f932a5eb..eaa1d12afb 100644
--- a/crawl-ref/source/transfor.cc
+++ b/crawl-ref/source/transfor.cc
@@ -311,7 +311,7 @@ static bool _check_for_cursed_equipment(const std::set<equipment_type> &remove,
continue;
const item_def& item = you.inv[ you.equip[e] ];
- if (item_cursed(item))
+ if (item.cursed())
{
if (e != EQ_WEAPON && _tran_may_meld_cursed(trans))
continue;
diff --git a/crawl-ref/source/trap_def.h b/crawl-ref/source/trap_def.h
index 90c2cc4372..2ec924d3b4 100644
--- a/crawl-ref/source/trap_def.h
+++ b/crawl-ref/source/trap_def.h
@@ -18,6 +18,7 @@ struct trap_def
void prepare_ammo();
bool type_has_ammo() const;
bool active() const;
+ int max_damage(const actor& act);
private:
void message_trap_entry();
diff --git a/crawl-ref/source/traps.cc b/crawl-ref/source/traps.cc
index e8b8d92bce..b7ca9f2dec 100644
--- a/crawl-ref/source/traps.cc
+++ b/crawl-ref/source/traps.cc
@@ -677,41 +677,41 @@ void trap_def::trigger(actor& triggerer, bool flat_footed)
this->destroy();
}
-int trap_def::shot_damage(actor& act)
+int trap_def::max_damage(const actor& act)
{
- if (act.atype() == ACT_PLAYER)
- {
- switch (this->type)
- {
- case TRAP_NEEDLE: return 0;
- case TRAP_DART: return random2( 4 + you.your_level/2) + 1;
- case TRAP_ARROW: return random2( 7 + you.your_level) + 1;
- case TRAP_SPEAR: return random2(10 + you.your_level) + 1;
- case TRAP_BOLT: return random2(13 + you.your_level) + 1;
- case TRAP_AXE: return random2(15 + you.your_level) + 1;
- default: return 0;
- }
- }
- else if (act.atype() == ACT_MONSTER)
+ int level = you.your_level;
+
+ // Trap damage to monsters is not a function of level, because
+ // they are fairly stupid and tend to have fewer hp than
+ // players -- this choice prevents traps from easily killing
+ // large monsters fairly deep within the dungeon.
+ if (act.atype() == ACT_MONSTER)
+ level = 0;
+
+ switch (this->type)
{
- // Trap damage to monsters is not a function of level, because
- // they are fairly stupid and tend to have fewer hp than
- // players -- this choice prevents traps from easily killing
- // large monsters fairly deep within the dungeon.
- switch (this->type)
- {
- case TRAP_NEEDLE: return 0;
- case TRAP_DART: return random2( 4) + 1;
- case TRAP_ARROW: return random2( 7) + 1;
- case TRAP_SPEAR: return random2(10) + 1;
- case TRAP_BOLT: return random2(13) + 1;
- case TRAP_AXE: return random2(15) + 1;
- default: return 0;
- }
+ case TRAP_NEEDLE: return 0;
+ case TRAP_DART: return 4 + level/2;
+ case TRAP_ARROW: return 7 + level;
+ case TRAP_SPEAR: return 10 + level;
+ case TRAP_BOLT: return 13 + level;
+ case TRAP_AXE: return 15 + level;
+ case TRAP_BLADE: return (level ? 2*level : 10) + 28;
+ default: return 0;
}
+
return (0);
}
+int trap_def::shot_damage(actor& act)
+{
+ const int dam = max_damage(act);
+
+ if (!dam)
+ return 0;
+ return random2(dam) + 1;
+}
+
int reveal_traps(const int range)
{
int traps_found = 0;
@@ -756,6 +756,15 @@ trap_type get_trap_type(const coord_def& pos)
return (TRAP_UNASSIGNED);
}
+static bool _disarm_is_deadly(trap_def& trap)
+{
+ int dam = trap.max_damage(you);
+ if (trap.type == TRAP_NEEDLE && you.res_poison() <= 0)
+ dam += 15; // arbitrary
+
+ return (you.hp <= dam);
+}
+
// where *must* point to a valid, discovered trap.
void disarm_trap(const coord_def& where)
{
@@ -780,11 +789,8 @@ void disarm_trap(const coord_def& where)
break;
}
-#ifdef CLUA_BINDINGS
// Prompt for any trap for which you might not survive setting it off.
- // (See trapwalk.lua)
- if (Options.trap_prompt
- && !clua.callbooleanfn(false, "ch_cross_trap", "s", trap_name(where)))
+ if (_disarm_is_deadly(trap))
{
std::string prompt = make_stringf(
"Really try disarming that %s?",
@@ -799,7 +805,6 @@ void disarm_trap(const coord_def& where)
return;
}
}
-#endif
// Make the actual attempt
you.turn_is_over = true;
diff --git a/crawl-ref/source/tutorial.cc b/crawl-ref/source/tutorial.cc
index 6893f64262..69aeb760a2 100644
--- a/crawl-ref/source/tutorial.cc
+++ b/crawl-ref/source/tutorial.cc
@@ -1549,7 +1549,7 @@ static bool _cant_butcher()
if (!wpn || wpn->base_type != OBJ_WEAPONS)
return false;
- return (item_cursed(*wpn) && !can_cut_meat(*wpn));
+ return (wpn->cursed() && !can_cut_meat(*wpn));
}
static int _num_butchery_tools()
@@ -3012,7 +3012,7 @@ void learned_something_new(tutorial_event_type seen_what, coord_def gc)
int wpn = you.equip[EQ_WEAPON];
if (wpn != -1
&& you.inv[wpn].base_type == OBJ_WEAPONS
- && item_cursed(you.inv[wpn]))
+ && you.inv[wpn].cursed())
{
// Don't trigger if the wielded weapon is cursed.
Tutorial.tutorial_events[seen_what] = true;
@@ -4440,7 +4440,7 @@ static void _tutorial_describe_cloud(int x, int y)
if (ctype == CLOUD_NONE)
return;
- std::string cname = cloud_name(ctype);
+ std::string cname = cloud_name(env.cgrid(coord_def(x, y)));
std::ostringstream ostr;
diff --git a/crawl-ref/source/viewchar.cc b/crawl-ref/source/viewchar.cc
index 78818642bd..bf0460591c 100644
--- a/crawl-ref/source/viewchar.cc
+++ b/crawl-ref/source/viewchar.cc
@@ -24,27 +24,35 @@ static const unsigned dchar_table[ NUM_CSET ][ NUM_DCHAR_TYPES ] =
177, 176, 249, 250, '\'', 254, '^', '>', '<', // wall .. stairs up
220, 239, 244, 247, '8', '~', '~', // altar .. item detect
'0', ')', '[', '/', '%', '?', '=', '!', '(', // orb .. missile
- '+', '\\', '}', '%', '$', '"', '#', 234, // book .. trees
+ 236, '\\', '}', '%', '$', '"', '#', 234, // book .. trees
' ', '!', '#', '%', '+', ')', '*', '+', // space .. fired_burst
'/', '=', '?', 'X', '[', '`', '#' // fi_stick .. explosion
},
// CSET_DEC - remember: 224-255 are mapped to shifted 96-127
+ // It's better known as "vt100 line drawing characters".
{
225, 224, 254, ':', '\'', 238, '^', '>', '<', // wall .. stairs up
251, 182, 167, 187, '8', 171, 168, // altar .. item detect
'0', ')', '[', '/', '%', '?', '=', '!', '(', // orb .. missile
- '+', '\\', '}', '%', '$', '"', '#', '7', // book .. trees
+ ':', '\\', '}', '%', '$', '"', '#', '7', // book .. trees
' ', '!', '#', '%', '+', ')', '*', '+', // space .. fired_burst
'/', '=', '?', 'X', '[', '`', '#' // fi_stick .. explosion
},
// CSET_UNICODE
+ /* Beware, some popular terminals (PuTTY, xterm) are incapable of coping with
+ the lack of a character in the chosen font, and most popular fonts have a
+ quite limited repertoire. A subset that is reasonably likely to be present
+ is http://en.wikipedia.org/wiki/WGL4; we could provide a richer alternate
+ set for those on more capable terminals (including for example Thai 0xEB0
+ for clouds), but that would require decoupling encoding from charset.
+ */
{
0x2592, 0x2591, 0xB7, 0x25E6, '\'', 0x25FC, '^', '>', '<',
'_', 0x2229, 0x2320, 0x2248, '8', '~', '~',
'0', ')', '[', '/', '%', '?', '=', '!', '(',
- '+', '|', '}', '%', '$', '"', '#', 0x2663,
+ 0x221E, '|', '}', '%', '$', '"', '#', 0x2663,
' ', '!', '#', '%', '+', ')', '*', '+', // space .. fired_burst
'/', '=', '?', 'X', '[', '`', '#' // fi_stick .. explosion
},
diff --git a/crawl-ref/source/wiz-dgn.cc b/crawl-ref/source/wiz-dgn.cc
index ea55dc9e56..8251e6c76e 100644
--- a/crawl-ref/source/wiz-dgn.cc
+++ b/crawl-ref/source/wiz-dgn.cc
@@ -269,70 +269,53 @@ void wizard_create_portal()
}
}
-void wizard_create_feature_number()
+void wizard_create_feature()
{
char specs[256];
int feat_num;
- mpr("Create which feature (by number)? ", MSGCH_PROMPT);
+ dungeon_feature_type feat;
+ mpr("Create which feature? ", MSGCH_PROMPT);
- if (!cancelable_get_line(specs, sizeof(specs))
- && (feat_num = atoi(specs)))
+ if (!cancelable_get_line(specs, sizeof(specs)) && specs[0] != 0)
{
- dungeon_feature_type feat = static_cast<dungeon_feature_type>(feat_num);
- if (feat == DNGN_ENTER_SHOP)
+ if ((feat_num = atoi(specs)))
{
- debug_make_shop();
- return;
+ feat = static_cast<dungeon_feature_type>(feat_num);
}
-
- dungeon_terrain_changed(you.pos(), feat, false);
-#ifdef USE_TILE
- env.tile_flv(you.pos()).special = 0;
-#endif
- }
- else
- canned_msg(MSG_OK);
-}
-
-void wizard_create_feature_name()
-{
- char specs[256];
- mpr("Create which feature (by name)? ", MSGCH_PROMPT);
- if (!cancelable_get_line(specs, sizeof(specs)) && specs[0] != 0)
- {
- // Accept both "shallow_water" and "Shallow water"
- std::string name = lowercase_string(specs);
- name = replace_all(name, " ", "_");
-
- dungeon_feature_type feat = dungeon_feature_by_name(name);
- if (feat == DNGN_UNSEEN) // no exact match
+ else
{
- std::vector<std::string> matches = dungeon_feature_matches(name);
-
- if (matches.empty())
+ std::string name = lowercase_string(specs);
+ name = replace_all(name, " ", "_");
+ feat = dungeon_feature_by_name(name);
+ if (feat == DNGN_UNSEEN) // no exact match
{
- mprf(MSGCH_DIAGNOSTICS, "No features matching '%s'",
- name.c_str());
- return;
- }
+ std::vector<std::string> matches = dungeon_feature_matches(name);
- // Only one possible match, use that.
- if (matches.size() == 1)
- {
- name = matches[0];
- feat = dungeon_feature_by_name(name);
- }
- // Multiple matches, list them to wizard
- else
- {
- std::string prefix = "No exact match for feature '" +
- name + "', possible matches are: ";
+ if (matches.empty())
+ {
+ mprf(MSGCH_DIAGNOSTICS, "No features matching '%s'",
+ name.c_str());
+ return;
+ }
- // Use mpr_comma_separated_list() because the list
- // might be *LONG*.
- mpr_comma_separated_list(prefix, matches, " and ", ", ",
- MSGCH_DIAGNOSTICS);
- return;
+ // Only one possible match, use that.
+ if (matches.size() == 1)
+ {
+ name = matches[0];
+ feat = dungeon_feature_by_name(name);
+ }
+ // Multiple matches, list them to wizard
+ else
+ {
+ std::string prefix = "No exact match for feature '" +
+ name + "', possible matches are: ";
+
+ // Use mpr_comma_separated_list() because the list
+ // might be *LONG*.
+ mpr_comma_separated_list(prefix, matches, " and ", ", ",
+ MSGCH_DIAGNOSTICS);
+ return;
+ }
}
}
@@ -342,8 +325,6 @@ void wizard_create_feature_name()
return;
}
- mprf(MSGCH_DIAGNOSTICS, "Setting (%d,%d) to %s (%d)",
- you.pos().x, you.pos().y, name.c_str(), feat);
dungeon_terrain_changed(you.pos(), feat, false);
#ifdef USE_TILE
env.tile_flv(you.pos()).special = 0;
diff --git a/crawl-ref/source/wiz-dgn.h b/crawl-ref/source/wiz-dgn.h
index c8561dcb1f..3db62ceb1b 100644
--- a/crawl-ref/source/wiz-dgn.h
+++ b/crawl-ref/source/wiz-dgn.h
@@ -10,8 +10,7 @@
#include <string>
void wizard_create_portal();
-void wizard_create_feature_number();
-void wizard_create_feature_name();
+void wizard_create_feature();
void wizard_list_branches();
void wizard_reveal_traps();
void wizard_map_level();
diff --git a/crawl-ref/source/wiz-item.cc b/crawl-ref/source/wiz-item.cc
index b4b94bb94f..6fa4b411b0 100644
--- a/crawl-ref/source/wiz-item.cc
+++ b/crawl-ref/source/wiz-item.cc
@@ -697,7 +697,7 @@ void wizard_uncurse_item()
{
item_def& item(you.inv[i]);
- if (item_cursed(item))
+ if (item.cursed())
do_uncurse_item(item);
else if (_item_type_can_be_cursed(item.base_type))
do_curse_item(item);
diff --git a/crawl-ref/source/xom.cc b/crawl-ref/source/xom.cc
index a2c7a4d227..4f01f1145a 100644
--- a/crawl-ref/source/xom.cc
+++ b/crawl-ref/source/xom.cc
@@ -2308,7 +2308,7 @@ static void _xom_zero_miscast()
{
const item_def &item(you.inv[i]);
if (item.is_valid() && !item_is_equipped(item)
- && !item_is_critical(item))
+ && !item.is_critical())
{
inv_items.push_back(i);
}