diff --git a/forge-core/src/main/java/forge/card/CardFacePredicates.java b/forge-core/src/main/java/forge/card/CardFacePredicates.java index 80209bb43b1..ee83dda3787 100644 --- a/forge-core/src/main/java/forge/card/CardFacePredicates.java +++ b/forge-core/src/main/java/forge/card/CardFacePredicates.java @@ -76,6 +76,51 @@ public final class CardFacePredicates { }; } + static class ValidPredicate implements Predicate { + private String valid; + + public ValidPredicate(final String valid) { + this.valid = valid; + } + + @Override + public boolean apply(ICardFace input) { + String k[] = valid.split("\\.", 2); + + if ("Card".equals(k[0])) { + // okay + } else if ("Permanent".equals(k[0])) { + if (input.getType().isInstant() || input.getType().isSorcery()) { + return false; + } + } else if (!input.getType().hasStringType(k[0])) { + return false; + } + if (k.length > 1) { + for (final String m : k[1].split("\\+")) { + if (!hasProperty(input, m)) { + return false; + } + } + } + + return true; + } + + static protected boolean hasProperty(ICardFace input, final String v) { + if (v.startsWith("non")) { + return !hasProperty(input, v.substring(3)); + } else if (!input.getType().hasStringType(v)) { + return false; + } + return true; + } + } + + public static Predicate valid(final String val) { + return new ValidPredicate(val); + } + public static class Presets { /** The Constant isBasicLand. */ public static final Predicate IS_BASIC_LAND = new Predicate() { diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index 9b16dafe2b1..cf44f0511ff 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -368,6 +368,7 @@ public class GameAction { final Map runParams = Maps.newHashMap(); runParams.put("Card", lastKnownInfo); + runParams.put("Cause", cause); runParams.put("Origin", zoneFrom != null ? zoneFrom.getZoneType().name() : null); runParams.put("Destination", zoneTo.getZoneType().name()); runParams.put("SpellAbilityStackInstance", game.stack.peek()); diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChooseCardNameEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChooseCardNameEffect.java index 7e35b96c0ca..4938ecb370e 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChooseCardNameEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChooseCardNameEffect.java @@ -105,17 +105,8 @@ public class ChooseCardNameEffect extends SpellAbilityEffect { final String message = validDesc.equals("card") ? "Name a card" : "Name a " + validDesc + " card."; Predicate cpp = Predicates.alwaysTrue(); - if ( StringUtils.containsIgnoreCase(valid, "nonland") ) { - cpp = CardFacePredicates.Presets.IS_NON_LAND; - } - if ( StringUtils.containsIgnoreCase(valid, "nonbasic") ) { - cpp = Predicates.not(CardFacePredicates.Presets.IS_BASIC_LAND); - } - - if ( StringUtils.containsIgnoreCase(valid, "noncreature") ) { - cpp = Predicates.not(CardFacePredicates.Presets.IS_CREATURE); - } else if ( StringUtils.containsIgnoreCase(valid, "creature") ) { - cpp = CardFacePredicates.Presets.IS_CREATURE; + if (sa.hasParam("ValidCards")) { + cpp = CardFacePredicates.valid(valid); } chosen = p.getController().chooseCardName(sa, cpp, valid, message); diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerChangesZone.java b/forge-game/src/main/java/forge/game/trigger/TriggerChangesZone.java index c24949f9e5a..ba02572e480 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerChangesZone.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerChangesZone.java @@ -65,57 +65,68 @@ public class TriggerChangesZone extends Trigger { /** {@inheritDoc} */ @Override - public final boolean performTest(final java.util.Map runParams2) { - if (this.mapParams.containsKey("Origin")) { - if (!this.mapParams.get("Origin").equals("Any")) { - if (this.mapParams.get("Origin") == null) { + public final boolean performTest(final Map runParams2) { + if (hasParam("Origin")) { + if (!getParam("Origin").equals("Any")) { + if (getParam("Origin") == null) { return false; } if (!ArrayUtils.contains( - this.mapParams.get("Origin").split(","), runParams2.get("Origin") + getParam("Origin").split(","), runParams2.get("Origin") )) { return false; } } } - if (this.mapParams.containsKey("Destination")) { - if (!this.mapParams.get("Destination").equals("Any")) { + if (hasParam("Destination")) { + if (!getParam("Destination").equals("Any")) { if (!ArrayUtils.contains( - this.mapParams.get("Destination").split(","), runParams2.get("Destination") + getParam("Destination").split(","), runParams2.get("Destination") )) { return false; } } } - if (this.mapParams.containsKey("ExcludedDestinations")) { + if (hasParam("ExcludedDestinations")) { if (!ArrayUtils.contains( - this.mapParams.get("ExcludedDestinations").split(","), runParams2.get("Destination") + getParam("ExcludedDestinations").split(","), runParams2.get("Destination") )) { return false; } } - if (this.mapParams.containsKey("ValidCard")) { + if (hasParam("ValidCard")) { Card moved = (Card) runParams2.get("Card"); - final Game game = this.getHostCard().getGame(); - boolean isDiesTrig = "Battlefield".equals(this.mapParams.get("Origin")) - && "Graveyard".equals(this.mapParams.get("Destination")); + final Game game = getHostCard().getGame(); + boolean isDiesTrig = "Battlefield".equals(getParam("Origin")) + && "Graveyard".equals(getParam("Destination")); if (isDiesTrig) { moved = game.getChangeZoneLKIInfo(moved); } - if (!moved.isValid(this.mapParams.get("ValidCard").split(","), this.getHostCard().getController(), - this.getHostCard(), null)) { + if (!moved.isValid(getParam("ValidCard").split(","), getHostCard().getController(), + getHostCard(), null)) { + return false; + } + } + + if (hasParam("ValidCause")) { + if (!runParams2.containsKey("Cause") ) { + return false; + } + SpellAbility cause = (SpellAbility) runParams2.get("Cause"); + if (!cause.getHostCard().isValid(getParam("ValidCause").split(","), getHostCard().getController(), + getHostCard(), null)) { return false; } } // Check number of lands ETB this turn on triggered card's controller - if (mapParams.containsKey("CheckOnTriggeredCard")) { - final String[] condition = mapParams.get("CheckOnTriggeredCard").split(" ", 2); + if (hasParam("CheckOnTriggeredCard")) { + final String[] condition = getParam("CheckOnTriggeredCard").split(" ", 2); final Card host = hostCard.getGame().getCardState(hostCard); final String comparator = condition.length < 2 ? "GE1" : condition[1]; @@ -128,8 +139,8 @@ public class TriggerChangesZone extends Trigger { } // Check amount of damage dealt to the triggered card - if (this.mapParams.containsKey("DamageReceivedCondition")) { - final String cond = this.mapParams.get("DamageReceivedCondition"); + if (hasParam("DamageReceivedCondition")) { + final String cond = getParam("DamageReceivedCondition"); if (cond.length() < 3) { return false; } @@ -152,7 +163,7 @@ public class TriggerChangesZone extends Trigger { } } - if (this.mapParams.containsKey("OncePerEffect")) { + if (hasParam("OncePerEffect")) { // A "once per effect" trigger will only trigger once regardless of how many things the effect caused // to change zones. @@ -184,8 +195,8 @@ public class TriggerChangesZone extends Trigger { } /* this trigger can only be activated once per turn, verify it hasn't already run */ - if (this.mapParams.containsKey("ActivationLimit")) { - return this.getActivationsThisTurn() < Integer.parseInt(this.mapParams.get("ActivationLimit")); + if (hasParam("ActivationLimit")) { + return this.getActivationsThisTurn() < Integer.parseInt(getParam("ActivationLimit")); } return true; diff --git a/forge-gui-desktop/src/main/java/forge/gui/GuiChoose.java b/forge-gui-desktop/src/main/java/forge/gui/GuiChoose.java index 5a4757b92a7..ccff647a248 100644 --- a/forge-gui-desktop/src/main/java/forge/gui/GuiChoose.java +++ b/forge-gui-desktop/src/main/java/forge/gui/GuiChoose.java @@ -13,6 +13,7 @@ import javax.swing.WindowConstants; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; +import forge.card.CardStateName; import org.apache.commons.lang3.StringUtils; import com.google.common.base.Function; @@ -165,7 +166,25 @@ public class GuiChoose { if (paper == null) { paper = FModel.getMagicDb().getVariantCards().getUniqueByName(face.getName()); } - matchUI.setCard(paper); + + if (paper != null && !paper.getName().equals(face.getName())) { + Card c = Card.getCardForUi(paper); + boolean foundState = false; + for (CardStateName cs : c.getStates()) { + if (c.getState(cs).getName().equals(face.getName())) { + foundState = true; + c.setState(cs, true); + matchUI.setCard(c.getView()); + break; + } + } + if (!foundState) { + matchUI.setCard(paper); + } + } else { + matchUI.setCard(paper); + } + return; } diff --git a/forge-gui/res/cardsfolder/upcoming/viviens_invocation.txt b/forge-gui/res/cardsfolder/upcoming/viviens_invocation.txt index 4a29089012b..f9ce13877ce 100644 --- a/forge-gui/res/cardsfolder/upcoming/viviens_invocation.txt +++ b/forge-gui/res/cardsfolder/upcoming/viviens_invocation.txt @@ -1,11 +1,8 @@ Name:Vivien's Invocation ManaCost:5 G G Types:Sorcery -A:SP$ PeekAndReveal | Cost$ 4 G G | PeekAmount$ 7 | RememberPeeked$ True | SubAbility$ DBChangeZone | OptionalDecider$ You | Look at the top seven cards of your library. You may put a creature card from among them onto the battlefield. Put the rest on the bottom of your library in a random order. When a creature is put onto the battlefield this way, it deals damage equal to its power to target creature an opponent controls. -SVar:DBEffect:DB$ Effect | Name$ Vivien's Invocation Effect | Triggers$ EffTModeChangesZone | RememberObjects$ Remembered.Creature | SVars$ EffTrigDealDamage,EffX | Description$ When a creature is put onto the battlefield this way, it deals damage equal to its power to target creature an opponent controls. | SubAbility$ DBChangeZone -SVar:DBChangeZone:DB$ ChangeZone | Origin$ Library | NoLooking$ True | Destination$ Battlefield | LimitSearchLibrary$ Creature.IsRemembered | ChangeValid$ Creature.IsRemembered | Controller$ You | WithoutManaCost$ True | Amount$ 1 | SubAbility$ DBRestRandomOrder -SVar:DBRestRandomOrder:DB$ ChangeZone | Defined$ Remembered | AtRandom$ True | Origin$ Library | Destination$ Library | LibraryPosition$ -1 -SVar:EffTModeChangesZone:Mode$ ChangesZone | ValidCard$ Remembered.Creature | TriggerZones$ Stack | Origin$ Library | Destination$ Battlefield | SubAbility$ EffTrigDealDamage | TriggerDescription$ When a creature is put onto the battlefield this way, it deals damage equal to its power to target creature an opponent controls. -SVar:EffTrigDealDamage:DB$ DealDamage | ValidSource$ Remembered+inZoneBattlefield | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | NumDmg$ EffX | References$ EffX -SVar:EffX:RememberedCard$CardPower -Oracle:Look at the top seven cards of your library. You may put a creature card from among them onto the battlefield. Put the rest on the bottom of your library in a random order. When a creature is put onto the battlefield this way, it deals damage equal to its power to target creature an opponent controls. \ No newline at end of file +A:SP$ Dig | Cost$ 5 G G | DigNum$ 7 | ChangeNum$ 1 | ChangeValid$ Creature | Optional$ True | RestRandomOrder$ True | DestinationZone$ Battlefield | ForceRevealToController$ True | SpellDescription$ Look at the top seven cards of your library. You may put a creature card from among them onto the battlefield. Put the rest on the bottom of your library in a random order. When a creature is put onto the battlefield this way, it deals damage equals to its power to target creature an opponent controls. +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature | ValidCause$ Card.Self | Execute$ DBDealDamage | Secondary$ True | TriggerDescription$ When a creature is put onto the battlefield this way, it deals damage equals to its power to target creature an opponent controls. +SVar:DBDealDamage:DB$ DealDamage | ValidTgts$ Creature.OppCtrl | AILogic$ PowerDmg | TgtPrompt$ Select target creature an opponent controls | NumDmg$ X | References$ X | DamageSource$ TriggeredCard +SVar:X:TriggeredCard$CardPower +Oracle:Look at the top seven cards of your library. You may put a creature card from among them onto the battlefield. Put the rest on the bottom of your library in a random order. When a creature is put onto the battlefield this way, it deals damage equals to its power to target creature an opponent controls. \ No newline at end of file