- Fixed accidental revert of PlayerControllerAi by r31697

This commit is contained in:
excessum
2016-07-25 12:49:35 +00:00
parent c7de464023
commit e43fe8abc6

View File

@@ -55,6 +55,7 @@ import org.apache.commons.lang3.tuple.Pair;
import java.security.InvalidParameterException; import java.security.InvalidParameterException;
import java.util.*; import java.util.*;
/** /**
* A prototype for player controller class * A prototype for player controller class
* *
@@ -80,7 +81,8 @@ public class PlayerControllerAi extends PlayerController {
public SpellAbility getAbilityToPlay(Card hostCard, List<SpellAbility> abilities, ITriggerEvent triggerEvent) { public SpellAbility getAbilityToPlay(Card hostCard, List<SpellAbility> abilities, ITriggerEvent triggerEvent) {
if (abilities.size() == 0) { if (abilities.size() == 0) {
return null; return null;
} else { }
else {
return abilities.get(0); return abilities.get(0);
} }
} }
@@ -101,20 +103,17 @@ public class PlayerControllerAi extends PlayerController {
} }
@Override @Override
public Map<Card, Integer> assignCombatDamage(Card attacker, CardCollectionView blockers, int damageDealt, public Map<Card, Integer> assignCombatDamage(Card attacker, CardCollectionView blockers, int damageDealt, GameEntity defender, boolean overrideOrder) {
GameEntity defender, boolean overrideOrder) {
return ComputerUtilCombat.distributeAIDamage(attacker, blockers, damageDealt, defender, overrideOrder); return ComputerUtilCombat.distributeAIDamage(attacker, blockers, damageDealt, defender, overrideOrder);
} }
@Override @Override
public Integer announceRequirements(SpellAbility ability, String announce, boolean allowZero) { public Integer announceRequirements(SpellAbility ability, String announce, boolean allowZero) {
// For now, these "announcements" are made within the AI classes of the // For now, these "announcements" are made within the AI classes of the appropriate SA effects
// appropriate SA effects
if (ability.getApi() != null) { if (ability.getApi() != null) {
switch (ability.getApi()) { switch (ability.getApi()) {
case ChooseNumber: case ChooseNumber:
return ability.getActivatingPlayer().isOpponentOf(player) ? 0 return ability.getActivatingPlayer().isOpponentOf(player) ? 0 : ComputerUtilMana.determineLeftoverMana(ability, player);
: ComputerUtilMana.determineLeftoverMana(ability, player);
case BidLife: case BidLife:
return 0; return 0;
default: default:
@@ -125,36 +124,30 @@ public class PlayerControllerAi extends PlayerController {
} }
@Override @Override
public CardCollectionView choosePermanentsToSacrifice(SpellAbility sa, int min, int max, public CardCollectionView choosePermanentsToSacrifice(SpellAbility sa, int min, int max, CardCollectionView validTargets, String message) {
CardCollectionView validTargets, String message) {
return ComputerUtil.choosePermanentsToSacrifice(player, validTargets, max, sa, false, min == 0); return ComputerUtil.choosePermanentsToSacrifice(player, validTargets, max, sa, false, min == 0);
} }
@Override @Override
public CardCollectionView choosePermanentsToDestroy(SpellAbility sa, int min, int max, public CardCollectionView choosePermanentsToDestroy(SpellAbility sa, int min, int max, CardCollectionView validTargets, String message) {
CardCollectionView validTargets, String message) {
return ComputerUtil.choosePermanentsToSacrifice(player, validTargets, max, sa, true, min == 0); return ComputerUtil.choosePermanentsToSacrifice(player, validTargets, max, sa, true, min == 0);
} }
@Override @Override
public CardCollectionView chooseCardsForEffect(CardCollectionView sourceList, SpellAbility sa, String title, public CardCollectionView chooseCardsForEffect(CardCollectionView sourceList, SpellAbility sa, String title, int min, int max, boolean isOptional) {
int min, int max, boolean isOptional) {
return brains.chooseCardsForEffect(sourceList, sa, min, max, isOptional); return brains.chooseCardsForEffect(sourceList, sa, min, max, isOptional);
} }
@Override @Override
public <T extends GameEntity> T chooseSingleEntityForEffect(FCollectionView<T> optionList, public <T extends GameEntity> T chooseSingleEntityForEffect(FCollectionView<T> optionList, DelayedReveal delayedReveal, SpellAbility sa, String title, boolean isOptional, Player targetedPlayer) {
DelayedReveal delayedReveal, SpellAbility sa, String title, boolean isOptional, Player targetedPlayer) {
if (delayedReveal != null) { if (delayedReveal != null) {
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
delayedReveal.getMessagePrefix());
} }
ApiType api = sa.getApi(); ApiType api = sa.getApi();
if (null == api) { if (null == api) {
throw new InvalidParameterException("SA is not api-based, this is not supported yet"); throw new InvalidParameterException("SA is not api-based, this is not supported yet");
} }
return SpellApiToAi.Converter.get(api).chooseSingleEntity(player, sa, (FCollection<T>) optionList, isOptional, return SpellApiToAi.Converter.get(api).chooseSingleEntity(player, sa, (FCollection<T>)optionList, isOptional, targetedPlayer);
targetedPlayer);
} }
@Override @Override
@@ -172,8 +165,8 @@ public class PlayerControllerAi extends PlayerController {
} }
@Override @Override
public boolean confirmBidAction(SpellAbility sa, PlayerActionConfirmMode mode, String string, int bid, public boolean confirmBidAction(SpellAbility sa, PlayerActionConfirmMode mode, String string,
Player winner) { int bid, Player winner) {
return getAi().confirmBidAction(sa, mode, string, bid, winner); return getAi().confirmBidAction(sa, mode, string, bid, winner);
} }
@@ -183,14 +176,12 @@ public class PlayerControllerAi extends PlayerController {
} }
@Override @Override
public boolean confirmTrigger(SpellAbility sa, Trigger regtrig, Map<String, String> triggerParams, public boolean confirmTrigger(SpellAbility sa, Trigger regtrig, Map<String, String> triggerParams, boolean isMandatory) {
boolean isMandatory) {
if (sa.getHostCard().getName().equals("Deathmist Raptor")) { if (sa.getHostCard().getName().equals("Deathmist Raptor")) {
return true; return true;
} }
if (triggerParams.containsKey("DelayedTrigger") || isMandatory) { if (triggerParams.containsKey("DelayedTrigger") || isMandatory) {
// TODO: The only card with an optional delayed trigger is Shirei, //TODO: The only card with an optional delayed trigger is Shirei, Shizo's Caretaker,
// Shizo's Caretaker,
// needs to be expanded when a more difficult cards comes up // needs to be expanded when a more difficult cards comes up
return true; return true;
} }
@@ -210,10 +201,8 @@ public class PlayerControllerAi extends PlayerController {
subtc = sub.getTargets(); subtc = sub.getTargets();
sub.resetTargets(); sub.resetTargets();
} }
// There is no way this doTrigger here will have the same target as // There is no way this doTrigger here will have the same target as stored above
// stored above // So it's possible it's making a different decision here than will actually happen
// So it's possible it's making a different decision here than will
// actually happen
if (!brains.doTrigger(sa, false)) { if (!brains.doTrigger(sa, false)) {
ret = false; ret = false;
} }
@@ -267,7 +256,8 @@ public class PlayerControllerAi extends PlayerController {
for (Card c: topN) { for (Card c: topN) {
if (ComputerUtil.scryWillMoveCardToBottomOfLibrary(player, c)) { if (ComputerUtil.scryWillMoveCardToBottomOfLibrary(player, c)) {
toBottom.add(c); toBottom.add(c);
} else { }
else {
toTop.add(c); toTop.add(c);
} }
} }
@@ -279,8 +269,7 @@ public class PlayerControllerAi extends PlayerController {
@Override @Override
public boolean willPutCardOnTop(Card c) { public boolean willPutCardOnTop(Card c) {
return true; // AI does not know what will happen next (another clash or return true; // AI does not know what will happen next (another clash or that would become his topdeck)
// that would become his topdeck)
} }
@Override @Override
@@ -290,27 +279,27 @@ public class PlayerControllerAi extends PlayerController {
} }
@Override @Override
public CardCollection chooseCardsToDiscardFrom(Player p, SpellAbility sa, CardCollection validCards, int min, public CardCollection chooseCardsToDiscardFrom(Player p, SpellAbility sa, CardCollection validCards, int min, int max) {
int max) {
if (p == player) { if (p == player) {
return brains.getCardsToDiscard(min, max, validCards, sa); return brains.getCardsToDiscard(min, max, validCards, sa);
} }
boolean isTargetFriendly = !p.isOpponentOf(player); boolean isTargetFriendly = !p.isOpponentOf(player);
return isTargetFriendly ? ComputerUtil.getCardsToDiscardFromFriend(player, p, sa, validCards, min, max) return isTargetFriendly
? ComputerUtil.getCardsToDiscardFromFriend(player, p, sa, validCards, min, max)
: ComputerUtil.getCardsToDiscardFromOpponent(player, p, sa, validCards, min, max); : ComputerUtil.getCardsToDiscardFromOpponent(player, p, sa, validCards, min, max);
} }
@Override @Override
public void playSpellAbilityForFree(SpellAbility copySA, boolean mayChooseNewTargets) { public void playSpellAbilityForFree(SpellAbility copySA, boolean mayChooseNewTargets) {
// Ai is known to set targets in doTrigger, so if it cannot choose new // Ai is known to set targets in doTrigger, so if it cannot choose new targets, we won't call canPlays
// targets, we won't call canPlays
if (mayChooseNewTargets) { if (mayChooseNewTargets) {
if (copySA instanceof Spell) { if (copySA instanceof Spell) {
Spell spell = (Spell) copySA; Spell spell = (Spell) copySA;
((PlayerControllerAi) player.getController()).getAi().canPlayFromEffectAI(spell, true, true); ((PlayerControllerAi) player.getController()).getAi().canPlayFromEffectAI(spell, true, true);
} else { }
else {
getAi().canPlaySa(copySA); getAi().canPlaySa(copySA);
} }
} }
@@ -320,9 +309,7 @@ public class PlayerControllerAi extends PlayerController {
@Override @Override
public void playSpellAbilityNoStack(SpellAbility effectSA, boolean canSetupTargets) { public void playSpellAbilityNoStack(SpellAbility effectSA, boolean canSetupTargets) {
if (canSetupTargets) if (canSetupTargets)
brains.doTrigger(effectSA, true); // first parameter does not brains.doTrigger(effectSA, true); // first parameter does not matter, since return value won't be used
// matter, since return value
// won't be used
ComputerUtil.playNoStack(player, effectSA, game); ComputerUtil.playNoStack(player, effectSA, game);
} }
@@ -338,14 +325,12 @@ public class PlayerControllerAi extends PlayerController {
@Override @Override
public TargetChoices chooseNewTargetsFor(SpellAbility ability) { public TargetChoices chooseNewTargetsFor(SpellAbility ability) {
// AI currently can't do this. But when it can it will need to be based // AI currently can't do this. But when it can it will need to be based on Ability API
// on Ability API
return null; return null;
} }
@Override @Override
public CardCollectionView chooseCardsToDiscardUnlessType(int num, CardCollectionView hand, String uType, public CardCollectionView chooseCardsToDiscardUnlessType(int num, CardCollectionView hand, String uType, SpellAbility sa) {
SpellAbility sa) {
final CardCollectionView cardsOfType = CardLists.getType(hand, uType); final CardCollectionView cardsOfType = CardLists.getType(hand, uType);
if (!cardsOfType.isEmpty()) { if (!cardsOfType.isEmpty()) {
Card toDiscard = Aggregates.itemWithMin(cardsOfType, CardPredicates.Accessors.fnGetCmc); Card toDiscard = Aggregates.itemWithMin(cardsOfType, CardPredicates.Accessors.fnGetCmc);
@@ -354,16 +339,17 @@ public class PlayerControllerAi extends PlayerController {
return getAi().getCardsToDiscard(num, (String[])null, sa); return getAi().getCardsToDiscard(num, (String[])null, sa);
} }
@Override @Override
public Mana chooseManaFromPool(List<Mana> manaChoices) { public Mana chooseManaFromPool(List<Mana> manaChoices) {
return manaChoices.get(0); // no brains used return manaChoices.get(0); // no brains used
} }
@Override @Override
public String chooseSomeType(String kindOfType, SpellAbility sa, List<String> validTypes, List<String> invalidTypes, public String chooseSomeType(String kindOfType, SpellAbility sa, List<String> validTypes, List<String> invalidTypes, boolean isOptional) {
boolean isOptional) {
String chosen = ComputerUtil.chooseSomeType(player, kindOfType, sa.getParam("AILogic"), invalidTypes); String chosen = ComputerUtil.chooseSomeType(player, kindOfType, sa.getParam("AILogic"), invalidTypes);
if (StringUtils.isBlank(chosen) && !validTypes.isEmpty()) { if (StringUtils.isBlank(chosen) && !validTypes.isEmpty())
{
chosen = validTypes.get(0); chosen = validTypes.get(0);
Log.warn("AI has no idea how to choose " + kindOfType +", defaulting to 1st element: chosen"); Log.warn("AI has no idea how to choose " + kindOfType +", defaulting to 1st element: chosen");
} }
@@ -377,8 +363,7 @@ public class PlayerControllerAi extends PlayerController {
} }
@Override @Override
public boolean confirmReplacementEffect(ReplacementEffect replacementEffect, SpellAbility effectSA, public boolean confirmReplacementEffect(ReplacementEffect replacementEffect, SpellAbility effectSA, String question) {
String question) {
return brains.aiShouldRun(replacementEffect, effectSA); return brains.aiShouldRun(replacementEffect, effectSA);
} }
@@ -429,11 +414,7 @@ public class PlayerControllerAi extends PlayerController {
@Override @Override
public boolean payManaOptional(Card c, Cost cost, SpellAbility sa, String prompt, ManaPaymentPurpose purpose) { public boolean payManaOptional(Card c, Cost cost, SpellAbility sa, String prompt, ManaPaymentPurpose purpose) {
final Ability ability = new AbilityStatic(c, cost, null) { final Ability ability = new AbilityStatic(c, cost, null) { @Override public void resolve() {} };
@Override
public void resolve() {
}
};
ability.setActivatingPlayer(c.getController()); ability.setActivatingPlayer(c.getController());
if (ComputerUtilCost.canPayCost(ability, c.getController())) { if (ComputerUtilCost.canPayCost(ability, c.getController())) {
@@ -445,8 +426,7 @@ public class PlayerControllerAi extends PlayerController {
@Override @Override
public List<SpellAbility> chooseSaToActivateFromOpeningHand(List<SpellAbility> usableFromOpeningHand) { public List<SpellAbility> chooseSaToActivateFromOpeningHand(List<SpellAbility> usableFromOpeningHand) {
// AI would play everything. But limits to one copy of (Leyline of // AI would play everything. But limits to one copy of (Leyline of Singularity) and (Gemstone Caverns)
// Singularity) and (Gemstone Caverns)
return brains.chooseSaToActivateFromOpeningHand(usableFromOpeningHand); return brains.chooseSaToActivateFromOpeningHand(usableFromOpeningHand);
} }
@@ -459,11 +439,8 @@ public class PlayerControllerAi extends PlayerController {
return brains.chooseNumber(sa, title, options, relatedPlayer); return brains.chooseNumber(sa, title, options, relatedPlayer);
} }
/* /* (non-Javadoc)
* (non-Javadoc) * @see forge.game.player.PlayerController#chooseFlipResult(forge.Card, forge.game.player.Player, java.lang.String[], boolean)
*
* @see forge.game.player.PlayerController#chooseFlipResult(forge.Card,
* forge.game.player.Player, java.lang.String[], boolean)
*/ */
@Override @Override
public boolean chooseFlipResult(SpellAbility sa, Player flipper, boolean[] results, boolean call) { public boolean chooseFlipResult(SpellAbility sa, Player flipper, boolean[] results, boolean call) {
@@ -485,37 +462,31 @@ public class PlayerControllerAi extends PlayerController {
} }
@Override @Override
public Pair<SpellAbilityStackInstance, GameObject> chooseTarget(SpellAbility saSrc, public Pair<SpellAbilityStackInstance, GameObject> chooseTarget(SpellAbility saSrc, List<Pair<SpellAbilityStackInstance, GameObject>> allTargets) {
List<Pair<SpellAbilityStackInstance, GameObject>> allTargets) {
// TODO Teach AI how to use Spellskite // TODO Teach AI how to use Spellskite
return allTargets.get(0); return allTargets.get(0);
} }
@Override @Override
public void notifyOfValue(SpellAbility saSource, GameObject realtedTarget, String value) { public void notifyOfValue(SpellAbility saSource, GameObject realtedTarget, String value) {
// AI should take into consideration creature types, numbers and other // AI should take into consideration creature types, numbers and other information (mostly choices) arriving through this channel
// information (mostly choices) arriving through this channel
} }
@Override @Override
public boolean chooseBinary(SpellAbility sa, String question, BinaryChoiceType kindOfChoice, Boolean defaultVal) { public boolean chooseBinary(SpellAbility sa, String question, BinaryChoiceType kindOfChoice, Boolean defaultVal) {
switch(kindOfChoice) { switch(kindOfChoice) {
case TapOrUntap: case TapOrUntap: return true;
return true; case UntapOrLeaveTapped: return defaultVal != null && defaultVal.booleanValue();
case UntapOrLeaveTapped: case UntapTimeVault: return false; // TODO Should AI skip his turn for time vault?
return defaultVal != null && defaultVal.booleanValue(); case LeftOrRight: return brains.chooseDirection(sa);
case UntapTimeVault:
return false; // TODO Should AI skip his turn for time vault?
case LeftOrRight:
return brains.chooseDirection(sa);
default: default:
return MyRandom.getRandom().nextBoolean(); return MyRandom.getRandom().nextBoolean();
} }
} }
@Override @Override
public Card chooseProtectionShield(GameEntity entityBeingDamaged, List<String> options, public Card chooseProtectionShield(GameEntity entityBeingDamaged, List<String> options, Map<String, Card> choiceMap) {
Map<String, Card> choiceMap) {
int i = MyRandom.getRandom().nextInt(options.size()); int i = MyRandom.getRandom().nextInt(options.size());
return choiceMap.get(options.get(i)); return choiceMap.get(options.get(i));
} }
@@ -539,8 +510,7 @@ public class PlayerControllerAi extends PlayerController {
@Override @Override
public Pair<CounterType,String> chooseAndRemoveOrPutCounter(Card cardWithCounter) { public Pair<CounterType,String> chooseAndRemoveOrPutCounter(Card cardWithCounter) {
if (!cardWithCounter.hasCounters()) { if (!cardWithCounter.hasCounters()) {
System.out.println( System.out.println("chooseCounterType was reached with a card with no counters on it. Consider filtering this card out earlier");
"chooseCounterType was reached with a card with no counters on it. Consider filtering this card out earlier");
return null; return null;
} }
@@ -564,7 +534,8 @@ public class PlayerControllerAi extends PlayerController {
if (!countersToIncrease.isEmpty()) { if (!countersToIncrease.isEmpty()) {
int random = MyRandom.getRandom().nextInt(countersToIncrease.size()); int random = MyRandom.getRandom().nextInt(countersToIncrease.size());
return new ImmutablePair<CounterType,String>(countersToIncrease.get(random),"Put"); return new ImmutablePair<CounterType,String>(countersToIncrease.get(random),"Put");
} else if (!countersToDecrease.isEmpty()) { }
else if (!countersToDecrease.isEmpty()) {
int random = MyRandom.getRandom().nextInt(countersToDecrease.size()); int random = MyRandom.getRandom().nextInt(countersToDecrease.size());
return new ImmutablePair<CounterType,String>(countersToDecrease.get(random),"Remove"); return new ImmutablePair<CounterType,String>(countersToDecrease.get(random),"Remove");
} }
@@ -575,6 +546,7 @@ public class PlayerControllerAi extends PlayerController {
return new ImmutablePair<CounterType,String>(countersOnCard.get(random),"Remove"); return new ImmutablePair<CounterType,String>(countersOnCard.get(random),"Remove");
} }
@Override @Override
public byte chooseColorAllowColorless(String message, Card card, ColorSet colors) { public byte chooseColorAllowColorless(String message, Card card, ColorSet colors) {
final String c = ComputerUtilCard.getMostProminentColor(player.getCardsIn(ZoneType.Hand)); final String c = ComputerUtilCard.getMostProminentColor(player.getCardsIn(ZoneType.Hand));
@@ -598,20 +570,16 @@ public class PlayerControllerAi extends PlayerController {
if ((colors.getColor() & chosenColorMask) != 0) { if ((colors.getColor() & chosenColorMask) != 0) {
return chosenColorMask; return chosenColorMask;
} else { }
else {
return Iterables.getFirst(colors, MagicColor.WHITE); return Iterables.getFirst(colors, MagicColor.WHITE);
} }
} }
@Override @Override
public PaperCard chooseSinglePaperCard(SpellAbility sa, String message, Predicate<PaperCard> cpp, String name) { public PaperCard chooseSinglePaperCard(SpellAbility sa, String message,
throw new UnsupportedOperationException("Should not be called for AI"); // or Predicate<PaperCard> cpp, String name) {
// implement throw new UnsupportedOperationException("Should not be called for AI"); // or implement it if you know how
// it
// if
// you
// know
// how
} }
@Override @Override
@@ -621,8 +589,7 @@ public class PlayerControllerAi extends PlayerController {
@Override @Override
public CounterType chooseCounterType(List<CounterType> options, SpellAbility sa, String prompt) { public CounterType chooseCounterType(List<CounterType> options, SpellAbility sa, String prompt) {
// may write a smarter AI if you need to (with calls to AI-clas for // may write a smarter AI if you need to (with calls to AI-clas for given API ability)
// given API ability)
// TODO: ArsenalNut (06 Feb 12)computer needs // TODO: ArsenalNut (06 Feb 12)computer needs
// better logic to pick a counter type and probably // better logic to pick a counter type and probably
@@ -633,15 +600,11 @@ public class PlayerControllerAi extends PlayerController {
@Override @Override
public boolean confirmPayment(CostPart costPart, String prompt) { public boolean confirmPayment(CostPart costPart, String prompt) {
return brains.confirmPayment(costPart); // AI is expected to know what return brains.confirmPayment(costPart); // AI is expected to know what it is paying for at the moment (otherwise add another parameter to this method)
// it is paying for at the
// moment (otherwise add another
// parameter to this method)
} }
@Override @Override
public ReplacementEffect chooseSingleReplacementEffect(String prompt, List<ReplacementEffect> possibleReplacers, public ReplacementEffect chooseSingleReplacementEffect(String prompt, List<ReplacementEffect> possibleReplacers, Map<String, Object> runParams) {
Map<String, Object> runParams) {
// AI logic for choosing which replacement effect to apply // AI logic for choosing which replacement effect to apply
// happens here. // happens here.
return possibleReplacers.get(0); return possibleReplacers.get(0);
@@ -690,8 +653,7 @@ public class PlayerControllerAi extends PlayerController {
} }
} }
final PhaseHandler ph = game.getPhaseHandler(); final PhaseHandler ph = game.getPhaseHandler();
if (ph.getPlayerTurn() == sa.getActivatingPlayer() && ph.getPhase() == PhaseType.MAIN1 if (ph.getPlayerTurn() == sa.getActivatingPlayer() && ph.getPhase() == PhaseType.MAIN1 && sa.getTargetCard() != null) {
&& sa.getTargetCard() != null) {
AiAttackController aiAtk = new AiAttackController(sa.getActivatingPlayer(), sa.getTargetCard()); AiAttackController aiAtk = new AiAttackController(sa.getActivatingPlayer(), sa.getTargetCard());
String s = aiAtk.toProtectAttacker(sa); String s = aiAtk.toProtectAttacker(sa);
if (s != null) { if (s != null) {
@@ -715,22 +677,12 @@ public class PlayerControllerAi extends PlayerController {
} }
@Override @Override
public boolean payCostToPreventEffect(Cost cost, SpellAbility sa, boolean alreadyPaid, public boolean payCostToPreventEffect(Cost cost, SpellAbility sa, boolean alreadyPaid, FCollectionView<Player> allPayers) {
FCollectionView<Player> allPayers) {
final Card source = sa.getHostCard(); final Card source = sa.getHostCard();
final Ability emptyAbility = new AbilityStatic(source, cost, sa.getTargetRestrictions()) { final Ability emptyAbility = new AbilityStatic(source, cost, sa.getTargetRestrictions()) { @Override public void resolve() { } };
@Override
public void resolve() {
}
};
emptyAbility.setActivatingPlayer(player); emptyAbility.setActivatingPlayer(player);
if (ComputerUtilCost.willPayUnlessCost(sa, player, cost, alreadyPaid, allPayers) if (ComputerUtilCost.willPayUnlessCost(sa, player, cost, alreadyPaid, allPayers) && ComputerUtilCost.canPayCost(emptyAbility, player)) {
&& ComputerUtilCost.canPayCost(emptyAbility, player)) { ComputerUtil.playNoStack(player, emptyAbility, game); // AI needs something to resolve to pay that cost
ComputerUtil.playNoStack(player, emptyAbility, game); // AI needs
// something
// to resolve
// to pay that
// cost
return true; return true;
} }
return false; return false;
@@ -789,19 +741,15 @@ public class PlayerControllerAi extends PlayerController {
} }
@Override @Override
public boolean chooseCardsPile(SpellAbility sa, CardCollectionView pile1, CardCollectionView pile2, public boolean chooseCardsPile(SpellAbility sa, CardCollectionView pile1, CardCollectionView pile2, boolean faceUp) {
boolean faceUp) {
if (!faceUp) { if (!faceUp) {
// AI will choose the first pile if it is larger or the same // AI will choose the first pile if it is larger or the same
// TODO Improve this to be slightly more random to not be so // TODO Improve this to be slightly more random to not be so predictable
// predictable
return pile1.size() >= pile2.size(); return pile1.size() >= pile2.size();
} else { } else {
boolean allCreatures = Iterables.all(Iterables.concat(pile1, pile2), CardPredicates.Presets.CREATURES); boolean allCreatures = Iterables.all(Iterables.concat(pile1, pile2), CardPredicates.Presets.CREATURES);
int cmc1 = allCreatures ? ComputerUtilCard.evaluateCreatureList(pile1) int cmc1 = allCreatures ? ComputerUtilCard.evaluateCreatureList(pile1) : ComputerUtilCard.evaluatePermanentList(pile1);
: ComputerUtilCard.evaluatePermanentList(pile1); int cmc2 = allCreatures ? ComputerUtilCard.evaluateCreatureList(pile2) : ComputerUtilCard.evaluatePermanentList(pile2);
int cmc2 = allCreatures ? ComputerUtilCard.evaluateCreatureList(pile2)
: ComputerUtilCard.evaluatePermanentList(pile2);
System.out.println("value:" + cmc1 + " " + cmc2); System.out.println("value:" + cmc1 + " " + cmc2);
// for now, this assumes that the outcome will be bad // for now, this assumes that the outcome will be bad
@@ -838,17 +786,14 @@ public class PlayerControllerAi extends PlayerController {
} }
@Override @Override
public boolean payManaCost(ManaCost toPay, CostPartMana costPartMana, SpellAbility sa, public boolean payManaCost(ManaCost toPay, CostPartMana costPartMana, SpellAbility sa, String prompt /* ai needs hints as well */, boolean isActivatedSa) {
String prompt /* ai needs hints as well */, boolean isActivatedSa) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
ManaCostBeingPaid cost = isActivatedSa ? ComputerUtilMana.calculateManaCost(sa, false, 0) ManaCostBeingPaid cost = isActivatedSa ? ComputerUtilMana.calculateManaCost(sa, false, 0) : new ManaCostBeingPaid(toPay);
: new ManaCostBeingPaid(toPay);
return ComputerUtilMana.payManaCost(cost, sa, player); return ComputerUtilMana.payManaCost(cost, sa, player);
} }
@Override @Override
public Map<Card, ManaCostShard> chooseCardsForConvoke(SpellAbility sa, ManaCost manaCost, public Map<Card, ManaCostShard> chooseCardsForConvoke(SpellAbility sa, ManaCost manaCost, CardCollectionView untappedCreats0) {
CardCollectionView untappedCreats0) {
final Player ai = sa.getActivatingPlayer(); final Player ai = sa.getActivatingPlayer();
final PhaseHandler ph = ai.getGame().getPhaseHandler(); final PhaseHandler ph = ai.getGame().getPhaseHandler();
//Filter out mana sources that will interfere with payManaCost() //Filter out mana sources that will interfere with payManaCost()
@@ -866,8 +811,8 @@ public class PlayerControllerAi extends PlayerController {
//Do not convoke potential blockers until after opponent's attack //Do not convoke potential blockers until after opponent's attack
final CardCollectionView blockers = ComputerUtilCard.getLikelyBlockers(ai, null); final CardCollectionView blockers = ComputerUtilCard.getLikelyBlockers(ai, null);
if ((ph.isPlayerTurn(ai) && ph.getPhase().isAfter(PhaseType.COMBAT_BEGIN)) if ((ph.isPlayerTurn(ai) && ph.getPhase().isAfter(PhaseType.COMBAT_BEGIN)) ||
|| (!ph.isPlayerTurn(ai) && ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS))) { (!ph.isPlayerTurn(ai) && ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS))) {
untappedCreats.removeAll((List<?>)blockers); untappedCreats.removeAll((List<?>)blockers);
//Add threatened creatures //Add threatened creatures
if (!ai.getGame().getStack().isEmpty()) { if (!ai.getGame().getStack().isEmpty()) {
@@ -891,16 +836,14 @@ public class PlayerControllerAi extends PlayerController {
} else if (logic.equals("MostProminentInHumanDeck")) { } else if (logic.equals("MostProminentInHumanDeck")) {
return ComputerUtilCard.getMostProminentCardName(player.getOpponent().getCardsIn(ZoneType.Library)); return ComputerUtilCard.getMostProminentCardName(player.getOpponent().getCardsIn(ZoneType.Library));
} else if (logic.equals("MostProminentCreatureInComputerDeck")) { } else if (logic.equals("MostProminentCreatureInComputerDeck")) {
CardCollectionView cards = CardLists.getValidCards(player.getCardsIn(ZoneType.Library), "Creature", CardCollectionView cards = CardLists.getValidCards(player.getCardsIn(ZoneType.Library), "Creature", player, sa.getHostCard());
player, sa.getHostCard());
return ComputerUtilCard.getMostProminentCardName(cards); return ComputerUtilCard.getMostProminentCardName(cards);
} else if (logic.equals("BestCreatureInComputerDeck")) { } else if (logic.equals("BestCreatureInComputerDeck")) {
return ComputerUtilCard.getBestCreatureAI(player.getCardsIn(ZoneType.Library)).getName(); return ComputerUtilCard.getBestCreatureAI(player.getCardsIn(ZoneType.Library)).getName();
} else if (logic.equals("RandomInComputerDeck")) { } else if (logic.equals("RandomInComputerDeck")) {
return Aggregates.random(player.getCardsIn(ZoneType.Library)).getName(); return Aggregates.random(player.getCardsIn(ZoneType.Library)).getName();
} else if (logic.equals("MostProminentSpellInComputerDeck")) { } else if (logic.equals("MostProminentSpellInComputerDeck")) {
CardCollectionView cards = CardLists.getValidCards(player.getCardsIn(ZoneType.Library), CardCollectionView cards = CardLists.getValidCards(player.getCardsIn(ZoneType.Library), "Card.Instant,Card.Sorcery", player, sa.getHostCard());
"Card.Instant,Card.Sorcery", player, sa.getHostCard());
return ComputerUtilCard.getMostProminentCardName(cards); return ComputerUtilCard.getMostProminentCardName(cards);
} }
} else { } else {
@@ -914,21 +857,19 @@ public class PlayerControllerAi extends PlayerController {
} }
@Override @Override
public Card chooseSingleCardForZoneChange(ZoneType destination, List<ZoneType> origin, SpellAbility sa, public Card chooseSingleCardForZoneChange(ZoneType destination,
CardCollection fetchList, DelayedReveal delayedReveal, String selectPrompt, boolean isOptional, List<ZoneType> origin, SpellAbility sa, CardCollection fetchList, DelayedReveal delayedReveal,
Player decider) { String selectPrompt, boolean isOptional, Player decider) {
if (delayedReveal != null) { if (delayedReveal != null) {
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
delayedReveal.getMessagePrefix());
} }
return ChangeZoneAi.chooseCardToHiddenOriginChangeZone(destination, origin, sa, fetchList, player, decider); return ChangeZoneAi.chooseCardToHiddenOriginChangeZone(destination, origin, sa, fetchList, player, decider);
} }
@Override @Override
public void resetAtEndOfTurn() { public void resetAtEndOfTurn() {
// TODO - if card memory is ever used to remember something for longer // TODO - if card memory is ever used to remember something for longer than a turn, make sure it's not reset here.
// than a turn, make sure it's not reset here.
getAi().getCardMemory().clearAllRemembered(); getAi().getCardMemory().clearAllRemembered();
} }
@@ -941,7 +882,6 @@ public class PlayerControllerAi extends PlayerController {
public void awaitNextInput() { public void awaitNextInput() {
// Do nothing // Do nothing
} }
@Override @Override
public void cancelAwaitNextInput() { public void cancelAwaitNextInput() {
// Do nothing // Do nothing