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 0000000000..ad2e02a2ed --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CyclopeanTomb.java @@ -0,0 +1,197 @@ +/* + * 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.UUID; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.PutIntoGraveFromBattlefieldSourceTriggeredAbility; +import mage.abilities.condition.common.IsStepCondition; +import mage.abilities.condition.common.PermanentHasCounterCondition; +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.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.Zone; +import mage.counters.CounterType; +import mage.filter.common.FilterLandPermanent; +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; + +/** + * + * @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); + // 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 CycleDelayedTriggeredAbility()); + 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 CycleDelayedTriggeredAbility extends DelayedTriggeredAbility { + + CycleDelayedTriggeredAbility() { + super(new CyclopeanTombEffect(), Duration.OneUse, true, false); + } + + CycleDelayedTriggeredAbility(CycleDelayedTriggeredAbility ability) { + super(ability); + } + + @Override + public CycleDelayedTriggeredAbility copy() { + return new CycleDelayedTriggeredAbility(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 { + + private static final FilterLandPermanent mireFilter = new FilterLandPermanent(); + + static { + mireFilter.add(new CounterPredicate(CounterType.MIRE)); + } + + 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){ + /* + * + *Remove all counters from target code goes here. Created a RemoveAllCountersTargetEffect for that. + * + */ + //CyclopianTombEffect and CycleDelayedTriggeredAbility will maintain a loop + //as long as there are one or more mire counters left to be removed + new ConditionalOneShotEffect(new CreateDelayedTriggeredAbilityEffect(new CycleDelayedTriggeredAbility(), false), new PermanentHasCounterCondition(CounterType.MIRE, 0, new FilterLandPermanent(), PermanentHasCounterCondition.CountType.MORE_THAN, true)).apply(game, source); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/LimitedEditionAlpha.java b/Mage.Sets/src/mage/sets/LimitedEditionAlpha.java index b01fe62f9d..fc8932374f 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 9505554702..cc95e865cf 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 ba8957b1b4..ed9a0246d7 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 c63a06be4b..a33f4d1557 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 16d45219dc..91609cc857 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 0000000000..dfbdf3b591 --- /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 d546c2b875..1f359e697f 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),