mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-17 20:58:07 +02:00
Unit.cpp refactor and some other minor changes
This commit is contained in:
parent
e3516120d8
commit
fb9a3da651
@ -280,7 +280,7 @@ int64_t AttackPossibility::evaluateBlockedShootersDmg(
|
||||
std::set<uint32_t> checkedUnits;
|
||||
|
||||
auto attacker = attackInfo.attacker;
|
||||
auto hexes = attacker->getSurroundingHexes(hex);
|
||||
const BattleHexArray & hexes = attacker->getSurroundingHexes(hex);
|
||||
for(BattleHex tile : hexes)
|
||||
{
|
||||
auto st = state->battleGetUnitByPos(tile, true);
|
||||
|
@ -278,7 +278,7 @@ BattleAction BattleEvaluator::selectStackAction(const CStack * stack)
|
||||
score = moveTarget.score;
|
||||
cachedAttack.ap = moveTarget.cachedAttack;
|
||||
cachedAttack.score = score;
|
||||
cachedAttack.turn = moveTarget.turnsToRich;
|
||||
cachedAttack.turn = moveTarget.turnsToReach;
|
||||
|
||||
if(stack->waited())
|
||||
{
|
||||
@ -390,11 +390,11 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, BattleHexAr
|
||||
return reachability.distances[h1] < reachability.distances[h2];
|
||||
});
|
||||
|
||||
BattleHex bestNeighbor = targetHexes.front();
|
||||
BattleHex bestNeighbour = hexes.front();
|
||||
|
||||
if(reachability.distances[bestNeighbor] > GameConstants::BFIELD_SIZE)
|
||||
if(reachability.distances[bestNeighbour] > GameConstants::BFIELD_SIZE)
|
||||
{
|
||||
logAi->trace("No richable hexes.");
|
||||
logAi->trace("No reachable hexes.");
|
||||
return BattleAction::makeDefend(stack);
|
||||
}
|
||||
|
||||
@ -421,22 +421,17 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, BattleHexAr
|
||||
{
|
||||
BattleHexArray obstacleHexes;
|
||||
|
||||
auto insertAffected = [](const CObstacleInstance & spellObst, BattleHexArray & obstacleHexes) {
|
||||
auto affectedHexes = spellObst.getAffectedTiles();
|
||||
obstacleHexes.merge(affectedHexes);
|
||||
};
|
||||
|
||||
const auto & obstacles = hb->battleGetAllObstacles();
|
||||
|
||||
for (const auto & obst : obstacles) {
|
||||
|
||||
for (const auto & obst : obstacles)
|
||||
{
|
||||
if(obst->triggersEffects())
|
||||
{
|
||||
auto triggerAbility = VLC->spells()->getById(obst->getTrigger());
|
||||
auto triggerIsNegative = triggerAbility->isNegative() || triggerAbility->isDamage();
|
||||
|
||||
if(triggerIsNegative)
|
||||
insertAffected(*obst, obstacleHexes);
|
||||
obstacleHexes.merge(obst->getAffectedTiles());
|
||||
}
|
||||
}
|
||||
// Flying stack doesn't go hex by hex, so we can't backtrack using predecessors.
|
||||
@ -446,7 +441,7 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, BattleHexAr
|
||||
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
|
||||
|
||||
auto distance = BattleHex::getDistance(bestNeighbor, hex);
|
||||
auto distance = BattleHex::getDistance(bestNeighbour, hex);
|
||||
|
||||
if(vstd::contains(obstacleHexes, hex))
|
||||
distance += NEGATIVE_OBSTACLE_PENALTY;
|
||||
@ -458,7 +453,8 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, BattleHexAr
|
||||
}
|
||||
else
|
||||
{
|
||||
BattleHex currentDest = bestNeighbor;
|
||||
BattleHex currentDest = bestNeighbour;
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(!currentDest.isValid())
|
||||
|
@ -21,7 +21,7 @@ AttackerValue::AttackerValue()
|
||||
MoveTarget::MoveTarget()
|
||||
: positions(), cachedAttack(), score(EvaluationResult::INEFFECTIVE_SCORE)
|
||||
{
|
||||
turnsToRich = 1;
|
||||
turnsToReach = 1;
|
||||
}
|
||||
|
||||
float BattleExchangeVariant::trackAttack(
|
||||
@ -361,7 +361,8 @@ MoveTarget BattleExchangeEvaluator::findMoveTowardsUnreachable(
|
||||
float penaltyMultiplier = 1.0f; // Default multiplier, no penalty
|
||||
float closestAllyDistance = std::numeric_limits<float>::max();
|
||||
|
||||
for (const battle::Unit* ally : hb->battleAliveUnits()) {
|
||||
for (const battle::Unit* ally : hb->battleAliveUnits())
|
||||
{
|
||||
if (ally == activeStack)
|
||||
continue;
|
||||
if (ally->unitSide() != activeStack->unitSide())
|
||||
@ -375,12 +376,13 @@ MoveTarget BattleExchangeEvaluator::findMoveTowardsUnreachable(
|
||||
}
|
||||
|
||||
// If an ally is closer to the enemy, compute the penaltyMultiplier
|
||||
if (closestAllyDistance < distance) {
|
||||
if (closestAllyDistance < distance)
|
||||
{
|
||||
penaltyMultiplier = closestAllyDistance / distance; // Ratio of distances
|
||||
}
|
||||
|
||||
auto turnsToRich = (distance - 1) / speed + 1;
|
||||
auto hexes = enemy->getSurroundingHexes();
|
||||
auto turnsToReach = (distance - 1) / speed + 1;
|
||||
const BattleHexArray & hexes = enemy->getSurroundingHexes();
|
||||
auto enemySpeed = enemy->getMovementRange();
|
||||
auto speedRatio = speed / static_cast<float>(enemySpeed);
|
||||
auto multiplier = (speedRatio > 1 ? 1 : speedRatio) * penaltyMultiplier;
|
||||
@ -393,16 +395,16 @@ MoveTarget BattleExchangeEvaluator::findMoveTowardsUnreachable(
|
||||
|
||||
attack.shootersBlockedDmg = 0; // we do not want to count on it, it is not for sure
|
||||
|
||||
auto score = calculateExchange(attack, turnsToRich, targets, damageCache, hb);
|
||||
auto score = calculateExchange(attack, turnsToReach, targets, damageCache, hb);
|
||||
|
||||
score.enemyDamageReduce *= multiplier;
|
||||
|
||||
#if BATTLE_TRACE_LEVEL >= 1
|
||||
logAi->trace("Multiplier: %f, turns: %d, current score %f, new score %f", multiplier, turnsToRich, result.score, scoreValue(score));
|
||||
logAi->trace("Multiplier: %f, turns: %d, current score %f, new score %f", multiplier, turnsToReach, result.score, scoreValue(score));
|
||||
#endif
|
||||
|
||||
if(result.score < scoreValue(score)
|
||||
|| (result.turnsToRich > turnsToRich && vstd::isAlmostEqual(result.score, scoreValue(score))))
|
||||
|| (result.turnsToReach > turnsToReach && vstd::isAlmostEqual(result.score, scoreValue(score))))
|
||||
{
|
||||
result.score = scoreValue(score);
|
||||
result.positions.clear();
|
||||
@ -411,10 +413,8 @@ MoveTarget BattleExchangeEvaluator::findMoveTowardsUnreachable(
|
||||
logAi->trace("New high score");
|
||||
#endif
|
||||
|
||||
for(const BattleHex & initialEnemyHex : enemy->getAttackableHexes(activeStack))
|
||||
for(BattleHex enemyHex : enemy->getAttackableHexes(activeStack))
|
||||
{
|
||||
BattleHex enemyHex = initialEnemyHex;
|
||||
|
||||
while(!flying && dists.distances[enemyHex] > speed && dists.predecessors.at(enemyHex).isValid())
|
||||
{
|
||||
enemyHex = dists.predecessors.at(enemyHex);
|
||||
@ -462,7 +462,7 @@ MoveTarget BattleExchangeEvaluator::findMoveTowardsUnreachable(
|
||||
}
|
||||
|
||||
result.cachedAttack = attack;
|
||||
result.turnsToRich = turnsToRich;
|
||||
result.turnsToReach = turnsToReach;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -484,7 +484,7 @@ std::vector<const battle::Unit *> BattleExchangeEvaluator::getAdjacentUnits(cons
|
||||
queue.pop();
|
||||
checkedStacks.push_back(stack);
|
||||
|
||||
auto hexes = stack->getSurroundingHexes();
|
||||
auto const & hexes = stack->getSurroundingHexes();
|
||||
for(auto hex : hexes)
|
||||
{
|
||||
auto neighbour = cb->battleGetUnitByPos(hex);
|
||||
@ -511,7 +511,8 @@ ReachabilityData BattleExchangeEvaluator::getExchangeUnits(
|
||||
|
||||
auto hexes = ap.attack.defender->getSurroundingHexes();
|
||||
|
||||
if(!ap.attack.shooting) hexes.insert(ap.from);
|
||||
if(!ap.attack.shooting)
|
||||
hexes.insert(ap.from);
|
||||
|
||||
std::vector<const battle::Unit *> allReachableUnits = additionalUnits;
|
||||
|
||||
@ -959,8 +960,7 @@ std::vector<const battle::Unit *> BattleExchangeEvaluator::getOneTurnReachableUn
|
||||
|
||||
if(hexStack && cb->battleMatchOwner(unit, hexStack, false))
|
||||
{
|
||||
const BattleHexArray & neighbours = BattleHexArray::neighbouringTilesCache[hex.hex];
|
||||
for(BattleHex neighbour : neighbours)
|
||||
for(BattleHex neighbour : BattleHexArray::neighbouringTilesCache[hex.hex])
|
||||
{
|
||||
reachable = unitReachability.distances.at(neighbour) <= radius;
|
||||
|
||||
|
@ -56,7 +56,7 @@ struct MoveTarget
|
||||
float score;
|
||||
BattleHexArray positions;
|
||||
std::optional<AttackPossibility> cachedAttack;
|
||||
uint8_t turnsToRich;
|
||||
uint8_t turnsToReach;
|
||||
|
||||
MoveTarget();
|
||||
};
|
||||
|
@ -55,42 +55,11 @@ BattleHex BattleHexArray::getClosestTile(BattleSide side, BattleHex initialPos)
|
||||
|
||||
auto bestTile = std::min_element(closestTiles.begin(), closestTiles.end(), compareHorizontal);
|
||||
return (bestTile != closestTiles.end()) ? *bestTile : BattleHex();
|
||||
|
||||
//BattleHex initialHex = BattleHex(initialPos);
|
||||
//auto compareDistance = [initialHex](const BattleHex left, const BattleHex right) -> bool
|
||||
//{
|
||||
// return initialHex.getDistance(initialHex, left) < initialHex.getDistance(initialHex, right);
|
||||
//};
|
||||
//BattleHexArray sortedTiles(*this);
|
||||
//boost::sort(sortedTiles, compareDistance); //closest tiles at front
|
||||
//int closestDistance = initialHex.getDistance(initialPos, sortedTiles.front()); //sometimes closest tiles can be many hexes away
|
||||
//auto notClosest = [closestDistance, initialPos](const BattleHex here) -> bool
|
||||
//{
|
||||
// return closestDistance < here.getDistance(initialPos, here);
|
||||
//};
|
||||
//vstd::erase_if(sortedTiles, notClosest); //only closest tiles are interesting
|
||||
//auto compareHorizontal = [side, initialPos](const BattleHex left, const BattleHex right) -> bool
|
||||
//{
|
||||
// if(left.getX() != right.getX())
|
||||
// {
|
||||
// if(side == BattleSide::ATTACKER)
|
||||
// return left.getX() > right.getX(); //find furthest right
|
||||
// else
|
||||
// return left.getX() < right.getX(); //find furthest left
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// //Prefer tiles in the same row.
|
||||
// return std::abs(left.getY() - initialPos.getY()) < std::abs(right.getY() - initialPos.getY());
|
||||
// }
|
||||
//};
|
||||
//boost::sort(sortedTiles, compareHorizontal);
|
||||
//return sortedTiles.front();
|
||||
}
|
||||
|
||||
BattleHexArray::NeighbouringTilesCache BattleHexArray::calculateNeighbouringTiles()
|
||||
BattleHexArray::ArrayOfBattleHexArrays BattleHexArray::calculateNeighbouringTiles()
|
||||
{
|
||||
BattleHexArray::NeighbouringTilesCache ret;
|
||||
BattleHexArray::ArrayOfBattleHexArrays ret;
|
||||
|
||||
for(si16 hex = 0; hex < GameConstants::BFIELD_SIZE; hex++)
|
||||
{
|
||||
@ -110,50 +79,75 @@ BattleHexArray BattleHexArray::generateNeighbouringTiles(BattleHex hex)
|
||||
BattleHexArray ret;
|
||||
for(auto dir : BattleHex::hexagonalDirections())
|
||||
ret.checkAndPush(hex.cloneInDirection(dir, false));
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BattleHexArray BattleHexArray::generateAttackerClosestTilesCache()
|
||||
const BattleHexArray & BattleHexArray::getNeighbouringTilesDblWide(BattleHex pos, BattleSide side)
|
||||
{
|
||||
static std::array<ArrayOfBattleHexArrays, 2> ret; // 2 -> only two valid sides: ATTACKER and DEFENDER
|
||||
size_t sideIdx = static_cast<size_t>(side);
|
||||
static bool initialized[2] = { false, false };
|
||||
|
||||
if(!initialized[sideIdx])
|
||||
{
|
||||
// first run, need to initialize
|
||||
|
||||
for(BattleHex hex = 0; hex < GameConstants::BFIELD_SIZE; hex.hex++)
|
||||
{
|
||||
BattleHexArray hexes;
|
||||
|
||||
if(side == BattleSide::ATTACKER)
|
||||
{
|
||||
const BattleHex otherHex = hex - 1;
|
||||
|
||||
for(auto dir = static_cast<BattleHex::EDir>(0); dir <= static_cast<BattleHex::EDir>(4); dir = static_cast<BattleHex::EDir>(dir + 1))
|
||||
hexes.checkAndPush(hex.cloneInDirection(dir, false));
|
||||
|
||||
hexes.checkAndPush(otherHex.cloneInDirection(BattleHex::EDir::BOTTOM_LEFT, false));
|
||||
hexes.checkAndPush(otherHex.cloneInDirection(BattleHex::EDir::LEFT, false));
|
||||
hexes.checkAndPush(otherHex.cloneInDirection(BattleHex::EDir::TOP_LEFT, false));
|
||||
}
|
||||
else if(side == BattleSide::DEFENDER)
|
||||
{
|
||||
const BattleHex otherHex = hex + 1;
|
||||
|
||||
hexes.checkAndPush(hex.cloneInDirection(BattleHex::EDir::TOP_LEFT, false));
|
||||
|
||||
for(auto dir = static_cast<BattleHex::EDir>(0); dir <= static_cast<BattleHex::EDir>(4); dir = static_cast<BattleHex::EDir>(dir + 1))
|
||||
hexes.checkAndPush(otherHex.cloneInDirection(dir, false));
|
||||
|
||||
hexes.checkAndPush(hex.cloneInDirection(BattleHex::EDir::BOTTOM_LEFT, false));
|
||||
hexes.checkAndPush(hex.cloneInDirection(BattleHex::EDir::LEFT, false));
|
||||
}
|
||||
ret[sideIdx][hex.hex] = std::move(hexes);
|
||||
}
|
||||
initialized[sideIdx] = true;
|
||||
}
|
||||
|
||||
return ret[sideIdx][pos.hex];
|
||||
}
|
||||
|
||||
const BattleHexArray & BattleHexArray::getClosestTilesCache(BattleHex pos, BattleSide side)
|
||||
{
|
||||
assert(!neighbouringTilesCache.empty());
|
||||
|
||||
BattleHexArray ret;
|
||||
static std::array<BattleHexArray, 2> ret;
|
||||
static bool initialized = false;
|
||||
size_t sideIdx = static_cast<size_t>(side);
|
||||
|
||||
ret.resize(GameConstants::BFIELD_SIZE);
|
||||
|
||||
for(si16 hex = 0; hex < GameConstants::BFIELD_SIZE; hex++)
|
||||
if(!initialized)
|
||||
{
|
||||
ret.set(hex, neighbouringTilesCache[hex].getClosestTile(BattleSide::ATTACKER, hex));
|
||||
ret[sideIdx].resize(GameConstants::BFIELD_SIZE);
|
||||
|
||||
for(si16 hex = 0; hex < GameConstants::BFIELD_SIZE; hex++)
|
||||
{
|
||||
ret[sideIdx].set(hex, neighbouringTilesCache[hex].getClosestTile(BattleSide::ATTACKER, hex));
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BattleHexArray BattleHexArray::generateDefenderClosestTilesCache()
|
||||
{
|
||||
assert(!neighbouringTilesCache.empty());
|
||||
|
||||
BattleHexArray ret;
|
||||
|
||||
ret.resize(GameConstants::BFIELD_SIZE);
|
||||
|
||||
for(si16 hex = 0; hex < GameConstants::BFIELD_SIZE; hex++)
|
||||
{
|
||||
ret.set(hex, neighbouringTilesCache[hex].getClosestTile(BattleSide::DEFENDER, hex));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BattleHex BattleHexArray::getClosestTileFromAllPossibleNeighbours(BattleSide side, BattleHex pos)
|
||||
{
|
||||
if(side == BattleSide::ATTACKER)
|
||||
return closestTilesCacheForAttacker[pos.hex];
|
||||
else if(side == BattleSide::DEFENDER)
|
||||
return closestTilesCacheForDefender[pos.hex];
|
||||
else
|
||||
assert(false); // we should never be here
|
||||
return ret[sideIdx];
|
||||
}
|
||||
|
||||
void BattleHexArray::merge(const BattleHexArray & other) noexcept
|
||||
@ -182,9 +176,6 @@ void BattleHexArray::clear() noexcept
|
||||
internalStorage.clear();
|
||||
}
|
||||
|
||||
const BattleHexArray::NeighbouringTilesCache BattleHexArray::neighbouringTilesCache = calculateNeighbouringTiles();
|
||||
|
||||
const BattleHexArray BattleHexArray::closestTilesCacheForAttacker = generateAttackerClosestTilesCache();
|
||||
const BattleHexArray BattleHexArray::closestTilesCacheForDefender = generateDefenderClosestTilesCache();
|
||||
const BattleHexArray::ArrayOfBattleHexArrays BattleHexArray::neighbouringTilesCache = calculateNeighbouringTiles();
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -33,11 +33,9 @@ public:
|
||||
using reverse_iterator = typename StorageType::reverse_iterator;
|
||||
using const_reverse_iterator = typename StorageType::const_reverse_iterator;
|
||||
|
||||
using NeighbouringTilesCache = std::array<BattleHexArray, GameConstants::BFIELD_SIZE>;
|
||||
using ArrayOfBattleHexArrays = std::array<BattleHexArray, GameConstants::BFIELD_SIZE>;
|
||||
|
||||
static const NeighbouringTilesCache neighbouringTilesCache;
|
||||
static const BattleHexArray closestTilesCacheForAttacker;
|
||||
static const BattleHexArray closestTilesCacheForDefender;
|
||||
static const ArrayOfBattleHexArrays neighbouringTilesCache;
|
||||
|
||||
BattleHexArray() noexcept
|
||||
{
|
||||
@ -130,7 +128,8 @@ public:
|
||||
return internalStorage.insert(pos, hex);
|
||||
}
|
||||
|
||||
static BattleHex getClosestTileFromAllPossibleNeighbours(BattleSide side, BattleHex pos);
|
||||
static const BattleHexArray & getClosestTilesCache(BattleHex pos, BattleSide side);
|
||||
static const BattleHexArray & getNeighbouringTilesDblWide(BattleHex pos, BattleSide side);
|
||||
|
||||
BattleHex getClosestTile(BattleSide side, BattleHex initialPos) const;
|
||||
|
||||
@ -190,7 +189,7 @@ public:
|
||||
logGlobal->warn("BattleHexArray::contains( %d ) - invalid BattleHex!", hex);
|
||||
*/
|
||||
|
||||
// return true for invalid hexes
|
||||
// returns true also for invalid hexes
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -298,10 +297,8 @@ private:
|
||||
}
|
||||
|
||||
/// returns all valid neighbouring tiles
|
||||
static BattleHexArray::NeighbouringTilesCache calculateNeighbouringTiles();
|
||||
static BattleHexArray::ArrayOfBattleHexArrays calculateNeighbouringTiles();
|
||||
static BattleHexArray generateNeighbouringTiles(BattleHex hex);
|
||||
static BattleHexArray generateAttackerClosestTilesCache();
|
||||
static BattleHexArray generateDefenderClosestTilesCache();
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -651,7 +651,7 @@ BattleHexArray CBattleInfoCallback::battleGetAvailableHexes(const battle::Unit *
|
||||
if(!otherSt->isValidTarget(false))
|
||||
continue;
|
||||
|
||||
BattleHexArray occupied = otherSt->getHexes();
|
||||
const BattleHexArray & occupied = otherSt->getHexes();
|
||||
|
||||
if(battleCanShoot(unit, otherSt->getPosition()))
|
||||
{
|
||||
@ -964,9 +964,7 @@ AccessibilityInfo CBattleInfoCallback::getAccessibility() const
|
||||
|
||||
if(bFieldType != BattleField::NONE)
|
||||
{
|
||||
BattleHexArray impassableHexes = bFieldType.getInfo()->impassableHexes;
|
||||
|
||||
for(auto hex : impassableHexes)
|
||||
for(auto hex : bFieldType.getInfo()->impassableHexes)
|
||||
ret[hex] = EAccessibility::UNAVAILABLE;
|
||||
}
|
||||
|
||||
@ -1031,20 +1029,20 @@ AccessibilityInfo CBattleInfoCallback::getAccessibility() const
|
||||
|
||||
AccessibilityInfo CBattleInfoCallback::getAccessibility(const battle::Unit * stack) const
|
||||
{
|
||||
return getAccessibility(battle::Unit::getHexes(stack->getPosition(), stack->doubleWide(), stack->unitSide()));
|
||||
return getAccessibility(& battle::Unit::getHexes(stack->getPosition(), stack->doubleWide(), stack->unitSide()));
|
||||
}
|
||||
|
||||
AccessibilityInfo CBattleInfoCallback::getAccessibility(const BattleHexArray & accessibleHexes) const
|
||||
AccessibilityInfo CBattleInfoCallback::getAccessibility(const BattleHexArray * accessibleHexes) const
|
||||
{
|
||||
auto ret = getAccessibility();
|
||||
for(auto hex : accessibleHexes)
|
||||
for(auto hex : *accessibleHexes)
|
||||
if(hex.isValid())
|
||||
ret[hex] = EAccessibility::ACCESSIBLE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo &accessibility, const ReachabilityInfo::Parameters & params) const
|
||||
ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo & accessibility, const ReachabilityInfo::Parameters & params) const
|
||||
{
|
||||
ReachabilityInfo ret;
|
||||
ret.accessibility = accessibility;
|
||||
@ -1114,11 +1112,11 @@ bool CBattleInfoCallback::isInObstacle(
|
||||
const BattleHexArray & obstacleHexes,
|
||||
const ReachabilityInfo::Parameters & params) const
|
||||
{
|
||||
auto occupiedHexes = battle::Unit::getHexes(hex, params.doubleWide, params.side);
|
||||
const BattleHexArray & occupiedHexes = battle::Unit::getHexes(hex, params.doubleWide, params.side);
|
||||
|
||||
for(auto occupiedHex : occupiedHexes)
|
||||
{
|
||||
if(params.ignoreKnownAccessible && params.knownAccessible.contains(occupiedHex))
|
||||
if(params.ignoreKnownAccessible && params.knownAccessible->contains(occupiedHex))
|
||||
continue;
|
||||
|
||||
if(obstacleHexes.contains(occupiedHex))
|
||||
@ -1146,7 +1144,7 @@ BattleHexArray CBattleInfoCallback::getStoppers(BattleSide whichSidePerspective)
|
||||
if(!battleIsObstacleVisibleForSide(*oi, whichSidePerspective))
|
||||
continue;
|
||||
|
||||
for(const auto & hex : oi->getStoppingTile())
|
||||
for(auto hex : oi->getStoppingTile())
|
||||
{
|
||||
if(hex == BattleHex::GATE_BRIDGE && oi->obstacleType == CObstacleInstance::MOAT)
|
||||
{
|
||||
@ -1162,7 +1160,6 @@ BattleHexArray CBattleInfoCallback::getStoppers(BattleSide whichSidePerspective)
|
||||
std::pair<const battle::Unit *, BattleHex> CBattleInfoCallback::getNearestStack(const battle::Unit * closest) const
|
||||
{
|
||||
auto reachability = getReachability(closest);
|
||||
auto avHexes = battleGetAvailableHexes(reachability, closest, false);
|
||||
|
||||
// I hate std::pairs with their undescriptive member names first / second
|
||||
struct DistStack
|
||||
@ -1181,7 +1178,7 @@ std::pair<const battle::Unit *, BattleHex> CBattleInfoCallback::getNearestStack(
|
||||
|
||||
for(const battle::Unit * st : possible)
|
||||
{
|
||||
for(BattleHex hex : avHexes)
|
||||
for(BattleHex hex : battleGetAvailableHexes(reachability, closest, false))
|
||||
if(CStack::isMeleeAttackPossible(closest, st, hex))
|
||||
{
|
||||
DistStack hlp = {reachability.distances[hex], hex, st};
|
||||
@ -1269,7 +1266,7 @@ ReachabilityInfo CBattleInfoCallback::getReachability(const battle::Unit * unit)
|
||||
return getReachability(params);
|
||||
}
|
||||
|
||||
ReachabilityInfo CBattleInfoCallback::getReachability(const ReachabilityInfo::Parameters ¶ms) const
|
||||
ReachabilityInfo CBattleInfoCallback::getReachability(const ReachabilityInfo::Parameters & params) const
|
||||
{
|
||||
if(params.flying)
|
||||
return getFlyingReachability(params);
|
||||
@ -1283,7 +1280,7 @@ ReachabilityInfo CBattleInfoCallback::getReachability(const ReachabilityInfo::Pa
|
||||
}
|
||||
}
|
||||
|
||||
ReachabilityInfo CBattleInfoCallback::getFlyingReachability(const ReachabilityInfo::Parameters ¶ms) const
|
||||
ReachabilityInfo CBattleInfoCallback::getFlyingReachability(const ReachabilityInfo::Parameters & params) const
|
||||
{
|
||||
ReachabilityInfo ret;
|
||||
ret.accessibility = getAccessibility(params.knownAccessible);
|
||||
@ -1340,11 +1337,11 @@ AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes(
|
||||
}
|
||||
if(attacker->hasBonusOfType(BonusType::ATTACKS_ALL_ADJACENT))
|
||||
{
|
||||
boost::copy(attacker->getSurroundingHexes(attackerPos), vstd::set_inserter(at.hostileCreaturePositions));
|
||||
at.hostileCreaturePositions.merge(attacker->getSurroundingHexes(attackerPos));
|
||||
}
|
||||
if(attacker->hasBonusOfType(BonusType::THREE_HEADED_ATTACK))
|
||||
{
|
||||
BattleHexArray hexes = attacker->getSurroundingHexes(attackerPos);
|
||||
const BattleHexArray & hexes = attacker->getSurroundingHexes(attackerPos);
|
||||
for(BattleHex tile : hexes)
|
||||
{
|
||||
if((BattleHex::mutualPosition(tile, destinationTile) > -1 && BattleHex::mutualPosition(tile, attackOriginHex) > -1)) //adjacent both to attacker's head and attacked tile
|
||||
@ -1432,9 +1429,8 @@ AttackableTiles CBattleInfoCallback::getPotentiallyShootableHexes(const battle::
|
||||
|
||||
if(attacker->hasBonusOfType(BonusType::SHOOTS_ALL_ADJACENT) && !BattleHexArray::neighbouringTilesCache[attackerPos].contains(destinationTile))
|
||||
{
|
||||
auto targetHexes = BattleHexArray::neighbouringTilesCache[destinationTile];
|
||||
targetHexes.insert(destinationTile);
|
||||
boost::copy(targetHexes, vstd::set_inserter(at.hostileCreaturePositions));
|
||||
at.hostileCreaturePositions.merge(BattleHexArray::neighbouringTilesCache[destinationTile]);
|
||||
at.hostileCreaturePositions.insert(destinationTile);
|
||||
}
|
||||
|
||||
return at;
|
||||
|
@ -162,7 +162,7 @@ public:
|
||||
ReachabilityInfo getReachability(const ReachabilityInfo::Parameters & params) const;
|
||||
AccessibilityInfo getAccessibility() const;
|
||||
AccessibilityInfo getAccessibility(const battle::Unit * stack) const; //Hexes occupied by stack will be marked as accessible.
|
||||
AccessibilityInfo getAccessibility(const BattleHexArray & accessibleHexes) const; //given hexes will be marked as accessible
|
||||
AccessibilityInfo getAccessibility(const BattleHexArray * accessibleHexes) const; //given hexes will be marked as accessible
|
||||
std::pair<const battle::Unit *, BattleHex> getNearestStack(const battle::Unit * closest) const;
|
||||
|
||||
BattleHex getAvailableHex(const CreatureID & creID, BattleSide side, int initialPos = -1) const; //find place for adding new stack
|
||||
|
@ -21,7 +21,7 @@ ReachabilityInfo::Parameters::Parameters(const battle::Unit * Stack, BattleHex S
|
||||
side(Stack->unitSide()),
|
||||
flying(Stack->hasBonusOfType(BonusType::FLYING))
|
||||
{
|
||||
knownAccessible = battle::Unit::getHexes(startPosition, doubleWide, side);
|
||||
knownAccessible = & battle::Unit::getHexes(startPosition, doubleWide, side);
|
||||
destructibleEnemyTurns.fill(-1);
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ struct DLL_LINKAGE ReachabilityInfo
|
||||
bool flying = false;
|
||||
bool ignoreKnownAccessible = false; //Ignore obstacles if it is in accessible hexes
|
||||
bool bypassEnemyStacks = false; // in case of true will count amount of turns needed to kill enemy and thus move forward
|
||||
BattleHexArray knownAccessible; //hexes that will be treated as accessible, even if they're occupied by stack (by default - tiles occupied by stack we do reachability for, so it doesn't block itself)
|
||||
const BattleHexArray * knownAccessible; //hexes that will be treated as accessible, even if they're occupied by stack (by default - tiles occupied by stack we do reachability for, so it doesn't block itself)
|
||||
std::array<int8_t, GameConstants::BFIELD_SIZE> destructibleEnemyTurns; // how many turns it is needed to kill enemy on specific hex (index <=> hex)
|
||||
|
||||
BattleHex startPosition; //assumed position of stack
|
||||
|
@ -51,53 +51,26 @@ const IBonusBearer* Unit::getBonusBearer() const
|
||||
return this;
|
||||
}
|
||||
|
||||
BattleHexArray Unit::getSurroundingHexes(BattleHex assumedPosition) const
|
||||
const BattleHexArray & Unit::getSurroundingHexes(BattleHex assumedPosition) const
|
||||
{
|
||||
BattleHex hex = (assumedPosition != BattleHex::INVALID) ? assumedPosition : getPosition(); //use hypothetical position
|
||||
|
||||
return getSurroundingHexes(hex, doubleWide(), unitSide());
|
||||
}
|
||||
|
||||
BattleHexArray Unit::getSurroundingHexes(BattleHex position, bool twoHex, BattleSide side)
|
||||
const BattleHexArray & Unit::getSurroundingHexes(BattleHex position, bool twoHex, BattleSide side)
|
||||
{
|
||||
if(!position.isValid())
|
||||
return { };
|
||||
|
||||
BattleHexArray hexes;
|
||||
if(twoHex)
|
||||
{
|
||||
const BattleHex otherHex = occupiedHex(position, twoHex, side);
|
||||
|
||||
if(side == BattleSide::ATTACKER)
|
||||
{
|
||||
for(auto dir = static_cast<BattleHex::EDir>(0); dir <= static_cast<BattleHex::EDir>(4); dir = static_cast<BattleHex::EDir>(dir + 1))
|
||||
hexes.checkAndPush(position.cloneInDirection(dir, false));
|
||||
|
||||
hexes.checkAndPush(otherHex.cloneInDirection(BattleHex::EDir::BOTTOM_LEFT, false));
|
||||
hexes.checkAndPush(otherHex.cloneInDirection(BattleHex::EDir::LEFT, false));
|
||||
hexes.checkAndPush(otherHex.cloneInDirection(BattleHex::EDir::TOP_LEFT, false));
|
||||
}
|
||||
else
|
||||
{
|
||||
hexes.checkAndPush(position.cloneInDirection(BattleHex::EDir::TOP_LEFT, false));
|
||||
|
||||
for(auto dir = static_cast<BattleHex::EDir>(0); dir <= static_cast<BattleHex::EDir>(4); dir = static_cast<BattleHex::EDir>(dir + 1))
|
||||
hexes.checkAndPush(otherHex.cloneInDirection(dir, false));
|
||||
|
||||
hexes.checkAndPush(position.cloneInDirection(BattleHex::EDir::BOTTOM_LEFT, false));
|
||||
hexes.checkAndPush(position.cloneInDirection(BattleHex::EDir::LEFT, false));
|
||||
}
|
||||
return hexes;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(position.isValid()); // check outside if position isValid
|
||||
|
||||
if(!twoHex)
|
||||
return BattleHexArray::neighbouringTilesCache[position];
|
||||
}
|
||||
|
||||
return BattleHexArray::getNeighbouringTilesDblWide(position, side);
|
||||
}
|
||||
|
||||
BattleHexArray Unit::getAttackableHexes(const Unit * attacker) const
|
||||
{
|
||||
auto defenderHexes = battle::Unit::getHexes(
|
||||
const BattleHexArray & defenderHexes = battle::Unit::getHexes(
|
||||
getPosition(),
|
||||
doubleWide(),
|
||||
unitSide());
|
||||
@ -126,25 +99,35 @@ bool Unit::coversPos(BattleHex pos) const
|
||||
return getPosition() == pos || (doubleWide() && (occupiedHex() == pos));
|
||||
}
|
||||
|
||||
BattleHexArray Unit::getHexes() const
|
||||
const BattleHexArray & Unit::getHexes() const
|
||||
{
|
||||
return getHexes(getPosition(), doubleWide(), unitSide());
|
||||
}
|
||||
|
||||
BattleHexArray Unit::getHexes(BattleHex assumedPos) const
|
||||
const BattleHexArray & Unit::getHexes(BattleHex assumedPos) const
|
||||
{
|
||||
return getHexes(assumedPos, doubleWide(), unitSide());
|
||||
}
|
||||
|
||||
BattleHexArray Unit::getHexes(BattleHex assumedPos, bool twoHex, BattleSide side)
|
||||
const BattleHexArray & Unit::getHexes(BattleHex assumedPos, bool twoHex, BattleSide side)
|
||||
{
|
||||
static BattleHexArray::ArrayOfBattleHexArrays cache[4];
|
||||
int index = side == BattleSide::ATTACKER ? 0 : 2;
|
||||
|
||||
if(!cache[index + twoHex][assumedPos].empty())
|
||||
return cache[index + twoHex][assumedPos];
|
||||
|
||||
// first run, initialize
|
||||
|
||||
BattleHexArray hexes;
|
||||
hexes.insert(assumedPos);
|
||||
|
||||
if(twoHex)
|
||||
hexes.insert(occupiedHex(assumedPos, twoHex, side));
|
||||
|
||||
return hexes;
|
||||
cache[index + twoHex][assumedPos] = std::move(hexes);
|
||||
|
||||
return cache[index + twoHex][assumedPos];
|
||||
}
|
||||
|
||||
BattleHex Unit::occupiedHex() const
|
||||
|
@ -127,15 +127,15 @@ public:
|
||||
|
||||
virtual std::string getDescription() const;
|
||||
|
||||
BattleHexArray getSurroundingHexes(BattleHex assumedPosition = BattleHex::INVALID) const; // get six or 8 surrounding hexes depending on creature size
|
||||
const BattleHexArray & getSurroundingHexes(BattleHex assumedPosition = BattleHex::INVALID) const; // get six or 8 surrounding hexes depending on creature size
|
||||
BattleHexArray getAttackableHexes(const Unit * attacker) const;
|
||||
static BattleHexArray getSurroundingHexes(BattleHex position, bool twoHex, BattleSide side);
|
||||
static const BattleHexArray & getSurroundingHexes(BattleHex position, bool twoHex, BattleSide side);
|
||||
|
||||
bool coversPos(BattleHex position) const; //checks also if unit is double-wide
|
||||
|
||||
BattleHexArray getHexes() const; //up to two occupied hexes, starting from front
|
||||
BattleHexArray getHexes(BattleHex assumedPos) const; //up to two occupied hexes, starting from front
|
||||
static BattleHexArray getHexes(BattleHex assumedPos, bool twoHex, BattleSide side);
|
||||
const BattleHexArray & getHexes() const; //up to two occupied hexes, starting from front
|
||||
const BattleHexArray & getHexes(BattleHex assumedPos) const; //up to two occupied hexes, starting from front
|
||||
static const BattleHexArray & getHexes(BattleHex assumedPos, bool twoHex, BattleSide side);
|
||||
|
||||
BattleHex occupiedHex() const; //returns number of occupied hex (not the position) if stack is double wide; otherwise -1
|
||||
BattleHex occupiedHex(BattleHex assumedPos) const; //returns number of occupied hex (not the position) if stack is double wide and would stand on assumedPos; otherwise -1
|
||||
|
Loading…
x
Reference in New Issue
Block a user