Allow defining random-teleport exclusion zones in lua

Adds a new lua command

  des.exclusion({ type = "teleport", region = { x1,y1, x2,y2 } });

which allows defining "exclusion zones" in the level, areas where
random teleports (or falling into the level) will never place the hero.
Does not prevent targeted teleportation into the area.

Breaks saves and bones.
This commit is contained in:
Pasi Kallinen
2023-08-24 17:42:06 +03:00
parent 0794a64b9d
commit e407af4477
15 changed files with 143 additions and 3 deletions

View File

@@ -159,6 +159,7 @@ xxxxxx.xxxxxx
]], contents = function()
des.non_diggable(selection.area(2,2, 10,8));
des.region(selection.area(4,4, 8,6), "lit");
des.exclusion({ type = "teleport", region = { 2,2, 10,8 } });
if (coldhell) then
des.replace_terrain({ region = {1,1, 11,9}, fromterrain="L", toterrain="P" });
end
@@ -228,6 +229,7 @@ BBBBBBB]], contents = function()
..........
..........
..........]], contents = function()
des.exclusion({ type = "teleport", region = { 4,4, 5,5 } });
local mons = { "Angel", "D", "H", "L" };
des.monster(mons[math.random(1, #mons)], 4,4);
end });
@@ -245,6 +247,7 @@ BBBBBBB]], contents = function()
.}}}}}}}.
.........
]], contents = function(rm)
des.exclusion({ type = "teleport", region = { 3,3, 5,5 } });
des.monster("L",04,04)
end })
end,

View File

@@ -662,6 +662,7 @@ xx|.....|xx
shuffle(nasty_undead);
des.monster(nasty_undead[1], 2, 2);
des.exclusion({ type = "teleport", region = { 2,2, 3,3 } });
end });
end,

View File

@@ -1228,6 +1228,7 @@ when a werecreature in human form attacked hero, it could transform to critter
status highlighting for hit points didn't work as intended for up or down HP
changes; 'up' rule was used for both, 'down' rule was ignored
unhide an unseen water monster using a polymorph trap on land
allow defining random-teleport exclusion zones in lua
Fixes to 3.7.0-x General Problems Exposed Via git Repository

View File

@@ -528,6 +528,18 @@ Example:
des.engraving({x,y}, "engrave", "Foo");
=== exclusion
Exclude an area of the map from being randomly chosen target when
falling or teleporting into the level. Multiple exclusions per level are allowed.
* type is one of "teleport", "teleport-up", or "teleport-down".
Example:
des.exclusion({ type = "teleport", region = { 0,0, 10,5 } });
=== feature
Create a feature, and set flags for it.

View File

@@ -340,6 +340,7 @@ struct instance_globals_e {
struct bubble *ebubbles;
/* new stuff */
struct exclusion_zone *exclusion_zones;
int early_raw_messages; /* if raw_prints occurred early prior
to gb.beyond_savefile_load */

View File

@@ -58,6 +58,14 @@ typedef struct dest_area { /* non-stairway level change identifier */
coordxy nhx, nhy; /* opposite corner of invalid area */
} dest_area;
/* teleportation exclusion zones in the level */
typedef struct exclusion_zone {
xint16 zonetype; /* level_region_types */
coordxy lx, ly;
coordxy hx, hy;
struct exclusion_zone *next;
} exclusion_zone;
typedef struct dungeon { /* basic dungeon identifier */
char dname[24]; /* name of the dungeon (eg. "Hell") */
char proto[15]; /* name of prototype file (eg. "tower") */

View File

@@ -745,6 +745,9 @@ extern char *stairs_description(stairway *, char *, boolean);
extern schar print_dungeon(boolean, schar *, xint16 *);
extern char *get_annotation(d_level *);
extern int donamelevel(void);
extern void free_exclusions(void);
extern void save_exclusions(NHFILE *);
extern void load_exclusions(NHFILE *);
extern int dooverview(void);
extern void show_overview(int, int);
extern void rm_mapseen(int);

View File

@@ -17,7 +17,7 @@
* Incrementing EDITLEVEL can be used to force invalidation of old bones
* and save files.
*/
#define EDITLEVEL 88
#define EDITLEVEL 89
/*
* Development status possibilities.

View File

@@ -342,6 +342,7 @@ const struct instance_globals_e g_init_e = {
/* mkmaze.c */
UNDEFINED_PTR, /* ebubbles */
/* new */
NULL, /* exclusion_zones */
0, /* early_raw_messages */
TRUE, /* havestate*/
IVMAGIC /* e_magic to validate that structure layout has been preserved */

View File

@@ -2675,6 +2675,66 @@ donamelevel(void)
return ECMD_OK;
}
/* exclusion zones */
void
free_exclusions(void)
{
struct exclusion_zone *ez = ge.exclusion_zones;
while (ez) {
struct exclusion_zone *nxtez = ez->next;
free(ez);
ez = nxtez;
}
ge.exclusion_zones = (struct exclusion_zone *) 0;
}
void
save_exclusions(NHFILE *nhfp)
{
struct exclusion_zone *ez;
int nez;
for (nez = 0, ez = ge.exclusion_zones; ez; ez = ez->next, ++nez) ;
if (nhfp->structlevel)
bwrite(nhfp->fd, (genericptr_t) &nez, sizeof nez);
for (ez = ge.exclusion_zones; ez; ez = ez->next) {
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &ez->zonetype, sizeof ez->zonetype);
bwrite(nhfp->fd, (genericptr_t) &ez->lx, sizeof ez->lx);
bwrite(nhfp->fd, (genericptr_t) &ez->ly, sizeof ez->ly);
bwrite(nhfp->fd, (genericptr_t) &ez->hx, sizeof ez->hx);
bwrite(nhfp->fd, (genericptr_t) &ez->hy, sizeof ez->hy);
}
}
}
void
load_exclusions(NHFILE *nhfp)
{
struct exclusion_zone *ez;
int nez = 0;
if (nhfp->structlevel)
mread(nhfp->fd, (genericptr_t) &nez, sizeof nez);
while (nez-- > 0) {
ez = (struct exclusion_zone *) alloc(sizeof *ez);
if (nhfp->structlevel) {
mread(nhfp->fd, (genericptr_t) &ez->zonetype, sizeof ez->zonetype);
mread(nhfp->fd, (genericptr_t) &ez->lx, sizeof ez->lx);
mread(nhfp->fd, (genericptr_t) &ez->ly, sizeof ez->ly);
mread(nhfp->fd, (genericptr_t) &ez->hx, sizeof ez->hx);
mread(nhfp->fd, (genericptr_t) &ez->hy, sizeof ez->hy);
}
ez->next = ge.exclusion_zones;
ge.exclusion_zones = ez;
}
}
/* find the particular mapseen object in the chain; may return null */
static mapseen *
find_mapseen(d_level *lev)

