1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +02:00

- Add new option for connection

- Store info about objects and roads in RequiredObjectInfo
This commit is contained in:
Tomasz Zieliński
2023-07-06 22:15:00 +02:00
parent fcf7a29f45
commit 0d3ac4a502
8 changed files with 139 additions and 59 deletions

View File

@@ -435,11 +435,12 @@ void ZoneOptions::serializeJson(JsonSerializeFormat & handler)
}
}
ZoneConnection::ZoneConnection()
: zoneA(-1),
ZoneConnection::ZoneConnection():
zoneA(-1),
zoneB(-1),
guardStrength(0),
connectionType(EConnectionType::EConnectionType::GUARDED)
connectionType(EConnectionType::EConnectionType::GUARDED),
hasRoad(ERoadOption::ERoadOption::ROAD_TRUE)
{
}
@@ -479,6 +480,11 @@ EConnectionType::EConnectionType ZoneConnection::getConnectionType() const
{
return connectionType;
}
ERoadOption::ERoadOption ZoneConnection::getRoadOption() const
{
return hasRoad;
}
bool operator==(const ZoneConnection & l, const ZoneConnection & r)
{
@@ -495,10 +501,18 @@ void ZoneConnection::serializeJson(JsonSerializeFormat & handler)
"wide"
};
static const std::vector<std::string> roadOptions =
{
"true",
"false",
"random"
};
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);
handler.serializeEnum("road", hasRoad, roadOptions);
}
}

View File

@@ -78,6 +78,16 @@ namespace EConnectionType
};
}
namespace ERoadOption
{
enum class ERoadOption
{
ROAD_TRUE,
ROAD_FALSE,
ROAD_RANDOM
};
}
namespace rmg
{
@@ -92,6 +102,7 @@ public:
TRmgTemplateZoneId getOtherZoneId(TRmgTemplateZoneId id) const;
int getGuardStrength() const;
EConnectionType::EConnectionType getConnectionType() const;
ERoadOption::ERoadOption getRoadOption() const;
void serializeJson(JsonSerializeFormat & handler);
@@ -101,6 +112,7 @@ private:
TRmgTemplateZoneId zoneB;
int guardStrength;
EConnectionType::EConnectionType connectionType;
ERoadOption::ERoadOption hasRoad;
};
class DLL_LINKAGE ZoneOptions

View File

@@ -254,15 +254,18 @@ void ConnectionsPlacer::selfSideDirectConnection(const rmg::ZoneConnection & con
otherZone->getModificator<ObjectManager>()->updateDistances(guardPos);
}
assert(zone.getModificator<RoadPlacer>());
zone.getModificator<RoadPlacer>()->addRoadNode(guardPos);
assert(otherZone->getModificator<RoadPlacer>());
otherZone->getModificator<RoadPlacer>()->addRoadNode(roadNode);
assert(otherZone->getModificator<ConnectionsPlacer>());
otherZone->getModificator<ConnectionsPlacer>()->otherSideConnection(connection);
if (shouldGenerateRoad(connection))
{
assert(zone.getModificator<RoadPlacer>());
zone.getModificator<RoadPlacer>()->addRoadNode(guardPos);
assert(otherZone->getModificator<RoadPlacer>());
otherZone->getModificator<RoadPlacer>()->addRoadNode(roadNode);
assert(otherZone->getModificator<ConnectionsPlacer>());
otherZone->getModificator<ConnectionsPlacer>()->otherSideConnection(connection);
}
success = true;
}
}
@@ -292,6 +295,8 @@ void ConnectionsPlacer::selfSideIndirectConnection(const rmg::ZoneConnection & c
bool success = false;
auto otherZoneId = (connection.getZoneA() == zone.getId() ? connection.getZoneB() : connection.getZoneA());
auto & otherZone = map.getZones().at(otherZoneId);
bool allowRoad = shouldGenerateRoad(connection);
//3. place subterrain gates
if(zone.isUnderground() != otherZone->isUnderground())
@@ -341,6 +346,7 @@ void ConnectionsPlacer::selfSideIndirectConnection(const rmg::ZoneConnection & c
zone.connectPath(path1);
otherZone->connectPath(path2);
//TODO: Check allowRoad
manager.placeObject(rmgGate1, guarded1, true);
managerOther.placeObject(rmgGate2, guarded2, true);
@@ -359,8 +365,10 @@ void ConnectionsPlacer::selfSideIndirectConnection(const rmg::ZoneConnection & c
auto * teleport1 = factory->create();
auto * teleport2 = factory->create();
zone.getModificator<ObjectManager>()->addRequiredObject(teleport1, connection.getGuardStrength());
otherZone->getModificator<ObjectManager>()->addRequiredObject(teleport2, connection.getGuardStrength());
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);
@@ -386,6 +394,12 @@ void ConnectionsPlacer::collectNeighbourZones()
}
}
bool ConnectionsPlacer::shouldGenerateRoad(const rmg::ZoneConnection& connection) const
{
return connection.getRoadOption() == ERoadOption::ERoadOption::ROAD_TRUE ||
(connection.getRoadOption() == ERoadOption::ERoadOption::ROAD_RANDOM && zone.getRand().nextDouble() >= 0.5f);
}
void ConnectionsPlacer::createBorder()
{
rmg::Area borderArea(zone.getArea().getBorder());

View File

@@ -28,11 +28,14 @@ public:
void selfSideIndirectConnection(const rmg::ZoneConnection & connection);
void otherSideConnection(const rmg::ZoneConnection & connection);
void createBorder();
bool shouldGenerateRoad(const rmg::ZoneConnection& connection) const;
protected:
void collectNeighbourZones();
protected:
std::vector<rmg::ZoneConnection> dConnections, dCompleted;
std::map<TRmgTemplateZoneId, rmg::Tileset> dNeighbourZones;
};

