Improve a few parts from previous PR (#2770)

This commit is contained in:
tool4ever
2023-03-28 23:11:13 +02:00
committed by GitHub
parent 26ddc5d18e
commit 4329e2b0c8
15 changed files with 65 additions and 98 deletions

View File

@@ -69,6 +69,7 @@ public class DeckHints {
public boolean isValid() { public boolean isValid() {
return valid; return valid;
} }
public boolean contains(Type type, String hint) { public boolean contains(Type type, String hint) {
if (filters == null) { if (filters == null) {
return false; return false;
@@ -84,16 +85,20 @@ public class DeckHints {
if (filters == null) { if (filters == null) {
return false; return false;
} }
int num = 0;
for (String hint : hints) { for (String hint : hints) {
for (Pair<Type, String> filter : filters) { for (Pair<Type, String> filter : filters) {
System.out.println(filter.getLeft() + " = type = " + type + " "+ filter.getRight() + " =filter= " + hint);
if (filter.getLeft() == type && filter.getRight().equals(hint)) { if (filter.getLeft() == type && filter.getRight().equals(hint)) {
continue; num++;
if (num == hints.length) {
return true;
}
}
} }
} }
return false; return false;
} }
return true;
}
/** /**
* Returns a Map of Cards by Type from the given Iterable<PaperCard> that match this * Returns a Map of Cards by Type from the given Iterable<PaperCard> that match this
@@ -111,7 +116,7 @@ public class DeckHints {
Iterable<PaperCard> cards = getCardsForFilter(cardList, type, param); Iterable<PaperCard> cards = getCardsForFilter(cardList, type, param);
if (cards != null) { if (cards != null) {
// if a type is used more than once intersect respective matches // if a type is used more than once intersect respective matches
if (ret.get(type) != null) { if (ret.containsKey(type)) {
Iterables.retainAll(cards, new FCollection<>(ret.get(type))); Iterables.retainAll(cards, new FCollection<>(ret.get(type)));
} }
ret.put(type, cards); ret.put(type, cards);
@@ -128,17 +133,8 @@ public class DeckHints {
* list of cards to be filtered * list of cards to be filtered
* @return List<PaperCard> of Cards that match this DeckHints. * @return List<PaperCard> of Cards that match this DeckHints.
*/ */
public List<PaperCard> filter(Iterable<PaperCard> cardList) { public Iterable<PaperCard> filter(Iterable<PaperCard> cardList) {
List<PaperCard> ret = new ArrayList<>(); return Iterables.concat(filterByType(cardList).values());
for (Pair<Type, String> pair : filters) {
Type type = pair.getLeft();
String param = pair.getRight();
Iterable<PaperCard> cards = getCardsForFilter(cardList, type, param);
if (cards != null) {
Iterables.addAll(ret, cards);
}
}
return ret;
} }
private Pair<Type, String> parseHint(String hint) { private Pair<Type, String> parseHint(String hint) {
@@ -164,58 +160,39 @@ public class DeckHints {
List<PaperCard> cards = new ArrayList<>(); List<PaperCard> cards = new ArrayList<>();
// this is case ABILITY, but other types can also use this when the implicit parsing would miss // this is case ABILITY, but other types can also use this when the implicit parsing would miss
String[] abilities = param.split("\\|"); String[] params = param.split("\\|");
for (String ability : abilities) { 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.FN_GET_RULES));
} }
// bonus if a DeckHas can satisfy the type with multiple ones // bonus if a DeckHas can satisfy the type with multiple ones
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.deckHasExactly(type, abilities), PaperCard.FN_GET_RULES)); if (params.length > 1) {
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.deckHasExactly(type, params), PaperCard.FN_GET_RULES));
}
for (String p : params) {
switch (type) { switch (type) {
case COLOR: case COLOR:
String[] colors = param.split("\\|"); ColorSet cc = ColorSet.fromNames(p);
for (String color : colors) {
ColorSet cc = ColorSet.fromNames(color);
if (cc.isColorless()) { 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.FN_GET_RULES));
} else { } else {
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.isColor(cc.getColor()), PaperCard.FN_GET_RULES)); Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.isColor(cc.getColor()), PaperCard.FN_GET_RULES));
} }
}
break; break;
case KEYWORD: case KEYWORD:
String[] keywords = param.split("\\|"); Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.hasKeyword(p), PaperCard.FN_GET_RULES));
for (String keyword : keywords) {
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.hasKeyword(keyword), PaperCard.FN_GET_RULES));
}
break; break;
case NAME: case NAME:
String[] names = param.split("\\|"); Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.name(StringOp.EQUALS, p), PaperCard.FN_GET_RULES));
for (String name : names) {
Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.name(StringOp.EQUALS, name), PaperCard.FN_GET_RULES));
}
break; break;
case TYPE: case TYPE:
String[] types = param.split("\\|"); Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.joinedType(StringOp.CONTAINS_IC, p), PaperCard.FN_GET_RULES));
for (String t : types) {
Predicate<CardRules> op;
if (t.contains(".")) {
String[] typeParts = t.split("\\.");
if (CardType.isASupertype(typeParts[0])) {
op = Predicates.and(CardRulesPredicates.superType(true, typeParts[0]), CardRulesPredicates.coreType(true, typeParts[1]));
} else {
op = Predicates.and(CardRulesPredicates.coreType(true, typeParts[0]), CardRulesPredicates.subType(typeParts[1]));
}
} else {
op = CardRulesPredicates.joinedType(StringOp.CONTAINS_IC, t);
}
Iterables.addAll(cards, getMatchingItems(cardList, op, PaperCard.FN_GET_RULES));
}
break; break;
case NONE: case NONE:
case ABILITY: // already done above case ABILITY: // already done above
break; break;
} }
}
return cards; return cards;
} }

