mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Merge pull request #2555 from vcmi/fix_rmg_object_pos
Fix hota offset + 2 possible crashes
This commit is contained in:
commit
4d4eaed808
@ -344,16 +344,6 @@ void Object::Instance::finalize(RmgMap & map)
|
||||
setTemplate(terrainType->getId());
|
||||
}
|
||||
}
|
||||
if (dObject.ID == Obj::MONSTER)
|
||||
{
|
||||
//Make up for extra offset in HotA creature templates
|
||||
auto visitableOffset = dObject.getVisitableOffset();
|
||||
auto fixedPos = getPosition(true) + visitableOffset;
|
||||
vstd::abetween(fixedPos.x, visitableOffset.x, map.width() - 1);
|
||||
vstd::abetween(fixedPos.y, visitableOffset.y, map.height() - 1);
|
||||
int3 parentPos = getPosition(true) - getPosition(false);
|
||||
setPosition(fixedPos - parentPos);
|
||||
}
|
||||
|
||||
if (dObject.isVisitable() && !map.isOnMap(dObject.visitablePos()))
|
||||
throw rmgException(boost::to_string(boost::format("Visitable tile %s of object %d at %s is outside the map") % dObject.visitablePos().toString() % dObject.id % dObject.pos.toString()));
|
||||
|
@ -130,6 +130,19 @@ int3 ObjectManager::findPlaceForObject(const rmg::Area & searchArea, rmg::Object
|
||||
float bestWeight = 0.f;
|
||||
int3 result(-1, -1, -1);
|
||||
|
||||
//Blocked area might not cover object position if it has an offset from (0,0)
|
||||
auto outsideTheMap = [this, &obj]() -> bool
|
||||
{
|
||||
for (const auto& oi : obj.instances())
|
||||
{
|
||||
if (!map.isOnMap(oi->getPosition(true)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if(optimizer & OptimizeType::DISTANCE)
|
||||
{
|
||||
auto open = tilesByDistance;
|
||||
@ -150,6 +163,9 @@ int3 ObjectManager::findPlaceForObject(const rmg::Area & searchArea, rmg::Object
|
||||
if(!searchArea.contains(obj.getArea()) || !searchArea.overlap(obj.getAccessibleArea()))
|
||||
continue;
|
||||
|
||||
if (outsideTheMap())
|
||||
continue;
|
||||
|
||||
float weight = weightFunction(tile);
|
||||
if(weight > bestWeight)
|
||||
{
|
||||
@ -172,6 +188,9 @@ int3 ObjectManager::findPlaceForObject(const rmg::Area & searchArea, rmg::Object
|
||||
if(!searchArea.contains(obj.getArea()) || !searchArea.overlap(obj.getAccessibleArea()))
|
||||
continue;
|
||||
|
||||
if (outsideTheMap())
|
||||
continue;
|
||||
|
||||
float weight = weightFunction(tile);
|
||||
if(weight > bestWeight)
|
||||
{
|
||||
@ -416,7 +435,7 @@ bool ObjectManager::createRequiredObjects()
|
||||
|
||||
//create object on specific positions
|
||||
//TODO: implement guards
|
||||
for (const auto &objInfo : instantObjects)
|
||||
for (const auto &objInfo : instantObjects) //Unused ATM
|
||||
{
|
||||
rmg::Object rmgObject(*objInfo.obj);
|
||||
rmgObject.setPosition(objInfo.pos);
|
||||
@ -433,6 +452,28 @@ bool ObjectManager::createRequiredObjects()
|
||||
|
||||
void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateDistance, bool createRoad/* = false*/)
|
||||
{
|
||||
//object.finalize(map);
|
||||
|
||||
if (object.instances().size() == 1 && object.instances().front()->object().ID == Obj::MONSTER)
|
||||
{
|
||||
//Fix for HoTA offset - lonely guards
|
||||
|
||||
auto monster = object.instances().front();
|
||||
if (!monster->object().appearance)
|
||||
{
|
||||
//Needed to determine visitable offset
|
||||
monster->setAnyTemplate();
|
||||
}
|
||||
object.getPosition();
|
||||
auto visitableOffset = monster->object().getVisitableOffset();
|
||||
auto fixedPos = monster->getPosition(true) + visitableOffset;
|
||||
|
||||
//Do not place guard outside the map
|
||||
vstd::abetween(fixedPos.x, visitableOffset.x, map.width() - 1);
|
||||
vstd::abetween(fixedPos.y, visitableOffset.y, map.height() - 1);
|
||||
int3 parentOffset = monster->getPosition(true) - monster->getPosition(false);
|
||||
monster->setPosition(fixedPos - parentOffset);
|
||||
}
|
||||
object.finalize(map);
|
||||
|
||||
Zone::Lock lock(zone.areaMutex);
|
||||
@ -444,7 +485,7 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD
|
||||
zone.areaUsed().unite(object.getArea());
|
||||
zone.areaUsed().erase(object.getVisitablePosition());
|
||||
|
||||
if(guarded)
|
||||
if(guarded) //We assume the monster won't be guarded
|
||||
{
|
||||
auto guardedArea = object.instances().back()->getAccessibleArea();
|
||||
guardedArea.add(object.instances().back()->getVisitablePosition());
|
||||
@ -501,6 +542,7 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD
|
||||
{
|
||||
case Obj::RANDOM_TREASURE_ART:
|
||||
case Obj::RANDOM_MINOR_ART: //In OH3 quest artifacts have higher value than normal arts
|
||||
case Obj::RANDOM_RESOURCE:
|
||||
{
|
||||
if (auto * qap = zone.getModificator<QuestArtifactPlacer>())
|
||||
{
|
||||
@ -629,9 +671,13 @@ bool ObjectManager::addGuard(rmg::Object & object, si32 strength, bool zoneGuard
|
||||
});
|
||||
|
||||
auto & instance = object.addInstance(*guard);
|
||||
instance.setPosition(guardPos - object.getPosition());
|
||||
instance.setAnyTemplate(); //terrain is irrelevant for monsters, but monsters need some template now
|
||||
|
||||
//Fix HoTA monsters with offset template
|
||||
auto visitableOffset = instance.object().getVisitableOffset();
|
||||
auto fixedPos = guardPos - object.getPosition() + visitableOffset;
|
||||
instance.setPosition(fixedPos);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user