From a429eed9840ac30796f831ea9af123241e7f41bf Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 20 Apr 2024 19:24:28 +0300 Subject: [PATCH] Add Garden themeroom Contains some wood nymphs and fountains, and the room walls are trees. Adds a new lua hook for themeroom generation, "post_level_generate", which is called last when generating the level. --- dat/themerms.lua | 80 +++++++++++++++++++++++++++++++++--------------- src/mklev.c | 31 ++++++++++++++++--- 2 files changed, 82 insertions(+), 29 deletions(-) diff --git a/dat/themerms.lua b/dat/themerms.lua index c651643b3..c1353df6d 100644 --- a/dat/themerms.lua +++ b/dat/themerms.lua @@ -19,11 +19,13 @@ -- 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. +-- post_themerooms_generate(). When the level has been generated, with +-- joining corridors and rooms filled, the core calls post_level_generate(). +-- The lua state is persistent through the gameplay, but not across saves, +-- so remember to reset any variables. -local buried_treasure = { }; +local postprocess = { }; themeroom_fills = { @@ -89,13 +91,29 @@ themeroom_fills = { locs:iterate(func); end, + -- Garden + { + eligible = function(rm) return rm.lit == true; end, + contents = function(rm) + local s = selection.room(); + local npts = (s:numpoints() / 6); + for i = 1, npts do + des.monster({ id = "wood nymph", asleep = true }); + if (percent(30)) then + des.feature("fountain"); + end + end + table.insert(postprocess, { handler = make_garden_walls, data = { sel = selection.room() } }); + 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 }; + table.insert(postprocess, { handler = make_dig_engraving, data = { x = xobj.ox, y = xobj.oy }}); end for i = 1, d(3,4) do des.object(); @@ -791,30 +809,11 @@ 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 +-- but before creating connecting corridors/doors, or filling rooms 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) @@ -846,3 +845,36 @@ function themeroom_fill(rm) end end +-- postprocess callback: create an engraving pointing at a location +function make_dig_engraving(data) + local floors = selection.negate():filter_mapchar("."); + local pos = floors:rndcoord(0); + local tx = data.x - pos.x - 1; + local ty = data.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 + +-- postprocess callback: turn room walls into trees +function make_garden_walls(data) + local sel = data.sel:grow(); + des.replace_terrain({ selection = sel, fromterrain="w", toterrain = "T" }); +end + +-- called once after the whole level has been generated +function post_level_generate() + for i, v in ipairs(postprocess) do + v.handler(v.data); + end + postprocess = { }; +end diff --git a/src/mklev.c b/src/mklev.c index 888bdb6ac..589d12d60 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -22,6 +22,7 @@ staticfn int mkinvk_check_wall(coordxy x, coordxy y); staticfn void mk_knox_portal(coordxy, coordxy); staticfn void makevtele(void); staticfn void fill_ordinary_room(struct mkroom *, boolean) NONNULLARG1; +staticfn void themerooms_post_level_generate(void); staticfn void makelevel(void); staticfn boolean bydoor(coordxy, coordxy); staticfn void mktrap_victim(struct trap *); @@ -333,11 +334,6 @@ makerooms(void) lua_getglobal(themes, "post_themerooms_generate"); nhl_pcall_handle(themes, 0, 0, "makerooms-3", NHLpa_panic); iflags.in_lua = gi.in_mk_themerooms = FALSE; - - wallification(1, 0, COLNO - 1, ROWNO - 1); - free(gc.coder); - gc.coder = NULL; - lua_gc(themes, LUA_GCCOLLECT); } } @@ -1076,6 +1072,29 @@ fill_ordinary_room( } } +staticfn void +themerooms_post_level_generate(void) +{ + lua_State *themes = (lua_State *) gl.luathemes[u.uz.dnum]; + + /* themes should already be loaded by makerooms(); + * if not, we don't run this either */ + if (!themes) + return; + + reset_xystart_size(); + iflags.in_lua = gi.in_mk_themerooms = TRUE; + gt.themeroom_failed = FALSE; + lua_getglobal(themes, "post_level_generate"); + nhl_pcall_handle(themes, 0, 0, "post_level_generate", NHLpa_panic); + iflags.in_lua = gi.in_mk_themerooms = FALSE; + + wallification(1, 0, COLNO - 1, ROWNO - 1); + free(gc.coder); + gc.coder = NULL; + lua_gc(themes, LUA_GCCOLLECT); +} + staticfn void makelevel(void) { @@ -1241,6 +1260,8 @@ makelevel(void) fill_special_room(&gr.rooms[i]); } + themerooms_post_level_generate(); + if (gl.luacore && nhcb_counts[NHCB_LVL_ENTER]) { lua_getglobal(gl.luacore, "nh_callback_run"); lua_pushstring(gl.luacore, nhcb_name[NHCB_LVL_ENTER]);