1
0
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:
MichalZr6 2024-12-04 21:37:31 +01:00
parent e3516120d8
commit fb9a3da651
12 changed files with 142 additions and 179 deletions

View File

@ -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);

View File

@ -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())

View File

@ -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;

View File

@ -56,7 +56,7 @@ struct MoveTarget
float score;
BattleHexArray positions;
std::optional<AttackPossibility> cachedAttack;
uint8_t turnsToRich;
uint8_t turnsToReach;
MoveTarget();
};

View File

@ -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

View File

@ -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

View File

@ -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 &params) 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 &params) 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;

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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