mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
- A complete solutions for reserved adventure objects
- AI won't get stuck at School of War / School of Magic when no money
This commit is contained in:
parent
3cf4ebc163
commit
81367ef6d5
100
AI/VCAI/VCAI.cpp
100
AI/VCAI/VCAI.cpp
@ -555,6 +555,8 @@ void VCAI::heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visi
|
||||
{
|
||||
visitedObject = const_cast<CGObjectInstance *>(visitedObj); // remember the object and wait for return
|
||||
markObjectVisited (visitedObj);
|
||||
remove_if_present(reservedObjs, visitedObj); //unreserve objects
|
||||
remove_if_present(reservedHeroesMap[visitor], visitedObj);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1115,6 +1117,9 @@ std::vector<const CGObjectInstance *> VCAI::getPossibleDestinations(const CGHero
|
||||
if (!shouldVisit(h, obj))
|
||||
return true;
|
||||
|
||||
if (vstd::contains(reservedObjs, obj)) //does checking for our own reserved objects make sense? here?
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}),possibleDestinations.end());
|
||||
|
||||
@ -1125,18 +1130,74 @@ void VCAI::wander(const CGHeroInstance * h)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
auto dests = getPossibleDestinations(h);
|
||||
std::vector <const CGObjectInstance *> dests (reservedHeroesMap[h].begin(), reservedHeroesMap[h].end()); //copy constructor
|
||||
if (!dests.size())
|
||||
dests = getPossibleDestinations(h);
|
||||
if(!dests.size())
|
||||
{
|
||||
PNLOG("Nowhere more to go...\n");
|
||||
setGoal (h, INVALID);
|
||||
auto compareReinforcements = [h](const CGTownInstance *lhs, const CGTownInstance *rhs) -> bool
|
||||
{
|
||||
return howManyReinforcementsCanGet(h, lhs) < howManyReinforcementsCanGet(h, rhs);
|
||||
};
|
||||
|
||||
std::vector<const CGTownInstance *> townsReachable;
|
||||
std::vector<const CGTownInstance *> townsNotReachable;
|
||||
BOOST_FOREACH(const CGTownInstance *t, cb->getTownsInfo())
|
||||
{
|
||||
if(!t->visitingHero && howManyReinforcementsCanGet(h,t) && !vstd::contains(townVisitsThisWeek[h], t))
|
||||
{
|
||||
if(isReachable(t))
|
||||
townsReachable.push_back(t);
|
||||
else
|
||||
townsNotReachable.push_back(t);
|
||||
}
|
||||
}
|
||||
if(townsReachable.size())
|
||||
{
|
||||
boost::sort(townsReachable, compareReinforcements);
|
||||
dests.push_back(townsReachable.back());
|
||||
}
|
||||
else if(townsNotReachable.size())
|
||||
{
|
||||
boost::sort(townsNotReachable, compareReinforcements);
|
||||
//TODO pick the truly best
|
||||
const CGTownInstance *t = townsNotReachable.back();
|
||||
BNLOG("%s can't reach any town, we'll try to make our way to %s at %s", h->name % t->name % t->visitablePos());
|
||||
int3 pos1 = h->pos;
|
||||
striveToGoal(CGoal(CLEAR_WAY_TO).settile(t->visitablePos()).sethero(h));
|
||||
if (pos1 == h->pos && h == primaryHero()) //hero can't move
|
||||
{
|
||||
if(cb->getResourceAmount(Res::GOLD) >= HERO_GOLD_COST && cb->getHeroesInfo().size() < ALLOWED_ROAMING_HEROES && cb->getAvailableHeroes(t).size())
|
||||
recruitHero(t);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if(cb->getResourceAmount(Res::GOLD) >= HERO_GOLD_COST)
|
||||
{
|
||||
std::vector<const CGTownInstance *> towns = cb->getTownsInfo();
|
||||
erase_if(towns, [](const CGTownInstance *t) -> bool
|
||||
{
|
||||
BOOST_FOREACH(const CGHeroInstance *h, cb->getHeroesInfo())
|
||||
if(!t->getArmyStrength() || howManyReinforcementsCanGet(h, t))
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
boost::sort(towns, compareArmyStrength);
|
||||
if(towns.size())
|
||||
recruitHero(towns.back());
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
PNLOG("Nowhere more to go...\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
const CGObjectInstance * obj = dests.front();
|
||||
if(!goVisitObj(obj, h))
|
||||
{
|
||||
BNLOG("Hero %s apparently used all MPs (%d left)\n", h->name % h->movement);
|
||||
markObjectVisited(obj); //reserve that object - we predict it will be reached soon
|
||||
reserveObject(h, obj); //reserve that object - we predict it will be reached soon
|
||||
setGoal(h, CGoal(VISIT_TILE).sethero(h).settile(obj->visitablePos()));
|
||||
break;
|
||||
}
|
||||
@ -1194,6 +1255,12 @@ void VCAI::markObjectVisited (const CGObjectInstance *obj)
|
||||
alreadyVisited.push_back(obj);
|
||||
}
|
||||
|
||||
void VCAI::reserveObject (const CGHeroInstance * h, const CGObjectInstance *obj)
|
||||
{
|
||||
reservedObjs.push_back(obj);
|
||||
reservedHeroesMap[h].insert(obj);
|
||||
}
|
||||
|
||||
void VCAI::validateVisitableObjs()
|
||||
{
|
||||
std::vector<const CGObjectInstance *> hlp;
|
||||
@ -1355,9 +1422,15 @@ bool VCAI::moveHeroToTile(int3 dst, const CGHeroInstance * h)
|
||||
cb->moveHero(h,CGHeroInstance::convertPosition(endpos, true));
|
||||
waitTillFree(); //movement may cause battle or blocking dialog
|
||||
boost::this_thread::interruption_point();
|
||||
if(h->tempOwner != playerID) //we lost hero
|
||||
if(h->tempOwner != playerID) //we lost hero - remove all tasks assigned to him/her
|
||||
{
|
||||
remove_if_present(lockedHeroes, h);
|
||||
BOOST_FOREACH (auto obj, reservedHeroesMap[h])
|
||||
{
|
||||
remove_if_present(reservedObjs, obj); //unreserve all objects for that hero
|
||||
}
|
||||
remove_if_present(reservedHeroesMap, h);
|
||||
|
||||
throw std::runtime_error("Hero was lost!"); //we need to throw, otherwise hero will be assigned to sth again
|
||||
break;
|
||||
}
|
||||
@ -1366,7 +1439,9 @@ bool VCAI::moveHeroToTile(int3 dst, const CGHeroInstance * h)
|
||||
ret = !i;
|
||||
}
|
||||
if (visitedObject) //we step into something interesting
|
||||
{
|
||||
performObjectInteraction (visitedObject, h);
|
||||
}
|
||||
|
||||
if(h->tempOwner == playerID) //lost hero after last move
|
||||
cb->recalculatePaths();
|
||||
@ -2524,8 +2599,6 @@ bool isWeeklyRevisitable (const CGObjectInstance * obj)
|
||||
|
||||
bool shouldVisit (const CGHeroInstance * h, const CGObjectInstance * obj)
|
||||
{
|
||||
if (obj->wasVisited(h))
|
||||
return false;
|
||||
switch (obj->ID)
|
||||
{
|
||||
case Obj::CREATURE_GENERATOR1:
|
||||
@ -2548,7 +2621,20 @@ bool shouldVisit (const CGHeroInstance * h, const CGObjectInstance * obj)
|
||||
case Obj::WHIRLPOOL:
|
||||
//TODO: mehcanism for handling monoliths
|
||||
return false;
|
||||
case Obj::SCHOOL_OF_MAGIC:
|
||||
case Obj::SCHOOL_OF_WAR:
|
||||
{
|
||||
TResources myRes = ai->myCb->getResourceAmount();
|
||||
if (myRes[Res::GOLD] - GOLD_RESERVE < 1000)
|
||||
return false;
|
||||
}
|
||||
case Obj::LIBRARY_OF_ENLIGHTENMENT:
|
||||
return h->level >= 12;
|
||||
}
|
||||
|
||||
if (obj->wasVisited(h))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -157,9 +157,11 @@ public:
|
||||
std::map<const CGHeroInstance *, std::vector<const CGTownInstance *> > townVisitsThisWeek;
|
||||
|
||||
std::map<const CGHeroInstance *, CGoal> lockedHeroes; //TODO: allow non-elementar objectives
|
||||
std::map<const CGHeroInstance *, std::set<const CGObjectInstance *> > reservedHeroesMap; //objects reserved by specific heroes
|
||||
|
||||
std::vector<const CGObjectInstance *> visitableObjs;
|
||||
std::vector<const CGObjectInstance *> alreadyVisited;
|
||||
std::vector<const CGObjectInstance *> reservedObjs; //to be visited by specific hero
|
||||
|
||||
TResources saving;
|
||||
|
||||
@ -266,6 +268,7 @@ public:
|
||||
|
||||
void addVisitableObj(const CGObjectInstance *obj);
|
||||
void markObjectVisited (const CGObjectInstance *obj);
|
||||
void reserveObject (const CGHeroInstance * h, const CGObjectInstance *obj);
|
||||
//void removeVisitableObj(const CGObjectInstance *obj);
|
||||
void validateVisitableObjs();
|
||||
void retreiveVisitableObjs(std::vector<const CGObjectInstance *> &out, bool includeOwned = false) const;
|
||||
|
@ -180,9 +180,11 @@ namespace Obj
|
||||
DERELICT_SHIP = 24,
|
||||
DRAGON_UTOPIA = 25,
|
||||
GARRISON = 33,
|
||||
LIBRARY_OF_ENLIGHTENMENT = 41,
|
||||
MONOLITH1 = 43,
|
||||
MONOLITH2 = 44,
|
||||
MONOLITH3 = 45,
|
||||
SCHOOL_OF_MAGIC = 47,
|
||||
MINE = 53,
|
||||
MONSTER = 54,
|
||||
OBELISK = 57,
|
||||
@ -192,6 +194,7 @@ namespace Obj
|
||||
STABLES = 94,
|
||||
TRADING_POST = 99,
|
||||
SUBTERRANEAN_GATE = 103,
|
||||
SCHOOL_OF_WAR = 107,
|
||||
WHIRLPOOL = 111,
|
||||
BORDER_GATE = 212,
|
||||
GARRISON2 = 219,
|
||||
|
Loading…
Reference in New Issue
Block a user