1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-10-08 23:22:25 +02:00

Fix battle draw scenario

This commit is contained in:
Opuszek
2025-08-26 13:18:27 +02:00
parent 83e2bfde11
commit 568fa41d72
3 changed files with 78 additions and 48 deletions

View File

@@ -522,7 +522,7 @@ void CGCreature::battleFinished(IGameEventCallback & gameEvents, const CGHeroIns
else if(result.winner == BattleSide::NONE) // draw else if(result.winner == BattleSide::NONE) // draw
{ {
// guarded reward is lost forever on draw // guarded reward is lost forever on draw
gameEvents.removeObject(this, hero->getOwner()); gameEvents.removeObject(this, result.attacker);
} }
else else
{ {

View File

@@ -121,7 +121,8 @@ struct DLL_LINKAGE BattleResult : public Query
{ {
BattleID battleID = BattleID::NONE; BattleID battleID = BattleID::NONE;
EBattleResult result = EBattleResult::NORMAL; EBattleResult result = EBattleResult::NORMAL;
BattleSide winner = BattleSide::NONE; //0 - attacker, 1 - defender, [2 - draw (should be possible?)] BattleSide winner = BattleSide::NONE; //0 - attacker, 1 - defender, 2 - draw
PlayerColor attacker; //used in case of a draw
BattleSideArray<std::map<CreatureID, si32>> casualties; //first => casualties of attackers - map crid => number BattleSideArray<std::map<CreatureID, si32>> casualties; //first => casualties of attackers - map crid => number
BattleSideArray<TExpType> exp{0,0}; //exp for attacker and defender BattleSideArray<TExpType> exp{0,0}; //exp for attacker and defender

View File

@@ -320,6 +320,9 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
cab1.updateArmy(gameHandler); cab1.updateArmy(gameHandler);
cab2.updateArmy(gameHandler); //take casualties after battle is deleted cab2.updateArmy(gameHandler); //take casualties after battle is deleted
const auto attackerHero = battle.battleGetFightingHero(BattleSide::ATTACKER);
const auto defenderHero = battle.battleGetFightingHero(BattleSide::DEFENDER);
const auto winnerHero = battle.battleGetFightingHero(finishingBattle->winnerSide); const auto winnerHero = battle.battleGetFightingHero(finishingBattle->winnerSide);
const auto loserHero = battle.battleGetFightingHero(CBattleInfoEssentials::otherSide(finishingBattle->winnerSide)); const auto loserHero = battle.battleGetFightingHero(CBattleInfoEssentials::otherSide(finishingBattle->winnerSide));
@@ -358,8 +361,8 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
BattleResultAccepted raccepted; BattleResultAccepted raccepted;
raccepted.battleID = battle.getBattle()->getBattleID(); raccepted.battleID = battle.getBattle()->getBattleID();
raccepted.heroResult[finishingBattle->winnerSide].heroID = winnerHero ? winnerHero->id : ObjectInstanceID::NONE; raccepted.heroResult[BattleSide::ATTACKER].heroID = attackerHero ? attackerHero->id : ObjectInstanceID::NONE;
raccepted.heroResult[CBattleInfoEssentials::otherSide(finishingBattle->winnerSide)].heroID = loserHero ? loserHero->id : ObjectInstanceID::NONE; raccepted.heroResult[BattleSide::DEFENDER].heroID = defenderHero ? defenderHero->id : ObjectInstanceID::NONE;
raccepted.heroResult[BattleSide::ATTACKER].armyID = battle.battleGetArmyObject(BattleSide::ATTACKER)->id; raccepted.heroResult[BattleSide::ATTACKER].armyID = battle.battleGetArmyObject(BattleSide::ATTACKER)->id;
raccepted.heroResult[BattleSide::DEFENDER].armyID = battle.battleGetArmyObject(BattleSide::DEFENDER)->id; raccepted.heroResult[BattleSide::DEFENDER].armyID = battle.battleGetArmyObject(BattleSide::DEFENDER)->id;
raccepted.heroResult[BattleSide::ATTACKER].exp = battleResult->exp[BattleSide::ATTACKER]; raccepted.heroResult[BattleSide::ATTACKER].exp = battleResult->exp[BattleSide::ATTACKER];
@@ -399,12 +402,24 @@ void BattleResultProcessor::battleFinalize(const BattleID & battleID, const Batt
}); });
assert(battle != gameHandler->gameState().currentBattles.end()); assert(battle != gameHandler->gameState().currentBattles.end());
const auto winnerHero = (*battle)->battleGetFightingHero(finishingBattle->winnerSide); const CGHeroInstance * winnerHero = nullptr;
const auto loserHero = (*battle)->battleGetFightingHero(CBattleInfoEssentials::otherSide(finishingBattle->winnerSide)); const CGHeroInstance * loserHero = nullptr;
const auto attackerHero = (*battle)->battleGetFightingHero(BattleSide::ATTACKER);
const auto defenderHero = (*battle)->battleGetFightingHero(BattleSide::DEFENDER);
const auto attackerSide = (*battle)->getSidePlayer(BattleSide::ATTACKER);
const auto defenderSide = (*battle)->getSidePlayer(BattleSide::DEFENDER);
if (!finishingBattle->isDraw())
{
winnerHero = (*battle)->battleGetFightingHero(finishingBattle->winnerSide);
loserHero = (*battle)->battleGetFightingHero(CBattleInfoEssentials::otherSide(finishingBattle->winnerSide));
}
BattleResultsApplied resultsApplied; BattleResultsApplied resultsApplied;
// Eagle Eye handling // Eagle Eye handling
if(!finishingBattle->isDraw() && winnerHero) if(winnerHero)
{ {
if(auto eagleEyeLevel = winnerHero->valOfBonuses(BonusType::LEARN_BATTLE_SPELL_LEVEL_LIMIT)) if(auto eagleEyeLevel = winnerHero->valOfBonuses(BonusType::LEARN_BATTLE_SPELL_LEVEL_LIMIT))
{ {
@@ -425,7 +440,7 @@ void BattleResultProcessor::battleFinalize(const BattleID & battleID, const Batt
} }
// Moving artifacts handling // Moving artifacts handling
if(result.result == EBattleResult::NORMAL && !finishingBattle->isDraw() && winnerHero) if(result.result == EBattleResult::NORMAL && winnerHero && loserHero)
{ {
CArtifactFittingSet artFittingSet(*winnerHero); CArtifactFittingSet artFittingSet(*winnerHero);
const auto addArtifactToTransfer = [&artFittingSet](BulkMoveArtifacts & pack, const ArtifactPosition & srcSlot, const CArtifactInstance * art) const auto addArtifactToTransfer = [&artFittingSet](BulkMoveArtifacts & pack, const ArtifactPosition & srcSlot, const CArtifactInstance * art)
@@ -441,8 +456,6 @@ void BattleResultProcessor::battleFinalize(const BattleID & battleID, const Batt
} }
}; };
if(loserHero)
{
BulkMoveArtifacts packHero(finishingBattle->victor, finishingBattle->loserId, finishingBattle->winnerId, false); BulkMoveArtifacts packHero(finishingBattle->victor, finishingBattle->loserId, finishingBattle->winnerId, false);
packHero.srcArtHolder = finishingBattle->loserId; packHero.srcArtHolder = finishingBattle->loserId;
for(const auto & slot : ArtifactUtils::commonWornSlots()) for(const auto & slot : ArtifactUtils::commonWornSlots())
@@ -484,10 +497,9 @@ void BattleResultProcessor::battleFinalize(const BattleID & battleID, const Batt
resultsApplied.movingArtifacts.emplace_back(std::move(packArmy)); resultsApplied.movingArtifacts.emplace_back(std::move(packArmy));
} }
} }
}
// Growing artifacts handling // Growing artifacts handling
if(!finishingBattle->isDraw() && winnerHero) if(winnerHero)
{ {
const auto addArtifactToGrowing = [&resultsApplied](const std::map<ArtifactPosition, ArtSlotInfo> & artMap) const auto addArtifactToGrowing = [&resultsApplied](const std::map<ArtifactPosition, ArtSlotInfo> & artMap)
{ {
@@ -555,12 +567,28 @@ void BattleResultProcessor::battleFinalize(const BattleID & battleID, const Batt
gameHandler->sendAndApply(ro); gameHandler->sendAndApply(ro);
} }
// For draw case both heroes should be removed // For draw case both heroes should be removed
if(finishingBattle->isDraw() && winnerHero) if(finishingBattle->isDraw())
{ {
RemoveObject ro(winnerHero->id, finishingBattle->loser);
if (attackerHero)
{
RemoveObject ro(attackerHero->id, defenderSide);
gameHandler->sendAndApply(ro); gameHandler->sendAndApply(ro);
}
if (defenderHero)
{
RemoveObject ro(defenderHero->id, attackerSide);
gameHandler->sendAndApply(ro);
}
if(gameHandler->gameInfo().getSettings().getBoolean(EGameSettings::HEROES_RETREAT_ON_WIN_WITHOUT_TROOPS)) if(gameHandler->gameInfo().getSettings().getBoolean(EGameSettings::HEROES_RETREAT_ON_WIN_WITHOUT_TROOPS))
gameHandler->heroPool->onHeroEscaped(finishingBattle->victor, winnerHero); {
if (attackerHero)
gameHandler->heroPool->onHeroEscaped(attackerSide, attackerHero);
if (defenderHero)
gameHandler->heroPool->onHeroEscaped(defenderSide, defenderHero);
}
} }
//handle victory/loss of engaged players //handle victory/loss of engaged players
@@ -592,6 +620,7 @@ void BattleResultProcessor::setBattleResult(const CBattleInfoCallback & battle,
battleResult->battleID = battle.getBattle()->getBattleID(); battleResult->battleID = battle.getBattle()->getBattleID();
battleResult->result = resultType; battleResult->result = resultType;
battleResult->winner = victoriusSide; //surrendering side loses battleResult->winner = victoriusSide; //surrendering side loses
battleResult->attacker = battle.getBattle()->getSidePlayer(BattleSide::ATTACKER);
auto allStacks = battle.battleGetStacksIf([](const CStack * stack){ auto allStacks = battle.battleGetStacksIf([](const CStack * stack){