Merge branch 'master' of git.cardforge.org:core-developers/forge into agetian-master

This commit is contained in:
Agetian
2019-09-06 07:45:57 +03:00
474 changed files with 2628 additions and 2669 deletions

View File

@@ -6,7 +6,7 @@
<parent> <parent>
<artifactId>forge</artifactId> <artifactId>forge</artifactId>
<groupId>forge</groupId> <groupId>forge</groupId>
<version>1.6.28-SNAPSHOT</version> <version>1.6.29-SNAPSHOT</version>
</parent> </parent>
<artifactId>forge-ai</artifactId> <artifactId>forge-ai</artifactId>

View File

@@ -1,5 +1,5 @@
package forge.ai; package forge.ai;
public enum AIOption { public enum AIOption {
USE_SIMULATION; USE_SIMULATION
} }

View File

@@ -1021,7 +1021,7 @@ public class AiAttackController {
} // stay at home to block } // stay at home to block
if ( LOG_AI_ATTACKS ) if ( LOG_AI_ATTACKS )
System.out.println(String.valueOf(this.aiAggression) + " = ai aggression"); System.out.println(this.aiAggression + " = ai aggression");
// **************** // ****************
// Evaluation the end // Evaluation the end
@@ -1457,7 +1457,7 @@ public class AiAttackController {
if (artifact != null) { if (artifact != null) {
return artifact; return artifact;
} }
return null; //should never get here return null;//should never get here
} }
private void doLightmineFieldAttackLogic(List<Card> attackersLeft, int numForcedAttackers, boolean playAggro) { private void doLightmineFieldAttackLogic(List<Card> attackersLeft, int numForcedAttackers, boolean playAggro) {

View File

@@ -859,7 +859,7 @@ public class AiBlockController {
damageToPW += ComputerUtilCombat.predictDamageTo((Card) def, pwatkr.getNetCombatDamage(), pwatkr, true); damageToPW += ComputerUtilCombat.predictDamageTo((Card) def, pwatkr.getNetCombatDamage(), pwatkr, true);
} }
} }
if ((!onlyIfLethal && damageToPW > 0) || damageToPW >= ((Card) def).getCounters(CounterType.LOYALTY)) { if ((!onlyIfLethal && damageToPW > 0) || damageToPW >= def.getCounters(CounterType.LOYALTY)) {
threatenedPWs.add((Card) def); threatenedPWs.add((Card) def);
} }
} }
@@ -879,7 +879,7 @@ public class AiBlockController {
if (!chumpPWDefenders.isEmpty()) { if (!chumpPWDefenders.isEmpty()) {
for (final Card attacker : attackers) { for (final Card attacker : attackers) {
GameEntity def = combat.getDefenderByAttacker(attacker); GameEntity def = combat.getDefenderByAttacker(attacker);
if (def instanceof Card && threatenedPWs.contains((Card) def)) { if (def instanceof Card && threatenedPWs.contains(def)) {
if (attacker.hasKeyword(Keyword.TRAMPLE)) { if (attacker.hasKeyword(Keyword.TRAMPLE)) {
// don't bother trying to chump a trampling creature // don't bother trying to chump a trampling creature
continue; continue;
@@ -914,7 +914,7 @@ public class AiBlockController {
pwDefenders.addAll(combat.getBlockers(pwAtk)); pwDefenders.addAll(combat.getBlockers(pwAtk));
} else { } else {
isFullyBlocked = false; isFullyBlocked = false;
damageToPW += ComputerUtilCombat.predictDamageTo((Card) pw, pwAtk.getNetCombatDamage(), pwAtk, true); damageToPW += ComputerUtilCombat.predictDamageTo(pw, pwAtk.getNetCombatDamage(), pwAtk, true);
} }
} }
if (!isFullyBlocked && damageToPW >= pw.getCounters(CounterType.LOYALTY)) { if (!isFullyBlocked && damageToPW >= pw.getCounters(CounterType.LOYALTY)) {
@@ -1329,13 +1329,9 @@ public class AiBlockController {
&& ((Card) combat.getDefenderByAttacker(attacker)).isPlaneswalker(); && ((Card) combat.getDefenderByAttacker(attacker)).isPlaneswalker();
boolean wantToTradeDownToSavePW = chanceToTradeDownToSaveWalker > 0; boolean wantToTradeDownToSavePW = chanceToTradeDownToSaveWalker > 0;
if (((evalBlk <= evalAtk + 1) || (wantToSavePlaneswalker && wantToTradeDownToSavePW)) // "1" accounts for tapped. return ((evalBlk <= evalAtk + 1) || (wantToSavePlaneswalker && wantToTradeDownToSavePW)) // "1" accounts for tapped.
&& powerParityOrHigher && powerParityOrHigher
&& (creatureParityOrAllowedDiff || wantToTradeWithCreatInHand) && (creatureParityOrAllowedDiff || wantToTradeWithCreatInHand)
&& (MyRandom.percentTrue(chance) || wantToSavePlaneswalker)) { && (MyRandom.percentTrue(chance) || wantToSavePlaneswalker);
return true;
}
return false;
} }
} }

View File

@@ -137,7 +137,7 @@ public class AiCardMemory {
Set<Card> memorySet = getMemorySet(set); Set<Card> memorySet = getMemorySet(set);
return memorySet == null ? false : memorySet.contains(c); return memorySet != null && memorySet.contains(c);
} }
/** /**
@@ -291,7 +291,7 @@ public class AiCardMemory {
* @return true, if the given memory set contains no remembered cards. * @return true, if the given memory set contains no remembered cards.
*/ */
public boolean isMemorySetEmpty(MemorySet set) { public boolean isMemorySetEmpty(MemorySet set) {
return set == null ? true : getMemorySet(set).isEmpty(); return set == null || getMemorySet(set).isEmpty();
} }
/** /**

View File

@@ -1645,7 +1645,6 @@ public class AiController {
// For non-converted triggers (such as Cumulative Upkeep) that don't have costs or targets to worry about // For non-converted triggers (such as Cumulative Upkeep) that don't have costs or targets to worry about
return true; return true;
} }
return false; return false;
} }
@@ -1690,16 +1689,11 @@ public class AiController {
left = AbilityUtils.calculateAmount(hostCard, svarToCheck, sa); left = AbilityUtils.calculateAmount(hostCard, svarToCheck, sa);
} }
System.out.println("aiShouldRun?" + left + comparator + compareTo); System.out.println("aiShouldRun?" + left + comparator + compareTo);
if (Expressions.compare(left, comparator, compareTo)) { return Expressions.compare(left, comparator, compareTo);
return true;
}
} else if (effect.getMapParams().containsKey("AICheckDredge")) { } else if (effect.getMapParams().containsKey("AICheckDredge")) {
return player.getCardsIn(ZoneType.Library).size() > 8 || player.isCardInPlay("Laboratory Maniac"); return player.getCardsIn(ZoneType.Library).size() > 8 || player.isCardInPlay("Laboratory Maniac");
} else if (sa != null && doTrigger(sa, false)) { } else return sa != null && doTrigger(sa, false);
return true;
}
return false;
} }
public List<SpellAbility> chooseSaToActivateFromOpeningHand(List<SpellAbility> usableFromOpeningHand) { public List<SpellAbility> chooseSaToActivateFromOpeningHand(List<SpellAbility> usableFromOpeningHand) {
@@ -2078,9 +2072,7 @@ public class AiController {
// AI-specific restrictions specified as activation parameters in spell abilities // AI-specific restrictions specified as activation parameters in spell abilities
if (sa.hasParam("AILifeThreshold")) { if (sa.hasParam("AILifeThreshold")) {
if (player.getLife() <= Integer.parseInt(sa.getParam("AILifeThreshold"))) { return player.getLife() > Integer.parseInt(sa.getParam("AILifeThreshold"));
return false;
}
} }
return true; return true;

View File

@@ -56,7 +56,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
@Override @Override
public PaymentDecision visit(CostChooseCreatureType cost) { public PaymentDecision visit(CostChooseCreatureType cost) {
String choice = player.getController().chooseSomeType("Creature", ability, CardType.getAllCreatureTypes(), String choice = player.getController().chooseSomeType("Creature", ability, CardType.getAllCreatureTypes(),
Lists.<String>newArrayList()); Lists.newArrayList());
return PaymentDecision.type(choice); return PaymentDecision.type(choice);
} }
@@ -475,7 +475,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
if (ability.getPayCosts().hasTapCost() && typeList.contains(ability.getHostCard())) { if (ability.getPayCosts().hasTapCost() && typeList.contains(ability.getHostCard())) {
c--; c--;
} }
source.setSVar("ChosenX", "Number$" + Integer.toString(c)); source.setSVar("ChosenX", "Number$" + c);
} else { } else {
if (!isVehicle) { if (!isVehicle) {
c = AbilityUtils.calculateAmount(source, amount, ability); c = AbilityUtils.calculateAmount(source, amount, ability);
@@ -809,7 +809,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
final String sVar = ability.getSVar(amount); final String sVar = ability.getSVar(amount);
if (sVar.equals("XChoice")) { if (sVar.equals("XChoice")) {
c = AbilityUtils.calculateAmount(source, "ChosenX", ability); c = AbilityUtils.calculateAmount(source, "ChosenX", ability);
source.setSVar("ChosenX", "Number$" + String.valueOf(c)); source.setSVar("ChosenX", "Number$" + c);
} else if (amount.equals("All")) { } else if (amount.equals("All")) {
c = source.getCounters(cost.counter); c = source.getCounters(cost.counter);
} else if (sVar.equals("Targeted$CardManaCost")) { } else if (sVar.equals("Targeted$CardManaCost")) {
@@ -865,7 +865,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
} }
typeList = CardLists.filter(typeList, Presets.TAPPED); typeList = CardLists.filter(typeList, Presets.TAPPED);
c = typeList.size(); c = typeList.size();
source.setSVar("ChosenX", "Number$" + Integer.toString(c)); source.setSVar("ChosenX", "Number$" + c);
} else { } else {
c = AbilityUtils.calculateAmount(source, amount, ability); c = AbilityUtils.calculateAmount(source, amount, ability);
} }

View File

@@ -17,5 +17,5 @@ public enum AiPlayDecision {
WouldBecomeZeroToughnessCreature, WouldBecomeZeroToughnessCreature,
WouldDestroyWorldEnchantment, WouldDestroyWorldEnchantment,
BadEtbEffects, BadEtbEffects,
CurseEffects; CurseEffects
} }

View File

@@ -423,7 +423,7 @@ public class ComputerUtil {
int mana = ComputerUtilMana.getAvailableManaEstimate(ai, false); int mana = ComputerUtilMana.getAvailableManaEstimate(ai, false);
boolean cantAffordSoon = activate.getCMC() > mana + 1; boolean cantAffordSoon = activate.getCMC() > mana + 1;
boolean wrongColor = !activate.determineColor().hasNoColorsExcept(ColorSet.fromNames(ComputerUtilCost.getAvailableManaColors(ai, ImmutableList.<Card>of())).getColor()); boolean wrongColor = !activate.determineColor().hasNoColorsExcept(ColorSet.fromNames(ComputerUtilCost.getAvailableManaColors(ai, ImmutableList.of())).getColor());
// Only do this for spells, not activated abilities // Only do this for spells, not activated abilities
// We can't pay for this spell even if we play another land, or have wrong colors // We can't pay for this spell even if we play another land, or have wrong colors
@@ -524,7 +524,7 @@ public class ComputerUtil {
typeList = CardLists.filter(typeList, CardPredicates.canBeSacrificedBy(ability)); typeList = CardLists.filter(typeList, CardPredicates.canBeSacrificedBy(ability));
if ((target != null) && target.getController() == ai && typeList.contains(target)) { if ((target != null) && target.getController() == ai) {
typeList.remove(target); // don't sacrifice the card we're pumping typeList.remove(target); // don't sacrifice the card we're pumping
} }
@@ -554,7 +554,7 @@ public class ComputerUtil {
final Card target, final int amount) { final Card target, final int amount) {
CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(zone), type.split(";"), activate.getController(), activate, null); CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(zone), type.split(";"), activate.getController(), activate, null);
if ((target != null) && target.getController() == ai && typeList.contains(target)) { if ((target != null) && target.getController() == ai) {
typeList.remove(target); // don't exile the card we're pumping typeList.remove(target); // don't exile the card we're pumping
} }
@@ -575,7 +575,7 @@ public class ComputerUtil {
final Card target, final int amount) { final Card target, final int amount) {
CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(zone), type.split(";"), activate.getController(), activate, null); CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(zone), type.split(";"), activate.getController(), activate, null);
if ((target != null) && target.getController() == ai && typeList.contains(target)) { if ((target != null) && target.getController() == ai) {
typeList.remove(target); // don't move the card we're pumping typeList.remove(target); // don't move the card we're pumping
} }
@@ -704,7 +704,7 @@ public class ComputerUtil {
public static CardCollection chooseReturnType(final Player ai, final String type, final Card activate, final Card target, final int amount) { public static CardCollection chooseReturnType(final Player ai, final String type, final Card activate, final Card target, final int amount) {
final CardCollection typeList = final CardCollection typeList =
CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, null); CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, null);
if ((target != null) && target.getController() == ai && typeList.contains(target)) { if ((target != null) && target.getController() == ai) {
// don't bounce the card we're pumping // don't bounce the card we're pumping
typeList.remove(target); typeList.remove(target);
} }
@@ -1967,11 +1967,8 @@ public class ComputerUtil {
final CardCollectionView lands = CardLists.filter(handList, new Predicate<Card>() { final CardCollectionView lands = CardLists.filter(handList, new Predicate<Card>() {
@Override @Override
public boolean apply(final Card c) { public boolean apply(final Card c) {
if (c.getManaCost().getCMC() > 0 || c.hasSVar("NeedsToPlay") return c.getManaCost().getCMC() <= 0 && !c.hasSVar("NeedsToPlay")
|| (!c.getType().isLand() && !c.getType().isArtifact())) { && (c.getType().isLand() || c.getType().isArtifact());
return false;
}
return true;
} }
}); });
@@ -1986,10 +1983,7 @@ public class ComputerUtil {
final CardCollectionView castables = CardLists.filter(handList, new Predicate<Card>() { final CardCollectionView castables = CardLists.filter(handList, new Predicate<Card>() {
@Override @Override
public boolean apply(final Card c) { public boolean apply(final Card c) {
if (c.getManaCost().getCMC() > 0 && c.getManaCost().getCMC() <= landSize) { return c.getManaCost().getCMC() <= 0 || c.getManaCost().getCMC() > landSize;
return false;
}
return true;
} }
}); });
@@ -2186,10 +2180,7 @@ public class ComputerUtil {
CardCollection goodChoices = CardLists.filter(validCards, new Predicate<Card>() { CardCollection goodChoices = CardLists.filter(validCards, new Predicate<Card>() {
@Override @Override
public boolean apply(final Card c) { public boolean apply(final Card c) {
if (c.hasSVar("DiscardMeByOpp") || c.hasSVar("DiscardMe")) { return !c.hasSVar("DiscardMeByOpp") && !c.hasSVar("DiscardMe");
return false;
}
return true;
} }
}); });
if (goodChoices.isEmpty()) { if (goodChoices.isEmpty()) {
@@ -2225,7 +2216,7 @@ public class ComputerUtil {
public static String chooseSomeType(Player ai, String kindOfType, String logic, List<String> invalidTypes) { public static String chooseSomeType(Player ai, String kindOfType, String logic, List<String> invalidTypes) {
if (invalidTypes == null) { if (invalidTypes == null) {
invalidTypes = ImmutableList.<String>of(); invalidTypes = ImmutableList.of();
} }
final Game game = ai.getGame(); final Game game = ai.getGame();
@@ -2546,8 +2537,7 @@ public class ComputerUtil {
@Override @Override
public boolean apply(final Card c) { public boolean apply(final Card c) {
if (c.getController() == ai) { if (c.getController() == ai) {
if (c.getSVar("Targeting").equals("Dies") || c.getSVar("Targeting").equals("Counter")) return !c.getSVar("Targeting").equals("Dies") && !c.getSVar("Targeting").equals("Counter");
return false;
} }
return true; return true;
} }
@@ -2875,7 +2865,6 @@ public class ComputerUtil {
} else if (Iterables.any(list, CardTraitPredicates.hasParam("AiLogic", "LichDraw"))) { } else if (Iterables.any(list, CardTraitPredicates.hasParam("AiLogic", "LichDraw"))) {
return false; return false;
} }
return true; return true;
} }

View File

@@ -368,7 +368,7 @@ public class ComputerUtilCard {
} }
if (hasEnchantmants || hasArtifacts) { if (hasEnchantmants || hasArtifacts) {
final List<Card> ae = CardLists.filter(list, Predicates.and(Predicates.<Card>or(CardPredicates.Presets.ARTIFACTS, CardPredicates.Presets.ENCHANTMENTS), new Predicate<Card>() { final List<Card> ae = CardLists.filter(list, Predicates.and(Predicates.or(CardPredicates.Presets.ARTIFACTS, CardPredicates.Presets.ENCHANTMENTS), new Predicate<Card>() {
@Override @Override
public boolean apply(Card card) { public boolean apply(Card card) {
return !card.hasSVar("DoNotDiscardIfAble"); return !card.hasSVar("DoNotDiscardIfAble");
@@ -1301,7 +1301,7 @@ public class ComputerUtilCard {
combatTrick = true; combatTrick = true;
final List<String> kws = sa.hasParam("KW") ? Arrays.asList(sa.getParam("KW").split(" & ")) final List<String> kws = sa.hasParam("KW") ? Arrays.asList(sa.getParam("KW").split(" & "))
: Lists.<String>newArrayList(); : Lists.newArrayList();
for (String kw : kws) { for (String kw : kws) {
if (!kw.equals("Trample") && !kw.equals("First Strike") && !kw.equals("Double Strike")) { if (!kw.equals("Trample") && !kw.equals("First Strike") && !kw.equals("Double Strike")) {
combatTrick = false; combatTrick = false;

View File

@@ -84,7 +84,7 @@ public class ComputerUtilCombat {
return Iterables.any(defenders, new Predicate<GameEntity>() { return Iterables.any(defenders, new Predicate<GameEntity>() {
@Override public boolean apply(final GameEntity input) { @Override public boolean apply(final GameEntity input) {
return ComputerUtilCombat.canAttackNextTurn(attacker, input); return ComputerUtilCombat.canAttackNextTurn(attacker, input);
}; }
}); });
} // canAttackNextTurn(Card) } // canAttackNextTurn(Card)
@@ -119,11 +119,7 @@ public class ComputerUtilCombat {
} }
// The creature won't untap next turn // The creature won't untap next turn
if (atacker.isTapped() && !Untap.canUntap(atacker)) { return !atacker.isTapped() || Untap.canUntap(atacker);
return false;
}
return true;
} // canAttackNextTurn(Card, GameEntity) } // canAttackNextTurn(Card, GameEntity)
/** /**
@@ -883,21 +879,20 @@ public class ComputerUtilCombat {
} else if (mode == TriggerType.DamageDone) { } else if (mode == TriggerType.DamageDone) {
willTrigger = true; willTrigger = true;
if (trigParams.containsKey("ValidSource")) { if (trigParams.containsKey("ValidSource")) {
if (CardTraitBase.matchesValid(defender, trigParams.get("ValidSource").split(","), source) if (!(CardTraitBase.matchesValid(defender, trigParams.get("ValidSource").split(","), source)
&& defender.getNetCombatDamage() > 0 && defender.getNetCombatDamage() > 0
&& (!trigParams.containsKey("ValidTarget") && (!trigParams.containsKey("ValidTarget")
|| CardTraitBase.matchesValid(attacker, trigParams.get("ValidTarget").split(","), source))) { || CardTraitBase.matchesValid(attacker, trigParams.get("ValidTarget").split(","), source)))) {
return true; return false;
} }
if (CardTraitBase.matchesValid(attacker, trigParams.get("ValidSource").split(","), source) if (!(CardTraitBase.matchesValid(attacker, trigParams.get("ValidSource").split(","), source)
&& attacker.getNetCombatDamage() > 0 && attacker.getNetCombatDamage() > 0
&& (!trigParams.containsKey("ValidTarget") && (!trigParams.containsKey("ValidTarget")
|| CardTraitBase.matchesValid(defender, trigParams.get("ValidTarget").split(","), source))) { || CardTraitBase.matchesValid(defender, trigParams.get("ValidTarget").split(","), source)))) {
return true;
}
}
return false; return false;
} }
}
}
return willTrigger; return willTrigger;
} }
@@ -1414,7 +1409,7 @@ public class ComputerUtilCombat {
if (att.matches("[0-9][0-9]?") || att.matches("-" + "[0-9][0-9]?")) { if (att.matches("[0-9][0-9]?") || att.matches("-" + "[0-9][0-9]?")) {
power += Integer.parseInt(att); power += Integer.parseInt(att);
} else { } else {
String bonus = new String(source.getSVar(att)); String bonus = source.getSVar(att);
if (bonus.contains("TriggerCount$NumBlockers")) { if (bonus.contains("TriggerCount$NumBlockers")) {
bonus = TextUtil.fastReplace(bonus, "TriggerCount$NumBlockers", "Number$1"); bonus = TextUtil.fastReplace(bonus, "TriggerCount$NumBlockers", "Number$1");
} else if (bonus.contains("TriggeredPlayersDefenders$Amount")) { // for Melee } else if (bonus.contains("TriggeredPlayersDefenders$Amount")) { // for Melee
@@ -1655,7 +1650,7 @@ public class ComputerUtilCombat {
if (def.matches("[0-9][0-9]?") || def.matches("-" + "[0-9][0-9]?")) { if (def.matches("[0-9][0-9]?") || def.matches("-" + "[0-9][0-9]?")) {
toughness += Integer.parseInt(def); toughness += Integer.parseInt(def);
} else { } else {
String bonus = new String(source.getSVar(def)); String bonus = source.getSVar(def);
if (bonus.contains("TriggerCount$NumBlockers")) { if (bonus.contains("TriggerCount$NumBlockers")) {
bonus = TextUtil.fastReplace(bonus, "TriggerCount$NumBlockers", "Number$1"); bonus = TextUtil.fastReplace(bonus, "TriggerCount$NumBlockers", "Number$1");
} else if (bonus.contains("TriggeredPlayersDefenders$Amount")) { // for Melee } else if (bonus.contains("TriggeredPlayersDefenders$Amount")) { // for Melee
@@ -1948,7 +1943,7 @@ public class ComputerUtilCombat {
return defenderDamage >= attackerLife; return defenderDamage >= attackerLife;
} // defender no double strike } // defender no double strike
return false; // should never arrive here return false;// should never arrive here
} // canDestroyAttacker } // canDestroyAttacker
// For AI safety measures like Regeneration // For AI safety measures like Regeneration
@@ -2195,7 +2190,7 @@ public class ComputerUtilCombat {
return attackerDamage >= defenderLife; return attackerDamage >= defenderLife;
} // attacker no double strike } // attacker no double strike
return false; // should never arrive here return false;// should never arrive here
} // canDestroyBlocker } // canDestroyBlocker

View File

@@ -424,7 +424,7 @@ public class ComputerUtilCost {
continue; continue;
} }
final int remainingLife = ai.getLife(); final int remainingLife = ai.getLife();
final int lifeCost = ((CostPayLife) part).convertAmount(); final int lifeCost = part.convertAmount();
if ((remainingLife - lifeCost) < 10) { if ((remainingLife - lifeCost) < 10) {
return false; //Don't pay life if it would put AI under 10 life return false; //Don't pay life if it would put AI under 10 life
} else if ((remainingLife / lifeCost) < 4) { } else if ((remainingLife / lifeCost) < 4) {
@@ -552,7 +552,7 @@ public class ComputerUtilCost {
final Card source = sa.getHostCard(); final Card source = sa.getHostCard();
final String aiLogic = sa.getParam("UnlessAI"); final String aiLogic = sa.getParam("UnlessAI");
boolean payForOwnOnly = "OnlyOwn".equals(aiLogic); boolean payForOwnOnly = "OnlyOwn".equals(aiLogic);
boolean payOwner = sa.hasParam("UnlessAI") ? aiLogic.startsWith("Defined") : false; boolean payOwner = sa.hasParam("UnlessAI") && aiLogic.startsWith("Defined");
boolean payNever = "Never".equals(aiLogic); boolean payNever = "Never".equals(aiLogic);
boolean shockland = "Shockland".equals(aiLogic); boolean shockland = "Shockland".equals(aiLogic);
boolean isMine = sa.getActivatingPlayer().equals(payer); boolean isMine = sa.getActivatingPlayer().equals(payer);

View File

@@ -880,10 +880,12 @@ public class ComputerUtilMana {
// For combat tricks, always obey mana reservation // For combat tricks, always obey mana reservation
if (curPhase == PhaseType.COMBAT_DECLARE_BLOCKERS || curPhase == PhaseType.CLEANUP) { if (curPhase == PhaseType.COMBAT_DECLARE_BLOCKERS || curPhase == PhaseType.CLEANUP) {
AiCardMemory.clearMemorySet(ai, AiCardMemory.MemorySet.HELD_MANA_SOURCES_FOR_DECLBLK); if (!(ai.getGame().getPhaseHandler().isPlayerTurn(ai))) {
} else if (!(ai.getGame().getPhaseHandler().isPlayerTurn(ai)) && (curPhase == PhaseType.COMBAT_DECLARE_BLOCKERS || curPhase == PhaseType.CLEANUP)) {
AiCardMemory.clearMemorySet(ai, AiCardMemory.MemorySet.HELD_MANA_SOURCES_FOR_ENEMY_DECLBLK); AiCardMemory.clearMemorySet(ai, AiCardMemory.MemorySet.HELD_MANA_SOURCES_FOR_ENEMY_DECLBLK);
AiCardMemory.clearMemorySet(ai, AiCardMemory.MemorySet.CHOSEN_FOG_EFFECT); AiCardMemory.clearMemorySet(ai, AiCardMemory.MemorySet.CHOSEN_FOG_EFFECT);
}
else
AiCardMemory.clearMemorySet(ai, AiCardMemory.MemorySet.HELD_MANA_SOURCES_FOR_DECLBLK);
} else { } else {
if ((AiCardMemory.isRememberedCard(ai, sourceCard, AiCardMemory.MemorySet.HELD_MANA_SOURCES_FOR_DECLBLK)) || if ((AiCardMemory.isRememberedCard(ai, sourceCard, AiCardMemory.MemorySet.HELD_MANA_SOURCES_FOR_DECLBLK)) ||
(AiCardMemory.isRememberedCard(ai, sourceCard, AiCardMemory.MemorySet.HELD_MANA_SOURCES_FOR_ENEMY_DECLBLK))) { (AiCardMemory.isRememberedCard(ai, sourceCard, AiCardMemory.MemorySet.HELD_MANA_SOURCES_FOR_ENEMY_DECLBLK))) {

View File

@@ -1061,7 +1061,7 @@ public abstract class GameState {
} }
private void applyCountersToGameEntity(GameEntity entity, String counterString) { private void applyCountersToGameEntity(GameEntity entity, String counterString) {
entity.setCounters(Maps.<CounterType, Integer>newEnumMap(CounterType.class)); entity.setCounters(Maps.newEnumMap(CounterType.class));
String[] allCounterStrings = counterString.split(","); String[] allCounterStrings = counterString.split(",");
for (final String counterPair : allCounterStrings) { for (final String counterPair : allCounterStrings) {
String[] pair = counterPair.split("=", 2); String[] pair = counterPair.split("=", 2);
@@ -1107,7 +1107,7 @@ public abstract class GameState {
Map<CounterType, Integer> counters = c.getCounters(); Map<CounterType, Integer> counters = c.getCounters();
// Note: Not clearCounters() since we want to keep the counters // Note: Not clearCounters() since we want to keep the counters
// var as-is. // var as-is.
c.setCounters(Maps.<CounterType, Integer>newEnumMap(CounterType.class)); c.setCounters(Maps.newEnumMap(CounterType.class));
if (c.isAura()) { if (c.isAura()) {
// dummy "enchanting" to indicate that the card will be force-attached elsewhere // dummy "enchanting" to indicate that the card will be force-attached elsewhere
// (will be overridden later, so the actual value shouldn't matter) // (will be overridden later, so the actual value shouldn't matter)

View File

@@ -492,7 +492,7 @@ public class PlayerControllerAi extends PlayerController {
Card toDiscard = Aggregates.itemWithMin(cardsOfType, CardPredicates.Accessors.fnGetCmc); Card toDiscard = Aggregates.itemWithMin(cardsOfType, CardPredicates.Accessors.fnGetCmc);
return new CardCollection(toDiscard); return new CardCollection(toDiscard);
} }
return getAi().getCardsToDiscard(num, (String[])null, sa); return getAi().getCardsToDiscard(num, null, sa);
} }
@@ -612,7 +612,7 @@ public class PlayerControllerAi extends PlayerController {
@Override @Override
public CardCollection chooseCardsToDiscardToMaximumHandSize(int numDiscard) { public CardCollection chooseCardsToDiscardToMaximumHandSize(int numDiscard) {
return brains.getCardsToDiscard(numDiscard, (String[])null, null); return brains.getCardsToDiscard(numDiscard, null, null);
} }
@Override @Override
@@ -669,7 +669,7 @@ public class PlayerControllerAi extends PlayerController {
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).chooseNumber(player, sa, min, max, params); return SpellApiToAi.Converter.get(api).chooseNumber(player, sa, min, max, params);
}; }
@Override @Override
public int chooseNumber(SpellAbility sa, String title, List<Integer> options, Player relatedPlayer) { public int chooseNumber(SpellAbility sa, String title, List<Integer> options, Player relatedPlayer) {

View File

@@ -94,12 +94,8 @@ public class SpecialCardAi {
int minCMC = isLowCMCDeck ? 3 : 4; // probably not worth wasting a lotus on a low-CMC spell (<4 CMC), except in low-CMC decks, where 3 CMC may be fine int minCMC = isLowCMCDeck ? 3 : 4; // probably not worth wasting a lotus on a low-CMC spell (<4 CMC), except in low-CMC decks, where 3 CMC may be fine
int paidCMC = cost.getConvertedManaCost(); int paidCMC = cost.getConvertedManaCost();
if (paidCMC < minCMC) { if (paidCMC < minCMC) {
if (paidCMC == 3 && numManaSrcs < 3) {
// if it's a CMC 3 spell and we're more than one mana source short for it, might be worth it anyway // if it's a CMC 3 spell and we're more than one mana source short for it, might be worth it anyway
return true; return paidCMC == 3 && numManaSrcs < 3;
}
return false;
} }
return true; return true;
@@ -218,11 +214,7 @@ public class SpecialCardAi {
} }
} }
if (ai.getLife() <= sa.getHostCard().getNetPower() && !hasUsefulBlocker) { return ai.getLife() <= sa.getHostCard().getNetPower() && !hasUsefulBlocker;
return true;
} else {
return false;
}
} }
public static int getSacThreshold() { public static int getSacThreshold() {
@@ -335,7 +327,7 @@ public class SpecialCardAi {
boolean canTrample = source.hasKeyword(Keyword.TRAMPLE); boolean canTrample = source.hasKeyword(Keyword.TRAMPLE);
if (!isBlocking && combat.getDefenderByAttacker(source) instanceof Card) { if (!isBlocking && combat.getDefenderByAttacker(source) instanceof Card) {
int loyalty = ((Card)combat.getDefenderByAttacker(source)).getCounters(CounterType.LOYALTY); int loyalty = combat.getDefenderByAttacker(source).getCounters(CounterType.LOYALTY);
int totalDamageToPW = 0; int totalDamageToPW = 0;
for (Card atk : (combat.getAttackersOf(combat.getDefenderByAttacker(source)))) { for (Card atk : (combat.getAttackersOf(combat.getDefenderByAttacker(source)))) {
if (combat.isUnblocked(atk)) { if (combat.isUnblocked(atk)) {
@@ -411,11 +403,7 @@ public class SpecialCardAi {
Pair<Integer, Integer> predictedPT = getPumpedPT(ai, source.getNetCombatDamage(), source.getNetToughness()); Pair<Integer, Integer> predictedPT = getPumpedPT(ai, source.getNetCombatDamage(), source.getNetToughness());
int oppT = Aggregates.sum(potentialBlockers, CardPredicates.Accessors.fnGetNetToughness); int oppT = Aggregates.sum(potentialBlockers, CardPredicates.Accessors.fnGetNetToughness);
if (potentialBlockers.isEmpty() || (source.hasKeyword(Keyword.TRAMPLE) && predictedPT.getLeft() - oppT >= oppLife)) { return potentialBlockers.isEmpty() || (source.hasKeyword(Keyword.TRAMPLE) && predictedPT.getLeft() - oppT >= oppLife);
return true;
}
return false;
} }
public static Pair<Integer, Integer> getPumpedPT(Player ai, int power, int toughness) { public static Pair<Integer, Integer> getPumpedPT(Player ai, int power, int toughness) {
@@ -522,7 +510,7 @@ public class SpecialCardAi {
best.add(sp); // these SAs are prioritized since the AI sees a reason to play them now best.add(sp); // these SAs are prioritized since the AI sees a reason to play them now
} }
final List<String> keywords = sp.hasParam("KW") ? Arrays.asList(sp.getParam("KW").split(" & ")) final List<String> keywords = sp.hasParam("KW") ? Arrays.asList(sp.getParam("KW").split(" & "))
: Lists.<String>newArrayList(); : Lists.newArrayList();
for (String kw : keywords) { for (String kw : keywords) {
if (!tgtCard.hasKeyword(kw)) { if (!tgtCard.hasKeyword(kw)) {
if ("Indestructible".equals(kw) && ai.getOpponents().getCreaturesInPlay().isEmpty()) { if ("Indestructible".equals(kw) && ai.getOpponents().getCreaturesInPlay().isEmpty()) {
@@ -568,10 +556,7 @@ public class SpecialCardAi {
@Override @Override
public boolean apply(final Card c) { public boolean apply(final Card c) {
// Don't enchant creatures that can survive // Don't enchant creatures that can survive
if (!c.canBeDestroyed() || c.getNetCombatDamage() < c.getNetToughness() || c.isEnchantedBy("Guilty Conscience")) { return c.canBeDestroyed() && c.getNetCombatDamage() >= c.getNetToughness() && !c.isEnchantedBy("Guilty Conscience");
return false;
}
return true;
} }
}); });
chosen = ComputerUtilCard.getBestCreatureAI(creatures); chosen = ComputerUtilCard.getBestCreatureAI(creatures);
@@ -919,7 +904,6 @@ public class SpecialCardAi {
// Only activate in AI's own turn (sans the exception above) // Only activate in AI's own turn (sans the exception above)
return false; return false;
} }
return true; return true;
} }
} }
@@ -941,11 +925,7 @@ public class SpecialCardAi {
} }
// Maybe use it for some important high-impact spells even if there are more cards in hand? // Maybe use it for some important high-impact spells even if there are more cards in hand?
if (ai.getCardsIn(ZoneType.Hand).size() > 1 && !hasEnsnaringBridgeEffect) { return ai.getCardsIn(ZoneType.Hand).size() <= 1 || hasEnsnaringBridgeEffect;
return false;
}
return true;
} }
} }
@@ -1310,12 +1290,8 @@ public class SpecialCardAi {
} }
} }
if (aiHandSize < HAND_SIZE_THRESHOLD || maxOppHandSize - aiHandSize > HAND_SIZE_THRESHOLD) {
// use in case we're getting low on cards or if we're significantly behind our opponent in cards in hand // use in case we're getting low on cards or if we're significantly behind our opponent in cards in hand
return true; return aiHandSize < HAND_SIZE_THRESHOLD || maxOppHandSize - aiHandSize > HAND_SIZE_THRESHOLD;
}
return false;
} }
} }
@@ -1342,9 +1318,7 @@ public class SpecialCardAi {
if (topGY == null if (topGY == null
|| !topGY.isCreature() || !topGY.isCreature()
|| ComputerUtilCard.evaluateCreature(creatHand) > ComputerUtilCard.evaluateCreature(topGY) + 80) { || ComputerUtilCard.evaluateCreature(creatHand) > ComputerUtilCard.evaluateCreature(topGY) + 80) {
if (numCreatsInHand > 1 || !ComputerUtilMana.canPayManaCost(creatHand.getSpellPermanent(), ai, 0)) { return numCreatsInHand > 1 || !ComputerUtilMana.canPayManaCost(creatHand.getSpellPermanent(), ai, 0);
return true;
}
} }
} }
@@ -1466,7 +1440,6 @@ public class SpecialCardAi {
// Only activate in AI's own turn (sans the exception above) // Only activate in AI's own turn (sans the exception above)
return false; return false;
} }
return true; return true;
} }
} }

View File

@@ -56,12 +56,9 @@ public class ActivateAbilityAi extends SpellAbilityAi {
} else { } else {
final List<Player> defined = AbilityUtils.getDefinedPlayers(source, sa.getParam("Defined"), sa); final List<Player> defined = AbilityUtils.getDefinedPlayers(source, sa.getParam("Defined"), sa);
if (!defined.contains(opp)) { return defined.contains(opp);
return false;
}
} }
return true;
} else { } else {
sa.resetTargets(); sa.resetTargets();
sa.getTargets().add(opp); sa.getTargets().add(opp);

View File

@@ -67,10 +67,8 @@ public class AddTurnAi extends SpellAbilityAi {
return false; return false;
} }
} }
if (!StringUtils.isNumeric(sa.getParam("NumTurns"))) {
// TODO: improve ai for Sage of Hours // TODO: improve ai for Sage of Hours
return false; return StringUtils.isNumeric(sa.getParam("NumTurns"));
}
// not sure if the AI should be playing with cards that give the // not sure if the AI should be playing with cards that give the
// Human more turns. // Human more turns.
} }

View File

@@ -23,9 +23,7 @@ public class AmassAi extends SpellAbilityAi {
final Game game = ai.getGame(); final Game game = ai.getGame();
if (!aiArmies.isEmpty()) { if (!aiArmies.isEmpty()) {
if (CardLists.count(aiArmies, CardPredicates.canReceiveCounters(CounterType.P1P1)) <= 0) { return CardLists.count(aiArmies, CardPredicates.canReceiveCounters(CounterType.P1P1)) > 0;
return false;
}
} else { } else {
final String tokenScript = "b_0_0_zombie_army"; final String tokenScript = "b_0_0_zombie_army";
final int amount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Num", "1"), sa); final int amount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Num", "1"), sa);
@@ -57,12 +55,9 @@ public class AmassAi extends SpellAbilityAi {
//reset static abilities //reset static abilities
game.getAction().checkStaticAbilities(false); game.getAction().checkStaticAbilities(false);
if (!result) { return result;
return false;
}
} }
return true;
} }
@Override @Override

View File

@@ -207,21 +207,16 @@ public class AnimateAi extends SpellAbilityAi {
return bFlag; // All of the defined stuff is animated, not very useful return bFlag; // All of the defined stuff is animated, not very useful
} else { } else {
sa.resetTargets(); sa.resetTargets();
if (!animateTgtAI(sa)) { return animateTgtAI(sa);
return false;
}
} }
return true;
} }
@Override @Override
public boolean chkAIDrawback(SpellAbility sa, Player aiPlayer) { public boolean chkAIDrawback(SpellAbility sa, Player aiPlayer) {
if (sa.usesTargeting()) { if (sa.usesTargeting()) {
sa.resetTargets(); sa.resetTargets();
if (!animateTgtAI(sa)) { return animateTgtAI(sa);
return false;
}
} }
return true; return true;

View File

@@ -8,11 +8,7 @@ public class AnimateAllAi extends SpellAbilityAi {
@Override @Override
protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) { protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) {
if ("Always".equals(sa.getParam("AILogic"))) { return "Always".equals(sa.getParam("AILogic"));
return true;
}
return false;
} // end animateAllCanPlayAI() } // end animateAllCanPlayAI()
@Override @Override

View File

@@ -123,9 +123,7 @@ public class AttachAi extends SpellAbilityAi {
return !(c.hasProtectionFrom(source) || c.hasKeyword(Keyword.SHROUD) || c.hasKeyword(Keyword.HEXPROOF)); return !(c.hasProtectionFrom(source) || c.hasKeyword(Keyword.SHROUD) || c.hasKeyword(Keyword.HEXPROOF));
} }
}); });
if (targets.isEmpty()) { return !targets.isEmpty();
return false;
}
} }
return true; return true;
@@ -239,9 +237,7 @@ public class AttachAi extends SpellAbilityAi {
return false; return false;
} }
if (!(combat.isAttacking(attachTarget) || combat.isBlocking(attachTarget))) { return combat.isAttacking(attachTarget) || combat.isBlocking(attachTarget);
return false;
}
} }
return true; return true;
@@ -987,9 +983,7 @@ public class AttachAi extends SpellAbilityAi {
return false; return false;
} }
// don't equip creatures that don't gain anything // don't equip creatures that don't gain anything
if (card.hasSVar("NonStackingAttachEffect") && newTarget.isEquippedBy(card.getName())) { return !card.hasSVar("NonStackingAttachEffect") || !newTarget.isEquippedBy(card.getName());
return false;
}
} }
} }
@@ -1353,7 +1347,7 @@ public class AttachAi extends SpellAbilityAi {
CardCollection prefList = list; CardCollection prefList = list;
// Filter AI-specific targets if provided // Filter AI-specific targets if provided
prefList = ComputerUtil.filterAITgts(sa, aiPlayer, (CardCollection)list, true); prefList = ComputerUtil.filterAITgts(sa, aiPlayer, list, true);
Card c = attachGeneralAI(aiPlayer, sa, prefList, mandatory, attachSource, sa.getParam("AILogic")); Card c = attachGeneralAI(aiPlayer, sa, prefList, mandatory, attachSource, sa.getParam("AILogic"));
@@ -1557,86 +1551,55 @@ public class AttachAi extends SpellAbilityAi {
} }
if (evasive) { if (evasive) {
if (card.getNetCombatDamage() + powerBonus <= 0 return card.getNetCombatDamage() + powerBonus > 0
|| !ComputerUtilCombat.canAttackNextTurn(card) && ComputerUtilCombat.canAttackNextTurn(card)
|| !canBeBlocked) { && canBeBlocked;
return false;
}
} else if (keyword.equals("Haste")) { } else if (keyword.equals("Haste")) {
if (!card.hasSickness() || !ph.isPlayerTurn(sa.getActivatingPlayer()) || card.isTapped() return card.hasSickness() && ph.isPlayerTurn(sa.getActivatingPlayer()) && !card.isTapped()
|| card.getNetCombatDamage() + powerBonus <= 0 && card.getNetCombatDamage() + powerBonus > 0
|| card.hasKeyword("CARDNAME can attack as though it had haste.") && !card.hasKeyword("CARDNAME can attack as though it had haste.")
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| !ComputerUtilCombat.canAttackNextTurn(card)) { && ComputerUtilCombat.canAttackNextTurn(card);
return false;
}
} else if (keyword.endsWith("Indestructible")) { } else if (keyword.endsWith("Indestructible")) {
return true; return true;
} else if (keyword.endsWith("Deathtouch") || keyword.endsWith("Wither")) { } else if (keyword.endsWith("Deathtouch") || keyword.endsWith("Wither")) {
if (card.getNetCombatDamage() + powerBonus <= 0 return card.getNetCombatDamage() + powerBonus > 0
|| ((!canBeBlocked || !ComputerUtilCombat.canAttackNextTurn(card)) && ((canBeBlocked && ComputerUtilCombat.canAttackNextTurn(card))
&& !CombatUtil.canBlock(card, true))) { || CombatUtil.canBlock(card, true));
return false;
}
} else if (keyword.equals("Double Strike") || keyword.equals("Lifelink")) { } else if (keyword.equals("Double Strike") || keyword.equals("Lifelink")) {
if (card.getNetCombatDamage() + powerBonus <= 0 return card.getNetCombatDamage() + powerBonus > 0
|| (!ComputerUtilCombat.canAttackNextTurn(card) && !CombatUtil.canBlock(card, true))) { && (ComputerUtilCombat.canAttackNextTurn(card) || CombatUtil.canBlock(card, true));
return false;
}
} else if (keyword.equals("First Strike")) { } else if (keyword.equals("First Strike")) {
if (card.getNetCombatDamage() + powerBonus <= 0 || card.hasKeyword(Keyword.DOUBLE_STRIKE) return card.getNetCombatDamage() + powerBonus > 0 && !card.hasKeyword(Keyword.DOUBLE_STRIKE)
|| (!ComputerUtilCombat.canAttackNextTurn(card) && !CombatUtil.canBlock(card, true))) { && (ComputerUtilCombat.canAttackNextTurn(card) || CombatUtil.canBlock(card, true));
return false;
}
} else if (keyword.startsWith("Flanking")) { } else if (keyword.startsWith("Flanking")) {
if (card.getNetCombatDamage() + powerBonus <= 0 return card.getNetCombatDamage() + powerBonus > 0
|| !ComputerUtilCombat.canAttackNextTurn(card) && ComputerUtilCombat.canAttackNextTurn(card)
|| !canBeBlocked) { && canBeBlocked;
return false;
}
} else if (keyword.startsWith("Bushido")) { } else if (keyword.startsWith("Bushido")) {
if ((!canBeBlocked || !ComputerUtilCombat.canAttackNextTurn(card)) return (canBeBlocked && ComputerUtilCombat.canAttackNextTurn(card))
&& !CombatUtil.canBlock(card, true)) { || CombatUtil.canBlock(card, true);
return false;
}
} else if (keyword.equals("Trample")) { } else if (keyword.equals("Trample")) {
if (card.getNetCombatDamage() + powerBonus <= 1 return card.getNetCombatDamage() + powerBonus > 1
|| !canBeBlocked && canBeBlocked
|| !ComputerUtilCombat.canAttackNextTurn(card)) { && ComputerUtilCombat.canAttackNextTurn(card);
return false;
}
} else if (keyword.equals("Infect")) { } else if (keyword.equals("Infect")) {
if (card.getNetCombatDamage() + powerBonus <= 0 return card.getNetCombatDamage() + powerBonus > 0
|| !ComputerUtilCombat.canAttackNextTurn(card)) { && ComputerUtilCombat.canAttackNextTurn(card);
return false;
}
} else if (keyword.equals("Vigilance")) { } else if (keyword.equals("Vigilance")) {
if (card.getNetCombatDamage() + powerBonus <= 0 return card.getNetCombatDamage() + powerBonus > 0
|| !ComputerUtilCombat.canAttackNextTurn(card) && ComputerUtilCombat.canAttackNextTurn(card)
|| !CombatUtil.canBlock(card, true)) { && CombatUtil.canBlock(card, true);
return false;
}
} else if (keyword.equals("Reach")) { } else if (keyword.equals("Reach")) {
if (card.hasKeyword(Keyword.FLYING) || !CombatUtil.canBlock(card, true)) { return !card.hasKeyword(Keyword.FLYING) && CombatUtil.canBlock(card, true);
return false;
}
} else if (keyword.endsWith("CARDNAME can block an additional creature each combat.")) { } else if (keyword.endsWith("CARDNAME can block an additional creature each combat.")) {
if (!CombatUtil.canBlock(card, true) || card.hasKeyword("CARDNAME can block any number of creatures.") return CombatUtil.canBlock(card, true) && !card.hasKeyword("CARDNAME can block any number of creatures.")
|| card.hasKeyword("CARDNAME can block an additional ninety-nine creatures each combat.")) { && !card.hasKeyword("CARDNAME can block an additional ninety-nine creatures each combat.");
return false;
}
} else if (keyword.equals("CARDNAME can attack as though it didn't have defender.")) { } else if (keyword.equals("CARDNAME can attack as though it didn't have defender.")) {
if (!card.hasKeyword(Keyword.DEFENDER) || card.getNetCombatDamage() + powerBonus <= 0) { return card.hasKeyword(Keyword.DEFENDER) && card.getNetCombatDamage() + powerBonus > 0;
return false;
}
} else if (keyword.equals("Shroud") || keyword.equals("Hexproof")) { } else if (keyword.equals("Shroud") || keyword.equals("Hexproof")) {
if (card.hasKeyword(Keyword.SHROUD) || card.hasKeyword(Keyword.HEXPROOF)) { return !card.hasKeyword(Keyword.SHROUD) && !card.hasKeyword(Keyword.HEXPROOF);
return false; } else return !keyword.equals("Defender");
}
} else if (keyword.equals("Defender")) {
return false;
}
return true;
} }
/** /**
@@ -1657,17 +1620,11 @@ public class AttachAi extends SpellAbilityAi {
if (keyword.endsWith("CARDNAME can't attack.") || keyword.equals("Defender") if (keyword.endsWith("CARDNAME can't attack.") || keyword.equals("Defender")
|| keyword.endsWith("CARDNAME can't attack or block.")) { || keyword.endsWith("CARDNAME can't attack or block.")) {
if (!ComputerUtilCombat.canAttackNextTurn(card) || card.getNetCombatDamage() < 1) { return ComputerUtilCombat.canAttackNextTurn(card) && card.getNetCombatDamage() >= 1;
return false;
}
} else if (keyword.endsWith("CARDNAME attacks each turn if able.") || keyword.endsWith("CARDNAME attacks each combat if able.")) { } else if (keyword.endsWith("CARDNAME attacks each turn if able.") || keyword.endsWith("CARDNAME attacks each combat if able.")) {
if (!ComputerUtilCombat.canAttackNextTurn(card) || !CombatUtil.canBlock(card, true) || ai.getCreaturesInPlay().isEmpty()) { return ComputerUtilCombat.canAttackNextTurn(card) && CombatUtil.canBlock(card, true) && !ai.getCreaturesInPlay().isEmpty();
return false;
}
} else if (keyword.endsWith("CARDNAME can't block.") || keyword.contains("CantBlock")) { } else if (keyword.endsWith("CARDNAME can't block.") || keyword.contains("CantBlock")) {
if (!CombatUtil.canBlock(card, true)) { return CombatUtil.canBlock(card, true);
return false;
}
} else if (keyword.endsWith("CARDNAME's activated abilities can't be activated.")) { } else if (keyword.endsWith("CARDNAME's activated abilities can't be activated.")) {
for (SpellAbility ability : card.getSpellAbilities()) { for (SpellAbility ability : card.getSpellAbilities()) {
if (ability.isAbility()) { if (ability.isAbility()) {
@@ -1676,18 +1633,12 @@ public class AttachAi extends SpellAbilityAi {
} }
return false; return false;
} else if (keyword.endsWith("Prevent all combat damage that would be dealt by CARDNAME.")) { } else if (keyword.endsWith("Prevent all combat damage that would be dealt by CARDNAME.")) {
if (!ComputerUtilCombat.canAttackNextTurn(card) || card.getNetCombatDamage() < 1) { return ComputerUtilCombat.canAttackNextTurn(card) && card.getNetCombatDamage() >= 1;
return false;
}
} else if (keyword.endsWith("Prevent all combat damage that would be dealt to and dealt by CARDNAME.") } else if (keyword.endsWith("Prevent all combat damage that would be dealt to and dealt by CARDNAME.")
|| keyword.endsWith("Prevent all damage that would be dealt to and dealt by CARDNAME.")) { || keyword.endsWith("Prevent all damage that would be dealt to and dealt by CARDNAME.")) {
if (!ComputerUtilCombat.canAttackNextTurn(card) || card.getNetCombatDamage() < 2) { return ComputerUtilCombat.canAttackNextTurn(card) && card.getNetCombatDamage() >= 2;
return false;
}
} else if (keyword.endsWith("CARDNAME doesn't untap during your untap step.")) { } else if (keyword.endsWith("CARDNAME doesn't untap during your untap step.")) {
if (card.isUntapped()) { return !card.isUntapped();
return false;
}
} }
return true; return true;
} }
@@ -1711,12 +1662,8 @@ public class AttachAi extends SpellAbilityAi {
return true; return true;
} }
if (sa.getHostCard().isEquipment() && ComputerUtilCard.isUselessCreature(ai, c)) {
// useless to equip a creature that can't attack or block. // useless to equip a creature that can't attack or block.
return false; return !sa.getHostCard().isEquipment() || !ComputerUtilCard.isUselessCreature(ai, c);
}
return true;
} }
public static Card doPumpOrCurseAILogic(final Player ai, final SpellAbility sa, final List<Card> list, final String type) { public static Card doPumpOrCurseAILogic(final Player ai, final SpellAbility sa, final List<Card> list, final String type) {

View File

@@ -355,9 +355,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
@Override @Override
public boolean apply(final Card c) { public boolean apply(final Card c) {
if (c.getType().isLegendary()) { if (c.getType().isLegendary()) {
if (ai.isCardInPlay(c.getName())) { return !ai.isCardInPlay(c.getName());
return false;
}
} }
return true; return true;
} }
@@ -738,11 +736,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
} }
final AbilitySub subAb = sa.getSubAbility(); final AbilitySub subAb = sa.getSubAbility();
if (subAb != null && !SpellApiToAi.Converter.get(subAb.getApi()).chkDrawbackWithSubs(ai, subAb)) { return subAb == null || SpellApiToAi.Converter.get(subAb.getApi()).chkDrawbackWithSubs(ai, subAb);
return false;
}
return true;
} }
/* /*
@@ -864,7 +858,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
list = CardLists.getTargetableCards(list, sa); list = CardLists.getTargetableCards(list, sa);
// Filter AI-specific targets if provided // Filter AI-specific targets if provided
list = ComputerUtil.filterAITgts(sa, ai, (CardCollection)list, true); list = ComputerUtil.filterAITgts(sa, ai, list, true);
if (sa.hasParam("AITgtsOnlyBetterThanSelf")) { if (sa.hasParam("AITgtsOnlyBetterThanSelf")) {
list = CardLists.filter(list, new Predicate<Card>() { list = CardLists.filter(list, new Predicate<Card>() {
@Override @Override
@@ -995,11 +989,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
@Override @Override
public boolean apply(final Card c) { public boolean apply(final Card c) {
for (Card aura : c.getEnchantedBy()) { for (Card aura : c.getEnchantedBy()) {
if (aura.getController().isOpponentOf(ai)) { return aura.getController().isOpponentOf(ai);
return true;
} else {
return false;
}
} }
if (blink) { if (blink) {
return c.isToken(); return c.isToken();
@@ -1471,16 +1461,12 @@ public class ChangeZoneAi extends SpellAbilityAi {
if (!list.isEmpty()) { if (!list.isEmpty()) {
final Card attachedTo = list.get(0); final Card attachedTo = list.get(0);
// This code is for the Dragon auras // This code is for the Dragon auras
if (attachedTo.getController().isOpponentOf(ai)) { return !attachedTo.getController().isOpponentOf(ai);
return false;
}
} }
} }
} else if (isPreferredTarget(ai, sa, mandatory, true)) { } else if (isPreferredTarget(ai, sa, mandatory, true)) {
// do nothing // do nothing
} else if (!isUnpreferredTarget(ai, sa, mandatory)) { } else return isUnpreferredTarget(ai, sa, mandatory);
return false;
}
return true; return true;
} }
@@ -1532,9 +1518,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
@Override @Override
public boolean apply(final Card c) { public boolean apply(final Card c) {
if (c.getType().isLegendary()) { if (c.getType().isLegendary()) {
if (decider.isCardInPlay(c.getName())) { return !decider.isCardInPlay(c.getName());
return false;
}
} }
return true; return true;
} }
@@ -1543,10 +1527,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
fetchList = CardLists.filter(fetchList, new Predicate<Card>() { fetchList = CardLists.filter(fetchList, new Predicate<Card>() {
@Override @Override
public boolean apply(final Card c) { public boolean apply(final Card c) {
if (ComputerUtilCard.isCardRemAIDeck(c) || ComputerUtilCard.isCardRemRandomDeck(c)) { return !ComputerUtilCard.isCardRemAIDeck(c) && !ComputerUtilCard.isCardRemRandomDeck(c);
return false;
}
return true;
} }
}); });
} }
@@ -1718,9 +1699,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
@Override @Override
public boolean apply(final Card c) { public boolean apply(final Card c) {
if (c.getType().isLegendary()) { if (c.getType().isLegendary()) {
if (ai.isCardInPlay(c.getName())) { return !ai.isCardInPlay(c.getName());
return false;
}
} }
return true; return true;
} }
@@ -1826,20 +1805,16 @@ public class ChangeZoneAi extends SpellAbilityAi {
&& "Battlefield".equals(causeSub.getParam("Destination"))) { && "Battlefield".equals(causeSub.getParam("Destination"))) {
// A blink effect implemented using ChangeZone API // A blink effect implemented using ChangeZone API
return false; return false;
} else if (subApi == ApiType.DelayedTrigger) { } else // This is an intrinsic effect that blinks the card (e.g. Obzedat, Ghost Council), no need to
// return the commander to the Command zone.
if (subApi == ApiType.DelayedTrigger) {
SpellAbility exec = causeSub.getAdditionalAbility("Execute"); SpellAbility exec = causeSub.getAdditionalAbility("Execute");
if (exec != null && exec.getApi() == ApiType.ChangeZone) { if (exec != null && exec.getApi() == ApiType.ChangeZone) {
if ("Exile".equals(exec.getParam("Origin")) && "Battlefield".equals(exec.getParam("Destination"))) {
// A blink effect implemented using a delayed trigger // A blink effect implemented using a delayed trigger
return false; return !"Exile".equals(exec.getParam("Origin")) || !"Battlefield".equals(exec.getParam("Destination"));
}
}
} else if (causeSa.getHostCard() != null && causeSa.getHostCard().equals((Card)sa.getReplacingObject("Card"))
&& causeSa.getActivatingPlayer().equals(aiPlayer)) {
// This is an intrinsic effect that blinks the card (e.g. Obzedat, Ghost Council), no need to
// return the commander to the Command zone.
return false;
} }
} else return causeSa.getHostCard() == null || !causeSa.getHostCard().equals(sa.getReplacingObject("Card"))
|| !causeSa.getActivatingPlayer().equals(aiPlayer);
} }
// Normally we want the commander back in Command zone to recast him later // Normally we want the commander back in Command zone to recast him later

View File

@@ -335,11 +335,8 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
return true; return true;
// if AI creature is better than Human Creature // if AI creature is better than Human Creature
if (ComputerUtilCard.evaluateCreatureList(aiCards) >= ComputerUtilCard return ComputerUtilCard.evaluateCreatureList(aiCards) >= ComputerUtilCard
.evaluateCreatureList(humanCards)) { .evaluateCreatureList(humanCards);
return true;
}
return false;
} }
return true; return true;
} }
@@ -441,29 +438,21 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
if (sa.getParam("GainControl") != null) { if (sa.getParam("GainControl") != null) {
// Check if the cards are valuable enough // Check if the cards are valuable enough
if ((CardLists.getNotType(humanType, "Creature").size() == 0) && (CardLists.getNotType(computerType, "Creature").size() == 0)) { if ((CardLists.getNotType(humanType, "Creature").size() == 0) && (CardLists.getNotType(computerType, "Creature").size() == 0)) {
if ((ComputerUtilCard.evaluateCreatureList(computerType) + ComputerUtilCard return (ComputerUtilCard.evaluateCreatureList(computerType) + ComputerUtilCard
.evaluateCreatureList(humanType)) < 1) { .evaluateCreatureList(humanType)) >= 1;
return false;
}
} // otherwise evaluate both lists by CMC and pass only if human } // otherwise evaluate both lists by CMC and pass only if human
// permanents are less valuable // permanents are less valuable
else if ((ComputerUtilCard.evaluatePermanentList(computerType) + ComputerUtilCard else return (ComputerUtilCard.evaluatePermanentList(computerType) + ComputerUtilCard
.evaluatePermanentList(humanType)) < 1) { .evaluatePermanentList(humanType)) >= 1;
return false;
}
} else { } else {
// don't activate if human gets more back than AI does // don't activate if human gets more back than AI does
if ((CardLists.getNotType(humanType, "Creature").isEmpty()) && (CardLists.getNotType(computerType, "Creature").isEmpty())) { if ((CardLists.getNotType(humanType, "Creature").isEmpty()) && (CardLists.getNotType(computerType, "Creature").isEmpty())) {
if (ComputerUtilCard.evaluateCreatureList(computerType) <= ComputerUtilCard return ComputerUtilCard.evaluateCreatureList(computerType) > ComputerUtilCard
.evaluateCreatureList(humanType)) { .evaluateCreatureList(humanType);
return false;
}
} // otherwise evaluate both lists by CMC and pass only if human } // otherwise evaluate both lists by CMC and pass only if human
// permanents are less valuable // permanents are less valuable
else if (ComputerUtilCard.evaluatePermanentList(computerType) <= ComputerUtilCard else return ComputerUtilCard.evaluatePermanentList(computerType) > ComputerUtilCard
.evaluatePermanentList(humanType)) { .evaluatePermanentList(humanType);
return false;
}
} }
} }

View File

@@ -71,21 +71,15 @@ public class ChooseCardAi extends SpellAbilityAi {
choices = CardLists.filterControlledBy(choices, ai.getOpponents()); choices = CardLists.filterControlledBy(choices, ai.getOpponents());
} }
if (aiLogic.equals("AtLeast1") || aiLogic.equals("OppPreferred")) { if (aiLogic.equals("AtLeast1") || aiLogic.equals("OppPreferred")) {
if (choices.isEmpty()) { return !choices.isEmpty();
return false;
}
} else if (aiLogic.equals("AtLeast2") || aiLogic.equals("BestBlocker")) { } else if (aiLogic.equals("AtLeast2") || aiLogic.equals("BestBlocker")) {
if (choices.size() < 2) { return choices.size() >= 2;
return false;
}
} else if (aiLogic.equals("Clone") || aiLogic.equals("Vesuva")) { } else if (aiLogic.equals("Clone") || aiLogic.equals("Vesuva")) {
final String filter = aiLogic.equals("Clone") ? "Permanent.YouDontCtrl,Permanent.nonLegendary" final String filter = aiLogic.equals("Clone") ? "Permanent.YouDontCtrl,Permanent.nonLegendary"
: "Permanent.YouDontCtrl+notnamedVesuva,Permanent.nonLegendary+notnamedVesuva"; : "Permanent.YouDontCtrl+notnamedVesuva,Permanent.nonLegendary+notnamedVesuva";
choices = CardLists.getValidCards(choices, filter, host.getController(), host); choices = CardLists.getValidCards(choices, filter, host.getController(), host);
if (choices.isEmpty()) { return !choices.isEmpty();
return false;
}
} else if (aiLogic.equals("Never")) { } else if (aiLogic.equals("Never")) {
return false; return false;
} else if (aiLogic.equals("NeedsPrevention")) { } else if (aiLogic.equals("NeedsPrevention")) {
@@ -103,9 +97,7 @@ public class ChooseCardAi extends SpellAbilityAi {
return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > ref; return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > ref;
} }
}); });
if (choices.isEmpty()) { return !choices.isEmpty();
return false;
}
} else if (aiLogic.equals("Ashiok")) { } else if (aiLogic.equals("Ashiok")) {
final int loyalty = host.getCounters(CounterType.LOYALTY) - 1; final int loyalty = host.getCounters(CounterType.LOYALTY) - 1;
for (int i = loyalty; i >= 0; i--) { for (int i = loyalty; i >= 0; i--) {
@@ -117,13 +109,9 @@ public class ChooseCardAi extends SpellAbilityAi {
} }
} }
if (choices.isEmpty()) { return !choices.isEmpty();
return false;
}
} else if (aiLogic.equals("RandomNonLand")) { } else if (aiLogic.equals("RandomNonLand")) {
if (CardLists.getValidCards(choices, "Card.nonLand", host.getController(), host).isEmpty()) { return !CardLists.getValidCards(choices, "Card.nonLand", host.getController(), host).isEmpty();
return false;
}
} else if (aiLogic.equals("Duneblast")) { } else if (aiLogic.equals("Duneblast")) {
CardCollection aiCreatures = ai.getCreaturesInPlay(); CardCollection aiCreatures = ai.getCreaturesInPlay();
CardCollection oppCreatures = ai.getWeakestOpponent().getCreaturesInPlay(); CardCollection oppCreatures = ai.getWeakestOpponent().getCreaturesInPlay();
@@ -139,10 +127,8 @@ public class ChooseCardAi extends SpellAbilityAi {
aiCreatures.remove(chosen); aiCreatures.remove(chosen);
int minGain = 200; int minGain = 200;
if ((ComputerUtilCard.evaluateCreatureList(aiCreatures) + minGain) >= ComputerUtilCard return (ComputerUtilCard.evaluateCreatureList(aiCreatures) + minGain) < ComputerUtilCard
.evaluateCreatureList(oppCreatures)) { .evaluateCreatureList(oppCreatures);
return false;
}
} }
return true; return true;
} }

View File

@@ -52,10 +52,7 @@ public class ChooseColorAi extends SpellAbilityAi {
} }
if ("Addle".equals(sourceName)) { if ("Addle".equals(sourceName)) {
if (ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS) || ai.getWeakestOpponent().getCardsIn(ZoneType.Hand).isEmpty()) { return !ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS) && !ai.getWeakestOpponent().getCardsIn(ZoneType.Hand).isEmpty();
return false;
}
return true;
} }
if (logic.equals("MostExcessOpponentControls")) { if (logic.equals("MostExcessOpponentControls")) {

View File

@@ -33,9 +33,7 @@ public class ChooseDirectionAi extends SpellAbilityAi {
CardCollection right = CardLists.filterControlledBy(all, game.getNextPlayerAfter(ai, Direction.Right)); CardCollection right = CardLists.filterControlledBy(all, game.getNextPlayerAfter(ai, Direction.Right));
int leftValue = Aggregates.sum(left, CardPredicates.Accessors.fnGetCmc); int leftValue = Aggregates.sum(left, CardPredicates.Accessors.fnGetCmc);
int rightValue = Aggregates.sum(right, CardPredicates.Accessors.fnGetCmc); int rightValue = Aggregates.sum(right, CardPredicates.Accessors.fnGetCmc);
if (aiValue > leftValue || aiValue > rightValue) { return aiValue <= leftValue && aiValue <= rightValue;
return false;
}
} }
} }
return true; return true;

View File

@@ -385,9 +385,7 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
final Player opp = player.getWeakestOpponent(); final Player opp = player.getWeakestOpponent();
if (opp != null) { if (opp != null) {
// TODO add predict Combat Damage? // TODO add predict Combat Damage?
if (opp.getLife() < copy.getNetPower()) { return opp.getLife() < copy.getNetPower();
return true;
}
} }
// haste might not be good enough? // haste might not be good enough?

View File

@@ -97,10 +97,7 @@ public class ChooseSourceAi extends SpellAbilityAi {
return false; return false;
} }
int dmg = AbilityUtils.calculateAmount(threatSource, topStack.getParam("NumDmg"), topStack); int dmg = AbilityUtils.calculateAmount(threatSource, topStack.getParam("NumDmg"), topStack);
if (ComputerUtilCombat.predictDamageTo(ai, dmg, threatSource, false) <= 0) { return ComputerUtilCombat.predictDamageTo(ai, dmg, threatSource, false) > 0;
return false;
}
return true;
} }
if (game.getPhaseHandler().getPhase() != PhaseType.COMBAT_DECLARE_BLOCKERS) { if (game.getPhaseHandler().getPhase() != PhaseType.COMBAT_DECLARE_BLOCKERS) {
return false; return false;
@@ -119,9 +116,7 @@ public class ChooseSourceAi extends SpellAbilityAi {
return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > 0; return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > 0;
} }
}); });
if (choices.isEmpty()) { return !choices.isEmpty();
return false;
}
} }
} }

View File

@@ -244,9 +244,6 @@ public class CloneAi extends SpellAbilityAi {
} }
// don't activate during main2 unless this effect is permanent // don't activate during main2 unless this effect is permanent
if (ph.is(PhaseType.MAIN2) && !sa.hasParam("Permanent")) { return !ph.is(PhaseType.MAIN2) || sa.hasParam("Permanent");
return false;
}
return true;
} }
} }

View File

@@ -84,9 +84,7 @@ public class ControlGainAi extends SpellAbilityAi {
if (sa.hasParam("AllValid")) { if (sa.hasParam("AllValid")) {
CardCollectionView tgtCards = CardLists.filterControlledBy(game.getCardsIn(ZoneType.Battlefield), opponents); CardCollectionView tgtCards = CardLists.filterControlledBy(game.getCardsIn(ZoneType.Battlefield), opponents);
tgtCards = AbilityUtils.filterListByType(tgtCards, sa.getParam("AllValid"), sa); tgtCards = AbilityUtils.filterListByType(tgtCards, sa.getParam("AllValid"), sa);
if (tgtCards.isEmpty()) { return !tgtCards.isEmpty();
return false;
}
} }
return true; return true;
} else { } else {
@@ -247,7 +245,7 @@ public class ControlGainAi extends SpellAbilityAi {
break; break;
} }
} }
}; }
if (t != null) { if (t != null) {
sa.getTargets().add(t); sa.getTargets().add(t);
@@ -296,15 +294,12 @@ public class ControlGainAi extends SpellAbilityAi {
lose.addAll(Lists.newArrayList(sa.getParam("LoseControl").split(","))); lose.addAll(Lists.newArrayList(sa.getParam("LoseControl").split(",")));
} }
if (lose.contains("EOT") return !lose.contains("EOT")
&& game.getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)) { || !game.getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS);
return false;
}
} else { } else {
return this.canPlayAI(ai, sa); return this.canPlayAI(ai, sa);
} }
return true;
} // pumpDrawbackAI() } // pumpDrawbackAI()
@Override @Override

View File

@@ -90,9 +90,7 @@ public class CountersMoveAi extends SpellAbilityAi {
} }
// for Simic Fluxmage and other // for Simic Fluxmage and other
if (!ph.getNextTurn().equals(ai) || ph.getPhase().isBefore(PhaseType.END_OF_TURN)) { return ph.getNextTurn().equals(ai) && !ph.getPhase().isBefore(PhaseType.END_OF_TURN);
return false;
}
} else if (CounterType.P1P1.equals(cType) && sa.hasParam("Defined")) { } else if (CounterType.P1P1.equals(cType) && sa.hasParam("Defined")) {
// something like Cyptoplast Root-kin // something like Cyptoplast Root-kin
@@ -107,9 +105,7 @@ public class CountersMoveAi extends SpellAbilityAi {
} }
// Make sure that removing the last counter doesn't kill the creature // Make sure that removing the last counter doesn't kill the creature
if ("Self".equals(sa.getParam("Source"))) { if ("Self".equals(sa.getParam("Source"))) {
if (host != null && host.getNetToughness() - 1 <= 0) { return host == null || host.getNetToughness() - 1 > 0;
return false;
}
} }
} }
return true; return true;
@@ -193,9 +189,7 @@ public class CountersMoveAi extends SpellAbilityAi {
// check for some specific AI preferences // check for some specific AI preferences
if ("DontMoveCounterIfLethal".equals(sa.getParam("AILogic"))) { if ("DontMoveCounterIfLethal".equals(sa.getParam("AILogic"))) {
if (cType == CounterType.P1P1 && src.getNetToughness() - src.getTempToughnessBoost() - 1 <= 0) { return cType != CounterType.P1P1 || src.getNetToughness() - src.getTempToughnessBoost() - 1 > 0;
return false;
}
} }
} }
// no target // no target
@@ -207,9 +201,7 @@ public class CountersMoveAi extends SpellAbilityAi {
public boolean chkAIDrawback(SpellAbility sa, Player ai) { public boolean chkAIDrawback(SpellAbility sa, Player ai) {
if (sa.usesTargeting()) { if (sa.usesTargeting()) {
sa.resetTargets(); sa.resetTargets();
if (!moveTgtAI(ai, sa)) { return moveTgtAI(ai, sa);
return false;
}
} }
return true; return true;
@@ -287,10 +279,7 @@ public class CountersMoveAi extends SpellAbilityAi {
// do not steal a P1P1 from Undying if it would die // do not steal a P1P1 from Undying if it would die
// this way // this way
if (CounterType.P1P1.equals(cType) && srcCardCpy.getNetToughness() <= 0) { if (CounterType.P1P1.equals(cType) && srcCardCpy.getNetToughness() <= 0) {
if (srcCardCpy.getCounters(cType) > 0 || !card.hasKeyword(Keyword.UNDYING) || card.isToken()) { return srcCardCpy.getCounters(cType) > 0 || !card.hasKeyword(Keyword.UNDYING) || card.isToken();
return true;
}
return false;
} }
return true; return true;
} }

View File

@@ -48,6 +48,7 @@ public class CountersMultiplyAi extends SpellAbilityAi {
if (!c.canReceiveCounters(counterType)) { if (!c.canReceiveCounters(counterType)) {
return false; return false;
} }
} else { } else {
for (Map.Entry<CounterType, Integer> e : c.getCounters().entrySet()) { for (Map.Entry<CounterType, Integer> e : c.getCounters().entrySet()) {
// has negative counter it would double // has negative counter it would double
@@ -96,10 +97,7 @@ public class CountersMultiplyAi extends SpellAbilityAi {
@Override @Override
protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) { protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) {
if (sa.usesTargeting() && !setTargets(ai, sa) && !mandatory) { return !sa.usesTargeting() || setTargets(ai, sa) || mandatory;
return false;
}
return true;
} }
private CounterType getCounterType(SpellAbility sa) { private CounterType getCounterType(SpellAbility sa) {

View File

@@ -85,10 +85,7 @@ public class CountersProliferateAi extends SpellAbilityAi {
} }
if (cperms.isEmpty() && hperms.isEmpty() && !opponentPoison && !allyExpOrEnergy) { return !cperms.isEmpty() || !hperms.isEmpty() || opponentPoison || allyExpOrEnergy;
return false;
}
return true;
} }
@Override @Override

View File

@@ -469,7 +469,7 @@ public class CountersPutAi extends SpellAbilityAi {
int left = amount; int left = amount;
for (Card c : list) { for (Card c : list) {
if (ComputerUtilCard.shouldPumpCard(ai, sa, c, i, i, if (ComputerUtilCard.shouldPumpCard(ai, sa, c, i, i,
Lists.<String>newArrayList())) { Lists.newArrayList())) {
sa.getTargets().add(c); sa.getTargets().add(c);
abTgt.addDividedAllocation(c, i); abTgt.addDividedAllocation(c, i);
left -= i; left -= i;
@@ -506,7 +506,7 @@ public class CountersPutAi extends SpellAbilityAi {
if (type.equals("P1P1") && !SpellAbilityAi.isSorcerySpeed(sa)) { if (type.equals("P1P1") && !SpellAbilityAi.isSorcerySpeed(sa)) {
for (Card c : list) { for (Card c : list) {
if (ComputerUtilCard.shouldPumpCard(ai, sa, c, amount, amount, if (ComputerUtilCard.shouldPumpCard(ai, sa, c, amount, amount,
Lists.<String>newArrayList())) { Lists.newArrayList())) {
choice = c; choice = c;
break; break;
} }

View File

@@ -101,7 +101,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
} }
// Filter AI-specific targets if provided // Filter AI-specific targets if provided
list = ComputerUtil.filterAITgts(sa, ai, (CardCollection)list, false); list = ComputerUtil.filterAITgts(sa, ai, list, false);
boolean noLegendary = game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noLegendRule); boolean noLegendary = game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noLegendRule);

View File

@@ -37,9 +37,7 @@ public abstract class DamageAiBase extends SpellAbilityAi {
} }
if ("SelfDamage".equals(sa.getParam("AILogic"))) { if ("SelfDamage".equals(sa.getParam("AILogic"))) {
if (comp.getLife() * 0.75 < enemy.getLife()) { if (comp.getLife() * 0.75 < enemy.getLife()) {
if (!lifelink) { return !lifelink;
return true;
}
} }
} }
return false; return false;

View File

@@ -80,10 +80,7 @@ public class DamageDealAi extends DamageAiBase {
dmg--; // the card will be spent casting the spell, so actual damage is 1 less dmg--; // the card will be spent casting the spell, so actual damage is 1 less
} }
} }
if (!this.damageTargetAI(ai, sa, dmg, true)) { return this.damageTargetAI(ai, sa, dmg, true);
return false;
}
return true;
} }
@Override @Override
@@ -490,11 +487,9 @@ public class DamageDealAi extends DamageAiBase {
for (final Object o : objects) { for (final Object o : objects) {
if (o instanceof Card) { if (o instanceof Card) {
final Card c = (Card) o; final Card c = (Card) o;
if (hPlay.contains(c)) {
hPlay.remove(c); hPlay.remove(c);
} }
} }
}
hPlay = CardLists.getTargetableCards(hPlay, sa); hPlay = CardLists.getTargetableCards(hPlay, sa);
return hPlay; return hPlay;
} }
@@ -952,9 +947,7 @@ public class DamageDealAi extends DamageAiBase {
final TargetRestrictions tgt = sa.getTargetRestrictions(); final TargetRestrictions tgt = sa.getTargetRestrictions();
if (tgt == null) { if (tgt == null) {
// If it's not mandatory check a few things // If it's not mandatory check a few things
if (!mandatory && !this.damageChooseNontargeted(ai, sa, dmg)) { return mandatory || this.damageChooseNontargeted(ai, sa, dmg);
return false;
}
} else { } else {
if (!this.damageChoosingTargets(ai, sa, tgt, dmg, mandatory, true) && !mandatory) { if (!this.damageChoosingTargets(ai, sa, tgt, dmg, mandatory, true) && !mandatory) {
return false; return false;

View File

@@ -124,7 +124,7 @@ public class DebuffAi extends SpellAbilityAi {
final TargetRestrictions tgt = sa.getTargetRestrictions(); final TargetRestrictions tgt = sa.getTargetRestrictions();
sa.resetTargets(); sa.resetTargets();
CardCollection list = getCurseCreatures(ai, sa, kws == null ? Lists.<String>newArrayList() : kws); CardCollection list = getCurseCreatures(ai, sa, kws == null ? Lists.newArrayList() : kws);
list = CardLists.getValidCards(list, tgt.getValidTgts(), sa.getActivatingPlayer(), sa.getHostCard(), sa); list = CardLists.getValidCards(list, tgt.getValidTgts(), sa.getActivatingPlayer(), sa.getHostCard(), sa);
// several uses here: // several uses here:

View File

@@ -27,7 +27,7 @@ public class DelayedTriggerAi extends SpellAbilityAi {
trigsa.setActivatingPlayer(ai); trigsa.setActivatingPlayer(ai);
if (trigsa instanceof AbilitySub) { if (trigsa instanceof AbilitySub) {
return SpellApiToAi.Converter.get(((AbilitySub) trigsa).getApi()).chkDrawbackWithSubs(ai, (AbilitySub)trigsa); return SpellApiToAi.Converter.get(trigsa.getApi()).chkDrawbackWithSubs(ai, (AbilitySub)trigsa);
} else { } else {
return AiPlayDecision.WillPlay == ((PlayerControllerAi)ai.getController()).getAi().canPlaySa(trigsa); return AiPlayDecision.WillPlay == ((PlayerControllerAi)ai.getController()).getAi().canPlaySa(trigsa);
} }

View File

@@ -48,7 +48,7 @@ public class DestroyAi extends SpellAbilityAi {
return false; return false;
} }
hasXCost = abCost.getCostMana() != null ? abCost.getCostMana().getAmountOfX() > 0 : false; hasXCost = abCost.getCostMana() != null && abCost.getCostMana().getAmountOfX() > 0;
} }
if ("AtOpponentsCombatOrAfter".equals(sa.getParam("AILogic"))) { if ("AtOpponentsCombatOrAfter".equals(sa.getParam("AILogic"))) {
@@ -132,7 +132,7 @@ public class DestroyAi extends SpellAbilityAi {
} }
// Filter AI-specific targets if provided // Filter AI-specific targets if provided
list = ComputerUtil.filterAITgts(sa, ai, (CardCollection)list, true); list = ComputerUtil.filterAITgts(sa, ai, list, true);
list = CardLists.getNotKeyword(list, Keyword.INDESTRUCTIBLE); list = CardLists.getNotKeyword(list, Keyword.INDESTRUCTIBLE);
if (CardLists.getNotType(list, "Creature").isEmpty()) { if (CardLists.getNotType(list, "Creature").isEmpty()) {
@@ -342,7 +342,7 @@ public class DestroyAi extends SpellAbilityAi {
} }
// Filter AI-specific targets if provided // Filter AI-specific targets if provided
preferred = ComputerUtil.filterAITgts(sa, ai, (CardCollection)preferred, true); preferred = ComputerUtil.filterAITgts(sa, ai, preferred, true);
for (final Card c : preferred) { for (final Card c : preferred) {
list.remove(c); list.remove(c);
@@ -400,16 +400,11 @@ public class DestroyAi extends SpellAbilityAi {
} }
} }
if (sa.getTargets().getNumTargeted() < tgt.getMinTargets(sa.getHostCard(), sa)) { return sa.getTargets().getNumTargeted() >= tgt.getMinTargets(sa.getHostCard(), sa);
return false;
}
} else { } else {
if (!mandatory) { return mandatory;
return false;
}
} }
return true;
} }
public boolean doLandForLandRemovalLogic(SpellAbility sa, Player ai, Card tgtLand, String logic) { public boolean doLandForLandRemovalLogic(SpellAbility sa, Player ai, Card tgtLand, String logic) {

View File

@@ -171,7 +171,6 @@ public class DestroyAllAi extends SpellAbilityAi {
else if ((ComputerUtilCard.evaluatePermanentList(ailist) + 3) >= ComputerUtilCard.evaluatePermanentList(opplist)) { else if ((ComputerUtilCard.evaluatePermanentList(ailist) + 3) >= ComputerUtilCard.evaluatePermanentList(opplist)) {
return false; return false;
} }
return true; return true;
} }
} }

View File

@@ -51,12 +51,9 @@ public class DrainManaAi extends SpellAbilityAi {
} else { } else {
final List<Player> defined = AbilityUtils.getDefinedPlayers(source, sa.getParam("Defined"), sa); final List<Player> defined = AbilityUtils.getDefinedPlayers(source, sa.getParam("Defined"), sa);
if (!defined.contains(opp)) { return defined.contains(opp);
return false;
}
} }
return true;
} else { } else {
sa.resetTargets(); sa.resetTargets();
sa.getTargets().add(opp); sa.getTargets().add(opp);

View File

@@ -283,11 +283,7 @@ public class EffectAi extends SpellAbilityAi {
return false; return false;
} }
final SpellAbility topStack = game.getStack().peekAbility(); final SpellAbility topStack = game.getStack().peekAbility();
if (topStack.getActivatingPlayer().isOpponentOf(ai) && topStack.getApi() == ApiType.GainLife) { return topStack.getActivatingPlayer().isOpponentOf(ai) && topStack.getApi() == ApiType.GainLife;
return true;
} else {
return false;
}
} else if (logic.equals("Fight")) { } else if (logic.equals("Fight")) {
return FightAi.canFightAi(ai, sa, 0, 0); return FightAi.canFightAi(ai, sa, 0, 0);
} else if (logic.equals("Burn")) { } else if (logic.equals("Burn")) {
@@ -301,11 +297,9 @@ public class EffectAi extends SpellAbilityAi {
return false; return false;
} }
if (logic.contains(":")) { if (logic.contains(":")) {
String k[] = logic.split(":"); String[] k = logic.split(":");
Integer i = Integer.valueOf(k[1]); Integer i = Integer.valueOf(k[1]);
if (ai.getCreaturesInPlay().size() < i) { return ai.getCreaturesInPlay().size() >= i;
return false;
}
} }
return true; return true;
} else if (logic.equals("CastFromGraveThisTurn")) { } else if (logic.equals("CastFromGraveThisTurn")) {

View File

@@ -11,9 +11,7 @@ public class GameWinAi extends SpellAbilityAi {
*/ */
@Override @Override
protected boolean canPlayAI(Player ai, SpellAbility sa) { protected boolean canPlayAI(Player ai, SpellAbility sa) {
if (ai.cantWin()) { return !ai.cantWin();
return false;
}
// TODO Check conditions are met on card (e.g. Coalition Victory) // TODO Check conditions are met on card (e.g. Coalition Victory)
@@ -21,7 +19,6 @@ public class GameWinAi extends SpellAbilityAi {
// In general, don't return true. // In general, don't return true.
// But this card wins the game, I can make an exception for that // But this card wins the game, I can make an exception for that
return true;
} }
@Override @Override

View File

@@ -106,13 +106,9 @@ public class LifeGainAi extends SpellAbilityAi {
return false; return false;
} }
if (!lifeCritical && !activateForCost return lifeCritical || activateForCost
&& (!ph.getNextTurn().equals(ai) || ph.getPhase().isBefore(PhaseType.END_OF_TURN)) || (ph.getNextTurn().equals(ai) && !ph.getPhase().isBefore(PhaseType.END_OF_TURN))
&& !sa.hasParam("PlayerTurn") && !SpellAbilityAi.isSorcerySpeed(sa)) { || sa.hasParam("PlayerTurn") || SpellAbilityAi.isSorcerySpeed(sa);
return false;
}
return true;
} }
/* /*
@@ -304,9 +300,7 @@ public class LifeGainAi extends SpellAbilityAi {
hasTgt = true; hasTgt = true;
} }
} }
if (!hasTgt) { return hasTgt;
return false;
}
} }
return true; return true;
} }

View File

@@ -53,9 +53,7 @@ public class LifeLoseAi extends SpellAbilityAi {
} }
if (sa.usesTargeting()) { if (sa.usesTargeting()) {
if (!doTgt(ai, sa, false)) { return doTgt(ai, sa, false);
return false;
}
} }
return true; return true;
@@ -187,12 +185,8 @@ public class LifeLoseAi extends SpellAbilityAi {
? new FCollection<Player>(sa.getTargets().getTargetPlayers()) ? new FCollection<Player>(sa.getTargets().getTargetPlayers())
: AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("Defined"), sa); : AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("Defined"), sa);
if (!mandatory && tgtPlayers.contains(ai) && amount > 0 && amount + 3 > ai.getLife()) {
// For cards like Foul Imp, ETB you lose life // For cards like Foul Imp, ETB you lose life
return false; return mandatory || !tgtPlayers.contains(ai) || amount <= 0 || amount + 3 <= ai.getLife();
}
return true;
} }
protected boolean doTgt(Player ai, SpellAbility sa, boolean mandatory) { protected boolean doTgt(Player ai, SpellAbility sa, boolean mandatory) {

View File

@@ -81,11 +81,8 @@ public class ManaEffectAi extends SpellAbilityAi {
return true; // handled elsewhere, does not meet the standard requirements return true; // handled elsewhere, does not meet the standard requirements
} }
if (!(sa.getPayCosts() != null && sa.getPayCosts().hasNoManaCost() && sa.getPayCosts().isReusuableResource() return sa.getPayCosts() != null && sa.getPayCosts().hasNoManaCost() && sa.getPayCosts().isReusuableResource()
&& sa.getSubAbility() == null && ComputerUtil.playImmediately(ai, sa))) { && sa.getSubAbility() == null && ComputerUtil.playImmediately(ai, sa);
return false;
}
return true;
// return super.checkApiLogic(ai, sa); // return super.checkApiLogic(ai, sa);
} }

View File

@@ -185,10 +185,7 @@ public class ManifestAi extends SpellAbilityAi {
CardCollection filtered = CardLists.filter(options, new Predicate<Card>() { CardCollection filtered = CardLists.filter(options, new Predicate<Card>() {
@Override @Override
public boolean apply(Card input) { public boolean apply(Card input) {
if (shouldManyfest(input, ai, sa)) { return !shouldManyfest(input, ai, sa);
return false;
}
return true;
} }
}); });
if (!filtered.isEmpty()) { if (!filtered.isEmpty()) {

View File

@@ -31,19 +31,13 @@ public class MillAi extends SpellAbilityAi {
PhaseHandler ph = ai.getGame().getPhaseHandler(); PhaseHandler ph = ai.getGame().getPhaseHandler();
if (aiLogic.equals("Main1")) { if (aiLogic.equals("Main1")) {
if (ph.getPhase().isBefore(PhaseType.MAIN2) && !sa.hasParam("ActivationPhases") return !ph.getPhase().isBefore(PhaseType.MAIN2) || sa.hasParam("ActivationPhases")
&& !ComputerUtil.castSpellInMain1(ai, sa)) { || ComputerUtil.castSpellInMain1(ai, sa);
return false;
}
} else if (aiLogic.equals("EndOfOppTurn")) { } else if (aiLogic.equals("EndOfOppTurn")) {
if (!(ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn().equals(ai))) { return ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn().equals(ai);
return false;
}
} else if (aiLogic.equals("LilianaMill")) { } else if (aiLogic.equals("LilianaMill")) {
// Only mill if a "Raise Dead" target is available, in case of control decks with few creatures // Only mill if a "Raise Dead" target is available, in case of control decks with few creatures
if (CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.CREATURES).size() < 1) { return CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.CREATURES).size() >= 1;
return false;
}
} }
return true; return true;
} }
@@ -62,11 +56,9 @@ public class MillAi extends SpellAbilityAi {
} }
} }
if (sa.getHostCard().isCreature() && sa.getPayCosts().hasTapCost()) { if (sa.getHostCard().isCreature() && sa.getPayCosts().hasTapCost()) {
if (!(ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn().equals(ai))) {
// creatures with a tap cost to mill (e.g. Doorkeeper) should be activated at the opponent's end step // creatures with a tap cost to mill (e.g. Doorkeeper) should be activated at the opponent's end step
// because they are also potentially useful for combat // because they are also potentially useful for combat
return false; return ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn().equals(ai);
}
} }
return true; return true;
} }
@@ -100,9 +92,7 @@ public class MillAi extends SpellAbilityAi {
// Set PayX here to maximum value. // Set PayX here to maximum value.
final int cardsToDiscard = getNumToDiscard(ai, sa); final int cardsToDiscard = getNumToDiscard(ai, sa);
source.setSVar("PayX", Integer.toString(cardsToDiscard)); source.setSVar("PayX", Integer.toString(cardsToDiscard));
if (cardsToDiscard <= 0) { return cardsToDiscard > 0;
return false;
}
} }
return true; return true;
} }

View File

@@ -38,10 +38,7 @@ public class PermanentAi extends SpellAbilityAi {
} }
// Wait for Main2 if possible // Wait for Main2 if possible
if (ph.is(PhaseType.MAIN1) && ph.isPlayerTurn(ai) && !ComputerUtil.castPermanentInMain1(ai, sa) && !sa.hasParam("WithoutManaCost")) { return !ph.is(PhaseType.MAIN1) || !ph.isPlayerTurn(ai) || ComputerUtil.castPermanentInMain1(ai, sa) || sa.hasParam("WithoutManaCost");
return false;
}
return true;
} }
/** /**
@@ -259,9 +256,7 @@ public class PermanentAi extends SpellAbilityAi {
} }
} }
if (dontCast) { return !dontCast;
return false;
}
} }
return true; return true;

View File

@@ -40,9 +40,7 @@ public class PermanentCreatureAi extends PermanentAi {
ComputerUtilCard.applyStaticContPT(game, copy, null); ComputerUtilCard.applyStaticContPT(game, copy, null);
if (copy.getNetToughness() <= 0) { return copy.getNetToughness() > 0;
return false;
}
} }
return true; return true;
} }
@@ -225,13 +223,9 @@ public class PermanentCreatureAi extends PermanentAi {
*/ */
final Card copy = CardUtil.getLKICopy(sa.getHostCard()); final Card copy = CardUtil.getLKICopy(sa.getHostCard());
ComputerUtilCard.applyStaticContPT(game, copy, null); ComputerUtilCard.applyStaticContPT(game, copy, null);
if (copy.getNetToughness() <= 0 && !copy.hasStartOfKeyword("etbCounter") && mana.countX() == 0
&& !copy.hasETBTrigger(false) && !copy.hasETBReplacement() && !copy.hasSVar("NoZeroToughnessAI")) {
// AiPlayDecision.WouldBecomeZeroToughnessCreature // AiPlayDecision.WouldBecomeZeroToughnessCreature
return false; return copy.getNetToughness() > 0 || copy.hasStartOfKeyword("etbCounter") || mana.countX() != 0
} || copy.hasETBTrigger(false) || copy.hasETBReplacement() || copy.hasSVar("NoZeroToughnessAI");
return true;
} }
} }

