From 0252d0f98631d9d151dc7661de7a21a1c38f7347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Zieli=C5=84ski?= Date: Fri, 11 Aug 2023 07:45:24 +0200 Subject: [PATCH 1/2] Fix hota offset + 2 possible crashes --- lib/rmg/RmgObject.cpp | 10 ------ lib/rmg/modificators/ObjectManager.cpp | 49 +++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/lib/rmg/RmgObject.cpp b/lib/rmg/RmgObject.cpp index 0106bee4f..540463948 100644 --- a/lib/rmg/RmgObject.cpp +++ b/lib/rmg/RmgObject.cpp @@ -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())); diff --git a/lib/rmg/modificators/ObjectManager.cpp b/lib/rmg/modificators/ObjectManager.cpp index 46f001c90..6644ee93f 100644 --- a/lib/rmg/modificators/ObjectManager.cpp +++ b/lib/rmg/modificators/ObjectManager.cpp @@ -129,6 +129,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) { @@ -149,6 +162,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) @@ -168,9 +184,12 @@ int3 ObjectManager::findPlaceForObject(const rmg::Area & searchArea, rmg::Object if (obj.getVisibleTop().y < 0) continue; - + 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); @@ -435,6 +454,21 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD { object.finalize(map); + if (object.instances().size() == 1 && object.instances().front()->object().ID == Obj::MONSTER) + { + //Fix for HoTA offset - lonely guards + object.getPosition(); + auto monster = object.instances().front(); + 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); + } + Zone::Lock lock(zone.areaMutex); zone.areaPossible().subtract(object.getArea()); bool keepVisitable = zone.freePaths().contains(object.getVisitablePosition()); @@ -443,8 +477,8 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD zone.freePaths().add(object.getVisitablePosition()); 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 +535,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()) { @@ -629,8 +664,12 @@ 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; } From 8f450cf253dea640f3320a972c6ba80e1a8bd4f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Zieli=C5=84ski?= Date: Fri, 11 Aug 2023 18:43:22 +0200 Subject: [PATCH 2/2] Fix for monsters spawning at left side of the map --- lib/rmg/modificators/ObjectManager.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/rmg/modificators/ObjectManager.cpp b/lib/rmg/modificators/ObjectManager.cpp index 6644ee93f..d1afd557e 100644 --- a/lib/rmg/modificators/ObjectManager.cpp +++ b/lib/rmg/modificators/ObjectManager.cpp @@ -452,13 +452,19 @@ bool ObjectManager::createRequiredObjects() void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateDistance, bool createRoad/* = false*/) { - object.finalize(map); + //object.finalize(map); if (object.instances().size() == 1 && object.instances().front()->object().ID == Obj::MONSTER) { //Fix for HoTA offset - lonely guards - object.getPosition(); + 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; @@ -468,6 +474,7 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD int3 parentOffset = monster->getPosition(true) - monster->getPosition(false); monster->setPosition(fixedPos - parentOffset); } + object.finalize(map); Zone::Lock lock(zone.areaMutex); zone.areaPossible().subtract(object.getArea());