View File

@@ -63,8 +63,11 @@ bool MinePlacer::placeMines(ObjectManager & manager)
createdMines.push_back(mine);
if(!i && (res == EGameResID::WOOD || res == EGameResID::ORE))
manager.addCloseObject(mine, rmginfo.value); //only first wood&ore mines are close
if (!i && (res == EGameResID::WOOD || res == EGameResID::ORE))
{
//only first wood&ore mines are close
manager.addCloseObject(RequiredObjectInfo(mine, rmginfo.value));
}
else
requiredObjects.push_back(std::pair<CGObjectInstance*, ui32>(mine, rmginfo.value));
}
@@ -74,7 +77,7 @@ bool MinePlacer::placeMines(ObjectManager & manager)
RandomGeneratorUtil::randomShuffle(requiredObjects, zone.getRand());
for (const auto& obj : requiredObjects)
{
manager.addRequiredObject(obj.first, obj.second);
manager.addRequiredObject(RequiredObjectInfo(obj.first, obj.second));
}
//create extra resources
@@ -84,9 +87,13 @@ bool MinePlacer::placeMines(ObjectManager & manager)
{
for(int rc = zone.getRand().nextInt(1, extraRes); rc > 0; --rc)
{
auto * resourse = dynamic_cast<CGResource *>(VLC->objtypeh->getHandlerFor(Obj::RESOURCE, mine->producedResource)->create());
resourse->amount = CGResource::RANDOM_AMOUNT;
manager.addNearbyObject(resourse, mine);
auto * resource = dynamic_cast<CGResource *>(VLC->objtypeh->getHandlerFor(Obj::RESOURCE, mine->producedResource)->create());
resource->amount = CGResource::RANDOM_AMOUNT;
RequiredObjectInfo roi;
roi.obj = resource;
roi.nearbyTarget = mine;
manager.addNearbyObject(roi);
}
}
}

View File

