mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	BattleAI: avoid selfblocking on siege
This commit is contained in:
		| @@ -212,11 +212,13 @@ AttackPossibility AttackPossibility::evaluate(const BattleAttackInfo & attackInf | ||||
| 	// check how much damage we gain from blocking enemy shooters on this hex | ||||
| 	bestAp.shootersBlockedDmg = evaluateBlockedShootersDmg(attackInfo, hex, state); | ||||
|  | ||||
| 	logAi->debug("BattleAI best AP: %s -> %s at %d from %d, affects %d units: d:%lld a:%lld c:%lld s:%lld", | ||||
| #if BATTLE_TRACE_LEVEL>=1 | ||||
| 	logAi->trace("BattleAI best AP: %s -> %s at %d from %d, affects %d units: d:%lld a:%lld c:%lld s:%lld", | ||||
| 		attackInfo.attacker->unitType()->getJsonKey(), | ||||
| 		attackInfo.defender->unitType()->getJsonKey(), | ||||
| 		(int)bestAp.dest, (int)bestAp.from, (int)bestAp.affectedUnits.size(), | ||||
| 		bestAp.defenderDamageReduce, bestAp.attackerDamageReduce, bestAp.collateralDamageReduce, bestAp.shootersBlockedDmg); | ||||
| #endif | ||||
|  | ||||
| 	//TODO other damage related to attack (eg. fire shield and other abilities) | ||||
| 	return bestAp; | ||||
|   | ||||
| @@ -89,6 +89,7 @@ void CBattleAI::initBattleInterface(std::shared_ptr<Environment> ENV, std::share | ||||
| 	wasUnlockingGs = CB->unlockGsWhenWaiting; | ||||
| 	CB->waitTillRealize = true; | ||||
| 	CB->unlockGsWhenWaiting = false; | ||||
| 	movesSkippedByDefense = 0; | ||||
| } | ||||
|  | ||||
| BattleAction CBattleAI::activeStack( const CStack * stack ) | ||||
| @@ -181,6 +182,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack ) | ||||
| 			if(bestSpellcast.is_initialized() && bestSpellcast->value > bestAttack.damageDiff()) | ||||
| 			{ | ||||
| 				// return because spellcast value is damage dealt and score is dps reduce | ||||
| 				movesSkippedByDefense = 0; | ||||
| 				return BattleAction::makeCreatureSpellcast(stack, bestSpellcast->dest, bestSpellcast->spell->id); | ||||
| 			} | ||||
|  | ||||
| @@ -196,14 +198,15 @@ BattleAction CBattleAI::activeStack( const CStack * stack ) | ||||
| 				} | ||||
| 				else if(bestAttack.attack.shooting) | ||||
| 				{ | ||||
|  | ||||
| 					result = BattleAction::makeShotAttack(stack, bestAttack.attack.defender); | ||||
| 					action = "shot"; | ||||
| 					movesSkippedByDefense = 0; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					result = BattleAction::makeMeleeAttack(stack, bestAttack.attack.defender->getPosition(), bestAttack.from); | ||||
| 					action = "melee"; | ||||
| 					movesSkippedByDefense = 0; | ||||
| 				} | ||||
|  | ||||
| 				logAi->debug("BattleAI: %s -> %s x %d, %s, from %d curpos %d dist %d speed %d: +%lld -%lld = %lld", | ||||
| @@ -217,6 +220,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack ) | ||||
| 		} | ||||
| 		else if(bestSpellcast.is_initialized()) | ||||
| 		{ | ||||
| 			movesSkippedByDefense = 0; | ||||
| 			return BattleAction::makeCreatureSpellcast(stack, bestSpellcast->dest, bestSpellcast->spell->id); | ||||
| 		} | ||||
|  | ||||
| @@ -235,12 +239,8 @@ BattleAction CBattleAI::activeStack( const CStack * stack ) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if(score > EvaluationResult::INEFFECTIVE_SCORE) | ||||
| 		{ | ||||
| 			return result; | ||||
| 		} | ||||
|  | ||||
| 		if(!stack->hasBonusOfType(Bonus::FLYING) | ||||
| 		if(score <= EvaluationResult::INEFFECTIVE_SCORE | ||||
| 			&& !stack->hasBonusOfType(Bonus::FLYING) | ||||
| 			&& stack->unitSide() == BattleSide::ATTACKER | ||||
| 			&& cb->battleGetSiegeLevel() >= CGTownInstance::CITADEL) | ||||
| 		{ | ||||
| @@ -248,10 +248,12 @@ BattleAction CBattleAI::activeStack( const CStack * stack ) | ||||
|  | ||||
| 			if(brokenWallMoat.size()) | ||||
| 			{ | ||||
| 				movesSkippedByDefense = 0; | ||||
|  | ||||
| 				if(stack->doubleWide() && vstd::contains(brokenWallMoat, stack->getPosition())) | ||||
| 					return BattleAction::makeMove(stack, stack->getPosition().cloneInDirection(BattleHex::RIGHT)); | ||||
| 					result = BattleAction::makeMove(stack, stack->getPosition().cloneInDirection(BattleHex::RIGHT)); | ||||
| 				else | ||||
| 					return goTowardsNearest(stack, brokenWallMoat); | ||||
| 					result = goTowardsNearest(stack, brokenWallMoat); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @@ -264,6 +266,15 @@ BattleAction CBattleAI::activeStack( const CStack * stack ) | ||||
| 		logAi->error("Exception occurred in %s %s",__FUNCTION__, e.what()); | ||||
| 	} | ||||
|  | ||||
| 	if(result.actionType == EActionType::DEFEND) | ||||
| 	{ | ||||
| 		movesSkippedByDefense++; | ||||
| 	} | ||||
| 	else if(result.actionType != EActionType::WAIT) | ||||
| 	{ | ||||
| 		movesSkippedByDefense = 0; | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| @@ -285,7 +296,9 @@ BattleAction CBattleAI::goTowardsNearest(const CStack * stack, std::vector<Battl | ||||
| 	for(auto hex : hexes) | ||||
| 	{ | ||||
| 		if(vstd::contains(avHexes, hex)) | ||||
| 		{ | ||||
| 			return BattleAction::makeMove(stack, hex); | ||||
| 		} | ||||
|  | ||||
| 		if(stack->coversPos(hex)) | ||||
| 		{ | ||||
| @@ -396,6 +409,8 @@ BattleAction CBattleAI::useCatapult(const CStack * stack) | ||||
| 	attack.side = side; | ||||
| 	attack.stackNumber = stack->ID; | ||||
|  | ||||
| 	movesSkippedByDefense = 0; | ||||
|  | ||||
| 	return attack; | ||||
| } | ||||
|  | ||||
| @@ -703,6 +718,7 @@ void CBattleAI::attemptCastingSpell() | ||||
| 		spellcast.side = side; | ||||
| 		spellcast.stackNumber = (!side) ? -1 : -2; | ||||
| 		cb->battleMakeAction(&spellcast); | ||||
| 		movesSkippedByDefense = 0; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @@ -796,12 +812,21 @@ boost::optional<BattleAction> CBattleAI::considerFleeingOrSurrendering() | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	bs.turnsSkippedByDefense = movesSkippedByDefense / bs.ourStacks.size(); | ||||
|  | ||||
| 	if(!bs.canFlee || !bs.canSurrender) | ||||
| 	{ | ||||
| 		return boost::none; | ||||
| 	} | ||||
|  | ||||
| 	return cb->makeSurrenderRetreatDecision(bs); | ||||
| 	auto result = cb->makeSurrenderRetreatDecision(bs); | ||||
|  | ||||
| 	if(!result && bs.canFlee && bs.turnsSkippedByDefense > 30) | ||||
| 	{ | ||||
| 		return BattleAction::makeRetreat(bs.ourSide); | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -60,6 +60,7 @@ class CBattleAI : public CBattleGameInterface | ||||
|  | ||||
| 	//Previous setting of cb | ||||
| 	bool wasWaitingForRealize, wasUnlockingGs; | ||||
| 	int movesSkippedByDefense; | ||||
|  | ||||
| public: | ||||
| 	CBattleAI(); | ||||
|   | ||||
| @@ -355,6 +355,13 @@ int64_t BattleExchangeEvaluator::calculateExchange( | ||||
| 	logAi->trace("Battle exchange at %lld", ap.attack.shooting ? ap.dest : ap.from); | ||||
| #endif | ||||
|  | ||||
| 	if(cb->battleGetMySide() == BattlePerspective::LEFT_SIDE | ||||
| 		&& cb->battleGetGateState() == EGateState::BLOCKED | ||||
| 		&& ap.attack.defender->coversPos(ESiegeHex::GATE_BRIDGE)) | ||||
| 	{ | ||||
| 		return EvaluationResult::INEFFECTIVE_SCORE; | ||||
| 	} | ||||
|  | ||||
| 	std::vector<const battle::Unit *> ourStacks; | ||||
| 	std::vector<const battle::Unit *> enemyStacks; | ||||
|  | ||||
|   | ||||
| @@ -42,7 +42,7 @@ struct EvaluationResult | ||||
| 	bool defend; | ||||
|  | ||||
| 	EvaluationResult(const AttackPossibility & ap) | ||||
| 		:wait(false), score(0), bestAttack(ap), defend(false) | ||||
| 		:wait(false), score(INEFFECTIVE_SCORE), bestAttack(ap), defend(false) | ||||
| 	{ | ||||
| 	} | ||||
| }; | ||||
|   | ||||
| @@ -29,6 +29,7 @@ public: | ||||
| 	std::vector<const battle::Unit *> enemyStacks; | ||||
| 	const CGHeroInstance * ourHero; | ||||
| 	const CGHeroInstance * enemyHero; | ||||
| 	int turnsSkippedByDefense; | ||||
|  | ||||
| 	BattleStateInfoForRetreat(); | ||||
| 	uint64_t getOurStrength() const; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user