1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Merge pull request #2237 from vcmi/fictive_connections

Wide, fictive, repulsive connections
This commit is contained in:
DjWarmonger 2023-06-25 19:57:08 +02:00 committed by GitHub
commit a560eaea51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 268 additions and 58 deletions

View File

@ -171,7 +171,7 @@
},
"connections" :
[
{ "a" : "1", "b" : "2", "guard" : 0 },
{ "a" : "1", "b" : "2", "type": "wide" },
{ "a" : "1", "b" : "3", "guard" : 0 },
{ "a" : "1", "b" : "4", "guard" : 0 },
{ "a" : "1", "b" : "5", "guard" : 2000 },
@ -183,19 +183,19 @@
{ "a" : "2", "b" : "3", "guard" : 0 },
{ "a" : "2", "b" : "4", "guard" : 0 },
{ "a" : "2", "b" : "5", "guard" : 2000 },
{ "a" : "5", "b" : "6", "guard" : 0 },
{ "a" : "5", "b" : "6", "type": "wide" },
{ "a" : "5", "b" : "7", "guard" : 0 },
{ "a" : "5", "b" : "8", "guard" : 0 },
{ "a" : "6", "b" : "7", "guard" : 0 },
{ "a" : "6", "b" : "8", "guard" : 0 },
{ "a" : "6", "b" : "9", "guard" : 2000 },
{ "a" : "9", "b" : "10", "guard" : 0 },
{ "a" : "9", "b" : "10", "type": "wide" },
{ "a" : "9", "b" : "11", "guard" : 0 },
{ "a" : "9", "b" : "12", "guard" : 0 },
{ "a" : "10", "b" : "11", "guard" : 0 },
{ "a" : "10", "b" : "12", "guard" : 0 },
{ "a" : "10", "b" : "13", "guard" : 2000 },
{ "a" : "13", "b" : "14", "guard" : 0 },
{ "a" : "13", "b" : "14", "type": "wide" },
{ "a" : "13", "b" : "15", "guard" : 0 },
{ "a" : "13", "b" : "16", "guard" : 0 },
{ "a" : "14", "b" : "15", "guard" : 0 },

View File

@ -93,11 +93,11 @@
"connections" :
[
{ "a" : "1", "b" : "3", "guard" : 6000 },
{ "a" : "1", "b" : "5", "guard" : 0 },
{ "a" : "1", "b" : "7", "guard" : 0 },
{ "a" : "1", "b" : "5", "type": "wide" },
{ "a" : "1", "b" : "7", "type": "wide" },
{ "a" : "2", "b" : "4", "guard" : 6000 },
{ "a" : "2", "b" : "6", "guard" : 0 },
{ "a" : "2", "b" : "8", "guard" : 0 },
{ "a" : "2", "b" : "6", "type": "wide" },
{ "a" : "2", "b" : "8", "type": "wide" },
{ "a" : "5", "b" : "6", "guard" : 6000 },
{ "a" : "7", "b" : "8", "guard" : 6000 }
]

View File

@ -299,8 +299,8 @@
{ "a" : "18", "b" : "22", "guard" : 9000 },
{ "a" : "19", "b" : "24", "guard" : 9000 },
{ "a" : "20", "b" : "25", "guard" : 9000 },
{ "a" : "21", "b" : "22", "guard" : 0 },
{ "a" : "24", "b" : "25", "guard" : 0 }
{ "a" : "21", "b" : "22", "type": "wide" },
{ "a" : "24", "b" : "25", "type": "wide" }
]
}
}

View File

@ -310,8 +310,8 @@
{ "a" : "19", "b" : "24", "guard" : 9000 },
{ "a" : "20", "b" : "25", "guard" : 9000 },
{ "a" : "21", "b" : "22", "guard" : 0 },
{ "a" : "24", "b" : "25", "guard" : 0 }
{ "a" : "21", "b" : "22", "type": "wide" },
{ "a" : "24", "b" : "25", "type": "wide" }
]
}
}

View File

@ -159,10 +159,10 @@
{ "a" : "8", "b" : "9", "guard" : 3000 },
{ "a" : "8", "b" : "11", "guard" : 6000 },
{ "a" : "8", "b" : "12", "guard" : 3000 },
{ "a" : "9", "b" : "10", "guard" : 0 },
{ "a" : "9", "b" : "12", "guard" : 0 },
{ "a" : "10", "b" : "13", "guard" : 0 },
{ "a" : "12", "b" : "13", "guard" : 0 }
{ "a" : "9", "b" : "10", "type": "wide" },
{ "a" : "9", "b" : "12", "type": "wide" },
{ "a" : "10", "b" : "13", "type": "wide" },
{ "a" : "12", "b" : "13", "type": "wide" }
]
}
}

