mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-13 19:54:17 +02:00
Merge pull request #2218 from vcmi/pregenerate_treasures
Okay, merging this for PvP feedback.
This commit is contained in:
@@ -18,8 +18,7 @@
|
|||||||
"treasure" :
|
"treasure" :
|
||||||
[
|
[
|
||||||
{ "min" : 300, "max" : 3000, "density" : 12 },
|
{ "min" : 300, "max" : 3000, "density" : 12 },
|
||||||
{ "min" : 5000, "max" : 9000, "density" : 6 },
|
{ "min" : 5000, "max" : 9000, "density" : 6 }
|
||||||
{ "min" : 0, "max" : 0, "density" : 1 }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"2" :
|
"2" :
|
||||||
@@ -34,8 +33,8 @@
|
|||||||
"mines" : { "wood" : 1, "mercury" : 1, "ore" : 1, "sulfur" : 1, "crystal" : 1, "gems" : 1, "gold" : 1 },
|
"mines" : { "wood" : 1, "mercury" : 1, "ore" : 1, "sulfur" : 1, "crystal" : 1, "gems" : 1, "gold" : 1 },
|
||||||
"treasure" :
|
"treasure" :
|
||||||
[
|
[
|
||||||
{ "min" : 5000, "max" : 7000, "density" : 30 },
|
|
||||||
{ "min" : 10000, "max" : 15000, "density" : 1 },
|
{ "min" : 10000, "max" : 15000, "density" : 1 },
|
||||||
|
{ "min" : 5000, "max" : 7000, "density" : 30 },
|
||||||
{ "min" : 300, "max" : 3000, "density" : 5 }
|
{ "min" : 300, "max" : 3000, "density" : 5 }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -51,8 +50,8 @@
|
|||||||
"mines" : { "wood" : 1, "mercury" : 1, "ore" : 1, "sulfur" : 1, "crystal" : 1, "gems" : 1, "gold" : 0 },
|
"mines" : { "wood" : 1, "mercury" : 1, "ore" : 1, "sulfur" : 1, "crystal" : 1, "gems" : 1, "gold" : 0 },
|
||||||
"treasure" :
|
"treasure" :
|
||||||
[
|
[
|
||||||
{ "min" : 12000, "max" : 16000, "density" : 5 },
|
|
||||||
{ "min" : 20000, "max" : 21000, "density" : 6 },
|
{ "min" : 20000, "max" : 21000, "density" : 6 },
|
||||||
|
{ "min" : 12000, "max" : 16000, "density" : 5 },
|
||||||
{ "min" : 300, "max" : 3000, "density" : 5 }
|
{ "min" : 300, "max" : 3000, "density" : 5 }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -69,8 +68,7 @@
|
|||||||
"treasure" :
|
"treasure" :
|
||||||
[
|
[
|
||||||
{ "min" : 25000, "max" : 30000, "density" : 10 },
|
{ "min" : 25000, "max" : 30000, "density" : 10 },
|
||||||
{ "min" : 300, "max" : 3000, "density" : 10 },
|
{ "min" : 300, "max" : 3000, "density" : 10 }
|
||||||
{ "min" : 0, "max" : 0, "density" : 1 }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"5" :
|
"5" :
|
||||||
@@ -85,9 +83,7 @@
|
|||||||
"mines" : { "wood" : 0, "mercury" : 0, "ore" : 0, "sulfur" : 0, "crystal" : 0, "gems" : 0, "gold" : 4 },
|
"mines" : { "wood" : 0, "mercury" : 0, "ore" : 0, "sulfur" : 0, "crystal" : 0, "gems" : 0, "gold" : 4 },
|
||||||
"treasure" :
|
"treasure" :
|
||||||
[
|
[
|
||||||
{ "min" : 30000, "max" : 90000, "density" : 25 },
|
{ "min" : 30000, "max" : 90000, "density" : 25 }
|
||||||
{ "min" : 0, "max" : 0, "density" : 1 },
|
|
||||||
{ "min" : 0, "max" : 0, "density" : 1 }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"6" :
|
"6" :
|
||||||
@@ -167,8 +163,7 @@
|
|||||||
"treasure" :
|
"treasure" :
|
||||||
[
|
[
|
||||||
{ "min" : 300, "max" : 3000, "density" : 12 },
|
{ "min" : 300, "max" : 3000, "density" : 12 },
|
||||||
{ "min" : 5000, "max" : 9000, "density" : 6 },
|
{ "min" : 5000, "max" : 9000, "density" : 6 }
|
||||||
{ "min" : 0, "max" : 0, "density" : 1 }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"2" :
|
"2" :
|
||||||
@@ -183,8 +178,8 @@
|
|||||||
"mines" : { "wood" : 1, "mercury" : 1, "ore" : 1, "sulfur" : 1, "crystal" : 1, "gems" : 1, "gold" : 1 },
|
"mines" : { "wood" : 1, "mercury" : 1, "ore" : 1, "sulfur" : 1, "crystal" : 1, "gems" : 1, "gold" : 1 },
|
||||||
"treasure" :
|
"treasure" :
|
||||||
[
|
[
|
||||||
{ "min" : 5000, "max" : 7000, "density" : 10 },
|
|
||||||
{ "min" : 10000, "max" : 15000, "density" : 1 },
|
{ "min" : 10000, "max" : 15000, "density" : 1 },
|
||||||
|
{ "min" : 5000, "max" : 7000, "density" : 10 },
|
||||||
{ "min" : 300, "max" : 3000, "density" : 5 }
|
{ "min" : 300, "max" : 3000, "density" : 5 }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -200,8 +195,8 @@
|
|||||||
"mines" : { "wood" : 1, "mercury" : 1, "ore" : 1, "sulfur" : 1, "crystal" : 1, "gems" : 1, "gold" : 0 },
|
"mines" : { "wood" : 1, "mercury" : 1, "ore" : 1, "sulfur" : 1, "crystal" : 1, "gems" : 1, "gold" : 0 },
|
||||||
"treasure" :
|
"treasure" :
|
||||||
[
|
[
|
||||||
{ "min" : 12000, "max" : 16000, "density" : 5 },
|
|
||||||
{ "min" : 20000, "max" : 21000, "density" : 6 },
|
{ "min" : 20000, "max" : 21000, "density" : 6 },
|
||||||
|
{ "min" : 12000, "max" : 16000, "density" : 5 },
|
||||||
{ "min" : 300, "max" : 3000, "density" : 5 }
|
{ "min" : 300, "max" : 3000, "density" : 5 }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -218,8 +213,7 @@
|
|||||||
"treasure" :
|
"treasure" :
|
||||||
[
|
[
|
||||||
{ "min" : 25000, "max" : 30000, "density" : 10 },
|
{ "min" : 25000, "max" : 30000, "density" : 10 },
|
||||||
{ "min" : 300, "max" : 3000, "density" : 10 },
|
{ "min" : 300, "max" : 3000, "density" : 10 }
|
||||||
{ "min" : 0, "max" : 0, "density" : 1 }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"5" :
|
"5" :
|
||||||
@@ -233,9 +227,7 @@
|
|||||||
"mines" : { "wood" : 0, "mercury" : 0, "ore" : 0, "sulfur" : 0, "crystal" : 0, "gems" : 0, "gold" : 10 },
|
"mines" : { "wood" : 0, "mercury" : 0, "ore" : 0, "sulfur" : 0, "crystal" : 0, "gems" : 0, "gold" : 10 },
|
||||||
"treasure" :
|
"treasure" :
|
||||||
[
|
[
|
||||||
{ "min" : 30000, "max" : 90000, "density" : 25 },
|
{ "min" : 30000, "max" : 90000, "density" : 25 }
|
||||||
{ "min" : 0, "max" : 0, "density" : 1 },
|
|
||||||
{ "min" : 0, "max" : 0, "density" : 1 }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"6" :
|
"6" :
|
||||||
|
@@ -511,6 +511,7 @@
|
|||||||
"index" : 0,
|
"index" : 0,
|
||||||
"aiValue" : 100,
|
"aiValue" : 100,
|
||||||
"rmg" : {
|
"rmg" : {
|
||||||
|
"zoneLimit" : 1,
|
||||||
"mapLimit" : 32,
|
"mapLimit" : 32,
|
||||||
"value" : 100,
|
"value" : 100,
|
||||||
"rarity" : 20
|
"rarity" : 20
|
||||||
|
@@ -50,6 +50,34 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"randomResource":
|
||||||
|
{
|
||||||
|
"index" :76,
|
||||||
|
"handler": "resource",
|
||||||
|
"base" : {
|
||||||
|
"base" : {
|
||||||
|
"visitableFrom" : [ "+++", "+-+", "+++" ],
|
||||||
|
"mask" : [ "VA" ]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"types" : {
|
||||||
|
"randomResource" : {
|
||||||
|
"index" : 0,
|
||||||
|
"rmg" : {
|
||||||
|
"value" : 1500,
|
||||||
|
"rarity" : 2000
|
||||||
|
},
|
||||||
|
"templates" :
|
||||||
|
{
|
||||||
|
"res" :
|
||||||
|
{
|
||||||
|
"animation" : "AVTrndm0.def"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// subtype: resource ID
|
// subtype: resource ID
|
||||||
"resource" : {
|
"resource" : {
|
||||||
"index" :79,
|
"index" :79,
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
"index" : 0,
|
"index" : 0,
|
||||||
"aiValue" : 100,
|
"aiValue" : 100,
|
||||||
"rmg" : {
|
"rmg" : {
|
||||||
|
"zoneLimit" : 1,
|
||||||
"value" : 100,
|
"value" : 100,
|
||||||
"rarity" : 100
|
"rarity" : 100
|
||||||
},
|
},
|
||||||
@@ -253,6 +254,7 @@
|
|||||||
"index" : 0,
|
"index" : 0,
|
||||||
"aiValue" : 100,
|
"aiValue" : 100,
|
||||||
"rmg" : {
|
"rmg" : {
|
||||||
|
"zoneLimit" : 1,
|
||||||
"value" : 100,
|
"value" : 100,
|
||||||
"rarity" : 20
|
"rarity" : 20
|
||||||
},
|
},
|
||||||
|
@@ -64,21 +64,35 @@ void Area::invalidate()
|
|||||||
dBorderOutsideCache.clear();
|
dBorderOutsideCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Area::connected() const
|
bool Area::connected(bool noDiagonals) const
|
||||||
{
|
{
|
||||||
std::list<int3> queue({*dTiles.begin()});
|
std::list<int3> queue({*dTiles.begin()});
|
||||||
Tileset connected = dTiles; //use invalidated cache - ok
|
Tileset connected = dTiles; //use invalidated cache - ok
|
||||||
|
|
||||||
while(!queue.empty())
|
while(!queue.empty())
|
||||||
{
|
{
|
||||||
auto t = queue.front();
|
auto t = queue.front();
|
||||||
connected.erase(t);
|
connected.erase(t);
|
||||||
queue.pop_front();
|
queue.pop_front();
|
||||||
|
|
||||||
for(auto & i : int3::getDirs())
|
if (noDiagonals)
|
||||||
{
|
{
|
||||||
if(connected.count(t + i))
|
for (auto& i : dirs4)
|
||||||
{
|
{
|
||||||
queue.push_back(t + i);
|
if (connected.count(t + i))
|
||||||
|
{
|
||||||
|
queue.push_back(t + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (auto& i : int3::getDirs())
|
||||||
|
{
|
||||||
|
if (connected.count(t + i))
|
||||||
|
{
|
||||||
|
queue.push_back(t + i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -44,7 +44,7 @@ namespace rmg
|
|||||||
|
|
||||||
Area getSubarea(const std::function<bool(const int3 &)> & filter) const;
|
Area getSubarea(const std::function<bool(const int3 &)> & filter) const;
|
||||||
|
|
||||||
bool connected() const; //is connected
|
bool connected(bool noDiagonals = false) const; //is connected
|
||||||
bool empty() const;
|
bool empty() const;
|
||||||
bool contains(const int3 & tile) const;
|
bool contains(const int3 & tile) const;
|
||||||
bool contains(const std::vector<int3> & tiles) const;
|
bool contains(const std::vector<int3> & tiles) const;
|
||||||
|
@@ -161,17 +161,21 @@ const CGObjectInstance & Object::Instance::object() const
|
|||||||
return dObject;
|
return dObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object::Object(CGObjectInstance & object, const int3 & position)
|
Object::Object(CGObjectInstance & object, const int3 & position):
|
||||||
|
guarded(false)
|
||||||
{
|
{
|
||||||
addInstance(object, position);
|
addInstance(object, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object::Object(CGObjectInstance & object)
|
Object::Object(CGObjectInstance & object):
|
||||||
|
guarded(false)
|
||||||
{
|
{
|
||||||
addInstance(object);
|
addInstance(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object::Object(const Object & object): dStrength(object.dStrength)
|
Object::Object(const Object & object):
|
||||||
|
dStrength(object.dStrength),
|
||||||
|
guarded(false)
|
||||||
{
|
{
|
||||||
for(const auto & i : object.dInstances)
|
for(const auto & i : object.dInstances)
|
||||||
addInstance(const_cast<CGObjectInstance &>(i.object()), i.getPosition());
|
addInstance(const_cast<CGObjectInstance &>(i.object()), i.getPosition());
|
||||||
@@ -197,7 +201,9 @@ std::list<const Object::Instance*> Object::instances() const
|
|||||||
void Object::addInstance(Instance & object)
|
void Object::addInstance(Instance & object)
|
||||||
{
|
{
|
||||||
//assert(object.dParent == *this);
|
//assert(object.dParent == *this);
|
||||||
|
setGuardedIfMonster(object);
|
||||||
dInstances.push_back(object);
|
dInstances.push_back(object);
|
||||||
|
|
||||||
dFullAreaCache.clear();
|
dFullAreaCache.clear();
|
||||||
dAccessibleAreaCache.clear();
|
dAccessibleAreaCache.clear();
|
||||||
dAccessibleAreaFullCache.clear();
|
dAccessibleAreaFullCache.clear();
|
||||||
@@ -206,6 +212,8 @@ void Object::addInstance(Instance & object)
|
|||||||
Object::Instance & Object::addInstance(CGObjectInstance & object)
|
Object::Instance & Object::addInstance(CGObjectInstance & object)
|
||||||
{
|
{
|
||||||
dInstances.emplace_back(*this, object);
|
dInstances.emplace_back(*this, object);
|
||||||
|
setGuardedIfMonster(dInstances.back());
|
||||||
|
|
||||||
dFullAreaCache.clear();
|
dFullAreaCache.clear();
|
||||||
dAccessibleAreaCache.clear();
|
dAccessibleAreaCache.clear();
|
||||||
dAccessibleAreaFullCache.clear();
|
dAccessibleAreaFullCache.clear();
|
||||||
@@ -215,6 +223,8 @@ Object::Instance & Object::addInstance(CGObjectInstance & object)
|
|||||||
Object::Instance & Object::addInstance(CGObjectInstance & object, const int3 & position)
|
Object::Instance & Object::addInstance(CGObjectInstance & object, const int3 & position)
|
||||||
{
|
{
|
||||||
dInstances.emplace_back(*this, object, position);
|
dInstances.emplace_back(*this, object, position);
|
||||||
|
setGuardedIfMonster(dInstances.back());
|
||||||
|
|
||||||
dFullAreaCache.clear();
|
dFullAreaCache.clear();
|
||||||
dAccessibleAreaCache.clear();
|
dAccessibleAreaCache.clear();
|
||||||
dAccessibleAreaFullCache.clear();
|
dAccessibleAreaFullCache.clear();
|
||||||
@@ -302,6 +312,19 @@ const int3 Object::getVisibleTop() const
|
|||||||
return topTile;
|
return topTile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool rmg::Object::isGuarded() const
|
||||||
|
{
|
||||||
|
return guarded;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rmg::Object::setGuardedIfMonster(const Instance& object)
|
||||||
|
{
|
||||||
|
if (object.object().ID == Obj::MONSTER)
|
||||||
|
{
|
||||||
|
guarded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Object::Instance::finalize(RmgMap & map)
|
void Object::Instance::finalize(RmgMap & map)
|
||||||
{
|
{
|
||||||
if(!map.isOnMap(getPosition(true)))
|
if(!map.isOnMap(getPosition(true)))
|
||||||
|
@@ -77,6 +77,9 @@ public:
|
|||||||
|
|
||||||
const Area & getArea() const; //lazy cache invalidation
|
const Area & getArea() const; //lazy cache invalidation
|
||||||
const int3 getVisibleTop() const;
|
const int3 getVisibleTop() const;
|
||||||
|
|
||||||
|
bool isGuarded() const;
|
||||||
|
void setGuardedIfMonster(const Instance & object);
|
||||||
|
|
||||||
void finalize(RmgMap & map);
|
void finalize(RmgMap & map);
|
||||||
void clear();
|
void clear();
|
||||||
@@ -87,6 +90,7 @@ private:
|
|||||||
mutable Area dAccessibleAreaCache, dAccessibleAreaFullCache;
|
mutable Area dAccessibleAreaCache, dAccessibleAreaFullCache;
|
||||||
int3 dPosition;
|
int3 dPosition;
|
||||||
ui32 dStrength;
|
ui32 dStrength;
|
||||||
|
bool guarded;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -203,8 +203,34 @@ void Zone::fractalize()
|
|||||||
rmg::Area possibleTiles(dAreaPossible);
|
rmg::Area possibleTiles(dAreaPossible);
|
||||||
rmg::Area tilesToIgnore; //will be erased in this iteration
|
rmg::Area tilesToIgnore; //will be erased in this iteration
|
||||||
|
|
||||||
const float minDistance = 10 * 10; //squared
|
//Squared
|
||||||
float blockDistance = minDistance * 0.25f;
|
float minDistance = 10 * 10;
|
||||||
|
float spanFactor = (pos.z ? 0.25 : 0.5f); //Narrower passages in the Underground
|
||||||
|
|
||||||
|
int treasureValue = 0;
|
||||||
|
int treasureDensity = 0;
|
||||||
|
for (auto t : treasureInfo)
|
||||||
|
{
|
||||||
|
treasureValue += ((t.min + t.max) / 2) * t.density / 1000.f; //Thousands
|
||||||
|
treasureDensity += t.density;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (treasureValue > 200)
|
||||||
|
{
|
||||||
|
//Less obstacles - max span is 1 (no obstacles)
|
||||||
|
spanFactor = 1.0f - ((std::max(0, (1000 - treasureValue)) / (1000.f - 200)) * (1 - spanFactor));
|
||||||
|
}
|
||||||
|
else if (treasureValue < 100)
|
||||||
|
{
|
||||||
|
//Dense obstacles
|
||||||
|
spanFactor *= (treasureValue / 100.f);
|
||||||
|
vstd::amax(spanFactor, 0.2f);
|
||||||
|
}
|
||||||
|
if (treasureDensity <= 10)
|
||||||
|
{
|
||||||
|
vstd::amin(spanFactor, 0.25f); //Add extra obstacles to fill up space
|
||||||
|
}
|
||||||
|
float blockDistance = minDistance * spanFactor; //More obstacles in the Underground
|
||||||
|
|
||||||
if(type != ETemplateZoneType::JUNCTION)
|
if(type != ETemplateZoneType::JUNCTION)
|
||||||
{
|
{
|
||||||
|
@@ -166,7 +166,6 @@ int3 ObjectManager::findPlaceForObject(const rmg::Area & searchArea, rmg::Object
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//FIXME: Race condition for tiles? For Area?
|
|
||||||
if(result.valid())
|
if(result.valid())
|
||||||
obj.setPosition(result);
|
obj.setPosition(result);
|
||||||
return result;
|
return result;
|
||||||
@@ -183,8 +182,15 @@ int3 ObjectManager::findPlaceForObject(const rmg::Area & searchArea, rmg::Object
|
|||||||
|
|
||||||
for(const auto & t : obj.getArea().getTilesVector())
|
for(const auto & t : obj.getArea().getTilesVector())
|
||||||
{
|
{
|
||||||
if(map.getTileInfo(t).getNearestObjectDistance() < min_dist)
|
auto localDist = map.getTileInfo(t).getNearestObjectDistance();
|
||||||
|
if (localDist < min_dist)
|
||||||
|
{
|
||||||
return -1.f;
|
return -1.f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vstd::amin(dist, localDist); //Evaluate object tile which will be closest to another object
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dist;
|
return dist;
|
||||||
@@ -206,6 +212,55 @@ rmg::Path ObjectManager::placeAndConnectObject(const rmg::Area & searchArea, rmg
|
|||||||
return -1.f;
|
return -1.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rmg::Area perimeter;
|
||||||
|
rmg::Area areaToBlock;
|
||||||
|
if (obj.isGuarded())
|
||||||
|
{
|
||||||
|
auto guardedArea = obj.instances().back()->getAccessibleArea();
|
||||||
|
guardedArea.add(obj.instances().back()->getVisitablePosition());
|
||||||
|
areaToBlock = obj.getAccessibleArea(true);
|
||||||
|
areaToBlock.subtract(guardedArea);
|
||||||
|
|
||||||
|
if (!areaToBlock.empty())
|
||||||
|
{
|
||||||
|
perimeter = areaToBlock;
|
||||||
|
perimeter.unite(areaToBlock.getBorderOutside());
|
||||||
|
//We could have added border around guard
|
||||||
|
perimeter.subtract(guardedArea);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
perimeter = obj.getArea();
|
||||||
|
perimeter.subtract(obj.getAccessibleArea());
|
||||||
|
if (!perimeter.empty())
|
||||||
|
{
|
||||||
|
perimeter.unite(perimeter.getBorderOutside());
|
||||||
|
perimeter.subtract(obj.getAccessibleArea());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Check if perimeter of the object intersects with more than one blocked areas
|
||||||
|
|
||||||
|
auto tiles = perimeter.getTiles();
|
||||||
|
vstd::erase_if(tiles, [this](const int3& tile) -> bool
|
||||||
|
{
|
||||||
|
//Out-of-map area also is an obstacle
|
||||||
|
if (!map.isOnMap(tile))
|
||||||
|
return false;
|
||||||
|
return !(map.isBlocked(tile) || map.isUsed(tile));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!tiles.empty())
|
||||||
|
{
|
||||||
|
rmg::Area border(tiles);
|
||||||
|
border.subtract(areaToBlock);
|
||||||
|
if (!border.connected())
|
||||||
|
{
|
||||||
|
//We don't want to connect two blocked areas to create impassable obstacle
|
||||||
|
return -1.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return dist;
|
return dist;
|
||||||
}, isGuarded, onlyStraight, optimizer);
|
}, isGuarded, onlyStraight, optimizer);
|
||||||
}
|
}
|
||||||
@@ -230,7 +285,7 @@ rmg::Path ObjectManager::placeAndConnectObject(const rmg::Area & searchArea, rmg
|
|||||||
accessibleArea.intersect(guardedArea);
|
accessibleArea.intersect(guardedArea);
|
||||||
accessibleArea.add(obj.instances().back()->getPosition(true));
|
accessibleArea.add(obj.instances().back()->getPosition(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto path = zone.searchPath(accessibleArea, onlyStraight, [&obj, isGuarded](const int3 & t)
|
auto path = zone.searchPath(accessibleArea, onlyStraight, [&obj, isGuarded](const int3 & t)
|
||||||
{
|
{
|
||||||
if(isGuarded)
|
if(isGuarded)
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
#include "ObstaclePlacer.h"
|
#include "ObstaclePlacer.h"
|
||||||
#include "ObjectManager.h"
|
#include "ObjectManager.h"
|
||||||
#include "TreasurePlacer.h"
|
#include "TreasurePlacer.h"
|
||||||
#include "RockPlacer.h"
|
#include "RockFiller.h"
|
||||||
#include "WaterRoutes.h"
|
#include "WaterRoutes.h"
|
||||||
#include "WaterProxy.h"
|
#include "WaterProxy.h"
|
||||||
#include "RoadPlacer.h"
|
#include "RoadPlacer.h"
|
||||||
@@ -35,14 +35,56 @@ void ObstaclePlacer::process()
|
|||||||
|
|
||||||
collectPossibleObstacles(zone.getTerrainType());
|
collectPossibleObstacles(zone.getTerrainType());
|
||||||
|
|
||||||
blockedArea = zone.area().getSubarea([this](const int3 & t)
|
|
||||||
{
|
{
|
||||||
return map.shouldBeBlocked(t);
|
Zone::Lock lock(zone.areaMutex);
|
||||||
});
|
blockedArea = zone.area().getSubarea([this](const int3& t)
|
||||||
blockedArea.subtract(zone.areaUsed());
|
{
|
||||||
zone.areaPossible().subtract(blockedArea);
|
return map.shouldBeBlocked(t);
|
||||||
|
});
|
||||||
|
blockedArea.subtract(zone.areaUsed());
|
||||||
|
zone.areaPossible().subtract(blockedArea);
|
||||||
|
|
||||||
prohibitedArea = zone.freePaths() + zone.areaUsed() + manager->getVisitableArea();
|
prohibitedArea = zone.freePaths() + zone.areaUsed() + manager->getVisitableArea();
|
||||||
|
|
||||||
|
//Progressively block tiles, but make sure they don't seal any gap between blocks
|
||||||
|
rmg::Area toBlock;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
toBlock.clear();
|
||||||
|
for (const auto& tile : zone.areaPossible().getTiles())
|
||||||
|
{
|
||||||
|
rmg::Area neighbors;
|
||||||
|
rmg::Area t;
|
||||||
|
t.add(tile);
|
||||||
|
|
||||||
|
for (const auto& n : t.getBorderOutside())
|
||||||
|
{
|
||||||
|
//Area outside the map is also impassable
|
||||||
|
if (!map.isOnMap(n) || map.shouldBeBlocked(n))
|
||||||
|
{
|
||||||
|
neighbors.add(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (neighbors.empty())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//Will only be added if it doesn't connect two disjointed blocks
|
||||||
|
if (neighbors.connected(true)) //Do not block diagonal pass
|
||||||
|
{
|
||||||
|
toBlock.add(tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zone.areaPossible().subtract(toBlock);
|
||||||
|
for (const auto& tile : toBlock.getTiles())
|
||||||
|
{
|
||||||
|
map.setOccupied(tile, ETileType::BLOCKED);
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (!toBlock.empty());
|
||||||
|
|
||||||
|
prohibitedArea.unite(zone.areaPossible());
|
||||||
|
}
|
||||||
|
|
||||||
auto objs = createObstacles(zone.getRand());
|
auto objs = createObstacles(zone.getRand());
|
||||||
mapProxy->insertObjects(objs);
|
mapProxy->insertObjects(objs);
|
||||||
@@ -52,10 +94,16 @@ void ObstaclePlacer::init()
|
|||||||
{
|
{
|
||||||
DEPENDENCY(ObjectManager);
|
DEPENDENCY(ObjectManager);
|
||||||
DEPENDENCY(TreasurePlacer);
|
DEPENDENCY(TreasurePlacer);
|
||||||
DEPENDENCY(WaterRoutes);
|
|
||||||
DEPENDENCY(WaterProxy);
|
|
||||||
DEPENDENCY(RoadPlacer);
|
DEPENDENCY(RoadPlacer);
|
||||||
DEPENDENCY_ALL(RockPlacer);
|
if (zone.isUnderground())
|
||||||
|
{
|
||||||
|
DEPENDENCY(RockFiller);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DEPENDENCY(WaterRoutes);
|
||||||
|
DEPENDENCY(WaterProxy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ObstaclePlacer::isInTheMap(const int3& tile)
|
bool ObstaclePlacer::isInTheMap(const int3& tile)
|
||||||
|
@@ -82,7 +82,10 @@ void RiverPlacer::process()
|
|||||||
|
|
||||||
void RiverPlacer::init()
|
void RiverPlacer::init()
|
||||||
{
|
{
|
||||||
DEPENDENCY_ALL(WaterProxy);
|
if (!zone.isUnderground())
|
||||||
|
{
|
||||||
|
DEPENDENCY_ALL(WaterProxy);
|
||||||
|
}
|
||||||
DEPENDENCY(ObjectManager);
|
DEPENDENCY(ObjectManager);
|
||||||
DEPENDENCY(ObstaclePlacer);
|
DEPENDENCY(ObstaclePlacer);
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
#include "RoadPlacer.h"
|
#include "RoadPlacer.h"
|
||||||
#include "ObjectManager.h"
|
#include "ObjectManager.h"
|
||||||
#include "ObstaclePlacer.h"
|
#include "ObstaclePlacer.h"
|
||||||
|
#include "RockFiller.h"
|
||||||
#include "../Functions.h"
|
#include "../Functions.h"
|
||||||
#include "../CMapGenerator.h"
|
#include "../CMapGenerator.h"
|
||||||
#include "../threadpool/MapProxy.h"
|
#include "../threadpool/MapProxy.h"
|
||||||
@@ -28,6 +29,14 @@ void RoadPlacer::process()
|
|||||||
connectRoads();
|
connectRoads();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RoadPlacer::init()
|
||||||
|
{
|
||||||
|
if (zone.isUnderground())
|
||||||
|
{
|
||||||
|
DEPENDENCY_ALL(RockFiller);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rmg::Area & RoadPlacer::areaForRoads()
|
rmg::Area & RoadPlacer::areaForRoads()
|
||||||
{
|
{
|
||||||
return areaRoads;
|
return areaRoads;
|
||||||
|
@@ -19,6 +19,7 @@ public:
|
|||||||
MODIFICATOR(RoadPlacer);
|
MODIFICATOR(RoadPlacer);
|
||||||
|
|
||||||
void process() override;
|
void process() override;
|
||||||
|
void init() override;
|
||||||
char dump(const int3 &) override;
|
char dump(const int3 &) override;
|
||||||
|
|
||||||
void addRoadNode(const int3 & node);
|
void addRoadNode(const int3 & node);
|
||||||
|
@@ -13,7 +13,6 @@
|
|||||||
#include "RockPlacer.h"
|
#include "RockPlacer.h"
|
||||||
#include "TreasurePlacer.h"
|
#include "TreasurePlacer.h"
|
||||||
#include "ObjectManager.h"
|
#include "ObjectManager.h"
|
||||||
#include "RoadPlacer.h"
|
|
||||||
#include "RiverPlacer.h"
|
#include "RiverPlacer.h"
|
||||||
#include "../RmgMap.h"
|
#include "../RmgMap.h"
|
||||||
#include "../CMapGenerator.h"
|
#include "../CMapGenerator.h"
|
||||||
@@ -63,7 +62,6 @@ void RockFiller::processMap()
|
|||||||
void RockFiller::init()
|
void RockFiller::init()
|
||||||
{
|
{
|
||||||
DEPENDENCY_ALL(RockPlacer);
|
DEPENDENCY_ALL(RockPlacer);
|
||||||
POSTFUNCTION_ALL(RoadPlacer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char RockFiller::dump(const int3 & t)
|
char RockFiller::dump(const int3 & t)
|
||||||
|
@@ -67,7 +67,17 @@ void RockPlacer::postProcess()
|
|||||||
|
|
||||||
void RockPlacer::init()
|
void RockPlacer::init()
|
||||||
{
|
{
|
||||||
DEPENDENCY_ALL(TreasurePlacer);
|
for (const auto& zone : map.getZones())
|
||||||
|
{
|
||||||
|
if (zone.second->isUnderground())
|
||||||
|
{
|
||||||
|
auto * tp = zone.second->getModificator<TreasurePlacer>();
|
||||||
|
if (tp)
|
||||||
|
{
|
||||||
|
dependency(tp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char RockPlacer::dump(const int3 & t)
|
char RockPlacer::dump(const int3 & t)
|
||||||
|
@@ -163,11 +163,14 @@ void TownPlacer::cleanupBoundaries(const rmg::Object & rmgObject)
|
|||||||
Zone::Lock lock(zone.areaMutex);
|
Zone::Lock lock(zone.areaMutex);
|
||||||
for(const auto & t : rmgObject.getArea().getBorderOutside())
|
for(const auto & t : rmgObject.getArea().getBorderOutside())
|
||||||
{
|
{
|
||||||
if(map.isOnMap(t))
|
if (t.y > rmgObject.getVisitablePosition().y) //Line below the town
|
||||||
{
|
{
|
||||||
map.setOccupied(t, ETileType::FREE);
|
if (map.isOnMap(t))
|
||||||
zone.areaPossible().erase(t);
|
{
|
||||||
zone.freePaths().add(t);
|
map.setOccupied(t, ETileType::FREE);
|
||||||
|
zone.areaPossible().erase(t);
|
||||||
|
zone.freePaths().add(t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -562,7 +562,7 @@ std::vector<ObjectInfo*> TreasurePlacer::prepareTreasurePile(const CTreasureInfo
|
|||||||
bool hasLargeObject = false;
|
bool hasLargeObject = false;
|
||||||
while(currentValue <= static_cast<int>(desiredValue) - 100) //no objects with value below 100 are available
|
while(currentValue <= static_cast<int>(desiredValue) - 100) //no objects with value below 100 are available
|
||||||
{
|
{
|
||||||
auto * oi = getRandomObject(desiredValue, currentValue, maxValue, !hasLargeObject);
|
auto * oi = getRandomObject(desiredValue, currentValue, !hasLargeObject);
|
||||||
if(!oi) //fail
|
if(!oi) //fail
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -659,13 +659,13 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
|
|||||||
return rmgObject;
|
return rmgObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectInfo * TreasurePlacer::getRandomObject(ui32 desiredValue, ui32 currentValue, ui32 maxValue, bool allowLargeObjects)
|
ObjectInfo * TreasurePlacer::getRandomObject(ui32 desiredValue, ui32 currentValue, bool allowLargeObjects)
|
||||||
{
|
{
|
||||||
std::vector<std::pair<ui32, ObjectInfo*>> thresholds; //handle complex object via pointer
|
std::vector<std::pair<ui32, ObjectInfo*>> thresholds; //handle complex object via pointer
|
||||||
ui32 total = 0;
|
ui32 total = 0;
|
||||||
|
|
||||||
//calculate actual treasure value range based on remaining value
|
//calculate actual treasure value range based on remaining value
|
||||||
ui32 maxVal = maxValue - currentValue;
|
ui32 maxVal = desiredValue - currentValue;
|
||||||
ui32 minValue = static_cast<ui32>(0.25f * (desiredValue - currentValue));
|
ui32 minValue = static_cast<ui32>(0.25f * (desiredValue - currentValue));
|
||||||
|
|
||||||
for(ObjectInfo & oi : possibleObjects) //copy constructor turned out to be costly
|
for(ObjectInfo & oi : possibleObjects) //copy constructor turned out to be costly
|
||||||
@@ -701,133 +701,165 @@ ObjectInfo * TreasurePlacer::getRandomObject(ui32 desiredValue, ui32 currentValu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TreasurePlacer::createTreasures(ObjectManager & manager)
|
void TreasurePlacer::createTreasures(ObjectManager& manager)
|
||||||
{
|
{
|
||||||
const int maxAttempts = 2;
|
const int maxAttempts = 2;
|
||||||
|
|
||||||
int mapMonsterStrength = map.getMapGenOptions().getMonsterStrength();
|
int mapMonsterStrength = map.getMapGenOptions().getMonsterStrength();
|
||||||
int monsterStrength = (zone.monsterStrength == EMonsterStrength::ZONE_NONE ? 0 : zone.monsterStrength + mapMonsterStrength - 1); //array index from 0 to 4; pick any correct value for ZONE_NONE, minGuardedValue won't be used in this case anyway
|
int monsterStrength = (zone.monsterStrength == EMonsterStrength::ZONE_NONE ? 0 : zone.monsterStrength + mapMonsterStrength - 1); //array index from 0 to 4; pick any correct value for ZONE_NONE, minGuardedValue won't be used in this case anyway
|
||||||
static int minGuardedValues[] = { 6500, 4167, 3000, 1833, 1333 };
|
static int minGuardedValues[] = { 6500, 4167, 3000, 1833, 1333 };
|
||||||
minGuardedValue = minGuardedValues[monsterStrength];
|
minGuardedValue = minGuardedValues[monsterStrength];
|
||||||
|
|
||||||
auto valueComparator = [](const CTreasureInfo & lhs, const CTreasureInfo & rhs) -> bool
|
auto valueComparator = [](const CTreasureInfo& lhs, const CTreasureInfo& rhs) -> bool
|
||||||
{
|
{
|
||||||
return lhs.max > rhs.max;
|
return lhs.max > rhs.max;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto restoreZoneLimits = [](const std::vector<ObjectInfo*> & treasurePile)
|
auto restoreZoneLimits = [](const std::vector<ObjectInfo*>& treasurePile)
|
||||||
{
|
{
|
||||||
for(auto * oi : treasurePile)
|
for (auto* oi : treasurePile)
|
||||||
{
|
{
|
||||||
oi->maxPerZone++;
|
oi->maxPerZone++;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//place biggest treasures first at large distance, place smaller ones inbetween
|
//place biggest treasures first at large distance, place smaller ones inbetween
|
||||||
auto treasureInfo = zone.getTreasureInfo();
|
auto treasureInfo = zone.getTreasureInfo();
|
||||||
boost::sort(treasureInfo, valueComparator);
|
boost::sort(treasureInfo, valueComparator);
|
||||||
|
|
||||||
//sort treasures by ascending value so we can stop checking treasures with too high value
|
//sort treasures by ascending value so we can stop checking treasures with too high value
|
||||||
boost::sort(possibleObjects, [](const ObjectInfo& oi1, const ObjectInfo& oi2) -> bool
|
boost::sort(possibleObjects, [](const ObjectInfo& oi1, const ObjectInfo& oi2) -> bool
|
||||||
{
|
{
|
||||||
return oi1.value < oi2.value;
|
return oi1.value < oi2.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
int totalDensity = 0;
|
size_t size = 0;
|
||||||
for (auto t : treasureInfo)
|
|
||||||
{
|
{
|
||||||
|
Zone::Lock lock(zone.areaMutex);
|
||||||
|
size = zone.getArea().getTiles().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalDensity = 0;
|
||||||
|
|
||||||
|
for (auto t = treasureInfo.begin(); t != treasureInfo.end(); t++)
|
||||||
|
{
|
||||||
|
std::vector<rmg::Object> treasures;
|
||||||
|
|
||||||
//discard objects with too high value to be ever placed
|
//discard objects with too high value to be ever placed
|
||||||
vstd::erase_if(possibleObjects, [t](const ObjectInfo& oi) -> bool
|
vstd::erase_if(possibleObjects, [t](const ObjectInfo& oi) -> bool
|
||||||
{
|
{
|
||||||
return oi.value > t.max;
|
return oi.value > t->max;
|
||||||
});
|
});
|
||||||
|
|
||||||
totalDensity += t.density;
|
totalDensity += t->density;
|
||||||
|
|
||||||
//treasure density is inversely proportional to zone size but must be scaled back to map size
|
size_t count = size * t->density / 500;
|
||||||
//also, normalize it to zone count - higher count means relatively smaller zones
|
|
||||||
|
//Assure space for lesser treasures, if there are any left
|
||||||
|
if (t != (treasureInfo.end() - 1))
|
||||||
|
{
|
||||||
|
const int averageValue = (t->min + t->max) / 2;
|
||||||
|
if (averageValue > 10000)
|
||||||
|
{
|
||||||
|
//Will surely be guarded => larger piles => less space inbetween
|
||||||
|
vstd::amin(count, size * (10.f / 500) / (std::sqrt((float)averageValue / 10000)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//this is squared distance for optimization purposes
|
//this is squared distance for optimization purposes
|
||||||
const float minDistance = std::max<float>((125.f / totalDensity), 2.0f);
|
const float minDistance = std::max<float>((125.f / totalDensity), 1.0f);
|
||||||
//distance lower than 2 causes objects to overlap and crash
|
|
||||||
|
|
||||||
for(int attempt = 0; attempt <= maxAttempts;)
|
|
||||||
{
|
|
||||||
auto treasurePileInfos = prepareTreasurePile(t);
|
|
||||||
if(treasurePileInfos.empty())
|
|
||||||
{
|
|
||||||
++attempt;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int value = std::accumulate(treasurePileInfos.begin(), treasurePileInfos.end(), 0, [](int v, const ObjectInfo * oi){return v + oi->value;});
|
|
||||||
|
|
||||||
auto rmgObject = constructTreasurePile(treasurePileInfos, attempt == maxAttempts);
|
|
||||||
if(rmgObject.instances().empty()) //handle incorrect placement
|
|
||||||
{
|
|
||||||
restoreZoneLimits(treasurePileInfos);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//guard treasure pile
|
|
||||||
bool guarded = isGuardNeededForTreasure(value);
|
|
||||||
if(guarded)
|
|
||||||
guarded = manager.addGuard(rmgObject, value);
|
|
||||||
|
|
||||||
Zone::Lock lock(zone.areaMutex); //We are going to subtract this area
|
|
||||||
//TODO: Don't place
|
|
||||||
auto possibleArea = zone.areaPossible();
|
|
||||||
|
|
||||||
auto path = rmg::Path::invalid();
|
|
||||||
if(guarded)
|
|
||||||
{
|
|
||||||
path = manager.placeAndConnectObject(possibleArea, rmgObject, [this, &rmgObject, &minDistance, &manager](const int3 & tile)
|
|
||||||
{
|
|
||||||
auto ti = map.getTileInfo(tile);
|
|
||||||
if(ti.getNearestObjectDistance() < minDistance)
|
|
||||||
return -1.f;
|
|
||||||
|
|
||||||
for(const auto & t : rmgObject.getArea().getTilesVector())
|
size_t emergencyLoopFinish = 0;
|
||||||
{
|
while(treasures.size() < count && emergencyLoopFinish < count)
|
||||||
if(map.getTileInfo(t).getNearestObjectDistance() < minDistance)
|
{
|
||||||
return -1.f;
|
auto treasurePileInfos = prepareTreasurePile(*t);
|
||||||
}
|
if (treasurePileInfos.empty())
|
||||||
|
|
||||||
auto guardedArea = rmgObject.instances().back()->getAccessibleArea();
|
|
||||||
auto areaToBlock = rmgObject.getAccessibleArea(true);
|
|
||||||
areaToBlock.subtract(guardedArea);
|
|
||||||
if(areaToBlock.overlap(zone.freePaths()) || areaToBlock.overlap(manager.getVisitableArea()))
|
|
||||||
return -1.f;
|
|
||||||
|
|
||||||
return ti.getNearestObjectDistance();
|
|
||||||
}, guarded, false, ObjectManager::OptimizeType::DISTANCE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
path = manager.placeAndConnectObject(possibleArea, rmgObject, minDistance, guarded, false, ObjectManager::OptimizeType::DISTANCE);
|
emergencyLoopFinish++; //Exit potentially infinite loop for bad settings
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(path.valid())
|
int value = std::accumulate(treasurePileInfos.begin(), treasurePileInfos.end(), 0, [](int v, const ObjectInfo* oi) {return v + oi->value; });
|
||||||
|
|
||||||
|
for (ui32 attempt = 0; attempt <= 2; attempt++)
|
||||||
{
|
{
|
||||||
//debug purposes
|
auto rmgObject = constructTreasurePile(treasurePileInfos, attempt == maxAttempts);
|
||||||
treasureArea.unite(rmgObject.getArea());
|
|
||||||
if(guarded)
|
if (rmgObject.instances().empty()) //handle incorrect placement
|
||||||
{
|
{
|
||||||
guards.unite(rmgObject.instances().back()->getBlockedArea());
|
restoreZoneLimits(treasurePileInfos);
|
||||||
auto guardedArea = rmgObject.instances().back()->getAccessibleArea();
|
continue;
|
||||||
auto areaToBlock = rmgObject.getAccessibleArea(true);
|
|
||||||
areaToBlock.subtract(guardedArea);
|
|
||||||
treasureBlockArea.unite(areaToBlock);
|
|
||||||
}
|
}
|
||||||
zone.connectPath(path);
|
|
||||||
manager.placeObject(rmgObject, guarded, true);
|
//guard treasure pile
|
||||||
attempt = 0;
|
bool guarded = isGuardNeededForTreasure(value);
|
||||||
|
if (guarded)
|
||||||
|
guarded = manager.addGuard(rmgObject, value);
|
||||||
|
|
||||||
|
treasures.push_back(rmgObject);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
for (auto& rmgObject : treasures)
|
||||||
|
{
|
||||||
|
const bool guarded = rmgObject.isGuarded();
|
||||||
|
|
||||||
|
for (int attempt = 0; attempt <= maxAttempts;)
|
||||||
{
|
{
|
||||||
restoreZoneLimits(treasurePileInfos);
|
auto path = rmg::Path::invalid();
|
||||||
rmgObject.clear();
|
|
||||||
++attempt;
|
Zone::Lock lock(zone.areaMutex); //We are going to subtract this area
|
||||||
|
auto possibleArea = zone.areaPossible();
|
||||||
|
|
||||||
|
if (guarded)
|
||||||
|
{
|
||||||
|
path = manager.placeAndConnectObject(possibleArea, rmgObject, [this, &rmgObject, &minDistance, &manager](const int3& tile)
|
||||||
|
{
|
||||||
|
auto ti = map.getTileInfo(tile);
|
||||||
|
if (ti.getNearestObjectDistance() < minDistance)
|
||||||
|
return -1.f;
|
||||||
|
|
||||||
|
for (const auto& t : rmgObject.getArea().getTilesVector())
|
||||||
|
{
|
||||||
|
if (map.getTileInfo(t).getNearestObjectDistance() < minDistance)
|
||||||
|
return -1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto guardedArea = rmgObject.instances().back()->getAccessibleArea();
|
||||||
|
auto areaToBlock = rmgObject.getAccessibleArea(true);
|
||||||
|
areaToBlock.subtract(guardedArea);
|
||||||
|
if (areaToBlock.overlap(zone.freePaths()) || areaToBlock.overlap(manager.getVisitableArea()))
|
||||||
|
return -1.f;
|
||||||
|
|
||||||
|
return ti.getNearestObjectDistance();
|
||||||
|
}, guarded, false, ObjectManager::OptimizeType::DISTANCE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
path = manager.placeAndConnectObject(possibleArea, rmgObject, minDistance, guarded, false, ObjectManager::OptimizeType::DISTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.valid())
|
||||||
|
{
|
||||||
|
//debug purposes
|
||||||
|
treasureArea.unite(rmgObject.getArea());
|
||||||
|
if (guarded)
|
||||||
|
{
|
||||||
|
guards.unite(rmgObject.instances().back()->getBlockedArea());
|
||||||
|
auto guardedArea = rmgObject.instances().back()->getAccessibleArea();
|
||||||
|
auto areaToBlock = rmgObject.getAccessibleArea(true);
|
||||||
|
areaToBlock.subtract(guardedArea);
|
||||||
|
treasureBlockArea.unite(areaToBlock);
|
||||||
|
}
|
||||||
|
zone.connectPath(path);
|
||||||
|
manager.placeObject(rmgObject, guarded, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++attempt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -54,7 +54,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
bool isGuardNeededForTreasure(int value);
|
bool isGuardNeededForTreasure(int value);
|
||||||
|
|
||||||
ObjectInfo * getRandomObject(ui32 desiredValue, ui32 currentValue, ui32 maxValue, bool allowLargeObjects);
|
ObjectInfo * getRandomObject(ui32 desiredValue, ui32 currentValue, bool allowLargeObjects);
|
||||||
std::vector<ObjectInfo*> prepareTreasurePile(const CTreasureInfo & treasureInfo);
|
std::vector<ObjectInfo*> prepareTreasurePile(const CTreasureInfo & treasureInfo);
|
||||||
rmg::Object constructTreasurePile(const std::vector<ObjectInfo*> & treasureInfos, bool densePlacement = false);
|
rmg::Object constructTreasurePile(const std::vector<ObjectInfo*> & treasureInfos, bool densePlacement = false);
|
||||||
|
|
||||||
|
@@ -83,8 +83,11 @@ void WaterProxy::init()
|
|||||||
{
|
{
|
||||||
for(auto & z : map.getZones())
|
for(auto & z : map.getZones())
|
||||||
{
|
{
|
||||||
dependency(z.second->getModificator<TownPlacer>());
|
if (!zone.isUnderground())
|
||||||
dependency(z.second->getModificator<WaterAdopter>());
|
{
|
||||||
|
dependency(z.second->getModificator<TownPlacer>());
|
||||||
|
dependency(z.second->getModificator<WaterAdopter>());
|
||||||
|
}
|
||||||
postfunction(z.second->getModificator<ConnectionsPlacer>());
|
postfunction(z.second->getModificator<ConnectionsPlacer>());
|
||||||
postfunction(z.second->getModificator<ObjectManager>());
|
postfunction(z.second->getModificator<ObjectManager>());
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user