From d890ee248cb0f418624a55250b83f80c394d7c0b Mon Sep 17 00:00:00 2001 From: Hanmac Date: Thu, 28 Jun 2018 22:40:16 +0200 Subject: [PATCH 1/5] CardFacePredicate: use new valid Predicate --- .../java/forge/card/CardFacePredicates.java | 45 +++++++++++++++++++ .../ability/effects/ChooseCardNameEffect.java | 13 +----- 2 files changed, 47 insertions(+), 11 deletions(-) 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/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); From eafc717dd88029dbb248bda151793c93ae429f8e Mon Sep 17 00:00:00 2001 From: Agetian Date: Fri, 29 Jun 2018 08:08:03 +0300 Subject: [PATCH 2/5] - GuiChoose (desktop Forge): show the right card face in the card detail panel when choosing a card name. --- .../src/main/java/forge/gui/GuiChoose.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) 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..768c5192008 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,24 @@ 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()); + } + } + if (!foundState) { + matchUI.setCard(paper); + } + } else { + matchUI.setCard(paper); + } + return; } From 543450d859eb368c445a44d6904898282ef5036a Mon Sep 17 00:00:00 2001 From: Hanmac Date: Fri, 29 Jun 2018 07:15:28 +0200 Subject: [PATCH 3/5] TriggerChangesZone: add ValidCause parameter --- .../src/main/java/forge/game/GameAction.java | 1 + .../game/trigger/TriggerChangesZone.java | 57 +++++++++++-------- .../upcoming/viviens_invocation.txt | 8 +++ 3 files changed, 43 insertions(+), 23 deletions(-) create mode 100644 forge-gui/res/cardsfolder/upcoming/viviens_invocation.txt 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/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/res/cardsfolder/upcoming/viviens_invocation.txt b/forge-gui/res/cardsfolder/upcoming/viviens_invocation.txt new file mode 100644 index 00000000000..d15f0f26306 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/viviens_invocation.txt @@ -0,0 +1,8 @@ +Name:Vivien's Invocation +ManaCost:5 G G +Types:Sorcery +A:SP$ Dig | Cost$ 5 G G | DigNum$ 7 | ChangeNum$ 1 | ChangeValid$ Creature | Optional$ True | RestRandomOrder$ True | DestinationZone$ Battlefield | 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. From 046f1019f5ea46909980aefb54afd1dfc8da9cfa Mon Sep 17 00:00:00 2001 From: Agetian Date: Fri, 29 Jun 2018 08:43:14 +0300 Subject: [PATCH 4/5] - Vivien's Invocation: force reveal to controller (for "Look at the top seven cards..."). --- forge-gui/res/cardsfolder/upcoming/viviens_invocation.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge-gui/res/cardsfolder/upcoming/viviens_invocation.txt b/forge-gui/res/cardsfolder/upcoming/viviens_invocation.txt index d15f0f26306..ef44e9133a7 100644 --- a/forge-gui/res/cardsfolder/upcoming/viviens_invocation.txt +++ b/forge-gui/res/cardsfolder/upcoming/viviens_invocation.txt @@ -1,7 +1,7 @@ Name:Vivien's Invocation ManaCost:5 G G Types:Sorcery -A:SP$ Dig | Cost$ 5 G G | DigNum$ 7 | ChangeNum$ 1 | ChangeValid$ Creature | Optional$ True | RestRandomOrder$ True | DestinationZone$ Battlefield | 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. +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 From fe49c460eb00c9065d105beeaca62a0a7814ca4d Mon Sep 17 00:00:00 2001 From: Agetian Date: Fri, 29 Jun 2018 08:55:41 +0300 Subject: [PATCH 5/5] - Added a break statement to GuiChoose. --- forge-gui-desktop/src/main/java/forge/gui/GuiChoose.java | 1 + 1 file changed, 1 insertion(+) 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 768c5192008..ccff647a248 100644 --- a/forge-gui-desktop/src/main/java/forge/gui/GuiChoose.java +++ b/forge-gui-desktop/src/main/java/forge/gui/GuiChoose.java @@ -175,6 +175,7 @@ public class GuiChoose { foundState = true; c.setState(cs, true); matchUI.setCard(c.getView()); + break; } } if (!foundState) {