View File

@@ -529,7 +529,7 @@ public final class GameActionUtil {
for (KeywordInterface inst : source.getKeywords()) { for (KeywordInterface inst : source.getKeywords()) {
final String keyword = inst.getOriginal(); final String keyword = inst.getOriginal();
if (keyword.startsWith("AlternateAdditionalCost")) { if (keyword.startsWith("AlternateAdditionalCost")) {
final List<SpellAbility> newAbilities = Lists.newArrayList(); abilities.clear();
for (String s : keyword.split(":", 2)[1].split(":")) { for (String s : keyword.split(":", 2)[1].split(":")) {
final SpellAbility newSA = sa.copy(); final SpellAbility newSA = sa.copy();
@@ -539,24 +539,21 @@ public final class GameActionUtil {
newSA.setDescription(sa.getDescription() + " (Additional cost: " + cost.toSimpleString() + ")"); newSA.setDescription(sa.getDescription() + " (Additional cost: " + cost.toSimpleString() + ")");
newSA.setPayCosts(cost.add(sa.getPayCosts())); newSA.setPayCosts(cost.add(sa.getPayCosts()));
if (newSA.canPlay()) { if (newSA.canPlay()) {
newAbilities.add(newSA); abilities.add(newSA);
} }
} }
abilities.clear();
abilities.addAll(newAbilities);
} }
} }
} else if (sa.isActivatedAbility() && sa.hasParam("AlternateCost")) { } else if (sa.isActivatedAbility() && sa.hasParam("AlternateCost")) {
// need to be handled there because it needs to rebuilt the description for the original ability // need to be handled there because it needs to rebuilt the description for the original ability
final List<SpellAbility> newAbilities = Lists.newArrayList(); abilities.clear();
SpellAbility newSA = sa.copy(); SpellAbility newSA = sa.copy();
newSA.removeParam("AlternateCost"); newSA.removeParam("AlternateCost");
newSA.rebuiltDescription(); newSA.rebuiltDescription();
if (newSA.canPlay()) { if (newSA.canPlay()) {
newAbilities.add(newSA); abilities.add(newSA);
} }
// set the cost to this directly to bypass non mana cost // set the cost to this directly to bypass non mana cost
@@ -565,11 +562,8 @@ public final class GameActionUtil {
newSA2.removeParam("AlternateCost"); newSA2.removeParam("AlternateCost");
newSA2.rebuiltDescription(); newSA2.rebuiltDescription();
if (newSA2.canPlay()) { if (newSA2.canPlay()) {
newAbilities.add(newSA2); abilities.add(newSA2);
} }
abilities.clear();
abilities.addAll(newAbilities);
} }
return abilities; return abilities;
} }

View File

