AttackPossibility.cpp 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. /*
  2. * AttackPossibility.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 "AttackPossibility.h"
  12. int AttackPossibility::damageDiff() const
  13. {
  14. if (!priorities)
  15. priorities = new Priorities;
  16. const auto dealtDmgValue = priorities->stackEvaluator(enemy) * damageDealt;
  17. const auto receivedDmgValue = priorities->stackEvaluator(attack.attacker) * damageReceived;
  18. return dealtDmgValue - receivedDmgValue;
  19. }
  20. int AttackPossibility::attackValue() const
  21. {
  22. return damageDiff() + tacticImpact;
  23. }
  24. AttackPossibility AttackPossibility::evaluate(const BattleAttackInfo &AttackInfo, const HypotheticChangesToBattleState &state, BattleHex hex)
  25. {
  26. auto attacker = AttackInfo.attacker;
  27. auto enemy = AttackInfo.defender;
  28. const int remainingCounterAttacks = getValOr(state.counterAttacksLeft, enemy, enemy->counterAttacksRemaining());
  29. const bool counterAttacksBlocked = attacker->hasBonusOfType(Bonus::BLOCKS_RETALIATION) || enemy->hasBonusOfType(Bonus::NO_RETALIATION);
  30. const int totalAttacks = 1 + AttackInfo.attackerBonuses->getBonuses(Selector::type(Bonus::ADDITIONAL_ATTACK), (Selector::effectRange (Bonus::NO_LIMIT).Or(Selector::effectRange(Bonus::ONLY_MELEE_FIGHT))))->totalValue();
  31. AttackPossibility ap = {enemy, hex, AttackInfo, 0, 0, 0};
  32. auto curBai = AttackInfo; //we'll modify here the stack counts
  33. for(int i = 0; i < totalAttacks; i++)
  34. {
  35. std::pair<ui32, ui32> retaliation(0,0);
  36. auto attackDmg = getCbc()->battleEstimateDamage(CRandomGenerator::getDefault(), curBai, &retaliation);
  37. ap.damageDealt = (attackDmg.first + attackDmg.second) / 2;
  38. ap.damageReceived = (retaliation.first + retaliation.second) / 2;
  39. if(remainingCounterAttacks <= i || counterAttacksBlocked)
  40. ap.damageReceived = 0;
  41. curBai.attackerCount = attacker->count - attacker->countKilledByAttack(ap.damageReceived).first;
  42. curBai.defenderCount = enemy->count - enemy->countKilledByAttack(ap.damageDealt).first;
  43. if(!curBai.attackerCount)
  44. break;
  45. //TODO what about defender? should we break? but in pessimistic scenario defender might be alive
  46. }
  47. //TODO other damage related to attack (eg. fire shield and other abilities)
  48. //Limit damages by total stack health
  49. vstd::amin(ap.damageDealt, enemy->count * enemy->MaxHealth() - (enemy->MaxHealth() - enemy->firstHPleft));
  50. vstd::amin(ap.damageReceived, attacker->count * attacker->MaxHealth() - (attacker->MaxHealth() - attacker->firstHPleft));
  51. return ap;
  52. }
  53. Priorities* AttackPossibility::priorities = nullptr;