summaryrefslogtreecommitdiffstats
path: root/crawl-ref
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref')
-rw-r--r--crawl-ref/source/cloud.cc36
-rw-r--r--crawl-ref/source/cloud.h4
-rw-r--r--crawl-ref/source/dat/clua/lm_fog.lua163
-rw-r--r--crawl-ref/source/dat/clua/luamark.lua1
-rw-r--r--crawl-ref/source/dgnevent.h11
-rw-r--r--crawl-ref/source/externs.h1
-rw-r--r--crawl-ref/source/files.cc2
-rw-r--r--crawl-ref/source/luadgn.cc210
-rw-r--r--crawl-ref/source/spells1.cc4
-rw-r--r--crawl-ref/source/spells1.h2
-rw-r--r--crawl-ref/source/spells4.cc6
-rw-r--r--crawl-ref/source/spells4.h4
-rw-r--r--crawl-ref/source/spl-util.cc84
-rw-r--r--crawl-ref/source/spl-util.h5
-rw-r--r--crawl-ref/source/tags.cc2
15 files changed, 471 insertions, 64 deletions
diff --git a/crawl-ref/source/cloud.cc b/crawl-ref/source/cloud.cc
index 05c5dcaa70..65128cf79d 100644
--- a/crawl-ref/source/cloud.cc
+++ b/crawl-ref/source/cloud.cc
@@ -20,21 +20,24 @@
#include "terrain.h"
// Returns true if this cloud spreads out as it dissipates.
-static bool cloud_spreads(const cloud_struct &cloud)
+static unsigned char actual_spread_rate(cloud_type type, int spread_rate)
{
- switch (cloud.type)
+ if (spread_rate > 0)
+ return (unsigned char) spread_rate;
+
+ switch (type)
{
case CLOUD_STEAM:
case CLOUD_GREY_SMOKE:
case CLOUD_BLACK_SMOKE:
- return (true);
+ return 20;
default:
- return (false);
+ return 0;
}
}
static void new_cloud( int cloud, cloud_type type, int x, int y, int decay,
- kill_category whose )
+ kill_category whose, unsigned char spread_rate )
{
ASSERT( env.cloud[ cloud ].type == CLOUD_NONE );
@@ -43,12 +46,13 @@ static void new_cloud( int cloud, cloud_type type, int x, int y, int decay,
env.cloud[ cloud ].x = x;
env.cloud[ cloud ].y = y;
env.cloud[ cloud ].whose = whose;
+ env.cloud[ cloud ].spread_rate = spread_rate;
env.cgrid[ x ][ y ] = cloud;
env.cloud_no++;
}
static void place_new_cloud(cloud_type cltype, int x, int y, int decay,
- kill_category whose)
+ kill_category whose, int spread_rate)
{
if (env.cloud_no >= MAX_CLOUDS)
return;
@@ -58,7 +62,7 @@ static void place_new_cloud(cloud_type cltype, int x, int y, int decay,
{
if (env.cloud[ci].type == CLOUD_NONE) // ie is empty
{
- new_cloud( ci, cltype, x, y, decay, whose );
+ new_cloud( ci, cltype, x, y, decay, whose, spread_rate );
break;
}
}
@@ -90,7 +94,8 @@ static int spread_cloud(const cloud_struct &cloud)
if (newdecay >= cloud.decay)
newdecay = cloud.decay - 1;
- place_new_cloud( cloud.type, x, y, newdecay, cloud.whose );
+ place_new_cloud( cloud.type, x, y, newdecay, cloud.whose,
+ cloud.spread_rate );
extra_decay += 8;
}
@@ -104,7 +109,7 @@ static void dissipate_cloud(int cc, cloud_struct &cloud, int dissipate)
// apply calculated rate to the actual cloud:
cloud.decay -= dissipate;
- if (cloud_spreads(cloud) && cloud.decay > 10 && one_chance_in(5))
+ if (random2(100) < cloud.spread_rate)
cloud.decay -= spread_cloud(cloud);
// check for total dissipation and handle accordingly:
@@ -159,6 +164,7 @@ void delete_cloud( int cloud )
env.cloud[ cloud ].x = 0;
env.cloud[ cloud ].y = 0;
env.cloud[ cloud ].whose = KC_OTHER;
+ env.cloud[ cloud ].spread_rate = 0;
env.cgrid[ cloud_x ][ cloud_y ] = EMPTY_CLOUD;
env.cloud_no--;
}
@@ -183,12 +189,12 @@ void move_cloud( int cloud, int new_x, int new_y )
// Places a cloud with the given stats assuming one doesn't already
// exist at that point.
void check_place_cloud( cloud_type cl_type, int x, int y, int lifetime,
- kill_category whose )
+ kill_category whose, int spread_rate )
{
if (!in_bounds(x, y) || env.cgrid[x][y] != EMPTY_CLOUD)
return;
- place_cloud( cl_type, x, y, lifetime, whose );
+ place_cloud( cl_type, x, y, lifetime, whose, spread_rate );
}
int steam_cloud_damage(const cloud_struct &cloud)
@@ -208,7 +214,7 @@ int steam_cloud_damage(const cloud_struct &cloud)
// cloud under some circumstances.
void place_cloud(cloud_type cl_type, int ctarget_x,
int ctarget_y, int cl_range,
- kill_category whose)
+ kill_category whose, int _spread_rate)
{
int cl_new = -1;
@@ -234,6 +240,8 @@ void place_cloud(cloud_type cl_type, int ctarget_x,
}
}
+ unsigned char spread_rate = actual_spread_rate( cl_type, _spread_rate );
+
// too many clouds
if (env.cloud_no >= MAX_CLOUDS)
{
@@ -261,7 +269,7 @@ void place_cloud(cloud_type cl_type, int ctarget_x,
// create new cloud
if (cl_new != -1)
new_cloud( cl_new, cl_type, ctarget_x, ctarget_y, cl_range * 10,
- whose );
+ whose, spread_rate );
else
{
// find slot for cloud
@@ -270,7 +278,7 @@ void place_cloud(cloud_type cl_type, int ctarget_x,
if (env.cloud[ci].type == CLOUD_NONE) // ie is empty
{
new_cloud( ci, cl_type, ctarget_x, ctarget_y, cl_range * 10,
- whose );
+ whose, spread_rate );
break;
}
}
diff --git a/crawl-ref/source/cloud.h b/crawl-ref/source/cloud.h
index be7502d6a0..e0d02d27ed 100644
--- a/crawl-ref/source/cloud.h
+++ b/crawl-ref/source/cloud.h
@@ -20,9 +20,9 @@ void delete_cloud( int cloud );
void move_cloud( int cloud, int new_x, int new_y );
void check_place_cloud( cloud_type cl_type, int x, int y, int lifetime,
- kill_category whose );
+ kill_category whose, int spread_rate = -1 );
void place_cloud(cloud_type cl_type, int ctarget_x, int ctarget_y,
- int cl_range, kill_category whose);
+ int cl_range, kill_category whose, int spread_rate = -1 );
void manage_clouds(void);
diff --git a/crawl-ref/source/dat/clua/lm_fog.lua b/crawl-ref/source/dat/clua/lm_fog.lua
new file mode 100644
index 0000000000..62853cb9b7
--- /dev/null
+++ b/crawl-ref/source/dat/clua/lm_fog.lua
@@ -0,0 +1,163 @@
+------------------------------------------------------------------------------
+-- lm_tmsg.lua:
+-- Fog machines.
+--
+-- There are three different "pure" ways to use a fog machine marker:
+--
+-- 1) Repeatedly lay down medium to large clouds on top of the marker
+-- and let them pile up on one another. (One of the cloud grids in
+-- the gfirst laid cloud has to decay away before this is this really
+-- starts working.
+--
+-- 2) Perform random walks from the marker and place a single-grid cloud
+-- at the destination of each walk.
+--
+-- 3) Place a single-grid cloud on the marker and let it spread out.
+--
+-- Comibining these different methods, along with varying the differrent
+-- parameters, can be used to achieve different effects.
+--
+-- Marker parameters:
+--
+-- cloud_type: The name of the cloud type to use. Defaults to "thin mist".
+-- walk_dist: The distance to move over the course of one random walk.
+-- defaults to 0.
+-- pow_min: The minimum "power" (lifetime) of each cloud; defaults to 1.
+-- pow_max: The maximum power of each cloud; must be provided.
+-- pow_rolls: The number of rolls of [pow_min, pow_max], with the average
+-- value uses; increasing the values makes the average value more likely
+-- and exterme values less likely. Defaults to 1.
+-- delay, delay_min and delay_max: The delay between laying down one cloud
+-- and the next. 10 is equal to normal-speed player turn. Either
+-- delay or delay_max and delay_min must be provided. Providing just
+-- "delay" is equivalent to delay_min and delay_max being equal.
+-- size, size_min and size_max: The number of grids each cloud will cover.
+-- Either size or size_max and size_min must be provided. Providing
+-- just "size" is equivalent to size_min and size_max being equal.
+-- spread_rate: The rate at which a cloud spreads. Must either be
+-- -1 (default spread rate that varies by cloud type) or between
+-- 0 and 100 inclusive.
+-- 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.
+------------------------------------------------------------------------------
+
+FogMachine = { }
+FogMachine.__index = FogMachine
+
+function FogMachine:_new()
+ local m = { }
+ setmetatable(m, self)
+ self.__index = self
+ return m
+end
+
+function FogMachine:new(pars)
+ if not pars then
+ error("No parameters provided")
+ end
+
+ if not pars.pow_max then
+ error("No pow_max provided.")
+ end
+
+ if not (pars.delay or (pars.delay_min and pars.delay_max)) then
+ error("Delay parameters not provided.")
+ end
+
+ if not (pars.size or (pars.size_min and pars.size_max)) then
+ error("Size parameters not provided.")
+ end
+
+ local m = FogMachine:_new()
+ m.cloud_type = pars.cloud_type or "thin mist"
+ m.walk_dist = pars.walk_dist or 0
+ m.pow_min = pars.pow_min or 1
+ m.pow_max = pars.pow_max
+ m.pow_rolls = pars.pow_rolls or 3
+ m.delay_min = pars.delay_min or pars.delay or 1
+ m.delay_max = pars.delay_max or pars.delay
+ m.kill_cat = pars.kill_cat or "other"
+ m.size_min = pars.size_min or pars.size or 1
+ 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.countdown = 0
+
+ return m
+end
+
+function FogMachine:do_fog(marker)
+ local x, y = marker:pos()
+ if self.walk_dist > 0 then
+ x, y = dgn.random_walk(x, y, self.walk_dist)
+ end
+
+ dgn.apply_area_cloud(x, y, self.pow_min, self.pow_max, self.pow_rolls,
+ crawl.random_range(self.size_min, self.size_max, 1),
+ self.cloud_type, self.kill_cat, self.spread_rate)
+end
+
+function FogMachine:activate(marker, verbose)
+ local _x, _y = marker:pos()
+ dgn.register_listener(dgn.dgn_event_type('turn'), marker)
+ dgn.register_listener(dgn.dgn_event_type('entered_level'), marker)
+end
+
+function FogMachine:event(marker, ev)
+ local _x, _y = marker:pos()
+ if ev:type() == dgn.dgn_event_type('turn') then
+ self.countdown = self.countdown - ev:ticks()
+
+ while self.countdown <= 0 do
+ self:do_fog(marker)
+ self.countdown = self.countdown +
+ crawl.random_range(self.delay_min, self.delay_max, 1)
+ end
+ elseif ev:type() == dgn.dgn_event_type('entered_level') then
+ for i = 1, self.start_clouds do
+ self:do_fog(marker)
+ self.countdown = crawl.random_range(self.delay_min, self.delay_max, 1)
+ end
+ end
+end
+
+function FogMachine:write(marker, th)
+ file.marshall(th, self.cloud_type)
+ file.marshall(th, self.walk_dist)
+ file.marshall(th, self.pow_min)
+ file.marshall(th, self.pow_max)
+ file.marshall(th, self.pow_rolls)
+ file.marshall(th, self.delay_min)
+ file.marshall(th, self.delay_max)
+ file.marshall(th, self.kill_cat)
+ file.marshall(th, self.size_min)
+ file.marshall(th, self.size_max)
+ file.marshall(th, self.spread_rate)
+ file.marshall(th, self.start_clouds)
+ file.marshall(th, self.countdown)
+end
+
+function FogMachine:read(marker, th)
+ self.cloud_type = file.unmarshall_string(th)
+ self.walk_dist = file.unmarshall_number(th)
+ self.pow_min = file.unmarshall_number(th)
+ self.pow_max = file.unmarshall_number(th)
+ self.pow_rolls = file.unmarshall_number(th)
+ self.delay_min = file.unmarshall_number(th)
+ self.delay_max = file.unmarshall_number(th)
+ self.kill_cat = file.unmarshall_string(th)
+ self.size_min = file.unmarshall_number(th)
+ self.size_max = file.unmarshall_number(th)
+ self.spread_rate = file.unmarshall_number(th)
+ self.start_clouds = file.unmarshall_number(th)
+ self.countdown = file.unmarshall_number(th)
+
+ setmetatable(self, FogMachine)
+
+ return self
+end
+
+function fog_machine(pars)
+ return FogMachine:new(pars)
+end
diff --git a/crawl-ref/source/dat/clua/luamark.lua b/crawl-ref/source/dat/clua/luamark.lua
index 0c29327ab5..cc677f18c1 100644
--- a/crawl-ref/source/dat/clua/luamark.lua
+++ b/crawl-ref/source/dat/clua/luamark.lua
@@ -7,6 +7,7 @@ dofile('clua/lm_pdesc.lua')
dofile('clua/lm_1way.lua')
dofile('clua/lm_timed.lua')
dofile('clua/lm_flags.lua')
+dofile('clua/lm_fog.lua')
function dlua_marker_function(table, name)
return table[name]
diff --git a/crawl-ref/source/dgnevent.h b/crawl-ref/source/dgnevent.h
index bc394cab77..3ccd1d0246 100644
--- a/crawl-ref/source/dgnevent.h
+++ b/crawl-ref/source/dgnevent.h
@@ -22,11 +22,12 @@ enum dgn_event_type
DET_PLAYER_MOVED = 0x0004,
DET_LEAVING_LEVEL = 0x0008,
DET_ENTERING_LEVEL = 0x0010,
- DET_PLAYER_IN_LOS = 0x0020, // Player just entered LOS.
- DET_PLAYER_CLIMBS = 0x0040, // Player climbing stairs.
- DET_MONSTER_DIED = 0x0080,
- DET_ITEM_PICKUP = 0x0100,
- DET_FEAT_CHANGE = 0x0200
+ DET_ENTERED_LEVEL = 0x0020,
+ DET_PLAYER_IN_LOS = 0x0040, // Player just entered LOS.
+ DET_PLAYER_CLIMBS = 0x0080, // Player climbing stairs.
+ DET_MONSTER_DIED = 0x0100,
+ DET_ITEM_PICKUP = 0x0200,
+ DET_FEAT_CHANGE = 0x0400
};
class dgn_event
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index ec7ea1cd49..7fc2a7870a 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -1167,6 +1167,7 @@ struct cloud_struct
int y;
cloud_type type;
int decay;
+ unsigned char spread_rate;
kill_category whose;
};
diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc
index 15b693fbf9..303b16707d 100644
--- a/crawl-ref/source/files.cc
+++ b/crawl-ref/source/files.cc
@@ -1068,6 +1068,8 @@ bool load( dungeon_feature_type stair_taken, int load_mode,
if (just_created_level)
you.attribute[ATTR_ABYSS_ENTOURAGE] = 0;
+ dungeon_events.fire_event(DET_ENTERED_LEVEL);
+
return just_created_level;
} // end load()
diff --git a/crawl-ref/source/luadgn.cc b/crawl-ref/source/luadgn.cc
index e1c60b05b5..bb76ad0a4a 100644
--- a/crawl-ref/source/luadgn.cc
+++ b/crawl-ref/source/luadgn.cc
@@ -11,6 +11,7 @@
#include "branch.h"
#include "clua.h"
+#include "cloud.h"
#include "direct.h"
#include "dungeon.h"
#include "files.h"
@@ -20,6 +21,8 @@
#include "mapdef.h"
#include "mapmark.h"
#include "maps.h"
+#include "misc.h"
+#include "spl-util.h"
#include "stuff.h"
#include "tags.h"
#include "terrain.h"
@@ -1159,9 +1162,9 @@ static int dgn_feature_name(lua_State *ls)
static const char *dgn_event_type_names[] =
{
- "none", "turn", "mons_move", "player_move", "leave_level", "enter_level",
- "player_los", "player_climb", "monster_dies", "item_pickup",
- "feat_change"
+ "none", "turn", "mons_move", "player_move", "leave_level",
+ "entering_level", "entered_level", "player_los", "player_climb",
+ "monster_dies", "item_pickup", "feat_change"
};
static dgn_event_type dgn_event_type_by_name(const std::string &name)
@@ -1453,6 +1456,205 @@ static int dgn_floor_halo(lua_State *ls)
return (0);
}
+#define SQRT_2 1.41421356237309504880
+
+static int dgn_random_walk(lua_State *ls)
+{
+ const int x = luaL_checkint(ls, 1);
+ const int y = luaL_checkint(ls, 2);
+ const int dist = luaL_checkint(ls, 3);
+
+ // Fourth param being true means that we can move past
+ // statues.
+ const dungeon_feature_type minmove =
+ lua_isnil(ls, 4) ? DNGN_MINMOVE : DNGN_ORCISH_IDOL;
+
+ if (!in_bounds(x, y))
+ {
+ char buf[80];
+ sprintf(buf, "Point (%d,%d) isn't in bounds.", x, y);
+ luaL_argerror(ls, 1, buf);
+ return (0);
+ }
+ if (dist < 1)
+ {
+ luaL_argerror(ls, 3, "Distance must be positive.");
+ return (0);
+ }
+
+ float dist_left = dist;
+ // Allow movement to all 8 adjacent squares if distance is 1
+ // (needed since diagonal moves are distance sqrt(2))
+ if (dist == 1)
+ dist_left = SQRT_2;
+
+ int moves_left = dist;
+ coord_def pos(x, y);
+ while (dist_left >= 1.0 && moves_left-- > 0)
+ {
+ int okay_dirs = 0;
+ int dir = -1;
+ for (int j = 0; j < 8; j++)
+ {
+ const coord_def new_pos = pos + Compass[j];
+ const float move_dist = (j % 2 == 0) ? 1.0 : SQRT_2;
+
+ if (in_bounds(new_pos) && grd(new_pos) >= minmove
+ && move_dist <= dist_left)
+ {
+ if (one_chance_in(++okay_dirs))
+ dir = j;
+ }
+ }
+
+ if (okay_dirs == 0)
+ break;
+
+ if (one_chance_in(++okay_dirs))
+ continue;
+
+ pos += Compass[dir];
+ dist_left -= (dir % 2 == 0) ? 1.0 : SQRT_2;
+ }
+
+ dlua_push_coord(ls, pos);
+
+ return (2);
+}
+
+static cloud_type dgn_cloud_name_to_type(std::string name)
+{
+ lowercase(name);
+
+ if (name == "random")
+ return (CLOUD_RANDOM);
+ else if (name == "debugging")
+ return (CLOUD_DEBUGGING);
+
+ for (int i = CLOUD_NONE; i < CLOUD_RANDOM; i++)
+ if (cloud_name(static_cast<cloud_type>(i)) == name)
+ return static_cast<cloud_type>(i);
+
+ return (CLOUD_NONE);
+}
+
+static kill_category dgn_kill_name_to_category(std::string name)
+{
+ if (name == "")
+ return KC_OTHER;
+
+ lowercase(name);
+
+ if (name == "you")
+ return KC_YOU;
+ else if (name == "friendly")
+ return KC_FRIENDLY;
+ else if (name == "other")
+ return KC_OTHER;
+ else
+ return KC_NCATEGORIES;
+}
+
+static int lua_cloud_pow_min;
+static int lua_cloud_pow_max;
+static int lua_cloud_pow_rolls;
+
+static int make_a_lua_cloud(int x, int y, int garbage, int spread_rate,
+ cloud_type ctype, kill_category whose)
+{
+ UNUSED( garbage );
+ const int pow = random_range(lua_cloud_pow_min,
+ lua_cloud_pow_max,
+ lua_cloud_pow_rolls);
+ place_cloud( ctype, x, y, pow, whose, spread_rate );
+
+ return 1;
+}
+
+static int dgn_apply_area_cloud(lua_State *ls)
+{
+ const int x = luaL_checkint(ls, 1);
+ const int y = luaL_checkint(ls, 2);
+ lua_cloud_pow_min = luaL_checkint(ls, 3);
+ lua_cloud_pow_max = luaL_checkint(ls, 4);
+ lua_cloud_pow_rolls = luaL_checkint(ls, 5);
+ const int size = luaL_checkint(ls, 6);
+
+ const cloud_type ctype = dgn_cloud_name_to_type(luaL_checkstring(ls, 7));
+ const char* kname = lua_isstring(ls, 8) ? luaL_checkstring(ls, 8)
+ : "";
+ const kill_category kc = dgn_kill_name_to_category(kname);
+
+ const int spread_rate = lua_isnumber(ls, 9) ? luaL_checkint(ls, 9) : -1;
+
+ if (!in_bounds(x, y))
+ {
+ char buf[80];
+ sprintf(buf, "Point (%d,%d) isn't in bounds.", x, y);
+ luaL_argerror(ls, 1, buf);
+ return (0);
+ }
+
+ if (lua_cloud_pow_min < 0)
+ {
+ luaL_argerror(ls, 4, "pow_min must be non-negative");
+ return (0);
+ }
+
+ if (lua_cloud_pow_max < lua_cloud_pow_min)
+ {
+ luaL_argerror(ls, 5, "pow_max must not be less than pow_min");
+ return (0);
+ }
+
+ if (lua_cloud_pow_max == 0)
+ {
+ luaL_argerror(ls, 5, "pow_max must be positive");
+ return (0);
+ }
+
+ if (lua_cloud_pow_rolls <= 0)
+ {
+ luaL_argerror(ls, 6, "pow_rolls must be positive");
+ return (0);
+ }
+
+ if (size < 1)
+ {
+ luaL_argerror(ls, 4, "size must be positive.");
+ return (0);
+ }
+
+ if (ctype == CLOUD_NONE)
+ {
+ std::string error = "Invalid cloud type '";
+ error += luaL_checkstring(ls, 7);
+ error += "'";
+ luaL_argerror(ls, 7, error.c_str());
+ return (0);
+ }
+
+ if (kc == KC_NCATEGORIES)
+ {
+ std::string error = "Invalid kill category '";
+ error += kname;
+ error += "'";
+ luaL_argerror(ls, 8, error.c_str());
+ return (0);
+ }
+
+ if (spread_rate < -1 || spread_rate > 100)
+ {
+ luaL_argerror(ls, 9, "spread_rate must be between -1 and 100,"
+ "inclusive");
+ return (0);
+ }
+
+ apply_area_cloud(make_a_lua_cloud, x, y, 0, size,
+ ctype, kc, spread_rate);
+
+ return (0);
+}
static const struct luaL_reg dgn_lib[] =
{
@@ -1513,6 +1715,8 @@ static const struct luaL_reg dgn_lib[] =
{ "set_lt_callback", lua_dgn_set_lt_callback},
{ "fixup_stairs", dgn_fixup_stairs},
{ "floor_halo", dgn_floor_halo},
+ { "random_walk", dgn_random_walk},
+ { "apply_area_cloud", dgn_apply_area_cloud},
{ NULL, NULL }
};
diff --git a/crawl-ref/source/spells1.cc b/crawl-ref/source/spells1.cc
index b419fe0bf7..35a8e8179b 100644
--- a/crawl-ref/source/spells1.cc
+++ b/crawl-ref/source/spells1.cc
@@ -580,10 +580,10 @@ int cast_big_c(int pow, cloud_type cty, kill_category whose, bolt &beam)
} // end cast_big_c()
void big_cloud(cloud_type cl_type, kill_category whose,
- int cl_x, int cl_y, int pow, int size)
+ int cl_x, int cl_y, int pow, int size, int spread_rate)
{
apply_area_cloud(make_a_normal_cloud, cl_x, cl_y, pow, size,
- cl_type, whose);
+ cl_type, whose, spread_rate);
} // end big_cloud()
static int healing_spell( int healed )
diff --git a/crawl-ref/source/spells1.h b/crawl-ref/source/spells1.h
index 2504f7670d..5764bdef73 100644
--- a/crawl-ref/source/spells1.h
+++ b/crawl-ref/source/spells1.h
@@ -58,7 +58,7 @@ int cast_healing(int power);
* called from: beam - it_use3 - spells - spells1
* *********************************************************************** */
void big_cloud(cloud_type cl_type, kill_category whose, int cl_x, int cl_y,
- int pow, int size);
+ int pow, int size, int spread_rate = -1);
// last updated 24may2000 {dlb}
diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc
index 8b75b917c7..1742ba2589 100644
--- a/crawl-ref/source/spells4.cc
+++ b/crawl-ref/source/spells4.cc
@@ -1568,12 +1568,12 @@ static int make_a_rot_cloud(int x, int y, int pow, cloud_type ctype)
return 0;
} // end make_a_rot_cloud()
-int make_a_normal_cloud(int x, int y, int pow, cloud_type ctype,
- kill_category whose)
+int make_a_normal_cloud(int x, int y, int pow, int spread_rate,
+ cloud_type ctype, kill_category whose)
{
place_cloud( ctype, x, y,
(3 + random2(pow / 4) + random2(pow / 4) + random2(pow / 4)),
- whose );
+ whose, spread_rate );
return 1;
} // end make_a_normal_cloud()
diff --git a/crawl-ref/source/spells4.h b/crawl-ref/source/spells4.h
index 515c8cc5a6..4a0b745d05 100644
--- a/crawl-ref/source/spells4.h
+++ b/crawl-ref/source/spells4.h
@@ -20,8 +20,8 @@ struct bolt;
std::string your_hand(bool plural);
bool backlight_monsters(int x, int y, int pow, int garbage);
-int make_a_normal_cloud(int x, int y, int pow, cloud_type ctype,
- kill_category);
+int make_a_normal_cloud(int x, int y, int pow, int spread_rate,
+ cloud_type ctype, kill_category);
int disperse_monsters(int x, int y, int pow, int message);
void cast_bend(int pow);
diff --git a/crawl-ref/source/spl-util.cc b/crawl-ref/source/spl-util.cc
index 918592a9ef..2f06175670 100644
--- a/crawl-ref/source/spl-util.cc
+++ b/crawl-ref/source/spl-util.cc
@@ -54,9 +54,10 @@ static int spell_list[NUM_SPELLS];
#define SPELLDATASIZE (sizeof(spelldata)/sizeof(struct spell_desc))
static struct spell_desc *seekspell(spell_type spellid);
-static bool cloud_helper(int (*func)(int, int, int, cloud_type, kill_category),
- int x, int y,
- int pow, cloud_type ctype, kill_category );
+static bool cloud_helper(int (*func)(int, int, int, int, cloud_type,
+ kill_category),
+ int x, int y, int pow, int spread_rate,
+ cloud_type ctype, kill_category );
/*
* BEGIN PUBLIC FUNCTIONS
@@ -539,17 +540,19 @@ int apply_area_within_radius( int (*func) (int, int, int, int),
// We really need some sort of a queue structure, since ideally I'd like
// to do a (shallow) breadth-first-search of the dungeon floor.
// This ought to work okay for small clouds.
-void apply_area_cloud( int (*func) (int, int, int, cloud_type, kill_category),
+void apply_area_cloud( int (*func) (int, int, int, int, cloud_type,
+ kill_category),
int x, int y,
int pow, int number, cloud_type ctype,
- kill_category whose )
+ kill_category whose, int spread_rate )
{
int spread, clouds_left = number;
int good_squares = 0, neighbours[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
int dx = 1, dy = 1;
bool x_first;
- if (clouds_left && cloud_helper(func, x, y, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x, y, pow, spread_rate,
+ ctype, whose))
clouds_left--;
if (!clouds_left)
@@ -564,28 +567,32 @@ void apply_area_cloud( int (*func) (int, int, int, cloud_type, kill_category),
if (x_first)
{
- if (clouds_left && cloud_helper(func, x + dx, y, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x + dx, y, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
neighbours[0]++;
}
- if (clouds_left && cloud_helper(func, x - dx, y, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x - dx, y, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
neighbours[1]++;
}
- if (clouds_left && cloud_helper(func, x, y + dy, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x, y + dy, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
neighbours[2]++;
}
- if (clouds_left && cloud_helper(func, x, y - dy, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x, y - dy, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
@@ -594,28 +601,32 @@ void apply_area_cloud( int (*func) (int, int, int, cloud_type, kill_category),
}
else
{
- if (clouds_left && cloud_helper(func, x, y + dy, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x, y + dy, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
neighbours[2]++;
}
- if (clouds_left && cloud_helper(func, x, y - dy, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x, y - dy, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
neighbours[3]++;
}
- if (clouds_left && cloud_helper(func, x + dx, y, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x + dx, y, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
neighbours[0]++;
}
- if (clouds_left && cloud_helper(func, x - dx, y, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x - dx, y, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
@@ -624,28 +635,32 @@ void apply_area_cloud( int (*func) (int, int, int, cloud_type, kill_category),
}
// now diagonals; we could randomize dx & dy again here
- if (clouds_left && cloud_helper(func, x + dx, y + dy, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x + dx, y + dy, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
neighbours[4]++;
}
- if (clouds_left && cloud_helper(func, x - dx, y + dy, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x - dx, y + dy, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
neighbours[5]++;
}
- if (clouds_left && cloud_helper(func, x + dx, y - dy, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x + dx, y - dy, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
neighbours[6]++;
}
- if (clouds_left && cloud_helper(func, x - dx, y - dy, pow, ctype, whose))
+ if (clouds_left && cloud_helper(func, x - dx, y - dy, pow, spread_rate,
+ ctype, whose))
{
clouds_left--;
good_squares++;
@@ -667,28 +682,36 @@ void apply_area_cloud( int (*func) (int, int, int, cloud_type, kill_category),
switch (i)
{
case 0:
- apply_area_cloud(func, x + dx, y, pow, spread, ctype, whose);
+ apply_area_cloud(func, x + dx, y, pow, spread, ctype, whose,
+ spread_rate);
break;
case 1:
- apply_area_cloud(func, x - dx, y, pow, spread, ctype, whose);
+ apply_area_cloud(func, x - dx, y, pow, spread, ctype, whose,
+ spread_rate);
break;
case 2:
- apply_area_cloud(func, x, y + dy, pow, spread, ctype, whose);
+ apply_area_cloud(func, x, y + dy, pow, spread, ctype, whose,
+ spread_rate);
break;
case 3:
- apply_area_cloud(func, x, y - dy, pow, spread, ctype, whose);
+ apply_area_cloud(func, x, y - dy, pow, spread, ctype, whose,
+ spread_rate);
break;
case 4:
- apply_area_cloud(func, x + dx, y + dy, pow, spread, ctype, whose);
+ apply_area_cloud(func, x + dx, y + dy, pow, spread, ctype, whose,
+ spread_rate);
break;
case 5:
- apply_area_cloud(func, x - dx, y + dy, pow, spread, ctype, whose);
+ apply_area_cloud(func, x - dx, y + dy, pow, spread, ctype, whose,
+ spread_rate);
break;
case 6:
- apply_area_cloud(func, x + dx, y - dy, pow, spread, ctype, whose);
+ apply_area_cloud(func, x + dx, y - dy, pow, spread, ctype, whose,
+ spread_rate);
break;
case 7:
- apply_area_cloud(func, x - dx, y - dy, pow, spread, ctype, whose);
+ apply_area_cloud(func, x - dx, y - dy, pow, spread, ctype, whose,
+ spread_rate);
break;
}
}
@@ -831,13 +854,14 @@ static spell_desc *seekspell(spell_type spell)
return (index != -1? &spelldata[index] : NULL);
}
-static bool cloud_helper(int (*func)(int, int, int, cloud_type, kill_category),
- int x, int y,
- int pow, cloud_type ctype, kill_category whose )
+static bool cloud_helper(int (*func)(int, int, int, int, cloud_type,
+ kill_category),
+ int x, int y, int pow, int spread_rate,
+ cloud_type ctype, kill_category whose )
{
if (!grid_is_solid(grd[x][y]) && env.cgrid[x][y] == EMPTY_CLOUD)
{
- func(x, y, pow, ctype, whose);
+ func(x, y, pow, spread_rate, ctype, whose);
return true;
}
diff --git a/crawl-ref/source/spl-util.h b/crawl-ref/source/spl-util.h
index 67f76133ef..56986ab064 100644
--- a/crawl-ref/source/spl-util.h
+++ b/crawl-ref/source/spl-util.h
@@ -128,9 +128,10 @@ bool spell_direction( dist &spelld, bolt &pbolt,
bool needs_path = true,
const char *prompt = NULL );
-void apply_area_cloud(int (*func) (int, int, int, cloud_type, kill_category),
+void apply_area_cloud(int (*func) (int, int, int, int, cloud_type,
+ kill_category),
int x, int y, int pow, int number, cloud_type ctype,
- kill_category);
+ kill_category kc, int spread_rate = -1);
const char *spelltype_name(unsigned int which_spelltype);
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index 8640b2e758..8aeabbf1c1 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -1510,6 +1510,7 @@ static void tag_construct_level(struct tagHeader &th)
marshallByte(th, env.cloud[i].y);
marshallByte(th, env.cloud[i].type);
marshallShort(th, env.cloud[i].decay);
+ marshallByte(th, (char) env.cloud[i].spread_rate);
marshallShort(th, env.cloud[i].whose);
}
@@ -1748,6 +1749,7 @@ static void tag_read_level( struct tagHeader &th, char minorVersion )
env.cloud[i].y = unmarshallByte(th);
env.cloud[i].type = static_cast<cloud_type>(unmarshallByte(th));
env.cloud[i].decay = unmarshallShort(th);
+ env.cloud[i].spread_rate = (unsigned char) unmarshallByte(th);
env.cloud[i].whose = static_cast<kill_category>(unmarshallShort(th));
}