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; }