@@ -174,7 +174,7 @@ public class Cost implements Serializable {
*/ */
public final ManaCost getTotalMana() { public final ManaCost getTotalMana() {
CostPartMana manapart = getCostMana(); CostPartMana manapart = getCostMana();
return manapart == null ? ManaCost.ZERO : manapart.getManaToPay(); return manapart == null ? ManaCost.ZERO : manapart.getMana();
} }
/** /**
@@ -943,7 +943,8 @@ public class Cost implements Serializable {
} else if (part instanceof CostPutCounter || (mergeAdditional && // below usually not desired because they're from different causes } else if (part instanceof CostPutCounter || (mergeAdditional && // below usually not desired because they're from different causes
(part instanceof CostDiscard || part instanceof CostDraw || (part instanceof CostDiscard || part instanceof CostDraw ||
part instanceof CostAddMana || part instanceof CostPayLife || part instanceof CostAddMana || part instanceof CostPayLife ||
part instanceof CostSacrifice || part instanceof CostTapType))) { part instanceof CostSacrifice || part instanceof CostTapType||
part instanceof CostExile))) {
boolean alreadyAdded = false; boolean alreadyAdded = false;
for (final CostPart other : costParts) { for (final CostPart other : costParts) {
if ((other.getClass().equals(part.getClass()) || (part instanceof CostPutCounter && ((CostPutCounter)part).getCounter().is(CounterEnumType.LOYALTY))) && if ((other.getClass().equals(part.getClass()) || (part instanceof CostPutCounter && ((CostPutCounter)part).getCounter().is(CounterEnumType.LOYALTY))) &&
@@ -952,6 +953,7 @@ public class Cost implements Serializable {
StringUtils.isNumeric(other.getAmount())) { StringUtils.isNumeric(other.getAmount())) {
String amount = String.valueOf(part.convertAmount() + other.convertAmount()); String amount = String.valueOf(part.convertAmount() + other.convertAmount());
if (part instanceof CostPutCounter) { // CR 606.5 path for Carth if (part instanceof CostPutCounter) { // CR 606.5 path for Carth
// TODO support X
if (other instanceof CostPutCounter && ((CostPutCounter)other).getCounter().equals(((CostPutCounter) part).getCounter())) { if (other instanceof CostPutCounter && ((CostPutCounter)other).getCounter().equals(((CostPutCounter) part).getCounter())) {
costParts.add(new CostPutCounter(amount, ((CostPutCounter) part).getCounter(), part.getType(), part.getTypeDescription())); costParts.add(new CostPutCounter(amount, ((CostPutCounter) part).getCounter(), part.getType(), part.getTypeDescription()));
} else if (other instanceof CostRemoveCounter && ((CostRemoveCounter)other).counter.is(CounterEnumType.LOYALTY)) { } else if (other instanceof CostRemoveCounter && ((CostRemoveCounter)other).counter.is(CounterEnumType.LOYALTY)) {
@@ -978,6 +980,8 @@ public class Cost implements Serializable {
costParts.add(new CostAddMana(amount, part.getType(), part.getTypeDescription())); costParts.add(new CostAddMana(amount, part.getType(), part.getTypeDescription()));
} else if (part instanceof CostPayLife) { } else if (part instanceof CostPayLife) {
costParts.add(new CostPayLife(amount, part.getTypeDescription())); costParts.add(new CostPayLife(amount, part.getTypeDescription()));
} else if (part instanceof CostExile) {
costParts.add(new CostExile(amount, part.getType(), part.getTypeDescription(), ((CostExile) part).getFrom()));
} }
toRemove.add(other); toRemove.add(other);
alreadyAdded = true; alreadyAdded = true;

View File

@@ -115,7 +115,13 @@ public class CostAdjustment {
int count = 0; int count = 0;
if (st.hasParam("ForEachShard")) { if (st.hasParam("ForEachShard")) {
ManaCost mc = sa.getHostCard().getManaCost(); ManaCost mc = ManaCost.ZERO;
if (sa.isSpell()) {
mc = sa.getHostCard().getManaCost();
} else if (sa.isAbility() && sa.getPayCosts().hasManaCost()) {
// TODO check for AlternateCost$, it should always be part of the activation cost too
mc = sa.getPayCosts().getCostMana().getMana();
}
byte atom = ManaAtom.fromName(st.getParam("ForEachShard").toLowerCase()); byte atom = ManaAtom.fromName(st.getParam("ForEachShard").toLowerCase());
for (ManaCostShard shard : mc) { for (ManaCostShard shard : mc) {
if ((shard.getColorMask() & atom) != 0) { if ((shard.getColorMask() & atom) != 0) {

View File

@@ -75,7 +75,6 @@ public class CostPartMana extends CostPart {
* @return the mana * @return the mana
*/ */
public final ManaCost getMana() { public final ManaCost getMana() {
// Only used for Human to pay for non-X cost first
return this.cost; return this.cost;
} }
@@ -90,15 +89,6 @@ public class CostPartMana extends CostPart {
return !xCantBe0; return !xCantBe0;
} }
/**
* Gets the mana to pay.
*
* @return the mana to pay
*/
public final ManaCost getManaToPay() {
return cost;
}
/** /**
* @return the isExiledCreatureCost * @return the isExiledCreatureCost
*/ */
@@ -149,13 +139,13 @@ public class CostPartMana extends CostPart {
if (timesToPay == 0) { if (timesToPay == 0) {
return null; return null;
} }
ManaCostBeingPaid totalMana = new ManaCostBeingPaid(getManaToPay()); ManaCostBeingPaid totalMana = new ManaCostBeingPaid(getMana());
for (int i = 1; i < timesToPay; i++) { for (int i = 1; i < timesToPay; i++) {
totalMana.addManaCost(getManaToPay()); totalMana.addManaCost(getMana());
} }
return totalMana.toManaCost(); return totalMana.toManaCost();
} }
return getManaToPay(); return getMana();
} }
@Override @Override

