Add lua selection match method
Also improve the replace_terrain command parameters.
This commit is contained in:
@@ -2468,6 +2468,12 @@ E void FDECL(sysopt_seduce_set, (int));
|
||||
|
||||
/* ### sp_lev.c ### */
|
||||
#if !defined(CROSSCOMPILE) || defined(CROSSCOMPILE_TARGET)
|
||||
E struct mapfragment *FDECL(mapfrag_fromstr, (char *));
|
||||
E void FDECL(mapfrag_free, (struct mapfragment **));
|
||||
E schar FDECL(mapfrag_get, (struct mapfragment *, int, int));
|
||||
E boolean FDECL(mapfrag_canmatch, (struct mapfragment *));
|
||||
E const char * FDECL(mapfrag_error, (struct mapfragment *));
|
||||
E boolean FDECL(mapfrag_match, (struct mapfragment *, int, int));
|
||||
E void FDECL(flip_level, (int, BOOLEAN_P));
|
||||
E void FDECL(flip_level_rnd, (int, BOOLEAN_P));
|
||||
E boolean FDECL(check_room, (xchar *, xchar *, xchar *, xchar *, BOOLEAN_P));
|
||||
|
||||
@@ -164,12 +164,6 @@ typedef struct {
|
||||
xchar ter, tlit;
|
||||
} terrain;
|
||||
|
||||
typedef struct {
|
||||
xchar chance;
|
||||
xchar x1, y1, x2, y2;
|
||||
xchar fromter, toter, tolit;
|
||||
} replaceterrain;
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
xchar room;
|
||||
@@ -186,12 +180,9 @@ typedef struct _room {
|
||||
xchar rtype, chance, rlit, filled, joined;
|
||||
} room;
|
||||
|
||||
typedef struct {
|
||||
schar zaligntyp;
|
||||
schar keep_region;
|
||||
schar halign, valign;
|
||||
char xsize, ysize;
|
||||
char **map;
|
||||
} mazepart;
|
||||
struct mapfragment {
|
||||
int wid, hei;
|
||||
char *data;
|
||||
};
|
||||
|
||||
#endif /* SP_LEV_H */
|
||||
|
||||
43
src/nhlsel.c
43
src/nhlsel.c
@@ -19,9 +19,9 @@ static int FDECL(l_selection_line, (lua_State *));
|
||||
static int FDECL(l_selection_randline, (lua_State *));
|
||||
static int FDECL(l_selection_rect, (lua_State *));
|
||||
static int FDECL(l_selection_fillrect, (lua_State *));
|
||||
static int FDECL(l_selection_fillrect, (lua_State *));
|
||||
static int FDECL(l_selection_grow, (lua_State *));
|
||||
static int FDECL(l_selection_filter_mapchar, (lua_State *));
|
||||
static int FDECL(l_selection_match, (lua_State *));
|
||||
static int FDECL(l_selection_flood, (lua_State *));
|
||||
static int FDECL(l_selection_circle, (lua_State *));
|
||||
static int FDECL(l_selection_ellipse, (lua_State *));
|
||||
@@ -568,6 +568,46 @@ lua_State *L;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* local s = selection.match([[...]]); */
|
||||
static int
|
||||
l_selection_match(L)
|
||||
lua_State *L;
|
||||
{
|
||||
int argc = lua_gettop(L);
|
||||
struct selectionvar *sel = (struct selectionvar *) 0;
|
||||
struct mapfragment *mf;
|
||||
int x, y;
|
||||
|
||||
if (argc == 1) {
|
||||
const char *err;
|
||||
char *mapstr = dupstr(luaL_checkstring(L, 1));
|
||||
lua_pop(L, 1);
|
||||
(void) l_selection_new(L);
|
||||
sel = l_selection_check(L, 1);
|
||||
|
||||
mf = mapfrag_fromstr(mapstr);
|
||||
free(mapstr);
|
||||
|
||||
if ((err = mapfrag_error(mf)) != NULL) {
|
||||
mapfrag_free(&mf);
|
||||
nhl_error(L, err);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
} else {
|
||||
nhl_error(L, "wrong parameters");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
for (y = 0; y <= sel->hei; y++)
|
||||
for (x = 0; x < sel->wid; x++)
|
||||
selection_setpoint(x, y, sel, mapfrag_match(mf, x,y) ? 1 : 0);
|
||||
|
||||
mapfrag_free(&mf);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* local s = selection.floodfill(x,y); */
|
||||
static int
|
||||
@@ -744,6 +784,7 @@ static const struct luaL_Reg l_selection_methods[] = {
|
||||
{ "area", l_selection_fillrect },
|
||||
{ "grow", l_selection_grow },
|
||||
{ "filter_mapchar", l_selection_filter_mapchar },
|
||||
{ "match", l_selection_match },
|
||||
{ "floodfill", l_selection_flood },
|
||||
{ "circle", l_selection_circle },
|
||||
{ "ellipse", l_selection_ellipse },
|
||||
|
||||
260
src/sp_lev.c
260
src/sp_lev.c
@@ -57,7 +57,6 @@ static int FDECL(pm_to_humidity, (struct permonst *));
|
||||
static void FDECL(create_monster, (monster *, struct mkroom *));
|
||||
static void FDECL(create_object, (object *, struct mkroom *));
|
||||
static void FDECL(create_altar, (altar *, struct mkroom *));
|
||||
static void FDECL(replace_terrain, (replaceterrain *, struct mkroom *));
|
||||
static boolean FDECL(search_door, (struct mkroom *,
|
||||
xchar *, xchar *, XCHAR_P, int));
|
||||
static void NDECL(fix_stair_rooms);
|
||||
@@ -173,6 +172,97 @@ static struct monst *invent_carrying_monster = (struct monst *) 0;
|
||||
* end of no 'g.'
|
||||
*/
|
||||
|
||||
struct mapfragment *
|
||||
mapfrag_fromstr(str)
|
||||
char *str;
|
||||
{
|
||||
struct mapfragment *mf = (struct mapfragment *) alloc(sizeof(struct mapfragment));
|
||||
|
||||
char *tmps;
|
||||
|
||||
mf->data = dupstr(str);
|
||||
|
||||
(void) stripdigits(mf->data);
|
||||
mf->wid = str_lines_maxlen(mf->data);
|
||||
mf->hei = 0;
|
||||
tmps = mf->data;
|
||||
while (tmps && *tmps) {
|
||||
char *s1 = index(tmps, '\n');
|
||||
|
||||
if (mf->hei > MAP_Y_LIM) {
|
||||
free(mf->data);
|
||||
free(mf);
|
||||
return NULL;
|
||||
}
|
||||
if (s1)
|
||||
s1++;
|
||||
tmps = s1;
|
||||
mf->hei++;
|
||||
}
|
||||
return mf;
|
||||
}
|
||||
|
||||
void
|
||||
mapfrag_free(mf)
|
||||
struct mapfragment **mf;
|
||||
{
|
||||
if (mf && *mf) {
|
||||
free((*mf)->data);
|
||||
free(*mf);
|
||||
mf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
schar
|
||||
mapfrag_get(mf, x,y)
|
||||
struct mapfragment *mf;
|
||||
int x,y;
|
||||
{
|
||||
if (y < 0 || x < 0 || y > mf->hei-1 || x > mf->wid-1)
|
||||
panic("outside mapfrag (%i,%i), wanted (%i,%i)", mf->wid, mf->hei, x,y);
|
||||
return splev_chr2typ(mf->data[y * (mf->wid + 1) + x]);
|
||||
}
|
||||
|
||||
boolean
|
||||
mapfrag_canmatch(mf)
|
||||
struct mapfragment *mf;
|
||||
{
|
||||
return ((mf->wid % 2) && (mf->hei % 2));
|
||||
}
|
||||
|
||||
const char *
|
||||
mapfrag_error(mf)
|
||||
struct mapfragment *mf;
|
||||
{
|
||||
if (!mf)
|
||||
return "mapfragment error";
|
||||
else if (!mapfrag_canmatch(mf)) {
|
||||
mapfrag_free(&mf);
|
||||
return "mapfragment needs to have odd height and width";
|
||||
} else if (mapfrag_get(mf, (mf->wid/2), (mf->hei/2)) >= MAX_TYPE) {
|
||||
mapfrag_free(&mf);
|
||||
return "mapfragment center must be valid terrain";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
boolean
|
||||
mapfrag_match(mf, x,y)
|
||||
struct mapfragment *mf;
|
||||
int x,y;
|
||||
{
|
||||
int rx, ry;
|
||||
|
||||
for (rx = -(mf->wid / 2); rx <= (mf->wid / 2); rx++)
|
||||
for (ry = -(mf->hei / 2); ry <= (mf->hei / 2); ry++) {
|
||||
schar mapc = mapfrag_get(mf, rx + (mf->wid / 2) , ry + (mf->hei / 2));
|
||||
schar levc = isok(x+rx, y+ry) ? levl[x+rx][y+ry].typ : STONE;
|
||||
if ((mapc < MAX_TYPE) && (mapc != levc))
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
solidify_map()
|
||||
{
|
||||
@@ -2127,31 +2217,6 @@ struct mkroom *croom;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
replace_terrain(terr, croom)
|
||||
replaceterrain *terr;
|
||||
struct mkroom *croom;
|
||||
{
|
||||
schar x, y, x1, y1, x2, y2;
|
||||
|
||||
if (terr->toter >= MAX_TYPE)
|
||||
return;
|
||||
|
||||
x1 = terr->x1;
|
||||
y1 = terr->y1;
|
||||
get_location(&x1, &y1, ANY_LOC, croom);
|
||||
|
||||
x2 = terr->x2;
|
||||
y2 = terr->y2;
|
||||
get_location(&x2, &y2, ANY_LOC, croom);
|
||||
|
||||
for (x = max(x1, 0); x <= min(x2, COLNO - 1); x++)
|
||||
for (y = max(y1, 0); y <= min(y2, ROWNO - 1); y++)
|
||||
if (levl[x][y].typ == terr->fromter && rn2(100) < terr->chance) {
|
||||
SET_TYPLIT(x, y, terr->toter, terr->tolit);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for a door in a room on a specified wall.
|
||||
*/
|
||||
@@ -4922,17 +4987,22 @@ lua_State *L;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: better parameters, allow selection instead of x1,y1,x2,y2 nonsense.
|
||||
TODO: or remove, if terrain + selection can do this better?
|
||||
*/
|
||||
/* replace_terrain({ x1=NN,y1=NN, x2=NN,y2=NN, fromterrain=MAPCHAR, toterrain=MAPCHAR, lit=N, chance=NN }); */
|
||||
/* replace_terrain({ region={x1,y1, x2,y2}, fromterrain=MAPCHAR, toterrain=MAPCHAR, lit=N, chance=NN }); */
|
||||
/* replace_terrain({ selection=selection.area(2,5, 40,10), fromterrain=MAPCHAR, toterrain=MAPCHAR }); */
|
||||
/* replace_terrain({ selection=SEL, mapfragment=[[...]], toterrain=MAPCHAR }); */
|
||||
int
|
||||
lspo_replace_terrain(L)
|
||||
lua_State *L;
|
||||
{
|
||||
replaceterrain rt;
|
||||
xchar totyp, fromtyp;
|
||||
struct mapfragment *mf = NULL;
|
||||
struct selectionvar *sel = NULL;
|
||||
boolean freesel = FALSE;
|
||||
int x, y;
|
||||
int x1, y1, x2, y2;
|
||||
int chance;
|
||||
int tolit;
|
||||
|
||||
create_des_coder();
|
||||
|
||||
@@ -4940,25 +5010,75 @@ lua_State *L;
|
||||
|
||||
totyp = get_table_mapchr(L, "toterrain");
|
||||
|
||||
fromtyp = get_table_mapchr(L, "fromterrain");
|
||||
if (totyp >= MAX_TYPE)
|
||||
return 0;
|
||||
|
||||
rt.chance = get_table_int_opt(L, "chance", 100);
|
||||
rt.tolit = get_table_int_opt(L, "lit", 1);
|
||||
rt.toter = totyp;
|
||||
rt.fromter = fromtyp;
|
||||
rt.x1 = get_table_int_opt(L, "x1", -1);
|
||||
rt.y1 = get_table_int_opt(L, "y1", -1);
|
||||
rt.x2 = get_table_int_opt(L, "x2", -1);
|
||||
rt.y2 = get_table_int_opt(L, "y2", -1);
|
||||
fromtyp = get_table_mapchr_opt(L, "fromterrain", INVALID_TYPE);
|
||||
|
||||
if (rt.x1 == -1 && rt.y1 == -1 && rt.x2 == -1 && rt.y2 == -1) {
|
||||
int rx1, ry1, rx2, ry2;
|
||||
get_table_region(L, "region", &rx1, &ry1, &rx2, &ry2, FALSE);
|
||||
rt.x1 = rx1; rt.y1 = ry1;
|
||||
rt.x2 = rx2; rt.y2 = ry2;
|
||||
if (fromtyp == INVALID_TYPE) {
|
||||
const char *err;
|
||||
char *tmpstr = get_table_str(L, "mapfragment");
|
||||
mf = mapfrag_fromstr(tmpstr);
|
||||
free(tmpstr);
|
||||
|
||||
if ((err = mapfrag_error(mf)) != NULL) {
|
||||
mapfrag_free(&mf);
|
||||
nhl_error(L, err);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
}
|
||||
|
||||
replace_terrain(&rt, g.coder->croom);
|
||||
chance = get_table_int_opt(L, "chance", 100);
|
||||
tolit = get_table_int_opt(L, "lit", -2);
|
||||
x1 = get_table_int_opt(L, "x1", -1);
|
||||
y1 = get_table_int_opt(L, "y1", -1);
|
||||
x2 = get_table_int_opt(L, "x2", -1);
|
||||
y2 = get_table_int_opt(L, "y2", -1);
|
||||
|
||||
if (x1 == -1 && y1 == -1 && x2 == -1 && y2 == -1) {
|
||||
get_table_region(L, "region", &x1, &y1, &x2, &y2, TRUE);
|
||||
}
|
||||
|
||||
if (x1 == -1 && y1 == -1 && x2 == -1 && y2 == -1) {
|
||||
lua_getfield(L, 1, "selection");
|
||||
if (lua_type(L, -1) != LUA_TNIL)
|
||||
sel = l_selection_check(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
if (!sel) {
|
||||
sel = selection_new();
|
||||
freesel = TRUE;
|
||||
|
||||
if (x1 == -1 && y1 == -1 && x2 == -1 && y2 == -1) {
|
||||
(void) selection_not(sel);
|
||||
} else {
|
||||
schar rx1, ry1, rx2, ry2;
|
||||
rx1 = x1, ry1 = y1, rx2 = x2, ry2 = x2;
|
||||
get_location(&rx1, &ry1, ANY_LOC, g.coder->croom);
|
||||
get_location(&rx2, &ry2, ANY_LOC, g.coder->croom);
|
||||
for (x = max(rx1, 0); x <= min(rx2, COLNO - 1); x++)
|
||||
for (y = max(ry1, 0); y <= min(ry2, ROWNO - 1); y++)
|
||||
selection_setpoint(x,y, sel, 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (y = 0; y <= sel->hei; y++)
|
||||
for (x = 0; x < sel->wid; x++)
|
||||
if (selection_getpoint(x,y,sel)) {
|
||||
if (mf) {
|
||||
if (mapfrag_match(mf, x,y) && (rn2(100)) < chance)
|
||||
SET_TYPLIT(x, y, totyp, tolit);
|
||||
} else {
|
||||
if (levl[x][y].typ == fromtyp && rn2(100) < chance)
|
||||
SET_TYPLIT(x, y, totyp, tolit);
|
||||
}
|
||||
}
|
||||
|
||||
if (freesel)
|
||||
selection_free(sel, TRUE);
|
||||
|
||||
mapfrag_free(&mf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -5736,7 +5856,6 @@ int
|
||||
lspo_map(L)
|
||||
lua_State *L;
|
||||
{
|
||||
mazepart tmpmazepart;
|
||||
xchar tmpxstart, tmpystart, tmpxsize, tmpysize;
|
||||
|
||||
/*
|
||||
@@ -5756,36 +5875,31 @@ TODO: g.coder->croom needs to be updated
|
||||
};
|
||||
static const int t_or_b2i[] = { TOP, CENTER, BOTTOM, -1, -1 };
|
||||
int lr, tb, keepregion = 1, x = -1, y = -1;
|
||||
char *tmps, *mapdata;
|
||||
int mapwid, maphei = 0;
|
||||
struct mapfragment *mf;
|
||||
int argc = lua_gettop(L);
|
||||
|
||||
create_des_coder();
|
||||
|
||||
if (argc == 1 && lua_type(L, 1) == LUA_TSTRING) {
|
||||
char *tmpstr = dupstr(luaL_checkstring(L, 1));
|
||||
lr = tb = CENTER;
|
||||
mapdata = dupstr(luaL_checkstring(L, 1));
|
||||
mf = mapfrag_fromstr(tmpstr);
|
||||
free(tmpstr);
|
||||
} else {
|
||||
char *tmpstr;
|
||||
lcheck_param_table(L);
|
||||
lr = l_or_r2i[get_table_option(L, "halign", "none", left_or_right)];
|
||||
tb = t_or_b2i[get_table_option(L, "valign", "none", top_or_bot)];
|
||||
keepregion = get_table_boolean_opt(L, "keepregion", 1); /* TODO: maybe rename? */
|
||||
get_table_xy_or_coord(L, &x, &y);
|
||||
mapdata = get_table_str(L, "map");
|
||||
tmpstr = get_table_str(L, "map");
|
||||
mf = mapfrag_fromstr(tmpstr);
|
||||
free(tmpstr);
|
||||
}
|
||||
|
||||
(void) stripdigits(mapdata);
|
||||
mapwid = str_lines_maxlen(mapdata);
|
||||
tmps = mapdata;
|
||||
while (tmps && *tmps) {
|
||||
char *s1 = index(tmps, '\n');
|
||||
|
||||
if (maphei > MAP_Y_LIM)
|
||||
break;
|
||||
if (s1)
|
||||
s1++;
|
||||
tmps = s1;
|
||||
maphei++;
|
||||
if (!mf) {
|
||||
nhl_error(L, "Map data error");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* keepregion restricts the coordinates of the commands coming after
|
||||
@@ -5797,10 +5911,8 @@ TODO: g.coder->croom needs to be updated
|
||||
tmpystart = g.ystart;
|
||||
|
||||
|
||||
g.xsize = tmpmazepart.xsize = mapwid;
|
||||
g.ysize = tmpmazepart.ysize = maphei;
|
||||
tmpmazepart.halign = lr;
|
||||
tmpmazepart.valign = tb;
|
||||
g.xsize = mf->wid;
|
||||
g.ysize = mf->hei;
|
||||
|
||||
if (lr == -1 && tb == -1) {
|
||||
if (isok(x,y)) {
|
||||
@@ -5809,17 +5921,18 @@ TODO: g.coder->croom needs to be updated
|
||||
/* in a room? adjust to room relative coords */
|
||||
g.xstart = x + g.coder->croom->lx;
|
||||
g.ystart = y + g.coder->croom->ly;
|
||||
g.xsize = min(tmpmazepart.xsize,
|
||||
g.xsize = min(mf->wid,
|
||||
(g.coder->croom->hx - g.coder->croom->lx));
|
||||
g.ysize = min(tmpmazepart.ysize,
|
||||
g.ysize = min(mf->hei,
|
||||
(g.coder->croom->hy - g.coder->croom->ly));
|
||||
} else {
|
||||
g.xsize = tmpmazepart.xsize;
|
||||
g.ysize = tmpmazepart.ysize;
|
||||
g.xsize = mf->wid;
|
||||
g.ysize = mf->hei;
|
||||
g.xstart = x;
|
||||
g.ystart = y;
|
||||
}
|
||||
} else {
|
||||
mapfrag_free(&mf);
|
||||
nhl_error(L, "Map requires either x,y or halign,valign params");
|
||||
return 0;
|
||||
}
|
||||
@@ -5873,15 +5986,12 @@ TODO: g.coder->croom needs to be updated
|
||||
g.xsize = COLNO - 1;
|
||||
g.ysize = ROWNO;
|
||||
} else {
|
||||
char mpchr;
|
||||
xchar mptyp;
|
||||
|
||||
/* Load the map */
|
||||
for (y = g.ystart; y < min(ROWNO, g.ystart + g.ysize); y++)
|
||||
for (x = g.xstart; x < min(COLNO, g.xstart + g.xsize); x++) {
|
||||
mpchr = mapdata[(y - g.ystart) * (mapwid + 1)
|
||||
+ (x - g.xstart)];
|
||||
mptyp = splev_chr2typ(mpchr);
|
||||
mptyp = mapfrag_get(mf, (x - g.xstart), (y - g.ystart));
|
||||
if (mptyp == INVALID_TYPE) {
|
||||
/* TODO: warn about illegal map char */
|
||||
continue;
|
||||
@@ -5930,7 +6040,7 @@ TODO: g.coder->croom needs to be updated
|
||||
g.ysize = tmpysize;
|
||||
}
|
||||
|
||||
Free(mapdata);
|
||||
mapfrag_free(&mf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -390,6 +390,8 @@ function test_replace_terrain()
|
||||
des.replace_terrain({ x1=1, y1=1, x2=70,y2=19, fromterrain=".", toterrain="I", lit=1 });
|
||||
des.replace_terrain({ x1=1, y1=1, x2=70,y2=19, fromterrain=".", toterrain="I", chance=50 });
|
||||
des.replace_terrain({ region={1,1, 70,19}, fromterrain=".", toterrain="L", chance=25 });
|
||||
des.replace_terrain({ selection=selection.area(2,5, 10,15), fromterrain="L", toterrain="." });
|
||||
des.replace_terrain({ mapfragment=[[...]], toterrain="T" });
|
||||
end
|
||||
|
||||
function test_corridor()
|
||||
|
||||
@@ -352,9 +352,12 @@ function test_sel_flood()
|
||||
sel_pt_ne(selb, 5,5, 1, __func__);
|
||||
sel_pt_ne(selb, 6,5, 1, __func__);
|
||||
sel_pt_ne(selb, 7,5, 1, __func__);
|
||||
|
||||
end -- test_sel_flood
|
||||
|
||||
function test_sel_match()
|
||||
local sel = selection.match([[...]]);
|
||||
end -- test_sel_match
|
||||
|
||||
test_selection_params();
|
||||
test_sel_negate();
|
||||
test_sel_logical_and();
|
||||
@@ -368,3 +371,4 @@ test_sel_randline();
|
||||
test_sel_grow();
|
||||
test_sel_filter_mapchar();
|
||||
test_sel_flood();
|
||||
test_sel_match();
|
||||
|
||||
Reference in New Issue
Block a user