|
@@ -38,11 +38,10 @@ const Area & Object::Instance::getBlockedArea() const
|
|
|
{
|
|
|
if(dBlockedAreaCache.empty())
|
|
|
{
|
|
|
- dBlockedAreaCache.assign(dObject.getBlockedPos());
|
|
|
+ std::set<int3> blockedArea = dObject.getBlockedPos();
|
|
|
+ dBlockedAreaCache.assign(rmg::Tileset(blockedArea.begin(), blockedArea.end()));
|
|
|
if(dObject.isVisitable() || dBlockedAreaCache.empty())
|
|
|
- if (!dObject.isBlockedVisitable())
|
|
|
- // Do no assume blocked tile is accessible
|
|
|
- dBlockedAreaCache.add(dObject.visitablePos());
|
|
|
+ dBlockedAreaCache.add(dObject.visitablePos());
|
|
|
}
|
|
|
return dBlockedAreaCache;
|
|
|
}
|
|
@@ -70,8 +69,10 @@ const rmg::Area & Object::Instance::getAccessibleArea() const
|
|
|
if(dAccessibleAreaCache.empty())
|
|
|
{
|
|
|
auto neighbours = rmg::Area({getVisitablePosition()}).getBorderOutside();
|
|
|
+ // FIXME: Blocked area of removable object is also accessible area for neighbors
|
|
|
rmg::Area visitable = rmg::Area(neighbours) - getBlockedArea();
|
|
|
- for(const auto & from : visitable.getTiles())
|
|
|
+ // TODO: Add in one operation to avoid multiple invalidation
|
|
|
+ for(const auto & from : visitable.getTilesVector())
|
|
|
{
|
|
|
if(isVisitableFrom(from))
|
|
|
dAccessibleAreaCache.add(from);
|
|
@@ -122,22 +123,13 @@ void Object::Instance::setAnyTemplate(CRandomGenerator & rng)
|
|
|
|
|
|
void Object::Instance::setTemplate(TerrainId terrain, CRandomGenerator & rng)
|
|
|
{
|
|
|
- auto templates = dObject.getObjectHandler()->getTemplates(terrain);
|
|
|
+ auto templates = dObject.getObjectHandler()->getMostSpecificTemplates(terrain);
|
|
|
+
|
|
|
if (templates.empty())
|
|
|
{
|
|
|
auto terrainName = VLC->terrainTypeHandler->getById(terrain)->getNameTranslated();
|
|
|
throw rmgException(boost::str(boost::format("Did not find graphics for object (%d,%d) at %s") % dObject.ID % dObject.getObjTypeIndex() % terrainName));
|
|
|
}
|
|
|
- //Get terrain-specific template if possible
|
|
|
- int leastTerrains = (*boost::min_element(templates, [](const std::shared_ptr<const ObjectTemplate> & tmp1, const std::shared_ptr<const ObjectTemplate> & tmp2)
|
|
|
- {
|
|
|
- return tmp1->getAllowedTerrains().size() < tmp2->getAllowedTerrains().size();
|
|
|
- }))->getAllowedTerrains().size();
|
|
|
-
|
|
|
- vstd::erase_if(templates, [leastTerrains](const std::shared_ptr<const ObjectTemplate> & tmp)
|
|
|
- {
|
|
|
- return tmp->getAllowedTerrains().size() > leastTerrains;
|
|
|
- });
|
|
|
|
|
|
dObject.appearance = *RandomGeneratorUtil::nextItem(templates, rng);
|
|
|
dAccessibleAreaCache.clear();
|
|
@@ -191,7 +183,6 @@ Object::Object(CGObjectInstance & object):
|
|
|
}
|
|
|
|
|
|
Object::Object(const Object & object):
|
|
|
- dStrength(object.dStrength),
|
|
|
guarded(false)
|
|
|
{
|
|
|
for(const auto & i : object.dInstances)
|
|
@@ -199,20 +190,24 @@ Object::Object(const Object & object):
|
|
|
setPosition(object.getPosition());
|
|
|
}
|
|
|
|
|
|
-std::list<Object::Instance*> Object::instances()
|
|
|
+std::list<Object::Instance*> & Object::instances()
|
|
|
{
|
|
|
- std::list<Object::Instance*> result;
|
|
|
- for(auto & i : dInstances)
|
|
|
- result.push_back(&i);
|
|
|
- return result;
|
|
|
+ if (cachedInstanceList.empty())
|
|
|
+ {
|
|
|
+ for(auto & i : dInstances)
|
|
|
+ cachedInstanceList.push_back(&i);
|
|
|
+ }
|
|
|
+ return cachedInstanceList;
|
|
|
}
|
|
|
|
|
|
-std::list<const Object::Instance*> Object::instances() const
|
|
|
+std::list<const Object::Instance*> & Object::instances() const
|
|
|
{
|
|
|
- std::list<const Object::Instance*> result;
|
|
|
- for(const auto & i : dInstances)
|
|
|
- result.push_back(&i);
|
|
|
- return result;
|
|
|
+ if (cachedInstanceConstList.empty())
|
|
|
+ {
|
|
|
+ for(const auto & i : dInstances)
|
|
|
+ cachedInstanceConstList.push_back(&i);
|
|
|
+ }
|
|
|
+ return cachedInstanceConstList;
|
|
|
}
|
|
|
|
|
|
void Object::addInstance(Instance & object)
|
|
@@ -220,16 +215,22 @@ void Object::addInstance(Instance & object)
|
|
|
//assert(object.dParent == *this);
|
|
|
setGuardedIfMonster(object);
|
|
|
dInstances.push_back(object);
|
|
|
+ cachedInstanceList.push_back(&object);
|
|
|
+ cachedInstanceConstList.push_back(&object);
|
|
|
|
|
|
clearCachedArea();
|
|
|
+ visibleTopOffset.reset();
|
|
|
}
|
|
|
|
|
|
Object::Instance & Object::addInstance(CGObjectInstance & object)
|
|
|
{
|
|
|
dInstances.emplace_back(*this, object);
|
|
|
setGuardedIfMonster(dInstances.back());
|
|
|
+ cachedInstanceList.push_back(&dInstances.back());
|
|
|
+ cachedInstanceConstList.push_back(&dInstances.back());
|
|
|
|
|
|
clearCachedArea();
|
|
|
+ visibleTopOffset.reset();
|
|
|
return dInstances.back();
|
|
|
}
|
|
|
|
|
@@ -237,8 +238,11 @@ Object::Instance & Object::addInstance(CGObjectInstance & object, const int3 & p
|
|
|
{
|
|
|
dInstances.emplace_back(*this, object, position);
|
|
|
setGuardedIfMonster(dInstances.back());
|
|
|
+ cachedInstanceList.push_back(&dInstances.back());
|
|
|
+ cachedInstanceConstList.push_back(&dInstances.back());
|
|
|
|
|
|
clearCachedArea();
|
|
|
+ visibleTopOffset.reset();
|
|
|
return dInstances.back();
|
|
|
}
|
|
|
|
|
@@ -265,15 +269,16 @@ const rmg::Area & Object::getAccessibleArea(bool exceptLast) const
|
|
|
return dAccessibleAreaCache;
|
|
|
if(!exceptLast && !dAccessibleAreaFullCache.empty())
|
|
|
return dAccessibleAreaFullCache;
|
|
|
-
|
|
|
+
|
|
|
+ // FIXME: This clears tiles for every consecutive object
|
|
|
for(auto i = dInstances.begin(); i != std::prev(dInstances.end()); ++i)
|
|
|
dAccessibleAreaCache.unite(i->getAccessibleArea());
|
|
|
-
|
|
|
+
|
|
|
dAccessibleAreaFullCache = dAccessibleAreaCache;
|
|
|
dAccessibleAreaFullCache.unite(dInstances.back().getAccessibleArea());
|
|
|
dAccessibleAreaCache.subtract(getArea());
|
|
|
dAccessibleAreaFullCache.subtract(getArea());
|
|
|
-
|
|
|
+
|
|
|
if(exceptLast)
|
|
|
return dAccessibleAreaCache;
|
|
|
else
|
|
@@ -282,33 +287,45 @@ const rmg::Area & Object::getAccessibleArea(bool exceptLast) const
|
|
|
|
|
|
const rmg::Area & Object::getBlockVisitableArea() const
|
|
|
{
|
|
|
- if(dInstances.empty())
|
|
|
- return dBlockVisitableCache;
|
|
|
-
|
|
|
- for(const auto & i : dInstances)
|
|
|
+ if(dBlockVisitableCache.empty())
|
|
|
{
|
|
|
- // FIXME: Account for blockvis objects with multiple visitable tiles
|
|
|
- if (i.isBlockedVisitable())
|
|
|
- dBlockVisitableCache.add(i.getVisitablePosition());
|
|
|
+ for(const auto & i : dInstances)
|
|
|
+ {
|
|
|
+ // FIXME: Account for blockvis objects with multiple visitable tiles
|
|
|
+ if (i.isBlockedVisitable())
|
|
|
+ dBlockVisitableCache.add(i.getVisitablePosition());
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
return dBlockVisitableCache;
|
|
|
}
|
|
|
|
|
|
const rmg::Area & Object::getRemovableArea() const
|
|
|
{
|
|
|
- if(dInstances.empty())
|
|
|
- return dRemovableAreaCache;
|
|
|
-
|
|
|
- for(const auto & i : dInstances)
|
|
|
+ if(dRemovableAreaCache.empty())
|
|
|
{
|
|
|
- if (i.isRemovable())
|
|
|
- dRemovableAreaCache.unite(i.getBlockedArea());
|
|
|
+ for(const auto & i : dInstances)
|
|
|
+ {
|
|
|
+ if (i.isRemovable())
|
|
|
+ dRemovableAreaCache.unite(i.getBlockedArea());
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
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
|
|
@@ -316,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);
|
|
@@ -326,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)
|
|
@@ -341,6 +362,8 @@ void Object::setTemplate(const TerrainId & terrain, CRandomGenerator & rng)
|
|
|
{
|
|
|
for(auto& i : dInstances)
|
|
|
i.setTemplate(terrain, rng);
|
|
|
+
|
|
|
+ visibleTopOffset.reset();
|
|
|
}
|
|
|
|
|
|
const Area & Object::getArea() const
|
|
@@ -358,15 +381,23 @@ const Area & Object::getArea() const
|
|
|
|
|
|
const int3 Object::getVisibleTop() const
|
|
|
{
|
|
|
- int3 topTile(-1, 10000, -1); //Start at the bottom
|
|
|
- for (const auto& i : dInstances)
|
|
|
+ if (visibleTopOffset)
|
|
|
+ {
|
|
|
+ return dPosition + visibleTopOffset.value();
|
|
|
+ }
|
|
|
+ else
|
|
|
{
|
|
|
- if (i.getTopTile().y < topTile.y)
|
|
|
+ int3 topTile(-1, 10000, -1); //Start at the bottom
|
|
|
+ for (const auto& i : dInstances)
|
|
|
{
|
|
|
- topTile = i.getTopTile();
|
|
|
+ if (i.getTopTile().y < topTile.y)
|
|
|
+ {
|
|
|
+ topTile = i.getTopTile();
|
|
|
+ }
|
|
|
}
|
|
|
+ visibleTopOffset = topTile - dPosition;
|
|
|
+ return topTile;
|
|
|
}
|
|
|
- return topTile;
|
|
|
}
|
|
|
|
|
|
bool rmg::Object::isGuarded() const
|
|
@@ -436,6 +467,7 @@ void Object::clearCachedArea() const
|
|
|
dAccessibleAreaCache.clear();
|
|
|
dAccessibleAreaFullCache.clear();
|
|
|
dBlockVisitableCache.clear();
|
|
|
+ dVisitableCache.clear();
|
|
|
dRemovableAreaCache.clear();
|
|
|
}
|
|
|
|
|
@@ -444,6 +476,9 @@ void Object::clear()
|
|
|
for(auto & instance : dInstances)
|
|
|
instance.clear();
|
|
|
dInstances.clear();
|
|
|
+ cachedInstanceList.clear();
|
|
|
+ cachedInstanceConstList.clear();
|
|
|
+ visibleTopOffset.reset();
|
|
|
|
|
|
clearCachedArea();
|
|
|
}
|