mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 12:48:00 +00:00
Tweak declareAttackers
This commit is contained in:
@@ -46,6 +46,7 @@ import forge.game.combat.GlobalAttackRestrictions;
|
|||||||
import forge.game.cost.Cost;
|
import forge.game.cost.Cost;
|
||||||
import forge.game.keyword.Keyword;
|
import forge.game.keyword.Keyword;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
|
import forge.game.player.PlayerCollection;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.spellability.SpellAbilityPredicates;
|
import forge.game.spellability.SpellAbilityPredicates;
|
||||||
import forge.game.trigger.Trigger;
|
import forge.game.trigger.Trigger;
|
||||||
@@ -71,7 +72,7 @@ public class AiAttackController {
|
|||||||
|
|
||||||
// possible attackers and blockers
|
// possible attackers and blockers
|
||||||
private List<Card> attackers;
|
private List<Card> attackers;
|
||||||
private final List<Card> blockers;
|
private List<Card> blockers;
|
||||||
|
|
||||||
private List<Card> oppList; // holds human player creatures
|
private List<Card> oppList; // holds human player creatures
|
||||||
private List<Card> myList; // holds computer creatures
|
private List<Card> myList; // holds computer creatures
|
||||||
@@ -95,11 +96,9 @@ public class AiAttackController {
|
|||||||
public AiAttackController(final Player ai, boolean nextTurn) {
|
public AiAttackController(final Player ai, boolean nextTurn) {
|
||||||
this.ai = ai;
|
this.ai = ai;
|
||||||
defendingOpponent = choosePreferredDefenderPlayer(ai);
|
defendingOpponent = choosePreferredDefenderPlayer(ai);
|
||||||
this.oppList = getOpponentCreatures(defendingOpponent);
|
|
||||||
myList = ai.getCreaturesInPlay();
|
myList = ai.getCreaturesInPlay();
|
||||||
this.nextTurn = nextTurn;
|
this.nextTurn = nextTurn;
|
||||||
refreshAttackers(defendingOpponent);
|
refreshCombatants(defendingOpponent);
|
||||||
this.blockers = getPossibleBlockers(oppList, this.attackers, this.nextTurn);
|
|
||||||
} // overloaded constructor to evaluate attackers that should attack next turn
|
} // overloaded constructor to evaluate attackers that should attack next turn
|
||||||
|
|
||||||
public AiAttackController(final Player ai, Card attacker) {
|
public AiAttackController(final Player ai, Card attacker) {
|
||||||
@@ -115,13 +114,15 @@ public class AiAttackController {
|
|||||||
this.blockers = getPossibleBlockers(oppList, this.attackers, this.nextTurn);
|
this.blockers = getPossibleBlockers(oppList, this.attackers, this.nextTurn);
|
||||||
} // overloaded constructor to evaluate single specified attacker
|
} // overloaded constructor to evaluate single specified attacker
|
||||||
|
|
||||||
private void refreshAttackers(GameEntity defender) {
|
private void refreshCombatants(GameEntity defender) {
|
||||||
|
this.oppList = getOpponentCreatures(defendingOpponent);
|
||||||
this.attackers = new ArrayList<>();
|
this.attackers = new ArrayList<>();
|
||||||
for (Card c : myList) {
|
for (Card c : myList) {
|
||||||
if (canAttackWrapper(c, defender)) {
|
if (canAttackWrapper(c, defender)) {
|
||||||
attackers.add(c);
|
attackers.add(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.blockers = getPossibleBlockers(oppList, this.attackers, this.nextTurn);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Card> getOpponentCreatures(final Player defender) {
|
public static List<Card> getOpponentCreatures(final Player defender) {
|
||||||
@@ -149,6 +150,7 @@ public class AiAttackController {
|
|||||||
|
|
||||||
public void removeBlocker(Card blocker) {
|
public void removeBlocker(Card blocker) {
|
||||||
this.oppList.remove(blocker);
|
this.oppList.remove(blocker);
|
||||||
|
this.blockers.remove(blocker);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean canAttackWrapper(final Card attacker, final GameEntity defender) {
|
private boolean canAttackWrapper(final Card attacker, final GameEntity defender) {
|
||||||
@@ -708,12 +710,24 @@ public class AiAttackController {
|
|||||||
* @return a {@link forge.game.combat.Combat} object.
|
* @return a {@link forge.game.combat.Combat} object.
|
||||||
*/
|
*/
|
||||||
public final int declareAttackers(final Combat combat) {
|
public final int declareAttackers(final Combat combat) {
|
||||||
|
// something prevents attacking, try another
|
||||||
|
if (this.attackers.isEmpty() && ai.getOpponents().size() > 1) {
|
||||||
|
final PlayerCollection opps = ai.getOpponents();
|
||||||
|
opps.remove(defendingOpponent);
|
||||||
|
defendingOpponent = Aggregates.random(opps);
|
||||||
|
refreshCombatants(defendingOpponent);
|
||||||
|
}
|
||||||
|
|
||||||
final boolean bAssault = doAssault();
|
final boolean bAssault = doAssault();
|
||||||
|
|
||||||
// Determine who will be attacked
|
// Determine who will be attacked
|
||||||
GameEntity defender = chooseDefender(combat, bAssault);
|
GameEntity defender = chooseDefender(combat, bAssault);
|
||||||
|
|
||||||
|
// decided to attack another defender so related lists need to be updated
|
||||||
|
// (though usually rather try to avoid this situation for performance reasons)
|
||||||
if (defender != defendingOpponent) {
|
if (defender != defendingOpponent) {
|
||||||
refreshAttackers(defender);
|
defendingOpponent = defender instanceof Player ? (Player) defender : ((Card)defender).getController();
|
||||||
|
refreshCombatants(defender);
|
||||||
}
|
}
|
||||||
if (this.attackers.isEmpty()) {
|
if (this.attackers.isEmpty()) {
|
||||||
return aiAggression;
|
return aiAggression;
|
||||||
@@ -910,8 +924,6 @@ public class AiAttackController {
|
|||||||
final List<Card> nextTurnAttackers = new ArrayList<>();
|
final List<Card> nextTurnAttackers = new ArrayList<>();
|
||||||
int candidateCounterAttackDamage = 0;
|
int candidateCounterAttackDamage = 0;
|
||||||
|
|
||||||
final Player opp = defender instanceof Player ? (Player) defender : ((Card)defender).getController();
|
|
||||||
this.oppList = getOpponentCreatures(opp);
|
|
||||||
// get the potential damage and strength of the AI forces
|
// get the potential damage and strength of the AI forces
|
||||||
final List<Card> candidateAttackers = new ArrayList<>();
|
final List<Card> candidateAttackers = new ArrayList<>();
|
||||||
int candidateUnblockedDamage = 0;
|
int candidateUnblockedDamage = 0;
|
||||||
@@ -920,7 +932,7 @@ public class AiAttackController {
|
|||||||
// turn, assume summoning sickness creatures will be able to
|
// turn, assume summoning sickness creatures will be able to
|
||||||
if (ComputerUtilCombat.canAttackNextTurn(pCard) && pCard.getNetCombatDamage() > 0) {
|
if (ComputerUtilCombat.canAttackNextTurn(pCard) && pCard.getNetCombatDamage() > 0) {
|
||||||
candidateAttackers.add(pCard);
|
candidateAttackers.add(pCard);
|
||||||
candidateUnblockedDamage += ComputerUtilCombat.damageIfUnblocked(pCard, opp, null, false);
|
candidateUnblockedDamage += ComputerUtilCombat.damageIfUnblocked(pCard, defendingOpponent, null, false);
|
||||||
computerForces++;
|
computerForces++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -962,7 +974,7 @@ public class AiAttackController {
|
|||||||
// find the potential damage ratio the AI can cause
|
// find the potential damage ratio the AI can cause
|
||||||
double humanLifeToDamageRatio = 1000000;
|
double humanLifeToDamageRatio = 1000000;
|
||||||
if (candidateUnblockedDamage > 0) {
|
if (candidateUnblockedDamage > 0) {
|
||||||
humanLifeToDamageRatio = (double) (opp.getLife() - ComputerUtil.possibleNonCombatDamage(ai, opp)) / candidateUnblockedDamage;
|
humanLifeToDamageRatio = (double) (defendingOpponent.getLife() - ComputerUtil.possibleNonCombatDamage(ai, defendingOpponent)) / candidateUnblockedDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine if the ai outnumbers the player
|
// determine if the ai outnumbers the player
|
||||||
@@ -987,7 +999,7 @@ public class AiAttackController {
|
|||||||
// get list of attackers ordered from low power to high
|
// get list of attackers ordered from low power to high
|
||||||
CardLists.sortByPowerAsc(this.attackers);
|
CardLists.sortByPowerAsc(this.attackers);
|
||||||
// get player life total
|
// get player life total
|
||||||
int humanLife = opp.getLife();
|
int humanLife = defendingOpponent.getLife();
|
||||||
// get the list of attackers up to the first blocked one
|
// get the list of attackers up to the first blocked one
|
||||||
final List<Card> attritionalAttackers = new ArrayList<>();
|
final List<Card> attritionalAttackers = new ArrayList<>();
|
||||||
for (int x = 0; x < (this.attackers.size() - humanForces); x++) {
|
for (int x = 0; x < (this.attackers.size() - humanForces); x++) {
|
||||||
@@ -1037,7 +1049,7 @@ public class AiAttackController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isUnblockableCreature) {
|
if (isUnblockableCreature) {
|
||||||
unblockableDamage += ComputerUtilCombat.damageIfUnblocked(attacker, opp, combat, false);
|
unblockableDamage += ComputerUtilCombat.damageIfUnblocked(attacker, defendingOpponent, combat, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (final Card attacker : nextTurnAttackers) {
|
for (final Card attacker : nextTurnAttackers) {
|
||||||
@@ -1051,13 +1063,13 @@ public class AiAttackController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isUnblockableCreature) {
|
if (isUnblockableCreature) {
|
||||||
nextUnblockableDamage += ComputerUtilCombat.damageIfUnblocked(attacker, opp, null, false);
|
nextUnblockableDamage += ComputerUtilCombat.damageIfUnblocked(attacker, defendingOpponent, null, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (unblockableDamage > 0 && !opp.cantLoseForZeroOrLessLife() && opp.canLoseLife()) {
|
if (unblockableDamage > 0 && !defendingOpponent.cantLoseForZeroOrLessLife() && defendingOpponent.canLoseLife()) {
|
||||||
turnsUntilDeathByUnblockable = 1 + (opp.getLife() - unblockableDamage) / nextUnblockableDamage;
|
turnsUntilDeathByUnblockable = 1 + (defendingOpponent.getLife() - unblockableDamage) / nextUnblockableDamage;
|
||||||
}
|
}
|
||||||
if (opp.canLoseLife()) {
|
if (defendingOpponent.canLoseLife()) {
|
||||||
doUnblockableAttack = true;
|
doUnblockableAttack = true;
|
||||||
}
|
}
|
||||||
// *****************
|
// *****************
|
||||||
@@ -1114,8 +1126,8 @@ public class AiAttackController {
|
|||||||
if ( LOG_AI_ATTACKS )
|
if ( LOG_AI_ATTACKS )
|
||||||
System.out.println("attackersLeft = " + attackersLeft);
|
System.out.println("attackersLeft = " + attackersLeft);
|
||||||
|
|
||||||
FCollection<GameEntity> possibleDefenders = new FCollection<>(opp);
|
FCollection<GameEntity> possibleDefenders = new FCollection<>(defendingOpponent);
|
||||||
possibleDefenders.addAll(opp.getPlaneswalkersInPlay());
|
possibleDefenders.addAll(defendingOpponent.getPlaneswalkersInPlay());
|
||||||
|
|
||||||
while (!attackersLeft.isEmpty()) {
|
while (!attackersLeft.isEmpty()) {
|
||||||
CardCollection attackersAssigned = new CardCollection();
|
CardCollection attackersAssigned = new CardCollection();
|
||||||
@@ -1164,7 +1176,7 @@ public class AiAttackController {
|
|||||||
if (pwDefending.isEmpty()) {
|
if (pwDefending.isEmpty()) {
|
||||||
// TODO for now only looks at same player as we'd have to check the others from start too
|
// TODO for now only looks at same player as we'd have to check the others from start too
|
||||||
//defender = new PlayerCollection(Iterables.filter(possibleDefenders, Player.class)).min(PlayerPredicates.compareByLife());
|
//defender = new PlayerCollection(Iterables.filter(possibleDefenders, Player.class)).min(PlayerPredicates.compareByLife());
|
||||||
defender = opp;
|
defender = defendingOpponent;
|
||||||
} else {
|
} else {
|
||||||
final Card pwNearUlti = ComputerUtilCard.getBestPlaneswalkerToDamage(pwDefending);
|
final Card pwNearUlti = ComputerUtilCard.getBestPlaneswalkerToDamage(pwDefending);
|
||||||
defender = pwNearUlti != null ? pwNearUlti : ComputerUtilCard.getBestPlaneswalkerAI(pwDefending);
|
defender = pwNearUlti != null ? pwNearUlti : ComputerUtilCard.getBestPlaneswalkerAI(pwDefending);
|
||||||
|
|||||||
Reference in New Issue
Block a user