Guava migration - Explode Predicate "Presets" subclasses

This commit is contained in:
Jetz
2024-09-06 18:10:24 -04:00
parent 0bf04c2fc8
commit 85f80bb5f1
117 changed files with 751 additions and 950 deletions

View File

@@ -611,9 +611,9 @@ public class AiAttackController {
// TODO: the AI should ideally predict how many times it can activate // TODO: the AI should ideally predict how many times it can activate
// for now, unless the opponent is tapped out, break at this point // for now, unless the opponent is tapped out, break at this point
// and do not predict the blocker limit (which is safer) // and do not predict the blocker limit (which is safer)
if (Iterables.any(defendingOpponent.getLandsInPlay(), CardPredicates.Presets.UNTAPPED)) { if (Iterables.any(defendingOpponent.getLandsInPlay(), CardPredicates.UNTAPPED)) {
maxBlockersAfterCrew += CardLists.count(CardLists.getNotType(defendingOpponent.getCardsIn(ZoneType.Battlefield), "Creature"), maxBlockersAfterCrew += CardLists.count(CardLists.getNotType(defendingOpponent.getCardsIn(ZoneType.Battlefield), "Creature"),
CardPredicates.isType("Vehicle").and(CardPredicates.Presets.UNTAPPED)); CardPredicates.isType("Vehicle").and(CardPredicates.UNTAPPED));
} }
} }

View File

