mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
2184 - fix battlefield corners unreachable for 2 hex units
This commit is contained in:
parent
58b8fe3d26
commit
ea073c81d3
@ -189,13 +189,17 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
|
|||||||
if(stack->waited())
|
if(stack->waited())
|
||||||
{
|
{
|
||||||
//ThreatMap threatsToUs(stack); // These lines may be usefull but they are't used in the code.
|
//ThreatMap threatsToUs(stack); // These lines may be usefull but they are't used in the code.
|
||||||
auto dists = getCbc()->battleGetDistances(stack, stack->getPosition());
|
auto dists = getCbc()->getReachability(stack);
|
||||||
if(!targets.unreachableEnemies.empty())
|
if(!targets.unreachableEnemies.empty())
|
||||||
{
|
{
|
||||||
const EnemyInfo &ei= *range::min_element(targets.unreachableEnemies, std::bind(isCloser, _1, _2, std::ref(dists)));
|
auto closestEnemy = vstd::minElementByFun(targets.unreachableEnemies, [&](const battle::Unit * enemy) -> int
|
||||||
if(distToNearestNeighbour(ei.s->getPosition(), dists) < GameConstants::BFIELD_SIZE)
|
|
||||||
{
|
{
|
||||||
return goTowards(stack, ei.s->getPosition());
|
return dists.distToNearestNeighbour(stack, enemy);
|
||||||
|
});
|
||||||
|
|
||||||
|
if(dists.distToNearestNeighbour(stack, *closestEnemy) < GameConstants::BFIELD_SIZE)
|
||||||
|
{
|
||||||
|
return goTowards(stack, *closestEnemy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -216,19 +220,15 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
|
|||||||
return BattleAction::makeDefend(stack);
|
return BattleAction::makeDefend(stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
BattleAction CBattleAI::goTowards(const CStack * stack, BattleHex destination)
|
BattleAction CBattleAI::goTowards(const CStack * stack, const battle::Unit * enemy) const
|
||||||
{
|
{
|
||||||
if(!destination.isValid())
|
|
||||||
{
|
|
||||||
logAi->error("CBattleAI::goTowards: invalid destination");
|
|
||||||
return BattleAction::makeDefend(stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto reachability = cb->getReachability(stack);
|
auto reachability = cb->getReachability(stack);
|
||||||
auto avHexes = cb->battleGetAvailableHexes(reachability, stack);
|
auto avHexes = cb->battleGetAvailableHexes(reachability, stack);
|
||||||
|
auto destination = enemy->getPosition();
|
||||||
|
|
||||||
if(vstd::contains(avHexes, destination))
|
if(vstd::contains(avHexes, destination))
|
||||||
return BattleAction::makeMove(stack, destination);
|
return BattleAction::makeMove(stack, destination);
|
||||||
|
|
||||||
auto destNeighbours = destination.neighbouringTiles();
|
auto destNeighbours = destination.neighbouringTiles();
|
||||||
if(vstd::contains_if(destNeighbours, [&](BattleHex n) { return stack->coversPos(destination); }))
|
if(vstd::contains_if(destNeighbours, [&](BattleHex n) { return stack->coversPos(destination); }))
|
||||||
{
|
{
|
||||||
@ -236,31 +236,31 @@ BattleAction CBattleAI::goTowards(const CStack * stack, BattleHex destination)
|
|||||||
//We shouldn't even be here...
|
//We shouldn't even be here...
|
||||||
return BattleAction::makeDefend(stack);
|
return BattleAction::makeDefend(stack);
|
||||||
}
|
}
|
||||||
vstd::erase_if(destNeighbours, [&](BattleHex hex){ return !reachability.accessibility.accessible(hex, stack); });
|
|
||||||
if(!avHexes.size() || !destNeighbours.size()) //we are blocked or dest is blocked
|
if(!avHexes.size()) //we are blocked or dest is blocked
|
||||||
{
|
{
|
||||||
return BattleAction::makeDefend(stack);
|
return BattleAction::makeDefend(stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BattleHex bestNeighbor = destination;
|
||||||
|
if(reachability.distToNearestNeighbour(stack, enemy, &bestNeighbor) > GameConstants::BFIELD_SIZE)
|
||||||
|
{
|
||||||
|
return BattleAction::makeDefend(stack);
|
||||||
|
}
|
||||||
|
|
||||||
if(stack->hasBonusOfType(Bonus::FLYING))
|
if(stack->hasBonusOfType(Bonus::FLYING))
|
||||||
{
|
{
|
||||||
// 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 distToDestNeighbour = [&](BattleHex hex) -> int
|
auto nearestAvailableHex = vstd::minElementByFun(avHexes, [&](BattleHex hex) -> int
|
||||||
{
|
{
|
||||||
auto nearestNeighbourToHex = vstd::minElementByFun(destNeighbours, [&](BattleHex a)
|
return BattleHex::getDistance(bestNeighbor, hex);
|
||||||
{return BattleHex::getDistance(a, hex);});
|
});
|
||||||
return BattleHex::getDistance(*nearestNeighbourToHex, hex);
|
|
||||||
};
|
|
||||||
auto nearestAvailableHex = vstd::minElementByFun(avHexes, distToDestNeighbour);
|
|
||||||
return BattleAction::makeMove(stack, *nearestAvailableHex);
|
return BattleAction::makeMove(stack, *nearestAvailableHex);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BattleHex bestNeighbor = destination;
|
|
||||||
if(distToNearestNeighbour(destination, reachability.distances, &bestNeighbor) > GameConstants::BFIELD_SIZE)
|
|
||||||
{
|
|
||||||
return BattleAction::makeDefend(stack);
|
|
||||||
}
|
|
||||||
BattleHex currentDest = bestNeighbor;
|
BattleHex currentDest = bestNeighbor;
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
@ -272,6 +272,7 @@ BattleAction CBattleAI::goTowards(const CStack * stack, BattleHex destination)
|
|||||||
|
|
||||||
if(vstd::contains(avHexes, currentDest))
|
if(vstd::contains(avHexes, currentDest))
|
||||||
return BattleAction::makeMove(stack, currentDest);
|
return BattleAction::makeMove(stack, currentDest);
|
||||||
|
|
||||||
currentDest = reachability.predecessors[currentDest];
|
currentDest = reachability.predecessors[currentDest];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -624,32 +625,12 @@ void CBattleAI::evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcas
|
|||||||
ps.value = totalGain;
|
ps.value = totalGain;
|
||||||
};
|
};
|
||||||
|
|
||||||
int CBattleAI::distToNearestNeighbour(BattleHex hex, const ReachabilityInfo::TDistances &dists, BattleHex *chosenHex)
|
|
||||||
{
|
|
||||||
int ret = 1000000;
|
|
||||||
for(BattleHex n : hex.neighbouringTiles())
|
|
||||||
{
|
|
||||||
if(dists[n] >= 0 && dists[n] < ret)
|
|
||||||
{
|
|
||||||
ret = dists[n];
|
|
||||||
if(chosenHex)
|
|
||||||
*chosenHex = n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CBattleAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side)
|
void CBattleAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side)
|
||||||
{
|
{
|
||||||
LOG_TRACE(logAi);
|
LOG_TRACE(logAi);
|
||||||
side = Side;
|
side = Side;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBattleAI::isCloser(const EnemyInfo &ei1, const EnemyInfo &ei2, const ReachabilityInfo::TDistances &dists)
|
|
||||||
{
|
|
||||||
return distToNearestNeighbour(ei1.s->getPosition(), dists) < distToNearestNeighbour(ei2.s->getPosition(), dists);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CBattleAI::print(const std::string &text) const
|
void CBattleAI::print(const std::string &text) const
|
||||||
{
|
{
|
||||||
logAi->trace("%s Battle AI[%p]: %s", playerID.getStr(), this, text);
|
logAi->trace("%s Battle AI[%p]: %s", playerID.getStr(), this, text);
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../lib/AI_Base.h"
|
#include "../../lib/AI_Base.h"
|
||||||
|
#include "../../lib/battle/ReachabilityInfo.h"
|
||||||
#include "PossibleSpellcast.h"
|
#include "PossibleSpellcast.h"
|
||||||
#include "PotentialTargets.h"
|
#include "PotentialTargets.h"
|
||||||
|
|
||||||
@ -64,13 +65,9 @@ public:
|
|||||||
void evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcast & ps); //for offensive damaging spells only
|
void evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcast & ps); //for offensive damaging spells only
|
||||||
|
|
||||||
BattleAction activeStack(const CStack * stack) override; //called when it's turn of that stack
|
BattleAction activeStack(const CStack * stack) override; //called when it's turn of that stack
|
||||||
BattleAction goTowards(const CStack * stack, BattleHex hex );
|
|
||||||
|
|
||||||
boost::optional<BattleAction> considerFleeingOrSurrendering();
|
boost::optional<BattleAction> considerFleeingOrSurrendering();
|
||||||
|
|
||||||
static int distToNearestNeighbour(BattleHex hex, const ReachabilityInfo::TDistances& dists, BattleHex *chosenHex = nullptr);
|
|
||||||
static bool isCloser(const EnemyInfo & ei1, const EnemyInfo & ei2, const ReachabilityInfo::TDistances & dists);
|
|
||||||
|
|
||||||
void print(const std::string &text) const;
|
void print(const std::string &text) const;
|
||||||
BattleAction useCatapult(const CStack *stack);
|
BattleAction useCatapult(const CStack *stack);
|
||||||
void battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool Side) override;
|
void battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool Side) override;
|
||||||
@ -88,4 +85,7 @@ public:
|
|||||||
//void battleTriggerEffect(const BattleTriggerEffect & bte) override;
|
//void battleTriggerEffect(const BattleTriggerEffect & bte) override;
|
||||||
//void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) override; //called by engine when battle starts; side=0 - left, side=1 - right
|
//void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) override; //called by engine when battle starts; side=0 - left, side=1 - right
|
||||||
//void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack
|
//void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack
|
||||||
|
|
||||||
|
private:
|
||||||
|
BattleAction goTowards(const CStack * stack, const battle::Unit * enemy) const;
|
||||||
};
|
};
|
||||||
|
@ -69,31 +69,6 @@ bool isMoreProfitable(const EnemyInfo &ei1, const EnemyInfo& ei2)
|
|||||||
return (ei1.adi-ei1.adr) < (ei2.adi - ei2.adr);
|
return (ei1.adi-ei1.adr) < (ei2.adi - ei2.adr);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
int distToNearestNeighbour(BattleHex hex, const ReachabilityInfo::TDistances& dists, BattleHex *chosenHex = nullptr)
|
|
||||||
{
|
|
||||||
int ret = 1000000;
|
|
||||||
for(auto & n: hex.neighbouringTiles())
|
|
||||||
{
|
|
||||||
if(dists[n] >= 0 && dists[n] < ret)
|
|
||||||
{
|
|
||||||
ret = dists[n];
|
|
||||||
if(chosenHex)
|
|
||||||
*chosenHex = n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isCloser(const EnemyInfo & ei1, const EnemyInfo & ei2, const ReachabilityInfo::TDistances & dists)
|
|
||||||
{
|
|
||||||
return distToNearestNeighbour(ei1.s->getPosition(), dists) < distToNearestNeighbour(ei2.s->getPosition(), dists);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool willSecondHexBlockMoreEnemyShooters(const BattleHex &h1, const BattleHex &h2)
|
static bool willSecondHexBlockMoreEnemyShooters(const BattleHex &h1, const BattleHex &h2)
|
||||||
{
|
{
|
||||||
int shooters[2] = {0}; //count of shooters on hexes
|
int shooters[2] = {0}; //count of shooters on hexes
|
||||||
@ -111,7 +86,7 @@ BattleAction CStupidAI::activeStack( const CStack * stack )
|
|||||||
{
|
{
|
||||||
//boost::this_thread::sleep(boost::posix_time::seconds(2));
|
//boost::this_thread::sleep(boost::posix_time::seconds(2));
|
||||||
print("activeStack called for " + stack->nodeName());
|
print("activeStack called for " + stack->nodeName());
|
||||||
auto dists = cb->battleGetDistances(stack, stack->getPosition());
|
ReachabilityInfo dists = cb->getReachability(stack);
|
||||||
std::vector<EnemyInfo> enemiesShootable, enemiesReachable, enemiesUnreachable;
|
std::vector<EnemyInfo> enemiesShootable, enemiesReachable, enemiesUnreachable;
|
||||||
|
|
||||||
if(stack->type->idNumber == CreatureID::CATAPULT)
|
if(stack->type->idNumber == CreatureID::CATAPULT)
|
||||||
@ -179,12 +154,14 @@ BattleAction CStupidAI::activeStack( const CStack * stack )
|
|||||||
}
|
}
|
||||||
else if(enemiesUnreachable.size()) //due to #955 - a buggy battle may occur when there are no enemies
|
else if(enemiesUnreachable.size()) //due to #955 - a buggy battle may occur when there are no enemies
|
||||||
{
|
{
|
||||||
assert(enemiesUnreachable.size());
|
auto closestEnemy = vstd::minElementByFun(enemiesUnreachable, [&](const EnemyInfo & ei) -> int
|
||||||
const EnemyInfo &ei= *std::min_element(enemiesUnreachable.begin(), enemiesUnreachable.end(), std::bind(isCloser, _1, _2, std::ref(dists)));
|
|
||||||
assert(ei.s);
|
|
||||||
if(distToNearestNeighbour(ei.s->getPosition(), dists) < GameConstants::BFIELD_SIZE)
|
|
||||||
{
|
{
|
||||||
return goTowards(stack, ei.s->getPosition());
|
return dists.distToNearestNeighbour(stack, ei.s);
|
||||||
|
});
|
||||||
|
|
||||||
|
if(dists.distToNearestNeighbour(stack, closestEnemy->s) < GameConstants::BFIELD_SIZE)
|
||||||
|
{
|
||||||
|
return goTowards(stack, closestEnemy->s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,11 +229,12 @@ void CStupidAI::print(const std::string &text) const
|
|||||||
logAi->trace("CStupidAI [%p]: %s", this, text);
|
logAi->trace("CStupidAI [%p]: %s", this, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
BattleAction CStupidAI::goTowards(const CStack * stack, BattleHex destination)
|
BattleAction CStupidAI::goTowards(const CStack * stack, const CStack * enemy) const
|
||||||
{
|
{
|
||||||
assert(destination.isValid());
|
assert(destination.isValid());
|
||||||
auto reachability = cb->getReachability(stack);
|
auto reachability = cb->getReachability(stack);
|
||||||
auto avHexes = cb->battleGetAvailableHexes(reachability, stack);
|
auto avHexes = cb->battleGetAvailableHexes(reachability, stack);
|
||||||
|
auto destination = enemy->getPosition();
|
||||||
|
|
||||||
if(vstd::contains(avHexes, destination))
|
if(vstd::contains(avHexes, destination))
|
||||||
return BattleAction::makeMove(stack, destination);
|
return BattleAction::makeMove(stack, destination);
|
||||||
@ -269,11 +247,14 @@ BattleAction CStupidAI::goTowards(const CStack * stack, BattleHex destination)
|
|||||||
return BattleAction::makeDefend(stack);
|
return BattleAction::makeDefend(stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
vstd::erase_if(destNeighbours, [&](BattleHex hex){ return !reachability.accessibility.accessible(hex, stack); });
|
if(!avHexes.size()) //we are blocked or dest is blocked
|
||||||
|
{
|
||||||
if(!avHexes.size() || !destNeighbours.size()) //we are blocked or dest is blocked
|
return BattleAction::makeDefend(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
BattleHex bestNeighbor = destination;
|
||||||
|
if(reachability.distToNearestNeighbour(stack, enemy, &bestNeighbor) > GameConstants::BFIELD_SIZE)
|
||||||
{
|
{
|
||||||
print("goTowards: Stack cannot move! That's " + stack->nodeName());
|
|
||||||
return BattleAction::makeDefend(stack);
|
return BattleAction::makeDefend(stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,32 +262,24 @@ BattleAction CStupidAI::goTowards(const CStack * stack, BattleHex destination)
|
|||||||
{
|
{
|
||||||
// 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 distToDestNeighbour = [&](BattleHex hex) -> int
|
auto nearestAvailableHex = vstd::minElementByFun(avHexes, [&](BattleHex hex) -> int
|
||||||
{
|
{
|
||||||
auto nearestNeighbourToHex = vstd::minElementByFun(destNeighbours, [&](BattleHex a)
|
return BattleHex::getDistance(bestNeighbor, hex);
|
||||||
{
|
});
|
||||||
return BattleHex::getDistance(a, hex);
|
|
||||||
});
|
|
||||||
|
|
||||||
return BattleHex::getDistance(*nearestNeighbourToHex, hex);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto nearestAvailableHex = vstd::minElementByFun(avHexes, distToDestNeighbour);
|
|
||||||
return BattleAction::makeMove(stack, *nearestAvailableHex);
|
return BattleAction::makeMove(stack, *nearestAvailableHex);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BattleHex bestNeighbor = destination;
|
|
||||||
if(distToNearestNeighbour(destination, reachability.distances, &bestNeighbor) > GameConstants::BFIELD_SIZE)
|
|
||||||
{
|
|
||||||
print("goTowards: Cannot reach");
|
|
||||||
return BattleAction::makeDefend(stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
BattleHex currentDest = bestNeighbor;
|
BattleHex currentDest = bestNeighbor;
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
assert(currentDest.isValid());
|
if(!currentDest.isValid())
|
||||||
|
{
|
||||||
|
logAi->error("CBattleAI::goTowards: internal error");
|
||||||
|
return BattleAction::makeDefend(stack);
|
||||||
|
}
|
||||||
|
|
||||||
if(vstd::contains(avHexes, currentDest))
|
if(vstd::contains(avHexes, currentDest))
|
||||||
return BattleAction::makeMove(stack, currentDest);
|
return BattleAction::makeMove(stack, currentDest);
|
||||||
|
|
||||||
|
@ -10,6 +10,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../../lib/battle/BattleHex.h"
|
#include "../../lib/battle/BattleHex.h"
|
||||||
|
#include "../../lib/battle/ReachabilityInfo.h"
|
||||||
|
|
||||||
|
class EnemyInfo;
|
||||||
|
|
||||||
class CStupidAI : public CBattleGameInterface
|
class CStupidAI : public CBattleGameInterface
|
||||||
{
|
{
|
||||||
@ -39,10 +42,10 @@ public:
|
|||||||
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) override; //called by engine when battle starts; side=0 - left, side=1 - right
|
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) override; //called by engine when battle starts; side=0 - left, side=1 - right
|
||||||
void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack
|
void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack
|
||||||
|
|
||||||
BattleAction goTowards(const CStack * stack, BattleHex hex );
|
|
||||||
|
|
||||||
virtual void saveGame(BinarySerializer & h, const int version) override;
|
virtual void saveGame(BinarySerializer & h, const int version) override;
|
||||||
virtual void loadGame(BinaryDeserializer & h, const int version) override;
|
virtual void loadGame(BinaryDeserializer & h, const int version) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BattleAction goTowards(const CStack * stack, const CStack * enemy) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -40,3 +40,42 @@ bool ReachabilityInfo::isReachable(BattleHex hex) const
|
|||||||
{
|
{
|
||||||
return distances[hex] < INFINITE_DIST;
|
return distances[hex] < INFINITE_DIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ReachabilityInfo::distToNearestNeighbour(
|
||||||
|
const battle::Unit * attacker,
|
||||||
|
const battle::Unit * defender,
|
||||||
|
BattleHex * chosenHex) const
|
||||||
|
{
|
||||||
|
int ret = 1000000;
|
||||||
|
auto defenderHexes = battle::Unit::getHexes(
|
||||||
|
defender->getPosition(),
|
||||||
|
defender->doubleWide(),
|
||||||
|
defender->unitSide());
|
||||||
|
|
||||||
|
std::vector<BattleHex> targetableHexes;
|
||||||
|
|
||||||
|
for(auto defenderHex : defenderHexes)
|
||||||
|
{
|
||||||
|
vstd::concatenate(targetableHexes, battle::Unit::getHexes(
|
||||||
|
defenderHex,
|
||||||
|
attacker->doubleWide(),
|
||||||
|
defender->unitSide()));
|
||||||
|
}
|
||||||
|
|
||||||
|
vstd::removeDuplicates(targetableHexes);
|
||||||
|
|
||||||
|
for(auto targetableHex : targetableHexes)
|
||||||
|
{
|
||||||
|
for(auto & n : targetableHex.neighbouringTiles())
|
||||||
|
{
|
||||||
|
if(distances[n] >= 0 && distances[n] < ret)
|
||||||
|
{
|
||||||
|
ret = distances[n];
|
||||||
|
if(chosenHex)
|
||||||
|
*chosenHex = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -43,6 +43,11 @@ struct DLL_LINKAGE ReachabilityInfo
|
|||||||
ReachabilityInfo();
|
ReachabilityInfo();
|
||||||
|
|
||||||
bool isReachable(BattleHex hex) const;
|
bool isReachable(BattleHex hex) const;
|
||||||
|
|
||||||
|
int distToNearestNeighbour(
|
||||||
|
const battle::Unit * attacker,
|
||||||
|
const battle::Unit * defender,
|
||||||
|
BattleHex * chosenHex = nullptr) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user