diff --git a/Mage.Sets/src/mage/cards/c/CairnWanderer.java b/Mage.Sets/src/mage/cards/c/CairnWanderer.java new file mode 100644 index 00000000000..720866bacd2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CairnWanderer.java @@ -0,0 +1,150 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.c; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.MageSingleton; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.keyword.ChangelingAbility; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.abilities.keyword.FearAbility; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.LandwalkAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.ProtectionAbility; +import mage.abilities.keyword.ReachAbility; +import mage.abilities.keyword.ShroudAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author psykad + */ +public class CairnWanderer extends CardImpl { + + public CairnWanderer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.subtype.add("Shapeshifter"); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Changeling + this.addAbility(ChangelingAbility.getInstance()); + + // As long as a creature card with flying is in a graveyard, Cairn Wanderer has flying. The same is true for fear, first strike, double strike, deathtouch, haste, landwalk, lifelink, protection, reach, trample, shroud, and vigilance. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CairnWandererEffect())); + } + + public CairnWanderer(final CairnWanderer card) { + super(card); + } + + @Override + public CairnWanderer copy() { + return new CairnWanderer(this); + } + + class CairnWandererEffect extends ContinuousEffectImpl { + + public CairnWandererEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + staticText = "As long as a creature card with flying is in a graveyard, {this} has flying. The same is true for fear, first strike, double strike, deathtouch, haste, landwalk, lifelink, protection, reach, trample, shroud, and vigilance."; + } + + public CairnWandererEffect(final CairnWandererEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + + if (sourcePermanent == null) { + return false; + } + + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + + if (player != null) { + for (Card card : player.getGraveyard().getCards(game)) { + if (card.getCardType().contains(CardType.CREATURE)) { + for (Ability ability : card.getAbilities(game)) { + if (ability instanceof MageSingleton) { + if (ability instanceof FlyingAbility + || ability instanceof FearAbility + || ability instanceof FirstStrikeAbility + || ability instanceof DoubleStrikeAbility + || ability instanceof DeathtouchAbility + || ability instanceof HasteAbility + || ability instanceof LifelinkAbility + || ability instanceof ReachAbility + || ability instanceof TrampleAbility + || ability instanceof ShroudAbility + || ability instanceof VigilanceAbility) { + sourcePermanent.addAbility(ability, game); + } + } else if (ability instanceof ProtectionAbility + || ability instanceof LandwalkAbility) { + sourcePermanent.addAbility(ability, game); + } + } + } + } + } + } + + return true; + } + + @Override + public CairnWandererEffect copy() { + return new CairnWandererEffect(this); + } + } +} diff --git a/Mage.Sets/src/mage/cards/c/CreatureBond.java b/Mage.Sets/src/mage/cards/c/CreatureBond.java index 2c022182861..b88a1283b2f 100644 --- a/Mage.Sets/src/mage/cards/c/CreatureBond.java +++ b/Mage.Sets/src/mage/cards/c/CreatureBond.java @@ -1,113 +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.cards.c; - -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.Mode; -import mage.abilities.common.DiesAttachedTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.keyword.EnchantAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; - -/** - * - * @author Styxo - */ -public class CreatureBond extends CardImpl { - - public CreatureBond(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); - - this.subtype.add("Aura"); - - // Enchant creature - TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.Benefit)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); - - // When enchanted creature dies, Creature Bond deals damage equal to that creature's toughness to the creature's controller. - this.addAbility(new DiesAttachedTriggeredAbility(new CreatureBondEffect(), "enchanted creature")); - - } - - public CreatureBond(final CreatureBond card) { - super(card); - } - - @Override - public CreatureBond copy() { - return new CreatureBond(this); - } -} - -class CreatureBondEffect extends OneShotEffect { - - public CreatureBondEffect() { - super(Outcome.Damage); - } - - public CreatureBondEffect(CreatureBondEffect copy) { - super(copy); - } - - @Override - public CreatureBondEffect copy() { - return new CreatureBondEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent creature = (Permanent) getValue("attachedTo"); - if (creature != null) { - Player player = game.getPlayer(creature.getOwnerId()); - if (player != null) { - player.damage(creature.getToughness().getValue(), source.getId(), game, false, true); - return true; - } - } - return false; - } - - @Override - public String getText(Mode mode) { - return "{this} deals damage equal to that creature's toughness to the creature's controller"; - } - -} +/* + * 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.cards.c; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.DiesAttachedTriggeredAbility; +import mage.abilities.dynamicvalue.common.AttachedPermanentToughnessValue; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DamageAttachedControllerEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author MTGfan + */ +public class CreatureBond extends CardImpl { + + public CreatureBond(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // When enchanted creature dies, Creature Bond deals damage equal to that creature's toughness to the creature's controller. + this.addAbility( new DiesAttachedTriggeredAbility(new DamageAttachedControllerEffect(new AttachedPermanentToughnessValue()), "enchanted creature")); + } + + public CreatureBond(final CreatureBond card) { + super(card); + } + + @Override + public CreatureBond copy() { + return new CreatureBond(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GaeasLiege.java b/Mage.Sets/src/mage/cards/g/GaeasLiege.java index 27ca80114fc..6e17bd4ae84 100644 --- a/Mage.Sets/src/mage/cards/g/GaeasLiege.java +++ b/Mage.Sets/src/mage/cards/g/GaeasLiege.java @@ -32,7 +32,7 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.common.AttackingCondition; +import mage.abilities.condition.common.SourceAttackingCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.dynamicvalue.DynamicValue; @@ -76,7 +76,7 @@ public class GaeasLiege extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.ALL, new ConditionalContinuousEffect( new SetPowerToughnessSourceEffect(new DefendersForestCount(), Duration.EndOfCombat), new SetPowerToughnessSourceEffect(new PermanentsOnBattlefieldCount(filterLands), Duration.EndOfGame), - AttackingCondition.getInstance(), + SourceAttackingCondition.getInstance(), "As long as {this} isn't attacking, its power and toughness are each equal to the number of Forests you control. As long as {this} is attacking, its power and toughness are each equal to the number of Forests defending player controls."))); // {tap}: Target land becomes a Forest until Gaea's Liege leaves the battlefield. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesBasicLandTargetEffect(Duration.WhileOnBattlefield, "Forest"), new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/k/KorScythemaster.java b/Mage.Sets/src/mage/cards/k/KorScythemaster.java index 4f24620ad87..4befcda12a8 100644 --- a/Mage.Sets/src/mage/cards/k/KorScythemaster.java +++ b/Mage.Sets/src/mage/cards/k/KorScythemaster.java @@ -30,7 +30,7 @@ package mage.cards.k; import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.common.SourceMatchesFilterCondition; +import mage.abilities.condition.common.SourceAttackingCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FirstStrikeAbility; @@ -38,7 +38,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; -import mage.filter.common.FilterAttackingCreature; /** * @@ -46,8 +45,6 @@ import mage.filter.common.FilterAttackingCreature; */ public class KorScythemaster extends CardImpl { - private static final String rule = "{this} has first strike as long as it's attacking"; - public KorScythemaster(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); this.subtype.add("Kor"); @@ -57,9 +54,7 @@ public class KorScythemaster extends CardImpl { this.toughness = new MageInt(1); // Kor Scythemaster has first strike as long as its attacking. - ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance()), - new SourceMatchesFilterCondition(new FilterAttackingCreature()), rule); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance()), SourceAttackingCondition.getInstance(), "{this} has first strike as long as it's attacking"))); } public KorScythemaster(final KorScythemaster card) { diff --git a/Mage.Sets/src/mage/cards/s/SoltariLancer.java b/Mage.Sets/src/mage/cards/s/SoltariLancer.java index 62a139d0ddd..62fb1c03663 100644 --- a/Mage.Sets/src/mage/cards/s/SoltariLancer.java +++ b/Mage.Sets/src/mage/cards/s/SoltariLancer.java @@ -30,7 +30,7 @@ package mage.cards.s; import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.common.SourceMatchesFilterCondition; +import mage.abilities.condition.common.SourceAttackingCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FirstStrikeAbility; @@ -39,7 +39,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; -import mage.filter.common.FilterAttackingCreature; /** * @@ -47,8 +46,6 @@ import mage.filter.common.FilterAttackingCreature; */ public class SoltariLancer extends CardImpl { - private static final String rule = "{this} has first strike as long as it's attacking"; - public SoltariLancer(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); this.subtype.add("Soltari"); @@ -60,8 +57,7 @@ public class SoltariLancer extends CardImpl { this.addAbility(ShadowAbility.getInstance()); // Soltari Lancer has first strike as long as it's attacking. - ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance()), new SourceMatchesFilterCondition(new FilterAttackingCreature()), rule); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance()), SourceAttackingCondition.getInstance(), "{this} has first strike as long as it's attacking"))); } public SoltariLancer(final SoltariLancer card) { diff --git a/Mage.Sets/src/mage/cards/s/SpiritOfTheNight.java b/Mage.Sets/src/mage/cards/s/SpiritOfTheNight.java index e39967eb971..e186413d9d0 100644 --- a/Mage.Sets/src/mage/cards/s/SpiritOfTheNight.java +++ b/Mage.Sets/src/mage/cards/s/SpiritOfTheNight.java @@ -31,16 +31,15 @@ import mage.constants.CardType; import mage.MageInt; import mage.ObjectColor; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.common.SourceMatchesFilterCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.Zone; -import mage.filter.common.FilterAttackingCreature; import java.util.UUID; +import mage.abilities.condition.common.SourceAttackingCondition; /** * @@ -48,8 +47,6 @@ import java.util.UUID; */ public class SpiritOfTheNight extends CardImpl { - private static final String rule = "Spirit of the Night has first strike as long as it's attacking"; - public SpiritOfTheNight(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{6}{B}{B}{B}"); this.supertype.add("Legendary"); @@ -72,8 +69,7 @@ public class SpiritOfTheNight extends CardImpl { this.addAbility(ProtectionAbility.from(ObjectColor.BLACK)); // Spirit of the Night has first strike as long as it's attacking. - ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance()), new SourceMatchesFilterCondition(new FilterAttackingCreature()), rule); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance()), SourceAttackingCondition.getInstance(), "{this} has first strike as long as it's attacking"))); } public SpiritOfTheNight(final SpiritOfTheNight card) { diff --git a/Mage.Sets/src/mage/sets/Lorwyn.java b/Mage.Sets/src/mage/sets/Lorwyn.java index 8b99e20d9c3..a911d9f488b 100644 --- a/Mage.Sets/src/mage/sets/Lorwyn.java +++ b/Mage.Sets/src/mage/sets/Lorwyn.java @@ -86,6 +86,7 @@ public class Lorwyn extends ExpansionSet { cards.add(new SetCardInfo("Brion Stoutarm", 246, Rarity.RARE, mage.cards.b.BrionStoutarm.class)); cards.add(new SetCardInfo("Broken Ambitions", 54, Rarity.COMMON, mage.cards.b.BrokenAmbitions.class)); cards.add(new SetCardInfo("Burrenton Forge-Tender", 7, Rarity.UNCOMMON, mage.cards.b.BurrentonForgeTender.class)); + cards.add(new SetCardInfo("Cairn Wanderer", 105, Rarity.RARE, mage.cards.c.CairnWanderer.class)); cards.add(new SetCardInfo("Caterwauling Boggart", 157, Rarity.COMMON, mage.cards.c.CaterwaulingBoggart.class)); cards.add(new SetCardInfo("Ceaseless Searblades", 158, Rarity.UNCOMMON, mage.cards.c.CeaselessSearblades.class)); cards.add(new SetCardInfo("Cenn's Heir", 8, Rarity.COMMON, mage.cards.c.CennsHeir.class)); @@ -260,7 +261,7 @@ public class Lorwyn extends ExpansionSet { cards.add(new SetCardInfo("Profane Command", 135, Rarity.RARE, mage.cards.p.ProfaneCommand.class)); cards.add(new SetCardInfo("Protective Bubble", 80, Rarity.COMMON, mage.cards.p.ProtectiveBubble.class)); cards.add(new SetCardInfo("Prowess of the Fair", 136, Rarity.UNCOMMON, mage.cards.p.ProwessOfTheFair.class)); - cards.add(new SetCardInfo("Purity", 37, Rarity.RARE, mage.cards.p.Purity.class)); + cards.add(new SetCardInfo("Purity", 37, Rarity.RARE, mage.cards.p.Purity.class)); cards.add(new SetCardInfo("Quill-Slinger Boggart", 137, Rarity.COMMON, mage.cards.q.QuillSlingerBoggart.class)); cards.add(new SetCardInfo("Rebellion of the Flamekin", 188, Rarity.UNCOMMON, mage.cards.r.RebellionOfTheFlamekin.class)); cards.add(new SetCardInfo("Ringskipper", 81, Rarity.COMMON, mage.cards.r.Ringskipper.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/lrw/CairnWandererTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/lrw/CairnWandererTest.java new file mode 100644 index 00000000000..2f3e6851fe3 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/lrw/CairnWandererTest.java @@ -0,0 +1,124 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.single.lrw; + +import java.util.ArrayList; +import java.util.List; +import mage.abilities.Ability; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.abilities.keyword.FearAbility; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.PlainswalkAbility; +import mage.abilities.keyword.ProtectionAbility; +import mage.abilities.keyword.ReachAbility; +import mage.abilities.keyword.ShroudAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.constants.Zone; +import mage.filter.FilterCard; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author psykad + */ +public class CairnWandererTest extends CardTestPlayerBase { + + /* + * Testing: As long as a creature card with flying is in a graveyard, + * {this} has flying. The same is true for fear, first strike, + * double strike, deathtouch, haste, landwalk, lifelink, protection, + * reach, trample, shroud, and vigilance. + */ + @Test + public void TestCairnWandererEffect() { + addCard(Zone.BATTLEFIELD, playerA, "Cairn Wanderer"); + + // Testing FlyingAbility. + addCard(Zone.GRAVEYARD, playerA, "Lantern Kami"); + + // Testing FearAbility. + addCard(Zone.GRAVEYARD, playerA, "Prickly Boggart"); + + // Testing FirstStrikeAbility. + addCard(Zone.GRAVEYARD, playerA, "Serra Zealot"); + + // Testing DoubleStrikeAbility. + addCard(Zone.GRAVEYARD, playerA, "Fencing Ace"); + + // Testing DeathtouchAbility. + addCard(Zone.GRAVEYARD, playerA, "Typhoid Rats"); + + // Testing HasteAbility. + addCard(Zone.GRAVEYARD, playerA, "Raging Goblin"); + + // Testing LandwalkAbility. + addCard(Zone.GRAVEYARD, playerA, "Zodiac Rooster"); + + // Testing LifelinkAbility. + addCard(Zone.GRAVEYARD, playerA, "Trained Caracal"); + + // Testing ProtectionAbility. + addCard(Zone.GRAVEYARD, playerA, "Progenitus"); + + // Testing ReachAbility. + addCard(Zone.GRAVEYARD, playerA, "Tree Monkey"); + + // Testing TrampleAbility. + addCard(Zone.GRAVEYARD, playerA, "Defiant Elf"); + + // Testing ShroudAbility. + addCard(Zone.GRAVEYARD, playerA, "Elvish Lookout"); + + // Testing VigilanceAbility. + addCard(Zone.GRAVEYARD, playerA, "Veteran Cavalier"); + + execute(); + + List abilities = new ArrayList<>(); + abilities.add(FlyingAbility.getInstance()); + abilities.add(FearAbility.getInstance()); + abilities.add(FirstStrikeAbility.getInstance()); + abilities.add(DoubleStrikeAbility.getInstance()); + abilities.add(DeathtouchAbility.getInstance()); + abilities.add(HasteAbility.getInstance()); + abilities.add(LifelinkAbility.getInstance()); + abilities.add(ReachAbility.getInstance()); + abilities.add(ShroudAbility.getInstance()); + abilities.add(TrampleAbility.getInstance()); + abilities.add(VigilanceAbility.getInstance()); + assertAbilities(playerA, "Cairn Wanderer", abilities); + assertAbility(playerA, "Cairn Wanderer", new PlainswalkAbility(), true); + assertAbility(playerA, "Cairn Wanderer", new ProtectionAbility(new FilterCard("everything")), true); // Progenitus - protection from everything. + } +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/turnmod/ExtraTurnsTest.java b/Mage.Tests/src/test/java/org/mage/test/turnmod/ExtraTurnsTest.java index 347e271c08e..c7746838f34 100644 --- a/Mage.Tests/src/test/java/org/mage/test/turnmod/ExtraTurnsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/turnmod/ExtraTurnsTest.java @@ -1,70 +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 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.turnmod; - -import mage.constants.PhaseStep; -import mage.constants.Zone; -import org.junit.Assert; -import org.junit.Test; -import org.mage.test.serverside.base.CardTestPlayerBase; - -/** - * - * @author LevelX2 - */ -public class ExtraTurnsTest extends CardTestPlayerBase { - - /** - * Emrakul, the Promised End not giving an extra turn when cast in the - * opponent's turn - */ - @Test - public void testEmrakulCastOnOpponentsTurn() { - addCard(Zone.BATTLEFIELD, playerA, "Island", 12); - addCard(Zone.GRAVEYARD, playerA, "Island", 1); - // Emrakul, the Promised End costs {1} less to cast for each card type among cards in your graveyard. - // When you cast Emrakul, you gain control of target opponent during that player's next turn. After that turn, that player takes an extra turn. - // Flying - // Trample - // Protection from instants - addCard(Zone.HAND, playerA, "Emrakul, the Promised End", 1); // {13} - // Flash (You may cast this spell any time you could cast an instant.) - // Creature cards you own that aren't on the battlefield have flash. - // Each opponent can cast spells only any time he or she could cast a sorcery. - addCard(Zone.BATTLEFIELD, playerA, "Teferi, Mage of Zhalfir", 1); - - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Emrakul, the Promised End"); - - setStopAt(3, PhaseStep.UPKEEP); - execute(); - - assertPermanentCount(playerA, "Emrakul, the Promised End", 1); - - Assert.assertTrue("For extra turn, playerB has to be the active player ", currentGame.getActivePlayerId().equals(playerB.getId())); - } -} +/* + * 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 org.mage.test.turnmod; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Assert; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class ExtraTurnsTest extends CardTestPlayerBase { + + /** + * Emrakul, the Promised End not giving an extra turn when cast in the + * opponent's turn + */ + @Test + public void testEmrakulCastOnOpponentsTurnCheckTurn3() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 12); + addCard(Zone.GRAVEYARD, playerA, "Island", 1); + // Emrakul, the Promised End costs {1} less to cast for each card type among cards in your graveyard. + // When you cast Emrakul, you gain control of target opponent during that player's next turn. After that turn, that player takes an extra turn. + // Flying + // Trample + // Protection from instants + addCard(Zone.HAND, playerA, "Emrakul, the Promised End", 1); // {13} + // Flash (You may cast this spell any time you could cast an instant.) + // Creature cards you own that aren't on the battlefield have flash. + // Each opponent can cast spells only any time he or she could cast a sorcery. + addCard(Zone.BATTLEFIELD, playerA, "Teferi, Mage of Zhalfir", 1); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Emrakul, the Promised End"); + // Turn 4 is the next turn of opponent (player B) that player A controls + // So Turn 5 is the extra turn for player B after Turn 4 + setStopAt(3, PhaseStep.DRAW); + execute(); + + assertPermanentCount(playerA, "Emrakul, the Promised End", 1); + Assert.assertTrue("Turn 3 is no extra turn ", !currentGame.getState().isExtraTurn()); + Assert.assertTrue("For turn " + currentGame.getTurnNum() + ", playerA has to be the active player but active player is: " + + currentGame.getPlayer(currentGame.getActivePlayerId()).getName(), currentGame.getActivePlayerId().equals(playerA.getId())); + } + + @Test + public void testEmrakulCastOnOpponentsTurnCheckTurn4() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 12); + addCard(Zone.GRAVEYARD, playerA, "Island", 1); + // Emrakul, the Promised End costs {1} less to cast for each card type among cards in your graveyard. + // When you cast Emrakul, you gain control of target opponent during that player's next turn. After that turn, that player takes an extra turn. + // Flying + // Trample + // Protection from instants + addCard(Zone.HAND, playerA, "Emrakul, the Promised End", 1); // {13} + // Flash (You may cast this spell any time you could cast an instant.) + // Creature cards you own that aren't on the battlefield have flash. + // Each opponent can cast spells only any time he or she could cast a sorcery. + addCard(Zone.BATTLEFIELD, playerA, "Teferi, Mage of Zhalfir", 1); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Emrakul, the Promised End"); + // Turn 4 is the next turn of opponent (player B) that player A controls + // So Turn 5 is the extra turn for player B after Turn 4 + setStopAt(4, PhaseStep.DRAW); + execute(); + + assertPermanentCount(playerA, "Emrakul, the Promised End", 1); + Assert.assertTrue("Turn 4 is a controlled turn ", !playerB.isGameUnderControl()); + Assert.assertTrue("For turn " + currentGame.getTurnNum() + ", playerB has to be the active player but active player is: " + + currentGame.getPlayer(currentGame.getActivePlayerId()).getName(), currentGame.getActivePlayerId().equals(playerB.getId())); + } + + @Test + public void testEmrakulCastOnOpponentsTurnCheckTurn5() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 12); + addCard(Zone.GRAVEYARD, playerA, "Island", 1); + // Emrakul, the Promised End costs {1} less to cast for each card type among cards in your graveyard. + // When you cast Emrakul, you gain control of target opponent during that player's next turn. After that turn, that player takes an extra turn. + // Flying + // Trample + // Protection from instants + addCard(Zone.HAND, playerA, "Emrakul, the Promised End", 1); // {13} + // Flash (You may cast this spell any time you could cast an instant.) + // Creature cards you own that aren't on the battlefield have flash. + // Each opponent can cast spells only any time he or she could cast a sorcery. + addCard(Zone.BATTLEFIELD, playerA, "Teferi, Mage of Zhalfir", 1); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Emrakul, the Promised End"); + // Turn 4 is the next turn of opponent (player B) that player A controls + // So Turn 5 is the extra turn for player B after Turn 4 + setStopOnTurn(5); + execute(); + + assertPermanentCount(playerA, "Emrakul, the Promised End", 1); + Assert.assertTrue("Turn 5 is an extra turn ", currentGame.getState().isExtraTurn()); + Assert.assertTrue("For turn " + currentGame.getTurnNum() + ", playerB has to be the active player but active player is: " + + currentGame.getPlayer(currentGame.getActivePlayerId()).getName(), currentGame.getActivePlayerId().equals(playerB.getId())); + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/AttackingCondition.java b/Mage/src/main/java/mage/abilities/condition/common/AttackingCondition.java deleted file mode 100644 index a1b315a3b09..00000000000 --- a/Mage/src/main/java/mage/abilities/condition/common/AttackingCondition.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package mage.abilities.condition.common; - -import mage.abilities.Ability; -import mage.abilities.condition.Condition; -import mage.game.Game; -import mage.game.permanent.Permanent; - -/** - * - * @author anonymous - */ -public class AttackingCondition implements Condition { - - private static final AttachedCondition fInstance = new AttachedCondition(); - - public static AttachedCondition getInstance() { - return fInstance; - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getSourceId()); - return permanent != null && permanent.isAttacking(); - } -} diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/AttachedPermanentToughnessValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/AttachedPermanentToughnessValue.java new file mode 100644 index 00000000000..2dab3cdd799 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/AttachedPermanentToughnessValue.java @@ -0,0 +1,41 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.dynamicvalue.common; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author MTGfan + */ +public class AttachedPermanentToughnessValue implements DynamicValue { + + @Override + public int calculate(Game game, Ability source, Effect effect) { + Permanent enchantment = game.getPermanentOrLKIBattlefield(source.getSourceId()); + Permanent enchanted = game.getPermanentOrLKIBattlefield(enchantment.getAttachedTo()); + return enchanted.getToughness().getValue(); + } + + @Override + public AttachedPermanentToughnessValue copy(){ + return new AttachedPermanentToughnessValue(); + } + + @Override + public String toString() { + return "equal to"; + } + + @Override + public String getMessage() { + return "that creature's toughness"; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageAttachedControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageAttachedControllerEffect.java index b248481aad9..4db95ed083f 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DamageAttachedControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageAttachedControllerEffect.java @@ -30,6 +30,8 @@ package mage.abilities.effects.common; import mage.abilities.Ability; import mage.abilities.Mode; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.game.Game; @@ -42,9 +44,14 @@ import mage.players.Player; */ public class DamageAttachedControllerEffect extends OneShotEffect { - protected int amount; + protected DynamicValue amount; public DamageAttachedControllerEffect(int amount) { + super(Outcome.Damage); + this.amount = new StaticValue(amount); + } + + public DamageAttachedControllerEffect(DynamicValue amount) { super(Outcome.Damage); this.amount = amount; } @@ -71,7 +78,7 @@ public class DamageAttachedControllerEffect extends OneShotEffect { } Player player = game.getPlayer(enchanted.getControllerId()); if(player != null) { - player.damage(amount, source.getSourceId(), game, false, true); + player.damage(amount.calculate(game, source, this), source.getSourceId(), game, false, true); return true; } return false; @@ -82,7 +89,9 @@ public class DamageAttachedControllerEffect extends OneShotEffect { if (staticText != null && !staticText.isEmpty()) { return staticText; } - return "{this} deals " + amount + " damage to that creature's controller"; + if ("equal to".equals(amount.toString())) { + return "{this} deals damage " + amount + " that creatures toughness to that creature's controller"; + } + return "{this} deals " + amount + " damage to that creature's controller"; } - } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouAllEffect.java index 1dbf2cf026f..c681328c3cc 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouAllEffect.java @@ -76,7 +76,7 @@ public class CantAttackYouAllEffect extends RestrictionEffect { @Override public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { return (!alsoPlaneswalker && !defenderId.equals(source.getControllerId())) - || (alsoPlaneswalker && !game.getCombat().getDefendingPlayerId(attacker.getId(), game).equals(source.getControllerId())); + || (alsoPlaneswalker && !(source.getControllerId().equals(game.getCombat().getDefendingPlayerId(attacker.getId(), game)))); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/ManifestEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/ManifestEffect.java index b64d9f792fe..206eb12a417 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/ManifestEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/ManifestEffect.java @@ -79,7 +79,7 @@ public class ManifestEffect extends OneShotEffect { for (Card card : cards) { ManaCosts manaCosts = null; if (card.getCardType().contains(CardType.CREATURE)) { - manaCosts = card.getSpellAbility().getManaCosts(); + manaCosts = card.getSpellAbility() != null ? card.getSpellAbility().getManaCosts() : null; if (manaCosts == null) { manaCosts = new ManaCostsImpl("{0}"); } diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 451f9bbb873..38fa841791f 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -759,14 +759,18 @@ public abstract class GameImpl implements Game, Serializable { Player playerByOrder = getPlayer(playerList.get()); state.setPlayerByOrderId(playerByOrder.getId()); while (!isPaused() && !gameOver(null)) { - playExtraTurns(); + if (!playExtraTurns()) { + break; + } GameEvent event = new GameEvent(GameEvent.EventType.PLAY_TURN, null, null, playerByOrder.getId()); if (!replaceEvent(event)) { if (!playTurn(playerByOrder)) { break; } } - playExtraTurns(); + if (!playExtraTurns()) { + break; + } playerByOrder = playerList.getNext(this); state.setPlayerByOrderId(playerByOrder.getId()); } @@ -792,7 +796,7 @@ public abstract class GameImpl implements Game, Serializable { } } - private void playExtraTurns() { + private boolean playExtraTurns() { //20091005 - 500.7 TurnMod extraTurn = getNextExtraTurn(); while (extraTurn != null) { @@ -805,14 +809,16 @@ public abstract class GameImpl implements Game, Serializable { if (!this.isSimulation()) { informPlayers(extraPlayer.getLogName() + " takes an extra turn"); } - playTurn(extraPlayer); + if (!playTurn(extraPlayer)) { + return false; + } } } extraTurn = getNextExtraTurn(); } state.setTurnId(null); state.setExtraTurn(false); - + return true; } private TurnMod getNextExtraTurn() { @@ -2275,7 +2281,7 @@ public abstract class GameImpl implements Game, Serializable { * * @param playerId */ - protected void leave(UUID playerId) { + protected void leave(UUID playerId) { // needs to be executed from the game thread, not from the concede thread of conceding player! Player player = getPlayer(playerId); if (player == null || player.hasLeft()) { diff --git a/Mage/src/main/java/mage/game/turn/Phase.java b/Mage/src/main/java/mage/game/turn/Phase.java index a474976eaae..4d2d1a0d331 100644 --- a/Mage/src/main/java/mage/game/turn/Phase.java +++ b/Mage/src/main/java/mage/game/turn/Phase.java @@ -133,11 +133,11 @@ public abstract class Phase implements Serializable { } private boolean checkStopOnStepOption(Game game) { - if (game.getOptions().stopOnTurn != null && game.getOptions().stopAtStep == getStep().getType()) { - if (game.getOptions().stopOnTurn <= game.getState().getTurnNum()) { - game.pause(); - return true; - } + if (game.getOptions().stopOnTurn != null + && game.getOptions().stopOnTurn <= game.getState().getTurnNum() + && game.getOptions().stopAtStep == getStep().getType()) { + game.pause(); + return true; } return false; } diff --git a/Mage/src/main/java/mage/game/turn/Turn.java b/Mage/src/main/java/mage/game/turn/Turn.java index 9239e55e8b6..bf2dc0a8725 100644 --- a/Mage/src/main/java/mage/game/turn/Turn.java +++ b/Mage/src/main/java/mage/game/turn/Turn.java @@ -337,7 +337,8 @@ public class Turn implements Serializable { } private void logStartOfTurn(Game game, Player player) { - StringBuilder sb = new StringBuilder("Turn ").append(game.getState().getTurnNum()).append(" "); + StringBuilder sb = new StringBuilder(game.getState().isExtraTurn() ? "Extra turn" : "Turn "); + sb.append(game.getState().getTurnNum()).append(" "); sb.append(player.getLogName()); sb.append(" ("); int delimiter = game.getPlayers().size() - 1;