AttackPossibility.cpp 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  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->counterAttacks.available());
  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.attackerHealth = attacker->healthAfterAttacked(ap.damageReceived);
  42. curBai.defenderHealth = enemy->healthAfterAttacked(ap.damageDealt);
  43. if(curBai.attackerHealth.getCount() <= 0)
  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. return ap;
  49. }
  50. Priorities* AttackPossibility::priorities = nullptr;