From 2212cf27eccfa018f2013c859926eceb312576b7 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 19 Jan 2024 17:54:19 +0200 Subject: [PATCH] Lua: Allow creating gas clouds Use the gas clouds in the Clouds themeroom. Use the existing visible_region_at() in the vision code. --- dat/themerms.lua | 2 +- doc/lua.adoc | 15 +++++++++++++++ include/extern.h | 1 + src/region.c | 38 ++++++++++++++++++++++++++++++++++++++ src/sp_lev.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/vision.c | 11 ++--------- 6 files changed, 102 insertions(+), 10 deletions(-) diff --git a/dat/themerms.lua b/dat/themerms.lua index ad42fbc01..9f898a195 100644 --- a/dat/themerms.lua +++ b/dat/themerms.lua @@ -43,10 +43,10 @@ themeroom_fills = { -- Cloud room function(rm) local fog = selection.room(); - des.terrain(fog, "C"); for i = 1, (fog:numpoints() / 4) do des.monster({ id = "fog cloud", asleep = true }); end + des.gas_cloud({ selection = fog }); end, -- Boulder room diff --git a/doc/lua.adoc b/doc/lua.adoc index b5766fecf..f5744eaac 100644 --- a/doc/lua.adoc +++ b/doc/lua.adoc @@ -569,6 +569,21 @@ Example: des.finalize_level(); +=== gas_cloud + +Create a gas cloud. +The `damage` and `ttl` fields are optional. +Defaults to non-poisonous and infinite lifetime. + +Example: + + des.gas_cloud({ x = XX, y = YY }); + des.gas_cloud({ coord = { XX, YY } }); + des.gas_cloud({ selection = SEL }); + des.gas_cloud({ selection = SEL, damage = 5 }); + des.gas_cloud({ selection = SEL, damage = 5, ttl = 200 }); + + === gold Create a pile of gold. diff --git a/include/extern.h b/include/extern.h index 756a3145a..3b5fe525c 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2560,6 +2560,7 @@ extern void save_regions(NHFILE *) NONNULLARG1; extern void rest_regions(NHFILE *) NONNULLARG1; extern void region_stats(const char *, char *, long *, long *) NONNULLPTRS; extern NhRegion *create_gas_cloud(coordxy, coordxy, int, int); +extern NhRegion *create_gas_cloud_selection(struct selectionvar *, int); extern boolean region_danger(void); extern void region_safety(void); diff --git a/src/region.c b/src/region.c index 2897591ba..3a32f015d 100644 --- a/src/region.c +++ b/src/region.c @@ -1189,6 +1189,44 @@ create_gas_cloud(coordxy x, coordxy y, int cloudsize, int damage) return cloud; } +/* create a single gas cloud from selection */ +NhRegion * +create_gas_cloud_selection(struct selectionvar *sel, int damage) +{ + NhRegion *cloud; + NhRect tmprect; + coordxy x, y; + NhRect r; + boolean inside_cloud = is_hero_inside_gas_cloud(); + + selection_getbounds(sel, &r); + + cloud = create_region((NhRect *) 0, 0); + for (x = r.lx; x <= r.hx; x++) + for (y = r.ly; y <= r.hy; y++) + if (selection_getpoint(x, y, sel)) { + tmprect.lx = tmprect.hx = x; + tmprect.ly = tmprect.hy = y; + add_rect_to_reg(cloud, &tmprect); + } + + if (!gi.in_mklev && !gc.context.mon_moving) + set_heros_fault(cloud); /* assume player has created it */ + cloud->inside_f = INSIDE_GAS_CLOUD; + cloud->expire_f = EXPIRE_GAS_CLOUD; + cloud->arg = cg.zeroany; + cloud->arg.a_int = damage; + cloud->visible = TRUE; + cloud->glyph = cmap_to_glyph(damage ? S_poisoncloud : S_cloud); + add_region(cloud); + + if (!gi.in_mklev && !inside_cloud && is_hero_inside_gas_cloud()) + You("are enveloped in a cloud of %s!", + damage ? "noxious gas" : "steam"); + return cloud; +} + + /* for checking troubles during prayer; is hero at risk? */ boolean region_danger(void) diff --git a/src/sp_lev.c b/src/sp_lev.c index 7bbf92a5a..ea8e2c130 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -159,6 +159,7 @@ int lspo_finalize_level(lua_State *); int lspo_room(lua_State *); int lspo_stair(lua_State *); int lspo_teleport_region(lua_State *); +int lspo_gas_cloud(lua_State *); int lspo_terrain(lua_State *); int lspo_trap(lua_State *); int lspo_wall_property(lua_State *); @@ -5545,6 +5546,49 @@ lspo_feature(lua_State *L) return 0; } +/* gas_cloud({ selection=SELECTION }); */ +/* gas_cloud({ selection=SELECTION, damage=N }); */ +/* gas_cloud({ selection=SELECTION, damage=N, ttl=N }); */ +int +lspo_gas_cloud(lua_State *L) +{ + coordxy x = 0, y = 0; + struct selectionvar *sel = NULL; + int argc = lua_gettop(L); + int damage = 0; + int ttl = -2; + + create_des_coder(); + + if (argc == 1 && lua_type(L, 1) == LUA_TTABLE) { + lua_Integer tx, ty; + NhRegion *reg; + + lcheck_param_table(L); + + get_table_xy_or_coord(L, &tx, &ty); + x = tx, y = ty; + if (tx == -1 && ty == -1) { + lua_getfield(L, 1, "selection"); + sel = l_selection_check(L, -1); + lua_pop(L, 1); + } + damage = get_table_int_opt(L, "damage", 0); + ttl = get_table_int_opt(L, "ttl", -2); + if (!sel) { + reg = create_gas_cloud(x, y, 1, damage); + } else + reg = create_gas_cloud_selection(sel, damage); + if (ttl > -2) + reg->ttl = ttl; + } else { + nhl_error(L, "wrong parameters"); + } + + return 0; +} + + /* * [lit_state: 1 On, 0 Off, -1 random, -2 leave as-is] * terrain({ x=NN, y=NN, typ=MAPCHAR, lit=lit_state }); @@ -6995,6 +7039,7 @@ static const struct luaL_Reg nhl_functions[] = { { "teleport_region", lspo_teleport_region }, { "reset_level", lspo_reset_level }, { "finalize_level", lspo_finalize_level }, + { "gas_cloud", lspo_gas_cloud }, /* TODO: { "branch", lspo_branch }, */ /* TODO: { "portal", lspo_portal }, */ { NULL, NULL } diff --git a/src/vision.c b/src/vision.c index 69d540032..004a9d5eb 100644 --- a/src/vision.c +++ b/src/vision.c @@ -141,7 +141,6 @@ does_block(int x, int y, struct rm *lev) { struct obj *obj; struct monst *mon; - int i; #ifdef DEBUG /* set DEBUGFILES=seethru in environment to see through bubbles */ @@ -181,14 +180,8 @@ does_block(int x, int y, struct rm *lev) if (gs.seethru != 1) { #endif /* Clouds (poisonous or not) block light. */ - for (i = 0; i < gn.n_regions; i++) { - /* Ignore regions with ttl == 0 - expire_gas_cloud must unblock its - * points prior to being removed itself. */ - if (gr.regions[i]->ttl > 0 && gr.regions[i]->visible - && inside_region(gr.regions[i], x, y)) { - return 1; - } - } + if (visible_region_at(x, y)) + return 1; #ifdef DEBUG } /* gs.seethru */ #endif