mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-11 16:26:22 +00:00
Miscallaneous Cleanup Part 2 - Lambdas and Method References (#5737)
* Cleanup - Unnecessary Boxing * Cleanup - Unnecessary Unboxing * Cleanup - For-Each Loops * Cleanup - `indexOf != -1` -> `contains` * Cleanup - Merge identical catch blocks * Cleanup - Try-with-resources * Cleanup - System.lineSeparator * Cleanup - Reference types to primitives Some loops over Integers were switched to IntStreams to hopefully cut down on overall boxing. * Cleanup - Manually filling and copying arrays * Remove unused imports * Switch a lambda to a method reference * Cleanup - CardPredicate Aggregates to method references * Cleanup - Other static functions to method references * Cleanup - Ambiguous class reference Unclear when or how this happened... * Cleanup - Anonymous -> Method reference * Cleanup - Anonymous -> Lambda * Cleanup - Comparator helper methods * Cleanup - final method in final class * Cleanup - private final methods * Remove unused imports * Convert a couple more lambdas to comparators. * Simplify creature type list comparison. --------- Co-authored-by: Jetz <Jetz722@gmail.com> Co-authored-by: tool4ever <therealtoolkit@hotmail.com>
This commit is contained in:
@@ -60,12 +60,7 @@ public class ActionEditor extends JComponent{
|
||||
add(edit,BorderLayout.CENTER);
|
||||
|
||||
|
||||
edit.addChangeListener(new ChangeListener() {
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
emitChanged();
|
||||
}
|
||||
});
|
||||
edit.addChangeListener(e -> emitChanged());
|
||||
}
|
||||
protected void emitChanged() {
|
||||
if (updating)
|
||||
|
||||
@@ -49,12 +49,7 @@ public class DialogTree extends JPanel {
|
||||
|
||||
public void addSelectionListener(){
|
||||
//subscribe to valueChanged, change to that object in edit pane
|
||||
dialogTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(TreeSelectionEvent e) {
|
||||
emitChanged(e);
|
||||
}
|
||||
});
|
||||
dialogTree.getSelectionModel().addTreeSelectionListener(this::emitChanged);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package forge.adventure.editor;
|
||||
|
||||
|
||||
import com.badlogic.gdx.tools.particleeditor.ParticleEditor;
|
||||
import com.google.common.base.Function;
|
||||
import forge.localinstance.properties.ForgeConstants;
|
||||
import forge.localinstance.properties.ForgePreferences;
|
||||
import forge.model.FModel;
|
||||
@@ -23,12 +22,9 @@ public class EditorMainWindow extends JFrame {
|
||||
public EditorMainWindow()
|
||||
{
|
||||
UIManager.LookAndFeelInfo[] var1 = UIManager.getInstalledLookAndFeels();
|
||||
FModel.initialize(null, new Function<ForgePreferences, Void>() {
|
||||
@Override
|
||||
public Void apply(ForgePreferences preferences) {
|
||||
FModel.initialize(null, preferences -> {
|
||||
preferences.setPref(ForgePreferences.FPref.LOAD_CARD_SCRIPTS_LAZILY, true);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
Lang.createInstance(FModel.getPreferences().getPref(ForgePreferences.FPref.UI_LANGUAGE));
|
||||
Localizer.getInstance().initialize(FModel.getPreferences().getPref(ForgePreferences.FPref.UI_LANGUAGE), ForgeConstants.LANG_DIR);
|
||||
|
||||
@@ -4,8 +4,6 @@ import forge.adventure.util.Config;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -21,12 +19,7 @@ public class FilePicker extends Box {
|
||||
super(BoxLayout.X_AXIS);
|
||||
this.fileEndings = fileEndings;
|
||||
|
||||
findButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
FilePicker.this.find();
|
||||
}
|
||||
});
|
||||
findButton.addActionListener(e -> FilePicker.this.find());
|
||||
|
||||
add(edit);
|
||||
add(findButton);
|
||||
|
||||
@@ -68,12 +68,7 @@ public class StructureEditor extends JComponent{
|
||||
add(edit,BorderLayout.CENTER);
|
||||
|
||||
|
||||
edit.addChangeListener(new ChangeListener() {
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
emitChanged();
|
||||
}
|
||||
});
|
||||
edit.addChangeListener(e -> emitChanged());
|
||||
}
|
||||
protected void emitChanged() {
|
||||
ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class);
|
||||
|
||||
@@ -60,12 +60,7 @@ public class TerrainsEditor extends JComponent{
|
||||
add(edit,BorderLayout.CENTER);
|
||||
|
||||
|
||||
edit.addChangeListener(new ChangeListener() {
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
emitChanged();
|
||||
}
|
||||
});
|
||||
edit.addChangeListener(e -> emitChanged());
|
||||
}
|
||||
protected void emitChanged() {
|
||||
ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class);
|
||||
|
||||
@@ -9,8 +9,6 @@ import forge.adventure.util.Config;
|
||||
import forge.adventure.util.Paths;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -81,12 +79,7 @@ public class WorldEditor extends JComponent {
|
||||
|
||||
public WorldEditor() {
|
||||
list.setCellRenderer(new BiomeDataRenderer());
|
||||
list.addListSelectionListener(new ListSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
WorldEditor.this.updateBiome();
|
||||
}
|
||||
});
|
||||
list.addListSelectionListener(e -> WorldEditor.this.updateBiome());
|
||||
BorderLayout layout = new BorderLayout();
|
||||
setLayout(layout);
|
||||
add(tabs);
|
||||
|
||||
@@ -124,12 +124,7 @@ public class AiAttackController {
|
||||
List<Card> defenders = defender.getCreaturesInPlay();
|
||||
int totalMana = ComputerUtilMana.getAvailableManaEstimate(defender, true);
|
||||
int manaReserved = 0; // for paying the cost to transform
|
||||
Predicate<Card> canAnimate = new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card c) {
|
||||
return !c.isTapped() && !c.isCreature() && !c.isPlaneswalker();
|
||||
}
|
||||
};
|
||||
Predicate<Card> canAnimate = c -> !c.isTapped() && !c.isCreature() && !c.isPlaneswalker();
|
||||
|
||||
CardCollection tappedDefenders = new CardCollection();
|
||||
for (Card c : CardLists.filter(defender.getCardsIn(ZoneType.Battlefield), canAnimate)) {
|
||||
@@ -331,12 +326,7 @@ public class AiAttackController {
|
||||
}
|
||||
|
||||
public final static List<Card> getPossibleBlockers(final List<Card> blockers, final List<Card> attackers, final boolean nextTurn) {
|
||||
return CardLists.filter(blockers, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return canBlockAnAttacker(c, attackers, nextTurn);
|
||||
}
|
||||
});
|
||||
return CardLists.filter(blockers, c -> canBlockAnAttacker(c, attackers, nextTurn));
|
||||
}
|
||||
|
||||
public final static boolean canBlockAnAttacker(final Card c, final List<Card> attackers, final boolean nextTurn) {
|
||||
@@ -395,15 +385,10 @@ public class AiAttackController {
|
||||
}
|
||||
}
|
||||
// reduce the search space
|
||||
final List<Card> opponentsAttackers = CardLists.filter(ai.getOpponents().getCreaturesInPlay(), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return !c.hasSVar("EndOfTurnLeavePlay")
|
||||
final List<Card> opponentsAttackers = CardLists.filter(ai.getOpponents().getCreaturesInPlay(), c -> !c.hasSVar("EndOfTurnLeavePlay")
|
||||
&& (c.toughnessAssignsDamage() || c.getNetCombatDamage() > 0 // performance shortcuts
|
||||
|| c.getNetCombatDamage() + ComputerUtilCombat.predictPowerBonusOfAttacker(c, null, null, true) > 0)
|
||||
&& ComputerUtilCombat.canAttackNextTurn(c);
|
||||
}
|
||||
});
|
||||
&& ComputerUtilCombat.canAttackNextTurn(c));
|
||||
|
||||
// don't hold back creatures that can't block any of the human creatures
|
||||
final List<Card> blockers = getPossibleBlockers(potentialAttackers, opponentsAttackers, true);
|
||||
@@ -770,7 +755,7 @@ public class AiAttackController {
|
||||
return false;
|
||||
}
|
||||
|
||||
private final Pair<Integer, Integer> getDamageFromBlockingTramplers(final List<Card> blockedAttackers, final List<Card> blockers, final int myFreeMana) {
|
||||
private Pair<Integer, Integer> getDamageFromBlockingTramplers(final List<Card> blockedAttackers, final List<Card> blockers, final int myFreeMana) {
|
||||
int currentAttackTax = 0;
|
||||
int trampleDamage = 0;
|
||||
CardCollection remainingBlockers = new CardCollection(blockers);
|
||||
@@ -797,7 +782,7 @@ public class AiAttackController {
|
||||
return Pair.of(trampleDamage, currentAttackTax);
|
||||
}
|
||||
|
||||
private final GameEntity chooseDefender(final Combat c, final boolean bAssault) {
|
||||
private GameEntity chooseDefender(final Combat c, final boolean bAssault) {
|
||||
final FCollectionView<GameEntity> defs = c.getDefenders();
|
||||
if (defs.size() == 1) {
|
||||
return defs.getFirst();
|
||||
@@ -932,9 +917,7 @@ public class AiAttackController {
|
||||
// check defenders in order of maximum requirements
|
||||
List<Pair<GameEntity, Integer>> reqs = combat.getAttackConstraints().getRequirements().get(attacker).getSortedRequirements();
|
||||
final GameEntity def = defender;
|
||||
reqs.sort(new Comparator<Pair<GameEntity, Integer>>() {
|
||||
@Override
|
||||
public int compare(Pair<GameEntity, Integer> r1, Pair<GameEntity, Integer> r2) {
|
||||
reqs.sort((r1, r2) -> {
|
||||
if (r1.getValue() == r2.getValue()) {
|
||||
// try to attack the designated defender
|
||||
if (r1.getKey().equals(def) && !r2.getKey().equals(def)) {
|
||||
@@ -956,7 +939,6 @@ public class AiAttackController {
|
||||
}
|
||||
}
|
||||
return r2.getValue() - r1.getValue();
|
||||
}
|
||||
});
|
||||
for (Pair<GameEntity, Integer> e : reqs) {
|
||||
if (e.getRight() == 0) continue;
|
||||
@@ -1406,14 +1388,9 @@ public class AiAttackController {
|
||||
}
|
||||
|
||||
// contains only the defender's blockers that can actually block the attacker
|
||||
CardCollection validBlockers = CardLists.filter(defenders, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card defender) {
|
||||
return CombatUtil.canBlock(attacker, defender);
|
||||
}
|
||||
});
|
||||
CardCollection validBlockers = CardLists.filter(defenders, defender1 -> CombatUtil.canBlock(attacker, defender1));
|
||||
|
||||
boolean canTrampleOverDefenders = attacker.hasKeyword(Keyword.TRAMPLE) && attacker.getNetCombatDamage() > Aggregates.sum(validBlockers, CardPredicates.Accessors.fnGetNetToughness);
|
||||
boolean canTrampleOverDefenders = attacker.hasKeyword(Keyword.TRAMPLE) && attacker.getNetCombatDamage() > Aggregates.sum(validBlockers, Card::getNetToughness);
|
||||
|
||||
// used to check that CanKillAllDangerous check makes sense in context where creatures with dangerous abilities are present
|
||||
boolean dangerousBlockersPresent = Iterables.any(validBlockers, Predicates.or(
|
||||
|
||||
@@ -140,9 +140,7 @@ public class AiBlockController {
|
||||
ComputerUtilCard.sortByEvaluateCreature(attackers);
|
||||
CardLists.sortByPowerDesc(attackers);
|
||||
//move cards like Phage the Untouchable to the front
|
||||
attackers.sort(new Comparator<Card>() {
|
||||
@Override
|
||||
public int compare(final Card o1, final Card o2) {
|
||||
attackers.sort((o1, o2) -> {
|
||||
if (o1.hasSVar("MustBeBlocked") && !o2.hasSVar("MustBeBlocked")) {
|
||||
return -1;
|
||||
}
|
||||
@@ -156,7 +154,6 @@ public class AiBlockController {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
return attackers;
|
||||
}
|
||||
@@ -330,21 +327,14 @@ public class AiBlockController {
|
||||
}
|
||||
|
||||
private Predicate<Card> rampagesOrNeedsManyToBlock(final Combat combat) {
|
||||
return Predicates.or(CardPredicates.hasKeyword(Keyword.RAMPAGE), new Predicate<Card>() {
|
||||
|
||||
@Override
|
||||
public boolean apply(Card input) {
|
||||
return Predicates.or(CardPredicates.hasKeyword(Keyword.RAMPAGE), input -> {
|
||||
// select creature that has a max blocker
|
||||
return StaticAbilityCantAttackBlock.getMinMaxBlocker(input, combat.getDefenderPlayerByAttacker(input)).getRight() < Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private Predicate<Card> changesPTWhenBlocked(final boolean onlyForDefVsTrample) {
|
||||
return new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return card -> {
|
||||
for (final Trigger tr : card.getTriggers()) {
|
||||
if (tr.getMode() == TriggerType.AttackerBlocked) {
|
||||
SpellAbility ab = tr.getOverridingAbility();
|
||||
@@ -366,7 +356,6 @@ public class AiBlockController {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -452,15 +441,12 @@ public class AiBlockController {
|
||||
|
||||
// Try to add blockers that could be destroyed, but are worth less than the attacker
|
||||
// Don't use blockers without First Strike or Double Strike if attacker has it
|
||||
usableBlockers = CardLists.filter(blockers, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
usableBlockers = CardLists.filter(blockers, c -> {
|
||||
if (ComputerUtilCombat.dealsFirstStrikeDamage(attacker, false, combat)
|
||||
&& !ComputerUtilCombat.dealsFirstStrikeDamage(c, false, combat)) {
|
||||
return false;
|
||||
}
|
||||
return lifeInDanger || wouldLikeToRandomlyTrade(attacker, c, combat) || ComputerUtilCard.evaluateCreature(c) + diff < ComputerUtilCard.evaluateCreature(attacker);
|
||||
}
|
||||
});
|
||||
if (usableBlockers.size() < 2) {
|
||||
return;
|
||||
@@ -579,13 +565,8 @@ public class AiBlockController {
|
||||
final List<Card> blockGang = new ArrayList<>();
|
||||
int absorbedDamage; // The amount of damage needed to kill the first blocker
|
||||
|
||||
List<Card> usableBlockers = CardLists.filter(blockers, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.getNetToughness() > attacker.getNetCombatDamage() // performance shortcut
|
||||
|| c.getNetToughness() + ComputerUtilCombat.predictToughnessBonusOfBlocker(attacker, c, true) > attacker.getNetCombatDamage();
|
||||
}
|
||||
});
|
||||
List<Card> usableBlockers = CardLists.filter(blockers, c -> c.getNetToughness() > attacker.getNetCombatDamage() // performance shortcut
|
||||
|| c.getNetToughness() + ComputerUtilCombat.predictToughnessBonusOfBlocker(attacker, c, true) > attacker.getNetCombatDamage());
|
||||
if (usableBlockers.size() < 2) {
|
||||
return;
|
||||
}
|
||||
@@ -829,12 +810,7 @@ public class AiBlockController {
|
||||
blockers.removeAll(combat.getBlockers(attacker));
|
||||
|
||||
// Don't add any blockers that won't kill the attacker because the damage would be prevented by a static effect
|
||||
blockers = CardLists.filter(blockers, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card blocker) {
|
||||
return !ComputerUtilCombat.isCombatDamagePrevented(blocker, attacker, blocker.getNetCombatDamage());
|
||||
}
|
||||
});
|
||||
blockers = CardLists.filter(blockers, blocker -> !ComputerUtilCombat.isCombatDamagePrevented(blocker, attacker, blocker.getNetCombatDamage()));
|
||||
|
||||
// Try to use safe blockers first
|
||||
if (blockers.size() > 0) {
|
||||
@@ -921,13 +897,9 @@ public class AiBlockController {
|
||||
|
||||
CardCollection pwsWithChumpBlocks = new CardCollection();
|
||||
CardCollection chosenChumpBlockers = new CardCollection();
|
||||
CardCollection chumpPWDefenders = CardLists.filter(this.blockersLeft, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return ComputerUtilCard.evaluateCreature(card) <= (card.isToken() ? evalThresholdToken
|
||||
: evalThresholdNonToken);
|
||||
}
|
||||
});
|
||||
CardCollection chumpPWDefenders = CardLists.filter(this.blockersLeft,
|
||||
card -> ComputerUtilCard.evaluateCreature(card) <= (card.isToken() ? evalThresholdToken : evalThresholdNonToken)
|
||||
);
|
||||
CardLists.sortByPowerAsc(chumpPWDefenders);
|
||||
if (!chumpPWDefenders.isEmpty()) {
|
||||
for (final Card attacker : attackers) {
|
||||
|
||||
@@ -37,7 +37,6 @@ import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.ability.SpellApiBased;
|
||||
import forge.game.card.*;
|
||||
import forge.game.card.CardPredicates.Accessors;
|
||||
import forge.game.card.CardPredicates.Presets;
|
||||
import forge.game.combat.Combat;
|
||||
import forge.game.combat.CombatUtil;
|
||||
@@ -418,7 +417,7 @@ public class AiController {
|
||||
CardCollection allCards = new CardCollection(player.getCardsIn(ZoneType.Graveyard));
|
||||
allCards.addAll(player.getCardsIn(ZoneType.Command));
|
||||
allCards.addAll(cardsInPlay);
|
||||
int maxCmcInHand = Aggregates.max(hand, CardPredicates.Accessors.fnGetCmc);
|
||||
int maxCmcInHand = Aggregates.max(hand, Card::getCMC);
|
||||
int max = Math.max(maxCmcInHand, 6);
|
||||
// consider not playing lands if there are enough already and an ability with a discard cost is present
|
||||
if (landsInPlay.size() + landList.size() > max) {
|
||||
@@ -437,9 +436,7 @@ public class AiController {
|
||||
}
|
||||
}
|
||||
|
||||
landList = CardLists.filter(landList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
landList = CardLists.filter(landList, c -> {
|
||||
CardCollectionView battlefield = player.getCardsIn(ZoneType.Battlefield);
|
||||
if (canPlaySpellBasic(c, null) != AiPlayDecision.WillPlay) {
|
||||
return false;
|
||||
@@ -451,11 +448,11 @@ public class AiController {
|
||||
}
|
||||
}
|
||||
|
||||
final CardCollectionView hand = player.getCardsIn(ZoneType.Hand);
|
||||
final CardCollectionView hand1 = player.getCardsIn(ZoneType.Hand);
|
||||
CardCollection lands = new CardCollection(battlefield);
|
||||
lands.addAll(hand);
|
||||
lands = CardLists.filter(lands, CardPredicates.Presets.LANDS);
|
||||
int maxCmcInHand = Aggregates.max(hand, CardPredicates.Accessors.fnGetCmc);
|
||||
lands.addAll(hand1);
|
||||
lands = CardLists.filter(lands, Presets.LANDS);
|
||||
int maxCmcInHand = Aggregates.max(hand1, Card::getCMC);
|
||||
|
||||
if (lands.size() >= Math.max(maxCmcInHand, 6)) {
|
||||
// don't play MDFC land if other side is spell and enough lands are available
|
||||
@@ -473,7 +470,6 @@ public class AiController {
|
||||
}
|
||||
|
||||
return player.canPlayLand(c);
|
||||
}
|
||||
});
|
||||
return landList;
|
||||
}
|
||||
@@ -1441,8 +1437,8 @@ public class AiController {
|
||||
}
|
||||
}
|
||||
|
||||
int totalCMCInHand = Aggregates.sum(inHand, CardPredicates.Accessors.fnGetCmc);
|
||||
int minCMCInHand = Aggregates.min(inHand, CardPredicates.Accessors.fnGetCmc);
|
||||
int totalCMCInHand = Aggregates.sum(inHand, Card::getCMC);
|
||||
int minCMCInHand = Aggregates.min(inHand, Card::getCMC);
|
||||
if (minCMCInHand == Integer.MAX_VALUE)
|
||||
minCMCInHand = 0;
|
||||
int predictedMana = ComputerUtilMana.getAvailableManaEstimate(player, true);
|
||||
@@ -1450,14 +1446,12 @@ public class AiController {
|
||||
boolean canCastWithLandDrop = (predictedMana + 1 >= minCMCInHand) && minCMCInHand > 0 && !isTapLand;
|
||||
boolean cantCastAnythingNow = predictedMana < minCMCInHand;
|
||||
|
||||
boolean hasRelevantAbsOTB = Iterables.any(otb, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
boolean isTapLand = false;
|
||||
boolean hasRelevantAbsOTB = Iterables.any(otb, card -> {
|
||||
boolean isTapLand1 = false;
|
||||
for (ReplacementEffect repl : card.getReplacementEffects()) {
|
||||
// TODO: improve the detection of taplands
|
||||
if (repl.getParamOrDefault("Description", "").equals("CARDNAME enters the battlefield tapped.")) {
|
||||
isTapLand = true;
|
||||
isTapLand1 = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1465,18 +1459,15 @@ public class AiController {
|
||||
if (sa.isAbility()
|
||||
&& sa.getPayCosts().getCostMana() != null
|
||||
&& sa.getPayCosts().getCostMana().getMana().getCMC() > 0
|
||||
&& (!sa.getPayCosts().hasTapCost() || !isTapLand)
|
||||
&& (!sa.getPayCosts().hasTapCost() || !isTapLand1)
|
||||
&& (!sa.hasParam("ActivationZone") || sa.getParam("ActivationZone").contains("Battlefield"))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
boolean hasLandBasedEffect = Iterables.any(otb, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
boolean hasLandBasedEffect = Iterables.any(otb, card -> {
|
||||
for (Trigger t : card.getTriggers()) {
|
||||
Map<String, String> params = t.getMapParams();
|
||||
if ("ChangesZone".equals(params.get("Mode"))
|
||||
@@ -1509,7 +1500,6 @@ public class AiController {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: add prediction for effects that will untap a tapland as it enters the battlefield
|
||||
@@ -1528,7 +1518,7 @@ public class AiController {
|
||||
return true;
|
||||
}
|
||||
|
||||
private final SpellAbility getSpellAbilityToPlay() {
|
||||
private SpellAbility getSpellAbilityToPlay() {
|
||||
CardCollection cards = ComputerUtilAbility.getAvailableCards(game, player);
|
||||
cards = ComputerUtilCard.dedupeCards(cards);
|
||||
List<SpellAbility> saList = Lists.newArrayList();
|
||||
@@ -1572,12 +1562,9 @@ public class AiController {
|
||||
saList = ComputerUtilAbility.getSpellAbilities(cards, player);
|
||||
}
|
||||
|
||||
Iterables.removeIf(saList, new Predicate<SpellAbility>() {
|
||||
@Override
|
||||
public boolean apply(final SpellAbility spellAbility) { //don't include removedAI cards if somehow the AI can play the ability or gain control of unsupported card
|
||||
Iterables.removeIf(saList, spellAbility -> { //don't include removedAI cards if somehow the AI can play the ability or gain control of unsupported card
|
||||
// TODO allow when experimental profile?
|
||||
return spellAbility instanceof LandAbility || (spellAbility.getHostCard() != null && ComputerUtilCard.isCardRemAIDeck(spellAbility.getHostCard()));
|
||||
}
|
||||
});
|
||||
//update LivingEndPlayer
|
||||
useLivingEnd = Iterables.any(player.getZone(ZoneType.Library), CardPredicates.nameEquals("Living End"));
|
||||
@@ -1997,14 +1984,9 @@ public class AiController {
|
||||
case FlipOntoBattlefield:
|
||||
if ("DamageCreatures".equals(sa.getParam("AILogic"))) {
|
||||
int maxToughness = Integer.parseInt(sa.getSubAbility().getParam("NumDmg"));
|
||||
CardCollectionView rightToughness = CardLists.filter(pool, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return card.getController().isOpponentOf(sa.getActivatingPlayer())
|
||||
CardCollectionView rightToughness = CardLists.filter(pool, card -> card.getController().isOpponentOf(sa.getActivatingPlayer())
|
||||
&& card.getNetToughness() <= maxToughness
|
||||
&& card.canBeDestroyed();
|
||||
}
|
||||
});
|
||||
&& card.canBeDestroyed());
|
||||
Card bestCreature = ComputerUtilCard.getBestCreatureAI(rightToughness.isEmpty() ? pool : rightToughness);
|
||||
if (bestCreature != null) {
|
||||
result.add(bestCreature);
|
||||
@@ -2140,7 +2122,7 @@ public class AiController {
|
||||
CardCollection all = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.NONLAND_PERMANENTS);
|
||||
CardCollection left = CardLists.filterControlledBy(all, game.getNextPlayerAfter(player, Direction.Left));
|
||||
CardCollection right = CardLists.filterControlledBy(all, game.getNextPlayerAfter(player, Direction.Right));
|
||||
return Aggregates.sum(left, Accessors.fnGetCmc) > Aggregates.sum(right, Accessors.fnGetCmc);
|
||||
return Aggregates.sum(left, Card::getCMC) > Aggregates.sum(right, Card::getCMC);
|
||||
}
|
||||
return MyRandom.getRandom().nextBoolean();
|
||||
}
|
||||
@@ -2167,8 +2149,8 @@ public class AiController {
|
||||
} else if (aiLogic.equals("CMCOppControlsByPower")) {
|
||||
// TODO: improve this to check for how dangerous those creatures actually are relative to host card
|
||||
CardCollectionView hand = sa.getActivatingPlayer().getOpponents().getCardsIn(ZoneType.Battlefield);
|
||||
int powerEven = Aggregates.sum(CardLists.filter(hand, CardPredicates.evenCMC()), Accessors.fnGetNetPower);
|
||||
int powerOdd = Aggregates.sum(CardLists.filter(hand, CardPredicates.oddCMC()), Accessors.fnGetNetPower);
|
||||
int powerEven = Aggregates.sum(CardLists.filter(hand, CardPredicates.evenCMC()), Card::getNetPower);
|
||||
int powerOdd = Aggregates.sum(CardLists.filter(hand, CardPredicates.oddCMC()), Card::getNetPower);
|
||||
return powerOdd > powerEven;
|
||||
}
|
||||
return MyRandom.getRandom().nextBoolean(); // outside of any specific logic, choose randomly
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package forge.ai;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Lists;
|
||||
import forge.card.CardType;
|
||||
@@ -445,16 +444,13 @@ public class AiCostDecision extends CostDecisionMakerBase {
|
||||
CardCollectionView toExclude =
|
||||
CardLists.getValidCards(player.getCardsIn(ZoneType.Battlefield), type.split(";"),
|
||||
ability.getActivatingPlayer(), ability.getHostCard(), ability);
|
||||
toExclude = CardLists.filter(toExclude, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
toExclude = CardLists.filter(toExclude, card -> {
|
||||
for (final SpellAbility sa : card.getSpellAbilities()) {
|
||||
if (sa.isManaAbility() && sa.getPayCosts().hasTapCost()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
exclude.addAll(toExclude);
|
||||
}
|
||||
@@ -642,16 +638,13 @@ public class AiCostDecision extends CostDecisionMakerBase {
|
||||
|
||||
// filter for negative counters
|
||||
if (c > toRemove && cost.counter == null) {
|
||||
List<Card> negatives = CardLists.filter(typeList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card crd) {
|
||||
List<Card> negatives = CardLists.filter(typeList, crd -> {
|
||||
for (CounterType cType : table.filterToRemove(crd).keySet()) {
|
||||
if (ComputerUtil.isNegativeCounter(cType, crd)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (!negatives.isEmpty()) {
|
||||
@@ -673,16 +666,13 @@ public class AiCostDecision extends CostDecisionMakerBase {
|
||||
// filter for useless counters
|
||||
// they have no effect on the card, if they are there or removed
|
||||
if (c > toRemove && cost.counter == null) {
|
||||
List<Card> useless = CardLists.filter(typeList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card crd) {
|
||||
List<Card> useless = CardLists.filter(typeList, crd -> {
|
||||
for (CounterType ctype : table.filterToRemove(crd).keySet()) {
|
||||
if (ComputerUtil.isUselessCounter(ctype, crd)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (!useless.isEmpty()) {
|
||||
@@ -710,9 +700,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
|
||||
// try to remove Quest counter on something with enough counters for the
|
||||
// effect to continue
|
||||
if (c > toRemove && (cost.counter == null || cost.counter.is(CounterEnumType.QUEST))) {
|
||||
List<Card> prefs = CardLists.filter(typeList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card crd) {
|
||||
List<Card> prefs = CardLists.filter(typeList, crd -> {
|
||||
// a Card without MaxQuestEffect doesn't need any Quest
|
||||
// counters
|
||||
int e = 0;
|
||||
@@ -720,7 +708,6 @@ public class AiCostDecision extends CostDecisionMakerBase {
|
||||
e = Integer.parseInt(crd.getSVar("MaxQuestEffect"));
|
||||
}
|
||||
return crd.getCounters(CounterEnumType.QUEST) > e;
|
||||
}
|
||||
});
|
||||
prefs.sort(Collections.reverseOrder(CardPredicates.compareByCounterType(CounterEnumType.QUEST)));
|
||||
|
||||
|
||||
@@ -11,11 +11,8 @@ import forge.game.zone.ZoneType;
|
||||
|
||||
public final class AiPlayerPredicates {
|
||||
|
||||
public static final Comparator<Player> compareByZoneValue(final String type, final ZoneType zone,
|
||||
final SpellAbility sa) {
|
||||
return new Comparator<Player>() {
|
||||
@Override
|
||||
public int compare(Player arg0, Player arg1) {
|
||||
public static Comparator<Player> compareByZoneValue(final String type, final ZoneType zone, final SpellAbility sa) {
|
||||
return (arg0, arg1) -> {
|
||||
CardCollectionView list0 = AbilityUtils.filterListByType(arg0.getCardsIn(zone), type, sa);
|
||||
CardCollectionView list1 = AbilityUtils.filterListByType(arg1.getCardsIn(zone), type, sa);
|
||||
|
||||
@@ -32,7 +29,6 @@ public final class AiPlayerPredicates {
|
||||
v1 = ComputerUtilCard.evaluatePermanentList(list1);
|
||||
}
|
||||
return Integer.compare(v0, v1);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ public class AiProfileUtil {
|
||||
* Load a single profile.
|
||||
* @param profileName a profile to load.
|
||||
*/
|
||||
private static final Map<AiProps, String> loadProfile(final String profileName) {
|
||||
private static Map<AiProps, String> loadProfile(final String profileName) {
|
||||
Map<AiProps, String> profileMap = new HashMap<>();
|
||||
|
||||
List<String> lines = FileUtil.readFile(buildFileName(profileName));
|
||||
|
||||
@@ -408,13 +408,9 @@ public class ComputerUtil {
|
||||
return ComputerUtilCard.getWorstLand(landsInPlay);
|
||||
}
|
||||
}
|
||||
final CardCollection sacMeList = CardLists.filter(typeList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return (c.hasSVar("SacMe") && Integer.parseInt(c.getSVar("SacMe")) == priority)
|
||||
|| (priority == 1 && shouldSacrificeThreatenedCard(ai, c, sa));
|
||||
}
|
||||
});
|
||||
final CardCollection sacMeList = CardLists.filter(typeList, c -> (c.hasSVar("SacMe") && Integer.parseInt(c.getSVar("SacMe")) == priority)
|
||||
|| (priority == 1 && shouldSacrificeThreatenedCard(ai, c, sa))
|
||||
);
|
||||
if (!sacMeList.isEmpty()) {
|
||||
CardLists.shuffle(sacMeList);
|
||||
return sacMeList.getFirst();
|
||||
@@ -429,16 +425,13 @@ public class ComputerUtil {
|
||||
int maxCreatureEval = aic.getIntProperty(AiProps.SACRIFICE_DEFAULT_PREF_MAX_CREATURE_EVAL);
|
||||
boolean allowTokens = aic.getBooleanProperty(AiProps.SACRIFICE_DEFAULT_PREF_ALLOW_TOKENS);
|
||||
List<String> dontSac = Arrays.asList("Black Lotus", "Mox Pearl", "Mox Jet", "Mox Emerald", "Mox Ruby", "Mox Sapphire", "Lotus Petal");
|
||||
CardCollection allowList = CardLists.filter(typeList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
CardCollection allowList = CardLists.filter(typeList, card -> {
|
||||
if (card.isCreature() && ComputerUtilCard.evaluateCreature(card) > maxCreatureEval) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (allowTokens && card.isToken())
|
||||
|| (card.getCMC() >= minCMC && card.getCMC() <= maxCMC && !dontSac.contains(card.getName()));
|
||||
}
|
||||
});
|
||||
if (!allowList.isEmpty()) {
|
||||
CardLists.sortByCmcDesc(allowList);
|
||||
@@ -455,7 +448,7 @@ public class ComputerUtil {
|
||||
final int landsInHand = Math.min(2, CardLists.getType(ai.getCardsIn(ZoneType.Hand), "Land").size());
|
||||
final CardCollection nonLandsInHand = CardLists.getNotType(ai.getCardsIn(ZoneType.Hand), "Land");
|
||||
nonLandsInHand.addAll(ai.getCardsIn(ZoneType.Library));
|
||||
final int highestCMC = Math.max(6, Aggregates.max(nonLandsInHand, CardPredicates.Accessors.fnGetCmc));
|
||||
final int highestCMC = Math.max(6, Aggregates.max(nonLandsInHand, Card::getCMC));
|
||||
if (landsInPlay.size() + landsInHand >= highestCMC) {
|
||||
// Don't need more land.
|
||||
return ComputerUtilCard.getWorstLand(landsInPlay);
|
||||
@@ -539,7 +532,7 @@ public class ComputerUtil {
|
||||
if (!landsInHand.isEmpty()) {
|
||||
final int numLandsInPlay = CardLists.count(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.LANDS_PRODUCING_MANA);
|
||||
final CardCollection nonLandsInHand = CardLists.getNotType(ai.getCardsIn(ZoneType.Hand), "Land");
|
||||
final int highestCMC = Math.max(6, Aggregates.max(nonLandsInHand, CardPredicates.Accessors.fnGetCmc));
|
||||
final int highestCMC = Math.max(6, Aggregates.max(nonLandsInHand, Card::getCMC));
|
||||
if (numLandsInPlay >= highestCMC
|
||||
|| (numLandsInPlay + landsInHand.size() > 6 && landsInHand.size() > 1)) {
|
||||
// Don't need more land.
|
||||
@@ -735,13 +728,10 @@ public class ComputerUtil {
|
||||
// FIXME: This is suboptimal, maybe implement a single comparator that'll take care of all of this?
|
||||
CardLists.sortByCmcDesc(typeList);
|
||||
Collections.reverse(typeList);
|
||||
typeList.sort(new Comparator<Card>() {
|
||||
@Override
|
||||
public int compare(final Card a, final Card b) {
|
||||
typeList.sort((a, b) -> {
|
||||
if (!a.isInPlay() && b.isInPlay()) return -1;
|
||||
else if (!b.isInPlay() && a.isInPlay()) return 1;
|
||||
else return 0;
|
||||
}
|
||||
}); // something that's not on the battlefield should come first
|
||||
}
|
||||
final CardCollection exileList = new CardCollection();
|
||||
@@ -958,9 +948,7 @@ public class ComputerUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
remaining = CardLists.filter(remaining, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
remaining = CardLists.filter(remaining, c -> {
|
||||
int sacThreshold = 190;
|
||||
|
||||
String logic = source.getParamOrDefault("AILogic", "");
|
||||
@@ -991,7 +979,6 @@ public class ComputerUtil {
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1362,7 +1349,7 @@ public class ComputerUtil {
|
||||
final CardCollection landsInPlay = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.LANDS_PRODUCING_MANA);
|
||||
final CardCollection landsInHand = CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.Presets.LANDS);
|
||||
final CardCollection nonLandsInHand = CardLists.getNotType(ai.getCardsIn(ZoneType.Hand), "Land");
|
||||
final int highestCMC = Math.max(6, Aggregates.max(nonLandsInHand, CardPredicates.Accessors.fnGetCmc));
|
||||
final int highestCMC = Math.max(6, Aggregates.max(nonLandsInHand, Card::getCMC));
|
||||
final int discardCMC = discard.getCMC();
|
||||
if (discard.isLand()) {
|
||||
if (landsInPlay.size() >= highestCMC
|
||||
@@ -2183,12 +2170,7 @@ public class ComputerUtil {
|
||||
AiController aic = ((PlayerControllerAi)ai.getController()).getAi();
|
||||
if (aic.getBooleanProperty(AiProps.AVOID_TARGETING_CREATS_THAT_WILL_DIE)) {
|
||||
// Try to avoid targeting creatures that are dead on board
|
||||
List<Card> willBeKilled = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return card.isCreature() && predictCreatureWillDieThisTurn(ai, card, excludeSa);
|
||||
}
|
||||
});
|
||||
List<Card> willBeKilled = CardLists.filter(list, card -> card.isCreature() && predictCreatureWillDieThisTurn(ai, card, excludeSa));
|
||||
list.removeAll(willBeKilled);
|
||||
}
|
||||
return list;
|
||||
@@ -2245,13 +2227,8 @@ public class ComputerUtil {
|
||||
return finalHandSize;
|
||||
}
|
||||
|
||||
final CardCollectionView lands = CardLists.filter(handList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.getManaCost().getCMC() <= 0 && !c.hasSVar("NeedsToPlay")
|
||||
&& (c.isLand() || c.isArtifact());
|
||||
}
|
||||
});
|
||||
final CardCollectionView lands = CardLists.filter(handList, c -> c.getManaCost().getCMC() <= 0 && !c.hasSVar("NeedsToPlay")
|
||||
&& (c.isLand() || c.isArtifact()));
|
||||
|
||||
final int handSize = handList.size();
|
||||
final int landSize = lands.size();
|
||||
@@ -2265,12 +2242,7 @@ public class ComputerUtil {
|
||||
score += 10;
|
||||
}
|
||||
|
||||
final CardCollectionView castables = CardLists.filter(handList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.getManaCost().getCMC() <= 0 || c.getManaCost().getCMC() <= landSize;
|
||||
}
|
||||
});
|
||||
final CardCollectionView castables = CardLists.filter(handList, c -> c.getManaCost().getCMC() <= 0 || c.getManaCost().getCMC() <= landSize);
|
||||
|
||||
score += castables.size() * 2;
|
||||
|
||||
@@ -2431,7 +2403,7 @@ public class ComputerUtil {
|
||||
} else if (c.isCreature()) {
|
||||
CardCollection creaturesOTB = CardLists.filter(cardsOTB, CardPredicates.Presets.CREATURES);
|
||||
int avgCreatureValue = numCards != 0 ? ComputerUtilCard.evaluateCreatureList(allCreatures) / numCards : 0;
|
||||
int maxControlledCMC = Aggregates.max(creaturesOTB, CardPredicates.Accessors.fnGetCmc);
|
||||
int maxControlledCMC = Aggregates.max(creaturesOTB, Card::getCMC);
|
||||
|
||||
if (ComputerUtilCard.evaluateCreature(c) < avgCreatureValue) {
|
||||
if (creaturesOTB.size() > minCreatsToScryCreatsAway) {
|
||||
@@ -2460,12 +2432,7 @@ public class ComputerUtil {
|
||||
}
|
||||
|
||||
public static CardCollection getCardsToDiscardFromOpponent(Player chooser, Player discarder, SpellAbility sa, CardCollection validCards, int min, int max) {
|
||||
CardCollection goodChoices = CardLists.filter(validCards, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return !c.hasSVar("DiscardMeByOpp") && !c.hasSVar("DiscardMe");
|
||||
}
|
||||
});
|
||||
CardCollection goodChoices = CardLists.filter(validCards, c -> !c.hasSVar("DiscardMeByOpp") && !c.hasSVar("DiscardMe"));
|
||||
if (goodChoices.isEmpty()) {
|
||||
goodChoices = validCards;
|
||||
}
|
||||
@@ -2859,25 +2826,17 @@ public class ComputerUtil {
|
||||
}
|
||||
|
||||
public static CardCollection getSafeTargets(final Player ai, SpellAbility sa, CardCollectionView validCards) {
|
||||
CardCollection safeCards = CardLists.filter(validCards, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
CardCollection safeCards = CardLists.filter(validCards, c -> {
|
||||
if (c.getController() == ai) {
|
||||
return !c.getSVar("Targeting").equals("Dies") && !c.getSVar("Targeting").equals("Counter");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return safeCards;
|
||||
}
|
||||
|
||||
public static Card getKilledByTargeting(final SpellAbility sa, CardCollectionView validCards) {
|
||||
CardCollection killables = CardLists.filter(validCards, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.getController() != sa.getActivatingPlayer() && c.getSVar("Targeting").equals("Dies");
|
||||
}
|
||||
});
|
||||
CardCollection killables = CardLists.filter(validCards, c -> c.getController() != sa.getActivatingPlayer() && c.getSVar("Targeting").equals("Dies"));
|
||||
return ComputerUtilCard.getBestCreatureAI(killables);
|
||||
}
|
||||
|
||||
@@ -3233,12 +3192,7 @@ public class ComputerUtil {
|
||||
CardCollectionView inHand = ai.getCardsIn(ZoneType.Hand);
|
||||
CardCollectionView inDeck = ai.getCardsIn(ZoneType.Library);
|
||||
|
||||
Predicate<Card> markedAsReanimator = new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return "true".equalsIgnoreCase(card.getSVar("IsReanimatorCard"));
|
||||
}
|
||||
};
|
||||
Predicate<Card> markedAsReanimator = card -> "true".equalsIgnoreCase(card.getSVar("IsReanimatorCard"));
|
||||
|
||||
int numInHand = CardLists.count(inHand, markedAsReanimator);
|
||||
int numInDeck = CardLists.count(inDeck, markedAsReanimator);
|
||||
@@ -3271,12 +3225,7 @@ public class ComputerUtil {
|
||||
value = ComputerUtilCard.evaluateCreature(source);
|
||||
}
|
||||
final int totalValue = value;
|
||||
list = CardLists.filter(srcList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return ComputerUtilCard.evaluateCreature(c) > totalValue + 30;
|
||||
}
|
||||
});
|
||||
list = CardLists.filter(srcList, c -> ComputerUtilCard.evaluateCreature(c) > totalValue + 30);
|
||||
} else {
|
||||
list = CardLists.getValidCards(srcList, sa.getParam("AITgts"), sa.getActivatingPlayer(), source, sa);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.card.CardStateName;
|
||||
@@ -38,9 +37,7 @@ public class ComputerUtilAbility {
|
||||
CardCollection landList = CardLists.filter(hand, Presets.LANDS);
|
||||
|
||||
//filter out cards that can't be played
|
||||
landList = CardLists.filter(landList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
landList = CardLists.filter(landList, c -> {
|
||||
if (!c.getSVar("NeedsToPlay").isEmpty()) {
|
||||
final String needsToPlay = c.getSVar("NeedsToPlay");
|
||||
CardCollection list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), needsToPlay, c.getController(), c, null);
|
||||
@@ -49,7 +46,6 @@ public class ComputerUtilAbility {
|
||||
}
|
||||
}
|
||||
return player.canPlayLand(c);
|
||||
}
|
||||
});
|
||||
|
||||
final CardCollection landsNotInHand = new CardCollection(player.getCardsIn(ZoneType.Graveyard));
|
||||
|
||||
@@ -58,12 +58,7 @@ public class ComputerUtilCard {
|
||||
public static Card getMostExpensivePermanentAI(final CardCollectionView list, final SpellAbility spell, final boolean targeted) {
|
||||
CardCollectionView all = list;
|
||||
if (targeted) {
|
||||
all = CardLists.filter(all, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.canBeTargetedBy(spell);
|
||||
}
|
||||
});
|
||||
all = CardLists.filter(all, c -> c.canBeTargetedBy(spell));
|
||||
}
|
||||
return getMostExpensivePermanentAI(all);
|
||||
}
|
||||
@@ -96,7 +91,7 @@ public class ComputerUtilCard {
|
||||
return null;
|
||||
}
|
||||
// get biggest Artifact
|
||||
return Aggregates.itemWithMax(all, CardPredicates.Accessors.fnGetCmc);
|
||||
return Aggregates.itemWithMax(all, Card::getCMC);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,7 +106,7 @@ public class ComputerUtilCard {
|
||||
return null;
|
||||
}
|
||||
// no AI logic, just return most expensive
|
||||
return Aggregates.itemWithMax(all, CardPredicates.Accessors.fnGetCmc);
|
||||
return Aggregates.itemWithMax(all, Card::getCMC);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,7 +121,7 @@ public class ComputerUtilCard {
|
||||
return null;
|
||||
}
|
||||
// no AI logic, just return least expensive
|
||||
return Aggregates.itemWithMin(all, CardPredicates.Accessors.fnGetCmc);
|
||||
return Aggregates.itemWithMin(all, Card::getCMC);
|
||||
}
|
||||
|
||||
public static Card getBestPlaneswalkerToDamage(final List<Card> pws) {
|
||||
@@ -194,16 +189,11 @@ public class ComputerUtilCard {
|
||||
public static Card getBestEnchantmentAI(final List<Card> list, final SpellAbility spell, final boolean targeted) {
|
||||
List<Card> all = CardLists.filter(list, CardPredicates.Presets.ENCHANTMENTS);
|
||||
if (targeted) {
|
||||
all = CardLists.filter(all, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.canBeTargetedBy(spell);
|
||||
}
|
||||
});
|
||||
all = CardLists.filter(all, c -> c.canBeTargetedBy(spell));
|
||||
}
|
||||
|
||||
// get biggest Enchantment
|
||||
return Aggregates.itemWithMax(all, CardPredicates.Accessors.fnGetCmc);
|
||||
return Aggregates.itemWithMax(all, Card::getCMC);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -342,12 +332,7 @@ public class ComputerUtilCard {
|
||||
*/
|
||||
public static Card getCheapestPermanentAI(Iterable<Card> all, final SpellAbility spell, final boolean targeted) {
|
||||
if (targeted) {
|
||||
all = CardLists.filter(all, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.canBeTargetedBy(spell);
|
||||
}
|
||||
});
|
||||
all = CardLists.filter(all, c -> c.canBeTargetedBy(spell));
|
||||
}
|
||||
if (Iterables.isEmpty(all)) {
|
||||
return null;
|
||||
@@ -524,12 +509,10 @@ public class ComputerUtilCard {
|
||||
}
|
||||
|
||||
if (hasEnchantmants || hasArtifacts) {
|
||||
final List<Card> ae = CardLists.filter(list, Predicates.and(Predicates.or(CardPredicates.Presets.ARTIFACTS, CardPredicates.Presets.ENCHANTMENTS), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return !card.hasSVar("DoNotDiscardIfAble");
|
||||
}
|
||||
}));
|
||||
final List<Card> ae = CardLists.filter(list, Predicates.and(
|
||||
Predicates.or(CardPredicates.Presets.ARTIFACTS, CardPredicates.Presets.ENCHANTMENTS),
|
||||
card -> !card.hasSVar("DoNotDiscardIfAble")
|
||||
));
|
||||
return getCheapestPermanentAI(ae, null, false);
|
||||
}
|
||||
|
||||
@@ -568,18 +551,10 @@ public class ComputerUtilCard {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static final Comparator<Card> EvaluateCreatureComparator = new Comparator<Card>() {
|
||||
@Override
|
||||
public int compare(final Card a, final Card b) {
|
||||
return evaluateCreature(b) - evaluateCreature(a);
|
||||
}
|
||||
};
|
||||
public static final Comparator<SpellAbility> EvaluateCreatureSpellComparator = new Comparator<SpellAbility>() {
|
||||
@Override
|
||||
public int compare(final SpellAbility a, final SpellAbility b) {
|
||||
public static final Comparator<Card> EvaluateCreatureComparator = (a, b) -> evaluateCreature(b) - evaluateCreature(a);
|
||||
public static final Comparator<SpellAbility> EvaluateCreatureSpellComparator = (a, b) -> {
|
||||
// TODO ideally we could reuse the value from the previous pass with false
|
||||
return ComputerUtilAbility.saEvaluator.compareEvaluator(a, b, true);
|
||||
}
|
||||
};
|
||||
|
||||
private static final CreatureEvaluator creatureEvaluator = new CreatureEvaluator();
|
||||
@@ -774,7 +749,7 @@ public class ComputerUtilCard {
|
||||
// Add all cost of all auras with the same controller
|
||||
if (card.isEnchanted()) {
|
||||
final List<Card> auras = CardLists.filterControlledBy(card.getEnchantedBy(), card.getController());
|
||||
curCMC += Aggregates.sum(auras, CardPredicates.Accessors.fnGetCmc) + auras.size();
|
||||
curCMC += Aggregates.sum(auras, Card::getCMC) + auras.size();
|
||||
}
|
||||
|
||||
if (curCMC >= bigCMC) {
|
||||
@@ -990,12 +965,7 @@ public class ComputerUtilCard {
|
||||
if (color.hasGreen()) map.get(4).setValue(map.get(4).getValue() + 1);
|
||||
}
|
||||
|
||||
Collections.sort(map, new Comparator<Pair<Byte, Integer>>() {
|
||||
@Override
|
||||
public int compare(Pair<Byte, Integer> o1, Pair<Byte, Integer> o2) {
|
||||
return o2.getValue() - o1.getValue();
|
||||
}
|
||||
});
|
||||
Collections.sort(map, Comparator.<Pair<Byte, Integer>>comparingInt(Pair::getValue).reversed());
|
||||
|
||||
// will this part be once dropped?
|
||||
List<String> result = new ArrayList<>(cntColors);
|
||||
@@ -1006,9 +976,7 @@ public class ComputerUtilCard {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static final Predicate<Deck> AI_KNOWS_HOW_TO_PLAY_ALL_CARDS = new Predicate<Deck>() {
|
||||
@Override
|
||||
public boolean apply(Deck d) {
|
||||
public static final Predicate<Deck> AI_KNOWS_HOW_TO_PLAY_ALL_CARDS = d -> {
|
||||
for (Entry<DeckSection, CardPool> cp : d) {
|
||||
for (Entry<PaperCard, Integer> e : cp.getValue()) {
|
||||
if (e.getKey().getRules().getAiHints().getRemAIDecks())
|
||||
@@ -1016,7 +984,6 @@ public class ComputerUtilCard {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
public static List<String> chooseColor(SpellAbility sa, int min, int max, List<String> colorChoices) {
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
package forge.ai;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
@@ -79,11 +78,7 @@ public class ComputerUtilCombat {
|
||||
*/
|
||||
public static boolean canAttackNextTurn(final Card attacker) {
|
||||
final Iterable<GameEntity> defenders = CombatUtil.getAllPossibleDefenders(attacker.getController());
|
||||
return Iterables.any(defenders, new Predicate<GameEntity>() {
|
||||
@Override public boolean apply(final GameEntity input) {
|
||||
return canAttackNextTurn(attacker, input);
|
||||
}
|
||||
});
|
||||
return Iterables.any(defenders, input -> canAttackNextTurn(attacker, input));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,12 +133,7 @@ public class ComputerUtilCombat {
|
||||
*/
|
||||
public static int getTotalFirstStrikeBlockPower(final Card attacker, final Player player) {
|
||||
List<Card> list = player.getCreaturesInPlay();
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return (c.hasFirstStrike() || c.hasDoubleStrike()) && CombatUtil.canBlock(attacker, c);
|
||||
}
|
||||
});
|
||||
list = CardLists.filter(list, c -> (c.hasFirstStrike() || c.hasDoubleStrike()) && CombatUtil.canBlock(attacker, c));
|
||||
|
||||
return totalFirstStrikeDamageOfBlockers(attacker, list);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package forge.ai;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -472,12 +471,7 @@ public class ComputerUtilCost {
|
||||
String totalP = type.split("withTotalPowerGE")[1];
|
||||
type = TextUtil.fastReplace(type, TextUtil.concatNoSpace("+withTotalPowerGE", totalP), "");
|
||||
CardCollection exclude = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), source.getController(), source, sa);
|
||||
exclude = CardLists.filter(exclude, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return ComputerUtilCard.evaluateCreature(c) >= vehicleValue;
|
||||
}
|
||||
}); // exclude creatures >= vehicle
|
||||
exclude = CardLists.filter(exclude, c -> ComputerUtilCard.evaluateCreature(c) >= vehicleValue); // exclude creatures >= vehicle
|
||||
exclude.addAll(alreadyTapped);
|
||||
CardCollection tappedCrew = ComputerUtil.chooseTapTypeAccumulatePower(ai, type, sa, true, Integer.parseInt(totalP), exclude);
|
||||
if (tappedCrew != null) {
|
||||
@@ -616,18 +610,15 @@ public class ComputerUtilCost {
|
||||
CardCollectionView nonManaSources =
|
||||
CardLists.getValidCards(player.getCardsIn(ZoneType.Battlefield), part.getType().split(";"),
|
||||
sa.getActivatingPlayer(), sa.getHostCard(), sa);
|
||||
nonManaSources = CardLists.filter(nonManaSources, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
nonManaSources = CardLists.filter(nonManaSources, card -> {
|
||||
boolean hasManaSa = false;
|
||||
for (final SpellAbility sa : card.getSpellAbilities()) {
|
||||
if (sa.isManaAbility() && sa.getPayCosts().hasTapCost()) {
|
||||
for (final SpellAbility sa1 : card.getSpellAbilities()) {
|
||||
if (sa1.isManaAbility() && sa1.getPayCosts().hasTapCost()) {
|
||||
hasManaSa = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return !hasManaSa;
|
||||
}
|
||||
});
|
||||
if (nonManaSources.size() < part.convertAmount()) {
|
||||
return false;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package forge.ai;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.*;
|
||||
import forge.ai.AiCardMemory.MemorySet;
|
||||
@@ -126,12 +125,7 @@ public class ComputerUtilMana {
|
||||
}
|
||||
}
|
||||
}
|
||||
orderedCards.sort(new Comparator<Card>() {
|
||||
@Override
|
||||
public int compare(final Card card1, final Card card2) {
|
||||
return Integer.compare(manaCardMap.get(card1), manaCardMap.get(card2));
|
||||
}
|
||||
});
|
||||
orderedCards.sort(Comparator.comparingInt(manaCardMap::get));
|
||||
|
||||
if (DEBUG_MANA_PAYMENT) {
|
||||
System.out.print("Ordered Cards: " + orderedCards.size());
|
||||
@@ -149,9 +143,7 @@ public class ComputerUtilMana {
|
||||
System.out.println("Unsorted Abilities: " + newAbilities);
|
||||
}
|
||||
|
||||
newAbilities.sort(new Comparator<SpellAbility>() {
|
||||
@Override
|
||||
public int compare(final SpellAbility ability1, final SpellAbility ability2) {
|
||||
newAbilities.sort((ability1, ability2) -> {
|
||||
int preOrder = orderedCards.indexOf(ability1.getHostCard()) - orderedCards.indexOf(ability2.getHostCard());
|
||||
|
||||
if (preOrder != 0) {
|
||||
@@ -171,7 +163,6 @@ public class ComputerUtilMana {
|
||||
}
|
||||
|
||||
return ability1.compareTo(ability2);
|
||||
}
|
||||
});
|
||||
|
||||
if (DEBUG_MANA_PAYMENT) {
|
||||
@@ -195,27 +186,21 @@ public class ComputerUtilMana {
|
||||
final List<SpellAbility> prefSortedAbilities = new ArrayList<>(newAbilities);
|
||||
final List<SpellAbility> otherSortedAbilities = new ArrayList<>(newAbilities);
|
||||
|
||||
prefSortedAbilities.sort(new Comparator<SpellAbility>() {
|
||||
@Override
|
||||
public int compare(final SpellAbility ability1, final SpellAbility ability2) {
|
||||
prefSortedAbilities.sort((ability1, ability2) -> {
|
||||
if (ability1.getManaPart().mana(ability1).contains(preferredShard))
|
||||
return -1;
|
||||
else if (ability2.getManaPart().mana(ability2).contains(preferredShard))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
otherSortedAbilities.sort(new Comparator<SpellAbility>() {
|
||||
@Override
|
||||
public int compare(final SpellAbility ability1, final SpellAbility ability2) {
|
||||
otherSortedAbilities.sort((ability1, ability2) -> {
|
||||
if (ability1.getManaPart().mana(ability1).contains(preferredShard))
|
||||
return 1;
|
||||
else if (ability2.getManaPart().mana(ability2).contains(preferredShard))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
final List<SpellAbility> finalAbilities = new ArrayList<>();
|
||||
@@ -251,24 +236,14 @@ public class ComputerUtilMana {
|
||||
List<SpellAbility> filteredList = Lists.newArrayList(saList);
|
||||
switch (manaSourceType) {
|
||||
case "Snow":
|
||||
filteredList.sort(new Comparator<SpellAbility>() {
|
||||
@Override
|
||||
public int compare(SpellAbility ab1, SpellAbility ab2) {
|
||||
return ab1.getHostCard() != null && ab1.getHostCard().isSnow()
|
||||
&& ab2.getHostCard() != null && !ab2.getHostCard().isSnow() ? -1 : 1;
|
||||
}
|
||||
});
|
||||
filteredList.sort((ab1, ab2) -> ab1.getHostCard() != null && ab1.getHostCard().isSnow()
|
||||
&& ab2.getHostCard() != null && !ab2.getHostCard().isSnow() ? -1 : 1);
|
||||
saList = filteredList;
|
||||
break;
|
||||
case "Treasure":
|
||||
// Try to spend only one Treasure if possible
|
||||
filteredList.sort(new Comparator<SpellAbility>() {
|
||||
@Override
|
||||
public int compare(SpellAbility ab1, SpellAbility ab2) {
|
||||
return ab1.getHostCard() != null && ab1.getHostCard().getType().hasSubtype("Treasure")
|
||||
&& ab2.getHostCard() != null && !ab2.getHostCard().getType().hasSubtype("Treasure") ? -1 : 1;
|
||||
}
|
||||
});
|
||||
filteredList.sort((ab1, ab2) -> ab1.getHostCard() != null && ab1.getHostCard().getType().hasSubtype("Treasure")
|
||||
&& ab2.getHostCard() != null && !ab2.getHostCard().getType().hasSubtype("Treasure") ? -1 : 1);
|
||||
SpellAbility first = filteredList.get(0);
|
||||
if (first.getHostCard() != null && first.getHostCard().getType().hasSubtype("Treasure")) {
|
||||
saList.remove(first);
|
||||
@@ -280,22 +255,12 @@ public class ComputerUtilMana {
|
||||
break;
|
||||
case "TreasureMax":
|
||||
// Ok to spend as many Treasures as possible
|
||||
filteredList.sort(new Comparator<SpellAbility>() {
|
||||
@Override
|
||||
public int compare(SpellAbility ab1, SpellAbility ab2) {
|
||||
return ab1.getHostCard() != null && ab1.getHostCard().getType().hasSubtype("Treasure")
|
||||
&& ab2.getHostCard() != null && !ab2.getHostCard().getType().hasSubtype("Treasure") ? -1 : 1;
|
||||
}
|
||||
});
|
||||
filteredList.sort((ab1, ab2) -> ab1.getHostCard() != null && ab1.getHostCard().getType().hasSubtype("Treasure")
|
||||
&& ab2.getHostCard() != null && !ab2.getHostCard().getType().hasSubtype("Treasure") ? -1 : 1);
|
||||
saList = filteredList;
|
||||
break;
|
||||
case "NotSameCard":
|
||||
saList = Lists.newArrayList(Iterables.filter(filteredList, new Predicate<SpellAbility>() {
|
||||
@Override
|
||||
public boolean apply(final SpellAbility saPay) {
|
||||
return !saPay.getHostCard().getName().equals(sa.getHostCard().getName());
|
||||
}
|
||||
}));
|
||||
saList = Lists.newArrayList(Iterables.filter(filteredList, saPay -> !saPay.getHostCard().getName().equals(sa.getHostCard().getName())));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -1096,12 +1061,7 @@ public class ComputerUtilMana {
|
||||
private static ManaCostShard getNextShardToPay(ManaCostBeingPaid cost, Multimap<ManaCostShard, SpellAbility> sourcesForShards) {
|
||||
List<ManaCostShard> shardsToPay = Lists.newArrayList(cost.getDistinctShards());
|
||||
// optimize order so that the shards with less available sources are considered first
|
||||
shardsToPay.sort(new Comparator<ManaCostShard>() {
|
||||
@Override
|
||||
public int compare(final ManaCostShard shard1, final ManaCostShard shard2) {
|
||||
return sourcesForShards.get(shard1).size() - sourcesForShards.get(shard2).size();
|
||||
}
|
||||
});
|
||||
shardsToPay.sort(Comparator.comparingInt(shard -> sourcesForShards.get(shard).size()));
|
||||
// mind the priorities
|
||||
// * Pay mono-colored first
|
||||
// * Pay 2/C with matching colors
|
||||
@@ -1387,12 +1347,7 @@ public class ComputerUtilMana {
|
||||
public static int getAvailableManaEstimate(final Player p, final boolean checkPlayable) {
|
||||
int availableMana = 0;
|
||||
|
||||
final List<Card> srcs = CardLists.filter(p.getCardsIn(ZoneType.Battlefield), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return !c.getManaAbilities().isEmpty();
|
||||
}
|
||||
});
|
||||
final List<Card> srcs = CardLists.filter(p.getCardsIn(ZoneType.Battlefield), c -> !c.getManaAbilities().isEmpty());
|
||||
|
||||
int maxProduced = 0;
|
||||
int producedWithCost = 0;
|
||||
@@ -1437,9 +1392,7 @@ public class ComputerUtilMana {
|
||||
//This method is currently used by AI to estimate available mana
|
||||
public static CardCollection getAvailableManaSources(final Player ai, final boolean checkPlayable) {
|
||||
final CardCollectionView list = CardCollection.combine(ai.getCardsIn(ZoneType.Battlefield), ai.getCardsIn(ZoneType.Hand));
|
||||
final List<Card> manaSources = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
final List<Card> manaSources = CardLists.filter(list, c -> {
|
||||
for (final SpellAbility am : getAIPlayableMana(c)) {
|
||||
am.setActivatingPlayer(ai, true);
|
||||
if (!checkPlayable || (am.canPlay() && am.checkRestrictions(ai))) {
|
||||
@@ -1447,7 +1400,6 @@ public class ComputerUtilMana {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}); // CardListFilter
|
||||
|
||||
final CardCollection sortedManaSources = new CardCollection();
|
||||
|
||||
@@ -570,12 +570,9 @@ public class PlayerControllerAi extends PlayerController {
|
||||
|
||||
if (destinationZone == ZoneType.Graveyard) {
|
||||
// In presence of Volrath's Shapeshifter in deck, try to place the best creature on top of the graveyard
|
||||
if (Iterables.any(getGame().getCardsInGame(), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
if (Iterables.any(getGame().getCardsInGame(), card -> {
|
||||
// need a custom predicate here since Volrath's Shapeshifter may have a different name OTB
|
||||
return card.getOriginalState(CardStateName.Original).getName().equals("Volrath's Shapeshifter");
|
||||
}
|
||||
})) {
|
||||
int bestValue = 0;
|
||||
Card bestCreature = null;
|
||||
@@ -702,7 +699,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
public CardCollectionView chooseCardsToDiscardUnlessType(int num, CardCollectionView hand, String uType, SpellAbility sa) {
|
||||
Iterable<Card> cardsOfType = Iterables.filter(hand, CardPredicates.restriction(uType.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa));
|
||||
if (!Iterables.isEmpty(cardsOfType)) {
|
||||
Card toDiscard = Aggregates.itemWithMin(cardsOfType, CardPredicates.Accessors.fnGetCmc);
|
||||
Card toDiscard = Aggregates.itemWithMin(cardsOfType, Card::getCMC);
|
||||
return new CardCollection(toDiscard);
|
||||
}
|
||||
return getAi().getCardsToDiscard(num, null, sa);
|
||||
@@ -1389,21 +1386,12 @@ public class PlayerControllerAi extends PlayerController {
|
||||
final Player ai = sa.getActivatingPlayer();
|
||||
final PhaseHandler ph = ai.getGame().getPhaseHandler();
|
||||
//Filter out mana sources that will interfere with payManaCost()
|
||||
CardCollection untapped = CardLists.filter(untappedCards, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.getManaAbilities().isEmpty();
|
||||
}
|
||||
});
|
||||
CardCollection untapped = CardLists.filter(untappedCards, c -> c.getManaAbilities().isEmpty());
|
||||
|
||||
// Filter out creatures if AI hasn't attacked yet
|
||||
if (ph.isPlayerTurn(ai) && ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
|
||||
if (improvise) {
|
||||
untapped = CardLists.filter(untapped, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {return !c.isCreature();
|
||||
}
|
||||
});
|
||||
untapped = CardLists.filter(untapped, c -> !c.isCreature());
|
||||
} else {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package forge.ai;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
@@ -91,13 +90,10 @@ public class SpecialAiLogic {
|
||||
bestOwnCardToUpgrade = Iterables.getFirst(CardLists.getKeyword(listOwn, Keyword.INDESTRUCTIBLE), null);
|
||||
}
|
||||
if (bestOwnCardToUpgrade == null) {
|
||||
bestOwnCardToUpgrade = ComputerUtilCard.getWorstCreatureAI(CardLists.filter(listOwn, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return card.isCreature() && (ComputerUtilCard.isUselessCreature(ai, card)
|
||||
|| ComputerUtilCard.evaluateCreature(token) > 2 * ComputerUtilCard.evaluateCreature(card));
|
||||
}
|
||||
}));
|
||||
bestOwnCardToUpgrade = ComputerUtilCard.getWorstCreatureAI(CardLists.filter(listOwn, card -> card.isCreature()
|
||||
&& (ComputerUtilCard.isUselessCreature(ai, card)
|
||||
|| ComputerUtilCard.evaluateCreature(token) > 2 * ComputerUtilCard.evaluateCreature(card))
|
||||
));
|
||||
}
|
||||
if (bestOwnCardToUpgrade != null) {
|
||||
if (ComputerUtilCard.isUselessCreature(ai, bestOwnCardToUpgrade) || (ph.getPhase().isAfter(PhaseType.COMBAT_END) || !ph.isPlayerTurn(ai))) {
|
||||
@@ -145,14 +141,9 @@ public class SpecialAiLogic {
|
||||
|
||||
if (indestructible || (source.getNetToughness() <= dmg && source.getNetToughness() + toughnessBonus * numCreatsToSac > dmg)) {
|
||||
final CardCollection sacFodder = CardLists.filter(ai.getCreaturesInPlay(),
|
||||
new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return ComputerUtilCard.isUselessCreature(ai, card)
|
||||
card -> ComputerUtilCard.isUselessCreature(ai, card)
|
||||
|| card.hasSVar("SacMe")
|
||||
|| ComputerUtilCard.evaluateCreature(card) < selfEval; // Maybe around 150 is OK?
|
||||
}
|
||||
}
|
||||
|| ComputerUtilCard.evaluateCreature(card) < selfEval // Maybe around 150 is OK?
|
||||
);
|
||||
return sacFodder.size() >= numCreatsToSac;
|
||||
}
|
||||
@@ -196,21 +187,16 @@ public class SpecialAiLogic {
|
||||
// We have already attacked. Thus, see if we have a creature to sac that is worse to lose
|
||||
// than the card we attacked with.
|
||||
final CardCollection sacTgts = CardLists.filter(ai.getCreaturesInPlay(),
|
||||
new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return ComputerUtilCard.isUselessCreature(ai, card)
|
||||
|| ComputerUtilCard.evaluateCreature(card) < selfEval;
|
||||
}
|
||||
}
|
||||
card -> ComputerUtilCard.isUselessCreature(ai, card)
|
||||
|| ComputerUtilCard.evaluateCreature(card) < selfEval
|
||||
);
|
||||
|
||||
if (sacTgts.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int minDefT = Aggregates.min(combat.getBlockers(source), CardPredicates.Accessors.fnGetNetToughness);
|
||||
final int DefP = indestructible ? 0 : Aggregates.sum(combat.getBlockers(source), CardPredicates.Accessors.fnGetNetPower);
|
||||
final int minDefT = Aggregates.min(combat.getBlockers(source), Card::getNetToughness);
|
||||
final int DefP = indestructible ? 0 : Aggregates.sum(combat.getBlockers(source), Card::getNetPower);
|
||||
|
||||
// Make sure we don't over-sacrifice, only sac until we can survive and kill a creature
|
||||
return source.getNetToughness() - source.getDamage() <= DefP || source.getNetCombatDamage() < minDefT;
|
||||
@@ -218,14 +204,9 @@ public class SpecialAiLogic {
|
||||
} else {
|
||||
// We can't deal lethal, check if there's any sac fodder than can be used for other circumstances
|
||||
final CardCollection sacFodder = CardLists.filter(ai.getCreaturesInPlay(),
|
||||
new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return ComputerUtilCard.isUselessCreature(ai, card)
|
||||
card -> ComputerUtilCard.isUselessCreature(ai, card)
|
||||
|| card.hasSVar("SacMe")
|
||||
|| ComputerUtilCard.evaluateCreature(card) < selfEval; // Maybe around 150 is OK?
|
||||
}
|
||||
}
|
||||
|| ComputerUtilCard.evaluateCreature(card) < selfEval // Maybe around 150 is OK?
|
||||
);
|
||||
|
||||
return !sacFodder.isEmpty();
|
||||
@@ -302,13 +283,8 @@ public class SpecialAiLogic {
|
||||
|
||||
// Check if there's anything that will die anyway that can be eaten to gain a perma-bonus
|
||||
final CardCollection forcedSacTgts = CardLists.filter(relevantCreats,
|
||||
new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return ComputerUtil.predictThreatenedObjects(ai, null, true).contains(card)
|
||||
|| (combat.isAttacking(card) && combat.isBlocked(card) && ComputerUtilCombat.combatantWouldBeDestroyed(ai, card, combat));
|
||||
}
|
||||
}
|
||||
card -> ComputerUtil.predictThreatenedObjects(ai, null, true).contains(card)
|
||||
|| (combat.isAttacking(card) && combat.isBlocked(card) && ComputerUtilCombat.combatantWouldBeDestroyed(ai, card, combat))
|
||||
);
|
||||
if (!forcedSacTgts.isEmpty()) {
|
||||
return true;
|
||||
@@ -327,14 +303,9 @@ public class SpecialAiLogic {
|
||||
// than the card we attacked with. Since we're getting a permanent bonus, consider sacrificing
|
||||
// things that are also threatened to be destroyed anyway.
|
||||
final CardCollection sacTgts = CardLists.filter(relevantCreats,
|
||||
new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return ComputerUtilCard.isUselessCreature(ai, card)
|
||||
card -> ComputerUtilCard.isUselessCreature(ai, card)
|
||||
|| ComputerUtilCard.evaluateCreature(card) < selfEval
|
||||
|| ComputerUtil.predictThreatenedObjects(ai, null, true).contains(card);
|
||||
}
|
||||
}
|
||||
|| ComputerUtil.predictThreatenedObjects(ai, null, true).contains(card)
|
||||
);
|
||||
|
||||
if (sacTgts.isEmpty()) {
|
||||
@@ -342,8 +313,8 @@ public class SpecialAiLogic {
|
||||
}
|
||||
|
||||
final boolean sourceCantDie = ComputerUtilCombat.combatantCantBeDestroyed(ai, source);
|
||||
final int minDefT = Aggregates.min(combat.getBlockers(source), CardPredicates.Accessors.fnGetNetToughness);
|
||||
final int DefP = sourceCantDie ? 0 : Aggregates.sum(combat.getBlockers(source), CardPredicates.Accessors.fnGetNetPower);
|
||||
final int minDefT = Aggregates.min(combat.getBlockers(source), Card::getNetToughness);
|
||||
final int DefP = sourceCantDie ? 0 : Aggregates.sum(combat.getBlockers(source), Card::getNetPower);
|
||||
|
||||
// Make sure we don't over-sacrifice, only sac until we can survive and kill a creature
|
||||
return source.getNetToughness() - source.getDamage() <= DefP || source.getNetCombatDamage() < minDefT;
|
||||
@@ -352,15 +323,10 @@ public class SpecialAiLogic {
|
||||
// We can't deal lethal, check if there's any sac fodder than can be used for other circumstances
|
||||
final boolean isBlocking = combat != null && combat.isBlocking(source);
|
||||
final CardCollection sacFodder = CardLists.filter(relevantCreats,
|
||||
new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return ComputerUtilCard.isUselessCreature(ai, card)
|
||||
card -> ComputerUtilCard.isUselessCreature(ai, card)
|
||||
|| card.hasSVar("SacMe")
|
||||
|| (isBlocking && ComputerUtilCard.evaluateCreature(card) < selfEval)
|
||||
|| ComputerUtil.predictThreatenedObjects(ai, null, true).contains(card);
|
||||
}
|
||||
}
|
||||
|| ComputerUtil.predictThreatenedObjects(ai, null, true).contains(card)
|
||||
);
|
||||
|
||||
return !sacFodder.isEmpty();
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
package forge.ai;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -478,8 +477,8 @@ public class SpecialCardAi {
|
||||
boolean cantDie = ComputerUtilCombat.combatantCantBeDestroyed(ai, source);
|
||||
|
||||
CardCollection opposition = isBlocking ? combat.getAttackersBlockedBy(source) : combat.getBlockers(source);
|
||||
int oppP = Aggregates.sum(opposition, CardPredicates.Accessors.fnGetAttack);
|
||||
int oppT = Aggregates.sum(opposition, CardPredicates.Accessors.fnGetNetToughness);
|
||||
int oppP = Aggregates.sum(opposition, Card::getNetCombatDamage);
|
||||
int oppT = Aggregates.sum(opposition, Card::getNetToughness);
|
||||
|
||||
boolean oppHasFirstStrike = false;
|
||||
boolean oppCantDie = true;
|
||||
@@ -561,7 +560,7 @@ public class SpecialCardAi {
|
||||
}
|
||||
|
||||
Pair<Integer, Integer> predictedPT = getPumpedPT(ai, source.getNetCombatDamage(), source.getNetToughness());
|
||||
int oppT = Aggregates.sum(potentialBlockers, CardPredicates.Accessors.fnGetNetToughness);
|
||||
int oppT = Aggregates.sum(potentialBlockers, Card::getNetToughness);
|
||||
|
||||
return potentialBlockers.isEmpty() || (source.hasKeyword(Keyword.TRAMPLE) && predictedPT.getLeft() - oppT >= oppLife);
|
||||
}
|
||||
@@ -754,28 +753,23 @@ public class SpecialCardAi {
|
||||
public static Card getBestAttachTarget(final Player ai, final SpellAbility sa, final List<Card> list) {
|
||||
Card chosen = null;
|
||||
|
||||
List<Card> aiStuffies = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
List<Card> aiStuffies = CardLists.filter(list, c -> {
|
||||
// Don't enchant creatures that can survive
|
||||
if (!c.getController().equals(ai)) {
|
||||
return false;
|
||||
}
|
||||
final String name = c.getName();
|
||||
return name.equals("Stuffy Doll") || name.equals("Boros Reckoner") || name.equals("Spitemare");
|
||||
}
|
||||
});
|
||||
if (!aiStuffies.isEmpty()) {
|
||||
chosen = aiStuffies.get(0);
|
||||
} else {
|
||||
List<Card> creatures = CardLists.filterControlledBy(list, ai.getOpponents());
|
||||
creatures = CardLists.filter(creatures, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
// Don't enchant creatures that can survive
|
||||
return c.canBeDestroyed() && c.getNetCombatDamage() >= c.getNetToughness() && !c.isEnchantedBy("Guilty Conscience");
|
||||
}
|
||||
});
|
||||
creatures = CardLists.filter(creatures, c -> c.canBeDestroyed()
|
||||
&& c.getNetCombatDamage() >= c.getNetToughness()
|
||||
&& !c.isEnchantedBy("Guilty Conscience")
|
||||
);
|
||||
chosen = ComputerUtilCard.getBestCreatureAI(creatures);
|
||||
}
|
||||
|
||||
@@ -1385,12 +1379,7 @@ public class SpecialCardAi {
|
||||
public static boolean considerMakeDragon(final Player ai, final SpellAbility sa) {
|
||||
// TODO: expand this logic to make the AI force the opponent to sacrifice a big threat bigger than a 5/5 flier?
|
||||
CardCollection creatures = ai.getCreaturesInPlay();
|
||||
boolean hasValidTgt = !CardLists.filter(creatures, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card t) {
|
||||
return t.getNetPower() < 5 && t.getNetToughness() < 5;
|
||||
}
|
||||
}).isEmpty();
|
||||
boolean hasValidTgt = !CardLists.filter(creatures, t -> t.getNetPower() < 5 && t.getNetToughness() < 5).isEmpty();
|
||||
if (hasValidTgt) {
|
||||
Card worstCreature = ComputerUtilCard.getWorstCreatureAI(creatures);
|
||||
sa.getTargets().add(worstCreature);
|
||||
@@ -1416,12 +1405,7 @@ public class SpecialCardAi {
|
||||
public static class SaviorOfOllenbock {
|
||||
public static boolean consider(final Player ai, final SpellAbility sa) {
|
||||
CardCollection oppTargetables = CardLists.getTargetableCards(ai.getOpponents().getCreaturesInPlay(), sa);
|
||||
CardCollection threats = CardLists.filter(oppTargetables, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return !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);
|
||||
|
||||
// TODO: improve the conditions for when the AI is considered threatened (check the possibility of being attacked?)
|
||||
@@ -1462,13 +1446,10 @@ public class SpecialCardAi {
|
||||
public static boolean consider(final Player ai, final SpellAbility sa) {
|
||||
int loyalty = sa.getHostCard().getCounters(CounterEnumType.LOYALTY);
|
||||
CardCollection creaturesToGet = CardLists.filter(ai.getCardsIn(ZoneType.Graveyard),
|
||||
Predicates.and(CardPredicates.Presets.CREATURES, CardPredicates.lessCMC(loyalty - 1), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
Predicates.and(CardPredicates.Presets.CREATURES, CardPredicates.lessCMC(loyalty - 1), card -> {
|
||||
final Card copy = CardCopyService.getLKICopy(card);
|
||||
ComputerUtilCard.applyStaticContPT(ai.getGame(), copy, null);
|
||||
return copy.getNetToughness() > 0;
|
||||
}
|
||||
}));
|
||||
CardLists.sortByCmcDesc(creaturesToGet);
|
||||
|
||||
@@ -1515,12 +1496,9 @@ public class SpecialCardAi {
|
||||
|
||||
// Cards in library that are either below/at (preferred) or above the max CMC affordable by the AI
|
||||
// (the latter might happen if we're playing a Reanimator deck with lots of fatties)
|
||||
CardCollection atTargetCMCInLib = CardLists.filter(creatsInLib, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return ComputerUtilMana.hasEnoughManaSourcesToCast(card.getSpellPermanent(), ai);
|
||||
}
|
||||
});
|
||||
CardCollection atTargetCMCInLib = CardLists.filter(creatsInLib,
|
||||
card -> ComputerUtilMana.hasEnoughManaSourcesToCast(card.getSpellPermanent(), ai)
|
||||
);
|
||||
if (atTargetCMCInLib.isEmpty()) {
|
||||
atTargetCMCInLib = CardLists.filter(creatsInLib, CardPredicates.greaterCMC(numManaSrcs));
|
||||
}
|
||||
@@ -1585,12 +1563,9 @@ public class SpecialCardAi {
|
||||
int numManaSrcs = ComputerUtilMana.getAvailableManaEstimate(ai, false)
|
||||
+ Math.min(1, manaSrcsInHand.size());
|
||||
|
||||
CardCollection atTargetCMCInLib = CardLists.filter(creatsInLib, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return ComputerUtilMana.hasEnoughManaSourcesToCast(card.getSpellPermanent(), ai);
|
||||
}
|
||||
});
|
||||
CardCollection atTargetCMCInLib = CardLists.filter(creatsInLib,
|
||||
card -> ComputerUtilMana.hasEnoughManaSourcesToCast(card.getSpellPermanent(), ai)
|
||||
);
|
||||
if (atTargetCMCInLib.isEmpty()) {
|
||||
atTargetCMCInLib = CardLists.filter(creatsInLib, CardPredicates.greaterCMC(numManaSrcs));
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import java.util.*;
|
||||
import forge.game.card.*;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
@@ -333,9 +332,7 @@ public class AttachAi extends SpellAbilityAi {
|
||||
list = CardLists.getNotType(list, type); // Filter out Basic Lands that have the same type as the changing type
|
||||
|
||||
// Don't target fetchlands
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
list = CardLists.filter(list, c -> {
|
||||
//Check for cards that can be sacrificed in response
|
||||
for (final SpellAbility ability : c.getAllSpellAbilities()) {
|
||||
if (ability.isActivatedAbility()) {
|
||||
@@ -352,7 +349,6 @@ public class AttachAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
final Card c = ComputerUtilCard.getBestAI(list);
|
||||
@@ -385,9 +381,7 @@ public class AttachAi extends SpellAbilityAi {
|
||||
*/
|
||||
private static Card attachAIKeepTappedPreference(final SpellAbility sa, final List<Card> list, final boolean mandatory, final Card attachSource) {
|
||||
// AI For Cards like Paralyzing Grasp and Glimmerdust Nap
|
||||
final List<Card> prefList = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
final List<Card> prefList = CardLists.filter(list, c -> {
|
||||
// Don't do Untapped Vigilance cards
|
||||
if (c.isCreature() && c.hasKeyword(Keyword.VIGILANCE) && c.isUntapped()) {
|
||||
return false;
|
||||
@@ -421,7 +415,6 @@ public class AttachAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
final Card c = ComputerUtilCard.getBestAI(prefList);
|
||||
@@ -506,24 +499,14 @@ public class AttachAi extends SpellAbilityAi {
|
||||
if (list.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Card c = null;
|
||||
Card card = null;
|
||||
// AI For choosing a Card to Animate.
|
||||
List<Card> betterList = CardLists.getNotType(list, "Creature");
|
||||
if (ComputerUtilAbility.getAbilitySourceName(sa).equals("Animate Artifact")) {
|
||||
betterList = CardLists.filter(betterList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.getCMC() > 0;
|
||||
}
|
||||
});
|
||||
c = ComputerUtilCard.getMostExpensivePermanentAI(betterList);
|
||||
betterList = CardLists.filter(betterList, c -> c.getCMC() > 0);
|
||||
card = ComputerUtilCard.getMostExpensivePermanentAI(betterList);
|
||||
} else {
|
||||
List<Card> evenBetterList = CardLists.filter(betterList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.hasKeyword(Keyword.INDESTRUCTIBLE) || c.hasKeyword(Keyword.HEXPROOF);
|
||||
}
|
||||
});
|
||||
List<Card> evenBetterList = CardLists.filter(betterList, c -> c.hasKeyword(Keyword.INDESTRUCTIBLE) || c.hasKeyword(Keyword.HEXPROOF));
|
||||
if (!evenBetterList.isEmpty()) {
|
||||
betterList = evenBetterList;
|
||||
}
|
||||
@@ -531,40 +514,32 @@ public class AttachAi extends SpellAbilityAi {
|
||||
if (!evenBetterList.isEmpty()) {
|
||||
betterList = evenBetterList;
|
||||
}
|
||||
evenBetterList = CardLists.filter(betterList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.getTurnInZone() != c.getGame().getPhaseHandler().getTurn();
|
||||
}
|
||||
});
|
||||
evenBetterList = CardLists.filter(betterList, c -> c.getTurnInZone() != c.getGame().getPhaseHandler().getTurn());
|
||||
if (!evenBetterList.isEmpty()) {
|
||||
betterList = evenBetterList;
|
||||
}
|
||||
evenBetterList = CardLists.filter(betterList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
for (final SpellAbility sa : c.getSpellAbilities()) {
|
||||
if (sa.isAbility() && sa.getPayCosts().hasTapCost()) {
|
||||
evenBetterList = CardLists.filter(betterList, c -> {
|
||||
for (final SpellAbility sa1 : c.getSpellAbilities()) {
|
||||
if (sa1.isAbility() && sa1.getPayCosts().hasTapCost()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (!evenBetterList.isEmpty()) {
|
||||
betterList = evenBetterList;
|
||||
}
|
||||
c = ComputerUtilCard.getWorstAI(betterList);
|
||||
card = ComputerUtilCard.getWorstAI(betterList);
|
||||
}
|
||||
|
||||
|
||||
// If Mandatory (brought directly into play without casting) gotta
|
||||
// choose something
|
||||
if (c == null && mandatory) {
|
||||
if (card == null && mandatory) {
|
||||
return chooseLessPreferred(mandatory, list);
|
||||
}
|
||||
|
||||
return c;
|
||||
return card;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -591,9 +566,7 @@ public class AttachAi extends SpellAbilityAi {
|
||||
|
||||
//TODO for Reanimate Auras i need the new Attach Spell, in later versions it might be part of the Enchant Keyword
|
||||
attachSourceLki.addSpellAbility(AbilityFactory.getAbility(attachSourceLki, "NewAttach"));
|
||||
List<Card> betterList = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
List<Card> betterList = CardLists.filter(list, c -> {
|
||||
final Card lki = CardCopyService.getLKICopy(c);
|
||||
// need to fake it as if lki would be on the battlefield
|
||||
lki.setLastKnownZone(ai.getZone(ZoneType.Battlefield));
|
||||
@@ -613,7 +586,6 @@ public class AttachAi extends SpellAbilityAi {
|
||||
c.getGame().getAction().checkStaticAbilities(false);
|
||||
|
||||
return result;
|
||||
}
|
||||
});
|
||||
|
||||
final Card c = ComputerUtilCard.getBestCreatureAI(betterList);
|
||||
@@ -864,42 +836,29 @@ public class AttachAi extends SpellAbilityAi {
|
||||
if (totToughness < 0) {
|
||||
// Kill a creature if we can
|
||||
final int tgh = totToughness;
|
||||
prefList = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
prefList = CardLists.filter(list, c -> {
|
||||
if (!c.hasKeyword(Keyword.INDESTRUCTIBLE) && (c.getLethalDamage() <= Math.abs(tgh))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return c.getNetToughness() <= Math.abs(tgh);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Card c = null;
|
||||
Card card = null;
|
||||
if (prefList == null || prefList.isEmpty()) {
|
||||
prefList = new ArrayList<>(list);
|
||||
} else {
|
||||
c = ComputerUtilCard.getBestAI(prefList);
|
||||
if (c != null) {
|
||||
return c;
|
||||
card = ComputerUtilCard.getBestAI(prefList);
|
||||
if (card != null) {
|
||||
return card;
|
||||
}
|
||||
}
|
||||
|
||||
if (!keywords.isEmpty()) {
|
||||
prefList = CardLists.filter(prefList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return containsUsefulCurseKeyword(keywords, c, sa);
|
||||
}
|
||||
});
|
||||
prefList = CardLists.filter(prefList, c -> containsUsefulCurseKeyword(keywords, c, sa));
|
||||
} else if (totPower < 0) {
|
||||
prefList = CardLists.filter(prefList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.getNetPower() > 0 && ComputerUtilCombat.canAttackNextTurn(c);
|
||||
}
|
||||
});
|
||||
prefList = CardLists.filter(prefList, c -> c.getNetPower() > 0 && ComputerUtilCombat.canAttackNextTurn(c));
|
||||
}
|
||||
|
||||
//some auras aren't useful in multiples
|
||||
@@ -915,25 +874,22 @@ public class AttachAi extends SpellAbilityAi {
|
||||
&& sa.getPayCosts() != null && sa.getPayCosts().hasSpecificCostType(CostSacrifice.class)) {
|
||||
final int oldEvalRating = ComputerUtilCard.evaluateCreature(sa.getHostCard().getAttachedTo());
|
||||
final int threshold = ai.isAI() ? ((PlayerControllerAi)ai.getController()).getAi().getIntProperty(AiProps.SAC_TO_REATTACH_TARGET_EVAL_THRESHOLD) : Integer.MAX_VALUE;
|
||||
prefList = CardLists.filter(prefList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
if (!card.isCreature()) {
|
||||
prefList = CardLists.filter(prefList, c -> {
|
||||
if (!c.isCreature()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ComputerUtilCard.evaluateCreature(card) >= oldEvalRating + threshold;
|
||||
}
|
||||
return ComputerUtilCard.evaluateCreature(c) >= oldEvalRating + threshold;
|
||||
});
|
||||
}
|
||||
|
||||
c = ComputerUtilCard.getBestAI(prefList);
|
||||
card = ComputerUtilCard.getBestAI(prefList);
|
||||
|
||||
if (c == null) {
|
||||
if (card == null) {
|
||||
return chooseLessPreferred(mandatory, list);
|
||||
}
|
||||
|
||||
return acceptableChoice(c, mandatory);
|
||||
return acceptableChoice(card, mandatory);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1029,41 +985,30 @@ public class AttachAi extends SpellAbilityAi {
|
||||
*/
|
||||
private static Card attachAIPumpPreference(final Player ai, final SpellAbility sa, final List<Card> list, final boolean mandatory, final Card attachSource) {
|
||||
// AI For choosing a Card to Pump
|
||||
Card c = null;
|
||||
Card card = null;
|
||||
List<Card> magnetList = null;
|
||||
String stCheck = null;
|
||||
if (attachSource.isAura() || sa.isBestow()) {
|
||||
stCheck = "EnchantedBy";
|
||||
magnetList = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
magnetList = CardLists.filter(list, c -> {
|
||||
if (!c.isCreature()) {
|
||||
return false;
|
||||
}
|
||||
String sVar = c.getSVar("EnchantMe");
|
||||
return sVar.equals("Multiple") || (sVar.equals("Once") && !c.isEnchanted());
|
||||
}
|
||||
});
|
||||
} else if (attachSource.isEquipment()) {
|
||||
stCheck = "EquippedBy";
|
||||
magnetList = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
magnetList = CardLists.filter(list, c -> {
|
||||
if (!c.isCreature()) {
|
||||
return false;
|
||||
}
|
||||
String sVar = c.getSVar("EquipMe");
|
||||
return sVar.equals("Multiple") || (sVar.equals("Once") && !c.isEquipped());
|
||||
}
|
||||
});
|
||||
} else if (attachSource.isFortification()) {
|
||||
stCheck = "FortifiedBy";
|
||||
magnetList = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.isCreature() && !c.isFortified();
|
||||
}
|
||||
});
|
||||
magnetList = CardLists.filter(list, c -> c.isCreature() && !c.isFortified());
|
||||
}
|
||||
|
||||
// Look for triggers that will damage the creature and remove AI-owned creatures that will die
|
||||
@@ -1109,23 +1054,13 @@ public class AttachAi extends SpellAbilityAi {
|
||||
// Probably want to "weight" the list by amount of Enchantments and
|
||||
// choose the "lightest"
|
||||
|
||||
List<Card> betterList = CardLists.filter(magnetList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return CombatUtil.canAttack(c, ai.getWeakestOpponent());
|
||||
}
|
||||
});
|
||||
List<Card> betterList = CardLists.filter(magnetList, c -> CombatUtil.canAttack(c, ai.getWeakestOpponent()));
|
||||
if (!betterList.isEmpty()) {
|
||||
return ComputerUtilCard.getBestAI(betterList);
|
||||
}
|
||||
|
||||
// Magnet List should not be attached when they are useless
|
||||
betterList = CardLists.filter(magnetList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return !ComputerUtilCard.isUselessCreature(ai, c);
|
||||
}
|
||||
});
|
||||
betterList = CardLists.filter(magnetList, c -> !ComputerUtilCard.isUselessCreature(ai, c));
|
||||
|
||||
if (!betterList.isEmpty()) {
|
||||
return ComputerUtilCard.getBestAI(betterList);
|
||||
@@ -1179,21 +1114,14 @@ public class AttachAi extends SpellAbilityAi {
|
||||
if (totToughness < 0) {
|
||||
// Don't kill my own stuff with Negative toughness Auras
|
||||
final int tgh = totToughness;
|
||||
prefList = CardLists.filter(prefList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.getLethalDamage() > Math.abs(tgh);
|
||||
}
|
||||
});
|
||||
prefList = CardLists.filter(prefList, c -> c.getLethalDamage() > Math.abs(tgh));
|
||||
}
|
||||
|
||||
//only add useful keywords unless P/T bonus is significant
|
||||
if (totToughness + totPower < 4 && (!keywords.isEmpty() || grantingExtraBlock)) {
|
||||
final int pow = totPower;
|
||||
final boolean extraBlock = grantingExtraBlock;
|
||||
prefList = CardLists.filter(prefList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
prefList = CardLists.filter(prefList, c -> {
|
||||
if (!keywords.isEmpty()) {
|
||||
for (final String keyword : keywords) {
|
||||
if (isUsefulAttachKeyword(keyword, c, sa, pow)) {
|
||||
@@ -1210,7 +1138,6 @@ public class AttachAi extends SpellAbilityAi {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1229,21 +1156,11 @@ public class AttachAi extends SpellAbilityAi {
|
||||
if (!attachSource.getName().equals("Daybreak Coronet")) {
|
||||
// TODO For Auras like Rancor, that aren't as likely to lead to
|
||||
// card disadvantage, this check should be skipped
|
||||
prefList = CardLists.filter(prefList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return !c.isEnchanted() || c.hasKeyword(Keyword.HEXPROOF);
|
||||
}
|
||||
});
|
||||
prefList = CardLists.filter(prefList, c -> !c.isEnchanted() || c.hasKeyword(Keyword.HEXPROOF));
|
||||
}
|
||||
|
||||
// should not attach Auras to creatures that does leave the play
|
||||
prefList = CardLists.filter(prefList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return !c.hasSVar("EndOfTurnLeavePlay");
|
||||
}
|
||||
});
|
||||
prefList = CardLists.filter(prefList, c -> !c.hasSVar("EndOfTurnLeavePlay"));
|
||||
}
|
||||
|
||||
// Should not attach things to crewed vehicles that will stop being creatures soon
|
||||
@@ -1258,12 +1175,7 @@ public class AttachAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
if (canOnlyTargetCreatures && (attachSource.isAura() || attachSource.isEquipment())) {
|
||||
prefList = CardLists.filter(prefList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return card.getTimesCrewedThisTurn() == 0 || (attachSource.isEquipment() && attachSource.getGame().getPhaseHandler().is(PhaseType.MAIN1, ai));
|
||||
}
|
||||
});
|
||||
prefList = CardLists.filter(prefList, c -> c.getTimesCrewedThisTurn() == 0 || (attachSource.isEquipment() && attachSource.getGame().getPhaseHandler().is(PhaseType.MAIN1, ai)));
|
||||
}
|
||||
|
||||
if (!grantingAbilities) {
|
||||
@@ -1271,17 +1183,14 @@ public class AttachAi extends SpellAbilityAi {
|
||||
// Filter out creatures that can't Attack or have Defender
|
||||
if (keywords.isEmpty()) {
|
||||
final int powerBonus = totPower;
|
||||
prefList = CardLists.filter(prefList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
prefList = CardLists.filter(prefList, c -> {
|
||||
if (!c.isCreature()) {
|
||||
return true;
|
||||
}
|
||||
return powerBonus + c.getNetPower() > 0 && ComputerUtilCombat.canAttackNextTurn(c);
|
||||
}
|
||||
});
|
||||
}
|
||||
c = ComputerUtilCard.getBestAI(prefList);
|
||||
card = ComputerUtilCard.getBestAI(prefList);
|
||||
} else {
|
||||
for (Card pref : prefList) {
|
||||
if (pref.isLand() && pref.isUntapped()) {
|
||||
@@ -1290,14 +1199,14 @@ public class AttachAi extends SpellAbilityAi {
|
||||
}
|
||||
// If we grant abilities, we may want to put it on something Weak?
|
||||
// Possibly more defensive?
|
||||
c = ComputerUtilCard.getWorstPermanentAI(prefList, false, false, false, false);
|
||||
card = ComputerUtilCard.getWorstPermanentAI(prefList, false, false, false, false);
|
||||
}
|
||||
|
||||
if (c == null) {
|
||||
if (card == null) {
|
||||
return chooseLessPreferred(mandatory, list);
|
||||
}
|
||||
|
||||
return c;
|
||||
return card;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1338,22 +1247,13 @@ public class AttachAi extends SpellAbilityAi {
|
||||
|
||||
// Is a SA that moves target attachment
|
||||
if ("MoveTgtAura".equals(sa.getParam("AILogic"))) {
|
||||
CardCollection list = CardLists.filter(CardUtil.getValidCardsToTarget(sa), Predicates.or(CardPredicates.isControlledByAnyOf(aiPlayer.getOpponents()), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card card) {
|
||||
return ComputerUtilCard.isUselessCreature(aiPlayer, card.getAttachedTo());
|
||||
}
|
||||
}));
|
||||
CardCollection list = CardLists.filter(CardUtil.getValidCardsToTarget(sa), Predicates.or(CardPredicates.isControlledByAnyOf(aiPlayer.getOpponents()),
|
||||
card -> ComputerUtilCard.isUselessCreature(aiPlayer, card.getAttachedTo())));
|
||||
|
||||
return !list.isEmpty() ? ComputerUtilCard.getBestAI(list) : null;
|
||||
} else if ("Unenchanted".equals(sa.getParam("AILogic"))) {
|
||||
List<Card> list = CardUtil.getValidCardsToTarget(sa);
|
||||
CardCollection preferred = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card card) {
|
||||
return !card.hasCardAttachments();
|
||||
}
|
||||
});
|
||||
CardCollection preferred = CardLists.filter(list, card -> !card.hasCardAttachments());
|
||||
return preferred.isEmpty() ? Aggregates.random(list) : Aggregates.random(preferred);
|
||||
}
|
||||
|
||||
@@ -1687,25 +1587,19 @@ public class AttachAi extends SpellAbilityAi {
|
||||
public static Card doPumpOrCurseAILogic(final Player ai, final SpellAbility sa, final List<Card> list, final String type) {
|
||||
Card chosen = null;
|
||||
|
||||
List<Card> aiType = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
List<Card> aiType = CardLists.filter(list, c -> {
|
||||
// Don't buff opponent's creatures of given type
|
||||
if (!c.getController().equals(ai)) {
|
||||
return false;
|
||||
}
|
||||
return c.isValid(type, ai, sa.getHostCard(), sa);
|
||||
}
|
||||
});
|
||||
List<Card> oppNonType = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
List<Card> oppNonType = CardLists.filter(list, c -> {
|
||||
// Don't debuff AI's own creatures not of given type
|
||||
if (c.getController().equals(ai)) {
|
||||
return false;
|
||||
}
|
||||
return !c.isValid(type, ai, sa.getHostCard(), sa) && !ComputerUtilCard.isUselessCreature(ai, c);
|
||||
}
|
||||
});
|
||||
|
||||
if (!aiType.isEmpty() && !oppNonType.isEmpty()) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import forge.ai.ComputerUtilCard;
|
||||
import forge.ai.SpecialAiLogic;
|
||||
import forge.ai.SpecialCardAi;
|
||||
@@ -35,12 +34,9 @@ public class BranchAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
final CardCollection attackers = combat.getAttackers();
|
||||
final CardCollection attackingBattle = CardLists.filter(attackers, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
final CardCollection attackingBattle = CardLists.filter(attackers, card -> {
|
||||
final GameEntity def = combat.getDefenderByAttacker(combat.getBandOfAttacker(card));
|
||||
return def instanceof Card && ((Card)def).isBattle();
|
||||
}
|
||||
});
|
||||
|
||||
if (!attackingBattle.isEmpty()) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -378,14 +377,11 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
if (type != null && p == ai) {
|
||||
// AI only "knows" about his information
|
||||
list = CardLists.getValidCards(list, type, source.getController(), source, sa);
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
list = CardLists.filter(list, c -> {
|
||||
if (c.getType().isLegendary()) {
|
||||
return !ai.isCardInPlay(c.getName());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
// TODO: prevent ai searching its own library when Ob Nixilis, Unshackled is in play
|
||||
@@ -906,12 +902,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
// Filter AI-specific targets if provided
|
||||
list = ComputerUtil.filterAITgts(sa, ai, list, true);
|
||||
if (sa.hasParam("AITgtsOnlyBetterThanSelf")) {
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return ComputerUtilCard.evaluateCreature(card) > ComputerUtilCard.evaluateCreature(source) + 30;
|
||||
}
|
||||
});
|
||||
list = CardLists.filter(list, card -> ComputerUtilCard.evaluateCreature(card) > ComputerUtilCard.evaluateCreature(source) + 30);
|
||||
}
|
||||
|
||||
if (source.isInZone(ZoneType.Hand)) {
|
||||
@@ -921,29 +912,23 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
list.remove(source); // spells can't target their own source, because it's actually in the stack zone
|
||||
}
|
||||
if (sa.hasParam("AttachedTo")) {
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
list = CardLists.filter(list, c -> {
|
||||
for (Card card : game.getCardsIn(ZoneType.Battlefield)) {
|
||||
if (card.isValid(sa.getParam("AttachedTo"), ai, c, sa)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (sa.hasParam("AttachAfter")) {
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
list = CardLists.filter(list, c -> {
|
||||
for (Card card : game.getCardsIn(ZoneType.Battlefield)) {
|
||||
if (card.isValid(sa.getParam("AttachAfter"), ai, c, sa)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1039,12 +1024,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
// blink logic: get my own permanents back or blink permanents with ETB effects
|
||||
if (blink) {
|
||||
CardCollection blinkTargets = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return !c.isToken() && c.getOwner().equals(ai) && (c.getController().isOpponentOf(ai) || c.hasETBTrigger(false));
|
||||
}
|
||||
});
|
||||
CardCollection blinkTargets = CardLists.filter(list, c -> !c.isToken() && c.getOwner().equals(ai) && (c.getController().isOpponentOf(ai) || c.hasETBTrigger(false)));
|
||||
if (!blinkTargets.isEmpty()) {
|
||||
CardCollection opponentBlinkTargets = CardLists.filterControlledBy(blinkTargets, ai.getOpponents());
|
||||
// prefer post-combat unless targeting opponent's stuff or part of another ability
|
||||
@@ -1070,9 +1050,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
list = CardLists.filterControlledBy(list, ai.getOpponents());
|
||||
if (!CardLists.getNotType(list, "Land").isEmpty()) {
|
||||
// When bouncing opponents stuff other than lands, don't bounce cards with CMC 0
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
list = CardLists.filter(list, c -> {
|
||||
for (Card aura : c.getEnchantedBy()) {
|
||||
return aura.getController().isOpponentOf(ai);
|
||||
}
|
||||
@@ -1080,7 +1058,6 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
return c.isToken();
|
||||
}
|
||||
return c.isToken() || c.getCMC() > 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1102,16 +1079,13 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
// only retrieve cards from computer graveyard
|
||||
list = CardLists.filterControlledBy(list, ai);
|
||||
} else if (sa.hasParam("AttachedTo")) {
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
list = CardLists.filter(list, c -> {
|
||||
for (SpellAbility attach : c.getSpellAbilities()) {
|
||||
if ("Pump".equals(attach.getParam("AILogic"))) {
|
||||
return true; //only use good auras
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1135,16 +1109,13 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
|
||||
if (!sa.hasParam("AITgtOwnCards")) {
|
||||
list = CardLists.filterControlledBy(list, ai.getOpponents());
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
list = CardLists.filter(list, c -> {
|
||||
for (Card aura : c.getEnchantedBy()) {
|
||||
if (c.getOwner().isOpponentOf(ai) && aura.getController().equals(ai)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1613,22 +1584,14 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
// Save a card as a default, in case we can't find anything suitable.
|
||||
Card first = fetchList.get(0);
|
||||
if (ZoneType.Battlefield.equals(destination)) {
|
||||
fetchList = CardLists.filter(fetchList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
if (c.getType().isLegendary()) {
|
||||
return !decider.isCardInPlay(c.getName());
|
||||
fetchList = CardLists.filter(fetchList, c1 -> {
|
||||
if (c1.getType().isLegendary()) {
|
||||
return !decider.isCardInPlay(c1.getName());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (player.isOpponentOf(decider) && sa.hasParam("GainControl") && activator.equals(decider)) {
|
||||
fetchList = CardLists.filter(fetchList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return !ComputerUtilCard.isCardRemAIDeck(c) && !ComputerUtilCard.isCardRemRandomDeck(c);
|
||||
}
|
||||
});
|
||||
fetchList = CardLists.filter(fetchList, c12 -> !ComputerUtilCard.isCardRemAIDeck(c12) && !ComputerUtilCard.isCardRemRandomDeck(c12));
|
||||
}
|
||||
}
|
||||
if (ZoneType.Exile.equals(destination) || origin.contains(ZoneType.Battlefield)
|
||||
@@ -1715,9 +1678,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
private static CardCollection prefilterOwnListForBounceAnyNum(CardCollection fetchList, Player decider) {
|
||||
fetchList = CardLists.filter(fetchList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card card) {
|
||||
fetchList = CardLists.filter(fetchList, card -> {
|
||||
if (card.isToken()) {
|
||||
return false;
|
||||
}
|
||||
@@ -1761,7 +1722,6 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return fetchList;
|
||||
@@ -1866,14 +1826,11 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
listGoal = CardLists.getValidCards(listGoal, curGoal + (curGoal.contains(".") ? "+" : ".") + "cmcGE" + goalCMC, source.getController(), source, sa);
|
||||
}
|
||||
|
||||
listGoal = CardLists.filter(listGoal, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
listGoal = CardLists.filter(listGoal, c -> {
|
||||
if (c.getType().isLegendary()) {
|
||||
return !ai.isCardInPlay(c.getName());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!listGoal.isEmpty()) {
|
||||
@@ -2014,9 +1971,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
exiledBy.add(exiled);
|
||||
}
|
||||
}
|
||||
scanList = CardLists.filter(scanList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
scanList = CardLists.filter(scanList, card -> {
|
||||
if (exiledBy.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
@@ -2024,7 +1979,6 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
return !c.getType().sharesCardTypeWith(card.getType());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2061,12 +2015,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
final CardType.CoreType determinedMaxType = maxType;
|
||||
CardCollection preferredList = CardLists.filter(fetchList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return card.getType().hasType(determinedMaxType);
|
||||
}
|
||||
});
|
||||
CardCollection preferredList = CardLists.filter(fetchList, card -> card.getType().hasType(determinedMaxType));
|
||||
CardCollection preferredOppList = CardLists.filter(preferredList, CardPredicates.isControlledByAnyOf(aiPlayer.getOpponents()));
|
||||
|
||||
if (!preferredOppList.isEmpty()) {
|
||||
@@ -2078,9 +2027,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
return Aggregates.random(fetchList);
|
||||
}
|
||||
|
||||
CardCollection preferredList = CardLists.filter(fetchList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
CardCollection preferredList = CardLists.filter(fetchList, card -> {
|
||||
boolean playerPref = true;
|
||||
if (isCurse) {
|
||||
playerPref = card.getController().isOpponentOf(aiPlayer);
|
||||
@@ -2093,7 +2040,6 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
return card.isValid(valid, aiPlayer, host, sa); // for things like ExilePreference:Land.Basic
|
||||
}
|
||||
});
|
||||
|
||||
if (!preferredList.isEmpty()) {
|
||||
|
||||
@@ -4,7 +4,6 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
@@ -85,15 +84,12 @@ public class ChooseCardAi extends SpellAbilityAi {
|
||||
return false;
|
||||
}
|
||||
final Combat combat = game.getCombat();
|
||||
choices = CardLists.filter(choices, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
choices = CardLists.filter(choices, c -> {
|
||||
if (!combat.isAttacking(c, ai) || !combat.isUnblocked(c)) {
|
||||
return false;
|
||||
}
|
||||
int ref = ComputerUtilAbility.getAbilitySourceName(sa).equals("Forcefield") ? 1 : 0;
|
||||
return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > ref;
|
||||
}
|
||||
});
|
||||
return !choices.isEmpty();
|
||||
} else if (aiLogic.equals("Ashiok")) {
|
||||
@@ -201,15 +197,12 @@ public class ChooseCardAi extends SpellAbilityAi {
|
||||
} else if (logic.equals("NeedsPrevention")) {
|
||||
final Game game = ai.getGame();
|
||||
final Combat combat = game.getCombat();
|
||||
CardCollectionView better = CardLists.filter(options, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
CardCollectionView better = CardLists.filter(options, c -> {
|
||||
if (combat == null || !combat.isAttacking(c, ai) || !combat.isUnblocked(c)) {
|
||||
return false;
|
||||
}
|
||||
int ref = ComputerUtilAbility.getAbilitySourceName(sa).equals("Forcefield") ? 1 : 0;
|
||||
return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > ref;
|
||||
}
|
||||
});
|
||||
if (!better.isEmpty()) {
|
||||
choice = ComputerUtilCard.getBestAI(better);
|
||||
@@ -235,26 +228,23 @@ public class ChooseCardAi extends SpellAbilityAi {
|
||||
choice = creats.get(0);
|
||||
}
|
||||
} else if ("NegativePowerFirst".equals(logic)) {
|
||||
Card lowest = Aggregates.itemWithMin(options, CardPredicates.Accessors.fnGetNetPower);
|
||||
Card lowest = Aggregates.itemWithMin(options, Card::getNetPower);
|
||||
if (lowest.getNetPower() <= 0) {
|
||||
choice = lowest;
|
||||
} else {
|
||||
choice = ComputerUtilCard.getBestCreatureAI(options);
|
||||
}
|
||||
} else if ("TangleWire".equals(logic)) {
|
||||
CardCollectionView betterList = CardLists.filter(options, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
CardCollectionView betterList = CardLists.filter(options, c -> {
|
||||
if (c.isCreature()) {
|
||||
return false;
|
||||
}
|
||||
for (SpellAbility sa : c.getAllSpellAbilities()) {
|
||||
if (sa.getPayCosts().hasTapCost()) {
|
||||
for (SpellAbility sa1 : c.getAllSpellAbilities()) {
|
||||
if (sa1.getPayCosts().hasTapCost()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (!betterList.isEmpty()) {
|
||||
choice = betterList.get(0);
|
||||
|
||||
@@ -3,9 +3,9 @@ package forge.ai.ability;
|
||||
import forge.ai.SpellAbilityAi;
|
||||
import forge.game.Direction;
|
||||
import forge.game.Game;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.card.CardPredicates;
|
||||
import forge.game.card.CardPredicates.Presets;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
@@ -28,11 +28,11 @@ public class ChooseDirectionAi extends SpellAbilityAi {
|
||||
CardCollection all = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.NONLAND_PERMANENTS);
|
||||
CardCollection aiPermanent = CardLists.filterControlledBy(all, ai);
|
||||
aiPermanent.remove(sa.getHostCard());
|
||||
int aiValue = Aggregates.sum(aiPermanent, CardPredicates.Accessors.fnGetCmc);
|
||||
int aiValue = Aggregates.sum(aiPermanent, Card::getCMC);
|
||||
CardCollection left = CardLists.filterControlledBy(all, game.getNextPlayerAfter(ai, Direction.Left));
|
||||
CardCollection right = CardLists.filterControlledBy(all, game.getNextPlayerAfter(ai, Direction.Right));
|
||||
int leftValue = Aggregates.sum(left, CardPredicates.Accessors.fnGetCmc);
|
||||
int rightValue = Aggregates.sum(right, CardPredicates.Accessors.fnGetCmc);
|
||||
int leftValue = Aggregates.sum(left, Card::getCMC);
|
||||
int rightValue = Aggregates.sum(right, Card::getCMC);
|
||||
return aiValue <= leftValue && aiValue <= rightValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import forge.ai.*;
|
||||
@@ -85,12 +84,7 @@ public class ChooseGenericAi extends SpellAbilityAi {
|
||||
} else if ("Random".equals(logic)) {
|
||||
return Aggregates.random(spells);
|
||||
} else if ("Phasing".equals(logic)) { // Teferi's Realm : keep aggressive
|
||||
List<SpellAbility> filtered = Lists.newArrayList(Iterables.filter(spells, new Predicate<SpellAbility>() {
|
||||
@Override
|
||||
public boolean apply(final SpellAbility sp) {
|
||||
return !sp.getDescription().contains("Creature") && !sp.getDescription().contains("Land");
|
||||
}
|
||||
}));
|
||||
List<SpellAbility> filtered = Lists.newArrayList(Iterables.filter(spells, sp -> !sp.getDescription().contains("Creature") && !sp.getDescription().contains("Land")));
|
||||
return Aggregates.random(filtered);
|
||||
} else if ("PayUnlessCost".equals(logic)) {
|
||||
for (final SpellAbility sp : spells) {
|
||||
|
||||
@@ -3,7 +3,6 @@ package forge.ai.ability;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
@@ -94,14 +93,11 @@ public class ChooseSourceAi extends SpellAbilityAi {
|
||||
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), host.getController(), host, sa);
|
||||
}
|
||||
final Combat combat = game.getCombat();
|
||||
choices = CardLists.filter(choices, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
choices = CardLists.filter(choices, c -> {
|
||||
if (combat == null || !combat.isAttacking(c, ai) || !combat.isUnblocked(c)) {
|
||||
return false;
|
||||
}
|
||||
return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > 0;
|
||||
}
|
||||
});
|
||||
return !choices.isEmpty();
|
||||
}
|
||||
@@ -124,15 +120,12 @@ public class ChooseSourceAi extends SpellAbilityAi {
|
||||
|
||||
final Combat combat = game.getCombat();
|
||||
|
||||
List<Card> permanentSources = CardLists.filter(options, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
List<Card> permanentSources = CardLists.filter(options, c -> {
|
||||
if (c == null || c.getZone() == null || c.getZone().getZoneType() != ZoneType.Battlefield
|
||||
|| combat == null || !combat.isAttacking(c, ai) || !combat.isUnblocked(c)) {
|
||||
return false;
|
||||
}
|
||||
return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > 0;
|
||||
}
|
||||
});
|
||||
|
||||
// Try to choose the best creature for damage prevention.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.ai.ComputerUtilCard;
|
||||
@@ -32,12 +31,7 @@ public class ControlExchangeAi extends SpellAbilityAi {
|
||||
CardCollection list =
|
||||
CardLists.getValidCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), tgt.getValidTgts(), ai, sa.getHostCard(), sa);
|
||||
// AI won't try to grab cards that are filtered out of AI decks on purpose
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return !ComputerUtilCard.isCardRemAIDeck(c) && c.canBeTargetedBy(sa);
|
||||
}
|
||||
});
|
||||
list = CardLists.filter(list, c -> !ComputerUtilCard.isCardRemAIDeck(c) && c.canBeTargetedBy(sa));
|
||||
object1 = ComputerUtilCard.getBestAI(list);
|
||||
if (sa.hasParam("Defined")) {
|
||||
object2 = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa).get(0);
|
||||
|
||||
@@ -20,7 +20,6 @@ package forge.ai.ability;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
@@ -132,9 +131,7 @@ public class ControlGainAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
// AI won't try to grab cards that are filtered out of AI decks on purpose
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
list = CardLists.filter(list, c -> {
|
||||
if (!sa.canTarget(c)) {
|
||||
return false;
|
||||
}
|
||||
@@ -171,7 +168,6 @@ public class ControlGainAi extends SpellAbilityAi {
|
||||
|
||||
// do not take control on something it doesn't know how to use
|
||||
return !ComputerUtilCard.isCardRemAIDeck(c);
|
||||
}
|
||||
});
|
||||
|
||||
if (list.isEmpty()) {
|
||||
|
||||
@@ -20,7 +20,6 @@ package forge.ai.ability;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
@@ -49,12 +48,7 @@ public class ControlGainVariantAi extends SpellAbilityAi {
|
||||
String logic = sa.getParam("AILogic");
|
||||
|
||||
if ("GainControlOwns".equals(logic)) {
|
||||
List<Card> list = CardLists.filter(ai.getGame().getCardsIn(ZoneType.Battlefield), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card crd) {
|
||||
return crd.isCreature() && !crd.getController().equals(crd.getOwner());
|
||||
}
|
||||
});
|
||||
List<Card> list = CardLists.filter(ai.getGame().getCardsIn(ZoneType.Battlefield), crd -> crd.isCreature() && !crd.getController().equals(crd.getOwner()));
|
||||
if (list.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
@@ -176,12 +175,7 @@ public class CopyPermanentAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return (!c.getType().isLegendary() || canCopyLegendary) || !c.getController().equals(aiPlayer);
|
||||
}
|
||||
});
|
||||
list = CardLists.filter(list, c -> (!c.getType().isLegendary() || canCopyLegendary) || !c.getController().equals(aiPlayer));
|
||||
Card choice;
|
||||
if (Iterables.any(list, Presets.CREATURES)) {
|
||||
if (sa.hasParam("TargetingPlayer")) {
|
||||
|
||||
@@ -19,7 +19,6 @@ package forge.ai.ability;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import forge.ai.ComputerUtilCard;
|
||||
@@ -109,12 +108,7 @@ public abstract class CountersAi extends SpellAbilityAi {
|
||||
choice = ComputerUtilCard.getBestLandToAnimate(list);
|
||||
}
|
||||
} else if (type.equals("DIVINITY")) {
|
||||
final CardCollection boon = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.getCounters(CounterEnumType.DIVINITY) == 0;
|
||||
}
|
||||
});
|
||||
final CardCollection boon = CardLists.filter(list, c -> c.getCounters(CounterEnumType.DIVINITY) == 0);
|
||||
choice = ComputerUtilCard.getMostExpensivePermanentAI(boon);
|
||||
} else if (CounterType.get(type).isKeywordCounter()) {
|
||||
choice = ComputerUtilCard.getBestCreatureAI(CardLists.getNotKeyword(list, type));
|
||||
|
||||
@@ -3,7 +3,6 @@ package forge.ai.ability;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import forge.ai.ComputerUtil;
|
||||
@@ -261,10 +260,7 @@ public class CountersMoveAi extends SpellAbilityAi {
|
||||
// prefered logic for this: try to steal counter
|
||||
List<Card> oppList = CardLists.filterControlledBy(tgtCards, ai.getOpponents());
|
||||
if (!oppList.isEmpty()) {
|
||||
List<Card> best = CardLists.filter(oppList, new Predicate<Card>() {
|
||||
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
List<Card> best = CardLists.filter(oppList, card -> {
|
||||
// do not weak a useless creature if able
|
||||
if (ComputerUtilCard.isUselessCreature(ai, card)) {
|
||||
return false;
|
||||
@@ -279,8 +275,6 @@ public class CountersMoveAi extends SpellAbilityAi {
|
||||
return srcCardCpy.getCounters(cType) > 0 || !card.hasKeyword(Keyword.UNDYING) || card.isToken();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// if no Prefered found, try normal list
|
||||
@@ -303,10 +297,7 @@ public class CountersMoveAi extends SpellAbilityAi {
|
||||
|
||||
List<Card> aiList = CardLists.filterControlledBy(tgtCards, ally);
|
||||
if (!aiList.isEmpty()) {
|
||||
List<Card> best = CardLists.filter(aiList, new Predicate<Card>() {
|
||||
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
List<Card> best = CardLists.filter(aiList, card -> {
|
||||
// gain from useless
|
||||
if (ComputerUtilCard.isUselessCreature(ai, card)) {
|
||||
return true;
|
||||
@@ -329,7 +320,6 @@ public class CountersMoveAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (best.isEmpty()) {
|
||||
@@ -379,10 +369,7 @@ public class CountersMoveAi extends SpellAbilityAi {
|
||||
if (ComputerUtilCard.evaluateCreature(lkiWithCounters) > ComputerUtilCard.evaluateCreature(lkiWithoutCounters)) {
|
||||
List<Card> aiList = CardLists.filterControlledBy(tgtCards, ai);
|
||||
if (!aiList.isEmpty()) {
|
||||
List<Card> best = CardLists.filter(aiList, new Predicate<Card>() {
|
||||
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
List<Card> best = CardLists.filter(aiList, card -> {
|
||||
// gain from useless
|
||||
if (ComputerUtilCard.isUselessCreature(ai, card)) {
|
||||
return false;
|
||||
@@ -406,7 +393,6 @@ public class CountersMoveAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
if (best.isEmpty()) {
|
||||
@@ -432,10 +418,7 @@ public class CountersMoveAi extends SpellAbilityAi {
|
||||
// try to move to something useless or something that would leave play
|
||||
List<Card> oppList = CardLists.filterControlledBy(tgtCards, ai.getOpponents());
|
||||
if (!oppList.isEmpty()) {
|
||||
List<Card> best = CardLists.filter(oppList, new Predicate<Card>() {
|
||||
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
List<Card> best = CardLists.filter(oppList, card -> {
|
||||
// gain from useless
|
||||
if (!ComputerUtilCard.isUselessCreature(ai, card)) {
|
||||
return true;
|
||||
@@ -447,7 +430,6 @@ public class CountersMoveAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (best.isEmpty()) {
|
||||
|
||||
@@ -4,7 +4,6 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -37,10 +36,7 @@ public class CountersMultiplyAi extends SpellAbilityAi {
|
||||
// defined are mostly Self or Creatures you control
|
||||
CardCollection list = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa);
|
||||
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
|
||||
@Override
|
||||
public boolean apply(Card c) {
|
||||
list = CardLists.filter(list, c -> {
|
||||
if (!c.hasCounters()) {
|
||||
return false;
|
||||
}
|
||||
@@ -62,8 +58,6 @@ public class CountersMultiplyAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if (list.isEmpty()) {
|
||||
@@ -137,10 +131,7 @@ public class CountersMultiplyAi extends SpellAbilityAi {
|
||||
CardCollection list = CardLists.getTargetableCards(game.getCardsIn(ZoneType.Battlefield), sa);
|
||||
|
||||
// pre filter targetable cards with counters and can receive one of them
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
|
||||
@Override
|
||||
public boolean apply(Card c) {
|
||||
list = CardLists.filter(list, c -> {
|
||||
if (!c.hasCounters()) {
|
||||
return false;
|
||||
}
|
||||
@@ -155,8 +146,6 @@ public class CountersMultiplyAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
CardCollection aiList = CardLists.filterControlledBy(list, ai);
|
||||
|
||||
@@ -4,7 +4,6 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
@@ -31,9 +30,7 @@ public class CountersProliferateAi extends SpellAbilityAi {
|
||||
if (p.getCounters(CounterEnumType.EXPERIENCE) + p.getCounters(CounterEnumType.ENERGY) >= 1) {
|
||||
allyExpOrEnergy = true;
|
||||
}
|
||||
cperms.addAll(CardLists.filter(p.getCardsIn(ZoneType.Battlefield), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card crd) {
|
||||
cperms.addAll(CardLists.filter(p.getCardsIn(ZoneType.Battlefield), crd -> {
|
||||
if (!crd.hasCounters()) {
|
||||
return false;
|
||||
}
|
||||
@@ -49,7 +46,6 @@ public class CountersProliferateAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -58,9 +54,7 @@ public class CountersProliferateAi extends SpellAbilityAi {
|
||||
|
||||
for (final Player o : ai.getOpponents()) {
|
||||
opponentPoison |= o.getPoisonCounters() > 0 && o.canReceiveCounters(CounterEnumType.POISON);
|
||||
hperms.addAll(CardLists.filter(o.getCardsIn(ZoneType.Battlefield), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card crd) {
|
||||
hperms.addAll(CardLists.filter(o.getCardsIn(ZoneType.Battlefield), crd -> {
|
||||
if (!crd.hasCounters()) {
|
||||
return false;
|
||||
}
|
||||
@@ -76,7 +70,6 @@ public class CountersProliferateAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -171,13 +170,7 @@ public class CountersPutAi extends CountersAi {
|
||||
CardCollection oppCreatM1 = CardLists.filter(oppCreat, CardPredicates.hasCounter(CounterEnumType.M1M1));
|
||||
oppCreatM1 = CardLists.getNotKeyword(oppCreatM1, Keyword.UNDYING);
|
||||
|
||||
oppCreatM1 = CardLists.filter(oppCreatM1, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card input) {
|
||||
return input.getNetToughness() <= 1 && input.canReceiveCounters(CounterType.get(CounterEnumType.M1M1));
|
||||
}
|
||||
|
||||
});
|
||||
oppCreatM1 = CardLists.filter(oppCreatM1, input -> input.getNetToughness() <= 1 && input.canReceiveCounters(CounterType.get(CounterEnumType.M1M1)));
|
||||
|
||||
Card best = ComputerUtilCard.getBestAI(oppCreatM1);
|
||||
if (best != null) {
|
||||
@@ -188,9 +181,7 @@ public class CountersPutAi extends CountersAi {
|
||||
CardCollection aiCreat = CardLists.getTargetableCards(ai.getCreaturesInPlay(), sa);
|
||||
aiCreat = CardLists.filter(aiCreat, CardPredicates.hasCounters());
|
||||
|
||||
aiCreat = CardLists.filter(aiCreat, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card input) {
|
||||
aiCreat = CardLists.filter(aiCreat, input -> {
|
||||
for (CounterType counterType : input.getCounters().keySet()) {
|
||||
if (!ComputerUtil.isNegativeCounter(counterType, input)
|
||||
&& input.canReceiveCounters(counterType)) {
|
||||
@@ -198,7 +189,6 @@ public class CountersPutAi extends CountersAi {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// TODO check whole state which creature would be the best
|
||||
@@ -251,8 +241,8 @@ public class CountersPutAi extends CountersAi {
|
||||
} else if (ai.getGame().getCombat().isBlocking(source)) {
|
||||
// when blocking, consider this if it's possible to save the blocker and/or kill at least one attacker
|
||||
CardCollection blocked = ai.getGame().getCombat().getAttackersBlockedBy(source);
|
||||
int totBlkPower = Aggregates.sum(blocked, CardPredicates.Accessors.fnGetNetPower);
|
||||
int totBlkToughness = Aggregates.min(blocked, CardPredicates.Accessors.fnGetNetToughness);
|
||||
int totBlkPower = Aggregates.sum(blocked, Card::getNetPower);
|
||||
int totBlkToughness = Aggregates.min(blocked, Card::getNetToughness);
|
||||
|
||||
int numActivations = ai.getCounters(CounterEnumType.ENERGY) / sa.getPayCosts().getCostEnergy().convertAmount();
|
||||
if (source.getNetToughness() + numActivations > totBlkPower
|
||||
@@ -327,7 +317,7 @@ public class CountersPutAi extends CountersAi {
|
||||
|
||||
if (sa.hasParam("Bolster")) {
|
||||
CardCollection creatsYouCtrl = ai.getCreaturesInPlay();
|
||||
List<Card> leastToughness = Aggregates.listWithMin(creatsYouCtrl, CardPredicates.Accessors.fnGetNetToughness);
|
||||
List<Card> leastToughness = Aggregates.listWithMin(creatsYouCtrl, Card::getNetToughness);
|
||||
if (leastToughness.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
@@ -389,7 +379,7 @@ public class CountersPutAi extends CountersAi {
|
||||
sa.setXManaCostPaid(amount);
|
||||
} else if ("ExiledCreatureFromGraveCMC".equals(logic)) {
|
||||
// e.g. Necropolis
|
||||
amount = Aggregates.max(CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.CREATURES), CardPredicates.Accessors.fnGetCmc);
|
||||
amount = Aggregates.max(CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.CREATURES), Card::getCMC);
|
||||
if (amount > 0 && ai.getGame().getPhaseHandler().is(PhaseType.END_OF_TURN)) {
|
||||
return true;
|
||||
}
|
||||
@@ -473,9 +463,7 @@ public class CountersPutAi extends CountersAi {
|
||||
list = ComputerUtil.getSafeTargets(ai, sa, ai.getCardsIn(ZoneType.Battlefield));
|
||||
}
|
||||
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
list = CardLists.filter(list, c -> {
|
||||
// don't put the counter on the dead creature
|
||||
if (sacSelf && c.equals(source)) {
|
||||
return false;
|
||||
@@ -490,7 +478,6 @@ public class CountersPutAi extends CountersAi {
|
||||
}
|
||||
}
|
||||
return sa.canTarget(c) && c.canReceiveCounters(CounterType.getType(type));
|
||||
}
|
||||
});
|
||||
|
||||
// Filter AI-specific targets if provided
|
||||
@@ -928,13 +915,9 @@ public class CountersPutAi extends CountersAi {
|
||||
final int tributeAmount = AbilityUtils.calculateAmount(source, amountStr, sa);
|
||||
|
||||
final boolean isHaste = source.hasKeyword(Keyword.HASTE);
|
||||
List<Card> threatening = CardLists.filter(creats, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card c) {
|
||||
return CombatUtil.canBlock(source, c, !isHaste)
|
||||
&& (c.getNetToughness() > source.getNetPower() + tributeAmount || c.hasKeyword(Keyword.DEATHTOUCH));
|
||||
}
|
||||
});
|
||||
List<Card> threatening = CardLists.filter(creats, c -> CombatUtil.canBlock(source, c, !isHaste)
|
||||
&& (c.getNetToughness() > source.getNetPower() + tributeAmount || c.hasKeyword(Keyword.DEATHTOUCH))
|
||||
);
|
||||
if (!threatening.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
@@ -946,12 +929,9 @@ public class CountersPutAi extends CountersAi {
|
||||
return false;
|
||||
} else if (logic.equals("CanBlockThisTurn")) {
|
||||
// pump haste
|
||||
List<Card> canBlock = CardLists.filter(creats, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card c) {
|
||||
return CombatUtil.canBlock(source, c) && (c.getNetToughness() > source.getNetPower() || c.hasKeyword(Keyword.DEATHTOUCH));
|
||||
}
|
||||
});
|
||||
List<Card> canBlock = CardLists.filter(creats, c -> CombatUtil.canBlock(source, c)
|
||||
&& (c.getNetToughness() > source.getNetPower() || c.hasKeyword(Keyword.DEATHTOUCH))
|
||||
);
|
||||
if (!canBlock.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
@@ -1003,9 +983,7 @@ public class CountersPutAi extends CountersAi {
|
||||
final CardCollection opponents = CardLists.filterControlledBy(options, ai.getOpponents());
|
||||
|
||||
if (!opponents.isEmpty()) {
|
||||
final CardCollection negative = CardLists.filter(opponents, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card input) {
|
||||
final CardCollection negative = CardLists.filter(opponents, input -> {
|
||||
if (input.hasSVar("EndOfTurnLeavePlay"))
|
||||
return false;
|
||||
if (ComputerUtilCard.isUselessCreature(ai, input))
|
||||
@@ -1018,7 +996,6 @@ public class CountersPutAi extends CountersAi {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (!negative.isEmpty()) {
|
||||
return ComputerUtilCard.getBestAI(negative);
|
||||
@@ -1053,13 +1030,10 @@ public class CountersPutAi extends CountersAi {
|
||||
if (doNotHaveKeyword.size() > 0)
|
||||
filtered = doNotHaveKeyword;
|
||||
|
||||
final CardCollection notUseless = CardLists.filter(filtered, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card input) {
|
||||
final CardCollection notUseless = CardLists.filter(filtered, input -> {
|
||||
if (input.hasSVar("EndOfTurnLeavePlay"))
|
||||
return false;
|
||||
return !ComputerUtilCard.isUselessCreature(ai, input);
|
||||
}
|
||||
});
|
||||
|
||||
if (!notUseless.isEmpty()) {
|
||||
@@ -1069,26 +1043,20 @@ public class CountersPutAi extends CountersAi {
|
||||
// some special logic to reload Persist/Undying
|
||||
for (CounterType type : types) {
|
||||
if (p1p1.equals(type)) {
|
||||
final CardCollection persist = CardLists.filter(filtered, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card input) {
|
||||
final CardCollection persist = CardLists.filter(filtered, input -> {
|
||||
if (!input.hasKeyword(Keyword.PERSIST))
|
||||
return false;
|
||||
return input.getCounters(m1m1) <= amount;
|
||||
}
|
||||
});
|
||||
|
||||
if (!persist.isEmpty()) {
|
||||
filtered = persist;
|
||||
}
|
||||
} else if (m1m1.equals(type)) {
|
||||
final CardCollection undying = CardLists.filter(filtered, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card input) {
|
||||
final CardCollection undying = CardLists.filter(filtered, input -> {
|
||||
if (!input.hasKeyword(Keyword.UNDYING))
|
||||
return false;
|
||||
return input.getCounters(p1p1) <= amount && input.getNetToughness() > amount;
|
||||
}
|
||||
});
|
||||
|
||||
if (!undying.isEmpty()) {
|
||||
@@ -1161,15 +1129,12 @@ public class CountersPutAi extends CountersAi {
|
||||
CardCollection targets = CardLists.getTargetableCards(ai.getCreaturesInPlay(), sa);
|
||||
targets.remove(source);
|
||||
|
||||
targets = CardLists.filter(targets, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
targets = CardLists.filter(targets, card -> {
|
||||
boolean tgtThreatened = ComputerUtil.predictThreatenedObjects(ai, null, true).contains(card)
|
||||
|| (combat != null && ((combat.isBlocked(card) && ComputerUtilCombat.attackerWouldBeDestroyed(ai, card, combat))
|
||||
|| (combat.isBlocking(card) && ComputerUtilCombat.blockerWouldBeDestroyed(ai, card, combat))));
|
||||
// when threatened, any non-threatened target is good to preserve the counter
|
||||
return !tgtThreatened && (threatened || ComputerUtilCard.evaluateCreature(card, false, false) > ComputerUtilCard.evaluateCreature(source, false, false) + creatDiff);
|
||||
}
|
||||
});
|
||||
|
||||
Card bestTgt = ComputerUtilCard.getBestCreatureAI(targets);
|
||||
@@ -1194,7 +1159,7 @@ public class CountersPutAi extends CountersAi {
|
||||
}
|
||||
}
|
||||
|
||||
int totBlkPower = Aggregates.sum(combat.getBlockers(source), CardPredicates.Accessors.fnGetNetPower);
|
||||
int totBlkPower = Aggregates.sum(combat.getBlockers(source), Card::getNetPower);
|
||||
if (source.getNetToughness() <= totBlkPower
|
||||
&& source.getNetToughness() + amount > totBlkPower) {
|
||||
return true;
|
||||
@@ -1208,7 +1173,7 @@ public class CountersPutAi extends CountersAi {
|
||||
}
|
||||
}
|
||||
|
||||
int totAtkPower = Aggregates.sum(combat.getAttackersBlockedBy(source), CardPredicates.Accessors.fnGetNetPower);
|
||||
int totAtkPower = Aggregates.sum(combat.getAttackersBlockedBy(source), Card::getNetPower);
|
||||
if (source.getNetToughness() <= totAtkPower
|
||||
&& source.getNetToughness() + amount > totAtkPower) {
|
||||
return true;
|
||||
@@ -1229,7 +1194,7 @@ public class CountersPutAi extends CountersAi {
|
||||
Card source = sa.getHostCard();
|
||||
CardCollectionView ownLib = CardLists.filter(ai.getCardsIn(ZoneType.Library), CardPredicates.isType("Creature"));
|
||||
int numCtrs = source.getCounters(CounterEnumType.CHARGE);
|
||||
int maxCMC = Aggregates.max(ownLib, CardPredicates.Accessors.fnGetCmc);
|
||||
int maxCMC = Aggregates.max(ownLib, Card::getCMC);
|
||||
int optimalCMC = 0;
|
||||
int curAmount = 0;
|
||||
// Assume the AI knows its deck list and realizes what it has left in its library. Could be improved to make this less cheat-y.
|
||||
@@ -1247,7 +1212,7 @@ public class CountersPutAi extends CountersAi {
|
||||
Card source = sa.getHostCard();
|
||||
CardCollectionView oppInPlay = CardLists.filter(ai.getOpponents().getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.NONLAND_PERMANENTS);
|
||||
int numCtrs = source.getCounters(CounterEnumType.CHARGE);
|
||||
int maxCMC = Aggregates.max(oppInPlay, CardPredicates.Accessors.fnGetCmc);
|
||||
int maxCMC = Aggregates.max(oppInPlay, Card::getCMC);
|
||||
int optimalCMC = 0;
|
||||
int curAmount = 0;
|
||||
for (int cmc = numCtrs; cmc <= maxCMC; cmc++) {
|
||||
|
||||
@@ -3,7 +3,6 @@ package forge.ai.ability;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.ai.ComputerUtilCost;
|
||||
@@ -95,12 +94,7 @@ public class CountersPutAllAi extends SpellAbilityAi {
|
||||
|
||||
if (curse) {
|
||||
if (type.equals("M1M1")) {
|
||||
final List<Card> killable = CardLists.filter(hList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.getNetToughness() <= amount;
|
||||
}
|
||||
});
|
||||
final List<Card> killable = CardLists.filter(hList, c -> c.getNetToughness() <= amount);
|
||||
if (!(killable.size() > 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -107,12 +107,7 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
|
||||
|
||||
if (!countersList.isEmpty()) {
|
||||
CardCollectionView marit = ai.getCardsIn(ZoneType.Battlefield, "Marit Lage");
|
||||
boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card input) {
|
||||
return input.ignoreLegendRule();
|
||||
}
|
||||
});
|
||||
boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, (Predicate<Card>) Card::ignoreLegendRule);
|
||||
if (maritEmpty) {
|
||||
CardCollectionView depthsList = CardLists.filter(countersList,
|
||||
CardPredicates.nameEquals("Dark Depths"), CardPredicates.hasCounter(CounterEnumType.ICE));
|
||||
@@ -237,12 +232,7 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
|
||||
// this counters are treat first to be removed
|
||||
if ("Dark Depths".equals(tgt.getName()) && options.contains(CounterType.get(CounterEnumType.ICE))) {
|
||||
CardCollectionView marit = ai.getCardsIn(ZoneType.Battlefield, "Marit Lage");
|
||||
boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card input) {
|
||||
return input.ignoreLegendRule();
|
||||
}
|
||||
});
|
||||
boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, (Predicate<Card>) Card::ignoreLegendRule);
|
||||
|
||||
if (maritEmpty) {
|
||||
return CounterType.get(CounterEnumType.ICE);
|
||||
@@ -288,12 +278,7 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
|
||||
} else {
|
||||
if (type.is(CounterEnumType.ICE) && "Dark Depths".equals(tgt.getName())) {
|
||||
CardCollectionView marit = ai.getCardsIn(ZoneType.Battlefield, "Marit Lage");
|
||||
boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card input) {
|
||||
return input.ignoreLegendRule();
|
||||
}
|
||||
});
|
||||
boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, (Predicate<Card>) Card::ignoreLegendRule);
|
||||
|
||||
if (maritEmpty) {
|
||||
return false;
|
||||
|
||||
@@ -118,12 +118,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
|
||||
list = ComputerUtil.filterAITgts(sa, ai, list, false);
|
||||
|
||||
CardCollectionView marit = ai.getCardsIn(ZoneType.Battlefield, "Marit Lage");
|
||||
boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card input) {
|
||||
return input.ignoreLegendRule();
|
||||
}
|
||||
});
|
||||
boolean maritEmpty = marit.isEmpty() || Iterables.contains(marit, (Predicate<Card>) Card::ignoreLegendRule);
|
||||
|
||||
if (type.matches("All")) {
|
||||
// Logic Part for Vampire Hexmage
|
||||
|
||||
@@ -253,12 +253,7 @@ public class DamageAllAi extends SpellAbilityAi {
|
||||
CardCollection list =
|
||||
CardLists.getValidCards(player.getCardsIn(ZoneType.Battlefield), validC, source.getController(), source, sa);
|
||||
|
||||
final Predicate<Card> filterKillable = new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return ComputerUtilCombat.predictDamageTo(c, dmg, source, false) >= ComputerUtilCombat.getDamageToKill(c, false);
|
||||
}
|
||||
};
|
||||
final Predicate<Card> filterKillable = c -> ComputerUtilCombat.predictDamageTo(c, dmg, source, false) >= ComputerUtilCombat.getDamageToKill(c, false);
|
||||
|
||||
list = CardLists.getNotKeyword(list, Keyword.INDESTRUCTIBLE);
|
||||
list = CardLists.filter(list, filterKillable);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
@@ -171,7 +170,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
} else if ("WildHunt".equals(logic)) {
|
||||
// This dummy ability will just deal 0 damage, but holds the logic for the AI for Master of Wild Hunt
|
||||
List<Card> wolves = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), "Creature.Wolf+untapped+YouCtrl+Other", ai, source, sa);
|
||||
dmg = Aggregates.sum(wolves, CardPredicates.Accessors.fnGetNetPower);
|
||||
dmg = Aggregates.sum(wolves, Card::getNetPower);
|
||||
} else if ("Triskelion".equals(logic)) {
|
||||
final int n = source.getCounters(CounterEnumType.P1P1);
|
||||
if (n > 0) {
|
||||
@@ -337,16 +336,11 @@ public class DamageDealAi extends DamageAiBase {
|
||||
// Filter MustTarget requirements
|
||||
StaticAbilityMustTarget.filterMustTargetCards(ai, hPlay, sa);
|
||||
|
||||
CardCollection killables = CardLists.filter(hPlay, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.getSVar("Targeting").equals("Dies")
|
||||
CardCollection killables = CardLists.filter(hPlay, c -> c.getSVar("Targeting").equals("Dies")
|
||||
|| (ComputerUtilCombat.getEnoughDamageToKill(c, d, source, false, noPrevention) <= d)
|
||||
&& !ComputerUtil.canRegenerate(ai, c)
|
||||
&& !c.hasSVar("SacMe")
|
||||
&& !ComputerUtilCard.hasActiveUndyingOrPersist(c);
|
||||
}
|
||||
});
|
||||
&& !ComputerUtilCard.hasActiveUndyingOrPersist(c));
|
||||
|
||||
// Filter AI-specific targets if provided
|
||||
killables = ComputerUtil.filterAITgts(sa, ai, killables, true);
|
||||
@@ -416,15 +410,10 @@ public class DamageDealAi extends DamageAiBase {
|
||||
final Game game = source.getGame();
|
||||
List<Card> hPlay = CardLists.filter(getTargetableCards(ai, sa, pl, tgt, activator, source, game), CardPredicates.Presets.PLANESWALKERS);
|
||||
|
||||
CardCollection killables = CardLists.filter(hPlay, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.getSVar("Targeting").equals("Dies")
|
||||
CardCollection killables = CardLists.filter(hPlay, c -> c.getSVar("Targeting").equals("Dies")
|
||||
|| (ComputerUtilCombat.getEnoughDamageToKill(c, d, source, false, noPrevention) <= d)
|
||||
&& !ComputerUtil.canRegenerate(ai, c)
|
||||
&& !c.hasSVar("SacMe");
|
||||
}
|
||||
});
|
||||
&& !c.hasSVar("SacMe"));
|
||||
|
||||
// Filter AI-specific targets if provided
|
||||
killables = ComputerUtil.filterAITgts(sa, ai, killables, true);
|
||||
|
||||
@@ -4,7 +4,6 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
@@ -69,9 +68,7 @@ public class DebuffAi extends SpellAbilityAi {
|
||||
List<Card> cards = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa);
|
||||
|
||||
final Combat combat = game.getCombat();
|
||||
return Iterables.any(cards, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return Iterables.any(cards, c -> {
|
||||
if (c.getController().equals(sa.getActivatingPlayer()) || combat == null)
|
||||
return false;
|
||||
|
||||
@@ -80,7 +77,6 @@ public class DebuffAi extends SpellAbilityAi {
|
||||
}
|
||||
// don't add duplicate negative keywords
|
||||
return sa.hasParam("Keywords") && c.hasAnyKeyword(Arrays.asList(sa.getParam("Keywords").split(" & ")));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return debuffTgtAI(ai, sa, sa.hasParam("Keywords") ? Arrays.asList(sa.getParam("Keywords").split(" & ")) : null, false);
|
||||
@@ -172,11 +168,8 @@ public class DebuffAi extends SpellAbilityAi {
|
||||
final Player opp = AiAttackController.choosePreferredDefenderPlayer(ai);
|
||||
CardCollection list = CardLists.getTargetableCards(opp.getCreaturesInPlay(), sa);
|
||||
if (!list.isEmpty()) {
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
list = CardLists.filter(list, c -> {
|
||||
return c.hasAnyKeyword(kws); // don't add duplicate negative keywords
|
||||
}
|
||||
});
|
||||
}
|
||||
return list;
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import forge.ai.*;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.cost.Cost;
|
||||
@@ -60,9 +58,7 @@ public class DelayedTriggerAi extends SpellAbilityAi {
|
||||
// fetch Instant or Sorcery and AI has reason to play this turn
|
||||
// does not try to get itself
|
||||
final ManaCost costSa = sa.getPayCosts().getTotalMana();
|
||||
final int count = CardLists.count(ai.getCardsIn(ZoneType.Hand), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
final int count = CardLists.count(ai.getCardsIn(ZoneType.Hand), c -> {
|
||||
if (!(c.isInstant() || c.isSorcery()) || c.equals(sa.getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
@@ -91,7 +87,6 @@ public class DelayedTriggerAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (count == 0) {
|
||||
@@ -106,9 +101,7 @@ public class DelayedTriggerAi extends SpellAbilityAi {
|
||||
|
||||
// fetch Instant or Sorcery without Rebound and AI has reason to play this turn
|
||||
// only need count, not the list
|
||||
final int count = CardLists.count(ai.getCardsIn(ZoneType.Hand), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
final int count = CardLists.count(ai.getCardsIn(ZoneType.Hand), c -> {
|
||||
if (!(c.isInstant() || c.isSorcery()) || c.hasKeyword(Keyword.REBOUND)) {
|
||||
return false;
|
||||
}
|
||||
@@ -129,7 +122,6 @@ public class DelayedTriggerAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (count == 0) {
|
||||
@@ -140,15 +132,12 @@ public class DelayedTriggerAi extends SpellAbilityAi {
|
||||
} else if (logic.equals("SaveCreature")) {
|
||||
CardCollection ownCreatures = ai.getCreaturesInPlay();
|
||||
|
||||
ownCreatures = CardLists.filter(ownCreatures, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card card) {
|
||||
ownCreatures = CardLists.filter(ownCreatures, card -> {
|
||||
if (ComputerUtilCard.isUselessCreature(ai, card)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ComputerUtil.predictCreatureWillDieThisTurn(ai, card, sa);
|
||||
}
|
||||
});
|
||||
|
||||
if (!ownCreatures.isEmpty()) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import forge.ai.*;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
@@ -170,9 +169,7 @@ public class DestroyAi extends SpellAbilityAi {
|
||||
if (!playReusable(ai, sa)) {
|
||||
list = CardLists.filter(list, Predicates.not(CardPredicates.hasCounter(CounterEnumType.SHIELD, 1)));
|
||||
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
list = CardLists.filter(list, c -> {
|
||||
//Check for cards that can be sacrificed in response
|
||||
for (final SpellAbility ability : c.getAllSpellAbilities()) {
|
||||
if (ability.isActivatedAbility()) {
|
||||
@@ -193,7 +190,6 @@ public class DestroyAi extends SpellAbilityAi {
|
||||
}
|
||||
//Check for undying
|
||||
return !c.hasKeyword(Keyword.UNDYING) || c.getCounters(CounterEnumType.P1P1) > 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -201,12 +197,7 @@ public class DestroyAi extends SpellAbilityAi {
|
||||
// regeneration shield
|
||||
if (!noRegen) {
|
||||
// TODO filter out things that might be tougher?
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.getShieldCount() == 0 && !ComputerUtil.canRegenerate(ai, c);
|
||||
}
|
||||
});
|
||||
list = CardLists.filter(list, c -> c.getShieldCount() == 0 && !ComputerUtil.canRegenerate(ai, c));
|
||||
}
|
||||
|
||||
// Try to avoid targeting creatures that are dead on board
|
||||
@@ -340,12 +331,7 @@ public class DestroyAi extends SpellAbilityAi {
|
||||
if (!noRegen) {
|
||||
// TODO filter out things that could regenerate in response?
|
||||
// might be tougher?
|
||||
preferred = CardLists.filter(preferred, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.getShieldCount() == 0;
|
||||
}
|
||||
});
|
||||
preferred = CardLists.filter(preferred, c -> c.getShieldCount() == 0);
|
||||
}
|
||||
|
||||
// Filter AI-specific targets if provided
|
||||
|
||||
@@ -19,12 +19,7 @@ import forge.game.zone.ZoneType;
|
||||
|
||||
public class DestroyAllAi extends SpellAbilityAi {
|
||||
|
||||
private static final Predicate<Card> predicate = new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return !(c.hasKeyword(Keyword.INDESTRUCTIBLE) || c.getCounters(CounterEnumType.SHIELD) > 0 || c.hasSVar("SacMe"));
|
||||
}
|
||||
};
|
||||
private static final Predicate<Card> predicate = c -> !(c.hasKeyword(Keyword.INDESTRUCTIBLE) || c.getCounters(CounterEnumType.SHIELD) > 0 || c.hasSVar("SacMe"));
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.abilityfactory.SpellAiLogic#doTriggerAINoCost(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility, boolean)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
import forge.ai.*;
|
||||
@@ -29,7 +28,6 @@ import forge.game.zone.MagicStack;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.MyRandom;
|
||||
import forge.util.TextUtil;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -173,22 +171,12 @@ public class EffectAi extends SpellAbilityAi {
|
||||
List<Card> human = opp.getCreaturesInPlay();
|
||||
|
||||
// only count creatures that can attack or block
|
||||
comp = CardLists.filter(comp, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return CombatUtil.canAttack(c, opp);
|
||||
}
|
||||
});
|
||||
comp = CardLists.filter(comp, c -> CombatUtil.canAttack(c, opp));
|
||||
if (comp.size() < 2) {
|
||||
continue;
|
||||
}
|
||||
final List<Card> attackers = comp;
|
||||
human = CardLists.filter(human, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return CombatUtil.canBlockAtLeastOne(c, attackers);
|
||||
}
|
||||
});
|
||||
human = CardLists.filter(human, c -> CombatUtil.canBlockAtLeastOne(c, attackers));
|
||||
if (human.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
@@ -345,10 +333,7 @@ public class EffectAi extends SpellAbilityAi {
|
||||
} else if (logic.equals("CantRegenerate")) {
|
||||
if (sa.usesTargeting()) {
|
||||
CardCollection list = CardLists.getTargetableCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), sa);
|
||||
list = CardLists.filter(list, CardPredicates.Presets.CAN_BE_DESTROYED, new Predicate<Card>() {
|
||||
|
||||
@Override
|
||||
public boolean apply(@Nullable Card input) {
|
||||
list = CardLists.filter(list, CardPredicates.Presets.CAN_BE_DESTROYED, input -> {
|
||||
Map<AbilityKey, Object> runParams = AbilityKey.mapFromAffected(input);
|
||||
runParams.put(AbilityKey.Regeneration, true);
|
||||
List<ReplacementEffect> repDestoryList = game.getReplacementHandler().getReplacementList(ReplacementType.Destroy, runParams, ReplacementLayer.Other);
|
||||
@@ -362,7 +347,6 @@ public class EffectAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (list.isEmpty()) {
|
||||
|
||||
@@ -20,8 +20,6 @@ package forge.ai.ability;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import forge.ai.ComputerUtilCard;
|
||||
import forge.ai.ComputerUtilCombat;
|
||||
import forge.ai.SpellAbilityAi;
|
||||
@@ -91,15 +89,8 @@ public final class EncodeAi extends SpellAbilityAi {
|
||||
Card choice = null;
|
||||
// final String logic = sa.getParam("AILogic");
|
||||
// if (logic == null) {
|
||||
final List<Card> attackers = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return ComputerUtilCombat.canAttackNextTurn(c);
|
||||
}
|
||||
});
|
||||
final List<Card> unblockables = CardLists.filter(attackers, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
final List<Card> attackers = CardLists.filter(list, ComputerUtilCombat::canAttackNextTurn);
|
||||
final List<Card> unblockables = CardLists.filter(attackers, c -> {
|
||||
boolean canAttackOpponent = false;
|
||||
for (Player opp : ai.getOpponents()) {
|
||||
if (CombatUtil.canAttack(c, opp) && !CombatUtil.canBeBlocked(c, null, opp)) {
|
||||
@@ -108,7 +99,6 @@ public final class EncodeAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
return canAttackOpponent;
|
||||
}
|
||||
});
|
||||
if (!unblockables.isEmpty()) {
|
||||
choice = ComputerUtilCard.getBestAI(unblockables);
|
||||
|
||||
@@ -2,9 +2,7 @@ package forge.ai.ability;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import forge.ai.SpellAbilityAi;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.phase.PhaseHandler;
|
||||
@@ -26,12 +24,7 @@ public class FlipOntoBattlefieldAi extends SpellAbilityAi {
|
||||
|
||||
if ("DamageCreatures".equals(logic)) {
|
||||
int maxToughness = Integer.parseInt(sa.getSubAbility().getParam("NumDmg"));
|
||||
CardCollectionView rightToughness = CardLists.filter(aiPlayer.getOpponents().getCreaturesInPlay(), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return card.getNetToughness() <= maxToughness && card.canBeDestroyed();
|
||||
}
|
||||
});
|
||||
CardCollectionView rightToughness = CardLists.filter(aiPlayer.getOpponents().getCreaturesInPlay(), card -> card.getNetToughness() <= maxToughness && card.canBeDestroyed());
|
||||
return !rightToughness.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@ package forge.ai.ability;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import forge.ai.ComputerUtilCard;
|
||||
import forge.ai.ComputerUtilCombat;
|
||||
import forge.ai.SpellAbilityAi;
|
||||
@@ -32,9 +30,7 @@ public class GoadAi extends SpellAbilityAi {
|
||||
|
||||
if (game.getPlayers().size() > 2) {
|
||||
// use this part only in multiplayer
|
||||
CardCollection betterList = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card c) {
|
||||
CardCollection betterList = CardLists.filter(list, c -> {
|
||||
// filter only creatures which can attack
|
||||
if (ComputerUtilCard.isUselessCreature(ai, c)) {
|
||||
return false;
|
||||
@@ -50,7 +46,6 @@ public class GoadAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// if better list is not empty, use that one instead
|
||||
@@ -61,9 +56,7 @@ public class GoadAi extends SpellAbilityAi {
|
||||
}
|
||||
} else {
|
||||
// single Player, goaded creature would attack ai
|
||||
CardCollection betterList = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card c) {
|
||||
CardCollection betterList = CardLists.filter(list, c -> {
|
||||
// filter only creatures which can attack
|
||||
if (ComputerUtilCard.isUselessCreature(ai, c)) {
|
||||
return false;
|
||||
@@ -74,7 +67,6 @@ public class GoadAi extends SpellAbilityAi {
|
||||
}
|
||||
// select only creatures AI can block
|
||||
return ComputerUtilCard.canBeBlockedProfitably(ai, c, false);
|
||||
}
|
||||
});
|
||||
|
||||
// if better list is not empty, use that one instead
|
||||
|
||||
@@ -245,7 +245,7 @@ public class ManaAi extends SpellAbilityAi {
|
||||
if (logic.startsWith("ManaRitualBattery")) {
|
||||
// Don't remove more counters than would be needed to cast the more expensive thing we want to cast,
|
||||
// otherwise the AI grabs too many counters at once.
|
||||
int maxCtrs = Aggregates.max(castableSpells, CardPredicates.Accessors.fnGetCmc) - manaSurplus;
|
||||
int maxCtrs = Aggregates.max(castableSpells, Card::getCMC) - manaSurplus;
|
||||
sa.setXManaCostPaid(Math.min(numCounters, maxCtrs));
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package forge.ai.ability;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import forge.ai.ComputerUtil;
|
||||
@@ -138,12 +137,7 @@ public abstract class ManifestBaseAi extends SpellAbilityAi {
|
||||
@Override
|
||||
protected Card chooseSingleCard(final Player ai, final SpellAbility sa, Iterable<Card> options, boolean isOptional, Player targetedPlayer, Map<String, Object> params) {
|
||||
if (Iterables.size(options) > 1 || isOptional) {
|
||||
CardCollection filtered = CardLists.filter(options, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card input) {
|
||||
return shouldApply(input, ai, sa);
|
||||
}
|
||||
});
|
||||
CardCollection filtered = CardLists.filter(options, input -> shouldApply(input, ai, sa));
|
||||
if (!filtered.isEmpty()) {
|
||||
return ComputerUtilCard.getBestAI(filtered);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -159,13 +158,7 @@ public class MillAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
// select Player which would cause the most damage
|
||||
// JAVA 1.8 use Map.Entry.comparingByValue()
|
||||
Map.Entry<Player, Integer> max = Collections.max(list.entrySet(), new Comparator<Map.Entry<Player,Integer>>(){
|
||||
@Override
|
||||
public int compare(Map.Entry<Player, Integer> o1, Map.Entry<Player, Integer> o2) {
|
||||
return o1.getValue() - o2.getValue();
|
||||
}
|
||||
});
|
||||
Map.Entry<Player, Integer> max = Collections.max(list.entrySet(), Map.Entry.comparingByValue());
|
||||
|
||||
sa.getTargets().add(max.getKey());
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package forge.ai.ability;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import forge.ai.AiCardMemory;
|
||||
@@ -122,9 +121,7 @@ public class MustBlockAi extends SpellAbilityAi {
|
||||
|
||||
private List<Card> determineBlockerFromList(final Card attacker, final Player ai, Iterable<Card> options, SpellAbility sa,
|
||||
final boolean onlyLethal, final boolean testTapped) {
|
||||
List<Card> list = CardLists.filter(options, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
List<Card> list = CardLists.filter(options, c -> {
|
||||
boolean tapped = c.isTapped();
|
||||
if (testTapped) {
|
||||
c.setTapped(false);
|
||||
@@ -142,8 +139,6 @@ public class MustBlockAi extends SpellAbilityAi {
|
||||
c.setTapped(tapped);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return list;
|
||||
|
||||
@@ -2,7 +2,6 @@ package forge.ai.ability;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
|
||||
import forge.ai.ComputerUtil;
|
||||
@@ -29,12 +28,7 @@ public class MutateAi extends SpellAbilityAi {
|
||||
CardPredicates.hasKeyword(Keyword.DEFENDER),
|
||||
CardPredicates.hasKeyword("CARDNAME can't attack."),
|
||||
CardPredicates.hasKeyword("CARDNAME can't block."),
|
||||
new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card card) {
|
||||
return ComputerUtilCard.isUselessCreature(aiPlayer, card);
|
||||
}
|
||||
}
|
||||
card -> ComputerUtilCard.isUselessCreature(aiPlayer, card)
|
||||
)));
|
||||
|
||||
if (mutateTgts.isEmpty()) {
|
||||
|
||||
@@ -3,8 +3,6 @@ package forge.ai.ability;
|
||||
import forge.game.card.CardCopyService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import forge.ai.AiController;
|
||||
import forge.ai.AiProps;
|
||||
import forge.ai.ComputerUtil;
|
||||
@@ -146,12 +144,9 @@ public class PermanentCreatureAi extends PermanentAi {
|
||||
if (combat != null && combat.getDefendingPlayers().contains(ai)) {
|
||||
// Currently we use a rather simplistic assumption that if we're behind on creature count on board,
|
||||
// a flashed in creature might prove to be good as an additional defender
|
||||
int numUntappedPotentialBlockers = CardLists.filter(ai.getCreaturesInPlay(), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card card) {
|
||||
return card.isUntapped() && !ComputerUtilCard.isUselessCreature(ai, card);
|
||||
}
|
||||
}).size();
|
||||
int numUntappedPotentialBlockers = CardLists.filter(ai.getCreaturesInPlay(),
|
||||
card1 -> card1.isUntapped() && !ComputerUtilCard.isUselessCreature(ai, card1)
|
||||
).size();
|
||||
|
||||
if (combat.getAttackersOf(ai).size() > numUntappedPotentialBlockers) {
|
||||
valuableBlocker = true;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import forge.ai.*;
|
||||
import forge.card.CardStateName;
|
||||
@@ -148,9 +147,7 @@ public class PlayAi extends SpellAbilityAi {
|
||||
state = CardStateName.Original;
|
||||
}
|
||||
|
||||
List<Card> tgtCards = CardLists.filter(options, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
List<Card> tgtCards = CardLists.filter(options, c -> {
|
||||
// TODO needs to be aligned for MDFC along with getAbilityToPlay so the knowledge
|
||||
// of which spell was the reason for the choice can be used there
|
||||
for (SpellAbility s : AbilityUtils.getSpellsFromPlayEffect(c, ai, state, false)) {
|
||||
@@ -198,7 +195,6 @@ public class PlayAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (sa.hasParam("CastTransformed")) {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import forge.ai.ComputerUtil;
|
||||
import forge.ai.SpellAbilityAi;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
@@ -86,17 +84,13 @@ public class PoisonAi extends SpellAbilityAi {
|
||||
PlayerCollection tgts = ai.getOpponents().filter(PlayerPredicates.isTargetableBy(sa));
|
||||
if (!tgts.isEmpty()) {
|
||||
// try to select a opponent that can lose through poison counters
|
||||
PlayerCollection betterTgts = tgts.filter(new Predicate<Player>() {
|
||||
@Override
|
||||
public boolean apply(Player input) {
|
||||
PlayerCollection betterTgts = tgts.filter(input -> {
|
||||
if (input.cantLose()) {
|
||||
return false;
|
||||
} else if (!input.canReceiveCounters(CounterType.get(CounterEnumType.POISON))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if (!betterTgts.isEmpty()) {
|
||||
@@ -120,15 +114,11 @@ public class PoisonAi extends SpellAbilityAi {
|
||||
PlayerCollection allies = ai.getAllies().filter(PlayerPredicates.isTargetableBy(sa));
|
||||
if (!allies.isEmpty()) {
|
||||
// some ally would be unaffected
|
||||
PlayerCollection betterAllies = allies.filter(new Predicate<Player>() {
|
||||
@Override
|
||||
public boolean apply(Player input) {
|
||||
PlayerCollection betterAllies = allies.filter(input -> {
|
||||
if (input.cantLose()) {
|
||||
return true;
|
||||
}
|
||||
return !input.canReceiveCounters(CounterType.get(CounterEnumType.POISON));
|
||||
}
|
||||
|
||||
});
|
||||
if (!betterAllies.isEmpty()) {
|
||||
allies = betterAllies;
|
||||
|
||||
@@ -2,8 +2,6 @@ package forge.ai.ability;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import forge.ai.ComputerUtilCard;
|
||||
import forge.ai.SpellAbilityAi;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
@@ -30,12 +28,7 @@ public class PowerExchangeAi extends SpellAbilityAi {
|
||||
|
||||
List<Card> list =
|
||||
CardLists.getValidCards(ai.getGame().getCardsIn(ZoneType.Battlefield), tgt.getValidTgts(), ai, sa.getHostCard(), sa);
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.canBeTargetedBy(sa) && c.getController() != ai;
|
||||
}
|
||||
});
|
||||
list = CardLists.filter(list, c -> c.canBeTargetedBy(sa) && c.getController() != ai);
|
||||
CardLists.sortByPowerDesc(list);
|
||||
c1 = list.isEmpty() ? null : list.get(0);
|
||||
if (sa.hasParam("Defined")) {
|
||||
|
||||
@@ -3,8 +3,6 @@ package forge.ai.ability;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import forge.ai.AiAttackController;
|
||||
import forge.ai.ComputerUtil;
|
||||
import forge.ai.ComputerUtilCard;
|
||||
@@ -107,9 +105,7 @@ public class ProtectAi extends SpellAbilityAi {
|
||||
|
||||
CardCollection list = ai.getCreaturesInPlay();
|
||||
final List<GameObject> threatenedObjects = ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), sa, true);
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
list = CardLists.filter(list, c -> {
|
||||
if (!c.canBeTargetedBy(sa)) {
|
||||
return false;
|
||||
}
|
||||
@@ -148,13 +144,12 @@ public class ProtectAi extends SpellAbilityAi {
|
||||
return false;
|
||||
}
|
||||
Player opponent = ai.getWeakestOpponent();
|
||||
Combat combat = ai.getGame().getCombat();
|
||||
int dmg = ComputerUtilCombat.damageIfUnblocked(c, opponent, combat, true);
|
||||
Combat combat1 = ai.getGame().getCombat();
|
||||
int dmg = ComputerUtilCombat.damageIfUnblocked(c, opponent, combat1, true);
|
||||
float ratio = 1.0f * dmg / opponent.getLife();
|
||||
return MyRandom.getRandom().nextFloat() < ratio;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return list;
|
||||
}
|
||||
@@ -266,19 +261,9 @@ public class ProtectAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
CardCollection pref = CardLists.filterControlledBy(list, ai);
|
||||
pref = CardLists.filter(pref, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return !hasProtectionFromAll(c, ProtectEffect.getProtectionList(sa));
|
||||
}
|
||||
});
|
||||
pref = CardLists.filter(pref, c -> !hasProtectionFromAll(c, ProtectEffect.getProtectionList(sa)));
|
||||
final CardCollection pref2 = CardLists.filterControlledBy(list, ai);
|
||||
pref = CardLists.filter(pref, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return !hasProtectionFromAny(c, ProtectEffect.getProtectionList(sa));
|
||||
}
|
||||
});
|
||||
pref = CardLists.filter(pref, c -> !hasProtectionFromAny(c, ProtectEffect.getProtectionList(sa)));
|
||||
final List<Card> forced = CardLists.filterControlledBy(list, ai);
|
||||
|
||||
while (sa.canAddMoreTarget()) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -164,9 +163,7 @@ public class PumpAi extends PumpAiBase {
|
||||
if (attr.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
CardCollection best = CardLists.filter(attr, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
CardCollection best = CardLists.filter(attr, card -> {
|
||||
int amount = 0;
|
||||
if (StringUtils.isNumeric(amountStr)) {
|
||||
amount = AbilityUtils.calculateAmount(source, amountStr, moveSA);
|
||||
@@ -190,8 +187,6 @@ public class PumpAi extends PumpAiBase {
|
||||
|| card.isToken();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if (best.isEmpty()) {
|
||||
@@ -213,9 +208,7 @@ public class PumpAi extends PumpAiBase {
|
||||
}
|
||||
List<Card> oppList = CardLists.filterControlledBy(list, ai.getOpponents());
|
||||
if (!oppList.isEmpty() && !sameCtrl) {
|
||||
List<Card> best = CardLists.filter(oppList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
List<Card> best = CardLists.filter(oppList, card -> {
|
||||
int amount = 0;
|
||||
if (StringUtils.isNumeric(amountStr)) {
|
||||
amount = AbilityUtils.calculateAmount(source, amountStr, moveSA);
|
||||
@@ -239,7 +232,6 @@ public class PumpAi extends PumpAiBase {
|
||||
|| card.isToken();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
if (best.isEmpty()) {
|
||||
@@ -520,16 +512,13 @@ public class PumpAi extends PumpAiBase {
|
||||
// Detain target nonland permanent: don't target noncreature permanents that don't have
|
||||
// any activated abilities.
|
||||
if ("DetainNonLand".equals(sa.getParam("AILogic"))) {
|
||||
list = CardLists.filter(list, Predicates.or(CardPredicates.Presets.CREATURES, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
for (SpellAbility sa : card.getSpellAbilities()) {
|
||||
if (sa.isActivatedAbility()) {
|
||||
list = CardLists.filter(list, Predicates.or(CardPredicates.Presets.CREATURES, card -> {
|
||||
for (SpellAbility sa1 : card.getSpellAbilities()) {
|
||||
if (sa1.isActivatedAbility()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -548,12 +537,7 @@ public class PumpAi extends PumpAiBase {
|
||||
if ("BetterCreatureThanSource".equals(sa.getParam("AILogic"))) {
|
||||
// Don't target cards that are not better in value than the targeting card
|
||||
final int sourceValue = ComputerUtilCard.evaluateCreature(source);
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return card.isCreature() && ComputerUtilCard.evaluateCreature(card) > sourceValue + 30;
|
||||
}
|
||||
});
|
||||
list = CardLists.filter(list, card -> card.isCreature() && ComputerUtilCard.evaluateCreature(card) > sourceValue + 30);
|
||||
}
|
||||
|
||||
if ("ReplaySpell".equals(sa.getParam("AILogic"))) {
|
||||
@@ -819,23 +803,11 @@ public class PumpAi extends PumpAiBase {
|
||||
}
|
||||
values.keySet().removeAll(toRemove);
|
||||
|
||||
// JAVA 1.8 use Map.Entry.comparingByValue()
|
||||
data.put(opp, Collections.max(values.entrySet(), new Comparator<Map.Entry<String, Integer>>() {
|
||||
@Override
|
||||
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
|
||||
return o1.getValue() - o2.getValue();
|
||||
}
|
||||
}));
|
||||
data.put(opp, Collections.max(values.entrySet(), Map.Entry.comparingByValue()));
|
||||
}
|
||||
|
||||
if (!data.isEmpty()) {
|
||||
// JAVA 1.8 use Map.Entry.comparingByValue() somehow
|
||||
Map.Entry<Player, Map.Entry<String, Integer>> max = Collections.max(data.entrySet(), new Comparator<Map.Entry<Player, Map.Entry<String, Integer>>>() {
|
||||
@Override
|
||||
public int compare(Map.Entry<Player, Map.Entry<String, Integer>> o1, Map.Entry<Player, Map.Entry<String, Integer>> o2) {
|
||||
return o1.getValue().getValue() - o2.getValue().getValue();
|
||||
}
|
||||
});
|
||||
Map.Entry<Player, Map.Entry<String, Integer>> max = Collections.max(data.entrySet(), Comparator.comparingInt(o -> o.getValue().getValue()));
|
||||
|
||||
// filter list again by the opponent and a creature of the wanted name that can be targeted
|
||||
list = CardLists.filter(CardLists.filterControlledBy(list, max.getKey()),
|
||||
|
||||
@@ -122,15 +122,12 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<Card> attackers = CardLists.filter(ai.getCreaturesInPlay(), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
List<Card> attackers = CardLists.filter(ai.getCreaturesInPlay(), c -> {
|
||||
if (c.equals(sa.getHostCard()) && sa.getPayCosts().hasTapCost()
|
||||
&& (combat == null || !combat.isAttacking(c))) {
|
||||
return false;
|
||||
}
|
||||
return (combat != null && combat.isAttacking(c)) || CombatUtil.canAttack(c, card.getController());
|
||||
}
|
||||
});
|
||||
return CombatUtil.canBlockAtLeastOne(card, attackers);
|
||||
}
|
||||
@@ -140,9 +137,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<Card> attackers = CardLists.filter(ai.getCreaturesInPlay(), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
List<Card> attackers = CardLists.filter(ai.getCreaturesInPlay(), c -> {
|
||||
if (c.equals(sa.getHostCard()) && sa.getPayCosts().hasTapCost()
|
||||
&& (combat == null || !combat.isAttacking(c))) {
|
||||
return false;
|
||||
@@ -150,7 +145,6 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
||||
// the cards controller needs to be the one attacked
|
||||
return (combat != null && combat.isAttacking(c) && card.getController().equals(combat.getDefenderPlayerByAttacker(c))) ||
|
||||
CombatUtil.canAttack(c, card.getController());
|
||||
}
|
||||
});
|
||||
return CombatUtil.canBlockAtLeastOne(card, attackers);
|
||||
} else if (keyword.endsWith("This card doesn't untap during your next untap step.")) {
|
||||
@@ -416,12 +410,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
||||
protected CardCollection getPumpCreatures(final Player ai, final SpellAbility sa, final int defense, final int attack,
|
||||
final List<String> keywords, final boolean immediately) {
|
||||
CardCollection list = CardLists.getTargetableCards(ai.getCreaturesInPlay(), sa);
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return ComputerUtilCard.shouldPumpCard(ai, sa, c, defense, attack, keywords, immediately);
|
||||
}
|
||||
});
|
||||
list = CardLists.filter(list, c -> ComputerUtilCard.shouldPumpCard(ai, sa, c, defense, attack, keywords, immediately));
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -449,14 +438,11 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
if (defense < 0) { // with spells that give -X/-X, compi will try to destroy a creature
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
list = CardLists.filter(list, c -> {
|
||||
if (c.getSVar("Targeting").equals("Dies") || c.getNetToughness() <= -defense) {
|
||||
return true; // can kill indestructible creatures
|
||||
}
|
||||
return ComputerUtilCombat.getDamageToKill(c, false) <= -defense && !c.hasKeyword(Keyword.INDESTRUCTIBLE);
|
||||
}
|
||||
}); // leaves all creatures that will be destroyed
|
||||
} // -X/-X end
|
||||
else if (attack < 0 && !game.getReplacementHandler().isPreventCombatDamageThisTurn()) {
|
||||
@@ -472,9 +458,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
||||
} else {
|
||||
// Human active, only curse attacking creatures
|
||||
if (game.getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
list = CardLists.filter(list, c -> {
|
||||
if (combat == null || !combat.isAttacking(c)) {
|
||||
return false;
|
||||
}
|
||||
@@ -483,7 +467,6 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
||||
}
|
||||
//Don't waste a -7/-0 spell on a 1/1 creature
|
||||
return c.getNetPower() + attack > -2 || c.getNetPower() > 3;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
list = new CardCollection();
|
||||
@@ -501,12 +484,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
|
||||
list = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return containsUsefulKeyword(ai, keywords, c, sa, attack);
|
||||
}
|
||||
});
|
||||
list = CardLists.filter(list, c -> containsUsefulKeyword(ai, keywords, c, sa, attack));
|
||||
} else if (sa.hasParam("NumAtt") || sa.hasParam("NumDef")) {
|
||||
// X is zero
|
||||
list = new CardCollection();
|
||||
|
||||
@@ -4,7 +4,6 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import forge.ai.ComputerUtil;
|
||||
@@ -85,23 +84,17 @@ public class PumpAllAi extends PumpAiBase {
|
||||
|
||||
if (sa.isCurse()) {
|
||||
if (defense < 0) { // try to destroy creatures
|
||||
comp = CardLists.filter(comp, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
comp = CardLists.filter(comp, c -> {
|
||||
if (c.getNetToughness() <= -defense) {
|
||||
return true; // can kill indestructible creatures
|
||||
}
|
||||
return ComputerUtilCombat.getDamageToKill(c, false) <= -defense && !c.hasKeyword(Keyword.INDESTRUCTIBLE);
|
||||
}
|
||||
}); // leaves all creatures that will be destroyed
|
||||
human = CardLists.filter(human, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
human = CardLists.filter(human, c -> {
|
||||
if (c.getNetToughness() <= -defense) {
|
||||
return true; // can kill indestructible creatures
|
||||
}
|
||||
return ComputerUtilCombat.getDamageToKill(c, false) <= -defense && !c.hasKeyword(Keyword.INDESTRUCTIBLE);
|
||||
}
|
||||
}); // leaves all creatures that will be destroyed
|
||||
} // -X/-X end
|
||||
else if (power < 0) { // -X/-0
|
||||
|
||||
@@ -3,7 +3,6 @@ package forge.ai.ability;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import forge.ai.*;
|
||||
import forge.game.card.Card;
|
||||
@@ -56,12 +55,7 @@ public class RepeatAi extends SpellAbilityAi {
|
||||
Card best = null;
|
||||
Iterable<Card> targetableAi = Iterables.filter(ai.getCreaturesInPlay(), CardPredicates.isTargetableBy(sa));
|
||||
if (!logic.endsWith("IgnoreLegendary")) {
|
||||
best = ComputerUtilCard.getBestAI(Iterables.filter(targetableAi, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return card.ignoreLegendRule();
|
||||
}
|
||||
}));
|
||||
best = ComputerUtilCard.getBestAI(Iterables.filter(targetableAi, Card::ignoreLegendRule));
|
||||
} else {
|
||||
best = ComputerUtilCard.getBestAI(targetableAi);
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@ package forge.ai.ability;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import forge.ai.ComputerUtilCard;
|
||||
import forge.ai.SpecialCardAi;
|
||||
import forge.ai.SpellAbilityAi;
|
||||
@@ -97,12 +95,7 @@ public class RepeatEachAi extends SpellAbilityAi {
|
||||
return hitOpp;
|
||||
} else if ("EquipAll".equals(logic)) {
|
||||
if (aiPlayer.getGame().getPhaseHandler().is(PhaseType.MAIN1, aiPlayer)) {
|
||||
final CardCollection unequipped = CardLists.filter(aiPlayer.getCardsIn(ZoneType.Battlefield), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return card.isEquipment() && card.getAttachedTo() != sa.getHostCard();
|
||||
}
|
||||
});
|
||||
final CardCollection unequipped = CardLists.filter(aiPlayer.getCardsIn(ZoneType.Battlefield), card -> card.isEquipment() && card.getAttachedTo() != sa.getHostCard());
|
||||
|
||||
return !unequipped.isEmpty();
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@ package forge.ai.ability;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import forge.ai.ComputerUtilCard;
|
||||
import forge.ai.ComputerUtilCost;
|
||||
import forge.ai.SpellAbilityAi;
|
||||
@@ -75,12 +73,7 @@ public class SetStateAi extends SpellAbilityAi {
|
||||
sa.resetTargets();
|
||||
|
||||
// select only the ones that can transform
|
||||
CardCollection list = CardLists.filter(CardUtil.getValidCardsToTarget(sa), CardPredicates.Presets.CREATURES, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card c) {
|
||||
return c.canTransform(sa);
|
||||
}
|
||||
});
|
||||
CardCollection list = CardLists.filter(CardUtil.getValidCardsToTarget(sa), CardPredicates.Presets.CREATURES, c -> c.canTransform(sa));
|
||||
|
||||
if (list.isEmpty()) {
|
||||
return false;
|
||||
|
||||
@@ -109,39 +109,33 @@ public abstract class TapAiBase extends SpellAbilityAi {
|
||||
final Game game = ai.getGame();
|
||||
CardCollection tapList = CardLists.getTargetableCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), sa);
|
||||
tapList = CardLists.filter(tapList, Presets.CAN_TAP);
|
||||
tapList = CardLists.filter(tapList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
tapList = CardLists.filter(tapList, c -> {
|
||||
if (c.isCreature()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (final SpellAbility sa : c.getSpellAbilities()) {
|
||||
if (sa.isAbility() && sa.getPayCosts().hasTapCost()) {
|
||||
for (final SpellAbility sa1 : c.getSpellAbilities()) {
|
||||
if (sa1.isAbility() && sa1.getPayCosts().hasTapCost()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
//use broader approach when the cost is a positive thing
|
||||
if (tapList.isEmpty() && ComputerUtil.activateForCost(sa, ai)) {
|
||||
tapList = CardLists.getTargetableCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), sa);
|
||||
tapList = CardLists.filter(tapList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
tapList = CardLists.filter(tapList, c -> {
|
||||
if (c.isCreature()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (final SpellAbility sa : c.getSpellAbilities()) {
|
||||
if (sa.isAbility() && sa.getPayCosts().hasTapCost()) {
|
||||
for (final SpellAbility sa12 : c.getSpellAbilities()) {
|
||||
if (sa12.isAbility() && sa12.getPayCosts().hasTapCost()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -187,12 +181,7 @@ public abstract class TapAiBase extends SpellAbilityAi {
|
||||
//Combat has already started
|
||||
attackers = game.getCombat().getAttackers();
|
||||
} else {
|
||||
attackers = CardLists.filter(ai.getCreaturesInPlay(), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return CombatUtil.canAttack(c, opp);
|
||||
}
|
||||
});
|
||||
attackers = CardLists.filter(ai.getCreaturesInPlay(), c -> CombatUtil.canAttack(c, opp));
|
||||
attackers.remove(source);
|
||||
}
|
||||
Predicate<Card> findBlockers = CardPredicates.possibleBlockerForAtLeastOne(attackers);
|
||||
@@ -209,12 +198,7 @@ public abstract class TapAiBase extends SpellAbilityAi {
|
||||
&& phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
|
||||
// Tap creatures possible blockers before combat during AI's turn.
|
||||
if (Iterables.any(tapList, CardPredicates.Presets.CREATURES)) {
|
||||
List<Card> creatureList = CardLists.filter(tapList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.isCreature() && CombatUtil.canAttack(c, opp);
|
||||
}
|
||||
});
|
||||
List<Card> creatureList = CardLists.filter(tapList, c -> c.isCreature() && CombatUtil.canAttack(c, opp));
|
||||
choice = ComputerUtilCard.getBestCreatureAI(creatureList);
|
||||
} else { // no creatures available
|
||||
choice = ComputerUtilCard.getMostExpensivePermanentAI(tapList);
|
||||
|
||||
@@ -2,7 +2,6 @@ package forge.ai.ability;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import forge.ai.ComputerUtilCombat;
|
||||
@@ -75,12 +74,7 @@ public class TapAllAi extends SpellAbilityAi {
|
||||
// in AI's turn, check if there are possible attackers, before tapping blockers
|
||||
if (game.getPhaseHandler().isPlayerTurn(ai)) {
|
||||
validTappables = ai.getCardsIn(ZoneType.Battlefield);
|
||||
final boolean any = Iterables.any(validTappables, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return CombatUtil.canAttack(c) && ComputerUtilCombat.canAttackNextTurn(c);
|
||||
}
|
||||
});
|
||||
final boolean any = Iterables.any(validTappables, c -> CombatUtil.canAttack(c) && ComputerUtilCombat.canAttackNextTurn(c));
|
||||
return any;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -3,7 +3,6 @@ package forge.ai.ability;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import forge.ai.AiController;
|
||||
@@ -182,12 +181,7 @@ public class TokenAi extends SpellAbilityAi {
|
||||
} else {
|
||||
// Flash Foliage
|
||||
CardCollection list = CardLists.getTargetableCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), sa);
|
||||
CardCollection betterList = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card c) {
|
||||
return c.getLethalDamage() == 1;
|
||||
}
|
||||
});
|
||||
CardCollection betterList = CardLists.filter(list, c -> c.getLethalDamage() == 1);
|
||||
if (!betterList.isEmpty()) {
|
||||
list = betterList;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
import forge.ai.*;
|
||||
@@ -408,18 +407,15 @@ public class UntapAi extends SpellAbilityAi {
|
||||
// (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 untappingCards = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
CardCollection untappingCards = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), card -> {
|
||||
boolean hasUntapLandLogic = false;
|
||||
for (SpellAbility sa : card.getSpellAbilities()) {
|
||||
if ("PoolExtraMana".equals(sa.getParam("AILogic"))) {
|
||||
for (SpellAbility sa1 : card.getSpellAbilities()) {
|
||||
if ("PoolExtraMana".equals(sa1.getParam("AILogic"))) {
|
||||
hasUntapLandLogic = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return hasUntapLandLogic && card.isUntapped();
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: currently limited to Main 2, somehow improve to let the AI use this SA at other time?
|
||||
|
||||
@@ -197,12 +197,7 @@ public class GameCopier {
|
||||
// TODO update thisTurnCast
|
||||
|
||||
if (advanceToPhase != null) {
|
||||
newGame.getPhaseHandler().devAdvanceToPhase(advanceToPhase, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
GameSimulator.resolveStack(newGame, aiPlayer.getWeakestOpponent());
|
||||
}
|
||||
});
|
||||
newGame.getPhaseHandler().devAdvanceToPhase(advanceToPhase, () -> GameSimulator.resolveStack(newGame, aiPlayer.getWeakestOpponent()));
|
||||
}
|
||||
|
||||
return newGame;
|
||||
|
||||
@@ -252,9 +252,7 @@ public class GameSimulator {
|
||||
// TODO: This needs to set an AI controller for all opponents, in case of multiplayer.
|
||||
PlayerControllerAi sim = new PlayerControllerAi(game, opponent, opponent.getLobbyPlayer());
|
||||
sim.setUseSimulation(true);
|
||||
opponent.runWithController(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
opponent.runWithController(() -> {
|
||||
final Set<Card> allAffectedCards = new HashSet<>();
|
||||
game.getAction().checkStateEffects(false, allAffectedCards);
|
||||
game.getStack().addAllTriggeredAbilitiesToStack();
|
||||
@@ -278,7 +276,6 @@ public class GameSimulator {
|
||||
|
||||
// Continue until stack is empty.
|
||||
}
|
||||
}
|
||||
}, sim);
|
||||
}
|
||||
|
||||
|
||||
@@ -59,12 +59,7 @@ public class GameStateEvaluator {
|
||||
gameCopy = copier.makeCopy(null, aiPlayer);
|
||||
}
|
||||
|
||||
gameCopy.getPhaseHandler().devAdvanceToPhase(PhaseType.COMBAT_DAMAGE, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
GameSimulator.resolveStack(gameCopy, aiPlayer.getWeakestOpponent());
|
||||
}
|
||||
});
|
||||
gameCopy.getPhaseHandler().devAdvanceToPhase(PhaseType.COMBAT_DAMAGE, () -> GameSimulator.resolveStack(gameCopy, aiPlayer.getWeakestOpponent()));
|
||||
CombatSimResult result = new CombatSimResult();
|
||||
result.copier = copier;
|
||||
result.gameCopy = gameCopy;
|
||||
|
||||
@@ -227,15 +227,13 @@ public class CardStorageReader {
|
||||
// Iterate through txt files or zip archive.
|
||||
// Report relevant numbers to progress monitor model.
|
||||
|
||||
final Set<CardRules> result = new TreeSet<>(new Comparator<CardRules>() {
|
||||
@Override
|
||||
public int compare(final CardRules o1, final CardRules o2) {
|
||||
final Set<CardRules> result;
|
||||
if (loadingTokens) {
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(o1.getNormalizedName(), o2.getNormalizedName());
|
||||
result = new TreeSet<>(Comparator.comparing(CardRules::getNormalizedName, String.CASE_INSENSITIVE_ORDER));
|
||||
}
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(o1.getName(), o2.getName());
|
||||
else {
|
||||
result = new TreeSet<>(Comparator.comparing(CardRules::getName, String.CASE_INSENSITIVE_ORDER));
|
||||
}
|
||||
});
|
||||
|
||||
if (loadCardsLazily) {
|
||||
return result;
|
||||
@@ -321,14 +319,11 @@ public class CardStorageReader {
|
||||
for (int iPart = 0; iPart < maxParts; iPart++) {
|
||||
final int from = iPart * filesPerPart;
|
||||
final int till = iPart == maxParts - 1 ? totalFiles : from + filesPerPart;
|
||||
tasks.add(new Callable<List<CardRules>>() {
|
||||
@Override
|
||||
public List<CardRules> call() throws Exception{
|
||||
tasks.add(() -> {
|
||||
final List<CardRules> res = loadCardsInRangeFromZip(entries, from, till);
|
||||
cdl.countDown();
|
||||
progressObserver.report(maxParts - (int)cdl.getCount(), maxParts);
|
||||
return res;
|
||||
}
|
||||
});
|
||||
}
|
||||
return tasks;
|
||||
@@ -342,14 +337,11 @@ public class CardStorageReader {
|
||||
for (int iPart = 0; iPart < maxParts; iPart++) {
|
||||
final int from = iPart * filesPerPart;
|
||||
final int till = iPart == maxParts - 1 ? totalFiles : from + filesPerPart;
|
||||
tasks.add(new Callable<List<CardRules>>() {
|
||||
@Override
|
||||
public List<CardRules> call() throws Exception{
|
||||
tasks.add(() -> {
|
||||
final List<CardRules> res = loadCardsInRange(allFiles, from, till);
|
||||
cdl.countDown();
|
||||
progressObserver.report(maxParts - (int)cdl.getCount(), maxParts);
|
||||
return res;
|
||||
}
|
||||
});
|
||||
}
|
||||
return tasks;
|
||||
|
||||
@@ -633,9 +633,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
cardName = cardNameRequest.cardName;
|
||||
isFoil = isFoil || cardNameRequest.isFoil;
|
||||
|
||||
List<PaperCard> candidates = getAllCards(cardName, new Predicate<PaperCard>() {
|
||||
@Override
|
||||
public boolean apply(PaperCard c) {
|
||||
List<PaperCard> candidates = getAllCards(cardName, c -> {
|
||||
boolean artIndexFilter = true;
|
||||
boolean collectorNumberFilter = true;
|
||||
boolean setFilter = c.getEdition().equalsIgnoreCase(edition.getCode()) ||
|
||||
@@ -646,7 +644,6 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
&& !(collectorNumber.equals(IPaperCard.NO_COLLECTOR_NUMBER)))
|
||||
collectorNumberFilter = (c.getCollectorNumber().equals(collectorNumber));
|
||||
return setFilter && artIndexFilter && collectorNumberFilter;
|
||||
}
|
||||
});
|
||||
if (candidates.isEmpty())
|
||||
return null;
|
||||
@@ -791,9 +788,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
Predicate<PaperCard> cardQueryFilter;
|
||||
filter = (filter != null) ? filter : Predicates.alwaysTrue();
|
||||
if (releaseDate != null) {
|
||||
cardQueryFilter = new Predicate<PaperCard>() {
|
||||
@Override
|
||||
public boolean apply(PaperCard c) {
|
||||
cardQueryFilter = c -> {
|
||||
if (c.getArtIndex() != cr.artIndex)
|
||||
return false; // not interested anyway!
|
||||
CardEdition ed = editions.get(c.getEdition());
|
||||
@@ -802,15 +797,9 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
return ed.getDate().before(releaseDate);
|
||||
else
|
||||
return ed.getDate().after(releaseDate);
|
||||
}
|
||||
};
|
||||
} else // filter candidates based on requested artIndex
|
||||
cardQueryFilter = new Predicate<PaperCard>() {
|
||||
@Override
|
||||
public boolean apply(PaperCard card) {
|
||||
return card.getArtIndex() == cr.artIndex;
|
||||
}
|
||||
};
|
||||
cardQueryFilter = card -> card.getArtIndex() == cr.artIndex;
|
||||
cardQueryFilter = Predicates.and(cardQueryFilter, filter);
|
||||
cards = getAllCards(cr.cardName, cardQueryFilter);
|
||||
// Note: No need to check whether "cards" is empty; the next for loop will validate condition at L699
|
||||
@@ -838,12 +827,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
return null; // nothing to do
|
||||
|
||||
// Filter Cards Editions based on set preferences
|
||||
List<CardEdition> acceptedEditions = Lists.newArrayList(Iterables.filter(cardEditions, new Predicate<CardEdition>() {
|
||||
@Override
|
||||
public boolean apply(CardEdition ed) {
|
||||
return artPref.accept(ed);
|
||||
}
|
||||
}));
|
||||
List<CardEdition> acceptedEditions = Lists.newArrayList(Iterables.filter(cardEditions, artPref::accept));
|
||||
|
||||
/* At this point, it may be possible that Art Preference is too-strict for the requested card!
|
||||
i.e. acceptedEditions.size() == 0!
|
||||
@@ -908,13 +892,10 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
}
|
||||
|
||||
public Collection<PaperCard> getUniqueCardsNoAlt() {
|
||||
return Maps.filterEntries(this.uniqueCardsByName, new Predicate<Entry<String, PaperCard>>() {
|
||||
@Override
|
||||
public boolean apply(Entry<String, PaperCard> e) {
|
||||
return Maps.filterEntries(this.uniqueCardsByName, e -> {
|
||||
if (e == null)
|
||||
return false;
|
||||
return e.getKey().equals(e.getValue().getName());
|
||||
}
|
||||
}).values();
|
||||
}
|
||||
|
||||
@@ -956,18 +937,11 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
}
|
||||
|
||||
public Collection<PaperCard> getAllCardsNoAlt() {
|
||||
return Multimaps.filterEntries(allCardsByName, new Predicate<Entry<String, PaperCard>>() {
|
||||
@Override
|
||||
public boolean apply(Entry<String, PaperCard> entry) {
|
||||
return entry.getKey().equals(entry.getValue().getName());
|
||||
}
|
||||
}).values();
|
||||
return Multimaps.filterEntries(allCardsByName, entry -> entry.getKey().equals(entry.getValue().getName())).values();
|
||||
}
|
||||
|
||||
public Collection<PaperCard> getAllNonPromoCards() {
|
||||
return Lists.newArrayList(Iterables.filter(getAllCards(), new Predicate<PaperCard>() {
|
||||
@Override
|
||||
public boolean apply(final PaperCard paperCard) {
|
||||
return Lists.newArrayList(Iterables.filter(getAllCards(), paperCard -> {
|
||||
CardEdition edition = null;
|
||||
try {
|
||||
edition = editions.getEditionByCodeOrThrow(paperCard.getEdition());
|
||||
@@ -975,14 +949,11 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
return false;
|
||||
}
|
||||
return edition != null && edition.getType() != Type.PROMO;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public Collection<PaperCard> getUniqueCardsNoAltNoOnline() {
|
||||
return Lists.newArrayList(Iterables.filter(getUniqueCardsNoAlt(), new Predicate<PaperCard>() {
|
||||
@Override
|
||||
public boolean apply(final PaperCard paperCard) {
|
||||
return Lists.newArrayList(Iterables.filter(getUniqueCardsNoAlt(), paperCard -> {
|
||||
CardEdition edition = null;
|
||||
try {
|
||||
edition = editions.getEditionByCodeOrThrow(paperCard.getEdition());
|
||||
@@ -992,14 +963,11 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public Collection<PaperCard> getAllNonPromosNonReprintsNoAlt() {
|
||||
return Lists.newArrayList(Iterables.filter(getAllCardsNoAlt(), new Predicate<PaperCard>() {
|
||||
@Override
|
||||
public boolean apply(final PaperCard paperCard) {
|
||||
return Lists.newArrayList(Iterables.filter(getAllCardsNoAlt(), paperCard -> {
|
||||
CardEdition edition = null;
|
||||
try {
|
||||
edition = editions.getEditionByCodeOrThrow(paperCard.getEdition());
|
||||
@@ -1009,7 +977,6 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -1032,12 +999,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
}
|
||||
|
||||
public List<PaperCard> getAllCardsNoAlt(String cardName) {
|
||||
return Lists.newArrayList(Multimaps.filterEntries(allCardsByName, new Predicate<Entry<String, PaperCard>>() {
|
||||
@Override
|
||||
public boolean apply(Entry<String, PaperCard> entry) {
|
||||
return entry.getKey().equals(entry.getValue().getName());
|
||||
}
|
||||
}).get(getName(cardName)));
|
||||
return Lists.newArrayList(Multimaps.filterEntries(allCardsByName, entry -> entry.getKey().equals(entry.getValue().getName())).get(getName(cardName)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
package forge.card;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.*;
|
||||
import forge.StaticData;
|
||||
@@ -423,13 +422,6 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
|
||||
public Map<String, Integer> getTokens() { return tokenNormalized; }
|
||||
|
||||
public static final Function<CardEdition, String> FN_GET_CODE = new Function<CardEdition, String>() {
|
||||
@Override
|
||||
public String apply(final CardEdition arg1) {
|
||||
return arg1.getCode();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int compareTo(final CardEdition o) {
|
||||
if (o == null) {
|
||||
@@ -542,12 +534,12 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
private final boolean isCustomEditions;
|
||||
|
||||
public Reader(File path) {
|
||||
super(path, CardEdition.FN_GET_CODE);
|
||||
super(path, CardEdition::getCode);
|
||||
this.isCustomEditions = false;
|
||||
}
|
||||
|
||||
public Reader(File path, boolean isCustomEditions) {
|
||||
super(path, CardEdition.FN_GET_CODE);
|
||||
super(path, CardEdition::getCode);
|
||||
this.isCustomEditions = isCustomEditions;
|
||||
}
|
||||
|
||||
@@ -737,12 +729,7 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
return TXT_FILE_FILTER;
|
||||
}
|
||||
|
||||
public static final FilenameFilter TXT_FILE_FILTER = new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(final File dir, final String name) {
|
||||
return name.endsWith(".txt");
|
||||
}
|
||||
};
|
||||
public static final FilenameFilter TXT_FILE_FILTER = (dir, name) -> name.endsWith(".txt");
|
||||
}
|
||||
|
||||
public static class Collection extends StorageBase<CardEdition> {
|
||||
@@ -798,12 +785,7 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
|
||||
public Iterable<CardEdition> getPrereleaseEditions() {
|
||||
List<CardEdition> res = Lists.newArrayList(this);
|
||||
return Iterables.filter(res, new Predicate<CardEdition>() {
|
||||
@Override
|
||||
public boolean apply(final CardEdition edition) {
|
||||
return edition.getPrerelease() != null;
|
||||
}
|
||||
});
|
||||
return Iterables.filter(res, edition -> edition.getPrerelease() != null);
|
||||
}
|
||||
|
||||
public CardEdition getEditionByCodeOrThrow(final String code) {
|
||||
@@ -822,19 +804,7 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
return set == null ? "" : set.getCode2();
|
||||
}
|
||||
|
||||
public final Function<String, CardEdition> FN_EDITION_BY_CODE = new Function<String, CardEdition>() {
|
||||
@Override
|
||||
public CardEdition apply(String code) {
|
||||
return Collection.this.get(code);
|
||||
}
|
||||
};
|
||||
|
||||
public final Comparator<PaperCard> CARD_EDITION_COMPARATOR = new Comparator<PaperCard>() {
|
||||
@Override
|
||||
public int compare(PaperCard c1, PaperCard c2) {
|
||||
return Collection.this.get(c1.getEdition()).compareTo(Collection.this.get(c2.getEdition()));
|
||||
}
|
||||
};
|
||||
public final Comparator<PaperCard> CARD_EDITION_COMPARATOR = Comparator.comparing(c -> Collection.this.get(c.getEdition()));
|
||||
|
||||
public IItemReader<SealedProduct.Template> getBoosterGenerator() {
|
||||
return new StorageReaderBase<SealedProduct.Template>(null) {
|
||||
@@ -913,12 +883,7 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
CardDb.CardArtPreference artPreference = StaticData.instance().getCardArtPreference();
|
||||
Iterable<CardEdition> editionsWithBasicLands = Iterables.filter(
|
||||
StaticData.instance().getEditions().getOrderedEditions(),
|
||||
com.google.common.base.Predicates.and(hasBasicLands, new Predicate<CardEdition>() {
|
||||
@Override
|
||||
public boolean apply(CardEdition edition) {
|
||||
return artPreference.accept(edition);
|
||||
}
|
||||
}));
|
||||
com.google.common.base.Predicates.and(hasBasicLands, artPreference::accept));
|
||||
Iterator<CardEdition> editionsIterator = editionsWithBasicLands.iterator();
|
||||
List<CardEdition> selectedEditions = new ArrayList<CardEdition>();
|
||||
while (editionsIterator.hasNext())
|
||||
@@ -954,9 +919,7 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
}
|
||||
}
|
||||
|
||||
public static final Predicate<CardEdition> hasBasicLands = new Predicate<CardEdition>() {
|
||||
@Override
|
||||
public boolean apply(CardEdition ed) {
|
||||
public static final Predicate<CardEdition> hasBasicLands = ed -> {
|
||||
if (ed == null) {
|
||||
// Happens for new sets with "???" code
|
||||
return false;
|
||||
@@ -966,7 +929,6 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -243,7 +243,7 @@ final class CardFace implements ICardFace, Cloneable {
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public final Object clone() {
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch (final Exception ex) {
|
||||
|
||||
@@ -67,12 +67,9 @@ public final class CardFacePredicates {
|
||||
}
|
||||
|
||||
public static Predicate<ICardFace> cmc(final int value) {
|
||||
return new Predicate<ICardFace>() {
|
||||
@Override
|
||||
public boolean apply(ICardFace input) {
|
||||
return input -> {
|
||||
ManaCost cost = input.getManaCost();
|
||||
return cost != null && cost.getCMC() == value;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -138,20 +135,10 @@ public final class CardFacePredicates {
|
||||
|
||||
public static class Presets {
|
||||
/** The Constant isBasicLand. */
|
||||
public static final Predicate<ICardFace> IS_BASIC_LAND = new Predicate<ICardFace>() {
|
||||
@Override
|
||||
public boolean apply(final ICardFace subject) {
|
||||
return 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 = new Predicate<ICardFace>() {
|
||||
@Override
|
||||
public boolean apply(final ICardFace subject) {
|
||||
return subject.getType().isLand() && !subject.getType().isBasicLand();
|
||||
}
|
||||
};
|
||||
public static final Predicate<ICardFace> IS_NONBASIC_LAND = subject -> subject.getType().isLand() && !subject.getType().isBasicLand();
|
||||
|
||||
/** The Constant isCreature. */
|
||||
public static final Predicate<ICardFace> IS_CREATURE = CardFacePredicates
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
*/
|
||||
package forge.card;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
public enum CardRarity {
|
||||
BasicLand("L", "Basic Land"),
|
||||
Common("C", "Common"),
|
||||
@@ -58,10 +56,4 @@ public enum CardRarity {
|
||||
return Unknown;
|
||||
}
|
||||
|
||||
public static final Function<CardRarity, String> FN_GET_LONG_NAME = new Function<CardRarity, String>() {
|
||||
@Override
|
||||
public String apply(final CardRarity rarity) {
|
||||
return rarity.longName;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package forge.card;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@@ -21,28 +19,13 @@ import forge.util.PredicateString;
|
||||
public final class CardRulesPredicates {
|
||||
|
||||
/** The Constant isKeptInAiDecks. */
|
||||
public static final Predicate<CardRules> IS_KEPT_IN_AI_DECKS = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules card) {
|
||||
return !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 = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules card) {
|
||||
return !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 = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules card) {
|
||||
return !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
|
||||
/**
|
||||
@@ -160,19 +143,9 @@ public final class CardRulesPredicates {
|
||||
}
|
||||
|
||||
public static Predicate<CardRules> hasCreatureType(final String... creatureTypes) {
|
||||
return new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules card) {
|
||||
return card -> {
|
||||
if (!card.getType().isCreature()) { return false; }
|
||||
|
||||
final Set<String> set = card.getType().getCreatureTypes();
|
||||
for (final String creatureType : creatureTypes) {
|
||||
if (set.contains(creatureType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return !Collections.disjoint(card.getType().getCreatureTypes(), Arrays.asList(creatureTypes));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -184,12 +157,7 @@ public final class CardRulesPredicates {
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> hasKeyword(final String keyword) {
|
||||
return new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules card) {
|
||||
return Iterables.any(card.getAllFaces(), cf -> cf != null && card.hasStartOfKeyword(keyword, cf));
|
||||
}
|
||||
};
|
||||
return card -> Iterables.any(card.getAllFaces(), cf -> cf != null && card.hasStartOfKeyword(keyword, cf));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -202,22 +170,16 @@ public final class CardRulesPredicates {
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> deckHas(final DeckHints.Type type, final String has) {
|
||||
return new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules card) {
|
||||
return card -> {
|
||||
DeckHints deckHas = card.getAiHints().getDeckHas();
|
||||
return deckHas != null && deckHas.isValid() && deckHas.contains(type, has);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Predicate<CardRules> deckHasExactly(final DeckHints.Type type, final String has[]) {
|
||||
return new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules card) {
|
||||
return card -> {
|
||||
DeckHints deckHas = card.getAiHints().getDeckHas();
|
||||
return deckHas != null && deckHas.isValid() && deckHas.is(type, has);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -348,12 +310,7 @@ public final class CardRulesPredicates {
|
||||
}
|
||||
|
||||
public static Predicate<CardRules> hasColorIdentity(final int colormask) {
|
||||
return new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules rules) {
|
||||
return rules.getColorIdentity().hasNoColorsExcept(colormask);
|
||||
}
|
||||
};
|
||||
return rules -> rules.getColorIdentity().hasNoColorsExcept(colormask);
|
||||
}
|
||||
|
||||
public static Predicate<CardRules> canBePartnerCommanderWith(final CardRules commander) {
|
||||
@@ -597,54 +554,19 @@ public final class CardRulesPredicates {
|
||||
public static final Predicate<CardRules> IS_LAND = CardRulesPredicates.coreType(true, CardType.CoreType.Land);
|
||||
|
||||
/** The Constant isBasicLand. */
|
||||
public static final Predicate<CardRules> IS_BASIC_LAND = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules subject) {
|
||||
return subject.getType().isBasicLand();
|
||||
}
|
||||
};
|
||||
public static final Predicate<CardRules> IS_BASIC_LAND = subject -> subject.getType().isBasicLand();
|
||||
|
||||
/** The Constant isBasicLandNotWastes. */
|
||||
public static final Predicate<CardRules> IS_BASIC_LAND_NOT_WASTES = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules subject) {
|
||||
return !subject.getName().equals("Wastes")&&subject.getType().isBasicLand();
|
||||
}
|
||||
};
|
||||
public static final Predicate<CardRules> IS_BASIC_LAND_NOT_WASTES = subject -> !subject.getName().equals("Wastes")&&subject.getType().isBasicLand();
|
||||
|
||||
/** The Constant isNonBasicLand. */
|
||||
public static final Predicate<CardRules> IS_NONBASIC_LAND = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules subject) {
|
||||
return 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 = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules subject) {
|
||||
return subject.canBeCommander();
|
||||
}
|
||||
};
|
||||
public static final Predicate<CardRules> CAN_BE_PARTNER_COMMANDER = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules subject) {
|
||||
return subject.canBePartnerCommander();
|
||||
}
|
||||
};
|
||||
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_OATHBREAKER = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules subject) {
|
||||
return subject.canBeOathbreaker();
|
||||
}
|
||||
};
|
||||
public static final Predicate<CardRules> CAN_BE_SIGNATURE_SPELL = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules subject) {
|
||||
return subject.canBeSignatureSpell();
|
||||
}
|
||||
};
|
||||
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> IS_PLANESWALKER = CardRulesPredicates.coreType(true, CardType.CoreType.Planeswalker);
|
||||
public static final Predicate<CardRules> IS_BATTLE = CardRulesPredicates.coreType(true, CardType.CoreType.Battle);
|
||||
|
||||
@@ -493,13 +493,13 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isAttachment() { return isAura() || isEquipment() || isFortification(); }
|
||||
public boolean isAttachment() { return isAura() || isEquipment() || isFortification(); }
|
||||
@Override
|
||||
public final boolean isAura() { return hasSubtype("Aura"); }
|
||||
public boolean isAura() { return hasSubtype("Aura"); }
|
||||
@Override
|
||||
public final boolean isEquipment() { return hasSubtype("Equipment"); }
|
||||
public boolean isEquipment() { return hasSubtype("Equipment"); }
|
||||
@Override
|
||||
public final boolean isFortification() { return hasSubtype("Fortification"); }
|
||||
public boolean isFortification() { return hasSubtype("Fortification"); }
|
||||
public boolean isAttraction() {
|
||||
return hasSubtype("Attraction");
|
||||
}
|
||||
@@ -858,71 +858,21 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
|
||||
"Warlock");
|
||||
}
|
||||
public static class Predicates {
|
||||
public static Predicate<String> IS_LAND_TYPE = new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(String input) {
|
||||
return CardType.isALandType(input);
|
||||
}
|
||||
};
|
||||
public static Predicate<String> IS_BASIC_LAND_TYPE = new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(String input) {
|
||||
return CardType.isABasicLandType(input);
|
||||
}
|
||||
};
|
||||
public static Predicate<String> IS_ARTIFACT_TYPE = new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(String input) {
|
||||
return CardType.isAnArtifactType(input);
|
||||
}
|
||||
};
|
||||
public static Predicate<String> IS_LAND_TYPE = CardType::isALandType;
|
||||
public static Predicate<String> IS_BASIC_LAND_TYPE = CardType::isABasicLandType;
|
||||
public static Predicate<String> IS_ARTIFACT_TYPE = CardType::isAnArtifactType;
|
||||
|
||||
public static Predicate<String> IS_CREATURE_TYPE = new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(String input) {
|
||||
return CardType.isACreatureType(input);
|
||||
}
|
||||
};
|
||||
public static Predicate<String> IS_CREATURE_TYPE = CardType::isACreatureType;
|
||||
|
||||
public static Predicate<String> IS_ENCHANTMENT_TYPE = new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(String input) {
|
||||
return CardType.isAnEnchantmentType(input);
|
||||
}
|
||||
};
|
||||
public static Predicate<String> IS_ENCHANTMENT_TYPE = CardType::isAnEnchantmentType;
|
||||
|
||||
public static Predicate<String> IS_SPELL_TYPE = new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(String input) {
|
||||
return CardType.isASpellType(input);
|
||||
}
|
||||
};
|
||||
public static Predicate<String> IS_SPELL_TYPE = CardType::isASpellType;
|
||||
|
||||
public static Predicate<String> IS_WALKER_TYPE = new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(String input) {
|
||||
return CardType.isAPlaneswalkerType(input);
|
||||
}
|
||||
};
|
||||
public static Predicate<String> IS_DUNGEON_TYPE = new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(String input) {
|
||||
return CardType.isADungeonType(input);
|
||||
}
|
||||
};
|
||||
public static Predicate<String> IS_BATTLE_TYPE = new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(String input) {
|
||||
return CardType.isABattleType(input);
|
||||
}
|
||||
};
|
||||
public static Predicate<String> IS_WALKER_TYPE = CardType::isAPlaneswalkerType;
|
||||
public static Predicate<String> IS_DUNGEON_TYPE = CardType::isADungeonType;
|
||||
public static Predicate<String> IS_BATTLE_TYPE = CardType::isABattleType;
|
||||
|
||||
public static Predicate<String> IS_PLANAR_TYPE = new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(String input) {
|
||||
return CardType.isAPlanarType(input);
|
||||
}
|
||||
};
|
||||
public static Predicate<String> IS_PLANAR_TYPE = CardType::isAPlanarType;
|
||||
}
|
||||
|
||||
///////// Utility methods
|
||||
@@ -1036,7 +986,7 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public static final String getSingularType(final String type) {
|
||||
public static String getSingularType(final String type) {
|
||||
if (Constant.singularTypes.containsKey(type)) {
|
||||
return Constant.singularTypes.get(type);
|
||||
}
|
||||
@@ -1049,7 +999,7 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
|
||||
* @param type a String.
|
||||
* @return the corresponding type.
|
||||
*/
|
||||
public static final String getPluralType(final String type) {
|
||||
public static String getPluralType(final String type) {
|
||||
if (Constant.pluralTypes.containsKey(type)) {
|
||||
return Constant.pluralTypes.get(type);
|
||||
}
|
||||
|
||||
@@ -172,11 +172,11 @@ public class DeckHints {
|
||||
// this is case ABILITY, but other types can also use this when the implicit parsing would miss
|
||||
String[] params = param.split("\\|");
|
||||
for (String ability : params) {
|
||||
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.deckHas(type, ability), PaperCard.FN_GET_RULES));
|
||||
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.deckHas(type, ability), PaperCard::getRules));
|
||||
}
|
||||
// bonus if a DeckHas can satisfy the type with multiple ones
|
||||
if (params.length > 1) {
|
||||
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.deckHasExactly(type, params), PaperCard.FN_GET_RULES));
|
||||
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.deckHasExactly(type, params), PaperCard::getRules));
|
||||
}
|
||||
|
||||
for (String p : params) {
|
||||
@@ -184,19 +184,19 @@ public class DeckHints {
|
||||
case COLOR:
|
||||
ColorSet cc = ColorSet.fromNames(p);
|
||||
if (cc.isColorless()) {
|
||||
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.Presets.IS_COLORLESS, PaperCard.FN_GET_RULES));
|
||||
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.Presets.IS_COLORLESS, PaperCard::getRules));
|
||||
} else {
|
||||
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.isColor(cc.getColor()), PaperCard.FN_GET_RULES));
|
||||
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.isColor(cc.getColor()), PaperCard::getRules));
|
||||
}
|
||||
break;
|
||||
case KEYWORD:
|
||||
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.hasKeyword(p), PaperCard.FN_GET_RULES));
|
||||
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.hasKeyword(p), PaperCard::getRules));
|
||||
break;
|
||||
case NAME:
|
||||
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.name(StringOp.EQUALS, p), PaperCard.FN_GET_RULES));
|
||||
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.name(StringOp.EQUALS, p), PaperCard::getRules));
|
||||
break;
|
||||
case TYPE:
|
||||
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.joinedType(StringOp.CONTAINS_IC, p), PaperCard.FN_GET_RULES));
|
||||
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.joinedType(StringOp.CONTAINS_IC, p), PaperCard::getRules));
|
||||
break;
|
||||
case NONE:
|
||||
case ABILITY: // already done above
|
||||
@@ -219,9 +219,7 @@ public class DeckHints {
|
||||
} else {
|
||||
tdb = null;
|
||||
}
|
||||
return new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules card) {
|
||||
return card -> {
|
||||
if (predicate.apply(card)) {
|
||||
return true;
|
||||
}
|
||||
@@ -231,7 +229,6 @@ public class DeckHints {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package forge.card;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
@@ -181,10 +180,4 @@ public final class MagicColor {
|
||||
}
|
||||
}
|
||||
|
||||
public static final Function<Color, String> FN_GET_SYMBOL = new Function<Color, String>() {
|
||||
@Override
|
||||
public String apply(final Color color) {
|
||||
return color.symbol;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.deck.CardPool;
|
||||
import forge.item.PaperCard;
|
||||
import forge.util.ItemPool;
|
||||
@@ -22,9 +20,6 @@ import forge.util.storage.StorageReaderFileSections;
|
||||
*
|
||||
*/
|
||||
public class PrintSheet {
|
||||
public static final Function<PrintSheet, String> FN_GET_KEY = new Function<PrintSheet, String>() {
|
||||
@Override public final String apply(PrintSheet sheet) { return sheet.name; }
|
||||
};
|
||||
|
||||
public static final IStorage<PrintSheet> initializePrintSheets(File sheetsFile, CardEdition.Collection editions) {
|
||||
IStorage<PrintSheet> sheets = new StorageExtendable<>("Special print runs", new PrintSheet.Reader(sheetsFile));
|
||||
@@ -156,7 +151,7 @@ public class PrintSheet {
|
||||
|
||||
public static class Reader extends StorageReaderFileSections<PrintSheet> {
|
||||
public Reader(File file) {
|
||||
super(file, PrintSheet.FN_GET_KEY);
|
||||
super(file, PrintSheet::getName);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -318,12 +318,7 @@ public class CardPool extends ItemPool<PaperCard> {
|
||||
ListMultimap<Integer, CardEdition> editionsStatistics = this.getCardEditionsGroupedByNumberOfCards(false);
|
||||
List<Integer> frequencyValues = new ArrayList<>(editionsStatistics.keySet());
|
||||
// Sort in descending order
|
||||
frequencyValues.sort(new Comparator<Integer>() {
|
||||
@Override
|
||||
public int compare(Integer f1, Integer f2) {
|
||||
return (f1.compareTo(f2)) * -1;
|
||||
}
|
||||
});
|
||||
frequencyValues.sort(Comparator.reverseOrder());
|
||||
float weightedMean = 0;
|
||||
int sumWeights = 0;
|
||||
for (Integer freq : frequencyValues) {
|
||||
@@ -351,12 +346,7 @@ public class CardPool extends ItemPool<PaperCard> {
|
||||
// Now Get editions corresponding to pivot frequency
|
||||
List<CardEdition> pivotCandidates = new ArrayList<>(editionsStatistics.get(pivotFrequency));
|
||||
// Now Sort candidates chronologically
|
||||
pivotCandidates.sort(new Comparator<CardEdition>() {
|
||||
@Override
|
||||
public int compare(CardEdition ed1, CardEdition ed2) {
|
||||
return ed1.compareTo(ed2);
|
||||
}
|
||||
});
|
||||
pivotCandidates.sort(CardEdition::compareTo);
|
||||
boolean searchPolicyAndPoolAreCompliant = isLatestCardArtPreference == this.isModern();
|
||||
if (!searchPolicyAndPoolAreCompliant)
|
||||
Collections.reverse(pivotCandidates); // reverse to have latest-first.
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
*/
|
||||
package forge.deck;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Lists;
|
||||
import forge.StaticData;
|
||||
import forge.card.CardDb;
|
||||
@@ -125,12 +123,7 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
|
||||
result.add(c.getKey());
|
||||
}
|
||||
if (result.size() > 1) { //sort by type so signature spell comes after oathbreaker
|
||||
Collections.sort(result, new Comparator<PaperCard>() {
|
||||
@Override
|
||||
public int compare(final PaperCard c1, final PaperCard c2) {
|
||||
return Boolean.compare(c1.getRules().canBeSignatureSpell(), c2.getRules().canBeSignatureSpell());
|
||||
}
|
||||
});
|
||||
Collections.sort(result, Comparator.comparing(c -> c.getRules().canBeSignatureSpell()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -309,12 +302,7 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
|
||||
continue; // pool empty, no card has been found!
|
||||
|
||||
// Filter pool by applying DeckSection Validation schema for Card Types (to avoid inconsistencies)
|
||||
CardPool filteredPool = pool.getFilteredPoolWithCardsCount(new Predicate<PaperCard>() {
|
||||
@Override
|
||||
public boolean apply(PaperCard input) {
|
||||
return deckSection.validate(input);
|
||||
}
|
||||
});
|
||||
CardPool filteredPool = pool.getFilteredPoolWithCardsCount(deckSection::validate);
|
||||
// Add all the cards from ValidPool anyway!
|
||||
List<String> whiteList = validatedSections.getOrDefault(s.getKey(), null);
|
||||
if (whiteList == null)
|
||||
@@ -326,12 +314,7 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
|
||||
validatedSections.put(s.getKey(), whiteList);
|
||||
|
||||
if (filteredPool.countDistinct() != pool.countDistinct()) {
|
||||
CardPool blackList = pool.getFilteredPoolWithCardsCount(new Predicate<PaperCard>() {
|
||||
@Override
|
||||
public boolean apply(PaperCard input) {
|
||||
return !(deckSection.validate(input));
|
||||
}
|
||||
});
|
||||
CardPool blackList = pool.getFilteredPoolWithCardsCount(input -> !(deckSection.validate(input)));
|
||||
|
||||
for (Entry<PaperCard, Integer> entry : blackList) {
|
||||
DeckSection cardSection = DeckSection.matchingSection(entry.getKey());
|
||||
@@ -513,13 +496,6 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
|
||||
return releaseDate.compareTo(referenceReleaseDate) < 0;
|
||||
}
|
||||
|
||||
public static final Function<Deck, String> FN_NAME_SELECTOR = new Function<Deck, String>() {
|
||||
@Override
|
||||
public String apply(Deck arg1) {
|
||||
return arg1.getName();
|
||||
}
|
||||
};
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
|
||||
@@ -59,25 +59,16 @@ public enum DeckFormat {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
Commander ( Range.is(99), Range.between(0, 10), 1, null, new Predicate<PaperCard>() {
|
||||
@Override
|
||||
public boolean apply(PaperCard card) {
|
||||
return StaticData.instance().getCommanderPredicate().apply(card);
|
||||
}
|
||||
}),
|
||||
Oathbreaker ( Range.is(58), Range.between(0, 10), 1, null, new Predicate<PaperCard>() {
|
||||
@Override
|
||||
public boolean apply(PaperCard card) {
|
||||
return StaticData.instance().getOathbreakerPredicate().apply(card);
|
||||
}
|
||||
}),
|
||||
Commander ( Range.is(99), Range.between(0, 10), 1, null,
|
||||
card -> StaticData.instance().getCommanderPredicate().apply(card)
|
||||
),
|
||||
Oathbreaker ( Range.is(58), Range.between(0, 10), 1, null,
|
||||
card -> StaticData.instance().getOathbreakerPredicate().apply(card)
|
||||
),
|
||||
Pauper ( Range.is(60), Range.between(0, 10), 1),
|
||||
Brawl ( Range.is(59), Range.between(0, 15), 1, null, new Predicate<PaperCard>() {
|
||||
@Override
|
||||
public boolean apply(PaperCard card) {
|
||||
return StaticData.instance().getBrawlPredicate().apply(card);
|
||||
}
|
||||
}),
|
||||
Brawl ( Range.is(59), Range.between(0, 15), 1, null,
|
||||
card -> StaticData.instance().getBrawlPredicate().apply(card)
|
||||
),
|
||||
TinyLeaders ( Range.is(49), Range.between(0, 10), 1, new Predicate<CardRules>() {
|
||||
private final Set<String> bannedCards = ImmutableSet.of(
|
||||
"Ancestral Recall", "Balance", "Black Lotus", "Black Vise", "Channel", "Chaos Orb", "Contract From Below", "Counterbalance", "Darkpact", "Demonic Attorney", "Demonic Tutor", "Earthcraft", "Edric, Spymaster of Trest", "Falling Star",
|
||||
@@ -501,18 +492,11 @@ public enum DeckFormat {
|
||||
}
|
||||
|
||||
public Predicate<Deck> isLegalDeckPredicate() {
|
||||
return new Predicate<Deck>() {
|
||||
@Override
|
||||
public boolean apply(Deck deck) {
|
||||
return getDeckConformanceProblem(deck) == null;
|
||||
}
|
||||
};
|
||||
return deck -> getDeckConformanceProblem(deck) == null;
|
||||
}
|
||||
|
||||
public Predicate<Deck> hasLegalCardsPredicate(boolean enforceDeckLegality) {
|
||||
return new Predicate<Deck>() {
|
||||
@Override
|
||||
public boolean apply(Deck deck) {
|
||||
return deck -> {
|
||||
if (!enforceDeckLegality)
|
||||
return true;
|
||||
if (cardPoolFilter != null) {
|
||||
@@ -534,26 +518,15 @@ public enum DeckFormat {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Predicate<PaperCard> isLegalCardPredicate() {
|
||||
return new Predicate<PaperCard>() {
|
||||
@Override
|
||||
public boolean apply(PaperCard card) {
|
||||
return isLegalCard(card);
|
||||
}
|
||||
};
|
||||
return this::isLegalCard;
|
||||
}
|
||||
|
||||
public Predicate<PaperCard> isLegalCommanderPredicate() {
|
||||
return new Predicate<PaperCard>() {
|
||||
@Override
|
||||
public boolean apply(PaperCard card) {
|
||||
return isLegalCommander(card.getRules());
|
||||
}
|
||||
};
|
||||
return card -> isLegalCommander(card.getRules());
|
||||
}
|
||||
|
||||
public Predicate<PaperCard> isLegalCardForCommanderPredicate(List<PaperCard> commanders) {
|
||||
@@ -567,6 +540,6 @@ public enum DeckFormat {
|
||||
//Notably, no partner ability or combination of partner abilities can ever let a player have more than two commanders.
|
||||
predicate = Predicates.or(predicate, CardRulesPredicates.canBePartnerCommanderWith(commanders.get(0).getRules()));
|
||||
}
|
||||
return Predicates.compose(predicate, PaperCard.FN_GET_RULES);
|
||||
return Predicates.compose(predicate, PaperCard::getRules);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@ import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* Related decks usually pertaining to a limited experience like draft or sealed
|
||||
* This file represents a human player deck and all opposing AI decks
|
||||
@@ -32,6 +30,10 @@ import com.google.common.base.Function;
|
||||
*/
|
||||
public class DeckGroup extends DeckBase {
|
||||
|
||||
public DeckGroup() {
|
||||
this("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new deck group.
|
||||
*
|
||||
@@ -137,21 +139,6 @@ public class DeckGroup extends DeckBase {
|
||||
return new DeckGroup(name0);
|
||||
}
|
||||
|
||||
public static final Function<DeckGroup, String> FN_NAME_SELECTOR = new Function<DeckGroup, String>() {
|
||||
@Override
|
||||
public String apply(DeckGroup arg1) {
|
||||
return arg1.getName();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public static final Function<DeckGroup, Deck> FN_HUMAN_DECK = new Function<DeckGroup, Deck>() {
|
||||
@Override
|
||||
public Deck apply(DeckGroup arg1) {
|
||||
return arg1.humanDeck;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return humanDeck == null || humanDeck.isEmpty();
|
||||
|
||||
@@ -66,63 +66,42 @@ public enum DeckSection {
|
||||
}
|
||||
|
||||
private static class Validators {
|
||||
static final Function<PaperCard, Boolean> DECK_AND_SIDE_VALIDATOR = new Function<PaperCard, Boolean>() {
|
||||
@Override
|
||||
public Boolean apply(PaperCard card) {
|
||||
static final Function<PaperCard, Boolean> DECK_AND_SIDE_VALIDATOR = card -> {
|
||||
CardType t = card.getRules().getType();
|
||||
// NOTE: Same rules applies to both Deck and Side, despite "Conspiracy cards" are allowed
|
||||
// in the SideBoard (see Rule 313.2)
|
||||
// Those will be matched later, in case (see `Deck::validateDeferredSections`)
|
||||
return !t.isConspiracy() && !t.isDungeon() && !t.isPhenomenon() && !t.isPlane() && !t.isScheme() && !t.isVanguard();
|
||||
}
|
||||
};
|
||||
|
||||
static final Function<PaperCard, Boolean> COMMANDER_VALIDATOR = new Function<PaperCard, Boolean>() {
|
||||
@Override
|
||||
public Boolean apply(PaperCard card) {
|
||||
static final Function<PaperCard, Boolean> COMMANDER_VALIDATOR = card -> {
|
||||
CardType t = card.getRules().getType();
|
||||
return card.getRules().canBeCommander() || t.isPlaneswalker() || card.getRules().canBeOathbreaker() || card.getRules().canBeSignatureSpell();
|
||||
}
|
||||
};
|
||||
|
||||
static final Function<PaperCard, Boolean> PLANES_VALIDATOR = new Function<PaperCard, Boolean>() {
|
||||
@Override
|
||||
public Boolean apply(PaperCard card) {
|
||||
static final Function<PaperCard, Boolean> PLANES_VALIDATOR = card -> {
|
||||
CardType t = card.getRules().getType();
|
||||
return t.isPlane() || t.isPhenomenon();
|
||||
}
|
||||
};
|
||||
|
||||
static final Function<PaperCard, Boolean> DUNGEON_VALIDATOR = new Function<PaperCard, Boolean>() {
|
||||
@Override
|
||||
public Boolean apply(PaperCard card) {
|
||||
static final Function<PaperCard, Boolean> DUNGEON_VALIDATOR = card -> {
|
||||
CardType t = card.getRules().getType();
|
||||
return t.isDungeon();
|
||||
}
|
||||
};
|
||||
|
||||
static final Function<PaperCard, Boolean> SCHEME_VALIDATOR = new Function<PaperCard, Boolean>() {
|
||||
@Override
|
||||
public Boolean apply(PaperCard card) {
|
||||
static final Function<PaperCard, Boolean> SCHEME_VALIDATOR = card -> {
|
||||
CardType t = card.getRules().getType();
|
||||
return t.isScheme();
|
||||
}
|
||||
};
|
||||
|
||||
static final Function<PaperCard, Boolean> CONSPIRACY_VALIDATOR = new Function<PaperCard, Boolean>() {
|
||||
@Override
|
||||
public Boolean apply(PaperCard card) {
|
||||
static final Function<PaperCard, Boolean> CONSPIRACY_VALIDATOR = card -> {
|
||||
CardType t = card.getRules().getType();
|
||||
return t.isConspiracy();
|
||||
}
|
||||
};
|
||||
|
||||
static final Function<PaperCard, Boolean> AVATAR_VALIDATOR = new Function<PaperCard, Boolean>() {
|
||||
@Override
|
||||
public Boolean apply(PaperCard card) {
|
||||
static final Function<PaperCard, Boolean> AVATAR_VALIDATOR = card -> {
|
||||
CardType t = card.getRules().getType();
|
||||
return t.isVanguard();
|
||||
}
|
||||
};
|
||||
|
||||
static final Function<PaperCard, Boolean> ATTRACTION_VALIDATOR = card -> {
|
||||
|
||||
@@ -92,12 +92,12 @@ public abstract class DeckGeneratorBase {
|
||||
final Iterable<PaperCard> cards = selectCardsOfMatchingColorForPlayer(forAi);
|
||||
// build subsets based on type
|
||||
|
||||
final Iterable<PaperCard> creatures = Iterables.filter(cards, Predicates.compose(CardRulesPredicates.Presets.IS_CREATURE, PaperCard.FN_GET_RULES));
|
||||
final Iterable<PaperCard> creatures = Iterables.filter(cards, Predicates.compose(CardRulesPredicates.Presets.IS_CREATURE, PaperCard::getRules));
|
||||
final int creatCnt = (int) Math.ceil(getCreaturePercentage() * size);
|
||||
trace.append("Creatures to add:").append(creatCnt).append("\n");
|
||||
addCmcAdjusted(creatures, creatCnt, cmcLevels);
|
||||
|
||||
Predicate<PaperCard> preSpells = Predicates.compose(CardRulesPredicates.Presets.IS_NON_CREATURE_SPELL, PaperCard.FN_GET_RULES);
|
||||
Predicate<PaperCard> preSpells = Predicates.compose(CardRulesPredicates.Presets.IS_NON_CREATURE_SPELL, PaperCard::getRules);
|
||||
final Iterable<PaperCard> spells = Iterables.filter(cards, preSpells);
|
||||
final int spellCnt = (int) Math.ceil(getSpellPercentage() * size);
|
||||
trace.append("Spells to add:").append(spellCnt).append("\n");
|
||||
@@ -114,9 +114,9 @@ public abstract class DeckGeneratorBase {
|
||||
Predicate<PaperCard> isSetBasicLand;
|
||||
if (edition !=null){
|
||||
isSetBasicLand = Predicates.and(IPaperCard.Predicates.printedInSet(edition),
|
||||
Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard.FN_GET_RULES));
|
||||
Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard::getRules));
|
||||
}else{
|
||||
isSetBasicLand = Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard.FN_GET_RULES);
|
||||
isSetBasicLand = Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard::getRules);
|
||||
}
|
||||
|
||||
landPool = new DeckGenPool(StaticData.instance().getCommonCards().getAllCards(isSetBasicLand));
|
||||
@@ -239,7 +239,7 @@ public abstract class DeckGeneratorBase {
|
||||
addSome(targetSize - actualSize, tDeck.toFlatList());
|
||||
}
|
||||
else if (actualSize > targetSize) {
|
||||
Predicate<PaperCard> exceptBasicLand = Predicates.not(Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard.FN_GET_RULES));
|
||||
Predicate<PaperCard> exceptBasicLand = Predicates.not(Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard::getRules));
|
||||
|
||||
for (int i = 0; i < 3 && actualSize > targetSize; i++) {
|
||||
Iterable<PaperCard> matchingCards = Iterables.filter(tDeck.toFlatList(), exceptBasicLand);
|
||||
@@ -266,7 +266,7 @@ public abstract class DeckGeneratorBase {
|
||||
float requestedOverTotal = (float)cnt / totalWeight;
|
||||
|
||||
for (ImmutablePair<FilterCMC, Integer> pair : cmcLevels) {
|
||||
Iterable<PaperCard> matchingCards = Iterables.filter(source, Predicates.compose(pair.getLeft(), PaperCard.FN_GET_RULES));
|
||||
Iterable<PaperCard> matchingCards = Iterables.filter(source, Predicates.compose(pair.getLeft(), PaperCard::getRules));
|
||||
int cmcCountForPool = (int) Math.ceil(pair.getRight() * desiredOverTotal);
|
||||
|
||||
int addOfThisCmc = Math.round(pair.getRight() * requestedOverTotal);
|
||||
@@ -288,18 +288,15 @@ public abstract class DeckGeneratorBase {
|
||||
// remove cards that generated decks don't like
|
||||
Predicate<CardRules> canPlay = forAi ? AI_CAN_PLAY : CardRulesPredicates.IS_KEPT_IN_RANDOM_DECKS;
|
||||
Predicate<CardRules> hasColor = new MatchColorIdentity(colors);
|
||||
Predicate<CardRules> canUseInFormat = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(CardRules c) {
|
||||
Predicate<CardRules> canUseInFormat = c -> {
|
||||
// FIXME: should this be limited to AI only (!forAi) or should it be generally applied to all random generated decks?
|
||||
return !c.getAiHints().getRemNonCommanderDecks() || format.hasCommander();
|
||||
}
|
||||
};
|
||||
|
||||
if (useArtifacts) {
|
||||
hasColor = Predicates.or(hasColor, COLORLESS_CARDS);
|
||||
}
|
||||
return Iterables.filter(pool.getAllCards(), Predicates.compose(Predicates.and(canPlay, hasColor, canUseInFormat), PaperCard.FN_GET_RULES));
|
||||
return Iterables.filter(pool.getAllCards(), Predicates.compose(Predicates.and(canPlay, hasColor, canUseInFormat), PaperCard::getRules));
|
||||
}
|
||||
|
||||
protected static Map<String, Integer> countLands(ItemPool<PaperCard> outList) {
|
||||
@@ -337,12 +334,9 @@ public abstract class DeckGeneratorBase {
|
||||
|
||||
public static final Predicate<CardRules> AI_CAN_PLAY = Predicates.and(CardRulesPredicates.IS_KEPT_IN_AI_DECKS, CardRulesPredicates.IS_KEPT_IN_RANDOM_DECKS);
|
||||
|
||||
public static final Predicate<CardRules> COLORLESS_CARDS = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(CardRules c) {
|
||||
public static final Predicate<CardRules> COLORLESS_CARDS = c -> {
|
||||
ManaCost mc = c.getManaCost();
|
||||
return c.getColorIdentity().isColorless() && !mc.isNoCost();
|
||||
}
|
||||
};
|
||||
|
||||
public static class MatchColorIdentity implements Predicate<CardRules> {
|
||||
@@ -401,7 +395,7 @@ public abstract class DeckGeneratorBase {
|
||||
Predicate<CardRules> dualLandFilter = CardRulesPredicates.coreType(true, CardType.CoreType.Land);
|
||||
Predicate<CardRules> exceptBasicLand = Predicates.not(CardRulesPredicates.Presets.IS_BASIC_LAND);
|
||||
|
||||
Iterable<PaperCard> landCards = pool.getAllCards(Predicates.compose(Predicates.and(dualLandFilter, exceptBasicLand, canPlay), PaperCard.FN_GET_RULES));
|
||||
Iterable<PaperCard> landCards = pool.getAllCards(Predicates.compose(Predicates.and(dualLandFilter, exceptBasicLand, canPlay), PaperCard::getRules));
|
||||
Iterable<String> dualLandPatterns = Arrays.asList("Add \\{([WUBRG])\\} or \\{([WUBRG])\\}",
|
||||
"Add \\{([WUBRG])\\}, \\{([WUBRG])\\}, or \\{([WUBRG])\\}",
|
||||
"Add \\{([WUBRG])\\}\\{([WUBRG])\\}",
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.util.List;
|
||||
|
||||
import forge.deck.DeckBase;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -45,7 +46,7 @@ public class DeckGroupSerializer extends StorageReaderFolder<DeckGroup> implemen
|
||||
* @param deckDir0 the deck dir0
|
||||
*/
|
||||
public DeckGroupSerializer(final File deckDir0, String rootDir0) {
|
||||
super(deckDir0, DeckGroup.FN_NAME_SELECTOR);
|
||||
super(deckDir0, DeckBase::getName);
|
||||
rootDir = rootDir0;
|
||||
}
|
||||
|
||||
@@ -122,16 +123,12 @@ public class DeckGroupSerializer extends StorageReaderFolder<DeckGroup> implemen
|
||||
*/
|
||||
@Override
|
||||
protected FilenameFilter getFileFilter() {
|
||||
return new FilenameFilter() {
|
||||
|
||||
@Override
|
||||
public boolean accept(final File dir, final String name) {
|
||||
return (dir, name) -> {
|
||||
final File testSubject = new File(dir, name);
|
||||
final boolean isVisibleFolder = testSubject.isDirectory() && !testSubject.isHidden();
|
||||
final boolean hasGoodName = StringUtils.isNotEmpty(name) && !name.startsWith(".");
|
||||
final File fileHumanDeck = new File(testSubject, DeckGroupSerializer.humanDeckFile);
|
||||
return isVisibleFolder && hasGoodName && fileHumanDeck.exists();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckBase;
|
||||
import forge.util.FileSection;
|
||||
import forge.util.FileUtil;
|
||||
import forge.util.IItemReader;
|
||||
@@ -39,19 +40,14 @@ public class DeckStorage extends StorageReaderFolder<Deck> implements IItemSeria
|
||||
private final boolean moveWronglyNamedDecks;
|
||||
|
||||
/** Constant <code>DCKFileFilter</code>. */
|
||||
public static final FilenameFilter DCK_FILE_FILTER = new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(final File dir, final String name) {
|
||||
return name.endsWith(FILE_EXTENSION);
|
||||
}
|
||||
};
|
||||
public static final FilenameFilter DCK_FILE_FILTER = (dir, name) -> name.endsWith(FILE_EXTENSION);
|
||||
|
||||
public DeckStorage(final File deckDir0, final String rootDir0) {
|
||||
this(deckDir0, rootDir0, false);
|
||||
}
|
||||
|
||||
public DeckStorage(final File deckDir0, final String rootDir0, boolean moveWrongDecks) {
|
||||
super(deckDir0, Deck.FN_NAME_SELECTOR);
|
||||
super(deckDir0, DeckBase::getName);
|
||||
rootDir = rootDir0;
|
||||
moveWronglyNamedDecks = moveWrongDecks;
|
||||
}
|
||||
|
||||
@@ -22,24 +22,19 @@ import java.util.ArrayList;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.ImageKeys;
|
||||
import forge.StaticData;
|
||||
import forge.card.CardEdition;
|
||||
|
||||
public class BoosterBox extends BoxedProduct {
|
||||
public static final Function<CardEdition, BoosterBox> FN_FROM_SET = new Function<CardEdition, BoosterBox>() {
|
||||
@Override
|
||||
public BoosterBox apply(final CardEdition arg1) {
|
||||
if (arg1.getBoosterBoxCount() <= 0) {
|
||||
|
||||
public static BoosterBox fromSet(CardEdition edition) {
|
||||
if (edition.getBoosterBoxCount() <= 0) {
|
||||
return null;
|
||||
}
|
||||
BoosterBox.Template d = new Template(arg1);
|
||||
if (d == null) { return null; }
|
||||
return new BoosterBox(arg1.getName(), d, d.cntBoosters);
|
||||
BoosterBox.Template d = new Template(edition);
|
||||
return new BoosterBox(edition.getName(), d, d.cntBoosters);
|
||||
}
|
||||
};
|
||||
|
||||
private final BoosterBox.Template fpData;
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ package forge.item;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import forge.ImageKeys;
|
||||
@@ -33,20 +32,15 @@ public class BoosterPack extends SealedProduct {
|
||||
private final int artIndex;
|
||||
private final int hash;
|
||||
|
||||
public static final Function<CardEdition, BoosterPack> FN_FROM_SET = new Function<CardEdition, BoosterPack>() {
|
||||
@Override
|
||||
public BoosterPack apply(final CardEdition edition) {
|
||||
public static BoosterPack fromSet(CardEdition edition) {
|
||||
String boosterKind = edition.getRandomBoosterKind();
|
||||
Template d = edition.getBoosterTemplate(boosterKind);
|
||||
StringBuilder sb = new StringBuilder(edition.getName());
|
||||
sb.append(" ").append(boosterKind);
|
||||
return new BoosterPack(sb.toString(), d);
|
||||
}
|
||||
};
|
||||
|
||||
public static final Function<String, BoosterPack> FN_FROM_COLOR = new Function<String, BoosterPack>() {
|
||||
@Override
|
||||
public BoosterPack apply(final String color) {
|
||||
public static BoosterPack fromColor(final String color) {
|
||||
return new BoosterPack(color, new Template("?", ImmutableList.of(
|
||||
Pair.of(BoosterSlots.COMMON + ":color(\"" + color + "\"):!" + BoosterSlots.LAND, 11),
|
||||
Pair.of(BoosterSlots.UNCOMMON + ":color(\"" + color + "\"):!" + BoosterSlots.LAND, 3),
|
||||
@@ -54,7 +48,6 @@ public class BoosterPack extends SealedProduct {
|
||||
Pair.of(BoosterSlots.LAND + ":color(\"" + color + "\")", 1))
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
public BoosterPack(final String name0, final Template boosterData) {
|
||||
super(name0, boosterData);
|
||||
|
||||
@@ -22,25 +22,20 @@ import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.ImageKeys;
|
||||
import forge.StaticData;
|
||||
import forge.card.CardEdition;
|
||||
import forge.item.generation.BoosterGenerator;
|
||||
|
||||
public class FatPack extends BoxedProduct {
|
||||
public static final Function<CardEdition, FatPack> FN_FROM_SET = new Function<CardEdition, FatPack>() {
|
||||
@Override
|
||||
public FatPack apply(final CardEdition edition) {
|
||||
public static FatPack fromSet(final CardEdition edition) {
|
||||
int boosters = edition.getFatPackCount();
|
||||
if (boosters <= 0) { return null; }
|
||||
|
||||
FatPack.Template d = new Template(edition);
|
||||
if (d == null || null == StaticData.instance().getBoosters().get(d.getEdition())) { return null; }
|
||||
if (null == StaticData.instance().getBoosters().get(d.getEdition())) { return null; }
|
||||
return new FatPack(edition.getName(), d, d.cntBoosters);
|
||||
}
|
||||
};
|
||||
|
||||
private final FatPack.Template fpData;
|
||||
|
||||
|
||||
@@ -225,19 +225,8 @@ public interface IPaperCard extends InventoryItem, Serializable {
|
||||
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 = new Predicate<PaperCard>() {
|
||||
@Override
|
||||
public boolean apply(PaperCard input) {
|
||||
return input.isUnRebalanced();
|
||||
}
|
||||
};
|
||||
public static final Predicate<PaperCard> IS_REBALANCED = new Predicate<PaperCard>() {
|
||||
|
||||
@Override
|
||||
public boolean apply(PaperCard input) {
|
||||
return input.isRebalanced();
|
||||
}
|
||||
};
|
||||
public static final Predicate<PaperCard> IS_UNREBALANCED = PaperCard::isUnRebalanced;
|
||||
public static final Predicate<PaperCard> IS_REBALANCED = PaperCard::isRebalanced;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,26 +19,14 @@ public abstract class ItemPredicate {
|
||||
*
|
||||
* @return the predicate
|
||||
*/
|
||||
public static final Predicate<InventoryItem> IsTournamentPack = new Predicate<InventoryItem>() {
|
||||
|
||||
@Override
|
||||
public boolean apply(final InventoryItem card) {
|
||||
return card instanceof TournamentPack && !((TournamentPack) card).isStarterDeck();
|
||||
}
|
||||
};
|
||||
public static final Predicate<InventoryItem> IsTournamentPack = card -> card instanceof TournamentPack && !((TournamentPack) card).isStarterDeck();
|
||||
|
||||
/**
|
||||
* Checks that the inventory item is a Starter Deck.
|
||||
*
|
||||
* @return the predicate
|
||||
*/
|
||||
public static final Predicate<InventoryItem> IsStarterDeck = new Predicate<InventoryItem>() {
|
||||
|
||||
@Override
|
||||
public boolean apply(final InventoryItem card) {
|
||||
return card instanceof TournamentPack && ((TournamentPack) card).isStarterDeck();
|
||||
}
|
||||
};
|
||||
public static final Predicate<InventoryItem> IsStarterDeck = card -> card instanceof TournamentPack && ((TournamentPack) card).isStarterDeck();
|
||||
|
||||
/**
|
||||
* Checks that the inventory item is a Prebuilt Deck.
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
package forge.item;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import forge.ImageKeys;
|
||||
import forge.StaticData;
|
||||
import forge.card.*;
|
||||
@@ -160,22 +159,6 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
return hasImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lambda to get rules for selects from list of printed cards.
|
||||
*/
|
||||
public static final Function<PaperCard, CardRules> FN_GET_RULES = new Function<PaperCard, CardRules>() {
|
||||
@Override
|
||||
public CardRules apply(final PaperCard from) {
|
||||
return from.rules;
|
||||
}
|
||||
};
|
||||
public static final Function<PaperCard, String> FN_GET_NAME = new Function<PaperCard, String>() {
|
||||
@Override
|
||||
public String apply(final PaperCard from) {
|
||||
return from.getName();
|
||||
}
|
||||
};
|
||||
|
||||
public PaperCard(final CardRules rules0, final String edition0, final CardRarity rarity0) {
|
||||
this(rules0, edition0, rarity0, IPaperCard.DEFAULT_ART_INDEX, false,
|
||||
IPaperCard.NO_COLLECTOR_NUMBER, IPaperCard.NO_ARTIST_NAME, IPaperCard.NO_FUNCTIONAL_VARIANT);
|
||||
|
||||
@@ -22,8 +22,6 @@ import java.io.FilenameFilter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.ImageKeys;
|
||||
import forge.StaticData;
|
||||
import forge.deck.Deck;
|
||||
@@ -89,16 +87,9 @@ public class PreconDeck implements InventoryItemFromSet {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public static final Function<PreconDeck, String> FN_NAME_SELECTOR = new Function<PreconDeck, String>() {
|
||||
@Override
|
||||
public String apply(PreconDeck arg1) {
|
||||
return arg1.getName();
|
||||
}
|
||||
};
|
||||
|
||||
public static class Reader extends StorageReaderFolder<PreconDeck> {
|
||||
public Reader(final File deckDir0) {
|
||||
super(deckDir0, PreconDeck.FN_NAME_SELECTOR);
|
||||
super(deckDir0, PreconDeck::getName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -124,13 +115,6 @@ public class PreconDeck implements InventoryItemFromSet {
|
||||
}
|
||||
}
|
||||
|
||||
public static final Function<PreconDeck, Deck> FN_GET_DECK = new Function<PreconDeck, Deck>() {
|
||||
@Override
|
||||
public Deck apply(PreconDeck arg1) {
|
||||
return arg1.getDeck();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public String getImageKey(boolean altState) {
|
||||
return ImageKeys.PRECON_PREFIX + imageFilename;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user