View File

@@ -19,10 +19,7 @@ public class PermanentNoncreatureAi extends PermanentAi {
@Override @Override
protected boolean checkAiLogic(final Player ai, final SpellAbility sa, final String aiLogic) { protected boolean checkAiLogic(final Player ai, final SpellAbility sa, final String aiLogic) {
if ("Never".equals(aiLogic) || "DontCast".equals(aiLogic)) { return !"Never".equals(aiLogic) && !"DontCast".equals(aiLogic);
return false;
}
return true;
} }
/** /**
@@ -54,10 +51,8 @@ public class PermanentNoncreatureAi extends PermanentAi {
// TODO: consider replacing the condition with host.hasSVar("OblivionRing") // TODO: consider replacing the condition with host.hasSVar("OblivionRing")
targets = CardLists.filterControlledBy(targets, ai.getOpponents()); targets = CardLists.filterControlledBy(targets, ai.getOpponents());
} }
if (targets.isEmpty()) {
// AiPlayDecision.AnotherTime // AiPlayDecision.AnotherTime
return false; return !targets.isEmpty();
}
} }
return true; return true;
} }

View File

@@ -33,9 +33,7 @@ public class PhasesAi extends SpellAbilityAi {
if (tgtCards.contains(source)) { if (tgtCards.contains(source)) {
// Protect it from something // Protect it from something
final boolean isThreatened = ComputerUtil.predictThreatenedObjects(aiPlayer, null, true).contains(source); final boolean isThreatened = ComputerUtil.predictThreatenedObjects(aiPlayer, null, true).contains(source);
if (isThreatened) { return isThreatened;
return true;
}
} else { } else {
// Card def = tgtCards.get(0); // Card def = tgtCards.get(0);
// Phase this out if it might attack me, or before it can be // Phase this out if it might attack me, or before it can be

View File

@@ -178,11 +178,7 @@ public class PlayAi extends SpellAbilityAi {
// Before accepting, see if the spell has a valid number of targets (it should at this point). // Before accepting, see if the spell has a valid number of targets (it should at this point).
// Proceeding past this point if the spell is not correctly targeted will result // Proceeding past this point if the spell is not correctly targeted will result
// in "Failed to add to stack" error and the card disappearing from the game completely. // in "Failed to add to stack" error and the card disappearing from the game completely.
if (!spell.isTargetNumberValid()) { return spell.isTargetNumberValid();
return false;
}
return true;
} }
} }
return false; return false;

View File

@@ -24,11 +24,8 @@ public class PoisonAi extends SpellAbilityAi {
*/ */
@Override @Override
protected boolean checkPhaseRestrictions(final Player ai, final SpellAbility sa, final PhaseHandler ph) { protected boolean checkPhaseRestrictions(final Player ai, final SpellAbility sa, final PhaseHandler ph) {
if (ph.getPhase().isBefore(PhaseType.MAIN2) return !ph.getPhase().isBefore(PhaseType.MAIN2)
&& !sa.hasParam("ActivationPhases")) { || sa.hasParam("ActivationPhases");
return false;
}
return true;
} }
/* /*
@@ -83,7 +80,6 @@ public class PoisonAi extends SpellAbilityAi {
return false; return false;
} }
} }
return true; return true;
} }
@@ -99,7 +95,6 @@ public class PoisonAi extends SpellAbilityAi {
} else if (!input.canReceiveCounters(CounterType.POISON)) { } else if (!input.canReceiveCounters(CounterType.POISON)) {
return false; return false;
} }
return true; return true;
} }
@@ -132,10 +127,7 @@ public class PoisonAi extends SpellAbilityAi {
if (input.cantLose()) { if (input.cantLose()) {
return true; return true;
} }
if (!input.canReceiveCounters(CounterType.POISON)) { return !input.canReceiveCounters(CounterType.POISON);
return true;
}
return false;
} }
}); });

View File

@@ -162,11 +162,8 @@ public class ProtectAi extends SpellAbilityAi {
@Override @Override
protected boolean checkPhaseRestrictions(final Player ai, final SpellAbility sa, final PhaseHandler ph) { protected boolean checkPhaseRestrictions(final Player ai, final SpellAbility sa, final PhaseHandler ph) {
final boolean notAiMain1 = !(ph.getPlayerTurn() == ai && ph.getPhase() == PhaseType.MAIN1); final boolean notAiMain1 = !(ph.getPlayerTurn() == ai && ph.getPhase() == PhaseType.MAIN1);
if (SpellAbilityAi.isSorcerySpeed(sa) && notAiMain1) {
// sorceries can only give protection in order to create an unblockable attacker // sorceries can only give protection in order to create an unblockable attacker
return false; return !SpellAbilityAi.isSorcerySpeed(sa) || !notAiMain1;
}
return true;
} }
@Override @Override
@@ -177,9 +174,7 @@ public class ProtectAi extends SpellAbilityAi {
return false; return false;
} else if (cards.size() == 1) { } else if (cards.size() == 1) {
// Affecting single card // Affecting single card
if ((getProtectCreatures(ai, sa)).contains(cards.get(0))) { return (getProtectCreatures(ai, sa)).contains(cards.get(0));
return true;
}
} }
/* /*
* when this happens we need to expand AI to consider if its ok * when this happens we need to expand AI to consider if its ok

View File

@@ -92,10 +92,7 @@ public class PumpAi extends PumpAiBase {
return true; return true;
} }
if (!ph.getNextTurn().equals(ai) || ph.getPhase().isBefore(PhaseType.END_OF_TURN)) { return ph.getNextTurn().equals(ai) && !ph.getPhase().isBefore(PhaseType.END_OF_TURN);
return false;
}
return true;
} else if (logic.equals("Aristocrat")) { } else if (logic.equals("Aristocrat")) {
final boolean isThreatened = ComputerUtil.predictThreatenedObjects(ai, null, true).contains(sa.getHostCard()); final boolean isThreatened = ComputerUtil.predictThreatenedObjects(ai, null, true).contains(sa.getHostCard());
if (!ph.is(PhaseType.COMBAT_DECLARE_BLOCKERS) && !isThreatened) { if (!ph.is(PhaseType.COMBAT_DECLARE_BLOCKERS) && !isThreatened) {
@@ -121,9 +118,7 @@ public class PumpAi extends PumpAiBase {
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS))) { || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS))) {
// Instant-speed pumps should not be cast outside of combat when the // Instant-speed pumps should not be cast outside of combat when the
// stack is empty // stack is empty
if (!sa.isCurse() && !SpellAbilityAi.isSorcerySpeed(sa) && !main1Preferred) { return sa.isCurse() || SpellAbilityAi.isSorcerySpeed(sa) || main1Preferred;
return false;
}
} }
return true; return true;
} }
@@ -134,7 +129,7 @@ public class PumpAi extends PumpAiBase {
final Card source = sa.getHostCard(); final Card source = sa.getHostCard();
final String sourceName = ComputerUtilAbility.getAbilitySourceName(sa); final String sourceName = ComputerUtilAbility.getAbilitySourceName(sa);
final List<String> keywords = sa.hasParam("KW") ? Arrays.asList(sa.getParam("KW").split(" & ")) final List<String> keywords = sa.hasParam("KW") ? Arrays.asList(sa.getParam("KW").split(" & "))
: Lists.<String>newArrayList(); : Lists.newArrayList();
final String numDefense = sa.hasParam("NumDef") ? sa.getParam("NumDef") : ""; final String numDefense = sa.hasParam("NumDef") ? sa.getParam("NumDef") : "";
final String numAttack = sa.hasParam("NumAtt") ? sa.getParam("NumAtt") : ""; final String numAttack = sa.hasParam("NumAtt") ? sa.getParam("NumAtt") : "";
@@ -191,11 +186,8 @@ public class PumpAi extends PumpAiBase {
srcCardCpy.setCounters(cType, srcCardCpy.getCounters(cType) - amount); srcCardCpy.setCounters(cType, srcCardCpy.getCounters(cType) - amount);
if (CounterType.P1P1.equals(cType) && srcCardCpy.getNetToughness() <= 0) { if (CounterType.P1P1.equals(cType) && srcCardCpy.getNetToughness() <= 0) {
if (srcCardCpy.getCounters(cType) > 0 || !card.hasKeyword(Keyword.UNDYING) return srcCardCpy.getCounters(cType) > 0 || !card.hasKeyword(Keyword.UNDYING)
|| card.isToken()) { || card.isToken();
return true;
}
return false;
} }
return false; return false;
} }
@@ -244,11 +236,8 @@ public class PumpAi extends PumpAiBase {
srcCardCpy.setCounters(cType, srcCardCpy.getCounters(cType) - amount); srcCardCpy.setCounters(cType, srcCardCpy.getCounters(cType) - amount);
if (CounterType.P1P1.equals(cType) && srcCardCpy.getNetToughness() <= 0) { if (CounterType.P1P1.equals(cType) && srcCardCpy.getNetToughness() <= 0) {
if (srcCardCpy.getCounters(cType) > 0 || !card.hasKeyword(Keyword.UNDYING) return srcCardCpy.getCounters(cType) > 0 || !card.hasKeyword(Keyword.UNDYING)
|| card.isToken()) { || card.isToken();
return true;
}
return false;
} }
return true; return true;
} }
@@ -395,9 +384,7 @@ public class PumpAi extends PumpAiBase {
Card pumped = ComputerUtilCard.getPumpedCreature(ai, sa, card, 0, 0, keywords); Card pumped = ComputerUtilCard.getPumpedCreature(ai, sa, card, 0, 0, keywords);
if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS, ai) if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS, ai)
|| game.getPhaseHandler().is(PhaseType.COMBAT_BEGIN, ai)) { || game.getPhaseHandler().is(PhaseType.COMBAT_BEGIN, ai)) {
if (!ComputerUtilCard.doesSpecifiedCreatureAttackAI(ai, pumped)) { return ComputerUtilCard.doesSpecifiedCreatureAttackAI(ai, pumped);
return false;
}
} }
return true; return true;
@@ -432,7 +419,7 @@ public class PumpAi extends PumpAiBase {
private boolean pumpTgtAI(final Player ai, final SpellAbility sa, final int defense, final int attack, final boolean mandatory, private boolean pumpTgtAI(final Player ai, final SpellAbility sa, final int defense, final int attack, final boolean mandatory,
boolean immediately) { boolean immediately) {
final List<String> keywords = sa.hasParam("KW") ? Arrays.asList(sa.getParam("KW").split(" & ")) final List<String> keywords = sa.hasParam("KW") ? Arrays.asList(sa.getParam("KW").split(" & "))
: Lists.<String>newArrayList(); : Lists.newArrayList();
final Game game = ai.getGame(); final Game game = ai.getGame();
final Card source = sa.getHostCard(); final Card source = sa.getHostCard();
final boolean isFight = "Fight".equals(sa.getParam("AILogic")) || "PowerDmg".equals(sa.getParam("AILogic")); final boolean isFight = "Fight".equals(sa.getParam("AILogic")) || "PowerDmg".equals(sa.getParam("AILogic"));
@@ -555,7 +542,7 @@ public class PumpAi extends PumpAiBase {
} }
// Filter AI-specific targets if provided // Filter AI-specific targets if provided
list = ComputerUtil.filterAITgts(sa, ai, (CardCollection)list, true); list = ComputerUtil.filterAITgts(sa, ai, list, true);
if (list.isEmpty()) { if (list.isEmpty()) {
if (ComputerUtil.activateForCost(sa, ai)) { if (ComputerUtil.activateForCost(sa, ai)) {
@@ -788,15 +775,11 @@ public class PumpAi extends PumpAiBase {
if (!source.hasKeyword(Keyword.INDESTRUCTIBLE) && source.getNetToughness() + defense <= source.getDamage()) { if (!source.hasKeyword(Keyword.INDESTRUCTIBLE) && source.getNetToughness() + defense <= source.getDamage()) {
return false; return false;
} }
if (source.getNetToughness() + defense <= 0) { return source.getNetToughness() + defense > 0;
return false;
}
} }
} else { } else {
//Targeted //Targeted
if (!pumpTgtAI(ai, sa, defense, attack, false, true)) { return pumpTgtAI(ai, sa, defense, attack, false, true);
return false;
}
} }
return true; return true;
@@ -849,9 +832,7 @@ public class PumpAi extends PumpAiBase {
} }
} }
); );
if (sacFodder.size() >= numCreatsToSac) { return sacFodder.size() >= numCreatsToSac;
return true;
}
} }
} }

View File

@@ -56,24 +56,17 @@ public abstract class PumpAiBase extends SpellAbilityAi {
if (!CardUtil.isStackingKeyword(keyword) && card.hasKeyword(keyword)) { if (!CardUtil.isStackingKeyword(keyword) && card.hasKeyword(keyword)) {
return false; return false;
} else if (keyword.equals("Defender") || keyword.endsWith("CARDNAME can't attack.")) { } else if (keyword.equals("Defender") || keyword.endsWith("CARDNAME can't attack.")) {
if (!ph.isPlayerTurn(card.getController()) || !CombatUtil.canAttack(card, ai) return ph.isPlayerTurn(card.getController()) && CombatUtil.canAttack(card, ai)
|| (card.getNetCombatDamage() <= 0) && (card.getNetCombatDamage() > 0)
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)) { && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS);
return false;
}
} else if (keyword.endsWith("CARDNAME can't attack or block.")) { } else if (keyword.endsWith("CARDNAME can't attack or block.")) {
if (sa.hasParam("UntilYourNextTurn")) { if (sa.hasParam("UntilYourNextTurn")) {
if (CombatUtil.canAttack(card, ai) || CombatUtil.canBlock(card, true)) { return CombatUtil.canAttack(card, ai) || CombatUtil.canBlock(card, true);
return true;
}
return false;
} }
if (!ph.isPlayerTurn(ai)) { if (!ph.isPlayerTurn(ai)) {
if (!CombatUtil.canAttack(card, ai) return CombatUtil.canAttack(card, ai)
|| (card.getNetCombatDamage() <= 0) && (card.getNetCombatDamage() > 0)
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)) { && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS);
return false;
}
} else { } else {
if (ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS) if (ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)
|| ph.getPhase().isBefore(PhaseType.MAIN1)) { || ph.getPhase().isBefore(PhaseType.MAIN1)) {
@@ -90,9 +83,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
return CombatUtil.canAttack(c, card.getController()) || (combat != null && combat.isAttacking(c)); return CombatUtil.canAttack(c, card.getController()) || (combat != null && combat.isAttacking(c));
} }
}); });
if (!CombatUtil.canBlockAtLeastOne(card, attackers)) { return CombatUtil.canBlockAtLeastOne(card, attackers);
return false;
}
} }
} else if (keyword.endsWith("CARDNAME can't block.")) { } else if (keyword.endsWith("CARDNAME can't block.")) {
if (!ph.isPlayerTurn(ai) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS) if (!ph.isPlayerTurn(ai) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)
@@ -112,24 +103,18 @@ public abstract class PumpAiBase extends SpellAbilityAi {
&& card.getController().equals(combat.getDefenderPlayerByAttacker(c))); && card.getController().equals(combat.getDefenderPlayerByAttacker(c)));
} }
}); });
if (!CombatUtil.canBlockAtLeastOne(card, attackers)) { return CombatUtil.canBlockAtLeastOne(card, attackers);
return false;
}
} else if (keyword.endsWith("CantBlockCardUIDSource")) { // can't block CARDNAME this turn } else if (keyword.endsWith("CantBlockCardUIDSource")) { // can't block CARDNAME this turn
if (!ph.isPlayerTurn(ai) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS) if (!ph.isPlayerTurn(ai) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)
|| ph.getPhase().isBefore(PhaseType.MAIN1) || !CombatUtil.canBlock(sa.getHostCard(), card)) { || ph.getPhase().isBefore(PhaseType.MAIN1) || !CombatUtil.canBlock(sa.getHostCard(), card)) {
return false; return false;
} }
// target needs to be a creature, controlled by the player which is attacked // target needs to be a creature, controlled by the player which is attacked
if (sa.getHostCard().isTapped() && (combat == null || !combat.isAttacking(sa.getHostCard()) return !sa.getHostCard().isTapped() || (combat != null && combat.isAttacking(sa.getHostCard())
|| !card.getController().equals(combat.getDefenderPlayerByAttacker(sa.getHostCard())))) { && card.getController().equals(combat.getDefenderPlayerByAttacker(sa.getHostCard())));
return false;
}
} else if (keyword.endsWith("This card doesn't untap during your next untap step.")) { } else if (keyword.endsWith("This card doesn't untap during your next untap step.")) {
if (ph.getPhase().isBefore(PhaseType.MAIN2) || card.isUntapped() || !ph.isPlayerTurn(ai) return !ph.getPhase().isBefore(PhaseType.MAIN2) && !card.isUntapped() && ph.isPlayerTurn(ai)
|| !Untap.canUntap(card)) { && Untap.canUntap(card);
return false;
}
} else if (keyword.endsWith("Prevent all combat damage that would be dealt by CARDNAME.") } else if (keyword.endsWith("Prevent all combat damage that would be dealt by CARDNAME.")
|| keyword.endsWith("Prevent all damage that would be dealt by CARDNAME.")) { || keyword.endsWith("Prevent all damage that would be dealt by CARDNAME.")) {
if (ph.isPlayerTurn(ai) && (!(CombatUtil.canBlock(card) || combat != null && combat.isBlocking(card)) if (ph.isPlayerTurn(ai) && (!(CombatUtil.canBlock(card) || combat != null && combat.isBlocking(card))
@@ -139,28 +124,18 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|| CardLists.getNotKeyword(ai.getCreaturesInPlay(), Keyword.DEFENDER).isEmpty())) { || CardLists.getNotKeyword(ai.getCreaturesInPlay(), Keyword.DEFENDER).isEmpty())) {
return false; return false;
} }
if (!ph.isPlayerTurn(ai) && (combat == null || !combat.isAttacking(card) || card.getNetCombatDamage() <= 0)) { return ph.isPlayerTurn(ai) || (combat != null && combat.isAttacking(card) && card.getNetCombatDamage() > 0);
return false;
}
} else if (keyword.endsWith("CARDNAME attacks each turn if able.") } else if (keyword.endsWith("CARDNAME attacks each turn if able.")
|| keyword.endsWith("CARDNAME attacks each combat if able.")) { || keyword.endsWith("CARDNAME attacks each combat if able.")) {
if (ph.isPlayerTurn(ai) || !CombatUtil.canAttack(card, ai) || !CombatUtil.canBeBlocked(card, ai) return !ph.isPlayerTurn(ai) && CombatUtil.canAttack(card, ai) && CombatUtil.canBeBlocked(card, ai)
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)) { && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS);
return false;
}
} else if (keyword.endsWith("CARDNAME can't be regenerated.")) { } else if (keyword.endsWith("CARDNAME can't be regenerated.")) {
if (card.getShieldCount() > 0) { if (card.getShieldCount() > 0) {
return true; return true;
} }
if (card.hasKeyword("If CARDNAME would be destroyed, regenerate it.") && combat != null return card.hasKeyword("If CARDNAME would be destroyed, regenerate it.") && combat != null
&& (combat.isBlocked(card) || combat.isBlocking(card))) { && (combat.isBlocked(card) || combat.isBlocking(card));
return true; } else return !keyword.endsWith("CARDNAME's activated abilities can't be activated."); //too complex
}
return false;
} else if (keyword.endsWith("CARDNAME's activated abilities can't be activated.")) {
return false; //too complex
}
return true;
} }
/** /**
@@ -187,12 +162,10 @@ public abstract class PumpAiBase extends SpellAbilityAi {
final boolean evasive = (keyword.endsWith("Unblockable") || keyword.endsWith("Shadow") || keyword.startsWith("CantBeBlockedBy")); final boolean evasive = (keyword.endsWith("Unblockable") || keyword.endsWith("Shadow") || keyword.startsWith("CantBeBlockedBy"));
// give evasive keywords to creatures that can or do attack // give evasive keywords to creatures that can or do attack
if (evasive) { if (evasive) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) return !ph.isPlayerTurn(opp) && (CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card)))
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| newPower <= 0 && newPower > 0
|| CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) { && !CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty();
return false;
}
} else if (keyword.endsWith("Flying")) { } else if (keyword.endsWith("Flying")) {
CardCollectionView attackingFlyer = CardCollection.EMPTY; CardCollectionView attackingFlyer = CardCollection.EMPTY;
if (combat != null) { if (combat != null) {
@@ -221,13 +194,11 @@ public abstract class PumpAiBase extends SpellAbilityAi {
} }
} }
} }
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) return !ph.isPlayerTurn(opp) && (CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card)))
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| newPower <= 0 && newPower > 0
|| !Iterables.any(CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)), && Iterables.any(CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)),
Predicates.not(flyingOrReach))) { Predicates.not(flyingOrReach));
return false;
}
} else if (keyword.endsWith("Horsemanship")) { } else if (keyword.endsWith("Horsemanship")) {
if (ph.isPlayerTurn(opp) if (ph.isPlayerTurn(opp)
&& ph.getPhase().equals(PhaseType.COMBAT_DECLARE_ATTACKERS) && ph.getPhase().equals(PhaseType.COMBAT_DECLARE_ATTACKERS)
@@ -236,46 +207,35 @@ public abstract class PumpAiBase extends SpellAbilityAi {
&& ComputerUtilCombat.lifeInDanger(ai, game.getCombat())) { && ComputerUtilCombat.lifeInDanger(ai, game.getCombat())) {
return true; return true;
} }
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) return !ph.isPlayerTurn(opp) && (CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card)))
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| newPower <= 0 && newPower > 0
|| CardLists.getNotKeyword(CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)), && !CardLists.getNotKeyword(CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)),
Keyword.HORSEMANSHIP).isEmpty()) { Keyword.HORSEMANSHIP).isEmpty();
return false;
}
} else if (keyword.endsWith("Intimidate")) { } else if (keyword.endsWith("Intimidate")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) return !ph.isPlayerTurn(opp) && (CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card)))
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| newPower <= 0 && newPower > 0
|| CardLists.getNotType(CardLists.filter( && !CardLists.getNotType(CardLists.filter(
opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)), "Artifact").isEmpty()) { opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)), "Artifact").isEmpty();
return false;
}
} else if (keyword.endsWith("Fear")) { } else if (keyword.endsWith("Fear")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) return !ph.isPlayerTurn(opp) && (CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card)))
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| newPower <= 0 && newPower > 0
|| CardLists.getNotColor(CardLists.getNotType(CardLists.filter( && !CardLists.getNotColor(CardLists.getNotType(CardLists.filter(
opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)), "Artifact"), MagicColor.BLACK).isEmpty()) { opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)), "Artifact"), MagicColor.BLACK).isEmpty();
return false;
}
} else if (keyword.endsWith("Haste")) { } else if (keyword.endsWith("Haste")) {
if (!card.hasSickness() || ph.isPlayerTurn(opp) || card.isTapped() return card.hasSickness() && !ph.isPlayerTurn(opp) && !card.isTapped()
|| newPower <= 0 && newPower > 0
|| card.hasKeyword("CARDNAME can attack as though it had haste.") && !card.hasKeyword("CARDNAME can attack as though it had haste.")
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| !ComputerUtilCombat.canAttackNextTurn(card)) { && ComputerUtilCombat.canAttackNextTurn(card);
return false;
}
} else if (keyword.endsWith("Indestructible")) { } else if (keyword.endsWith("Indestructible")) {
// Predicting threatened objects in relevant non-combat situations happens elsewhere, // Predicting threatened objects in relevant non-combat situations happens elsewhere,
// so we are only worrying about combat relevance of Indestructible at this point. // so we are only worrying about combat relevance of Indestructible at this point.
if (combat == null return combat != null
|| !((combat.isBlocked(card) || combat.isBlocking(card)) && ((combat.isBlocked(card) || combat.isBlocking(card))
&& ComputerUtilCombat.combatantWouldBeDestroyed(ai, card, combat))) { && ComputerUtilCombat.combatantWouldBeDestroyed(ai, card, combat));
return false;
}
return true;
} else if (keyword.endsWith("Deathtouch")) { } else if (keyword.endsWith("Deathtouch")) {
if (ph.isPlayerTurn(opp) && ph.getPhase().equals(PhaseType.COMBAT_DECLARE_ATTACKERS)) { if (ph.isPlayerTurn(opp) && ph.getPhase().equals(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
List<Card> attackers = combat.getAttackers(); List<Card> attackers = combat.getAttackers();
@@ -297,12 +257,10 @@ public abstract class PumpAiBase extends SpellAbilityAi {
} }
return false; return false;
} else if (keyword.equals("Bushido")) { } else if (keyword.equals("Bushido")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) return !ph.isPlayerTurn(opp) && (CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card)))
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS) && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)
|| opp.getCreaturesInPlay().isEmpty() && !opp.getCreaturesInPlay().isEmpty()
|| CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) { && !CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty();
return false;
}
} else if (keyword.equals("First Strike")) { } else if (keyword.equals("First Strike")) {
if (card.hasKeyword(Keyword.DOUBLE_STRIKE)) { if (card.hasKeyword(Keyword.DOUBLE_STRIKE)) {
return false; return false;
@@ -321,40 +279,31 @@ public abstract class PumpAiBase extends SpellAbilityAi {
if (!ComputerUtilCombat.canDestroyAttacker(ai, attacker, card, combat, true) if (!ComputerUtilCombat.canDestroyAttacker(ai, attacker, card, combat, true)
&& ComputerUtilCombat.canDestroyAttacker(ai, attacker, card, combat, false)) && ComputerUtilCombat.canDestroyAttacker(ai, attacker, card, combat, false))
return true; return true;
if (ComputerUtilCombat.canDestroyBlocker(ai, card, attacker, combat, true) return ComputerUtilCombat.canDestroyBlocker(ai, card, attacker, combat, true)
&& !ComputerUtilCombat.canDestroyBlocker(ai, card, attacker, combat, false)) && !ComputerUtilCombat.canDestroyBlocker(ai, card, attacker, combat, false);
return true;
} }
return false; return false;
} else if (keyword.equals("Double Strike")) { } else if (keyword.equals("Double Strike")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) return !ph.isPlayerTurn(opp) && (CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card)))
|| newPower <= 0 && newPower > 0
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)) { && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS);
return false;
}
} else if (keyword.startsWith("Rampage")) { } else if (keyword.startsWith("Rampage")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) return !ph.isPlayerTurn(opp) && (CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card)))
|| newPower <= 0 && newPower > 0
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).size() < 2) { && CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).size() >= 2;
return false;
}
} else if (keyword.startsWith("Flanking")) { } else if (keyword.startsWith("Flanking")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) return !ph.isPlayerTurn(opp) && (CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card)))
|| newPower <= 0 && newPower > 0
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| CardLists.getNotKeyword(CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)), && !CardLists.getNotKeyword(CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)),
Keyword.FLANKING).isEmpty()) { Keyword.FLANKING).isEmpty();
return false;
}
} else if (keyword.startsWith("Trample")) { } else if (keyword.startsWith("Trample")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) return !ph.isPlayerTurn(opp) && (CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card)))
|| !CombatUtil.canBeBlocked(card, opp) && CombatUtil.canBeBlocked(card, opp)
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| newPower <= 1 && newPower > 1
|| CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) { && !CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty();
return false;
}
} else if (keyword.equals("Infect")) { } else if (keyword.equals("Infect")) {
if (newPower <= 0) { if (newPower <= 0) {
return false; return false;
@@ -362,11 +311,9 @@ public abstract class PumpAiBase extends SpellAbilityAi {
if (combat != null && combat.isBlocking(card) && !card.hasKeyword(Keyword.WITHER)) { if (combat != null && combat.isBlocking(card) && !card.hasKeyword(Keyword.WITHER)) {
return true; return true;
} }
if ((ph.isPlayerTurn(opp)) return (!ph.isPlayerTurn(opp))
|| !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) && (CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card)))
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)) { && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS);
return false;
}
} else if (keyword.endsWith("Wither")) { } else if (keyword.endsWith("Wither")) {
if (newPower <= 0 || card.hasKeyword(Keyword.INFECT)) { if (newPower <= 0 || card.hasKeyword(Keyword.INFECT)) {
return false; return false;
@@ -378,20 +325,16 @@ public abstract class PumpAiBase extends SpellAbilityAi {
} }
return combat != null && ( combat.isAttacking(card) || combat.isBlocking(card) ); return combat != null && ( combat.isAttacking(card) || combat.isBlocking(card) );
} else if (keyword.equals("Vigilance")) { } else if (keyword.equals("Vigilance")) {
if (ph.isPlayerTurn(opp) || !CombatUtil.canAttack(card, opp) return !ph.isPlayerTurn(opp) && CombatUtil.canAttack(card, opp)
|| newPower <= 0 && newPower > 0
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| CardLists.getNotKeyword(opp.getCreaturesInPlay(), Keyword.DEFENDER).isEmpty()) { && !CardLists.getNotKeyword(opp.getCreaturesInPlay(), Keyword.DEFENDER).isEmpty();
return false;
}
} else if (keyword.equals("Reach")) { } else if (keyword.equals("Reach")) {
if (ph.isPlayerTurn(ai) return !ph.isPlayerTurn(ai)
|| !ph.getPhase().equals(PhaseType.COMBAT_DECLARE_ATTACKERS) && ph.getPhase().equals(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| CardLists.getKeyword(game.getCombat().getAttackers(), Keyword.FLYING).isEmpty() && !CardLists.getKeyword(game.getCombat().getAttackers(), Keyword.FLYING).isEmpty()
|| card.hasKeyword(Keyword.FLYING) && !card.hasKeyword(Keyword.FLYING)
|| !CombatUtil.canBlock(card)) { && CombatUtil.canBlock(card);
return false;
}
} else if (keyword.endsWith("CARDNAME can block an additional creature each combat.")) { } else if (keyword.endsWith("CARDNAME can block an additional creature each combat.")) {
if (ph.isPlayerTurn(ai) if (ph.isPlayerTurn(ai)
|| !ph.getPhase().equals(PhaseType.COMBAT_DECLARE_ATTACKERS)) { || !ph.getPhase().equals(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
@@ -407,63 +350,43 @@ public abstract class PumpAiBase extends SpellAbilityAi {
} }
} }
} }
if (possibleBlockNum <= canBlockNum) { return possibleBlockNum > canBlockNum;
return false;
}
} else if (keyword.equals("Shroud") || keyword.equals("Hexproof")) { } else if (keyword.equals("Shroud") || keyword.equals("Hexproof")) {
if (!ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), sa).contains(card)) { return ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), sa).contains(card);
return false;
}
} else if (keyword.equals("Persist")) { } else if (keyword.equals("Persist")) {
if (card.getBaseToughness() <= 1 || card.hasKeyword(Keyword.UNDYING)) { return card.getBaseToughness() > 1 && !card.hasKeyword(Keyword.UNDYING);
return false;
}
} else if (keyword.equals("Islandwalk")) { } else if (keyword.equals("Islandwalk")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) return !ph.isPlayerTurn(opp) && (CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card)))
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| newPower <= 0 && newPower > 0
|| CardLists.getType(opp.getLandsInPlay(), "Island").isEmpty() && !CardLists.getType(opp.getLandsInPlay(), "Island").isEmpty()
|| CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) { && !CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty();
return false;
}
} else if (keyword.equals("Swampwalk")) { } else if (keyword.equals("Swampwalk")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) return !ph.isPlayerTurn(opp) && (CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card)))
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| newPower <= 0 && newPower > 0
|| CardLists.getType(opp.getLandsInPlay(), "Swamp").isEmpty() && !CardLists.getType(opp.getLandsInPlay(), "Swamp").isEmpty()
|| CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) { && !CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty();
return false;
}
} else if (keyword.equals("Mountainwalk")) { } else if (keyword.equals("Mountainwalk")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) return !ph.isPlayerTurn(opp) && (CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card)))
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| newPower <= 0 && newPower > 0
|| CardLists.getType(opp.getLandsInPlay(), "Mountain").isEmpty() && !CardLists.getType(opp.getLandsInPlay(), "Mountain").isEmpty()
|| CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) { && !CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty();
return false;
}
} else if (keyword.equals("Forestwalk")) { } else if (keyword.equals("Forestwalk")) {
if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) return !ph.isPlayerTurn(opp) && (CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card)))
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) && !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| newPower <= 0 && newPower > 0
|| CardLists.getType(opp.getLandsInPlay(), "Forest").isEmpty() && !CardLists.getType(opp.getLandsInPlay(), "Forest").isEmpty()
|| CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) { && !CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty();
return false;
}
} else if (keyword.endsWith("CARDNAME can attack as though it didn't have defender.")) { } else if (keyword.endsWith("CARDNAME can attack as though it didn't have defender.")) {
if (!ph.isPlayerTurn(ai) || !card.hasKeyword(Keyword.DEFENDER) return ph.isPlayerTurn(ai) && card.hasKeyword(Keyword.DEFENDER)
|| ph.getPhase().isAfter(PhaseType.COMBAT_BEGIN) && !ph.getPhase().isAfter(PhaseType.COMBAT_BEGIN)
|| card.isTapped() || newPower <= 0) { && !card.isTapped() && newPower > 0;
return false;
}
} else if (keyword.equals("Prevent all combat damage that would be dealt to CARDNAME.")) { } else if (keyword.equals("Prevent all combat damage that would be dealt to CARDNAME.")) {
if (combat == null || !(combat.isBlocking(card) || combat.isBlocked(card))) { return combat != null && (combat.isBlocking(card) || combat.isBlocked(card));
return false;
}
} else if (keyword.equals("Menace")) { } else if (keyword.equals("Menace")) {
if (combat == null || !combat.isAttacking(card)) { return combat != null && combat.isAttacking(card);
return false;
}
} }
return true; return true;
} }
@@ -547,10 +470,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
return true; return true;
} }
//Don't waste a -7/-0 spell on a 1/1 creature //Don't waste a -7/-0 spell on a 1/1 creature
if (c.getNetPower() + attack > -2 || c.getNetPower() > 3) { return c.getNetPower() + attack > -2 || c.getNetPower() > 3;
return true;
}
return false;
} }
}); });
} else { } else {

View File

@@ -141,10 +141,7 @@ public class PumpAllAi extends PumpAiBase {
// evaluate both lists and pass only if human creatures are more // evaluate both lists and pass only if human creatures are more
// valuable // valuable
if ((ComputerUtilCard.evaluateCreatureList(comp) + 200) >= ComputerUtilCard.evaluateCreatureList(human)) { return (ComputerUtilCard.evaluateCreatureList(comp) + 200) < ComputerUtilCard.evaluateCreatureList(human);
return false;
}
return true;
} // end Curse } // end Curse
return !CardLists.getValidCards(getPumpCreatures(ai, sa, defense, power, keywords, false), valid, source.getController(), source).isEmpty(); return !CardLists.getValidCards(getPumpCreatures(ai, sa, defense, power, keywords, false), valid, source.getController(), source).isEmpty();

View File

@@ -18,9 +18,7 @@ public class RemoveFromCombatAi extends SpellAbilityAi {
// AI should only activate this during Human's turn // AI should only activate this during Human's turn
if ("RemoveBestAttacker".equals(sa.getParam("AILogic"))) { if ("RemoveBestAttacker".equals(sa.getParam("AILogic"))) {
if (aiPlayer.getGame().getCombat() != null && aiPlayer.getGame().getCombat().getDefenders().contains(aiPlayer)) { return aiPlayer.getGame().getCombat() != null && aiPlayer.getGame().getCombat().getDefenders().contains(aiPlayer);
return true;
}
} }
// TODO - implement AI // TODO - implement AI

View File

@@ -32,9 +32,7 @@ public class RepeatAi extends SpellAbilityAi {
// Set PayX here to maximum value. // Set PayX here to maximum value.
final int max = ComputerUtilMana.determineLeftoverMana(sa, ai); final int max = ComputerUtilMana.determineLeftoverMana(sa, ai);
source.setSVar("PayX", Integer.toString(max)); source.setSVar("PayX", Integer.toString(max));
if (max <= 0) { return max > 0;
return false;
}
} }
return true; return true;
} }

View File

@@ -35,9 +35,7 @@ public class RepeatEachAi extends SpellAbilityAi {
List<Card> humTokenCreats = CardLists.filter(aiPlayer.getOpponents().getCreaturesInPlay(), Presets.TOKEN); List<Card> humTokenCreats = CardLists.filter(aiPlayer.getOpponents().getCreaturesInPlay(), Presets.TOKEN);
List<Card> compTokenCreats = CardLists.filter(aiPlayer.getCreaturesInPlay(), Presets.TOKEN); List<Card> compTokenCreats = CardLists.filter(aiPlayer.getCreaturesInPlay(), Presets.TOKEN);
if (compTokenCreats.size() <= humTokenCreats.size()) { return compTokenCreats.size() > humTokenCreats.size();
return false;
}
} else if ("BalanceLands".equals(logic)) { } else if ("BalanceLands".equals(logic)) {
if (CardLists.filter(aiPlayer.getCardsIn(ZoneType.Battlefield), Presets.LANDS).size() >= 5) { if (CardLists.filter(aiPlayer.getCardsIn(ZoneType.Battlefield), Presets.LANDS).size() >= 5) {
return false; return false;
@@ -111,9 +109,7 @@ public class RepeatEachAi extends SpellAbilityAi {
} }
} }
// would not hit oppoent, don't do that // would not hit oppoent, don't do that
if (!hitOpp) { return hitOpp;
return false;
}
} }
// TODO Add some normal AI variability here // TODO Add some normal AI variability here

View File

@@ -30,11 +30,7 @@ public class RevealHandAi extends RevealAiBase {
@Override @Override
protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) { protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) {
if (!revealHandTargetAI(ai, sa/*, false, mandatory*/)) { return revealHandTargetAI(ai, sa/*, false, mandatory*/);
return false;
}
return true;
} }
} }

