From fec750ef0161d6083507daec7686225eefefcddb Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 3 Nov 2012 16:42:53 +0100 Subject: [PATCH] [BOK] 12 cards --- .../betrayersofkamigawa/BlazingShoal.java | 129 +++++++++ .../betrayersofkamigawa/DisruptingShoal.java | 162 ++++++++++++ .../sets/betrayersofkamigawa/FirstVolley.java | 99 +++++++ .../betrayersofkamigawa/NourishingShoal.java | 126 +++++++++ .../OpalEyeKondasYojimbo.java | 212 +++++++++++++++ .../betrayersofkamigawa/PatronOfTheAkki.java | 71 +++++ .../PatronOfTheKitsune.java | 102 ++++++++ .../betrayersofkamigawa/PatronOfTheMoon.java | 116 +++++++++ .../PatronOfTheNezumi.java | 115 +++++++++ .../PatronOfTheOrochi.java | 120 +++++++++ .../betrayersofkamigawa/ShiningShoal.java | 244 ++++++++++++++++++ .../betrayersofkamigawa/SickeningShoal.java | 127 +++++++++ 12 files changed, 1623 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/betrayersofkamigawa/BlazingShoal.java create mode 100644 Mage.Sets/src/mage/sets/betrayersofkamigawa/DisruptingShoal.java create mode 100644 Mage.Sets/src/mage/sets/betrayersofkamigawa/FirstVolley.java create mode 100644 Mage.Sets/src/mage/sets/betrayersofkamigawa/NourishingShoal.java create mode 100644 Mage.Sets/src/mage/sets/betrayersofkamigawa/OpalEyeKondasYojimbo.java create mode 100644 Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheAkki.java create mode 100644 Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheKitsune.java create mode 100644 Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheMoon.java create mode 100644 Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheNezumi.java create mode 100644 Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheOrochi.java create mode 100644 Mage.Sets/src/mage/sets/betrayersofkamigawa/ShiningShoal.java create mode 100644 Mage.Sets/src/mage/sets/betrayersofkamigawa/SickeningShoal.java diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/BlazingShoal.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/BlazingShoal.java new file mode 100644 index 00000000000..99170f2d324 --- /dev/null +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/BlazingShoal.java @@ -0,0 +1,129 @@ +/* + * 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 LIAB8LE 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.betrayersofkamigawa; + +import java.util.List; +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Duration; +import mage.Constants.Rarity; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.costs.AlternativeCost; +import mage.abilities.costs.AlternativeCostImpl; +import mage.abilities.costs.Cost; +import mage.abilities.costs.Costs; +import mage.abilities.costs.common.ExileFromHandCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.continious.BoostTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.other.OwnerPredicate; +import mage.game.Game; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class BlazingShoal extends CardImpl { + + private static final String ALTERNATIVE_COST_DESCRIPTION = "You may exile a red card with converted mana cost X from your hand rather than pay Blazing Shoal's mana cost"; + private static final FilterCard filter = new FilterCard("red card from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.RED)); + filter.add(new OwnerPredicate(Constants.TargetController.YOU)); + } + + public BlazingShoal(UUID ownerId) { + super(ownerId, 96, "Blazing Shoal", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{X}{R}{R}"); + this.expansionSetCode = "BOK"; + this.subtype.add("Arcane"); + this.color.setRed(true); + + // You may exile a red card with converted mana cost X from your hand rather than pay Blazing Shoal's mana cost. + this.getSpellAbility().addAlternativeCost(new AlternativeCostImpl(ALTERNATIVE_COST_DESCRIPTION, new ExileFromHandCost(new TargetCardInHand(filter)))); + + // Target creature gets +X/+0 until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(new BlazingShoalVariableValue(), new StaticValue(0), Duration.EndOfTurn)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public BlazingShoal(final BlazingShoal card) { + super(card); + } + + @Override + public BlazingShoal copy() { + return new BlazingShoal(this); + } +} + +class BlazingShoalVariableValue implements DynamicValue { + @Override + public int calculate(Game game, Ability sourceAbility) { + List aCosts = sourceAbility.getAlternativeCosts(); + for (AlternativeCost aCost: aCosts) { + if (aCost.isPaid()) { + Costs aCostsList = (Costs) aCost; + for (int x=0; x < aCostsList.size(); x++) { + Cost cost = (Cost) aCostsList.get(x); + if (cost instanceof ExileFromHandCost) { + int xMana = 0; + for (Card card : ((ExileFromHandCost) cost).getCards()) { + xMana += card.getManaCost().convertedManaCost(); + } + return xMana; + } + } + } + } + return sourceAbility.getManaCostsToPay().getX(); + } + + @Override + public DynamicValue clone() { + return new BlazingShoalVariableValue(); + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return ""; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/DisruptingShoal.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/DisruptingShoal.java new file mode 100644 index 00000000000..7d8ae4a3fb2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/DisruptingShoal.java @@ -0,0 +1,162 @@ +/* + * 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 LIAB8LE 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.betrayersofkamigawa; + +import java.util.List; +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Outcome; +import mage.Constants.Rarity; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.costs.AlternativeCost; +import mage.abilities.costs.AlternativeCostImpl; +import mage.abilities.costs.Cost; +import mage.abilities.costs.Costs; +import mage.abilities.costs.common.ExileFromHandCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.other.OwnerIdPredicate; +import mage.filter.predicate.other.OwnerPredicate; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.target.TargetSpell; +import mage.target.common.TargetCardInHand; + +/** + * + * @author LevelX2 + */ +public class DisruptingShoal extends CardImpl { + + private static final String ALTERNATIVE_COST_DESCRIPTION = "You may exile a blue card with converted mana cost X from your hand rather than pay Disrupting Shoal's mana cost"; + private static final FilterCard filter = new FilterCard("blue card from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLUE)); + filter.add(new OwnerPredicate(Constants.TargetController.YOU)); + } + + public DisruptingShoal(UUID ownerId) { + super(ownerId, 33, "Disrupting Shoal", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{X}{U}{U}"); + this.expansionSetCode = "BOK"; + this.subtype.add("Arcane"); + this.color.setBlue(true); + + // You may exile a blue card with converted mana cost X from your hand rather than pay Disrupting Shoal's mana cost. + this.getSpellAbility().addAlternativeCost(new AlternativeCostImpl(ALTERNATIVE_COST_DESCRIPTION, new ExileFromHandCost(new TargetCardInHand(filter)))); + + // 2/1/2005: Disrupting Shoal can target any spell, but does nothing unless that spell's converted mana cost is X. + // Counter target spell if its converted mana cost is X. + this.getSpellAbility().addEffect(new DisruptingShoalCounterTargetEffect()); + this.getSpellAbility().addTarget(new TargetSpell()); + } + + public DisruptingShoal(final DisruptingShoal card) { + super(card); + } + + @Override + public DisruptingShoal copy() { + return new DisruptingShoal(this); + } +} +// ConvertedManaExileFromHandOrVariableManaValue +class DisruptingShoalVariableValue implements DynamicValue { + @Override + public int calculate(Game game, Ability sourceAbility) { + for (AlternativeCost aCost: (List) sourceAbility.getAlternativeCosts()) { + if (aCost.isPaid()) { + for (int x=0; x < ((Costs) aCost).size(); x++) { + Cost cost = (Cost) ((Costs) aCost).get(x); + if (cost instanceof ExileFromHandCost) { + int xValue = 0; + for (Card card : ((ExileFromHandCost) cost).getCards()) { + xValue += card.getManaCost().convertedManaCost(); + } + return xValue; + } + } + } + } + return sourceAbility.getManaCostsToPay().getX(); + } + + @Override + public DynamicValue clone() { + return new DisruptingShoalVariableValue(); + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return ""; + } +} + +class DisruptingShoalCounterTargetEffect extends OneShotEffect { + + public DisruptingShoalCounterTargetEffect() { + super(Outcome.Detriment); + } + + public DisruptingShoalCounterTargetEffect(final DisruptingShoalCounterTargetEffect effect) { + super(effect); + } + + @Override + public DisruptingShoalCounterTargetEffect copy() { + return new DisruptingShoalCounterTargetEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + DynamicValue amount = new DisruptingShoalVariableValue(); + Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); + if (spell != null && spell.getManaCost().convertedManaCost() == amount.calculate(game, source)) { + return game.getStack().counter(source.getFirstTarget(), source.getSourceId(), game); + } + return false; + } + + @Override + public String getText(Mode mode) { + return "Counter target spell if its converted mana cost is X"; + } + +} diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/FirstVolley.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/FirstVolley.java new file mode 100644 index 00000000000..9fe4a15d0a4 --- /dev/null +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/FirstVolley.java @@ -0,0 +1,99 @@ +/* + * 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 LIAB8LE 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.betrayersofkamigawa; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Outcome; +import mage.Constants.Rarity; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class FirstVolley extends CardImpl { + + public FirstVolley(UUID ownerId) { + super(ownerId, 100, "First Volley", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{R}"); + this.expansionSetCode = "BOK"; + this.subtype.add("Arcane"); + this.color.setRed(true); + + // First Volley deals 1 damage to target creature and 1 damage to that creature's controller. + this.getSpellAbility().addEffect(new FirstVolleyEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + } + + public FirstVolley(final FirstVolley card) { + super(card); + } + + @Override + public FirstVolley copy() { + return new FirstVolley(this); + } +} + +class FirstVolleyEffect extends OneShotEffect { + + public FirstVolleyEffect() { + super(Outcome.Damage); + this.staticText = "{this} deals 1 damage to target creature and 1 damage to that creature's controller"; + } + + public FirstVolleyEffect(final FirstVolleyEffect effect) { + super(effect); + } + + @Override + public FirstVolleyEffect copy() { + return new FirstVolleyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); + if (permanent != null) { + Player controller = game.getPlayer(permanent.getControllerId()); + if (controller != null) { + permanent.damage(1, source.getSourceId(), game, true, false); + controller.damage(1, source.getSourceId(), game, false, true); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/NourishingShoal.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/NourishingShoal.java new file mode 100644 index 00000000000..d12491dbe60 --- /dev/null +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/NourishingShoal.java @@ -0,0 +1,126 @@ +/* + * 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 LIAB8LE 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.betrayersofkamigawa; + +import java.util.List; +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.costs.AlternativeCost; +import mage.abilities.costs.AlternativeCostImpl; +import mage.abilities.costs.Cost; +import mage.abilities.costs.Costs; +import mage.abilities.costs.common.ExileFromHandCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.other.OwnerPredicate; +import mage.game.Game; +import mage.target.common.TargetCardInHand; + +/** + * + * @author LevelX2 + */ +public class NourishingShoal extends CardImpl { + + private static final String ALTERNATIVE_COST_DESCRIPTION = "You may exile a green card with converted mana cost X from your hand rather than pay Nourishing Shoal's mana cost"; + private static final FilterCard filter = new FilterCard("green card from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.GREEN)); + filter.add(new OwnerPredicate(Constants.TargetController.YOU)); + } + + public NourishingShoal(UUID ownerId) { + super(ownerId, 137, "Nourishing Shoal", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{X}{G}{G}"); + this.expansionSetCode = "BOK"; + this.subtype.add("Arcane"); + this.color.setGreen(true); + + // You may exile a green card with converted mana cost X from your hand rather than pay Nourishing Shoal's mana cost. + this.getSpellAbility().addAlternativeCost(new AlternativeCostImpl(ALTERNATIVE_COST_DESCRIPTION, new ExileFromHandCost(new TargetCardInHand(filter)))); + + // You gain X life. + this.getSpellAbility().addEffect(new GainLifeEffect(new NourishingShoalVariableValue())); + + } + + public NourishingShoal(final NourishingShoal card) { + super(card); + } + + @Override + public NourishingShoal copy() { + return new NourishingShoal(this); + } +} + +class NourishingShoalVariableValue implements DynamicValue { + @Override + public int calculate(Game game, Ability sourceAbility) { + List aCosts = sourceAbility.getAlternativeCosts(); + for (AlternativeCost aCost: aCosts) { + if (aCost.isPaid()) { + Costs aCostsList = (Costs) aCost; + for (int x=0; x < aCostsList.size(); x++) { + Cost cost = (Cost) aCostsList.get(x); + if (cost instanceof ExileFromHandCost) { + int xMana = 0; + for (Card card : ((ExileFromHandCost) cost).getCards()) { + xMana += card.getManaCost().convertedManaCost(); + } + return xMana; + } + } + } + } + return sourceAbility.getManaCostsToPay().getX(); + } + + @Override + public DynamicValue clone() { + return new NourishingShoalVariableValue(); + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return ""; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/OpalEyeKondasYojimbo.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/OpalEyeKondasYojimbo.java new file mode 100644 index 00000000000..1813a07c3e0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/OpalEyeKondasYojimbo.java @@ -0,0 +1,212 @@ +/* + * 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.betrayersofkamigawa; + +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Outcome; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.MageInt; +import mage.MageObject; +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.PreventionEffectImpl; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.keyword.BushidoAbility; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.game.Game; +import mage.game.events.DamageEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetSource; + +/** + * @author LevelX2 + */ +public class OpalEyeKondasYojimbo extends CardImpl { + + public OpalEyeKondasYojimbo(UUID ownerId) { + super(ownerId, 17, "Opal-Eye, Konda's Yojimbo", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); + this.expansionSetCode = "BOK"; + this.supertype.add("Legendary"); + this.subtype.add("Fox"); + this.subtype.add("Samurai"); + this.color.setWhite(true); + this.power = new MageInt(1); + this.toughness = new MageInt(4); + + // Defender (This creature can't attack.) + this.addAbility(DefenderAbility.getInstance()); + + // Bushido 1 (When this blocks or becomes blocked, it gets +1/+1 until end of turn.) + this.addAbility(new BushidoAbility(1)); + + // {T}: The next time a source of your choice would deal damage this turn, that damage is dealt to Opal-Eye, Konda's Yojimbo instead. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new OpalEyeKondasYojimboRedirectionEffect(), new TapSourceCost()); + ability.addTarget(new TargetSource()); + this.addAbility(ability); + + // {1}{W}: Prevent the next 1 damage that would be dealt to Opal-Eye this turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new OpalEyeKondasYojimboPreventEffect(), new ManaCostsImpl("{1}{W}"))); + + } + + public OpalEyeKondasYojimbo(final OpalEyeKondasYojimbo card) { + super(card); + } + + @Override + public OpalEyeKondasYojimbo copy() { + return new OpalEyeKondasYojimbo(this); + } +} + +class OpalEyeKondasYojimboRedirectionEffect extends ReplacementEffectImpl { + + OpalEyeKondasYojimboRedirectionEffect() { + super(Constants.Duration.EndOfTurn, Outcome.RedirectDamage); + staticText = "The next time a source of your choice would deal damage this turn, that damage is dealt to {this} instead"; + } + + OpalEyeKondasYojimboRedirectionEffect(final OpalEyeKondasYojimboRedirectionEffect effect) { + super(effect); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (!this.used) { + if (event.getType().equals(GameEvent.EventType.DAMAGE_CREATURE ) || + event.getType().equals(GameEvent.EventType.DAMAGE_PLANESWALKER ) || + event.getType().equals(GameEvent.EventType.DAMAGE_PLAYER ) ) { + if (event.getSourceId().equals(targetPointer.getFirst(game, source))) { + // check source + MageObject object = game.getObject(event.getSourceId()); + if (object == null) { + game.informPlayers("Couldn't find source of damage"); + return false; + } + return true; + } + } + } + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + DamageEvent damageEvent = (DamageEvent)event; + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (sourcePermanent != null) { + // get name of old target + Permanent targetPermanent = game.getPermanent(event.getTargetId()); + StringBuilder message = new StringBuilder(); + message.append(sourcePermanent.getName()).append(": gets "); + message.append(damageEvent.getAmount()).append(" damage redirected from "); + if (targetPermanent != null) { + message.append(targetPermanent.getName()); + } + else { + Player targetPlayer = game.getPlayer(event.getTargetId()); + if (targetPlayer != null) { + message.append(targetPlayer.getName()); + } + else { + message.append("unknown"); + } + } + game.informPlayers(message.toString()); + // remember redirection effect (614.5) + event.getAppliedEffects().add(getId()); + // redirect damage + this.used = true; + sourcePermanent.damage(damageEvent.getAmount(), damageEvent.getSourceId(), game, damageEvent.isPreventable(), damageEvent.isCombatDamage(), event.getAppliedEffects()); + return true; + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public OpalEyeKondasYojimboRedirectionEffect copy() { + return new OpalEyeKondasYojimboRedirectionEffect(this); + } +} + +class OpalEyeKondasYojimboPreventEffect extends PreventionEffectImpl { + + public OpalEyeKondasYojimboPreventEffect() { + super(Constants.Duration.EndOfTurn); + staticText = "Prevent the next 1 damage that would be dealt to {this} this turn"; + } + + public OpalEyeKondasYojimboPreventEffect(final OpalEyeKondasYojimboPreventEffect effect) { + super(effect); + } + + @Override + public OpalEyeKondasYojimboPreventEffect copy() { + return new OpalEyeKondasYojimboPreventEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + GameEvent preventEvent = new GameEvent(GameEvent.EventType.PREVENT_DAMAGE, source.getFirstTarget(), source.getId(), source.getControllerId(), event.getAmount(), false); + if (!game.replaceEvent(preventEvent)) { + if (event.getAmount() >= 1) { + int damage = 1; + event.setAmount(event.getAmount() - 1); + this.used = true; + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, source.getFirstTarget(), source.getId(), source.getControllerId(), damage)); + } + } + return false; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (!this.used && super.applies(event, source, game) && event.getTargetId().equals(source.getSourceId())) { + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheAkki.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheAkki.java new file mode 100644 index 00000000000..f367d787ab3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheAkki.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.betrayersofkamigawa; + +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.continious.BoostControlledEffect; +import mage.abilities.keyword.OfferingAbility; +import mage.cards.CardImpl; +import mage.filter.common.FilterCreaturePermanent; + + +/** + * @author LevelX2 + */ +public class PatronOfTheAkki extends CardImpl { + + public PatronOfTheAkki(UUID ownerId) { + super(ownerId, 115, "Patron of the Akki", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{4}{R}{R}"); + this.expansionSetCode = "BOK"; + this.supertype.add("Legendary"); + this.subtype.add("Spirit"); + this.color.setRed(true); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Goblin offering (You may cast this card any time you could cast an instant by sacrificing a Goblin and paying the difference in mana costs between this and the sacrificed Goblin. Mana cost includes color.) + this.addAbility(new OfferingAbility("Goblin")); + + // Whenever Patron of the Akki attacks, creatures you control get +2/+0 until end of turn. + this.addAbility(new AttacksTriggeredAbility(new BoostControlledEffect(2, 0, Constants.Duration.EndOfTurn, new FilterCreaturePermanent(), false), false)); + } + + public PatronOfTheAkki(final PatronOfTheAkki card) { + super(card); + } + + @Override + public PatronOfTheAkki copy() { + return new PatronOfTheAkki(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheKitsune.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheKitsune.java new file mode 100644 index 00000000000..ad849976529 --- /dev/null +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheKitsune.java @@ -0,0 +1,102 @@ +/* + * 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.betrayersofkamigawa; + +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.keyword.OfferingAbility; +import mage.cards.CardImpl; +import mage.game.Game; +import mage.game.events.GameEvent; + + +/** + * @author LevelX2 + */ +public class PatronOfTheKitsune extends CardImpl { + + public PatronOfTheKitsune(UUID ownerId) { + super(ownerId, 19, "Patron of the Kitsune", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{4}{W}{W}"); + this.expansionSetCode = "BOK"; + this.supertype.add("Legendary"); + this.subtype.add("Spirit"); + this.color.setWhite(true); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Fox offering (You may cast this card any time you could cast an instant by sacrificing a Fox and paying the difference in mana costs between this and the sacrificed Fox. Mana cost includes color.) + this.addAbility(new OfferingAbility("Fox")); + + // Whenever a creature attacks, you may gain 1 life. + this.addAbility(new PatronOfTheKitsuneTriggeredAbility()); + } + + public PatronOfTheKitsune(final PatronOfTheKitsune card) { + super(card); + } + + @Override + public PatronOfTheKitsune copy() { + return new PatronOfTheKitsune(this); + } +} + +class PatronOfTheKitsuneTriggeredAbility extends TriggeredAbilityImpl { + + public PatronOfTheKitsuneTriggeredAbility() { + super(Constants.Zone.BATTLEFIELD, new GainLifeEffect(1), true); + } + + public PatronOfTheKitsuneTriggeredAbility(PatronOfTheKitsuneTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED) { + return true; + } + return false; + } + + @Override + public PatronOfTheKitsuneTriggeredAbility copy() { + return new PatronOfTheKitsuneTriggeredAbility(this); + } + + @Override + public String getRule() { + return "Whenever a creature attacks, " + super.getRule(); + } + +} diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheMoon.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheMoon.java new file mode 100644 index 00000000000..67179c36b25 --- /dev/null +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheMoon.java @@ -0,0 +1,116 @@ +/* + * 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.betrayersofkamigawa; + +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.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.OfferingAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.filter.common.FilterLandCard; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCardInHand; + + +/** + * @author LevelX2 + */ +public class PatronOfTheMoon extends CardImpl { + + public PatronOfTheMoon(UUID ownerId) { + super(ownerId, 45, "Patron of the Moon", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{5}{U}{U}"); + this.expansionSetCode = "BOK"; + this.supertype.add("Legendary"); + this.subtype.add("Spirit"); + this.color.setBlue(true); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // Moonfolk offering (You may cast this card any time you could cast an instant by sacrificing a Moonfolk and paying the difference in mana costs between this and the sacrificed Moonfolk. Mana cost includes color.) + this.addAbility(new OfferingAbility("Moonfolk")); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {1}: Put up to two land cards from your hand onto the battlefield tapped. + Ability ability = new SimpleActivatedAbility(Constants.Zone.BATTLEFIELD, new PatronOfTheMoonEffect(), new ManaCostsImpl("{1}")); + ability.addTarget(new TargetCardInHand(0,2, new FilterLandCard())); + this.addAbility(ability); + + } + + public PatronOfTheMoon(final PatronOfTheMoon card) { + super(card); + } + + @Override + public PatronOfTheMoon copy() { + return new PatronOfTheMoon(this); + } +} + +class PatronOfTheMoonEffect extends OneShotEffect { + PatronOfTheMoonEffect() { + super(Constants.Outcome.PutLandInPlay); + staticText = "Put up to two land cards from your hand onto the battlefield tapped"; + } + + PatronOfTheMoonEffect(final PatronOfTheMoonEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID cardId : targetPointer.getTargets(game, source)) { + Card c = game.getCard(cardId); + if (c != null) { + c.moveToZone(Constants.Zone.BATTLEFIELD, source.getSourceId(), game, false); + Permanent land = game.getPermanent(cardId); + if (land != null) { + land.setTapped(true); + } + } + } + return true; + } + + @Override + public PatronOfTheMoonEffect copy() { + return new PatronOfTheMoonEffect(this); + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheNezumi.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheNezumi.java new file mode 100644 index 00000000000..71400ef8130 --- /dev/null +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheNezumi.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.betrayersofkamigawa; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.keyword.OfferingAbility; +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.events.ZoneChangeEvent; +import mage.target.targetpointer.FixedTarget; + + +/** + * @author LevelX2 + */ +public class PatronOfTheNezumi extends CardImpl { + + public PatronOfTheNezumi(UUID ownerId) { + super(ownerId, 77, "Patron of the Nezumi", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{5}{B}{B}"); + this.expansionSetCode = "BOK"; + this.supertype.add("Legendary"); + this.subtype.add("Spirit"); + this.color.setBlack(true); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Rat offering (You may cast this card any time you could cast an instant by sacrificing a Rat and paying the difference in mana costs between this and the sacrificed Rat. Mana cost includes color.) + this.addAbility(new OfferingAbility("Rat")); + + // Whenever a permanent is put into an opponent's graveyard, that player loses 1 life. + this.addAbility(new PatronOfTheNezumiTriggeredAbility(new LoseLifeTargetEffect(1))); + + } + + public PatronOfTheNezumi(final PatronOfTheNezumi card) { + super(card); + } + + @Override + public PatronOfTheNezumi copy() { + return new PatronOfTheNezumi(this); + } +} + +class PatronOfTheNezumiTriggeredAbility extends TriggeredAbilityImpl { + + public PatronOfTheNezumiTriggeredAbility(Effect effect) { + super(Zone.BATTLEFIELD, effect, false); + } + + public PatronOfTheNezumiTriggeredAbility(final PatronOfTheNezumiTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == EventType.ZONE_CHANGE) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getFromZone() == Zone.BATTLEFIELD + && zEvent.getToZone() == Zone.GRAVEYARD) { + Card card = game.getCard(zEvent.getTargetId()); + if (card != null && game.getOpponents(controllerId).contains(card.getOwnerId())) { + this.getEffects().get(0).setTargetPointer(new FixedTarget(zEvent.getPlayerId())); + return true; + } + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever a permanent is put into an opponent's graveyard, that player loses 1 life."; + } + + @Override + public PatronOfTheNezumiTriggeredAbility copy() { + return new PatronOfTheNezumiTriggeredAbility(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheOrochi.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheOrochi.java new file mode 100644 index 00000000000..6e7176874ea --- /dev/null +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/PatronOfTheOrochi.java @@ -0,0 +1,120 @@ +/* + * 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.betrayersofkamigawa; + +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.ActivateOncePerTurnActivatedAbility; +import mage.abilities.effects.OneShotEffect; +import mage.ObjectColor; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.keyword.OfferingAbility; +import mage.cards.CardImpl; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + + +/** + * @author LevelX2 + */ +public class PatronOfTheOrochi extends CardImpl { + + public PatronOfTheOrochi(UUID ownerId) { + super(ownerId, 138, "Patron of the Orochi", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{6}{G}{G}"); + this.expansionSetCode = "BOK"; + this.supertype.add("Legendary"); + this.subtype.add("Spirit"); + this.color.setGreen(true); + this.power = new MageInt(7); + this.toughness = new MageInt(7); + + // Snake offering (You may cast this card any time you could cast an instant by sacrificing a Snake and paying the difference in mana costs between this and the sacrificed Snake. Mana cost includes color.) + this.addAbility(new OfferingAbility("Snake")); + + // {T}: Untap all Forests and all green creatures. Activate this ability only once each turn. + this.addAbility(new ActivateOncePerTurnActivatedAbility(Constants.Zone.BATTLEFIELD, new PatronOfTheOrochiEffect(), new TapSourceCost())); + + } + + public PatronOfTheOrochi(final PatronOfTheOrochi card) { + super(card); + } + + @Override + public PatronOfTheOrochi copy() { + return new PatronOfTheOrochi(this); + } +} + +class PatronOfTheOrochiEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterPermanent(); + static { + filter.add(Predicates.or( new NamePredicate("Forest"), + Predicates.and(new CardTypePredicate(CardType.CREATURE), + new ColorPredicate(ObjectColor.GREEN)) + )); + } + + public PatronOfTheOrochiEffect() { + super(Constants.Outcome.Untap); + staticText = "Untap all Forests and all green creatures"; + } + + public PatronOfTheOrochiEffect(final PatronOfTheOrochiEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + for (Permanent permanent: game.getBattlefield().getAllActivePermanents(filter, game)) { + permanent.untap(game); + } + return true; + } + return false; + } + + @Override + public PatronOfTheOrochiEffect copy() { + return new PatronOfTheOrochiEffect(this); + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/ShiningShoal.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/ShiningShoal.java new file mode 100644 index 00000000000..fff50d5cf05 --- /dev/null +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/ShiningShoal.java @@ -0,0 +1,244 @@ +/* + * 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 LIAB8LE 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.betrayersofkamigawa; + +import java.util.List; +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.MageObject; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.costs.AlternativeCost; +import mage.abilities.costs.AlternativeCostImpl; +import mage.abilities.costs.Cost; +import mage.abilities.costs.Costs; +import mage.abilities.costs.common.ExileFromHandCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.PreventionEffectImpl; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.other.OwnerPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetSource; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author LevelX2 + */ +public class ShiningShoal extends CardImpl { + + private static final String ALTERNATIVE_COST_DESCRIPTION = "You may exile a white card with converted mana cost X from your hand rather than pay Shining Shoal's mana cost"; + private static final FilterCard filter = new FilterCard("white card from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.WHITE)); + filter.add(new OwnerPredicate(Constants.TargetController.YOU)); + } + + public ShiningShoal(UUID ownerId) { + super(ownerId, 21, "Shining Shoal", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{X}{W}{W}"); + this.expansionSetCode = "BOK"; + this.subtype.add("Arcane"); + this.color.setWhite(true); + + // You may exile a white card with converted mana cost X from your hand rather than pay Shining Shoal's mana cost + this.getSpellAbility().addAlternativeCost(new AlternativeCostImpl(ALTERNATIVE_COST_DESCRIPTION, new ExileFromHandCost(new TargetCardInHand(filter)))); + + // The next X damage that a source of your choice would deal to you and/or creatures you control this turn is dealt to target creature or player instead. + this.getSpellAbility().addEffect(new ShiningShoalPreventDamageTargetEffect(Constants.Duration.EndOfTurn, new ShiningShoalVariableValue())); + this.getSpellAbility().addTarget(new TargetSource()); + this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); + } + + public ShiningShoal(final ShiningShoal card) { + super(card); + } + + @Override + public ShiningShoal copy() { + return new ShiningShoal(this); + } +} + +class ShiningShoalVariableValue implements DynamicValue { + @Override + public int calculate(Game game, Ability sourceAbility) { + List aCosts = sourceAbility.getAlternativeCosts(); + for (AlternativeCost aCost: aCosts) { + if (aCost.isPaid()) { + Costs aCostsList = (Costs) aCost; + for (int x=0; x < aCostsList.size(); x++) { + Cost cost = (Cost) aCostsList.get(x); + if (cost instanceof ExileFromHandCost) { + int xMana = 0; + for (Card card : ((ExileFromHandCost) cost).getCards()) { + xMana += card.getManaCost().convertedManaCost(); + } + return xMana; + } + } + } + } + return sourceAbility.getManaCostsToPay().getX(); + } + + @Override + public DynamicValue clone() { + return new ShiningShoalVariableValue(); + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return ""; + } +} + +class ShiningShoalPreventDamageTargetEffect extends PreventionEffectImpl { + + private DynamicValue dynamicAmount; + private int amount; + + public ShiningShoalPreventDamageTargetEffect(Constants.Duration duration, DynamicValue dynamicAmount) { + super(duration); + this.dynamicAmount = dynamicAmount; + staticText = "The next X damage that a source of your choice would deal to you and/or creatures you control this turn is dealt to target creature or player instead"; + } + + public ShiningShoalPreventDamageTargetEffect(final ShiningShoalPreventDamageTargetEffect effect) { + super(effect); + this.amount = effect.amount; + this.dynamicAmount = effect.dynamicAmount; + } + + @Override + public ShiningShoalPreventDamageTargetEffect copy() { + return new ShiningShoalPreventDamageTargetEffect(this); + } + + @Override + public void init(Ability source, Game game) { + this.amount = dynamicAmount.calculate(game, source); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + GameEvent preventEvent = new GameEvent(GameEvent.EventType.PREVENT_DAMAGE, source.getFirstTarget(), source.getId(), source.getControllerId(), event.getAmount(), false); + if (!game.replaceEvent(preventEvent)) { + int prevented = 0; + if (event.getAmount() >= this.amount) { + int damage = amount; + event.setAmount(event.getAmount() - amount); + this.used = true; + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, source.getFirstTarget(), source.getId(), source.getControllerId(), damage)); + prevented = damage; + } else { + int damage = event.getAmount(); + event.setAmount(0); + amount -= damage; + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, source.getFirstTarget(), source.getId(), source.getControllerId(), damage)); + prevented = damage; + } + + // deal damage now + if (prevented > 0) { + UUID redirectTo = source.getTargets().get(1).getFirstTarget(); + Permanent permanent = game.getPermanent(redirectTo); + if (permanent != null) { + game.informPlayers("Dealing " + prevented + " to " + permanent.getName() + " instead"); + // keep the original source id as it is redirecting + event.getAppliedEffects().add(getId()); + permanent.damage(prevented, event.getSourceId(), game, true, false, event.getAppliedEffects()); + } + Player player = game.getPlayer(redirectTo); + if (player != null) { + game.informPlayers("Dealing " + prevented + " to " + player.getName() + " instead"); + // keep the original source id as it is redirecting + event.getAppliedEffects().add(getId()); + player.damage(prevented, event.getSourceId(), game, true, false, event.getAppliedEffects()); + } + } + } + return false; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (!this.used && super.applies(event, source, game) && !event.getAppliedEffects().contains(getId())) { + + // check source + MageObject object = game.getObject(event.getSourceId()); + if (object == null) { + game.informPlayers("Couldn't find source of damage"); + return false; + } + + if (!object.getId().equals(source.getFirstTarget())) { + return false; + } + + // check target + // check creature first + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent != null && permanent.getCardType().contains(CardType.CREATURE)) { + if (permanent.getControllerId().equals(source.getControllerId())) { + // it's your creature + return true; + } + } + // check player + Player player = game.getPlayer(event.getTargetId()); + if (player != null) { + if (player.getId().equals(source.getControllerId())) { + // it is you + return true; + } + } + } + return false; + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/SickeningShoal.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/SickeningShoal.java new file mode 100644 index 00000000000..f0a94eaf38c --- /dev/null +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/SickeningShoal.java @@ -0,0 +1,127 @@ +/* + * 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 LIAB8LE 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.betrayersofkamigawa; + +import java.util.List; +import java.util.UUID; +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.costs.AlternativeCost; +import mage.abilities.costs.AlternativeCostImpl; +import mage.abilities.costs.Cost; +import mage.abilities.costs.Costs; +import mage.abilities.costs.common.ExileFromHandCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; +import mage.abilities.effects.common.continious.BoostTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.other.OwnerPredicate; +import mage.game.Game; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class SickeningShoal extends CardImpl { + + private static final String ALTERNATIVE_COST_DESCRIPTION = "You may exile a black card with converted mana cost X from your hand rather than pay Sickening Shoal's mana cost"; + private static final FilterCard filter = new FilterCard("black card from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + filter.add(new OwnerPredicate(Constants.TargetController.YOU)); + } + + public SickeningShoal(UUID ownerId) { + super(ownerId, 82, "Sickening Shoal", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{X}{B}{B}"); + this.expansionSetCode = "BOK"; + this.subtype.add("Arcane"); + this.color.setBlack(true); + + // You may exile a black card with converted mana cost X from your hand rather than pay Sickening Shoal's mana cost. + this.getSpellAbility().addAlternativeCost(new AlternativeCostImpl(ALTERNATIVE_COST_DESCRIPTION, new ExileFromHandCost(new TargetCardInHand(filter)))); + + // Target creature gets -X/-X until end of turn. + DynamicValue x = new SignInversionDynamicValue(new SickeningShoalVariableValue()); + this.getSpellAbility().addEffect(new BoostTargetEffect(x, x, Constants.Duration.EndOfTurn, true)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public SickeningShoal(final SickeningShoal card) { + super(card); + } + + @Override + public SickeningShoal copy() { + return new SickeningShoal(this); + } +} +// ConvertedManaExileFromHandOrVariableManaValue +class SickeningShoalVariableValue implements DynamicValue { + @Override + public int calculate(Game game, Ability sourceAbility) { + for (AlternativeCost aCost: (List) sourceAbility.getAlternativeCosts()) { + if (aCost.isPaid()) { + for (int x=0; x < ((Costs) aCost).size(); x++) { + Cost cost = (Cost) ((Costs) aCost).get(x); + if (cost instanceof ExileFromHandCost) { + int xValue = 0; + for (Card card : ((ExileFromHandCost) cost).getCards()) { + xValue += card.getManaCost().convertedManaCost(); + } + return xValue; + } + } + } + } + return sourceAbility.getManaCostsToPay().getX(); + } + + @Override + public DynamicValue clone() { + return new SickeningShoalVariableValue(); + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return ""; + } +} \ No newline at end of file