From 9a1e7565ec8802a38a9649744920923fc262dff7 Mon Sep 17 00:00:00 2001 From: ennewalker Date: Thu, 22 May 2008 13:18:50 +0000 Subject: 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 --- crawl-ref/source/clua.cc | 53 +++++ crawl-ref/source/dat/layout.des | 293 ++++----------------------- crawl-ref/source/dungeon.cc | 111 ++++++----- crawl-ref/source/dungeon.h | 29 +++ crawl-ref/source/luadgn.cc | 424 ++++++++++++++++++++++++++++++++++++++-- 5 files changed, 591 insertions(+), 319 deletions(-) (limited to 'crawl-ref') 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 #include +#include #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 } }; -- cgit v1.2.3-54-g00ecf