Browse Source

- Handling for Hill fort and (kinda) Magic Well
- Improved hero exchange
- Fixed strange case when AI found allied town extremely dangerous, resulting in endless loop

DjWarmonger 13 years ago
parent
commit
4e726f0eb2
3 changed files with 72 additions and 10 deletions
  1. 66 9
      AI/VCAI/VCAI.cpp
  2. 4 1
      AI/VCAI/VCAI.h
  3. 2 0
      lib/GameConstants.h

+ 66 - 9
AI/VCAI/VCAI.cpp

@@ -100,6 +100,8 @@ std::string goalName(EGoals goalType)
 			return "GET OBJECT";
 		case FIND_OBJ:
 			return "FIND OBJECT";
+		case VISIT_HERO:
+			return "VISIT HERO";
 		case GET_ART_TYPE:
 			return "GET ARTIFACT OF TYPE";
 		case ISSUE_COMMAND:
@@ -359,12 +361,12 @@ ui64 evaluateDanger(crint3 tile, const CGHeroInstance *visitor)
 	if(const CGObjectInstance * dangerousObject = backOrNull(cb->getVisitableObjs(tile)))
 	{
 		objectDanger = evaluateDanger(dangerousObject); //unguarded objects can also be dangerous or unhandled
-		if (dangerousObject)
+		if (objectDanger)
 		{
 			//TODO: don't downcast objects AI shouldnt know about!
 			auto armedObj = dynamic_cast<const CArmedInstance*>(dangerousObject);
 			if(armedObj)
-				objectDanger *= fh->getTacticalAdvantage(visitor, armedObj);
+				objectDanger *= fh->getTacticalAdvantage(visitor, armedObj); //this line tends to go infinite for allied towns (?)
 		}
 	}
 
@@ -374,8 +376,6 @@ ui64 evaluateDanger(crint3 tile, const CGHeroInstance *visitor)
 
 	//TODO mozna odwiedzic blockvis nie ruszajac straznika
 	return std::max(objectDanger, guardDanger);
-
-	return 0;
 }
 
 ui64 evaluateDanger(const CGObjectInstance *obj)
