1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-26 22:57:00 +02:00

BattleAI: fix ap calculation in exchange variant

This commit is contained in:
Andrii Danylchenko 2024-08-03 16:07:50 +03:00
parent 3d856bfa9d
commit 801e919e7e
2 changed files with 58 additions and 68 deletions

View File

@ -317,41 +317,42 @@ AttackPossibility AttackPossibility::evaluate(
auto defenderState = defenderStates.at(u->unitId());
int64_t damageDealt;
int64_t damageReceived;
float defenderDamageReduce;
float attackerDamageReduce;
DamageEstimation retaliation;
auto attackDmg = state->battleEstimateDamage(ap.attack, &retaliation);
vstd::amin(attackDmg.damage.min, defenderState->getAvailableHealth());
vstd::amin(attackDmg.damage.max, defenderState->getAvailableHealth());
vstd::amin(retaliation.damage.min, ap.attackerState->getAvailableHealth());
vstd::amin(retaliation.damage.max, ap.attackerState->getAvailableHealth());
damageDealt = averageDmg(attackDmg.damage);
vstd::amin(damageDealt, defenderState->getAvailableHealth());
defenderDamageReduce = calculateDamageReduce(attacker, u, damageDealt, damageCache, state);
ap.attackerState->afterAttack(attackInfo.shooting, false);
//FIXME: use ranged retaliation
damageReceived = 0;
attackerDamageReduce = 0;
if (!attackInfo.shooting && u->unitId() == defender->unitId() && defenderState->ableToRetaliate() && !counterAttacksBlocked)
{
for(auto retaliated : retaliatedUnits)
{
damageReceived = averageDmg(retaliation.damage);
if(retaliated->unitId() == attacker->unitId())
{
int64_t damageReceived = averageDmg(retaliation.damage);
vstd::amin(damageReceived, ap.attackerState->getAvailableHealth());
attackerDamageReduce = calculateDamageReduce(defender, retaliated, damageReceived, damageCache, state);
ap.attackerState->damage(damageReceived);
}
else
{
if(state->battleMatchOwner(defender, u))
auto retaliationCollateral = state->battleEstimateDamage(defender, retaliated, 0);
int64_t damageReceived = averageDmg(retaliationCollateral.damage);
vstd::amin(damageReceived, retaliated->getAvailableHealth());
if(defender->unitSide() == retaliated->unitSide())
defenderDamageReduce += calculateDamageReduce(defender, retaliated, damageReceived, damageCache, state);
else
ap.collateralDamageReduce += calculateDamageReduce(defender, retaliated, damageReceived, damageCache, state);

View File

@ -30,100 +30,89 @@ float BattleExchangeVariant::trackAttack(
{
auto attacker = hb->getForUpdate(ap.attack.attacker->unitId());
const std::string cachingStringBlocksRetaliation = "type_BLOCKS_RETALIATION";
static const auto selectorBlocksRetaliation = Selector::type()(BonusType::BLOCKS_RETALIATION);
const bool counterAttacksBlocked = attacker->hasBonus(selectorBlocksRetaliation, cachingStringBlocksRetaliation);
float attackValue = 0;
float attackValue = ap.attackValue();
auto affectedUnits = ap.affectedUnits;
dpsScore.ourDamageReduce += ap.attackerDamageReduce + ap.collateralDamageReduce;
dpsScore.enemyDamageReduce += ap.defenderDamageReduce + ap.shootersBlockedDmg;
attackerValue[attacker->unitId()].value = attackValue;
affectedUnits.push_back(ap.attackerState);
for(auto affectedUnit : affectedUnits)
{
auto unitToUpdate = hb->getForUpdate(affectedUnit->unitId());
auto damageDealt = unitToUpdate->getTotalHealth() - affectedUnit->getTotalHealth();
if(damageDealt > 0)
{
unitToUpdate->damage(damageDealt);
}
if(unitToUpdate->unitSide() == attacker->unitSide())
{
if(unitToUpdate->unitId() == attacker->unitId())
{
auto defender = hb->getForUpdate(ap.attack.defender->unitId());
if(!defender->alive() || counterAttacksBlocked || ap.attack.shooting || !defender->ableToRetaliate())
continue;
auto retaliationDamage = damageCache.getDamage(defender.get(), unitToUpdate.get(), hb);
auto attackerDamageReduce = AttackPossibility::calculateDamageReduce(defender.get(), unitToUpdate.get(), retaliationDamage, damageCache, hb);
attackValue -= attackerDamageReduce;
dpsScore.ourDamageReduce += attackerDamageReduce;
attackerValue[unitToUpdate->unitId()].isRetaliated = true;
unitToUpdate->damage(retaliationDamage);
defender->afterAttack(false, true);
unitToUpdate->afterAttack(ap.attack.shooting, false);
#if BATTLE_TRACE_LEVEL>=1
logAi->trace(
"%s -> %s, ap retaliation, %s, dps: %2f, score: %2f",
defender->getDescription(),
unitToUpdate->getDescription(),
"%s -> %s, ap retaliation, %s, dps: %lld",
ap.attack.defender->getDescription(),
ap.attack.attacker->getDescription(),
ap.attack.shooting ? "shot" : "mellee",
retaliationDamage,
attackerDamageReduce);
damageDealt);
#endif
}
else
{
auto collateralDamage = damageCache.getDamage(attacker.get(), unitToUpdate.get(), hb);
auto collateralDamageReduce = AttackPossibility::calculateDamageReduce(attacker.get(), unitToUpdate.get(), collateralDamage, damageCache, hb);
attackValue -= collateralDamageReduce;
dpsScore.ourDamageReduce += collateralDamageReduce;
unitToUpdate->damage(collateralDamage);
#if BATTLE_TRACE_LEVEL>=1
logAi->trace(
"%s -> %s, ap collateral, %s, dps: %2f, score: %2f",
attacker->getDescription(),
"%s, ap collateral, dps: %lld",
unitToUpdate->getDescription(),
ap.attack.shooting ? "shot" : "mellee",
collateralDamage,
collateralDamageReduce);
damageDealt);
#endif
}
}
else
{
int64_t attackDamage = damageCache.getDamage(attacker.get(), unitToUpdate.get(), hb);
float defenderDamageReduce = AttackPossibility::calculateDamageReduce(attacker.get(), unitToUpdate.get(), attackDamage, damageCache, hb);
attackValue += defenderDamageReduce;
dpsScore.enemyDamageReduce += defenderDamageReduce;
attackerValue[attacker->unitId()].value += defenderDamageReduce;
unitToUpdate->damage(attackDamage);
if(unitToUpdate->unitId() == ap.attack.defender->unitId())
{
if(unitToUpdate->ableToRetaliate() && !affectedUnit->ableToRetaliate())
{
unitToUpdate->afterAttack(ap.attack.shooting, true);
}
#if BATTLE_TRACE_LEVEL>=1
logAi->trace(
"%s -> %s, ap attack, %s, dps: %2f, score: %2f",
attacker->getDescription(),
unitToUpdate->getDescription(),
ap.attack.shooting ? "shot" : "mellee",
attackDamage,
defenderDamageReduce);
logAi->trace(
"%s -> %s, ap attack, %s, dps: %lld",
attacker->getDescription(),
ap.attack.defender->getDescription(),
ap.attack.shooting ? "shot" : "mellee",
damageDealt);
#endif
}
else
{
#if BATTLE_TRACE_LEVEL>=1
logAi->trace(
"%s, ap enemy collateral, dps: %lld",
unitToUpdate->getDescription(),
damageDealt);
#endif
}
}
}
#if BATTLE_TRACE_LEVEL >= 1
logAi->trace("ap shooters blocking: %lld", ap.shootersBlockedDmg);
logAi->trace(
"ap score: our: %2f, enemy: %2f, collateral: %2f, blocked: %2f",
ap.attackerDamageReduce,
ap.defenderDamageReduce,
ap.collateralDamageReduce,
ap.shootersBlockedDmg);
#endif
attackValue += ap.shootersBlockedDmg;
dpsScore.enemyDamageReduce += ap.shootersBlockedDmg;
attacker->afterAttack(ap.attack.shooting, false);
return attackValue;
}