Explorar o código

Fix hota offset + 2 possible crashes

Tomasz Zieliński %!s(int64=2) %!d(string=hai) anos
pai
achega
0252d0f986
Modificáronse 2 ficheiros con 44 adicións e 15 borrados
  1. 0 10
      lib/rmg/RmgObject.cpp
  2. 44 5
      lib/rmg/modificators/ObjectManager.cpp

+ 0 - 10
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()));

+ 44 - 5
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<QuestArtifactPlacer>())
 				{
@@ -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;
 }