From bb3dc379bc27eaf9042f869fbbee829eeeab2e23 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 18 Sep 2022 12:35:30 +0300 Subject: [PATCH] Themerooms: Engraving hints the location of buried treasure Add two new themeroom functions that are called when generating the level: pre_themerooms_generate and post_themerooms_generate, calles before and after themerooms_generate. Allow the buried treasure -themeroom to put down an engraving anywhere on the level, hinting at the location of the treasure. des.object contents function now gets the generated object passed to it as a parameter. --- dat/nhlib.lua | 5 +++++ dat/themerms.lua | 48 +++++++++++++++++++++++++++++++++++++++++++++--- doc/lua.adoc | 6 ++++-- src/mklev.c | 16 ++++++++++++++++ src/sp_lev.c | 19 ++++++++++++------- 5 files changed, 82 insertions(+), 12 deletions(-) diff --git a/dat/nhlib.lua b/dat/nhlib.lua index a3f9662a75..8bdd87ffc9 100644 --- a/dat/nhlib.lua +++ b/dat/nhlib.lua @@ -50,3 +50,8 @@ function monkfoodshop() end return "food shop"; end + +-- pline with variable number of arguments +function pline(fmt, ...) + nh.pline(string.format(fmt, table.unpack({...}))); +end diff --git a/dat/themerms.lua b/dat/themerms.lua index 1c97015f22..9a7983a517 100644 --- a/dat/themerms.lua +++ b/dat/themerms.lua @@ -14,8 +14,15 @@ -- 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. --- core calls themerooms_generate() multiple times per level --- to generate a single themed room. +-- +-- 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 = { @@ -74,7 +81,12 @@ themeroom_fills = { -- Buried treasure function(rm) - des.object({ id = "chest", buried = true, contents = function() + 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 @@ -649,6 +661,7 @@ function is_eligible(room, mkrm) return true end +-- called repeatedly until the core decides there are enough rooms function themerooms_generate() local pick = 1; local total_frequency = 0; @@ -678,6 +691,34 @@ function themerooms_generate() 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; @@ -706,3 +747,4 @@ function themeroom_fill(rm) themeroom_fills[pick](rm); end end + diff --git a/doc/lua.adoc b/doc/lua.adoc index 8b614bb4df..e7d30618e3 100644 --- a/doc/lua.adoc +++ b/doc/lua.adoc @@ -651,6 +651,7 @@ Example: des.non_passwall(selection); des.non_passwall(); + === object Create an object. The table parameter accepts the following: @@ -682,7 +683,7 @@ Create an object. The table parameter accepts the following: | male | boolean | Is statue male? | female | boolean | Is statue female? | laid_by_you | boolean | Is an egg laid by you? -| contents | function | Container contents +| contents | function | Container contents. The container object is given as a parameter. See <> class. |=== Example: @@ -694,7 +695,8 @@ Example: des.object("scimitar", {6, 7}); des.object({ class = "%" }); des.object({ id = "boulder", x = 03, y = 12}); - des.object({ id = "chest", coord = {03, 12}, locked = true, contents = function() des.object("rock"); end }); + des.object({ id = "chest", coord = {03, 12}, locked = true, contents = function(obj) des.object("rock"); end }); + === random_corridors diff --git a/src/mklev.c b/src/mklev.c index 3a9d4d617f..a011e0da30 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -289,6 +289,13 @@ makerooms(void) if (themes) { create_des_coder(); + iflags.in_lua = g.in_mk_themerooms = TRUE; + g.themeroom_failed = FALSE; + lua_getglobal(themes, "pre_themerooms_generate"); + if ( nhl_pcall(themes, 0, 0)){ + impossible("Lua error: %s", lua_tostring(themes, -1)); + } + iflags.in_lua = g.in_mk_themerooms = FALSE; } /* make rooms until satisfied */ @@ -321,6 +328,15 @@ makerooms(void) } } if (themes) { + reset_xystart_size(); + iflags.in_lua = g.in_mk_themerooms = TRUE; + g.themeroom_failed = FALSE; + lua_getglobal(themes, "post_themerooms_generate"); + if ( nhl_pcall(themes, 0, 0)){ + impossible("Lua error: %s", lua_tostring(themes, -1)); + } + iflags.in_lua = g.in_mk_themerooms = FALSE; + wallification(1, 0, COLNO - 1, ROWNO - 1); free(g.coder); g.coder = NULL; diff --git a/src/sp_lev.c b/src/sp_lev.c index b40dfdf698..81d7c136f8 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -55,7 +55,7 @@ static boolean m_bad_boulder_spot(coordxy, coordxy); static int pm_to_humidity(struct permonst *); static unsigned int sp_amask_to_amask(unsigned int sp_amask); static void create_monster(monster *, struct mkroom *); -static void create_object(object *, struct mkroom *); +static struct obj *create_object(object *, struct mkroom *); static void create_altar(altar *, struct mkroom *); static boolean search_door(struct mkroom *, coordxy *, coordxy *, xint16, int); static void create_corridor(corridor *); @@ -2125,7 +2125,7 @@ create_monster(monster* m, struct mkroom* croom) /* * Create an object in a room. */ -static void +static struct obj * create_object(object* o, struct mkroom* croom) { struct obj *otmp; @@ -2267,7 +2267,7 @@ create_object(object* o, struct mkroom* croom) artifact_exists(otmp, safe_oname(otmp), FALSE, ONAME_NO_FLAGS); /* flags don't matter */ obfree(otmp, NULL); - return; + return NULL; } } } @@ -2359,11 +2359,14 @@ create_object(object* o, struct mkroom* croom) boolean dealloced; (void) bury_an_obj(otmp, &dealloced); - if (dealloced && container_idx) { - container_obj[container_idx - 1] = NULL; + if (dealloced) { + if (container_idx) + container_obj[container_idx - 1] = NULL; + otmp = NULL; } } } + return otmp; } /* @@ -3461,6 +3464,7 @@ lspo_object(lua_State *L) lua_Integer ox = -1, oy = -1; int argc = lua_gettop(L); int maybe_contents = 0; + struct obj *otmp = NULL; create_des_coder(); @@ -3601,14 +3605,15 @@ lspo_object(lua_State *L) } do { - create_object(&tmpobj, g.coder->croom); + otmp = create_object(&tmpobj, g.coder->croom); quancnt--; } while ((quancnt > 0) && ((tmpobj.id > STRANGE_OBJECT) && !objects[tmpobj.id].oc_merge)); if (lua_type(L, -1) == LUA_TFUNCTION) { lua_remove(L, -2); - if (nhl_pcall(L, 0, 0)){ + nhl_push_obj(L, otmp); + if (nhl_pcall(L, 1, 0)){ impossible("Lua error: %s", lua_tostring(L, -1)); } } else