View File

@@ -144,7 +144,7 @@ public class RollPlanarDiceAi extends SpellAbilityAi {
} }
} }
return decideToRoll ? true : false; return decideToRoll;
} }
/* (non-Javadoc) /* (non-Javadoc)

View File

@@ -136,9 +136,7 @@ public class SacrificeAi extends SpellAbilityAi {
// Since all of the cards have AI:RemoveDeck:All, I enabled 1 for 1 // Since all of the cards have AI:RemoveDeck:All, I enabled 1 for 1
// (or X for X) trades for special decks // (or X for X) trades for special decks
if (humanList.size() < amount) { return humanList.size() >= amount;
return false;
}
} else if (defined.equals("You")) { } else if (defined.equals("You")) {
List<Card> computerList = List<Card> computerList =
CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa); CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa);

View File

@@ -145,10 +145,10 @@ public class ScryAi extends SpellAbilityAi {
if (maxToRemove <= 0) { if (maxToRemove <= 0) {
return false; return false;
} }
sa.setSVar("ChosenX", "Number$" + Integer.toString(maxToRemove)); sa.setSVar("ChosenX", "Number$" + maxToRemove);
} else { } else {
// no Instant or Sorceries anymore, just scry // no Instant or Sorceries anymore, just scry
sa.setSVar("ChosenX", "Number$" + Integer.toString(Math.min(counterNum, libsize))); sa.setSVar("ChosenX", "Number$" + Math.min(counterNum, libsize));
} }
} }
return true; return true;

View File

@@ -92,9 +92,7 @@ public class SetStateAi extends SpellAbilityAi {
} }
} }
if (sa.getTargets().getNumTargeted() < tgt.getMinTargets(source, sa)) { return sa.getTargets().getNumTargeted() >= tgt.getMinTargets(source, sa);
return false;
}
} }
} else if ("TurnFace".equals(mode)) { } else if ("TurnFace".equals(mode)) {
if (!sa.usesTargeting()) { if (!sa.usesTargeting()) {
@@ -123,9 +121,7 @@ public class SetStateAi extends SpellAbilityAi {
} }
} }
if (sa.getTargets().getNumTargeted() < tgt.getMinTargets(source, sa)) { return sa.getTargets().getNumTargeted() >= tgt.getMinTargets(source, sa);
return false;
}
} }
} }
return true; return true;
@@ -254,9 +250,7 @@ public class SetStateAi extends SpellAbilityAi {
// for legendary KI counter creatures // for legendary KI counter creatures
if (othercard.getCounters(CounterType.KI) >= source.getCounters(CounterType.KI)) { if (othercard.getCounters(CounterType.KI) >= source.getCounters(CounterType.KI)) {
// if the other legendary is useless try to replace it // if the other legendary is useless try to replace it
if (!ComputerUtilCard.isUselessCreature(aiPlayer, othercard)) { return ComputerUtilCard.isUselessCreature(aiPlayer, othercard);
return false;
}
} }
} }
} }
@@ -266,10 +260,6 @@ public class SetStateAi extends SpellAbilityAi {
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) { public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
// TODO: improve the AI for when it may want to transform something that's optional to transform // TODO: improve the AI for when it may want to transform something that's optional to transform
if (!isSafeToTransformIntoLegendary(player, sa.getHostCard())) { return isSafeToTransformIntoLegendary(player, sa.getHostCard());
return false;
}
return true;
} }
} }

View File

@@ -11,10 +11,7 @@ public class SkipTurnAi extends SpellAbilityAi {
*/ */
@Override @Override
protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) { protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) {
if ("Always".equals(sa.getParam("AILogic"))) { return "Always".equals(sa.getParam("AILogic"));
return true;
}
return false;
} }
/* (non-Javadoc) /* (non-Javadoc)

View File

@@ -76,9 +76,7 @@ public class SurveilAi extends SpellAbilityAi {
if ("Never".equals(aiLogic)) { if ("Never".equals(aiLogic)) {
return false; return false;
} else if ("Once".equals(aiLogic)) { } else if ("Once".equals(aiLogic)) {
if (AiCardMemory.isRememberedCard(ai, source, AiCardMemory.MemorySet.ACTIVATED_THIS_TURN)) { return !AiCardMemory.isRememberedCard(ai, source, AiCardMemory.MemorySet.ACTIVATED_THIS_TURN);
return false;
}
} }
// TODO: add card-specific Surveil AI logic here when/if necessary // TODO: add card-specific Surveil AI logic here when/if necessary

View File

@@ -64,9 +64,7 @@ public class TapAi extends TapAiBase {
bFlag |= c.isUntapped(); bFlag |= c.isUntapped();
} }
if (!bFlag) { return bFlag;
return false;
}
} else { } else {
if ("TapForXCounters".equals(sa.getParam("AILogic"))) { if ("TapForXCounters".equals(sa.getParam("AILogic"))) {
// e.g. Waxmane Baku // e.g. Waxmane Baku
@@ -83,12 +81,9 @@ public class TapAi extends TapAiBase {
} }
sa.resetTargets(); sa.resetTargets();
if (!tapPrefTargeting(ai, source, tgt, sa, false)) { return tapPrefTargeting(ai, source, tgt, sa, false);
return false;
}
} }
return true;
} }
} }

View File

@@ -248,12 +248,8 @@ public abstract class TapAiBase extends SpellAbilityAi {
sa.getTargets().add(choice); sa.getTargets().add(choice);
} }
if (sa.getTargets().getNumTargeted() == 0) {
// Nothing was ever targeted, so we need to bail. // Nothing was ever targeted, so we need to bail.
return false; return sa.getTargets().getNumTargeted() != 0;
}
return true;
} }
/** /**
@@ -307,11 +303,7 @@ public abstract class TapAiBase extends SpellAbilityAi {
// just tap whatever we can // just tap whatever we can
tapList = list; tapList = list;
if (tapTargetList(ai, sa, tapList, mandatory)) { return tapTargetList(ai, sa, tapList, mandatory);
return true;
}
return false;
} }
@Override @Override

View File

@@ -93,9 +93,7 @@ public class TapAllAi extends SpellAbilityAi {
return CombatUtil.canAttack(c) && ComputerUtilCombat.canAttackNextTurn(c); return CombatUtil.canAttack(c) && ComputerUtilCombat.canAttackNextTurn(c);
} }
}); });
if(!any) { return any;
return false;
}
} }
return true; return true;
} }

View File

@@ -103,12 +103,9 @@ public class TokenAi extends SpellAbilityAi {
if (actualToken == null) { if (actualToken == null) {
final AbilitySub sub = sa.getSubAbility(); final AbilitySub sub = sa.getSubAbility();
if (pwPlus || (sub != null && SpellApiToAi.Converter.get(sub.getApi()).chkAIDrawback(sub, ai))) {
return true; // planeswalker plus ability or sub-ability is
// useful // useful
} else { // no token created
return false; // no token created return pwPlus || (sub != null && SpellApiToAi.Converter.get(sub.getApi()).chkAIDrawback(sub, ai)); // planeswalker plus ability or sub-ability is
}
} }
// X-cost spells // X-cost spells
@@ -154,10 +151,7 @@ public class TokenAi extends SpellAbilityAi {
&& !haste && !pwMinus) { && !haste && !pwMinus) {
return false; return false;
} }
if ((ph.getPhase().isAfter(PhaseType.COMBAT_BEGIN) || !ph.isPlayerTurn(ai)) && oneShot) { return (!ph.getPhase().isAfter(PhaseType.COMBAT_BEGIN) && ph.isPlayerTurn(ai)) || !oneShot;
return false;
}
return true;
} }
@Override @Override
@@ -269,10 +263,8 @@ public class TokenAi extends SpellAbilityAi {
list.add(token); list.add(token);
list = CardLists.getValidCards(list, valid.split(","), ai.getWeakestOpponent(), topStack.getHostCard(), sa); list = CardLists.getValidCards(list, valid.split(","), ai.getWeakestOpponent(), topStack.getHostCard(), sa);
list = CardLists.filter(list, CardPredicates.canBeSacrificedBy(topStack)); list = CardLists.filter(list, CardPredicates.canBeSacrificedBy(topStack));
if (ComputerUtilCard.evaluateCreature(token) < ComputerUtilCard.evaluateCreature(list.get(0)) return ComputerUtilCard.evaluateCreature(token) < ComputerUtilCard.evaluateCreature(list.get(0))
&& list.contains(token)) { && list.contains(token);
return true;
}
} }
return false; return false;
} }

View File

@@ -82,9 +82,7 @@ public class UnattachAllAi extends SpellAbilityAi {
//don't equip a worse creature //don't equip a worse creature
if (card.isEquipping()) { if (card.isEquipping()) {
Card oldTarget = card.getEquipping(); Card oldTarget = card.getEquipping();
if (ComputerUtilCard.evaluateCreature(oldTarget) > ComputerUtilCard.evaluateCreature(newTarget)) { return ComputerUtilCard.evaluateCreature(oldTarget) <= ComputerUtilCard.evaluateCreature(newTarget);
return false;
}
} }
} }

View File

@@ -45,11 +45,7 @@ public class UntapAi extends SpellAbilityAi {
return false; return false;
} }
if (!ComputerUtilCost.checkDiscardCost(ai, cost, sa.getHostCard())) { return ComputerUtilCost.checkDiscardCost(ai, cost, sa.getHostCard());
return false;
}
return true;
} }
@Override @Override
@@ -63,16 +59,11 @@ public class UntapAi extends SpellAbilityAi {
if (tgt == null) { if (tgt == null) {
final List<Card> pDefined = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa); final List<Card> pDefined = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa);
if (pDefined != null && pDefined.get(0).isUntapped() && pDefined.get(0).getController() == ai) { return pDefined == null || !pDefined.get(0).isUntapped() || pDefined.get(0).getController() != ai;
return false;
}
} else { } else {
if (!untapPrefTargeting(ai, tgt, sa, false)) { return untapPrefTargeting(ai, tgt, sa, false);
return false;
}
} }
return true;
} }
@Override @Override
@@ -86,11 +77,7 @@ public class UntapAi extends SpellAbilityAi {
// TODO: use Defined to determine, if this is an unfavorable result // TODO: use Defined to determine, if this is an unfavorable result
final List<Card> pDefined = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa); final List<Card> pDefined = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa);
if (pDefined != null && pDefined.get(0).isUntapped() && pDefined.get(0).getController() == ai) { return pDefined == null || !pDefined.get(0).isUntapped() || pDefined.get(0).getController() != ai;
return false;
}
return true;
} else { } else {
if (untapPrefTargeting(ai, tgt, sa, mandatory)) { if (untapPrefTargeting(ai, tgt, sa, mandatory)) {
return true; return true;
@@ -271,11 +258,7 @@ public class UntapAi extends SpellAbilityAi {
// just tap whatever we can // just tap whatever we can
tapList = list; tapList = list;
if (untapTargetList(source, tgt, sa, mandatory, tapList)) { return untapTargetList(source, tgt, sa, mandatory, tapList);
return true;
}
return false;
} }
private boolean untapTargetList(final Card source, final TargetRestrictions tgt, final SpellAbility sa, final boolean mandatory, private boolean untapTargetList(final Card source, final TargetRestrictions tgt, final SpellAbility sa, final boolean mandatory,
@@ -438,13 +421,10 @@ public class UntapAi extends SpellAbilityAi {
// no harm in doing this past declare blockers during the opponent's turn and right before our turn, // no harm in doing this past declare blockers during the opponent's turn and right before our turn,
// maybe we'll serendipitously untap into something like a removal spell or burn spell that'll help // maybe we'll serendipitously untap into something like a removal spell or burn spell that'll help
if (ph.getNextTurn() == ai return ph.getNextTurn() == ai
&& (ph.is(PhaseType.COMBAT_DECLARE_BLOCKERS) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS))) { && (ph.is(PhaseType.COMBAT_DECLARE_BLOCKERS) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS));
return true;
}
// haven't found any immediate playable options // haven't found any immediate playable options
return false;
} }
} }

View File

@@ -80,7 +80,7 @@ public class PossibleTargetSelector {
} }
private static class SimilarTargetSkipper { private static class SimilarTargetSkipper {
private ArrayListMultimap<String, Card> validTargetsMap = ArrayListMultimap.<String, Card>create(); private ArrayListMultimap<String, Card> validTargetsMap = ArrayListMultimap.create();
private HashMap<Card, String> cardTypeStrings = new HashMap<Card, String>(); private HashMap<Card, String> cardTypeStrings = new HashMap<Card, String>();
private HashMap<Card, Integer> creatureScores; private HashMap<Card, Integer> creatureScores;

View File

@@ -49,7 +49,7 @@ public class SpellAbilityChoicesIterator {
// TODO: Do we need to do something special to support cards that have extra costs // TODO: Do we need to do something special to support cards that have extra costs
// when choosing more modes, like Blessed Alliance? // when choosing more modes, like Blessed Alliance?
if (!allowRepeat) { if (!allowRepeat) {
modeIterator = CombinatoricsUtils.combinationsIterator(choices.size(), num);; modeIterator = CombinatoricsUtils.combinationsIterator(choices.size(), num);
} else { } else {
// Note: When allowRepeat is true, it does result in many possibilities being tried. // Note: When allowRepeat is true, it does result in many possibilities being tried.
// We should ideally prune some of those at a higher level. // We should ideally prune some of those at a higher level.

View File

@@ -308,9 +308,7 @@ public class SpellAbilityPicker {
return true; return true;
} }
List<PhaseType> phases = conditions.getPhases(); List<PhaseType> phases = conditions.getPhases();
if (phases.isEmpty() || phases.contains(PhaseType.MAIN1)) { return phases.isEmpty() || phases.contains(PhaseType.MAIN1);
return true;
}
} }
return false; return false;

View File

@@ -6,7 +6,7 @@
<parent> <parent>
<artifactId>forge</artifactId> <artifactId>forge</artifactId>
<groupId>forge</groupId> <groupId>forge</groupId>
<version>1.6.28-SNAPSHOT</version> <version>1.6.29-SNAPSHOT</version>
</parent> </parent>
<artifactId>forge-core</artifactId> <artifactId>forge-core</artifactId>

View File

@@ -64,7 +64,7 @@ public class CardStorageReader {
void report(int current, int total); void report(int current, int total);
// does nothing, used when they pass null instead of an instance // does nothing, used when they pass null instead of an instance
public final static ProgressObserver emptyObserver = new ProgressObserver() { ProgressObserver emptyObserver = new ProgressObserver() {
@Override public void setOperationName(final String name, final boolean usePercents) {} @Override public void setOperationName(final String name, final boolean usePercents) {}
@Override public void report(final int current, final int total) {} @Override public void report(final int current, final int total) {}
}; };

View File

@@ -123,7 +123,7 @@ public final class ImageKeys {
int index = filename.lastIndexOf('_'); int index = filename.lastIndexOf('_');
if (index != -1) { if (index != -1) {
String setlessFilename = filename.substring(0, index); String setlessFilename = filename.substring(0, index);
String setCode = filename.substring(index + 1, filename.length()); String setCode = filename.substring(index + 1);
// try with upper case set // try with upper case set
file = findFile(dir, setlessFilename + "_" + setCode.toUpperCase()); file = findFile(dir, setlessFilename + "_" + setCode.toUpperCase());
if (file != null) { return file; } if (file != null) { return file; }

View File

@@ -41,7 +41,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
public final static char NameSetSeparator = '|'; public final static char NameSetSeparator = '|';
// need this to obtain cardReference by name+set+artindex // need this to obtain cardReference by name+set+artindex
private final ListMultimap<String, PaperCard> allCardsByName = Multimaps.newListMultimap(new TreeMap<String,Collection<PaperCard>>(String.CASE_INSENSITIVE_ORDER), CollectionSuppliers.<PaperCard>arrayLists()); private final ListMultimap<String, PaperCard> allCardsByName = Multimaps.newListMultimap(new TreeMap<String,Collection<PaperCard>>(String.CASE_INSENSITIVE_ORDER), CollectionSuppliers.arrayLists());
private final Map<String, PaperCard> uniqueCardsByName = Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER); private final Map<String, PaperCard> uniqueCardsByName = Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER);
private final Map<String, CardRules> rulesByName; private final Map<String, CardRules> rulesByName;
private final Map<String, ICardFace> facesByName = Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER); private final Map<String, ICardFace> facesByName = Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER);
@@ -62,7 +62,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
Random(false); Random(false);
final boolean filterSets; final boolean filterSets;
private SetPreference(boolean filterIrregularSets) { SetPreference(boolean filterIrregularSets) {
filterSets = filterIrregularSets; filterSets = filterIrregularSets;
} }

View File

@@ -189,7 +189,7 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
public String getBoosterMustContain() { return boosterMustContain; } public String getBoosterMustContain() { return boosterMustContain; }
public CardInSet[] getCards() { return cards; } public CardInSet[] getCards() { return cards; }
public Map<String, Integer> getTokens() { return tokenNormalized; }; public Map<String, Integer> getTokens() { return tokenNormalized; }
public static final Function<CardEdition, String> FN_GET_CODE = new Function<CardEdition, String>() { public static final Function<CardEdition, String> FN_GET_CODE = new Function<CardEdition, String>() {
@Override @Override

View File

@@ -20,7 +20,7 @@ final class CardFace implements ICardFace {
public enum FaceSelectionMethod { // public enum FaceSelectionMethod { //
USE_ACTIVE_FACE, USE_ACTIVE_FACE,
USE_PRIMARY_FACE, USE_PRIMARY_FACE,
COMBINE; COMBINE
} }
@@ -87,7 +87,7 @@ final class CardFace implements ICardFace {
void setInitialLoyalty(String value) { this.initialLoyalty = value; } void setInitialLoyalty(String value) { this.initialLoyalty = value; }
void setPtText(String value) { void setPtText(String value) {
final String k[] = value.split("/"); final String[] k = value.split("/");
if (k.length != 2) { if (k.length != 2) {
throw new RuntimeException("Creature '" + this.getName() + "' has bad p/t stats"); throw new RuntimeException("Creature '" + this.getName() + "' has bad p/t stats");

View File

@@ -85,7 +85,7 @@ public final class CardFacePredicates {
@Override @Override
public boolean apply(ICardFace input) { public boolean apply(ICardFace input) {
String k[] = valid.split("\\.", 2); String[] k = valid.split("\\.", 2);
if ("Card".equals(k[0])) { if ("Card".equals(k[0])) {
// okay // okay
@@ -110,10 +110,7 @@ public final class CardFacePredicates {
static protected boolean hasProperty(ICardFace input, final String v) { static protected boolean hasProperty(ICardFace input, final String v) {
if (v.startsWith("non")) { if (v.startsWith("non")) {
return !hasProperty(input, v.substring(3)); return !hasProperty(input, v.substring(3));
} else if (!input.getType().hasStringType(v)) { } else return input.getType().hasStringType(v);
return false;
}
return true;
} }
} }

View File

@@ -35,7 +35,7 @@ public enum CardRarity {
private final String shortName, longName; private final String shortName, longName;
private CardRarity(final String shortName0, final String longName0) { CardRarity(final String shortName0, final String longName0) {
shortName = shortName0; shortName = shortName0;
longName = longName0; longName = longName0;
} }

View File

@@ -435,10 +435,10 @@ public final class CardRulesPredicates {
return this.op(card.getManaCost().getGenericCost(), this.operand); return this.op(card.getManaCost().getGenericCost(), this.operand);
case POWER: case POWER:
value = card.getIntPower(); value = card.getIntPower();
return value != Integer.MAX_VALUE ? this.op(value, this.operand) : false; return value != Integer.MAX_VALUE && this.op(value, this.operand);
case TOUGHNESS: case TOUGHNESS:
value = card.getIntToughness(); value = card.getIntToughness();
return value != Integer.MAX_VALUE ? this.op(value, this.operand) : false; return value != Integer.MAX_VALUE && this.op(value, this.operand);
default: default:
return false; return false;
} }

View File

@@ -10,7 +10,7 @@ public enum CardSplitType
Split(FaceSelectionMethod.COMBINE, CardStateName.RightSplit), Split(FaceSelectionMethod.COMBINE, CardStateName.RightSplit),
Flip(FaceSelectionMethod.USE_PRIMARY_FACE, CardStateName.Flipped); Flip(FaceSelectionMethod.USE_PRIMARY_FACE, CardStateName.Flipped);
private CardSplitType(FaceSelectionMethod calcMode, CardStateName stateName) { CardSplitType(FaceSelectionMethod calcMode, CardStateName stateName) {
method = calcMode; method = calcMode;
this.changedStateName = stateName; this.changedStateName = stateName;
} }

View File

@@ -73,7 +73,7 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
public final boolean isPermanent; public final boolean isPermanent;
private static final ImmutableList<String> allCoreTypeNames = EnumUtil.getNames(CoreType.class); private static final ImmutableList<String> allCoreTypeNames = EnumUtil.getNames(CoreType.class);
private CoreType(final boolean permanent) { CoreType(final boolean permanent) {
isPermanent = permanent; isPermanent = permanent;
} }
} }

View File

@@ -5,5 +5,5 @@ package forge.card;
* *
*/ */
public interface ICardFace extends ICardCharacteristics, ICardRawAbilites, Comparable<ICardFace> { public interface ICardFace extends ICardCharacteristics, ICardRawAbilites, Comparable<ICardFace> {
public String getAltName(); String getAltName();
} }

