diff --git a/include/extern.h b/include/extern.h index 8d4bdb55f..33198552b 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2514,6 +2514,8 @@ E struct selectionvar *FDECL(selection_filter_mapchar, (struct selectionvar *, E void FDECL(set_floodfillchk_match_under, (XCHAR_P)); E void FDECL(selection_do_ellipse, (struct selectionvar *, int, int, int, int, int)); +E void FDECL(selection_do_gradient, (struct selectionvar *, long, long, + long, long, long, long, long, long)); E void NDECL(update_croom); E const char *FDECL(get_trapname_bytype, (int)); E void FDECL(l_register_des, (lua_State *)); diff --git a/src/nhlsel.c b/src/nhlsel.c index 9a10d1098..1da3d5e8e 100644 --- a/src/nhlsel.c +++ b/src/nhlsel.c @@ -25,6 +25,7 @@ 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 *)); +static int FDECL(l_selection_gradient, (lua_State *)); static int FDECL(l_selection_iterate, (lua_State *)); static int FDECL(l_selection_gc, (lua_State *)); static int FDECL(l_selection_not, (lua_State *)); @@ -39,7 +40,6 @@ static int FDECL(l_selection_not, (lua_State *)); if ifdef'd out the prototype here and the function body below. */ -static int FDECL(l_selection_gradient, (lua_State *)); static int FDECL(l_selection_add, (lua_State *)); static int FDECL(l_selection_sub, (lua_State *)); static int FDECL(l_selection_ipairs, (lua_State *)); @@ -736,6 +736,70 @@ lua_State *L; return 1; } +/* Gradients are versatile enough, with so many independently optional + * arguments, that it doesn't seem helpful to provide a non-table form with + * non-obvious argument order. */ +/* selection.gradient({ type = "radial", x = 3, y = 5, x2 = 10, y2 = 12, + * mindist = 4, maxdist = 10, limited = false }); */ +static int +l_selection_gradient(L) +lua_State *L; +{ + int argc = lua_gettop(L); + struct selectionvar *sel = (struct selectionvar *) 0; + /* if x2 and y2 aren't set, the gradient has a single center point of x,y; + * if they are set, the gradient is centered on a (x,y) to (x2,y2) line */ + schar x = 0, y = 0, x2 = -1, y2 = -1; + /* points will not be added within mindist of the center; the chance for a + * point between mindist and maxdist to be added to the selection starts at + * 0% at mindist and increases linearly to 100% at maxdist */ + xchar mindist = 0, maxdist = 0; + /* if limited is true, no points farther than maxdist will be added; if + * false, all points farther than maxdist will be added */ + boolean limited = FALSE; + long type; + static const char *const gradtypes[] = { + "radial", "square", NULL + }; + static const int gradtypes2i[] = { + SEL_GRADIENT_RADIAL, SEL_GRADIENT_SQUARE, -1 + }; + + if (argc == 1 && lua_type(L, 1) == LUA_TTABLE) { + lcheck_param_table(L); + type = gradtypes2i[get_table_option(L, "type", "radial", gradtypes)]; + x = (schar) get_table_int(L, "x"); + y = (schar) get_table_int(L, "y"); + x2 = (schar) get_table_int_opt(L, "x2", -1); + y2 = (schar) get_table_int_opt(L, "y2", -1); + /* maxdist is required because there's no obvious default value for it, + * whereas mindist has an obvious defalt of 0 */ + maxdist = get_table_int(L, "maxdist"); + mindist = get_table_int_opt(L, "mindist", 0); + limited = get_table_boolean_opt(L, "limited", FALSE); + + lua_pop(L, 1); + (void) l_selection_new(L); + sel = l_selection_check(L, 1); + } else { + nhl_error(L, "wrong parameters"); + /* NOTREACHED */ + } + + /* someone might conceivably want to draw a gradient somewhere off-map. So + * the only coordinate that's "illegal" for that is (-1,-1). + * If a level designer really needs to draw a gradient line using that + * coordinate, they can do so by setting regular x and y to -1. */ + if (x2 == -1 && y2 == -1) { + x2 = x; + y2 = y; + } + + selection_do_gradient(sel, x, y, x2, y2, type, mindist, maxdist, limited); + lua_settop(L, 1); + return 1; +} + /* sel:iterate(function(x,y) ... end); */ static int l_selection_iterate(L) @@ -782,10 +846,8 @@ static const struct luaL_Reg l_selection_methods[] = { { "floodfill", l_selection_flood }, { "circle", l_selection_circle }, { "ellipse", l_selection_ellipse }, + { "gradient", l_selection_gradient }, { "iterate", l_selection_iterate }, - /* TODO: - { "gradient", l_selection_gradient }, - */ { NULL, NULL } }; diff --git a/src/sp_lev.c b/src/sp_lev.c index bf0131b1f..6a870778c 100755 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -4683,6 +4683,8 @@ long x, y, x2, y2, gtyp, mind, maxd, limit; switch (gtyp) { default: + impossible("Unrecognized gradient type! Defaulting to radial..."); + /* FALLTHRU */ case SEL_GRADIENT_RADIAL: { for (dx = 0; dx < COLNO; dx++) for (dy = 0; dy < ROWNO; dy++) {