@@ -647,9 +647,9 @@ void VCAI::heroExchangeStarted(si32 hero1, si32 hero2)
 
 	requestActionASAP([=]()
 	{
-		if (firstHero->getHeroStrength() > secondHero->getHeroStrength())
+		if (firstHero->getHeroStrength() > secondHero->getHeroStrength() && canGetArmy (firstHero, secondHero))
 			pickBestCreatures (firstHero, secondHero);
-		else
+		else if (canGetArmy (secondHero, firstHero))
 			pickBestCreatures (secondHero, firstHero);
 
 		completeGoal(CGoal(VISIT_HERO).sethero(firstHero)); //TODO: what if we were visited by other hero in the meantime?
@@ -721,6 +721,11 @@ void VCAI::showHillFortWindow(const CGObjectInstance *object, const CGHeroInstan
 {
 	NET_EVENT_HANDLER;
 	LOG_ENTRY;
+
+	requestActionASAP([=]()
+	{
+		makePossibleUpgrades(visitor);
+	});
 }
 
 void VCAI::playerBonusChanged(const Bonus &bonus, bool gain)
@@ -1111,6 +1116,36 @@ void VCAI::moveCreaturesToHero(const CGTownInstance * t)
 	}
 }
 
+bool VCAI::canGetArmy (const CGHeroInstance * h, const CGHeroInstance * source)
+{
+	int totalStacks = h->Slots().size() + source->Slots().size();
+	if (totalStacks > GameConstants::ARMY_SIZE)
+	{ //exchange stacks or move full stack
+		BOOST_FOREACH (auto slot, source->Slots())
+		{
+			if (h->getSlotFor(slot.second->type->idNumber)) //we can take full stack
+				return true;
+			BOOST_FOREACH (auto ourSlot, h->Slots())
+			{
+				if (slot.second->getPower() > ourSlot.second->getPower()) 
+					return true;
+			}
+		}
+	}
+	else //only exchange
+	{
+		BOOST_FOREACH (auto slot, source->Slots())
+		{
+			BOOST_FOREACH (auto ourSlot, h->Slots())
+			{
+				if (slot.second->getPower() > ourSlot.second->getPower()) 
+					return true;
+			}
+		}
+	}
+	return false;
+}
+
 void VCAI::pickBestCreatures(const CArmedInstance * army, const CArmedInstance * source)
 {
 	//TODO - what if source is a hero (the last stack problem) -> it'd good to create a single stack of weakest cre
@@ -1138,10 +1173,16 @@ void VCAI::pickBestCreatures(const CArmedInstance * army, const CArmedInstance *
 
 	//foreach best type -> iterate over slots in both armies and if it's the appropriate type, send it to the slot where it belongs
 	for (int i = 0; i < bestArmy.size(); i++) //i-th strongest creature type will go to i-th slot
+	{
+		if (source->needsLastStack() && source->Slots().size() <= 1)
+			break;
 		BOOST_FOREACH(auto armyPtr, armies)
 			for (int j = 0; j < GameConstants::ARMY_SIZE; j++)
+			{
 				if(armyPtr->getCreature(j) == bestArmy[i]  &&  (i != j || armyPtr != army)) //it's a searched creature not in dst slot
-						cb->mergeOrSwapStacks(armyPtr, army, j, i);
+					cb->mergeOrSwapStacks(armyPtr, army, j, i);
+			}
+	}
 
 	//TODO - having now strongest possible army, we may want to think about arranging stacks
 
@@ -3162,7 +3203,7 @@ TSubgoal CGoal::whatToDoToAchieve()
 					auto heroDummy = hero;
 					erase_if(otherHeroes, [heroDummy](const CGHeroInstance * h)
 					{
-						return (h == heroDummy.h || !ai->isAccessibleForHero(heroDummy->pos, h, true));
+						return (h == heroDummy.h || !ai->isAccessibleForHero(heroDummy->pos, h, true) || !ai->canGetArmy(heroDummy.h, h));
 					});
 					if (otherHeroes.size())
 					{
@@ -3375,8 +3416,11 @@ bool isWeeklyRevisitable (const CGObjectInstance * obj)
 		return true;
 	switch (obj->ID)
 	{
-		case Obj::STABLES: //any other potential visitable objects?
+		case Obj::STABLES:
+		case Obj::MAGIC_WELL:
+		case Obj::HILL_FORT:
 			return true;
+			break;
 		case Obj::BORDER_GATE:
 		case Obj::BORDERGUARD:
 			return (dynamic_cast <const CGKeys *>(obj))->wasMyColorVisited (ai->playerID); //FIXME: they could be revisited sooner than in a week
@@ -3425,6 +3469,16 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
 			return canRecruitCreatures;
 			break;
 		}
+		case Obj::HILL_FORT:
+		{	
+			BOOST_FOREACH (auto slot, h->Slots())
+			{
+				if (slot.second->type->upgrades.size())
+					return true; //TODO: check price?
+			}
+			return false;
+			break;
+		}
 		case Obj::MONOLITH1:
 		case Obj::MONOLITH2:
 		case Obj::MONOLITH3:
@@ -3451,6 +3505,9 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
 					return false;
 			}
 			break;
+		case Obj::MAGIC_WELL:
+			return h->mana < h->manaLimit();
+			break;
 	}
 
 	if (obj->wasVisited(*h)) //it must pointer to hero instance, heroPtr calls function wasVisited(ui8 player);

+ 4 - 1
AI/VCAI/VCAI.h

@@ -327,6 +327,7 @@ public:
 	void buildStructure(const CGTownInstance * t);
 	//void recruitCreatures(const CGTownInstance * t);
 	void recruitCreatures(const CGDwelling * d);
+	bool canGetArmy (const CGHeroInstance * h, const CGHeroInstance * source); //can we get any better stacks from other hero?
 	void pickBestCreatures(const CArmedInstance * army, const CArmedInstance * source); //called when we can't find a slot for new stack
 	void moveCreaturesToHero(const CGTownInstance * t);
 	bool goVisitObj(const CGObjectInstance * obj, HeroPtr h);
@@ -375,4 +376,6 @@ bool objWithID(const CGObjectInstance *obj)
 bool isBlockedBorderGate(int3 tileToHit);
 
 bool isWeeklyRevisitable (const CGObjectInstance * obj);
-bool shouldVisit (HeroPtr h, const CGObjectInstance * obj);
+bool shouldVisit (HeroPtr h, const CGObjectInstance * obj);
+
+void makePossibleUpgrades(const CArmedInstance *obj);

+ 2 - 0
lib/GameConstants.h

@@ -210,12 +210,14 @@ namespace Obj
 		DERELICT_SHIP = 24,
 		DRAGON_UTOPIA = 25,
 		GARRISON = 33,
+		HILL_FORT = 35,
 		LIBRARY_OF_ENLIGHTENMENT = 41,
 		MONOLITH1 = 43,
 		MONOLITH2 = 44,
 		MONOLITH3 = 45,
 		MAGIC_PLAINS1 = 46,
 		SCHOOL_OF_MAGIC = 47,
+		MAGIC_WELL = 49,
 		MINE = 53,
 		MONSTER = 54,
 		OBELISK = 57,