Reported by vultur-cadens: it was possible to encounter ettin zombies and giant zombies at shallow levels if those levels were generated with the "buried zombies" theme room. This uses a simpler fix than the suggestion(s); it's only applicable to the zombie room though. Also, vary the zombify_mon timeout. If the hero happened to be in the room at the time that that expired, they would all claw their way out of the ground at once. The new variation is quite small so they still escape burial as a group, but over the span of 21 turns rather than all on one turn. Fixes #1016
811 lines
23 KiB
Lua
811 lines
23 KiB
Lua
-- NetHack themerms.lua $NHDT-Date: 1652196294 2022/05/10 15:24:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.16 $
|
|
-- Copyright (c) 2020 by Pasi Kallinen
|
|
-- NetHack may be freely redistributed. See license for details.
|
|
--
|
|
-- themerooms is an array of tables and/or functions.
|
|
-- the tables define "frequency", "contents", "mindiff" and "maxdiff".
|
|
-- frequency is optional; if omitted, 1 is assumed.
|
|
-- mindiff and maxdiff are optional and independent; if omitted, the room is
|
|
-- not constrained by level difficulty.
|
|
-- a plain function has frequency of 1, and no difficulty constraints.
|
|
-- des.room({ type = "ordinary", filled = 1 })
|
|
-- - ordinary rooms can be converted to shops or any other special rooms.
|
|
-- - filled = 1 means the room gets random room contents, even if it
|
|
-- doesn't get converted into a special room. Without filled,
|
|
-- the room only gets what you define in here.
|
|
-- - use type = "themed" to force a room that's never converted
|
|
-- to a special room, such as a shop or a temple.
|
|
--
|
|
-- for each level, the core first calls pre_themerooms_generate(),
|
|
-- then it calls themerooms_generate() multiple times until it decides
|
|
-- enough rooms have been generated, and then it calls
|
|
-- post_themerooms_generate(). The lua state is persistent through
|
|
-- the gameplay, but not across saves, so remember to reset any variables.
|
|
|
|
|
|
local buried_treasure = { };
|
|
|
|
themeroom_fills = {
|
|
|
|
-- Ice room
|
|
function(rm)
|
|
local ice = selection.room();
|
|
des.terrain(ice, "I");
|
|
if (percent(25)) then
|
|
local mintime = 1000 - (nh.level_difficulty() * 100);
|
|
local ice_melter = function(x,y)
|
|
nh.start_timer_at(x,y, "melt-ice", mintime + nh.rn2(1000));
|
|
end;
|
|
ice:iterate(ice_melter);
|
|
end
|
|
end,
|
|
|
|
-- Boulder room
|
|
{
|
|
mindiff = 4,
|
|
contents = function(rm)
|
|
local locs = selection.room():percentage(30);
|
|
local func = function(x,y)
|
|
if (percent(50)) then
|
|
des.object("boulder", x, y);
|
|
else
|
|
des.trap("rolling boulder", x, y);
|
|
end
|
|
end;
|
|
locs:iterate(func);
|
|
end
|
|
},
|
|
|
|
-- Spider nest
|
|
function(rm)
|
|
local spooders = nh.level_difficulty() > 8;
|
|
local locs = selection.room():percentage(30);
|
|
local func = function(x,y)
|
|
des.trap({ type = "web", x = x, y = y,
|
|
spider_on_web = spooders and percent(80) });
|
|
end
|
|
locs:iterate(func);
|
|
end,
|
|
|
|
-- Trap room
|
|
function(rm)
|
|
local traps = { "arrow", "dart", "falling rock", "bear",
|
|
"land mine", "sleep gas", "rust",
|
|
"anti magic" };
|
|
shuffle(traps);
|
|
local locs = selection.room():percentage(30);
|
|
local func = function(x,y)
|
|
des.trap(traps[1], x, y);
|
|
end
|
|
locs:iterate(func);
|
|
end,
|
|
|
|
-- Buried treasure
|
|
function(rm)
|
|
des.object({ id = "chest", buried = true, contents = function(otmp)
|
|
local xobj = otmp:totable();
|
|
-- keep track of the last buried treasure
|
|
if (xobj.NO_OBJ == nil) then
|
|
buried_treasure = { x = xobj.ox, y = xobj.oy };
|
|
end
|
|
for i = 1, d(3,4) do
|
|
des.object();
|
|
end
|
|
end });
|
|
end,
|
|
|
|
-- Buried zombies
|
|
function(rm)
|
|
local diff = nh.level_difficulty()
|
|
-- start with [1..4] for low difficulty
|
|
local zombifiable = { "kobold", "gnome", "orc", "dwarf" };
|
|
if diff > 3 then -- medium difficulty
|
|
zombifiable[5], zombifiable[6] = "elf", "human";
|
|
if diff > 6 then -- high difficulty (relatively speaking)
|
|
zombifiable[7], zombifiable[8] = "ettin", "giant";
|
|
end
|
|
end
|
|
for i = 1, (rm.width * rm.height) / 2 do
|
|
shuffle(zombifiable);
|
|
local o = des.object({ id = "corpse", montype = zombifiable[1],
|
|
buried = true });
|
|
o:stop_timer("rot-corpse");
|
|
o:start_timer("zombify-mon", math.random(990, 1010));
|
|
end
|
|
end,
|
|
|
|
-- Massacre
|
|
function(rm)
|
|
local mon = { "apprentice", "warrior", "ninja", "thug",
|
|
"hunter", "acolyte", "abbot", "page",
|
|
"attendant", "neanderthal", "chieftain",
|
|
"student", "wizard", "valkyrie", "tourist",
|
|
"samurai", "rogue", "ranger", "priestess",
|
|
"priest", "monk", "knight", "healer",
|
|
"cavewoman", "caveman", "barbarian",
|
|
"archeologist" };
|
|
local idx = math.random(#mon);
|
|
for i = 1, d(5,5) do
|
|
if (percent(10)) then idx = math.random(#mon); end
|
|
des.object({ id = "corpse", montype = mon[idx] });
|
|
end
|
|
end,
|
|
|
|
-- Statuary
|
|
function(rm)
|
|
for i = 1, d(5,5) do
|
|
des.object({ id = "statue" });
|
|
end
|
|
for i = 1, d(3) do
|
|
des.trap("statue");
|
|
end
|
|
end,
|
|
|
|
-- Light source
|
|
{
|
|
eligible = function(rm) return rm.lit == false; end,
|
|
contents = function(rm)
|
|
des.object({ id = "oil lamp", lit = true });
|
|
end
|
|
},
|
|
|
|
-- Temple of the gods
|
|
function(rm)
|
|
des.altar({ align = align[1] });
|
|
des.altar({ align = align[2] });
|
|
des.altar({ align = align[3] });
|
|
end,
|
|
|
|
-- Ghost of an Adventurer
|
|
function(rm)
|
|
local loc = selection.room():rndcoord(0);
|
|
des.monster({ id = "ghost", asleep = true, waiting = true, coord = loc });
|
|
if percent(65) then
|
|
des.object({ id = "dagger", coord = loc, buc = "not-blessed" });
|
|
end
|
|
if percent(55) then
|
|
des.object({ class = ")", coord = loc, buc = "not-blessed" });
|
|
end
|
|
if percent(45) then
|
|
des.object({ id = "bow", coord = loc, buc = "not-blessed" });
|
|
des.object({ id = "arrow", coord = loc, buc = "not-blessed" });
|
|
end
|
|
if percent(65) then
|
|
des.object({ class = "[", coord = loc, buc = "not-blessed" });
|
|
end
|
|
if percent(20) then
|
|
des.object({ class = "=", coord = loc, buc = "not-blessed" });
|
|
end
|
|
if percent(20) then
|
|
des.object({ class = "?", coord = loc, buc = "not-blessed" });
|
|
end
|
|
end,
|
|
|
|
-- Storeroom
|
|
function(rm)
|
|
local locs = selection.room():percentage(30);
|
|
local func = function(x,y)
|
|
if (percent(25)) then
|
|
des.object("chest");
|
|
else
|
|
des.monster({ class = "m", appear_as = "obj:chest" });
|
|
end
|
|
end;
|
|
locs:iterate(func);
|
|
end,
|
|
};
|
|
|
|
themerooms = {
|
|
{
|
|
-- the "default" room
|
|
frequency = 1000,
|
|
contents = function()
|
|
des.room({ type = "ordinary", filled = 1 });
|
|
end
|
|
},
|
|
|
|
-- Fake Delphi
|
|
function()
|
|
des.room({ type = "ordinary", w = 11,h = 9, filled = 1,
|
|
contents = function()
|
|
des.room({ type = "ordinary", x = 4,y = 3, w = 3,h = 3, filled = 1,
|
|
contents = function()
|
|
des.door({ state="random", wall="all" });
|
|
end
|
|
});
|
|
end
|
|
});
|
|
end,
|
|
|
|
-- Room in a room
|
|
function()
|
|
des.room({ type = "ordinary", filled = 1,
|
|
contents = function()
|
|
des.room({ type = "ordinary",
|
|
contents = function()
|
|
des.door({ state="random", wall="all" });
|
|
end
|
|
});
|
|
end
|
|
});
|
|
end,
|
|
|
|
-- Huge room, with another room inside (90%)
|
|
function()
|
|
des.room({ type = "ordinary", w = nh.rn2(10)+11,h = nh.rn2(5)+8, filled = 1,
|
|
contents = function()
|
|
if (percent(90)) then
|
|
des.room({ type = "ordinary", filled = 1,
|
|
contents = function()
|
|
des.door({ state="random", wall="all" });
|
|
if (percent(50)) then
|
|
des.door({ state="random", wall="all" });
|
|
end
|
|
end
|
|
});
|
|
end
|
|
end
|
|
});
|
|
end,
|
|
|
|
-- Nesting rooms
|
|
function()
|
|
des.room({ type = "ordinary", w = 9 + nh.rn2(4), h = 9 + nh.rn2(4), filled = 1,
|
|
contents = function(rm)
|
|
local wid = math.random(math.floor(rm.width / 2), rm.width - 2);
|
|
local hei = math.random(math.floor(rm.height / 2), rm.height - 2);
|
|
des.room({ type = "ordinary", w = wid,h = hei, filled = 1,
|
|
contents = function()
|
|
if (percent(90)) then
|
|
des.room({ type = "ordinary", filled = 1,
|
|
contents = function()
|
|
des.door({ state="random", wall="all" });
|
|
if (percent(15)) then
|
|
des.door({ state="random", wall="all" });
|
|
end
|
|
end
|
|
});
|
|
end
|
|
des.door({ state="random", wall="all" });
|
|
if (percent(15)) then
|
|
des.door({ state="random", wall="all" });
|
|
end
|
|
end
|
|
});
|
|
end
|
|
});
|
|
end,
|
|
|
|
{
|
|
frequency = 6,
|
|
contents = function()
|
|
des.room({ type = "themed", contents = themeroom_fill });
|
|
end
|
|
},
|
|
|
|
{
|
|
frequency = 2,
|
|
contents = function()
|
|
des.room({ type = "themed", lit = 0, contents = themeroom_fill });
|
|
end
|
|
},
|
|
|
|
{
|
|
frequency = 2,
|
|
contents = function()
|
|
des.room({ type = "themed", filled = 1, contents = themeroom_fill });
|
|
end
|
|
},
|
|
|
|
-- Pillars
|
|
function()
|
|
des.room({ type = "themed", w = 10, h = 10,
|
|
contents = function(rm)
|
|
local terr = { "-", "-", "-", "-", "L", "P", "T" };
|
|
shuffle(terr);
|
|
for x = 0, (rm.width / 4) - 1 do
|
|
for y = 0, (rm.height / 4) - 1 do
|
|
des.terrain({ x = x * 4 + 2, y = y * 4 + 2, typ = terr[1], lit = -2 });
|
|
des.terrain({ x = x * 4 + 3, y = y * 4 + 2, typ = terr[1], lit = -2 });
|
|
des.terrain({ x = x * 4 + 2, y = y * 4 + 3, typ = terr[1], lit = -2 });
|
|
des.terrain({ x = x * 4 + 3, y = y * 4 + 3, typ = terr[1], lit = -2 });
|
|
end
|
|
end
|
|
end
|
|
});
|
|
end,
|
|
|
|
-- Mausoleum
|
|
function()
|
|
des.room({ type = "themed", w = 5 + nh.rn2(3)*2, h = 5 + nh.rn2(3)*2,
|
|
contents = function(rm)
|
|
des.room({ type = "themed",
|
|
x = (rm.width - 1) / 2, y = (rm.height - 1) / 2,
|
|
w = 1, h = 1, joined = false,
|
|
contents = function()
|
|
if (percent(50)) then
|
|
local mons = { "M", "V", "L", "Z" };
|
|
shuffle(mons);
|
|
des.monster({ class = mons[1], x=0,y=0, waiting = 1 });
|
|
else
|
|
des.object({ id = "corpse", montype = "@", coord = {0,0} });
|
|
end
|
|
if (percent(20)) then
|
|
des.door({ state="secret", wall="all" });
|
|
end
|
|
end
|
|
});
|
|
end
|
|
});
|
|
end,
|
|
|
|
-- Random dungeon feature in the middle of a odd-sized room
|
|
function()
|
|
local wid = 3 + (nh.rn2(3) * 2);
|
|
local hei = 3 + (nh.rn2(3) * 2);
|
|
des.room({ type = "ordinary", filled = 1, w = wid, h = hei,
|
|
contents = function(rm)
|
|
local feature = { "C", "L", "I", "P", "T" };
|
|
shuffle(feature);
|
|
des.terrain((rm.width - 1) / 2, (rm.height - 1) / 2,
|
|
feature[1]);
|
|
end
|
|
});
|
|
end,
|
|
|
|
-- L-shaped
|
|
function()
|
|
des.map({ map = [[
|
|
-----xxx
|
|
|...|xxx
|
|
|...|xxx
|
|
|...----
|
|
|......|
|
|
|......|
|
|
|......|
|
|
--------]], contents = function(m) filler_region(1,1); end });
|
|
end,
|
|
|
|
-- L-shaped, rot 1
|
|
function()
|
|
des.map({ map = [[
|
|
xxx-----
|
|
xxx|...|
|
|
xxx|...|
|
|
----...|
|
|
|......|
|
|
|......|
|
|
|......|
|
|
--------]], contents = function(m) filler_region(5,1); end });
|
|
end,
|
|
|
|
-- L-shaped, rot 2
|
|
function()
|
|
des.map({ map = [[
|
|
--------
|
|
|......|
|
|
|......|
|
|
|......|
|
|
----...|
|
|
xxx|...|
|
|
xxx|...|
|
|
xxx-----]], contents = function(m) filler_region(1,1); end });
|
|
end,
|
|
|
|
-- L-shaped, rot 3
|
|
function()
|
|
des.map({ map = [[
|
|
--------
|
|
|......|
|
|
|......|
|
|
|......|
|
|
|...----
|
|
|...|xxx
|
|
|...|xxx
|
|
-----xxx]], contents = function(m) filler_region(1,1); end });
|
|
end,
|
|
|
|
-- Blocked center
|
|
function()
|
|
des.map({ map = [[
|
|
-----------
|
|
|.........|
|
|
|.........|
|
|
|.........|
|
|
|...LLL...|
|
|
|...LLL...|
|
|
|...LLL...|
|
|
|.........|
|
|
|.........|
|
|
|.........|
|
|
-----------]], contents = function(m)
|
|
if (percent(30)) then
|
|
local terr = { "-", "P" };
|
|
shuffle(terr);
|
|
des.replace_terrain({ region = {1,1, 9,9}, fromterrain = "L", toterrain = terr[1] });
|
|
end
|
|
filler_region(1,1);
|
|
end });
|
|
end,
|
|
|
|
-- Circular, small
|
|
function()
|
|
des.map({ map = [[
|
|
xx---xx
|
|
x--.--x
|
|
--...--
|
|
|.....|
|
|
--...--
|
|
x--.--x
|
|
xx---xx]], contents = function(m) filler_region(3,3); end });
|
|
end,
|
|
|
|
-- Circular, medium
|
|
function()
|
|
des.map({ map = [[
|
|
xx-----xx
|
|
x--...--x
|
|
--.....--
|
|
|.......|
|
|
|.......|
|
|
|.......|
|
|
--.....--
|
|
x--...--x
|
|
xx-----xx]], contents = function(m) filler_region(4,4); end });
|
|
end,
|
|
|
|
-- Circular, big
|
|
function()
|
|
des.map({ map = [[
|
|
xxx-----xxx
|
|
x---...---x
|
|
x-.......-x
|
|
--.......--
|
|
|.........|
|
|
|.........|
|
|
|.........|
|
|
--.......--
|
|
x-.......-x
|
|
x---...---x
|
|
xxx-----xxx]], contents = function(m) filler_region(5,5); end });
|
|
end,
|
|
|
|
-- T-shaped
|
|
function()
|
|
des.map({ map = [[
|
|
xxx-----xxx
|
|
xxx|...|xxx
|
|
xxx|...|xxx
|
|
----...----
|
|
|.........|
|
|
|.........|
|
|
|.........|
|
|
-----------]], contents = function(m) filler_region(5,5); end });
|
|
end,
|
|
|
|
-- T-shaped, rot 1
|
|
function()
|
|
des.map({ map = [[
|
|
-----xxx
|
|
|...|xxx
|
|
|...|xxx
|
|
|...----
|
|
|......|
|
|
|......|
|
|
|......|
|
|
|...----
|
|
|...|xxx
|
|
|...|xxx
|
|
-----xxx]], contents = function(m) filler_region(2,2); end });
|
|
end,
|
|
|
|
-- T-shaped, rot 2
|
|
function()
|
|
des.map({ map = [[
|
|
-----------
|
|
|.........|
|
|
|.........|
|
|
|.........|
|
|
----...----
|
|
xxx|...|xxx
|
|
xxx|...|xxx
|
|
xxx-----xxx]], contents = function(m) filler_region(2,2); end });
|
|
end,
|
|
|
|
-- T-shaped, rot 3
|
|
function()
|
|
des.map({ map = [[
|
|
xxx-----
|
|
xxx|...|
|
|
xxx|...|
|
|
----...|
|
|
|......|
|
|
|......|
|
|
|......|
|
|
----...|
|
|
xxx|...|
|
|
xxx|...|
|
|
xxx-----]], contents = function(m) filler_region(5,5); end });
|
|
end,
|
|
|
|
-- S-shaped
|
|
function()
|
|
des.map({ map = [[
|
|
-----xxx
|
|
|...|xxx
|
|
|...|xxx
|
|
|...----
|
|
|......|
|
|
|......|
|
|
|......|
|
|
----...|
|
|
xxx|...|
|
|
xxx|...|
|
|
xxx-----]], contents = function(m) filler_region(2,2); end });
|
|
end,
|
|
|
|
-- S-shaped, rot 1
|
|
function()
|
|
des.map({ map = [[
|
|
xxx--------
|
|
xxx|......|
|
|
xxx|......|
|
|
----......|
|
|
|......----
|
|
|......|xxx
|
|
|......|xxx
|
|
--------xxx]], contents = function(m) filler_region(5,5); end });
|
|
end,
|
|
|
|
-- Z-shaped
|
|
function()
|
|
des.map({ map = [[
|
|
xxx-----
|
|
xxx|...|
|
|
xxx|...|
|
|
----...|
|
|
|......|
|
|
|......|
|
|
|......|
|
|
|...----
|
|
|...|xxx
|
|
|...|xxx
|
|
-----xxx]], contents = function(m) filler_region(5,5); end });
|
|
end,
|
|
|
|
-- Z-shaped, rot 1
|
|
function()
|
|
des.map({ map = [[
|
|
--------xxx
|
|
|......|xxx
|
|
|......|xxx
|
|
|......----
|
|
----......|
|
|
xxx|......|
|
|
xxx|......|
|
|
xxx--------]], contents = function(m) filler_region(2,2); end });
|
|
end,
|
|
|
|
-- Cross
|
|
function()
|
|
des.map({ map = [[
|
|
xxx-----xxx
|
|
xxx|...|xxx
|
|
xxx|...|xxx
|
|
----...----
|
|
|.........|
|
|
|.........|
|
|
|.........|
|
|
----...----
|
|
xxx|...|xxx
|
|
xxx|...|xxx
|
|
xxx-----xxx]], contents = function(m) filler_region(6,6); end });
|
|
end,
|
|
|
|
-- Four-leaf clover
|
|
function()
|
|
des.map({ map = [[
|
|
-----x-----
|
|
|...|x|...|
|
|
|...---...|
|
|
|.........|
|
|
---.....---
|
|
xx|.....|xx
|
|
---.....---
|
|
|.........|
|
|
|...---...|
|
|
|...|x|...|
|
|
-----x-----]], contents = function(m) filler_region(6,6); end });
|
|
end,
|
|
|
|
-- Water-surrounded vault
|
|
function()
|
|
des.map({ map = [[
|
|
}}}}}}
|
|
}----}
|
|
}|..|}
|
|
}|..|}
|
|
}----}
|
|
}}}}}}]], contents = function(m) des.region({ region={3,3,3,3}, type="themed", irregular=true, filled=0, joined=false });
|
|
local nasty_undead = { "giant zombie", "ettin zombie", "vampire lord" };
|
|
des.object("chest", 2, 2);
|
|
des.object("chest", 3, 2);
|
|
des.object("chest", 2, 3);
|
|
des.object("chest", 3, 3);
|
|
shuffle(nasty_undead);
|
|
des.monster(nasty_undead[1], 2, 2);
|
|
end });
|
|
end,
|
|
|
|
-- Twin businesses
|
|
{
|
|
mindiff = 4; -- arbitrary
|
|
contents = function()
|
|
-- Due to the way room connections work in mklev.c, we must guarantee
|
|
-- that the "aisle" between the shops touches all four walls of the
|
|
-- larger room. Thus it has an extra width and height.
|
|
des.room({ type="themed", w=9, h=5, contents = function()
|
|
-- There are eight possible placements of the two shops, four of
|
|
-- which have the vertical aisle in the center.
|
|
southeast = function() return percent(50) and "south" or "east" end
|
|
northeast = function() return percent(50) and "north" or "east" end
|
|
northwest = function() return percent(50) and "north" or "west" end
|
|
southwest = function() return percent(50) and "south" or "west" end
|
|
placements = {
|
|
{ lx = 1, ly = 1, rx = 4, ry = 1, lwall = "south", rwall = southeast() },
|
|
{ lx = 1, ly = 2, rx = 4, ry = 2, lwall = "north", rwall = northeast() },
|
|
{ lx = 1, ly = 1, rx = 5, ry = 1, lwall = southeast(), rwall = southwest() },
|
|
{ lx = 1, ly = 1, rx = 5, ry = 2, lwall = southeast(), rwall = northwest() },
|
|
{ lx = 1, ly = 2, rx = 5, ry = 1, lwall = northeast(), rwall = southwest() },
|
|
{ lx = 1, ly = 2, rx = 5, ry = 2, lwall = northeast(), rwall = northwest() },
|
|
{ lx = 2, ly = 1, rx = 5, ry = 1, lwall = southwest(), rwall = "south" },
|
|
{ lx = 2, ly = 2, rx = 5, ry = 2, lwall = northwest(), rwall = "north" }
|
|
}
|
|
ltype,rtype = "weapon shop","armor shop"
|
|
if percent(50) then
|
|
ltype,rtype = rtype,ltype
|
|
end
|
|
shopdoorstate = function()
|
|
if percent(1) then
|
|
return "locked"
|
|
elseif percent(50) then
|
|
return "closed"
|
|
else
|
|
return "open"
|
|
end
|
|
end
|
|
p = placements[d(#placements)]
|
|
des.room({ type=ltype, x=p["lx"], y=p["ly"], w=3, h=3, filled=1, joined=false,
|
|
contents = function()
|
|
des.door({ state=shopdoorstate(), wall=p["lwall"] })
|
|
end
|
|
});
|
|
des.room({ type=rtype, x=p["rx"], y=p["ry"], w=3, h=3, filled=1, joined=false,
|
|
contents = function()
|
|
des.door({ state=shopdoorstate(), wall=p["rwall"] })
|
|
end
|
|
});
|
|
end
|
|
});
|
|
end
|
|
},
|
|
|
|
};
|
|
|
|
|
|
function filler_region(x, y)
|
|
local rmtyp = "ordinary";
|
|
local func = nil;
|
|
if (percent(30)) then
|
|
rmtyp = "themed";
|
|
func = themeroom_fill;
|
|
end
|
|
des.region({ region={x,y,x,y}, type=rmtyp, irregular=true, filled=1, contents = func });
|
|
end
|
|
|
|
function is_eligible(room, mkrm)
|
|
local t = type(room);
|
|
local diff = nh.level_difficulty();
|
|
if (t == "table") then
|
|
if (room.mindiff ~= nil and diff < room.mindiff) then
|
|
return false
|
|
elseif (room.maxdiff ~= nil and diff > room.maxdiff) then
|
|
return false
|
|
end
|
|
if (mkrm ~= nil and room.eligible ~= nil) then
|
|
return room.eligible(mkrm);
|
|
end
|
|
elseif (t == "function") then
|
|
-- functions currently have no constraints
|
|
end
|
|
return true
|
|
end
|
|
|
|
-- called repeatedly until the core decides there are enough rooms
|
|
function themerooms_generate()
|
|
local pick = 1;
|
|
local total_frequency = 0;
|
|
for i = 1, #themerooms do
|
|
-- Reservoir sampling: select one room from the set of eligible rooms,
|
|
-- which may change on different levels because of level difficulty.
|
|
if is_eligible(themerooms[i], nil) then
|
|
local this_frequency;
|
|
if (type(themerooms[i]) == "table" and themerooms[i].frequency ~= nil) then
|
|
this_frequency = themerooms[i].frequency;
|
|
else
|
|
this_frequency = 1;
|
|
end
|
|
total_frequency = total_frequency + this_frequency;
|
|
-- avoid rn2(0) if a room has freq 0
|
|
if this_frequency > 0 and nh.rn2(total_frequency) < this_frequency then
|
|
pick = i;
|
|
end
|
|
end
|
|
end
|
|
|
|
local t = type(themerooms[pick]);
|
|
if (t == "table") then
|
|
themerooms[pick].contents();
|
|
elseif (t == "function") then
|
|
themerooms[pick]();
|
|
end
|
|
end
|
|
|
|
-- called before any rooms are generated
|
|
function pre_themerooms_generate()
|
|
-- reset the buried treasure location
|
|
buried_treasure = { };
|
|
end
|
|
|
|
-- called after all rooms have been generated
|
|
function post_themerooms_generate()
|
|
if (buried_treasure.x ~= nil) then
|
|
local floors = selection.negate():filter_mapchar(".");
|
|
local pos = floors:rndcoord(0);
|
|
local tx = buried_treasure.x - pos.x - 1;
|
|
local ty = buried_treasure.y - pos.y;
|
|
local dig = "";
|
|
if (tx == 0 and ty == 0) then
|
|
dig = " here";
|
|
else
|
|
if (tx < 0 or tx > 0) then
|
|
dig = string.format(" %i %s", math.abs(tx), (tx > 0) and "east" or "west");
|
|
end
|
|
if (ty < 0 or ty > 0) then
|
|
dig = dig .. string.format(" %i %s", math.abs(ty), (ty > 0) and "south" or "north");
|
|
end
|
|
end
|
|
des.engraving({ coord = pos, type = "burn", text = "Dig" .. dig });
|
|
end
|
|
end
|
|
|
|
function themeroom_fill(rm)
|
|
local pick = 1;
|
|
local total_frequency = 0;
|
|
for i = 1, #themeroom_fills do
|
|
-- Reservoir sampling: select one room from the set of eligible rooms,
|
|
-- which may change on different levels because of level difficulty.
|
|
if is_eligible(themeroom_fills[i], rm) then
|
|
local this_frequency;
|
|
if (type(themeroom_fills[i]) == "table" and themeroom_fills[i].frequency ~= nil) then
|
|
this_frequency = themeroom_fills[i].frequency;
|
|
else
|
|
this_frequency = 1;
|
|
end
|
|
total_frequency = total_frequency + this_frequency;
|
|
-- avoid rn2(0) if a room has freq 0
|
|
if this_frequency > 0 and nh.rn2(total_frequency) < this_frequency then
|
|
pick = i;
|
|
end
|
|
end
|
|
end
|
|
|
|
local t = type(themeroom_fills[pick]);
|
|
if (t == "table") then
|
|
themeroom_fills[pick].contents(rm);
|
|
elseif (t == "function") then
|
|
themeroom_fills[pick](rm);
|
|
end
|
|
end
|
|
|