浏览代码

revert some changes

SoundSSGood 8 月之前
父节点
当前提交
603672ff51

+ 1 - 1
lib/mapObjects/CGHeroInstance.cpp

@@ -968,7 +968,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<CreatureID,si32> &casualties = battleResult.casualties[CBattleInfoEssentials::otherSide(battleResult.winner)];
+		const std::map<CreatureID,si32> 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;

+ 0 - 1
lib/networkPacks/ArtifactLocation.h

@@ -10,7 +10,6 @@
 #pragma once
 
 #include "../constants/EntityIdentifiers.h"
-#include <optional>
 
 VCMI_LIB_NAMESPACE_BEGIN
 

+ 22 - 19
lib/networkPacks/NetPacksLib.cpp

@@ -2105,17 +2105,16 @@ void BattleCancelled::applyGs(CGameState *gs)
 
 void BattleResultAccepted::applyGs(CGameState *gs)
 {
-	const auto attackerArmy = gs->getArmyInstance(heroResult[BattleSide::ATTACKER].army);
-	const auto defenderArmy = gs->getArmyInstance(heroResult[BattleSide::DEFENDER].army);
-
 	// Remove any "until next battle" bonuses
-	attackerArmy->removeBonusesRecursive(Bonus::OneBattle);
-	defenderArmy->removeBonusesRecursive(Bonus::OneBattle);
+	if(const auto attackerHero = gs->getHero(heroResult[BattleSide::ATTACKER].heroId))
+		attackerHero->removeBonusesRecursive(Bonus::OneBattle);
+	if(const auto defenderHero = gs->getHero(heroResult[BattleSide::DEFENDER].heroId))
+		defenderHero->removeBonusesRecursive(Bonus::OneBattle);
 
 	if(winnerSide != BattleSide::NONE)
 	{
 		// Grow up growing artifacts
-		if(const auto winnerHero = gs->getHero(heroResult[winnerSide].army))
+		if(const auto winnerHero = gs->getHero(heroResult[winnerSide].heroId))
 		{
 			if(winnerHero->commander && winnerHero->commander->alive)
 			{
@@ -2131,28 +2130,17 @@ void BattleResultAccepted::applyGs(CGameState *gs)
 
 	if(gs->getSettings().getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE))
 	{
-		if(heroResult[BattleSide::ATTACKER].army)
+		if(const auto attackerArmy = gs->getArmyInstance(heroResult[BattleSide::ATTACKER].armyId))
 		{
 			attackerArmy->giveStackExp(heroResult[BattleSide::ATTACKER].exp);
 			attackerArmy->nodeHasChanged();
 		}
-		if(heroResult[BattleSide::DEFENDER].army)
+		if(const auto defenderArmy = gs->getArmyInstance(heroResult[BattleSide::DEFENDER].armyId))
 		{
 			defenderArmy->giveStackExp(heroResult[BattleSide::DEFENDER].exp);
 			defenderArmy->nodeHasChanged();
 		}
 	}
-
-	for(auto & artPack : artifacts)
-		artPack.applyGs(gs);
-
-	auto currentBattle = boost::range::find_if(gs->currentBattles, [&](const auto & battle)
-	{
-		return battle->battleID == battleID;
-	});
-
-	assert(currentBattle != gs->currentBattles.end());
-	gs->currentBattles.erase(currentBattle);
 }
 
 void BattleLogMessage::applyGs(CGameState *gs)
@@ -2316,6 +2304,21 @@ void BattleUnitsChanged::applyBattle(IBattleState * battleState)
 	}
 }
 
