1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-04-15 11:46:56 +02:00

Merge pull request #4341 from vcmi/force_portal_connection

Add RMG connection option "forcePortal"
This commit is contained in:
Ivan Savenko 2024-08-07 13:07:45 +03:00 committed by GitHub
commit 65af198fbf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 86 additions and 26 deletions

View File

@ -99,7 +99,7 @@
"type": "type":
{ {
"type" : "string", "type" : "string",
"enum" : ["wide", "fictive", "repulsive"] "enum" : ["wide", "fictive", "repulsive", "forcePortal"]
} }
} }
}, },

View File

@ -38,7 +38,7 @@
{ "a" : "zoneA", "b" : "zoneB", "guard" : 5000, "road" : "false" }, { "a" : "zoneA", "b" : "zoneB", "guard" : 5000, "road" : "false" },
{ "a" : "zoneA", "b" : "zoneC", "guard" : 5000, "road" : "random" }, { "a" : "zoneA", "b" : "zoneC", "guard" : 5000, "road" : "random" },
{ "a" : "zoneB", "b" : "zoneC", "type" : "wide" } { "a" : "zoneB", "b" : "zoneC", "type" : "wide" }
//"type" can be "guarded" (default), "wide", "fictive" or "repulsive" //"type" can be "guarded" (default), "wide", "fictive", "repulsive" or "forcePortal"
//"wide" connections have no border, or guard. "fictive" and "repulsive" connections are virtual - //"wide" connections have no border, or guard. "fictive" and "repulsive" connections are virtual -
//they do not create actual path, but only attract or repulse zones, respectively //they do not create actual path, but only attract or repulse zones, respectively
] ]

View File

@ -463,7 +463,8 @@ void ZoneConnection::serializeJson(JsonSerializeFormat & handler)
"guarded", "guarded",
"fictive", "fictive",
"repulsive", "repulsive",
"wide" "wide",
"forcePortal"
}; };
static const std::vector<std::string> roadOptions = static const std::vector<std::string> roadOptions =

View File

@ -75,7 +75,8 @@ enum class EConnectionType
GUARDED = 0, //default GUARDED = 0, //default
FICTIVE, FICTIVE,
REPULSIVE, REPULSIVE,
WIDE WIDE,
FORCE_PORTAL
}; };
enum class ERoadOption enum class ERoadOption

View File

