1
0
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:
DjWarmonger 2023-08-12 09:14:02 +02:00 committed by GitHub
commit 4d4eaed808
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 51 additions and 15 deletions

View File

@ -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()));

View File

@ -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;
}