mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-29 23:07:48 +02:00
- Added terrain & object selection classes - Added CComposedOperation - Refactored clear terrain, it is now an operation - Added rough support for updating terrain type if required
This commit is contained in:
@@ -26,6 +26,7 @@
|
|||||||
#include "filesystem/CResourceLoader.h"
|
#include "filesystem/CResourceLoader.h"
|
||||||
#include "GameConstants.h"
|
#include "GameConstants.h"
|
||||||
#include "rmg/CMapGenerator.h"
|
#include "rmg/CMapGenerator.h"
|
||||||
|
#include "CStopWatch.h"
|
||||||
|
|
||||||
DLL_LINKAGE boost::rand48 ran;
|
DLL_LINKAGE boost::rand48 ran;
|
||||||
class CGObjectInstance;
|
class CGObjectInstance;
|
||||||
@@ -864,6 +865,7 @@ void CGameState::init(StartInfo * si)
|
|||||||
if(scenarioOps->createRandomMap)
|
if(scenarioOps->createRandomMap)
|
||||||
{
|
{
|
||||||
logGlobal->infoStream() << "Create random map.";
|
logGlobal->infoStream() << "Create random map.";
|
||||||
|
CStopWatch sw;
|
||||||
|
|
||||||
// Create player settings for RMG
|
// Create player settings for RMG
|
||||||
BOOST_FOREACH(const auto & pair, scenarioOps->playerInfos)
|
BOOST_FOREACH(const auto & pair, scenarioOps->playerInfos)
|
||||||
@@ -902,6 +904,7 @@ void CGameState::init(StartInfo * si)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logGlobal->infoStream() << boost::format("Generated random map in %i ms.") % sw.getDiff();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -76,6 +76,44 @@ int3 MapRect::bottomRight() const
|
|||||||
return int3(right(), bottom(), z);
|
return int3(right(), bottom(), z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CTerrainSelection::CTerrainSelection(CMap * map) : CMapSelection(map)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTerrainSelection::selectRange(const MapRect & rect)
|
||||||
|
{
|
||||||
|
rect.forEach([this](const int3 pos)
|
||||||
|
{
|
||||||
|
this->select(pos);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTerrainSelection::deselectRange(const MapRect & rect)
|
||||||
|
{
|
||||||
|
rect.forEach([this](const int3 pos)
|
||||||
|
{
|
||||||
|
this->deselect(pos);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTerrainSelection::selectAll()
|
||||||
|
{
|
||||||
|
selectRange(MapRect(int3(0, 0, 0), getMap()->width, getMap()->height));
|
||||||
|
selectRange(MapRect(int3(0, 0, 1), getMap()->width, getMap()->height));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTerrainSelection::clearSelection()
|
||||||
|
{
|
||||||
|
deselectRange(MapRect(int3(0, 0, 0), getMap()->width, getMap()->height));
|
||||||
|
deselectRange(MapRect(int3(0, 0, 1), getMap()->width, getMap()->height));
|
||||||
|
}
|
||||||
|
|
||||||
|
CObjectSelection::CObjectSelection(CMap * map) : CMapSelection(map)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
CMapOperation::CMapOperation(CMap * map) : map(map)
|
CMapOperation::CMapOperation(CMap * map) : map(map)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -159,37 +197,30 @@ const CMapOperation * CMapUndoManager::peek(const TStack & stack) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
CMapEditManager::CMapEditManager(CMap * map)
|
CMapEditManager::CMapEditManager(CMap * map)
|
||||||
: map(map)
|
: map(map), terrainSel(map), objectSel(map)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapEditManager::clearTerrain(CRandomGenerator * gen)
|
CMap * CMapEditManager::getMap()
|
||||||
{
|
{
|
||||||
for(int i = 0; i < map->width; ++i)
|
return map;
|
||||||
{
|
|
||||||
for(int j = 0; j < map->height; ++j)
|
|
||||||
{
|
|
||||||
map->getTile(int3(i, j, 0)).terType = ETerrainType::WATER;
|
|
||||||
map->getTile(int3(i, j, 0)).terView = gen->getInteger(20, 32);
|
|
||||||
|
|
||||||
if(map->twoLevel)
|
|
||||||
{
|
|
||||||
map->getTile(int3(i, j, 1)).terType = ETerrainType::ROCK;
|
|
||||||
map->getTile(int3(i, j, 1)).terView = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapEditManager::drawTerrain(const MapRect & rect, ETerrainType terType, CRandomGenerator * gen)
|
void CMapEditManager::clearTerrain(CRandomGenerator * gen/* = nullptr*/)
|
||||||
{
|
{
|
||||||
execute(make_unique<CDrawTerrainOperation>(map, rect, terType, gen));
|
execute(make_unique<CClearTerrainOperation>(map, gen ? gen : &(this->gen)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapEditManager::insertObject(const int3 & pos, CGObjectInstance * obj)
|
void CMapEditManager::drawTerrain(ETerrainType terType, CRandomGenerator * gen/* = nullptr*/)
|
||||||
{
|
{
|
||||||
execute(make_unique<CInsertObjectOperation>(map, pos, obj));
|
execute(make_unique<CDrawTerrainOperation>(map, terrainSel, terType, gen ? gen : &(this->gen)));
|
||||||
|
terrainSel.clearSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMapEditManager::insertObject(CGObjectInstance * obj, const int3 & pos)
|
||||||
|
{
|
||||||
|
execute(make_unique<CInsertObjectOperation>(map, obj, pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapEditManager::execute(unique_ptr<CMapOperation> && operation)
|
void CMapEditManager::execute(unique_ptr<CMapOperation> && operation)
|
||||||
@@ -198,14 +229,14 @@ void CMapEditManager::execute(unique_ptr<CMapOperation> && operation)
|
|||||||
undoManager.addOperation(std::move(operation));
|
undoManager.addOperation(std::move(operation));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapEditManager::undo()
|
CTerrainSelection & CMapEditManager::getTerrainSelection()
|
||||||
{
|
{
|
||||||
undoManager.undo();
|
return terrainSel;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapEditManager::redo()
|
CObjectSelection & CMapEditManager::getObjectSelection()
|
||||||
{
|
{
|
||||||
undoManager.redo();
|
return objectSel;
|
||||||
}
|
}
|
||||||
|
|
||||||
CMapUndoManager & CMapEditManager::getUndoManager()
|
CMapUndoManager & CMapEditManager::getUndoManager()
|
||||||
@@ -213,6 +244,40 @@ CMapUndoManager & CMapEditManager::getUndoManager()
|
|||||||
return undoManager;
|
return undoManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CComposedOperation::CComposedOperation(CMap * map) : CMapOperation(map)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CComposedOperation::execute()
|
||||||
|
{
|
||||||
|
BOOST_FOREACH(auto & operation, operations)
|
||||||
|
{
|
||||||
|
operation->execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CComposedOperation::undo()
|
||||||
|
{
|
||||||
|
BOOST_FOREACH(auto & operation, operations)
|
||||||
|
{
|
||||||
|
operation->undo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CComposedOperation::redo()
|
||||||
|
{
|
||||||
|
BOOST_FOREACH(auto & operation, operations)
|
||||||
|
{
|
||||||
|
operation->redo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CComposedOperation::addOperation(unique_ptr<CMapOperation> && operation)
|
||||||
|
{
|
||||||
|
operations.push_back(std::move(operation));
|
||||||
|
}
|
||||||
|
|
||||||
const std::string TerrainViewPattern::FLIP_MODE_DIFF_IMAGES = "D";
|
const std::string TerrainViewPattern::FLIP_MODE_DIFF_IMAGES = "D";
|
||||||
|
|
||||||
const std::string TerrainViewPattern::RULE_DIRT = "D";
|
const std::string TerrainViewPattern::RULE_DIRT = "D";
|
||||||
@@ -351,27 +416,24 @@ boost::optional<const TerrainViewPattern &> CTerrainViewPatternConfig::getPatter
|
|||||||
return boost::optional<const TerrainViewPattern &>();
|
return boost::optional<const TerrainViewPattern &>();
|
||||||
}
|
}
|
||||||
|
|
||||||
CDrawTerrainOperation::CDrawTerrainOperation(CMap * map, const MapRect & rect, ETerrainType terType, CRandomGenerator * gen)
|
CDrawTerrainOperation::CDrawTerrainOperation(CMap * map, const CTerrainSelection & terrainSel, ETerrainType terType, CRandomGenerator * gen)
|
||||||
: CMapOperation(map), rect(rect), terType(terType), gen(gen)
|
: CMapOperation(map), terrainSel(terrainSel), terType(terType), gen(gen)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDrawTerrainOperation::execute()
|
void CDrawTerrainOperation::execute()
|
||||||
{
|
{
|
||||||
for(int i = rect.x; i < rect.x + rect.width; ++i)
|
BOOST_FOREACH(const auto & pos, terrainSel.getSelectedItems())
|
||||||
{
|
{
|
||||||
for(int j = rect.y; j < rect.y + rect.height; ++j)
|
auto & tile = map->getTile(pos);
|
||||||
{
|
tile.terType = terType;
|
||||||
map->getTile(int3(i, j, rect.z)).terType = terType;
|
invalidateTerrainViews(pos);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO there are situations where more tiles are affected implicitely
|
updateTerrainTypes();
|
||||||
|
updateTerrainViews();
|
||||||
//TODO add coastal bit to extTileFlags appropriately
|
//TODO add coastal bit to extTileFlags appropriately
|
||||||
|
|
||||||
MapRect viewRect(int3(rect.x - 1, rect.y - 1, rect.z), rect.width + 2, rect.height + 2); // Has to overlap 1 tile around
|
|
||||||
updateTerrainViews(viewRect & MapRect(int3(0, 0, viewRect.z), map->width, map->height)); // Rect should not overlap map dimensions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDrawTerrainOperation::undo()
|
void CDrawTerrainOperation::undo()
|
||||||
@@ -389,14 +451,95 @@ std::string CDrawTerrainOperation::getLabel() const
|
|||||||
return "Draw Terrain";
|
return "Draw Terrain";
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDrawTerrainOperation::updateTerrainViews(const MapRect & rect)
|
void CDrawTerrainOperation::updateTerrainTypes()
|
||||||
{
|
{
|
||||||
for(int x = rect.x; x < rect.x + rect.width; ++x)
|
auto positions = terrainSel.getSelectedItems();
|
||||||
|
while(!positions.empty())
|
||||||
{
|
{
|
||||||
for(int y = rect.y; y < rect.y + rect.height; ++y)
|
const auto & centerPos = *(positions.begin());
|
||||||
|
auto centerTile = map->getTile(centerPos);
|
||||||
|
auto tiles = getInvalidTiles(centerPos);
|
||||||
|
auto updateTerrainType = [&](const int3 & pos)
|
||||||
|
{
|
||||||
|
map->getTile(pos).terType = centerTile.terType;
|
||||||
|
invalidateTerrainViews(pos);
|
||||||
|
logGlobal->debugStream() << boost::format("Update terrain tile at '%s' to type '%i'.") % pos % centerTile.terType;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fill foreign invalid tiles
|
||||||
|
BOOST_FOREACH(const auto & tile, tiles.foreignTiles)
|
||||||
|
{
|
||||||
|
updateTerrainType(tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tiles.nativeTiles.find(centerPos) != tiles.nativeTiles.end())
|
||||||
|
{
|
||||||
|
// Blow up
|
||||||
|
auto rect = extendTileAroundSafely(centerPos);
|
||||||
|
std::set<int3> suitableTiles;
|
||||||
|
int invalidForeignTilesCnt, invalidNativeTilesCnt;
|
||||||
|
invalidForeignTilesCnt = invalidNativeTilesCnt = std::numeric_limits<int>::max();
|
||||||
|
rect.forEach([&](const int3 & posToTest)
|
||||||
|
{
|
||||||
|
auto & terrainTile = map->getTile(posToTest);
|
||||||
|
if(centerTile.terType != terrainTile.terType)
|
||||||
|
{
|
||||||
|
auto formerTerType = terrainTile.terType;
|
||||||
|
terrainTile.terType = centerTile.terType;
|
||||||
|
auto testTile = getInvalidTiles(posToTest);
|
||||||
|
auto addToSuitableTiles = [&](const int3 & pos)
|
||||||
|
{
|
||||||
|
suitableTiles.insert(pos);
|
||||||
|
logGlobal->debugStream() << boost::format("Found suitable tile '%s' for main tile '%s'.") % pos % centerPos;
|
||||||
|
};
|
||||||
|
|
||||||
|
if(testTile.nativeTiles.size() < invalidNativeTilesCnt ||
|
||||||
|
(testTile.nativeTiles.size() == invalidNativeTilesCnt && testTile.foreignTiles.size() < invalidForeignTilesCnt))
|
||||||
|
{
|
||||||
|
suitableTiles.clear();
|
||||||
|
addToSuitableTiles(posToTest);
|
||||||
|
}
|
||||||
|
else if(testTile.nativeTiles.size() == invalidNativeTilesCnt &&
|
||||||
|
testTile.foreignTiles.size() == invalidForeignTilesCnt)
|
||||||
|
{
|
||||||
|
addToSuitableTiles(posToTest);
|
||||||
|
}
|
||||||
|
terrainTile.terType = formerTerType;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(suitableTiles.size() == 1)
|
||||||
|
{
|
||||||
|
updateTerrainType(*suitableTiles.begin());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const int3 directions[] = { int3(0, -1, 0), int3(-1, 0, 0), int3(0, 1, 0), int3(1, 0, 0),
|
||||||
|
int3(-1, -1, 0), int3(-1, 1, 0), int3(1, 1, 0), int3(1, -1, 0)};
|
||||||
|
for(int i = 0; i < ARRAY_COUNT(directions); ++i)
|
||||||
|
{
|
||||||
|
auto it = suitableTiles.find(centerPos + directions[i]);
|
||||||
|
if(it != suitableTiles.end())
|
||||||
|
{
|
||||||
|
updateTerrainType(*it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
positions.erase(centerPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDrawTerrainOperation::updateTerrainViews()
|
||||||
|
{
|
||||||
|
BOOST_FOREACH(const auto & pos, invalidatedTerViews)
|
||||||
{
|
{
|
||||||
const auto & patterns =
|
const auto & patterns =
|
||||||
CTerrainViewPatternConfig::get().getPatternsForGroup(getTerrainGroup(map->getTile(int3(x, y, rect.z)).terType));
|
CTerrainViewPatternConfig::get().getPatternsForGroup(getTerrainGroup(map->getTile(pos).terType));
|
||||||
|
|
||||||
// Detect a pattern which fits best
|
// Detect a pattern which fits best
|
||||||
int bestPattern = -1;
|
int bestPattern = -1;
|
||||||
@@ -404,11 +547,11 @@ void CDrawTerrainOperation::updateTerrainViews(const MapRect & rect)
|
|||||||
for(int k = 0; k < patterns.size(); ++k)
|
for(int k = 0; k < patterns.size(); ++k)
|
||||||
{
|
{
|
||||||
const auto & pattern = patterns[k];
|
const auto & pattern = patterns[k];
|
||||||
valRslt = validateTerrainView(int3(x, y, rect.z), pattern);
|
valRslt = validateTerrainView(pos, pattern);
|
||||||
if(valRslt.result)
|
if(valRslt.result)
|
||||||
{
|
{
|
||||||
logGlobal->debugStream() << "Pattern detected at pos " << x << "x" << y << "x" << rect.z << ": P-Nr. " << pattern.id
|
/*logGlobal->debugStream() << boost::format("Pattern detected at pos '%s': Pattern '%s', Flip '%i', Repl. '%s'.") %
|
||||||
<< ", Flip " << valRslt.flip << ", Repl. " << valRslt.transitionReplacement;
|
pos % pattern.id % valRslt.flip % valRslt.transitionReplacement;*/
|
||||||
bestPattern = k;
|
bestPattern = k;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -417,7 +560,7 @@ void CDrawTerrainOperation::updateTerrainViews(const MapRect & rect)
|
|||||||
if(bestPattern == -1)
|
if(bestPattern == -1)
|
||||||
{
|
{
|
||||||
// This shouldn't be the case
|
// This shouldn't be the case
|
||||||
logGlobal->warnStream() << "No pattern detected at pos " << x << "x" << y << "x" << rect.z;
|
logGlobal->warnStream() << boost::format("No pattern detected at pos '%s'.") % pos;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,7 +577,7 @@ void CDrawTerrainOperation::updateTerrainViews(const MapRect & rect)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set terrain view
|
// Set terrain view
|
||||||
auto & tile = map->getTile(int3(x, y, rect.z));
|
auto & tile = map->getTile(pos);
|
||||||
if(!pattern.diffImages)
|
if(!pattern.diffImages)
|
||||||
{
|
{
|
||||||
tile.terView = gen->getInteger(mapping.first, mapping.second);
|
tile.terView = gen->getInteger(mapping.first, mapping.second);
|
||||||
@@ -449,7 +592,6 @@ void CDrawTerrainOperation::updateTerrainViews(const MapRect & rect)
|
|||||||
tile.extTileFlags = 0;
|
tile.extTileFlags = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ETerrainGroup::ETerrainGroup CDrawTerrainOperation::getTerrainGroup(ETerrainType terType) const
|
ETerrainGroup::ETerrainGroup CDrawTerrainOperation::getTerrainGroup(ETerrainType terType) const
|
||||||
@@ -651,13 +793,80 @@ TerrainViewPattern CDrawTerrainOperation::getFlippedPattern(const TerrainViewPat
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CDrawTerrainOperation::invalidateTerrainViews(const int3 & centerPos)
|
||||||
|
{
|
||||||
|
auto rect = extendTileAroundSafely(centerPos);
|
||||||
|
rect.forEach([&](const int3 & pos)
|
||||||
|
{
|
||||||
|
invalidatedTerViews.insert(pos);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
CDrawTerrainOperation::InvalidTiles CDrawTerrainOperation::getInvalidTiles(const int3 & centerPos) const
|
||||||
|
{
|
||||||
|
InvalidTiles tiles;
|
||||||
|
auto centerTerType = map->getTile(centerPos).terType;
|
||||||
|
auto rect = extendTileAround(centerPos);
|
||||||
|
rect.forEach([&](const int3 & pos)
|
||||||
|
{
|
||||||
|
if(map->isInTheMap(pos))
|
||||||
|
{
|
||||||
|
auto terType = map->getTile(pos).terType;
|
||||||
|
// Pattern 2x2
|
||||||
|
const int3 translations[4] = { int3(-1, -1, 0), int3(0, -1, 0), int3(-1, 0, 0), int3(0, 0, 0) };
|
||||||
|
bool valid = true;
|
||||||
|
for(int i = 0; i < ARRAY_COUNT(translations); ++i)
|
||||||
|
{
|
||||||
|
valid = true;
|
||||||
|
MapRect square(int3(pos.x + translations[i].x, pos.y + translations[i].y, pos.z), 2, 2);
|
||||||
|
square.forEach([&](const int3 & pos)
|
||||||
|
{
|
||||||
|
if(map->isInTheMap(pos) && map->getTile(pos).terType != terType) valid = false;
|
||||||
|
});
|
||||||
|
if(valid) break;
|
||||||
|
}
|
||||||
|
if(!valid)
|
||||||
|
{
|
||||||
|
if(terType == centerTerType) tiles.nativeTiles.insert(pos);
|
||||||
|
else tiles.foreignTiles.insert(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return tiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapRect CDrawTerrainOperation::extendTileAround(const int3 & centerPos) const
|
||||||
|
{
|
||||||
|
return MapRect(int3(centerPos.x - 1, centerPos.y - 1, centerPos.z), 3, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
MapRect CDrawTerrainOperation::extendTileAroundSafely(const int3 & centerPos) const
|
||||||
|
{
|
||||||
|
return extendTileAround(centerPos) & MapRect(int3(0, 0, centerPos.z), map->width, map->height);
|
||||||
|
}
|
||||||
|
|
||||||
CDrawTerrainOperation::ValidationResult::ValidationResult(bool result, const std::string & transitionReplacement /*= ""*/)
|
CDrawTerrainOperation::ValidationResult::ValidationResult(bool result, const std::string & transitionReplacement /*= ""*/)
|
||||||
: result(result), transitionReplacement(transitionReplacement)
|
: result(result), transitionReplacement(transitionReplacement)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CInsertObjectOperation::CInsertObjectOperation(CMap * map, const int3 & pos, CGObjectInstance * obj)
|
CClearTerrainOperation::CClearTerrainOperation(CMap * map, CRandomGenerator * gen) : CComposedOperation(map)
|
||||||
|
{
|
||||||
|
CTerrainSelection terrainSel(map);
|
||||||
|
terrainSel.selectRange(MapRect(int3(0, 0, 0), map->width, map->height));
|
||||||
|
addOperation(make_unique<CDrawTerrainOperation>(map, terrainSel, ETerrainType::WATER, gen));
|
||||||
|
terrainSel.clearSelection();
|
||||||
|
terrainSel.selectRange(MapRect(int3(0, 0, 1), map->width, map->height));
|
||||||
|
addOperation(make_unique<CDrawTerrainOperation>(map, terrainSel, ETerrainType::ROCK, gen));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CClearTerrainOperation::getLabel() const
|
||||||
|
{
|
||||||
|
return "Clear Terrain";
|
||||||
|
}
|
||||||
|
|
||||||
|
CInsertObjectOperation::CInsertObjectOperation(CMap * map, CGObjectInstance * obj, const int3 & pos)
|
||||||
: CMapOperation(map), pos(pos), obj(obj)
|
: CMapOperation(map), pos(pos), obj(obj)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -38,19 +38,79 @@ struct DLL_LINKAGE MapRect
|
|||||||
|
|
||||||
/// Returns a MapRect of the intersection of this rectangle and the given one.
|
/// Returns a MapRect of the intersection of this rectangle and the given one.
|
||||||
MapRect operator&(const MapRect & rect) const;
|
MapRect operator&(const MapRect & rect) const;
|
||||||
|
|
||||||
|
template<typename Func>
|
||||||
|
void forEach(Func f) const
|
||||||
|
{
|
||||||
|
for(int i = x; i < right(); ++i)
|
||||||
|
{
|
||||||
|
for(int j = y; j < bottom(); ++j)
|
||||||
|
{
|
||||||
|
f(int3(i, j, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Generic selection class to select any type
|
||||||
|
template<typename T>
|
||||||
|
class DLL_LINKAGE CMapSelection
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit CMapSelection(CMap * map) : map(map) { }
|
||||||
|
virtual ~CMapSelection() { };
|
||||||
|
void select(const T & item)
|
||||||
|
{
|
||||||
|
selectedItems.insert(item);
|
||||||
|
}
|
||||||
|
void deselect(const T & item)
|
||||||
|
{
|
||||||
|
selectedItems.erase(item);
|
||||||
|
}
|
||||||
|
std::set<T> getSelectedItems()
|
||||||
|
{
|
||||||
|
return selectedItems;
|
||||||
|
}
|
||||||
|
CMap * getMap() { return map; }
|
||||||
|
virtual void selectRange(const MapRect & rect) { }
|
||||||
|
virtual void deselectRange(const MapRect & rect) { }
|
||||||
|
virtual void selectAll() { }
|
||||||
|
virtual void clearSelection() { }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::set<T> selectedItems;
|
||||||
|
CMap * map;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Selection class to select terrain.
|
||||||
|
class DLL_LINKAGE CTerrainSelection : public CMapSelection<int3>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit CTerrainSelection(CMap * map);
|
||||||
|
void selectRange(const MapRect & rect) override;
|
||||||
|
void deselectRange(const MapRect & rect) override;
|
||||||
|
void selectAll() override;
|
||||||
|
void clearSelection() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Selection class to select objects.
|
||||||
|
class DLL_LINKAGE CObjectSelection: public CMapSelection<CGObjectInstance *>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit CObjectSelection(CMap * map);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The abstract base class CMapOperation defines an operation that can be executed, undone and redone.
|
/// The abstract base class CMapOperation defines an operation that can be executed, undone and redone.
|
||||||
class DLL_LINKAGE CMapOperation : public boost::noncopyable
|
class DLL_LINKAGE CMapOperation : public boost::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CMapOperation(CMap * map);
|
explicit CMapOperation(CMap * map);
|
||||||
virtual ~CMapOperation() { };
|
virtual ~CMapOperation() { };
|
||||||
|
|
||||||
virtual void execute() = 0;
|
virtual void execute() = 0;
|
||||||
virtual void undo() = 0;
|
virtual void undo() = 0;
|
||||||
virtual void redo() = 0;
|
virtual void redo() = 0;
|
||||||
virtual std::string getLabel() const; /// Returns a display-able name of the operation.
|
virtual std::string getLabel() const = 0; /// Returns a display-able name of the operation.
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
CMap * map;
|
CMap * map;
|
||||||
@@ -93,28 +153,50 @@ class DLL_LINKAGE CMapEditManager : boost::noncopyable
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CMapEditManager(CMap * map);
|
CMapEditManager(CMap * map);
|
||||||
|
CMap * getMap();
|
||||||
|
|
||||||
/// Clears the terrain. The free level is filled with water and the underground level with rock.
|
/// Clears the terrain. The free level is filled with water and the underground level with rock.
|
||||||
void clearTerrain(CRandomGenerator * gen);
|
void clearTerrain(CRandomGenerator * gen = nullptr);
|
||||||
|
|
||||||
void drawTerrain(const MapRect & rect, ETerrainType terType, CRandomGenerator * gen);
|
/// Draws terrain at the current terrain selection. The selection will be cleared automatically.
|
||||||
void insertObject(const int3 & pos, CGObjectInstance * obj);
|
void drawTerrain(ETerrainType terType, CRandomGenerator * gen = nullptr);
|
||||||
|
void insertObject(CGObjectInstance * obj, const int3 & pos);
|
||||||
|
|
||||||
|
CTerrainSelection & getTerrainSelection();
|
||||||
|
CObjectSelection & getObjectSelection();
|
||||||
|
|
||||||
CMapUndoManager & getUndoManager();
|
CMapUndoManager & getUndoManager();
|
||||||
void undo();
|
|
||||||
void redo();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void execute(unique_ptr<CMapOperation> && operation);
|
void execute(unique_ptr<CMapOperation> && operation);
|
||||||
|
|
||||||
CMap * map;
|
CMap * map;
|
||||||
CMapUndoManager undoManager;
|
CMapUndoManager undoManager;
|
||||||
|
CRandomGenerator gen;
|
||||||
|
CTerrainSelection terrainSel;
|
||||||
|
CObjectSelection objectSel;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------------- */
|
||||||
/* Implementation/Detail classes, Private API */
|
/* Implementation/Detail classes, Private API */
|
||||||
/* ---------------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/// The CComposedOperation is an operation which consists of several operations.
|
||||||
|
class CComposedOperation : public CMapOperation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CComposedOperation(CMap * map);
|
||||||
|
|
||||||
|
void execute() override;
|
||||||
|
void undo() override;
|
||||||
|
void redo() override;
|
||||||
|
|
||||||
|
void addOperation(unique_ptr<CMapOperation> && operation);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::list<unique_ptr<CMapOperation> > operations;
|
||||||
|
};
|
||||||
|
|
||||||
namespace ETerrainGroup
|
namespace ETerrainGroup
|
||||||
{
|
{
|
||||||
enum ETerrainGroup
|
enum ETerrainGroup
|
||||||
@@ -214,7 +296,7 @@ private:
|
|||||||
class CDrawTerrainOperation : public CMapOperation
|
class CDrawTerrainOperation : public CMapOperation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CDrawTerrainOperation(CMap * map, const MapRect & rect, ETerrainType terType, CRandomGenerator * gen);
|
CDrawTerrainOperation(CMap * map, const CTerrainSelection & terrainSel, ETerrainType terType, CRandomGenerator * gen);
|
||||||
|
|
||||||
void execute() override;
|
void execute() override;
|
||||||
void undo() override;
|
void undo() override;
|
||||||
@@ -232,7 +314,18 @@ private:
|
|||||||
int flip;
|
int flip;
|
||||||
};
|
};
|
||||||
|
|
||||||
void updateTerrainViews(const MapRect & rect);
|
struct InvalidTiles
|
||||||
|
{
|
||||||
|
std::set<int3> foreignTiles, nativeTiles;
|
||||||
|
};
|
||||||
|
|
||||||
|
void updateTerrainTypes();
|
||||||
|
void invalidateTerrainViews(const int3 & centerPos);
|
||||||
|
InvalidTiles getInvalidTiles(const int3 & centerPos) const;
|
||||||
|
MapRect extendTileAround(const int3 & centerPos) const;
|
||||||
|
MapRect extendTileAroundSafely(const int3 & centerPos) const; /// doesn't exceed map size
|
||||||
|
|
||||||
|
void updateTerrainViews();
|
||||||
ETerrainGroup::ETerrainGroup getTerrainGroup(ETerrainType terType) const;
|
ETerrainGroup::ETerrainGroup getTerrainGroup(ETerrainType terType) const;
|
||||||
/// Validates the terrain view of the given position and with the given pattern. The first method wraps the
|
/// Validates the terrain view of the given position and with the given pattern. The first method wraps the
|
||||||
/// second method to validate the terrain view with the given pattern in all four flip directions(horizontal, vertical).
|
/// second method to validate the terrain view with the given pattern in all four flip directions(horizontal, vertical).
|
||||||
@@ -246,16 +339,29 @@ private:
|
|||||||
static const int FLIP_PATTERN_VERTICAL = 2;
|
static const int FLIP_PATTERN_VERTICAL = 2;
|
||||||
static const int FLIP_PATTERN_BOTH = 3;
|
static const int FLIP_PATTERN_BOTH = 3;
|
||||||
|
|
||||||
MapRect rect;
|
CTerrainSelection terrainSel;
|
||||||
ETerrainType terType;
|
ETerrainType terType;
|
||||||
CRandomGenerator * gen;
|
CRandomGenerator * gen;
|
||||||
|
std::set<int3> invalidatedTerViews;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The CClearTerrainOperation clears+initializes the terrain.
|
||||||
|
class CClearTerrainOperation : public CComposedOperation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CClearTerrainOperation(CMap * map, CRandomGenerator * gen);
|
||||||
|
|
||||||
|
std::string getLabel() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The CInsertObjectOperation class inserts an object to the map.
|
/// The CInsertObjectOperation class inserts an object to the map.
|
||||||
class CInsertObjectOperation : public CMapOperation
|
class CInsertObjectOperation : public CMapOperation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CInsertObjectOperation(CMap * map, const int3 & pos, CGObjectInstance * obj);
|
CInsertObjectOperation(CMap * map, CGObjectInstance * obj, const int3 & pos);
|
||||||
|
|
||||||
void execute() override;
|
void execute() override;
|
||||||
void undo() override;
|
void undo() override;
|
||||||
|
|||||||
@@ -422,7 +422,8 @@ void CMapGenerator::genTerrain()
|
|||||||
{
|
{
|
||||||
map->initTerrain();
|
map->initTerrain();
|
||||||
editManager->clearTerrain(&gen);
|
editManager->clearTerrain(&gen);
|
||||||
editManager->drawTerrain(MapRect(int3(10, 10, 0), 20, 30), ETerrainType::GRASS, &gen);
|
editManager->getTerrainSelection().selectRange(MapRect(int3(10, 10, 0), 20, 30));
|
||||||
|
editManager->drawTerrain(ETerrainType::GRASS, &gen);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapGenerator::genTowns()
|
void CMapGenerator::genTowns()
|
||||||
@@ -445,7 +446,7 @@ void CMapGenerator::genTowns()
|
|||||||
town->defInfo = VLC->dobjinfo->gobjs[town->ID][town->subID];
|
town->defInfo = VLC->dobjinfo->gobjs[town->ID][town->subID];
|
||||||
town->builtBuildings.insert(BuildingID::FORT);
|
town->builtBuildings.insert(BuildingID::FORT);
|
||||||
town->builtBuildings.insert(BuildingID::DEFAULT);
|
town->builtBuildings.insert(BuildingID::DEFAULT);
|
||||||
editManager->insertObject(int3(townPos[side].x, townPos[side].y + (i / 2) * 5, 0), town);
|
editManager->insertObject(town, int3(townPos[side].x, townPos[side].y + (i / 2) * 5, 0));
|
||||||
|
|
||||||
// Update player info
|
// Update player info
|
||||||
playerInfo.allowedFactions.clear();
|
playerInfo.allowedFactions.clear();
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ BOOST_AUTO_TEST_CASE(CMapEditManager_DrawTerrain)
|
|||||||
int3 pos(posVector[0].Float(), posVector[1].Float(), posVector[2].Float());
|
int3 pos(posVector[0].Float(), posVector[1].Float(), posVector[2].Float());
|
||||||
logGlobal->infoStream() << boost::format("Test pattern '%s' on position x '%d', y '%d', z '%d'.") % patternStr % pos.x % pos.y % pos.z;
|
logGlobal->infoStream() << boost::format("Test pattern '%s' on position x '%d', y '%d', z '%d'.") % patternStr % pos.x % pos.y % pos.z;
|
||||||
const auto & originalTile = originalMap->getTile(pos);
|
const auto & originalTile = originalMap->getTile(pos);
|
||||||
editManager->drawTerrain(MapRect(pos, 1, 1), originalTile.terType, &gen);
|
editManager->getTerrainSelection().selectRange(MapRect(pos, 1, 1));
|
||||||
|
editManager->drawTerrain(originalTile.terType, &gen);
|
||||||
const auto & tile = map->getTile(pos);
|
const auto & tile = map->getTile(pos);
|
||||||
bool isInRange = false;
|
bool isInRange = false;
|
||||||
BOOST_FOREACH(const auto & range, mapping)
|
BOOST_FOREACH(const auto & range, mapping)
|
||||||
|
|||||||
Reference in New Issue
Block a user