From 81242d3500d3271816c9bf324fc5dbfbb252a9ab Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 22 Aug 2023 20:57:58 +0300 Subject: [PATCH] Fixed ending of battles due to retreat/surrender --- client/battle/BattleInterface.cpp | 23 ++++------------------- lib/battle/BattleAction.cpp | 10 ++++++++-- lib/battle/BattleAction.h | 1 + server/battles/BattleActionProcessor.cpp | 15 +++++++++++---- server/battles/BattleProcessor.cpp | 3 +++ server/battles/BattleResultProcessor.cpp | 6 ++++++ server/battles/BattleResultProcessor.h | 2 ++ 7 files changed, 35 insertions(+), 25 deletions(-) diff --git a/client/battle/BattleInterface.cpp b/client/battle/BattleInterface.cpp index 93842e95b..5bc4133ca 100644 --- a/client/battle/BattleInterface.cpp +++ b/client/battle/BattleInterface.cpp @@ -325,7 +325,7 @@ void BattleInterface::battleFinished(const BattleResult& br, QueryID queryID) curInt->cb->selectionMade(selection, queryID); }; GH.windows().pushWindow(wnd); - + curInt->waitWhileDialog(); // Avoid freeze when AI end turn after battle. Check bug #1897 CPlayerInterface::battleInt = nullptr; } @@ -601,28 +601,13 @@ void BattleInterface::startAction(const BattleAction & action) return; } - const CStack *stack = curInt->cb->battleGetStackByID(action.stackNumber); - - if (stack) - { - windowObject->updateQueue(); - } - else - { - assert(action.actionType == EActionType::HERO_SPELL); //only cast spell is valid action without acting stack number - } - stacksController->startAction(action); - if(action.actionType == EActionType::HERO_SPELL) //when hero casts spell + if (!action.isUnitAction()) return; - if (!stack) - { - logGlobal->error("Something wrong with stackNumber in actionStarted. Stack number: %d", action.stackNumber); - return; - } - + assert(curInt->cb->battleGetStackByID(action.stackNumber)); + windowObject->updateQueue(); effectsController->startAction(action); } diff --git a/lib/battle/BattleAction.cpp b/lib/battle/BattleAction.cpp index 5a92ce08e..f8f63a333 100644 --- a/lib/battle/BattleAction.cpp +++ b/lib/battle/BattleAction.cpp @@ -205,7 +205,6 @@ bool BattleAction::isUnitAction() const EActionType::BAD_MORALE, EActionType::STACK_HEAL }; - return vstd::contains(actions, actionType); } @@ -215,7 +214,15 @@ bool BattleAction::isSpellAction() const EActionType::HERO_SPELL, EActionType::MONSTER_SPELL }; + return vstd::contains(actions, actionType); +} +bool BattleAction::isBattleEndAction() const +{ + static const std::array actions = { + EActionType::RETREAT, + EActionType::SURRENDER + }; return vstd::contains(actions, actionType); } @@ -227,7 +234,6 @@ bool BattleAction::isTacticsAction() const EActionType::RETREAT, EActionType::SURRENDER }; - return vstd::contains(actions, actionType); } diff --git a/lib/battle/BattleAction.h b/lib/battle/BattleAction.h index 12eba04e4..593b6290f 100644 --- a/lib/battle/BattleAction.h +++ b/lib/battle/BattleAction.h @@ -46,6 +46,7 @@ public: bool isTacticsAction() const; bool isUnitAction() const; bool isSpellAction() const; + bool isBattleEndAction() const; std::string toString() const; void aimToHex(const BattleHex & destination); diff --git a/server/battles/BattleActionProcessor.cpp b/server/battles/BattleActionProcessor.cpp index e32d082f3..18da73a5b 100644 --- a/server/battles/BattleActionProcessor.cpp +++ b/server/battles/BattleActionProcessor.cpp @@ -535,13 +535,20 @@ bool BattleActionProcessor::makeBattleActionImpl(const BattleAction &ba) logGlobal->trace("Making action: %s", ba.toString()); const CStack * stack = gameHandler->gameState()->curB->battleGetStackByID(ba.stackNumber); - StartAction startAction(ba); - gameHandler->sendAndApply(&startAction); + // for these events client does not expects StartAction/EndAction wrapper + if (!ba.isBattleEndAction()) + { + StartAction startAction(ba); + gameHandler->sendAndApply(&startAction); + } bool result = dispatchBattleAction(ba); - EndAction endAction; - gameHandler->sendAndApply(&endAction); + if (!ba.isBattleEndAction()) + { + EndAction endAction; + gameHandler->sendAndApply(&endAction); + } if(ba.actionType == EActionType::WAIT || ba.actionType == EActionType::DEFEND || ba.actionType == EActionType::SHOOT || ba.actionType == EActionType::MONSTER_SPELL) gameHandler->handleObstacleTriggersForUnit(*gameHandler->spellEnv, *stack); diff --git a/server/battles/BattleProcessor.cpp b/server/battles/BattleProcessor.cpp index 62a0be3a1..5d7be25ec 100644 --- a/server/battles/BattleProcessor.cpp +++ b/server/battles/BattleProcessor.cpp @@ -147,6 +147,9 @@ bool BattleProcessor::checkBattleStateChanges() if (gameHandler->battleGetSiegeLevel() > 0) updateGateState(); + if (resultProcessor->battleIsEnding()) + return true; + //check if battle ended if (auto result = gameHandler->battleIsFinished()) { diff --git a/server/battles/BattleResultProcessor.cpp b/server/battles/BattleResultProcessor.cpp index 912de4e65..6e23d3103 100644 --- a/server/battles/BattleResultProcessor.cpp +++ b/server/battles/BattleResultProcessor.cpp @@ -528,6 +528,7 @@ void BattleResultProcessor::battleAfterLevelUp(const BattleResult &result) } finishingBattle.reset(); + battleResult.reset(); } void BattleResultProcessor::setBattleResult(EBattleResult resultType, int victoriusSide) @@ -537,3 +538,8 @@ void BattleResultProcessor::setBattleResult(EBattleResult resultType, int victor battleResult->winner = victoriusSide; //surrendering side loses gameHandler->gameState()->curB->calculateCasualties(battleResult->casualties); } + +bool BattleResultProcessor::battleIsEnding() const +{ + return battleResult != nullptr; +} diff --git a/server/battles/BattleResultProcessor.h b/server/battles/BattleResultProcessor.h index ec4b13ab6..e758cadfe 100644 --- a/server/battles/BattleResultProcessor.h +++ b/server/battles/BattleResultProcessor.h @@ -71,6 +71,8 @@ public: explicit BattleResultProcessor(BattleProcessor * owner); void setGameHandler(CGameHandler * newGameHandler); + bool battleIsEnding() const; + void setBattleResult(EBattleResult resultType, int victoriusSide); void endBattle(int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2); //ends battle void endBattleConfirm(const BattleInfo * battleInfo);