View File

@@ -374,7 +374,7 @@ public class AbilityManaPart implements java.io.Serializable {
if (restriction.endsWith("X") && sa.costHasManaX()) { if (restriction.endsWith("X") && sa.costHasManaX()) {
return true; return true;
} }
if (restriction.endsWith("C") && sa.getPayCosts().hasManaCost() && sa.getPayCosts().getCostMana().getManaToPay().getShardCount(ManaCostShard.COLORLESS) > 0) { if (restriction.endsWith("C") && sa.getPayCosts().hasManaCost() && sa.getPayCosts().getCostMana().getMana().getShardCount(ManaCostShard.COLORLESS) > 0) {
return true; return true;
} }
continue; continue;

View File

@@ -618,7 +618,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
payingMana.clear(); payingMana.clear();
} }
//getSpendPhyrexianMana
public final int getSpendPhyrexianMana() { public final int getSpendPhyrexianMana() {
return this.spentPhyrexian; return this.spentPhyrexian;
} }

View File

@@ -44,9 +44,9 @@ public class DeckHintsTest {
list.add(readCard("assault_griffin.txt")); list.add(readCard("assault_griffin.txt"));
list.add(readCard("auramancer.txt")); list.add(readCard("auramancer.txt"));
List<PaperCard> filtered = hints.filter(list); Iterable<PaperCard> filtered = hints.filter(list);
Assert.assertEquals(1, filtered.size()); Assert.assertEquals(1, Iterables.size(filtered));
Assert.assertEquals("Assault Griffin", filtered.get(0).getName()); Assert.assertEquals("Assault Griffin", Iterables.getLast(filtered).getName());
} }
/** /**
@@ -65,7 +65,7 @@ public class DeckHintsTest {
list.add(readCard("scepter_of_empires.txt")); list.add(readCard("scepter_of_empires.txt"));
list.add(readCard("crown_of_empires.txt")); list.add(readCard("crown_of_empires.txt"));
Assert.assertEquals(2, hints.filter(list).size()); Assert.assertEquals(2, Iterables.size(hints.filter(list)));
} }
/** /**
@@ -82,7 +82,7 @@ public class DeckHintsTest {
list.add(readCard("acidic_slime.txt")); list.add(readCard("acidic_slime.txt"));
list.add(readCard("ajanis_sunstriker.txt")); list.add(readCard("ajanis_sunstriker.txt"));
Assert.assertEquals(1, hints.filter(list).size()); Assert.assertEquals(1, Iterables.size(hints.filter(list)));
} }
/** /**
@@ -99,7 +99,7 @@ public class DeckHintsTest {
list.add(readCard("llanowar_elves.txt")); list.add(readCard("llanowar_elves.txt"));
list.add(readCard("unsummon.txt")); list.add(readCard("unsummon.txt"));
Assert.assertEquals(1, hints.filter(list).size()); Assert.assertEquals(1, Iterables.size(hints.filter(list)));
} }
/** /**
@@ -150,7 +150,7 @@ public class DeckHintsTest {
list.add(pc); list.add(pc);
list.add(readCard("assault_griffin.txt")); list.add(readCard("assault_griffin.txt"));
Assert.assertEquals(1, hints.filter(list).size()); Assert.assertEquals(1, Iterables.size(hints.filter(list)));
} }
/** /**

View File

@@ -4,5 +4,5 @@ Types:Artifact Equipment
K:Equip:2 K:Equip:2
S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 2 | AddToughness$ 1 | Description$ Equipped creature gets +2/+1. S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 2 | AddToughness$ 1 | Description$ Equipped creature gets +2/+1.
S:Mode$ Continuous | Affected$ Card.EquippedBy+Legendary | AddKeyword$ Trample & Haste | Description$ As long as equipped creature is legendary, it has trample and haste. S:Mode$ Continuous | Affected$ Card.EquippedBy+Legendary | AddKeyword$ Trample & Haste | Description$ As long as equipped creature is legendary, it has trample and haste.
DeckNeeds:Type$Creature.Legendary DeckNeeds:Type$Legendary & Type$Creature
Oracle:Equipped creature gets +2/+1.\nAs long as equipped creature is legendary, it has trample and haste.\nEquip {2} Oracle:Equipped creature gets +2/+1.\nAs long as equipped creature is legendary, it has trample and haste.\nEquip {2}

View File

@@ -1,7 +1,7 @@
Name:Phyrexian Purge Name:Phyrexian Purge
ManaCost:2 B R ManaCost:2 B R
Types:Sorcery Types:Sorcery
A:SP$ Destroy | Cost$ 2 B R PayLife<X> | ValidTgts$ Creature | TargetMin$ 0 | TargetMax$ MaxPayLifeLimit | SpellDescription$ This spell costs 3 life more to cast for each target. Destroy any number of target creatures. A:SP$ Destroy | Cost$ 2 B R PayLife<X> | ValidTgts$ Creature | TargetMin$ 0 | TargetMax$ MaxPayLifeLimit | CostDesc$ This spell costs 3 life more to cast for each target. | SpellDescription$ Destroy any number of target creatures.
SVar:MaxPayLifeLimit:Count$YourLifeTotal/DivideEvenlyDown.3 SVar:MaxPayLifeLimit:Count$YourLifeTotal/DivideEvenlyDown.3
SVar:X:SVar$Y/Times.3 SVar:X:SVar$Y/Times.3
SVar:Y:Targeted$Amount SVar:Y:Targeted$Amount

View File

@@ -5,5 +5,5 @@ A:AB$ Mana | Cost$ T PayLife<1> | Produced$ Combo B R | SpellDescription$ Add {B
A:AB$ DealDamage | Cost$ 1 B R T | Defined$ Opponent | NumDmg$ 1 | SpellDescription$ CARDNAME deals 1 damage to each opponent. A:AB$ DealDamage | Cost$ 1 B R T | Defined$ Opponent | NumDmg$ 1 | SpellDescription$ CARDNAME deals 1 damage to each opponent.
A:AB$ ChooseCard | Cost$ 5 B R T Sac<1/CARDNAME> Sac<1/Artifact.Legendary/legendary artifact> | Defined$ You | Amount$ 2 | Choices$ Creature | ChoiceTitle$ Choose up to two creatures | SorcerySpeed$ True | AILogic$ Duneblast | SubAbility$ DBDestroyAll | StackDescription$ {p:You} chooses up to two creatures. Destroy the rest. | SpellDescription$ Choose up to two creatures, then destroy the rest. Activate only as a sorcery. A:AB$ ChooseCard | Cost$ 5 B R T Sac<1/CARDNAME> Sac<1/Artifact.Legendary/legendary artifact> | Defined$ You | Amount$ 2 | Choices$ Creature | ChoiceTitle$ Choose up to two creatures | SorcerySpeed$ True | AILogic$ Duneblast | SubAbility$ DBDestroyAll | StackDescription$ {p:You} chooses up to two creatures. Destroy the rest. | SpellDescription$ Choose up to two creatures, then destroy the rest. Activate only as a sorcery.
SVar:DBDestroyAll:DB$ DestroyAll | ValidCards$ Creature.nonChosenCard | StackDescription$ None SVar:DBDestroyAll:DB$ DestroyAll | ValidCards$ Creature.nonChosenCard | StackDescription$ None
DeckNeeds:Type$Legendary.Artifact DeckNeeds:Type$Legendary & Type$Artifact
Oracle:{T}, Pay 1 life: Add {B} or {R}.\n{1}{B}{R}, {T}: Mount Doom deals 1 damage to each opponent.\n{5}{B}{R}, {T}, Sacrifice Mount Doom and a legendary artifact: Choose up to two creatures, then destroy the rest. Activate only as a sorcery. Oracle:{T}, Pay 1 life: Add {B} or {R}.\n{1}{B}{R}, {T}: Mount Doom deals 1 damage to each opponent.\n{5}{B}{R}, {T}, Sacrifice Mount Doom and a legendary artifact: Choose up to two creatures, then destroy the rest. Activate only as a sorcery.

View File

@@ -2,5 +2,5 @@ Name:You Cannot Pass!
ManaCost:W ManaCost:W
Types:Instant Types:Instant
A:SP$ Destroy | ValidTgts$ Creature.blockedValidThisTurn Creature.Legendary,Creature.blockedByValidThisTurn Creature.Legendary | TgtPrompt$ Select target creature that blocked or was blocked by a legendary creature this turn | SpellDescription$ Destroy target creature that blocked or was blocked by a legendary creature this turn. A:SP$ Destroy | ValidTgts$ Creature.blockedValidThisTurn Creature.Legendary,Creature.blockedByValidThisTurn Creature.Legendary | TgtPrompt$ Select target creature that blocked or was blocked by a legendary creature this turn | SpellDescription$ Destroy target creature that blocked or was blocked by a legendary creature this turn.
DeckNeeds:Type$Legendary.Creature DeckNeeds:Type$Legendary & Type$Creature
Oracle:Destroy target creature that blocked or was blocked by a legendary creature this turn. Oracle:Destroy target creature that blocked or was blocked by a legendary creature this turn.

View File

@@ -18,7 +18,6 @@ import forge.card.CardEdition;
import forge.card.CardRules; import forge.card.CardRules;
import forge.card.CardRulesPredicates; import forge.card.CardRulesPredicates;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.card.DeckHints;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard; import forge.card.mana.ManaCostShard;
@@ -591,12 +590,10 @@ public class LimitedDeckBuilder extends DeckGeneratorBase {
if (ai.getRemRandomDecks()) { if (ai.getRemRandomDecks()) {
final List<PaperCard> comboCards = new ArrayList<>(); final List<PaperCard> comboCards = new ArrayList<>();
if (ai.getDeckNeeds() != null && ai.getDeckNeeds().isValid()) { if (ai.getDeckNeeds() != null && ai.getDeckNeeds().isValid()) {
final DeckHints needs = ai.getDeckNeeds(); Iterables.addAll(comboCards, ai.getDeckNeeds().filter(deckList));
comboCards.addAll(needs.filter(deckList));
} }
if (ai.getDeckHints() != null && ai.getDeckHints().isValid()) { if (ai.getDeckHints() != null && ai.getDeckHints().isValid()) {
final DeckHints hints = ai.getDeckHints(); Iterables.addAll(comboCards, ai.getDeckHints().filter(deckList));
comboCards.addAll(hints.filter(deckList));
} }
if (comboCards.isEmpty()) { if (comboCards.isEmpty()) {
if (logToConsole) { if (logToConsole) {

View File

@@ -236,7 +236,7 @@ public class HumanPlay {
} }
// 0 mana costs were slipping through because CostPart.getAmount returns 1 // 0 mana costs were slipping through because CostPart.getAmount returns 1
else if (costPart instanceof CostPartMana && parts.size() < 2) { else if (costPart instanceof CostPartMana && parts.size() < 2) {
if (((CostPartMana) costPart).getManaToPay().isZero()) { if (((CostPartMana) costPart).getMana().isZero()) {
return p.getController().confirmPayment(costPart, Localizer.getInstance().getMessage("lblDoYouWantPay") + " {0}?" + orString, sourceAbility); return p.getController().confirmPayment(costPart, Localizer.getInstance().getMessage("lblDoYouWantPay") + " {0}?" + orString, sourceAbility);
} }
} }
@@ -438,7 +438,7 @@ public class HumanPlay {
if (!hasPaid) { return false; } if (!hasPaid) { return false; }
} }
else if (part instanceof CostPartMana) { else if (part instanceof CostPartMana) {
if (!((CostPartMana) part).getManaToPay().isZero()) { // non-zero costs require input if (!((CostPartMana) part).getMana().isZero()) { // non-zero costs require input
mayRemovePart = false; mayRemovePart = false;
} }
} }