From 82b9a261421d818ce4b471b776a1dad90cd037b0 Mon Sep 17 00:00:00 2001
From: spjspj <spjspj4@gmail.com>
Date: Sat, 21 Apr 2018 18:32:28 +1000
Subject: [PATCH] Two more planes

---
 .../effects/common/RollPlanarDieEffect.java   |  10 +-
 Mage/src/main/java/mage/constants/Planes.java |   2 +
 .../command/planes/TheZephyrMazePlane.java    | 104 +++++++++++
 .../planes/TrailOfTheMageRingsPlane.java      | 166 ++++++++++++++++++
 4 files changed, 279 insertions(+), 3 deletions(-)
 create mode 100644 Mage/src/main/java/mage/game/command/planes/TheZephyrMazePlane.java
 create mode 100644 Mage/src/main/java/mage/game/command/planes/TrailOfTheMageRingsPlane.java

diff --git a/Mage/src/main/java/mage/abilities/effects/common/RollPlanarDieEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RollPlanarDieEffect.java
index bd02002b65..923075ef53 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/RollPlanarDieEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/RollPlanarDieEffect.java
@@ -179,9 +179,13 @@ public class RollPlanarDieEffect extends OneShotEffect {
         for (int i = 0; i < chaosEffects.size(); i++) {
             Effect effect = chaosEffects.get(i);
             if (effect != null) {
-                String emode = effect.getText(mode);
-                emode = emode.substring(0, 1).toLowerCase() + emode.substring(1);
-                sb.append(emode);
+                try { 
+                    String emode = effect.getText(mode);
+                    emode = emode.substring(0, 1).toLowerCase() + emode.substring(1);
+                    sb.append(emode);
+                } catch (Exception e) {
+                    sb.append("perform the CHAOS action");
+                }
             }
         }
         sb.append(".  If you roll PW, planeswalk to a new plane");
diff --git a/Mage/src/main/java/mage/constants/Planes.java b/Mage/src/main/java/mage/constants/Planes.java
index 4ea9df74cd..3b8749d38a 100644
--- a/Mage/src/main/java/mage/constants/Planes.java
+++ b/Mage/src/main/java/mage/constants/Planes.java
@@ -46,7 +46,9 @@ public enum Planes {
     PLANE_TAZEEM("TazeemPlane"),
     PLANE_THE_DARK_BARONY("TheDarkBaronyPlane"),
     PLANE_THE_EON_FOG("TheEonFogPlane"),
+    PLANE_THE_ZEPHYR_MAZE_FOG("TheZephyrMazePlane"),
     PLANE_TRUGA_JUNGLE("TrugaJunglePlane"),
+    PLANE_TRAIL_OF_THE_MAGE_RINGS("TrailOfTheMageRingsPlane"),
     PLANE_TURRI_ISLAND("TurriIslandPlane"),
     PLANE_UNDERCITY_REACHES("UndercityReachesPlane");
     
diff --git a/Mage/src/main/java/mage/game/command/planes/TheZephyrMazePlane.java b/Mage/src/main/java/mage/game/command/planes/TheZephyrMazePlane.java
new file mode 100644
index 0000000000..e401724eb8
--- /dev/null
+++ b/Mage/src/main/java/mage/game/command/planes/TheZephyrMazePlane.java
@@ -0,0 +1,104 @@
+/*
+ *  Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without modification, are
+ *  permitted provided that the following conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above copyright notice, this list of
+ *        conditions and the following disclaimer.
+ *
+ *     2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *        of conditions and the following disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ..AS IS.. AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ *  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ *  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  The views and conclusions contained in the software and documentation are those of the
+ *  authors and should not be interpreted as representing official policies, either expressed
+ *  or implied, of BetaSteward_at_googlemail.com.
+ */
+package mage.game.command.planes;
+
+import java.util.ArrayList;
+import java.util.List;
+import mage.abilities.Ability;
+import mage.abilities.common.ActivateIfConditionActivatedAbility;
+import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.condition.common.IsStillOnPlaneCondition;
+import mage.abilities.condition.common.MainPhaseStackEmptyCondition;
+import mage.abilities.costs.mana.GenericManaCost;
+import mage.abilities.decorator.ConditionalContinuousEffect;
+import mage.abilities.effects.Effect;
+import mage.abilities.effects.common.RollPlanarDieEffect;
+import mage.abilities.effects.common.continuous.BoostAllEffect;
+import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
+import mage.abilities.keyword.FlyingAbility;
+import mage.constants.Duration;
+import mage.constants.TargetController;
+import mage.constants.Zone;
+import mage.filter.common.FilterCreaturePermanent;
+import mage.filter.predicate.Predicates;
+import mage.filter.predicate.mageobject.AbilityPredicate;
+import mage.game.command.Plane;
+import mage.target.Target;
+import mage.target.common.TargetCreaturePermanent;
+import mage.watchers.common.PlanarRollWatcher;
+
+/**
+ *
+ * @author spjspj
+ */
+public class TheZephyrMazePlane extends Plane {
+
+    private static final FilterCreaturePermanent filter1 = new FilterCreaturePermanent("creatures with flying");
+    private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("creatures without flying");
+
+    static {
+        filter1.add(new AbilityPredicate(FlyingAbility.class));
+        filter2.add(Predicates.not(new AbilityPredicate(FlyingAbility.class)));
+    }
+
+    private static final String flyingRule = "Creatures with flying get +2/+0";
+    private static final String walkingRule = "Creatures without flying get -2/-0";
+
+    public TheZephyrMazePlane() {
+        this.setName("Plane - The Zephyr Maze");
+        this.setExpansionSetCodeForImage("PCA");
+
+        // Creatures with flying get +2/+0
+        // Creatures without flying get -2/+0
+        Ability ability = new SimpleStaticAbility(Zone.COMMAND, new ConditionalContinuousEffect(
+                new BoostAllEffect(2, 0, Duration.WhileOnBattlefield, filter1, false),
+                new IsStillOnPlaneCondition(this.getName()),
+                flyingRule));
+        this.getAbilities().add(ability);
+        Ability ability2 = new SimpleStaticAbility(Zone.COMMAND, new ConditionalContinuousEffect(
+                new BoostAllEffect(-2, 0, Duration.WhileOnBattlefield, filter2, false),
+                new IsStillOnPlaneCondition(this.getName()),
+                walkingRule));
+        this.getAbilities().add(ability2);
+
+        // Active player can roll the planar die: Whenever you roll {CHAOS}, target creature gains flying until end of turn
+        Effect chaosEffect = new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn);        
+        Target chaosTarget = new TargetCreaturePermanent(0, 1);
+
+        List<Effect> chaosEffects = new ArrayList<Effect>();
+        chaosEffects.add(chaosEffect);
+        List<Target> chaosTargets = new ArrayList<Target>();
+        chaosTargets.add(chaosTarget);
+
+        ActivateIfConditionActivatedAbility chaosAbility = new ActivateIfConditionActivatedAbility(Zone.COMMAND, new RollPlanarDieEffect(chaosEffects, chaosTargets), new GenericManaCost(0), MainPhaseStackEmptyCondition.instance);
+        chaosAbility.addWatcher(new PlanarRollWatcher());
+        this.getAbilities().add(chaosAbility);
+        chaosAbility.setMayActivate(TargetController.ANY);
+        this.getAbilities().add(new SimpleStaticAbility(Zone.ALL, new PlanarDieRollCostIncreasingEffect(chaosAbility.getOriginalId())));
+    }
+}
diff --git a/Mage/src/main/java/mage/game/command/planes/TrailOfTheMageRingsPlane.java b/Mage/src/main/java/mage/game/command/planes/TrailOfTheMageRingsPlane.java
new file mode 100644
index 0000000000..cc8909f532
--- /dev/null
+++ b/Mage/src/main/java/mage/game/command/planes/TrailOfTheMageRingsPlane.java
@@ -0,0 +1,166 @@
+/*
+ *  Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without modification, are
+ *  permitted provided that the following conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above copyright notice, this list of
+ *        conditions and the following disclaimer.
+ *
+ *     2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *        of conditions and the following disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ..AS IS.. AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ *  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ *  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  The views and conclusions contained in the software and documentation are those of the
+ *  authors and should not be interpreted as representing official policies, either expressed
+ *  or implied, of BetaSteward_at_googlemail.com.
+ */
+package mage.game.command.planes;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.UUID;
+import mage.abilities.Ability;
+import mage.abilities.common.ActivateIfConditionActivatedAbility;
+import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.condition.common.MainPhaseStackEmptyCondition;
+import mage.abilities.costs.mana.GenericManaCost;
+import mage.abilities.effects.ContinuousEffectImpl;
+import mage.abilities.effects.Effect;
+import mage.abilities.effects.common.RollPlanarDieEffect;
+import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
+import mage.abilities.keyword.ReboundAbility;
+import mage.cards.Card;
+import mage.constants.CardType;
+import mage.constants.Duration;
+import mage.constants.Layer;
+import mage.constants.Outcome;
+import mage.constants.SubLayer;
+import mage.constants.TargetController;
+import mage.constants.Zone;
+import mage.filter.FilterCard;
+import mage.filter.common.FilterInstantOrSorceryCard;
+import mage.filter.predicate.Predicates;
+import mage.filter.predicate.mageobject.CardTypePredicate;
+import mage.game.Game;
+import mage.game.command.Plane;
+import mage.game.stack.Spell;
+import mage.game.stack.StackObject;
+import mage.players.Player;
+import mage.target.Target;
+import mage.target.common.TargetCardInLibrary;
+import mage.watchers.common.PlanarRollWatcher;
+
+/**
+ *
+ * @author spjspj
+ */
+public class TrailOfTheMageRingsPlane extends Plane {
+
+    private static final FilterCard filter = new FilterCard("creature spells");
+
+    static {
+        filter.add(new CardTypePredicate(CardType.CREATURE));
+    }
+
+    public TrailOfTheMageRingsPlane() {
+        this.setName("Plane - Trail of the Mage-Rings");
+        this.setExpansionSetCodeForImage("PCA");
+
+        // Instant and sorcery spells have rebound
+        Ability ability = new SimpleStaticAbility(Zone.COMMAND, new TrailOfTheMageRingsReboundEffect());
+        this.getAbilities().add(ability);
+
+        // Active player can roll the planar die: Whenever you roll {CHAOS}, you may search your library for an instant or sorcery card, reveal it, put it into your hand, then shuffle your library
+        Effect chaosEffect = new SearchLibraryPutInHandEffect(new TargetCardInLibrary(0, 1, new FilterInstantOrSorceryCard()), true, true);
+        Target chaosTarget = null;
+
+        List<Effect> chaosEffects = new ArrayList<Effect>();
+        chaosEffects.add(chaosEffect);
+        List<Target> chaosTargets = new ArrayList<Target>();
+        chaosTargets.add(chaosTarget);
+
+        ActivateIfConditionActivatedAbility chaosAbility = new ActivateIfConditionActivatedAbility(Zone.COMMAND, new RollPlanarDieEffect(chaosEffects, chaosTargets), new GenericManaCost(0), MainPhaseStackEmptyCondition.instance);
+        chaosAbility.addWatcher(new PlanarRollWatcher());
+        this.getAbilities().add(chaosAbility);
+        chaosAbility.setMayActivate(TargetController.ANY);
+        this.getAbilities().add(new SimpleStaticAbility(Zone.ALL, new PlanarDieRollCostIncreasingEffect(chaosAbility.getOriginalId())));
+    }
+}
+
+class TrailOfTheMageRingsReboundEffect extends ContinuousEffectImpl {
+
+    protected static final FilterCard filter = new FilterCard("Instant and sorcery spells");
+
+    static {
+        filter.add(Predicates.or(new CardTypePredicate(CardType.INSTANT), new CardTypePredicate(CardType.SORCERY)));
+    }
+
+    public TrailOfTheMageRingsReboundEffect() {
+        super(Duration.Custom, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
+        staticText = "Instant and sorcery spells have rebound";
+    }
+
+    public TrailOfTheMageRingsReboundEffect(final TrailOfTheMageRingsReboundEffect effect) {
+        super(effect);
+    }
+
+    @Override
+    public TrailOfTheMageRingsReboundEffect copy() {
+        return new TrailOfTheMageRingsReboundEffect(this);
+    }
+
+    @Override
+    public boolean apply(Game game, Ability source) {
+        Plane cPlane = game.getState().getCurrentPlane();
+        if (cPlane == null) {
+            return false;
+        }
+        if (cPlane != null) {
+            if (!cPlane.getName().equalsIgnoreCase("Plane - Trail of the Mage-Rings")) {
+                return false;
+            }
+        }
+
+        for (UUID playerId : game.getPlayers().keySet()) {
+            Player player = game.getPlayer(playerId);
+            if (player != null) {
+                for (Card card : player.getHand().getCards(filter, game)) {
+                    addReboundAbility(card, source, game);
+                }
+                for (Iterator<StackObject> iterator = game.getStack().iterator(); iterator.hasNext();) {
+                    StackObject stackObject = iterator.next();
+                    if (stackObject instanceof Spell && stackObject.getControllerId().equals(source.getControllerId())) {
+                        Spell spell = (Spell) stackObject;
+                        Card card = spell.getCard();
+                        if (card != null) {
+                            addReboundAbility(card, source, game);
+                        }
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    private void addReboundAbility(Card card, Ability source, Game game) {
+        if (filter.match(card, game)) {
+            boolean found = card.getAbilities().stream().anyMatch(ability -> ability instanceof ReboundAbility);
+            if (!found) {
+                Ability ability = new ReboundAbility();
+                game.getState().addOtherAbility(card, ability);
+            }
+        }
+    }
+}