@@ -57,22 +57,22 @@ void ObjectManager::createDistancesPriorityQueue()
}
}
void ObjectManager::addRequiredObject(CGObjectInstance * obj, si32 strength)
void ObjectManager::addRequiredObject(const RequiredObjectInfo & info)
{
RecursiveLock lock(externalAccessMutex);
requiredObjects.emplace_back(obj, strength);
requiredObjects.emplace_back(info);
}
void ObjectManager::addCloseObject(CGObjectInstance * obj, si32 strength)
void ObjectManager::addCloseObject(const RequiredObjectInfo & info)
{
RecursiveLock lock(externalAccessMutex);
closeObjects.emplace_back(obj, strength);
closeObjects.emplace_back(info);
}
void ObjectManager::addNearbyObject(CGObjectInstance * obj, CGObjectInstance * nearbyTarget)
void ObjectManager::addNearbyObject(const RequiredObjectInfo & info)
{
RecursiveLock lock(externalAccessMutex);
nearbyObjects.emplace_back(obj, nearbyTarget);
nearbyObjects.emplace_back(info);
}
void ObjectManager::updateDistances(const rmg::Object & obj)
@@ -331,13 +331,11 @@ bool ObjectManager::createRequiredObjects()
logGlobal->trace("Creating required objects");
//RecursiveLock lock(externalAccessMutex); //Why could requiredObjects be modified during the loop?
for(const auto & object : requiredObjects)
for(const auto & objInfo : requiredObjects)
{
auto * obj = object.first;
//FIXME: Invalid dObject inside object?
rmg::Object rmgObject(*obj);
rmg::Object rmgObject(*objInfo.obj);
rmgObject.setTemplate(zone.getTerrainType());
bool guarded = addGuard(rmgObject, object.second, (obj->ID == Obj::MONOLITH_TWO_WAY));
bool guarded = addGuard(rmgObject, objInfo.guardStrength, (objInfo.obj->ID == Obj::MONOLITH_TWO_WAY));
Zone::Lock lock(zone.areaMutex);
auto path = placeAndConnectObject(zone.areaPossible(), rmgObject, 3, guarded, false, OptimizeType::DISTANCE);
@@ -353,10 +351,10 @@ bool ObjectManager::createRequiredObjects()
for(const auto & nearby : nearbyObjects)
{
if(nearby.second != obj)
if(nearby.nearbyTarget != nearby.obj)
continue;
rmg::Object rmgNearObject(*nearby.first);
rmg::Object rmgNearObject(*nearby.obj);
rmg::Area possibleArea(rmgObject.instances().front()->getBlockedArea().getBorderOutside());
possibleArea.intersect(zone.areaPossible());
if(possibleArea.empty())
@@ -370,17 +368,14 @@ bool ObjectManager::createRequiredObjects()
}
}
for(const auto & object : closeObjects)
for(const auto & objInfo : closeObjects)
{
auto * obj = object.first;
//TODO: Wrap into same area proxy?
Zone::Lock lock(zone.areaMutex);
auto possibleArea = zone.areaPossible();
rmg::Object rmgObject(*obj);
rmg::Object rmgObject(*objInfo.obj);
rmgObject.setTemplate(zone.getTerrainType());
bool guarded = addGuard(rmgObject, object.second, (obj->ID == Obj::MONOLITH_TWO_WAY));
bool guarded = addGuard(rmgObject, objInfo.guardStrength, (objInfo.obj->ID == Obj::MONOLITH_TWO_WAY));
auto path = placeAndConnectObject(zone.areaPossible(), rmgObject,
[this, &rmgObject](const int3 & tile)
{
@@ -401,10 +396,10 @@ bool ObjectManager::createRequiredObjects()
for(const auto & nearby : nearbyObjects)
{
if(nearby.second != obj)
if(nearby.nearbyTarget != objInfo.obj)
continue;
rmg::Object rmgNearObject(*nearby.first);
rmg::Object rmgNearObject(*nearby.obj);
rmg::Area possibleArea(rmgObject.instances().front()->getBlockedArea().getBorderOutside());
possibleArea.intersect(zone.areaPossible());
if(possibleArea.empty())
@@ -420,10 +415,10 @@ bool ObjectManager::createRequiredObjects()
//create object on specific positions
//TODO: implement guards
for (const auto &obj : instantObjects)
for (const auto &objInfo : instantObjects)
{
rmg::Object rmgObject(*obj.first);
rmgObject.setPosition(obj.second);
rmg::Object rmgObject(*objInfo.obj);
rmgObject.setPosition(objInfo.pos);
placeObject(rmgObject, false, false);
}
@@ -435,7 +430,7 @@ bool ObjectManager::createRequiredObjects()
return true;
}
void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateDistance)
void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateDistance, bool allowRoad/* = true*/)
{
object.finalize(map);
@@ -493,8 +488,10 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD
}
}
switch(object.instances().front()->object().ID)
if (allowRoad)
{
switch (object.instances().front()->object().ID)
{
case Obj::TOWN:
case Obj::RANDOM_TOWN:
case Obj::MONOLITH_TWO_WAY:
@@ -502,17 +499,18 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD
case Obj::MONOLITH_ONE_WAY_EXIT:
case Obj::SUBTERRANEAN_GATE:
case Obj::SHIPYARD:
if(auto * m = zone.getModificator<RoadPlacer>())
if (auto* m = zone.getModificator<RoadPlacer>())
m->addRoadNode(object.instances().front()->getVisitablePosition());
break;
case Obj::WATER_WHEEL:
if(auto * m = zone.getModificator<RiverPlacer>())
if (auto* m = zone.getModificator<RiverPlacer>())
m->addRiverNode(object.instances().front()->getVisitablePosition());
break;
default:
break;
}
}
}
@@ -614,3 +612,19 @@ bool ObjectManager::addGuard(rmg::Object & object, si32 strength, bool zoneGuard
}
VCMI_LIB_NAMESPACE_END
RequiredObjectInfo::RequiredObjectInfo():
obj(nullptr),
nearbyTarget(nullptr),
guardStrength(0),
allowRoad(true)
{}
RequiredObjectInfo::RequiredObjectInfo(CGObjectInstance* obj, ui32 guardStrength, bool allowRoad, CGObjectInstance* nearbyTarget):
obj(obj),
nearbyTarget(nearbyTarget),
guardStrength(guardStrength),
allowRoad(allowRoad)
{}

