فهرست منبع

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

DjWarmonger 13 سال پیش
والد
کامیت
e913d94c62
2فایلهای تغییر یافته به همراه85 افزوده شده و 11 حذف شده
  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