diff --git a/dat/themerms.lua b/dat/themerms.lua index 85c3e18f4..db831a496 100644 --- a/dat/themerms.lua +++ b/dat/themerms.lua @@ -1,7 +1,10 @@ -- themerooms is an array of tables and/or functions. --- the tables define "frequency" and "contents", --- a plain function has frequency of 1 +-- 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 @@ -538,36 +541,45 @@ end }); }; -local total_frequency = 0; -for i = 1, #themerooms do - local t = type(themerooms[i]); +function is_eligible(room) + local t = type(room); + local diff = nh.level_difficulty(); if (t == "table") then - total_frequency = total_frequency + themerooms[i].frequency; + if (room.mindiff ~= nil and diff < room.mindiff) then + return false + elseif (room.maxdiff ~= nil and diff > room.maxdiff) then + return false + end elseif (t == "function") then - total_frequency = total_frequency + 1; + -- functions currently have no constraints end -end - -if (total_frequency == 0) then - error("Theme rooms total_frequency == 0"); + return true end function themerooms_generate() - local pick = nh.rn2(total_frequency); + local pick = 1; + local total_frequency = 0; for i = 1, #themerooms do - local t = type(themerooms[i]); - if (t == "table") then - pick = pick - themerooms[i].frequency; - if (pick < 0) then - themerooms[i].contents(); - return; + -- 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 + local this_frequency; + if (type(themerooms[i]) == "table" and themerooms[i].frequency ~= nil) then + this_frequency = themerooms[i].frequency; + else + this_frequency = 1; end - elseif (t == "function") then - pick = pick - 1; - if (pick < 0) then - themerooms[i](); - return; + total_frequency = total_frequency + this_frequency; + if (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 diff --git a/src/nhlua.c b/src/nhlua.c index 24bcc5d59..b3906592b 100644 --- a/src/nhlua.c +++ b/src/nhlua.c @@ -34,6 +34,7 @@ static int FDECL(nhl_ing_suffix, (lua_State *)); static int FDECL(nhl_an, (lua_State *)); static int FDECL(nhl_rn2, (lua_State *)); static int FDECL(nhl_random, (lua_State *)); +static int FDECL(nhl_level_difficulty, (lua_State *)); static void FDECL(init_nhc_data, (lua_State *)); static int FDECL(nhl_push_anything, (lua_State *, int, void *)); static int FDECL(nhl_meta_u_index, (lua_State *)); @@ -657,6 +658,21 @@ lua_State *L; return 1; } +/* level_difficulty() */ +static int +nhl_level_difficulty(L) +lua_State *L; +{ + int argc = lua_gettop(L); + if (argc == 0) { + lua_pushinteger(L, level_difficulty()); + } + else { + nhl_error(L, "level_difficulty should not have any args"); + } + return 1; +} + /* get mandatory integer value from table */ int get_table_int(L, name) @@ -831,6 +847,7 @@ static const struct luaL_Reg nhl_functions[] = { {"an", nhl_an}, {"rn2", nhl_rn2}, {"random", nhl_random}, + {"level_difficulty", nhl_level_difficulty}, {NULL, NULL} };