diff --git a/Mage.Sets/src/mage/cards/b/BenalishMarshal.java b/Mage.Sets/src/mage/cards/b/BenalishMarshal.java new file mode 100644 index 00000000000..c89f1273e1b --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BenalishMarshal.java @@ -0,0 +1,38 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; + +import java.util.UUID; + +public class BenalishMarshal extends CardImpl { + + public BenalishMarshal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}{W}"); + subtype.add(SubType.HUMAN); + subtype.add(SubType.KNIGHT); + power = new MageInt(3); + toughness = new MageInt(3); + + // Other creatures you control get +1/+1. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, true))); + + } + + + public BenalishMarshal(BenalishMarshal benalishMarshall) { + super(benalishMarshall); + } + + @Override + public BenalishMarshal copy() { + return new BenalishMarshal(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/Charge.java b/Mage.Sets/src/mage/cards/c/Charge.java new file mode 100644 index 00000000000..e9146dffa44 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/Charge.java @@ -0,0 +1,30 @@ +package mage.cards.c; + +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; + +import java.util.UUID; + +public class Charge extends CardImpl { + + public Charge(UUID ownerId, CardSetInfo cardSetInfo){ + super(ownerId, cardSetInfo, new CardType[]{CardType.INSTANT}, "{W}"); + + // Creatures you control get +1/+1 until end of turn. + this.getSpellAbility().addEffect(new BoostControlledEffect(1, 1, Duration.EndOfTurn)); + + } + + + public Charge(final Charge charge){ + super(charge); + } + + @Override + public Charge copy(){ + return new Charge(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KnightOfGrace.java b/Mage.Sets/src/mage/cards/k/KnightOfGrace.java new file mode 100644 index 00000000000..235258e9506 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KnightOfGrace.java @@ -0,0 +1,63 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.AnyPlayerControlsCondition; +import mage.abilities.condition.common.DefendingPlayerControlsCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.BoostSourceWhileControlsEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.HexproofFromBlackAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.ColorPredicate; + +import java.util.UUID; + +public class KnightOfGrace extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("black permanent"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + } + + public KnightOfGrace(UUID ownerId, CardSetInfo cardSetInfo) { + super(ownerId, cardSetInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + subtype.add(SubType.HUMAN); + subtype.add(SubType.KNIGHT); + power = new MageInt(2); + toughness = new MageInt(2); + addAbility(FirstStrikeAbility.getInstance()); + addAbility(HexproofFromBlackAbility.getInstance()); + + + //Knight of Grace gets +1/+0 as long as any player controls a black permanent. + addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new BoostControlledEffect(1, 0, Duration.WhileOnBattlefield), + new AnyPlayerControlsCondition(filter), + "{this} gets +1/+0 as long as any player controls a black permanent."))); + + + + + + } + + public KnightOfGrace(final KnightOfGrace knightOfGrace){ + super(knightOfGrace); + } + + public KnightOfGrace copy(){ + return new KnightOfGrace(this); + } + + +} diff --git a/Mage.Sets/src/mage/sets/Dominaria.java b/Mage.Sets/src/mage/sets/Dominaria.java index 998ba6047e6..75192767a27 100644 --- a/Mage.Sets/src/mage/sets/Dominaria.java +++ b/Mage.Sets/src/mage/sets/Dominaria.java @@ -1,37 +1,37 @@ /* -* 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. + * 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; import mage.cards.ExpansionSet; +import mage.constants.Rarity; import mage.constants.SetType; /** - * * @author fireshoes */ public class Dominaria extends ExpansionSet { @@ -51,5 +51,9 @@ public class Dominaria extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; + + cards.add(new SetCardInfo("Benalish Marshal", 10, Rarity.UNCOMMON, mage.cards.b.BenalishMarshal.class)); + cards.add(new SetCardInfo("Charge", 11, Rarity.COMMON, mage.cards.c.Charge.class)); + cards.add(new SetCardInfo("Knight of Grace", 12, Rarity.UNCOMMON, mage.cards.k.KnightOfGrace.class)); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/dom/SimpleDominariaCards.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/dom/SimpleDominariaCards.java new file mode 100644 index 00000000000..be434c01182 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/dom/SimpleDominariaCards.java @@ -0,0 +1,87 @@ +package org.mage.test.cards.single.dom; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +public class SimpleDominariaCards extends CardTestPlayerBase { + + @Test + public void benalishMarshall(){ + addCard(Zone.BATTLEFIELD, playerA, "Benalish Marshal", 1); + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1); + addCard(Zone.BATTLEFIELD, playerB, "Wood Elves", 1); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPowerToughness(playerA, "Benalish Marshal", 3, 3); + assertPowerToughness(playerA, "Grizzly Bears", 3, 3); + assertPowerToughness(playerB, "Wood Elves", 1, 1); + } + + @Test + public void testCharge(){ + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1); + addCard(Zone.BATTLEFIELD, playerB, "Wood Elves", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.HAND, playerA, "Charge", 1); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Charge"); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertPowerToughness(playerA, "Grizzly Bears", 3, 3); + assertPowerToughness(playerB, "Wood Elves", 1, 1); + } + + @Test + public void testKnightOfGraceBlackSpell(){ + addCard(Zone.BATTLEFIELD, playerA, "Knight of Grace"); + addCard(Zone.HAND, playerB, "Terror"); + addCard(Zone.BATTLEFIELD, playerB, "Swamp", 3); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Terror", "Knight of Grace"); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerA, "Knight of Grace", 0); + } + + @Test + public void testKnightOfGraceRedSpell(){ + addCard(Zone.BATTLEFIELD, playerA, "Knight of Grace"); + addCard(Zone.HAND, playerB, "Geistflame"); + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 3); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Geistflame", "Knight of Grace"); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerA, "Knight of Grace", 0); + assertDamageReceived(playerA, "Knight of Grace", 1); + assertPowerToughness(playerA, "Knight of Grace", 2, 2); + } + + @Test + public void testKnightOfGraceBlackAbility(){ + addCard(Zone.BATTLEFIELD, playerA, "Knight of Grace"); + addCard(Zone.BATTLEFIELD, playerB, "Royal Assassin"); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{T}: ", "Knight of Grace"); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerA, "Knight of Grace", 0); + } + + @Test + public void testKnightOfGraceAnyPlayerControls(){ + addCard(Zone.BATTLEFIELD, playerA, "Knight of Grace"); + addCard(Zone.BATTLEFIELD, playerB, "Royal Assassin"); + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertPowerToughness(playerA, "Knight of Grace", 3, 2); + } +} 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 21e95570f80..c5a01a37418 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 @@ -1299,10 +1299,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } } - public void assertDamageReceived(Player player, String cardName, int amount) { + public void assertDamageReceived(Player player, String cardName, int expected) { Permanent p = getPermanent(cardName, player.getId()); if (p != null) { - Assert.assertEquals(p.getDamage(), amount); + Assert.assertEquals("Wrong damage received: ", expected, p.getDamage()); } } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/AnyPlayerControlsCondition.java b/Mage/src/main/java/mage/abilities/condition/common/AnyPlayerControlsCondition.java new file mode 100644 index 00000000000..a733ee74f0a --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/AnyPlayerControlsCondition.java @@ -0,0 +1,61 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.filter.FilterPermanent; +import mage.game.Game; +import mage.players.Player; + +import java.util.Map; +import java.util.UUID; + +/** + * @author North + */ +public class AnyPlayerControlsCondition implements Condition { + + private final FilterPermanent filter; + + public AnyPlayerControlsCondition(FilterPermanent filter) { + this.filter = filter; + } + + @Override + public boolean apply(Game game, Ability source) { + + for (UUID player : game.getPlayers().keySet()) { + if(player != null && game.getBattlefield().countAll(filter, player, game)> 0){ + return true; + } + + } + return false; + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/HexproofFromBlackAbility.java b/Mage/src/main/java/mage/abilities/keyword/HexproofFromBlackAbility.java new file mode 100644 index 00000000000..80090d6d96b --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/HexproofFromBlackAbility.java @@ -0,0 +1,44 @@ +package mage.abilities.keyword; + +import mage.abilities.MageSingleton; +import mage.abilities.common.SimpleStaticAbility; +import mage.constants.Zone; + +import java.io.ObjectStreamException; + +/** + * Hexproof from black (This creature or player can't be the target of black spells or abilities + * your opponents control.) + * + * @author igoudt + */ +public class HexproofFromBlackAbility extends SimpleStaticAbility implements MageSingleton { + + private static final HexproofFromBlackAbility instance; + + static { + instance = new HexproofFromBlackAbility(); + } + + private Object readResolve() throws ObjectStreamException { + return instance; + } + + public static HexproofFromBlackAbility getInstance() { + return instance; + } + + private HexproofFromBlackAbility() { + super(Zone.BATTLEFIELD, null); + } + + @Override + public HexproofFromBlackAbility copy() { + return instance; + } + + @Override + public String getRule() { + return "hexproof from black"; + } +} diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index 8332a1d8888..57b89875907 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -945,6 +945,16 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { return false; } } + + + if (abilities.containsKey(HexproofFromBlackAbility.getInstance().getId()) ) { + if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game) + && !game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, sourceControllerId, game) + && source.getColor(game).isBlack()) { + return false; + } + } + if (hasProtectionFrom(source, game)) { return false; }