Repository navigation
Consider next unit on planning retreat #10954
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
92bf460
3b117f4
31f22a7
8197f4c
e1f1111
964c0a6
44bca62
ac1018e
a54f42c
367f2e7
4f1edf7
e162408
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,6 +29,7 @@ | |
| #include <functional> | ||
| #include <limits> | ||
| #include <map> | ||
| #include <memory> | ||
| #include <numeric> | ||
| #include <optional> | ||
| #include <ostream> | ||
|
|
@@ -39,6 +40,7 @@ | |
| #include <utility> | ||
| #include <vector> | ||
|
|
||
| #include "army_troop.h" | ||
| #include "artifact.h" | ||
| #include "artifact_info.h" | ||
| #include "battle.h" | ||
|
|
@@ -68,6 +70,8 @@ | |
| #include "spell_info.h" | ||
| #include "spell_storage.h" | ||
|
|
||
| class Army; | ||
|
|
||
| namespace | ||
| { | ||
| const std::vector<int32_t> cellsUnderWallsIndexes = { 7, 28, 49, 72, 95 }; | ||
|
|
@@ -734,6 +738,45 @@ bool AI::BattlePlanner::isLimitOfTurnsExceeded( const Battle::Arena & arena, Bat | |
| return false; | ||
| } | ||
|
|
||
| std::optional<const Battle::Unit *> AI::BattlePlanner::findNextUnit( const Battle::Arena & arena, const Battle::Unit & currentUnit ) | ||
| { | ||
| const std::shared_ptr<const Battle::Units> order = arena.getOrderOfUnits(); | ||
| const Battle::Units * units = order.get(); | ||
|
|
||
| size_t i = 0; | ||
| const size_t count = units->size(); | ||
| for ( ; i < count; i++ ) { | ||
| const Battle::Unit * unit = units->at( i ); | ||
| if ( *unit == currentUnit ) { | ||
| break; | ||
| } | ||
| } | ||
| i++; | ||
| if ( i == count ) { | ||
| i = 0; | ||
| } | ||
|
|
||
| const Battle::Unit * next_unit = units->at( i ); | ||
| assert( next_unit != nullptr ); | ||
| return { next_unit }; | ||
| } | ||
|
|
||
| bool AI::BattlePlanner::isPostponeRetreat( const Battle::Arena & arena, const Battle::Unit & currentUnit ) | ||
| { | ||
| const std::optional<const Battle::Unit *> maybeNextUnit = findNextUnit( arena, currentUnit ); | ||
| if ( !maybeNextUnit.has_value() ) { | ||
| return false; | ||
| } | ||
| const Battle::Unit * nextUnit = maybeNextUnit.value(); | ||
| assert( nextUnit != nullptr ); | ||
|
|
||
| const Army * currentArmy = currentUnit.GetArmy(); | ||
| const Army * nextArmy = nextUnit->GetArmy(); | ||
|
|
||
| const bool isSameArmy = ( currentArmy != nullptr ) && ( currentArmy == nextArmy ); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need to compare armies instead of units?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought of that as the simplest way to check if two units belong to the same army. Otherwise I can make a function like |
||
| return isSameArmy && ( nextUnit->GetMorale() >= 0 ); | ||
| } | ||
|
|
||
| Battle::Actions AI::BattlePlanner::planUnitTurn( Battle::Arena & arena, const Battle::Unit & currentUnit ) | ||
| { | ||
| if ( currentUnit.Modes( Battle::SP_BERSERKER ) ) { | ||
|
|
@@ -757,7 +800,7 @@ Battle::Actions AI::BattlePlanner::planUnitTurn( Battle::Arena & arena, const Ba | |
| Surrender | ||
| }; | ||
|
|
||
| const Outcome outcome = [this, &arena, actualHero]() { | ||
| const Outcome outcome = [this, &arena, actualHero, ¤tUnit]() { | ||
| if ( !_considerRetreat ) { | ||
| return Outcome::ContinueBattle; | ||
| } | ||
|
|
@@ -852,7 +895,7 @@ Battle::Actions AI::BattlePlanner::planUnitTurn( Battle::Arena & arena, const Ba | |
|
|
||
| // If the hero has valuable artifacts, he should retreat so that these artifacts do not end up at the disposal of the enemy, especially in the case of an | ||
| // alliance war | ||
| if ( hasValuableArtifacts ) { | ||
| if ( hasValuableArtifacts && !isPostponeRetreat( arena, currentUnit ) ) { | ||
| return Outcome::Retreat; | ||
| } | ||
|
|
||
|
|
@@ -862,7 +905,7 @@ Battle::Actions AI::BattlePlanner::planUnitTurn( Battle::Arena & arena, const Ba | |
| } | ||
|
|
||
| // Otherwise, if this hero is relatively experienced, then he should retreat so that he can be hired again later | ||
| if ( actualHero->getTotalPrimarySkillLevel() >= minHeroTotalPrimarySkillLevelForRetreat ) { | ||
| if ( ( actualHero->getTotalPrimarySkillLevel() >= minHeroTotalPrimarySkillLevelForRetreat ) && !( isPostponeRetreat( arena, currentUnit ) ) ) { | ||
| return Outcome::Retreat; | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| /*************************************************************************** | ||
| * fheroes2: https://github.com/ihhub/fheroes2 * | ||
| * Copyright (C) 2019 - 2025 * | ||
| * Copyright (C) 2019 - 2026 * | ||
| * * | ||
| * Free Heroes2 Engine: http://sourceforge.net/projects/fheroes2 * | ||
| * Copyright (C) 2010 by Andrey Afletdinov <fheroes2@gmail.com> * | ||
|
|
@@ -152,6 +152,11 @@ namespace Battle | |
| const Unit * GetTroopBoard( int32_t ) const; | ||
|
|
||
| Unit * GetTroopUID( uint32_t ); | ||
| std::shared_ptr<const Units> getOrderOfUnits() const | ||
| { | ||
| return _orderOfUnits; | ||
| } | ||
|
Comment on lines
+155
to
+158
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should revert this change: see my comments above.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have no objections here, but how to receive order of units otherwise? It's required to find the next unit. |
||
|
|
||
| const Unit * GetTroopUID( uint32_t ) const; | ||
|
|
||
| const SpellStorage & GetUsedSpells() const; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this code check units for the next turn?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I could understand,
_orderOfUnitsis like a circular buffer, hence I tried to find current unit in it and get the next unit by index.