diff --git a/AI/BattleAI/AttackPossibility.cpp b/AI/BattleAI/AttackPossibility.cpp index ced430425..5e3f4b022 100644 --- a/AI/BattleAI/AttackPossibility.cpp +++ b/AI/BattleAI/AttackPossibility.cpp @@ -26,7 +26,7 @@ void DamageCache::cacheDamage(const battle::Unit * attacker, const battle::Unit } -void DamageCache::buildDamageCache(std::shared_ptr hb, int side) +void DamageCache::buildDamageCache(std::shared_ptr hb, BattleSide side) { auto stacks = hb->battleGetUnitsIf([=](const battle::Unit * u) -> bool { diff --git a/AI/BattleAI/AttackPossibility.h b/AI/BattleAI/AttackPossibility.h index 014a4266a..990dcdb00 100644 --- a/AI/BattleAI/AttackPossibility.h +++ b/AI/BattleAI/AttackPossibility.h @@ -27,7 +27,7 @@ public: void cacheDamage(const battle::Unit * attacker, const battle::Unit * defender, std::shared_ptr hb); int64_t getDamage(const battle::Unit * attacker, const battle::Unit * defender, std::shared_ptr hb); int64_t getOriginalDamage(const battle::Unit * attacker, const battle::Unit * defender, std::shared_ptr hb); - void buildDamageCache(std::shared_ptr hb, int side); + void buildDamageCache(std::shared_ptr hb, BattleSide side); }; /// diff --git a/AI/BattleAI/BattleAI.cpp b/AI/BattleAI/BattleAI.cpp index 4e3e97787..202681bf7 100644 --- a/AI/BattleAI/BattleAI.cpp +++ b/AI/BattleAI/BattleAI.cpp @@ -32,7 +32,7 @@ #define LOGFL(text, formattingEl) print(boost::str(boost::format(text) % formattingEl)) CBattleAI::CBattleAI() - : side(-1), + : side(BattleSide::NONE), wasWaitingForRealize(false), wasUnlockingGs(false) { @@ -100,7 +100,7 @@ void CBattleAI::yourTacticPhase(const BattleID & battleID, int distance) cb->battleMakeTacticAction(battleID, BattleAction::makeEndOFTacticPhase(cb->getBattle(battleID)->battleGetTacticsSide())); } -static float getStrengthRatio(std::shared_ptr cb, int side) +static float getStrengthRatio(std::shared_ptr cb, BattleSide side) { auto stacks = cb->battleGetAllStacks(); auto our = 0; @@ -243,7 +243,7 @@ BattleAction CBattleAI::useCatapult(const BattleID & battleID, const CStack * st return attack; } -void CBattleAI::battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side, bool replayAllowed) +void CBattleAI::battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, BattleSide Side, bool replayAllowed) { LOG_TRACE(logAi); side = Side; diff --git a/AI/BattleAI/BattleAI.h b/AI/BattleAI/BattleAI.h index 7074667ef..f36c2cb26 100644 --- a/AI/BattleAI/BattleAI.h +++ b/AI/BattleAI/BattleAI.h @@ -27,7 +27,7 @@ struct CurrentOffensivePotential std::map ourAttacks; std::map enemyAttacks; - CurrentOffensivePotential(ui8 side) + CurrentOffensivePotential(BattleSide side) { for(auto stack : cbc->battleGetStacks()) { @@ -54,7 +54,7 @@ struct CurrentOffensivePotential class CBattleAI : public CBattleGameInterface { - int side; + BattleSide side; std::shared_ptr cb; std::shared_ptr env; @@ -80,7 +80,7 @@ public: BattleAction useCatapult(const BattleID & battleID, const CStack *stack); BattleAction useHealingTent(const BattleID & battleID, const CStack *stack); - void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool Side, bool replayAllowed) override; + void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, BattleSide side, bool replayAllowed) override; //void actionFinished(const BattleAction &action) override;//occurs AFTER every action taken by any stack or by the hero //void actionStarted(const BattleAction &action) override;//occurs BEFORE every action taken by any stack or by the hero //void battleAttack(const BattleAttack *ba) override; //called when stack is performing attack @@ -93,7 +93,7 @@ public: //void battleSpellCast(const BattleSpellCast *sc) override; //void battleStacksEffectsSet(const SetStackEffect & sse) override;//called when a specific effect is set to stacks //void battleTriggerEffect(const BattleTriggerEffect & bte) override; - //void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) override; //called by engine when battle starts; side=0 - left, side=1 - right + //void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, BattleSide side) override; //called by engine when battle starts; side=0 - left, side=1 - right //void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack AutocombatPreferences autobattlePreferences = AutocombatPreferences(); }; diff --git a/AI/BattleAI/BattleEvaluator.cpp b/AI/BattleAI/BattleEvaluator.cpp index a0f0c01af..a20899f11 100644 --- a/AI/BattleAI/BattleEvaluator.cpp +++ b/AI/BattleAI/BattleEvaluator.cpp @@ -686,7 +686,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack) spellcast.spell = castToPerform.spell->id; spellcast.setTarget(castToPerform.dest); spellcast.side = side; - spellcast.stackNumber = (!side) ? -1 : -2; + spellcast.stackNumber = -1; cb->battleMakeSpellAction(battleID, spellcast); activeActionMade = true; diff --git a/AI/BattleAI/BattleEvaluator.h b/AI/BattleAI/BattleEvaluator.h index 6198d56a4..1c71c45f6 100644 --- a/AI/BattleAI/BattleEvaluator.h +++ b/AI/BattleAI/BattleEvaluator.h @@ -33,7 +33,7 @@ class BattleEvaluator std::optional cachedAttack; PlayerColor playerID; BattleID battleID; - int side; + BattleSide side; float cachedScore; DamageCache damageCache; float strengthRatio; @@ -54,7 +54,7 @@ public: const battle::Unit * activeStack, PlayerColor playerID, BattleID battleID, - int side, + BattleSide side, float strengthRatio) :scoreEvaluator(cb->getBattle(battleID), env, strengthRatio), cachedAttack(), playerID(playerID), side(side), env(env), cb(cb), strengthRatio(strengthRatio), battleID(battleID) { @@ -73,7 +73,7 @@ public: const battle::Unit * activeStack, PlayerColor playerID, BattleID battleID, - int side, + BattleSide side, float strengthRatio) :scoreEvaluator(cb->getBattle(battleID), env, strengthRatio), cachedAttack(), playerID(playerID), side(side), env(env), cb(cb), hb(hb), damageCache(damageCache), strengthRatio(strengthRatio), battleID(battleID) { diff --git a/AI/BattleAI/BattleExchangeVariant.cpp b/AI/BattleAI/BattleExchangeVariant.cpp index 0200915c9..7755dec9c 100644 --- a/AI/BattleAI/BattleExchangeVariant.cpp +++ b/AI/BattleAI/BattleExchangeVariant.cpp @@ -500,7 +500,7 @@ BattleScore BattleExchangeEvaluator::calculateExchange( logAi->trace("Battle exchange at %d", ap.attack.shooting ? ap.dest.hex : ap.from.hex); #endif - if(cb->battleGetMySide() == BattlePerspective::LEFT_SIDE + if(cb->battleGetMySide() == BattleSide::LEFT_SIDE && cb->battleGetGateState() == EGateState::BLOCKED && ap.attack.defender->coversPos(BattleHex::GATE_BRIDGE)) { diff --git a/AI/BattleAI/StackWithBonuses.cpp b/AI/BattleAI/StackWithBonuses.cpp index 1f6711612..c6dc197da 100644 --- a/AI/BattleAI/StackWithBonuses.cpp +++ b/AI/BattleAI/StackWithBonuses.cpp @@ -116,7 +116,7 @@ uint32_t StackWithBonuses::unitId() const return id; } -ui8 StackWithBonuses::unitSide() const +BattleSide StackWithBonuses::unitSide() const { return side; } @@ -467,7 +467,7 @@ int64_t HypotheticBattle::getActualDamage(const DamageRange & damage, int32_t at return (damage.min + damage.max) / 2; } -std::vector HypotheticBattle::getUsedSpells(ui8 side) const +std::vector HypotheticBattle::getUsedSpells(BattleSide side) const { // TODO return {}; diff --git a/AI/BattleAI/StackWithBonuses.h b/AI/BattleAI/StackWithBonuses.h index 13bf74a54..118dde639 100644 --- a/AI/BattleAI/StackWithBonuses.h +++ b/AI/BattleAI/StackWithBonuses.h @@ -85,7 +85,7 @@ public: int32_t unitBaseAmount() const override; uint32_t unitId() const override; - ui8 unitSide() const override; + BattleSide unitSide() const override; PlayerColor unitOwner() const override; SlotID unitSlot() const override; @@ -111,7 +111,7 @@ private: const CCreature * type; ui32 baseAmount; uint32_t id; - ui8 side; + BattleSide side; PlayerColor player; SlotID slot; }; @@ -158,7 +158,7 @@ public: uint32_t nextUnitId() const override; int64_t getActualDamage(const DamageRange & damage, int32_t attackerCount, vstd::RNG & rng) const override; - std::vector getUsedSpells(ui8 side) const override; + std::vector getUsedSpells(BattleSide side) const override; int3 getLocation() const override; bool isCreatureBank() const override; diff --git a/AI/Nullkiller/AIGateway.cpp b/AI/Nullkiller/AIGateway.cpp index bee760d7d..1a105d5f8 100644 --- a/AI/Nullkiller/AIGateway.cpp +++ b/AI/Nullkiller/AIGateway.cpp @@ -1148,7 +1148,7 @@ void AIGateway::recruitCreatures(const CGDwelling * d, const CArmedInstance * re } } -void AIGateway::battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) +void AIGateway::battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, BattleSide side, bool replayAllowed) { NET_EVENT_HANDLER; assert(!playerID.isValidPlayer() || status.getBattle() == UPCOMING_BATTLE); diff --git a/AI/Nullkiller/AIGateway.h b/AI/Nullkiller/AIGateway.h index fde31a730..a4a8a845a 100644 --- a/AI/Nullkiller/AIGateway.h +++ b/AI/Nullkiller/AIGateway.h @@ -156,7 +156,7 @@ public: void showWorldViewEx(const std::vector & objectPositions, bool showTerrain) override; std::optional makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) override; - void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) override; + void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, BattleSide side, bool replayAllowed) override; void battleEnd(const BattleID & battleID, const BattleResult * br, QueryID queryID) override; void makeTurn(); diff --git a/AI/StupidAI/StupidAI.cpp b/AI/StupidAI/StupidAI.cpp index 3c152de13..c0ccdf967 100644 --- a/AI/StupidAI/StupidAI.cpp +++ b/AI/StupidAI/StupidAI.cpp @@ -18,7 +18,7 @@ #include "../../lib/CRandomGenerator.h" CStupidAI::CStupidAI() - : side(-1) + : side(BattleSide::NONE) , wasWaitingForRealize(false) , wasUnlockingGs(false) { @@ -262,7 +262,7 @@ void CStupidAI::battleStacksEffectsSet(const BattleID & battleID, const SetStack print("battleStacksEffectsSet called"); } -void CStupidAI::battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side, bool replayAllowed) +void CStupidAI::battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, BattleSide Side, bool replayAllowed) { print("battleStart called"); side = Side; diff --git a/AI/StupidAI/StupidAI.h b/AI/StupidAI/StupidAI.h index 7c81a864c..302bd5590 100644 --- a/AI/StupidAI/StupidAI.h +++ b/AI/StupidAI/StupidAI.h @@ -17,7 +17,7 @@ class EnemyInfo; class CStupidAI : public CBattleGameInterface { - int side; + BattleSide side; std::shared_ptr cb; std::shared_ptr env; @@ -47,7 +47,7 @@ public: void battleSpellCast(const BattleID & battleID, const BattleSpellCast *sc) override; void battleStacksEffectsSet(const BattleID & battleID, const SetStackEffect & sse) override;//called when a specific effect is set to stacks //void battleTriggerEffect(const BattleTriggerEffect & bte) override; - void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) override; //called by engine when battle starts; side=0 - left, side=1 - right + void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, BattleSide side, bool replayAllowed) override; //called by engine when battle starts; side=0 - left, side=1 - right void battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca) override; //called when catapult makes an attack private: diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index ef33d96c3..e00a119c9 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -1566,7 +1566,7 @@ void VCAI::completeGoal(Goals::TSubgoal goal) } -void VCAI::battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) +void VCAI::battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, BattleSide side, bool replayAllowed) { NET_EVENT_HANDLER; assert(!playerID.isValidPlayer() || status.getBattle() == UPCOMING_BATTLE); diff --git a/AI/VCAI/VCAI.h b/AI/VCAI/VCAI.h index 8537e8f01..57f68de19 100644 --- a/AI/VCAI/VCAI.h +++ b/AI/VCAI/VCAI.h @@ -187,7 +187,7 @@ public: void showMarketWindow(const IMarket * market, const CGHeroInstance * visitor, QueryID queryID) override; void showWorldViewEx(const std::vector & objectPositions, bool showTerrain) override; - void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) override; + void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, BattleSide side, bool replayAllowed) override; void battleEnd(const BattleID & battleID, const BattleResult * br, QueryID queryID) override; std::optional makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) override; diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index d3dc88c9f..b55c5bdd6 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -624,7 +624,7 @@ void CPlayerInterface::battleStartBefore(const BattleID & battleID, const CCreat waitForAllDialogs(); } -void CPlayerInterface::battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) +void CPlayerInterface::battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, BattleSide side, bool replayAllowed) { EVENT_HANDLER_CALLED_BY_CLIENT; diff --git a/client/CPlayerInterface.h b/client/CPlayerInterface.h index c5d682621..0ae02576c 100644 --- a/client/CPlayerInterface.h +++ b/client/CPlayerInterface.h @@ -160,7 +160,7 @@ protected: // Call-ins from server, should not be called directly, but only via void battleTriggerEffect(const BattleID & battleID, const BattleTriggerEffect & bte) override; //various one-shot effect void battleStacksAttacked(const BattleID & battleID, const std::vector & bsa, bool ranged) override; void battleStartBefore(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2) override; //called by engine just before battle starts; side=0 - left, side=1 - right - void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) override; //called by engine when battle starts; side=0 - left, side=1 - right + void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, BattleSide side, bool replayAllowed) override; //called by engine when battle starts; side=0 - left, side=1 - right void battleUnitsChanged(const BattleID & battleID, const std::vector & units) override; void battleObstaclesChanged(const BattleID & battleID, const std::vector & obstacles) override; void battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca) override; //called when catapult makes an attack diff --git a/client/Client.cpp b/client/Client.cpp index 174acdb39..8de7c4157 100644 --- a/client/Client.cpp +++ b/client/Client.cpp @@ -443,8 +443,8 @@ void CClient::battleStarted(const BattleInfo * info) { std::shared_ptr att; std::shared_ptr def; - auto & leftSide = info->sides[0]; - auto & rightSide = info->sides[1]; + const auto & leftSide = info->getSide(BattleSide::LEFT_SIDE); + const auto & rightSide = info->getSide(BattleSide::RIGHT_SIDE); for(auto & battleCb : battleCallbacks) { @@ -453,17 +453,17 @@ void CClient::battleStarted(const BattleInfo * info) } //If quick combat is not, do not prepare interfaces for battleint - auto callBattleStart = [&](PlayerColor color, ui8 side) + auto callBattleStart = [&](PlayerColor color, BattleSide side) { if(vstd::contains(battleints, color)) battleints[color]->battleStart(info->battleID, leftSide.armyObject, rightSide.armyObject, info->tile, leftSide.hero, rightSide.hero, side, info->replayAllowed); }; - callBattleStart(leftSide.color, 0); - callBattleStart(rightSide.color, 1); - callBattleStart(PlayerColor::UNFLAGGABLE, 1); + callBattleStart(leftSide.color, BattleSide::LEFT_SIDE); + callBattleStart(rightSide.color, BattleSide::RIGHT_SIDE); + callBattleStart(PlayerColor::UNFLAGGABLE, BattleSide::RIGHT_SIDE); if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-skip-battle"].Bool()) - callBattleStart(PlayerColor::SPECTATOR, 1); + callBattleStart(PlayerColor::SPECTATOR, BattleSide::RIGHT_SIDE); if(vstd::contains(playerint, leftSide.color) && playerint[leftSide.color]->human) att = std::dynamic_pointer_cast(playerint[leftSide.color]); @@ -480,9 +480,9 @@ void CClient::battleStarted(const BattleInfo * info) { auto side = interface->cb->getBattle(info->battleID)->playerToSide(interface->playerID); - if(interface->playerID == info->sides[info->tacticsSide].color) + if(interface->playerID == info->getSide(info->tacticsSide).color) { - auto action = BattleAction::makeEndOFTacticPhase(*side); + auto action = BattleAction::makeEndOFTacticPhase(side); interface->cb->battleMakeTacticAction(info->battleID, action); } } @@ -514,7 +514,7 @@ void CClient::battleStarted(const BattleInfo * info) if(info->tacticDistance) { - auto tacticianColor = info->sides[info->tacticsSide].color; + auto tacticianColor = info->getSide(info->tacticsSide).color; if (vstd::contains(battleints, tacticianColor)) battleints[tacticianColor]->yourTacticPhase(info->battleID, info->tacticDistance); @@ -523,9 +523,11 @@ void CClient::battleStarted(const BattleInfo * info) void CClient::battleFinished(const BattleID & battleID) { - for(auto & side : gs->getBattle(battleID)->sides) - if(battleCallbacks.count(side.color)) - battleCallbacks[side.color]->onBattleEnded(battleID); + for(auto side : { BattleSide::ATTACKER, BattleSide::DEFENDER }) + { + if(battleCallbacks.count(gs->getBattle(battleID)->getSide(side).color)) + battleCallbacks[gs->getBattle(battleID)->getSide(side).color]->onBattleEnded(battleID); + } if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-skip-battle"].Bool()) battleCallbacks[PlayerColor::SPECTATOR]->onBattleEnded(battleID); diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index 6d16608a0..c4379e3d7 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -108,8 +108,8 @@ void callBattleInterfaceIfPresentForBothSides(CClient & cl, const BattleID & bat return; } - callOnlyThatBattleInterface(cl, cl.gameState()->getBattle(battleID)->sides[0].color, ptr, std::forward(args)...); - callOnlyThatBattleInterface(cl, cl.gameState()->getBattle(battleID)->sides[1].color, ptr, std::forward(args)...); + callOnlyThatBattleInterface(cl, cl.gameState()->getBattle(battleID)->getSide(BattleSide::ATTACKER).color, ptr, std::forward(args)...); + callOnlyThatBattleInterface(cl, cl.gameState()->getBattle(battleID)->getSide(BattleSide::DEFENDER).color, ptr, std::forward(args)...); if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-skip-battle"].Bool() && LOCPLINT->battleInt) { callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, ptr, std::forward(args)...); @@ -769,12 +769,12 @@ void ApplyClientNetPackVisitor::visitMapObjectSelectDialog(MapObjectSelectDialog void ApplyFirstClientNetPackVisitor::visitBattleStart(BattleStart & pack) { // Cannot use the usual code because curB is not set yet - callOnlyThatBattleInterface(cl, pack.info->sides[0].color, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->sides[0].armyObject, pack.info->sides[1].armyObject, - pack.info->tile, pack.info->sides[0].hero, pack.info->sides[1].hero); - callOnlyThatBattleInterface(cl, pack.info->sides[1].color, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->sides[0].armyObject, pack.info->sides[1].armyObject, - pack.info->tile, pack.info->sides[0].hero, pack.info->sides[1].hero); - callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->sides[0].armyObject, pack.info->sides[1].armyObject, - pack.info->tile, pack.info->sides[0].hero, pack.info->sides[1].hero); + callOnlyThatBattleInterface(cl, pack.info->getSide(BattleSide::ATTACKER).color, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->getSide(BattleSide::ATTACKER).armyObject, pack.info->getSide(BattleSide::DEFENDER).armyObject, + pack.info->tile, pack.info->getSide(BattleSide::ATTACKER).hero, pack.info->getSide(BattleSide::DEFENDER).hero); + callOnlyThatBattleInterface(cl, pack.info->getSide(BattleSide::DEFENDER).color, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->getSide(BattleSide::ATTACKER).armyObject, pack.info->getSide(BattleSide::DEFENDER).armyObject, + pack.info->tile, pack.info->getSide(BattleSide::ATTACKER).hero, pack.info->getSide(BattleSide::DEFENDER).hero); + callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->getSide(BattleSide::ATTACKER).armyObject, pack.info->getSide(BattleSide::DEFENDER).armyObject, + pack.info->tile, pack.info->getSide(BattleSide::ATTACKER).hero, pack.info->getSide(BattleSide::DEFENDER).hero); } void ApplyClientNetPackVisitor::visitBattleStart(BattleStart & pack) @@ -801,9 +801,9 @@ void ApplyClientNetPackVisitor::visitBattleSetActiveStack(BattleSetActiveStack & PlayerColor playerToCall; //pack.player that will move activated stack if (activated->hasBonusOfType(BonusType::HYPNOTIZED)) { - playerToCall = (gs.getBattle(pack.battleID)->sides[0].color == activated->unitOwner() - ? gs.getBattle(pack.battleID)->sides[1].color - : gs.getBattle(pack.battleID)->sides[0].color); + playerToCall = gs.getBattle(pack.battleID)->getSide(BattleSide::ATTACKER).color == activated->unitOwner() + ? gs.getBattle(pack.battleID)->getSide(BattleSide::DEFENDER).color + : gs.getBattle(pack.battleID)->getSide(BattleSide::ATTACKER).color; } else { diff --git a/client/battle/BattleActionsController.cpp b/client/battle/BattleActionsController.cpp index b182cb400..8635f24d1 100644 --- a/client/battle/BattleActionsController.cpp +++ b/client/battle/BattleActionsController.cpp @@ -312,8 +312,8 @@ void BattleActionsController::castThisSpell(SpellID spellID) heroSpellToCast = std::make_shared(); heroSpellToCast->actionType = EActionType::HERO_SPELL; heroSpellToCast->spell = spellID; - heroSpellToCast->stackNumber = (owner.attackingHeroInstance->tempOwner == owner.curInt->playerID) ? -1 : -2; - heroSpellToCast->side = owner.defendingHeroInstance ? (owner.curInt->playerID == owner.defendingHeroInstance->tempOwner) : false; + heroSpellToCast->stackNumber = -1; + heroSpellToCast->side = owner.curInt->cb->getBattle(owner.getBattleID())->battleGetMySide(); //choosing possible targets const CGHeroInstance *castingHero = (owner.attackingHeroInstance->tempOwner == owner.curInt->playerID) ? owner.attackingHeroInstance : owner.defendingHeroInstance; diff --git a/client/battle/BattleInterface.cpp b/client/battle/BattleInterface.cpp index 15f14baf8..826c401a1 100644 --- a/client/battle/BattleInterface.cpp +++ b/client/battle/BattleInterface.cpp @@ -229,19 +229,19 @@ void BattleInterface::stacksAreAttacked(std::vector attackedI { stacksController->stacksAreAttacked(attackedInfos); - std::array killedBySide = {0, 0}; + BattleSideArray killedBySide; for(const StackAttackedInfo & attackedInfo : attackedInfos) { - ui8 side = attackedInfo.defender->unitSide(); + BattleSide side = attackedInfo.defender->unitSide(); killedBySide.at(side) += attackedInfo.amountKilled; } - for(ui8 side = 0; side < 2; side++) + for(BattleSide side : { BattleSide::ATTACKER, BattleSide::DEFENDER }) { - if(killedBySide.at(side) > killedBySide.at(1-side)) + if(killedBySide.at(side) > killedBySide.at(getBattle()->otherSide(side))) setHeroAnimation(side, EHeroAnimType::DEFEAT); - else if(killedBySide.at(side) < killedBySide.at(1-side)) + else if(killedBySide.at(side) < killedBySide.at(getBattle()->otherSide(side))) setHeroAnimation(side, EHeroAnimType::VICTORY); } } @@ -271,14 +271,14 @@ void BattleInterface::giveCommand(EActionType action, BattleHex tile, SpellID sp } auto side = getBattle()->playerToSide(curInt->playerID); - if(!side) + if(side == BattleSide::NONE) { logGlobal->error("Player %s is not in battle", curInt->playerID.toString()); return; } BattleAction ba; - ba.side = side.value(); + ba.side = side; ba.actionType = action; ba.aimToHex(tile); ba.spell = spell; @@ -409,7 +409,7 @@ void BattleInterface::spellCast(const BattleSpellCast * sc) } else { - auto hero = sc->side ? defendingHero : attackingHero; + auto hero = sc->side == BattleSide::DEFENDER ? defendingHero : attackingHero; assert(hero); addToAnimationStage(EAnimationEvents::BEFORE_HIT, [=]() @@ -466,11 +466,11 @@ void BattleInterface::spellCast(const BattleSpellCast * sc) { Point leftHero = Point(15, 30); Point rightHero = Point(755, 30); - bool side = sc->side; + BattleSide side = sc->side; addToAnimationStage(EAnimationEvents::AFTER_HIT, [=](){ - stacksController->addNewAnim(new EffectAnimation(*this, AnimationPath::builtin(side ? "SP07_A.DEF" : "SP07_B.DEF"), leftHero)); - stacksController->addNewAnim(new EffectAnimation(*this, AnimationPath::builtin(side ? "SP07_B.DEF" : "SP07_A.DEF"), rightHero)); + stacksController->addNewAnim(new EffectAnimation(*this, AnimationPath::builtin(side == BattleSide::DEFENDER ? "SP07_A.DEF" : "SP07_B.DEF"), leftHero)); + stacksController->addNewAnim(new EffectAnimation(*this, AnimationPath::builtin(side == BattleSide::DEFENDER ? "SP07_B.DEF" : "SP07_A.DEF"), rightHero)); }); } @@ -483,7 +483,7 @@ void BattleInterface::battleStacksEffectsSet(const SetStackEffect & sse) fieldController->redrawBackgroundWithHexes(); } -void BattleInterface::setHeroAnimation(ui8 side, EHeroAnimType phase) +void BattleInterface::setHeroAnimation(BattleSide side, EHeroAnimType phase) { if(side == BattleSide::ATTACKER) { @@ -656,7 +656,7 @@ void BattleInterface::tacticPhaseEnd() tacticsMode = false; auto side = tacticianInterface->cb->getBattle(battleID)->playerToSide(tacticianInterface->playerID); - auto action = BattleAction::makeEndOFTacticPhase(*side); + auto action = BattleAction::makeEndOFTacticPhase(side); tacticianInterface->cb->battleMakeTacticAction(battleID, action); } diff --git a/client/battle/BattleInterface.h b/client/battle/BattleInterface.h index 1281d5ca4..a7c578ecf 100644 --- a/client/battle/BattleInterface.h +++ b/client/battle/BattleInterface.h @@ -170,7 +170,7 @@ public: void showInterface(Canvas & to); - void setHeroAnimation(ui8 side, EHeroAnimType phase); + void setHeroAnimation(BattleSide side, EHeroAnimType phase); void executeSpellCast(); //called when a hero casts a spell diff --git a/client/battle/BattleInterfaceClasses.cpp b/client/battle/BattleInterfaceClasses.cpp index c8509b941..1f9413f49 100644 --- a/client/battle/BattleInterfaceClasses.cpp +++ b/client/battle/BattleInterfaceClasses.cpp @@ -746,7 +746,7 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface labels.push_back(std::make_shared(232, 520, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->translate("vcmi.battleResultsWindow.applyResultsLabel"))); } - if(br.winner == 0) //attacker won + if(br.winner == BattleSide::ATTACKER) { labels.push_back(std::make_shared(59, 124, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[410])); } @@ -754,8 +754,8 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface { labels.push_back(std::make_shared(59, 124, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[411])); } - - if(br.winner == 1) + + if(br.winner == BattleSide::DEFENDER) { labels.push_back(std::make_shared(412, 124, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[410])); } @@ -770,15 +770,15 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface std::string sideNames[2] = {"N/A", "N/A"}; - for(int i = 0; i < 2; i++) + for(auto i : {BattleSide::ATTACKER, BattleSide::DEFENDER}) { auto heroInfo = owner.cb->getBattle(br.battleID)->battleGetHeroInfo(i); const int xs[] = {21, 392}; if(heroInfo.portraitSource.isValid()) //attacking hero { - icons.push_back(std::make_shared(AnimationPath::builtin("PortraitsLarge"), heroInfo.getIconIndex(), 0, xs[i], 38)); - sideNames[i] = heroInfo.name; + icons.push_back(std::make_shared(AnimationPath::builtin("PortraitsLarge"), heroInfo.getIconIndex(), 0, xs[static_cast(i)], 38)); + sideNames[static_cast(i)] = heroInfo.name; } else { @@ -795,8 +795,8 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface if(best != stacks.end()) //should be always but to be safe... { - icons.push_back(std::make_shared(AnimationPath::builtin("TWCRPORT"), (*best)->unitType()->getIconIndex(), 0, xs[i], 38)); - sideNames[i] = (*best)->unitType()->getNamePluralTranslated(); + icons.push_back(std::make_shared(AnimationPath::builtin("TWCRPORT"), (*best)->unitType()->getIconIndex(), 0, xs[static_cast(i)], 38)); + sideNames[static_cast(i)] = (*best)->unitType()->getNamePluralTranslated(); } } } @@ -806,16 +806,16 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface labels.push_back(std::make_shared(381, 53, FONT_SMALL, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, sideNames[1])); //printing casualties - for(int step = 0; step < 2; ++step) + for(auto step : {BattleSide::ATTACKER, BattleSide::DEFENDER}) { if(br.casualties[step].size()==0) { - labels.push_back(std::make_shared(235, 360 + 97 * step, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[523])); + labels.push_back(std::make_shared(235, 360 + 97 * static_cast(step), FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[523])); } else { int xPos = 235 - ((int)br.casualties[step].size()*32 + ((int)br.casualties[step].size() - 1)*10)/2; //increment by 42 with each picture - int yPos = 344 + step * 97; + int yPos = 344 + static_cast(step) * 97; for(auto & elem : br.casualties[step]) { auto creature = CGI->creatures()->getByIndex(elem.first); @@ -842,9 +842,9 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface BattleResultResources BattleResultWindow::getResources(const BattleResult & br) { //printing result description - bool weAreAttacker = !(owner.cb->getBattle(br.battleID)->battleGetMySide()); + bool weAreAttacker = owner.cb->getBattle(br.battleID)->battleGetMySide() == BattleSide::ATTACKER; bool weAreDefender = !weAreAttacker; - bool weWon = (br.winner == 0 && weAreAttacker) || (br.winner == 1 && !weAreAttacker); + bool weWon = (br.winner == BattleSide::ATTACKER && weAreAttacker) || (br.winner == BattleSide::DEFENDER && !weAreAttacker); bool isSiege = owner.cb->getBattle(br.battleID)->battleGetDefendedTown() != nullptr; BattleResultResources resources; @@ -884,7 +884,7 @@ BattleResultResources BattleResultWindow::getResources(const BattleResult & br) { resources.resultText.appendTextID("core.genrltxt.305"); resources.resultText.replaceTextID(ourHero->getNameTranslated()); - resources.resultText.replaceNumber(br.exp[weAreAttacker ? 0 : 1]); + resources.resultText.replaceNumber(br.exp[weAreAttacker ? BattleSide::ATTACKER : BattleSide::DEFENDER]); } } else // we lose diff --git a/client/battle/BattleObstacleController.cpp b/client/battle/BattleObstacleController.cpp index 031d40ee9..e291ee62b 100644 --- a/client/battle/BattleObstacleController.cpp +++ b/client/battle/BattleObstacleController.cpp @@ -102,7 +102,7 @@ void BattleObstacleController::obstaclePlaced(const std::vectorplayerToSide(owner.curInt->playerID); - if(!oi->visibleForSide(side.value(), owner.getBattle()->battleHasNativeStack(side.value()))) + if(!oi->visibleForSide(side, owner.getBattle()->battleHasNativeStack(side))) continue; auto animation = GH.renderHandler().loadAnimation(oi->getAppearAnimation(), EImageBlitMode::ALPHA); diff --git a/lib/CGameInterface.cpp b/lib/CGameInterface.cpp index a705ea415..a62f1c83d 100644 --- a/lib/CGameInterface.cpp +++ b/lib/CGameInterface.cpp @@ -168,7 +168,7 @@ void CAdventureAI::battleCatapultAttacked(const BattleID & battleID, const Catap } void CAdventureAI::battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, - const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) + const CGHeroInstance * hero1, const CGHeroInstance * hero2, BattleSide side, bool replayAllowed) { assert(!battleAI); assert(cbc); diff --git a/lib/CGameInterface.h b/lib/CGameInterface.h index b0af48a49..3e65b79af 100644 --- a/lib/CGameInterface.h +++ b/lib/CGameInterface.h @@ -146,7 +146,7 @@ public: void battleNewRound(const BattleID & battleID) override; void battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca) override; - void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) override; + void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, BattleSide side, bool replayAllowed) override; void battleStacksAttacked(const BattleID & battleID, const std::vector & bsa, bool ranged) override; void actionStarted(const BattleID & battleID, const BattleAction &action) override; void battleNewRoundFirst(const BattleID & battleID) override; diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index e598a4389..1eaab7cd4 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -403,6 +403,7 @@ set(lib_MAIN_HEADERS battle/BattleAttackInfo.h battle/BattleHex.h battle/BattleInfo.h + battle/BattleSide.h battle/BattleStateInfoForRetreat.h battle/BattleProxy.h battle/CBattleInfoCallback.h diff --git a/lib/CStack.cpp b/lib/CStack.cpp index fde17490c..0c3c6646a 100644 --- a/lib/CStack.cpp +++ b/lib/CStack.cpp @@ -24,7 +24,7 @@ VCMI_LIB_NAMESPACE_BEGIN ///CStack -CStack::CStack(const CStackInstance * Base, const PlayerColor & O, int I, ui8 Side, const SlotID & S): +CStack::CStack(const CStackInstance * Base, const PlayerColor & O, int I, BattleSide Side, const SlotID & S): CBonusSystemNode(STACK_BATTLE), base(Base), ID(I), @@ -45,7 +45,7 @@ CStack::CStack(): { } -CStack::CStack(const CStackBasicDescriptor * stack, const PlayerColor & O, int I, ui8 Side, const SlotID & S): +CStack::CStack(const CStackBasicDescriptor * stack, const PlayerColor & O, int I, BattleSide Side, const SlotID & S): CBonusSystemNode(STACK_BATTLE), ID(I), type(stack->type), @@ -367,7 +367,7 @@ uint32_t CStack::unitId() const return ID; } -ui8 CStack::unitSide() const +BattleSide CStack::unitSide() const { return side; } diff --git a/lib/CStack.h b/lib/CStack.h index 789c58969..456b44bc2 100644 --- a/lib/CStack.h +++ b/lib/CStack.h @@ -32,7 +32,7 @@ private: ui32 baseAmount = -1; PlayerColor owner; //owner - player color (255 for neutrals) - ui8 side = 1; + BattleSide side = BattleSide::NONE; SlotID slot; //slot - position in garrison (may be 255 for neutrals/called creatures) @@ -41,8 +41,8 @@ public: BattleHex initialPosition; //position on battlefield; -2 - keep, -3 - lower tower, -4 - upper tower - CStack(const CStackInstance * base, const PlayerColor & O, int I, ui8 Side, const SlotID & S); - CStack(const CStackBasicDescriptor * stack, const PlayerColor & O, int I, ui8 Side, const SlotID & S = SlotID(255)); + CStack(const CStackInstance * base, const PlayerColor & O, int I, BattleSide Side, const SlotID & S); + CStack(const CStackBasicDescriptor * stack, const PlayerColor & O, int I, BattleSide Side, const SlotID & S = SlotID(255)); CStack(); ~CStack(); @@ -74,7 +74,7 @@ public: int32_t unitBaseAmount() const override; uint32_t unitId() const override; - ui8 unitSide() const override; + BattleSide unitSide() const override; PlayerColor unitOwner() const override; SlotID unitSlot() const override; diff --git a/lib/IGameEventsReceiver.h b/lib/IGameEventsReceiver.h index 0e1c932f9..5f6c5540a 100644 --- a/lib/IGameEventsReceiver.h +++ b/lib/IGameEventsReceiver.h @@ -68,7 +68,7 @@ public: virtual void battleStacksEffectsSet(const BattleID & battleID, const SetStackEffect & sse){};//called when a specific effect is set to stacks virtual void battleTriggerEffect(const BattleID & battleID, const BattleTriggerEffect & bte){}; //called for various one-shot effects virtual void battleStartBefore(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2) {}; //called just before battle start - virtual void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed){}; //called by engine when battle starts; side=0 - left, side=1 - right + virtual void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, BattleSide side, bool replayAllowed){}; //called by engine when battle starts; side=0 - left, side=1 - right virtual void battleUnitsChanged(const BattleID & battleID, const std::vector & units){}; virtual void battleObstaclesChanged(const BattleID & battleID, const std::vector & obstacles){}; virtual void battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca){}; //called when catapult makes an attack diff --git a/lib/battle/AccessibilityInfo.cpp b/lib/battle/AccessibilityInfo.cpp index a7a29dae5..44e093f99 100644 --- a/lib/battle/AccessibilityInfo.cpp +++ b/lib/battle/AccessibilityInfo.cpp @@ -15,7 +15,7 @@ VCMI_LIB_NAMESPACE_BEGIN -bool AccessibilityInfo::tileAccessibleWithGate(BattleHex tile, ui8 side) const +bool AccessibilityInfo::tileAccessibleWithGate(BattleHex tile, BattleSide side) const { //at(otherHex) != EAccessibility::ACCESSIBLE && (at(otherHex) != EAccessibility::GATE || side != BattleSide::DEFENDER) if(at(tile) != EAccessibility::ACCESSIBLE) @@ -29,7 +29,7 @@ bool AccessibilityInfo::accessible(BattleHex tile, const battle::Unit * stack) c return accessible(tile, stack->doubleWide(), stack->unitSide()); } -bool AccessibilityInfo::accessible(BattleHex tile, bool doubleWide, ui8 side) const +bool AccessibilityInfo::accessible(BattleHex tile, bool doubleWide, BattleSide side) const { // All hexes that stack would cover if standing on tile have to be accessible. //do not use getHexes for speed reasons diff --git a/lib/battle/AccessibilityInfo.h b/lib/battle/AccessibilityInfo.h index dc3648412..f9604a490 100644 --- a/lib/battle/AccessibilityInfo.h +++ b/lib/battle/AccessibilityInfo.h @@ -37,9 +37,9 @@ struct DLL_LINKAGE AccessibilityInfo : TAccessibilityArray { public: bool accessible(BattleHex tile, const battle::Unit * stack) const; //checks for both tiles if stack is double wide - bool accessible(BattleHex tile, bool doubleWide, ui8 side) const; //checks for both tiles if stack is double wide + bool accessible(BattleHex tile, bool doubleWide, BattleSide side) const; //checks for both tiles if stack is double wide private: - bool tileAccessibleWithGate(BattleHex tile, ui8 side) const; + bool tileAccessibleWithGate(BattleHex tile, BattleSide side) const; }; VCMI_LIB_NAMESPACE_END diff --git a/lib/battle/BattleAction.cpp b/lib/battle/BattleAction.cpp index e021cc1ba..8fe94b520 100644 --- a/lib/battle/BattleAction.cpp +++ b/lib/battle/BattleAction.cpp @@ -18,7 +18,7 @@ VCMI_LIB_NAMESPACE_BEGIN static const int32_t INVALID_UNIT_ID = -1000; BattleAction::BattleAction(): - side(-1), + side(BattleSide::NONE), stackNumber(-1), actionType(EActionType::NO_ACTION) { @@ -96,7 +96,7 @@ BattleAction BattleAction::makeMove(const battle::Unit * stack, BattleHex dest) return ba; } -BattleAction BattleAction::makeEndOFTacticPhase(ui8 side) +BattleAction BattleAction::makeEndOFTacticPhase(BattleSide side) { BattleAction ba; ba.side = side; @@ -104,7 +104,7 @@ BattleAction BattleAction::makeEndOFTacticPhase(ui8 side) return ba; } -BattleAction BattleAction::makeSurrender(ui8 side) +BattleAction BattleAction::makeSurrender(BattleSide side) { BattleAction ba; ba.side = side; @@ -112,7 +112,7 @@ BattleAction BattleAction::makeSurrender(ui8 side) return ba; } -BattleAction BattleAction::makeRetreat(ui8 side) +BattleAction BattleAction::makeRetreat(BattleSide side) { BattleAction ba; ba.side = side; diff --git a/lib/battle/BattleAction.h b/lib/battle/BattleAction.h index 40253b2a5..0c5aa533d 100644 --- a/lib/battle/BattleAction.h +++ b/lib/battle/BattleAction.h @@ -24,7 +24,7 @@ namespace battle class DLL_LINKAGE BattleAction { public: - ui8 side; //who made this action + BattleSide side; //who made this action ui32 stackNumber; //stack ID, -1 left hero, -2 right hero, EActionType actionType; //use ActionType enum for values @@ -39,9 +39,9 @@ public: static BattleAction makeShotAttack(const battle::Unit * shooter, const battle::Unit * target); static BattleAction makeCreatureSpellcast(const battle::Unit * stack, const battle::Target & target, const SpellID & spellID); static BattleAction makeMove(const battle::Unit * stack, BattleHex dest); - static BattleAction makeEndOFTacticPhase(ui8 side); - static BattleAction makeRetreat(ui8 side); - static BattleAction makeSurrender(ui8 side); + static BattleAction makeEndOFTacticPhase(BattleSide side); + static BattleAction makeRetreat(BattleSide side); + static BattleAction makeSurrender(BattleSide side); bool isTacticsAction() const; bool isUnitAction() const; diff --git a/lib/battle/BattleHex.cpp b/lib/battle/BattleHex.cpp index f6eaf319f..581cf538f 100644 --- a/lib/battle/BattleHex.cpp +++ b/lib/battle/BattleHex.cpp @@ -184,7 +184,7 @@ void BattleHex::checkAndPush(BattleHex tile, std::vector & ret) ret.push_back(tile); } -BattleHex BattleHex::getClosestTile(ui8 side, BattleHex initialPos, std::set & possibilities) +BattleHex BattleHex::getClosestTile(BattleSide side, BattleHex initialPos, std::set & possibilities) { std::vector sortedTiles (possibilities.begin(), possibilities.end()); //set can't be sorted properly :( BattleHex initialHex = BattleHex(initialPos); diff --git a/lib/battle/BattleHex.h b/lib/battle/BattleHex.h index 3b06b4828..0f1dc37e4 100644 --- a/lib/battle/BattleHex.h +++ b/lib/battle/BattleHex.h @@ -9,19 +9,12 @@ */ #pragma once +#include "BattleSide.h" + VCMI_LIB_NAMESPACE_BEGIN //TODO: change to enum class -namespace BattleSide -{ - enum Type - { - ATTACKER = 0, - DEFENDER = 1 - }; -} - namespace GameConstants { const int BFIELD_WIDTH = 17; @@ -29,8 +22,6 @@ namespace GameConstants const int BFIELD_SIZE = BFIELD_WIDTH * BFIELD_HEIGHT; } -using BattleSideOpt = std::optional; - // for battle stacks' positions struct DLL_LINKAGE BattleHex //TODO: decide if this should be changed to class for better code design { @@ -102,7 +93,7 @@ struct DLL_LINKAGE BattleHex //TODO: decide if this should be changed to class f static EDir mutualPosition(BattleHex hex1, BattleHex hex2); static uint8_t getDistance(BattleHex hex1, BattleHex hex2); static void checkAndPush(BattleHex tile, std::vector & ret); - static BattleHex getClosestTile(ui8 side, BattleHex initialPos, std::set & possibilities); //TODO: vector or set? copying one to another is bad + static BattleHex getClosestTile(BattleSide side, BattleHex initialPos, std::set & possibilities); //TODO: vector or set? copying one to another is bad template void serialize(Handler &h) diff --git a/lib/battle/BattleInfo.cpp b/lib/battle/BattleInfo.cpp index 4f4a1b3cf..4f7367b1b 100644 --- a/lib/battle/BattleInfo.cpp +++ b/lib/battle/BattleInfo.cpp @@ -27,10 +27,20 @@ VCMI_LIB_NAMESPACE_BEGIN -///BattleInfo -CStack * BattleInfo::generateNewStack(uint32_t id, const CStackInstance & base, ui8 side, const SlotID & slot, BattleHex position) +const SideInBattle & BattleInfo::getSide(BattleSide side) const { - PlayerColor owner = sides[side].color; + return sides.at(side); +} + +SideInBattle & BattleInfo::getSide(BattleSide side) +{ + return sides.at(side); +} + +///BattleInfo +CStack * BattleInfo::generateNewStack(uint32_t id, const CStackInstance & base, BattleSide side, const SlotID & slot, BattleHex position) +{ + PlayerColor owner = getSide(side).color; assert(!owner.isValidPlayer() || (base.armyObj && base.armyObj->tempOwner == owner)); auto * ret = new CStack(&base, owner, id, side, slot); @@ -39,9 +49,9 @@ CStack * BattleInfo::generateNewStack(uint32_t id, const CStackInstance & base, return ret; } -CStack * BattleInfo::generateNewStack(uint32_t id, const CStackBasicDescriptor & base, ui8 side, const SlotID & slot, BattleHex position) +CStack * BattleInfo::generateNewStack(uint32_t id, const CStackBasicDescriptor & base, BattleSide side, const SlotID & slot, BattleHex position) { - PlayerColor owner = sides[side].color; + PlayerColor owner = getSide(side).color; auto * ret = new CStack(&base, owner, id, side, slot); ret->initialPosition = position; stacks.push_back(ret); @@ -50,7 +60,7 @@ CStack * BattleInfo::generateNewStack(uint32_t id, const CStackBasicDescriptor & void BattleInfo::localInit() { - for(int i = 0; i < 2; i++) + for(BattleSide i : { BattleSide::ATTACKER, BattleSide::DEFENDER}) { auto * armyObj = battleGetArmyObject(i); armyObj->battle = this; @@ -162,12 +172,12 @@ struct RangeGenerator std::function myRand; }; -BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const BattleField & battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town) +BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const BattleField & battlefieldType, BattleSideArray armies, BattleSideArray heroes, bool creatureBank, const CGTownInstance * town) { CMP_stack cmpst; auto * curB = new BattleInfo(); - for(auto i = 0u; i < curB->sides.size(); i++) + for(auto i : { BattleSide::LEFT_SIDE, BattleSide::RIGHT_SIDE}) curB->sides[i].init(heroes[i], armies[i]); @@ -315,36 +325,32 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const //reading battleStartpos - add creatures AFTER random obstacles are generated //TODO: parse once to some structure - std::vector> looseFormations[2]; - std::vector> tightFormations[2]; - std::vector> creBankFormations[2]; - std::vector commanderField; - std::vector commanderBank; + BattleSideArray>> looseFormations; + BattleSideArray>> tightFormations; + BattleSideArray>> creBankFormations; + BattleSideArray commanderField; + BattleSideArray commanderBank; const JsonNode config(JsonPath::builtin("config/battleStartpos.json")); const JsonVector &positions = config["battle_positions"].Vector(); - CGH::readBattlePositions(positions[0]["levels"], looseFormations[0]); - CGH::readBattlePositions(positions[1]["levels"], looseFormations[1]); - CGH::readBattlePositions(positions[2]["levels"], tightFormations[0]); - CGH::readBattlePositions(positions[3]["levels"], tightFormations[1]); - CGH::readBattlePositions(positions[4]["levels"], creBankFormations[0]); - CGH::readBattlePositions(positions[5]["levels"], creBankFormations[1]); + CGH::readBattlePositions(positions[0]["levels"], looseFormations[BattleSide::ATTACKER]); + CGH::readBattlePositions(positions[1]["levels"], looseFormations[BattleSide::DEFENDER]); + CGH::readBattlePositions(positions[2]["levels"], tightFormations[BattleSide::ATTACKER]); + CGH::readBattlePositions(positions[3]["levels"], tightFormations[BattleSide::DEFENDER]); + CGH::readBattlePositions(positions[4]["levels"], creBankFormations[BattleSide::ATTACKER]); + CGH::readBattlePositions(positions[5]["levels"], creBankFormations[BattleSide::DEFENDER]); - for (auto position : config["commanderPositions"]["field"].Vector()) - { - commanderField.push_back(static_cast(position.Float())); - } - for (auto position : config["commanderPositions"]["creBank"].Vector()) - { - commanderBank.push_back(static_cast(position.Float())); - } + commanderField[BattleSide::ATTACKER] = config["commanderPositions"]["field"][0].Integer(); + commanderField[BattleSide::DEFENDER] = config["commanderPositions"]["field"][1].Integer(); + commanderBank[BattleSide::ATTACKER] = config["commanderPositions"]["creBank"][0].Integer(); + commanderBank[BattleSide::DEFENDER] = config["commanderPositions"]["creBank"][1].Integer(); //adding war machines if(!creatureBank) { //Checks if hero has artifact and create appropriate stack - auto handleWarMachine = [&](int side, const ArtifactPosition & artslot, BattleHex hex) + auto handleWarMachine = [&](BattleSide side, const ArtifactPosition & artslot, BattleHex hex) { const CArtifactInstance * warMachineArt = heroes[side]->getArt(artslot); @@ -357,28 +363,28 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const } }; - if(heroes[0]) + if(heroes[BattleSide::ATTACKER]) { - handleWarMachine(0, ArtifactPosition::MACH1, 52); - handleWarMachine(0, ArtifactPosition::MACH2, 18); - handleWarMachine(0, ArtifactPosition::MACH3, 154); + handleWarMachine(BattleSide::ATTACKER, ArtifactPosition::MACH1, 52); + handleWarMachine(BattleSide::ATTACKER, ArtifactPosition::MACH2, 18); + handleWarMachine(BattleSide::ATTACKER, ArtifactPosition::MACH3, 154); if(town && town->hasFort()) - handleWarMachine(0, ArtifactPosition::MACH4, 120); + handleWarMachine(BattleSide::ATTACKER, ArtifactPosition::MACH4, 120); } - if(heroes[1]) + if(heroes[BattleSide::DEFENDER]) { if(!town) //defending hero shouldn't receive ballista (bug #551) - handleWarMachine(1, ArtifactPosition::MACH1, 66); - handleWarMachine(1, ArtifactPosition::MACH2, 32); - handleWarMachine(1, ArtifactPosition::MACH3, 168); + handleWarMachine(BattleSide::DEFENDER, ArtifactPosition::MACH1, 66); + handleWarMachine(BattleSide::DEFENDER, ArtifactPosition::MACH2, 32); + handleWarMachine(BattleSide::DEFENDER, ArtifactPosition::MACH3, 168); } } //war machines added //battleStartpos read - for(int side = 0; side < 2; side++) + for(BattleSide side : {BattleSide::ATTACKER, BattleSide::DEFENDER}) { int formationNo = armies[side]->stacksCount() - 1; vstd::abetween(formationNo, 0, GameConstants::ARMY_SIZE - 1); @@ -397,14 +403,14 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const BattleHex pos = (k < formationVector->size() ? formationVector->at(k) : 0); if(creatureBank && i->second->type->isDoubleWide()) - pos += side ? BattleHex::LEFT : BattleHex::RIGHT; + pos += side == BattleSide::RIGHT_SIDE ? BattleHex::LEFT : BattleHex::RIGHT; curB->generateNewStack(curB->nextUnitId(), *i->second, side, i->first, pos); } } //adding commanders - for (int i = 0; i < 2; ++i) + for(BattleSide i : {BattleSide::ATTACKER, BattleSide::DEFENDER}) { if (heroes[i] && heroes[i]->commander && heroes[i]->commander->alive) { @@ -416,14 +422,14 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const if (curB->town && curB->town->fortLevel() >= CGTownInstance::CITADEL) { // keep tower - curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), 1, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_CENTRAL_TOWER); + curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_CENTRAL_TOWER); if (curB->town->fortLevel() >= CGTownInstance::CASTLE) { // lower tower + upper tower - curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), 1, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_UPPER_TOWER); + curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_UPPER_TOWER); - curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), 1, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_BOTTOM_TOWER); + curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_BOTTOM_TOWER); } //Moat generating is done on server @@ -453,11 +459,9 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const //tactics bool isTacticsAllowed = !creatureBank; //no tactics in creature banks - constexpr int sideSize = 2; - - std::array battleRepositionHex = {}; - std::array battleRepositionHexBlock = {}; - for(int i = 0; i < sideSize; i++) + BattleSideArray battleRepositionHex = {}; + BattleSideArray battleRepositionHexBlock = {}; + for(auto i : {BattleSide::ATTACKER, BattleSide::DEFENDER}) { if(heroes[i]) { @@ -508,14 +512,14 @@ const CGHeroInstance * BattleInfo::getHero(const PlayerColor & player) const return nullptr; } -ui8 BattleInfo::whatSide(const PlayerColor & player) const +BattleSide BattleInfo::whatSide(const PlayerColor & player) const { - for(int i = 0; i < sides.size(); i++) + for(auto i : {BattleSide::ATTACKER, BattleSide::DEFENDER}) if(sides[i].color == player) return i; logGlobal->warn("BattleInfo::whatSide: Player %s is not in battle!", player.toString()); - return -1; + return BattleSide::NONE; } CStack * BattleInfo::getStack(int stackID, bool onlyAlive) @@ -529,7 +533,7 @@ BattleInfo::BattleInfo(): town(nullptr), tile(-1,-1,-1), battlefieldType(BattleField::NONE), - tacticsSide(0), + tacticsSide(BattleSide::NONE), tacticDistance(0) { setNodeType(BATTLE); @@ -555,7 +559,7 @@ BattleInfo::~BattleInfo() for (auto & elem : stacks) delete elem; - for(int i = 0; i < 2; i++) + for(auto i : {BattleSide::ATTACKER, BattleSide::DEFENDER}) if(auto * _armyObj = battleGetArmyObject(i)) _armyObj->battle = nullptr; } @@ -600,27 +604,27 @@ IBattleInfo::ObstacleCList BattleInfo::getAllObstacles() const return ret; } -PlayerColor BattleInfo::getSidePlayer(ui8 side) const +PlayerColor BattleInfo::getSidePlayer(BattleSide side) const { - return sides.at(side).color; + return getSide(side).color; } -const CArmedInstance * BattleInfo::getSideArmy(ui8 side) const +const CArmedInstance * BattleInfo::getSideArmy(BattleSide side) const { - return sides.at(side).armyObject; + return getSide(side).armyObject; } -const CGHeroInstance * BattleInfo::getSideHero(ui8 side) const +const CGHeroInstance * BattleInfo::getSideHero(BattleSide side) const { - return sides.at(side).hero; + return getSide(side).hero; } -ui8 BattleInfo::getTacticDist() const +uint8_t BattleInfo::getTacticDist() const { return tacticDistance; } -ui8 BattleInfo::getTacticsSide() const +BattleSide BattleInfo::getTacticsSide() const { return tacticsSide; } @@ -640,14 +644,14 @@ EGateState BattleInfo::getGateState() const return si.gateState; } -uint32_t BattleInfo::getCastSpells(ui8 side) const +uint32_t BattleInfo::getCastSpells(BattleSide side) const { - return sides.at(side).castSpellsCount; + return getSide(side).castSpellsCount; } -int32_t BattleInfo::getEnchanterCounter(ui8 side) const +int32_t BattleInfo::getEnchanterCounter(BattleSide side) const { - return sides.at(side).enchanterCounter; + return getSide(side).enchanterCounter; } const IBonusBearer * BattleInfo::getBonusBearer() const @@ -685,14 +689,14 @@ bool BattleInfo::isCreatureBank() const } -std::vector BattleInfo::getUsedSpells(ui8 side) const +std::vector BattleInfo::getUsedSpells(BattleSide side) const { - return sides.at(side).usedSpellsHistory; + return getSide(side).usedSpellsHistory; } void BattleInfo::nextRound() { - for(int i = 0; i < 2; ++i) + for(auto i : {BattleSide::ATTACKER, BattleSide::DEFENDER}) { sides.at(i).castSpellsCount = 0; vstd::amax(--sides.at(i).enchanterCounter, 0); @@ -994,12 +998,12 @@ void BattleInfo::removeObstacle(uint32_t id) } } -CArmedInstance * BattleInfo::battleGetArmyObject(ui8 side) const +CArmedInstance * BattleInfo::battleGetArmyObject(BattleSide side) const { return const_cast(CBattleInfoEssentials::battleGetArmyObject(side)); } -CGHeroInstance * BattleInfo::battleGetFightingHero(ui8 side) const +CGHeroInstance * BattleInfo::battleGetFightingHero(BattleSide side) const { return const_cast(CBattleInfoEssentials::battleGetFightingHero(side)); } @@ -1009,7 +1013,7 @@ scripting::Pool * BattleInfo::getContextPool() const { //this is real battle, use global scripting context pool //TODO: make this line not ugly - return battleGetFightingHero(0)->cb->getGlobalContextPool(); + return battleGetFightingHero(BattleSide::ATTACKER)->cb->getGlobalContextPool(); } #endif @@ -1045,7 +1049,7 @@ bool CMP_stack::operator()(const battle::Unit * a, const battle::Unit * b) const return false; } -CMP_stack::CMP_stack(int Phase, int Turn, uint8_t Side): +CMP_stack::CMP_stack(int Phase, int Turn, BattleSide Side): phase(Phase), turn(Turn), side(Side) diff --git a/lib/battle/BattleInfo.h b/lib/battle/BattleInfo.h index 58b901fab..a95c154b5 100644 --- a/lib/battle/BattleInfo.h +++ b/lib/battle/BattleInfo.h @@ -25,15 +25,10 @@ class BattleField; class DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallback, public IBattleState { + BattleSideArray sides; //sides[0] - attacker, sides[1] - defender public: BattleID battleID = BattleID(0); - enum BattleSide - { - ATTACKER = 0, - DEFENDER - }; - std::array sides; //sides[0] - attacker, sides[1] - defender si32 round; si32 activeStack; const CGTownInstance * town; //used during town siege, nullptr if this is not a siege (note that fortless town IS also a siege) @@ -47,7 +42,7 @@ public: BattleField battlefieldType; //like !!BA:B TerrainId terrainType; //used for some stack nativity checks (not the bonus limiters though that have their own copy) - ui8 tacticsSide; //which side is requested to play tactics phase + BattleSide tacticsSide; //which side is requested to play tactics phase ui8 tacticDistance; //how many hexes we can go forward (1 = only hexes adjacent to margin line) template void serialize(Handler &h) @@ -92,19 +87,19 @@ public: ObstacleCList getAllObstacles() const override; - PlayerColor getSidePlayer(ui8 side) const override; - const CArmedInstance * getSideArmy(ui8 side) const override; - const CGHeroInstance * getSideHero(ui8 side) const override; + PlayerColor getSidePlayer(BattleSide side) const override; + const CArmedInstance * getSideArmy(BattleSide side) const override; + const CGHeroInstance * getSideHero(BattleSide side) const override; ui8 getTacticDist() const override; - ui8 getTacticsSide() const override; + BattleSide getTacticsSide() const override; const CGTownInstance * getDefendedTown() const override; EWallState getWallState(EWallPart partOfWall) const override; EGateState getGateState() const override; - uint32_t getCastSpells(ui8 side) const override; - int32_t getEnchanterCounter(ui8 side) const override; + uint32_t getCastSpells(BattleSide side) const override; + int32_t getEnchanterCounter(BattleSide side) const override; const IBonusBearer * getBonusBearer() const override; @@ -115,7 +110,7 @@ public: int3 getLocation() const override; bool isCreatureBank() const override; - std::vector getUsedSpells(ui8 side) const override; + std::vector getUsedSpells(BattleSide side) const override; ////////////////////////////////////////////////////////////////////////// // IBattleState @@ -144,19 +139,22 @@ public: ////////////////////////////////////////////////////////////////////////// CStack * getStack(int stackID, bool onlyAlive = true); using CBattleInfoEssentials::battleGetArmyObject; - CArmedInstance * battleGetArmyObject(ui8 side) const; + CArmedInstance * battleGetArmyObject(BattleSide side) const; using CBattleInfoEssentials::battleGetFightingHero; - CGHeroInstance * battleGetFightingHero(ui8 side) const; + CGHeroInstance * battleGetFightingHero(BattleSide side) const; - CStack * generateNewStack(uint32_t id, const CStackInstance & base, ui8 side, const SlotID & slot, BattleHex position); - CStack * generateNewStack(uint32_t id, const CStackBasicDescriptor & base, ui8 side, const SlotID & slot, BattleHex position); + CStack * generateNewStack(uint32_t id, const CStackInstance & base, BattleSide side, const SlotID & slot, BattleHex position); + CStack * generateNewStack(uint32_t id, const CStackBasicDescriptor & base, BattleSide side, const SlotID & slot, BattleHex position); + + const SideInBattle & getSide(BattleSide side) const; + SideInBattle & getSide(BattleSide side); const CGHeroInstance * getHero(const PlayerColor & player) const; //returns fighting hero that belongs to given player void localInit(); - static BattleInfo * setupBattle(const int3 & tile, TerrainId, const BattleField & battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town); + static BattleInfo * setupBattle(const int3 & tile, TerrainId, const BattleField & battlefieldType, BattleSideArray armies, BattleSideArray heroes, bool creatureBank, const CGTownInstance * town); - ui8 whatSide(const PlayerColor & player) const; + BattleSide whatSide(const PlayerColor & player) const; protected: #if SCRIPTING_ENABLED @@ -169,10 +167,10 @@ class DLL_LINKAGE CMP_stack { int phase; //rules of which phase will be used int turn; - uint8_t side; + BattleSide side; public: bool operator()(const battle::Unit * a, const battle::Unit * b) const; - CMP_stack(int Phase = 1, int Turn = 0, uint8_t Side = BattleSide::ATTACKER); + CMP_stack(int Phase = 1, int Turn = 0, BattleSide Side = BattleSide::ATTACKER); }; VCMI_LIB_NAMESPACE_END diff --git a/lib/battle/BattleProxy.cpp b/lib/battle/BattleProxy.cpp index 6bc34a77e..d9a748745 100644 --- a/lib/battle/BattleProxy.cpp +++ b/lib/battle/BattleProxy.cpp @@ -65,17 +65,17 @@ IBattleInfo::ObstacleCList BattleProxy::getAllObstacles() const return subject->battleGetAllObstacles(); } -PlayerColor BattleProxy::getSidePlayer(ui8 side) const +PlayerColor BattleProxy::getSidePlayer(BattleSide side) const { return subject->sideToPlayer(side); } -const CArmedInstance * BattleProxy::getSideArmy(ui8 side) const +const CArmedInstance * BattleProxy::getSideArmy(BattleSide side) const { return subject->battleGetArmyObject(side); } -const CGHeroInstance * BattleProxy::getSideHero(ui8 side) const +const CGHeroInstance * BattleProxy::getSideHero(BattleSide side) const { return subject->battleGetFightingHero(side); } @@ -85,7 +85,7 @@ ui8 BattleProxy::getTacticDist() const return subject->battleTacticDist(); } -ui8 BattleProxy::getTacticsSide() const +BattleSide BattleProxy::getTacticsSide() const { return subject->battleGetTacticsSide(); } @@ -105,12 +105,12 @@ EGateState BattleProxy::getGateState() const return subject->battleGetGateState(); } -uint32_t BattleProxy::getCastSpells(ui8 side) const +uint32_t BattleProxy::getCastSpells(BattleSide side) const { return subject->battleCastSpells(side); } -int32_t BattleProxy::getEnchanterCounter(ui8 side) const +int32_t BattleProxy::getEnchanterCounter(BattleSide side) const { return subject->battleGetEnchanterCounter(side); } diff --git a/lib/battle/BattleProxy.h b/lib/battle/BattleProxy.h index c43ede14d..1131d9614 100644 --- a/lib/battle/BattleProxy.h +++ b/lib/battle/BattleProxy.h @@ -38,19 +38,19 @@ public: ObstacleCList getAllObstacles() const override; - PlayerColor getSidePlayer(ui8 side) const override; - const CArmedInstance * getSideArmy(ui8 side) const override; - const CGHeroInstance * getSideHero(ui8 side) const override; + PlayerColor getSidePlayer(BattleSide side) const override; + const CArmedInstance * getSideArmy(BattleSide side) const override; + const CGHeroInstance * getSideHero(BattleSide side) const override; ui8 getTacticDist() const override; - ui8 getTacticsSide() const override; + BattleSide getTacticsSide() const override; const CGTownInstance * getDefendedTown() const override; EWallState getWallState(EWallPart partOfWall) const override; EGateState getGateState() const override; - uint32_t getCastSpells(ui8 side) const override; - int32_t getEnchanterCounter(ui8 side) const override; + uint32_t getCastSpells(BattleSide side) const override; + int32_t getEnchanterCounter(BattleSide side) const override; const IBonusBearer * getBonusBearer() const override; protected: diff --git a/lib/battle/BattleSide.h b/lib/battle/BattleSide.h new file mode 100644 index 000000000..44156d75c --- /dev/null +++ b/lib/battle/BattleSide.h @@ -0,0 +1,53 @@ +/* + * BattleSide.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +VCMI_LIB_NAMESPACE_BEGIN + +enum class BattleSide : int8_t +{ + NONE = -1, + INVALID = -2, + ALL_KNOWING = -3, + + ATTACKER = 0, + DEFENDER = 1, + + // Aliases for convenience + LEFT_SIDE = ATTACKER, + RIGHT_SIDE = DEFENDER, +}; + +template +class BattleSideArray : public std::array +{ +public: + const T & at(BattleSide side) const + { + return std::array::at(static_cast(side)); + } + + T & at(BattleSide side) + { + return std::array::at(static_cast(side)); + } + + const T & operator[](BattleSide side) const + { + return std::array::at(static_cast(side)); + } + + T & operator[](BattleSide side) + { + return std::array::at(static_cast(side)); + } +}; + +VCMI_LIB_NAMESPACE_END diff --git a/lib/battle/BattleStateInfoForRetreat.cpp b/lib/battle/BattleStateInfoForRetreat.cpp index 8eabecc12..d517f242a 100644 --- a/lib/battle/BattleStateInfoForRetreat.cpp +++ b/lib/battle/BattleStateInfoForRetreat.cpp @@ -23,7 +23,7 @@ BattleStateInfoForRetreat::BattleStateInfoForRetreat(): isLastTurnBeforeDie(false), ourHero(nullptr), enemyHero(nullptr), - ourSide(-1) + ourSide(BattleSide::NONE) { } diff --git a/lib/battle/BattleStateInfoForRetreat.h b/lib/battle/BattleStateInfoForRetreat.h index 341ed7ffe..42cd8b7a6 100644 --- a/lib/battle/BattleStateInfoForRetreat.h +++ b/lib/battle/BattleStateInfoForRetreat.h @@ -9,6 +9,8 @@ */ #pragma once +#include "BattleSide.h" + VCMI_LIB_NAMESPACE_BEGIN namespace battle @@ -24,7 +26,7 @@ public: bool canFlee; bool canSurrender; bool isLastTurnBeforeDie; - ui8 ourSide; + BattleSide ourSide; std::vector ourStacks; std::vector enemyStacks; const CGHeroInstance * ourHero; diff --git a/lib/battle/CBattleInfoCallback.cpp b/lib/battle/CBattleInfoCallback.cpp index ae1ca02cb..53bec15b1 100644 --- a/lib/battle/CBattleInfoCallback.cpp +++ b/lib/battle/CBattleInfoCallback.cpp @@ -110,9 +110,9 @@ ESpellCastProblem CBattleInfoCallback::battleCanCastSpell(const spells::Caster * } const PlayerColor player = caster->getCasterOwner(); const auto side = playerToSide(player); - if(!side) + if(side == BattleSide::NONE) return ESpellCastProblem::INVALID; - if(!battleDoWeKnowAbout(side.value())) + if(!battleDoWeKnowAbout(side)) { logGlobal->warn("You can't check if enemy can cast given spell!"); return ESpellCastProblem::INVALID; @@ -125,7 +125,7 @@ ESpellCastProblem CBattleInfoCallback::battleCanCastSpell(const spells::Caster * { case spells::Mode::HERO: { - if(battleCastSpells(side.value()) > 0) + if(battleCastSpells(side) > 0) return ESpellCastProblem::CASTS_PER_TURN_LIMIT; const auto * hero = dynamic_cast(caster); @@ -376,7 +376,7 @@ battle::Units CBattleInfoCallback::battleAliveUnits() const }); } -battle::Units CBattleInfoCallback::battleAliveUnits(ui8 side) const +battle::Units CBattleInfoCallback::battleAliveUnits(BattleSide side) const { return battleGetUnitsIf([=](const battle::Unit * unit) { @@ -388,7 +388,7 @@ using namespace battle; //T is battle::Unit descendant template -const T * takeOneUnit(std::vector & allUnits, const int turn, int8_t & sideThatLastMoved, int phase) +const T * takeOneUnit(std::vector & allUnits, const int turn, BattleSide & sideThatLastMoved, int phase) { const T * returnedUnit = nullptr; size_t currentUnitIndex = 0; @@ -417,13 +417,13 @@ const T * takeOneUnit(std::vector & allUnits, const int turn, int8_t & } else if(currentUnitInitiative == returnedUnitInitiative) { - if(sideThatLastMoved == -1 && turn <= 0 && currentUnit->unitSide() == BattleSide::ATTACKER + if(sideThatLastMoved == BattleSide::NONE && turn <= 0 && currentUnit->unitSide() == BattleSide::ATTACKER && !(returnedUnit->unitSide() == currentUnit->unitSide() && returnedUnit->unitSlot() < currentUnit->unitSlot())) // Turn 0 attacker priority { returnedUnit = currentUnit; currentUnitIndex = i; } - else if(sideThatLastMoved != -1 && currentUnit->unitSide() != sideThatLastMoved + else if(sideThatLastMoved != BattleSide::NONE && currentUnit->unitSide() != sideThatLastMoved && !(returnedUnit->unitSide() == currentUnit->unitSide() && returnedUnit->unitSlot() < currentUnit->unitSlot())) // Alternate equal speeds units { returnedUnit = currentUnit; @@ -438,7 +438,7 @@ const T * takeOneUnit(std::vector & allUnits, const int turn, int8_t & returnedUnit = currentUnit; currentUnitIndex = i; } - else if(currentUnitInitiative == returnedUnitInitiative && sideThatLastMoved != -1 && currentUnit->unitSide() != sideThatLastMoved + else if(currentUnitInitiative == returnedUnitInitiative && sideThatLastMoved != BattleSide::NONE && currentUnit->unitSide() != sideThatLastMoved && !(returnedUnit->unitSide() == currentUnit->unitSide() && returnedUnit->unitSlot() < currentUnit->unitSlot())) // Alternate equal speeds units { returnedUnit = currentUnit; @@ -458,7 +458,7 @@ const T * takeOneUnit(std::vector & allUnits, const int turn, int8_t & return returnedUnit; } -void CBattleInfoCallback::battleGetTurnOrder(std::vector & turns, const size_t maxUnits, const int maxTurns, const int turn, int8_t sideThatLastMoved) const +void CBattleInfoCallback::battleGetTurnOrder(std::vector & turns, const size_t maxUnits, const int maxTurns, const int turn, BattleSide sideThatLastMoved) const { RETURN_IF_NOT_BATTLE(); @@ -500,7 +500,7 @@ void CBattleInfoCallback::battleGetTurnOrder(std::vector & turns, //its first or current turn, turn priority for active stack side //TODO: what if active stack mind-controlled? - if(turn <= 0 && sideThatLastMoved < 0) + if(turn <= 0 && sideThatLastMoved == BattleSide::NONE) sideThatLastMoved = activeUnit->unitSide(); } @@ -560,7 +560,7 @@ void CBattleInfoCallback::battleGetTurnOrder(std::vector & turns, } } - if(sideThatLastMoved < 0) + if(sideThatLastMoved == BattleSide::NONE) sideThatLastMoved = BattleSide::ATTACKER; if(!turnsIsFull() && (maxTurns == 0 || turns.size() < maxTurns)) @@ -887,7 +887,7 @@ bool CBattleInfoCallback::handleObstacleTriggersForUnit(SpellCastEnvironment & s spellEnv.apply(&bocp); }; const auto side = unit.unitSide(); - auto shouldReveal = !spellObstacle->hidden || !battleIsObstacleVisibleForSide(*obstacle, (BattlePerspective::BattlePerspective)side); + auto shouldReveal = !spellObstacle->hidden || !battleIsObstacleVisibleForSide(*obstacle, side); const auto * hero = battleGetFightingHero(spellObstacle->casterSide); auto caster = spells::ObstacleCasterProxy(getBattle()->getSidePlayer(spellObstacle->casterSide), hero, *spellObstacle); @@ -1098,7 +1098,7 @@ bool CBattleInfoCallback::isInObstacle( return false; } -std::set CBattleInfoCallback::getStoppers(BattlePerspective::BattlePerspective whichSidePerspective) const +std::set CBattleInfoCallback::getStoppers(BattleSide whichSidePerspective) const { std::set ret; RETURN_IF_NOT_BATTLE(ret); @@ -1161,7 +1161,7 @@ std::pair CBattleInfoCallback::getNearestStack( return std::make_pair(nullptr, BattleHex::INVALID); } -BattleHex CBattleInfoCallback::getAvailableHex(const CreatureID & creID, ui8 side, int initialPos) const +BattleHex CBattleInfoCallback::getAvailableHex(const CreatureID & creID, BattleSide side, int initialPos) const { bool twoHex = VLC->creatures()->getById(creID)->isDoubleWide(); @@ -1208,8 +1208,13 @@ bool CBattleInfoCallback::isInTacticRange(BattleHex dest) const auto side = battleGetTacticsSide(); auto dist = battleGetTacticDist(); - return ((!side && dest.getX() > 0 && dest.getX() <= dist) - || (side && dest.getX() < GameConstants::BFIELD_WIDTH - 1 && dest.getX() >= GameConstants::BFIELD_WIDTH - dist - 1)); + if (side == BattleSide::ATTACKER && dest.getX() > 0 && dest.getX() <= dist) + return true; + + if (side == BattleSide::DEFENDER && dest.getX() < GameConstants::BFIELD_WIDTH - 1 && dest.getX() >= GameConstants::BFIELD_WIDTH - dist - 1) + return true; + + return false; } ReachabilityInfo CBattleInfoCallback::getReachability(const battle::Unit * unit) const @@ -1452,7 +1457,7 @@ std::set CBattleInfoCallback::getAttackedCreatures(const CStack* return attackedCres; } -static bool isHexInFront(BattleHex hex, BattleHex testHex, BattleSide::Type side ) +static bool isHexInFront(BattleHex hex, BattleHex testHex, BattleSide side ) { static const std::set rightDirs { BattleHex::BOTTOM_RIGHT, BattleHex::TOP_RIGHT, BattleHex::RIGHT }; static const std::set leftDirs { BattleHex::BOTTOM_LEFT, BattleHex::TOP_LEFT, BattleHex::LEFT }; @@ -1477,7 +1482,7 @@ bool CBattleInfoCallback::isToReverse(const battle::Unit * attacker, const battl if (attackerHex < 0 ) //turret return false; - if(isHexInFront(attackerHex, defenderHex, static_cast(attacker->unitSide()))) + if(isHexInFront(attackerHex, defenderHex, attacker->unitSide())) return false; auto defenderOtherHex = defenderHex; @@ -1487,7 +1492,7 @@ bool CBattleInfoCallback::isToReverse(const battle::Unit * attacker, const battl { defenderOtherHex = battle::Unit::occupiedHex(defenderHex, true, defender->unitSide()); - if(isHexInFront(attackerHex, defenderOtherHex, static_cast(attacker->unitSide()))) + if(isHexInFront(attackerHex, defenderOtherHex, attacker->unitSide())) return false; } @@ -1495,7 +1500,7 @@ bool CBattleInfoCallback::isToReverse(const battle::Unit * attacker, const battl { attackerOtherHex = battle::Unit::occupiedHex(attackerHex, true, attacker->unitSide()); - if(isHexInFront(attackerOtherHex, defenderHex, static_cast(attacker->unitSide()))) + if(isHexInFront(attackerOtherHex, defenderHex, attacker->unitSide())) return false; } @@ -1503,7 +1508,7 @@ bool CBattleInfoCallback::isToReverse(const battle::Unit * attacker, const battl // but this is how H3 handles it which is important, e.g. for direction of dragon breath attacks if (attacker->doubleWide() && defender->doubleWide()) { - if(isHexInFront(attackerOtherHex, defenderOtherHex, static_cast(attacker->unitSide()))) + if(isHexInFront(attackerOtherHex, defenderOtherHex, attacker->unitSide())) return false; } return true; @@ -1762,7 +1767,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(vstd::RNG & rand, const ba case SpellID::PROTECTION_FROM_FIRE: case SpellID::PROTECTION_FROM_WATER: { - const ui8 enemySide = 1 - subject->unitSide(); + const BattleSide enemySide = otherSide(subject->unitSide()); //todo: only if enemy has spellbook if (!battleHasHero(enemySide)) //only if there is enemy hero continue; @@ -1853,10 +1858,9 @@ int CBattleInfoCallback::battleGetSurrenderCost(const PlayerColor & Player) cons if(!battleCanSurrender(Player)) return -1; - const auto sideOpt = playerToSide(Player); - if(!sideOpt) + const BattleSide side = playerToSide(Player); + if(side == BattleSide::NONE) return -1; - const auto side = sideOpt.value(); int ret = 0; double discount = 0; @@ -1872,7 +1876,7 @@ int CBattleInfoCallback::battleGetSurrenderCost(const PlayerColor & Player) cons return ret; } -si8 CBattleInfoCallback::battleMinSpellLevel(ui8 side) const +si8 CBattleInfoCallback::battleMinSpellLevel(BattleSide side) const { const IBonusBearer * node = nullptr; if(const CGHeroInstance * h = battleGetFightingHero(side)) @@ -1890,7 +1894,7 @@ si8 CBattleInfoCallback::battleMinSpellLevel(ui8 side) const return 0; } -si8 CBattleInfoCallback::battleMaxSpellLevel(ui8 side) const +si8 CBattleInfoCallback::battleMaxSpellLevel(BattleSide side) const { const IBonusBearer *node = nullptr; if(const CGHeroInstance * h = battleGetFightingHero(side)) @@ -1909,21 +1913,21 @@ si8 CBattleInfoCallback::battleMaxSpellLevel(ui8 side) const return GameConstants::SPELL_LEVELS; } -std::optional CBattleInfoCallback::battleIsFinished() const +std::optional CBattleInfoCallback::battleIsFinished() const { auto units = battleGetUnitsIf([=](const battle::Unit * unit) { return unit->alive() && !unit->isTurret() && !unit->hasBonusOfType(BonusType::SIEGE_WEAPON); }); - std::array hasUnit = {false, false}; //index is BattleSide + BattleSideArray hasUnit = {false, false}; //index is BattleSide for(auto & unit : units) { //todo: move SIEGE_WEAPON check to Unit state hasUnit.at(unit->unitSide()) = true; - if(hasUnit[0] && hasUnit[1]) + if(hasUnit[BattleSide::ATTACKER] && hasUnit[BattleSide::DEFENDER]) return std::nullopt; } @@ -1937,12 +1941,12 @@ std::optional CBattleInfoCallback::battleIsFinished() const } } - if(!hasUnit[0] && !hasUnit[1]) - return 2; - if(!hasUnit[1]) - return 0; + if(!hasUnit[BattleSide::ATTACKER] && !hasUnit[BattleSide::DEFENDER]) + return BattleSide::NONE; + if(!hasUnit[BattleSide::DEFENDER]) + return BattleSide::ATTACKER; else - return 1; + return BattleSide::DEFENDER; } VCMI_LIB_NAMESPACE_END diff --git a/lib/battle/CBattleInfoCallback.h b/lib/battle/CBattleInfoCallback.h index c965e72f5..6e42f3d94 100644 --- a/lib/battle/CBattleInfoCallback.h +++ b/lib/battle/CBattleInfoCallback.h @@ -56,7 +56,7 @@ struct DLL_LINKAGE BattleClientInterfaceData class DLL_LINKAGE CBattleInfoCallback : public virtual CBattleInfoEssentials { public: - std::optional battleIsFinished() const override; //return none if battle is ongoing; otherwise the victorious side (0/1) or 2 if it is a draw + std::optional battleIsFinished() const override; //return none if battle is ongoing; otherwise the victorious side (0/1) or 2 if it is a draw std::vector> battleGetAllObstaclesOnPos(BattleHex tile, bool onlyBlocking = true) const override; std::vector> getAllAffectedObstaclesByStack(const battle::Unit * unit, const std::set & passed) const override; @@ -70,9 +70,9 @@ public: ///returns all alive units excluding turrets battle::Units battleAliveUnits() const; ///returns all alive units from particular side excluding turrets - battle::Units battleAliveUnits(ui8 side) const; + battle::Units battleAliveUnits(BattleSide side) const; - void battleGetTurnOrder(std::vector & out, const size_t maxUnits, const int maxTurns, const int turn = 0, int8_t lastMoved = -1) const; + void battleGetTurnOrder(std::vector & out, const size_t maxUnits, const int maxTurns, const int turn = 0, BattleSide lastMoved = BattleSide::NONE) const; ///returns reachable hexes (valid movement destinations), DOES contain stack current position std::vector battleGetAvailableHexes(const battle::Unit * unit, bool obtainMovementRange, bool addOccupiable, std::vector * attackable) const; @@ -116,8 +116,8 @@ public: bool isWallPartAttackable(EWallPart wallPart) const; // returns true if the wall part is actually attackable, false if not std::vector getAttackableBattleHexes() const; - si8 battleMinSpellLevel(ui8 side) const; //calculates maximum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, 0 is returned - si8 battleMaxSpellLevel(ui8 side) const; //calculates minimum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, 0 is returned + si8 battleMinSpellLevel(BattleSide side) const; //calculates maximum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, 0 is returned + si8 battleMaxSpellLevel(BattleSide side) const; //calculates minimum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, 0 is returned int32_t battleGetSpellCost(const spells::Spell * sp, const CGHeroInstance * caster) const; //returns cost of given spell ESpellCastProblem battleCanCastSpell(const spells::Caster * caster, spells::Mode mode) const; //returns true if there are no general issues preventing from casting a spell @@ -163,12 +163,12 @@ public: AccessibilityInfo getAccessibility(const std::vector & accessibleHexes) const; //given hexes will be marked as accessible std::pair getNearestStack(const battle::Unit * closest) const; - BattleHex getAvailableHex(const CreatureID & creID, ui8 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 protected: ReachabilityInfo getFlyingReachability(const ReachabilityInfo::Parameters & params) const; ReachabilityInfo makeBFS(const AccessibilityInfo & accessibility, const ReachabilityInfo::Parameters & params) const; bool isInObstacle(BattleHex hex, const std::set & obstacles, const ReachabilityInfo::Parameters & params) const; - std::set getStoppers(BattlePerspective::BattlePerspective whichSidePerspective) const; //get hexes with stopping obstacles (quicksands) + std::set getStoppers(BattleSide whichSidePerspective) const; //get hexes with stopping obstacles (quicksands) }; VCMI_LIB_NAMESPACE_END diff --git a/lib/battle/CBattleInfoEssentials.cpp b/lib/battle/CBattleInfoEssentials.cpp index f3ee409c0..7fce0ad88 100644 --- a/lib/battle/CBattleInfoEssentials.cpp +++ b/lib/battle/CBattleInfoEssentials.cpp @@ -35,13 +35,13 @@ BattleField CBattleInfoEssentials::battleGetBattlefieldType() const return getBattle()->getBattlefieldType(); } -int32_t CBattleInfoEssentials::battleGetEnchanterCounter(ui8 side) const +int32_t CBattleInfoEssentials::battleGetEnchanterCounter(BattleSide side) const { RETURN_IF_NOT_BATTLE(0); return getBattle()->getEnchanterCounter(side); } -std::vector> CBattleInfoEssentials::battleGetAllObstacles(std::optional perspective) const +std::vector> CBattleInfoEssentials::battleGetAllObstacles(std::optional perspective) const { std::vector > ret; RETURN_IF_NOT_BATTLE(ret); @@ -82,13 +82,13 @@ std::shared_ptr CBattleInfoEssentials::battleGetObstacl return std::shared_ptr(); } -bool CBattleInfoEssentials::battleIsObstacleVisibleForSide(const CObstacleInstance & coi, BattlePerspective::BattlePerspective side) const +bool CBattleInfoEssentials::battleIsObstacleVisibleForSide(const CObstacleInstance & coi, BattleSide side) const { RETURN_IF_NOT_BATTLE(false); - return side == BattlePerspective::ALL_KNOWING || coi.visibleForSide(side, battleHasNativeStack(side)); + return side == BattleSide::ALL_KNOWING || coi.visibleForSide(side, battleHasNativeStack(side)); } -bool CBattleInfoEssentials::battleHasNativeStack(ui8 side) const +bool CBattleInfoEssentials::battleHasNativeStack(BattleSide side) const { RETURN_IF_NOT_BATTLE(false); @@ -160,18 +160,18 @@ const CGTownInstance * CBattleInfoEssentials::battleGetDefendedTown() const return getBattle()->getDefendedTown(); } -BattlePerspective::BattlePerspective CBattleInfoEssentials::battleGetMySide() const +BattleSide CBattleInfoEssentials::battleGetMySide() const { - RETURN_IF_NOT_BATTLE(BattlePerspective::INVALID); + RETURN_IF_NOT_BATTLE(BattleSide::INVALID); if(!getPlayerID() || getPlayerID()->isSpectator()) - return BattlePerspective::ALL_KNOWING; + return BattleSide::ALL_KNOWING; if(*getPlayerID() == getBattle()->getSidePlayer(BattleSide::ATTACKER)) - return BattlePerspective::LEFT_SIDE; + return BattleSide::LEFT_SIDE; if(*getPlayerID() == getBattle()->getSidePlayer(BattleSide::DEFENDER)) - return BattlePerspective::RIGHT_SIDE; + return BattleSide::RIGHT_SIDE; logGlobal->error("Cannot find player %s in battle!", getPlayerID()->toString()); - return BattlePerspective::INVALID; + return BattleSide::INVALID; } const CStack* CBattleInfoEssentials::battleGetStackByID(int ID, bool onlyAlive) const @@ -189,11 +189,11 @@ const CStack* CBattleInfoEssentials::battleGetStackByID(int ID, bool onlyAlive) return stacks[0]; } -bool CBattleInfoEssentials::battleDoWeKnowAbout(ui8 side) const +bool CBattleInfoEssentials::battleDoWeKnowAbout(BattleSide side) const { RETURN_IF_NOT_BATTLE(false); auto p = battleGetMySide(); - return p == BattlePerspective::ALL_KNOWING || p == side; + return p == BattleSide::ALL_KNOWING || p == side; } si8 CBattleInfoEssentials::battleTacticDist() const @@ -202,16 +202,16 @@ si8 CBattleInfoEssentials::battleTacticDist() const return getBattle()->getTacticDist(); } -si8 CBattleInfoEssentials::battleGetTacticsSide() const +BattleSide CBattleInfoEssentials::battleGetTacticsSide() const { - RETURN_IF_NOT_BATTLE(-1); + RETURN_IF_NOT_BATTLE(BattleSide::NONE); return getBattle()->getTacticsSide(); } -const CGHeroInstance * CBattleInfoEssentials::battleGetFightingHero(ui8 side) const +const CGHeroInstance * CBattleInfoEssentials::battleGetFightingHero(BattleSide side) const { RETURN_IF_NOT_BATTLE(nullptr); - if(side > 1) + if(side != BattleSide::DEFENDER && side != BattleSide::ATTACKER) { logGlobal->error("FIXME: %s wrong argument!", __FUNCTION__); return nullptr; @@ -226,10 +226,10 @@ const CGHeroInstance * CBattleInfoEssentials::battleGetFightingHero(ui8 side) co return getBattle()->getSideHero(side); } -const CArmedInstance * CBattleInfoEssentials::battleGetArmyObject(ui8 side) const +const CArmedInstance * CBattleInfoEssentials::battleGetArmyObject(BattleSide side) const { RETURN_IF_NOT_BATTLE(nullptr); - if(side > 1) + if(side != BattleSide::DEFENDER && side != BattleSide::ATTACKER) { logGlobal->error("FIXME: %s wrong argument!", __FUNCTION__); return nullptr; @@ -242,7 +242,7 @@ const CArmedInstance * CBattleInfoEssentials::battleGetArmyObject(ui8 side) cons return getBattle()->getSideArmy(side); } -InfoAboutHero CBattleInfoEssentials::battleGetHeroInfo(ui8 side) const +InfoAboutHero CBattleInfoEssentials::battleGetHeroInfo(BattleSide side) const { const auto * hero = getBattle()->getSideHero(side); if(!hero) @@ -253,7 +253,7 @@ InfoAboutHero CBattleInfoEssentials::battleGetHeroInfo(ui8 side) const return InfoAboutHero(hero, infoLevel); } -uint32_t CBattleInfoEssentials::battleCastSpells(ui8 side) const +uint32_t CBattleInfoEssentials::battleCastSpells(BattleSide side) const { RETURN_IF_NOT_BATTLE(-1); return getBattle()->getCastSpells(side); @@ -268,10 +268,10 @@ bool CBattleInfoEssentials::battleCanFlee(const PlayerColor & player) const { RETURN_IF_NOT_BATTLE(false); const auto side = playerToSide(player); - if(!side) + if(side == BattleSide::NONE) return false; - const CGHeroInstance * myHero = battleGetFightingHero(side.value()); + const CGHeroInstance * myHero = battleGetFightingHero(side); //current player have no hero if(!myHero) @@ -292,28 +292,28 @@ bool CBattleInfoEssentials::battleCanFlee(const PlayerColor & player) const return true; } -BattleSideOpt CBattleInfoEssentials::playerToSide(const PlayerColor & player) const +BattleSide CBattleInfoEssentials::playerToSide(const PlayerColor & player) const { - RETURN_IF_NOT_BATTLE(std::nullopt); + RETURN_IF_NOT_BATTLE(BattleSide::NONE); if(getBattle()->getSidePlayer(BattleSide::ATTACKER) == player) - return BattleSideOpt(BattleSide::ATTACKER); + return BattleSide::ATTACKER; if(getBattle()->getSidePlayer(BattleSide::DEFENDER) == player) - return BattleSideOpt(BattleSide::DEFENDER); + return BattleSide::DEFENDER; logGlobal->warn("Cannot find side for player %s", player.toString()); - return std::nullopt; + return BattleSide::INVALID; } -PlayerColor CBattleInfoEssentials::sideToPlayer(ui8 side) const +PlayerColor CBattleInfoEssentials::sideToPlayer(BattleSide side) const { RETURN_IF_NOT_BATTLE(PlayerColor::CANNOT_DETERMINE); return getBattle()->getSidePlayer(side); } -ui8 CBattleInfoEssentials::otherSide(ui8 side) const +BattleSide CBattleInfoEssentials::otherSide(BattleSide side) { if(side == BattleSide::ATTACKER) return BattleSide::DEFENDER; @@ -326,19 +326,19 @@ PlayerColor CBattleInfoEssentials::otherPlayer(const PlayerColor & player) const RETURN_IF_NOT_BATTLE(PlayerColor::CANNOT_DETERMINE); auto side = playerToSide(player); - if(!side) + if(side == BattleSide::NONE) return PlayerColor::CANNOT_DETERMINE; - return getBattle()->getSidePlayer(otherSide(side.value())); + return getBattle()->getSidePlayer(otherSide(side)); } bool CBattleInfoEssentials::playerHasAccessToHeroInfo(const PlayerColor & player, const CGHeroInstance * h) const { RETURN_IF_NOT_BATTLE(false); const auto side = playerToSide(player); - if(side) + if(side != BattleSide::NONE) { - auto opponentSide = otherSide(side.value()); + auto opponentSide = otherSide(side); if(getBattle()->getSideHero(opponentSide) == h) return true; } @@ -355,14 +355,14 @@ bool CBattleInfoEssentials::battleCanSurrender(const PlayerColor & player) const { RETURN_IF_NOT_BATTLE(false); const auto side = playerToSide(player); - if(!side) + if(side == BattleSide::NONE) return false; - bool iAmSiegeDefender = (side.value() == BattleSide::DEFENDER && getBattle()->getDefendedTown() != nullptr); + bool iAmSiegeDefender = (side == BattleSide::DEFENDER && getBattle()->getDefendedTown() != nullptr); //conditions like for fleeing (except escape tunnel presence) + enemy must have a hero - return battleCanFlee(player) && !iAmSiegeDefender && battleHasHero(otherSide(side.value())); + return battleCanFlee(player) && !iAmSiegeDefender && battleHasHero(otherSide(side)); } -bool CBattleInfoEssentials::battleHasHero(ui8 side) const +bool CBattleInfoEssentials::battleHasHero(BattleSide side) const { RETURN_IF_NOT_BATTLE(false); return getBattle()->getSideHero(side) != nullptr; @@ -413,9 +413,9 @@ const CGHeroInstance * CBattleInfoEssentials::battleGetOwnerHero(const battle::U { RETURN_IF_NOT_BATTLE(nullptr); const auto side = playerToSide(battleGetOwner(unit)); - if(!side) + if(side == BattleSide::NONE) return nullptr; - return getBattle()->getSideHero(side.value()); + return getBattle()->getSideHero(side); } bool CBattleInfoEssentials::battleMatchOwner(const battle::Unit * attacker, const battle::Unit * defender, const boost::logic::tribool positivness) const diff --git a/lib/battle/CBattleInfoEssentials.h b/lib/battle/CBattleInfoEssentials.h index 3af7c1b50..c389bff74 100644 --- a/lib/battle/CBattleInfoEssentials.h +++ b/lib/battle/CBattleInfoEssentials.h @@ -9,6 +9,7 @@ */ #pragma once #include "IBattleInfoCallback.h" +#include "BattleSide.h" VCMI_LIB_NAMESPACE_BEGIN @@ -22,21 +23,10 @@ class CArmedInstance; using TStacks = std::vector; using TStackFilter = std::function; -namespace BattlePerspective -{ - enum BattlePerspective - { - INVALID = -2, - ALL_KNOWING = -1, - LEFT_SIDE, - RIGHT_SIDE - }; -} - class DLL_LINKAGE CBattleInfoEssentials : public IBattleInfoCallback { protected: - bool battleDoWeKnowAbout(ui8 side) const; + bool battleDoWeKnowAbout(BattleSide side) const; public: enum EStackOwnership @@ -45,14 +35,14 @@ public: }; bool duringBattle() const; - BattlePerspective::BattlePerspective battleGetMySide() const; + BattleSide battleGetMySide() const; const IBonusBearer * getBonusBearer() const override; TerrainId battleTerrainType() const override; BattleField battleGetBattlefieldType() const override; - int32_t battleGetEnchanterCounter(ui8 side) const; + int32_t battleGetEnchanterCounter(BattleSide side) const; - std::vector> battleGetAllObstacles(std::optional perspective = std::nullopt) const; //returns all obstacles on the battlefield + std::vector> battleGetAllObstacles(std::optional perspective = std::nullopt) const; //returns all obstacles on the battlefield std::shared_ptr battleGetObstacleByID(uint32_t ID) const; @@ -70,27 +60,27 @@ public: uint32_t battleNextUnitId() const override; - bool battleHasNativeStack(ui8 side) const; + bool battleHasNativeStack(BattleSide side) const; const CGTownInstance * battleGetDefendedTown() const; //returns defended town if current battle is a siege, nullptr instead si8 battleTacticDist() const override; //returns tactic distance in current tactics phase; 0 if not in tactics phase - si8 battleGetTacticsSide() const override; //returns which side is in tactics phase, undefined if none (?) + BattleSide battleGetTacticsSide() const override; //returns which side is in tactics phase, undefined if none (?) bool battleCanFlee(const PlayerColor & player) const; bool battleCanSurrender(const PlayerColor & player) const; - ui8 otherSide(ui8 side) const; + static BattleSide otherSide(BattleSide side); PlayerColor otherPlayer(const PlayerColor & player) const; - BattleSideOpt playerToSide(const PlayerColor & player) const; - PlayerColor sideToPlayer(ui8 side) const; + BattleSide playerToSide(const PlayerColor & player) const; + PlayerColor sideToPlayer(BattleSide side) const; bool playerHasAccessToHeroInfo(const PlayerColor & player, const CGHeroInstance * h) const; ui8 battleGetSiegeLevel() const; //returns 0 when there is no siege, 1 if fort, 2 is citadel, 3 is castle - bool battleHasHero(ui8 side) const; - uint32_t battleCastSpells(ui8 side) const; //how many spells has given side cast - const CGHeroInstance * battleGetFightingHero(ui8 side) const; //deprecated for players callback, easy to get wrong - const CArmedInstance * battleGetArmyObject(ui8 side) const; - InfoAboutHero battleGetHeroInfo(ui8 side) const; + bool battleHasHero(BattleSide side) const; + uint32_t battleCastSpells(BattleSide side) const; //how many spells has given side cast + const CGHeroInstance * battleGetFightingHero(BattleSide side) const; //deprecated for players callback, easy to get wrong + const CArmedInstance * battleGetArmyObject(BattleSide side) const; + InfoAboutHero battleGetHeroInfo(BattleSide side) const; // for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall, // [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; returned value: 1 - intact, 2 - damaged, 3 - destroyed; 0 - no battle @@ -103,7 +93,7 @@ public: TStacks battleGetAllStacks(bool includeTurrets = false) const; const CStack * battleGetStackByID(int ID, bool onlyAlive = true) const; //returns stack info by given ID - bool battleIsObstacleVisibleForSide(const CObstacleInstance & coi, BattlePerspective::BattlePerspective side) const; + bool battleIsObstacleVisibleForSide(const CObstacleInstance & coi, BattleSide side) const; ///returns player that controls given stack; mind control included PlayerColor battleGetOwner(const battle::Unit * unit) const; diff --git a/lib/battle/CObstacleInstance.cpp b/lib/battle/CObstacleInstance.cpp index ae716943c..098d980a2 100644 --- a/lib/battle/CObstacleInstance.cpp +++ b/lib/battle/CObstacleInstance.cpp @@ -52,7 +52,7 @@ std::vector CObstacleInstance::getAffectedTiles() const } } -bool CObstacleInstance::visibleForSide(ui8 side, bool hasNativeStack) const +bool CObstacleInstance::visibleForSide(BattleSide side, bool hasNativeStack) const { //by default obstacle is visible for everyone return true; @@ -134,7 +134,7 @@ SpellCreatedObstacle::SpellCreatedObstacle() : turnsRemaining(-1), casterSpellPower(0), spellLevel(0), - casterSide(0), + casterSide(BattleSide::NONE), hidden(false), passable(false), trigger(false), @@ -148,7 +148,7 @@ SpellCreatedObstacle::SpellCreatedObstacle() obstacleType = SPELL_CREATED; } -bool SpellCreatedObstacle::visibleForSide(ui8 side, bool hasNativeStack) const +bool SpellCreatedObstacle::visibleForSide(BattleSide side, bool hasNativeStack) const { //we hide mines and not discovered quicksands //quicksands are visible to the caster or if owned unit stepped into that particular patch diff --git a/lib/battle/CObstacleInstance.h b/lib/battle/CObstacleInstance.h index 8499f9bb5..3ce98a202 100644 --- a/lib/battle/CObstacleInstance.h +++ b/lib/battle/CObstacleInstance.h @@ -50,7 +50,7 @@ struct DLL_LINKAGE CObstacleInstance : public Serializeable virtual SpellID getTrigger() const; virtual std::vector getAffectedTiles() const; - virtual bool visibleForSide(ui8 side, bool hasNativeStack) const; //0 attacker + virtual bool visibleForSide(BattleSide side, bool hasNativeStack) const; //0 attacker virtual void battleTurnPassed(){}; @@ -80,7 +80,7 @@ struct DLL_LINKAGE SpellCreatedObstacle : CObstacleInstance int32_t casterSpellPower; int32_t spellLevel; int32_t minimalDamage; //How many damage should it do regardless of power and level of caster - si8 casterSide; //0 - obstacle created by attacker; 1 - by defender + BattleSide casterSide; SpellID trigger; @@ -102,7 +102,7 @@ struct DLL_LINKAGE SpellCreatedObstacle : CObstacleInstance SpellCreatedObstacle(); std::vector getAffectedTiles() const override; - bool visibleForSide(ui8 side, bool hasNativeStack) const override; + bool visibleForSide(BattleSide side, bool hasNativeStack) const override; bool blocksTiles() const override; bool stopsMovement() const override; diff --git a/lib/battle/CPlayerBattleCallback.cpp b/lib/battle/CPlayerBattleCallback.cpp index c0457b89e..2de755613 100644 --- a/lib/battle/CPlayerBattleCallback.cpp +++ b/lib/battle/CPlayerBattleCallback.cpp @@ -76,7 +76,7 @@ const CGHeroInstance * CPlayerBattleCallback::battleGetMyHero() const InfoAboutHero CPlayerBattleCallback::battleGetEnemyHero() const { - return battleGetHeroInfo(!battleGetMySide()); + return battleGetHeroInfo(otherSide(battleGetMySide())); } diff --git a/lib/battle/CUnitState.cpp b/lib/battle/CUnitState.cpp index c96dc721c..e00f5925b 100644 --- a/lib/battle/CUnitState.cpp +++ b/lib/battle/CUnitState.cpp @@ -921,7 +921,7 @@ uint32_t CUnitStateDetached::unitId() const return unit->unitId(); } -ui8 CUnitStateDetached::unitSide() const +BattleSide CUnitStateDetached::unitSide() const { return unit->unitSide(); } diff --git a/lib/battle/CUnitState.h b/lib/battle/CUnitState.h index c641d1a0a..09d8dba7b 100644 --- a/lib/battle/CUnitState.h +++ b/lib/battle/CUnitState.h @@ -289,7 +289,7 @@ public: CUnitStateDetached & operator= (const CUnitState & other); uint32_t unitId() const override; - ui8 unitSide() const override; + BattleSide unitSide() const override; const CCreature * unitType() const override; PlayerColor unitOwner() const override; diff --git a/lib/battle/IBattleInfoCallback.h b/lib/battle/IBattleInfoCallback.h index b5b9ce583..ca43cb767 100644 --- a/lib/battle/IBattleInfoCallback.h +++ b/lib/battle/IBattleInfoCallback.h @@ -65,10 +65,10 @@ public: virtual BattleField battleGetBattlefieldType() const = 0; ///return none if battle is ongoing; otherwise the victorious side (0/1) or 2 if it is a draw - virtual std::optional battleIsFinished() const = 0; + virtual std::optional battleIsFinished() const = 0; virtual si8 battleTacticDist() const = 0; //returns tactic distance in current tactics phase; 0 if not in tactics phase - virtual si8 battleGetTacticsSide() const = 0; //returns which side is in tactics phase, undefined if none (?) + virtual BattleSide battleGetTacticsSide() const = 0; //returns which side is in tactics phase, undefined if none (?) virtual uint32_t battleNextUnitId() const = 0; diff --git a/lib/battle/IBattleState.h b/lib/battle/IBattleState.h index fd643c56c..6c866d449 100644 --- a/lib/battle/IBattleState.h +++ b/lib/battle/IBattleState.h @@ -55,17 +55,17 @@ public: virtual EWallState getWallState(EWallPart partOfWall) const = 0; virtual EGateState getGateState() const = 0; - virtual PlayerColor getSidePlayer(ui8 side) const = 0; - virtual const CArmedInstance * getSideArmy(ui8 side) const = 0; - virtual const CGHeroInstance * getSideHero(ui8 side) const = 0; + virtual PlayerColor getSidePlayer(BattleSide side) const = 0; + virtual const CArmedInstance * getSideArmy(BattleSide side) const = 0; + virtual const CGHeroInstance * getSideHero(BattleSide side) const = 0; /// Returns list of all spells used by specified side (and that can be learned by opposite hero) - virtual std::vector getUsedSpells(ui8 side) const = 0; + virtual std::vector getUsedSpells(BattleSide side) const = 0; - virtual uint32_t getCastSpells(ui8 side) const = 0; - virtual int32_t getEnchanterCounter(ui8 side) const = 0; + virtual uint32_t getCastSpells(BattleSide side) const = 0; + virtual int32_t getEnchanterCounter(BattleSide side) const = 0; virtual ui8 getTacticDist() const = 0; - virtual ui8 getTacticsSide() const = 0; + virtual BattleSide getTacticsSide() const = 0; virtual uint32_t nextUnitId() const = 0; diff --git a/lib/battle/IUnitInfo.h b/lib/battle/IUnitInfo.h index f91ccce2f..3185b84f1 100644 --- a/lib/battle/IUnitInfo.h +++ b/lib/battle/IUnitInfo.h @@ -11,6 +11,7 @@ #pragma once #include "../GameConstants.h" +#include "BattleSide.h" VCMI_LIB_NAMESPACE_BEGIN @@ -35,7 +36,7 @@ public: virtual int32_t unitBaseAmount() const = 0; virtual uint32_t unitId() const = 0; - virtual ui8 unitSide() const = 0; + virtual BattleSide unitSide() const = 0; virtual PlayerColor unitOwner() const = 0; virtual SlotID unitSlot() const = 0; diff --git a/lib/battle/ReachabilityInfo.cpp b/lib/battle/ReachabilityInfo.cpp index 809c3450d..c0165b7af 100644 --- a/lib/battle/ReachabilityInfo.cpp +++ b/lib/battle/ReachabilityInfo.cpp @@ -15,7 +15,7 @@ VCMI_LIB_NAMESPACE_BEGIN ReachabilityInfo::Parameters::Parameters(const battle::Unit * Stack, BattleHex StartPosition): - perspective(static_cast(Stack->unitSide())), + perspective(static_cast(Stack->unitSide())), startPosition(StartPosition), doubleWide(Stack->doubleWide()), side(Stack->unitSide()), diff --git a/lib/battle/ReachabilityInfo.h b/lib/battle/ReachabilityInfo.h index 7c872ad86..de4fe21c4 100644 --- a/lib/battle/ReachabilityInfo.h +++ b/lib/battle/ReachabilityInfo.h @@ -25,14 +25,14 @@ struct DLL_LINKAGE ReachabilityInfo struct DLL_LINKAGE Parameters { - ui8 side = 0; + BattleSide side = BattleSide::NONE; bool doubleWide = false; bool flying = false; bool ignoreKnownAccessible = false; //Ignore obstacles if it is in accessible hexes std::vector 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) BattleHex startPosition; //assumed position of stack - BattlePerspective::BattlePerspective perspective = BattlePerspective::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 Parameters() = default; Parameters(const battle::Unit * Stack, BattleHex StartPosition); diff --git a/lib/battle/Unit.cpp b/lib/battle/Unit.cpp index 3ad33e95b..51bf21d77 100644 --- a/lib/battle/Unit.cpp +++ b/lib/battle/Unit.cpp @@ -41,7 +41,7 @@ bool Unit::isTurret() const std::string Unit::getDescription() const { boost::format fmt("Unit %d of side %d"); - fmt % unitId() % unitSide(); + fmt % unitId() % static_cast(unitSide()); return fmt.str(); } @@ -58,7 +58,7 @@ std::vector Unit::getSurroundingHexes(BattleHex assumedPosition) cons return getSurroundingHexes(hex, doubleWide(), unitSide()); } -std::vector Unit::getSurroundingHexes(BattleHex position, bool twoHex, ui8 side) +std::vector Unit::getSurroundingHexes(BattleHex position, bool twoHex, BattleSide side) { std::vector hexes; if(twoHex) @@ -135,7 +135,7 @@ std::vector Unit::getHexes(BattleHex assumedPos) const return getHexes(assumedPos, doubleWide(), unitSide()); } -std::vector Unit::getHexes(BattleHex assumedPos, bool twoHex, ui8 side) +std::vector Unit::getHexes(BattleHex assumedPos, bool twoHex, BattleSide side) { std::vector hexes; hexes.push_back(assumedPos); @@ -156,7 +156,7 @@ BattleHex Unit::occupiedHex(BattleHex assumedPos) const return occupiedHex(assumedPos, doubleWide(), unitSide()); } -BattleHex Unit::occupiedHex(BattleHex assumedPos, bool twoHex, ui8 side) +BattleHex Unit::occupiedHex(BattleHex assumedPos, bool twoHex, BattleSide side) { if(twoHex) { diff --git a/lib/battle/Unit.h b/lib/battle/Unit.h index aa42fedd7..cbe585593 100644 --- a/lib/battle/Unit.h +++ b/lib/battle/Unit.h @@ -129,17 +129,17 @@ public: std::vector getSurroundingHexes(BattleHex assumedPosition = BattleHex::INVALID) const; // get six or 8 surrounding hexes depending on creature size std::vector getAttackableHexes(const Unit * attacker) const; - static std::vector getSurroundingHexes(BattleHex position, bool twoHex, ui8 side); + static std::vector getSurroundingHexes(BattleHex position, bool twoHex, BattleSide side); bool coversPos(BattleHex position) const; //checks also if unit is double-wide std::vector getHexes() const; //up to two occupied hexes, starting from front std::vector getHexes(BattleHex assumedPos) const; //up to two occupied hexes, starting from front - static std::vector getHexes(BattleHex assumedPos, bool twoHex, ui8 side); + static std::vector getHexes(BattleHex assumedPos, bool twoHex, BattleSide side); BattleHex occupiedHex() const; //returns number of occupied hex (not the position) if stack is double wide; otherwise -1 BattleHex occupiedHex(BattleHex assumedPos) const; //returns number of occupied hex (not the position) if stack is double wide and would stand on assumedPos; otherwise -1 - static BattleHex occupiedHex(BattleHex assumedPos, bool twoHex, ui8 side); + static BattleHex occupiedHex(BattleHex assumedPos, bool twoHex, BattleSide side); ///MetaStrings void addText(MetaString & text, EMetaText type, int32_t serial, const boost::logic::tribool & plural = boost::logic::indeterminate) const; @@ -166,7 +166,7 @@ public: uint32_t id = 0; TQuantity count = 0; CreatureID type; - ui8 side = 0; + BattleSide side = BattleSide::NONE; BattleHex position; bool summoned = false; diff --git a/lib/gameState/CGameState.cpp b/lib/gameState/CGameState.cpp index 19359d455..7598801b6 100644 --- a/lib/gameState/CGameState.cpp +++ b/lib/gameState/CGameState.cpp @@ -1020,7 +1020,7 @@ const BattleInfo * CGameState::getBattle(const PlayerColor & player) const return nullptr; for (const auto & battlePtr : currentBattles) - if (battlePtr->sides[0].color == player || battlePtr->sides[1].color == player) + if (battlePtr->getSide(BattleSide::ATTACKER).color == player || battlePtr->getSide(BattleSide::DEFENDER).color == player) return battlePtr.get(); return nullptr; diff --git a/lib/mapObjects/CBank.cpp b/lib/mapObjects/CBank.cpp index 552237825..8177b56af 100644 --- a/lib/mapObjects/CBank.cpp +++ b/lib/mapObjects/CBank.cpp @@ -387,7 +387,7 @@ void CBank::doVisit(const CGHeroInstance * hero) const void CBank::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const { - if (result.winner == 0) + if (result.winner == BattleSide::ATTACKER) { doVisit(hero); } diff --git a/lib/mapObjects/CGCreature.cpp b/lib/mapObjects/CGCreature.cpp index efba48004..389ce862b 100644 --- a/lib/mapObjects/CGCreature.cpp +++ b/lib/mapObjects/CGCreature.cpp @@ -480,12 +480,12 @@ void CGCreature::flee( const CGHeroInstance * h ) const void CGCreature::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const { - if(result.winner == 0) + if(result.winner == BattleSide::ATTACKER) { giveReward(hero); cb->removeObject(this, hero->getOwner()); } - else if(result.winner > 1) // draw + else if(result.winner == BattleSide::NONE) // draw { // guarded reward is lost forever on draw cb->removeObject(this, hero->getOwner()); diff --git a/lib/mapObjects/CGDwelling.cpp b/lib/mapObjects/CGDwelling.cpp index 37a717960..c810f1307 100644 --- a/lib/mapObjects/CGDwelling.cpp +++ b/lib/mapObjects/CGDwelling.cpp @@ -510,7 +510,7 @@ void CGDwelling::heroAcceptsCreatures( const CGHeroInstance *h) const void CGDwelling::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const { - if (result.winner == 0) + if (result.winner == BattleSide::ATTACKER) { onHeroVisit(hero); } diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index a4941ea37..f14e92fce 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -31,6 +31,7 @@ #include "../StartInfo.h" #include "CGTownInstance.h" #include "../entities/faction/CTownHandler.h" +#include "../battle/CBattleInfoEssentials.h" #include "../campaign/CampaignState.h" #include "../json/JsonBonus.h" #include "../pathfinder/TurnInfo.h" @@ -880,7 +881,7 @@ CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &b double necromancySkill = valOfBonuses(BonusType::UNDEAD_RAISE_PERCENTAGE) / 100.0; const ui8 necromancyLevel = valOfBonuses(BonusType::IMPROVED_NECROMANCY); vstd::amin(necromancySkill, 1.0); //it's impossible to raise more creatures than all... - const std::map &casualties = battleResult.casualties[!battleResult.winner]; + const std::map &casualties = battleResult.casualties[CBattleInfoEssentials::otherSide(battleResult.winner)]; // figure out what to raise - pick strongest creature meeting requirements CreatureID creatureTypeRaised = CreatureID::NONE; //now we always have IMPROVED_NECROMANCY, no need for hardcode int requiredCasualtyLevel = 1; diff --git a/lib/mapObjects/CGPandoraBox.cpp b/lib/mapObjects/CGPandoraBox.cpp index c9ede1335..8e931cf90 100644 --- a/lib/mapObjects/CGPandoraBox.cpp +++ b/lib/mapObjects/CGPandoraBox.cpp @@ -180,7 +180,7 @@ void CGPandoraBox::onHeroVisit(const CGHeroInstance * h) const void CGPandoraBox::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const { - if(result.winner == 0) + if(result.winner == BattleSide::ATTACKER) { CRewardableObject::onHeroVisit(hero); } diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index 95059c339..8c01200c3 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -205,7 +205,7 @@ ui32 CGMine::getProducedQuantity() const void CGMine::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const { - if(result.winner == 0) //attacker won + if(result.winner == BattleSide::ATTACKER) //attacker won { if(isAbandoned()) { @@ -344,7 +344,7 @@ void CGResource::collectRes(const PlayerColor & player) const void CGResource::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const { - if(result.winner == 0) //attacker won + if(result.winner == BattleSide::ATTACKER) //attacker won collectRes(hero->getOwner()); } @@ -911,7 +911,7 @@ BattleField CGArtifact::getBattlefield() const void CGArtifact::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const { - if(result.winner == 0) //attacker won + if(result.winner == BattleSide::ATTACKER) //attacker won pick(hero); } @@ -1010,7 +1010,7 @@ bool CGGarrison::passableFor(PlayerColor player) const void CGGarrison::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const { - if (result.winner == 0) + if (result.winner == BattleSide::ATTACKER) onHeroVisit(hero); } diff --git a/lib/networkPacks/NetPacksLib.cpp b/lib/networkPacks/NetPacksLib.cpp index 2cb873835..b6cd10376 100644 --- a/lib/networkPacks/NetPacksLib.cpp +++ b/lib/networkPacks/NetPacksLib.cpp @@ -2114,7 +2114,7 @@ void BattleResultAccepted::applyGs(CGameState * gs) const res.hero->removeBonusesRecursive(Bonus::OneBattle); } - if(winnerSide != 2) + if(winnerSide != BattleSide::NONE) { // Grow up growing artifacts const auto hero = heroResult[winnerSide].hero; @@ -2135,10 +2135,10 @@ void BattleResultAccepted::applyGs(CGameState * gs) const if(VLC->settings()->getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE)) { - if(heroResult[0].army) - heroResult[0].army->giveStackExp(heroResult[0].exp); - if(heroResult[1].army) - heroResult[1].army->giveStackExp(heroResult[1].exp); + if(heroResult[BattleSide::ATTACKER].army) + heroResult[BattleSide::ATTACKER].army->giveStackExp(heroResult[BattleSide::ATTACKER].exp); + if(heroResult[BattleSide::DEFENDER].army) + heroResult[BattleSide::DEFENDER].army->giveStackExp(heroResult[BattleSide::DEFENDER].exp); CBonusSystemNode::treeHasChanged(); } @@ -2242,19 +2242,14 @@ void StartAction::applyGs(CGameState *gs) else { if(ba.actionType == EActionType::HERO_SPELL) - gs->getBattle(battleID)->sides[ba.side].usedSpellsHistory.push_back(ba.spell); + gs->getBattle(battleID)->getSide(ba.side).usedSpellsHistory.push_back(ba.spell); } } void BattleSpellCast::applyGs(CGameState * gs) const { - if(castByHero) - { - if(side < 2) - { - gs->getBattle(battleID)->sides[side].castSpellsCount++; - } - } + if(castByHero && side != BattleSide::NONE) + gs->getBattle(battleID)->getSide(side).castSpellsCount++; } void SetStackEffect::applyGs(CGameState *gs) @@ -2388,7 +2383,7 @@ void BattleSetStackProperty::applyGs(CGameState * gs) const } case ENCHANTER_COUNTER: { - auto & counter = gs->getBattle(battleID)->sides[gs->getBattle(battleID)->whatSide(stack->unitOwner())].enchanterCounter; + auto & counter = gs->getBattle(battleID)->getSide(gs->getBattle(battleID)->whatSide(stack->unitOwner())).enchanterCounter; if(absolute) counter = val; else diff --git a/lib/networkPacks/PacksForClientBattle.h b/lib/networkPacks/PacksForClientBattle.h index b9d498794..db3aaa3ed 100644 --- a/lib/networkPacks/PacksForClientBattle.h +++ b/lib/networkPacks/PacksForClientBattle.h @@ -109,8 +109,8 @@ struct DLL_LINKAGE BattleResultAccepted : public CPackForClient }; BattleID battleID = BattleID::NONE; - std::array heroResult; - ui8 winnerSide; + BattleSideArray heroResult; + BattleSide winnerSide; template void serialize(Handler & h) { @@ -127,9 +127,9 @@ struct DLL_LINKAGE BattleResult : public Query BattleID battleID = BattleID::NONE; EBattleResult result = EBattleResult::NORMAL; - ui8 winner = 2; //0 - attacker, 1 - defender, [2 - draw (should be possible?)] - std::map casualties[2]; //first => casualties of attackers - map crid => number - TExpType exp[2] = {0, 0}; //exp for attacker and defender + BattleSide winner = BattleSide::NONE; //0 - attacker, 1 - defender, [2 - draw (should be possible?)] + BattleSideArray> casualties; //first => casualties of attackers - map crid => number + BattleSideArray exp{0,0}; //exp for attacker and defender std::set artifacts; //artifacts taken from loser to winner - currently unused void visitTyped(ICPackVisitor & visitor) override; @@ -140,8 +140,7 @@ struct DLL_LINKAGE BattleResult : public Query h & queryID; h & result; h & winner; - h & casualties[0]; - h & casualties[1]; + h & casualties; h & exp; h & artifacts; assert(battleID != BattleID::NONE); @@ -369,7 +368,7 @@ struct DLL_LINKAGE BattleSpellCast : public CPackForClient BattleID battleID = BattleID::NONE; bool activeCast = true; - ui8 side = 0; //which hero did cast spell: 0 - attacker, 1 - defender + BattleSide side = BattleSide::NONE; //which hero did cast spell SpellID spellID; //id of spell ui8 manaGained = 0; //mana channeling ability BattleHex tile; //destination tile (may not be set in some global/mass spells diff --git a/lib/spells/BattleSpellMechanics.cpp b/lib/spells/BattleSpellMechanics.cpp index 5ba490138..62954d66b 100644 --- a/lib/spells/BattleSpellMechanics.cpp +++ b/lib/spells/BattleSpellMechanics.cpp @@ -193,16 +193,16 @@ bool BattleSpellMechanics::canBeCast(Problem & problem) const return adaptProblem(ESpellCastProblem::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL, problem); const PlayerColor player = caster->getCasterOwner(); - const auto side = battle()->playerToSide(player); + const BattleSide side = battle()->playerToSide(player); - if(!side) + if(side == BattleSide::NONE) return adaptProblem(ESpellCastProblem::INVALID, problem); //effect like Recanter's Cloak. Blocks also passive casting. //TODO: check creature abilities to block //TODO: check any possible caster - if(battle()->battleMaxSpellLevel(side.value()) < getSpellLevel() || battle()->battleMinSpellLevel(side.value()) > getSpellLevel()) + if(battle()->battleMaxSpellLevel(side) < getSpellLevel() || battle()->battleMinSpellLevel(side) > getSpellLevel()) return adaptProblem(ESpellCastProblem::SPELL_LEVEL_LIMIT_EXCEEDED, problem); return effects->applicable(problem, this); @@ -284,7 +284,7 @@ void BattleSpellMechanics::cast(ServerCallback * server, const Target & target) const CGHeroInstance * otherHero = nullptr; { //check it there is opponent hero - const ui8 otherSide = battle()->otherSide(casterSide); + const BattleSide otherSide = battle()->otherSide(casterSide); if(battle()->battleHasHero(otherSide)) otherHero = battle()->battleGetFightingHero(otherSide); diff --git a/lib/spells/ISpellMechanics.cpp b/lib/spells/ISpellMechanics.cpp index 8a1593a73..a1488e1e8 100644 --- a/lib/spells/ISpellMechanics.cpp +++ b/lib/spells/ISpellMechanics.cpp @@ -397,7 +397,7 @@ std::unique_ptr ISpellMechanicsFactory::get(const CSpell ///Mechanics Mechanics::Mechanics() : caster(nullptr), - casterSide(0) + casterSide(BattleSide::NONE) { } @@ -413,8 +413,7 @@ BaseMechanics::BaseMechanics(const IBattleCast * event): { caster = event->getCaster(); - //FIXME: do not crash on invalid side - casterSide = cb->playerToSide(caster->getCasterOwner()).value(); + casterSide = cb->playerToSide(caster->getCasterOwner()); { auto value = event->getSpellLevel(); diff --git a/lib/spells/ISpellMechanics.h b/lib/spells/ISpellMechanics.h index ea150497d..35fedbf72 100644 --- a/lib/spells/ISpellMechanics.h +++ b/lib/spells/ISpellMechanics.h @@ -252,7 +252,7 @@ public: const Caster * caster; - ui8 casterSide; + BattleSide casterSide; protected: Mechanics(); diff --git a/lib/spells/effects/Moat.cpp b/lib/spells/effects/Moat.cpp index ddcef5f5a..653e146e9 100644 --- a/lib/spells/effects/Moat.cpp +++ b/lib/spells/effects/Moat.cpp @@ -134,7 +134,7 @@ void Moat::placeObstacles(ServerCallback * server, const Mechanics * m, const Ef BattleObstaclesChanged pack; pack.battleID = m->battle()->getBattle()->getBattleID(); - auto all = m->battle()->battleGetAllObstacles(BattlePerspective::ALL_KNOWING); + auto all = m->battle()->battleGetAllObstacles(BattleSide::ALL_KNOWING); int obstacleIdToGive = 1; for(auto & one : all) diff --git a/lib/spells/effects/Obstacle.cpp b/lib/spells/effects/Obstacle.cpp index e75052684..8359e3e0d 100644 --- a/lib/spells/effects/Obstacle.cpp +++ b/lib/spells/effects/Obstacle.cpp @@ -274,7 +274,7 @@ void Obstacle::placeObstacles(ServerCallback * server, const Mechanics * m, cons BattleObstaclesChanged pack; pack.battleID = m->battle()->getBattle()->getBattleID(); - auto all = m->battle()->battleGetAllObstacles(BattlePerspective::ALL_KNOWING); + auto all = m->battle()->battleGetAllObstacles(BattleSide::ALL_KNOWING); int obstacleIdToGive = 1; for(auto & one : all) diff --git a/lib/spells/effects/Obstacle.h b/lib/spells/effects/Obstacle.h index 1dd256e1a..b6410aed4 100644 --- a/lib/spells/effects/Obstacle.h +++ b/lib/spells/effects/Obstacle.h @@ -66,7 +66,7 @@ private: bool passable = false; int32_t turnsRemaining = -1; - std::array sideOptions; + BattleSideArray sideOptions; static bool isHexAvailable(const CBattleInfoCallback * cb, const BattleHex & hex, const bool mustBeClear); static bool noRoomToPlace(Problem & problem, const Mechanics * m); diff --git a/lib/spells/effects/RemoveObstacle.cpp b/lib/spells/effects/RemoveObstacle.cpp index f24b0e881..58e462c69 100644 --- a/lib/spells/effects/RemoveObstacle.cpp +++ b/lib/spells/effects/RemoveObstacle.cpp @@ -90,7 +90,7 @@ std::set RemoveObstacle::getTargets(const Mechanics * std::set possibleTargets; if(m->isMassive() || alwaysMassive) { - for(const auto & obstacle : m->battle()->battleGetAllObstacles(BattlePerspective::ALL_KNOWING)) + for(const auto & obstacle : m->battle()->battleGetAllObstacles(BattleSide::ALL_KNOWING)) if(canRemove(obstacle.get())) possibleTargets.insert(obstacle.get()); } diff --git a/server/TurnTimerHandler.cpp b/server/TurnTimerHandler.cpp index b8dd196ed..a694e1df6 100644 --- a/server/TurnTimerHandler.cpp +++ b/server/TurnTimerHandler.cpp @@ -256,7 +256,7 @@ void TurnTimerHandler::onBattleLoop(const BattleID & battleID, int waitTime) if (!si->turnTimerInfo.isBattleEnabled()) return; - ui8 side = 0; + BattleSide side = BattleSide::NONE; const CStack * stack = nullptr; bool isTactisPhase = gs->getBattle(battleID)->battleTacticDist() > 0; diff --git a/server/battles/BattleActionProcessor.cpp b/server/battles/BattleActionProcessor.cpp index 945ee960c..3e115d36f 100644 --- a/server/battles/BattleActionProcessor.cpp +++ b/server/battles/BattleActionProcessor.cpp @@ -65,7 +65,7 @@ bool BattleActionProcessor::doRetreatAction(const CBattleInfoCallback & battle, return false; } - owner->setBattleResult(battle, EBattleResult::ESCAPE, !ba.side); + owner->setBattleResult(battle, EBattleResult::ESCAPE, battle.otherSide(ba.side)); return true; } @@ -86,7 +86,7 @@ bool BattleActionProcessor::doSurrenderAction(const CBattleInfoCallback & battle } gameHandler->giveResource(player, EGameResID::GOLD, -cost); - owner->setBattleResult(battle, EBattleResult::SURRENDER, !ba.side); + owner->setBattleResult(battle, EBattleResult::SURRENDER, battle.otherSide(ba.side)); return true; } @@ -1574,7 +1574,7 @@ bool BattleActionProcessor::makeAutomaticBattleAction(const CBattleInfoCallback bool BattleActionProcessor::makePlayerBattleAction(const CBattleInfoCallback & battle, PlayerColor player, const BattleAction &ba) { - if (ba.side != 0 && ba.side != 1 && gameHandler->complain("Can not make action - invalid battle side!")) + if (ba.side != BattleSide::ATTACKER && ba.side != BattleSide::DEFENDER && gameHandler->complain("Can not make action - invalid battle side!")) return false; if(battle.battleGetTacticDist() != 0) diff --git a/server/battles/BattleFlowProcessor.cpp b/server/battles/BattleFlowProcessor.cpp index e16da4ba3..c4c1235db 100644 --- a/server/battles/BattleFlowProcessor.cpp +++ b/server/battles/BattleFlowProcessor.cpp @@ -34,7 +34,7 @@ BattleFlowProcessor::BattleFlowProcessor(BattleProcessor * owner, CGameHandler * { } -void BattleFlowProcessor::summonGuardiansHelper(const CBattleInfoCallback & battle, std::vector & output, const BattleHex & targetPosition, ui8 side, bool targetIsTwoHex) //return hexes for summoning two hex monsters in output, target = unit to guard +void BattleFlowProcessor::summonGuardiansHelper(const CBattleInfoCallback & battle, std::vector & output, const BattleHex & targetPosition, BattleSide side, bool targetIsTwoHex) //return hexes for summoning two hex monsters in output, target = unit to guard { int x = targetPosition.getX(); int y = targetPosition.getY(); @@ -185,7 +185,7 @@ void BattleFlowProcessor::trySummonGuardians(const CBattleInfoCallback & battle, void BattleFlowProcessor::castOpeningSpells(const CBattleInfoCallback & battle) { - for (int i = 0; i < 2; ++i) + for(auto i : {BattleSide::ATTACKER, BattleSide::DEFENDER}) { auto h = battle.battleGetFightingHero(i); if (!h) @@ -742,7 +742,7 @@ void BattleFlowProcessor::stackTurnTrigger(const CBattleInfoCallback & battle, c return b->subtype.as() == SpellID::NONE; }); - int side = *battle.playerToSide(st->unitOwner()); + BattleSide side = battle.playerToSide(st->unitOwner()); if(st->canCast() && battle.battleGetEnchanterCounter(side) == 0) { bool cast = false; diff --git a/server/battles/BattleFlowProcessor.h b/server/battles/BattleFlowProcessor.h index e781b0a75..70ef29249 100644 --- a/server/battles/BattleFlowProcessor.h +++ b/server/battles/BattleFlowProcessor.h @@ -9,6 +9,8 @@ */ #pragma once +#include "../lib/battle/BattleSide.h" + VCMI_LIB_NAMESPACE_BEGIN class CStack; struct BattleHex; @@ -35,7 +37,7 @@ class BattleFlowProcessor : boost::noncopyable bool rollGoodMorale(const CBattleInfoCallback & battle, const CStack * stack); bool tryMakeAutomaticAction(const CBattleInfoCallback & battle, const CStack * stack); - void summonGuardiansHelper(const CBattleInfoCallback & battle, std::vector & output, const BattleHex & targetPosition, ui8 side, bool targetIsTwoHex); + void summonGuardiansHelper(const CBattleInfoCallback & battle, std::vector & output, const BattleHex & targetPosition, BattleSide side, bool targetIsTwoHex); void trySummonGuardians(const CBattleInfoCallback & battle, const CStack * stack); void tryPlaceMoats(const CBattleInfoCallback & battle); void castOpeningSpells(const CBattleInfoCallback & battle); diff --git a/server/battles/BattleProcessor.cpp b/server/battles/BattleProcessor.cpp index 14f359397..660e9d317 100644 --- a/server/battles/BattleProcessor.cpp +++ b/server/battles/BattleProcessor.cpp @@ -57,20 +57,18 @@ void BattleProcessor::restartBattlePrimary(const BattleID & battleID, const CArm { auto battle = gameHandler->gameState()->getBattle(battleID); - auto lastBattleQuery = std::dynamic_pointer_cast(gameHandler->queries->topQuery(battle->sides[0].color)); + auto lastBattleQuery = std::dynamic_pointer_cast(gameHandler->queries->topQuery(battle->getSide(BattleSide::ATTACKER).color)); if(!lastBattleQuery) - lastBattleQuery = std::dynamic_pointer_cast(gameHandler->queries->topQuery(battle->sides[1].color)); + lastBattleQuery = std::dynamic_pointer_cast(gameHandler->queries->topQuery(battle->getSide(BattleSide::DEFENDER).color)); assert(lastBattleQuery); //existing battle query for retying auto-combat if(lastBattleQuery) { - const CGHeroInstance*heroes[2]; - heroes[0] = hero1; - heroes[1] = hero2; + BattleSideArray heroes{hero1, hero2}; - for(int i : {0, 1}) + for(auto i : {BattleSide::ATTACKER, BattleSide::DEFENDER}) { if(heroes[i]) { @@ -83,8 +81,8 @@ void BattleProcessor::restartBattlePrimary(const BattleID & battleID, const CArm lastBattleQuery->result = std::nullopt; - assert(lastBattleQuery->belligerents[0] == battle->sides[0].armyObject); - assert(lastBattleQuery->belligerents[1] == battle->sides[1].armyObject); + assert(lastBattleQuery->belligerents[BattleSide::ATTACKER] == battle->getSide(BattleSide::ATTACKER).armyObject); + assert(lastBattleQuery->belligerents[BattleSide::DEFENDER] == battle->getSide(BattleSide::DEFENDER).armyObject); } BattleCancelled bc; @@ -101,12 +99,8 @@ void BattleProcessor::startBattlePrimary(const CArmedInstance *army1, const CArm assert(gameHandler->gameState()->getBattle(army1->getOwner()) == nullptr); assert(gameHandler->gameState()->getBattle(army2->getOwner()) == nullptr); - const CArmedInstance *armies[2]; - armies[0] = army1; - armies[1] = army2; - const CGHeroInstance*heroes[2]; - heroes[0] = hero1; - heroes[1] = hero2; + BattleSideArray armies{army1, army2}; + BattleSideArrayheroes{hero1, hero2}; auto battleID = setupBattle(tile, armies, heroes, creatureBank, town); //initializes stacks, places creatures on battlefield, blocks and informs player interfaces @@ -126,9 +120,9 @@ void BattleProcessor::startBattlePrimary(const CArmedInstance *army1, const CArm } } - auto lastBattleQuery = std::dynamic_pointer_cast(gameHandler->queries->topQuery(battle->sides[0].color)); + auto lastBattleQuery = std::dynamic_pointer_cast(gameHandler->queries->topQuery(battle->getSide(BattleSide::ATTACKER).color)); if(!lastBattleQuery) - lastBattleQuery = std::dynamic_pointer_cast(gameHandler->queries->topQuery(battle->sides[1].color)); + lastBattleQuery = std::dynamic_pointer_cast(gameHandler->queries->topQuery(battle->getSide(BattleSide::DEFENDER).color)); if (lastBattleQuery) { @@ -139,7 +133,7 @@ void BattleProcessor::startBattlePrimary(const CArmedInstance *army1, const CArm auto newBattleQuery = std::make_shared(gameHandler, battle); // store initial mana to reset if battle has been restarted - for(int i : {0, 1}) + for(auto i : {BattleSide::ATTACKER, BattleSide::DEFENDER}) if(heroes[i]) newBattleQuery->initialHeroMana[i] = heroes[i]->mana; @@ -162,7 +156,7 @@ void BattleProcessor::startBattleI(const CArmedInstance *army1, const CArmedInst startBattleI(army1, army2, army2->visitablePos(), creatureBank); } -BattleID BattleProcessor::setupBattle(int3 tile, const CArmedInstance *armies[2], const CGHeroInstance *heroes[2], bool creatureBank, const CGTownInstance *town) +BattleID BattleProcessor::setupBattle(int3 tile, BattleSideArray armies, BattleSideArray heroes, bool creatureBank, const CGTownInstance *town) { const auto & t = *gameHandler->getTile(tile); TerrainId terrain = t.terType->getId(); @@ -170,7 +164,7 @@ BattleID BattleProcessor::setupBattle(int3 tile, const CArmedInstance *armies[2] terrain = ETerrainId::SAND; BattleField terType = gameHandler->gameState()->battleGetBattlefieldType(tile, gameHandler->getRandomGenerator()); - if (heroes[0] && heroes[0]->boat && heroes[1] && heroes[1]->boat) + if (heroes[BattleSide::ATTACKER] && heroes[BattleSide::ATTACKER]->boat && heroes[BattleSide::DEFENDER] && heroes[BattleSide::DEFENDER]->boat) terType = BattleField(*VLC->identifiers()->getIdentifier("core", "battlefield.ship_to_ship")); //send info about battles @@ -178,14 +172,14 @@ BattleID BattleProcessor::setupBattle(int3 tile, const CArmedInstance *armies[2] bs.info = BattleInfo::setupBattle(tile, terrain, terType, armies, heroes, creatureBank, town); bs.battleID = gameHandler->gameState()->nextBattleID; - engageIntoBattle(bs.info->sides[0].color); - engageIntoBattle(bs.info->sides[1].color); + engageIntoBattle(bs.info->getSide(BattleSide::ATTACKER).color); + engageIntoBattle(bs.info->getSide(BattleSide::DEFENDER).color); - auto lastBattleQuery = std::dynamic_pointer_cast(gameHandler->queries->topQuery(bs.info->sides[0].color)); + auto lastBattleQuery = std::dynamic_pointer_cast(gameHandler->queries->topQuery(bs.info->getSide(BattleSide::ATTACKER).color)); if(!lastBattleQuery) - lastBattleQuery = std::dynamic_pointer_cast(gameHandler->queries->topQuery(bs.info->sides[1].color)); - bool isDefenderHuman = bs.info->sides[1].color.isValidPlayer() && gameHandler->getPlayerState(bs.info->sides[1].color)->isHuman(); - bool isAttackerHuman = gameHandler->getPlayerState(bs.info->sides[0].color)->isHuman(); + lastBattleQuery = std::dynamic_pointer_cast(gameHandler->queries->topQuery(bs.info->getSide(BattleSide::DEFENDER).color)); + bool isDefenderHuman = bs.info->getSide(BattleSide::DEFENDER).color.isValidPlayer() && gameHandler->getPlayerState(bs.info->getSide(BattleSide::DEFENDER).color)->isHuman(); + bool isAttackerHuman = gameHandler->getPlayerState(bs.info->getSide(BattleSide::ATTACKER).color)->isHuman(); bool onlyOnePlayerHuman = isDefenderHuman != isAttackerHuman; bs.info->replayAllowed = lastBattleQuery == nullptr && onlyOnePlayerHuman; @@ -284,7 +278,7 @@ bool BattleProcessor::makePlayerBattleAction(const BattleID & battleID, PlayerCo return result; } -void BattleProcessor::setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, int victoriusSide) +void BattleProcessor::setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, BattleSide victoriusSide) { resultProcessor->setBattleResult(battle, resultType, victoriusSide); resultProcessor->endBattle(battle); diff --git a/server/battles/BattleProcessor.h b/server/battles/BattleProcessor.h index e284def89..c21dd6a66 100644 --- a/server/battles/BattleProcessor.h +++ b/server/battles/BattleProcessor.h @@ -10,6 +10,7 @@ #pragma once #include "../../lib/GameConstants.h" +#include "../../lib/battle/BattleSide.h" VCMI_LIB_NAMESPACE_BEGIN class CGHeroInstance; @@ -44,11 +45,11 @@ class BattleProcessor : boost::noncopyable void engageIntoBattle(PlayerColor player); bool checkBattleStateChanges(const CBattleInfoCallback & battle); - BattleID setupBattle(int3 tile, const CArmedInstance *armies[2], const CGHeroInstance *heroes[2], bool creatureBank, const CGTownInstance *town); + BattleID setupBattle(int3 tile, BattleSideArray armies, BattleSideArray heroes, bool creatureBank, const CGTownInstance *town); bool makeAutomaticBattleAction(const CBattleInfoCallback & battle, const BattleAction & ba); - void setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, int victoriusSide); + void setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, BattleSide victoriusSide); public: explicit BattleProcessor(CGameHandler * gameHandler); diff --git a/server/battles/BattleResultProcessor.cpp b/server/battles/BattleResultProcessor.cpp index 46d5f3954..7b39a870e 100644 --- a/server/battles/BattleResultProcessor.cpp +++ b/server/battles/BattleResultProcessor.cpp @@ -38,7 +38,7 @@ BattleResultProcessor::BattleResultProcessor(BattleProcessor * owner, CGameHandl { } -CasualtiesAfterBattle::CasualtiesAfterBattle(const CBattleInfoCallback & battle, uint8_t sideInBattle): +CasualtiesAfterBattle::CasualtiesAfterBattle(const CBattleInfoCallback & battle, BattleSide sideInBattle): army(battle.battleGetArmyObject(sideInBattle)) { heroWithDeadCommander = ObjectInstanceID(); @@ -205,25 +205,18 @@ FinishingBattleHelper::FinishingBattleHelper(const CBattleInfoCallback & info, c this->remainingBattleQueriesCount = remainingBattleQueriesCount; } -//FinishingBattleHelper::FinishingBattleHelper() -//{ -// winnerHero = loserHero = nullptr; -// winnerSide = 0; -// remainingBattleQueriesCount = 0; -//} - void BattleResultProcessor::endBattle(const CBattleInfoCallback & battle) { - auto const & giveExp = [](BattleResult &r) + auto const & giveExp = [&battle](BattleResult &r) { - if (r.winner > 1) + if (r.winner == BattleSide::NONE) { // draw return; } - r.exp[0] = 0; - r.exp[1] = 0; - for (auto i = r.casualties[!r.winner].begin(); i!=r.casualties[!r.winner].end(); i++) + r.exp[BattleSide::ATTACKER] = 0; + r.exp[BattleSide::DEFENDER] = 0; + for (auto i = r.casualties[battle.otherSide(r.winner)].begin(); i!=r.casualties[battle.otherSide(r.winner)].end(); i++) { r.exp[r.winner] += VLC->creh->objects.at(i->first)->valOfBonuses(BonusType::STACK_HEALTH) * i->second; } @@ -241,9 +234,9 @@ void BattleResultProcessor::endBattle(const CBattleInfoCallback & battle) if (battleResult->result == EBattleResult::NORMAL) // give 500 exp for defeating hero, unless he escaped { if(heroAttacker) - battleResult->exp[1] += 500; + battleResult->exp[BattleSide::DEFENDER] += 500; if(heroDefender) - battleResult->exp[0] += 500; + battleResult->exp[BattleSide::ATTACKER] += 500; } // Give 500 exp to winner if a town was conquered during the battle @@ -252,17 +245,17 @@ void BattleResultProcessor::endBattle(const CBattleInfoCallback & battle) battleResult->exp[BattleSide::ATTACKER] += 500; if(heroAttacker) - battleResult->exp[0] = heroAttacker->calculateXp(battleResult->exp[0]);//scholar skill + battleResult->exp[BattleSide::ATTACKER] = heroAttacker->calculateXp(battleResult->exp[BattleSide::ATTACKER]);//scholar skill if(heroDefender) - battleResult->exp[1] = heroDefender->calculateXp(battleResult->exp[1]); + battleResult->exp[BattleSide::DEFENDER] = heroDefender->calculateXp(battleResult->exp[BattleSide::DEFENDER]); - auto battleQuery = std::dynamic_pointer_cast(gameHandler->queries->topQuery(battle.sideToPlayer(0))); + auto battleQuery = std::dynamic_pointer_cast(gameHandler->queries->topQuery(battle.sideToPlayer(BattleSide::ATTACKER))); if(!battleQuery) - battleQuery = std::dynamic_pointer_cast(gameHandler->queries->topQuery(battle.sideToPlayer(1))); + battleQuery = std::dynamic_pointer_cast(gameHandler->queries->topQuery(battle.sideToPlayer(BattleSide::DEFENDER))); if (!battleQuery) { logGlobal->error("Cannot find battle query!"); - gameHandler->complain("Player " + boost::lexical_cast(battle.sideToPlayer(0)) + " has no battle query at the top!"); + gameHandler->complain("Player " + boost::lexical_cast(battle.sideToPlayer(BattleSide::ATTACKER)) + " has no battle query at the top!"); return; } @@ -307,9 +300,9 @@ void BattleResultProcessor::endBattle(const CBattleInfoCallback & battle) void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle) { - auto battleQuery = std::dynamic_pointer_cast(gameHandler->queries->topQuery(battle.sideToPlayer(0))); + auto battleQuery = std::dynamic_pointer_cast(gameHandler->queries->topQuery(battle.sideToPlayer(BattleSide::ATTACKER))); if(!battleQuery) - battleQuery = std::dynamic_pointer_cast(gameHandler->queries->topQuery(battle.sideToPlayer(1))); + battleQuery = std::dynamic_pointer_cast(gameHandler->queries->topQuery(battle.sideToPlayer(BattleSide::DEFENDER))); if(!battleQuery) { logGlobal->trace("No battle query, battle end was confirmed by another player"); @@ -498,29 +491,29 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle) } // add statistic - if(battle.sideToPlayer(0) == PlayerColor::NEUTRAL || battle.sideToPlayer(1) == PlayerColor::NEUTRAL) + if(battle.sideToPlayer(BattleSide::ATTACKER) == PlayerColor::NEUTRAL || battle.sideToPlayer(BattleSide::DEFENDER) == PlayerColor::NEUTRAL) { - gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(0)].numBattlesNeutral++; - gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(1)].numBattlesNeutral++; + gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(BattleSide::ATTACKER)].numBattlesNeutral++; + gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(BattleSide::DEFENDER)].numBattlesNeutral++; if(!finishingBattle->isDraw()) gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(finishingBattle->winnerSide)].numWinBattlesNeutral++; } else { - gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(0)].numBattlesPlayer++; - gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(1)].numBattlesPlayer++; + gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(BattleSide::ATTACKER)].numBattlesPlayer++; + gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(BattleSide::DEFENDER)].numBattlesPlayer++; if(!finishingBattle->isDraw()) gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(finishingBattle->winnerSide)].numWinBattlesPlayer++; } BattleResultAccepted raccepted; raccepted.battleID = battle.getBattle()->getBattleID(); - raccepted.heroResult[0].army = const_cast(battle.battleGetArmyObject(BattleSide::ATTACKER)); - raccepted.heroResult[1].army = const_cast(battle.battleGetArmyObject(BattleSide::DEFENDER)); - raccepted.heroResult[0].hero = const_cast(battle.battleGetFightingHero(BattleSide::ATTACKER)); - raccepted.heroResult[1].hero = const_cast(battle.battleGetFightingHero(BattleSide::DEFENDER)); - raccepted.heroResult[0].exp = battleResult->exp[0]; - raccepted.heroResult[1].exp = battleResult->exp[1]; + raccepted.heroResult[BattleSide::ATTACKER].army = const_cast(battle.battleGetArmyObject(BattleSide::ATTACKER)); + raccepted.heroResult[BattleSide::DEFENDER].army = const_cast(battle.battleGetArmyObject(BattleSide::DEFENDER)); + raccepted.heroResult[BattleSide::ATTACKER].hero = const_cast(battle.battleGetFightingHero(BattleSide::ATTACKER)); + raccepted.heroResult[BattleSide::DEFENDER].hero = const_cast(battle.battleGetFightingHero(BattleSide::DEFENDER)); + raccepted.heroResult[BattleSide::ATTACKER].exp = battleResult->exp[BattleSide::ATTACKER]; + raccepted.heroResult[BattleSide::DEFENDER].exp = battleResult->exp[BattleSide::DEFENDER]; raccepted.winnerSide = finishingBattle->winnerSide; gameHandler->sendAndApply(&raccepted); @@ -583,7 +576,7 @@ void BattleResultProcessor::battleAfterLevelUp(const BattleID & battleID, const gameHandler->heroPool->onHeroEscaped(finishingBattle->loser, finishingBattle->loserHero); } - if (result.winner != 2 && finishingBattle->winnerHero && finishingBattle->winnerHero->stacks.empty() + if (result.winner != BattleSide::NONE && finishingBattle->winnerHero && finishingBattle->winnerHero->stacks.empty() && (!finishingBattle->winnerHero->commander || !finishingBattle->winnerHero->commander->alive)) { RemoveObject ro(finishingBattle->winnerHero->id, finishingBattle->winnerHero->getOwner()); @@ -597,7 +590,7 @@ void BattleResultProcessor::battleAfterLevelUp(const BattleID & battleID, const battleResults.erase(battleID); } -void BattleResultProcessor::setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, int victoriusSide) +void BattleResultProcessor::setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, BattleSide victoriusSide) { assert(battleResults.count(battle.getBattle()->getBattleID()) == 0); diff --git a/server/battles/BattleResultProcessor.h b/server/battles/BattleResultProcessor.h index f82f18fba..2e5e73bd1 100644 --- a/server/battles/BattleResultProcessor.h +++ b/server/battles/BattleResultProcessor.h @@ -12,6 +12,7 @@ #include "../../lib/GameConstants.h" #include "../../lib/networkPacks/StackLocation.h" #include "../../lib/networkPacks/ArtifactLocation.h" +#include "../../lib/battle/BattleSide.h" VCMI_LIB_NAMESPACE_BEGIN struct SideInBattle; @@ -34,7 +35,7 @@ struct CasualtiesAfterBattle TSummoned summoned; ObjectInstanceID heroWithDeadCommander; //TODO: unify stack locations - CasualtiesAfterBattle(const CBattleInfoCallback & battle, uint8_t sideInBattle); + CasualtiesAfterBattle(const CBattleInfoCallback & battle, BattleSide sideInBattle); void updateArmy(CGameHandler * gh); }; @@ -42,11 +43,11 @@ struct FinishingBattleHelper { FinishingBattleHelper(const CBattleInfoCallback & battle, const BattleResult & result, int RemainingBattleQueriesCount); - inline bool isDraw() const {return winnerSide == 2;} + inline bool isDraw() const {return winnerSide == BattleSide::NONE;} const CGHeroInstance *winnerHero, *loserHero; PlayerColor victor, loser; - ui8 winnerSide; + BattleSide winnerSide; int remainingBattleQueriesCount; @@ -74,7 +75,7 @@ public: bool battleIsEnding(const CBattleInfoCallback & battle) const; - void setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, int victoriusSide); + void setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, BattleSide victoriusSide); void endBattle(const CBattleInfoCallback & battle); //ends battle void endBattleConfirm(const CBattleInfoCallback & battle); void battleAfterLevelUp(const BattleID & battleID, const BattleResult & result); diff --git a/server/queries/BattleQueries.cpp b/server/queries/BattleQueries.cpp index 485f1f9fa..4fc0c25f0 100644 --- a/server/queries/BattleQueries.cpp +++ b/server/queries/BattleQueries.cpp @@ -35,17 +35,18 @@ CBattleQuery::CBattleQuery(CGameHandler * owner, const IBattleInfo * bi): CQuery(owner), battleID(bi->getBattleID()) { - belligerents[0] = bi->getSideArmy(0); - belligerents[1] = bi->getSideArmy(1); + belligerents[BattleSide::ATTACKER] = bi->getSideArmy(BattleSide::ATTACKER); + belligerents[BattleSide::DEFENDER] = bi->getSideArmy(BattleSide::DEFENDER); - addPlayer(bi->getSidePlayer(0)); - addPlayer(bi->getSidePlayer(1)); + addPlayer(bi->getSidePlayer(BattleSide::ATTACKER)); + addPlayer(bi->getSidePlayer(BattleSide::DEFENDER)); } CBattleQuery::CBattleQuery(CGameHandler * owner): CQuery(owner) { - belligerents[0] = belligerents[1] = nullptr; + belligerents[BattleSide::ATTACKER] = nullptr; + belligerents[BattleSide::DEFENDER] = nullptr; } bool CBattleQuery::blocksPack(const CPack * pack) const @@ -81,8 +82,8 @@ CBattleDialogQuery::CBattleDialogQuery(CGameHandler * owner, const IBattleInfo * bi(bi), result(Br) { - addPlayer(bi->getSidePlayer(0)); - addPlayer(bi->getSidePlayer(1)); + addPlayer(bi->getSidePlayer(BattleSide::ATTACKER)); + addPlayer(bi->getSidePlayer(BattleSide::DEFENDER)); } void CBattleDialogQuery::onRemoval(PlayerColor color) @@ -97,11 +98,11 @@ void CBattleDialogQuery::onRemoval(PlayerColor color) { gh->battles->restartBattlePrimary( bi->getBattleID(), - bi->getSideArmy(0), - bi->getSideArmy(1), + bi->getSideArmy(BattleSide::ATTACKER), + bi->getSideArmy(BattleSide::DEFENDER), bi->getLocation(), - bi->getSideHero(0), - bi->getSideHero(1), + bi->getSideHero(BattleSide::ATTACKER), + bi->getSideHero(BattleSide::DEFENDER), bi->isCreatureBank(), bi->getDefendedTown() ); diff --git a/server/queries/BattleQueries.h b/server/queries/BattleQueries.h index cae8c3b09..6916cb7f5 100644 --- a/server/queries/BattleQueries.h +++ b/server/queries/BattleQueries.h @@ -11,6 +11,7 @@ #include "CQuery.h" #include "../../lib/networkPacks/PacksForClientBattle.h" +#include "../../lib/battle/BattleSide.h" VCMI_LIB_NAMESPACE_BEGIN class IBattleInfo; @@ -20,8 +21,8 @@ VCMI_LIB_NAMESPACE_END class CBattleQuery : public CQuery { public: - std::array belligerents; - std::array initialHeroMana; + BattleSideArray belligerents; + BattleSideArray initialHeroMana; BattleID battleID; std::optional result; diff --git a/test/battle/BattleHexTest.cpp b/test/battle/BattleHexTest.cpp index d2179587d..075952bba 100644 --- a/test/battle/BattleHexTest.cpp +++ b/test/battle/BattleHexTest.cpp @@ -92,16 +92,16 @@ TEST(BattleHexTest, getClosestTile) possibilities.insert(119); possibilities.insert(186); - EXPECT_EQ(mainHex.getClosestTile(0,mainHex,possibilities), 3); + EXPECT_EQ(mainHex.getClosestTile(BattleSide::ATTACKER,mainHex,possibilities), 3); mainHex = 139; - EXPECT_EQ(mainHex.getClosestTile(1,mainHex,possibilities), 119); + EXPECT_EQ(mainHex.getClosestTile(BattleSide::DEFENDER,mainHex,possibilities), 119); mainHex = 16; - EXPECT_EQ(mainHex.getClosestTile(1,mainHex,possibilities), 100); + EXPECT_EQ(mainHex.getClosestTile(BattleSide::DEFENDER,mainHex,possibilities), 100); mainHex = 166; - EXPECT_EQ(mainHex.getClosestTile(0,mainHex,possibilities), 186); + EXPECT_EQ(mainHex.getClosestTile(BattleSide::ATTACKER,mainHex,possibilities), 186); mainHex = 76; - EXPECT_EQ(mainHex.getClosestTile(1,mainHex,possibilities), 3); - EXPECT_EQ(mainHex.getClosestTile(0,mainHex,possibilities), 100); + EXPECT_EQ(mainHex.getClosestTile(BattleSide::DEFENDER,mainHex,possibilities), 3); + EXPECT_EQ(mainHex.getClosestTile(BattleSide::ATTACKER,mainHex,possibilities), 100); } TEST(BattleHexTest, moveEDir) diff --git a/test/battle/CBattleInfoCallbackTest.cpp b/test/battle/CBattleInfoCallbackTest.cpp index 8a443ef48..d7929f7ea 100644 --- a/test/battle/CBattleInfoCallbackTest.cpp +++ b/test/battle/CBattleInfoCallbackTest.cpp @@ -104,7 +104,7 @@ class UnitsFake public: std::vector> allUnits; - UnitFake & add(ui8 side) + UnitFake & add(BattleSide side) { auto * unit = new UnitFake(); EXPECT_CALL(*unit, unitSide()).WillRepeatedly(Return(side)); @@ -207,7 +207,7 @@ public: class AttackableHexesTest : public CBattleInfoCallbackTest { public: - UnitFake & addRegularMelee(BattleHex hex, uint8_t side) + UnitFake & addRegularMelee(BattleHex hex, BattleSide side) { auto & unit = unitsFake.add(side); @@ -219,7 +219,7 @@ public: return unit; } - UnitFake & addDragon(BattleHex hex, uint8_t side) + UnitFake & addDragon(BattleHex hex, BattleSide side) { auto & unit = addRegularMelee(hex, side); @@ -245,9 +245,9 @@ public: TEST_F(AttackableHexesTest, DragonRightRegular_RightHorithontalBreath) { // X A D # - UnitFake & attacker = addDragon(35, 0); - UnitFake & defender = addRegularMelee(36, 1); - UnitFake & next = addRegularMelee(37, 1); + UnitFake & attacker = addDragon(35, BattleSide::ATTACKER); + UnitFake & defender = addRegularMelee(36, BattleSide::DEFENDER); + UnitFake & next = addRegularMelee(37, BattleSide::DEFENDER); auto attacked = getAttackedUnits(attacker, defender, defender.getPosition()); @@ -259,9 +259,9 @@ TEST_F(AttackableHexesTest, DragonDragonBottomRightHead_BottomRightBreathFromHea // X A // D X target D // # - UnitFake & attacker = addDragon(35, 0); - UnitFake & defender = addDragon(attacker.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 1); - UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 1); + UnitFake & attacker = addDragon(35, BattleSide::ATTACKER); + UnitFake & defender = addDragon(attacker.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), BattleSide::DEFENDER); + UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), BattleSide::DEFENDER); auto attacked = getAttackedUnits(attacker, defender, defender.getPosition()); @@ -273,9 +273,9 @@ TEST_F(AttackableHexesTest, DragonDragonVerticalDownHead_VerticalDownBreathFromH // X A // D X target D // # - UnitFake & attacker = addDragon(35, 0); - UnitFake & defender = addDragon(attacker.getPosition().cloneInDirection(BattleHex::BOTTOM_LEFT), 1); - UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 1); + UnitFake & attacker = addDragon(35, BattleSide::ATTACKER); + UnitFake & defender = addDragon(attacker.getPosition().cloneInDirection(BattleHex::BOTTOM_LEFT), BattleSide::DEFENDER); + UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), BattleSide::DEFENDER); auto attacked = getAttackedUnits(attacker, defender, defender.getPosition()); @@ -287,9 +287,9 @@ TEST_F(AttackableHexesTest, DragonDragonVerticalDownHeadReverse_VerticalDownBrea // A X // X D target D // # - UnitFake & attacker = addDragon(36, 1); - UnitFake & defender = addDragon(attacker.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 0); - UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_LEFT), 0); + UnitFake & attacker = addDragon(36, BattleSide::DEFENDER); + UnitFake & defender = addDragon(attacker.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), BattleSide::ATTACKER); + UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_LEFT), BattleSide::ATTACKER); auto attacked = getAttackedUnits(attacker, defender, defender.getPosition()); @@ -301,9 +301,9 @@ TEST_F(AttackableHexesTest, DragonDragonVerticalDownBack_VerticalDownBreath) // X A // D X target X // # - UnitFake & attacker = addDragon(37, 0); - UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_LEFT), 1); - UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 1); + UnitFake & attacker = addDragon(37, BattleSide::ATTACKER); + UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_LEFT), BattleSide::DEFENDER); + UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), BattleSide::DEFENDER); auto attacked = getAttackedUnits(attacker, defender, defender.occupiedHex()); @@ -315,9 +315,9 @@ TEST_F(AttackableHexesTest, DragonDragonHeadBottomRight_BottomRightBreathFromHea // X A // D X target D // # - UnitFake & attacker = addDragon(37, 0); - UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_LEFT), 1); - UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 1); + UnitFake & attacker = addDragon(37, BattleSide::ATTACKER); + UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_LEFT), BattleSide::DEFENDER); + UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), BattleSide::DEFENDER); auto attacked = getAttackedUnits(attacker, defender, defender.getPosition()); @@ -329,9 +329,9 @@ TEST_F(AttackableHexesTest, DragonVerticalDownDragonBackReverse_VerticalDownBrea // A X // X D target X // # - UnitFake & attacker = addDragon(36, 1); - UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_RIGHT), 0); - UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_LEFT), 0); + UnitFake & attacker = addDragon(36, BattleSide::DEFENDER); + UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_RIGHT), BattleSide::ATTACKER); + UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_LEFT), BattleSide::ATTACKER); auto attacked = getAttackedUnits(attacker, defender, defender.occupiedHex()); @@ -342,9 +342,9 @@ TEST_F(AttackableHexesTest, DragonRightBottomDragonHeadReverse_RightBottomBreath { // A X // X D target D - UnitFake & attacker = addDragon(36, 1); - UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_RIGHT), 0); - UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_LEFT), 0); + UnitFake & attacker = addDragon(36, BattleSide::DEFENDER); + UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_RIGHT), BattleSide::ATTACKER); + UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_LEFT), BattleSide::ATTACKER); auto attacked = getAttackedUnits(attacker, defender, defender.getPosition()); @@ -356,9 +356,9 @@ TEST_F(AttackableHexesTest, DragonLeftBottomDragonBackToBack_LeftBottomBreathFro // X A // D X target X // # - UnitFake & attacker = addDragon(8, 0); - UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_LEFT).cloneInDirection(BattleHex::LEFT), 1); - UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 1); + UnitFake & attacker = addDragon(8, BattleSide::ATTACKER); + UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_LEFT).cloneInDirection(BattleHex::LEFT), BattleSide::DEFENDER); + UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), BattleSide::DEFENDER); auto attacked = getAttackedUnits(attacker, defender, defender.occupiedHex()); @@ -370,9 +370,9 @@ TEST_F(AttackableHexesTest, DefenderPositionOverride_BreathCountsHypoteticDefend // # N // X D target D // A X - UnitFake & attacker = addDragon(35, 1); - UnitFake & defender = addDragon(8, 0); - UnitFake & next = addDragon(2, 0); + UnitFake & attacker = addDragon(35, BattleSide::DEFENDER); + UnitFake & defender = addDragon(8, BattleSide::ATTACKER); + UnitFake & next = addDragon(2, BattleSide::ATTACKER); startBattle(); redirectUnitsToFake(); @@ -402,10 +402,10 @@ public: auto ret = subject.battleIsFinished(); EXPECT_TRUE(ret); - EXPECT_EQ(*ret, 2); + EXPECT_EQ(*ret, BattleSide::NONE); } - void expectBattleWinner(ui8 side) + void expectBattleWinner(BattleSide side) { auto ret = subject.battleIsFinished(); @@ -413,12 +413,12 @@ public: EXPECT_EQ(*ret, side); } - void expectBattleLooser(ui8 side) + void expectBattleLooser(BattleSide side) { auto ret = subject.battleIsFinished(); EXPECT_TRUE(ret); - EXPECT_NE(*ret, (int)side); + EXPECT_NE(*ret, side); } void setDefaultExpectations() @@ -443,21 +443,21 @@ TEST_F(BattleFinishedTest, EmptyBattleIsDraw) TEST_F(BattleFinishedTest, LastAliveUnitWins) { - UnitFake & unit = unitsFake.add(1); + UnitFake & unit = unitsFake.add(BattleSide::DEFENDER); unit.makeAlive(); unit.setDefaultState(); setDefaultExpectations(); startBattle(); - expectBattleWinner(1); + expectBattleWinner(BattleSide::DEFENDER); } TEST_F(BattleFinishedTest, TwoUnitsContinueFight) { - UnitFake & unit1 = unitsFake.add(0); + UnitFake & unit1 = unitsFake.add(BattleSide::ATTACKER); unit1.makeAlive(); - UnitFake & unit2 = unitsFake.add(1); + UnitFake & unit2 = unitsFake.add(BattleSide::DEFENDER); unit2.makeAlive(); setDefaultExpectations(); @@ -468,7 +468,7 @@ TEST_F(BattleFinishedTest, TwoUnitsContinueFight) TEST_F(BattleFinishedTest, LastWarMachineNotWins) { - UnitFake & unit = unitsFake.add(0); + UnitFake & unit = unitsFake.add(BattleSide::ATTACKER); unit.makeAlive(); unit.makeWarMachine(); unit.setDefaultState(); @@ -476,18 +476,18 @@ TEST_F(BattleFinishedTest, LastWarMachineNotWins) setDefaultExpectations(); startBattle(); - expectBattleLooser(0); + expectBattleLooser(BattleSide::ATTACKER); } TEST_F(BattleFinishedTest, LastWarMachineLoose) { try { - UnitFake & unit1 = unitsFake.add(0); + UnitFake & unit1 = unitsFake.add(BattleSide::ATTACKER); unit1.makeAlive(); unit1.setDefaultState(); - UnitFake & unit2 = unitsFake.add(1); + UnitFake & unit2 = unitsFake.add(BattleSide::DEFENDER); unit2.makeAlive(); unit2.makeWarMachine(); unit2.setDefaultState(); @@ -495,7 +495,7 @@ TEST_F(BattleFinishedTest, LastWarMachineLoose) setDefaultExpectations(); startBattle(); - expectBattleWinner(0); + expectBattleWinner(BattleSide::ATTACKER); } catch(const std::exception & e) { diff --git a/test/battle/battle_UnitTest.cpp b/test/battle/battle_UnitTest.cpp index 390c35a29..b6ead9ab2 100644 --- a/test/battle/battle_UnitTest.cpp +++ b/test/battle/battle_UnitTest.cpp @@ -15,7 +15,7 @@ TEST(battle_Unit_getSurroundingHexes, oneWide) { BattleHex position(77); - auto actual = battle::Unit::getSurroundingHexes(position, false, 0); + auto actual = battle::Unit::getSurroundingHexes(position, false, BattleSide::ATTACKER); EXPECT_EQ(actual, position.neighbouringTiles()); } @@ -24,7 +24,7 @@ TEST(battle_Unit_getSurroundingHexes, oneWideLeftCorner) { BattleHex position(34); - auto actual = battle::Unit::getSurroundingHexes(position, false, 0); + auto actual = battle::Unit::getSurroundingHexes(position, false, BattleSide::ATTACKER); EXPECT_EQ(actual, position.neighbouringTiles()); } @@ -33,7 +33,7 @@ TEST(battle_Unit_getSurroundingHexes, oneWideRightCorner) { BattleHex position(117); - auto actual = battle::Unit::getSurroundingHexes(position, false, 0); + auto actual = battle::Unit::getSurroundingHexes(position, false, BattleSide::ATTACKER); EXPECT_EQ(actual, position.neighbouringTiles()); } diff --git a/test/game/CGameStateTest.cpp b/test/game/CGameStateTest.cpp index 941397fdc..8acd3bbc9 100644 --- a/test/game/CGameStateTest.cpp +++ b/test/game/CGameStateTest.cpp @@ -188,8 +188,8 @@ public: void startTestBattle(const CGHeroInstance * attacker, const CGHeroInstance * defender) { - const CGHeroInstance * heroes[2] = {attacker, defender}; - const CArmedInstance * armedInstancies[2] = {attacker, defender}; + BattleSideArray heroes = {attacker, defender}; + BattleSideArray armedInstancies = {attacker, defender}; int3 tile(4,4,0); diff --git a/test/mock/BattleFake.cpp b/test/mock/BattleFake.cpp index c22e5e3a4..3a5c6488c 100644 --- a/test/mock/BattleFake.cpp +++ b/test/mock/BattleFake.cpp @@ -44,7 +44,7 @@ void UnitFake::expectAnyBonusSystemCall() EXPECT_CALL(*this, getTreeVersion()).Times(AtLeast(0)); } -UnitFake & UnitsFake::add(ui8 side) +UnitFake & UnitsFake::add(BattleSide side) { auto * unit = new UnitFake(); ON_CALL(*unit, unitSide()).WillByDefault(Return(side)); diff --git a/test/mock/BattleFake.h b/test/mock/BattleFake.h index 4a8d04b4d..42ff10e07 100644 --- a/test/mock/BattleFake.h +++ b/test/mock/BattleFake.h @@ -52,7 +52,7 @@ class UnitsFake public: std::vector> allUnits; - UnitFake & add(ui8 side); + UnitFake & add(BattleSide side); battle::Units getUnitsIf(battle::UnitFilter predicate) const; diff --git a/test/mock/mock_IBattleInfoCallback.h b/test/mock/mock_IBattleInfoCallback.h index f28dd37f6..f2eb2b35b 100644 --- a/test/mock/mock_IBattleInfoCallback.h +++ b/test/mock/mock_IBattleInfoCallback.h @@ -22,10 +22,10 @@ public: MOCK_CONST_METHOD0(battleTerrainType, TerrainId()); MOCK_CONST_METHOD0(battleGetBattlefieldType, BattleField()); - MOCK_CONST_METHOD0(battleIsFinished, std::optional()); + MOCK_CONST_METHOD0(battleIsFinished, std::optional()); MOCK_CONST_METHOD0(battleTacticDist, si8()); - MOCK_CONST_METHOD0(battleGetTacticsSide, si8()); + MOCK_CONST_METHOD0(battleGetTacticsSide, BattleSide()); MOCK_CONST_METHOD0(battleNextUnitId, uint32_t()); diff --git a/test/mock/mock_UnitInfo.h b/test/mock/mock_UnitInfo.h index fda7aa8e1..a336fbbd5 100644 --- a/test/mock/mock_UnitInfo.h +++ b/test/mock/mock_UnitInfo.h @@ -18,7 +18,7 @@ public: MOCK_CONST_METHOD0(unitBaseAmount, int32_t()); MOCK_CONST_METHOD0(unitId, uint32_t()); - MOCK_CONST_METHOD0(unitSide, ui8()); + MOCK_CONST_METHOD0(unitSide, BattleSide()); MOCK_CONST_METHOD0(unitOwner, PlayerColor()); MOCK_CONST_METHOD0(unitSlot, SlotID()); diff --git a/test/mock/mock_battle_IBattleState.h b/test/mock/mock_battle_IBattleState.h index 6ef0998d8..0893fd6cc 100644 --- a/test/mock/mock_battle_IBattleState.h +++ b/test/mock/mock_battle_IBattleState.h @@ -25,20 +25,20 @@ public: MOCK_CONST_METHOD0(getDefendedTown, const CGTownInstance *()); MOCK_CONST_METHOD1(getWallState, EWallState(EWallPart)); MOCK_CONST_METHOD0(getGateState, EGateState()); - MOCK_CONST_METHOD1(getSidePlayer, PlayerColor(ui8)); - MOCK_CONST_METHOD1(getSideArmy, const CArmedInstance *(ui8)); - MOCK_CONST_METHOD1(getSideHero, const CGHeroInstance *(ui8)); - MOCK_CONST_METHOD1(getCastSpells, uint32_t(ui8)); - MOCK_CONST_METHOD1(getEnchanterCounter, int32_t(ui8)); + MOCK_CONST_METHOD1(getSidePlayer, PlayerColor(BattleSide)); + MOCK_CONST_METHOD1(getSideArmy, const CArmedInstance *(BattleSide)); + MOCK_CONST_METHOD1(getSideHero, const CGHeroInstance *(BattleSide)); + MOCK_CONST_METHOD1(getCastSpells, uint32_t(BattleSide)); + MOCK_CONST_METHOD1(getEnchanterCounter, int32_t(BattleSide)); MOCK_CONST_METHOD0(getTacticDist, ui8()); - MOCK_CONST_METHOD0(getTacticsSide, ui8()); + MOCK_CONST_METHOD0(getTacticsSide, BattleSide()); MOCK_CONST_METHOD0(getBonusBearer, const IBonusBearer *()); MOCK_CONST_METHOD0(nextUnitId, uint32_t()); MOCK_CONST_METHOD3(getActualDamage, int64_t(const DamageRange &, int32_t, vstd::RNG &)); MOCK_CONST_METHOD0(getBattleID, BattleID()); MOCK_CONST_METHOD0(getLocation, int3()); MOCK_CONST_METHOD0(isCreatureBank, bool()); - MOCK_CONST_METHOD1(getUsedSpells, std::vector(ui8)); + MOCK_CONST_METHOD1(getUsedSpells, std::vector(BattleSide)); MOCK_METHOD0(nextRound, void()); MOCK_METHOD1(nextTurn, void(uint32_t)); diff --git a/test/mock/mock_battle_Unit.h b/test/mock/mock_battle_Unit.h index 14d3e5dd4..3562c48ea 100644 --- a/test/mock/mock_battle_Unit.h +++ b/test/mock/mock_battle_Unit.h @@ -38,7 +38,7 @@ public: MOCK_CONST_METHOD0(unitBaseAmount, int32_t()); MOCK_CONST_METHOD0(unitId, uint32_t()); - MOCK_CONST_METHOD0(unitSide, ui8()); + MOCK_CONST_METHOD0(unitSide, BattleSide()); MOCK_CONST_METHOD0(unitOwner, PlayerColor()); MOCK_CONST_METHOD0(unitSlot, SlotID()); MOCK_CONST_METHOD0(unitType, const CCreature * ());