View File

@@ -29,6 +29,18 @@ struct DistanceMaximizeFunctor
}
};
struct RequiredObjectInfo
{
RequiredObjectInfo();
RequiredObjectInfo(CGObjectInstance* obj, ui32 guardStrength = 0, bool allowRoad = true, CGObjectInstance* nearbyTarget = nullptr);
CGObjectInstance* obj;
CGObjectInstance* nearbyTarget;
int3 pos;
ui32 guardStrength;
bool allowRoad;
};
class ObjectManager: public Modificator
{
public:
@@ -45,9 +57,9 @@ public:
void process() override;
void init() override;
void addRequiredObject(CGObjectInstance * obj, si32 guardStrength=0);
void addCloseObject(CGObjectInstance * obj, si32 guardStrength = 0);
void addNearbyObject(CGObjectInstance * obj, CGObjectInstance * nearbyTarget);
void addRequiredObject(const RequiredObjectInfo & info);
void addCloseObject(const RequiredObjectInfo & info);
void addNearbyObject(const RequiredObjectInfo & info);
bool createRequiredObjects();
@@ -59,7 +71,7 @@ public:
CGCreature * chooseGuard(si32 strength, bool zoneGuard = false);
bool addGuard(rmg::Object & object, si32 strength, bool zoneGuard = false);
void placeObject(rmg::Object & object, bool guarded, bool updateDistance);
void placeObject(rmg::Object & object, bool guarded, bool updateDistance, bool allowRoad = true);
void updateDistances(const rmg::Object & obj);
void updateDistances(const int3& pos);
@@ -72,10 +84,10 @@ public:
protected:
//content info
std::vector<std::pair<CGObjectInstance*, ui32>> requiredObjects;
std::vector<std::pair<CGObjectInstance*, ui32>> closeObjects;
std::vector<std::pair<CGObjectInstance*, int3>> instantObjects;
std::vector<std::pair<CGObjectInstance*, CGObjectInstance*>> nearbyObjects;
std::vector<RequiredObjectInfo> requiredObjects;
std::vector<RequiredObjectInfo> closeObjects;
std::vector<RequiredObjectInfo> instantObjects;
std::vector<RequiredObjectInfo> nearbyObjects;
std::vector<CGObjectInstance*> objects;
rmg::Area objectsVisitableArea;

View File

@@ -294,6 +294,8 @@ bool WaterProxy::placeBoat(Zone & land, const Lake & lake, RouteInfo & info)
bool WaterProxy::placeShipyard(Zone & land, const Lake & lake, si32 guard, RouteInfo & info)
{
//TODO: Check for road
auto * manager = land.getModificator<ObjectManager>();
if(!manager)
return false;
@@ -372,7 +374,9 @@ bool WaterProxy::placeShipyard(Zone & land, const Lake & lake, si32 guard, Route
info.boarding = boardingPosition;
info.water = shipPositions;
manager->placeObject(rmgObject, guarded, true);
//TODO: Check connection properties
bool allowRoad = true;
manager->placeObject(rmgObject, guarded, true, allowRoad);
zone.areaPossible().subtract(shipyardOutToBlock);
for(const auto & i : shipyardOutToBlock.getTilesVector())