1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-25 22:42:04 +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:
MichalZr6
2025-01-06 23:05:45 +01:00
parent 4031006317
commit dbe82b94f6
39 changed files with 223 additions and 174 deletions

View File

@@ -280,7 +280,7 @@ int64_t AttackPossibility::evaluateBlockedShootersDmg(
std::set<uint32_t> checkedUnits; std::set<uint32_t> checkedUnits;
auto attacker = attackInfo.attacker; auto attacker = attackInfo.attacker;
const BattleHexArray & hexes = attacker->getSurroundingHexes(hex); const auto & hexes = attacker->getSurroundingHexes(hex);
for(BattleHex tile : hexes) for(BattleHex tile : hexes)
{ {
auto st = state->battleGetUnitByPos(tile, true); auto st = state->battleGetUnitByPos(tile, true);

View File

@@ -214,8 +214,8 @@ BattleAction BattleEvaluator::selectStackAction(const CStack * stack)
bestAttack.attackerState->unitType()->getJsonKey(), bestAttack.attackerState->unitType()->getJsonKey(),
bestAttack.affectedUnits[0]->unitType()->getJsonKey(), bestAttack.affectedUnits[0]->unitType()->getJsonKey(),
bestAttack.affectedUnits[0]->getCount(), bestAttack.affectedUnits[0]->getCount(),
(int)bestAttack.from, bestAttack.from.toInt(),
(int)bestAttack.attack.attacker->getPosition(), bestAttack.attack.attacker->getPosition().toInt(),
bestAttack.attack.chargeDistance, bestAttack.attack.chargeDistance,
bestAttack.attack.attacker->getMovementRange(0), bestAttack.attack.attacker->getMovementRange(0),
bestAttack.defenderDamageReduce, 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 reachability = cb->getBattle(battleID)->getReachability(stack);
auto avHexes = cb->getBattle(battleID)->battleGetAvailableHexes(reachability, stack, false); 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 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(); BattleHex bestNeighbour = hexes.front();
if(reachability.distances[bestNeighbour] > GameConstants::BFIELD_SIZE) if(reachability.distances[bestNeighbour.toInt()] > GameConstants::BFIELD_SIZE)
{ {
logAi->trace("No reachable hexes."); logAi->trace("No reachable hexes.");
return BattleAction::makeDefend(stack); return BattleAction::makeDefend(stack);
@@ -468,7 +468,7 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, BattleHexAr
return moveOrAttack(stack, currentDest, targets); return moveOrAttack(stack, currentDest, targets);
} }
currentDest = reachability.predecessors[currentDest]; currentDest = reachability.predecessors[currentDest.toInt()];
} }
} }

View File

@@ -51,7 +51,7 @@ public:
bool attemptCastingSpell(const CStack * stack); bool attemptCastingSpell(const CStack * stack);
bool canCastSpell(); bool canCastSpell();
std::optional<PossibleSpellcast> findBestCreatureSpell(const CStack * stack); 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; std::vector<BattleHex> getBrokenWallMoatHexes() const;
bool hasWorkingTowers() const; bool hasWorkingTowers() const;
void evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcast & ps); //for offensive damaging spells only void evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcast & ps); //for offensive damaging spells only

View File

@@ -310,7 +310,7 @@ ReachabilityInfo getReachabilityWithEnemyBypass(
for(auto & hex : unit->getHexes()) for(auto & hex : unit->getHexes())
if(hex.isAvailable()) //towers can have <0 pos; we don't also want to overwrite side columns 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; params.bypassEnemyStacks = true;
@@ -415,11 +415,11 @@ MoveTarget BattleExchangeEvaluator::findMoveTowardsUnreachable(
for(BattleHex enemyHex : enemy->getAttackableHexes(activeStack)) 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); auto defenderToBypass = hb->battleGetUnitByPos(enemyHex);
@@ -429,7 +429,7 @@ MoveTarget BattleExchangeEvaluator::findMoveTowardsUnreachable(
logAi->trace("Found target to bypass at %d", enemyHex.hex); logAi->trace("Found target to bypass at %d", enemyHex.hex);
#endif #endif
auto attackHex = dists.predecessors[enemyHex]; auto attackHex = dists.predecessors[enemyHex.toInt()];
auto baiBypass = BattleAttackInfo(activeStack, defenderToBypass, 0, cb->battleCanShoot(activeStack)); auto baiBypass = BattleAttackInfo(activeStack, defenderToBypass, 0, cb->battleCanShoot(activeStack));
auto attackBypass = AttackPossibility::evaluate(baiBypass, attackHex, damageCache, hb); auto attackBypass = AttackPossibility::evaluate(baiBypass, attackHex, damageCache, hb);
@@ -440,7 +440,7 @@ MoveTarget BattleExchangeEvaluator::findMoveTowardsUnreachable(
auto bypassScore = calculateExchange( auto bypassScore = calculateExchange(
attackBypass, attackBypass,
dists.distances[attackHex], dists.distances[attackHex.toInt()],
targets, targets,
damageCache, damageCache,
hb, hb,
@@ -916,8 +916,7 @@ void BattleExchangeEvaluator::updateReachabilityMap(std::shared_ptr<HypotheticBa
} }
} }
} }
for(BattleHex hex = BattleHex::TOP_LEFT; hex.isValid(); ++hex)
for(BattleHex hex = BattleHex::TOP_LEFT; hex.isValid(); hex = hex + 1)
{ {
reachabilityMap[hex] = getOneTurnReachableUnits(0, 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); 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); const battle::Unit * hexStack = cb->battleGetUnitByPos(hex);
@@ -962,7 +961,7 @@ std::vector<const battle::Unit *> BattleExchangeEvaluator::getOneTurnReachableUn
{ {
for(BattleHex neighbour : hex.getNeighbouringTiles()) for(BattleHex neighbour : hex.getNeighbouringTiles())
{ {
reachable = unitReachability.distances.at(neighbour) <= radius; reachable = unitReachability.distances.at(neighbour.toInt()) <= radius;
if(reachable) break; if(reachable) break;
} }
@@ -1009,12 +1008,12 @@ bool BattleExchangeEvaluator::checkPositionBlocksOurStacks(HypotheticBattle & hb
auto unitReachability = turnBattle.getReachability(unit); auto unitReachability = turnBattle.getReachability(unit);
auto unitSpeed = unit->getMovementRange(turn); // Cached value, to avoid performance hit 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 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); const battle::Unit * hexStack = turnBattle.battleGetUnitByPos(hex);
@@ -1023,7 +1022,7 @@ bool BattleExchangeEvaluator::checkPositionBlocksOurStacks(HypotheticBattle & hb
enemyUnit = true; enemyUnit = true;
for(BattleHex neighbour : hex.getNeighbouringTiles()) for(BattleHex neighbour : hex.getNeighbouringTiles())
{ {
reachable = unitReachability.distances.at(neighbour) <= unitSpeed; reachable = unitReachability.distances.at(neighbour.toInt()) <= unitSpeed;
if(reachable) break; if(reachable) break;
} }

View File

@@ -50,7 +50,7 @@ PotentialTargets::PotentialTargets(
auto GenerateAttackInfo = [&](bool shooting, BattleHex hex) -> AttackPossibility 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); auto bai = BattleAttackInfo(attackerInfo, defender, distance, shooting);
return AttackPossibility::evaluate(bai, hex, damageCache, state); return AttackPossibility::evaluate(bai, hex, damageCache, state);

View File

@@ -291,7 +291,7 @@ BattleAction CStupidAI::goTowards(const BattleID & battleID, const CStack * stac
std::sort(hexes.begin(), hexes.end(), [&](BattleHex h1, BattleHex h2) -> bool 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) for(auto hex : hexes)
@@ -313,7 +313,7 @@ BattleAction CStupidAI::goTowards(const BattleID & battleID, const CStack * stac
BattleHex bestneighbour = hexes.front(); BattleHex bestneighbour = hexes.front();
if(reachability.distances[bestneighbour] > GameConstants::BFIELD_SIZE) if(reachability.distances[bestneighbour.toInt()] > GameConstants::BFIELD_SIZE)
{ {
return BattleAction::makeDefend(stack); return BattleAction::makeDefend(stack);
} }
@@ -347,7 +347,7 @@ BattleAction CStupidAI::goTowards(const BattleID & battleID, const CStack * stac
return BattleAction::makeMove(stack, currentDest); return BattleAction::makeMove(stack, currentDest);
} }
currentDest = reachability.predecessors[currentDest]; currentDest = reachability.predecessors[currentDest.toInt()];
} }
} }
} }

