mirror of
https://github.com/vcmi/vcmi.git
synced 2025-07-05 00:49:09 +02:00
Merge pull request #1909 from vcmi/avoid-freeze-on-siege-selfblocking
BattleAI: avoid selfblocking on siege
This commit is contained in:
@ -212,11 +212,13 @@ AttackPossibility AttackPossibility::evaluate(const BattleAttackInfo & attackInf
|
|||||||
// check how much damage we gain from blocking enemy shooters on this hex
|
// check how much damage we gain from blocking enemy shooters on this hex
|
||||||
bestAp.shootersBlockedDmg = evaluateBlockedShootersDmg(attackInfo, hex, state);
|
bestAp.shootersBlockedDmg = evaluateBlockedShootersDmg(attackInfo, hex, state);
|
||||||
|
|
||||||
logAi->debug("BattleAI best AP: %s -> %s at %d from %d, affects %d units: d:%lld a:%lld c:%lld s:%lld",
|
#if BATTLE_TRACE_LEVEL>=1
|
||||||
|
logAi->trace("BattleAI best AP: %s -> %s at %d from %d, affects %d units: d:%lld a:%lld c:%lld s:%lld",
|
||||||
attackInfo.attacker->unitType()->getJsonKey(),
|
attackInfo.attacker->unitType()->getJsonKey(),
|
||||||
attackInfo.defender->unitType()->getJsonKey(),
|
attackInfo.defender->unitType()->getJsonKey(),
|
||||||
(int)bestAp.dest, (int)bestAp.from, (int)bestAp.affectedUnits.size(),
|
(int)bestAp.dest, (int)bestAp.from, (int)bestAp.affectedUnits.size(),
|
||||||
bestAp.defenderDamageReduce, bestAp.attackerDamageReduce, bestAp.collateralDamageReduce, bestAp.shootersBlockedDmg);
|
bestAp.defenderDamageReduce, bestAp.attackerDamageReduce, bestAp.collateralDamageReduce, bestAp.shootersBlockedDmg);
|
||||||
|
#endif
|
||||||
|
|
||||||
//TODO other damage related to attack (eg. fire shield and other abilities)
|
//TODO other damage related to attack (eg. fire shield and other abilities)
|
||||||
return bestAp;
|
return bestAp;
|
||||||
|
@ -89,6 +89,7 @@ void CBattleAI::initBattleInterface(std::shared_ptr<Environment> ENV, std::share
|
|||||||
wasUnlockingGs = CB->unlockGsWhenWaiting;
|
wasUnlockingGs = CB->unlockGsWhenWaiting;
|
||||||
CB->waitTillRealize = true;
|
CB->waitTillRealize = true;
|
||||||
CB->unlockGsWhenWaiting = false;
|
CB->unlockGsWhenWaiting = false;
|
||||||
|
movesSkippedByDefense = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
BattleAction CBattleAI::activeStack( const CStack * stack )
|
BattleAction CBattleAI::activeStack( const CStack * stack )
|
||||||
@ -181,6 +182,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
|
|||||||
if(bestSpellcast.is_initialized() && bestSpellcast->value > bestAttack.damageDiff())
|
if(bestSpellcast.is_initialized() && bestSpellcast->value > bestAttack.damageDiff())
|
||||||
{
|
{
|
||||||
// return because spellcast value is damage dealt and score is dps reduce
|
// return because spellcast value is damage dealt and score is dps reduce
|
||||||
|
movesSkippedByDefense = 0;
|
||||||
return BattleAction::makeCreatureSpellcast(stack, bestSpellcast->dest, bestSpellcast->spell->id);
|
return BattleAction::makeCreatureSpellcast(stack, bestSpellcast->dest, bestSpellcast->spell->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,14 +198,15 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
|
|||||||
}
|
}
|
||||||
else if(bestAttack.attack.shooting)
|
else if(bestAttack.attack.shooting)
|
||||||
{
|
{
|
||||||
|
|
||||||
result = BattleAction::makeShotAttack(stack, bestAttack.attack.defender);
|
result = BattleAction::makeShotAttack(stack, bestAttack.attack.defender);
|
||||||
action = "shot";
|
action = "shot";
|
||||||
|
movesSkippedByDefense = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = BattleAction::makeMeleeAttack(stack, bestAttack.attack.defender->getPosition(), bestAttack.from);
|
result = BattleAction::makeMeleeAttack(stack, bestAttack.attack.defender->getPosition(), bestAttack.from);
|
||||||
action = "melee";
|
action = "melee";
|
||||||
|
movesSkippedByDefense = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
logAi->debug("BattleAI: %s -> %s x %d, %s, from %d curpos %d dist %d speed %d: +%lld -%lld = %lld",
|
logAi->debug("BattleAI: %s -> %s x %d, %s, from %d curpos %d dist %d speed %d: +%lld -%lld = %lld",
|
||||||
@ -217,6 +220,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
|
|||||||
}
|
}
|
||||||
else if(bestSpellcast.is_initialized())
|
else if(bestSpellcast.is_initialized())
|
||||||
{
|
{
|
||||||
|
movesSkippedByDefense = 0;
|
||||||
return BattleAction::makeCreatureSpellcast(stack, bestSpellcast->dest, bestSpellcast->spell->id);
|
return BattleAction::makeCreatureSpellcast(stack, bestSpellcast->dest, bestSpellcast->spell->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,12 +239,8 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(score > EvaluationResult::INEFFECTIVE_SCORE)
|
if(score <= EvaluationResult::INEFFECTIVE_SCORE
|
||||||
{
|
&& !stack->hasBonusOfType(Bonus::FLYING)
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!stack->hasBonusOfType(Bonus::FLYING)
|
|
||||||
&& stack->unitSide() == BattleSide::ATTACKER
|
&& stack->unitSide() == BattleSide::ATTACKER
|
||||||
&& cb->battleGetSiegeLevel() >= CGTownInstance::CITADEL)
|
&& cb->battleGetSiegeLevel() >= CGTownInstance::CITADEL)
|
||||||
{
|
{
|
||||||
@ -248,10 +248,12 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
|
|||||||
|
|
||||||
if(brokenWallMoat.size())
|
if(brokenWallMoat.size())
|
||||||
{
|
{
|
||||||
|
movesSkippedByDefense = 0;
|
||||||
|
|
||||||
if(stack->doubleWide() && vstd::contains(brokenWallMoat, stack->getPosition()))
|
if(stack->doubleWide() && vstd::contains(brokenWallMoat, stack->getPosition()))
|
||||||
return BattleAction::makeMove(stack, stack->getPosition().cloneInDirection(BattleHex::RIGHT));
|
result = BattleAction::makeMove(stack, stack->getPosition().cloneInDirection(BattleHex::RIGHT));
|
||||||
else
|
else
|
||||||
return goTowardsNearest(stack, brokenWallMoat);
|
result = goTowardsNearest(stack, brokenWallMoat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -264,6 +266,15 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
|
|||||||
logAi->error("Exception occurred in %s %s",__FUNCTION__, e.what());
|
logAi->error("Exception occurred in %s %s",__FUNCTION__, e.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(result.actionType == EActionType::DEFEND)
|
||||||
|
{
|
||||||
|
movesSkippedByDefense++;
|
||||||
|
}
|
||||||
|
else if(result.actionType != EActionType::WAIT)
|
||||||
|
{
|
||||||
|
movesSkippedByDefense = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,7 +296,9 @@ BattleAction CBattleAI::goTowardsNearest(const CStack * stack, std::vector<Battl
|
|||||||
for(auto hex : hexes)
|
for(auto hex : hexes)
|
||||||
{
|
{
|
||||||
if(vstd::contains(avHexes, hex))
|
if(vstd::contains(avHexes, hex))
|
||||||
|
{
|
||||||
return BattleAction::makeMove(stack, hex);
|
return BattleAction::makeMove(stack, hex);
|
||||||
|
}
|
||||||
|
|
||||||
if(stack->coversPos(hex))
|
if(stack->coversPos(hex))
|
||||||
{
|
{
|
||||||
@ -396,6 +409,8 @@ BattleAction CBattleAI::useCatapult(const CStack * stack)
|
|||||||
attack.side = side;
|
attack.side = side;
|
||||||
attack.stackNumber = stack->ID;
|
attack.stackNumber = stack->ID;
|
||||||
|
|
||||||
|
movesSkippedByDefense = 0;
|
||||||
|
|
||||||
return attack;
|
return attack;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -703,6 +718,7 @@ void CBattleAI::attemptCastingSpell()
|
|||||||
spellcast.side = side;
|
spellcast.side = side;
|
||||||
spellcast.stackNumber = (!side) ? -1 : -2;
|
spellcast.stackNumber = (!side) ? -1 : -2;
|
||||||
cb->battleMakeAction(&spellcast);
|
cb->battleMakeAction(&spellcast);
|
||||||
|
movesSkippedByDefense = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -796,12 +812,21 @@ boost::optional<BattleAction> CBattleAI::considerFleeingOrSurrendering()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bs.turnsSkippedByDefense = movesSkippedByDefense / bs.ourStacks.size();
|
||||||
|
|
||||||
if(!bs.canFlee || !bs.canSurrender)
|
if(!bs.canFlee || !bs.canSurrender)
|
||||||
{
|
{
|
||||||
return boost::none;
|
return boost::none;
|
||||||
}
|
}
|
||||||
|
|
||||||
return cb->makeSurrenderRetreatDecision(bs);
|
auto result = cb->makeSurrenderRetreatDecision(bs);
|
||||||
|
|
||||||
|
if(!result && bs.canFlee && bs.turnsSkippedByDefense > 30)
|
||||||
|
{
|
||||||
|
return BattleAction::makeRetreat(bs.ourSide);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@ class CBattleAI : public CBattleGameInterface
|
|||||||
|
|
||||||
//Previous setting of cb
|
//Previous setting of cb
|
||||||
bool wasWaitingForRealize, wasUnlockingGs;
|
bool wasWaitingForRealize, wasUnlockingGs;
|
||||||
|
int movesSkippedByDefense;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CBattleAI();
|
CBattleAI();
|
||||||
|
@ -355,6 +355,13 @@ int64_t BattleExchangeEvaluator::calculateExchange(
|
|||||||
logAi->trace("Battle exchange at %lld", ap.attack.shooting ? ap.dest : ap.from);
|
logAi->trace("Battle exchange at %lld", ap.attack.shooting ? ap.dest : ap.from);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if(cb->battleGetMySide() == BattlePerspective::LEFT_SIDE
|
||||||
|
&& cb->battleGetGateState() == EGateState::BLOCKED
|
||||||
|
&& ap.attack.defender->coversPos(ESiegeHex::GATE_BRIDGE))
|
||||||
|
{
|
||||||
|
return EvaluationResult::INEFFECTIVE_SCORE;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<const battle::Unit *> ourStacks;
|
std::vector<const battle::Unit *> ourStacks;
|
||||||
std::vector<const battle::Unit *> enemyStacks;
|
std::vector<const battle::Unit *> enemyStacks;
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ struct EvaluationResult
|
|||||||
bool defend;
|
bool defend;
|
||||||
|
|
||||||
EvaluationResult(const AttackPossibility & ap)
|
EvaluationResult(const AttackPossibility & ap)
|
||||||
:wait(false), score(0), bestAttack(ap), defend(false)
|
:wait(false), score(INEFFECTIVE_SCORE), bestAttack(ap), defend(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -29,6 +29,7 @@ public:
|
|||||||
std::vector<const battle::Unit *> enemyStacks;
|
std::vector<const battle::Unit *> enemyStacks;
|
||||||
const CGHeroInstance * ourHero;
|
const CGHeroInstance * ourHero;
|
||||||
const CGHeroInstance * enemyHero;
|
const CGHeroInstance * enemyHero;
|
||||||
|
int turnsSkippedByDefense;
|
||||||
|
|
||||||
BattleStateInfoForRetreat();
|
BattleStateInfoForRetreat();
|
||||||
uint64_t getOurStrength() const;
|
uint64_t getOurStrength() const;
|
||||||
|
Reference in New Issue
Block a user