diff --git a/Mage.Sets/src/mage/sets/darkascension/ClingingMists.java b/Mage.Sets/src/mage/sets/darkascension/ClingingMists.java new file mode 100644 index 00000000000..bf83b85f146 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/ClingingMists.java @@ -0,0 +1,150 @@ +/* + * 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.darkascension; + +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.abilities.Ability; +import mage.abilities.condition.common.FatefulHourCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.PreventAllDamageEffect; +import mage.cards.CardImpl; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterAttackingCreature; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author BetaSteward + */ +public class ClingingMists extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(); + + public ClingingMists(UUID ownerId) { + super(ownerId, 109, "Clinging Mists", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{2}{G}"); + this.expansionSetCode = "DKA"; + + this.color.setGreen(true); + + // Prevent all combat damage that would be dealt this turn. + this.getSpellAbility().addEffect(new PreventAllDamageEffect(filter, Constants.Duration.EndOfTurn, true)); + + // Fateful hour — If you have 5 or less life, tap all attacking creatures. Those creatures don't untap during their controller's next untap step. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new ClingingMistsEffect(), + FatefulHourCondition.getInstance(), "If you have 5 or less life, tap all attacking creatures. Those creatures don't untap during their controller's next untap step.")); + + } + + public ClingingMists(final ClingingMists card) { + super(card); + } + + @Override + public ClingingMists copy() { + return new ClingingMists(this); + } +} + +class ClingingMistsEffect extends OneShotEffect { + + private static final FilterAttackingCreature filter = new FilterAttackingCreature("attacking creatures"); + + public ClingingMistsEffect() { + super(Constants.Outcome.Tap); + staticText = "tap all attacking creatures. Those creatures don't untap during their controller's next untap step"; + } + + public ClingingMistsEffect(final ClingingMistsEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + for (Permanent creature: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + creature.tap(game); + game.addEffect(new ClingingMistsEffect2(creature.getId()), source); + } + return true; + } + + @Override + public ClingingMistsEffect copy() { + return new ClingingMistsEffect(this); + } + +} + +class ClingingMistsEffect2 extends ReplacementEffectImpl { + + protected UUID creatureId; + + public ClingingMistsEffect2(UUID creatureId) { + super(Constants.Duration.OneUse, Constants.Outcome.Detriment); + this.creatureId = creatureId; + } + + public ClingingMistsEffect2(final ClingingMistsEffect2 effect) { + super(effect); + creatureId = effect.creatureId; + } + + @Override + public ClingingMistsEffect2 copy() { + return new ClingingMistsEffect2(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + used = true; + return true; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (game.getTurn().getStepType() == Constants.PhaseStep.UNTAP && + event.getType() == GameEvent.EventType.UNTAP && + event.getTargetId().equals(creatureId)) { + return true; + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/sets/darkascension/DeadlyAllure.java b/Mage.Sets/src/mage/sets/darkascension/DeadlyAllure.java new file mode 100644 index 00000000000..0e2bfdd85d6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/DeadlyAllure.java @@ -0,0 +1,74 @@ +/* + * 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.darkascension; + +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.MustBlockSourceEffect; +import mage.abilities.effects.common.continious.GainAbilityTargetEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.FlashbackAbility; +import mage.cards.CardImpl; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author BetaSteward + */ +public class DeadlyAllure extends CardImpl { + + public DeadlyAllure(UUID ownerId) { + super(ownerId, 58, "Deadly Allure", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{B}"); + this.expansionSetCode = "DKA"; + + this.color.setBlack(true); + + // Target creature gains deathtouch until end of turn and must be blocked this turn if able. + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(new SimpleStaticAbility(Constants.Zone.BATTLEFIELD, new MustBlockSourceEffect()), Constants.Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(DeathtouchAbility.getInstance(), Constants.Duration.EndOfTurn)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Flashback {G} + this.addAbility(new FlashbackAbility(new ManaCostsImpl("{G}"), Constants.TimingRule.SORCERY)); + + } + + public DeadlyAllure(final DeadlyAllure card) { + super(card); + } + + @Override + public DeadlyAllure copy() { + return new DeadlyAllure(this); + } +} + diff --git a/Mage.Sets/src/mage/sets/darkascension/FeedThePack.java b/Mage.Sets/src/mage/sets/darkascension/FeedThePack.java new file mode 100644 index 00000000000..50640d52474 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/FeedThePack.java @@ -0,0 +1,114 @@ +/* + * 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.darkascension; + +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Outcome; +import mage.Constants.Rarity; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfYourEndStepTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.filter.Filter; +import mage.filter.common.FilterNonTokenPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.WolfToken; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author BetaSteward + */ +public class FeedThePack extends CardImpl { + + public FeedThePack(UUID ownerId) { + super(ownerId, 114, "Feed the Pack", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{5}{G}"); + this.expansionSetCode = "DKA"; + + this.color.setGreen(true); + + // At the beginning of your end step, you may sacrifice a nontoken creature. If you do, put X 2/2 green Wolf creature tokens onto the battlefield, where X is the sacrificed creature's toughness. + this.addAbility(new BeginningOfYourEndStepTriggeredAbility(new FeedThePackEffect(), true)); + } + + public FeedThePack(final FeedThePack card) { + super(card); + } + + @Override + public FeedThePack copy() { + return new FeedThePack(this); + } +} + +class FeedThePackEffect extends OneShotEffect { + + private static final FilterNonTokenPermanent filter = new FilterNonTokenPermanent("nontoken creature"); + + static { + filter.getCardType().add(CardType.CREATURE); + filter.setScopeCardType(Filter.ComparisonScope.Any); + filter.setTargetController(Constants.TargetController.YOU); + } + + public FeedThePackEffect() { + super(Constants.Outcome.Sacrifice); + this.staticText = "sacrifice a nontoken creature. If you do, put X 2/2 green Wolf creature tokens onto the battlefield, where X is the sacrificed creature's toughness"; + } + + public FeedThePackEffect(final FeedThePackEffect effect) { + super(effect); + } + + @Override + public FeedThePackEffect copy() { + return new FeedThePackEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Target target = new TargetPermanent(filter); + Player player = game.getPlayer(source.getControllerId()); + if (player.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null && permanent.sacrifice(source.getSourceId(), game)) { + int toughness = permanent.getToughness().getValue(); + WolfToken token = new WolfToken(); + token.putOntoBattlefield(toughness, game, source.getSourceId(), source.getControllerId()); + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/darkascension/FlayerOfTheHatebound.java b/Mage.Sets/src/mage/sets/darkascension/FlayerOfTheHatebound.java new file mode 100644 index 00000000000..63d5b4777ce --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/FlayerOfTheHatebound.java @@ -0,0 +1,157 @@ +/* + * 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.darkascension; + +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.UndyingAbility; +import mage.cards.CardImpl; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author BetaSteward + */ +public class FlayerOfTheHatebound extends CardImpl { + + public FlayerOfTheHatebound(UUID ownerId) { + super(ownerId, 89, "Flayer of the Hatebound", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{5}{R}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Devil"); + + this.color.setRed(true); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + this.addAbility(new UndyingAbility()); + + // Whenever Flayer of the Hatebound or another creature enters the battlefield from your graveyard, that creature deals damage equal to its power to target creature or player. + Ability ability = new FlayerTriggeredAbility(); + ability.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(ability); + } + + public FlayerOfTheHatebound(final FlayerOfTheHatebound card) { + super(card); + } + + @Override + public FlayerOfTheHatebound copy() { + return new FlayerOfTheHatebound(this); + } +} + +class FlayerTriggeredAbility extends TriggeredAbilityImpl { + + public FlayerTriggeredAbility() { + super(Constants.Zone.BATTLEFIELD, new FlayerEffect(), false); + } + + public FlayerTriggeredAbility(FlayerTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ZONE_CHANGE) { + Permanent permanent = game.getPermanent(event.getTargetId()); + if (((ZoneChangeEvent) event).getToZone() == Constants.Zone.BATTLEFIELD + && ((ZoneChangeEvent) event).getFromZone() == Constants.Zone.GRAVEYARD + && permanent.getOwnerId().equals(controllerId) + && permanent.getCardType().contains(CardType.CREATURE)) { + Effect effect = this.getEffects().get(0); + effect.setValue("damageSource", event.getTargetId()); + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever Flayer of the Hatebound or another creature enters the battlefield from your graveyard, that creature deals damage equal to its power to target creature or player."; + } + + @Override + public FlayerTriggeredAbility copy() { + return new FlayerTriggeredAbility(this); + } +} + +class FlayerEffect extends OneShotEffect { + + public FlayerEffect() { + super(Constants.Outcome.Damage); + staticText = "that creature deals damage equal to its power to target creature or player"; + } + + public FlayerEffect(final FlayerEffect effect) { + super(effect); + } + + @Override + public FlayerEffect copy() { + return new FlayerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + UUID creatureId = (UUID) getValue("damageSource"); + Permanent creature = game.getPermanent(creatureId); + if (creature == null) { + creature = (Permanent) game.getLastKnownInformation(creatureId, Constants.Zone.BATTLEFIELD); + } + if (creature != null) { + int amount = creature.getPower().getValue(); + UUID target = source.getTargets().getFirstTarget(); + Permanent targetCreature = game.getPermanent(target); + if (targetCreature != null) { + targetCreature.damage(amount, creature.getId(), game, true, false); + return true; + } + Player player = game.getPlayer(target); + if (player != null) { + player.damage(amount, creature.getId(), game, false, true); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/GruesomeDiscovery.java b/Mage.Sets/src/mage/sets/darkascension/GruesomeDiscovery.java new file mode 100644 index 00000000000..d490294c179 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/GruesomeDiscovery.java @@ -0,0 +1,124 @@ +/* + * 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.darkascension; + +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.condition.common.MorbidCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DiscardTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPlayer; + +/** + * + * @author North + */ +public class GruesomeDiscovery extends CardImpl { + + public GruesomeDiscovery(UUID ownerId) { + super(ownerId, 66, "Gruesome Discovery", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{2}{B}{B}"); + this.expansionSetCode = "DKA"; + + this.color.setBlack(true); + + // Target player discards two cards. + // Morbid - If a creature died this turn, instead that player reveals his or her hand, you choose two cards from it, then that player discards those cards. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new GruesomeDiscoveryEffect(), + new DiscardTargetEffect(2), + MorbidCondition.getInstance(), + "Target player discards two cards. Morbid - If a creature died this turn, instead that player reveals his or her hand, you choose two cards from it, then that player discards those cards")); + this.getSpellAbility().addTarget(new TargetPlayer()); + } + + public GruesomeDiscovery(final GruesomeDiscovery card) { + super(card); + } + + @Override + public GruesomeDiscovery copy() { + return new GruesomeDiscovery(this); + } +} + +class GruesomeDiscoveryEffect extends OneShotEffect { + + public GruesomeDiscoveryEffect() { + super(Outcome.Discard); + this.staticText = "target player reveals his or her hand, you choose two cards from it, then that player discards those cards"; + } + + public GruesomeDiscoveryEffect(final GruesomeDiscoveryEffect effect) { + super(effect); + } + + @Override + public GruesomeDiscoveryEffect copy() { + return new GruesomeDiscoveryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Player targetPlayer = game.getPlayer(source.getFirstTarget()); + + if (player != null && targetPlayer != null) { + targetPlayer.revealCards("Gruesome Discovery", targetPlayer.getHand(), game); + + if (targetPlayer.getHand().size() <= 2) { + targetPlayer.discard(2, source, game); + } + + TargetCard target = new TargetCard(2, Zone.PICK, new FilterCard()); + target.setRequired(true); + if (player.choose(Outcome.Benefit, targetPlayer.getHand(), target, game)) { + List targets = target.getTargets(); + for (UUID targetId : targets) { + Card card = targetPlayer.getHand().get(targetId, game); + if (card != null) { + return targetPlayer.discard(card, source, game); + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/Hellrider.java b/Mage.Sets/src/mage/sets/darkascension/Hellrider.java new file mode 100644 index 00000000000..2c251c07b01 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/Hellrider.java @@ -0,0 +1,105 @@ +/* + * 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.darkascension; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author North + */ +public class Hellrider extends CardImpl { + + public Hellrider(UUID ownerId) { + super(ownerId, 93, "Hellrider", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Devil"); + + this.color.setRed(true); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + this.addAbility(HasteAbility.getInstance()); + // Whenever a creature you control attacks, Hellrider deals 1 damage to defending player. + this.addAbility(new HellriderTriggeredAbility()); + } + + public Hellrider(final Hellrider card) { + super(card); + } + + @Override + public Hellrider copy() { + return new Hellrider(this); + } +} + +class HellriderTriggeredAbility extends TriggeredAbilityImpl { + + public HellriderTriggeredAbility() { + super(Zone.BATTLEFIELD, new DamageTargetEffect(1)); + } + + public HellriderTriggeredAbility(final HellriderTriggeredAbility ability) { + super(ability); + } + + @Override + public HellriderTriggeredAbility copy() { + return new HellriderTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED) { + Permanent source = game.getPermanent(event.getSourceId()); + if (source != null && source.getControllerId().equals(controllerId)) { + this.getEffects().get(0).setTargetPointer(new FixedTarget(event.getTargetId())); + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever a creature you control attacks, {this} deals 1 damage to defending player."; + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/HinterlandHermit.java b/Mage.Sets/src/mage/sets/darkascension/HinterlandHermit.java new file mode 100644 index 00000000000..144f252f40b --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/HinterlandHermit.java @@ -0,0 +1,76 @@ +/* + * 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.darkascension; + +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.MageInt; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.common.NoSpellsWereCastLastTurnCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.keyword.TransformAbility; +import mage.cards.CardImpl; + +/** + * + * @author BetaSteward + */ +public class HinterlandHermit extends CardImpl { + + public HinterlandHermit(UUID ownerId) { + super(ownerId, 94, "Hinterland Hermit", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{R}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Human"); + this.subtype.add("Werewolf"); + + this.canTransform = true; + this.secondSideCard = new HinterlandScourge(ownerId); + + this.color.setRed(true); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // At the beginning of each upkeep, if no spells were cast last turn, transform Hinterland Hermit. + this.addAbility(new TransformAbility()); + TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect(true), Constants.TargetController.ANY, false); + this.addAbility(new ConditionalTriggeredAbility(ability, NoSpellsWereCastLastTurnCondition.getInstance(), TransformAbility.NO_SPELLS_TRANSFORM_RULE)); + } + + public HinterlandHermit(final HinterlandHermit card) { + super(card); + } + + @Override + public HinterlandHermit copy() { + return new HinterlandHermit(this); + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/HinterlandScourge.java b/Mage.Sets/src/mage/sets/darkascension/HinterlandScourge.java new file mode 100644 index 00000000000..39847d0ef48 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/HinterlandScourge.java @@ -0,0 +1,79 @@ +/* + * 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.darkascension; + +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.MageInt; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.TwoOrMoreSpellsWereCastLastTurnCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.MustBlockSourceEffect; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.keyword.TransformAbility; +import mage.cards.CardImpl; + +/** + * + * @author BetaSteward + */ +public class HinterlandScourge extends CardImpl { + + public HinterlandScourge(UUID ownerId) { + super(ownerId, 94, "Hinterland Scourge", Rarity.COMMON, new CardType[]{CardType.CREATURE}, ""); + this.expansionSetCode = "DKA"; + this.subtype.add("Werewolf"); + + // this card is the second face of double-faced card + this.nightCard = true; + this.canTransform = true; + + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Hinterland Scourge must be blocked if able. + this.addAbility(new SimpleStaticAbility(Constants.Zone.BATTLEFIELD, new MustBlockSourceEffect())); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Hinterland Scourge. + TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect(false), Constants.TargetController.ANY, false); + this.addAbility(new ConditionalTriggeredAbility(ability, TwoOrMoreSpellsWereCastLastTurnCondition.getInstance(), TransformAbility.TWO_OR_MORE_SPELLS_TRANSFORM_RULE)); + } + + public HinterlandScourge(final HinterlandScourge card) { + super(card); + } + + @Override + public HinterlandScourge copy() { + return new HinterlandScourge(this); + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/JarOfEyeballs.java b/Mage.Sets/src/mage/sets/darkascension/JarOfEyeballs.java new file mode 100644 index 00000000000..a91199446cd --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/JarOfEyeballs.java @@ -0,0 +1,233 @@ +/* + * 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.darkascension; + +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.TriggeredAbilityImpl; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetCard; + +/** + * + * @author North + */ +public class JarOfEyeballs extends CardImpl { + + public JarOfEyeballs(UUID ownerId) { + super(ownerId, 152, "Jar of Eyeballs", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{3}"); + this.expansionSetCode = "DKA"; + + // Whenever a creature you control dies, put two eyeball counters on Jar of Eyeballs. + this.addAbility(new JarOfEyeballsTriggeredAbility()); + // {3}, {tap}, Remove all eyeball counters from Jar of Eyeballs: + // Look at the top X cards of your library, where X is the number of eyeball counters removed this way. + // Put one of them into your hand and the rest on the bottom of your library in any order. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new JarOfEyeballsEffect(), new GenericManaCost(3)); + ability.addCost(new TapSourceCost()); + ability.addCost(new JarOfEyeballsCost()); + this.addAbility(ability); + } + + public JarOfEyeballs(final JarOfEyeballs card) { + super(card); + } + + @Override + public JarOfEyeballs copy() { + return new JarOfEyeballs(this); + } +} + +class JarOfEyeballsTriggeredAbility extends TriggeredAbilityImpl { + + public JarOfEyeballsTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.EYEBALL.createInstance(2))); + } + + public JarOfEyeballsTriggeredAbility(final JarOfEyeballsTriggeredAbility ability) { + super(ability); + } + + @Override + public JarOfEyeballsTriggeredAbility copy() { + return new JarOfEyeballsTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ZONE_CHANGE + && ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD + && ((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD) { + Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); + if (permanent.getControllerId().equals(this.getControllerId()) && permanent.getCardType().contains(CardType.CREATURE)) { + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever a creature you control dies, " + super.getRule(); + } +} + +class JarOfEyeballsCost extends CostImpl { + + private int removedCounters; + + public JarOfEyeballsCost() { + super(); + this.removedCounters = 0; + this.text = "Remove all eyeball counters from {this}"; + } + + public JarOfEyeballsCost(JarOfEyeballsCost cost) { + super(cost); + this.removedCounters = cost.removedCounters; + } + + @Override + public boolean canPay(UUID sourceId, UUID controllerId, Game game) { + return true; + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + Permanent permanent = game.getPermanent(ability.getSourceId()); + if (permanent != null) { + this.removedCounters = permanent.getCounters().getCount(CounterType.EYEBALL); + if (this.removedCounters > 0) { + permanent.removeCounters(CounterType.EYEBALL.createInstance(this.removedCounters), game); + } + } + this.paid = true; + return true; + } + + @Override + public JarOfEyeballsCost copy() { + return new JarOfEyeballsCost(this); + } + + public int getRemovedCounters() { + return this.removedCounters; + } +} + +class JarOfEyeballsEffect extends OneShotEffect { + + public JarOfEyeballsEffect() { + super(Outcome.DrawCard); + this.staticText = "Look at the top X cards of your library, where X is the number of eyeball counters removed this way. Put one of them into your hand and the rest on the bottom of your library in any order"; + } + + public JarOfEyeballsEffect(final JarOfEyeballsEffect effect) { + super(effect); + } + + @Override + public JarOfEyeballsEffect copy() { + return new JarOfEyeballsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int countersRemoved = 0; + for (Cost cost : source.getCosts()) { + if (cost instanceof JarOfEyeballsCost) { + countersRemoved = ((JarOfEyeballsCost) cost).getRemovedCounters(); + } + } + + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + + Cards cards = new CardsImpl(Zone.PICK); + int count = Math.min(player.getLibrary().size(), countersRemoved); + for (int i = 0; i < count; i++) { + Card card = player.getLibrary().removeFromTop(game); + if (card != null) { + cards.add(card); + game.setZone(card.getId(), Zone.PICK); + } + } + player.lookAtCards("Jar of Eyeballs", cards, game); + + TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put into your hand")); + if (player.choose(Outcome.DrawCard, cards, target, game)) { + Card card = cards.get(target.getFirstTarget(), game); + if (card != null) { + cards.remove(card); + card.moveToZone(Zone.HAND, source.getId(), game, false); + } + } + + target = new TargetCard(Zone.PICK, new FilterCard("card to put on the bottom of your library")); + target.setRequired(true); + while (cards.size() > 1) { + player.choose(Outcome.Neutral, cards, target, game); + Card card = cards.get(target.getFirstTarget(), game); + if (card != null) { + cards.remove(card); + card.moveToZone(Zone.LIBRARY, source.getId(), game, false); + } + target.clearChosen(); + } + if (cards.size() == 1) { + Card card = cards.get(cards.iterator().next(), game); + card.moveToZone(Zone.LIBRARY, source.getId(), game, false); + } + + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/LoyalCathar.java b/Mage.Sets/src/mage/sets/darkascension/LoyalCathar.java new file mode 100644 index 00000000000..13b0db5a6dc --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/LoyalCathar.java @@ -0,0 +1,148 @@ +/* + * 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.darkascension; + +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.common.delayed.AtEndOfTurnDelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnFromExileEffect; +import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.game.ExileZone; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author BetaSteward + */ +public class LoyalCathar extends CardImpl { + + public LoyalCathar(UUID ownerId) { + super(ownerId, 13, "Loyal Cathar", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{W}{W}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Human"); + this.subtype.add("Soldier"); + + this.canTransform = true; + this.secondSideCard = new UnhallowedCathar(ownerId); + + this.color.setWhite(true); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + this.addAbility(VigilanceAbility.getInstance()); + + // When Loyal Cathar dies, return it to the battlefield transformed under your control at the beginning of the next end step. + this.addAbility(new TransformAbility()); + this.addAbility(new DiesTriggeredAbility(new LoyalCatharEffect())); + } + + public LoyalCathar(final LoyalCathar card) { + super(card); + } + + @Override + public LoyalCathar copy() { + return new LoyalCathar(this); + } +} + +class LoyalCatharEffect extends OneShotEffect { + + private static final String effectText = "return it to the battlefield transformed under your control at the beginning of the next end step"; + + LoyalCatharEffect ( ) { + super(Constants.Outcome.Benefit); + staticText = effectText; + } + + LoyalCatharEffect(LoyalCatharEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + //create delayed triggered ability + AtEndOfTurnDelayedTriggeredAbility delayedAbility = new AtEndOfTurnDelayedTriggeredAbility(new ReturnLoyalCatharEffect(source.getSourceId())); + delayedAbility.setSourceId(source.getSourceId()); + delayedAbility.setControllerId(source.getControllerId()); + game.addDelayedTriggeredAbility(delayedAbility); + return true; + } + + @Override + public LoyalCatharEffect copy() { + return new LoyalCatharEffect(this); + } + +} + +class ReturnLoyalCatharEffect extends OneShotEffect { + + private UUID cardId; + + public ReturnLoyalCatharEffect(UUID cardId) { + super(Constants.Outcome.PutCardInPlay); + this.cardId = cardId; + this.staticText = "return it to the battlefield transformed under your control"; + } + + public ReturnLoyalCatharEffect(final ReturnLoyalCatharEffect effect) { + super(effect); + this.cardId = effect.cardId; + } + + @Override + public ReturnLoyalCatharEffect copy() { + return new ReturnLoyalCatharEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Card card = game.getCard(cardId); + if (card != null) { + card.putOntoBattlefield(game, Constants.Zone.GRAVEYARD, source.getSourceId(), source.getControllerId()); + Permanent perm = game.getPermanent(cardId); + if (perm != null && perm.canTransform()) { + perm.transform(game); + return true; + } + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/sets/darkascension/Seance.java b/Mage.Sets/src/mage/sets/darkascension/Seance.java new file mode 100644 index 00000000000..70a6c61b7b4 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/Seance.java @@ -0,0 +1,118 @@ +/* + * 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.darkascension; + +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.delayed.AtEndOfTurnDelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.filter.common.FilterCreatureCard; +import mage.game.Game; +import mage.sets.tokens.EmptyToken; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +/** + * + * @author BetaSteward + */ +public class Seance extends CardImpl { + + public Seance(UUID ownerId) { + super(ownerId, 20, "Seance", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); + this.expansionSetCode = "DKA"; + + this.color.setWhite(true); + + // At the beginning of each upkeep, you may exile target creature card from your graveyard. If you do, put a token onto the battlefield that's a copy of that card except it's a Spirit in addition to its other types. Exile it at the beginning of the next end step. + Ability ability = new BeginningOfUpkeepTriggeredAbility(new SeanceEffect(), Constants.TargetController.ANY, true); + ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard())); + this.addAbility(ability); + } + + public Seance(final Seance card) { + super(card); + } + + @Override + public Seance copy() { + return new Seance(this); + } +} + +class SeanceEffect extends OneShotEffect { + + public SeanceEffect() { + super(Constants.Outcome.PutCreatureInPlay); + this.staticText = "put a token onto the battlefield that's a copy of that card except it's a Spirit in addition to its other types. Exile it at the beginning of the next end step"; + } + + public SeanceEffect(final SeanceEffect effect) { + super(effect); + } + + @Override + public SeanceEffect copy() { + return new SeanceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Card card = game.getCard(source.getFirstTarget()); + if (card != null) { + card.moveToExile(null, "", source.getSourceId(), game); + EmptyToken token = new EmptyToken(); + CardUtil.copyTo(token).from(card); + + if (!token.getSubtype().contains("Spirit")) + token.getSubtype().add("Spirit"); + token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId()); + + ExileTargetEffect exileEffect = new ExileTargetEffect(); + exileEffect.setTargetPointer(new FixedTarget(token.getLastAddedToken())); + DelayedTriggeredAbility delayedAbility = new AtEndOfTurnDelayedTriggeredAbility(exileEffect); + delayedAbility.setSourceId(source.getSourceId()); + delayedAbility.setControllerId(source.getControllerId()); + game.addDelayedTriggeredAbility(delayedAbility); + + return true; + } + + return false; + } + +} diff --git a/Mage.Sets/src/mage/sets/darkascension/SpitefulShadows.java b/Mage.Sets/src/mage/sets/darkascension/SpitefulShadows.java new file mode 100644 index 00000000000..33cf2df5064 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/SpitefulShadows.java @@ -0,0 +1,151 @@ +/* + * 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.darkascension; + +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.TriggeredAbilityImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.game.Game; +import mage.game.events.DamagedCreatureEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author North + */ +public class SpitefulShadows extends CardImpl { + + public SpitefulShadows(UUID ownerId) { + super(ownerId, 75, "Spiteful Shadows", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Aura"); + + this.color.setBlack(true); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.UnboostCreature)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + // Whenever enchanted creature is dealt damage, it deals that much damage to its controller. + this.addAbility(new SpitefulShadowsTriggeredAbility()); + } + + public SpitefulShadows(final SpitefulShadows card) { + super(card); + } + + @Override + public SpitefulShadows copy() { + return new SpitefulShadows(this); + } +} + +class SpitefulShadowsTriggeredAbility extends TriggeredAbilityImpl { + + public SpitefulShadowsTriggeredAbility() { + super(Zone.BATTLEFIELD, new SpitefulShadowsEffect()); + } + + public SpitefulShadowsTriggeredAbility(final SpitefulShadowsTriggeredAbility ability) { + super(ability); + } + + @Override + public SpitefulShadowsTriggeredAbility copy() { + return new SpitefulShadowsTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.DAMAGED_CREATURE) { + Permanent enchantment = game.getPermanent(sourceId); + if (enchantment != null && enchantment.getAttachedTo() != null) { + if (event.getTargetId().equals(enchantment.getAttachedTo())) { + this.getEffects().get(0).setValue("damageAmount", event.getAmount()); + this.getEffects().get(0).setValue("targetId", event.getTargetId()); + return true; + } + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever enchanted creature is dealt damage, it deals that much damage to its controller."; + } +} + +class SpitefulShadowsEffect extends OneShotEffect { + + public SpitefulShadowsEffect() { + super(Outcome.Damage); + this.staticText = "it deals that much damage to its controller"; + } + + public SpitefulShadowsEffect(final SpitefulShadowsEffect effect) { + super(effect); + } + + @Override + public SpitefulShadowsEffect copy() { + return new SpitefulShadowsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Integer damageAmount = (Integer) this.getValue("damageAmount"); + UUID targetId = (UUID) this.getValue("targetId"); + if (damageAmount != null && targetId != null) { + Permanent permanent = game.getPermanent(targetId); + if (permanent == null) + permanent = (Permanent) game.getLastKnownInformation(targetId, Zone.BATTLEFIELD); + if (permanent != null) { + Player player = game.getPlayer(permanent.getControllerId()); + if (player != null) { + player.damage(damageAmount, targetId, game, false, true); + return true; + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/UnhallowedCathar.java b/Mage.Sets/src/mage/sets/darkascension/UnhallowedCathar.java new file mode 100644 index 00000000000..f75aa50da64 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/UnhallowedCathar.java @@ -0,0 +1,68 @@ +/* + * 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.darkascension; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.MageInt; +import mage.abilities.common.CantBlockAbility; +import mage.cards.CardImpl; + +/** + * + * @author BetaSteward + */ +public class UnhallowedCathar extends CardImpl { + + public UnhallowedCathar(UUID ownerId) { + super(ownerId, 13, "Unhallowed Cathar", Rarity.COMMON, new CardType[]{CardType.CREATURE}, ""); + this.expansionSetCode = "DKA"; + this.subtype.add("Zombie"); + this.subtype.add("Soldier"); + + // this card is the second face of double-faced card + this.nightCard = true; + this.canTransform = true; + + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Unhallowed Cathar can't block. + this.addAbility(CantBlockAbility.getInstance()); + } + + public UnhallowedCathar(final UnhallowedCathar card) { + super(card); + } + + @Override + public UnhallowedCathar copy() { + return new UnhallowedCathar(this); + } +} diff --git a/Mage.Sets/src/mage/sets/dissension/ProperBurial.java b/Mage.Sets/src/mage/sets/dissension/ProperBurial.java new file mode 100644 index 00000000000..663c3e419cd --- /dev/null +++ b/Mage.Sets/src/mage/sets/dissension/ProperBurial.java @@ -0,0 +1,101 @@ +/* + * 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.dissension; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; + +/** + * + * @author North + */ +public class ProperBurial extends CardImpl { + + public ProperBurial(UUID ownerId) { + super(ownerId, 16, "Proper Burial", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); + this.expansionSetCode = "DIS"; + + this.color.setWhite(true); + + // Whenever a creature you control dies, you gain life equal to that creature's toughness. + this.addAbility(new ProperBurialTriggeredAbility()); + } + + public ProperBurial(final ProperBurial card) { + super(card); + } + + @Override + public ProperBurial copy() { + return new ProperBurial(this); + } +} + +class ProperBurialTriggeredAbility extends TriggeredAbilityImpl { + + public ProperBurialTriggeredAbility() { + super(Zone.BATTLEFIELD, null); + } + + public ProperBurialTriggeredAbility(final ProperBurialTriggeredAbility ability) { + super(ability); + } + + @Override + public ProperBurialTriggeredAbility copy() { + return new ProperBurialTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ZONE_CHANGE + && ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD + && ((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD) { + Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); + if (permanent.getControllerId().equals(this.getControllerId()) && permanent.getCardType().contains(CardType.CREATURE)) { + this.addEffect(new GainLifeEffect(permanent.getToughness().getValue())); + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever a creature you control dies, you gain life equal to that creature's toughness."; + } +} diff --git a/Mage.Sets/src/mage/sets/eighthedition/GravePact.java b/Mage.Sets/src/mage/sets/eighthedition/GravePact.java new file mode 100644 index 00000000000..9a4399450bd --- /dev/null +++ b/Mage.Sets/src/mage/sets/eighthedition/GravePact.java @@ -0,0 +1,52 @@ +/* + * 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.eighthedition; + +import java.util.UUID; + +/** + * + * @author North + */ +public class GravePact extends mage.sets.ninthedition.GravePact { + + public GravePact(UUID ownerId) { + super(ownerId); + this.cardNumber = 137; + this.expansionSetCode = "8ED"; + } + + public GravePact(final GravePact card) { + super(card); + } + + @Override + public GravePact copy() { + return new GravePact(this); + } +} diff --git a/Mage.Sets/src/mage/sets/newphyrexia/PhyrexianIngester.java b/Mage.Sets/src/mage/sets/newphyrexia/PhyrexianIngester.java index 0747d5f2efd..5cc486e0a13 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/PhyrexianIngester.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/PhyrexianIngester.java @@ -43,11 +43,11 @@ import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.Filter; +import mage.filter.common.FilterNonTokenPermanent; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.permanent.PermanentToken; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; /** * @@ -55,6 +55,13 @@ import mage.target.common.TargetCreaturePermanent; */ public class PhyrexianIngester extends CardImpl { + private static final FilterNonTokenPermanent filter = new FilterNonTokenPermanent("nontoken creature"); + + static { + filter.getCardType().add(CardType.CREATURE); + filter.setScopeCardType(Filter.ComparisonScope.Any); + } + public PhyrexianIngester(UUID ownerId) { super(ownerId, 41, "Phyrexian Ingester", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{6}{U}"); this.expansionSetCode = "NPH"; @@ -66,22 +73,7 @@ public class PhyrexianIngester extends CardImpl { // Imprint - When Phyrexian Ingester enters the battlefield, you may exile target nontoken creature. Ability ability = new EntersBattlefieldTriggeredAbility(new PhyrexianIngesterImprintEffect(), true); - FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature") { - - @Override - public boolean match(Permanent permanent) { - if (!super.match(permanent)) { - return notFilter; - } - - if (permanent instanceof PermanentToken) { - return notFilter; - } - - return !notFilter; - } - }; - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Phyrexian Ingester gets +X/+Y, where X is the exiled creature card's power and Y is its toughness. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PhyrexianIngesterBoostEffect())); diff --git a/Mage.Sets/src/mage/sets/ninthedition/GravePact.java b/Mage.Sets/src/mage/sets/ninthedition/GravePact.java new file mode 100644 index 00000000000..2aa6455e0ed --- /dev/null +++ b/Mage.Sets/src/mage/sets/ninthedition/GravePact.java @@ -0,0 +1,139 @@ +/* + * 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.ninthedition; + +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.TriggeredAbilityImpl; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author North + */ +public class GravePact extends CardImpl { + + public GravePact(UUID ownerId) { + super(ownerId, 135, "Grave Pact", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}{B}{B}"); + this.expansionSetCode = "9ED"; + + this.color.setBlack(true); + + // Whenever a creature you control dies, each other player sacrifices a creature. + this.addAbility(new GravePactTriggeredAbility()); + } + + public GravePact(final GravePact card) { + super(card); + } + + @Override + public GravePact copy() { + return new GravePact(this); + } +} + +class GravePactTriggeredAbility extends TriggeredAbilityImpl { + + public GravePactTriggeredAbility() { + super(Zone.BATTLEFIELD, new GravePactEffect()); + } + + public GravePactTriggeredAbility(final GravePactTriggeredAbility ability) { + super(ability); + } + + @Override + public GravePactTriggeredAbility copy() { + return new GravePactTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ZONE_CHANGE + && ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD + && ((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD) { + Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); + if (permanent.getControllerId().equals(this.getControllerId()) && permanent.getCardType().contains(CardType.CREATURE)) { + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever a creature you control dies, " + super.getRule(); + } +} + +class GravePactEffect extends OneShotEffect { + + public GravePactEffect() { + super(Outcome.Sacrifice); + this.staticText = "each other player sacrifices a creature"; + } + + public GravePactEffect(final GravePactEffect effect) { + super(effect); + } + + @Override + public GravePactEffect copy() { + return new GravePactEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID playerId : game.getPlayerList()) { + if (!playerId.equals(source.getControllerId())) { + Player player = game.getPlayer(playerId); + Target target = new TargetControlledCreaturePermanent(); + if (player != null && player.choose(Outcome.Sacrifice, target, source.getSourceId(), game)) { + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + permanent.sacrifice(source.getSourceId(), game); + } + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/planechase/GravePact.java b/Mage.Sets/src/mage/sets/planechase/GravePact.java new file mode 100644 index 00000000000..023b40c7a8b --- /dev/null +++ b/Mage.Sets/src/mage/sets/planechase/GravePact.java @@ -0,0 +1,52 @@ +/* + * 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.planechase; + +import java.util.UUID; + +/** + * + * @author North + */ +public class GravePact extends mage.sets.ninthedition.GravePact { + + public GravePact(UUID ownerId) { + super(ownerId); + this.cardNumber = 28; + this.expansionSetCode = "HOP"; + } + + public GravePact(final GravePact card) { + super(card); + } + + @Override + public GravePact copy() { + return new GravePact(this); + } +} diff --git a/Mage.Sets/src/mage/sets/planechase/SyphonSoul.java b/Mage.Sets/src/mage/sets/planechase/SyphonSoul.java index 15079ce8751..87f7a1444b2 100644 --- a/Mage.Sets/src/mage/sets/planechase/SyphonSoul.java +++ b/Mage.Sets/src/mage/sets/planechase/SyphonSoul.java @@ -28,9 +28,8 @@ package mage.sets.planechase; import java.util.UUID; - -import mage.Constants; import mage.Constants.CardType; +import mage.Constants.Outcome; import mage.Constants.Rarity; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -47,6 +46,8 @@ public class SyphonSoul extends CardImpl { super(ownerId, 43, "Syphon Soul", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{2}{B}"); this.expansionSetCode = "HOP"; this.color.setBlack(true); + + // Syphon Soul deals 2 damage to each other player. You gain life equal to the damage dealt this way. this.getSpellAbility().addEffect(new SyphonSoulEffect()); } @@ -62,7 +63,7 @@ public class SyphonSoul extends CardImpl { class SyphonSoulEffect extends OneShotEffect { public SyphonSoulEffect() { - super(Constants.Outcome.Damage); + super(Outcome.Damage); staticText = "{this} deals 2 damage to each other player. You gain life equal to the damage dealt this way"; } @@ -72,12 +73,15 @@ class SyphonSoulEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - int loseLife = 0; - for (UUID opponentId : game.getOpponents(source.getControllerId())) { - loseLife += game.getPlayer(opponentId).loseLife(2, game); + int damageDealt = 0; + for (UUID playerId : game.getPlayerList()) { + if (!playerId.equals(source.getControllerId())) { + damageDealt += game.getPlayer(playerId).damage(2, source.getSourceId(), game, false, true); + } + } + if (damageDealt > 0) { + game.getPlayer(source.getControllerId()).gainLife(damageDealt, game); } - if (loseLife > 0) - game.getPlayer(source.getControllerId()).gainLife(loseLife, game); return true; } diff --git a/Mage.Sets/src/mage/sets/tempest/EssenceBottle.java b/Mage.Sets/src/mage/sets/tempest/EssenceBottle.java new file mode 100644 index 00000000000..463d1863748 --- /dev/null +++ b/Mage.Sets/src/mage/sets/tempest/EssenceBottle.java @@ -0,0 +1,154 @@ +/* + * 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.tempest; + +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.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author North + */ +public class EssenceBottle extends CardImpl { + + public EssenceBottle(UUID ownerId) { + super(ownerId, 276, "Essence Bottle", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT}, "{2}"); + this.expansionSetCode = "TMP"; + // {3}, {tap}: Put an elixir counter on Essence Bottle. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new AddCountersSourceEffect(CounterType.ELIXIR.createInstance()), + new GenericManaCost(3)); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + // {tap}, Remove all elixir counters from Essence Bottle: You gain 2 life for each elixir counter removed this way. + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new EssenceBottleEffect(), new TapSourceCost()); + ability.addCost(new EssenceBottleCost()); + this.addAbility(ability); + } + + public EssenceBottle(final EssenceBottle card) { + super(card); + } + + @Override + public EssenceBottle copy() { + return new EssenceBottle(this); + } +} + +class EssenceBottleCost extends CostImpl { + + private int removedCounters; + + public EssenceBottleCost() { + super(); + this.removedCounters = 0; + this.text = "Remove all elixir counters from {this}"; + } + + public EssenceBottleCost(EssenceBottleCost cost) { + super(cost); + this.removedCounters = cost.removedCounters; + } + + @Override + public boolean canPay(UUID sourceId, UUID controllerId, Game game) { + return true; + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + Permanent permanent = game.getPermanent(ability.getSourceId()); + if (permanent != null) { + this.removedCounters = permanent.getCounters().getCount(CounterType.ELIXIR); + if (this.removedCounters > 0) { + permanent.removeCounters(CounterType.ELIXIR.createInstance(this.removedCounters), game); + } + } + this.paid = true; + return true; + } + + @Override + public EssenceBottleCost copy() { + return new EssenceBottleCost(this); + } + + public int getRemovedCounters() { + return this.removedCounters; + } +} + +class EssenceBottleEffect extends OneShotEffect { + + public EssenceBottleEffect() { + super(Outcome.GainLife); + this.staticText = "You gain 2 life for each elixir counter removed this way"; + } + + public EssenceBottleEffect(final EssenceBottleEffect effect) { + super(effect); + } + + @Override + public EssenceBottleEffect copy() { + return new EssenceBottleEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int countersRemoved = 0; + for (Cost cost : source.getCosts()) { + if (cost instanceof EssenceBottleCost) { + countersRemoved = ((EssenceBottleCost) cost).getRemovedCounters(); + } + } + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + player.gainLife(countersRemoved * 2, game); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/tempest/TortureChamber.java b/Mage.Sets/src/mage/sets/tempest/TortureChamber.java new file mode 100644 index 00000000000..6a9b7ea0ccb --- /dev/null +++ b/Mage.Sets/src/mage/sets/tempest/TortureChamber.java @@ -0,0 +1,188 @@ +/* + * 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.tempest; + +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.common.BeginningOfYourEndStepTriggeredAbility; +import mage.abilities.common.OnEventTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author North + */ +public class TortureChamber extends CardImpl { + + public TortureChamber(UUID ownerId) { + super(ownerId, 303, "Torture Chamber", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{3}"); + this.expansionSetCode = "TMP"; + + // At the beginning of your upkeep, put a pain counter on Torture Chamber. + this.addAbility(new OnEventTriggeredAbility(EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", new AddCountersSourceEffect(CounterType.PAIN.createInstance()))); + // At the beginning of your end step, Torture Chamber deals damage to you equal to the number of pain counters on it. + this.addAbility(new BeginningOfYourEndStepTriggeredAbility(new TortureChamberEffect1(), false)); + // {1}, {tap}, Remove all pain counters from Torture Chamber: Torture Chamber deals damage to target creature equal to the number of pain counters removed this way. + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TortureChamberEffect2(), new GenericManaCost(1)); + ability.addCost(new TapSourceCost()); + ability.addCost(new TortureChamberCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public TortureChamber(final TortureChamber card) { + super(card); + } + + @Override + public TortureChamber copy() { + return new TortureChamber(this); + } +} + +class TortureChamberCost extends CostImpl { + + private int removedCounters; + + public TortureChamberCost() { + super(); + this.removedCounters = 0; + this.text = "Remove all pain counters from {this}"; + } + + public TortureChamberCost(TortureChamberCost cost) { + super(cost); + this.removedCounters = cost.removedCounters; + } + + @Override + public boolean canPay(UUID sourceId, UUID controllerId, Game game) { + return true; + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { + Permanent permanent = game.getPermanent(ability.getSourceId()); + if (permanent != null) { + this.removedCounters = permanent.getCounters().getCount(CounterType.PAIN); + if (this.removedCounters > 0) { + permanent.removeCounters(CounterType.PAIN.createInstance(this.removedCounters), game); + } + } + this.paid = true; + return true; + } + + @Override + public TortureChamberCost copy() { + return new TortureChamberCost(this); + } + + public int getRemovedCounters() { + return this.removedCounters; + } +} + +class TortureChamberEffect1 extends OneShotEffect { + + public TortureChamberEffect1() { + super(Outcome.Damage); + this.staticText = "{this} deals damage to you equal to the number of pain counters on it"; + } + + public TortureChamberEffect1(final TortureChamberEffect1 effect) { + super(effect); + } + + @Override + public TortureChamberEffect1 copy() { + return new TortureChamberEffect1(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(source.getSourceId()); + if (player != null && permanent != null) { + int painCounters = permanent.getCounters().getCount(CounterType.PAIN); + player.damage(painCounters, source.getSourceId(), game, false, true); + return true; + } + return false; + } +} + +class TortureChamberEffect2 extends OneShotEffect { + + public TortureChamberEffect2() { + super(Outcome.Damage); + this.staticText = "{this} deals damage to target creature equal to the number of pain counters removed this way"; + } + + public TortureChamberEffect2(final TortureChamberEffect2 effect) { + super(effect); + } + + @Override + public TortureChamberEffect2 copy() { + return new TortureChamberEffect2(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int countersRemoved = 0; + for (Cost cost : source.getCosts()) { + if (cost instanceof TortureChamberCost) { + countersRemoved = ((TortureChamberCost) cost).getRemovedCounters(); + } + } + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent != null) { + permanent.damage(countersRemoved, source.getSourceId(), game, true, false); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/tenth/AngelicChorus.java b/Mage.Sets/src/mage/sets/tenth/AngelicChorus.java new file mode 100644 index 00000000000..f9e73501b78 --- /dev/null +++ b/Mage.Sets/src/mage/sets/tenth/AngelicChorus.java @@ -0,0 +1,52 @@ +/* + * 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.tenth; + +import java.util.UUID; + +/** + * + * @author Backfir3 + */ +public class AngelicChorus extends mage.sets.urzassaga.AngelicChorus { + + public AngelicChorus(UUID ownerId) { + super(ownerId); + this.cardNumber = 4; + this.expansionSetCode = "10E"; + } + + public AngelicChorus(final AngelicChorus card) { + super(card); + } + + @Override + public AngelicChorus copy() { + return new AngelicChorus(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/tenth/GravePact.java b/Mage.Sets/src/mage/sets/tenth/GravePact.java new file mode 100644 index 00000000000..537e29985b7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/tenth/GravePact.java @@ -0,0 +1,52 @@ +/* + * 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.tenth; + +import java.util.UUID; + +/** + * + * @author North + */ +public class GravePact extends mage.sets.ninthedition.GravePact { + + public GravePact(UUID ownerId) { + super(ownerId); + this.cardNumber = 144; + this.expansionSetCode = "10E"; + } + + public GravePact(final GravePact card) { + super(card); + } + + @Override + public GravePact copy() { + return new GravePact(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/AbsoluteGrace.java b/Mage.Sets/src/mage/sets/urzassaga/AbsoluteGrace.java new file mode 100644 index 00000000000..92791a1f7b8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/AbsoluteGrace.java @@ -0,0 +1,76 @@ +/* +* 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.urzassaga; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Duration; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continious.GainAbilityAllEffect; +import mage.abilities.keyword.ProtectionAbility; +import mage.cards.CardImpl; +import mage.filter.Filter.ComparisonScope; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreaturePermanent; + +/** + * + * @author Backfir3 + */ +public class AbsoluteGrace extends CardImpl { + + private static final FilterCard filter = new FilterCard("Black"); + + static { + filter.setUseColor(true); + filter.getColor().setBlack(true); + filter.setScopeColor(ComparisonScope.Any); + } + + public AbsoluteGrace(UUID ownerId) { + super(ownerId, 1, "Absolute Grace", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); + this.expansionSetCode = "USG"; + this.color.setWhite(true); + Ability ability = new ProtectionAbility(filter); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(ability, Duration.WhileOnBattlefield, new FilterCreaturePermanent(), false))); + } + + public AbsoluteGrace(final AbsoluteGrace card) { + super(card); + } + + @Override + public AbsoluteGrace copy() { + return new AbsoluteGrace(this); + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/urzassaga/AbsoluteLaw.java b/Mage.Sets/src/mage/sets/urzassaga/AbsoluteLaw.java new file mode 100644 index 00000000000..1e6cb4da05d --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/AbsoluteLaw.java @@ -0,0 +1,76 @@ +/* +* 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.urzassaga; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Duration; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continious.GainAbilityAllEffect; +import mage.abilities.keyword.ProtectionAbility; +import mage.cards.CardImpl; +import mage.filter.Filter.ComparisonScope; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreaturePermanent; + +/** + * + * @author Backfir3 + */ +public class AbsoluteLaw extends CardImpl { + + private static final FilterCard filter = new FilterCard("Red"); + + static { + filter.setUseColor(true); + filter.getColor().setRed(true); + filter.setScopeColor(ComparisonScope.Any); + } + + public AbsoluteLaw(UUID ownerId) { + super(ownerId, 2, "Absolute Law", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); + this.expansionSetCode = "USG"; + this.color.setWhite(true); + Ability ability = new ProtectionAbility(filter); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(ability, Duration.WhileOnBattlefield, new FilterCreaturePermanent(), false))); + } + + public AbsoluteLaw(final AbsoluteLaw card) { + super(card); + } + + @Override + public AbsoluteLaw copy() { + return new AbsoluteLaw(this); + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/urzassaga/AngelicChorus.java b/Mage.Sets/src/mage/sets/urzassaga/AngelicChorus.java new file mode 100644 index 00000000000..007de417299 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/AngelicChorus.java @@ -0,0 +1,142 @@ +/* + * 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.urzassaga; + +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.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author Backfir3 + */ +public class AngelicChorus extends CardImpl { + + public AngelicChorus(UUID ownerId) { + super(ownerId, 3, "Angelic Chorus", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}{W}"); + this.expansionSetCode = "USG"; + + this.color.setWhite(true); + + Ability ability = new AngelicChorusTriggeredAbility(); + this.addAbility(ability); + } + + public AngelicChorus(final AngelicChorus card) { + super(card); + } + + @Override + public AngelicChorus copy() { + return new AngelicChorus(this); + } +} + +class AngelicChorusTriggeredAbility extends TriggeredAbilityImpl { + + public AngelicChorusTriggeredAbility() { + super(Zone.BATTLEFIELD, new AngelicChorusEffect(), false); + } + + public AngelicChorusTriggeredAbility(AngelicChorusTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == EventType.ZONE_CHANGE) { + Permanent permanent = game.getPermanent(event.getTargetId()); + if (((ZoneChangeEvent) event).getToZone() == Zone.BATTLEFIELD + && permanent.getCardType().contains(CardType.CREATURE) + && permanent.getControllerId().equals(this.controllerId)) { + Effect effect = this.getEffects().get(0); + effect.setValue("lifeSource", event.getTargetId()); + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever a creature enters the battlefield under your control, you gain life equal to its toughness."; + } + + @Override + public AngelicChorusTriggeredAbility copy() { + return new AngelicChorusTriggeredAbility(this); + } +} + +class AngelicChorusEffect extends OneShotEffect { + + public AngelicChorusEffect() { + super(Outcome.GainLife); + staticText = "you gain life equal to its toughness"; + } + + public AngelicChorusEffect(final AngelicChorusEffect effect) { + super(effect); + } + + @Override + public AngelicChorusEffect copy() { + return new AngelicChorusEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + UUID creatureId = (UUID) getValue("lifeSource"); + Permanent creature = game.getPermanent(creatureId); + if (creature == null) { + creature = (Permanent) game.getLastKnownInformation(creatureId, Zone.BATTLEFIELD); + } + if (creature != null) { + int amount = creature.getToughness().getValue(); + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + player.gainLife(amount, game); + } + return true; + } + return false; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/urzassaga/AngelicPage.java b/Mage.Sets/src/mage/sets/urzassaga/AngelicPage.java new file mode 100644 index 00000000000..90140935e46 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/AngelicPage.java @@ -0,0 +1,85 @@ +/* + * 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.urzassaga; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Duration; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.continious.BoostTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.filter.common.FilterCreaturePermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author Backfir3 + */ +public class AngelicPage extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking or blocking creature"); + + static { + filter.setAttacking(true); + filter.setUseAttacking(true); + filter.setBlocking(true); + filter.setUseBlocking(true); + } + + public AngelicPage(UUID ownerId) { + super(ownerId, 4, "Angelic Page", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{W}"); + this.expansionSetCode = "USG"; + this.subtype.add("Angel"); + this.subtype.add("Spirit"); + this.color.setWhite(true); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + this.addAbility(FlyingAbility.getInstance()); + + //{T}: Target attacking or blocking creature gets +1/+1 until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(1, 1, Duration.EndOfTurn), new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public AngelicPage(final AngelicPage card) { + super(card); + } + + @Override + public AngelicPage copy() { + return new AngelicPage(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/urzassaga/BloodVassal.java b/Mage.Sets/src/mage/sets/urzassaga/BloodVassal.java new file mode 100644 index 00000000000..cac9681ac8e --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/BloodVassal.java @@ -0,0 +1,67 @@ +/* + * 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.urzassaga; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.MageInt; +import mage.Mana; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.effects.common.BasicManaEffect; +import mage.cards.CardImpl; + + +/** + * + * @author Backfir3 + */ +public class BloodVassal extends CardImpl { + + public BloodVassal(UUID ownerId) { + super(ownerId, 118, "Blood Vassal", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.expansionSetCode = "USG"; + this.subtype.add("Thrull"); + this.color.setBlack(true); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BasicManaEffect(new Mana(0, 0, 0, 0, 2, 0, 0)), new SacrificeSourceCost())); + } + + public BloodVassal(final BloodVassal card) { + super(card); + } + + @Override + public BloodVassal copy() { + return new BloodVassal(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/urzassaga/CacklingFiend.java b/Mage.Sets/src/mage/sets/urzassaga/CacklingFiend.java new file mode 100644 index 00000000000..b986105379e --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/CacklingFiend.java @@ -0,0 +1,98 @@ +/* + * 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.urzassaga; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Outcome; +import mage.Constants.Rarity; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author Backfir3 + */ +public class CacklingFiend extends CardImpl { + + public CacklingFiend(UUID ownerId) { + super(ownerId, 121, "Cackling Fiend", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); + this.expansionSetCode = "USG"; + this.subtype.add("Zombie"); + this.color.setBlack(true); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + this.addAbility(FlyingAbility.getInstance()); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CacklingFiendEffect(), false)); + } + + public CacklingFiend(final CacklingFiend card) { + super(card); + } + + @Override + public CacklingFiend copy() { + return new CacklingFiend(this); + } + +} + +class CacklingFiendEffect extends OneShotEffect { + + public CacklingFiendEffect() { + super(Outcome.Discard); + staticText = "each opponent discards a card"; + } + + public CacklingFiendEffect(final CacklingFiendEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID playerId: game.getOpponents(source.getControllerId())) { + Player player = game.getPlayer(playerId); + player.discard(1, source, game); + } + return true; + } + + @Override + public CacklingFiendEffect copy() { + return new CacklingFiendEffect(this); + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/urzassaga/ChildOfGaea.java b/Mage.Sets/src/mage/sets/urzassaga/ChildOfGaea.java new file mode 100644 index 00000000000..063cc7018da --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/ChildOfGaea.java @@ -0,0 +1,72 @@ +/* +* 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.urzassaga; + +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.MageInt; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; + +/** + * + * @author Backfir3 + */ +public class ChildOfGaea extends CardImpl { + + public ChildOfGaea(UUID ownerId) { + super(ownerId, 242, "Child of Gaea", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{G}{G}{G}"); + this.expansionSetCode = "USG"; + this.subtype.add("Elemental"); + this.color.setGreen(true); + this.power = new MageInt(7); + this.toughness = new MageInt(7); + + this.addAbility(TrampleAbility.getInstance()); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ManaCostsImpl("{G}{G}")), Constants.TargetController.YOU, false)); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{1}{G}"))); + } + + public ChildOfGaea(final ChildOfGaea card) { + super(card); + } + + @Override + public ChildOfGaea copy() { + return new ChildOfGaea(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/urzassaga/GaeasCradle.java b/Mage.Sets/src/mage/sets/urzassaga/GaeasCradle.java new file mode 100644 index 00000000000..ed8eb6ea64c --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/GaeasCradle.java @@ -0,0 +1,72 @@ +/* +* 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.urzassaga; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.Mana; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.mana.DynamicManaAbility; +import mage.cards.CardImpl; +import mage.filter.Filter; +import mage.filter.common.FilterControlledPermanent; + +/** + * + * @author Backfir3 + */ + +public class GaeasCradle extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("creature you control");; + + static { + filter.getCardType().add(CardType.CREATURE); + filter.setScopeSubtype(Filter.ComparisonScope.Any); + } + + public GaeasCradle(UUID ownerId) { + super(ownerId, 321, "Gaea's Cradle", Rarity.RARE, new CardType[]{CardType.LAND}, ""); + this.expansionSetCode = "USG"; + this.supertype.add("Legendary"); + + DynamicManaAbility ability = new DynamicManaAbility(Mana.GreenMana, new PermanentsOnBattlefieldCount(filter)); + this.addAbility(ability); + } + + public GaeasCradle(final GaeasCradle card) { + super(card); + } + + @Override + public GaeasCradle copy() { + return new GaeasCradle(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/urzassaga/ZephidsEmbrace.java b/Mage.Sets/src/mage/sets/urzassaga/ZephidsEmbrace.java new file mode 100644 index 00000000000..08346df9994 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/ZephidsEmbrace.java @@ -0,0 +1,134 @@ +/* +* 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.urzassaga; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Duration; +import mage.Constants.Layer; +import mage.Constants.Outcome; +import mage.Constants.Rarity; +import mage.Constants.SubLayer; +import mage.Constants.Zone; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.ShroudAbility; +import mage.cards.CardImpl; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author Backfir3 + */ +public class ZephidsEmbrace extends CardImpl { + + public ZephidsEmbrace(UUID ownerId) { + super(ownerId, 114, "Zephid's Embrace", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}"); + this.expansionSetCode = "USG"; + this.color.setBlue(true); + this.subtype.add("Aura"); + + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ZephidsEmbraceEffect())); + } + + public ZephidsEmbrace(final ZephidsEmbrace card) { + super(card); + } + + @Override + public ZephidsEmbrace copy() { + return new ZephidsEmbrace(this); + } +} + +class ZephidsEmbraceEffect extends ContinuousEffectImpl { + + public ZephidsEmbraceEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + staticText = "Enchanted creature gets +2/+2 and has flying and shroud"; + } + + public ZephidsEmbraceEffect(final ZephidsEmbraceEffect effect) { + super(effect); + } + + @Override + public ZephidsEmbraceEffect copy() { + return new ZephidsEmbraceEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent enchantment = game.getPermanent(source.getSourceId()); + if (enchantment != null && enchantment.getAttachedTo() != null) { + Permanent creature = game.getPermanent(enchantment.getAttachedTo()); + if (creature != null) { + switch (layer) { + case PTChangingEffects_7: + if (sublayer == SubLayer.ModifyPT_7c) { + creature.addPower(2); + creature.addToughness(2); + } + break; + case AbilityAddingRemovingEffects_6: + if (sublayer == SubLayer.NA) { + creature.addAbility(FlyingAbility.getInstance(), game); + creature.addAbility(ShroudAbility.getInstance(), game); + } + break; + } + return true; + } + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.PTChangingEffects_7; + } + +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestClingingMists.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestClingingMists.java new file mode 100644 index 00000000000..8a6615f2b24 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestClingingMists.java @@ -0,0 +1,72 @@ +package org.mage.test.cards; + +import mage.Constants; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * also tests regenerate and + * tests that permanents with protection can be sacrificed + * + * @author BetaSteward + */ +public class TestClingingMists extends CardTestPlayerBase { + + @Test + public void testCard() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "White Knight"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Forest", 3); + addCard(Constants.Zone.HAND, playerA, "Clinging Mists"); + + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Clinging Mists"); + attack(1, playerA, "White Knight"); + + setStopAt(1, Constants.PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + } + + @Test + public void testCardExile1() { + setLife(playerA, 5); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Abbey Griffin"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Forest", 3); + addCard(Constants.Zone.HAND, playerA, "Clinging Mists"); + + attack(1, playerA, "Abbey Griffin"); + castSpell(1, Constants.PhaseStep.DECLARE_BLOCKERS, playerA, "Clinging Mists"); + + setStopAt(3, Constants.PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 5); + assertLife(playerB, 20); + assertTapped("Abbey Griffin", true); + } + + @Test + public void testCardExile2() { + setLife(playerA, 5); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Forest", 3); + addCard(Constants.Zone.HAND, playerA, "Clinging Mists"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Mountain"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Abbey Griffin"); + addCard(Constants.Zone.HAND, playerB, "Lightning Bolt"); + + attack(2, playerB, "Abbey Griffin"); + castSpell(2, Constants.PhaseStep.DECLARE_BLOCKERS, playerA, "Clinging Mists"); + castSpell(2, Constants.PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", playerA); + + setStopAt(6, Constants.PhaseStep.DRAW); + execute(); + + assertLife(playerA, 2); + assertLife(playerB, 20); + assertTapped("Abbey Griffin", false); + assertGraveyardCount(playerB, "Lightning Bolt", 1); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestFeedThePack.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestFeedThePack.java new file mode 100644 index 00000000000..12b99918e45 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestFeedThePack.java @@ -0,0 +1,28 @@ +package org.mage.test.cards; + +import mage.Constants; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author BetaSteward + */ +public class TestFeedThePack extends CardTestPlayerBase { + + @Test + public void testCard() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Feed the Pack"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Craw Wurm"); + + setStopAt(2, Constants.PhaseStep.DRAW); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Wolf", 4); + assertPermanentCount(playerB, "Craw Wurm", 0); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestFlayerOfTheHatebound.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestFlayerOfTheHatebound.java new file mode 100644 index 00000000000..15e28335495 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestFlayerOfTheHatebound.java @@ -0,0 +1,67 @@ +package org.mage.test.cards; + +import mage.Constants; +import mage.filter.Filter; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * also tests undying + * + * @author BetaSteward + */ +public class TestFlayerOfTheHatebound extends CardTestPlayerBase { + + @Test + public void testCard() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Flayer of the Hatebound"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Constants.Zone.HAND, playerA, "Lightning Bolt", 1); + + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Flayer of the Hatebound"); + setStopAt(2, Constants.PhaseStep.DRAW); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 15); + assertPermanentCount(playerA, "Flayer of the Hatebound", 1); + assertPowerToughness(playerA, "Flayer of the Hatebound", 5, 3, Filter.ComparisonScope.Any); + } + + @Test + public void testCard1() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Flayer of the Hatebound"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Swamp", 2); + addCard(Constants.Zone.GRAVEYARD, playerA, "Reassembling Skeleton", 1); + + activateAbility(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{B}:"); + setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 19); + assertPermanentCount(playerA, "Flayer of the Hatebound", 1); + assertPermanentCount(playerA, "Reassembling Skeleton", 1); + assertPowerToughness(playerA, "Flayer of the Hatebound", 4, 2, Filter.ComparisonScope.Any); + } + + @Test + public void testCard2() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Flayer of the Hatebound"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Swamp", 2); + addCard(Constants.Zone.GRAVEYARD, playerB, "Reassembling Skeleton", 1); + + activateAbility(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerB, "{1}{B}:"); + setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Flayer of the Hatebound", 1); + assertPermanentCount(playerB, "Reassembling Skeleton", 1); + assertPowerToughness(playerA, "Flayer of the Hatebound", 4, 2, Filter.ComparisonScope.Any); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestHinterlandScourge.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestHinterlandScourge.java new file mode 100644 index 00000000000..29236cd3636 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestHinterlandScourge.java @@ -0,0 +1,57 @@ +package org.mage.test.cards; + +import mage.Constants; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author BetaSteward + */ +public class TestHinterlandScourge extends CardTestPlayerBase { + + @Test + public void testCard() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Hinterland Hermit"); +// addCard(Constants.Zone.BATTLEFIELD, playerB, "Ornithopter"); + + setStopAt(2, Constants.PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Hinterland Hermit", 0); + assertPermanentCount(playerA, "Hinterland Scourge", 1); + } + + @Test + public void testCard1() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Hinterland Hermit"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Ornithopter"); + + attack(3, playerA, "Hinterland Scourge"); + setStopAt(3, Constants.PhaseStep.END_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Hinterland Hermit", 0); + assertPermanentCount(playerA, "Hinterland Scourge", 1); + assertPermanentCount(playerB, "Ornithopter", 0); + } + + @Test + public void testCard2() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Hinterland Hermit"); + + attack(3, playerA, "Hinterland Scourge"); + setStopAt(3, Constants.PhaseStep.END_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 17); + assertPermanentCount(playerA, "Hinterland Hermit", 0); + assertPermanentCount(playerA, "Hinterland Scourge", 1); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestSeance.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestSeance.java new file mode 100644 index 00000000000..876d5202052 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestSeance.java @@ -0,0 +1,41 @@ +package org.mage.test.cards; + +import mage.Constants; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author BetaSteward + */ +public class TestSeance extends CardTestPlayerBase { + + @Test + public void testCard() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Seance"); + addCard(Constants.Zone.GRAVEYARD, playerA, "Craw Wurm"); + + setStopAt(1, Constants.PhaseStep.DRAW); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertExileCount("Craw Wurm", 1); + assertPermanentCount(playerA, "Craw Wurm", 1); + } + + @Test + public void testCard1() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Seance"); + addCard(Constants.Zone.GRAVEYARD, playerA, "Craw Wurm"); + + setStopAt(2, Constants.PhaseStep.DRAW); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertExileCount("Craw Wurm", 1); + assertPermanentCount(playerA, "Craw Wurm", 0); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestUnhallowedCathar.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestUnhallowedCathar.java new file mode 100644 index 00000000000..36ed3b381e2 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestUnhallowedCathar.java @@ -0,0 +1,30 @@ +package org.mage.test.cards; + +import mage.Constants; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author BetaSteward + */ +public class TestUnhallowedCathar extends CardTestPlayerBase { + + @Test + public void testCard() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Loyal Cathar"); + addCard(Constants.Zone.HAND, playerA, "Lightning Bolt"); + + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Loyal Cathar"); + setStopAt(2, Constants.PhaseStep.DRAW); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Loyal Cathar", 0); + assertPermanentCount(playerA, "Unhallowed Cathar", 1); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/damage/TestSpitefulShadows.java b/Mage.Tests/src/test/java/org/mage/test/cards/damage/TestSpitefulShadows.java new file mode 100644 index 00000000000..852578bc434 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/damage/TestSpitefulShadows.java @@ -0,0 +1,56 @@ +package org.mage.test.cards.damage; + +import mage.Constants; +import mage.counters.CounterType; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * also tests regenerate and + * tests that permanents with protection can be sacrificed + * + * @author BetaSteward + */ +public class TestSpitefulShadows extends CardTestPlayerBase { + + @Test + public void testCard() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Glistener Elf"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Swamp", 2); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain", 2); + addCard(Constants.Zone.HAND, playerA, "Spiteful Shadows"); + addCard(Constants.Zone.HAND, playerA, "Lightning Bolt"); + + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Spiteful Shadows", "Glistener Elf"); + castSpell(1, Constants.PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "Glistener Elf"); + + setStopAt(1, Constants.PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertCounterCount(playerA, CounterType.POISON, 3); + } + + @Test + public void testCard1() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Craw Wurm"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Swamp", 2); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain", 2); + addCard(Constants.Zone.HAND, playerA, "Spiteful Shadows"); + addCard(Constants.Zone.HAND, playerA, "Lightning Bolt"); + + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Spiteful Shadows", "Craw Wurm"); + castSpell(1, Constants.PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "Craw Wurm"); + + setStopAt(1, Constants.PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 17); + assertLife(playerB, 20); + assertCounterCount(playerA, CounterType.POISON, 0); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java index 65dfc07b5b3..064a66ff281 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java @@ -391,6 +391,17 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement Assert.assertEquals("(Battlefield) Counter counts are not equal (" + cardName + ":" + type + ")", count, found.getCounters().getCount(type)); } + + /** + * Assert counter count on a player + * + * @param player The player whos counters should be counted. + * @param type Type of the counter that should be counted. + * @param count Expected count. + */ + public void assertCounterCount(Player player, CounterType type, int count) throws AssertionError { + Assert.assertEquals("(Battlefield) Counter counts are not equal (" + player.getName() + ":" + type + ")", count, player.getCounters().getCount(type)); + } /** * Assert whether a permanent is a specified type or not diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/cards/effects/BoostContinuousEffectTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/cards/effects/BoostContinuousEffectTest.java index 9dfc4024c05..25a7d9c1fe7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/cards/effects/BoostContinuousEffectTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/cards/effects/BoostContinuousEffectTest.java @@ -26,13 +26,13 @@ public class BoostContinuousEffectTest extends CardTestBase { @Test public void testHonorOfThePoor2() { - addCard(Constants.Zone.BATTLEFIELD, playerA, "Honor of the Pure"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Honor of the Pure", 2); addCard(Constants.Zone.BATTLEFIELD, playerA, "White Knight"); addCard(Constants.Zone.BATTLEFIELD, playerA, "Black Knight"); setStopAt(1, PhaseStep.CLEANUP); execute(); - assertPowerToughness(playerA, "White Knight", 3, 3, Filter.ComparisonScope.Any); + assertPowerToughness(playerA, "White Knight", 4, 4, Filter.ComparisonScope.Any); assertPowerToughness(playerA, "Black Knight", 2, 2, Filter.ComparisonScope.Any); } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/cards/effects/TestActivatedContinuousEffect.java b/Mage.Tests/src/test/java/org/mage/test/serverside/cards/effects/TestActivatedContinuousEffect.java new file mode 100644 index 00000000000..630411085ee --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/cards/effects/TestActivatedContinuousEffect.java @@ -0,0 +1,53 @@ +package org.mage.test.serverside.cards.effects; + +import org.mage.test.cards.*; +import junit.framework.Assert; +import mage.Constants; +import mage.filter.Filter; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author BetaSteward + */ +public class TestActivatedContinuousEffect extends CardTestPlayerBase { + + @Test + public void testCard() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain", 3); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Captive Flame"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "White Knight"); + + activateAbility(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "{R}:", "White Knight"); + + setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "White Knight", 1); + assertPowerToughness(playerA, "White Knight", 3, 2, Filter.ComparisonScope.Any); + + } + + @Test + public void testCard2() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain", 3); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Captive Flame"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "White Knight"); + + activateAbility(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "{R}:", "White Knight"); + activateAbility(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "{R}:", "White Knight"); + + setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "White Knight", 1); + assertPowerToughness(playerA, "White Knight", 4, 2, Filter.ComparisonScope.Any); + + } + +} diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java index c0c916b1149..492c475e5b7 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java @@ -29,24 +29,14 @@ package mage.abilities.effects; import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; import java.util.Map.Entry; -import java.util.UUID; +import java.util.*; import mage.Constants.AsThoughEffectType; import mage.Constants.Duration; -import mage.Constants.EffectType; import mage.Constants.Layer; import mage.Constants.SubLayer; -import mage.Constants.Zone; import mage.abilities.Ability; import mage.abilities.StaticAbility; -import mage.cards.Card; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -60,16 +50,13 @@ import mage.players.Player; public class ContinuousEffects implements Serializable { //transient Continuous effects - private final ArrayList layeredEffects = new ArrayList(); - private final ArrayList replacementEffects = new ArrayList(); - private final ArrayList preventionEffects = new ArrayList(); - private final ArrayList requirementEffects = new ArrayList(); - private final ArrayList restrictionEffects = new ArrayList(); - private final ArrayList asThoughEffects = new ArrayList(); - private final ArrayList costModificationEffects = new ArrayList(); - - //map Abilities to Continuous effects - private final Map abilityMap = new HashMap(); + private ContinuousEffectsList layeredEffects = new ContinuousEffectsList(); + private ContinuousEffectsList replacementEffects = new ContinuousEffectsList(); + private ContinuousEffectsList preventionEffects = new ContinuousEffectsList(); + private ContinuousEffectsList requirementEffects = new ContinuousEffectsList(); + private ContinuousEffectsList restrictionEffects = new ContinuousEffectsList(); + private ContinuousEffectsList asThoughEffects = new ContinuousEffectsList(); + private ContinuousEffectsList costModificationEffects = new ContinuousEffectsList(); private final ApplyCountersEffect applyCounters; private final PlaneswalkerRedirectionEffect planeswalkerRedirectionEffect; @@ -82,37 +69,13 @@ public class ContinuousEffects implements Serializable { public ContinuousEffects(final ContinuousEffects effect) { this.applyCounters = effect.applyCounters.copy(); this.planeswalkerRedirectionEffect = effect.planeswalkerRedirectionEffect.copy(); - layeredEffects.ensureCapacity(effect.layeredEffects.size()); - for (ContinuousEffect entry: effect.layeredEffects) { - layeredEffects.add((ContinuousEffect) entry.copy()); - } - replacementEffects.ensureCapacity(effect.replacementEffects.size()); - for (ReplacementEffect entry: effect.replacementEffects) { - replacementEffects.add((ReplacementEffect)entry.copy()); - } - preventionEffects.ensureCapacity(effect.preventionEffects.size()); - for (PreventionEffect entry: effect.preventionEffects) { - preventionEffects.add((PreventionEffect)entry.copy()); - } - requirementEffects.ensureCapacity(effect.requirementEffects.size()); - for (RequirementEffect entry: effect.requirementEffects) { - requirementEffects.add((RequirementEffect)entry.copy()); - } - restrictionEffects.ensureCapacity(effect.restrictionEffects.size()); - for (RestrictionEffect entry: effect.restrictionEffects) { - restrictionEffects.add((RestrictionEffect)entry.copy()); - } - asThoughEffects.ensureCapacity(effect.asThoughEffects.size()); - for (AsThoughEffect entry: effect.asThoughEffects) { - asThoughEffects.add((AsThoughEffect)entry.copy()); - } - costModificationEffects.ensureCapacity(effect.costModificationEffects.size()); - for ( CostModificationEffect entry : effect.costModificationEffects ) { - costModificationEffects.add(entry); - } - for (Entry entry: effect.abilityMap.entrySet()) { - abilityMap.put(entry.getKey(), entry.getValue().copy()); - } + layeredEffects = effect.layeredEffects.copy(); + replacementEffects = effect.replacementEffects.copy(); + preventionEffects = effect.preventionEffects.copy(); + requirementEffects = effect.requirementEffects.copy(); + restrictionEffects = effect.restrictionEffects.copy(); + asThoughEffects = effect.asThoughEffects.copy(); + costModificationEffects = effect.costModificationEffects.copy(); } public ContinuousEffects copy() { @@ -128,92 +91,41 @@ public class ContinuousEffects implements Serializable { } public Ability getAbility(UUID effectId) { - return abilityMap.get(effectId); + Ability ability = layeredEffects.getAbility(effectId); + if (ability == null) + ability = replacementEffects.getAbility(effectId); + if (ability == null) + ability = preventionEffects.getAbility(effectId); + if (ability == null) + ability = requirementEffects.getAbility(effectId); + if (ability == null) + ability = restrictionEffects.getAbility(effectId); + if (ability == null) + ability = asThoughEffects.getAbility(effectId); + if (ability == null) + ability = costModificationEffects.getAbility(effectId); + return ability; } public void removeEndOfTurnEffects() { - for (Iterator i = layeredEffects.iterator(); i.hasNext();) { - ContinuousEffect entry = i.next(); - if (entry.getDuration() == Duration.EndOfTurn) - i.remove(); - } - for (Iterator i = replacementEffects.iterator(); i.hasNext();) { - ContinuousEffect entry = i.next(); - if (entry.getDuration() == Duration.EndOfTurn) - i.remove(); - } - for (Iterator i = preventionEffects.iterator(); i.hasNext();) { - ContinuousEffect entry = i.next(); - if (entry.getDuration() == Duration.EndOfTurn) - i.remove(); - } - for (Iterator i = requirementEffects.iterator(); i.hasNext();) { - ContinuousEffect entry = i.next(); - if (entry.getDuration() == Duration.EndOfTurn) - i.remove(); - } - for (Iterator i = restrictionEffects.iterator(); i.hasNext();) { - ContinuousEffect entry = i.next(); - if (entry.getDuration() == Duration.EndOfTurn) - i.remove(); - } - for (Iterator i = asThoughEffects.iterator(); i.hasNext();) { - ContinuousEffect entry = i.next(); - if (entry.getDuration() == Duration.EndOfTurn) - i.remove(); - } - for (Iterator i = costModificationEffects.iterator(); i.hasNext();) { - ContinuousEffect entry = i.next(); - if (entry.getDuration() == Duration.EndOfTurn) - i.remove(); - } + layeredEffects.removeEndOfTurnEffects(); + replacementEffects.removeEndOfTurnEffects(); + preventionEffects.removeEndOfTurnEffects(); + requirementEffects.removeEndOfTurnEffects(); + restrictionEffects.removeEndOfTurnEffects(); + asThoughEffects.removeEndOfTurnEffects(); + costModificationEffects.removeEndOfTurnEffects(); } public void removeInactiveEffects(Game game) { - for (Iterator i = layeredEffects.iterator(); i.hasNext();) { - if (isInactive(i.next(), game)) - i.remove(); - } - for (Iterator i = replacementEffects.iterator(); i.hasNext();) { - if (isInactive(i.next(), game)) - i.remove(); - } - for (Iterator i = preventionEffects.iterator(); i.hasNext();) { - if (isInactive(i.next(), game)) - i.remove(); - } - for (Iterator i = requirementEffects.iterator(); i.hasNext();) { - if (isInactive(i.next(), game)) - i.remove(); - } - for (Iterator i = restrictionEffects.iterator(); i.hasNext();) { - if (isInactive(i.next(), game)) - i.remove(); - } - for (Iterator i = asThoughEffects.iterator(); i.hasNext();) { - if (isInactive(i.next(), game)) - i.remove(); - } - for (Iterator i = costModificationEffects.iterator(); i.hasNext();) { - if (isInactive(i.next(), game)) - i.remove(); - } - } + layeredEffects.removeInactiveEffects(game); + replacementEffects.removeInactiveEffects(game); + preventionEffects.removeInactiveEffects(game); + requirementEffects.removeInactiveEffects(game); + restrictionEffects.removeInactiveEffects(game); + asThoughEffects.removeInactiveEffects(game); + costModificationEffects.removeInactiveEffects(game); - private boolean isInactive(ContinuousEffect effect, Game game) { - Ability ability = abilityMap.get(effect.getId()); - if (ability == null) - return true; - switch(effect.getDuration()) { - case WhileOnBattlefield: - if (game.getObject(ability.getSourceId()) == null) - return (true); - case OneUse: - return effect.isUsed(); - case Custom: - return effect.isInactive(abilityMap.get(effect.getId()), game); - } - return false; } private List getLayeredEffects(Game game) { @@ -223,7 +135,7 @@ public class ContinuousEffects implements Serializable { case WhileOnBattlefield: case WhileOnStack: case WhileInGraveyard: - Ability ability = abilityMap.get(effect.getId()); + Ability ability = layeredEffects.getAbility(effect.getId()); if (ability.isInUseableZone(game)) layerEffects.add(effect); break; @@ -247,7 +159,7 @@ public class ContinuousEffects implements Serializable { public List getApplicableRequirementEffects(Permanent permanent, Game game) { List effects = new ArrayList(); for (RequirementEffect effect: requirementEffects) { - Ability ability = abilityMap.get(effect.getId()); + Ability ability = requirementEffects.getAbility(effect.getId()); if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game)) { if (effect.applies(permanent, ability, game)) effects.add(effect); @@ -259,7 +171,7 @@ public class ContinuousEffects implements Serializable { public List getApplicableRestrictionEffects(Permanent permanent, Game game) { List effects = new ArrayList(); for (RestrictionEffect effect: restrictionEffects) { - Ability ability = abilityMap.get(effect.getId()); + Ability ability = restrictionEffects.getAbility(effect.getId()); if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game)) { if (effect.applies(permanent, ability, game)) effects.add(effect); @@ -280,7 +192,7 @@ public class ContinuousEffects implements Serializable { replaceEffects.add(planeswalkerRedirectionEffect); //get all applicable transient Replacement effects for (ReplacementEffect effect: replacementEffects) { - Ability ability = abilityMap.get(effect.getId()); + Ability ability = replacementEffects.getAbility(effect.getId()); if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game)) { if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) { if (effect.applies(event, ability, game)) { @@ -290,7 +202,7 @@ public class ContinuousEffects implements Serializable { } } for (PreventionEffect effect: preventionEffects) { - Ability ability = abilityMap.get(effect.getId()); + Ability ability = preventionEffects.getAbility(effect.getId()); if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game)) { if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) { if (effect.applies(event, ability, game)) { @@ -307,7 +219,7 @@ public class ContinuousEffects implements Serializable { AsThoughEffect effect = entry; if (effect.getAsThoughEffectType() == type) { if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) { - if (effect.applies(objectId, abilityMap.get(entry.getId()), game)) { + if (effect.applies(objectId, asThoughEffects.getAbility(entry.getId()), game)) { return true; } } @@ -317,7 +229,7 @@ public class ContinuousEffects implements Serializable { } /** - * Inspects all {@link Permanent permanent's} {@link Ability abilities} on the battlefied + * Inspects all {@link Permanent permanent's} {@link Ability abilities} on the battlefield * for {@link CostModificationEffect cost modification effects} and applies them if necessary. * * @param abilityToModify @@ -326,8 +238,8 @@ public class ContinuousEffects implements Serializable { */ public void costModification ( Ability abilityToModify, Game game ) { for ( CostModificationEffect effect : costModificationEffects ) { - if ( effect.applies(abilityToModify, abilityMap.get(effect.getId()), game) ) { - effect.apply(game, abilityMap.get(effect.getId()), abilityToModify); + if ( effect.applies(abilityToModify, costModificationEffects.getAbility(effect.getId()), game) ) { + effect.apply(game, costModificationEffects.getAbility(effect.getId()), abilityToModify); } } } @@ -354,7 +266,7 @@ public class ContinuousEffects implements Serializable { index = player.chooseEffect(rEffects, game); } ReplacementEffect rEffect = rEffects.get(index); - caught = rEffect.replaceEvent(event, abilityMap.get(rEffect.getId()), game); + caught = rEffect.replaceEvent(event, this.getAbility(rEffect.getId()), game); if (caught) break; consumed.add(rEffect.getId()); @@ -368,47 +280,47 @@ public class ContinuousEffects implements Serializable { List layerEffects = getLayeredEffects(game); List layer = filterLayeredEffects(layerEffects, Layer.CopyEffects_1); for (ContinuousEffect effect: layer) { - effect.apply(Layer.CopyEffects_1, SubLayer.NA, abilityMap.get(effect.getId()), game); + effect.apply(Layer.CopyEffects_1, SubLayer.NA, layeredEffects.getAbility(effect.getId()), game); } layer = filterLayeredEffects(layerEffects, Layer.ControlChangingEffects_2); for (ContinuousEffect effect: layer) { - effect.apply(Layer.ControlChangingEffects_2, SubLayer.NA, abilityMap.get(effect.getId()), game); + effect.apply(Layer.ControlChangingEffects_2, SubLayer.NA, layeredEffects.getAbility(effect.getId()), game); } layer = filterLayeredEffects(layerEffects, Layer.TextChangingEffects_3); for (ContinuousEffect effect: layer) { - effect.apply(Layer.TextChangingEffects_3, SubLayer.NA, abilityMap.get(effect.getId()), game); + effect.apply(Layer.TextChangingEffects_3, SubLayer.NA, layeredEffects.getAbility(effect.getId()), game); } layer = filterLayeredEffects(layerEffects, Layer.TypeChangingEffects_4); for (ContinuousEffect effect: layer) { - effect.apply(Layer.TypeChangingEffects_4, SubLayer.NA, abilityMap.get(effect.getId()), game); + effect.apply(Layer.TypeChangingEffects_4, SubLayer.NA, layeredEffects.getAbility(effect.getId()), game); } layer = filterLayeredEffects(layerEffects, Layer.ColorChangingEffects_5); for (ContinuousEffect effect: layer) { - effect.apply(Layer.ColorChangingEffects_5, SubLayer.NA, abilityMap.get(effect.getId()), game); + effect.apply(Layer.ColorChangingEffects_5, SubLayer.NA, layeredEffects.getAbility(effect.getId()), game); } layer = filterLayeredEffects(layerEffects, Layer.AbilityAddingRemovingEffects_6); for (ContinuousEffect effect: layer) { - effect.apply(Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, abilityMap.get(effect.getId()), game); + effect.apply(Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, layeredEffects.getAbility(effect.getId()), game); } layerEffects = getLayeredEffects(game); layer = filterLayeredEffects(layerEffects, Layer.PTChangingEffects_7); for (ContinuousEffect effect: layer) { - effect.apply(Layer.PTChangingEffects_7, SubLayer.SetPT_7b, abilityMap.get(effect.getId()), game); + effect.apply(Layer.PTChangingEffects_7, SubLayer.SetPT_7b, layeredEffects.getAbility(effect.getId()), game); } for (ContinuousEffect effect: layer) { - effect.apply(Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, abilityMap.get(effect.getId()), game); + effect.apply(Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, layeredEffects.getAbility(effect.getId()), game); } applyCounters.apply(Layer.PTChangingEffects_7, SubLayer.Counters_7d, null, game); for (ContinuousEffect effect: layer) { - effect.apply(Layer.PTChangingEffects_7, SubLayer.SwitchPT_e, abilityMap.get(effect.getId()), game); + effect.apply(Layer.PTChangingEffects_7, SubLayer.SwitchPT_e, layeredEffects.getAbility(effect.getId()), game); } layer = filterLayeredEffects(layerEffects, Layer.PlayerEffects); for (ContinuousEffect effect: layer) { - effect.apply(Layer.PlayerEffects, SubLayer.NA, abilityMap.get(effect.getId()), game); + effect.apply(Layer.PlayerEffects, SubLayer.NA, layeredEffects.getAbility(effect.getId()), game); } layer = filterLayeredEffects(layerEffects, Layer.RulesEffects); for (ContinuousEffect effect: layer) { - effect.apply(Layer.RulesEffects, SubLayer.NA, abilityMap.get(effect.getId()), game); + effect.apply(Layer.RulesEffects, SubLayer.NA, layeredEffects.getAbility(effect.getId()), game); } } @@ -416,38 +328,31 @@ public class ContinuousEffects implements Serializable { switch (effect.getEffectType()) { case REPLACEMENT: ReplacementEffect newReplacementEffect = (ReplacementEffect)effect; - replacementEffects.add(newReplacementEffect); - abilityMap.put(newReplacementEffect.getId(), source); + replacementEffects.addEffect(newReplacementEffect, source); break; case PREVENTION: PreventionEffect newPreventionEffect = (PreventionEffect)effect; - preventionEffects.add(newPreventionEffect); - abilityMap.put(newPreventionEffect.getId(), source); + preventionEffects.addEffect(newPreventionEffect, source); break; case RESTRICTION: RestrictionEffect newRestrictionEffect = (RestrictionEffect)effect; - restrictionEffects.add(newRestrictionEffect); - abilityMap.put(newRestrictionEffect.getId(), source); + restrictionEffects.addEffect(newRestrictionEffect, source); break; case REQUIREMENT: RequirementEffect newRequirementEffect = (RequirementEffect)effect; - requirementEffects.add(newRequirementEffect); - abilityMap.put(newRequirementEffect.getId(), source); + requirementEffects.addEffect(newRequirementEffect, source); break; case ASTHOUGH: AsThoughEffect newAsThoughEffect = (AsThoughEffect)effect; - asThoughEffects.add(newAsThoughEffect); - abilityMap.put(newAsThoughEffect.getId(), source); + asThoughEffects.addEffect(newAsThoughEffect, source); break; case COSTMODIFICATION: CostModificationEffect newCostModificationEffect = (CostModificationEffect)effect; - costModificationEffects.add(newCostModificationEffect); - abilityMap.put(newCostModificationEffect.getId(), source); + costModificationEffects.addEffect(newCostModificationEffect, source); break; default: ContinuousEffect newEffect = (ContinuousEffect)effect; - layeredEffects.add(newEffect); - abilityMap.put(newEffect.getId(), source); + layeredEffects.addEffect(newEffect, source); break; } } @@ -460,7 +365,6 @@ public class ContinuousEffects implements Serializable { restrictionEffects.clear(); asThoughEffects.clear(); costModificationEffects.clear(); - abilityMap.clear(); } } diff --git a/Mage/src/mage/abilities/effects/ContinuousEffectsList.java b/Mage/src/mage/abilities/effects/ContinuousEffectsList.java new file mode 100644 index 00000000000..da663d824f0 --- /dev/null +++ b/Mage/src/mage/abilities/effects/ContinuousEffectsList.java @@ -0,0 +1,111 @@ +/* +* Copyright 2012 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; + +import java.util.*; +import mage.Constants; +import mage.abilities.Ability; +import mage.game.Game; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class ContinuousEffectsList extends ArrayList { + + private final Map abilityMap = new HashMap(); + + public ContinuousEffectsList() { } + + public ContinuousEffectsList(final ContinuousEffectsList effects) { + this.ensureCapacity(effects.size()); + for (ContinuousEffect cost: effects) { + this.add((T)cost.copy()); + } + for (Map.Entry entry: effects.abilityMap.entrySet()) { + abilityMap.put(entry.getKey(), entry.getValue().copy()); + } + } + + public ContinuousEffectsList copy() { + return new ContinuousEffectsList(this); + } + + public void removeEndOfTurnEffects() { + for (Iterator i = this.iterator(); i.hasNext();) { + T entry = i.next(); + if (entry.getDuration() == Constants.Duration.EndOfTurn) { + i.remove(); + abilityMap.remove(entry.getId()); + } + } + } + + public void removeInactiveEffects(Game game) { + for (Iterator i = this.iterator(); i.hasNext();) { + T entry = i.next(); + if (isInactive(entry, game)) { + i.remove(); + abilityMap.remove(entry.getId()); + } + } + } + + private boolean isInactive(T effect, Game game) { + Ability ability = abilityMap.get(effect.getId()); + if (ability == null) + return true; + switch(effect.getDuration()) { + case WhileOnBattlefield: + if (game.getObject(ability.getSourceId()) == null) + return (true); + case OneUse: + return effect.isUsed(); + case Custom: + return effect.isInactive(abilityMap.get(effect.getId()), game); + } + return false; + } + + public void addEffect(T effect, Ability source) { + if (abilityMap.containsKey(effect.getId())) + return; + this.add(effect); + this.abilityMap.put(effect.getId(), source); + } + + public Ability getAbility(UUID effectId) { + return abilityMap.get(effectId); + } + + @Override + public void clear() { + super.clear(); + abilityMap.clear(); + } +} diff --git a/Mage/src/mage/abilities/effects/common/GetEmblemEffect.java b/Mage/src/mage/abilities/effects/common/GetEmblemEffect.java index 077d86654c7..3b731ce2e88 100644 --- a/Mage/src/mage/abilities/effects/common/GetEmblemEffect.java +++ b/Mage/src/mage/abilities/effects/common/GetEmblemEffect.java @@ -65,7 +65,7 @@ public class GetEmblemEffect extends OneShotEffect { newEmblem.setControllerId(source.getControllerId()); game.getState().getCommand().add(newEmblem); for (Ability ability: newEmblem.getAbilities()) { - game.getState().addAbility(ability); + ability.resolve(game); } return true; } diff --git a/Mage/src/mage/counters/CounterType.java b/Mage/src/mage/counters/CounterType.java index 91ff51e2ae2..972f33003ff 100644 --- a/Mage/src/mage/counters/CounterType.java +++ b/Mage/src/mage/counters/CounterType.java @@ -60,7 +60,10 @@ public enum CounterType { KI(new KiCounter().name), SLIME(new SlimeCounter().name), SPORE(new SporeCounter().name), - STUDY(new StudyCounter().name); + STUDY(new StudyCounter().name), + EYEBALL(new EyeballCounter().name), + ELIXIR(new ElixirCounter().name), + PAIN(new PainCounter().name); private String name; @@ -144,6 +147,12 @@ public enum CounterType { return new SporeCounter(amount); case STUDY: return new StudyCounter(amount); + case EYEBALL: + return new EyeballCounter(amount); + case ELIXIR: + return new ElixirCounter(amount); + case PAIN: + return new PainCounter(amount); } return null; } diff --git a/Mage/src/mage/counters/common/ElixirCounter.java b/Mage/src/mage/counters/common/ElixirCounter.java new file mode 100644 index 00000000000..b31fb6df46d --- /dev/null +++ b/Mage/src/mage/counters/common/ElixirCounter.java @@ -0,0 +1,47 @@ +/* + * 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.counters.common; + +import mage.counters.Counter; + +/** + * + * @author North + */ +public class ElixirCounter extends Counter { + + public ElixirCounter() { + super("Elixir"); + this.count = 1; + } + + public ElixirCounter(int amount) { + super("Elixir"); + this.count = amount; + } +} diff --git a/Mage/src/mage/counters/common/EyeballCounter.java b/Mage/src/mage/counters/common/EyeballCounter.java new file mode 100644 index 00000000000..a0949d85dd3 --- /dev/null +++ b/Mage/src/mage/counters/common/EyeballCounter.java @@ -0,0 +1,47 @@ +/* + * 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.counters.common; + +import mage.counters.Counter; + +/** + * + * @author North + */ +public class EyeballCounter extends Counter { + + public EyeballCounter() { + super("Eyeball"); + this.count = 1; + } + + public EyeballCounter(int amount) { + super("Eyeball"); + this.count = amount; + } +} diff --git a/Mage/src/mage/counters/common/PainCounter.java b/Mage/src/mage/counters/common/PainCounter.java new file mode 100644 index 00000000000..e3f9f4809a5 --- /dev/null +++ b/Mage/src/mage/counters/common/PainCounter.java @@ -0,0 +1,47 @@ +/* + * 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.counters.common; + +import mage.counters.Counter; + +/** + * + * @author North + */ +public class PainCounter extends Counter { + + public PainCounter() { + super("Pain"); + this.count = 1; + } + + public PainCounter(int amount) { + super("Pain"); + this.count = amount; + } +} diff --git a/Mage/src/mage/filter/common/FilterNonTokenPermanent.java b/Mage/src/mage/filter/common/FilterNonTokenPermanent.java new file mode 100644 index 00000000000..2ffe30ee9bc --- /dev/null +++ b/Mage/src/mage/filter/common/FilterNonTokenPermanent.java @@ -0,0 +1,71 @@ +/* +* Copyright 2012 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.filter.common; + +import mage.filter.FilterPermanent; +import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentToken; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class FilterNonTokenPermanent extends FilterPermanent { + + public FilterNonTokenPermanent() { + this("nontoken permanent"); + } + + public FilterNonTokenPermanent(String name) { + super(name); + } + + public FilterNonTokenPermanent(final FilterNonTokenPermanent filter) { + super(filter); + } + + @Override + public boolean match(Permanent permanent) { + if (!super.match(permanent)) { + return notFilter; + } + + if (permanent instanceof PermanentToken) { + return notFilter; + } + + return !notFilter; + } + + @Override + public FilterNonTokenPermanent copy() { + return new FilterNonTokenPermanent(this); + } + +} diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 06b45c8fd6c..74456705efe 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -864,6 +864,12 @@ public abstract class PlayerImpl> implements Player, Ser int actualDamage = event.getAmount(); if (actualDamage > 0) { Permanent source = game.getPermanent(sourceId); + if(source == null){ + MageObject lastKnownInformation = game.getLastKnownInformation(sourceId, Zone.BATTLEFIELD); + if(lastKnownInformation instanceof Permanent){ + source = (Permanent) lastKnownInformation; + } + } if (source != null && (source.getAbilities().containsKey(InfectAbility.getInstance().getId()))) { addCounters(CounterType.POISON.createInstance(actualDamage), game); } else { @@ -1389,6 +1395,7 @@ public abstract class PlayerImpl> implements Player, Ser // do nothing } + @Override public void setAllowBadMoves(boolean allowBadMoves) { // do nothing }