diff --git a/src/tools/map_replace_area.cpp b/src/tools/map_replace_area.cpp new file mode 100644 index 000000000..5be50c080 --- /dev/null +++ b/src/tools/map_replace_area.cpp @@ -0,0 +1,274 @@ +#include +#include +#include +#include +#include + +// global new layers data (set by ReplaceAreaTiles and ReplaceAreaQuads) +void *g_pNewData[1024]; +void *g_pNewItem[1024]; +int g_NewDataSize[1024]; + +bool ReplaceArea(IStorage*, const char[][64], const int[][2]); +bool OpenMaps(IStorage*, const char[][64], CDataFileReader[], CDataFileWriter&); +bool CompareLayers(const char[][64], CDataFileReader[]); +void ReplaceAreaTiles(CDataFileReader[], const int[][2], CMapItemLayer*[]); +void ReplaceAreaQuads(CDataFileReader[], const int[][2], CMapItemLayer*[], const int); +bool IsQuadInsideArea(const int[][2], const int, CPoint&); +void SaveOutputMap(CDataFileReader[], CDataFileWriter&); + +int main(int argc, const char *argv[]) +{ + cmdline_fix(&argc, &argv); + dbg_logger_stdout(); + + if(argc != 10) + { + dbg_msg("map_replace_area", "Invalid arguments"); + dbg_msg("map_replace_area", "Usage: %s ", argv[0]); + return -1; + } + + char pMapNames[3][64]; + strcpy(pMapNames[0], argv[1]); //from_map + strcpy(pMapNames[1], argv[4]); //to_map + strcpy(pMapNames[2], argv[9]); //output_map + + int pAreaData[3][2]; + pAreaData[0][0] = atoi(argv[2]); //from_x + pAreaData[0][1] = atoi(argv[3]); //from_y + pAreaData[1][0] = atoi(argv[5]); //to_x + pAreaData[1][1] = atoi(argv[6]); //to_y + pAreaData[2][0] = atoi(argv[7]); //width + pAreaData[2][1] = atoi(argv[8]); //height + + cmdline_free(argc, argv); + + IStorage *pStorage = CreateLocalStorage(); + for(int i = 0; i < 1024; i++) + { + g_pNewData[i] = g_pNewItem[i] = 0; + g_NewDataSize[i] = 0; + } + + dbg_msg("map_replace_area", "from_map='%s'; to_map='%s'; from_area='(%dx,%dy)'; to_area='%dx,%dy'; area_width='%d'; area_heigth='%d'; output_map='%s'", + pMapNames[0], pMapNames[1], pAreaData[0][0], pAreaData[0][1], pAreaData[1][0], pAreaData[1][1], pAreaData[2][0], pAreaData[2][1], pMapNames[2]); + + return ReplaceArea(pStorage, pMapNames, pAreaData) ? 0 : 1; +} + +bool ReplaceArea(IStorage *pStorage, const char pMapNames[3][64], const int pAreaData[2][2]) +{ + + CDataFileReader InputMaps[2]; + CDataFileWriter OutputMap; + + if(!OpenMaps(pStorage, pMapNames, InputMaps, OutputMap)) + return false; + + if(!CompareLayers(pMapNames, InputMaps)) + return false; + + int LayersOffset[2], LayersCount; + InputMaps[0].GetType(MAPITEMTYPE_LAYER, &LayersOffset[0], &LayersCount); + InputMaps[1].GetType(MAPITEMTYPE_LAYER, &LayersOffset[1], &LayersCount); + + for(int j = 0; j < LayersCount; j++) + { + CMapItemLayer *pItem[2]; + for(int i = 0; i < 2; i++) + pItem[i] = (CMapItemLayer *)InputMaps[i].GetItem(LayersOffset[i] + j, 0, 0); + + if(pItem[0]->m_Type == LAYERTYPE_TILES) + ReplaceAreaTiles(InputMaps, pAreaData, pItem); + else if (pItem[0]->m_Type == LAYERTYPE_QUADS) + ReplaceAreaQuads(InputMaps, pAreaData, pItem, LayersOffset[1] + j); + } + + SaveOutputMap(InputMaps, OutputMap); + + return true; +} + + +bool OpenMaps(IStorage *pStorage, const char pMapNames[3][64], CDataFileReader InputMaps[2], CDataFileWriter& OutputMap) +{ + for(int i = 0; i < 2; i++) + { + if(!InputMaps[i].Open(pStorage, pMapNames[i], IStorage::TYPE_ABSOLUTE)) + { + dbg_msg("map_replace_area", "Error: unable to open map '%s'", pMapNames[i]); + return false; + } + } + + if(!OutputMap.Open(pStorage, pMapNames[2], IStorage::TYPE_ABSOLUTE)) + { + dbg_msg("map_replace_area", "Error: unable to open map '%s'", pMapNames[2]); + return false; + } + + return true; +} + +bool CompareLayers(const char pMapNames[3][64], CDataFileReader InputMaps[2]) +{ + int Start[2], Num[2]; + InputMaps[0].GetType(MAPITEMTYPE_LAYER, &Start[0], &Num[0]); + InputMaps[1].GetType(MAPITEMTYPE_LAYER, &Start[1], &Num[1]); + + if(Num[0] != Num[1]) + { + dbg_msg("map_replace_area", "Error: different layers number"); + for(int i = 0; i < 2; i++) + dbg_msg("map_replace_area", " \"%s\": %d layers", pMapNames[i], Num[i]); + return false; + } + + for(int j = 0; j < Num[0]; j++) + { + CMapItemLayer *pItem[2]; + for(int i = 0; i < 2; i++) + pItem[i] = (CMapItemLayer *)InputMaps[i].GetItem(Start[i] + j, 0, 0); + + if(pItem[0]->m_Type != pItem[1]->m_Type) + { + dbg_msg("map_replace_area", "Error: different types on layer number %d", j); + for(int i = 0; i < 2; i++) + { + char aLayerType[16]; + strcpy(aLayerType, pItem[i]->m_Type == LAYERTYPE_TILES ? "tiles layer" : "quad layer"); + dbg_msg("map_replace_area", " \"%s\": %s", pMapNames[i], aLayerType); + } + return false; + } + } + + return true; +} + +void ReplaceAreaTiles(CDataFileReader InputMaps[2], const int pAreaData[2][2], CMapItemLayer* pItem[2]) +{ + CMapItemLayerTilemap *pTilemap[2]; + for(int i = 0; i < 2; ++i) + pTilemap[i] = (CMapItemLayerTilemap *)pItem[i]; + + CTile *pTile[2]; + for(int i = 0; i < 2; ++i) + pTile[i] = (CTile *)InputMaps[i].GetData(pTilemap[i]->m_Data); + + bool bDataChanged = false; + for(int y = 0; y < pAreaData[2][1]; y++) + { + if(y + pAreaData[0][1] >= pTilemap[0]->m_Height || y + pAreaData[1][1] >= pTilemap[1]->m_Height) + continue; + + for(int x = 0; x < pAreaData[2][0]; x++) + { + if(x + pAreaData[0][0] >= pTilemap[1]->m_Width || x + pAreaData[1][0] >= pTilemap[1]->m_Width) + continue; + + int pos[2]; + for(int i = 0; i < 2; i++) + pos[i] = (y + pAreaData[i][1]) * pTilemap[i]->m_Width + x + pAreaData[i][0]; + + pTile[1][pos[1]] = pTile[0][pos[0]]; + bDataChanged = true; + } + } + + if(bDataChanged) + g_pNewData[pTilemap[1]->m_Data] = pTile[1]; +} + +void ReplaceAreaQuads(CDataFileReader InputMaps[2], const int pAreaData[2][2], CMapItemLayer* pItem[2], const int ItemNumber) +{ + + CMapItemLayerQuads *pQuadLayer[2]; + for(int i = 0; i < 2; i++) + pQuadLayer[i] = (CMapItemLayerQuads *)pItem[i]; + + CQuad *pQuads[3]; + for(int i = 0; i < 2; i++) + pQuads[i] = (CQuad *)InputMaps[i].GetDataSwapped(pQuadLayer[i]->m_Data); + + pQuads[3] = new CQuad[maximum(pQuadLayer[0]->m_NumQuads, pQuadLayer[1]->m_NumQuads)]; + int QuadsCounter = 0; + + bool bDataChanged = false; + for(int i = 0; i < pQuadLayer[1]->m_NumQuads; i++) + { + if(IsQuadInsideArea(pAreaData, 1, pQuads[1][i].m_aPoints[4])) + { + bDataChanged = true; + continue; + } + + pQuads[3][QuadsCounter] = pQuads[1][i]; + QuadsCounter++; + } + + for(int i = 0; i < pQuadLayer[0]->m_NumQuads; i++) + { + if(IsQuadInsideArea(pAreaData, 0, pQuads[0][i].m_aPoints[4])) + { + pQuads[3][QuadsCounter] = pQuads[0][i]; + + float Distancex = (pAreaData[0][0] - pAreaData[1][0]) * 32; + float Distancey = (pAreaData[0][1] - pAreaData[1][1]) * 32; + + for(int j = 0; j < 5; j++) + { + pQuads[3][QuadsCounter].m_aPoints[j].x -= f2fx(Distancex); + pQuads[3][QuadsCounter].m_aPoints[j].y -= f2fx(Distancey); + } + + QuadsCounter++; + bDataChanged = true; + } + } + + if(bDataChanged) + { + g_pNewData[pQuadLayer[1]->m_Data] = pQuads[3]; + g_NewDataSize[pQuadLayer[1]->m_Data] = ((int)sizeof(CQuad)) * QuadsCounter; + pQuadLayer[1]->m_NumQuads = QuadsCounter; + g_pNewItem[ItemNumber] = pItem[1]; + } + +} + +bool IsQuadInsideArea(const int pAreaData[2][2], const int AreaIndex, CPoint& QuadPivot) +{ + return fx2f(QuadPivot.x) / 32 >= pAreaData[AreaIndex][0] + && fx2f(QuadPivot.x) / 32 <= pAreaData[AreaIndex][0] + pAreaData[2][0] + && fx2f(QuadPivot.y) / 32 >= pAreaData[AreaIndex][1] + && fx2f(QuadPivot.y) / 32 <= pAreaData[AreaIndex][1] + pAreaData[2][1]; +} + +void SaveOutputMap(CDataFileReader InputMaps[2], CDataFileWriter& OutputMap) +{ + for(int i = 0; i < InputMaps[1].NumItems(); i++) + { + int ID, Type; + int Size = InputMaps[1].GetItemSize(i); + void *pItem = InputMaps[1].GetItem(i, &Type, &ID); + if(g_pNewItem[i]) + pItem = g_pNewItem[i]; + + // filter ITEMTYPE_EX items, they will be automatically added again + if(Type == ITEMTYPE_EX) + continue; + + OutputMap.AddItem(Type, ID, Size, pItem); + } + + for(int i = 0; i < InputMaps[1].NumData(); i++) + { + void *pData = g_pNewData[i] ? g_pNewData[i] : InputMaps[1].GetData(i); + int Size = g_NewDataSize[i] ? g_NewDataSize[i] : InputMaps[1].GetDataSize(i); + OutputMap.AddData(Size, pData); + } + + OutputMap.Finish(); +} \ No newline at end of file