Files
nethack/test/test_des.lua
copperwater f71bff3285 Standardize all core and obj functions with relative coords
This is a large iteration on a previous implementation of making
nh.getmap() parse its coordinates as relative to the last defined map or
room rather than absolute to the entire level. Now, everything in the
nh.* and obj.* functions interprets coords as relative rather than
absolute. (By default; if no map or room has been defined, or if the lua
code is executing after level creation is done, they will interpret the
coordinates as absolute).

The general motivation is basically the same - routines that use
absolute coordinates are difficult to use in level creation routines,
because then the designer has to remember to convert the relative
coordinate to an absolute one (and that was impossible before
nh.abscoord was added, particularly in themed rooms). And once
nh.getmap() takes relative coordinates, it would be very strange to have
all the other functions (setting timers, burying objects, etc) remain
with absolute ones.

In a couple places, code is changed to account for coordinates that are
relative to a *room* (which uses g.coder->croom->[lx,ly] as an offset,
instead of relative to a *map*, which uses [xstart,ystart].
Specifically, selection.iterate did not account for this, and without
this the ice themed room timer was not being started in the proper
place.

All tests are updated to respect the new behavior. Most of the modified
functions are not actually used anywhere in level files; the one
exception is starting a timer in a themed room, and that has been
adjusted.

Documentation updated as well to clarify when various things are tossing
around relative and absolute coordinates, both in comments and in
lua.adoc.
2022-08-31 18:26:05 +03:00

530 lines
16 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, y);
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, y);
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 = "solidfill", fg = " ", lit = false });
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 = true, joined = true, lit = 0 });
des.reset_level();
des.level_init({ style = "mines", fg = ".", bg = "L", smoothed = true, joined = true, lit = true });
des.reset_level();
des.level_init({ style = "mines", fg = ".", bg = " ", smoothed = true, joined = true, walled = true });
des.reset_level();
des.level_init({ style = "swamp", fg = " ", lit = false });
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 = true })
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, stunned = 1, confused = 1, fleeing = 20, blinded = 20, paralyzed = 20 })
des.monster({ class = "H", asleep = true, female = true, invisible = true, cancelled = true, revived = true, avenge = true, stunned = true, confused = true });
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.monster({ id = "long worm", tail = false });
des.monster({ id = "hill orc", group = false });
des.monster({ id = "lurker above", adjacentok = true });
des.monster({ id = "gnome", ignorewater = true });
des.monster({ id = "xan", countbirth = false });
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 = 0,2 do
for y = 0,2 do
local nam = "iron bars";
if (x == 1 and y == 1) then
nam = "room";
end
check_loc_name(x, y, nam);
end
end
des.map({ coord = {60, 5}, map = [[
...
.T.
...]] })
for x = 0, 2 do
for y = 0, 2 do
local nam = "room";
if (x == 1 and y == 1) 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(0, 0, "lava pool");
check_loc_name(2, 2, "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, 08, "fountain");
des.feature("sink", {41, 08});
check_loc_name(41, 08, "sink");
des.feature({ type = "pool", x = 42, y = 08 });
check_loc_name(42, 08, "pool");
des.feature({ type = "sink", coord = {43, 08} });
check_loc_name(43, 08, "sink");
des.feature({ type = "throne", coord = {44, 08}, looted=true });
check_loc_name(44, 08, "throne");
check_loc_flag(44, 08, "looted", true);
des.feature({ type = "throne", coord = {44, 08}, looted=false });
check_loc_name(44, 08, "throne");
check_loc_flag(44, 08, "looted", false);
des.feature({ type = "tree", coord = {45, 08}, looted=true, swarm=false });
check_loc_name(45, 08, "tree");
check_loc_flag(45, 08, "looted", true);
check_loc_flag(45, 08, "swarm", false);
des.feature({ type = "tree", coord = {45, 08}, looted=false, swarm=true });
check_loc_name(45, 08, "tree");
check_loc_flag(45, 08, "looted", false);
check_loc_flag(45, 08, "swarm", true);
des.feature({ type = "fountain", coord = {46, 08}, looted=false, warned=true });
check_loc_name(46, 08, "fountain");
check_loc_flag(46, 08, "looted", false);
check_loc_flag(46, 08, "warned", true);
des.feature({ type = "sink", coord = {47, 08}, pudding=false, dishwasher=true, ring=true });
check_loc_name(47, 08, "sink");
check_loc_flag(47, 08, "pudding", false);
check_loc_flag(47, 08, "dishwasher", true);
check_loc_flag(47, 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();
des.stair("up");
des.stair("down", 4, 7);
des.stair("down", {7, 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();
des.ladder("up");
des.ladder("down", 4, 7);
des.ladder("down", {7, 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.reset_level();
des.replace_terrain({ x1=2, y1=3, x2=4,y2=5, fromterrain=" ", toterrain="I", lit=1 });
for x = 2,4 do
for y = 3,5 do
is_map_at(x,y, "I", true);
end
end
for x = 1,5 do
is_map_at(x,2, " ", false);
is_map_at(x,6, " ", false);
end
for y = 2,6 do
is_map_at(1, y, " ", false);
is_map_at(5, y, " ", false);
end
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
nh.debug_flags({mongen = false, hunger = false, overwrite_stairs = true });
run_tests();