mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-28 08:48:48 +02:00
Definitive solution for Corpse
This commit is contained in:
parent
e22f6dd07e
commit
d5f9de5beb
@ -313,6 +313,19 @@ const rmg::Area & Object::getRemovableArea() const
|
||||
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
|
||||
{
|
||||
// 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.)
|
||||
// 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();
|
||||
blockVisitableArea.subtract(getRemovableArea());
|
||||
entrableArea.subtract(blockVisitableArea);
|
||||
@ -330,11 +344,14 @@ const rmg::Area Object::getEntrableArea() const
|
||||
|
||||
void Object::setPosition(const int3 & position)
|
||||
{
|
||||
dAccessibleAreaCache.translate(position - dPosition);
|
||||
dAccessibleAreaFullCache.translate(position - dPosition);
|
||||
dBlockVisitableCache.translate(position - dPosition);
|
||||
dRemovableAreaCache.translate(position - dPosition);
|
||||
dFullAreaCache.translate(position - dPosition);
|
||||
auto shift = position - dPosition;
|
||||
|
||||
dAccessibleAreaCache.translate(shift);
|
||||
dAccessibleAreaFullCache.translate(shift);
|
||||
dBlockVisitableCache.translate(shift);
|
||||
dVisitableCache.translate(shift);
|
||||
dRemovableAreaCache.translate(shift);
|
||||
dFullAreaCache.translate(shift);
|
||||
|
||||
dPosition = position;
|
||||
for(auto& i : dInstances)
|
||||
@ -450,6 +467,7 @@ void Object::clearCachedArea() const
|
||||
dAccessibleAreaCache.clear();
|
||||
dAccessibleAreaFullCache.clear();
|
||||
dBlockVisitableCache.clear();
|
||||
dVisitableCache.clear();
|
||||
dRemovableAreaCache.clear();
|
||||
}
|
||||
|
||||
|
@ -74,6 +74,7 @@ public:
|
||||
int3 getVisitablePosition() const;
|
||||
const Area & getAccessibleArea(bool exceptLast = false) const;
|
||||
const Area & getBlockVisitableArea() const;
|
||||
const Area & getVisitableArea() const;
|
||||
const Area & getRemovableArea() const;
|
||||
const Area getEntrableArea() const;
|
||||
|
||||
@ -96,6 +97,7 @@ private:
|
||||
mutable Area dFullAreaCache;
|
||||
mutable Area dAccessibleAreaCache, dAccessibleAreaFullCache;
|
||||
mutable Area dBlockVisitableCache;
|
||||
mutable Area dVisitableCache;
|
||||
mutable Area dRemovableAreaCache;
|
||||
int3 dPosition;
|
||||
mutable std::optional<int3> visibleTopOffset;
|
||||
|
@ -600,11 +600,13 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD
|
||||
//Cannot be trespassed (Corpse)
|
||||
continue;
|
||||
}
|
||||
else if(instance->object().appearance->isVisitableFromTop())
|
||||
m->areaForRoads().add(instance->getVisitablePosition());
|
||||
else
|
||||
else if(!instance->object().appearance->isVisitableFromTop())
|
||||
{
|
||||
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;
|
||||
|
||||
// Prefer non-blocking tiles, if any
|
||||
const auto & entrableTiles = object.getEntrableArea().getTilesVector();
|
||||
int3 entrableTile(-1, -1, -1);
|
||||
if (entrableTiles.empty())
|
||||
auto entrableArea = object.getEntrableArea();
|
||||
if (entrableArea.empty())
|
||||
{
|
||||
entrableTile = object.getVisitablePosition();
|
||||
}
|
||||
else
|
||||
{
|
||||
entrableTile = *RandomGeneratorUtil::nextItem(entrableTiles, zone.getRand());
|
||||
entrableArea.add(object.getVisitablePosition());
|
||||
}
|
||||
|
||||
rmg::Area visitablePos({entrableTile});
|
||||
visitablePos.unite(visitablePos.getBorderOutside());
|
||||
rmg::Area entrableBorder = entrableArea.getBorderOutside();
|
||||
|
||||
auto accessibleArea = object.getAccessibleArea();
|
||||
accessibleArea.intersect(visitablePos);
|
||||
accessibleArea.erase_if([&](const int3 & tile)
|
||||
{
|
||||
return !entrableBorder.contains(tile);
|
||||
});
|
||||
|
||||
if(accessibleArea.empty())
|
||||
{
|
||||
delete guard;
|
||||
|
@ -633,9 +633,12 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
|
||||
{
|
||||
auto blockedArea = rmgObject.getArea();
|
||||
auto entrableArea = rmgObject.getEntrableArea();
|
||||
auto accessibleArea = rmgObject.getAccessibleArea();
|
||||
|
||||
if(rmgObject.instances().empty())
|
||||
entrableArea.add(int3());
|
||||
{
|
||||
accessibleArea.add(int3());
|
||||
}
|
||||
|
||||
auto * object = oi->generateObject();
|
||||
if(oi->templates.empty())
|
||||
@ -650,20 +653,21 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
|
||||
|
||||
object->appearance = *RandomGeneratorUtil::nextItem(templates, zone.getRand());
|
||||
|
||||
auto blockingIssue = object->isBlockedVisitable() && !object->isRemovable();
|
||||
if (blockingIssue)
|
||||
//Put object in accessible area next to entrable area (excluding blockvis tiles)
|
||||
if (!entrableArea.empty())
|
||||
{
|
||||
// Do not place next to another such object (Corpse issue)
|
||||
// Calculate this before instance is added to rmgObject
|
||||
auto blockVisitProximity = rmgObject.getBlockVisitableArea().getBorderOutside();
|
||||
entrableArea.subtract(blockVisitProximity);
|
||||
auto entrableBorder = entrableArea.getBorderOutside();
|
||||
accessibleArea.erase_if([&](const int3 & tile)
|
||||
{
|
||||
return !entrableBorder.count(tile);
|
||||
});
|
||||
}
|
||||
|
||||
auto & instance = rmgObject.addInstance(*object);
|
||||
|
||||
do
|
||||
{
|
||||
if(entrableArea.empty())
|
||||
if(accessibleArea.empty())
|
||||
{
|
||||
//fail - fallback
|
||||
rmgObject.clear();
|
||||
@ -671,15 +675,24 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
|
||||
}
|
||||
|
||||
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();
|
||||
for(const auto & t : entrableArea.getTilesVector())
|
||||
for(const auto & t : accessibleArea.getTilesVector())
|
||||
{
|
||||
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
|
||||
bestPositions.clear();
|
||||
@ -691,12 +704,11 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
|
||||
bestPositions.push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (bestPositions.empty())
|
||||
{
|
||||
bestPositions = entrableArea.getTilesVector();
|
||||
bestPositions = accessibleArea.getTilesVector();
|
||||
}
|
||||
|
||||
int3 nextPos = *RandomGeneratorUtil::nextItem(bestPositions, zone.getRand());
|
||||
@ -713,11 +725,11 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
|
||||
if(rmgObject.instances().size() == 1)
|
||||
break;
|
||||
|
||||
if(!blockedArea.overlap(instance.getBlockedArea()) && entrableArea.overlap(instanceAccessibleArea))
|
||||
if(!blockedArea.overlap(instance.getBlockedArea()) && accessibleArea.overlap(instanceAccessibleArea))
|
||||
break;
|
||||
|
||||
//fail - new position
|
||||
entrableArea.erase(nextPos);
|
||||
accessibleArea.erase(nextPos);
|
||||
} while(true);
|
||||
}
|
||||
return rmgObject;
|
||||
|
Loading…
Reference in New Issue
Block a user