From 34952f173d57d9b31ba35c02c9e6a7ba0ae5b9d6 Mon Sep 17 00:00:00 2001 From: L_J Date: Sat, 28 Apr 2018 13:15:31 +0000 Subject: [PATCH 1/5] Mana Short filter fix --- Mage.Sets/src/mage/cards/m/ManaShort.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Mage.Sets/src/mage/cards/m/ManaShort.java b/Mage.Sets/src/mage/cards/m/ManaShort.java index 567fef5ed66..e906ca77da6 100644 --- a/Mage.Sets/src/mage/cards/m/ManaShort.java +++ b/Mage.Sets/src/mage/cards/m/ManaShort.java @@ -33,7 +33,7 @@ import mage.abilities.effects.common.TapAllTargetPlayerControlsEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.StaticFilters; +import mage.filter.common.FilterLandPermanent; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; @@ -47,7 +47,7 @@ public class ManaShort extends CardImpl { public ManaShort(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{U}"); - // Tap all lands target player controls and empty their mana pool. + // Tap all lands target player controls and empty his or her mana pool. this.getSpellAbility().addEffect(new ManaShortEffect()); this.getSpellAbility().addTarget(new TargetPlayer()); } @@ -65,8 +65,8 @@ public class ManaShort extends CardImpl { class ManaShortEffect extends TapAllTargetPlayerControlsEffect { public ManaShortEffect() { - super(StaticFilters.FILTER_LANDS); - staticText = "Tap all lands target player controls and empty their mana pool"; + super(new FilterLandPermanent()); + staticText = "Tap all lands target player controls and empty his or her mana pool"; } public ManaShortEffect(final ManaShortEffect effect) { From 4446adfadf8cba48ab507137f1bb94516424377d Mon Sep 17 00:00:00 2001 From: L_J Date: Sat, 28 Apr 2018 13:17:25 +0000 Subject: [PATCH 2/5] Made Mana#includesMana capable of comparing colorless to generic --- Mage/src/main/java/mage/Mana.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage/src/main/java/mage/Mana.java b/Mage/src/main/java/mage/Mana.java index 395f52e284d..d173437878b 100644 --- a/Mage/src/main/java/mage/Mana.java +++ b/Mage/src/main/java/mage/Mana.java @@ -1083,7 +1083,7 @@ public class Mana implements Comparable, Serializable, Copyable { && this.red >= mana.red && this.colorless >= mana.colorless && (this.generic >= mana.generic - || this.countColored() >= mana.countColored() + mana.generic); + || this.countColored() + this.colorless >= mana.count()); } From 826eb6843ef2921d0f2c49e1dc77929e9834d7d1 Mon Sep 17 00:00:00 2001 From: L_J Date: Sat, 28 Apr 2018 15:19:16 +0200 Subject: [PATCH 3/5] Implemented Drain Power --- Mage.Sets/src/mage/cards/d/DrainPower.java | 178 ++++++++++++++++++ Mage.Sets/src/mage/sets/FifthEdition.java | 1 + Mage.Sets/src/mage/sets/FourthEdition.java | 1 + .../src/mage/sets/LimitedEditionAlpha.java | 1 + .../src/mage/sets/LimitedEditionBeta.java | 1 + Mage.Sets/src/mage/sets/MastersEditionIV.java | 1 + Mage.Sets/src/mage/sets/RevisedEdition.java | 1 + Mage.Sets/src/mage/sets/UnlimitedEdition.java | 1 + 8 files changed, 185 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/d/DrainPower.java diff --git a/Mage.Sets/src/mage/cards/d/DrainPower.java b/Mage.Sets/src/mage/cards/d/DrainPower.java new file mode 100644 index 00000000000..8aa9047668b --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DrainPower.java @@ -0,0 +1,178 @@ +/* + * 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.d; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.ActivatedAbility; +import mage.abilities.costs.mana.ManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.mana.ActivatedManaAbilityImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.permanent.PermanentInListPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.TargetPlayer; + +/** + * + * @author L_J + */ +public class DrainPower extends CardImpl { + + public DrainPower(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{U}{U}"); + + // Target player activates a mana ability of each land they control. Then that player loses all unspent mana and you add the mana lost this way. + this.getSpellAbility().addEffect(new DrainPowerEffect()); + this.getSpellAbility().addTarget(new TargetPlayer()); + } + + public DrainPower(final DrainPower card) { + super(card); + } + + @Override + public DrainPower copy() { + return new DrainPower(this); + } +} + +class DrainPowerEffect extends OneShotEffect { + + private static final FilterLandPermanent filter = new FilterLandPermanent(); + + public DrainPowerEffect() { + super(Outcome.Tap); + this.staticText = "Target player activates a mana ability of each land they control. Then that player loses all unspent mana and you add the mana lost this way"; + } + + public DrainPowerEffect(final DrainPowerEffect effect) { + super(effect); + } + + @Override + public DrainPowerEffect copy() { + return new DrainPowerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player targetPlayer = game.getPlayer(source.getFirstTarget()); + if (targetPlayer != null) { + List ignorePermanents = new ArrayList<>(); + TargetPermanent target = null; + + do { + Map> manaAbilitiesMap = new HashMap<>(); + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, targetPlayer.getId(), game)) { + if (!ignorePermanents.contains(permanent)) { + List manaAbilities = new ArrayList<>(); + abilitySearch: + for (Ability ability : permanent.getAbilities()) { + if (ability instanceof ActivatedAbility && ability.getAbilityType() == AbilityType.MANA) { + ActivatedManaAbilityImpl manaAbility = (ActivatedManaAbilityImpl) ability; + // TODO: make Rhystic Cave untappable due to its instant speed limitation (this is a Rhystic Cave canActivate bug) + if (manaAbility != null && manaAbility.canActivate(targetPlayer.getId(), game)) { + // canActivate can't check for mana abilities that require a mana cost, if the payment isn't possible (Cabal Coffers etc) + // so it's necessary to filter them out manually - might be buggy in some fringe cases + for (ManaCost manaCost : manaAbility.getManaCosts()) { + if (!targetPlayer.getManaPool().getMana().includesMana(manaCost.getMana())) { + continue abilitySearch; + } + } + manaAbilities.add(manaAbility); + } + } + } + if (!manaAbilities.isEmpty()) { + manaAbilitiesMap.put(permanent, manaAbilities); + } + } + } + if (manaAbilitiesMap.isEmpty()) { + break; + } + + List permList = new ArrayList(manaAbilitiesMap.keySet()); + Permanent permanent = null; + if (permList.size() > 1 || target != null) { + FilterLandPermanent filter2 = new FilterLandPermanent("land you control to tap for mana (remaining: " + permList.size() + ')'); + filter2.add(new PermanentInListPredicate(permList)); + target = new TargetPermanent(1, 1, filter2, true); + while (!target.isChosen() && target.canChoose(targetPlayer.getId(), game) && targetPlayer.canRespond()) { + targetPlayer.chooseTarget(Outcome.Neutral, target, source, game); + } + permanent = game.getPermanent(target.getFirstTarget()); + } else { + permanent = permList.get(0); + } + if (permanent != null) { + int i = 0; + for (ActivatedManaAbilityImpl manaAbility : manaAbilitiesMap.get(permanent)) { + i++; + if (manaAbilitiesMap.get(permanent).size() <= i + || targetPlayer.chooseUse(Outcome.Neutral, "Activate mana ability \"" + manaAbility.getRule() + "\" of " + permanent.getLogName() + + "? (Choose \"no\" to activate next mana ability)", source, game)) { + boolean originalCanUndo = manaAbility.isUndoPossible(); + manaAbility.setUndoPossible(false); // prevents being able to undo Drain Power + if (targetPlayer.activateAbility(manaAbility, game)) { + ignorePermanents.add(permanent); + } + manaAbility.setUndoPossible(originalCanUndo); // resets undoPossible to its original state + break; + } + } + } + } while (target != null && target.canChoose(targetPlayer.getId(), game)); + + // 106.12. One card (Drain Power) causes one player to lose unspent mana and another to add “the mana lost this way.” (Note that these may be the same player.) + // This empties the former player’s mana pool and causes the mana emptied this way to be put into the latter player’s mana pool. Which permanents, spells, and/or + // abilities produced that mana are unchanged, as are any restrictions or additional effects associated with any of that mana. + // TODO: retain riders associated with drained mana + Mana mana = targetPlayer.getManaPool().getMana(); + targetPlayer.getManaPool().emptyPool(game); + controller.getManaPool().addMana(mana, game, source); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/FifthEdition.java b/Mage.Sets/src/mage/sets/FifthEdition.java index 74a66d2e135..520dc1c6de9 100644 --- a/Mage.Sets/src/mage/sets/FifthEdition.java +++ b/Mage.Sets/src/mage/sets/FifthEdition.java @@ -136,6 +136,7 @@ public class FifthEdition extends ExpansionSet { cards.add(new SetCardInfo("Divine Transformation", 304, Rarity.UNCOMMON, mage.cards.d.DivineTransformation.class)); cards.add(new SetCardInfo("Dragon Engine", 366, Rarity.RARE, mage.cards.d.DragonEngine.class)); cards.add(new SetCardInfo("Drain Life", 18, Rarity.COMMON, mage.cards.d.DrainLife.class)); + cards.add(new SetCardInfo("Drain Power", 82, Rarity.RARE, mage.cards.d.DrainPower.class)); cards.add(new SetCardInfo("Drudge Skeletons", 19, Rarity.COMMON, mage.cards.d.DrudgeSkeletons.class)); cards.add(new SetCardInfo("Durkwood Boars", 151, Rarity.COMMON, mage.cards.d.DurkwoodBoars.class)); cards.add(new SetCardInfo("Dust to Dust", 305, Rarity.UNCOMMON, mage.cards.d.DustToDust.class)); diff --git a/Mage.Sets/src/mage/sets/FourthEdition.java b/Mage.Sets/src/mage/sets/FourthEdition.java index 0b5d5d5f421..7405ca25a5a 100644 --- a/Mage.Sets/src/mage/sets/FourthEdition.java +++ b/Mage.Sets/src/mage/sets/FourthEdition.java @@ -119,6 +119,7 @@ public class FourthEdition extends ExpansionSet { cards.add(new SetCardInfo("Control Magic", 64, Rarity.UNCOMMON, mage.cards.c.ControlMagic.class)); cards.add(new SetCardInfo("Counterspell", 65, Rarity.UNCOMMON, mage.cards.c.Counterspell.class)); cards.add(new SetCardInfo("Creature Bond", 66, Rarity.COMMON, mage.cards.c.CreatureBond.class)); + cards.add(new SetCardInfo("Drain Power", 67, Rarity.RARE, mage.cards.d.DrainPower.class)); cards.add(new SetCardInfo("Energy Flux", 68, Rarity.UNCOMMON, mage.cards.e.EnergyFlux.class)); cards.add(new SetCardInfo("Energy Tap", 69, Rarity.COMMON, mage.cards.e.EnergyTap.class)); cards.add(new SetCardInfo("Erosion", 70, Rarity.COMMON, mage.cards.e.Erosion.class)); diff --git a/Mage.Sets/src/mage/sets/LimitedEditionAlpha.java b/Mage.Sets/src/mage/sets/LimitedEditionAlpha.java index 8b7de5a757d..2b9c646a0e8 100644 --- a/Mage.Sets/src/mage/sets/LimitedEditionAlpha.java +++ b/Mage.Sets/src/mage/sets/LimitedEditionAlpha.java @@ -88,6 +88,7 @@ public class LimitedEditionAlpha extends ExpansionSet { cards.add(new SetCardInfo("Disrupting Scepter", 242, Rarity.RARE, mage.cards.d.DisruptingScepter.class)); cards.add(new SetCardInfo("Dragon Whelp", 142, Rarity.UNCOMMON, mage.cards.d.DragonWhelp.class)); cards.add(new SetCardInfo("Drain Life", 14, Rarity.COMMON, mage.cards.d.DrainLife.class)); + cards.add(new SetCardInfo("Drain Power", 57, Rarity.RARE, mage.cards.d.DrainPower.class)); cards.add(new SetCardInfo("Drudge Skeletons", 15, Rarity.COMMON, mage.cards.d.DrudgeSkeletons.class)); cards.add(new SetCardInfo("Dwarven Demolition Team", 143, Rarity.UNCOMMON, mage.cards.d.DwarvenDemolitionTeam.class)); cards.add(new SetCardInfo("Dwarven Warriors", 144, Rarity.COMMON, mage.cards.d.DwarvenWarriors.class)); diff --git a/Mage.Sets/src/mage/sets/LimitedEditionBeta.java b/Mage.Sets/src/mage/sets/LimitedEditionBeta.java index 9b642609e4c..ba6e2fe89db 100644 --- a/Mage.Sets/src/mage/sets/LimitedEditionBeta.java +++ b/Mage.Sets/src/mage/sets/LimitedEditionBeta.java @@ -89,6 +89,7 @@ public class LimitedEditionBeta extends ExpansionSet { cards.add(new SetCardInfo("Disrupting Scepter", 243, Rarity.RARE, mage.cards.d.DisruptingScepter.class)); cards.add(new SetCardInfo("Dragon Whelp", 142, Rarity.UNCOMMON, mage.cards.d.DragonWhelp.class)); cards.add(new SetCardInfo("Drain Life", 106, Rarity.COMMON, mage.cards.d.DrainLife.class)); + cards.add(new SetCardInfo("Drain Power", 57, Rarity.RARE, mage.cards.d.DrainPower.class)); cards.add(new SetCardInfo("Drudge Skeletons", 107, Rarity.COMMON, mage.cards.d.DrudgeSkeletons.class)); cards.add(new SetCardInfo("Dwarven Demolition Team", 143, Rarity.UNCOMMON, mage.cards.d.DwarvenDemolitionTeam.class)); cards.add(new SetCardInfo("Dwarven Warriors", 144, Rarity.COMMON, mage.cards.d.DwarvenWarriors.class)); diff --git a/Mage.Sets/src/mage/sets/MastersEditionIV.java b/Mage.Sets/src/mage/sets/MastersEditionIV.java index e06cd8e06cd..6e967fa5ca3 100644 --- a/Mage.Sets/src/mage/sets/MastersEditionIV.java +++ b/Mage.Sets/src/mage/sets/MastersEditionIV.java @@ -130,6 +130,7 @@ public class MastersEditionIV extends ExpansionSet { cards.add(new SetCardInfo("Diabolic Machine", 196, Rarity.UNCOMMON, mage.cards.d.DiabolicMachine.class)); cards.add(new SetCardInfo("Divine Offering", 10, Rarity.COMMON, mage.cards.d.DivineOffering.class)); cards.add(new SetCardInfo("Dragon Engine", 197, Rarity.COMMON, mage.cards.d.DragonEngine.class)); + cards.add(new SetCardInfo("Drain Power", 46, Rarity.RARE, mage.cards.d.DrainPower.class)); cards.add(new SetCardInfo("Dread Reaper", 78, Rarity.RARE, mage.cards.d.DreadReaper.class)); cards.add(new SetCardInfo("Drop of Honey", 150, Rarity.RARE, mage.cards.d.DropOfHoney.class)); cards.add(new SetCardInfo("Drowned", 47, Rarity.COMMON, mage.cards.d.Drowned.class)); diff --git a/Mage.Sets/src/mage/sets/RevisedEdition.java b/Mage.Sets/src/mage/sets/RevisedEdition.java index 74924028acb..e4e83cf7021 100644 --- a/Mage.Sets/src/mage/sets/RevisedEdition.java +++ b/Mage.Sets/src/mage/sets/RevisedEdition.java @@ -91,6 +91,7 @@ public class RevisedEdition extends ExpansionSet { cards.add(new SetCardInfo("Dragon Engine", 246, Rarity.RARE, mage.cards.d.DragonEngine.class)); cards.add(new SetCardInfo("Dragon Whelp", 142, Rarity.UNCOMMON, mage.cards.d.DragonWhelp.class)); cards.add(new SetCardInfo("Drain Life", 14, Rarity.COMMON, mage.cards.d.DrainLife.class)); + cards.add(new SetCardInfo("Drain Power", 56, Rarity.RARE, mage.cards.d.DrainPower.class)); cards.add(new SetCardInfo("Drudge Skeletons", 15, Rarity.COMMON, mage.cards.d.DrudgeSkeletons.class)); cards.add(new SetCardInfo("Dwarven Warriors", 143, Rarity.COMMON, mage.cards.d.DwarvenWarriors.class)); cards.add(new SetCardInfo("Dwarven Weaponsmith", 144, Rarity.UNCOMMON, mage.cards.d.DwarvenWeaponsmith.class)); diff --git a/Mage.Sets/src/mage/sets/UnlimitedEdition.java b/Mage.Sets/src/mage/sets/UnlimitedEdition.java index a27c910c64f..ee5e51551d3 100644 --- a/Mage.Sets/src/mage/sets/UnlimitedEdition.java +++ b/Mage.Sets/src/mage/sets/UnlimitedEdition.java @@ -89,6 +89,7 @@ public class UnlimitedEdition extends ExpansionSet { cards.add(new SetCardInfo("Disrupting Scepter", 243, Rarity.RARE, mage.cards.d.DisruptingScepter.class)); cards.add(new SetCardInfo("Dragon Whelp", 142, Rarity.UNCOMMON, mage.cards.d.DragonWhelp.class)); cards.add(new SetCardInfo("Drain Life", 14, Rarity.COMMON, mage.cards.d.DrainLife.class)); + cards.add(new SetCardInfo("Drain Power", 57, Rarity.RARE, mage.cards.d.DrainPower.class)); cards.add(new SetCardInfo("Drudge Skeletons", 15, Rarity.COMMON, mage.cards.d.DrudgeSkeletons.class)); cards.add(new SetCardInfo("Dwarven Demolition Team", 143, Rarity.UNCOMMON, mage.cards.d.DwarvenDemolitionTeam.class)); cards.add(new SetCardInfo("Dwarven Warriors", 144, Rarity.COMMON, mage.cards.d.DwarvenWarriors.class)); From d83af8be91ec2c2aa58fb89738d8e052c2b78d6f Mon Sep 17 00:00:00 2001 From: L_J Date: Sat, 28 Apr 2018 13:22:26 +0000 Subject: [PATCH 4/5] Mana Short text fix --- Mage.Sets/src/mage/cards/m/ManaShort.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/cards/m/ManaShort.java b/Mage.Sets/src/mage/cards/m/ManaShort.java index e906ca77da6..701ebe6c831 100644 --- a/Mage.Sets/src/mage/cards/m/ManaShort.java +++ b/Mage.Sets/src/mage/cards/m/ManaShort.java @@ -47,7 +47,7 @@ public class ManaShort extends CardImpl { public ManaShort(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{U}"); - // Tap all lands target player controls and empty his or her mana pool. + // Tap all lands target player controls and empty their mana pool. this.getSpellAbility().addEffect(new ManaShortEffect()); this.getSpellAbility().addTarget(new TargetPlayer()); } @@ -66,7 +66,7 @@ class ManaShortEffect extends TapAllTargetPlayerControlsEffect { public ManaShortEffect() { super(new FilterLandPermanent()); - staticText = "Tap all lands target player controls and empty his or her mana pool"; + staticText = "Tap all lands target player controls and empty their mana pool"; } public ManaShortEffect(final ManaShortEffect effect) { From 97606fc50dc44940e85070022abcee147a06aa7a Mon Sep 17 00:00:00 2001 From: L_J Date: Sat, 28 Apr 2018 13:59:28 +0000 Subject: [PATCH 5/5] Drain Power while loop logic fix --- Mage.Sets/src/mage/cards/d/DrainPower.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/cards/d/DrainPower.java b/Mage.Sets/src/mage/cards/d/DrainPower.java index 8aa9047668b..dd74c601caf 100644 --- a/Mage.Sets/src/mage/cards/d/DrainPower.java +++ b/Mage.Sets/src/mage/cards/d/DrainPower.java @@ -101,7 +101,7 @@ class DrainPowerEffect extends OneShotEffect { List ignorePermanents = new ArrayList<>(); TargetPermanent target = null; - do { + while (true) { Map> manaAbilitiesMap = new HashMap<>(); for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, targetPlayer.getId(), game)) { if (!ignorePermanents.contains(permanent)) { @@ -162,7 +162,7 @@ class DrainPowerEffect extends OneShotEffect { } } } - } while (target != null && target.canChoose(targetPlayer.getId(), game)); + } // 106.12. One card (Drain Power) causes one player to lose unspent mana and another to add “the mana lost this way.” (Note that these may be the same player.) // This empties the former player’s mana pool and causes the mana emptied this way to be put into the latter player’s mana pool. Which permanents, spells, and/or