From 99352a722012f306b891463b25ec3c98b686bb09 Mon Sep 17 00:00:00 2001 From: DjWarmonger Date: Sun, 8 Sep 2013 17:43:10 +0000 Subject: [PATCH] Fixed crashes when clone dies #1357, #1441. --- lib/BattleState.cpp | 2 +- lib/BattleState.h | 4 ++++ lib/GameConstants.h | 2 +- lib/NetPacksLib.cpp | 6 +++--- server/CGameHandler.cpp | 19 +++++++++++++++++-- 5 files changed, 26 insertions(+), 7 deletions(-) diff --git a/lib/BattleState.cpp b/lib/BattleState.cpp index c05b0cb20..b4b6991a2 100644 --- a/lib/BattleState.cpp +++ b/lib/BattleState.cpp @@ -1201,7 +1201,7 @@ bool CStack::isMeleeAttackPossible(const CStack * attacker, const CStack * defen } -bool CStack::ableToRetaliate() const +bool CStack::ableToRetaliate() const //FIXME: crash after clone is killed { return alive() && (counterAttacks > 0 || hasBonusOfType(Bonus::UNLIMITED_RETALIATIONS)) diff --git a/lib/BattleState.h b/lib/BattleState.h index bfaed7103..4228e5cdd 100644 --- a/lib/BattleState.h +++ b/lib/BattleState.h @@ -264,6 +264,10 @@ public: { return vstd::contains(state,EBattleStackState::ALIVE); } + bool idDeadClone() const //determines if stack is alive + { + return vstd::contains(state,EBattleStackState::DEAD_CLONE); + } bool isValidTarget(bool allowDead = false) const; //alive non-turret stacks (can be attacked or be object of magic effect) }; diff --git a/lib/GameConstants.h b/lib/GameConstants.h index 306928e87..357b6bee0 100644 --- a/lib/GameConstants.h +++ b/lib/GameConstants.h @@ -429,7 +429,7 @@ namespace EMarketMode namespace EBattleStackState { - enum EBattleStackState{ALIVE = 180, SUMMONED, CLONED, HAD_MORALE, WAITING, MOVED, DEFENDING, FEAR, + enum EBattleStackState{ALIVE = 180, SUMMONED, CLONED, DEAD_CLONE, HAD_MORALE, WAITING, MOVED, DEFENDING, FEAR, DRAINED_MANA /*remember to drain mana only once per turn*/}; } diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index f4e764160..b9a499fcd 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -1185,9 +1185,9 @@ DLL_LINKAGE void BattleStackAttacked::applyGs( CGameState *gs ) } if (cloneKilled()) { - BattleStacksRemoved bsr; //remove body - bsr.stackIDs.insert(at->ID); - bsr.applyGs(gs); + //"hide" killed creatures instead so we keep info about it + at->state.insert(EBattleStackState::DEAD_CLONE); + } } diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 71ed2ddc0..08fb611ad 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -3433,7 +3433,8 @@ bool CGameHandler::makeBattleAction( BattleAction &ba ) } //counterattack - if (!stack->hasBonusOfType(Bonus::BLOCKS_RETALIATION) + if (stackAtEnd + && !stack->hasBonusOfType(Bonus::BLOCKS_RETALIATION) && stackAtEnd->ableToRetaliate() && stack->alive()) //attacker may have died (fire shield) { @@ -3451,6 +3452,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba ) moveStack(ba.stackNumber, startingPos); //NOTE: curStack->ID == ba.stackNumber (rev 1431) } + sendAndApply(&end_action); break; } @@ -3773,7 +3775,6 @@ bool CGameHandler::makeBattleAction( BattleAction &ba ) handleSpellCasting(spellID, spellLvl, destination, casterSide, stack->owner, nullptr, secHero, 0, ECastingMode::CREATURE_ACTIVE_CASTING, stack); } - sendAndApply(&end_action); break; } @@ -5895,7 +5896,21 @@ void CGameHandler::runBattle() const BattleInfo & curB = *gs->curB; + //remove clones after all mechanics and animations are handled! + std::set stacksToRemove; + for (auto stack : curB.stacks) + { + if (stack->idDeadClone()) + stacksToRemove.insert(stack); + } + for (auto stack : stacksToRemove) + { + BattleStacksRemoved bsr; + bsr.stackIDs.insert(stack->ID); + sendAndApply(&bsr); + } //stack loop + const CStack *next; while(!battleResult.get() && (next = curB.getNextStack()) && next->willMove()) {