+void BattleResultsApplied::applyGs(CGameState * gs)
+{
+	for(auto & artPack : artifacts)
+		artPack.applyGs(gs);
+
+	const auto currentBattle = std::find_if(gs->currentBattles.begin(), gs->currentBattles.end(),
+		[this](const auto & battle)
+		{
+			return battle->battleID == battleID;
+		});
+
+	assert(currentBattle != gs->currentBattles.end());
+	gs->currentBattles.erase(currentBattle);
+}
+
 void BattleObstaclesChanged::applyGs(CGameState *gs)
 {
 	applyBattle(gs->getBattle(battleID));

+ 8 - 4
lib/networkPacks/PacksForClientBattle.h

@@ -96,14 +96,18 @@ struct DLL_LINKAGE BattleResultAccepted : public CPackForClient
 	struct HeroBattleResults
 	{
 		HeroBattleResults()
-			: army(ObjectInstanceID::NONE), exp(0) {}
+			: armyId(ObjectInstanceID::NONE)
+			, heroId(ObjectInstanceID::NONE)
+			, exp(0) {}
 
-		ObjectInstanceID army;
+		ObjectInstanceID heroId;
+		ObjectInstanceID armyId;
 		TExpType exp;
 
 		template <typename Handler> void serialize(Handler & h)
 		{
-			h & army;
+			h & armyId;
+			h & heroId;
 			h & exp;
 		}
 	};
@@ -424,7 +428,7 @@ struct DLL_LINKAGE BattleResultsApplied : public CPackForClient
 	PlayerColor loser;
 	std::vector<BulkMoveArtifacts> artifacts;
 	void visitTyped(ICPackVisitor & visitor) override;
-	void applyGs(CGameState *gs) override {}
+	void applyGs(CGameState *gs) override;
 
 	template <typename Handler> void serialize(Handler & h)
 	{

+ 0 - 5
server/CGameHandler.cpp

@@ -4098,11 +4098,6 @@ void CGameHandler::removeAfterVisit(const ObjectInstanceID & id)
 				someVistQuery->removeObjectAfterVisit = true;
 				return;
 			}
-			else if(someVistQuery->visitingHero->id == id)
-			{
-				someVistQuery->removeVisitorAfterVisit = true;
-				return;
-			}
 		}
 	}
 

+ 2 - 2
server/battles/BattleProcessor.cpp

@@ -306,7 +306,7 @@ void BattleProcessor::endBattleConfirm(const BattleID & battleID)
 	resultProcessor->endBattleConfirm(*battle);
 }
 
-void BattleProcessor::battleAfterLevelUp(const BattleID & battleID, const BattleResult &result)
+void BattleProcessor::battleFinalize(const BattleID & battleID, const BattleResult &result)
 {
-	resultProcessor->battleAfterLevelUp(battleID, result);
+	resultProcessor->battleFinalize(battleID, result);
 }

+ 1 - 1
server/battles/BattleProcessor.h

@@ -69,7 +69,7 @@ public:
 	/// Applies results of a battle once player agrees to them
 	void endBattleConfirm(const BattleID & battleID);
 	/// Applies results of a battle after potential levelup
-	void battleAfterLevelUp(const BattleID & battleID, const BattleResult & result);
+	void battleFinalize(const BattleID & battleID, const BattleResult & result);
 
 	template <typename Handler> void serialize(Handler &h)
 	{

+ 111 - 91
server/battles/BattleResultProcessor.cpp

@@ -9,6 +9,7 @@
  */
 #include "StdInc.h"
 #include "BattleResultProcessor.h"
+#include "battle/BattleInfo.h"
 
 #include "../CGameHandler.h"
 #include "../TurnTimerHandler.h"
@@ -186,17 +187,19 @@ void CasualtiesAfterBattle::updateArmy(CGameHandler *gh)
 
 FinishingBattleHelper::FinishingBattleHelper(const CBattleInfoCallback & info, const BattleResult & result, int remainingBattleQueriesCount)
 {
+	const auto attackerHero = info.getBattle()->getSideHero(BattleSide::ATTACKER);
+	const auto defenderHero = info.getBattle()->getSideHero(BattleSide::DEFENDER);
 	if (result.winner == BattleSide::ATTACKER)
 	{
-		winnerId = info.getBattle()->getSideArmy(BattleSide::ATTACKER)->id;
-		loserId = info.getBattle()->getSideArmy(BattleSide::DEFENDER)->id;
+		winnerId = attackerHero ? attackerHero->id : ObjectInstanceID::NONE;
+		loserId = defenderHero ? defenderHero->id : ObjectInstanceID::NONE;
 		victor = info.getBattle()->getSidePlayer(BattleSide::ATTACKER);
 		loser = info.getBattle()->getSidePlayer(BattleSide::DEFENDER);
 	}
 	else
 	{
-		winnerId = info.getBattle()->getSideArmy(BattleSide::DEFENDER)->id;
-		loserId = info.getBattle()->getSideArmy(BattleSide::ATTACKER)->id;
+		winnerId = defenderHero ? defenderHero->id : ObjectInstanceID::NONE;
+		loserId = attackerHero ? attackerHero->id : ObjectInstanceID::NONE;
 		victor = info.getBattle()->getSidePlayer(BattleSide::DEFENDER);
 		loser = info.getBattle()->getSidePlayer(BattleSide::ATTACKER);
 	}
@@ -301,6 +304,15 @@ void BattleResultProcessor::endBattle(const CBattleInfoCallback & battle)
 
 void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
 {
+	auto battleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle.sideToPlayer(BattleSide::ATTACKER)));
+	if(!battleQuery)
+		battleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle.sideToPlayer(BattleSide::DEFENDER)));
+	if(!battleQuery)
+	{
+		logGlobal->trace("No battle query, battle end was confirmed by another player");
+		return;
+	}
+
 	auto * battleResult = battleResults.at(battle.getBattle()->getBattleID()).get();
 	auto * finishingBattle = finishingBattles.at(battle.getBattle()->getBattleID()).get();
 
