PotentialTargets.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /*
  2. * PotentialTargets.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "PotentialTargets.h"
  12. #include "../../lib/CStack.h"//todo: remove
  13. PotentialTargets::PotentialTargets(const battle::Unit * attacker, const HypotheticBattle * state)
  14. {
  15. auto attIter = state->stackStates.find(attacker->unitId());
  16. const battle::Unit * attackerInfo = (attIter == state->stackStates.end()) ? attacker : attIter->second.get();
  17. auto reachability = state->getReachability(attackerInfo);
  18. auto avHexes = state->battleGetAvailableHexes(reachability, attackerInfo);
  19. //FIXME: this should part of battleGetAvailableHexes
  20. bool forceTarget = false;
  21. const battle::Unit * forcedTarget = nullptr;
  22. BattleHex forcedHex;
  23. if(attackerInfo->hasBonusOfType(Bonus::ATTACKS_NEAREST_CREATURE))
  24. {
  25. forceTarget = true;
  26. auto nearest = state->getNearestStack(attackerInfo);
  27. if(nearest.first != nullptr)
  28. {
  29. forcedTarget = nearest.first;
  30. forcedHex = nearest.second;
  31. }
  32. }
  33. auto aliveUnits = state->battleGetUnitsIf([=](const battle::Unit * unit)
  34. {
  35. return unit->isValidTarget() && unit->unitId() != attackerInfo->unitId();
  36. });
  37. for(auto defender : aliveUnits)
  38. {
  39. if(!forceTarget && !state->battleMatchOwner(attackerInfo, defender))
  40. continue;
  41. auto GenerateAttackInfo = [&](bool shooting, BattleHex hex) -> AttackPossibility
  42. {
  43. auto bai = BattleAttackInfo(attackerInfo, defender, shooting);
  44. if(hex.isValid() && !shooting)
  45. bai.chargedFields = reachability.distances[hex];
  46. return AttackPossibility::evaluate(bai, hex, state);
  47. };
  48. if(forceTarget)
  49. {
  50. if(forcedTarget && defender->unitId() == forcedTarget->unitId())
  51. possibleAttacks.push_back(GenerateAttackInfo(false, forcedHex));
  52. else
  53. unreachableEnemies.push_back(defender);
  54. }
  55. else if(state->battleCanShoot(attackerInfo, defender->getPosition()))
  56. {
  57. possibleAttacks.push_back(GenerateAttackInfo(true, BattleHex::INVALID));
  58. }
  59. else
  60. {
  61. for(BattleHex hex : avHexes) {
  62. if(!CStack::isMeleeAttackPossible(attackerInfo, defender, hex))
  63. continue;
  64. auto bai = GenerateAttackInfo(false, hex);
  65. if(!bai.affectedUnits.empty())
  66. possibleAttacks.push_back(bai);
  67. }
  68. if(!vstd::contains_if(possibleAttacks, [=](const AttackPossibility & pa) { return pa.attack.defender->unitId() == defender->unitId(); }))
  69. unreachableEnemies.push_back(defender);
  70. }
  71. }
  72. boost::sort(possibleAttacks, [](const AttackPossibility & lhs, const AttackPossibility & rhs) -> bool
  73. {
  74. if(lhs.collateralDamage < rhs.collateralDamage)
  75. return false;
  76. if(lhs.collateralDamage > rhs.collateralDamage)
  77. return true;
  78. return (lhs.damageDealt + lhs.shootersBlockedDmg + lhs.damageReceived > rhs.damageDealt + rhs.shootersBlockedDmg + rhs.damageReceived);
  79. });
  80. if (!possibleAttacks.empty())
  81. {
  82. auto &bestAp = possibleAttacks[0];
  83. logGlobal->info("Battle AI best: %s -> %s at %d from %d, affects %d units: %d %d %d %s",
  84. VLC->creh->creatures.at(bestAp.attackerState->creatureId())->identifier.c_str(),
  85. VLC->creh->creatures.at(state->battleGetUnitByPos(bestAp.dest)->creatureId())->identifier.c_str(),
  86. (int)bestAp.dest, (int)bestAp.from, (int)bestAp.affectedUnits.size(),
  87. (int)bestAp.damageDealt, (int)bestAp.damageReceived, (int)bestAp.collateralDamage, (int)bestAp.shootersBlockedDmg);
  88. }
  89. }
  90. int64_t PotentialTargets::bestActionValue() const
  91. {
  92. if(possibleAttacks.empty())
  93. return 0;
  94. return bestAction().attackValue();
  95. }
  96. AttackPossibility PotentialTargets::bestAction() const
  97. {
  98. if(possibleAttacks.empty())
  99. throw std::runtime_error("No best action, since we don't have any actions");
  100. return possibleAttacks[0];
  101. //return *vstd::maxElementByFun(possibleAttacks, [](const AttackPossibility &ap) { return ap.attackValue(); } );
  102. }