PotentialTargets.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  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. #include "../../lib/mapObjects/CGTownInstance.h"
  14. PotentialTargets::PotentialTargets(
  15. const battle::Unit * attacker,
  16. DamageCache & damageCache,
  17. std::shared_ptr<HypotheticBattle> state)
  18. {
  19. auto attackerInfo = state->battleGetUnitByID(attacker->unitId());
  20. auto reachability = state->getReachability(attackerInfo);
  21. auto avHexes = state->battleGetAvailableHexes(reachability, attackerInfo, false);
  22. //FIXME: this should part of battleGetAvailableHexes
  23. bool isBerserk = attackerInfo->hasBonusOfType(BonusType::ATTACKS_NEAREST_CREATURE);
  24. ForcedAction forcedAction = {};
  25. if(isBerserk)
  26. forcedAction = state->getBerserkForcedAction(attackerInfo);
  27. auto aliveUnits = state->battleGetUnitsIf([=](const battle::Unit * unit)
  28. {
  29. return unit->isValidTarget() && unit->unitId() != attackerInfo->unitId();
  30. });
  31. for(auto defender : aliveUnits)
  32. {
  33. if(!isBerserk && !state->battleMatchOwner(attackerInfo, defender))
  34. continue;
  35. auto GenerateAttackInfo = [&](bool shooting, const BattleHex & hex) -> AttackPossibility
  36. {
  37. int distance = hex.isValid() ? reachability.distances[hex.toInt()] : 0;
  38. auto bai = BattleAttackInfo(attackerInfo, defender, distance, shooting);
  39. return AttackPossibility::evaluate(bai, hex, damageCache, state);
  40. };
  41. if(isBerserk)
  42. {
  43. bool isActionAttack = forcedAction.type == EActionType::WALK_AND_ATTACK || forcedAction.type == EActionType::SHOOT;
  44. if (isActionAttack && defender->unitId() == forcedAction.target->unitId())
  45. {
  46. bool rangeAttack = forcedAction.type == EActionType::SHOOT;
  47. BattleHex hex = forcedAction.type == EActionType::WALK_AND_ATTACK ? forcedAction.position : BattleHex::INVALID;
  48. possibleAttacks.push_back(GenerateAttackInfo(rangeAttack, hex));
  49. }
  50. else
  51. {
  52. unreachableEnemies.push_back(defender);
  53. }
  54. }
  55. else if(state->battleCanShoot(attackerInfo, defender->getPosition()))
  56. {
  57. possibleAttacks.push_back(GenerateAttackInfo(true, BattleHex::INVALID));
  58. }
  59. else
  60. {
  61. for(const BattleHex & hex : avHexes)
  62. {
  63. if(!CStack::isMeleeAttackPossible(attackerInfo, defender, hex))
  64. continue;
  65. auto bai = GenerateAttackInfo(false, hex);
  66. if(!bai.affectedUnits.empty())
  67. possibleAttacks.push_back(bai);
  68. }
  69. if(!vstd::contains_if(possibleAttacks, [=](const AttackPossibility & pa) { return pa.attack.defender->unitId() == defender->unitId(); }))
  70. unreachableEnemies.push_back(defender);
  71. }
  72. }
  73. boost::sort(possibleAttacks, [](const AttackPossibility & lhs, const AttackPossibility & rhs) -> bool
  74. {
  75. return lhs.damageDiff() > rhs.damageDiff();
  76. });
  77. }
  78. int64_t PotentialTargets::bestActionValue() const
  79. {
  80. if(possibleAttacks.empty())
  81. return 0;
  82. return bestAction().attackValue();
  83. }
  84. const AttackPossibility & PotentialTargets::bestAction() const
  85. {
  86. if(possibleAttacks.empty())
  87. throw std::runtime_error("No best action, since we don't have any actions");
  88. return possibleAttacks.front();
  89. }