From 40036271da302b4ae5b94fc2e4a281edf00f14df Mon Sep 17 00:00:00 2001 From: 18ths <13023067+18ths@users.noreply.github.com> Date: Wed, 24 Jun 2020 17:17:32 +0200 Subject: [PATCH] Implemented Allosaurus Shepherd and Blessed Sanctuary (#6711) * added allosaurus shepherd and blessed sanctuary * fixed nonascii apostrophes * added continuous effect dependency --- .../src/main/resources/card-pictures-tok.txt | 5 +- .../src/mage/cards/a/AllosaurusShepherd.java | 68 +++++++++++++++++++ .../src/mage/cards/b/BlessedSanctuary.java | 49 +++++++++++++ .../src/mage/cards/d/DismissIntoDream.java | 47 +++++++------ Mage.Sets/src/mage/sets/Jumpstart.java | 2 + .../PreventAllNonCombatDamageToAllEffect.java | 6 +- .../CreaturesBecomeOtherTypeEffect.java | 67 ++++++++++++++++++ .../SetPowerToughnessAllEffect.java | 4 ++ .../src/main/java/mage/constants/SubType.java | 13 ++++ .../game/permanent/token/UnicornToken.java | 27 ++++++++ 10 files changed, 264 insertions(+), 24 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/a/AllosaurusShepherd.java create mode 100644 Mage.Sets/src/mage/cards/b/BlessedSanctuary.java create mode 100644 Mage/src/main/java/mage/abilities/effects/common/continuous/CreaturesBecomeOtherTypeEffect.java create mode 100644 Mage/src/main/java/mage/game/permanent/token/UnicornToken.java diff --git a/Mage.Client/src/main/resources/card-pictures-tok.txt b/Mage.Client/src/main/resources/card-pictures-tok.txt index d259a41e0a..0609d4e9ea 100644 --- a/Mage.Client/src/main/resources/card-pictures-tok.txt +++ b/Mage.Client/src/main/resources/card-pictures-tok.txt @@ -1401,4 +1401,7 @@ |Generate|TOK:C20|Soldier|||SoldierToken| |Generate|TOK:C20|Spirit|||SpiritWhiteToken| |Generate|TOK:C20|Treasure|||TreasureToken| -|Generate|TOK:C20|Zombie|||ZombieToken| \ No newline at end of file +|Generate|TOK:C20|Zombie|||ZombieToken| + +# JMP +|Generate|TOK:JMP|Unicorn|||UnicornToken| \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/a/AllosaurusShepherd.java b/Mage.Sets/src/mage/cards/a/AllosaurusShepherd.java new file mode 100644 index 0000000000..a9ec318ff6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AllosaurusShepherd.java @@ -0,0 +1,68 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.CantBeCounteredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CantBeCounteredControlledEffect; +import mage.abilities.effects.common.continuous.CreaturesBecomeOtherTypeEffect; +import mage.abilities.effects.common.continuous.SetPowerToughnessAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.FilterSpell; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; + +import java.util.UUID; + +public class AllosaurusShepherd extends CardImpl { + + private static final FilterSpell greenSpellsFilter = new FilterSpell("green spells"); + private static final FilterPermanent elvesFilter = new FilterControlledCreaturePermanent("each Elf creature you control"); + + static { + greenSpellsFilter.add(new ColorPredicate(ObjectColor.GREEN)); + elvesFilter.add(SubType.ELF.getPredicate()); + } + + public AllosaurusShepherd(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}"); + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.SHAMAN); + + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + //Allosaurus Shepherd can't be countered. + this.addAbility(new CantBeCounteredAbility()); + + //Green spells you control can't be countered. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new CantBeCounteredControlledEffect(greenSpellsFilter, null, Duration.WhileOnBattlefield))); + + //4GG: Until end of turn, each Elf creature you control has base power and toughness 5/5 and becomes a Dinosaur in addition to its other creature types. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new SetPowerToughnessAllEffect(5, 5, Duration.EndOfTurn, elvesFilter, true) + .setText("Until end of turn, each Elf creature you control has base power and toughness 5/5"), + new ManaCostsImpl("{4}{G}{G}")); + ability.addEffect(new CreaturesBecomeOtherTypeEffect(elvesFilter, SubType.DINOSAUR, Duration.EndOfTurn) + .setText("and becomes a Dinosaur in addition to its other creature types")); + this.addAbility(ability); + + } + + public AllosaurusShepherd(final AllosaurusShepherd card) { + super(card); + } + + @Override + public AllosaurusShepherd copy() { + return new AllosaurusShepherd(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/b/BlessedSanctuary.java b/Mage.Sets/src/mage/cards/b/BlessedSanctuary.java new file mode 100644 index 0000000000..8b0099dc4d --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BlessedSanctuary.java @@ -0,0 +1,49 @@ +package mage.cards.b; + +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.PreventAllNonCombatDamageToAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.permanent.token.UnicornToken; + +import java.util.UUID; + +public class BlessedSanctuary extends CardImpl { + + private static final FilterPermanent filterYourCreatures = new FilterControlledCreaturePermanent("creatures you control"); + private static final FilterControlledCreaturePermanent filterNontoken = new FilterControlledCreaturePermanent("nontoken creature"); + + static { + filterNontoken.add(Predicates.not(TokenPredicate.instance)); + } + + public BlessedSanctuary(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{W}{W}"); + + //Prevent all noncombat damage that would be dealt to you and creatures you control. + this.addAbility(new SimpleStaticAbility(new PreventAllNonCombatDamageToAllEffect( + Duration.WhileOnBattlefield, filterYourCreatures, true))); + + //Whenever a nontoken creature enters the battlefield under your control, create a 2/2 white Unicorn creature token. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, + new CreateTokenEffect(new UnicornToken()), filterNontoken, false)); + } + + public BlessedSanctuary(final BlessedSanctuary card) { + super(card); + } + + @Override + public BlessedSanctuary copy() { + return new BlessedSanctuary(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DismissIntoDream.java b/Mage.Sets/src/mage/cards/d/DismissIntoDream.java index 16a2addbe1..2c2a2fcd09 100644 --- a/Mage.Sets/src/mage/cards/d/DismissIntoDream.java +++ b/Mage.Sets/src/mage/cards/d/DismissIntoDream.java @@ -3,13 +3,15 @@ package mage.cards.d; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.Mode; import mage.abilities.common.BecomesTargetTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.effects.common.continuous.CreaturesBecomeOtherTypeEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -20,13 +22,18 @@ import mage.game.permanent.Permanent; */ public final class DismissIntoDream extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Each creature your opponents control"); + static { + filter.add(TargetController.OPPONENT.getControllerPredicate()); + } + public DismissIntoDream(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{6}{U}"); // Each creature your opponents control is an Illusion in addition to its other types // and has "When this creature becomes the target of a spell or ability, sacrifice it." - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DismissIntoDreamEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DismissIntoDreamEffect(filter))); } public DismissIntoDream(final DismissIntoDream card) { @@ -39,16 +46,11 @@ public final class DismissIntoDream extends CardImpl { } } -class DismissIntoDreamEffect extends ContinuousEffectImpl { +class DismissIntoDreamEffect extends CreaturesBecomeOtherTypeEffect { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - - DismissIntoDreamEffect() { - super(Duration.WhileOnBattlefield, Outcome.Detriment); - this.staticText = "Each creature your opponents control is an Illusion in addition to its other types and has \"When this creature becomes the target of a spell or ability, sacrifice it.\""; + DismissIntoDreamEffect(FilterPermanent filter) { + super(filter, SubType.ILLUSION, Duration.WhileOnBattlefield); + this.outcome = Outcome.Detriment; } DismissIntoDreamEffect(final DismissIntoDreamEffect effect) { @@ -67,23 +69,24 @@ class DismissIntoDreamEffect extends ContinuousEffectImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - for (Permanent object: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { - switch (layer) { - case AbilityAddingRemovingEffects_6: - object.addAbility(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect()), source.getSourceId(), game); - break; - case TypeChangingEffects_4: - if (!object.hasSubtype(SubType.ILLUSION, game)) { - object.getSubtype(game).add(SubType.ILLUSION); - } - break; + super.apply(layer, sublayer, source, game); + + if (layer == Layer.AbilityAddingRemovingEffects_6) { + for (Permanent object: game.getBattlefield().getActivePermanents(this.filter, source.getControllerId(), game)) { + object.addAbility(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect()), source.getSourceId(), game); } } + return true; } @Override public boolean hasLayer(Layer layer) { - return layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.TypeChangingEffects_4; + return super.hasLayer(layer) || layer == Layer.AbilityAddingRemovingEffects_6; + } + + @Override + public String getText(Mode mode) { + return super.getText(mode) + " and has \"When this creature becomes the target of a spell or ability, sacrifice it.\""; } } diff --git a/Mage.Sets/src/mage/sets/Jumpstart.java b/Mage.Sets/src/mage/sets/Jumpstart.java index 6fc7e0aa64..5b61d404cd 100644 --- a/Mage.Sets/src/mage/sets/Jumpstart.java +++ b/Mage.Sets/src/mage/sets/Jumpstart.java @@ -31,6 +31,7 @@ public final class Jumpstart extends ExpansionSet { cards.add(new SetCardInfo("Agonizing Syphon", 199, Rarity.COMMON, mage.cards.a.AgonizingSyphon.class)); cards.add(new SetCardInfo("Ajani's Chosen", 82, Rarity.RARE, mage.cards.a.AjanisChosen.class)); cards.add(new SetCardInfo("Alabaster Mage", 83, Rarity.UNCOMMON, mage.cards.a.AlabasterMage.class)); + cards.add(new SetCardInfo("Allosaurus Shepherd", 28, Rarity.MYTHIC, mage.cards.a.AllosaurusShepherd.class)); cards.add(new SetCardInfo("Alloy Myr", 457, Rarity.COMMON, mage.cards.a.AlloyMyr.class)); cards.add(new SetCardInfo("Ambassador Oak", 375, Rarity.COMMON, mage.cards.a.AmbassadorOak.class)); cards.add(new SetCardInfo("Ancestral Statue", 458, Rarity.COMMON, mage.cards.a.AncestralStatue.class)); @@ -63,6 +64,7 @@ public final class Jumpstart extends ExpansionSet { cards.add(new SetCardInfo("Black Cat", 203, Rarity.COMMON, mage.cards.b.BlackCat.class)); cards.add(new SetCardInfo("Black Market", 204, Rarity.RARE, mage.cards.b.BlackMarket.class)); cards.add(new SetCardInfo("Blessed Spirits", 92, Rarity.UNCOMMON, mage.cards.b.BlessedSpirits.class)); + cards.add(new SetCardInfo("Blessed Sanctuary", 1, Rarity.RARE, mage.cards.b.BlessedSanctuary.class)); cards.add(new SetCardInfo("Blighted Bat", 205, Rarity.COMMON, mage.cards.b.BlightedBat.class)); cards.add(new SetCardInfo("Blindblast", 295, Rarity.COMMON, mage.cards.b.Blindblast.class)); cards.add(new SetCardInfo("Blood Artist", 206, Rarity.UNCOMMON, mage.cards.b.BloodArtist.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/PreventAllNonCombatDamageToAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PreventAllNonCombatDamageToAllEffect.java index 51cbe53711..49aee45b7f 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PreventAllNonCombatDamageToAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PreventAllNonCombatDamageToAllEffect.java @@ -27,7 +27,11 @@ public class PreventAllNonCombatDamageToAllEffect extends PreventionEffectImpl { super(duration, Integer.MAX_VALUE, false); this.filter = filter; this.andToYou = andToYou; - staticText = "Prevent all non combat damage that would be dealt to " + (andToYou ? "you and " : "") + filter.getMessage() + ' ' + duration.toString(); + staticText = "Prevent all non combat damage that would be dealt to " + (andToYou ? "you and " : "") + filter.getMessage(); + + if (duration != Duration.WhileOnBattlefield) { + staticText += ' ' + duration.toString(); + } } private PreventAllNonCombatDamageToAllEffect(final PreventAllNonCombatDamageToAllEffect effect) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/CreaturesBecomeOtherTypeEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/CreaturesBecomeOtherTypeEffect.java new file mode 100644 index 0000000000..e2513cac56 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/CreaturesBecomeOtherTypeEffect.java @@ -0,0 +1,67 @@ +package mage.abilities.effects.common.continuous; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; + +public class CreaturesBecomeOtherTypeEffect extends ContinuousEffectImpl { + + protected final FilterPermanent filter; + private final SubType subType; + + public CreaturesBecomeOtherTypeEffect(FilterPermanent filter, SubType subType, Duration duration) { + super(duration, Outcome.Neutral); + this.filter = filter; + this.subType = subType; + + this.dependendToTypes.add(DependencyType.BecomeCreature); // Opalescence and Starfield of Nyx + } + + protected CreaturesBecomeOtherTypeEffect(final CreaturesBecomeOtherTypeEffect effect) { + super(effect); + this.filter = effect.filter; + this.subType = effect.subType; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public CreaturesBecomeOtherTypeEffect copy() { + return new CreaturesBecomeOtherTypeEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + if (layer == Layer.TypeChangingEffects_4) { + for (Permanent object: game.getBattlefield().getActivePermanents(this.filter, source.getControllerId(), game)) { + if (!object.hasSubtype(this.subType, game)) { + object.getSubtype(game).add(this.subType); + } + } + } + + return true; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.TypeChangingEffects_4; + } + + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + + return this.filter.getMessage() + " is " + this.subType.getIndefiniteArticle() + + " " + this.subType.toString() + " in addition to its other types"; + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessAllEffect.java index edb7b8e459..ac2b5127a9 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessAllEffect.java @@ -98,6 +98,10 @@ public class SetPowerToughnessAllEffect extends ContinuousEffectImpl { @Override public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + StringBuilder sb = new StringBuilder(); sb.append(filter.getMessage()); if (filter.getMessage().toLowerCase(Locale.ENGLISH).startsWith("Each ")) { diff --git a/Mage/src/main/java/mage/constants/SubType.java b/Mage/src/main/java/mage/constants/SubType.java index 7724b09214..8fe70263a2 100644 --- a/Mage/src/main/java/mage/constants/SubType.java +++ b/Mage/src/main/java/mage/constants/SubType.java @@ -496,6 +496,19 @@ public enum SubType { return predicate; } + + public String getIndefiniteArticle() { + if (isVowel(description.charAt(0))) { + return "an"; + } else { + return "a"; + } + } + + private boolean isVowel(char c) { + return "AEIOUaeiou".indexOf(c) != -1; + } + public static SubType fromString(String value) { for (SubType st : SubType.values()) { if (st.toString().equals(value)) { diff --git a/Mage/src/main/java/mage/game/permanent/token/UnicornToken.java b/Mage/src/main/java/mage/game/permanent/token/UnicornToken.java new file mode 100644 index 0000000000..4d118d3df8 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/UnicornToken.java @@ -0,0 +1,27 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +public final class UnicornToken extends TokenImpl { + + public UnicornToken() { + super("Unicorn", "2/2 white Unicorn creature token"); + setExpansionSetCodeForImage("JMP"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.UNICORN); + color.setWhite(true); + power = new MageInt(2); + toughness = new MageInt(2); + } + + private UnicornToken(final UnicornToken token) { + super(token); + } + + @Override + public UnicornToken copy() { + return new UnicornToken(this); + } +} \ No newline at end of file