From 007b9cd849666ce6205fbdec2cf58d6414d5f5e6 Mon Sep 17 00:00:00 2001 From: spjspj Date: Thu, 20 Jul 2017 18:35:30 +1000 Subject: [PATCH 1/6] Fix Magnetic Mountain (ARN) --- .../src/mage/cards/m/MagneticMountain.java | 95 +++++++++---------- 1 file changed, 46 insertions(+), 49 deletions(-) diff --git a/Mage.Sets/src/mage/cards/m/MagneticMountain.java b/Mage.Sets/src/mage/cards/m/MagneticMountain.java index 8cea715903d..2d637afb763 100644 --- a/Mage.Sets/src/mage/cards/m/MagneticMountain.java +++ b/Mage.Sets/src/mage/cards/m/MagneticMountain.java @@ -27,51 +27,50 @@ */ package mage.cards.m; +import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.Mode; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DontUntapInControllersUntapStepAllEffect; -import mage.abilities.effects.common.UntapEnchantedEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import static mage.cards.m.MagneticMountain.filter; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.Outcome; import mage.constants.TargetController; import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.ObjectPlayer; -import mage.filter.predicate.ObjectPlayerPredicate; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; - -import java.util.UUID; - - +import mage.target.Target; +import mage.target.common.TargetControlledCreaturePermanent; /** * * @author MarcoMarin */ public class MagneticMountain extends CardImpl { - + static final FilterCreaturePermanent filter = new FilterCreaturePermanent("blue creatures"); - + static { filter.add(new ColorPredicate(ObjectColor.BLUE)); } - + public MagneticMountain(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}{R}"); // Blue creatures don't untap during their controllers' untap steps. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, - new DontUntapInControllersUntapStepAllEffect(Duration.WhileOnBattlefield, TargetController.ANY, filter))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DontUntapInControllersUntapStepAllEffect(Duration.WhileOnBattlefield, TargetController.ANY, filter))); + // At the beginning of each player's upkeep, that player may choose any number of tapped blue creatures he or she controls and pay {4} for each creature chosen this way. If the player does, untap those creatures. this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new MagneticMountainEffect(), TargetController.ANY, false)); } @@ -85,13 +84,22 @@ public class MagneticMountain extends CardImpl { return new MagneticMountain(this); } } -class MagneticMountainEffect extends DoIfCostPaid { - public MagneticMountainEffect(){ - super(new UntapEnchantedEffect(), new GenericManaCost(4)); +class MagneticMountainEffect extends OneShotEffect { + + private static final FilterControlledCreaturePermanent filter2 = new FilterControlledCreaturePermanent("tapped blue creature"); + + static { + filter2.add(new ColorPredicate(ObjectColor.BLUE)); + filter2.add(new TappedPredicate()); } - public MagneticMountainEffect(final MagneticMountainEffect effect) { + MagneticMountainEffect() { + super(Outcome.Benefit); + staticText = "that player may choose any number of tapped blue creatures he or she controls and pay {4} for each creature chosen this way. If the player does, untap those creatures."; + } + + MagneticMountainEffect(MagneticMountainEffect effect) { super(effect); } @@ -100,38 +108,27 @@ class MagneticMountainEffect extends DoIfCostPaid { return new MagneticMountainEffect(this); } - @Override - protected Player getPayingPlayer(Game game, Ability source) { - return game.getPlayer(game.getActivePlayerId()); - } - - @Override - public String getText(Mode mode) { - return new StringBuilder("that player may ").append(getCostText()) - .append(". If he or she does, ").append(executingEffects.getText(mode)).toString(); - } - @Override public boolean apply(Game game, Ability source) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("blue creatures"); - filter.add(new ColorPredicate(ObjectColor.BLUE)); - filter.add(new MagneticMountainPredicate()); - - if (!game.getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game).isEmpty()){ - this.copy(); + + Player player = game.getPlayer(targetPointer.getFirst(game, source)); + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (player != null && sourcePermanent != null) { + int countBattlefield = game.getBattlefield().getAllActivePermanents(filter2, game.getActivePlayerId(), game).size(); + while (player.canRespond() && countBattlefield > 0 && player.chooseUse(Outcome.AIDontUseIt, "Pay {4} and untap a tapped blue creature under your control?", source, game)) { + Target tappedCreatureTarget = new TargetControlledCreaturePermanent(1, 1, filter2, true); + if (player.choose(Outcome.Detriment, tappedCreatureTarget, source.getSourceId(), game)) { + GenericManaCost cost = new GenericManaCost(4); + Permanent tappedCreature = game.getPermanent(tappedCreatureTarget.getFirstTarget()); + + if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { + tappedCreature.untap(game); + } + } + countBattlefield = game.getBattlefield().getAllActivePermanents(filter2, game.getActivePlayerId(), game).size(); + } + return true; } - return true; - - } - static class MagneticMountainPredicate implements ObjectPlayerPredicate> { - @Override - public boolean apply(ObjectPlayer input, Game game) { - return input.getObject().isTapped(); - - } - @Override - public String toString() { - return "Tapped"; + return false; } } -} \ No newline at end of file From ce1ff40ca0653684358bf46b4f51e6d8c92c588e Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 20 Jul 2017 11:03:02 -0500 Subject: [PATCH 2/6] - Null check added --- Mage.Sets/src/mage/cards/m/MindsDesire.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/cards/m/MindsDesire.java b/Mage.Sets/src/mage/cards/m/MindsDesire.java index 655f5a86c7f..213fc9ec8f7 100644 --- a/Mage.Sets/src/mage/cards/m/MindsDesire.java +++ b/Mage.Sets/src/mage/cards/m/MindsDesire.java @@ -134,11 +134,14 @@ class MindsDesireCastFromExileEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { UUID targetId = getTargetPointer().getFirst(game, source); - if (targetId != null && targetId.equals(sourceId)) { + Player player = game.getPlayer(affectedControllerId); + if (targetId != null + && targetId.equals(sourceId) + && player != null) { if (affectedControllerId.equals(source.getControllerId())) { Card card = game.getCard(sourceId); - if (card != null && game.getState().getZone(sourceId) == Zone.EXILED) { - Player player = game.getPlayer(affectedControllerId); + if (card != null + && game.getState().getZone(sourceId) == Zone.EXILED) { player.setCastSourceIdWithAlternateMana(sourceId, null, card.getSpellAbility().getCosts()); return true; } From 44e85ca35168d00912a65337ab107698d5103fd3 Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 20 Jul 2017 11:09:59 -0500 Subject: [PATCH 3/6] - Refactor Past In Flames --- Mage.Sets/src/mage/cards/p/PastInFlames.java | 39 +++++++++----------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/Mage.Sets/src/mage/cards/p/PastInFlames.java b/Mage.Sets/src/mage/cards/p/PastInFlames.java index 515b8e3f73d..2eeb46e2829 100644 --- a/Mage.Sets/src/mage/cards/p/PastInFlames.java +++ b/Mage.Sets/src/mage/cards/p/PastInFlames.java @@ -95,12 +95,9 @@ class PastInFlamesEffect extends ContinuousEffectImpl { if (this.affectedObjectsSet) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - for (UUID cardId: player.getGraveyard()) { - Card card = game.getCard(cardId); - if (card.isInstant() || card.isSorcery()) { - affectedObjectList.add(new MageObjectReference(card, game)); - } - } + player.getGraveyard().stream().map((cardId) -> game.getCard(cardId)).filter((card) -> (card.isInstant() || card.isSorcery())).forEachOrdered((card) -> { + affectedObjectList.add(new MageObjectReference(card, game)); + }); } } } @@ -109,23 +106,21 @@ class PastInFlamesEffect extends ContinuousEffectImpl { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - for (UUID cardId: player.getGraveyard()) { - if (affectedObjectList.contains(new MageObjectReference(cardId, game))) { - Card card = game.getCard(cardId); - FlashbackAbility ability = null; - if (card.isInstant()) { - ability = new FlashbackAbility(card.getManaCost(), TimingRule.INSTANT); - } - else if (card.isSorcery()) { - ability = new FlashbackAbility(card.getManaCost(), TimingRule.SORCERY); - } - if (ability != null) { - ability.setSourceId(cardId); - ability.setControllerId(card.getOwnerId()); - game.getState().addOtherAbility(card, ability); - } + player.getGraveyard().stream().filter((cardId) -> (affectedObjectList.contains(new MageObjectReference(cardId, game)))).forEachOrdered((cardId) -> { + Card card = game.getCard(cardId); + FlashbackAbility ability = null; + if (card.isInstant()) { + ability = new FlashbackAbility(card.getManaCost(), TimingRule.INSTANT); } - } + else if (card.isSorcery()) { + ability = new FlashbackAbility(card.getManaCost(), TimingRule.SORCERY); + } + if (ability != null) { + ability.setSourceId(cardId); + ability.setControllerId(card.getOwnerId()); + game.getState().addOtherAbility(card, ability); + } + }); return true; } return false; From 7ffcf39260a01cf748e58eda0ec4de46b19ee861 Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 20 Jul 2017 11:15:58 -0500 Subject: [PATCH 4/6] - Added requested card Volcano Hellion. --- .../src/mage/cards/v/VolcanoHellion.java | 111 ++++++++++++++++++ Mage.Sets/src/mage/sets/PlanarChaos.java | 1 + .../mage/abilities/keyword/EchoAbility.java | 106 +++++++++++------ 3 files changed, 184 insertions(+), 34 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/v/VolcanoHellion.java diff --git a/Mage.Sets/src/mage/cards/v/VolcanoHellion.java b/Mage.Sets/src/mage/cards/v/VolcanoHellion.java new file mode 100644 index 00000000000..d8d9dffdd51 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VolcanoHellion.java @@ -0,0 +1,111 @@ +/* + * 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.cards.v; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.ControllerLifeCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.EchoAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author jeffwadsworth + */ +public class VolcanoHellion extends CardImpl { + + public VolcanoHellion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + + this.subtype.add("Hellion"); + this.power = new MageInt(6); + this.toughness = new MageInt(5); + + // Volcano Hellion has echo {X}, where X is your life total. + this.addAbility(new EchoAbility(new ControllerLifeCount(), "{this} has echo {X}, where X is your life total.")); + + // When Volcano Hellion enters the battlefield, it deals an amount of damage of your choice to you and target creature. The damage can't be prevented. + Ability ability = new EntersBattlefieldTriggeredAbility(new VolcanoHellionEffect(), false); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + } + + public VolcanoHellion(final VolcanoHellion card) { + super(card); + } + + @Override + public VolcanoHellion copy() { + return new VolcanoHellion(this); + } +} + +class VolcanoHellionEffect extends OneShotEffect { + + public VolcanoHellionEffect() { + super(Outcome.AIDontUseIt); + this.staticText = "it deals an amount of damage of your choice to you and target creature. The damage can't be prevented"; + } + + public VolcanoHellionEffect(final VolcanoHellionEffect effect) { + super(effect); + } + + @Override + public VolcanoHellionEffect copy() { + return new VolcanoHellionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (controller != null) { + int amount = controller.getAmount(0, Integer.MAX_VALUE, "Choose the amount of damage to deliver to you and a target creature. The damage can't be prevented.", game); + if (amount > 0) { + controller.damage(amount, source.getSourceId(), game, false, false); + if (permanent != null) { + permanent.damage(amount, source.getSourceId(), game, false, false); + } + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/PlanarChaos.java b/Mage.Sets/src/mage/sets/PlanarChaos.java index f6622a868b1..8c99068372d 100644 --- a/Mage.Sets/src/mage/sets/PlanarChaos.java +++ b/Mage.Sets/src/mage/sets/PlanarChaos.java @@ -204,6 +204,7 @@ public class PlanarChaos extends ExpansionSet { cards.add(new SetCardInfo("Venarian Glimmer", 52, Rarity.UNCOMMON, mage.cards.v.VenarianGlimmer.class)); cards.add(new SetCardInfo("Vitaspore Thallid", 143, Rarity.COMMON, mage.cards.v.VitasporeThallid.class)); cards.add(new SetCardInfo("Voidstone Gargoyle", 21, Rarity.RARE, mage.cards.v.VoidstoneGargoyle.class)); + cards.add(new SetCardInfo("Volcano Hellion", 111, Rarity.RARE, mage.cards.v.VolcanoHellion.class)); cards.add(new SetCardInfo("Vorosh, the Hunter", 164, Rarity.RARE, mage.cards.v.VoroshTheHunter.class)); cards.add(new SetCardInfo("Waning Wurm", 83, Rarity.UNCOMMON, mage.cards.w.WaningWurm.class)); cards.add(new SetCardInfo("Whitemane Lion", 22, Rarity.COMMON, mage.cards.w.WhitemaneLion.class)); diff --git a/Mage/src/main/java/mage/abilities/keyword/EchoAbility.java b/Mage/src/main/java/mage/abilities/keyword/EchoAbility.java index 6fd2119c17c..afe35d923f2 100644 --- a/Mage/src/main/java/mage/abilities/keyword/EchoAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/EchoAbility.java @@ -24,8 +24,7 @@ * 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.abilities.keyword; import java.util.UUID; @@ -36,6 +35,7 @@ import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; import mage.abilities.costs.CostsImpl; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.constants.Zone; @@ -54,12 +54,25 @@ public class EchoAbility extends TriggeredAbilityImpl { protected boolean echoPaid; protected Costs echoCosts = new CostsImpl<>(); private boolean manaEcho = true; + private DynamicValue amount; + private String rule; public EchoAbility(String manaString) { super(Zone.BATTLEFIELD, new EchoEffect(new ManaCostsImpl(manaString)), false); this.echoPaid = false; this.echoCosts.add(new ManaCostsImpl(manaString)); this.lastController = null; + this.rule = null; + } + + public EchoAbility(DynamicValue amount, String rule) { + super(Zone.BATTLEFIELD, new EchoEffect(amount), false); + this.amount = amount; + this.echoPaid = false; + this.echoCosts.add(costs); + this.lastController = null; + this.manaEcho = true; + this.rule = rule; } public EchoAbility(Cost echoCost) { @@ -68,6 +81,7 @@ public class EchoAbility extends TriggeredAbilityImpl { this.echoCosts.add(echoCost); this.manaEcho = false; this.lastController = null; + this.rule = null; } public EchoAbility(final EchoAbility ability) { @@ -76,6 +90,8 @@ public class EchoAbility extends TriggeredAbilityImpl { this.echoCosts = ability.echoCosts.copy(); this.manaEcho = ability.manaEcho; this.lastController = ability.lastController; + this.amount = ability.amount; + this.rule = ability.rule; } @Override @@ -85,7 +101,8 @@ public class EchoAbility extends TriggeredAbilityImpl { @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD || event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE; + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD + || event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE; } @Override @@ -93,20 +110,21 @@ public class EchoAbility extends TriggeredAbilityImpl { // reset the echo paid state back, if creature enteres the battlefield if (event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD && event.getTargetId().equals(this.getSourceId())) { - + this.echoPaid = false; } if (event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE) { - if(lastController != null){ - if(!lastController.equals(this.controllerId)){ + if (lastController != null) { + if (!lastController.equals(this.controllerId)) { this.echoPaid = false; } } // remember the last controller lastController = this.getControllerId(); // if echo not paid yet, controller has to pay - if (event.getPlayerId().equals(this.controllerId) && - lastController.equals(this.controllerId) && !this.echoPaid){ + if (event.getPlayerId().equals(this.controllerId) + && lastController.equals(this.controllerId) + && !this.echoPaid) { this.echoPaid = true; return true; } @@ -116,45 +134,66 @@ public class EchoAbility extends TriggeredAbilityImpl { @Override public String getRule() { - StringBuilder sb = new StringBuilder("Echo"); - if (manaEcho) { - sb.append(' '); + StringBuilder sb = new StringBuilder(); + if (rule != null) { + sb.append(rule); } else { - sb.append("—"); + sb = new StringBuilder("Echo"); + if (manaEcho) { + sb.append(' '); + } else { + sb.append("—"); + } + if (echoCosts != null) { + sb.append(echoCosts.getText()); + } } - sb.append(echoCosts.getText()); sb.append(" (At the beginning of your upkeep, if this came under your control since the beginning of your last upkeep, sacrifice it unless you pay its echo cost.)"); return sb.toString(); } } class EchoEffect extends OneShotEffect { + protected Cost cost; + protected DynamicValue amount; public EchoEffect(Cost costs) { super(Outcome.Sacrifice); this.cost = costs; - } + this.amount = null; + } + + public EchoEffect(DynamicValue amount) { + super(Outcome.Sacrifice); + this.amount = amount; + this.cost = null; + } public EchoEffect(final EchoEffect effect) { super(effect); this.cost = effect.cost; + this.amount = effect.amount; } @Override public boolean apply(Game game, Ability source) { + if (amount != null) { + cost = new ManaCostsImpl(Integer.toString(amount.calculate(game, source, this))); + } Player controller = game.getPlayer(source.getControllerId()); - if (controller != null && source.getSourceObjectIfItStillExists(game) != null) { - if (controller.chooseUse(Outcome.Benefit, "Pay " + cost.getText() /* + " or sacrifice " + permanent.getName() */ + '?', source, game)) { - cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { - return true; - } - } - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - permanent.sacrifice(source.getSourceId(), game); + if (controller != null + && source.getSourceObjectIfItStillExists(game) != null) { + if (controller.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + '?', source, game)) { + cost.clearPaid(); + if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { + return true; } + } + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent != null) { + permanent.sacrifice(source.getSourceId(), game); + } return true; } return false; @@ -167,17 +206,16 @@ class EchoEffect extends OneShotEffect { @Override public String getText(Mode mode) { - StringBuilder sb = new StringBuilder("sacrifice {this} unless you "); - String costText = cost.getText(); - if (costText.toLowerCase().startsWith("discard")) { - sb.append(costText.substring(0, 1).toLowerCase()); - sb.append(costText.substring(1)); - } - else { - sb.append("pay ").append(costText); - } + StringBuilder sb = new StringBuilder("sacrifice {this} unless you "); + String costText = cost.getText(); + if (costText.toLowerCase().startsWith("discard")) { + sb.append(costText.substring(0, 1).toLowerCase()); + sb.append(costText.substring(1)); + } else { + sb.append("pay ").append(costText); + } - return sb.toString(); + return sb.toString(); } } From 469ddcea6b648a801a9a85fb01d841bda01ceb1f Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 20 Jul 2017 13:37:23 -0500 Subject: [PATCH 5/6] - Refactor AnnihilatorAbility(). --- .../abilities/keyword/AnnihilatorAbility.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/Mage/src/main/java/mage/abilities/keyword/AnnihilatorAbility.java b/Mage/src/main/java/mage/abilities/keyword/AnnihilatorAbility.java index 66653099764..d2036ef91a4 100644 --- a/Mage/src/main/java/mage/abilities/keyword/AnnihilatorAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/AnnihilatorAbility.java @@ -30,7 +30,6 @@ package mage.abilities.keyword; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.constants.Zone; @@ -79,9 +78,9 @@ public class AnnihilatorAbility extends TriggeredAbilityImpl { UUID defendingPlayerId = game.getCombat().getDefendingPlayerId(sourceId, game); if (defendingPlayerId != null) { // the id has to be set here because the source can be leave battlefield - for (Effect effect : getEffects()) { + getEffects().forEach((effect) -> { effect.setValue("defendingPlayerId", defendingPlayerId); - } + }); return true; } } @@ -125,19 +124,23 @@ class AnnihilatorEffect extends OneShotEffect { } if (player != null) { int amount = Math.min(count, game.getBattlefield().countAll(FILTER, player.getId(), game)); - Target target = new TargetControlledPermanent(amount, amount, FILTER, true); - if (target.canChoose(player.getId(), game)) { - while (!target.isChosen() && target.canChoose(player.getId(), game) && player.canRespond()) { - player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); - } - for (int idx = 0; idx < target.getTargets().size(); idx++) { - Permanent permanent = game.getPermanent(target.getTargets().get(idx)); - if (permanent != null) { - permanent.sacrifice(source.getSourceId(), game); + if (amount > 0) { + Target target = new TargetControlledPermanent(amount, amount, FILTER, true); + if (target.canChoose(player.getId(), game)) { + while (player.canRespond() + && target.canChoose(player.getId(), game) + && !target.isChosen()) { + player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + } + for (int idx = 0; idx < target.getTargets().size(); idx++) { + Permanent permanent = game.getPermanent(target.getTargets().get(idx)); + if (permanent != null) { + permanent.sacrifice(source.getSourceId(), game); + } } } + return true; } - return true; } return false; } From 5ce1052ebca39517eb703f4150ee755362158132 Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 20 Jul 2017 14:54:50 -0500 Subject: [PATCH 6/6] - Added requested card Seedtime. --- Mage.Sets/src/mage/cards/s/Seedtime.java | 100 +++++++++++++++++++++++ Mage.Sets/src/mage/sets/Judgment.java | 1 + 2 files changed, 101 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/Seedtime.java diff --git a/Mage.Sets/src/mage/cards/s/Seedtime.java b/Mage.Sets/src/mage/cards/s/Seedtime.java new file mode 100644 index 00000000000..992ba5f2cab --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Seedtime.java @@ -0,0 +1,100 @@ +/* + * 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.cards.s; + +import java.util.List; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.turn.AddExtraTurnControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.watchers.common.SpellsCastWatcher; + +/** + * + * @author jeffwadsworth + */ +public class Seedtime extends CardImpl { + + private final static String rule = "Cast {this} only during your turn."; + private final static String rule2 = "Take an extra turn after this one if an opponent cast a blue spell this turn."; + + public Seedtime(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); + + // Cast Seedtime only during your turn. + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(null, null, MyTurnCondition.instance, rule)); + + // Take an extra turn after this one if an opponent cast a blue spell this turn. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new AddExtraTurnControllerEffect(), OpponentCastBlueSpellThisTurnCondition.instance, rule2)); + this.getSpellAbility().addWatcher(new SpellsCastWatcher()); + + } + + public Seedtime(final Seedtime card) { + super(card); + } + + @Override + public Seedtime copy() { + return new Seedtime(this); + } +} + +enum OpponentCastBlueSpellThisTurnCondition implements Condition { + + instance; + + @Override + public boolean apply(Game game, Ability source) { + SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName()); + if (watcher != null) { + for (UUID opponentId : game.getOpponents(source.getControllerId())) { + if (opponentId != null) { + List spells = watcher.getSpellsCastThisTurn(opponentId); + if (spells != null) { + for (Spell spell : spells) { + if (spell != null + && spell.getColor(game).isBlue()) { + return true; + } + } + } + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/Judgment.java b/Mage.Sets/src/mage/sets/Judgment.java index 0d2fa87a1ad..b1cb49a0261 100644 --- a/Mage.Sets/src/mage/sets/Judgment.java +++ b/Mage.Sets/src/mage/sets/Judgment.java @@ -142,6 +142,7 @@ public class Judgment extends ExpansionSet { cards.add(new SetCardInfo("Ray of Revelation", 20, Rarity.COMMON, mage.cards.r.RayOfRevelation.class)); cards.add(new SetCardInfo("Riftstone Portal", 143, Rarity.UNCOMMON, mage.cards.r.RiftstonePortal.class)); cards.add(new SetCardInfo("Scalpelexis", 50, Rarity.RARE, mage.cards.s.Scalpelexis.class)); + cards.add(new SetCardInfo("Seedtime", 130, Rarity.RARE, mage.cards.s.Seedtime.class)); cards.add(new SetCardInfo("Silver Seraph", 23, Rarity.RARE, mage.cards.s.SilverSeraph.class)); cards.add(new SetCardInfo("Solitary Confinement", 24, Rarity.RARE, mage.cards.s.SolitaryConfinement.class)); cards.add(new SetCardInfo("Soulcatchers' Aerie", 25, Rarity.UNCOMMON, mage.cards.s.SoulcatchersAerie.class));