summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorennewalker <ennewalker@c06c8d41-db1a-0410-9941-cceddc491573>2008-05-22 13:18:50 +0000
committerennewalker <ennewalker@c06c8d41-db1a-0410-9941-cceddc491573>2008-05-22 13:18:50 +0000
commit9a1e7565ec8802a38a9649744920923fc262dff7 (patch)
tree700f62fb01028913c0d99ab99645a004d4f42fa7
parent0d4f7611a414a3f92ade376733eb51bda0328000 (diff)
downloadcrawl-ref-9a1e7565ec8802a38a9649744920923fc262dff7.tar.gz
crawl-ref-9a1e7565ec8802a38a9649744920923fc262dff7.zip
Pushing some dungeon-related lua functions back into C++.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@5176 c06c8d41-db1a-0410-9941-cceddc491573
-rw-r--r--crawl-ref/source/clua.cc53
-rw-r--r--crawl-ref/source/dat/layout.des293
-rw-r--r--crawl-ref/source/dungeon.cc111
-rw-r--r--crawl-ref/source/dungeon.h29
-rw-r--r--crawl-ref/source/luadgn.cc424
5 files changed, 591 insertions, 319 deletions
diff --git a/crawl-ref/source/clua.cc b/crawl-ref/source/clua.cc
index 4bd14e1708..b957150e22 100644
--- a/crawl-ref/source/clua.cc
+++ b/crawl-ref/source/clua.cc
@@ -1983,6 +1983,58 @@ LUARET1(crawl_random_range, number,
lua_isnumber(ls, 3)? luaL_checkint(ls, 3) : 1 ))
LUARET1(crawl_coinflip, boolean, coinflip())
+static int crawl_random_element(lua_State *ls)
+{
+ const int table_idx = 1;
+ const int value_idx = 2;
+
+ if (lua_gettop(ls) == 0)
+ {
+ lua_pushnil(ls);
+ return 1;
+ }
+
+ // Only the first arg does anything now. Maybe this should
+ // select from a variable number of table args?
+ lua_pop(ls, lua_gettop(ls) - 1);
+
+ // Keep max value on the stack, as it could be any type of value.
+ lua_pushnil(ls);
+ int rollsize = 0;
+
+ lua_pushnil(ls);
+ while (lua_next(ls, table_idx) != 0)
+ {
+ const int weight_idx = -1;
+ const int key_idx = -2;
+
+ int this_weight = lua_isnil(ls, weight_idx) ?
+ 1 : (int)lua_tonumber(ls, weight_idx);
+
+ if (rollsize > 0)
+ {
+ rollsize += this_weight;
+ if (random2(rollsize) < this_weight)
+ {
+ lua_pushvalue(ls, key_idx);
+ lua_replace(ls, value_idx);
+ }
+ }
+ else
+ {
+ lua_pushvalue(ls, key_idx);
+ lua_replace(ls, value_idx);
+ rollsize = this_weight;
+ }
+
+ lua_pop(ls, 1);
+ }
+
+ lua_pushvalue(ls, value_idx);
+
+ return 1;
+}
+
static int crawl_err_trace(lua_State *ls)
{
const int nargs = lua_gettop(ls);
@@ -2025,6 +2077,7 @@ static const struct luaL_reg crawl_lib[] =
{ "random2avg" , crawl_random2avg },
{ "coinflip", crawl_coinflip },
{ "random_range", crawl_random_range },
+ { "random_element", crawl_random_element },
{ "redraw_screen", crawl_redraw_screen },
{ "input_line", crawl_input_line },
{ "c_input_line", crawl_c_input_line},
diff --git a/crawl-ref/source/dat/layout.des b/crawl-ref/source/dat/layout.des
index 366100d082..59e5d5d561 100644
--- a/crawl-ref/source/dat/layout.des
+++ b/crawl-ref/source/dat/layout.des
@@ -6,227 +6,6 @@
#
###############################################################################
-lua {{
- -- TODO enne - most of these should probably get moved back into C++
-
- function fill_area(x1, y1, x2, y2, feature)
- for x = x1, x2 do
- for y = y1, y2 do
- dgn.grid(x, y, feature)
- end
- end
- end
-
- function octa_room(x1, y1, x2, y2, oblique, fill)
- local ob_temp = oblique
-
- local rock_wall = dgn.feature_number("rock_wall")
- local shallow_water = dgn.feature_number("shallow_water")
- local deep_water = dgn.feature_number("deep_water")
- local floor = dgn.feature_number("floor")
-
- for x = x1, x2 do
- for y = y1 + ob_temp, y2 - ob_temp do
- if dgn.grid(x, y) == rock_wall then
- dgn.grid(x, y, fill)
- end
- if dgn.grid(x, y) == floor and (fill == shallow_water or fill == deep_water) then
- dgn.grid(x, y, shallow_water)
- end
- end
-
- if x > x2 - oblique then
- ob_temp = ob_temp + 1
- elseif ob_temp > 0 then
- ob_temp = ob_temp - 1
- end
- end
- end
-
- function pillars(center_x, center_y, num, flip_x, big_radius,
- pillar_radius, pillar_routine, fill)
- for i = 0, num - 1 do
- local angle = i * 2 * math.pi / num
- local x = math.floor(math.cos(angle) * big_radius * flip_x + 0.5)
- local y = math.floor(math.sin(angle) * big_radius + 0.5)
-
- pillar_routine(center_x + x, center_y + y, pillar_radius, fill)
- end
- end
-
- -- begin pillar functions
- function pillar_square(center_x, center_y, radius, fill)
- for x = -radius, radius do
- for y = -radius, radius do
- dgn.grid(center_x + x, center_y + y, fill)
- end
- end
- end
-
- function pillar_rounded_square(center_x, center_y, radius, fill)
- for x = -radius, radius do
- for y = -radius, radius do
- if math.abs(x) ~= radius or math.abs(y) ~= radius then
- dgn.grid(center_x + x, center_y + y, fill)
- end
- end
- end
- end
-
- function pillar_circle(center_x, center_y, radius, fill)
- for x = -radius, radius do
- for y = -radius, radius do
- if x * x + y * y < radius * radius then
- dgn.grid(center_x + x, center_y + y, fill)
- end
- end
- end
- end
- -- end pillar functions
-
- function select_from_weighted_table(tb)
- local value = nil
- local rollsize = 0
- for temp_val, temp_weight in pairs (tb) do
- if rollsize == 0 then
- value = temp_val
- rollsize = temp_weight
- else
- rollsize = rollsize + temp_weight
- if crawl.random2(rollsize) < temp_weight then
- value = temp_val
- end
- end
- end
-
- return value
- end
-
- -- Randomly selects a grid with feature 'search' and sets it to 'replace'
- function replace_random(search, replace)
- local gxm, gym = dgn.max_bounds()
-
- local feature = nil, x, y
- while feature ~= search do
- x = crawl.random2(gxm)
- y = crawl.random2(gym)
- feature = dgn.grid(x, y)
- end
-
- dgn.grid(x, y, replace)
- end
-
- function valid(x, y)
- local gxm, gym = dgn.max_bounds()
- return (x >= 0 and y >= 0 and x < gxm and y < gym)
- end
-
- -- Walks from x, y along dx,dy until it finds 'search'
- function replace_first(x, y, dx, dy, search, replace)
-
- local feature = dgn.grid(x, y)
-
- while feature ~= search and valid(x,y) do
- x = x + dx
- y = y + dy
- feature = dgn.grid(x, y)
- end
-
- if valid(x, y) then
- dgn.grid(x, y, replace)
- return true
- else
- return false
- end
- end
-
- function spotty_level(boxy, x1, y1, x2, y2)
- local iterations
- -- boxy levels have more clearing, so they get fewer iterations
- if boxy then
- iterations = 200 + crawl.random2(750)
- else
- iterations = 200 + crawl.random2(1500)
- end
-
- make_spotty(iterations, boxy, x1, y1, x2, y2)
- end
-
- -- randomly turns walls into floors
- function make_spotty(iterations, boxy, x1, y1, x2, y2)
- if x2 - x1 - 8 <= 0 or y2 - y1 - 8 <= 0 then
- return
- end
-
- local wall = dgn.feature_number("rock_wall")
- local floor = dgn.feature_number("floor")
-
- for i = 1, iterations do
- local x, y
- repeat
- x = crawl.random2(x2 - x1 - 7) + x1 + 4
- y = crawl.random2(y2 - y1 - 7) + y1 + 4
- until dgn.grid(x, y) ~= wall or
- dgn.grid(x-1, y) ~= wall or
- dgn.grid(x+1, y) ~= wall or
- dgn.grid(x, y-1) ~= wall or
- dgn.grid(x, y+1) ~= wall or
- dgn.grid(x-2, y) ~= wall or
- dgn.grid(x+2, y) ~= wall or
- dgn.grid(x, y-2) ~= wall or
- dgn.grid(x, y+2) ~= wall
-
- -- convenience function
- function replace_grid(x, y, search, replace)
- if dgn.grid(x, y) == search then
- dgn.grid(x, y, replace)
- end
- end
-
- replace_grid(x, y, wall, floor)
- replace_grid(x, y-1, wall, floor)
- replace_grid(x, y+1, wall, floor)
- replace_grid(x-1, y, wall, floor)
- replace_grid(x+1, y, wall, floor)
-
- if boxy then
- replace_grid(x-1, y-1, wall, floor)
- replace_grid(x+1, y+1, wall, floor)
- replace_grid(x-1, y+1, wall, floor)
- replace_grid(x+1, y-1, wall, floor)
- end
- end
- end
-
- -- randomly extends walls onto floors
- function smear_feature(iterations, boxy, feature, x1, y1, x2, y2)
- for i = 1, iterations do
- local x, y
- function check_box(x, y, feature)
- return dgn.grid(x+1, y) == feature or
- dgn.grid(x-1, y) == feature or
- dgn.grid(x, y+1) == feature or
- dgn.grid(x, y-1) == feature
- end
- function check_diagonal(x, y, feature)
- return dgn.grid(x+1, y+1) == feature or
- dgn.grid(x-1, y+1) == feature or
- dgn.grid(x-1, y-1) == feature or
- dgn.grid(x+1, y-1) == feature
- end
-
- repeat
- x = crawl.random2(x2 - x1 - 2) + x1 + 1
- y = crawl.random2(y2 - y1 - 2) + y1 + 1
- until dgn.grid(x, y) ~= feature and
- (check_box(x, y, feature) or
- not boxy and check_diagonal(x, y, feature))
-
- dgn.grid(x, y, feature)
- end
- end
-}}
-
##############################################################
# layout_forbidden_doughnut
#
@@ -241,15 +20,15 @@ TAGS: layout allow_dup
local gxm, gym = dgn.max_bounds()
local wall = dgn.feature_number("rock_wall")
local floor = dgn.feature_number("floor")
- fill_area(0, 0, gxm - 1, gym - 1, wall)
+ dgn.fill_area(0, 0, gxm - 1, gym - 1, wall)
local width = (10 - crawl.random2(7))
-- construct donut
- fill_area(10, 10, gxm - 10, 10 + width, floor)
- fill_area(10, 60 - width, gxm - 10, gym - 10, floor)
- fill_area(10, 10, 10 + width, gym - 10, floor)
- fill_area(60 - width, 10, gxm - 10, gym - 10, floor)
+ dgn.fill_area(10, 10, gxm - 10, 10 + width, floor)
+ dgn.fill_area(10, 60 - width, gxm - 10, gym - 10, floor)
+ dgn.fill_area(10, 10, 10 + width, gym - 10, floor)
+ dgn.fill_area(60 - width, 10, gxm - 10, gym - 10, floor)
local spotty = crawl.coinflip()
local smears = crawl.random2(300)
@@ -258,8 +37,8 @@ TAGS: layout allow_dup
if crawl.coinflip() then
local width2 = 1 + crawl.random2(5)
- fill_area(10, gym/2 - width2, gxm - 10, gym/2 + width2, floor)
- fill_area(gxm/2 - width2, 10, gxm/2 + width2, gym - 10, floor)
+ dgn.fill_area(10, gym/2 - width2, gxm - 10, gym/2 + width2, floor)
+ dgn.fill_area(gxm/2 - width2, 10, gxm/2 + width2, gym - 10, floor)
-- sometimes add a small octagon room
if crawl.coinflip() and crawl.random2(15) > 7 then
@@ -268,14 +47,12 @@ TAGS: layout allow_dup
oblique = 5 + crawl.random2(20)
end
- local feature_name = select_from_weighted_table({
+ local feature_name = crawl.random_element({
["floor"] = 5,
["deep_water"] = 1,
["lava"] = 1,
})
- local feature_idx = dgn.feature_number(feature_name)
-
- octa_room(25, 25, gxm - 25, gym - 25, oblique, feature_idx)
+ dgn.octa_room(25, 25, gxm - 25, gym - 25, oblique, feature_name)
-- decrease spotty chance
spotty = crawl.one_chance_in(5)
@@ -286,10 +63,10 @@ TAGS: layout allow_dup
local smear_boxy = crawl.coinflip()
if spotty then
- spotty_level(spotty_boxy, 0, 0, gxm - 1, gym - 1)
+ dgn.spotty_level(true, 0, spotty_boxy)
end
if not spotty and crawl.one_chance_in(4) or spotty then
- smear_feature(smears, smear_boxy, wall, 0, 0, gxm - 1, gym - 1)
+ dgn.smear_feature(smears, smear_boxy, wall, 0, 0, gxm - 1, gym - 1)
end
}}
MAP
@@ -328,23 +105,23 @@ TAGS: layout allow_dup
end
-- fill with rock
- fill_area(0, 0, gxm-1, gym-1, wall)
+ dgn.fill_area(0, 0, gxm-1, gym-1, wall)
-- create window
if window then
local clear = dgn.feature_number("clear_rock_wall")
- fill_area(10, gym/2 - height - 1, gxm - 10, gym/2 - height - 1, clear)
- fill_area(10, gym/2 + height + 1, gxm - 10, gym/2 + height + 1, clear)
- fill_area(gxm/2 - width - 1, 10, gxm/2 - width - 1, gym - 10, clear)
- fill_area(gxm/2 + width + 1, 10, gxm/2 + width + 1, gym - 10, clear)
+ dgn.fill_area(10, gym/2 - height - 1, gxm - 10, gym/2 - height - 1, clear)
+ dgn.fill_area(10, gym/2 + height + 1, gxm - 10, gym/2 + height + 1, clear)
+ dgn.fill_area(gxm/2 - width - 1, 10, gxm/2 - width - 1, gym - 10, clear)
+ dgn.fill_area(gxm/2 + width + 1, 10, gxm/2 + width + 1, gym - 10, clear)
end
-- create a cross
- fill_area(10, gym/2 - height, gxm - 10, gym/2 + height, floor)
- fill_area(gxm/2 - width, 10, gxm/2 + width, gym - 10, floor)
+ dgn.fill_area(10, gym/2 - height, gxm - 10, gym/2 + height, floor)
+ dgn.fill_area(gxm/2 - width, 10, gxm/2 + width, gym - 10, floor)
if not crawl.one_chance_in(4) then
- spotty_level(crawl.coinflip(), 0, 0, gxm - 1, gym - 1)
+ dgn.spotty_level(true, 0, crawl.coinflip())
end
}}
MAP
@@ -369,13 +146,12 @@ TAGS: layout allow_dup
local oblique = 10 + crawl.random2(20)
- -- Step 1: Create octagon
- fill_area(0, 0, gxm - 1, gym - 1, wall)
- octa_room(10, 10, gxm - 10, gym - 10, oblique, floor)
+ dgn.fill_area(0, 0, gxm - 1, gym - 1, "rock_wall")
+ dgn.octa_room(10, 10, gxm - 10, gym - 10, oblique, "floor")
- if crawl.coinflip() then
+ if crawl.coinflip() or true then
local iterations = 100 + crawl.random2(200)
- smear_feature(iterations, false, wall, 0, 0, gxm - 1, gym - 1)
+ dgn.smear_feature(iterations, false, wall, 0, 0, gxm - 1, gym - 1)
end
-- Step 2: Add pillars
@@ -389,10 +165,14 @@ TAGS: layout allow_dup
["deep_water"] = 2,
["lava"] = 1,
}
- local fill = dgn.feature_number(select_from_weighted_table(pillar_fill))
+ local fill = dgn.feature_number(crawl.random_element(pillar_fill))
-- Potential pillar drawing routines
- local pillar_func = {pillar_circle, pillar_square, pillar_rounded_square}
+ local pillar_func = {
+ dgn.make_circle,
+ dgn.make_square,
+ dgn.make_rounded_square
+ }
-- Pillar size params
-- NOTE: Be careful about tweaking the ranges here. Pillars that are
@@ -402,14 +182,15 @@ TAGS: layout allow_dup
local pillar_radius = 1 + crawl.random2(3)
local circle_radius = 2 + crawl.random2(6) + pillar_radius * 2 + num / 2
+
-- beautification hack: no "circle" pillars of radius 1
if type == 1 and pillar_radius == 1 then
fill = dgn.feature_number("stone_arch")
end
-- Finally, make the pillars
- pillars(gxm/2, gym/2, num, 1, circle_radius, pillar_radius,
- pillar_func[type], fill)
+ dgn.make_pillars(gxm/2, gym/2, num, 1, circle_radius, pillar_radius,
+ pillar_func[type], fill)
-- Step 3: Create stairs
@@ -445,17 +226,17 @@ TAGS: layout allow_dup
local ret = true
if loc == 0 then
- replace_random(floor, stair_list[i])
+ dgn.replace_random(floor, stair_list[i])
elseif loc == 1 then
dgn.grid(gxm/2 + i - 2, gym/2 + 1 - math.abs(i - 2), st)
elseif loc == 2 then
- ret = replace_first(gxm/2 + i - 2, 0, 0, 1, floor, st)
+ ret = dgn.replace_first(gxm/2 + i-2, 0, 0, 1, floor, st)
elseif loc == 3 then
- ret = replace_first(gxm - 1, gym/2 + i - 2, -1, 0, floor, st)
+ ret = dgn.replace_first(gxm - 1, gym/2 + i-2, -1, 0, floor, st)
elseif loc == 4 then
- ret = replace_first(gxm/2 + i - 2, gym - 1, 0, -1, floor, st)
+ ret = dgn.replace_first(gxm/2 + i-2, gym - 1, 0, -1, floor, st)
elseif loc == 5 then
- ret = replace_first(0, gym/2 + i - 2, 1, 0, floor, st)
+ ret = dgn.replace_first(0, gym/2 + i-2, 1, 0, floor, st)
end
assert(ret)
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index 3e2611cfb8..9e7cbe1c76 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -83,20 +83,6 @@ struct pit_mons_def
int rare;
};
-struct spec_room
-{
- bool created;
- bool hooked_up;
- int x1;
- int y1;
- int x2;
- int y2;
-
- spec_room() : created(false), hooked_up(false), x1(0), y1(0), x2(0), y2(0)
- {
- }
-};
-
struct dist_feat
{
int dist;
@@ -155,8 +141,6 @@ static void _place_pool(dungeon_feature_type pool_type, unsigned char pool_x1,
unsigned char pool_y1, unsigned char pool_x2,
unsigned char pool_y2);
static void _many_pools(dungeon_feature_type pool_type);
-static bool _join_the_dots(const coord_def &from, const coord_def &to,
- unsigned mmask, bool early_exit = false);
static bool _join_the_dots_rigorous(const coord_def &from,
const coord_def &to,
unsigned mapmask,
@@ -165,7 +149,6 @@ static bool _join_the_dots_rigorous(const coord_def &from,
static void _build_river(dungeon_feature_type river_type); //mv
static void _build_lake(dungeon_feature_type lake_type); //mv
-static void _spotty_level(bool seeded, int iterations, bool boxy);
static void _bigger_room();
static void _plan_main(int level_number, int force_plan);
static char _plan_1(int level_number);
@@ -175,8 +158,6 @@ static char _plan_4(char forbid_x1, char forbid_y1, char forbid_x2,
char forbid_y2, dungeon_feature_type force_wall);
static char _plan_5();
static char _plan_6(int level_number);
-static bool _octa_room(spec_room &sr, int oblique_max,
- dungeon_feature_type type_floor);
static void _portal_vault_level(int level_number);
static void _labyrinth_level(int level_number);
static void _box_room(int bx1, int bx2, int by1, int by2,
@@ -1406,8 +1387,8 @@ static void _place_ellipse(int x, int y, int a, int b,
}
}
-static int _count_feature_in_box(int x0, int y0, int x1, int y1,
- dungeon_feature_type feat)
+int count_feature_in_box(int x0, int y0, int x1, int y1,
+ dungeon_feature_type feat)
{
int result = 0;
for ( int i = x0; i < x1; ++i )
@@ -1420,16 +1401,16 @@ static int _count_feature_in_box(int x0, int y0, int x1, int y1,
return result;
}
-static int _count_antifeature_in_box(int x0, int y0, int x1, int y1,
- dungeon_feature_type feat)
+int count_antifeature_in_box(int x0, int y0, int x1, int y1,
+ dungeon_feature_type feat)
{
- return (x1-x0)*(y1-y0) - _count_feature_in_box(x0,y0,x1,y1,feat);
+ return (x1-x0)*(y1-y0) - count_feature_in_box(x0,y0,x1,y1,feat);
}
// count how many neighbours of grd[x][y] are the feature feat.
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);
+ 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,
@@ -2011,7 +1992,7 @@ static builder_rc_type _builder_by_branch(int level_number)
case BRANCH_HIVE:
case BRANCH_SLIME_PITS:
case BRANCH_ORCISH_MINES:
- _spotty_level(false, 100 + random2(500), false);
+ spotty_level(false, 100 + random2(500), false);
return BUILD_SKIP;
default:
@@ -2131,7 +2112,7 @@ static builder_rc_type _builder_normal(int level_number, char level_type,
{
if (one_chance_in(16))
{
- _spotty_level(false, 0, coinflip());
+ spotty_level(false, 0, coinflip());
return BUILD_SKIP;
}
@@ -3739,7 +3720,7 @@ static void _build_rooms(const dgn_region_list &excluded,
if (connections.size())
{
const coord_def c = connections[0];
- if (_join_the_dots(c, myroom.random_edge_point(), MMT_VAULT))
+ if (join_the_dots(c, myroom.random_edge_point(), MMT_VAULT))
connections.erase( connections.begin() );
}
@@ -4029,7 +4010,7 @@ static void _connect_vault(const vault_placement &vp)
if (!floor.x && !floor.y)
continue;
- _join_the_dots(p, floor, MMT_VAULT, true);
+ join_the_dots(p, floor, MMT_VAULT, true);
}
}
@@ -5066,8 +5047,8 @@ static bool _join_the_dots_rigorous(const coord_def &from,
return (found);
}
-static bool _join_the_dots( const coord_def &from, const coord_def &to,
- unsigned mapmask, bool early_exit)
+bool join_the_dots(const coord_def &from, const coord_def &to,
+ unsigned mapmask, bool early_exit)
{
if (from == to)
return (true);
@@ -5200,7 +5181,7 @@ static void _many_pools(dungeon_feature_type pool_type)
const int k = i + 2 + roll_dice( 2, 9 );
const int l = j + 2 + roll_dice( 2, 9 );
- if ( _count_antifeature_in_box(i, j, k, l, DNGN_FLOOR) == 0 )
+ if ( count_antifeature_in_box(i, j, k, l, DNGN_FLOOR) == 0 )
{
_place_pool(pool_type, i, j, k, l);
pools++;
@@ -5332,13 +5313,13 @@ static void _place_altar()
int px = 15 + random2(55);
int py = 15 + random2(45);
- const int numfloors = _count_feature_in_box(px-2, py-2, px+3, py+3,
+ const int numfloors = count_feature_in_box(px-2, py-2, px+3, py+3,
DNGN_FLOOR);
const int numgood =
- _count_feature_in_box(px-2, py-2, px+3, py+3, DNGN_ROCK_WALL) +
- _count_feature_in_box(px-2, py-2, px+3, py+3, DNGN_CLOSED_DOOR) +
- _count_feature_in_box(px-2, py-2, px+3, py+3, DNGN_SECRET_DOOR) +
- _count_feature_in_box(px-2, py-2, px+3, py+3, DNGN_FLOOR);
+ count_feature_in_box(px-2, py-2, px+3, py+3, DNGN_ROCK_WALL) +
+ count_feature_in_box(px-2, py-2, px+3, py+3, DNGN_CLOSED_DOOR) +
+ count_feature_in_box(px-2, py-2, px+3, py+3, DNGN_SECRET_DOOR) +
+ count_feature_in_box(px-2, py-2, px+3, py+3, DNGN_FLOOR);
if ( numgood < 5*5 || numfloors == 0 )
continue;
@@ -5624,7 +5605,7 @@ static object_class_type _item_in_shop(unsigned char shop_type)
return (OBJ_RANDOM);
} // end item_in_shop()
-static void _spotty_level(bool seeded, int iterations, bool boxy)
+void spotty_level(bool seeded, int iterations, bool boxy)
{
dgn_Build_Method = "spotty_level";
@@ -5718,6 +5699,34 @@ static void _spotty_level(bool seeded, int iterations, bool boxy)
}
} // end spotty_level()
+void smear_feature(int iterations, bool boxy, dungeon_feature_type feature,
+ int x1, int y1, int x2, int y2)
+{
+ for (int i = 0; i < iterations; i++)
+ {
+ int x, y;
+ bool diagonals, straights;
+ do
+ {
+ x = random_range(x1+1, x2-1);
+ y = random_range(y1+1, y2-1);
+
+ diagonals = grd[x+1][y+1] == feature ||
+ grd[x-1][y+1] == feature ||
+ grd[x-1][y-1] == feature ||
+ grd[x+1][y-1] == feature;
+
+ straights = grd[x+1][y] == feature ||
+ grd[x-1][y] == feature ||
+ grd[x][y+1] == feature ||
+ grd[x][y-1] == feature;
+ }
+ while (grd[x][y] == feature || !straights && (boxy || !diagonals));
+
+ grd[x][y] = feature;
+ }
+}
+
static void _bigger_room()
{
dgn_Build_Method = "bigger_room";
@@ -5780,7 +5789,7 @@ static void _plan_main(int level_number, int force_plan)
: _plan_3());
if (do_stairs == 3 || do_stairs == 1)
- _spotty_level(true, 0, coinflip());
+ spotty_level(true, 0, coinflip());
if (do_stairs == 2 || do_stairs == 3)
{
@@ -5849,7 +5858,7 @@ static char _plan_3()
romx2[which_room] = romx1[which_room] + 2 + random2(8);
romy2[which_room] = romy1[which_room] + 2 + random2(8);
- if (exclusive && _count_antifeature_in_box(romx1[which_room] - 1,
+ if (exclusive && count_antifeature_in_box(romx1[which_room] - 1,
romy1[which_room] - 1,
romx2[which_room] + 1,
romy2[which_room] + 1,
@@ -5873,7 +5882,7 @@ static char _plan_3()
const int prev_ry1 = romy1[which_room - 1];
const int prev_ry2 = romy2[which_room - 1];
- _join_the_dots( coord_def(rx1 + random2( rx2 - rx1 ),
+ join_the_dots( coord_def(rx1 + random2( rx2 - rx1 ),
ry1 + random2( ry2 - ry1 )),
coord_def(prev_rx1 + random2(prev_rx2 - prev_rx1),
prev_ry1 + random2(prev_ry2 - prev_ry1)),
@@ -5903,7 +5912,7 @@ static char _plan_3()
const int prev_ry1 = romy1[i - 1];
const int prev_ry2 = romy2[i - 1];
- _join_the_dots( coord_def( rx1 + random2( rx2 - rx1 ),
+ join_the_dots( coord_def( rx1 + random2( rx2 - rx1 ),
ry1 + random2( ry2 - ry1 ) ),
coord_def(
prev_rx1 + random2( prev_rx2 - prev_rx1 ),
@@ -5975,7 +5984,7 @@ static char _plan_4(char forbid_x1, char forbid_y1, char forbid_x2,
}
}
- if (_count_antifeature_in_box(b1x-1, b1y-1, b2x+1, b2y+1, DNGN_FLOOR))
+ if (count_antifeature_in_box(b1x-1, b1y-1, b2x+1, b2y+1, DNGN_FLOOR))
continue;
if (force_wall == NUM_FEATURES)
@@ -6016,7 +6025,7 @@ static char _plan_4(char forbid_x1, char forbid_y1, char forbid_x2,
if (one_chance_in(10))
feature = coinflip()? DNGN_DEEP_WATER : DNGN_LAVA;
- _octa_room(sr, oblique_max, feature);
+ octa_room(sr, oblique_max, feature);
}
return 2;
@@ -6030,14 +6039,14 @@ static char _plan_5()
for (unsigned char i = 0; i < imax; i++)
{
- _join_the_dots(
+ join_the_dots(
coord_def( random2(GXM - 20) + 10, random2(GYM - 20) + 10 ),
coord_def( random2(GXM - 20) + 10, random2(GYM - 20) + 10 ),
MMT_VAULT );
}
if (!one_chance_in(4))
- _spotty_level(true, 100, coinflip());
+ spotty_level(true, 100, coinflip());
return 2;
} // end plan_5()
@@ -6069,8 +6078,8 @@ static char _plan_6(int level_number)
return 0;
} // end plan_6()
-static bool _octa_room(spec_room &sr, int oblique_max,
- dungeon_feature_type type_floor)
+bool octa_room(spec_room &sr, int oblique_max,
+ dungeon_feature_type type_floor)
{
dgn_Build_Method = "octa_room";
@@ -6762,7 +6771,7 @@ static void _diamond_rooms(int level_number)
oblique_max = (sr.x2 - sr.x1) / 2; //random2(20) + 5;
- if (!_octa_room(sr, oblique_max, type_floor))
+ if (!octa_room(sr, oblique_max, type_floor))
{
runthru++;
if (runthru > 9)
@@ -6797,7 +6806,7 @@ static void _big_room(int level_number)
// usually floor, except at higher levels
if (!one_chance_in(5) || level_number < 8 + random2(8))
{
- _octa_room(sr, oblique, DNGN_FLOOR);
+ octa_room(sr, oblique, DNGN_FLOOR);
return;
}
@@ -6810,7 +6819,7 @@ static void _big_room(int level_number)
: DNGN_LAVA);
}
- _octa_room(sr, oblique, type_floor);
+ octa_room(sr, oblique, type_floor);
}
// what now?
diff --git a/crawl-ref/source/dungeon.h b/crawl-ref/source/dungeon.h
index b1fe5f3c59..4644cd05fe 100644
--- a/crawl-ref/source/dungeon.h
+++ b/crawl-ref/source/dungeon.h
@@ -340,4 +340,33 @@ void dgn_set_lt_callback(std::string level_type_name,
// vaults used in the current level).
bool dgn_square_is_passable(const coord_def &c);
+struct spec_room
+{
+ bool created;
+ bool hooked_up;
+ int x1;
+ int y1;
+ int x2;
+ int y2;
+
+ spec_room() : created(false), hooked_up(false), x1(0), y1(0), x2(0), y2(0)
+ {
+ }
+};
+
+bool join_the_dots(const coord_def &from, const coord_def &to,
+ unsigned mmask, bool early_exit = false);
+void spotty_level(bool seeded, int iterations, bool boxy);
+void smear_feature(int iterations, bool boxy, dungeon_feature_type feature,
+ int x1, int y1, int x2, int y2);
+bool octa_room(spec_room &sr, int oblique_max,
+ dungeon_feature_type type_floor);
+
+int count_feature_in_box(int x0, int y0, int x1, int y1,
+ dungeon_feature_type feat);
+int count_antifeature_in_box(int x0, int y0, int x1, int y1,
+ dungeon_feature_type feat);
+int count_neighbours(int x, int y, dungeon_feature_type feat);
+
+
#endif
diff --git a/crawl-ref/source/luadgn.cc b/crawl-ref/source/luadgn.cc
index f99ea111d5..32dbbfb9d3 100644
--- a/crawl-ref/source/luadgn.cc
+++ b/crawl-ref/source/luadgn.cc
@@ -10,6 +10,7 @@
#include <sstream>
#include <algorithm>
+#include <cmath>
#include "branch.h"
#include "clua.h"
@@ -1668,6 +1669,387 @@ static int dgn_apply_area_cloud(lua_State *ls)
return (0);
}
+static dungeon_feature_type _get_lua_feature(lua_State *ls, int idx)
+{
+ dungeon_feature_type feat = (dungeon_feature_type)0;
+ if (lua_isnumber(ls, idx))
+ feat = (dungeon_feature_type)luaL_checkint(ls, idx);
+ else if (lua_isstring(ls, idx))
+ feat = dungeon_feature_by_name(luaL_checkstring(ls, idx));
+ else
+ luaL_argerror(ls, idx, "Feature must be a string or a feature index.");
+
+ return feat;
+}
+
+static void _clamp_to_bounds(int &x, int &y)
+{
+ x = std::min(std::max(x, X_BOUND_1+1), X_BOUND_2-1);
+ y = std::min(std::max(y, Y_BOUND_1+1), Y_BOUND_2-1);
+}
+
+static int dgn_fill_area(lua_State *ls)
+{
+ int x1 = luaL_checkint(ls, 1);
+ int y1 = luaL_checkint(ls, 2);
+ int x2 = luaL_checkint(ls, 3);
+ int y2 = luaL_checkint(ls, 4);
+ dungeon_feature_type feat = _get_lua_feature(ls, 5);
+ if (!feat)
+ {
+ luaL_argerror(ls, 5, "Invalid feature.");
+ return 0;
+ }
+
+ _clamp_to_bounds(x1, y1);
+ _clamp_to_bounds(x2, y2);
+ if (x2 < x1)
+ std::swap(x1, x2);
+ if (y2 < y1)
+ std::swap(y1, y2);
+
+ for (int y = y1; y <= y2; y++)
+ for (int x = x1; x <= x2; x++)
+ grd[x][y] = feat;
+
+ return 0;
+}
+
+static int dgn_replace_area(lua_State *ls)
+{
+ int x1 = luaL_checkint(ls, 1);
+ int y1 = luaL_checkint(ls, 2);
+ int x2 = luaL_checkint(ls, 3);
+ int y2 = luaL_checkint(ls, 4);
+ dungeon_feature_type search = _get_lua_feature(ls, 5);
+ if (!search)
+ {
+ luaL_argerror(ls, 5, "Invalid feature.");
+ return 0;
+ }
+ dungeon_feature_type replace = _get_lua_feature(ls, 6);
+ if (!replace)
+ {
+ luaL_argerror(ls, 6, "Invalid feature.");
+ return 0;
+ }
+
+ // gracefully handle out of bound areas by truncating them.
+ _clamp_to_bounds(x1, y1);
+ _clamp_to_bounds(x2, y2);
+ if (x2 < x1)
+ std::swap(x1, x2);
+ if (y2 < y1)
+ std::swap(y1, y2);
+
+ for (int y = y1; y <= y2; y++)
+ for (int x = x1; x <= x2; x++)
+ if (grd[x][y] == search)
+ grd[x][y] = replace;
+
+ return 0;
+}
+
+static int dgn_octa_room(lua_State *ls)
+{
+ int x1 = luaL_checkint(ls, 1);
+ int y1 = luaL_checkint(ls, 2);
+ int x2 = luaL_checkint(ls, 3);
+ int y2 = luaL_checkint(ls, 4);
+ int oblique = luaL_checkint(ls, 5);
+ dungeon_feature_type fill = _get_lua_feature(ls, 6);
+ if (!fill)
+ {
+ luaL_argerror(ls, 6, "Invalid feature.");
+ return 0;
+ }
+
+ spec_room sr;
+ sr.x1 = x1;
+ sr.x2 = x2;
+ sr.y1 = y1;
+ sr.y2 = y2;
+
+ octa_room(sr, oblique, fill);
+
+ return 0;
+}
+
+static int dgn_make_pillars(lua_State *ls)
+{
+ int center_x = luaL_checkint(ls, 1);
+ int center_y = luaL_checkint(ls, 2);
+ int num = luaL_checkint(ls, 3);
+ int scale_x = luaL_checkint(ls, 4);
+ int big_radius = luaL_checkint(ls, 5);
+ int pillar_radius = luaL_checkint(ls, 6);
+ dungeon_feature_type fill = _get_lua_feature(ls, 8);
+ if (!fill)
+ {
+ luaL_argerror(ls, 8, "Invalid feature.");
+ return 0;
+ }
+
+ const float PI = 3.14159265f;
+ for (int n = 0; n < num; n++)
+ {
+ float angle = n * 2 * PI / (float)num;
+ int x = (int)std::floor(std::cos(angle) * big_radius * scale_x + 0.5f);
+ int y = (int)std::floor(std::sin(angle) * big_radius + 0.5f);
+
+ lua_pushvalue(ls, 7);
+ lua_pushnumber(ls, center_x + x);
+ lua_pushnumber(ls, center_y + y);
+ lua_pushnumber(ls, pillar_radius);
+ lua_pushnumber(ls, fill);
+
+ lua_call(ls, 4, 0);
+ }
+
+ return 0;
+}
+
+static int dgn_make_square(lua_State *ls)
+{
+ int center_x = luaL_checkint(ls, 1);
+ int center_y = luaL_checkint(ls, 2);
+ int radius = std::abs(luaL_checkint(ls, 3));
+ dungeon_feature_type fill = _get_lua_feature(ls, 4);
+ if (!fill)
+ {
+ luaL_argerror(ls, 4, "Invalid feature.");
+ return 0;
+ }
+
+ for (int x = -radius; x <= radius; x++)
+ for (int y = -radius; y <= radius; y++)
+ grd[center_x + x][center_y + y] = fill;
+
+ return 0;
+}
+
+static int dgn_make_rounded_square(lua_State *ls)
+{
+ int center_x = luaL_checkint(ls, 1);
+ int center_y = luaL_checkint(ls, 2);
+ int radius = std::abs(luaL_checkint(ls, 3));
+ dungeon_feature_type fill = _get_lua_feature(ls, 4);
+ if (!fill)
+ {
+ luaL_argerror(ls, 4, "Invalid feature.");
+ return 0;
+ }
+
+ for (int x = -radius; x <= radius; x++)
+ for (int y = -radius; y <= radius; y++)
+ if (std::abs(x) != radius || std::abs(y) != radius)
+ grd[center_x + x][center_y + y] = fill;
+
+ return 0;
+}
+
+static int dgn_make_circle(lua_State *ls)
+{
+ int center_x = luaL_checkint(ls, 1);
+ int center_y = luaL_checkint(ls, 2);
+ int radius = std::abs(luaL_checkint(ls, 3));
+ dungeon_feature_type fill = _get_lua_feature(ls, 4);
+ if (!fill)
+ {
+ luaL_argerror(ls, 4, "Invalid feature.");
+ return 0;
+ }
+
+ for (int x = -radius; x <= radius; x++)
+ for (int y = -radius; y <= radius; y++)
+ if (x * x + y * y < radius * radius)
+ grd[center_x + x][center_y + y] = fill;
+
+ return 0;
+}
+
+static int dgn_in_bounds(lua_State *ls)
+{
+ int x = luaL_checkint(ls, 1);
+ int y = luaL_checkint(ls, 2);
+
+ lua_pushboolean(ls, in_bounds(x, y));
+ return 1;
+}
+
+static int dgn_replace_first(lua_State *ls)
+{
+ int x = luaL_checkint(ls, 1);
+ int y = luaL_checkint(ls, 2);
+ int dx = luaL_checkint(ls, 3);
+ int dy = luaL_checkint(ls, 4);
+ dungeon_feature_type search = _get_lua_feature(ls, 5);
+ if (!search)
+ {
+ luaL_argerror(ls, 5, "Invalid feature.");
+ lua_pushboolean(ls, false);
+ return 1;
+ }
+ dungeon_feature_type replace = _get_lua_feature(ls, 6);
+ if (!replace)
+ {
+ luaL_argerror(ls, 6, "Invalid feature.");
+ lua_pushboolean(ls, false);
+ return 1;
+ }
+
+ _clamp_to_bounds(x, y);
+ bool found = false;
+ while (in_bounds(x, y))
+ {
+ if (grd[x][y] == search)
+ {
+ grd[x][y] = replace;
+ found = true;
+ break;
+ }
+
+ x += dx;
+ y += dy;
+ }
+
+ lua_pushboolean(ls, found);
+ return 1;
+}
+
+static int dgn_replace_random(lua_State *ls)
+{
+ dungeon_feature_type search = _get_lua_feature(ls, 1);
+ if (!search)
+ {
+ luaL_argerror(ls, 1, "Invalid feature.");
+ return 0;
+ }
+ dungeon_feature_type replace = _get_lua_feature(ls, 2);
+ if (!replace)
+ {
+ luaL_argerror(ls, 2, "Invalid feature.");
+ return 0;
+ }
+
+ int x, y;
+ do
+ {
+ x = random2(GXM);
+ y = random2(GYM);
+ }
+ while (grd[x][y] != search);
+
+ grd[x][y] = replace;
+
+ return 0;
+}
+
+static int dgn_spotty_level(lua_State *ls)
+{
+ bool seeded = lua_toboolean(ls, 1);
+ int iterations = luaL_checkint(ls, 2);
+ bool boxy = lua_toboolean(ls, 3);
+
+ spotty_level(seeded, iterations, boxy);
+ return 0;
+}
+
+static int dgn_smear_feature(lua_State *ls)
+{
+ int iterations = luaL_checkint(ls, 1);
+ bool boxy = lua_toboolean(ls, 2);
+ dungeon_feature_type feat = _get_lua_feature(ls, 3);
+ if (!feat)
+ {
+ luaL_argerror(ls, 3, "Invalid feature.");
+ return 0;
+ }
+
+ int x1 = luaL_checkint(ls, 4);
+ int y1 = luaL_checkint(ls, 5);
+ int x2 = luaL_checkint(ls, 6);
+ int y2 = luaL_checkint(ls, 7);
+
+ _clamp_to_bounds(x1, y1);
+ _clamp_to_bounds(x2, y2);
+
+ smear_feature(iterations, boxy, feat, x1, y1, x2, y2);
+
+ return 0;
+}
+
+static int dgn_count_feature_in_box(lua_State *ls)
+{
+ int x1 = luaL_checkint(ls, 1);
+ int y1 = luaL_checkint(ls, 2);
+ int x2 = luaL_checkint(ls, 3);
+ int y2 = luaL_checkint(ls, 4);
+ dungeon_feature_type feat = _get_lua_feature(ls, 5);
+ if (!feat)
+ {
+ luaL_argerror(ls, 5, "Invalid feature.");
+ lua_pushnil(ls);
+ return 1;
+ }
+
+ lua_pushnumber(ls, count_feature_in_box(x1, y1, x2, y2, feat));
+ return 1;
+}
+
+static int dgn_count_antifeature_in_box(lua_State *ls)
+{
+ int x1 = luaL_checkint(ls, 1);
+ int y1 = luaL_checkint(ls, 2);
+ int x2 = luaL_checkint(ls, 3);
+ int y2 = luaL_checkint(ls, 4);
+ dungeon_feature_type feat = _get_lua_feature(ls, 5);
+ if (!feat)
+ {
+ luaL_argerror(ls, 5, "Invalid feature.");
+ lua_pushnil(ls);
+ return 1;
+ }
+
+ lua_pushnumber(ls, count_antifeature_in_box(x1, y1, x2, y2, feat));
+ return 1;
+}
+
+static int dgn_count_neighbours(lua_State *ls)
+{
+ int x = luaL_checkint(ls, 1);
+ int y = luaL_checkint(ls, 2);
+ dungeon_feature_type feat = _get_lua_feature(ls, 3);
+ if (!feat)
+ {
+ luaL_argerror(ls, 3, "Invalid feature.");
+ lua_pushnil(ls);
+ return 1;
+ }
+
+ lua_pushnumber(ls, count_neighbours(x, y, feat));
+ return 1;
+}
+
+static int dgn_join_the_dots(lua_State *ls)
+{
+ int from_x = luaL_checkint(ls, 1);
+ int from_y = luaL_checkint(ls, 2);
+ int to_x = luaL_checkint(ls, 3);
+ int to_y = luaL_checkint(ls, 4);
+ // TODO enne - push map masks to lua?
+ unsigned map_mask = MMT_VAULT;
+ bool early_exit = lua_toboolean(ls, 5);
+
+ coord_def from(from_x, from_y);
+ coord_def to(to_x, to_y);
+
+ bool ret = join_the_dots(from, to, map_mask, early_exit);
+ lua_pushboolean(ls, ret);
+
+ return 1;
+}
+
static const struct luaL_reg dgn_lib[] =
{
{ "default_depth", dgn_default_depth },
@@ -1716,22 +2098,40 @@ static const struct luaL_reg dgn_lib[] =
{ "register_listener", dgn_register_listener },
{ "remove_listener", dgn_remove_listener },
{ "remove_marker", dgn_remove_marker },
- { "num_matching_markers", dgn_num_matching_markers},
+ { "num_matching_markers", dgn_num_matching_markers },
{ "feature_desc", dgn_feature_desc },
{ "feature_desc_at", dgn_feature_desc_at },
{ "item_from_index", dgn_item_from_index },
{ "mons_from_index", dgn_mons_from_index },
- { "change_level_flags", dgn_change_level_flags},
- { "change_branch_flags", dgn_change_branch_flags},
- { "get_floor_colour", dgn_get_floor_colour},
- { "get_rock_colour", dgn_get_rock_colour},
- { "change_floor_colour", dgn_change_floor_colour},
- { "change_rock_colour", dgn_change_rock_colour},
- { "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},
+ { "change_level_flags", dgn_change_level_flags },
+ { "change_branch_flags", dgn_change_branch_flags },
+ { "get_floor_colour", dgn_get_floor_colour },
+ { "get_rock_colour", dgn_get_rock_colour },
+ { "change_floor_colour", dgn_change_floor_colour },
+ { "change_rock_colour", dgn_change_rock_colour },
+ { "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 },
+
+ // building routines
+ { "fill_area", dgn_fill_area },
+ { "replace_area", dgn_replace_area },
+ { "octa_room", dgn_octa_room },
+ { "make_pillars", dgn_make_pillars },
+ { "make_square", dgn_make_square },
+ { "make_rounded_square", dgn_make_rounded_square },
+ { "make_circle", dgn_make_circle },
+ { "in_bounds", dgn_in_bounds },
+ { "replace_first", dgn_replace_first },
+ { "replace_random", dgn_replace_random },
+ { "spotty_level", dgn_spotty_level },
+ { "smear_feature", dgn_smear_feature },
+ { "count_feature_in_box", dgn_count_feature_in_box },
+ { "count_antifeature_in_box", dgn_count_antifeature_in_box },
+ { "count_neighbours", dgn_count_neighbours },
+ { "join_the_dots", dgn_join_the_dots },
{ NULL, NULL }
};