summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2007-10-18 17:42:50 +0000
committerzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2007-10-18 17:42:50 +0000
commit45b0ff6c34bfa8f1653413349a31a65070e662c6 (patch)
tree6d41494b0b486decce22d11a24903da7655faada
parent6953c233808fe5c5cbc1b9f7143e7986a6e09439 (diff)
downloadcrawl-ref-45b0ff6c34bfa8f1653413349a31a65070e662c6.tar.gz
crawl-ref-45b0ff6c34bfa8f1653413349a31a65070e662c6.zip
Added fog machine Lua map markers. Needs a C interface to make it usable
in level generation. Clouds now have a "spread rate" field, which by default uses the same per-cloud-type rate as before (normal spread rate for steam, grey smoke and black smoke, no spreading for other cloud types). Might want to make the spread rate decrease as the cloud spreads (currently it remains unchanged). Added new dungeon event type "entered level", to complement "entering level". git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2489 c06c8d41-db1a-0410-9941-cceddc491573
-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));
}