From 7d026c699fccdcd0329fd3b98393fea9f1b58078 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 2 Jan 2018 17:47:38 +0100 Subject: [PATCH] [RIX] Added 3 cards. --- Mage.Sets/src/mage/cards/a/ArdentRecruit.java | 8 +- Mage.Sets/src/mage/cards/d/DuskCharger.java | 78 +++++++++ Mage.Sets/src/mage/cards/f/FirstResponse.java | 42 +---- .../src/mage/cards/g/GloriousDestiny.java | 92 ++++++++++ .../src/mage/cards/p/PaladinOfAtonement.java | 79 +++++++++ Mage.Sets/src/mage/sets/RivalsOfIxalan.java | 159 +++++++++--------- .../common/LiveLostLastTurnCondition.java | 54 ++++++ .../ConditionalTriggeredAbility.java | 14 +- .../effects/keyword/AscendEffect.java | 23 +-- .../mage/abilities/keyword/AscendAbility.java | 115 +++++++++++++ .../main/java/mage/filter/StaticFilters.java | 3 + .../main/java/mage/watchers/WatcherUtils.java | 46 +++++ .../common/PlayerLostLifeWatcher.java | 2 +- Utils/keywords.txt | 1 + 14 files changed, 571 insertions(+), 145 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/d/DuskCharger.java create mode 100644 Mage.Sets/src/mage/cards/g/GloriousDestiny.java create mode 100644 Mage.Sets/src/mage/cards/p/PaladinOfAtonement.java create mode 100644 Mage/src/main/java/mage/abilities/condition/common/LiveLostLastTurnCondition.java create mode 100644 Mage/src/main/java/mage/abilities/keyword/AscendAbility.java create mode 100644 Mage/src/main/java/mage/watchers/WatcherUtils.java diff --git a/Mage.Sets/src/mage/cards/a/ArdentRecruit.java b/Mage.Sets/src/mage/cards/a/ArdentRecruit.java index 1fe2d66ec1..c793bb0435 100644 --- a/Mage.Sets/src/mage/cards/a/ArdentRecruit.java +++ b/Mage.Sets/src/mage/cards/a/ArdentRecruit.java @@ -25,7 +25,6 @@ * 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; @@ -46,14 +45,17 @@ import mage.constants.*; public class ArdentRecruit extends CardImpl { public ArdentRecruit(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); this.power = new MageInt(1); this.toughness = new MageInt(1); + + // Metalcraft — Ardent Recruit gets +2/+2 as long as you control three or more artifacts. ContinuousEffect boostSource = new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield); - ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, MetalcraftCondition.instance, "Ardent Recruit gets +2/+2 as long as you control three or more artifacts"); + ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, MetalcraftCondition.instance, + "{this} gets +2/+2 as long as you control three or more artifacts"); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); ability.setAbilityWord(AbilityWord.METALCRAFT); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/d/DuskCharger.java b/Mage.Sets/src/mage/cards/d/DuskCharger.java new file mode 100644 index 0000000000..e9a09ec133 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DuskCharger.java @@ -0,0 +1,78 @@ +/* + * 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 java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CitysBlessingCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.AscendAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; + +/** + * + * @author LevelX2 + */ +public class DuskCharger extends CardImpl { + + public DuskCharger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.HORSE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Ascend + this.addAbility(new AscendAbility()); + + // Dusk Charger gets +2/+2 as long as you have the city's blessing. + ContinuousEffect boostSource = new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield); + ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, CitysBlessingCondition.instance, + "{this} gets +2/+2 as long as you have the city's blessing"); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); + this.addAbility(ability); + } + + public DuskCharger(final DuskCharger card) { + super(card); + } + + @Override + public DuskCharger copy() { + return new DuskCharger(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FirstResponse.java b/Mage.Sets/src/mage/cards/f/FirstResponse.java index 51b618397a..5e249cf39d 100644 --- a/Mage.Sets/src/mage/cards/f/FirstResponse.java +++ b/Mage.Sets/src/mage/cards/f/FirstResponse.java @@ -28,18 +28,15 @@ package mage.cards.f; import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.condition.common.LiveLostLastTurnCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.TargetController; -import mage.game.Game; import mage.game.permanent.token.SoldierToken; -import mage.watchers.common.PlayerLostLifeWatcher; /** * @@ -51,8 +48,10 @@ public class FirstResponse extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); // At the beginning of each upkeep, if you lost life last turn, create a 1/1 white Soldier creature token. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new FirstResponseEffect(), TargetController.ANY, false), new PlayerLostLifeWatcher()); - + this.addAbility(new ConditionalTriggeredAbility( + new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new SoldierToken()), TargetController.ANY, false), + LiveLostLastTurnCondition.instance, + "At the beginning of each upkeep, if you lost life last turn, create a 1/1 white Soldier creature token.")); } public FirstResponse(final FirstResponse card) { @@ -64,32 +63,3 @@ public class FirstResponse extends CardImpl { return new FirstResponse(this); } } - -class FirstResponseEffect extends OneShotEffect { - - public FirstResponseEffect() { - super(Outcome.PutCreatureInPlay); - this.staticText = "if you lost life last turn, create a 1/1 white Soldier creature token"; - } - - public FirstResponseEffect(final FirstResponseEffect effect) { - super(effect); - } - - @Override - public FirstResponseEffect copy() { - return new FirstResponseEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName()); - if (watcher != null) { - if (watcher.getLiveLostLastTurn(source.getControllerId()) > 0) { - return new CreateTokenEffect(new SoldierToken()).apply(game, source); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/g/GloriousDestiny.java b/Mage.Sets/src/mage/cards/g/GloriousDestiny.java new file mode 100644 index 0000000000..ec88a4e9ef --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GloriousDestiny.java @@ -0,0 +1,92 @@ +/* + * 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.g; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CitysBlessingCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; +import mage.abilities.effects.common.continuous.BoostAllOfChosenSubtypeEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllOfChosenSubtypeEffect; +import mage.abilities.keyword.AscendAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES_CONTROLLED; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; + +/** + * + * @author LevelX2 + */ +public class GloriousDestiny extends CardImpl { + + private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures you control of the chosen type"); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + public GloriousDestiny(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); + + // Ascend + this.addAbility(new AscendAbility()); + + // As Glorious Destiny enters the battlefield, choose a creature type. + this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.BoostCreature))); + + // Creatures you control of the chosen type get +1/+1. They have vigilance as long as you have the city's blessing. + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllOfChosenSubtypeEffect(1, 1, Duration.WhileOnBattlefield, filter, true)); + ContinuousEffect effect = new ConditionalContinuousEffect( + new GainAbilityAllOfChosenSubtypeEffect(VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, FILTER_PERMANENT_CREATURES_CONTROLLED), + CitysBlessingCondition.instance, + "They have vigilance as long as you have the city's blessing"); + ability.addEffect(effect); + this.addAbility(ability); + } + + public GloriousDestiny(final GloriousDestiny card) { + super(card); + } + + @Override + public GloriousDestiny copy() { + return new GloriousDestiny(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PaladinOfAtonement.java b/Mage.Sets/src/mage/cards/p/PaladinOfAtonement.java new file mode 100644 index 0000000000..941c0495ab --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PaladinOfAtonement.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.p; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.condition.common.LiveLostLastTurnCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.dynamicvalue.common.SourcePermanentToughnessValue; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.counters.CounterType; + +/** + * + * @author LevelX2 + */ +public class PaladinOfAtonement extends CardImpl { + + public PaladinOfAtonement(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // At the beginning of each upkeep, if you lost life last turn, put a +1/+1 counter on Paladin of Atonement. + this.addAbility(new ConditionalTriggeredAbility( + new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), TargetController.ANY, false), + LiveLostLastTurnCondition.instance, + "At the beginning of each upkeep, if you lost life last turn, put a +1/+1 counter on {this}")); + + // When Paladin of Atonement dies, you gain life equal to it's toughness. + this.addAbility(new DiesTriggeredAbility(new GainLifeEffect(SourcePermanentToughnessValue.getInstance(), + "you gain life equal to it's toughness"))); + } + + public PaladinOfAtonement(final PaladinOfAtonement card) { + super(card); + } + + @Override + public PaladinOfAtonement copy() { + return new PaladinOfAtonement(this); + } +} diff --git a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java index 710c3994e7..3aab703e2f 100644 --- a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java +++ b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java @@ -1,78 +1,81 @@ -/* -* 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 RivalsOfIxalan extends ExpansionSet { - - private static final RivalsOfIxalan instance = new RivalsOfIxalan(); - - public static RivalsOfIxalan getInstance() { - return instance; - } - - private RivalsOfIxalan() { - super("Rivals of Ixalan", "RIX", ExpansionSet.buildDate(2018, 1, 19), SetType.EXPANSION); - this.blockName = "Ixalan"; - this.parentSet = Ixalan.getInstance(); - this.hasBoosters = true; - this.hasBasicLands = false; - this.numBoosterLands = 1; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 8; - - cards.add(new SetCardInfo("Angrath's Ambusher", 202, Rarity.UNCOMMON, mage.cards.a.AngrathsAmbusher.class)); - cards.add(new SetCardInfo("Angrath's Fury", 204, Rarity.RARE, mage.cards.a.AngrathsFury.class)); - cards.add(new SetCardInfo("Angrath, Minotaur Pirate", 201, Rarity.MYTHIC, mage.cards.a.AngrathMinotaurPirate.class)); - cards.add(new SetCardInfo("Brass's Bounty", 94, Rarity.RARE, mage.cards.b.BrasssBounty.class)); - cards.add(new SetCardInfo("Captain's Hook", 177, Rarity.RARE, mage.cards.c.CaptainsHook.class)); - cards.add(new SetCardInfo("Cinder Barrens", 205, Rarity.RARE, mage.cards.c.CinderBarrens.class)); - cards.add(new SetCardInfo("Evolving Wilds", 186, Rarity.RARE, mage.cards.e.EvolvingWilds.class)); - cards.add(new SetCardInfo("Ghalta, Primal Hunger", 130, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class)); - cards.add(new SetCardInfo("Silvergill Adept", 53, Rarity.UNCOMMON, mage.cards.s.SilvergillAdept.class)); - cards.add(new SetCardInfo("Storm the Vault", 173, Rarity.RARE, mage.cards.s.StormTheVault.class)); - cards.add(new SetCardInfo("Swab Goblin", 203, Rarity.COMMON, mage.cards.s.SwabGoblin.class)); - cards.add(new SetCardInfo("Tetzimoc, Primal Death", 86, Rarity.RARE, mage.cards.t.TetzimocPrimalDeath.class)); - cards.add(new SetCardInfo("The Immortal Sun", 180, Rarity.MYTHIC, mage.cards.t.TheImmortalSun.class)); - cards.add(new SetCardInfo("Vampire Champion", 198, Rarity.COMMON, mage.cards.v.VampireChampion.class)); - cards.add(new SetCardInfo("Vault of Catlacan", 173, Rarity.RARE, mage.cards.v.VaultOfCatlacan.class)); - cards.add(new SetCardInfo("Vona's Hunger", 90, Rarity.RARE, mage.cards.v.VonasHunger.class)); - cards.add(new SetCardInfo("Vraska's Conquistador", 199, Rarity.UNCOMMON, mage.cards.v.VraskasConquistador.class)); - cards.add(new SetCardInfo("Vraska's Scorn", 200, Rarity.RARE, mage.cards.v.VraskasScorn.class)); - cards.add(new SetCardInfo("Vraska, Scheming Gorgon", 197, Rarity.MYTHIC, mage.cards.v.VraskaSchemingGorgon.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 RivalsOfIxalan extends ExpansionSet { + + private static final RivalsOfIxalan instance = new RivalsOfIxalan(); + + public static RivalsOfIxalan getInstance() { + return instance; + } + + private RivalsOfIxalan() { + super("Rivals of Ixalan", "RIX", ExpansionSet.buildDate(2018, 1, 19), SetType.EXPANSION); + this.blockName = "Ixalan"; + this.parentSet = Ixalan.getInstance(); + this.hasBoosters = true; + this.hasBasicLands = false; + this.numBoosterLands = 1; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 8; + + cards.add(new SetCardInfo("Angrath's Ambusher", 202, Rarity.UNCOMMON, mage.cards.a.AngrathsAmbusher.class)); + cards.add(new SetCardInfo("Angrath's Fury", 204, Rarity.RARE, mage.cards.a.AngrathsFury.class)); + cards.add(new SetCardInfo("Angrath, Minotaur Pirate", 201, Rarity.MYTHIC, mage.cards.a.AngrathMinotaurPirate.class)); + cards.add(new SetCardInfo("Brass's Bounty", 94, Rarity.RARE, mage.cards.b.BrasssBounty.class)); + cards.add(new SetCardInfo("Captain's Hook", 177, Rarity.RARE, mage.cards.c.CaptainsHook.class)); + cards.add(new SetCardInfo("Cinder Barrens", 205, Rarity.RARE, mage.cards.c.CinderBarrens.class)); + cards.add(new SetCardInfo("Dusk Charger", 69, Rarity.COMMON, mage.cards.d.DuskCharger.class)); + cards.add(new SetCardInfo("Evolving Wilds", 186, Rarity.RARE, mage.cards.e.EvolvingWilds.class)); + cards.add(new SetCardInfo("Ghalta, Primal Hunger", 130, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class)); + cards.add(new SetCardInfo("Glorious Destiny", 18, Rarity.RARE, mage.cards.g.GloriousDestiny.class)); + cards.add(new SetCardInfo("Paladin of Atonement", 16, Rarity.RARE, mage.cards.p.PaladinOfAtonement.class)); + cards.add(new SetCardInfo("Silvergill Adept", 53, Rarity.UNCOMMON, mage.cards.s.SilvergillAdept.class)); + cards.add(new SetCardInfo("Storm the Vault", 173, Rarity.RARE, mage.cards.s.StormTheVault.class)); + cards.add(new SetCardInfo("Swab Goblin", 203, Rarity.COMMON, mage.cards.s.SwabGoblin.class)); + cards.add(new SetCardInfo("Tetzimoc, Primal Death", 86, Rarity.RARE, mage.cards.t.TetzimocPrimalDeath.class)); + cards.add(new SetCardInfo("The Immortal Sun", 180, Rarity.MYTHIC, mage.cards.t.TheImmortalSun.class)); + cards.add(new SetCardInfo("Vampire Champion", 198, Rarity.COMMON, mage.cards.v.VampireChampion.class)); + cards.add(new SetCardInfo("Vault of Catlacan", 173, Rarity.RARE, mage.cards.v.VaultOfCatlacan.class)); + cards.add(new SetCardInfo("Vona's Hunger", 90, Rarity.RARE, mage.cards.v.VonasHunger.class)); + cards.add(new SetCardInfo("Vraska's Conquistador", 199, Rarity.UNCOMMON, mage.cards.v.VraskasConquistador.class)); + cards.add(new SetCardInfo("Vraska's Scorn", 200, Rarity.RARE, mage.cards.v.VraskasScorn.class)); + cards.add(new SetCardInfo("Vraska, Scheming Gorgon", 197, Rarity.MYTHIC, mage.cards.v.VraskaSchemingGorgon.class)); + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/LiveLostLastTurnCondition.java b/Mage/src/main/java/mage/abilities/condition/common/LiveLostLastTurnCondition.java new file mode 100644 index 0000000000..61fd4c49fe --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/LiveLostLastTurnCondition.java @@ -0,0 +1,54 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.game.Game; +import mage.watchers.WatcherUtils; +import mage.watchers.common.PlayerLostLifeWatcher; + +/** + * + * @author LevelX + */ +public enum LiveLostLastTurnCondition implements Condition { + + instance; + + @Override + public boolean apply(Game game, Ability source) { + PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName()); + if (watcher != null) { + return watcher.getLiveLostLastTurn(source.getControllerId()) > 0; + } else { + WatcherUtils.logMissingWatcher(game, source, PlayerLostLifeWatcher.class, this.getClass()); + } + return false; + } +} diff --git a/Mage/src/main/java/mage/abilities/decorator/ConditionalTriggeredAbility.java b/Mage/src/main/java/mage/abilities/decorator/ConditionalTriggeredAbility.java index 33a9dc10a7..a450227a67 100644 --- a/Mage/src/main/java/mage/abilities/decorator/ConditionalTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/decorator/ConditionalTriggeredAbility.java @@ -19,7 +19,7 @@ public class ConditionalTriggeredAbility extends TriggeredAbilityImpl { protected TriggeredAbility ability; protected Condition condition; - protected String text; + protected String abilityText; /** * Triggered ability with a condition. Set the optionality for the trigger @@ -27,22 +27,22 @@ public class ConditionalTriggeredAbility extends TriggeredAbilityImpl { * * @param ability * @param condition - * @param text if null or empty, the rule text of the triggered ability - * itself is used. + * @param text explicit rule text for the ability, if null or empty, the + * rule text generated by the triggered ability itself is used. */ public ConditionalTriggeredAbility(TriggeredAbility ability, Condition condition, String text) { super(ability.getZone(), null); this.ability = ability; this.modes = ability.getModes(); this.condition = condition; - this.text = text; + this.abilityText = text; } public ConditionalTriggeredAbility(final ConditionalTriggeredAbility triggered) { super(triggered); this.ability = triggered.ability.copy(); this.condition = triggered.condition; - this.text = triggered.text; + this.abilityText = triggered.abilityText; } @Override @@ -69,10 +69,10 @@ public class ConditionalTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - if (text == null || text.isEmpty()) { + if (abilityText == null || abilityText.isEmpty()) { return ability.getRule(); } - return text; + return abilityText; } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/AscendEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/AscendEffect.java index 11d7bbba84..be290d6eac 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/AscendEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/AscendEffect.java @@ -29,12 +29,9 @@ package mage.abilities.effects.keyword; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.AscendAbility; import mage.constants.Outcome; -import mage.designations.CitysBlessing; -import mage.designations.DesignationType; -import mage.filter.StaticFilters; import mage.game.Game; -import mage.players.Player; /** * @@ -44,7 +41,7 @@ public class AscendEffect extends OneShotEffect { public AscendEffect() { super(Outcome.Detriment); - staticText = "Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)
"; + staticText = AscendAbility.ASCEND_RULE + "
"; } public AscendEffect(final AscendEffect effect) { @@ -58,20 +55,6 @@ public class AscendEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - if (game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE_ENCHANTMENT_OR_LAND, controller.getId(), game) > 9) { - if (!controller.hasDesignation(DesignationType.CITYS_BLESSING)) { - controller.addDesignation(new CitysBlessing()); - game.informPlayers(controller.getLogName() + " gets the city's blessing for the rest of the game."); - } else { - game.informPlayers(controller.getLogName() + " already has the city's blessing."); - } - } else { - game.informPlayers(controller.getLogName() + " does not get the city's blessing."); - } - return true; - } - return false; + return AscendAbility.checkAscend(game, source, true); } } diff --git a/Mage/src/main/java/mage/abilities/keyword/AscendAbility.java b/Mage/src/main/java/mage/abilities/keyword/AscendAbility.java new file mode 100644 index 0000000000..0f35ff9d01 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/AscendAbility.java @@ -0,0 +1,115 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.abilities.keyword; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import static mage.abilities.keyword.AscendAbility.ASCEND_RULE; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.constants.Zone; +import mage.designations.CitysBlessing; +import mage.designations.DesignationType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author LevelX2 + */ +public class AscendAbility extends SimpleStaticAbility { + + public static String ASCEND_RULE = "Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)"; + + public AscendAbility() { + super(Zone.BATTLEFIELD, new AscendContinuousEffect()); + } + + public AscendAbility(final AscendAbility ability) { + super(ability); + } + + @Override + public AscendAbility copy() { + return new AscendAbility(this); + } + + public static boolean checkAscend(Game game, Ability source, boolean verbose) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + if (!controller.hasDesignation(DesignationType.CITYS_BLESSING)) { + if (game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE_ENCHANTMENT_OR_LAND, controller.getId(), game) > 9) { + controller.addDesignation(new CitysBlessing()); + game.informPlayers(controller.getLogName() + " gets the city's blessing for the rest of the game."); + } else { + if (verbose) { + game.informPlayers(controller.getLogName() + " does not get the city's blessing."); + } + } + } else { + if (verbose) { + game.informPlayers(controller.getLogName() + " already has the city's blessing."); + } + } + return true; + } + return false; + } + + @Override + public String getRule() { + return ASCEND_RULE; + } + +} + +class AscendContinuousEffect extends ContinuousEffectImpl { + + public AscendContinuousEffect() { + super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit); + staticText = ASCEND_RULE; + } + + public AscendContinuousEffect(final AscendContinuousEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return AscendAbility.checkAscend(game, source, false); + } + + @Override + public AscendContinuousEffect copy() { + return new AscendContinuousEffect(this); + } +} diff --git a/Mage/src/main/java/mage/filter/StaticFilters.java b/Mage/src/main/java/mage/filter/StaticFilters.java index 0e7f18bc02..6600612341 100644 --- a/Mage/src/main/java/mage/filter/StaticFilters.java +++ b/Mage/src/main/java/mage/filter/StaticFilters.java @@ -61,6 +61,7 @@ public final class StaticFilters { public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURE = new FilterCreaturePermanent(); public static final FilterCreaturePermanent FILTER_PERMANENT_A_CREATURE = new FilterCreaturePermanent("a creature"); public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURES = new FilterCreaturePermanent("creatures"); + public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURES_CONTROLLED = new FilterCreaturePermanent("creatures you control"); public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURE_GOBLINS = new FilterCreaturePermanent(SubType.GOBLIN, "Goblin creatures"); public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURE_SLIVERS = new FilterCreaturePermanent(SubType.SLIVER, "all Sliver creatures"); public static final FilterPlaneswalkerPermanent FILTER_PERMANENT_PLANESWALKER = new FilterPlaneswalkerPermanent(); @@ -108,6 +109,8 @@ public final class StaticFilters { FILTER_ATTACKING_CREATURES.add(new AttackingPredicate()); + FILTER_PERMANENT_CREATURES_CONTROLLED.add(new ControllerPredicate(TargetController.YOU)); + FILTER_PERMANENT_ARTIFACT_OR_CREATURE.add(Predicates.or( new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.CREATURE) diff --git a/Mage/src/main/java/mage/watchers/WatcherUtils.java b/Mage/src/main/java/mage/watchers/WatcherUtils.java new file mode 100644 index 0000000000..ec717a9822 --- /dev/null +++ b/Mage/src/main/java/mage/watchers/WatcherUtils.java @@ -0,0 +1,46 @@ +/* + * 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.watchers; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.game.Game; +import org.apache.log4j.Logger; + +/** + * + * @author LevelX2 + */ +public final class WatcherUtils { + + public static void logMissingWatcher(Game game, Ability source, Class watcherClass, Class usingClass) { + MageObject sourceObject = source.getSourceObject(game); + Logger.getLogger(usingClass).error("Needed watcher is not started " + watcherClass.getSimpleName() + + " - " + (sourceObject == null ? " no source object" : sourceObject.getName())); + } +} diff --git a/Mage/src/main/java/mage/watchers/common/PlayerLostLifeWatcher.java b/Mage/src/main/java/mage/watchers/common/PlayerLostLifeWatcher.java index 462f2db408..9dce3c3c5b 100644 --- a/Mage/src/main/java/mage/watchers/common/PlayerLostLifeWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/PlayerLostLifeWatcher.java @@ -38,7 +38,7 @@ import mage.watchers.Watcher; /* * Counts amount of life lost current or last turn by players. - * This watcher is always added in gameImpl.init + * This watcher is automatically started in gameImpl.init for each game * * @author LevelX2 */ diff --git a/Utils/keywords.txt b/Utils/keywords.txt index 875ab52c00..f78722fbbb 100644 --- a/Utils/keywords.txt +++ b/Utils/keywords.txt @@ -1,5 +1,6 @@ Afflict|number| Annihilator|number| +Ascend|new| Basic landcycling|cost| Battle cry|new| Bestow|card, manaString|