void frmMain::_onSaveMenuSave(wxCommandEvent& evt) { if(m_sFilename.empty()) { _onSaveMenuSaveAs(evt); return; } map_save_t oSave; if(oSave.fFile.Open(m_sFilename, wxFile::write)) { lua_State* L = m_pGamePanel->getLua(); luaT_execute(L, "return TheApp.world.map.th"); THMap *pMap = reinterpret_cast<THMap*>(lua_touserdata(L, -1)); lua_pop(L, 1); THMapWrapper::autoSetHelipad(pMap); luaT_execute(L, "return TheApp.ui:ScreenToWorld(...)", m_pGamePanel->GetSize().GetWidth() / 2, m_pGamePanel->GetSize().GetHeight() / 2); int iCameraX = (int)lua_tointeger(L, -2); int iCameraY = (int)lua_tointeger(L, -1); lua_pop(L, 2); pMap->setPlayerCameraTile(0, iCameraX, iCameraY); pMap->save(map_save_t::writer, reinterpret_cast<void*>(&oSave)); ::wxMessageBox(wxT("Map saved."), wxT("Save"), wxOK | wxCENTER | wxICON_INFORMATION, this); } }
int ScrollableGamePanel::_l_init_with_app(lua_State *L) { // Call the original MapEditorInitWithLuaApp function lua_pushvalue(L, lua_upvalueindex(1)); if(lua_type(L, -1) == LUA_TNIL) lua_pop(L, 1); else { lua_insert(L, 1); lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); } // Wrap our _l_on_ui_scroll_map function around GameUI:scrollMap() // 1st upvalue: original GameUI:scrollMap() function // 2nd upvalue: light userdata this // This has to be done with the Lua App initialisation as we need for // dofile() to be the custom dofile() used by CorsixTH, rather than the // default one present at Lua initialisation time. luaT_execute(L, "dofile [[game_ui]]"); lua_getglobal(L, "GameUI"); lua_getfield(L, -1, "scrollMap"); lua_pushvalue(L, lua_upvalueindex(2)); lua_pushcclosure(L, _l_on_ui_scroll_map, 2); lua_setfield(L, -2, "scrollMap"); return lua_gettop(L); }
void frmMain::_applyViewOverlay() { if(m_bViewFlags || m_bViewParcels) { lua_State *L = m_pGamePanel->getLua(); luaT_execute(L, "return TheApp.gfx:loadBuiltinFont(), TheApp.map.cell_outline"); THFont *pFont = reinterpret_cast<THFont*>(lua_touserdata(L, -2)); THSpriteSheet *pSprites = reinterpret_cast<THSpriteSheet*>(lua_touserdata(L, -1)); lua_pop(L, 2); THMapTypicalOverlay *pFlags = NULL; THMapTypicalOverlay *pParcels = NULL; if(m_bViewFlags) { pFlags = new THMapFlagsOverlay; pFlags->setFont(pFont, false); pFlags->setSprites(pSprites, false); } if(m_bViewParcels) { pParcels = new THMapParcelsOverlay; pParcels->setFont(pFont, false); pParcels->setSprites(pSprites, false); } THMapOverlayPair *pOverlays = new THMapOverlayPair; pOverlays->setFirst(pParcels, true); pOverlays->setSecond(pFlags, true); m_pGamePanel->getMap()->setOverlay(pOverlays, true); } else m_pGamePanel->getMap()->setOverlay(NULL, false); }
int frmMain::_l_init(lua_State *L) { frmMain *pThis = reinterpret_cast<frmMain*>(lua_touserdata(L, 1)); THMapWrapper::wrap(L); // Create a new environment table: { // [1] = <light userdata pThis>, // } lua_newtable(L); lua_insert(L, 1); lua_rawseti(L, 1, 1); lua_replace(L, LUA_ENVIRONINDEX); // NB: Following functions registered with above environment table luaT_execute(L, "MapEditorSetBlocks = ...", _l_set_blocks); luaT_execute(L, "MapEditorSetBlockBrush = ...", _l_set_block_brush); luaT_execute(L, "MapEditorInitWithLuaApp = ...", _l_init_with_lua_app); return 0; }
int CorsixTH_lua_main_no_eval(lua_State *L) { // assert(_VERSION == LUA_VERSION) size_t iLength; lua_getglobal(L, "_VERSION"); const char* sVersion = lua_tolstring(L, -1, &iLength); if(iLength != strlen(LUA_VERSION) || strcmp(sVersion, LUA_VERSION) != 0) { lua_pushliteral(L, "Linked against a version of Lua different to the " "one used when compiling.\nPlease recompile CorsixTH against the " "same Lua version it is linked against."); return lua_error(L); } lua_pop(L, 1); // registry._CLEANUP = {} lua_newtable(L); lua_setfield(L, LUA_REGISTRYINDEX, "_CLEANUP"); // math.random* = Mersenne twister variant luaT_cpcall(L, luaopen_random, NULL); // package.preload["jit.opt"] = load(jit_opt_lua) // package.preload["jit.opt_inline"] = load(jit_opt_inline_lua) lua_getglobal(L, "package"); lua_getfield(L, -1, "preload"); luaL_loadbuffer(L, (const char*)jit_opt_lua, sizeof(jit_opt_lua), "jit/opt.luac"); lua_setfield(L, -2, "jit.opt"); luaL_loadbuffer(L, (const char*)jit_opt_inline_lua, sizeof(jit_opt_inline_lua), "jit/opt_inline.luac"); lua_setfield(L, -2, "jit.opt_inline"); lua_pop(L, 2); // if registry._LOADED.jit then // require"jit.opt".start() // else // print "Notice: ..." // end // (this could be done in Lua rather than here, but ideally the optimiser // should be turned on before any Lua code is loaded) lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_getfield(L, -1, "jit"); if(lua_type(L, -1) == LUA_TNIL) { lua_pop(L, 2); lua_getglobal(L, "print"); lua_pushliteral(L, "Notice: LuaJIT not being used.\nConsider replacing" " Lua with LuaJIT to improve performance."); #ifdef CORSIX_TH_64BIT lua_pushliteral(L, " Note that there is not currently a 64 bit version" " of LuaJIT."); lua_concat(L, 2); #endif lua_call(L, 1, 0); } else { lua_pop(L, 2); lua_getglobal(L, "require"); lua_pushliteral(L, "jit.opt"); lua_call(L, 1, 1); lua_getfield(L, -1, "start"); lua_call(L, 0, 0); lua_pop(L, 1); } // Fill in package.preload table so that calls to require("X") from Lua // will call the appropriate luaopen_X function in C. #define PRELOAD(name, fn) \ luaT_execute(L, "package.preload." name " = ...", fn) PRELOAD("lfs", luaopen_lfs_ext); PRELOAD("lpeg", luaopen_lpeg); PRELOAD("rnc", luaopen_rnc); PRELOAD("TH", luaopen_th); PRELOAD("ISO_FS", luaopen_iso_fs); PRELOAD("persist", luaopen_persist); PRELOAD("sdl", luaopen_sdl); #undef PRELOAD // require "debug" (Harmless in Lua 5.1, useful in 5.2 for compatbility) luaT_execute(L, "require \"debug\""); // Check for --interpreter and run that instead of CorsixTH.lua bool bGotScriptFile = false; int iNArgs = lua_gettop(L); for(int i = 1; i <= iNArgs; ++i) { if(lua_type(L, i) == LUA_TSTRING) { size_t iLen; const char* sCmd = lua_tolstring(L, i, &iLen); if(iLen > 14 && memcmp(sCmd, "--interpreter=", 14) == 0) { lua_getglobal(L, "assert"); lua_getglobal(L, "loadfile"); lua_pushlstring(L, sCmd + 14, iLen - 14); bGotScriptFile = true; break; } } } // Code to try several variations on finding CorsixTH.lua: // CorsixTH.lua // CorsixTH/CorsixTH.lua // ../CorsixTH.lua // ../CorsixTH/CorsixTH.lua // ../../CorsixTH.lua // ../../CorsixTH/CorsixTH.lua // ../../../CorsixTH.lua // ../../../CorsixTH/CorsixTH.lua // It is simpler to write this in Lua than in C. const char sLuaCorsixTHLuaOld[] = "local name, sep, code = \"CorsixTH.lua\", package.config:sub(1, 1)\n" "local root = (... or \"\"):match(\"^(.*[\"..sep..\"])\") or \"\"\n" "code = loadfile(\"%s\"..name)\n" "if code then return code end\n" #ifdef __APPLE__ // Darrell: Search inside the bundle first. // There's probably a better way of doing this. #if defined(IS_CORSIXTH_APP) "code = loadfile(\"CorsixTH.app/Contents/Resources/\"..name)\n" "if code then return code end\n" #elif defined(IS_MAPEDIT_APP) "code = loadfile(\"MapEdit.app/Contents/Resources/\"..name)\n" "if code then return code end\n" #endif #endif "for num_dotdot = 0, 3 do\n" " for num_dir = 0, 1 do\n" " code = loadfile(root..(\"..\"..sep):rep(num_dotdot)..\n" " (\"CorsixTH\"..sep):rep(num_dir)..name)\n" " if code then return code end \n" " end \n" "end \n" "return loadfile(name)"; char sLuaCorsixTHLua[sizeof(sLuaCorsixTHLuaOld) + sizeof(path)]; sprintf(sLuaCorsixTHLua, sLuaCorsixTHLuaOld, path); //LOGI(sLuaCorsixTHLua); // return assert(loadfile"CorsixTH.lua")(...) if(!bGotScriptFile) { lua_getglobal(L, "assert"); luaL_loadbuffer(L, sLuaCorsixTHLua, strlen(sLuaCorsixTHLua), "@main.cpp (l_main bootstrap)"); if(lua_gettop(L) == 2) lua_pushnil(L); else lua_pushvalue(L, 1); } lua_call(L, 1, 2); lua_call(L, 2, 1); lua_insert(L, 1); return lua_gettop(L); }
void frmMain::_setLuaBlockBrush(int iBlockF, int iBlockW1, int iBlockW2) { lua_State *L = m_pGamePanel->getLua(); luaT_execute(L, "_MAP_EDITOR:setBlockBrush(...)", iBlockF, iBlockW1, iBlockW2); }
void frmMain::_setLuaParcelBrush(int iParcel) { m_iParcelBrush = iParcel; lua_State *L = m_pGamePanel->getLua(); luaT_execute(L, "_MAP_EDITOR:setBlockBrushParcel(...)", iParcel); }
void frmMain::_populateParcelGallery(wxRibbonGallery* pGallery) { THSpriteSheet *pBlocksSheet; THSpriteSheet *pOutlineSheet; THSpriteSheet *pFontSheet; { lua_State *L = m_pGamePanel->getLua(); luaT_execute(L, "return TheApp.map.blocks"); pBlocksSheet = reinterpret_cast<THSpriteSheet*>(lua_touserdata(L, -1)); luaT_execute(L, "return TheApp.map.cell_outline"); pOutlineSheet = reinterpret_cast<THSpriteSheet*>(lua_touserdata(L, -1)); luaT_execute(L, "return TheApp.gfx:loadBuiltinFont()"); pFontSheet = reinterpret_cast<THBitmapFont*>(lua_touserdata(L, -1)) ->getSpriteSheet(); lua_pop(L, 3); } wxBitmap bmOutline(_asBitmap(pBlocksSheet, 74)); wxMemoryDC dcMem; dcMem.SelectObject(bmOutline); for(int i = 0; i < 4; ++i) { dcMem.DrawBitmap(_asBitmap(pOutlineSheet, 18 + i), 0, 0); } dcMem.SelectObject(wxNullBitmap); wxBitmap bmNumbers[10]; for(int i = 0; i < 10; ++i) { bmNumbers[i] = _asBitmap(pFontSheet, '0' + i - 31); } for(intptr_t iParcel = 0; iParcel < 32; ++iParcel) { wxBitmap bmParcel(bmOutline); dcMem.SelectObject(bmParcel); char sMsg[8]; #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4996) #endif sprintf(sMsg, "%i", iParcel); #ifdef _MSC_VER #pragma warning(pop) #endif int iX = 0, iY = 0; for(char* s = sMsg; *s; ++s) { wxBitmap& bm = bmNumbers[*s - '0']; iX += bm.GetWidth(); iY = std::max(iY, bm.GetHeight()); } iX = (bmParcel.GetWidth() - iX) / 2; iY = (bmParcel.GetHeight() - iY) / 2; for(char* s = sMsg; *s; ++s) { wxBitmap& bm = bmNumbers[*s - '0']; dcMem.DrawBitmap(bm, iX, iY); iX += bm.GetWidth(); } dcMem.SelectObject(wxNullBitmap); pGallery->SetItemClientData(pGallery->Append(bmParcel, iParcel), reinterpret_cast<void*>(iParcel)); } }
bool EmbeddedGamePanel::loadLua() { // Create state m_L = luaL_newstate(); lua_atpanic(m_L, _l_panic); // Save a pointer to ourselves in the registry lua_pushliteral(m_L, "wxWindow"); lua_pushlightuserdata(m_L, reinterpret_cast<wxWindow*>(this)); lua_settable(m_L, LUA_REGISTRYINDEX); // Open default libraries, and override appropriate bits luaL_openlibs(m_L); luaT_execute(m_L, "print = ...", _l_print); // Set _MAP_EDITOR to true, to allow scripts to notice that they are // running inside this component, rather than standalone. luaT_execute(m_L, "_MAP_EDITOR = true"); // Load CorsixTH.lua and perform other initialisation needed by it lua_settop(m_L, 0); lua_pushcfunction(m_L, CorsixTH_lua_stacktrace); lua_pushcfunction(m_L, CorsixTH_lua_main_no_eval); lua_checkstack(m_L, wxTheApp->argc); for(int i = 0; i < wxTheApp->argc; ++ i) lua_pushstring(m_L, wxTheApp->argv[i]); if(lua_pcall(m_L, wxTheApp->argc, 1, 1)) { if(m_pPrintTarget) { m_pPrintTarget->AppendText(L"Error initialising Lua: "); m_pPrintTarget->AppendText(lua_tostring(m_L, -1)); m_pPrintTarget->AppendText(L"\n"); } return false; } // NB: CorsixTH_lua_main_no_eval will have loaded CorsixTH.lua and left it // as the top value on the stack, but will not have executed it. // The stack will hence have two things on it: the stacktrace function, // and the loaded CorsixTH.lua // Overwrite what CorsixTH_lua_main_no_eval registered for require("sdl") // with our own function that uses wxWidgets to do what SDL would have. luaT_execute(m_L, "package.preload.sdl = ...", _l_open_sdl); // Replace the Surface:endFrame() function with our own lua_getglobal(m_L, "require"); lua_pushliteral(m_L, "TH"); lua_call(m_L, 1, 1); lua_getfield(m_L, -1, "surface"); lua_getfield(m_L, -1, "endFrame"); lua_pushcclosure(m_L, _l_end_frame, 1); lua_setfield(m_L, -2, "endFrame"); lua_pop(m_L, 2); // Perform extra initialisation if(m_fnExtraLuaInit) { if(lua_cpcall(m_L, m_fnExtraLuaInit, m_pExtraLuaInitArg) != 0) lua_pop(m_L, 1); } // Execute CorsixTH.lua in a coroutine lua_getglobal(m_L, "coroutine"); lua_getfield(m_L, -1, "create"); lua_replace(m_L, -2); lua_insert(m_L, -2); lua_call(m_L, 1, 1); lua_State *L = lua_tothread(m_L, -1); if(lua_resume(L, 0) != LUA_YIELD) { if(m_pPrintTarget) { // Push debug.traceback onto m_L lua_getglobal(m_L, "debug"); lua_getfield(m_L, -1, "traceback"); lua_replace(m_L, -2); // Push the thread onto m_L lua_pushvalue(m_L, -2); // Push tostring(errmsg) onto m_L lua_getglobal(m_L, "tostring"); lua_xmove(L, m_L, 1); lua_call(m_L, 1, 1); // Push constant 1 onto m_L lua_pushinteger(m_L, 1); // Call debug.traceback(thread, tostring(err), 1) lua_call(m_L, 3, 1); // Display resulting string and pop it m_pPrintTarget->AppendText(L"Error initialising Lua: "); m_pPrintTarget->AppendText(lua_tostring(m_L, -1)); m_pPrintTarget->AppendText(L"\n"); lua_pop(m_L, 1); } return false; } lua_settop(L, 1); m_Lthread = L; // The stack of the Lua states is now as follows: // m_L: stacktrace function, m_Lthread <top // m_Lthread: event dispatch coroutine <top return true; }