mirror of
https://github.com/vcmi/vcmi.git
synced 2025-02-21 19:19:26 +02:00
Changes following review:
- shared_ptr for destructibleEnemyTurns instead of raw pointer - drop implicit int conversion for BattleHex class and implement toInt() instead - implement necessary operators in BattleHex - adjust code to work properly with JSON serializer
This commit is contained in:
parent
4031006317
commit
dbe82b94f6
@ -280,7 +280,7 @@ int64_t AttackPossibility::evaluateBlockedShootersDmg(
|
||||
std::set<uint32_t> checkedUnits;
|
||||
|
||||
auto attacker = attackInfo.attacker;
|
||||
const BattleHexArray & hexes = attacker->getSurroundingHexes(hex);
|
||||
const auto & hexes = attacker->getSurroundingHexes(hex);
|
||||
for(BattleHex tile : hexes)
|
||||
{
|
||||
auto st = state->battleGetUnitByPos(tile, true);
|
||||
|
@ -214,8 +214,8 @@ BattleAction BattleEvaluator::selectStackAction(const CStack * stack)
|
||||
bestAttack.attackerState->unitType()->getJsonKey(),
|
||||
bestAttack.affectedUnits[0]->unitType()->getJsonKey(),
|
||||
bestAttack.affectedUnits[0]->getCount(),
|
||||
(int)bestAttack.from,
|
||||
(int)bestAttack.attack.attacker->getPosition(),
|
||||
bestAttack.from.toInt(),
|
||||
bestAttack.attack.attacker->getPosition().toInt(),
|
||||
bestAttack.attack.chargeDistance,
|
||||
bestAttack.attack.attacker->getMovementRange(0),
|
||||
bestAttack.defenderDamageReduce,
|
||||
@ -355,7 +355,7 @@ BattleAction BattleEvaluator::moveOrAttack(const CStack * stack, BattleHex hex,
|
||||
}
|
||||
}
|
||||
|
||||
BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, BattleHexArray hexes, const PotentialTargets & targets)
|
||||
BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, const BattleHexArray & hexes, const PotentialTargets & targets)
|
||||
{
|
||||
auto reachability = cb->getBattle(battleID)->getReachability(stack);
|
||||
auto avHexes = cb->getBattle(battleID)->battleGetAvailableHexes(reachability, stack, false);
|
||||
@ -387,12 +387,12 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, BattleHexAr
|
||||
|
||||
std::sort(targetHexes.begin(), targetHexes.end(), [&](BattleHex h1, BattleHex h2) -> bool
|
||||
{
|
||||
return reachability.distances[h1] < reachability.distances[h2];
|
||||
return reachability.distances[h1.toInt()] < reachability.distances[h2.toInt()];
|
||||
});
|
||||
|
||||
BattleHex bestNeighbour = hexes.front();
|
||||
|
||||
if(reachability.distances[bestNeighbour] > GameConstants::BFIELD_SIZE)
|
||||
if(reachability.distances[bestNeighbour.toInt()] > GameConstants::BFIELD_SIZE)
|
||||
{
|
||||
logAi->trace("No reachable hexes.");
|
||||
return BattleAction::makeDefend(stack);
|
||||
@ -468,7 +468,7 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, BattleHexAr
|
||||
return moveOrAttack(stack, currentDest, targets);
|
||||
}
|
||||
|
||||
currentDest = reachability.predecessors[currentDest];
|
||||
currentDest = reachability.predecessors[currentDest.toInt()];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ public:
|
||||
bool attemptCastingSpell(const CStack * stack);
|
||||
bool canCastSpell();
|
||||
std::optional<PossibleSpellcast> findBestCreatureSpell(const CStack * stack);
|
||||
BattleAction goTowardsNearest(const CStack * stack, BattleHexArray hexes, const PotentialTargets & targets);
|
||||
BattleAction goTowardsNearest(const CStack * stack, const BattleHexArray & hexes, const PotentialTargets & targets);
|
||||
std::vector<BattleHex> getBrokenWallMoatHexes() const;
|
||||
bool hasWorkingTowers() const;
|
||||
void evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcast & ps); //for offensive damaging spells only
|
||||
|
@ -310,7 +310,7 @@ ReachabilityInfo getReachabilityWithEnemyBypass(
|
||||
|
||||
for(auto & hex : unit->getHexes())
|
||||
if(hex.isAvailable()) //towers can have <0 pos; we don't also want to overwrite side columns
|
||||
params.destructibleEnemyTurns[hex] = turnsToKill * unit->getMovementRange();
|
||||
params.destructibleEnemyTurns[hex.toInt()] = turnsToKill * unit->getMovementRange();
|
||||
}
|
||||
|
||||
params.bypassEnemyStacks = true;
|
||||
@ -415,11 +415,11 @@ MoveTarget BattleExchangeEvaluator::findMoveTowardsUnreachable(
|
||||
|
||||
for(BattleHex enemyHex : enemy->getAttackableHexes(activeStack))
|
||||
{
|
||||
while(!flying && dists.distances[enemyHex] > speed && dists.predecessors.at(enemyHex).isValid())
|
||||
while(!flying && dists.distances[enemyHex.toInt()] > speed && dists.predecessors.at(enemyHex.toInt()).isValid())
|
||||
{
|
||||
enemyHex = dists.predecessors.at(enemyHex);
|
||||
enemyHex = dists.predecessors.at(enemyHex.toInt());
|
||||
|
||||
if(dists.accessibility[enemyHex] == EAccessibility::ALIVE_STACK)
|
||||
if(dists.accessibility[enemyHex.toInt()] == EAccessibility::ALIVE_STACK)
|
||||
{
|
||||
auto defenderToBypass = hb->battleGetUnitByPos(enemyHex);
|
||||
|
||||
@ -429,7 +429,7 @@ MoveTarget BattleExchangeEvaluator::findMoveTowardsUnreachable(
|
||||
logAi->trace("Found target to bypass at %d", enemyHex.hex);
|
||||
#endif
|
||||
|
||||
auto attackHex = dists.predecessors[enemyHex];
|
||||
auto attackHex = dists.predecessors[enemyHex.toInt()];
|
||||
auto baiBypass = BattleAttackInfo(activeStack, defenderToBypass, 0, cb->battleCanShoot(activeStack));
|
||||
auto attackBypass = AttackPossibility::evaluate(baiBypass, attackHex, damageCache, hb);
|
||||
|
||||
@ -440,7 +440,7 @@ MoveTarget BattleExchangeEvaluator::findMoveTowardsUnreachable(
|
||||
|
||||
auto bypassScore = calculateExchange(
|
||||
attackBypass,
|
||||
dists.distances[attackHex],
|
||||
dists.distances[attackHex.toInt()],
|
||||
targets,
|
||||
damageCache,
|
||||
hb,
|
||||
@ -916,8 +916,7 @@ void BattleExchangeEvaluator::updateReachabilityMap(std::shared_ptr<HypotheticBa
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(BattleHex hex = BattleHex::TOP_LEFT; hex.isValid(); hex = hex + 1)
|
||||
for(BattleHex hex = BattleHex::TOP_LEFT; hex.isValid(); ++hex)
|
||||
{
|
||||
reachabilityMap[hex] = getOneTurnReachableUnits(0, hex);
|
||||
}
|
||||
@ -952,9 +951,9 @@ std::vector<const battle::Unit *> BattleExchangeEvaluator::getOneTurnReachableUn
|
||||
|
||||
ReachabilityInfo unitReachability = reachabilityIter != reachabilityCache.end() ? reachabilityIter->second : turnBattle.getReachability(unit);
|
||||
|
||||
bool reachable = unitReachability.distances.at(hex) <= radius;
|
||||
bool reachable = unitReachability.distances.at(hex.toInt()) <= radius;
|
||||
|
||||
if(!reachable && unitReachability.accessibility[hex] == EAccessibility::ALIVE_STACK)
|
||||
if(!reachable && unitReachability.accessibility[hex.toInt()] == EAccessibility::ALIVE_STACK)
|
||||
{
|
||||
const battle::Unit * hexStack = cb->battleGetUnitByPos(hex);
|
||||
|
||||
@ -962,7 +961,7 @@ std::vector<const battle::Unit *> BattleExchangeEvaluator::getOneTurnReachableUn
|
||||
{
|
||||
for(BattleHex neighbour : hex.getNeighbouringTiles())
|
||||
{
|
||||
reachable = unitReachability.distances.at(neighbour) <= radius;
|
||||
reachable = unitReachability.distances.at(neighbour.toInt()) <= radius;
|
||||
|
||||
if(reachable) break;
|
||||
}
|
||||
@ -1009,12 +1008,12 @@ bool BattleExchangeEvaluator::checkPositionBlocksOurStacks(HypotheticBattle & hb
|
||||
auto unitReachability = turnBattle.getReachability(unit);
|
||||
auto unitSpeed = unit->getMovementRange(turn); // Cached value, to avoid performance hit
|
||||
|
||||
for(BattleHex hex = BattleHex::TOP_LEFT; hex.isValid(); hex = hex + 1)
|
||||
for(BattleHex hex = BattleHex::TOP_LEFT; hex.isValid(); hex++)
|
||||
{
|
||||
bool enemyUnit = false;
|
||||
bool reachable = unitReachability.distances.at(hex) <= unitSpeed;
|
||||
bool reachable = unitReachability.distances.at(hex.toInt()) <= unitSpeed;
|
||||
|
||||
if(!reachable && unitReachability.accessibility[hex] == EAccessibility::ALIVE_STACK)
|
||||
if(!reachable && unitReachability.accessibility[hex.toInt()] == EAccessibility::ALIVE_STACK)
|
||||
{
|
||||
const battle::Unit * hexStack = turnBattle.battleGetUnitByPos(hex);
|
||||
|
||||
@ -1023,7 +1022,7 @@ bool BattleExchangeEvaluator::checkPositionBlocksOurStacks(HypotheticBattle & hb
|
||||
enemyUnit = true;
|
||||
for(BattleHex neighbour : hex.getNeighbouringTiles())
|
||||
{
|
||||
reachable = unitReachability.distances.at(neighbour) <= unitSpeed;
|
||||
reachable = unitReachability.distances.at(neighbour.toInt()) <= unitSpeed;
|
||||
|
||||
if(reachable) break;
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ PotentialTargets::PotentialTargets(
|
||||
|
||||
auto GenerateAttackInfo = [&](bool shooting, BattleHex hex) -> AttackPossibility
|
||||
{
|
||||
int distance = hex.isValid() ? reachability.distances[hex] : 0;
|
||||
int distance = hex.isValid() ? reachability.distances[hex.toInt()] : 0;
|
||||
auto bai = BattleAttackInfo(attackerInfo, defender, distance, shooting);
|
||||
|
||||
return AttackPossibility::evaluate(bai, hex, damageCache, state);
|
||||
|
@ -291,7 +291,7 @@ BattleAction CStupidAI::goTowards(const BattleID & battleID, const CStack * stac
|
||||
|
||||
std::sort(hexes.begin(), hexes.end(), [&](BattleHex h1, BattleHex h2) -> bool
|
||||
{
|
||||
return reachability.distances[h1] < reachability.distances[h2];
|
||||
return reachability.distances[h1.toInt()] < reachability.distances[h2.toInt()];
|
||||
});
|
||||
|
||||
for(auto hex : hexes)
|
||||
@ -313,7 +313,7 @@ BattleAction CStupidAI::goTowards(const BattleID & battleID, const CStack * stac
|
||||
|
||||
BattleHex bestneighbour = hexes.front();
|
||||
|
||||
if(reachability.distances[bestneighbour] > GameConstants::BFIELD_SIZE)
|
||||
if(reachability.distances[bestneighbour.toInt()] > GameConstants::BFIELD_SIZE)
|
||||
{
|
||||
return BattleAction::makeDefend(stack);
|
||||
}
|
||||
@ -347,7 +347,7 @@ BattleAction CStupidAI::goTowards(const BattleID & battleID, const CStack * stac
|
||||
return BattleAction::makeMove(stack, currentDest);
|
||||
}
|
||||
|
||||
currentDest = reachability.predecessors[currentDest];
|
||||
currentDest = reachability.predecessors[currentDest.toInt()];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -522,7 +522,7 @@ std::string BattleActionsController::actionGetStatusMessage(PossiblePlayerBattle
|
||||
{
|
||||
const auto * attacker = owner.stacksController->getActiveStack();
|
||||
BattleHex attackFromHex = owner.fieldController->fromWhichHexAttack(targetHex);
|
||||
int distance = attacker->position.isValid() ? owner.getBattle()->battleGetDistances(attacker, attacker->getPosition())[attackFromHex] : 0;
|
||||
int distance = attacker->position.isValid() ? owner.getBattle()->battleGetDistances(attacker, attacker->getPosition())[attackFromHex.toInt()] : 0;
|
||||
DamageEstimation retaliation;
|
||||
BattleAttackInfo attackInfo(attacker, targetStack, distance, false );
|
||||
DamageEstimation estimation = owner.getBattle()->battleEstimateDamage(attackInfo, &retaliation);
|
||||
|
@ -174,7 +174,7 @@ AttackAnimation::AttackAnimation(BattleInterface & owner, const CStack *attacker
|
||||
attackingStack(attacker)
|
||||
{
|
||||
assert(attackingStack && "attackingStack is nullptr in CBattleAttack::CBattleAttack !\n");
|
||||
attackingStackPosBeforeReturn = attackingStack->getPosition();
|
||||
attackingStackPosBeforeReturn = attackingStack->getPosition().toInt();
|
||||
}
|
||||
|
||||
HittedAnimation::HittedAnimation(BattleInterface & owner, const CStack * stack)
|
||||
|
@ -839,7 +839,7 @@ void BattleFieldController::updateAccessibleHexes()
|
||||
|
||||
bool BattleFieldController::stackCountOutsideHex(const BattleHex & number) const
|
||||
{
|
||||
return stackCountOutsideHexes[number];
|
||||
return stackCountOutsideHexes[number.toInt()];
|
||||
}
|
||||
|
||||
void BattleFieldController::showAll(Canvas & to)
|
||||
|
@ -185,7 +185,7 @@ BattleSiegeController::BattleSiegeController(BattleInterface & owner, const CGTo
|
||||
|
||||
const CCreature *BattleSiegeController::getTurretCreature(BattleHex position) const
|
||||
{
|
||||
switch (position)
|
||||
switch (position.toInt())
|
||||
{
|
||||
case BattleHex::CASTLE_CENTRAL_TOWER:
|
||||
return town->fortificationsLevel().citadelShooter.toCreature();
|
||||
@ -195,14 +195,14 @@ const CCreature *BattleSiegeController::getTurretCreature(BattleHex position) co
|
||||
return town->fortificationsLevel().lowerTowerShooter.toCreature();
|
||||
}
|
||||
|
||||
throw std::runtime_error("Unable to select shooter for tower at " + std::to_string(position));
|
||||
throw std::runtime_error("Unable to select shooter for tower at " + std::to_string(position.toInt()));
|
||||
}
|
||||
|
||||
Point BattleSiegeController::getTurretCreaturePosition( BattleHex position ) const
|
||||
{
|
||||
// Turret positions are read out of the config/wall_pos.txt
|
||||
int posID = 0;
|
||||
switch (position)
|
||||
switch (position.toInt())
|
||||
{
|
||||
case BattleHex::CASTLE_CENTRAL_TOWER: // keep creature
|
||||
posID = EWallVisual::CREATURE_KEEP;
|
||||
|
@ -252,8 +252,8 @@ BattleHexArray CStack::meleeAttackHexes(const battle::Unit * attacker, const bat
|
||||
if (!defenderPos.isValid())
|
||||
defenderPos = defender->getPosition();
|
||||
|
||||
BattleHex otherAttackerPos = attackerPos + (attacker->unitSide() == BattleSide::ATTACKER ? -1 : 1);
|
||||
BattleHex otherDefenderPos = defenderPos + (defender->unitSide() == BattleSide::ATTACKER ? -1 : 1);
|
||||
BattleHex otherAttackerPos = attackerPos.toInt() + (attacker->unitSide() == BattleSide::ATTACKER ? -1 : 1);
|
||||
BattleHex otherDefenderPos = defenderPos.toInt() + (defender->unitSide() == BattleSide::ATTACKER ? -1 : 1);
|
||||
|
||||
if(BattleHex::mutualPosition(attackerPos, defenderPos) >= 0) //front <=> front
|
||||
{
|
||||
|
@ -66,7 +66,7 @@ BattleHexArray ObstacleInfo::getBlocked(BattleHex hex) const
|
||||
BattleHexArray ret;
|
||||
for(int offset : blockedTiles)
|
||||
{
|
||||
BattleHex toBlock = hex + offset;
|
||||
BattleHex toBlock = hex.toInt() + offset;
|
||||
if((hex.getY() & 1) && !(toBlock.getY() & 1))
|
||||
toBlock += BattleHex::LEFT;
|
||||
|
||||
|
@ -18,14 +18,14 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
bool AccessibilityInfo::tileAccessibleWithGate(BattleHex tile, BattleSide side) const
|
||||
{
|
||||
//at(otherHex) != EAccessibility::ACCESSIBLE && (at(otherHex) != EAccessibility::GATE || side != BattleSide::DEFENDER)
|
||||
const auto & accessibility = at(tile);
|
||||
const auto & accessibility = at(tile.toInt());
|
||||
|
||||
if(accessibility == EAccessibility::ALIVE_STACK)
|
||||
{
|
||||
if(!destructibleEnemyTurns)
|
||||
return false;
|
||||
|
||||
return destructibleEnemyTurns->at(tile) >= 0;
|
||||
return destructibleEnemyTurns->at(tile.toInt()) >= 0;
|
||||
}
|
||||
|
||||
if(accessibility != EAccessibility::ACCESSIBLE)
|
||||
|
@ -32,10 +32,11 @@ enum class EAccessibility
|
||||
|
||||
|
||||
using TAccessibilityArray = std::array<EAccessibility, GameConstants::BFIELD_SIZE>;
|
||||
using TBattlefieldTurnsArray = std::array<int8_t, GameConstants::BFIELD_SIZE>;
|
||||
|
||||
struct DLL_LINKAGE AccessibilityInfo : TAccessibilityArray
|
||||
{
|
||||
const std::array<int8_t, GameConstants::BFIELD_SIZE> * destructibleEnemyTurns = nullptr;
|
||||
std::shared_ptr<const TBattlefieldTurnsArray> destructibleEnemyTurns; //used only as a view for destructibleEnemyTurns from ReachabilityInfo::Parameters
|
||||
|
||||
public:
|
||||
bool accessible(BattleHex tile, const battle::Unit * stack) const; //checks for both tiles if stack is double wide
|
||||
|
@ -48,24 +48,24 @@ BattleHex BattleHex::getClosestTile(BattleSide side, BattleHex initialPos, const
|
||||
return (bestTile != closestTiles.end()) ? *bestTile : BattleHex();
|
||||
}
|
||||
|
||||
const BattleHexArray & BattleHex::getAllNeighbouringTiles() const
|
||||
const BattleHexArray & BattleHex::getAllNeighbouringTiles() const noexcept
|
||||
{
|
||||
return BattleHexArray::getAllNeighbouringTiles(*this);
|
||||
}
|
||||
|
||||
const BattleHexArray & BattleHex::getNeighbouringTiles() const
|
||||
const BattleHexArray & BattleHex::getNeighbouringTiles() const noexcept
|
||||
{
|
||||
return BattleHexArray::getNeighbouringTiles(*this);
|
||||
}
|
||||
|
||||
const BattleHexArray & BattleHex::getNeighbouringTilesDblWide(BattleSide side) const
|
||||
const BattleHexArray & BattleHex::getNeighbouringTilesDoubleWide(BattleSide side) const noexcept
|
||||
{
|
||||
return BattleHexArray::getNeighbouringTilesDblWide(*this, side);
|
||||
return BattleHexArray::getNeighbouringTilesDoubleWide(*this, side);
|
||||
}
|
||||
|
||||
std::ostream & operator<<(std::ostream & os, const BattleHex & hex)
|
||||
{
|
||||
return os << boost::str(boost::format("{BattleHex: x '%d', y '%d', hex '%d'}") % hex.getX() % hex.getY() % static_cast<si16>(hex));
|
||||
return os << boost::str(boost::format("{BattleHex: x '%d', y '%d', hex '%d'}") % hex.getX() % hex.getY() % hex.toInt());
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -24,7 +24,8 @@ namespace GameConstants
|
||||
|
||||
class BattleHexArray;
|
||||
|
||||
// for battle stacks' positions
|
||||
// for battle stacks' positions; valid hexes are from 0 to 186; available are only those not in first and last column
|
||||
// castle towers are -2, -3 and -4
|
||||
class DLL_LINKAGE BattleHex
|
||||
{
|
||||
public:
|
||||
@ -68,10 +69,10 @@ public:
|
||||
BOTTOM
|
||||
};
|
||||
|
||||
BattleHex()
|
||||
BattleHex() noexcept
|
||||
: hex(INVALID)
|
||||
{}
|
||||
BattleHex(si16 _hex)
|
||||
BattleHex(si16 _hex) noexcept
|
||||
: hex(_hex)
|
||||
{}
|
||||
BattleHex(si16 x, si16 y)
|
||||
@ -82,17 +83,13 @@ public:
|
||||
{
|
||||
setXY(xy);
|
||||
}
|
||||
operator si16() const
|
||||
{
|
||||
return hex;
|
||||
}
|
||||
|
||||
inline bool isValid() const
|
||||
[[nodiscard]] bool isValid() const noexcept
|
||||
{
|
||||
return hex >= 0 && hex < GameConstants::BFIELD_SIZE;
|
||||
}
|
||||
|
||||
bool isAvailable() const //valid position not in first or last column
|
||||
[[nodiscard]] bool isAvailable() const noexcept //valid position not in first or last column
|
||||
{
|
||||
return isValid() && getX() > 0 && getX() < GameConstants::BFIELD_WIDTH - 1;
|
||||
}
|
||||
@ -123,17 +120,17 @@ public:
|
||||
setXY(xy.first, xy.second);
|
||||
}
|
||||
|
||||
si16 getX() const
|
||||
[[nodiscard]] si16 getX() const noexcept
|
||||
{
|
||||
return hex % GameConstants::BFIELD_WIDTH;
|
||||
}
|
||||
|
||||
si16 getY() const
|
||||
[[nodiscard]] si16 getY() const noexcept
|
||||
{
|
||||
return hex / GameConstants::BFIELD_WIDTH;
|
||||
}
|
||||
|
||||
std::pair<si16, si16> getXY() const
|
||||
[[nodiscard]] std::pair<si16, si16> getXY() const noexcept
|
||||
{
|
||||
return std::make_pair(getX(), getY());
|
||||
}
|
||||
@ -171,24 +168,14 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
BattleHex & operator+=(EDir dir)
|
||||
{
|
||||
return moveInDirection(dir);
|
||||
}
|
||||
|
||||
BattleHex operator+(EDir dir) const
|
||||
{
|
||||
return cloneInDirection(dir);
|
||||
}
|
||||
|
||||
BattleHex cloneInDirection(EDir dir, bool hasToBeValid = true) const
|
||||
[[nodiscard]] BattleHex cloneInDirection(EDir dir, bool hasToBeValid = true) const
|
||||
{
|
||||
BattleHex result(hex);
|
||||
result.moveInDirection(dir, hasToBeValid);
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint8_t getDistance(BattleHex hex1, BattleHex hex2)
|
||||
[[nodiscard]] static uint8_t getDistance(BattleHex hex1, BattleHex hex2) noexcept
|
||||
{
|
||||
int y1 = hex1.getY();
|
||||
int y2 = hex2.getY();
|
||||
@ -205,15 +192,15 @@ public:
|
||||
return std::abs(xDst) + std::abs(yDst);
|
||||
}
|
||||
|
||||
static BattleHex getClosestTile(BattleSide side, BattleHex initialPos, const BattleHexArray & hexes);
|
||||
[[nodiscard]] static BattleHex getClosestTile(BattleSide side, BattleHex initialPos, const BattleHexArray & hexes);
|
||||
|
||||
//Constexpr defined array with all directions used in battle
|
||||
static constexpr auto hexagonalDirections()
|
||||
[[nodiscard]] static constexpr auto hexagonalDirections() noexcept
|
||||
{
|
||||
return std::array<EDir,6>{TOP_LEFT, TOP_RIGHT, RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT, LEFT};
|
||||
}
|
||||
|
||||
static EDir mutualPosition(BattleHex hex1, BattleHex hex2)
|
||||
[[nodiscard]] static EDir mutualPosition(BattleHex hex1, BattleHex hex2)
|
||||
{
|
||||
for(auto dir : hexagonalDirections())
|
||||
if(hex2 == hex1.cloneInDirection(dir, false))
|
||||
@ -222,13 +209,59 @@ public:
|
||||
}
|
||||
|
||||
/// get (precomputed) all possible surrounding tiles
|
||||
const BattleHexArray & getAllNeighbouringTiles() const;
|
||||
[[nodiscard]] const BattleHexArray & getAllNeighbouringTiles() const noexcept;
|
||||
|
||||
/// get (precomputed) only valid and available surrounding tiles
|
||||
const BattleHexArray & getNeighbouringTiles() const;
|
||||
[[nodiscard]] const BattleHexArray & getNeighbouringTiles() const noexcept;
|
||||
|
||||
/// get (precomputed) only valid and available surrounding tiles for double wide creatures
|
||||
const BattleHexArray & getNeighbouringTilesDblWide(BattleSide side) const;
|
||||
[[nodiscard]] const BattleHexArray & getNeighbouringTilesDoubleWide(BattleSide side) const noexcept;
|
||||
|
||||
/// get integer hex value
|
||||
[[nodiscard]] si16 toInt() const noexcept
|
||||
{
|
||||
return hex;
|
||||
}
|
||||
|
||||
BattleHex & operator+=(EDir dir)
|
||||
{
|
||||
return moveInDirection(dir);
|
||||
}
|
||||
|
||||
[[nodiscard]] BattleHex operator+(EDir dir) const
|
||||
{
|
||||
return cloneInDirection(dir);
|
||||
}
|
||||
|
||||
// Prefix increment
|
||||
BattleHex & operator++() noexcept
|
||||
{
|
||||
++hex;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Postfix increment
|
||||
BattleHex operator++(int) noexcept
|
||||
{
|
||||
BattleHex temp = *this;
|
||||
++hex;
|
||||
return temp;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator ==(BattleHex other) const noexcept
|
||||
{
|
||||
return hex == other.hex;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator !=(BattleHex other) const noexcept
|
||||
{
|
||||
return hex != other.hex;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator <(BattleHex other) const noexcept
|
||||
{
|
||||
return hex < other.hex;
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
void serialize(Handler & h)
|
||||
|
@ -34,7 +34,7 @@ void BattleHexArray::erase(iterator first, iterator last) noexcept
|
||||
{
|
||||
for(auto it = first; it != last && it != internalStorage.end(); ++it)
|
||||
{
|
||||
presenceFlags[*it] = 0;
|
||||
presenceFlags[it->toInt()] = 0;
|
||||
}
|
||||
|
||||
internalStorage.erase(first, last);
|
||||
@ -43,7 +43,7 @@ void BattleHexArray::erase(iterator first, iterator last) noexcept
|
||||
void BattleHexArray::clear() noexcept
|
||||
{
|
||||
for(auto hex : internalStorage)
|
||||
presenceFlags[hex] = 0;
|
||||
presenceFlags[hex.toInt()] = 0;
|
||||
|
||||
internalStorage.clear();
|
||||
}
|
||||
@ -83,7 +83,7 @@ BattleHexArray::ArrayOfBattleHexArrays BattleHexArray::precalculateAllNeighbouri
|
||||
return ret;
|
||||
}
|
||||
|
||||
BattleHexArray::ArrayOfBattleHexArrays BattleHexArray::precalculateNeighbouringTilesDblWide(BattleSide side)
|
||||
BattleHexArray::ArrayOfBattleHexArrays BattleHexArray::precalculateNeighbouringTilesDoubleWide(BattleSide side)
|
||||
{
|
||||
ArrayOfBattleHexArrays ret;
|
||||
|
||||
@ -123,10 +123,10 @@ BattleHexArray::ArrayOfBattleHexArrays BattleHexArray::precalculateNeighbouringT
|
||||
|
||||
const BattleHexArray::ArrayOfBattleHexArrays BattleHexArray::neighbouringTiles = precalculateNeighbouringTiles();
|
||||
const BattleHexArray::ArrayOfBattleHexArrays BattleHexArray::allNeighbouringTiles = precalculateAllNeighbouringTiles();
|
||||
const std::map<BattleSide, BattleHexArray::ArrayOfBattleHexArrays> BattleHexArray::neighbouringTilesDblWide =
|
||||
const std::map<BattleSide, BattleHexArray::ArrayOfBattleHexArrays> BattleHexArray::neighbouringTilesDoubleWide =
|
||||
{
|
||||
{ BattleSide::ATTACKER, precalculateNeighbouringTilesDblWide(BattleSide::ATTACKER) },
|
||||
{ BattleSide::DEFENDER, precalculateNeighbouringTilesDblWide(BattleSide::DEFENDER) }
|
||||
{ BattleSide::ATTACKER, precalculateNeighbouringTilesDoubleWide(BattleSide::ATTACKER) },
|
||||
{ BattleSide::DEFENDER, precalculateNeighbouringTilesDoubleWide(BattleSide::DEFENDER) }
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -60,7 +60,7 @@ public:
|
||||
{
|
||||
if(tile.isAvailable() && !contains(tile))
|
||||
{
|
||||
presenceFlags[tile] = 1;
|
||||
presenceFlags[tile.toInt()] = true;
|
||||
internalStorage.emplace_back(tile);
|
||||
}
|
||||
}
|
||||
@ -70,7 +70,7 @@ public:
|
||||
if(contains(hex))
|
||||
return;
|
||||
|
||||
presenceFlags[hex] = 1;
|
||||
presenceFlags[hex.toInt()] = true;
|
||||
internalStorage.emplace_back(hex);
|
||||
}
|
||||
|
||||
@ -87,7 +87,7 @@ public:
|
||||
if(contains(hex))
|
||||
return;
|
||||
|
||||
presenceFlags[hex] = 1;
|
||||
presenceFlags[hex.toInt()] = true;
|
||||
internalStorage[index] = hex;
|
||||
}
|
||||
|
||||
@ -96,7 +96,7 @@ public:
|
||||
if(contains(hex))
|
||||
return pos;
|
||||
|
||||
presenceFlags[hex] = 1;
|
||||
presenceFlags[hex.toInt()] = true;
|
||||
return internalStorage.insert(pos, hex);
|
||||
}
|
||||
|
||||
@ -122,7 +122,7 @@ public:
|
||||
void erase(iterator first, iterator last) noexcept;
|
||||
inline void pop_back() noexcept
|
||||
{
|
||||
presenceFlags[internalStorage.back()] = 0;
|
||||
presenceFlags[internalStorage.back().toInt()] = false;
|
||||
internalStorage.pop_back();
|
||||
}
|
||||
|
||||
@ -158,33 +158,33 @@ public:
|
||||
}
|
||||
|
||||
/// get (precomputed) all possible surrounding tiles
|
||||
static const BattleHexArray & getAllNeighbouringTiles(BattleHex hex)
|
||||
static const BattleHexArray & getAllNeighbouringTiles(BattleHex hex) noexcept
|
||||
{
|
||||
assert(hex.isValid());
|
||||
|
||||
return allNeighbouringTiles[hex];
|
||||
return allNeighbouringTiles[hex.toInt()];
|
||||
}
|
||||
|
||||
/// get (precomputed) only valid and available surrounding tiles
|
||||
static const BattleHexArray & getNeighbouringTiles(BattleHex hex)
|
||||
static const BattleHexArray & getNeighbouringTiles(BattleHex hex) noexcept
|
||||
{
|
||||
assert(hex.isValid());
|
||||
|
||||
return neighbouringTiles[hex];
|
||||
return neighbouringTiles[hex.toInt()];
|
||||
}
|
||||
|
||||
/// get (precomputed) only valid and available surrounding tiles for double wide creatures
|
||||
static const BattleHexArray & getNeighbouringTilesDblWide(BattleHex hex, BattleSide side)
|
||||
static const BattleHexArray & getNeighbouringTilesDoubleWide(BattleHex hex, BattleSide side) noexcept
|
||||
{
|
||||
assert(hex.isValid() && (side == BattleSide::ATTACKER || side == BattleSide::DEFENDER));
|
||||
|
||||
return neighbouringTilesDblWide.at(side)[hex];
|
||||
return neighbouringTilesDoubleWide.at(side)[hex.toInt()];
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool contains(BattleHex hex) const noexcept
|
||||
{
|
||||
if(hex.isValid())
|
||||
return presenceFlags[hex];
|
||||
return presenceFlags[hex.toInt()];
|
||||
/*
|
||||
if(!isTower(hex))
|
||||
logGlobal->warn("BattleHexArray::contains( %d ) - invalid BattleHex!", hex);
|
||||
@ -198,10 +198,10 @@ public:
|
||||
void serialize(Serializer & s)
|
||||
{
|
||||
s & internalStorage;
|
||||
if(!internalStorage.empty() && presenceFlags[internalStorage.front()] == 0)
|
||||
if(!s.saving)
|
||||
{
|
||||
for(auto hex : internalStorage)
|
||||
presenceFlags[hex] = 1;
|
||||
presenceFlags[hex.toInt()] = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,11 +307,11 @@ private:
|
||||
|
||||
static const ArrayOfBattleHexArrays neighbouringTiles;
|
||||
static const ArrayOfBattleHexArrays allNeighbouringTiles;
|
||||
static const std::map<BattleSide, ArrayOfBattleHexArrays> neighbouringTilesDblWide;
|
||||
static const std::map<BattleSide, ArrayOfBattleHexArrays> neighbouringTilesDoubleWide;
|
||||
|
||||
static ArrayOfBattleHexArrays precalculateNeighbouringTiles();
|
||||
static ArrayOfBattleHexArrays precalculateAllNeighbouringTiles();
|
||||
static ArrayOfBattleHexArrays precalculateNeighbouringTilesDblWide(BattleSide side);
|
||||
static ArrayOfBattleHexArrays precalculateNeighbouringTilesDoubleWide(BattleSide side);
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -46,7 +46,7 @@ CStack * BattleInfo::generateNewStack(uint32_t id, const CStackInstance & base,
|
||||
assert(!owner.isValidPlayer() || (base.armyObj && base.armyObj->tempOwner == owner));
|
||||
|
||||
auto * ret = new CStack(&base, owner, id, side, slot);
|
||||
ret->initialPosition = getAvailableHex(base.getCreatureID(), side, position); //TODO: what if no free tile on battlefield was found?
|
||||
ret->initialPosition = getAvailableHex(base.getCreatureID(), side, position.toInt()); //TODO: what if no free tile on battlefield was found?
|
||||
stacks.push_back(ret);
|
||||
return ret;
|
||||
}
|
||||
@ -264,7 +264,7 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
||||
|
||||
for(BattleHex blocked : obi.getBlocked(pos))
|
||||
{
|
||||
if(tileAccessibility[blocked] == EAccessibility::UNAVAILABLE) //for ship-to-ship battlefield - exclude hardcoded unavailable tiles
|
||||
if(tileAccessibility[blocked.toInt()] == EAccessibility::UNAVAILABLE) //for ship-to-ship battlefield - exclude hardcoded unavailable tiles
|
||||
return false;
|
||||
if(blockedTiles.contains(blocked))
|
||||
return false;
|
||||
|
@ -43,19 +43,15 @@ static BattleHex lineToWallHex(int line) //returns hex with wall in given line (
|
||||
|
||||
static bool sameSideOfWall(BattleHex pos1, BattleHex pos2)
|
||||
{
|
||||
const int wallInStackLine = lineToWallHex(pos1.getY());
|
||||
const int wallInDestLine = lineToWallHex(pos2.getY());
|
||||
|
||||
const bool stackLeft = pos1 < wallInStackLine;
|
||||
const bool destLeft = pos2 < wallInDestLine;
|
||||
const bool stackLeft = pos1 < lineToWallHex(pos1.getY());
|
||||
const bool destLeft = pos2 < lineToWallHex(pos2.getY());
|
||||
|
||||
return stackLeft == destLeft;
|
||||
}
|
||||
|
||||
static bool isInsideWalls(BattleHex pos)
|
||||
{
|
||||
const int wallInStackLine = lineToWallHex(pos.getY());
|
||||
return wallInStackLine < pos;
|
||||
return lineToWallHex(pos.getY()) < pos;
|
||||
}
|
||||
|
||||
// parts of wall
|
||||
@ -79,9 +75,10 @@ static const std::pair<int, EWallPart> wallParts[] =
|
||||
|
||||
static EWallPart hexToWallPart(BattleHex hex)
|
||||
{
|
||||
si16 hexValue = hex.toInt();
|
||||
for(const auto & elem : wallParts)
|
||||
{
|
||||
if(elem.first == hex)
|
||||
if(elem.first == hexValue)
|
||||
return elem.second;
|
||||
}
|
||||
|
||||
@ -151,7 +148,7 @@ std::pair< BattleHexArray, int > CBattleInfoCallback::getPath(BattleHex start, B
|
||||
{
|
||||
auto reachability = getReachability(stack);
|
||||
|
||||
if(reachability.predecessors[dest] == -1) //cannot reach destination
|
||||
if(reachability.predecessors[dest.toInt()] == -1) //cannot reach destination
|
||||
{
|
||||
return std::make_pair(BattleHexArray(), 0);
|
||||
}
|
||||
@ -162,10 +159,10 @@ std::pair< BattleHexArray, int > CBattleInfoCallback::getPath(BattleHex start, B
|
||||
while(curElem != start)
|
||||
{
|
||||
path.insert(curElem);
|
||||
curElem = reachability.predecessors[curElem];
|
||||
curElem = reachability.predecessors[curElem.toInt()];
|
||||
}
|
||||
|
||||
return std::make_pair(path, reachability.distances[dest]);
|
||||
return std::make_pair(path, reachability.distances[dest.toInt()]);
|
||||
}
|
||||
|
||||
bool CBattleInfoCallback::battleIsInsideWalls(BattleHex from) const
|
||||
@ -176,7 +173,7 @@ bool CBattleInfoCallback::battleIsInsideWalls(BattleHex from) const
|
||||
bool CBattleInfoCallback::battleHasPenaltyOnLine(BattleHex from, BattleHex dest, bool checkWall, bool checkMoat) const
|
||||
{
|
||||
if (!from.isAvailable() || !dest.isAvailable())
|
||||
throw std::runtime_error("Invalid hex (" + std::to_string(from) + " and " + std::to_string(dest) + ") received in battleHasPenaltyOnLine!" );
|
||||
throw std::runtime_error("Invalid hex (" + std::to_string(from.toInt()) + " and " + std::to_string(dest.toInt()) + ") received in battleHasPenaltyOnLine!" );
|
||||
|
||||
auto isTileBlocked = [&](BattleHex tile)
|
||||
{
|
||||
@ -225,7 +222,7 @@ bool CBattleInfoCallback::battleHasPenaltyOnLine(BattleHex from, BattleHex dest,
|
||||
|
||||
auto obstacles = battleGetAllObstaclesOnPos(hex, false);
|
||||
|
||||
if(hex != BattleHex::GATE_BRIDGE || (battleIsGatePassable()))
|
||||
if(hex.toInt() != BattleHex::GATE_BRIDGE || (battleIsGatePassable()))
|
||||
for(const auto & obst : obstacles)
|
||||
if(obst->obstacleType == CObstacleInstance::MOAT)
|
||||
pathHasMoat |= true;
|
||||
@ -786,7 +783,7 @@ DamageEstimation CBattleInfoCallback::battleEstimateDamage(const battle::Unit *
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE({});
|
||||
auto reachability = battleGetDistances(attacker, attacker->getPosition());
|
||||
int movementRange = attackerPosition.isValid() ? reachability[attackerPosition] : 0;
|
||||
int movementRange = attackerPosition.isValid() ? reachability[attackerPosition.toInt()] : 0;
|
||||
return battleEstimateDamage(attacker, defender, movementRange, retaliationDmg);
|
||||
}
|
||||
|
||||
@ -955,8 +952,8 @@ AccessibilityInfo CBattleInfoCallback::getAccessibility() const
|
||||
//removing accessibility for side columns of hexes
|
||||
for(int y = 0; y < GameConstants::BFIELD_HEIGHT; y++)
|
||||
{
|
||||
ret[BattleHex(GameConstants::BFIELD_WIDTH - 1, y)] = EAccessibility::SIDE_COLUMN;
|
||||
ret[BattleHex(0, y)] = EAccessibility::SIDE_COLUMN;
|
||||
ret[BattleHex(GameConstants::BFIELD_WIDTH - 1, y).toInt()] = EAccessibility::SIDE_COLUMN;
|
||||
ret[BattleHex(0, y).toInt()] = EAccessibility::SIDE_COLUMN;
|
||||
}
|
||||
|
||||
//special battlefields with logically unavailable tiles
|
||||
@ -965,7 +962,7 @@ AccessibilityInfo CBattleInfoCallback::getAccessibility() const
|
||||
if(bFieldType != BattleField::NONE)
|
||||
{
|
||||
for(auto hex : bFieldType.getInfo()->impassableHexes)
|
||||
ret[hex] = EAccessibility::UNAVAILABLE;
|
||||
ret[hex.toInt()] = EAccessibility::UNAVAILABLE;
|
||||
}
|
||||
|
||||
//gate -> should be before stacks
|
||||
@ -990,14 +987,14 @@ AccessibilityInfo CBattleInfoCallback::getAccessibility() const
|
||||
{
|
||||
for(auto hex : unit->getHexes())
|
||||
if(hex.isAvailable()) //towers can have <0 pos; we don't also want to overwrite side columns
|
||||
ret[hex] = EAccessibility::ALIVE_STACK;
|
||||
ret[hex.toInt()] = EAccessibility::ALIVE_STACK;
|
||||
}
|
||||
|
||||
//obstacles
|
||||
for(const auto &obst : battleGetAllObstacles())
|
||||
{
|
||||
for(auto hex : obst->getBlockedTiles())
|
||||
ret[hex] = EAccessibility::OBSTACLE;
|
||||
ret[hex.toInt()] = EAccessibility::OBSTACLE;
|
||||
}
|
||||
|
||||
//walls
|
||||
@ -1020,7 +1017,7 @@ AccessibilityInfo CBattleInfoCallback::getAccessibility() const
|
||||
for(const auto & elem : lockedIfNotDestroyed)
|
||||
{
|
||||
if(battleGetWallState(elem.first) != EWallState::DESTROYED)
|
||||
ret[elem.second] = EAccessibility::DESTRUCTIBLE_WALL;
|
||||
ret[elem.second.toInt()] = EAccessibility::DESTRUCTIBLE_WALL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1029,15 +1026,15 @@ 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;
|
||||
ret[hex.toInt()] = EAccessibility::ACCESSIBLE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1062,7 +1059,7 @@ ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo & accessib
|
||||
|
||||
//first element
|
||||
hexq.push(params.startPosition);
|
||||
ret.distances[params.startPosition] = 0;
|
||||
ret.distances[params.startPosition.toInt()] = 0;
|
||||
|
||||
std::array<bool, GameConstants::BFIELD_SIZE> accessibleCache{};
|
||||
for(int hex = 0; hex < GameConstants::BFIELD_SIZE; hex++)
|
||||
@ -1077,7 +1074,7 @@ ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo & accessib
|
||||
if(isInObstacle(curHex, obstacles, checkParams))
|
||||
continue;
|
||||
|
||||
const int costToNeighbour = ret.distances.at(curHex) + 1;
|
||||
const int costToNeighbour = ret.distances.at(curHex.toInt()) + 1;
|
||||
|
||||
for(BattleHex neighbour : curHex.getNeighbouringTiles())
|
||||
{
|
||||
@ -1085,7 +1082,7 @@ ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo & accessib
|
||||
|
||||
if(params.bypassEnemyStacks)
|
||||
{
|
||||
auto enemyToBypass = params.destructibleEnemyTurns.at(neighbour);
|
||||
auto enemyToBypass = params.destructibleEnemyTurns.at(neighbour.toInt());
|
||||
|
||||
if(enemyToBypass >= 0)
|
||||
{
|
||||
@ -1093,13 +1090,13 @@ ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo & accessib
|
||||
}
|
||||
}
|
||||
|
||||
const int costFoundSoFar = ret.distances[neighbour];
|
||||
const int costFoundSoFar = ret.distances[neighbour.toInt()];
|
||||
|
||||
if(accessibleCache[neighbour] && costToNeighbour + additionalCost < costFoundSoFar)
|
||||
if(accessibleCache[neighbour.toInt()] && costToNeighbour + additionalCost < costFoundSoFar)
|
||||
{
|
||||
hexq.push(neighbour);
|
||||
ret.distances[neighbour] = costToNeighbour + additionalCost;
|
||||
ret.predecessors[neighbour] = curHex;
|
||||
ret.distances[neighbour.toInt()] = costToNeighbour + additionalCost;
|
||||
ret.predecessors[neighbour.toInt()] = curHex;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1181,7 +1178,7 @@ std::pair<const battle::Unit *, BattleHex> CBattleInfoCallback::getNearestStack(
|
||||
for(BattleHex hex : avHexes)
|
||||
if(CStack::isMeleeAttackPossible(closest, st, hex))
|
||||
{
|
||||
DistStack hlp = {reachability.distances[hex], hex, st};
|
||||
DistStack hlp = {reachability.distances[hex.toInt()], hex, st};
|
||||
stackPairs.push_back(hlp);
|
||||
}
|
||||
}
|
||||
@ -1272,9 +1269,12 @@ ReachabilityInfo CBattleInfoCallback::getReachability(const ReachabilityInfo::Pa
|
||||
return getFlyingReachability(params);
|
||||
else
|
||||
{
|
||||
auto accessibility = getAccessibility(params.knownAccessible);
|
||||
auto accessibility = getAccessibility(* params.knownAccessible);
|
||||
|
||||
accessibility.destructibleEnemyTurns = & params.destructibleEnemyTurns;
|
||||
accessibility.destructibleEnemyTurns = std::shared_ptr<const TBattlefieldTurnsArray>(
|
||||
& params.destructibleEnemyTurns,
|
||||
[](const TBattlefieldTurnsArray *) { }
|
||||
);
|
||||
|
||||
return makeBFS(accessibility, params);
|
||||
}
|
||||
@ -1283,7 +1283,7 @@ ReachabilityInfo CBattleInfoCallback::getReachability(const ReachabilityInfo::Pa
|
||||
ReachabilityInfo CBattleInfoCallback::getFlyingReachability(const ReachabilityInfo::Parameters & params) const
|
||||
{
|
||||
ReachabilityInfo ret;
|
||||
ret.accessibility = getAccessibility(params.knownAccessible);
|
||||
ret.accessibility = getAccessibility(* params.knownAccessible);
|
||||
|
||||
for(int i = 0; i < GameConstants::BFIELD_SIZE; i++)
|
||||
{
|
||||
@ -1326,9 +1326,9 @@ AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes(
|
||||
AttackableTiles at;
|
||||
RETURN_IF_NOT_BATTLE(at);
|
||||
|
||||
BattleHex attackOriginHex = (attackerPos != BattleHex::INVALID) ? attackerPos : attacker->getPosition(); //real or hypothetical (cursor) position
|
||||
BattleHex attackOriginHex = (attackerPos.toInt() != BattleHex::INVALID) ? attackerPos : attacker->getPosition(); //real or hypothetical (cursor) position
|
||||
|
||||
defenderPos = (defenderPos != BattleHex::INVALID) ? defenderPos : defender->getPosition(); //real or hypothetical (cursor) position
|
||||
defenderPos = (defenderPos.toInt() != BattleHex::INVALID) ? defenderPos : defender->getPosition(); //real or hypothetical (cursor) position
|
||||
|
||||
bool reverse = isToReverse(attacker, defender, attackerPos, defenderPos);
|
||||
if(reverse && attacker->doubleWide())
|
||||
|
@ -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
|
||||
|
@ -113,7 +113,9 @@ void CObstacleInstance::serializeJson(JsonSerializeFormat & handler)
|
||||
animationYOffset -= 42;
|
||||
|
||||
//We need only a subset of obstacle info for correct render
|
||||
handler.serializeInt("position", pos);
|
||||
si16 posValue = pos.toInt();
|
||||
handler.serializeInt("position", posValue);
|
||||
pos = posValue;
|
||||
handler.serializeInt("animationYOffset", animationYOffset);
|
||||
handler.serializeBool("hidden", hidden);
|
||||
handler.serializeBool("needAnimationOffsetFix", needAnimationOffsetFix);
|
||||
@ -188,7 +190,9 @@ void SpellCreatedObstacle::fromInfo(const ObstacleChanges & info)
|
||||
void SpellCreatedObstacle::serializeJson(JsonSerializeFormat & handler)
|
||||
{
|
||||
handler.serializeInt("spell", ID);
|
||||
handler.serializeInt("position", pos);
|
||||
si16 posValue = pos.toInt();
|
||||
handler.serializeInt("position", posValue);
|
||||
pos = posValue;
|
||||
|
||||
handler.serializeInt("turnsRemaining", turnsRemaining);
|
||||
handler.serializeInt("casterSpellPower", casterSpellPower);
|
||||
@ -215,9 +219,9 @@ void SpellCreatedObstacle::serializeJson(JsonSerializeFormat & handler)
|
||||
JsonArraySerializer customSizeJson = handler.enterArray("customSize");
|
||||
customSizeJson.syncSize(customSize, JsonNode::JsonType::DATA_INTEGER);
|
||||
|
||||
BattleHex hex;
|
||||
for(size_t index = 0; index < customSizeJson.size(); index++)
|
||||
{
|
||||
si16 hex = customSize.at(index).toInt();
|
||||
customSizeJson.serializeInt(index, hex);
|
||||
customSize.set(index, hex);
|
||||
}
|
||||
|
@ -798,7 +798,9 @@ void CUnitState::serializeJson(JsonSerializeFormat & handler)
|
||||
|
||||
handler.serializeInt("cloneID", cloneID);
|
||||
|
||||
handler.serializeInt("position", position);
|
||||
si16 posValue = position.toInt();
|
||||
handler.serializeInt("position", posValue);
|
||||
position = posValue;
|
||||
}
|
||||
|
||||
void CUnitState::localInit(const IUnitEnvironment * env_)
|
||||
|
@ -45,7 +45,7 @@ DamageRange DamageCalculator::getBaseDamageSingle() const
|
||||
const auto * town = callback.battleGetDefendedTown();
|
||||
assert(town);
|
||||
|
||||
switch(info.attacker->getPosition())
|
||||
switch(info.attacker->getPosition().toInt())
|
||||
{
|
||||
case BattleHex::CASTLE_CENTRAL_TOWER:
|
||||
return town->getKeepDamageRange();
|
||||
|
@ -33,7 +33,7 @@ ReachabilityInfo::ReachabilityInfo()
|
||||
|
||||
bool ReachabilityInfo::isReachable(BattleHex hex) const
|
||||
{
|
||||
return distances[hex] < INFINITE_DIST;
|
||||
return distances[hex.toInt()] < INFINITE_DIST;
|
||||
}
|
||||
|
||||
uint32_t ReachabilityInfo::distToNearestNeighbour(
|
||||
@ -46,9 +46,9 @@ uint32_t ReachabilityInfo::distToNearestNeighbour(
|
||||
{
|
||||
for(auto & n : targetHex.getNeighbouringTiles())
|
||||
{
|
||||
if(distances[n] < ret)
|
||||
if(distances[n.toInt()] < ret)
|
||||
{
|
||||
ret = distances[n];
|
||||
ret = distances[n.toInt()];
|
||||
if(chosenHex)
|
||||
*chosenHex = n;
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ struct DLL_LINKAGE ReachabilityInfo
|
||||
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
|
||||
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)
|
||||
TBattlefieldTurnsArray destructibleEnemyTurns; // how many turns it is needed to kill enemy on specific hex (index <=> hex)
|
||||
|
||||
BattleHex startPosition; //assumed position of stack
|
||||
BattleSide perspective = BattleSide::ALL_KNOWING; //some obstacles (eg. quicksands) may be invisible for some side
|
||||
|
@ -53,7 +53,7 @@ const IBonusBearer* Unit::getBonusBearer() const
|
||||
|
||||
const BattleHexArray & Unit::getSurroundingHexes(BattleHex assumedPosition) const
|
||||
{
|
||||
BattleHex hex = (assumedPosition != BattleHex::INVALID) ? assumedPosition : getPosition(); //use hypothetical position
|
||||
BattleHex hex = (assumedPosition.toInt() != BattleHex::INVALID) ? assumedPosition : getPosition(); //use hypothetical position
|
||||
|
||||
return getSurroundingHexes(hex, doubleWide(), unitSide());
|
||||
}
|
||||
@ -63,7 +63,7 @@ const BattleHexArray & Unit::getSurroundingHexes(BattleHex position, bool twoHex
|
||||
if(!twoHex)
|
||||
return position.getNeighbouringTiles();
|
||||
|
||||
return position.getNeighbouringTilesDblWide(side);
|
||||
return position.getNeighbouringTilesDoubleWide(side);
|
||||
}
|
||||
|
||||
BattleHexArray Unit::getAttackableHexes(const Unit * attacker) const
|
||||
@ -112,8 +112,8 @@ const BattleHexArray & Unit::getHexes(BattleHex assumedPos, bool twoHex, BattleS
|
||||
static BattleHexArray::ArrayOfBattleHexArrays precomputed[4];
|
||||
int index = side == BattleSide::ATTACKER ? 0 : 2;
|
||||
|
||||
if(!precomputed[index + twoHex][assumedPos].empty())
|
||||
return precomputed[index + twoHex][assumedPos];
|
||||
if(!precomputed[index + twoHex][assumedPos.toInt()].empty())
|
||||
return precomputed[index + twoHex][assumedPos.toInt()];
|
||||
|
||||
// first run, compute
|
||||
|
||||
@ -123,9 +123,9 @@ const BattleHexArray & Unit::getHexes(BattleHex assumedPos, bool twoHex, BattleS
|
||||
if(twoHex)
|
||||
hexes.insert(occupiedHex(assumedPos, twoHex, side));
|
||||
|
||||
precomputed[index + twoHex][assumedPos] = std::move(hexes);
|
||||
precomputed[index + twoHex][assumedPos.toInt()] = std::move(hexes);
|
||||
|
||||
return precomputed[index + twoHex][assumedPos];
|
||||
return precomputed[index + twoHex][assumedPos.toInt()];
|
||||
}
|
||||
|
||||
BattleHex Unit::occupiedHex() const
|
||||
@ -143,9 +143,9 @@ BattleHex Unit::occupiedHex(BattleHex assumedPos, bool twoHex, BattleSide side)
|
||||
if(twoHex)
|
||||
{
|
||||
if(side == BattleSide::ATTACKER)
|
||||
return assumedPos - 1;
|
||||
return assumedPos.toInt() - 1;
|
||||
else
|
||||
return assumedPos + 1;
|
||||
return assumedPos.toInt() + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -201,7 +201,9 @@ void UnitInfo::serializeJson(JsonSerializeFormat & handler)
|
||||
handler.serializeInt("count", count);
|
||||
handler.serializeId("type", type, CreatureID(CreatureID::NONE));
|
||||
handler.serializeInt("side", side);
|
||||
handler.serializeInt("position", position);
|
||||
si16 positionValue = position.toInt();
|
||||
handler.serializeInt("position", positionValue);
|
||||
position = positionValue;
|
||||
handler.serializeBool("summoned", summoned);
|
||||
}
|
||||
|
||||
|
@ -84,11 +84,14 @@ public:
|
||||
bool isTurret() const;
|
||||
virtual bool isValidTarget(bool allowDead = false) const = 0; //non-turret non-ghost stacks (can be attacked or be object of magic effect)
|
||||
|
||||
virtual bool isHypnotized() const = 0;
|
||||
|
||||
virtual bool isClone() const = 0;
|
||||
virtual bool hasClone() const = 0;
|
||||
|
||||
virtual bool canCast() const = 0;
|
||||
virtual bool isCaster() const = 0;
|
||||
virtual bool canShootBlocked() const = 0;
|
||||
virtual bool canShoot() const = 0;
|
||||
virtual bool isShooter() const = 0;
|
||||
|
||||
@ -112,8 +115,6 @@ public:
|
||||
virtual BattleHex getPosition() const = 0;
|
||||
virtual void setPosition(BattleHex hex) = 0;
|
||||
|
||||
virtual int32_t getInitiative(int turn = 0) const = 0;
|
||||
|
||||
virtual bool canMove(int turn = 0) const = 0; //if stack can move
|
||||
virtual bool defended(int turn = 0) const = 0;
|
||||
virtual bool moved(int turn = 0) const = 0; //if stack was already moved this turn
|
||||
|
@ -238,7 +238,7 @@ JsonNode UnitOnHexLimiter::toJsonNode() const
|
||||
|
||||
root["type"].String() = "UNIT_ON_HEXES";
|
||||
for(auto hex : applicableHexes)
|
||||
root["parameters"].Vector().emplace_back(hex);
|
||||
root["parameters"].Vector().emplace_back(hex.toInt());
|
||||
|
||||
return root;
|
||||
}
|
||||
|
@ -517,7 +517,7 @@ BattleHexArray BattleSpellMechanics::spellRangeInHexes(BattleHex centralHex) con
|
||||
|
||||
for(auto & elem : rng)
|
||||
{
|
||||
std::set<ui16> curLayer = getInRange(centralHex, elem, elem);
|
||||
std::set<ui16> curLayer = getInRange(centralHex.toInt(), elem, elem);
|
||||
//adding obtained hexes
|
||||
for(const auto & curLayer_it : curLayer)
|
||||
ret.insert(curLayer_it);
|
||||
|
@ -754,7 +754,14 @@ std::vector<int> CSpellHandler::spellRangeInHexes(std::string input) const
|
||||
}
|
||||
}
|
||||
|
||||
return std::vector<int>(ret.begin(), ret.end());
|
||||
std::vector<int> result;
|
||||
result.reserve(ret.size());
|
||||
|
||||
std::transform(ret.begin(), ret.end(), std::back_inserter(result),
|
||||
[](BattleHex hex) { return hex.toInt(); }
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<CSpell> CSpellHandler::loadFromJson(const std::string & scope, const JsonNode & json, const std::string & identifier, size_t index)
|
||||
|
@ -95,7 +95,7 @@ void Catapult::applyMassive(ServerCallback * server, const Mechanics * m) const
|
||||
CatapultAttack::AttackInfo newInfo;
|
||||
newInfo.damageDealt = getRandomDamage(server);
|
||||
newInfo.attackedPart = target;
|
||||
newInfo.destinationTile = m->battle()->wallPartToBattleHex(target);
|
||||
newInfo.destinationTile = m->battle()->wallPartToBattleHex(target).toInt();
|
||||
ca.attackedParts.push_back(newInfo);
|
||||
attackInfo = ca.attackedParts.end() - 1;
|
||||
}
|
||||
@ -137,7 +137,7 @@ void Catapult::applyTargeted(ServerCallback * server, const Mechanics * m, const
|
||||
|
||||
CatapultAttack::AttackInfo attack;
|
||||
attack.attackedPart = actualTarget;
|
||||
attack.destinationTile = m->battle()->wallPartToBattleHex(actualTarget);
|
||||
attack.destinationTile = m->battle()->wallPartToBattleHex(actualTarget).toInt();
|
||||
attack.damageDealt = getRandomDamage(server);
|
||||
|
||||
CatapultAttack ca; //package for clients
|
||||
|
@ -43,7 +43,7 @@ void Clone::apply(ServerCallback * server, const Mechanics * m, const EffectTarg
|
||||
if(clonedStack->getCount() < 1)
|
||||
continue;
|
||||
|
||||
auto hex = m->battle()->getAvailableHex(clonedStack->creatureId(), m->casterSide, clonedStack->getPosition());
|
||||
auto hex = m->battle()->getAvailableHex(clonedStack->creatureId(), m->casterSide, clonedStack->getPosition().toInt());
|
||||
|
||||
if(!hex.isValid())
|
||||
{
|
||||
|
@ -65,7 +65,7 @@ void DemonSummon::apply(ServerCallback * server, const Mechanics * m, const Effe
|
||||
continue;
|
||||
}
|
||||
|
||||
auto hex = m->battle()->getAvailableHex(targetStack->creatureId(), m->casterSide, targetStack->getPosition());
|
||||
auto hex = m->battle()->getAvailableHex(targetStack->creatureId(), m->casterSide, targetStack->getPosition().toInt());
|
||||
|
||||
if(!hex.isValid())
|
||||
{
|
||||
|
@ -43,9 +43,9 @@ static void serializeMoatHexes(JsonSerializeFormat & handler, const std::string
|
||||
JsonArraySerializer inner = outer.enterArray(outerIndex);
|
||||
inner.syncSize(moatHexes.at(outerIndex), JsonNode::JsonType::DATA_INTEGER);
|
||||
|
||||
BattleHex hex;
|
||||
for(size_t innerIndex = 0; innerIndex < inner.size(); innerIndex++)
|
||||
{
|
||||
si16 hex = moatHexes.at(outerIndex).at(innerIndex).toInt();
|
||||
inner.serializeInt(innerIndex, hex);
|
||||
moatHexes.at(outerIndex).set(innerIndex, hex);
|
||||
}
|
||||
|
@ -223,7 +223,7 @@ EffectTarget UnitEffect::transformTargetByChain(const Mechanics * m, const Targe
|
||||
effectTarget.emplace_back();
|
||||
|
||||
for(auto hex : battle::Unit::getHexes(unit->getPosition(), unit->doubleWide(), unit->unitSide()))
|
||||
possibleHexes.erase(hex);
|
||||
possibleHexes.erase(hex.toInt());
|
||||
|
||||
if(possibleHexes.empty())
|
||||
break;
|
||||
|
@ -98,7 +98,7 @@ bool LuaSpellEffect::applicable(Problem & problem, const Mechanics * m, const Ef
|
||||
for(const auto & dest : target)
|
||||
{
|
||||
JsonNode targetData;
|
||||
targetData.Vector().emplace_back(static_cast<si16>(dest.hexValue));
|
||||
targetData.Vector().emplace_back(dest.hexValue.toInt());
|
||||
|
||||
if(dest.unitValue)
|
||||
targetData.Vector().emplace_back(dest.unitValue->unitId());
|
||||
@ -141,7 +141,7 @@ void LuaSpellEffect::apply(ServerCallback * server, const Mechanics * m, const E
|
||||
for(const auto & dest : target)
|
||||
{
|
||||
JsonNode targetData;
|
||||
targetData.Vector().emplace_back(static_cast<si16>(dest.hexValue));
|
||||
targetData.Vector().emplace_back(dest.hexValue.toInt());
|
||||
|
||||
if(dest.unitValue)
|
||||
targetData.Vector().emplace_back(dest.unitValue->unitId());
|
||||
|
@ -84,7 +84,7 @@ TEST_F(LuaSpellEffectAPITest, DISABLED_ApplicableOnLeftSideOfField)
|
||||
BattleHex hex(2,2);
|
||||
|
||||
JsonNode first;
|
||||
first.Vector().emplace_back(static_cast<si16>(hex));
|
||||
first.Vector().emplace_back(hex.toInt());
|
||||
first.Vector().emplace_back();
|
||||
|
||||
JsonNode targets;
|
||||
@ -113,7 +113,7 @@ TEST_F(LuaSpellEffectAPITest, DISABLED_NotApplicableOnRightSideOfField)
|
||||
BattleHex hex(11,2);
|
||||
|
||||
JsonNode first;
|
||||
first.Vector().emplace_back(static_cast<si16>(hex));
|
||||
first.Vector().emplace_back(hex.toInt());
|
||||
first.Vector().emplace_back(-1);
|
||||
|
||||
JsonNode targets;
|
||||
@ -138,13 +138,13 @@ TEST_F(LuaSpellEffectAPITest, DISABLED_ApplyMoveUnit)
|
||||
BattleHex hex1(11,2);
|
||||
|
||||
JsonNode unit;
|
||||
unit.Vector().emplace_back(static_cast<si16>(hex1));
|
||||
unit.Vector().emplace_back(hex1.toInt());
|
||||
unit.Vector().emplace_back(42);
|
||||
|
||||
BattleHex hex2(5,4);
|
||||
|
||||
JsonNode destination;
|
||||
destination.Vector().emplace_back(static_cast<si16>(hex2));
|
||||
destination.Vector().emplace_back(hex2.toInt());
|
||||
destination.Vector().emplace_back(-1);
|
||||
|
||||
JsonNode targets;
|
||||
|
@ -154,11 +154,11 @@ TEST_F(LuaSpellEffectTest, ApplicableTargetRedirected)
|
||||
|
||||
|
||||
JsonNode first;
|
||||
first.Vector().emplace_back(static_cast<si16>(hex1));
|
||||
first.Vector().emplace_back(hex1.toInt());
|
||||
first.Vector().emplace_back(id1);
|
||||
|
||||
JsonNode second;
|
||||
second.Vector().emplace_back(static_cast<si16>(hex2));
|
||||
second.Vector().emplace_back(hex2.toInt());
|
||||
second.Vector().emplace_back(-1);
|
||||
|
||||
JsonNode targets;
|
||||
@ -193,7 +193,7 @@ TEST_F(LuaSpellEffectTest, ApplyRedirected)
|
||||
subject->apply(&serverMock, &mechanicsMock, target);
|
||||
|
||||
JsonNode first;
|
||||
first.Vector().emplace_back(static_cast<si16>(hex1));
|
||||
first.Vector().emplace_back(hex1.toInt());
|
||||
first.Vector().emplace_back(id1);
|
||||
|
||||
JsonNode targets;
|
||||
|
Loading…
x
Reference in New Issue
Block a user