View File

@ -12,6 +12,7 @@
#include <vstd/ContainerUtils.h>
#include <boost/bimap.hpp>
#include "CRmgTemplate.h"
#include "Functions.h"
#include "../VCMI_Lib.h"
#include "../CTownHandler.h"
@ -285,14 +286,20 @@ TRmgTemplateZoneId ZoneOptions::getTreasureLikeZone() const
return treasureLikeZone;
}
void ZoneOptions::addConnection(TRmgTemplateZoneId otherZone)
void ZoneOptions::addConnection(const ZoneConnection & connection)
{
connections.push_back (otherZone);
connectedZoneIds.push_back(connection.getOtherZoneId(getId()));
connectionDetails.push_back(connection);
}
std::vector<TRmgTemplateZoneId> ZoneOptions::getConnections() const
std::vector<ZoneConnection> ZoneOptions::getConnections() const
{
return connections;
return connectionDetails;
}
std::vector<TRmgTemplateZoneId> ZoneOptions::getConnectedZoneIds() const
{
return connectedZoneIds;
}
bool ZoneOptions::areTownsSameType() const
@ -429,7 +436,8 @@ void ZoneOptions::serializeJson(JsonSerializeFormat & handler)
ZoneConnection::ZoneConnection()
: zoneA(-1),
zoneB(-1),
guardStrength(0)
guardStrength(0),
connectionType(EConnectionType::EConnectionType::GUARDED)
{
}
@ -444,10 +452,31 @@ TRmgTemplateZoneId ZoneConnection::getZoneB() const
return zoneB;
}
TRmgTemplateZoneId ZoneConnection::getOtherZoneId(TRmgTemplateZoneId id) const
{
if (id == zoneA)
{
return zoneB;
}
else if (id == zoneB)
{
return zoneA;
}
else
{
throw rmgException("Zone does not belong to this connection");
}
}
int ZoneConnection::getGuardStrength() const
{
return guardStrength;
}
EConnectionType::EConnectionType ZoneConnection::getConnectionType() const
{
return connectionType;
}
bool operator==(const ZoneConnection & l, const ZoneConnection & r)
{
@ -456,9 +485,18 @@ bool operator==(const ZoneConnection & l, const ZoneConnection & r)
void ZoneConnection::serializeJson(JsonSerializeFormat & handler)
{
static const std::vector<std::string> connectionTypes =
{
"guarded",
"fictive",
"repulsive",
"wide"
};
handler.serializeId<TRmgTemplateZoneId, TRmgTemplateZoneId, ZoneEncoder>("a", zoneA, -1);
handler.serializeId<TRmgTemplateZoneId, TRmgTemplateZoneId, ZoneEncoder>("b", zoneB, -1);
handler.serializeInt("guard", guardStrength, 0);
handler.serializeEnum("type", connectionType, connectionTypes);
}
}
@ -526,9 +564,9 @@ const CRmgTemplate::Zones & CRmgTemplate::getZones() const
return zones;
}
const std::vector<ZoneConnection> & CRmgTemplate::getConnections() const
const std::vector<ZoneConnection> & CRmgTemplate::getConnectedZoneIds() const
{
return connections;
return connectedZoneIds;
}
void CRmgTemplate::validate() const
@ -644,7 +682,7 @@ void CRmgTemplate::serializeJson(JsonSerializeFormat & handler)
{
auto connectionsData = handler.enterArray("connections");
connectionsData.serializeStruct(connections);
connectionsData.serializeStruct(connectedZoneIds);
}
{
@ -759,16 +797,18 @@ void CRmgTemplate::afterLoad()
inheritTreasureInfo(zone);
}
for(const auto & connection : connections)
for(const auto & connection : connectedZoneIds)
{
//TODO: Remember connection details and allow to access them from anywhere
auto id1 = connection.getZoneA();
auto id2 = connection.getZoneB();
auto zone1 = zones.at(id1);
auto zone2 = zones.at(id2);
zone1->addConnection(id2);
zone2->addConnection(id1);
zone1->addConnection(connection);
zone2->addConnection(connection);
}
if(allowedWaterContent.empty() || allowedWaterContent.count(EWaterContent::RANDOM))

View File

