diff --git a/forge-core/src/main/java/forge/card/DeckHints.java b/forge-core/src/main/java/forge/card/DeckHints.java index 6af5a15dfad..d7078a4120a 100644 --- a/forge-core/src/main/java/forge/card/DeckHints.java +++ b/forge-core/src/main/java/forge/card/DeckHints.java @@ -69,6 +69,7 @@ public class DeckHints { public boolean isValid() { return valid; } + public boolean contains(Type type, String hint) { if (filters == null) { return false; @@ -84,15 +85,19 @@ public class DeckHints { if (filters == null) { return false; } + int num = 0; for (String hint : hints) { for (Pair filter : filters) { + System.out.println(filter.getLeft() + " = type = " + type + " "+ filter.getRight() + " =filter= " + hint); if (filter.getLeft() == type && filter.getRight().equals(hint)) { - continue; + num++; + if (num == hints.length) { + return true; + } } } - return false; } - return true; + return false; } /** @@ -111,7 +116,7 @@ public class DeckHints { Iterable cards = getCardsForFilter(cardList, type, param); if (cards != null) { // 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))); } ret.put(type, cards); @@ -128,17 +133,8 @@ public class DeckHints { * list of cards to be filtered * @return List of Cards that match this DeckHints. */ - public List filter(Iterable cardList) { - List ret = new ArrayList<>(); - for (Pair pair : filters) { - Type type = pair.getLeft(); - String param = pair.getRight(); - Iterable cards = getCardsForFilter(cardList, type, param); - if (cards != null) { - Iterables.addAll(ret, cards); - } - } - return ret; + public Iterable filter(Iterable cardList) { + return Iterables.concat(filterByType(cardList).values()); } private Pair parseHint(String hint) { @@ -164,57 +160,38 @@ public class DeckHints { List cards = new ArrayList<>(); // this is case ABILITY, but other types can also use this when the implicit parsing would miss - String[] abilities = param.split("\\|"); - for (String ability : abilities) { + String[] params = param.split("\\|"); + for (String ability : params) { Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.deckHas(type, ability), PaperCard.FN_GET_RULES)); } // 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)); + } - switch (type) { + for (String p : params) { + switch (type) { case COLOR: - String[] colors = param.split("\\|"); - for (String color : colors) { - ColorSet cc = ColorSet.fromNames(color); - if (cc.isColorless()) { - Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.Presets.IS_COLORLESS, PaperCard.FN_GET_RULES)); - } else { - Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.isColor(cc.getColor()), PaperCard.FN_GET_RULES)); - } + ColorSet cc = ColorSet.fromNames(p); + if (cc.isColorless()) { + Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.Presets.IS_COLORLESS, PaperCard.FN_GET_RULES)); + } else { + Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.isColor(cc.getColor()), PaperCard.FN_GET_RULES)); } break; case KEYWORD: - String[] keywords = param.split("\\|"); - for (String keyword : keywords) { - Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.hasKeyword(keyword), PaperCard.FN_GET_RULES)); - } + Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.hasKeyword(p), PaperCard.FN_GET_RULES)); break; case NAME: - String[] names = param.split("\\|"); - for (String name : names) { - Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.name(StringOp.EQUALS, name), PaperCard.FN_GET_RULES)); - } + Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.name(StringOp.EQUALS, p), PaperCard.FN_GET_RULES)); break; case TYPE: - String[] types = param.split("\\|"); - for (String t : types) { - Predicate 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)); - } + Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.joinedType(StringOp.CONTAINS_IC, p), PaperCard.FN_GET_RULES)); break; case NONE: case ABILITY: // already done above break; + } } return cards; } diff --git a/forge-core/src/main/java/forge/card/mana/ManaCost.java b/forge-core/src/main/java/forge/card/mana/ManaCost.java index 79580f04ba1..cfbde1a74d4 100644 --- a/forge-core/src/main/java/forge/card/mana/ManaCost.java +++ b/forge-core/src/main/java/forge/card/mana/ManaCost.java @@ -391,7 +391,7 @@ public final class ManaCost implements Comparable, Iterable iterator() { return this.shards.iterator(); } - + public int getGlyphCount() { // counts all colored shards or 1 for {0} costs int width = shards.size(); if (genericCost > 0 || (genericCost == 0 && width == 0)) { diff --git a/forge-game/src/main/java/forge/game/GameActionUtil.java b/forge-game/src/main/java/forge/game/GameActionUtil.java index c6b010d643b..4c9e1ef999a 100644 --- a/forge-game/src/main/java/forge/game/GameActionUtil.java +++ b/forge-game/src/main/java/forge/game/GameActionUtil.java @@ -529,7 +529,7 @@ public final class GameActionUtil { for (KeywordInterface inst : source.getKeywords()) { final String keyword = inst.getOriginal(); if (keyword.startsWith("AlternateAdditionalCost")) { - final List newAbilities = Lists.newArrayList(); + abilities.clear(); for (String s : keyword.split(":", 2)[1].split(":")) { final SpellAbility newSA = sa.copy(); @@ -539,24 +539,21 @@ public final class GameActionUtil { newSA.setDescription(sa.getDescription() + " (Additional cost: " + cost.toSimpleString() + ")"); newSA.setPayCosts(cost.add(sa.getPayCosts())); if (newSA.canPlay()) { - newAbilities.add(newSA); + abilities.add(newSA); } } - - abilities.clear(); - abilities.addAll(newAbilities); } } } else if (sa.isActivatedAbility() && sa.hasParam("AlternateCost")) { // need to be handled there because it needs to rebuilt the description for the original ability - final List newAbilities = Lists.newArrayList(); + abilities.clear(); SpellAbility newSA = sa.copy(); newSA.removeParam("AlternateCost"); newSA.rebuiltDescription(); if (newSA.canPlay()) { - newAbilities.add(newSA); + abilities.add(newSA); } // set the cost to this directly to bypass non mana cost @@ -565,11 +562,8 @@ public final class GameActionUtil { newSA2.removeParam("AlternateCost"); newSA2.rebuiltDescription(); if (newSA2.canPlay()) { - newAbilities.add(newSA2); + abilities.add(newSA2); } - - abilities.clear(); - abilities.addAll(newAbilities); } return abilities; } diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index d82fbd469d0..984f8e3174a 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -3934,38 +3934,32 @@ public class Card extends GameEntity implements Comparable, IHasSVars { currentState.setBaseLoyalty(Integer.toString(n)); } - // values that are printed on card public final int getBasePower() { return currentState.getBasePower(); } - public final int getBaseToughness() { return currentState.getBaseToughness(); } - // values that are printed on card public final void setBasePower(final int n) { currentState.setBasePower(n); } - public final void setBaseToughness(final int n) { currentState.setBaseToughness(n); } // values that are printed on card public final String getBasePowerString() { - return currentState.getBasePowerString(); + return (null == currentState.getBasePowerString()) ? String.valueOf(getBasePower()) : currentState.getBasePowerString(); } - public final String getBaseToughnessString() { - return currentState.getBaseToughnessString(); + return (null == currentState.getBaseToughnessString()) ? String.valueOf(getBaseToughness()) : currentState.getBaseToughnessString(); } // values that are printed on card public final void setBasePowerString(final String s) { currentState.setBasePowerString(s); } - public final void setBaseToughnessString(final String s) { currentState.setBaseToughnessString(s); } diff --git a/forge-game/src/main/java/forge/game/card/CardFactory.java b/forge-game/src/main/java/forge/game/card/CardFactory.java index b6267e7fb93..7d76f29962e 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactory.java +++ b/forge-game/src/main/java/forge/game/card/CardFactory.java @@ -568,7 +568,7 @@ public class CardFactory { c.setRules(in.getRules()); return c; - } // copyStats() + } /** * Copy characteristics of a particular state of one card to those of a @@ -764,12 +764,14 @@ public class CardFactory { state.removeIntrinsicKeyword(kw); } - if (state.getType().isCreature()) { + // CR 208.3 A noncreature object not on the battlefield has power or toughness only if it has a power and toughness printed on it. + // currently only LKI can be trusted? + if (state.getType().isCreature() || in.getOriginalState(originalState.getStateName()).getBasePowerString() != null) { if (sa.hasParam("SetPower")) { - state.setBasePower(AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("SetPower"), sa)); + state.setBasePower(AbilityUtils.calculateAmount(host, sa.getParam("SetPower"), sa)); } if (sa.hasParam("SetToughness")) { - state.setBaseToughness(AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("SetToughness"), sa)); + state.setBaseToughness(AbilityUtils.calculateAmount(host, sa.getParam("SetToughness"), sa)); } } diff --git a/forge-game/src/main/java/forge/game/card/CardState.java b/forge-game/src/main/java/forge/game/card/CardState.java index 32469ade7f1..a529582a31a 100644 --- a/forge-game/src/main/java/forge/game/card/CardState.java +++ b/forge-game/src/main/java/forge/game/card/CardState.java @@ -202,10 +202,10 @@ public class CardState extends GameObject implements IHasSVars { // values that are printed on card public final String getBasePowerString() { - return (null == basePowerString) ? "" + getBasePower() : basePowerString; + return basePowerString; } public final String getBaseToughnessString() { - return (null == baseToughnessString) ? "" + getBaseToughness() : baseToughnessString; + return baseToughnessString; } // values that are printed on card diff --git a/forge-game/src/main/java/forge/game/card/CardUtil.java b/forge-game/src/main/java/forge/game/card/CardUtil.java index e567cd853f0..1110614f04f 100644 --- a/forge-game/src/main/java/forge/game/card/CardUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardUtil.java @@ -222,7 +222,7 @@ public final class CardUtil { newCopy.addAlternateState(CardStateName.Cloner, false); newCopy.getState(CardStateName.Cloner).copyFrom(in.getState(CardStateName.Cloner), true); } - //*/ + */ newCopy.setToken(in.isToken()); newCopy.setCopiedSpell(in.isCopiedSpell()); @@ -233,6 +233,10 @@ public final class CardUtil { newCopy.setBasePower(in.getCurrentPower()); newCopy.setBaseToughness(in.getCurrentToughness()); + // printed P/T + newCopy.setBasePowerString(in.getCurrentState().getBasePowerString()); + newCopy.setBaseToughnessString(in.getCurrentState().getBaseToughnessString()); + // extra copy PT boost newCopy.setPTBoost(in.getPTBoostTable()); diff --git a/forge-game/src/main/java/forge/game/cost/Cost.java b/forge-game/src/main/java/forge/game/cost/Cost.java index e5222a5f05c..27037e37814 100644 --- a/forge-game/src/main/java/forge/game/cost/Cost.java +++ b/forge-game/src/main/java/forge/game/cost/Cost.java @@ -174,7 +174,7 @@ public class Cost implements Serializable { */ public final ManaCost getTotalMana() { 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 (part instanceof CostDiscard || part instanceof CostDraw || part instanceof CostAddMana || part instanceof CostPayLife || - part instanceof CostSacrifice || part instanceof CostTapType))) { + part instanceof CostSacrifice || part instanceof CostTapType|| + part instanceof CostExile))) { boolean alreadyAdded = false; for (final CostPart other : costParts) { 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())) { String amount = String.valueOf(part.convertAmount() + other.convertAmount()); if (part instanceof CostPutCounter) { // CR 606.5 path for Carth + // TODO support X if (other instanceof CostPutCounter && ((CostPutCounter)other).getCounter().equals(((CostPutCounter) part).getCounter())) { costParts.add(new CostPutCounter(amount, ((CostPutCounter) part).getCounter(), part.getType(), part.getTypeDescription())); } 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())); } else if (part instanceof CostPayLife) { 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); alreadyAdded = true; diff --git a/forge-game/src/main/java/forge/game/cost/CostAdjustment.java b/forge-game/src/main/java/forge/game/cost/CostAdjustment.java index 9011499911e..e60806b2c6d 100644 --- a/forge-game/src/main/java/forge/game/cost/CostAdjustment.java +++ b/forge-game/src/main/java/forge/game/cost/CostAdjustment.java @@ -115,7 +115,13 @@ public class CostAdjustment { int count = 0; 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()); for (ManaCostShard shard : mc) { if ((shard.getColorMask() & atom) != 0) { diff --git a/forge-game/src/main/java/forge/game/cost/CostPartMana.java b/forge-game/src/main/java/forge/game/cost/CostPartMana.java index d07ce100a12..47562d35ea7 100644 --- a/forge-game/src/main/java/forge/game/cost/CostPartMana.java +++ b/forge-game/src/main/java/forge/game/cost/CostPartMana.java @@ -75,7 +75,6 @@ public class CostPartMana extends CostPart { * @return the mana */ public final ManaCost getMana() { - // Only used for Human to pay for non-X cost first return this.cost; } @@ -90,15 +89,6 @@ public class CostPartMana extends CostPart { return !xCantBe0; } - /** - * Gets the mana to pay. - * - * @return the mana to pay - */ - public final ManaCost getManaToPay() { - return cost; - } - /** * @return the isExiledCreatureCost */ @@ -149,13 +139,13 @@ public class CostPartMana extends CostPart { if (timesToPay == 0) { return null; } - ManaCostBeingPaid totalMana = new ManaCostBeingPaid(getManaToPay()); + ManaCostBeingPaid totalMana = new ManaCostBeingPaid(getMana()); for (int i = 1; i < timesToPay; i++) { - totalMana.addManaCost(getManaToPay()); + totalMana.addManaCost(getMana()); } return totalMana.toManaCost(); } - return getManaToPay(); + return getMana(); } @Override diff --git a/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java b/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java index 8a5a8ce3120..1ee84e2bc8f 100644 --- a/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java +++ b/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java @@ -374,7 +374,7 @@ public class AbilityManaPart implements java.io.Serializable { if (restriction.endsWith("X") && sa.costHasManaX()) { 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; } continue; diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java index be2f2bb8796..61a52200332 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -618,7 +618,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit payingMana.clear(); } - //getSpendPhyrexianMana public final int getSpendPhyrexianMana() { return this.spentPhyrexian; } diff --git a/forge-gui-desktop/src/test/java/forge/item/DeckHintsTest.java b/forge-gui-desktop/src/test/java/forge/item/DeckHintsTest.java index 901c029d15b..b82e3aee81e 100644 --- a/forge-gui-desktop/src/test/java/forge/item/DeckHintsTest.java +++ b/forge-gui-desktop/src/test/java/forge/item/DeckHintsTest.java @@ -44,9 +44,9 @@ public class DeckHintsTest { list.add(readCard("assault_griffin.txt")); list.add(readCard("auramancer.txt")); - List filtered = hints.filter(list); - Assert.assertEquals(1, filtered.size()); - Assert.assertEquals("Assault Griffin", filtered.get(0).getName()); + Iterable filtered = hints.filter(list); + Assert.assertEquals(1, Iterables.size(filtered)); + 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("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("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("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(readCard("assault_griffin.txt")); - Assert.assertEquals(1, hints.filter(list).size()); + Assert.assertEquals(1, Iterables.size(hints.filter(list))); } /** diff --git a/forge-gui/res/adventure/Shandalar/maps/map/phyrexian_b1.tmx b/forge-gui/res/adventure/Shandalar/maps/map/phyrexian_b1.tmx index fa6ee774c07..3b65ab87d01 100644 --- a/forge-gui/res/adventure/Shandalar/maps/map/phyrexian_b1.tmx +++ b/forge-gui/res/adventure/Shandalar/maps/map/phyrexian_b1.tmx @@ -48,7 +48,7 @@ - + @@ -109,13 +109,13 @@ - - - - - - - + + + + + + + [{ diff --git a/forge-gui/res/adventure/Shandalar/sprites/gitaxianscientist.png b/forge-gui/res/adventure/Shandalar/sprites/gitaxianscientist.png index 7efaf2659cd..b497e2bb611 100644 Binary files a/forge-gui/res/adventure/Shandalar/sprites/gitaxianscientist.png and b/forge-gui/res/adventure/Shandalar/sprites/gitaxianscientist.png differ diff --git a/forge-gui/res/adventure/Shandalar/sprites/gitaxianunderling.png b/forge-gui/res/adventure/Shandalar/sprites/gitaxianunderling.png index 12f9afc665c..7739a300073 100644 Binary files a/forge-gui/res/adventure/Shandalar/sprites/gitaxianunderling.png and b/forge-gui/res/adventure/Shandalar/sprites/gitaxianunderling.png differ diff --git a/forge-gui/res/adventure/Shandalar/sprites/phyrexianangel.png b/forge-gui/res/adventure/Shandalar/sprites/phyrexianangel.png index d085813af84..8e68badb34b 100644 Binary files a/forge-gui/res/adventure/Shandalar/sprites/phyrexianangel.png and b/forge-gui/res/adventure/Shandalar/sprites/phyrexianangel.png differ diff --git a/forge-gui/res/adventure/Shandalar/sprites/phyrexianduelist.png b/forge-gui/res/adventure/Shandalar/sprites/phyrexianduelist.png index 78693e297ae..a2d8e985c16 100644 Binary files a/forge-gui/res/adventure/Shandalar/sprites/phyrexianduelist.png and b/forge-gui/res/adventure/Shandalar/sprites/phyrexianduelist.png differ diff --git a/forge-gui/res/cardsfolder/h/heros_heirloom.txt b/forge-gui/res/cardsfolder/h/heros_heirloom.txt index 93a32b779f8..9c1d7e83c66 100644 --- a/forge-gui/res/cardsfolder/h/heros_heirloom.txt +++ b/forge-gui/res/cardsfolder/h/heros_heirloom.txt @@ -4,5 +4,5 @@ Types:Artifact Equipment K:Equip:2 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. -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} diff --git a/forge-gui/res/cardsfolder/p/phyrexian_purge.txt b/forge-gui/res/cardsfolder/p/phyrexian_purge.txt index 637b50c5523..6c1aedf612f 100644 --- a/forge-gui/res/cardsfolder/p/phyrexian_purge.txt +++ b/forge-gui/res/cardsfolder/p/phyrexian_purge.txt @@ -1,7 +1,7 @@ Name:Phyrexian Purge ManaCost:2 B R Types:Sorcery -A:SP$ Destroy | Cost$ 2 B R PayLife | 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 | 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:X:SVar$Y/Times.3 SVar:Y:Targeted$Amount diff --git a/forge-gui/res/cardsfolder/upcoming/mount_doom.txt b/forge-gui/res/cardsfolder/upcoming/mount_doom.txt index 1a9924c7ce7..f0b7bd32358 100644 --- a/forge-gui/res/cardsfolder/upcoming/mount_doom.txt +++ b/forge-gui/res/cardsfolder/upcoming/mount_doom.txt @@ -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$ 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 -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. diff --git a/forge-gui/res/cardsfolder/upcoming/you_cannot_pass!.txt b/forge-gui/res/cardsfolder/upcoming/you_cannot_pass!.txt index 976fe3979ad..bac784a6b81 100644 --- a/forge-gui/res/cardsfolder/upcoming/you_cannot_pass!.txt +++ b/forge-gui/res/cardsfolder/upcoming/you_cannot_pass!.txt @@ -2,5 +2,5 @@ Name:You Cannot Pass! ManaCost:W 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. -DeckNeeds:Type$Legendary.Creature +DeckNeeds:Type$Legendary & Type$Creature Oracle:Destroy target creature that blocked or was blocked by a legendary creature this turn. diff --git a/forge-gui/res/cardsfolder/w/wyll_blade_of_frontiers.txt b/forge-gui/res/cardsfolder/w/wyll_blade_of_frontiers.txt index 801e553ece8..09d82a0d8ec 100644 --- a/forge-gui/res/cardsfolder/w/wyll_blade_of_frontiers.txt +++ b/forge-gui/res/cardsfolder/w/wyll_blade_of_frontiers.txt @@ -4,7 +4,7 @@ Types:Legendary Creature Human Warlock PT:1/1 S:Mode$ Continuous | Affected$ You | AddKeyword$ If you would roll one or more dice, instead roll that many dice plus one and ignore the lowest roll. | Description$ If you would roll one or more dice, instead roll that many dice plus one and ignore the lowest roll. T:Mode$ RolledDieOnce | TriggerZones$ Battlefield | ValidPlayer$ You | Execute$ TrigPut | TriggerDescription$ Whenever you roll one or more dice, put a +1/+1 counter on CARDNAME. -SVar:TrigPut:DB$ PutCounter | CounterType$ P1P1 +SVar:TrigPut:DB$ PutCounter | CounterType$ P1P1 K:Choose a Background AI:RemoveDeck:Random DeckHas:Ability$Counters diff --git a/forge-gui/res/editions/March of the Machine Commander.txt b/forge-gui/res/editions/March of the Machine Commander.txt index 5e9b3ea18a2..7e00a25b51e 100644 --- a/forge-gui/res/editions/March of the Machine Commander.txt +++ b/forge-gui/res/editions/March of the Machine Commander.txt @@ -6,8 +6,17 @@ Type=Commander ScryfallCode=MOC [cards] +1 M Bright-Palm, Soul Awakener @Mila Pesic +2 M Brimaz, Blight of Oreskos @Uriah Voth +3 M Gimbal, Gremlin Prodigy @Fajareka Setiawan +4 M Kasla, the Broken Halo @Martina Fackova +5 M Sidar Jabari of Zhalfir @Simon Dominic +49 C Esper @Bruce Brenneise +61 C Nyx @Piotr Dura 67 C Towashi @Kamila Szutenberg 147 C Isle of Vesuva @Zoltan Boros & Gabor Szikszai +148 C Jund @Aleksi Briclot +153 C Panopticon @John Avon 158 C Spatial Merging @Gabor Szikszai 445 M Goro-Goro and Satoru @Johannes Voss 446 M Katilda and Lier @Justyna Dura diff --git a/forge-gui/res/editions/March of the Machine.txt b/forge-gui/res/editions/March of the Machine.txt index 76cbf48cbd8..05a926ca2bb 100644 --- a/forge-gui/res/editions/March of the Machine.txt +++ b/forge-gui/res/editions/March of the Machine.txt @@ -6,15 +6,25 @@ Type=Expansion ScryfallCode=MOM [cards] +9 R Boon-Bringer Valkyrie @Heonhwa Choe 17 R Heliod, the Radiant Dawn @Victor Adame Minguez 58 R Faerie Mastermind @Joshua Raphael 65 M Jin-Gitaxias @Ekaterina Burmak 67 C Moment of Truth @Rovina Cai +89 R Archpriest of Shadows @Fariba Khamseh 94 R Breach the Multiverse @Liiga Smilshkalne +114 R Invasion of Fiora @Joshua Raphael +117 U Merciless Repurposing @Artur Nakhodkin 134 M Chandra, Hope's Beacon @Kieran Yanner +190 R Invasion of Ikoria @Antonio José Manzanedo +191 R Invasion of Ixalan @Viktor Titov +194 U Invasion of Zendikar @Diego Gisbert 217 M Wrenn and Realmbreaker @Cristi Balanescu 222 R Drana and Linvala @Raluca Marinescu 225 R Ghalta and Mavren @Zezhou Chen +227 U Halo Forager @Kevin Sidharta +233 U Invasion of Ergamon @Manuel Castañón +239 M Invasion of New Phyrexia @Chris Rallis 249 R Omnath, Locus of All @Bryan Sola 255 M Thalia and The Gitrog Monster @Howard Lyon 256 R Yargle and Multani @Slawomir Maniak @@ -40,5 +50,9 @@ ScryfallCode=MOM 339 M Jin-Gitaxias @Julian Kok Joon Wen 352 R Faerie Mastermind @Joshua Raphael 358 R Breach the Multiverse @Liiga Smilshkalne +381 U Norn's Inquisitor @Denis Zhbankov +382 U Scrappy Bruiser @David Auden Nash +383 U Kami of Whispered Hopes @Filipe Pagliuso +384 U Botanical Brawler @Jesper Ejsing 386 R Ghalta and Mavren @Betty Jiang 387 R Omnath, Locus of All @Helge C. Balzer diff --git a/forge-gui/res/editions/Multiverse Legends.txt b/forge-gui/res/editions/Multiverse Legends.txt index aa5940c27eb..0969fcae74f 100644 --- a/forge-gui/res/editions/Multiverse Legends.txt +++ b/forge-gui/res/editions/Multiverse Legends.txt @@ -6,5 +6,16 @@ Type=Collector_Edition ScryfallCode=MUL [cards] +3 M Elesh Norn, Grand Cenobite @Flavio Girón +9 R Emry, Lurker of the Loch @Wylie Beckert +11 M Jin-Gitaxias, Core Augur @Kekai Kotaki +16 M Sheoldred, Whispering One @Flavio Girón +17 M Skithiryx, the Blight Dragon @Kekai Kotaki +19 U Yargle, Glutton of Urborg @Serena Malyon 21 M Ragavan, Nimble Pilferer @Magali Villeneuve +23 M Urabrask the Hidden @Flavio Girón +25 U Zada, Hedron Grinder @Dominik Mayer +29 M Vorinclex, Voice of Hunger @JungShan 33 M Atraxa, Praetors' Voice @Justin Hernandez & Alexis Hernandez +49 M Kroxa, Titan of Death's Hunger @Jason A. Engle +53 M Niv-Mizzet Reborn @Illustranesia diff --git a/forge-gui/src/main/java/forge/gamemodes/limited/LimitedDeckBuilder.java b/forge-gui/src/main/java/forge/gamemodes/limited/LimitedDeckBuilder.java index 4e6d4874698..59d3bfbec37 100644 --- a/forge-gui/src/main/java/forge/gamemodes/limited/LimitedDeckBuilder.java +++ b/forge-gui/src/main/java/forge/gamemodes/limited/LimitedDeckBuilder.java @@ -18,7 +18,6 @@ import forge.card.CardEdition; import forge.card.CardRules; import forge.card.CardRulesPredicates; import forge.card.ColorSet; -import forge.card.DeckHints; import forge.card.MagicColor; import forge.card.mana.ManaCost; import forge.card.mana.ManaCostShard; @@ -591,12 +590,10 @@ public class LimitedDeckBuilder extends DeckGeneratorBase { if (ai.getRemRandomDecks()) { final List comboCards = new ArrayList<>(); if (ai.getDeckNeeds() != null && ai.getDeckNeeds().isValid()) { - final DeckHints needs = ai.getDeckNeeds(); - comboCards.addAll(needs.filter(deckList)); + Iterables.addAll(comboCards, ai.getDeckNeeds().filter(deckList)); } if (ai.getDeckHints() != null && ai.getDeckHints().isValid()) { - final DeckHints hints = ai.getDeckHints(); - comboCards.addAll(hints.filter(deckList)); + Iterables.addAll(comboCards, ai.getDeckHints().filter(deckList)); } if (comboCards.isEmpty()) { if (logToConsole) { diff --git a/forge-gui/src/main/java/forge/gamemodes/match/input/InputConfirm.java b/forge-gui/src/main/java/forge/gamemodes/match/input/InputConfirm.java index ff638c30c50..be1484755c4 100644 --- a/forge-gui/src/main/java/forge/gamemodes/match/input/InputConfirm.java +++ b/forge-gui/src/main/java/forge/gamemodes/match/input/InputConfirm.java @@ -26,6 +26,7 @@ import forge.game.card.Card; import forge.game.card.CardView; import forge.game.spellability.SpellAbility; import forge.gui.GuiBase; +import forge.item.IPaperCard; import forge.localinstance.properties.ForgePreferences; import forge.model.FModel; import forge.player.PlayerControllerHuman; @@ -78,8 +79,12 @@ public class InputConfirm extends InputSyncronizedBase { return controller.getGui().confirm(null, message, defaultIsYes, options); if (sa.getTargets() != null && sa.getTargets().isTargetingAnyCard() && sa.getTargets().size() == 1) return controller.getGui().confirm((sa.getTargetCard()==null)?null:CardView.get(sa.getTargetCard()), message, defaultIsYes, options); - if (ApiType.Play.equals(sa.getApi()) && sa.getPlayEffectCard() != null) + if (ApiType.Play.equals(sa.getApi()) && sa.getPlayEffectCard() != null) { + IPaperCard iPaperCard = sa.getPlayEffectCard().getPaperCard(); + if (iPaperCard != null) //getcardforUI regardless of zone if it's hidden or not... + return controller.getGui().confirm(CardView.getCardForUi(iPaperCard), message, defaultIsYes, options); return controller.getGui().confirm(CardView.get(sa.getPlayEffectCard()), message, defaultIsYes, options); + } return controller.getGui().confirm(CardView.get(sa.getHostCard()), message, defaultIsYes, options); } else { InputConfirm inp; diff --git a/forge-gui/src/main/java/forge/player/HumanPlay.java b/forge-gui/src/main/java/forge/player/HumanPlay.java index 15d81f2c81a..c2f5b5cd4d8 100644 --- a/forge-gui/src/main/java/forge/player/HumanPlay.java +++ b/forge-gui/src/main/java/forge/player/HumanPlay.java @@ -236,7 +236,7 @@ public class HumanPlay { } // 0 mana costs were slipping through because CostPart.getAmount returns 1 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); } } @@ -438,7 +438,7 @@ public class HumanPlay { if (!hasPaid) { return false; } } 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; } }