浏览代码

Complete solution for artifact equip & exchange.

DjWarmonger 10 年之前
父节点
当前提交
d32461d9d1
共有 1 个文件被更改,包括 83 次插入49 次删除
  1. 83 49
      AI/VCAI/VCAI.cpp

+ 83 - 49
AI/VCAI/VCAI.cpp

@@ -988,63 +988,97 @@ void VCAI::pickBestCreatures(const CArmedInstance * army, const CArmedInstance *
 }
 
 void VCAI::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance * other)
-{
-	std::vector<ArtifactLocation> allArtifacts;
-
-	for (auto p : h->artifactsWorn)
+{	
+	auto equipBest = [](const CGHeroInstance * h, const CGHeroInstance * otherh, bool giveStuffToFirstHero) -> void
 	{
-		if (p.second.artifact)
-			allArtifacts.push_back(ArtifactLocation(h, p.first));
-	}
-	for (auto slot : h->artifactsInBackpack)
-		allArtifacts.push_back(ArtifactLocation(h, h->getArtPos(slot.artifact)));
+		bool changeMade = false;
 
-	if (other)
-	{
-		for (auto p : other->artifactsWorn)
+		do
 		{
-			if (p.second.artifact)
-				allArtifacts.push_back(ArtifactLocation(other, p.first));
-		}
-		for (auto slot : other->artifactsInBackpack)
-			allArtifacts.push_back(ArtifactLocation(other, other->getArtPos(slot.artifact)));
-	}
-	
+			changeMade = false;
 
-	for (auto location : allArtifacts)
-	{
-		auto artifact = location.getSlot()->artifact;
-		auto otherSlot = h->getSlot(artifact->firstAvailableSlot(h));
-		if (otherSlot && otherSlot->artifact)
-			if (compareArtifacts (artifact, otherSlot->artifact)) //if that artifact is better than what we have, pick it
-				cb->swapArtifacts (location, ArtifactLocation(h, h->getArtPos(otherSlot->artifact)));
-	}
+			//we collect gear always in same order
+			std::vector<ArtifactLocation> allArtifacts;
+			if (giveStuffToFirstHero)
+			{
+				for (auto p : h->artifactsWorn)
+				{
+					if (p.second.artifact)
+						allArtifacts.push_back(ArtifactLocation(h, p.first));
+				}
+			}
+			for (auto slot : h->artifactsInBackpack)
+				allArtifacts.push_back(ArtifactLocation(h, h->getArtPos(slot.artifact)));
 
-	if (other)
-	{
-		//do not touch artifacts worn by first (main) hero
-		//slots may have moved significantly, just start from scratch
-		allArtifacts.clear();
+			if (otherh)
+			{
+				for (auto p : otherh->artifactsWorn)
+				{
+					if (p.second.artifact)
+						allArtifacts.push_back(ArtifactLocation(otherh, p.first));
+				}
+				for (auto slot : otherh->artifactsInBackpack)
+					allArtifacts.push_back(ArtifactLocation(otherh, otherh->getArtPos(slot.artifact)));
+			}
+			//we give stuff to one hero or another, depending on giveStuffToFirstHero
 
-		for (auto slot : h->artifactsInBackpack)
-			allArtifacts.push_back(ArtifactLocation(h, h->getArtPos(slot.artifact)));
+			const CGHeroInstance * target = nullptr;
+			if (giveStuffToFirstHero)
+				target = h;
+			else
+				target = otherh;
 
-		for (auto p : other->artifactsWorn)
-		{
-			if (p.second.artifact)
-				allArtifacts.push_back(ArtifactLocation(other, p.first));
-		}
-		for (auto slot : other->artifactsInBackpack)
-			allArtifacts.push_back(ArtifactLocation(other, other->getArtPos(slot.artifact)));
+			for (auto location : allArtifacts)
+			{
+				if (location.relatedObj() == target && location.slot < ArtifactPosition::AFTER_LAST)
+					continue; //don't reequip artifact we already wear
 
-		for (auto location : allArtifacts)
-		{
-			auto artifact = location.getSlot()->artifact;
-			auto otherSlot = other->getSlot(artifact->firstAvailableSlot(other));
-			if (otherSlot && otherSlot->artifact)
-				if (compareArtifacts(artifact, otherSlot->artifact)) //if that artifact is better than what we have, pick it
-					cb->swapArtifacts(location, ArtifactLocation(other, other->getArtPos(otherSlot->artifact)));
-		}
+				auto s = location.getSlot();
+				if (!s)
+					continue;
+				auto artifact = s->artifact;
+				if (!artifact)
+					continue;
+				//FIXME: why are the above possible to be null?
+
+				bool emptySlotFound = false;
+				for (auto slot : artifact->artType->possibleSlots.at(target->bearerType()))
+				{
+					if (target->isPositionFree(slot))
+					{
+						cb->swapArtifacts(location, ArtifactLocation(target, slot)); //just put into empty slot
+						emptySlotFound = true;
+						changeMade = true;
+						break;
+					}
+				}
+				if (!emptySlotFound) //try to put that atifact in already occupied slot
+				{
+					for (auto slot : artifact->artType->possibleSlots.at(target->bearerType()))
+					{
+						auto otherSlot = target->getSlot(slot);
+						if (otherSlot && otherSlot->artifact) //we need to exchange artifact for better one
+						{
+							if (compareArtifacts(artifact, otherSlot->artifact)) //if that artifact is better than what we have, pick it
+							{
+								cb->swapArtifacts(location, ArtifactLocation(target, target->getArtPos(otherSlot->artifact)));
+								break;
+								changeMade = true;
+							}
+						}
+					}
+				}
+				if (changeMade)
+					break; //start evaluating artifacts from scratch
+			}
+		} while (changeMade);
+	};
+
+	equipBest (h, other, true);
+
+	if (other)
+	{
+		equipBest(h, other, false);
 	}
 
 }