diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/utils/RateCard.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/utils/RateCard.java index ca3091211b0..404f4eaa204 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/utils/RateCard.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/utils/RateCard.java @@ -203,7 +203,9 @@ public class RateCard { maxSingleCount = Math.max(maxSingleCount, typeCount); } } - return 2 * converted + 3 * (10 - SINGLE_PENALTY[maxSingleCount]/*-DOUBLE_PENALTY[doubleCount]*/); + if (maxSingleCount > 5) + maxSingleCount = 5; + return 2 * converted + 3 * (10 - SINGLE_PENALTY[maxSingleCount]/*-DOUBLE_PENALTY[doubleCount]*/); } /** diff --git a/Mage.Server/plugins/mage-player-ai.jar b/Mage.Server/plugins/mage-player-ai.jar index cf196b3c470..2041685d8e8 100644 Binary files a/Mage.Server/plugins/mage-player-ai.jar and b/Mage.Server/plugins/mage-player-ai.jar differ diff --git a/Mage.Sets/src/mage/sets/darkascension/AfflictedDeserter.java b/Mage.Sets/src/mage/sets/darkascension/AfflictedDeserter.java new file mode 100644 index 00000000000..371d6218f36 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/AfflictedDeserter.java @@ -0,0 +1,174 @@ +/* + * 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.Constants.Zone; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbility; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.common.NoSpellsWereCastLastTurnCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.keyword.TransformAbility; +import mage.cards.CardImpl; +import mage.filter.Filter; +import mage.filter.FilterPermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; + +/** + * + * @author BetaSteward + */ +public class AfflictedDeserter extends CardImpl { + + public AfflictedDeserter(UUID ownerId) { + super(ownerId, 81, "Afflicted Deserter", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{R}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Human"); + this.subtype.add("Werewolf"); + + this.canTransform = true; + this.secondSideCard = new WerewolfRansacker(ownerId); + + this.color.setRed(true); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Whenever this creature transforms into Werewolf Ransacker, you may destroy target artifact. If that artifact is put into a graveyard this way, Werewolf Ransacker deals 3 damage to that artifact's controller. + this.addAbility(new WerewolfRansackerAbility()); + + // At the beginning of each upkeep, if no spells were cast last turn, transform Afflicted Deserter. + 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 AfflictedDeserter(final AfflictedDeserter card) { + super(card); + } + + @Override + public AfflictedDeserter copy() { + return new AfflictedDeserter(this); + } +} + +class WerewolfRansackerAbility extends TriggeredAbilityImpl { + + private static final FilterPermanent filter = new FilterPermanent("artifact"); + + static { + filter.getCardType().add(CardType.ARTIFACT); + filter.setScopeCardType(Filter.ComparisonScope.Any); + } + + public WerewolfRansackerAbility() { + super(Constants.Zone.BATTLEFIELD, new WerewolfRansackerEffect(), true); + Target target = new TargetPermanent(filter); + target.setRequired(true); + this.addTarget(target); + } + + public WerewolfRansackerAbility(final WerewolfRansackerAbility ability) { + super(ability); + } + + @Override + public WerewolfRansackerAbility copy() { + return new WerewolfRansackerAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.TRANSFORMED) { + if (event.getTargetId().equals(sourceId)) { + Permanent permanent = game.getPermanent(sourceId); + if (permanent != null && permanent.isTransformed()) + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever this creature transforms into Werewolf Ransacker, you may destroy target artifact. If that artifact is put into a graveyard this way, Werewolf Ransacker deals 3 damage to that artifact's controller."; + } + +} + +class WerewolfRansackerEffect extends OneShotEffect { + + public WerewolfRansackerEffect() { + super(Constants.Outcome.DestroyPermanent); + } + + public WerewolfRansackerEffect(final WerewolfRansackerEffect effect) { + super(effect); + } + + @Override + public WerewolfRansackerEffect copy() { + return new WerewolfRansackerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int affectedTargets = 0; + if (targetPointer.getTargets(source).size() > 0) { + for (UUID permanentId : targetPointer.getTargets(source)) { + Permanent permanent = game.getPermanent(permanentId); + if (permanent != null) { + if (permanent.destroy(source.getId(), game, false)) { + affectedTargets++; + if (game.getState().getZone(permanent.getId()) == Zone.GRAVEYARD) { + Player player = game.getPlayer(permanent.getControllerId()); + if (player != null) + player.damage(3, source.getSourceId(), game, false, true); + } + } + } + } + } + return affectedTargets > 0; + } + +} diff --git a/Mage.Sets/src/mage/sets/darkascension/ChosenOfMarkov.java b/Mage.Sets/src/mage/sets/darkascension/ChosenOfMarkov.java new file mode 100644 index 00000000000..99b0f076778 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/ChosenOfMarkov.java @@ -0,0 +1,88 @@ +/* + * 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.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.keyword.TransformAbility; +import mage.cards.CardImpl; +import mage.filter.Filter; +import mage.filter.common.FilterControlledPermanent; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author Loki + */ +public class ChosenOfMarkov extends CardImpl { + private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Vampire you control"); + + static { + filter.setUseTapped(true); + filter.setTapped(false); + filter.getSubtype().add("Vampire"); + filter.setScopeSubtype(Filter.ComparisonScope.Any); + } + + public ChosenOfMarkov(UUID ownerId) { + super(ownerId, 55, "Chosen of Markov", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Human"); + + this.color.setBlack(true); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + this.canTransform = true; + this.secondSideCard = new MarkovsServant(ownerId); + + // {tap}, Tap an untapped Vampire you control: Transform Chosen of Markov. + this.addAbility(new TransformAbility()); + Ability ability = new SimpleActivatedAbility(Constants.Zone.BATTLEFIELD, new TransformSourceEffect(true), new TapSourceCost()); + ability.addCost(new TapTargetCost(new TargetControlledPermanent(filter))); + this.addAbility(ability); + } + + public ChosenOfMarkov(final ChosenOfMarkov card) { + super(card); + } + + @Override + public ChosenOfMarkov copy() { + return new ChosenOfMarkov(this); + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/Counterlash.java b/Mage.Sets/src/mage/sets/darkascension/Counterlash.java new file mode 100644 index 00000000000..f43e9bf01bf --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/Counterlash.java @@ -0,0 +1,115 @@ +/* + * 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.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.filter.Filter; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.game.Game; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.target.TargetSpell; +import mage.target.common.TargetCardInHand; + +/** + * + * @author BetaSteward + */ +public class Counterlash extends CardImpl { + + public Counterlash(UUID ownerId) { + super(ownerId, 33, "Counterlash", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{4}{U}{U}"); + this.expansionSetCode = "DKA"; + + this.color.setBlue(true); + + // Counter target spell. You may cast a nonland card in your hand that shares a card type with that spell without paying its mana cost. + this.getSpellAbility().addTarget(new TargetSpell()); + this.getSpellAbility().addEffect(new CounterlashEffect()); + } + + public Counterlash(final Counterlash card) { + super(card); + } + + @Override + public Counterlash copy() { + return new Counterlash(this); + } +} + +class CounterlashEffect extends OneShotEffect { + + public CounterlashEffect() { + super(Constants.Outcome.Detriment); + this.staticText = "Counter target spell. You may cast a nonland card in your hand that shares a card type with that spell without paying its mana cost"; + } + + public CounterlashEffect(final CounterlashEffect effect) { + super(effect); + } + + @Override + public CounterlashEffect copy() { + return new CounterlashEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + StackObject stackObject = game.getStack().getStackObject(source.getFirstTarget()); + Player player = game.getPlayer(source.getControllerId()); + if (stackObject != null && player != null) { + game.getStack().counter(source.getFirstTarget(), source.getSourceId(), game); + if (player.chooseUse(Constants.Outcome.PutCardInPlay, "Cast a nonland card in your hand that shares a card type with that spell without paying its mana cost?", game)) { + FilterCard filter = new FilterCard(); + for (CardType type: stackObject.getCardType()) { + if (type != CardType.LAND) + filter.getCardType().add(type); + } + filter.setScopeCardType(Filter.ComparisonScope.Any); + TargetCardInHand target = new TargetCardInHand(filter); + if (player.choose(Constants.Outcome.PutCardInPlay, target, source.getSourceId(), game)) { + Card card = player.getHand().get(target.getFirstTarget(), game); + if (card != null) { + player.cast(card.getSpellAbility(), game, true); + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/CurseOfThirst.java b/Mage.Sets/src/mage/sets/darkascension/CurseOfThirst.java new file mode 100644 index 00000000000..d4044a42968 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/CurseOfThirst.java @@ -0,0 +1,156 @@ +/* + * 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.TriggeredAbilityImpl; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author BetaSteward + */ +public class CurseOfThirst extends CardImpl { + + public CurseOfThirst(UUID ownerId) { + super(ownerId, 57, "Curse of Thirst", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{4}{B}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Aura"); + this.subtype.add("Curse"); + + this.color.setBlack(true); + + // Enchant player + TargetPlayer auraTarget = new TargetPlayer(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Constants.Outcome.Detriment)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // At the beginning of enchanted player's upkeep, Curse of Thirst deals damage to that player equal to the number of Curses attached to him or her. + this.addAbility(new CurseOfThirstAbility()); + + } + + public CurseOfThirst(final CurseOfThirst card) { + super(card); + } + + @Override + public CurseOfThirst copy() { + return new CurseOfThirst(this); + } +} + +class CurseOfThirstAbility extends TriggeredAbilityImpl { + + public CurseOfThirstAbility() { + super(Constants.Zone.BATTLEFIELD, new DamageTargetEffect(new CursesAttachedCount())); + } + + public CurseOfThirstAbility(final CurseOfThirstAbility ability) { + super(ability); + } + + @Override + public CurseOfThirstAbility copy() { + return new CurseOfThirstAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE) { + Permanent enchantment = game.getPermanent(this.sourceId); + if (enchantment != null && enchantment.getAttachedTo() != null) { + Player player = game.getPlayer(enchantment.getAttachedTo()); + if (player != null && game.getActivePlayerId().equals(player.getId())) { + this.getEffects().get(0).setTargetPointer(new FixedTarget(player.getId())); + return true; + } + } + } + return false; + } + + @Override + public String getRule() { + return "At the beginning of enchanted player's upkeep, Curse of Thirst deals damage to that player equal to the number of Curses attached to him or her."; + } + +} + +class CursesAttachedCount implements DynamicValue { + + public CursesAttachedCount() { + } + + @Override + public int calculate(Game game, Ability sourceAbility) { + int count = 0; + Permanent enchantment = game.getPermanent(sourceAbility.getSourceId()); + if (enchantment != null && enchantment.getAttachedTo() != null) { + Player player = game.getPlayer(enchantment.getAttachedTo()); + if (player != null) { + for (UUID attachmentId: player.getAttachments()) { + Permanent attachment = game.getPermanent(attachmentId); + if (attachment != null && attachment.getSubtype().contains("Curse")) + count++; + } + } + } + return count; + } + + @Override + public DynamicValue clone() { + return new CursesAttachedCount(); + } + + @Override + public String toString() { + return ""; + } + + @Override + public String getMessage() { + return "number of Curses attached to him or her"; + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/FiendOfTheShadows.java b/Mage.Sets/src/mage/sets/darkascension/FiendOfTheShadows.java new file mode 100644 index 00000000000..c366fd41646 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/FiendOfTheShadows.java @@ -0,0 +1,135 @@ +/* + * 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.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.common.ExileFromZoneTargetEffect; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.filter.Filter; +import mage.filter.FilterCard; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.game.ExileZone; +import mage.game.Game; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author BetaSteward + */ +public class FiendOfTheShadows extends CardImpl { + + private UUID exileId = UUID.randomUUID(); + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a human"); + + static { + filter.getSubtype().add("Human"); + filter.setScopeSubtype(Filter.ComparisonScope.Any); + } + + public FiendOfTheShadows(UUID ownerId) { + super(ownerId, 62, "Fiend of the Shadows", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Vampire"); + this.subtype.add("Wizard"); + + this.color.setBlack(true); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + this.addAbility(FlyingAbility.getInstance()); + // Whenever Fiend of the Shadows deals combat damage to a player, that player exiles a card from his or her hand. You may play that card for as long as it remains exiled. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new ExileFromZoneTargetEffect(Constants.Zone.HAND, exileId, "Fiend of the Shadows", new FilterCard()), false, true)); + this.addAbility(new SimpleStaticAbility(Constants.Zone.ALL, new FiendOfTheShadowsEffect(exileId))); + + // Sacrifice a Human: Regenerate Fiend of the Shadows. + this.addAbility(new SimpleActivatedAbility(Constants.Zone.BATTLEFIELD, new RegenerateSourceEffect(), new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, false)))); + } + + public FiendOfTheShadows(final FiendOfTheShadows card) { + super(card); + } + + @Override + public FiendOfTheShadows copy() { + return new FiendOfTheShadows(this); + } +} + +class FiendOfTheShadowsEffect extends AsThoughEffectImpl { + + private UUID exileId; + + public FiendOfTheShadowsEffect(UUID exileId) { + super(Constants.AsThoughEffectType.CAST, Constants.Duration.EndOfGame, Constants.Outcome.Benefit); + this.exileId = exileId; + staticText = "You may play that card for as long as it remains exiled"; + } + + public FiendOfTheShadowsEffect(final FiendOfTheShadowsEffect effect) { + super(effect); + this.exileId = effect.exileId; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public FiendOfTheShadowsEffect copy() { + return new FiendOfTheShadowsEffect(this); + } + + @Override + public boolean applies(UUID sourceId, Ability source, Game game) { + Card card = game.getCard(sourceId); + if (card != null) { + ExileZone zone = game.getExile().getExileZone(exileId); + if (zone != null && zone.contains(card.getId())) { + card.setControllerId(source.getControllerId()); + return true; + } + } + return false; + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/darkascension/HeadlessSkaab.java b/Mage.Sets/src/mage/sets/darkascension/HeadlessSkaab.java new file mode 100644 index 00000000000..76b9f59237b --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/HeadlessSkaab.java @@ -0,0 +1,70 @@ +/* + * 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.EntersBattlefieldTappedAbility; +import mage.abilities.costs.common.ExileFromGraveCost; +import mage.cards.CardImpl; +import mage.filter.common.FilterCreatureCard; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author Loki + */ +public class HeadlessSkaab extends CardImpl { + + public HeadlessSkaab(UUID ownerId) { + super(ownerId, 40, "Headless Skaab", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{U}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Zombie"); + this.subtype.add("Warrior"); + + this.color.setBlue(true); + this.power = new MageInt(3); + this.toughness = new MageInt(6); + + // As an additional cost to cast Headless Skaab, exile a creature card from your graveyard. + this.getSpellAbility().addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard")))); + // Headless Skaab enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + } + + public HeadlessSkaab(final HeadlessSkaab card) { + super(card); + } + + @Override + public HeadlessSkaab copy() { + return new HeadlessSkaab(this); + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/HuntmasterOfTheFells.java b/Mage.Sets/src/mage/sets/darkascension/HuntmasterOfTheFells.java new file mode 100644 index 00000000000..6aae73ad182 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/HuntmasterOfTheFells.java @@ -0,0 +1,252 @@ +/* + * 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.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbility; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.common.NoSpellsWereCastLastTurnCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.keyword.TransformAbility; +import mage.cards.CardImpl; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.WolfToken; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.target.common.TargetOpponent; + +/** + * + * @author BetaSteward + */ +public class HuntmasterOfTheFells extends CardImpl { + + public HuntmasterOfTheFells(UUID ownerId) { + super(ownerId, 140, "Huntmaster of the Fells", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{2}{R}{G}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Human"); + this.subtype.add("Werewolf"); + + this.canTransform = true; + this.secondSideCard = new RavagerOfTheFells(ownerId); + + this.color.setRed(true); + this.color.setGreen(true); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever this creature enters the battlefield or transforms into Huntmaster of the Fells, put a 2/2 green Wolf creature token onto the battlefield and you gain 2 life. + this.addAbility(new HuntmasterOfTheFellsAbility()); + + // Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls. + this.addAbility(new RavagerOfTheFellsAbility()); + + // At the beginning of each upkeep, if no spells were cast last turn, transform Huntmaster of the Fells. + 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 HuntmasterOfTheFells(final HuntmasterOfTheFells card) { + super(card); + } + + @Override + public HuntmasterOfTheFells copy() { + return new HuntmasterOfTheFells(this); + } +} + +class HuntmasterOfTheFellsAbility extends TriggeredAbilityImpl { + + public HuntmasterOfTheFellsAbility() { + super(Constants.Zone.BATTLEFIELD, new CreateTokenEffect(new WolfToken()), true); + this.addEffect(new GainLifeEffect(2)); + } + + public HuntmasterOfTheFellsAbility(final HuntmasterOfTheFellsAbility ability) { + super(ability); + } + + @Override + public HuntmasterOfTheFellsAbility copy() { + return new HuntmasterOfTheFellsAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.TRANSFORMED && event.getTargetId().equals(this.getSourceId())) { + Permanent permanent = game.getPermanent(sourceId); + if (permanent != null && !permanent.isTransformed()) + return true; + } + if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(this.getSourceId())) { + ZoneChangeEvent zEvent = (ZoneChangeEvent)event; + if (zEvent.getToZone() == Zone.BATTLEFIELD) { + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever this creature enters the battlefield or transforms into Huntmaster of the Fells, put a 2/2 green Wolf creature token onto the battlefield and you gain 2 life."; + } + +} + +class RavagerOfTheFellsAbility extends TriggeredAbilityImpl { + + public RavagerOfTheFellsAbility() { + super(Constants.Zone.BATTLEFIELD, new RavagerOfTheFellsEffect(), true); + Target target1 = new TargetOpponent(); + target1.setRequired(true); + this.addTarget(target1); + this.addTarget(new RavagerOfTheFellsTarget()); + } + + public RavagerOfTheFellsAbility(final RavagerOfTheFellsAbility ability) { + super(ability); + } + + @Override + public RavagerOfTheFellsAbility copy() { + return new RavagerOfTheFellsAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.TRANSFORMED && event.getTargetId().equals(sourceId)) { + Permanent permanent = game.getPermanent(sourceId); + if (permanent != null && permanent.isTransformed()) + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls."; + } + +} + +class RavagerOfTheFellsEffect extends OneShotEffect { + + public RavagerOfTheFellsEffect() { + super(Constants.Outcome.Damage); + staticText = "{this} deals 2 damage to target opponent and 2 damage to up to one target creature that player controls"; + } + + public RavagerOfTheFellsEffect(final RavagerOfTheFellsEffect effect) { + super(effect); + } + + @Override + public RavagerOfTheFellsEffect copy() { + return new RavagerOfTheFellsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getTargets().get(0).getFirstTarget()); + if (player != null) { + player.damage(2, source.getSourceId(), game, false, true); + } + Permanent creature = game.getPermanent(source.getTargets().get(1).getFirstTarget()); + if (creature != null) { + creature.damage(2, source.getSourceId(), game, true, false); + } + return true; + } + +} + +class RavagerOfTheFellsTarget extends TargetPermanent { + + public RavagerOfTheFellsTarget() { + super(0, 1, new FilterCreaturePermanent(), false); + } + + public RavagerOfTheFellsTarget(final RavagerOfTheFellsTarget target) { + super(target); + } + + @Override + public boolean canTarget(UUID id, Ability source, Game game) { + UUID firstTarget = source.getFirstTarget(); + Permanent permanent = game.getPermanent(id); + if (firstTarget != null && permanent != null && permanent.getControllerId().equals(firstTarget)) { + return super.canTarget(id, source, game); + } + return false; + } + + @Override + public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + Set availablePossibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + Set possibleTargets = new HashSet(); + MageObject object = game.getObject(sourceId); + if (object instanceof StackObject) { + UUID playerId = ((StackObject)object).getStackAbility().getFirstTarget(); + for (UUID targetId : availablePossibleTargets) { + Permanent permanent = game.getPermanent(targetId); + if(permanent != null && permanent.getControllerId().equals(playerId)){ + possibleTargets.add(targetId); + } + } + } + return possibleTargets; + } + + @Override + public RavagerOfTheFellsTarget copy() { + return new RavagerOfTheFellsTarget(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/darkascension/KrallenhordeKiller.java b/Mage.Sets/src/mage/sets/darkascension/KrallenhordeKiller.java new file mode 100644 index 00000000000..e20f9266ac1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/KrallenhordeKiller.java @@ -0,0 +1,80 @@ +/* + * 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.ActivateOncePerTurnActivatedAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.common.TwoOrMoreSpellsWereCastLastTurnCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continious.BoostSourceEffect; +import mage.abilities.keyword.TransformAbility; +import mage.cards.CardImpl; + +/** + * + * @author Loki + */ +public class KrallenhordeKiller extends CardImpl { + + public KrallenhordeKiller(UUID ownerId) { + super(ownerId, 133, "Krallenhorde Killer", Rarity.RARE, new CardType[]{CardType.CREATURE}, ""); + this.expansionSetCode = "DKA"; + this.subtype.add("Werewolf"); + + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + this.nightCard = true; + this.canTransform = true; + + // {3}{G}: Krallenhorde Killer gets +4/+4 until end of turn. Activate this ability only once each turn. + this.addAbility(new ActivateOncePerTurnActivatedAbility(Constants.Zone.BATTLEFIELD, new BoostSourceEffect(4, 4, Constants.Duration.EndOfTurn), new ManaCostsImpl("{3}{G}"))); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Krallenhorde Killer. + 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 KrallenhordeKiller(final KrallenhordeKiller card) { + super(card); + } + + @Override + public KrallenhordeKiller copy() { + return new KrallenhordeKiller(this); + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/MarkovsServant.java b/Mage.Sets/src/mage/sets/darkascension/MarkovsServant.java new file mode 100644 index 00000000000..5e4c2d45f71 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/MarkovsServant.java @@ -0,0 +1,62 @@ +/* + * 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.cards.CardImpl; + +/** + * + * @author Loki + */ +public class MarkovsServant extends CardImpl { + + public MarkovsServant(UUID ownerId) { + super(ownerId, 55, "Markov's Servant", Rarity.COMMON, new CardType[]{CardType.CREATURE}, null); + this.expansionSetCode = "DKA"; + this.subtype.add("Vampire"); + + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + this.canTransform = true; + this.nightCard = true; + } + + public MarkovsServant(final MarkovsServant card) { + super(card); + } + + @Override + public MarkovsServant copy() { + return new MarkovsServant(this); + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/MysticRetrieval.java b/Mage.Sets/src/mage/sets/darkascension/MysticRetrieval.java new file mode 100644 index 00000000000..8c8bc517284 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/MysticRetrieval.java @@ -0,0 +1,77 @@ +/* + * 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.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.keyword.FlashbackAbility; +import mage.cards.CardImpl; +import mage.filter.Filter; +import mage.filter.FilterCard; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author Loki + */ +public class MysticRetrieval extends CardImpl { + private static final FilterCard filter = new FilterCard("instant or sorcery card from your graveyard"); + + static { + filter.getCardType().add(CardType.INSTANT); + filter.getCardType().add(CardType.SORCERY); + filter.setScopeCardType(Filter.ComparisonScope.Any); + } + + public MysticRetrieval(UUID ownerId) { + super(ownerId, 42, "Mystic Retrieval", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{3}{U}"); + this.expansionSetCode = "DKA"; + + this.color.setBlue(true); + + // Return target instant or sorcery card from your graveyard to your hand. + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); + // Flashback {2}{R} + this.addAbility(new FlashbackAbility(new ManaCostsImpl("{2}{R}"), Constants.TimingRule.SORCERY)); + } + + public MysticRetrieval(final MysticRetrieval card) { + super(card); + } + + @Override + public MysticRetrieval copy() { + return new MysticRetrieval(this); + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/NiblisOfTheBreath.java b/Mage.Sets/src/mage/sets/darkascension/NiblisOfTheBreath.java new file mode 100644 index 00000000000..4edfebe5579 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/NiblisOfTheBreath.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.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ColoredManaCost; +import mage.abilities.effects.common.MayTapOrUntapTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author Loki + */ +public class NiblisOfTheBreath extends CardImpl { + + public NiblisOfTheBreath(UUID ownerId) { + super(ownerId, 44, "Niblis of the Breath", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{U}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Spirit"); + + this.color.setBlue(true); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + this.addAbility(FlyingAbility.getInstance()); + // {U}, {tap}: You may tap or untap target creature. + Ability ability = new SimpleActivatedAbility(Constants.Zone.BATTLEFIELD, new MayTapOrUntapTargetEffect(), new ColoredManaCost(Constants.ColoredManaSymbol.U)); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public NiblisOfTheBreath(final NiblisOfTheBreath card) { + super(card); + } + + @Override + public NiblisOfTheBreath copy() { + return new NiblisOfTheBreath(this); + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/RavagerOfTheFells.java b/Mage.Sets/src/mage/sets/darkascension/RavagerOfTheFells.java new file mode 100644 index 00000000000..05ac541ef86 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/RavagerOfTheFells.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.condition.common.TwoOrMoreSpellsWereCastLastTurnCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.TransformAbility; +import mage.cards.CardImpl; + +/** + * + * @author BetaSteward + */ +public class RavagerOfTheFells extends CardImpl { + + public RavagerOfTheFells(UUID ownerId) { + super(ownerId, 140, "Ravager of the Fells", Rarity.MYTHIC, 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(4); + this.toughness = new MageInt(4); + + this.addAbility(TrampleAbility.getInstance()); + + // Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls. + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ravager of the Fells. + 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 RavagerOfTheFells(final RavagerOfTheFells card) { + super(card); + } + + @Override + public RavagerOfTheFells copy() { + return new RavagerOfTheFells(this); + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/RelentlessSkaabs.java b/Mage.Sets/src/mage/sets/darkascension/RelentlessSkaabs.java new file mode 100644 index 00000000000..f740282dbfa --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/RelentlessSkaabs.java @@ -0,0 +1,69 @@ +/* + * 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.costs.common.ExileFromGraveCost; +import mage.abilities.keyword.UndyingAbility; +import mage.cards.CardImpl; +import mage.filter.common.FilterCreatureCard; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author Loki + */ +public class RelentlessSkaabs extends CardImpl { + + public RelentlessSkaabs(UUID ownerId) { + super(ownerId, 45, "Relentless Skaabs", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Zombie"); + + this.color.setBlue(true); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // As an additional cost to cast Relentless Skaabs, exile a creature card from your graveyard. + this.getSpellAbility().addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard")))); + // Undying + this.addAbility(new UndyingAbility()); + } + + public RelentlessSkaabs(final RelentlessSkaabs card) { + super(card); + } + + @Override + public RelentlessSkaabs copy() { + return new RelentlessSkaabs(this); + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/SorinLordOfInnistrad.java b/Mage.Sets/src/mage/sets/darkascension/SorinLordOfInnistrad.java new file mode 100644 index 00000000000..05aff395e25 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/SorinLordOfInnistrad.java @@ -0,0 +1,169 @@ +/* + * 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.Duration; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.GetEmblemEffect; +import mage.abilities.effects.common.continious.BoostControlledEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.counters.CounterType; +import mage.filter.Filter; +import mage.filter.FilterPermanent; +import mage.game.Game; +import mage.game.command.Emblem; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.Token; +import mage.players.Player; +import mage.target.TargetPermanent; + +/** + * + * @author BetaSteward + */ +public class SorinLordOfInnistrad extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("creature or planeswalker"); + + static { + filter.getCardType().add(CardType.CREATURE); + filter.getCardType().add(CardType.PLANESWALKER); + filter.setScopeCardType(Filter.ComparisonScope.Any); + } + + public SorinLordOfInnistrad(UUID ownerId) { + super(ownerId, 142, "Sorin, Lord of Innistrad", Rarity.MYTHIC, new CardType[]{CardType.PLANESWALKER}, "{2}{W}{B}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Sorin"); + + this.color.setBlack(true); + this.color.setWhite(true); + + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), "")); + + // +1: Put a 1/1 black Vampire creature token with lifelink onto the battlefield. + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new VampireToken()), 1)); + + // -2: You get an emblem with "Creatures you control get +1/+0." + this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new SorinEmblem()), -2)); + + // -6: Destroy up to three target creatures and/or other planeswalkers. Return each card put into a graveyard this way to the battlefield under your control. + LoyaltyAbility ability = new LoyaltyAbility(new SorinLordOfInnistradEffect(), -6); + ability.addTarget(new TargetPermanent(0, 3, filter, false)); + this.addAbility(ability); + } + + public SorinLordOfInnistrad(final SorinLordOfInnistrad card) { + super(card); + } + + @Override + public SorinLordOfInnistrad copy() { + return new SorinLordOfInnistrad(this); + } +} + +class VampireToken extends Token { + VampireToken() { + super("Vampire", "a 1/1 black Vampire creature token with lifelink"); + cardType.add(Constants.CardType.CREATURE); + color.setBlack(true); + subtype.add("Vampire"); + power = new MageInt(1); + toughness = new MageInt(1); + addAbility(LifelinkAbility.getInstance()); + } +} + +class SorinEmblem extends Emblem { + + public SorinEmblem() { + BoostControlledEffect effect = new BoostControlledEffect(1, 0, Duration.EndOfGame); + Ability ability = new SimpleStaticAbility(Zone.COMMAND, effect); + this.getAbilities().add(ability); + } +} + +class SorinLordOfInnistradEffect extends OneShotEffect { + + public SorinLordOfInnistradEffect() { + super(Constants.Outcome.Sacrifice); + this.staticText = "Destroy up to three target creatures and/or other planeswalkers. Return each card put into a graveyard this way to the battlefield under your control"; + } + + public SorinLordOfInnistradEffect(final SorinLordOfInnistradEffect effect) { + super(effect); + } + + @Override + public SorinLordOfInnistradEffect copy() { + return new SorinLordOfInnistradEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID targetId: source.getTargets().get(0).getTargets()) { + Permanent perm = game.getPermanent(targetId); + if (perm != null) { + perm.destroy(source.getSourceId(), game, false); + } + } + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + for (UUID targetId: source.getTargets().get(0).getTargets()) { + if (game.getState().getZone(targetId) == Zone.GRAVEYARD) { + Card card = game.getCard(targetId); + if (card != null) { + Player owner = game.getPlayer(card.getOwnerId()); + if (owner != null) { + owner.removeFromGraveyard(card, game); + card.putOntoBattlefield(game, Zone.GRAVEYARD, source.getId(), player.getId()); + } + } + } + } + } + + return true; + } + +} diff --git a/Mage.Sets/src/mage/sets/darkascension/StormboundGeist.java b/Mage.Sets/src/mage/sets/darkascension/StormboundGeist.java new file mode 100644 index 00000000000..d2bf3af6fa2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/StormboundGeist.java @@ -0,0 +1,71 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.darkascension; + +import java.util.UUID; + +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continious.CanBlockOnlyFlyingEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.UndyingAbility; +import mage.cards.CardImpl; + +/** + * @author Loki + */ +public class StormboundGeist extends CardImpl { + + public StormboundGeist(UUID ownerId) { + super(ownerId, 51, "Stormbound Geist", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Spirit"); + + this.color.setBlue(true); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + this.addAbility(FlyingAbility.getInstance()); + // Stormbound Geist can block only creatures with flying. + this.addAbility(new SimpleStaticAbility(Constants.Zone.BATTLEFIELD, new CanBlockOnlyFlyingEffect())); + // Undying + this.addAbility(new UndyingAbility()); + } + + public StormboundGeist(final StormboundGeist card) { + super(card); + } + + @Override + public StormboundGeist copy() { + return new StormboundGeist(this); + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/ThrabenHeretic.java b/Mage.Sets/src/mage/sets/darkascension/ThrabenHeretic.java new file mode 100644 index 00000000000..6540efee4a9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/ThrabenHeretic.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.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.CardImpl; +import mage.filter.common.FilterCreatureCard; +import mage.target.common.TargetCardInGraveyard; + +/** + * + * @author Loki + */ +public class ThrabenHeretic extends CardImpl { + + public ThrabenHeretic(UUID ownerId) { + super(ownerId, 26, "Thraben Heretic", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{W}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Human"); + this.subtype.add("Wizard"); + + this.color.setWhite(true); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {tap}: Exile target creature card from a graveyard. + Ability ability = new SimpleActivatedAbility(Constants.Zone.BATTLEFIELD, new ExileTargetEffect(), new TapSourceCost()); + ability.addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card from a graveyard"))); + this.addAbility(ability); + } + + public ThrabenHeretic(final ThrabenHeretic card) { + super(card); + } + + @Override + public ThrabenHeretic copy() { + return new ThrabenHeretic(this); + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/TorchFiend.java b/Mage.Sets/src/mage/sets/darkascension/TorchFiend.java new file mode 100644 index 00000000000..511ebf62be9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/TorchFiend.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.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.ColoredManaCost; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.target.common.TargetArtifactPermanent; + +/** + * + * @author Loki + */ +public class TorchFiend extends CardImpl { + + public TorchFiend(UUID ownerId) { + super(ownerId, 106, "Torch Fiend", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{R}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Devil"); + + this.color.setRed(true); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // {R}, Sacrifice Torch Fiend: Destroy target artifact. + Ability ability = new SimpleActivatedAbility(Constants.Zone.BATTLEFIELD, new DestroyTargetEffect(), new ColoredManaCost(Constants.ColoredManaSymbol.R)); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetArtifactPermanent()); + this.addAbility(ability); + } + + public TorchFiend(final TorchFiend card) { + super(card); + } + + @Override + public TorchFiend copy() { + return new TorchFiend(this); + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/VillageSurvivors.java b/Mage.Sets/src/mage/sets/darkascension/VillageSurvivors.java new file mode 100644 index 00000000000..cb5f1ce6349 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/VillageSurvivors.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.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MorbidCondition; +import mage.abilities.decorator.ConditionalContinousEffect; +import mage.abilities.effects.common.continious.GainAbilityControlledEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; + +/** + * + * @author Loki + */ +public class VillageSurvivors extends CardImpl { + + public VillageSurvivors(UUID ownerId) { + super(ownerId, 130, "Village Survivors", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{4}{G}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Human"); + + this.color.setGreen(true); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + this.addAbility(VigilanceAbility.getInstance()); + // Fateful hour - As long as you have 5 or less life, other creatures you control have vigilance. + this.addAbility(new SimpleStaticAbility(Constants.Zone.BATTLEFIELD, new ConditionalContinousEffect( + new GainAbilityControlledEffect(VigilanceAbility.getInstance(), Constants.Duration.WhileOnBattlefield), + MorbidCondition.getInstance(), + "Fateful hour - As long as you have 5 or less life, other creatures you control have vigilance"))); + } + + public VillageSurvivors(final VillageSurvivors card) { + super(card); + } + + @Override + public VillageSurvivors copy() { + return new VillageSurvivors(this); + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/Wakedancer.java b/Mage.Sets/src/mage/sets/darkascension/Wakedancer.java new file mode 100644 index 00000000000..ae100bc7f6d --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/Wakedancer.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.darkascension; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.MageInt; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.MorbidCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.game.permanent.token.ZombieToken; + +/** + * + * @author Loki + */ +public class Wakedancer extends CardImpl { + static String staticText = "Morbid - When {this} enters the battlefield, if a creature died this turn, put a 2/2 black Zombie creature token onto the battlefield."; + + public Wakedancer(UUID ownerId) { + super(ownerId, 79, "Wakedancer", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Human"); + this.subtype.add("Shaman"); + + this.color.setBlack(true); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Morbid - When Wakedancer enters the battlefield, if a creature died this turn, put a 2/2 black Zombie creature token onto the battlefield. + TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ZombieToken())); + this.addAbility(new ConditionalTriggeredAbility(ability, MorbidCondition.getInstance(), staticText)); + } + + public Wakedancer(final Wakedancer card) { + super(card); + } + + @Override + public Wakedancer copy() { + return new Wakedancer(this); + } +} diff --git a/Mage.Sets/src/mage/sets/darkascension/WerewolfRansacker.java b/Mage.Sets/src/mage/sets/darkascension/WerewolfRansacker.java new file mode 100644 index 00000000000..3e04acfd9d7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/WerewolfRansacker.java @@ -0,0 +1,77 @@ +/* + * 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.TwoOrMoreSpellsWereCastLastTurnCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.keyword.TransformAbility; +import mage.cards.CardImpl; + +/** + * + * @author BetaSteward + */ +public class WerewolfRansacker extends CardImpl { + + public WerewolfRansacker(UUID ownerId) { + super(ownerId, 81, "Werewolf Ransacker", Rarity.UNCOMMON, 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(5); + this.toughness = new MageInt(4); + + // Whenever this creature transforms into Werewolf Ransacker, you may destroy target artifact. If that artifact is put into a graveyard this way, Werewolf Ransacker deals 3 damage to that artifact's controller. + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Werewolf Ransacker. + 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 WerewolfRansacker(final WerewolfRansacker card) { + super(card); + } + + @Override + public WerewolfRansacker copy() { + return new WerewolfRansacker(this); + } +} + diff --git a/Mage.Sets/src/mage/sets/darkascension/WolfbittenCaptive.java b/Mage.Sets/src/mage/sets/darkascension/WolfbittenCaptive.java new file mode 100644 index 00000000000..303ddd98e1f --- /dev/null +++ b/Mage.Sets/src/mage/sets/darkascension/WolfbittenCaptive.java @@ -0,0 +1,83 @@ +/* + * 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.ActivateOncePerTurnActivatedAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.common.NoSpellsWereCastLastTurnCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continious.BoostSourceEffect; +import mage.abilities.keyword.TransformAbility; +import mage.cards.CardImpl; + +/** + * + * @author Loki + */ +public class WolfbittenCaptive extends CardImpl { + + public WolfbittenCaptive(UUID ownerId) { + super(ownerId, 133, "Wolfbitten Captive", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{G}"); + this.expansionSetCode = "DKA"; + this.subtype.add("Human"); + this.subtype.add("Werewolf"); + + this.color.setGreen(true); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + this.canTransform = true; + this.secondSideCard = new KrallenhordeKiller(ownerId); + + // {1}{G}: Wolfbitten Captive gets +2/+2 until end of turn. Activate this ability only once each turn. + this.addAbility(new ActivateOncePerTurnActivatedAbility(Constants.Zone.BATTLEFIELD, new BoostSourceEffect(2, 2, Constants.Duration.EndOfTurn), new ManaCostsImpl("{1}{G}"))); + + // At the beginning of each upkeep, if no spells were cast last turn, transform Wolfbitten Captive. + 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 WolfbittenCaptive(final WolfbittenCaptive card) { + super(card); + } + + @Override + public WolfbittenCaptive copy() { + return new WolfbittenCaptive(this); + } +} diff --git a/Mage.Sets/src/mage/sets/innistrad/BackFromTheBrink.java b/Mage.Sets/src/mage/sets/innistrad/BackFromTheBrink.java index af2c366afb8..5738cbd5271 100644 --- a/Mage.Sets/src/mage/sets/innistrad/BackFromTheBrink.java +++ b/Mage.Sets/src/mage/sets/innistrad/BackFromTheBrink.java @@ -122,7 +122,7 @@ class BackFromTheBrinkCost extends CostImpl { @Override public boolean canPay(UUID sourceId, UUID controllerId, Game game) { - return targets.canChoose(controllerId, controllerId, game); + return targets.canChoose(controllerId, game); } @Override diff --git a/Mage.Sets/src/mage/sets/innistrad/CivilizedScholar.java b/Mage.Sets/src/mage/sets/innistrad/CivilizedScholar.java index 96e03c4944a..7f78f666f0c 100644 --- a/Mage.Sets/src/mage/sets/innistrad/CivilizedScholar.java +++ b/Mage.Sets/src/mage/sets/innistrad/CivilizedScholar.java @@ -44,6 +44,8 @@ import mage.players.Player; import mage.target.common.TargetDiscard; import java.util.UUID; +import mage.game.events.GameEvent; +import mage.watchers.WatcherImpl; /** * @author nantuko @@ -67,7 +69,7 @@ public class CivilizedScholar extends CardImpl { this.addAbility(new SimpleActivatedAbility(Constants.Zone.BATTLEFIELD, new CivilizedScholarEffect(), new TapSourceCost())); this.addAbility(new TransformAbility()); -// this.addWatcher(new HomicidalBrute.HomicidalBruteWatcher()); + this.addWatcher(new HomicidalBruteWatcher()); } public CivilizedScholar(final CivilizedScholar card) { @@ -80,6 +82,31 @@ public class CivilizedScholar extends CardImpl { } } +class HomicidalBruteWatcher extends WatcherImpl { + + public HomicidalBruteWatcher() { + super("HomicidalBruteAttacked", Constants.WatcherScope.CARD); + } + + public HomicidalBruteWatcher(final HomicidalBruteWatcher watcher) { + super(watcher); + } + + @Override + public HomicidalBruteWatcher copy() { + return new HomicidalBruteWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + if (condition == true) + return; + if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED && event.getSourceId().equals(sourceId)) { + condition = true; + } + } +} + class CivilizedScholarEffect extends OneShotEffect { public CivilizedScholarEffect() { diff --git a/Mage.Sets/src/mage/sets/innistrad/CurseOfOblivion.java b/Mage.Sets/src/mage/sets/innistrad/CurseOfOblivion.java index 9fb3d1870af..7890bc366e2 100644 --- a/Mage.Sets/src/mage/sets/innistrad/CurseOfOblivion.java +++ b/Mage.Sets/src/mage/sets/innistrad/CurseOfOblivion.java @@ -99,7 +99,7 @@ class CurseOfOblivionAbility extends TriggeredAbilityImpl implements VariableCost Player player = game.getPlayer(controllerId); while (true) { target.clearChosen(); - if (target.choose(Outcome.Exile, controllerId, sourceId, game)) { + if (target.canChoose(controllerId, game) && target.choose(Outcome.Exile, controllerId, sourceId, game)) { Card card = player.getGraveyard().get(target.getFirstTarget(), game); if (card != null) { player.getGraveyard().remove(card); diff --git a/Mage.Sets/src/mage/sets/innistrad/HomicidalBrute.java b/Mage.Sets/src/mage/sets/innistrad/HomicidalBrute.java index c98c80d526e..240a073df1f 100644 --- a/Mage.Sets/src/mage/sets/innistrad/HomicidalBrute.java +++ b/Mage.Sets/src/mage/sets/innistrad/HomicidalBrute.java @@ -65,7 +65,6 @@ public class HomicidalBrute extends CardImpl { // At the beginning of your end step, if Homicidal Brute didn't attack this turn, tap Homicidal Brute, then transform it. this.addAbility(new HomicidalBruteTriggeredAbility()); - this.addWatcher(new HomicidalBruteWatcher()); } public HomicidalBrute(final HomicidalBrute card) { @@ -79,31 +78,6 @@ public class HomicidalBrute extends CardImpl { } -class HomicidalBruteWatcher extends WatcherImpl { - - public HomicidalBruteWatcher() { - super("HomicidalBruteAttacked", WatcherScope.CARD); - } - - public HomicidalBruteWatcher(final HomicidalBruteWatcher watcher) { - super(watcher); - } - - @Override - public HomicidalBruteWatcher copy() { - return new HomicidalBruteWatcher(this); - } - - @Override - public void watch(GameEvent event, Game game) { - if (condition == true) - return; - if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED && event.getSourceId().equals(sourceId)) { - condition = true; - } - } -} - class HomicidalBruteTriggeredAbility extends TriggeredAbilityImpl { public HomicidalBruteTriggeredAbility() { @@ -124,7 +98,7 @@ class HomicidalBruteTriggeredAbility extends TriggeredAbilityImpl { return false; } -// private Choice createChoice(CardsImpl pile1, CardsImpl cards, Game game) { -// Choice choice = new ChoiceImpl(true); -// choice.setMessage("Select a pile of permanents to sacrifice:"); -// StringBuilder sb = new StringBuilder("Pile 1: "); -// for (UUID cardId : pile1) { -// Card card = pile1.get(cardId, game); -// if (card != null) { -// sb.append(card.getName()).append("; "); -// } -// } -// sb.delete(sb.length() - 2, sb.length()); -// choice.getChoices().add(sb.toString()); -// sb = new StringBuilder("Pile 2: "); -// for (UUID cardId : cards) { -// Card card = cards.get(cardId, game); -// if (card != null) { -// sb.append(card.getName()).append("; "); -// } -// } -// sb.delete(sb.length() - 2, sb.length()); -// choice.getChoices().add(sb.toString()); -// return choice; -// } - private void sacrificePermanents(List pile, Game game, Ability source) { for (Permanent permanent : pile) { if (permanent != null) { diff --git a/Mage.Sets/src/mage/sets/magic2011/NecroticPlague.java b/Mage.Sets/src/mage/sets/magic2011/NecroticPlague.java index 0625c1e11bc..0739aac6d09 100644 --- a/Mage.Sets/src/mage/sets/magic2011/NecroticPlague.java +++ b/Mage.Sets/src/mage/sets/magic2011/NecroticPlague.java @@ -42,6 +42,7 @@ import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.common.DiesTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.SacrificeSourceEffect; @@ -73,7 +74,7 @@ public class NecroticPlague extends CardImpl { this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new NecroticPlagueEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new NecroticPlagueEffect(this.objectId))); } @@ -81,21 +82,44 @@ public class NecroticPlague extends CardImpl { super(card); } + @Override + public void assignNewId() { + super.assignNewId(); + updateSource(); + } + @Override public NecroticPlague copy() { return new NecroticPlague(this); } + + private void updateSource() { + for (Ability ability: abilities) { + for (Effect effect: ability.getEffects()) { + if (effect instanceof NecroticPlagueEffect) { + ((NecroticPlagueEffect)effect).updateSource(objectId); + } + } + } + } } class NecroticPlagueEffect extends ContinuousEffectImpl { - public NecroticPlagueEffect() { + private Ability ability1; + private Ability ability2; + + public NecroticPlagueEffect(UUID cardId) { super(Duration.WhileOnBattlefield, Outcome.Detriment); + ability1 = new OnEventTriggeredAbility(EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", new SacrificeSourceEffect()); + ability2 = new DiesTriggeredAbility(new NecroticPlagueEffect2(cardId), false); staticText = "Enchanted creature has \"At the beginning of your upkeep, sacrifice this creature.\" When enchanted creature is put into a graveyard, its controller chooses target creature one of his or her opponents controls. Return {this} from its owner's graveyard to the battlefield attached to that creature."; } public NecroticPlagueEffect(final NecroticPlagueEffect effect) { super(effect); + this.ability1 = effect.ability1.copy(); + this.ability2 = effect.ability2.copy(); } @Override @@ -112,8 +136,8 @@ class NecroticPlagueEffect extends ContinuousEffectImpl { switch (layer) { case AbilityAddingRemovingEffects_6: if (sublayer == SubLayer.NA) { - creature.addAbility(new OnEventTriggeredAbility(EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", new SacrificeSourceEffect()), game); - creature.addAbility(new DiesTriggeredAbility(new NecroticPlagueEffect2(source.getSourceId()), false), game); + creature.addAbility(ability1, game); + creature.addAbility(ability2, game); } break; } @@ -123,6 +147,14 @@ class NecroticPlagueEffect extends ContinuousEffectImpl { return false; } + public void updateSource(UUID id) { + for (Effect effect: ability2.getEffects()) { + if (effect instanceof NecroticPlagueEffect2) { + ((NecroticPlagueEffect2)effect).updateSource(id); + } + } + } + @Override public boolean apply(Game game, Ability source) { return false; @@ -137,14 +169,14 @@ class NecroticPlagueEffect extends ContinuousEffectImpl { class NecroticPlagueEffect2 extends OneShotEffect { + private UUID cardId; + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); static { filter.setTargetController(TargetController.OPPONENT); } - protected UUID cardId; - public NecroticPlagueEffect2(UUID cardId) { super(Outcome.PutCardInPlay); this.cardId = cardId; @@ -177,6 +209,10 @@ class NecroticPlagueEffect2 extends OneShotEffect { return false; } + public void updateSource(UUID id) { + this.cardId = id; + } + @Override public NecroticPlagueEffect2 copy() { return new NecroticPlagueEffect2(this); diff --git a/Mage.Sets/src/mage/sets/morningtide/PreeminentCaptain.java b/Mage.Sets/src/mage/sets/morningtide/PreeminentCaptain.java index a057f63a378..0d621407c0c 100644 --- a/Mage.Sets/src/mage/sets/morningtide/PreeminentCaptain.java +++ b/Mage.Sets/src/mage/sets/morningtide/PreeminentCaptain.java @@ -96,7 +96,7 @@ class PreeminentCaptainEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); TargetCardInHand target = new TargetCardInHand(new FilterSoldierCard()); - if (target.choose(getOutcome(), player.getId(), source.getSourceId(), game)) { + if (target.canChoose(player.getId(), game) && target.choose(getOutcome(), player.getId(), source.getSourceId(), game)) { if (target.getTargets().size() > 0) { UUID cardId = target.getFirstTarget(); Card card = player.getHand().get(cardId, game); diff --git a/Mage.Sets/src/mage/sets/newphyrexia/MortisDogs.java b/Mage.Sets/src/mage/sets/newphyrexia/MortisDogs.java index 3ff00ffb326..73c1415cffb 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/MortisDogs.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/MortisDogs.java @@ -91,7 +91,7 @@ class MortisDogsEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(targetPointer.getFirst(source)); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (player != null) { + if (player != null && sourcePermanent != null) { player.loseLife(sourcePermanent.getPower().getValue(), game); return true; } diff --git a/Mage.Sets/src/mage/sets/urzassaga/AbyssalHorror.java b/Mage.Sets/src/mage/sets/urzassaga/AbyssalHorror.java new file mode 100644 index 00000000000..a5303668932 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/AbyssalHorror.java @@ -0,0 +1,71 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.urzassaga; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DiscardTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.target.TargetPlayer; + +/** + * + * @author Backfir3 + */ +public class AbyssalHorror extends CardImpl { + + public AbyssalHorror (UUID ownerId) { + super(ownerId, 115, "Abyssal Horror", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); + this.expansionSetCode = "USG"; + this.subtype.add("Horror"); + this.color.setBlack(true); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + this.addAbility(FlyingAbility.getInstance()); + + Ability ability = new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(2)); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + public AbyssalHorror (final AbyssalHorror card) { + super(card); + } + + @Override + public AbyssalHorror copy() { + return new AbyssalHorror(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/ArgothianElder.java b/Mage.Sets/src/mage/sets/urzassaga/ArgothianElder.java new file mode 100644 index 00000000000..7041acabb22 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/ArgothianElder.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.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.UntapTargetEffect; +import mage.cards.CardImpl; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author Backfir3 + */ +public class ArgothianElder extends CardImpl { + + public ArgothianElder(UUID ownerId) { + super(ownerId, 233, "Argothian Elder", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{G}"); + this.expansionSetCode = "USG"; + this.subtype.add("Elf"); + this.subtype.add("Druid"); + this.color.setGreen(true); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new UntapTargetEffect(), new TapSourceCost()); + ability.addTarget(new TargetLandPermanent(2)); + this.addAbility(ability); + } + + public ArgothianElder(final ArgothianElder card) { + super(card); + } + + @Override + public ArgothianElder copy() { + return new ArgothianElder(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/ArgothianEnchantress.java b/Mage.Sets/src/mage/sets/urzassaga/ArgothianEnchantress.java new file mode 100644 index 00000000000..1e41a434552 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/ArgothianEnchantress.java @@ -0,0 +1,75 @@ +/* + * 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.MageInt; +import mage.abilities.common.SpellCastTriggeredAbility; +import mage.abilities.effects.common.DrawCardControllerEffect; +import mage.abilities.keyword.ShroudAbility; +import mage.cards.CardImpl; +import mage.filter.FilterCard; + +/** + * + * @author Backfir3 + */ +public class ArgothianEnchantress extends CardImpl { + + private static final FilterCard filter = new FilterCard("an Enchantment spell"); + + static { + filter.getCardType().add(CardType.ENCHANTMENT); + } + + public ArgothianEnchantress(UUID ownerId) { + super(ownerId, 234, "Argothian Enchantress", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{G}"); + this.expansionSetCode = "USG"; + this.subtype.add("Human"); + this.subtype.add("Druid"); + + this.color.setGreen(true); + this.power = new MageInt(0); + this.toughness = new MageInt(1); + + this.addAbility(ShroudAbility.getInstance()); + // Whenever you cast an Enchantment spell, you draw a card. + this.addAbility(new SpellCastTriggeredAbility(new DrawCardControllerEffect(1), filter, false)); + } + + public ArgothianEnchantress(final ArgothianEnchantress card) { + super(card); + } + + @Override + public ArgothianEnchantress copy() { + return new ArgothianEnchantress(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/Bedlam.java b/Mage.Sets/src/mage/sets/urzassaga/Bedlam.java new file mode 100644 index 00000000000..b62cd840f3c --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/Bedlam.java @@ -0,0 +1,93 @@ +/* + * 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.abilities.Ability; +import mage.abilities.effects.RestrictionEffect; +import mage.cards.CardImpl; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author Backfir3 + */ +public class Bedlam extends CardImpl { + + public Bedlam (UUID ownerId) { + super(ownerId, 175, "Bedlam", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}{R}"); + this.expansionSetCode = "USG"; + this.color.setRed(true); + this.getSpellAbility().addEffect(new BedlamEffect()); + } + + public Bedlam (final Bedlam card) { + super(card); + } + + @Override + public Bedlam copy() { + return new Bedlam(this); + } + +} + +class BedlamEffect extends RestrictionEffect { + BedlamEffect() { + super(Constants.Duration.WhileOnBattlefield); + staticText = "Creatures can't block"; + } + + BedlamEffect(final BedlamEffect effect) { + super(effect); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + if (!permanent.getCardType().contains(CardType.CREATURE)) { + return true; + } + return false; + } + + @Override + public BedlamEffect copy() { + return new BedlamEffect(this); + } + + @Override + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + return false; + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/urzassaga/Dromosaur.java b/Mage.Sets/src/mage/sets/urzassaga/Dromosaur.java new file mode 100644 index 00000000000..92f5386532c --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/Dromosaur.java @@ -0,0 +1,66 @@ +/* + * 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.MageInt; +import mage.abilities.common.BlocksOrBecomesBlockedTriggeredAbility; +import mage.abilities.effects.common.continious.BoostSourceEffect; +import mage.cards.CardImpl; + +/** + * + * @author Backfir3 + */ +public class Dromosaur extends CardImpl { + + public Dromosaur(UUID ownerId) { + super(ownerId, 182, "Dromosaur", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{R}"); + this.expansionSetCode = "USG"; + this.subtype.add("Lizard"); + + this.color.setRed(true); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Whenever Dromosaur blocks or becomes blocked by a creature, it gets +2/-2 until end of turn. + this.addAbility(new BlocksOrBecomesBlockedTriggeredAbility(new BoostSourceEffect(2, -2, Duration.EndOfTurn), false)); + } + + public Dromosaur(final Dromosaur card) { + super(card); + } + + @Override + public Dromosaur copy() { + return new Dromosaur(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/urzassaga/EasternPaladin.java b/Mage.Sets/src/mage/sets/urzassaga/EasternPaladin.java new file mode 100644 index 00000000000..2af61058269 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/EasternPaladin.java @@ -0,0 +1,84 @@ +/* +* 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.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.filter.Filter; +import mage.filter.common.FilterCreaturePermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author Backfir3 + */ +public class EasternPaladin extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("green creature"); + + static { + filter.getColor().setGreen(true); + filter.setUseColor(true); + filter.setScopeColor(Filter.ComparisonScope.Any); + } + + public EasternPaladin(UUID ownerId) { + super(ownerId, 133, "Eastern Paladin", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); + this.expansionSetCode = "USG"; + this.subtype.add("Zombie"); + this.subtype.add("Knight"); + this.color.setBlack(true); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new ManaCostsImpl("{B}{B}")); + ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + public EasternPaladin(final EasternPaladin card) { + super(card); + } + + @Override + public EasternPaladin copy() { + return new EasternPaladin(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/Island1.java b/Mage.Sets/src/mage/sets/urzassaga/Island1.java new file mode 100644 index 00000000000..32686b51430 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/Island1.java @@ -0,0 +1,53 @@ +/* +* 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; + +/** + * + * @author Backfir3 + */ +public class Island1 extends mage.cards.basiclands.Island { + + public Island1(UUID ownerId) { + super(ownerId, 335); + this.expansionSetCode = "USG"; + } + + public Island1(final Island1 card) { + super(card); + } + + @Override + public Island1 copy() { + return new Island1(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/Island2.java b/Mage.Sets/src/mage/sets/urzassaga/Island2.java new file mode 100644 index 00000000000..4f2d9a859fc --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/Island2.java @@ -0,0 +1,53 @@ +/* +* 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; + +/** + * + * @author Backfir3 + */ +public class Island2 extends mage.cards.basiclands.Island { + + public Island2(UUID ownerId) { + super(ownerId, 336); + this.expansionSetCode = "USG"; + } + + public Island2(final Island2 card) { + super(card); + } + + @Override + public Island2 copy() { + return new Island2(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/Island3.java b/Mage.Sets/src/mage/sets/urzassaga/Island3.java new file mode 100644 index 00000000000..070e4e7b428 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/Island3.java @@ -0,0 +1,53 @@ +/* +* 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; + +/** + * + * @author Backfir3 + */ +public class Island3 extends mage.cards.basiclands.Island { + + public Island3(UUID ownerId) { + super(ownerId, 337); + this.expansionSetCode = "USG"; + } + + public Island3(final Island3 card) { + super(card); + } + + @Override + public Island3 copy() { + return new Island3(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/Island4.java b/Mage.Sets/src/mage/sets/urzassaga/Island4.java new file mode 100644 index 00000000000..5a373c6cec5 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/Island4.java @@ -0,0 +1,53 @@ +/* +* 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; + +/** + * + * @author Backfir3 + */ +public class Island4 extends mage.cards.basiclands.Island { + + public Island4(UUID ownerId) { + super(ownerId, 338); + this.expansionSetCode = "USG"; + } + + public Island4(final Island4 card) { + super(card); + } + + @Override + public Island4 copy() { + return new Island4(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/Mountain1.java b/Mage.Sets/src/mage/sets/urzassaga/Mountain1.java new file mode 100644 index 00000000000..d4461e80262 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/Mountain1.java @@ -0,0 +1,53 @@ +/* +* 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; + +/** + * + * @author Backfir3 + */ +public class Mountain1 extends mage.cards.basiclands.Mountain { + + public Mountain1(UUID ownerId) { + super(ownerId, 343); + this.expansionSetCode = "USG"; + } + + public Mountain1(final Mountain1 card) { + super(card); + } + + @Override + public Mountain1 copy() { + return new Mountain1(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/Mountain2.java b/Mage.Sets/src/mage/sets/urzassaga/Mountain2.java new file mode 100644 index 00000000000..0282c62b77c --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/Mountain2.java @@ -0,0 +1,53 @@ +/* +* 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; + +/** + * + * @author Backfir3 + */ +public class Mountain2 extends mage.cards.basiclands.Mountain { + + public Mountain2(UUID ownerId) { + super(ownerId, 344); + this.expansionSetCode = "USG"; + } + + public Mountain2(final Mountain2 card) { + super(card); + } + + @Override + public Mountain2 copy() { + return new Mountain2(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/Mountain3.java b/Mage.Sets/src/mage/sets/urzassaga/Mountain3.java new file mode 100644 index 00000000000..9b77f7c7545 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/Mountain3.java @@ -0,0 +1,53 @@ +/* +* 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; + +/** + * + * @author Backfir3 + */ +public class Mountain3 extends mage.cards.basiclands.Mountain { + + public Mountain3(UUID ownerId) { + super(ownerId, 345); + this.expansionSetCode = "USG"; + } + + public Mountain3(final Mountain3 card) { + super(card); + } + + @Override + public Mountain3 copy() { + return new Mountain3(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/Mountain4.java b/Mage.Sets/src/mage/sets/urzassaga/Mountain4.java new file mode 100644 index 00000000000..06fdd247ddf --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/Mountain4.java @@ -0,0 +1,53 @@ +/* +* 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; + +/** + * + * @author Backfir3 + */ +public class Mountain4 extends mage.cards.basiclands.Mountain { + + public Mountain4(UUID ownerId) { + super(ownerId, 346); + this.expansionSetCode = "USG"; + } + + public Mountain4(final Mountain4 card) { + super(card); + } + + @Override + public Mountain4 copy() { + return new Mountain4(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/Plains1.java b/Mage.Sets/src/mage/sets/urzassaga/Plains1.java new file mode 100644 index 00000000000..4c8216b8484 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/Plains1.java @@ -0,0 +1,53 @@ +/* +* 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; + +/** + * + * @author Backfir3 + */ +public class Plains1 extends mage.cards.basiclands.Plains { + + public Plains1(UUID ownerId) { + super(ownerId, 331); + this.expansionSetCode = "USG"; + } + + public Plains1(final Plains1 card) { + super(card); + } + + @Override + public Plains1 copy() { + return new Plains1(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/Plains2.java b/Mage.Sets/src/mage/sets/urzassaga/Plains2.java new file mode 100644 index 00000000000..b2bc5684141 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/Plains2.java @@ -0,0 +1,53 @@ +/* +* 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; + +/** + * + * @author Backfir3 + */ +public class Plains2 extends mage.cards.basiclands.Plains { + + public Plains2(UUID ownerId) { + super(ownerId, 332); + this.expansionSetCode = "USG"; + } + + public Plains2(final Plains2 card) { + super(card); + } + + @Override + public Plains2 copy() { + return new Plains2(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/Plains3.java b/Mage.Sets/src/mage/sets/urzassaga/Plains3.java new file mode 100644 index 00000000000..a3856c282b7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/Plains3.java @@ -0,0 +1,53 @@ +/* +* 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; + +/** + * + * @author Backfir3 + */ +public class Plains3 extends mage.cards.basiclands.Plains { + + public Plains3(UUID ownerId) { + super(ownerId, 333); + this.expansionSetCode = "USG"; + } + + public Plains3(final Plains3 card) { + super(card); + } + + @Override + public Plains3 copy() { + return new Plains3(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/Plains4.java b/Mage.Sets/src/mage/sets/urzassaga/Plains4.java new file mode 100644 index 00000000000..b26e5031d21 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/Plains4.java @@ -0,0 +1,53 @@ +/* +* 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; + +/** + * + * @author Backfir3 + */ +public class Plains4 extends mage.cards.basiclands.Plains { + + public Plains4(UUID ownerId) { + super(ownerId, 334); + this.expansionSetCode = "USG"; + } + + public Plains4(final Plains4 card) { + super(card); + } + + @Override + public Plains4 copy() { + return new Plains4(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/PriestOfGix.java b/Mage.Sets/src/mage/sets/urzassaga/PriestOfGix.java new file mode 100644 index 00000000000..a73f2d0ae84 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/PriestOfGix.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.MageInt; +import mage.Mana; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.BasicManaEffect; +import mage.cards.CardImpl; + +/** + * + * @author Backfir3 + */ +public class PriestOfGix extends CardImpl { + + public PriestOfGix(UUID ownerId) { + super(ownerId, 150, "Priest of Gix", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.expansionSetCode = "USG"; + this.subtype.add("Human"); + this.subtype.add("Cleric"); + this.subtype.add("Minion"); + + this.color.setBlack(true); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + this.addAbility(new EntersBattlefieldTriggeredAbility(new BasicManaEffect(Mana.BlackMana(3)))); + } + + public PriestOfGix(final PriestOfGix card) { + super(card); + } + + @Override + public PriestOfGix copy() { + return new PriestOfGix(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/PriestOfTitania.java b/Mage.Sets/src/mage/sets/urzassaga/PriestOfTitania.java new file mode 100644 index 00000000000..3ed3301ffaf --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/PriestOfTitania.java @@ -0,0 +1,73 @@ +/* + * 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.MageInt; +import mage.Mana; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.mana.DynamicManaAbility; +import mage.cards.CardImpl; +import mage.filter.common.FilterCreaturePermanent; + +/** + * + * @author BetaSteward_at_googlemail.com, North + */ +public class PriestOfTitania extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Elf creatures"); + + static { + filter.getSubtype().add("Elf"); + } + + public PriestOfTitania(UUID ownerId) { + super(ownerId, 270, "Priest of Titania", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{G}"); + this.expansionSetCode = "USG"; + this.subtype.add("Elf"); + this.subtype.add("Druid"); + this.color.setGreen(true); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + this.addAbility(new DynamicManaAbility(Mana.GreenMana, new PermanentsOnBattlefieldCount(filter))); + } + + public PriestOfTitania(final PriestOfTitania card) { + super(card); + } + + @Override + public PriestOfTitania copy() { + return new PriestOfTitania(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/RainOfSalt.java b/Mage.Sets/src/mage/sets/urzassaga/RainOfSalt.java new file mode 100644 index 00000000000..5a05a246def --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/RainOfSalt.java @@ -0,0 +1,69 @@ +/* +* 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.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.filter.Filter; +import mage.filter.FilterPermanent; +import mage.target.TargetPermanent; + +/** + * + * @author Backfir3 + */ +public class RainOfSalt extends CardImpl { + + private final static FilterPermanent filter = new FilterPermanent("land"); + + static { + filter.getCardType().add(CardType.LAND); + filter.setScopeCardType(Filter.ComparisonScope.Any); + } + + public RainOfSalt(UUID ownerId) { + super(ownerId, 206, "Rain of Salt", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{4}{R}{R}"); + this.expansionSetCode = "USG"; + this.color.setRed(true); + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(2, filter)); + } + + public RainOfSalt(final RainOfSalt card) { + super(card); + } + + @Override + public RainOfSalt copy() { + return new RainOfSalt(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/Rescind.java b/Mage.Sets/src/mage/sets/urzassaga/Rescind.java new file mode 100644 index 00000000000..9e28ca5c572 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/Rescind.java @@ -0,0 +1,62 @@ +/* + * 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.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.keyword.CyclingAbility; +import mage.cards.CardImpl; +import mage.target.TargetPermanent; + +/** + * + * @author Backfir3 + */ +public class Rescind extends CardImpl { + + public Rescind(UUID ownerId) { + super(ownerId, 92, "Rescind", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{U}{U}"); + this.expansionSetCode = "USG"; + this.color.setBlue(true); + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent()); + this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}"))); + } + + public Rescind(final Rescind card) { + super(card); + } + + @Override + public Rescind copy() { + return new Rescind(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/WesternPaladin.java b/Mage.Sets/src/mage/sets/urzassaga/WesternPaladin.java index 62e8ab40eac..af601715a5a 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/WesternPaladin.java +++ b/Mage.Sets/src/mage/sets/urzassaga/WesternPaladin.java @@ -67,10 +67,10 @@ public class WesternPaladin extends CardImpl { this.power = new MageInt(3); this.toughness = new MageInt(3); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new ManaCostsImpl("{B}{B}")); - ability.addCost(new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent(filter)); - this.addAbility(ability); - } + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } public WesternPaladin(final WesternPaladin card) { super(card); diff --git a/Mage.Sets/src/mage/sets/zendikar/CobraTrap.java b/Mage.Sets/src/mage/sets/zendikar/CobraTrap.java index 888cb91aade..d2964df2625 100644 --- a/Mage.Sets/src/mage/sets/zendikar/CobraTrap.java +++ b/Mage.Sets/src/mage/sets/zendikar/CobraTrap.java @@ -32,16 +32,19 @@ import mage.Constants.CardType; import mage.Constants.ColoredManaSymbol; import mage.Constants.Rarity; import mage.Constants.WatcherScope; +import mage.Constants.Zone; import mage.abilities.Ability; import mage.abilities.costs.AlternativeCostImpl; import mage.abilities.costs.mana.ColoredManaCost; import mage.abilities.effects.common.CreateTokenEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; import mage.game.permanent.token.SnakeToken; +import mage.game.stack.StackObject; +import mage.players.Player; import mage.watchers.Watcher; import mage.watchers.WatcherImpl; @@ -96,11 +99,17 @@ class CobraTrapWatcher extends WatcherImpl { if (condition == true) { // no need to check - condition has already occured return; } - if (event.getType() == EventType.DESTROYED_PERMANENT - && !game.getPlayer(controllerId).getGraveyard().get(event.getTargetId(), game).getCardType().contains(CardType.CREATURE) - && game.getStack().getStackObject(event.getSourceId()) != null - && game.getOpponents(controllerId).contains(game.getStack().getStackObject(event.getSourceId()).getControllerId())) { - condition = true; + Player player = game.getPlayer(controllerId); + if (player != null && event.getType() == EventType.DESTROYED_PERMANENT) { + Permanent perm = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); + if (perm != null && !perm.getCardType().contains(CardType.CREATURE)) { + if (game.getStack().size() > 0) { + StackObject spell = game.getStack().getStackObject(event.getSourceId()); + if (spell != null && game.getOpponents(controllerId).contains(spell.getControllerId())) { + condition = true; + } + } + } } } } diff --git a/Mage.Tests/plugins/mage-player-ai.jar b/Mage.Tests/plugins/mage-player-ai.jar index 387174114dd..2041685d8e8 100644 Binary files a/Mage.Tests/plugins/mage-player-ai.jar and b/Mage.Tests/plugins/mage-player-ai.jar differ diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestCobraTrap.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestCobraTrap.java new file mode 100644 index 00000000000..20da51773ed --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestCobraTrap.java @@ -0,0 +1,50 @@ +package org.mage.test.cards; + +import mage.Constants; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author BetaSteward + */ +public class TestCobraTrap extends CardTestPlayerBase { + + @Test + public void testCard() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Forest", 2); + addCard(Constants.Zone.HAND, playerA, "Cobra Trap"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Mountain", 3); + addCard(Constants.Zone.HAND, playerB, "Stone Rain"); + + castSpell(2, Constants.PhaseStep.PRECOMBAT_MAIN, playerB, "Stone Rain", "Forest"); + castSpell(2, Constants.PhaseStep.POSTCOMBAT_MAIN, playerA, "Cobra Trap"); + + setStopAt(2, Constants.PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Forest", 1); + assertPermanentCount(playerA, "Snake", 4); + } + + @Test + public void testCardNegative() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Forest", 2); + addCard(Constants.Zone.HAND, playerA, "Cobra Trap"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Mountain", 3); + addCard(Constants.Zone.HAND, playerB, "Stone Rain"); + + castSpell(2, Constants.PhaseStep.POSTCOMBAT_MAIN, playerA, "Cobra Trap"); + + setStopAt(2, Constants.PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Forest", 2); + assertPermanentCount(playerA, "Snake", 0); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestCounterlash.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestCounterlash.java new file mode 100644 index 00000000000..98a3f6f4919 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestCounterlash.java @@ -0,0 +1,36 @@ +package org.mage.test.cards; + +import junit.framework.Assert; +import mage.Constants; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author BetaSteward + */ +public class TestCounterlash extends CardTestPlayerBase { + + @Test + public void testCard() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain"); + addCard(Constants.Zone.HAND, playerA, "Lightning Bolt"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Island", 6); + addCard(Constants.Zone.HAND, playerB, "Counterlash"); + addCard(Constants.Zone.HAND, playerB, "Beacon of Immortality"); + + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt"); + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerB, "Counterlash", "Lightning Bolt"); + + setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 40); + assertGraveyardCount(playerA, 1); + assertGraveyardCount(playerB, 1); + + } + + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestCurseOfThirst.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestCurseOfThirst.java new file mode 100644 index 00000000000..173eea2729f --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestCurseOfThirst.java @@ -0,0 +1,44 @@ +package org.mage.test.cards; + +import mage.Constants; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author BetaSteward + */ +public class TestCurseOfThirst extends CardTestPlayerBase { + + @Test + public void testCard1() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Swamp", 5); + addCard(Constants.Zone.HAND, playerA, "Curse of Thirst"); + + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Curse of Thirst", playerB); + + setStopAt(2, Constants.PhaseStep.DRAW); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 19); + } + + @Test + public void testCard2() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Swamp", 5); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Constants.Zone.HAND, playerA, "Curse of Thirst"); + addCard(Constants.Zone.HAND, playerA, "Curse of Bloodletting"); + + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Curse of Bloodletting", playerB); + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Curse of Thirst", playerB); + + setStopAt(2, Constants.PhaseStep.DRAW); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 16); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestFiendOfTheShadows.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestFiendOfTheShadows.java new file mode 100644 index 00000000000..0157ff0ba06 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestFiendOfTheShadows.java @@ -0,0 +1,76 @@ +package org.mage.test.cards; + +import mage.Constants; +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 TestFiendOfTheShadows extends CardTestPlayerBase { + + @Test + public void testCard() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "White Knight"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Fiend of the Shadows"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Mountain"); + addCard(Constants.Zone.HAND, playerB, "Lightning Bolt"); + + activateAbility(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice a human: Regenerate {this}. "); + castSpell(1, Constants.PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", "Fiend of the Shadows"); + + setStopAt(1, Constants.PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Fiend of the Shadows", 1); + assertPermanentCount(playerA, "White Knight", 0); + } + + @Test + public void testCardExile1() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Fiend of the Shadows"); + removeAllCardsFromHand(playerB); + addCard(Constants.Zone.HAND, playerB, "Swamp"); + + attack(1, playerA, "Fiend of the Shadows"); + playLand(1, Constants.PhaseStep.POSTCOMBAT_MAIN, playerA, "Swamp"); + + setStopAt(1, Constants.PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 17); + assertPermanentCount(playerA, "Fiend of the Shadows", 1); + assertPermanentCount(playerA, "Swamp", 1); + assertHandCount(playerB, 0); + } + + @Test + public void testCardExile2() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Fiend of the Shadows"); + removeAllCardsFromHand(playerB); + addCard(Constants.Zone.HAND, playerB, "Lightning Bolt"); + + attack(1, playerA, "Fiend of the Shadows"); + castSpell(1, Constants.PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + + setStopAt(1, Constants.PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 14); + assertPermanentCount(playerA, "Fiend of the Shadows", 1); + assertGraveyardCount(playerA, "Lightning Bolt", 0); + assertHandCount(playerB, 0); + assertGraveyardCount(playerB, "Lightning Bolt", 1); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestHomicidalBrute.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestHomicidalBrute.java new file mode 100644 index 00000000000..59d26e14195 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestHomicidalBrute.java @@ -0,0 +1,86 @@ +package org.mage.test.cards; + +import mage.Constants; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author BetaSteward + */ +public class TestHomicidalBrute extends CardTestPlayerBase { + + @Test + public void testCard() { + removeAllCardsFromHand(playerA); + removeAllCardsFromLibrary(playerA); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Civilized Scholar"); + addCard(Constants.Zone.LIBRARY, playerA, "Sejiri Merfolk"); + + activateAbility(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Draw a card, then discard a card. "); + setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Civilized Scholar", 0); + assertPermanentCount(playerA, "Homicidal Brute", 1); + assertTapped("Homicidal Brute", false); + } + + @Test + public void testCardNegative() { + removeAllCardsFromHand(playerA); + removeAllCardsFromLibrary(playerA); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Civilized Scholar"); + addCard(Constants.Zone.LIBRARY, playerA, "Lightning Bolt"); + + activateAbility(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Draw a card, then discard a card. "); + setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Civilized Scholar", 1); + assertTapped("Civilized Scholar", true); + assertPermanentCount(playerA, "Homicidal Brute", 0); + } + + @Test + public void testCardTransform() { + removeAllCardsFromHand(playerA); + removeAllCardsFromLibrary(playerA); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Civilized Scholar"); + addCard(Constants.Zone.LIBRARY, playerA, "Sejiri Merfolk"); + + activateAbility(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Draw a card, then discard a card. "); + setStopAt(2, Constants.PhaseStep.UPKEEP); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Civilized Scholar", 1); + assertTapped("Civilized Scholar", true); + assertPermanentCount(playerA, "Homicidal Brute", 0); + } + + @Test + public void testCardNotTransform() { + removeAllCardsFromHand(playerA); + removeAllCardsFromLibrary(playerA); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Civilized Scholar"); + addCard(Constants.Zone.LIBRARY, playerA, "Sejiri Merfolk", 2); + + activateAbility(3, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Draw a card, then discard a card. "); + attack(3, playerA, "Homicidal Brute"); + setStopAt(4, Constants.PhaseStep.UPKEEP); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 15); + assertPermanentCount(playerA, "Civilized Scholar", 0); + assertPermanentCount(playerA, "Homicidal Brute", 1); + assertTapped("Homicidal Brute", true); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestHuntmasterOfTheFells.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestHuntmasterOfTheFells.java new file mode 100644 index 00000000000..4ed3d34e1ca --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestHuntmasterOfTheFells.java @@ -0,0 +1,32 @@ +package org.mage.test.cards; + +import mage.Constants; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author BetaSteward + */ +public class TestHuntmasterOfTheFells extends CardTestPlayerBase { + + @Test + public void testCard() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Forest", 3); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain"); + addCard(Constants.Zone.HAND, playerA, "Huntmaster of the Fells"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Ornithopter"); + + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Huntmaster of the Fells"); + setStopAt(3, Constants.PhaseStep.DRAW); + execute(); + + assertLife(playerA, 22); + assertLife(playerB, 18); + assertPermanentCount(playerA, "Wolf", 1); + assertPermanentCount(playerA, "Huntmaster of the Fells", 0); + assertPermanentCount(playerA, "Ravager of the Fells", 1); + assertPermanentCount(playerB, "Ornithopter", 0); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestNecroticPlague.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestNecroticPlague.java new file mode 100644 index 00000000000..cd98225d21f --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestNecroticPlague.java @@ -0,0 +1,59 @@ +package org.mage.test.cards; + +import mage.Constants; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * also tests triggered abilities that switch from one permanent to another + * + * @author BetaSteward + * + */ +public class TestNecroticPlague extends CardTestPlayerBase { + + @Test + public void testCard1() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Swamp", 4); + addCard(Constants.Zone.HAND, playerA, "Necrotic Plague"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Sejiri Merfolk"); + + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Necrotic Plague", "Sejiri Merfolk"); + + setStopAt(2, Constants.PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerB, "Sejiri Merfolk", 0); + assertGraveyardCount(playerA, "Necrotic Plague", 1); + assertGraveyardCount(playerB, 1); + assertGraveyardCount(playerB, "Sejiri Merfolk", 1); + } + + @Test + public void testCard2() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Swamp", 4); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Goblin Deathraiders"); + addCard(Constants.Zone.HAND, playerA, "Necrotic Plague"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Sejiri Merfolk"); + + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Necrotic Plague", "Sejiri Merfolk"); + + setStopAt(3, Constants.PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Goblin Deathraiders", 0); + assertPermanentCount(playerB, "Sejiri Merfolk", 0); + assertGraveyardCount(playerA, 2); + assertGraveyardCount(playerA, "Necrotic Plague", 1); + assertGraveyardCount(playerA, "Goblin Deathraiders", 1); + assertGraveyardCount(playerB, 1); + assertGraveyardCount(playerB, "Sejiri Merfolk", 1); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestSorinLordOfInnistrad.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestSorinLordOfInnistrad.java new file mode 100644 index 00000000000..c99b258adf7 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestSorinLordOfInnistrad.java @@ -0,0 +1,71 @@ +package org.mage.test.cards; + +import mage.Constants; +import mage.counters.CounterType; +import mage.filter.Filter; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * also tests emblems + * + * @author BetaSteward + */ +public class TestSorinLordOfInnistrad extends CardTestPlayerBase { + + @Test + public void testCard() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Sorin, Lord of Innistrad"); + + activateAbility(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "+1: put a a 1/1 black Vampire creature token with lifelink onto the battlefield. "); + setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Sorin, Lord of Innistrad", 1); + assertPermanentCount(playerA, "Vampire", 1); + + } + + @Test + public void testCard2() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Sorin, Lord of Innistrad"); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Sejiri Merfolk"); + + addCounters(1, Constants.PhaseStep.UPKEEP, playerA, "Sorin, Lord of Innistrad", CounterType.LOYALTY, 1); + activateAbility(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "-2: You get an emblem with \"[creature you control get +1/+0. ]\". "); + activateAbility(3, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "-2: You get an emblem with \"[creature you control get +1/+0. ]\". "); + setStopAt(3, Constants.PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Sorin, Lord of Innistrad", 0); + assertPermanentCount(playerA, "Sejiri Merfolk", 1); + assertPowerToughness(playerA, "Sejiri Merfolk", 4, 1, Filter.ComparisonScope.Any); + } + + @Test + public void testCard3() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Sorin, Lord of Innistrad"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Craw Wurm"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Angel of Mercy"); + + addCounters(1, Constants.PhaseStep.UPKEEP, playerA, "Sorin, Lord of Innistrad", CounterType.LOYALTY, 3); + activateAbility(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "-6: ", "Craw Wurm^Angel of Mercy"); + setStopAt(1, Constants.PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 23); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Sorin, Lord of Innistrad", 0); + assertPermanentCount(playerA, "Craw Wurm", 1); + assertPermanentCount(playerB, "Craw Wurm", 0); + assertPermanentCount(playerA, "Angel of Mercy", 1); + assertPermanentCount(playerB, "Angel of Mercy", 0); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestTurnToFrog.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestTurnToFrog.java new file mode 100644 index 00000000000..77f0e3906d2 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestTurnToFrog.java @@ -0,0 +1,61 @@ +package org.mage.test.cards; + +import mage.Constants; +import mage.counters.CounterType; +import mage.filter.Filter; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * also tests triggered abilities that are added to permanents + * + * @author BetaSteward + */ +public class TestTurnToFrog extends CardTestPlayerBase { + + @Test + public void testCard() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain", 3); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Forest", 1); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Raging Ravine"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Island", 2); + addCard(Constants.Zone.HAND, playerB, "Turn to Frog"); + + activateAbility(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "{2}{R}{G}: until end of turn {this} becomes a 3/3 red and green Elemental creature with \"Whenever this creature attacks, put a +1/+1 counter on it.\" that's still a land. "); + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerB, "Turn to Frog", "Raging Ravine"); + attack(1, playerA, "Raging Ravine"); + + setStopAt(1, Constants.PhaseStep.END_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 19); + assertPowerToughness(playerA, "Raging Ravine", 1, 1, Filter.ComparisonScope.Any); + assertCounterCount("Raging Ravine", CounterType.P1P1, 0); + } + + @Test + public void testCard2() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain", 3); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Forest", 1); + addCard(Constants.Zone.BATTLEFIELD, playerA, "Raging Ravine"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Island", 2); + addCard(Constants.Zone.HAND, playerB, "Turn to Frog"); + + activateAbility(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "{2}{R}{G}: until end of turn {this} becomes a 3/3 red and green Elemental creature with \"Whenever this creature attacks, put a +1/+1 counter on it.\" that's still a land. "); + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerB, "Turn to Frog", "Raging Ravine"); + + activateAbility(3, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "{2}{R}{G}: until end of turn {this} becomes a 3/3 red and green Elemental creature with \"Whenever this creature attacks, put a +1/+1 counter on it.\" that's still a land. "); + attack(3, playerA, "Raging Ravine"); + + setStopAt(3, Constants.PhaseStep.END_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 16); + assertPowerToughness(playerA, "Raging Ravine", 4, 4, Filter.ComparisonScope.Any); + assertCounterCount("Raging Ravine", CounterType.P1P1, 1); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/TestWerewolfRansacker.java b/Mage.Tests/src/test/java/org/mage/test/cards/TestWerewolfRansacker.java new file mode 100644 index 00000000000..cf3b72ec31c --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/TestWerewolfRansacker.java @@ -0,0 +1,49 @@ +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 TestWerewolfRansacker extends CardTestPlayerBase { + + @Test + public void testCard() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Afflicted Deserter"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Ornithopter"); + + setStopAt(2, Constants.PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 17); + assertPermanentCount(playerB, "Ornithopter", 0); + assertPermanentCount(playerA, "Afflicted Deserter", 0); + assertPermanentCount(playerA, "Werewolf Ransacker", 1); + } + + @Test + public void testCard1() { + addCard(Constants.Zone.BATTLEFIELD, playerA, "Plains", 3); + addCard(Constants.Zone.HAND, playerA, "Blade Splicer"); + addCard(Constants.Zone.BATTLEFIELD, playerB, "Mountain", 4); + addCard(Constants.Zone.HAND, playerB, "Afflicted Deserter"); + + castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Blade Splicer"); + castSpell(2, Constants.PhaseStep.PRECOMBAT_MAIN, playerB, "Afflicted Deserter"); + setStopAt(4, Constants.PhaseStep.DRAW); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerB, "Afflicted Deserter", 0); + assertPermanentCount(playerB, "Werewolf Ransacker", 1); + assertPermanentCount(playerA, "Blade Splicer", 1); + assertPermanentCount(playerA, "Golem", 0); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java new file mode 100644 index 00000000000..a753e3f8425 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java @@ -0,0 +1,462 @@ +/* + * 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 org.mage.test.player; + +import java.io.Serializable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.UUID; +import mage.Constants; +import mage.Constants.Outcome; +import mage.Constants.RangeOfInfluence; +import mage.Constants.Zone; +import mage.abilities.Ability; +import mage.abilities.ActivatedAbility; +import mage.abilities.Mode; +import mage.abilities.Modes; +import mage.abilities.TriggeredAbilities; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.PassAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCost; +import mage.abilities.costs.mana.ManaCosts; +import mage.abilities.costs.mana.VariableManaCost; +import mage.abilities.effects.ReplacementEffect; +import mage.abilities.mana.ManaAbility; +import mage.cards.Card; +import mage.cards.Cards; +import mage.choices.Choice; +import mage.game.Game; +import mage.game.combat.CombatGroup; +import mage.game.permanent.Permanent; +import mage.game.stack.StackAbility; +import mage.player.ai.ComputerPlayer; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetAmount; +import mage.target.TargetCard; +import org.apache.log4j.Logger; + +/** + * + * plays randomly + * + * @author BetaSteward_at_googlemail.com + */ +public class RandomPlayer extends ComputerPlayer { + + private boolean isSimulatedPlayer; + private static Random rnd = new Random(); + private int actionCount = 0; + + protected PassAbility pass = new PassAbility(); + + public RandomPlayer(String name) { + super(name, RangeOfInfluence.ALL); + this.isSimulatedPlayer = true; + } + + public RandomPlayer(final RandomPlayer player) { + super(player); + this.isSimulatedPlayer = player.isSimulatedPlayer; + } + + @Override + public RandomPlayer copy() { + return new RandomPlayer(this); + } + + public boolean isSimulatedPlayer() { + return this.isSimulatedPlayer; + } + + public int getActionCount() { + return actionCount; + } + + @Override + public boolean priority(Game game) { + boolean didSomething = false; + Ability ability = getAction(game); + if (!(ability instanceof PassAbility)) + didSomething = true; + + activateAbility((ActivatedAbility) ability, game); + + actionCount++; + return didSomething; + } + + private Ability getAction(Game game) { + List playables = getPlayableAbilities(game); + Ability ability; + while (true) { + if (playables.size() == 1) + ability = playables.get(0); + else + ability = playables.get(rnd.nextInt(playables.size())); + List options = getPlayableOptions(ability, game); + if (!options.isEmpty()) { + if (options.size() == 1) + ability = options.get(0); + else + ability = options.get(rnd.nextInt(options.size())); + } + if (ability.getManaCosts().getVariableCosts().size() > 0) { + int amount = getAvailableManaProducers(game).size() - ability.getManaCosts().convertedManaCost(); + if (amount > 0) { + ability = ability.copy(); + ability.getManaCostsToPay().add(new GenericManaCost(rnd.nextInt(amount))); + } + } + // check if ability kills player, if not then it's ok to play +// if (ability.isUsesStack()) { +// Game testSim = game.copy(); +// activateAbility((ActivatedAbility) ability, testSim); +// StackObject testAbility = testSim.getStack().pop(); +// testAbility.resolve(testSim); +// testSim.applyEffects(); +// testSim.checkStateAndTriggered(); +// if (!testSim.getPlayer(playerId).hasLost()) { +// break; +// } +// } +// else { + break; +// } + } + return ability; + } + + protected List getPlayableAbilities(Game game) { + List playables = getPlayable(game, true); + playables.add(pass); + return playables; + } + + @Override + public boolean triggerAbility(TriggeredAbility source, Game game) { + if (source != null && source.canChooseTarget(game)) { + Ability ability; + List options = getPlayableOptions(source, game); + if (options.isEmpty()) { + ability = source; + } + else { + if (options.size() == 1) + ability = options.get(0); + else + ability = options.get(rnd.nextInt(options.size())); + } + if (ability.isUsesStack()) { + game.getStack().push(new StackAbility(ability, playerId)); + if (ability.activate(game, false)) { + actionCount++; + return true; + } + } else { + if (ability.activate(game, false)) { + ability.resolve(game); + actionCount++; + return true; + } + } + } + return false; + } + + @Override + public void selectAttackers(Game game) { + //useful only for two player games - will only attack first opponent + UUID defenderId = game.getOpponents(playerId).iterator().next(); + List attackersList = super.getAvailableAttackers(game); + //use binary digits to calculate powerset of attackers + int powerElements = (int) Math.pow(2, attackersList.size()); + int value = rnd.nextInt(powerElements); + StringBuilder binary = new StringBuilder(); + binary.append(Integer.toBinaryString(value)); + while (binary.length() < attackersList.size()) { + binary.insert(0, "0"); //pad with zeros + } + for (int i = 0; i < attackersList.size(); i++) { + if (binary.charAt(i) == '1') + game.getCombat().declareAttacker(attackersList.get(i).getId(), defenderId, game); + } + actionCount++; + } + + @Override + public void selectBlockers(Game game) { + int numGroups = game.getCombat().getGroups().size(); + if (numGroups == 0) return; + + List blockers = getAvailableBlockers(game); + for (Permanent blocker: blockers) { + int check = rnd.nextInt(numGroups + 1); + if (check < numGroups) { + CombatGroup group = game.getCombat().getGroups().get(check); + if (group.getAttackers().size() > 0) + this.declareBlocker(blocker.getId(), group.getAttackers().get(0), game); + } + } + actionCount++; + } + + @Override + public void abort() { + abort = true; + } + + protected boolean chooseRandom(Target target, Game game) { + Set possibleTargets = target.possibleTargets(playerId, game); + if (possibleTargets.isEmpty()) + return !target.isRequired(); + if (!target.isRequired()) { + if (rnd.nextInt(possibleTargets.size() + 1) == 0) { + return false; + } + } + if (possibleTargets.size() == 1) { + target.add(possibleTargets.iterator().next(), game); + return true; + } + Iterator it = possibleTargets.iterator(); + int targetNum = rnd.nextInt(possibleTargets.size()); + UUID targetId = it.next(); + for (int i = 0; i < targetNum; i++) { + targetId = it.next(); + } + target.add(targetId, game); + return true; + } + + protected boolean chooseRandomTarget(Target target, Ability source, Game game) { + Set possibleTargets = target.possibleTargets(source==null?null:source.getSourceId(), playerId, game); + if (possibleTargets.isEmpty()) + return false; + if (!target.isRequired()) { + if (rnd.nextInt(possibleTargets.size() + 1) == 0) { + return false; + } + } + if (possibleTargets.size() == 1) { + target.addTarget(possibleTargets.iterator().next(), source, game); + return true; + } + Iterator it = possibleTargets.iterator(); + int targetNum = rnd.nextInt(possibleTargets.size()); + UUID targetId = it.next(); + for (int i = 0; i < targetNum; i++) { + targetId = it.next(); + } + target.addTarget(targetId, source, game); + return true; + } + + @Override + public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) { + return chooseRandom(target, game); + } + + @Override + public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map options) { + return chooseRandom(target, game); + } + + @Override + public boolean choose(Outcome outcome, Cards cards, TargetCard target, Game game) { + if (cards.isEmpty()) + return !target.isRequired(); + Set possibleTargets = target.possibleTargets(playerId, cards, game); + if (possibleTargets.isEmpty()) + return !target.isRequired(); + Iterator it = possibleTargets.iterator(); + int targetNum = rnd.nextInt(possibleTargets.size()); + UUID targetId = it.next(); + for (int i = 0; i < targetNum; i++) { + targetId = it.next(); + } + target.add(targetId, game); + return true; + } + + @Override + public boolean chooseTarget(Outcome outcome, Target target, Ability source, Game game) { + return chooseRandomTarget(target, source, game); + } + + @Override + public boolean chooseTarget(Outcome outcome, Cards cards, TargetCard target, Ability source, Game game) { + if (cards.isEmpty()) + return !target.isRequired(); + Card card = cards.getRandom(game); + target.addTarget(card.getId(), source, game); + return true; + } + + @Override + public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) { + Set possibleTargets = target.possibleTargets(source==null?null:source.getSourceId(), playerId, game); + if (possibleTargets.isEmpty()) + return !target.isRequired(); + if (!target.isRequired()) { + if (rnd.nextInt(possibleTargets.size() + 1) == 0) { + return false; + } + } + if (possibleTargets.size() == 1) { + target.addTarget(possibleTargets.iterator().next(), target.getAmountRemaining(), source, game); + return true; + } + Iterator it = possibleTargets.iterator(); + int targetNum = rnd.nextInt(possibleTargets.size()); + UUID targetId = it.next(); + for (int i = 0; i < targetNum; i++) { + targetId = it.next(); + } + target.addTarget(targetId, rnd.nextInt(target.getAmountRemaining()) + 1, source, game); + return true; + } + + @Override + public boolean chooseMulligan(Game game) { + return rnd.nextBoolean(); + } + + @Override + public boolean chooseUse(Outcome outcome, String message, Game game) { + return rnd.nextBoolean(); + } + + @Override + public boolean choosePile(Outcome outcome, String message, List pile1, List pile2, Game game) { + return rnd.nextBoolean(); + } + + @Override + public boolean choose(Outcome outcome, Choice choice, Game game) { + Iterator it = choice.getChoices().iterator(); + String sChoice = it.next(); + int choiceNum = rnd.nextInt(choice.getChoices().size()); + for (int i = 0; i < choiceNum; i++) { + sChoice = it.next(); + } + choice.setChoice(sChoice); + return true; + } + + @Override + public boolean playXMana(VariableManaCost cost, ManaCosts costs, Game game) { + for (Permanent perm: this.getAvailableManaProducers(game)) { + for (ManaAbility ability: perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { + if (rnd.nextBoolean()) + activateAbility(ability, game); + } + } + + // don't allow X=0 + if (getManaPool().count() == 0) { + return false; + } + + cost.setPaid(); + return true; + } + + @Override + public int chooseEffect(List rEffects, Game game) { + return rnd.nextInt(rEffects.size()); + } + + @Override + public TriggeredAbility chooseTriggeredAbility(List abilities, Game game) { + return abilities.get(rnd.nextInt(abilities.size())); + } + + @Override + public Mode chooseMode(Modes modes, Ability source, Game game) { + Iterator it = modes.values().iterator(); + Mode mode = it.next(); + if (modes.size() == 1) + return mode; + int modeNum = rnd.nextInt(modes.values().size()); + for (int i = 0; i < modeNum; i++) { + mode = it.next(); + } + return mode; + } + + @Override + public UUID chooseAttackerOrder(List attackers, Game game) { + return attackers.get(rnd.nextInt(attackers.size())).getId(); + } + + @Override + public UUID chooseBlockerOrder(List blockers, Game game) { + return blockers.get(rnd.nextInt(blockers.size())).getId(); + } + + @Override + public void assignDamage(int damage, List targets, String singleTargetName, UUID sourceId, Game game) { + int remainingDamage = damage; + UUID targetId; + int amount; + while (remainingDamage > 0) { + if (targets.size() == 1) { + targetId = targets.get(0); + amount = remainingDamage; + } + else { + targetId = targets.get(rnd.nextInt(targets.size())); + amount = rnd.nextInt(damage + 1); + } + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + permanent.damage(amount, sourceId, game, true, false); + remainingDamage -= amount; + } + else { + Player player = game.getPlayer(targetId); + if (player != null) { + player.damage(amount, sourceId, game, false, true); + remainingDamage -= amount; + } + } + targets.remove(targetId); + } + } + + @Override + public int getAmount(int min, int max, String message, Game game) { + return rnd.nextInt(max - min) + min; + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index c8b3725b59e..41d1be17806 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -29,17 +29,20 @@ package org.mage.test.player; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.UUID; import mage.Constants; import mage.Constants.PhaseStep; import mage.abilities.Ability; import mage.abilities.ActivatedAbility; +import mage.counters.Counter; import mage.filter.FilterPermanent; import mage.filter.common.FilterAttackingCreature; import mage.filter.common.FilterCreatureForCombat; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.game.stack.StackObject; import mage.player.ai.ComputerPlayer; import mage.players.Player; @@ -78,7 +81,7 @@ public class TestPlayer extends ComputerPlayer { command = command.substring(command.indexOf("activate:") + 9); String[] groups = command.split(";"); for (Ability ability: this.getPlayable(game, true)) { - if (ability.toString().equals(groups[0])) { + if (ability.toString().startsWith(groups[0])) { if (groups.length > 1) { addTargets(ability, groups, game); } @@ -88,6 +91,18 @@ public class TestPlayer extends ComputerPlayer { } } } + if (action.getAction().startsWith("addCounters:")) { + String command = action.getAction(); + command = command.substring(command.indexOf("addCounters:") + 12); + String[] groups = command.split(";"); + for (Permanent permanent : game.getBattlefield().getAllActivePermanents()) { + if (permanent.getName().equals(groups[0])) { + Counter counter = new Counter(groups[1], Integer.parseInt(groups[2])); + permanent.addCounters(counter, game); + break; + } + } + } } } pass(); @@ -156,10 +171,21 @@ public class TestPlayer extends ComputerPlayer { } else if (group.startsWith("target=")) { target = group.substring(group.indexOf("target=") + 7); - for (Permanent permanent: game.getBattlefield().getAllActivePermanents()) { - if (permanent.getName().equals(target)) { - ability.getTargets().get(0).addTarget(permanent.getId(), ability, game); - break; + String[] targets = target.split("\\^"); + for (String t: targets) { + for (Permanent permanent: game.getBattlefield().getAllActivePermanents()) { + if (permanent.getName().equals(t)) { + ability.getTargets().get(0).addTarget(permanent.getId(), ability, game); + break; + } + } + Iterator it = game.getStack().iterator(); + while (it.hasNext()) { + StackObject object = it.next(); + if (object.getName().equals(t)) { + ability.getTargets().get(0).addTarget(object.getId(), ability, game); + break; + } } } } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/TestPlayRandomGame.java b/Mage.Tests/src/test/java/org/mage/test/serverside/TestPlayRandomGame.java new file mode 100644 index 00000000000..7f7df12e3f6 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/TestPlayRandomGame.java @@ -0,0 +1,83 @@ +package org.mage.test.serverside; + +import mage.Constants; +import mage.Constants.ColoredManaSymbol; +import mage.cards.Card; +import mage.cards.decks.Deck; +import mage.game.Game; +import mage.game.GameException; +import mage.game.GameOptions; +import mage.game.TwoPlayerDuel; +import mage.player.ai.ComputerPlayer; +import mage.players.Player; +import mage.sets.Sets; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.MageTestBase; + +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +/** + * @author ayratn + */ +public class TestPlayRandomGame extends MageTestBase { + + private static List colorChoices = Arrays.asList("bu", "bg", "br", "bw", "ug", "ur", "uw", "gr", "gw", "rw", "bur", "buw", "bug", "brg", "brw", "bgw", "wur", "wug", "wrg", "rgu"); + + @Test + @Ignore + public void playGames() throws GameException, FileNotFoundException { + for (int i = 1; i < 100; i++) { + logger.info("Playing game: " + i); + playOneGame(); + } + } + + private void playOneGame() throws GameException, FileNotFoundException, IllegalArgumentException { + Game game = new TwoPlayerDuel(Constants.MultiplayerAttackOption.LEFT, Constants.RangeOfInfluence.ALL); + + Player computerA = createRandomPlayer("ComputerA"); + Deck deck = generateRandomDeck(); + + if (deck.getCards().size() < 40) { + throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck.getCards().size()); + } + game.addPlayer(computerA, deck); + game.loadCards(deck.getCards(), computerA.getId()); + + Player computerB = createRandomPlayer("ComputerB"); + Deck deck2 = generateRandomDeck(); + if (deck2.getCards().size() < 40) { + throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck2.getCards().size()); + } + game.addPlayer(computerB, deck2); + game.loadCards(deck2.getCards(), computerB.getId()); + + boolean testMode = true; + + long t1 = System.nanoTime(); + GameOptions options = new GameOptions(); + options.testMode = true; + game.start(computerA.getId(), options); + long t2 = System.nanoTime(); + + logger.info("Winner: " + game.getWinner()); + logger.info("Time: " + (t2 - t1) / 1000000 + " ms"); + } + + private Deck generateRandomDeck() { + String selectedColors = colorChoices.get(new Random().nextInt(colorChoices.size())).toUpperCase(); + List allowedColors = new ArrayList(); + logger.info("Building deck with colors: " + selectedColors); + for (int i = 0; i < selectedColors.length(); i++) { + char c = selectedColors.charAt(i); + allowedColors.add(ColoredManaSymbol.lookup(c)); + } + List cardPool = Sets.generateRandomCardPool(45, allowedColors); + return ComputerPlayer.buildDeck(cardPool, allowedColors); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestBase.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestBase.java index 19727975e18..4ea7b8c7cff 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestBase.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestBase.java @@ -28,6 +28,7 @@ import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import mage.Constants.PhaseStep; +import org.mage.test.player.RandomPlayer; /** * Base class for all tests. @@ -298,4 +299,8 @@ public abstract class MageTestBase { protected Player createPlayer(String name, String playerType) { return PlayerFactory.getInstance().createPlayer(playerType, name, Constants.RangeOfInfluence.ALL, 5); } + + protected Player createRandomPlayer(String name) { + return new RandomPlayer(name); + } } 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 0c0ab908178..9bc5ea4d774 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 @@ -15,6 +15,7 @@ import org.mage.test.serverside.base.MageTestPlayerBase; import java.util.List; import java.util.UUID; import mage.Constants.PhaseStep; +import mage.counters.Counter; import mage.counters.CounterType; import org.mage.test.player.TestPlayer; @@ -82,6 +83,20 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } /** + * Removes all cards from player's hand from the game. + * Usually this should be used once before initialization to set the players hand. + * + * @param player {@link Player} to remove all cards from hand. + */ + public void removeAllCardsFromHand(Player player) { + if (player.equals(playerA)) { + commandsA.put(Constants.Zone.HAND, "clear"); + } else if (player.equals(playerB)) { + commandsB.put(Constants.Zone.HAND, "clear"); + } + } + + /** * Add a card to specified zone of specified player. * * @param gameZone {@link Constants.Zone} to add cards to. @@ -142,7 +157,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } } } - + /** * Returns card list containter for specified game zone and player. * @@ -361,16 +376,38 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param count Expected count. */ public void assertCounterCount(String cardName, CounterType type, int count) throws AssertionError { - int actualCount = 0; - for (Permanent permanent : currentGame.getBattlefield().getAllPermanents()) { - if (permanent.getName().equals(cardName)) { - actualCount += permanent.getCounters().getCount(type); - } + Permanent found = null; + for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) { + if (permanent.getName().equals(cardName)) { + found = permanent; + } } - Assert.assertEquals("(Battlefield) Counter counts are not equal (" + cardName + ":" + type + ")", count, actualCount); + + Assert.assertNotNull("There is no such permanent on the battlefield, cardName=" + cardName, found); + + Assert.assertEquals("(Battlefield) Counter counts are not equal (" + cardName + ":" + type + ")", count, found.getCounters().getCount(type)); } /** + * Assert whether a permanent is tapped or not + * + * @param cardName Name of the permanent that should be checked. + * @param tapped Whether the permanent is tapped or not + */ + public void assertTapped(String cardName, boolean tapped) throws AssertionError { + Permanent found = null; + for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) { + if (permanent.getName().equals(cardName)) { + found = permanent; + } + } + + Assert.assertNotNull("There is no such permanent on the battlefield, cardName=" + cardName, found); + + Assert.assertEquals("(Battlefield) Tapped state is not equal (" + cardName + ")", tapped, found.isTapped()); + } + + /** * Assert card count in player's hand. * * @param player {@link Player} who's hand should be counted. @@ -427,7 +464,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } public void playLand(int turnNum, PhaseStep step, TestPlayer player, String cardName) { - player.addAction(turnNum, step, "activate:Cast " + cardName); + player.addAction(turnNum, step, "activate:Play " + cardName); } public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName) { @@ -442,6 +479,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement player.addAction(turnNum, step, "activate:Cast " + cardName + ";target=" + targetName); } + public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability) { + player.addAction(turnNum, step, "activate:" + ability); + } + public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, Player target) { player.addAction(turnNum, step, "activate:" + ability + ";target=" + target.getName()); } @@ -450,7 +491,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement player.addAction(turnNum, step, "activate:" + ability + ";target=" + targetName); } - public void useAbility(int turnNum, PhaseStep step, TestPlayer player, String cardName) { + public void addCounters(int turnNum, PhaseStep step, TestPlayer player, String cardName, CounterType type, int count) { + player.addAction(turnNum, step, "addCounters:" + cardName + ";" + type.getName() + ";" + count); } public void attack(int turnNum, TestPlayer player, String attacker) { diff --git a/Mage/src/mage/abilities/ActivatedAbilityImpl.java b/Mage/src/mage/abilities/ActivatedAbilityImpl.java index e10e2497863..3d32511fa3f 100644 --- a/Mage/src/mage/abilities/ActivatedAbilityImpl.java +++ b/Mage/src/mage/abilities/ActivatedAbilityImpl.java @@ -32,9 +32,9 @@ import java.util.UUID; import mage.Constants.AbilityType; import mage.Constants.TimingRule; import mage.Constants.Zone; +import mage.MageObject; import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; -import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.PhyrexianManaCost; import mage.abilities.effects.Effect; @@ -176,7 +176,11 @@ public abstract class ActivatedAbilityImpl> ex protected String getMessageText(Game game) { StringBuilder sb = new StringBuilder(); - sb.append(game.getObject(this.sourceId).getName()); + MageObject object = game.getObject(this.sourceId); + if (object != null) + sb.append(object.getName()); + else + sb.append("unknown"); if (getTargets().size() > 0) { sb.append(" targeting "); for (Target target: getTargets()) { diff --git a/Mage/src/mage/abilities/TriggeredAbilities.java b/Mage/src/mage/abilities/TriggeredAbilities.java index f51634e0735..f26b0148396 100644 --- a/Mage/src/mage/abilities/TriggeredAbilities.java +++ b/Mage/src/mage/abilities/TriggeredAbilities.java @@ -28,9 +28,9 @@ package mage.abilities; +import java.util.HashMap; +import java.util.Map; import java.util.UUID; -import mage.Constants; -import mage.Constants.Zone; import mage.MageObject; import mage.game.Game; import mage.game.events.GameEvent; @@ -39,18 +39,22 @@ import mage.game.events.GameEvent; * * @author BetaSteward_at_googlemail.com */ -public class TriggeredAbilities extends AbilitiesImpl { +public class TriggeredAbilities extends HashMap { public TriggeredAbilities() {} public TriggeredAbilities(final TriggeredAbilities abilities) { - super(abilities); + for (Map.Entry entry: abilities.entrySet()) { + this.put(entry.getKey(), entry.getValue().copy()); + } } public void checkTriggers(GameEvent event, Game game) { - for (TriggeredAbility ability: this) { + for (TriggeredAbility ability: this.values()) { if (ability.isInUseableZone(game)) { - MageObject object = game.getObject(ability.getSourceId()); + MageObject object = game.getLastKnownInformation(ability.getSourceId(), event.getZone()); + if (object == null) + object = game.getObject(ability.getSourceId()); if (object != null && object.getAbilities().contains(ability)) { if (ability.checkTrigger(event, game)) { ability.trigger(game, ability.getControllerId()); @@ -59,8 +63,11 @@ public class TriggeredAbilities extends AbilitiesImpl { } } } + + public void add(TriggeredAbility ability) { + this.put(ability.getId(), ability); + } - @Override public TriggeredAbilities copy() { return new TriggeredAbilities(this); } diff --git a/Mage/src/mage/abilities/costs/common/ExileFromGraveCost.java b/Mage/src/mage/abilities/costs/common/ExileFromGraveCost.java index a1be6a7b785..0709332da55 100644 --- a/Mage/src/mage/abilities/costs/common/ExileFromGraveCost.java +++ b/Mage/src/mage/abilities/costs/common/ExileFromGraveCost.java @@ -79,7 +79,7 @@ public class ExileFromGraveCost extends CostImpl { @Override public boolean canPay(UUID sourceId, UUID controllerId, Game game) { - return targets.canChoose(controllerId, controllerId, game); + return targets.canChoose(controllerId, game); } @Override diff --git a/Mage/src/mage/abilities/costs/common/ReturnToHandTargetCost.java b/Mage/src/mage/abilities/costs/common/ReturnToHandTargetCost.java index 5d62c9176cf..7a6d2508d1c 100644 --- a/Mage/src/mage/abilities/costs/common/ReturnToHandTargetCost.java +++ b/Mage/src/mage/abilities/costs/common/ReturnToHandTargetCost.java @@ -71,7 +71,7 @@ public class ReturnToHandTargetCost extends CostImpl { @Override public boolean canPay(UUID sourceId, UUID controllerId, Game game) { - return targets.canChoose(controllerId, controllerId, game); + return targets.canChoose(controllerId, game); } @Override diff --git a/Mage/src/mage/abilities/costs/common/SacrificeTargetCost.java b/Mage/src/mage/abilities/costs/common/SacrificeTargetCost.java index 7d95a81591b..eef4de0b656 100644 --- a/Mage/src/mage/abilities/costs/common/SacrificeTargetCost.java +++ b/Mage/src/mage/abilities/costs/common/SacrificeTargetCost.java @@ -74,7 +74,7 @@ public class SacrificeTargetCost extends CostImpl { @Override public boolean canPay(UUID sourceId, UUID controllerId, Game game) { - return targets.canChoose(sourceId, controllerId, game); + return targets.canChoose(controllerId, game); } @Override diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java index e53841168a3..9d71b4fd153 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java @@ -246,15 +246,6 @@ public class ContinuousEffects implements Serializable { public List getApplicableRequirementEffects(Permanent permanent, Game game) { List effects = new ArrayList(); - //get all applicable Requirement effects on the battlefield -// for (Permanent perm: game.getBattlefield().getActivePermanents(permanent.getControllerId(), game)) { -// for (Entry entry: perm.getAbilities().getEffects(game, Zone.BATTLEFIELD, EffectType.REQUIREMENT).entrySet()) { -// if (((RequirementEffect)entry.getKey()).applies(permanent, entry.getValue(), game)) { -// effects.add((RequirementEffect)entry.getKey()); -// abilityMap.put(entry.getKey().getId(), entry.getValue()); -// } -// } -// } for (RequirementEffect effect: requirementEffects) { Ability ability = abilityMap.get(effect.getId()); if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game)) { @@ -267,15 +258,6 @@ public class ContinuousEffects implements Serializable { public List getApplicableRestrictionEffects(Permanent permanent, Game game) { List effects = new ArrayList(); - //get all applicable Restriction effects on the battlefield -// for (Permanent perm: game.getBattlefield().getActivePermanents(permanent.getControllerId(), game)) { -// for (Entry entry: perm.getAbilities().getEffects(game, Zone.BATTLEFIELD, EffectType.RESTRICTION).entrySet()) { -// if (((RestrictionEffect)entry.getKey()).applies(permanent, entry.getValue(), game)) { -// effects.add((RestrictionEffect)entry.getKey()); -// abilityMap.put(entry.getKey().getId(), entry.getValue()); -// } -// } -// } for (RestrictionEffect effect: restrictionEffects) { Ability ability = abilityMap.get(effect.getId()); if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game)) { @@ -296,36 +278,6 @@ public class ContinuousEffects implements Serializable { List replaceEffects = new ArrayList(); if (planeswalkerRedirectionEffect.applies(event, null, game)) replaceEffects.add(planeswalkerRedirectionEffect); - //get all applicable Replacement effects in each players hand and graveyard -// for (Card card: game.getCards()) { -// Zone zone = game.getState().getZone(card.getId()); -// if (zone == Zone.HAND || zone == Zone.GRAVEYARD) { -// for (Entry entry: card.getAbilities().getReplacementEffects(zone).entrySet()) { -// if (entry.getKey().applies(event, entry.getValue(), game)) { -// replaceEffects.add(entry.getKey()); -// abilityMap.put(entry.getKey().getId(), entry.getValue()); -// } -// } -// } -// } - //get all applicable Replacement effects on the battlefield -// for (Permanent permanent: game.getBattlefield().getAllPermanents()) { -// for (Entry entry: permanent.getAbilities().getReplacementEffects(Zone.BATTLEFIELD).entrySet()) { -// if (entry.getKey().applies(event, entry.getValue(), game)) { -// replaceEffects.add(entry.getKey()); -// abilityMap.put(entry.getKey().getId(), entry.getValue()); -// } -// } -// } - //get all applicable Replacement effects on players -// for (Player player: game.getPlayers().values()) { -// for (Entry entry: player.getAbilities().getReplacementEffects(Zone.BATTLEFIELD).entrySet()) { -// if (entry.getKey().applies(event, entry.getValue(), game)) { -// replaceEffects.add(entry.getKey()); -// abilityMap.put(entry.getKey().getId(), entry.getValue()); -// } -// } -// } //get all applicable transient Replacement effects for (ReplacementEffect effect: replacementEffects) { Ability ability = abilityMap.get(effect.getId()); @@ -351,16 +303,6 @@ public class ContinuousEffects implements Serializable { } public boolean asThough(UUID objectId, AsThoughEffectType type, Game game) { - for (Permanent permanent: game.getBattlefield().getAllPermanents()) { - for (Ability ability: permanent.getAbilities().getStaticAbilities(Zone.BATTLEFIELD)) { - for (Effect effect: ability.getEffects(game, EffectType.ASTHOUGH)) { - AsThoughEffect rEffect = (AsThoughEffect) effect; - if (rEffect.applies(objectId, ability, game)) { - return true; - } - } - } - } for (AsThoughEffect entry: asThoughEffects) { AsThoughEffect effect = entry; if (effect.getAsThoughEffectType() == type) { @@ -435,52 +377,31 @@ public class ContinuousEffects implements Serializable { removeInactiveEffects(game); List layerEffects = getLayeredEffects(game); List layer = filterLayeredEffects(layerEffects, Layer.CopyEffects_1); -// for (ContinuousEffect effect: layer) { -// effect.apply(Layer.CopyEffects_1, SubLayer.CharacteristicDefining_7a, abilityMap.get(effect.getId()), game); -// } for (ContinuousEffect effect: layer) { effect.apply(Layer.CopyEffects_1, SubLayer.NA, abilityMap.get(effect.getId()), game); } layer = filterLayeredEffects(layerEffects, Layer.ControlChangingEffects_2); -// for (ContinuousEffect effect: layer) { -// effect.apply(Layer.ControlChangingEffects_2, SubLayer.CharacteristicDefining_7a, abilityMap.get(effect.getId()), game); -// } for (ContinuousEffect effect: layer) { effect.apply(Layer.ControlChangingEffects_2, SubLayer.NA, abilityMap.get(effect.getId()), game); } layer = filterLayeredEffects(layerEffects, Layer.TextChangingEffects_3); -// for (ContinuousEffect effect: layer) { -// effect.apply(Layer.TextChangingEffects_3, SubLayer.CharacteristicDefining_7a, abilityMap.get(effect.getId()), game); -// } for (ContinuousEffect effect: layer) { effect.apply(Layer.TextChangingEffects_3, SubLayer.NA, abilityMap.get(effect.getId()), game); } layer = filterLayeredEffects(layerEffects, Layer.TypeChangingEffects_4); -// for (ContinuousEffect effect: layer) { -// effect.apply(Layer.TypeChangingEffects_4, SubLayer.CharacteristicDefining_7a, abilityMap.get(effect.getId()), game); -// } for (ContinuousEffect effect: layer) { effect.apply(Layer.TypeChangingEffects_4, SubLayer.NA, abilityMap.get(effect.getId()), game); } layer = filterLayeredEffects(layerEffects, Layer.ColorChangingEffects_5); -// for (ContinuousEffect effect: layer) { -// effect.apply(Layer.ColorChangingEffects_5, SubLayer.CharacteristicDefining_7a, abilityMap.get(effect.getId()), game); -// } for (ContinuousEffect effect: layer) { effect.apply(Layer.ColorChangingEffects_5, SubLayer.NA, abilityMap.get(effect.getId()), game); } layer = filterLayeredEffects(layerEffects, Layer.AbilityAddingRemovingEffects_6); -// for (ContinuousEffect effect: layer) { -// effect.apply(Layer.AbilityAddingRemovingEffects_6, SubLayer.CharacteristicDefining_7a, abilityMap.get(effect.getId()), game); -// } for (ContinuousEffect effect: layer) { effect.apply(Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, abilityMap.get(effect.getId()), game); } layerEffects = getLayeredEffects(game); layer = filterLayeredEffects(layerEffects, Layer.PTChangingEffects_7); -// for (ContinuousEffect effect: layer) { -// effect.apply(Layer.PTChangingEffects_7, SubLayer.CharacteristicDefining_7a, abilityMap.get(effect.getId()), game); -// } for (ContinuousEffect effect: layer) { effect.apply(Layer.PTChangingEffects_7, SubLayer.SetPT_7b, abilityMap.get(effect.getId()), game); } diff --git a/Mage/src/mage/abilities/effects/common/GetEmblemEffect.java b/Mage/src/mage/abilities/effects/common/GetEmblemEffect.java index 62dcd2b8787..077d86654c7 100644 --- a/Mage/src/mage/abilities/effects/common/GetEmblemEffect.java +++ b/Mage/src/mage/abilities/effects/common/GetEmblemEffect.java @@ -30,12 +30,9 @@ package mage.abilities.effects.common; import mage.Constants.Outcome; import mage.abilities.Ability; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.game.Game; import mage.game.command.Emblem; -import mage.game.permanent.token.Token; /** * @@ -67,6 +64,9 @@ public class GetEmblemEffect extends OneShotEffect { newEmblem.setSourceId(source.getSourceId()); newEmblem.setControllerId(source.getControllerId()); game.getState().getCommand().add(newEmblem); + for (Ability ability: newEmblem.getAbilities()) { + game.getState().addAbility(ability); + } return true; } diff --git a/Mage/src/mage/abilities/keyword/BloodthirstAbility.java b/Mage/src/mage/abilities/keyword/BloodthirstAbility.java index 4a4d98ebe40..8f68caf5592 100644 --- a/Mage/src/mage/abilities/keyword/BloodthirstAbility.java +++ b/Mage/src/mage/abilities/keyword/BloodthirstAbility.java @@ -58,7 +58,7 @@ class BloodthirstEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null) { BloodthirstWatcher watcher = (BloodthirstWatcher) game.getState().getWatchers().get("DamagedOpponents", source.getControllerId()); - if (watcher.conditionMet()) { + if (watcher != null && watcher.conditionMet()) { Permanent p = game.getPermanent(source.getSourceId()); if (p != null) { p.addCounters(CounterType.P1P1.createInstance(amount), game); diff --git a/Mage/src/mage/abilities/keyword/CascadeAbility.java b/Mage/src/mage/abilities/keyword/CascadeAbility.java index dbab9913a10..6d1aaf66027 100644 --- a/Mage/src/mage/abilities/keyword/CascadeAbility.java +++ b/Mage/src/mage/abilities/keyword/CascadeAbility.java @@ -96,7 +96,7 @@ class CascadeEffect extends OneShotEffect { ExileZone exile = game.getExile().createZone(source.getSourceId(), player.getName() + " Cascade"); int sourceCost = game.getObject(source.getSourceId()).getManaCost().convertedManaCost(); do { - card = player.getLibrary().getFromTop(game); + card = player.getLibrary().removeFromTop(game); if (card == null) break; card.moveToExile(exile.getId(), exile.getName(), source.getId(), game); diff --git a/Mage/src/mage/cards/CardImpl.java b/Mage/src/mage/cards/CardImpl.java index 1fbc8374ebb..43bbe74c2a2 100644 --- a/Mage/src/mage/cards/CardImpl.java +++ b/Mage/src/mage/cards/CardImpl.java @@ -273,6 +273,7 @@ public abstract class CardImpl> extends MageObjectImpl logger.fatal("invalid zone for card - " + toZone); return false; } + setControllerId(ownerId); game.setZone(objectId, event.getToZone()); game.fireEvent(event); return game.getState().getZone(objectId) == toZone; diff --git a/Mage/src/mage/game/command/Emblem.java b/Mage/src/mage/game/command/Emblem.java index 55986304da9..95f6412ad40 100644 --- a/Mage/src/mage/game/command/Emblem.java +++ b/Mage/src/mage/game/command/Emblem.java @@ -27,22 +27,19 @@ */ package mage.game.command; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; import mage.Constants; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Abilities; import mage.abilities.AbilitiesImpl; import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.ManaCostsImpl; import mage.game.Game; -import mage.game.events.GameEvent; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; /** * @author nantuko @@ -82,25 +79,13 @@ public class Emblem implements CommandObject { public void setControllerId(UUID controllerId) { this.controllerId = controllerId; + this.abilites.setControllerId(controllerId); } public void setSourceId(UUID sourceId) { this.sourceId = sourceId; } -// @Override -// public void checkTriggers(GameEvent event, Game game) { -// // we have to use Zone.BATTLEFIELD to use the same predefined abilities (like SpellCastTriggeredAbility) -// // and not create duplicates -// for (TriggeredAbility ability: getAbilities().getTriggeredAbilities(Constants.Zone.BATTLEFIELD)) { -// ability.setControllerId(getControllerId()); -// ability.setSourceId(getSourceId()); -// if (ability.checkTrigger(event, game)) { -// ability.trigger(game, getControllerId()); -// } -// } -// } - @Override public String getName() { return ""; @@ -162,6 +147,7 @@ public class Emblem implements CommandObject { return this.id; } + @Override public Emblem copy() { return new Emblem(this); } diff --git a/Mage/src/mage/game/permanent/PermanentCard.java b/Mage/src/mage/game/permanent/PermanentCard.java index 4555adc99b7..dd3f8dc0a31 100644 --- a/Mage/src/mage/game/permanent/PermanentCard.java +++ b/Mage/src/mage/game/permanent/PermanentCard.java @@ -96,6 +96,7 @@ public class PermanentCard extends PermanentImpl { this.abilities.clear(); this.abilities.addAll(card.getAbilities()); this.abilities.setControllerId(this.controllerId); + this.watchers.addAll(card.getWatchers()); this.cardType.clear(); this.cardType.addAll(card.getCardType()); this.color = card.getColor().copy(); diff --git a/Mage/src/mage/players/Library.java b/Mage/src/mage/players/Library.java index 0bdf079efbc..a590ed72620 100644 --- a/Mage/src/mage/players/Library.java +++ b/Mage/src/mage/players/Library.java @@ -201,12 +201,6 @@ public class Library implements Serializable { return emptyDraw; } - void setControllerId(UUID playerId, Game game) { - for (UUID cardId: library) { - game.getCard(cardId).setControllerId(playerId); - } - } - public void addAll(Set cards, Game game) { for (Card card: cards) { game.setZone(card.getId(), Zone.LIBRARY); diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 97c9f810392..36a0b517c16 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -62,6 +62,7 @@ import mage.counters.Counter; import mage.counters.CounterType; import mage.counters.Counters; import mage.filter.common.FilterCreatureForCombat; +import mage.game.ExileZone; import mage.game.Game; import mage.game.combat.CombatGroup; import mage.game.events.DamagePlayerEvent; @@ -489,7 +490,8 @@ public abstract class PlayerImpl> implements Player, Ser Ability spellAbility = game.getStack().getSpell(ability.getId()).getSpellAbility(); if (spellAbility.activate(game, noMana)) { for (KickerAbility kicker: card.getAbilities().getKickerAbilities()) { - kicker.activate(game, false); + if (kicker.getCosts().canPay(ability.getSourceId(), playerId, game) && kicker.canChooseTarget(game)) + kicker.activate(game, false); } GameEvent event = GameEvent.getEvent(GameEvent.EventType.SPELL_CAST, spellAbility.getId(), spellAbility.getSourceId(), playerId); event.setZone(fromZone); @@ -520,6 +522,9 @@ public abstract class PlayerImpl> implements Player, Ser case GRAVEYARD: removeFromGraveyard(card, game); break; + case EXILED: + game.getExile().removeCard(card, game); + break; default: // invalid zone for play land return false; @@ -1209,7 +1214,10 @@ public abstract class PlayerImpl> implements Player, Ser } } } - + for (AlternativeCost cost: ability.getAlternativeCosts()) { + if (cost.isAvailable(game, ability) && cost.canPay(ability.getSourceId(), playerId, game)) + return true; + } } return false; } @@ -1235,6 +1243,24 @@ public abstract class PlayerImpl> implements Player, Ser playable.add(ability); } } + for (ExileZone exile: game.getExile().getExileZones()) { + for (Card card: exile.getCards(game)) { + if (game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.CAST, game)) { + for (ActivatedAbility ability: card.getAbilities().getActivatedAbilities(Zone.HAND)) { + playable.add(ability); + } + } + } + } + for (Cards cards: game.getState().getRevealed().values()) { + for (Card card: cards.getCards(game)) { + if (game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.CAST, game)) { + for (ActivatedAbility ability: card.getAbilities().getActivatedAbilities(Zone.HAND)) { + playable.add(ability); + } + } + } + } // eliminate duplicate activated abilities Map playableActivated = new HashMap(); for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) { diff --git a/Mage/src/mage/target/TargetObject.java b/Mage/src/mage/target/TargetObject.java index 38a3d1e2573..9e6567b7826 100644 --- a/Mage/src/mage/target/TargetObject.java +++ b/Mage/src/mage/target/TargetObject.java @@ -66,7 +66,9 @@ public abstract class TargetObject> extends TargetImpl public String getTargetedName(Game game) { StringBuilder sb = new StringBuilder(); for (UUID targetId: getTargets()) { - sb.append(game.getObject(targetId).getName()).append(" "); + MageObject object = game.getObject(targetId); + if (object != null) + sb.append(object.getName()).append(" "); } return sb.toString(); }