瀏覽代碼

Merge pull request #238 from vmarkovtsev/develop

Fix segfault/assertion failure during battle
Vadim Markovtsev 9 年之前
父節點
當前提交
a146d1c887
共有 2 個文件被更改,包括 14 次插入7 次删除
  1. 13 6
      server/CGameHandler.cpp
  2. 1 1
      server/CGameHandler.h

+ 13 - 6
server/CGameHandler.cpp

@@ -3892,7 +3892,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
 					BattleAttack bat;
 					prepareAttack(bat, stack, destinationStack, (i ? 0 : distance),  ba.additionalInfo); //no distance travelled on second attack
 					//prepareAttack(bat, stack, stackAtEnd, 0, ba.additionalInfo);
-					handleAttackBeforeCasting(bat); //only before first attack
+					handleAttackBeforeCasting(&bat); //only before first attack
 					sendAndApply(&bat);
 					handleAfterAttackCasting(bat);
 				}
@@ -3936,7 +3936,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
 				BattleAttack bat;
 				bat.flags |= BattleAttack::SHOT;
 				prepareAttack(bat, stack, destinationStack, 0, ba.destinationTile);
-				handleAttackBeforeCasting(bat);
+				handleAttackBeforeCasting(&bat);
 				sendAndApply(&bat);
 				handleAfterAttackCasting(bat);
 			}
@@ -5209,16 +5209,23 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta
 	}
 }
 
-void CGameHandler::handleAttackBeforeCasting (const BattleAttack & bat)
+void CGameHandler::handleAttackBeforeCasting(BattleAttack *bat)
 {
-	const CStack * attacker = gs->curB->battleGetStackByID(bat.stackAttacking);
-	attackCasting(bat, Bonus::SPELL_BEFORE_ATTACK, attacker); //no death stare / acid breath needed?
+	const CStack * attacker = gs->curB->battleGetStackByID(bat->stackAttacking);
+	attackCasting(*bat, Bonus::SPELL_BEFORE_ATTACK, attacker); //no death stare / acid breath needed?
+	// filter possibly dead stacks
+	bat->bsa.erase(std::remove_if(bat->bsa.begin(), bat->bsa.end(),
+	               [this](const BattleStackAttacked &bsa)
+	               {
+	                 return battleGetStackByID(bsa.stackAttacked) == nullptr;
+	               }),
+	               bat->bsa.end());
 }
 
 void CGameHandler::handleAfterAttackCasting(const BattleAttack & bat)
 {
 	const CStack * attacker = gs->curB->battleGetStackByID(bat.stackAttacking);
-	if (!attacker) //could be already dead
+	if (!attacker || bat.bsa.empty()) // can be already dead
 		return;
 
 	auto cast = [=](SpellID spellID, int power)

+ 1 - 1
server/CGameHandler.h

@@ -279,7 +279,7 @@ public:
 
 	void run(bool resume);
 	void newTurn();
-	void handleAttackBeforeCasting (const BattleAttack & bat);
+	void handleAttackBeforeCasting(BattleAttack *bat);
 	void handleAfterAttackCasting (const BattleAttack & bat);
 	void attackCasting(const BattleAttack & bat, Bonus::BonusType attackMode, const CStack * attacker);
 	bool sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, ArtifactPosition slot);