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:
committed by
Andrii Danylchenko
parent
1fd838a5b9
commit
5344df51c6
@@ -123,9 +123,6 @@ Goals::TGoalVec CaptureObjectsBehavior::getTasks()
|
|||||||
if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
|
if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(ai->nullkiller->getHeroLockedReason(way->hero.get()) == HeroLockedReason::STARTUP)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
way->evaluationContext.closestWayRatio
|
way->evaluationContext.closestWayRatio
|
||||||
= closestWay->evaluationContext.movementCost / way->evaluationContext.movementCost;
|
= closestWay->evaluationContext.movementCost / way->evaluationContext.movementCost;
|
||||||
|
|
||||||
@@ -149,7 +146,6 @@ Goals::TGoalVec CaptureObjectsBehavior::getTasks()
|
|||||||
bool CaptureObjectsBehavior::shouldVisitObject(ObjectIdRef obj) const
|
bool CaptureObjectsBehavior::shouldVisitObject(ObjectIdRef obj) const
|
||||||
{
|
{
|
||||||
const CGObjectInstance* objInstance = obj;
|
const CGObjectInstance* objInstance = obj;
|
||||||
|
|
||||||
if(!objInstance)
|
if(!objInstance)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -163,6 +159,11 @@ bool CaptureObjectsBehavior::shouldVisitObject(ObjectIdRef obj) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(isObjectRemovable(obj))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const int3 pos = objInstance->visitablePos();
|
const int3 pos = objInstance->visitablePos();
|
||||||
|
|
||||||
if(objInstance->ID != Obj::CREATURE_GENERATOR1 && vstd::contains(ai->alreadyVisited, objInstance)
|
if(objInstance->ID != Obj::CREATURE_GENERATOR1 && vstd::contains(ai->alreadyVisited, objInstance)
|
||||||
|
@@ -148,9 +148,6 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her
|
|||||||
if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
|
if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(ai->nullkiller->getHeroLockedReason(way->hero.get()) == HeroLockedReason::STARTUP)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
way->evaluationContext.closestWayRatio = 1;
|
way->evaluationContext.closestWayRatio = 1;
|
||||||
|
|
||||||
tasks.push_back(sptr(*way));
|
tasks.push_back(sptr(*way));
|
||||||
@@ -246,9 +243,6 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader)
|
|||||||
if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
|
if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(ai->nullkiller->getHeroLockedReason(way->hero.get()) == HeroLockedReason::STARTUP)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
way->evaluationContext.closestWayRatio = 1;
|
way->evaluationContext.closestWayRatio = 1;
|
||||||
|
|
||||||
tasks.push_back(sptr(*way));
|
tasks.push_back(sptr(*way));
|
||||||
|
@@ -69,12 +69,13 @@ Goals::TSubgoal Nullkiller::choseBestTask(std::shared_ptr<Behavior> behavior) co
|
|||||||
void Nullkiller::resetAiState()
|
void Nullkiller::resetAiState()
|
||||||
{
|
{
|
||||||
lockedHeroes.clear();
|
lockedHeroes.clear();
|
||||||
|
|
||||||
dangerHitMap->reset();
|
dangerHitMap->reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Nullkiller::updateAiState()
|
void Nullkiller::updateAiState()
|
||||||
{
|
{
|
||||||
|
activeHero = nullptr;
|
||||||
|
|
||||||
ai->validateVisitableObjs();
|
ai->validateVisitableObjs();
|
||||||
dangerHitMap->updateHitMap();
|
dangerHitMap->updateHitMap();
|
||||||
|
|
||||||
@@ -94,17 +95,44 @@ void Nullkiller::updateAiState()
|
|||||||
buildAnalyzer->update();
|
buildAnalyzer->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Nullkiller::isHeroLocked(const CGHeroInstance * hero) const
|
||||||
|
{
|
||||||
|
return getHeroLockedReason(hero) != HeroLockedReason::NOT_LOCKED;
|
||||||
|
}
|
||||||
|
|
||||||
bool Nullkiller::arePathHeroesLocked(const AIPath & path) const
|
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)
|
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 true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
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()
|
void Nullkiller::makeTurn()
|
||||||
{
|
{
|
||||||
resetAiState();
|
resetAiState();
|
||||||
@@ -149,7 +177,7 @@ void Nullkiller::makeTurn()
|
|||||||
{
|
{
|
||||||
if(bestTask->hero)
|
if(bestTask->hero)
|
||||||
{
|
{
|
||||||
activeHero = bestTask->hero.get();
|
setActive(bestTask->hero.get(), bestTask->tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
bestTask->accept(ai.get());
|
bestTask->accept(ai.get());
|
||||||
|
@@ -34,6 +34,7 @@ class Nullkiller
|
|||||||
private:
|
private:
|
||||||
std::unique_ptr<PriorityEvaluator> priorityEvaluator;
|
std::unique_ptr<PriorityEvaluator> priorityEvaluator;
|
||||||
const CGHeroInstance * activeHero;
|
const CGHeroInstance * activeHero;
|
||||||
|
int3 targetTile;
|
||||||
std::map<const CGHeroInstance *, HeroLockedReason> lockedHeroes;
|
std::map<const CGHeroInstance *, HeroLockedReason> lockedHeroes;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -43,9 +44,11 @@ public:
|
|||||||
Nullkiller();
|
Nullkiller();
|
||||||
void makeTurn();
|
void makeTurn();
|
||||||
bool isActive(const CGHeroInstance * hero) const { return activeHero == hero; }
|
bool isActive(const CGHeroInstance * hero) const { return activeHero == hero; }
|
||||||
bool isHeroLocked(const CGHeroInstance * hero) const { return vstd::contains(lockedHeroes, hero); }
|
bool isHeroLocked(const CGHeroInstance * hero) const;
|
||||||
HeroLockedReason getHeroLockedReason(const CGHeroInstance * hero) const { return isHeroLocked(hero) ? lockedHeroes.at(hero) : HeroLockedReason::NOT_LOCKED; }
|
HeroPtr getActiveHero() { return activeHero; }
|
||||||
void setActive(const CGHeroInstance * hero) { activeHero = hero; }
|
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 lockHero(const CGHeroInstance * hero, HeroLockedReason lockReason) { lockedHeroes[hero] = lockReason; }
|
||||||
void unlockHero(const CGHeroInstance * hero) { lockedHeroes.erase(hero); }
|
void unlockHero(const CGHeroInstance * hero) { lockedHeroes.erase(hero); }
|
||||||
bool arePathHeroesLocked(const AIPath & path) const;
|
bool arePathHeroesLocked(const AIPath & path) const;
|
||||||
|
@@ -289,6 +289,15 @@ ui64 FuzzyHelper::evaluateDanger(const CGObjectInstance * obj, const VCAI * ai)
|
|||||||
const CGTownInstance * cre = dynamic_cast<const CGTownInstance *>(obj);
|
const CGTownInstance * cre = dynamic_cast<const CGTownInstance *>(obj);
|
||||||
return cre->getUpperArmy()->getArmyStrength();
|
return cre->getUpperArmy()->getArmyStrength();
|
||||||
}
|
}
|
||||||
|
case Obj::ARTIFACT:
|
||||||
|
case Obj::RESOURCE:
|
||||||
|
{
|
||||||
|
if(!vstd::contains(ai->alreadyVisited, obj))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// passthrough
|
||||||
|
}
|
||||||
case Obj::MONSTER:
|
case Obj::MONSTER:
|
||||||
case Obj::HERO:
|
case Obj::HERO:
|
||||||
case Obj::GARRISON:
|
case Obj::GARRISON:
|
||||||
|
@@ -88,7 +88,7 @@ void ExecuteHeroChain::accept(VCAI * ai)
|
|||||||
{
|
{
|
||||||
if(hero->movement)
|
if(hero->movement)
|
||||||
{
|
{
|
||||||
ai->nullkiller->setActive(hero.get());
|
ai->nullkiller->setActive(hero.get(), node.coord);
|
||||||
|
|
||||||
if(node.specialAction)
|
if(node.specialAction)
|
||||||
{
|
{
|
||||||
|
@@ -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])
|
if(selection) //select from multiple components -> take the last one (they're indexed [1-size])
|
||||||
sel = components.size();
|
sel = components.size();
|
||||||
|
|
||||||
if(!selection && cancel) //yes&no -> always answer yes, we are a brave AI :)
|
if(!selection && cancel)
|
||||||
sel = 1;
|
{
|
||||||
|
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
|
// TODO: Find better way to understand it is Chest of Treasures
|
||||||
if(components.size() == 2 && components.front().id == Component::RESOURCE)
|
if(components.size() == 2 && components.front().id == Component::RESOURCE)
|
||||||
|
Reference in New Issue
Block a user