mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
BattleAI: fix health bounty calculation
This commit is contained in:
parent
870fbd50e3
commit
f74daa2e1f
@ -114,6 +114,23 @@ float AttackPossibility::attackValue() const
|
||||
return damageDiff();
|
||||
}
|
||||
|
||||
float hpFunction(uint64_t unitHealthStart, uint64_t unitHealthEnd, uint64_t maxHealth)
|
||||
{
|
||||
float ratioStart = static_cast<float>(unitHealthStart) / maxHealth;
|
||||
float ratioEnd = static_cast<float>(unitHealthEnd) / maxHealth;
|
||||
float base = 0.666666f;
|
||||
|
||||
// reduce from max to 0 must be 1.
|
||||
// 10 hp from end costs bit more than 10 hp from start because our goal is to kill unit, not just hurt it
|
||||
// ********** 2 * base - ratioStart *********
|
||||
// * *
|
||||
// * height = ratioStart - ratioEnd *
|
||||
// * *
|
||||
// ******************** 2 * base - ratioEnd ******
|
||||
// S = (a + b) * h / 2
|
||||
return (base * (4 - ratioStart - ratioEnd)) * (ratioStart - ratioEnd) / 2 ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// How enemy damage will be reduced by this attack
|
||||
/// Half bounty for kill, half for making damage equal to enemy health
|
||||
@ -127,6 +144,7 @@ float AttackPossibility::calculateDamageReduce(
|
||||
std::shared_ptr<CBattleInfoCallback> state)
|
||||
{
|
||||
const float HEALTH_BOUNTY = 0.5;
|
||||
const float KILL_BOUNTY = 0.5;
|
||||
|
||||
// FIXME: provide distance info for Jousting bonus
|
||||
auto attackerUnitForMeasurement = attacker;
|
||||
@ -157,9 +175,20 @@ float AttackPossibility::calculateDamageReduce(
|
||||
auto enemyDamageBeforeAttack = damageCache.getOriginalDamage(defender, attackerUnitForMeasurement, state);
|
||||
auto enemiesKilled = damageDealt / maxHealth + (damageDealt % maxHealth >= defender->getFirstHPleft() ? 1 : 0);
|
||||
auto damagePerEnemy = enemyDamageBeforeAttack / (double)defender->getCount();
|
||||
auto lastUnitKillValue = (damageDealt % maxHealth) / (double)maxHealth;;
|
||||
auto exceedingDamage = (damageDealt % maxHealth);
|
||||
float hpValue = (damageDealt / maxHealth);
|
||||
|
||||
return damagePerEnemy * (enemiesKilled + lastUnitKillValue * HEALTH_BOUNTY);
|
||||
if(defender->getFirstHPleft() >= exceedingDamage)
|
||||
{
|
||||
hpValue += hpFunction(defender->getFirstHPleft(), defender->getFirstHPleft() - exceedingDamage, maxHealth);
|
||||
}
|
||||
else
|
||||
{
|
||||
hpValue += hpFunction(defender->getFirstHPleft(), 0, maxHealth);
|
||||
hpValue += hpFunction(maxHealth, maxHealth + defender->getFirstHPleft() - exceedingDamage, maxHealth);
|
||||
}
|
||||
|
||||
return damagePerEnemy * (enemiesKilled * KILL_BOUNTY + hpValue * HEALTH_BOUNTY);
|
||||
}
|
||||
|
||||
int64_t AttackPossibility::evaluateBlockedShootersDmg(
|
||||
|
@ -268,7 +268,7 @@ EvaluationResult BattleExchangeEvaluator::findBestTarget(
|
||||
{
|
||||
float score = evaluateExchange(ap, 0, targets, damageCache, hb);
|
||||
|
||||
if(score > result.score || score == result.score && result.wait)
|
||||
if(score > result.score || (score == result.score && result.wait))
|
||||
{
|
||||
result.score = score;
|
||||
result.bestAttack = ap;
|
||||
@ -558,7 +558,7 @@ BattleScore BattleExchangeEvaluator::calculateExchange(
|
||||
vstd::removeDuplicates(melleeAttackers);
|
||||
vstd::erase_if(melleeAttackers, [&](const battle::Unit * u) -> bool
|
||||
{
|
||||
return !cb->battleCanShoot(u);
|
||||
return cb->battleCanShoot(u);
|
||||
});
|
||||
|
||||
bool canUseAp = true;
|
||||
@ -687,7 +687,10 @@ BattleScore BattleExchangeEvaluator::calculateExchange(
|
||||
for(auto hex : hexes)
|
||||
reachabilityMap[hex] = getOneTurnReachableUnits(turn, hex);
|
||||
|
||||
if(!ap.attack.shooting)
|
||||
{
|
||||
v.adjustPositions(melleeAttackers, ap, reachabilityMap);
|
||||
}
|
||||
|
||||
#if BATTLE_TRACE_LEVEL>=1
|
||||
logAi->trace("Exchange score: enemy: %2f, our -%2f", v.getScore().enemyDamageReduce, v.getScore().ourDamageReduce);
|
||||
@ -714,11 +717,8 @@ void BattleExchangeVariant::adjustPositions(
|
||||
return attackerValue[u1->unitId()].value > attackerValue[u2->unitId()].value;
|
||||
});
|
||||
|
||||
if(!ap.attack.shooting)
|
||||
{
|
||||
vstd::erase_if_present(hexes, ap.from);
|
||||
vstd::erase_if_present(hexes, ap.attack.attacker->occupiedHex(ap.attack.attackerPos));
|
||||
}
|
||||
|
||||
float notRealizedDamage = 0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user