View File

@@ -822,6 +822,7 @@ clear_level_structures(void)
stairway_free_all();
gm.made_branch = FALSE;
clear_regions();
free_exclusions();
reset_xystart_size();
if (gl.lev_message) {
free(gl.lev_message);

View File

@@ -297,6 +297,22 @@ maze0xy(coord *cc)
return;
}
static boolean
is_exclusion_zone(xint16 type, coordxy x, coordxy y)
{
struct exclusion_zone *ez = ge.exclusion_zones;
while (ez) {
if (((type == LR_DOWNTELE && (ez->zonetype == LR_DOWNTELE || ez->zonetype == LR_TELE))
|| (type == LR_UPTELE && (ez->zonetype == LR_UPTELE || ez->zonetype == LR_TELE))
|| type == ez->zonetype)
&& within_bounded_area(x, y, ez->lx, ez->ly, ez->hx, ez->hy))
return TRUE;
ez = ez->next;
}
return FALSE;
}
/*
* Bad if:
* pos is occupied OR
@@ -375,7 +391,7 @@ put_lregion_here(
{
struct monst *mtmp;
if (bad_location(x, y, nlx, nly, nhx, nhy)) {
if (bad_location(x, y, nlx, nly, nhx, nhy) || is_exclusion_zone(rtype, x, y)) {
if (!oneshot) {
return FALSE; /* caller should try again */
} else {
@@ -389,7 +405,7 @@ put_lregion_here(
mtmp->mtrapped = 0;
deltrap(t);
}
if (bad_location(x, y, nlx, nly, nhx, nhy))
if (bad_location(x, y, nlx, nly, nhx, nhy) || is_exclusion_zone(rtype, x, y))
return FALSE;
}
}

View File

@@ -1141,6 +1141,7 @@ getlev(NHFILE *nhfp, int pid, xint8 lev)
restdamage(nhfp);
rest_regions(nhfp);
rest_bubbles(nhfp); /* for water and air; empty marker on other levels */
load_exclusions(nhfp);
if (ghostly) {
stairway *stway = gs.stairs;

View File

@@ -553,6 +553,7 @@ savelev_core(NHFILE *nhfp, xint8 lev)
savedamage(nhfp); /* pending shop wall and/or floor repair */
save_regions(nhfp);
save_bubbles(nhfp, lev); /* for water and air */
save_exclusions(nhfp);
if (nhfp->mode != FREEING) {
if (nhfp->structlevel)

View File

@@ -141,6 +141,7 @@ int lspo_ladder(lua_State *);
int lspo_level_flags(lua_State *);
int lspo_level_init(lua_State *);
int lspo_levregion(lua_State *);
int lspo_exclusion(lua_State *);
int lspo_map(lua_State *);
int lspo_mazewalk(lua_State *);
int lspo_message(lua_State *);
@@ -6073,6 +6074,35 @@ lspo_levregion(lua_State *L)
return 0;
}
/* exclusion({ type = "teleport", region = { x1,y1, x2,y2 } }); */
int
lspo_exclusion(lua_State *L)
{
static const char *const ez_types[] = {
"teleport", "teleport-up", "teleport-down", NULL
};
static const int ez_types2i[] = {
LR_TELE, LR_UPTELE, LR_DOWNTELE, 0
};
struct exclusion_zone *ez = (struct exclusion_zone *) alloc(sizeof *ez);
lua_Integer x1,y1,x2,y2;
create_des_coder();
lcheck_param_table(L);
ez->zonetype = ez_types2i[get_table_option(L, "type", "teleport",
ez_types)];
get_table_region(L, "region", &x1, &y1, &x2, &y2, FALSE);
ez->lx = x1;
ez->ly = y1;
ez->hx = x2;
ez->hy = y2;
cvt_to_abscoord(&ez->lx, &ez->ly);
cvt_to_abscoord(&ez->hx, &ez->hy);
ez->next = ge.exclusion_zones;
ge.exclusion_zones = ez;
return 0;
}
static void
sel_set_lit(coordxy x, coordxy y, genericptr_t arg)
{
@@ -6960,6 +6990,7 @@ static const struct luaL_Reg nhl_functions[] = {
{ "drawbridge", lspo_drawbridge },
{ "region", lspo_region },
{ "levregion", lspo_levregion },
{ "exclusion", lspo_exclusion },
{ "wallify", lspo_wallify },
{ "wall_property", lspo_wall_property },
{ "non_diggable", lspo_non_diggable },