Also minor cleanup.
RJIGO3YE7LKSLASPVA7K6CNWJAPKXD7ENJDURI5GXBGIEXFBBINAC
O6QYS2KYXUXMODO3X4SYX7SPZE7AOIFT2XJZHRABMMQFEUN4UXLAC
WQBSKRTHZRKIYIDHROBSIEHEEQX26UAFDTMYY24UOPYNMYWXDFCAC
LE5U6CTXEIETQN5GOVYF2K2VCISRXR3ULORXDKIKWYDVBG5GS3WAC
MQ62OAMLGJVRW2QIL4PAZRAU6PC52ZVGY2FCOBIY6IWGQIHMU5CAC
3A5FX3Y4RPKWQEHKKXZKXZJ7RKV6RKWT7GTR4WFE5UBWKV2HT4RQC
UL7XFKMUX3WIU4O2LZANK4ECJ654UZPDBFGNXUEYZYOLKBYBCG6AC
void luaopen_dgnevent(lua_State *ls)
{
luaopen_setmeta(ls, "dgnevent", dgnevent_lib, DEVENT_METATABLE);
}
/*
* File: l_dgnbf.cc
* Summary: Dungeon lua builder functions.
*/
#include "AppHdr.h"
#include "dlua.h"
#include "l_libs.h"
#include "mapdef.h"
// Return the integer stored in the table (on the stack) with the key name.
// If the key doesn't exist or the value is the wrong type, return defval.
static int _table_int(lua_State *ls, int idx, const char *name, int defval)
{
lua_pushstring(ls, name);
lua_gettable(ls, idx < 0 ? idx - 1 : idx);
bool nil = lua_isnil(ls, idx);
bool valid = lua_isnumber(ls, idx);
if (!nil && !valid)
luaL_error(ls, "'%s' in table, but not an int.", name);
int ret = (!nil && valid ? lua_tonumber(ls, idx) : defval);
lua_pop(ls, 1);
return (ret);
}
// Return the character stored in the table (on the stack) with the key name.
// If the key doesn't exist or the value is the wrong type, return defval.
static char _table_char(lua_State *ls, int idx, const char *name, char defval)
{
lua_pushstring(ls, name);
lua_gettable(ls, idx < 0 ? idx - 1 : idx);
bool nil = lua_isnil(ls, idx);
bool valid = lua_isstring(ls, idx);
if (!nil && !valid)
luaL_error(ls, "'%s' in table, but not a string.", name);
char ret = defval;
if (!nil && valid)
{
const char *str = lua_tostring(ls, idx);
if (str[0] && !str[1])
ret = str[0];
else
luaL_error(ls, "'%s' has more than one character.", name);
}
lua_pop(ls, 1);
return (ret);
}
// Return the string stored in the table (on the stack) with the key name.
// If the key doesn't exist or the value is the wrong type, return defval.
static const char* _table_str(lua_State *ls, int idx, const char *name, const char *defval)
{
lua_pushstring(ls, name);
lua_gettable(ls, idx < 0 ? idx - 1 : idx);
bool nil = lua_isnil(ls, idx);
bool valid = lua_isstring(ls, idx);
if (!nil && !valid)
luaL_error(ls, "'%s' in table, but not a string.", name);
const char *ret = (!nil && valid ? lua_tostring(ls, idx) : defval);
lua_pop(ls, 1);
return (ret);
}
// Return the boolean stored in the table (on the stack) with the key name.
// If the key doesn't exist or the value is the wrong type, return defval.
static bool _table_bool(lua_State *ls, int idx, const char *name, bool defval)
{
lua_pushstring(ls, name);
lua_gettable(ls, idx < 0 ? idx - 1 : idx);
bool nil = lua_isnil(ls, idx);
bool valid = lua_isboolean(ls, idx);
if (!nil && !valid)
luaL_error(ls, "'%s' in table, but not a bool.", name);
bool ret = (!nil && valid ? lua_toboolean(ls, idx) : defval);
lua_pop(ls, 1);
return (ret);
}
#define BF_INT(ls, val, def) int val = _table_int(ls, -1, #val, def);
#define BF_CHAR(ls, val, def) char val = _table_char(ls, -1, #val, def);
#define BF_STR(ls, val, def) const char *val = _table_str(ls, -1, #val, def);
#define BF_BOOL(ls, val, def) bool val = _table_bool(ls, -1, #val, def);
static void bf_octa_room(lua_State *ls, map_lines &lines)
{
int default_oblique = std::min(lines.width(), lines.height()) / 2 - 1;
BF_INT(ls, oblique, default_oblique);
BF_CHAR(ls, outside, 'x');
BF_CHAR(ls, inside, '.');
BF_STR(ls, replace, ".");
coord_def tl, br;
if (!lines.find_bounds(replace, tl, br))
return;
for (rectangle_iterator ri(tl, br); ri; ++ri)
{
const coord_def mc = *ri;
char glyph = lines(mc);
if (replace[0] && !strchr(replace, glyph))
continue;
int ob = 0;
ob += std::max(oblique + tl.x - mc.x, 0);
ob += std::max(oblique + mc.x - br.x, 0);
bool is_inside = (mc.y >= tl.y + ob && mc.y <= br.y - ob);
lines(mc) = is_inside ? inside : outside;
}
}
static void bf_smear(lua_State *ls, map_lines &lines)
{
BF_INT(ls, iterations, 1);
BF_CHAR(ls, smear, 'x');
BF_STR(ls, onto, ".");
BF_BOOL(ls, boxy, false);
const int max_test_per_iteration = 10;
int sanity = 0;
int max_sanity = iterations * max_test_per_iteration;
for (int i = 0; i < iterations; i++)
{
bool diagonals, straights;
coord_def mc;
do
{
do
{
sanity++;
mc.x = random_range(1, lines.width() - 2);
mc.y = random_range(1, lines.height() - 2);
}
while (onto[0] && !strchr(onto, lines(mc)));
// Prevent too many iterations.
if (sanity > max_sanity)
return;
// Is there a "smear" feature along the diagonal from mc?
diagonals = lines(coord_def(mc.x+1, mc.y+1)) == smear ||
lines(coord_def(mc.x-1, mc.y+1)) == smear ||
lines(coord_def(mc.x-1, mc.y-1)) == smear ||
lines(coord_def(mc.x+1, mc.y-1)) == smear;
// Is there a "smear" feature up, down, left, or right from mc?
straights = lines(coord_def(mc.x+1, mc.y)) == smear ||
lines(coord_def(mc.x-1, mc.y)) == smear ||
lines(coord_def(mc.x, mc.y+1)) == smear ||
lines(coord_def(mc.x, mc.y-1)) == smear;
}
while (!straights && (boxy || !diagonals));
lines(mc) = smear;
}
}
static void bf_extend(lua_State *ls, map_lines &lines)
{
BF_INT(ls, height, 1);
BF_INT(ls, width, 1);
BF_CHAR(ls, fill, 'x');
lines.extend(width, height, fill);
}
typedef void (*bf_func)(lua_State *ls, map_lines &lines);
struct bf_entry
{
const char* name;
bf_func func;
};
// Create a separate list of builder funcs so that we can automatically
// generate a list of closures for them, rather than individually
// and explicitly exposing them to the dgn namespace.
static struct bf_entry bf_map[] =
{
{ "map_octa_room", &bf_octa_room },
{ "map_smear", &bf_smear },
{ "map_extend", &bf_extend }
};
static int dgn_call_builder_func(lua_State *ls)
{
// This function gets called for all the builder functions that
// operate on map_lines.
MAP(ls, 1, map);
if (!lua_istable(ls, 2) && !lua_isfunction(ls, 2))
return luaL_argerror(ls, 2, "Expected table");
bf_func *func = (bf_func *)lua_topointer(ls, lua_upvalueindex(1));
if (!func)
return luaL_error(ls, "Expected C function in closure upval");
// Put the table on top.
lua_settop(ls, 2);
// Call the builder func itself.
(*func)(ls, map->map);
return (0);
}
void register_builder_funcs(lua_State *ls)
{
lua_getglobal(ls, "dgn");
const size_t num_entries = sizeof(bf_map) / sizeof(bf_entry);
for (size_t i = 0; i < num_entries; i++)
{
// Push a closure with the C function into the dgn table.
lua_pushlightuserdata(ls, &bf_map[i].func);
lua_pushcclosure(ls, &dgn_call_builder_func, 1);
lua_setfield(ls, -2, bf_map[i].name);
}
lua_pop(ls, 1);
}
}
static void luaopen_dgnevent(lua_State *ls)
{
luaopen_setmeta(ls, "dgnevent", dgnevent_lib, DEVENT_METATABLE);
}
// Return the integer stored in the table (on the stack) with the key name.
// If the key doesn't exist or the value is the wrong type, return defval.
static int _table_int(lua_State *ls, int idx, const char *name, int defval)
{
lua_pushstring(ls, name);
lua_gettable(ls, idx < 0 ? idx - 1 : idx);
bool nil = lua_isnil(ls, idx);
bool valid = lua_isnumber(ls, idx);
if (!nil && !valid)
luaL_error(ls, "'%s' in table, but not an int.", name);
int ret = (!nil && valid ? lua_tonumber(ls, idx) : defval);
lua_pop(ls, 1);
return (ret);
}
// Return the character stored in the table (on the stack) with the key name.
// If the key doesn't exist or the value is the wrong type, return defval.
static char _table_char(lua_State *ls, int idx, const char *name, char defval)
{
lua_pushstring(ls, name);
lua_gettable(ls, idx < 0 ? idx - 1 : idx);
bool nil = lua_isnil(ls, idx);
bool valid = lua_isstring(ls, idx);
if (!nil && !valid)
luaL_error(ls, "'%s' in table, but not a string.", name);
char ret = defval;
if (!nil && valid)
{
const char *str = lua_tostring(ls, idx);
if (str[0] && !str[1])
ret = str[0];
else
luaL_error(ls, "'%s' has more than one character.", name);
}
lua_pop(ls, 1);
return (ret);
}
// Return the string stored in the table (on the stack) with the key name.
// If the key doesn't exist or the value is the wrong type, return defval.
static const char* _table_str(lua_State *ls, int idx, const char *name, const char *defval)
{
lua_pushstring(ls, name);
lua_gettable(ls, idx < 0 ? idx - 1 : idx);
bool nil = lua_isnil(ls, idx);
bool valid = lua_isstring(ls, idx);
if (!nil && !valid)
luaL_error(ls, "'%s' in table, but not a string.", name);
const char *ret = (!nil && valid ? lua_tostring(ls, idx) : defval);
lua_pop(ls, 1);
return (ret);
}
// Return the boolean stored in the table (on the stack) with the key name.
// If the key doesn't exist or the value is the wrong type, return defval.
static bool _table_bool(lua_State *ls, int idx, const char *name, bool defval)
{
lua_pushstring(ls, name);
lua_gettable(ls, idx < 0 ? idx - 1 : idx);
bool nil = lua_isnil(ls, idx);
bool valid = lua_isboolean(ls, idx);
if (!nil && !valid)
luaL_error(ls, "'%s' in table, but not a bool.", name);
bool ret = (!nil && valid ? lua_toboolean(ls, idx) : defval);
lua_pop(ls, 1);
return (ret);
}
#define BF_INT(ls, val, def) int val = _table_int(ls, -1, #val, def);
#define BF_CHAR(ls, val, def) char val = _table_char(ls, -1, #val, def);
#define BF_STR(ls, val, def) const char *val = _table_str(ls, -1, #val, def);
#define BF_BOOL(ls, val, def) bool val = _table_bool(ls, -1, #val, def);
static void bf_octa_room(lua_State *ls, map_lines &lines)
{
int default_oblique = std::min(lines.width(), lines.height()) / 2 - 1;
BF_INT(ls, oblique, default_oblique);
BF_CHAR(ls, outside, 'x');
BF_CHAR(ls, inside, '.');
BF_STR(ls, replace, ".");
coord_def tl, br;
if (!lines.find_bounds(replace, tl, br))
return;
for (rectangle_iterator ri(tl, br); ri; ++ri)
{
const coord_def mc = *ri;
char glyph = lines(mc);
if (replace[0] && !strchr(replace, glyph))
continue;
int ob = 0;
ob += std::max(oblique + tl.x - mc.x, 0);
ob += std::max(oblique + mc.x - br.x, 0);
bool is_inside = (mc.y >= tl.y + ob && mc.y <= br.y - ob);
lines(mc) = is_inside ? inside : outside;
}
}
static void bf_smear(lua_State *ls, map_lines &lines)
{
BF_INT(ls, iterations, 1);
BF_CHAR(ls, smear, 'x');
BF_STR(ls, onto, ".");
BF_BOOL(ls, boxy, false);
const int max_test_per_iteration = 10;
int sanity = 0;
int max_sanity = iterations * max_test_per_iteration;
for (int i = 0; i < iterations; i++)
{
bool diagonals, straights;
coord_def mc;
do
{
do
{
sanity++;
mc.x = random_range(1, lines.width() - 2);
mc.y = random_range(1, lines.height() - 2);
}
while (onto[0] && !strchr(onto, lines(mc)));
// Prevent too many iterations.
if (sanity > max_sanity)
return;
// Is there a "smear" feature along the diagonal from mc?
diagonals = lines(coord_def(mc.x+1, mc.y+1)) == smear ||
lines(coord_def(mc.x-1, mc.y+1)) == smear ||
lines(coord_def(mc.x-1, mc.y-1)) == smear ||
lines(coord_def(mc.x+1, mc.y-1)) == smear;
// Is there a "smear" feature up, down, left, or right from mc?
straights = lines(coord_def(mc.x+1, mc.y)) == smear ||
lines(coord_def(mc.x-1, mc.y)) == smear ||
lines(coord_def(mc.x, mc.y+1)) == smear ||
lines(coord_def(mc.x, mc.y-1)) == smear;
}
while (!straights && (boxy || !diagonals));
lines(mc) = smear;
}
}
static void bf_extend(lua_State *ls, map_lines &lines)
{
BF_INT(ls, height, 1);
BF_INT(ls, width, 1);
BF_CHAR(ls, fill, 'x');
lines.extend(width, height, fill);
typedef void (*bf_func)(lua_State *ls, map_lines &lines);
struct bf_entry
{
const char* name;
bf_func func;
};
// Create a separate list of builder funcs so that we can automatically
// generate a list of closures for them, rather than individually
// and explicitly exposing them to the dgn namespace.
static struct bf_entry bf_map[] =
{
{ "map_octa_room", &bf_octa_room },
{ "map_smear", &bf_smear },
{ "map_extend", &bf_extend }
};
static int dgn_call_builder_func(lua_State *ls)
{
// This function gets called for all the builder functions that
// operate on map_lines.
MAP(ls, 1, map);
if (!lua_istable(ls, 2) && !lua_isfunction(ls, 2))
return luaL_argerror(ls, 2, "Expected table");
bf_func *func = (bf_func *)lua_topointer(ls, lua_upvalueindex(1));
if (!func)
return luaL_error(ls, "Expected C function in closure upval");
// Put the table on top.
lua_settop(ls, 2);
// Call the builder func itself.
(*func)(ls, map->map);
return (0);
}
static void _register_builder_funcs(lua_State *ls)
{
lua_getglobal(ls, "dgn");
const size_t num_entries = sizeof(bf_map) / sizeof(bf_entry);
for (size_t i = 0; i < num_entries; i++)
{
// Push a closure with the C function into the dgn table.
lua_pushlightuserdata(ls, &bf_map[i].func);
lua_pushcclosure(ls, &dgn_call_builder_func, 1);
lua_setfield(ls, -2, bf_map[i].name);
}
lua_pop(ls, 1);
}