1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

BattleAI: divide only positive part of score onto turns count

This commit is contained in:
Andrii Danylchenko 2023-10-03 08:16:12 +03:00
parent 3880ea58b9
commit 9eb9404f28
4 changed files with 187 additions and 55 deletions

View File

@ -190,6 +190,14 @@ BattleAction BattleEvaluator::selectStackAction(const CStack * stack)
if(stack->waited()) if(stack->waited())
{ {
logAi->debug(
"Moving %s towards hex %s[%d], score: %2f/%2f",
stack->getDescription(),
moveTarget.cachedAttack->attack.defender->getDescription(),
moveTarget.cachedAttack->attack.defender->getPosition().hex,
moveTarget.score,
moveTarget.scorePerTurn);
return goTowardsNearest(stack, moveTarget.positions); return goTowardsNearest(stack, moveTarget.positions);
} }
else else
@ -572,7 +580,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
} }
else else
{ {
ps.value = scoreEvaluator.calculateExchange(*cachedAttack, *targets, innerCache, state); ps.value = scoreEvaluator.evaluateExchange(*cachedAttack, *targets, innerCache, state);
} }
for(auto unit : allUnits) for(auto unit : allUnits)

View File

@ -18,10 +18,8 @@ AttackerValue::AttackerValue()
} }
MoveTarget::MoveTarget() MoveTarget::MoveTarget()
: positions(), cachedAttack() : positions(), cachedAttack(), score(EvaluationResult::INEFFECTIVE_SCORE), scorePerTurn(EvaluationResult::INEFFECTIVE_SCORE)
{ {
score = EvaluationResult::INEFFECTIVE_SCORE;
scorePerTurn = EvaluationResult::INEFFECTIVE_SCORE;
turnsToRich = 1; turnsToRich = 1;
} }
@ -58,7 +56,7 @@ float BattleExchangeVariant::trackAttack(
auto attackerDamageReduce = AttackPossibility::calculateDamageReduce(defender.get(), unitToUpdate.get(), retaliationDamage, damageCache, hb); auto attackerDamageReduce = AttackPossibility::calculateDamageReduce(defender.get(), unitToUpdate.get(), retaliationDamage, damageCache, hb);
attackValue -= attackerDamageReduce; attackValue -= attackerDamageReduce;
dpsScore -= attackerDamageReduce * negativeEffectMultiplier; dpsScore.ourDamageReduce += attackerDamageReduce;
attackerValue[unitToUpdate->unitId()].isRetalitated = true; attackerValue[unitToUpdate->unitId()].isRetalitated = true;
unitToUpdate->damage(retaliationDamage); unitToUpdate->damage(retaliationDamage);
@ -80,7 +78,7 @@ float BattleExchangeVariant::trackAttack(
auto collateralDamageReduce = AttackPossibility::calculateDamageReduce(attacker.get(), unitToUpdate.get(), collateralDamage, damageCache, hb); auto collateralDamageReduce = AttackPossibility::calculateDamageReduce(attacker.get(), unitToUpdate.get(), collateralDamage, damageCache, hb);
attackValue -= collateralDamageReduce; attackValue -= collateralDamageReduce;
dpsScore -= collateralDamageReduce * negativeEffectMultiplier; dpsScore.ourDamageReduce += collateralDamageReduce;
unitToUpdate->damage(collateralDamage); unitToUpdate->damage(collateralDamage);
@ -101,7 +99,7 @@ float BattleExchangeVariant::trackAttack(
float defenderDamageReduce = AttackPossibility::calculateDamageReduce(attacker.get(), unitToUpdate.get(), attackDamage, damageCache, hb); float defenderDamageReduce = AttackPossibility::calculateDamageReduce(attacker.get(), unitToUpdate.get(), attackDamage, damageCache, hb);
attackValue += defenderDamageReduce; attackValue += defenderDamageReduce;
dpsScore += defenderDamageReduce * positiveEffectMultiplier; dpsScore.enemyDamageReduce += defenderDamageReduce;
attackerValue[attacker->unitId()].value += defenderDamageReduce; attackerValue[attacker->unitId()].value += defenderDamageReduce;
unitToUpdate->damage(attackDamage); unitToUpdate->damage(attackDamage);
@ -119,7 +117,7 @@ float BattleExchangeVariant::trackAttack(
} }
attackValue += ap.shootersBlockedDmg; attackValue += ap.shootersBlockedDmg;
dpsScore += ap.shootersBlockedDmg * positiveEffectMultiplier; dpsScore.enemyDamageReduce += ap.shootersBlockedDmg;
attacker->afterAttack(ap.attack.shooting, false); attacker->afterAttack(ap.attack.shooting, false);
return attackValue; return attackValue;
@ -156,11 +154,11 @@ float BattleExchangeVariant::trackAttack(
if(isOurAttack) if(isOurAttack)
{ {
dpsScore += defenderDamageReduce * positiveEffectMultiplier; dpsScore.enemyDamageReduce += defenderDamageReduce;
attackerValue[attacker->unitId()].value += defenderDamageReduce; attackerValue[attacker->unitId()].value += defenderDamageReduce;
} }
else else
dpsScore -= defenderDamageReduce * negativeEffectMultiplier; dpsScore.ourDamageReduce += defenderDamageReduce;
defender->damage(attackDamage); defender->damage(attackDamage);
attacker->afterAttack(shooting, false); attacker->afterAttack(shooting, false);
@ -182,12 +180,12 @@ float BattleExchangeVariant::trackAttack(
if(isOurAttack) if(isOurAttack)
{ {
dpsScore -= attackerDamageReduce * negativeEffectMultiplier; dpsScore.ourDamageReduce += attackerDamageReduce;
attackerValue[attacker->unitId()].isRetalitated = true; attackerValue[attacker->unitId()].isRetalitated = true;
} }
else else
{ {
dpsScore += attackerDamageReduce * positiveEffectMultiplier; dpsScore.enemyDamageReduce += attackerDamageReduce;
attackerValue[defender->unitId()].value += attackerDamageReduce; attackerValue[defender->unitId()].value += attackerDamageReduce;
} }
@ -200,13 +198,18 @@ float BattleExchangeVariant::trackAttack(
#if BATTLE_TRACE_LEVEL>=1 #if BATTLE_TRACE_LEVEL>=1
if(!score) if(!score)
{ {
logAi->trace("Attack has zero score d:%2f a:%2f", defenderDamageReduce, attackerDamageReduce); logAi->trace("Attack has zero score def:%2f att:%2f", defenderDamageReduce, attackerDamageReduce);
} }
#endif #endif
return score; return score;
} }
float BattleExchangeEvaluator::scoreValue(const BattleScore & score) const
{
return score.enemyDamageReduce * getPositiveEffectMultiplier() - score.ourDamageReduce * getNegativeEffectMultiplier();
}
EvaluationResult BattleExchangeEvaluator::findBestTarget( EvaluationResult BattleExchangeEvaluator::findBestTarget(
const battle::Unit * activeStack, const battle::Unit * activeStack,
PotentialTargets & targets, PotentialTargets & targets,
@ -215,7 +218,7 @@ EvaluationResult BattleExchangeEvaluator::findBestTarget(
{ {
EvaluationResult result(targets.bestAction()); EvaluationResult result(targets.bestAction());
if(!activeStack->waited()) if(!activeStack->waited() && !activeStack->acquireState()->hadMorale)
{ {
#if BATTLE_TRACE_LEVEL>=1 #if BATTLE_TRACE_LEVEL>=1
logAi->trace("Evaluating waited attack for %s", activeStack->getDescription()); logAi->trace("Evaluating waited attack for %s", activeStack->getDescription());
@ -230,7 +233,7 @@ EvaluationResult BattleExchangeEvaluator::findBestTarget(
for(auto & ap : targets.possibleAttacks) for(auto & ap : targets.possibleAttacks)
{ {
float score = calculateExchange(ap, targets, damageCache, hbWaited); float score = evaluateExchange(ap, targets, damageCache, hbWaited);
if(score > result.score) if(score > result.score)
{ {
@ -247,9 +250,15 @@ EvaluationResult BattleExchangeEvaluator::findBestTarget(
updateReachabilityMap(hb); updateReachabilityMap(hb);
if(result.bestAttack.attack.shooting && hb->battleHasShootingPenalty(activeStack, result.bestAttack.dest))
{
if(!canBeHitThisTurn(result.bestAttack))
return result; // lets wait
}
for(auto & ap : targets.possibleAttacks) for(auto & ap : targets.possibleAttacks)
{ {
float score = calculateExchange(ap, targets, damageCache, hb); float score = evaluateExchange(ap, targets, damageCache, hb);
if(score >= result.score) if(score >= result.score)
{ {
@ -269,7 +278,7 @@ MoveTarget BattleExchangeEvaluator::findMoveTowardsUnreachable(
std::shared_ptr<HypotheticBattle> hb) std::shared_ptr<HypotheticBattle> hb)
{ {
MoveTarget result; MoveTarget result;
BattleExchangeVariant ev(getPositiveEffectMultiplier(), getNegativeEffectMultiplier()); BattleExchangeVariant ev;
if(targets.unreachableEnemies.empty()) if(targets.unreachableEnemies.empty())
return result; return result;
@ -301,6 +310,9 @@ MoveTarget BattleExchangeEvaluator::findMoveTowardsUnreachable(
auto turnsToRich = (distance - 1) / speed + 1; auto turnsToRich = (distance - 1) / speed + 1;
auto hexes = closestStack->getSurroundingHexes(); auto hexes = closestStack->getSurroundingHexes();
auto enemySpeed = closestStack->speed();
auto speedRatio = speed / static_cast<float>(enemySpeed);
auto penalty = speedRatio > 1 ? 1 : speedRatio;
for(auto hex : hexes) for(auto hex : hexes)
{ {
@ -310,13 +322,13 @@ MoveTarget BattleExchangeEvaluator::findMoveTowardsUnreachable(
attack.shootersBlockedDmg = 0; // we do not want to count on it, it is not for sure attack.shootersBlockedDmg = 0; // we do not want to count on it, it is not for sure
auto score = calculateExchange(attack, targets, damageCache, hb); auto score = calculateExchange(attack, turnsToRich, targets, damageCache, hb);
auto scorePerTurn = score / turnsToRich; auto scorePerTurn = BattleScore(score.enemyDamageReduce * std::sqrt(penalty / turnsToRich), score.ourDamageReduce);
if(result.scorePerTurn < scorePerTurn) if(result.scorePerTurn < scoreValue(scorePerTurn))
{ {
result.scorePerTurn = scorePerTurn; result.scorePerTurn = scoreValue(scorePerTurn);
result.score = score; result.score = scoreValue(score);
result.positions = closestStack->getAttackableHexes(activeStack); result.positions = closestStack->getAttackableHexes(activeStack);
result.cachedAttack = attack; result.cachedAttack = attack;
result.turnsToRich = turnsToRich; result.turnsToRich = turnsToRich;
@ -357,16 +369,17 @@ std::vector<const battle::Unit *> BattleExchangeEvaluator::getAdjacentUnits(cons
return checkedStacks; return checkedStacks;
} }
std::vector<const battle::Unit *> BattleExchangeEvaluator::getExchangeUnits( ReachabilityData BattleExchangeEvaluator::getExchangeUnits(
const AttackPossibility & ap, const AttackPossibility & ap,
PotentialTargets & targets, PotentialTargets & targets,
std::shared_ptr<HypotheticBattle> hb) std::shared_ptr<HypotheticBattle> hb)
{ {
ReachabilityData result;
auto hexes = ap.attack.defender->getHexes(); auto hexes = ap.attack.defender->getHexes();
if(!ap.attack.shooting) hexes.push_back(ap.from); if(!ap.attack.shooting) hexes.push_back(ap.from);
std::vector<const battle::Unit *> exchangeUnits;
std::vector<const battle::Unit *> allReachableUnits; std::vector<const battle::Unit *> allReachableUnits;
for(auto hex : hexes) for(auto hex : hexes)
@ -404,7 +417,28 @@ std::vector<const battle::Unit *> BattleExchangeEvaluator::getExchangeUnits(
logAi->trace("Reachability map contains only %d stacks", allReachableUnits.size()); logAi->trace("Reachability map contains only %d stacks", allReachableUnits.size());
#endif #endif
return exchangeUnits; return result;
}
for(auto unit : allReachableUnits)
{
auto accessible = !unit->canShoot();
if(!accessible)
{
for(auto hex : unit->getSurroundingHexes())
{
if(ap.attack.defender->coversPos(hex))
{
accessible = true;
}
}
}
if(accessible)
result.melleeAccessible.push_back(unit);
else
result.shooters.push_back(unit);
} }
for(int turn = 0; turn < turnOrder.size(); turn++) for(int turn = 0; turn < turnOrder.size(); turn++)
@ -412,19 +446,30 @@ std::vector<const battle::Unit *> BattleExchangeEvaluator::getExchangeUnits(
for(auto unit : turnOrder[turn]) for(auto unit : turnOrder[turn])
{ {
if(vstd::contains(allReachableUnits, unit)) if(vstd::contains(allReachableUnits, unit))
exchangeUnits.push_back(unit); result.units.push_back(unit);
} }
} }
vstd::erase_if(exchangeUnits, [&](const battle::Unit * u) -> bool vstd::erase_if(result.units, [&](const battle::Unit * u) -> bool
{ {
return !hb->battleGetUnitByID(u->unitId())->alive(); return !hb->battleGetUnitByID(u->unitId())->alive();
}); });
return exchangeUnits; return result;
} }
float BattleExchangeEvaluator::calculateExchange( float BattleExchangeEvaluator::evaluateExchange(
const AttackPossibility & ap,
PotentialTargets & targets,
DamageCache & damageCache,
std::shared_ptr<HypotheticBattle> hb)
{
BattleScore score = calculateExchange(ap, targets, damageCache, hb);
return scoreValue(score);
}
BattleScore BattleExchangeEvaluator::calculateExchange(
const AttackPossibility & ap, const AttackPossibility & ap,
PotentialTargets & targets, PotentialTargets & targets,
DamageCache & damageCache, DamageCache & damageCache,
@ -438,7 +483,7 @@ float BattleExchangeEvaluator::calculateExchange(
&& cb->battleGetGateState() == EGateState::BLOCKED && cb->battleGetGateState() == EGateState::BLOCKED
&& ap.attack.defender->coversPos(BattleHex::GATE_BRIDGE)) && ap.attack.defender->coversPos(BattleHex::GATE_BRIDGE))
{ {
return EvaluationResult::INEFFECTIVE_SCORE; return BattleScore(EvaluationResult::INEFFECTIVE_SCORE, 0);
} }
std::vector<const battle::Unit *> ourStacks; std::vector<const battle::Unit *> ourStacks;
@ -447,17 +492,19 @@ float BattleExchangeEvaluator::calculateExchange(
if(hb->battleGetUnitByID(ap.attack.defender->unitId())->alive()) if(hb->battleGetUnitByID(ap.attack.defender->unitId())->alive())
enemyStacks.push_back(ap.attack.defender); enemyStacks.push_back(ap.attack.defender);
std::vector<const battle::Unit *> exchangeUnits = getExchangeUnits(ap, targets, hb); vstd::amin(turn, reachabilityMapByTurns.size() - 1);
if(exchangeUnits.empty()) ReachabilityData exchangeUnits = getExchangeUnits(ap, turn, targets, hb);
if(exchangeUnits.units.empty())
{ {
return 0; return BattleScore();
} }
auto exchangeBattle = std::make_shared<HypotheticBattle>(env.get(), hb); auto exchangeBattle = std::make_shared<HypotheticBattle>(env.get(), hb);
BattleExchangeVariant v(getPositiveEffectMultiplier(), getNegativeEffectMultiplier()); BattleExchangeVariant v;
for(auto unit : exchangeUnits) for(auto unit : exchangeUnits.units)
{ {
if(unit->isTurret()) if(unit->isTurret())
continue; continue;
@ -481,7 +528,7 @@ float BattleExchangeEvaluator::calculateExchange(
bool canUseAp = true; bool canUseAp = true;
for(auto activeUnit : exchangeUnits) for(auto activeUnit : exchangeUnits.units)
{ {
bool isOur = exchangeBattle->battleMatchOwner(ap.attack.attacker, activeUnit, true); bool isOur = exchangeBattle->battleMatchOwner(ap.attack.attacker, activeUnit, true);
battle::Units & attackerQueue = isOur ? ourStacks : enemyStacks; battle::Units & attackerQueue = isOur ? ourStacks : enemyStacks;
@ -521,9 +568,16 @@ float BattleExchangeEvaluator::calculateExchange(
return score; return score;
}; };
if(!oppositeQueue.empty()) auto unitsInOppositeQueueExceptInaccessible = oppositeQueue;
vstd::erase_if(unitsInOppositeQueueExceptInaccessible, [&](const battle::Unit * u)->bool
{ {
targetUnit = *vstd::maxElementByFun(oppositeQueue, estimateAttack); return vstd::contains(exchangeUnits.shooters, u);
});
if(!unitsInOppositeQueueExceptInaccessible.empty())
{
targetUnit = *vstd::maxElementByFun(unitsInOppositeQueueExceptInaccessible, estimateAttack);
} }
else else
{ {
@ -594,7 +648,7 @@ float BattleExchangeEvaluator::calculateExchange(
v.adjustPositions(melleeAttackers, ap, reachabilityMap); v.adjustPositions(melleeAttackers, ap, reachabilityMap);
#if BATTLE_TRACE_LEVEL>=1 #if BATTLE_TRACE_LEVEL>=1
logAi->trace("Exchange score: %2f", v.getScore()); logAi->trace("Exchange score: enemy: %2f, our -%2f", v.getScore().enemyDamageReduce, v.getScore().ourDamageReduce);
#endif #endif
return v.getScore(); return v.getScore();
@ -662,10 +716,26 @@ void BattleExchangeVariant::adjustPositions(
if(notRealizedDamage > ap.attackValue() && notRealizedDamage > attackerValue[ap.attack.attacker->unitId()].value) if(notRealizedDamage > ap.attackValue() && notRealizedDamage > attackerValue[ap.attack.attacker->unitId()].value)
{ {
dpsScore = EvaluationResult::INEFFECTIVE_SCORE; dpsScore = BattleScore(EvaluationResult::INEFFECTIVE_SCORE, 0);
} }
} }
bool BattleExchangeEvaluator::canBeHitThisTurn(const AttackPossibility & ap)
{
for(auto pos : ap.attack.attacker->getSurroundingHexes())
{
for(auto u : reachabilityMap[pos])
{
if(u->unitSide() != ap.attack.attacker->unitSide())
{
return true;
}
}
}
return false;
}
void BattleExchangeEvaluator::updateReachabilityMap( std::shared_ptr<HypotheticBattle> hb) void BattleExchangeEvaluator::updateReachabilityMap( std::shared_ptr<HypotheticBattle> hb)
{ {
const int TURN_DEPTH = 2; const int TURN_DEPTH = 2;

View File

@ -14,6 +14,34 @@
#include "PotentialTargets.h" #include "PotentialTargets.h"
#include "StackWithBonuses.h" #include "StackWithBonuses.h"
struct BattleScore
{
float ourDamageReduce;
float enemyDamageReduce;
BattleScore(float enemyDamageReduce, float ourDamageReduce)
:enemyDamageReduce(enemyDamageReduce), ourDamageReduce(ourDamageReduce)
{
}
BattleScore() : BattleScore(0, 0) {}
float value()
{
return enemyDamageReduce - ourDamageReduce;
}
BattleScore operator+(BattleScore & other)
{
BattleScore result = *this;
result.ourDamageReduce += other.ourDamageReduce;
result.enemyDamageReduce += other.enemyDamageReduce;
return result;
}
};
struct AttackerValue struct AttackerValue
{ {
float value; float value;
@ -59,8 +87,8 @@ struct EvaluationResult
class BattleExchangeVariant class BattleExchangeVariant
{ {
public: public:
BattleExchangeVariant(float positiveEffectMultiplier, float negativeEffectMultiplier) BattleExchangeVariant()
: dpsScore(0), positiveEffectMultiplier(positiveEffectMultiplier), negativeEffectMultiplier(negativeEffectMultiplier) {} : dpsScore() {}
float trackAttack( float trackAttack(
const AttackPossibility & ap, const AttackPossibility & ap,
@ -76,7 +104,7 @@ public:
std::shared_ptr<HypotheticBattle> hb, std::shared_ptr<HypotheticBattle> hb,
bool evaluateOnly = false); bool evaluateOnly = false);
float getScore() const { return dpsScore; } const BattleScore & getScore() const { return dpsScore; }
void adjustPositions( void adjustPositions(
std::vector<const battle::Unit *> attackers, std::vector<const battle::Unit *> attackers,
@ -84,12 +112,21 @@ public:
std::map<BattleHex, battle::Units> & reachabilityMap); std::map<BattleHex, battle::Units> & reachabilityMap);
private: private:
float positiveEffectMultiplier; BattleScore dpsScore;
float negativeEffectMultiplier;
float dpsScore;
std::map<uint32_t, AttackerValue> attackerValue; std::map<uint32_t, AttackerValue> attackerValue;
}; };
struct ReachabilityData
{
std::vector<const battle::Unit *> units;
// shooters which are within mellee attack and mellee units
std::vector<const battle::Unit *> melleeAccessible;
// far shooters
std::vector<const battle::Unit *> shooters;
};
class BattleExchangeEvaluator class BattleExchangeEvaluator
{ {
private: private:
@ -99,12 +136,22 @@ private:
std::vector<battle::Units> turnOrder; std::vector<battle::Units> turnOrder;
float negativeEffectMultiplier; float negativeEffectMultiplier;
float scoreValue(const BattleScore & score) const;
BattleScore calculateExchange(
const AttackPossibility & ap,
PotentialTargets & targets,
DamageCache & damageCache,
std::shared_ptr<HypotheticBattle> hb);
bool canBeHitThisTurn(const AttackPossibility & ap);
public: public:
BattleExchangeEvaluator( BattleExchangeEvaluator(
std::shared_ptr<CBattleInfoCallback> cb, std::shared_ptr<CBattleInfoCallback> cb,
std::shared_ptr<Environment> env, std::shared_ptr<Environment> env,
float strengthRatio): cb(cb), env(env) { float strengthRatio): cb(cb), env(env) {
negativeEffectMultiplier = strengthRatio; negativeEffectMultiplier = std::sqrt(strengthRatio);
} }
EvaluationResult findBestTarget( EvaluationResult findBestTarget(
@ -113,14 +160,20 @@ public:
DamageCache & damageCache, DamageCache & damageCache,
std::shared_ptr<HypotheticBattle> hb); std::shared_ptr<HypotheticBattle> hb);
float calculateExchange( float evaluateExchange(
const AttackPossibility & ap, const AttackPossibility & ap,
PotentialTargets & targets, PotentialTargets & targets,
DamageCache & damageCache, DamageCache & damageCache,
std::shared_ptr<HypotheticBattle> hb); std::shared_ptr<HypotheticBattle> hb);
void updateReachabilityMap(std::shared_ptr<HypotheticBattle> hb); void updateReachabilityMap(std::shared_ptr<HypotheticBattle> hb);
std::vector<const battle::Unit *> getExchangeUnits(const AttackPossibility & ap, PotentialTargets & targets, std::shared_ptr<HypotheticBattle> hb);
ReachabilityData getExchangeUnits(
const AttackPossibility & ap,
uint8_t turn,
PotentialTargets & targets,
std::shared_ptr<HypotheticBattle> hb);
bool checkPositionBlocksOurStacks(HypotheticBattle & hb, const battle::Unit * unit, BattleHex position); bool checkPositionBlocksOurStacks(HypotheticBattle & hb, const battle::Unit * unit, BattleHex position);
MoveTarget findMoveTowardsUnreachable( MoveTarget findMoveTowardsUnreachable(
@ -131,6 +184,6 @@ public:
std::vector<const battle::Unit *> getAdjacentUnits(const battle::Unit * unit); std::vector<const battle::Unit *> getAdjacentUnits(const battle::Unit * unit);
float getPositiveEffectMultiplier() { return 1; } float getPositiveEffectMultiplier() const { return 1; }
float getNegativeEffectMultiplier() { return negativeEffectMultiplier; } float getNegativeEffectMultiplier() const { return negativeEffectMultiplier; }
}; };

View File

@ -274,6 +274,7 @@ void Nullkiller::makeTurn()
bestTask = choseBestTask(bestTasks); bestTask = choseBestTask(bestTasks);
std::string taskDescription = bestTask->toString();
HeroPtr hero = bestTask->getHero(); HeroPtr hero = bestTask->getHero();
HeroRole heroRole = HeroRole::MAIN; HeroRole heroRole = HeroRole::MAIN;
@ -292,7 +293,7 @@ void Nullkiller::makeTurn()
logAi->trace( logAi->trace(
"Goal %s has low priority %f so decreasing scan depth to gain performance.", "Goal %s has low priority %f so decreasing scan depth to gain performance.",
bestTask->toString(), taskDescription,
bestTask->priority); bestTask->priority);
} }
@ -308,7 +309,7 @@ void Nullkiller::makeTurn()
{ {
logAi->trace( logAi->trace(
"Goal %s has too low priority %f so increasing scan depth to full.", "Goal %s has too low priority %f so increasing scan depth to full.",
bestTask->toString(), taskDescription,
bestTask->priority); bestTask->priority);
scanDepth = ScanDepth::ALL_FULL; scanDepth = ScanDepth::ALL_FULL;
@ -316,7 +317,7 @@ void Nullkiller::makeTurn()
continue; continue;
} }
logAi->trace("Goal %s has too low priority. It is not worth doing it. Ending turn.", bestTask->toString()); logAi->trace("Goal %s has too low priority. It is not worth doing it. Ending turn.", taskDescription);
return; return;
} }
@ -325,7 +326,7 @@ void Nullkiller::makeTurn()
if(i == MAXPASS) if(i == MAXPASS)
{ {
logAi->error("Goal %s exceeded maxpass. Terminating AI turn.", bestTask->toString()); logAi->error("Goal %s exceeded maxpass. Terminating AI turn.", taskDescription);
} }
} }
} }