Skip to content

Commit

Permalink
Reduce code duplication in battle_main (ihhub#4217)
Browse files Browse the repository at this point in the history
  • Loading branch information
a1exsh authored Oct 14, 2021
1 parent da0eeb4 commit 2d2813d
Showing 1 changed file with 72 additions and 106 deletions.
178 changes: 72 additions & 106 deletions src/fheroes2/battle/battle_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,10 @@ namespace

Battle::Result Battle::Loader( Army & army1, Army & army2, s32 mapsindex )
{
Result result;

// Validate the arguments - check if battle should even load
if ( !army1.isValid() || !army2.isValid() ) {
Result result;
// Check second army first so attacker would win by default
if ( !army2.isValid() ) {
result.army1 = RESULT_WINS;
Expand Down Expand Up @@ -206,132 +207,97 @@ Battle::Result Battle::Loader( Army & army1, Army & army2, s32 mapsindex )
showBattle = true;
#endif

const size_t battleDeterministicSeed = computeBattleSeed( mapsindex, world.GetMapSeed(), army1, army2 );
const size_t battlePureRandomSeed = Rand::Get( std::numeric_limits<uint32_t>::max() );
const size_t battleSeed = Settings::Get().ExtBattleDeterministicResult() ? battleDeterministicSeed : battlePureRandomSeed;
Rand::DeterministicRandomGenerator randomGenerator( battleSeed );

std::unique_ptr<Arena> arena( new Arena( army1, army2, mapsindex, showBattle, randomGenerator ) );

DEBUG_LOG( DBG_BATTLE, DBG_INFO, "army1 " << army1.String() );
DEBUG_LOG( DBG_BATTLE, DBG_INFO, "army2 " << army2.String() );

while ( arena->BattleValid() ) {
arena->Turns();
}

Result result = arena->GetResult();
const size_t battleSeed = Settings::Get().ExtBattleDeterministicResult() ? computeBattleSeed( mapsindex, world.GetMapSeed(), army1, army2 )
: Rand::Get( std::numeric_limits<uint32_t>::max() );

HeroBase * hero_wins = ( result.army1 & RESULT_WINS ? commander1 : ( result.army2 & RESULT_WINS ? commander2 : nullptr ) );
HeroBase * hero_loss = ( result.army1 & RESULT_LOSS ? commander1 : ( result.army2 & RESULT_LOSS ? commander2 : nullptr ) );
u32 loss_result = result.army1 & RESULT_LOSS ? result.army1 : result.army2;
bool loserAbandoned = !( ( RESULT_RETREAT | RESULT_SURRENDER ) & loss_result );
bool isBattleOver = false;
while ( !isBattleOver ) {
Rand::DeterministicRandomGenerator randomGenerator( battleSeed );
Arena arena( army1, army2, mapsindex, showBattle, randomGenerator );

std::vector<Artifact> artifactsToTransfer;
if ( hero_wins && hero_loss && loserAbandoned && hero_wins->isHeroes() && hero_loss->isHeroes() ) {
artifactsToTransfer = planArtifactTransfer( hero_wins->GetBagArtifacts(), hero_loss->GetBagArtifacts() );
}
DEBUG_LOG( DBG_BATTLE, DBG_INFO, "army1 " << army1.String() );
DEBUG_LOG( DBG_BATTLE, DBG_INFO, "army2 " << army2.String() );

bool battleSummaryShown = false;
// Check if it was an auto battle
if ( isHumanBattle && !showBattle ) {
if ( arena->DialogBattleSummary( result, artifactsToTransfer, true ) ) {
// If dialog returns true we will restart battle in manual mode
showBattle = true;

// Reset army commander state
if ( commander1 )
commander1->SetSpellPoints( initialSpellPoints1 );
if ( commander2 )
commander2->SetSpellPoints( initialSpellPoints2 );
while ( arena.BattleValid() ) {
arena.Turns();
}
result = arena.GetResult();

// Have to destroy old Arena instance first
arena.reset();
HeroBase * const winnerHero = ( result.army1 & RESULT_WINS ? commander1 : ( result.army2 & RESULT_WINS ? commander2 : nullptr ) );
HeroBase * const loserHero = ( result.army1 & RESULT_LOSS ? commander1 : ( result.army2 & RESULT_LOSS ? commander2 : nullptr ) );
const uint32_t lossResult = result.army1 & RESULT_LOSS ? result.army1 : result.army2;
const bool loserAbandoned = !( ( RESULT_RETREAT | RESULT_SURRENDER ) & lossResult );

// reset random seed
randomGenerator.UpdateSeed( battleSeed );
const std::vector<Artifact> artifactsToTransfer = winnerHero && loserHero && loserAbandoned && winnerHero->isHeroes() && loserHero->isHeroes()
? planArtifactTransfer( winnerHero->GetBagArtifacts(), loserHero->GetBagArtifacts() )
: std::vector<Artifact>();

// Reset artifacts that are planned for transfer
artifactsToTransfer.clear();
if ( showBattle ) {
// fade arena
const bool clearMessageLog = ( result.army1 & ( RESULT_RETREAT | RESULT_SURRENDER ) ) || ( result.army2 & ( RESULT_RETREAT | RESULT_SURRENDER ) );
arena.FadeArena( clearMessageLog );
}

arena = std::unique_ptr<Arena>( new Arena( army1, army2, mapsindex, true, randomGenerator ) );
if ( isHumanBattle ) {
if ( arena.DialogBattleSummary( result, artifactsToTransfer, !showBattle ) ) {
// If dialog returns true we will restart battle in manual mode
showBattle = true;

while ( arena->BattleValid() ) {
arena->Turns();
// Reset army commander state
if ( commander1 )
commander1->SetSpellPoints( initialSpellPoints1 );
if ( commander2 )
commander2->SetSpellPoints( initialSpellPoints2 );
continue;
}
}
isBattleOver = true;

// Override the result
result = arena->GetResult();
hero_wins = ( result.army1 & RESULT_WINS ? commander1 : ( result.army2 & RESULT_WINS ? commander2 : nullptr ) );
hero_loss = ( result.army1 & RESULT_LOSS ? commander1 : ( result.army2 & RESULT_LOSS ? commander2 : nullptr ) );
loss_result = result.army1 & RESULT_LOSS ? result.army1 : result.army2;
loserAbandoned = !( ( RESULT_RETREAT | RESULT_SURRENDER ) & loss_result );
if ( loserHero != nullptr && loserAbandoned ) {
// if a hero lost the battle and didn't flee or surrender, they lose all artifacts
clearArtifacts( loserHero->GetBagArtifacts() );

if ( hero_wins && hero_loss && loserAbandoned && hero_wins->isHeroes() && hero_loss->isHeroes() ) {
artifactsToTransfer = planArtifactTransfer( hero_wins->GetBagArtifacts(), hero_loss->GetBagArtifacts() );
// if the other army also had a hero, some artifacts may be captured by them
if ( winnerHero != nullptr ) {
transferArtifacts( winnerHero->GetBagArtifacts(), artifactsToTransfer );
}
}
else {
battleSummaryShown = true;
}
}

if ( showBattle ) {
// fade arena
const bool clearMessageLog
= ( result.army1 & RESULT_RETREAT ) || ( result.army2 & RESULT_RETREAT ) || ( result.army1 & RESULT_SURRENDER ) || ( result.army2 & RESULT_SURRENDER );
arena->FadeArena( clearMessageLog );
}

// final summary dialog
if ( isHumanBattle && !battleSummaryShown ) {
arena->DialogBattleSummary( result, artifactsToTransfer, false );
}
// save count troop
arena.GetForce1().SyncArmyCount();
arena.GetForce2().SyncArmyCount();

if ( hero_loss != nullptr && loserAbandoned ) {
// if a hero lost the battle and didn't flee or surrender, they lose all artifacts
clearArtifacts( hero_loss->GetBagArtifacts() );

// if the other army also had a hero, some artifacts may be captured by them
if ( hero_wins != nullptr ) {
transferArtifacts( hero_wins->GetBagArtifacts(), artifactsToTransfer );
// after battle army1
if ( commander1 ) {
if ( army1.isControlAI() )
AI::Get().HeroesAfterBattle( *commander1, true );
else
commander1->ActionAfterBattle();
}
}

// save count troop
arena->GetForce1().SyncArmyCount();
arena->GetForce2().SyncArmyCount();

// after battle army1
if ( commander1 ) {
if ( army1.isControlAI() )
AI::Get().HeroesAfterBattle( *commander1, true );
else
commander1->ActionAfterBattle();
}

// after battle army2
if ( commander2 ) {
if ( army2.isControlAI() )
AI::Get().HeroesAfterBattle( *commander2, false );
else
commander2->ActionAfterBattle();
}
// after battle army2
if ( commander2 ) {
if ( army2.isControlAI() )
AI::Get().HeroesAfterBattle( *commander2, false );
else
commander2->ActionAfterBattle();
}

// eagle eye capability
if ( hero_wins && hero_loss && hero_wins->GetLevelSkill( Skill::Secondary::EAGLEEYE ) && hero_loss->isHeroes() )
EagleEyeSkillAction( *hero_wins, arena->GetUsageSpells(), hero_wins->isControlHuman(), randomGenerator );
// eagle eye capability
if ( winnerHero && loserHero && winnerHero->GetLevelSkill( Skill::Secondary::EAGLEEYE ) && loserHero->isHeroes() )
EagleEyeSkillAction( *winnerHero, arena.GetUsageSpells(), winnerHero->isControlHuman(), randomGenerator );

// necromancy capability
if ( hero_wins && hero_wins->GetLevelSkill( Skill::Secondary::NECROMANCY ) )
NecromancySkillAction( *hero_wins, result.killed, hero_wins->isControlHuman(), *arena );
// necromancy capability
if ( winnerHero && winnerHero->GetLevelSkill( Skill::Secondary::NECROMANCY ) )
NecromancySkillAction( *winnerHero, result.killed, winnerHero->isControlHuman(), arena );

if ( hero_wins ) {
Heroes * kingdomHero = dynamic_cast<Heroes *>( hero_wins );
if ( winnerHero ) {
Heroes * kingdomHero = dynamic_cast<Heroes *>( winnerHero );

if ( kingdomHero ) {
Kingdom & kingdom = kingdomHero->GetKingdom();
kingdom.SetLastBattleWinHero( *kingdomHero );
if ( kingdomHero ) {
Kingdom & kingdom = kingdomHero->GetKingdom();
kingdom.SetLastBattleWinHero( *kingdomHero );
}
}
}

Expand Down

0 comments on commit 2d2813d

Please sign in to comment.