mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-24 03:47:18 +02:00
AI: GATHER_TROOPS improvements and fixes
This commit is contained in:
parent
614cde4a55
commit
60c5f584a8
@ -137,7 +137,7 @@ bool Goals::GatherArmy::operator==(const GatherArmy & other) const
|
||||
|
||||
bool Goals::BuyArmy::operator==(const BuyArmy & other) const
|
||||
{
|
||||
return town == other.town;
|
||||
return town == other.town && objid == other.objid;
|
||||
}
|
||||
|
||||
bool Goals::BoostHero::operator==(const BoostHero & other) const
|
||||
@ -1219,11 +1219,58 @@ bool CollectRes::fulfillsMe(TSubgoal goal)
|
||||
return false;
|
||||
}
|
||||
|
||||
int GatherTroops::getCreaturesCount(const CArmedInstance * army)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for(auto stack : army->Slots())
|
||||
{
|
||||
if(objid == stack.second->getCreatureID().num)
|
||||
{
|
||||
count += stack.second->count;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
TSubgoal GatherTroops::whatToDoToAchieve()
|
||||
{
|
||||
std::vector<const CGDwelling *> dwellings;
|
||||
auto heroes = cb->getHeroesInfo(true);
|
||||
|
||||
for(auto hero : heroes)
|
||||
{
|
||||
if(getCreaturesCount(hero) >= this->value)
|
||||
{
|
||||
logAi->trace("Completing GATHER_TROOPS by hero %s", hero->name);
|
||||
|
||||
throw goalFulfilledException(sptr(*this));
|
||||
}
|
||||
}
|
||||
|
||||
TGoalVec solutions = getAllPossibleSubgoals();
|
||||
|
||||
if(solutions.empty())
|
||||
return sptr(Goals::Explore());
|
||||
|
||||
return fh->chooseSolution(solutions);
|
||||
}
|
||||
|
||||
|
||||
TGoalVec GatherTroops::getAllPossibleSubgoals()
|
||||
{
|
||||
TGoalVec solutions;
|
||||
|
||||
for(const CGTownInstance * t : cb->getTownsInfo())
|
||||
{
|
||||
int count = getCreaturesCount(t->getUpperArmy());
|
||||
|
||||
if(count >= this->value)
|
||||
{
|
||||
vstd::concatenate(solutions, ai->ah->howToVisitObj(t));
|
||||
continue;
|
||||
}
|
||||
|
||||
auto creature = VLC->creh->creatures[objid];
|
||||
if(t->subID == creature->faction) //TODO: how to force AI to build unupgraded creatures? :O
|
||||
{
|
||||
@ -1238,7 +1285,7 @@ TSubgoal GatherTroops::whatToDoToAchieve()
|
||||
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);
|
||||
solutions.push_back(sptr(Goals::BuyArmy(t, creature->AIValue * this->value).setobjid(objid)));
|
||||
}
|
||||
/*else //disable random building requests for now - this code needs to know a lot of town/resource context to do more good than harm
|
||||
{
|
||||
@ -1248,10 +1295,11 @@ TSubgoal GatherTroops::whatToDoToAchieve()
|
||||
}
|
||||
for(auto obj : ai->visitableObjs)
|
||||
{
|
||||
if(obj->ID != Obj::CREATURE_GENERATOR1) //TODO: what with other creature generators?
|
||||
auto d = dynamic_cast<const CGDwelling *>(obj);
|
||||
|
||||
if(!d || obj->ID == Obj::TOWN)
|
||||
continue;
|
||||
|
||||
auto d = dynamic_cast<const CGDwelling *>(obj);
|
||||
for(auto creature : d->creatures)
|
||||
{
|
||||
if(creature.first) //there are more than 0 creatures avaliabe
|
||||
@ -1259,49 +1307,13 @@ TSubgoal GatherTroops::whatToDoToAchieve()
|
||||
for(auto type : creature.second)
|
||||
{
|
||||
if(type == objid && ai->ah->freeResources().canAfford(VLC->creh->creatures[type]->cost))
|
||||
dwellings.push_back(d);
|
||||
vstd::concatenate(solutions, ai->ah->howToVisitObj(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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());
|
||||
const CGPathNode * 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));
|
||||
}
|
||||
if(nearestDwellings.size())
|
||||
{
|
||||
// find hero who is nearest to a dwelling
|
||||
const CGDwelling * nearest = boost::range::min_element(nearestDwellings, comparator)->second;
|
||||
if(!nearest)
|
||||
throw cannotFulfillGoalException("Cannot find nearest dwelling!");
|
||||
|
||||
return sptr(Goals::VisitObj(nearest->id.getNum()));
|
||||
}
|
||||
else
|
||||
return sptr(Goals::Explore());
|
||||
}
|
||||
else
|
||||
{
|
||||
return sptr(Goals::Explore());
|
||||
}
|
||||
return solutions;
|
||||
//TODO: exchange troops between heroes
|
||||
}
|
||||
|
||||
|
@ -535,13 +535,13 @@ public:
|
||||
value = val;
|
||||
priority = 2;
|
||||
}
|
||||
TGoalVec getAllPossibleSubgoals() override
|
||||
{
|
||||
return TGoalVec();
|
||||
}
|
||||
TGoalVec getAllPossibleSubgoals() override;
|
||||
TSubgoal whatToDoToAchieve() override;
|
||||
bool fulfillsMe(TSubgoal goal) override;
|
||||
virtual bool operator==(const GatherTroops & other) const override;
|
||||
|
||||
private:
|
||||
int getCreaturesCount(const CArmedInstance * army);
|
||||
};
|
||||
|
||||
class DLL_EXPORT VisitObj : public CGoal<VisitObj> //this goal was previously known as GetObj
|
||||
|
@ -144,6 +144,9 @@ Goals::TGoalVec PathfindingManager::findPath(
|
||||
: clearWayTo(hero, firstTileToGet);
|
||||
}
|
||||
|
||||
if(solution->invalid())
|
||||
continue;
|
||||
|
||||
if(solution->evaluationContext.danger < danger)
|
||||
solution->evaluationContext.danger = danger;
|
||||
|
||||
@ -212,6 +215,7 @@ Goals::TSubgoal PathfindingManager::clearWayTo(HeroPtr hero, int3 firstTileToGet
|
||||
//ret.push_back(ai->questToGoal());
|
||||
//however, visiting obj for firts time will give us quest
|
||||
//do not access quets guard if we can't complete the quest
|
||||
logAi->trace("Can not visit this quest guard! Not ready!");
|
||||
return sptr(Goals::Invalid());
|
||||
}
|
||||
}
|
||||
|
@ -2193,16 +2193,18 @@ void VCAI::tryRealize(Goals::BuyArmy & g)
|
||||
{
|
||||
auto res = ah->allResources();
|
||||
std::vector<creInfo> creaturesInDwellings;
|
||||
|
||||
for (int i = 0; i < t->creatures.size(); i++)
|
||||
{
|
||||
auto ci = infoFromDC(t->creatures[i]);
|
||||
|
||||
if(!ci.count || ci.creID == -1 || (g.objid != -1 && ci.creID != g.objid))
|
||||
continue;
|
||||
|
||||
ci.level = i; //this is important for Dungeon Summoning Portal
|
||||
creaturesInDwellings.push_back(ci);
|
||||
}
|
||||
vstd::erase_if(creaturesInDwellings, [](const creInfo & ci) -> bool
|
||||
{
|
||||
return !ci.count || ci.creID == -1;
|
||||
});
|
||||
|
||||
if (creaturesInDwellings.empty())
|
||||
throw cannotFulfillGoalException("Can't buy any more creatures!");
|
||||
|
||||
@ -2433,6 +2435,8 @@ Goals::TSubgoal VCAI::decomposeGoal(Goals::TSubgoal ultimateGoal)
|
||||
|
||||
Goals::TSubgoal VCAI::questToGoal(const QuestInfo & q)
|
||||
{
|
||||
Goals::TSubgoal result = sptr(Goals::Invalid());
|
||||
|
||||
if (q.quest->missionType && q.quest->progress != CQuest::COMPLETE)
|
||||
{
|
||||
MetaString ms;
|
||||
@ -2476,12 +2480,18 @@ Goals::TSubgoal VCAI::questToGoal(const QuestInfo & q)
|
||||
{
|
||||
if (q.quest->checkQuest(hero)) //very bad info - stacks can be split between multiple heroes :(
|
||||
{
|
||||
return sptr(Goals::VisitObj(q.obj->id.getNum()).sethero(hero));
|
||||
result = sptr(Goals::VisitObj(q.obj->id.getNum()).sethero(hero));
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (auto creature : q.quest->m6creatures)
|
||||
|
||||
if(result->invalid())
|
||||
{
|
||||
return sptr(Goals::GatherTroops(creature.type->idNumber, creature.count));
|
||||
for(auto creature : q.quest->m6creatures)
|
||||
{
|
||||
result = sptr(Goals::GatherTroops(creature.type->idNumber, creature.count));
|
||||
break;
|
||||
}
|
||||
}
|
||||
//TODO: exchange armies... oh my
|
||||
//BNLOG ("Don't know how to recruit %d of %s\n", (int)(creature.count) % creature.type->namePl);
|
||||
@ -2576,7 +2586,15 @@ Goals::TSubgoal VCAI::questToGoal(const QuestInfo & q)
|
||||
}
|
||||
} //end of switch
|
||||
}
|
||||
return sptr(Goals::Invalid());
|
||||
|
||||
logAi->trace(
|
||||
"Returning %s, tile: %s, objid: %d, hero: %s",
|
||||
result->name(),
|
||||
result->tile.toString(),
|
||||
result->objid,
|
||||
result->hero.validAndSet() ? result->hero->name : "not specified");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void VCAI::performTypicalActions()
|
||||
|
Loading…
x
Reference in New Issue
Block a user