mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-06 09:09:40 +02:00
Definitive solution for Corpse
This commit is contained in:
@@ -313,6 +313,19 @@ const rmg::Area & Object::getRemovableArea() const
|
|||||||
return dRemovableAreaCache;
|
return dRemovableAreaCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const rmg::Area & Object::getVisitableArea() const
|
||||||
|
{
|
||||||
|
if(dVisitableCache.empty())
|
||||||
|
{
|
||||||
|
for(const auto & i : dInstances)
|
||||||
|
{
|
||||||
|
// FIXME: Account for bjects with multiple visitable tiles
|
||||||
|
dVisitableCache.add(i.getVisitablePosition());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dVisitableCache;
|
||||||
|
}
|
||||||
|
|
||||||
const rmg::Area Object::getEntrableArea() const
|
const rmg::Area Object::getEntrableArea() const
|
||||||
{
|
{
|
||||||
// Calculate Area that hero can freely pass
|
// Calculate Area that hero can freely pass
|
||||||
@@ -320,7 +333,8 @@ const rmg::Area Object::getEntrableArea() const
|
|||||||
// Do not use blockVisitTiles, unless they belong to removable objects (resources etc.)
|
// Do not use blockVisitTiles, unless they belong to removable objects (resources etc.)
|
||||||
// area = accessibleArea - (blockVisitableArea - removableArea)
|
// area = accessibleArea - (blockVisitableArea - removableArea)
|
||||||
|
|
||||||
rmg::Area entrableArea = getAccessibleArea();
|
// FIXME: What does it do? AccessibleArea means area AROUND the object
|
||||||
|
rmg::Area entrableArea = getVisitableArea();
|
||||||
rmg::Area blockVisitableArea = getBlockVisitableArea();
|
rmg::Area blockVisitableArea = getBlockVisitableArea();
|
||||||
blockVisitableArea.subtract(getRemovableArea());
|
blockVisitableArea.subtract(getRemovableArea());
|
||||||
entrableArea.subtract(blockVisitableArea);
|
entrableArea.subtract(blockVisitableArea);
|
||||||
@@ -330,11 +344,14 @@ const rmg::Area Object::getEntrableArea() const
|
|||||||
|
|
||||||
void Object::setPosition(const int3 & position)
|
void Object::setPosition(const int3 & position)
|
||||||
{
|
{
|
||||||
dAccessibleAreaCache.translate(position - dPosition);
|
auto shift = position - dPosition;
|
||||||
dAccessibleAreaFullCache.translate(position - dPosition);
|
|
||||||
dBlockVisitableCache.translate(position - dPosition);
|
dAccessibleAreaCache.translate(shift);
|
||||||
dRemovableAreaCache.translate(position - dPosition);
|
dAccessibleAreaFullCache.translate(shift);
|
||||||
dFullAreaCache.translate(position - dPosition);
|
dBlockVisitableCache.translate(shift);
|
||||||
|
dVisitableCache.translate(shift);
|
||||||
|
dRemovableAreaCache.translate(shift);
|
||||||
|
dFullAreaCache.translate(shift);
|
||||||
|
|
||||||
dPosition = position;
|
dPosition = position;
|
||||||
for(auto& i : dInstances)
|
for(auto& i : dInstances)
|
||||||
@@ -450,6 +467,7 @@ void Object::clearCachedArea() const
|
|||||||
dAccessibleAreaCache.clear();
|
dAccessibleAreaCache.clear();
|
||||||
dAccessibleAreaFullCache.clear();
|
dAccessibleAreaFullCache.clear();
|
||||||
dBlockVisitableCache.clear();
|
dBlockVisitableCache.clear();
|
||||||
|
dVisitableCache.clear();
|
||||||
dRemovableAreaCache.clear();
|
dRemovableAreaCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ public:
|
|||||||
int3 getVisitablePosition() const;
|
int3 getVisitablePosition() const;
|
||||||
const Area & getAccessibleArea(bool exceptLast = false) const;
|
const Area & getAccessibleArea(bool exceptLast = false) const;
|
||||||
const Area & getBlockVisitableArea() const;
|
const Area & getBlockVisitableArea() const;
|
||||||
|
const Area & getVisitableArea() const;
|
||||||
const Area & getRemovableArea() const;
|
const Area & getRemovableArea() const;
|
||||||
const Area getEntrableArea() const;
|
const Area getEntrableArea() const;
|
||||||
|
|
||||||
@@ -96,6 +97,7 @@ private:
|
|||||||
mutable Area dFullAreaCache;
|
mutable Area dFullAreaCache;
|
||||||
mutable Area dAccessibleAreaCache, dAccessibleAreaFullCache;
|
mutable Area dAccessibleAreaCache, dAccessibleAreaFullCache;
|
||||||
mutable Area dBlockVisitableCache;
|
mutable Area dBlockVisitableCache;
|
||||||
|
mutable Area dVisitableCache;
|
||||||
mutable Area dRemovableAreaCache;
|
mutable Area dRemovableAreaCache;
|
||||||
int3 dPosition;
|
int3 dPosition;
|
||||||
mutable std::optional<int3> visibleTopOffset;
|
mutable std::optional<int3> visibleTopOffset;
|
||||||
|
|||||||
@@ -600,11 +600,13 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD
|
|||||||
//Cannot be trespassed (Corpse)
|
//Cannot be trespassed (Corpse)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if(instance->object().appearance->isVisitableFromTop())
|
else if(!instance->object().appearance->isVisitableFromTop())
|
||||||
m->areaForRoads().add(instance->getVisitablePosition());
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
m->areaIsolated().add(instance->getVisitablePosition() + int3(0, -1, 0));
|
auto abovePos = instance->getVisitablePosition() + int3(0, -1, 0);
|
||||||
|
if (!instance->object().blockingAt(abovePos))
|
||||||
|
{
|
||||||
|
m->areaIsolated().add(abovePos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -718,22 +720,20 @@ bool ObjectManager::addGuard(rmg::Object & object, si32 strength, bool zoneGuard
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Prefer non-blocking tiles, if any
|
// Prefer non-blocking tiles, if any
|
||||||
const auto & entrableTiles = object.getEntrableArea().getTilesVector();
|
auto entrableArea = object.getEntrableArea();
|
||||||
int3 entrableTile(-1, -1, -1);
|
if (entrableArea.empty())
|
||||||
if (entrableTiles.empty())
|
|
||||||
{
|
{
|
||||||
entrableTile = object.getVisitablePosition();
|
entrableArea.add(object.getVisitablePosition());
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entrableTile = *RandomGeneratorUtil::nextItem(entrableTiles, zone.getRand());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rmg::Area visitablePos({entrableTile});
|
rmg::Area entrableBorder = entrableArea.getBorderOutside();
|
||||||
visitablePos.unite(visitablePos.getBorderOutside());
|
|
||||||
|
|
||||||
auto accessibleArea = object.getAccessibleArea();
|
auto accessibleArea = object.getAccessibleArea();
|
||||||
accessibleArea.intersect(visitablePos);
|
accessibleArea.erase_if([&](const int3 & tile)
|
||||||
|
{
|
||||||
|
return !entrableBorder.contains(tile);
|
||||||
|
});
|
||||||
|
|
||||||
if(accessibleArea.empty())
|
if(accessibleArea.empty())
|
||||||
{
|
{
|
||||||
delete guard;
|
delete guard;
|
||||||
|
|||||||
@@ -633,9 +633,12 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
|
|||||||
{
|
{
|
||||||
auto blockedArea = rmgObject.getArea();
|
auto blockedArea = rmgObject.getArea();
|
||||||
auto entrableArea = rmgObject.getEntrableArea();
|
auto entrableArea = rmgObject.getEntrableArea();
|
||||||
|
auto accessibleArea = rmgObject.getAccessibleArea();
|
||||||
|
|
||||||
if(rmgObject.instances().empty())
|
if(rmgObject.instances().empty())
|
||||||
entrableArea.add(int3());
|
{
|
||||||
|
accessibleArea.add(int3());
|
||||||
|
}
|
||||||
|
|
||||||
auto * object = oi->generateObject();
|
auto * object = oi->generateObject();
|
||||||
if(oi->templates.empty())
|
if(oi->templates.empty())
|
||||||
@@ -650,20 +653,21 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
|
|||||||
|
|
||||||
object->appearance = *RandomGeneratorUtil::nextItem(templates, zone.getRand());
|
object->appearance = *RandomGeneratorUtil::nextItem(templates, zone.getRand());
|
||||||
|
|
||||||
auto blockingIssue = object->isBlockedVisitable() && !object->isRemovable();
|
//Put object in accessible area next to entrable area (excluding blockvis tiles)
|
||||||
if (blockingIssue)
|
if (!entrableArea.empty())
|
||||||
{
|
{
|
||||||
// Do not place next to another such object (Corpse issue)
|
auto entrableBorder = entrableArea.getBorderOutside();
|
||||||
// Calculate this before instance is added to rmgObject
|
accessibleArea.erase_if([&](const int3 & tile)
|
||||||
auto blockVisitProximity = rmgObject.getBlockVisitableArea().getBorderOutside();
|
{
|
||||||
entrableArea.subtract(blockVisitProximity);
|
return !entrableBorder.count(tile);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto & instance = rmgObject.addInstance(*object);
|
auto & instance = rmgObject.addInstance(*object);
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if(entrableArea.empty())
|
if(accessibleArea.empty())
|
||||||
{
|
{
|
||||||
//fail - fallback
|
//fail - fallback
|
||||||
rmgObject.clear();
|
rmgObject.clear();
|
||||||
@@ -671,15 +675,24 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int3> bestPositions;
|
std::vector<int3> bestPositions;
|
||||||
if(densePlacement)
|
if(densePlacement && !entrableArea.empty())
|
||||||
{
|
{
|
||||||
|
// Choose positon which has access to as many entrable tiles as possible
|
||||||
int bestPositionsWeight = std::numeric_limits<int>::max();
|
int bestPositionsWeight = std::numeric_limits<int>::max();
|
||||||
for(const auto & t : entrableArea.getTilesVector())
|
for(const auto & t : accessibleArea.getTilesVector())
|
||||||
{
|
{
|
||||||
instance.setPosition(t);
|
instance.setPosition(t);
|
||||||
int w = rmgObject.getEntrableArea().getTilesVector().size();
|
|
||||||
|
|
||||||
if(w && w < bestPositionsWeight)
|
auto currentAccessibleArea = rmgObject.getAccessibleArea();
|
||||||
|
auto currentEntrableBorder = rmgObject.getEntrableArea().getBorderOutside();
|
||||||
|
currentAccessibleArea.erase_if([&](const int3 & tile)
|
||||||
|
{
|
||||||
|
return !currentEntrableBorder.count(tile);
|
||||||
|
});
|
||||||
|
|
||||||
|
size_t w = currentAccessibleArea.getTilesVector().size();
|
||||||
|
|
||||||
|
if(w > bestPositionsWeight)
|
||||||
{
|
{
|
||||||
// Minimum 1 position must be entrable
|
// Minimum 1 position must be entrable
|
||||||
bestPositions.clear();
|
bestPositions.clear();
|
||||||
@@ -691,12 +704,11 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
|
|||||||
bestPositions.push_back(t);
|
bestPositions.push_back(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bestPositions.empty())
|
if (bestPositions.empty())
|
||||||
{
|
{
|
||||||
bestPositions = entrableArea.getTilesVector();
|
bestPositions = accessibleArea.getTilesVector();
|
||||||
}
|
}
|
||||||
|
|
||||||
int3 nextPos = *RandomGeneratorUtil::nextItem(bestPositions, zone.getRand());
|
int3 nextPos = *RandomGeneratorUtil::nextItem(bestPositions, zone.getRand());
|
||||||
@@ -713,11 +725,11 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
|
|||||||
if(rmgObject.instances().size() == 1)
|
if(rmgObject.instances().size() == 1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if(!blockedArea.overlap(instance.getBlockedArea()) && entrableArea.overlap(instanceAccessibleArea))
|
if(!blockedArea.overlap(instance.getBlockedArea()) && accessibleArea.overlap(instanceAccessibleArea))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//fail - new position
|
//fail - new position
|
||||||
entrableArea.erase(nextPos);
|
accessibleArea.erase(nextPos);
|
||||||
} while(true);
|
} while(true);
|
||||||
}
|
}
|
||||||
return rmgObject;
|
return rmgObject;
|
||||||
|
|||||||
Reference in New Issue
Block a user