Apply the new ground_level method.
[crawl.git] / crawl-ref / source / dlua.cc
blob2df429c3a62667b38017b0569ca5216028cba9b7
1 /*
2 * File: dlua.cc
3 * Summary: Dungeon-builder Lua interface.
4 * Created by: dshaligram on Sat Jun 23 20:02:09 2007 UTC
5 */
7 #include "AppHdr.h"
9 #include <sstream>
11 #include "dlua.h"
12 #include "l_libs.h"
13 #include "libutil.h"
14 #include "tags.h"
16 static int dlua_compiled_chunk_writer(lua_State *ls, const void *p,
17 size_t sz, void *ud)
19 std::ostringstream &out = *static_cast<std::ostringstream*>(ud);
20 out.write(static_cast<const char *>(p), sz);
21 return (0);
24 ///////////////////////////////////////////////////////////////////////////
25 // dlua_chunk
27 dlua_chunk::dlua_chunk(const std::string &_context)
28 : file(), chunk(), compiled(), context(_context), first(-1),
29 last(-1), error()
31 clear();
34 // Initialises a chunk from the function on the top of stack.
35 // This function must not be a closure, i.e. must not have any upvalues.
36 dlua_chunk::dlua_chunk(lua_State *ls)
37 : file(), chunk(), compiled(), context(), first(-1), last(-1), error()
39 clear();
41 lua_stack_cleaner cln(ls);
42 std::ostringstream out;
43 const int err = lua_dump(ls, dlua_compiled_chunk_writer, &out);
44 if (err)
46 const char *e = lua_tostring(ls, -1);
47 error = e? e : "Unknown error compiling chunk";
49 compiled = out.str();
52 dlua_chunk dlua_chunk::precompiled(const std::string &_chunk)
54 dlua_chunk dchunk;
55 dchunk.compiled = _chunk;
56 return (dchunk);
59 std::string dlua_chunk::describe(const std::string &name) const
61 if (chunk.empty())
62 return "";
63 return make_stringf("function %s()\n%s\nend\n",
64 name.c_str(), chunk.c_str());
67 void dlua_chunk::write(writer& outf) const
69 if (empty())
71 marshallByte(outf, CT_EMPTY);
72 return;
75 if (!compiled.empty())
77 marshallByte(outf, CT_COMPILED);
78 marshallString4(outf, compiled);
80 else
82 marshallByte(outf, CT_SOURCE);
83 marshallString4(outf, chunk);
86 marshallString4(outf, file);
87 marshallInt(outf, first);
90 void dlua_chunk::read(reader& inf)
92 clear();
93 chunk_t type = static_cast<chunk_t>(unmarshallByte(inf));
94 switch (type)
96 case CT_EMPTY:
97 return;
98 case CT_SOURCE:
99 unmarshallString4(inf, chunk);
100 break;
101 case CT_COMPILED:
102 unmarshallString4(inf, compiled);
103 break;
105 unmarshallString4(inf, file);
106 first = unmarshallInt(inf);
109 void dlua_chunk::clear()
111 file.clear();
112 chunk.clear();
113 first = last = -1;
114 error.clear();
115 compiled.clear();
118 void dlua_chunk::set_file(const std::string &s)
120 file = s;
123 void dlua_chunk::add(int line, const std::string &s)
125 if (first == -1)
126 first = line;
128 if (line != last && last != -1)
129 while (last++ < line)
130 chunk += '\n';
132 chunk += " ";
133 chunk += s;
134 last = line;
137 void dlua_chunk::set_chunk(const std::string &s)
139 chunk = s;
142 int dlua_chunk::check_op(CLua &interp, int err)
144 error = interp.error;
145 return (err);
148 int dlua_chunk::load(CLua &interp)
150 if (!compiled.empty())
151 return check_op(interp,
152 interp.loadbuffer(compiled.c_str(), compiled.length(),
153 context.c_str()));
155 if (empty())
157 chunk.clear();
158 return (E_CHUNK_LOAD_FAILURE);
161 int err = check_op(interp,
162 interp.loadstring(chunk.c_str(), context.c_str()));
163 if (err)
164 return (err);
165 std::ostringstream out;
166 err = lua_dump(interp, dlua_compiled_chunk_writer, &out);
167 if (err)
169 const char *e = lua_tostring(interp, -1);
170 error = e? e : "Unknown error compiling chunk";
171 lua_pop(interp, 2);
173 compiled = out.str();
174 return (err);
177 int dlua_chunk::run(CLua &interp)
179 int err = load(interp);
180 if (err)
181 return (err);
182 // callfn returns true on success, but we want to return 0 on success.
183 return (check_op(interp, !interp.callfn(NULL, 0, 0)));
186 int dlua_chunk::load_call(CLua &interp, const char *fn)
188 int err = load(interp);
189 if (err == E_CHUNK_LOAD_FAILURE)
190 return (0);
191 if (err)
192 return (err);
194 return check_op(interp, !interp.callfn(fn, fn? 1 : 0, 0));
197 std::string dlua_chunk::orig_error() const
199 rewrite_chunk_errors(error);
200 return (error);
203 bool dlua_chunk::empty() const
205 return compiled.empty() && trimmed_string(chunk).empty();
208 bool dlua_chunk::rewrite_chunk_errors(std::string &s) const
210 const std::string contextm = "[string \"" + context + "\"]:";
211 std::string::size_type dlwhere = s.find(contextm);
213 if (dlwhere == std::string::npos)
214 return (false);
216 if (!dlwhere)
218 s = rewrite_chunk_prefix(s);
219 return (true);
222 // Our chunk is mentioned, go back through and rewrite lines.
223 std::vector<std::string> lines = split_string("\n", s);
224 std::string newmsg = lines[0];
225 bool wrote_prefix = false;
226 for (int i = 2, size = lines.size() - 1; i < size; ++i)
228 const std::string &st = lines[i];
229 if (st.find(context) != std::string::npos)
231 if (!wrote_prefix)
233 newmsg = get_chunk_prefix(st) + ": " + newmsg;
234 wrote_prefix = true;
236 else
237 newmsg += "\n" + rewrite_chunk_prefix(st);
240 s = newmsg;
241 return (true);
244 std::string dlua_chunk::rewrite_chunk_prefix(const std::string &line,
245 bool skip_body) const
247 std::string s = line;
248 const std::string contextm = "[string \"" + context + "\"]:";
249 const std::string::size_type ps = s.find(contextm);
250 if (ps == std::string::npos)
251 return (s);
253 const std::string::size_type lns = ps + contextm.length();
254 std::string::size_type pe = s.find(':', ps + contextm.length());
255 if (pe != std::string::npos)
257 const std::string line_num = s.substr(lns, pe - lns);
258 const int lnum = atoi(line_num.c_str());
259 const std::string newlnum = make_stringf("%d", lnum + first - 1);
260 s = s.substr(0, lns) + newlnum + s.substr(pe);
261 pe = lns + newlnum.length();
264 return s.substr(0, ps) + (file.empty()? context : file) + ":"
265 + (skip_body? s.substr(lns, pe - lns)
266 : s.substr(lns));
269 std::string dlua_chunk::get_chunk_prefix(const std::string &sorig) const
271 return rewrite_chunk_prefix(sorig, true);
274 static void _dlua_register_constants(CLua &lua)
276 lua_pushstring(lua, CORPSE_NEVER_DECAYS);
277 lua.setglobal("CORPSE_NEVER_DECAYS");
280 void init_dungeon_lua()
282 lua_stack_cleaner clean(dlua);
284 dluaopen_colour(dlua);
285 dluaopen_crawl(dlua);
286 dluaopen_file(dlua);
287 dluaopen_mapgrd(dlua);
288 dluaopen_monsters(dlua);
289 dluaopen_you(dlua);
290 dluaopen_dgn(dlua);
292 luaL_openlib(dlua, "feat", feat_dlib, 0);
293 luaL_openlib(dlua, "spells", spells_dlib, 0);
294 luaL_openlib(dlua, "debug", debug_dlib, 0);
295 luaL_openlib(dlua, "los", los_dlib, 0);
297 dlua.execfile("clua/dungeon.lua", true, true);
298 dlua.execfile("clua/luamark.lua", true, true);
299 dlua.execfile("clua/mapinit.lua", true, true);
301 lua_getglobal(dlua, "dgn_run_map");
302 luaopen_debug(dlua);
303 luaL_newmetatable(dlua, MAP_METATABLE);
305 luaopen_dgnevent(dlua);
306 luaopen_mapmarker(dlua);
307 luaopen_ray(dlua);
309 register_itemlist(dlua);
310 register_monslist(dlua);
312 _dlua_register_constants(dlua);