mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-31 22:05:10 +02:00
Implemented simple target selection logic for arrow towers
This commit is contained in:
parent
3c611ffa5b
commit
5bd9a32d97
@ -50,6 +50,12 @@ static bool sameSideOfWall(BattleHex pos1, BattleHex pos2)
|
|||||||
return stackLeft == destLeft;
|
return stackLeft == destLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isInsideWalls(BattleHex pos)
|
||||||
|
{
|
||||||
|
const int wallInStackLine = lineToWallHex(pos.getY());
|
||||||
|
return wallInStackLine < pos;
|
||||||
|
}
|
||||||
|
|
||||||
// parts of wall
|
// parts of wall
|
||||||
static const std::pair<int, EWallPart> wallParts[] =
|
static const std::pair<int, EWallPart> wallParts[] =
|
||||||
{
|
{
|
||||||
@ -158,6 +164,11 @@ std::pair< std::vector<BattleHex>, int > CBattleInfoCallback::getPath(BattleHex
|
|||||||
return std::make_pair(path, reachability.distances[dest]);
|
return std::make_pair(path, reachability.distances[dest]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CBattleInfoCallback::battleIsInsideWalls(BattleHex from) const
|
||||||
|
{
|
||||||
|
return isInsideWalls(from);
|
||||||
|
}
|
||||||
|
|
||||||
bool CBattleInfoCallback::battleHasPenaltyOnLine(BattleHex from, BattleHex dest, bool checkWall, bool checkMoat) const
|
bool CBattleInfoCallback::battleHasPenaltyOnLine(BattleHex from, BattleHex dest, bool checkWall, bool checkMoat) const
|
||||||
{
|
{
|
||||||
auto isTileBlocked = [&](BattleHex tile)
|
auto isTileBlocked = [&](BattleHex tile)
|
||||||
|
@ -104,6 +104,7 @@ public:
|
|||||||
DamageEstimation battleEstimateDamage(const battle::Unit * attacker, const battle::Unit * defender, BattleHex attackerPosition, DamageEstimation * retaliationDmg = nullptr) const;
|
DamageEstimation battleEstimateDamage(const battle::Unit * attacker, const battle::Unit * defender, BattleHex attackerPosition, DamageEstimation * retaliationDmg = nullptr) const;
|
||||||
DamageEstimation battleEstimateDamage(const battle::Unit * attacker, const battle::Unit * defender, int getMovementRange, DamageEstimation * retaliationDmg = nullptr) const;
|
DamageEstimation battleEstimateDamage(const battle::Unit * attacker, const battle::Unit * defender, int getMovementRange, DamageEstimation * retaliationDmg = nullptr) const;
|
||||||
|
|
||||||
|
bool battleIsInsideWalls(BattleHex from) const;
|
||||||
bool battleHasPenaltyOnLine(BattleHex from, BattleHex dest, bool checkWall, bool checkMoat) const;
|
bool battleHasPenaltyOnLine(BattleHex from, BattleHex dest, bool checkWall, bool checkMoat) const;
|
||||||
bool battleHasDistancePenalty(const IBonusBearer * shooter, BattleHex shooterPosition, BattleHex destHex) const;
|
bool battleHasDistancePenalty(const IBonusBearer * shooter, BattleHex shooterPosition, BattleHex destHex) const;
|
||||||
bool battleHasWallPenalty(const IBonusBearer * shooter, BattleHex shooterPosition, BattleHex destHex) const;
|
bool battleHasWallPenalty(const IBonusBearer * shooter, BattleHex shooterPosition, BattleHex destHex) const;
|
||||||
|
@ -389,20 +389,47 @@ bool BattleFlowProcessor::tryMakeAutomaticAction(const CBattleInfoCallback & bat
|
|||||||
attack.side = next->unitSide();
|
attack.side = next->unitSide();
|
||||||
attack.stackNumber = next->unitId();
|
attack.stackNumber = next->unitId();
|
||||||
|
|
||||||
//TODO: select target by priority
|
// TODO: unify logic with AI?
|
||||||
|
// Find best target using logic similar to H3 AI
|
||||||
|
|
||||||
|
const auto & isBetterTarget = [&battle](const battle::Unit * candidate, const battle::Unit * current)
|
||||||
|
{
|
||||||
|
bool candidateInsideWalls = battle.battleIsInsideWalls(candidate->getPosition());
|
||||||
|
bool currentInsideWalls = battle.battleIsInsideWalls(current->getPosition());
|
||||||
|
|
||||||
|
if (candidateInsideWalls != currentInsideWalls)
|
||||||
|
return candidateInsideWalls > currentInsideWalls;
|
||||||
|
|
||||||
|
// also check for war machines - shooters are more dangerous than war machines, ballista or catapult
|
||||||
|
bool candidateCanShoot = candidate->canShoot() && candidate->unitType()->warMachine == ArtifactID::NONE;
|
||||||
|
bool currentCanShoot = current->canShoot() && current->unitType()->warMachine == ArtifactID::NONE;
|
||||||
|
|
||||||
|
if (candidateCanShoot != currentCanShoot)
|
||||||
|
return candidateCanShoot > currentCanShoot;
|
||||||
|
|
||||||
|
int64_t candidateTargetValue = static_cast<int64_t>(candidate->unitType()->getAIValue() * candidate->getCount());
|
||||||
|
int64_t currentTargetValue = static_cast<int64_t>(current->unitType()->getAIValue() * current->getCount());
|
||||||
|
|
||||||
|
return candidateTargetValue > currentTargetValue;
|
||||||
|
};
|
||||||
|
|
||||||
const battle::Unit * target = nullptr;
|
const battle::Unit * target = nullptr;
|
||||||
|
|
||||||
for(auto & elem : battle.battleGetAllStacks(true))
|
for(auto & elem : battle.battleGetAllStacks(true))
|
||||||
{
|
{
|
||||||
if(elem->unitType()->getId() != CreatureID::CATAPULT
|
if (elem->unitOwner() == next->unitOwner())
|
||||||
&& elem->unitOwner() != next->unitOwner()
|
continue;
|
||||||
&& elem->isValidTarget()
|
|
||||||
&& battle.battleCanShoot(next, elem->getPosition()))
|
if (!elem->isValidTarget())
|
||||||
{
|
continue;
|
||||||
|
|
||||||
|
if (!battle.battleCanShoot(next, elem->getPosition()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (target && !isBetterTarget(elem, target))
|
||||||
|
continue;
|
||||||
|
|
||||||
target = elem;
|
target = elem;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(target == nullptr)
|
if(target == nullptr)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user