From 8427d9086f9639b2a193833e619bb83a36d82d3a Mon Sep 17 00:00:00 2001 From: Pete Rossi Date: Mon, 28 Nov 2016 21:18:58 -0800 Subject: [PATCH 01/38] Implement Specter's Shroud --- .../src/mage/cards/s/SpectersShroud.java | 71 +++++++++++++++++++ Mage.Sets/src/mage/sets/Darksteel.java | 1 + 2 files changed, 72 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SpectersShroud.java diff --git a/Mage.Sets/src/mage/cards/s/SpectersShroud.java b/Mage.Sets/src/mage/cards/s/SpectersShroud.java new file mode 100644 index 00000000000..ca9103c968f --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpectersShroud.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.cards.s; + +import java.util.UUID; +import mage.abilities.common.DealsDamageToAPlayerAttachedTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; + + +/** + * + * @author Pete Rossi + */ +public class SpectersShroud extends CardImpl { + + public SpectersShroud(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + this.subtype.add("Equipment"); + + // Equipped creature gets +1/+0. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(1, 0))); + // Whenever equipped creature deals combat damage to a player, that player discards a card. + this.addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility(new DiscardTargetEffect(1), "equipped creature", false, true, false)); + // Equip {1} + this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(1))); + } + + public SpectersShroud(final SpectersShroud card) { + super(card); + } + + @Override + public SpectersShroud copy() { + return new SpectersShroud(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Darksteel.java b/Mage.Sets/src/mage/sets/Darksteel.java index 441baeeb03c..4c7c880dee5 100644 --- a/Mage.Sets/src/mage/sets/Darksteel.java +++ b/Mage.Sets/src/mage/sets/Darksteel.java @@ -138,6 +138,7 @@ public class Darksteel extends ExpansionSet { cards.add(new SetCardInfo("Slobad, Goblin Tinkerer", 69, Rarity.RARE, mage.cards.s.SlobadGoblinTinkerer.class)); cards.add(new SetCardInfo("Soulscour", 14, Rarity.RARE, mage.cards.s.Soulscour.class)); cards.add(new SetCardInfo("Spawning Pit", 141, Rarity.UNCOMMON, mage.cards.s.SpawningPit.class)); + cards.add(new SetCardInfo("Specter's Shroud", 142, Rarity.UNCOMMON, mage.cards.s.SpectersShroud.class)); cards.add(new SetCardInfo("Spellbinder", 143, Rarity.RARE, mage.cards.s.Spellbinder.class)); cards.add(new SetCardInfo("Spincrusher", 144, Rarity.UNCOMMON, mage.cards.s.Spincrusher.class)); cards.add(new SetCardInfo("Spire Golem", 145, Rarity.COMMON, mage.cards.s.SpireGolem.class)); From 19d6f80b96138f1a9a95cd5b5624d9bf74bea53c Mon Sep 17 00:00:00 2001 From: JRHerlehy Date: Wed, 30 Nov 2016 02:52:21 -0800 Subject: [PATCH 02/38] Implement Council's Dilemma Cards Implement cards with the Council's Dilemma from Conspriacy: Take the Crown expansion. Card - Lieutenants of the Guard, Messenger Jays, Capital Punishment, Orchard Elemental, and Selvala's Stampede. Missing is Expropriate. Cards have been tested locally with up to three players. --- .../src/mage/cards/c/CapitalPunishment.java | 121 ++++++++++++++++ .../mage/cards/l/LieutenantsOfTheGuard.java | 126 +++++++++++++++++ Mage.Sets/src/mage/cards/m/MessengerJays.java | 128 +++++++++++++++++ .../src/mage/cards/o/OrchardElemental.java | 121 ++++++++++++++++ .../src/mage/cards/s/SelvalasStampede.java | 133 ++++++++++++++++++ .../src/mage/sets/ConspiracyTakeTheCrown.java | 5 + 6 files changed, 634 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/c/CapitalPunishment.java create mode 100644 Mage.Sets/src/mage/cards/l/LieutenantsOfTheGuard.java create mode 100644 Mage.Sets/src/mage/cards/m/MessengerJays.java create mode 100644 Mage.Sets/src/mage/cards/o/OrchardElemental.java create mode 100644 Mage.Sets/src/mage/cards/s/SelvalasStampede.java diff --git a/Mage.Sets/src/mage/cards/c/CapitalPunishment.java b/Mage.Sets/src/mage/cards/c/CapitalPunishment.java new file mode 100644 index 00000000000..9d3352938b0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CapitalPunishment.java @@ -0,0 +1,121 @@ +/* + * 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.dynamicvalue.common.StaticValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeOpponentsEffect; +import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author JRHerlehy + */ +public class CapitalPunishment extends CardImpl { + + public CapitalPunishment(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}{B}"); + + + // Council's dilemma — Starting with you, each player votes for death or taxes. Each opponent sacrifices a creature for each death vote and discards a card for each taxes vote. + this.getSpellAbility().addEffect(new CapitalPunishmentDilemmaEffect()); + } + + public CapitalPunishment(final CapitalPunishment card) { + super(card); + } + + @Override + public CapitalPunishment copy() { + return new CapitalPunishment(this); + } +} + +class CapitalPunishmentDilemmaEffect extends OneShotEffect { + + public CapitalPunishmentDilemmaEffect() { + super(Outcome.Detriment); + this.staticText = "Council's dilemma — Starting with you, each player votes for death or taxes. Each opponent sacrifices a creature for each death vote and discards a card for each taxes vote"; + } + + public CapitalPunishmentDilemmaEffect(final CapitalPunishmentDilemmaEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + + //If no controller, exit out here and do not vote. + if (controller == null) return false; + + int deathCount = 0, taxesCount = 0; + + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + if (player.chooseUse(Outcome.Detriment, "Choose death?", source, game)) { + deathCount++; + game.informPlayers(player.getName() + " has voted for death"); + } else { + taxesCount++; + game.informPlayers(player.getName() + " has voted for taxes"); + } + } + } + + if (deathCount > 0) { + Effect sacraficeEffect = new SacrificeOpponentsEffect(deathCount, new FilterControlledCreaturePermanent()); + sacraficeEffect.apply(game, source); + } + + if (taxesCount > 0) { + Effect discardEffect = new DiscardEachPlayerEffect(new StaticValue(taxesCount), false, TargetController.OPPONENT); + discardEffect.apply(game, source); + } + + return true; + } + + @Override + public CapitalPunishmentDilemmaEffect copy() { + return new CapitalPunishmentDilemmaEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LieutenantsOfTheGuard.java b/Mage.Sets/src/mage/cards/l/LieutenantsOfTheGuard.java new file mode 100644 index 00000000000..9290e927f14 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LieutenantsOfTheGuard.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 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.l; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.SoldierToken; +import mage.players.Player; + +import java.util.UUID; + +/** + * + * @author JRHerlehy + */ +public class LieutenantsOfTheGuard extends CardImpl { + + public LieutenantsOfTheGuard(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}"); + + this.subtype.add("Human"); + this.subtype.add("Soldier"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Council's dilemma — When Lieutenants of the Guard enters the battlefield, starting with you, each player votes for strength or numbers. Put a +1/+1 counter on Lieutenants of the Guard for each strength vote and put a 1/1 white Soldier creature token onto the battlefield for each numbers vote. + this.addAbility(new EntersBattlefieldTriggeredAbility(new LieutenantsOfTheGuardDilemmaEffect(), false, "Council's dilemma — ")); + } + + public LieutenantsOfTheGuard(final LieutenantsOfTheGuard card) { + super(card); + } + + @Override + public LieutenantsOfTheGuard copy() { + return new LieutenantsOfTheGuard(this); + } +} + +class LieutenantsOfTheGuardDilemmaEffect extends OneShotEffect { + public LieutenantsOfTheGuardDilemmaEffect() { + super(Outcome.Benefit); + this.staticText = "starting with you, each player votes for strength or numbers. Put a +1/+1 counter on {this} for each strength vote and put a 1/1 white Soldier creature token onto the battlefield for each numbers vote."; + } + + public LieutenantsOfTheGuardDilemmaEffect(final LieutenantsOfTheGuardDilemmaEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + + //If no controller, exit out here and do not vote. + if (controller == null) return false; + + int strengthCount = 0, numbersCount = 0; + + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + if (player.chooseUse(Outcome.BoostCreature, "Choose strength?", source, game)) { + strengthCount++; + game.informPlayers(player.getName() + " has voted for strength"); + } else { + numbersCount++; + game.informPlayers(player.getName() + " has voted for numbers"); + } + } + } + + Permanent permanent = game.getPermanent(source.getSourceId()); + + //If strength received zero votes or the permanent is no longer on the battlefield, do not attempt to put P1P1 counters on it. + if (strengthCount > 0 && permanent != null) permanent.addCounters(CounterType.P1P1.createInstance(strengthCount), game); + + //Create the appropriate number of tokens for the controller. + if (numbersCount > 0) { + Effect tokenEffect = new CreateTokenEffect(new SoldierToken(), numbersCount); + tokenEffect.apply(game, source); + } + + return true; + } + + @Override + public LieutenantsOfTheGuardDilemmaEffect copy() { + return new LieutenantsOfTheGuardDilemmaEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MessengerJays.java b/Mage.Sets/src/mage/cards/m/MessengerJays.java new file mode 100644 index 00000000000..3cc5174e3d8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MessengerJays.java @@ -0,0 +1,128 @@ +/* + * 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.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.UUID; + +/** + * + * @author JRHerlehy + */ +public class MessengerJays extends CardImpl { + + public MessengerJays(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.subtype.add("Bird"); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // Council's dilemma — When Messenger Jays enters the battlefield, starting with you, each player votes for feather or quill. Put a +1/+1 counter on Messenger Jays for each feather vote and draw a card for each quill vote. For each card drawn this way, discard a card. + this.addAbility(new EntersBattlefieldTriggeredAbility(new MessengerJaysDilemmaEffect(), false, "Council's dilemma — ")); + } + + public MessengerJays(final MessengerJays card) { + super(card); + } + + @Override + public MessengerJays copy() { + return new MessengerJays(this); + } +} + +class MessengerJaysDilemmaEffect extends OneShotEffect { + + public MessengerJaysDilemmaEffect() { + super(Outcome.Benefit); + this.staticText = "starting with you, each player votes for feather or quill. Put a +1/+1 counter on {this} for each feather vote and draw a card for each quill vote. For each card drawn this way, discard a card."; + } + + public MessengerJaysDilemmaEffect(final MessengerJaysDilemmaEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + + //If no controller, exit out here and do not vote. + if (controller == null) return false; + + int featherCount = 0, quillCount = 0; + + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + if (player.chooseUse(Outcome.BoostCreature, "Choose feather?", source, game)) { + featherCount++; + game.informPlayers(player.getName() + " has voted for feather"); + } else { + quillCount++; + game.informPlayers(player.getName() + " has voted for quill"); + } + } + } + + Permanent permanent = game.getPermanent(source.getSourceId()); + + //If feathers received zero votes or the permanent is no longer on the battlefield, do not attempt to put P1P1 counter on it. + if (featherCount > 0 && permanent != null) permanent.addCounters(CounterType.P1P1.createInstance(featherCount), game); + + //Only let the controller loot the appropriate amount of cards if it was voted for. + if (quillCount > 0) { + Effect lootCardsEffect = new DrawDiscardControllerEffect(quillCount, quillCount); + lootCardsEffect.apply(game, source); + } + + return true; + } + + @Override + public MessengerJaysDilemmaEffect copy() { + return new MessengerJaysDilemmaEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OrchardElemental.java b/Mage.Sets/src/mage/cards/o/OrchardElemental.java new file mode 100644 index 00000000000..2a4c3e4bc80 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OrchardElemental.java @@ -0,0 +1,121 @@ +/* + * 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.o; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author JRHerlehy + */ +public class OrchardElemental extends CardImpl { + + public OrchardElemental(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}"); + + this.subtype.add("Elemental"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Council's dilemma &mdash When Orchard Elemental enters the battlefield, starting with you, each player votes for sprout or harvest. Put two +1/+1 counters on Orchard Elemental for each sprout vote. You gain 3 life for each harvest vote. + this.addAbility(new EntersBattlefieldTriggeredAbility(new OrchardElementalDilemmaEffect(), false, "Council's dilemma — ")); + } + + public OrchardElemental(final OrchardElemental card) { + super(card); + } + + @Override + public OrchardElemental copy() { + return new OrchardElemental(this); + } +} + +class OrchardElementalDilemmaEffect extends OneShotEffect { + + public OrchardElementalDilemmaEffect() { + super(Outcome.Benefit); + this.staticText = "starting with you, each player votes for sprout or harvest. Put two +1/+1 counters on Orchard Elemental for each sprout vote. You gain 3 life for each harvest vote"; + } + + public OrchardElementalDilemmaEffect(final OrchardElementalDilemmaEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + + if (controller == null) return false; + + int sproutCount = 0, harvestCount = 0; + + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + if (player.chooseUse(Outcome.BoostCreature, "Choose sprout?", source, game)) { + sproutCount++; + game.informPlayers(player.getName() + " has voted for sprout"); + } else { + harvestCount++; + game.informPlayers(player.getName() + " has voted for harvest"); + } + } + } + + Permanent permanent = game.getPermanent(source.getSourceId()); + + if (sproutCount > 0 && permanent != null) permanent.addCounters(CounterType.P1P1.createInstance(sproutCount * 2), game); + + if (harvestCount > 0) { + Effect gainLifeEffect = new GainLifeEffect(harvestCount * 3); + gainLifeEffect.apply(game, source); + } + + return true; + } + + @Override + public OrchardElementalDilemmaEffect copy() { + return new OrchardElementalDilemmaEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SelvalasStampede.java b/Mage.Sets/src/mage/cards/s/SelvalasStampede.java new file mode 100644 index 00000000000..f8a86470d97 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SelvalasStampede.java @@ -0,0 +1,133 @@ +/* + * 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.s; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterPermanentCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInHand; + +/** + * + * @author JRHerlehy + */ +public class SelvalasStampede extends CardImpl { + + public SelvalasStampede(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}{G}"); + + + // Council's dilemma &mdash Starting with you, each player votes for wild or free. Reveal cards from the top of your library until you reveal a creature card for each wild vote. Put those creature cards onto the battlefield, then shuffle the rest into your library. You may put a permanent card from your hand onto the battlefield for each free vote. + this.getSpellAbility().addEffect(new SelvalasStampedeDilemmaEffect()); + } + + public SelvalasStampede(final SelvalasStampede card) { + super(card); + } + + @Override + public SelvalasStampede copy() { + return new SelvalasStampede(this); + } +} + +class SelvalasStampedeDilemmaEffect extends OneShotEffect { + + public SelvalasStampedeDilemmaEffect() { + super(Outcome.Benefit); + this.staticText = "Council's dilemma — Starting with you, each player votes for wild or free. Reveal cards from the top of your library until you reveal a creature card for each wild vote. Put those creature cards onto the battlefield, then shuffle the rest into your library. You may put a permanent card from your hand onto the battlefield for each free vote"; + } + + public SelvalasStampedeDilemmaEffect(final SelvalasStampedeDilemmaEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + + //If no controller, exit here and do not vote. + if (controller == null) return false; + + int wildCount = 0, freeCount = 0; + + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + if (player.chooseUse(Outcome.Benefit, "Choose wild?", source, game)) { + wildCount++; + game.informPlayers(player.getName() + " has voted for wild"); + } else { + freeCount++; + game.informPlayers(player.getName() + " has voted for free"); + } + } + } + + if (wildCount > 0) { + Cards revealedCards = new CardsImpl(); + + while (wildCount > 0 && controller.getLibrary().size() > 0) { + Card card = controller.getLibrary().removeFromTop(game); + if (card.getCardType().contains(CardType.CREATURE)) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game); + wildCount--; + } else { + revealedCards.add(card); + } + } + + controller.revealCards("Selvala's Stampede", revealedCards, game); + controller.moveCards(revealedCards, Zone.LIBRARY, source, game); + controller.shuffleLibrary(source, game); + } + + if (freeCount > 0) { + TargetCardInHand target = new TargetCardInHand(0, freeCount, new FilterPermanentCard("permanent cards")); + if (controller.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { + controller.moveCards(new CardsImpl(target.getTargets()), Zone.BATTLEFIELD, source, game); + } + } + + return true; + } + + @Override + public SelvalasStampedeDilemmaEffect copy() { + return new SelvalasStampedeDilemmaEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ConspiracyTakeTheCrown.java b/Mage.Sets/src/mage/sets/ConspiracyTakeTheCrown.java index f95cfadd065..8a1131debd3 100644 --- a/Mage.Sets/src/mage/sets/ConspiracyTakeTheCrown.java +++ b/Mage.Sets/src/mage/sets/ConspiracyTakeTheCrown.java @@ -74,6 +74,7 @@ public class ConspiracyTakeTheCrown extends ExpansionSet { cards.add(new SetCardInfo("Burning Wish", 152, Rarity.RARE, mage.cards.b.BurningWish.class)); cards.add(new SetCardInfo("Caller of Gales", 103, Rarity.COMMON, mage.cards.c.CallerOfGales.class)); cards.add(new SetCardInfo("Canal Courier", 28, Rarity.COMMON, mage.cards.c.CanalCourier.class)); + cards.add(new SetCardInfo("Capital Punishment", 40, Rarity.RARE, mage.cards.c.CapitalPunishment.class)); cards.add(new SetCardInfo("Carnage Gladiator", 199, Rarity.UNCOMMON, mage.cards.c.CarnageGladiator.class)); cards.add(new SetCardInfo("Charmbreaker Devils", 153, Rarity.RARE, mage.cards.c.CharmbreakerDevils.class)); cards.add(new SetCardInfo("Child of Night", 130, Rarity.COMMON, mage.cards.c.ChildOfNight.class)); @@ -155,11 +156,13 @@ public class ConspiracyTakeTheCrown extends ExpansionSet { cards.add(new SetCardInfo("Lace with Moonglove", 184, Rarity.COMMON, mage.cards.l.LaceWithMoonglove.class)); cards.add(new SetCardInfo("Lay of the Land", 185, Rarity.COMMON, mage.cards.l.LayOfTheLand.class)); cards.add(new SetCardInfo("Leovold, Emissary of Trest", 77, Rarity.MYTHIC, mage.cards.l.LeovoldEmissaryOfTrest.class)); + cards.add(new SetCardInfo("Lieutenants of the Guard", 16, Rarity.COMMON, mage.cards.l.LieutenantsOfTheGuard.class)); cards.add(new SetCardInfo("Manaplasm", 186, Rarity.UNCOMMON, mage.cards.m.Manaplasm.class)); cards.add(new SetCardInfo("Marchesa's Decree", 44, Rarity.UNCOMMON, mage.cards.m.MarchesasDecree.class)); cards.add(new SetCardInfo("Menagerie Liberator", 67, Rarity.COMMON, mage.cards.m.MenagerieLiberator.class)); cards.add(new SetCardInfo("Merfolk Looter", 114, Rarity.UNCOMMON, mage.cards.m.MerfolkLooter.class)); cards.add(new SetCardInfo("Merfolk Skyscout", 115, Rarity.UNCOMMON, mage.cards.m.MerfolkSkyscout.class)); + cards.add(new SetCardInfo("Messenger Jays", 35, Rarity.COMMON, mage.cards.m.MessengerJays.class)); cards.add(new SetCardInfo("Mnemonic Wall", 116, Rarity.COMMON, mage.cards.m.MnemonicWall.class)); cards.add(new SetCardInfo("Murder", 143, Rarity.COMMON, mage.cards.m.Murder.class)); cards.add(new SetCardInfo("Negate", 117, Rarity.COMMON, mage.cards.n.Negate.class)); @@ -168,6 +171,7 @@ public class ConspiracyTakeTheCrown extends ExpansionSet { cards.add(new SetCardInfo("Ogre Sentry", 168, Rarity.COMMON, mage.cards.o.OgreSentry.class)); cards.add(new SetCardInfo("Omenspeaker", 118, Rarity.COMMON, mage.cards.o.Omenspeaker.class)); cards.add(new SetCardInfo("Opaline Unicorn", 213, Rarity.COMMON, mage.cards.o.OpalineUnicorn.class)); + cards.add(new SetCardInfo("Orchard Elemental", 68, Rarity.COMMON, mage.cards.o.OrchardElemental.class)); cards.add(new SetCardInfo("Overrun", 189, Rarity.UNCOMMON, mage.cards.o.Overrun.class)); cards.add(new SetCardInfo("Palace Jailer", 18, Rarity.UNCOMMON, mage.cards.p.PalaceJailer.class)); cards.add(new SetCardInfo("Palace Sentinels", 19, Rarity.COMMON, mage.cards.p.PalaceSentinels.class)); @@ -192,6 +196,7 @@ public class ConspiracyTakeTheCrown extends ExpansionSet { cards.add(new SetCardInfo("Runed Servitor", 216, Rarity.UNCOMMON, mage.cards.r.RunedServitor.class)); cards.add(new SetCardInfo("Sanctum Prelate", 23, Rarity.MYTHIC, mage.cards.s.SanctumPrelate.class)); cards.add(new SetCardInfo("Sangromancer", 147, Rarity.RARE, mage.cards.s.Sangromancer.class)); + cards.add(new SetCardInfo("Selvala's Stampede", 71, Rarity.RARE, mage.cards.s.SelvalasStampede.class)); cards.add(new SetCardInfo("Selvala, Heart of the Wilds", 70, Rarity.MYTHIC, mage.cards.s.SelvalaHeartOfTheWilds.class)); cards.add(new SetCardInfo("Serum Visions", 120, Rarity.UNCOMMON, mage.cards.s.SerumVisions.class)); cards.add(new SetCardInfo("Shambling Goblin", 148, Rarity.COMMON, mage.cards.s.ShamblingGoblin.class)); From a14232cce22cc89263d527f5f73ae53fe02f5007 Mon Sep 17 00:00:00 2001 From: Pete Rossi Date: Wed, 30 Nov 2016 19:24:42 -0800 Subject: [PATCH 03/38] Set the 'onlyCombat' parameter to true --- Mage.Sets/src/mage/cards/s/SpectersShroud.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/cards/s/SpectersShroud.java b/Mage.Sets/src/mage/cards/s/SpectersShroud.java index ca9103c968f..532fd246442 100644 --- a/Mage.Sets/src/mage/cards/s/SpectersShroud.java +++ b/Mage.Sets/src/mage/cards/s/SpectersShroud.java @@ -55,7 +55,7 @@ public class SpectersShroud extends CardImpl { // Equipped creature gets +1/+0. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(1, 0))); // Whenever equipped creature deals combat damage to a player, that player discards a card. - this.addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility(new DiscardTargetEffect(1), "equipped creature", false, true, false)); + this.addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility(new DiscardTargetEffect(1), "equipped creature", false, true, true)); // Equip {1} this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(1))); } From b7695f7feabf76235b48042016b28c5efecba9c3 Mon Sep 17 00:00:00 2001 From: spjspj Date: Thu, 1 Dec 2016 19:01:00 +1100 Subject: [PATCH 04/38] spjspj - 7pt Aus Highlander --- Mage.Client/src/main/java/mage/client/table/TablesPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java index 9e366c2ceaf..646369c1668 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java @@ -602,7 +602,7 @@ public class TablesPanel extends javax.swing.JPanel { formatFilterList.add(RowFilter.regexFilter("^Limited", TableTableModel.COLUMN_DECK_TYPE)); } if (btnFormatOther.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Momir Basic|^Constructed - Pauper|^Constructed - Frontier|^Constructed - Extended|^Constructed - Eternal|^Constructed - Historical|^Constructed - Super|^Constructed - Freeform", TableTableModel.COLUMN_DECK_TYPE)); + formatFilterList.add(RowFilter.regexFilter("^Momir Basic|^Constructed - Pauper|^Constructed - Frontier|^Constructed - Extended|^Constructed - Eternal|^Constructed - Historical|^Constructed - Super|^Constructed - Freeform|^Australian Highlander", TableTableModel.COLUMN_DECK_TYPE)); } List> skillFilterList = new ArrayList<>(); From d051cb7b42666586bd14dfd88bcc21c4a67197a1 Mon Sep 17 00:00:00 2001 From: "ludwig.hirth" Date: Fri, 2 Dec 2016 16:06:34 +0100 Subject: [PATCH 05/38] * Some client menu changes. --- .../src/main/java/mage/client/MageFrame.form | 112 ++++++--- .../src/main/java/mage/client/MageFrame.java | 229 +++++++++--------- .../mage/client/components/tray/MageTray.java | 11 +- .../card/dl/beans/EventListenerList.java | 71 +++--- Mage.Client/src/main/resources/menu/about.png | Bin 0 -> 860 bytes .../src/main/resources/menu/collection.png | Bin 0 -> 366 bytes .../src/main/resources/menu/connect.png | Bin 0 -> 636 bytes .../src/main/resources/menu/deck_editor.png | Bin 0 -> 271 bytes .../src/main/resources/menu/feedback.png | Bin 0 -> 547 bytes .../src/main/resources/menu/images.png | Bin 0 -> 811 bytes .../src/main/resources/menu/memory.png | Bin 0 -> 675 bytes .../src/main/resources/menu/preferences.png | Bin 0 -> 512 bytes .../src/main/resources/menu/symbol.png | Bin 0 -> 376 bytes 13 files changed, 226 insertions(+), 197 deletions(-) create mode 100644 Mage.Client/src/main/resources/menu/about.png create mode 100644 Mage.Client/src/main/resources/menu/collection.png create mode 100644 Mage.Client/src/main/resources/menu/connect.png create mode 100644 Mage.Client/src/main/resources/menu/deck_editor.png create mode 100644 Mage.Client/src/main/resources/menu/feedback.png create mode 100644 Mage.Client/src/main/resources/menu/images.png create mode 100644 Mage.Client/src/main/resources/menu/memory.png create mode 100644 Mage.Client/src/main/resources/menu/preferences.png create mode 100644 Mage.Client/src/main/resources/menu/symbol.png diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.form b/Mage.Client/src/main/java/mage/client/MageFrame.form index f0741e20828..de5ca825483 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.form +++ b/Mage.Client/src/main/java/mage/client/MageFrame.form @@ -26,8 +26,8 @@ - - + + @@ -78,9 +78,12 @@ + + + - + @@ -91,35 +94,36 @@ - + + + + - + - - - + - - + + - + - - - + + + - + @@ -130,9 +134,12 @@ - + + + + - + @@ -143,9 +150,12 @@ + + + - + @@ -154,11 +164,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -167,30 +214,15 @@ - - - - - - - - - - - + + + + - - - - - - - - - - + + diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index 5b91c2b29b8..c6eec4f6d83 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -63,7 +63,6 @@ import java.util.concurrent.TimeUnit; import java.util.prefs.Preferences; import javax.imageio.ImageIO; import javax.swing.AbstractButton; -import javax.swing.Box; import javax.swing.ImageIcon; import javax.swing.InputMap; import javax.swing.JButton; @@ -79,7 +78,6 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JToggleButton; -import javax.swing.JToolBar.Separator; import javax.swing.KeyStroke; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; @@ -357,41 +355,8 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { balloonTip.setPositioner(new LeftAbovePositioner(0, 0)); balloonTip.setVisible(false); - mageToolbar.add(new javax.swing.JToolBar.Separator()); - mageToolbar.add(createWindowsButton()); - - //TODO: move to plugin impl - if (Plugins.getInstance().isCardPluginLoaded()) { - Separator separator = new javax.swing.JToolBar.Separator(); - mageToolbar.add(separator); - - JButton btnDownloadSymbols = new JButton("Symbols"); - btnDownloadSymbols.setFocusable(false); - btnDownloadSymbols.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnDownloadSymbols.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnDownloadSymbols.addActionListener(new java.awt.event.ActionListener() { - @Override - public void actionPerformed(java.awt.event.ActionEvent evt) { - btnSymbolsActionPerformed(evt); - } - }); - mageToolbar.add(btnDownloadSymbols); - - separator = new javax.swing.JToolBar.Separator(); - mageToolbar.add(separator); - - JButton btnDownload = new JButton("Images"); - btnDownload.setFocusable(false); - btnDownload.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnDownload.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnDownload.addActionListener(new java.awt.event.ActionListener() { - @Override - public void actionPerformed(java.awt.event.ActionEvent evt) { - btnImagesActionPerformed(evt); - } - }); - mageToolbar.add(btnDownload); - } + mageToolbar.add(createSwitchPanelsButton(), 0); + mageToolbar.add(new javax.swing.JToolBar.Separator(), 1); if (Plugins.getInstance().isCounterPluginLoaded()) { int i = Plugins.getInstance().getGamesPlayed(); @@ -402,8 +367,6 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { label.setBounds(0, 0, 180, 30); } - UI.addButton(MageComponents.TABLES_MENU_BUTTON, btnGames); - setGUISize(); SwingUtilities.invokeLater(new Runnable() { @@ -567,22 +530,22 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { setIconImage(image); } - private AbstractButton createWindowsButton() { - final JToggleButton windowButton = new JToggleButton("Windows"); - windowButton.addItemListener(new ItemListener() { + private AbstractButton createSwitchPanelsButton() { + final JToggleButton switchPanelsButton = new JToggleButton("Switch panels"); + switchPanelsButton.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { - createAndShowMenu((JComponent) e.getSource(), windowButton); + createAndShowSwitchPanelsMenu((JComponent) e.getSource(), switchPanelsButton); } } }); - windowButton.setFocusable(false); - windowButton.setHorizontalTextPosition(SwingConstants.LEADING); - return windowButton; + switchPanelsButton.setFocusable(false); + switchPanelsButton.setHorizontalTextPosition(SwingConstants.LEADING); + return switchPanelsButton; } - private void createAndShowMenu(final JComponent component, final AbstractButton windowButton) { + private void createAndShowSwitchPanelsMenu(final JComponent component, final AbstractButton windowButton) { JPopupMenu menu = new JPopupMenu(); JInternalFrame[] windows = desktopPane.getAllFramesInLayer(javax.swing.JLayeredPane.DEFAULT_LAYER); MagePaneMenuItem menuItem; @@ -641,18 +604,16 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { } } - public void btnImagesActionPerformed(java.awt.event.ActionEvent evt) { - List cards = CardRepository.instance.findCards(new CardCriteria()); - DownloadPictures.startDownload(null, cards); - } - - public void btnSymbolsActionPerformed(java.awt.event.ActionEvent evt) { - UserRequestMessage message = new UserRequestMessage("Download additional resources", "Do you want to download game symbols and additional image files?"); - message.setButton1("No", null); - message.setButton2("Yes", PlayerAction.CLIENT_DOWNLOAD_SYMBOLS); - showUserRequestDialog(message); - } - +// public void btnImagesActionPerformed(java.awt.event.ActionEvent evt) { +// List cards = CardRepository.instance.findCards(new CardCriteria()); +// DownloadPictures.startDownload(null, cards); +// } +// public void btnSymbolsActionPerformed(java.awt.event.ActionEvent evt) { +// UserRequestMessage message = new UserRequestMessage("Download additional resources", "Do you want to download game symbols and additional image files?"); +// message.setButton1("No", null); +// message.setButton2("Yes", PlayerAction.CLIENT_DOWNLOAD_SYMBOLS); +// showUserRequestDialog(message); +// } public static void setActive(MagePane frame) { if (frame == null) { activeFrame = null; @@ -888,8 +849,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { btnPreferences = new javax.swing.JButton(); jSeparator4 = new javax.swing.JToolBar.Separator(); btnConnect = new javax.swing.JButton(); - jSeparator3 = new javax.swing.JToolBar.Separator(); - btnGames = new javax.swing.JButton(); + lblStatus = new javax.swing.JLabel(); jSeparator1 = new javax.swing.JToolBar.Separator(); btnDeckEditor = new javax.swing.JButton(); jSeparator2 = new javax.swing.JToolBar.Separator(); @@ -897,12 +857,13 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { jSeparator5 = new javax.swing.JToolBar.Separator(); btnSendFeedback = new javax.swing.JButton(); jSeparator6 = new javax.swing.JToolBar.Separator(); + btnSymbols = new javax.swing.JButton(); + jSeparatorSymbols = new javax.swing.JToolBar.Separator(); + btnImages = new javax.swing.JButton(); + jSeparatorImages = new javax.swing.JToolBar.Separator(); btnAbout = new javax.swing.JButton(); jSeparator7 = new javax.swing.JToolBar.Separator(); - btnExit = new javax.swing.JButton(); jMemUsageLabel = new javax.swing.JLabel(); - jSeparator8 = new javax.swing.JToolBar.Separator(); - lblStatus = new javax.swing.JLabel(); setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE); setMinimumSize(new java.awt.Dimension(1024, 768)); @@ -916,9 +877,10 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { mageToolbar.setMinimumSize(new java.awt.Dimension(566, 60)); mageToolbar.setPreferredSize(new java.awt.Dimension(614, 60)); + btnPreferences.setIcon(new javax.swing.ImageIcon(getClass().getResource("/menu/preferences.png"))); // NOI18N btnPreferences.setText("Preferences"); btnPreferences.setFocusable(false); - btnPreferences.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnPreferences.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT); btnPreferences.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); btnPreferences.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -928,9 +890,10 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { mageToolbar.add(btnPreferences); mageToolbar.add(jSeparator4); - btnConnect.setText("Connect"); + btnConnect.setIcon(new javax.swing.ImageIcon(getClass().getResource("/menu/connect.png"))); // NOI18N + btnConnect.setToolTipText("Connect to or disconnect from a XMage server."); btnConnect.setFocusable(false); - btnConnect.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnConnect.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT); btnConnect.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); btnConnect.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -938,23 +901,18 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { } }); mageToolbar.add(btnConnect); - mageToolbar.add(jSeparator3); - btnGames.setText("Games"); - btnGames.setFocusable(false); - btnGames.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnGames.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnGames.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - btnGamesActionPerformed(evt); - } - }); - mageToolbar.add(btnGames); + lblStatus.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + lblStatus.setText("Not connected"); + lblStatus.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + lblStatus.setInheritsPopupMenu(false); + mageToolbar.add(lblStatus); mageToolbar.add(jSeparator1); + btnDeckEditor.setIcon(new javax.swing.ImageIcon(getClass().getResource("/menu/deck_editor.png"))); // NOI18N btnDeckEditor.setText("Deck Editor"); btnDeckEditor.setFocusable(false); - btnDeckEditor.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnDeckEditor.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT); btnDeckEditor.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); btnDeckEditor.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -964,9 +922,10 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { mageToolbar.add(btnDeckEditor); mageToolbar.add(jSeparator2); - btnCollectionViewer.setText("Collection Viewer"); + btnCollectionViewer.setIcon(new javax.swing.ImageIcon(getClass().getResource("/menu/collection.png"))); // NOI18N + btnCollectionViewer.setText("Viewer"); btnCollectionViewer.setFocusable(false); - btnCollectionViewer.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnCollectionViewer.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT); btnCollectionViewer.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); btnCollectionViewer.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -976,9 +935,10 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { mageToolbar.add(btnCollectionViewer); mageToolbar.add(jSeparator5); + btnSendFeedback.setIcon(new javax.swing.ImageIcon(getClass().getResource("/menu/feedback.png"))); // NOI18N btnSendFeedback.setText("Feedback"); btnSendFeedback.setFocusable(false); - btnSendFeedback.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnSendFeedback.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT); btnSendFeedback.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); btnSendFeedback.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -988,9 +948,38 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { mageToolbar.add(btnSendFeedback); mageToolbar.add(jSeparator6); + btnSymbols.setIcon(new javax.swing.ImageIcon(getClass().getResource("/menu/symbol.png"))); // NOI18N + btnSymbols.setText("Symbols"); + btnSymbols.setToolTipText("Load symbols from the internet.
\nYou need to do that only once."); + btnSymbols.setFocusable(false); + btnSymbols.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT); + btnSymbols.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnSymbols.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnSymbolsActionPerformed(evt); + } + }); + mageToolbar.add(btnSymbols); + mageToolbar.add(jSeparatorSymbols); + + btnImages.setIcon(new javax.swing.ImageIcon(getClass().getResource("/menu/images.png"))); // NOI18N + btnImages.setText("Images"); + btnImages.setToolTipText("Load card images from external sources."); + btnImages.setFocusable(false); + btnImages.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT); + btnImages.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnImages.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnImagesActionPerformed(evt); + } + }); + mageToolbar.add(btnImages); + mageToolbar.add(jSeparatorImages); + + btnAbout.setIcon(new javax.swing.ImageIcon(getClass().getResource("/menu/about.png"))); // NOI18N btnAbout.setText("About"); btnAbout.setFocusable(false); - btnAbout.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnAbout.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT); btnAbout.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); btnAbout.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -1000,31 +989,19 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { mageToolbar.add(btnAbout); mageToolbar.add(jSeparator7); - btnExit.setText("Exit"); - btnExit.setFocusable(false); - btnExit.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnExit.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnExit.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - btnExitActionPerformed(evt); - } - }); - mageToolbar.add(btnExit); - + jMemUsageLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + jMemUsageLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/menu/memory.png"))); // NOI18N jMemUsageLabel.setText("100% Free mem"); - mageToolbar.add(Box.createHorizontalGlue()); + jMemUsageLabel.setFocusable(false); + jMemUsageLabel.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT); mageToolbar.add(jMemUsageLabel); - mageToolbar.add(jSeparator8); - - lblStatus.setText("Not connected "); - mageToolbar.add(lblStatus); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(desktopPane) - .addComponent(mageToolbar, javax.swing.GroupLayout.DEFAULT_SIZE, 697, Short.MAX_VALUE) + .addComponent(desktopPane, javax.swing.GroupLayout.DEFAULT_SIZE, 769, Short.MAX_VALUE) + .addComponent(mageToolbar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -1041,14 +1018,6 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { showDeckEditor(DeckEditorMode.FREE_BUILDING, null, null, 0); }//GEN-LAST:event_btnDeckEditorActionPerformed - private void btnGamesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnGamesActionPerformed - this.showGames(true); - }//GEN-LAST:event_btnGamesActionPerformed - - private void btnExitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnExitActionPerformed - exitApp(); - }//GEN-LAST:event_btnExitActionPerformed - private void btnConnectActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnConnectActionPerformed if (SessionHandler.isConnected()) { UserRequestMessage message = new UserRequestMessage("Confirm disconnect", "Are you sure you want to disconnect?"); @@ -1090,6 +1059,26 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { FeedbackDialog.main(new String[]{}); }//GEN-LAST:event_btnSendFeedbackActionPerformed + private void btnSymbolsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSymbolsActionPerformed + downloadAdditionalResources(); + }//GEN-LAST:event_btnSymbolsActionPerformed + + public void downloadAdditionalResources() { + UserRequestMessage message = new UserRequestMessage("Download additional resources", "Do you want to download game symbols and additional image files?"); + message.setButton1("No", null); + message.setButton2("Yes", PlayerAction.CLIENT_DOWNLOAD_SYMBOLS); + showUserRequestDialog(message); + } + + private void btnImagesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnImagesActionPerformed + downloadImages(); + }//GEN-LAST:event_btnImagesActionPerformed + + public void downloadImages() { + List cards = CardRepository.instance.findCards(new CardCriteria()); + DownloadPictures.startDownload(null, cards); + } + public void exitApp() { if (SessionHandler.isConnected()) { UserRequestMessage message = new UserRequestMessage("Confirm disconnect", "You are currently connected. Are you sure you want to disconnect?"); @@ -1106,15 +1095,11 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { public void enableButtons() { btnConnect.setEnabled(true); - btnConnect.setText("Disconnect"); - btnGames.setEnabled(true); btnDeckEditor.setEnabled(true); } public void disableButtons() { btnConnect.setEnabled(true); - btnConnect.setText("Connect"); - btnGames.setEnabled(false); btnDeckEditor.setEnabled(true); } @@ -1131,9 +1116,9 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { if (setActive) { setActive(tablesPane); } else // if other panel was already shown, mamke sure it's topmost again - if (topPanebefore != null) { - setActive(topPanebefore); - } + if (topPanebefore != null) { + setActive(topPanebefore); + } } public void hideGames() { @@ -1305,20 +1290,20 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { private javax.swing.JButton btnCollectionViewer; private javax.swing.JButton btnConnect; private javax.swing.JButton btnDeckEditor; - private javax.swing.JButton btnExit; - private javax.swing.JButton btnGames; + private javax.swing.JButton btnImages; private javax.swing.JButton btnPreferences; private javax.swing.JButton btnSendFeedback; + private javax.swing.JButton btnSymbols; private static javax.swing.JDesktopPane desktopPane; private javax.swing.JLabel jMemUsageLabel; private javax.swing.JToolBar.Separator jSeparator1; private javax.swing.JToolBar.Separator jSeparator2; - private javax.swing.JToolBar.Separator jSeparator3; private javax.swing.JToolBar.Separator jSeparator4; private javax.swing.JToolBar.Separator jSeparator5; private javax.swing.JToolBar.Separator jSeparator6; private javax.swing.JToolBar.Separator jSeparator7; - private javax.swing.JToolBar.Separator jSeparator8; + private javax.swing.JToolBar.Separator jSeparatorImages; + private javax.swing.JToolBar.Separator jSeparatorSymbols; private javax.swing.JLabel lblStatus; private javax.swing.JToolBar mageToolbar; // End of variables declaration//GEN-END:variables @@ -1330,7 +1315,9 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { public void setStatusText(String status) { this.lblStatus.setText(status); - changeGUISize(); // Needed to layout the tooltbar after text length chnage + changeGUISize(); // Needed to layout the tooltbar after text length change + this.lblStatus.repaint(); + this.lblStatus.revalidate(); } public static MageUI getUI() { diff --git a/Mage.Client/src/main/java/mage/client/components/tray/MageTray.java b/Mage.Client/src/main/java/mage/client/components/tray/MageTray.java index 85079256e2b..f016f0edd24 100644 --- a/Mage.Client/src/main/java/mage/client/components/tray/MageTray.java +++ b/Mage.Client/src/main/java/mage/client/components/tray/MageTray.java @@ -1,12 +1,11 @@ package mage.client.components.tray; -import mage.client.MageFrame; -import org.apache.log4j.Logger; -import org.mage.plugins.card.utils.impl.ImageManagerImpl; - import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import mage.client.MageFrame; +import org.apache.log4j.Logger; +import org.mage.plugins.card.utils.impl.ImageManagerImpl; /** * @author noxx @@ -63,14 +62,14 @@ public class MageTray { imagesItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - MageFrame.getInstance().btnImagesActionPerformed(null); + MageFrame.getInstance().downloadImages(); } }); iconsItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - MageFrame.getInstance().btnSymbolsActionPerformed(null); + MageFrame.getInstance().downloadAdditionalResources(); } }); diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/beans/EventListenerList.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/beans/EventListenerList.java index e17eee6e69d..aaf87ff37f6 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/beans/EventListenerList.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/beans/EventListenerList.java @@ -1,39 +1,37 @@ /** * EventListenerList.java - * + * * Created on 08.04.2010 */ - package org.mage.plugins.card.dl.beans; - -import static java.util.Arrays.*; - -import java.util.ArrayList; -import java.util.EventListener; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; - import com.google.common.base.Function; import com.google.common.collect.AbstractIterator; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; - +import java.util.ArrayList; +import static java.util.Arrays.*; +import java.util.EventListener; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; /** * The class EventListenerList. - * + * * @version V0.0 08.04.2010 * @author Clemens Koza */ public class EventListenerList extends javax.swing.event.EventListenerList { + private static final long serialVersionUID = -7545754245081842909L; /** - * Returns an iterable over all listeners for the specified classes. the listener classes are in the specified - * order. for every class, listeners are in the reverse order of registering. A listener contained multiple - * times (for a single or multiple classes) is only returned the first time it occurs. + * Returns an iterable over all listeners for the specified classes. the + * listener classes are in the specified order. for every class, listeners + * are in the reverse order of registering. A listener contained multiple + * times (for a single or multiple classes) is only returned the first time + * it occurs. */ public Iterable getIterable(final Class... listenerClass) { //transform class -> iterable @@ -51,22 +49,30 @@ public class EventListenerList extends javax.swing.event.EventListenerList { } /** - * Returns an iterator over all listeners for the specified classes. the listener classes are in the specified - * order. for every class, listeners are in the reverse order of registering. A listener contained multiple - * times (for a single or multiple classes) is only returned the first time it occurs. + * Returns an iterator over all listeners for the specified classes. the + * listener classes are in the specified order. for every class, listeners + * are in the reverse order of registering. A listener contained multiple + * times (for a single or multiple classes) is only returned the first time + * it occurs. + * + * @param + * @param listenerClass + * @return */ public Iterator getIterator(Class... listenerClass) { return getIterable(listenerClass).iterator(); } /** - * Iterates backwards over the listeners registered for a class by using the original array. The Listener runs - * backwards, just as listener notification usually works. + * Iterates backwards over the listeners registered for a class by using the + * original array. The Listener runs backwards, just as listener + * notification usually works. */ private class ListenerIterator extends AbstractIterator { + private final Class listenerClass; - private Object[] listeners = listenerList; - private int index = listeners.length; + private Object[] listeners = listenerList; + private int index = listeners.length; private ListenerIterator(Class listenerClass) { this.listenerClass = listenerClass; @@ -75,8 +81,10 @@ public class EventListenerList extends javax.swing.event.EventListenerList { @Override @SuppressWarnings("unchecked") protected T computeNext() { - for(index -= 2; index >= 0; index -= 2) { - if(listenerClass == listeners[index]) return (T) listeners[index + 1]; + for (index -= 2; index >= 0; index -= 2) { + if (listenerClass == listeners[index]) { + return (T) listeners[index + 1]; + } } return endOfData(); } @@ -98,22 +106,25 @@ public class EventListenerList extends javax.swing.event.EventListenerList { } /** - * Filters the delegate iterator so that every but the first occurrence of every element is ignored. + * Filters the delegate iterator so that every but the first occurrence of + * every element is ignored. */ private static class SingletonIterator extends AbstractIterator { + private Iterator it; - private HashSet previous = new HashSet(); + private HashSet previous = new HashSet(); public SingletonIterator(Iterator it) { this.it = it; } - @Override protected T computeNext() { - while(it.hasNext()) { + while (it.hasNext()) { T next = it.next(); - if(previous.add(next)) return next; + if (previous.add(next)) { + return next; + } } return endOfData(); } diff --git a/Mage.Client/src/main/resources/menu/about.png b/Mage.Client/src/main/resources/menu/about.png new file mode 100644 index 0000000000000000000000000000000000000000..f05319ae1775414f65c14f1c2c8ebf2f6470ce16 GIT binary patch literal 860 zcmV-i1Ec(jP)ei-AHpJuh@@V^>}3TXZ=lsrp{_}mne+KvG z{jLLzwYGx>L6EkHl;(3BCs?LAl}@L^oQ+OC>D=k-yPI4DsH#6!%5(g!wd;$^DmRs* za8(}sssaYUf}Y0s#57)o-yj@*Gie&BQ@x?vkA4C6G&JqfvU583?XC5#DJ<}s+~Z=X zAEsrawQduGQP_@yFH&7lI1K3K=U5VV z`adD2+bAmxV2LJq0GUcCDk|beKaN$cE-vZeOUf&+Z{5CgYyQeyriXYFQ)v@~Ve*&w zupvJOt8*wUW{jJzI-c(G51qIMe3&w)s6}W|0?>z>kvZtovXbpoq zNVA$`iopr6JP-g?)SZMC1(-6VjBgMG0jeS+J5$4zrrn6@9Oi85J=2(>nootQ%AR$u zQc)08K@#{G*0_Q&ER`fkk_br@p~?z$NH86V6^ii5JX6M+c-}MEvMh*%OcFy+KS|9e zel&}M*X*7}mX4&t7F7r$&&;Eqfo@VZ7UoWHU02-W-J&F%f{$+i0000OUv)Pd114?^w=ga+$cDRkfH|T|!U7k@Lzoc4 zLWLb+76=2`OJ2^WwBVyGdP`2vsuUF*9^>4AOVP? zh_WmZks-vf^;Z$VzJ=eq4#am`xZQ4u2%hIrRh2aZ$8l(y2Cemc3w2!+h9R!&0+6QZ zWTYSnx{htz3BEdb*LD1Dd`qnv7-KNTptVM8Jv@)eHvHvp{Nlg(2Cr76iZUI>SO5S3 M07*qoM6N<$f_9&r#sB~S literal 0 HcmV?d00001 diff --git a/Mage.Client/src/main/resources/menu/connect.png b/Mage.Client/src/main/resources/menu/connect.png new file mode 100644 index 0000000000000000000000000000000000000000..830f2a0e5c6c3e587c9ed519ba16c7f4d72aa305 GIT binary patch literal 636 zcmV-?0)zdDP)(_`g8%^e{{R4h=>PzAFaQARU;qF*m;eA5Z<1fd zMgRZ;0!c(cRCwBqlCf?RK@f)jncF*OSGLcblM@mm??45jfC7akf)@E5kdP=43J?hb z=^_+~M+iIsC=DhB>8N-FDilONuBfzL8TN;36)|IGaV(B9sA0DyB2tyT-n zjI+vn4*)DuJt&HDbawZDU|rW>=6lBILu1S}X8y_-1&L_A+wFcy)AVB$wZ3_eCjh4E zEYN!oW?pZ%+mCv^-kMShO=Q%_w)U|^mB6#l+MbV8o?(W2K@21uoL<9g35gZ*Iz031_ z)7lc=10q$kCD<4PV+@ky((g1)54F}m7vh45z*>8^D5e`Ca(R}-JnmpH7ytmmFdS*E z4~XakfDwSJ0Q$^~PN&m1#@z891LtJLx%$Vf2fXNka}FmbC%=x5kGIRR{7gh3B7|Xx ze!q{^)zvG@%PY5nfYZMV5|p(TOG`@-5oB2g5kVA1uR5L1LjWKmIOkARc34%_u2O2h z@n@bwbI=L_GKA)E~@}c#|Z_Mi4Nj)5*}<1|%#_JtZ)M zcj7pHEFuS!N%{6Xa4z7z*I^jG)LLIJisF7ZVN*pyFj-=0HX-Q$4Z4b#v}7JO)XeD-ZO7xnX=xo^Pri-ADJu;D+jY1 zZ4!q~7PQ?I5EQX#;bE?PZ+K<*5jIvohD~p+1fB~>is=5RImmRRePN@oPk_LePgx3a zJ}E#(5$lySPNk+M4Snqgp7AFf9VbmMRE>!UnDFGOjLGzaJpXu)>~4%;XrErl6cZQL zDAjiMG|!P|0!e#(1SUL6UBs|4PEGQ`XCqgJyQg({LYTCUi1-^YFw9);GdE@JaTlOx O7(8A5T-G@yGywpD4qKxD literal 0 HcmV?d00001 diff --git a/Mage.Client/src/main/resources/menu/feedback.png b/Mage.Client/src/main/resources/menu/feedback.png new file mode 100644 index 0000000000000000000000000000000000000000..449bb13db21512076dd94680c8966a38f1c390bd GIT binary patch literal 547 zcmV+;0^I$HP)pF7<5HgbW?9;ba!ELWdKlNX>N2bPDNB8 zb~7$BHmT?0B>(^cp-DtRR5(wylgmp2Q51)#KgC_{tA%a~T7~o=2rD5WG_nXGD+od; z$)FZt8MO$CG$z7G(H_!>r9StQhjk74e)_d9dvo+YU@|#2=0YdCL47bM*CK$x2)e2Ur#G+iDt`g*OIaHE; zVBmL;fu^?*j&Lx~&Vh5gF|5^|R0%SfOev$tE$71dVF!3tg$O%|ndwP*kB&jsN!~&{ z9*0QuipB}uh78w>^i>~rR~tb)*S_PD0+wY#2nDv`bGG6>rUiG_4d;piKG#AiCL$?d z7~#C$P5AekaTo4JG@!?uG002ovPDHLkV1jRD<$C}C literal 0 HcmV?d00001 diff --git a/Mage.Client/src/main/resources/menu/images.png b/Mage.Client/src/main/resources/menu/images.png new file mode 100644 index 0000000000000000000000000000000000000000..91b5df72437b06c5b4ada44f3ad15d575d990975 GIT binary patch literal 811 zcmV+`1JwM9P)dt$&e zjrM(U#uyaE=1xmv9h#<(Qo3H|Y~1#O-EAus7jJY!Q*}gQ3~&1TAbIWAuD~=CT@(dy zyB?Ad(9n7rDJcR6(>R{G9)Zg)+HM5i*N>4^(SbAPx*+?mu4?d2J+lPzt6OpQe3upP z1T?IB+&Iy636jery6}WUdZijB`Lzuk!I)L}L$8H@gIlq_xB@31w_?9hhrI{`aS$ag zv2g6pg_4Ep<`x8eOK7<@RQ0c+4c%^;&de{t)bJ2`2bW5jtMmA3Jf`Q?HZ@}Ni-)dn zV?{YZti)>IUrKa6Tv7|?fk}M(nND*yM0Rl{CSJV-w{y2*nj*KehpzQ~6x)6kJ6l1_ zcuB^lSkt#QK=J&NKtv59w5uY#Jc_pNIvTQQS7Zkfk5Xr5VV|(<9Y-v#AWB%C9seyT zYvjHSJ(}1MB{m11Oe4FX48?^E#Yc%m>twV$rpWzEC644D-wDQHXNkhXJZ2G_dkV+^$^V2i3_tK8 z9A((u15`p>STm^S(w-^_q}s_0E*%nKOO~FaSS&Qx-uuGV=fc002ovPDHLkV1jKZZJPi9 literal 0 HcmV?d00001 diff --git a/Mage.Client/src/main/resources/menu/memory.png b/Mage.Client/src/main/resources/menu/memory.png new file mode 100644 index 0000000000000000000000000000000000000000..0088a2e46de776ae3019f8bc2f46b917d2a07ad2 GIT binary patch literal 675 zcmV;U0$lxxP)8NE-%3osy)qU&Y3 zf$<5()!Aj7sxKsyN44TC43=WQ=)9oc9B9yEwEg=fgK0}1j9ktBf}CQDsH?WF>AIFt zQuJ}i;w2$ZUU#3SZ6RY0Gw;kZ&ol1~2ky^QZ(fom$=jNJZt!z7w_pH~wdQ;R)Gh%BbQFCx+Nm!4SuS-vkr`vhhrX zM*>w%e+v~?m@q~ImPAgtLkR_3U<2F8LP3W5=LJ*ZN|S5p#sf4YFr$p~Q~Z*0Ngxf2 zjk#J#<7EAlhzlrV53~GF&pIzcCN_lz9@05UeoUXiK%N z#x+4o*i_c|6_Uu1+&TIho?3@y4k-#b8Y_o94zW*B3a1ne2-Y5s0uke$$|@=}OP-i= zNYZQA=>PrZu0MfSL=b8UhD_={W4IY1{b{)U)*gc45xtL%IYLY&hF;d`@GzI&7H&D# zh;z_BX$#hqh@q?AY3sJTod2%*Yd)_>YM0#q&ixGuh+PQsneK)F0000K-N!J41?214AqH?8C16#X zuTYOBd|?DzQ3484fLENMMaTEijqh9mQsv0v616%eVQu&b3y5PH)hI)cuSeG3i{t+S zSUmjV|vkETBj??84a7S!L{}{#Bm7UfdBNN4pg#Xg2omd Date: Fri, 2 Dec 2016 14:33:25 -0800 Subject: [PATCH 06/38] Implement final Council's dilemma card, Expropriate. --- Mage.Sets/src/mage/cards/e/Expropriate.java | 193 ++++++++++++++++++ .../src/mage/sets/ConspiracyTakeTheCrown.java | 1 + 2 files changed, 194 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/e/Expropriate.java diff --git a/Mage.Sets/src/mage/cards/e/Expropriate.java b/Mage.Sets/src/mage/cards/e/Expropriate.java new file mode 100644 index 00000000000..9621e43c900 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/Expropriate.java @@ -0,0 +1,193 @@ +/* + * 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.e; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileSpellEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.other.OwnerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.turn.TurnMod; +import mage.players.Player; +import mage.players.Players; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author JRHerlehy + */ +public class Expropriate extends CardImpl { + + public Expropriate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{7}{U}{U}"); + + // Council's dilemma — Starting with you, each player votes for time or money. For each time vote, take an extra turn after this one. For each money vote, choose a permanent owned by the voter and gain control of it. Exile Expropriate + this.getSpellAbility().addEffect(new ExpropriateDilemmaEffect()); + this.getSpellAbility().addEffect(ExileSpellEffect.getInstance()); + } + + public Expropriate(final Expropriate card) { + super(card); + } + + @Override + public Expropriate copy() { + return new Expropriate(this); + } +} + +class ExpropriateDilemmaEffect extends OneShotEffect { + + public ExpropriateDilemmaEffect() { + super(Outcome.Benefit); + this.staticText = "Council's dilemma — Starting with you, each player votes for time or money. For each time vote, take an extra turn after this one. For each money vote, choose a permanent owned by the voter and gain control of it."; + } + + public ExpropriateDilemmaEffect(final ExpropriateDilemmaEffect effect) { + super(effect); + } + + public ExpropriateDilemmaEffect(Outcome outcome) { + super(outcome); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + + //If not controller, exit out here and do not vote. + if (controller == null) return false; + + int timeCount = 0, moneyCount = 0; + Players moneyVoters = new Players(); + + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + if (player.chooseUse(Outcome.Benefit, "Choose time?", source, game)) { + timeCount++; + game.informPlayers(player.getName() + " has voted for time"); + } else { + moneyCount++; + moneyVoters.addPlayer(player); + game.informPlayers(player.getName() + " has voted for money"); + } + } + } + + if (timeCount > 0) { + if (timeCount == 1) { + game.informPlayers(controller.getName() + " will take an extra turn"); + } else { + game.informPlayers(controller.getName() + " will take " + timeCount + " extra turns"); + } + + do { + game.getState().getTurnMods().add(new TurnMod(source.getControllerId(), false)); + timeCount--; + } while (timeCount > 0); + } + + if (moneyCount > 0) { + List chosenCards = new ArrayList<>(); + + for (UUID playerId : moneyVoters.keySet()) { + FilterPermanent filter = new FilterPermanent("permanent owned by " + game.getPlayer(playerId).getName()); + filter.add(new OwnerIdPredicate(playerId)); + + Target target = new TargetPermanent(filter); + target.setNotTarget(true); + + if (controller.choose(Outcome.GainControl, target, source.getSourceId(), game)) { + Permanent targetPermanent = game.getPermanent(target.getFirstTarget()); + + if (targetPermanent != null) chosenCards.add(targetPermanent); + } + } + + for (Permanent permanent : chosenCards) { + ContinuousEffect effect = new ExpropriateControlEffect(controller.getId()); + effect.setTargetPointer(new FixedTarget(permanent.getId())); + game.addEffect(effect, source); + } + } //End moneyCount if statement + + return true; + } + + @Override + public ExpropriateDilemmaEffect copy() { + return new ExpropriateDilemmaEffect(this); + } + +} + +class ExpropriateControlEffect extends ContinuousEffectImpl { + + private UUID controllerId; + + public ExpropriateControlEffect(UUID controllerId) { + super(Duration.EndOfGame, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); + this.controllerId = controllerId; + } + + public ExpropriateControlEffect(final ExpropriateControlEffect effect) { + super(effect); + this.controllerId = effect.controllerId; + } + + @Override + public ExpropriateControlEffect copy() { + return new ExpropriateControlEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); + if (permanent != null && controllerId != null) { + return permanent.changeControllerId(controllerId, game); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/ConspiracyTakeTheCrown.java b/Mage.Sets/src/mage/sets/ConspiracyTakeTheCrown.java index 8a1131debd3..4535ef849c5 100644 --- a/Mage.Sets/src/mage/sets/ConspiracyTakeTheCrown.java +++ b/Mage.Sets/src/mage/sets/ConspiracyTakeTheCrown.java @@ -105,6 +105,7 @@ public class ConspiracyTakeTheCrown extends ExpansionSet { cards.add(new SetCardInfo("Evolving Wilds", 218, Rarity.COMMON, mage.cards.e.EvolvingWilds.class)); cards.add(new SetCardInfo("Exotic Orchard", 219, Rarity.RARE, mage.cards.e.ExoticOrchard.class)); cards.add(new SetCardInfo("Explosive Vegetation", 180, Rarity.UNCOMMON, mage.cards.e.ExplosiveVegetation.class)); + cards.add(new SetCardInfo("Expropriate", 30, Rarity.MYTHIC, mage.cards.e.Expropriate.class)); cards.add(new SetCardInfo("Fade into Antiquity", 181, Rarity.COMMON, mage.cards.f.FadeIntoAntiquity.class)); cards.add(new SetCardInfo("Faith's Reward", 84, Rarity.RARE, mage.cards.f.FaithsReward.class)); cards.add(new SetCardInfo("Farbog Boneflinger", 134, Rarity.UNCOMMON, mage.cards.f.FarbogBoneflinger.class)); From 3eea0cb13d51d52a32a61f40cd0af2f93d5924d8 Mon Sep 17 00:00:00 2001 From: JRHerlehy Date: Fri, 2 Dec 2016 15:15:11 -0800 Subject: [PATCH 07/38] Add chat information message for gaining control of a permanent. Reformatted and optimized imports. --- Mage.Sets/src/mage/cards/e/Expropriate.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Mage.Sets/src/mage/cards/e/Expropriate.java b/Mage.Sets/src/mage/cards/e/Expropriate.java index 9621e43c900..fefd82a3c53 100644 --- a/Mage.Sets/src/mage/cards/e/Expropriate.java +++ b/Mage.Sets/src/mage/cards/e/Expropriate.java @@ -28,21 +28,15 @@ package mage.cards.e; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileSpellEffect; -import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterPermanent; -import mage.filter.predicate.Predicates; import mage.filter.predicate.other.OwnerIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; @@ -53,8 +47,11 @@ import mage.target.Target; import mage.target.TargetPermanent; import mage.target.targetpointer.FixedTarget; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author JRHerlehy */ public class Expropriate extends CardImpl { @@ -150,6 +147,7 @@ class ExpropriateDilemmaEffect extends OneShotEffect { ContinuousEffect effect = new ExpropriateControlEffect(controller.getId()); effect.setTargetPointer(new FixedTarget(permanent.getId())); game.addEffect(effect, source); + game.informPlayers(controller.getName() + " gained control of " + permanent.getName() + " owned by " + game.getPlayer(permanent.getOwnerId()).getName()); } } //End moneyCount if statement From 9f66125cf99e96e239ad494ba5d5fe5b30223c63 Mon Sep 17 00:00:00 2001 From: spjspj Date: Sat, 3 Dec 2016 18:26:40 +1100 Subject: [PATCH 08/38] spjspj - Fix for must attack effects not forcing attacks in multiplayer --- .../src/mage/player/human/HumanPlayer.java | 12 +++++------- Mage/src/main/java/mage/game/combat/Combat.java | 13 +++++++++++-- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index f26b96a4b4c..72eddf6af08 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -52,6 +52,7 @@ import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.PhyrexianManaCost; import mage.abilities.effects.RequirementEffect; +import mage.abilities.effects.common.combat.AttacksIfAbleAllEffect; import mage.abilities.mana.ActivatedManaAbilityImpl; import mage.cards.Card; import mage.cards.Cards; @@ -921,7 +922,10 @@ public class HumanPlayer extends PlayerImpl { FilterCreatureForCombat filter = filterCreatureForCombat.copy(); filter.add(new ControllerIdPredicate(attackingPlayerId)); while (!abort) { - + if (passedAllTurns || passedUntilEndStepBeforeMyTurn + || (!getUserData().getUserSkipPrioritySteps().isStopOnDeclareAttackersDuringSkipAction() && (passedTurn || passedTurnSkipStack || passedUntilEndOfTurn || passedUntilNextMain))) { + return; + } Map options = new HashMap<>(); List possibleAttackers = new ArrayList<>(); @@ -933,12 +937,6 @@ public class HumanPlayer extends PlayerImpl { options.put(Constants.Option.POSSIBLE_ATTACKERS, (Serializable) possibleAttackers); if (possibleAttackers.size() > 0) { options.put(Constants.Option.SPECIAL_BUTTON, (Serializable) "All attack"); - if (getUserData().getUserSkipPrioritySteps().isStopOnDeclareAttackersDuringSkipAction()) { - resetPlayerPassedActions(); - } - } else if (passedAllTurns || passedUntilEndStepBeforeMyTurn - || (!getUserData().getUserSkipPrioritySteps().isStopOnDeclareAttackersDuringSkipAction() && (passedTurn || passedTurnSkipStack || passedUntilEndOfTurn || passedUntilNextMain))) { - return; } game.fireSelectEvent(playerId, "Select attackers", options); diff --git a/Mage/src/main/java/mage/game/combat/Combat.java b/Mage/src/main/java/mage/game/combat/Combat.java index c3afd1477bf..58c89c0b5b1 100644 --- a/Mage/src/main/java/mage/game/combat/Combat.java +++ b/Mage/src/main/java/mage/game/combat/Combat.java @@ -339,8 +339,17 @@ public class Combat implements Serializable, Copyable { // No need to attack a special defender if (defendersForcedToAttack.isEmpty()) { if (defendersForcedToAttack.isEmpty()) { - if (defendersCostlessAttackable.size() == 1) { - player.declareAttacker(creature.getId(), defenders.iterator().next(), game, false); + if (defendersCostlessAttackable.size() >= 1) { + if (defenders.size() == 1) { + player.declareAttacker(creature.getId(), defenders.iterator().next(), game, false); + } else { + TargetDefender target = new TargetDefender(defenders, creature.getId()); + target.setRequired(true); + target.setTargetName("planeswalker or player for " + creature.getLogName() + " to attack"); + if (player.chooseTarget(Outcome.Damage, target, null, game)) { + player.declareAttacker(creature.getId(), target.getFirstTarget(), game, false); + } + } } } else { TargetDefender target = new TargetDefender(defendersCostlessAttackable, creature.getId()); From 2d1e7761530f35d88daf6b491116aaf2d156925a Mon Sep 17 00:00:00 2001 From: spjspj Date: Sat, 3 Dec 2016 18:48:41 +1100 Subject: [PATCH 09/38] spjspj - Fix for must attack effects not forcing attacks in multiplayer --- .../Mage.Player.Human/src/mage/player/human/HumanPlayer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index 72eddf6af08..f3a4fcae963 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -52,7 +52,6 @@ import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.PhyrexianManaCost; import mage.abilities.effects.RequirementEffect; -import mage.abilities.effects.common.combat.AttacksIfAbleAllEffect; import mage.abilities.mana.ActivatedManaAbilityImpl; import mage.cards.Card; import mage.cards.Cards; From 6f0aafb449122aaf5bed8433916348020f1e7381 Mon Sep 17 00:00:00 2001 From: spjspj Date: Sat, 3 Dec 2016 19:29:57 +1100 Subject: [PATCH 10/38] spjspj - More updates to edh Power Level. --- .../src/mage/deck/Commander.java | 115 ++++++++++++------ 1 file changed, 75 insertions(+), 40 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java index 261aafb75bb..66b858ae86d 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java @@ -220,6 +220,7 @@ public class Commander extends Constructed { boolean buyback = false; boolean cascade = false; boolean copy = false; + boolean costLessEach = false; boolean exile = false; boolean exileAll = false; boolean counter = false; @@ -227,20 +228,25 @@ public class Commander extends Constructed { boolean destroyAll = false; boolean each = false; boolean exalted = false; + boolean doesntUntap = false; boolean drawCards = false; boolean extraTurns = false; boolean gainControl = false; + boolean hexproof = false; boolean infect = false; boolean mayCastForFree = false; boolean miracle = false; boolean overload = false; boolean persist = false; boolean proliferate = false; + boolean protection = false; boolean retrace = false; boolean sacrifice = false; + boolean shroud = false; boolean skip = false; boolean sliver = false; boolean tutor = false; + boolean unblockable = false; boolean undying = false; boolean wheneverEnters = false; boolean youControlTarget = false; @@ -251,9 +257,12 @@ public class Commander extends Constructed { buyback |= s.contains("buyback"); cascade |= s.contains("cascade"); copy |= s.contains("copy"); + costLessEach |= s.contains("cost") || s.contains("less") || s.contains("each"); counter |= s.contains("counter") && s.contains("target"); destroy |= s.contains("destroy"); destroyAll |= s.contains("destroy all"); + doesntUntap |= s.contains("doesn't untap"); + doesntUntap |= s.contains("don't untap"); drawCards |= s.contains("draw cards"); each |= s.contains("each"); exalted |= s.contains("exalted"); @@ -261,17 +270,21 @@ public class Commander extends Constructed { exileAll |= s.contains("exile") && s.contains(" all "); extraTurns |= s.contains("extra turn"); gainControl |= s.contains("gain control"); + hexproof |= s.contains("hexproof"); infect |= s.contains("infect"); mayCastForFree |= s.contains("may cast") && s.contains("without paying"); miracle |= s.contains("miracle"); overload |= s.contains("overload"); persist |= s.contains("persist"); proliferate |= s.contains("proliferate"); + protection |= s.contains("protection"); retrace |= s.contains("retrace"); sacrifice |= s.contains("sacrifice"); - skip |= s.contains("skip") && s.contains("each"); + shroud |= s.contains("shroud"); + skip |= s.contains("skip"); sliver |= s.contains("sliver"); tutor |= s.contains("search your library"); + unblockable |= s.contains("can't be blocked"); undying |= s.contains("undying"); wheneverEnters |= s.contains("when") && s.contains("another") && s.contains("enters"); youControlTarget |= s.contains("you control target"); @@ -292,9 +305,15 @@ public class Commander extends Constructed { if (overload) { thisMaxPower = Math.max(thisMaxPower, 5); } + if (costLessEach) { + thisMaxPower = Math.max(thisMaxPower, 5); + } if (cascade) { thisMaxPower = Math.max(thisMaxPower, 4); } + if (doesntUntap) { + thisMaxPower = Math.max(thisMaxPower, 4); + } if (each) { thisMaxPower = Math.max(thisMaxPower, 4); } @@ -310,9 +329,15 @@ public class Commander extends Constructed { if (proliferate) { thisMaxPower = Math.max(thisMaxPower, 4); } + if (protection) { + thisMaxPower = Math.max(thisMaxPower, 4); + } if (skip) { thisMaxPower = Math.max(thisMaxPower, 4); } + if (unblockable) { + thisMaxPower = Math.max(thisMaxPower, 4); + } if (wheneverEnters) { thisMaxPower = Math.max(thisMaxPower, 4); } @@ -325,6 +350,12 @@ public class Commander extends Constructed { if (destroyAll) { thisMaxPower = Math.max(thisMaxPower, 3); } + if (hexproof) { + thisMaxPower = Math.max(thisMaxPower, 3); + } + if (shroud) { + thisMaxPower = Math.max(thisMaxPower, 3); + } if (undying) { thisMaxPower = Math.max(thisMaxPower, 3); } @@ -401,6 +432,7 @@ public class Commander extends Constructed { || cn.equals("edric, spymaster of trest") || cn.equals("elesh norn, grand cenobite") || cn.equals("entomb") + || cn.equals("force of will") || cn.equals("food chain") || cn.equals("gaddock teeg") || cn.equals("gaea's cradle") @@ -456,7 +488,8 @@ public class Commander extends Constructed { } // Parts of infinite combos - if (cn.equals("animate artifact") || cn.equals("archaeomancer") + if (cn.equals("animate artifact") || cn.equals("animar, soul of element") + || cn.equals("archaeomancer") || cn.equals("ashnod's altar") || cn.equals("azami, lady of scrolls") || cn.equals("basalt monolith") || cn.equals("brago, king eternal") || cn.equals("candelabra of tawnos") || cn.equals("cephalid aristocrat") @@ -483,6 +516,7 @@ public class Commander extends Constructed { || cn.equals("myr turbine") || cn.equals("narset, enlightened master") || cn.equals("nekusar, the mindrazer") || cn.equals("norin the wary") || cn.equals("opalescence") || cn.equals("ornithopter") + || cn.equals("peregrine drake") || cn.equals("palinchron") || cn.equals("planar portal") || cn.equals("power artifact") || cn.equals("rings of brighthearth") || cn.equals("rite of replication") || cn.equals("sanguine bond") || cn.equals("sensei's divining top") @@ -497,7 +531,7 @@ public class Commander extends Constructed { || cn.equals("workhorse") || cn.equals("worldgorger dragon") || cn.equals("worthy cause") || cn.equals("yawgmoth's will") || cn.equals("zealous conscripts")) { - thisMaxPower = Math.max(thisMaxPower, 6); + thisMaxPower = Math.max(thisMaxPower, 7); } edhPowerLevel += thisMaxPower; } @@ -507,48 +541,49 @@ public class Commander extends Constructed { String cn = commander.getName().toLowerCase(); // Least fun commanders - if (cn.equals("azami, lady of scrolls") - || cn.equals("braids, cabal minion") - || cn.equals("child of alara") - || cn.equals("derevi, empyrial tactician") - || cn.equals("edric, spymaster of trest") - || cn.equals("gaddock teeg") - || cn.equals("grand arbiter augustin iv") - || cn.equals("hokori, dust drinker") - || cn.equals("iona, shield of emeria") - || cn.equals("jin-gitaxias, core augur") - || cn.equals("karador, ghost chieftain") - || cn.equals("leovold, emissary of trest") - || cn.equals("linvala, keeper of silence") - || cn.equals("llawan, cephalid empress") - || cn.equals("memnarch") - || cn.equals("meren of clan nel toth") - || cn.equals("michiko konda, truth seeker") - || cn.equals("narset, enlightened master") - || cn.equals("nekusar, the mindrazer") - || cn.equals("norin the wary") - || cn.equals("numot, the devastator") - || cn.equals("sheoldred, whispering one") - || cn.equals("teferi, mage of zhalfir") - || cn.equals("zur the enchanter")) { + if (cn.equals("animar, soul of element") + || cn.equals("azami, lady of scrolls") + || cn.equals("braids, cabal minion") + || cn.equals("child of alara") + || cn.equals("derevi, empyrial tactician") + || cn.equals("edric, spymaster of trest") + || cn.equals("gaddock teeg") + || cn.equals("grand arbiter augustin iv") + || cn.equals("hokori, dust drinker") + || cn.equals("iona, shield of emeria") + || cn.equals("jin-gitaxias, core augur") + || cn.equals("karador, ghost chieftain") + || cn.equals("leovold, emissary of trest") + || cn.equals("linvala, keeper of silence") + || cn.equals("llawan, cephalid empress") + || cn.equals("memnarch") + || cn.equals("meren of clan nel toth") + || cn.equals("michiko konda, truth seeker") + || cn.equals("narset, enlightened master") + || cn.equals("nekusar, the mindrazer") + || cn.equals("norin the wary") + || cn.equals("numot, the devastator") + || cn.equals("sheoldred, whispering one") + || cn.equals("teferi, mage of zhalfir") + || cn.equals("zur the enchanter")) { thisMaxPower = Math.max(thisMaxPower, 15); } // Next least fun commanders if (cn.equals("anafenza, the foremost") - || cn.equals("arcum dagsson") - || cn.equals("azusa, lost but seeking") - || cn.equals("brago, king eternal") - || cn.equals("captain sisay") - || cn.equals("elesh norn, grand cenobite") - || cn.equals("malfegor") - || cn.equals("maelstrom wanderer") - || cn.equals("mikaeus the unhallowed") - || cn.equals("nath of the gilt-leaf") - || cn.equals("purphoros, god of the forge") - || cn.equals("sen triplets") - || cn.equals("urabrask the hidden") - || cn.equals("vorinclex, voice of hunger")) { + || cn.equals("arcum dagsson") + || cn.equals("azusa, lost but seeking") + || cn.equals("brago, king eternal") + || cn.equals("captain sisay") + || cn.equals("elesh norn, grand cenobite") + || cn.equals("malfegor") + || cn.equals("maelstrom wanderer") + || cn.equals("mikaeus the unhallowed") + || cn.equals("nath of the gilt-leaf") + || cn.equals("purphoros, god of the forge") + || cn.equals("sen triplets") + || cn.equals("urabrask the hidden") + || cn.equals("vorinclex, voice of hunger")) { thisMaxPower = Math.max(thisMaxPower, 10); } edhPowerLevel += thisMaxPower; From f3f498b10cc580d28af1a18c0d7b45fe4c7d9035 Mon Sep 17 00:00:00 2001 From: spjspj Date: Sun, 4 Dec 2016 23:47:04 +1100 Subject: [PATCH 11/38] spjspj - Crown of the Ages (ICE,5ED). --- .../src/mage/cards/c/CrownOfTheAges.java | 172 ++++++++++++++++++ Mage.Sets/src/mage/sets/FifthEdition.java | 1 + Mage.Sets/src/mage/sets/IceAge.java | 1 + 3 files changed, 174 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/c/CrownOfTheAges.java diff --git a/Mage.Sets/src/mage/cards/c/CrownOfTheAges.java b/Mage.Sets/src/mage/cards/c/CrownOfTheAges.java new file mode 100644 index 00000000000..bc66c7ed776 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CrownOfTheAges.java @@ -0,0 +1,172 @@ +/* + * 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.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterEnchantmentPermanent; +import mage.filter.predicate.Predicate; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; + +/** + * + * @author spjspj + */ +public class CrownOfTheAges extends CardImpl { + + private static final FilterEnchantmentPermanent filter = new FilterEnchantmentPermanent("Aura attached to a creature"); + + static { + filter.add(new AttachmentAttachedToCardTypePredicate(CardType.CREATURE)); + filter.add(new SubtypePredicate("Aura")); + } + + public CrownOfTheAges(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + // {4}, {tap}: Attach target Aura attached to a creature to another creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CrownOfTheAgesEffect(), new GenericManaCost(4)); + ability.addTarget(new TargetPermanent(filter)); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + public CrownOfTheAges(final CrownOfTheAges card) { + super(card); + } + + @Override + public CrownOfTheAges copy() { + return new CrownOfTheAges(this); + } +} + +class AttachmentAttachedToCardTypePredicate implements Predicate { + + private final CardType cardType; + + public AttachmentAttachedToCardTypePredicate(CardType cardType) { + this.cardType = cardType; + } + + @Override + public boolean apply(Permanent input, Game game) { + if (input.getAttachedTo() != null) { + Permanent attachedTo = game.getPermanent(input.getAttachedTo()); + if (attachedTo != null && attachedTo.getCardType().contains(cardType)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return "AttachmentAttachedToCardType(" + cardType + ')'; + } +} + +class CrownOfTheAgesEffect extends OneShotEffect { + + public CrownOfTheAgesEffect() { + super(Outcome.BoostCreature); + this.staticText = "Attach target Aura attached to a creature to another creature"; + } + + public CrownOfTheAgesEffect(final CrownOfTheAgesEffect effect) { + super(effect); + } + + @Override + public CrownOfTheAgesEffect copy() { + return new CrownOfTheAgesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + UUID auraId = getTargetPointer().getFirst(game, source); + Permanent aura = game.getPermanent(auraId); + Permanent fromPermanent = game.getPermanent(aura.getAttachedTo()); + Player controller = game.getPlayer(source.getControllerId()); + if (fromPermanent != null && controller != null) { + Boolean passed = true; + FilterCreaturePermanent filterChoice = new FilterCreaturePermanent("another creature"); + filterChoice.add(Predicates.not(new PermanentIdPredicate(fromPermanent.getId()))); + + Target chosenCreatureToAttachAura = new TargetPermanent(filterChoice); + chosenCreatureToAttachAura.setNotTarget(true); + + if (chosenCreatureToAttachAura.canChoose(source.getSourceId(), source.getControllerId(), game) + && controller.choose(Outcome.Neutral, chosenCreatureToAttachAura, source.getSourceId(), game)) { + Permanent creatureToAttachAura = game.getPermanent(chosenCreatureToAttachAura.getFirstTarget()); + if (creatureToAttachAura != null) { + if (aura != null && passed) { + // Check the target filter + Target target = aura.getSpellAbility().getTargets().get(0); + if (target instanceof TargetPermanent) { + if (!target.getFilter().match(creatureToAttachAura, game)) { + passed = false; + } + } + // Check for protection + MageObject auraObject = game.getObject(auraId); + if (creatureToAttachAura.cantBeAttachedBy(auraObject, game)) { + passed = false; + } + } + if (passed) { + fromPermanent.removeAttachment(aura.getId(), game); + creatureToAttachAura.addAttachment(aura.getId(), game); + return true; + } + } + } + return true; + } + + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/FifthEdition.java b/Mage.Sets/src/mage/sets/FifthEdition.java index 33bd237509f..467b517593f 100644 --- a/Mage.Sets/src/mage/sets/FifthEdition.java +++ b/Mage.Sets/src/mage/sets/FifthEdition.java @@ -103,6 +103,7 @@ public class FifthEdition extends ExpansionSet { cards.add(new SetCardInfo("Craw Giant", 147, Rarity.UNCOMMON, mage.cards.c.CrawGiant.class)); cards.add(new SetCardInfo("Craw Wurm", 148, Rarity.COMMON, mage.cards.c.CrawWurm.class)); cards.add(new SetCardInfo("Crimson Manticore", 217, Rarity.RARE, mage.cards.c.CrimsonManticore.class)); + cards.add(new SetCardInfo("Crown of the Ages", 360, Rarity.RARE, mage.cards.c.CrownOfTheAges.class)); cards.add(new SetCardInfo("Crumble", 149, Rarity.UNCOMMON, mage.cards.c.Crumble.class)); cards.add(new SetCardInfo("Crusade", 298, Rarity.RARE, mage.cards.c.Crusade.class)); cards.add(new SetCardInfo("Crystal Rod", 361, Rarity.UNCOMMON, mage.cards.c.CrystalRod.class)); diff --git a/Mage.Sets/src/mage/sets/IceAge.java b/Mage.Sets/src/mage/sets/IceAge.java index 19c66b44fda..b8b5459f826 100644 --- a/Mage.Sets/src/mage/sets/IceAge.java +++ b/Mage.Sets/src/mage/sets/IceAge.java @@ -87,6 +87,7 @@ public class IceAge extends ExpansionSet { cards.add(new SetCardInfo("Cold Snap", 241, Rarity.UNCOMMON, mage.cards.c.ColdSnap.class)); cards.add(new SetCardInfo("Conquer", 180, Rarity.UNCOMMON, mage.cards.c.Conquer.class)); cards.add(new SetCardInfo("Counterspell", 64, Rarity.COMMON, mage.cards.c.Counterspell.class)); + cards.add(new SetCardInfo("Crown of the Ages", 290, Rarity.RARE, mage.cards.c.CrownOfTheAges.class)); cards.add(new SetCardInfo("Curse of Marit Lage", 181, Rarity.RARE, mage.cards.c.CurseOfMaritLage.class)); cards.add(new SetCardInfo("Dance of the Dead", 6, Rarity.UNCOMMON, mage.cards.d.DanceOfTheDead.class)); cards.add(new SetCardInfo("Dark Banishing", 7, Rarity.COMMON, mage.cards.d.DarkBanishing.class)); From 85f9812d7256fe3ec0473a9fb0fa3d56f885fdb7 Mon Sep 17 00:00:00 2001 From: Fenhl Date: Mon, 5 Dec 2016 01:59:42 +0000 Subject: [PATCH 12/38] Fix basic land artwork of C16 precons --- .../Commander 2016/Breed Lethality (GWUB).dck | 16 ++++++++++++---- .../Commander 2016/Entropic Uprising (UBRG).dck | 16 ++++++++++++---- .../Commander 2016/Invent Superiority (WUBR).dck | 16 ++++++++++++---- .../Commander 2016/Open Hostility (BRGW).dck | 16 ++++++++++++---- .../Commander 2016/Stalwart Unity (RGWU) .dck | 16 ++++++++++++---- 5 files changed, 60 insertions(+), 20 deletions(-) diff --git a/Mage.Client/release/sample-decks/Commander/Commander 2016/Breed Lethality (GWUB).dck b/Mage.Client/release/sample-decks/Commander/Commander 2016/Breed Lethality (GWUB).dck index ddd95532234..5a4b93bdf98 100644 --- a/Mage.Client/release/sample-decks/Commander/Commander 2016/Breed Lethality (GWUB).dck +++ b/Mage.Client/release/sample-decks/Commander/Commander 2016/Breed Lethality (GWUB).dck @@ -17,7 +17,9 @@ 1 [C16:57] Abzan Falconer 1 [C16:56] Ash Barrens 1 [C16:9] Grip of Phyresis -5 [C16:337] Plains +2 [C16:337] Plains +1 [C16:338] Plains +2 [C16:339] Plains 1 [C16:99] Tezzeret's Gambit 1 [C16:217] Putrefy 1 [C16:7] Deepglow Skate @@ -67,17 +69,23 @@ 1 [C16:33] Ishai, Ojutai Dragonspeaker 1 [C16:40] Reyhan, Last of the Abzan 1 [C16:186] Bred for the Hunt -4 [C16:340] Island +1 [C16:340] Island +2 [C16:341] Island +1 [C16:340] Island 1 [C16:100] Thrummingbird 1 [C16:144] Champion of Lambholt 1 [C16:101] Treasure Cruise 1 [C16:266] Orzhov Signet -5 [C16:343] Swamp +2 [C16:343] Swamp +1 [C16:344] Swamp +2 [C16:345] Swamp 1 [C16:106] Bane of the Living 1 [C16:227] Vorel of the Hull Clade 1 [C16:44] Sylvan Reclamation 1 [C16:88] Disdainful Stroke 1 [C16:228] Vulturous Zombie -7 [C16:349] Forest +3 [C16:349] Forest +2 [C16:350] Forest +2 [C16:351] Forest 1 [C16:308] Murmuring Bosk SB: 1 [C16:28] Atraxa, Praetors' Voice diff --git a/Mage.Client/release/sample-decks/Commander/Commander 2016/Entropic Uprising (UBRG).dck b/Mage.Client/release/sample-decks/Commander/Commander 2016/Entropic Uprising (UBRG).dck index cfce6fc688e..e2ebfff4137 100644 --- a/Mage.Client/release/sample-decks/Commander/Commander 2016/Entropic Uprising (UBRG).dck +++ b/Mage.Client/release/sample-decks/Commander/Commander 2016/Entropic Uprising (UBRG).dck @@ -63,22 +63,30 @@ 1 [C16:184] Bloodbraid Elf 1 [C16:82] Aeon Chronicler 1 [C16:81] Academy Elite -5 [C16:340] Island +2 [C16:340] Island +2 [C16:341] Island +1 [C16:342] Island 1 [C16:143] Burgeoning 1 [C16:188] Coiling Oracle 1 [C16:101] Treasure Cruise 1 [C16:189] Consuming Aberration 1 [C16:222] Spellheart Chimera 1 [C16:49] Vial Smasher the Fierce -5 [C16:343] Swamp +2 [C16:343] Swamp +2 [C16:344] Swamp +1 [C16:345] Swamp 1 [C16:268] Rakdos Signet 1 [C16:47] Treacherous Terrain 1 [C16:104] Windfall 1 [C16:148] Far Wanderings 1 [C16:46] Thrasios, Triton Hero -5 [C16:346] Mountain +1 [C16:346] Mountain +2 [C16:347] Mountain +1 [C16:348] Mountain 1 [C16:105] Army of the Damned 1 [C16:303] Jungle Hollow -5 [C16:349] Forest +2 [C16:349] Forest +2 [C16:350] Forest +1 [C16:351] Forest 1 [C16:229] Whispering Madness SB: 1 [C16:50] Yidris, Maelstrom Wielder diff --git a/Mage.Client/release/sample-decks/Commander/Commander 2016/Invent Superiority (WUBR).dck b/Mage.Client/release/sample-decks/Commander/Commander 2016/Invent Superiority (WUBR).dck index d197ca84e29..a9583cbcbd4 100644 --- a/Mage.Client/release/sample-decks/Commander/Commander 2016/Invent Superiority (WUBR).dck +++ b/Mage.Client/release/sample-decks/Commander/Commander 2016/Invent Superiority (WUBR).dck @@ -19,7 +19,9 @@ 1 [C16:12] Curse of Vengeance 1 [C16:9] Grip of Phyresis 1 [C16:8] Faerie Artisans -5 [C16:337] Plains +1 [C16:337] Plains +2 [C16:338] Plains +2 [C16:339] Plains 1 [C16:6] Coastal Breach 1 [C16:64] Dispeller's Capsule 1 [C16:281] Arcane Sanctum @@ -68,17 +70,23 @@ 1 [C16:140] Whipflare 1 [C16:262] Mycosynth Wellspring 1 [C16:263] Myr Battlesphere -5 [C16:340] Island +2 [C16:340] Island +1 [C16:341] Island +2 [C16:342] Island 1 [C16:264] Myr Retriever 1 [C16:221] Sharuum the Hegemon 1 [C16:265] Nevinyrral's Disk -4 [C16:343] Swamp +1 [C16:343] Swamp +2 [C16:344] Swamp +1 [C16:345] Swamp 1 [C16:223] Sphinx Summoner 1 [C16:102] Trinket Mage 1 [C16:224] Sydri, Galvanic Genius 1 [C16:103] Vedalken Engineer 1 [C16:269] Shimmer Myr -4 [C16:346] Mountain +2 [C16:346] Mountain +1 [C16:347] Mountain +1 [C16:348] Mountain 1 [C16:89] Etherium Sculptor 1 [C16:107] Beacon of Unrest 1 [C16:109] Executioner's Capsule diff --git a/Mage.Client/release/sample-decks/Commander/Commander 2016/Open Hostility (BRGW).dck b/Mage.Client/release/sample-decks/Commander/Commander 2016/Open Hostility (BRGW).dck index c0028d1d0f9..9d2ef543779 100644 --- a/Mage.Client/release/sample-decks/Commander/Commander 2016/Open Hostility (BRGW).dck +++ b/Mage.Client/release/sample-decks/Commander/Commander 2016/Open Hostility (BRGW).dck @@ -22,7 +22,9 @@ 1 [C16:215] Necrogenesis 1 [C16:336] Windbrisk Heights 1 [C16:56] Ash Barrens -3 [C16:337] Plains +1 [C16:337] Plains +1 [C16:338] Plains +1 [C16:339] Plains 1 [C16:160] Quirion Explorer 1 [C16:161] Rampant Growth 1 [C16:240] Order // Chaos @@ -69,12 +71,16 @@ 1 [C16:185] Boros Charm 1 [C16:142] Beastmaster Ascension 1 [C16:187] Clan Defiance -3 [C16:343] Swamp +1 [C16:343] Swamp +1 [C16:344] Swamp +1 [C16:345] Swamp 1 [C16:300] Gruul Turf 1 [C16:48] Tymna the Weaver 1 [C16:147] Den Protector 1 [C16:47] Treacherous Terrain -5 [C16:346] Mountain +2 [C16:346] Mountain +1 [C16:347] Mountain +2 [C16:348] Mountain 1 [C16:225] Terminate 1 [C16:45] Tana, the Bloodsower 1 [C16:149] Farseek @@ -82,7 +88,9 @@ 1 [C16:304] Jungle Shrine 1 [C16:44] Sylvan Reclamation 1 [C16:305] Karplusan Forest -5 [C16:349] Forest +2 [C16:349] Forest +1 [C16:350] Forest +2 [C16:351] Forest 1 [C16:108] Brutal Hordechief 1 [C16:307] Mosswort Bridge SB: 1 [C16:41] Saskia the Unyielding diff --git a/Mage.Client/release/sample-decks/Commander/Commander 2016/Stalwart Unity (RGWU) .dck b/Mage.Client/release/sample-decks/Commander/Commander 2016/Stalwart Unity (RGWU) .dck index 8ace597f7e1..819d5e9de2a 100644 --- a/Mage.Client/release/sample-decks/Commander/Commander 2016/Stalwart Unity (RGWU) .dck +++ b/Mage.Client/release/sample-decks/Commander/Commander 2016/Stalwart Unity (RGWU) .dck @@ -18,7 +18,9 @@ 1 [C16:259] Keening Stone 1 [C16:55] Prismatic Geoscope 1 [C16:216] Progenitor Mimic -5 [C16:337] Plains +2 [C16:337] Plains +2 [C16:338] Plains +1 [C16:339] Plains 1 [C16:219] Rubblehulk 1 [C16:4] Selfless Squire 1 [C16:3] Orzhov Advokist @@ -66,7 +68,9 @@ 1 [C16:83] Arcane Denial 1 [C16:141] Beast Within 1 [C16:80] Windborn Muse -5 [C16:340] Island +2 [C16:340] Island +1 [C16:341] Island +2 [C16:342] Island 1 [C16:220] Selvala, Explorer Returned 1 [C16:145] Collective Voyage 1 [C16:146] Cultivate @@ -75,10 +79,14 @@ 1 [C16:301] Homeward Path 1 [C16:47] Treacherous Terrain 1 [C16:302] Izzet Boilerworks -5 [C16:346] Mountain +1 [C16:346] Mountain +2 [C16:347] Mountain +2 [C16:348] Mountain 1 [C16:304] Jungle Shrine 1 [C16:44] Sylvan Reclamation -5 [C16:349] Forest +1 [C16:349] Forest +2 [C16:350] Forest +2 [C16:351] Forest 1 [C16:306] Krosan Verge 1 [C16:309] Myriad Landscape SB: 1 [C16:36] Kynaios and Tiro of Meletis From 96b4a446a95e425091acb9d6622da3912cb01742 Mon Sep 17 00:00:00 2001 From: Fenhl Date: Mon, 5 Dec 2016 05:01:26 +0000 Subject: [PATCH 13/38] Fix typo in the Breed Lethality deck --- .../Commander/Commander 2016/Breed Lethality (GWUB).dck | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Client/release/sample-decks/Commander/Commander 2016/Breed Lethality (GWUB).dck b/Mage.Client/release/sample-decks/Commander/Commander 2016/Breed Lethality (GWUB).dck index 5a4b93bdf98..013c0f960cd 100644 --- a/Mage.Client/release/sample-decks/Commander/Commander 2016/Breed Lethality (GWUB).dck +++ b/Mage.Client/release/sample-decks/Commander/Commander 2016/Breed Lethality (GWUB).dck @@ -71,7 +71,7 @@ 1 [C16:186] Bred for the Hunt 1 [C16:340] Island 2 [C16:341] Island -1 [C16:340] Island +1 [C16:342] Island 1 [C16:100] Thrummingbird 1 [C16:144] Champion of Lambholt 1 [C16:101] Treasure Cruise From 02bfd09a0c7d2a5cb59a85b451a2a67b3c47c7df Mon Sep 17 00:00:00 2001 From: spjspj Date: Mon, 5 Dec 2016 22:58:35 +1100 Subject: [PATCH 14/38] spjspj - More updates to edh Power Level. --- .../src/mage/deck/Commander.java | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java index 66b858ae86d..2273473b938 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java @@ -217,8 +217,10 @@ public class Commander extends Constructed { // Examine rules to work out most egregious functions in edh boolean anyNumberOfTarget = false; + boolean annihilator = false; boolean buyback = false; boolean cascade = false; + boolean cantBe = false; boolean copy = false; boolean costLessEach = false; boolean exile = false; @@ -240,11 +242,14 @@ public class Commander extends Constructed { boolean persist = false; boolean proliferate = false; boolean protection = false; + boolean putUnderYourControl = false; boolean retrace = false; boolean sacrifice = false; boolean shroud = false; boolean skip = false; boolean sliver = false; + boolean storm = false; + boolean trample = false; boolean tutor = false; boolean unblockable = false; boolean undying = false; @@ -253,8 +258,10 @@ public class Commander extends Constructed { for (String str : card.getRules()) { String s = str.toLowerCase(); + annihilator |= s.contains("annihilator"); anyNumberOfTarget |= s.contains("any number"); buyback |= s.contains("buyback"); + cantBe |= s.contains("can't be"); cascade |= s.contains("cascade"); copy |= s.contains("copy"); costLessEach |= s.contains("cost") || s.contains("less") || s.contains("each"); @@ -278,11 +285,14 @@ public class Commander extends Constructed { persist |= s.contains("persist"); proliferate |= s.contains("proliferate"); protection |= s.contains("protection"); + putUnderYourControl |= s.contains("put") && s.contains("under your control"); retrace |= s.contains("retrace"); sacrifice |= s.contains("sacrifice"); shroud |= s.contains("shroud"); skip |= s.contains("skip"); sliver |= s.contains("sliver"); + storm |= s.contains("storm"); + trample |= s.contains("trample"); tutor |= s.contains("search your library"); unblockable |= s.contains("can't be blocked"); undying |= s.contains("undying"); @@ -299,15 +309,18 @@ public class Commander extends Constructed { if (tutor) { thisMaxPower = Math.max(thisMaxPower, 6); } + if (annihilator) { + thisMaxPower = Math.max(thisMaxPower, 5); + } + if (costLessEach) { + thisMaxPower = Math.max(thisMaxPower, 5); + } if (infect) { thisMaxPower = Math.max(thisMaxPower, 5); } if (overload) { thisMaxPower = Math.max(thisMaxPower, 5); } - if (costLessEach) { - thisMaxPower = Math.max(thisMaxPower, 5); - } if (cascade) { thisMaxPower = Math.max(thisMaxPower, 4); } @@ -332,9 +345,15 @@ public class Commander extends Constructed { if (protection) { thisMaxPower = Math.max(thisMaxPower, 4); } + if (putUnderYourControl) { + thisMaxPower = Math.max(thisMaxPower, 4); + } if (skip) { thisMaxPower = Math.max(thisMaxPower, 4); } + if (storm) { + thisMaxPower = Math.max(thisMaxPower, 4); + } if (unblockable) { thisMaxPower = Math.max(thisMaxPower, 4); } @@ -362,6 +381,9 @@ public class Commander extends Constructed { if (persist) { thisMaxPower = Math.max(thisMaxPower, 3); } + if (cantBe) { + thisMaxPower = Math.max(thisMaxPower, 2); + } if (exile) { thisMaxPower = Math.max(thisMaxPower, 2); } @@ -392,12 +414,18 @@ public class Commander extends Constructed { if (retrace) { thisMaxPower = Math.max(thisMaxPower, 1); } + if (trample) { + thisMaxPower = Math.max(thisMaxPower, 1); + } // Planeswalkers if (card.getCardType().contains(CardType.PLANESWALKER)) { if (card.getName().toLowerCase().equals("jace, the mind sculptor")) { thisMaxPower = Math.max(thisMaxPower, 5); } + if (card.getName().toLowerCase().equals("ugin, the spirit dragon")) { + thisMaxPower = Math.max(thisMaxPower, 4); + } thisMaxPower = Math.max(thisMaxPower, 3); } @@ -478,7 +506,6 @@ public class Commander extends Constructed { || cn.equals("strip mine") || cn.equals("the tabernacle at pendrell vale") || cn.equals("tinker") - || cn.equals("tolarian academy") || cn.equals("treasure cruise") || cn.equals("urabrask the hidden") || cn.equals("vorinclex, voice of hunger") From 33a9ecaa64f652a5709f30a7ee6f51b8f655a83e Mon Sep 17 00:00:00 2001 From: Ryan Skeldon Date: Mon, 5 Dec 2016 18:26:31 -0500 Subject: [PATCH 15/38] Fixed Ob Nixilis Unshackled Corrected opponent targeting. --- Mage.Sets/src/mage/cards/o/ObNixilisUnshackled.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/cards/o/ObNixilisUnshackled.java b/Mage.Sets/src/mage/cards/o/ObNixilisUnshackled.java index 68016bc1970..29c1344144e 100644 --- a/Mage.Sets/src/mage/cards/o/ObNixilisUnshackled.java +++ b/Mage.Sets/src/mage/cards/o/ObNixilisUnshackled.java @@ -47,7 +47,7 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.players.Player; -import mage.target.TargetPlayer; +import mage.target.targetpointer.FixedTarget; /** * @@ -110,8 +110,7 @@ class ObNixilisUnshackledTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { Player controller = game.getPlayer(this.getControllerId()); if (controller != null && game.isOpponent(controller, event.getTargetId())) { - this.addTarget(new TargetPlayer()); - getTargets().get(0).add(event.getPlayerId(), game); + getEffects().get(0).setTargetPointer(new FixedTarget(event.getPlayerId())); return true; } return false; From d8e2173b4a4638da9edd002f670dd0a5180d49ce Mon Sep 17 00:00:00 2001 From: JRHerlehy Date: Tue, 6 Dec 2016 01:00:58 -0800 Subject: [PATCH 16/38] Added Aether Rvolt cards to Data File Added known confirmed Aether Revolt Cards to the Data File. --- Utils/mtg-cards-data.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 2fb11353a84..dae5095a0d9 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -30321,3 +30321,15 @@ Mountain|Commander 2016|348|L||Basic Land - Mountain|||| Forest|Commander 2016|349|L||Basic Land - Forest|||| Forest|Commander 2016|350|L||Basic Land - Forest|||| Forest|Commander 2016|351|L||Basic Land - Forest|||| +Disallow|Aether Revolt|31|R|{1}{U}{U}|Instant|||Counter target spell, activated ability, or triggered ability. (Mana abilities can't be targeted.)| +Trophy Mage|Aether Revolt|48|U|{2}{U}|Creature - Human Wizard|2|2|When Trophy Mage enters the battlefield, you may search your library for an artifact card with converted mana cost 3, reveal it, put it into your hand, then shuffle your library.| +Battle at the Bridge|Aether Revolt|53|R|{X}{B}|Sorcery|||Improvise (Your artifacts can help cast this spell. Each artifact you tap after you're done activating mana abilities pays for {1}.)$Target creature gets -X/-X until end of turn. You gain X life.| +Yahenni's Expertise|Aether Revolt|75|R|{2}{B}{B}|Sorcery|||All creatures get -3/-3 until end of turn.$You may cast a card with converted mana cost 3 or less from your hand without paying its mana cost.| +Pia's Revolution|Aether Revolt|91|R|{2}{R}|Enchantment|||Whenever a nontoken artifact is put into your graveyard from the battlefield, return that card to your hand unless target opponent has Pia's Revolution deal 3 damage to him or her.| +Quicksmith Rebel|Aether Revolt|93|R|{3}{R}|Creature - Human Artificer|3|2|When Quicksmith Rebel enters the battlefield, target artifact you control gains "{T}: This artifact deals 2 damage to target creature or player" for as long as you control Quicksmith Rebel.| +Ajani Unyielding|Aether Revolt|127|M|{4}{G}{W}|Planeswalker - Ajani|||+2: Reveal the top three cards of your library. Put all nonland permanent cards revealed this way into your hand and the rest on the bottom of your library in any order.$-2: Exile target creature. Its controller gains life equal to its power.$-9: Put five +1/+1 counters on each creature you control and five loyalty counters on each other planeswalker you control.| +Dark Intimations|Aether Revolt|128|R|{2}{U}{B}{R}|Sorcery|||Each opponent sacrifices a creature or planeswalker, then discards a card. You return a creature or planeswalker card from your graveyard to your hand, then draw a card.$When you cast a Bolas planeswalker spell, exile Dark Intimations from your graveyard. That planeswalker enters the battlefield with an additional loyalty counter on it.| +Heart of Kiran|Aether Revolt|153|M|{2}|Legendary Artifact - Vehicle|4|4|Flying, vigilance$Crew 3 (Tap any number of creatures you control with total power 3 or more: This Vehicle becomes an artifact creature until end of turn.)$You may remove a loyalty counter from a planeswalker you control rather than pay Heart of Kiran's crew cost.| +Scrap Trawler|Aether Revolt|175|R|{3}|Artifact Creature - Construct|3|2|Whenever Scrap Trawler or another artifact you control is put into a graveyard from the battlefield, return to your hand target artifact card in your graveyard with lesser converted mana cost.| +Ajani, Valiant Protector|Aether Revolt|185|M|{4}{G}{W}|Planeswalker - Ajani|||+2: Put two +1/+1 counters on up to one target creature.$+1: Reveal cards from the top of your library until you reveal a creature card. Put that card into your hand and the rest on the bottom of your library in a random order.$-11: Put X +1/+1 counters on target creature, where X is your life total. That creature gains trample until end of turn.| +Tezzeret, Master of Metal|Aether Revolt|190|M|{4}{U}{B}|Planeswalker - Tezzeret|||+1: Reveal cards from the top of your library until you reveal an artifact card. Put that card into your hand and the rest on the bottom of your library in a random order.$-3: Target opponent loses life equal to the number of artifacts you control.$-8: Gain control of all artifacts and creatures target opponent controls.| \ No newline at end of file From efd5d15995d4afa2d97618ac54070dbe62d66723 Mon Sep 17 00:00:00 2001 From: JRHerlehy Date: Tue, 6 Dec 2016 02:41:36 -0800 Subject: [PATCH 17/38] Implement AER card Disallow --- Mage.Sets/src/mage/cards/d/Disallow.java | 60 +++++++++++++++++++++++ Mage.Sets/src/mage/sets/AetherRevolt.java | 7 ++- 2 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/d/Disallow.java diff --git a/Mage.Sets/src/mage/cards/d/Disallow.java b/Mage.Sets/src/mage/cards/d/Disallow.java new file mode 100644 index 00000000000..a938a69e69d --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/Disallow.java @@ -0,0 +1,60 @@ +/* + * 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.d; + +import mage.abilities.effects.common.CounterTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.TargetStackObject; + +import java.util.UUID; + +/** + * @author JRHerlehy + */ +public class Disallow extends CardImpl { + + public Disallow(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}{U}"); + + + // Counter target spell, activated ability, or triggered ability. + this.getSpellAbility().addEffect(new CounterTargetEffect()); + this.getSpellAbility().addTarget(new TargetStackObject()); + } + + public Disallow(final Disallow card) { + super(card); + } + + @Override + public Disallow copy() { + return new Disallow(this); + } +} diff --git a/Mage.Sets/src/mage/sets/AetherRevolt.java b/Mage.Sets/src/mage/sets/AetherRevolt.java index 6f3887a87d4..f282fdd6ecb 100644 --- a/Mage.Sets/src/mage/sets/AetherRevolt.java +++ b/Mage.Sets/src/mage/sets/AetherRevolt.java @@ -27,14 +27,16 @@ */ package mage.sets; -import java.util.ArrayList; -import java.util.List; import mage.cards.ExpansionSet; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; +import mage.constants.Rarity; import mage.constants.SetType; +import java.util.ArrayList; +import java.util.List; + /** * * @author fireshoes @@ -64,6 +66,7 @@ public class AetherRevolt extends ExpansionSet { premium mythic rare. These ratios may change for future sets. */ this.ratioBoosterSpecialLand = 144; this.parentSet = Kaladesh.getInstance(); + cards.add(new SetCardInfo("Disallow", 31, Rarity.RARE, mage.cards.d.Disallow.class)); } @Override From ba30a514d296465be619334658392561daa80690 Mon Sep 17 00:00:00 2001 From: Styxo Date: Tue, 6 Dec 2016 15:38:24 +0100 Subject: [PATCH 18/38] [AER] Added Ajani and Tezzeret from PW decks --- .../mage/cards/a/AjaniValiantProtector.java | 87 +++++++++ .../src/mage/cards/e/EvolutionaryLeap.java | 73 +------- .../mage/cards/t/TezzeretMasterOfMetal.java | 155 ++++++++++++++++ Mage.Sets/src/mage/sets/AetherRevolt.java | 168 +++++++++--------- .../RevealCardsFromLibraryUntilEffect.java | 106 +++++++++++ 5 files changed, 435 insertions(+), 154 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/a/AjaniValiantProtector.java create mode 100644 Mage.Sets/src/mage/cards/t/TezzeretMasterOfMetal.java create mode 100644 Mage/src/main/java/mage/abilities/effects/common/RevealCardsFromLibraryUntilEffect.java diff --git a/Mage.Sets/src/mage/cards/a/AjaniValiantProtector.java b/Mage.Sets/src/mage/cards/a/AjaniValiantProtector.java new file mode 100644 index 00000000000..0389e582081 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AjaniValiantProtector.java @@ -0,0 +1,87 @@ +/* + * 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.a; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; +import mage.abilities.dynamicvalue.common.ControllerLifeCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.RevealCardsFromLibraryUntilEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.counters.CounterType; +import mage.filter.common.FilterCreatureCard; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author Styxo + */ +public class AjaniValiantProtector extends CardImpl { + + public AjaniValiantProtector(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{4}{G}{W}"); + this.subtype.add("Ajani"); + + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); + + // +2: Put two +1/+1 counters on up to one target creature. + Ability ability = new LoyaltyAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)), 2); + ability.addTarget(new TargetCreaturePermanent(0, 1)); + this.addAbility(ability); + + // +1: Reveal cards from the top of your library until you reveal a creature card. Put that card into your hand and the rest on the bottom of your library in a random order. + this.addAbility(new LoyaltyAbility(new RevealCardsFromLibraryUntilEffect(new FilterCreatureCard()), 1)); + + // -11: Put X +1/+1 counters on target creature, where X is your life total. That creature gains trample until end of turn. + Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(), new ControllerLifeCount()); + effect.setText("Put X +1/+1 counters on target creature, where X is your life total."); + ability = new LoyaltyAbility(effect, -11); + effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); + effect.setText("That creature gains trample until end of turn"); + ability.addEffect(effect); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public AjaniValiantProtector(final AjaniValiantProtector card) { + super(card); + } + + @Override + public AjaniValiantProtector copy() { + return new AjaniValiantProtector(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EvolutionaryLeap.java b/Mage.Sets/src/mage/cards/e/EvolutionaryLeap.java index c4628b8d6bf..a97a36e2e44 100644 --- a/Mage.Sets/src/mage/cards/e/EvolutionaryLeap.java +++ b/Mage.Sets/src/mage/cards/e/EvolutionaryLeap.java @@ -28,25 +28,17 @@ package mage.cards.e; import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.common.RevealCardsFromLibraryUntilEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreatureCard; -import mage.game.Game; -import mage.players.Library; -import mage.players.Player; import mage.target.common.TargetControlledCreaturePermanent; /** @@ -56,10 +48,10 @@ import mage.target.common.TargetControlledCreaturePermanent; public class EvolutionaryLeap extends CardImpl { public EvolutionaryLeap(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); // {G}, Sacrifice a creature: Reveal cards from the top of your library until you reveal a creature card. Put that card into your hand and the rest on the bottom of your library in a random order. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new EvolutionaryLeapEffect(), new ManaCostsImpl("{G}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RevealCardsFromLibraryUntilEffect(new FilterCreatureCard()), new ManaCostsImpl("{G}")); ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(new FilterControlledCreaturePermanent("a creature")))); this.addAbility(ability); } @@ -73,62 +65,3 @@ public class EvolutionaryLeap extends CardImpl { return new EvolutionaryLeap(this); } } - -class EvolutionaryLeapEffect extends OneShotEffect { - - private static final FilterCreatureCard filter = new FilterCreatureCard(); - - public EvolutionaryLeapEffect() { - super(Outcome.ReturnToHand); - this.staticText = "reveal cards from the top of your library until you reveal a creature card. Put that card into your hand and the rest on the bottom of your library in a random order"; - } - - public EvolutionaryLeapEffect(final EvolutionaryLeapEffect effect) { - super(effect); - } - - @Override - public EvolutionaryLeapEffect copy() { - return new EvolutionaryLeapEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (controller != null && controller.getLibrary().size() > 0) { - Cards cards = new CardsImpl(); - Library library = controller.getLibrary(); - Card card = null; - do { - card = library.removeFromTop(game); - if (card != null) { - cards.add(card); - } - } while (library.size() > 0 && card != null && !filter.match(card, game)); - // reveal cards - if (!cards.isEmpty()) { - controller.revealCards(sourceObject.getIdName(), cards, game); - if (filter.match(card, game)) { - // put creature card in hand - controller.moveCards(card, Zone.HAND, source, game); - // remove it from revealed card list - cards.remove(card); - } - // Put the rest on the bottom of your library in a random order - Cards randomOrder = new CardsImpl(); - while (cards.size() > 0) { - card = cards.getRandom(game); - if (card != null) { - cards.remove(card); - randomOrder.add(card); - controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.HAND, false, false); - } - } - controller.putCardsOnBottomOfLibrary(randomOrder, game, source, false); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/t/TezzeretMasterOfMetal.java b/Mage.Sets/src/mage/cards/t/TezzeretMasterOfMetal.java new file mode 100644 index 00000000000..9d5cfad6b40 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TezzeretMasterOfMetal.java @@ -0,0 +1,155 @@ +/* + * 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.t; + +import java.util.List; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.effects.common.RevealCardsFromLibraryUntilEffect; +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.filter.FilterPermanent; +import mage.filter.common.FilterArtifactCard; +import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetOpponent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author Styxo + */ +public class TezzeretMasterOfMetal extends CardImpl { + + public TezzeretMasterOfMetal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{4}{U}{B}"); + this.subtype.add("Tezzeret"); + + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(5)); + + // +1: Reveal cards from the top of your library until you reveal an artifact card. Put that card into your hand and the rest on the bottom of your library in a random order. + this.addAbility(new LoyaltyAbility(new RevealCardsFromLibraryUntilEffect(new FilterArtifactCard()), 1)); + + // -3: Target opponent loses life equal to the number of artifacts you control. + Ability ability = new LoyaltyAbility(new LoseLifeTargetEffect(new PermanentsOnBattlefieldCount(new FilterControlledArtifactPermanent())), -3); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + + // -8: Gain control of all artifacts and creatures target opponent controls. + ability = new LoyaltyAbility(new TezzeretMasterOfMetalEffect(), -8); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + public TezzeretMasterOfMetal(final TezzeretMasterOfMetal card) { + super(card); + } + + @Override + public TezzeretMasterOfMetal copy() { + return new TezzeretMasterOfMetal(this); + } +} + +class TezzeretMasterOfMetalEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterPermanent("artifacts and creatures"); + + static { + filter.add(Predicates.or(new CardTypePredicate(CardType.CREATURE), new CardTypePredicate(CardType.ARTIFACT))); + } + + public TezzeretMasterOfMetalEffect() { + super(Outcome.GainControl); + this.staticText = "Gain control of all artifacts and creatures target opponent controls"; + } + + public TezzeretMasterOfMetalEffect(final TezzeretMasterOfMetalEffect effect) { + super(effect); + } + + @Override + public TezzeretMasterOfMetalEffect copy() { + return new TezzeretMasterOfMetalEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + List permanents = game.getBattlefield().getAllActivePermanents(filter, targetPointer.getFirst(game, source), game); + for (Permanent permanent : permanents) { + ContinuousEffect effect = new TibaltTheFiendBloodedControlEffect(source.getControllerId()); + effect.setTargetPointer(new FixedTarget(permanent.getId())); + game.addEffect(effect, source); + } + return true; + } +} + +class TezzeretMasterOfMetalControlEffect extends ContinuousEffectImpl { + + private final UUID controllerId; + + public TezzeretMasterOfMetalControlEffect(UUID controllerId) { + super(Duration.EndOfGame, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); + this.controllerId = controllerId; + } + + public TezzeretMasterOfMetalControlEffect(final TezzeretMasterOfMetalControlEffect effect) { + super(effect); + this.controllerId = effect.controllerId; + } + + @Override + public TezzeretMasterOfMetalControlEffect copy() { + return new TezzeretMasterOfMetalControlEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); + if (permanent != null && controllerId != null) { + return permanent.changeControllerId(controllerId, game); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/AetherRevolt.java b/Mage.Sets/src/mage/sets/AetherRevolt.java index f282fdd6ecb..610c24e217c 100644 --- a/Mage.Sets/src/mage/sets/AetherRevolt.java +++ b/Mage.Sets/src/mage/sets/AetherRevolt.java @@ -1,84 +1,84 @@ -/* - * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of BetaSteward_at_googlemail.com. - */ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.cards.repository.CardCriteria; -import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; -import mage.constants.Rarity; -import mage.constants.SetType; - -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author fireshoes - */ -public class AetherRevolt extends ExpansionSet { - - private static final AetherRevolt fINSTANCE = new AetherRevolt(); - - public static AetherRevolt getInstance() { - return fINSTANCE; - } - - protected final List savedSpecialLand = new ArrayList<>(); - - private AetherRevolt() { - super("Aether Revolt", "AER", ExpansionSet.buildDate(2017, 1, 20), SetType.EXPANSION); - this.blockName = "Kaladesh"; - this.hasBoosters = true; - this.hasBasicLands = false; - this.numBoosterLands = 1; - this.numBoosterCommon = 10; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 8; - /* The Masterpiece Series will exist at a rarity higher than mythic rare. For example, in Kaladesh, you will open a Kaladesh Inventions card roughly - 1 out of every 144 boosters. (Technically, the Kaladesh booster pack says the ratio is 1:2,160 cards.) This is slightly more often than opening a - premium mythic rare. These ratios may change for future sets. */ - this.ratioBoosterSpecialLand = 144; - this.parentSet = Kaladesh.getInstance(); - cards.add(new SetCardInfo("Disallow", 31, Rarity.RARE, mage.cards.d.Disallow.class)); - } - - @Override - public List getSpecialLand() { - if (savedSpecialLand.isEmpty()) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes("MPS"); - criteria.minCardNumber(31); - criteria.maxCardNumber(54); - savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); - } - - return new ArrayList<>(savedSpecialLand); - } -} +/* + * 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.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; +import mage.constants.Rarity; +import mage.constants.SetType; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author fireshoes + */ +public class AetherRevolt extends ExpansionSet { + + private static final AetherRevolt fINSTANCE = new AetherRevolt(); + + public static AetherRevolt getInstance() { + return fINSTANCE; + } + + protected final List savedSpecialLand = new ArrayList<>(); + + private AetherRevolt() { + super("Aether Revolt", "AER", ExpansionSet.buildDate(2017, 1, 20), SetType.EXPANSION); + this.blockName = "Kaladesh"; + this.hasBoosters = true; + this.hasBasicLands = false; + this.numBoosterLands = 1; + this.numBoosterCommon = 10; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 8; + this.maxCardNumberInBooster = 184; + this.ratioBoosterSpecialLand = 144; + this.parentSet = Kaladesh.getInstance(); + cards.add(new SetCardInfo("Ajani, Valiant Protector", 185, Rarity.MYTHIC, mage.cards.a.AjaniValiantProtector.class)); + cards.add(new SetCardInfo("Disallow", 31, Rarity.RARE, mage.cards.d.Disallow.class)); + cards.add(new SetCardInfo("Tezzeret, Master of Metal", 190, Rarity.MYTHIC, mage.cards.t.TezzeretMasterOfMetal.class)); + } + + @Override + public List getSpecialLand() { + if (savedSpecialLand.isEmpty()) { + CardCriteria criteria = new CardCriteria(); + criteria.setCodes("MPS"); + criteria.minCardNumber(31); + criteria.maxCardNumber(54); + savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); + } + + return new ArrayList<>(savedSpecialLand); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/RevealCardsFromLibraryUntilEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RevealCardsFromLibraryUntilEffect.java new file mode 100644 index 00000000000..91f696dbef0 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/RevealCardsFromLibraryUntilEffect.java @@ -0,0 +1,106 @@ +/* + * 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.effects.common; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Library; +import mage.players.Player; + +/** + * + * @author Styxo + */ +public class RevealCardsFromLibraryUntilEffect extends OneShotEffect { + + private FilterCard filter; + + public RevealCardsFromLibraryUntilEffect(FilterCard filter) { + super(Outcome.ReturnToHand); + this.filter = filter; + this.staticText = "reveal cards from the top of your library until you reveal a " + filter.getMessage() + ". Put that card into your hand and the rest on the bottom of your library in a random order"; + } + + public RevealCardsFromLibraryUntilEffect(final RevealCardsFromLibraryUntilEffect effect) { + super(effect); + this.filter = effect.filter; + } + + @Override + public RevealCardsFromLibraryUntilEffect copy() { + return new RevealCardsFromLibraryUntilEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller != null && controller.getLibrary().size() > 0) { + Cards cards = new CardsImpl(); + Library library = controller.getLibrary(); + Card card = null; + do { + card = library.removeFromTop(game); + if (card != null) { + cards.add(card); + } + } while (library.size() > 0 && card != null && !filter.match(card, game)); + // reveal cards + if (!cards.isEmpty()) { + controller.revealCards(sourceObject.getIdName(), cards, game); + if (filter.match(card, game)) { + // put creature card in hand + controller.moveCards(card, Zone.HAND, source, game); + // remove it from revealed card list + cards.remove(card); + } + // Put the rest on the bottom of your library in a random order + Cards randomOrder = new CardsImpl(); + while (cards.size() > 0) { + card = cards.getRandom(game); + if (card != null) { + cards.remove(card); + randomOrder.add(card); + controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.HAND, false, false); + } + } + controller.putCardsOnBottomOfLibrary(randomOrder, game, source, false); + } + return true; + } + return false; + } +} From 83b7f7a545450653afcca9ada9f568fbdd725bc2 Mon Sep 17 00:00:00 2001 From: JRHerlehy Date: Tue, 6 Dec 2016 17:26:46 -0800 Subject: [PATCH 19/38] Implement AER card Pia's Revolution --- .../src/mage/cards/p/PiasRevolution.java | 175 ++++++++++++++++++ Mage.Sets/src/mage/sets/AetherRevolt.java | 169 ++++++++--------- 2 files changed, 260 insertions(+), 84 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/p/PiasRevolution.java diff --git a/Mage.Sets/src/mage/cards/p/PiasRevolution.java b/Mage.Sets/src/mage/cards/p/PiasRevolution.java new file mode 100644 index 00000000000..9777be1f6fc --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PiasRevolution.java @@ -0,0 +1,175 @@ +/* + * 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.p; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.common.FilterArtifactPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.other.OwnerPredicate; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author JRHerlehy + */ +public class PiasRevolution extends CardImpl { + + private static final FilterArtifactPermanent filter = new FilterArtifactPermanent("nontoken artifact"); + + static { + filter.add(Predicates.not(new TokenPredicate())); + filter.add(new OwnerPredicate(TargetController.YOU)); + } + + public PiasRevolution(UUID ownerId, CardSetInfo setInfo) { + + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); + + // Whenever a nontoken artifact is put into your graveyard from the battlefield, return that card to your hand unless target opponent has Pia's Revolution deal 3 damage to him or her. + Ability ability = new PiasRevolutionArtifactToGraveyardTriggeredAbility(new PiasRevolutionReturnEffect(), false, filter); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + public PiasRevolution(final PiasRevolution card) { + super(card); + } + + @Override + public PiasRevolution copy() { + return new PiasRevolution(this); + } +} + +class PiasRevolutionArtifactToGraveyardTriggeredAbility extends TriggeredAbilityImpl { + + protected FilterArtifactPermanent filter; + + public PiasRevolutionArtifactToGraveyardTriggeredAbility(Effect effect, boolean optional, FilterArtifactPermanent filter) { + super(Zone.BATTLEFIELD, effect, optional); + this.filter = filter; + } + + public PiasRevolutionArtifactToGraveyardTriggeredAbility(final PiasRevolutionArtifactToGraveyardTriggeredAbility ability) { + super(ability); + this.filter = ability.filter; + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getFromZone().equals(Zone.BATTLEFIELD) && zEvent.getToZone().equals(Zone.GRAVEYARD)) { + Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); + if (permanent != null && filter.match(permanent, sourceId, controllerId, game)) { + for (Effect effect : this.getEffects()) { + effect.setValue("artifactId", event.getTargetId()); + } + return true; + } + } + return false; + } + + @Override + public PiasRevolutionArtifactToGraveyardTriggeredAbility copy() { + return new PiasRevolutionArtifactToGraveyardTriggeredAbility(this); + } + + @Override + public String getRule() { + return "Whenever " + filter.getMessage() + " is put into your graveyard from the battlefield, " + super.getRule(); + } +} + +class PiasRevolutionReturnEffect extends OneShotEffect { + + public PiasRevolutionReturnEffect() { + super(Outcome.Benefit); + this.staticText = "return it to your hand unless target opponent has {this} deal 3 damage to him or her"; + } + + public PiasRevolutionReturnEffect(final PiasRevolutionReturnEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + + if (controller == null) return false; + + MageObject sourceObject = source.getSourceObject(game); + UUID artifactId = (UUID) this.getValue("artifactId"); + Permanent artifact = game.getPermanentOrLKIBattlefield(artifactId); + if (artifact != null) { + Player opponent = game.getPlayer(source.getFirstTarget()); + boolean takeDamage = false; + if (opponent != null) { + String message = "Have " + sourceObject.getLogName() + " deal you 3 damage to prevent " + artifact.getName() + " returning to " + controller.getLogName() + "'s hand?"; + if (opponent.chooseUse(outcome, message, source, game)) takeDamage = true; + } + if (opponent == null || !takeDamage) { + if (game.getState().getZone(artifact.getId()).equals(Zone.GRAVEYARD)) { + controller.moveCards(game.getCard(artifactId), Zone.HAND, source, game); + } + } else { + opponent.damage(3, source.getSourceId(), game, false, true); + game.informPlayers(opponent.getLogName() + " has " + sourceObject.getLogName() + " deal 3 damage to him or her"); + } + } + return true; + } + + @Override + public PiasRevolutionReturnEffect copy() { + return new PiasRevolutionReturnEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/AetherRevolt.java b/Mage.Sets/src/mage/sets/AetherRevolt.java index 610c24e217c..254e66c1153 100644 --- a/Mage.Sets/src/mage/sets/AetherRevolt.java +++ b/Mage.Sets/src/mage/sets/AetherRevolt.java @@ -1,84 +1,85 @@ -/* - * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of BetaSteward_at_googlemail.com. - */ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.cards.repository.CardCriteria; -import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; -import mage.constants.Rarity; -import mage.constants.SetType; - -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author fireshoes - */ -public class AetherRevolt extends ExpansionSet { - - private static final AetherRevolt fINSTANCE = new AetherRevolt(); - - public static AetherRevolt getInstance() { - return fINSTANCE; - } - - protected final List savedSpecialLand = new ArrayList<>(); - - private AetherRevolt() { - super("Aether Revolt", "AER", ExpansionSet.buildDate(2017, 1, 20), SetType.EXPANSION); - this.blockName = "Kaladesh"; - this.hasBoosters = true; - this.hasBasicLands = false; - this.numBoosterLands = 1; - this.numBoosterCommon = 10; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 8; - this.maxCardNumberInBooster = 184; - this.ratioBoosterSpecialLand = 144; - this.parentSet = Kaladesh.getInstance(); - cards.add(new SetCardInfo("Ajani, Valiant Protector", 185, Rarity.MYTHIC, mage.cards.a.AjaniValiantProtector.class)); - cards.add(new SetCardInfo("Disallow", 31, Rarity.RARE, mage.cards.d.Disallow.class)); - cards.add(new SetCardInfo("Tezzeret, Master of Metal", 190, Rarity.MYTHIC, mage.cards.t.TezzeretMasterOfMetal.class)); - } - - @Override - public List getSpecialLand() { - if (savedSpecialLand.isEmpty()) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes("MPS"); - criteria.minCardNumber(31); - criteria.maxCardNumber(54); - savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); - } - - return new ArrayList<>(savedSpecialLand); - } -} +/* + * 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.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; +import mage.constants.Rarity; +import mage.constants.SetType; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author fireshoes + */ +public class AetherRevolt extends ExpansionSet { + + private static final AetherRevolt fINSTANCE = new AetherRevolt(); + + public static AetherRevolt getInstance() { + return fINSTANCE; + } + + protected final List savedSpecialLand = new ArrayList<>(); + + private AetherRevolt() { + super("Aether Revolt", "AER", ExpansionSet.buildDate(2017, 1, 20), SetType.EXPANSION); + this.blockName = "Kaladesh"; + this.hasBoosters = true; + this.hasBasicLands = false; + this.numBoosterLands = 1; + this.numBoosterCommon = 10; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 8; + this.maxCardNumberInBooster = 184; + this.ratioBoosterSpecialLand = 144; + this.parentSet = Kaladesh.getInstance(); + cards.add(new SetCardInfo("Ajani, Valiant Protector", 185, Rarity.MYTHIC, mage.cards.a.AjaniValiantProtector.class)); + cards.add(new SetCardInfo("Disallow", 31, Rarity.RARE, mage.cards.d.Disallow.class)); + cards.add(new SetCardInfo("Tezzeret, Master of Metal", 190, Rarity.MYTHIC, mage.cards.t.TezzeretMasterOfMetal.class)); + cards.add(new SetCardInfo("Pia's Revolution", 91, Rarity.RARE, mage.cards.p.PiasRevolution.class)); + } + + @Override + public List getSpecialLand() { + if (savedSpecialLand.isEmpty()) { + CardCriteria criteria = new CardCriteria(); + criteria.setCodes("MPS"); + criteria.minCardNumber(31); + criteria.maxCardNumber(54); + savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); + } + + return new ArrayList<>(savedSpecialLand); + } +} From 2b088bde22e0207df9bf299599fde1e14799cf92 Mon Sep 17 00:00:00 2001 From: Styxo Date: Wed, 7 Dec 2016 09:33:12 +0100 Subject: [PATCH 20/38] Fix for Jazal Goldmane and Ovalchase Daredevil --- Mage.Sets/src/mage/cards/j/JazalGoldmane.java | 4 ++-- Mage.Sets/src/mage/cards/o/OvalchaseDaredevil.java | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Mage.Sets/src/mage/cards/j/JazalGoldmane.java b/Mage.Sets/src/mage/cards/j/JazalGoldmane.java index 7c4b17d9020..84a1a8f3112 100644 --- a/Mage.Sets/src/mage/cards/j/JazalGoldmane.java +++ b/Mage.Sets/src/mage/cards/j/JazalGoldmane.java @@ -49,7 +49,7 @@ import mage.filter.common.FilterAttackingCreature; public class JazalGoldmane extends CardImpl { public JazalGoldmane(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}"); this.supertype.add("Legendary"); this.subtype.add("Cat"); this.subtype.add("Warrior"); @@ -63,7 +63,7 @@ public class JazalGoldmane extends CardImpl { DynamicValue xValue = new AttackingCreatureCount("the number of attacking creatures"); this.addAbility(new SimpleActivatedAbility( Zone.BATTLEFIELD, - new BoostControlledEffect(xValue, xValue , Duration.EndOfTurn, new FilterAttackingCreature("Attacking creatures"), false), + new BoostControlledEffect(xValue, xValue, Duration.EndOfTurn, new FilterAttackingCreature("Attacking creatures"), false, true), new ManaCostsImpl("{3}{W}{W}"))); } diff --git a/Mage.Sets/src/mage/cards/o/OvalchaseDaredevil.java b/Mage.Sets/src/mage/cards/o/OvalchaseDaredevil.java index b3256b8ecd1..9d51943a0d6 100644 --- a/Mage.Sets/src/mage/cards/o/OvalchaseDaredevil.java +++ b/Mage.Sets/src/mage/cards/o/OvalchaseDaredevil.java @@ -34,6 +34,7 @@ import mage.abilities.effects.common.ReturnToHandSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SetTargetPointer; import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.FilterPermanent; @@ -53,14 +54,14 @@ public class OvalchaseDaredevil extends CardImpl { } public OvalchaseDaredevil(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); this.subtype.add("Human"); this.subtype.add("Pilot"); this.power = new MageInt(4); this.toughness = new MageInt(2); // Whenever an artifact enters the battlefield under your control, you may return Ovalchase Daredevil from your graveyard to your hand. - this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.GRAVEYARD, new ReturnToHandSourceEffect(), filter, true)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.GRAVEYARD, new ReturnToHandSourceEffect(), filter, true, SetTargetPointer.NONE, null, true)); } public OvalchaseDaredevil(final OvalchaseDaredevil card) { From c4df86fb105858f3e14a8c9a03fa91dcab9cf3b4 Mon Sep 17 00:00:00 2001 From: Styxo Date: Wed, 7 Dec 2016 09:34:32 +0100 Subject: [PATCH 21/38] [AER] Added Pias Revolution and Trophy Mage --- .../src/mage/cards/p/PiasRevolution.java | 160 ++++++++++++++++++ Mage.Sets/src/mage/cards/t/TrophyMage.java | 79 +++++++++ Mage.Sets/src/mage/sets/AetherRevolt.java | 2 + 3 files changed, 241 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/p/PiasRevolution.java create mode 100644 Mage.Sets/src/mage/cards/t/TrophyMage.java diff --git a/Mage.Sets/src/mage/cards/p/PiasRevolution.java b/Mage.Sets/src/mage/cards/p/PiasRevolution.java new file mode 100644 index 00000000000..400758900cc --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PiasRevolution.java @@ -0,0 +1,160 @@ +/* + * 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.p; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterArtifactPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetOpponent; + +/** + * + * @author Styxo + */ +public class PiasRevolution extends CardImpl { + + public PiasRevolution(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); + + // Whenever a nontoken artifact is put into your graveyard from the battlefield, return that card to your hand unless target opponent has Pia's Revolution deal 3 damage to him or her. + Ability ability = new PiasRevolutionTriggeredAbility(); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + public PiasRevolution(final PiasRevolution card) { + super(card); + } + + @Override + public PiasRevolution copy() { + return new PiasRevolution(this); + } +} + +class PiasRevolutionReturnEffect extends OneShotEffect { + + public PiasRevolutionReturnEffect() { + super(Outcome.Benefit); + this.staticText = "return that card to your hand unless target opponent has {this} deal 3 damage to him or her"; + } + + public PiasRevolutionReturnEffect(final PiasRevolutionReturnEffect effect) { + super(effect); + } + + @Override + public PiasRevolutionReturnEffect copy() { + return new PiasRevolutionReturnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + UUID permanentId = (UUID) this.getValue("permanentId"); + Permanent permanent = game.getPermanentOrLKIBattlefield(permanentId); + if (permanent != null) { + Player opponent = game.getPlayer(source.getFirstTarget()); + if (opponent != null) { + if (opponent.chooseUse(outcome, new StringBuilder("Have Pia's Revolution deal 3 damage to you to prevent that ").append(permanent.getLogName()).append(" returns to ").append(controller.getLogName()).append("'s hand?").toString(), source, game)) { + opponent.damage(3, source.getId(), game, false, true); + } else { + if (game.getState().getZone(permanent.getId()).equals(Zone.GRAVEYARD)) { + controller.moveCards(game.getCard(permanentId), Zone.HAND, source, game); + } + } + } + } + return true; + } + return false; + } +} + +class PiasRevolutionTriggeredAbility extends TriggeredAbilityImpl { + + private static final FilterArtifactPermanent filter = new FilterArtifactPermanent(); + + static { + filter.add(Predicates.not(new TokenPredicate())); + } + + public PiasRevolutionTriggeredAbility() { + super(Zone.BATTLEFIELD, new PiasRevolutionReturnEffect(), false); + } + + public PiasRevolutionTriggeredAbility(PiasRevolutionTriggeredAbility ability) { + super(ability); + } + + @Override + public PiasRevolutionTriggeredAbility copy() { + return new PiasRevolutionTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getFromZone().equals(Zone.BATTLEFIELD) && zEvent.getToZone().equals(Zone.GRAVEYARD)) { + Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); + if (permanent != null && filter.match(permanent, sourceId, controllerId, game)) { + for (Effect effect : this.getEffects()) { + effect.setValue("permanentId", event.getTargetId()); + } + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever a nontoken artifact is put into your graveyard from the battlefield, " + super.getRule(); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TrophyMage.java b/Mage.Sets/src/mage/cards/t/TrophyMage.java new file mode 100644 index 00000000000..6345d5c5d22 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TrophyMage.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.t; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.SearchEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.Filter; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author Styxo + */ +public class TrophyMage extends CardImpl { + + private static final FilterCard filter = new FilterCard("an artifact card with converted mana cost 3"); + + static { + filter.add(new CardTypePredicate(CardType.ARTIFACT)); + filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.Equal, 3)); + } + + public TrophyMage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add("Human"); + this.subtype.add("Wizard"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Trophy Mage enters the battlefield, you may search your library for an artifact card with converted mana cost 3, reveal it, put it into your hand, then shuffle your library. + TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter); + SearchEffect effect = new SearchLibraryPutInHandEffect(target, true, true); + this.addAbility(new EntersBattlefieldTriggeredAbility(effect, true)); + } + + public TrophyMage(final TrophyMage card) { + super(card); + } + + @Override + public TrophyMage copy() { + return new TrophyMage(this); + } +} diff --git a/Mage.Sets/src/mage/sets/AetherRevolt.java b/Mage.Sets/src/mage/sets/AetherRevolt.java index 610c24e217c..e3c9ef8870b 100644 --- a/Mage.Sets/src/mage/sets/AetherRevolt.java +++ b/Mage.Sets/src/mage/sets/AetherRevolt.java @@ -66,7 +66,9 @@ public class AetherRevolt extends ExpansionSet { this.parentSet = Kaladesh.getInstance(); cards.add(new SetCardInfo("Ajani, Valiant Protector", 185, Rarity.MYTHIC, mage.cards.a.AjaniValiantProtector.class)); cards.add(new SetCardInfo("Disallow", 31, Rarity.RARE, mage.cards.d.Disallow.class)); + cards.add(new SetCardInfo("Pia's Revolution", 91, Rarity.RARE, mage.cards.p.PiasRevolution.class)); cards.add(new SetCardInfo("Tezzeret, Master of Metal", 190, Rarity.MYTHIC, mage.cards.t.TezzeretMasterOfMetal.class)); + cards.add(new SetCardInfo("Trophy Mage", 48, Rarity.UNCOMMON, mage.cards.t.TrophyMage.class)); } @Override From eaa0e3587e957855f3ed41a86bf67c5a8cc26927 Mon Sep 17 00:00:00 2001 From: JRHerlehy Date: Tue, 6 Dec 2016 17:26:46 -0800 Subject: [PATCH 22/38] Implement AER card Pia's Revolution --- .../src/mage/cards/p/PiasRevolution.java | 320 +++++++++--------- Mage.Sets/src/mage/sets/AetherRevolt.java | 172 +++++----- 2 files changed, 246 insertions(+), 246 deletions(-) diff --git a/Mage.Sets/src/mage/cards/p/PiasRevolution.java b/Mage.Sets/src/mage/cards/p/PiasRevolution.java index 400758900cc..b9d8c629a70 100644 --- a/Mage.Sets/src/mage/cards/p/PiasRevolution.java +++ b/Mage.Sets/src/mage/cards/p/PiasRevolution.java @@ -1,160 +1,160 @@ -/* - * 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.p; - -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.common.FilterArtifactPermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.TokenPredicate; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.ZoneChangeEvent; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.common.TargetOpponent; - -/** - * - * @author Styxo - */ -public class PiasRevolution extends CardImpl { - - public PiasRevolution(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); - - // Whenever a nontoken artifact is put into your graveyard from the battlefield, return that card to your hand unless target opponent has Pia's Revolution deal 3 damage to him or her. - Ability ability = new PiasRevolutionTriggeredAbility(); - ability.addTarget(new TargetOpponent()); - this.addAbility(ability); - } - - public PiasRevolution(final PiasRevolution card) { - super(card); - } - - @Override - public PiasRevolution copy() { - return new PiasRevolution(this); - } -} - -class PiasRevolutionReturnEffect extends OneShotEffect { - - public PiasRevolutionReturnEffect() { - super(Outcome.Benefit); - this.staticText = "return that card to your hand unless target opponent has {this} deal 3 damage to him or her"; - } - - public PiasRevolutionReturnEffect(final PiasRevolutionReturnEffect effect) { - super(effect); - } - - @Override - public PiasRevolutionReturnEffect copy() { - return new PiasRevolutionReturnEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - UUID permanentId = (UUID) this.getValue("permanentId"); - Permanent permanent = game.getPermanentOrLKIBattlefield(permanentId); - if (permanent != null) { - Player opponent = game.getPlayer(source.getFirstTarget()); - if (opponent != null) { - if (opponent.chooseUse(outcome, new StringBuilder("Have Pia's Revolution deal 3 damage to you to prevent that ").append(permanent.getLogName()).append(" returns to ").append(controller.getLogName()).append("'s hand?").toString(), source, game)) { - opponent.damage(3, source.getId(), game, false, true); - } else { - if (game.getState().getZone(permanent.getId()).equals(Zone.GRAVEYARD)) { - controller.moveCards(game.getCard(permanentId), Zone.HAND, source, game); - } - } - } - } - return true; - } - return false; - } -} - -class PiasRevolutionTriggeredAbility extends TriggeredAbilityImpl { - - private static final FilterArtifactPermanent filter = new FilterArtifactPermanent(); - - static { - filter.add(Predicates.not(new TokenPredicate())); - } - - public PiasRevolutionTriggeredAbility() { - super(Zone.BATTLEFIELD, new PiasRevolutionReturnEffect(), false); - } - - public PiasRevolutionTriggeredAbility(PiasRevolutionTriggeredAbility ability) { - super(ability); - } - - @Override - public PiasRevolutionTriggeredAbility copy() { - return new PiasRevolutionTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ZONE_CHANGE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone().equals(Zone.BATTLEFIELD) && zEvent.getToZone().equals(Zone.GRAVEYARD)) { - Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); - if (permanent != null && filter.match(permanent, sourceId, controllerId, game)) { - for (Effect effect : this.getEffects()) { - effect.setValue("permanentId", event.getTargetId()); - } - return true; - } - } - return false; - } - - @Override - public String getRule() { - return "Whenever a nontoken artifact is put into your graveyard from the battlefield, " + super.getRule(); - } -} +/* + * 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.p; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterArtifactPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetOpponent; + +/** + * + * @author Styxo + */ +public class PiasRevolution extends CardImpl { + + public PiasRevolution(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); + + // Whenever a nontoken artifact is put into your graveyard from the battlefield, return that card to your hand unless target opponent has Pia's Revolution deal 3 damage to him or her. + Ability ability = new PiasRevolutionTriggeredAbility(); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + public PiasRevolution(final PiasRevolution card) { + super(card); + } + + @Override + public PiasRevolution copy() { + return new PiasRevolution(this); + } +} + +class PiasRevolutionReturnEffect extends OneShotEffect { + + public PiasRevolutionReturnEffect() { + super(Outcome.Benefit); + this.staticText = "return that card to your hand unless target opponent has {this} deal 3 damage to him or her"; + } + + public PiasRevolutionReturnEffect(final PiasRevolutionReturnEffect effect) { + super(effect); + } + + @Override + public PiasRevolutionReturnEffect copy() { + return new PiasRevolutionReturnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + UUID permanentId = (UUID) this.getValue("permanentId"); + Permanent permanent = game.getPermanentOrLKIBattlefield(permanentId); + if (permanent != null) { + Player opponent = game.getPlayer(source.getFirstTarget()); + if (opponent != null) { + if (opponent.chooseUse(outcome, new StringBuilder("Have Pia's Revolution deal 3 damage to you to prevent that ").append(permanent.getLogName()).append(" returns to ").append(controller.getLogName()).append("'s hand?").toString(), source, game)) { + opponent.damage(3, source.getId(), game, false, true); + } else { + if (game.getState().getZone(permanent.getId()).equals(Zone.GRAVEYARD)) { + controller.moveCards(game.getCard(permanentId), Zone.HAND, source, game); + } + } + } + } + return true; + } + return false; + } +} + +class PiasRevolutionTriggeredAbility extends TriggeredAbilityImpl { + + private static final FilterArtifactPermanent filter = new FilterArtifactPermanent(); + + static { + filter.add(Predicates.not(new TokenPredicate())); + } + + public PiasRevolutionTriggeredAbility() { + super(Zone.BATTLEFIELD, new PiasRevolutionReturnEffect(), false); + } + + public PiasRevolutionTriggeredAbility(PiasRevolutionTriggeredAbility ability) { + super(ability); + } + + @Override + public PiasRevolutionTriggeredAbility copy() { + return new PiasRevolutionTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getFromZone().equals(Zone.BATTLEFIELD) && zEvent.getToZone().equals(Zone.GRAVEYARD)) { + Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); + if (permanent != null && filter.match(permanent, sourceId, controllerId, game)) { + for (Effect effect : this.getEffects()) { + effect.setValue("permanentId", event.getTargetId()); + } + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever a nontoken artifact is put into your graveyard from the battlefield, " + super.getRule(); + } +} diff --git a/Mage.Sets/src/mage/sets/AetherRevolt.java b/Mage.Sets/src/mage/sets/AetherRevolt.java index e3c9ef8870b..761e72694f4 100644 --- a/Mage.Sets/src/mage/sets/AetherRevolt.java +++ b/Mage.Sets/src/mage/sets/AetherRevolt.java @@ -1,86 +1,86 @@ -/* - * 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.cards.repository.CardCriteria; -import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; -import mage.constants.Rarity; -import mage.constants.SetType; - -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author fireshoes - */ -public class AetherRevolt extends ExpansionSet { - - private static final AetherRevolt fINSTANCE = new AetherRevolt(); - - public static AetherRevolt getInstance() { - return fINSTANCE; - } - - protected final List savedSpecialLand = new ArrayList<>(); - - private AetherRevolt() { - super("Aether Revolt", "AER", ExpansionSet.buildDate(2017, 1, 20), SetType.EXPANSION); - this.blockName = "Kaladesh"; - this.hasBoosters = true; - this.hasBasicLands = false; - this.numBoosterLands = 1; - this.numBoosterCommon = 10; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 8; - this.maxCardNumberInBooster = 184; - this.ratioBoosterSpecialLand = 144; - this.parentSet = Kaladesh.getInstance(); - cards.add(new SetCardInfo("Ajani, Valiant Protector", 185, Rarity.MYTHIC, mage.cards.a.AjaniValiantProtector.class)); - cards.add(new SetCardInfo("Disallow", 31, Rarity.RARE, mage.cards.d.Disallow.class)); - cards.add(new SetCardInfo("Pia's Revolution", 91, Rarity.RARE, mage.cards.p.PiasRevolution.class)); - cards.add(new SetCardInfo("Tezzeret, Master of Metal", 190, Rarity.MYTHIC, mage.cards.t.TezzeretMasterOfMetal.class)); - cards.add(new SetCardInfo("Trophy Mage", 48, Rarity.UNCOMMON, mage.cards.t.TrophyMage.class)); - } - - @Override - public List getSpecialLand() { - if (savedSpecialLand.isEmpty()) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes("MPS"); - criteria.minCardNumber(31); - criteria.maxCardNumber(54); - savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); - } - - return new ArrayList<>(savedSpecialLand); - } -} +/* + * 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.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; +import mage.constants.Rarity; +import mage.constants.SetType; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author fireshoes + */ +public class AetherRevolt extends ExpansionSet { + + private static final AetherRevolt fINSTANCE = new AetherRevolt(); + + public static AetherRevolt getInstance() { + return fINSTANCE; + } + + protected final List savedSpecialLand = new ArrayList<>(); + + private AetherRevolt() { + super("Aether Revolt", "AER", ExpansionSet.buildDate(2017, 1, 20), SetType.EXPANSION); + this.blockName = "Kaladesh"; + this.hasBoosters = true; + this.hasBasicLands = false; + this.numBoosterLands = 1; + this.numBoosterCommon = 10; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 8; + this.maxCardNumberInBooster = 184; + this.ratioBoosterSpecialLand = 144; + this.parentSet = Kaladesh.getInstance(); + cards.add(new SetCardInfo("Ajani, Valiant Protector", 185, Rarity.MYTHIC, mage.cards.a.AjaniValiantProtector.class)); + cards.add(new SetCardInfo("Disallow", 31, Rarity.RARE, mage.cards.d.Disallow.class)); + cards.add(new SetCardInfo("Pia's Revolution", 91, Rarity.RARE, mage.cards.p.PiasRevolution.class)); + cards.add(new SetCardInfo("Tezzeret, Master of Metal", 190, Rarity.MYTHIC, mage.cards.t.TezzeretMasterOfMetal.class)); + cards.add(new SetCardInfo("Trophy Mage", 48, Rarity.UNCOMMON, mage.cards.t.TrophyMage.class)); + } + + @Override + public List getSpecialLand() { + if (savedSpecialLand.isEmpty()) { + CardCriteria criteria = new CardCriteria(); + criteria.setCodes("MPS"); + criteria.minCardNumber(31); + criteria.maxCardNumber(54); + savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); + } + + return new ArrayList<>(savedSpecialLand); + } +} From deb59d409dafe9bea935d124f10234ac1d33a3de Mon Sep 17 00:00:00 2001 From: JRHerlehy Date: Wed, 7 Dec 2016 00:45:06 -0800 Subject: [PATCH 23/38] Implement AER card Ajani Unyielding Moved Swords to Plowshares effect to common class to dedupe code. --- .../src/mage/cards/a/AjaniUnyielding.java | 97 +++++++++++++++++++ .../src/mage/cards/s/SwordsToPlowshares.java | 42 +------- Mage.Sets/src/mage/sets/AetherRevolt.java | 1 + .../common/SwordsToPlowsharesEffect.java | 69 +++++++++++++ 4 files changed, 171 insertions(+), 38 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/a/AjaniUnyielding.java create mode 100644 Mage/src/main/java/mage/abilities/effects/common/SwordsToPlowsharesEffect.java diff --git a/Mage.Sets/src/mage/cards/a/AjaniUnyielding.java b/Mage.Sets/src/mage/cards/a/AjaniUnyielding.java new file mode 100644 index 00000000000..bc530cba2c6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AjaniUnyielding.java @@ -0,0 +1,97 @@ +/* + * 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.a; + +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.RevealLibraryPutIntoHandEffect; +import mage.abilities.effects.common.SwordsToPlowsharesEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterPermanentCard; +import mage.filter.common.FilterPlaneswalkerPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author JRHerlehy + */ +public class AjaniUnyielding extends CardImpl { + + private static final FilterPermanentCard nonlandPermanentFilter = new FilterPermanentCard("nonland permanent card"); + private static final FilterCreaturePermanent creatureFilter = new FilterCreaturePermanent("creature you control"); + private static final FilterPlaneswalkerPermanent planeswalkerFilter = new FilterPlaneswalkerPermanent("other planeswalker you control"); + + static { + nonlandPermanentFilter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); + creatureFilter.add(new ControllerPredicate(TargetController.YOU)); + planeswalkerFilter.add(new ControllerPredicate(TargetController.YOU)); + planeswalkerFilter.add(new AnotherPredicate()); + } + + public AjaniUnyielding(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{4}{G}{W}"); + this.subtype.add("Ajani"); + + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); + + // +2: Reveal the top three cards of your library. Put all nonland permanent cards revealed this way into your hand and the rest on the bottom of your library in any order. + this.addAbility(new LoyaltyAbility(new RevealLibraryPutIntoHandEffect(3, nonlandPermanentFilter, true), 2)); + + // -2: Exile target creature. Its controller gains life equal to its power. + LoyaltyAbility ajaniAbility2 = new LoyaltyAbility(new SwordsToPlowsharesEffect(), -2); + ajaniAbility2.addEffect(new ExileTargetEffect()); + ajaniAbility2.addTarget(new TargetCreaturePermanent()); + this.addAbility(ajaniAbility2); + + // -9: Put five +1/+1 counters on each creature you control and five loyalty counters on each other planeswalker you control. + LoyaltyAbility ajaniAbility3 = new LoyaltyAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(5), creatureFilter), -9); + ajaniAbility3.addEffect(new AddCountersAllEffect(CounterType.LOYALTY.createInstance(5), planeswalkerFilter)); + this.addAbility(ajaniAbility3); + } + + public AjaniUnyielding(final AjaniUnyielding card) { + super(card); + } + + @Override + public AjaniUnyielding copy() { + return new AjaniUnyielding(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SwordsToPlowshares.java b/Mage.Sets/src/mage/cards/s/SwordsToPlowshares.java index c8dd2cd0cdc..d821b122739 100644 --- a/Mage.Sets/src/mage/cards/s/SwordsToPlowshares.java +++ b/Mage.Sets/src/mage/cards/s/SwordsToPlowshares.java @@ -27,19 +27,15 @@ */ package mage.cards.s; -import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.SwordsToPlowsharesEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; +import mage.constants.CardType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * * @author jonubuu @@ -67,33 +63,3 @@ public class SwordsToPlowshares extends CardImpl { return new SwordsToPlowshares(this); } } - -class SwordsToPlowsharesEffect extends OneShotEffect { - - public SwordsToPlowsharesEffect() { - super(Outcome.GainLife); - staticText = "Its controller gains life equal to its power"; - } - - public SwordsToPlowsharesEffect(final SwordsToPlowsharesEffect effect) { - super(effect); - } - - @Override - public SwordsToPlowsharesEffect copy() { - return new SwordsToPlowsharesEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); - if (permanent != null) { - Player player = game.getPlayer(permanent.getControllerId()); - if (player != null) { - player.gainLife(permanent.getPower().getValue(), game); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/sets/AetherRevolt.java b/Mage.Sets/src/mage/sets/AetherRevolt.java index 761e72694f4..b5a4df68369 100644 --- a/Mage.Sets/src/mage/sets/AetherRevolt.java +++ b/Mage.Sets/src/mage/sets/AetherRevolt.java @@ -64,6 +64,7 @@ public class AetherRevolt extends ExpansionSet { this.maxCardNumberInBooster = 184; this.ratioBoosterSpecialLand = 144; this.parentSet = Kaladesh.getInstance(); + cards.add(new SetCardInfo("Ajani Unyielding", 127, Rarity.MYTHIC, mage.cards.a.AjaniUnyielding.class)); cards.add(new SetCardInfo("Ajani, Valiant Protector", 185, Rarity.MYTHIC, mage.cards.a.AjaniValiantProtector.class)); cards.add(new SetCardInfo("Disallow", 31, Rarity.RARE, mage.cards.d.Disallow.class)); cards.add(new SetCardInfo("Pia's Revolution", 91, Rarity.RARE, mage.cards.p.PiasRevolution.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/SwordsToPlowsharesEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SwordsToPlowsharesEffect.java new file mode 100644 index 00000000000..7cd7f595295 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/SwordsToPlowsharesEffect.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * @author JRHerlehy + */ +public class SwordsToPlowsharesEffect extends OneShotEffect { + + public SwordsToPlowsharesEffect() { + super(Outcome.GainLife); + staticText = "Its controller gains life equal to its power"; + } + + public SwordsToPlowsharesEffect(final SwordsToPlowsharesEffect effect) { + super(effect); + } + + @Override + public SwordsToPlowsharesEffect copy() { + return new SwordsToPlowsharesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); + if (permanent != null) { + Player player = game.getPlayer(permanent.getControllerId()); + if (player != null) { + player.gainLife(permanent.getPower().getValue(), game); + } + return true; + } + return false; + } +} From 0a88531333796b1d9dfc84dd2ea6617c9c507c2c Mon Sep 17 00:00:00 2001 From: Styxo Date: Wed, 7 Dec 2016 11:47:01 +0100 Subject: [PATCH 24/38] [LRW] Added Colfenors Plan and Colfenors Urn --- .../src/mage/cards/c/ColfenorsPlans.java | 192 ++++++++++++++++++ Mage.Sets/src/mage/cards/c/ColfenorsUrn.java | 138 +++++++++++++ Mage.Sets/src/mage/sets/Lorwyn.java | 2 + 3 files changed, 332 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/c/ColfenorsPlans.java create mode 100644 Mage.Sets/src/mage/cards/c/ColfenorsUrn.java diff --git a/Mage.Sets/src/mage/cards/c/ColfenorsPlans.java b/Mage.Sets/src/mage/cards/c/ColfenorsPlans.java new file mode 100644 index 00000000000..d1fd6e37a19 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ColfenorsPlans.java @@ -0,0 +1,192 @@ +/* + * 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.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SkipDrawStepEffect; +import mage.abilities.effects.common.continuous.CantCastMoreThanOneSpellEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AsThoughEffectType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.ExileZone; +import mage.game.Game; +import mage.players.Player; +import mage.util.CardUtil; + +/** + * + * @author Styxo + */ +public class ColfenorsPlans extends CardImpl { + + public ColfenorsPlans(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); + + // When Colfenor's Plans enters the battlefield, exile the top seven cards of your library face down. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ColfenorsPlansExileEffect(), false)); + + // You may look at and play cards exiled with Colfenor's Plans. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ColfenorsPlansPlayCardEffect())); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new ColfenorsPlansLookAtCardEffect())); + + // Skip your draw step. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SkipDrawStepEffect())); + + // You can't cast more than one spell each turn. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantCastMoreThanOneSpellEffect(TargetController.YOU))); + + } + + public ColfenorsPlans(final ColfenorsPlans card) { + super(card); + } + + @Override + public ColfenorsPlans copy() { + return new ColfenorsPlans(this); + } +} + +class ColfenorsPlansExileEffect extends OneShotEffect { + + public ColfenorsPlansExileEffect() { + super(Outcome.DrawCard); + staticText = "exile the top seven cards of your library face down"; + } + + public ColfenorsPlansExileEffect(final ColfenorsPlansExileEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (player != null && sourceObject != null) { + for (int i = 0; i < 7; i++) { + Card card = player.getLibrary().removeFromTop(game); + if (card != null) { + if (player.moveCardToExileWithInfo(card, CardUtil.getCardExileZoneId(game, source), sourceObject.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true)) { + card.setFaceDown(true, game); + } + } + } + return true; + } + return false; + } + + @Override + public ColfenorsPlansExileEffect copy() { + return new ColfenorsPlansExileEffect(this); + } +} + +class ColfenorsPlansPlayCardEffect extends AsThoughEffectImpl { + + public ColfenorsPlansPlayCardEffect() { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "You may play cards exiled with {this}"; + } + + public ColfenorsPlansPlayCardEffect(final ColfenorsPlansPlayCardEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public ColfenorsPlansPlayCardEffect copy() { + return new ColfenorsPlansPlayCardEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + Card card = game.getCard(objectId); + if (affectedControllerId.equals(source.getControllerId()) && card != null && game.getState().getZone(card.getId()) == Zone.EXILED) { + ExileZone zone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)); + return zone != null && zone.contains(card.getId()); + } + return false; + } +} + +class ColfenorsPlansLookAtCardEffect extends AsThoughEffectImpl { + + public ColfenorsPlansLookAtCardEffect() { + super(AsThoughEffectType.LOOK_AT_FACE_DOWN, Duration.EndOfGame, Outcome.Benefit); + staticText = "You may look at cards exiled with {this}"; + } + + public ColfenorsPlansLookAtCardEffect(final ColfenorsPlansLookAtCardEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public ColfenorsPlansLookAtCardEffect copy() { + return new ColfenorsPlansLookAtCardEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + if (affectedControllerId.equals(source.getControllerId())) { + Card card = game.getCard(objectId); + if (card != null) { + MageObject sourceObject = game.getObject(source.getSourceId()); + if (sourceObject == null) { + return false; + } + UUID exileId = CardUtil.getCardExileZoneId(game, source); + ExileZone exile = game.getExile().getExileZone(exileId); + return exile != null && exile.contains(objectId); + } + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/cards/c/ColfenorsUrn.java b/Mage.Sets/src/mage/cards/c/ColfenorsUrn.java new file mode 100644 index 00000000000..0c477bc253c --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ColfenorsUrn.java @@ -0,0 +1,138 @@ +/* + * 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.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetForSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.Filter; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ToughnessPredicate; +import mage.game.ExileZone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.util.CardUtil; + +/** + * + * @author Styxo + */ +public class ColfenorsUrn extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature with toughness 4 or greater"); + + static { + filter.add(new ToughnessPredicate(Filter.ComparisonType.GreaterThan, 3)); + } + + public ColfenorsUrn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + + // Whenever a creature with toughness 4 or greater is put into your graveyard from the battlefield, you may exile it. + this.addAbility(new DiesCreatureTriggeredAbility(new ExileTargetForSourceEffect(), true, filter, true)); + + // At the beginning of the end step, if three or more cards have been exiled with Colfenor's Urn, sacrifice it. If you do, return those cards to the battlefield under their owner's control. + this.addAbility(new BeginningOfEndStepTriggeredAbility(Zone.BATTLEFIELD, new ColfenorsUrnEffect(), TargetController.ANY, new ColfenorsUrnCondition(), false)); + } + + public ColfenorsUrn(final ColfenorsUrn card) { + super(card); + } + + @Override + public ColfenorsUrn copy() { + return new ColfenorsUrn(this); + } +} + +class ColfenorsUrnEffect extends OneShotEffect { + + public ColfenorsUrnEffect() { + super(Outcome.PutCreatureInPlay); + this.staticText = "If you do, return those cards to the battlefield under their owner's control"; + } + + public ColfenorsUrnEffect(final ColfenorsUrnEffect effect) { + super(effect); + } + + @Override + public ColfenorsUrnEffect copy() { + return new ColfenorsUrnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent permanent = (Permanent) source.getSourceObjectIfItStillExists(game); + if (controller != null && permanent != null) { + UUID exileId = CardUtil.getCardExileZoneId(game, source); + ExileZone exile = game.getExile().getExileZone(exileId); + if (permanent.sacrifice(source.getSourceId(), game)) { + controller.moveCards(exile.getCards(game), Zone.BATTLEFIELD, source, game); + } + return true; + + } + return false; + } +} + +class ColfenorsUrnCondition implements Condition { + + @Override + public final boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller != null && sourceObject != null) { + UUID exileId = CardUtil.getCardExileZoneId(game, source); + ExileZone exile = game.getExile().getExileZone(exileId); + if (exile != null) { + return exile.size() > 2; + } + } + return false; + } + + @Override + public String toString() { + return "if three or more cards have been exiled with Colfenor's Urn, sacrifice it."; + } +} diff --git a/Mage.Sets/src/mage/sets/Lorwyn.java b/Mage.Sets/src/mage/sets/Lorwyn.java index a911d9f488b..89aac18df37 100644 --- a/Mage.Sets/src/mage/sets/Lorwyn.java +++ b/Mage.Sets/src/mage/sets/Lorwyn.java @@ -97,6 +97,8 @@ public class Lorwyn extends ExpansionSet { cards.add(new SetCardInfo("Cloudcrown Oak", 201, Rarity.COMMON, mage.cards.c.CloudcrownOak.class)); cards.add(new SetCardInfo("Cloudgoat Ranger", 10, Rarity.UNCOMMON, mage.cards.c.CloudgoatRanger.class)); cards.add(new SetCardInfo("Cloudthresher", 202, Rarity.RARE, mage.cards.c.Cloudthresher.class)); + cards.add(new SetCardInfo("Colfenor's Plans", 106, Rarity.RARE, mage.cards.c.ColfenorsPlans.class)); + cards.add(new SetCardInfo("Colfenor's Urn", 254, Rarity.RARE, mage.cards.c.ColfenorsUrn.class)); cards.add(new SetCardInfo("Consuming Bonfire", 161, Rarity.COMMON, mage.cards.c.ConsumingBonfire.class)); cards.add(new SetCardInfo("Crib Swap", 11, Rarity.UNCOMMON, mage.cards.c.CribSwap.class)); cards.add(new SetCardInfo("Crush Underfoot", 162, Rarity.UNCOMMON, mage.cards.c.CrushUnderfoot.class)); From d5d2657cea60bb807d8b140565393219b6365455 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 7 Dec 2016 16:21:27 +0100 Subject: [PATCH 25/38] Protector of the Crown - Added missing Soldier subtype. --- Mage.Sets/src/mage/cards/p/ProtectorOfTheCrown.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Mage.Sets/src/mage/cards/p/ProtectorOfTheCrown.java b/Mage.Sets/src/mage/cards/p/ProtectorOfTheCrown.java index e391d27a759..526e6d329b4 100644 --- a/Mage.Sets/src/mage/cards/p/ProtectorOfTheCrown.java +++ b/Mage.Sets/src/mage/cards/p/ProtectorOfTheCrown.java @@ -55,6 +55,7 @@ public class ProtectorOfTheCrown extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}"); this.subtype.add("Giant"); + this.subtype.add("Soldier"); this.power = new MageInt(2); this.toughness = new MageInt(5); From 271fbf0963a86b42609462cc55db6a7a4a2a29ae Mon Sep 17 00:00:00 2001 From: fireshoes Date: Wed, 7 Dec 2016 09:33:00 -0600 Subject: [PATCH 26/38] Merge --- Mage.Sets/src/mage/sets/AetherRevolt.java | 169 +++++++++++----------- 1 file changed, 85 insertions(+), 84 deletions(-) diff --git a/Mage.Sets/src/mage/sets/AetherRevolt.java b/Mage.Sets/src/mage/sets/AetherRevolt.java index 610c24e217c..716a7e65044 100644 --- a/Mage.Sets/src/mage/sets/AetherRevolt.java +++ b/Mage.Sets/src/mage/sets/AetherRevolt.java @@ -1,84 +1,85 @@ -/* - * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of BetaSteward_at_googlemail.com. - */ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.cards.repository.CardCriteria; -import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; -import mage.constants.Rarity; -import mage.constants.SetType; - -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author fireshoes - */ -public class AetherRevolt extends ExpansionSet { - - private static final AetherRevolt fINSTANCE = new AetherRevolt(); - - public static AetherRevolt getInstance() { - return fINSTANCE; - } - - protected final List savedSpecialLand = new ArrayList<>(); - - private AetherRevolt() { - super("Aether Revolt", "AER", ExpansionSet.buildDate(2017, 1, 20), SetType.EXPANSION); - this.blockName = "Kaladesh"; - this.hasBoosters = true; - this.hasBasicLands = false; - this.numBoosterLands = 1; - this.numBoosterCommon = 10; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 8; - this.maxCardNumberInBooster = 184; - this.ratioBoosterSpecialLand = 144; - this.parentSet = Kaladesh.getInstance(); - cards.add(new SetCardInfo("Ajani, Valiant Protector", 185, Rarity.MYTHIC, mage.cards.a.AjaniValiantProtector.class)); - cards.add(new SetCardInfo("Disallow", 31, Rarity.RARE, mage.cards.d.Disallow.class)); - cards.add(new SetCardInfo("Tezzeret, Master of Metal", 190, Rarity.MYTHIC, mage.cards.t.TezzeretMasterOfMetal.class)); - } - - @Override - public List getSpecialLand() { - if (savedSpecialLand.isEmpty()) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes("MPS"); - criteria.minCardNumber(31); - criteria.maxCardNumber(54); - savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); - } - - return new ArrayList<>(savedSpecialLand); - } -} +/* + * 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.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; +import mage.constants.Rarity; +import mage.constants.SetType; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author fireshoes + */ +public class AetherRevolt extends ExpansionSet { + + private static final AetherRevolt fINSTANCE = new AetherRevolt(); + + public static AetherRevolt getInstance() { + return fINSTANCE; + } + + protected final List savedSpecialLand = new ArrayList<>(); + + private AetherRevolt() { + super("Aether Revolt", "AER", ExpansionSet.buildDate(2017, 1, 20), SetType.EXPANSION); + this.blockName = "Kaladesh"; + this.hasBoosters = true; + this.hasBasicLands = false; + this.numBoosterLands = 1; + this.numBoosterCommon = 10; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 8; + this.maxCardNumberInBooster = 184; + this.ratioBoosterSpecialLand = 144; + this.parentSet = Kaladesh.getInstance(); + cards.add(new SetCardInfo("Ajani, Valiant Protector", 185, Rarity.MYTHIC, mage.cards.a.AjaniValiantProtector.class)); + cards.add(new SetCardInfo("Disallow", 31, Rarity.RARE, mage.cards.d.Disallow.class)); + cards.add(new SetCardInfo("Tezzeret, Master of Metal", 190, Rarity.MYTHIC, mage.cards.t.TezzeretMasterOfMetal.class)); + cards.add(new SetCardInfo("Yaheeni's Expertise", 75, Rarity.RARE, mage.cards.y.YaheenisExpertise.class)); + } + + @Override + public List getSpecialLand() { + if (savedSpecialLand.isEmpty()) { + CardCriteria criteria = new CardCriteria(); + criteria.setCodes("MPS"); + criteria.minCardNumber(31); + criteria.maxCardNumber(54); + savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); + } + + return new ArrayList<>(savedSpecialLand); + } +} From 11a705fda3ef07b0d162dccd77b7db8a2fdf3bec Mon Sep 17 00:00:00 2001 From: fireshoes Date: Wed, 7 Dec 2016 09:46:27 -0600 Subject: [PATCH 27/38] Added Borderland Explorer, Yaheeni's Expertise, and Vintage Cube Nov '16. --- .../cubes/VintageCubeNovember2016.java | 583 ++++++++++++++++++ .../src/mage/cards/b/BorderlandExplorer.java | 168 +++++ .../src/mage/cards/y/YaheenisExpertise.java | 124 ++++ 3 files changed, 875 insertions(+) create mode 100644 Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/VintageCubeNovember2016.java create mode 100644 Mage.Sets/src/mage/cards/b/BorderlandExplorer.java create mode 100644 Mage.Sets/src/mage/cards/y/YaheenisExpertise.java diff --git a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/VintageCubeNovember2016.java b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/VintageCubeNovember2016.java new file mode 100644 index 00000000000..4e18c21ff9c --- /dev/null +++ b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/VintageCubeNovember2016.java @@ -0,0 +1,583 @@ +/* + * 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.tournament.cubes; + +import mage.game.draft.DraftCube; + +/** + * + * @author fireshoes + */ +public class VintageCubeNovember2016 extends DraftCube { + + public VintageCubeNovember2016() { + super("MTGO Vintage Cube November 2016"); + + cubeCards.add(new DraftCube.CardIdentity("Abbot of Keral Keep", "")); + cubeCards.add(new DraftCube.CardIdentity("Abrupt Decay", "")); + cubeCards.add(new DraftCube.CardIdentity("Academy Rector", "")); + cubeCards.add(new DraftCube.CardIdentity("Academy Ruins", "")); + cubeCards.add(new DraftCube.CardIdentity("Acidic Slime", "")); + cubeCards.add(new DraftCube.CardIdentity("Ajani Vengeant", "")); + cubeCards.add(new DraftCube.CardIdentity("Ancestral Recall", "")); + cubeCards.add(new DraftCube.CardIdentity("Ancestral Vision", "")); + cubeCards.add(new DraftCube.CardIdentity("Ancient Grudge", "")); + cubeCards.add(new DraftCube.CardIdentity("Ancient Tomb", "")); + cubeCards.add(new DraftCube.CardIdentity("Angel of Serenity", "")); + cubeCards.add(new DraftCube.CardIdentity("Anguished Unmaking", "")); + cubeCards.add(new DraftCube.CardIdentity("Animate Dead", "")); + cubeCards.add(new DraftCube.CardIdentity("Anticipate", "")); + cubeCards.add(new DraftCube.CardIdentity("Arbor Elf", "")); + cubeCards.add(new DraftCube.CardIdentity("Archangel of Thune", "")); + cubeCards.add(new DraftCube.CardIdentity("Arid Mesa", "")); + cubeCards.add(new DraftCube.CardIdentity("Armageddon", "")); + cubeCards.add(new DraftCube.CardIdentity("Ashiok, Nightmare Weaver", "")); + cubeCards.add(new DraftCube.CardIdentity("Avacyn's Pilgrim", "")); + cubeCards.add(new DraftCube.CardIdentity("Avalanche Riders", "")); + cubeCards.add(new DraftCube.CardIdentity("Avenger of Zendikar", "")); + cubeCards.add(new DraftCube.CardIdentity("Awakening Zone", "")); + cubeCards.add(new DraftCube.CardIdentity("Azorius Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Badlands", "")); + cubeCards.add(new DraftCube.CardIdentity("Balance", "")); + cubeCards.add(new DraftCube.CardIdentity("Baleful Strix", "")); + cubeCards.add(new DraftCube.CardIdentity("Baneslayer Angel", "")); + cubeCards.add(new DraftCube.CardIdentity("Banisher Priest", "")); + cubeCards.add(new DraftCube.CardIdentity("Banishing Light", "")); + cubeCards.add(new DraftCube.CardIdentity("Basalt Monolith", "")); + cubeCards.add(new DraftCube.CardIdentity("Batterskull", "")); + cubeCards.add(new DraftCube.CardIdentity("Bayou", "")); + cubeCards.add(new DraftCube.CardIdentity("Bazaar of Baghdad", "")); + cubeCards.add(new DraftCube.CardIdentity("Beast Within", "")); + cubeCards.add(new DraftCube.CardIdentity("Birds of Paradise", "")); + cubeCards.add(new DraftCube.CardIdentity("Birthing Pod", "")); + cubeCards.add(new DraftCube.CardIdentity("Bitterblossom", "")); + cubeCards.add(new DraftCube.CardIdentity("Black Lotus", "")); + cubeCards.add(new DraftCube.CardIdentity("Blade Splicer", "")); + cubeCards.add(new DraftCube.CardIdentity("Blightsteel Colossus", "")); + cubeCards.add(new DraftCube.CardIdentity("Blood Crypt", "")); + cubeCards.add(new DraftCube.CardIdentity("Bloodbraid Elf", "")); + cubeCards.add(new DraftCube.CardIdentity("Bloodstained Mire", "")); + cubeCards.add(new DraftCube.CardIdentity("Bone Shredder", "")); + cubeCards.add(new DraftCube.CardIdentity("Bonfire of the Damned", "")); + cubeCards.add(new DraftCube.CardIdentity("Boros Charm", "")); + cubeCards.add(new DraftCube.CardIdentity("Boros Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Braids, Cabal Minion", "")); + cubeCards.add(new DraftCube.CardIdentity("Brain Freeze", "")); + cubeCards.add(new DraftCube.CardIdentity("Brain Maggot", "")); + cubeCards.add(new DraftCube.CardIdentity("Brainstorm", "")); + cubeCards.add(new DraftCube.CardIdentity("Breeding Pool", "")); + cubeCards.add(new DraftCube.CardIdentity("Bribery", "")); + cubeCards.add(new DraftCube.CardIdentity("Brimaz, King of Oreskos", "")); + cubeCards.add(new DraftCube.CardIdentity("Brimstone Volley", "")); + cubeCards.add(new DraftCube.CardIdentity("Bring to Light", "")); + cubeCards.add(new DraftCube.CardIdentity("Buried Alive", "")); + cubeCards.add(new DraftCube.CardIdentity("Burning of Xinye", "")); + cubeCards.add(new DraftCube.CardIdentity("Burst Lightning", "")); + cubeCards.add(new DraftCube.CardIdentity("Cabal Ritual", "")); + cubeCards.add(new DraftCube.CardIdentity("Careful Study", "")); + cubeCards.add(new DraftCube.CardIdentity("Celestial Colonnade", "")); + cubeCards.add(new DraftCube.CardIdentity("Chain Lightning", "")); + cubeCards.add(new DraftCube.CardIdentity("Chandra, Flamecaller", "")); + cubeCards.add(new DraftCube.CardIdentity("Chandra, Pyromaster", "")); + cubeCards.add(new DraftCube.CardIdentity("Chandra, Torch of Defiance", "")); + cubeCards.add(new DraftCube.CardIdentity("Channel", "")); + cubeCards.add(new DraftCube.CardIdentity("Char", "")); + cubeCards.add(new DraftCube.CardIdentity("Chrome Mox", "")); + cubeCards.add(new DraftCube.CardIdentity("Coalition Relic", "")); + cubeCards.add(new DraftCube.CardIdentity("Coercive Portal", "")); + cubeCards.add(new DraftCube.CardIdentity("Compulsive Research", "")); + cubeCards.add(new DraftCube.CardIdentity("Conclave Naturalists", "")); + cubeCards.add(new DraftCube.CardIdentity("Consecrated Sphinx", "")); + cubeCards.add(new DraftCube.CardIdentity("Control Magic", "")); + cubeCards.add(new DraftCube.CardIdentity("Corpse Dance", "")); + cubeCards.add(new DraftCube.CardIdentity("Council's Judgment", "")); + cubeCards.add(new DraftCube.CardIdentity("Counterspell", "")); + cubeCards.add(new DraftCube.CardIdentity("Courser of Kruphix", "")); + cubeCards.add(new DraftCube.CardIdentity("Crater's Claws", "")); + cubeCards.add(new DraftCube.CardIdentity("Craterhoof Behemoth", "")); + cubeCards.add(new DraftCube.CardIdentity("Creeping Tar Pit", "")); + cubeCards.add(new DraftCube.CardIdentity("Crucible of Worlds", "")); + cubeCards.add(new DraftCube.CardIdentity("Cryptic Command", "")); + cubeCards.add(new DraftCube.CardIdentity("Dack Fayden", "")); + cubeCards.add(new DraftCube.CardIdentity("Damnation", "")); + cubeCards.add(new DraftCube.CardIdentity("Daretti, Scrap Savant", "")); + cubeCards.add(new DraftCube.CardIdentity("Dark Confidant", "")); + cubeCards.add(new DraftCube.CardIdentity("Dark Petition", "")); + cubeCards.add(new DraftCube.CardIdentity("Dark Ritual", "")); + cubeCards.add(new DraftCube.CardIdentity("Day of Judgment", "")); + cubeCards.add(new DraftCube.CardIdentity("Daze", "")); + cubeCards.add(new DraftCube.CardIdentity("Deathrite Shaman", "")); + cubeCards.add(new DraftCube.CardIdentity("Deceiver Exarch", "")); + cubeCards.add(new DraftCube.CardIdentity("Declaration in Stone", "")); + cubeCards.add(new DraftCube.CardIdentity("Delver of Secrets", "")); + cubeCards.add(new DraftCube.CardIdentity("Demonic Tutor", "")); + cubeCards.add(new DraftCube.CardIdentity("Den Protector", "")); + cubeCards.add(new DraftCube.CardIdentity("Deranged Hermit", "")); + cubeCards.add(new DraftCube.CardIdentity("Desecration Demon", "")); + cubeCards.add(new DraftCube.CardIdentity("Diabolic Edict", "")); + cubeCards.add(new DraftCube.CardIdentity("Dig Through Time", "")); + cubeCards.add(new DraftCube.CardIdentity("Dimir Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Disenchant", "")); + cubeCards.add(new DraftCube.CardIdentity("Disfigure", "")); + cubeCards.add(new DraftCube.CardIdentity("Dismember", "")); + cubeCards.add(new DraftCube.CardIdentity("Dragonlord Atarka", "")); + cubeCards.add(new DraftCube.CardIdentity("Dragonlord Dromoka", "")); + cubeCards.add(new DraftCube.CardIdentity("Dragonlord Ojutai", "")); + cubeCards.add(new DraftCube.CardIdentity("Dragonlord Silumgar", "")); + cubeCards.add(new DraftCube.CardIdentity("Dreadbore", "")); + cubeCards.add(new DraftCube.CardIdentity("Dromoka's Command", "")); + cubeCards.add(new DraftCube.CardIdentity("Dualcaster Mage", "")); + cubeCards.add(new DraftCube.CardIdentity("Duplicant", "")); + cubeCards.add(new DraftCube.CardIdentity("Duress", "")); + cubeCards.add(new DraftCube.CardIdentity("Edric, Spymaster of Trest", "")); + cubeCards.add(new DraftCube.CardIdentity("Eidolon of the Great Revel", "")); + cubeCards.add(new DraftCube.CardIdentity("Electrolyze", "")); + cubeCards.add(new DraftCube.CardIdentity("Elesh Norn, Grand Cenobite", "")); + cubeCards.add(new DraftCube.CardIdentity("Elspeth, Knight-Errant", "")); + cubeCards.add(new DraftCube.CardIdentity("Elspeth, Sun's Champion", "")); + cubeCards.add(new DraftCube.CardIdentity("Elves of Deep Shadow", "")); + cubeCards.add(new DraftCube.CardIdentity("Elvish Mystic", "")); + cubeCards.add(new DraftCube.CardIdentity("Emeria Angel", "")); + cubeCards.add(new DraftCube.CardIdentity("Empty the Warrens", "")); + cubeCards.add(new DraftCube.CardIdentity("Emrakul, the Aeons Torn", "")); + cubeCards.add(new DraftCube.CardIdentity("Emrakul, the Promised End", "")); + cubeCards.add(new DraftCube.CardIdentity("Enlightened Tutor", "")); + cubeCards.add(new DraftCube.CardIdentity("Entomb", "")); + cubeCards.add(new DraftCube.CardIdentity("Eternal Witness", "")); + cubeCards.add(new DraftCube.CardIdentity("Eureka", "")); + cubeCards.add(new DraftCube.CardIdentity("Everflowing Chalice", "")); + cubeCards.add(new DraftCube.CardIdentity("Exalted Angel", "")); + cubeCards.add(new DraftCube.CardIdentity("Exquisite Firecraft", "")); + cubeCards.add(new DraftCube.CardIdentity("Exhume", "")); + cubeCards.add(new DraftCube.CardIdentity("Fact or Fiction", "")); + cubeCards.add(new DraftCube.CardIdentity("Faith's Fetters", "")); + cubeCards.add(new DraftCube.CardIdentity("Faithless Looting", "")); + cubeCards.add(new DraftCube.CardIdentity("Falkenrath Gorger", "")); + cubeCards.add(new DraftCube.CardIdentity("Fastbond", "")); + cubeCards.add(new DraftCube.CardIdentity("Fauna Shaman", "")); + cubeCards.add(new DraftCube.CardIdentity("Fiend Hunter", "")); + cubeCards.add(new DraftCube.CardIdentity("Fiery Confluence", "")); + cubeCards.add(new DraftCube.CardIdentity("Figure of Destiny", "")); + cubeCards.add(new DraftCube.CardIdentity("Fire // Ice", "")); + cubeCards.add(new DraftCube.CardIdentity("Fireblast", "")); + cubeCards.add(new DraftCube.CardIdentity("Firebolt", "")); + cubeCards.add(new DraftCube.CardIdentity("Firedrinker Satyr", "")); + cubeCards.add(new DraftCube.CardIdentity("Flametongue Kavu", "")); + cubeCards.add(new DraftCube.CardIdentity("Flickerwisp", "")); + cubeCards.add(new DraftCube.CardIdentity("Flooded Strand", "")); + cubeCards.add(new DraftCube.CardIdentity("Force of Will", "")); + cubeCards.add(new DraftCube.CardIdentity("Force Spike", "")); + cubeCards.add(new DraftCube.CardIdentity("Frantic Search", "")); + cubeCards.add(new DraftCube.CardIdentity("Freyalise, Llanowar's Fury", "")); + cubeCards.add(new DraftCube.CardIdentity("Frost Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Fyndhorn Elves", "")); + cubeCards.add(new DraftCube.CardIdentity("Gaea's Cradle", "")); + cubeCards.add(new DraftCube.CardIdentity("Garruk Relentless", "")); + cubeCards.add(new DraftCube.CardIdentity("Garruk Wildspeaker", "")); + cubeCards.add(new DraftCube.CardIdentity("Garruk, Apex Predator", "")); + cubeCards.add(new DraftCube.CardIdentity("Garruk, Primal Hunter", "")); + cubeCards.add(new DraftCube.CardIdentity("Geist of Saint Traft", "")); + cubeCards.add(new DraftCube.CardIdentity("Genesis Wave", "")); + cubeCards.add(new DraftCube.CardIdentity("Gideon Jura", "")); + cubeCards.add(new DraftCube.CardIdentity("Gideon, Ally of Zendikar", "")); + cubeCards.add(new DraftCube.CardIdentity("Gifts Ungiven", "")); + cubeCards.add(new DraftCube.CardIdentity("Gilded Lotus", "")); + cubeCards.add(new DraftCube.CardIdentity("Gitaxian Probe", "")); + cubeCards.add(new DraftCube.CardIdentity("Glen Elendra Archmage", "")); + cubeCards.add(new DraftCube.CardIdentity("Go for the Throat", "")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Dark-Dwellers", "")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Guide", "")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Welder", "")); + cubeCards.add(new DraftCube.CardIdentity("Godless Shrine", "")); + cubeCards.add(new DraftCube.CardIdentity("Golgari Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Grave Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Green Sun's Zenith", "")); + cubeCards.add(new DraftCube.CardIdentity("Grim Lavamancer", "")); + cubeCards.add(new DraftCube.CardIdentity("Grim Monolith", "")); + cubeCards.add(new DraftCube.CardIdentity("Grim Tutor", "")); + cubeCards.add(new DraftCube.CardIdentity("Griselbrand", "")); + cubeCards.add(new DraftCube.CardIdentity("Gruul Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Gurmag Angler", "")); + cubeCards.add(new DraftCube.CardIdentity("Gush", "")); + cubeCards.add(new DraftCube.CardIdentity("Guttersnipe", "")); + cubeCards.add(new DraftCube.CardIdentity("Hallowed Fountain", "")); + cubeCards.add(new DraftCube.CardIdentity("Hangarback Walker", "")); + cubeCards.add(new DraftCube.CardIdentity("Harmonize", "")); + cubeCards.add(new DraftCube.CardIdentity("Heartbeat of Spring", "")); + cubeCards.add(new DraftCube.CardIdentity("Hedron Archive", "")); + cubeCards.add(new DraftCube.CardIdentity("Hellrider", "")); + cubeCards.add(new DraftCube.CardIdentity("Hero of Bladehold", "")); + cubeCards.add(new DraftCube.CardIdentity("Hero's Downfall", "")); + cubeCards.add(new DraftCube.CardIdentity("High Tide", "")); + cubeCards.add(new DraftCube.CardIdentity("Hissing Quagmire", "")); + cubeCards.add(new DraftCube.CardIdentity("Honor of the Pure", "")); + cubeCards.add(new DraftCube.CardIdentity("Huntmaster of the Fells", "")); + cubeCards.add(new DraftCube.CardIdentity("Hymn to Tourach", "")); + cubeCards.add(new DraftCube.CardIdentity("Hypnotic Specter", "")); + cubeCards.add(new DraftCube.CardIdentity("Imperial Recruiter", "")); + cubeCards.add(new DraftCube.CardIdentity("Imperial Seal", "")); + cubeCards.add(new DraftCube.CardIdentity("Impulse", "")); + cubeCards.add(new DraftCube.CardIdentity("Incinerate", "")); + cubeCards.add(new DraftCube.CardIdentity("Inferno Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Inkwell Leviathan", "")); + cubeCards.add(new DraftCube.CardIdentity("Inquisition of Kozilek", "")); + cubeCards.add(new DraftCube.CardIdentity("Iona, Shield of Emeria", "")); + cubeCards.add(new DraftCube.CardIdentity("Isochron Scepter", "")); + cubeCards.add(new DraftCube.CardIdentity("Izzet Charm", "")); + cubeCards.add(new DraftCube.CardIdentity("Izzet Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Jace Beleren", "")); + cubeCards.add(new DraftCube.CardIdentity("Jace, Architect of Thought", "")); + cubeCards.add(new DraftCube.CardIdentity("Jace, the Mind Sculptor", "")); + cubeCards.add(new DraftCube.CardIdentity("Jace, Vryn's Prodigy", "")); + cubeCards.add(new DraftCube.CardIdentity("Jackal Pup", "")); + cubeCards.add(new DraftCube.CardIdentity("Joraga Treespeaker", "")); + cubeCards.add(new DraftCube.CardIdentity("Kalitas, Traitor of Ghet", "")); + cubeCards.add(new DraftCube.CardIdentity("Karakas", "")); + cubeCards.add(new DraftCube.CardIdentity("Kargan Dragonlord", "")); + cubeCards.add(new DraftCube.CardIdentity("Karn Liberated", "")); + cubeCards.add(new DraftCube.CardIdentity("Kiki-Jiki, Mirror Breaker", "")); + cubeCards.add(new DraftCube.CardIdentity("Kitchen Finks", "")); + cubeCards.add(new DraftCube.CardIdentity("Knight of the White Orchid", "")); + cubeCards.add(new DraftCube.CardIdentity("Kolaghan's Command", "")); + cubeCards.add(new DraftCube.CardIdentity("Koth of the Hammer", "")); + cubeCards.add(new DraftCube.CardIdentity("Kozilek, Butcher of Truth", "")); + cubeCards.add(new DraftCube.CardIdentity("Kuldotha Forgemaster", "")); + cubeCards.add(new DraftCube.CardIdentity("Kytheon, Hero of Akros", "")); + cubeCards.add(new DraftCube.CardIdentity("Land Tax", "")); + cubeCards.add(new DraftCube.CardIdentity("Lavaclaw Reaches", "")); + cubeCards.add(new DraftCube.CardIdentity("Leonin Relic-Warder", "")); + cubeCards.add(new DraftCube.CardIdentity("Leyline of Sanctity", "")); + cubeCards.add(new DraftCube.CardIdentity("Library of Alexandria", "")); + cubeCards.add(new DraftCube.CardIdentity("Lifebane Zombie", "")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Bolt", "")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Greaves", "")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Helix", "")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Mauler", "")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Strike", "")); + cubeCards.add(new DraftCube.CardIdentity("Liliana of the Veil", "")); + cubeCards.add(new DraftCube.CardIdentity("Lingering Souls", "")); + cubeCards.add(new DraftCube.CardIdentity("Linvala, Keeper of Silence", "")); + cubeCards.add(new DraftCube.CardIdentity("Linvala, the Preserver", "")); + cubeCards.add(new DraftCube.CardIdentity("Lion's Eye Diamond", "")); + cubeCards.add(new DraftCube.CardIdentity("Living Death", "")); + cubeCards.add(new DraftCube.CardIdentity("Llanowar Elves", "")); + cubeCards.add(new DraftCube.CardIdentity("Lodestone Golem", "")); + cubeCards.add(new DraftCube.CardIdentity("Looter il-Kor", "")); + cubeCards.add(new DraftCube.CardIdentity("Lotus Bloom", "")); + cubeCards.add(new DraftCube.CardIdentity("Lotus Cobra", "")); + cubeCards.add(new DraftCube.CardIdentity("Lumbering Falls", "")); + cubeCards.add(new DraftCube.CardIdentity("Maelstrom Pulse", "")); + cubeCards.add(new DraftCube.CardIdentity("Magma Jet", "")); + cubeCards.add(new DraftCube.CardIdentity("Magus of the Moon", "")); + cubeCards.add(new DraftCube.CardIdentity("Magus of the Wheel", "")); + cubeCards.add(new DraftCube.CardIdentity("Magus of the Will", "")); + cubeCards.add(new DraftCube.CardIdentity("Makeshift Mannequin", "")); + cubeCards.add(new DraftCube.CardIdentity("Managorger Hydra", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Confluence", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Crypt", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Drain", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Leak", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Tithe", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Vault", "")); + cubeCards.add(new DraftCube.CardIdentity("Manic Vandal", "")); + cubeCards.add(new DraftCube.CardIdentity("Mardu Woe-Reaper", "")); + cubeCards.add(new DraftCube.CardIdentity("Marsh Flats", "")); + cubeCards.add(new DraftCube.CardIdentity("Massacre Wurm", "")); + cubeCards.add(new DraftCube.CardIdentity("Master of the Wild Hunt", "")); + cubeCards.add(new DraftCube.CardIdentity("Maze of Ith", "")); + cubeCards.add(new DraftCube.CardIdentity("Mental Misstep", "")); + cubeCards.add(new DraftCube.CardIdentity("Memory Jar", "")); + cubeCards.add(new DraftCube.CardIdentity("Mesmeric Fiend", "")); + cubeCards.add(new DraftCube.CardIdentity("Metalworker", "")); + cubeCards.add(new DraftCube.CardIdentity("Mind Twist", "")); + cubeCards.add(new DraftCube.CardIdentity("Mindslaver", "")); + cubeCards.add(new DraftCube.CardIdentity("Mind's Desire", "")); + cubeCards.add(new DraftCube.CardIdentity("Mirari's Wake", "")); + cubeCards.add(new DraftCube.CardIdentity("Mirran Crusader", "")); + cubeCards.add(new DraftCube.CardIdentity("Mishra's Factory", "")); + cubeCards.add(new DraftCube.CardIdentity("Mishra's Workshop", "")); + cubeCards.add(new DraftCube.CardIdentity("Misty Rainforest", "")); + cubeCards.add(new DraftCube.CardIdentity("Mizzium Mortars", "")); + cubeCards.add(new DraftCube.CardIdentity("Moat", "")); + cubeCards.add(new DraftCube.CardIdentity("Monastery Mentor", "")); + cubeCards.add(new DraftCube.CardIdentity("Monastery Swiftspear", "")); + cubeCards.add(new DraftCube.CardIdentity("Mother of Runes", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Diamond", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Emerald", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Jet", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Pearl", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Ruby", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Sapphire", "")); + cubeCards.add(new DraftCube.CardIdentity("Mulldrifter", "")); + cubeCards.add(new DraftCube.CardIdentity("Murderous Cut", "")); + cubeCards.add(new DraftCube.CardIdentity("Mutavault", "")); + cubeCards.add(new DraftCube.CardIdentity("Myr Battlesphere", "")); + cubeCards.add(new DraftCube.CardIdentity("Mystical Tutor", "")); + cubeCards.add(new DraftCube.CardIdentity("Mystic Confluence", "")); + cubeCards.add(new DraftCube.CardIdentity("Mystic Snake", "")); + cubeCards.add(new DraftCube.CardIdentity("Nahiri, the Harbinger", "")); + cubeCards.add(new DraftCube.CardIdentity("Natural Order", "")); + cubeCards.add(new DraftCube.CardIdentity("Nature's Claim", "")); + cubeCards.add(new DraftCube.CardIdentity("Necromancy", "")); + cubeCards.add(new DraftCube.CardIdentity("Necropotence", "")); + cubeCards.add(new DraftCube.CardIdentity("Needle Spires", "")); + cubeCards.add(new DraftCube.CardIdentity("Nekrataal", "")); + cubeCards.add(new DraftCube.CardIdentity("Nevinyrral's Disk", "")); + cubeCards.add(new DraftCube.CardIdentity("Nezumi Graverobber", "")); + cubeCards.add(new DraftCube.CardIdentity("Nezumi Shortfang", "")); + cubeCards.add(new DraftCube.CardIdentity("Nicol Bolas, Planeswalker", "")); + cubeCards.add(new DraftCube.CardIdentity("Nissa, Worldwaker", "")); + cubeCards.add(new DraftCube.CardIdentity("Noble Hierarch", "")); + cubeCards.add(new DraftCube.CardIdentity("Nykthos, Shrine to Nyx", "")); + cubeCards.add(new DraftCube.CardIdentity("Oath of Druids", "")); + cubeCards.add(new DraftCube.CardIdentity("Oath of Nissa", "")); + cubeCards.add(new DraftCube.CardIdentity("Oblivion Ring", "")); + cubeCards.add(new DraftCube.CardIdentity("Olivia Voldaren", "")); + cubeCards.add(new DraftCube.CardIdentity("Oona's Prowler", "")); + cubeCards.add(new DraftCube.CardIdentity("Ophiomancer", "")); + cubeCards.add(new DraftCube.CardIdentity("Opposition", "")); + cubeCards.add(new DraftCube.CardIdentity("Oracle of Mul Daya", "")); + cubeCards.add(new DraftCube.CardIdentity("Orzhov Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Overgrown Tomb", "")); + cubeCards.add(new DraftCube.CardIdentity("Pack Rat", "")); + cubeCards.add(new DraftCube.CardIdentity("Painful Truths", "")); + cubeCards.add(new DraftCube.CardIdentity("Palinchron", "")); + cubeCards.add(new DraftCube.CardIdentity("Parallax Wave", "")); + cubeCards.add(new DraftCube.CardIdentity("Path to Exile", "")); + cubeCards.add(new DraftCube.CardIdentity("Pentad Prism", "")); + cubeCards.add(new DraftCube.CardIdentity("Pernicious Deed", "")); + cubeCards.add(new DraftCube.CardIdentity("Pestermite", "")); + cubeCards.add(new DraftCube.CardIdentity("Phantasmal Image", "")); + cubeCards.add(new DraftCube.CardIdentity("Phyrexian Metamorph", "")); + cubeCards.add(new DraftCube.CardIdentity("Phyrexian Revoker", "")); + cubeCards.add(new DraftCube.CardIdentity("Pithing Needle", "")); + cubeCards.add(new DraftCube.CardIdentity("Plateau", "")); + cubeCards.add(new DraftCube.CardIdentity("Polluted Delta", "")); + cubeCards.add(new DraftCube.CardIdentity("Polukranos, World Eater", "")); + cubeCards.add(new DraftCube.CardIdentity("Ponder", "")); + cubeCards.add(new DraftCube.CardIdentity("Porcelain Legionnaire", "")); + cubeCards.add(new DraftCube.CardIdentity("Preordain", "")); + cubeCards.add(new DraftCube.CardIdentity("Primal Command", "")); + cubeCards.add(new DraftCube.CardIdentity("Primeval Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Progenitus", "")); + cubeCards.add(new DraftCube.CardIdentity("Puppeteer Clique", "")); + cubeCards.add(new DraftCube.CardIdentity("Putrid Imp", "")); + cubeCards.add(new DraftCube.CardIdentity("Qasali Pridemage", "")); + cubeCards.add(new DraftCube.CardIdentity("Quicken", "")); + cubeCards.add(new DraftCube.CardIdentity("Raging Ravine", "")); + cubeCards.add(new DraftCube.CardIdentity("Rakdos Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Rakdos's Return", "")); + cubeCards.add(new DraftCube.CardIdentity("Ral Zarek", "")); + cubeCards.add(new DraftCube.CardIdentity("Ravages of War", "")); + cubeCards.add(new DraftCube.CardIdentity("Reanimate", "")); + cubeCards.add(new DraftCube.CardIdentity("Reckless Bushwhacker", "")); + cubeCards.add(new DraftCube.CardIdentity("Reclamation Sage", "")); + cubeCards.add(new DraftCube.CardIdentity("Recruiter of the Guard", "")); + cubeCards.add(new DraftCube.CardIdentity("Recurring Nightmare", "")); + cubeCards.add(new DraftCube.CardIdentity("Reflector Mage", "")); + cubeCards.add(new DraftCube.CardIdentity("Regrowth", "")); + cubeCards.add(new DraftCube.CardIdentity("Remand", "")); + cubeCards.add(new DraftCube.CardIdentity("Repeal", "")); + cubeCards.add(new DraftCube.CardIdentity("Restoration Angel", "")); + cubeCards.add(new DraftCube.CardIdentity("Reveillark", "")); + cubeCards.add(new DraftCube.CardIdentity("Rift Bolt", "")); + cubeCards.add(new DraftCube.CardIdentity("Riftwing Cloudskate", "")); + cubeCards.add(new DraftCube.CardIdentity("Rishadan Port", "")); + cubeCards.add(new DraftCube.CardIdentity("Roast", "")); + cubeCards.add(new DraftCube.CardIdentity("Rofellos, Llanowar Emissary", "")); + cubeCards.add(new DraftCube.CardIdentity("Sacred Foundry", "")); + cubeCards.add(new DraftCube.CardIdentity("Sakura-Tribe Elder", "")); + cubeCards.add(new DraftCube.CardIdentity("Savannah", "")); + cubeCards.add(new DraftCube.CardIdentity("Scalding Tarn", "")); + cubeCards.add(new DraftCube.CardIdentity("Scavenging Ooze", "")); + cubeCards.add(new DraftCube.CardIdentity("Scroll Rack", "")); + cubeCards.add(new DraftCube.CardIdentity("Scrubland", "")); + cubeCards.add(new DraftCube.CardIdentity("Search for Tomorrow", "")); + cubeCards.add(new DraftCube.CardIdentity("Searing Blaze", "")); + cubeCards.add(new DraftCube.CardIdentity("Searing Spear", "")); + cubeCards.add(new DraftCube.CardIdentity("Seasons Past", "")); + cubeCards.add(new DraftCube.CardIdentity("Seeker of the Way", "")); + cubeCards.add(new DraftCube.CardIdentity("Seething Song", "")); + cubeCards.add(new DraftCube.CardIdentity("Selesnya Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Selfless Spirit", "")); + cubeCards.add(new DraftCube.CardIdentity("Sensei's Divining Top", "")); + cubeCards.add(new DraftCube.CardIdentity("Shadowmage Infiltrator", "")); + cubeCards.add(new DraftCube.CardIdentity("Shallow Grave", "")); + cubeCards.add(new DraftCube.CardIdentity("Shambling Vent", "")); + cubeCards.add(new DraftCube.CardIdentity("Shardless Agent", "")); + cubeCards.add(new DraftCube.CardIdentity("Shelldock Isle", "")); + cubeCards.add(new DraftCube.CardIdentity("Sheoldred, Whispering One", "")); + cubeCards.add(new DraftCube.CardIdentity("Show and Tell", "")); + cubeCards.add(new DraftCube.CardIdentity("Shriekmaw", "")); + cubeCards.add(new DraftCube.CardIdentity("Shrine of Burning Rage", "")); + cubeCards.add(new DraftCube.CardIdentity("Sidisi, Undead Vizier", "")); + cubeCards.add(new DraftCube.CardIdentity("Siege-Gang Commander", "")); + cubeCards.add(new DraftCube.CardIdentity("Silverblade Paladin", "")); + cubeCards.add(new DraftCube.CardIdentity("Simic Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Skinrender", "")); + cubeCards.add(new DraftCube.CardIdentity("Skullclamp", "")); + cubeCards.add(new DraftCube.CardIdentity("Smash to Smithereens", "")); + cubeCards.add(new DraftCube.CardIdentity("Smokestack", "")); + cubeCards.add(new DraftCube.CardIdentity("Smuggler's Copter", "")); + cubeCards.add(new DraftCube.CardIdentity("Snapcaster Mage", "")); + cubeCards.add(new DraftCube.CardIdentity("Sneak Attack", "")); + cubeCards.add(new DraftCube.CardIdentity("Sol Ring", "")); + cubeCards.add(new DraftCube.CardIdentity("Soldier of the Pantheon", "")); + cubeCards.add(new DraftCube.CardIdentity("Solemn Simulacrum", "")); + cubeCards.add(new DraftCube.CardIdentity("Song of the Dryads", "")); + cubeCards.add(new DraftCube.CardIdentity("Soulfire Grand Master", "")); + cubeCards.add(new DraftCube.CardIdentity("Sower of Temptation", "")); + cubeCards.add(new DraftCube.CardIdentity("Spear of Heliod", "")); + cubeCards.add(new DraftCube.CardIdentity("Spectral Procession", "")); + cubeCards.add(new DraftCube.CardIdentity("Spell Pierce", "")); + cubeCards.add(new DraftCube.CardIdentity("Spellskite", "")); + cubeCards.add(new DraftCube.CardIdentity("Sphinx of the Steel Wind", "")); + cubeCards.add(new DraftCube.CardIdentity("Sphinx's Revelation", "")); + cubeCards.add(new DraftCube.CardIdentity("Spirit of the Labyrinth", "")); + cubeCards.add(new DraftCube.CardIdentity("Splinter Twin", "")); + cubeCards.add(new DraftCube.CardIdentity("Steam Vents", "")); + cubeCards.add(new DraftCube.CardIdentity("Stirring Wildwood", "")); + cubeCards.add(new DraftCube.CardIdentity("Stomping Ground", "")); + cubeCards.add(new DraftCube.CardIdentity("Stoneforge Mystic", "")); + cubeCards.add(new DraftCube.CardIdentity("Stormbreath Dragon", "")); + cubeCards.add(new DraftCube.CardIdentity("Strip Mine", "")); + cubeCards.add(new DraftCube.CardIdentity("Student of Warfare", "")); + cubeCards.add(new DraftCube.CardIdentity("Sulfuric Vortex", "")); + cubeCards.add(new DraftCube.CardIdentity("Sun Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Sundering Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Supreme Verdict", "")); + cubeCards.add(new DraftCube.CardIdentity("Survival of the Fittest", "")); + cubeCards.add(new DraftCube.CardIdentity("Sword of Body and Mind", "")); + cubeCards.add(new DraftCube.CardIdentity("Sword of Feast and Famine", "")); + cubeCards.add(new DraftCube.CardIdentity("Sword of Fire and Ice", "")); + cubeCards.add(new DraftCube.CardIdentity("Sword of Light and Shadow", "")); + cubeCards.add(new DraftCube.CardIdentity("Sword of War and Peace", "")); + cubeCards.add(new DraftCube.CardIdentity("Swords to Plowshares", "")); + cubeCards.add(new DraftCube.CardIdentity("Sylvan Caryatid", "")); + cubeCards.add(new DraftCube.CardIdentity("Sylvan Library", "")); + cubeCards.add(new DraftCube.CardIdentity("Taiga", "")); + cubeCards.add(new DraftCube.CardIdentity("Tamiyo, the Moon Sage", "")); + cubeCards.add(new DraftCube.CardIdentity("Tangle Wire", "")); + cubeCards.add(new DraftCube.CardIdentity("Tarmogoyf", "")); + cubeCards.add(new DraftCube.CardIdentity("Tasigur, the Golden Fang", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple Garden", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Abandon", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Deceit", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Enlightenment", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Epiphany", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Malady", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Malice", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Mystery", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Plenty", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Silence", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Triumph", "")); + cubeCards.add(new DraftCube.CardIdentity("Tendrils of Agony", "")); + cubeCards.add(new DraftCube.CardIdentity("Terastodon", "")); + cubeCards.add(new DraftCube.CardIdentity("Terminate", "")); + cubeCards.add(new DraftCube.CardIdentity("Tezzeret the Seeker", "")); + cubeCards.add(new DraftCube.CardIdentity("Tezzeret, Agent of Bolas", "")); + cubeCards.add(new DraftCube.CardIdentity("Thada Adel, Acquisitor", "")); + cubeCards.add(new DraftCube.CardIdentity("Thalia, Guardian of Thraben", "")); + cubeCards.add(new DraftCube.CardIdentity("The Abyss", "")); + cubeCards.add(new DraftCube.CardIdentity("Thing in the Ice", "")); + cubeCards.add(new DraftCube.CardIdentity("Thirst for Knowledge", "")); + cubeCards.add(new DraftCube.CardIdentity("Thoughtseize", "")); + cubeCards.add(new DraftCube.CardIdentity("Thragtusk", "")); + cubeCards.add(new DraftCube.CardIdentity("Thran Dynamo", "")); + cubeCards.add(new DraftCube.CardIdentity("Through the Breach", "")); + cubeCards.add(new DraftCube.CardIdentity("Thrun, the Last Troll", "")); + cubeCards.add(new DraftCube.CardIdentity("Thundermaw Hellkite", "")); + cubeCards.add(new DraftCube.CardIdentity("Tidehollow Sculler", "")); + cubeCards.add(new DraftCube.CardIdentity("Time Spiral", "")); + cubeCards.add(new DraftCube.CardIdentity("Time Walk", "")); + cubeCards.add(new DraftCube.CardIdentity("Timely Reinforcements", "")); + cubeCards.add(new DraftCube.CardIdentity("Timetwister", "")); + cubeCards.add(new DraftCube.CardIdentity("Tinker", "")); + cubeCards.add(new DraftCube.CardIdentity("Tolarian Academy", "")); + cubeCards.add(new DraftCube.CardIdentity("Tooth and Nail", "")); + cubeCards.add(new DraftCube.CardIdentity("Torch Fiend", "")); + cubeCards.add(new DraftCube.CardIdentity("Torrential Gearhulk", "")); + cubeCards.add(new DraftCube.CardIdentity("Toxic Deluge", "")); + cubeCards.add(new DraftCube.CardIdentity("Traverse the Ulvenwald", "")); + cubeCards.add(new DraftCube.CardIdentity("Treachery", "")); + cubeCards.add(new DraftCube.CardIdentity("Treasure Cruise", "")); + cubeCards.add(new DraftCube.CardIdentity("Trinket Mage", "")); + cubeCards.add(new DraftCube.CardIdentity("Tropical Island", "")); + cubeCards.add(new DraftCube.CardIdentity("True-Name Nemesis", "")); + cubeCards.add(new DraftCube.CardIdentity("Trygon Predator", "")); + cubeCards.add(new DraftCube.CardIdentity("Tundra", "")); + cubeCards.add(new DraftCube.CardIdentity("Turnabout", "")); + cubeCards.add(new DraftCube.CardIdentity("Ugin, the Spirit Dragon", "")); + cubeCards.add(new DraftCube.CardIdentity("Ulamog, the Ceaseless Hunger", "")); + cubeCards.add(new DraftCube.CardIdentity("Ulamog, the Infinite Gyre", "")); + cubeCards.add(new DraftCube.CardIdentity("Ultimate Price", "")); + cubeCards.add(new DraftCube.CardIdentity("Umezawa's Jitte", "")); + cubeCards.add(new DraftCube.CardIdentity("Unburial Rites", "")); + cubeCards.add(new DraftCube.CardIdentity("Underground Sea", "")); + cubeCards.add(new DraftCube.CardIdentity("Unexpectedly Absent", "")); + cubeCards.add(new DraftCube.CardIdentity("Upheaval", "")); + cubeCards.add(new DraftCube.CardIdentity("Urborg, Tomb of Yawgmoth", "")); + cubeCards.add(new DraftCube.CardIdentity("Vampire Nighthawk", "")); + cubeCards.add(new DraftCube.CardIdentity("Vampiric Tutor", "")); + cubeCards.add(new DraftCube.CardIdentity("Vedalken Shackles", "")); + cubeCards.add(new DraftCube.CardIdentity("Vendilion Clique", "")); + cubeCards.add(new DraftCube.CardIdentity("Venser, Shaper Savant", "")); + cubeCards.add(new DraftCube.CardIdentity("Verdant Catacombs", "")); + cubeCards.add(new DraftCube.CardIdentity("Verdurous Gearhulk", "")); + cubeCards.add(new DraftCube.CardIdentity("Villainous Wealth", "")); + cubeCards.add(new DraftCube.CardIdentity("Vindicate", "")); + cubeCards.add(new DraftCube.CardIdentity("Voice of Resurgence", "")); + cubeCards.add(new DraftCube.CardIdentity("Volcanic Island", "")); + cubeCards.add(new DraftCube.CardIdentity("Vryn Wingmare", "")); + cubeCards.add(new DraftCube.CardIdentity("Wall of Blossoms", "")); + cubeCards.add(new DraftCube.CardIdentity("Wall of Omens", "")); + cubeCards.add(new DraftCube.CardIdentity("Wall of Roots", "")); + cubeCards.add(new DraftCube.CardIdentity("Wandering Fumarole", "")); + cubeCards.add(new DraftCube.CardIdentity("War Priest of Thune", "")); + cubeCards.add(new DraftCube.CardIdentity("Wasteland", "")); + cubeCards.add(new DraftCube.CardIdentity("Watery Grave", "")); + cubeCards.add(new DraftCube.CardIdentity("Westvale Abbey", "")); + cubeCards.add(new DraftCube.CardIdentity("Wheel of Fortune", "")); + cubeCards.add(new DraftCube.CardIdentity("Wildfire", "")); + cubeCards.add(new DraftCube.CardIdentity("Windswept Heath", "")); + cubeCards.add(new DraftCube.CardIdentity("Winter Orb", "")); + cubeCards.add(new DraftCube.CardIdentity("Wolfir Silverheart", "")); + cubeCards.add(new DraftCube.CardIdentity("Wooded Foothills", "")); + cubeCards.add(new DraftCube.CardIdentity("Woodfall Primus", "")); + cubeCards.add(new DraftCube.CardIdentity("Worn Powerstone", "")); + cubeCards.add(new DraftCube.CardIdentity("Wrath of God", "")); + cubeCards.add(new DraftCube.CardIdentity("Wurmcoil Engine", "")); + cubeCards.add(new DraftCube.CardIdentity("Xenagos, the Reveler", "")); + cubeCards.add(new DraftCube.CardIdentity("Yavimaya Elder", "")); + cubeCards.add(new DraftCube.CardIdentity("Yawgmoth's Bargain", "")); + cubeCards.add(new DraftCube.CardIdentity("Yawgmoth's Will", "")); + cubeCards.add(new DraftCube.CardIdentity("Young Pyromancer", "")); + cubeCards.add(new DraftCube.CardIdentity("Zealous Conscripts", "")); + cubeCards.add(new DraftCube.CardIdentity("Zurgo Bellstriker", "")); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BorderlandExplorer.java b/Mage.Sets/src/mage/cards/b/BorderlandExplorer.java new file mode 100644 index 00000000000..73519045280 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BorderlandExplorer.java @@ -0,0 +1,168 @@ +/* + * 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.b; + +import java.util.HashMap; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterCard; +import mage.filter.common.FilterBasicLandCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetDiscard; + +/** + * + * @author fireshoes + */ +public class BorderlandExplorer extends CardImpl { + + public BorderlandExplorer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add("Elf"); + this.subtype.add("Scout"); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // When Borderland Explorer enters the battlefield, each player may discard a card. Each player who discarded a card this way may search his or her library + // for a basic land card, reveal it, put it into his or her hand, then shuffle his or her library. + this.addAbility(new EntersBattlefieldTriggeredAbility(new BorderlandExplorerEffect())); + } + + public BorderlandExplorer(final BorderlandExplorer card) { + super(card); + } + + @Override + public BorderlandExplorer copy() { + return new BorderlandExplorer(this); + } +} + +class BorderlandExplorerEffect extends OneShotEffect { + + public BorderlandExplorerEffect() { + super(Outcome.Neutral); + this.staticText = "each player may discard a card. Each player who discarded a card this way may search his or her library " + + "for a basic land card, reveal it, put it into his or her hand, then shuffle his or her library"; + } + + public BorderlandExplorerEffect(final BorderlandExplorerEffect effect) { + super(effect); + } + + @Override + public BorderlandExplorerEffect copy() { + return new BorderlandExplorerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + // Store for each player the cards to discard, that's important because all discard shall happen at the same time + HashMap cardsToDiscard = new HashMap<>(); + // Store for each player the lands to reveal, that's important because all reveals shall happen at the same time + HashMap cardsToReveal = new HashMap<>(); + if (controller != null) { + // choose cards to discard + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + Cards cards = new CardsImpl(); + Target target = new TargetDiscard(0, 1, new FilterCard(), playerId); + player.chooseTarget(outcome, target, source, game); + cards.addAll(target.getTargets()); + cardsToDiscard.put(playerId, cards); + } + } + // discard all chosen cards + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + Cards cardsPlayer = cardsToDiscard.get(playerId); + if (cardsPlayer != null) { + for (UUID cardId : cardsPlayer) { + Card card = game.getCard(cardId); + if (card != null) { + player.discard(card, source, game); + } + } + } + } + } + // search for a land for each player that discarded + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + Cards cardsPlayer = cardsToDiscard.get(playerId); + if (cardsPlayer != null) { + TargetCardInLibrary target = new TargetCardInLibrary(0, 1, new FilterBasicLandCard()); + if (player.searchLibrary(target, game)) { + if (target.getTargets().size() > 0) { + Cards cards = new CardsImpl(target.getTargets()); + cards.addAll(target.getTargets()); + cardsToReveal.put(playerId, cards); + } + } + } + } + } + // reveal the searched lands, put in hands, and shuffle + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + Cards cardsPlayer = cardsToReveal.get(playerId); + if (cardsPlayer != null) { + for (UUID cardId : cardsPlayer) { + Cards cards = new CardsImpl(game.getCard(cardId)); + Card card = game.getCard(cardId); + player.revealCards(card.getIdName() + " (" + player.getName() + ")", cards, game); + player.moveCardToHandWithInfo(card, source.getSourceId(), game); + player.shuffleLibrary(source, game); + } + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/y/YaheenisExpertise.java b/Mage.Sets/src/mage/cards/y/YaheenisExpertise.java new file mode 100644 index 00000000000..0c21a325020 --- /dev/null +++ b/Mage.Sets/src/mage/cards/y/YaheenisExpertise.java @@ -0,0 +1,124 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.y; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.Filter; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInHand; + +/** + * + * @author fireshoes + */ +public class YaheenisExpertise extends CardImpl { + + public YaheenisExpertise(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}{B}"); + + + // All creatures get -3/-3 until end of turn. + getSpellAbility().addEffect(new BoostAllEffect(-3, -3, Duration.EndOfTurn)); + + // You may cast a card with converted mana cost 3 or less from your hand without paying its mana cost. + getSpellAbility().addEffect(new YaheenisExpertiseCastEffect()); + } + + public YaheenisExpertise(final YaheenisExpertise card) { + super(card); + } + + @Override + public YaheenisExpertise copy() { + return new YaheenisExpertise(this); + } +} + +class YaheenisExpertiseCastEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterCard("card with converted mana cost 3 or less from your hand"); + + static { + filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.LessThan, 4)); + } + + public YaheenisExpertiseCastEffect() { + super(Outcome.PlayForFree); + this.staticText = "you may cast a card with converted mana cost 3 or less from your hand without paying its mana cost"; + } + + public YaheenisExpertiseCastEffect(final YaheenisExpertiseCastEffect effect) { + super(effect); + } + + @Override + public YaheenisExpertiseCastEffect copy() { + return new YaheenisExpertiseCastEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Target target = new TargetCardInHand(filter); + if (target.canChoose(source.getSourceId(), controller.getId(), game) && + controller.chooseUse(outcome, "Cast a card with converted mana cost 3 or less from your hand without paying its mana cost?", source, game)) { + Card cardToCast = null; + boolean cancel = false; + while (controller.canRespond() && !cancel) { + if (controller.chooseTarget(outcome, target, source, game)) { + cardToCast = game.getCard(target.getFirstTarget()); + if (cardToCast != null && cardToCast.getSpellAbility().canChooseTarget(game)) { + cancel = true; + } + } else { + cancel = true; + } + } + if (cardToCast != null) { + controller.cast(cardToCast.getSpellAbility(), game, true); + } + } + return true; + } + return false; + } +} From 3d95849c1071ed87357523b010f1ecc7ab32c175 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 7 Dec 2016 17:14:08 +0100 Subject: [PATCH 28/38] Some fixes to the Monarch designation. --- .../mage/card/arcane/CardPanelRenderImpl.java | 3 + .../plugins/card/utils/CardImageUtils.java | 6 +- Mage.Common/src/mage/view/CardView.java | 18 +- Mage.Common/src/mage/view/GameView.java | 9 + Mage/src/main/java/mage/MageInt.java | 2 +- .../mage/abilities/TriggeredAbilities.java | 9 + ...CombatDamageToAPlayerTriggeredAbility.java | 1 - .../MonarchIsSourceControllerCondition.java | 28 ++- .../common/BecomesMonarchTargetEffect.java | 44 ++++ Mage/src/main/java/mage/cards/FrameStyle.java | 21 +- .../java/mage/designations/Designation.java | 212 ++++++++++++++++++ .../main/java/mage/designations/Monarch.java | 152 +++++++++++++ Mage/src/main/java/mage/game/GameImpl.java | 15 +- Mage/src/main/java/mage/game/GameState.java | 17 ++ .../main/java/mage/players/PlayerImpl.java | 11 +- 15 files changed, 511 insertions(+), 37 deletions(-) create mode 100644 Mage/src/main/java/mage/abilities/effects/common/BecomesMonarchTargetEffect.java create mode 100644 Mage/src/main/java/mage/designations/Designation.java create mode 100644 Mage/src/main/java/mage/designations/Monarch.java diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderImpl.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderImpl.java index fdd49bb6b41..05bc713a8b4 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderImpl.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderImpl.java @@ -63,6 +63,9 @@ public class CardPanelRenderImpl extends CardPanel { if (!a.getRules().equals(b.getRules())) { return false; } + if (a.getRarity() == null || b.getRarity() == null) { + return false; + } if (!a.getRarity().equals(b.getRarity())) { return false; } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/utils/CardImageUtils.java b/Mage.Client/src/main/java/org/mage/plugins/card/utils/CardImageUtils.java index 3784205acd3..34a2ede8113 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/utils/CardImageUtils.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/utils/CardImageUtils.java @@ -42,7 +42,7 @@ public class CardImageUtils { return filePath; } } - log.warn("Token image file not found: " + card.getTokenSetCode() + " - " + card.getName()); + log.warn("Token image file not found: " + card.getSet() + " - " + card.getTokenSetCode() + " - " + card.getName()); return null; } @@ -117,7 +117,7 @@ public class CardImageUtils { return buildPath(imagesDir, set); } } - + public static String getImageBasePath() { String useDefault = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_USE_DEFAULT, "true"); String imagesPath = useDefault.equals("true") ? Constants.IO.imageBaseDir : PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PATH, null); @@ -126,7 +126,7 @@ public class CardImageUtils { } return imagesPath; } - + public static String getTokenBasePath() { String imagesPath = getImageBasePath(); diff --git a/Mage.Common/src/mage/view/CardView.java b/Mage.Common/src/mage/view/CardView.java index 190c68bf016..5413d844ac5 100644 --- a/Mage.Common/src/mage/view/CardView.java +++ b/Mage.Common/src/mage/view/CardView.java @@ -45,6 +45,7 @@ import mage.constants.Rarity; import mage.constants.Zone; import mage.counters.Counter; import mage.counters.CounterType; +import mage.designations.Designation; import mage.game.Game; import mage.game.command.Emblem; import mage.game.permanent.Permanent; @@ -138,8 +139,7 @@ public class CardView extends SimpleCardView { this(card, game, false); this.id = cardId; } - - + public CardView(CardView cardView) { super(cardView.id, cardView.expansionSetCode, cardView.cardNumber, cardView.usesVariousArt, cardView.tokenSetCode, cardView.gameObject, cardView.tokenDescriptor); @@ -488,6 +488,20 @@ public class CardView extends SimpleCardView { this.rarity = Rarity.COMMON; } + public CardView(Designation designation, StackAbility stackAbility) { + this(true); + this.gameObject = true; + this.id = designation.getId(); + this.mageObjectType = MageObjectType.NULL; + this.name = designation.getName(); + this.displayName = name; + this.rules = new ArrayList<>(); + this.rules.add(stackAbility.getRule(designation.getName())); + this.frameStyle = FrameStyle.M15_NORMAL; + this.expansionSetCode = designation.getExpansionSetCodeForImage(); + this.rarity = Rarity.COMMON; + } + public CardView(boolean empty) { super(null, "", "0", false, "", ""); if (!empty) { diff --git a/Mage.Common/src/mage/view/GameView.java b/Mage.Common/src/mage/view/GameView.java index 775fd2e099c..bc12e6cb692 100644 --- a/Mage.Common/src/mage/view/GameView.java +++ b/Mage.Common/src/mage/view/GameView.java @@ -40,6 +40,7 @@ import mage.constants.CardType; import mage.constants.PhaseStep; import mage.constants.TurnPhase; import mage.constants.Zone; +import mage.designations.Designation; import mage.game.ExileZone; import mage.game.Game; import mage.game.GameState; @@ -143,6 +144,14 @@ public class GameView implements Serializable { stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, object.getName(), cardView)); checkPaid(stackObject.getId(), ((StackAbility) stackObject)); + } else if (object instanceof Designation) { + Designation designation = (Designation) game.getObject(object.getId()); + if (designation != null) { + stack.put(stackObject.getId(), new CardView(designation, (StackAbility) stackObject)); + } else { + LOGGER.fatal("Designation object not found: " + object.getName() + " " + object.toString() + " " + object.getClass().toString()); + } + } else if (object instanceof StackAbility) { StackAbility stackAbility = ((StackAbility) object); stackAbility.newId(); diff --git a/Mage/src/main/java/mage/MageInt.java b/Mage/src/main/java/mage/MageInt.java index bb0fb75f820..73954ede007 100644 --- a/Mage/src/main/java/mage/MageInt.java +++ b/Mage/src/main/java/mage/MageInt.java @@ -32,7 +32,7 @@ import mage.util.Copyable; public class MageInt implements Serializable, Copyable { - public static MageInt EmptyMageInt = new MageInt(Integer.MIN_VALUE, null) { + public static MageInt EmptyMageInt = new MageInt(Integer.MIN_VALUE, "") { private static final String exceptionMessage = "MageInt.EmptyMageInt can't be modified."; diff --git a/Mage/src/main/java/mage/abilities/TriggeredAbilities.java b/Mage/src/main/java/mage/abilities/TriggeredAbilities.java index 967b22938e4..b9f6a179c0f 100644 --- a/Mage/src/main/java/mage/abilities/TriggeredAbilities.java +++ b/Mage/src/main/java/mage/abilities/TriggeredAbilities.java @@ -39,6 +39,7 @@ import java.util.concurrent.ConcurrentHashMap; import mage.MageObject; import mage.cards.Card; import mage.constants.Zone; +import mage.designations.Designation; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.NumberOfTriggersEvent; @@ -146,6 +147,8 @@ public class TriggeredAbilities extends ConcurrentHashMap uuidList = new LinkedList<>(); @@ -190,8 +193,14 @@ public class TriggeredAbilities extends ConcurrentHashMap keysToRemove = new ArrayList<>(); + Abilities: for (Entry entry : this.entrySet()) { if (game.getObject(entry.getValue().getSourceId()) == null) { + for (Designation designation : game.getState().getDesignations()) { + if (designation.getId().equals(entry.getValue().getSourceId())) { + continue Abilities; + } + } keysToRemove.add(entry.getKey()); } } diff --git a/Mage/src/main/java/mage/abilities/common/DealsCombatDamageToAPlayerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DealsCombatDamageToAPlayerTriggeredAbility.java index 43f94d113cc..c13f59afbbd 100644 --- a/Mage/src/main/java/mage/abilities/common/DealsCombatDamageToAPlayerTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DealsCombatDamageToAPlayerTriggeredAbility.java @@ -29,7 +29,6 @@ package mage.abilities.common; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; -import mage.constants.SetTargetPointer; import mage.constants.Zone; import mage.game.Game; import mage.game.events.DamagedPlayerEvent; diff --git a/Mage/src/main/java/mage/abilities/condition/common/MonarchIsSourceControllerCondition.java b/Mage/src/main/java/mage/abilities/condition/common/MonarchIsSourceControllerCondition.java index e94fa838f98..a7c6910f3b3 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/MonarchIsSourceControllerCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/MonarchIsSourceControllerCondition.java @@ -1,7 +1,29 @@ /* - * 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. +* 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; diff --git a/Mage/src/main/java/mage/abilities/effects/common/BecomesMonarchTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/BecomesMonarchTargetEffect.java new file mode 100644 index 00000000000..d4fe9ebeb68 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/BecomesMonarchTargetEffect.java @@ -0,0 +1,44 @@ +/* + * 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.effects.common; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author LevelX2 + */ +public class BecomesMonarchTargetEffect extends OneShotEffect { + + public BecomesMonarchTargetEffect() { + super(Outcome.Benefit); + staticText = "target player becomes the monarch"; + } + + public BecomesMonarchTargetEffect(final BecomesMonarchTargetEffect effect) { + super(effect); + } + + @Override + public BecomesMonarchTargetEffect copy() { + return new BecomesMonarchTargetEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (targetPlayer != null) { + game.setMonarchId(source, targetPlayer.getId()); + return true; + } + return false; + } + +} diff --git a/Mage/src/main/java/mage/cards/FrameStyle.java b/Mage/src/main/java/mage/cards/FrameStyle.java index 3a006b61cc3..add2795cc52 100644 --- a/Mage/src/main/java/mage/cards/FrameStyle.java +++ b/Mage/src/main/java/mage/cards/FrameStyle.java @@ -14,27 +14,22 @@ public enum FrameStyle { * The default card frame, normal M15 card frames */ M15_NORMAL(BorderType.M15, false), - /** * Battle for Zendkiar full art basic lands */ BFZ_FULL_ART_BASIC(BorderType.M15, true), - /** * Kaladesh block Inventions */ KLD_INVENTION(BorderType.M15, false), - /** * Zenkikar full art lands */ ZEN_FULL_ART_BASIC(BorderType.MOD, true), - /** * Unhinged full art lands */ UNH_FULL_ART_BASIC(BorderType.SPC, true), - /** * Unglued full art lands */ @@ -45,30 +40,26 @@ public enum FrameStyle { */ public enum BorderType { /** - * Various specialty borders - * EG: Unhinged, Unglued + * Various specialty borders EG: Unhinged, Unglued */ SPC, - /** * Old border cards */ OLD, - /** * Modern border cards (8th -> Theros) */ MOD, - /** * M15 border cards (M14 -> current) */ M15 } - - private BorderType borderType; - private boolean isFullArt; - + + private final BorderType borderType; + private final boolean isFullArt; + public BorderType getBorderType() { return borderType; } @@ -76,7 +67,7 @@ public enum FrameStyle { public boolean isFullArt() { return isFullArt; } - + FrameStyle(BorderType borderType, boolean isFullArt) { this.borderType = borderType; this.isFullArt = isFullArt; diff --git a/Mage/src/main/java/mage/designations/Designation.java b/Mage/src/main/java/mage/designations/Designation.java new file mode 100644 index 00000000000..ecf203ff47d --- /dev/null +++ b/Mage/src/main/java/mage/designations/Designation.java @@ -0,0 +1,212 @@ +/* + * 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.designations; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.ObjectColor; +import mage.abilities.Abilities; +import mage.abilities.AbilitiesImpl; +import mage.abilities.Ability; +import mage.abilities.costs.mana.ManaCost; +import mage.abilities.costs.mana.ManaCosts; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.cards.FrameStyle; +import mage.constants.CardType; +import mage.game.Game; +import mage.game.events.ZoneChangeEvent; +import mage.util.GameLog; + +/** + * + * @author LevelX2 + */ +public abstract class Designation implements MageObject { + + private static List emptyList = new ArrayList(); + private static ObjectColor emptyColor = new ObjectColor(); + private static ManaCosts emptyCost = new ManaCostsImpl(); + + private String name; + private UUID id; + private FrameStyle frameStyle; + private Abilities abilites = new AbilitiesImpl<>(); + private String expansionSetCodeForImage; + + public Designation(String name, String expansionSetCode) { + this.name = name; + this.id = UUID.randomUUID(); + this.frameStyle = FrameStyle.M15_NORMAL; + this.expansionSetCodeForImage = expansionSetCode; + } + + public Designation(final Designation designation) { + this.id = designation.id; + this.name = designation.name; + this.frameStyle = designation.frameStyle; + this.abilites = designation.abilites.copy(); + } + + public abstract void start(Game game, UUID controllerId); + + @Override + public FrameStyle getFrameStyle() { + return frameStyle; + } + + public void assignNewId() { + this.id = UUID.randomUUID(); + } + + @Override + public String getName() { + return name; + } + + @Override + public String getIdName() { + return getName() + " [" + getId().toString().substring(0, 3) + "]"; + } + + @Override + public String getImageName() { + return this.name; + } + + @Override + public void setName(String name) { + this.name = name; + } + + public void addAbility(Ability ability) { + ability.setSourceId(id); + abilites.add(ability); + } + + @Override + public Abilities getAbilities() { + return abilites; + } + + @Override + public ObjectColor getFrameColor(Game game) { + return emptyColor; + } + + @Override + public UUID getId() { + return this.id; + } + + public void setExpansionSetCodeForImage(String expansionSetCodeForImage) { + this.expansionSetCodeForImage = expansionSetCodeForImage; + } + + public String getExpansionSetCodeForImage() { + return expansionSetCodeForImage; + } + + @Override + public String getLogName() { + return GameLog.getColoredObjectIdName(this); + } + + @Override + public List getCardType() { + return emptyList; + } + + @Override + public List getSubtype(Game game) { + return emptyList; + } + + @Override + public boolean hasSubtype(String subtype, Game game) { + return false; + } + + @Override + public List getSupertype() { + return emptyList; + } + + @Override + public boolean hasAbility(UUID abilityId, Game game) { + return abilites.containsKey(abilityId); + } + + @Override + public ObjectColor getColor(Game game) { + return emptyColor; + } + + @Override + public ManaCosts getManaCost() { + return emptyCost; + } + + @Override + public int getConvertedManaCost() { + return 0; + } + + @Override + public MageInt getPower() { + return MageInt.EmptyMageInt; + } + + @Override + public MageInt getToughness() { + return MageInt.EmptyMageInt; + } + + @Override + public int getStartingLoyalty() { + return 0; + } + + @Override + public void adjustCosts(Ability ability, Game game) { + } + + @Override + public void adjustTargets(Ability ability, Game game) { + } + + @Override + public void setCopy(boolean isCopy) { + } + + @Override + public boolean isCopy() { + return false; + } + + @Override + public Designation copy() { + return this; + } + + @Override + public int getZoneChangeCounter(Game game) { + return 1; // Emblems can't move zones until now so return always 1 + } + + @Override + public void updateZoneChangeCounter(Game game, ZoneChangeEvent event) { + throw new UnsupportedOperationException("Unsupported operation"); + } + + @Override + public void setZoneChangeCounter(int value, Game game) { + throw new UnsupportedOperationException("Unsupported operation"); + } + +} diff --git a/Mage/src/main/java/mage/designations/Monarch.java b/Mage/src/main/java/mage/designations/Monarch.java new file mode 100644 index 00000000000..1277945e439 --- /dev/null +++ b/Mage/src/main/java/mage/designations/Monarch.java @@ -0,0 +1,152 @@ +/* +* 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.designations; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.effects.common.BecomesMonarchTargetEffect; +import mage.abilities.effects.common.DrawCardTargetEffect; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.DamagedPlayerEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author LevelX2 + */ +public class Monarch extends Designation { + + public Monarch() { + super("The Monarch", "CN2"); + addAbility(new MonarchDrawTriggeredAbility()); + addAbility(new MonarchDealsCombatDamageToAPlayerTriggeredAbility()); + } + + /** + * + * @param game + * @param controllerId + */ + @Override + public void start(Game game, UUID controllerId) { + + } + +} + +// At the beginning of the monarch’s end step, that player draws a card +class MonarchDrawTriggeredAbility extends BeginningOfEndStepTriggeredAbility { + + public MonarchDrawTriggeredAbility() { + super(Zone.ALL, new DrawCardTargetEffect(1), TargetController.ANY, null, false); + } + + public MonarchDrawTriggeredAbility(final MonarchDrawTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (game.getMonarchId() != null && event.getPlayerId().equals(game.getMonarchId())) { + setControllerId(game.getMonarchId()); + getEffects().get(0).setTargetPointer(new FixedTarget(game.getMonarchId())); + return true; + } + return false; + } + + @Override + public MonarchDrawTriggeredAbility copy() { + return new MonarchDrawTriggeredAbility(this); + } + + @Override + public boolean isInUseableZone(Game game, MageObject source, GameEvent event) { + return true; + } + + @Override + public String getRule() { + return "At the beginning of the monarch’s end step, that player draws a card."; + } +} + +// Whenever a creature deals combat damage to the monarch, its controller becomes the monarch. +class MonarchDealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbilityImpl { + + public MonarchDealsCombatDamageToAPlayerTriggeredAbility() { + super(Zone.ALL, new BecomesMonarchTargetEffect(), false); + } + + public MonarchDealsCombatDamageToAPlayerTriggeredAbility(final MonarchDealsCombatDamageToAPlayerTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (((DamagedPlayerEvent) event).isCombatDamage()) { + MageObject damagingObject = game.getObject(event.getSourceId()); + if (damagingObject != null + && damagingObject instanceof Permanent + && damagingObject.getCardType().contains(CardType.CREATURE) + && event.getTargetId().equals(game.getMonarchId())) { + setControllerId(event.getPlayerId()); + getEffects().get(0).setTargetPointer(new FixedTarget(((Permanent) damagingObject).getControllerId())); + return true; + } + } + return false; + } + + @Override + public MonarchDealsCombatDamageToAPlayerTriggeredAbility copy() { + return new MonarchDealsCombatDamageToAPlayerTriggeredAbility(this); + } + + @Override + public boolean isInUseableZone(Game game, MageObject source, GameEvent event) { + return true; + } + + @Override + public String getRule() { + return "Whenever a creature deals combat damage to the monarch, its controller becomes the monarch."; + } +} diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index df561aea631..8425f4b4d4a 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -81,6 +81,8 @@ import mage.constants.SpellAbilityType; import mage.constants.Zone; import mage.counters.CounterType; import mage.counters.Counters; +import mage.designations.Designation; +import mage.designations.Monarch; import mage.filter.Filter; import mage.filter.FilterCard; import mage.filter.FilterPermanent; @@ -385,11 +387,11 @@ public abstract class GameImpl implements Game, Serializable { object = getCard(objectId); if (object == null) { -// for (CommandObject commandObject : state.getCommand()) { -// if (commandObject.getId().equals(objectId)) { -// return commandObject; -// } -// } + for (Designation designation : state.getDesignations()) { + if (designation.getId().equals(objectId)) { + return designation; + } + } // can be an ability of a sacrificed Token trying to get it's source object object = getLastKnownInformation(objectId, Zone.BATTLEFIELD); } @@ -2916,6 +2918,9 @@ public abstract class GameImpl implements Game, Serializable { @Override public void setMonarchId(Ability source, UUID monarchId) { Player newMonarch = getPlayer(monarchId); + if (getMonarchId() == null) { + getState().addDesignation(new Monarch(), this, monarchId); + } if (newMonarch != null) { getState().setMonarchId(monarchId); informPlayers(newMonarch.getLogName() + " is the monarch"); diff --git a/Mage/src/main/java/mage/game/GameState.java b/Mage/src/main/java/mage/game/GameState.java index 47e113e3044..6b42e627eac 100644 --- a/Mage/src/main/java/mage/game/GameState.java +++ b/Mage/src/main/java/mage/game/GameState.java @@ -58,6 +58,7 @@ import mage.abilities.effects.Effect; import mage.cards.Card; import mage.cards.SplitCard; import mage.constants.Zone; +import mage.designations.Designation; import mage.game.combat.Combat; import mage.game.combat.CombatGroup; import mage.game.command.Command; @@ -113,6 +114,7 @@ public class GameState implements Serializable, Copyable { private UUID monarchId; // player that is the monarch private SpellStack stack; private Command command; + private List designations = new ArrayList<>(); private Exile exile; private Battlefield battlefield; private int turnNum = 1; @@ -170,6 +172,7 @@ public class GameState implements Serializable, Copyable { this.stack = state.stack.copy(); this.command = state.command.copy(); + this.designations.addAll(state.designations); this.exile = state.exile.copy(); this.battlefield = state.battlefield.copy(); this.turnNum = state.turnNum; @@ -219,6 +222,7 @@ public class GameState implements Serializable, Copyable { this.monarchId = state.monarchId; this.stack = state.stack; this.command = state.command; + this.designations = state.designations; this.exile = state.exile; this.battlefield = state.battlefield; this.turnNum = state.turnNum; @@ -461,6 +465,10 @@ public class GameState implements Serializable, Copyable { return exile; } + public List getDesignations() { + return designations; + } + public Command getCommand() { return command; } @@ -859,6 +867,14 @@ public class GameState implements Serializable, Copyable { } } + public void addDesignation(Designation designation, Game game, UUID controllerId) { + getDesignations().add(designation); + for (Ability ability : designation.getAbilities()) { + ability.setControllerId(controllerId); + addAbility(ability, designation.getId(), null); + } + } + public void addCommandObject(CommandObject commandObject) { getCommand().add(commandObject); setZone(commandObject.getId(), Zone.COMMAND); @@ -1026,6 +1042,7 @@ public class GameState implements Serializable, Copyable { stack.clear(); exile.clear(); command.clear(); + designations.clear(); revealed.clear(); lookedAt.clear(); turnNum = 0; diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index dd0ccecaa07..86f053fa9d0 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -1231,14 +1231,14 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean triggerAbility(TriggeredAbility source, Game game) { - if (source == null) { + public boolean triggerAbility(TriggeredAbility triggeredAbility, Game game) { + if (triggeredAbility == null) { logger.warn("Null source in triggerAbility method"); throw new IllegalArgumentException("source TriggeredAbility must not be null"); } //20091005 - 603.3c, 603.3d int bookmark = game.bookmarkState(); - TriggeredAbility ability = source.copy(); + TriggeredAbility ability = triggeredAbility.copy(); MageObject sourceObject = ability.getSourceObject(game); if (sourceObject != null) { sourceObject.adjustTargets(ability, game); @@ -1260,7 +1260,7 @@ public abstract class PlayerImpl implements Player, Serializable { return true; } } - restoreState(bookmark, source.getRule(), game); // why restore is needed here? (to remove the triggered ability from the stack) + restoreState(bookmark, triggeredAbility.getRule(), game); // why restore is needed here? (to remove the triggered ability from the stack) return false; } @@ -1829,9 +1829,6 @@ public abstract class PlayerImpl implements Player, Serializable { if (sourceAbilities != null && sourceAbilities.containsKey(InfectAbility.getInstance().getId())) { addCounters(CounterType.POISON.createInstance(actualDamage), game); } else { - if (getId().equals(game.getMonarchId()) && sourceControllerId != null) { - game.setMonarchId(null, sourceControllerId); - } GameEvent damageToLifeLossEvent = new GameEvent(EventType.DAMAGE_CAUSES_LIFE_LOSS, playerId, sourceId, playerId, actualDamage, combatDamage); if (!game.replaceEvent(damageToLifeLossEvent)) { this.loseLife(damageToLifeLossEvent.getAmount(), game, combatDamage); From ed829a792fa6e64dde2f82d9fd2b409a603429af Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 7 Dec 2016 17:47:57 +0100 Subject: [PATCH 29/38] * Ephara, God of thePolis - Fixed that the draw effect was applied to the active player. --- Mage.Sets/src/mage/cards/e/EpharaGodOfThePolis.java | 2 +- Mage.Sets/src/mage/cards/o/Ophiomancer.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/cards/e/EpharaGodOfThePolis.java b/Mage.Sets/src/mage/cards/e/EpharaGodOfThePolis.java index 4bbee99f28d..363b9184176 100644 --- a/Mage.Sets/src/mage/cards/e/EpharaGodOfThePolis.java +++ b/Mage.Sets/src/mage/cards/e/EpharaGodOfThePolis.java @@ -71,7 +71,7 @@ public class EpharaGodOfThePolis extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); // At the beginning of each upkeep, if you had another creature enter the battlefield under your control last turn, draw a card. this.addAbility(new ConditionalTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), TargetController.ANY, false), + new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), TargetController.ANY, false, false), HadAnotherCreatureEnterTheBattlefieldCondition.getInstance(), "At the beginning of each upkeep, if you had another creature enter the battlefield under your control last turn, draw a card."), new PermanentsEnteredBattlefieldWatcher()); diff --git a/Mage.Sets/src/mage/cards/o/Ophiomancer.java b/Mage.Sets/src/mage/cards/o/Ophiomancer.java index ddf9e606cab..9cd6cab47d1 100644 --- a/Mage.Sets/src/mage/cards/o/Ophiomancer.java +++ b/Mage.Sets/src/mage/cards/o/Ophiomancer.java @@ -49,7 +49,7 @@ import mage.game.permanent.token.Token; public class Ophiomancer extends CardImpl { public Ophiomancer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.subtype.add("Human"); this.subtype.add("Shaman"); @@ -58,7 +58,7 @@ public class Ophiomancer extends CardImpl { // At the beginning of each upkeep, if you control no Snakes, create a 1/1 black Snake creature token with deathtouch. this.addAbility(new ConditionalTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new OphiomancerSnakeToken()), TargetController.ANY, false), + new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new OphiomancerSnakeToken()), TargetController.ANY, false, false), new PermanentsOnTheBattlefieldCondition(new FilterCreaturePermanent("Snake", "no Snakes"), PermanentsOnTheBattlefieldCondition.CountType.EQUAL_TO, 0), "At the beginning of each upkeep, if you control no Snakes, create a 1/1 black Snake creature token with deathtouch.")); } From 7d673519213801042bad479111ddb8382691acf1 Mon Sep 17 00:00:00 2001 From: spjspj Date: Thu, 8 Dec 2016 10:29:37 +1100 Subject: [PATCH 30/38] spjspj - More updates to edh Power Level. --- .../src/mage/deck/Commander.java | 55 ++++++++++++++++--- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java index 2273473b938..e38a34da7c8 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java @@ -211,6 +211,8 @@ public class Commander extends Constructed { } int edhPowerLevel = 0; + int numberInfinitePieces = 0; + for (Card card : deck.getCards()) { int thisMaxPower = 0; @@ -223,6 +225,7 @@ public class Commander extends Constructed { boolean cantBe = false; boolean copy = false; boolean costLessEach = false; + boolean dredge = false; boolean exile = false; boolean exileAll = false; boolean counter = false; @@ -232,11 +235,14 @@ public class Commander extends Constructed { boolean exalted = false; boolean doesntUntap = false; boolean drawCards = false; + boolean evoke = false; boolean extraTurns = false; + boolean flicker = false; boolean gainControl = false; boolean hexproof = false; boolean infect = false; boolean mayCastForFree = false; + boolean menace = false; boolean miracle = false; boolean overload = false; boolean persist = false; @@ -244,6 +250,7 @@ public class Commander extends Constructed { boolean protection = false; boolean putUnderYourControl = false; boolean retrace = false; + boolean returnFromYourGY = false; boolean sacrifice = false; boolean shroud = false; boolean skip = false; @@ -251,9 +258,11 @@ public class Commander extends Constructed { boolean storm = false; boolean trample = false; boolean tutor = false; + boolean twiceAs = false; boolean unblockable = false; boolean undying = false; boolean wheneverEnters = false; + boolean whenCounterThatSpell = false; boolean youControlTarget = false; for (String str : card.getRules()) { @@ -271,15 +280,19 @@ public class Commander extends Constructed { doesntUntap |= s.contains("doesn't untap"); doesntUntap |= s.contains("don't untap"); drawCards |= s.contains("draw cards"); + dredge |= s.contains("dredge"); each |= s.contains("each"); + evoke |= s.contains("evoke"); exalted |= s.contains("exalted"); exile |= s.contains("exile"); exileAll |= s.contains("exile") && s.contains(" all "); extraTurns |= s.contains("extra turn"); + flicker |= s.contains("exile") && s.contains("return") && s.contains("to the battlefield under"); gainControl |= s.contains("gain control"); hexproof |= s.contains("hexproof"); infect |= s.contains("infect"); mayCastForFree |= s.contains("may cast") && s.contains("without paying"); + menace |= s.contains("menace"); miracle |= s.contains("miracle"); overload |= s.contains("overload"); persist |= s.contains("persist"); @@ -287,6 +300,7 @@ public class Commander extends Constructed { protection |= s.contains("protection"); putUnderYourControl |= s.contains("put") && s.contains("under your control"); retrace |= s.contains("retrace"); + returnFromYourGY |= s.contains("return") && s.contains("from your graveyard"); sacrifice |= s.contains("sacrifice"); shroud |= s.contains("shroud"); skip |= s.contains("skip"); @@ -294,8 +308,10 @@ public class Commander extends Constructed { storm |= s.contains("storm"); trample |= s.contains("trample"); tutor |= s.contains("search your library"); + twiceAs |= s.contains("twice that many") || s.contains("twice as much"); unblockable |= s.contains("can't be blocked"); undying |= s.contains("undying"); + whenCounterThatSpell |= s.contains("when") && s.contains("counter that spell"); wheneverEnters |= s.contains("when") && s.contains("another") && s.contains("enters"); youControlTarget |= s.contains("you control target"); } @@ -321,6 +337,9 @@ public class Commander extends Constructed { if (overload) { thisMaxPower = Math.max(thisMaxPower, 5); } + if (twiceAs) { + thisMaxPower = Math.max(thisMaxPower, 5); + } if (cascade) { thisMaxPower = Math.max(thisMaxPower, 4); } @@ -333,6 +352,9 @@ public class Commander extends Constructed { if (exileAll) { thisMaxPower = Math.max(thisMaxPower, 4); } + if (flicker) { + thisMaxPower = Math.max(thisMaxPower, 4); + } if (gainControl) { thisMaxPower = Math.max(thisMaxPower, 4); } @@ -347,7 +369,10 @@ public class Commander extends Constructed { } if (putUnderYourControl) { thisMaxPower = Math.max(thisMaxPower, 4); - } + } + if (returnFromYourGY) { + thisMaxPower = Math.max(thisMaxPower, 4); + } if (skip) { thisMaxPower = Math.max(thisMaxPower, 4); } @@ -357,6 +382,9 @@ public class Commander extends Constructed { if (unblockable) { thisMaxPower = Math.max(thisMaxPower, 4); } + if (whenCounterThatSpell) { + thisMaxPower = Math.max(thisMaxPower, 4); + } if (wheneverEnters) { thisMaxPower = Math.max(thisMaxPower, 4); } @@ -369,6 +397,9 @@ public class Commander extends Constructed { if (destroyAll) { thisMaxPower = Math.max(thisMaxPower, 3); } + if (dredge) { + thisMaxPower = Math.max(thisMaxPower, 3); + } if (hexproof) { thisMaxPower = Math.max(thisMaxPower, 3); } @@ -384,9 +415,15 @@ public class Commander extends Constructed { if (cantBe) { thisMaxPower = Math.max(thisMaxPower, 2); } + if (evoke) { + thisMaxPower = Math.max(thisMaxPower, 2); + } if (exile) { thisMaxPower = Math.max(thisMaxPower, 2); } + if (menace) { + thisMaxPower = Math.max(thisMaxPower, 2); + } if (miracle) { thisMaxPower = Math.max(thisMaxPower, 2); } @@ -421,12 +458,12 @@ public class Commander extends Constructed { // Planeswalkers if (card.getCardType().contains(CardType.PLANESWALKER)) { if (card.getName().toLowerCase().equals("jace, the mind sculptor")) { - thisMaxPower = Math.max(thisMaxPower, 5); + thisMaxPower = Math.max(thisMaxPower, 6); } if (card.getName().toLowerCase().equals("ugin, the spirit dragon")) { - thisMaxPower = Math.max(thisMaxPower, 4); + thisMaxPower = Math.max(thisMaxPower, 5); } - thisMaxPower = Math.max(thisMaxPower, 3); + thisMaxPower = Math.max(thisMaxPower, 4); } if (card.getCardType().contains(CardType.LAND)) { @@ -521,12 +558,14 @@ public class Commander extends Constructed { || cn.equals("basalt monolith") || cn.equals("brago, king eternal") || cn.equals("candelabra of tawnos") || cn.equals("cephalid aristocrat") || cn.equals("cephalid illusionist") || cn.equals("changeling berserker") + || cn.equals("the chain veil") || cn.equals("cinderhaze wretch") || cn.equals("cryptic gateway") || cn.equals("deadeye navigator") || cn.equals("derevi, empyrial tactician") || cn.equals("doubling season") || cn.equals("dross scorpion") || cn.equals("earthcraft") || cn.equals("erratic portal") || cn.equals("enter the infinite") || cn.equals("omniscience") || cn.equals("exquisite blood") || cn.equals("future sight") + || cn.equals("ghave, guru of spores") || cn.equals("grave titan") || cn.equals("great whale") || cn.equals("grim monolith") || cn.equals("gush") || cn.equals("hellkite charger") || cn.equals("intruder alarm") @@ -559,6 +598,7 @@ public class Commander extends Constructed { || cn.equals("worthy cause") || cn.equals("yawgmoth's will") || cn.equals("zealous conscripts")) { thisMaxPower = Math.max(thisMaxPower, 7); + numberInfinitePieces ++; } edhPowerLevel += thisMaxPower; } @@ -593,7 +633,7 @@ public class Commander extends Constructed { || cn.equals("sheoldred, whispering one") || cn.equals("teferi, mage of zhalfir") || cn.equals("zur the enchanter")) { - thisMaxPower = Math.max(thisMaxPower, 15); + thisMaxPower = Math.max(thisMaxPower, 25); } // Next least fun commanders @@ -611,12 +651,13 @@ public class Commander extends Constructed { || cn.equals("sen triplets") || cn.equals("urabrask the hidden") || cn.equals("vorinclex, voice of hunger")) { - thisMaxPower = Math.max(thisMaxPower, 10); + thisMaxPower = Math.max(thisMaxPower, 15); } edhPowerLevel += thisMaxPower; } - edhPowerLevel = (int) Math.round(edhPowerLevel / 2.5); + edhPowerLevel += numberInfinitePieces * 10; + edhPowerLevel = (int) Math.round(edhPowerLevel / 3.5); if (edhPowerLevel > 100) { edhPowerLevel = 100; } From a5c677f72acb41c96e384cb373791bf1929ecbb9 Mon Sep 17 00:00:00 2001 From: spjspj Date: Thu, 8 Dec 2016 10:54:45 +1100 Subject: [PATCH 31/38] spjspj - More updates to edh Power Level. --- .../Mage.Deck.Constructed/src/mage/deck/Commander.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java index e38a34da7c8..44ba78fcbd0 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java @@ -225,6 +225,7 @@ public class Commander extends Constructed { boolean cantBe = false; boolean copy = false; boolean costLessEach = false; + boolean createToken = false; boolean dredge = false; boolean exile = false; boolean exileAll = false; @@ -275,6 +276,7 @@ public class Commander extends Constructed { copy |= s.contains("copy"); costLessEach |= s.contains("cost") || s.contains("less") || s.contains("each"); counter |= s.contains("counter") && s.contains("target"); + createToken |= s.contains("create") && s.contains("token"); destroy |= s.contains("destroy"); destroyAll |= s.contains("destroy all"); doesntUntap |= s.contains("doesn't untap"); @@ -394,6 +396,9 @@ public class Commander extends Constructed { if (anyNumberOfTarget) { thisMaxPower = Math.max(thisMaxPower, 3); } + if (createToken) { + thisMaxPower = Math.max(thisMaxPower, 3); + } if (destroyAll) { thisMaxPower = Math.max(thisMaxPower, 3); } From 9caaf0d5be6398972a2d9a0b96fd72bfb5826439 Mon Sep 17 00:00:00 2001 From: spjspj Date: Thu, 8 Dec 2016 11:57:45 +1100 Subject: [PATCH 32/38] spjspj - Final update to edh Power Level. --- .../src/mage/deck/Commander.java | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java index 44ba78fcbd0..66da5a90c57 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java @@ -32,7 +32,9 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import mage.abilities.Ability; import mage.abilities.common.CanBeYourCommanderAbility; +import mage.abilities.costs.mana.ManaCost; import mage.abilities.keyword.PartnerAbility; import mage.cards.Card; import mage.cards.ExpansionSet; @@ -212,7 +214,7 @@ public class Commander extends Constructed { int edhPowerLevel = 0; int numberInfinitePieces = 0; - + for (Card card : deck.getCards()) { int thisMaxPower = 0; @@ -262,8 +264,10 @@ public class Commander extends Constructed { boolean twiceAs = false; boolean unblockable = false; boolean undying = false; + boolean untapTarget = false; boolean wheneverEnters = false; boolean whenCounterThatSpell = false; + boolean xCost = false; boolean youControlTarget = false; for (String str : card.getRules()) { @@ -313,11 +317,25 @@ public class Commander extends Constructed { twiceAs |= s.contains("twice that many") || s.contains("twice as much"); unblockable |= s.contains("can't be blocked"); undying |= s.contains("undying"); + untapTarget |= s.contains("untap target"); whenCounterThatSpell |= s.contains("when") && s.contains("counter that spell"); wheneverEnters |= s.contains("when") && s.contains("another") && s.contains("enters"); youControlTarget |= s.contains("you control target"); } + for (ManaCost cost : card.getManaCost()) { + if (cost.getText().contains("X")) { + xCost = true; + } + } + for (Ability a : card.getAbilities()) { + for (ManaCost cost : a.getManaCosts()) { + if (cost.getText().contains("X")) { + xCost = true; + } + } + } + if (extraTurns) { thisMaxPower = Math.max(thisMaxPower, 7); } @@ -390,6 +408,9 @@ public class Commander extends Constructed { if (wheneverEnters) { thisMaxPower = Math.max(thisMaxPower, 4); } + if (xCost) { + thisMaxPower = Math.max(thisMaxPower, 4); + } if (youControlTarget) { thisMaxPower = Math.max(thisMaxPower, 4); } @@ -438,6 +459,9 @@ public class Commander extends Constructed { if (sacrifice) { thisMaxPower = Math.max(thisMaxPower, 2); } + if (untapTarget) { + thisMaxPower = Math.max(thisMaxPower, 2); + } if (copy) { thisMaxPower = Math.max(thisMaxPower, 1); } @@ -603,7 +627,7 @@ public class Commander extends Constructed { || cn.equals("worthy cause") || cn.equals("yawgmoth's will") || cn.equals("zealous conscripts")) { thisMaxPower = Math.max(thisMaxPower, 7); - numberInfinitePieces ++; + numberInfinitePieces++; } edhPowerLevel += thisMaxPower; } @@ -662,7 +686,7 @@ public class Commander extends Constructed { } edhPowerLevel += numberInfinitePieces * 10; - edhPowerLevel = (int) Math.round(edhPowerLevel / 3.5); + edhPowerLevel = (int) Math.round(edhPowerLevel / 4.5); if (edhPowerLevel > 100) { edhPowerLevel = 100; } From cc6e67a0d4c2a5e2ffc01ecd9268adfcc610a754 Mon Sep 17 00:00:00 2001 From: JRHerlehy Date: Wed, 7 Dec 2016 18:52:42 -0800 Subject: [PATCH 33/38] Fix for Trench Wurm --- Mage.Sets/src/mage/cards/t/TrenchWurm.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/cards/t/TrenchWurm.java b/Mage.Sets/src/mage/cards/t/TrenchWurm.java index 9d86f4cdc59..5b1cc8c497d 100644 --- a/Mage.Sets/src/mage/cards/t/TrenchWurm.java +++ b/Mage.Sets/src/mage/cards/t/TrenchWurm.java @@ -27,10 +27,10 @@ */ package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; @@ -39,6 +39,8 @@ import mage.constants.CardType; import mage.constants.Zone; import mage.target.common.TargetNonBasicLandPermanent; +import java.util.UUID; + /** * * @author michael.napoleon@gmail.com @@ -54,6 +56,7 @@ public class TrenchWurm extends CardImpl { // {2}{R}, {tap}: Destroy target nonbasic land. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new ManaCostsImpl("{2}{R}")); ability.addTarget(new TargetNonBasicLandPermanent()); + ability.addCost(new TapSourceCost()); this.addAbility(ability); } From 8680ab212fb429b98111ee4473f4e73bfcf9cd46 Mon Sep 17 00:00:00 2001 From: spjspj Date: Thu, 8 Dec 2016 17:08:10 +1100 Subject: [PATCH 34/38] spjspj - Final.. update to edh Power Level. --- .../src/mage/deck/Commander.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java index 66da5a90c57..1d35210ae5e 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java @@ -249,6 +249,7 @@ public class Commander extends Constructed { boolean miracle = false; boolean overload = false; boolean persist = false; + boolean preventDamage = false; boolean proliferate = false; boolean protection = false; boolean putUnderYourControl = false; @@ -261,6 +262,7 @@ public class Commander extends Constructed { boolean storm = false; boolean trample = false; boolean tutor = false; + boolean tutorBasic = false; boolean twiceAs = false; boolean unblockable = false; boolean undying = false; @@ -302,7 +304,8 @@ public class Commander extends Constructed { miracle |= s.contains("miracle"); overload |= s.contains("overload"); persist |= s.contains("persist"); - proliferate |= s.contains("proliferate"); + preventDamage |= s.contains("prevent") && s.contains("all") && s.contains("damage"); + proliferate |= s.contains("proliferate"); protection |= s.contains("protection"); putUnderYourControl |= s.contains("put") && s.contains("under your control"); retrace |= s.contains("retrace"); @@ -313,7 +316,8 @@ public class Commander extends Constructed { sliver |= s.contains("sliver"); storm |= s.contains("storm"); trample |= s.contains("trample"); - tutor |= s.contains("search your library"); + tutor |= s.contains("search your library") && !s.contains("basic land"); + tutorBasic |= s.contains("search your library") && s.contains("basic land"); twiceAs |= s.contains("twice that many") || s.contains("twice as much"); unblockable |= s.contains("can't be blocked"); undying |= s.contains("undying"); @@ -381,6 +385,9 @@ public class Commander extends Constructed { if (mayCastForFree) { thisMaxPower = Math.max(thisMaxPower, 4); } + if (preventDamage) { + thisMaxPower = Math.max(thisMaxPower, 4); + } if (proliferate) { thisMaxPower = Math.max(thisMaxPower, 4); } @@ -483,6 +490,9 @@ public class Commander extends Constructed { if (trample) { thisMaxPower = Math.max(thisMaxPower, 1); } + if (tutorBasic) { + thisMaxPower = Math.max(thisMaxPower, 1); + } // Planeswalkers if (card.getCardType().contains(CardType.PLANESWALKER)) { From c4ec832717327e896ae974de1d370c19c75ea68c Mon Sep 17 00:00:00 2001 From: "ludwig.hirth" Date: Thu, 8 Dec 2016 16:51:05 +0100 Subject: [PATCH 35/38] =?UTF-8?q?*=20Obzedat,=20Ghost=20Council=20&=20S?= =?UTF-8?q?=C3=A9ance=20-=20Fixed=20problems=20that=20the=20effects=20did?= =?UTF-8?q?=20nor=20work=20correctly=20if=20the=20move=20to=20exile=20was?= =?UTF-8?q?=20replaced=20(e.g.=20when=20a=20commander=20goes=20to=20comman?= =?UTF-8?q?d=20zone=20instead).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/mage/cards/o/ObzedatGhostCouncil.java | 14 ++++++------- Mage.Sets/src/mage/cards/s/Seance.java | 21 +++++++++---------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/Mage.Sets/src/mage/cards/o/ObzedatGhostCouncil.java b/Mage.Sets/src/mage/cards/o/ObzedatGhostCouncil.java index 1ace8136d5c..19a2581e677 100644 --- a/Mage.Sets/src/mage/cards/o/ObzedatGhostCouncil.java +++ b/Mage.Sets/src/mage/cards/o/ObzedatGhostCouncil.java @@ -49,7 +49,6 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.TargetController; import mage.constants.Zone; -import mage.game.ExileZone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; @@ -64,7 +63,7 @@ import mage.target.common.TargetOpponent; public class ObzedatGhostCouncil extends CardImpl { public ObzedatGhostCouncil(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}{W}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}{B}{B}"); this.subtype.add("Spirit"); this.subtype.add("Advisor"); this.supertype.add("Legendary"); @@ -175,14 +174,15 @@ class ObzedatGhostCouncilReturnEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Card card = game.getCard(source.getSourceId()); if (card != null) { - ExileZone currentZone = game.getState().getExile().getExileZone(source.getSourceId()); - // return it only from the own exile zone - if (currentZone != null && currentZone.size() > 0) { + Zone zone = game.getState().getZone(source.getSourceId()); + // return it from every public zone - http://www.mtgsalvation.com/forums/magic-fundamentals/magic-rulings/magic-rulings-archives/513186-obzedat-gc-as-edh-commander + if (!zone.equals(Zone.BATTLEFIELD) && !zone.equals(Zone.LIBRARY) && !zone.equals(Zone.HAND)) { Player owner = game.getPlayer(card.getOwnerId()); - if (owner != null && owner.moveCards(card, Zone.BATTLEFIELD, source, game)) { - return true; + if (owner != null) { + owner.moveCards(card, Zone.BATTLEFIELD, source, game); } } + return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/s/Seance.java b/Mage.Sets/src/mage/cards/s/Seance.java index b612367fb7b..8a5794460dd 100644 --- a/Mage.Sets/src/mage/cards/s/Seance.java +++ b/Mage.Sets/src/mage/cards/s/Seance.java @@ -56,7 +56,7 @@ import mage.target.targetpointer.FixedTargets; public class Seance extends CardImpl { public Seance(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); // At the beginning of each upkeep, you may exile target creature card from your graveyard. If you do, create a token that's a copy of that card except it's a Spirit in addition to its other types. Exile it at the beginning of the next end step. Ability ability = new BeginningOfUpkeepTriggeredAbility(new SeanceEffect(), TargetController.ANY, true); @@ -95,16 +95,15 @@ class SeanceEffect extends OneShotEffect { Card card = game.getCard(source.getFirstTarget()); Player controller = game.getPlayer(source.getControllerId()); if (controller != null && card != null) { - if (controller.moveCards(card, Zone.EXILED, source, game)) { - PutTokenOntoBattlefieldCopyTargetEffect effect = new PutTokenOntoBattlefieldCopyTargetEffect(source.getControllerId(), null, false); - effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game))); - effect.setAdditionalSubType("Spirit"); - effect.apply(game, source); - ExileTargetEffect exileEffect = new ExileTargetEffect(); - exileEffect.setTargetPointer(new FixedTargets(effect.getAddedPermanent(), game)); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - game.addDelayedTriggeredAbility(delayedAbility, source); - } + controller.moveCards(card, Zone.EXILED, source, game); // Also if the move to exile is replaced, the copy takes place + PutTokenOntoBattlefieldCopyTargetEffect effect = new PutTokenOntoBattlefieldCopyTargetEffect(source.getControllerId(), null, false); + effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game))); + effect.setAdditionalSubType("Spirit"); + effect.apply(game, source); + ExileTargetEffect exileEffect = new ExileTargetEffect(); + exileEffect.setTargetPointer(new FixedTargets(effect.getAddedPermanent(), game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } From 32e2578270f7cdf5c12fd3ed9881c48ee587da8d Mon Sep 17 00:00:00 2001 From: JRHerlehy Date: Thu, 8 Dec 2016 15:21:15 -0800 Subject: [PATCH 36/38] [JUD] Crush of Wurms --- Mage.Sets/src/mage/cards/c/CrushOfWurms.java | 64 ++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/c/CrushOfWurms.java diff --git a/Mage.Sets/src/mage/cards/c/CrushOfWurms.java b/Mage.Sets/src/mage/cards/c/CrushOfWurms.java new file mode 100644 index 00000000000..f6f671d191c --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CrushOfWurms.java @@ -0,0 +1,64 @@ +/* + * 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 mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.FlashbackAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TimingRule; +import mage.game.permanent.token.WurmToken; + +import java.util.UUID; + +/** + * @author JRHerlehy + */ +public class CrushOfWurms extends CardImpl { + + public CrushOfWurms(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{6}{G}{G}{G}"); + + + // Put three 6/6 green Wurm creature tokens onto the battlefield. + this.getSpellAbility().addEffect(new CreateTokenEffect(new WurmToken(), 3)); + // Flashback {9}{G}{G}{G} + this.addAbility(new FlashbackAbility(new ManaCostsImpl("{9}{G}{G}{G}"), TimingRule.SORCERY)); + } + + public CrushOfWurms(final CrushOfWurms card) { + super(card); + } + + @Override + public CrushOfWurms copy() { + return new CrushOfWurms(this); + } +} From e09af19c6436bbd3a4475285330afe8d83c36509 Mon Sep 17 00:00:00 2001 From: JRHerlehy Date: Thu, 8 Dec 2016 15:21:15 -0800 Subject: [PATCH 37/38] [JUD] Crush of Wurms --- Mage.Sets/src/mage/cards/c/CrushOfWurms.java | 64 ++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/c/CrushOfWurms.java diff --git a/Mage.Sets/src/mage/cards/c/CrushOfWurms.java b/Mage.Sets/src/mage/cards/c/CrushOfWurms.java new file mode 100644 index 00000000000..f6f671d191c --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CrushOfWurms.java @@ -0,0 +1,64 @@ +/* + * 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 mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.FlashbackAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TimingRule; +import mage.game.permanent.token.WurmToken; + +import java.util.UUID; + +/** + * @author JRHerlehy + */ +public class CrushOfWurms extends CardImpl { + + public CrushOfWurms(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{6}{G}{G}{G}"); + + + // Put three 6/6 green Wurm creature tokens onto the battlefield. + this.getSpellAbility().addEffect(new CreateTokenEffect(new WurmToken(), 3)); + // Flashback {9}{G}{G}{G} + this.addAbility(new FlashbackAbility(new ManaCostsImpl("{9}{G}{G}{G}"), TimingRule.SORCERY)); + } + + public CrushOfWurms(final CrushOfWurms card) { + super(card); + } + + @Override + public CrushOfWurms copy() { + return new CrushOfWurms(this); + } +} From e80c55a7bd7c41706b2980e61daaf66eb64fa2c0 Mon Sep 17 00:00:00 2001 From: JRHerlehy Date: Thu, 8 Dec 2016 15:24:34 -0800 Subject: [PATCH 38/38] [JUD] Crush of Wurms --- Mage.Sets/src/mage/sets/Judgment.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/Judgment.java b/Mage.Sets/src/mage/sets/Judgment.java index a4cd5ad2bd9..c9729947ef1 100644 --- a/Mage.Sets/src/mage/sets/Judgment.java +++ b/Mage.Sets/src/mage/sets/Judgment.java @@ -27,9 +27,9 @@ */ package mage.sets; -import mage.constants.SetType; import mage.cards.ExpansionSet; import mage.constants.Rarity; +import mage.constants.SetType; /** * @@ -78,6 +78,7 @@ public class Judgment extends ExpansionSet { cards.add(new SetCardInfo("Cephalid Constable", 35, Rarity.RARE, mage.cards.c.CephalidConstable.class)); cards.add(new SetCardInfo("Chastise", 8, Rarity.UNCOMMON, mage.cards.c.Chastise.class)); cards.add(new SetCardInfo("Commander Eesha", 9, Rarity.RARE, mage.cards.c.CommanderEesha.class)); + cards.add(new SetCardInfo("Crush of Wurms", 110, Rarity.RARE, mage.cards.c.CrushOfWurms.class)); cards.add(new SetCardInfo("Cunning Wish", 37, Rarity.RARE, mage.cards.c.CunningWish.class)); cards.add(new SetCardInfo("Death Wish", 64, Rarity.RARE, mage.cards.d.DeathWish.class)); cards.add(new SetCardInfo("Defy Gravity", 38, Rarity.COMMON, mage.cards.d.DefyGravity.class));