@ -80,12 +80,21 @@ void CZonePlacer::findPathsBetweenZones()
for (auto & connection : connectedZoneIds) for (auto & connection : connectedZoneIds)
{ {
if (connection.getConnectionType() == rmg::EConnectionType::REPULSIVE) switch (connection.getConnectionType())
{ {
//Do not consider virtual connections for graph distance //Do not consider virtual connections for graph distance
continue; case rmg::EConnectionType::REPULSIVE:
case rmg::EConnectionType::FORCE_PORTAL:
continue;
} }
auto neighbor = connection.getOtherZoneId(current); auto neighbor = connection.getOtherZoneId(current);
if (current == neighbor)
{
//Do not consider self-connections
continue;
}
if (!visited[neighbor]) if (!visited[neighbor])
{ {
visited[neighbor] = true; visited[neighbor] = true;
@ -552,8 +561,16 @@ void CZonePlacer::attractConnectedZones(TZoneMap & zones, TForceVector & forces,
for (const auto & connection : zone.second->getConnections()) for (const auto & connection : zone.second->getConnections())
{ {
if (connection.getConnectionType() == rmg::EConnectionType::REPULSIVE) switch (connection.getConnectionType())
{ {
//Do not consider virtual connections for graph distance
case rmg::EConnectionType::REPULSIVE:
case rmg::EConnectionType::FORCE_PORTAL:
continue;
}
if (connection.getZoneA() == connection.getZoneB())
{
//Do not consider self-connections
continue; continue;
} }
@ -710,11 +727,19 @@ void CZonePlacer::moveOneZone(TZoneMap& zones, TForceVector& totalForces, TDista
std::set<TRmgTemplateZoneId> connectedZones; std::set<TRmgTemplateZoneId> connectedZones;
for (const auto& connection : firstZone->getConnections()) for (const auto& connection : firstZone->getConnections())
{ {
//FIXME: Should we also exclude fictive connections? switch (connection.getConnectionType())
if (connection.getConnectionType() != rmg::EConnectionType::REPULSIVE)
{ {
connectedZones.insert(connection.getOtherZoneId(firstZone->getId())); //Do not consider virtual connections for graph distance
case rmg::EConnectionType::REPULSIVE:
case rmg::EConnectionType::FORCE_PORTAL:
continue;
} }
if (connection.getZoneA() == connection.getZoneB())
{
//Do not consider self-connections
continue;
}
connectedZones.insert(connection.getOtherZoneId(firstZone->getId()));
} }
auto level = firstZone->getCenter().z; auto level = firstZone->getCenter().z;

View File

@ -55,6 +55,17 @@ void ConnectionsPlacer::process()
{ {
for (auto& c : dConnections) for (auto& c : dConnections)
{ {
if (c.getZoneA() == c.getZoneB())
{
// Zone can always be connected to itself, but only by monolith pair
RecursiveLock lock(externalAccessMutex);
if (!vstd::contains(dCompleted, c))
{
placeMonolithConnection(c);
continue;
}
}
auto otherZone = map.getZones().at(c.getZoneB()); auto otherZone = map.getZones().at(c.getZoneB());
auto* cp = otherZone->getModificator<ConnectionsPlacer>(); auto* cp = otherZone->getModificator<ConnectionsPlacer>();
@ -74,6 +85,11 @@ void ConnectionsPlacer::process()
} }
}; };
diningPhilosophers([this](const rmg::ZoneConnection& c)
{
forcePortalConnection(c);
});
diningPhilosophers([this](const rmg::ZoneConnection& c) diningPhilosophers([this](const rmg::ZoneConnection& c)
{ {
selfSideDirectConnection(c); selfSideDirectConnection(c);
@ -115,6 +131,15 @@ void ConnectionsPlacer::otherSideConnection(const rmg::ZoneConnection & connecti
dCompleted.push_back(connection); dCompleted.push_back(connection);
} }
void ConnectionsPlacer::forcePortalConnection(const rmg::ZoneConnection & connection)
{
// This should always succeed
if (connection.getConnectionType() == rmg::EConnectionType::FORCE_PORTAL)
{
placeMonolithConnection(connection);
}
}
void ConnectionsPlacer::selfSideDirectConnection(const rmg::ZoneConnection & connection) void ConnectionsPlacer::selfSideDirectConnection(const rmg::ZoneConnection & connection)
{ {
bool success = false; bool success = false;
@ -410,23 +435,30 @@ void ConnectionsPlacer::selfSideIndirectConnection(const rmg::ZoneConnection & c
//4. place monoliths/portals //4. place monoliths/portals
if(!success) if(!success)
{ {
auto factory = VLC->objtypeh->getHandlerFor(Obj::MONOLITH_TWO_WAY, generator.getNextMonlithIndex()); placeMonolithConnection(connection);
auto * teleport1 = factory->create(map.mapInstance->cb, nullptr);
auto * teleport2 = factory->create(map.mapInstance->cb, nullptr);
RequiredObjectInfo obj1(teleport1, connection.getGuardStrength(), allowRoad);
RequiredObjectInfo obj2(teleport2, connection.getGuardStrength(), allowRoad);
zone.getModificator<ObjectManager>()->addRequiredObject(obj1);
otherZone->getModificator<ObjectManager>()->addRequiredObject(obj2);
assert(otherZone->getModificator<ConnectionsPlacer>());
otherZone->getModificator<ConnectionsPlacer>()->otherSideConnection(connection);
success = true;
} }
}
void ConnectionsPlacer::placeMonolithConnection(const rmg::ZoneConnection & connection)
{
auto otherZoneId = (connection.getZoneA() == zone.getId() ? connection.getZoneB() : connection.getZoneA());
auto & otherZone = map.getZones().at(otherZoneId);
bool allowRoad = shouldGenerateRoad(connection);
auto factory = VLC->objtypeh->getHandlerFor(Obj::MONOLITH_TWO_WAY, generator.getNextMonlithIndex());
auto * teleport1 = factory->create(map.mapInstance->cb, nullptr);
auto * teleport2 = factory->create(map.mapInstance->cb, nullptr);
RequiredObjectInfo obj1(teleport1, connection.getGuardStrength(), allowRoad);
RequiredObjectInfo obj2(teleport2, connection.getGuardStrength(), allowRoad);
zone.getModificator<ObjectManager>()->addRequiredObject(obj1);
otherZone->getModificator<ObjectManager>()->addRequiredObject(obj2);
dCompleted.push_back(connection);
if(success) assert(otherZone->getModificator<ConnectionsPlacer>());
dCompleted.push_back(connection); otherZone->getModificator<ConnectionsPlacer>()->otherSideConnection(connection);
} }
void ConnectionsPlacer::collectNeighbourZones() void ConnectionsPlacer::collectNeighbourZones()

View File

@ -23,7 +23,8 @@ public:
void init() override; void init() override;
void addConnection(const rmg::ZoneConnection& connection); void addConnection(const rmg::ZoneConnection& connection);
void placeMonolithConnection(const rmg::ZoneConnection& connection);
void forcePortalConnection(const rmg::ZoneConnection & connection);
void selfSideDirectConnection(const rmg::ZoneConnection & connection); void selfSideDirectConnection(const rmg::ZoneConnection & connection);
void selfSideIndirectConnection(const rmg::ZoneConnection & connection); void selfSideIndirectConnection(const rmg::ZoneConnection & connection);
void otherSideConnection(const rmg::ZoneConnection & connection); void otherSideConnection(const rmg::ZoneConnection & connection);