View File

@@ -522,7 +522,7 @@ std::string BattleActionsController::actionGetStatusMessage(PossiblePlayerBattle
{ {
const auto * attacker = owner.stacksController->getActiveStack(); const auto * attacker = owner.stacksController->getActiveStack();
BattleHex attackFromHex = owner.fieldController->fromWhichHexAttack(targetHex); 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; DamageEstimation retaliation;
BattleAttackInfo attackInfo(attacker, targetStack, distance, false ); BattleAttackInfo attackInfo(attacker, targetStack, distance, false );
DamageEstimation estimation = owner.getBattle()->battleEstimateDamage(attackInfo, &retaliation); DamageEstimation estimation = owner.getBattle()->battleEstimateDamage(attackInfo, &retaliation);

View File

@@ -174,7 +174,7 @@ AttackAnimation::AttackAnimation(BattleInterface & owner, const CStack *attacker
attackingStack(attacker) attackingStack(attacker)
{ {
assert(attackingStack && "attackingStack is nullptr in CBattleAttack::CBattleAttack !\n"); assert(attackingStack && "attackingStack is nullptr in CBattleAttack::CBattleAttack !\n");
attackingStackPosBeforeReturn = attackingStack->getPosition(); attackingStackPosBeforeReturn = attackingStack->getPosition().toInt();
} }
HittedAnimation::HittedAnimation(BattleInterface & owner, const CStack * stack) HittedAnimation::HittedAnimation(BattleInterface & owner, const CStack * stack)

View File

@@ -839,7 +839,7 @@ void BattleFieldController::updateAccessibleHexes()
bool BattleFieldController::stackCountOutsideHex(const BattleHex & number) const bool BattleFieldController::stackCountOutsideHex(const BattleHex & number) const
{ {
return stackCountOutsideHexes[number]; return stackCountOutsideHexes[number.toInt()];
} }
void BattleFieldController::showAll(Canvas & to) void BattleFieldController::showAll(Canvas & to)

View File

@@ -185,7 +185,7 @@ BattleSiegeController::BattleSiegeController(BattleInterface & owner, const CGTo
const CCreature *BattleSiegeController::getTurretCreature(BattleHex position) const const CCreature *BattleSiegeController::getTurretCreature(BattleHex position) const
{ {
switch (position) switch (position.toInt())
{ {
case BattleHex::CASTLE_CENTRAL_TOWER: case BattleHex::CASTLE_CENTRAL_TOWER:
return town->fortificationsLevel().citadelShooter.toCreature(); return town->fortificationsLevel().citadelShooter.toCreature();
@@ -195,14 +195,14 @@ const CCreature *BattleSiegeController::getTurretCreature(BattleHex position) co
return town->fortificationsLevel().lowerTowerShooter.toCreature(); 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 Point BattleSiegeController::getTurretCreaturePosition( BattleHex position ) const
{ {
// Turret positions are read out of the config/wall_pos.txt // Turret positions are read out of the config/wall_pos.txt
int posID = 0; int posID = 0;
switch (position) switch (position.toInt())
{ {
case BattleHex::CASTLE_CENTRAL_TOWER: // keep creature case BattleHex::CASTLE_CENTRAL_TOWER: // keep creature
posID = EWallVisual::CREATURE_KEEP; posID = EWallVisual::CREATURE_KEEP;

View File

@@ -252,8 +252,8 @@ BattleHexArray CStack::meleeAttackHexes(const battle::Unit * attacker, const bat
if (!defenderPos.isValid()) if (!defenderPos.isValid())
defenderPos = defender->getPosition(); defenderPos = defender->getPosition();
BattleHex otherAttackerPos = attackerPos + (attacker->unitSide() == BattleSide::ATTACKER ? -1 : 1); BattleHex otherAttackerPos = attackerPos.toInt() + (attacker->unitSide() == BattleSide::ATTACKER ? -1 : 1);
BattleHex otherDefenderPos = defenderPos + (defender->unitSide() == BattleSide::ATTACKER ? -1 : 1); BattleHex otherDefenderPos = defenderPos.toInt() + (defender->unitSide() == BattleSide::ATTACKER ? -1 : 1);
if(BattleHex::mutualPosition(attackerPos, defenderPos) >= 0) //front <=> front if(BattleHex::mutualPosition(attackerPos, defenderPos) >= 0) //front <=> front
{ {

View File

@@ -66,7 +66,7 @@ BattleHexArray ObstacleInfo::getBlocked(BattleHex hex) const
BattleHexArray ret; BattleHexArray ret;
for(int offset : blockedTiles) for(int offset : blockedTiles)
{ {
BattleHex toBlock = hex + offset; BattleHex toBlock = hex.toInt() + offset;
if((hex.getY() & 1) && !(toBlock.getY() & 1)) if((hex.getY() & 1) && !(toBlock.getY() & 1))
toBlock += BattleHex::LEFT; toBlock += BattleHex::LEFT;

View File

@@ -18,14 +18,14 @@ VCMI_LIB_NAMESPACE_BEGIN
bool AccessibilityInfo::tileAccessibleWithGate(BattleHex tile, BattleSide side) const bool AccessibilityInfo::tileAccessibleWithGate(BattleHex tile, BattleSide side) const
{ {
//at(otherHex) != EAccessibility::ACCESSIBLE && (at(otherHex) != EAccessibility::GATE || side != BattleSide::DEFENDER) //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(accessibility == EAccessibility::ALIVE_STACK)
{ {
if(!destructibleEnemyTurns) if(!destructibleEnemyTurns)
return false; return false;
return destructibleEnemyTurns->at(tile) >= 0; return destructibleEnemyTurns->at(tile.toInt()) >= 0;
} }
if(accessibility != EAccessibility::ACCESSIBLE) if(accessibility != EAccessibility::ACCESSIBLE)

View File

@@ -32,10 +32,11 @@ enum class EAccessibility
using TAccessibilityArray = std::array<EAccessibility, GameConstants::BFIELD_SIZE>; using TAccessibilityArray = std::array<EAccessibility, GameConstants::BFIELD_SIZE>;
using TBattlefieldTurnsArray = std::array<int8_t, GameConstants::BFIELD_SIZE>;
struct DLL_LINKAGE AccessibilityInfo : TAccessibilityArray 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: public:
bool accessible(BattleHex tile, const battle::Unit * stack) const; //checks for both tiles if stack is double wide bool accessible(BattleHex tile, const battle::Unit * stack) const; //checks for both tiles if stack is double wide

View File

@@ -48,24 +48,24 @@ BattleHex BattleHex::getClosestTile(BattleSide side, BattleHex initialPos, const
return (bestTile != closestTiles.end()) ? *bestTile : BattleHex(); return (bestTile != closestTiles.end()) ? *bestTile : BattleHex();
} }
const BattleHexArray & BattleHex::getAllNeighbouringTiles() const const BattleHexArray & BattleHex::getAllNeighbouringTiles() const noexcept
{ {
return BattleHexArray::getAllNeighbouringTiles(*this); return BattleHexArray::getAllNeighbouringTiles(*this);
} }
const BattleHexArray & BattleHex::getNeighbouringTiles() const const BattleHexArray & BattleHex::getNeighbouringTiles() const noexcept
{ {
return BattleHexArray::getNeighbouringTiles(*this); 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) 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 VCMI_LIB_NAMESPACE_END

View File

@@ -24,7 +24,8 @@ namespace GameConstants
class BattleHexArray; 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 class DLL_LINKAGE BattleHex
{ {
public: public:
@@ -68,10 +69,10 @@ public:
BOTTOM BOTTOM
}; };
BattleHex() BattleHex() noexcept
: hex(INVALID) : hex(INVALID)
{} {}
BattleHex(si16 _hex) BattleHex(si16 _hex) noexcept
: hex(_hex) : hex(_hex)
{} {}
BattleHex(si16 x, si16 y) BattleHex(si16 x, si16 y)
@@ -82,17 +83,13 @@ public:
{ {
setXY(xy); setXY(xy);
} }
operator si16() const
{
return hex;
}
inline bool isValid() const [[nodiscard]] bool isValid() const noexcept
{ {
return hex >= 0 && hex < GameConstants::BFIELD_SIZE; 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; return isValid() && getX() > 0 && getX() < GameConstants::BFIELD_WIDTH - 1;
} }
@@ -123,17 +120,17 @@ public:
setXY(xy.first, xy.second); setXY(xy.first, xy.second);
} }
si16 getX() const [[nodiscard]] si16 getX() const noexcept
{ {
return hex % GameConstants::BFIELD_WIDTH; return hex % GameConstants::BFIELD_WIDTH;
} }
si16 getY() const [[nodiscard]] si16 getY() const noexcept
{ {
return hex / GameConstants::BFIELD_WIDTH; 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()); return std::make_pair(getX(), getY());
} }
@@ -171,24 +168,14 @@ public:
return *this; return *this;
} }
BattleHex & operator+=(EDir dir) [[nodiscard]] BattleHex cloneInDirection(EDir dir, bool hasToBeValid = true) const
{
return moveInDirection(dir);
}
BattleHex operator+(EDir dir) const
{
return cloneInDirection(dir);
}
BattleHex cloneInDirection(EDir dir, bool hasToBeValid = true) const
{ {
BattleHex result(hex); BattleHex result(hex);
result.moveInDirection(dir, hasToBeValid); result.moveInDirection(dir, hasToBeValid);
return result; 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 y1 = hex1.getY();
int y2 = hex2.getY(); int y2 = hex2.getY();
@@ -205,15 +192,15 @@ public:
return std::abs(xDst) + std::abs(yDst); 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 //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}; 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()) for(auto dir : hexagonalDirections())
if(hex2 == hex1.cloneInDirection(dir, false)) if(hex2 == hex1.cloneInDirection(dir, false))
@@ -222,13 +209,59 @@ public:
} }
/// get (precomputed) all possible surrounding tiles /// get (precomputed) all possible surrounding tiles
const BattleHexArray & getAllNeighbouringTiles() const; [[nodiscard]] const BattleHexArray & getAllNeighbouringTiles() const noexcept;
/// get (precomputed) only valid and available surrounding tiles /// 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 /// 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> template <typename Handler>
void serialize(Handler & h) void serialize(Handler & h)

View File

@@ -34,7 +34,7 @@ void BattleHexArray::erase(iterator first, iterator last) noexcept
{ {
for(auto it = first; it != last && it != internalStorage.end(); ++it) for(auto it = first; it != last && it != internalStorage.end(); ++it)
{ {
presenceFlags[*it] = 0; presenceFlags[it->toInt()] = 0;
} }
internalStorage.erase(first, last); internalStorage.erase(first, last);
@@ -43,7 +43,7 @@ void BattleHexArray::erase(iterator first, iterator last) noexcept
void BattleHexArray::clear() noexcept void BattleHexArray::clear() noexcept
{ {
for(auto hex : internalStorage) for(auto hex : internalStorage)
presenceFlags[hex] = 0; presenceFlags[hex.toInt()] = 0;
internalStorage.clear(); internalStorage.clear();
} }
@@ -83,7 +83,7 @@ BattleHexArray::ArrayOfBattleHexArrays BattleHexArray::precalculateAllNeighbouri
return ret; return ret;
} }
BattleHexArray::ArrayOfBattleHexArrays BattleHexArray::precalculateNeighbouringTilesDblWide(BattleSide side) BattleHexArray::ArrayOfBattleHexArrays BattleHexArray::precalculateNeighbouringTilesDoubleWide(BattleSide side)
{ {
ArrayOfBattleHexArrays ret; ArrayOfBattleHexArrays ret;
@@ -123,10 +123,10 @@ BattleHexArray::ArrayOfBattleHexArrays BattleHexArray::precalculateNeighbouringT
const BattleHexArray::ArrayOfBattleHexArrays BattleHexArray::neighbouringTiles = precalculateNeighbouringTiles(); const BattleHexArray::ArrayOfBattleHexArrays BattleHexArray::neighbouringTiles = precalculateNeighbouringTiles();
const BattleHexArray::ArrayOfBattleHexArrays BattleHexArray::allNeighbouringTiles = precalculateAllNeighbouringTiles(); 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::ATTACKER, precalculateNeighbouringTilesDoubleWide(BattleSide::ATTACKER) },
{ BattleSide::DEFENDER, precalculateNeighbouringTilesDblWide(BattleSide::DEFENDER) } { BattleSide::DEFENDER, precalculateNeighbouringTilesDoubleWide(BattleSide::DEFENDER) }
}; };
VCMI_LIB_NAMESPACE_END VCMI_LIB_NAMESPACE_END

View File

@@ -60,7 +60,7 @@ public:
{ {
if(tile.isAvailable() && !contains(tile)) if(tile.isAvailable() && !contains(tile))
{ {
presenceFlags[tile] = 1; presenceFlags[tile.toInt()] = true;
internalStorage.emplace_back(tile); internalStorage.emplace_back(tile);
} }
} }
@@ -70,7 +70,7 @@ public:
if(contains(hex)) if(contains(hex))
return; return;
presenceFlags[hex] = 1; presenceFlags[hex.toInt()] = true;
internalStorage.emplace_back(hex); internalStorage.emplace_back(hex);
} }
@@ -87,7 +87,7 @@ public:
if(contains(hex)) if(contains(hex))
return; return;
presenceFlags[hex] = 1; presenceFlags[hex.toInt()] = true;
internalStorage[index] = hex; internalStorage[index] = hex;
} }
@@ -96,7 +96,7 @@ public:
if(contains(hex)) if(contains(hex))
return pos; return pos;
presenceFlags[hex] = 1; presenceFlags[hex.toInt()] = true;
return internalStorage.insert(pos, hex); return internalStorage.insert(pos, hex);
} }
@@ -122,7 +122,7 @@ public:
void erase(iterator first, iterator last) noexcept; void erase(iterator first, iterator last) noexcept;
inline void pop_back() noexcept inline void pop_back() noexcept
{ {
presenceFlags[internalStorage.back()] = 0; presenceFlags[internalStorage.back().toInt()] = false;
internalStorage.pop_back(); internalStorage.pop_back();
} }
@@ -158,33 +158,33 @@ public:
} }
/// get (precomputed) all possible surrounding tiles /// get (precomputed) all possible surrounding tiles
static const BattleHexArray & getAllNeighbouringTiles(BattleHex hex) static const BattleHexArray & getAllNeighbouringTiles(BattleHex hex) noexcept
{ {
assert(hex.isValid()); assert(hex.isValid());
return allNeighbouringTiles[hex]; return allNeighbouringTiles[hex.toInt()];
} }
/// get (precomputed) only valid and available surrounding tiles /// get (precomputed) only valid and available surrounding tiles
static const BattleHexArray & getNeighbouringTiles(BattleHex hex) static const BattleHexArray & getNeighbouringTiles(BattleHex hex) noexcept
{ {
assert(hex.isValid()); assert(hex.isValid());
return neighbouringTiles[hex]; return neighbouringTiles[hex.toInt()];
} }
/// get (precomputed) only valid and available surrounding tiles for double wide creatures /// 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)); 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 [[nodiscard]] inline bool contains(BattleHex hex) const noexcept
{ {
if(hex.isValid()) if(hex.isValid())
return presenceFlags[hex]; return presenceFlags[hex.toInt()];
/* /*
if(!isTower(hex)) if(!isTower(hex))
logGlobal->warn("BattleHexArray::contains( %d ) - invalid BattleHex!", hex); logGlobal->warn("BattleHexArray::contains( %d ) - invalid BattleHex!", hex);
@@ -198,10 +198,10 @@ public:
void serialize(Serializer & s) void serialize(Serializer & s)
{ {
s & internalStorage; s & internalStorage;
if(!internalStorage.empty() && presenceFlags[internalStorage.front()] == 0) if(!s.saving)
{ {
for(auto hex : internalStorage) for(auto hex : internalStorage)
presenceFlags[hex] = 1; presenceFlags[hex.toInt()] = true;
} }
} }
@@ -307,11 +307,11 @@ private:
static const ArrayOfBattleHexArrays neighbouringTiles; static const ArrayOfBattleHexArrays neighbouringTiles;
static const ArrayOfBattleHexArrays allNeighbouringTiles; static const ArrayOfBattleHexArrays allNeighbouringTiles;
static const std::map<BattleSide, ArrayOfBattleHexArrays> neighbouringTilesDblWide; static const std::map<BattleSide, ArrayOfBattleHexArrays> neighbouringTilesDoubleWide;
static ArrayOfBattleHexArrays precalculateNeighbouringTiles(); static ArrayOfBattleHexArrays precalculateNeighbouringTiles();
static ArrayOfBattleHexArrays precalculateAllNeighbouringTiles(); static ArrayOfBattleHexArrays precalculateAllNeighbouringTiles();
static ArrayOfBattleHexArrays precalculateNeighbouringTilesDblWide(BattleSide side); static ArrayOfBattleHexArrays precalculateNeighbouringTilesDoubleWide(BattleSide side);
}; };
VCMI_LIB_NAMESPACE_END VCMI_LIB_NAMESPACE_END

View File

@@ -46,7 +46,7 @@ CStack * BattleInfo::generateNewStack(uint32_t id, const CStackInstance & base,
assert(!owner.isValidPlayer() || (base.armyObj && base.armyObj->tempOwner == owner)); assert(!owner.isValidPlayer() || (base.armyObj && base.armyObj->tempOwner == owner));
auto * ret = new CStack(&base, owner, id, side, slot); 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); stacks.push_back(ret);
return ret; return ret;
} }
@@ -264,7 +264,7 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
for(BattleHex blocked : obi.getBlocked(pos)) 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; return false;
if(blockedTiles.contains(blocked)) if(blockedTiles.contains(blocked))
return false; return false;

View File

@@ -43,19 +43,15 @@ static BattleHex lineToWallHex(int line) //returns hex with wall in given line (
static bool sameSideOfWall(BattleHex pos1, BattleHex pos2) static bool sameSideOfWall(BattleHex pos1, BattleHex pos2)
{ {
const int wallInStackLine = lineToWallHex(pos1.getY()); const bool stackLeft = pos1 < lineToWallHex(pos1.getY());
const int wallInDestLine = lineToWallHex(pos2.getY()); const bool destLeft = pos2 < lineToWallHex(pos2.getY());
const bool stackLeft = pos1 < wallInStackLine;
const bool destLeft = pos2 < wallInDestLine;
return stackLeft == destLeft; return stackLeft == destLeft;
} }
static bool isInsideWalls(BattleHex pos) static bool isInsideWalls(BattleHex pos)
{ {
const int wallInStackLine = lineToWallHex(pos.getY()); return lineToWallHex(pos.getY()) < pos;
return wallInStackLine < pos;
} }
// parts of wall // parts of wall
@@ -79,9 +75,10 @@ static const std::pair<int, EWallPart> wallParts[] =
static EWallPart hexToWallPart(BattleHex hex) static EWallPart hexToWallPart(BattleHex hex)
{ {
si16 hexValue = hex.toInt();
for(const auto & elem : wallParts) for(const auto & elem : wallParts)
{ {
if(elem.first == hex) if(elem.first == hexValue)
return elem.second; return elem.second;
} }
@@ -151,7 +148,7 @@ std::pair< BattleHexArray, int > CBattleInfoCallback::getPath(BattleHex start, B
{ {
auto reachability = getReachability(stack); 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); return std::make_pair(BattleHexArray(), 0);
} }
@@ -162,10 +159,10 @@ std::pair< BattleHexArray, int > CBattleInfoCallback::getPath(BattleHex start, B
while(curElem != start) while(curElem != start)
{ {
path.insert(curElem); 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 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 bool CBattleInfoCallback::battleHasPenaltyOnLine(BattleHex from, BattleHex dest, bool checkWall, bool checkMoat) const
{ {
if (!from.isAvailable() || !dest.isAvailable()) 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) auto isTileBlocked = [&](BattleHex tile)
{ {
@@ -225,7 +222,7 @@ bool CBattleInfoCallback::battleHasPenaltyOnLine(BattleHex from, BattleHex dest,
auto obstacles = battleGetAllObstaclesOnPos(hex, false); auto obstacles = battleGetAllObstaclesOnPos(hex, false);
if(hex != BattleHex::GATE_BRIDGE || (battleIsGatePassable())) if(hex.toInt() != BattleHex::GATE_BRIDGE || (battleIsGatePassable()))
for(const auto & obst : obstacles) for(const auto & obst : obstacles)
if(obst->obstacleType == CObstacleInstance::MOAT) if(obst->obstacleType == CObstacleInstance::MOAT)
pathHasMoat |= true; pathHasMoat |= true;
@@ -786,7 +783,7 @@ DamageEstimation CBattleInfoCallback::battleEstimateDamage(const battle::Unit *
{ {
RETURN_IF_NOT_BATTLE({}); RETURN_IF_NOT_BATTLE({});
auto reachability = battleGetDistances(attacker, attacker->getPosition()); 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); return battleEstimateDamage(attacker, defender, movementRange, retaliationDmg);
} }
@@ -955,8 +952,8 @@ AccessibilityInfo CBattleInfoCallback::getAccessibility() const
//removing accessibility for side columns of hexes //removing accessibility for side columns of hexes
for(int y = 0; y < GameConstants::BFIELD_HEIGHT; y++) for(int y = 0; y < GameConstants::BFIELD_HEIGHT; y++)
{ {
ret[BattleHex(GameConstants::BFIELD_WIDTH - 1, y)] = EAccessibility::SIDE_COLUMN; ret[BattleHex(GameConstants::BFIELD_WIDTH - 1, y).toInt()] = EAccessibility::SIDE_COLUMN;
ret[BattleHex(0, y)] = EAccessibility::SIDE_COLUMN; ret[BattleHex(0, y).toInt()] = EAccessibility::SIDE_COLUMN;
} }
//special battlefields with logically unavailable tiles //special battlefields with logically unavailable tiles
@@ -965,7 +962,7 @@ AccessibilityInfo CBattleInfoCallback::getAccessibility() const
if(bFieldType != BattleField::NONE) if(bFieldType != BattleField::NONE)
{ {
for(auto hex : bFieldType.getInfo()->impassableHexes) for(auto hex : bFieldType.getInfo()->impassableHexes)
ret[hex] = EAccessibility::UNAVAILABLE; ret[hex.toInt()] = EAccessibility::UNAVAILABLE;
} }
//gate -> should be before stacks //gate -> should be before stacks
@@ -990,14 +987,14 @@ AccessibilityInfo CBattleInfoCallback::getAccessibility() const
{ {
for(auto hex : unit->getHexes()) for(auto hex : unit->getHexes())
if(hex.isAvailable()) //towers can have <0 pos; we don't also want to overwrite side columns 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 //obstacles
for(const auto &obst : battleGetAllObstacles()) for(const auto &obst : battleGetAllObstacles())
{ {
for(auto hex : obst->getBlockedTiles()) for(auto hex : obst->getBlockedTiles())
ret[hex] = EAccessibility::OBSTACLE; ret[hex.toInt()] = EAccessibility::OBSTACLE;
} }
//walls //walls
@@ -1020,7 +1017,7 @@ AccessibilityInfo CBattleInfoCallback::getAccessibility() const
for(const auto & elem : lockedIfNotDestroyed) for(const auto & elem : lockedIfNotDestroyed)
{ {
if(battleGetWallState(elem.first) != EWallState::DESTROYED) 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 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(); auto ret = getAccessibility();
for(auto hex : *accessibleHexes) for(auto hex : accessibleHexes)
if(hex.isValid()) if(hex.isValid())
ret[hex] = EAccessibility::ACCESSIBLE; ret[hex.toInt()] = EAccessibility::ACCESSIBLE;
return ret; return ret;
} }
@@ -1062,7 +1059,7 @@ ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo & accessib
//first element //first element
hexq.push(params.startPosition); hexq.push(params.startPosition);
ret.distances[params.startPosition] = 0; ret.distances[params.startPosition.toInt()] = 0;
std::array<bool, GameConstants::BFIELD_SIZE> accessibleCache{}; std::array<bool, GameConstants::BFIELD_SIZE> accessibleCache{};
for(int hex = 0; hex < GameConstants::BFIELD_SIZE; hex++) for(int hex = 0; hex < GameConstants::BFIELD_SIZE; hex++)
@@ -1077,7 +1074,7 @@ ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo & accessib
if(isInObstacle(curHex, obstacles, checkParams)) if(isInObstacle(curHex, obstacles, checkParams))
continue; continue;
const int costToNeighbour = ret.distances.at(curHex) + 1; const int costToNeighbour = ret.distances.at(curHex.toInt()) + 1;
for(BattleHex neighbour : curHex.getNeighbouringTiles()) for(BattleHex neighbour : curHex.getNeighbouringTiles())
{ {
@@ -1085,7 +1082,7 @@ ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo & accessib
if(params.bypassEnemyStacks) if(params.bypassEnemyStacks)
{ {
auto enemyToBypass = params.destructibleEnemyTurns.at(neighbour); auto enemyToBypass = params.destructibleEnemyTurns.at(neighbour.toInt());
if(enemyToBypass >= 0) 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); hexq.push(neighbour);
ret.distances[neighbour] = costToNeighbour + additionalCost; ret.distances[neighbour.toInt()] = costToNeighbour + additionalCost;
ret.predecessors[neighbour] = curHex; ret.predecessors[neighbour.toInt()] = curHex;
} }
} }
} }
@@ -1181,7 +1178,7 @@ std::pair<const battle::Unit *, BattleHex> CBattleInfoCallback::getNearestStack(
for(BattleHex hex : avHexes) for(BattleHex hex : avHexes)
if(CStack::isMeleeAttackPossible(closest, st, hex)) 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); stackPairs.push_back(hlp);
} }
} }
@@ -1272,9 +1269,12 @@ ReachabilityInfo CBattleInfoCallback::getReachability(const ReachabilityInfo::Pa
return getFlyingReachability(params); return getFlyingReachability(params);
else 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); return makeBFS(accessibility, params);
} }
@@ -1283,7 +1283,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; ReachabilityInfo ret;
ret.accessibility = getAccessibility(params.knownAccessible); ret.accessibility = getAccessibility(* params.knownAccessible);
for(int i = 0; i < GameConstants::BFIELD_SIZE; i++) for(int i = 0; i < GameConstants::BFIELD_SIZE; i++)
{ {
@@ -1326,9 +1326,9 @@ AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes(
AttackableTiles at; AttackableTiles at;
RETURN_IF_NOT_BATTLE(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); bool reverse = isToReverse(attacker, defender, attackerPos, defenderPos);
if(reverse && attacker->doubleWide()) if(reverse && attacker->doubleWide())

View File

@@ -162,7 +162,7 @@ public:
ReachabilityInfo getReachability(const ReachabilityInfo::Parameters & params) const; ReachabilityInfo getReachability(const ReachabilityInfo::Parameters & params) const;
AccessibilityInfo getAccessibility() const; AccessibilityInfo getAccessibility() const;
AccessibilityInfo getAccessibility(const battle::Unit * stack) const; //Hexes occupied by stack will be marked as accessible. 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; 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 BattleHex getAvailableHex(const CreatureID & creID, BattleSide side, int initialPos = -1) const; //find place for adding new stack

View File

@@ -113,7 +113,9 @@ void CObstacleInstance::serializeJson(JsonSerializeFormat & handler)
animationYOffset -= 42; animationYOffset -= 42;
//We need only a subset of obstacle info for correct render //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.serializeInt("animationYOffset", animationYOffset);
handler.serializeBool("hidden", hidden); handler.serializeBool("hidden", hidden);
handler.serializeBool("needAnimationOffsetFix", needAnimationOffsetFix); handler.serializeBool("needAnimationOffsetFix", needAnimationOffsetFix);
@@ -188,7 +190,9 @@ void SpellCreatedObstacle::fromInfo(const ObstacleChanges & info)
void SpellCreatedObstacle::serializeJson(JsonSerializeFormat & handler) void SpellCreatedObstacle::serializeJson(JsonSerializeFormat & handler)
{ {
handler.serializeInt("spell", ID); handler.serializeInt("spell", ID);
handler.serializeInt("position", pos); si16 posValue = pos.toInt();
handler.serializeInt("position", posValue);
pos = posValue;
handler.serializeInt("turnsRemaining", turnsRemaining); handler.serializeInt("turnsRemaining", turnsRemaining);
handler.serializeInt("casterSpellPower", casterSpellPower); handler.serializeInt("casterSpellPower", casterSpellPower);
@@ -215,9 +219,9 @@ void SpellCreatedObstacle::serializeJson(JsonSerializeFormat & handler)
JsonArraySerializer customSizeJson = handler.enterArray("customSize"); JsonArraySerializer customSizeJson = handler.enterArray("customSize");
customSizeJson.syncSize(customSize, JsonNode::JsonType::DATA_INTEGER); customSizeJson.syncSize(customSize, JsonNode::JsonType::DATA_INTEGER);
BattleHex hex;
for(size_t index = 0; index < customSizeJson.size(); index++) for(size_t index = 0; index < customSizeJson.size(); index++)
{ {
si16 hex = customSize.at(index).toInt();
customSizeJson.serializeInt(index, hex); customSizeJson.serializeInt(index, hex);
customSize.set(index, hex); customSize.set(index, hex);
} }

View File

@@ -798,7 +798,9 @@ void CUnitState::serializeJson(JsonSerializeFormat & handler)
handler.serializeInt("cloneID", cloneID); handler.serializeInt("cloneID", cloneID);
handler.serializeInt("position", position); si16 posValue = position.toInt();
handler.serializeInt("position", posValue);
position = posValue;
} }
void CUnitState::localInit(const IUnitEnvironment * env_) void CUnitState::localInit(const IUnitEnvironment * env_)

View File

@@ -45,7 +45,7 @@ DamageRange DamageCalculator::getBaseDamageSingle() const
const auto * town = callback.battleGetDefendedTown(); const auto * town = callback.battleGetDefendedTown();
assert(town); assert(town);
switch(info.attacker->getPosition()) switch(info.attacker->getPosition().toInt())
{ {
case BattleHex::CASTLE_CENTRAL_TOWER: case BattleHex::CASTLE_CENTRAL_TOWER:
return town->getKeepDamageRange(); return town->getKeepDamageRange();

View File

@@ -33,7 +33,7 @@ ReachabilityInfo::ReachabilityInfo()
bool ReachabilityInfo::isReachable(BattleHex hex) const bool ReachabilityInfo::isReachable(BattleHex hex) const
{ {
return distances[hex] < INFINITE_DIST; return distances[hex.toInt()] < INFINITE_DIST;
} }
uint32_t ReachabilityInfo::distToNearestNeighbour( uint32_t ReachabilityInfo::distToNearestNeighbour(
@@ -46,9 +46,9 @@ uint32_t ReachabilityInfo::distToNearestNeighbour(
{ {
for(auto & n : targetHex.getNeighbouringTiles()) for(auto & n : targetHex.getNeighbouringTiles())
{ {
if(distances[n] < ret) if(distances[n.toInt()] < ret)
{ {
ret = distances[n]; ret = distances[n.toInt()];
if(chosenHex) if(chosenHex)
*chosenHex = n; *chosenHex = n;
} }

View File

@@ -33,7 +33,7 @@ struct DLL_LINKAGE ReachabilityInfo
bool ignoreKnownAccessible = false; //Ignore obstacles if it is in accessible hexes 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 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) 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 BattleHex startPosition; //assumed position of stack
BattleSide perspective = BattleSide::ALL_KNOWING; //some obstacles (eg. quicksands) may be invisible for some side BattleSide perspective = BattleSide::ALL_KNOWING; //some obstacles (eg. quicksands) may be invisible for some side

View File

@@ -53,7 +53,7 @@ const IBonusBearer* Unit::getBonusBearer() const
const BattleHexArray & Unit::getSurroundingHexes(BattleHex assumedPosition) 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()); return getSurroundingHexes(hex, doubleWide(), unitSide());
} }
@@ -63,7 +63,7 @@ const BattleHexArray & Unit::getSurroundingHexes(BattleHex position, bool twoHex
if(!twoHex) if(!twoHex)
return position.getNeighbouringTiles(); return position.getNeighbouringTiles();
return position.getNeighbouringTilesDblWide(side); return position.getNeighbouringTilesDoubleWide(side);
} }
BattleHexArray Unit::getAttackableHexes(const Unit * attacker) const 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]; static BattleHexArray::ArrayOfBattleHexArrays precomputed[4];
int index = side == BattleSide::ATTACKER ? 0 : 2; int index = side == BattleSide::ATTACKER ? 0 : 2;
if(!precomputed[index + twoHex][assumedPos].empty()) if(!precomputed[index + twoHex][assumedPos.toInt()].empty())
return precomputed[index + twoHex][assumedPos]; return precomputed[index + twoHex][assumedPos.toInt()];
// first run, compute // first run, compute
@@ -123,9 +123,9 @@ const BattleHexArray & Unit::getHexes(BattleHex assumedPos, bool twoHex, BattleS
if(twoHex) if(twoHex)
hexes.insert(occupiedHex(assumedPos, twoHex, side)); 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 BattleHex Unit::occupiedHex() const
@@ -143,9 +143,9 @@ BattleHex Unit::occupiedHex(BattleHex assumedPos, bool twoHex, BattleSide side)
if(twoHex) if(twoHex)
{ {
if(side == BattleSide::ATTACKER) if(side == BattleSide::ATTACKER)
return assumedPos - 1; return assumedPos.toInt() - 1;
else else
return assumedPos + 1; return assumedPos.toInt() + 1;
} }
else else
{ {
@@ -201,7 +201,9 @@ void UnitInfo::serializeJson(JsonSerializeFormat & handler)
handler.serializeInt("count", count); handler.serializeInt("count", count);
handler.serializeId("type", type, CreatureID(CreatureID::NONE)); handler.serializeId("type", type, CreatureID(CreatureID::NONE));
handler.serializeInt("side", side); handler.serializeInt("side", side);
handler.serializeInt("position", position); si16 positionValue = position.toInt();
handler.serializeInt("position", positionValue);
position = positionValue;
handler.serializeBool("summoned", summoned); handler.serializeBool("summoned", summoned);
} }

View File

@@ -84,11 +84,14 @@ public:
bool isTurret() const; 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 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 isClone() const = 0;
virtual bool hasClone() const = 0; virtual bool hasClone() const = 0;
virtual bool canCast() const = 0; virtual bool canCast() const = 0;
virtual bool isCaster() const = 0; virtual bool isCaster() const = 0;
virtual bool canShootBlocked() const = 0;
virtual bool canShoot() const = 0; virtual bool canShoot() const = 0;
virtual bool isShooter() const = 0; virtual bool isShooter() const = 0;
@@ -112,8 +115,6 @@ public:
virtual BattleHex getPosition() const = 0; virtual BattleHex getPosition() const = 0;
virtual void setPosition(BattleHex hex) = 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 canMove(int turn = 0) const = 0; //if stack can move
virtual bool defended(int turn = 0) const = 0; virtual bool defended(int turn = 0) const = 0;
virtual bool moved(int turn = 0) const = 0; //if stack was already moved this turn virtual bool moved(int turn = 0) const = 0; //if stack was already moved this turn

View File

@@ -238,7 +238,7 @@ JsonNode UnitOnHexLimiter::toJsonNode() const
root["type"].String() = "UNIT_ON_HEXES"; root["type"].String() = "UNIT_ON_HEXES";
for(auto hex : applicableHexes) for(auto hex : applicableHexes)
root["parameters"].Vector().emplace_back(hex); root["parameters"].Vector().emplace_back(hex.toInt());
return root; return root;
} }

View File

@@ -517,7 +517,7 @@ BattleHexArray BattleSpellMechanics::spellRangeInHexes(BattleHex centralHex) con
for(auto & elem : rng) for(auto & elem : rng)
{ {
std::set<ui16> curLayer = getInRange(centralHex, elem, elem); std::set<ui16> curLayer = getInRange(centralHex.toInt(), elem, elem);
//adding obtained hexes //adding obtained hexes
for(const auto & curLayer_it : curLayer) for(const auto & curLayer_it : curLayer)
ret.insert(curLayer_it); ret.insert(curLayer_it);

View File

@@ -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) std::shared_ptr<CSpell> CSpellHandler::loadFromJson(const std::string & scope, const JsonNode & json, const std::string & identifier, size_t index)

View File

@@ -95,7 +95,7 @@ void Catapult::applyMassive(ServerCallback * server, const Mechanics * m) const
CatapultAttack::AttackInfo newInfo; CatapultAttack::AttackInfo newInfo;
newInfo.damageDealt = getRandomDamage(server); newInfo.damageDealt = getRandomDamage(server);
newInfo.attackedPart = target; newInfo.attackedPart = target;
newInfo.destinationTile = m->battle()->wallPartToBattleHex(target); newInfo.destinationTile = m->battle()->wallPartToBattleHex(target).toInt();
ca.attackedParts.push_back(newInfo); ca.attackedParts.push_back(newInfo);
attackInfo = ca.attackedParts.end() - 1; attackInfo = ca.attackedParts.end() - 1;
} }
@@ -137,7 +137,7 @@ void Catapult::applyTargeted(ServerCallback * server, const Mechanics * m, const
CatapultAttack::AttackInfo attack; CatapultAttack::AttackInfo attack;
attack.attackedPart = actualTarget; attack.attackedPart = actualTarget;
attack.destinationTile = m->battle()->wallPartToBattleHex(actualTarget); attack.destinationTile = m->battle()->wallPartToBattleHex(actualTarget).toInt();
attack.damageDealt = getRandomDamage(server); attack.damageDealt = getRandomDamage(server);
CatapultAttack ca; //package for clients CatapultAttack ca; //package for clients

View File

@@ -43,7 +43,7 @@ void Clone::apply(ServerCallback * server, const Mechanics * m, const EffectTarg
if(clonedStack->getCount() < 1) if(clonedStack->getCount() < 1)
continue; 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()) if(!hex.isValid())
{ {

View File

@@ -65,7 +65,7 @@ void DemonSummon::apply(ServerCallback * server, const Mechanics * m, const Effe
continue; 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()) if(!hex.isValid())
{ {

View File

@@ -43,9 +43,9 @@ static void serializeMoatHexes(JsonSerializeFormat & handler, const std::string
JsonArraySerializer inner = outer.enterArray(outerIndex); JsonArraySerializer inner = outer.enterArray(outerIndex);
inner.syncSize(moatHexes.at(outerIndex), JsonNode::JsonType::DATA_INTEGER); inner.syncSize(moatHexes.at(outerIndex), JsonNode::JsonType::DATA_INTEGER);
BattleHex hex;
for(size_t innerIndex = 0; innerIndex < inner.size(); innerIndex++) for(size_t innerIndex = 0; innerIndex < inner.size(); innerIndex++)
{ {
si16 hex = moatHexes.at(outerIndex).at(innerIndex).toInt();
inner.serializeInt(innerIndex, hex); inner.serializeInt(innerIndex, hex);
moatHexes.at(outerIndex).set(innerIndex, hex); moatHexes.at(outerIndex).set(innerIndex, hex);
} }

View File

@@ -223,7 +223,7 @@ EffectTarget UnitEffect::transformTargetByChain(const Mechanics * m, const Targe
effectTarget.emplace_back(); effectTarget.emplace_back();
for(auto hex : battle::Unit::getHexes(unit->getPosition(), unit->doubleWide(), unit->unitSide())) for(auto hex : battle::Unit::getHexes(unit->getPosition(), unit->doubleWide(), unit->unitSide()))
possibleHexes.erase(hex); possibleHexes.erase(hex.toInt());
if(possibleHexes.empty()) if(possibleHexes.empty())
break; break;

View File

@@ -98,7 +98,7 @@ bool LuaSpellEffect::applicable(Problem & problem, const Mechanics * m, const Ef
for(const auto & dest : target) for(const auto & dest : target)
{ {
JsonNode targetData; JsonNode targetData;
targetData.Vector().emplace_back(static_cast<si16>(dest.hexValue)); targetData.Vector().emplace_back(dest.hexValue.toInt());
if(dest.unitValue) if(dest.unitValue)
targetData.Vector().emplace_back(dest.unitValue->unitId()); 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) for(const auto & dest : target)
{ {
JsonNode targetData; JsonNode targetData;
targetData.Vector().emplace_back(static_cast<si16>(dest.hexValue)); targetData.Vector().emplace_back(dest.hexValue.toInt());
if(dest.unitValue) if(dest.unitValue)
targetData.Vector().emplace_back(dest.unitValue->unitId()); targetData.Vector().emplace_back(dest.unitValue->unitId());

View File

@@ -84,7 +84,7 @@ TEST_F(LuaSpellEffectAPITest, DISABLED_ApplicableOnLeftSideOfField)
BattleHex hex(2,2); BattleHex hex(2,2);
JsonNode first; JsonNode first;
first.Vector().emplace_back(static_cast<si16>(hex)); first.Vector().emplace_back(hex.toInt());
first.Vector().emplace_back(); first.Vector().emplace_back();
JsonNode targets; JsonNode targets;
@@ -113,7 +113,7 @@ TEST_F(LuaSpellEffectAPITest, DISABLED_NotApplicableOnRightSideOfField)
BattleHex hex(11,2); BattleHex hex(11,2);
JsonNode first; JsonNode first;
first.Vector().emplace_back(static_cast<si16>(hex)); first.Vector().emplace_back(hex.toInt());
first.Vector().emplace_back(-1); first.Vector().emplace_back(-1);
JsonNode targets; JsonNode targets;
@@ -138,13 +138,13 @@ TEST_F(LuaSpellEffectAPITest, DISABLED_ApplyMoveUnit)
BattleHex hex1(11,2); BattleHex hex1(11,2);
JsonNode unit; JsonNode unit;
unit.Vector().emplace_back(static_cast<si16>(hex1)); unit.Vector().emplace_back(hex1.toInt());
unit.Vector().emplace_back(42); unit.Vector().emplace_back(42);
BattleHex hex2(5,4); BattleHex hex2(5,4);
JsonNode destination; JsonNode destination;
destination.Vector().emplace_back(static_cast<si16>(hex2)); destination.Vector().emplace_back(hex2.toInt());
destination.Vector().emplace_back(-1); destination.Vector().emplace_back(-1);
JsonNode targets; JsonNode targets;

View File

@@ -154,11 +154,11 @@ TEST_F(LuaSpellEffectTest, ApplicableTargetRedirected)
JsonNode first; JsonNode first;
first.Vector().emplace_back(static_cast<si16>(hex1)); first.Vector().emplace_back(hex1.toInt());
first.Vector().emplace_back(id1); first.Vector().emplace_back(id1);
JsonNode second; JsonNode second;
second.Vector().emplace_back(static_cast<si16>(hex2)); second.Vector().emplace_back(hex2.toInt());
second.Vector().emplace_back(-1); second.Vector().emplace_back(-1);
JsonNode targets; JsonNode targets;
@@ -193,7 +193,7 @@ TEST_F(LuaSpellEffectTest, ApplyRedirected)
subject->apply(&serverMock, &mechanicsMock, target); subject->apply(&serverMock, &mechanicsMock, target);
JsonNode first; JsonNode first;
first.Vector().emplace_back(static_cast<si16>(hex1)); first.Vector().emplace_back(hex1.toInt());
first.Vector().emplace_back(id1); first.Vector().emplace_back(id1);
JsonNode targets; JsonNode targets;