Example #1
0
TGoalVec CompleteQuest::missionResources() const
{
	TGoalVec solutions;

	auto heroes = cb->getHeroesInfo(); //TODO: choose best / free hero from among many possibilities?

	if(heroes.size())
	{
		if(q.quest->checkQuest(heroes.front())) //it doesn't matter which hero it is
		{
			return ai->ah->howToVisitObj(q.obj);
		}
		else
		{
			for(int i = 0; i < q.quest->m7resources.size(); ++i)
			{
				if(q.quest->m7resources[i])
					solutions.push_back(sptr(CollectRes(i, q.quest->m7resources[i])));
			}
		}
	}
	else
	{
		solutions.push_back(sptr(Goals::RecruitHero())); //FIXME: checkQuest requires any hero belonging to player :(
	}

	return solutions;
}
Example #2
0
File: Goals.cpp Project: szpak/vcmi
TGoalVec VisitTile::getAllPossibleSubgoals()
{
	assert(cb->isInTheMap(tile));

	TGoalVec ret;
	if (!cb->isVisible(tile))
		ret.push_back (sptr(Goals::Explore())); //what sense does it make?
	else
	{
		std::vector<const CGHeroInstance *> heroes;
		if (hero)
			heroes.push_back(hero.h); //use assigned hero if any
		else
			heroes = cb->getHeroesInfo(); //use most convenient hero

		for (auto h : heroes)
		{
			if (ai->isAccessibleForHero(tile, h))
				ret.push_back (sptr(Goals::VisitTile(tile).sethero(h)));
		}
		if (ai->canRecruitAnyHero())
			ret.push_back (sptr(Goals::RecruitHero()));
	}
	if (ret.empty())
	{
		auto obj = frontOrNull(cb->getVisitableObjs(tile));
		if (obj && obj->ID == Obj::HERO && obj->tempOwner == ai->playerID) //our own hero stands on that tile
			ret.push_back (sptr(Goals::VisitTile(tile).sethero(dynamic_cast<const CGHeroInstance *>(obj)).setisElementar(true)));
		else
			ret.push_back (sptr(Goals::ClearWayTo(tile)));
	}

	//important - at least one sub-goal must handle case which is impossible to fulfill (unreachable tile)
	return ret;
}
Example #3
0
TGoalVec ClearWayTo::getAllPossibleSubgoals()
{
	TGoalVec ret;
	for (auto h : cb->getHeroesInfo())
	{
		if ((hero && hero->visitablePos() == tile && hero == *h) || //we can't free the way ourselves
			h->visitablePos() == tile) //we are already on that tile! what does it mean?
			continue;

		SectorMap sm(h);

		int3 tileToHit = sm.firstTileToGet(hero ? hero : h, tile);
		//if our hero is trapped, make sure we request clearing the way from OUR perspective
		if (!tileToHit.valid())
			continue;

		if (isBlockedBorderGate(tileToHit))
		{	//FIXME: this way we'll not visit gate and activate quest :?
			ret.push_back  (sptr (Goals::FindObj (Obj::KEYMASTER, cb->getTile(tileToHit)->visitableObjects.back()->subID)));
		}

		auto topObj = cb->getTopObj(tileToHit);
		if(topObj)
		{
			if (topObj->ID == Obj::HERO && cb->getPlayerRelations(h->tempOwner, topObj->tempOwner) != PlayerRelations::ENEMIES)
				if (topObj != hero.get(true)) //the hero we wnat to free
					logAi->errorStream() << boost::format("%s stands in the way of %s") % topObj->getHoverText()  % h->getHoverText();
			if (topObj->ID == Obj::QUEST_GUARD || topObj->ID == Obj::BORDERGUARD)
			{
				if (shouldVisit(h, topObj))
				{
					//do NOT use VISIT_TILE, as tile with quets guard can't be visited
					ret.push_back (sptr (Goals::GetObj(topObj->id.getNum()).sethero(h)));
				}
				else
				{
					//TODO: we should be able to return apriopriate quest here (VCAI::striveToQuest)
					logAi->debugStream() << "Quest guard blocks the way to " + tile();
				}
			}
		}
		else
			ret.push_back (sptr (Goals::VisitTile(tileToHit).sethero(h)));
	}
	if (ai->canRecruitAnyHero())
		ret.push_back (sptr (Goals::RecruitHero()));

	if (ret.empty())
	{
		logAi->warnStream() << "There is no known way to clear the way to tile " + tile();
		throw goalFulfilledException (sptr(*this)); //make sure asigned hero gets unlocked
	}

	return ret;
}
Example #4
0
File: Goals.cpp Project: szpak/vcmi
TGoalVec Conquer::getAllPossibleSubgoals()
{
	TGoalVec ret;

	auto conquerable = [](const CGObjectInstance * obj) -> bool
	{
		if (cb->getPlayerRelations(ai->playerID, obj->tempOwner) == PlayerRelations::ENEMIES)
		{
			switch (obj->ID.num)
			{
				case Obj::TOWN:
				case Obj::HERO:
				case Obj::CREATURE_GENERATOR1:
				case Obj::MINE: //TODO: check ai->knownSubterraneanGates
					return true;
			}
		}
		return false;
	};

	std::vector<const CGObjectInstance *> objs;
	for (auto obj : ai->visitableObjs)
	{
		if (conquerable(obj)) 
			objs.push_back (obj);
	}

	for (auto h : cb->getHeroesInfo())
	{
		SectorMap sm(h);
		std::vector<const CGObjectInstance *> ourObjs(objs); //copy common objects

		for (auto obj : ai->reservedHeroesMap[h]) //add objects reserved by this hero
		{
			if (conquerable(obj))
				ourObjs.push_back(obj);
		}
		for (auto obj : ourObjs) //double loop, performance risk?
		{
			auto t = sm.firstTileToGet(h, obj->visitablePos()); //we assume that no more than one tile on the way is guarded
			if (ai->canReachTile(h, t))
				ret.push_back (sptr(Goals::ClearWayTo(obj->visitablePos(), h).setisAbstract(true)));
		}
	}
	if (!objs.empty() && ai->canRecruitAnyHero()) //probably no point to recruit hero if we see no objects to capture
		ret.push_back (sptr(Goals::RecruitHero()));

	if (ret.empty())
		ret.push_back (sptr(Goals::Explore())); //we need to find an enemy
	return ret;
}
Example #5
0
TGoalVec CompleteQuest::tryCompleteQuest() const
{
	TGoalVec solutions;

	auto heroes = cb->getHeroesInfo(); //TODO: choose best / free hero from among many possibilities?

	for(auto hero : heroes)
	{
		if(q.quest->checkQuest(hero))
		{
			vstd::concatenate(solutions, ai->ah->howToVisitObj(hero, ObjectIdRef(q.obj->id)));
		}
	}

	return solutions;
}
Example #6
0
TGoalVec VisitTile::getAllPossibleSubgoals()
{
	assert(cb->isInTheMap(tile));

	TGoalVec ret;
	if (!cb->isVisible(tile))
		ret.push_back (sptr(Goals::Explore())); //what sense does it make?
	else
	{
		std::vector<const CGHeroInstance *> heroes;
		if (hero)
			heroes.push_back(hero.h); //use assigned hero if any
		else
			heroes = cb->getHeroesInfo(); //use most convenient hero

		for (auto h : heroes)
		{
			if (ai->isAccessibleForHero(tile, h))
				ret.push_back (sptr(Goals::VisitTile(tile).sethero(h)));
		}
		if (ai->canRecruitAnyHero())
			ret.push_back (sptr(Goals::RecruitHero()));
	}
	if(ret.empty())
	{
		auto obj = vstd::frontOrNull(cb->getVisitableObjs(tile));
		if(obj && obj->ID == Obj::HERO && obj->tempOwner == ai->playerID) //our own hero stands on that tile
		{
			if (hero.get(true) && hero->id == obj->id) //if it's assigned hero, visit tile. If it's different hero, we can't visit tile now
				ret.push_back(sptr(Goals::VisitTile(tile).sethero(dynamic_cast<const CGHeroInstance *>(obj)).setisElementar(true)));
			else
				throw cannotFulfillGoalException("Tile is already occupied by another hero "); //FIXME: we should give up this tile earlier
		}
		else
			ret.push_back (sptr(Goals::ClearWayTo(tile)));
	}

	//important - at least one sub-goal must handle case which is impossible to fulfill (unreachable tile)
	return ret;
}
Example #7
0
TSubgoal GetObj::whatToDoToAchieve()
{
	const CGObjectInstance * obj = cb->getObj(ObjectInstanceID(objid));
	if(!obj)
		return sptr (Goals::Explore());
	if (obj->tempOwner == ai->playerID) //we can't capture our own object -> move to Win codition
		throw cannotFulfillGoalException("Cannot capture my own object " + obj->getObjectName());

	int3 pos = obj->visitablePos();
	if (hero)
	{
		if (ai->isAccessibleForHero(pos, hero))
			return sptr (Goals::VisitTile(pos).sethero(hero));
	}
	else
	{
		for (auto h : cb->getHeroesInfo())
		{
			if (ai->isAccessibleForHero(pos, h))
				return sptr(Goals::VisitTile(pos).sethero(h)); //we must visit object with same hero, if any
		}
	}
	return sptr (Goals::ClearWayTo(pos).sethero(hero));
}
Example #8
0
File: Goals.cpp Project: szpak/vcmi
TGoalVec GatherArmy::getAllPossibleSubgoals()
{
	//get all possible towns, heroes and dwellings we may use
	TGoalVec ret;
	
	//TODO: include evaluation of monsters gather in calculation
	for (auto t : cb->getTownsInfo())
	{
		auto pos = t->visitablePos();
		if (ai->isAccessibleForHero(pos, hero))
		{
			if(!t->visitingHero && howManyReinforcementsCanGet(hero,t))
			{
				if (!vstd::contains (ai->townVisitsThisWeek[hero], t))
					ret.push_back (sptr (Goals::VisitTile(pos).sethero(hero)));
			}
			auto bid = ai->canBuildAnyStructure(t, std::vector<BuildingID>
							(unitsSource, unitsSource + ARRAY_COUNT(unitsSource)), 8 - cb->getDate(Date::DAY_OF_WEEK));
			if (bid != BuildingID::NONE)
				ret.push_back (sptr(BuildThis(bid, t)));
		}
	}

	auto otherHeroes = cb->getHeroesInfo();
	auto heroDummy = hero;
	erase_if(otherHeroes, [heroDummy](const CGHeroInstance * h)
	{
		return (h == heroDummy.h || !ai->isAccessibleForHero(heroDummy->visitablePos(), h, true)
			|| !ai->canGetArmy(heroDummy.h, h) || ai->getGoal(h)->goalType == Goals::GATHER_ARMY);
	});
	for (auto h : otherHeroes)
	{
		ret.push_back (sptr (Goals::VisitHero(h->id.getNum()).setisAbstract(true).sethero(hero)));
				//go to the other hero if we are faster
		ret.push_back (sptr (Goals::VisitHero(hero->id.getNum()).setisAbstract(true).sethero(h)));
				//let the other hero come to us
	}

	std::vector <const CGObjectInstance *> objs;
	for (auto obj : ai->visitableObjs)
	{
		if(obj->ID == Obj::CREATURE_GENERATOR1)
		{
			auto relationToOwner = cb->getPlayerRelations(obj->getOwner(), ai->playerID);

			//Use flagged dwellings only when there are available creatures that we can afford
			if(relationToOwner == PlayerRelations::SAME_PLAYER)
			{
				auto dwelling = dynamic_cast<const CGDwelling*>(obj);
				for(auto & creLevel : dwelling->creatures)
				{
					if(creLevel.first)
					{
						for(auto & creatureID : creLevel.second)
						{
							auto creature = VLC->creh->creatures[creatureID];
							if (ai->freeResources().canAfford(creature->cost))
								objs.push_back(obj);
						}
					}
				}
			}
		}
	}
	for(auto h : cb->getHeroesInfo())
	{
		for (auto obj : objs)
		{ //find safe dwelling
			auto pos = obj->visitablePos();
			if (ai->isGoodForVisit(obj, h))
				ret.push_back (sptr (Goals::VisitTile(pos).sethero(h)));
		}
	}
	if (ai->canRecruitAnyHero()) //this is not stupid in early phase of game
		ret.push_back (sptr(Goals::RecruitHero()));

	if (ret.empty())
	{
		if (hero == ai->primaryHero() || value >= 1.1f)
			ret.push_back (sptr(Goals::Explore()));
		else //workaround to break loop - seemingly there are no ways to explore left
			throw goalFulfilledException (sptr(Goals::GatherArmy(0).sethero(hero)));
	}

	return ret;
}
Example #9
0
File: Goals.cpp Project: szpak/vcmi
TGoalVec Explore::getAllPossibleSubgoals()
{
	TGoalVec ret;
	std::vector<const CGHeroInstance *> heroes;

	if (hero)
		heroes.push_back(hero.h);
	else
	{
		//heroes = ai->getUnblockedHeroes();
		heroes = cb->getHeroesInfo();
		erase_if (heroes, [](const HeroPtr h)
		{
			if (ai->getGoal(h)->goalType == Goals::EXPLORE) //do not reassign hero who is already explorer
				return true;

			return !h->movement; //saves time, immobile heroes are useless anyway
		});
	}

	//try to use buildings that uncover map
	std::vector<const CGObjectInstance *> objs;
	for (auto obj : ai->visitableObjs)
	{
		if (!vstd::contains(ai->alreadyVisited, obj))
		{
			switch (obj->ID.num)
			{
				case Obj::REDWOOD_OBSERVATORY:
				case Obj::PILLAR_OF_FIRE:
				case Obj::CARTOGRAPHER:
				case Obj::SUBTERRANEAN_GATE: //TODO: check ai->knownSubterraneanGates
					objs.push_back (obj);
			}
		}
	}
	for (auto h : heroes)
	{
		SectorMap sm(h);

		for (auto obj : objs) //double loop, performance risk?
		{
			auto t = sm.firstTileToGet(h, obj->visitablePos()); //we assume that no more than one tile on the way is guarded
			if (ai->canReachTile(h, t))
				ret.push_back (sptr(Goals::ClearWayTo(obj->visitablePos(), h).setisAbstract(true)));
		}

		int3 t = whereToExplore(h);
		if (t.valid())
		{
			ret.push_back (sptr (Goals::VisitTile(t).sethero(h)));
		}
		else if (hero.h == h || (!hero && h == ai->primaryHero().h)) //check this only ONCE, high cost
		{
			t = ai->explorationDesperate(h);
			if (t.valid()) //don't waste time if we are completely blocked
				ret.push_back (sptr(Goals::ClearWayTo(t, h).setisAbstract(true)));
		}
	}
	//we either don't have hero yet or none of heroes can explore
	if ((!hero || ret.empty()) && ai->canRecruitAnyHero())
		ret.push_back (sptr(Goals::RecruitHero()));

	if (ret.empty())
	{
		throw goalFulfilledException (sptr(Goals::Explore().sethero(hero)));
	}
	//throw cannotFulfillGoalException("Cannot explore - no possible ways found!");

	return ret;
}
Example #10
0
File: Goals.cpp Project: szpak/vcmi
TGoalVec ClearWayTo::getAllPossibleSubgoals()
{
	TGoalVec ret;

	std::vector<const CGHeroInstance *> heroes;

	if (hero)
		heroes.push_back(hero.h);
	else
	{
		heroes = cb->getHeroesInfo();
	}

	for (auto h : heroes)
	{
		//TODO: handle clearing way to allied heroes that are blocked
		//if ((hero && hero->visitablePos() == tile && hero == *h) || //we can't free the way ourselves
		//	h->visitablePos() == tile) //we are already on that tile! what does it mean?
		//	continue;

		//if our hero is trapped, make sure we request clearing the way from OUR perspective

		SectorMap sm(h);

		int3 tileToHit = sm.firstTileToGet(h, tile);
		if (!tileToHit.valid())
			continue;

		if (isBlockedBorderGate(tileToHit))
		{	//FIXME: this way we'll not visit gate and activate quest :?
			ret.push_back  (sptr (Goals::FindObj (Obj::KEYMASTER, cb->getTile(tileToHit)->visitableObjects.back()->subID)));
		}

		auto topObj = cb->getTopObj(tileToHit);
		if (topObj)
		{
			if (vstd::contains(ai->reservedObjs, topObj) && !vstd::contains(ai->reservedHeroesMap[h], topObj))
			{
				throw goalFulfilledException (sptr(Goals::ClearWayTo(tile, h)));
				continue; //do not capure object reserved by other hero
			}

			if (topObj->ID == Obj::HERO && cb->getPlayerRelations(h->tempOwner, topObj->tempOwner) != PlayerRelations::ENEMIES)
				if (topObj != hero.get(true)) //the hero we want to free
					logAi->errorStream() << boost::format("%s stands in the way of %s") % topObj->getHoverText()  % h->getHoverText();
			if (topObj->ID == Obj::QUEST_GUARD || topObj->ID == Obj::BORDERGUARD)
			{
				if (shouldVisit(h, topObj))
				{
					//do NOT use VISIT_TILE, as tile with quets guard can't be visited
					ret.push_back (sptr (Goals::GetObj(topObj->id.getNum()).sethero(h)));
					continue; //do not try to visit tile or gather army
				}
				else
				{
					//TODO: we should be able to return apriopriate quest here (VCAI::striveToQuest)
					logAi->debugStream() << "Quest guard blocks the way to " + tile();
				}
			}
		}

		if (isSafeToVisit(h, tileToHit)) //this makes sense only if tile is guarded, but there i no quest object
		{
			ret.push_back (sptr (Goals::VisitTile(tileToHit).sethero(h)));
		}
		else
		{
			ret.push_back (sptr (Goals::GatherArmy(evaluateDanger(tileToHit, h)*SAFE_ATTACK_CONSTANT).
				sethero(h).setisAbstract(true)));
		}
	}
	if (ai->canRecruitAnyHero())
		ret.push_back (sptr (Goals::RecruitHero()));

	if (ret.empty())
	{
		logAi->warnStream() << "There is no known way to clear the way to tile " + tile();
		throw goalFulfilledException (sptr(Goals::ClearWayTo(tile))); //make sure asigned hero gets unlocked
	}

	return ret;
}
Example #11
0
TGoalVec Conquer::getAllPossibleSubgoals()
{
	TGoalVec ret;

	auto conquerable = [](const CGObjectInstance * obj) -> bool
	{
		if (cb->getPlayerRelations(ai->playerID, obj->tempOwner) == PlayerRelations::ENEMIES)
		{
			switch (obj->ID.num)
			{
				case Obj::TOWN:
				case Obj::HERO:
				case Obj::CREATURE_GENERATOR1:
				case Obj::MINE: //TODO: check ai->knownSubterraneanGates
					return true;
			}
		}
		return false;
	};

	std::vector<const CGObjectInstance *> objs;
	for (auto obj : ai->visitableObjs)
	{
		if (conquerable(obj))
			objs.push_back (obj);
	}

	for (auto h : cb->getHeroesInfo())
	{
		auto sm = ai->getCachedSectorMap(h);
		std::vector<const CGObjectInstance *> ourObjs(objs); //copy common objects

		for (auto obj : ai->reservedHeroesMap[h]) //add objects reserved by this hero
		{
			if (conquerable(obj))
				ourObjs.push_back(obj);
		}
		for (auto obj : ourObjs)
		{
			int3 dest = obj->visitablePos();
			auto t = sm->firstTileToGet(h, dest); //we assume that no more than one tile on the way is guarded
			if (t.valid()) //we know any path at all
			{
				if (ai->isTileNotReserved(h, t)) //no other hero wants to conquer that tile
				{
					if (isSafeToVisit(h, dest))
					{
						if (dest != t) //there is something blocking our way
							ret.push_back(sptr(Goals::ClearWayTo(dest, h).setisAbstract(true)));
						else
						{
							if (obj->ID.num == Obj::HERO) //enemy hero may move to other position
								ret.push_back(sptr(Goals::VisitHero(obj->id.getNum()).sethero(h).setisAbstract(true)));
							else //just visit that tile
								ret.push_back(sptr(Goals::VisitTile(dest).sethero(h).setisAbstract(true)));
						}
					}
					else //we need to get army in order to conquer that place
						ret.push_back(sptr(Goals::GatherArmy(evaluateDanger(dest, h) * SAFE_ATTACK_CONSTANT).sethero(h).setisAbstract(true)));
				}
			}
		}
	}
	if (!objs.empty() && ai->canRecruitAnyHero()) //probably no point to recruit hero if we see no objects to capture
		ret.push_back (sptr(Goals::RecruitHero()));

	if (ret.empty())
		ret.push_back (sptr(Goals::Explore())); //we need to find an enemy
	return ret;
}
Example #12
0
TSubgoal GatherTroops::whatToDoToAchieve()
{
	std::vector<const CGDwelling *> dwellings;
	for(const CGTownInstance *t : cb->getTownsInfo())
	{
		auto creature = VLC->creh->creatures[objid];
		if (t->subID == creature->faction) //TODO: how to force AI to build unupgraded creatures? :O
		{
			auto creatures = vstd::tryAt(t->town->creatures, creature->level - 1);
			if(!creatures)
				continue;

			int upgradeNumber = vstd::find_pos(*creatures, creature->idNumber);
			if(upgradeNumber < 0)
				continue;

			BuildingID bid(BuildingID::DWELL_FIRST + creature->level - 1 + upgradeNumber * GameConstants::CREATURES_PER_TOWN);
			if (t->hasBuilt(bid)) //this assumes only creatures with dwellings are assigned to faction
			{
				dwellings.push_back(t);
			}
			else
			{
				return sptr (Goals::BuildThis(bid, t));
			}
		}
	}
	for (auto obj : ai->visitableObjs)
	{
		if (obj->ID != Obj::CREATURE_GENERATOR1) //TODO: what with other creature generators?
			continue;

		auto d = dynamic_cast<const CGDwelling *>(obj);
		for (auto creature : d->creatures)
		{
			if (creature.first) //there are more than 0 creatures avaliabe
			{
				for (auto type : creature.second)
				{
					if (type == objid  &&  ai->freeResources().canAfford(VLC->creh->creatures[type]->cost))
						dwellings.push_back(d);
				}
			}
		}
	}
	if (dwellings.size())
	{
		typedef std::map<const CGHeroInstance *, const CGDwelling *> TDwellMap;

		// sorted helper
		auto comparator = [](const TDwellMap::value_type & a, const TDwellMap::value_type & b) -> bool
		{
			const CGPathNode *ln = ai->myCb->getPathsInfo(a.first)->getPathInfo(a.second->visitablePos()),
			                 *rn = ai->myCb->getPathsInfo(b.first)->getPathInfo(b.second->visitablePos());

			if(ln->turns != rn->turns)
				return ln->turns < rn->turns;

			return (ln->moveRemains > rn->moveRemains);
		};

		// for all owned heroes generate map <hero -> nearest dwelling>
		TDwellMap nearestDwellings;
		for (const CGHeroInstance * hero : cb->getHeroesInfo(true))
		{
			nearestDwellings[hero] = *boost::range::min_element(dwellings, CDistanceSorter(hero));
		}

		// find hero who is nearest to a dwelling
		const CGDwelling * nearest = boost::range::min_element(nearestDwellings, comparator)->second;

		return sptr (Goals::GetObj(nearest->id.getNum()));
	}
	else
		return sptr (Goals::Explore());
	//TODO: exchange troops between heroes
}
Example #13
0
TGoalVec Explore::getAllPossibleSubgoals()
{
	TGoalVec ret;
	std::vector<const CGHeroInstance *> heroes;

	if (hero)
		heroes.push_back(hero.h);
	else
	{
		//heroes = ai->getUnblockedHeroes();
		heroes = cb->getHeroesInfo();
		vstd::erase_if(heroes, [](const HeroPtr h)
		{
			if (ai->getGoal(h)->goalType == Goals::EXPLORE) //do not reassign hero who is already explorer
				return true;

			if (!ai->isAbleToExplore(h))
				return true;

			return !h->movement; //saves time, immobile heroes are useless anyway
		});
	}

	//try to use buildings that uncover map
	std::vector<const CGObjectInstance *> objs;
	for (auto obj : ai->visitableObjs)
	{
		if (!vstd::contains(ai->alreadyVisited, obj))
		{
			switch (obj->ID.num)
			{
			case Obj::REDWOOD_OBSERVATORY:
			case Obj::PILLAR_OF_FIRE:
			case Obj::CARTOGRAPHER:
				objs.push_back (obj);
				break;
			case Obj::MONOLITH_ONE_WAY_ENTRANCE:
			case Obj::MONOLITH_TWO_WAY:
			case Obj::SUBTERRANEAN_GATE:
				auto tObj = dynamic_cast<const CGTeleport *>(obj);
				assert(ai->knownTeleportChannels.find(tObj->channel) != ai->knownTeleportChannels.end());
				if(TeleportChannel::IMPASSABLE != ai->knownTeleportChannels[tObj->channel]->passability)
					objs.push_back (obj);
				break;
			}
		}
		else
		{
			switch (obj->ID.num)
			{
			case Obj::MONOLITH_TWO_WAY:
			case Obj::SUBTERRANEAN_GATE:
				auto tObj = dynamic_cast<const CGTeleport *>(obj);
				if(TeleportChannel::IMPASSABLE == ai->knownTeleportChannels[tObj->channel]->passability)
					break;
				for(auto exit : ai->knownTeleportChannels[tObj->channel]->exits)
				{
					if(!cb->getObj(exit))
					{ // Always attempt to visit two-way teleports if one of channel exits is not visible
						objs.push_back(obj);
						break;
					}
				}
				break;
			}
		}
	}

	for (auto h : heroes)
	{
		auto sm = ai->getCachedSectorMap(h);

		for (auto obj : objs) //double loop, performance risk?
		{
			auto t = sm->firstTileToGet(h, obj->visitablePos()); //we assume that no more than one tile on the way is guarded
			if (ai->isTileNotReserved(h, t))
				ret.push_back (sptr(Goals::ClearWayTo(obj->visitablePos(), h).setisAbstract(true)));
		}

		int3 t = whereToExplore(h);
		if (t.valid())
		{
			ret.push_back (sptr (Goals::VisitTile(t).sethero(h)));
		}
		else
		{
			ai->markHeroUnableToExplore (h); //there is no freely accessible tile, do not poll this hero anymore
			//possible issues when gathering army to break

			if (hero.h == h || (!hero && h == ai->primaryHero().h)) //check this only ONCE, high cost
			{
				t = ai->explorationDesperate(h);
				if (t.valid()) //don't waste time if we are completely blocked
					ret.push_back (sptr(Goals::ClearWayTo(t, h).setisAbstract(true)));
			}
		}
	}
	//we either don't have hero yet or none of heroes can explore
	if ((!hero || ret.empty()) && ai->canRecruitAnyHero())
		ret.push_back (sptr(Goals::RecruitHero()));

	if (ret.empty())
	{
		throw goalFulfilledException (sptr(Goals::Explore().sethero(hero)));
	}
	//throw cannotFulfillGoalException("Cannot explore - no possible ways found!");

	return ret;
}
Example #14
0
TGoalVec CollectRes::getAllPossibleSubgoals()
{
	TGoalVec ret;

	auto givesResource = [this](const CGObjectInstance * obj) -> bool
	{
		//TODO: move this logic to object side
		//TODO: remember mithril exists
		//TODO: water objects
		//TODO: Creature banks

		//return false first from once-visitable, before checking if they were even visited
		switch (obj->ID.num)
		{
		case Obj::TREASURE_CHEST:
			return resID == Res::GOLD;
			break;
		case Obj::RESOURCE:
			return obj->subID == resID;
			break;
		case Obj::MINE:
			return (obj->subID == resID &&
				(cb->getPlayerRelations(obj->tempOwner, ai->playerID) == PlayerRelations::ENEMIES)); //don't capture our mines
			break;
		case Obj::CAMPFIRE:
			return true; //contains all resources
			break;
		case Obj::WINDMILL:
			switch (resID)
			{
			case Res::GOLD:
			case Res::WOOD:
				return false;
			}
			break;
		case Obj::WATER_WHEEL:
			if (resID != Res::GOLD)
				return false;
			break;
		case Obj::MYSTICAL_GARDEN:
			if ((resID != Res::GOLD) && (resID != Res::GEMS))
				return false;
			break;
		case Obj::LEAN_TO:
		case Obj::WAGON:
			if (resID != Res::GOLD)
				return false;
			break;
		default:
			return false;
			break;
		}
		return !vstd::contains(ai->alreadyVisited, obj); //for weekly / once visitable
	};

	std::vector<const CGObjectInstance *> objs;
	for (auto obj : ai->visitableObjs)
	{
		if (givesResource(obj))
			objs.push_back(obj);
	}
	for (auto h : cb->getHeroesInfo())
	{
		std::vector<const CGObjectInstance *> ourObjs(objs); //copy common objects

		for (auto obj : ai->reservedHeroesMap[h]) //add objects reserved by this hero
		{
			if (givesResource(obj))
				ourObjs.push_back(obj);
		}

		for (auto obj : ourObjs)
		{
			auto waysToGo = ai->ah->howToVisitObj(h, ObjectIdRef(obj));

			vstd::concatenate(ret, waysToGo);
		}
	}
	return ret;
}
Example #15
0
TGoalVec GatherArmy::getAllPossibleSubgoals()
{
	//get all possible towns, heroes and dwellings we may use
	TGoalVec ret;

	if(!hero.validAndSet())
	{
		return ret;
	}

	//TODO: include evaluation of monsters gather in calculation
	for(auto t : cb->getTownsInfo())
	{
		auto waysToVisit = ai->ah->howToVisitObj(hero, t);

		if(waysToVisit.size())
		{
			//grab army from town
			if(!t->visitingHero && howManyReinforcementsCanGet(hero.get(), t))
			{
				if(!vstd::contains(ai->townVisitsThisWeek[hero], t))
					vstd::concatenate(ret, waysToVisit);
			}

			//buy army in town
			if (!t->visitingHero || t->visitingHero == hero.get(true))
			{
				std::vector<int> values = {
					value,
					(int)howManyReinforcementsCanBuy(t->getUpperArmy(), t),
					(int)howManyReinforcementsCanBuy(hero.get(), t) };

				int val = *std::min_element(values.begin(), values.end());

				if (val)
				{
					auto goal = sptr(BuyArmy(t, val).sethero(hero));

					if(!ai->ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice
						ret.push_back(goal);
					else
						logAi->debug("Can not buy army, because of ai->ah->containsObjective");
				}
			}
			//build dwelling
			//TODO: plan building over multiple turns?
			//auto bid = ah->canBuildAnyStructure(t, std::vector<BuildingID>(unitsSource, unitsSource + ARRAY_COUNT(unitsSource)), 8 - cb->getDate(Date::DAY_OF_WEEK));

			//Do not use below code for now, rely on generic Build. Code below needs to know a lot of town/resource context to do more good than harm
			/*auto bid = ai->ah->canBuildAnyStructure(t, std::vector<BuildingID>(unitsSource, unitsSource + ARRAY_COUNT(unitsSource)), 1);
			if (bid.is_initialized())
			{
				auto goal = sptr(BuildThis(bid.get(), t).setpriority(priority));
				if (!ai->ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice
					ret.push_back(goal);
				else
					logAi->debug("Can not build a structure, because of ai->ah->containsObjective");
			}*/
		}
	}

	auto otherHeroes = cb->getHeroesInfo();
	auto heroDummy = hero;
	vstd::erase_if(otherHeroes, [heroDummy](const CGHeroInstance * h)
	{
		if(h == heroDummy.h)
			return true;
		else if(!ai->isAccessibleForHero(heroDummy->visitablePos(), h, true))
			return true;
		else if(!ai->canGetArmy(heroDummy.h, h)) //TODO: return actual aiValue
			return true;
		else if(ai->getGoal(h)->goalType == GATHER_ARMY)
			return true;
		else
		   return false;
	});

	for(auto h : otherHeroes)
	{
		// Go to the other hero if we are faster
		if(!vstd::contains(ai->visitedHeroes[hero], h))
		{
			vstd::concatenate(ret, ai->ah->howToVisitObj(hero, h));
		}

		// Go to the other hero if we are faster
		if(!vstd::contains(ai->visitedHeroes[h], hero))
		{
			vstd::concatenate(ret, ai->ah->howToVisitObj(h, hero.get()));
		}
	}

	std::vector<const CGObjectInstance *> objs;
	for(auto obj : ai->visitableObjs)
	{
		if(obj->ID == Obj::CREATURE_GENERATOR1)
		{
			auto relationToOwner = cb->getPlayerRelations(obj->getOwner(), ai->playerID);

			//Use flagged dwellings only when there are available creatures that we can afford
			if(relationToOwner == PlayerRelations::SAME_PLAYER)
			{
				auto dwelling = dynamic_cast<const CGDwelling *>(obj);

				ui32 val = std::min<ui32>(value, howManyReinforcementsCanBuy(hero.get(), dwelling));

				if(val)
				{
					for(auto & creLevel : dwelling->creatures)
					{
						if(creLevel.first)
						{
							for(auto & creatureID : creLevel.second)
							{
								auto creature = VLC->creh->creatures[creatureID];
								if(ai->ah->freeResources().canAfford(creature->cost))
									objs.push_back(obj); //TODO: reserve resources?
							}
						}
					}
				}
			}
		}
	}

	for(auto h : cb->getHeroesInfo())
	{
		for(auto obj : objs)
		{
			//find safe dwelling
			if(ai->isGoodForVisit(obj, h))
			{
				vstd::concatenate(ret, ai->ah->howToVisitObj(h, obj));
			}
		}
	}

	if(ai->canRecruitAnyHero() && ai->ah->freeGold() > GameConstants::HERO_GOLD_COST) //this is not stupid in early phase of game
	{
		if(auto t = ai->findTownWithTavern())
		{
			for(auto h : cb->getAvailableHeroes(t)) //we assume that all towns have same set of heroes
			{
				if(h && h->getTotalStrength() > 500) //do not buy heroes with single creatures for GatherArmy
				{
					ret.push_back(sptr(RecruitHero()));
					break;
				}
			}
		}
	}

	if(ret.empty())
	{
		const bool allowGatherArmy = false;

		if(hero == ai->primaryHero())
			ret.push_back(sptr(Explore(allowGatherArmy)));
		else
			throw cannotFulfillGoalException("No ways to gather army");
	}

	return ret;
}