1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

BattleAI: check negative obstacles instead of moat.

This will work for fire walls too (and if someone will summon elementals
after placing land mines). But will not work for Tower's landmines.
This commit is contained in:
Konstantin 2023-03-20 12:41:36 +03:00
parent 1100bc7a5b
commit 6c5f5dba75

View File

@ -19,6 +19,7 @@
#include "../../lib/spells/CSpellHandler.h" #include "../../lib/spells/CSpellHandler.h"
#include "../../lib/spells/ISpellMechanics.h" #include "../../lib/spells/ISpellMechanics.h"
#include "../../lib/battle/BattleStateInfoForRetreat.h" #include "../../lib/battle/BattleStateInfoForRetreat.h"
#include "../../lib/battle/CObstacleInstance.h"
#include "../../lib/CStack.h" // TODO: remove #include "../../lib/CStack.h" // TODO: remove
// Eventually only IBattleInfoCallback and battle::Unit should be used, // Eventually only IBattleInfoCallback and battle::Unit should be used,
// CUnitState should be private and CStack should be removed completely // CUnitState should be private and CStack should be removed completely
@ -309,25 +310,38 @@ BattleAction CBattleAI::goTowardsNearest(const CStack * stack, std::vector<Battl
if(stack->hasBonusOfType(Bonus::FLYING)) if(stack->hasBonusOfType(Bonus::FLYING))
{ {
std::set<BattleHex> moatHexes; std::set<BattleHex> obstacleHexes;
if(hb.battleGetSiegeLevel() >= BuildingID::CITADEL) auto insertAffected = [](const CObstacleInstance* spellObst, std::set<BattleHex> obstacleHexes) {
auto affectedHexes = spellObst->getAffectedTiles();
obstacleHexes.insert(affectedHexes.cbegin(), affectedHexes.cend());
};
const auto & obstacles = hb.battleGetAllObstacles();
for (const auto & obst: obstacles) {
const auto * spellObst = dynamic_cast<const SpellCreatedObstacle*>(obst.get());
if(spellObst && spellObst->trigger)
{ {
auto townMoat = hb.getDefendedTown()->town->moatHexes; auto triggerAbility = VLC->spells()->getById(SpellID(spellObst->ID));
auto triggerIsNegative = triggerAbility->isNegative() || triggerAbility->isDamage();
moatHexes = std::set<BattleHex>(townMoat.begin(), townMoat.end()); if(triggerIsNegative)
insertAffected(spellObst, obstacleHexes);
}
} }
// Flying stack doesn't go hex by hex, so we can't backtrack using predecessors. // Flying stack doesn't go hex by hex, so we can't backtrack using predecessors.
// We just check all available hexes and pick the one closest to the target. // We just check all available hexes and pick the one closest to the target.
auto nearestAvailableHex = vstd::minElementByFun(avHexes, [&](BattleHex hex) -> int auto nearestAvailableHex = vstd::minElementByFun(avHexes, [&](BattleHex hex) -> int
{ {
const int MOAT_PENALTY = 100; // avoid landing on moat const int NEGATIVE_OBSTACLE_PENALTY = 100; // avoid landing on negative obstacle (moat, fire wall, etc)
const int BLOCKED_STACK_PENALTY = 100; // avoid landing on moat const int BLOCKED_STACK_PENALTY = 100; // avoid landing on moat
auto distance = BattleHex::getDistance(bestNeighbor, hex); auto distance = BattleHex::getDistance(bestNeighbor, hex);
if(vstd::contains(moatHexes, hex)) if(vstd::contains(obstacleHexes, hex))
distance += MOAT_PENALTY; distance += NEGATIVE_OBSTACLE_PENALTY;
return scoreEvaluator.checkPositionBlocksOurStacks(hb, stack, hex) ? BLOCKED_STACK_PENALTY + distance : distance; return scoreEvaluator.checkPositionBlocksOurStacks(hb, stack, hex) ? BLOCKED_STACK_PENALTY + distance : distance;
}); });