// Generic string method handler // The name of the method is stored at upvalue 1 static int l_str_func(lua_State *L) { int iArgCount = lua_gettop(L); lua_checkstack(L, iArgCount + 10); int iUserdataCount = 0; // Construct the resulting value aux_push_weak_table(L, 0); for(int i = 1; i <= iArgCount; ++i) { lua_pushvalue(L, i); if(lua_type(L, i) == LUA_TUSERDATA) { lua_rawget(L, iArgCount + 1); ++iUserdataCount; } } lua_pushvalue(L, luaT_upvalueindex(1)); lua_gettable(L, iArgCount + 2); lua_replace(L, iArgCount + 1); lua_call(L, iArgCount, 1); // Trivial case of result not depending upon any proxies if(iUserdataCount == 0) return 1; // Wrap result in a proxy l_str_new_aux(L); // Create and save reconstruction information lua_createtable(L, iArgCount + 1, 0); lua_pushvalue(L, luaT_upvalueindex(1)); lua_rawseti(L, -2, 1); for(int i = 1; i <= iArgCount; ++i) { lua_pushvalue(L, i); lua_rawseti(L, -2, i + 1); } lua_setfenv(L, -2); return 1; }
static int l_mk_cache(lua_State *L) { lua_newtable(L); lua_pushvalue(L, luaT_upvalueindex(1)); lua_setmetatable(L, -2); lua_pushvalue(L, 2); lua_pushvalue(L, 3); lua_settable(L, 1); return 1; }
static int l_map_hittest(lua_State *L) { level_map* pMap = luaT_testuserdata<level_map>(L); drawable* pObject = pMap->hit_test(static_cast<int>(luaL_checkinteger(L, 2)), static_cast<int>(luaL_checkinteger(L, 3))); if(pObject == nullptr) return 0; lua_rawgeti(L, luaT_upvalueindex(1), 1); lua_pushlightuserdata(L, pObject); lua_gettable(L, -2); return 1; }
void setErrorObject(int iStackObject) { if(m_bHadError) return; lua_State *L = m_L; lua_pushvalue(L, iStackObject); lua_getmetatable(L, luaT_upvalueindex(2)); lua_insert(L, -2); lua_setfield(L, -2, "err"); lua_pop(L, 1); }
static int l_get_fps(lua_State *L) { fps_ctrl *ctrl = (fps_ctrl*)lua_touserdata(L, luaT_upvalueindex(1)); if(ctrl->track_fps) { lua_pushinteger(L, ctrl->frame_count); } else { lua_pushnil(L); } return 1; }
void init(const uint8_t *pData, size_t iLength) { lua_State *L = m_L; m_pData = pData; m_iDataBufferLength = iLength; m_iNextIndex = 1; m_bHadError = false; lua_createtable(L, 32, 0); // Environment lua_pushvalue(L, 2); lua_rawseti(L, -2, 0); lua_pushvalue(L, luaT_upvalueindex(1)); lua_rawseti(L, -2, -1); lua_pushvalue(L, luaT_upvalueindex(2)); lua_rawseti(L, -2, -2); lua_pushvalue(L, 1); lua_rawseti(L, -2, -3); lua_setfenv(L, 1); lua_createtable(L, 0, 1); // Metatable lua_pushcclosure(L, l_crude_gc<LuaPersistBasicReader>, 0); lua_setfield(L, -2, "__gc"); lua_setmetatable(L, 1); }
static int l_anims_draw(lua_State *L) { THAnimationManager* pAnims = luaT_testuserdata<THAnimationManager>(L); THRenderTarget* pCanvas = luaT_testuserdata<THRenderTarget>(L, 2); int iFrame = luaL_checkint(L, 3); THLayers_t* pLayers = luaT_testuserdata<THLayers_t>(L, 4, luaT_upvalueindex(2)); int iX = luaL_checkint(L, 5); int iY = luaL_checkint(L, 6); int iFlags = luaL_optint(L, 7, 0); pAnims->drawFrame(pCanvas, (unsigned int)iFrame, *pLayers, iX, iY, iFlags); lua_settop(L, 1); return 1; }
static int l_rawbitmap_load(lua_State *L) { THRawBitmap* pBitmap = luaT_testuserdata<THRawBitmap>(L); size_t iDataLen; const uint8_t* pData = luaT_checkfile(L, 2, &iDataLen); int iWidth = static_cast<int>(luaL_checkinteger(L, 3)); THRenderTarget* pSurface = luaT_testuserdata<THRenderTarget>(L, 4, luaT_upvalueindex(1), false); if(pBitmap->loadFromTHFile(pData, iDataLen, iWidth, pSurface)) lua_pushboolean(L, 1); else lua_pushboolean(L, 0); return 1; }
static int l_spritesheet_load(lua_State *L) { THSpriteSheet* pSheet = luaT_testuserdata<THSpriteSheet>(L); size_t iDataLenTable, iDataLenChunk; const uint8_t* pDataTable = luaT_checkfile(L, 2, &iDataLenTable); const uint8_t* pDataChunk = luaT_checkfile(L, 3, &iDataLenChunk); bool bComplex = lua_toboolean(L, 4) != 0; THRenderTarget* pSurface = luaT_testuserdata<THRenderTarget>(L, 5, luaT_upvalueindex(1), false); if(pSheet->loadFromTHFile(pDataTable, iDataLenTable, pDataChunk, iDataLenChunk, bComplex, pSurface)) lua_pushboolean(L, 1); else lua_pushboolean(L, 0); return 1; }
void init() { lua_State *L = m_L; lua_createtable(L, 1, 8); // Environment lua_pushvalue(L, 2); // Permanent objects lua_rawseti(L, -2, 1); lua_createtable(L, 1, 0); // Environment metatable lua_pushvalue(L, 2); // Permanent objects lua_pushvalue(L, 1); // self lua_pushcclosure(L, l_writer_mt_index, 2); lua_setfield(L, -2, "__index"); lua_setmetatable(L, -2); lua_setfenv(L, 1); lua_createtable(L, 1, 4); // Metatable lua_pushcclosure(L, l_crude_gc<LuaPersistBasicWriter>, 0); lua_setfield(L, -2, "__gc"); lua_pushvalue(L, luaT_upvalueindex(1)); // Prototype persistance names lua_rawseti(L, -2, 1); lua_setmetatable(L, 1); m_iNextIndex = 1; m_iDataLength = 0; m_bHadError = false; }
static int l_map_updateblueprint(lua_State *L) { // NB: This function can be implemented in Lua, but is implemented in C for // efficiency. const unsigned short iFloorTileGood = 24 + (THDF_Alpha50 << 8); const unsigned short iFloorTileGoodCenter = 37 + (THDF_Alpha50 << 8); const unsigned short iFloorTileBad = 67 + (THDF_Alpha50 << 8); const unsigned int iWallAnimTopCorner = 124; const unsigned int iWallAnim = 120; THMap* pMap = luaT_testuserdata<THMap>(L); int iOldX = static_cast<int>(luaL_checkinteger(L, 2)) - 1; int iOldY = static_cast<int>(luaL_checkinteger(L, 3)) - 1; int iOldW = static_cast<int>(luaL_checkinteger(L, 4)); int iOldH = static_cast<int>(luaL_checkinteger(L, 5)); int iNewX = static_cast<int>(luaL_checkinteger(L, 6)) - 1; int iNewY = static_cast<int>(luaL_checkinteger(L, 7)) - 1; int iNewW = static_cast<int>(luaL_checkinteger(L, 8)); int iNewH = static_cast<int>(luaL_checkinteger(L, 9)); luaL_checktype(L, 10, LUA_TTABLE); // Animation list THAnimationManager* pAnims = luaT_testuserdata<THAnimationManager>(L, 11, luaT_upvalueindex(1)); bool entire_invalid = lua_toboolean(L, 12) != 0; bool valid = !entire_invalid; if(iOldX < 0 || iOldY < 0 || (iOldX + iOldW) > pMap->getWidth() || (iOldY + iOldH) > pMap->getHeight()) luaL_argerror(L, 2, "Old rectangle is out of bounds"); if(iNewX < 0 || iNewY < 0 || (iNewX + iNewW) >= pMap->getWidth() || (iNewY + iNewH) >= pMap->getHeight()) luaL_argerror(L, 6, "New rectangle is out of bounds"); // Clear blueprint flag from previous selected floor tiles (copying it to the passable flag). for(int iY = iOldY; iY < iOldY + iOldH; ++iY) { for(int iX = iOldX; iX < iOldX + iOldW; ++iX) { THMapNode *pNode = pMap->getNodeUnchecked(iX, iY); pNode->iBlock[3] = 0; uint32_t iFlags = pNode->iFlags; iFlags |= ((iFlags & THMN_PassableIfNotForBlueprint) != 0) ? THMN_Passable : 0; iFlags &= ~THMN_PassableIfNotForBlueprint; pNode->iFlags = iFlags; } } // Add blueprint flag to new floor tiles. for(int iY = iNewY; iY < iNewY + iNewH; ++iY) { for(int iX = iNewX; iX < iNewX + iNewW; ++iX) { THMapNode *pNode = pMap->getNodeUnchecked(iX, iY); if(is_valid(entire_invalid, pNode)) pNode->iBlock[3] = iFloorTileGood; else { pNode->iBlock[3] = iFloorTileBad; valid = false; } pNode->iFlags |= ((pNode->iFlags & THMN_Passable) != 0) ? THMN_PassableIfNotForBlueprint : 0; } } // Set center floor tiles if(iNewW >= 2 && iNewH >= 2) { int iCenterX = iNewX + (iNewW - 2) / 2; int iCenterY = iNewY + (iNewH - 2) / 2; THMapNode *pNode = pMap->getNodeUnchecked(iCenterX, iCenterY); if(pNode->iBlock[3] == iFloorTileGood) pNode->iBlock[3] = iFloorTileGoodCenter + 2; pNode = pMap->getNodeUnchecked(iCenterX + 1, iCenterY); if(pNode->iBlock[3] == iFloorTileGood) pNode->iBlock[3] = iFloorTileGoodCenter + 1; pNode = pMap->getNodeUnchecked(iCenterX, iCenterY + 1); if(pNode->iBlock[3] == iFloorTileGood) pNode->iBlock[3] = iFloorTileGoodCenter + 0; pNode = pMap->getNodeUnchecked(iCenterX + 1, iCenterY + 1); if(pNode->iBlock[3] == iFloorTileGood) pNode->iBlock[3] = iFloorTileGoodCenter + 3; } // Set wall animations int iNextAnim = 1; THAnimation *pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim); THMapNode *pNode = pMap->getNodeUnchecked(iNewX, iNewY); pAnim->setAnimation(pAnims, iWallAnimTopCorner); pAnim->setFlags(THDF_ListBottom | (is_valid(entire_invalid, pNode) ? 0 : THDF_AltPalette)); pAnim->attachToTile(pNode, 0); for(int iX = iNewX; iX < iNewX + iNewW; ++iX) { if(iX != iNewX) { pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim); pNode = pMap->getNodeUnchecked(iX, iNewY); pAnim->setAnimation(pAnims, iWallAnim); pAnim->setFlags(THDF_ListBottom | (is_valid(entire_invalid, pNode) ? 0 : THDF_AltPalette)); pAnim->attachToTile(pNode, 0); pAnim->setPosition(0, 0); } pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim); pNode = pMap->getNodeUnchecked(iX, iNewY + iNewH - 1); pAnim->setAnimation(pAnims, iWallAnim); pAnim->setFlags(THDF_ListBottom | (is_valid(entire_invalid, pNode) ? 0 : THDF_AltPalette)); pNode = pMap->getNodeUnchecked(iX, iNewY + iNewH); pAnim->attachToTile(pNode, 0); pAnim->setPosition(0, -1); } for(int iY = iNewY; iY < iNewY + iNewH; ++iY) { if(iY != iNewY) { pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim); pNode = pMap->getNodeUnchecked(iNewX, iY); pAnim->setAnimation(pAnims, iWallAnim); pAnim->setFlags(THDF_ListBottom | THDF_FlipHorizontal | (is_valid(entire_invalid, pNode) ? 0 : THDF_AltPalette)); pAnim->attachToTile(pNode, 0); pAnim->setPosition(2, 0); } pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim); pNode = pMap->getNodeUnchecked(iNewX + iNewW - 1, iY); pAnim->setAnimation(pAnims, iWallAnim); pAnim->setFlags(THDF_ListBottom | THDF_FlipHorizontal | (is_valid(entire_invalid, pNode) ? 0 : THDF_AltPalette)); pNode = pMap->getNodeUnchecked(iNewX + iNewW, iY); pAnim->attachToTile(pNode, 0); pAnim->setPosition(2, -1); } // Clear away extra animations int iAnimCount = (int)lua_objlen(L, 10); if(iAnimCount >= iNextAnim) { for(int i = iNextAnim; i <= iAnimCount; ++i) { pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim); pAnim->removeFromTile(); lua_pushnil(L); lua_rawseti(L, 10, i); } } lua_pushboolean(L, valid ? 1 : 0); return 1; }
static int l_mainloop(lua_State *L) { luaL_checktype(L, 1, LUA_TTHREAD); lua_State *dispatcher = lua_tothread(L, 1); fps_ctrl *fps_control = (fps_ctrl*)lua_touserdata(L, luaT_upvalueindex(1)); SDL_TimerID timer = SDL_AddTimer(30, timer_frame_callback, nullptr); SDL_Event e; while(SDL_WaitEvent(&e) != 0) { bool do_frame = false; bool do_timer = false; do { int nargs; switch(e.type) { case SDL_QUIT: goto leave_loop; case SDL_KEYDOWN: lua_pushliteral(dispatcher, "keydown"); lua_pushstring(dispatcher, SDL_GetKeyName(e.key.keysym.sym)); l_push_modifiers_table(dispatcher, e.key.keysym.mod); lua_pushboolean(dispatcher, e.key.repeat != 0); nargs = 4; break; case SDL_KEYUP: lua_pushliteral(dispatcher, "keyup"); lua_pushstring(dispatcher, SDL_GetKeyName(e.key.keysym.sym)); nargs = 2; break; case SDL_TEXTINPUT: lua_pushliteral(dispatcher, "textinput"); lua_pushstring(dispatcher, e.text.text); nargs = 2; break; case SDL_TEXTEDITING: lua_pushliteral(dispatcher, "textediting"); lua_pushstring(dispatcher, e.edit.text); lua_pushinteger(dispatcher, e.edit.start); lua_pushinteger(dispatcher, e.edit.length); nargs = 4; break; case SDL_MOUSEBUTTONDOWN: lua_pushliteral(dispatcher, "buttondown"); lua_pushinteger(dispatcher, e.button.button); lua_pushinteger(dispatcher, e.button.x); lua_pushinteger(dispatcher, e.button.y); nargs = 4; break; case SDL_MOUSEBUTTONUP: lua_pushliteral(dispatcher, "buttonup"); lua_pushinteger(dispatcher, e.button.button); lua_pushinteger(dispatcher, e.button.x); lua_pushinteger(dispatcher, e.button.y); nargs = 4; break; case SDL_MOUSEWHEEL: lua_pushliteral(dispatcher, "mousewheel"); lua_pushinteger(dispatcher, e.wheel.x); lua_pushinteger(dispatcher, e.wheel.y); nargs = 3; break; case SDL_MOUSEMOTION: lua_pushliteral(dispatcher, "motion"); lua_pushinteger(dispatcher, e.motion.x); lua_pushinteger(dispatcher, e.motion.y); lua_pushinteger(dispatcher, e.motion.xrel); lua_pushinteger(dispatcher, e.motion.yrel); nargs = 5; break; case SDL_WINDOWEVENT: switch (e.window.event) { case SDL_WINDOWEVENT_FOCUS_GAINED: lua_pushliteral(dispatcher, "active"); lua_pushinteger(dispatcher, 1); nargs = 2; break; case SDL_WINDOWEVENT_FOCUS_LOST: lua_pushliteral(dispatcher, "active"); lua_pushinteger(dispatcher, 0); nargs = 2; break; default: nargs = 0; break; } break; case SDL_USEREVENT_MUSIC_OVER: lua_pushliteral(dispatcher, "music_over"); nargs = 1; break; case SDL_USEREVENT_CPCALL: if(luaT_cpcall(L, (lua_CFunction)e.user.data1, e.user.data2)) { SDL_RemoveTimer(timer); lua_pushliteral(L, "callback"); return 2; } nargs = 0; break; case SDL_USEREVENT_TICK: do_timer = true; nargs = 0; break; case SDL_USEREVENT_MOVIE_OVER: lua_pushliteral(dispatcher, "movie_over"); nargs = 1; break; case SDL_USEREVENT_SOUND_OVER: lua_pushliteral(dispatcher, "sound_over"); lua_pushinteger(dispatcher, *(static_cast<int*>(e.user.data1))); nargs = 2; break; default: nargs = 0; break; } if(nargs != 0) { if(luaT_resume(dispatcher, dispatcher, nargs) != LUA_YIELD) { goto leave_loop; } do_frame = do_frame || (lua_toboolean(dispatcher, 1) != 0); lua_settop(dispatcher, 0); } } while(SDL_PollEvent(&e) != 0); if(do_timer) { lua_pushliteral(dispatcher, "timer"); if(luaT_resume(dispatcher, dispatcher, 1) != LUA_YIELD) { break; } do_frame = do_frame || (lua_toboolean(dispatcher, 1) != 0); lua_settop(dispatcher, 0); } if(do_frame || !fps_control->limit_fps) { do { if(fps_control->track_fps) { fps_control->count_frame(); } lua_pushliteral(dispatcher, "frame"); if(luaT_resume(dispatcher, dispatcher, 1) != LUA_YIELD) { goto leave_loop; } lua_settop(dispatcher, 0); } while(fps_control->limit_fps == false && SDL_PollEvent(nullptr) == 0); } // No events pending - a good time to do a bit of garbage collection lua_gc(L, LUA_GCSTEP, 2); } leave_loop: SDL_RemoveTimer(timer); int n = lua_gettop(dispatcher); if(lua_status(dispatcher) >= LUA_ERRRUN) { n = 1; } lua_checkstack(L, n); lua_xmove(dispatcher, L, n); return n; }
static int l_writer_mt_index(lua_State *L) { return reinterpret_cast<LuaPersistBasicWriter*>( lua_touserdata(L, luaT_upvalueindex(2)))->writeObjectRaw(); }
static int l_limit_fps(lua_State *L) { fps_ctrl *ctrl = (fps_ctrl*)lua_touserdata(L, luaT_upvalueindex(1)); ctrl->limit_fps = lua_isnone(L, 1) ? true : (lua_toboolean(L, 1) != 0); return 0; }
int writeObjectRaw() { lua_State *L = m_L; uint8_t iType; // Save the index to the cache lua_pushvalue(L, 2); lua_pushnumber(L, (lua_Number)(m_iNextIndex++)); lua_settable(L, 1); // Lookup the object in the permanents table lua_pushvalue(L, 2); lua_gettable(L, luaT_upvalueindex(1)); if(lua_type(L, -1) != LUA_TNIL) { // Object is in the permanents table. uint8_t iType = PERSIST_TPERMANENT; writeByteStream(&iType, 1); // Replace self's environment with self (for call to writeStackObject) lua_pushvalue(L, luaT_upvalueindex(2)); lua_replace(L, 1); // Write the key corresponding to the permanent object writeStackObject(-1); } else { // Object is not in the permanents table. lua_pop(L, 1); switch(lua_type(L, 2)) { // LUA_TNIL handled in writeStackObject // LUA_TBOOLEAN handled in writeStackObject // LUA_TNUMBER handled in writeStackObject case LUA_TSTRING: { iType = LUA_TSTRING; writeByteStream(&iType, 1); // Strings are simple: length and then bytes (not null terminated) size_t iLength; const char *sString = lua_tolstring(L, 2, &iLength); writeVUInt(iLength); writeByteStream(reinterpret_cast<const uint8_t*>(sString), iLength); break; } case LUA_TTABLE: { // Replace self's environment with self (for calls to writeStackObject) lua_pushvalue(L, luaT_upvalueindex(2)); lua_replace(L, 1); // Save env and insert prior to table lua_getfenv(L, 1); lua_insert(L, 2); int iTable = 3; table_reentry: // Handle the metatable if(lua_getmetatable(L, iTable)) { iType = PERSIST_TTABLE_WITH_META; writeByteStream(&iType, 1); writeStackObject(-1); lua_pop(L, 1); } else { iType = LUA_TTABLE; writeByteStream(&iType, 1); } // Write the children as key, value pairs lua_pushnil(L); while(lua_next(L, iTable)) { writeStackObject(-2); // The naive thing to do now would be writeStackObject(-1) // but this can easily lead to Lua's C call stack limit // being hit. To reduce the likelyhood of this happening, // we check to see if about to write another table. if(lua_type(L, -1) == LUA_TTABLE) { lua_pushvalue(L, -1); lua_rawget(L, 2); lua_pushvalue(L, -2); lua_gettable(L, luaT_upvalueindex(1)); if(lua_isnil(L, -1) && lua_isnil(L, -2)) { lua_pop(L, 2); lua_checkstack(L, 10); iTable += 2; lua_pushvalue(L, iTable); lua_pushnumber(L, (lua_Number)(m_iNextIndex++)); lua_settable(L, 2); goto table_reentry; table_resume: iTable -= 2; } else { lua_pop(L, 2); writeStackObject(-1); } } else writeStackObject(-1); lua_pop(L, 1); } // Write a nil to mark the end of the children (as nil is the // only value which cannot be used as a key in a table). iType = LUA_TNIL; writeByteStream(&iType, 1); if(iTable != 3) goto table_resume; break; } case LUA_TFUNCTION: if(lua_iscfunction(L, 2)) { setErrorObject(2); setError("Cannot persist C functions"); } else { iType = LUA_TFUNCTION; writeByteStream(&iType, 1); // Replace self's environment with self (for calls to writeStackObject) lua_pushvalue(L, luaT_upvalueindex(2)); lua_replace(L, 1); // Write the prototype (the part of a function which is common across // multiple closures - see LClosure / Proto in Lua's lobject.h). lua_Debug proto_info; lua_pushvalue(L, 2); lua_getinfo(L, ">Su", &proto_info); writePrototype(&proto_info, 2); // Write the values of the upvalues // If available, also write the upvalue IDs (so that in // the future, we could hypothetically rejoin shared // upvalues). An ID is just an opaque sequence of bytes. writeVUInt(proto_info.nups); #if LUA_VERSION_NUM >= 502 writeVUInt(sizeof(void*)); #else writeVUInt(0); #endif for(int i = 1; i <= proto_info.nups; ++i) { lua_getupvalue(L, 2, i); writeStackObject(-1); #if LUA_VERSION_NUM >= 502 void *pUpvalueID = lua_upvalueid(L, 2, i); writeByteStream((uint8_t*)&pUpvalueID, sizeof(void*)); #endif } // Write the environment table lua_getfenv(L, 2); writeStackObject(-1); lua_pop(L, 1); } break; case LUA_TUSERDATA: if(!_checkThatUserdataCanBeDepersisted(2)) break; // Replace self's environment with self (for calls to writeStackObject) lua_pushvalue(L, luaT_upvalueindex(2)); lua_replace(L, 1); // Write type, metatable, and then environment iType = LUA_TUSERDATA; writeByteStream(&iType, 1); writeStackObject(-1); lua_getfenv(L, 2); writeStackObject(-1); lua_pop(L, 1); // Write the raw data if(lua_type(L, -1) == LUA_TTABLE) { lua_getfield(L, -1, "__persist"); if(lua_isnil(L, -1)) lua_pop(L, 1); else { lua_pushvalue(L, 2); lua_pushvalue(L, luaT_upvalueindex(2)); lua_call(L, 2, 0); } } writeVUInt((uint64_t)0x42); // sync marker break; default: setError(lua_pushfstring(L, "Cannot persist %s values", luaL_typename(L, 2))); break; } } lua_pushnumber(L, 0); return 1; }
static int l_map_updateblueprint(lua_State *L) { // NB: This function can be implemented in Lua, but is implemented in C for // efficiency. const unsigned short iFloorTileGood = 24 + (thdf_alpha_50 << 8); const unsigned short iFloorTileGoodCenter = 37 + (thdf_alpha_50 << 8); const unsigned short iFloorTileBad = 67 + (thdf_alpha_50 << 8); const unsigned int iWallAnimTopCorner = 124; const unsigned int iWallAnim = 120; level_map* pMap = luaT_testuserdata<level_map>(L); int iOldX = static_cast<int>(luaL_checkinteger(L, 2)) - 1; int iOldY = static_cast<int>(luaL_checkinteger(L, 3)) - 1; int iOldW = static_cast<int>(luaL_checkinteger(L, 4)); int iOldH = static_cast<int>(luaL_checkinteger(L, 5)); int iNewX = static_cast<int>(luaL_checkinteger(L, 6)) - 1; int iNewY = static_cast<int>(luaL_checkinteger(L, 7)) - 1; int iNewW = static_cast<int>(luaL_checkinteger(L, 8)); int iNewH = static_cast<int>(luaL_checkinteger(L, 9)); int player_id = static_cast<int>(luaL_checkinteger(L, 10)); luaL_checktype(L, 11, LUA_TTABLE); // Animation list animation_manager* pAnims = luaT_testuserdata<animation_manager>(L, 12, luaT_upvalueindex(1)); bool entire_invalid = lua_toboolean(L, 13) != 0; bool valid = !entire_invalid; if(iOldX < 0 || iOldY < 0 || (iOldX + iOldW) > pMap->get_width() || (iOldY + iOldH) > pMap->get_height()) luaL_argerror(L, 2, "Old rectangle is out of bounds"); if(iNewX < 0 || iNewY < 0 || (iNewX + iNewW) >= pMap->get_width() || (iNewY + iNewH) >= pMap->get_height()) luaL_argerror(L, 6, "New rectangle is out of bounds"); // Clear blueprint flag from previous selected floor tiles (copying it to the passable flag). for(int iY = iOldY; iY < iOldY + iOldH; ++iY) { for(int iX = iOldX; iX < iOldX + iOldW; ++iX) { map_tile *pNode = pMap->get_tile_unchecked(iX, iY); pNode->iBlock[3] = 0; pNode->flags.passable |= pNode->flags.passable_if_not_for_blueprint; pNode->flags.passable_if_not_for_blueprint = false; } } // Add blueprint flag to new floor tiles. for(int iY = iNewY; iY < iNewY + iNewH; ++iY) { for(int iX = iNewX; iX < iNewX + iNewW; ++iX) { map_tile *pNode = pMap->get_tile_unchecked(iX, iY); if(is_valid(entire_invalid, pNode, pMap, player_id)) pNode->iBlock[3] = iFloorTileGood; else { pNode->iBlock[3] = iFloorTileBad; valid = false; } pNode->flags.passable_if_not_for_blueprint = pNode->flags.passable; } } // Set center floor tiles if(iNewW >= 2 && iNewH >= 2) { int iCenterX = iNewX + (iNewW - 2) / 2; int iCenterY = iNewY + (iNewH - 2) / 2; map_tile *pNode = pMap->get_tile_unchecked(iCenterX, iCenterY); if(pNode->iBlock[3] == iFloorTileGood) pNode->iBlock[3] = iFloorTileGoodCenter + 2; pNode = pMap->get_tile_unchecked(iCenterX + 1, iCenterY); if(pNode->iBlock[3] == iFloorTileGood) pNode->iBlock[3] = iFloorTileGoodCenter + 1; pNode = pMap->get_tile_unchecked(iCenterX, iCenterY + 1); if(pNode->iBlock[3] == iFloorTileGood) pNode->iBlock[3] = iFloorTileGoodCenter + 0; pNode = pMap->get_tile_unchecked(iCenterX + 1, iCenterY + 1); if(pNode->iBlock[3] == iFloorTileGood) pNode->iBlock[3] = iFloorTileGoodCenter + 3; } // Set wall animations int iNextAnim = 1; animation *pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim); map_tile *pNode = pMap->get_tile_unchecked(iNewX, iNewY); pAnim->set_animation(pAnims, iWallAnimTopCorner); pAnim->set_flags(thdf_list_bottom | (is_valid(entire_invalid, pNode, pMap, player_id) ? 0 : thdf_alt_palette)); pAnim->attach_to_tile(pNode, 0); for(int iX = iNewX; iX < iNewX + iNewW; ++iX) { if(iX != iNewX) { pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim); pNode = pMap->get_tile_unchecked(iX, iNewY); pAnim->set_animation(pAnims, iWallAnim); pAnim->set_flags(thdf_list_bottom | (is_valid(entire_invalid, pNode, pMap, player_id) ? 0 : thdf_alt_palette)); pAnim->attach_to_tile(pNode, 0); pAnim->set_position(0, 0); } pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim); pNode = pMap->get_tile_unchecked(iX, iNewY + iNewH - 1); pAnim->set_animation(pAnims, iWallAnim); pAnim->set_flags(thdf_list_bottom | (is_valid(entire_invalid, pNode, pMap, player_id) ? 0 : thdf_alt_palette)); pNode = pMap->get_tile_unchecked(iX, iNewY + iNewH); pAnim->attach_to_tile(pNode, 0); pAnim->set_position(0, -1); } for(int iY = iNewY; iY < iNewY + iNewH; ++iY) { if(iY != iNewY) { pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim); pNode = pMap->get_tile_unchecked(iNewX, iY); pAnim->set_animation(pAnims, iWallAnim); pAnim->set_flags(thdf_list_bottom | thdf_flip_horizontal | (is_valid(entire_invalid, pNode, pMap, player_id) ? 0 : thdf_alt_palette)); pAnim->attach_to_tile(pNode, 0); pAnim->set_position(2, 0); } pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim); pNode = pMap->get_tile_unchecked(iNewX + iNewW - 1, iY); pAnim->set_animation(pAnims, iWallAnim); pAnim->set_flags(thdf_list_bottom | thdf_flip_horizontal | (is_valid(entire_invalid, pNode, pMap, player_id) ? 0 : thdf_alt_palette)); pNode = pMap->get_tile_unchecked(iNewX + iNewW, iY); pAnim->attach_to_tile(pNode, 0); pAnim->set_position(2, -1); } // Clear away extra animations int iAnimCount = (int)lua_objlen(L, 11); if(iAnimCount >= iNextAnim) { for(int i = iNextAnim; i <= iAnimCount; ++i) { pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim); pAnim->remove_from_tile(); lua_pushnil(L); lua_rawseti(L, 11, i); } } lua_pushboolean(L, valid ? 1 : 0); return 1; }
static int l_cursor_position(lua_State *L) { THRenderTarget* pCanvas = luaT_testuserdata<THRenderTarget>(L, 1, luaT_upvalueindex(1)); lua_pushboolean(L, THCursor::setPosition(pCanvas, static_cast<int>(luaL_checkinteger(L, 2)), static_cast<int>(luaL_checkinteger(L, 3))) ? 1 : 0); return 1; }