@@ -1343,7 +1343,7 @@ public class AiBlockController {
boolean creatureParityOrAllowedDiff = aiCreatureCount boolean creatureParityOrAllowedDiff = aiCreatureCount
+ (randomTradeIfBehindOnBoard ? maxCreatDiff : 0) >= oppCreatureCount; + (randomTradeIfBehindOnBoard ? maxCreatDiff : 0) >= oppCreatureCount;
boolean wantToTradeWithCreatInHand = !checkingOther && randomTradeIfCreatInHand boolean wantToTradeWithCreatInHand = !checkingOther && randomTradeIfCreatInHand
&& ai.getZone(ZoneType.Hand).contains(CardPredicates.Presets.CREATURES) && ai.getZone(ZoneType.Hand).contains(CardPredicates.CREATURES)
&& aiCreatureCount + maxCreatDiffWithRepl >= oppCreatureCount; && aiCreatureCount + maxCreatDiffWithRepl >= oppCreatureCount;
boolean wantToSavePlaneswalker = MyRandom.percentTrue(chanceToSavePW) boolean wantToSavePlaneswalker = MyRandom.percentTrue(chanceToSavePW)
&& combat.getDefenderByAttacker(attacker) instanceof Card && combat.getDefenderByAttacker(attacker) instanceof Card

View File

@@ -34,7 +34,6 @@ import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.ability.SpellApiBased; import forge.game.ability.SpellApiBased;
import forge.game.card.*; import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.combat.Combat; import forge.game.combat.Combat;
import forge.game.combat.CombatUtil; import forge.game.combat.CombatUtil;
import forge.game.cost.*; import forge.game.cost.*;
@@ -404,10 +403,10 @@ public class AiController {
private CardCollection filterLandsToPlay(CardCollection landList) { private CardCollection filterLandsToPlay(CardCollection landList) {
final CardCollectionView hand = player.getCardsIn(ZoneType.Hand); final CardCollectionView hand = player.getCardsIn(ZoneType.Hand);
CardCollection nonLandList = CardLists.filter(hand, Presets.NON_LANDS); CardCollection nonLandList = CardLists.filter(hand, CardPredicates.NON_LANDS);
if (landList.size() == 1 && nonLandList.size() < 3) { if (landList.size() == 1 && nonLandList.size() < 3) {
CardCollectionView cardsInPlay = player.getCardsIn(ZoneType.Battlefield); CardCollectionView cardsInPlay = player.getCardsIn(ZoneType.Battlefield);
CardCollection landsInPlay = CardLists.filter(cardsInPlay, Presets.LANDS); CardCollection landsInPlay = CardLists.filter(cardsInPlay, CardPredicates.LANDS);
CardCollection allCards = new CardCollection(player.getCardsIn(ZoneType.Graveyard)); CardCollection allCards = new CardCollection(player.getCardsIn(ZoneType.Graveyard));
allCards.addAll(player.getCardsIn(ZoneType.Command)); allCards.addAll(player.getCardsIn(ZoneType.Command));
allCards.addAll(cardsInPlay); allCards.addAll(cardsInPlay);
@@ -445,7 +444,7 @@ public class AiController {
final CardCollectionView hand1 = player.getCardsIn(ZoneType.Hand); final CardCollectionView hand1 = player.getCardsIn(ZoneType.Hand);
CardCollection lands = new CardCollection(battlefield); CardCollection lands = new CardCollection(battlefield);
lands.addAll(hand1); lands.addAll(hand1);
lands = CardLists.filter(lands, Presets.LANDS); lands = CardLists.filter(lands, CardPredicates.LANDS);
int maxCmcInHand = Aggregates.max(hand1, Card::getCMC); int maxCmcInHand = Aggregates.max(hand1, Card::getCMC);
if (lands.size() >= Math.max(maxCmcInHand, 6)) { if (lands.size() >= Math.max(maxCmcInHand, 6)) {
@@ -469,7 +468,7 @@ public class AiController {
return null; return null;
} }
CardCollection nonLandsInHand = CardLists.filter(player.getCardsIn(ZoneType.Hand), Presets.NON_LANDS); CardCollection nonLandsInHand = CardLists.filter(player.getCardsIn(ZoneType.Hand), CardPredicates.NON_LANDS);
// Some considerations for Momir/MoJhoSto // Some considerations for Momir/MoJhoSto
boolean hasMomir = player.isCardInCommand("Momir Vig, Simic Visionary Avatar"); boolean hasMomir = player.isCardInCommand("Momir Vig, Simic Visionary Avatar");
@@ -598,8 +597,8 @@ public class AiController {
} }
// pick dual lands if available // pick dual lands if available
if (Iterables.any(landList, Presets.NONBASIC_LANDS)) { if (Iterables.any(landList, CardPredicates.NONBASIC_LANDS)) {
landList = CardLists.filter(landList, Presets.NONBASIC_LANDS); landList = CardLists.filter(landList, CardPredicates.NONBASIC_LANDS);
} }
} }
return ComputerUtilCard.getBestLandToPlayAI(landList); return ComputerUtilCard.getBestLandToPlayAI(landList);
@@ -1061,7 +1060,7 @@ public class AiController {
if ("DiscardUncastableAndExcess".equals(sa.getParam("AILogic"))) { if ("DiscardUncastableAndExcess".equals(sa.getParam("AILogic"))) {
CardCollection discards = new CardCollection(); CardCollection discards = new CardCollection();
final CardCollectionView inHand = player.getCardsIn(ZoneType.Hand); final CardCollectionView inHand = player.getCardsIn(ZoneType.Hand);
final int numLandsOTB = CardLists.count(inHand, CardPredicates.Presets.LANDS); final int numLandsOTB = CardLists.count(inHand, CardPredicates.LANDS);
int numOppInHand = 0; int numOppInHand = 0;
for (Player p : player.getGame().getPlayers()) { for (Player p : player.getGame().getPlayers()) {
if (p.getCardsIn(ZoneType.Hand).size() > numOppInHand) { if (p.getCardsIn(ZoneType.Hand).size() > numOppInHand) {
@@ -1119,8 +1118,8 @@ public class AiController {
if (validCards.isEmpty()) { if (validCards.isEmpty()) {
continue; continue;
} }
final int numLandsInPlay = CardLists.count(player.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.LANDS_PRODUCING_MANA); final int numLandsInPlay = CardLists.count(player.getCardsIn(ZoneType.Battlefield), CardPredicates.LANDS_PRODUCING_MANA);
final CardCollection landsInHand = CardLists.filter(validCards, CardPredicates.Presets.LANDS); final CardCollection landsInHand = CardLists.filter(validCards, CardPredicates.LANDS);
final int numLandsInHand = landsInHand.size(); final int numLandsInHand = landsInHand.size();
// Discard a land // Discard a land
@@ -1397,11 +1396,11 @@ public class AiController {
return false; return false;
} }
CardCollection inHand = CardLists.filter(player.getCardsIn(ZoneType.Hand), Presets.NON_LANDS); CardCollection inHand = CardLists.filter(player.getCardsIn(ZoneType.Hand), CardPredicates.NON_LANDS);
CardCollectionView otb = player.getCardsIn(ZoneType.Battlefield); CardCollectionView otb = player.getCardsIn(ZoneType.Battlefield);
if (getBooleanProperty(AiProps.HOLD_LAND_DROP_ONLY_IF_HAVE_OTHER_PERMS)) { if (getBooleanProperty(AiProps.HOLD_LAND_DROP_ONLY_IF_HAVE_OTHER_PERMS)) {
if (!Iterables.any(otb, Presets.NON_LANDS)) { if (!Iterables.any(otb, CardPredicates.NON_LANDS)) {
return false; return false;
} }
} }
@@ -1578,7 +1577,7 @@ public class AiController {
if (sa.getHostCard().hasKeyword(Keyword.STORM) if (sa.getHostCard().hasKeyword(Keyword.STORM)
&& sa.getApi() != ApiType.Counter // AI would suck at trying to deliberately proc a Storm counterspell && sa.getApi() != ApiType.Counter // AI would suck at trying to deliberately proc a Storm counterspell
&& player.getZone(ZoneType.Hand).contains( && player.getZone(ZoneType.Hand).contains(
Presets.LANDS.or(CardPredicates.hasKeyword("Storm")).negate())) { CardPredicates.LANDS.or(CardPredicates.hasKeyword("Storm")).negate())) {
if (game.getView().getStormCount() < this.getIntProperty(AiProps.MIN_COUNT_FOR_STORM_SPELLS)) { if (game.getView().getStormCount() < this.getIntProperty(AiProps.MIN_COUNT_FOR_STORM_SPELLS)) {
// skip evaluating Storm unless we reached the minimum Storm count // skip evaluating Storm unless we reached the minimum Storm count
continue; continue;
@@ -1601,7 +1600,7 @@ public class AiController {
} else if (sa.getHostCard().hasKeyword(Keyword.CASCADE)) { } else if (sa.getHostCard().hasKeyword(Keyword.CASCADE)) {
if (isLifeInDanger) { //needs more tune up for certain conditions if (isLifeInDanger) { //needs more tune up for certain conditions
aiPlayDecision = player.getCreaturesInPlay().size() >= 4 ? AiPlayDecision.CantPlaySa : AiPlayDecision.WillPlay; aiPlayDecision = player.getCreaturesInPlay().size() >= 4 ? AiPlayDecision.CantPlaySa : AiPlayDecision.WillPlay;
} else if (CardLists.filter(player.getZone(ZoneType.Graveyard).getCards(), CardPredicates.Presets.CREATURES).size() > 4) { } else if (CardLists.filter(player.getZone(ZoneType.Graveyard).getCards(), CardPredicates.CREATURES).size() > 4) {
if (player.getCreaturesInPlay().size() >= 4) // it's good minimum if (player.getCreaturesInPlay().size() >= 4) // it's good minimum
continue; continue;
else if (!sa.getHostCard().isPermanent() && sa.canCastTiming(player) && ComputerUtilCost.canPayCost(sa, player, sa.isTrigger())) else if (!sa.getHostCard().isPermanent() && sa.canCastTiming(player) && ComputerUtilCost.canPayCost(sa, player, sa.isTrigger()))
@@ -1971,7 +1970,7 @@ public class AiController {
break; break;
} }
} else { } else {
CardCollectionView viableOptions = CardLists.filter(pool, CardPredicates.isControlledByAnyOf(sa.getActivatingPlayer().getOpponents()), CardPredicates.Presets.CAN_BE_DESTROYED); CardCollectionView viableOptions = CardLists.filter(pool, CardPredicates.isControlledByAnyOf(sa.getActivatingPlayer().getOpponents()), CardPredicates.CAN_BE_DESTROYED);
Card best = ComputerUtilCard.getBestAI(viableOptions); Card best = ComputerUtilCard.getBestAI(viableOptions);
if (best != null) { if (best != null) {
result.add(best); result.add(best);
@@ -2047,7 +2046,7 @@ public class AiController {
CardLists.shuffle(library); CardLists.shuffle(library);
// remove all land, keep non-basicland in there, shuffled // remove all land, keep non-basicland in there, shuffled
CardCollection land = CardLists.filter(library, CardPredicates.Presets.LANDS); CardCollection land = CardLists.filter(library, CardPredicates.LANDS);
for (Card c : land) { for (Card c : land) {
if (c.isLand()) { if (c.isLand()) {
library.remove(c); library.remove(c);
@@ -2097,7 +2096,7 @@ public class AiController {
} }
} }
if ("Aminatou".equals(sa.getParam("AILogic")) && game.getPlayers().size() > 2) { if ("Aminatou".equals(sa.getParam("AILogic")) && game.getPlayers().size() > 2) {
CardCollection all = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.NONLAND_PERMANENTS); CardCollection all = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), CardPredicates.NONLAND_PERMANENTS);
CardCollection left = CardLists.filterControlledBy(all, game.getNextPlayerAfter(player, Direction.Left)); CardCollection left = CardLists.filterControlledBy(all, game.getNextPlayerAfter(player, Direction.Left));
CardCollection right = CardLists.filterControlledBy(all, game.getNextPlayerAfter(player, Direction.Right)); CardCollection right = CardLists.filterControlledBy(all, game.getNextPlayerAfter(player, Direction.Right));
return Aggregates.sum(left, Card::getCMC) > Aggregates.sum(right, Card::getCMC); return Aggregates.sum(left, Card::getCMC) > Aggregates.sum(right, Card::getCMC);

View File

@@ -48,7 +48,6 @@ import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.ability.effects.CharmEffect; import forge.game.ability.effects.CharmEffect;
import forge.game.card.CardPredicates.Presets;
import forge.game.combat.Combat; import forge.game.combat.Combat;
import forge.game.combat.CombatUtil; import forge.game.combat.CombatUtil;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
@@ -528,7 +527,7 @@ public class ComputerUtil {
// Discard lands // Discard lands
final CardCollection landsInHand = CardLists.getType(typeList, "Land"); final CardCollection landsInHand = CardLists.getType(typeList, "Land");
if (!landsInHand.isEmpty()) { if (!landsInHand.isEmpty()) {
final int numLandsInPlay = CardLists.count(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.LANDS_PRODUCING_MANA); final int numLandsInPlay = CardLists.count(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.LANDS_PRODUCING_MANA);
final CardCollection nonLandsInHand = CardLists.getNotType(ai.getCardsIn(ZoneType.Hand), "Land"); final CardCollection nonLandsInHand = CardLists.getNotType(ai.getCardsIn(ZoneType.Hand), "Land");
final int highestCMC = Math.max(6, Aggregates.max(nonLandsInHand, Card::getCMC)); final int highestCMC = Math.max(6, Aggregates.max(nonLandsInHand, Card::getCMC));
if (numLandsInPlay >= highestCMC if (numLandsInPlay >= highestCMC
@@ -769,7 +768,7 @@ public class ComputerUtil {
all.removeAll(exclude); all.removeAll(exclude);
CardCollection typeList = CardLists.getValidCards(all, type.split(";"), activate.getController(), activate, sa); CardCollection typeList = CardLists.getValidCards(all, type.split(";"), activate.getController(), activate, sa);
typeList = CardLists.filter(typeList, Presets.CAN_TAP); typeList = CardLists.filter(typeList, CardPredicates.CAN_TAP);
if (tap) { if (tap) {
typeList.remove(activate); typeList.remove(activate);
@@ -799,7 +798,7 @@ public class ComputerUtil {
all.removeAll(exclude); all.removeAll(exclude);
CardCollection typeList = CardLists.getValidCards(all, type.split(";"), activate.getController(), activate, sa); CardCollection typeList = CardLists.getValidCards(all, type.split(";"), activate.getController(), activate, sa);
typeList = CardLists.filter(typeList, sa.isCrew() ? Presets.CAN_CREW : Presets.CAN_TAP); typeList = CardLists.filter(typeList, sa.isCrew() ? CardPredicates.CAN_CREW : CardPredicates.CAN_TAP);
if (tap) { if (tap) {
typeList.remove(activate); typeList.remove(activate);
@@ -837,7 +836,7 @@ public class ComputerUtil {
CardCollection typeList = CardCollection typeList =
CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, sa); CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, sa);
typeList = CardLists.filter(typeList, Presets.TAPPED); typeList = CardLists.filter(typeList, CardPredicates.TAPPED);
if (untap) { if (untap) {
typeList.remove(activate); typeList.remove(activate);
@@ -1035,7 +1034,7 @@ public class ComputerUtil {
c = ComputerUtilCard.getWorstCreatureAI(remaining); c = ComputerUtilCard.getWorstCreatureAI(remaining);
} }
else if (CardLists.getNotType(remaining, "Land").isEmpty()) { else if (CardLists.getNotType(remaining, "Land").isEmpty()) {
c = ComputerUtilCard.getWorstLand(CardLists.filter(remaining, CardPredicates.Presets.LANDS)); c = ComputerUtilCard.getWorstLand(CardLists.filter(remaining, CardPredicates.LANDS));
} }
else { else {
c = ComputerUtilCard.getWorstPermanentAI(remaining, false, false, false, false); c = ComputerUtilCard.getWorstPermanentAI(remaining, false, false, false, false);
@@ -1344,8 +1343,8 @@ public class ComputerUtil {
} }
final Game game = ai.getGame(); final Game game = ai.getGame();
final CardCollection landsInPlay = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.LANDS_PRODUCING_MANA); final CardCollection landsInPlay = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.LANDS_PRODUCING_MANA);
final CardCollection landsInHand = CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.Presets.LANDS); final CardCollection landsInHand = CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.LANDS);
final CardCollection nonLandsInHand = CardLists.getNotType(ai.getCardsIn(ZoneType.Hand), "Land"); final CardCollection nonLandsInHand = CardLists.getNotType(ai.getCardsIn(ZoneType.Hand), "Land");
final int highestCMC = Math.max(6, Aggregates.max(nonLandsInHand, Card::getCMC)); final int highestCMC = Math.max(6, Aggregates.max(nonLandsInHand, Card::getCMC));
final int discardCMC = discard.getCMC(); final int discardCMC = discard.getCMC();
@@ -1664,7 +1663,7 @@ public class ComputerUtil {
int damage = 0; int damage = 0;
final CardCollection all = new CardCollection(ai.getCardsIn(ZoneType.Battlefield)); final CardCollection all = new CardCollection(ai.getCardsIn(ZoneType.Battlefield));
all.addAll(ai.getCardsActivatableInExternalZones(true)); all.addAll(ai.getCardsActivatableInExternalZones(true));
all.addAll(CardLists.filter(ai.getCardsIn(ZoneType.Hand), Presets.PERMANENTS.negate())); all.addAll(CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.PERMANENTS.negate()));
for (final Card c : all) { for (final Card c : all) {
if (c.getZone().getPlayer() != null && c.getZone().getPlayer() != ai && c.mayPlay(ai).isEmpty()) { if (c.getZone().getPlayer() != null && c.getZone().getPlayer() != ai && c.mayPlay(ai).isEmpty()) {
@@ -2218,7 +2217,7 @@ public class ComputerUtil {
} }
CardCollectionView library = ai.getCardsIn(ZoneType.Library); CardCollectionView library = ai.getCardsIn(ZoneType.Library);
int landsInDeck = CardLists.count(library, Presets.LANDS); int landsInDeck = CardLists.count(library, CardPredicates.LANDS);
// no land deck, can't do anything better // no land deck, can't do anything better
if (landsInDeck == 0) { if (landsInDeck == 0) {
@@ -2363,14 +2362,14 @@ public class ComputerUtil {
CardCollectionView cardsInHand = player.getCardsIn(ZoneType.Hand); CardCollectionView cardsInHand = player.getCardsIn(ZoneType.Hand);
CardCollectionView cardsOTB = player.getCardsIn(ZoneType.Battlefield); CardCollectionView cardsOTB = player.getCardsIn(ZoneType.Battlefield);
CardCollection landsOTB = CardLists.filter(cardsOTB, CardPredicates.Presets.LANDS_PRODUCING_MANA); CardCollection landsOTB = CardLists.filter(cardsOTB, CardPredicates.LANDS_PRODUCING_MANA);
CardCollection thisLandOTB = CardLists.filter(cardsOTB, CardPredicates.nameEquals(c.getName())); CardCollection thisLandOTB = CardLists.filter(cardsOTB, CardPredicates.nameEquals(c.getName()));
CardCollection landsInHand = CardLists.filter(cardsInHand, CardPredicates.Presets.LANDS_PRODUCING_MANA); CardCollection landsInHand = CardLists.filter(cardsInHand, CardPredicates.LANDS_PRODUCING_MANA);
// valuable mana-producing artifacts that may be equated to a land // valuable mana-producing artifacts that may be equated to a land
List<String> manaArts = Arrays.asList("Mox Pearl", "Mox Sapphire", "Mox Jet", "Mox Ruby", "Mox Emerald"); List<String> manaArts = Arrays.asList("Mox Pearl", "Mox Sapphire", "Mox Jet", "Mox Ruby", "Mox Emerald");
// evaluate creatures available in deck // evaluate creatures available in deck
CardCollectionView allCreatures = CardLists.filter(allCards, CardPredicates.Presets.CREATURES, CardPredicates.isOwner(player)); CardCollectionView allCreatures = CardLists.filter(allCards, CardPredicates.CREATURES, CardPredicates.isOwner(player));
int numCards = allCreatures.size(); int numCards = allCreatures.size();
if (landsOTB.size() < maxLandsToScryLandsToTop && landsInHand.isEmpty()) { if (landsOTB.size() < maxLandsToScryLandsToTop && landsInHand.isEmpty()) {
@@ -2399,7 +2398,7 @@ public class ComputerUtil {
} }
} }
} else if (c.isCreature()) { } else if (c.isCreature()) {
CardCollection creaturesOTB = CardLists.filter(cardsOTB, CardPredicates.Presets.CREATURES); CardCollection creaturesOTB = CardLists.filter(cardsOTB, CardPredicates.CREATURES);
int avgCreatureValue = numCards != 0 ? ComputerUtilCard.evaluateCreatureList(allCreatures) / numCards : 0; int avgCreatureValue = numCards != 0 ? ComputerUtilCard.evaluateCreatureList(allCreatures) / numCards : 0;
int maxControlledCMC = Aggregates.max(creaturesOTB, Card::getCMC); int maxControlledCMC = Aggregates.max(creaturesOTB, Card::getCMC);
@@ -2490,7 +2489,7 @@ public class ComputerUtil {
double amount = 0; double amount = 0;
for (String type : CardType.getAllCardTypes()) { for (String type : CardType.getAllCardTypes()) {
if (!invalidTypes.contains(type)) { if (!invalidTypes.contains(type)) {
CardCollection list = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.isType(type), Presets.TAPPED); CardCollection list = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.isType(type), CardPredicates.TAPPED);
double i = type.equals("Creature") ? list.size() * 1.5 : list.size(); double i = type.equals("Creature") ? list.size() * 1.5 : list.size();
if (i > amount) { if (i > amount) {
amount = i; amount = i;
@@ -2801,7 +2800,7 @@ public class ComputerUtil {
} }
// has cards with SacMe or Token // has cards with SacMe or Token
if (CardLists.count(aiCreatures, CardPredicates.hasSVar("SacMe").or(Presets.TOKEN)) >= numDeath) { if (CardLists.count(aiCreatures, CardPredicates.hasSVar("SacMe").or(CardPredicates.TOKEN)) >= numDeath) {
return "Death"; return "Death";
} }

View File

@@ -81,7 +81,7 @@ public class ComputerUtilCard {
* @return a {@link forge.game.card.Card} object. * @return a {@link forge.game.card.Card} object.
*/ */
public static Card getBestArtifactAI(final List<Card> list) { public static Card getBestArtifactAI(final List<Card> list) {
List<Card> all = CardLists.filter(list, CardPredicates.Presets.ARTIFACTS); List<Card> all = CardLists.filter(list, CardPredicates.ARTIFACTS);
if (all.size() == 0) { if (all.size() == 0) {
return null; return null;
} }
@@ -96,7 +96,7 @@ public class ComputerUtilCard {
* @return best Planeswalker * @return best Planeswalker
*/ */
public static Card getBestPlaneswalkerAI(final List<Card> list) { public static Card getBestPlaneswalkerAI(final List<Card> list) {
List<Card> all = CardLists.filter(list, CardPredicates.Presets.PLANESWALKERS); List<Card> all = CardLists.filter(list, CardPredicates.PLANESWALKERS);
if (all.isEmpty()) { if (all.isEmpty()) {
return null; return null;
} }
@@ -111,7 +111,7 @@ public class ComputerUtilCard {
* @return best Planeswalker * @return best Planeswalker
*/ */
public static Card getWorstPlaneswalkerAI(final List<Card> list) { public static Card getWorstPlaneswalkerAI(final List<Card> list) {
List<Card> all = CardLists.filter(list, CardPredicates.Presets.PLANESWALKERS); List<Card> all = CardLists.filter(list, CardPredicates.PLANESWALKERS);
if (all.isEmpty()) { if (all.isEmpty()) {
return null; return null;
} }
@@ -182,7 +182,7 @@ public class ComputerUtilCard {
* @return a {@link forge.game.card.Card} object. * @return a {@link forge.game.card.Card} object.
*/ */
public static Card getBestEnchantmentAI(final List<Card> list, final SpellAbility spell, final boolean targeted) { public static Card getBestEnchantmentAI(final List<Card> list, final SpellAbility spell, final boolean targeted) {
List<Card> all = CardLists.filter(list, CardPredicates.Presets.ENCHANTMENTS); List<Card> all = CardLists.filter(list, CardPredicates.ENCHANTMENTS);
if (targeted) { if (targeted) {
all = CardLists.filter(all, c -> c.canBeTargetedBy(spell)); all = CardLists.filter(all, c -> c.canBeTargetedBy(spell));
} }
@@ -200,13 +200,13 @@ public class ComputerUtilCard {
* @return a {@link forge.game.card.Card} object. * @return a {@link forge.game.card.Card} object.
*/ */
public static Card getBestLandAI(final Iterable<Card> list) { public static Card getBestLandAI(final Iterable<Card> list) {
final List<Card> land = CardLists.filter(list, CardPredicates.Presets.LANDS); final List<Card> land = CardLists.filter(list, CardPredicates.LANDS);
if (land.isEmpty()) { if (land.isEmpty()) {
return null; return null;
} }
// prefer to target non basic lands // prefer to target non basic lands
final List<Card> nbLand = CardLists.filter(land, CardPredicates.Presets.NONBASIC_LANDS); final List<Card> nbLand = CardLists.filter(land, CardPredicates.NONBASIC_LANDS);
if (!nbLand.isEmpty()) { if (!nbLand.isEmpty()) {
// TODO - Improve ranking various non-basic lands depending on context // TODO - Improve ranking various non-basic lands depending on context
@@ -245,12 +245,12 @@ public class ComputerUtilCard {
} }
if (iminBL == Integer.MAX_VALUE) { if (iminBL == Integer.MAX_VALUE) {
// All basic lands have no basic land type. Just return something // All basic lands have no basic land type. Just return something
return Iterables.find(land, CardPredicates.Presets.UNTAPPED, land.get(0)); return Iterables.find(land, CardPredicates.UNTAPPED, land.get(0));
} }
final List<Card> bLand = CardLists.getType(land, sminBL); final List<Card> bLand = CardLists.getType(land, sminBL);
for (Card ut : Iterables.filter(bLand, CardPredicates.Presets.UNTAPPED)) { for (Card ut : Iterables.filter(bLand, CardPredicates.UNTAPPED)) {
return ut; return ut;
} }
@@ -357,10 +357,10 @@ public class ComputerUtilCard {
*/ */
public static Card getBestAI(final Iterable<Card> list) { public static Card getBestAI(final Iterable<Card> list) {
// Get Best will filter by appropriate getBest list if ALL of the list is of that type // Get Best will filter by appropriate getBest list if ALL of the list is of that type
if (Iterables.all(list, CardPredicates.Presets.CREATURES)) { if (Iterables.all(list, CardPredicates.CREATURES)) {
return getBestCreatureAI(list); return getBestCreatureAI(list);
} }
if (Iterables.all(list, CardPredicates.Presets.LANDS)) { if (Iterables.all(list, CardPredicates.LANDS)) {
return getBestLandAI(list); return getBestLandAI(list);
} }
// TODO - Once we get an EvaluatePermanent this should call getBestPermanent() // TODO - Once we get an EvaluatePermanent this should call getBestPermanent()
@@ -377,7 +377,7 @@ public class ComputerUtilCard {
if (Iterables.size(list) == 1) { if (Iterables.size(list) == 1) {
return Iterables.get(list, 0); return Iterables.get(list, 0);
} }
return Aggregates.itemWithMax(Iterables.filter(list, CardPredicates.Presets.CREATURES), ComputerUtilCard.creatureEvaluator); return Aggregates.itemWithMax(Iterables.filter(list, CardPredicates.CREATURES), ComputerUtilCard.creatureEvaluator);
} }
/** /**
@@ -390,7 +390,7 @@ public class ComputerUtilCard {
if (Iterables.size(list) == 1) { if (Iterables.size(list) == 1) {
return Iterables.get(list, 0); return Iterables.get(list, 0);
} }
return Aggregates.itemWithMax(Iterables.filter(list, CardPredicates.Presets.LANDS), ComputerUtilCard.landEvaluator); return Aggregates.itemWithMax(Iterables.filter(list, CardPredicates.LANDS), ComputerUtilCard.landEvaluator);
} }
/** /**
@@ -405,7 +405,7 @@ public class ComputerUtilCard {
if (Iterables.size(list) == 1) { if (Iterables.size(list) == 1) {
return Iterables.get(list, 0); return Iterables.get(list, 0);
} }
return Aggregates.itemWithMin(Iterables.filter(list, CardPredicates.Presets.CREATURES), ComputerUtilCard.creatureEvaluator); return Aggregates.itemWithMin(Iterables.filter(list, CardPredicates.CREATURES), ComputerUtilCard.creatureEvaluator);
} }
// This selection rates tokens higher // This selection rates tokens higher
@@ -426,7 +426,7 @@ public class ComputerUtilCard {
Card biggest = null; Card biggest = null;
int biggestvalue = -1; int biggestvalue = -1;
for (Card card : CardLists.filter(list, CardPredicates.Presets.CREATURES)) { for (Card card : CardLists.filter(list, CardPredicates.CREATURES)) {
int newvalue = evaluateCreature(card); int newvalue = evaluateCreature(card);
newvalue += card.isToken() ? tokenBonus : 0; // raise the value of tokens newvalue += card.isToken() ? tokenBonus : 0; // raise the value of tokens
@@ -479,40 +479,40 @@ public class ComputerUtilCard {
return null; return null;
} }
final boolean hasEnchantmants = Iterables.any(list, CardPredicates.Presets.ENCHANTMENTS); final boolean hasEnchantmants = Iterables.any(list, CardPredicates.ENCHANTMENTS);
if (biasEnch && hasEnchantmants) { if (biasEnch && hasEnchantmants) {
return getCheapestPermanentAI(CardLists.filter(list, CardPredicates.Presets.ENCHANTMENTS), null, false); return getCheapestPermanentAI(CardLists.filter(list, CardPredicates.ENCHANTMENTS), null, false);
} }
final boolean hasArtifacts = Iterables.any(list, CardPredicates.Presets.ARTIFACTS); final boolean hasArtifacts = Iterables.any(list, CardPredicates.ARTIFACTS);
if (biasArt && hasArtifacts) { if (biasArt && hasArtifacts) {
return getCheapestPermanentAI(CardLists.filter(list, CardPredicates.Presets.ARTIFACTS), null, false); return getCheapestPermanentAI(CardLists.filter(list, CardPredicates.ARTIFACTS), null, false);
} }
if (biasLand && Iterables.any(list, CardPredicates.Presets.LANDS)) { if (biasLand && Iterables.any(list, CardPredicates.LANDS)) {
return getWorstLand(CardLists.filter(list, CardPredicates.Presets.LANDS)); return getWorstLand(CardLists.filter(list, CardPredicates.LANDS));
} }
final boolean hasCreatures = Iterables.any(list, CardPredicates.Presets.CREATURES); final boolean hasCreatures = Iterables.any(list, CardPredicates.CREATURES);
if (biasCreature && hasCreatures) { if (biasCreature && hasCreatures) {
return getWorstCreatureAI(CardLists.filter(list, CardPredicates.Presets.CREATURES)); return getWorstCreatureAI(CardLists.filter(list, CardPredicates.CREATURES));
} }
List<Card> lands = CardLists.filter(list, CardPredicates.Presets.LANDS); List<Card> lands = CardLists.filter(list, CardPredicates.LANDS);
if (lands.size() > 6) { if (lands.size() > 6) {
return getWorstLand(lands); return getWorstLand(lands);
} }
if (hasEnchantmants || hasArtifacts) { if (hasEnchantmants || hasArtifacts) {
final List<Card> ae = CardLists.filter(list, final List<Card> ae = CardLists.filter(list,
(CardPredicates.Presets.ARTIFACTS.or(CardPredicates.Presets.ENCHANTMENTS)) (CardPredicates.ARTIFACTS.or(CardPredicates.ENCHANTMENTS))
.and(card -> !card.hasSVar("DoNotDiscardIfAble")) .and(card -> !card.hasSVar("DoNotDiscardIfAble"))
); );
return getCheapestPermanentAI(ae, null, false); return getCheapestPermanentAI(ae, null, false);
} }
if (hasCreatures) { if (hasCreatures) {
return getWorstCreatureAI(CardLists.filter(list, CardPredicates.Presets.CREATURES)); return getWorstCreatureAI(CardLists.filter(list, CardPredicates.CREATURES));
} }
// Planeswalkers fall through to here, lands will fall through if there aren't very many // Planeswalkers fall through to here, lands will fall through if there aren't very many
@@ -521,7 +521,7 @@ public class ComputerUtilCard {
public static final Card getCheapestSpellAI(final Iterable<Card> list) { public static final Card getCheapestSpellAI(final Iterable<Card> list) {
if (!Iterables.isEmpty(list)) { if (!Iterables.isEmpty(list)) {
CardCollection cc = CardLists.filter(list, CardPredicates.Presets.INSTANTS_AND_SORCERIES); CardCollection cc = CardLists.filter(list, CardPredicates.INSTANTS_AND_SORCERIES);
if (cc.isEmpty()) { if (cc.isEmpty()) {
return null; return null;
@@ -1001,7 +1001,7 @@ public class ComputerUtilCard {
} else if (logic.equals("MostProminentHumanCreatures")) { } else if (logic.equals("MostProminentHumanCreatures")) {
CardCollectionView list = opp.getCreaturesInPlay(); CardCollectionView list = opp.getCreaturesInPlay();
if (list.isEmpty()) { if (list.isEmpty()) {
list = CardLists.filter(CardLists.filterControlledBy(game.getCardsInGame(), opp), CardPredicates.Presets.CREATURES); list = CardLists.filter(CardLists.filterControlledBy(game.getCardsInGame(), opp), CardPredicates.CREATURES);
} }
chosen.add(getMostProminentColor(list, colorChoices)); chosen.add(getMostProminentColor(list, colorChoices));
} else if (logic.equals("MostProminentComputerControls")) { } else if (logic.equals("MostProminentComputerControls")) {
@@ -1943,7 +1943,7 @@ public class ComputerUtilCard {
CardCollection aiCreats = ai.getCreaturesInPlay(); CardCollection aiCreats = ai.getCreaturesInPlay();
if (temporary) { if (temporary) {
// Pump effects that add "CARDNAME can't attack" and similar things. Only do it if something is untapped. // Pump effects that add "CARDNAME can't attack" and similar things. Only do it if something is untapped.
oppCards = CardLists.filter(oppCards, CardPredicates.Presets.UNTAPPED); oppCards = CardLists.filter(oppCards, CardPredicates.UNTAPPED);
} }
CardCollection priorityCards = new CardCollection(); CardCollection priorityCards = new CardCollection();

View File

@@ -10,7 +10,6 @@ import forge.game.Game;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.*; import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.combat.Combat; import forge.game.combat.Combat;
import forge.game.combat.CombatUtil; import forge.game.combat.CombatUtil;
import forge.game.cost.*; import forge.game.cost.*;
@@ -745,7 +744,7 @@ public class ComputerUtilCost {
// Special Card logic, this one try to median its power with the number of artifacts // Special Card logic, this one try to median its power with the number of artifacts
if ("Marionette Master".equals(source.getName())) { if ("Marionette Master".equals(source.getName())) {
CardCollection list = CardLists.filter(payer.getCardsIn(ZoneType.Battlefield), Presets.ARTIFACTS); CardCollection list = CardLists.filter(payer.getCardsIn(ZoneType.Battlefield), CardPredicates.ARTIFACTS);
return list.size() >= copy.getNetPower(); return list.size() >= copy.getNetPower();
} else if ("Cultivator of Blades".equals(source.getName())) { } else if ("Cultivator of Blades".equals(source.getName())) {
// Cultivator does try to median with number of Creatures // Cultivator does try to median with number of Creatures
@@ -832,7 +831,7 @@ public class ComputerUtilCost {
return getAvailableManaColors(ai, Lists.newArrayList(additionalLand)); return getAvailableManaColors(ai, Lists.newArrayList(additionalLand));
} }
public static Set<String> getAvailableManaColors(Player ai, List<Card> additionalLands) { public static Set<String> getAvailableManaColors(Player ai, List<Card> additionalLands) {
CardCollection cardsToConsider = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), Presets.UNTAPPED); CardCollection cardsToConsider = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.UNTAPPED);
Set<String> colorsAvailable = Sets.newHashSet(); Set<String> colorsAvailable = Sets.newHashSet();
if (additionalLands != null) { if (additionalLands != null) {

View File

@@ -313,7 +313,7 @@ public class ComputerUtilMana {
// For cards like Genju of the Cedars, make sure we're not attaching to the same land that will // For cards like Genju of the Cedars, make sure we're not attaching to the same land that will
// be tapped to pay its own cost if there's another untapped land like that available // be tapped to pay its own cost if there's another untapped land like that available
if (ma.getHostCard().equals(sa.getTargetCard())) { if (ma.getHostCard().equals(sa.getTargetCard())) {
if (CardLists.count(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.nameEquals(ma.getHostCard().getName()).and(CardPredicates.Presets.UNTAPPED)) > 1) { if (CardLists.count(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.nameEquals(ma.getHostCard().getName()).and(CardPredicates.UNTAPPED)) > 1) {
continue; continue;
} }
} }

View File

@@ -19,7 +19,6 @@ import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.ability.effects.CharmEffect; import forge.game.ability.effects.CharmEffect;
import forge.game.card.*; import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.combat.Combat; import forge.game.combat.Combat;
import forge.game.cost.Cost; import forge.game.cost.Cost;
import forge.game.cost.CostEnlist; import forge.game.cost.CostEnlist;
@@ -614,7 +613,7 @@ public class PlayerControllerAi extends PlayerController {
} }
} }
int landsOTB = CardLists.count(p.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.LANDS_PRODUCING_MANA); int landsOTB = CardLists.count(p.getCardsIn(ZoneType.Battlefield), CardPredicates.LANDS_PRODUCING_MANA);
if (!p.isOpponentOf(player)) { if (!p.isOpponentOf(player)) {
if (landsOTB <= 2) { if (landsOTB <= 2) {
@@ -758,13 +757,13 @@ public class PlayerControllerAi extends PlayerController {
for (int i = 0; i < cardsToReturn; i++) { for (int i = 0; i < cardsToReturn; i++) {
hand.removeAll(toReturn); hand.removeAll(toReturn);
CardCollection landsInHand = CardLists.filter(hand, Presets.LANDS); CardCollection landsInHand = CardLists.filter(hand, CardPredicates.LANDS);
int numLandsInHand = landsInHand.size() - CardLists.count(toReturn, Presets.LANDS); int numLandsInHand = landsInHand.size() - CardLists.count(toReturn, CardPredicates.LANDS);
// If we're flooding with lands, get rid of the worst land we have // If we're flooding with lands, get rid of the worst land we have
if (numLandsInHand > 0 && numLandsInHand > numLandsDesired) { if (numLandsInHand > 0 && numLandsInHand > numLandsDesired) {
CardCollection producingLands = CardLists.filter(landsInHand, Presets.LANDS_PRODUCING_MANA); CardCollection producingLands = CardLists.filter(landsInHand, CardPredicates.LANDS_PRODUCING_MANA);
CardCollection nonProducingLands = CardLists.filter(landsInHand, Presets.LANDS_PRODUCING_MANA.negate()); CardCollection nonProducingLands = CardLists.filter(landsInHand, CardPredicates.LANDS_PRODUCING_MANA.negate());
Card worstLand = nonProducingLands.isEmpty() ? ComputerUtilCard.getWorstLand(producingLands) Card worstLand = nonProducingLands.isEmpty() ? ComputerUtilCard.getWorstLand(producingLands)
: ComputerUtilCard.getWorstLand(nonProducingLands); : ComputerUtilCard.getWorstLand(nonProducingLands);
toReturn.add(worstLand); toReturn.add(worstLand);
@@ -1074,7 +1073,7 @@ public class PlayerControllerAi extends PlayerController {
return Iterables.getFirst(options, null); return Iterables.getFirst(options, null);
} }
List<String> possible = Lists.newArrayList(); List<String> possible = Lists.newArrayList();
CardCollection oppUntappedCreatures = CardLists.filter(player.getOpponents().getCreaturesInPlay(), CardPredicates.Presets.UNTAPPED); CardCollection oppUntappedCreatures = CardLists.filter(player.getOpponents().getCreaturesInPlay(), CardPredicates.UNTAPPED);
if (tgtCard != null) { if (tgtCard != null) {
for (String kw : options) { for (String kw : options) {
if (tgtCard.hasKeyword(kw)) { if (tgtCard.hasKeyword(kw)) {
@@ -1336,7 +1335,7 @@ public class PlayerControllerAi extends PlayerController {
// Probably want to see if the face up pile has anything "worth it", then potentially take face down pile // Probably want to see if the face up pile has anything "worth it", then potentially take face down pile
return pile1.size() >= pile2.size(); return pile1.size() >= pile2.size();
} else { } else {
boolean allCreatures = Iterables.all(Iterables.concat(pile1, pile2), CardPredicates.Presets.CREATURES); boolean allCreatures = Iterables.all(Iterables.concat(pile1, pile2), CardPredicates.CREATURES);
int cmc1 = allCreatures ? ComputerUtilCard.evaluateCreatureList(pile1) : ComputerUtilCard.evaluatePermanentList(pile1); int cmc1 = allCreatures ? ComputerUtilCard.evaluateCreatureList(pile1) : ComputerUtilCard.evaluatePermanentList(pile1);
int cmc2 = allCreatures ? ComputerUtilCard.evaluateCreatureList(pile2) : ComputerUtilCard.evaluatePermanentList(pile2); int cmc2 = allCreatures ? ComputerUtilCard.evaluateCreatureList(pile2) : ComputerUtilCard.evaluatePermanentList(pile2);
@@ -1469,7 +1468,7 @@ public class PlayerControllerAi extends PlayerController {
} }
} else { } else {
CardCollectionView list = CardLists.filterControlledBy(getGame().getCardsInGame(), player.getOpponents()); CardCollectionView list = CardLists.filterControlledBy(getGame().getCardsInGame(), player.getOpponents());
list = CardLists.filter(list, Presets.NON_LANDS); list = CardLists.filter(list, CardPredicates.NON_LANDS);
if (!list.isEmpty()) { if (!list.isEmpty()) {
return list.get(0).getName(); return list.get(0).getName();
} }

View File

@@ -124,8 +124,8 @@ public class SpecialCardAi {
CardCollection manaSources = ComputerUtilMana.getAvailableManaSources(ai, true); CardCollection manaSources = ComputerUtilMana.getAvailableManaSources(ai, true);
int numManaSrcs = manaSources.size(); int numManaSrcs = manaSources.size();
CardCollection allCards = CardLists.filter(ai.getAllCards(), Arrays.asList(CardPredicates.Presets.NON_TOKEN, CardCollection allCards = CardLists.filter(ai.getAllCards(), Arrays.asList(CardPredicates.NON_TOKEN,
CardPredicates.Presets.NON_LANDS, CardPredicates.isOwner(ai))); CardPredicates.NON_LANDS, CardPredicates.isOwner(ai)));
int numHighCMC = CardLists.count(allCards, CardPredicates.greaterCMC(5)); int numHighCMC = CardLists.count(allCards, CardPredicates.greaterCMC(5));
int numLowCMC = CardLists.count(allCards, CardPredicates.lessCMC(3)); int numLowCMC = CardLists.count(allCards, CardPredicates.lessCMC(3));
@@ -156,7 +156,7 @@ public class SpecialCardAi {
int libsize = ai.getCardsIn(ZoneType.Library).size(); int libsize = ai.getCardsIn(ZoneType.Library).size();
final CardCollection hand = CardLists.filter(ai.getCardsIn(ZoneType.Hand), final CardCollection hand = CardLists.filter(ai.getCardsIn(ZoneType.Hand),
CardPredicates.Presets.INSTANTS_AND_SORCERIES); CardPredicates.INSTANTS_AND_SORCERIES);
if (!hand.isEmpty()) { if (!hand.isEmpty()) {
// has spell that can be cast in hand with put ability // has spell that can be cast in hand with put ability
if (Iterables.any(hand, CardPredicates.hasCMC(counterNum + 1))) { if (Iterables.any(hand, CardPredicates.hasCMC(counterNum + 1))) {
@@ -169,7 +169,7 @@ public class SpecialCardAi {
} }
} }
final CardCollection library = CardLists.filter(ai.getCardsIn(ZoneType.Library), final CardCollection library = CardLists.filter(ai.getCardsIn(ZoneType.Library),
CardPredicates.Presets.INSTANTS_AND_SORCERIES); CardPredicates.INSTANTS_AND_SORCERIES);
if (!library.isEmpty()) { if (!library.isEmpty()) {
// get max cmc of instant or sorceries in the libary // get max cmc of instant or sorceries in the libary
int maxCMC = 0; int maxCMC = 0;
@@ -204,9 +204,9 @@ public class SpecialCardAi {
public static class ChainOfAcid { public static class ChainOfAcid {
public static boolean consider(final Player ai, final SpellAbility sa) { public static boolean consider(final Player ai, final SpellAbility sa) {
List<Card> AiLandsOnly = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), List<Card> AiLandsOnly = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield),
CardPredicates.Presets.LANDS); CardPredicates.LANDS);
List<Card> OppPerms = CardLists.filter(ai.getOpponents().getCardsIn(ZoneType.Battlefield), List<Card> OppPerms = CardLists.filter(ai.getOpponents().getCardsIn(ZoneType.Battlefield),
CardPredicates.Presets.NON_CREATURES); CardPredicates.NON_CREATURES);
// TODO: improve this logic (currently the AI has difficulty evaluating non-creature permanents, // TODO: improve this logic (currently the AI has difficulty evaluating non-creature permanents,
// which it can only distinguish by their CMC, considering >CMC higher value). // which it can only distinguish by their CMC, considering >CMC higher value).
@@ -330,13 +330,13 @@ public class SpecialCardAi {
// Deathgorge Scavenger // Deathgorge Scavenger
public static class DeathgorgeScavenger { public static class DeathgorgeScavenger {
public static boolean consider(final Player ai, final SpellAbility sa) { public static boolean consider(final Player ai, final SpellAbility sa) {
Card worstCreat = ComputerUtilCard.getWorstAI(CardLists.filter(ai.getOpponents().getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.CREATURES)); Card worstCreat = ComputerUtilCard.getWorstAI(CardLists.filter(ai.getOpponents().getCardsIn(ZoneType.Graveyard), CardPredicates.CREATURES));
Card worstNonCreat = ComputerUtilCard.getWorstAI(CardLists.filter(ai.getOpponents().getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.NON_CREATURES)); Card worstNonCreat = ComputerUtilCard.getWorstAI(CardLists.filter(ai.getOpponents().getCardsIn(ZoneType.Graveyard), CardPredicates.NON_CREATURES));
if (worstCreat == null) { if (worstCreat == null) {
worstCreat = ComputerUtilCard.getWorstAI(CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.CREATURES)); worstCreat = ComputerUtilCard.getWorstAI(CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.CREATURES));
} }
if (worstNonCreat == null) { if (worstNonCreat == null) {
worstNonCreat = ComputerUtilCard.getWorstAI(CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.NON_CREATURES)); worstNonCreat = ComputerUtilCard.getWorstAI(CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.NON_CREATURES));
} }
sa.resetTargets(); sa.resetTargets();
@@ -359,7 +359,7 @@ public class SpecialCardAi {
public static boolean considerSacrificingCreature(final Player ai, final SpellAbility sa) { public static boolean considerSacrificingCreature(final Player ai, final SpellAbility sa) {
CardCollection flyingCreatures = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardCollection flyingCreatures = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield),
CardPredicates.Presets.UNTAPPED.and( CardPredicates.UNTAPPED.and(
CardPredicates.hasKeyword(Keyword.FLYING).or(CardPredicates.hasKeyword(Keyword.REACH)))); CardPredicates.hasKeyword(Keyword.FLYING).or(CardPredicates.hasKeyword(Keyword.REACH))));
boolean hasUsefulBlocker = false; boolean hasUsefulBlocker = false;
@@ -402,7 +402,7 @@ public class SpecialCardAi {
// select player with less lands on the field (helpful for Illusions of Grandeur and probably Pacts too) // select player with less lands on the field (helpful for Illusions of Grandeur and probably Pacts too)
Player opp = Collections.min(Lists.newArrayList(oppTarget), Player opp = Collections.min(Lists.newArrayList(oppTarget),
PlayerPredicates.compareByZoneSize(ZoneType.Battlefield, CardPredicates.Presets.LANDS)); PlayerPredicates.compareByZoneSize(ZoneType.Battlefield, CardPredicates.LANDS));
if (opp != null) { if (opp != null) {
sa.resetTargets(); sa.resetTargets();
@@ -581,9 +581,9 @@ public class SpecialCardAi {
Card bestBasic = null; Card bestBasic = null;
Card bestBasicSelfOnly = null; Card bestBasicSelfOnly = null;
CardCollection aiLands = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.LANDS_PRODUCING_MANA); CardCollection aiLands = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.LANDS_PRODUCING_MANA);
CardCollection oppLands = CardLists.filter(ai.getOpponents().getCardsIn(ZoneType.Battlefield), CardCollection oppLands = CardLists.filter(ai.getOpponents().getCardsIn(ZoneType.Battlefield),
CardPredicates.Presets.LANDS_PRODUCING_MANA); CardPredicates.LANDS_PRODUCING_MANA);
int bestCount = 0; int bestCount = 0;
int bestSelfOnlyCount = 0; int bestSelfOnlyCount = 0;
@@ -629,7 +629,7 @@ public class SpecialCardAi {
} }
CardCollection oppList = CardLists.filter(ai.getGame().getCardsIn(ZoneType.Battlefield), CardCollection oppList = CardLists.filter(ai.getGame().getCardsIn(ZoneType.Battlefield),
CardPredicates.Presets.CREATURES, CardPredicates.isControlledByAnyOf(ai.getOpponents())); CardPredicates.CREATURES, CardPredicates.isControlledByAnyOf(ai.getOpponents()));
oppList = CardLists.filterPower(oppList, lowest.getNetPower() + 1); oppList = CardLists.filterPower(oppList, lowest.getNetPower() + 1);
if (ComputerUtilCard.evaluateCreatureList(oppList) > 200) { if (ComputerUtilCard.evaluateCreatureList(oppList) > 200) {
@@ -685,7 +685,7 @@ public class SpecialCardAi {
// Goblin Polka Band // Goblin Polka Band
public static class GoblinPolkaBand { public static class GoblinPolkaBand {
public static boolean consider(final Player ai, final SpellAbility sa) { public static boolean consider(final Player ai, final SpellAbility sa) {
int maxPotentialTgts = Lists.newArrayList(Iterables.filter(ai.getOpponents().getCreaturesInPlay(), CardPredicates.Presets.UNTAPPED)).size(); int maxPotentialTgts = Lists.newArrayList(Iterables.filter(ai.getOpponents().getCreaturesInPlay(), CardPredicates.UNTAPPED)).size();
int maxPotentialPayment = ComputerUtilMana.determineLeftoverMana(sa, ai, "R", false); int maxPotentialPayment = ComputerUtilMana.determineLeftoverMana(sa, ai, "R", false);
int numTgts = Math.min(maxPotentialPayment, maxPotentialTgts); int numTgts = Math.min(maxPotentialPayment, maxPotentialTgts);
@@ -921,7 +921,7 @@ public class SpecialCardAi {
int aiBattlefieldPower = 0, aiGraveyardPower = 0; int aiBattlefieldPower = 0, aiGraveyardPower = 0;
int threshold = 320; // approximately a 4/4 Flying creature worth of extra value int threshold = 320; // approximately a 4/4 Flying creature worth of extra value
CardCollection aiCreaturesInGY = CardLists.filter(ai.getZone(ZoneType.Graveyard).getCards(), CardPredicates.Presets.CREATURES); CardCollection aiCreaturesInGY = CardLists.filter(ai.getZone(ZoneType.Graveyard).getCards(), CardPredicates.CREATURES);
if (aiCreaturesInGY.isEmpty()) { if (aiCreaturesInGY.isEmpty()) {
// nothing in graveyard, so cut short // nothing in graveyard, so cut short
@@ -945,7 +945,7 @@ public class SpecialCardAi {
for (Card c : p.getCreaturesInPlay()) { for (Card c : p.getCreaturesInPlay()) {
playerPower += ComputerUtilCard.evaluateCreature(c); playerPower += ComputerUtilCard.evaluateCreature(c);
} }
for (Card c : CardLists.filter(p.getZone(ZoneType.Graveyard).getCards(), CardPredicates.Presets.CREATURES)) { for (Card c : CardLists.filter(p.getZone(ZoneType.Graveyard).getCards(), CardPredicates.CREATURES)) {
tempGraveyardPower += ComputerUtilCard.evaluateCreature(c); tempGraveyardPower += ComputerUtilCard.evaluateCreature(c);
} }
if (playerPower > oppBattlefieldPower) { if (playerPower > oppBattlefieldPower) {
@@ -997,7 +997,7 @@ public class SpecialCardAi {
// Scan the fetch list for a card with at least one activated ability. // Scan the fetch list for a card with at least one activated ability.
// TODO: can be improved to a full consider(sa, ai) logic which would scan the graveyard first and hand last // TODO: can be improved to a full consider(sa, ai) logic which would scan the graveyard first and hand last
public static Card considerCardFromList(final CardCollection fetchList) { public static Card considerCardFromList(final CardCollection fetchList) {
for (Card c : CardLists.filter(fetchList, CardPredicates.Presets.ARTIFACTS.or(CardPredicates.Presets.CREATURES))) { for (Card c : CardLists.filter(fetchList, CardPredicates.ARTIFACTS.or(CardPredicates.CREATURES))) {
for (SpellAbility ab : c.getSpellAbilities()) { for (SpellAbility ab : c.getSpellAbilities()) {
if (ab.isActivatedAbility()) { if (ab.isActivatedAbility()) {
Player controller = c.getController(); Player controller = c.getController();
@@ -1058,7 +1058,7 @@ public class SpecialCardAi {
// In MoJhoSto, prefer Jhoira sorcery ability from time to time // In MoJhoSto, prefer Jhoira sorcery ability from time to time
if (source.getGame().getRules().hasAppliedVariant(GameType.MoJhoSto) if (source.getGame().getRules().hasAppliedVariant(GameType.MoJhoSto)
&& CardLists.filter(ai.getLandsInPlay(), CardPredicates.Presets.UNTAPPED).size() >= 3) { && CardLists.filter(ai.getLandsInPlay(), CardPredicates.UNTAPPED).size() >= 3) {
AiController aic = ((PlayerControllerAi)ai.getController()).getAi(); AiController aic = ((PlayerControllerAi)ai.getController()).getAi();
int chanceToPrefJhoira = aic.getIntProperty(AiProps.MOJHOSTO_CHANCE_TO_PREFER_JHOIRA_OVER_MOMIR); int chanceToPrefJhoira = aic.getIntProperty(AiProps.MOJHOSTO_CHANCE_TO_PREFER_JHOIRA_OVER_MOMIR);
int numLandsForJhoira = aic.getIntProperty(AiProps.MOJHOSTO_NUM_LANDS_TO_ACTIVATE_JHOIRA); int numLandsForJhoira = aic.getIntProperty(AiProps.MOJHOSTO_NUM_LANDS_TO_ACTIVATE_JHOIRA);
@@ -1219,7 +1219,7 @@ public class SpecialCardAi {
final CardCollectionView cards = ai.getCardsIn(Arrays.asList(ZoneType.Hand, ZoneType.Battlefield, ZoneType.Command)); final CardCollectionView cards = ai.getCardsIn(Arrays.asList(ZoneType.Hand, ZoneType.Battlefield, ZoneType.Command));
List<SpellAbility> all = ComputerUtilAbility.getSpellAbilities(cards, ai); List<SpellAbility> all = ComputerUtilAbility.getSpellAbilities(cards, ai);
int numManaSrcs = CardLists.filter(ComputerUtilMana.getAvailableManaSources(ai, true), CardPredicates.Presets.UNTAPPED).size(); int numManaSrcs = CardLists.filter(ComputerUtilMana.getAvailableManaSources(ai, true), CardPredicates.UNTAPPED).size();
for (final SpellAbility testSa : ComputerUtilAbility.getOriginalAndAltCostAbilities(all, ai)) { for (final SpellAbility testSa : ComputerUtilAbility.getOriginalAndAltCostAbilities(all, ai)) {
ManaCost cost = testSa.getPayCosts().getTotalMana(); ManaCost cost = testSa.getPayCosts().getTotalMana();
@@ -1316,7 +1316,7 @@ public class SpecialCardAi {
return false; return false;
} }
int aiLands = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.NONBASIC_LANDS).size(); int aiLands = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.NONBASIC_LANDS).size();
boolean hasBridge = false; boolean hasBridge = false;
for (Card c : ai.getCardsIn(ZoneType.Battlefield)) { for (Card c : ai.getCardsIn(ZoneType.Battlefield)) {
@@ -1334,7 +1334,7 @@ public class SpecialCardAi {
} }
for (Player opp : ai.getOpponents()) { for (Player opp : ai.getOpponents()) {
int oppLands = CardLists.filter(opp.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.NONBASIC_LANDS).size(); int oppLands = CardLists.filter(opp.getCardsIn(ZoneType.Battlefield), CardPredicates.NONBASIC_LANDS).size();
// Always if enemy would die and we don't! // Always if enemy would die and we don't!
// TODO : predict actual damage instead of assuming it'll be 2*lands // TODO : predict actual damage instead of assuming it'll be 2*lands
// Don't if we lose, unless we lose anyway to unblocked creatures next turn // Don't if we lose, unless we lose anyway to unblocked creatures next turn
@@ -1402,7 +1402,7 @@ public class SpecialCardAi {
public static boolean consider(final Player ai, final SpellAbility sa) { public static boolean consider(final Player ai, final SpellAbility sa) {
CardCollection oppTargetables = CardLists.getTargetableCards(ai.getOpponents().getCreaturesInPlay(), sa); CardCollection oppTargetables = CardLists.getTargetableCards(ai.getOpponents().getCreaturesInPlay(), sa);
CardCollection threats = CardLists.filter(oppTargetables, card -> !ComputerUtilCard.isUselessCreature(card.getController(), card)); CardCollection threats = CardLists.filter(oppTargetables, card -> !ComputerUtilCard.isUselessCreature(card.getController(), card));
CardCollection ownTgts = CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.CREATURES); CardCollection ownTgts = CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.CREATURES);
// TODO: improve the conditions for when the AI is considered threatened (check the possibility of being attacked?) // TODO: improve the conditions for when the AI is considered threatened (check the possibility of being attacked?)
int lifeInDanger = (((PlayerControllerAi) ai.getController()).getAi().getIntProperty(AiProps.AI_IN_DANGER_THRESHOLD)); int lifeInDanger = (((PlayerControllerAi) ai.getController()).getAi().getIntProperty(AiProps.AI_IN_DANGER_THRESHOLD));
@@ -1442,7 +1442,7 @@ public class SpecialCardAi {
public static boolean consider(final Player ai, final SpellAbility sa) { public static boolean consider(final Player ai, final SpellAbility sa) {
int loyalty = sa.getHostCard().getCounters(CounterEnumType.LOYALTY); int loyalty = sa.getHostCard().getCounters(CounterEnumType.LOYALTY);
CardCollection creaturesToGet = CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardCollection creaturesToGet = CardLists.filter(ai.getCardsIn(ZoneType.Graveyard),
CardPredicates.Presets.CREATURES CardPredicates.CREATURES
.and(CardPredicates.lessCMC(loyalty - 1)) .and(CardPredicates.lessCMC(loyalty - 1))
.and(card -> { .and(card -> {
final Card copy = CardCopyService.getLKICopy(card); final Card copy = CardCopyService.getLKICopy(card);
@@ -1484,9 +1484,9 @@ public class SpecialCardAi {
// face down (on the battlefield or in exile). Might need some kind of an update to consider hidden information // face down (on the battlefield or in exile). Might need some kind of an update to consider hidden information
// like that properly (probably by adding all those cards to the evaluation mix so the AI doesn't "know" which // like that properly (probably by adding all those cards to the evaluation mix so the AI doesn't "know" which
// ones are already face down in play and which are still in the library) // ones are already face down in play and which are still in the library)
CardCollectionView creatsInLib = CardLists.filter(ai.getCardsIn(ZoneType.Library), CardPredicates.Presets.CREATURES); CardCollectionView creatsInLib = CardLists.filter(ai.getCardsIn(ZoneType.Library), CardPredicates.CREATURES);
CardCollectionView creatsInHand = CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.Presets.CREATURES); CardCollectionView creatsInHand = CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.CREATURES);
CardCollectionView manaSrcsInHand = CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.Presets.LANDS_PRODUCING_MANA); CardCollectionView manaSrcsInHand = CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.LANDS_PRODUCING_MANA);
if (creatsInHand.isEmpty() || creatsInLib.isEmpty()) { return null; } if (creatsInHand.isEmpty() || creatsInLib.isEmpty()) { return null; }
@@ -1555,10 +1555,10 @@ public class SpecialCardAi {
} }
public static Card considerCardToGet(final Player ai, final SpellAbility sa) { public static Card considerCardToGet(final Player ai, final SpellAbility sa) {
CardCollectionView creatsInLib = CardLists.filter(ai.getCardsIn(ZoneType.Library), CardPredicates.Presets.CREATURES); CardCollectionView creatsInLib = CardLists.filter(ai.getCardsIn(ZoneType.Library), CardPredicates.CREATURES);
if (creatsInLib.isEmpty()) { return null; } if (creatsInLib.isEmpty()) { return null; }
CardCollectionView manaSrcsInHand = CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.Presets.LANDS_PRODUCING_MANA); CardCollectionView manaSrcsInHand = CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.LANDS_PRODUCING_MANA);
int numManaSrcs = ComputerUtilMana.getAvailableManaEstimate(ai, false) int numManaSrcs = ComputerUtilMana.getAvailableManaEstimate(ai, false)
+ Math.min(1, manaSrcsInHand.size()); + Math.min(1, manaSrcsInHand.size());
@@ -1602,8 +1602,8 @@ public class SpecialCardAi {
// The Scarab God // The Scarab God
public static class TheScarabGod { public static class TheScarabGod {
public static boolean consider(final Player ai, final SpellAbility sa) { public static boolean consider(final Player ai, final SpellAbility sa) {
Card bestOppCreat = ComputerUtilCard.getBestAI(CardLists.filter(ai.getOpponents().getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.CREATURES)); Card bestOppCreat = ComputerUtilCard.getBestAI(CardLists.filter(ai.getOpponents().getCardsIn(ZoneType.Graveyard), CardPredicates.CREATURES));
Card worstOwnCreat = ComputerUtilCard.getWorstAI(CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.CREATURES)); Card worstOwnCreat = ComputerUtilCard.getWorstAI(CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.CREATURES));
sa.resetTargets(); sa.resetTargets();
if (bestOppCreat != null) { if (bestOppCreat != null) {
@@ -1704,7 +1704,7 @@ public class SpecialCardAi {
CardCollectionView aiGY = ai.getCardsIn(ZoneType.Graveyard); CardCollectionView aiGY = ai.getCardsIn(ZoneType.Graveyard);
Card topGY = null; Card topGY = null;
Card creatHand = ComputerUtilCard.getBestCreatureAI(ai.getCardsIn(ZoneType.Hand)); Card creatHand = ComputerUtilCard.getBestCreatureAI(ai.getCardsIn(ZoneType.Hand));
int numCreatsInHand = CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.Presets.CREATURES).size(); int numCreatsInHand = CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.CREATURES).size();
if (!aiGY.isEmpty()) { if (!aiGY.isEmpty()) {
topGY = ai.getCardsIn(ZoneType.Graveyard).get(0); topGY = ai.getCardsIn(ZoneType.Graveyard).get(0);

View File

@@ -130,7 +130,7 @@ public class AnimateAi extends SpellAbilityAi {
&& game.getPhaseHandler().getNextTurn() != ai && game.getPhaseHandler().getNextTurn() != ai
&& source.isPermanent(); && source.isPermanent();
if (ph.isPlayerTurn(ai) && ai.getLife() < 6 && opponent.getLife() > 6 if (ph.isPlayerTurn(ai) && ai.getLife() < 6 && opponent.getLife() > 6
&& opponent.getZone(ZoneType.Battlefield).contains(CardPredicates.Presets.CREATURES) && opponent.getZone(ZoneType.Battlefield).contains(CardPredicates.CREATURES)
&& !sa.hasParam("AILogic") && !"Permanent".equals(sa.getParam("Duration")) && !activateAsPotentialBlocker) { && !sa.hasParam("AILogic") && !"Permanent".equals(sa.getParam("Duration")) && !activateAsPotentialBlocker) {
return false; return false;
} }

View File

@@ -509,7 +509,7 @@ public class AttachAi extends SpellAbilityAi {
if (!evenBetterList.isEmpty()) { if (!evenBetterList.isEmpty()) {
betterList = evenBetterList; betterList = evenBetterList;
} }
evenBetterList = CardLists.filter(betterList, CardPredicates.Presets.UNTAPPED); evenBetterList = CardLists.filter(betterList, CardPredicates.UNTAPPED);
if (!evenBetterList.isEmpty()) { if (!evenBetterList.isEmpty()) {
betterList = evenBetterList; betterList = evenBetterList;
} }

View File

@@ -25,10 +25,10 @@ public class BalanceAi extends SpellAbilityAi {
if ("BalanceCreaturesAndLands".equals(logic)) { if ("BalanceCreaturesAndLands".equals(logic)) {
// TODO Copied over from hardcoded Balance. We should be checking value of the lands/creatures for each opponent, not just counting // TODO Copied over from hardcoded Balance. We should be checking value of the lands/creatures for each opponent, not just counting
diff += CardLists.filter(humPerms, CardPredicates.Presets.LANDS).size() - diff += CardLists.filter(humPerms, CardPredicates.LANDS).size() -
CardLists.filter(compPerms, CardPredicates.Presets.LANDS).size(); CardLists.filter(compPerms, CardPredicates.LANDS).size();
diff += 1.5 * (CardLists.filter(humPerms, CardPredicates.Presets.CREATURES).size() - diff += 1.5 * (CardLists.filter(humPerms, CardPredicates.CREATURES).size() -
CardLists.filter(compPerms, CardPredicates.Presets.CREATURES).size()); CardLists.filter(compPerms, CardPredicates.CREATURES).size());
} }
else if ("BalancePermanents".equals(logic)) { else if ("BalancePermanents".equals(logic)) {
// Don't cast if you have to sacrifice permanents // Don't cast if you have to sacrifice permanents

View File

@@ -12,7 +12,6 @@ import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.*; import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.combat.Combat; import forge.game.combat.Combat;
import forge.game.cost.*; import forge.game.cost.*;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
@@ -32,7 +31,6 @@ import forge.util.MyRandom;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.*; import java.util.*;
import java.util.function.Predicate;
public class ChangeZoneAi extends SpellAbilityAi { public class ChangeZoneAi extends SpellAbilityAi {
/* /*
@@ -614,8 +612,8 @@ public class ChangeZoneAi extends SpellAbilityAi {
} }
// pick dual lands if available // pick dual lands if available
if (Iterables.any(result, Presets.NONBASIC_LANDS)) { if (Iterables.any(result, CardPredicates.NONBASIC_LANDS)) {
result = CardLists.filter(result, Presets.NONBASIC_LANDS); result = CardLists.filter(result, CardPredicates.NONBASIC_LANDS);
} }
return result.get(0); return result.get(0);
@@ -1013,7 +1011,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
boolean saheeliFelidarCombo = ComputerUtilAbility.getAbilitySourceName(sa).equals("Felidar Guardian") boolean saheeliFelidarCombo = ComputerUtilAbility.getAbilitySourceName(sa).equals("Felidar Guardian")
&& tobounce.getName().equals("Saheeli Rai") && tobounce.getName().equals("Saheeli Rai")
&& CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.nameEquals("Felidar Guardian")).size() < && CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.nameEquals("Felidar Guardian")).size() <
CardLists.filter(ai.getOpponents().getCardsIn(ZoneType.Battlefield), Presets.CREATURES).size() + ai.getOpponentsGreatestLifeTotal() + 10; CardLists.filter(ai.getOpponents().getCardsIn(ZoneType.Battlefield), CardPredicates.CREATURES).size() + ai.getOpponentsGreatestLifeTotal() + 10;
// remember that the card was bounced already unless it's a special combo case // remember that the card was bounced already unless it's a special combo case
if (!saheeliFelidarCombo) { if (!saheeliFelidarCombo) {
@@ -1197,7 +1195,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
} else if (destination.equals(ZoneType.Hand) || destination.equals(ZoneType.Library)) { } else if (destination.equals(ZoneType.Hand) || destination.equals(ZoneType.Library)) {
List<Card> nonLands = CardLists.getNotType(list, "Land"); List<Card> nonLands = CardLists.getNotType(list, "Land");
// Prefer to pull a creature, generally more useful for AI. // Prefer to pull a creature, generally more useful for AI.
choice = chooseCreature(ai, CardLists.filter(nonLands, CardPredicates.Presets.CREATURES)); choice = chooseCreature(ai, CardLists.filter(nonLands, CardPredicates.CREATURES));
if (choice == null) { // Could not find a creature. if (choice == null) { // Could not find a creature.
if (ai.getLife() <= 5) { // Desperate? if (ai.getLife() <= 5) { // Desperate?
// Get something AI can cast soon. // Get something AI can cast soon.
@@ -1309,7 +1307,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
Game game = ai.getGame(); Game game = ai.getGame();
// filter out untargetables // filter out untargetables
CardCollectionView aiPermanents = CardLists.filterControlledBy(list, ai); CardCollectionView aiPermanents = CardLists.filterControlledBy(list, ai);
CardCollection aiPlaneswalkers = CardLists.filter(aiPermanents, Presets.PLANESWALKERS); CardCollection aiPlaneswalkers = CardLists.filter(aiPermanents, CardPredicates.PLANESWALKERS);
// Felidar Guardian + Saheeli Rai combo support // Felidar Guardian + Saheeli Rai combo support
if (sa.getHostCard().getName().equals("Felidar Guardian")) { if (sa.getHostCard().getName().equals("Felidar Guardian")) {
@@ -1335,7 +1333,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
else if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) { else if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
Combat combat = game.getCombat(); Combat combat = game.getCombat();
final CardCollection combatants = CardLists.filter(aiPermanents, final CardCollection combatants = CardLists.filter(aiPermanents,
CardPredicates.Presets.CREATURES); CardPredicates.CREATURES);
ComputerUtilCard.sortByEvaluateCreature(combatants); ComputerUtilCard.sortByEvaluateCreature(combatants);
for (final Card c : combatants) { for (final Card c : combatants) {
@@ -1455,7 +1453,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
} else if (destination.equals(ZoneType.Hand) || destination.equals(ZoneType.Library)) { } else if (destination.equals(ZoneType.Hand) || destination.equals(ZoneType.Library)) {
List<Card> nonLands = CardLists.getNotType(list, "Land"); List<Card> nonLands = CardLists.getNotType(list, "Land");
// Prefer to pull a creature, generally more useful for AI. // Prefer to pull a creature, generally more useful for AI.
choice = chooseCreature(ai, CardLists.filter(nonLands, CardPredicates.Presets.CREATURES)); choice = chooseCreature(ai, CardLists.filter(nonLands, CardPredicates.CREATURES));
if (choice == null) { // Could not find a creature. if (choice == null) { // Could not find a creature.
if (ai.getLife() <= 5) { // Desperate? if (ai.getLife() <= 5) { // Desperate?
// Get something AI can cast soon. // Get something AI can cast soon.
@@ -1636,7 +1634,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
// Does AI need a land? // Does AI need a land?
CardCollectionView hand = decider.getCardsIn(ZoneType.Hand); CardCollectionView hand = decider.getCardsIn(ZoneType.Hand);
if (!Iterables.any(hand, Presets.LANDS) && CardLists.count(decider.getCardsIn(ZoneType.Battlefield), Presets.LANDS) < 4) { if (!Iterables.any(hand, CardPredicates.LANDS) && CardLists.count(decider.getCardsIn(ZoneType.Battlefield), CardPredicates.LANDS) < 4) {
boolean canCastSomething = false; boolean canCastSomething = false;
for (Card cardInHand : hand) { for (Card cardInHand : hand) {
canCastSomething = canCastSomething || ComputerUtilMana.hasEnoughManaSourcesToCast(cardInHand.getFirstSpellAbility(), decider); canCastSomething = canCastSomething || ComputerUtilMana.hasEnoughManaSourcesToCast(cardInHand.getFirstSpellAbility(), decider);
@@ -1646,13 +1644,13 @@ public class ChangeZoneAi extends SpellAbilityAi {
} }
} }
if (c == null) { if (c == null) {
if (Iterables.all(fetchList, Presets.LANDS)) { if (Iterables.all(fetchList, CardPredicates.LANDS)) {
// we're only choosing from lands, so get the best land // we're only choosing from lands, so get the best land
c = ComputerUtilCard.getBestLandAI(fetchList); c = ComputerUtilCard.getBestLandAI(fetchList);
} else { } else {
fetchList = CardLists.getNotType(fetchList, "Land"); fetchList = CardLists.getNotType(fetchList, "Land");
// Prefer to pull a creature, generally more useful for AI. // Prefer to pull a creature, generally more useful for AI.
c = chooseCreature(decider, CardLists.filter(fetchList, CardPredicates.Presets.CREATURES)); c = chooseCreature(decider, CardLists.filter(fetchList, CardPredicates.CREATURES));
} }
} }
if (c == null) { // Could not find a creature. if (c == null) { // Could not find a creature.
@@ -1770,7 +1768,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
CardCollection listToSac = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), definedSac, ai, source, sa); CardCollection listToSac = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), definedSac, ai, source, sa);
listToSac.sort(Collections.reverseOrder(CardLists.CmcComparatorInv)); listToSac.sort(Collections.reverseOrder(CardLists.CmcComparatorInv));
CardCollection listToRet = CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), Presets.CREATURES); CardCollection listToRet = CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.CREATURES);
listToRet.sort(CardLists.CmcComparatorInv); listToRet.sort(CardLists.CmcComparatorInv);
if (!listToSac.isEmpty() && !listToRet.isEmpty()) { if (!listToSac.isEmpty() && !listToRet.isEmpty()) {
@@ -1961,7 +1959,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
} }
if (logic.contains("NonLand")) { if (logic.contains("NonLand")) {
scanList = CardLists.filter(scanList, Presets.NON_LANDS); scanList = CardLists.filter(scanList, CardPredicates.NON_LANDS);
} }
if (logic.contains("NonExiled")) { if (logic.contains("NonExiled")) {

View File

@@ -92,7 +92,7 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
} else if ("ExileGraveyards".equals(aiLogic)) { } else if ("ExileGraveyards".equals(aiLogic)) {
for (Player opp : ai.getOpponents()) { for (Player opp : ai.getOpponents()) {
CardCollectionView cardsGY = opp.getCardsIn(ZoneType.Graveyard); CardCollectionView cardsGY = opp.getCardsIn(ZoneType.Graveyard);
CardCollection creats = CardLists.filter(cardsGY, CardPredicates.Presets.CREATURES); CardCollection creats = CardLists.filter(cardsGY, CardPredicates.CREATURES);
if (opp.hasDelirium() || opp.hasThreshold() || creats.size() >= 5) { if (opp.hasDelirium() || opp.hasThreshold() || creats.size() >= 5) {
return true; return true;
@@ -107,7 +107,7 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
Player bestTgt = null; Player bestTgt = null;
if (player.canBeTargetedBy(sa)) { if (player.canBeTargetedBy(sa)) {
int numGY = CardLists.count(player.getCardsIn(ZoneType.Graveyard), int numGY = CardLists.count(player.getCardsIn(ZoneType.Graveyard),
CardPredicates.Presets.CREATURES); CardPredicates.CREATURES);
if (numGY > maxSize) { if (numGY > maxSize) {
maxSize = numGY; maxSize = numGY;
bestTgt = player; bestTgt = player;
@@ -353,7 +353,7 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
// TODO: this is a stub to prevent the AI from crashing the game when, for instance, playing the opponent's // TODO: this is a stub to prevent the AI from crashing the game when, for instance, playing the opponent's
// Profaner from exile without paying its mana cost. Otherwise the card is marked AI:RemoveDeck:All and // Profaner from exile without paying its mana cost. Otherwise the card is marked AI:RemoveDeck:All and
// there is no specific AI to support playing it in a smarter way. Feel free to expand. // there is no specific AI to support playing it in a smarter way. Feel free to expand.
return Iterables.any(ai.getOpponents().getCardsIn(origin), CardPredicates.Presets.CREATURES); return Iterables.any(ai.getOpponents().getCardsIn(origin), CardPredicates.CREATURES);
} }
CardCollectionView humanType = ai.getOpponents().getCardsIn(origin); CardCollectionView humanType = ai.getOpponents().getCardsIn(origin);

View File

@@ -15,7 +15,6 @@ import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView; import forge.game.card.CardCollectionView;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CardPredicates; import forge.game.card.CardPredicates;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CounterEnumType; import forge.game.card.CounterEnumType;
import forge.game.combat.Combat; import forge.game.combat.Combat;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
@@ -178,8 +177,8 @@ public class ChooseCardAi extends SpellAbilityAi {
} }
choice = ComputerUtilCard.getBestAI(ownChoices); choice = ComputerUtilCard.getBestAI(ownChoices);
} else if (logic.equals("BestBlocker")) { } else if (logic.equals("BestBlocker")) {
if (Iterables.any(options, Presets.UNTAPPED)) { if (Iterables.any(options, CardPredicates.UNTAPPED)) {
options = CardLists.filter(options, Presets.UNTAPPED); options = CardLists.filter(options, CardPredicates.UNTAPPED);
} }
choice = ComputerUtilCard.getBestCreatureAI(options); choice = ComputerUtilCard.getBestCreatureAI(options);
} else if (logic.equals("Clone")) { } else if (logic.equals("Clone")) {
@@ -216,7 +215,7 @@ public class ChooseCardAi extends SpellAbilityAi {
choice = ComputerUtilCard.getWorstAI(aiControlled); choice = ComputerUtilCard.getWorstAI(aiControlled);
} }
} else if ("LowestCMCCreature".equals(logic)) { } else if ("LowestCMCCreature".equals(logic)) {
CardCollection creats = CardLists.filter(options, Presets.CREATURES); CardCollection creats = CardLists.filter(options, CardPredicates.CREATURES);
creats = CardLists.filterToughness(creats, 1); creats = CardLists.filterToughness(creats, 1);
if (creats.isEmpty()) { if (creats.isEmpty()) {
choice = ComputerUtilCard.getWorstAI(options); choice = ComputerUtilCard.getWorstAI(options);
@@ -268,10 +267,10 @@ public class ChooseCardAi extends SpellAbilityAi {
// might also be good to do a separate AI for Noble Heritage // might also be good to do a separate AI for Noble Heritage
} }
} else if (logic.equals("Phylactery")) { } else if (logic.equals("Phylactery")) {
CardCollection aiArtifacts = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), Presets.ARTIFACTS); CardCollection aiArtifacts = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.ARTIFACTS);
CardCollection indestructibles = CardLists.filter(aiArtifacts, CardPredicates.hasKeyword(Keyword.INDESTRUCTIBLE)); CardCollection indestructibles = CardLists.filter(aiArtifacts, CardPredicates.hasKeyword(Keyword.INDESTRUCTIBLE));
CardCollection nonCreatures = CardLists.filter(aiArtifacts, Presets.NON_CREATURES); CardCollection nonCreatures = CardLists.filter(aiArtifacts, CardPredicates.NON_CREATURES);
CardCollection creatures = CardLists.filter(aiArtifacts, Presets.CREATURES); CardCollection creatures = CardLists.filter(aiArtifacts, CardPredicates.CREATURES);
if (!indestructibles.isEmpty()) { if (!indestructibles.isEmpty()) {
// Choose the worst (smallest) indestructible artifact so that the opponent would have to waste // Choose the worst (smallest) indestructible artifact so that the opponent would have to waste
// removal on something unpreferred // removal on something unpreferred

View File

@@ -68,7 +68,7 @@ public class ChooseColorAi extends SpellAbilityAi {
// activate in Main 2 hoping that the extra mana surplus will make a difference // activate in Main 2 hoping that the extra mana surplus will make a difference
// if there are some nonland permanents in hand // if there are some nonland permanents in hand
CardCollectionView permanents = CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardCollectionView permanents = CardLists.filter(ai.getCardsIn(ZoneType.Hand),
CardPredicates.Presets.NONLAND_PERMANENTS); CardPredicates.NONLAND_PERMANENTS);
return permanents.size() > 0 && ph.is(PhaseType.MAIN2, ai); return permanents.size() > 0 && ph.is(PhaseType.MAIN2, ai);
} }

View File

@@ -6,7 +6,7 @@ import forge.game.Game;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCollection; import forge.game.card.CardCollection;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CardPredicates.Presets; import forge.game.card.CardPredicates;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
@@ -25,7 +25,7 @@ public class ChooseDirectionAi extends SpellAbilityAi {
return false; return false;
} else { } else {
if ("Aminatou".equals(logic)) { if ("Aminatou".equals(logic)) {
CardCollection all = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.NONLAND_PERMANENTS); CardCollection all = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), CardPredicates.NONLAND_PERMANENTS);
CardCollection aiPermanent = CardLists.filterControlledBy(all, ai); CardCollection aiPermanent = CardLists.filterControlledBy(all, ai);
aiPermanent.remove(sa.getHostCard()); aiPermanent.remove(sa.getHostCard());
int aiValue = Aggregates.sum(aiPermanent, Card::getCMC); int aiValue = Aggregates.sum(aiPermanent, Card::getCMC);

View File

@@ -134,10 +134,10 @@ public class ChooseSourceAi extends SpellAbilityAi {
// No optimal creature was found above, so try to broaden the choice. // No optimal creature was found above, so try to broaden the choice.
if (!Iterables.isEmpty(options)) { if (!Iterables.isEmpty(options)) {
List<Card> oppCreatures = CardLists.filter(options, List<Card> oppCreatures = CardLists.filter(options,
CardPredicates.Presets.CREATURES.and(CardPredicates.isOwner(aiChoser).negate())); CardPredicates.CREATURES.and(CardPredicates.isOwner(aiChoser).negate()));
List<Card> aiNonCreatures = CardLists.filter(options, List<Card> aiNonCreatures = CardLists.filter(options,
CardPredicates.Presets.NON_CREATURES CardPredicates.NON_CREATURES
.and(CardPredicates.Presets.PERMANENTS) .and(CardPredicates.PERMANENTS)
.and(CardPredicates.isOwner(aiChoser)) .and(CardPredicates.isOwner(aiChoser))
); );

View File

@@ -65,7 +65,7 @@ public class ChooseTypeAi extends SpellAbilityAi {
int avgPower = 0; int avgPower = 0;
// predict the opposition // predict the opposition
CardCollection oppCreatures = CardLists.filter(aiPlayer.getOpponents().getCreaturesInPlay(), CardPredicates.Presets.UNTAPPED); CardCollection oppCreatures = CardLists.filter(aiPlayer.getOpponents().getCreaturesInPlay(), CardPredicates.UNTAPPED);
int maxOppPower = 0; int maxOppPower = 0;
int maxOppToughness = 0; int maxOppToughness = 0;
int oppUsefulCreatures = 0; int oppUsefulCreatures = 0;
@@ -85,7 +85,7 @@ public class ChooseTypeAi extends SpellAbilityAi {
if (maxX > 1) { if (maxX > 1) {
CardCollection cre = CardLists.filter(aiPlayer.getCardsIn(ZoneType.Battlefield), CardCollection cre = CardLists.filter(aiPlayer.getCardsIn(ZoneType.Battlefield),
CardPredicates.isType(chosenType), CardPredicates.Presets.UNTAPPED); CardPredicates.isType(chosenType), CardPredicates.UNTAPPED);
if (!cre.isEmpty()) { if (!cre.isEmpty()) {
for (Card c: cre) { for (Card c: cre) {
avgPower += c.getNetPower(); avgPower += c.getNetPower();

View File

@@ -92,7 +92,7 @@ public class ClashAi extends SpellAbilityAi {
// Springjack Knight // Springjack Knight
// TODO: Whirlpool Whelm also uses creature targeting but it's trickier to support // TODO: Whirlpool Whelm also uses creature targeting but it's trickier to support
CardCollectionView aiCreats = ai.getCreaturesInPlay(); CardCollectionView aiCreats = ai.getCreaturesInPlay();
CardCollectionView oppCreats = CardLists.filter(ai.getOpponents().getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.CREATURES); CardCollectionView oppCreats = CardLists.filter(ai.getOpponents().getCardsIn(ZoneType.Battlefield), CardPredicates.CREATURES);
Card tgt = aiCreats.isEmpty() ? ComputerUtilCard.getWorstCreatureAI(oppCreats) : ComputerUtilCard.getBestCreatureAI(aiCreats); Card tgt = aiCreats.isEmpty() ? ComputerUtilCard.getWorstCreatureAI(oppCreats) : ComputerUtilCard.getBestCreatureAI(aiCreats);

View File

@@ -22,7 +22,6 @@ import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView; import forge.game.card.CardCollectionView;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CardPredicates; import forge.game.card.CardPredicates;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardUtil; import forge.game.card.CardUtil;
import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
@@ -177,7 +176,7 @@ public class CopyPermanentAi extends SpellAbilityAi {
list = CardLists.filter(list, c -> (!c.getType().isLegendary() || canCopyLegendary) || !c.getController().equals(aiPlayer)); list = CardLists.filter(list, c -> (!c.getType().isLegendary() || canCopyLegendary) || !c.getController().equals(aiPlayer));
Card choice; Card choice;
if (Iterables.any(list, Presets.CREATURES)) { if (Iterables.any(list, CardPredicates.CREATURES)) {
if (sa.hasParam("TargetingPlayer")) { if (sa.hasParam("TargetingPlayer")) {
choice = ComputerUtilCard.getWorstCreatureAI(list); choice = ComputerUtilCard.getWorstCreatureAI(list);
} else { } else {

View File

@@ -380,7 +380,7 @@ public class CountersPutAi extends CountersAi {
sa.setXManaCostPaid(amount); sa.setXManaCostPaid(amount);
} else if ("ExiledCreatureFromGraveCMC".equals(logic)) { } else if ("ExiledCreatureFromGraveCMC".equals(logic)) {
// e.g. Necropolis // e.g. Necropolis
amount = Aggregates.max(CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.CREATURES), Card::getCMC); amount = Aggregates.max(CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.CREATURES), Card::getCMC);
if (amount > 0 && ai.getGame().getPhaseHandler().is(PhaseType.END_OF_TURN)) { if (amount > 0 && ai.getGame().getPhaseHandler().is(PhaseType.END_OF_TURN)) {
return true; return true;
} }
@@ -703,7 +703,7 @@ public class CountersPutAi extends CountersAi {
if (sa.isCurse()) { if (sa.isCurse()) {
choice = chooseCursedTarget(list, type, amount, ai); choice = chooseCursedTarget(list, type, amount, ai);
} else { } else {
CardCollection lands = CardLists.filter(list, CardPredicates.Presets.LANDS); CardCollection lands = CardLists.filter(list, CardPredicates.LANDS);
SpellAbility animate = sa.findSubAbilityByType(ApiType.Animate); SpellAbility animate = sa.findSubAbilityByType(ApiType.Animate);
if (!lands.isEmpty() && animate != null) { if (!lands.isEmpty() && animate != null) {
choice = ComputerUtilCard.getWorstLand(lands); choice = ComputerUtilCard.getWorstLand(lands);
@@ -796,7 +796,7 @@ public class CountersPutAi extends CountersAi {
} }
// try to choose player with less creatures // try to choose player with less creatures
Player choice = playerList.min(PlayerPredicates.compareByZoneSize(ZoneType.Battlefield, CardPredicates.Presets.CREATURES)); Player choice = playerList.min(PlayerPredicates.compareByZoneSize(ZoneType.Battlefield, CardPredicates.CREATURES));
if (choice != null) { if (choice != null) {
sa.getTargets().add(choice); sa.getTargets().add(choice);
@@ -1193,7 +1193,7 @@ public class CountersPutAi extends CountersAi {
private boolean doChargeToCMCLogic(Player ai, SpellAbility sa) { private boolean doChargeToCMCLogic(Player ai, SpellAbility sa) {
Card source = sa.getHostCard(); Card source = sa.getHostCard();
CardCollectionView ownLib = CardLists.filter(ai.getCardsIn(ZoneType.Library), CardPredicates.Presets.CREATURES); CardCollectionView ownLib = CardLists.filter(ai.getCardsIn(ZoneType.Library), CardPredicates.CREATURES);
int numCtrs = source.getCounters(CounterEnumType.CHARGE); int numCtrs = source.getCounters(CounterEnumType.CHARGE);
int maxCMC = Aggregates.max(ownLib, Card::getCMC); int maxCMC = Aggregates.max(ownLib, Card::getCMC);
int optimalCMC = 0; int optimalCMC = 0;
@@ -1211,7 +1211,7 @@ public class CountersPutAi extends CountersAi {
private boolean doChargeToOppCtrlCMCLogic(Player ai, SpellAbility sa) { private boolean doChargeToOppCtrlCMCLogic(Player ai, SpellAbility sa) {
Card source = sa.getHostCard(); Card source = sa.getHostCard();
CardCollectionView oppInPlay = CardLists.filter(ai.getOpponents().getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.NONLAND_PERMANENTS); CardCollectionView oppInPlay = CardLists.filter(ai.getOpponents().getCardsIn(ZoneType.Battlefield), CardPredicates.NONLAND_PERMANENTS);
int numCtrs = source.getCounters(CounterEnumType.CHARGE); int numCtrs = source.getCounters(CounterEnumType.CHARGE);
int maxCMC = Aggregates.max(oppInPlay, Card::getCMC); int maxCMC = Aggregates.max(oppInPlay, Card::getCMC);
int optimalCMC = 0; int optimalCMC = 0;

View File

@@ -121,7 +121,7 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
// with one touch // with one touch
CardCollection planeswalkerList = CardLists.filter( CardCollection planeswalkerList = CardLists.filter(
CardLists.filterControlledBy(countersList, ai.getOpponents()), CardLists.filterControlledBy(countersList, ai.getOpponents()),
CardPredicates.Presets.PLANESWALKERS, CardPredicates.PLANESWALKERS,
CardPredicates.hasLessCounter(CounterEnumType.LOYALTY, amount)); CardPredicates.hasLessCounter(CounterEnumType.LOYALTY, amount));
if (!planeswalkerList.isEmpty()) { if (!planeswalkerList.isEmpty()) {

View File

@@ -135,7 +135,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
list = ai.getOpponents().getCardsIn(ZoneType.Battlefield); list = ai.getOpponents().getCardsIn(ZoneType.Battlefield);
list = CardLists.filter(list, CardPredicates.isTargetableBy(sa)); list = CardLists.filter(list, CardPredicates.isTargetableBy(sa));
CardCollection planeswalkerList = CardLists.filter(list, CardPredicates.Presets.PLANESWALKERS, CardCollection planeswalkerList = CardLists.filter(list, CardPredicates.PLANESWALKERS,
CardPredicates.hasCounter(CounterEnumType.LOYALTY, 5)); CardPredicates.hasCounter(CounterEnumType.LOYALTY, 5));
if (!planeswalkerList.isEmpty()) { if (!planeswalkerList.isEmpty()) {
@@ -182,7 +182,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
list = CardLists.filter(list, CardPredicates.isTargetableBy(sa)); list = CardLists.filter(list, CardPredicates.isTargetableBy(sa));
CardCollection planeswalkerList = CardLists.filter(list, CardCollection planeswalkerList = CardLists.filter(list,
CardPredicates.Presets.PLANESWALKERS.and(CardPredicates.isControlledByAnyOf(ai.getOpponents())), CardPredicates.PLANESWALKERS.and(CardPredicates.isControlledByAnyOf(ai.getOpponents())),
CardPredicates.hasLessCounter(CounterEnumType.LOYALTY, amount)); CardPredicates.hasLessCounter(CounterEnumType.LOYALTY, amount));
if (!planeswalkerList.isEmpty()) { if (!planeswalkerList.isEmpty()) {
@@ -222,7 +222,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
// remove P1P1 counters from opposing creatures // remove P1P1 counters from opposing creatures
CardCollection oppP1P1List = CardLists.filter(list, CardCollection oppP1P1List = CardLists.filter(list,
CardPredicates.Presets.CREATURES.and(CardPredicates.isControlledByAnyOf(ai.getOpponents())), CardPredicates.CREATURES.and(CardPredicates.isControlledByAnyOf(ai.getOpponents())),
CardPredicates.hasCounter(CounterEnumType.P1P1)); CardPredicates.hasCounter(CounterEnumType.P1P1));
if (!oppP1P1List.isEmpty()) { if (!oppP1P1List.isEmpty()) {
sa.getTargets().add(ComputerUtilCard.getBestCreatureAI(oppP1P1List)); sa.getTargets().add(ComputerUtilCard.getBestCreatureAI(oppP1P1List));

View File

@@ -28,7 +28,6 @@ import forge.game.staticability.StaticAbilityMustTarget;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.Aggregates; import forge.util.Aggregates;
import forge.util.MyRandom; import forge.util.MyRandom;
import forge.util.Predicates;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
@@ -408,7 +407,7 @@ public class DamageDealAi extends DamageAiBase {
final Player activator = sa.getActivatingPlayer(); final Player activator = sa.getActivatingPlayer();
final Card source = sa.getHostCard(); final Card source = sa.getHostCard();
final Game game = source.getGame(); final Game game = source.getGame();
List<Card> hPlay = CardLists.filter(getTargetableCards(ai, sa, pl, tgt, activator, source, game), CardPredicates.Presets.PLANESWALKERS); List<Card> hPlay = CardLists.filter(getTargetableCards(ai, sa, pl, tgt, activator, source, game), CardPredicates.PLANESWALKERS);
CardCollection killables = CardLists.filter(hPlay, c -> c.getSVar("Targeting").equals("Dies") CardCollection killables = CardLists.filter(hPlay, c -> c.getSVar("Targeting").equals("Dies")
|| (ComputerUtilCombat.getEnoughDamageToKill(c, d, source, false, noPrevention) <= d) || (ComputerUtilCombat.getEnoughDamageToKill(c, d, source, false, noPrevention) <= d)
@@ -892,8 +891,8 @@ public class DamageDealAi extends DamageAiBase {
// See if there's an indestructible target that can be used // See if there's an indestructible target that can be used
CardCollection indestructible = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardCollection indestructible = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield),
CardPredicates.Presets.CREATURES CardPredicates.CREATURES
.and(CardPredicates.Presets.PLANESWALKERS) //TODO: Should this be "or" Planeswalkers? .and(CardPredicates.PLANESWALKERS) //TODO: Should this be "or" Planeswalkers?
.and(CardPredicates.hasKeyword(Keyword.INDESTRUCTIBLE)) .and(CardPredicates.hasKeyword(Keyword.INDESTRUCTIBLE))
.and(CardPredicates.isTargetableBy(sa)) .and(CardPredicates.isTargetableBy(sa))
); );
@@ -909,7 +908,7 @@ public class DamageDealAi extends DamageAiBase {
} }
else if (tgt.canTgtPlaneswalker()) { else if (tgt.canTgtPlaneswalker()) {
// Second pass for planeswalkers: choose AI's worst planeswalker // Second pass for planeswalkers: choose AI's worst planeswalker
final Card c = ComputerUtilCard.getWorstPlaneswalkerToDamage(CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.PLANESWALKERS, CardPredicates.isTargetableBy(sa))); final Card c = ComputerUtilCard.getWorstPlaneswalkerToDamage(CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.PLANESWALKERS, CardPredicates.isTargetableBy(sa)));
if (c != null) { if (c != null) {
sa.getTargets().add(c); sa.getTargets().add(c);
if (divided) { if (divided) {

View File

@@ -126,7 +126,7 @@ public class DamagePreventAi extends SpellAbilityAi {
if (targetables.isEmpty()) { if (targetables.isEmpty()) {
return false; return false;
} }
final CardCollection combatants = CardLists.filter(targetables, CardPredicates.Presets.CREATURES); final CardCollection combatants = CardLists.filter(targetables, CardPredicates.CREATURES);
ComputerUtilCard.sortByEvaluateCreature(combatants); ComputerUtilCard.sortByEvaluateCreature(combatants);
for (final Card c : combatants) { for (final Card c : combatants) {
@@ -187,7 +187,7 @@ public class DamagePreventAi extends SpellAbilityAi {
} }
if (!compTargetables.isEmpty()) { if (!compTargetables.isEmpty()) {
final CardCollection combatants = CardLists.filter(compTargetables, CardPredicates.Presets.CREATURES); final CardCollection combatants = CardLists.filter(compTargetables, CardPredicates.CREATURES);
ComputerUtilCard.sortByEvaluateCreature(combatants); ComputerUtilCard.sortByEvaluateCreature(combatants);
if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) { if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
Combat combat = game.getCombat(); Combat combat = game.getCombat();

View File

@@ -425,8 +425,8 @@ public class DestroyAi extends SpellAbilityAi {
boolean nonBasicTgt = !tgtLand.isBasicLand(); boolean nonBasicTgt = !tgtLand.isBasicLand();
// Try not to lose tempo too much and not to mana-screw yourself when considering this logic // Try not to lose tempo too much and not to mana-screw yourself when considering this logic
int numLandsInHand = CardLists.count(ai.getCardsIn(ZoneType.Hand), CardPredicates.Presets.LANDS_PRODUCING_MANA); int numLandsInHand = CardLists.count(ai.getCardsIn(ZoneType.Hand), CardPredicates.LANDS_PRODUCING_MANA);
int numLandsOTB = CardLists.count(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.LANDS_PRODUCING_MANA); int numLandsOTB = CardLists.count(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.LANDS_PRODUCING_MANA);
// If the opponent skipped a land drop, consider not looking at having the extra land in hand if the profile allows it // If the opponent skipped a land drop, consider not looking at having the extra land in hand if the profile allows it
boolean isHighPriority = highPriorityIfNoLandDrop && oppSkippedLandDrop; boolean isHighPriority = highPriorityIfNoLandDrop && oppSkippedLandDrop;

View File

@@ -109,8 +109,8 @@ public class DestroyAllAi extends SpellAbilityAi {
// Special handling for Raiding Party // Special handling for Raiding Party
if (logic.equals("RaidingParty")) { if (logic.equals("RaidingParty")) {
int numAiCanSave = Math.min(CardLists.count(ai.getCreaturesInPlay(), CardPredicates.isColor(MagicColor.WHITE).and(CardPredicates.Presets.UNTAPPED)) * 2, ailist.size()); int numAiCanSave = Math.min(CardLists.count(ai.getCreaturesInPlay(), CardPredicates.isColor(MagicColor.WHITE).and(CardPredicates.UNTAPPED)) * 2, ailist.size());
int numOppsCanSave = Math.min(CardLists.count(ai.getOpponents().getCreaturesInPlay(), CardPredicates.isColor(MagicColor.WHITE).and(CardPredicates.Presets.UNTAPPED)) * 2, opplist.size()); int numOppsCanSave = Math.min(CardLists.count(ai.getOpponents().getCreaturesInPlay(), CardPredicates.isColor(MagicColor.WHITE).and(CardPredicates.UNTAPPED)) * 2, opplist.size());
return numOppsCanSave < opplist.size() && (ailist.size() - numAiCanSave < opplist.size() - numOppsCanSave); return numOppsCanSave < opplist.size() && (ailist.size() - numAiCanSave < opplist.size() - numOppsCanSave);
} }

View File

@@ -45,7 +45,7 @@ public class DigUntilAi extends SpellAbilityAi {
return false; return false;
} }
if ("Land.Basic".equals(sa.getParam("Valid")) if ("Land.Basic".equals(sa.getParam("Valid"))
&& ai.getZone(ZoneType.Hand).contains(CardPredicates.Presets.LANDS_PRODUCING_MANA)) { && ai.getZone(ZoneType.Hand).contains(CardPredicates.LANDS_PRODUCING_MANA)) {
// We already have a mana-producing land in hand, so bail // We already have a mana-producing land in hand, so bail
// until opponent's end of turn phase! // until opponent's end of turn phase!
// But we still want more (and want to fill grave) if nothing better to do then // But we still want more (and want to fill grave) if nothing better to do then
@@ -128,7 +128,7 @@ public class DigUntilAi extends SpellAbilityAi {
final String logic = sa.getParam("AILogic"); final String logic = sa.getParam("AILogic");
if ("OathOfDruids".equals(logic)) { if ("OathOfDruids".equals(logic)) {
final List<Card> creaturesInLibrary = final List<Card> creaturesInLibrary =
CardLists.filter(player.getCardsIn(ZoneType.Library), CardPredicates.Presets.CREATURES); CardLists.filter(player.getCardsIn(ZoneType.Library), CardPredicates.CREATURES);
final List<Card> creaturesInBattlefield = player.getCreaturesInPlay(); final List<Card> creaturesInBattlefield = player.getCreaturesInPlay();
// if there are at least 3 creatures in library, // if there are at least 3 creatures in library,
// or none in play with one in library, oath // or none in play with one in library, oath

View File

@@ -94,7 +94,7 @@ public class DiscardAi extends SpellAbilityAi {
if (sa.hasParam("AnyNumber")) { if (sa.hasParam("AnyNumber")) {
if ("DiscardUncastableAndExcess".equals(aiLogic)) { if ("DiscardUncastableAndExcess".equals(aiLogic)) {
final CardCollectionView inHand = ai.getCardsIn(ZoneType.Hand); final CardCollectionView inHand = ai.getCardsIn(ZoneType.Hand);
final int numLandsOTB = CardLists.count(ai.getCardsIn(ZoneType.Hand), CardPredicates.Presets.LANDS); final int numLandsOTB = CardLists.count(ai.getCardsIn(ZoneType.Hand), CardPredicates.LANDS);
int numDiscard = 0; int numDiscard = 0;
int numOppInHand = 0; int numOppInHand = 0;
for (Player p : ai.getGame().getPlayers()) { for (Player p : ai.getGame().getPlayers()) {

View File

@@ -8,7 +8,6 @@ import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.*; import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.combat.Combat; import forge.game.combat.Combat;
import forge.game.combat.CombatUtil; import forge.game.combat.CombatUtil;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
@@ -56,8 +55,8 @@ public class EffectAi extends SpellAbilityAi {
for (Player opp : ai.getOpponents()) { for (Player opp : ai.getOpponents()) {
boolean worthHolding = false; boolean worthHolding = false;
CardCollectionView oppCreatsLands = CardLists.filter(opp.getCardsIn(ZoneType.Battlefield), CardCollectionView oppCreatsLands = CardLists.filter(opp.getCardsIn(ZoneType.Battlefield),
Presets.LANDS.or(Presets.CREATURES)); CardPredicates.LANDS.or(CardPredicates.CREATURES));
CardCollectionView oppCreatsLandsTapped = CardLists.filter(oppCreatsLands, CardPredicates.Presets.TAPPED); CardCollectionView oppCreatsLandsTapped = CardLists.filter(oppCreatsLands, CardPredicates.TAPPED);
if (oppCreatsLandsTapped.size() >= 3 || oppCreatsLands.size() == oppCreatsLandsTapped.size()) { if (oppCreatsLandsTapped.size() >= 3 || oppCreatsLands.size() == oppCreatsLandsTapped.size()) {
worthHolding = true; worthHolding = true;
@@ -83,7 +82,7 @@ public class EffectAi extends SpellAbilityAi {
Player opp = ai.getStrongestOpponent(); Player opp = ai.getStrongestOpponent();
List<Card> possibleAttackers = ai.getCreaturesInPlay(); List<Card> possibleAttackers = ai.getCreaturesInPlay();
List<Card> possibleBlockers = opp.getCreaturesInPlay(); List<Card> possibleBlockers = opp.getCreaturesInPlay();
possibleBlockers = CardLists.filter(possibleBlockers, Presets.UNTAPPED); possibleBlockers = CardLists.filter(possibleBlockers, CardPredicates.UNTAPPED);
final Combat combat = game.getCombat(); final Combat combat = game.getCombat();
int oppLife = opp.getLife(); int oppLife = opp.getLife();
int potentialDmg = 0; int potentialDmg = 0;
@@ -332,7 +331,7 @@ public class EffectAi extends SpellAbilityAi {
} else if (logic.equals("CantRegenerate")) { } else if (logic.equals("CantRegenerate")) {
if (sa.usesTargeting()) { if (sa.usesTargeting()) {
CardCollection list = CardLists.getTargetableCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), sa); CardCollection list = CardLists.getTargetableCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), sa);
list = CardLists.filter(list, CardPredicates.Presets.CAN_BE_DESTROYED, input -> { list = CardLists.filter(list, CardPredicates.CAN_BE_DESTROYED, input -> {
Map<AbilityKey, Object> runParams = AbilityKey.mapFromAffected(input); Map<AbilityKey, Object> runParams = AbilityKey.mapFromAffected(input);
runParams.put(AbilityKey.Regeneration, true); runParams.put(AbilityKey.Regeneration, true);
List<ReplacementEffect> repDestoryList = game.getReplacementHandler().getReplacementList(ReplacementType.Destroy, runParams, ReplacementLayer.Other); List<ReplacementEffect> repDestoryList = game.getReplacementHandler().getReplacementList(ReplacementType.Destroy, runParams, ReplacementLayer.Other);

View File

@@ -43,8 +43,8 @@ public class ExploreAi extends SpellAbilityAi {
int predictedMana = ComputerUtilMana.getAvailableManaSources(ai, false).size(); int predictedMana = ComputerUtilMana.getAvailableManaSources(ai, false).size();
CardCollectionView cardsOTB = ai.getCardsIn(ZoneType.Battlefield); CardCollectionView cardsOTB = ai.getCardsIn(ZoneType.Battlefield);
CardCollectionView cardsInHand = ai.getCardsIn(ZoneType.Hand); CardCollectionView cardsInHand = ai.getCardsIn(ZoneType.Hand);
CardCollection landsOTB = CardLists.filter(cardsOTB, CardPredicates.Presets.LANDS_PRODUCING_MANA); CardCollection landsOTB = CardLists.filter(cardsOTB, CardPredicates.LANDS_PRODUCING_MANA);
CardCollection landsInHand = CardLists.filter(cardsInHand, CardPredicates.Presets.LANDS_PRODUCING_MANA); CardCollection landsInHand = CardLists.filter(cardsInHand, CardPredicates.LANDS_PRODUCING_MANA);
int maxCMCDiff = 1; int maxCMCDiff = 1;
int numLandsToStillNeedMore = 2; int numLandsToStillNeedMore = 2;

View File

@@ -20,7 +20,7 @@ public class HauntAi extends SpellAbilityAi {
final Game game = ai.getGame(); final Game game = ai.getGame();
if (sa.usesTargeting() && !card.isToken()) { if (sa.usesTargeting() && !card.isToken()) {
final List<Card> creats = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), final List<Card> creats = CardLists.filter(game.getCardsIn(ZoneType.Battlefield),
CardPredicates.Presets.CREATURES); CardPredicates.CREATURES);
// nothing to haunt // nothing to haunt
if (creats.isEmpty()) { if (creats.isEmpty()) {

View File

@@ -37,7 +37,7 @@ public class MillAi extends SpellAbilityAi {
return ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn().equals(ai); return ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn().equals(ai);
} 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
return CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.CREATURES).size() >= 1; return CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.CREATURES).size() >= 1;
} }
return true; return true;
} }

View File

@@ -140,8 +140,8 @@ public class PermanentAi extends SpellAbilityAi {
&& card.getState(CardStateName.Original).getManaCost() != null && card.getState(CardStateName.Original).getManaCost() != null
&& card.getState(CardStateName.Original).getManaCost().getCMC() == manaValue); && card.getState(CardStateName.Original).getManaCost().getCMC() == manaValue);
if (manaValue == 0) { if (manaValue == 0) {
aiCards = CardLists.filter(aiCards, CardPredicates.Presets.NON_LANDS); aiCards = CardLists.filter(aiCards, CardPredicates.NON_LANDS);
oppCards = CardLists.filter(oppCards, CardPredicates.Presets.NON_LANDS); oppCards = CardLists.filter(oppCards, CardPredicates.NON_LANDS);
// also filter out other Chalices in our own deck // also filter out other Chalices in our own deck
aiCards = CardLists.filter(aiCards, CardPredicates.nameNotEquals("Chalice of the Void")); aiCards = CardLists.filter(aiCards, CardPredicates.nameNotEquals("Chalice of the Void"));
} }
@@ -257,7 +257,7 @@ public class PermanentAi extends SpellAbilityAi {
// Only cast if there are X or more mana sources controlled by the AI *or* // Only cast if there are X or more mana sources controlled by the AI *or*
// if there are X-1 mana sources in play but the AI has an extra land in hand // if there are X-1 mana sources in play but the AI has an extra land in hand
CardCollection m = ComputerUtilMana.getAvailableManaSources(ai, true); CardCollection m = ComputerUtilMana.getAvailableManaSources(ai, true);
int extraMana = CardLists.count(ai.getCardsIn(ZoneType.Hand), CardPredicates.Presets.LANDS) > 0 ? 1 : 0; int extraMana = CardLists.count(ai.getCardsIn(ZoneType.Hand), CardPredicates.LANDS) > 0 ? 1 : 0;
if (source.getName().equals("Illusions of Grandeur")) { if (source.getName().equals("Illusions of Grandeur")) {
// TODO: this is currently hardcoded for specific Illusions-Donate cost reduction spells, need to make this generic. // TODO: this is currently hardcoded for specific Illusions-Donate cost reduction spells, need to make this generic.
extraMana += Math.min(3, CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.nameEquals("Sapphire Medallion").or(CardPredicates.nameEquals("Helm of Awakening"))).size()) * 2; // each cost-reduction spell accounts for {1} in both Illusions and Donate extraMana += Math.min(3, CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.nameEquals("Sapphire Medallion").or(CardPredicates.nameEquals("Helm of Awakening"))).size()) * 2; // each cost-reduction spell accounts for {1} in both Illusions and Donate

View File

@@ -8,7 +8,6 @@ import forge.game.Game;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.*; import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.cost.Cost; import forge.game.cost.Cost;
import forge.game.cost.CostTapType; import forge.game.cost.CostTapType;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
@@ -402,7 +401,7 @@ public class PumpAi extends PumpAiBase {
CardCollection list; CardCollection list;
if (sa.hasParam("AILogic")) { if (sa.hasParam("AILogic")) {
if (sa.getParam("AILogic").equals("HighestPower") || sa.getParam("AILogic").equals("ContinuousBonus")) { if (sa.getParam("AILogic").equals("HighestPower") || sa.getParam("AILogic").equals("ContinuousBonus")) {
list = CardLists.getValidCards(CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.CREATURES), tgt.getValidTgts(), ai, source, sa); list = CardLists.getValidCards(CardLists.filter(game.getCardsIn(ZoneType.Battlefield), CardPredicates.CREATURES), tgt.getValidTgts(), ai, source, sa);
list = CardLists.getTargetableCards(list, sa); list = CardLists.getTargetableCards(list, sa);
CardLists.sortByPowerDesc(list); CardLists.sortByPowerDesc(list);
@@ -511,7 +510,7 @@ public class PumpAi extends PumpAiBase {
// Detain target nonland permanent: don't target noncreature permanents that don't have // Detain target nonland permanent: don't target noncreature permanents that don't have
// any activated abilities. // any activated abilities.
if ("DetainNonLand".equals(sa.getParam("AILogic"))) { if ("DetainNonLand".equals(sa.getParam("AILogic"))) {
list = CardLists.filter(list, Presets.CREATURES.or(card -> { list = CardLists.filter(list, CardPredicates.CREATURES.or(card -> {
for (SpellAbility sa1 : card.getSpellAbilities()) { for (SpellAbility sa1 : card.getSpellAbilities()) {
if (sa1.isActivatedAbility()) { if (sa1.isActivatedAbility()) {
return true; return true;

View File

@@ -115,7 +115,7 @@ public class RearrangeTopOfLibraryAi extends SpellAbilityAi {
uncastableCMCThreshold = aic.getIntProperty(AiProps.SCRY_IMMEDIATELY_UNCASTABLE_CMC_DIFF); uncastableCMCThreshold = aic.getIntProperty(AiProps.SCRY_IMMEDIATELY_UNCASTABLE_CMC_DIFF);
} }
int landsOTB = CardLists.count(p.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.LANDS_PRODUCING_MANA); int landsOTB = CardLists.count(p.getCardsIn(ZoneType.Battlefield), CardPredicates.LANDS_PRODUCING_MANA);
int cmc = top.isSplitCard() ? Math.min(top.getCMC(Card.SplitCMCMode.LeftSplitCMC), top.getCMC(Card.SplitCMCMode.RightSplitCMC)) int cmc = top.isSplitCard() ? Math.min(top.getCMC(Card.SplitCMCMode.LeftSplitCMC), top.getCMC(Card.SplitCMCMode.RightSplitCMC))
: top.getCMC(); : top.getCMC();
int maxCastable = ComputerUtilMana.getAvailableManaEstimate(p, false); int maxCastable = ComputerUtilMana.getAvailableManaEstimate(p, false);

View File

@@ -82,7 +82,7 @@ public class RegenerateAi extends SpellAbilityAi {
chance = true; chance = true;
} }
} else if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) { } else if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
final CardCollection combatants = CardLists.filter(targetables, CardPredicates.Presets.CREATURES); final CardCollection combatants = CardLists.filter(targetables, CardPredicates.CREATURES);
ComputerUtilCard.sortByEvaluateCreature(combatants); ComputerUtilCard.sortByEvaluateCreature(combatants);
for (final Card c : combatants) { for (final Card c : combatants) {
@@ -156,7 +156,7 @@ public class RegenerateAi extends SpellAbilityAi {
} }
if (compTargetables.size() > 0) { if (compTargetables.size() > 0) {
final CardCollection combatants = CardLists.filter(compTargetables, CardPredicates.Presets.CREATURES); final CardCollection combatants = CardLists.filter(compTargetables, CardPredicates.CREATURES);
ComputerUtilCard.sortByEvaluateCreature(combatants); ComputerUtilCard.sortByEvaluateCreature(combatants);
if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) { if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
Combat combat = game.getCombat(); Combat combat = game.getCombat();

View File

@@ -8,7 +8,6 @@ import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi; import forge.ai.SpellAbilityAi;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.card.*; import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
@@ -30,7 +29,7 @@ public class RepeatEachAi extends SpellAbilityAi {
} else if ("Never".equals(logic)) { } else if ("Never".equals(logic)) {
return false; return false;
} else if ("CloneAllTokens".equals(logic)) { } else if ("CloneAllTokens".equals(logic)) {
List<Card> humTokenCreats = CardLists.filter(aiPlayer.getOpponents().getCreaturesInPlay(), Presets.TOKEN); List<Card> humTokenCreats = CardLists.filter(aiPlayer.getOpponents().getCreaturesInPlay(), CardPredicates.TOKEN);
List<Card> compTokenCreats = aiPlayer.getTokensInPlay(); List<Card> compTokenCreats = aiPlayer.getTokensInPlay();
return compTokenCreats.size() > humTokenCreats.size(); return compTokenCreats.size() > humTokenCreats.size();

View File

@@ -99,7 +99,7 @@ public class ScryAi extends SpellAbilityAi {
private boolean doBestOpportunityLogic(Player ai, SpellAbility sa, PhaseHandler ph) { private boolean doBestOpportunityLogic(Player ai, SpellAbility sa, PhaseHandler ph) {
// Check to see if there are any cards in hand that may be worth casting // Check to see if there are any cards in hand that may be worth casting
boolean hasSomethingElse = false; boolean hasSomethingElse = false;
for (Card c : CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.Presets.NON_LANDS)) { for (Card c : CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.NON_LANDS)) {
for (SpellAbility ab : c.getAllSpellAbilities()) { for (SpellAbility ab : c.getAllSpellAbilities()) {
if (ab.getPayCosts().hasManaCost() if (ab.getPayCosts().hasManaCost()
&& ComputerUtilMana.hasEnoughManaSourcesToCast(ab, ai)) { && ComputerUtilMana.hasEnoughManaSourcesToCast(ab, ai)) {

View File

@@ -73,7 +73,7 @@ public class SetStateAi extends SpellAbilityAi {
sa.resetTargets(); sa.resetTargets();
// select only the ones that can transform // select only the ones that can transform
CardCollection list = CardLists.filter(CardUtil.getValidCardsToTarget(sa), CardPredicates.Presets.CREATURES, c -> c.canTransform(sa)); CardCollection list = CardLists.filter(CardUtil.getValidCardsToTarget(sa), CardPredicates.CREATURES, c -> c.canTransform(sa));
if (list.isEmpty()) { if (list.isEmpty()) {
return false; return false;

View File

@@ -15,7 +15,6 @@ import forge.game.card.Card;
import forge.game.card.CardCollection; import forge.game.card.CardCollection;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CardPredicates; import forge.game.card.CardPredicates;
import forge.game.card.CardPredicates.Presets;
import forge.game.combat.CombatUtil; import forge.game.combat.CombatUtil;
import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
@@ -107,7 +106,7 @@ public abstract class TapAiBase extends SpellAbilityAi {
protected boolean tapPrefTargeting(final Player ai, final Card source, final SpellAbility sa, final boolean mandatory) { protected boolean tapPrefTargeting(final Player ai, final Card source, final SpellAbility sa, final boolean mandatory) {
final Game game = ai.getGame(); final Game game = ai.getGame();
CardCollection tapList = CardLists.getTargetableCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), sa); CardCollection tapList = CardLists.getTargetableCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), sa);
tapList = CardLists.filter(tapList, Presets.CAN_TAP); tapList = CardLists.filter(tapList, CardPredicates.CAN_TAP);
tapList = CardLists.filter(tapList, c -> { tapList = CardLists.filter(tapList, c -> {
if (c.isCreature()) { if (c.isCreature()) {
return true; return true;
@@ -196,7 +195,7 @@ public abstract class TapAiBase extends SpellAbilityAi {
} else if (phase.isPlayerTurn(opp) } else if (phase.isPlayerTurn(opp)
&& phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) { && phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
// Tap creatures possible blockers before combat during AI's turn. // Tap creatures possible blockers before combat during AI's turn.
if (Iterables.any(tapList, CardPredicates.Presets.CREATURES)) { if (Iterables.any(tapList, CardPredicates.CREATURES)) {
List<Card> creatureList = CardLists.filter(tapList, c -> c.isCreature() && CombatUtil.canAttack(c, opp)); List<Card> creatureList = CardLists.filter(tapList, c -> c.isCreature() && CombatUtil.canAttack(c, opp));
choice = ComputerUtilCard.getBestCreatureAI(creatureList); choice = ComputerUtilCard.getBestCreatureAI(creatureList);
} else { // no creatures available } else { // no creatures available
@@ -264,7 +263,7 @@ public abstract class TapAiBase extends SpellAbilityAi {
} }
// try to just tap already tapped things // try to just tap already tapped things
tapList = CardLists.filter(list, Presets.TAPPED); tapList = CardLists.filter(list, CardPredicates.TAPPED);
if (tapTargetList(ai, sa, tapList, mandatory)) { if (tapTargetList(ai, sa, tapList, mandatory)) {
return true; return true;

View File

@@ -45,7 +45,7 @@ public class TapAllAi extends SpellAbilityAi {
} }
validTappables = CardLists.getValidCards(validTappables, valid, source.getController(), source, sa); validTappables = CardLists.getValidCards(validTappables, valid, source.getController(), source, sa);
validTappables = CardLists.filter(validTappables, CardPredicates.Presets.UNTAPPED); validTappables = CardLists.filter(validTappables, CardPredicates.UNTAPPED);
if (sa.hasParam("AILogic")) { if (sa.hasParam("AILogic")) {
String logic = sa.getParam("AILogic"); String logic = sa.getParam("AILogic");
@@ -83,7 +83,7 @@ public class TapAllAi extends SpellAbilityAi {
final Game game = source.getGame(); final Game game = source.getGame();
CardCollectionView tmpList = game.getCardsIn(ZoneType.Battlefield); CardCollectionView tmpList = game.getCardsIn(ZoneType.Battlefield);
tmpList = CardLists.getValidCards(tmpList, valid, source.getController(), source, sa); tmpList = CardLists.getValidCards(tmpList, valid, source.getController(), source, sa);
tmpList = CardLists.filter(tmpList, CardPredicates.Presets.UNTAPPED); tmpList = CardLists.filter(tmpList, CardPredicates.UNTAPPED);
return tmpList; return tmpList;
} }

View File

@@ -8,7 +8,7 @@ import forge.game.ability.ApiType;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCollection; import forge.game.card.CardCollection;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CardPredicates.Presets; import forge.game.card.CardPredicates;
import forge.game.combat.Combat; import forge.game.combat.Combat;
import forge.game.cost.Cost; import forge.game.cost.Cost;
import forge.game.cost.CostTap; import forge.game.cost.CostTap;
@@ -155,7 +155,7 @@ public class UntapAi extends SpellAbilityAi {
} }
} }
CardCollection untapList = targetUntapped ? list : CardLists.filter(list, Presets.TAPPED); CardCollection untapList = targetUntapped ? list : CardLists.filter(list, CardPredicates.TAPPED);
// filter out enchantments and planeswalkers, their tapped state doesn't matter. // filter out enchantments and planeswalkers, their tapped state doesn't matter.
final String[] tappablePermanents = {"Creature", "Land", "Artifact"}; final String[] tappablePermanents = {"Creature", "Land", "Artifact"};
untapList = CardLists.getValidCards(untapList, tappablePermanents, source.getController(), source, sa); untapList = CardLists.getValidCards(untapList, tappablePermanents, source.getController(), source, sa);
@@ -260,7 +260,7 @@ public class UntapAi extends SpellAbilityAi {
} }
// try to just tap already tapped things // try to just tap already tapped things
tapList = CardLists.filter(list, Presets.UNTAPPED); tapList = CardLists.filter(list, CardPredicates.UNTAPPED);
if (untapTargetList(source, tgt, sa, mandatory, tapList)) { if (untapTargetList(source, tgt, sa, mandatory, tapList)) {
return true; return true;
@@ -400,10 +400,10 @@ public class UntapAi extends SpellAbilityAi {
} }
// Check if something is playable if we untap for an additional mana with this, then proceed // Check if something is playable if we untap for an additional mana with this, then proceed
CardCollection inHand = CardLists.filter(ai.getCardsIn(ZoneType.Hand), Presets.NON_LANDS); CardCollection inHand = CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.NON_LANDS);
// The AI is not very good at timing non-permanent spells this way, so filter them out // The AI is not very good at timing non-permanent spells this way, so filter them out
// (it may actually be possible to enable this for sorceries, but that'll need some canPlay shenanigans) // (it may actually be possible to enable this for sorceries, but that'll need some canPlay shenanigans)
CardCollection playable = CardLists.filter(inHand, Presets.PERMANENTS); CardCollection playable = CardLists.filter(inHand, CardPredicates.PERMANENTS);
CardCollection untappingCards = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), card -> { CardCollection untappingCards = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), card -> {
boolean hasUntapLandLogic = false; boolean hasUntapLandLogic = false;
@@ -427,7 +427,7 @@ public class UntapAi extends SpellAbilityAi {
reduced.decreaseShard(ManaCostShard.GENERIC, untappingCards.size()); reduced.decreaseShard(ManaCostShard.GENERIC, untappingCards.size());
if (ComputerUtilMana.canPayManaCost(reduced, ab, ai, false)) { if (ComputerUtilMana.canPayManaCost(reduced, ab, ai, false)) {
CardCollection manaLandsTapped = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardCollection manaLandsTapped = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield),
Presets.LANDS_PRODUCING_MANA, Presets.TAPPED); CardPredicates.LANDS_PRODUCING_MANA, CardPredicates.TAPPED);
manaLandsTapped = CardLists.getValidCards(manaLandsTapped, sa.getParam("ValidTgts"), ai, source, null); manaLandsTapped = CardLists.getValidCards(manaLandsTapped, sa.getParam("ValidTgts"), ai, source, null);
if (!manaLandsTapped.isEmpty()) { if (!manaLandsTapped.isEmpty()) {
@@ -437,7 +437,7 @@ public class UntapAi extends SpellAbilityAi {
// pool one additional mana by tapping a land to try to ramp to something // pool one additional mana by tapping a land to try to ramp to something
CardCollection manaLands = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardCollection manaLands = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield),
Presets.LANDS_PRODUCING_MANA, Presets.CAN_TAP); CardPredicates.LANDS_PRODUCING_MANA, CardPredicates.CAN_TAP);
manaLands = CardLists.getValidCards(manaLands, sa.getParam("ValidTgts"), ai, source, null); manaLands = CardLists.getValidCards(manaLands, sa.getParam("ValidTgts"), ai, source, null);
if (manaLands.isEmpty()) { if (manaLands.isEmpty()) {

View File

@@ -24,7 +24,7 @@ public class UntapAllAi extends SpellAbilityAi {
&& source.getGame().getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_END)) { && source.getGame().getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_END)) {
return false; return false;
} }
CardCollectionView list = CardLists.filter(aiPlayer.getGame().getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.TAPPED); CardCollectionView list = CardLists.filter(aiPlayer.getGame().getCardsIn(ZoneType.Battlefield), CardPredicates.TAPPED);
final String valid = sa.getParamOrDefault("ValidCards", ""); final String valid = sa.getParamOrDefault("ValidCards", "");
list = CardLists.getValidCards(list, valid, source.getController(), source, sa); list = CardLists.getValidCards(list, valid, source.getController(), source, sa);
// don't untap if only opponent benefits // don't untap if only opponent benefits
@@ -39,7 +39,7 @@ public class UntapAllAi extends SpellAbilityAi {
if (sa.hasParam("ValidCards")) { if (sa.hasParam("ValidCards")) {
String valid = sa.getParam("ValidCards"); String valid = sa.getParam("ValidCards");
CardCollectionView list = CardLists.filter(aiPlayer.getGame().getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.TAPPED); CardCollectionView list = CardLists.filter(aiPlayer.getGame().getCardsIn(ZoneType.Battlefield), CardPredicates.TAPPED);
list = CardLists.getValidCards(list, valid, source.getController(), source, sa); list = CardLists.getValidCards(list, valid, source.getController(), source, sa);
return mandatory || !list.isEmpty(); return mandatory || !list.isEmpty();
} }

View File

@@ -133,21 +133,9 @@ public final class CardFacePredicates {
return new ValidPredicate(val); return new ValidPredicate(val);
} }
public static class Presets {
/** The Constant isBasicLand. */
public static final Predicate<ICardFace> IS_BASIC_LAND = subject -> subject.getType().isBasicLand(); public static final Predicate<ICardFace> IS_BASIC_LAND = subject -> subject.getType().isBasicLand();
/** The Constant isNonBasicLand. */
public static final Predicate<ICardFace> IS_NONBASIC_LAND = subject -> subject.getType().isLand() && !subject.getType().isBasicLand(); public static final Predicate<ICardFace> IS_NONBASIC_LAND = subject -> subject.getType().isLand() && !subject.getType().isBasicLand();
public static final Predicate<ICardFace> IS_CREATURE = CardFacePredicates.coreType(true, CardType.CoreType.Creature);
/** The Constant isCreature. */ public static final Predicate<ICardFace> IS_LEGENDARY = CardFacePredicates.superType(true, CardType.Supertype.Legendary);
public static final Predicate<ICardFace> IS_CREATURE = CardFacePredicates public static final Predicate<ICardFace> IS_NON_LAND = CardFacePredicates.coreType(false, CardType.CoreType.Land);
.coreType(true, CardType.CoreType.Creature);
public static final Predicate<ICardFace> IS_LEGENDARY = CardFacePredicates
.superType(true, CardType.Supertype.Legendary);
public static final Predicate<ICardFace> IS_NON_LAND = CardFacePredicates
.coreType(false, CardType.CoreType.Land);
}
} }

View File

@@ -12,13 +12,8 @@ import org.apache.commons.lang3.StringUtils;
*/ */
public final class CardRulesPredicates { public final class CardRulesPredicates {
/** The Constant isKeptInAiDecks. */
public static final Predicate<CardRules> IS_KEPT_IN_AI_DECKS = card -> !card.getAiHints().getRemAIDecks(); public static final Predicate<CardRules> IS_KEPT_IN_AI_DECKS = card -> !card.getAiHints().getRemAIDecks();
/** The Constant isKeptInAiLimitedDecks. */
public static final Predicate<CardRules> IS_KEPT_IN_AI_LIMITED_DECKS = card -> !card.getAiHints().getRemAIDecks() && !card.getAiHints().getRemNonCommanderDecks(); public static final Predicate<CardRules> IS_KEPT_IN_AI_LIMITED_DECKS = card -> !card.getAiHints().getRemAIDecks() && !card.getAiHints().getRemNonCommanderDecks();
/** The Constant isKeptInRandomDecks. */
public static final Predicate<CardRules> IS_KEPT_IN_RANDOM_DECKS = card -> !card.getAiHints().getRemRandomDecks(); public static final Predicate<CardRules> IS_KEPT_IN_RANDOM_DECKS = card -> !card.getAiHints().getRemRandomDecks();
// Static builder methods - they choose concrete implementation by themselves // Static builder methods - they choose concrete implementation by themselves
@@ -524,52 +519,36 @@ public final class CardRulesPredicates {
} }
} }
/** public static final Predicate<CardRules> IS_CREATURE = CardRulesPredicates.coreType(true, CardType.CoreType.Creature);
* The Class Presets. public static final Predicate<CardRules> IS_LEGENDARY = CardRulesPredicates.superType(true, CardType.Supertype.Legendary);
*/ public static final Predicate<CardRules> IS_ARTIFACT = CardRulesPredicates.coreType(true, CardType.CoreType.Artifact);
public static class Presets { public static final Predicate<CardRules> IS_ATTRACTION = CardRulesPredicates.IS_ARTIFACT.and(CardRulesPredicates.subType("Attraction"));
public static final Predicate<CardRules> IS_EQUIPMENT = CardRulesPredicates.subType("Equipment");
/** The Constant isCreature. */
public static final Predicate<CardRules> IS_CREATURE = CardRulesPredicates
.coreType(true, CardType.CoreType.Creature);
public static final Predicate<CardRules> IS_LEGENDARY = CardRulesPredicates
.superType(true, CardType.Supertype.Legendary);
/** The Constant isArtifact. */
public static final Predicate<CardRules> IS_ARTIFACT = CardRulesPredicates
.coreType(true, CardType.CoreType.Artifact);
/** The Constant isEquipment. */
public static final Predicate<CardRules> IS_EQUIPMENT = CardRulesPredicates
.subType("Equipment");
/** The Constant isLand. */
public static final Predicate<CardRules> IS_LAND = CardRulesPredicates.coreType(true, CardType.CoreType.Land); public static final Predicate<CardRules> IS_LAND = CardRulesPredicates.coreType(true, CardType.CoreType.Land);
/** The Constant isBasicLand. */
public static final Predicate<CardRules> IS_BASIC_LAND = subject -> subject.getType().isBasicLand(); public static final Predicate<CardRules> IS_BASIC_LAND = subject -> subject.getType().isBasicLand();
public static final Predicate<CardRules> NOT_BASIC_LAND = subject -> !subject.getType().isBasicLand(); public static final Predicate<CardRules> NOT_BASIC_LAND = subject -> !subject.getType().isBasicLand();
/** Matches only Plains, Island, Swamp, Mountain, or Forest. */ /** Matches only Plains, Island, Swamp, Mountain, or Forest. */
public static final Predicate<CardRules> IS_BASIC_LAND_NOT_WASTES = subject -> !subject.getName().equals("Wastes")&&subject.getType().isBasicLand(); public static final Predicate<CardRules> IS_TRUE_BASIC_LAND = subject -> !subject.getName().equals("Wastes")&&subject.getType().isBasicLand();
/** Matches any card except Plains, Island, Swamp, Mountain, or Forest. */ /** Matches any card except Plains, Island, Swamp, Mountain, or Forest. */
public static final Predicate<CardRules> NOT_TRUE_BASIC_LAND = subject -> !subject.getType().isBasicLand() || subject.getName().equals("Wastes"); public static final Predicate<CardRules> NOT_TRUE_BASIC_LAND = subject -> !subject.getType().isBasicLand() || subject.getName().equals("Wastes");
/** The Constant isNonBasicLand. */
public static final Predicate<CardRules> IS_NONBASIC_LAND = subject -> subject.getType().isLand() && !subject.getType().isBasicLand(); public static final Predicate<CardRules> IS_NONBASIC_LAND = subject -> subject.getType().isLand() && !subject.getType().isBasicLand();
public static final Predicate<CardRules> CAN_BE_COMMANDER = CardRules::canBeCommander; public static final Predicate<CardRules> CAN_BE_COMMANDER = CardRules::canBeCommander;
public static final Predicate<CardRules> CAN_BE_PARTNER_COMMANDER = CardRules::canBePartnerCommander; public static final Predicate<CardRules> CAN_BE_PARTNER_COMMANDER = CardRules::canBePartnerCommander;
public static final Predicate<CardRules> CAN_BE_OATHBREAKER = CardRules::canBeOathbreaker; public static final Predicate<CardRules> CAN_BE_OATHBREAKER = CardRules::canBeOathbreaker;
public static final Predicate<CardRules> CAN_BE_SIGNATURE_SPELL = CardRules::canBeSignatureSpell; public static final Predicate<CardRules> CAN_BE_SIGNATURE_SPELL = CardRules::canBeSignatureSpell;
public static final Predicate<CardRules> IS_PLANESWALKER = CardRulesPredicates.coreType(true, CardType.CoreType.Planeswalker); public static final Predicate<CardRules> IS_PLANESWALKER = CardRulesPredicates.coreType(true, CardType.CoreType.Planeswalker);
public static final Predicate<CardRules> CAN_BE_TINY_LEADERS_COMMANDER = CardRulesPredicates.IS_LEGENDARY.and(CardRulesPredicates.IS_CREATURE.or(CardRulesPredicates.IS_PLANESWALKER));
public static final Predicate<CardRules> CAN_BE_BRAWL_COMMANDER = CardRulesPredicates.IS_LEGENDARY.and(CardRulesPredicates.IS_CREATURE.or(CardRulesPredicates.IS_PLANESWALKER));
public static final Predicate<CardRules> IS_BATTLE = CardRulesPredicates.coreType(true, CardType.CoreType.Battle); public static final Predicate<CardRules> IS_BATTLE = CardRulesPredicates.coreType(true, CardType.CoreType.Battle);
public static final Predicate<CardRules> IS_INSTANT = CardRulesPredicates.coreType(true, CardType.CoreType.Instant); public static final Predicate<CardRules> IS_INSTANT = CardRulesPredicates.coreType(true, CardType.CoreType.Instant);
public static final Predicate<CardRules> IS_SORCERY = CardRulesPredicates.coreType(true, CardType.CoreType.Sorcery); public static final Predicate<CardRules> IS_SORCERY = CardRulesPredicates.coreType(true, CardType.CoreType.Sorcery);
public static final Predicate<CardRules> IS_ENCHANTMENT = CardRulesPredicates.coreType(true, CardType.CoreType.Enchantment); public static final Predicate<CardRules> IS_ENCHANTMENT = CardRulesPredicates.coreType(true, CardType.CoreType.Enchantment);
public static final Predicate<CardRules> IS_NON_CREATURE_SPELL =
CardRulesPredicates.IS_SORCERY
.or(CardRulesPredicates.IS_INSTANT)
.or(CardRulesPredicates.IS_PLANESWALKER)
.or(CardRulesPredicates.IS_ENCHANTMENT) //TODO: Battles? Is testing these one by one really the best way to check "non-creature"?
.or(CardRulesPredicates.IS_ARTIFACT.and(CardRulesPredicates.IS_CREATURE.negate()));
public static final Predicate<CardRules> IS_PLANE = CardRulesPredicates.coreType(true, CardType.CoreType.Plane); public static final Predicate<CardRules> IS_PLANE = CardRulesPredicates.coreType(true, CardType.CoreType.Plane);
public static final Predicate<CardRules> IS_PHENOMENON = CardRulesPredicates.coreType(true, CardType.CoreType.Phenomenon); public static final Predicate<CardRules> IS_PHENOMENON = CardRulesPredicates.coreType(true, CardType.CoreType.Phenomenon);
public static final Predicate<CardRules> IS_PLANE_OR_PHENOMENON = IS_PLANE.or(IS_PHENOMENON); public static final Predicate<CardRules> IS_PLANE_OR_PHENOMENON = IS_PLANE.or(IS_PHENOMENON);
@@ -577,53 +556,13 @@ public final class CardRulesPredicates {
public static final Predicate<CardRules> IS_VANGUARD = CardRulesPredicates.coreType(true, CardType.CoreType.Vanguard); public static final Predicate<CardRules> IS_VANGUARD = CardRulesPredicates.coreType(true, CardType.CoreType.Vanguard);
public static final Predicate<CardRules> IS_CONSPIRACY = CardRulesPredicates.coreType(true, CardType.CoreType.Conspiracy); public static final Predicate<CardRules> IS_CONSPIRACY = CardRulesPredicates.coreType(true, CardType.CoreType.Conspiracy);
public static final Predicate<CardRules> IS_DUNGEON = CardRulesPredicates.coreType(true, CardType.CoreType.Dungeon); public static final Predicate<CardRules> IS_DUNGEON = CardRulesPredicates.coreType(true, CardType.CoreType.Dungeon);
public static final Predicate<CardRules> IS_ATTRACTION = Presets.IS_ARTIFACT.and(CardRulesPredicates.subType("Attraction"));
public static final Predicate<CardRules> IS_NON_LAND = CardRulesPredicates.coreType(false, CardType.CoreType.Land); public static final Predicate<CardRules> IS_NON_LAND = CardRulesPredicates.coreType(false, CardType.CoreType.Land);
public static final Predicate<CardRules> CAN_BE_BRAWL_COMMANDER = Presets.IS_LEGENDARY.and(Presets.IS_CREATURE.or(Presets.IS_PLANESWALKER));
public static final Predicate<CardRules> CAN_BE_TINY_LEADERS_COMMANDER = Presets.IS_LEGENDARY.and(Presets.IS_CREATURE.or(Presets.IS_PLANESWALKER));
/** The Constant IS_NON_CREATURE_SPELL. **/
public static final Predicate<CardRules> IS_NON_CREATURE_SPELL =
Presets.IS_SORCERY
.or(Presets.IS_INSTANT)
.or(Presets.IS_PLANESWALKER)
.or(Presets.IS_ENCHANTMENT) //TODO: Battles? Is testing these one by one really the best way to check "non-creature"?
.or(Presets.IS_ARTIFACT.and(Presets.IS_CREATURE.negate()));
/** The Constant isWhite. */
public static final Predicate<CardRules> IS_WHITE = CardRulesPredicates.isColor(MagicColor.WHITE); public static final Predicate<CardRules> IS_WHITE = CardRulesPredicates.isColor(MagicColor.WHITE);
/** The Constant isBlue. */
public static final Predicate<CardRules> IS_BLUE = CardRulesPredicates.isColor(MagicColor.BLUE); public static final Predicate<CardRules> IS_BLUE = CardRulesPredicates.isColor(MagicColor.BLUE);
/** The Constant isBlack. */
public static final Predicate<CardRules> IS_BLACK = CardRulesPredicates.isColor(MagicColor.BLACK); public static final Predicate<CardRules> IS_BLACK = CardRulesPredicates.isColor(MagicColor.BLACK);
/** The Constant isRed. */
public static final Predicate<CardRules> IS_RED = CardRulesPredicates.isColor(MagicColor.RED); public static final Predicate<CardRules> IS_RED = CardRulesPredicates.isColor(MagicColor.RED);
/** The Constant isGreen. */
public static final Predicate<CardRules> IS_GREEN = CardRulesPredicates.isColor(MagicColor.GREEN); public static final Predicate<CardRules> IS_GREEN = CardRulesPredicates.isColor(MagicColor.GREEN);
/** The Constant isColorless. */
public static final Predicate<CardRules> IS_COLORLESS = CardRulesPredicates.hasCntColors((byte) 0); public static final Predicate<CardRules> IS_COLORLESS = CardRulesPredicates.hasCntColors((byte) 0);
/** The Constant isMulticolor. */
public static final Predicate<CardRules> IS_MULTICOLOR = CardRulesPredicates.hasAtLeastCntColors((byte) 2); public static final Predicate<CardRules> IS_MULTICOLOR = CardRulesPredicates.hasAtLeastCntColors((byte) 2);
/** The Constant isMonocolor. */
public static final Predicate<CardRules> IS_MONOCOLOR = CardRulesPredicates.hasCntColors((byte) 1); public static final Predicate<CardRules> IS_MONOCOLOR = CardRulesPredicates.hasCntColors((byte) 1);
/** The Constant colors. */
public static final List<Predicate<CardRules>> COLORS = new ArrayList<>();
static {
Presets.COLORS.add(Presets.IS_WHITE);
Presets.COLORS.add(Presets.IS_BLUE);
Presets.COLORS.add(Presets.IS_BLACK);
Presets.COLORS.add(Presets.IS_RED);
Presets.COLORS.add(Presets.IS_GREEN);
Presets.COLORS.add(Presets.IS_COLORLESS);
}
}
} }

View File

@@ -181,7 +181,7 @@ public class DeckHints {
case COLOR: case COLOR:
ColorSet cc = ColorSet.fromNames(p); ColorSet cc = ColorSet.fromNames(p);
if (cc.isColorless()) { if (cc.isColorless()) {
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.Presets.IS_COLORLESS, PaperCard::getRules)); Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.IS_COLORLESS, PaperCard::getRules));
} else { } else {
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.isColor(cc.getColor()), PaperCard::getRules)); Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.isColor(cc.getColor()), PaperCard::getRules));
} }

View File

@@ -4,8 +4,8 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Predicate; import java.util.function.Predicate;
import forge.item.IPaperCard;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.item.PaperCardPredicates;
import forge.util.Iterables; import forge.util.Iterables;
public class DeckGenPool implements IDeckGenPool { public class DeckGenPool implements IDeckGenPool {
@@ -37,7 +37,7 @@ public class DeckGenPool implements IDeckGenPool {
@Override @Override
public PaperCard getCard(String name, String edition) { public PaperCard getCard(String name, String edition) {
Predicate<PaperCard> filter = IPaperCard.Predicates.printedInSet(edition).and(IPaperCard.Predicates.name(name)); Predicate<PaperCard> filter = PaperCardPredicates.printedInSet(edition).and(PaperCardPredicates.name(name));
Iterable<PaperCard> editionCards=Iterables.filter(cards.values(), filter); Iterable<PaperCard> editionCards=Iterables.filter(cards.values(), filter);
if (editionCards.iterator().hasNext()){ if (editionCards.iterator().hasNext()){
return editionCards.iterator().next(); return editionCards.iterator().next();

View File

@@ -23,8 +23,8 @@ import forge.card.*;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.deck.CardPool; import forge.deck.CardPool;
import forge.deck.DeckFormat; import forge.deck.DeckFormat;
import forge.item.IPaperCard;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.item.PaperCardPredicates;
import forge.util.*; import forge.util.*;
import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.ImmutablePair;
@@ -87,12 +87,12 @@ public abstract class DeckGeneratorBase {
final Iterable<PaperCard> cards = selectCardsOfMatchingColorForPlayer(forAi); final Iterable<PaperCard> cards = selectCardsOfMatchingColorForPlayer(forAi);
// build subsets based on type // build subsets based on type
final Iterable<PaperCard> creatures = Iterables.filter(cards, Predicates.compose(CardRulesPredicates.Presets.IS_CREATURE, PaperCard::getRules)); final Iterable<PaperCard> creatures = Iterables.filter(cards, Predicates.compose(CardRulesPredicates.IS_CREATURE, PaperCard::getRules));
final int creatCnt = (int) Math.ceil(getCreaturePercentage() * size); final int creatCnt = (int) Math.ceil(getCreaturePercentage() * size);
trace.append("Creatures to add:").append(creatCnt).append("\n"); trace.append("Creatures to add:").append(creatCnt).append("\n");
addCmcAdjusted(creatures, creatCnt, cmcLevels); addCmcAdjusted(creatures, creatCnt, cmcLevels);
Predicate<PaperCard> preSpells = Predicates.compose(CardRulesPredicates.Presets.IS_NON_CREATURE_SPELL, PaperCard::getRules); Predicate<PaperCard> preSpells = Predicates.compose(CardRulesPredicates.IS_NON_CREATURE_SPELL, PaperCard::getRules);
final Iterable<PaperCard> spells = Iterables.filter(cards, preSpells); final Iterable<PaperCard> spells = Iterables.filter(cards, preSpells);
final int spellCnt = (int) Math.ceil(getSpellPercentage() * size); final int spellCnt = (int) Math.ceil(getSpellPercentage() * size);
trace.append("Spells to add:").append(spellCnt).append("\n"); trace.append("Spells to add:").append(spellCnt).append("\n");
@@ -108,10 +108,10 @@ public abstract class DeckGeneratorBase {
protected boolean setBasicLandPool(String edition){ protected boolean setBasicLandPool(String edition){
Predicate<PaperCard> isSetBasicLand; Predicate<PaperCard> isSetBasicLand;
if (edition !=null){ if (edition !=null){
isSetBasicLand = IPaperCard.Predicates.printedInSet(edition) isSetBasicLand = PaperCardPredicates.printedInSet(edition)
.and(Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard::getRules)); .and(Predicates.compose(CardRulesPredicates.IS_BASIC_LAND, PaperCard::getRules));
}else{ }else{
isSetBasicLand = Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard::getRules); isSetBasicLand = Predicates.compose(CardRulesPredicates.IS_BASIC_LAND, PaperCard::getRules);
} }
landPool = new DeckGenPool(StaticData.instance().getCommonCards().getAllCards(isSetBasicLand)); landPool = new DeckGenPool(StaticData.instance().getCommonCards().getAllCards(isSetBasicLand));
@@ -234,7 +234,7 @@ public abstract class DeckGeneratorBase {
addSome(targetSize - actualSize, tDeck.toFlatList()); addSome(targetSize - actualSize, tDeck.toFlatList());
} }
else if (actualSize > targetSize) { else if (actualSize > targetSize) {
Predicate<PaperCard> exceptBasicLand = Predicates.compose(CardRulesPredicates.Presets.NOT_BASIC_LAND, PaperCard::getRules); Predicate<PaperCard> exceptBasicLand = Predicates.compose(CardRulesPredicates.NOT_BASIC_LAND, PaperCard::getRules);
for (int i = 0; i < 3 && actualSize > targetSize; i++) { for (int i = 0; i < 3 && actualSize > targetSize; i++) {
Iterable<PaperCard> matchingCards = Iterables.filter(tDeck.toFlatList(), exceptBasicLand); Iterable<PaperCard> matchingCards = Iterables.filter(tDeck.toFlatList(), exceptBasicLand);
@@ -388,7 +388,7 @@ public abstract class DeckGeneratorBase {
//filter to provide all dual lands from pool matching 2 or 3 colors from current deck //filter to provide all dual lands from pool matching 2 or 3 colors from current deck
Predicate<CardRules> dualLandFilter = CardRulesPredicates.coreType(true, CardType.CoreType.Land); Predicate<CardRules> dualLandFilter = CardRulesPredicates.coreType(true, CardType.CoreType.Land);
Predicate<CardRules> exceptBasicLand = CardRulesPredicates.Presets.NOT_BASIC_LAND; Predicate<CardRules> exceptBasicLand = CardRulesPredicates.NOT_BASIC_LAND;
Iterable<PaperCard> landCards = pool.getAllCards(Predicates.compose(dualLandFilter.and(exceptBasicLand).and(canPlay), PaperCard::getRules)); Iterable<PaperCard> landCards = pool.getAllCards(Predicates.compose(dualLandFilter.and(exceptBasicLand).and(canPlay), PaperCard::getRules));
Iterable<String> dualLandPatterns = Arrays.asList("Add \\{([WUBRG])\\} or \\{([WUBRG])\\}", Iterable<String> dualLandPatterns = Arrays.asList("Add \\{([WUBRG])\\} or \\{([WUBRG])\\}",

View File

@@ -24,211 +24,6 @@ public interface IPaperCard extends InventoryItem, Serializable {
String NO_ARTIST_NAME = ""; String NO_ARTIST_NAME = "";
String NO_FUNCTIONAL_VARIANT = ""; String NO_FUNCTIONAL_VARIANT = "";
/**
* Number of filters based on CardPrinted values.
*/
abstract class Predicates {
public static Predicate<PaperCard> rarity(final boolean isEqual, final CardRarity value) {
return new PredicateRarity(value, isEqual);
}
public static Predicate<PaperCard> color(final boolean isEqual, final boolean noColor, final byte value) {
return new PredicateColor(value, noColor, isEqual);
}
public static Predicate<PaperCard> printedInSets(final String[] sets) {
return printedInSets(Lists.newArrayList(sets), true);
}
public static Predicate<PaperCard> printedInSets(final List<String> value, final boolean shouldContain) {
if ((value == null) || value.isEmpty()) {
return x -> true;
}
return new PredicateSets(value, shouldContain);
}
public static Predicate<PaperCard> printedInSet(final String value) {
if (StringUtils.isEmpty(value)) {
return x -> true;
}
return new PredicateSets(Lists.newArrayList(value), true);
}
public static Predicate<PaperCard> name(final String what) {
return new PredicateName(PredicateString.StringOp.EQUALS_IC, what);
}
public static Predicate<PaperCard> name(final PredicateString.StringOp op, final String what) {
return new PredicateName(op, what);
}
public static Predicate<PaperCard> names(final List<String> what) {
return new PredicateNames(what);
}
public static PredicateCards cards(final List<PaperCard> what) { return new PredicateCards(what); }
private static final class PredicateColor implements Predicate<PaperCard> {
private final byte operand;
private final boolean noColor;
private final boolean shouldBeEqual;
private PredicateColor(final byte color, final boolean noColor, final boolean wantEqual) {
this.operand = color;
this.noColor = noColor;
this.shouldBeEqual = wantEqual;
}
@Override
public boolean test(final PaperCard card) {
boolean colorFound = false;
if (noColor) {
return card.getRules().getColor().isColorless() == shouldBeEqual;
}
for (final byte color : card.getRules().getColor()) {
if (color == operand) {
colorFound = true;
break;
}
}
if (card.getRules().getType().hasType(CoreType.Land)) {
for (final byte color : card.getRules().getColorIdentity()) {
if (color == operand) {
colorFound = true;
break;
}
}
}
return colorFound == shouldBeEqual;
}
}
private static final class PredicateRarity implements Predicate<PaperCard> {
private final CardRarity operand;
private final boolean shouldBeEqual;
@Override
public boolean test(final PaperCard card) {
return (card.getRarity() == this.operand) == this.shouldBeEqual;
}
private PredicateRarity(final CardRarity type, final boolean wantEqual) {
this.operand = type;
this.shouldBeEqual = wantEqual;
}
}
private static final class PredicateSets implements Predicate<PaperCard> {
private final Set<String> sets;
private final boolean mustContain;
@Override
public boolean test(final PaperCard card) {
return this.sets.contains(card.getEdition()) == this.mustContain;
}
private PredicateSets(final List<String> wantSets, final boolean shouldContain) {
this.sets = new HashSet<>(wantSets);
this.mustContain = shouldContain;
}
}
private static final class PredicateName extends PredicateString<PaperCard> {
private final String operand;
@Override
public boolean test(final PaperCard card) {
return this.op(card.getName(), this.operand);
}
private PredicateName(final PredicateString.StringOp operator, final String operand) {
super(operator);
this.operand = operand;
}
}
private static final class PredicateNames extends PredicateString<PaperCard> {
private final List<String> operand;
@Override
public boolean test(final PaperCard card) {
final String cardName = card.getName();
for (final String element : this.operand) {
if (this.op(cardName, element)) {
return true;
}
}
return false;
}
private PredicateNames(final List<String> operand) {
super(StringOp.EQUALS);
this.operand = operand;
}
}
private static final class PredicateCards extends PredicateCard<PaperCard> {
private final List<PaperCard> operand;
@Override
public boolean test(final PaperCard card) {
for (final PaperCard element : this.operand) {
if (this.op(card, element)) {
return true;
}
}
return false;
}
private PredicateCards(final List<PaperCard> operand) {
super(StringOp.EQUALS);
this.operand = operand;
}
}
/**
* Pre-built predicates are stored here to allow their re-usage and
* easier access from code.
*/
public abstract static class Presets {
// Think twice before using these, since rarity is a prop of printed
// card.
/** The Constant isCommon. */
public static final Predicate<PaperCard> IS_COMMON = Predicates.rarity(true, CardRarity.Common);
/** The Constant isUncommon. */
public static final Predicate<PaperCard> IS_UNCOMMON = Predicates.rarity(true, CardRarity.Uncommon);
/** The Constant isRare. */
public static final Predicate<PaperCard> IS_RARE = Predicates.rarity(true, CardRarity.Rare);
/** The Constant isMythicRare. */
public static final Predicate<PaperCard> IS_MYTHIC_RARE = Predicates.rarity(true, CardRarity.MythicRare);
/** The Constant isRareOrMythic. */
public static final Predicate<PaperCard> IS_RARE_OR_MYTHIC = Presets.IS_RARE.or(Presets.IS_MYTHIC_RARE);
/** The Constant isSpecial. */
public static final Predicate<PaperCard> IS_SPECIAL = Predicates.rarity(true, CardRarity.Special);
/** The Constant exceptLands. */
public static final Predicate<PaperCard> IS_BASIC_LAND = Predicates.rarity(true, CardRarity.BasicLand);
public static final Predicate<PaperCard> IS_BLACK = Predicates.color(true, false, MagicColor.BLACK);
public static final Predicate<PaperCard> IS_BLUE = Predicates.color(true, false, MagicColor.BLUE);
public static final Predicate<PaperCard> IS_GREEN = Predicates.color(true, false, MagicColor.GREEN);
public static final Predicate<PaperCard> IS_RED = Predicates.color(true, false, MagicColor.RED);
public static final Predicate<PaperCard> IS_WHITE = Predicates.color(true, false, MagicColor.WHITE);
public static final Predicate<PaperCard> IS_COLORLESS = Predicates.color(true, true, MagicColor.COLORLESS);
public static final Predicate<PaperCard> IS_UNREBALANCED = PaperCard::isUnRebalanced;
public static final Predicate<PaperCard> IS_REBALANCED = PaperCard::isRebalanced;
}
}
String getName(); String getName();
String getEdition(); String getEdition();

View File

@@ -10,34 +10,21 @@ public abstract class ItemPredicate {
// Static builder methods - they choose concrete implementation by themselves // Static builder methods - they choose concrete implementation by themselves
public static final Predicate<Object> IsBoosterPack = BoosterPack.class::isInstance; public static final Predicate<Object> IsBoosterPack = BoosterPack.class::isInstance;
/**
* Checks that the inventory item is a Prebuilt Deck.
*/
public static final Predicate<Object> IsPrebuiltDeck = PreconDeck.class::isInstance; public static final Predicate<Object> IsPrebuiltDeck = PreconDeck.class::isInstance;
public static final Predicate<Object> IsFatPack = FatPack.class::isInstance; public static final Predicate<Object> IsFatPack = FatPack.class::isInstance;
/** /**
* Checks that the inventory item is a Tournament Pack. * Checks that the inventory item is a Tournament Pack.
*
* @return the predicate
*/ */
public static final Predicate<Object> IsTournamentPack = card -> card instanceof TournamentPack && !((TournamentPack) card).isStarterDeck(); public static final Predicate<Object> IsTournamentPack = card -> card instanceof TournamentPack && !((TournamentPack) card).isStarterDeck();
/** /**
* Checks that the inventory item is a Starter Deck. * Checks that the inventory item is a Starter Deck.
*
* @return the predicate
*/ */
public static final Predicate<Object> IsStarterDeck = card -> card instanceof TournamentPack && ((TournamentPack) card).isStarterDeck(); public static final Predicate<Object> IsStarterDeck = card -> card instanceof TournamentPack && ((TournamentPack) card).isStarterDeck();
/**
* Checks that the inventory item is a Prebuilt Deck.
*
* @return the predicate
*/
/**
* The Class Presets.
*/
public static class Presets {
/** The Item IsPack. */
public static final Predicate<Object> IS_PACK_OR_DECK = IsBoosterPack.or(IsFatPack).or(IsTournamentPack).or(IsStarterDeck).or(IsPrebuiltDeck); public static final Predicate<Object> IS_PACK_OR_DECK = IsBoosterPack.or(IsFatPack).or(IsTournamentPack).or(IsStarterDeck).or(IsPrebuiltDeck);
}
} }

View File

@@ -0,0 +1,197 @@
package forge.item;
import com.google.common.collect.Lists;
import forge.card.CardRarity;
import forge.card.CardType;
import forge.card.MagicColor;
import forge.util.PredicateCard;
import forge.util.PredicateString;
import org.apache.commons.lang3.StringUtils;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
/**
* Filters based on PaperCard values.
*/
public abstract class PaperCardPredicates {
public static Predicate<PaperCard> rarity(final boolean isEqual, final CardRarity value) {
return new PredicateRarity(value, isEqual);
}
public static Predicate<PaperCard> color(final boolean isEqual, final boolean noColor, final byte value) {
return new PredicateColor(value, noColor, isEqual);
}
public static Predicate<PaperCard> printedInSets(final String[] sets) {
return printedInSets(Lists.newArrayList(sets), true);
}
public static Predicate<PaperCard> printedInSets(final List<String> value, final boolean shouldContain) {
if ((value == null) || value.isEmpty()) {
return x -> true;
}
return new PredicateSets(value, shouldContain);
}
public static Predicate<PaperCard> printedInSet(final String value) {
if (StringUtils.isEmpty(value)) {
return x -> true;
}
return new PredicateSets(Lists.newArrayList(value), true);
}
public static Predicate<PaperCard> name(final String what) {
return new PredicateName(PredicateString.StringOp.EQUALS_IC, what);
}
public static Predicate<PaperCard> name(final PredicateString.StringOp op, final String what) {
return new PredicateName(op, what);
}
public static Predicate<PaperCard> names(final List<String> what) {
return new PredicateNames(what);
}
public static Predicate<PaperCard> cards(final List<PaperCard> what) {
return new PredicateCards(what);
}
private static final class PredicateColor implements Predicate<PaperCard> {
private final byte operand;
private final boolean noColor;
private final boolean shouldBeEqual;
private PredicateColor(final byte color, final boolean noColor, final boolean wantEqual) {
this.operand = color;
this.noColor = noColor;
this.shouldBeEqual = wantEqual;
}
@Override
public boolean test(final PaperCard card) {
boolean colorFound = false;
if (noColor) {
return card.getRules().getColor().isColorless() == shouldBeEqual;
}
for (final byte color : card.getRules().getColor()) {
if (color == operand) {
colorFound = true;
break;
}
}
if (card.getRules().getType().hasType(CardType.CoreType.Land)) {
for (final byte color : card.getRules().getColorIdentity()) {
if (color == operand) {
colorFound = true;
break;
}
}
}
return colorFound == shouldBeEqual;
}
}
private static final class PredicateRarity implements Predicate<PaperCard> {
private final CardRarity operand;
private final boolean shouldBeEqual;
@Override
public boolean test(final PaperCard card) {
return (card.getRarity() == this.operand) == this.shouldBeEqual;
}
private PredicateRarity(final CardRarity type, final boolean wantEqual) {
this.operand = type;
this.shouldBeEqual = wantEqual;
}
}
private static final class PredicateSets implements Predicate<PaperCard> {
private final Set<String> sets;
private final boolean mustContain;
@Override
public boolean test(final PaperCard card) {
return this.sets.contains(card.getEdition()) == this.mustContain;
}
private PredicateSets(final List<String> wantSets, final boolean shouldContain) {
this.sets = new HashSet<>(wantSets);
this.mustContain = shouldContain;
}
}
private static final class PredicateName extends PredicateString<PaperCard> {
private final String operand;
@Override
public boolean test(final PaperCard card) {
return this.op(card.getName(), this.operand);
}
private PredicateName(final StringOp operator, final String operand) {
super(operator);
this.operand = operand;
}
}
private static final class PredicateNames extends PredicateString<PaperCard> {
private final List<String> operand;
@Override
public boolean test(final PaperCard card) {
final String cardName = card.getName();
for (final String element : this.operand) {
if (this.op(cardName, element)) {
return true;
}
}
return false;
}
private PredicateNames(final List<String> operand) {
super(StringOp.EQUALS);
this.operand = operand;
}
}
private static final class PredicateCards extends PredicateCard<PaperCard> {
private final List<PaperCard> operand;
@Override
public boolean test(final PaperCard card) {
for (final PaperCard element : this.operand) {
if (this.op(card, element)) {
return true;
}
}
return false;
}
private PredicateCards(final List<PaperCard> operand) {
super(StringOp.EQUALS);
this.operand = operand;
}
}
public static final Predicate<PaperCard> IS_COMMON = PaperCardPredicates.rarity(true, CardRarity.Common);
public static final Predicate<PaperCard> IS_UNCOMMON = PaperCardPredicates.rarity(true, CardRarity.Uncommon);
public static final Predicate<PaperCard> IS_RARE = PaperCardPredicates.rarity(true, CardRarity.Rare);
public static final Predicate<PaperCard> IS_MYTHIC_RARE = PaperCardPredicates.rarity(true, CardRarity.MythicRare);
public static final Predicate<PaperCard> IS_RARE_OR_MYTHIC = PaperCardPredicates.IS_RARE.or(PaperCardPredicates.IS_MYTHIC_RARE);
public static final Predicate<PaperCard> IS_SPECIAL = PaperCardPredicates.rarity(true, CardRarity.Special);
public static final Predicate<PaperCard> IS_BASIC_LAND = PaperCardPredicates.rarity(true, CardRarity.BasicLand);
public static final Predicate<PaperCard> IS_BLACK = PaperCardPredicates.color(true, false, MagicColor.BLACK);
public static final Predicate<PaperCard> IS_BLUE = PaperCardPredicates.color(true, false, MagicColor.BLUE);
public static final Predicate<PaperCard> IS_GREEN = PaperCardPredicates.color(true, false, MagicColor.GREEN);
public static final Predicate<PaperCard> IS_RED = PaperCardPredicates.color(true, false, MagicColor.RED);
public static final Predicate<PaperCard> IS_WHITE = PaperCardPredicates.color(true, false, MagicColor.WHITE);
public static final Predicate<PaperCard> IS_COLORLESS = PaperCardPredicates.color(true, true, MagicColor.COLORLESS);
public static final Predicate<PaperCard> IS_UNREBALANCED = PaperCard::isUnRebalanced;
public static final Predicate<PaperCard> IS_REBALANCED = PaperCard::isRebalanced;
}

View File

@@ -113,8 +113,8 @@ public abstract class SealedProduct implements InventoryItemFromSet {
} }
protected List<PaperCard> getRandomBasicLands(final String setCode, final int count) { protected List<PaperCard> getRandomBasicLands(final String setCode, final int count) {
Predicate<PaperCard> cardsRule = IPaperCard.Predicates.printedInSet(setCode) Predicate<PaperCard> cardsRule = PaperCardPredicates.printedInSet(setCode)
.and(Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard::getRules)); .and(Predicates.compose(CardRulesPredicates.IS_BASIC_LAND, PaperCard::getRules));
return Aggregates.random(Iterables.filter(StaticData.instance().getCommonCards().getAllCards(), cardsRule), count); return Aggregates.random(Iterables.filter(StaticData.instance().getCommonCards().getAllCards(), cardsRule), count);
} }
} }

View File

@@ -23,7 +23,6 @@ import forge.StaticData;
import forge.card.*; import forge.card.*;
import forge.card.CardEdition.FoilType; import forge.card.CardEdition.FoilType;
import forge.item.*; import forge.item.*;
import forge.item.IPaperCard.Predicates.Presets;
import forge.util.*; import forge.util.*;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
@@ -510,20 +509,20 @@ public class BoosterGenerator {
Predicate<PaperCard> rarityPredicate = null; Predicate<PaperCard> rarityPredicate = null;
switch (toAdd.getRarity()) { switch (toAdd.getRarity()) {
case BasicLand: case BasicLand:
rarityPredicate = Presets.IS_BASIC_LAND; rarityPredicate = PaperCardPredicates.IS_BASIC_LAND;
break; break;
case Common: case Common:
rarityPredicate = Presets.IS_COMMON; rarityPredicate = PaperCardPredicates.IS_COMMON;
break; break;
case Uncommon: case Uncommon:
rarityPredicate = Presets.IS_UNCOMMON; rarityPredicate = PaperCardPredicates.IS_UNCOMMON;
break; break;
case Rare: case Rare:
case MythicRare: case MythicRare:
rarityPredicate = Presets.IS_RARE_OR_MYTHIC; rarityPredicate = PaperCardPredicates.IS_RARE_OR_MYTHIC;
break; break;
default: default:
rarityPredicate = Presets.IS_SPECIAL; rarityPredicate = PaperCardPredicates.IS_SPECIAL;
} }
PaperCard toReplace = null; PaperCard toReplace = null;
@@ -568,7 +567,7 @@ public class BoosterGenerator {
public static PrintSheet makeSheet(String sheetKey, Iterable<PaperCard> src) { public static PrintSheet makeSheet(String sheetKey, Iterable<PaperCard> src) {
PrintSheet ps = new PrintSheet(sheetKey); PrintSheet ps = new PrintSheet(sheetKey);
String[] sKey = TextUtil.splitWithParenthesis(sheetKey, ' ', 2); String[] sKey = TextUtil.splitWithParenthesis(sheetKey, ' ', 2);
Predicate<PaperCard> setPred = sKey.length > 1 ? IPaperCard.Predicates.printedInSets(sKey[1].split(" ")) : x1 -> true; Predicate<PaperCard> setPred = sKey.length > 1 ? PaperCardPredicates.printedInSets(sKey[1].split(" ")) : x1 -> true;
List<String> operators = new LinkedList<>(Arrays.asList(TextUtil.splitWithParenthesis(sKey[0], ':'))); List<String> operators = new LinkedList<>(Arrays.asList(TextUtil.splitWithParenthesis(sKey[0], ':')));
Predicate<PaperCard> extraPred = buildExtraPredicate(operators); Predicate<PaperCard> extraPred = buildExtraPredicate(operators);
@@ -613,31 +612,31 @@ public class BoosterGenerator {
ps.addAll(Iterables.filter(src, predicate)); ps.addAll(Iterables.filter(src, predicate));
} else if (mainCode.equalsIgnoreCase(BoosterSlots.UNCOMMON_RARE)) { // for sets like ARN, where U1 cards are considered rare and U3 are uncommon } else if (mainCode.equalsIgnoreCase(BoosterSlots.UNCOMMON_RARE)) { // for sets like ARN, where U1 cards are considered rare and U3 are uncommon
Predicate<PaperCard> predicateRares = setPred.and(Presets.IS_RARE).and(extraPred); Predicate<PaperCard> predicateRares = setPred.and(PaperCardPredicates.IS_RARE).and(extraPred);
ps.addAll(Iterables.filter(src, predicateRares)); ps.addAll(Iterables.filter(src, predicateRares));
Predicate<PaperCard> predicateUncommon = setPred.and(Presets.IS_UNCOMMON).and(extraPred); Predicate<PaperCard> predicateUncommon = setPred.and(PaperCardPredicates.IS_UNCOMMON).and(extraPred);
ps.addAll(Iterables.filter(src, predicateUncommon), 3); ps.addAll(Iterables.filter(src, predicateUncommon), 3);
} else if (mainCode.equalsIgnoreCase(BoosterSlots.RARE_MYTHIC)) { } else if (mainCode.equalsIgnoreCase(BoosterSlots.RARE_MYTHIC)) {
// Typical ratio of rares to mythics is 53:15, changing to 35:10 in smaller sets. // Typical ratio of rares to mythics is 53:15, changing to 35:10 in smaller sets.
// To achieve the desired 1:8 are all mythics are added once, and all rares added twice per print sheet. // To achieve the desired 1:8 are all mythics are added once, and all rares added twice per print sheet.
Predicate<PaperCard> predicateMythic = setPred.and(Presets.IS_MYTHIC_RARE).and(extraPred); Predicate<PaperCard> predicateMythic = setPred.and(PaperCardPredicates.IS_MYTHIC_RARE).and(extraPred);
ps.addAll(Iterables.filter(src, predicateMythic)); ps.addAll(Iterables.filter(src, predicateMythic));
Predicate<PaperCard> predicateRare = setPred.and(Presets.IS_RARE).and(extraPred); Predicate<PaperCard> predicateRare = setPred.and(PaperCardPredicates.IS_RARE).and(extraPred);
ps.addAll(Iterables.filter(src, predicateRare), 2); ps.addAll(Iterables.filter(src, predicateRare), 2);
} else if (mainCode.equalsIgnoreCase(BoosterSlots.UNCOMMON_RARE_MYTHIC)) { } else if (mainCode.equalsIgnoreCase(BoosterSlots.UNCOMMON_RARE_MYTHIC)) {
// Extended version of RARE_MYTHIC, used for Alchemy slots // Extended version of RARE_MYTHIC, used for Alchemy slots
Predicate<PaperCard> predicateMythic = setPred.and(Presets.IS_MYTHIC_RARE).and(extraPred); Predicate<PaperCard> predicateMythic = setPred.and(PaperCardPredicates.IS_MYTHIC_RARE).and(extraPred);
ps.addAll(Iterables.filter(src, predicateMythic)); ps.addAll(Iterables.filter(src, predicateMythic));
Predicate<PaperCard> predicateRare = setPred.and(Presets.IS_RARE).and(extraPred); Predicate<PaperCard> predicateRare = setPred.and(PaperCardPredicates.IS_RARE).and(extraPred);
ps.addAll(Iterables.filter(src, predicateRare), 2); ps.addAll(Iterables.filter(src, predicateRare), 2);
Predicate<PaperCard> predicateUncommon = setPred.and(Presets.IS_UNCOMMON).and(extraPred); Predicate<PaperCard> predicateUncommon = setPred.and(PaperCardPredicates.IS_UNCOMMON).and(extraPred);
ps.addAll(Iterables.filter(src, predicateUncommon), 4); ps.addAll(Iterables.filter(src, predicateUncommon), 4);
} else { } else {
throw new IllegalArgumentException("Booster generator: operator could not be parsed - " + mainCode); throw new IllegalArgumentException("Booster generator: operator could not be parsed - " + mainCode);
@@ -675,48 +674,48 @@ public class BoosterGenerator {
.or(CardRulesPredicates.splitType(CardSplitType.Modal) .or(CardRulesPredicates.splitType(CardSplitType.Modal)
), ),
PaperCard::getRules); PaperCard::getRules);
} else if (operator.equalsIgnoreCase(BoosterSlots.LAND)) { toAdd = Predicates.compose(CardRulesPredicates.Presets.IS_LAND, PaperCard::getRules); } else if (operator.equalsIgnoreCase(BoosterSlots.LAND)) { toAdd = Predicates.compose(CardRulesPredicates.IS_LAND, PaperCard::getRules);
} else if (operator.equalsIgnoreCase(BoosterSlots.BASIC_LAND)) { toAdd = IPaperCard.Predicates.Presets.IS_BASIC_LAND; } else if (operator.equalsIgnoreCase(BoosterSlots.BASIC_LAND)) { toAdd = PaperCardPredicates.IS_BASIC_LAND;
} else if (operator.equalsIgnoreCase(BoosterSlots.TIME_SHIFTED)) { toAdd = IPaperCard.Predicates.Presets.IS_SPECIAL; } else if (operator.equalsIgnoreCase(BoosterSlots.TIME_SHIFTED)) { toAdd = PaperCardPredicates.IS_SPECIAL;
} else if (operator.equalsIgnoreCase(BoosterSlots.SPECIAL)) { toAdd = IPaperCard.Predicates.Presets.IS_SPECIAL; } else if (operator.equalsIgnoreCase(BoosterSlots.SPECIAL)) { toAdd = PaperCardPredicates.IS_SPECIAL;
} else if (operator.equalsIgnoreCase(BoosterSlots.MYTHIC)) { toAdd = IPaperCard.Predicates.Presets.IS_MYTHIC_RARE; } else if (operator.equalsIgnoreCase(BoosterSlots.MYTHIC)) { toAdd = PaperCardPredicates.IS_MYTHIC_RARE;
} else if (operator.equalsIgnoreCase(BoosterSlots.RARE)) { toAdd = IPaperCard.Predicates.Presets.IS_RARE; } else if (operator.equalsIgnoreCase(BoosterSlots.RARE)) { toAdd = PaperCardPredicates.IS_RARE;
} else if (operator.equalsIgnoreCase(BoosterSlots.UNCOMMON)) { toAdd = IPaperCard.Predicates.Presets.IS_UNCOMMON; } else if (operator.equalsIgnoreCase(BoosterSlots.UNCOMMON)) { toAdd = PaperCardPredicates.IS_UNCOMMON;
} else if (operator.equalsIgnoreCase(BoosterSlots.COMMON)) { toAdd = IPaperCard.Predicates.Presets.IS_COMMON; } else if (operator.equalsIgnoreCase(BoosterSlots.COMMON)) { toAdd = PaperCardPredicates.IS_COMMON;
} else if (operator.startsWith("name(")) { } else if (operator.startsWith("name(")) {
operator = StringUtils.strip(operator.substring(4), "() "); operator = StringUtils.strip(operator.substring(4), "() ");
String[] cardNames = TextUtil.splitWithParenthesis(operator, ',', '"', '"'); String[] cardNames = TextUtil.splitWithParenthesis(operator, ',', '"', '"');
toAdd = IPaperCard.Predicates.names(Lists.newArrayList(cardNames)); toAdd = PaperCardPredicates.names(Lists.newArrayList(cardNames));
} else if (operator.startsWith("color(")) { } else if (operator.startsWith("color(")) {
operator = StringUtils.strip(operator.substring("color(".length() + 1), "()\" "); operator = StringUtils.strip(operator.substring("color(".length() + 1), "()\" ");
switch (operator.toLowerCase()) { switch (operator.toLowerCase()) {
case "black": case "black":
toAdd = Presets.IS_BLACK; toAdd = PaperCardPredicates.IS_BLACK;
break; break;
case "blue": case "blue":
toAdd = Presets.IS_BLUE; toAdd = PaperCardPredicates.IS_BLUE;
break; break;
case "green": case "green":
toAdd = Presets.IS_GREEN; toAdd = PaperCardPredicates.IS_GREEN;
break; break;
case "red": case "red":
toAdd = Presets.IS_RED; toAdd = PaperCardPredicates.IS_RED;
break; break;
case "white": case "white":
toAdd = Presets.IS_WHITE; toAdd = PaperCardPredicates.IS_WHITE;
break; break;
case "colorless": case "colorless":
toAdd = Presets.IS_COLORLESS; toAdd = PaperCardPredicates.IS_COLORLESS;
break; break;
} }
} else if (operator.startsWith("fromSets(")) { } else if (operator.startsWith("fromSets(")) {
operator = StringUtils.strip(operator.substring("fromSets(".length() + 1), "()\" "); operator = StringUtils.strip(operator.substring("fromSets(".length() + 1), "()\" ");
String[] sets = operator.split(","); String[] sets = operator.split(",");
toAdd = IPaperCard.Predicates.printedInSets(sets); toAdd = PaperCardPredicates.printedInSets(sets);
} else if (operator.startsWith("fromSheet(") && invert) { } else if (operator.startsWith("fromSheet(") && invert) {
String sheetName = StringUtils.strip(operator.substring(9), "()\" "); String sheetName = StringUtils.strip(operator.substring(9), "()\" ");
Iterable<PaperCard> cards = StaticData.instance().getPrintSheets().get(sheetName).toFlatList(); Iterable<PaperCard> cards = StaticData.instance().getPrintSheets().get(sheetName).toFlatList();
toAdd = IPaperCard.Predicates.cards(Lists.newArrayList(cards)); toAdd = PaperCardPredicates.cards(Lists.newArrayList(cards));
} }
if (toAdd == null) { if (toAdd == null) {

View File

@@ -1099,7 +1099,7 @@ public class Game {
private void chooseRandomCardsForAnte(final Player player, final Multimap<Player, Card> anteed) { private void chooseRandomCardsForAnte(final Player player, final Multimap<Player, Card> anteed) {
final CardCollectionView lib = player.getCardsIn(ZoneType.Library); final CardCollectionView lib = player.getCardsIn(ZoneType.Library);
Predicate<Card> goodForAnte = CardPredicates.Presets.BASIC_LANDS.negate(); Predicate<Card> goodForAnte = CardPredicates.BASIC_LANDS.negate();
Card ante = Aggregates.random(Iterables.filter(lib, goodForAnte)); Card ante = Aggregates.random(Iterables.filter(lib, goodForAnte));
if (ante == null) { if (ante == null) {
getGameLog().add(GameLogEntryType.ANTE, "Only basic lands found. Will ante one of them"); getGameLog().add(GameLogEntryType.ANTE, "Only basic lands found. Will ante one of them");

View File

@@ -817,14 +817,14 @@ public class GameAction {
if (!stAb.hasParam("ValidAttacker") || (stAb.hasParam("ValidBlocker") && stAb.getParam("ValidBlocker").equals("Creature.Self"))) { if (!stAb.hasParam("ValidAttacker") || (stAb.hasParam("ValidBlocker") && stAb.getParam("ValidBlocker").equals("Creature.Self"))) {
continue; continue;
} }
for (Card creature : Iterables.filter(game.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.CREATURES)) { for (Card creature : Iterables.filter(game.getCardsIn(ZoneType.Battlefield), CardPredicates.CREATURES)) {
if (stAb.matchesValidParam("ValidAttacker", creature)) { if (stAb.matchesValidParam("ValidAttacker", creature)) {
creature.updateAbilityTextForView(); creature.updateAbilityTextForView();
} }
} }
} }
if (stAb.checkMode(StaticAbilityCantAttackBlock.MinMaxBlockerMode)) { if (stAb.checkMode(StaticAbilityCantAttackBlock.MinMaxBlockerMode)) {
for (Card creature : Iterables.filter(game.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.CREATURES)) { for (Card creature : Iterables.filter(game.getCardsIn(ZoneType.Battlefield), CardPredicates.CREATURES)) {
if (stAb.matchesValidParam("ValidCard", creature)) { if (stAb.matchesValidParam("ValidCard", creature)) {
creature.updateAbilityTextForView(); creature.updateAbilityTextForView();
} }
@@ -1431,7 +1431,7 @@ public class GameAction {
if (desCreats != null) { if (desCreats != null) {
if (desCreats.size() > 1 && !orderedDesCreats) { if (desCreats.size() > 1 && !orderedDesCreats) {
desCreats = CardLists.filter(desCreats, CardPredicates.Presets.CAN_BE_DESTROYED); desCreats = CardLists.filter(desCreats, CardPredicates.CAN_BE_DESTROYED);
if (!desCreats.isEmpty()) { if (!desCreats.isEmpty()) {
desCreats = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, desCreats, ZoneType.Graveyard, null); desCreats = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, desCreats, ZoneType.Graveyard, null);
} }

View File

@@ -144,7 +144,7 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
public final CardCollectionView getEnchantedBy() { public final CardCollectionView getEnchantedBy() {
// enchanted means attached by Aura // enchanted means attached by Aura
return CardLists.filter(getAttachedCards(), CardPredicates.Presets.AURA); return CardLists.filter(getAttachedCards(), CardPredicates.AURA);
} }
// doesn't include phased out cards // doesn't include phased out cards
@@ -176,7 +176,7 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
public final boolean isEnchanted() { public final boolean isEnchanted() {
// enchanted means attached by Aura // enchanted means attached by Aura
return Iterables.any(getAttachedCards(), CardPredicates.Presets.AURA); return Iterables.any(getAttachedCards(), CardPredicates.AURA);
} }
public final boolean hasCardAttachment(Card c) { public final boolean hasCardAttachment(Card c) {

View File

@@ -25,8 +25,8 @@ import forge.card.CardEdition.CardInSet;
import forge.card.CardRarity; import forge.card.CardRarity;
import forge.deck.CardPool; import forge.deck.CardPool;
import forge.deck.Deck; import forge.deck.Deck;
import forge.item.IPaperCard;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.item.PaperCardPredicates;
import forge.util.FileSection; import forge.util.FileSection;
import forge.util.FileUtil; import forge.util.FileUtil;
import forge.util.Predicates; import forge.util.Predicates;
@@ -138,17 +138,17 @@ public class GameFormat implements Comparable<GameFormat> {
this.filterPrinted = this.buildFilterPrinted(); this.filterPrinted = this.buildFilterPrinted();
} }
protected Predicate<PaperCard> buildFilter(boolean printed) { protected Predicate<PaperCard> buildFilter(boolean printed) {
Predicate<PaperCard> p = IPaperCard.Predicates.names(this.getBannedCardNames()).negate(); Predicate<PaperCard> p = PaperCardPredicates.names(this.getBannedCardNames()).negate();
if (FormatSubType.ARENA.equals(this.getFormatSubType())) { if (FormatSubType.ARENA.equals(this.getFormatSubType())) {
p = p.and(IPaperCard.Predicates.Presets.IS_UNREBALANCED.negate()); p = p.and(PaperCardPredicates.IS_UNREBALANCED.negate());
} else { } else {
p = p.and(IPaperCard.Predicates.Presets.IS_REBALANCED.negate()); p = p.and(PaperCardPredicates.IS_REBALANCED.negate());
} }
if (!this.getAllowedSetCodes().isEmpty()) { if (!this.getAllowedSetCodes().isEmpty()) {
p = p.and(printed ? p = p.and(printed ?
IPaperCard.Predicates.printedInSets(this.getAllowedSetCodes(), printed) : PaperCardPredicates.printedInSets(this.getAllowedSetCodes(), printed) :
StaticData.instance().getCommonCards().wasPrintedInSets(this.getAllowedSetCodes())); StaticData.instance().getCommonCards().wasPrintedInSets(this.getAllowedSetCodes()));
} }
if (!this.getAllowedRarities().isEmpty()) { if (!this.getAllowedRarities().isEmpty()) {
@@ -159,7 +159,7 @@ public class GameFormat implements Comparable<GameFormat> {
p = p.and(Predicates.or(crp)); p = p.and(Predicates.or(crp));
} }
if (!this.getAdditionalCards().isEmpty()) { if (!this.getAdditionalCards().isEmpty()) {
p = p.or(IPaperCard.Predicates.names(this.getAdditionalCards())); p = p.or(PaperCardPredicates.names(this.getAdditionalCards()));
} }
return p; return p;
} }

View File

@@ -2225,7 +2225,7 @@ public class AbilityUtils {
if (sq[0].equals("EnchantedControllerCreatures")) { // maybe refactor into a Valid with ControlledBy if (sq[0].equals("EnchantedControllerCreatures")) { // maybe refactor into a Valid with ControlledBy
int v = 0; int v = 0;
if (c.getEnchantingCard() != null) { if (c.getEnchantingCard() != null) {
v = CardLists.count(c.getEnchantingCard().getController().getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.CREATURES); v = CardLists.count(c.getEnchantingCard().getController().getCardsIn(ZoneType.Battlefield), CardPredicates.CREATURES);
} }
return doXMath(v, expr, c, ctb); return doXMath(v, expr, c, ctb);
} }
@@ -3877,9 +3877,9 @@ public class AbilityUtils {
// Refined qualities // Refined qualities
// "Untapped Lands" - Count$UntappedTypeYouCtrl.Land // "Untapped Lands" - Count$UntappedTypeYouCtrl.Land
// if (sq[0].contains("Untapped")) { someCards = CardLists.filter(someCards, Presets.UNTAPPED); } // if (sq[0].contains("Untapped")) { someCards = CardLists.filter(someCards, CardPredicates.UNTAPPED); }
// if (sq[0].contains("Tapped")) { someCards = CardLists.filter(someCards, Presets.TAPPED); } // if (sq[0].contains("Tapped")) { someCards = CardLists.filter(someCards, CardPredicates.TAPPED); }
// String sq0 = sq[0].toLowerCase(); // String sq0 = sq[0].toLowerCase();
// for (String color : MagicColor.Constant.ONLY_COLORS) { // for (String color : MagicColor.Constant.ONLY_COLORS) {

View File

@@ -17,7 +17,6 @@ import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView; import forge.game.card.CardCollectionView;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CardPredicates; import forge.game.card.CardPredicates;
import forge.game.card.CardPredicates.Presets;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode; import forge.game.player.PlayerActionConfirmMode;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
@@ -119,7 +118,7 @@ public class ChooseCardEffect extends SpellAbilityEffect {
boolean dontRevealToOwner = true; boolean dontRevealToOwner = true;
if (sa.hasParam("EachBasicType")) { if (sa.hasParam("EachBasicType")) {
// Get all lands, // Get all lands,
List<Card> land = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.LANDS); List<Card> land = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), CardPredicates.LANDS);
String eachBasic = sa.getParam("EachBasicType"); String eachBasic = sa.getParam("EachBasicType");
if (eachBasic.equals("Controlled")) { if (eachBasic.equals("Controlled")) {
land = CardLists.filterControlledBy(land, p); land = CardLists.filterControlledBy(land, p);

View File

@@ -70,7 +70,7 @@ public class ChooseCardNameEffect extends SpellAbilityEffect {
// Momir needs PaperCard // Momir needs PaperCard
//Collection<PaperCard> cards = StaticData.instance().getCommonCards().getUniqueCards(); //Collection<PaperCard> cards = StaticData.instance().getCommonCards().getUniqueCards();
//Predicate<PaperCard> cpp = Predicates.and( //Predicate<PaperCard> cpp = Predicates.and(
// Predicates.compose(CardRulesPredicates.Presets.IS_CREATURE, PaperCard.FN_GET_RULES), // Predicates.compose(CardRulesPredicates.IS_CREATURE, PaperCard.FN_GET_RULES),
// Predicates.compose(CardRulesPredicates.cmc(ComparableOp.EQUALS, validAmount), PaperCard.FN_GET_RULES)); // Predicates.compose(CardRulesPredicates.cmc(ComparableOp.EQUALS, validAmount), PaperCard.FN_GET_RULES));
//cards = Lists.newArrayList(Iterables.filter(cards, cpp)); //cards = Lists.newArrayList(Iterables.filter(cards, cpp));
//if (!cards.isEmpty()) { chosen = Aggregates.random(cards).getName(); //if (!cards.isEmpty()) { chosen = Aggregates.random(cards).getName();

View File

@@ -78,7 +78,7 @@ public class ConniveEffect extends SpellAbilityEffect {
p.drawCards(num, sa, moveParams); p.drawCards(num, sa, moveParams);
CardCollection validDiscards = CardLists.filter(p.getCardsIn(ZoneType.Hand), CardPredicates.Presets.NON_TOKEN); CardCollection validDiscards = CardLists.filter(p.getCardsIn(ZoneType.Hand), CardPredicates.NON_TOKEN);
if (validDiscards.isEmpty() || !p.canDiscardBy(sa, true)) { // hand being empty unlikely, just to be safe if (validDiscards.isEmpty() || !p.canDiscardBy(sa, true)) { // hand being empty unlikely, just to be safe
continue; continue;
} }

View File

@@ -156,11 +156,11 @@ public class CopyPermanentEffect extends TokenEffectBase {
"X", Integer.toString(AbilityUtils.calculateAmount(host, "X", sa))); "X", Integer.toString(AbilityUtils.calculateAmount(host, "X", sa)));
} }
if (StringUtils.containsIgnoreCase(valid, "creature")) { if (StringUtils.containsIgnoreCase(valid, "creature")) {
Predicate<PaperCard> cpp = Predicates.compose(CardRulesPredicates.Presets.IS_CREATURE, PaperCard::getRules); Predicate<PaperCard> cpp = Predicates.compose(CardRulesPredicates.IS_CREATURE, PaperCard::getRules);
cards = Lists.newArrayList(Iterables.filter(cards, cpp)); cards = Lists.newArrayList(Iterables.filter(cards, cpp));
} }
if (StringUtils.containsIgnoreCase(valid, "equipment")) { if (StringUtils.containsIgnoreCase(valid, "equipment")) {
Predicate<PaperCard> cpp = Predicates.compose(CardRulesPredicates.Presets.IS_EQUIPMENT, PaperCard::getRules); Predicate<PaperCard> cpp = Predicates.compose(CardRulesPredicates.IS_EQUIPMENT, PaperCard::getRules);
cards = Lists.newArrayList(Iterables.filter(cards, cpp)); cards = Lists.newArrayList(Iterables.filter(cards, cpp));
} }
if (sa.hasParam("RandomCopied")) { if (sa.hasParam("RandomCopied")) {

View File

@@ -82,7 +82,7 @@ public class DestroyAllEffect extends SpellAbilityEffect {
return; return;
} }
// exclude cards that can't be destroyed at this moment // exclude cards that can't be destroyed at this moment
list = CardLists.filter(list, CardPredicates.Presets.CAN_BE_DESTROYED); list = CardLists.filter(list, CardPredicates.CAN_BE_DESTROYED);
list = GameActionUtil.orderCardsByTheirOwners(game, list, ZoneType.Graveyard, sa); list = GameActionUtil.orderCardsByTheirOwners(game, list, ZoneType.Graveyard, sa);

View File

@@ -29,7 +29,7 @@ public class InternalRadiationEffect extends SpellAbilityEffect {
final CardCollectionView milled = game.getAction().mill(new PlayerCollection(p), numRad, ZoneType.Graveyard, sa, moveParams); final CardCollectionView milled = game.getAction().mill(new PlayerCollection(p), numRad, ZoneType.Graveyard, sa, moveParams);
table.triggerChangesZoneAll(game, sa); table.triggerChangesZoneAll(game, sa);
int n = CardLists.count(milled, CardPredicates.Presets.NON_LANDS); int n = CardLists.count(milled, CardPredicates.NON_LANDS);
if (StaticAbilityGainLifeRadiation.gainLifeRadiation(p)) { if (StaticAbilityGainLifeRadiation.gainLifeRadiation(p)) {
p.gainLife(n, sa.getHostCard(), sa); p.gainLife(n, sa.getHostCard(), sa);

View File

@@ -14,10 +14,7 @@ import forge.game.player.PlayerCollection;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.trigger.TriggerType; import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.item.BoosterPack; import forge.item.*;
import forge.item.IPaperCard;
import forge.item.PaperCard;
import forge.item.SealedTemplate;
import forge.util.Aggregates; import forge.util.Aggregates;
import forge.util.CardTranslation; import forge.util.CardTranslation;
import forge.util.Iterables; import forge.util.Iterables;
@@ -153,7 +150,7 @@ public class MakeCardEffect extends SpellAbilityEffect {
while (toMake > 0) { while (toMake > 0) {
PaperCard pc; PaperCard pc;
if (pack != null) { if (pack != null) {
pc = Iterables.getLast(Iterables.filter(pack, IPaperCard.Predicates.name(name))); pc = Iterables.getLast(Iterables.filter(pack, PaperCardPredicates.name(name)));
} else { } else {
pc = StaticData.instance().getCommonCards().getUniqueByName(name); pc = StaticData.instance().getCommonCards().getUniqueByName(name);
} }

View File

@@ -121,11 +121,11 @@ public class PlayEffect extends SpellAbilityEffect {
} }
} else if (valid.equalsIgnoreCase("sorcery")) { } else if (valid.equalsIgnoreCase("sorcery")) {
cards = Lists.newArrayList(StaticData.instance().getCommonCards().getUniqueCards()); cards = Lists.newArrayList(StaticData.instance().getCommonCards().getUniqueCards());
final Predicate<PaperCard> cpp = Predicates.compose(CardRulesPredicates.Presets.IS_SORCERY, PaperCard::getRules); final Predicate<PaperCard> cpp = Predicates.compose(CardRulesPredicates.IS_SORCERY, PaperCard::getRules);
cards = Lists.newArrayList(Iterables.filter(cards, cpp)); cards = Lists.newArrayList(Iterables.filter(cards, cpp));
} else if (valid.equalsIgnoreCase("instant")) { } else if (valid.equalsIgnoreCase("instant")) {
cards = Lists.newArrayList(StaticData.instance().getCommonCards().getUniqueCards()); cards = Lists.newArrayList(StaticData.instance().getCommonCards().getUniqueCards());
final Predicate<PaperCard> cpp = Predicates.compose(CardRulesPredicates.Presets.IS_INSTANT, PaperCard::getRules); final Predicate<PaperCard> cpp = Predicates.compose(CardRulesPredicates.IS_INSTANT, PaperCard::getRules);
cards = Lists.newArrayList(Iterables.filter(cards, cpp)); cards = Lists.newArrayList(Iterables.filter(cards, cpp));
} }
if (sa.hasParam("RandomCopied")) { if (sa.hasParam("RandomCopied")) {

View File

@@ -30,7 +30,7 @@ public class PlayLandVariantEffect extends SpellAbilityEffect {
final String landType = sa.getParam("Clone"); final String landType = sa.getParam("Clone");
List<PaperCard> cards = Lists.newArrayList(StaticData.instance().getCommonCards().getUniqueCards()); List<PaperCard> cards = Lists.newArrayList(StaticData.instance().getCommonCards().getUniqueCards());
if ("BasicLand".equals(landType)) { if ("BasicLand".equals(landType)) {
final Predicate<PaperCard> cpp = Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard::getRules); final Predicate<PaperCard> cpp = Predicates.compose(CardRulesPredicates.IS_BASIC_LAND, PaperCard::getRules);
cards = Lists.newArrayList(Iterables.filter(cards, cpp)); cards = Lists.newArrayList(Iterables.filter(cards, cpp));
} }
// current color of source card // current color of source card

View File

@@ -4,12 +4,7 @@ import com.google.common.collect.Maps;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.*;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardUtil;
import forge.game.card.CardPredicates.Presets;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.trigger.TriggerType; import forge.game.trigger.TriggerType;
@@ -102,7 +97,7 @@ public class UntapEffect extends SpellAbilityEffect {
valid, sa.getActivatingPlayer(), sa.getHostCard(), sa); valid, sa.getActivatingPlayer(), sa.getHostCard(), sa);
// the few mandatory are handled differently // the few mandatory are handled differently
if (!mandatory) { if (!mandatory) {
list = CardLists.filter(list, Presets.TAPPED); list = CardLists.filter(list, CardPredicates.TAPPED);
} }
final CardCollectionView selected = p.getController().chooseCardsForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectCardToUntap"), mandatory ? num : 0, num, !mandatory, null); final CardCollectionView selected = p.getController().chooseCardsForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectCardToUntap"), mandatory ? num : 0, num, !mandatory, null);

View File

@@ -46,13 +46,13 @@ public class VentureEffect extends SpellAbilityEffect {
if (sa.hasParam("Dungeon")) { if (sa.hasParam("Dungeon")) {
dungeonCards = StaticData.instance().getVariantCards() dungeonCards = StaticData.instance().getVariantCards()
.getAllCards(Predicates.compose( .getAllCards(Predicates.compose(
CardRulesPredicates.Presets.IS_DUNGEON CardRulesPredicates.IS_DUNGEON
.and(CardRulesPredicates.subType(StringOp.EQUALS, sa.getParam("Dungeon"))), .and(CardRulesPredicates.subType(StringOp.EQUALS, sa.getParam("Dungeon"))),
PaperCard::getRules)); PaperCard::getRules));
} else { } else {
// Create a new dungeon card chosen by player in command zone. // Create a new dungeon card chosen by player in command zone.
dungeonCards = StaticData.instance().getVariantCards().getAllCards( dungeonCards = StaticData.instance().getVariantCards().getAllCards(
Predicates.compose(CardRulesPredicates.Presets.IS_DUNGEON, PaperCard::getRules)); Predicates.compose(CardRulesPredicates.IS_DUNGEON, PaperCard::getRules));
dungeonCards.removeIf(c -> !c.getRules().isEnterableDungeon()); dungeonCards.removeIf(c -> !c.getRules().isEnterableDungeon());
} }
String message = Localizer.getInstance().getMessage("lblChooseDungeon"); String message = Localizer.getInstance().getMessage("lblChooseDungeon");

View File

@@ -3862,11 +3862,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
} }
public final CardCollectionView getEquippedBy() { public final CardCollectionView getEquippedBy() {
return CardLists.filter(getAttachedCards(), CardPredicates.Presets.EQUIPMENT); return CardLists.filter(getAttachedCards(), CardPredicates.EQUIPMENT);
} }
public final boolean isEquipped() { public final boolean isEquipped() {
return Iterables.any(getAttachedCards(), CardPredicates.Presets.EQUIPMENT); return Iterables.any(getAttachedCards(), CardPredicates.EQUIPMENT);
} }
public final boolean isEquippedBy(Card c) { public final boolean isEquippedBy(Card c) {
return this.hasCardAttachment(c); return this.hasCardAttachment(c);
@@ -3876,11 +3876,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
} }
public final CardCollectionView getFortifiedBy() { public final CardCollectionView getFortifiedBy() {
return CardLists.filter(getAttachedCards(), CardPredicates.Presets.FORTIFICATION); return CardLists.filter(getAttachedCards(), CardPredicates.FORTIFICATION);
} }
public final boolean isFortified() { public final boolean isFortified() {
return Iterables.any(getAttachedCards(), CardPredicates.Presets.FORTIFICATION); return Iterables.any(getAttachedCards(), CardPredicates.FORTIFICATION);
} }
public final boolean isFortifiedBy(Card c) { public final boolean isFortifiedBy(Card c) {
// 301.5e + 301.6 // 301.5e + 301.6

View File

@@ -302,102 +302,36 @@ public final class CardPredicates {
return c -> c.isAttraction() && c.getAttractionLights().contains(light); return c -> c.isAttraction() && c.getAttractionLights().contains(light);
} }
public static class Presets {
/**
* a Predicate<Card> to get all cards that are tapped.
*/
public static final Predicate<Card> TAPPED = Card::isTapped; public static final Predicate<Card> TAPPED = Card::isTapped;
public static final Predicate<Card> FACE_DOWN = Card::isFaceDown; public static final Predicate<Card> FACE_DOWN = Card::isFaceDown;
/**
* a Predicate<Card> to get all cards that are untapped.
*/
public static final Predicate<Card> UNTAPPED = Card::isUntapped; public static final Predicate<Card> UNTAPPED = Card::isUntapped;
public static final Predicate<Card> CAN_TAP = Card::canTap; public static final Predicate<Card> CAN_TAP = Card::canTap;
public static final Predicate<Card> CAN_CREW = Card::canCrew; public static final Predicate<Card> CAN_CREW = Card::canCrew;
/**
* a Predicate<Card> to get all creatures.
*/
public static final Predicate<Card> CREATURES = Card::isCreature; public static final Predicate<Card> CREATURES = Card::isCreature;
public static final Predicate<Card> NON_CREATURES = c -> !c.isCreature(); public static final Predicate<Card> NON_CREATURES = c -> !c.isCreature();
/**
* a Predicate<Card> to get all enchantments.
*/
public static final Predicate<Card> ENCHANTMENTS = Card::isEnchantment; public static final Predicate<Card> ENCHANTMENTS = Card::isEnchantment;
/**
* a Predicate<Card> to get all aura.
*/
public static final Predicate<Card> AURA = Card::isAura; public static final Predicate<Card> AURA = Card::isAura;
/**
* a Predicate<Card> to get all equipment.
*/
public static final Predicate<Card> EQUIPMENT = Card::isEquipment; public static final Predicate<Card> EQUIPMENT = Card::isEquipment;
/**
* a Predicate<Card> to get all fortification.
*/
public static final Predicate<Card> FORTIFICATION = Card::isFortification; public static final Predicate<Card> FORTIFICATION = Card::isFortification;
/**
* a Predicate<Card> to get all curse.
*/
public static final Predicate<Card> CURSE = Card::isCurse; public static final Predicate<Card> CURSE = Card::isCurse;
/**
* a Predicate<Card> to get all unenchanted cards in a list.
*/
public static final Predicate<Card> UNENCHANTED = c -> !c.isEnchanted(); public static final Predicate<Card> UNENCHANTED = c -> !c.isEnchanted();
/**
* a Predicate<Card> to get all enchanted cards in a list.
*/
public static final Predicate<Card> ENCHANTED = GameEntity::isEnchanted; public static final Predicate<Card> ENCHANTED = GameEntity::isEnchanted;
/**
* a Predicate<Card> to get all nontoken cards.
*/
public static final Predicate<Card> NON_TOKEN = c -> !(c.isToken() || c.isTokenCard()); public static final Predicate<Card> NON_TOKEN = c -> !(c.isToken() || c.isTokenCard());
/**
* a Predicate<Card> to get all token cards.
*/
public static final Predicate<Card> TOKEN = c -> c.isToken() || c.isTokenCard(); public static final Predicate<Card> TOKEN = c -> c.isToken() || c.isTokenCard();
/**
* a Predicate<Card> to get all basicLands.
*/
public static final Predicate<Card> BASIC_LANDS = c -> { public static final Predicate<Card> BASIC_LANDS = c -> {
// the isBasicLand() check here may be sufficient... // the isBasicLand() check here may be sufficient...
return c.isLand() && c.isBasicLand(); return c.isLand() && c.isBasicLand();
}; };
public static final Predicate<Card> NONBASIC_LANDS = c -> c.isLand() && !c.isBasicLand(); public static final Predicate<Card> NONBASIC_LANDS = c -> c.isLand() && !c.isBasicLand();
/**
* a Predicate<Card> to get all artifacts.
*/
public static final Predicate<Card> ARTIFACTS = Card::isArtifact; public static final Predicate<Card> ARTIFACTS = Card::isArtifact;
/**
* a Predicate<Card> to get all nonartifacts.
*/
public static final Predicate<Card> NON_ARTIFACTS = c -> !c.isArtifact();
public static final Predicate<Card> INSTANTS_AND_SORCERIES = Card::isInstantOrSorcery; public static final Predicate<Card> INSTANTS_AND_SORCERIES = Card::isInstantOrSorcery;
/**
* a Predicate<Card> to get all lands.
*/
public static final Predicate<Card> LANDS = Card::isLand; public static final Predicate<Card> LANDS = Card::isLand;
public static final Predicate<Card> NON_LANDS = c -> !c.isLand(); public static final Predicate<Card> NON_LANDS = c -> !c.isLand();
/**
* a Predicate<Card> to get all mana-producing lands.
*/
public static final Predicate<Card> LANDS_PRODUCING_MANA = c -> c.isBasicLand() || (c.isLand() && !c.getManaAbilities().isEmpty()); public static final Predicate<Card> LANDS_PRODUCING_MANA = c -> c.isBasicLand() || (c.isLand() && !c.getManaAbilities().isEmpty());
/**
* a Predicate<Card> to get all permanents.
*/
public static final Predicate<Card> PERMANENTS = Card::isPermanent; public static final Predicate<Card> PERMANENTS = Card::isPermanent;
/**
* a Predicate<Card> to get all nonland permanents.
*/
public static final Predicate<Card> NONLAND_PERMANENTS = c -> c.isPermanent() && !c.isLand(); public static final Predicate<Card> NONLAND_PERMANENTS = c -> c.isPermanent() && !c.isLand();
public static final Predicate<Card> hasFirstStrike = c -> c.isCreature() && (c.hasFirstStrike() || c.hasDoubleStrike()); public static final Predicate<Card> hasFirstStrike = c -> c.isCreature() && (c.hasFirstStrike() || c.hasDoubleStrike());
public static final Predicate<Card> hasSecondStrike = c -> c.isCreature() && (!c.hasFirstStrike() || c.hasDoubleStrike()); public static final Predicate<Card> hasSecondStrike = c -> c.isCreature() && (!c.hasFirstStrike() || c.hasDoubleStrike());
public static final Predicate<Card> SNOW_LANDS = c -> c.isLand() && c.isSnow(); public static final Predicate<Card> SNOW_LANDS = c -> c.isLand() && c.isSnow();
@@ -405,6 +339,4 @@ public final class CardPredicates {
public static final Predicate<Card> BATTLES = Card::isBattle; public static final Predicate<Card> BATTLES = Card::isBattle;
public static final Predicate<Card> CAN_BE_DESTROYED = Card::canBeDestroyed; public static final Predicate<Card> CAN_BE_DESTROYED = Card::canBeDestroyed;
public static final Predicate<Card> ATTRACTIONS = Card::isAttraction; public static final Predicate<Card> ATTRACTIONS = Card::isAttraction;
}
} }

View File

@@ -14,7 +14,6 @@ import forge.game.Game;
import forge.game.GameEntity; import forge.game.GameEntity;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.card.CardPredicates.Presets;
import forge.game.combat.AttackRequirement; import forge.game.combat.AttackRequirement;
import forge.game.combat.AttackingBand; import forge.game.combat.AttackingBand;
import forge.game.combat.Combat; import forge.game.combat.Combat;
@@ -646,7 +645,7 @@ public class CardProperty {
return false; return false;
} }
} else if (property.startsWith("TopGraveyardCreature")) { } else if (property.startsWith("TopGraveyardCreature")) {
CardCollection cards = CardLists.filter(card.getOwner().getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.CREATURES); CardCollection cards = CardLists.filter(card.getOwner().getCardsIn(ZoneType.Graveyard), CardPredicates.CREATURES);
Collections.reverse(cards); Collections.reverse(cards);
if (cards.isEmpty() || !card.equals(cards.get(0))) { if (cards.isEmpty() || !card.equals(cards.get(0))) {
return false; return false;
@@ -931,7 +930,7 @@ public class CardProperty {
return false; return false;
} else if (restriction.equals("NonToken")) { } else if (restriction.equals("NonToken")) {
return !CardLists.filter(game.getCardsIn(ZoneType.Battlefield), return !CardLists.filter(game.getCardsIn(ZoneType.Battlefield),
Presets.NON_TOKEN, CardPredicates.sharesNameWith(card)).isEmpty(); CardPredicates.NON_TOKEN, CardPredicates.sharesNameWith(card)).isEmpty();
} else if (restriction.equals("TriggeredCard")) { } else if (restriction.equals("TriggeredCard")) {
if (!(spellAbility instanceof SpellAbility)) { if (!(spellAbility instanceof SpellAbility)) {
System.out.println("Looking at TriggeredCard but no SA?"); System.out.println("Looking at TriggeredCard but no SA?");
@@ -1305,7 +1304,7 @@ public class CardProperty {
return false; return false;
} }
} else if (property.startsWith("greatestPower")) { } else if (property.startsWith("greatestPower")) {
CardCollectionView cards = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.CREATURES); CardCollectionView cards = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), CardPredicates.CREATURES);
if (property.contains("ControlledBy")) { if (property.contains("ControlledBy")) {
FCollectionView<Player> p = AbilityUtils.getDefinedPlayers(source, property.split("ControlledBy")[1], spellAbility); FCollectionView<Player> p = AbilityUtils.getDefinedPlayers(source, property.split("ControlledBy")[1], spellAbility);
cards = CardLists.filterControlledBy(cards, p); cards = CardLists.filterControlledBy(cards, p);
@@ -1319,14 +1318,14 @@ public class CardProperty {
} }
} }
} else if (property.startsWith("yardGreatestPower")) { } else if (property.startsWith("yardGreatestPower")) {
final CardCollectionView cards = CardLists.filter(sourceController.getCardsIn(ZoneType.Graveyard), Presets.CREATURES); final CardCollectionView cards = CardLists.filter(sourceController.getCardsIn(ZoneType.Graveyard), CardPredicates.CREATURES);
for (final Card crd : cards) { for (final Card crd : cards) {
if (crd.getNetPower() > card.getNetPower()) { if (crd.getNetPower() > card.getNetPower()) {
return false; return false;
} }
} }
} else if (property.startsWith("leastPower")) { } else if (property.startsWith("leastPower")) {
CardCollectionView cards = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.CREATURES); CardCollectionView cards = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), CardPredicates.CREATURES);
if (property.contains("ControlledBy")) { if (property.contains("ControlledBy")) {
FCollectionView<Player> p = AbilityUtils.getDefinedPlayers(source, property.split("ControlledBy")[1], spellAbility); FCollectionView<Player> p = AbilityUtils.getDefinedPlayers(source, property.split("ControlledBy")[1], spellAbility);
cards = CardLists.filterControlledBy(cards, p); cards = CardLists.filterControlledBy(cards, p);
@@ -1340,7 +1339,7 @@ public class CardProperty {
} }
} }
} else if (property.startsWith("leastToughness")) { } else if (property.startsWith("leastToughness")) {
CardCollectionView cards = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.CREATURES); CardCollectionView cards = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), CardPredicates.CREATURES);
if (property.contains("ControlledBy")) { // 4/25/2023 only used for adventure mode Death Ring if (property.contains("ControlledBy")) { // 4/25/2023 only used for adventure mode Death Ring
FCollectionView<Player> p = AbilityUtils.getDefinedPlayers(source, property.split("ControlledBy")[1], spellAbility); FCollectionView<Player> p = AbilityUtils.getDefinedPlayers(source, property.split("ControlledBy")[1], spellAbility);
cards = CardLists.filterControlledBy(cards, p); cards = CardLists.filterControlledBy(cards, p);
@@ -1363,7 +1362,7 @@ public class CardProperty {
} }
if ("NonLandPermanent".equals(prop)) { if ("NonLandPermanent".equals(prop)) {
cards = CardLists.filter(cards, CardPredicates.Presets.NONLAND_PERMANENTS); cards = CardLists.filter(cards, CardPredicates.NONLAND_PERMANENTS);
} else { } else {
cards = CardLists.getType(cards, prop); cards = CardLists.getType(cards, prop);
} }

View File

@@ -222,11 +222,11 @@ public class Combat {
} }
public final CardCollection getDefendingPlaneswalkers() { public final CardCollection getDefendingPlaneswalkers() {
return CardLists.filter(Iterables.filter(attackableEntries, Card.class), CardPredicates.Presets.PLANESWALKERS); return CardLists.filter(Iterables.filter(attackableEntries, Card.class), CardPredicates.PLANESWALKERS);
} }
public final CardCollection getDefendingBattles() { public final CardCollection getDefendingBattles() {
return CardLists.filter(Iterables.filter(attackableEntries, Card.class), CardPredicates.Presets.BATTLES); return CardLists.filter(Iterables.filter(attackableEntries, Card.class), CardPredicates.BATTLES);
} }
public final Map<Card, GameEntity> getAttackersAndDefenders() { public final Map<Card, GameEntity> getAttackersAndDefenders() {

View File

@@ -70,7 +70,7 @@ public class CombatUtil {
// Relevant battles (protected by the attacking player's opponents) // Relevant battles (protected by the attacking player's opponents)
final Game game = playerWhoAttacks.getGame(); final Game game = playerWhoAttacks.getGame();
final CardCollection battles = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.BATTLES); final CardCollection battles = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), CardPredicates.BATTLES);
for (Card battle : battles) { for (Card battle : battles) {
if (battle.getType().hasSubtype("Siege") && battle.getProtectingPlayer().isOpponentOf(playerWhoAttacks)) { if (battle.getType().hasSubtype("Siege") && battle.getProtectingPlayer().isOpponentOf(playerWhoAttacks)) {
defenders.add(battle); defenders.add(battle);

View File

@@ -338,11 +338,11 @@ public class CostAdjustment {
final Player activator = sa.getActivatingPlayer(); final Player activator = sa.getActivatingPlayer();
CardCollectionView untappedCards = CardLists.filter(activator.getCardsIn(ZoneType.Battlefield), CardCollectionView untappedCards = CardLists.filter(activator.getCardsIn(ZoneType.Battlefield),
CardPredicates.Presets.CAN_TAP); CardPredicates.CAN_TAP);
if (improvise) { if (improvise) {
untappedCards = CardLists.filter(untappedCards, CardPredicates.Presets.ARTIFACTS); untappedCards = CardLists.filter(untappedCards, CardPredicates.ARTIFACTS);
} else { } else {
untappedCards = CardLists.filter(untappedCards, CardPredicates.Presets.CREATURES); untappedCards = CardLists.filter(untappedCards, CardPredicates.CREATURES);
} }
Map<Card, ManaCostShard> convokedCards = activator.getController().chooseCardsForConvokeOrImprovise(sa, Map<Card, ManaCostShard> convokedCards = activator.getController().chooseCardsForConvokeOrImprovise(sa,

View File

@@ -20,7 +20,6 @@ package forge.game.cost;
import forge.card.CardType; import forge.card.CardType;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.card.*; import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.trigger.TriggerType; import forge.game.trigger.TriggerType;
@@ -67,7 +66,7 @@ public class CostTapType extends CostPartWithList {
if (!canTapSource) { if (!canTapSource) {
typeList.remove(source); typeList.remove(source);
} }
typeList = CardLists.filter(typeList, ability.isCrew() ? Presets.CAN_CREW : Presets.CAN_TAP); typeList = CardLists.filter(typeList, ability.isCrew() ? CardPredicates.CAN_CREW : CardPredicates.CAN_TAP);
return typeList.size(); return typeList.size();
} }
@@ -165,7 +164,7 @@ public class CostTapType extends CostPartWithList {
if (!canTapSource) { if (!canTapSource) {
typeList.remove(source); typeList.remove(source);
} }
typeList = CardLists.filter(typeList, ability.isCrew() ? Presets.CAN_CREW : Presets.CAN_TAP); typeList = CardLists.filter(typeList, ability.isCrew() ? CardPredicates.CAN_CREW : CardPredicates.CAN_TAP);
if (sameType) { if (sameType) {
for (final Card card : typeList) { for (final Card card : typeList) {

View File

@@ -19,11 +19,7 @@ package forge.game.cost;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.card.Card; import forge.game.card.*;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates.Presets;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.trigger.TriggerType; import forge.game.trigger.TriggerType;
@@ -90,7 +86,7 @@ public class CostUntapType extends CostPartWithList {
if (!canUntapSource) { if (!canUntapSource) {
typeList.remove(source); typeList.remove(source);
} }
typeList = CardLists.filter(typeList, Presets.TAPPED); typeList = CardLists.filter(typeList, CardPredicates.TAPPED);
final int amount = this.getAbilityAmount(ability); final int amount = this.getAbilityAmount(ability);
return (typeList.size() != 0) && (typeList.size() >= amount); return (typeList.size() != 0) && (typeList.size() >= amount);

View File

@@ -26,7 +26,6 @@ import forge.game.ability.AbilityKey;
import forge.game.ability.effects.AddTurnEffect; import forge.game.ability.effects.AddTurnEffect;
import forge.game.ability.effects.SkipPhaseEffect; import forge.game.ability.effects.SkipPhaseEffect;
import forge.game.card.*; import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.combat.Combat; import forge.game.combat.Combat;
import forge.game.combat.CombatUtil; import forge.game.combat.CombatUtil;
import forge.game.cost.CostEnlist; import forge.game.cost.CostEnlist;
@@ -185,7 +184,7 @@ public class PhaseHandler implements java.io.Serializable {
game.getAction().resetActivationsPerTurn(); game.getAction().resetActivationsPerTurn();
final int lands = CardLists.count(playerTurn.getLandsInPlay(), Presets.UNTAPPED); final int lands = CardLists.count(playerTurn.getLandsInPlay(), CardPredicates.UNTAPPED);
playerTurn.setNumPowerSurgeLands(lands); playerTurn.setNumPowerSurgeLands(lands);
} }
//update tokens //update tokens
@@ -287,7 +286,7 @@ public class PhaseHandler implements java.io.Serializable {
} }
} }
// roll for attractions if we have any // roll for attractions if we have any
if (Iterables.any(playerTurn.getCardsIn(ZoneType.Battlefield), Presets.ATTRACTIONS)) { if (Iterables.any(playerTurn.getCardsIn(ZoneType.Battlefield), CardPredicates.ATTRACTIONS)) {
playerTurn.rollToVisitAttractions(); playerTurn.rollToVisitAttractions();
} }
table.replaceCounterEffect(game, null, false); table.replaceCounterEffect(game, null, false);

View File

@@ -34,7 +34,6 @@ import forge.game.card.Card;
import forge.game.card.CardCollection; import forge.game.card.CardCollection;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CardPredicates; import forge.game.card.CardPredicates;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardZoneTable; import forge.game.card.CardZoneTable;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
import forge.game.keyword.KeywordInterface; import forge.game.keyword.KeywordInterface;
@@ -113,7 +112,7 @@ public class Untap extends Phase {
*/ */
private void doUntap() { private void doUntap() {
final Player player = game.getPhaseHandler().getPlayerTurn(); final Player player = game.getPhaseHandler().getPlayerTurn();
final Predicate<Card> tappedCanUntap = Presets.TAPPED.and(CANUNTAP); final Predicate<Card> tappedCanUntap = CardPredicates.TAPPED.and(CANUNTAP);
Map<Player, CardCollection> untapMap = Maps.newHashMap(); Map<Player, CardCollection> untapMap = Maps.newHashMap();
CardCollection list = new CardCollection(player.getCardsIn(ZoneType.Battlefield)); CardCollection list = new CardCollection(player.getCardsIn(ZoneType.Battlefield));

View File

@@ -30,7 +30,6 @@ import forge.game.ability.ApiType;
import forge.game.ability.effects.DetachedCardEffect; import forge.game.ability.effects.DetachedCardEffect;
import forge.game.ability.effects.RollDiceEffect; import forge.game.ability.effects.RollDiceEffect;
import forge.game.card.*; import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.event.*; import forge.game.event.*;
import forge.game.keyword.*; import forge.game.keyword.*;
import forge.game.keyword.KeywordCollection.KeywordCollectionView; import forge.game.keyword.KeywordCollection.KeywordCollectionView;
@@ -63,7 +62,6 @@ import org.apache.commons.lang3.tuple.Pair;
import java.util.*; import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.function.Predicate;
/** /**
* <p> * <p>
@@ -2084,7 +2082,7 @@ public class Player extends GameEntity implements Comparable<Player> {
} }
public final boolean hasMetalcraft() { public final boolean hasMetalcraft() {
return CardLists.count(getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.ARTIFACTS) >= 3; return CardLists.count(getCardsIn(ZoneType.Battlefield), CardPredicates.ARTIFACTS) >= 3;
} }
public final boolean hasDesert() { public final boolean hasDesert() {
@@ -2123,7 +2121,7 @@ public class Player extends GameEntity implements Comparable<Player> {
} }
public final boolean hasLandfall() { public final boolean hasLandfall() {
return Iterables.any(getZone(ZoneType.Battlefield).getCardsAddedThisTurn(null), CardPredicates.Presets.LANDS); return Iterables.any(getZone(ZoneType.Battlefield).getCardsAddedThisTurn(null), CardPredicates.LANDS);
} }
public boolean hasFerocious() { public boolean hasFerocious() {
@@ -2436,29 +2434,29 @@ public class Player extends GameEntity implements Comparable<Player> {
* use to get a list of creatures in play for a given player. * use to get a list of creatures in play for a given player.
*/ */
public CardCollection getCreaturesInPlay() { public CardCollection getCreaturesInPlay() {
return CardLists.filter(getCardsIn(ZoneType.Battlefield), Presets.CREATURES); return CardLists.filter(getCardsIn(ZoneType.Battlefield), CardPredicates.CREATURES);
} }
public CardCollection getPlaneswalkersInPlay() { public CardCollection getPlaneswalkersInPlay() {
return CardLists.filter(getCardsIn(ZoneType.Battlefield), Presets.PLANESWALKERS); return CardLists.filter(getCardsIn(ZoneType.Battlefield), CardPredicates.PLANESWALKERS);
} }
public CardCollection getBattlesInPlay() { public CardCollection getBattlesInPlay() {
return CardLists.filter(getCardsIn(ZoneType.Battlefield), Presets.BATTLES); return CardLists.filter(getCardsIn(ZoneType.Battlefield), CardPredicates.BATTLES);
} }
/** /**
* use to get a list of tokens in play for a given player. * use to get a list of tokens in play for a given player.
*/ */
public CardCollection getTokensInPlay() { public CardCollection getTokensInPlay() {
return CardLists.filter(getCardsIn(ZoneType.Battlefield), Presets.TOKEN); return CardLists.filter(getCardsIn(ZoneType.Battlefield), CardPredicates.TOKEN);
} }
/** /**
* use to get a list of all lands a given player has on the battlefield. * use to get a list of all lands a given player has on the battlefield.
*/ */
public CardCollection getLandsInPlay() { public CardCollection getLandsInPlay() {
return CardLists.filter(getCardsIn(ZoneType.Battlefield), Presets.LANDS); return CardLists.filter(getCardsIn(ZoneType.Battlefield), CardPredicates.LANDS);
} }
public boolean isCardInPlay(final String cardName) { public boolean isCardInPlay(final String cardName) {
@@ -3596,7 +3594,7 @@ public class Player extends GameEntity implements Comparable<Player> {
} }
public final boolean isCursed() { public final boolean isCursed() {
return CardLists.count(getAttachedCards(), CardPredicates.Presets.CURSE) > 0; return CardLists.count(getAttachedCards(), CardPredicates.CURSE) > 0;
} }
public boolean canDiscardBy(SpellAbility sa, final boolean effect) { public boolean canDiscardBy(SpellAbility sa, final boolean effect) {

View File

@@ -24,12 +24,12 @@ import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.function.Predicate; import java.util.function.Predicate;
import forge.item.PaperCardPredicates;
import forge.util.Iterables; import forge.util.Iterables;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import forge.card.CardEdition; import forge.card.CardEdition;
import forge.item.IPaperCard;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.localinstance.properties.ForgeConstants; import forge.localinstance.properties.ForgeConstants;
import forge.model.FModel; import forge.model.FModel;
@@ -374,7 +374,7 @@ public class ImportSourceAnalyzer {
cardFileNamesBySet = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); cardFileNamesBySet = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
for (final CardEdition ce : FModel.getMagicDb().getEditions()) { for (final CardEdition ce : FModel.getMagicDb().getEditions()) {
final Map<String, String> cardFileNames = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); final Map<String, String> cardFileNames = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
final Predicate<PaperCard> filter = IPaperCard.Predicates.printedInSet(ce.getCode()); final Predicate<PaperCard> filter = PaperCardPredicates.printedInSet(ce.getCode());
addSetCards(cardFileNames, FModel.getMagicDb().getCommonCards().getAllCards(), filter); addSetCards(cardFileNames, FModel.getMagicDb().getCommonCards().getAllCards(), filter);
addSetCards(cardFileNames, FModel.getMagicDb().getVariantCards().getAllCards(), filter); addSetCards(cardFileNames, FModel.getMagicDb().getVariantCards().getAllCards(), filter);
cardFileNamesBySet.put(ce.getCode2(), cardFileNames); cardFileNamesBySet.put(ce.getCode2(), cardFileNames);

View File

@@ -33,7 +33,7 @@ public class CardPowerFilter extends ValueRangeFilter<PaperCard> {
if (predicate == null) { if (predicate == null) {
return x -> true; return x -> true;
} }
predicate = predicate.and(CardRulesPredicates.Presets.IS_CREATURE); predicate = predicate.and(CardRulesPredicates.IS_CREATURE);
return Predicates.compose(predicate, PaperCard::getRules); return Predicates.compose(predicate, PaperCard::getRules);
} }
} }

View File

@@ -33,7 +33,7 @@ public class CardToughnessFilter extends ValueRangeFilter<PaperCard> {
if (predicate == null) { if (predicate == null) {
return x -> true; return x -> true;
} }
predicate = predicate.and(CardRulesPredicates.Presets.IS_CREATURE); predicate = predicate.and(CardRulesPredicates.IS_CREATURE);
return Predicates.compose(predicate, PaperCard::getRules); return Predicates.compose(predicate, PaperCard::getRules);
} }
} }

View File

@@ -59,7 +59,7 @@ public abstract class StatTypeFilter<T extends InventoryItem> extends ToggleButt
protected <U extends InventoryItem> boolean showUnsupportedItem(U item) { protected <U extends InventoryItem> boolean showUnsupportedItem(U item) {
FLabel btnPackOrDeck = buttonMap.get(StatTypes.PACK_OR_DECK); //support special pack/deck case FLabel btnPackOrDeck = buttonMap.get(StatTypes.PACK_OR_DECK); //support special pack/deck case
if (btnPackOrDeck != null && btnPackOrDeck.isSelected()) { if (btnPackOrDeck != null && btnPackOrDeck.isSelected()) {
return ItemPredicate.Presets.IS_PACK_OR_DECK.test(item); return ItemPredicate.IS_PACK_OR_DECK.test(item);
} }
return false; return false;
} }
@@ -70,7 +70,7 @@ public abstract class StatTypeFilter<T extends InventoryItem> extends ToggleButt
FLabel btnPackOrDeck = buttonMap.get(StatTypes.PACK_OR_DECK); FLabel btnPackOrDeck = buttonMap.get(StatTypes.PACK_OR_DECK);
if (btnPackOrDeck != null) { //support special pack/deck case if (btnPackOrDeck != null) { //support special pack/deck case
int count = items.countAll(ItemPredicate.Presets.IS_PACK_OR_DECK, InventoryItem.class); int count = items.countAll(ItemPredicate.IS_PACK_OR_DECK, InventoryItem.class);
btnPackOrDeck.setText(String.valueOf(count)); btnPackOrDeck.setText(String.valueOf(count));
} }

View File

@@ -70,7 +70,7 @@ public enum CDeckgen implements ICDoc {
final Deck randomDeck = new Deck(); final Deck randomDeck = new Deck();
final Predicate<PaperCard> notBasicLand = Predicates.compose(CardRulesPredicates.Presets.NOT_BASIC_LAND, PaperCard::getRules); final Predicate<PaperCard> notBasicLand = Predicates.compose(CardRulesPredicates.NOT_BASIC_LAND, PaperCard::getRules);
final Iterable<PaperCard> source = Iterables.filter(FModel.getMagicDb().getCommonCards().getUniqueCards(), notBasicLand); final Iterable<PaperCard> source = Iterables.filter(FModel.getMagicDb().getCommonCards().getUniqueCards(), notBasicLand);
randomDeck.getMain().addAllFlat(Aggregates.random(source, 15 * 5)); randomDeck.getMain().addAllFlat(Aggregates.random(source, 15 * 5));

View File

@@ -82,14 +82,14 @@ public final class CEditorCommander extends CDeckEditor<Deck> {
CardDb commonCards = FModel.getMagicDb().getCommonCards(); CardDb commonCards = FModel.getMagicDb().getCommonCards();
if (gameType == GameType.Brawl){ if (gameType == GameType.Brawl){
GameFormat format = FModel.getFormats().get("Brawl"); GameFormat format = FModel.getFormats().get("Brawl");
Predicate<CardRules> commanderFilter = CardRulesPredicates.Presets.CAN_BE_BRAWL_COMMANDER; Predicate<CardRules> commanderFilter = CardRulesPredicates.CAN_BE_BRAWL_COMMANDER;
commanderPool = ItemPool.createFrom(commonCards.getAllCardsNoAlt(format.getFilterPrinted().and(Predicates.compose(commanderFilter, PaperCard::getRules))), PaperCard.class); commanderPool = ItemPool.createFrom(commonCards.getAllCardsNoAlt(format.getFilterPrinted().and(Predicates.compose(commanderFilter, PaperCard::getRules))), PaperCard.class);
normalPool = ItemPool.createFrom(format.getAllCards(), PaperCard.class); normalPool = ItemPool.createFrom(format.getAllCards(), PaperCard.class);
} }
else { else {
Predicate<CardRules> commanderFilter = gameType == GameType.Oathbreaker Predicate<CardRules> commanderFilter = gameType == GameType.Oathbreaker
? CardRulesPredicates.Presets.CAN_BE_OATHBREAKER.or(CardRulesPredicates.Presets.CAN_BE_SIGNATURE_SPELL) ? CardRulesPredicates.CAN_BE_OATHBREAKER.or(CardRulesPredicates.CAN_BE_SIGNATURE_SPELL)
: CardRulesPredicates.Presets.CAN_BE_COMMANDER; : CardRulesPredicates.CAN_BE_COMMANDER;
commanderPool = ItemPool.createFrom(commonCards.getAllCardsNoAlt(Predicates.compose(commanderFilter, PaperCard::getRules)),PaperCard.class); commanderPool = ItemPool.createFrom(commonCards.getAllCardsNoAlt(Predicates.compose(commanderFilter, PaperCard::getRules)),PaperCard.class);
normalPool = ItemPool.createFrom(commonCards.getAllCardsNoAlt(), PaperCard.class); normalPool = ItemPool.createFrom(commonCards.getAllCardsNoAlt(), PaperCard.class);
} }

View File

@@ -346,7 +346,7 @@ public final class CEditorQuest extends CDeckEditor<Deck> {
} }
private ItemPool<PaperCard> getCommanderCardPool(){ private ItemPool<PaperCard> getCommanderCardPool(){
Predicate<PaperCard> commanderPredicate = Predicates.compose(CardRulesPredicates.Presets.CAN_BE_COMMANDER, PaperCard::getRules); Predicate<PaperCard> commanderPredicate = Predicates.compose(CardRulesPredicates.CAN_BE_COMMANDER, PaperCard::getRules);
return getRemainingCardPool().getFilteredPool(commanderPredicate); return getRemainingCardPool().getFilteredPool(commanderPredicate);
} }

View File

@@ -76,16 +76,16 @@ public enum CStatistics implements ICDoc {
// Hack-ish: avoid /0 cases, but still populate labels :) // Hack-ish: avoid /0 cases, but still populate labels :)
if (total == 0) { total = 1; } if (total == 0) { total = 1; }
setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblCreature(), deck, CardRulesPredicates.Presets.IS_CREATURE, total); setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblCreature(), deck, CardRulesPredicates.IS_CREATURE, total);
setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblLand(), deck, CardRulesPredicates.Presets.IS_LAND, total); setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblLand(), deck, CardRulesPredicates.IS_LAND, total);
setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblEnchantment(), deck, CardRulesPredicates.Presets.IS_ENCHANTMENT, total); setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblEnchantment(), deck, CardRulesPredicates.IS_ENCHANTMENT, total);
setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblArtifact(), deck, CardRulesPredicates.Presets.IS_ARTIFACT, total); setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblArtifact(), deck, CardRulesPredicates.IS_ARTIFACT, total);
setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblInstant(), deck, CardRulesPredicates.Presets.IS_INSTANT, total); setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblInstant(), deck, CardRulesPredicates.IS_INSTANT, total);
setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblSorcery(), deck, CardRulesPredicates.Presets.IS_SORCERY, total); setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblSorcery(), deck, CardRulesPredicates.IS_SORCERY, total);
setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblPlaneswalker(), deck, CardRulesPredicates.Presets.IS_PLANESWALKER, total); setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblPlaneswalker(), deck, CardRulesPredicates.IS_PLANESWALKER, total);
setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblMulti(), deck, CardRulesPredicates.Presets.IS_MULTICOLOR, total); setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblMulti(), deck, CardRulesPredicates.IS_MULTICOLOR, total);
setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblColorless(), deck, CardRulesPredicates.Presets.IS_COLORLESS, total); setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblColorless(), deck, CardRulesPredicates.IS_COLORLESS, total);
setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblBlack(), deck, CardRulesPredicates.isMonoColor(MagicColor.BLACK), total); setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblBlack(), deck, CardRulesPredicates.isMonoColor(MagicColor.BLACK), total);
setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblBlue(), deck, CardRulesPredicates.isMonoColor(MagicColor.BLUE), total); setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblBlue(), deck, CardRulesPredicates.isMonoColor(MagicColor.BLUE), total);
setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblGreen(), deck, CardRulesPredicates.isMonoColor(MagicColor.GREEN), total); setLabelValue(VStatistics.SINGLETON_INSTANCE.getLblGreen(), deck, CardRulesPredicates.isMonoColor(MagicColor.GREEN), total);

View File

@@ -57,16 +57,16 @@ public class CStatisticsImporter {
// Hack-ish: avoid /0 cases, but still populate labels :) // Hack-ish: avoid /0 cases, but still populate labels :)
if (total == 0) { total = 1; } if (total == 0) { total = 1; }
setLabelValue(this.view.getLblCreature(), deck, CardRulesPredicates.Presets.IS_CREATURE, total); setLabelValue(this.view.getLblCreature(), deck, CardRulesPredicates.IS_CREATURE, total);
setLabelValue(this.view.getLblLand(), deck, CardRulesPredicates.Presets.IS_LAND, total); setLabelValue(this.view.getLblLand(), deck, CardRulesPredicates.IS_LAND, total);
setLabelValue(this.view.getLblEnchantment(), deck, CardRulesPredicates.Presets.IS_ENCHANTMENT, total); setLabelValue(this.view.getLblEnchantment(), deck, CardRulesPredicates.IS_ENCHANTMENT, total);
setLabelValue(this.view.getLblArtifact(), deck, CardRulesPredicates.Presets.IS_ARTIFACT, total); setLabelValue(this.view.getLblArtifact(), deck, CardRulesPredicates.IS_ARTIFACT, total);
setLabelValue(this.view.getLblInstant(), deck, CardRulesPredicates.Presets.IS_INSTANT, total); setLabelValue(this.view.getLblInstant(), deck, CardRulesPredicates.IS_INSTANT, total);
setLabelValue(this.view.getLblSorcery(), deck, CardRulesPredicates.Presets.IS_SORCERY, total); setLabelValue(this.view.getLblSorcery(), deck, CardRulesPredicates.IS_SORCERY, total);
setLabelValue(this.view.getLblPlaneswalker(), deck, CardRulesPredicates.Presets.IS_PLANESWALKER, total); setLabelValue(this.view.getLblPlaneswalker(), deck, CardRulesPredicates.IS_PLANESWALKER, total);
setLabelValue(this.view.getLblMulti(), deck, CardRulesPredicates.Presets.IS_MULTICOLOR, total); setLabelValue(this.view.getLblMulti(), deck, CardRulesPredicates.IS_MULTICOLOR, total);
setLabelValue(this.view.getLblColorless(), deck, CardRulesPredicates.Presets.IS_COLORLESS, total); setLabelValue(this.view.getLblColorless(), deck, CardRulesPredicates.IS_COLORLESS, total);
setLabelValue(this.view.getLblBlack(), deck, CardRulesPredicates.isMonoColor(MagicColor.BLACK), total); setLabelValue(this.view.getLblBlack(), deck, CardRulesPredicates.isMonoColor(MagicColor.BLACK), total);
setLabelValue(this.view.getLblBlue(), deck, CardRulesPredicates.isMonoColor(MagicColor.BLUE), total); setLabelValue(this.view.getLblBlue(), deck, CardRulesPredicates.isMonoColor(MagicColor.BLUE), total);
setLabelValue(this.view.getLblGreen(), deck, CardRulesPredicates.isMonoColor(MagicColor.GREEN), total); setLabelValue(this.view.getLblGreen(), deck, CardRulesPredicates.isMonoColor(MagicColor.GREEN), total);

View File

@@ -77,8 +77,8 @@ public class PlanarConquestCommanderGeneraterGA extends PlanarConquestGeneraterG
Iterable<PaperCard> filtered= Iterables.filter(cards, Iterable<PaperCard> filtered= Iterables.filter(cards,
Predicates.compose(CardRulesPredicates.IS_KEPT_IN_AI_DECKS, PaperCard::getRules) Predicates.compose(CardRulesPredicates.IS_KEPT_IN_AI_DECKS, PaperCard::getRules)
.and(Predicates.compose(CardRulesPredicates.Presets.IS_PLANESWALKER, PaperCard::getRules)) .and(Predicates.compose(CardRulesPredicates.IS_PLANESWALKER, PaperCard::getRules))
//.and(Predicates.compose(CardRulesPredicates.Presets.IS_LEGENDARY, PaperCard::getRules)) //.and(Predicates.compose(CardRulesPredicates.IS_LEGENDARY, PaperCard::getRules))
.and(gameFormat.getFilterPrinted()) .and(gameFormat.getFilterPrinted())
); );

View File

@@ -107,7 +107,7 @@ public class PlanarConquestGeneraterGA extends AbstractGeneticAlgorithm<Deck> {
Iterable<PaperCard> filtered= Iterables.filter(cards, Iterable<PaperCard> filtered= Iterables.filter(cards,
Predicates.compose(CardRulesPredicates.IS_KEPT_IN_AI_DECKS, PaperCard::getRules) Predicates.compose(CardRulesPredicates.IS_KEPT_IN_AI_DECKS, PaperCard::getRules)
.and(Predicates.compose(CardRulesPredicates.Presets.IS_NON_LAND, PaperCard::getRules)) .and(Predicates.compose(CardRulesPredicates.IS_NON_LAND, PaperCard::getRules))
.and(gameFormat.getFilterPrinted()) .and(gameFormat.getFilterPrinted())
); );

View File

@@ -80,7 +80,7 @@ public class PlanarConquestTribalGeneraterGA extends PlanarConquestGeneraterGA {
Iterable<PaperCard> filteredTribe= Iterables.filter(cards, Iterable<PaperCard> filteredTribe= Iterables.filter(cards,
Predicates.compose(CardRulesPredicates.IS_KEPT_IN_AI_DECKS, PaperCard::getRules) Predicates.compose(CardRulesPredicates.IS_KEPT_IN_AI_DECKS, PaperCard::getRules)
.and(Predicates.compose(CardRulesPredicates.hasCreatureType("Pirate"), PaperCard::getRules)) .and(Predicates.compose(CardRulesPredicates.hasCreatureType("Pirate"), PaperCard::getRules))
.and(Predicates.compose(CardRulesPredicates.Presets.IS_CREATURE, PaperCard::getRules)) .and(Predicates.compose(CardRulesPredicates.IS_CREATURE, PaperCard::getRules))
.and(gameFormat.getFilterPrinted()) .and(gameFormat.getFilterPrinted())
); );

View File

@@ -481,7 +481,7 @@ public class EnemySprite extends CharacterSprite implements Steerable<Vector2> {
if(data.rewards != null) { //Collect standard rewards. if(data.rewards != null) { //Collect standard rewards.
Deck enemyDeck = Current.latestDeck(); Deck enemyDeck = Current.latestDeck();
// By popular demand, remove basic lands from the reward pool. // By popular demand, remove basic lands from the reward pool.
CardPool deckNoBasicLands = enemyDeck.getMain().getFilteredPool(Predicates.compose(CardRulesPredicates.Presets.NOT_BASIC_LAND, PaperCard::getRules)); CardPool deckNoBasicLands = enemyDeck.getMain().getFilteredPool(Predicates.compose(CardRulesPredicates.NOT_BASIC_LAND, PaperCard::getRules));
for (RewardData rdata : data.rewards) { for (RewardData rdata : data.rewards) {
ret.addAll(rdata.generate(false, enemyDeck == null ? null : deckNoBasicLands.toFlatList(),true )); ret.addAll(rdata.generate(false, enemyDeck == null ? null : deckNoBasicLands.toFlatList(),true ));

View File

@@ -30,7 +30,7 @@ public class CardPowerFilter extends ValueRangeFilter<PaperCard> {
if (predicate == null) { if (predicate == null) {
return x -> true; return x -> true;
} }
predicate = predicate.and(CardRulesPredicates.Presets.IS_CREATURE); predicate = predicate.and(CardRulesPredicates.IS_CREATURE);
return Predicates.compose(predicate, PaperCard::getRules); return Predicates.compose(predicate, PaperCard::getRules);
} }
} }

View File

@@ -30,7 +30,7 @@ public class CardToughnessFilter extends ValueRangeFilter<PaperCard> {
if (predicate == null) { if (predicate == null) {
return x -> true; return x -> true;
} }
predicate = predicate.and(CardRulesPredicates.Presets.IS_CREATURE); predicate = predicate.and(CardRulesPredicates.IS_CREATURE);
return Predicates.compose(predicate, PaperCard::getRules); return Predicates.compose(predicate, PaperCard::getRules);
} }
} }

View File

@@ -37,7 +37,7 @@ public abstract class StatTypeFilter<T extends InventoryItem> extends ToggleButt
protected <U extends InventoryItem> boolean showUnsupportedItem(U item) { protected <U extends InventoryItem> boolean showUnsupportedItem(U item) {
FLabel btnPackOrDeck = buttonMap.get(StatTypes.PACK_OR_DECK); //support special pack/deck case FLabel btnPackOrDeck = buttonMap.get(StatTypes.PACK_OR_DECK); //support special pack/deck case
if (btnPackOrDeck != null && btnPackOrDeck.isSelected()) { if (btnPackOrDeck != null && btnPackOrDeck.isSelected()) {
return ItemPredicate.Presets.IS_PACK_OR_DECK.test(item); return ItemPredicate.IS_PACK_OR_DECK.test(item);
} }
return false; return false;
} }

View File

@@ -74,7 +74,7 @@ public final class CardRelationMatrixGenerator {
true); true);
final Iterable<PaperCard> cards = Iterables.filter(format.getAllCards() final Iterable<PaperCard> cards = Iterables.filter(format.getAllCards()
, Predicates.compose(CardRulesPredicates.Presets.NOT_TRUE_BASIC_LAND, PaperCard::getRules)); , Predicates.compose(CardRulesPredicates.NOT_TRUE_BASIC_LAND, PaperCard::getRules));
List<PaperCard> cardList = Lists.newArrayList(cards); List<PaperCard> cardList = Lists.newArrayList(cards);
cardList.add(FModel.getMagicDb().getCommonCards().getCard("Wastes")); cardList.add(FModel.getMagicDb().getCommonCards().getCard("Wastes"));
Map<String, Integer> cardIntegerMap = new HashMap<>(); Map<String, Integer> cardIntegerMap = new HashMap<>();
@@ -90,7 +90,7 @@ public final class CardRelationMatrixGenerator {
for (Deck deck:decks){ for (Deck deck:decks){
if (deck.getMain().contains(card)){ if (deck.getMain().contains(card)){
for (PaperCard pairCard:Iterables.filter(deck.getMain().toFlatList(), for (PaperCard pairCard:Iterables.filter(deck.getMain().toFlatList(),
Predicates.compose(CardRulesPredicates.Presets.NOT_TRUE_BASIC_LAND, PaperCard::getRules))){ Predicates.compose(CardRulesPredicates.NOT_TRUE_BASIC_LAND, PaperCard::getRules))){
if (!pairCard.getName().equals(card.getName())){ if (!pairCard.getName().equals(card.getName())){
try { try {
int old = matrix[cardIntegerMap.get(card.getName())][cardIntegerMap.get(pairCard.getName())]; int old = matrix[cardIntegerMap.get(card.getName())][cardIntegerMap.get(pairCard.getName())];
@@ -143,7 +143,7 @@ public final class CardRelationMatrixGenerator {
//get all cards //get all cards
final Iterable<PaperCard> cards = Iterables.filter(FModel.getMagicDb().getCommonCards().getUniqueCards() final Iterable<PaperCard> cards = Iterables.filter(FModel.getMagicDb().getCommonCards().getUniqueCards()
, Predicates.compose(CardRulesPredicates.Presets.NOT_TRUE_BASIC_LAND, PaperCard::getRules)); , Predicates.compose(CardRulesPredicates.NOT_TRUE_BASIC_LAND, PaperCard::getRules));
List<PaperCard> cardList = Lists.newArrayList(cards); List<PaperCard> cardList = Lists.newArrayList(cards);
cardList.add(FModel.getMagicDb().getCommonCards().getCard("Wastes")); cardList.add(FModel.getMagicDb().getCommonCards().getCard("Wastes"));
Map<String, Integer> cardIntegerMap = new HashMap<>(); Map<String, Integer> cardIntegerMap = new HashMap<>();
@@ -200,7 +200,7 @@ public final class CardRelationMatrixGenerator {
public static void updateLegendMatrix(Deck deck, PaperCard legend, Map<String, Integer> cardIntegerMap, public static void updateLegendMatrix(Deck deck, PaperCard legend, Map<String, Integer> cardIntegerMap,
Map<String, Integer> legendIntegerMap, int[][] matrix){ Map<String, Integer> legendIntegerMap, int[][] matrix){
for (PaperCard pairCard:Iterables.filter(deck.getMain().toFlatList(), for (PaperCard pairCard:Iterables.filter(deck.getMain().toFlatList(),
Predicates.compose(CardRulesPredicates.Presets.NOT_TRUE_BASIC_LAND, PaperCard::getRules))){ Predicates.compose(CardRulesPredicates.NOT_TRUE_BASIC_LAND, PaperCard::getRules))){
if (!pairCard.getName().equals(legend.getName())){ if (!pairCard.getName().equals(legend.getName())){
try { try {
int old = matrix[legendIntegerMap.get(legend.getName())][cardIntegerMap.get(pairCard.getName())]; int old = matrix[legendIntegerMap.get(legend.getName())][cardIntegerMap.get(pairCard.getName())];

View File

@@ -65,7 +65,7 @@ public class CommanderDeckGenerator extends DeckProxy implements Comparable<Comm
Predicate<CardRules> canPlay = isForAi ? DeckGeneratorBase.AI_CAN_PLAY : CardRulesPredicates.IS_KEPT_IN_RANDOM_DECKS; Predicate<CardRules> canPlay = isForAi ? DeckGeneratorBase.AI_CAN_PLAY : CardRulesPredicates.IS_KEPT_IN_RANDOM_DECKS;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Iterable<PaperCard> legends = Iterables.filter(uniqueCards.toFlatList(), format.isLegalCardPredicate() Iterable<PaperCard> legends = Iterables.filter(uniqueCards.toFlatList(), format.isLegalCardPredicate()
.and(Predicates.compose(CardRulesPredicates.Presets.CAN_BE_BRAWL_COMMANDER.and(canPlay), PaperCard::getRules))); .and(Predicates.compose(CardRulesPredicates.CAN_BE_BRAWL_COMMANDER.and(canPlay), PaperCard::getRules)));
final List<DeckProxy> decks = new ArrayList<>(); final List<DeckProxy> decks = new ArrayList<>();
for (PaperCard legend: legends) { for (PaperCard legend: legends) {
decks.add(new CommanderDeckGenerator(legend, format, isForAi, isCardGen)); decks.add(new CommanderDeckGenerator(legend, format, isForAi, isCardGen));

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