@ -67,17 +67,31 @@ public:
void serializeJson(JsonSerializeFormat & handler);
};
namespace EConnectionType
{
enum class EConnectionType
{
GUARDED = 0, //default
FICTIVE,
REPULSIVE,
WIDE
};
}
namespace rmg
{
class DLL_LINKAGE ZoneConnection
{
public:
ZoneConnection();
TRmgTemplateZoneId getZoneA() const;
TRmgTemplateZoneId getZoneB() const;
TRmgTemplateZoneId getOtherZoneId(TRmgTemplateZoneId id) const;
int getGuardStrength() const;
EConnectionType::EConnectionType getConnectionType() const;
void serializeJson(JsonSerializeFormat & handler);
@ -86,6 +100,7 @@ private:
TRmgTemplateZoneId zoneA;
TRmgTemplateZoneId zoneB;
int guardStrength;
EConnectionType::EConnectionType connectionType;
};
class DLL_LINKAGE ZoneOptions
@ -149,8 +164,9 @@ public:
TRmgTemplateZoneId getTerrainTypeLikeZone() const;
TRmgTemplateZoneId getTreasureLikeZone() const;
void addConnection(TRmgTemplateZoneId otherZone);
std::vector<TRmgTemplateZoneId> getConnections() const;
void addConnection(const ZoneConnection & connection);
std::vector<ZoneConnection> getConnections() const;
std::vector<TRmgTemplateZoneId> getConnectedZoneIds() const;
void serializeJson(JsonSerializeFormat & handler);
@ -178,7 +194,8 @@ protected:
std::vector<CTreasureInfo> treasureInfo;
std::vector<TRmgTemplateZoneId> connections; //list of adjacent zones
std::vector<TRmgTemplateZoneId> connectedZoneIds; //list of adjacent zone ids
std::vector<ZoneConnection> connectionDetails; //list of connections linked to that zone
TRmgTemplateZoneId minesLikeZone;
TRmgTemplateZoneId terrainTypeLikeZone;
@ -223,7 +240,7 @@ public:
const CPlayerCountRange & getCpuPlayers() const;
std::pair<int3, int3> getMapSizes() const;
const Zones & getZones() const;
const std::vector<rmg::ZoneConnection> & getConnections() const;
const std::vector<rmg::ZoneConnection> & getConnectedZoneIds() const;
void validate() const; /// Tests template on validity and throws exception on failure
@ -235,7 +252,7 @@ private:
int3 minSize, maxSize;
CPlayerCountRange players, cpuPlayers;
Zones zones;
std::vector<rmg::ZoneConnection> connections;
std::vector<rmg::ZoneConnection> connectedZoneIds;
std::set<EWaterContent::EWaterContent> allowedWaterContent;
void afterLoad();

View File

@ -71,10 +71,16 @@ void CZonePlacer::findPathsBetweenZones()
q.pop();
const auto& currentZone = zones.at(current);
const auto& connections = currentZone->getConnections();
const auto& connectedZoneIds = currentZone->getConnections();
for (uint32_t neighbor : connections)
for (auto & connection : connectedZoneIds)
{
if (connection.getConnectionType() == EConnectionType::EConnectionType::REPULSIVE)
{
//Do not consider virtual connections for graph distance
continue;
}
auto neighbor = connection.getOtherZoneId(current);
if (!visited[neighbor])
{
visited[neighbor] = true;
@ -98,7 +104,6 @@ void CZonePlacer::placeOnGrid(CRandomGenerator* rand)
GridType grid(boost::extents[gridSize][gridSize]);
TZoneVector zonesVector(zones.begin(), zones.end());
RandomGeneratorUtil::randomShuffle(zonesVector, *rand);
//Place first zone
@ -132,7 +137,7 @@ void CZonePlacer::placeOnGrid(CRandomGenerator* rand)
{
case ETemplateZoneType::PLAYER_START:
case ETemplateZoneType::CPU_START:
if (firstZone->getConnections().size() > 2)
if (firstZone->getConnectedZoneIds().size() > 2)
{
getRandomEdge(x, y);
}
@ -180,7 +185,7 @@ void CZonePlacer::placeOnGrid(CRandomGenerator* rand)
for (size_t i = 1; i < zones.size(); i++)
{
auto zone = zonesVector[i].second;
auto connections = zone->getConnections();
auto connectedZoneIds = zone->getConnectedZoneIds();
float maxDistance = -1000.0;
int3 mostDistantPlace;
@ -220,16 +225,7 @@ void CZonePlacer::placeOnGrid(CRandomGenerator* rand)
localDistance = -potentialPos.dist2d(int3(existingX, existingY, 0));
}
//Spread apart player starting zones
if (zone->getOwner() && existingZone->getOwner()) //Players participate in game
{
int firstPlayer = zone->getOwner().value();
int secondPlayer = existingZone->getOwner().value();
//Players with lower indexes (especially 1 and 2) will be placed further apart
localDistance *= (1.0f + (2.0f / (firstPlayer * secondPlayer)));
}
localDistance *= scaleForceBetweenZones(zone, existingZone);
distance += localDistance;
}
@ -287,6 +283,23 @@ void CZonePlacer::placeOnGrid(CRandomGenerator* rand)
}
}
float CZonePlacer::scaleForceBetweenZones(const std::shared_ptr<Zone> zoneA, const std::shared_ptr<Zone> zoneB) const
{
if (zoneA->getOwner() && zoneB->getOwner()) //Players participate in game
{
int firstPlayer = zoneA->getOwner().value();
int secondPlayer = zoneB->getOwner().value();
//Players with lower indexes (especially 1 and 2) will be placed further apart
return (1.0f + (2.0f / (firstPlayer * secondPlayer)));
}
else
{
return 1;
}
}
void CZonePlacer::placeZones(CRandomGenerator * rand)
{
logGlobal->info("Starting zone placement");
@ -521,13 +534,18 @@ void CZonePlacer::attractConnectedZones(TZoneMap & zones, TForceVector & forces,
float3 pos = zone.second->getCenter();
float totalDistance = 0;
for (auto con : zone.second->getConnections())
for (const auto & connection : zone.second->getConnections())
{
auto otherZone = zones[con];
if (connection.getConnectionType() == EConnectionType::EConnectionType::REPULSIVE)
{
continue;
}
auto otherZone = zones[connection.getOtherZoneId(zone.second->getId())];
float3 otherZoneCenter = otherZone->getCenter();
auto distance = static_cast<float>(pos.dist2d(otherZoneCenter));
forceVector += (otherZoneCenter - pos) * distance * gravityConstant; //positive value
forceVector += (otherZoneCenter - pos) * distance * gravityConstant * scaleForceBetweenZones(zone.second, otherZone); //positive value
//Attract zone centers always
@ -569,6 +587,7 @@ void CZonePlacer::separateOverlappingZones(TZoneMap &zones, TForceVector &forces
{
float3 localForce = (((otherZoneCenter - pos)*(minDistance / (distance ? distance : 1e-3f))) / getDistance(distance)) * stifness;
//negative value
localForce *= scaleForceBetweenZones(zone.second, otherZone.second);
forceVector -= localForce * (distancesBetweenZones[zone.second->getId()][otherZone.second->getId()] / 2.0f);
overlap += (minDistance - distance); //overlapping of small zones hurts us more
}
@ -601,6 +620,25 @@ void CZonePlacer::separateOverlappingZones(TZoneMap &zones, TForceVector &forces
{
pushAwayFromBoundary(pos.x, 1);
}
//Always move repulsive zones away, no matter their distance
//TODO: Consider z plane?
for (auto& connection : zone.second->getConnections())
{
if (connection.getConnectionType() == EConnectionType::EConnectionType::REPULSIVE)
{
auto & otherZone = zones[connection.getOtherZoneId(zone.second->getId())];
float3 otherZoneCenter = otherZone->getCenter();
//TODO: Roll into lambda?
auto distance = static_cast<float>(pos.dist2d(otherZoneCenter));
float minDistance = (zone.second->getSize() + otherZone->getSize()) / mapSize;
float3 localForce = (((otherZoneCenter - pos)*(minDistance / (distance ? distance : 1e-3f))) / getDistance(distance)) * stifness;
localForce *= (distancesBetweenZones[zone.second->getId()][otherZone->getId()]);
forceVector -= localForce * scaleForceBetweenZones(zone.second, otherZone);
}
}
overlaps[zone.second] = overlap;
forceVector.z = 0; //operator - doesn't preserve z coordinate :/
forces[zone.second] = forceVector;
@ -609,7 +647,9 @@ void CZonePlacer::separateOverlappingZones(TZoneMap &zones, TForceVector &forces
void CZonePlacer::moveOneZone(TZoneMap& zones, TForceVector& totalForces, TDistanceVector& distances, TDistanceVector& overlaps)
{
const int maxDistanceMovementRatio = zones.size() * zones.size(); //The more zones, the greater total distance expected
//The more zones, the greater total distance expected
//Also, higher stiffness make expected movement lower
const int maxDistanceMovementRatio = zones.size() * zones.size() * (stiffnessConstant / stifness);
typedef std::pair<float, std::shared_ptr<Zone>> Misplacement;
std::vector<Misplacement> misplacedZones;
@ -638,7 +678,7 @@ void CZonePlacer::moveOneZone(TZoneMap& zones, TForceVector& totalForces, TDista
boost::sort(misplacedZones, [](const Misplacement& lhs, Misplacement& rhs)
{
return lhs.first > rhs.first; //Biggest first
return lhs.first > rhs.first; //Largest dispalcement first
});
logGlobal->trace("Worst misplacement/movement ratio: %3.2f", misplacedZones.front().first);
@ -649,14 +689,24 @@ void CZonePlacer::moveOneZone(TZoneMap& zones, TForceVector& totalForces, TDista
auto firstZone = misplacedZones.front().second;
std::shared_ptr<Zone> secondZone;
std::set<TRmgTemplateZoneId> connectedZones;
for (const auto& connection : firstZone->getConnections())
{
//FIXME: Should we also exclude fictive connections?
if (connection.getConnectionType() != EConnectionType::EConnectionType::REPULSIVE)
{
connectedZones.insert(connection.getOtherZoneId(firstZone->getId()));
}
}
auto level = firstZone->getCenter().z;
for (size_t i = 1; i < misplacedZones.size(); i++)
{
//Only swap zones on the same level
//Don't swap zones that should be connected (Jebus)
if (misplacedZones[i].second->getCenter().z == level &&
!vstd::contains(firstZone->getConnections(), misplacedZones[i].second->getId()))
!vstd::contains(connectedZones, misplacedZones[i].second->getId()))
{
secondZone = misplacedZones[i].second;
break;
@ -690,7 +740,12 @@ void CZonePlacer::moveOneZone(TZoneMap& zones, TForceVector& totalForces, TDista
float maxDistance = 0;
for (auto con : misplacedZone->getConnections())
{
auto otherZone = zones[con];
if (con.getConnectionType() == EConnectionType::EConnectionType::REPULSIVE)
{
continue;
}
auto otherZone = zones[con.getOtherZoneId(misplacedZone->getId())];
float distance = static_cast<float>(otherZone->getCenter().dist2dSQ(ourCenter));
if (distance > maxDistance)
{

View File

@ -40,6 +40,7 @@ public:
void placeZones(CRandomGenerator * rand);
void findPathsBetweenZones();
void placeOnGrid(CRandomGenerator* rand);
float scaleForceBetweenZones(const std::shared_ptr<Zone> zoneA, const std::shared_ptr<Zone> zoneB) const;
void assignZones(CRandomGenerator * rand);
const TDistanceMap & getDistanceMap();

View File

@ -79,7 +79,7 @@ void ConnectionsPlacer::init()
POSTFUNCTION(RoadPlacer);
POSTFUNCTION(ObjectManager);
for(auto c : map.getMapGenOptions().getMapTemplate()->getConnections())
for(auto c : map.getMapGenOptions().getMapTemplate()->getConnectedZoneIds())
addConnection(c);
}
@ -108,8 +108,67 @@ void ConnectionsPlacer::selfSideDirectConnection(const rmg::ZoneConnection & con
|| vstd::contains(otherTerrain->prohibitTransitions, zone.getTerrainType());
auto directConnectionIterator = dNeighbourZones.find(otherZoneId);
if (directConnectionIterator != dNeighbourZones.end())
{
if (connection.getConnectionType() == EConnectionType::EConnectionType::WIDE)
{
for (auto borderPos : directConnectionIterator->second)
{
//TODO: Refactor common code with direct connection
int3 potentialPos = zone.areaPossible().nearest(borderPos);
assert(borderPos != potentialPos);
auto safetyGap = rmg::Area({ potentialPos });
safetyGap.unite(safetyGap.getBorderOutside());
safetyGap.intersect(zone.areaPossible());
if (!safetyGap.empty())
{
safetyGap.intersect(otherZone->areaPossible());
if (safetyGap.empty())
{
rmg::Area border(zone.getArea().getBorder());
border.unite(otherZone->getArea().getBorder());
auto costFunction = [&border](const int3& s, const int3& d)
{
return 1.f / (1.f + border.distanceSqr(d));
};
auto ourArea = zone.areaPossible() + zone.freePaths();
auto theirArea = otherZone->areaPossible() + otherZone->freePaths();
theirArea.add(potentialPos);
rmg::Path ourPath(ourArea);
rmg::Path theirPath(theirArea);
ourPath.connect(zone.freePaths());
ourPath = ourPath.search(potentialPos, true, costFunction);
theirPath.connect(otherZone->freePaths());
theirPath = theirPath.search(potentialPos, true, costFunction);
if (ourPath.valid() && theirPath.valid())
{
zone.connectPath(ourPath);
otherZone->connectPath(theirPath);
otherZone->getModificator<ObjectManager>()->updateDistances(potentialPos);
success = true;
break;
}
}
}
}
}
}
if (connection.getConnectionType() == EConnectionType::EConnectionType::FICTIVE ||
connection.getConnectionType() == EConnectionType::EConnectionType::REPULSIVE)
{
//Fictive or repulsive connections are not real, take no action
dCompleted.push_back(connection);
return;
}
float maxDist = -10e6;
if(!directProhibited && directConnectionIterator != dNeighbourZones.end())
if(!success && !directProhibited && directConnectionIterator != dNeighbourZones.end())
{
int3 guardPos(-1, -1, -1);
int3 roadNode;
@ -187,9 +246,12 @@ void ConnectionsPlacer::selfSideDirectConnection(const rmg::ZoneConnection & con
}
else
{
//Update distances from empty passage, too
zone.areaPossible().erase(guardPos);
zone.freePaths().add(guardPos);
map.setOccupied(guardPos, ETileType::FREE);
manager.updateDistances(guardPos);
otherZone->getModificator<ObjectManager>()->updateDistances(guardPos);
}
assert(zone.getModificator<RoadPlacer>());
@ -334,6 +396,23 @@ void ConnectionsPlacer::createBorder()
return map.isOnMap(tile) && map.getZones()[map.getZoneID(tile)]->getType() != ETemplateZoneType::WATER;
});
//No border for wide connections
for (auto& connection : zone.getConnections()) // We actually placed that connection already
{
auto otherZone = connection.getOtherZoneId(zone.getId());
if (connection.getConnectionType() == EConnectionType::EConnectionType::WIDE)
{
auto sharedBorder = borderArea.getSubarea([this, otherZone, &borderOutsideArea](const int3 & t)
{
auto tile = borderOutsideArea.nearest(t);
return map.isOnMap(tile) && map.getZones()[map.getZoneID(tile)]->getId() == otherZone;
});
blockBorder.subtract(sharedBorder);
}
};
Zone::Lock lock(zone.areaMutex); //Protect from erasing same tiles again
for(const auto & tile : blockBorder.getTilesVector())
{

View File

@ -76,12 +76,28 @@ void ObjectManager::addNearbyObject(CGObjectInstance * obj, CGObjectInstance * n
}
void ObjectManager::updateDistances(const rmg::Object & obj)
{
updateDistances([obj](const int3& tile) -> ui32
{
return obj.getArea().distanceSqr(tile); //optimization, only relative distance is interesting
});
}
void ObjectManager::updateDistances(const int3 & pos)
{
updateDistances([pos](const int3& tile) -> ui32
{
return pos.dist2dSQ(tile); //optimization, only relative distance is interesting
});
}
void ObjectManager::updateDistances(std::function<ui32(const int3 & tile)> distanceFunction)
{
RecursiveLock lock(externalAccessMutex);
tilesByDistance.clear();
for (auto tile : zone.areaPossible().getTiles()) //don't need to mark distance for not possible tiles
{
ui32 d = obj.getArea().distanceSqr(tile); //optimization, only relative distance is interesting
ui32 d = distanceFunction(tile);
map.setNearestObjectDistance(tile, std::min(static_cast<float>(d), map.getNearestObjectDistance(tile)));
tilesByDistance.push(std::make_pair(tile, map.getNearestObjectDistance(tile)));
}

View File

@ -62,6 +62,8 @@ public:
void placeObject(rmg::Object & object, bool guarded, bool updateDistance);
void updateDistances(const rmg::Object & obj);
void updateDistances(const int3& pos);
void updateDistances(std::function<ui32(const int3 & tile)> distanceFunction);
void createDistancesPriorityQueue();
const rmg::Area & getVisitableArea() const;

View File

@ -404,7 +404,7 @@ void TreasurePlacer::addAllPossibleObjects()
//Seer huts with creatures or generic rewards
if(zone.getConnections().size()) //Unlikely, but...
if(zone.getConnectedZoneIds().size()) //Unlikely, but...
{
auto * qap = zone.getModificator<QuestArtifactPlacer>();
if(!qap)