diff --git a/Mage.Sets/src/mage/cards/c/CelestialSword.java b/Mage.Sets/src/mage/cards/c/CelestialSword.java index fedf9772bbd..33ef469455f 100644 --- a/Mage.Sets/src/mage/cards/c/CelestialSword.java +++ b/Mage.Sets/src/mage/cards/c/CelestialSword.java @@ -30,22 +30,18 @@ package mage.cards.c; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; -import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.SacrificeTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Zone; -import mage.game.events.GameEvent; import mage.target.common.TargetControlledCreaturePermanent; /** diff --git a/Mage.Sets/src/mage/cards/c/CyclopeanTomb.java b/Mage.Sets/src/mage/cards/c/CyclopeanTomb.java new file mode 100644 index 00000000000..65d67df7184 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CyclopeanTomb.java @@ -0,0 +1,344 @@ +/* + * 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.c; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import mage.MageObject; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.PutIntoGraveFromBattlefieldSourceTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.IsStepCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.continuous.BecomesBasicLandTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.effects.common.counter.RemoveAllCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.constants.SubLayer; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.Predicate; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.CounterPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetLandPermanent; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; +import mage.watchers.Watcher; + +/** + * + * @author MTGfan + */ +public class CyclopeanTomb extends CardImpl { + + private static final FilterLandPermanent filter = new FilterLandPermanent(); + + static { + filter.add(Predicates.not(new SubtypePredicate("Swamp"))); + } + + public CyclopeanTomb(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); + + // {2}, {tap}: Put a mire counter on target non-Swamp land. That land is a Swamp for as long as it has a mire counter on it. Activate this ability only during your upkeep. + Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.MIRE.createInstance()), new GenericManaCost(2), new IsStepCondition(PhaseStep.UPKEEP), "{2}, {T}: Put a mire counter on target non-Swamp land. That land is a Swamp for as long as it has a mire counter on it. Activate this ability only during your upkeep."); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetLandPermanent(filter)); + ability.addEffect(new BecomeSwampEffect(Duration.Custom, false, true, "Swamp")); + this.addAbility(ability, new CyclopeanTombCounterWatcher()); + // When Cyclopean Tomb is put into a graveyard from the battlefield, at the beginning of each of your upkeeps for the rest of the game, remove all mire counters from a land that a mire counter was put onto with Cyclopean Tomb but that a mire counter has not been removed from with Cyclopean Tomb. + Effect effect = new CreateDelayedTriggeredAbilityEffect(new CyclopeanTombDelayedTriggeredAbility()); + effect.setText("at the beginning of each of your upkeeps for the rest of the game, remove all mire counters from a land that a mire counter was put onto with {this} but that a mire counter has not been removed from with {this}."); + this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(effect)); + } + + public CyclopeanTomb(final CyclopeanTomb card) { + super(card); + } + + @Override + public CyclopeanTomb copy() { + return new CyclopeanTomb(this); + } +} + +class BecomeSwampEffect extends BecomesBasicLandTargetEffect { + + public BecomeSwampEffect(Duration duration, boolean chooseLandType, boolean loseOther, String... landNames) { + super(duration, chooseLandType, loseOther, landNames); + staticText = "That land is a Swamp for as long as it has a mire counter on it."; + } + + public BecomeSwampEffect(final BecomeSwampEffect effect) { + super(effect); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent land = game.getPermanent(this.targetPointer.getFirst(game, source)); + if (land == null) { + // if permanent left battlefield the effect can be removed because it was only valid for that object + this.discard(); + } else if (land.getCounters(game).getCount(CounterType.MIRE) > 0) { + // only if Mire counter is on the object it becomes a Swamp. + super.apply(layer, sublayer, source, game); + } + return true; + } + + @Override + public BecomeSwampEffect copy() { + return new BecomeSwampEffect(this); + } +} + +class CyclopeanTombDelayedTriggeredAbility extends DelayedTriggeredAbility { + + CyclopeanTombDelayedTriggeredAbility() { + super(new CyclopeanTombEffect(), Duration.OneUse, true, false); + } + + CyclopeanTombDelayedTriggeredAbility(CyclopeanTombDelayedTriggeredAbility ability) { + super(ability); + } + + @Override + public CyclopeanTombDelayedTriggeredAbility copy() { + return new CyclopeanTombDelayedTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.BEGINNING_PHASE_PRE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getPlayerId().equals(this.controllerId); + } +} + +class CyclopeanTombEffect extends OneShotEffect { + + public CyclopeanTombEffect() { + super(Outcome.Benefit); + this.staticText = "at the beginning of each of your upkeeps for the rest of the game, remove all mire counters from a land that a mire counter was put onto with {this} but that a mire counter has not been removed from with {this}."; + } + + public CyclopeanTombEffect(final CyclopeanTombEffect effect) { + super(effect); + } + + @Override + public CyclopeanTombEffect copy() { + return new CyclopeanTombEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if(controller != null){ + new ChooseLandEffect().apply(game, source); + Effect effect = new RemoveAllCountersTargetEffect(CounterType.MIRE); + effect.setTargetPointer(new FixedTarget((UUID) game.getState().getValue(source.getSourceId().toString() + "_land"))); + effect.apply(game, source); + //CyclopianTombEffect and CyclopeanTombDelayedTriggeredAbility will maintain a loop + //as long as there are one or more mire counters left to be removed + new ConditionalOneShotEffect(new CreateDelayedTriggeredAbilityEffect(new CyclopeanTombDelayedTriggeredAbility(), false), new CyclopeanTombCounterCondition()).apply(game, source); + return true; + } + return false; + } +} + +class CyclopeanTombCounterCondition implements Condition { + + private static final FilterLandPermanent mireFilter = new FilterLandPermanent(); + + static { + mireFilter.add(new CounterPredicate(CounterType.MIRE)); + } + + public CyclopeanTombCounterCondition() { + } + + @Override + public boolean apply(Game game, Ability source) { + + List permanents = game.getBattlefield().getAllActivePermanents(mireFilter, game); + Permanent cyclopeanTombInstance = game.getPermanentOrLKIBattlefield(source.getSourceId()); + CyclopeanTombCounterWatcher watcher = (CyclopeanTombCounterWatcher) game.getState().getWatchers().get(CyclopeanTombCounterWatcher.class.getName()); + + for(Permanent land : permanents) { + if(watcher.landMiredByCyclopeanTombInstance(land, cyclopeanTombInstance, game)) { + return land.getCounters(game).getCount(CounterType.MIRE) > 0; + } + } + return false; + } +} + +class ChooseLandEffect extends OneShotEffect { + + public ChooseLandEffect() { + super(Outcome.Neutral); + this.staticText = "choose a land that a mire counter was put onto with Cyclopean Tomb but that a mire counter has not been removed from with Cyclopean Tomb"; + } + + public ChooseLandEffect(final ChooseLandEffect effect) { + super(effect); + } + + @Override + public ChooseLandEffect copy() { + return new ChooseLandEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + + Player controller = game.getPlayer(source.getControllerId()); + MageObject mageObject = game.getPermanentEntering(source.getSourceId()); + + if (mageObject == null) { + mageObject = game.getObject(source.getSourceId()); + } + + FilterLandPermanent filter = new FilterLandPermanent(); + filter.add(new LandIdPredicate(source)); + + if(controller != null && mageObject != null){ + TargetLandPermanent target = new TargetLandPermanent(1, 1, filter, true); + /*Player must choose a land each upkeep. Using the message are above the player hand where frequent interactions + * take place is the most logical way to prompt for this scenario. A new constructor added to provide a not optional + * option for any cards like this where the player must choose a target in such the way this card requires. + */ + if (controller.chooseTarget(Outcome.Neutral, target, source, game, false)) { + Permanent chosenLand = game.getPermanent(target.getFirstTarget()); + if(chosenLand != null) { + game.getState().setValue(mageObject.getId() + "_land", target.getFirstTarget()); + if (mageObject instanceof Permanent) { + ((Permanent) mageObject).addInfo("chosen land", CardUtil.addToolTipMarkTags("Chosen player: " + chosenLand.getLogName()), game); + } + return true; + } + } + } + return false; + } +} + +class LandIdPredicate implements Predicate { + + public Ability source; + + public LandIdPredicate(Ability source) { + this.source = source; + } + + @Override + public boolean apply(Permanent input, Game game) { + Permanent cyclopeanTombInstance = game.getPermanentOrLKIBattlefield(source.getSourceId()); + CyclopeanTombCounterWatcher watcher = (CyclopeanTombCounterWatcher) game.getState().getWatchers().get(CyclopeanTombCounterWatcher.class.getName()); + return watcher.landMiredByCyclopeanTombInstance(input, cyclopeanTombInstance, game); + } +} + +class CyclopeanTombCounterWatcher extends Watcher { + + public HashMap> counterData = new HashMap<>(); + + public CyclopeanTombCounterWatcher() { + super(CyclopeanTombCounterWatcher.class.getName(), WatcherScope.GAME); + } + + public CyclopeanTombCounterWatcher(final CyclopeanTombCounterWatcher watcher) { + super(watcher); + for (MageObjectReference mageObjectReference : watcher.counterData.keySet()) { + Set miredLands = new HashSet<>(); + miredLands.addAll(watcher.counterData.get(mageObjectReference)); + counterData.put(mageObjectReference, miredLands); + } + } + + @Override + public CyclopeanTombCounterWatcher copy() { + return new CyclopeanTombCounterWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + if(event.getType() == GameEvent.EventType.COUNTER_ADDED || event.getType() == GameEvent.EventType.COUNTERS_ADDED) { + MageObjectReference cylopeanTombInstance = new MageObjectReference(/*ID needs to go here*/, game); + Set miredLands = counterData.get(cylopeanTombInstance); + if (miredLands != null) { + miredLands.add(new MageObjectReference(event.getTargetId(), game)); + } else { + miredLands = new HashSet<>(); + miredLands.add(new MageObjectReference(event.getTargetId(), game)); + counterData.put(cylopeanTombInstance, miredLands); + } + } + } + + @Override + public void reset() { + super.reset(); + counterData.clear(); + } + + public boolean landMiredByCyclopeanTombInstance(Permanent land, Permanent cylopeanTombInstance, Game game) { + Set miredLands = counterData.get(new MageObjectReference(cylopeanTombInstance, game)); + return miredLands != null && miredLands.contains(new MageObjectReference(land, game)); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GaeasLiege.java b/Mage.Sets/src/mage/cards/g/GaeasLiege.java index 6e17bd4ae84..52014ab9381 100644 --- a/Mage.Sets/src/mage/cards/g/GaeasLiege.java +++ b/Mage.Sets/src/mage/cards/g/GaeasLiege.java @@ -32,6 +32,7 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.SourceAttackingCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.decorator.ConditionalContinuousEffect; @@ -74,9 +75,9 @@ public class GaeasLiege extends CardImpl { // As long as Gaea's Liege isn't attacking, its power and toughness are each equal to the number of Forests you control. As long as Gaea's Liege is attacking, its power and toughness are each equal to the number of Forests defending player controls. this.addAbility(new SimpleStaticAbility(Zone.ALL, new ConditionalContinuousEffect( - new SetPowerToughnessSourceEffect(new DefendersForestCount(), Duration.EndOfCombat), new SetPowerToughnessSourceEffect(new PermanentsOnBattlefieldCount(filterLands), Duration.EndOfGame), - SourceAttackingCondition.getInstance(), + new SetPowerToughnessSourceEffect(new DefendersForestCount(), Duration.EndOfCombat), + new InvertCondition(SourceAttackingCondition.getInstance()), "As long as {this} isn't attacking, its power and toughness are each equal to the number of Forests you control. As long as {this} is attacking, its power and toughness are each equal to the number of Forests defending player controls."))); // {tap}: Target land becomes a Forest until Gaea's Liege leaves the battlefield. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesBasicLandTargetEffect(Duration.WhileOnBattlefield, "Forest"), new TapSourceCost()); @@ -131,4 +132,4 @@ class DefendersForestCount implements DynamicValue { public String getMessage() { return "the number of Forests defending player controls"; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/g/GilderBairn.java b/Mage.Sets/src/mage/cards/g/GilderBairn.java index 24881249dd0..321e66118c5 100644 --- a/Mage.Sets/src/mage/cards/g/GilderBairn.java +++ b/Mage.Sets/src/mage/cards/g/GilderBairn.java @@ -40,6 +40,8 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.counters.Counter; +import mage.filter.FilterPermanent; +import mage.filter.predicate.permanent.CounterAnyPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; @@ -49,6 +51,12 @@ import mage.target.TargetPermanent; * @author LevelX2 */ public class GilderBairn extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(); + + static { + filter.add(new CounterAnyPredicate()); + } public GilderBairn(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G/U}{G/U}"); @@ -60,7 +68,7 @@ public class GilderBairn extends CardImpl { // {2}{GU}, {untap}: For each counter on target permanent, put another of those counters on that permanent. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GilderBairnEffect(), new ManaCostsImpl("{2}{G/U}")); ability.addCost(new UntapSourceCost()); - ability.addTarget(new TargetPermanent()); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/j/Jihad.java b/Mage.Sets/src/mage/cards/j/Jihad.java index aed2f07adba..06a6a0f9338 100644 --- a/Mage.Sets/src/mage/cards/j/Jihad.java +++ b/Mage.Sets/src/mage/cards/j/Jihad.java @@ -40,11 +40,11 @@ import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; -import mage.abilities.common.OnEventTriggeredAbility; +import mage.abilities.StateTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.constants.Duration; @@ -74,15 +74,10 @@ public class Jihad extends CardImpl { this.addAbility(new AsEntersBattlefieldAbility(new ChooseOpponentEffect(Outcome.Detriment))); // White creatures get +2/+1 as long as the chosen player controls a nontoken permanent of the chosen color. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(2, 1, Duration.WhileOnBattlefield, filter, false))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new BoostAllEffect(2, 1, Duration.WhileOnBattlefield, filter, false), new JihadOpponentCondition(), "White creatures get +2/+1 as long as the chosen player controls a nontoken permanent of the chosen color."))); // When the chosen player controls no nontoken permanents of the chosen color, sacrifice Jihad. - - // Not quite as immediate as I'd like but.. Static doesnt accept that effect and probably only work upon casting (maybe a continuous ability would, if not hog the system) - TriggeredAbility triggered = new OnEventTriggeredAbility(GameEvent.EventType.STEP_CHANGED, "end Jihad", true, new SacrificeSourceEffect()); - this.addAbility(new ConditionalTriggeredAbility(triggered, new NoColoredPermanentOpponentCondition(), "no nontoken permanents of the chosen color, sacrifice Jihad")); - //this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalOneShotEffect(new SacrificeSourceEffect()), new NoColoredPermanentOpponentCondition(), "Jihad ending")); - + this.addAbility(new JihadTriggeredAbility(new SacrificeSourceEffect())); } public Jihad(final Jihad card) { @@ -95,24 +90,44 @@ public class Jihad extends CardImpl { } } -class NoColoredPermanentOpponentCondition implements Condition { +class JihadTriggeredAbility extends StateTriggeredAbility { - private static NoColoredPermanentOpponentCondition fInstance = new NoColoredPermanentOpponentCondition(); - - public static Condition getInstance() { - return fInstance; + public JihadTriggeredAbility(Effect effect) { + super(Zone.BATTLEFIELD, effect); } + public JihadTriggeredAbility(final JihadTriggeredAbility ability) { + super(ability); + } + + @Override + public JihadTriggeredAbility copy() { + return new JihadTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + UUID chosenOpponent = (UUID) game.getState().getValue(getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY); + FilterPermanent filter = new FilterPermanent(); + filter.add(new ColorPredicate((ObjectColor) game.getState().getValue(getSourceId() + "_color"))); + filter.add(Predicates.not(new TokenPredicate())); + return game.getBattlefield().countAll(filter, chosenOpponent, game) == 0; + } + + @Override + public String getRule() { + return "When the chosen player controls no nontoken permanents of the chosen color, " + super.getRule(); + } +} + +class JihadOpponentCondition implements Condition { + @Override public boolean apply(Game game, Ability source) { UUID chosenOpponent = (UUID) game.getState().getValue(source.getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY); - FilterPermanent filter = new FilterPermanent(); filter.add(new ColorPredicate((ObjectColor) game.getState().getValue(source.getSourceId() + "_color"))); filter.add(Predicates.not(new TokenPredicate())); - //filter.add(new ColorPredicate(ObjectColor.WHITE)); // Given this typing, somehow the above doesn't seem right, but I copied from StoryCircle card - - return game.getBattlefield().countAll(filter, chosenOpponent, game)==0; - + return game.getBattlefield().countAll(filter, chosenOpponent, game) > 0; } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/LimitedEditionAlpha.java b/Mage.Sets/src/mage/sets/LimitedEditionAlpha.java index b01fe62f9d9..fc8932374ff 100644 --- a/Mage.Sets/src/mage/sets/LimitedEditionAlpha.java +++ b/Mage.Sets/src/mage/sets/LimitedEditionAlpha.java @@ -73,6 +73,7 @@ public class LimitedEditionAlpha extends ExpansionSet { cards.add(new SetCardInfo("Crusade", 200, Rarity.RARE, mage.cards.c.Crusade.class)); cards.add(new SetCardInfo("Crystal Rod", 239, Rarity.UNCOMMON, mage.cards.c.CrystalRod.class)); cards.add(new SetCardInfo("Cursed Land", 6, Rarity.UNCOMMON, mage.cards.c.CursedLand.class)); + cards.add(new SetCardInfo("Cyclopean Tomb", 240, Rarity.RARE, mage.cards.c.CyclopeanTomb.class)); cards.add(new SetCardInfo("Dark Ritual", 7, Rarity.COMMON, mage.cards.d.DarkRitual.class)); cards.add(new SetCardInfo("Deathgrip", 9, Rarity.UNCOMMON, mage.cards.d.Deathgrip.class)); cards.add(new SetCardInfo("Deathlace", 10, Rarity.RARE, mage.cards.d.Deathlace.class)); diff --git a/Mage.Sets/src/mage/sets/LimitedEditionBeta.java b/Mage.Sets/src/mage/sets/LimitedEditionBeta.java index 95055547027..cc95e865cf3 100644 --- a/Mage.Sets/src/mage/sets/LimitedEditionBeta.java +++ b/Mage.Sets/src/mage/sets/LimitedEditionBeta.java @@ -74,6 +74,7 @@ public class LimitedEditionBeta extends ExpansionSet { cards.add(new SetCardInfo("Crusade", 202, Rarity.RARE, mage.cards.c.Crusade.class)); cards.add(new SetCardInfo("Crystal Rod", 241, Rarity.UNCOMMON, mage.cards.c.CrystalRod.class)); cards.add(new SetCardInfo("Cursed Land", 6, Rarity.UNCOMMON, mage.cards.c.CursedLand.class)); + cards.add(new SetCardInfo("Cyclopean Tomb", 242, Rarity.RARE, mage.cards.c.CyclopeanTomb.class)); cards.add(new SetCardInfo("Dark Ritual", 7, Rarity.COMMON, mage.cards.d.DarkRitual.class)); cards.add(new SetCardInfo("Deathgrip", 9, Rarity.UNCOMMON, mage.cards.d.Deathgrip.class)); cards.add(new SetCardInfo("Deathlace", 10, Rarity.RARE, mage.cards.d.Deathlace.class)); diff --git a/Mage.Sets/src/mage/sets/MastersEditionIV.java b/Mage.Sets/src/mage/sets/MastersEditionIV.java index ba8957b1b4b..ed9a0246d7e 100644 --- a/Mage.Sets/src/mage/sets/MastersEditionIV.java +++ b/Mage.Sets/src/mage/sets/MastersEditionIV.java @@ -105,6 +105,7 @@ public class MastersEditionIV extends ExpansionSet { cards.add(new SetCardInfo("Crumble", 147, Rarity.COMMON, mage.cards.c.Crumble.class)); cards.add(new SetCardInfo("Cyclone", 148, Rarity.RARE, mage.cards.c.Cyclone.class)); cards.add(new SetCardInfo("Cyclopean Mummy", 72, Rarity.COMMON, mage.cards.c.CyclopeanMummy.class)); + cards.add(new SetCardInfo("Cyclopean Tomb", 195, Rarity.RARE, mage.cards.c.CyclopeanTomb.class)); cards.add(new SetCardInfo("Dakmor Plague", 73, Rarity.UNCOMMON, mage.cards.d.DakmorPlague.class)); cards.add(new SetCardInfo("Dark Ritual", 74, Rarity.COMMON, mage.cards.d.DarkRitual.class)); cards.add(new SetCardInfo("Deathcoil Wurm", 149, Rarity.RARE, mage.cards.d.DeathcoilWurm.class)); diff --git a/Mage.Sets/src/mage/sets/UnlimitedEdition.java b/Mage.Sets/src/mage/sets/UnlimitedEdition.java index c63a06be4b1..a33f4d15572 100644 --- a/Mage.Sets/src/mage/sets/UnlimitedEdition.java +++ b/Mage.Sets/src/mage/sets/UnlimitedEdition.java @@ -74,6 +74,7 @@ public class UnlimitedEdition extends ExpansionSet { cards.add(new SetCardInfo("Crusade", 201, Rarity.RARE, mage.cards.c.Crusade.class)); cards.add(new SetCardInfo("Crystal Rod", 240, Rarity.UNCOMMON, mage.cards.c.CrystalRod.class)); cards.add(new SetCardInfo("Cursed Land", 6, Rarity.UNCOMMON, mage.cards.c.CursedLand.class)); + cards.add(new SetCardInfo("Cyclopean Tomb", 241, Rarity.RARE, mage.cards.c.CyclopeanTomb.class)); cards.add(new SetCardInfo("Dark Ritual", 7, Rarity.COMMON, mage.cards.d.DarkRitual.class)); cards.add(new SetCardInfo("Deathgrip", 9, Rarity.UNCOMMON, mage.cards.d.Deathgrip.class)); cards.add(new SetCardInfo("Deathlace", 10, Rarity.RARE, mage.cards.d.Deathlace.class)); diff --git a/Mage/src/main/java/mage/abilities/condition/common/PermanentHasCounterCondition.java b/Mage/src/main/java/mage/abilities/condition/common/PermanentHasCounterCondition.java index 16d45219dc1..91609cc857a 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/PermanentHasCounterCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/PermanentHasCounterCondition.java @@ -49,9 +49,11 @@ public class PermanentHasCounterCondition implements Condition { private int amount; private FilterPermanent filter; private CountType type; + private boolean anyPlayer; public PermanentHasCounterCondition(CounterType counterType, int amount, FilterPermanent filter) { this(counterType, amount, filter, CountType.EQUAL_TO); + this.anyPlayer = false; } public PermanentHasCounterCondition(CounterType counterType, int amount, FilterPermanent filter, CountType type) { @@ -59,11 +61,22 @@ public class PermanentHasCounterCondition implements Condition { this.amount = amount; this.filter = filter; this.type = type; + this.anyPlayer = false; } + public PermanentHasCounterCondition(CounterType counterType, int amount, FilterPermanent filter, CountType type, boolean any) { + this.counterType = counterType; + this.amount = amount; + this.filter = filter; + this.type = type; + this.anyPlayer = any; + } @Override public boolean apply(Game game, Ability source) { List permanents = game.getBattlefield().getActivePermanents(this.filter, source.getControllerId(), game); + if(this.anyPlayer == true) { + permanents = game.getBattlefield().getAllActivePermanents(this.filter, game); + } for (Permanent permanent : permanents) { switch (this.type) { case FEWER_THAN: diff --git a/Mage/src/main/java/mage/abilities/effects/common/counter/RemoveAllCountersTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/counter/RemoveAllCountersTargetEffect.java new file mode 100644 index 00000000000..dfbdf3b5915 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/counter/RemoveAllCountersTargetEffect.java @@ -0,0 +1,71 @@ +/* + * 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.abilities.effects.common.counter; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author MTGfan + */ +public class RemoveAllCountersTargetEffect extends OneShotEffect { + + private final CounterType counterType; + + public RemoveAllCountersTargetEffect(CounterType counterType) { + super(Outcome.Neutral); + this.counterType = counterType; + staticText = "remove all " + counterType.getName() + " counters from it."; + } + + public RemoveAllCountersTargetEffect(RemoveAllCountersTargetEffect effect) { + super(effect); + this.counterType = effect.counterType; + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); + if(permanent != null) { + int count = permanent.getCounters(game).getCount(counterType); + permanent.removeCounters(counterType.getName(), count, game); + return true; + } + return false; + } + + @Override + public RemoveAllCountersTargetEffect copy() { + return new RemoveAllCountersTargetEffect(this); + } +} diff --git a/Mage/src/main/java/mage/counters/CounterType.java b/Mage/src/main/java/mage/counters/CounterType.java index f429bd35fff..87ddf281ad4 100644 --- a/Mage/src/main/java/mage/counters/CounterType.java +++ b/Mage/src/main/java/mage/counters/CounterType.java @@ -82,6 +82,7 @@ public enum CounterType { M2M1(new BoostCounter(-2, -1).name), M2M2(new BoostCounter(-2, -2).name), MINING("mining"), + MIRE("mire"), MUSTER("muster"), P0P1(new BoostCounter(0, 1).name), P1P0(new BoostCounter(1, 0).name),