Files
nethack/test/test_des.lua
copperwater 0fef8fce9f Unify all special level filling options
The existing system was a confusing mess of competing names (filled,
needfill, prefilled, etc) that had varying semantics, with prefilled
being the worst offender as it meant at least three different things in
various contexts. This commit unifies everything in the code under
"needfill", and everything in Lua under "filled", which defaults to 0
everywhere.

This also removes the second argument to fill_special_room; that
function now just checks the needfill of the room it's passed. As
before, a filled == 2 value is used for a special room to indicate that
the room should set the appropriate level flag, but shouldn't actually
be stocked with anything (for instance, King Arthur's throne room); the
difference is that this now comes directly from the lua script instead
of being manipulated within sp_lev.c.

The prefilled argument had one use case that is occasionally used in the
level files: if the level designer had specified an ordinary region with
prefilled = 1, it would become a room to control monster arrivals on a
level -- monsters that arrive within the bounds of a room are supposed
to stay there.
However, not all of the places where the comments indicated this was
being used were using it correctly; I tested this by letting a few
monsters fall through the knox portal (they're supposed to be
constrained to the entry room) and waiting a hundred turns, then going
through the portal; they were not constrained to the room and had
"wandered" through its walls.
Instead of trying to maintain this special case, I have added an
optional "arrival_room" boolean argument to des.region, which forces it
to create a room for the purposes of constraining monster arrival.

I have gone through and replaced occurrences of prefilled in lua files
with the appropriate filled option (or arrival, as needed). In some
cases, that resulted in questionable regions such as a filled ordinary
area in a non-themeroom (I just dropped the filled=1), or an area which
didn't do anything, not even lighting (which I deleted).
2020-09-27 18:54:15 +03:00

493 lines
15 KiB
Lua

-- Test the des-file commands
-- reset_level is only needed here, not in normal special level scripts.
function is_map_at(x,y, mapch, lit)
local rm = nh.getmap(x + 1, y); -- + 1 == g.xstart
if rm.mapchr ~= mapch then
error("Terrain at (" .. x .. "," .. y .. ") is not \"" .. mapch .. "\", but \"" .. rm.mapchr .. "\"");
end
if lit ~= nil then
if rm.lit ~= lit then
error("light state at (" .. x .. "," .. y .. ") is not \"" .. lit .. "\", but \"" .. tostring(rm.lit) .. "\"");
end
end
end
function check_loc_name(x, y, name)
local loc = nh.getmap(x,y);
if (loc.typ_name ~= name) then
error("No " .. name .. " at " .. x .. "," .. y .. " (" .. loc.typ_name .. ")");
end
end
function check_loc_flag(x, y, flag, value)
local loc = nh.getmap(x, y);
if (loc.flags[flag] ~= value) then
error(loc.typ_name .. " at (" .. x .. "," .. y .. ") flag " .. flag .. " is " .. tostring(loc.flags[flag]) .. ", not " .. tostring(value));
end
end
function check_trap_at(x,y, name)
local t = nh.gettrap(x + 1, y); -- + 1 == g.xstart
if (t.ttyp_name ~= name) then
error("Trap at " .. x .. "," .. y .. " is " .. t.ttyp_name .. ", not " .. name);
end
end
function test_level_init()
des.reset_level();
des.level_init();
des.reset_level();
des.level_init({ style = "solidfill" });
des.reset_level();
des.level_init({ style = "solidfill", fg = " " });
des.reset_level();
des.level_init({ style = "mazegrid", bg ="-" });
des.reset_level();
des.level_init({ style = "rogue" });
des.reset_level();
des.level_init({ style = "mines" });
des.reset_level();
des.level_init({ style = "mines", fg = ".", bg = " ", smoothed = true });
des.reset_level();
des.level_init({ style = "mines", fg = ".", bg = "}", joined = true });
des.reset_level();
des.level_init({ style = "mines", fg = ".", bg = "L", smoothed = 1, joined = 1, lit = 0 });
des.reset_level();
des.level_init({ style = "mines", fg = ".", bg = " ", smoothed = true, joined = true, walled = true });
des.reset_level();
des.level_init({ style = "solidfill", fg = ".", lit = 1 });
end
function test_message()
des.message("Test message");
des.message("Message 2");
end
function test_monster()
des.monster();
des.monster("gnome")
des.monster("S")
des.monster("giant eel",11,06);
des.monster("hill giant", {08,06});
des.monster({ id = "ogre" })
des.monster({ class = "D" })
des.monster({ id = "ogre", x = 10, y = 15 })
des.monster({ class = "D", coord = {11,16} })
des.monster({ x = 73, y = 16 });
des.monster({ id = "watchman", peaceful = 1 })
des.monster({ class = "H", peaceful = 0 })
des.monster({ id = "giant mimic", appear_as = "obj:boulder" });
des.monster({ id = "giant mimic", appear_as = "ter:altar" });
des.monster({ id = "chameleon", appear_as = "mon:bat" });
des.monster({ class = "H", asleep = 1, female = 1, invisible = 1, cancelled = 1, revived = 1, avenge = 1, fleeing = 20, blinded = 20, paralyzed = 20, stunned = 20, confused = 20 })
des.monster({ id = "ogre", x = 10, y = 15, name = "Fred",
inventory = function()
des.object();
des.object("[");
des.object({ class = "/" });
des.object({ id = "statue", contents=0 })
end
});
des.reset_level();
des.level_init();
end
function test_object()
des.reset_level();
des.level_init();
des.object()
des.object("*")
des.object({ class = "%" });
des.object({ id = "statue", contents=0 })
des.object("sack")
des.object({ x = 41, y = 03 })
des.object({ coord = {42, 03} });
des.object({ id = "boulder", coord = {03,12} });
des.object("diamond", 69, 04)
des.object("diamond", {68, 04})
des.object({ id = "egg", x = 05, y = 04, montype = "yellow dragon" });
des.object({ id = "egg", x = 06, y = 04, montype = "yellow dragon", laid_by_you = true });
des.object({ id = "corpse", montype = "valkyrie" })
des.object({ id = "statue", montype = "C", historic = true, male = true });
des.object({ id = "statue", montype = "C", historic = true, female = true });
des.object({ id = "chest", buried = true, locked = true,
contents = function()
des.object();
des.object("*")
des.object({ class = "%" });
des.object({ id = "statue", contents=0 })
end
});
des.object({ id = "chest", greased = true, broken = true, contents = 0 });
des.object({ id = "chest", trapped = 1, broken = true, contents = 0 });
des.object({ id = "oil lamp", lit = 1 });
des.object({ id = "silver dagger", spe = 127, buc = "cursed" });
des.object({ id = "silver dagger", spe = -127, buc = "blessed" });
des.object({ id = "bamboo arrow", quantity = 100 });
des.object({ id = "leather armor", eroded = 1 });
des.object({ id = "probing", recharged = 2, spe = 3 });
des.object({ name = "Random object" });
des.object({ class = "*", name = "Random stone" });
des.object({ id ="broadsword", name = "Dragonbane" })
des.reset_level();
des.level_init();
end
function test_level_flags()
des.level_flags("noteleport")
des.level_flags("noteleport", "hardfloor", "nommap", "shortsighted", "arboreal")
des.level_flags("mazelevel", "shroud", "graveyard", "icedpools", "corrmaze")
des.level_flags("premapped", "solidify", "inaccessibles")
end
function test_engraving()
des.engraving({02,04},"engrave","Trespassers will be persecuted!")
des.engraving({ x = 1, y = 2, type = "burn", text = "Elbereth" });
des.engraving({ coord = {1, 3}, type = "burn", text = "Elbereth" });
des.engraving({ type = "dust", text = "X marks the spot." })
des.engraving({ text = "Foobar" })
des.engraving({ type = "mark", text = "X" })
des.engraving({ type = "blood", text = "redrum" })
end
function test_mineralize()
des.mineralize();
des.mineralize({ gem_prob = 1, gold_prob = 10, kelp_moat = 25, kelp_pool = 100 })
end
function test_grave()
des.grave();
des.grave(39,10, "Foo is here");
des.grave({ text = "Lil Miss Marker" });
des.grave({ x = 40, y = 11 });
des.grave({ coord = {40, 12} });
des.grave({ x = 41, y = 12, text = "Bongo" });
des.grave({ x = 42, y = 13, text = "" });
end
function test_altar()
des.altar();
des.altar({ x = 44, y = 20 });
des.altar({ coord = {46, 20 } });
des.altar({ coord = {48, 20 }, type = "altar", align = "law" });
des.altar({ coord = {50, 20 }, type = "shrine", align = "noalign" });
des.altar({ coord = {52, 20 }, type = "sanctum", align = "coaligned" });
end
function test_map()
des.map([[
TTT
LTL
LTL]])
des.map({ x = 60, y = 5, map = [[
FFF
F.F
FFF]] })
for x = 60, 62 do
for y = 5, 7 do
local nam = "iron bars";
if (x == 61 and y == 6) then
nam = "room";
end
check_loc_name(x, y, nam);
end
end
des.map({ coord = {60, 5}, map = [[
...
.T.
...]] })
for x = 60, 62 do
for y = 5, 7 do
local nam = "room";
if (x == 61 and y == 6) then
nam = "tree";
end
check_loc_name(x, y, nam);
end
end
des.map({ halign = "left", valign = "bottom", map = [[
III
.I.
III]] })
des.map({ coord = {30, 5}, map = [[
...
...
...]], contents = function(map)
des.terrain(0,0, "L");
des.terrain(map.width-1,map.height-1, "T");
end});
check_loc_name(30, 5, "lava pool");
check_loc_name(32, 7, "tree");
end
function test_feature()
des.reset_level();
des.level_init({ style = "solidfill", fg = ".", lit = 1 });
des.feature("fountain", 40, 08);
check_loc_name(40 + 1, 08, "fountain");
des.feature("sink", {41, 08});
check_loc_name(41 + 1, 08, "sink");
des.feature({ type = "pool", x = 42, y = 08 });
check_loc_name(42 + 1, 08, "pool");
des.feature({ type = "sink", coord = {43, 08} });
check_loc_name(43 + 1, 08, "sink");
des.feature({ type = "throne", coord = {44, 08}, looted=true });
check_loc_name(44 + 1, 08, "throne");
check_loc_flag(44 + 1, 08, "looted", true);
des.feature({ type = "throne", coord = {44, 08}, looted=false });
check_loc_name(44 + 1, 08, "throne");
check_loc_flag(44 + 1, 08, "looted", false);
des.feature({ type = "tree", coord = {45, 08}, looted=true, swarm=false });
check_loc_name(45 + 1, 08, "tree");
check_loc_flag(45 + 1, 08, "looted", true);
check_loc_flag(45 + 1, 08, "swarm", false);
des.feature({ type = "tree", coord = {45, 08}, looted=false, swarm=true });
check_loc_name(45 + 1, 08, "tree");
check_loc_flag(45 + 1, 08, "looted", false);
check_loc_flag(45 + 1, 08, "swarm", true);
des.feature({ type = "fountain", coord = {46, 08}, looted=false, warned=true });
check_loc_name(46 + 1, 08, "fountain");
check_loc_flag(46 + 1, 08, "looted", false);
check_loc_flag(46 + 1, 08, "warned", true);
des.feature({ type = "sink", coord = {47, 08}, pudding=false, dishwasher=true, ring=true });
check_loc_name(47 + 1, 08, "sink");
check_loc_flag(47 + 1, 08, "pudding", false);
check_loc_flag(47 + 1, 08, "dishwasher", true);
check_loc_flag(47 + 1, 08, "ring", true);
end
function test_gold()
des.gold();
des.gold({ amount = 999, x = 40, y = 07 });
des.gold({ amount = 999, coord = {40, 08} });
des.gold(666, 41,07);
des.gold(123, {42,07});
end
function test_trap()
des.trap("pit", 41, 06);
check_trap_at(41, 06, "pit");
des.trap("level teleport", {42, 06});
check_trap_at(42, 06, "level teleport");
des.trap({ type = "falling rock", x = 43, y = 06 });
check_trap_at(43, 06, "falling rock");
des.trap({ type = "dart", coord = {44, 06} });
check_trap_at(44, 06, "dart");
des.trap();
des.trap("rust");
end
function test_wall_prop()
des.wall_property({ x1 = 0, y1 = 0, x2 = 78, y2 = 20, property = "nondiggable" });
des.wall_property({ region={0,0, 78,20}, property = "nondiggable" });
des.non_diggable();
des.non_diggable(selection.area(5,5, 15, 15));
des.non_passwall();
des.non_passwall(selection.area(5,5, 15, 15));
end
function test_wallify()
des.wallify();
des.wallify({ x1 = 0, y1 = 0, x2 = 78, y2 = 20 });
end
function test_teleport_region()
des.teleport_region({ region = {69,00,79,20} })
des.teleport_region({ region = {69,00,79,20}, dir="up" })
des.teleport_region({ region = {69,00,79,20}, region_islev=1, dir="up" })
des.teleport_region({ region = {01,00,10,20}, region_islev=1, exclude={1,1,61,15}, dir="down" })
des.teleport_region({ region = {01,00,10,20}, region_islev=1, exclude={1,1,61,15}, exclude_islev=1 })
end
function test_region()
des.region(selection.area(08,03,54,03),"unlit")
des.region(selection.area(56,02,60,03),"lit")
des.region({ region={16,05, 25,06}, lit=1, type="barracks", filled=0 })
des.region({ region={1,5, 3,7}, lit=1, irregular=true, filled=1, joined=false })
end
function test_door()
des.terrain(12, 12, "-");
des.door("nodoor", 12,12);
des.terrain(13, 12, "-");
des.door({ x = 13, y = 12, state = "open" });
des.terrain(14, 12, "-");
des.door({ coord = {14, 12}, state = "open" });
des.room({ type = "ordinary", contents = function()
des.door({ wall = "north", pos = 1 });
des.door({ wall = "random", state = "locked" });
end
});
end
function test_mazewalk()
des.reset_level();
des.level_init({ style = "mazegrid", bg ="-" });
des.mazewalk(01,10,"east")
des.reset_level();
des.level_init({ style = "mazegrid", bg ="-" });
des.mazewalk({ x=2,y=10, dir="north", typ="L", stocked=true });
des.reset_level();
des.level_init({ style = "mazegrid", bg ="-" });
des.mazewalk({ coord={2,10}, dir="north", typ="L", stocked=true });
end
function test_room()
des.reset_level();
des.level_init({ style = "solidfill", fg=" " });
des.room({ type = "ordinary", lit = 1,
x=3, y=3, xalign="center", yalign="center",
w=11, h=9, contents = function()
des.room({ x=4, y=3, w=3,h=3 });
end
});
des.room({ type="ordinary", coord={3, 3}, w=3, h=3 });
des.room();
des.room({ contents = function(rm)
des.object();
des.monster();
des.terrain(0,0, "L");
des.terrain(rm.width, rm.height, "T");
end
});
des.random_corridors();
end
function test_stair()
des.reset_level();
des.level_init();
des.stair("up");
des.stair("down", 4, 7);
des.stair({ dir = "down", x = 5, y = 7 });
des.stair({ dir = "down", coord = {6, 7} });
end
function test_ladder()
des.reset_level();
des.level_init();
des.ladder("up");
des.ladder("down", 4, 7);
des.ladder({ dir = "down", x = 5, y = 7 });
des.ladder({ dir = "down", coord = {6, 7} });
end
function test_terrain()
des.reset_level();
des.level_init();
des.terrain(2, 2, "L");
is_map_at(2,2, "L");
des.terrain({6,7}, "L");
is_map_at(6,7, "L");
des.terrain({ x = 5, y = 5, typ = "L" });
is_map_at(5,5, "L");
des.terrain({ coord = {5, 5}, typ = "T" });
is_map_at(5,5, "T");
-- TODO: allow lit = false
-- des.terrain({ x = 5, y = 5, typ = ".", lit = false });
-- is_map_at(5,5, ".", false);
des.terrain({ x = 5, y = 5, typ = ".", lit = 1 });
is_map_at(5,5, ".", true);
des.terrain({ x = 5, y = 5, typ = " ", lit = 0 });
is_map_at(5,5, " ", false);
des.terrain({ selection = selection.area(4,4, 6,6), typ = "L", lit = 0 });
for x = 4,6 do
for y = 4,6 do
is_map_at(x,y, "L", true);
end
end
des.terrain(selection.area(2,2, 4,4), "T");
for x = 2,4 do
for y = 2,4 do
is_map_at(x,y, "T");
end
end
end
function test_replace_terrain()
des.replace_terrain({ x1=1, y1=1, x2=70,y2=19, fromterrain=".", toterrain="I", lit=1 });
des.replace_terrain({ x1=1, y1=1, x2=70,y2=19, fromterrain=".", toterrain="I", chance=50 });
des.replace_terrain({ region={1,1, 70,19}, fromterrain=".", toterrain="L", chance=25 });
des.replace_terrain({ selection=selection.area(2,5, 10,15), fromterrain="L", toterrain="." });
des.replace_terrain({ mapfragment=[[...]], toterrain="T" });
des.replace_terrain({ mapfragment=[[w.w]], toterrain="L" });
end
function test_corridor()
des.reset_level();
des.level_init({ style = "solidfill", fg=" " });
des.room({ x=2, y=2, xalign="center", yalign="center", w=4, h=4 });
des.room({ x=1, y=3, xalign="center", yalign="center", w=6, h=6 });
des.corridor({ srcroom=0, srcwall="south", srcdoor=0, destroom=1, destwall="north", destdoor=0 });
end
function run_tests()
test_level_init();
test_message();
test_monster();
test_object();
test_level_flags();
test_engraving();
test_mineralize();
test_grave();
test_altar();
test_feature();
test_gold();
test_trap();
test_door();
test_map();
test_wall_prop();
test_wallify();
test_teleport_region();
test_region();
test_mazewalk();
test_room();
test_stair();
test_ladder();
test_terrain();
test_replace_terrain();
test_corridor();
des.reset_level();
des.level_init();
end
run_tests();