@@ -311,8 +323,8 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
 	cab1.updateArmy(gameHandler);
 	cab2.updateArmy(gameHandler); //take casualties after battle is deleted
 
-	const auto winnerHero = gameHandler->getHero(finishingBattle->winnerId);
-	const auto loserHero = gameHandler->getHero(finishingBattle->loserId);
+	const auto winnerHero = battle.battleGetFightingHero(finishingBattle->winnerSide);
+	const auto loserHero = battle.battleGetFightingHero(CBattleInfoEssentials::otherSide(finishingBattle->winnerSide));
 
 	if(battleResult->winner == BattleSide::DEFENDER
 	   && winnerHero
@@ -326,6 +338,77 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
 	if(!finishingBattle->isDraw() && battleResult->exp[finishingBattle->winnerSide] && winnerHero)
 		gameHandler->giveExperience(winnerHero, battleResult->exp[finishingBattle->winnerSide]);
 
+	// Add statistics
+	if(loserHero && !finishingBattle->isDraw())
+	{
+		ConstTransitivePtr<CGHeroInstance> strongestHero = nullptr;
+		for(auto & hero : gameHandler->gameState()->getPlayerState(finishingBattle->loser)->getHeroes())
+			if(!strongestHero || hero->exp > strongestHero->exp)
+				strongestHero = hero;
+		if(strongestHero->id == finishingBattle->loserId && strongestHero->level > 5)
+			gameHandler->gameState()->statistic.accumulatedValues[finishingBattle->victor].lastDefeatedStrongestHeroDay = gameHandler->gameState()->getDate(Date::DAY);
+	}
+	if(battle.sideToPlayer(BattleSide::ATTACKER) == PlayerColor::NEUTRAL || battle.sideToPlayer(BattleSide::DEFENDER) == PlayerColor::NEUTRAL)
+	{
+		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(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[finishingBattle->winnerSide].heroId = winnerHero ? winnerHero->id : ObjectInstanceID::NONE;
+	raccepted.heroResult[CBattleInfoEssentials::otherSide(finishingBattle->winnerSide)].heroId = loserHero ? loserHero->id : ObjectInstanceID::NONE;
+	raccepted.heroResult[BattleSide::ATTACKER].armyId = battle.battleGetArmyObject(BattleSide::ATTACKER)->id;
+	raccepted.heroResult[BattleSide::DEFENDER].armyId = battle.battleGetArmyObject(BattleSide::DEFENDER)->id;
+	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);
+
+	//--> continuation (battleAfterLevelUp) occurs after level-up gameHandler->queries are handled or on removing query
+}
+
+void BattleResultProcessor::battleFinalize(const BattleID & battleID, const BattleResult & result)
+{
+	LOG_TRACE(logGlobal);
+
+	assert(finishingBattles.count(battleID) != 0);
+	if(finishingBattles.count(battleID) == 0)
+		return;
+
+	auto & finishingBattle = finishingBattles[battleID];
+
+	finishingBattle->remainingBattleQueriesCount--;
+	logGlobal->trace("Decremented gameHandler->queries count to %d", finishingBattle->remainingBattleQueriesCount);
+
+	if (finishingBattle->remainingBattleQueriesCount > 0)
+		//Battle results will be handled when all battle gameHandler->queries are closed
+		return;
+
+	//TODO consider if we really want it to work like above. ATM each player as unblocked as soon as possible
+	// but the battle consequences are applied after final player is unblocked. Hard to abuse...
+	// Still, it looks like a hole.
+
+	const auto battle = std::find_if(gameHandler->gameState()->currentBattles.begin(), gameHandler->gameState()->currentBattles.end(),
+		[battleID](const auto & battle)
+		{
+			return battle->battleID == battleID;
+		});
+	assert(battle != gameHandler->gameState()->currentBattles.end());
+
+	const auto winnerHero = (*battle)->battleGetFightingHero(finishingBattle->winnerSide);
+	const auto loserHero = (*battle)->battleGetFightingHero(CBattleInfoEssentials::otherSide(finishingBattle->winnerSide));
+	BattleResultsApplied resultsApplied;
+
 	// Eagle Eye handling
 	if(!finishingBattle->isDraw() && winnerHero)
 	{
@@ -334,7 +417,7 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
 		if(auto eagleEyeLevel = winnerHero->valOfBonuses(BonusType::LEARN_BATTLE_SPELL_LEVEL_LIMIT))
 		{
 			auto eagleEyeChance = winnerHero->valOfBonuses(BonusType::LEARN_BATTLE_SPELL_CHANCE);
-			for(auto & spellId : battle.getBattle()->getUsedSpells(battle.otherSide(battleResult->winner)))
+			for(const auto & spellId : (*battle)->getUsedSpells(CBattleInfoEssentials::otherSide(result.winner)))
 			{
 				auto spell = spellId.toEntity(LIBRARY->spells());
 				if(spell
@@ -382,8 +465,9 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
 			gameHandler->sendAndApply(spells);
 		}
 	}
+
 	// Artifacts handling
-	if(battleResult->result == EBattleResult::NORMAL && !finishingBattle->isDraw() && winnerHero)
+	if(result.result == EBattleResult::NORMAL && !finishingBattle->isDraw() && winnerHero)
 	{
 		CArtifactFittingSet artFittingSet(*winnerHero);
 		const auto addArtifactToTransfer = [&artFittingSet](BulkMoveArtifacts & pack, const ArtifactPosition & srcSlot, const CArtifactInstance * art)
@@ -401,7 +485,7 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
 
 		if(loserHero)
 		{
-			auto & packHero = finishingBattle->artifacts.emplace_back(finishingBattle->victor, finishingBattle->loserId, finishingBattle->winnerId, false);
+			auto & packHero = resultsApplied.artifacts.emplace_back(finishingBattle->victor, finishingBattle->loserId, finishingBattle->winnerId, false);
 			packHero.srcArtHolder = finishingBattle->loserId;
 			for(const auto & slot : ArtifactUtils::commonWornSlots())
 			{
@@ -418,15 +502,15 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
 
 			if(loserHero->commander)
 			{
-				auto & packCommander = finishingBattle->artifacts.emplace_back(finishingBattle->victor, finishingBattle->loserId, finishingBattle->winnerId, false);
+				auto & packCommander = resultsApplied.artifacts.emplace_back(finishingBattle->victor, finishingBattle->loserId, finishingBattle->winnerId, false);
 				packCommander.srcCreature = loserHero->findStack(loserHero->commander);
 				for(const auto & artSlot : loserHero->commander->artifactsWorn)
 					addArtifactToTransfer(packCommander, artSlot.first, artSlot.second.getArt());
 			}
-			auto armyObj = battle.battleGetArmyObject(battle.otherSide(battleResult->winner));
+			auto armyObj = dynamic_cast<const CArmedInstance*>(gameHandler->getObj(finishingBattle->loserId));
 			for(const auto & armySlot : armyObj->stacks)
 			{
-				auto & packsArmy = finishingBattle->artifacts.emplace_back(finishingBattle->victor, finishingBattle->loserId, finishingBattle->winnerId, false);
+				auto & packsArmy = resultsApplied.artifacts.emplace_back(finishingBattle->victor, finishingBattle->loserId, finishingBattle->winnerId, false);
 				packsArmy.srcArtHolder = armyObj->id;
 				packsArmy.srcCreature = armySlot.first;
 				for(const auto & artSlot : armySlot.second->artifactsWorn)
@@ -435,83 +519,6 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
 		}
 	}
 
-	// Remove beaten hero
-	if(loserHero)
-	{
-		//add statistics
-		if(!finishingBattle->isDraw())
-		{
-			ConstTransitivePtr<CGHeroInstance> strongestHero = nullptr;
-			for(auto & hero : gameHandler->gameState()->getPlayerState(finishingBattle->loser)->getHeroes())
-				if(!strongestHero || hero->exp > strongestHero->exp)
-					strongestHero = hero;
-			if(strongestHero->id == finishingBattle->loserId && strongestHero->level > 5)
-				gameHandler->gameState()->statistic.accumulatedValues[finishingBattle->victor].lastDefeatedStrongestHeroDay = gameHandler->gameState()->getDate(Date::DAY);
-		}
-
-		gameHandler->removeAfterVisit(finishingBattle->loserId);
-	}
-	// For draw case both heroes should be removed
-	if(finishingBattle->isDraw() && winnerHero)
-	{
-		gameHandler->removeAfterVisit(finishingBattle->winnerId);
-		if(gameHandler->getSettings().getBoolean(EGameSettings::HEROES_RETREAT_ON_WIN_WITHOUT_TROOPS))
-			gameHandler->heroPool->onHeroEscaped(finishingBattle->victor, winnerHero);
-	}
-
-	// add statistic
-	if(battle.sideToPlayer(BattleSide::ATTACKER) == PlayerColor::NEUTRAL || battle.sideToPlayer(BattleSide::DEFENDER) == PlayerColor::NEUTRAL)
-	{
-		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(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[BattleSide::ATTACKER].army = battle.battleGetArmyObject(BattleSide::ATTACKER)->id;
-	raccepted.heroResult[BattleSide::DEFENDER].army = battle.battleGetArmyObject(BattleSide::DEFENDER)->id;
-	raccepted.heroResult[BattleSide::ATTACKER].exp = battleResult->exp[BattleSide::ATTACKER];
-	raccepted.heroResult[BattleSide::DEFENDER].exp = battleResult->exp[BattleSide::DEFENDER];
-	raccepted.winnerSide = finishingBattle->winnerSide;
-	raccepted.artifacts = finishingBattle->artifacts;
-	gameHandler->sendAndApply(raccepted);
-
-	//--> continuation (battleAfterLevelUp) occurs after level-up gameHandler->queries are handled or on removing query
-}
-
-void BattleResultProcessor::battleAfterLevelUp(const BattleID & battleID, const BattleResult & result)
-{
-	LOG_TRACE(logGlobal);
-
-	assert(finishingBattles.count(battleID) != 0);
-	if(finishingBattles.count(battleID) == 0)
-		return;
-
-	auto & finishingBattle = finishingBattles[battleID];
-
-	const auto winnerHero = gameHandler->getHero(finishingBattle->winnerId);
-	const auto loserHero = gameHandler->getHero(finishingBattle->loserId);
-
-	finishingBattle->remainingBattleQueriesCount--;
-	logGlobal->trace("Decremented gameHandler->queries count to %d", finishingBattle->remainingBattleQueriesCount);
-
-	if (finishingBattle->remainingBattleQueriesCount > 0)
-		//Battle results will be handled when all battle gameHandler->queries are closed
-		return;
-
-	//TODO consider if we really want it to work like above. ATM each player as unblocked as soon as possible
-	// but the battle consequences are applied after final player is unblocked. Hard to abuse...
-	// Still, it looks like a hole.
-
 	// Necromancy if applicable.
 	const CStackBasicDescriptor raisedStack = winnerHero ? winnerHero->calculateNecromancy(result) : CStackBasicDescriptor();
 	// Give raised units to winner and show dialog, if any were raised,
@@ -524,11 +531,9 @@ void BattleResultProcessor::battleAfterLevelUp(const BattleID & battleID, const
 		gameHandler->addToSlot(StackLocation(finishingBattle->winnerId, necroSlot), raisedStack.getCreature(), raisedStack.count);
 	}
 
-	BattleResultsApplied resultsApplied;
 	resultsApplied.battleID = battleID;
 	resultsApplied.victor = finishingBattle->victor;
 	resultsApplied.loser = finishingBattle->loser;
-	resultsApplied.artifacts = finishingBattle->artifacts;
 	gameHandler->sendAndApply(resultsApplied);
 
 	//handle victory/loss of engaged players
@@ -547,6 +552,21 @@ void BattleResultProcessor::battleAfterLevelUp(const BattleID & battleID, const
 		gameHandler->heroPool->onHeroEscaped(finishingBattle->loser, loserHero);
 	}
 
+	// Remove beaten hero
+	if(loserHero)
+	{
+		RemoveObject ro(loserHero->id, finishingBattle->victor);
+		gameHandler->sendAndApply(ro);
+	}
+	// For draw case both heroes should be removed
+	if(finishingBattle->isDraw() && winnerHero)
+	{
+		RemoveObject ro(winnerHero->id, finishingBattle->loser);
+		gameHandler->sendAndApply(ro);
+		if(gameHandler->getSettings().getBoolean(EGameSettings::HEROES_RETREAT_ON_WIN_WITHOUT_TROOPS))
+			gameHandler->heroPool->onHeroEscaped(finishingBattle->victor, winnerHero);
+	}
+
 	finishingBattles.erase(battleID);
 	battleResults.erase(battleID);
 }

+ 3 - 4
server/battles/BattleResultProcessor.h

@@ -47,10 +47,10 @@ struct FinishingBattleHelper
 
 	inline bool isDraw() const {return winnerSide == BattleSide::NONE;}
 
-	ObjectInstanceID winnerId = ObjectInstanceID::NONE, loserId = ObjectInstanceID::NONE;
+	ObjectInstanceID winnerId;
+	ObjectInstanceID loserId;
 	PlayerColor victor, loser;
 	BattleSide winnerSide;
-	std::vector<BulkMoveArtifacts> artifacts;
 
 	int remainingBattleQueriesCount;
 
@@ -61,7 +61,6 @@ struct FinishingBattleHelper
 		h & victor;
 		h & loser;
 		h & winnerSide;
-		h & artifacts;
 		h & remainingBattleQueriesCount;
 	}
 };
@@ -82,5 +81,5 @@ public:
 	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);
+	void battleFinalize(const BattleID & battleID, const BattleResult & result);
 };

+ 1 - 1
server/queries/BattleQueries.cpp

@@ -65,7 +65,7 @@ void CBattleQuery::onRemoval(PlayerColor color)
 	assert(result);
 
 	if(result)
-		gh->battles->battleAfterLevelUp(battleID, *result);
+		gh->battles->battleFinalize(battleID, *result);
 }
 
 void CBattleQuery::onExposure(QueryPtr topQuery)

+ 0 - 3
server/queries/VisitQueries.cpp

@@ -43,7 +43,6 @@ void MapObjectVisitQuery::onExposure(QueryPtr topQuery)
 MapObjectVisitQuery::MapObjectVisitQuery(CGameHandler * owner, const CGObjectInstance * Obj, const CGHeroInstance * Hero)
 	: VisitQuery(owner, Obj, Hero)
 	, removeObjectAfterVisit(false)
-	, removeVisitorAfterVisit(false)
 {
 }
 
@@ -54,8 +53,6 @@ void MapObjectVisitQuery::onRemoval(PlayerColor color)
 	//Can object visit affect 2 players and what would be desired behavior?
 	if(removeObjectAfterVisit)
 		gh->removeObject(visitedObject, color);
-	if(removeVisitorAfterVisit)
-		gh->removeObject(visitingHero, color);
 }
 
 TownBuildingVisitQuery::TownBuildingVisitQuery(CGameHandler * owner, const CGTownInstance * Obj, std::vector<const CGHeroInstance *> heroes, std::vector<BuildingID> buildingToVisit)

+ 0 - 1
server/queries/VisitQueries.h

@@ -33,7 +33,6 @@ class MapObjectVisitQuery final : public VisitQuery
 {
 public:
 	bool removeObjectAfterVisit;
-	bool removeVisitorAfterVisit;
 
 	MapObjectVisitQuery(CGameHandler * owner, const CGObjectInstance * Obj, const CGHeroInstance * Hero);