diff --git a/Mage.Sets/src/mage/sets/newphyrexia/KarnLiberated.java b/Mage.Sets/src/mage/sets/newphyrexia/KarnLiberated.java new file mode 100644 index 00000000000..12046b5570d --- /dev/null +++ b/Mage.Sets/src/mage/sets/newphyrexia/KarnLiberated.java @@ -0,0 +1,205 @@ +/* + * 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.sets.newphyrexia; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Outcome; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileFromZoneTargetEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.game.ExileZone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.TargetPlayer; + +/** + * + * @author anonymous + */ +public class KarnLiberated extends CardImpl { + + private UUID exileId = UUID.randomUUID(); + + public KarnLiberated(UUID ownerId) { + super(ownerId, 1, "Karn Liberated", Rarity.MYTHIC, new CardType[]{CardType.PLANESWALKER}, "{7}"); + this.expansionSetCode = "NPH"; + this.subtype.add("Karn"); + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(6)), "")); + + // +4: Target player exiles a card from his or her hand. + LoyaltyAbility ability1 = new LoyaltyAbility(new ExileFromZoneTargetEffect(Zone.HAND, exileId, "Karn Liberated", new FilterCard()), 4); + ability1.addTarget(new TargetPlayer()); + this.addAbility(ability1); + + // -3: Exile target permanent. + LoyaltyAbility ability2 = new LoyaltyAbility(new ExileTargetEffect(), -3); + ability2.addTarget(new TargetPermanent()); + this.addAbility(ability2); + + // -14: Restart the game, leaving in exile all non-Aura permanent cards exiled with Karn Liberated. Then put those cards onto the battlefield under your control. + this.addAbility(new LoyaltyAbility(new KarnLiberatedEffect(exileId), -14)); + } + + public KarnLiberated(final KarnLiberated card) { + super(card); + } + + @Override + public KarnLiberated copy() { + return new KarnLiberated(this); + } +} + +class KarnLiberatedEffect extends OneShotEffect { + + private UUID exileId; + + public KarnLiberatedEffect(UUID exileId) { + super(Outcome.ExtraTurn); + this.exileId = exileId; + this.staticText = "Restart the game, leaving in exile all non-Aura permanent cards exiled with {this}. Then put those cards onto the battlefield under your control."; + } + + public KarnLiberatedEffect(final KarnLiberatedEffect effect) { + super(effect); + this.exileId = effect.exileId; + } + + @Override + public boolean apply(Game game, Ability source) { + List cards = new ArrayList(); + for (ExileZone zone: game.getExile().getExileZones()) { + if (zone.getId().equals(exileId)) { + for (Card card: zone.getCards(game)) { + if (!card.getSubtype().contains("Aura")) + cards.add(card); + } + } + } + game.getState().clear(); + for (Player player: game.getPlayers().values()) { + player.getGraveyard().clear(); + player.getHand().clear(); + player.getLibrary().clear(); + for (Card card: game.getCards()) { + if (card.getOwnerId().equals(player.getId())) { + player.getLibrary().putOnTop(card, game); + } + } + player.init(game); + } + for (Card card: cards) { + game.getExile().add(exileId, "Karn Liberated", card); + } + DelayedTriggeredAbility delayedAbility = new KarnLiberatedDelayedTriggeredAbility(exileId); + delayedAbility.setSourceId(source.getSourceId()); + delayedAbility.setControllerId(source.getControllerId()); + game.addDelayedTriggeredAbility(delayedAbility); + game.start(null); + return true; + } + + @Override + public KarnLiberatedEffect copy() { + return new KarnLiberatedEffect(this); + } + +} + +class KarnLiberatedDelayedTriggeredAbility extends DelayedTriggeredAbility { + + public KarnLiberatedDelayedTriggeredAbility(UUID exileId) { + super(new KarnLiberatedDelayedEffect(exileId)); + } + + public KarnLiberatedDelayedTriggeredAbility(final KarnLiberatedDelayedTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == EventType.BEGINNING_PHASE_PRE) { + return true; + } + return false; + } + + @Override + public KarnLiberatedDelayedTriggeredAbility copy() { + return new KarnLiberatedDelayedTriggeredAbility(this); + } + +} + +class KarnLiberatedDelayedEffect extends OneShotEffect { + + private UUID exileId; + + public KarnLiberatedDelayedEffect(UUID exileId) { + super(Outcome.PlayForFree); + this.exileId = exileId; + this.staticText = "Put those cards onto the battlefield under your control"; + } + + public KarnLiberatedDelayedEffect(final KarnLiberatedDelayedEffect effect) { + super(effect); + this.exileId = effect.exileId; + } + + @Override + public boolean apply(Game game, Ability source) { + ExileZone exile = game.getExile().getExileZone(exileId); + for (Card card: exile.getCards(game)) { + card.putOntoBattlefield(game, Zone.EXILED, source.getSourceId(), source.getControllerId()); + } + return true; + } + + @Override + public KarnLiberatedDelayedEffect copy() { + return new KarnLiberatedDelayedEffect(this); + } + +} \ No newline at end of file diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java index 34417b534bf..175396277b5 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java @@ -52,6 +52,7 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; + /** * * @author BetaSteward_at_googlemail.com @@ -537,8 +538,18 @@ public class ContinuousEffects implements Serializable { } } -} + public void clear() { + layeredEffects.clear(); + replacementEffects.clear(); + preventionEffects.clear(); + requirementEffects.clear(); + restrictionEffects.clear(); + asThoughEffects.clear(); + costModificationEffects.clear(); + abilityMap.clear(); + } +} class TimestampSorter implements Comparator { @Override public int compare(ContinuousEffect one, ContinuousEffect two) { diff --git a/Mage/src/mage/abilities/effects/common/ExileFromZoneTargetEffect.java b/Mage/src/mage/abilities/effects/common/ExileFromZoneTargetEffect.java new file mode 100644 index 00000000000..6e4460a3fa0 --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/ExileFromZoneTargetEffect.java @@ -0,0 +1,108 @@ +/* + * Copyright 2011 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; + +import java.util.UUID; +import mage.Constants.Outcome; +import mage.Constants.Zone; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetCardInHand; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class ExileFromZoneTargetEffect extends OneShotEffect { + + private Zone zone; + private FilterCard filter; + private UUID exileId; + private String exileName; + + public ExileFromZoneTargetEffect(Zone zone, UUID exileId, String exileName, FilterCard filter) { + super(Outcome.Exile); + this.zone = zone; + this.filter = filter; + this.exileId = exileId; + this.exileName = exileName; + setText(); + } + + public ExileFromZoneTargetEffect(final ExileFromZoneTargetEffect effect) { + super(effect); + this.zone = effect.zone; + this.filter = effect.filter.copy(); + this.exileId = effect.exileId; + this.exileName = effect.exileName; + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(targetPointer.getFirst(source)); + if (player != null) { + Target target; + Card card = null; + switch (zone) { + case HAND: + target = new TargetCardInHand(filter); + player.choose(Outcome.Exile, target, game); + card = player.getHand().get(target.getFirstTarget(), game); + break; + case GRAVEYARD: + target = new TargetCardInGraveyard(filter); + player.choose(Outcome.Exile, target, game); + card = player.getGraveyard().get(target.getFirstTarget(), game); + break; + default: + + } + if (card != null) { + card.moveToExile(exileId, exileName, source.getSourceId(), game); + return true; + } + } + return false; + } + + @Override + public ExileFromZoneTargetEffect copy() { + return new ExileFromZoneTargetEffect(this); + } + + private void setText() { + staticText = "Target player exiles a " + filter.getMessage() + " from his or her " + zone.toString(); + } + +} diff --git a/Mage/src/mage/game/Exile.java b/Mage/src/mage/game/Exile.java index c47378526d1..374de688519 100644 --- a/Mage/src/mage/game/Exile.java +++ b/Mage/src/mage/game/Exile.java @@ -114,4 +114,10 @@ public class Exile implements Serializable, Copyable { public Exile copy() { return new Exile(this); } + + public void clear() { + for (ExileZone exile: exileZones.values()) { + exile.clear(); + } + } } diff --git a/Mage/src/mage/game/GameState.java b/Mage/src/mage/game/GameState.java index eab90fb18fd..4f71f40f2c9 100644 --- a/Mage/src/mage/game/GameState.java +++ b/Mage/src/mage/game/GameState.java @@ -409,4 +409,24 @@ public class GameState implements Serializable, Copyable { values.put(valueId, value); } + public void clear() { + battlefield.clear(); + effects.clear(); + delayed.clear(); + triggers.clear(); + stack.clear(); + exile.clear(); + command.clear(); + revealed.clear(); + lookedAt.clear(); + turnNum = 0; + gameOver = false; + specialActions.clear(); + combat.clear(); + turnMods.clear(); + watchers.clear(); + values.clear(); + zones.clear(); + } + }