00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "lua/lualib.h"
00028 #include "lua/lauxlib.h"
00029
00030 #include <cassert>
00031 #include <cstring>
00032 #include <boost/bind.hpp>
00033 #include <boost/variant.hpp>
00034
00035 #include "scripting/lua.hpp"
00036 #include "scripting/lua_api.hpp"
00037
00038 #include "actions.hpp"
00039 #include "ai/manager.hpp"
00040 #include "attack_prediction.hpp"
00041 #include "filesystem.hpp"
00042 #include "foreach.hpp"
00043 #include "game_display.hpp"
00044 #include "game_preferences.hpp"
00045 #include "gamestatus.hpp"
00046 #include "log.hpp"
00047 #include "lua_jailbreak_exception.hpp"
00048 #include "map.hpp"
00049 #include "pathfind/pathfind.hpp"
00050 #include "pathfind/teleport.hpp"
00051 #include "play_controller.hpp"
00052 #include "replay.hpp"
00053 #include "reports.hpp"
00054 #include "resources.hpp"
00055 #include "terrain_filter.hpp"
00056 #include "terrain_translation.hpp"
00057 #include "side_filter.hpp"
00058 #include "sound.hpp"
00059 #include "unit.hpp"
00060 #include "ai/lua/core.hpp"
00061 #include "version.hpp"
00062 #include "gui/widgets/clickable.hpp"
00063 #ifdef GUI2_EXPERIMENTAL_LISTBOX
00064 #include "gui/widgets/list.hpp"
00065 #else
00066 #include "gui/widgets/listbox.hpp"
00067 #endif
00068 #include "gui/widgets/multi_page.hpp"
00069 #include "gui/widgets/selectable.hpp"
00070 #include "gui/widgets/settings.hpp"
00071 #include "gui/widgets/text_box.hpp"
00072 #include "gui/widgets/slider.hpp"
00073 #include "gui/widgets/progress_bar.hpp"
00074 #include "gui/widgets/window.hpp"
00075
00076 #ifdef DEBUG_LUA
00077 #include "scripting/debug_lua.hpp"
00078 #endif
00079
00080 static lg::log_domain log_scripting_lua("scripting/lua");
00081 #define LOG_LUA LOG_STREAM(info, log_scripting_lua)
00082 #define ERR_LUA LOG_STREAM(err, log_scripting_lua)
00083
00084 static std::vector<config> preload_scripts;
00085 static config preload_config;
00086
00087 void extract_preload_scripts(config const &game_config)
00088 {
00089 preload_scripts.clear();
00090 foreach (config const &cfg, game_config.child_range("lua")) {
00091 preload_scripts.push_back(cfg);
00092 }
00093 preload_config = game_config.child("game_config");
00094 }
00095
00096
00097
00098
00099 struct queued_event_context
00100 {
00101 typedef game_events::queued_event qe;
00102 static qe default_qe;
00103 static qe const *current_qe;
00104 static qe const &get()
00105 { return *(current_qe ? current_qe : &default_qe); }
00106 qe const *previous_qe;
00107
00108 queued_event_context(qe const *new_qe)
00109 : previous_qe(current_qe)
00110 {
00111 current_qe = new_qe;
00112 }
00113
00114 ~queued_event_context()
00115 { current_qe = previous_qe; }
00116 };
00117
00118 game_events::queued_event const *queued_event_context::current_qe = 0;
00119 game_events::queued_event queued_event_context::default_qe
00120 ("_from_lua", map_location(), map_location(), config());
00121
00122
00123 static char const dlgclbkKey = 0;
00124 static char const executeKey = 0;
00125 static char const getsideKey = 0;
00126 static char const gettextKey = 0;
00127 static char const gettypeKey = 0;
00128 static char const getraceKey = 0;
00129 static char const getunitKey = 0;
00130 static char const tstringKey = 0;
00131 static char const unitvarKey = 0;
00132 static char const ustatusKey = 0;
00133 static char const vconfigKey = 0;
00134
00135
00136
00137
00138 static void chat_message(std::string const &caption, std::string const &msg)
00139 {
00140 resources::screen->add_chat_message(time(NULL), caption, 0, msg,
00141 events::chat_handler::MESSAGE_PUBLIC, false);
00142 }
00143
00144
00145
00146
00147 static void luaW_pushvconfig(lua_State *L, vconfig const &cfg)
00148 {
00149 new(lua_newuserdata(L, sizeof(vconfig))) vconfig(cfg);
00150 lua_pushlightuserdata(L
00151 , static_cast<void *>(const_cast<char *>(&vconfigKey)));
00152
00153 lua_rawget(L, LUA_REGISTRYINDEX);
00154 lua_setmetatable(L, -2);
00155 }
00156
00157
00158
00159
00160 static void luaW_pushtstring(lua_State *L, t_string const &v)
00161 {
00162 new(lua_newuserdata(L, sizeof(t_string))) t_string(v);
00163 lua_pushlightuserdata(L
00164 , static_cast<void *>(const_cast<char *>(&tstringKey)));
00165
00166 lua_rawget(L, LUA_REGISTRYINDEX);
00167 lua_setmetatable(L, -2);
00168 }
00169
00170 struct luaW_pushscalar_visitor : boost::static_visitor<>
00171 {
00172 lua_State *L;
00173 luaW_pushscalar_visitor(lua_State *l): L(l) {}
00174 void operator()(boost::blank const &) const
00175 { lua_pushnil(L); }
00176 void operator()(bool b) const
00177 { lua_pushboolean(L, b); }
00178 void operator()(double d) const
00179 { lua_pushnumber(L, d); }
00180 void operator()(size_t s) const
00181 { lua_pushnumber(L,s); }
00182 void operator()(long t) const
00183 { lua_pushnumber(L,t); }
00184 void operator()(int i) const
00185 { lua_pushnumber(L,i); }
00186 void operator()(std::string const &s) const
00187 { lua_pushstring(L, s.c_str()); }
00188 void operator()(t_string const &s) const
00189 { luaW_pushtstring(L, s); }
00190 };
00191
00192
00193
00194
00195 void luaW_pushscalar(lua_State *L, config::attribute_value const &v)
00196 {
00197 boost::apply_visitor(luaW_pushscalar_visitor(L), v.value);
00198 }
00199
00200
00201
00202
00203 static bool luaW_hasmetatable(lua_State *L
00204 , int index
00205 , char const &key)
00206 {
00207 if (!lua_getmetatable(L, index))
00208 return false;
00209 lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&key)));
00210 lua_rawget(L, LUA_REGISTRYINDEX);
00211 bool ok = lua_rawequal(L, -1, -2);
00212 lua_pop(L, 2);
00213 return ok;
00214 }
00215
00216
00217
00218
00219 static bool luaW_totstring(lua_State *L, int index, t_string &str)
00220 {
00221 switch (lua_type(L, index)) {
00222 case LUA_TBOOLEAN:
00223 str = lua_toboolean(L, index) ? "yes" : "no";
00224 break;
00225 case LUA_TNUMBER:
00226 case LUA_TSTRING:
00227 str = lua_tostring(L, index);
00228 break;
00229 case LUA_TUSERDATA:
00230 {
00231 if (!luaW_hasmetatable(L, index, tstringKey)) return false;
00232 str = *static_cast<t_string *>(lua_touserdata(L, index));
00233 break;
00234 }
00235 default:
00236 return false;
00237 }
00238 return true;
00239 }
00240
00241
00242
00243
00244 static t_string luaW_checktstring(lua_State *L, int index)
00245 {
00246 t_string result;
00247 if (!luaW_totstring(L, index, result))
00248 luaL_typerror(L, index, "translatable string");
00249 return result;
00250 }
00251
00252
00253
00254
00255
00256
00257 static void luaW_filltable(lua_State *L, config const &cfg)
00258 {
00259 if (!lua_checkstack(L, LUA_MINSTACK))
00260 return;
00261
00262 int k = 1;
00263 foreach (const config::any_child &ch, cfg.all_children_range())
00264 {
00265 lua_createtable(L, 2, 0);
00266 lua_pushstring(L, ch.key.c_str());
00267 lua_rawseti(L, -2, 1);
00268 lua_newtable(L);
00269 luaW_filltable(L, ch.cfg);
00270 lua_rawseti(L, -2, 2);
00271 lua_rawseti(L, -2, k++);
00272 }
00273 foreach (const config::attribute &attr, cfg.attribute_range())
00274 {
00275 luaW_pushscalar(L, attr.second);
00276 lua_setfield(L, -2, attr.first.c_str());
00277 }
00278 }
00279
00280
00281
00282
00283 void luaW_pushconfig(lua_State *L, config const &cfg)
00284 {
00285 lua_newtable(L);
00286 luaW_filltable(L, cfg);
00287 }
00288
00289 #define return_misformed() \
00290 do { lua_settop(L, initial_top); return false; } while (0)
00291
00292
00293
00294
00295
00296
00297
00298
00299 bool luaW_toconfig(lua_State *L, int index, config &cfg, int tstring_meta)
00300 {
00301 if (!lua_checkstack(L, LUA_MINSTACK))
00302 return false;
00303
00304
00305 int initial_top = lua_gettop(L);
00306 if (-initial_top <= index && index <= -1)
00307 index = initial_top + index + 1;
00308
00309 switch (lua_type(L, index))
00310 {
00311 case LUA_TTABLE:
00312 break;
00313 case LUA_TUSERDATA:
00314 {
00315 if (!luaW_hasmetatable(L, index, vconfigKey))
00316 return false;
00317 cfg = static_cast<vconfig *>(lua_touserdata(L, index))->get_parsed_config();
00318 return true;
00319 }
00320 case LUA_TNONE:
00321 case LUA_TNIL:
00322 return true;
00323 default:
00324 return false;
00325 }
00326
00327
00328 if (!tstring_meta) {
00329 lua_pushlightuserdata(L
00330 , static_cast<void *>(const_cast<char *>(&tstringKey)));
00331
00332 lua_rawget(L, LUA_REGISTRYINDEX);
00333 tstring_meta = initial_top + 1;
00334 }
00335
00336
00337 for (int i = 1, i_end = lua_rawlen(L, index); i <= i_end; ++i)
00338 {
00339 lua_rawgeti(L, index, i);
00340 if (!lua_istable(L, -1)) return_misformed();
00341 lua_rawgeti(L, -1, 1);
00342 char const *m = lua_tostring(L, -1);
00343 if (!m) return_misformed();
00344 lua_rawgeti(L, -2, 2);
00345 if (!luaW_toconfig(L, -1, cfg.add_child(m), tstring_meta))
00346 return_misformed();
00347 lua_pop(L, 3);
00348 }
00349
00350
00351 for (lua_pushnil(L); lua_next(L, index); lua_pop(L, 1))
00352 {
00353 if (lua_isnumber(L, -2)) continue;
00354 if (!lua_isstring(L, -2)) return_misformed();
00355 config::attribute_value &v = cfg[lua_tostring(L, -2)];
00356 switch (lua_type(L, -1)) {
00357 case LUA_TBOOLEAN:
00358 v = bool(lua_toboolean(L, -1));
00359 break;
00360 case LUA_TNUMBER:
00361 v = lua_tonumber(L, -1);
00362 break;
00363 case LUA_TSTRING:
00364 v = lua_tostring(L, -1);
00365 break;
00366 case LUA_TUSERDATA:
00367 {
00368 if (!lua_getmetatable(L, -1)) return_misformed();
00369 bool tstr = lua_rawequal(L, -1, tstring_meta) != 0;
00370 lua_pop(L, 1);
00371 if (!tstr) return_misformed();
00372 v = *static_cast<t_string *>(lua_touserdata(L, -1));
00373 break;
00374 }
00375 default:
00376 return_misformed();
00377 }
00378 }
00379
00380 lua_settop(L, initial_top);
00381 return true;
00382 }
00383
00384 #undef return_misformed
00385
00386
00387
00388
00389 static config luaW_checkconfig(lua_State *L, int index)
00390 {
00391 config result;
00392 if (!luaW_toconfig(L, index, result))
00393 luaL_typerror(L, index, "WML table");
00394 return result;
00395 }
00396
00397
00398
00399
00400
00401 bool luaW_tovconfig(lua_State *L, int index, vconfig &vcfg)
00402 {
00403 switch (lua_type(L, index))
00404 {
00405 case LUA_TTABLE:
00406 {
00407 config cfg;
00408 bool ok = luaW_toconfig(L, index, cfg);
00409 if (!ok) return false;
00410 vcfg = vconfig(cfg, true);
00411 break;
00412 }
00413 case LUA_TUSERDATA:
00414 if (!luaW_hasmetatable(L, index, vconfigKey))
00415 return false;
00416 vcfg = *static_cast<vconfig *>(lua_touserdata(L, index));
00417 break;
00418 case LUA_TNONE:
00419 case LUA_TNIL:
00420 break;
00421 default:
00422 return false;
00423 }
00424 return true;
00425 }
00426
00427
00428
00429
00430
00431
00432 static vconfig luaW_checkvconfig(lua_State *L, int index, bool allow_missing = false)
00433 {
00434 vconfig result = vconfig::unconstructed_vconfig();
00435 if (!luaW_tovconfig(L, index, result) || (!allow_missing && result.null()))
00436 luaL_typerror(L, index, "WML table");
00437 return result;
00438 }
00439
00440 #ifdef _MSC_VER
00441 #pragma warning (push)
00442 #pragma warning (disable: 4706)
00443 #endif
00444
00445
00446
00447
00448
00449 bool luaW_pcall(lua_State *L
00450 , int nArgs, int nRets, bool allow_wml_error)
00451 {
00452
00453 lua_pushlightuserdata(L
00454 , static_cast<void *>(const_cast<char *>(&executeKey)));
00455
00456 lua_rawget(L, LUA_REGISTRYINDEX);
00457 lua_insert(L, -2 - nArgs);
00458
00459 int error_handler_index = lua_gettop(L) - nArgs - 1;
00460
00461
00462 int res = lua_pcall(L, nArgs, nRets, -2 - nArgs);
00463 tlua_jailbreak_exception::rethrow();
00464
00465 if (res)
00466 {
00467
00468
00469
00470
00471 char const *m = lua_tostring(L, -1);
00472 if(m) {
00473 if (allow_wml_error && strncmp(m, "~wml:", 5) == 0) {
00474 m += 5;
00475 char const *e = strstr(m, "stack traceback");
00476 lg::wml_error << std::string(m, e ? e - m : strlen(m));
00477 } else if (allow_wml_error && strncmp(m, "~lua:", 5) == 0) {
00478 m += 5;
00479 char const *e = NULL, *em = m;
00480 while (em[0] && ((em = strstr(em + 1, "stack traceback"))))
00481 #ifdef _MSC_VER
00482 #pragma warning (pop)
00483 #endif
00484 e = em;
00485 chat_message("Lua error", std::string(m, e ? e - m : strlen(m)));
00486 } else {
00487 ERR_LUA << m << '\n';
00488 chat_message("Lua error", m);
00489 }
00490 } else {
00491 chat_message("Lua caught unknown exception", "");
00492 }
00493 lua_pop(L, 2);
00494 return false;
00495 }
00496
00497
00498 lua_remove(L, error_handler_index);
00499
00500 return true;
00501 }
00502
00503
00504
00505
00506
00507
00508 #ifdef __GNUC__
00509 __attribute__((sentinel))
00510 #endif
00511 static bool luaW_getglobal(lua_State *L, ...)
00512 {
00513 lua_pushglobaltable(L);
00514 va_list ap;
00515 va_start(ap, L);
00516 while (const char *s = va_arg(ap, const char *))
00517 {
00518 if (!lua_istable(L, -1)) goto discard;
00519 lua_pushstring(L, s);
00520 lua_rawget(L, -2);
00521 lua_remove(L, -2);
00522 }
00523 va_end(ap);
00524
00525 if (lua_isnil(L, -1)) {
00526 discard:
00527 lua_pop(L, 1);
00528 return false;
00529 }
00530 return true;
00531 }
00532
00533 lua_unit::~lua_unit()
00534 {
00535 delete ptr;
00536 }
00537
00538 unit *lua_unit::get()
00539 {
00540 if (ptr) return ptr;
00541 if (side) {
00542 foreach (unit &u, (*resources::teams)[side - 1].recall_list()) {
00543 if (u.underlying_id() == uid) return &u;
00544 }
00545 return NULL;
00546 }
00547 unit_map::unit_iterator ui = resources::units->find(uid);
00548 if (!ui.valid()) return NULL;
00549 return &*ui;
00550 }
00551
00552
00553
00554
00555 unit *luaW_tounit(lua_State *L, int index, bool only_on_map)
00556 {
00557 if (!luaW_hasmetatable(L, index, getunitKey)) return NULL;
00558 lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, index));
00559 if (only_on_map && !lu->on_map()) return NULL;
00560 return lu->get();
00561 }
00562
00563
00564
00565
00566 static unit *luaW_checkunit(lua_State *L, int index, bool only_on_map = false)
00567 {
00568 unit *u = luaW_tounit(L, index, only_on_map);
00569 if (!u) luaL_typerror(L, index, "unit");
00570 return u;
00571 }
00572
00573
00574
00575
00576
00577
00578
00579 static int impl_gettext(lua_State *L)
00580 {
00581 char const *m = luaL_checkstring(L, 2);
00582 char const *d = static_cast<char *>(lua_touserdata(L, 1));
00583
00584 luaW_pushtstring(L, t_string(m, d));
00585 return 1;
00586 }
00587
00588
00589
00590
00591
00592
00593 static int intf_textdomain(lua_State *L)
00594 {
00595 size_t l;
00596 char const *m = luaL_checklstring(L, 1, &l);
00597 void *p = lua_newuserdata(L, l + 1);
00598 memcpy(p, m, l + 1);
00599 lua_pushlightuserdata(L
00600 , static_cast<void *>(const_cast<char *>(&gettextKey)));
00601
00602 lua_rawget(L, LUA_REGISTRYINDEX);
00603 lua_setmetatable(L, -2);
00604 return 1;
00605 }
00606
00607
00608
00609
00610
00611
00612
00613
00614 static void tstring_concat_aux(lua_State *L, t_string &dst, int src)
00615 {
00616 switch (lua_type(L, src)) {
00617 case LUA_TNUMBER:
00618 case LUA_TSTRING:
00619 dst += lua_tostring(L, src);
00620 break;
00621 case LUA_TUSERDATA:
00622
00623 if (!lua_getmetatable(L, src) || !lua_rawequal(L, -1, -2))
00624 luaL_typerror(L, src, "string");
00625 dst += *static_cast<t_string *>(lua_touserdata(L, src));
00626 lua_pop(L, 1);
00627 break;
00628 default:
00629 luaL_typerror(L, src, "string");
00630 }
00631 }
00632
00633
00634
00635
00636 static int impl_tstring_concat(lua_State *L)
00637 {
00638
00639 t_string *t = new(lua_newuserdata(L, sizeof(t_string))) t_string;
00640
00641 lua_pushlightuserdata(L
00642 , static_cast<void *>(const_cast<char *>(&tstringKey)));
00643
00644 lua_rawget(L, LUA_REGISTRYINDEX);
00645
00646
00647 tstring_concat_aux(L, *t, 1);
00648 tstring_concat_aux(L, *t, 2);
00649
00650 lua_setmetatable(L, -2);
00651 return 1;
00652 }
00653
00654
00655
00656
00657 static int impl_tstring_collect(lua_State *L)
00658 {
00659 t_string *t = static_cast<t_string *>(lua_touserdata(L, 1));
00660 t->t_string::~t_string();
00661 return 0;
00662 }
00663
00664
00665
00666
00667
00668 static int impl_tstring_tostring(lua_State *L)
00669 {
00670 t_string *t = static_cast<t_string *>(lua_touserdata(L, 1));
00671 lua_pushstring(L, t->c_str());
00672 return 1;
00673 }
00674
00675
00676
00677
00678
00679
00680 static int impl_vconfig_get(lua_State *L)
00681 {
00682 vconfig *v = static_cast<vconfig *>(lua_touserdata(L, 1));
00683
00684 if (lua_isnumber(L, 2))
00685 {
00686 vconfig::all_children_iterator i = v->ordered_begin();
00687 unsigned len = std::distance(i, v->ordered_end());
00688 unsigned pos = lua_tointeger(L, 2) - 1;
00689 if (pos >= len) return 0;
00690 std::advance(i, pos);
00691 lua_createtable(L, 2, 0);
00692 lua_pushstring(L, i.get_key().c_str());
00693 lua_rawseti(L, -2, 1);
00694 new(lua_newuserdata(L, sizeof(vconfig))) vconfig(i.get_child());
00695 lua_pushlightuserdata(L
00696 , static_cast<void *>(const_cast<char *>(&vconfigKey)));
00697
00698 lua_rawget(L, LUA_REGISTRYINDEX);
00699 lua_setmetatable(L, -2);
00700 lua_rawseti(L, -2, 2);
00701 return 1;
00702 }
00703
00704 char const *m = luaL_checkstring(L, 2);
00705 if (strcmp(m, "__literal") == 0) {
00706 luaW_pushconfig(L, v->get_config());
00707 return 1;
00708 }
00709 if (strcmp(m, "__parsed") == 0) {
00710 luaW_pushconfig(L, v->get_parsed_config());
00711 return 1;
00712 }
00713
00714 bool shallow_literal = strcmp(m, "__shallow_literal") == 0;
00715 if (shallow_literal || strcmp(m, "__shallow_parsed") == 0)
00716 {
00717 lua_newtable(L);
00718 foreach (const config::attribute &a, v->get_config().attribute_range()) {
00719 if (shallow_literal)
00720 luaW_pushscalar(L, a.second);
00721 else
00722 luaW_pushscalar(L, v->expand(a.first));
00723 lua_setfield(L, -2, a.first.c_str());
00724 }
00725 vconfig::all_children_iterator i = v->ordered_begin(),
00726 i_end = v->ordered_end();
00727 if (shallow_literal) {
00728 i.disable_insertion();
00729 i_end.disable_insertion();
00730 }
00731 for (int j = 1; i != i_end; ++i, ++j)
00732 {
00733 lua_createtable(L, 2, 0);
00734 lua_pushstring(L, i.get_key().c_str());
00735 lua_rawseti(L, -2, 1);
00736 luaW_pushvconfig(L, i.get_child());
00737 lua_rawseti(L, -2, 2);
00738 lua_rawseti(L, -2, j);
00739 }
00740 return 1;
00741 }
00742
00743 if (v->null() || !v->has_attribute(m)) return 0;
00744 luaW_pushscalar(L, (*v)[m]);
00745 return 1;
00746 }
00747
00748
00749
00750
00751 static int impl_vconfig_size(lua_State *L)
00752 {
00753 vconfig *v = static_cast<vconfig *>(lua_touserdata(L, 1));
00754 lua_pushinteger(L, v->null() ? 0 :
00755 std::distance(v->ordered_begin(), v->ordered_end()));
00756 return 1;
00757 }
00758
00759
00760
00761
00762 static int impl_vconfig_collect(lua_State *L)
00763 {
00764 vconfig *v = static_cast<vconfig *>(lua_touserdata(L, 1));
00765 v->vconfig::~vconfig();
00766 return 0;
00767 }
00768
00769 #define return_tstring_attrib(name, accessor) \
00770 if (strcmp(m, name) == 0) { \
00771 luaW_pushtstring(L, accessor); \
00772 return 1; \
00773 }
00774
00775 #define return_cstring_attrib(name, accessor) \
00776 if (strcmp(m, name) == 0) { \
00777 lua_pushstring(L, accessor); \
00778 return 1; \
00779 }
00780
00781 #define return_string_attrib(name, accessor) \
00782 return_cstring_attrib(name, accessor.c_str())
00783
00784 #define return_int_attrib(name, accessor) \
00785 if (strcmp(m, name) == 0) { \
00786 lua_pushinteger(L, accessor); \
00787 return 1; \
00788 }
00789
00790 #define return_float_attrib(name, accessor) \
00791 if (strcmp(m, name) == 0) { \
00792 lua_pushnumber(L, accessor); \
00793 return 1; \
00794 }
00795
00796 #define return_bool_attrib(name, accessor) \
00797 if (strcmp(m, name) == 0) { \
00798 lua_pushboolean(L, accessor); \
00799 return 1; \
00800 }
00801
00802 #define return_cfg_attrib(name, accessor) \
00803 if (strcmp(m, name) == 0) { \
00804 config cfg; \
00805 accessor; \
00806 luaW_pushconfig(L, cfg); \
00807 return 1; \
00808 }
00809
00810 #define return_cfgref_attrib(name, accessor) \
00811 if (strcmp(m, name) == 0) { \
00812 luaW_pushconfig(L, accessor); \
00813 return 1; \
00814 }
00815
00816 #define return_vector_string_attrib(name, accessor) \
00817 if (strcmp(m, name) == 0) { \
00818 const std::vector<std::string>& vector = accessor; \
00819 lua_createtable(L, vector.size(), 0); \
00820 int i = 1; \
00821 foreach (const std::string& s, vector) { \
00822 lua_pushstring(L, s.c_str()); \
00823 lua_rawseti(L, -2, i); \
00824 ++i; \
00825 } \
00826 return 1; \
00827 }
00828
00829 #define modify_tstring_attrib(name, accessor) \
00830 if (strcmp(m, name) == 0) { \
00831 t_string value = luaW_checktstring(L, 3); \
00832 accessor; \
00833 return 0; \
00834 }
00835
00836 #define modify_string_attrib(name, accessor) \
00837 if (strcmp(m, name) == 0) { \
00838 const char *value = luaL_checkstring(L, 3); \
00839 accessor; \
00840 return 0; \
00841 }
00842
00843 #define modify_int_attrib(name, accessor) \
00844 if (strcmp(m, name) == 0) { \
00845 int value = luaL_checkinteger(L, 3); \
00846 accessor; \
00847 return 0; \
00848 }
00849
00850 #define modify_int_attrib_check_range(name, accessor, allowed_min, allowed_max) \
00851 if (strcmp(m, name) == 0) { \
00852 int value = luaL_checkinteger(L, 3); \
00853 if (value < allowed_min || allowed_max < value) return luaL_argerror(L, 3, "out of bounds"); \
00854 accessor; \
00855 return 0; \
00856 }
00857
00858 #define modify_bool_attrib(name, accessor) \
00859 if (strcmp(m, name) == 0) { \
00860 bool value = lua_toboolean(L, 3); \
00861 accessor; \
00862 return 0; \
00863 }
00864
00865 #define modify_vector_string_attrib(name, accessor) \
00866 if (strcmp(m, name) == 0) { \
00867 std::vector<std::string> vector; \
00868 char const* message = "table with unnamed indices holding strings expected"; \
00869 if (!lua_istable(L, 3)) return luaL_argerror(L, 3, message); \
00870 unsigned length = lua_rawlen(L, 3); \
00871 for (unsigned i = 1; i <= length; ++i) { \
00872 lua_rawgeti(L, 3, i); \
00873 char const* string = lua_tostring(L, 4); \
00874 if(!string) return luaL_argerror(L, 2 + i, message); \
00875 vector.push_back(string); \
00876 lua_pop(L, 1); \
00877 } \
00878 accessor; \
00879 return 0; \
00880 }
00881
00882
00883
00884
00885
00886
00887
00888 static int impl_unit_type_get(lua_State *L)
00889 {
00890 char const *m = luaL_checkstring(L, 2);
00891 lua_pushstring(L, "id");
00892 lua_rawget(L, 1);
00893 const unit_type *utp = unit_types.find(lua_tostring(L, -1));
00894 if (!utp) return luaL_argerror(L, 1, "unknown unit type");
00895 unit_type const &ut = *utp;
00896
00897
00898 return_tstring_attrib("name", ut.type_name());
00899 return_int_attrib("max_hitpoints", ut.hitpoints());
00900 return_int_attrib("max_moves", ut.movement());
00901 return_int_attrib("max_experience", ut.experience_needed());
00902 return_int_attrib("cost", ut.cost());
00903 return_int_attrib("level", ut.level());
00904 return_cfgref_attrib("__cfg", ut.get_cfg());
00905 return 0;
00906 }
00907
00908
00909
00910
00911
00912
00913
00914 static int impl_race_get(lua_State* L)
00915 {
00916 char const* m = luaL_checkstring(L, 2);
00917 lua_pushstring(L, "id");
00918 lua_rawget(L, 1);
00919 const unit_race* raceptr = unit_types.find_race(lua_tostring(L, -1));
00920 if(!raceptr) return luaL_argerror(L, 1, "unknown race");
00921 unit_race const &race = *raceptr;
00922
00923 return_tstring_attrib("description", race.description());
00924 return_tstring_attrib("name", race.name());
00925 return_int_attrib("num_traits", race.num_traits());
00926 return_tstring_attrib("plural_name", race.plural_name());
00927 return_bool_attrib("ignore_global_traits", !race.uses_global_traits());
00928 return_string_attrib("undead_variation", race.undead_variation());
00929 return_cfgref_attrib("__cfg", race.get_cfg());
00930
00931 return 0;
00932 }
00933
00934
00935
00936
00937 static int impl_unit_collect(lua_State *L)
00938 {
00939 lua_unit *u = static_cast<lua_unit *>(lua_touserdata(L, 1));
00940 u->lua_unit::~lua_unit();
00941 return 0;
00942 }
00943
00944
00945
00946
00947
00948
00949
00950 static int impl_unit_get(lua_State *L)
00951 {
00952 lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, 1));
00953 char const *m = luaL_checkstring(L, 2);
00954 unit const *pu = lu->get();
00955
00956 if (strcmp(m, "valid") == 0)
00957 {
00958 if (!pu) return 0;
00959 if (lu->on_map())
00960 lua_pushstring(L, "map");
00961 else if (lu->on_recall_list())
00962 lua_pushstring(L, "recall");
00963 else
00964 lua_pushstring(L, "private");
00965 return 1;
00966 }
00967
00968 if (!pu) return luaL_argerror(L, 1, "unknown unit");
00969 unit const &u = *pu;
00970
00971
00972 return_int_attrib("x", u.get_location().x + 1);
00973 return_int_attrib("y", u.get_location().y + 1);
00974 if (strcmp(m, "loc") == 0) {
00975 lua_pushinteger(L, u.get_location().x + 1);
00976 lua_pushinteger(L, u.get_location().y + 1);
00977 return 2;
00978 }
00979 return_int_attrib("side", u.side());
00980 return_string_attrib("id", u.id());
00981 return_string_attrib("type", u.type_id());
00982 return_string_attrib("image_mods", u.effect_image_mods());
00983 return_int_attrib("hitpoints", u.hitpoints());
00984 return_int_attrib("max_hitpoints", u.max_hitpoints());
00985 return_int_attrib("experience", u.experience());
00986 return_int_attrib("max_experience", u.max_experience());
00987 return_int_attrib("moves", u.movement_left());
00988 return_int_attrib("max_moves", u.total_movement());
00989 return_int_attrib("max_attacks", u.max_attacks());
00990 return_int_attrib("attacks_left", u.attacks_left());
00991 return_tstring_attrib("name", u.name());
00992 return_bool_attrib("canrecruit", u.can_recruit());
00993
00994 return_vector_string_attrib("extra_recruit", u.recruits());
00995 return_vector_string_attrib("advances_to", u.advances_to());
00996
00997 if (strcmp(m, "status") == 0) {
00998 lua_createtable(L, 1, 0);
00999 lua_pushvalue(L, 1);
01000 lua_rawseti(L, -2, 1);
01001 lua_pushlightuserdata(L
01002 , static_cast<void *>(const_cast<char *>(&ustatusKey)));
01003 lua_rawget(L, LUA_REGISTRYINDEX);
01004 lua_setmetatable(L, -2);
01005 return 1;
01006 }
01007 if (strcmp(m, "variables") == 0) {
01008 lua_createtable(L, 1, 0);
01009 lua_pushvalue(L, 1);
01010 lua_rawseti(L, -2, 1);
01011 lua_pushlightuserdata(L
01012 , static_cast<void *>(const_cast<char *>(&unitvarKey)));
01013 lua_rawget(L, LUA_REGISTRYINDEX);
01014 lua_setmetatable(L, -2);
01015 return 1;
01016 }
01017 return_bool_attrib("hidden", u.get_hidden());
01018 return_bool_attrib("petrified", u.incapacitated());
01019 return_bool_attrib("resting", u.resting());
01020 return_string_attrib("role", u.get_role());
01021 return_string_attrib("facing", map_location::write_direction(u.facing()));
01022 return_cfg_attrib("__cfg", u.write(cfg); u.get_location().write(cfg));
01023 return 0;
01024 }
01025
01026
01027
01028
01029
01030
01031
01032 static int impl_unit_set(lua_State *L)
01033 {
01034 lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, 1));
01035 char const *m = luaL_checkstring(L, 2);
01036 unit *pu = lu->get();
01037 if (!pu) return luaL_argerror(L, 1, "unknown unit");
01038 unit &u = *pu;
01039
01040
01041 modify_int_attrib_check_range("side", u.set_side(value), 1, static_cast<int>(resources::teams->size()));
01042 modify_int_attrib("moves", u.set_movement(value));
01043 modify_int_attrib("hitpoints", u.set_hitpoints(value));
01044 modify_int_attrib("experience", u.set_experience(value));
01045 modify_int_attrib("attacks_left", u.set_attacks(value));
01046 modify_bool_attrib("resting", u.set_resting(value));
01047 modify_tstring_attrib("name", u.set_name(value));
01048 modify_string_attrib("role", u.set_role(value));
01049 modify_string_attrib("facing", u.set_facing(map_location::parse_direction(value)));
01050 modify_bool_attrib("hidden", u.set_hidden(value));
01051
01052 modify_vector_string_attrib("extra_recruit", u.set_recruits(vector));
01053 modify_vector_string_attrib("advances_to", u.set_advances_to(vector));
01054
01055 if (!lu->on_map()) {
01056 map_location loc = u.get_location();
01057 modify_int_attrib("x", loc.x = value - 1; u.set_location(loc));
01058 modify_int_attrib("y", loc.y = value - 1; u.set_location(loc));
01059 }
01060
01061 return luaL_argerror(L, 2, "unknown modifiable property");
01062 }
01063
01064
01065
01066
01067
01068
01069
01070 static int impl_unit_status_get(lua_State *L)
01071 {
01072 if (!lua_istable(L, 1))
01073 return luaL_typerror(L, 1, "unit status");
01074 lua_rawgeti(L, 1, 1);
01075 unit const *u = luaW_tounit(L, -1);
01076 if (!u) return luaL_argerror(L, 1, "unknown unit");
01077 char const *m = luaL_checkstring(L, 2);
01078 lua_pushboolean(L, u->get_state(m));
01079 return 1;
01080 }
01081
01082
01083
01084
01085
01086
01087
01088 static int impl_unit_status_set(lua_State *L)
01089 {
01090 if (!lua_istable(L, 1))
01091 return luaL_typerror(L, 1, "unit status");
01092 lua_rawgeti(L, 1, 1);
01093 unit *u = luaW_tounit(L, -1);
01094 if (!u) return luaL_argerror(L, 1, "unknown unit");
01095 char const *m = luaL_checkstring(L, 2);
01096 u->set_state(m, lua_toboolean(L, 3));
01097 return 0;
01098 }
01099
01100
01101
01102
01103
01104
01105
01106 static int impl_unit_variables_get(lua_State *L)
01107 {
01108 if (!lua_istable(L, 1))
01109 return luaL_typerror(L, 1, "unit variables");
01110 lua_rawgeti(L, 1, 1);
01111 unit const *u = luaW_tounit(L, -1);
01112 if (!u) return luaL_argerror(L, 1, "unknown unit");
01113 char const *m = luaL_checkstring(L, 2);
01114 return_cfgref_attrib("__cfg", u->variables());
01115 luaW_pushscalar(L, u->variables()[m]);
01116 return 1;
01117 }
01118
01119
01120
01121
01122
01123
01124
01125 static int impl_unit_variables_set(lua_State *L)
01126 {
01127 if (!lua_istable(L, 1))
01128 return luaL_typerror(L, 1, "unit variables");
01129 lua_rawgeti(L, 1, 1);
01130 unit *u = luaW_tounit(L, -1);
01131 if (!u) return luaL_argerror(L, 1, "unknown unit");
01132 char const *m = luaL_checkstring(L, 2);
01133 if (strcmp(m, "__cfg") == 0) {
01134 u->variables() = luaW_checkconfig(L, 3);
01135 return 0;
01136 }
01137 config::attribute_value &v = u->variables()[m];
01138 switch (lua_type(L, 3)) {
01139 case LUA_TNIL:
01140 u->variables().remove_attribute(m);
01141 break;
01142 case LUA_TBOOLEAN:
01143 v = bool(lua_toboolean(L, 3));
01144 break;
01145 case LUA_TNUMBER:
01146 v = lua_tonumber(L, 3);
01147 break;
01148 case LUA_TSTRING:
01149 v = lua_tostring(L, 3);
01150 break;
01151 case LUA_TUSERDATA:
01152 if (luaW_hasmetatable(L, 3, tstringKey)) {
01153 v = *static_cast<t_string *>(lua_touserdata(L, 3));
01154 break;
01155 }
01156
01157 default:
01158 return luaL_typerror(L, 3, "WML scalar");
01159 }
01160 return 0;
01161 }
01162
01163
01164
01165
01166
01167
01168
01169
01170 static int intf_get_unit(lua_State *L)
01171 {
01172 int x = luaL_checkinteger(L, 1) - 1;
01173 int y = luaL_optint(L, 2, 0) - 1;
01174
01175 unit_map &units = *resources::units;
01176 unit_map::const_iterator ui;
01177
01178 if (lua_isnoneornil(L, 2)) {
01179 ui = units.find(x + 1);
01180 } else {
01181 ui = units.find(map_location(x, y));
01182 }
01183
01184 if (!ui.valid()) return 0;
01185
01186 new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(ui->underlying_id());
01187 lua_pushlightuserdata(L
01188 , static_cast<void *>(const_cast<char *>(&getunitKey)));
01189 lua_rawget(L, LUA_REGISTRYINDEX);
01190 lua_setmetatable(L, -2);
01191 return 1;
01192 }
01193
01194
01195
01196
01197
01198
01199 static int intf_get_displayed_unit(lua_State *L)
01200 {
01201 unit_map::const_iterator ui = find_visible_unit(
01202 resources::screen->displayed_unit_hex(),
01203 (*resources::teams)[resources::screen->viewing_team()],
01204 resources::screen->show_everything());
01205 if (!ui.valid()) return 0;
01206
01207 new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(ui->underlying_id());
01208 lua_pushlightuserdata(L
01209 , static_cast<void *>(const_cast<char *>(&getunitKey)));
01210 lua_rawget(L, LUA_REGISTRYINDEX);
01211 lua_setmetatable(L, -2);
01212 return 1;
01213 }
01214
01215
01216
01217
01218
01219
01220
01221 static int intf_get_units(lua_State *L)
01222 {
01223 vconfig filter = luaW_checkvconfig(L, 1, true);
01224
01225
01226
01227 lua_settop(L, 0);
01228 lua_pushlightuserdata(L
01229 , static_cast<void *>(const_cast<char *>(&getunitKey)));
01230 lua_rawget(L, LUA_REGISTRYINDEX);
01231 lua_newtable(L);
01232 int i = 1;
01233 unit_map &units = *resources::units;
01234 for (unit_map::const_unit_iterator ui = units.begin(), ui_end = units.end();
01235 ui != ui_end; ++ui)
01236 {
01237 if (!filter.null() && !ui->matches_filter(filter, ui->get_location()))
01238 continue;
01239 new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(ui->underlying_id());
01240 lua_pushvalue(L, 1);
01241 lua_setmetatable(L, 3);
01242 lua_rawseti(L, 2, i);
01243 ++i;
01244 }
01245 return 1;
01246 }
01247
01248
01249
01250
01251
01252
01253
01254 static int intf_match_unit(lua_State *L)
01255 {
01256 if (!luaW_hasmetatable(L, 1, getunitKey))
01257 return luaL_typerror(L, 1, "unit");
01258
01259 lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, 1));
01260 unit *u = lu->get();
01261 if (!u) return luaL_argerror(L, 1, "unit not found");
01262
01263 vconfig filter = luaW_checkvconfig(L, 2, true);
01264
01265 if (filter.null()) {
01266 lua_pushboolean(L, true);
01267 return 1;
01268 }
01269
01270 if (int side = lu->on_recall_list()) {
01271 team &t = (*resources::teams)[side - 1];
01272 scoped_recall_unit auto_store("this_unit",
01273 t.save_id(), u - &t.recall_list()[0]);
01274 lua_pushboolean(L, u->matches_filter(filter, map_location()));
01275 return 1;
01276 }
01277
01278 lua_pushboolean(L, u->matches_filter(filter, u->get_location()));
01279 return 1;
01280 }
01281
01282
01283
01284
01285
01286
01287
01288 static int intf_get_recall_units(lua_State *L)
01289 {
01290 vconfig filter = luaW_checkvconfig(L, 1, true);
01291
01292
01293
01294 lua_settop(L, 0);
01295 lua_pushlightuserdata(L
01296 , static_cast<void *>(const_cast<char *>(&getunitKey)));
01297 lua_rawget(L, LUA_REGISTRYINDEX);
01298 lua_newtable(L);
01299 int i = 1, s = 1;
01300 foreach (team &t, *resources::teams)
01301 {
01302 foreach (unit &u, t.recall_list())
01303 {
01304 if (!filter.null()) {
01305 scoped_recall_unit auto_store("this_unit",
01306 t.save_id(), &u - &t.recall_list()[0]);
01307 if (!u.matches_filter(filter, map_location()))
01308 continue;
01309 }
01310 new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(s, u.underlying_id());
01311 lua_pushvalue(L, 1);
01312 lua_setmetatable(L, 3);
01313 lua_rawseti(L, 2, i);
01314 ++i;
01315 }
01316 ++s;
01317 }
01318 return 1;
01319 }
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330 static int intf_fire_event(lua_State *L)
01331 {
01332 char const *m = luaL_checkstring(L, 1);
01333
01334 int pos = 2;
01335 map_location l1, l2;
01336 config data;
01337
01338 if (lua_isnumber(L, 2)) {
01339 l1.x = lua_tointeger(L, 2) - 1;
01340 l1.y = luaL_checkinteger(L, 3) - 1;
01341 if (lua_isnumber(L, 4)) {
01342 l2.x = lua_tointeger(L, 4) - 1;
01343 l2.y = luaL_checkinteger(L, 5) - 1;
01344 pos = 6;
01345 } else pos = 4;
01346 }
01347
01348 if (!lua_isnoneornil(L, pos)) {
01349 data.add_child("first", luaW_checkconfig(L, pos));
01350 }
01351 ++pos;
01352 if (!lua_isnoneornil(L, pos)) {
01353 data.add_child("second", luaW_checkconfig(L, pos));
01354 }
01355
01356 bool b = game_events::fire(m, l1, l2, data);
01357 lua_pushboolean(L, b);
01358 return 1;
01359 }
01360
01361
01362
01363
01364
01365
01366
01367 static int intf_get_variable(lua_State *L)
01368 {
01369 char const *m = luaL_checkstring(L, 1);
01370 variable_info v(m, false, variable_info::TYPE_SCALAR);
01371 if (v.is_valid) {
01372 luaW_pushscalar(L, v.as_scalar());
01373 return 1;
01374 } else {
01375 variable_info w(m, false, variable_info::TYPE_CONTAINER);
01376 if (w.is_valid) {
01377 lua_newtable(L);
01378 if (lua_toboolean(L, 2))
01379 luaW_filltable(L, w.as_container());
01380 return 1;
01381 }
01382 }
01383 return 0;
01384 }
01385
01386
01387
01388
01389
01390
01391 static int intf_set_variable(lua_State *L)
01392 {
01393 const std::string& m = luaL_checkstring(L, 1);
01394 if(m.empty()) return luaL_argerror(L, 1, "empty variable name");
01395 if (lua_isnoneornil(L, 2)) {
01396 resources::state_of_game->clear_variable(m);
01397 return 0;
01398 }
01399
01400 variable_info v(m);
01401 switch (lua_type(L, 2)) {
01402 case LUA_TBOOLEAN:
01403 v.as_scalar() = bool(lua_toboolean(L, 2));
01404 break;
01405 case LUA_TNUMBER:
01406 v.as_scalar() = lua_tonumber(L, 2);
01407 break;
01408 case LUA_TSTRING:
01409 v.as_scalar() = lua_tostring(L, 2);
01410 break;
01411 case LUA_TUSERDATA:
01412 if (luaW_hasmetatable(L, 2, tstringKey)) {
01413 v.as_scalar() = *static_cast<t_string *>(lua_touserdata(L, 2));
01414 break;
01415 }
01416
01417 case LUA_TTABLE:
01418 {
01419 config &cfg = v.as_container();
01420 cfg.clear();
01421 if (luaW_toconfig(L, 2, cfg))
01422 break;
01423
01424 }
01425 default:
01426 return luaL_typerror(L, 2, "WML table or scalar");
01427 }
01428 return 0;
01429 }
01430
01431
01432
01433
01434
01435
01436 static int intf_dofile(lua_State *L)
01437 {
01438 char const *m = luaL_checkstring(L, 1);
01439 std::string p = get_wml_location(m);
01440 if (p.empty())
01441 return luaL_argerror(L, 1, "file not found");
01442
01443 lua_settop(L, 0);
01444 if (luaL_loadfile(L, p.c_str()))
01445 return lua_error(L);
01446
01447 lua_call(L, 0, LUA_MULTRET);
01448 return lua_gettop(L);
01449 }
01450
01451
01452
01453
01454
01455
01456
01457 static int intf_require(lua_State *L)
01458 {
01459 char const *m = luaL_checkstring(L, 1);
01460
01461
01462 luaW_getglobal(L, "wesnoth", NULL);
01463 lua_pushstring(L, "package");
01464 lua_rawget(L, -2);
01465 lua_pushvalue(L, 1);
01466 lua_rawget(L, -2);
01467 if (!lua_isnil(L, -1)) return 1;
01468 lua_pop(L, 1);
01469
01470 std::string p = get_wml_location(m);
01471 if (p.empty())
01472 return luaL_argerror(L, 1, "file not found");
01473
01474
01475 int res = luaL_loadfile(L, p.c_str());
01476 if (res)
01477 {
01478 char const *m = lua_tostring(L, -1);
01479 chat_message("Lua error", m);
01480 ERR_LUA << m << '\n';
01481 return 0;
01482 }
01483
01484
01485 if (!luaW_pcall(L, 0, 1)) return 0;
01486
01487
01488 lua_pushvalue(L, 1);
01489 lua_pushvalue(L, -2);
01490 lua_settable(L, -4);
01491 return 1;
01492 }
01493
01494
01495
01496
01497
01498 static int intf_highlight_hex(lua_State *L)
01499 {
01500 ERR_LUA << "wesnoth.highlight_hex is deprecated, use wesnoth.select_hex\n";
01501
01502 int x = luaL_checkinteger(L, 1) - 1;
01503 int y = luaL_checkinteger(L, 2) - 1;
01504 const map_location loc(x, y);
01505 resources::screen->highlight_hex(loc);
01506 resources::screen->display_unit_hex(loc);
01507
01508 unit_map::const_unit_iterator i = resources::units->find(loc);
01509 if(i != resources::units->end()) {
01510 resources::screen->highlight_reach(pathfind::paths(
01511 *resources::game_map, *resources::units, *i, *resources::teams, false,
01512 (*i).get_ability_bool("teleport"), resources::teams->front()));
01513 }
01514
01515 return 0;
01516 }
01517
01518
01519
01520
01521
01522
01523 static int intf_is_enemy(lua_State *L)
01524 {
01525 unsigned side_1 = luaL_checkint(L, 1) - 1;
01526 unsigned side_2 = luaL_checkint(L, 2) - 1;
01527 std::vector<team> &teams = *resources::teams;
01528 if (side_1 >= teams.size() || side_2 >= teams.size()) return 0;
01529 lua_pushboolean(L, teams[side_1].is_enemy(side_2 + 1));
01530 return 1;
01531 }
01532
01533
01534
01535
01536
01537
01538
01539 static int impl_side_get(lua_State *L)
01540 {
01541
01542 team &t = **static_cast<team **>(lua_touserdata(L, 1));
01543 char const *m = luaL_checkstring(L, 2);
01544
01545
01546 return_int_attrib("side", t.side());
01547 return_int_attrib("gold", t.gold());
01548 return_tstring_attrib("objectives", t.objectives());
01549 return_int_attrib("village_gold", t.village_gold());
01550 return_int_attrib("recall_cost", t.recall_cost());
01551 return_int_attrib("base_income", t.base_income());
01552 return_int_attrib("total_income", t.total_income());
01553 return_bool_attrib("objectives_changed", t.objectives_changed());
01554 return_bool_attrib("fog", t.uses_fog());
01555 return_bool_attrib("shroud", t.uses_shroud());
01556 return_bool_attrib("hidden", t.hidden());
01557 return_tstring_attrib("user_team_name", t.user_team_name());
01558 return_string_attrib("team_name", t.team_name());
01559 return_string_attrib("name", t.name());
01560 return_string_attrib("color", t.color());
01561 return_cstring_attrib("controller", t.controller_string());
01562
01563 if (strcmp(m, "recruit") == 0) {
01564 std::set<std::string> const &recruits = t.recruits();
01565 lua_createtable(L, recruits.size(), 0);
01566 int i = 1;
01567 foreach (std::string const &r, t.recruits()) {
01568 lua_pushstring(L, r.c_str());
01569 lua_rawseti(L, -2, i++);
01570 }
01571 return 1;
01572 }
01573
01574 return_cfg_attrib("__cfg", t.write(cfg));
01575 return 0;
01576 }
01577
01578
01579
01580
01581
01582
01583
01584 static int impl_side_set(lua_State *L)
01585 {
01586
01587 team &t = **static_cast<team **>(lua_touserdata(L, 1));
01588 char const *m = luaL_checkstring(L, 2);
01589
01590
01591 modify_int_attrib("gold", t.set_gold(value));
01592 modify_tstring_attrib("objectives", t.set_objectives(value, true));
01593 modify_int_attrib("village_gold", t.set_village_gold(value));
01594 modify_int_attrib("recall_cost", t.set_recall_cost(value));
01595 modify_int_attrib("base_income", t.set_base_income(value));
01596 modify_bool_attrib("objectives_changed", t.set_objectives_changed(value));
01597 modify_tstring_attrib("user_team_name", t.change_team(t.team_name(), value));
01598 modify_string_attrib("team_name", t.change_team(value, t.user_team_name()));
01599 modify_string_attrib("controller", t.change_controller(value));
01600 modify_string_attrib("color", t.set_color(value));
01601
01602 if (strcmp(m, "recruit") == 0) {
01603 t.set_recruits(std::set<std::string>());
01604 if (!lua_istable(L, 3)) return 0;
01605 for (int i = 1;; ++i) {
01606 lua_rawgeti(L, 3, i);
01607 if (lua_isnil(L, -1)) break;
01608 t.add_recruit(lua_tostring(L, -1));
01609 lua_pop(L, 1);
01610 }
01611 return 0;
01612 }
01613
01614 return luaL_argerror(L, 2, "unknown modifiable property");
01615 }
01616
01617
01618
01619
01620
01621
01622 static int intf_get_terrain(lua_State *L)
01623 {
01624 int x = luaL_checkint(L, 1);
01625 int y = luaL_checkint(L, 2);
01626
01627 t_translation::t_terrain const &t = resources::game_map->
01628 get_terrain(map_location(x - 1, y - 1));
01629 lua_pushstring(L, t_translation::write_terrain_code(t).c_str());
01630 return 1;
01631 }
01632
01633
01634
01635
01636
01637
01638
01639
01640 static int intf_set_terrain(lua_State *L)
01641 {
01642 int x = luaL_checkint(L, 1);
01643 int y = luaL_checkint(L, 2);
01644 t_translation::t_terrain terrain = t_translation::read_terrain_code(luaL_checkstring(L, 3));
01645 if (terrain == t_translation::NONE_TERRAIN) return 0;
01646
01647 gamemap::tmerge_mode mode = gamemap::BOTH;
01648 bool replace_if_failed = false;
01649 if (!lua_isnone(L, 4)) {
01650 if (!lua_isnil(L, 4)) {
01651 const char* const layer = luaL_checkstring(L, 4);
01652 if (strcmp(layer, "base") == 0) mode = gamemap::BASE;
01653 else if (strcmp(layer, "overlay") == 0) mode = gamemap::OVERLAY;
01654 }
01655
01656 if(!lua_isnoneornil(L, 5)) {
01657 replace_if_failed = lua_toboolean(L, 5);
01658 }
01659 }
01660
01661 change_terrain(map_location(x - 1, y - 1), terrain, mode, replace_if_failed);
01662 return 0;
01663 }
01664
01665
01666
01667
01668
01669
01670 static int intf_get_terrain_info(lua_State *L)
01671 {
01672 char const *m = luaL_checkstring(L, 1);
01673 t_translation::t_terrain t = t_translation::read_terrain_code(m);
01674 if (t == t_translation::NONE_TERRAIN) return 0;
01675 terrain_type const &info = resources::game_map->get_terrain_info(t);
01676
01677 lua_newtable(L);
01678 lua_pushstring(L, info.id().c_str());
01679 lua_setfield(L, -2, "id");
01680 luaW_pushtstring(L, info.name());
01681 lua_setfield(L, -2, "name");
01682 luaW_pushtstring(L, info.editor_name());
01683 lua_setfield(L, -2, "editor_name");
01684 luaW_pushtstring(L, info.description());
01685 lua_setfield(L, -2, "description");
01686 lua_pushboolean(L, info.is_village());
01687 lua_setfield(L, -2, "village");
01688 lua_pushboolean(L, info.is_castle());
01689 lua_setfield(L, -2, "castle");
01690 lua_pushboolean(L, info.is_keep());
01691 lua_setfield(L, -2, "keep");
01692 lua_pushinteger(L, info.gives_healing());
01693 lua_setfield(L, -2, "healing");
01694
01695 return 1;
01696 }
01697
01698
01699
01700
01701
01702
01703
01704 static int intf_get_time_of_day(lua_State *L)
01705 {
01706 unsigned arg = 1;
01707
01708 int for_turn = resources::tod_manager->turn();
01709 map_location loc = map_location();
01710 bool consider_illuminates = false;
01711
01712 if(lua_isnumber(L, arg)) {
01713 ++arg;
01714 for_turn = luaL_checkint(L, 1);
01715 if(for_turn < 1 || for_turn > resources::tod_manager->number_of_turns()) {
01716 return luaL_argerror(L, 1, "turn number out of range");
01717 }
01718 }
01719 else if(lua_isnil(L, arg)) ++arg;
01720
01721 if(lua_istable(L, arg)) {
01722 lua_rawgeti(L, arg, 1);
01723 lua_rawgeti(L, arg, 2);
01724 loc = map_location(luaL_checkinteger(L, -2) - 1, luaL_checkinteger(L, -1) - 1);
01725 if(!resources::game_map->on_board(loc)) return luaL_argerror(L, arg, "coordinates are not on board");
01726 lua_pop(L, 2);
01727
01728 lua_rawgeti(L, arg, 3);
01729 consider_illuminates = lua_toboolean(L, -1);
01730 lua_pop(L, 1);
01731 }
01732
01733 const time_of_day& tod = consider_illuminates ?
01734 resources::tod_manager->get_illuminated_time_of_day(loc, for_turn) :
01735 resources::tod_manager->get_time_of_day(loc, for_turn);
01736
01737 lua_newtable(L);
01738 lua_pushstring(L, tod.id.c_str());
01739 lua_setfield(L, -2, "id");
01740 lua_pushinteger(L, tod.lawful_bonus);
01741 lua_setfield(L, -2, "lawful_bonus");
01742 lua_pushinteger(L, tod.bonus_modified);
01743 lua_setfield(L, -2, "bonus_modified");
01744 lua_pushstring(L, tod.image.c_str());
01745 lua_setfield(L, -2, "image");
01746 luaW_pushtstring(L, tod.name);
01747 lua_setfield(L, -2, "name");
01748
01749 lua_pushinteger(L, tod.color.r);
01750 lua_setfield(L, -2, "red");
01751 lua_pushinteger(L, tod.color.g);
01752 lua_setfield(L, -2, "green");
01753 lua_pushinteger(L, tod.color.b);
01754 lua_setfield(L, -2, "blue");
01755
01756 return 1;
01757 }
01758
01759
01760
01761
01762
01763
01764 static int intf_get_village_owner(lua_State *L)
01765 {
01766 int x = luaL_checkint(L, 1);
01767 int y = luaL_checkint(L, 2);
01768
01769 map_location loc(x - 1, y - 1);
01770 if (!resources::game_map->is_village(loc))
01771 return 0;
01772
01773 int side = village_owner(loc, *resources::teams) + 1;
01774 if (!side) return 0;
01775 lua_pushinteger(L, side);
01776 return 1;
01777 }
01778
01779
01780
01781
01782
01783
01784 static int intf_set_village_owner(lua_State *L)
01785 {
01786 int x = luaL_checkint(L, 1);
01787 int y = luaL_checkint(L, 2);
01788 int new_side = lua_isnoneornil(L, 3) ? 0 : luaL_checkint(L, 3);
01789
01790 std::vector<team> &teams = *resources::teams;
01791 map_location loc(x - 1, y - 1);
01792 if (!resources::game_map->is_village(loc))
01793 return 0;
01794
01795 int old_side = village_owner(loc, teams) + 1;
01796 if (new_side == old_side
01797 || new_side < 0
01798 || new_side > static_cast<int>(teams.size())
01799 || (new_side && !resources::units->find_leader(new_side).valid()))
01800 return 0;
01801
01802 if (old_side) teams[old_side - 1].lose_village(loc);
01803 if (new_side) teams[new_side - 1].get_village(loc, old_side, lua_toboolean(L, 4));
01804 return 0;
01805 }
01806
01807
01808
01809
01810
01811
01812
01813 static int intf_get_map_size(lua_State *L)
01814 {
01815 const gamemap &map = *resources::game_map;
01816 lua_pushinteger(L, map.w());
01817 lua_pushinteger(L, map.h());
01818 lua_pushinteger(L, map.border_size());
01819 return 3;
01820 }
01821
01822
01823
01824
01825
01826
01827 static int intf_get_mouseover_tile(lua_State *L)
01828 {
01829 const map_location &loc = resources::screen->mouseover_hex();
01830 if (!resources::game_map->on_board(loc)) return 0;
01831 lua_pushinteger(L, loc.x + 1);
01832 lua_pushinteger(L, loc.y + 1);
01833 return 2;
01834 }
01835
01836
01837
01838
01839
01840
01841 static int intf_get_selected_tile(lua_State *L)
01842 {
01843 const map_location &loc = resources::screen->selected_hex();
01844 if (!resources::game_map->on_board(loc)) return 0;
01845 lua_pushinteger(L, loc.x + 1);
01846 lua_pushinteger(L, loc.y + 1);
01847 return 2;
01848 }
01849
01850
01851
01852
01853
01854
01855 static int intf_get_starting_location(lua_State* L)
01856 {
01857 const int side = luaL_checkint(L, 1);
01858 if(side < 1 || static_cast<int>(resources::teams->size()) < side)
01859 return luaL_argerror(L, 1, "out of bounds");
01860 const map_location& starting_pos = resources::game_map->starting_position(side);
01861 if(!resources::game_map->on_board(starting_pos)) return 0;
01862
01863 lua_createtable(L, 2, 0);
01864 lua_pushinteger(L, starting_pos.x + 1);
01865 lua_rawseti(L, -2, 1);
01866 lua_pushinteger(L, starting_pos.y + 1);
01867 lua_rawseti(L, -2, 2);
01868
01869 return 1;
01870 }
01871
01872
01873
01874
01875
01876
01877
01878 static int impl_game_config_get(lua_State *L)
01879 {
01880 char const *m = luaL_checkstring(L, 2);
01881
01882
01883 return_int_attrib("base_income", game_config::base_income);
01884 return_int_attrib("village_income", game_config::village_income);
01885 return_int_attrib("village_support", game_config::village_support);
01886 return_int_attrib("poison_amount", game_config::poison_amount);
01887 return_int_attrib("rest_heal_amount", game_config::rest_heal_amount);
01888 return_int_attrib("recall_cost", game_config::recall_cost);
01889 return_int_attrib("kill_experience", game_config::kill_experience);
01890 return_int_attrib("last_turn", resources::tod_manager->number_of_turns());
01891 return_string_attrib("version", game_config::version);
01892 return_bool_attrib("debug", game_config::debug);
01893 return_bool_attrib("mp_debug", game_config::mp_debug);
01894 return 0;
01895 }
01896
01897
01898
01899
01900
01901
01902
01903 static int impl_game_config_set(lua_State *L)
01904 {
01905 char const *m = luaL_checkstring(L, 2);
01906
01907
01908 modify_int_attrib("base_income", game_config::base_income = value);
01909 modify_int_attrib("village_income", game_config::village_income = value);
01910 modify_int_attrib("village_support", game_config::village_support = value);
01911 modify_int_attrib("poison_amount", game_config::poison_amount = value);
01912 modify_int_attrib("rest_heal_amount", game_config::rest_heal_amount = value);
01913 modify_int_attrib("recall_cost", game_config::recall_cost = value);
01914 modify_int_attrib("kill_experience", game_config::kill_experience = value);
01915 modify_int_attrib("last_turn", resources::tod_manager->set_number_of_turns(value));
01916 return luaL_argerror(L, 2, "unknown modifiable property");
01917 }
01918
01919
01920
01921
01922
01923
01924
01925 static int impl_current_get(lua_State *L)
01926 {
01927 char const *m = luaL_checkstring(L, 2);
01928
01929
01930 return_int_attrib("side", resources::controller->current_side());
01931 return_int_attrib("turn", resources::controller->turn());
01932
01933 if (strcmp(m, "event_context") == 0)
01934 {
01935 const game_events::queued_event &ev = queued_event_context::get();
01936 config cfg;
01937 cfg["name"] = ev.name;
01938 if (const config &weapon = ev.data.child("first")) {
01939 cfg.add_child("weapon", weapon);
01940 }
01941 if (const config &weapon = ev.data.child("second")) {
01942 cfg.add_child("second_weapon", weapon);
01943 }
01944 if (ev.loc1.valid()) {
01945 cfg["x1"] = ev.loc1.x + 1;
01946 cfg["y1"] = ev.loc1.y + 1;
01947 }
01948 if (ev.loc2.valid()) {
01949 cfg["x2"] = ev.loc2.x + 1;
01950 cfg["y2"] = ev.loc2.y + 1;
01951 }
01952 luaW_pushconfig(L, cfg);
01953 return 1;
01954 }
01955
01956 return 0;
01957 }
01958
01959
01960
01961
01962
01963
01964 static int intf_message(lua_State *L)
01965 {
01966 char const *m = luaL_checkstring(L, 1);
01967 char const *h = m;
01968 if (lua_isnone(L, 2)) {
01969 h = "Lua";
01970 } else {
01971 m = luaL_checkstring(L, 2);
01972 }
01973 chat_message(h, m);
01974 LOG_LUA << "Script says: \"" << m << "\"\n";
01975 return 0;
01976 }
01977
01978
01979
01980
01981
01982
01983 static int intf_debug(lua_State* L)
01984 {
01985 const config& arg = luaW_checkconfig(L, 1);
01986 const std::string& result = arg.debug();
01987 lua_pushstring(L, result.c_str());
01988 return 1;
01989 }
01990
01991
01992
01993
01994 static int intf_clear_messages(lua_State*)
01995 {
01996 resources::screen->clear_chat_messages();
01997 return 0;
01998 }
01999
02000
02001
02002
02003
02004
02005 static int intf_eval_conditional(lua_State *L)
02006 {
02007 vconfig cond = luaW_checkvconfig(L, 1);
02008 bool b = game_events::conditional_passed(cond);
02009 lua_pushboolean(L, b);
02010 return 1;
02011 }
02012
02013
02014
02015
02016
02017 struct lua_calculator : pathfind::cost_calculator
02018 {
02019 lua_State *L;
02020 int index;
02021
02022 lua_calculator(lua_State *L_, int i): L(L_), index(i) {}
02023 double cost(const map_location &loc, const double so_far) const;
02024 };
02025
02026 double lua_calculator::cost(const map_location &loc, const double so_far) const
02027 {
02028
02029 lua_pushvalue(L, index);
02030 lua_pushinteger(L, loc.x + 1);
02031 lua_pushinteger(L, loc.y + 1);
02032 lua_pushnumber(L, so_far);
02033
02034
02035 if (!luaW_pcall(L, 3, 1)) return 1.;
02036
02037
02038
02039 double cost = lua_tonumber(L, -1);
02040 lua_pop(L, 1);
02041 return !(cost >= 1.) ? 1. : cost;
02042 }
02043
02044
02045
02046
02047
02048
02049
02050
02051
02052
02053 static int intf_find_path(lua_State *L)
02054 {
02055 int arg = 1;
02056 map_location src, dst;
02057 unit_map &units = *resources::units;
02058 const unit *u = NULL;
02059
02060 if (lua_isuserdata(L, arg))
02061 {
02062 u = luaW_checkunit(L, 1);
02063 src = u->get_location();
02064 ++arg;
02065 }
02066 else
02067 {
02068 src.x = luaL_checkinteger(L, arg) - 1;
02069 ++arg;
02070 src.y = luaL_checkinteger(L, arg) - 1;
02071 unit_map::const_unit_iterator ui = units.find(src);
02072 if (ui.valid()) u = &*ui;
02073 ++arg;
02074 }
02075
02076 dst.x = luaL_checkinteger(L, arg) - 1;
02077 ++arg;
02078 dst.y = luaL_checkinteger(L, arg) - 1;
02079 ++arg;
02080
02081 if (!resources::game_map->on_board(src))
02082 return luaL_argerror(L, 1, "invalid location");
02083 if (!resources::game_map->on_board(dst))
02084 return luaL_argerror(L, arg - 2, "invalid location");
02085
02086 std::vector<team> &teams = *resources::teams;
02087 gamemap &map = *resources::game_map;
02088 int viewing_side = 0;
02089 bool ignore_units = false, see_all = false, ignore_teleport = false;
02090 double stop_at = 10000;
02091 pathfind::cost_calculator *calc = NULL;
02092
02093 if (lua_istable(L, arg))
02094 {
02095 lua_pushstring(L, "ignore_units");
02096 lua_rawget(L, arg);
02097 ignore_units = lua_toboolean(L, -1);
02098 lua_pop(L, 1);
02099
02100 lua_pushstring(L, "ignore_teleport");
02101 lua_rawget(L, arg);
02102 ignore_teleport = lua_toboolean(L, -1);
02103 lua_pop(L, 1);
02104
02105 lua_pushstring(L, "max_cost");
02106 lua_rawget(L, arg);
02107 if (!lua_isnil(L, -1))
02108 stop_at = luaL_checknumber(L, -1);
02109 lua_pop(L, 1);
02110
02111 lua_pushstring(L, "viewing_side");
02112 lua_rawget(L, arg);
02113 if (!lua_isnil(L, -1)) {
02114 int i = luaL_checkinteger(L, -1);
02115 if (i >= 1 && i <= int(teams.size())) viewing_side = i;
02116 else see_all = true;
02117 }
02118 lua_pop(L, 1);
02119 }
02120 else if (lua_isfunction(L, arg))
02121 {
02122 calc = new lua_calculator(L, arg);
02123 }
02124
02125 pathfind::teleport_map teleport_locations;
02126
02127 if (!calc) {
02128 if (!u) return luaL_argerror(L, 1, "unit not found");
02129
02130 team &viewing_team = teams[(viewing_side ? viewing_side : u->side()) - 1];
02131 if (!ignore_teleport) {
02132 teleport_locations = pathfind::get_teleport_locations(
02133 *u, viewing_team, see_all, ignore_units);
02134 }
02135 calc = new pathfind::shortest_path_calculator(*u, viewing_team,
02136 units, teams, map, ignore_units, false, see_all);
02137 }
02138
02139 pathfind::plain_route res = pathfind::a_star_search(src, dst, stop_at, calc, map.w(), map.h(),
02140 &teleport_locations);
02141 delete calc;
02142
02143 int nb = res.steps.size();
02144 lua_createtable(L, nb, 0);
02145 for (int i = 0; i < nb; ++i)
02146 {
02147 lua_createtable(L, 2, 0);
02148 lua_pushinteger(L, res.steps[i].x + 1);
02149 lua_rawseti(L, -2, 1);
02150 lua_pushinteger(L, res.steps[i].y + 1);
02151 lua_rawseti(L, -2, 2);
02152 lua_rawseti(L, -2, i + 1);
02153 }
02154 lua_pushinteger(L, res.move_cost);
02155
02156 return 2;
02157 }
02158
02159
02160
02161
02162
02163
02164
02165 static int intf_find_reach(lua_State *L)
02166 {
02167 int arg = 1;
02168 unit_map &units = *resources::units;
02169 const unit *u = NULL;
02170
02171 if (lua_isuserdata(L, arg))
02172 {
02173 u = luaW_checkunit(L, 1);
02174 ++arg;
02175 }
02176 else
02177 {
02178 map_location src;
02179 src.x = luaL_checkinteger(L, arg) - 1;
02180 ++arg;
02181 src.y = luaL_checkinteger(L, arg) - 1;
02182 unit_map::const_unit_iterator ui = units.find(src);
02183 if (!ui.valid())
02184 return luaL_argerror(L, 1, "unit not found");
02185 u = &*ui;
02186 ++arg;
02187 }
02188
02189 std::vector<team> &teams = *resources::teams;
02190 gamemap &map = *resources::game_map;
02191 int viewing_side = 0;
02192 bool ignore_units = false, see_all = false, ignore_teleport = false;
02193 int additional_turns = 0;
02194
02195 if (lua_istable(L, arg))
02196 {
02197 lua_pushstring(L, "ignore_units");
02198 lua_rawget(L, arg);
02199 ignore_units = lua_toboolean(L, -1);
02200 lua_pop(L, 1);
02201
02202 lua_pushstring(L, "ignore_teleport");
02203 lua_rawget(L, arg);
02204 ignore_teleport = lua_toboolean(L, -1);
02205 lua_pop(L, 1);
02206
02207 lua_pushstring(L, "additional_turns");
02208 lua_rawget(L, arg);
02209 additional_turns = lua_tointeger(L, -1);
02210 lua_pop(L, 1);
02211
02212 lua_pushstring(L, "viewing_side");
02213 lua_rawget(L, arg);
02214 if (!lua_isnil(L, -1)) {
02215 int i = luaL_checkinteger(L, -1);
02216 if (i >= 1 && i <= int(teams.size())) viewing_side = i;
02217 else see_all = true;
02218 }
02219 lua_pop(L, 1);
02220 }
02221
02222 team &viewing_team = teams[(viewing_side ? viewing_side : u->side()) - 1];
02223 pathfind::paths res(map, units, *u, teams, ignore_units, !ignore_teleport,
02224 viewing_team, additional_turns, see_all, ignore_units);
02225
02226 int nb = res.destinations.size();
02227 lua_createtable(L, nb, 0);
02228 for (int i = 0; i < nb; ++i)
02229 {
02230 pathfind::paths::step &s = res.destinations[i];
02231 lua_createtable(L, 2, 0);
02232 lua_pushinteger(L, s.curr.x + 1);
02233 lua_rawseti(L, -2, 1);
02234 lua_pushinteger(L, s.curr.y + 1);
02235 lua_rawseti(L, -2, 2);
02236 lua_pushinteger(L, s.move_left);
02237 lua_rawseti(L, -2, 3);
02238 lua_rawseti(L, -2, i + 1);
02239 }
02240
02241 return 1;
02242 }
02243
02244
02245
02246
02247
02248
02249 static int intf_put_unit(lua_State *L)
02250 {
02251 int unit_arg = 1;
02252
02253 lua_unit *lu = NULL;
02254 unit *u = NULL;
02255 map_location loc;
02256 if (lua_isnumber(L, 1)) {
02257 unit_arg = 3;
02258 loc.x = lua_tointeger(L, 1) - 1;
02259 loc.y = luaL_checkinteger(L, 2) - 1;
02260 if (!resources::game_map->on_board(loc))
02261 return luaL_argerror(L, 1, "invalid location");
02262 }
02263
02264 if (luaW_hasmetatable(L, unit_arg, getunitKey))
02265 {
02266 lu = static_cast<lua_unit *>(lua_touserdata(L, unit_arg));
02267 u = lu->get();
02268 if (!u) return luaL_argerror(L, unit_arg, "unit not found");
02269 if (lu->on_map()) {
02270 if (unit_arg == 1 || u->get_location() == loc) return 0;
02271 resources::units->erase(loc);
02272 resources::units->move(u->get_location(), loc);
02273 return 0;
02274 } else if (int side = lu->on_recall_list()) {
02275 team &t = (*resources::teams)[side - 1];
02276 unit *v = new unit(*u);
02277 std::vector<unit> &rl = t.recall_list();
02278 rl.erase(rl.begin() + (u - &rl[0]));
02279 u = v;
02280 }
02281 if (unit_arg == 1) {
02282 loc = u->get_location();
02283 if (!resources::game_map->on_board(loc))
02284 return luaL_argerror(L, 1, "invalid location");
02285 }
02286 }
02287 else if (!lua_isnoneornil(L, unit_arg))
02288 {
02289 config cfg = luaW_checkconfig(L, unit_arg);
02290 if (unit_arg == 1) {
02291 loc.x = cfg["x"] - 1;
02292 loc.y = cfg["y"] - 1;
02293 if (!resources::game_map->on_board(loc))
02294 return luaL_argerror(L, 1, "invalid location");
02295 }
02296 u = new unit(cfg, true, resources::state_of_game);
02297 }
02298
02299 resources::units->erase(loc);
02300 if (!u) return 0;
02301
02302 if (lu) {
02303 resources::units->add(loc, *u);
02304 size_t uid = u->underlying_id();
02305 lu->lua_unit::~lua_unit();
02306 new(lu) lua_unit(uid);
02307 } else {
02308 u->set_location(loc);
02309 resources::units->insert(u);
02310 }
02311
02312 return 0;
02313 }
02314
02315
02316
02317
02318
02319
02320 static int intf_put_recall_unit(lua_State *L)
02321 {
02322 lua_unit *lu = NULL;
02323 unit *u = NULL;
02324 int side = lua_tointeger(L, 2);
02325 if (unsigned(side) > resources::teams->size()) side = 0;
02326
02327 if (luaW_hasmetatable(L, 1, getunitKey))
02328 {
02329 lu = static_cast<lua_unit *>(lua_touserdata(L, 1));
02330 u = lu->get();
02331 if (!u || lu->on_recall_list())
02332 return luaL_argerror(L, 1, "unit not found");
02333 }
02334 else
02335 {
02336 config cfg = luaW_checkconfig(L, 1);
02337 u = new unit(cfg, true, resources::state_of_game);
02338 }
02339
02340 if (!side) side = u->side();
02341 team &t = (*resources::teams)[side - 1];
02342 if (!t.persistent())
02343 return luaL_argerror(L, 2, "nonpersistent side");
02344 std::vector<unit> &rl = t.recall_list();
02345
02346
02347 size_t uid = u->underlying_id();
02348 std::vector<unit>::iterator i = rl.begin();
02349 while (i != rl.end()) {
02350 if (i->underlying_id() == u->underlying_id()) {
02351 i = rl.erase(i);
02352 } else ++i;
02353 }
02354
02355 rl.push_back(*u);
02356 if (lu) {
02357 if (lu->on_map())
02358 resources::units->erase(u->get_location());
02359 lu->lua_unit::~lua_unit();
02360 new(lu) lua_unit(side, uid);
02361 }
02362
02363 return 0;
02364 }
02365
02366
02367
02368
02369
02370 static int intf_extract_unit(lua_State *L)
02371 {
02372 if (!luaW_hasmetatable(L, 1, getunitKey))
02373 return luaL_typerror(L, 1, "unit");
02374 lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, 1));
02375 unit *u = lu->get();
02376 if (!u) return luaL_argerror(L, 1, "unit not found");
02377
02378 if (lu->on_map()) {
02379 u = resources::units->extract(u->get_location());
02380 assert(u);
02381 } else if (int side = lu->on_recall_list()) {
02382 team &t = (*resources::teams)[side - 1];
02383 unit *v = new unit(*u);
02384 std::vector<unit> &rl = t.recall_list();
02385 rl.erase(rl.begin() + (u - &rl[0]));
02386 u = v;
02387 } else {
02388 return 0;
02389 }
02390
02391 lu->lua_unit::~lua_unit();
02392 new(lu) lua_unit(u);
02393 return 0;
02394 }
02395
02396
02397
02398
02399
02400
02401
02402 static int intf_find_vacant_tile(lua_State *L)
02403 {
02404 int x = luaL_checkint(L, 1) - 1, y = luaL_checkint(L, 2) - 1;
02405
02406 const unit *u = NULL;
02407 bool fake_unit = false;
02408 if (!lua_isnoneornil(L, 3)) {
02409 if (luaW_hasmetatable(L, 3, getunitKey)) {
02410 u = static_cast<lua_unit *>(lua_touserdata(L, 3))->get();
02411 } else {
02412 config cfg = luaW_checkconfig(L, 3);
02413 u = new unit(cfg, false, resources::state_of_game);
02414 fake_unit = true;
02415 }
02416 }
02417
02418 map_location res = find_vacant_tile(*resources::game_map,
02419 *resources::units, map_location(x, y), pathfind::VACANT_ANY, u);
02420
02421 if (fake_unit) delete u;
02422
02423 if (!res.valid()) return 0;
02424 lua_pushinteger(L, res.x + 1);
02425 lua_pushinteger(L, res.y + 1);
02426 return 2;
02427 }
02428
02429
02430
02431
02432
02433
02434 static int intf_float_label(lua_State *L)
02435 {
02436 map_location loc;
02437 loc.x = luaL_checkinteger(L, 1) - 1;
02438 loc.y = luaL_checkinteger(L, 2) - 1;
02439
02440 t_string text = luaW_checktstring(L, 3);
02441 resources::screen->float_label(loc, text, font::LABEL_COLOR.r,
02442 font::LABEL_COLOR.g, font::LABEL_COLOR.b);
02443 return 0;
02444 }
02445
02446
02447
02448
02449
02450
02451 static int intf_create_unit(lua_State *L)
02452 {
02453 config cfg = luaW_checkconfig(L, 1);
02454 unit *u = new unit(cfg, true, resources::state_of_game);
02455 new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(u);
02456 lua_pushlightuserdata(L
02457 , static_cast<void *>(const_cast<char *>(&getunitKey)));
02458 lua_rawget(L, LUA_REGISTRYINDEX);
02459 lua_setmetatable(L, -2);
02460 return 1;
02461 }
02462
02463
02464
02465
02466
02467
02468 static int intf_copy_unit(lua_State *L)
02469 {
02470 unit const *u = luaW_checkunit(L, 1);
02471 new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(new unit(*u));
02472 lua_pushlightuserdata(L
02473 , static_cast<void *>(const_cast<char *>(&getunitKey)));
02474 lua_rawget(L, LUA_REGISTRYINDEX);
02475 lua_setmetatable(L, -2);
02476 return 1;
02477 }
02478
02479
02480
02481
02482
02483
02484
02485
02486
02487 static int intf_unit_resistance(lua_State *L)
02488 {
02489 unit const *u = luaW_checkunit(L, 1);
02490 char const *m = luaL_checkstring(L, 2);
02491 bool a = lua_toboolean(L, 3);
02492
02493 map_location loc = u->get_location();
02494 if (!lua_isnoneornil(L, 4)) {
02495 loc.x = luaL_checkinteger(L, 4) - 1;
02496 loc.y = luaL_checkinteger(L, 5) - 1;
02497 }
02498
02499 lua_pushinteger(L, u->resistance_against(m, a, loc));
02500 return 1;
02501 }
02502
02503
02504
02505
02506
02507
02508
02509 static int intf_unit_movement_cost(lua_State *L)
02510 {
02511 unit const *u = luaW_checkunit(L, 1);
02512 char const *m = luaL_checkstring(L, 2);
02513 t_translation::t_terrain t = t_translation::read_terrain_code(m);
02514 lua_pushinteger(L, u->movement_cost(t));
02515 return 1;
02516 }
02517
02518
02519
02520
02521
02522
02523
02524 static int intf_unit_defense(lua_State *L)
02525 {
02526 unit const *u = luaW_checkunit(L, 1);
02527 char const *m = luaL_checkstring(L, 2);
02528 t_translation::t_terrain t = t_translation::read_terrain_code(m);
02529 lua_pushinteger(L, u->defense_modifier(t));
02530 return 1;
02531 }
02532
02533
02534
02535
02536
02537
02538
02539 static int intf_unit_ability(lua_State *L)
02540 {
02541 unit const *u = luaW_checkunit(L, 1);
02542 char const *m = luaL_checkstring(L, 2);
02543 lua_pushboolean(L, u->get_ability_bool(m));
02544 return 1;
02545 }
02546
02547
02548
02549
02550
02551
02552 static int intf_transform_unit(lua_State *L)
02553 {
02554 unit *u = luaW_checkunit(L, 1);
02555 char const *m = luaL_checkstring(L, 2);
02556 const unit_type *utp = unit_types.find(m);
02557 if (!utp) return luaL_argerror(L, 2, "unknown unit type");
02558 u->advance_to(utp);
02559 return 0;
02560 }
02561
02562
02563
02564
02565 static void luaW_pushsimdata(lua_State *L, const combatant &cmb)
02566 {
02567 int n = cmb.hp_dist.size();
02568 lua_createtable(L, 0, 4);
02569 lua_pushnumber(L, cmb.poisoned);
02570 lua_setfield(L, -2, "poisoned");
02571 lua_pushnumber(L, cmb.slowed);
02572 lua_setfield(L, -2, "slowed");
02573 lua_pushnumber(L, cmb.average_hp());
02574 lua_setfield(L, -2, "average_hp");
02575 lua_createtable(L, n, 0);
02576 for (int i = 0; i < n; ++i) {
02577 lua_pushnumber(L, cmb.hp_dist[i]);
02578 lua_rawseti(L, -2, i);
02579 }
02580 lua_setfield(L, -2, "hp_chance");
02581 }
02582
02583
02584
02585
02586
02587
02588
02589
02590
02591
02592 static int intf_simulate_combat(lua_State *L)
02593 {
02594 int arg_num = 1, att_w = -1, def_w = -1;
02595
02596 unit const *att = luaW_checkunit(L, arg_num);
02597 ++arg_num;
02598 if (lua_isnumber(L, arg_num)) {
02599 att_w = lua_tointeger(L, arg_num) - 1;
02600 if (att_w < 0 || att_w >= int(att->attacks().size()))
02601 return luaL_argerror(L, arg_num, "weapon index out of bounds");
02602 ++arg_num;
02603 }
02604
02605 unit const *def = luaW_checkunit(L, arg_num, true);
02606 ++arg_num;
02607 if (lua_isnumber(L, arg_num)) {
02608 def_w = lua_tointeger(L, arg_num) - 1;
02609 if (def_w < 0 || def_w >= int(def->attacks().size()))
02610 return luaL_argerror(L, arg_num, "weapon index out of bounds");
02611 ++arg_num;
02612 }
02613
02614 battle_context context(*resources::units, att->get_location(),
02615 def->get_location(), att_w, def_w, 0.0, NULL, att);
02616
02617 luaW_pushsimdata(L, context.get_attacker_combatant());
02618 luaW_pushsimdata(L, context.get_defender_combatant());
02619 return 2;
02620 }
02621
02622
02623
02624
02625
02626
02627 static int intf_tovconfig(lua_State *L)
02628 {
02629 vconfig vcfg = luaW_checkvconfig(L, 1);
02630 luaW_pushvconfig(L, vcfg);
02631 return 1;
02632 }
02633
02634
02635
02636
02637
02638 static int intf_set_music(lua_State *L)
02639 {
02640 if (lua_isnoneornil(L, 1)) {
02641 sound::commit_music_changes();
02642 return 0;
02643 }
02644
02645 config cfg = luaW_checkconfig(L, 1);
02646 sound::play_music_config(cfg);
02647 return 0;
02648 }
02649
02650
02651
02652
02653
02654
02655 static int intf_play_sound(lua_State *L)
02656 {
02657 char const *m = luaL_checkstring(L, 1);
02658 if (resources::controller->is_skipping_replay()) return 0;
02659 int repeats = lua_tointeger(L, 2);
02660 sound::play_sound(m, sound::SOUND_FX, repeats);
02661 return 0;
02662 }
02663
02664
02665
02666
02667
02668
02669 static int intf_scroll_to_tile(lua_State *L)
02670 {
02671 int x = luaL_checkinteger(L, 1) - 1;
02672 int y = luaL_checkinteger(L, 2) - 1;
02673 bool check_fogged = lua_toboolean(L, 3);
02674 resources::screen->scroll_to_tile(map_location(x, y),
02675 game_display::SCROLL, check_fogged);
02676 return 0;
02677 }
02678
02679
02680
02681
02682
02683
02684
02685 static int intf_compare_versions(lua_State* L)
02686 {
02687 char const *v1 = luaL_checkstring(L, 1);
02688
02689 const VERSION_COMP_OP vop = parse_version_op(luaL_checkstring(L, 2));
02690 if(vop == OP_INVALID) return luaL_argerror(L, 2, "unknown version comparison operator - allowed are ==, !=, <, <=, > and >=");
02691
02692 char const *v2 = luaL_checkstring(L, 3);
02693
02694 const bool result = do_version_check(version_info(v1), vop, version_info(v2));
02695 lua_pushboolean(L, result);
02696
02697 return 1;
02698 }
02699
02700
02701
02702
02703
02704
02705 static int intf_select_hex(lua_State *L)
02706 {
02707 const int x = luaL_checkinteger(L, 1) - 1;
02708 const int y = luaL_checkinteger(L, 2) - 1;
02709
02710 map_location loc(x, y);
02711 if(!resources::game_map->on_board(loc)) return luaL_argerror(L, 1, "not on board");
02712 bool highlight = true;
02713 if(!lua_isnoneornil(L, 3))
02714 highlight = lua_toboolean(L, 3);
02715 const bool fire_event = lua_toboolean(L, 4);
02716 resources::controller->get_mouse_handler_base().select_hex(
02717 map_location(x, y), false, highlight, fire_event);
02718 if(highlight)
02719 resources::screen->highlight_hex(loc);
02720 return 0;
02721 }
02722
02723 struct lua_synchronize : mp_sync::user_choice
02724 {
02725 lua_State *L;
02726 lua_synchronize(lua_State *l): L(l) {}
02727
02728 virtual config query_user() const
02729 {
02730 config cfg;
02731 int index = 1;
02732 if (!lua_isnoneornil(L, 2)) {
02733 int side = resources::controller->current_side();
02734 if ((*resources::teams)[side - 1].is_ai())
02735 index = 2;
02736 }
02737 lua_settop(L, index);
02738 if (luaW_pcall(L, 0, 1, false))
02739 luaW_toconfig(L, -1, cfg);
02740 return cfg;
02741 }
02742
02743 virtual config random_choice(rand_rng::simple_rng &) const
02744 {
02745 return config();
02746 }
02747 };
02748
02749
02750
02751
02752
02753
02754
02755 static int intf_synchronize_choice(lua_State *L)
02756 {
02757 config cfg = mp_sync::get_user_choice("input", lua_synchronize(L));
02758 luaW_pushconfig(L, cfg);
02759 return 1;
02760 }
02761
02762 struct scoped_dialog
02763 {
02764 lua_State *L;
02765 scoped_dialog *prev;
02766 static scoped_dialog *current;
02767 gui2::twindow *window;
02768 typedef std::map<gui2::twidget *, int> callback_map;
02769 callback_map callbacks;
02770
02771 scoped_dialog(lua_State *l, gui2::twindow *w);
02772 ~scoped_dialog();
02773 private:
02774 scoped_dialog(const scoped_dialog &);
02775 };
02776
02777 scoped_dialog *scoped_dialog::current = NULL;
02778
02779 scoped_dialog::scoped_dialog(lua_State *l, gui2::twindow *w)
02780 : L(l), prev(current), window(w), callbacks()
02781 {
02782 lua_pushlightuserdata(L
02783 , static_cast<void *>(const_cast<char *>(&dlgclbkKey)));
02784 lua_createtable(L, 1, 0);
02785 lua_pushvalue(L, -2);
02786 lua_rawget(L, LUA_REGISTRYINDEX);
02787 lua_rawseti(L, -2, 1);
02788 lua_rawset(L, LUA_REGISTRYINDEX);
02789 current = this;
02790 }
02791
02792 scoped_dialog::~scoped_dialog()
02793 {
02794 delete window;
02795 current = prev;
02796 lua_pushlightuserdata(L
02797 , static_cast<void *>(const_cast<char *>(&dlgclbkKey)));
02798 lua_pushvalue(L, -1);
02799 lua_rawget(L, LUA_REGISTRYINDEX);
02800 lua_rawgeti(L, -1, 1);
02801 lua_remove(L, -2);
02802 lua_rawset(L, LUA_REGISTRYINDEX);
02803 }
02804
02805 static gui2::twidget *find_widget(lua_State *L, int i, bool readonly)
02806 {
02807 if (!scoped_dialog::current) {
02808 luaL_error(L, "no visible dialog");
02809 error_call_destructors_1:
02810 luaL_argerror(L, i, "out of bounds");
02811 error_call_destructors_2:
02812 luaL_typerror(L, i, "string");
02813 error_call_destructors_3:
02814 luaL_argerror(L, i, "widget not found");
02815 return NULL;
02816 }
02817
02818 gui2::twidget *w = scoped_dialog::current->window;
02819 for (; !lua_isnoneornil(L, i); ++i)
02820 {
02821 #ifdef GUI2_EXPERIMENTAL_LISTBOX
02822 if (gui2::tlist *l = dynamic_cast<gui2::tlist *>(w))
02823 #else
02824 if (gui2::tlistbox *l = dynamic_cast<gui2::tlistbox *>(w))
02825 #endif
02826 {
02827 int v = lua_tointeger(L, i);
02828 if (v < 1)
02829 goto error_call_destructors_1;
02830 int n = l->get_item_count();
02831 if (v > n) {
02832 if (readonly)
02833 goto error_call_destructors_1;
02834 utils::string_map dummy;
02835 for (; n < v; ++n)
02836 l->add_row(dummy);
02837 }
02838 w = l->get_row_grid(v - 1);
02839 }
02840 else if (gui2::tmulti_page *l = dynamic_cast<gui2::tmulti_page *>(w))
02841 {
02842 int v = lua_tointeger(L, i);
02843 if (v < 1)
02844 goto error_call_destructors_1;
02845 int n = l->get_page_count();
02846 if (v > n) {
02847 if (readonly)
02848 goto error_call_destructors_1;
02849 utils::string_map dummy;
02850 for (; n < v; ++n)
02851 l->add_page(dummy);
02852 }
02853 w = &l->page_grid(v - 1);
02854 }
02855 else
02856 {
02857 char const *m = lua_tostring(L, i);
02858 if (!m) goto error_call_destructors_2;
02859 w = w->find(m, false);
02860 }
02861 if (!w) goto error_call_destructors_3;
02862 }
02863
02864 return w;
02865 }
02866
02867
02868
02869
02870
02871
02872
02873
02874 static int intf_show_dialog(lua_State *L)
02875 {
02876 config def_cfg = luaW_checkconfig(L, 1);
02877
02878 gui2::twindow_builder::tresolution def(def_cfg);
02879 scoped_dialog w(L, gui2::build(resources::screen->video(), &def));
02880
02881 if (!lua_isnoneornil(L, 2)) {
02882 lua_pushvalue(L, 2);
02883 lua_call(L, 0, 0);
02884 }
02885
02886 int v = scoped_dialog::current->window->show(true, 0);
02887
02888 if (!lua_isnoneornil(L, 3)) {
02889 lua_pushvalue(L, 3);
02890 lua_call(L, 0, 0);
02891 }
02892
02893 lua_pushinteger(L, v);
02894 return 1;
02895 }
02896
02897
02898
02899
02900
02901
02902 static int intf_set_dialog_value(lua_State *L)
02903 {
02904 gui2::twidget *w = find_widget(L, 2, false);
02905
02906 #ifdef GUI2_EXPERIMENTAL_LISTBOX
02907 if (gui2::tlist *l = dynamic_cast<gui2::tlist *>(w))
02908 #else
02909 if (gui2::tlistbox *l = dynamic_cast<gui2::tlistbox *>(w))
02910 #endif
02911 {
02912 int v = luaL_checkinteger(L, 1);
02913 int n = l->get_item_count();
02914 if (1 <= v && v <= n)
02915 l->select_row(v - 1);
02916 else
02917 return luaL_argerror(L, 1, "out of bounds");
02918 }
02919 else if (gui2::tmulti_page *l = dynamic_cast<gui2::tmulti_page *>(w))
02920 {
02921 int v = luaL_checkinteger(L, 1);
02922 int n = l->get_page_count();
02923 if (1 <= v && v <= n)
02924 l->select_page(v - 1);
02925 else
02926 return luaL_argerror(L, 1, "out of bounds");
02927 }
02928 else if (gui2::tselectable_ *s = dynamic_cast<gui2::tselectable_ *>(w))
02929 {
02930 s->set_value(lua_toboolean(L, 1));
02931 }
02932 else if (gui2::ttext_box *t = dynamic_cast<gui2::ttext_box *>(w))
02933 {
02934 const t_string& text = luaW_checktstring(L, 1);
02935 t->set_value(text.str());
02936 }
02937 else if (gui2::tslider *s = dynamic_cast<gui2::tslider *>(w))
02938 {
02939 const int v = luaL_checkinteger(L, 1);
02940 const int m = s->get_minimum_value();
02941 const int n = s->get_maximum_value();
02942 if (m <= v && v <= n)
02943 s->set_value(v);
02944 else
02945 return luaL_argerror(L, 1, "out of bounds");
02946 }
02947 else if (gui2::tprogress_bar *p = dynamic_cast<gui2::tprogress_bar *>(w))
02948 {
02949 const int v = luaL_checkinteger(L, 1);
02950 if (0 <= v && v <= 100)
02951 p->set_percentage(v);
02952 else
02953 return luaL_argerror(L, 1, "out of bounds");
02954 }
02955 else
02956 {
02957 t_string v = luaW_checktstring(L, 1);
02958 gui2::tcontrol *c = dynamic_cast<gui2::tcontrol *>(w);
02959 if (!c) return luaL_argerror(L, lua_gettop(L), "unsupported widget");
02960 c->set_label(v);
02961 }
02962
02963 return 0;
02964 }
02965
02966
02967
02968
02969
02970
02971 static int intf_get_dialog_value(lua_State *L)
02972 {
02973 gui2::twidget *w = find_widget(L, 1, true);
02974
02975 #ifdef GUI2_EXPERIMENTAL_LISTBOX
02976 if (gui2::tlist *l = dynamic_cast<gui2::tlist *>(w))
02977 #else
02978 if (gui2::tlistbox *l = dynamic_cast<gui2::tlistbox *>(w))
02979 #endif
02980 {
02981 lua_pushinteger(L, l->get_selected_row() + 1);
02982 } else if (gui2::tmulti_page *l = dynamic_cast<gui2::tmulti_page *>(w)) {
02983 lua_pushinteger(L, l->get_selected_page() + 1);
02984 } else if (gui2::tselectable_ *s = dynamic_cast<gui2::tselectable_ *>(w)) {
02985 lua_pushboolean(L, s->get_value());
02986 } else if (gui2::ttext_box *t = dynamic_cast<gui2::ttext_box *>(w)) {
02987 lua_pushstring(L, t->get_value().c_str());
02988 } else if (gui2::tslider *s = dynamic_cast<gui2::tslider *>(w)) {
02989 lua_pushinteger(L, s->get_value());
02990 } else if (gui2::tprogress_bar *p = dynamic_cast<gui2::tprogress_bar *>(w)) {
02991 lua_pushinteger(L, p->get_percentage());
02992 } else
02993 return luaL_argerror(L, lua_gettop(L), "unsupported widget");
02994
02995 return 1;
02996 }
02997
02998 static void dialog_callback(gui2::twidget *w)
02999 {
03000 int cb;
03001 {
03002 scoped_dialog::callback_map &m = scoped_dialog::current->callbacks;
03003 scoped_dialog::callback_map::const_iterator i = m.find(w);
03004 if (i == m.end()) return;
03005 cb = i->second;
03006 }
03007 lua_State *L = scoped_dialog::current->L;
03008 lua_pushlightuserdata(L
03009 , static_cast<void *>(const_cast<char *>(&dlgclbkKey)));
03010 lua_rawget(L, LUA_REGISTRYINDEX);
03011 lua_rawgeti(L, -1, cb);
03012 lua_remove(L, -2);
03013 lua_call(L, 0, 0);
03014 }
03015
03016
03017 struct tdialog_callback_wrapper
03018 {
03019 void forward(gui2::twidget* widget)
03020 {
03021 dialog_callback(widget);
03022 }
03023 };
03024
03025
03026
03027
03028
03029 static int intf_set_dialog_callback(lua_State *L)
03030 {
03031 gui2::twidget *w = find_widget(L, 2, true);
03032
03033 scoped_dialog::callback_map &m = scoped_dialog::current->callbacks;
03034 scoped_dialog::callback_map::iterator i = m.find(w);
03035 if (i != m.end())
03036 {
03037 lua_pushlightuserdata(L
03038 , static_cast<void *>(const_cast<char *>(&dlgclbkKey)));
03039 lua_rawget(L, LUA_REGISTRYINDEX);
03040 lua_pushnil(L);
03041 lua_rawseti(L, -2, i->second);
03042 lua_pop(L, 1);
03043 m.erase(i);
03044 }
03045
03046 if (lua_isnil(L, 1)) return 0;
03047
03048 if (gui2::tclickable_ *c = dynamic_cast<gui2::tclickable_ *>(w)) {
03049 static tdialog_callback_wrapper wrapper;
03050 c->connect_click_handler(boost::bind(
03051 &tdialog_callback_wrapper::forward
03052 , wrapper
03053 , w));
03054 } else if (gui2::tselectable_ *s = dynamic_cast<gui2::tselectable_ *>(w)) {
03055 s->set_callback_state_change(&dialog_callback);
03056 }
03057 #ifdef GUI2_EXPERIMENTAL_LISTBOX
03058 else if (gui2::tlist *l = dynamic_cast<gui2::tlist *>(w)) {
03059 static tdialog_callback_wrapper wrapper;
03060 connect_signal_notify_modified(*l
03061 , boost::bind(
03062 &tdialog_callback_wrapper::forward
03063 , wrapper
03064 , w));
03065 }
03066 #else
03067 else if (gui2::tlistbox *l = dynamic_cast<gui2::tlistbox *>(w)) {
03068 l->set_callback_value_change(&dialog_callback);
03069 }
03070 #endif
03071 else
03072 return luaL_argerror(L, lua_gettop(L), "unsupported widget");
03073
03074 lua_pushlightuserdata(L
03075 , static_cast<void *>(const_cast<char *>(&dlgclbkKey)));
03076 lua_rawget(L, LUA_REGISTRYINDEX);
03077 int n = lua_rawlen(L, -1) + 1;
03078 m[w] = n;
03079 lua_pushvalue(L, 1);
03080 lua_rawseti(L, -2, n);
03081 lua_pop(L, 1);
03082
03083 return 0;
03084 }
03085
03086
03087
03088
03089
03090
03091
03092 static int intf_set_dialog_canvas(lua_State *L)
03093 {
03094 int i = luaL_checkinteger(L, 1);
03095 gui2::twidget *w = find_widget(L, 3, true);
03096 gui2::tcontrol *c = dynamic_cast<gui2::tcontrol *>(w);
03097 if (!c) return luaL_argerror(L, lua_gettop(L), "unsupported widget");
03098
03099 std::vector<gui2::tcanvas> &cv = c->canvas();
03100 if (i < 1 || unsigned(i) > cv.size())
03101 return luaL_argerror(L, 1, "out of bounds");
03102
03103 config cfg = luaW_checkconfig(L, 2);
03104 cv[i - 1].set_cfg(cfg);
03105 return 0;
03106 }
03107
03108
03109
03110
03111
03112
03113 static int intf_set_dialog_active(lua_State *L)
03114 {
03115 const bool b = lua_toboolean(L, 1);
03116 gui2::twidget *w = find_widget(L, 2, true);
03117 gui2::tcontrol *c = dynamic_cast<gui2::tcontrol *>(w);
03118 if (!c) return luaL_argerror(L, lua_gettop(L), "unsupported widget");
03119
03120 c->set_active(b);
03121 return 0;
03122 }
03123
03124
03125
03126
03127
03128
03129 static int intf_get_locations(lua_State *L)
03130 {
03131 vconfig filter = luaW_checkvconfig(L, 1);
03132
03133 std::set<map_location> res;
03134 const terrain_filter t_filter(filter, *resources::units);
03135 t_filter.get_locations(res, true);
03136
03137 lua_createtable(L, res.size(), 0);
03138 int i = 1;
03139 foreach (map_location const &loc, res)
03140 {
03141 lua_createtable(L, 2, 0);
03142 lua_pushinteger(L, loc.x + 1);
03143 lua_rawseti(L, -2, 1);
03144 lua_pushinteger(L, loc.y + 1);
03145 lua_rawseti(L, -2, 2);
03146 lua_rawseti(L, -2, i);
03147 ++i;
03148 }
03149 return 1;
03150 }
03151
03152
03153
03154
03155
03156
03157
03158 static int intf_match_location(lua_State *L)
03159 {
03160 int x = luaL_checkinteger(L, 1) - 1;
03161 int y = luaL_checkinteger(L, 2) - 1;
03162 vconfig filter = luaW_checkvconfig(L, 3, true);
03163
03164 if (filter.null()) {
03165 lua_pushboolean(L, true);
03166 return 1;
03167 }
03168
03169 const terrain_filter t_filter(filter, *resources::units);
03170 lua_pushboolean(L, t_filter.match(map_location(x, y)));
03171 return 1;
03172 }
03173
03174
03175
03176
03177
03178
03179
03180
03181
03182 static int intf_match_side(lua_State *L)
03183 {
03184 unsigned side = luaL_checkinteger(L, 1) - 1;
03185 if (side >= resources::teams->size()) return 0;
03186 vconfig filter = luaW_checkvconfig(L, 2, true);
03187
03188 if (filter.null()) {
03189 lua_pushboolean(L, true);
03190 return 1;
03191 }
03192
03193 side_filter s_filter(filter);
03194 lua_pushboolean(L, s_filter.match(side + 1));
03195 return 1;
03196 }
03197
03198
03199
03200
03201
03202
03203 static int intf_get_sides(lua_State* L)
03204 {
03205 std::vector<int> sides;
03206 const vconfig ssf = luaW_checkvconfig(L, 1, true);
03207 if(ssf.null()){
03208 for(unsigned side_number = 1; side_number <= resources::teams->size(); ++side_number)
03209 sides.push_back(side_number);
03210 } else {
03211 side_filter filter(ssf);
03212 sides = filter.get_teams();
03213 }
03214
03215
03216
03217
03218
03219
03220
03221 lua_settop(L, 0);
03222 lua_pushlightuserdata(L
03223 , static_cast<void*>(const_cast<char *>(&getsideKey)));
03224 lua_rawget(L, LUA_REGISTRYINDEX);
03225 lua_createtable(L, sides.size(), 0);
03226 unsigned index = 1;
03227 foreach(int side, sides) {
03228
03229 team** t = static_cast<team**>(lua_newuserdata(L, sizeof(team*)));
03230 *t = &((*resources::teams)[side - 1]);
03231 lua_pushvalue(L, 1);
03232 lua_setmetatable(L, 3);
03233 lua_rawseti(L, 2, index);
03234 ++index;
03235 }
03236
03237 return 1;
03238 }
03239
03240
03241
03242
03243
03244 static int intf_get_traits(lua_State* L)
03245 {
03246 lua_newtable(L);
03247 foreach(const config& trait, unit_types.traits()) {
03248 const std::string& id = trait["id"];
03249
03250
03251
03252
03253 lua_pushstring(L, id.c_str());
03254 luaW_pushconfig(L, trait);
03255 lua_rawset(L, -3);
03256 }
03257 return 1;
03258 }
03259
03260
03261
03262
03263
03264
03265
03266 static int intf_add_modification(lua_State *L)
03267 {
03268 unit *u = luaW_checkunit(L, 1);
03269 char const *m = luaL_checkstring(L, 2);
03270 std::string sm = m;
03271 if (sm != "advance" && sm != "object" && sm != "trait")
03272 return luaL_argerror(L, 2, "unknown modification type");
03273
03274 config cfg = luaW_checkconfig(L, 3);
03275 u->add_modification(sm, cfg);
03276 return 0;
03277 }
03278
03279
03280
03281
03282
03283 static int intf_add_known_unit(lua_State *L)
03284 {
03285 char const *ty = luaL_checkstring(L, 1);
03286 if(!unit_types.find(ty)) return luaL_argerror(L, 1, "unknown unit type");
03287 preferences::encountered_units().insert(ty);
03288 return 0;
03289 }
03290
03291
03292
03293
03294
03295
03296 static int intf_add_tile_overlay(lua_State *L)
03297 {
03298 int x = luaL_checkinteger(L, 1) - 1;
03299 int y = luaL_checkinteger(L, 2) - 1;
03300 config cfg = luaW_checkconfig(L, 3);
03301
03302 resources::screen->add_overlay(map_location(x, y), cfg["image"], cfg["halo"],
03303 cfg["team_name"], cfg["visible_in_fog"].to_bool(true));
03304 return 0;
03305 }
03306
03307
03308
03309
03310
03311
03312 static int intf_remove_tile_overlay(lua_State *L)
03313 {
03314 int x = luaL_checkinteger(L, 1) - 1;
03315 int y = luaL_checkinteger(L, 2) - 1;
03316 char const *m = lua_tostring(L, 3);
03317
03318 if (m) {
03319 resources::screen->remove_single_overlay(map_location(x, y), m);
03320 } else {
03321 resources::screen->remove_overlay(map_location(x, y));
03322 }
03323 return 0;
03324 }
03325
03326
03327
03328
03329
03330 static int intf_delay(lua_State *L)
03331 {
03332 unsigned final = SDL_GetTicks() + luaL_checkinteger(L, 1);
03333 do {
03334 resources::controller->play_slice(false);
03335 resources::screen->delay(10);
03336 } while (int(final - SDL_GetTicks()) > 0);
03337 return 0;
03338 }
03339
03340
03341
03342
03343
03344
03345
03346 static int intf_get_image_size(lua_State *L)
03347 {
03348 char const *m = luaL_checkstring(L, 1);
03349 image::locator img(m);
03350 if (!img.file_exists()) return 0;
03351 surface s = get_image(img);
03352 lua_pushinteger(L, s->w);
03353 lua_pushinteger(L, s->h);
03354 return 2;
03355 }
03356
03357
03358
03359
03360
03361 static int intf_modify_ai(lua_State *L)
03362 {
03363 config cfg;
03364 luaW_toconfig(L, 1, cfg);
03365 int side = cfg["side"];
03366 ai::manager::modify_active_ai_for_side(side, cfg);
03367 return 0;
03368 }
03369
03370 struct lua_report_generator : reports::generator
03371 {
03372 lua_State *mState;
03373 std::string name;
03374 lua_report_generator(lua_State *L, const std::string &n)
03375 : mState(L), name(n) {}
03376 virtual config generate();
03377 };
03378
03379 config lua_report_generator::generate()
03380 {
03381 lua_State *L = mState;
03382 config cfg;
03383 if (!luaW_getglobal(L, "wesnoth", "theme_items", name.c_str(), NULL))
03384 return cfg;
03385 if (!luaW_pcall(L, 0, 1)) return cfg;
03386 luaW_toconfig(L, -1, cfg);
03387 lua_pop(L, 1);
03388 return cfg;
03389 }
03390
03391
03392
03393
03394 static int cfun_theme_item(lua_State *L)
03395 {
03396 const char *m = lua_tostring(L, lua_upvalueindex(1));
03397 luaW_pushconfig(L, reports::generate_report(m, true));
03398 return 1;
03399 }
03400
03401
03402
03403
03404 static int impl_theme_items_get(lua_State *L)
03405 {
03406 char const *m = luaL_checkstring(L, 2);
03407 lua_pushvalue(L, 2);
03408 lua_pushcclosure(L, cfun_theme_item, 1);
03409 lua_pushvalue(L, 2);
03410 lua_pushvalue(L, -2);
03411 lua_rawset(L, 1);
03412 reports::register_generator(m, new lua_report_generator(L, m));
03413 return 1;
03414 }
03415
03416
03417
03418
03419 static int impl_theme_items_set(lua_State *L)
03420 {
03421 char const *m = luaL_checkstring(L, 2);
03422 lua_pushvalue(L, 2);
03423 lua_pushvalue(L, 3);
03424 lua_rawset(L, 1);
03425 reports::register_generator(m, new lua_report_generator(L, m));
03426 return 0;
03427 }
03428
03429
03430 LuaKernel::LuaKernel(const config &cfg)
03431 : mState(luaL_newstate()), level_(cfg)
03432 {
03433 lua_State *L = mState;
03434
03435
03436
03437 static const luaL_Reg safe_libs[] = {
03438 { "", luaopen_base },
03439 { "table", luaopen_table },
03440 { "string", luaopen_string },
03441 { "math", luaopen_math },
03442 { "debug", luaopen_debug },
03443 { "os", luaopen_os },
03444 { NULL, NULL }
03445 };
03446 for (luaL_Reg const *lib = safe_libs; lib->func; ++lib)
03447 {
03448 luaL_requiref(L, lib->name, lib->func, 1);
03449 lua_pop(L, 1);
03450 }
03451
03452
03453 static luaL_Reg const callbacks[] = {
03454 { "add_known_unit", &intf_add_known_unit },
03455 { "add_modification", &intf_add_modification },
03456 { "add_tile_overlay", &intf_add_tile_overlay },
03457 { "clear_messages", &intf_clear_messages },
03458 { "compare_versions", &intf_compare_versions },
03459 { "copy_unit", &intf_copy_unit },
03460 { "create_unit", &intf_create_unit },
03461 { "debug", &intf_debug },
03462 { "delay", &intf_delay },
03463 { "dofile", &intf_dofile },
03464 { "eval_conditional", &intf_eval_conditional },
03465 { "extract_unit", &intf_extract_unit },
03466 { "find_path", &intf_find_path },
03467 { "find_reach", &intf_find_reach },
03468 { "find_vacant_tile", &intf_find_vacant_tile },
03469 { "fire_event", &intf_fire_event },
03470 { "float_label", &intf_float_label },
03471 { "get_dialog_value", &intf_get_dialog_value },
03472 { "get_displayed_unit", &intf_get_displayed_unit },
03473 { "get_image_size", &intf_get_image_size },
03474 { "get_locations", &intf_get_locations },
03475 { "get_map_size", &intf_get_map_size },
03476 { "get_mouseover_tile", &intf_get_mouseover_tile },
03477 { "get_recall_units", &intf_get_recall_units },
03478 { "get_selected_tile", &intf_get_selected_tile },
03479 { "get_sides", &intf_get_sides },
03480 { "get_starting_location", &intf_get_starting_location },
03481 { "get_terrain", &intf_get_terrain },
03482 { "get_terrain_info", &intf_get_terrain_info },
03483 { "get_time_of_day", &intf_get_time_of_day },
03484 { "get_traits", &intf_get_traits },
03485 { "get_unit", &intf_get_unit },
03486 { "get_units", &intf_get_units },
03487 { "get_variable", &intf_get_variable },
03488 { "get_village_owner", &intf_get_village_owner },
03489 { "highlight_hex", &intf_highlight_hex },
03490 { "is_enemy", &intf_is_enemy },
03491 { "match_location", &intf_match_location },
03492 { "match_side", &intf_match_side },
03493 { "match_unit", &intf_match_unit },
03494 { "message", &intf_message },
03495 { "modify_ai", &intf_modify_ai },
03496 { "play_sound", &intf_play_sound },
03497 { "put_recall_unit", &intf_put_recall_unit },
03498 { "put_unit", &intf_put_unit },
03499 { "remove_tile_overlay", &intf_remove_tile_overlay },
03500 { "require", &intf_require },
03501 { "scroll_to_tile", &intf_scroll_to_tile },
03502 { "select_hex", &intf_select_hex },
03503 { "set_dialog_active", &intf_set_dialog_active },
03504 { "set_dialog_callback", &intf_set_dialog_callback },
03505 { "set_dialog_canvas", &intf_set_dialog_canvas },
03506 { "set_dialog_value", &intf_set_dialog_value },
03507 { "set_music", &intf_set_music },
03508 { "set_terrain", &intf_set_terrain },
03509 { "set_variable", &intf_set_variable },
03510 { "set_village_owner", &intf_set_village_owner },
03511 { "show_dialog", &intf_show_dialog },
03512 { "simulate_combat", &intf_simulate_combat },
03513 { "synchronize_choice", &intf_synchronize_choice },
03514 { "textdomain", &intf_textdomain },
03515 { "tovconfig", &intf_tovconfig },
03516 { "transform_unit", &intf_transform_unit },
03517 { "unit_ability", &intf_unit_ability },
03518 { "unit_defense", &intf_unit_defense },
03519 { "unit_movement_cost", &intf_unit_movement_cost },
03520 { "unit_resistance", &intf_unit_resistance },
03521 { NULL, NULL }
03522 };
03523 luaL_register(L, "wesnoth", callbacks);
03524
03525
03526 lua_pushlightuserdata(L
03527 , static_cast<void *>(const_cast<char *>(&getsideKey)));
03528 lua_createtable(L, 0, 3);
03529 lua_pushcfunction(L, impl_side_get);
03530 lua_setfield(L, -2, "__index");
03531 lua_pushcfunction(L, impl_side_set);
03532 lua_setfield(L, -2, "__newindex");
03533 lua_pushstring(L, "side");
03534 lua_setfield(L, -2, "__metatable");
03535 lua_rawset(L, LUA_REGISTRYINDEX);
03536
03537
03538 lua_pushlightuserdata(L
03539 , static_cast<void *>(const_cast<char *>(&gettextKey)));
03540 lua_createtable(L, 0, 2);
03541 lua_pushcfunction(L, impl_gettext);
03542 lua_setfield(L, -2, "__call");
03543 lua_pushstring(L, "message domain");
03544 lua_setfield(L, -2, "__metatable");
03545 lua_rawset(L, LUA_REGISTRYINDEX);
03546
03547
03548 lua_pushlightuserdata(L
03549 , static_cast<void *>(const_cast<char *>(&gettypeKey)));
03550 lua_createtable(L, 0, 2);
03551 lua_pushcfunction(L, impl_unit_type_get);
03552 lua_setfield(L, -2, "__index");
03553 lua_pushstring(L, "unit type");
03554 lua_setfield(L, -2, "__metatable");
03555 lua_rawset(L, LUA_REGISTRYINDEX);
03556
03557
03558 lua_pushlightuserdata(L
03559 , static_cast<void *>(const_cast<char *>(&getraceKey)));
03560 lua_createtable(L, 0, 2);
03561 lua_pushcfunction(L, impl_race_get);
03562 lua_setfield(L, -2, "__index");
03563 lua_pushstring(L, "race");
03564 lua_setfield(L, -2, "__metatable");
03565 lua_rawset(L, LUA_REGISTRYINDEX);
03566
03567
03568 lua_pushlightuserdata(L
03569 , static_cast<void *>(const_cast<char *>(&getunitKey)));
03570 lua_createtable(L, 0, 4);
03571 lua_pushcfunction(L, impl_unit_collect);
03572 lua_setfield(L, -2, "__gc");
03573 lua_pushcfunction(L, impl_unit_get);
03574 lua_setfield(L, -2, "__index");
03575 lua_pushcfunction(L, impl_unit_set);
03576 lua_setfield(L, -2, "__newindex");
03577 lua_pushstring(L, "unit");
03578 lua_setfield(L, -2, "__metatable");
03579 lua_rawset(L, LUA_REGISTRYINDEX);
03580
03581
03582 lua_pushlightuserdata(L
03583 , static_cast<void *>(const_cast<char *>(&tstringKey)));
03584 lua_createtable(L, 0, 4);
03585 lua_pushcfunction(L, impl_tstring_concat);
03586 lua_setfield(L, -2, "__concat");
03587 lua_pushcfunction(L, impl_tstring_collect);
03588 lua_setfield(L, -2, "__gc");
03589 lua_pushcfunction(L, impl_tstring_tostring);
03590 lua_setfield(L, -2, "__tostring");
03591 lua_pushstring(L, "translatable string");
03592 lua_setfield(L, -2, "__metatable");
03593 lua_rawset(L, LUA_REGISTRYINDEX);
03594
03595
03596 lua_pushlightuserdata(L
03597 , static_cast<void *>(const_cast<char *>(&ustatusKey)));
03598 lua_createtable(L, 0, 3);
03599 lua_pushcfunction(L, impl_unit_status_get);
03600 lua_setfield(L, -2, "__index");
03601 lua_pushcfunction(L, impl_unit_status_set);
03602 lua_setfield(L, -2, "__newindex");
03603 lua_pushstring(L, "unit status");
03604 lua_setfield(L, -2, "__metatable");
03605 lua_rawset(L, LUA_REGISTRYINDEX);
03606
03607
03608 lua_pushlightuserdata(L
03609 , static_cast<void *>(const_cast<char *>(&unitvarKey)));
03610 lua_createtable(L, 0, 3);
03611 lua_pushcfunction(L, impl_unit_variables_get);
03612 lua_setfield(L, -2, "__index");
03613 lua_pushcfunction(L, impl_unit_variables_set);
03614 lua_setfield(L, -2, "__newindex");
03615 lua_pushstring(L, "unit variables");
03616 lua_setfield(L, -2, "__metatable");
03617 lua_rawset(L, LUA_REGISTRYINDEX);
03618
03619
03620 lua_pushlightuserdata(L
03621 , static_cast<void *>(const_cast<char *>(&vconfigKey)));
03622 lua_createtable(L, 0, 4);
03623 lua_pushcfunction(L, impl_vconfig_collect);
03624 lua_setfield(L, -2, "__gc");
03625 lua_pushcfunction(L, impl_vconfig_get);
03626 lua_setfield(L, -2, "__index");
03627 lua_pushcfunction(L, impl_vconfig_size);
03628 lua_setfield(L, -2, "__len");
03629 lua_pushstring(L, "wml object");
03630 lua_setfield(L, -2, "__metatable");
03631 lua_rawset(L, LUA_REGISTRYINDEX);
03632
03633
03634 ai::lua_ai_context::init(L);
03635
03636
03637 lua_pushnil(L);
03638 lua_setglobal(L, "dofile");
03639 lua_pushnil(L);
03640 lua_setglobal(L, "loadfile");
03641
03642
03643 lua_getglobal(L, "wesnoth");
03644 lua_newuserdata(L, 0);
03645 lua_createtable(L, 0, 3);
03646 lua_pushcfunction(L, impl_game_config_get);
03647 lua_setfield(L, -2, "__index");
03648 lua_pushcfunction(L, impl_game_config_set);
03649 lua_setfield(L, -2, "__newindex");
03650 lua_pushstring(L, "game config");
03651 lua_setfield(L, -2, "__metatable");
03652 lua_setmetatable(L, -2);
03653 lua_setfield(L, -2, "game_config");
03654 lua_pop(L, 1);
03655
03656
03657 lua_getglobal(L, "wesnoth");
03658 lua_newuserdata(L, 0);
03659 lua_createtable(L, 0, 2);
03660 lua_pushcfunction(L, impl_current_get);
03661 lua_setfield(L, -2, "__index");
03662 lua_pushstring(L, "current config");
03663 lua_setfield(L, -2, "__metatable");
03664 lua_setmetatable(L, -2);
03665 lua_setfield(L, -2, "current");
03666 lua_pop(L, 1);
03667
03668
03669 lua_getglobal(L, "wesnoth");
03670 lua_newtable(L);
03671 lua_setfield(L, -2, "package");
03672 lua_pop(L, 1);
03673
03674
03675 lua_getglobal(L, "wesnoth");
03676 lua_newtable(L);
03677 lua_setfield(L, -2, "wml_actions");
03678 lua_pop(L, 1);
03679
03680
03681 lua_getglobal(L, "wesnoth");
03682 lua_newtable(L);
03683 lua_setfield(L, -2, "game_events");
03684 lua_pop(L, 1);
03685
03686
03687 lua_getglobal(L, "wesnoth");
03688 lua_newtable(L);
03689 lua_createtable(L, 0, 2);
03690 lua_pushcfunction(L, impl_theme_items_get);
03691 lua_setfield(L, -2, "__index");
03692 lua_pushcfunction(L, impl_theme_items_set);
03693 lua_setfield(L, -2, "__newindex");
03694 lua_setmetatable(L, -2);
03695 lua_setfield(L, -2, "theme_items");
03696 lua_pop(L, 1);
03697
03698
03699 lua_pushlightuserdata(L
03700 , static_cast<void *>(const_cast<char *>(&executeKey)));
03701 lua_getglobal(L, "debug");
03702 lua_getfield(L, -1, "traceback");
03703 lua_remove(L, -2);
03704 lua_rawset(L, LUA_REGISTRYINDEX);
03705
03706
03707 lua_getglobal(L, "os");
03708 lua_pushnil(L);
03709 while(lua_next(L, -2) != 0) {
03710 lua_pop(L, 1);
03711 char const* function = lua_tostring(L, -1);
03712 if(strcmp(function, "clock") == 0 || strcmp(function, "date") == 0
03713 || strcmp(function, "time") == 0 || strcmp(function, "difftime") == 0) continue;
03714 lua_pushnil(L);
03715 lua_setfield(L, -3, function);
03716 }
03717 lua_pop(L, 1);
03718
03719
03720 lua_getglobal(L, "debug");
03721 lua_pushnil(L);
03722 while(lua_next(L, -2) != 0) {
03723 lua_pop(L, 1);
03724 char const* function = lua_tostring(L, -1);
03725 if(strcmp(function, "traceback") == 0) continue;
03726 lua_pushnil(L);
03727 lua_setfield(L, -3, function);
03728 }
03729 lua_pop(L, 1);
03730
03731 lua_settop(L, 0);
03732 }
03733
03734 void LuaKernel::initialize()
03735 {
03736 lua_State *L = mState;
03737
03738
03739
03740
03741
03742 lua_getglobal(L, "wesnoth");
03743 std::vector<team> &teams = *resources::teams;
03744 lua_pushlightuserdata(L
03745 , static_cast<void *>(const_cast<char *>(&getsideKey)));
03746 lua_rawget(L, LUA_REGISTRYINDEX);
03747 lua_createtable(L, teams.size(), 0);
03748 for (unsigned i = 0; i != teams.size(); ++i)
03749 {
03750
03751 team **p = static_cast<team **>(lua_newuserdata(L, sizeof(team *)));
03752 *p = &teams[i];
03753 lua_pushvalue(L, -3);
03754 lua_setmetatable(L, -2);
03755 lua_rawseti(L, -2, i + 1);
03756 }
03757 lua_setfield(L, -3, "sides");
03758 lua_pop(L, 2);
03759
03760
03761 lua_getglobal(L, "wesnoth");
03762 lua_pushlightuserdata(L
03763 , static_cast<void *>(const_cast<char *>(&gettypeKey)));
03764 lua_rawget(L, LUA_REGISTRYINDEX);
03765 lua_newtable(L);
03766 foreach (const unit_type_data::unit_type_map::value_type &ut, unit_types.types())
03767 {
03768 lua_createtable(L, 0, 1);
03769 lua_pushstring(L, ut.first.c_str());
03770 lua_setfield(L, -2, "id");
03771 lua_pushvalue(L, -3);
03772 lua_setmetatable(L, -2);
03773 lua_setfield(L, -2, ut.first.c_str());
03774 }
03775 lua_setfield(L, -3, "unit_types");
03776 lua_pop(L, 2);
03777
03778
03779 lua_getglobal(L, "wesnoth");
03780 lua_pushlightuserdata(L
03781 , static_cast<void *>(const_cast<char *>(&getraceKey)));
03782 lua_rawget(L, LUA_REGISTRYINDEX);
03783 const race_map& races = unit_types.races();
03784 lua_createtable(L, 0, races.size());
03785 foreach(const race_map::value_type &race, races)
03786 {
03787 lua_createtable(L, 0, 1);
03788 char const* id = race.first.c_str();
03789 lua_pushstring(L, id);
03790 lua_setfield(L, -2, "id");
03791 lua_pushvalue(L, -3);
03792 lua_setmetatable(L, -2);
03793 lua_setfield(L, -2, id);
03794 }
03795 lua_setfield(L, -3, "races");
03796 lua_pop(L, 2);
03797
03798
03799 game_config::load_config(preload_config);
03800 foreach (const config &cfg, preload_scripts) {
03801 execute(cfg["code"].str().c_str(), 0, 0);
03802 }
03803 foreach (const config &cfg, level_.child_range("lua")) {
03804 execute(cfg["code"].str().c_str(), 0, 0);
03805 }
03806
03807 load_game();
03808 }
03809
03810 static char const *handled_file_tags[] = {
03811 "color_palette", "color_range", "era", "event", "generator",
03812 "label", "lua", "map", "menu_item", "music", "side", "sound_source", "story",
03813 "terrain_graphics", "time", "time_area", "tunnel", "variables", "endlevel",
03814 "display",
03815
03816 "snapshot", "multiplayer", "replay_start"
03817 };
03818
03819 static bool is_handled_file_tag(const std::string &s)
03820 {
03821 foreach (char const *t, handled_file_tags) {
03822 if (s == t) return true;
03823 }
03824 return false;
03825 }
03826
03827
03828
03829
03830
03831 void LuaKernel::load_game()
03832 {
03833 lua_State *L = mState;
03834
03835 if (!luaW_getglobal(L, "wesnoth", "game_events", "on_load", NULL))
03836 return;
03837
03838 lua_newtable(L);
03839 int k = 1;
03840 foreach (const config::any_child &v, level_.all_children_range())
03841 {
03842 if (is_handled_file_tag(v.key)) continue;
03843 lua_createtable(L, 2, 0);
03844 lua_pushstring(L, v.key.c_str());
03845 lua_rawseti(L, -2, 1);
03846 luaW_pushconfig(L, v.cfg);
03847 lua_rawseti(L, -2, 2);
03848 lua_rawseti(L, -2, k++);
03849 }
03850
03851 luaW_pcall(L, 1, 0, true);
03852 }
03853
03854
03855
03856
03857
03858 void LuaKernel::save_game(config &cfg)
03859 {
03860 foreach (const config &v, level_.child_range("lua")) {
03861 cfg.add_child("lua", v);
03862 }
03863
03864 lua_State *L = mState;
03865
03866 if (!luaW_getglobal(L, "wesnoth", "game_events", "on_save", NULL))
03867 return;
03868
03869 if (!luaW_pcall(L, 0, 1, false))
03870 return;
03871
03872 config v;
03873 luaW_toconfig(L, -1, v);
03874 lua_pop(L, 1);
03875
03876 for (;;)
03877 {
03878 config::all_children_iterator i = v.ordered_begin();
03879 if (i == v.ordered_end()) break;
03880 if (is_handled_file_tag(i->key))
03881 {
03882
03883
03884
03885
03886
03887 const std::string m = "Tag is already used: [" + i->key + "]";
03888 chat_message("Lua error", m);
03889 ERR_LUA << m << '\n';
03890 v.erase(i);
03891 continue;
03892 }
03893 cfg.splice_children(v, i->key);
03894 }
03895 }
03896
03897
03898
03899
03900
03901 bool LuaKernel::run_event(game_events::queued_event const &ev)
03902 {
03903 lua_State *L = mState;
03904
03905 if (!luaW_getglobal(L, "wesnoth", "game_events", "on_event", NULL))
03906 return false;
03907
03908 queued_event_context dummy(&ev);
03909 lua_pushstring(L, ev.name.c_str());
03910 luaW_pcall(L, 1, 0, false);
03911 return true;
03912 }
03913
03914 LuaKernel::~LuaKernel()
03915 {
03916 lua_close(mState);
03917 }
03918
03919
03920
03921
03922 static int cfun_wml_action(lua_State *L)
03923 {
03924 game_events::action_handler h = reinterpret_cast<game_events::action_handler>
03925 (lua_touserdata(L, lua_upvalueindex(1)));
03926
03927 vconfig vcfg = luaW_checkvconfig(L, 1);
03928 h(queued_event_context::get(), vcfg);
03929 return 0;
03930 }
03931
03932
03933
03934
03935 void LuaKernel::set_wml_action(std::string const &cmd, game_events::action_handler h)
03936 {
03937 lua_State *L = mState;
03938
03939 lua_getglobal(L, "wesnoth");
03940 lua_pushstring(L, "wml_actions");
03941 lua_rawget(L, -2);
03942 lua_pushstring(L, cmd.c_str());
03943 lua_pushlightuserdata(L, reinterpret_cast<void *>(h));
03944 lua_pushcclosure(L, cfun_wml_action, 1);
03945 lua_rawset(L, -3);
03946 lua_pop(L, 2);
03947 }
03948
03949
03950
03951
03952
03953
03954
03955 bool LuaKernel::run_wml_action(std::string const &cmd, vconfig const &cfg,
03956 game_events::queued_event const &ev)
03957 {
03958 lua_State *L = mState;
03959
03960
03961 if (!luaW_getglobal(L, "wesnoth", "wml_actions", cmd.c_str(), NULL))
03962 return false;
03963
03964 queued_event_context dummy(&ev);
03965 luaW_pushvconfig(L, cfg);
03966 luaW_pcall(L, 1, 0, true);
03967 return true;
03968 }
03969
03970
03971
03972
03973
03974
03975 bool LuaKernel::run_filter(char const *name, unit const &u)
03976 {
03977 lua_State *L = mState;
03978
03979 unit_map::const_unit_iterator ui = resources::units->find(u.get_location());
03980 if (!ui.valid()) return false;
03981
03982
03983 luaW_getglobal(L, name, NULL);
03984
03985
03986 new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(ui->underlying_id());
03987 lua_pushlightuserdata(L
03988 , static_cast<void *>(const_cast<char *>(&getunitKey)));
03989 lua_rawget(L, LUA_REGISTRYINDEX);
03990 lua_setmetatable(L, -2);
03991
03992 if (!luaW_pcall(L, 1, 1)) return false;
03993
03994 bool b = lua_toboolean(L, -1);
03995 lua_pop(L, 1);
03996 return b;
03997 }
03998
03999
04000
04001
04002
04003 bool LuaKernel::execute(char const *prog, int nArgs, int nRets)
04004 {
04005 lua_State *L = mState;
04006
04007
04008 int res = luaL_loadstring(L, prog);
04009 if (res)
04010 {
04011 char const *m = lua_tostring(L, -1);
04012 chat_message("Lua error", m);
04013 ERR_LUA << m << '\n';
04014 lua_pop(L, 1);
04015 return false;
04016 }
04017
04018
04019 if (nArgs)
04020 lua_insert(L, -1 - nArgs);
04021
04022 return luaW_pcall(L, nArgs, nRets);
04023 }
04024
04025
04026
04027
04028
04029
04030
04031 void LuaKernel::load_package()
04032 {
04033 lua_State *L = mState;
04034 lua_pushcfunction(L, luaopen_package);
04035 lua_pushstring(L, "package");
04036 lua_call(L, 1, 0);
04037 }
04038
04039 ai::lua_ai_context* LuaKernel::create_lua_ai_context(char const *code, ai::engine_lua *engine)
04040 {
04041 return ai::lua_ai_context::create(mState,code,engine);
04042 }
04043
04044 ai::lua_ai_action_handler* LuaKernel::create_lua_ai_action_handler(char const *code, ai::lua_ai_context &context)
04045 {
04046 return ai::lua_ai_action_handler::create(mState,code,context);
04047 }