1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +02:00

Nullkiller: capture guarded artifacts and other fixes

This commit is contained in:
Andrii Danylchenko
2021-05-16 14:22:41 +03:00
committed by Andrii Danylchenko
parent 1fd838a5b9
commit 5344df51c6
7 changed files with 80 additions and 19 deletions

View File

@@ -123,9 +123,6 @@ Goals::TGoalVec CaptureObjectsBehavior::getTasks()
if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
continue;
if(ai->nullkiller->getHeroLockedReason(way->hero.get()) == HeroLockedReason::STARTUP)
continue;
way->evaluationContext.closestWayRatio
= closestWay->evaluationContext.movementCost / way->evaluationContext.movementCost;
@@ -149,7 +146,6 @@ Goals::TGoalVec CaptureObjectsBehavior::getTasks()
bool CaptureObjectsBehavior::shouldVisitObject(ObjectIdRef obj) const
{
const CGObjectInstance* objInstance = obj;
if(!objInstance)
return false;
@@ -162,6 +158,11 @@ bool CaptureObjectsBehavior::shouldVisitObject(ObjectIdRef obj) const
{
return false;
}
if(isObjectRemovable(obj))
{
return true;
}
const int3 pos = objInstance->visitablePos();

View File

@@ -148,9 +148,6 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her
if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
continue;
if(ai->nullkiller->getHeroLockedReason(way->hero.get()) == HeroLockedReason::STARTUP)
continue;
way->evaluationContext.closestWayRatio = 1;
tasks.push_back(sptr(*way));
@@ -246,9 +243,6 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader)
if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
continue;
if(ai->nullkiller->getHeroLockedReason(way->hero.get()) == HeroLockedReason::STARTUP)
continue;
way->evaluationContext.closestWayRatio = 1;
tasks.push_back(sptr(*way));

View File

@@ -69,12 +69,13 @@ Goals::TSubgoal Nullkiller::choseBestTask(std::shared_ptr<Behavior> behavior) co
void Nullkiller::resetAiState()
{
lockedHeroes.clear();
dangerHitMap->reset();
}
void Nullkiller::updateAiState()
{
activeHero = nullptr;
ai->validateVisitableObjs();
dangerHitMap->updateHitMap();
@@ -94,17 +95,44 @@ void Nullkiller::updateAiState()
buildAnalyzer->update();
}
bool Nullkiller::isHeroLocked(const CGHeroInstance * hero) const
{
return getHeroLockedReason(hero) != HeroLockedReason::NOT_LOCKED;
}
bool Nullkiller::arePathHeroesLocked(const AIPath & path) const
{
if(getHeroLockedReason(path.targetHero) == HeroLockedReason::STARTUP)
{
#if AI_TRACE_LEVEL >= 1
logAi->trace("Hero %s is locked by STARTUP. Discarding %s", path.targetHero->name, path.toString());
#endif
return true;
}
for(auto & node : path.nodes)
{
if(isHeroLocked(node.targetHero))
auto lockReason = getHeroLockedReason(node.targetHero);
if(lockReason != HeroLockedReason::NOT_LOCKED)
{
#if AI_TRACE_LEVEL >= 1
logAi->trace("Hero %s is locked by STARTUP. Discarding %s", path.targetHero->name, path.toString());
#endif
return true;
}
}
return false;
}
HeroLockedReason Nullkiller::getHeroLockedReason(const CGHeroInstance * hero) const
{
auto found = lockedHeroes.find(hero);
return found != lockedHeroes.end() ? found->second : HeroLockedReason::NOT_LOCKED;
}
void Nullkiller::makeTurn()
{
resetAiState();
@@ -149,7 +177,7 @@ void Nullkiller::makeTurn()
{
if(bestTask->hero)
{
activeHero = bestTask->hero.get();
setActive(bestTask->hero.get(), bestTask->tile);
}
bestTask->accept(ai.get());

View File

@@ -34,6 +34,7 @@ class Nullkiller
private:
std::unique_ptr<PriorityEvaluator> priorityEvaluator;
const CGHeroInstance * activeHero;
int3 targetTile;
std::map<const CGHeroInstance *, HeroLockedReason> lockedHeroes;
public:
@@ -43,9 +44,11 @@ public:
Nullkiller();
void makeTurn();
bool isActive(const CGHeroInstance * hero) const { return activeHero == hero; }
bool isHeroLocked(const CGHeroInstance * hero) const { return vstd::contains(lockedHeroes, hero); }
HeroLockedReason getHeroLockedReason(const CGHeroInstance * hero) const { return isHeroLocked(hero) ? lockedHeroes.at(hero) : HeroLockedReason::NOT_LOCKED; }
void setActive(const CGHeroInstance * hero) { activeHero = hero; }
bool isHeroLocked(const CGHeroInstance * hero) const;
HeroPtr getActiveHero() { return activeHero; }
HeroLockedReason getHeroLockedReason(const CGHeroInstance * hero) const;
int3 getTargetTile() const { return targetTile; }
void setActive(const CGHeroInstance * hero, int3 tile) { activeHero = hero; targetTile = tile; }
void lockHero(const CGHeroInstance * hero, HeroLockedReason lockReason) { lockedHeroes[hero] = lockReason; }
void unlockHero(const CGHeroInstance * hero) { lockedHeroes.erase(hero); }
bool arePathHeroesLocked(const AIPath & path) const;

View File

@@ -289,6 +289,15 @@ ui64 FuzzyHelper::evaluateDanger(const CGObjectInstance * obj, const VCAI * ai)
const CGTownInstance * cre = dynamic_cast<const CGTownInstance *>(obj);
return cre->getUpperArmy()->getArmyStrength();
}
case Obj::ARTIFACT:
case Obj::RESOURCE:
{
if(!vstd::contains(ai->alreadyVisited, obj))
{
return 0;
}
// passthrough
}
case Obj::MONSTER:
case Obj::HERO:
case Obj::GARRISON:

View File

@@ -88,7 +88,7 @@ void ExecuteHeroChain::accept(VCAI * ai)
{
if(hero->movement)
{
ai->nullkiller->setActive(hero.get());
ai->nullkiller->setActive(hero.get(), node.coord);
if(node.specialAction)
{

View File

@@ -652,8 +652,34 @@ void VCAI::showBlockingDialog(const std::string & text, const std::vector<Compon
if(selection) //select from multiple components -> take the last one (they're indexed [1-size])
sel = components.size();
if(!selection && cancel) //yes&no -> always answer yes, we are a brave AI :)
sel = 1;
if(!selection && cancel)
{
requestActionASAP([=]()
{
//yes&no -> always answer yes, we are a brave AI :)
auto answer = 1;
if(nullkiller)
{
auto hero = nullkiller->getActiveHero();
auto target = nullkiller->getTargetTile();
if(hero.validAndSet() && target.valid())
{
auto ratio = (float)fh->evaluateDanger(target, hero.get()) / (float)hero->getTotalStrength();
bool dangerUnknown = ratio == 0;
bool dangerTooHigh = ratio > (1 / SAFE_ATTACK_CONSTANT);
logAi->trace("Guarded object query hook: %s by %s danger ratio %f", target.toString(), hero.name, ratio);
if(text.find("guarded") >= 0 && (dangerUnknown || dangerTooHigh))
answer = 0; // no
}
}
answerQuery(askID, answer);
});
return;
}
// TODO: Find better way to understand it is Chest of Treasures
if(components.size() == 2 && components.front().id == Component::RESOURCE)