View File

@@ -168,7 +168,7 @@ public final class MagicColor {
private final String name, symbol; private final String name, symbol;
private final byte colormask; private final byte colormask;
private Color(String name0, byte colormask0, String symbol0) { Color(String name0, byte colormask0, String symbol0) {
name = name0; name = name0;
colormask = colormask0; colormask = colormask0;
symbol = symbol0; symbol = symbol0;

View File

@@ -44,7 +44,7 @@ public abstract class ManaAtom {
if (s.length() == 2) { //if name is two characters, check for combination of two colors if (s.length() == 2) { //if name is two characters, check for combination of two colors
return (byte)(fromName(s.charAt(0)) | fromName(s.charAt(1))); return (byte)(fromName(s.charAt(0)) | fromName(s.charAt(1)));
} else if (s.length() == 1) { } else if (s.length() == 1) {
return (byte) fromName(s.charAt(0)); return fromName(s.charAt(0));
} }
s = s.toLowerCase(); s = s.toLowerCase();

View File

@@ -69,7 +69,7 @@ public final class ManaCost implements Comparable<ManaCost>, Iterable<ManaCostSh
private ManaCost(int cmc) { private ManaCost(int cmc) {
this.hasNoCost = cmc < 0; this.hasNoCost = cmc < 0;
this.genericCost = cmc < 0 ? 0 : cmc; this.genericCost = cmc < 0 ? 0 : cmc;
sealClass(Lists.<ManaCostShard>newArrayList()); sealClass(Lists.newArrayList());
} }
private ManaCost(int cmc, List<ManaCostShard> shards0) { private ManaCost(int cmc, List<ManaCostShard> shards0) {

View File

@@ -86,7 +86,7 @@ public enum ManaCostShard {
* @param sValue * @param sValue
* the s value * the s value
*/ */
private ManaCostShard(final int value, final String sValue) { ManaCostShard(final int value, final String sValue) {
this(value, sValue, sValue); this(value, sValue, sValue);
} }
@@ -100,7 +100,7 @@ public enum ManaCostShard {
* @param imgKey * @param imgKey
* the img key * the img key
*/ */
private ManaCostShard(final int value, final String sValue, final String imgKey) { ManaCostShard(final int value, final String sValue, final String imgKey) {
this.shard = value; this.shard = value;
this.cmc = this.getCMC(); this.cmc = this.getCMC();
this.cmpc = this.getCmpCost(); this.cmpc = this.getCmpCost();

View File

@@ -85,10 +85,7 @@ public enum DeckFormat {
if (otherPart != null && otherPart.getManaCost().getCMC() > 3) { if (otherPart != null && otherPart.getManaCost().getCMC() > 3) {
return false; //only cards with CMC less than 3 are allowed return false; //only cards with CMC less than 3 are allowed
} }
if (bannedCards.contains(rules.getName())) { return !bannedCards.contains(rules.getName());
return false;
}
return true;
} }
}) { }) {
private final Set<String> bannedCommanders = ImmutableSet.of("Derevi, Empyrial Tactician", "Erayo, Soratami Ascendant", "Rofellos, Llanowar Emissary"); private final Set<String> bannedCommanders = ImmutableSet.of("Derevi, Empyrial Tactician", "Erayo, Soratami Ascendant", "Rofellos, Llanowar Emissary");
@@ -120,7 +117,7 @@ public enum DeckFormat {
private final static String ADVPROCLAMATION = "Advantageous Proclamation"; private final static String ADVPROCLAMATION = "Advantageous Proclamation";
private final static String SOVREALM = "Sovereign's Realm"; private final static String SOVREALM = "Sovereign's Realm";
private DeckFormat(Range<Integer> mainRange0, Range<Integer> sideRange0, int maxCardCopies0, Predicate<CardRules> cardPoolFilter0, Predicate<PaperCard> paperCardPoolFilter0) { DeckFormat(Range<Integer> mainRange0, Range<Integer> sideRange0, int maxCardCopies0, Predicate<CardRules> cardPoolFilter0, Predicate<PaperCard> paperCardPoolFilter0) {
mainRange = mainRange0; mainRange = mainRange0;
sideRange = sideRange0; sideRange = sideRange0;
maxCardCopies = maxCardCopies0; maxCardCopies = maxCardCopies0;
@@ -128,7 +125,7 @@ public enum DeckFormat {
paperCardPoolFilter = paperCardPoolFilter0; paperCardPoolFilter = paperCardPoolFilter0;
} }
private DeckFormat(Range<Integer> mainRange0, Range<Integer> sideRange0, int maxCardCopies0, Predicate<CardRules> cardPoolFilter0) { DeckFormat(Range<Integer> mainRange0, Range<Integer> sideRange0, int maxCardCopies0, Predicate<CardRules> cardPoolFilter0) {
mainRange = mainRange0; mainRange = mainRange0;
sideRange = sideRange0; sideRange = sideRange0;
maxCardCopies = maxCardCopies0; maxCardCopies = maxCardCopies0;
@@ -136,7 +133,7 @@ public enum DeckFormat {
cardPoolFilter = cardPoolFilter0; cardPoolFilter = cardPoolFilter0;
} }
private DeckFormat(Range<Integer> mainRange0, Range<Integer> sideRange0, int maxCardCopies0) { DeckFormat(Range<Integer> mainRange0, Range<Integer> sideRange0, int maxCardCopies0) {
mainRange = mainRange0; mainRange = mainRange0;
sideRange = sideRange0; sideRange = sideRange0;
maxCardCopies = maxCardCopies0; maxCardCopies = maxCardCopies0;

View File

@@ -10,7 +10,7 @@ public enum DeckSection {
Conspiracy(0); Conspiracy(0);
private final int typicalSize; // Rules enforcement is done in DeckFormat class, this is for reference only private final int typicalSize; // Rules enforcement is done in DeckFormat class, this is for reference only
private DeckSection(int commonSize) { DeckSection(int commonSize) {
typicalSize = commonSize; typicalSize = commonSize;
} }

View File

@@ -142,7 +142,7 @@ public abstract class DeckGeneratorBase {
if(basicLandEdition == null){ if(basicLandEdition == null){
if(setBasicLandPool(cp.getEdition())){ if(setBasicLandPool(cp.getEdition())){
basicLandEdition = cp.getEdition(); basicLandEdition = cp.getEdition();
}; }
} }
cardCounts.put(cp.getName(), newCount); cardCounts.put(cp.getName(), newCount);
trace.append(String.format("(%d) %s [%s]%n", cp.getRules().getManaCost().getCMC(), cp.getName(), cp.getRules().getManaCost())); trace.append(String.format("(%d) %s [%s]%n", cp.getRules().getManaCost().getCMC(), cp.getName(), cp.getRules().getManaCost()));

View File

@@ -238,13 +238,11 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
// Return true if card is one of the five basic lands that can be added for free // Return true if card is one of the five basic lands that can be added for free
public boolean isVeryBasicLand() { public boolean isVeryBasicLand() {
if ((this.getName().equals("Swamp")) return (this.getName().equals("Swamp"))
|| (this.getName().equals("Plains")) || (this.getName().equals("Plains"))
|| (this.getName().equals("Island")) || (this.getName().equals("Island"))
|| (this.getName().equals("Forest")) || (this.getName().equals("Forest"))
|| (this.getName().equals("Mountain"))) { || (this.getName().equals("Mountain"));
return true;
} else return false;
} }
} }

View File

@@ -36,6 +36,7 @@ import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory; import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec; import javax.crypto.spec.PBEParameterSpec;
import java.nio.charset.StandardCharsets;
/** /**
* A Base64 encoder/decoder. * A Base64 encoder/decoder.
@@ -377,7 +378,7 @@ public final class Base64Coder {
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD)); SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES"); Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20)); pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
return String.valueOf(encode(pbeCipher.doFinal(value.getBytes("UTF-8")))); return String.valueOf(encode(pbeCipher.doFinal(value.getBytes(StandardCharsets.UTF_8))));
} }
public static String decrypt(String value) throws Exception { public static String decrypt(String value) throws Exception {
@@ -385,7 +386,7 @@ public final class Base64Coder {
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD)); SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES"); Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(SALT, 20)); pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
return new String(pbeCipher.doFinal(decode(value)), "UTF-8"); return new String(pbeCipher.doFinal(decode(value)), StandardCharsets.UTF_8);
} }
// Dummy constructor. // Dummy constructor.

Some files were not shown because too many files have changed in this diff Show More