1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +02:00

Ground connections between adjacent zones.

This commit is contained in:
DjWarmonger 2014-05-31 10:56:14 +02:00
parent 8ab2a8df86
commit 8e8b27087a
5 changed files with 152 additions and 20 deletions

View File

@ -350,6 +350,21 @@ std::set<int3> CGObjectInstance::getBlockedPos() const
return ret;
}
std::set<int3> CGObjectInstance::getBlockedOffsets() const
{
std::set<int3> ret;
for(int w=0; w<getWidth(); ++w)
{
for(int h=0; h<getHeight(); ++h)
{
if (appearance.isBlockedAt(w, h))
ret.insert(int3(-w, -h, 0));
}
}
return ret;
}
bool CGObjectInstance::operator<(const CGObjectInstance & cmp) const //screen printing priority comparing
{
if (appearance.printPriority != cmp.appearance.printPriority)

View File

@ -227,6 +227,7 @@ public:
bool blockingAt(int x, int y) const; //returns true if object is blocking location (x, y) (h3m pos)
bool coveringAt(int x, int y) const; //returns true if object covers with picture location (x, y) (h3m pos)
std::set<int3> getBlockedPos() const; //returns set of positions blocked by this object
std::set<int3> getBlockedOffsets() const; //returns set of relative positions blocked by this object
bool isVisitable() const; //returns true if object is visitable
bool operator<(const CGObjectInstance & cmp) const; //screen printing priority comparing
void hideTiles(PlayerColor ourplayer, int radius) const;

View File

@ -207,14 +207,6 @@ void CMapGenerator::genZones()
for(auto const it : zones)
{
CRmgTemplateZone * zone = it.second;
std::vector<int3> shape;
int left = part_w*(i%player_per_side);
int top = part_h*(i/player_per_side);
shape.push_back(int3(left, top, 0));
shape.push_back(int3(left + part_w, top, 0));
shape.push_back(int3(left + part_w, top + part_h, 0));
shape.push_back(int3(left, top + part_h, 0));
zone->setShape(shape);
zone->setType(i < pcnt ? ETemplateZoneType::PLAYER_START : ETemplateZoneType::TREASURE);
this->zones[it.first] = zone;
++i;
@ -225,8 +217,14 @@ void CMapGenerator::genZones()
void CMapGenerator::fillZones()
{
logGlobal->infoStream() << "Started filling zones";
for(auto it : zones)
for (auto it : zones)
{
it.second->createConnections(this);
}
for (auto it : zones)
{
//make sure all connections are passable before creating borders
it.second->createBorder(this);
it.second->fill(this);
}

View File

@ -297,11 +297,6 @@ bool CRmgTemplateZone::pointIsIn(int x, int y)
return true;
}
void CRmgTemplateZone::setShape(std::vector<int3> shape)
{
this->shape = shape;
}
int3 CRmgTemplateZone::getPos() const
{
return pos;
@ -316,6 +311,44 @@ void CRmgTemplateZone::addTile (const int3 &pos)
tileinfo.insert(pos);
}
std::set<int3> CRmgTemplateZone::getTileInfo () const
{
return tileinfo;
}
void CRmgTemplateZone::createConnections(CMapGenerator* gen)
{
for (auto connection : connections)
{
if (getId() > connection) //only one connection between each pair
continue;
int3 guardPos(-1,-1,-1);
auto otherZoneTiles = gen->getZones()[connection]->getTileInfo();
auto otherZoneCenter = gen->getZones()[connection]->getPos();
for (auto tile : tileinfo)
{
gen->foreach_neighbour (tile, [&guardPos, tile, &otherZoneTiles](int3 &pos)
{
if (vstd::contains(otherZoneTiles, pos))
guardPos = tile;
});
if (guardPos.valid())
{
gen->setOccupied (pos, ETileType::FREE); //TODO: place monster here
//zones can make paths only in their own area
this->crunchPath (gen, guardPos, this->getPos(), this->getId()); //make connection towards our zone center
gen->getZones()[connection]->crunchPath (gen, guardPos, otherZoneCenter, connection); //make connection towards other zone center
break; //we're done with this connection
}
}
if (!guardPos.valid())
logGlobal->warnStream() << boost::format ("Did not find connection between zones %d and %d") %getId() %connection;
}
}
void CRmgTemplateZone::createBorder(CMapGenerator* gen)
{
for (auto tile : tileinfo)
@ -323,11 +356,78 @@ void CRmgTemplateZone::createBorder(CMapGenerator* gen)
gen->foreach_neighbour (tile, [this, gen](int3 &pos)
{
if (!vstd::contains(this->tileinfo, pos))
gen->setOccupied (pos, ETileType::BLOCKED);
{
gen->foreach_neighbour (pos, [this, gen](int3 &pos)
{
if (gen->isPossible(pos))
gen->setOccupied (pos, ETileType::BLOCKED);
});
}
});
}
}
bool CRmgTemplateZone::crunchPath (CMapGenerator* gen, int3 &src, int3 &dst, TRmgTemplateZoneId zone)
{
/*
make shortest path with free tiles, reachning dst or closest already free tile. Avoid blocks.
do not leave zone border
*/
bool result = false;
bool end = false;
int3 currentPos = src;
float distance = currentPos.dist2dSQ (dst);
while (!end)
{
if (currentPos == dst)
break;
auto lastDistance = distance;
gen->foreach_neighbour (currentPos, [this, gen, &currentPos, dst, &distance, &result, &end](int3 &pos)
{
if (!result) //not sure if lambda is worth it...
{
if (pos == dst)
{
result = true;
end = true;
}
if (pos.dist2dSQ (dst) < distance)
{
if (!gen->isBlocked(pos))
{
if (vstd::contains (tileinfo, pos))
{
if (gen->isPossible(pos))
{
gen->setOccupied (pos, ETileType::FREE);
currentPos = pos;
distance = currentPos.dist2dSQ (dst);
}
else if (gen->isFree(pos))
{
end = true;
result = true;
}
else
throw rmgException(boost::to_string(boost::format("Tile %s of uknown type found on path") % pos()));
}
}
}
}
});
if (!(result || distance < lastDistance)) //we do not advance, use more avdnaced pathfinding algorithm?
{
logGlobal->warnStream() << boost::format ("No tile closer than %s found on path from %s to %s") %currentPos %src %dst;
break;
}
}
return result;
}
bool CRmgTemplateZone::fill(CMapGenerator* gen)
{
std::vector<CGObjectInstance*> required_objects;
@ -486,12 +586,27 @@ bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance*
continue;
if (gen->isPossible(tile) && (dist >= min_dist) && (dist > best_distance))
{
best_distance = dist;
pos = tile;
gen->setOccupied(pos, ETileType::BLOCKED);
result = true;
bool allTilesAvailable = true;
for (auto blockingTile : obj->getBlockedOffsets())
{
if (!gen->isPossible(pos + blockingTile))
{
allTilesAvailable = false; //if at least one tile is not possible, object can't be placed here
break;
}
}
if (allTilesAvailable)
{
best_distance = dist;
pos = tile;
result = true;
}
}
}
if (result)
{
gen->setOccupied(pos, ETileType::BLOCKED); //block that tile
}
return result;
}

View File

@ -110,9 +110,12 @@ public:
void setPos(const int3 &pos);
void addTile (const int3 &pos);
void setShape(std::vector<int3> shape);
std::set<int3> getTileInfo () const;
bool fill(CMapGenerator* gen);
void createConnections(CMapGenerator* gen);
void createBorder(CMapGenerator* gen);
bool crunchPath (CMapGenerator* gen, int3 &src, int3 &dst, TRmgTemplateZoneId zone);
void addConnection(TRmgTemplateZoneId otherZone);
std::vector<TRmgTemplateZoneId> getConnections() const;