| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 | 
							- /*
 
-  * PotentialTargets.cpp, 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
 
-  *
 
-  */
 
- #include "StdInc.h"
 
- #include "PotentialTargets.h"
 
- #include "../../lib/CStack.h"//todo: remove
 
- PotentialTargets::PotentialTargets(const battle::Unit * attacker, const HypotheticBattle & state)
 
- {
 
- 	auto attackerInfo = state.battleGetUnitByID(attacker->unitId());
 
- 	auto reachability = state.getReachability(attackerInfo);
 
- 	auto avHexes = state.battleGetAvailableHexes(reachability, attackerInfo);
 
- 	//FIXME: this should part of battleGetAvailableHexes
 
- 	bool forceTarget = false;
 
- 	const battle::Unit * forcedTarget = nullptr;
 
- 	BattleHex forcedHex;
 
- 	if(attackerInfo->hasBonusOfType(Bonus::ATTACKS_NEAREST_CREATURE))
 
- 	{
 
- 		forceTarget = true;
 
- 		auto nearest = state.getNearestStack(attackerInfo);
 
- 		if(nearest.first != nullptr)
 
- 		{
 
- 			forcedTarget = nearest.first;
 
- 			forcedHex = nearest.second;
 
- 		}
 
- 	}
 
- 	auto aliveUnits = state.battleGetUnitsIf([=](const battle::Unit * unit)
 
- 	{
 
- 		return unit->isValidTarget() && unit->unitId() != attackerInfo->unitId();
 
- 	});
 
- 	for(auto defender : aliveUnits)
 
- 	{
 
- 		if(!forceTarget && !state.battleMatchOwner(attackerInfo, defender))
 
- 			continue;
 
- 		auto GenerateAttackInfo = [&](bool shooting, BattleHex hex) -> AttackPossibility
 
- 		{
 
- 			int distance = hex.isValid() ? reachability.distances[hex] : 0;
 
- 			auto bai = BattleAttackInfo(attackerInfo, defender, distance, shooting);
 
- 			return AttackPossibility::evaluate(bai, hex, state);
 
- 		};
 
- 		if(forceTarget)
 
- 		{
 
- 			if(forcedTarget && defender->unitId() == forcedTarget->unitId())
 
- 				possibleAttacks.push_back(GenerateAttackInfo(false, forcedHex));
 
- 			else
 
- 				unreachableEnemies.push_back(defender);
 
- 		}
 
- 		else if(state.battleCanShoot(attackerInfo, defender->getPosition()))
 
- 		{
 
- 			possibleAttacks.push_back(GenerateAttackInfo(true, BattleHex::INVALID));
 
- 		}
 
- 		else
 
- 		{
 
- 			for(BattleHex hex : avHexes)
 
- 			{
 
- 				if(!CStack::isMeleeAttackPossible(attackerInfo, defender, hex))
 
- 					continue;
 
- 				auto bai = GenerateAttackInfo(false, hex);
 
- 				if(!bai.affectedUnits.empty())
 
- 					possibleAttacks.push_back(bai);
 
- 			}
 
- 			if(!vstd::contains_if(possibleAttacks, [=](const AttackPossibility & pa) { return pa.attack.defender->unitId() == defender->unitId(); }))
 
- 				unreachableEnemies.push_back(defender);
 
- 		}
 
- 	}
 
- 	boost::sort(possibleAttacks, [](const AttackPossibility & lhs, const AttackPossibility & rhs) -> bool
 
- 	{
 
- 		return lhs.damageDiff() > rhs.damageDiff();
 
- 	});
 
- 	if (!possibleAttacks.empty())
 
- 	{
 
- 		auto & bestAp = possibleAttacks[0];
 
- 		logGlobal->info("Battle AI best: %s -> %s at %d from %d, affects %d units: d:%lld a:%lld c:%lld s:%lld",
 
- 			bestAp.attack.attacker->unitType()->getJsonKey(),
 
- 			state.battleGetUnitByPos(bestAp.dest)->unitType()->getJsonKey(),
 
- 			(int)bestAp.dest, (int)bestAp.from, (int)bestAp.affectedUnits.size(),
 
- 			bestAp.defenderDamageReduce, bestAp.attackerDamageReduce, bestAp.collateralDamageReduce, bestAp.shootersBlockedDmg);
 
- 	}
 
- }
 
- int64_t PotentialTargets::bestActionValue() const
 
- {
 
- 	if(possibleAttacks.empty())
 
- 		return 0;
 
- 	return bestAction().attackValue();
 
- }
 
- const AttackPossibility & PotentialTargets::bestAction() const
 
- {
 
- 	if(possibleAttacks.empty())
 
- 		throw std::runtime_error("No best action, since we don't have any actions");
 
- 	return possibleAttacks.front();
 
- }
 
 
  |