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
102
AI/VCAI/VCAI.cpp
102
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
|
visitedObject = const_cast<CGObjectInstance *>(visitedObj); // remember the object and wait for return
|
||||||
markObjectVisited (visitedObj);
|
markObjectVisited (visitedObj);
|
||||||
|
remove_if_present(reservedObjs, visitedObj); //unreserve objects
|
||||||
|
remove_if_present(reservedHeroesMap[visitor], visitedObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1114,6 +1116,9 @@ std::vector<const CGObjectInstance *> VCAI::getPossibleDestinations(const CGHero
|
|||||||
|
|
||||||
if (!shouldVisit(h, obj))
|
if (!shouldVisit(h, obj))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (vstd::contains(reservedObjs, obj)) //does checking for our own reserved objects make sense? here?
|
||||||
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}),possibleDestinations.end());
|
}),possibleDestinations.end());
|
||||||
@ -1125,18 +1130,74 @@ void VCAI::wander(const CGHeroInstance * h)
|
|||||||
{
|
{
|
||||||
while(1)
|
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())
|
if(!dests.size())
|
||||||
{
|
{
|
||||||
PNLOG("Nowhere more to go...\n");
|
auto compareReinforcements = [h](const CGTownInstance *lhs, const CGTownInstance *rhs) -> bool
|
||||||
setGoal (h, INVALID);
|
{
|
||||||
break;
|
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();
|
const CGObjectInstance * obj = dests.front();
|
||||||
if(!goVisitObj(obj, h))
|
if(!goVisitObj(obj, h))
|
||||||
{
|
{
|
||||||
BNLOG("Hero %s apparently used all MPs (%d left)\n", h->name % h->movement);
|
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()));
|
setGoal(h, CGoal(VISIT_TILE).sethero(h).settile(obj->visitablePos()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1194,6 +1255,12 @@ void VCAI::markObjectVisited (const CGObjectInstance *obj)
|
|||||||
alreadyVisited.push_back(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()
|
void VCAI::validateVisitableObjs()
|
||||||
{
|
{
|
||||||
std::vector<const CGObjectInstance *> hlp;
|
std::vector<const CGObjectInstance *> hlp;
|
||||||
@ -1355,9 +1422,15 @@ bool VCAI::moveHeroToTile(int3 dst, const CGHeroInstance * h)
|
|||||||
cb->moveHero(h,CGHeroInstance::convertPosition(endpos, true));
|
cb->moveHero(h,CGHeroInstance::convertPosition(endpos, true));
|
||||||
waitTillFree(); //movement may cause battle or blocking dialog
|
waitTillFree(); //movement may cause battle or blocking dialog
|
||||||
boost::this_thread::interruption_point();
|
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);
|
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
|
throw std::runtime_error("Hero was lost!"); //we need to throw, otherwise hero will be assigned to sth again
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1366,7 +1439,9 @@ bool VCAI::moveHeroToTile(int3 dst, const CGHeroInstance * h)
|
|||||||
ret = !i;
|
ret = !i;
|
||||||
}
|
}
|
||||||
if (visitedObject) //we step into something interesting
|
if (visitedObject) //we step into something interesting
|
||||||
|
{
|
||||||
performObjectInteraction (visitedObject, h);
|
performObjectInteraction (visitedObject, h);
|
||||||
|
}
|
||||||
|
|
||||||
if(h->tempOwner == playerID) //lost hero after last move
|
if(h->tempOwner == playerID) //lost hero after last move
|
||||||
cb->recalculatePaths();
|
cb->recalculatePaths();
|
||||||
@ -2524,8 +2599,6 @@ bool isWeeklyRevisitable (const CGObjectInstance * obj)
|
|||||||
|
|
||||||
bool shouldVisit (const CGHeroInstance * h, const CGObjectInstance * obj)
|
bool shouldVisit (const CGHeroInstance * h, const CGObjectInstance * obj)
|
||||||
{
|
{
|
||||||
if (obj->wasVisited(h))
|
|
||||||
return false;
|
|
||||||
switch (obj->ID)
|
switch (obj->ID)
|
||||||
{
|
{
|
||||||
case Obj::CREATURE_GENERATOR1:
|
case Obj::CREATURE_GENERATOR1:
|
||||||
@ -2548,7 +2621,20 @@ bool shouldVisit (const CGHeroInstance * h, const CGObjectInstance * obj)
|
|||||||
case Obj::WHIRLPOOL:
|
case Obj::WHIRLPOOL:
|
||||||
//TODO: mehcanism for handling monoliths
|
//TODO: mehcanism for handling monoliths
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,9 +157,11 @@ public:
|
|||||||
std::map<const CGHeroInstance *, std::vector<const CGTownInstance *> > townVisitsThisWeek;
|
std::map<const CGHeroInstance *, std::vector<const CGTownInstance *> > townVisitsThisWeek;
|
||||||
|
|
||||||
std::map<const CGHeroInstance *, CGoal> lockedHeroes; //TODO: allow non-elementar objectives
|
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 *> visitableObjs;
|
||||||
std::vector<const CGObjectInstance *> alreadyVisited;
|
std::vector<const CGObjectInstance *> alreadyVisited;
|
||||||
|
std::vector<const CGObjectInstance *> reservedObjs; //to be visited by specific hero
|
||||||
|
|
||||||
TResources saving;
|
TResources saving;
|
||||||
|
|
||||||
@ -266,6 +268,7 @@ public:
|
|||||||
|
|
||||||
void addVisitableObj(const CGObjectInstance *obj);
|
void addVisitableObj(const CGObjectInstance *obj);
|
||||||
void markObjectVisited (const CGObjectInstance *obj);
|
void markObjectVisited (const CGObjectInstance *obj);
|
||||||
|
void reserveObject (const CGHeroInstance * h, const CGObjectInstance *obj);
|
||||||
//void removeVisitableObj(const CGObjectInstance *obj);
|
//void removeVisitableObj(const CGObjectInstance *obj);
|
||||||
void validateVisitableObjs();
|
void validateVisitableObjs();
|
||||||
void retreiveVisitableObjs(std::vector<const CGObjectInstance *> &out, bool includeOwned = false) const;
|
void retreiveVisitableObjs(std::vector<const CGObjectInstance *> &out, bool includeOwned = false) const;
|
||||||
|
@ -180,9 +180,11 @@ namespace Obj
|
|||||||
DERELICT_SHIP = 24,
|
DERELICT_SHIP = 24,
|
||||||
DRAGON_UTOPIA = 25,
|
DRAGON_UTOPIA = 25,
|
||||||
GARRISON = 33,
|
GARRISON = 33,
|
||||||
|
LIBRARY_OF_ENLIGHTENMENT = 41,
|
||||||
MONOLITH1 = 43,
|
MONOLITH1 = 43,
|
||||||
MONOLITH2 = 44,
|
MONOLITH2 = 44,
|
||||||
MONOLITH3 = 45,
|
MONOLITH3 = 45,
|
||||||
|
SCHOOL_OF_MAGIC = 47,
|
||||||
MINE = 53,
|
MINE = 53,
|
||||||
MONSTER = 54,
|
MONSTER = 54,
|
||||||
OBELISK = 57,
|
OBELISK = 57,
|
||||||
@ -192,6 +194,7 @@ namespace Obj
|
|||||||
STABLES = 94,
|
STABLES = 94,
|
||||||
TRADING_POST = 99,
|
TRADING_POST = 99,
|
||||||
SUBTERRANEAN_GATE = 103,
|
SUBTERRANEAN_GATE = 103,
|
||||||
|
SCHOOL_OF_WAR = 107,
|
||||||
WHIRLPOOL = 111,
|
WHIRLPOOL = 111,
|
||||||
BORDER_GATE = 212,
|
BORDER_GATE = 212,
|
||||||
GARRISON2 = 219,
|
GARRISON2 = 219,
|
||||||
|
Loading…
Reference in New Issue
Block a user