mirror of
https://github.com/vcmi/vcmi.git
synced 2025-05-13 22:06:58 +02:00
more sensible road placement
This commit is contained in:
parent
896a2b17c0
commit
eb60d9737f
@ -13,6 +13,8 @@
|
|||||||
#include "CZonePlacer.h"
|
#include "CZonePlacer.h"
|
||||||
#include "../mapObjects/CObjectClassesHandler.h"
|
#include "../mapObjects/CObjectClassesHandler.h"
|
||||||
|
|
||||||
|
static const int3 dirs4[] = {int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0)};
|
||||||
|
|
||||||
void CMapGenerator::foreach_neighbour(const int3 &pos, std::function<void(int3& pos)> foo)
|
void CMapGenerator::foreach_neighbour(const int3 &pos, std::function<void(int3& pos)> foo)
|
||||||
{
|
{
|
||||||
for(const int3 &dir : dirs)
|
for(const int3 &dir : dirs)
|
||||||
@ -23,6 +25,16 @@ void CMapGenerator::foreach_neighbour(const int3 &pos, std::function<void(int3&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CMapGenerator::foreachDirectNeighbour(const int3& pos, std::function<void(int3& pos)> foo)
|
||||||
|
{
|
||||||
|
for(const int3 &dir : dirs4)
|
||||||
|
{
|
||||||
|
int3 n = pos + dir;
|
||||||
|
if(map->isInTheMap(n))
|
||||||
|
foo(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
CMapGenerator::CMapGenerator() :
|
CMapGenerator::CMapGenerator() :
|
||||||
zonesTotal(0), monolithIndex(0)
|
zonesTotal(0), monolithIndex(0)
|
||||||
@ -421,8 +433,8 @@ void CMapGenerator::createConnections()
|
|||||||
setOccupied (guardPos, ETileType::FREE); //just in case monster is too weak to spawn
|
setOccupied (guardPos, ETileType::FREE); //just in case monster is too weak to spawn
|
||||||
zoneA->addMonster (this, guardPos, connection.getGuardStrength(), false, true);
|
zoneA->addMonster (this, guardPos, connection.getGuardStrength(), false, true);
|
||||||
//zones can make paths only in their own area
|
//zones can make paths only in their own area
|
||||||
zoneA->crunchPath (this, guardPos, posA, zoneA->getId(), zoneA->getFreePaths()); //make connection towards our zone center
|
zoneA->crunchRoad(this, guardPos, posA, zoneA->getFreePaths()); //make connection towards our zone center
|
||||||
zoneB->crunchPath (this, guardPos, posB, zoneB->getId(), zoneB->getFreePaths()); //make connection towards other zone center
|
zoneB->crunchRoad(this, guardPos, posB, zoneB->getFreePaths()); //make connection towards other zone center
|
||||||
break; //we're done with this connection
|
break; //we're done with this connection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,7 @@ public:
|
|||||||
void createConnections();
|
void createConnections();
|
||||||
void findZonesForQuestArts();
|
void findZonesForQuestArts();
|
||||||
void foreach_neighbour(const int3 &pos, std::function<void(int3& pos)> foo);
|
void foreach_neighbour(const int3 &pos, std::function<void(int3& pos)> foo);
|
||||||
|
void foreachDirectNeighbour(const int3 &pos, std::function<void(int3& pos)> foo);
|
||||||
|
|
||||||
bool isBlocked(const int3 &tile) const;
|
bool isBlocked(const int3 &tile) const;
|
||||||
bool shouldBeBlocked(const int3 &tile) const;
|
bool shouldBeBlocked(const int3 &tile) const;
|
||||||
|
@ -575,7 +575,7 @@ void CRmgTemplateZone::fractalize(CMapGenerator* gen)
|
|||||||
//logGlobal->infoStream() << boost::format ("Zone %d subdivided fractally") %id;
|
//logGlobal->infoStream() << boost::format ("Zone %d subdivided fractally") %id;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CRmgTemplateZone::crunchPath (CMapGenerator* gen, const int3 &src, const int3 &dst, TRmgTemplateZoneId zone, std::set<int3>* clearedTiles)
|
bool CRmgTemplateZone::crunchPath(CMapGenerator* gen, const int3 &src, const int3 &dst, std::set<int3>* clearedTiles, bool forRoad)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
make shortest path with free tiles, reachning dst or closest already free tile. Avoid blocks.
|
make shortest path with free tiles, reachning dst or closest already free tile. Avoid blocks.
|
||||||
@ -596,7 +596,8 @@ do not leave zone border
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto lastDistance = distance;
|
auto lastDistance = distance;
|
||||||
gen->foreach_neighbour (currentPos, [this, gen, ¤tPos, dst, &distance, &result, &end, clearedTiles](int3 &pos)
|
|
||||||
|
auto processNeighbours = [this, gen, ¤tPos, dst, &distance, &result, &end, clearedTiles](int3 &pos)
|
||||||
{
|
{
|
||||||
if (!result) //not sure if lambda is worth it...
|
if (!result) //not sure if lambda is worth it...
|
||||||
{
|
{
|
||||||
@ -628,15 +629,21 @@ do not leave zone border
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if(forRoad)
|
||||||
|
gen->foreachDirectNeighbour(currentPos,processNeighbours);
|
||||||
|
else
|
||||||
|
gen->foreach_neighbour (currentPos,processNeighbours);
|
||||||
|
|
||||||
int3 anotherPos(-1, -1, -1);
|
int3 anotherPos(-1, -1, -1);
|
||||||
|
|
||||||
if (!(result || distance < lastDistance)) //we do not advance, use more advaced pathfinding algorithm?
|
if (!(result || distance < lastDistance)) //we do not advance, use more advanced pathfinding algorithm?
|
||||||
{
|
{
|
||||||
//try any nearby tiles, even if its not closer than current
|
//try any nearby tiles, even if its not closer than current
|
||||||
float lastDistance = 2 * distance; //start with significantly larger value
|
float lastDistance = 2 * distance; //start with significantly larger value
|
||||||
gen->foreach_neighbour(currentPos, [this, gen, ¤tPos, dst, &lastDistance, &anotherPos, &end, clearedTiles](int3 &pos)
|
|
||||||
|
auto processNeighbours2 = [this, gen, ¤tPos, dst, &lastDistance, &anotherPos, &end, clearedTiles](int3 &pos)
|
||||||
{
|
{
|
||||||
if (currentPos.dist2dSQ(dst) < lastDistance) //try closest tiles from all surrounding unused tiles
|
if (currentPos.dist2dSQ(dst) < lastDistance) //try closest tiles from all surrounding unused tiles
|
||||||
{
|
{
|
||||||
@ -651,7 +658,14 @@ do not leave zone border
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if(forRoad)
|
||||||
|
gen->foreachDirectNeighbour(currentPos,processNeighbours2);
|
||||||
|
else
|
||||||
|
gen->foreach_neighbour (currentPos,processNeighbours2);
|
||||||
|
|
||||||
|
|
||||||
if (anotherPos.valid())
|
if (anotherPos.valid())
|
||||||
{
|
{
|
||||||
if (clearedTiles)
|
if (clearedTiles)
|
||||||
@ -671,6 +685,26 @@ do not leave zone border
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CRmgTemplateZone::crunchRoad(CMapGenerator* gen, const int3& src, const int3& dst, std::set<int3>* clearedTiles)
|
||||||
|
{
|
||||||
|
std::set<int3> currentClearedTiles;
|
||||||
|
|
||||||
|
if(crunchPath(gen, src, dst, ¤tClearedTiles, true))
|
||||||
|
{
|
||||||
|
roads.insert(std::begin(currentClearedTiles), std::end(currentClearedTiles));
|
||||||
|
|
||||||
|
if(nullptr != clearedTiles)
|
||||||
|
clearedTiles->insert(std::begin(currentClearedTiles), std::end(currentClearedTiles));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void CRmgTemplateZone::addRequiredObject(CGObjectInstance * obj, si32 strength)
|
void CRmgTemplateZone::addRequiredObject(CGObjectInstance * obj, si32 strength)
|
||||||
{
|
{
|
||||||
requiredObjects.push_back(std::make_pair(obj, strength));
|
requiredObjects.push_back(std::make_pair(obj, strength));
|
||||||
@ -904,7 +938,7 @@ bool CRmgTemplateZone::createTreasurePile(CMapGenerator* gen, int3 &pos, float m
|
|||||||
gen->setOccupied(tile, ETileType::BLOCKED); //so that crunch path doesn't cut through objects
|
gen->setOccupied(tile, ETileType::BLOCKED); //so that crunch path doesn't cut through objects
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!crunchPath (gen, closestTile, closestFreeTile, id))
|
if (!crunchPath (gen, closestTile, closestFreeTile))
|
||||||
{
|
{
|
||||||
//we can't connect this pile, just block it off and start over
|
//we can't connect this pile, just block it off and start over
|
||||||
for (auto treasure : treasures)
|
for (auto treasure : treasures)
|
||||||
@ -1239,7 +1273,22 @@ bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen)
|
|||||||
logGlobal->errorStream() << boost::format("Failed to fill zone %d due to lack of space") %id;
|
logGlobal->errorStream() << boost::format("Failed to fill zone %d due to lack of space") %id;
|
||||||
//TODO CLEANUP!
|
//TODO CLEANUP!
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (obj.first->ID)
|
||||||
|
{
|
||||||
|
case Obj::TOWN:
|
||||||
|
case Obj::MONOLITH_TWO_WAY:
|
||||||
|
case Obj::SUBTERRANEAN_GATE:
|
||||||
|
{
|
||||||
|
crunchRoad(gen, this->pos, pos + obj.first->getVisitableOffset(), &freePaths);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
placeObject (gen, obj.first, pos);
|
placeObject (gen, obj.first, pos);
|
||||||
guardObject (gen, obj.first, obj.second, (obj.first->ID == Obj::MONOLITH_TWO_WAY), true);
|
guardObject (gen, obj.first, obj.second, (obj.first->ID == Obj::MONOLITH_TWO_WAY), true);
|
||||||
@ -1434,7 +1483,7 @@ void CRmgTemplateZone::createObstacles2(CMapGenerator* gen)
|
|||||||
void CRmgTemplateZone::drawRoads(CMapGenerator* gen)
|
void CRmgTemplateZone::drawRoads(CMapGenerator* gen)
|
||||||
{
|
{
|
||||||
std::vector<int3> tiles;
|
std::vector<int3> tiles;
|
||||||
for (auto tile : freePaths)
|
for (auto tile : roads)
|
||||||
{
|
{
|
||||||
tiles.push_back (tile);
|
tiles.push_back (tile);
|
||||||
}
|
}
|
||||||
@ -1715,7 +1764,7 @@ bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object,
|
|||||||
{
|
{
|
||||||
//crunching path may fail if center of the zone is directly over wide object
|
//crunching path may fail if center of the zone is directly over wide object
|
||||||
//make sure object is accessible before surrounding it with blocked tiles
|
//make sure object is accessible before surrounding it with blocked tiles
|
||||||
if (crunchPath (gen, tile, findClosestTile(freePaths, tile), id, addToFreePaths ? &freePaths : nullptr))
|
if (crunchPath (gen, tile, findClosestTile(freePaths, tile), addToFreePaths ? &freePaths : nullptr))
|
||||||
{
|
{
|
||||||
guardTile = tile;
|
guardTile = tile;
|
||||||
break;
|
break;
|
||||||
|
@ -167,7 +167,8 @@ public:
|
|||||||
void createTreasures(CMapGenerator* gen);
|
void createTreasures(CMapGenerator* gen);
|
||||||
void createObstacles1(CMapGenerator* gen);
|
void createObstacles1(CMapGenerator* gen);
|
||||||
void createObstacles2(CMapGenerator* gen);
|
void createObstacles2(CMapGenerator* gen);
|
||||||
bool crunchPath (CMapGenerator* gen, const int3 &src, const int3 &dst, TRmgTemplateZoneId zone, std::set<int3>* clearedTiles = nullptr);
|
bool crunchPath(CMapGenerator* gen, const int3 &src, const int3 &dst, std::set<int3>* clearedTiles = nullptr, bool forRoad = false);
|
||||||
|
bool crunchRoad(CMapGenerator* gen, const int3 &src, const int3 &dst, std::set<int3>* clearedTiles = nullptr);
|
||||||
std::vector<int3> getAccessibleOffsets (CMapGenerator* gen, CGObjectInstance* object);
|
std::vector<int3> getAccessibleOffsets (CMapGenerator* gen, CGObjectInstance* object);
|
||||||
|
|
||||||
void addConnection(TRmgTemplateZoneId otherZone);
|
void addConnection(TRmgTemplateZoneId otherZone);
|
||||||
@ -217,6 +218,8 @@ private:
|
|||||||
std::vector<TRmgTemplateZoneId> connections; //list of adjacent zones
|
std::vector<TRmgTemplateZoneId> connections; //list of adjacent zones
|
||||||
std::set<int3> freePaths; //core paths of free tiles that all other objects will be linked to
|
std::set<int3> freePaths; //core paths of free tiles that all other objects will be linked to
|
||||||
|
|
||||||
|
std::set<int3> roads;
|
||||||
|
|
||||||
void drawRoads(CMapGenerator* gen);
|
void drawRoads(CMapGenerator* gen);
|
||||||
|
|
||||||
bool pointIsIn(int x, int y);
|
bool pointIsIn(int x, int y);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user