Browse Source

VCAI can now exchange armies between heroes. By default, it will pass army to main hero.

DjWarmonger 13 years ago
parent
commit
e913d94c62
2 changed files with 85 additions and 11 deletions
  1. 84 8
      AI/VCAI/VCAI.cpp
  2. 1 3
      AI/VCAI/VCAI.h

+ 84 - 8
AI/VCAI/VCAI.cpp

@@ -641,6 +641,21 @@ void VCAI::heroExchangeStarted(si32 hero1, si32 hero2)
 {
 	NET_EVENT_HANDLER;
 	LOG_ENTRY;
+
+	auto firstHero = cb->getHero(hero1);
+	auto secondHero = cb->getHero(hero2);
+
+	requestActionASAP([=]()
+	{
+		if (firstHero->getHeroStrength() > secondHero->getHeroStrength())
+			pickBestCreatures (firstHero, secondHero);
+		else
+			pickBestCreatures (secondHero, firstHero);
+
+		completeGoal(CGoal(VISIT_HERO).sethero(firstHero)); //TODO: what if we were visited by other hero in the meantime?
+		completeGoal(CGoal(VISIT_HERO).sethero(secondHero));
+		//TODO: exchange artifacts
+	});
 }
 
 void VCAI::heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val)
@@ -1815,6 +1830,16 @@ void VCAI::tryRealize(CGoal g)
 			//	throw cannotFulfillGoalException("There's a blocked gate!, we should never be here"); //CLEAR_WAY_TO should get keymaster tent
 		}
 		break;
+	case VISIT_HERO:
+		{
+			if(!g.hero->movement)
+				throw cannotFulfillGoalException("Cannot visit tile: hero is out of MPs!");
+			if (ai->moveHeroToTile(g.tile, g.hero.get()))
+			{
+				throw goalFulfilledException("");
+			}
+		}
+		break;
 	case BUILD_STRUCTURE:
 		{
 			const CGTownInstance *t = g.town;
@@ -1844,7 +1869,7 @@ void VCAI::tryRealize(CGoal g)
 			throw cannotFulfillGoalException("Cannot build a given structure!");
 		}
 		break;
-		case DIG_AT_TILE:
+	case DIG_AT_TILE:
 		{
 			assert(g.hero->visitablePos() == g.tile);
 			if (g.hero->diggingStatus() == CGHeroInstance::CAN_DIG)
@@ -2742,6 +2767,17 @@ TSubgoal CGoal::whatToDoToAchieve()
 			return CGoal(VISIT_TILE).settile(pos);
 		}
 		break;
+	case VISIT_HERO:
+		{
+			const CGObjectInstance * obj = cb->getObj(objid);
+			if(!obj)
+				return CGoal(EXPLORE);
+			int3 pos = cb->getObj(objid)->visitablePos();
+
+			if (hero && ai->isAccessibleForHero(obj->pos, hero, true))
+				return CGoal(*this).settile(pos).setisElementar(true);
+		}
+		break;
 	case GET_ART_TYPE:
 		{
 			TSubgoal alternativeWay = CGoal::lookForArtSmart(aid); //TODO: use
@@ -3120,22 +3156,61 @@ TSubgoal CGoal::whatToDoToAchieve()
 			}
 			else
 			{
+				if (hero == ai->primaryHero()) //we can get army from other heroes
+				{
+					auto otherHeroes = cb->getHeroesInfo();
+					auto heroDummy = hero;
+					erase_if(otherHeroes, [heroDummy](const CGHeroInstance * h)
+					{
+						return (h == heroDummy.h || !ai->isAccessibleForHero(heroDummy->pos, h, true));
+					});
+					if (otherHeroes.size())
+					{
+						boost::sort(otherHeroes, compareArmyStrength); //TODO:  check if hero has at least one stack more powerful than ours? not likely to fail
+						int primaryPath, secondaryPath;
+						auto h = otherHeroes.back();
+						cb->setSelection(hero.h);
+							primaryPath = cb->getPathInfo(h->pos)->turns;
+						cb->setSelection(h);
+							secondaryPath = cb->getPathInfo(hero->pos)->turns;
+
+						if (primaryPath < secondaryPath)
+							return CGoal(VISIT_HERO).setisAbstract(true).setobjid(h->id).sethero(hero); //go to the other hero if we are faster
+						else
+							return CGoal(VISIT_HERO).setisAbstract(true).setobjid(hero->id).sethero(h); //let the other hero come to us
+					}
+				}
+
 				std::vector<const CGObjectInstance *> objs; //here we'll gather all dwellings
 				ai->retreiveVisitableObjs(objs);
 				erase_if(objs, [&](const CGObjectInstance *obj)
 				{
-					return (obj->ID != Obj::CREATURE_GENERATOR1); //not town/ dwelling
+					return (obj->ID != Obj::CREATURE_GENERATOR1);
 				});
 				if(objs.empty()) //no possible objects, we did eveyrthing already
 					return CGoal(EXPLORE).sethero(hero);
 				//TODO: check if we can recruit any creatures there, evaluate army
 
-				boost::sort(objs, isCloser);
-				BOOST_FOREACH(const CGObjectInstance *obj, objs)
-				{ //find safe dwelling
-					auto pos = obj->visitablePos();
-					if (isSafeToVisit(hero, pos) && ai->isAccessibleForHero(pos, hero)) //TODO: make use of multiple heroes
-						return CGoal(VISIT_TILE).sethero(hero).settile(pos);
+				if (objs.size())
+				{
+					boost::sort(objs, isCloser);
+					HeroPtr h = NULL;
+					BOOST_FOREACH(const CGObjectInstance *obj, objs)
+					{ //find safe dwelling
+						auto pos = obj->visitablePos();
+						if (shouldVisit (hero, obj)) //creatures fit in army
+							h = hero;
+						else
+						{
+							BOOST_FOREACH(auto ourHero, cb->getHeroesInfo()) //make use of multiple heroes
+							{
+								if (shouldVisit(ourHero, obj))
+									h = ourHero;
+							}
+						}
+						if (h && isSafeToVisit(h, pos) && ai->isAccessibleForHero(pos, h))
+							return CGoal(VISIT_TILE).sethero(h).settile(pos);
+					}
 				}
 			}
 
@@ -3319,6 +3394,7 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
 		case Obj::SEER_HUT:
 		case Obj::QUEST_GUARD:
 		{
+			return false; //fixme: avoid crash
 			BOOST_FOREACH (auto q, ai->myCb->getMyQuests())
 			{
 				if (q.obj == obj)

+ 1 - 3
AI/VCAI/VCAI.h

@@ -78,15 +78,13 @@ enum EGoals
 	OBJECT_GOALS_BEGIN,
 	GET_OBJ, //visit or defeat or collect the object
 	FIND_OBJ, //find and visit any obj with objid + resid //TODO: consider universal subid for various types (aid, bid)
+	VISIT_HERO, //heroes can move around - set goal abstract and track hero every turn
 
 	GET_ART_TYPE,
 
 	//BUILD_STRUCTURE,
 	ISSUE_COMMAND,
 
-	//hero
-	//VISIT_OBJ, //hero + tile
-
 	VISIT_TILE, //tile, in conjunction with hero elementar; assumes tile is reachable
 	CLEAR_WAY_TO,
 	DIG_AT_TILE //elementar with hero on tile