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); + } + } + } +}