From 81367ef6d54eeea6a01212c9932dec1ffdcedbf7 Mon Sep 17 00:00:00 2001 From: DjWarmonger Date: Thu, 29 Mar 2012 18:26:06 +0000 Subject: [PATCH] - A complete solutions for reserved adventure objects - AI won't get stuck at School of War / School of Magic when no money --- AI/VCAI/VCAI.cpp | 102 ++++++++++++++++++++++++++++++++++++++++---- AI/VCAI/VCAI.h | 3 ++ lib/GameConstants.h | 3 ++ 3 files changed, 100 insertions(+), 8 deletions(-) diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index 0d25cc4dc..81b263fcb 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -555,6 +555,8 @@ void VCAI::heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visi { visitedObject = const_cast(visitedObj); // remember the object and wait for return markObjectVisited (visitedObj); + remove_if_present(reservedObjs, visitedObj); //unreserve objects + remove_if_present(reservedHeroesMap[visitor], visitedObj); } } @@ -1114,6 +1116,9 @@ std::vector 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 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); - break; + auto compareReinforcements = [h](const CGTownInstance *lhs, const CGTownInstance *rhs) -> bool + { + return howManyReinforcementsCanGet(h, lhs) < howManyReinforcementsCanGet(h, rhs); + }; + + std::vector townsReachable; + std::vector 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 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 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; } diff --git a/AI/VCAI/VCAI.h b/AI/VCAI/VCAI.h index 1e603b7d5..b777a98aa 100644 --- a/AI/VCAI/VCAI.h +++ b/AI/VCAI/VCAI.h @@ -157,9 +157,11 @@ public: std::map > townVisitsThisWeek; std::map lockedHeroes; //TODO: allow non-elementar objectives + std::map > reservedHeroesMap; //objects reserved by specific heroes std::vector visitableObjs; std::vector alreadyVisited; + std::vector 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 &out, bool includeOwned = false) const; diff --git a/lib/GameConstants.h b/lib/GameConstants.h index 372108df1..ad0f4892f 100644 --- a/lib/GameConstants.h +++ b/lib/GameConstants.h @@ -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,