| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 | 
							- /*
 
-  * 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 attIter = state->stackStates.find(attacker->unitId());
 
- 	const battle::Unit * attackerInfo = (attIter == state->stackStates.end()) ? attacker : attIter->second.get();
 
- 	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
 
- 		{
 
- 			auto bai = BattleAttackInfo(attackerInfo, defender, shooting);
 
- 			if(hex.isValid() && !shooting)
 
- 				bai.chargedFields = reachability.distances[hex];
 
- 			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
 
- 	{
 
- 		if(lhs.collateralDamage > rhs.collateralDamage)
 
- 			return false;
 
- 		if(lhs.collateralDamage < rhs.collateralDamage)
 
- 			return true;
 
- 		return (lhs.damageDealt + lhs.shootersBlockedDmg - lhs.damageReceived > rhs.damageDealt + rhs.shootersBlockedDmg - rhs.damageReceived);
 
- 	});
 
- 	if (!possibleAttacks.empty())
 
- 	{
 
- 		auto &bestAp = possibleAttacks[0];
 
- 		logGlobal->info("Battle AI best: %s -> %s at %d from %d, affects %d units: %lld %lld %lld %lld",
 
- 			bestAp.attack.attacker->unitType()->identifier,
 
- 			state->battleGetUnitByPos(bestAp.dest)->unitType()->identifier,
 
- 			(int)bestAp.dest, (int)bestAp.from, (int)bestAp.affectedUnits.size(),
 
- 			bestAp.damageDealt, bestAp.damageReceived, bestAp.collateralDamage, bestAp.shootersBlockedDmg);
 
- 	}
 
- }
 
- int64_t PotentialTargets::bestActionValue() const
 
- {
 
- 	if(possibleAttacks.empty())
 
- 		return 0;
 
- 	return bestAction().attackValue();
 
- }
 
- AttackPossibility PotentialTargets::bestAction() const
 
- {
 
- 	if(possibleAttacks.empty())
 
- 		throw std::runtime_error("No best action, since we don't have any actions");
 
- 	return possibleAttacks[0];
 
- 	//return *vstd::maxElementByFun(possibleAttacks, [](const AttackPossibility &ap) { return ap.attackValue(); } );
 
- }
 
 
  |