From f8f1e6fb68e2cfd7d725f4fdde94d6d45545f30b Mon Sep 17 00:00:00 2001 From: Enne Walker Date: Mon, 2 Nov 2009 08:51:09 -0500 Subject: Lua builder funcs act on map_lines, not grd. This lets regular vaults use the same Lua functions that layout vaults do. Convert functions in l_dgnbld that acted on grd. Update layout vaults to use these new functions. Also, remove l_dgn_bf, as all of its functionality is now in l_dgnbld. --- crawl-ref/source/Crawl.xcodeproj/project.pbxproj | 6 - crawl-ref/source/MSVC/crawl.vcproj | 4 - crawl-ref/source/cluautil.h | 4 +- crawl-ref/source/dat/entry.des | 4 +- crawl-ref/source/dat/layout.des | 312 +++++---- crawl-ref/source/dlua.cc | 2 - crawl-ref/source/l_dgn_bf.cc | 225 ------ crawl-ref/source/l_dgnbld.cc | 845 ++++++++++++++++------- crawl-ref/source/makefile.obj | 1 - crawl-ref/source/mapdef.cc | 81 ++- crawl-ref/source/mapdef.h | 11 + 11 files changed, 882 insertions(+), 613 deletions(-) delete mode 100644 crawl-ref/source/l_dgn_bf.cc (limited to 'crawl-ref') diff --git a/crawl-ref/source/Crawl.xcodeproj/project.pbxproj b/crawl-ref/source/Crawl.xcodeproj/project.pbxproj index 49b76aeeb4..5b183caf87 100644 --- a/crawl-ref/source/Crawl.xcodeproj/project.pbxproj +++ b/crawl-ref/source/Crawl.xcodeproj/project.pbxproj @@ -412,7 +412,6 @@ B0F01D31108DDEBF00A53656 /* dlua.cc in Sources */ = {isa = PBXBuildFile; fileRef = B0F01D20108DDEBF00A53656 /* dlua.cc */; }; B0F01D32108DDEBF00A53656 /* l_crawl.cc in Sources */ = {isa = PBXBuildFile; fileRef = B0F01D22108DDEBF00A53656 /* l_crawl.cc */; }; B0F01D33108DDEBF00A53656 /* l_debug.cc in Sources */ = {isa = PBXBuildFile; fileRef = B0F01D23108DDEBF00A53656 /* l_debug.cc */; }; - B0F01D34108DDEBF00A53656 /* l_dgn_bf.cc in Sources */ = {isa = PBXBuildFile; fileRef = B0F01D24108DDEBF00A53656 /* l_dgn_bf.cc */; }; B0F01D35108DDEBF00A53656 /* l_dgn.cc in Sources */ = {isa = PBXBuildFile; fileRef = B0F01D25108DDEBF00A53656 /* l_dgn.cc */; }; B0F01D36108DDEBF00A53656 /* l_dgnbld.cc in Sources */ = {isa = PBXBuildFile; fileRef = B0F01D26108DDEBF00A53656 /* l_dgnbld.cc */; }; B0F01D37108DDEBF00A53656 /* l_dgnevt.cc in Sources */ = {isa = PBXBuildFile; fileRef = B0F01D27108DDEBF00A53656 /* l_dgnevt.cc */; }; @@ -427,7 +426,6 @@ B0F01D40108DDEBF00A53656 /* dlua.cc in Sources */ = {isa = PBXBuildFile; fileRef = B0F01D20108DDEBF00A53656 /* dlua.cc */; }; B0F01D41108DDEBF00A53656 /* l_crawl.cc in Sources */ = {isa = PBXBuildFile; fileRef = B0F01D22108DDEBF00A53656 /* l_crawl.cc */; }; B0F01D42108DDEBF00A53656 /* l_debug.cc in Sources */ = {isa = PBXBuildFile; fileRef = B0F01D23108DDEBF00A53656 /* l_debug.cc */; }; - B0F01D43108DDEBF00A53656 /* l_dgn_bf.cc in Sources */ = {isa = PBXBuildFile; fileRef = B0F01D24108DDEBF00A53656 /* l_dgn_bf.cc */; }; B0F01D44108DDEBF00A53656 /* l_dgn.cc in Sources */ = {isa = PBXBuildFile; fileRef = B0F01D25108DDEBF00A53656 /* l_dgn.cc */; }; B0F01D45108DDEBF00A53656 /* l_dgnbld.cc in Sources */ = {isa = PBXBuildFile; fileRef = B0F01D26108DDEBF00A53656 /* l_dgnbld.cc */; }; B0F01D46108DDEBF00A53656 /* l_dgnevt.cc in Sources */ = {isa = PBXBuildFile; fileRef = B0F01D27108DDEBF00A53656 /* l_dgnevt.cc */; }; @@ -1137,7 +1135,6 @@ B0F01D21108DDEBF00A53656 /* dlua.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dlua.h; sourceTree = ""; }; B0F01D22108DDEBF00A53656 /* l_crawl.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = l_crawl.cc; sourceTree = ""; }; B0F01D23108DDEBF00A53656 /* l_debug.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = l_debug.cc; sourceTree = ""; }; - B0F01D24108DDEBF00A53656 /* l_dgn_bf.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = l_dgn_bf.cc; sourceTree = ""; }; B0F01D25108DDEBF00A53656 /* l_dgn.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = l_dgn.cc; sourceTree = ""; }; B0F01D26108DDEBF00A53656 /* l_dgnbld.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = l_dgnbld.cc; sourceTree = ""; }; B0F01D27108DDEBF00A53656 /* l_dgnevt.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = l_dgnevt.cc; sourceTree = ""; }; @@ -1488,7 +1485,6 @@ B0F01D22108DDEBF00A53656 /* l_crawl.cc */, B0F01D23108DDEBF00A53656 /* l_debug.cc */, B0F01D25108DDEBF00A53656 /* l_dgn.cc */, - B0F01D24108DDEBF00A53656 /* l_dgn_bf.cc */, B0F01D26108DDEBF00A53656 /* l_dgnbld.cc */, B0F01D27108DDEBF00A53656 /* l_dgnevt.cc */, B0F01D28108DDEBF00A53656 /* l_dgngrd.cc */, @@ -2251,7 +2247,6 @@ B0F01D41108DDEBF00A53656 /* l_crawl.cc in Sources */, B0F01D42108DDEBF00A53656 /* l_debug.cc in Sources */, B0F01D44108DDEBF00A53656 /* l_dgn.cc in Sources */, - B0F01D43108DDEBF00A53656 /* l_dgn_bf.cc in Sources */, B0F01D45108DDEBF00A53656 /* l_dgnbld.cc in Sources */, B0F01D46108DDEBF00A53656 /* l_dgnevt.cc in Sources */, B0F01D47108DDEBF00A53656 /* l_dgngrd.cc in Sources */, @@ -2389,7 +2384,6 @@ B0F01D32108DDEBF00A53656 /* l_crawl.cc in Sources */, B0F01D33108DDEBF00A53656 /* l_debug.cc in Sources */, B0F01D35108DDEBF00A53656 /* l_dgn.cc in Sources */, - B0F01D34108DDEBF00A53656 /* l_dgn_bf.cc in Sources */, B0F01D36108DDEBF00A53656 /* l_dgnbld.cc in Sources */, B0F01D37108DDEBF00A53656 /* l_dgnevt.cc in Sources */, B0F01D38108DDEBF00A53656 /* l_dgngrd.cc in Sources */, diff --git a/crawl-ref/source/MSVC/crawl.vcproj b/crawl-ref/source/MSVC/crawl.vcproj index a4f46ef72e..83ecc61d16 100644 --- a/crawl-ref/source/MSVC/crawl.vcproj +++ b/crawl-ref/source/MSVC/crawl.vcproj @@ -1244,10 +1244,6 @@ RelativePath="..\l_dgn.cc" > - - diff --git a/crawl-ref/source/cluautil.h b/crawl-ref/source/cluautil.h index 0f02555750..8b3a91937b 100644 --- a/crawl-ref/source/cluautil.h +++ b/crawl-ref/source/cluautil.h @@ -168,8 +168,10 @@ branch_type br = str_to_branch(branch_name); \ if (lev == LEVEL_DUNGEON && br == NUM_BRANCHES) \ luaL_error(ls, "Expected branch name"); -#define MAP(ls, n, var) \ +#define MAP(ls, n, var) \ map_def *var = *(map_def **) luaL_checkudata(ls, n, MAP_METATABLE) +#define LINES(ls, n, var) \ +map_lines &var = (*(map_def **) luaL_checkudata(ls, n, MAP_METATABLE))->map #define DEVENT(ls, n, var) \ dgn_event *var = *(dgn_event **) luaL_checkudata(ls, n, DEVENT_METATABLE) #define MAPMARKER(ls, n, var) \ diff --git a/crawl-ref/source/dat/entry.des b/crawl-ref/source/dat/entry.des index f450e26af3..11f4c40f99 100644 --- a/crawl-ref/source/dat/entry.des +++ b/crawl-ref/source/dat/entry.des @@ -4934,14 +4934,14 @@ TAGS: entry no_monster_gen FTILE: '[({ = floor_sand_stone SUBST: ' = . {{ - map_octa_room({ + octa_room({ oblique = crawl.random_range(3,7), replace = '.', outside = 'W', inside = '.' }) if crawl.coinflip() then - map_smear({iterations=20, smear='x', onto='.W', boxy=true}) + smear_map({iterations=20, smear='x', onto='.W', boxy=true}) end }} SUBST: W:xw diff --git a/crawl-ref/source/dat/layout.des b/crawl-ref/source/dat/layout.des index 0166e93227..64fe16d2be 100644 --- a/crawl-ref/source/dat/layout.des +++ b/crawl-ref/source/dat/layout.des @@ -7,14 +7,19 @@ ############################################################################### {{ - function dgn.random_room_point(room) - return dgn.point(room.x1 + crawl.random2(room.x2 - room.x1), - room.y1 + crawl.random2(room.y2 - room.y1)) - end + -- Call func num times around a circle of radius centered at (x, y) + function apply_circle(x, y, num, radius, scale_x, scale_y, func) + radius = math.floor(radius) + for n = 1, num do + local rad = n * 2 * math.pi / num + + local rx = math.floor(math.cos(rad) * radius * scale_x + 0.5) + local ry = math.floor(math.sin(rad) * radius * scale_y + 0.5) + + func(x + rx, y + ry) + end + end - function dgn.join_the_dots_p(start, finish) - return dgn.join_the_dots(start.x, start.y, finish.x, finish.y) - end }} ############################################################## @@ -26,20 +31,21 @@ NAME: layout_forbidden_donut ORIENT: encompass TAGS: layout allow_dup - {{ local gxm, gym = dgn.max_bounds() - local wall = dgn.feature_number("rock_wall") - local floor = dgn.feature_number("floor") - dgn.fill_area(0, 0, gxm - 1, gym - 1, wall) + extend_map{width=gxm, height=gym, fill='x'} + fill_area{fill='x'} local width = (10 - crawl.random2(7)) + local floor = '.' + local wall = 'x' + -- construct donut - 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) + fill_area{x1=10, y1=10, x2=gxm-10, y2=10+width, fill=floor} + fill_area{x1=10, y1=60-width, x2=gxm-10, y2=gym-10, fill=floor} + fill_area{x1=10, y1=10, x2=10+width, y2=gym-10, fill=floor} + fill_area{x1=60-width, y1=10, x2=gxm-10, y2=gym-10, fill=floor} local spotty = crawl.coinflip() local smears = crawl.random2(300) @@ -48,22 +54,22 @@ TAGS: layout allow_dup if crawl.coinflip() then local width2 = 1 + crawl.random2(5) - 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) + fill_area{x1=10, y1=gym/2-width2, x2=gxm-10, y2=gym/2+width2, fill=floor} + fill_area{x1=gxm/2-width2, y1=10, x2=gxm/2+width2, y2=gym-10, fill=floor} -- sometimes add a small octagon room - if crawl.coinflip() and crawl.random2(15) > 7 then - local oblique = 0 + if crawl.coinflip() then + local obl = 0 if crawl.coinflip() then - oblique = 5 + crawl.random2(20) + obl = 5 + crawl.random2(20) end - local feature_name = crawl.random_element({ - ["floor"] = 5, - ["deep_water"] = 1, - ["lava"] = 1, + local fill = crawl.random_element({ + ["."] = 10, + ["w"] = 5, + ["l"] = 1, }) - dgn.octa_room(25, 25, gxm - 25, gym - 25, oblique, feature_name) + octa_room{x1=25, y1=25, x2=gxm-25, y2=gym-25, oblique=obl, replace='x', inside=fill} -- decrease spotty chance spotty = crawl.one_chance_in(5) @@ -74,10 +80,10 @@ TAGS: layout allow_dup local smear_boxy = crawl.coinflip() if spotty then - dgn.spotty_level(true, 0, spotty_boxy) + spotty_map{boxy=spotty_boxy} end if not spotty and crawl.one_chance_in(4) or spotty then - dgn.smear_feature(smears, smear_boxy, wall, 0, 0, gxm - 1, gym - 1) + smear_map{iterations=smears, smear='x', onto='.', boxy=smear_boxy} end }} MAP @@ -94,45 +100,45 @@ ORIENT: encompass TAGS: layout allow_dup {{ - local width = 5 - crawl.random2(5) - local height = 5 - crawl.random2(5) - local gxm, gym = dgn.max_bounds() + extend_map{width = gxm, height = gym, fill = 'x'} - local wall = dgn.feature_number("rock_wall") - local floor = dgn.feature_number("floor") + local floor = '.' + local wall = 'x' + + local width = 5 - crawl.random2(5) + local height = 5 - crawl.random2(5) -- Include a small possibility of adding windows around the cross. -- This layout can get used with spotty_level, so don't make this -- chance too large as lava/water prevents that from happening. local window = crawl.one_chance_in(20) - if window or crawl.one_chance_in(20) then + if window then if crawl.coinflip() then - wall = dgn.feature_number("lava") + wall = 'l' else - wall = dgn.feature_number("deep_water") + wall = 'w' end end - -- fill with rock - dgn.fill_area(0, 0, gxm-1, gym-1, wall) + fill_area{fill=wall} -- create window if window then - local clear = dgn.feature_number("clear_rock_wall") - 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) + local clear = 'm' + fill_area{x1=10, y1=gym/2-height-1, x2=gxm-10, y2=gym/2-height-1, fill=clear} + fill_area{x1=10, y1=gym/2+height+1, x2=gxm-10, y2=gym/2+height+1, fill=clear} + fill_area{x1=gxm/2-width-1, y1=10, x2=gxm/2-width-1, y2=gym-10, fill=clear} + fill_area{x1=gxm/2+width+1, y1=10, x2=gxm/2+width+1, y2=gym-10, fill=clear} end -- create a cross - 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) + fill_area{x1=10, y1=gym/2-height, x2=gxm-10, y2=gym/2+height, fill=floor} + fill_area{x1=gxm/2-width, y1=10, x2=gxm/2+width, y2=gym-10, fill=floor} if not crawl.one_chance_in(4) then - dgn.spotty_level(true, 0, crawl.coinflip()) + spotty_map{boxy = crawl.coinflip()} end }} MAP @@ -151,58 +157,83 @@ ORIENT: encompass TAGS: layout allow_dup {{ + -- Step 1: Big octagon. + local gxm, gym = dgn.max_bounds() - local wall = dgn.feature_number("rock_wall") - local floor = dgn.feature_number("floor") + extend_map{width = gxm, height = gym, fill = 'x'} + fill_area{fill = 'x'} local oblique = 10 + crawl.random2(20) - - dgn.fill_area(0, 0, gxm - 1, gym - 1, "rock_wall") - dgn.octa_room(10, 10, gxm - 10, gym - 10, oblique, "floor") - - local smear = crawl.coinflip() - if smear then - local iterations = 100 + crawl.random2(500 - oblique * 12) - dgn.smear_feature(iterations, false, wall, 0, 0, gxm - 1, gym - 1) + octa_room{ + x1 = 10, + y1 = 10, + x2 = gxm-10, + y2 = gym-10, + oblique = oblique, + replace = 'x', + inside = '.'} + + local do_smear = crawl.coinflip() + if do_smear then + local iterations = 100 + crawl.random2(800) + smear_map{iterations = iterations, boxy = false} + + --Fill in disconnected zones now, prior to adding the stairs. + --Temporarily set a (passable) unique symbol in the middle of the map, + --to guarantee everything is connected to it after smearing. + mapgrd[gxm/2][gym/2] = '@' + fill_disconnected{wanted = '@'} + mapgrd[gxm/2][gym/2] = '.' end -- Step 2: Add pillars -- pillar types and relative weights local pillar_fill = { - ["rock_wall"] = 15, - ["green_crystal_wall"] = 5, - ["metal_wall"] = 4, - ["clear_rock_wall"] = 3, - ["deep_water"] = 2, - ["lava"] = 1, + ["x"] = 15, + ["b"] = 5, + ["v"] = 4, + ["m"] = 3, + ["w"] = 2, + ["l"] = 1, } - local fill = dgn.feature_number(crawl.random_element(pillar_fill)) + if (you.in_branch("lair")) then + pillar_fill["t"] = 15 + end -- Potential pillar drawing routines local pillar_func = { - dgn.make_circle, - dgn.make_square, - dgn.make_rounded_square - } + make_circle, + make_diamond, + make_square, + make_rounded_square} -- Pillar size params -- NOTE: Be careful about tweaking the ranges here. Pillars that are -- too large, close, or large in number can entirely surround the center. - local type = crawl.random2(#pillar_func) + 1 + + local pfunc = pillar_func[crawl.random2(#pillar_func) + 1] + pfunc = make_diamond local num = 3 + crawl.random2(9) local pillar_radius = 1 + crawl.random2(3) local circle_radius = 2 + crawl.random2(6) + pillar_radius * 2 + num / 2 - + local fill = crawl.random_element(pillar_fill) -- beautification hack: no "circle" pillars of radius 1 - if type == 1 and pillar_radius == 1 then - fill = dgn.feature_number("stone_arch") + if pfunc == make_circle and pillar_radius == 1 then + fill = crawl.random_element({"G", "X", "t"}) + kfeat("X = stone_arch") end -- Finally, make the pillars - dgn.make_pillars(gxm/2, gym/2, num, 1, circle_radius, pillar_radius, - pillar_func[type], fill) + local make_pillar = function(x, y) + return pfunc({ + x = x, + y = y, + radius = pillar_radius, + fill = fill}) + end + apply_circle(gxm/2, gym/2, num, circle_radius, 1, 1, make_pillar) -- Step 3: Create stairs @@ -220,44 +251,57 @@ TAGS: layout allow_dup down_loc = crawl.random2(6) end - local up_stairs = { - dgn.feature_number("stone_stairs_up_i"), - dgn.feature_number("stone_stairs_up_ii"), - dgn.feature_number("stone_stairs_up_iii"), - } - local down_stairs = { - dgn.feature_number("stone_stairs_down_i"), - dgn.feature_number("stone_stairs_down_ii"), - dgn.feature_number("stone_stairs_down_iii"), - } + local up_stairs = {"{", "(", "["} + local down_stairs = {"}", ")", "]"} local full_stair_set = {[up_loc] = up_stairs, [down_loc] = down_stairs} for loc, stair_list in pairs (full_stair_set) do for i = 1, #stair_list do local st = stair_list[i] - local ret = true if loc == 0 then - dgn.replace_random(floor, stair_list[i]) + replace_random({find = ".", replace = st, required = true}) elseif loc == 1 then - dgn.grid(gxm/2 + i - 2, gym/2 + 1 - math.abs(i - 2), st) + mapgrd[gxm/2 + i - 2][gym/2 + 1 - math.abs(i - 2)] = st elseif loc == 2 then - ret = dgn.replace_first(gxm/2 + i-2, 0, 0, 1, floor, st) + replace_first({ + required = true, + x = gxm/2 + i - 2, + y = 1, + xdir = 0, + ydir = 1, + find = ".", + replace = st}) elseif loc == 3 then - ret = dgn.replace_first(gxm - 1, gym/2 + i-2, -1, 0, floor, st) + replace_first({ + required = true, + x = gxm, + y = gym/2 + i - 2, + xdir = -1, + ydir = 0, + find = ".", + replace = st}) elseif loc == 4 then - ret = dgn.replace_first(gxm/2 + i-2, gym - 1, 0, -1, floor, st) + replace_first({ + required = true, + x = gxm/2 + i - 2, + y = gym, + xdir = 0, + ydir = -1, + find = ".", + replace = st}) elseif loc == 5 then - ret = dgn.replace_first(0, gym/2 + i-2, 1, 0, floor, st) + replace_first({ + required = true, + x = 1, + y = gym/2 + i - 2, + xdir = 1, + ydir = 0, + find = ".", + replace = st}) end - - assert(ret) end end - - if smear then - dgn.fill_disconnected_zones(0, 0, gxm - 1, gym - 1, wall) - end }} MAP ENDMAP @@ -271,8 +315,22 @@ NAME: layout_rooms ORIENT: encompass TAGS: layout allow_dup {{ - local wall = dgn.feature_number("rock_wall") - local floor = dgn.feature_number("floor") + function random_room_point(room) + return dgn.point(room.x1 + crawl.random2(room.x2 - room.x1), + room.y1 + crawl.random2(room.y2 - room.y1)) + end + + function join_the_dots_p(start, finish) + return join_the_dots({ + x1 = start.x, + y1 = start.y, + x2 = finish.x, + y2 = finish.y}) + end + + local gxm, gym = dgn.max_bounds() + extend_map{width = gxm, height = gym, fill = 'x'} + fill_area{fill = 'x'} local num_rooms = 30 + crawl.random2(90) local exclusive = not crawl.one_chance_in(10) @@ -281,36 +339,46 @@ TAGS: layout allow_dup local rooms = {} for i = 0, num_rooms do - local new_room = { - x1 = 10 + crawl.random2(50), - y1 = 10 + crawl.random2(40) - } - new_room.x2 = new_room.x1 + 2 + crawl.random2(8) - new_room.y2 = new_room.y1 + 2 + crawl.random2(8) - - local not_walls = dgn.count_antifeature_in_box(new_room.x1 - 1, - new_room.y1 - 1, new_room.x2 + 1, new_room.y2 + 1, wall) - if (not exclusive or not_walls == 0) then - dgn.replace_area(new_room.x1, new_room.y1, new_room.x2, - new_room.y2, wall, floor); - - if #rooms > 0 and not exclusive2 then - dgn.join_the_dots_p(dgn.random_room_point(new_room), - dgn.random_room_point(rooms[#rooms])) - end + local new_room = { + x1 = 10 + crawl.random2(50), + y1 = 10 + crawl.random2(40) + } + new_room.x2 = new_room.x1 + 2 + crawl.random2(8) + new_room.y2 = new_room.y1 + 2 + crawl.random2(8) + + local not_walls = count_antifeature_in_box({ + x1 = new_room.x1, + y1 = new_room.y1, + x2 = new_room.x2, + y2 = new_room.y2, + feat = "x"}) + + if (not exclusive or not_walls == 0) then + replace_area({ + x1 = new_room.x1, + y1 = new_room.y1, + x2 = new_room.x2, + y2 = new_room.y2, + find = "x", + replace = "."}) + + if #rooms > 0 and not exclusive2 then + join_the_dots_p(random_room_point(new_room), + random_room_point(rooms[#rooms])) + end - table.insert(rooms, new_room) - if #rooms >= 30 then - break + table.insert(rooms, new_room) + if #rooms >= 30 then + break + end end - end end if exclusive2 then - for i = 2, #rooms do - dgn.join_the_dots_p(dgn.random_room_point(rooms[i]), - dgn.random_room_point(rooms[i - 1])) - end + for i = 2, #rooms do + join_the_dots_p(random_room_point(rooms[i]), + random_room_point(rooms[i - 1])) + end end }} MAP diff --git a/crawl-ref/source/dlua.cc b/crawl-ref/source/dlua.cc index 24fd13356f..256f3210bf 100644 --- a/crawl-ref/source/dlua.cc +++ b/crawl-ref/source/dlua.cc @@ -296,8 +296,6 @@ void init_dungeon_lua() luaopen_mapmarker(dlua); luaopen_ray(dlua); - register_builder_funcs(dlua); - register_itemlist(dlua); register_monslist(dlua); } diff --git a/crawl-ref/source/l_dgn_bf.cc b/crawl-ref/source/l_dgn_bf.cc deleted file mode 100644 index 1d9ee8e5b0..0000000000 --- a/crawl-ref/source/l_dgn_bf.cc +++ /dev/null @@ -1,225 +0,0 @@ -/* - * File: l_dgn_bf.cc - * Summary: Dungeon lua builder functions. - */ - -#include "AppHdr.h" - -#include "cluautil.h" -#include "l_libs.h" -#include "mapdef.h" -#include "random.h" - -// Return the integer stored in the table (on the stack) with the key name. -// If the key doesn't exist or the value is the wrong type, return defval. -static int _table_int(lua_State *ls, int idx, const char *name, int defval) -{ - lua_pushstring(ls, name); - lua_gettable(ls, idx < 0 ? idx - 1 : idx); - bool nil = lua_isnil(ls, idx); - bool valid = lua_isnumber(ls, idx); - if (!nil && !valid) - luaL_error(ls, "'%s' in table, but not an int.", name); - int ret = (!nil && valid ? luaL_checkint(ls, idx) : defval); - lua_pop(ls, 1); - return (ret); -} - -// Return the character stored in the table (on the stack) with the key name. -// If the key doesn't exist or the value is the wrong type, return defval. -static char _table_char(lua_State *ls, int idx, const char *name, char defval) -{ - lua_pushstring(ls, name); - lua_gettable(ls, idx < 0 ? idx - 1 : idx); - bool nil = lua_isnil(ls, idx); - bool valid = lua_isstring(ls, idx); - if (!nil && !valid) - luaL_error(ls, "'%s' in table, but not a string.", name); - - char ret = defval; - if (!nil && valid) - { - const char *str = lua_tostring(ls, idx); - if (str[0] && !str[1]) - ret = str[0]; - else - luaL_error(ls, "'%s' has more than one character.", name); - } - lua_pop(ls, 1); - return (ret); -} - -// Return the string stored in the table (on the stack) with the key name. -// If the key doesn't exist or the value is the wrong type, return defval. -static const char* _table_str(lua_State *ls, int idx, const char *name, const char *defval) -{ - lua_pushstring(ls, name); - lua_gettable(ls, idx < 0 ? idx - 1 : idx); - bool nil = lua_isnil(ls, idx); - bool valid = lua_isstring(ls, idx); - if (!nil && !valid) - luaL_error(ls, "'%s' in table, but not a string.", name); - const char *ret = (!nil && valid ? lua_tostring(ls, idx) : defval); - lua_pop(ls, 1); - return (ret); -} - -// Return the boolean stored in the table (on the stack) with the key name. -// If the key doesn't exist or the value is the wrong type, return defval. -static bool _table_bool(lua_State *ls, int idx, const char *name, bool defval) -{ - lua_pushstring(ls, name); - lua_gettable(ls, idx < 0 ? idx - 1 : idx); - bool nil = lua_isnil(ls, idx); - bool valid = lua_isboolean(ls, idx); - if (!nil && !valid) - luaL_error(ls, "'%s' in table, but not a bool.", name); - bool ret = (!nil && valid ? lua_toboolean(ls, idx) : defval); - lua_pop(ls, 1); - return (ret); -} - -#define BF_INT(ls, val, def) int val = _table_int(ls, -1, #val, def); -#define BF_CHAR(ls, val, def) char val = _table_char(ls, -1, #val, def); -#define BF_STR(ls, val, def) const char *val = _table_str(ls, -1, #val, def); -#define BF_BOOL(ls, val, def) bool val = _table_bool(ls, -1, #val, def); - -static void bf_octa_room(lua_State *ls, map_lines &lines) -{ - int default_oblique = std::min(lines.width(), lines.height()) / 2 - 1; - BF_INT(ls, oblique, default_oblique); - BF_CHAR(ls, outside, 'x'); - BF_CHAR(ls, inside, '.'); - BF_STR(ls, replace, "."); - - coord_def tl, br; - if (!lines.find_bounds(replace, tl, br)) - return; - - for (rectangle_iterator ri(tl, br); ri; ++ri) - { - const coord_def mc = *ri; - char glyph = lines(mc); - if (replace[0] && !strchr(replace, glyph)) - continue; - - int ob = 0; - ob += std::max(oblique + tl.x - mc.x, 0); - ob += std::max(oblique + mc.x - br.x, 0); - - bool is_inside = (mc.y >= tl.y + ob && mc.y <= br.y - ob); - lines(mc) = is_inside ? inside : outside; - } -} - -static void bf_smear(lua_State *ls, map_lines &lines) -{ - BF_INT(ls, iterations, 1); - BF_CHAR(ls, smear, 'x'); - BF_STR(ls, onto, "."); - BF_BOOL(ls, boxy, false); - - const int max_test_per_iteration = 10; - int sanity = 0; - int max_sanity = iterations * max_test_per_iteration; - - for (int i = 0; i < iterations; i++) - { - bool diagonals, straights; - coord_def mc; - - do - { - do - { - sanity++; - mc.x = random_range(1, lines.width() - 2); - mc.y = random_range(1, lines.height() - 2); - } - while (onto[0] && !strchr(onto, lines(mc))); - - // Prevent too many iterations. - if (sanity > max_sanity) - return; - - // Is there a "smear" feature along the diagonal from mc? - diagonals = lines(coord_def(mc.x+1, mc.y+1)) == smear || - lines(coord_def(mc.x-1, mc.y+1)) == smear || - lines(coord_def(mc.x-1, mc.y-1)) == smear || - lines(coord_def(mc.x+1, mc.y-1)) == smear; - - // Is there a "smear" feature up, down, left, or right from mc? - straights = lines(coord_def(mc.x+1, mc.y)) == smear || - lines(coord_def(mc.x-1, mc.y)) == smear || - lines(coord_def(mc.x, mc.y+1)) == smear || - lines(coord_def(mc.x, mc.y-1)) == smear; - } - while (!straights && (boxy || !diagonals)); - - lines(mc) = smear; - } -} - -static void bf_extend(lua_State *ls, map_lines &lines) -{ - BF_INT(ls, height, 1); - BF_INT(ls, width, 1); - BF_CHAR(ls, fill, 'x'); - - lines.extend(width, height, fill); -} - -typedef void (*bf_func)(lua_State *ls, map_lines &lines); -struct bf_entry -{ - const char* name; - bf_func func; -}; - -// Create a separate list of builder funcs so that we can automatically -// generate a list of closures for them, rather than individually -// and explicitly exposing them to the dgn namespace. -static struct bf_entry bf_map[] = -{ - { "map_octa_room", &bf_octa_room }, - { "map_smear", &bf_smear }, - { "map_extend", &bf_extend } -}; - -static int dgn_call_builder_func(lua_State *ls) -{ - // This function gets called for all the builder functions that - // operate on map_lines. - - MAP(ls, 1, map); - if (!lua_istable(ls, 2) && !lua_isfunction(ls, 2)) - return luaL_argerror(ls, 2, "Expected table"); - - bf_func *func = (bf_func *)lua_topointer(ls, lua_upvalueindex(1)); - if (!func) - return luaL_error(ls, "Expected C function in closure upval"); - - // Put the table on top. - lua_settop(ls, 2); - - // Call the builder func itself. - (*func)(ls, map->map); - - return (0); -} - -void register_builder_funcs(lua_State *ls) -{ - lua_getglobal(ls, "dgn"); - - const size_t num_entries = sizeof(bf_map) / sizeof(bf_entry); - for (size_t i = 0; i < num_entries; i++) - { - // Push a closure with the C function into the dgn table. - lua_pushlightuserdata(ls, &bf_map[i].func); - lua_pushcclosure(ls, &dgn_call_builder_func, 1); - lua_setfield(ls, -2, bf_map[i].name); - } - - lua_pop(ls, 1); -} diff --git a/crawl-ref/source/l_dgnbld.cc b/crawl-ref/source/l_dgnbld.cc index 6a3d0da004..61de206aee 100644 --- a/crawl-ref/source/l_dgnbld.cc +++ b/crawl-ref/source/l_dgnbld.cc @@ -8,360 +8,709 @@ #include #include "cluautil.h" -#include "l_libs.h" - #include "coord.h" #include "dungeon.h" +#include "l_libs.h" +#include "mapdef.h" #include "random.h" -// Return a metatable for a point on the map_lines grid. -static int dgn_mapgrd_table(lua_State *ls) -{ - MAP(ls, 1, map); +static const char *traversable_glyphs = + ".+=w@{}()[]<>BC^~TUVY$%*|Odefghijk0123456789"; - map_def **mapref = clua_new_userdata(ls, MAPGRD_METATABLE); - *mapref = map; +static const char *exit_glyphs = "{}()[]<>@"; - return (1); +// Return the integer stored in the table (on the stack) with the key name. +// If the key doesn't exist or the value is the wrong type, return defval. +static int _table_int(lua_State *ls, int idx, const char *name, int defval) +{ + if (!lua_istable(ls, idx)) + return defval; + lua_pushstring(ls, name); + lua_gettable(ls, idx < 0 ? idx - 1 : idx); + bool nil = lua_isnil(ls, idx); + bool valid = lua_isnumber(ls, idx); + if (!nil && !valid) + luaL_error(ls, "'%s' in table, but not an int.", name); + int ret = (!nil && valid ? luaL_checkint(ls, idx) : defval); + lua_pop(ls, 1); + return (ret); } -static int dgn_width(lua_State *ls) +// Return the character stored in the table (on the stack) with the key name. +// If the key doesn't exist or the value is the wrong type, return defval. +static char _table_char(lua_State *ls, int idx, const char *name, char defval) { - MAP(ls, 1, map); - - lua_pushnumber(ls, map->map.width()); - return (1); + if (!lua_istable(ls, idx)) + return defval; + lua_pushstring(ls, name); + lua_gettable(ls, idx < 0 ? idx - 1 : idx); + bool nil = lua_isnil(ls, idx); + bool valid = lua_isstring(ls, idx); + if (!nil && !valid) + luaL_error(ls, "'%s' in table, but not a string.", name); + + char ret = defval; + if (!nil && valid) + { + const char *str = lua_tostring(ls, idx); + if (str[0] && !str[1]) + ret = str[0]; + else + luaL_error(ls, "'%s' has more than one character.", name); + } + lua_pop(ls, 1); + return (ret); } -static int dgn_height(lua_State *ls) +// Return the string stored in the table (on the stack) with the key name. +// If the key doesn't exist or the value is the wrong type, return defval. +static const char* _table_str(lua_State *ls, int idx, const char *name, const char *defval) { - MAP(ls, 1, map); - - lua_pushnumber(ls, map->map.height()); - return (1); + if (!lua_istable(ls, idx)) + return defval; + lua_pushstring(ls, name); + lua_gettable(ls, idx < 0 ? idx - 1 : idx); + bool nil = lua_isnil(ls, idx); + bool valid = lua_isstring(ls, idx); + if (!nil && !valid) + luaL_error(ls, "'%s' in table, but not a string.", name); + const char *ret = (!nil && valid ? lua_tostring(ls, idx) : defval); + lua_pop(ls, 1); + return (ret); } -static void _clamp_to_bounds(int &x, int &y, bool edge_ok = false) +// Return the boolean stored in the table (on the stack) with the key name. +// If the key doesn't exist or the value is the wrong type, return defval. +static bool _table_bool(lua_State *ls, int idx, const char *name, bool defval) { - const int edge_offset = edge_ok ? 0 : 1; - x = std::min(std::max(x, X_BOUND_1 + edge_offset), X_BOUND_2 - edge_offset); - y = std::min(std::max(y, Y_BOUND_1 + edge_offset), Y_BOUND_2 - edge_offset); + if (!lua_istable(ls, idx)) + return defval; + lua_pushstring(ls, name); + lua_gettable(ls, idx < 0 ? idx - 1 : idx); + bool nil = lua_isnil(ls, idx); + bool valid = lua_isboolean(ls, idx); + if (!nil && !valid) + luaL_error(ls, "'%s' in table, but not a bool.", name); + bool ret = (!nil && valid ? lua_toboolean(ls, idx) : defval); + lua_pop(ls, 1); + return (ret); } -static int dgn_fill_area(lua_State *ls) +// These macros all assume the table is on the top of the lua stack. +#define TABLE_INT(ls, val, def) int val = _table_int(ls, -1, #val, def); +#define TABLE_CHAR(ls, val, def) char val = _table_char(ls, -1, #val, def); +#define TABLE_STR(ls, val, def) const char *val = _table_str(ls, -1, #val, def); +#define TABLE_BOOL(ls, val, def) bool val = _table_bool(ls, -1, #val, def); + +// Read a set of box coords (x1, y1, x2, y2) from the table. +// Return true if coords are valid. +static bool _coords(lua_State *ls, map_lines &lines, + int &x1, int &y1, int &x2, int &y2, int border = 0) { - 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 = check_lua_feature(ls, 5); - - _clamp_to_bounds(x1, y1); - _clamp_to_bounds(x2, y2); + const int idx = -1; + x1 = _table_int(ls, idx, "x1", 1); + y1 = _table_int(ls, idx, "y1", 1); + x2 = _table_int(ls, idx, "x2", lines.width()); + y2 = _table_int(ls, idx, "y2", lines.height()); + if (x2 < x1) - std::swap(x1, x2); + 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; + x1--; + y1--; + x2--; + y2--; - return 0; + return (x1 + border <= x2 - border && y1 + border <= y2 - border); } -static int dgn_replace_area(lua_State *ls) +// Check if a given coordiante is valid for lines. +static bool _valid_coord(lua_State *ls, map_lines &lines, int x, int y) { - 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 = check_lua_feature(ls, 5); - dungeon_feature_type replace = check_lua_feature(ls, 6); - - // 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); + if (x < 0 || x >= lines.width()) + { + luaL_error(ls, "Invalid x coordinate: %d", x); + return false; + } - for (int y = y1; y <= y2; y++) - for (int x = x1; x <= x2; x++) - if (grd[x][y] == search) - grd[x][y] = replace; + if (y < 0 || y >= lines.height()) + { + luaL_error(ls, "Invalid y coordinate: %d", y); + return false; + } - return 0; + return true; } -static int dgn_octa_room(lua_State *ls) +LUAFN(dgn_count_feature_in_box) { - 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 = check_lua_feature(ls, 6); - - spec_room sr; - sr.tl.x = x1; - sr.br.x = x2; - sr.tl.y = y1; - sr.br.y = y2; - - octa_room(sr, oblique, fill); - - return 0; -} + LINES(ls, 1, lines); -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 = check_lua_feature(ls, 8); - - // [enne] The underscore is for DJGPP's brain damage. - 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); + int x1, y1, x2, y2; + if (!_coords(ls, lines, x1, y1, x2, y2)) + return (0); - 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); + TABLE_STR(ls, feat, ""); - lua_call(ls, 4, 0); - } + coord_def tl(x1, y1); + coord_def br(x2, y2); - return 0; + PLUARET(number, lines.count_feature_in_box(tl, br, feat)); } -static int dgn_make_square(lua_State *ls) +LUAFN(dgn_count_antifeature_in_box) { - 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 = check_lua_feature(ls, 4); + LINES(ls, 1, lines); + + int x1, y1, x2, y2; + if (!_coords(ls, lines, x1, y1, x2, y2)) + return (0); - for (int x = -radius; x <= radius; x++) - for (int y = -radius; y <= radius; y++) - grd[center_x + x][center_y + y] = fill; + TABLE_STR(ls, feat, ""); - return 0; + coord_def tl(x1, y1); + coord_def br(x2, y2); + + int sum = (br.x - tl.x + 1) * (br.y - tl.y + 1); + PLUARET(number, sum - lines.count_feature_in_box(tl, br, feat)); } -static int dgn_make_rounded_square(lua_State *ls) +LUAFN(dgn_count_neighbors) { - 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 = check_lua_feature(ls, 4); + LINES(ls, 1, lines); + + TABLE_STR(ls, feat, ""); + TABLE_INT(ls, x, -1); + TABLE_INT(ls, y, -1); - 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; + if (!_valid_coord(ls, lines, --x, --y)) + return (0); - return 0; + coord_def tl(x-1, y-1); + coord_def br(x+1, y+1); + + PLUARET(number, lines.count_feature_in_box(tl, br, feat)); } -static int dgn_make_circle(lua_State *ls) +LUAFN(dgn_extend_map) { - 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 = check_lua_feature(ls, 4); + LINES(ls, 1, lines); + + TABLE_INT(ls, height, 1); + TABLE_INT(ls, width, 1); + TABLE_CHAR(ls, fill, 'x'); - 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; + lines.extend(width, height, fill); - return 0; + return (0); } -static int dgn_in_bounds(lua_State *ls) +LUAFN(dgn_fill_area) { - int x = luaL_checkint(ls, 1); - int y = luaL_checkint(ls, 2); + LINES(ls, 1, lines); + + int x1, y1, x2, y2; + if (!_coords(ls, lines, x1, y1, x2, y2)) + return (0); + + TABLE_CHAR(ls, fill, 'x'); - lua_pushboolean(ls, in_bounds(x, y)); - return 1; + for (int y = y1; y <= y2; ++y) + for (int x = x1; x <= x2; ++x) + { + lines(x, y) = fill; + } + + return (0); } -static int dgn_replace_first(lua_State *ls) +LUAFN(dgn_fill_disconnected) { - 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 = check_lua_feature(ls, 5); - dungeon_feature_type replace = check_lua_feature(ls, 6); - - _clamp_to_bounds(x, y); - bool found = false; - while (in_bounds(x, y)) + LINES(ls, 1, lines); + + int x1, y1, x2, y2; + if (!_coords(ls, lines, x1, y1, x2, y2)) + return (0); + + TABLE_CHAR(ls, fill, 'x'); + TABLE_STR(ls, passable, traversable_glyphs); + TABLE_STR(ls, wanted, exit_glyphs); + + coord_def tl(x1, y1); + coord_def br(x2, y2); + + travel_distance_grid_t tpd; + memset(tpd, 0, sizeof(tpd)); + + int nzones = 0; + for (rectangle_iterator ri(tl, br); ri; ++ri) { - if (grd[x][y] == search) + const coord_def c = *ri; + if (tpd[c.x][c.y] || passable && !strchr(passable, lines(c))) + continue; + + if (lines.fill_zone(tpd, c, tl, br, ++nzones, wanted, passable)) + continue; + + // If wanted wasn't found, fill every passable square that + // we just found with the 'fill' glyph. + for (rectangle_iterator f(tl, br); f; ++f) { - grd[x][y] = replace; - found = true; - break; + const coord_def fc = *f; + if (tpd[fc.x][fc.y] == nzones) + lines(fc) = fill; } - - x += dx; - y += dy; } - lua_pushboolean(ls, found); - return 1; + return (0); +} + +LUAFN(dgn_height) +{ + LINES(ls, 1, lines); + PLUARET(number, lines.height()); } -static int dgn_replace_random(lua_State *ls) +LUAFN(dgn_join_the_dots) { - dungeon_feature_type search = check_lua_feature(ls, 1); - dungeon_feature_type replace = check_lua_feature(ls, 2); + LINES(ls, 1, lines); - int x, y; + TABLE_INT(ls, x1, -1); + TABLE_INT(ls, y1, -1); + TABLE_INT(ls, x2, -1); + TABLE_INT(ls, y2, -1); + TABLE_STR(ls, passable, traversable_glyphs); + TABLE_CHAR(ls, fill, '.'); + + if (!_valid_coord(ls, lines, --x1, --y1)) + return (0); + if (!_valid_coord(ls, lines, --x2, --y2)) + return (0); + + coord_def from(x1, y1); + coord_def to(x2, y2); + + if (from == to) + return (0); + + coord_def at = from; do { - x = random2(GXM); - y = random2(GYM); + char glyph = lines(at); + + if (!strchr(passable, glyph)) + lines(at) = fill; + + if (at == to) + break; + + if (at.x < to.x) + { + at.x++; + continue; + } + + if (at.x > to.x) + { + at.x--; + continue; + } + + if (at.y > to.y) + { + at.y--; + continue; + } + + if (at.y < to.y) + { + at.y++; + continue; + } } - while (grd[x][y] != search); + while (true); + + return (0); +} + +LUAFN(dgn_make_circle) +{ + LINES(ls, 1, lines); + + TABLE_INT(ls, x, -1); + TABLE_INT(ls, y, -1); + TABLE_INT(ls, radius, 1); + TABLE_CHAR(ls, fill, 'x'); - grd[x][y] = replace; + if (!_valid_coord(ls, lines, --x, --y)) + return (0); - return 0; + for (int ry = -radius; ry <= radius; ++ry) + for (int rx = -radius; rx <= radius; ++rx) + if (rx * rx + ry * ry < radius * radius) + lines(x + rx, y + ry) = fill; + + return (0); } -static int dgn_spotty_level(lua_State *ls) +LUAFN(dgn_make_diamond) { - bool seeded = lua_toboolean(ls, 1); - int iterations = luaL_checkint(ls, 2); - bool boxy = lua_toboolean(ls, 3); + LINES(ls, 1, lines); + + TABLE_INT(ls, x, -1); + TABLE_INT(ls, y, -1); + TABLE_INT(ls, radius, 1); + TABLE_CHAR(ls, fill, 'x'); + + if (!_valid_coord(ls, lines, --x, --y)) + return (0); - spotty_level(seeded, iterations, boxy); - return 0; + for (int ry = -radius; ry <= radius; ++ry) + for (int rx = -radius; rx <= radius; ++rx) + if (std::abs(rx) + std::abs(ry) <= radius) + lines(x + rx, y + ry) = fill; + + return (0); } -static int dgn_smear_feature(lua_State *ls) +LUAFN(dgn_make_rounded_square) { - int iterations = luaL_checkint(ls, 1); - bool boxy = lua_toboolean(ls, 2); - dungeon_feature_type feat = check_lua_feature(ls, 3); + LINES(ls, 1, lines); - int x1 = luaL_checkint(ls, 4); - int y1 = luaL_checkint(ls, 5); - int x2 = luaL_checkint(ls, 6); - int y2 = luaL_checkint(ls, 7); + TABLE_INT(ls, x, -1); + TABLE_INT(ls, y, -1); + TABLE_INT(ls, radius, 1); + TABLE_CHAR(ls, fill, 'x'); - _clamp_to_bounds(x1, y1, true); - _clamp_to_bounds(x2, y2, true); + if (!_valid_coord(ls, lines, --x, --y)) + return (0); - smear_feature(iterations, boxy, feat, x1, y1, x2, y2); + for (int ry = -radius; ry <= radius; ++ry) + for (int rx = -radius; rx <= radius; ++rx) + if (std::abs(rx) != radius || std::abs(ry) != radius) + lines(x + rx, y + ry) = fill; - return 0; + return (0); } -static int dgn_count_feature_in_box(lua_State *ls) +LUAFN(dgn_make_square) { - 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 = check_lua_feature(ls, 5); - - lua_pushnumber(ls, count_feature_in_box(x1, y1, x2, y2, feat)); - return 1; + LINES(ls, 1, lines); + + TABLE_INT(ls, x, -1); + TABLE_INT(ls, y, -1); + TABLE_INT(ls, radius, 1); + TABLE_CHAR(ls, fill, 'x'); + + if (!_valid_coord(ls, lines, --x, --y)) + return (0); + + for (int ry = -radius; ry <= radius; ++ry) + for (int rx = -radius; rx <= radius; ++rx) + lines(x + rx, y + ry) = fill; + + return (0); } -static int dgn_count_antifeature_in_box(lua_State *ls) +// Return a metatable for a point on the map_lines grid. +LUAFN(dgn_mapgrd_table) { - 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 = check_lua_feature(ls, 5); - - lua_pushnumber(ls, count_antifeature_in_box(x1, y1, x2, y2, feat)); - return 1; + MAP(ls, 1, map); + + map_def **mapref = clua_new_userdata(ls, MAPGRD_METATABLE); + *mapref = map; + + return (1); } -static int dgn_count_neighbours(lua_State *ls) +LUAFN(dgn_octa_room) { - int x = luaL_checkint(ls, 1); - int y = luaL_checkint(ls, 2); - dungeon_feature_type feat = check_lua_feature(ls, 3); + LINES(ls, 1, lines); + + int default_oblique = std::min(lines.width(), lines.height()) / 2 - 1; + TABLE_INT(ls, oblique, default_oblique); + TABLE_CHAR(ls, outside, 'x'); + TABLE_CHAR(ls, inside, '.'); + TABLE_STR(ls, replace, ""); + + int x1, y1, x2, y2; + if (!_coords(ls, lines, x1, y1, x2, y2)) + return (0); + + coord_def tl(x1, y1); + coord_def br(x2, y2); + + for (rectangle_iterator ri(tl, br); ri; ++ri) + { + const coord_def mc = *ri; + char glyph = lines(mc); + if (replace[0] && !strchr(replace, glyph)) + continue; + + int ob = 0; + ob += std::max(oblique + tl.x - mc.x, 0); + ob += std::max(oblique + mc.x - br.x, 0); + + bool is_inside = (mc.y >= tl.y + ob && mc.y <= br.y - ob); + lines(mc) = is_inside ? inside : outside; + } + + return (0); +} + +LUAFN(dgn_replace_area) +{ + LINES(ls, 1, lines); + + TABLE_STR(ls, find, '\0'); + TABLE_CHAR(ls, replace, '\0'); + + int x1, y1, x2, y2; + if (!_coords(ls, lines, x1, y1, x2, y2)) + return (0); + + for (int y = y1; y <= y2; ++y) + for (int x = x1; x <= x2; ++x) + if (strchr(find, lines(x, y))) + lines(x, y) = replace; + + return (0); +} + +LUAFN(dgn_replace_first) +{ + LINES(ls, 1, lines); + + TABLE_INT(ls, x, 0); + TABLE_INT(ls, y, 0); + TABLE_INT(ls, xdir, 2); + TABLE_INT(ls, ydir, 2); + TABLE_CHAR(ls, find, '\0'); + TABLE_CHAR(ls, replace, '\0'); + TABLE_BOOL(ls, required, false); + + if (!_valid_coord(ls, lines, --x, --y)) + return (0); + + if (xdir < -1 || xdir > 1) + { + return (luaL_error(ls, "Invalid xdir: %d", xdir)); + } - lua_pushnumber(ls, count_neighbours(x, y, feat)); - return 1; + if (ydir < -1 || ydir > 1) + { + return (luaL_error(ls, "Invalid ydir: %d", ydir)); + } + + while (lines.in_bounds(coord_def(x, y))) + { + if (lines(x, y) == find) + { + lines(x, y) = replace; + return (0); + } + + x += xdir; + y += ydir; + } + + if (required) + return (luaL_error(ls, "Could not find feature '%c' to replace", find)); + + return (0); } -static int dgn_join_the_dots(lua_State *ls) +LUAFN(dgn_replace_random) { - 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); + LINES(ls, 1, lines); - coord_def from(from_x, from_y); - coord_def to(to_x, to_y); + TABLE_CHAR(ls, find, '\0'); + TABLE_CHAR(ls, replace, '\0'); + TABLE_BOOL(ls, required, false); - bool ret = join_the_dots(from, to, map_mask, early_exit); - lua_pushboolean(ls, ret); + int x1, y1, x2, y2; + if (!_coords(ls, lines, x1, y1, x2, y2)) + return (0); - return 1; + int count = (x2 - x1) * (y2 - y1); + if (!count) + { + if (required) + luaL_error(ls, "%s", "No elements to replace"); + return (0); + } + + std::vector loc; + loc.reserve(count); + + for (int y = y1; y <= y2; ++y) + for (int x = x1; x <= x2; ++x) + if (lines(x, y) == find) + loc.push_back(coord_def(x, y)); + + if (!loc.size()) + { + if (required) + return (luaL_error(ls, "Could not find '%c'", find)); + } + + int idx = random2(loc.size()); + lines(loc[idx]) = replace; + + return (0); } -static int dgn_fill_disconnected_zones(lua_State *ls) +LUAFN(dgn_smear_map) { - 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); + LINES(ls, 1, lines); + + TABLE_INT(ls, iterations, 1); + TABLE_CHAR(ls, smear, 'x'); + TABLE_STR(ls, onto, "."); + TABLE_BOOL(ls, boxy, false); - dungeon_feature_type feat = check_lua_feature(ls, 5); + const int border = 1; + int x1, y1, x2, y2; + if (!_coords(ls, lines, x1, y1, x2, y2, border)) + return (0); - process_disconnected_zones(from_x, from_y, to_x, to_y, true, feat); + const int max_test_per_iteration = 10; + int sanity = 0; + int max_sanity = iterations * max_test_per_iteration; - return 0; + for (int i = 0; i < iterations; i++) + { + bool diagonals, straights; + coord_def mc; + + do + { + do + { + if (sanity++ > max_sanity) + return (0); + + mc.x = random_range(x1+border, y2-border); + mc.y = random_range(y1+border, y2-border); + } + while (onto[0] && !strchr(onto, lines(mc))); + + // Is there a "smear" feature along the diagonal from mc? + diagonals = lines(mc.x+1, mc.y+1) == smear || + lines(mc.x-1, mc.y+1) == smear || + lines(mc.x-1, mc.y-1) == smear || + lines(mc.x+1, mc.y-1) == smear; + + // Is there a "smear" feature up, down, left, or right from mc? + straights = lines(mc.x+1, mc.y) == smear || + lines(mc.x-1, mc.y) == smear || + lines(mc.x, mc.y+1) == smear || + lines(mc.x, mc.y-1) == smear; + } + while (!straights && (boxy || !diagonals)); + + lines(mc) = smear; + } + + return (0); +} + +LUAFN(dgn_spotty_map) +{ + LINES(ls, 1, lines); + + TABLE_STR(ls, replace, "x"); + TABLE_CHAR(ls, fill, '.'); + TABLE_BOOL(ls, boxy, true); + TABLE_INT(ls, iterations, random2(boxy ? 750 : 1500)); + + const int border = 4; + int x1, y1, x2, y2; + if (!_coords(ls, lines, x1, y1, x2, y2, border)) + return (0); + + const int max_test_per_iteration = 10; + int sanity = 0; + int max_sanity = iterations * max_test_per_iteration; + + for (int i = 0; i < iterations; i++) + { + int x, y; + do + { + if (sanity++ > max_sanity) + return (0); + + x = random_range(x1 + border, x2 - border); + y = random_range(y1 + border, y2 - border); + } + while (strchr(replace, lines(x, y)) + && strchr(replace, lines(x-1, y)) + && strchr(replace, lines(x+1, y)) + && strchr(replace, lines(x, y-1)) + && strchr(replace, lines(x, y+1)) + && strchr(replace, lines(x-2, y)) + && strchr(replace, lines(x+2, y)) + && strchr(replace, lines(x, y-2)) + && strchr(replace, lines(x, y+2))); + + if (strchr(replace, lines(x, y))) + lines(x, y) = fill; + if (strchr(replace, lines(x, y-1))) + lines(x, y-1) = fill; + if (strchr(replace, lines(x, y+1))) + lines(x, y+1) = fill; + if (strchr(replace, lines(x-1, y))) + lines(x-1, y) = fill; + if (strchr(replace, lines(x+1, y))) + lines(x+1, y) = fill; + + if (boxy) + { + if (strchr(replace, lines(x-1, y-1))) + lines(x-1, y-1) = fill; + if (strchr(replace, lines(x+1, y+1))) + lines(x+1, y+1) = fill; + if (strchr(replace, lines(x-1, y+1))) + lines(x-1, y+1) = fill; + if (strchr(replace, lines(x+1, y-1))) + lines(x+1, y-1) = fill; + } + } + + return (0); +} + +static int dgn_width(lua_State *ls) +{ + LINES(ls, 1, lines); + PLUARET(number, lines.width()); } const struct luaL_reg dgn_build_dlib[] = { -{ "mapgrd_table", dgn_mapgrd_table }, -{ "width", dgn_width }, -{ "height", dgn_height }, -{ "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 }, -{ "fill_disconnected_zones", dgn_fill_disconnected_zones }, - -{ NULL, NULL } + { "count_feature_in_box", &dgn_count_feature_in_box }, + { "count_antifeature_in_box", &dgn_count_antifeature_in_box }, + { "count_neighbors", &dgn_count_neighbors }, + { "extend_map", &dgn_extend_map }, + { "fill_area", &dgn_fill_area }, + { "fill_disconnected", &dgn_fill_disconnected }, + { "height", dgn_height }, + { "join_the_dots", &dgn_join_the_dots }, + { "make_circle", &dgn_make_circle }, + { "make_diamond", &dgn_make_diamond }, + { "make_rounded_square", &dgn_make_rounded_square }, + { "make_square", &dgn_make_square }, + { "mapgrd_table", dgn_mapgrd_table }, + { "octa_room", &dgn_octa_room }, + { "replace_area", &dgn_replace_area }, + { "replace_first", &dgn_replace_first }, + { "replace_random", &dgn_replace_random }, + { "smear_map", &dgn_smear_map }, + { "spotty_map", &dgn_spotty_map }, + { "width", dgn_width }, + + { NULL, NULL } }; diff --git a/crawl-ref/source/makefile.obj b/crawl-ref/source/makefile.obj index 0ecee6cd2e..183a392cd3 100644 --- a/crawl-ref/source/makefile.obj +++ b/crawl-ref/source/makefile.obj @@ -51,7 +51,6 @@ kills.o \ l_crawl.o \ l_debug.o \ l_dgn.o \ -l_dgn_bf.o \ l_dgnbld.o \ l_dgnevt.o \ l_dgngrd.o \ diff --git a/crawl-ref/source/mapdef.cc b/crawl-ref/source/mapdef.cc index b34a05fe59..84506d5a8e 100644 --- a/crawl-ref/source/mapdef.cc +++ b/crawl-ref/source/mapdef.cc @@ -365,14 +365,30 @@ rectangle_iterator map_lines::get_iter() const char map_lines::operator () (const coord_def &c) const { - return lines[c.y][c.x]; + return (lines[c.y][c.x]); } char& map_lines::operator () (const coord_def &c) { - return lines[c.y][c.x]; + return (lines[c.y][c.x]); } +char map_lines::operator () (int x, int y) const +{ + return (lines[y][x]); +} + +char& map_lines::operator () (int x, int y) +{ + return (lines[y][x]); +} + +bool map_lines::in_bounds(const coord_def &c) const +{ + return (c.x >= 0 && c.y >= 0 && c.x < width() && c.y < height()); +} + + bool map_lines::in_map(const coord_def &c) const { return (lines[c.y][c.x] != ' '); @@ -1353,6 +1369,67 @@ std::string map_lines::add_floortile(const std::string &sub) return add_tile(sub, true); } +bool map_lines::fill_zone(travel_distance_grid_t &tpd, const coord_def &start, + const coord_def &tl, const coord_def &br, int zone, + const char *wanted, const char *passable) const +{ + // This is the map_lines equivalent of _dgn_fill_zone. + // It's unfortunately extremely similar, but not close enough to combine. + + bool ret = false; + std::list points[2]; + int cur = 0; + + for (points[cur].push_back(start); !points[cur].empty(); ) + { + for (std::list::const_iterator i = points[cur].begin(); + i != points[cur].end(); ++i) + { + const coord_def &c(*i); + + tpd[c.x][c.y] = zone; + + ret |= (wanted && strchr(wanted, (*this)(c)) != NULL); + + for (int yi = -1; yi <= 1; ++yi) + for (int xi = -1; xi <= 1; ++xi) + { + if (!xi && !yi) + continue; + + const coord_def cp(c.x + xi, c.y + yi); + if (cp.x < tl.x || cp.x > br.x + || cp.y < tl.y || cp.y > br.y + || !in_bounds(cp) || tpd[cp.x][cp.y] + || passable && !strchr(passable, (*this)(cp))) + { + continue; + } + + tpd[cp.x][cp.y] = zone; + points[!cur].push_back(cp); + } + } + + points[cur].clear(); + cur = !cur; + } + return (ret); +} + +int map_lines::count_feature_in_box(const coord_def &tl, const coord_def &br, + const char *feat) const +{ + int result = 0; + for (rectangle_iterator ri(tl, br); ri; ++ri) + { + if (strchr(feat, (*this)(*ri))) + result++; + } + + return (result); +} + ////////////////////////////////////////////////////////////////////////// // tile_spec diff --git a/crawl-ref/source/mapdef.h b/crawl-ref/source/mapdef.h index c08093243c..de55bd511c 100644 --- a/crawl-ref/source/mapdef.h +++ b/crawl-ref/source/mapdef.h @@ -302,10 +302,21 @@ public: rectangle_iterator get_iter() const; char operator () (const coord_def &c) const; char& operator () (const coord_def &c); + char operator () (int x, int y) const; + char& operator () (int x, int y); + + bool in_bounds(const coord_def &c) const; // Extend map dimensions with glyph 'fill' to minimum width and height. void extend(int min_width, int min_height, char fill); + bool fill_zone(travel_distance_grid_t &tpd, const coord_def &start, + const coord_def &tl, const coord_def &br, int zone, + const char *wanted, const char *passable) const; + + int count_feature_in_box(const coord_def &tl, const coord_def &br, + const char *feat) const; + private: void init_from(const map_lines &map); template void clear_vector(V &vect); -- cgit v1.2.3-54-g00ecf