mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-15 20:03:15 +02:00
- Explore goal will also use fuzzy comparison
- Fixed AI afraid of town with Castle built: #1514, #1515, #1584
This commit is contained in:
@@ -159,7 +159,7 @@ void FuzzyHelper::initTacticalAdvantage()
|
||||
ta.castleWalls = new fl::InputLVar("CastleWalls");
|
||||
ta.castleWalls->addTerm(new fl::SingletonTerm("NONE", CGTownInstance::NONE));
|
||||
ta.castleWalls->addTerm(new fl::TrapezoidalTerm("MEDIUM", CGTownInstance::FORT, 2.5));
|
||||
ta.castleWalls->addTerm(new fl::ShoulderTerm("HIGH", CGTownInstance::CITADEL - 0.1, CGTownInstance::CASTLE));
|
||||
ta.castleWalls->addTerm(new fl::ShoulderTerm("HIGH", CGTownInstance::CITADEL - 0.1, CGTownInstance::CASTLE, false));
|
||||
engine.addInputLVar(ta.castleWalls);
|
||||
|
||||
ta.bankPresent = new fl::InputLVar("Bank");
|
||||
|
@@ -368,6 +368,33 @@ std::string Explore::completeMessage() const
|
||||
|
||||
TSubgoal Explore::whatToDoToAchieve()
|
||||
{
|
||||
auto ret = fh->chooseSolution(getAllPossibleSubgoals());
|
||||
if (hero) //use best step for this hero
|
||||
return ret;
|
||||
else
|
||||
{
|
||||
if (ret->hero.get(true))
|
||||
return sptr (sethero(ret->hero.h).setisAbstract(true)); //choose this hero and then continue with him
|
||||
else
|
||||
return ret; //other solutions, like buying hero from tavern
|
||||
}
|
||||
};
|
||||
|
||||
TGoalVec Explore::getAllPossibleSubgoals()
|
||||
{
|
||||
TGoalVec ret;
|
||||
std::vector<const CGHeroInstance *> heroes;
|
||||
if (hero)
|
||||
heroes.push_back(hero.h);
|
||||
else
|
||||
{
|
||||
heroes = cb->getHeroesInfo();
|
||||
erase_if(heroes, [](const CGHeroInstance *h)
|
||||
{
|
||||
return !h->movement; //only hero with movement are of interest for us
|
||||
});
|
||||
}
|
||||
|
||||
auto objs = ai->visitableObjs; //try to use buildings that uncover map
|
||||
erase_if(objs, [&](const CGObjectInstance *obj) -> bool
|
||||
{
|
||||
@@ -389,94 +416,28 @@ TSubgoal Explore::whatToDoToAchieve()
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (objs.size())
|
||||
|
||||
for (auto h : heroes)
|
||||
{
|
||||
if (hero.get(true))
|
||||
for (auto obj : objs) //double loop, performance risk?
|
||||
{
|
||||
for (auto obj : objs)
|
||||
if (ai->isAccessibleForHero(obj->visitablePos(), h) && isSafeToVisit(h, obj->visitablePos()))
|
||||
{
|
||||
auto pos = obj->visitablePos();
|
||||
//FIXME: this confition fails if everything but guarded subterranen gate was explored. in this case we should gather army for hero
|
||||
if (isSafeToVisit(hero, pos) && ai->isAccessibleForHero(pos, hero))
|
||||
return sptr (Goals::VisitTile(pos).sethero(hero));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto obj : objs)
|
||||
{
|
||||
auto pos = obj->visitablePos();
|
||||
if (ai->isAccessible (pos)) //TODO: check safety?
|
||||
return sptr (Goals::VisitTile(pos).sethero(hero));
|
||||
ret.push_back (sptr (Goals::VisitTile(obj->visitablePos()).sethero(h)));
|
||||
}
|
||||
}
|
||||
|
||||
int3 t = whereToExplore(h);
|
||||
if (t.z != -1) //no safe tile to explore - we need to break!
|
||||
ret.push_back (sptr (Goals::VisitTile(t).sethero(h)));
|
||||
}
|
||||
if (!hero && ai->canRecruitAnyHero())//if hero is assigned to that goal, no need to buy another one yet
|
||||
ret.push_back (sptr(Goals::RecruitHero()));
|
||||
|
||||
if (hero)
|
||||
{
|
||||
int3 t = whereToExplore(hero);
|
||||
if (t.z == -1) //no safe tile to explore - we need to break!
|
||||
{
|
||||
erase_if (objs, [&](const CGObjectInstance *obj) -> bool
|
||||
{
|
||||
switch (obj->ID.num)
|
||||
{
|
||||
case Obj::CARTOGRAPHER:
|
||||
case Obj::SUBTERRANEAN_GATE:
|
||||
//case Obj::MONOLITH1:
|
||||
//case obj::MONOLITH2:
|
||||
//case obj::MONOLITH3:
|
||||
//case Obj::WHIRLPOOL:
|
||||
return false; //do not erase
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (objs.size())
|
||||
{
|
||||
return sptr (Goals::VisitTile(objs.front()->visitablePos()).sethero(hero).setisAbstract(true));
|
||||
}
|
||||
else
|
||||
throw cannotFulfillGoalException("Cannot explore - no possible ways found!");
|
||||
}
|
||||
return sptr (Goals::VisitTile(t).sethero(hero));
|
||||
}
|
||||
if (ret.empty())
|
||||
throw cannotFulfillGoalException("Cannot explore - no possible ways found!");
|
||||
|
||||
auto hs = cb->getHeroesInfo();
|
||||
int howManyHeroes = hs.size();
|
||||
|
||||
erase(hs, [](const CGHeroInstance *h)
|
||||
{
|
||||
return contains(ai->lockedHeroes, h);
|
||||
});
|
||||
if(hs.empty()) //all heroes are busy. buy new one
|
||||
{
|
||||
if (howManyHeroes < 3 && ai->findTownWithTavern()) //we may want to recruit second hero. TODO: make it smart finally
|
||||
return sptr (Goals::RecruitHero());
|
||||
else //find mobile hero with weakest army
|
||||
{
|
||||
hs = cb->getHeroesInfo();
|
||||
erase_if(hs, [](const CGHeroInstance *h)
|
||||
{
|
||||
return !h->movement; //only hero with movement are of interest for us
|
||||
});
|
||||
if (hs.empty())
|
||||
{
|
||||
if (howManyHeroes < GameConstants::MAX_HEROES_PER_PLAYER)
|
||||
return sptr (Goals::RecruitHero());
|
||||
else
|
||||
throw cannotFulfillGoalException("No heroes with remaining MPs for exploring!\n");
|
||||
}
|
||||
boost::sort(hs, compareMovement); //closer to what?
|
||||
}
|
||||
}
|
||||
|
||||
const CGHeroInstance *h = hs.front();
|
||||
|
||||
return sptr (sethero(h).setisAbstract(true));
|
||||
|
||||
return iAmElementar(); //FIXME: how can this be called?
|
||||
return ret;
|
||||
};
|
||||
|
||||
float Explore::importanceWhenLocked() const
|
||||
|
@@ -229,7 +229,7 @@ class Explore : public CGoal<Explore>
|
||||
public:
|
||||
Explore() : CGoal (Goals::EXPLORE){};
|
||||
Explore(HeroPtr h) : CGoal (Goals::EXPLORE){hero = h;};
|
||||
TGoalVec getAllPossibleSubgoals() override {return TGoalVec();};
|
||||
TGoalVec getAllPossibleSubgoals() override;
|
||||
TSubgoal whatToDoToAchieve() override;
|
||||
std::string completeMessage() const override;
|
||||
float importanceWhenLocked() const override;
|
||||
|
Reference in New Issue
Block a user