git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1630 c06c8d41-db1a-0410-9941-cceddc491573
AUXHSGS4EFOPZ6TVZYWNVOUDO7NYKUKE3HBKGQQWTALSVFOE3HAAC
/*
* File: luadgn.h
* Summary: Dungeon-builder Lua interface.
*
* Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-06-21T19:20:47.183838Z $
*/
#ifndef LUADGN_H
#define LUADGN_H
#include "AppHdr.h"
#include "clua.h"
extern CLua dlua;
class dlua_chunk
{
private:
std::string file;
std::string chunk;
int first, last; // First and last lines of the original source.
private:
int check_op(CLua *, int);
public:
std::string error;
public:
dlua_chunk();
void clear();
void add(int line, const std::string &line);
int load(CLua *interp);
int load_call(CLua *interp, const char *function);
void set_file(const std::string &s);
const std::string &lua_string() const { return chunk; }
std::string orig_error() const;
bool empty() const;
};
void init_dungeon_lua();
std::string dgn_set_default_depth(const std::string &s);
void dgn_reset_default_depth();
#endif
/*
* File: luadgn.cc
* Summary: Dungeon-builder Lua interface.
*
* Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-06-21T19:20:47.183838Z $
*/
#include "AppHdr.h"
#include "clua.h"
#include "luadgn.h"
#include "mapdef.h"
// Lua interpreter for the dungeon builder.
CLua dlua(false);
template <typename list, typename lpush>
static int dlua_gentable(lua_State *ls, const list &strings, lpush push)
{
lua_newtable(ls);
for (int i = 0, size = strings.size(); i < size; ++i)
{
push(ls, strings[i]);
lua_rawseti(ls, -2, i + 1);
}
return (1);
}
inline static void dlua_pushcxxstring(lua_State *ls, const std::string &s)
{
lua_pushstring(ls, s.c_str());
}
static int dlua_stringtable(lua_State *ls, const std::vector<std::string> &s)
{
return dlua_gentable(ls, s, dlua_pushcxxstring);
}
///////////////////////////////////////////////////////////////////////////
// dlua_chunk
dlua_chunk::dlua_chunk()
: file(), chunk(), first(-1), last(-1), error()
{
clear();
}
void dlua_chunk::clear()
{
file.clear();
chunk.clear();
first = last = -1;
error.clear();
}
void dlua_chunk::set_file(const std::string &s)
{
file = s;
}
void dlua_chunk::add(int line, const std::string &s)
{
if (first == -1)
first = line;
if (line != last && last != -1)
chunk += "\n";
chunk += " ";
chunk += s;
last = line;
}
int dlua_chunk::check_op(CLua *interp, int err)
{
error = interp->error;
return (err);
}
int dlua_chunk::load(CLua *interp)
{
if (trimmed_string(chunk).empty())
return (-1000);
return check_op(interp,
interp->loadstring(chunk.c_str(), "dlua_chunk"));
}
int dlua_chunk::load_call(CLua *interp, const char *fn)
{
int err = load(interp);
if (err == -1000)
return (0);
if (err)
return (err);
return check_op(interp, interp->callfn(fn, 1, 0));
}
std::string dlua_chunk::orig_error() const
{
return (error);
}
bool dlua_chunk::empty() const
{
return trimmed_string(chunk).empty();
}
///////////////////////////////////////////////////////////////////////////
// Lua dungeon bindings (in the dgn table).
static depth_ranges dgn_default_depths;
#define MAP(ls, n, var) \
map_def *var = *(map_def **) luaL_checkudata(ls, n, MAP_METATABLE)
void dgn_reset_default_depth()
{
dgn_default_depths.clear();
}
std::string dgn_set_default_depth(const std::string &s)
{
std::vector<std::string> frags = split_string(",", s);
for (int i = 0, size = frags.size(); i < size; ++i)
{
try
{
dgn_default_depths.push_back( level_range::parse(frags[i]) );
}
catch (const std::string &error)
{
return (error);
}
}
return ("");
}
static void dgn_add_depths(depth_ranges &drs, lua_State *ls, int s, int e)
{
for (int i = s; i <= e; ++i)
{
const char *depth = luaL_checkstring(ls, i);
std::vector<std::string> frags = split_string(",", depth);
for (int j = 0, size = frags.size(); i < size; ++i)
{
try
{
dgn_default_depths.push_back( level_range::parse(frags[j]) );
}
catch (const std::string &error)
{
luaL_error(ls, error.c_str());
}
}
}
}
static std::string dgn_depth_list_string(const depth_ranges &drs)
{
return (comma_separated_line(drs.begin(), drs.end(), ", ", ", "));
}
static int dgn_depth_proc(lua_State *ls, depth_ranges &dr, int s)
{
if (lua_gettop(ls) < s)
{
PLUARET(string, dgn_depth_list_string(dr).c_str());
}
if (lua_isnil(ls, s))
{
dr.clear();
return (0);
}
dr.clear();
dgn_add_depths(dr, ls, s, lua_gettop(ls));
return (0);
}
static int dgn_default_depth(lua_State *ls)
{
return dgn_depth_proc(ls, dgn_default_depths, 1);
}
static int dgn_depth(lua_State *ls)
{
MAP(ls, 1, map);
return dgn_depth_proc(ls, map->depths, 2);
}
static int dgn_place(lua_State *ls)
{
MAP(ls, 1, map);
if (lua_gettop(ls) > 1)
{
if (lua_isnil(ls, 2))
map->place.clear();
else
map->place = luaL_checkstring(ls, 2);
}
PLUARET(string, map->place.c_str());
}
static int dgn_tags(lua_State *ls)
{
MAP(ls, 1, map);
if (lua_gettop(ls) > 1)
{
if (lua_isnil(ls, 2))
map->tags.clear();
else
{
const char *s = luaL_checkstring(ls, 2);
map->tags += " " + trimmed_string(s) + " ";
}
}
PLUARET(string, map->tags.c_str());
}
static int dgn_tags_remove(lua_State *ls)
{
MAP(ls, 1, map);
const int top = lua_gettop(ls);
for (int i = 2; i <= top; ++i)
{
const std::string axee = luaL_checkstring(ls, i);
const std::string::size_type pos = map->tags.find(axee);
if (pos != std::string::npos)
map->tags =
map->tags.substr(0, pos)
+ map->tags.substr(pos + axee.length());
}
PLUARET(string, map->tags.c_str());
}
static int dgn_weight(lua_State *ls)
{
MAP(ls, 1, map);
if (!lua_isnil(ls, 2))
map->chance = luaL_checkint(ls, 2);
PLUARET(number, map->chance);
}
static int dgn_orient(lua_State *ls)
{
MAP(ls, 1, map);
if (lua_gettop(ls) > 1)
{
if (lua_isnil(ls, 2))
map->orient = MAP_NONE;
else
{
const std::string orient = luaL_checkstring(ls, 2);
bool found = false;
// Note: Empty string is intentionally mapped to MAP_NONE!
for (int i = MAP_NONE; i < MAP_NUM_SECTION_TYPES; ++i)
{
if (orient == map_section_name(i))
{
map->orient = static_cast<map_section_type>(i);
found = true;
break;
}
}
if (!found)
luaL_error(ls, ("Bad orient: " + orient).c_str());
}
}
PLUARET(string, map_section_name(map->orient));
}
static int dgn_shuffle(lua_State *ls)
{
MAP(ls, 1, map);
if (lua_gettop(ls) == 1)
return dlua_stringtable(ls, map->get_shuffle_strings());
for (int i = 2, size = lua_gettop(ls); i <= size; ++i)
{
if (lua_isnil(ls, i))
map->map.clear_shuffles();
else
{
std::string err = map->map.add_shuffle(luaL_checkstring(ls, i));
if (!err.empty())
luaL_error(ls, err.c_str());
}
}
return (0);
}
static int dgn_shuffle_remove(lua_State *ls)
{
MAP(ls, 1, map);
for (int i = 2, size = lua_gettop(ls); i <= size; ++i)
map->map.remove_shuffle(luaL_checkstring(ls, i));
return (0);
}
static int dgn_subst(lua_State *ls)
{
MAP(ls, 1, map);
if (lua_gettop(ls) == 1)
return dlua_stringtable(ls, map->get_subst_strings());
for (int i = 2, size = lua_gettop(ls); i <= size; ++i)
{
if (lua_isnil(ls, i))
map->map.clear_substs();
else
{
std::string err = map->map.add_subst(luaL_checkstring(ls, i));
if (!err.empty())
luaL_error(ls, err.c_str());
}
}
return (0);
}
static int dgn_subst_remove(lua_State *ls)
{
MAP(ls, 1, map);
for (int i = 2, size = lua_gettop(ls); i <= size; ++i)
map->map.remove_subst(luaL_checkstring(ls, i));
return (0);
}
static int dgn_map(lua_State *ls)
{
MAP(ls, 1, map);
if (lua_gettop(ls) == 1)
return dlua_stringtable(ls, map->map.get_lines());
if (lua_isnil(ls, 2))
{
map->map.clear();
return (0);
}
if (lua_isstring(ls, 2))
{
map->map.add_line(luaL_checkstring(ls, 2));
return (0);
}
std::vector<std::string> &lines = map->map.get_lines();
int which_line = luaL_checkint(ls, 2);
if (which_line < 0)
which_line += (int) lines.size();
if (lua_gettop(ls) == 2)
{
if (which_line < 0 || which_line >= (int) lines.size())
{
luaL_error(ls,
lines.empty()? "Map is empty"
: make_stringf("Line %d out of range (0-%u)",
which_line,
lines.size() - 1).c_str());
}
PLUARET(string, lines[which_line].c_str());
}
if (lua_isnil(ls, 3))
{
if (which_line >= 0 && which_line < (int) lines.size())
{
lines.erase(lines.begin() + which_line);
PLUARET(boolean, true);
}
return (0);
}
const std::string newline = luaL_checkstring(ls, 3);
if (which_line < 0)
luaL_error(ls,
make_stringf("Index %d out of range", which_line).c_str());
if (which_line < (int) lines.size())
{
lines[which_line] = newline;
return (0);
}
lines.reserve(which_line + 1);
lines.resize(which_line + 1, "");
lines[which_line] = newline;
return (0);
}
static int dgn_mons(lua_State *ls)
{
MAP(ls, 1, map);
if (lua_gettop(ls) == 1)
return (0);
if (lua_isnil(ls, 2))
{
map->mons.clear();
return (0);
}
if (lua_isstring(ls, 2))
{
std::string err = map->mons.add_mons(luaL_checkstring(ls, 2));
if (!err.empty())
luaL_error(ls, err.c_str());
return (0);
}
const int index = luaL_checkint(ls, 2);
std::string err = map->mons.set_mons(index, luaL_checkstring(ls, 3));
if (!err.empty())
luaL_error(ls, err.c_str());
return (0);
}
static int dgn_item(lua_State *ls)
{
MAP(ls, 1, map);
if (lua_gettop(ls) == 1)
return (0);
if (lua_isnil(ls, 2))
{
map->items.clear();
return (0);
}
if (lua_isstring(ls, 2))
{
std::string err = map->items.add_item(luaL_checkstring(ls, 2));
if (!err.empty())
luaL_error(ls, err.c_str());
return (0);
}
const int index = luaL_checkint(ls, 2);
std::string err = map->items.set_item(index, luaL_checkstring(ls, 3));
if (!err.empty())
luaL_error(ls, err.c_str());
return (0);
}
static int dgn_kfeat(lua_State *ls)
{
MAP(ls, 1, map);
std::string err = map->add_key_feat(luaL_checkstring(ls, 2));
if (!err.empty())
luaL_error(ls, err.c_str());
return (0);
}
static int dgn_kmons(lua_State *ls)
{
MAP(ls, 1, map);
std::string err = map->add_key_mons(luaL_checkstring(ls, 2));
if (!err.empty())
luaL_error(ls, err.c_str());
return (0);
}
static int dgn_kitem(lua_State *ls)
{
MAP(ls, 1, map);
std::string err = map->add_key_item(luaL_checkstring(ls, 2));
if (!err.empty())
luaL_error(ls, err.c_str());
return (0);
}
static const struct luaL_reg dgn_lib[] =
{
{ "default_depth", dgn_default_depth },
{ "depth", dgn_depth },
{ "place", dgn_place },
{ "tags", dgn_tags },
{ "tags_remove", dgn_tags_remove },
{ "chance", dgn_weight },
{ "weight", dgn_weight },
{ "orient", dgn_orient },
{ "shuffle", dgn_shuffle },
{ "shuffle_remove", dgn_shuffle_remove },
{ "subst", dgn_subst },
{ "subst_remove", dgn_subst_remove },
{ "map", dgn_map },
{ "mons", dgn_mons },
{ "item", dgn_item },
{ "kfeat", dgn_kfeat },
{ "kitem", dgn_kitem },
{ "kmons", dgn_kmons },
{ NULL, NULL }
};
void init_dungeon_lua()
{
dlua.execfile("clua/dungeon.lua");
luaL_newmetatable(dlua, MAP_METATABLE);
lua_pop(dlua, 1);
luaL_openlib(dlua, "dgn", dgn_lib, 0);
}