/* * BattleExchangeVariant.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */ #pragma once #include "../../lib/AI_Base.h" #include "../../lib/battle/ReachabilityInfo.h" #include "PotentialTargets.h" #include "StackWithBonuses.h" struct AttackerValue { int64_t value; bool isRetalitated; BattleHex position; AttackerValue(); }; struct MoveTarget { int64_t score; int64_t scorePerTurn; std::vector positions; std::optional cachedAttack; uint8_t turnsToRich; MoveTarget(); }; struct EvaluationResult { static const int64_t INEFFECTIVE_SCORE = -1000000; AttackPossibility bestAttack; MoveTarget bestMove; bool wait; int64_t score; bool defend; EvaluationResult(const AttackPossibility & ap) :wait(false), score(INEFFECTIVE_SCORE), bestAttack(ap), defend(false) { } }; /// /// The class represents evaluation of attack value /// of exchanges between all stacks which can access particular hex /// starting from initial attack represented by AttackPossibility and further according turn order. /// Negative score value means we get more demage than deal /// class BattleExchangeVariant { public: BattleExchangeVariant(float positiveEffectMultiplier, float negativeEffectMultiplier) : dpsScore(0), positiveEffectMultiplier(positiveEffectMultiplier), negativeEffectMultiplier(negativeEffectMultiplier) {} int64_t trackAttack(const AttackPossibility & ap, HypotheticBattle & state); int64_t trackAttack( std::shared_ptr attacker, std::shared_ptr defender, bool shooting, bool isOurAttack, DamageCache & damageCache, std::shared_ptr hb, bool evaluateOnly = false); int64_t getScore() const { return dpsScore; } void adjustPositions( std::vector attackers, const AttackPossibility & ap, std::map & reachabilityMap); private: float positiveEffectMultiplier; float negativeEffectMultiplier; int64_t dpsScore; std::map attackerValue; }; class BattleExchangeEvaluator { private: std::shared_ptr cb; std::shared_ptr env; std::map> reachabilityMap; std::vector turnOrder; float negativeEffectMultiplier; public: BattleExchangeEvaluator( std::shared_ptr cb, std::shared_ptr env, float strengthRatio): cb(cb), env(env) { negativeEffectMultiplier = strengthRatio; } EvaluationResult findBestTarget( const battle::Unit * activeStack, PotentialTargets & targets, DamageCache & damageCache, std::shared_ptr hb); int64_t calculateExchange( const AttackPossibility & ap, PotentialTargets & targets, DamageCache & damageCache, std::shared_ptr hb); void updateReachabilityMap(std::shared_ptr hb); std::vector getExchangeUnits(const AttackPossibility & ap, PotentialTargets & targets, std::shared_ptr hb); bool checkPositionBlocksOurStacks(HypotheticBattle & hb, const battle::Unit * unit, BattleHex position); MoveTarget findMoveTowardsUnreachable( const battle::Unit * activeStack, PotentialTargets & targets, DamageCache & damageCache, std::shared_ptr hb); std::vector getAdjacentUnits(const battle::Unit * unit); float getPositiveEffectMultiplier() { return 1; } float getNegativeEffectMultiplier() { return negativeEffectMultiplier; } };