From 9ac7fe27f0bbfa7b0a8ba98039fffa2e272a1879 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 21 Aug 2017 18:49:37 +0200 Subject: [PATCH 1/4] * Vindictive Lich (mode target handling not fixed yet). --- .../client/util/sets/ConstructedFormats.java | 1 + .../src/mage/cards/v/VindictiveLich.java | 106 +++++++++ Mage.Sets/src/mage/sets/Commander2017.java | 203 +++++++++--------- .../main/java/mage/abilities/AbilityImpl.java | 5 +- .../main/java/mage/filter/FilterOpponent.java | 53 +++++ .../mageobject/AnotherTargetPredicate.java | 2 +- .../mage/target/common/TargetOpponent.java | 12 +- 7 files changed, 273 insertions(+), 109 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/v/VindictiveLich.java create mode 100644 Mage/src/main/java/mage/filter/FilterOpponent.java diff --git a/Mage.Client/src/main/java/mage/client/util/sets/ConstructedFormats.java b/Mage.Client/src/main/java/mage/client/util/sets/ConstructedFormats.java index a0b80a0d8d2..ba020a6ffb6 100644 --- a/Mage.Client/src/main/java/mage/client/util/sets/ConstructedFormats.java +++ b/Mage.Client/src/main/java/mage/client/util/sets/ConstructedFormats.java @@ -11,6 +11,7 @@ import mage.cards.repository.ExpansionRepository; import mage.constants.SetType; import mage.deck.Standard; + /** * Utility class for constructed formats (expansions and other editions). * diff --git a/Mage.Sets/src/mage/cards/v/VindictiveLich.java b/Mage.Sets/src/mage/cards/v/VindictiveLich.java new file mode 100644 index 00000000000..57a2da8d736 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VindictiveLich.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.cards.v; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.effects.common.SacrificeEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterOpponent; +import mage.filter.StaticFilters; +import mage.filter.predicate.mageobject.AnotherTargetPredicate; +import mage.target.Target; +import mage.target.common.TargetOpponent; + +/** + * + * @author anonymous + */ + + + public class VindictiveLich extends CardImpl { + +public VindictiveLich(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add("Zombie"); + this.subtype.add("Wizard"); + this.power = new MageInt(4); + this.toughness = new MageInt(1); + + // When Vindictive Lich dies, choose one or more. Each mode must target a different player. + // *Target opponent sacrifices a creature. + Ability ability = new DiesTriggeredAbility(new SacrificeEffect(StaticFilters.FILTER_PERMANENT_CREATURE, 1, "target opponent")); + ability.getModes().setMinModes(1); + ability.getModes().setMaxModes(3); + + FilterOpponent filter = new FilterOpponent(); + filter.add(new AnotherTargetPredicate(1)); + Target target = new TargetOpponent(filter, false); + target.setTargetTag(1); + ability.addTarget(target); + + // *Target opponent discards two cards. + Mode mode = new Mode(); + mode.getEffects().add(new DiscardTargetEffect(2, false)); + filter = new FilterOpponent(); + filter.add(new AnotherTargetPredicate(2)); + target = new TargetOpponent(filter, false); + target.setTargetTag(2); + mode.getTargets().add(target); + ability.addMode(mode); + + // *Target opponent loses 5 life. + mode = new Mode(); + mode.getEffects().add(new LoseLifeTargetEffect(2)); + filter = new FilterOpponent(); + filter.add(new AnotherTargetPredicate(2)); + target = new TargetOpponent(filter, false); + target.setTargetTag(3); + mode.getTargets().add(target); + ability.addMode(mode); + this.addAbility(ability); +} + +public VindictiveLich(final VindictiveLich card) { + super(card); +} + +@Override +public VindictiveLich copy() { + return new VindictiveLich(this); +} + +} diff --git a/Mage.Sets/src/mage/sets/Commander2017.java b/Mage.Sets/src/mage/sets/Commander2017.java index 65065e15498..df33d3155b8 100644 --- a/Mage.Sets/src/mage/sets/Commander2017.java +++ b/Mage.Sets/src/mage/sets/Commander2017.java @@ -1,101 +1,102 @@ -/* - * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of BetaSteward_at_googlemail.com. - */ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author fireshoes - */ -public class Commander2017 extends ExpansionSet { - - private static final Commander2017 instance = new Commander2017(); - - public static Commander2017 getInstance() { - return instance; - } - - private Commander2017() { - super("Commander 2017 Edition", "C17", ExpansionSet.buildDate(2017, 8, 25), SetType.SUPPLEMENTAL); - this.blockName = "Command Zone"; - - cards.add(new SetCardInfo("Arahbo, Roar of the World", 35, Rarity.MYTHIC, mage.cards.a.ArahboRoarOfTheWorld.class)); - cards.add(new SetCardInfo("Balan, Wandering Knight", 2, Rarity.RARE, mage.cards.b.BalanWanderingKnight.class)); - cards.add(new SetCardInfo("Bloodforged War Axe", 50, Rarity.RARE, mage.cards.b.BloodforgedWarAxe.class)); - cards.add(new SetCardInfo("Bloodline Necromancer", 14, Rarity.UNCOMMON, mage.cards.b.BloodlineNecromancer.class)); - cards.add(new SetCardInfo("Bloodsworn Steward", 22, Rarity.RARE, mage.cards.b.BloodswornSteward.class)); - cards.add(new SetCardInfo("Boneyard Scourge", 15, Rarity.RARE, mage.cards.b.BoneyardScourge.class)); - cards.add(new SetCardInfo("Crimson Honor Guard", 23, Rarity.RARE, mage.cards.c.CrimsonHonorGuard.class)); - cards.add(new SetCardInfo("Curse of Bounty", 30, Rarity.UNCOMMON, mage.cards.c.CurseOfBounty.class)); - cards.add(new SetCardInfo("Curse of Disturbance", 16, Rarity.UNCOMMON, mage.cards.c.CurseOfDisturbance.class)); - cards.add(new SetCardInfo("Curse of Opulence", 24, Rarity.UNCOMMON, mage.cards.c.CurseOfOpulence.class)); - cards.add(new SetCardInfo("Curse of Verbosity", 9, Rarity.UNCOMMON, mage.cards.c.CurseOfVerbosity.class)); - cards.add(new SetCardInfo("Curse of Vitality", 3, Rarity.UNCOMMON, mage.cards.c.CurseOfVitality.class)); - cards.add(new SetCardInfo("Disrupt Decorum", 25, Rarity.RARE, mage.cards.d.DisruptDecorum.class)); - cards.add(new SetCardInfo("Edgar Markov", 36, Rarity.MYTHIC, mage.cards.e.EdgarMarkov.class)); - cards.add(new SetCardInfo("Fortunate Few", 4, Rarity.RARE, mage.cards.f.FortunateFew.class)); - cards.add(new SetCardInfo("Fractured Identity", 37, Rarity.RARE, mage.cards.f.FracturedIdentity.class)); - cards.add(new SetCardInfo("Galecaster Colossus", 10, Rarity.RARE, mage.cards.g.GalecasterColossus.class)); - cards.add(new SetCardInfo("Hammer of Nazahn", 51, Rarity.RARE, mage.cards.h.HammerOfNazahn.class)); - cards.add(new SetCardInfo("Herald's Horn", 53, Rarity.UNCOMMON, mage.cards.h.HeraldsHorn.class)); - cards.add(new SetCardInfo("Heirloom Blade", 52, Rarity.UNCOMMON, mage.cards.h.HeirloomBlade.class)); - cards.add(new SetCardInfo("Hungry Lynx", 31, Rarity.RARE, mage.cards.h.HungryLynx.class)); - cards.add(new SetCardInfo("Inalla, Archmage Ritualist", 38, Rarity.MYTHIC, mage.cards.i.InallaArchmageRitualist.class)); - cards.add(new SetCardInfo("Izzet Chemister", 26, Rarity.RARE, mage.cards.i.IzzetChemister.class)); - cards.add(new SetCardInfo("Kess, Dissident Mage", 39, Rarity.MYTHIC, mage.cards.k.KessDissidentMage.class)); - cards.add(new SetCardInfo("Kheru Mind-Eater", 17, Rarity.RARE, mage.cards.k.KheruMindEater.class)); - cards.add(new SetCardInfo("Kindred Boon", 5, Rarity.RARE, mage.cards.k.KindredBoon.class)); - cards.add(new SetCardInfo("Kindred Charge", 27, Rarity.RARE, mage.cards.k.KindredCharge.class)); - cards.add(new SetCardInfo("Kindred Discovery", 11, Rarity.RARE, mage.cards.k.KindredDiscovery.class)); - cards.add(new SetCardInfo("Kindred Dominance", 18, Rarity.RARE, mage.cards.k.KindredDominance.class)); - cards.add(new SetCardInfo("Kindred Summons", 32, Rarity.RARE, mage.cards.k.KindredSummons.class)); - cards.add(new SetCardInfo("Licia, Sanguine Tribune", 40, Rarity.MYTHIC, mage.cards.l.LiciaSanguineTribune.class)); - cards.add(new SetCardInfo("Magus of the Mind", 12, Rarity.RARE, mage.cards.m.MagusOfTheMind.class)); - cards.add(new SetCardInfo("Mathas, Fiend Seeker", 42, Rarity.MYTHIC, mage.cards.m.MathasFiendSeeker.class)); - cards.add(new SetCardInfo("Mirri, Weatherlight Duelist", 43, Rarity.MYTHIC, mage.cards.m.MirriWeatherlightDuelist.class)); - cards.add(new SetCardInfo("Mirror of the Forebears", 54, Rarity.UNCOMMON, mage.cards.m.MirrorOfTheForebears.class)); - cards.add(new SetCardInfo("Nazahn, Revered Bladesmith", 44, Rarity.MYTHIC, mage.cards.n.NazahnReveredBladesmith.class)); - cards.add(new SetCardInfo("O-Kagachi, Vengeful Kami", 45, Rarity.MYTHIC, mage.cards.o.OKagachiVengefulKami.class)); - cards.add(new SetCardInfo("Path of Ancestry", 56, Rarity.COMMON, mage.cards.p.PathOfAncestry.class)); - cards.add(new SetCardInfo("Patron of the Vein", 20, Rarity.RARE, mage.cards.p.PatronOfTheVein.class)); - cards.add(new SetCardInfo("Qasali Slingers", 33, Rarity.RARE, mage.cards.q.QasaliSlingers.class)); - cards.add(new SetCardInfo("Ramos, Dragon Engine", 55, Rarity.MYTHIC, mage.cards.r.RamosDragonEngine.class)); - cards.add(new SetCardInfo("Scalelord Reckoner", 6, Rarity.RARE, mage.cards.s.ScalelordReckoner.class)); - cards.add(new SetCardInfo("Shifting Shadow", 28, Rarity.RARE, mage.cards.s.ShiftingShadow.class)); - cards.add(new SetCardInfo("Taigam, Ojutai Master", 46, Rarity.MYTHIC, mage.cards.t.TaigamOjutaiMaster.class)); - cards.add(new SetCardInfo("Taigam, Sidisi's Hand", 47, Rarity.RARE, mage.cards.t.TaigamSidisisHand.class)); - cards.add(new SetCardInfo("Teferi's Protection", 8, Rarity.RARE, mage.cards.t.TeferisProtection.class)); - cards.add(new SetCardInfo("Territorial Hellkite", 29, Rarity.RARE, mage.cards.t.TerritorialHellkite.class)); - cards.add(new SetCardInfo("The Ur-Dragon", 48, Rarity.MYTHIC, mage.cards.t.TheUrDragon.class)); - cards.add(new SetCardInfo("Traverse the Outlands", 34, Rarity.RARE, mage.cards.t.TraverseTheOutlands.class)); - cards.add(new SetCardInfo("Wasitora, Nekoru Queen", 49, Rarity.MYTHIC, mage.cards.w.WasitoraNekoruQueen.class)); - } -} +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * + * @author fireshoes + */ +public class Commander2017 extends ExpansionSet { + + private static final Commander2017 instance = new Commander2017(); + + public static Commander2017 getInstance() { + return instance; + } + + private Commander2017() { + super("Commander 2017 Edition", "C17", ExpansionSet.buildDate(2017, 8, 25), SetType.SUPPLEMENTAL); + this.blockName = "Command Zone"; + + cards.add(new SetCardInfo("Arahbo, Roar of the World", 35, Rarity.MYTHIC, mage.cards.a.ArahboRoarOfTheWorld.class)); + cards.add(new SetCardInfo("Balan, Wandering Knight", 2, Rarity.RARE, mage.cards.b.BalanWanderingKnight.class)); + cards.add(new SetCardInfo("Bloodforged War Axe", 50, Rarity.RARE, mage.cards.b.BloodforgedWarAxe.class)); + cards.add(new SetCardInfo("Bloodline Necromancer", 14, Rarity.UNCOMMON, mage.cards.b.BloodlineNecromancer.class)); + cards.add(new SetCardInfo("Bloodsworn Steward", 22, Rarity.RARE, mage.cards.b.BloodswornSteward.class)); + cards.add(new SetCardInfo("Boneyard Scourge", 15, Rarity.RARE, mage.cards.b.BoneyardScourge.class)); + cards.add(new SetCardInfo("Crimson Honor Guard", 23, Rarity.RARE, mage.cards.c.CrimsonHonorGuard.class)); + cards.add(new SetCardInfo("Curse of Bounty", 30, Rarity.UNCOMMON, mage.cards.c.CurseOfBounty.class)); + cards.add(new SetCardInfo("Curse of Disturbance", 16, Rarity.UNCOMMON, mage.cards.c.CurseOfDisturbance.class)); + cards.add(new SetCardInfo("Curse of Opulence", 24, Rarity.UNCOMMON, mage.cards.c.CurseOfOpulence.class)); + cards.add(new SetCardInfo("Curse of Verbosity", 9, Rarity.UNCOMMON, mage.cards.c.CurseOfVerbosity.class)); + cards.add(new SetCardInfo("Curse of Vitality", 3, Rarity.UNCOMMON, mage.cards.c.CurseOfVitality.class)); + cards.add(new SetCardInfo("Disrupt Decorum", 25, Rarity.RARE, mage.cards.d.DisruptDecorum.class)); + cards.add(new SetCardInfo("Edgar Markov", 36, Rarity.MYTHIC, mage.cards.e.EdgarMarkov.class)); + cards.add(new SetCardInfo("Fortunate Few", 4, Rarity.RARE, mage.cards.f.FortunateFew.class)); + cards.add(new SetCardInfo("Fractured Identity", 37, Rarity.RARE, mage.cards.f.FracturedIdentity.class)); + cards.add(new SetCardInfo("Galecaster Colossus", 10, Rarity.RARE, mage.cards.g.GalecasterColossus.class)); + cards.add(new SetCardInfo("Hammer of Nazahn", 51, Rarity.RARE, mage.cards.h.HammerOfNazahn.class)); + cards.add(new SetCardInfo("Herald's Horn", 53, Rarity.UNCOMMON, mage.cards.h.HeraldsHorn.class)); + cards.add(new SetCardInfo("Heirloom Blade", 52, Rarity.UNCOMMON, mage.cards.h.HeirloomBlade.class)); + cards.add(new SetCardInfo("Hungry Lynx", 31, Rarity.RARE, mage.cards.h.HungryLynx.class)); + cards.add(new SetCardInfo("Inalla, Archmage Ritualist", 38, Rarity.MYTHIC, mage.cards.i.InallaArchmageRitualist.class)); + cards.add(new SetCardInfo("Izzet Chemister", 26, Rarity.RARE, mage.cards.i.IzzetChemister.class)); + cards.add(new SetCardInfo("Kess, Dissident Mage", 39, Rarity.MYTHIC, mage.cards.k.KessDissidentMage.class)); + cards.add(new SetCardInfo("Kheru Mind-Eater", 17, Rarity.RARE, mage.cards.k.KheruMindEater.class)); + cards.add(new SetCardInfo("Kindred Boon", 5, Rarity.RARE, mage.cards.k.KindredBoon.class)); + cards.add(new SetCardInfo("Kindred Charge", 27, Rarity.RARE, mage.cards.k.KindredCharge.class)); + cards.add(new SetCardInfo("Kindred Discovery", 11, Rarity.RARE, mage.cards.k.KindredDiscovery.class)); + cards.add(new SetCardInfo("Kindred Dominance", 18, Rarity.RARE, mage.cards.k.KindredDominance.class)); + cards.add(new SetCardInfo("Kindred Summons", 32, Rarity.RARE, mage.cards.k.KindredSummons.class)); + cards.add(new SetCardInfo("Licia, Sanguine Tribune", 40, Rarity.MYTHIC, mage.cards.l.LiciaSanguineTribune.class)); + cards.add(new SetCardInfo("Magus of the Mind", 12, Rarity.RARE, mage.cards.m.MagusOfTheMind.class)); + cards.add(new SetCardInfo("Mathas, Fiend Seeker", 42, Rarity.MYTHIC, mage.cards.m.MathasFiendSeeker.class)); + cards.add(new SetCardInfo("Mirri, Weatherlight Duelist", 43, Rarity.MYTHIC, mage.cards.m.MirriWeatherlightDuelist.class)); + cards.add(new SetCardInfo("Mirror of the Forebears", 54, Rarity.UNCOMMON, mage.cards.m.MirrorOfTheForebears.class)); + cards.add(new SetCardInfo("Nazahn, Revered Bladesmith", 44, Rarity.MYTHIC, mage.cards.n.NazahnReveredBladesmith.class)); + cards.add(new SetCardInfo("O-Kagachi, Vengeful Kami", 45, Rarity.MYTHIC, mage.cards.o.OKagachiVengefulKami.class)); + cards.add(new SetCardInfo("Path of Ancestry", 56, Rarity.COMMON, mage.cards.p.PathOfAncestry.class)); + cards.add(new SetCardInfo("Patron of the Vein", 20, Rarity.RARE, mage.cards.p.PatronOfTheVein.class)); + cards.add(new SetCardInfo("Qasali Slingers", 33, Rarity.RARE, mage.cards.q.QasaliSlingers.class)); + cards.add(new SetCardInfo("Ramos, Dragon Engine", 55, Rarity.MYTHIC, mage.cards.r.RamosDragonEngine.class)); + cards.add(new SetCardInfo("Scalelord Reckoner", 6, Rarity.RARE, mage.cards.s.ScalelordReckoner.class)); + cards.add(new SetCardInfo("Shifting Shadow", 28, Rarity.RARE, mage.cards.s.ShiftingShadow.class)); + cards.add(new SetCardInfo("Taigam, Ojutai Master", 46, Rarity.MYTHIC, mage.cards.t.TaigamOjutaiMaster.class)); + cards.add(new SetCardInfo("Taigam, Sidisi's Hand", 47, Rarity.RARE, mage.cards.t.TaigamSidisisHand.class)); + cards.add(new SetCardInfo("Teferi's Protection", 8, Rarity.RARE, mage.cards.t.TeferisProtection.class)); + cards.add(new SetCardInfo("Territorial Hellkite", 29, Rarity.RARE, mage.cards.t.TerritorialHellkite.class)); + cards.add(new SetCardInfo("The Ur-Dragon", 48, Rarity.MYTHIC, mage.cards.t.TheUrDragon.class)); + cards.add(new SetCardInfo("Traverse the Outlands", 34, Rarity.RARE, mage.cards.t.TraverseTheOutlands.class)); + cards.add(new SetCardInfo("Vindictive Lich", 21, Rarity.RARE, mage.cards.v.VindictiveLich.class)); + cards.add(new SetCardInfo("Wasitora, Nekoru Queen", 49, Rarity.MYTHIC, mage.cards.w.WasitoraNekoruQueen.class)); + } +} diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index 0ea915148dc..33f84c4e633 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -858,7 +858,10 @@ public abstract class AbilityImpl implements Ability { @Override public Targets getTargets() { - return getModes().getMode().getTargets(); + if (getModes().getMode() != null) { + return getModes().getMode().getTargets(); + } + return null; } @Override diff --git a/Mage/src/main/java/mage/filter/FilterOpponent.java b/Mage/src/main/java/mage/filter/FilterOpponent.java new file mode 100644 index 00000000000..efffdb4b983 --- /dev/null +++ b/Mage/src/main/java/mage/filter/FilterOpponent.java @@ -0,0 +1,53 @@ +/* +* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are +* permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, this list +* of conditions and the following disclaimer in the documentation and/or other materials +* provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* The views and conclusions contained in the software and documentation are those of the +* authors and should not be interpreted as representing official policies, either expressed +* or implied, of BetaSteward_at_googlemail.com. + */ +package mage.filter; + +import mage.constants.TargetController; +import mage.filter.predicate.other.PlayerPredicate; + +/** + * + * @author LevelX2 + */ +public class FilterOpponent extends FilterPlayer{ + + public FilterOpponent() { + super("opponent"); + add(new PlayerPredicate(TargetController.OPPONENT)); + } + + + public FilterOpponent(final FilterOpponent filter) { + super(filter); + + } + @Override + public FilterOpponent copy() { + return new FilterOpponent(this); + } +} diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/AnotherTargetPredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/AnotherTargetPredicate.java index 18959437deb..ee3a866e2f2 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/AnotherTargetPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/AnotherTargetPredicate.java @@ -57,7 +57,7 @@ public class AnotherTargetPredicate implements ObjectSourcePlayerPredicate input, Game game) { StackObject source = game.getStack().getStackObject(input.getSourceId()); - if (source != null) { + if (source != null && source.getStackAbility().getTargets() != null) { for (Target target : source.getStackAbility().getTargets()) { if (target.getTargetTag() > 0 // target is included in the target group to check && target.getTargetTag() != targetTag // it's not the target of this predicate diff --git a/Mage/src/main/java/mage/target/common/TargetOpponent.java b/Mage/src/main/java/mage/target/common/TargetOpponent.java index 4c4eb6d623c..a14c987657e 100644 --- a/Mage/src/main/java/mage/target/common/TargetOpponent.java +++ b/Mage/src/main/java/mage/target/common/TargetOpponent.java @@ -27,9 +27,7 @@ */ package mage.target.common; -import mage.constants.TargetController; -import mage.filter.FilterPlayer; -import mage.filter.predicate.other.PlayerPredicate; +import mage.filter.FilterOpponent; import mage.target.TargetPlayer; /** @@ -44,9 +42,11 @@ public class TargetOpponent extends TargetPlayer { } public TargetOpponent(boolean notTarget) { - super(1, 1, false, new FilterPlayer("opponent")); - this.filter.add(new PlayerPredicate(TargetController.OPPONENT)); - setNotTarget(notTarget); + this(new FilterOpponent(), notTarget); + } + + public TargetOpponent(FilterOpponent filter, boolean notTarget) { + super(1, 1, notTarget, filter); } public TargetOpponent(final TargetOpponent target) { From 7b1ba214e25cfa48f29dd67ef10c2abf4362b50e Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 21 Aug 2017 16:24:15 -0500 Subject: [PATCH 2/4] - Added Funeral Pyre. Fixed Orcish Settlers. --- Mage.Sets/src/mage/cards/f/FuneralPyre.java | 102 ++++++++++++++++++ .../src/mage/cards/o/OrcishSettlers.java | 24 ++--- Mage.Sets/src/mage/sets/Judgment.java | 3 +- 3 files changed, 116 insertions(+), 13 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/f/FuneralPyre.java diff --git a/Mage.Sets/src/mage/cards/f/FuneralPyre.java b/Mage.Sets/src/mage/cards/f/FuneralPyre.java new file mode 100644 index 00000000000..c9fa645b890 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FuneralPyre.java @@ -0,0 +1,102 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.f; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.token.SpiritWhiteToken; +import mage.game.permanent.token.Token; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; +import mage.util.CardUtil; + +/** + * + * @author jeffwadsworth + */ +public class FuneralPyre extends CardImpl { + + public FuneralPyre(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); + + + // Exile target card from a graveyard. Its owner puts a 1/1 white Spirit creature token with flying onto the battlefield. + this.getSpellAbility().addEffect(new FuneralPyreEffect()); + this.getSpellAbility().addTarget(new TargetCardInGraveyard()); + + } + + public FuneralPyre(final FuneralPyre card) { + super(card); + } + + @Override + public FuneralPyre copy() { + return new FuneralPyre(this); + } +} + +class FuneralPyreEffect extends OneShotEffect { + + public FuneralPyreEffect() { + super(Outcome.Benefit); + this.staticText = "Exile target card from a graveyard. Its owner puts a 1/1 white Spirit creature token with flying onto the battlefield"; + } + + public FuneralPyreEffect(final FuneralPyreEffect effect) { + super(effect); + } + + @Override + public FuneralPyreEffect copy() { + return new FuneralPyreEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Card exiledCard = game.getCard(source.getTargets().getFirstTarget()); + if (exiledCard != null) { + UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), 0); + if (exiledCard.moveToExile(exileId, "Funeral Pyre", source.getSourceId(), game)) { + Player owner = game.getPlayer(exiledCard.getOwnerId()); + if (owner != null) { + Token token = new SpiritWhiteToken(); + return token.putOntoBattlefield(1, game, source.getSourceId(), owner.getId()); + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/o/OrcishSettlers.java b/Mage.Sets/src/mage/cards/o/OrcishSettlers.java index f71fed3f56d..7fc3ea2c18b 100644 --- a/Mage.Sets/src/mage/cards/o/OrcishSettlers.java +++ b/Mage.Sets/src/mage/cards/o/OrcishSettlers.java @@ -55,7 +55,7 @@ import mage.target.common.TargetLandPermanent; public class OrcishSettlers extends CardImpl { public OrcishSettlers(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); this.subtype.add("Orc"); this.power = new MageInt(1); @@ -96,24 +96,24 @@ class OrcishSettlersEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - int amount = new ManacostVariableValue().calculate(game, source, this); - TargetLandPermanent target = new TargetLandPermanent(amount); - - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + int amount = source.getManaCostsToPay().getX(); + if (amount == 0) { return false; } - - if (player.choose(Outcome.DestroyPermanent, target, id, game)) { + TargetLandPermanent target = new TargetLandPermanent(amount); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null + && target.canChoose(controller.getId(), game) + && controller.choose(Outcome.DestroyPermanent, target, source.getSourceId(), game)) { List targets = target.getTargets(); - for (UUID landId : targets) { + targets.forEach((landId) -> { Permanent land = game.getPermanent(landId); if (land != null) { land.destroy(landId, game, false); } - } - + }); + return true; } - return true; + return false; } } diff --git a/Mage.Sets/src/mage/sets/Judgment.java b/Mage.Sets/src/mage/sets/Judgment.java index 7443e32904e..cfc1f90904a 100644 --- a/Mage.Sets/src/mage/sets/Judgment.java +++ b/Mage.Sets/src/mage/sets/Judgment.java @@ -78,7 +78,7 @@ public class Judgment extends ExpansionSet { cards.add(new SetCardInfo("Canopy Claws", 108, Rarity.COMMON, mage.cards.c.CanopyClaws.class)); cards.add(new SetCardInfo("Centaur Rootcaster", 109, Rarity.COMMON, mage.cards.c.CentaurRootcaster.class)); cards.add(new SetCardInfo("Cephalid Constable", 35, Rarity.RARE, mage.cards.c.CephalidConstable.class)); - cards.add(new SetCardInfo("Cephalid Inkshrouder", 36, Rarity.UNCOMMON, mage.cards.c.CephalidInkshrouder.class)); + cards.add(new SetCardInfo("Cephalid Inkshrouder", 36, Rarity.UNCOMMON, mage.cards.c.CephalidInkshrouder.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)); @@ -100,6 +100,7 @@ public class Judgment extends ExpansionSet { cards.add(new SetCardInfo("Flash of Insight", 40, Rarity.UNCOMMON, mage.cards.f.FlashOfInsight.class)); cards.add(new SetCardInfo("Fledgling Dragon", 90, Rarity.RARE, mage.cards.f.FledglingDragon.class)); cards.add(new SetCardInfo("Folk Medicine", 115, Rarity.COMMON, mage.cards.f.FolkMedicine.class)); + cards.add(new SetCardInfo("Funeral Pyre", 10, Rarity.COMMON, mage.cards.f.FuneralPyre.class)); cards.add(new SetCardInfo("Genesis", 117, Rarity.RARE, mage.cards.g.Genesis.class)); cards.add(new SetCardInfo("Giant Warthog", 118, Rarity.COMMON, mage.cards.g.GiantWarthog.class)); cards.add(new SetCardInfo("Glory", 11, Rarity.RARE, mage.cards.g.Glory.class)); From 2880b324445a1deb2b65d86097df4c9ff3404184 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 22 Aug 2017 00:27:18 +0200 Subject: [PATCH 3/4] * Vindictive Lich - Fixed cross mode target handling. --- .../src/mage/cards/v/VindictiveLich.java | 211 +++++++++--------- Mage/src/main/java/mage/abilities/Modes.java | 30 ++- .../main/java/mage/filter/FilterOpponent.java | 110 ++++----- .../mageobject/AnotherTargetPredicate.java | 31 ++- 4 files changed, 216 insertions(+), 166 deletions(-) diff --git a/Mage.Sets/src/mage/cards/v/VindictiveLich.java b/Mage.Sets/src/mage/cards/v/VindictiveLich.java index 57a2da8d736..bf8182a2d25 100644 --- a/Mage.Sets/src/mage/cards/v/VindictiveLich.java +++ b/Mage.Sets/src/mage/cards/v/VindictiveLich.java @@ -1,106 +1,105 @@ -/* - * 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.v; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.Mode; -import mage.abilities.common.DiesTriggeredAbility; -import mage.abilities.effects.common.LoseLifeTargetEffect; -import mage.abilities.effects.common.SacrificeEffect; -import mage.abilities.effects.common.discard.DiscardTargetEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.filter.FilterOpponent; -import mage.filter.StaticFilters; -import mage.filter.predicate.mageobject.AnotherTargetPredicate; -import mage.target.Target; -import mage.target.common.TargetOpponent; - -/** - * - * @author anonymous - */ - - - public class VindictiveLich extends CardImpl { - -public VindictiveLich(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); - - this.subtype.add("Zombie"); - this.subtype.add("Wizard"); - this.power = new MageInt(4); - this.toughness = new MageInt(1); - - // When Vindictive Lich dies, choose one or more. Each mode must target a different player. - // *Target opponent sacrifices a creature. - Ability ability = new DiesTriggeredAbility(new SacrificeEffect(StaticFilters.FILTER_PERMANENT_CREATURE, 1, "target opponent")); - ability.getModes().setMinModes(1); - ability.getModes().setMaxModes(3); - - FilterOpponent filter = new FilterOpponent(); - filter.add(new AnotherTargetPredicate(1)); - Target target = new TargetOpponent(filter, false); - target.setTargetTag(1); - ability.addTarget(target); - - // *Target opponent discards two cards. - Mode mode = new Mode(); - mode.getEffects().add(new DiscardTargetEffect(2, false)); - filter = new FilterOpponent(); - filter.add(new AnotherTargetPredicate(2)); - target = new TargetOpponent(filter, false); - target.setTargetTag(2); - mode.getTargets().add(target); - ability.addMode(mode); - - // *Target opponent loses 5 life. - mode = new Mode(); - mode.getEffects().add(new LoseLifeTargetEffect(2)); - filter = new FilterOpponent(); - filter.add(new AnotherTargetPredicate(2)); - target = new TargetOpponent(filter, false); - target.setTargetTag(3); - mode.getTargets().add(target); - ability.addMode(mode); - this.addAbility(ability); -} - -public VindictiveLich(final VindictiveLich card) { - super(card); -} - -@Override -public VindictiveLich copy() { - return new VindictiveLich(this); -} - -} +/* + * 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.v; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.effects.common.SacrificeEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterOpponent; +import mage.filter.StaticFilters; +import mage.filter.predicate.mageobject.AnotherTargetPredicate; +import mage.target.Target; +import mage.target.common.TargetOpponent; + +/** + * + * @author anonymous + */ +public class VindictiveLich extends CardImpl { + + public VindictiveLich(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.ZOMBIE, SubType.WIZARD); + this.power = new MageInt(4); + this.toughness = new MageInt(1); + + // When Vindictive Lich dies, choose one or more. Each mode must target a different player. + // *Target opponent sacrifices a creature. + Ability ability = new DiesTriggeredAbility(new SacrificeEffect(StaticFilters.FILTER_PERMANENT_CREATURE, 1, "target opponent")); + ability.getModes().setMinModes(1); + ability.getModes().setMaxModes(3); + ability.getModes().setMaxModesFilter(new FilterOpponent("a different player")); + + FilterOpponent filter = new FilterOpponent("opponent (sacrifice)"); + filter.add(new AnotherTargetPredicate(1, true)); + Target target = new TargetOpponent(filter, false); + target.setTargetTag(1); + ability.addTarget(target); + + // *Target opponent discards two cards. + Mode mode = new Mode(); + mode.getEffects().add(new DiscardTargetEffect(2, false)); + filter = new FilterOpponent("opponent (discard)"); + filter.add(new AnotherTargetPredicate(2, true)); + target = new TargetOpponent(filter, false); + target.setTargetTag(2); + mode.getTargets().add(target); + ability.addMode(mode); + + // *Target opponent loses 5 life. + mode = new Mode(); + mode.getEffects().add(new LoseLifeTargetEffect(2)); + filter = new FilterOpponent("opponent (life loss)"); + filter.add(new AnotherTargetPredicate(3, true)); + target = new TargetOpponent(filter, false); + target.setTargetTag(3); + mode.getTargets().add(target); + ability.addMode(mode); + this.addAbility(ability); + } + + public VindictiveLich(final VindictiveLich card) { + super(card); + } + + @Override + public VindictiveLich copy() { + return new VindictiveLich(this); + } + +} diff --git a/Mage/src/main/java/mage/abilities/Modes.java b/Mage/src/main/java/mage/abilities/Modes.java index d8c8e42fd73..c06591cb3fd 100644 --- a/Mage/src/main/java/mage/abilities/Modes.java +++ b/Mage/src/main/java/mage/abilities/Modes.java @@ -38,6 +38,8 @@ import mage.abilities.costs.OptionalAdditionalModeSourceCosts; import mage.cards.Card; import mage.constants.Outcome; import mage.constants.TargetController; +import mage.filter.Filter; +import mage.filter.FilterPlayer; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetOpponent; @@ -57,6 +59,7 @@ public class Modes extends LinkedHashMap { private boolean eachModeOnlyOnce; // state if each mode can be chosen only once as long as the source object exists private final LinkedHashMap duplicateModes = new LinkedHashMap<>(); private OptionalAdditionalModeSourceCosts optionalAdditionalModeSourceCosts = null; // only set if costs have to be paid + private Filter maxModesFilter = null; // calculates the max number of available modes public Modes() { this.currentMode = new Mode(); @@ -89,6 +92,7 @@ public class Modes extends LinkedHashMap { this.eachModeOnlyOnce = modes.eachModeOnlyOnce; this.eachModeMoreThanOnce = modes.eachModeMoreThanOnce; this.optionalAdditionalModeSourceCosts = modes.optionalAdditionalModeSourceCosts; + this.maxModesFilter = modes.maxModesFilter; // can't change so no copy needed } public Modes copy() { @@ -151,6 +155,14 @@ public class Modes extends LinkedHashMap { this.maxModes = maxModes; } + public Filter getMaxModesFilter() { + return maxModesFilter; + } + + public void setMaxModesFilter(Filter maxModesFilter) { + this.maxModesFilter = maxModesFilter; + } + public int getMaxModes() { return this.maxModes; } @@ -230,7 +242,19 @@ public class Modes extends LinkedHashMap { // player chooses modes manually this.currentMode = null; - while (this.selectedModes.size() < this.getMaxModes()) { + int currentMaxModes = this.getMaxModes(); + if (getMaxModesFilter() != null) { + if (maxModesFilter instanceof FilterPlayer) { + currentMaxModes = 0; + for (UUID targetPlayerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player targetPlayer = game.getPlayer(targetPlayerId); + if (((FilterPlayer) maxModesFilter).match(targetPlayer, source.getSourceId(), source.getControllerId(), game)) { + currentMaxModes++; + } + } + } + } + while (this.selectedModes.size() < currentMaxModes) { Mode choice = player.chooseMode(this, source, game); if (choice == null) { if (isEachModeOnlyOnce()) { @@ -337,7 +361,9 @@ public class Modes extends LinkedHashMap { return this.getMode().getEffects().getText(this.getMode()); } StringBuilder sb = new StringBuilder(); - if (this.getMinModes() == 1 && this.getMaxModes() == 3) { + if (this.getMaxModesFilter() != null) { + sb.append("choose one or more. Each mode must target ").append(getMaxModesFilter().getMessage()); + } else if (this.getMinModes() == 1 && this.getMaxModes() == 3) { sb.append("choose one or more "); } else if (this.getMinModes() == 1 && this.getMaxModes() == 2) { sb.append("choose one or both "); diff --git a/Mage/src/main/java/mage/filter/FilterOpponent.java b/Mage/src/main/java/mage/filter/FilterOpponent.java index efffdb4b983..d413dee473b 100644 --- a/Mage/src/main/java/mage/filter/FilterOpponent.java +++ b/Mage/src/main/java/mage/filter/FilterOpponent.java @@ -1,53 +1,57 @@ -/* -* 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.filter; - -import mage.constants.TargetController; -import mage.filter.predicate.other.PlayerPredicate; - -/** - * - * @author LevelX2 - */ -public class FilterOpponent extends FilterPlayer{ - - public FilterOpponent() { - super("opponent"); - add(new PlayerPredicate(TargetController.OPPONENT)); - } - - - public FilterOpponent(final FilterOpponent filter) { - super(filter); - - } - @Override - public FilterOpponent copy() { - return new FilterOpponent(this); - } -} +/* +* 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.filter; + +import mage.constants.TargetController; +import mage.filter.predicate.other.PlayerPredicate; + +/** + * + * @author LevelX2 + */ +public class FilterOpponent extends FilterPlayer { + + public FilterOpponent() { + this("opponent"); + } + + public FilterOpponent(String text) { + super(text); + add(new PlayerPredicate(TargetController.OPPONENT)); + } + + public FilterOpponent(final FilterOpponent filter) { + super(filter); + + } + + @Override + public FilterOpponent copy() { + return new FilterOpponent(this); + } +} diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/AnotherTargetPredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/AnotherTargetPredicate.java index ee3a866e2f2..c21819b23e6 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/AnotherTargetPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/AnotherTargetPredicate.java @@ -27,7 +27,9 @@ */ package mage.filter.predicate.mageobject; +import java.util.UUID; import mage.MageItem; +import mage.abilities.Mode; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; @@ -45,24 +47,43 @@ import mage.target.Target; public class AnotherTargetPredicate implements ObjectSourcePlayerPredicate> { private final int targetTag; + private final boolean crossModalCheck; /** * * @param targetTag tag of the target the filter belongs to */ public AnotherTargetPredicate(int targetTag) { + this(targetTag, false); + } + + public AnotherTargetPredicate(int targetTag, boolean crossModalCheck) { this.targetTag = targetTag; + this.crossModalCheck = crossModalCheck; } @Override public boolean apply(ObjectSourcePlayer input, Game game) { StackObject source = game.getStack().getStackObject(input.getSourceId()); if (source != null && source.getStackAbility().getTargets() != null) { - for (Target target : source.getStackAbility().getTargets()) { - if (target.getTargetTag() > 0 // target is included in the target group to check - && target.getTargetTag() != targetTag // it's not the target of this predicate - && target.getTargets().contains(input.getObject().getId())) { // if the uuid already is used for another target in the group it's not allowed here - return false; + if (crossModalCheck) { + for (UUID modeId : source.getStackAbility().getModes().getSelectedModes()) { + Mode mode = source.getStackAbility().getModes().get(modeId); + for (Target target : mode.getTargets()) { + if (target.getTargetTag() > 0 // target is included in the target group to check + && target.getTargetTag() != targetTag // it's not the target of this predicate + && target.getTargets().contains(input.getObject().getId())) { // if the uuid already is used for another target in the group it's not allowed here + return false; + } + } + } + } else { + for (Target target : source.getStackAbility().getTargets()) { + if (target.getTargetTag() > 0 // target is included in the target group to check + && target.getTargetTag() != targetTag // it's not the target of this predicate + && target.getTargets().contains(input.getObject().getId())) { // if the uuid already is used for another target in the group it's not allowed here + return false; + } } } } From 1a4d6ea547583587a6ce5aa68b8c63c17a28d5c0 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 22 Aug 2017 00:37:44 +0200 Subject: [PATCH 4/4] * Vindictive Lich - Fixed cross mode target handling. --- Mage/src/main/java/mage/abilities/Modes.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Mage/src/main/java/mage/abilities/Modes.java b/Mage/src/main/java/mage/abilities/Modes.java index c06591cb3fd..c942f58c362 100644 --- a/Mage/src/main/java/mage/abilities/Modes.java +++ b/Mage/src/main/java/mage/abilities/Modes.java @@ -252,6 +252,9 @@ public class Modes extends LinkedHashMap { currentMaxModes++; } } + if (currentMaxModes > this.getMaxModes()) { + currentMaxModes = this.getMaxModes(); + } } } while (this.selectedModes.size() < currentMaxModes) {