- 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,7 +55,8 @@ import org.apache.commons.lang3.tuple.Pair;
import java.security.InvalidParameterException;
import java.util.*;
/**
/**
* A prototype for player controller class
*
* Handles phase skips for now.
@@ -68,11 +69,11 @@ public class PlayerControllerAi extends PlayerController {
brains = new AiController(p, game);
}
public void allowCheatShuffle(boolean value) {
public void allowCheatShuffle(boolean value){
brains.allowCheatShuffle(value);
}
public void setUseSimulation(boolean value) {
brains.setUseSimulation(value);
}
@@ -80,7 +81,8 @@ public class PlayerControllerAi extends PlayerController {
public SpellAbility getAbilityToPlay(Card hostCard, List<SpellAbility> abilities, ITriggerEvent triggerEvent) {
if (abilities.size() == 0) {
return null;
} else {
}
else {
return abilities.get(0);
}
}
@@ -101,60 +103,51 @@ public class PlayerControllerAi extends PlayerController {
}
@Override
public Map<Card, Integer> assignCombatDamage(Card attacker, CardCollectionView blockers, int damageDealt,
GameEntity defender, boolean overrideOrder) {
public Map<Card, Integer> assignCombatDamage(Card attacker, CardCollectionView blockers, int damageDealt, GameEntity defender, boolean overrideOrder) {
return ComputerUtilCombat.distributeAIDamage(attacker, blockers, damageDealt, defender, overrideOrder);
}
@Override
public Integer announceRequirements(SpellAbility ability, String announce, boolean allowZero) {
// For now, these "announcements" are made within the AI classes of the
// appropriate SA effects
// For now, these "announcements" are made within the AI classes of the appropriate SA effects
if (ability.getApi() != null) {
switch (ability.getApi()) {
case ChooseNumber:
return ability.getActivatingPlayer().isOpponentOf(player) ? 0
: ComputerUtilMana.determineLeftoverMana(ability, player);
case BidLife:
return 0;
default:
return null;
case ChooseNumber:
return ability.getActivatingPlayer().isOpponentOf(player) ? 0 : ComputerUtilMana.determineLeftoverMana(ability, player);
case BidLife:
return 0;
default:
return null;
}
}
return null; // return incorrect value to indicate that
}
@Override
public CardCollectionView choosePermanentsToSacrifice(SpellAbility sa, int min, int max,
CardCollectionView validTargets, String message) {
public CardCollectionView choosePermanentsToSacrifice(SpellAbility sa, int min, int max, CardCollectionView validTargets, String message) {
return ComputerUtil.choosePermanentsToSacrifice(player, validTargets, max, sa, false, min == 0);
}
@Override
public CardCollectionView choosePermanentsToDestroy(SpellAbility sa, int min, int max,
CardCollectionView validTargets, String message) {
public CardCollectionView choosePermanentsToDestroy(SpellAbility sa, int min, int max, CardCollectionView validTargets, String message) {
return ComputerUtil.choosePermanentsToSacrifice(player, validTargets, max, sa, true, min == 0);
}
@Override
public CardCollectionView chooseCardsForEffect(CardCollectionView sourceList, SpellAbility sa, String title,
int min, int max, boolean isOptional) {
public CardCollectionView chooseCardsForEffect(CardCollectionView sourceList, SpellAbility sa, String title, int min, int max, boolean isOptional) {
return brains.chooseCardsForEffect(sourceList, sa, min, max, isOptional);
}
@Override
public <T extends GameEntity> T chooseSingleEntityForEffect(FCollectionView<T> optionList,
DelayedReveal delayedReveal, SpellAbility sa, String title, boolean isOptional, Player targetedPlayer) {
public <T extends GameEntity> T chooseSingleEntityForEffect(FCollectionView<T> optionList, DelayedReveal delayedReveal, SpellAbility sa, String title, boolean isOptional, Player targetedPlayer) {
if (delayedReveal != null) {
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(),
delayedReveal.getMessagePrefix());
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
}
ApiType api = sa.getApi();
if (null == api) {
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,
targetedPlayer);
return SpellApiToAi.Converter.get(api).chooseSingleEntity(player, sa, (FCollection<T>)optionList, isOptional, targetedPlayer);
}
@Override
@@ -170,10 +163,10 @@ public class PlayerControllerAi extends PlayerController {
public boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message) {
return getAi().confirmAction(sa, mode, message);
}
@Override
public boolean confirmBidAction(SpellAbility sa, PlayerActionConfirmMode mode, String string, int bid,
Player winner) {
public boolean confirmBidAction(SpellAbility sa, PlayerActionConfirmMode mode, String string,
int bid, Player winner) {
return getAi().confirmBidAction(sa, mode, string, bid, winner);
}
@@ -183,15 +176,13 @@ public class PlayerControllerAi extends PlayerController {
}
@Override
public boolean confirmTrigger(SpellAbility sa, Trigger regtrig, Map<String, String> triggerParams,
boolean isMandatory) {
public boolean confirmTrigger(SpellAbility sa, Trigger regtrig, Map<String, String> triggerParams, boolean isMandatory) {
if (sa.getHostCard().getName().equals("Deathmist Raptor")) {
return true;
}
if (triggerParams.containsKey("DelayedTrigger") || isMandatory) {
// TODO: The only card with an optional delayed trigger is Shirei,
// Shizo's Caretaker,
// needs to be expanded when a more difficult cards comes up
//TODO: The only card with an optional delayed trigger is Shirei, Shizo's Caretaker,
// needs to be expanded when a more difficult cards comes up
return true;
}
// Store/replace target choices more properly to get this SA cleared.
@@ -210,10 +201,8 @@ public class PlayerControllerAi extends PlayerController {
subtc = sub.getTargets();
sub.resetTargets();
}
// There is no way this doTrigger here will have the same target as
// stored above
// So it's possible it's making a different decision here than will
// actually happen
// There is no way this doTrigger here will have the same target as stored above
// So it's possible it's making a different decision here than will actually happen
if (!brains.doTrigger(sa, false)) {
ret = false;
}
@@ -238,10 +227,10 @@ public class PlayerControllerAi extends PlayerController {
public CardCollection orderBlockers(Card attacker, CardCollection blockers) {
return AiBlockController.orderBlockers(attacker, blockers);
}
@Override
public CardCollection orderBlocker(Card attacker, Card blocker, CardCollection oldBlockers) {
return AiBlockController.orderBlocker(attacker, blocker, oldBlockers);
return AiBlockController.orderBlocker(attacker, blocker, oldBlockers);
};
@Override
@@ -264,10 +253,11 @@ public class PlayerControllerAi extends PlayerController {
CardCollection toBottom = new CardCollection();
CardCollection toTop = new CardCollection();
for (Card c : topN) {
for (Card c: topN) {
if (ComputerUtil.scryWillMoveCardToBottomOfLibrary(player, c)) {
toBottom.add(c);
} else {
}
else {
toTop.add(c);
}
}
@@ -279,38 +269,37 @@ public class PlayerControllerAi extends PlayerController {
@Override
public boolean willPutCardOnTop(Card c) {
return true; // AI does not know what will happen next (another clash or
// that would become his topdeck)
return true; // AI does not know what will happen next (another clash or that would become his topdeck)
}
@Override
public CardCollectionView orderMoveToZoneList(CardCollectionView cards, ZoneType destinationZone) {
// TODO Add logic for AI ordering here
//TODO Add logic for AI ordering here
return cards;
}
@Override
public CardCollection chooseCardsToDiscardFrom(Player p, SpellAbility sa, CardCollection validCards, int min,
int max) {
public CardCollection chooseCardsToDiscardFrom(Player p, SpellAbility sa, CardCollection validCards, int min, int max) {
if (p == player) {
return brains.getCardsToDiscard(min, max, validCards, sa);
}
boolean isTargetFriendly = !p.isOpponentOf(player);
return isTargetFriendly ? ComputerUtil.getCardsToDiscardFromFriend(player, p, sa, validCards, min, max)
: ComputerUtil.getCardsToDiscardFromOpponent(player, p, sa, validCards, min, max);
return isTargetFriendly
? ComputerUtil.getCardsToDiscardFromFriend(player, p, sa, validCards, min, max)
: ComputerUtil.getCardsToDiscardFromOpponent(player, p, sa, validCards, min, max);
}
@Override
public void playSpellAbilityForFree(SpellAbility copySA, boolean mayChooseNewTargets) {
// Ai is known to set targets in doTrigger, so if it cannot choose new
// targets, we won't call canPlays
// Ai is known to set targets in doTrigger, so if it cannot choose new targets, we won't call canPlays
if (mayChooseNewTargets) {
if (copySA instanceof Spell) {
Spell spell = (Spell) copySA;
((PlayerControllerAi) player.getController()).getAi().canPlayFromEffectAI(spell, true, true);
} else {
}
else {
getAi().canPlaySa(copySA);
}
}
@@ -320,9 +309,7 @@ public class PlayerControllerAi extends PlayerController {
@Override
public void playSpellAbilityNoStack(SpellAbility effectSA, boolean canSetupTargets) {
if (canSetupTargets)
brains.doTrigger(effectSA, true); // first parameter does not
// matter, since return value
// won't be used
brains.doTrigger(effectSA, true); // first parameter does not matter, since return value won't be used
ComputerUtil.playNoStack(player, effectSA, game);
}
@@ -338,34 +325,33 @@ public class PlayerControllerAi extends PlayerController {
@Override
public TargetChoices chooseNewTargetsFor(SpellAbility ability) {
// AI currently can't do this. But when it can it will need to be based
// on Ability API
// AI currently can't do this. But when it can it will need to be based on Ability API
return null;
}
@Override
public CardCollectionView chooseCardsToDiscardUnlessType(int num, CardCollectionView hand, String uType,
SpellAbility sa) {
public CardCollectionView chooseCardsToDiscardUnlessType(int num, CardCollectionView hand, String uType, SpellAbility sa) {
final CardCollectionView cardsOfType = CardLists.getType(hand, uType);
if (!cardsOfType.isEmpty()) {
Card toDiscard = Aggregates.itemWithMin(cardsOfType, CardPredicates.Accessors.fnGetCmc);
return new CardCollection(toDiscard);
}
return getAi().getCardsToDiscard(num, (String[]) null, sa);
return getAi().getCardsToDiscard(num, (String[])null, sa);
}
@Override
public Mana chooseManaFromPool(List<Mana> manaChoices) {
return manaChoices.get(0); // no brains used
}
@Override
public String chooseSomeType(String kindOfType, SpellAbility sa, List<String> validTypes, List<String> invalidTypes,
boolean isOptional) {
public String chooseSomeType(String kindOfType, SpellAbility sa, List<String> validTypes, List<String> invalidTypes, boolean isOptional) {
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);
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");
}
game.getAction().nofityOfValue(sa, null, "Computer picked: " + chosen, player);
return chosen;
@@ -377,13 +363,12 @@ public class PlayerControllerAi extends PlayerController {
}
@Override
public boolean confirmReplacementEffect(ReplacementEffect replacementEffect, SpellAbility effectSA,
String question) {
public boolean confirmReplacementEffect(ReplacementEffect replacementEffect, SpellAbility effectSA, String question) {
return brains.aiShouldRun(replacementEffect, effectSA);
}
@Override
public CardCollectionView getCardsToMulligan(Player firstPlayer) {
public CardCollectionView getCardsToMulligan(Player firstPlayer) {
if (!ComputerUtil.wantMulligan(player)) {
return null;
}
@@ -405,7 +390,7 @@ public class PlayerControllerAi extends PlayerController {
public List<SpellAbility> chooseSpellAbilityToPlay() {
return brains.chooseSpellAbilityToPlay();
}
@Override
public void playChosenSpellAbility(SpellAbility sa) {
// System.out.println("Playing sa: " + sa);
@@ -414,26 +399,22 @@ public class PlayerControllerAi extends PlayerController {
} else {
ComputerUtil.handlePlayingSpellAbility(player, sa, game);
}
}
}
@Override
public CardCollection chooseCardsToDiscardToMaximumHandSize(int numDiscard) {
return brains.getCardsToDiscard(numDiscard, (String[]) null, null);
return brains.getCardsToDiscard(numDiscard, (String[])null, null);
}
@Override
public CardCollection chooseCardsToRevealFromHand(int min, int max, CardCollectionView valid) {
int numCardsToReveal = Math.min(max, valid.size());
return numCardsToReveal == 0 ? new CardCollection() : (CardCollection) valid.subList(0, numCardsToReveal);
return numCardsToReveal == 0 ? new CardCollection() : (CardCollection)valid.subList(0, numCardsToReveal);
}
@Override
public boolean payManaOptional(Card c, Cost cost, SpellAbility sa, String prompt, ManaPaymentPurpose purpose) {
final Ability ability = new AbilityStatic(c, cost, null) {
@Override
public void resolve() {
}
};
final Ability ability = new AbilityStatic(c, cost, null) { @Override public void resolve() {} };
ability.setActivatingPlayer(c.getController());
if (ComputerUtilCost.canPayCost(ability, c.getController())) {
@@ -445,8 +426,7 @@ public class PlayerControllerAi extends PlayerController {
@Override
public List<SpellAbility> chooseSaToActivateFromOpeningHand(List<SpellAbility> usableFromOpeningHand) {
// AI would play everything. But limits to one copy of (Leyline of
// Singularity) and (Gemstone Caverns)
// AI would play everything. But limits to one copy of (Leyline of Singularity) and (Gemstone Caverns)
return brains.chooseSaToActivateFromOpeningHand(usableFromOpeningHand);
}
@@ -454,16 +434,13 @@ public class PlayerControllerAi extends PlayerController {
public int chooseNumber(SpellAbility sa, String title, int min, int max) {
return brains.chooseNumber(sa, title, min, max);
}
public int chooseNumber(SpellAbility sa, String title, List<Integer> options, Player relatedPlayer) {
return brains.chooseNumber(sa, title, options, relatedPlayer);
}
/*
* (non-Javadoc)
*
* @see forge.game.player.PlayerController#chooseFlipResult(forge.Card,
* forge.game.player.Player, java.lang.String[], boolean)
/* (non-Javadoc)
* @see forge.game.player.PlayerController#chooseFlipResult(forge.Card, forge.game.player.Player, java.lang.String[], boolean)
*/
@Override
public boolean chooseFlipResult(SpellAbility sa, Player flipper, boolean[] results, boolean call) {
@@ -485,37 +462,31 @@ public class PlayerControllerAi extends PlayerController {
}
@Override
public Pair<SpellAbilityStackInstance, GameObject> chooseTarget(SpellAbility saSrc,
List<Pair<SpellAbilityStackInstance, GameObject>> allTargets) {
public Pair<SpellAbilityStackInstance, GameObject> chooseTarget(SpellAbility saSrc, List<Pair<SpellAbilityStackInstance, GameObject>> allTargets) {
// TODO Teach AI how to use Spellskite
return allTargets.get(0);
}
@Override
public void notifyOfValue(SpellAbility saSource, GameObject realtedTarget, String value) {
// AI should take into consideration creature types, numbers and other
// information (mostly choices) arriving through this channel
// AI should take into consideration creature types, numbers and other information (mostly choices) arriving through this channel
}
@Override
public boolean chooseBinary(SpellAbility sa, String question, BinaryChoiceType kindOfChoice, Boolean defaultVal) {
switch (kindOfChoice) {
case TapOrUntap:
return true;
case UntapOrLeaveTapped:
return defaultVal != null && defaultVal.booleanValue();
case UntapTimeVault:
return false; // TODO Should AI skip his turn for time vault?
case LeftOrRight:
return brains.chooseDirection(sa);
default:
return MyRandom.getRandom().nextBoolean();
switch(kindOfChoice) {
case TapOrUntap: return true;
case UntapOrLeaveTapped: return defaultVal != null && defaultVal.booleanValue();
case UntapTimeVault: return false; // TODO Should AI skip his turn for time vault?
case LeftOrRight: return brains.chooseDirection(sa);
default:
return MyRandom.getRandom().nextBoolean();
}
}
@Override
public Card chooseProtectionShield(GameEntity entityBeingDamaged, List<String> options,
Map<String, Card> choiceMap) {
public Card chooseProtectionShield(GameEntity entityBeingDamaged, List<String> options, Map<String, Card> choiceMap) {
int i = MyRandom.getRandom().nextInt(options.size());
return choiceMap.get(options.get(i));
}
@@ -537,10 +508,9 @@ public class PlayerControllerAi extends PlayerController {
}
@Override
public Pair<CounterType, String> chooseAndRemoveOrPutCounter(Card cardWithCounter) {
public Pair<CounterType,String> chooseAndRemoveOrPutCounter(Card cardWithCounter) {
if (!cardWithCounter.hasCounters()) {
System.out.println(
"chooseCounterType was reached with a card with no counters on it. Consider filtering this card out earlier");
System.out.println("chooseCounterType was reached with a card with no counters on it. Consider filtering this card out earlier");
return null;
}
@@ -554,7 +524,7 @@ public class PlayerControllerAi extends PlayerController {
for (final CounterType counter : cardWithCounter.getCounters().keySet()) {
if ((!ComputerUtil.isNegativeCounter(counter, cardWithCounter) && allies.contains(controller))
|| (ComputerUtil.isNegativeCounter(counter, cardWithCounter) && enemies.contains(controller))) {
|| (ComputerUtil.isNegativeCounter(counter, cardWithCounter) && enemies.contains(controller))) {
countersToIncrease.add(counter);
} else {
countersToDecrease.add(counter);
@@ -563,18 +533,20 @@ public class PlayerControllerAi extends PlayerController {
if (!countersToIncrease.isEmpty()) {
int random = MyRandom.getRandom().nextInt(countersToIncrease.size());
return new ImmutablePair<CounterType, String>(countersToIncrease.get(random), "Put");
} else if (!countersToDecrease.isEmpty()) {
return new ImmutablePair<CounterType,String>(countersToIncrease.get(random),"Put");
}
else if (!countersToDecrease.isEmpty()) {
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");
}
// shouldn't reach here but just in case, remove random counter
List<CounterType> countersOnCard = new ArrayList<CounterType>();
int random = MyRandom.getRandom().nextInt(countersOnCard.size());
return new ImmutablePair<CounterType, String>(countersOnCard.get(random), "Remove");
return new ImmutablePair<CounterType,String>(countersOnCard.get(random),"Remove");
}
@Override
public byte chooseColorAllowColorless(String message, Card card, ColorSet colors) {
final String c = ComputerUtilCard.getMostProminentColor(player.getCardsIn(ZoneType.Hand));
@@ -582,7 +554,7 @@ public class PlayerControllerAi extends PlayerController {
if ((colors.getColor() & chosenColorMask) != 0) {
return chosenColorMask;
} else {
return Iterables.getFirst(colors, (byte) 0);
return Iterables.getFirst(colors, (byte)0);
}
}
@@ -598,20 +570,16 @@ public class PlayerControllerAi extends PlayerController {
if ((colors.getColor() & chosenColorMask) != 0) {
return chosenColorMask;
} else {
}
else {
return Iterables.getFirst(colors, MagicColor.WHITE);
}
}
@Override
public PaperCard chooseSinglePaperCard(SpellAbility sa, String message, Predicate<PaperCard> cpp, String name) {
throw new UnsupportedOperationException("Should not be called for AI"); // or
// implement
// it
// if
// you
// know
// how
public PaperCard chooseSinglePaperCard(SpellAbility sa, String message,
Predicate<PaperCard> cpp, String name) {
throw new UnsupportedOperationException("Should not be called for AI"); // or implement it if you know how
}
@Override
@@ -621,8 +589,7 @@ public class PlayerControllerAi extends PlayerController {
@Override
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
// given API ability)
// may write a smarter AI if you need to (with calls to AI-clas for given API ability)
// TODO: ArsenalNut (06 Feb 12)computer needs
// better logic to pick a counter type and probably
@@ -633,15 +600,11 @@ public class PlayerControllerAi extends PlayerController {
@Override
public boolean confirmPayment(CostPart costPart, String prompt) {
return brains.confirmPayment(costPart); // AI is expected to know what
// it is paying for at the
// moment (otherwise add another
// parameter to this method)
return brains.confirmPayment(costPart); // AI is expected to know what it is paying for at the moment (otherwise add another parameter to this method)
}
@Override
public ReplacementEffect chooseSingleReplacementEffect(String prompt, List<ReplacementEffect> possibleReplacers,
Map<String, Object> runParams) {
public ReplacementEffect chooseSingleReplacementEffect(String prompt, List<ReplacementEffect> possibleReplacers, Map<String, Object> runParams) {
// AI logic for choosing which replacement effect to apply
// happens here.
return possibleReplacers.get(0);
@@ -650,7 +613,7 @@ public class PlayerControllerAi extends PlayerController {
@Override
public String chooseProtectionType(String string, SpellAbility sa, List<String> choices) {
String choice = choices.get(0);
SpellAbility hostsa = null; // for Protect sub-ability
SpellAbility hostsa = null; //for Protect sub-ability
if (game.stack.size() > 1) {
for (SpellAbilityStackInstance si : game.getStack()) {
SpellAbility spell = si.getSpellAbility(true);
@@ -690,8 +653,7 @@ public class PlayerControllerAi extends PlayerController {
}
}
final PhaseHandler ph = game.getPhaseHandler();
if (ph.getPlayerTurn() == sa.getActivatingPlayer() && ph.getPhase() == PhaseType.MAIN1
&& sa.getTargetCard() != null) {
if (ph.getPlayerTurn() == sa.getActivatingPlayer() && ph.getPhase() == PhaseType.MAIN1 && sa.getTargetCard() != null) {
AiAttackController aiAtk = new AiAttackController(sa.getActivatingPlayer(), sa.getTargetCard());
String s = aiAtk.toProtectAttacker(sa);
if (s != null) {
@@ -715,22 +677,12 @@ public class PlayerControllerAi extends PlayerController {
}
@Override
public boolean payCostToPreventEffect(Cost cost, SpellAbility sa, boolean alreadyPaid,
FCollectionView<Player> allPayers) {
public boolean payCostToPreventEffect(Cost cost, SpellAbility sa, boolean alreadyPaid, FCollectionView<Player> allPayers) {
final Card source = sa.getHostCard();
final Ability emptyAbility = new AbilityStatic(source, cost, sa.getTargetRestrictions()) {
@Override
public void resolve() {
}
};
final Ability emptyAbility = new AbilityStatic(source, cost, sa.getTargetRestrictions()) { @Override public void resolve() { } };
emptyAbility.setActivatingPlayer(player);
if (ComputerUtilCost.willPayUnlessCost(sa, player, cost, alreadyPaid, allPayers)
&& ComputerUtilCost.canPayCost(emptyAbility, player)) {
ComputerUtil.playNoStack(player, emptyAbility, game); // AI needs
// something
// to resolve
// to pay that
// cost
if (ComputerUtilCost.willPayUnlessCost(sa, player, cost, alreadyPaid, allPayers) && ComputerUtilCost.canPayCost(emptyAbility, player)) {
ComputerUtil.playNoStack(player, emptyAbility, game); // AI needs something to resolve to pay that cost
return true;
}
return false;
@@ -739,12 +691,12 @@ public class PlayerControllerAi extends PlayerController {
@Override
public void orderAndPlaySimultaneousSa(List<SpellAbility> activePlayerSAs) {
for (final SpellAbility sa : activePlayerSAs) {
prepareSingleSa(sa.getHostCard(), sa, true);
prepareSingleSa(sa.getHostCard(),sa,true);
ComputerUtil.playStack(sa, player, game);
}
}
private void prepareSingleSa(final Card host, final SpellAbility sa, boolean isMandatory) {
private void prepareSingleSa(final Card host, final SpellAbility sa, boolean isMandatory){
if (sa.hasParam("TargetingPlayer")) {
Player targetingPlayer = AbilityUtils.getDefinedPlayers(host, sa.getParam("TargetingPlayer"), sa).get(0);
sa.setTargetingPlayer(targetingPlayer);
@@ -772,7 +724,7 @@ public class PlayerControllerAi extends PlayerController {
} else {
ComputerUtil.playStack(tgtSA, player, game);
}
} else
} else
return false; // didn't play spell
}
return true;
@@ -789,19 +741,15 @@ public class PlayerControllerAi extends PlayerController {
}
@Override
public boolean chooseCardsPile(SpellAbility sa, CardCollectionView pile1, CardCollectionView pile2,
boolean faceUp) {
public boolean chooseCardsPile(SpellAbility sa, CardCollectionView pile1, CardCollectionView pile2, boolean faceUp) {
if (!faceUp) {
// 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
// predictable
// TODO Improve this to be slightly more random to not be so predictable
return pile1.size() >= pile2.size();
} else {
boolean allCreatures = Iterables.all(Iterables.concat(pile1, pile2), CardPredicates.Presets.CREATURES);
int cmc1 = allCreatures ? ComputerUtilCard.evaluateCreatureList(pile1)
: ComputerUtilCard.evaluatePermanentList(pile1);
int cmc2 = allCreatures ? ComputerUtilCard.evaluateCreatureList(pile2)
: ComputerUtilCard.evaluatePermanentList(pile2);
int cmc1 = allCreatures ? ComputerUtilCard.evaluateCreatureList(pile1) : ComputerUtilCard.evaluatePermanentList(pile1);
int cmc2 = allCreatures ? ComputerUtilCard.evaluateCreatureList(pile2) : ComputerUtilCard.evaluatePermanentList(pile2);
System.out.println("value:" + cmc1 + " " + cmc2);
// for now, this assumes that the outcome will be bad
@@ -815,7 +763,7 @@ public class PlayerControllerAi extends PlayerController {
public void revealAnte(String message, Multimap<Player, PaperCard> removedAnteCards) {
// Ai won't understand that anyway
}
@Override
public Collection<? extends PaperCard> complainCardsCantPlayWell(Deck myDeck) {
return brains.complainCardsCantPlayWell(myDeck);
@@ -826,10 +774,10 @@ public class PlayerControllerAi extends PlayerController {
return brains.getBooleanProperty(AiProps.CHEAT_WITH_MANA_ON_SHUFFLE) ? brains.cheatShuffle(list) : list;
}
@Override
public CardShields chooseRegenerationShield(Card c) {
return Iterables.getFirst(c.getShields(), null);
}
@Override
public CardShields chooseRegenerationShield(Card c) {
return Iterables.getFirst(c.getShields(), null);
}
@Override
public List<PaperCard> chooseCardsYouWonToAddToDeck(List<PaperCard> losses) {
@@ -838,38 +786,35 @@ public class PlayerControllerAi extends PlayerController {
}
@Override
public boolean payManaCost(ManaCost toPay, CostPartMana costPartMana, SpellAbility sa,
String prompt /* ai needs hints as well */, boolean isActivatedSa) {
public boolean payManaCost(ManaCost toPay, CostPartMana costPartMana, SpellAbility sa, String prompt /* ai needs hints as well */, boolean isActivatedSa) {
// TODO Auto-generated method stub
ManaCostBeingPaid cost = isActivatedSa ? ComputerUtilMana.calculateManaCost(sa, false, 0)
: new ManaCostBeingPaid(toPay);
ManaCostBeingPaid cost = isActivatedSa ? ComputerUtilMana.calculateManaCost(sa, false, 0) : new ManaCostBeingPaid(toPay);
return ComputerUtilMana.payManaCost(cost, sa, player);
}
@Override
public Map<Card, ManaCostShard> chooseCardsForConvoke(SpellAbility sa, ManaCost manaCost,
CardCollectionView untappedCreats0) {
public Map<Card, ManaCostShard> chooseCardsForConvoke(SpellAbility sa, ManaCost manaCost, CardCollectionView untappedCreats0) {
final Player ai = sa.getActivatingPlayer();
final PhaseHandler ph = ai.getGame().getPhaseHandler();
// Filter out mana sources that will interfere with payManaCost()
//Filter out mana sources that will interfere with payManaCost()
CardCollection untappedCreats = CardLists.filter(untappedCreats0, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.getManaAbilities().isEmpty();
}
});
// Only convoke after attackers have been declared
//Only convoke after attackers have been declared
if (ph.isPlayerTurn(ai) && ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
return new HashMap<Card, ManaCostShard>();
}
// 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);
if ((ph.isPlayerTurn(ai) && ph.getPhase().isAfter(PhaseType.COMBAT_BEGIN))
|| (!ph.isPlayerTurn(ai) && ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS))) {
untappedCreats.removeAll((List<?>) blockers);
// Add threatened creatures
if ((ph.isPlayerTurn(ai) && ph.getPhase().isAfter(PhaseType.COMBAT_BEGIN)) ||
(!ph.isPlayerTurn(ai) && ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS))) {
untappedCreats.removeAll((List<?>)blockers);
//Add threatened creatures
if (!ai.getGame().getStack().isEmpty()) {
final List<GameObject> objects = ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), null);
for (Card c : blockers) {
@@ -891,16 +836,14 @@ public class PlayerControllerAi extends PlayerController {
} else if (logic.equals("MostProminentInHumanDeck")) {
return ComputerUtilCard.getMostProminentCardName(player.getOpponent().getCardsIn(ZoneType.Library));
} else if (logic.equals("MostProminentCreatureInComputerDeck")) {
CardCollectionView cards = CardLists.getValidCards(player.getCardsIn(ZoneType.Library), "Creature",
player, sa.getHostCard());
CardCollectionView cards = CardLists.getValidCards(player.getCardsIn(ZoneType.Library), "Creature", player, sa.getHostCard());
return ComputerUtilCard.getMostProminentCardName(cards);
} else if (logic.equals("BestCreatureInComputerDeck")) {
return ComputerUtilCard.getBestCreatureAI(player.getCardsIn(ZoneType.Library)).getName();
} else if (logic.equals("RandomInComputerDeck")) {
return Aggregates.random(player.getCardsIn(ZoneType.Library)).getName();
} else if (logic.equals("MostProminentSpellInComputerDeck")) {
CardCollectionView cards = CardLists.getValidCards(player.getCardsIn(ZoneType.Library),
"Card.Instant,Card.Sorcery", player, sa.getHostCard());
CardCollectionView cards = CardLists.getValidCards(player.getCardsIn(ZoneType.Library), "Card.Instant,Card.Sorcery", player, sa.getHostCard());
return ComputerUtilCard.getMostProminentCardName(cards);
}
} else {
@@ -914,21 +857,19 @@ public class PlayerControllerAi extends PlayerController {
}
@Override
public Card chooseSingleCardForZoneChange(ZoneType destination, List<ZoneType> origin, SpellAbility sa,
CardCollection fetchList, DelayedReveal delayedReveal, String selectPrompt, boolean isOptional,
Player decider) {
public Card chooseSingleCardForZoneChange(ZoneType destination,
List<ZoneType> origin, SpellAbility sa, CardCollection fetchList, DelayedReveal delayedReveal,
String selectPrompt, boolean isOptional, Player decider) {
if (delayedReveal != null) {
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(),
delayedReveal.getMessagePrefix());
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
}
return ChangeZoneAi.chooseCardToHiddenOriginChangeZone(destination, origin, sa, fetchList, player, decider);
}
@Override
public void resetAtEndOfTurn() {
// TODO - if card memory is ever used to remember something for longer
// than a turn, make sure it's not reset here.
// TODO - if card memory is ever used to remember something for longer than a turn, make sure it's not reset here.
getAi().getCardMemory().clearAllRemembered();
}
@@ -941,7 +882,6 @@ public class PlayerControllerAi extends PlayerController {
public void awaitNextInput() {
// Do nothing
}
@Override
public void cancelAwaitNextInput() {
// Do nothing