Split themeroom shape from themeroom contents
Previously, the tetris-shaped rooms were always either normal rooms, or turned into shops or other special rooms in NetHack core. Now, the themed room lua code first picks the themed room (which can be a themed or shaped), and some of those will then pick a random filling (eg. ice floor, traps, corpses, 3 altars). Adds a new lua binding to create a selection picking locations in current room. The content-function in special level regions now get passed the room data as a parameter.
This commit is contained in:
396
dat/themerms.lua
396
dat/themerms.lua
@@ -17,6 +17,139 @@
|
||||
-- core calls themerooms_generate() multiple times per level
|
||||
-- to generate a single themed room.
|
||||
|
||||
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()
|
||||
for i = 1, d(3,4) do
|
||||
des.object();
|
||||
end
|
||||
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,
|
||||
|
||||
};
|
||||
|
||||
themerooms = {
|
||||
{
|
||||
-- the "default" room
|
||||
@@ -71,114 +204,26 @@ themerooms = {
|
||||
});
|
||||
end,
|
||||
|
||||
-- Ice room
|
||||
function()
|
||||
des.room({ type = "themed", filled = 1,
|
||||
contents = function()
|
||||
local ice = selection.floodfill(1,1);
|
||||
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
|
||||
});
|
||||
end,
|
||||
|
||||
-- Boulder room
|
||||
{
|
||||
mindiff = 4,
|
||||
frequency = 6,
|
||||
contents = function()
|
||||
des.room({ type = "themed",
|
||||
contents = function(rm)
|
||||
for x = 0, rm.width - 1 do
|
||||
for y = 0, rm.height - 1 do
|
||||
if (percent(30)) then
|
||||
if (percent(50)) then
|
||||
des.object("boulder");
|
||||
else
|
||||
des.trap("rolling boulder");
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
});
|
||||
des.room({ type = "themed", contents = themeroom_fill });
|
||||
end
|
||||
},
|
||||
|
||||
-- Spider nest
|
||||
function()
|
||||
des.room({ type = "themed",
|
||||
contents = function(rm)
|
||||
local spooders = nh.level_difficulty() > 8;
|
||||
for x = 0, rm.width - 1 do
|
||||
for y = 0, rm.height - 1 do
|
||||
if (percent(30)) then
|
||||
des.trap({ type = "web", x = x, y = y,
|
||||
spider_on_web = spooders and percent(80) });
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
});
|
||||
end,
|
||||
{
|
||||
frequency = 2,
|
||||
contents = function()
|
||||
des.room({ type = "themed", lit = 0, contents = themeroom_fill });
|
||||
end
|
||||
},
|
||||
|
||||
-- Trap room
|
||||
function()
|
||||
des.room({ type = "themed", filled = 0,
|
||||
contents = function(rm)
|
||||
local traps = { "arrow", "dart", "falling rock", "bear",
|
||||
"land mine", "sleep gas", "rust",
|
||||
"anti magic" };
|
||||
shuffle(traps);
|
||||
for x = 0, rm.width - 1 do
|
||||
for y = 0, rm.height - 1 do
|
||||
if (percent(30)) then
|
||||
des.trap(traps[1], x, y);
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
});
|
||||
end,
|
||||
|
||||
-- Buried treasure
|
||||
function()
|
||||
des.room({ type = "ordinary", filled = 1,
|
||||
contents = function()
|
||||
des.object({ id = "chest", buried = true, contents = function()
|
||||
for i = 1, d(3,4) do
|
||||
des.object();
|
||||
end
|
||||
end });
|
||||
end
|
||||
});
|
||||
end,
|
||||
|
||||
-- Massacre
|
||||
function()
|
||||
des.room({ type = "themed",
|
||||
contents = function()
|
||||
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" };
|
||||
shuffle(mon);
|
||||
for i = 1, d(5,5) do
|
||||
if (percent(10)) then shuffle(mon); end
|
||||
des.object({ id = "corpse", montype = mon[1] });
|
||||
end
|
||||
end
|
||||
});
|
||||
end,
|
||||
{
|
||||
frequency = 2,
|
||||
contents = function()
|
||||
des.room({ type = "themed", filled = 1, contents = themeroom_fill });
|
||||
end
|
||||
},
|
||||
|
||||
-- Pillars
|
||||
function()
|
||||
@@ -198,70 +243,6 @@ themerooms = {
|
||||
});
|
||||
end,
|
||||
|
||||
-- Statuary
|
||||
function()
|
||||
des.room({ type = "themed",
|
||||
contents = function()
|
||||
for i = 1, d(5,5) do
|
||||
des.object({ id = "statue" });
|
||||
end
|
||||
for i = 1, d(3) do
|
||||
des.trap("statue");
|
||||
end
|
||||
end
|
||||
});
|
||||
end,
|
||||
|
||||
-- Light source
|
||||
function()
|
||||
des.room({ type = "themed", lit = 0,
|
||||
contents = function()
|
||||
des.object({ id = "oil lamp", lit = true });
|
||||
end
|
||||
});
|
||||
end,
|
||||
|
||||
-- Temple of the gods
|
||||
function()
|
||||
des.room({ type = "themed",
|
||||
contents = function()
|
||||
des.altar({ align = align[1] });
|
||||
des.altar({ align = align[2] });
|
||||
des.altar({ align = align[3] });
|
||||
end
|
||||
});
|
||||
end,
|
||||
|
||||
-- Ghost of an Adventurer
|
||||
function()
|
||||
des.room({ type = "themed", lit = 0,
|
||||
contents = function(rm)
|
||||
local px = nh.rn2(rm.width);
|
||||
local py = nh.rn2(rm.height);
|
||||
des.monster({ id = "ghost", asleep = true, waiting = true, coord = {px,py} });
|
||||
if percent(65) then
|
||||
des.object({ id = "dagger", coord = {px,py}, buc = "not-blessed" });
|
||||
end
|
||||
if percent(55) then
|
||||
des.object({ class = ")", coord = {px,py}, buc = "not-blessed" });
|
||||
end
|
||||
if percent(45) then
|
||||
des.object({ id = "bow", coord = {px,py}, buc = "not-blessed" });
|
||||
des.object({ id = "arrow", coord = {px,py}, buc = "not-blessed" });
|
||||
end
|
||||
if percent(65) then
|
||||
des.object({ class = "[", coord = {px,py}, buc = "not-blessed" });
|
||||
end
|
||||
if percent(20) then
|
||||
des.object({ class = "=", coord = {px,py}, buc = "not-blessed" });
|
||||
end
|
||||
if percent(20) then
|
||||
des.object({ class = "?", coord = {px,py}, buc = "not-blessed" });
|
||||
end
|
||||
end
|
||||
});
|
||||
end,
|
||||
|
||||
-- Mausoleum
|
||||
function()
|
||||
des.room({ type = "themed", w = 5 + nh.rn2(3)*2, h = 5 + nh.rn2(3)*2,
|
||||
@@ -310,7 +291,7 @@ themerooms = {
|
||||
|......|
|
||||
|......|
|
||||
|......|
|
||||
--------]], contents = function(m) des.region({ region={1,1,3,3}, type="ordinary", irregular=true, filled=1 }); end });
|
||||
--------]], contents = function(m) filler_region(1,1); end });
|
||||
end,
|
||||
|
||||
-- L-shaped, rot 1
|
||||
@@ -323,7 +304,7 @@ xxx|...|
|
||||
|......|
|
||||
|......|
|
||||
|......|
|
||||
--------]], contents = function(m) des.region({ region={5,1,5,3}, type="ordinary", irregular=true, filled=1 }); end });
|
||||
--------]], contents = function(m) filler_region(5,1); end });
|
||||
end,
|
||||
|
||||
-- L-shaped, rot 2
|
||||
@@ -336,7 +317,7 @@ xxx|...|
|
||||
----...|
|
||||
xxx|...|
|
||||
xxx|...|
|
||||
xxx-----]], contents = function(m) des.region({ region={1,1,2,2}, type="ordinary", irregular=true, filled=1 }); end });
|
||||
xxx-----]], contents = function(m) filler_region(1,1); end });
|
||||
end,
|
||||
|
||||
-- L-shaped, rot 3
|
||||
@@ -349,7 +330,7 @@ xxx-----]], contents = function(m) des.region({ region={1,1,2,2}, type="ordinary
|
||||
|...----
|
||||
|...|xxx
|
||||
|...|xxx
|
||||
-----xxx]], contents = function(m) des.region({ region={1,1,2,2}, type="ordinary", irregular=true, filled=1 }); end });
|
||||
-----xxx]], contents = function(m) filler_region(1,1); end });
|
||||
end,
|
||||
|
||||
-- Blocked center
|
||||
@@ -371,7 +352,7 @@ if (percent(30)) then
|
||||
shuffle(terr);
|
||||
des.replace_terrain({ region = {1,1, 9,9}, fromterrain = "L", toterrain = terr[1] });
|
||||
end
|
||||
des.region({ region={1,1,2,2}, type="ordinary", irregular=true, filled=1 });
|
||||
filler_region(1,1);
|
||||
end });
|
||||
end,
|
||||
|
||||
@@ -384,7 +365,7 @@ x--.--x
|
||||
|.....|
|
||||
--...--
|
||||
x--.--x
|
||||
xx---xx]], contents = function(m) des.region({ region={3,3,3,3}, type="ordinary", irregular=true, filled=1 }); end });
|
||||
xx---xx]], contents = function(m) filler_region(3,3); end });
|
||||
end,
|
||||
|
||||
-- Circular, medium
|
||||
@@ -398,7 +379,7 @@ x--...--x
|
||||
|.......|
|
||||
--.....--
|
||||
x--...--x
|
||||
xx-----xx]], contents = function(m) des.region({ region={4,4,4,4}, type="ordinary", irregular=true, filled=1 }); end });
|
||||
xx-----xx]], contents = function(m) filler_region(4,4); end });
|
||||
end,
|
||||
|
||||
-- Circular, big
|
||||
@@ -414,7 +395,7 @@ x-.......-x
|
||||
--.......--
|
||||
x-.......-x
|
||||
x---...---x
|
||||
xxx-----xxx]], contents = function(m) des.region({ region={5,5,5,5}, type="ordinary", irregular=true, filled=1 }); end });
|
||||
xxx-----xxx]], contents = function(m) filler_region(5,5); end });
|
||||
end,
|
||||
|
||||
-- T-shaped
|
||||
@@ -427,7 +408,7 @@ xxx|...|xxx
|
||||
|.........|
|
||||
|.........|
|
||||
|.........|
|
||||
-----------]], contents = function(m) des.region({ region={5,5,5,5}, type="ordinary", irregular=true, filled=1 }); end });
|
||||
-----------]], contents = function(m) filler_region(5,5); end });
|
||||
end,
|
||||
|
||||
-- T-shaped, rot 1
|
||||
@@ -443,7 +424,7 @@ xxx|...|xxx
|
||||
|...----
|
||||
|...|xxx
|
||||
|...|xxx
|
||||
-----xxx]], contents = function(m) des.region({ region={2,2,2,2}, type="ordinary", irregular=true, filled=1 }); end });
|
||||
-----xxx]], contents = function(m) filler_region(2,2); end });
|
||||
end,
|
||||
|
||||
-- T-shaped, rot 2
|
||||
@@ -456,7 +437,7 @@ xxx|...|xxx
|
||||
----...----
|
||||
xxx|...|xxx
|
||||
xxx|...|xxx
|
||||
xxx-----xxx]], contents = function(m) des.region({ region={2,2,2,2}, type="ordinary", irregular=true, filled=1 }); end });
|
||||
xxx-----xxx]], contents = function(m) filler_region(2,2); end });
|
||||
end,
|
||||
|
||||
-- T-shaped, rot 3
|
||||
@@ -472,7 +453,7 @@ xxx|...|
|
||||
----...|
|
||||
xxx|...|
|
||||
xxx|...|
|
||||
xxx-----]], contents = function(m) des.region({ region={5,5,5,5}, type="ordinary", irregular=true, filled=1 }); end });
|
||||
xxx-----]], contents = function(m) filler_region(5,5); end });
|
||||
end,
|
||||
|
||||
-- S-shaped
|
||||
@@ -488,7 +469,7 @@ xxx-----]], contents = function(m) des.region({ region={5,5,5,5}, type="ordinary
|
||||
----...|
|
||||
xxx|...|
|
||||
xxx|...|
|
||||
xxx-----]], contents = function(m) des.region({ region={2,2,2,2}, type="ordinary", irregular=true, filled=1 }); end });
|
||||
xxx-----]], contents = function(m) filler_region(2,2); end });
|
||||
end,
|
||||
|
||||
-- S-shaped, rot 1
|
||||
@@ -501,7 +482,7 @@ xxx|......|
|
||||
|......----
|
||||
|......|xxx
|
||||
|......|xxx
|
||||
--------xxx]], contents = function(m) des.region({ region={5,5,5,5}, type="ordinary", irregular=true, filled=1 }); end });
|
||||
--------xxx]], contents = function(m) filler_region(5,5); end });
|
||||
end,
|
||||
|
||||
-- Z-shaped
|
||||
@@ -517,7 +498,7 @@ xxx|...|
|
||||
|...----
|
||||
|...|xxx
|
||||
|...|xxx
|
||||
-----xxx]], contents = function(m) des.region({ region={5,5,5,5}, type="ordinary", irregular=true, filled=1 }); end });
|
||||
-----xxx]], contents = function(m) filler_region(5,5); end });
|
||||
end,
|
||||
|
||||
-- Z-shaped, rot 1
|
||||
@@ -530,7 +511,7 @@ xxx|...|
|
||||
----......|
|
||||
xxx|......|
|
||||
xxx|......|
|
||||
xxx--------]], contents = function(m) des.region({ region={2,2,2,2}, type="ordinary", irregular=true, filled=1 }); end });
|
||||
xxx--------]], contents = function(m) filler_region(2,2); end });
|
||||
end,
|
||||
|
||||
-- Cross
|
||||
@@ -546,7 +527,7 @@ xxx|...|xxx
|
||||
----...----
|
||||
xxx|...|xxx
|
||||
xxx|...|xxx
|
||||
xxx-----xxx]], contents = function(m) des.region({ region={6,6,6,6}, type="ordinary", irregular=true, filled=1 }); end });
|
||||
xxx-----xxx]], contents = function(m) filler_region(6,6); end });
|
||||
end,
|
||||
|
||||
-- Four-leaf clover
|
||||
@@ -562,7 +543,7 @@ xx|.....|xx
|
||||
|.........|
|
||||
|...---...|
|
||||
|...|x|...|
|
||||
-----x-----]], contents = function(m) des.region({ region={6,6,6,6}, type="ordinary", irregular=true, filled=1 }); end });
|
||||
-----x-----]], contents = function(m) filler_region(6,6); end });
|
||||
end,
|
||||
|
||||
-- Water-surrounded vault
|
||||
@@ -639,7 +620,18 @@ end });
|
||||
|
||||
};
|
||||
|
||||
function is_eligible(room)
|
||||
|
||||
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
|
||||
@@ -648,6 +640,9 @@ function is_eligible(room)
|
||||
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
|
||||
@@ -660,7 +655,7 @@ function themerooms_generate()
|
||||
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]) then
|
||||
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;
|
||||
@@ -682,3 +677,32 @@ function themerooms_generate()
|
||||
themerooms[pick]();
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user