From 4e194d965e9e44647f5dce5dd1cb6dbe859ab850 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 18 Sep 2017 14:45:56 -0400 Subject: [PATCH 1/8] fixed error with Sunbird's Invocation (#4022) --- Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java b/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java index e451faaa090..77e7a088f6c 100644 --- a/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java +++ b/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java @@ -92,7 +92,7 @@ class SunbirdsInvocationTriggeredAbility extends SpellCastControllerTriggeredAbi if (spell != null && spell.getFromZone() == Zone.HAND) { if (spell.getCard() != null) { for (Effect effect : getEffects()) { - effect.setTargetPointer(new FixedTarget(spell.getId(), spell.getZoneChangeCounter(game))); + effect.setTargetPointer(new FixedTarget(spell.getId())); } return true; } @@ -125,8 +125,16 @@ class SunbirdsInvocationEffect extends OneShotEffect { if (controller == null || sourceObject == null) { return false; } + Spell spell = game.getStack().getSpell(this.getTargetPointer().getFirst(game, source)); + int xValue = 0; + if (spell == null) { + spell = (Spell) game.getLastKnownInformation(this.getTargetPointer().getFirst(game, source), Zone.STACK); + } + if (spell == null) { + return false; + } + xValue = spell.getConvertedManaCost(); Cards cards = new CardsImpl(); - int xValue = game.getLastKnownInformation(this.getTargetPointer().getFirst(game, source), Zone.STACK).getConvertedManaCost(); cards.addAll(controller.getLibrary().getTopCards(game, xValue)); if (!cards.isEmpty()) { controller.revealCards(sourceObject.getIdName(), cards, game); @@ -138,7 +146,7 @@ class SunbirdsInvocationEffect extends OneShotEffect { if (controller.chooseTarget(Outcome.PlayForFree, cards, target, source, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { - if (controller.chooseUse(outcome, "Do you wish to cast " + card.getName(), source, game)) { + if (controller.chooseUse(outcome, "Cast " + card.getLogName() + " without paying its mana cost?", source, game)) { controller.cast(card.getSpellAbility(), game, true); cards.remove(card); } From e3245c496c2e4f0f6df67ee48be2c801c3b1479c Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 18 Sep 2017 15:29:19 -0400 Subject: [PATCH 2/8] fixed Ixalan's Binding preventing both players from casting spells --- Mage.Sets/src/mage/cards/i/IxalansBinding.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Mage.Sets/src/mage/cards/i/IxalansBinding.java b/Mage.Sets/src/mage/cards/i/IxalansBinding.java index 0e562625f03..1e41ce332e2 100644 --- a/Mage.Sets/src/mage/cards/i/IxalansBinding.java +++ b/Mage.Sets/src/mage/cards/i/IxalansBinding.java @@ -107,6 +107,9 @@ class IxalansBindingReplacementEffect extends ContinuousRuleModifyingEffectImpl public boolean applies(GameEvent event, Ability source, Game game) { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); Card card = game.getCard(event.getSourceId()); + if(event.getPlayerId().equals(source.getControllerId())){ + return false; + } if (sourcePermanent != null && card != null) { UUID exileZone = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); if (exileZone != null) { From 7bb7754bb31a9c4b6f10473520b591c2786bc95e Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 18 Sep 2017 17:02:55 -0400 Subject: [PATCH 3/8] Updated how spell triggers get information about the spell that triggered them. This prevents countering the spell from removing the effect of the trigger. --- Mage.Sets/src/mage/cards/b/BloodbondMarch.java | 2 +- Mage.Sets/src/mage/cards/b/BounteousKirin.java | 4 ++-- Mage.Sets/src/mage/cards/c/CelestialKirin.java | 4 ++-- .../src/mage/cards/c/ChandraTheFirebrand.java | 2 +- Mage.Sets/src/mage/cards/c/CloudhoofKirin.java | 6 +++--- Mage.Sets/src/mage/cards/c/ClovenCasting.java | 2 +- Mage.Sets/src/mage/cards/c/CurseOfEchoes.java | 4 ++-- Mage.Sets/src/mage/cards/d/Dovescape.java | 6 +----- .../src/mage/cards/e/EndrekSahrMasterBreeder.java | 6 +----- Mage.Sets/src/mage/cards/h/HiveMind.java | 8 ++------ Mage.Sets/src/mage/cards/h/HowlOfTheHorde.java | 2 +- Mage.Sets/src/mage/cards/i/InfernalKirin.java | 8 ++++---- .../src/mage/cards/k/KaervekTheMerciless.java | 9 ++++----- .../src/mage/cards/m/MetallurgicSummonings.java | 6 +----- Mage.Sets/src/mage/cards/m/Mirari.java | 2 +- Mage.Sets/src/mage/cards/p/PrimalWellspring.java | 2 +- .../src/mage/cards/p/PyromancerAscension.java | 2 +- .../src/mage/cards/p/PyromancersGoggles.java | 2 +- Mage.Sets/src/mage/cards/r/RamosDragonEngine.java | 2 +- .../src/mage/cards/r/RikuOfTwoReflections.java | 2 +- .../src/mage/cards/s/SunbirdsInvocation.java | 8 ++------ Mage.Sets/src/mage/cards/s/SwarmIntelligence.java | 2 +- Mage.Sets/src/mage/cards/z/ZadaHedronGrinder.java | 5 +---- .../effects/common/CopyTargetSpellEffect.java | 15 ++++++++++++++- Mage/src/main/java/mage/game/Game.java | 5 +++++ Mage/src/main/java/mage/game/GameImpl.java | 14 ++++++++++++++ 26 files changed, 69 insertions(+), 61 deletions(-) diff --git a/Mage.Sets/src/mage/cards/b/BloodbondMarch.java b/Mage.Sets/src/mage/cards/b/BloodbondMarch.java index da7b086ba98..de0ab798e89 100644 --- a/Mage.Sets/src/mage/cards/b/BloodbondMarch.java +++ b/Mage.Sets/src/mage/cards/b/BloodbondMarch.java @@ -85,7 +85,7 @@ public class BloodbondMarch extends CardImpl { return false; } - Spell spell = (Spell) game.getStack().getStackObject(targetPointer.getFirst(game, source)); + Spell spell = game.getSpellOrLKIStack(this.getTargetPointer().getFirst(game, source)); if (spell == null) { return false; diff --git a/Mage.Sets/src/mage/cards/b/BounteousKirin.java b/Mage.Sets/src/mage/cards/b/BounteousKirin.java index afcd8911c14..5a3ae7a8fac 100644 --- a/Mage.Sets/src/mage/cards/b/BounteousKirin.java +++ b/Mage.Sets/src/mage/cards/b/BounteousKirin.java @@ -48,7 +48,7 @@ import mage.players.Player; public class BounteousKirin extends CardImpl { public BounteousKirin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}{G}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.KIRIN, SubType.SPIRIT); @@ -89,7 +89,7 @@ class BounteousKirinEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getState().getStack().getSpell(getTargetPointer().getFirst(game, source)); + Spell spell = game.getSpellOrLKIStack(this.getTargetPointer().getFirst(game, source)); if (spell != null) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { diff --git a/Mage.Sets/src/mage/cards/c/CelestialKirin.java b/Mage.Sets/src/mage/cards/c/CelestialKirin.java index 678da2418de..3082e74b94d 100644 --- a/Mage.Sets/src/mage/cards/c/CelestialKirin.java +++ b/Mage.Sets/src/mage/cards/c/CelestialKirin.java @@ -50,7 +50,7 @@ import mage.game.stack.Spell; public class CelestialKirin extends CardImpl { public CelestialKirin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.KIRIN); this.subtype.add(SubType.SPIRIT); @@ -92,7 +92,7 @@ class CelestialKirinEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getState().getStack().getSpell(getTargetPointer().getFirst(game, source)); + Spell spell = game.getSpellOrLKIStack(this.getTargetPointer().getFirst(game, source)); if (spell != null) { int cmc = spell.getConvertedManaCost(); FilterPermanent filter = new FilterPermanent(); diff --git a/Mage.Sets/src/mage/cards/c/ChandraTheFirebrand.java b/Mage.Sets/src/mage/cards/c/ChandraTheFirebrand.java index e98cd3a959d..1d474d1b251 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraTheFirebrand.java +++ b/Mage.Sets/src/mage/cards/c/ChandraTheFirebrand.java @@ -91,7 +91,7 @@ public class ChandraTheFirebrand extends CardImpl { class ChandraTheFirebrandAbility extends DelayedTriggeredAbility { ChandraTheFirebrandAbility() { - super(new CopyTargetSpellEffect(), Duration.EndOfTurn); + super(new CopyTargetSpellEffect(true), Duration.EndOfTurn); } ChandraTheFirebrandAbility(final ChandraTheFirebrandAbility ability) { diff --git a/Mage.Sets/src/mage/cards/c/CloudhoofKirin.java b/Mage.Sets/src/mage/cards/c/CloudhoofKirin.java index 8cc24f3b144..2494270a629 100644 --- a/Mage.Sets/src/mage/cards/c/CloudhoofKirin.java +++ b/Mage.Sets/src/mage/cards/c/CloudhoofKirin.java @@ -54,7 +54,7 @@ import mage.target.TargetPlayer; public class CloudhoofKirin extends CardImpl { public CloudhoofKirin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.KIRIN); this.subtype.add(SubType.SPIRIT); @@ -98,10 +98,10 @@ class CloudhoofKirinEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); + Spell spell = game.getSpellOrLKIStack(this.getTargetPointer().getFirst(game, source)); if (spell != null) { Player targetPlayer = null; - for(Target target: source.getTargets()) { + for (Target target : source.getTargets()) { if (target instanceof TargetPlayer) { targetPlayer = game.getPlayer(target.getFirstTarget()); } diff --git a/Mage.Sets/src/mage/cards/c/ClovenCasting.java b/Mage.Sets/src/mage/cards/c/ClovenCasting.java index eea8864f432..107ed2c49da 100644 --- a/Mage.Sets/src/mage/cards/c/ClovenCasting.java +++ b/Mage.Sets/src/mage/cards/c/ClovenCasting.java @@ -60,7 +60,7 @@ public class ClovenCasting extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{5}{U}{R}"); // Whenever you cast a multicolored instant or sorcery spell, you may pay {1}. If you do, copy that spell. You may choose new targets for the copy. - Effect effect = new CopyTargetSpellEffect(); + Effect effect = new CopyTargetSpellEffect(true); effect.setText("copy that spell. You may choose new targets for the copy"); this.addAbility(new SpellCastControllerTriggeredAbility(new DoIfCostPaid(effect, new GenericManaCost(1)), filter, true, true)); } diff --git a/Mage.Sets/src/mage/cards/c/CurseOfEchoes.java b/Mage.Sets/src/mage/cards/c/CurseOfEchoes.java index b7f238deb80..96e43762b90 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfEchoes.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfEchoes.java @@ -58,7 +58,7 @@ import mage.target.targetpointer.FixedTarget; public class CurseOfEchoes extends CardImpl { public CurseOfEchoes(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{4}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{U}"); this.subtype.add(SubType.AURA, SubType.CURSE); // Enchant player @@ -143,7 +143,7 @@ class CurseOfEchoesEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); + Spell spell = game.getSpellOrLKIStack(this.getTargetPointer().getFirst(game, source)); if (spell != null) { String chooseMessage = "Copy target spell? You may choose new targets for the copy."; for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { diff --git a/Mage.Sets/src/mage/cards/d/Dovescape.java b/Mage.Sets/src/mage/cards/d/Dovescape.java index 1b97b32810c..2b8e339aa4d 100644 --- a/Mage.Sets/src/mage/cards/d/Dovescape.java +++ b/Mage.Sets/src/mage/cards/d/Dovescape.java @@ -36,7 +36,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SetTargetPointer; -import mage.constants.Zone; import mage.filter.FilterSpell; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -92,12 +91,9 @@ class DovescapeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getStack().getSpell(this.getTargetPointer().getFirst(game, source)); + Spell spell = game.getSpellOrLKIStack(this.getTargetPointer().getFirst(game, source)); int spellCMC = 0; UUID spellControllerID = null; - if (spell == null) { - spell = (Spell) game.getLastKnownInformation(this.getTargetPointer().getFirst(game, source), Zone.STACK); - } if (spell != null) { spellCMC = spell.getConvertedManaCost(); spellControllerID = spell.getControllerId(); diff --git a/Mage.Sets/src/mage/cards/e/EndrekSahrMasterBreeder.java b/Mage.Sets/src/mage/cards/e/EndrekSahrMasterBreeder.java index 8ee17fad26b..931f6885b01 100644 --- a/Mage.Sets/src/mage/cards/e/EndrekSahrMasterBreeder.java +++ b/Mage.Sets/src/mage/cards/e/EndrekSahrMasterBreeder.java @@ -43,7 +43,6 @@ import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.token.ThrullToken; import mage.game.stack.Spell; -import mage.target.targetpointer.FixedTarget; /** * @author LevelX2 @@ -95,10 +94,7 @@ class EndrekSahrMasterBreederEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); - if (spell == null) { - spell = (Spell) game.getLastKnownInformation(((FixedTarget) getTargetPointer()).getTarget(), Zone.STACK); - } + Spell spell = game.getSpellOrLKIStack(this.getTargetPointer().getFirst(game, source)); if (spell != null) { int cmc = spell.getConvertedManaCost(); if (cmc > 0) { diff --git a/Mage.Sets/src/mage/cards/h/HiveMind.java b/Mage.Sets/src/mage/cards/h/HiveMind.java index d0694c38012..a2549bea8d0 100644 --- a/Mage.Sets/src/mage/cards/h/HiveMind.java +++ b/Mage.Sets/src/mage/cards/h/HiveMind.java @@ -50,7 +50,7 @@ import mage.target.targetpointer.FixedTarget; public class HiveMind extends CardImpl { public HiveMind(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{5}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{5}{U}"); // Whenever a player casts an instant or sorcery spell, each other player copies that spell. Each of those players may choose new targets for his or her copy. this.addAbility(new HiveMindTriggeredAbility()); @@ -125,11 +125,7 @@ class HiveMindEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Spell spell; - spell = game.getStack().getSpell(((FixedTarget) getTargetPointer()).getTarget()); - if (spell == null) { // if spell e.g. was countered - spell = (Spell) game.getLastKnownInformation(((FixedTarget) getTargetPointer()).getTarget(), Zone.STACK); - } + Spell spell = game.getSpellOrLKIStack(this.getTargetPointer().getFirst(game, source)); Player player = game.getPlayer(source.getControllerId()); if (spell != null && player != null) { for (UUID playerId : game.getState().getPlayersInRange(player.getId(), game)) { diff --git a/Mage.Sets/src/mage/cards/h/HowlOfTheHorde.java b/Mage.Sets/src/mage/cards/h/HowlOfTheHorde.java index 5dba37f4c3c..d6e46210fa7 100644 --- a/Mage.Sets/src/mage/cards/h/HowlOfTheHorde.java +++ b/Mage.Sets/src/mage/cards/h/HowlOfTheHorde.java @@ -77,7 +77,7 @@ public class HowlOfTheHorde extends CardImpl { class HowlOfTheHordeDelayedTriggeredAbility extends DelayedTriggeredAbility { HowlOfTheHordeDelayedTriggeredAbility() { - super(new CopyTargetSpellEffect(), Duration.EndOfTurn); + super(new CopyTargetSpellEffect(true), Duration.EndOfTurn); } HowlOfTheHordeDelayedTriggeredAbility(final HowlOfTheHordeDelayedTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/i/InfernalKirin.java b/Mage.Sets/src/mage/cards/i/InfernalKirin.java index 90104521c5f..8ac95b840b8 100644 --- a/Mage.Sets/src/mage/cards/i/InfernalKirin.java +++ b/Mage.Sets/src/mage/cards/i/InfernalKirin.java @@ -55,7 +55,7 @@ import mage.target.TargetPlayer; public class InfernalKirin extends CardImpl { public InfernalKirin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.KIRIN); this.subtype.add(SubType.SPIRIT); @@ -100,11 +100,11 @@ class InfernalKirinEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); + Spell spell = game.getSpellOrLKIStack(this.getTargetPointer().getFirst(game, source)); if (spell != null) { int cmc = spell.getConvertedManaCost(); Player targetPlayer = null; - for(Target target: source.getTargets()) { + for (Target target : source.getTargets()) { if (target instanceof TargetPlayer) { targetPlayer = game.getPlayer(target.getFirstTarget()); } @@ -112,7 +112,7 @@ class InfernalKirinEffect extends OneShotEffect { if (targetPlayer != null) { if (!targetPlayer.getHand().isEmpty()) { targetPlayer.revealCards("Infernal Kirin", targetPlayer.getHand(), game); - for (UUID uuid: targetPlayer.getHand().copy()) { + for (UUID uuid : targetPlayer.getHand().copy()) { Card card = game.getCard(uuid); if (card != null && card.getConvertedManaCost() == cmc) { targetPlayer.discard(card, source, game); diff --git a/Mage.Sets/src/mage/cards/k/KaervekTheMerciless.java b/Mage.Sets/src/mage/cards/k/KaervekTheMerciless.java index fb626204b33..a196c1f169a 100644 --- a/Mage.Sets/src/mage/cards/k/KaervekTheMerciless.java +++ b/Mage.Sets/src/mage/cards/k/KaervekTheMerciless.java @@ -29,7 +29,6 @@ package mage.cards.k; import java.util.UUID; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SpellCastOpponentTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -51,7 +50,7 @@ import mage.target.common.TargetCreatureOrPlayer; public class KaervekTheMerciless extends CardImpl { public KaervekTheMerciless(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{B}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{R}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SHAMAN); @@ -94,9 +93,9 @@ class KaervekTheMercilessEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject spellCast = game.getObject(getTargetPointer().getFirst(game, source)); - if (spellCast instanceof Spell) { - int cost = ((Spell) spellCast).getConvertedManaCost(); + Spell spell = game.getSpellOrLKIStack(this.getTargetPointer().getFirst(game, source)); + if (spell != null) { + int cost = spell.getConvertedManaCost(); Player target = game.getPlayer(source.getFirstTarget()); if (target != null) { target.damage(cost, source.getSourceId(), game, false, true); diff --git a/Mage.Sets/src/mage/cards/m/MetallurgicSummonings.java b/Mage.Sets/src/mage/cards/m/MetallurgicSummonings.java index 56c3273bad4..cdd7b429e61 100644 --- a/Mage.Sets/src/mage/cards/m/MetallurgicSummonings.java +++ b/Mage.Sets/src/mage/cards/m/MetallurgicSummonings.java @@ -51,7 +51,6 @@ import mage.game.Game; import mage.game.permanent.token.MetallurgicSummoningsConstructToken; import mage.game.stack.Spell; import mage.players.Player; -import mage.target.targetpointer.FixedTarget; /** * @@ -106,10 +105,7 @@ class MetallurgicSummoningsTokenEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); - if (spell == null) { - spell = (Spell) game.getLastKnownInformation(((FixedTarget) getTargetPointer()).getTarget(), Zone.STACK); - } + Spell spell = game.getSpellOrLKIStack(this.getTargetPointer().getFirst(game, source)); if (spell != null) { int cmc = spell.getConvertedManaCost(); if (cmc > 0) { diff --git a/Mage.Sets/src/mage/cards/m/Mirari.java b/Mage.Sets/src/mage/cards/m/Mirari.java index 7a657a5fd89..f9732899095 100644 --- a/Mage.Sets/src/mage/cards/m/Mirari.java +++ b/Mage.Sets/src/mage/cards/m/Mirari.java @@ -84,7 +84,7 @@ class MirariTriggeredAbility extends TriggeredAbilityImpl { } MirariTriggeredAbility() { - super(Zone.BATTLEFIELD, new DoIfCostPaid(new CopyTargetSpellEffect(), new GenericManaCost(3)), false); + super(Zone.BATTLEFIELD, new DoIfCostPaid(new CopyTargetSpellEffect(true), new GenericManaCost(3)), false); this.addTarget(new TargetSpell(filter)); } diff --git a/Mage.Sets/src/mage/cards/p/PrimalWellspring.java b/Mage.Sets/src/mage/cards/p/PrimalWellspring.java index cbdbae5b85c..fe6bcfba62b 100644 --- a/Mage.Sets/src/mage/cards/p/PrimalWellspring.java +++ b/Mage.Sets/src/mage/cards/p/PrimalWellspring.java @@ -59,7 +59,7 @@ public class PrimalWellspring extends CardImpl { this.addAbility(ability); // When that mana is spent to cast an instant or sorcery spell, copy that spell and you may choose new targets for the copy. - Effect effect = new CopyTargetSpellEffect(); + Effect effect = new CopyTargetSpellEffect(true); effect.setText("copy that spell and you may choose new targets for the copy"); this.addAbility(new PyrimalWellspringTriggeredAbility(ability.getOriginalId(), effect)); } diff --git a/Mage.Sets/src/mage/cards/p/PyromancerAscension.java b/Mage.Sets/src/mage/cards/p/PyromancerAscension.java index 556835d0473..21a6ac5d85e 100644 --- a/Mage.Sets/src/mage/cards/p/PyromancerAscension.java +++ b/Mage.Sets/src/mage/cards/p/PyromancerAscension.java @@ -127,7 +127,7 @@ class PyromancerAscensionQuestTriggeredAbility extends TriggeredAbilityImpl { class PyromancerAscensionCopyTriggeredAbility extends TriggeredAbilityImpl { PyromancerAscensionCopyTriggeredAbility() { - super(Zone.BATTLEFIELD, new CopyTargetSpellEffect(), true); + super(Zone.BATTLEFIELD, new CopyTargetSpellEffect(true), true); } PyromancerAscensionCopyTriggeredAbility(final PyromancerAscensionCopyTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/p/PyromancersGoggles.java b/Mage.Sets/src/mage/cards/p/PyromancersGoggles.java index fd658c276eb..bc8b0429891 100644 --- a/Mage.Sets/src/mage/cards/p/PyromancersGoggles.java +++ b/Mage.Sets/src/mage/cards/p/PyromancersGoggles.java @@ -62,7 +62,7 @@ public class PyromancersGoggles extends CardImpl { this.addAbility(ability); // When that mana is used to cast a red instant or sorcery spell, copy that spell and you may choose new targets for the copy. - Effect effect = new CopyTargetSpellEffect(); + Effect effect = new CopyTargetSpellEffect(true); effect.setText("copy that spell and you may choose new targets for the copy"); this.addAbility(new PyromancersGogglesTriggeredAbility(ability.getOriginalId(), effect)); diff --git a/Mage.Sets/src/mage/cards/r/RamosDragonEngine.java b/Mage.Sets/src/mage/cards/r/RamosDragonEngine.java index e6fc90f0e12..7453ae445f7 100644 --- a/Mage.Sets/src/mage/cards/r/RamosDragonEngine.java +++ b/Mage.Sets/src/mage/cards/r/RamosDragonEngine.java @@ -101,7 +101,7 @@ class RamosDragonEngineAddCountersEffect extends OneShotEffect { Player you = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); if (you != null && permanent != null) { - Spell spell = game.getStack().getSpell(this.getTargetPointer().getFirst(game, source)); + Spell spell = game.getSpellOrLKIStack(this.getTargetPointer().getFirst(game, source)); if (spell != null) { int amount = 0; if (spell.getColor(game).isWhite()) { diff --git a/Mage.Sets/src/mage/cards/r/RikuOfTwoReflections.java b/Mage.Sets/src/mage/cards/r/RikuOfTwoReflections.java index b9c21392346..78b85688e7f 100644 --- a/Mage.Sets/src/mage/cards/r/RikuOfTwoReflections.java +++ b/Mage.Sets/src/mage/cards/r/RikuOfTwoReflections.java @@ -78,7 +78,7 @@ public class RikuOfTwoReflections extends CardImpl { this.toughness = new MageInt(2); // Whenever you cast an instant or sorcery spell, you may pay {U}{R}. If you do, copy that spell. You may choose new targets for the copy. - Effect effect = new CopyTargetSpellEffect(); + Effect effect = new CopyTargetSpellEffect(true); effect.setText("copy that spell. You may choose new targets for the copy"); this.addAbility(new SpellCastControllerTriggeredAbility(new DoIfCostPaid(effect, new ManaCostsImpl("{U}{R}")), filter, false, true)); diff --git a/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java b/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java index 77e7a088f6c..0b934660f81 100644 --- a/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java +++ b/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java @@ -125,15 +125,11 @@ class SunbirdsInvocationEffect extends OneShotEffect { if (controller == null || sourceObject == null) { return false; } - Spell spell = game.getStack().getSpell(this.getTargetPointer().getFirst(game, source)); - int xValue = 0; - if (spell == null) { - spell = (Spell) game.getLastKnownInformation(this.getTargetPointer().getFirst(game, source), Zone.STACK); - } + Spell spell = game.getSpellOrLKIStack(this.getTargetPointer().getFirst(game, source)); if (spell == null) { return false; } - xValue = spell.getConvertedManaCost(); + int xValue = spell.getConvertedManaCost(); Cards cards = new CardsImpl(); cards.addAll(controller.getLibrary().getTopCards(game, xValue)); if (!cards.isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/s/SwarmIntelligence.java b/Mage.Sets/src/mage/cards/s/SwarmIntelligence.java index b6418efb89e..4c1c1064b62 100644 --- a/Mage.Sets/src/mage/cards/s/SwarmIntelligence.java +++ b/Mage.Sets/src/mage/cards/s/SwarmIntelligence.java @@ -46,7 +46,7 @@ public class SwarmIntelligence extends CardImpl { // Whenever you cast an instant or sorcery spell, you may copy that spell. You may choose new targets for the copy. this.addAbility(new SpellCastControllerTriggeredAbility( - new CopyTargetSpellEffect().setText("you may copy that spell. You may choose new targets for the copy"), new FilterInstantOrSorcerySpell("an instant or sorcery spell"), true, true)); + new CopyTargetSpellEffect(true).setText("you may copy that spell. You may choose new targets for the copy"), new FilterInstantOrSorcerySpell("an instant or sorcery spell"), true, true)); } public SwarmIntelligence(final SwarmIntelligence card) { diff --git a/Mage.Sets/src/mage/cards/z/ZadaHedronGrinder.java b/Mage.Sets/src/mage/cards/z/ZadaHedronGrinder.java index 90ffe363c1a..d4498f3f01b 100644 --- a/Mage.Sets/src/mage/cards/z/ZadaHedronGrinder.java +++ b/Mage.Sets/src/mage/cards/z/ZadaHedronGrinder.java @@ -154,10 +154,7 @@ class ZadaHedronGrinderEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); - if (spell == null) { - spell = (Spell) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.STACK); - } + Spell spell = game.getSpellOrLKIStack(this.getTargetPointer().getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); if (spell != null && controller != null) { // search the target that targets source diff --git a/Mage/src/main/java/mage/abilities/effects/common/CopyTargetSpellEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CopyTargetSpellEffect.java index 567dac9b351..56d50b8c409 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CopyTargetSpellEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CopyTargetSpellEffect.java @@ -43,17 +43,30 @@ import mage.players.Player; */ public class CopyTargetSpellEffect extends OneShotEffect { + private boolean useLKI = false; + public CopyTargetSpellEffect() { super(Outcome.Copy); } + public CopyTargetSpellEffect(boolean useLKI) { + super(Outcome.Copy); + this.useLKI = useLKI; + } + public CopyTargetSpellEffect(final CopyTargetSpellEffect effect) { super(effect); + this.useLKI = effect.useLKI; } @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); + Spell spell; + if (useLKI) { + spell = game.getSpellOrLKIStack(targetPointer.getFirst(game, source)); + } else { + spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); + } if (spell == null) { spell = (Spell) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.STACK); } diff --git a/Mage/src/main/java/mage/game/Game.java b/Mage/src/main/java/mage/game/Game.java index 9ac4302df8e..044e6a3ae79 100644 --- a/Mage/src/main/java/mage/game/Game.java +++ b/Mage/src/main/java/mage/game/Game.java @@ -57,6 +57,7 @@ import mage.game.match.MatchType; import mage.game.permanent.Battlefield; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentCard; +import mage.game.stack.Spell; import mage.game.stack.SpellStack; import mage.game.turn.Phase; import mage.game.turn.Step; @@ -106,6 +107,10 @@ public interface Game extends MageItem, Serializable { UUID getOwnerId(MageObject object); + Spell getSpell(UUID spellId); + + Spell getSpellOrLKIStack(UUID spellId); + Permanent getPermanent(UUID permanentId); Permanent getPermanentOrLKIBattlefield(UUID permanentId); diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index b1856a43dc8..bf310a6d29c 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -445,6 +445,20 @@ public abstract class GameImpl implements Game, Serializable { return null; } + @Override + public Spell getSpell(UUID spellId) { + return state.getStack().getSpell(spellId); + } + + @Override + public Spell getSpellOrLKIStack(UUID spellId) { + Spell spell = state.getStack().getSpell(spellId); + if (spell == null) { + spell = (Spell) this.getLastKnownInformation(spellId, Zone.STACK); + } + return spell; + } + @Override public Permanent getPermanent(UUID permanentId) { return state.getPermanent(permanentId); From b7611d2e61be5b5ae98e388de5d5c9e64115c41f Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 18 Sep 2017 18:41:03 -0400 Subject: [PATCH 4/8] Implemented Weaver of Lies --- Mage.Sets/src/mage/cards/w/WeaverOfLies.java | 121 +++++++++++++++++++ Mage.Sets/src/mage/sets/Legions.java | 1 + 2 files changed, 122 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/w/WeaverOfLies.java diff --git a/Mage.Sets/src/mage/cards/w/WeaverOfLies.java b/Mage.Sets/src/mage/cards/w/WeaverOfLies.java new file mode 100644 index 00000000000..f43b4290401 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WeaverOfLies.java @@ -0,0 +1,121 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.w; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.TurnedFaceUpSourceTriggeredAbility; +import mage.constants.SubType; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureAllEffect; +import mage.abilities.keyword.MorphAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicate; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.game.Game; +import mage.target.Target; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public class WeaverOfLies extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other creatures with a morph ability"); + + static { + filter.add(new AbilityPredicate(MorphAbility.class)); + filter.add(new AnotherPredicate()); + } + + public WeaverOfLies(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}{U}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Morph {4}{U} + this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{U}"))); + + // When Weaver of Lies is turned face up, turn any number of target creatures with a morph ability other than Weaver of Lies face down. + Ability ability = new TurnedFaceUpSourceTriggeredAbility(new WeaverOfLiesEffect(), false, false); + ability.addTarget(new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, false)); + this.addAbility(ability); + } + + public WeaverOfLies(final WeaverOfLies card) { + super(card); + } + + @Override + public WeaverOfLies copy() { + return new WeaverOfLies(this); + } +} + +class WeaverOfLiesEffect extends OneShotEffect { + + WeaverOfLiesEffect() { + super(Outcome.Benefit); + this.staticText = "turn any number of target creatures with a morph ability other than {this} face down"; + } + + WeaverOfLiesEffect(final WeaverOfLiesEffect effect) { + super(effect); + } + + @Override + public WeaverOfLiesEffect copy() { + return new WeaverOfLiesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Predicate pred = new PermanentIdPredicate(UUID.randomUUID()); + for (Target target : source.getTargets()) { + for (UUID targetId : target.getTargets()) { + pred = Predicates.or(pred, new PermanentIdPredicate(targetId)); + } + } + FilterCreaturePermanent filter = new FilterCreaturePermanent(); + filter.add(pred); + game.addEffect(new BecomesFaceDownCreatureAllEffect(filter), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/Legions.java b/Mage.Sets/src/mage/sets/Legions.java index fe75ca609d6..f6826dc59db 100644 --- a/Mage.Sets/src/mage/sets/Legions.java +++ b/Mage.Sets/src/mage/sets/Legions.java @@ -178,6 +178,7 @@ public class Legions extends ExpansionSet { cards.add(new SetCardInfo("Wall of Hope", 24, Rarity.COMMON, mage.cards.w.WallOfHope.class)); cards.add(new SetCardInfo("Warbreak Trumpeter", 116, Rarity.UNCOMMON, mage.cards.w.WarbreakTrumpeter.class)); cards.add(new SetCardInfo("Ward Sliver", 25, Rarity.UNCOMMON, mage.cards.w.WardSliver.class)); + cards.add(new SetCardInfo("Weaver of Lies", 57, Rarity.RARE, mage.cards.w.WeaverOfLies.class)); cards.add(new SetCardInfo("White Knight", 27, Rarity.UNCOMMON, mage.cards.w.WhiteKnight.class)); cards.add(new SetCardInfo("Willbender", 58, Rarity.UNCOMMON, mage.cards.w.Willbender.class)); cards.add(new SetCardInfo("Windborn Muse", 28, Rarity.RARE, mage.cards.w.WindbornMuse.class)); From ed7923c471e0ec1d35754ed2912cf2b23f7f017c Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 18 Sep 2017 18:47:02 -0400 Subject: [PATCH 5/8] Implemented Backslide --- Mage.Sets/src/mage/cards/b/Backslide.java | 113 ++++++++++++++++++++++ Mage.Sets/src/mage/sets/Onslaught.java | 1 + 2 files changed, 114 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/b/Backslide.java diff --git a/Mage.Sets/src/mage/cards/b/Backslide.java b/Mage.Sets/src/mage/cards/b/Backslide.java new file mode 100644 index 00000000000..deaf789121d --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/Backslide.java @@ -0,0 +1,113 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.b; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureAllEffect; +import mage.abilities.keyword.CyclingAbility; +import mage.abilities.keyword.MorphAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicate; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.game.Game; +import mage.target.Target; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public class Backslide extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with a morph ability"); + + static { + filter.add(new AbilityPredicate(MorphAbility.class)); + } + + public Backslide(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); + + // Turn target creature with a morph ability face down. + this.getSpellAbility().addEffect(new BackslideEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + + // Cycling {U} + this.addAbility(new CyclingAbility(new ManaCostsImpl("{U}"))); + + } + + public Backslide(final Backslide card) { + super(card); + } + + @Override + public Backslide copy() { + return new Backslide(this); + } +} + +class BackslideEffect extends OneShotEffect { + + BackslideEffect() { + super(Outcome.Benefit); + this.staticText = "Turn target creature with a morph ability face down."; + } + + BackslideEffect(final BackslideEffect effect) { + super(effect); + } + + @Override + public BackslideEffect copy() { + return new BackslideEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Predicate pred = new PermanentIdPredicate(UUID.randomUUID()); + for (Target target : source.getTargets()) { + for (UUID targetId : target.getTargets()) { + pred = Predicates.or(pred, new PermanentIdPredicate(targetId)); + } + } + FilterCreaturePermanent filter = new FilterCreaturePermanent(); + filter.add(pred); + game.addEffect(new BecomesFaceDownCreatureAllEffect(filter), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/Onslaught.java b/Mage.Sets/src/mage/sets/Onslaught.java index b38d6a752e9..0a94569ee29 100644 --- a/Mage.Sets/src/mage/sets/Onslaught.java +++ b/Mage.Sets/src/mage/sets/Onslaught.java @@ -46,6 +46,7 @@ public class Onslaught extends ExpansionSet { cards.add(new SetCardInfo("Aven Brigadier", 7, Rarity.RARE, mage.cards.a.AvenBrigadier.class)); cards.add(new SetCardInfo("Aven Fateshaper", 69, Rarity.UNCOMMON, mage.cards.a.AvenFateshaper.class)); cards.add(new SetCardInfo("Aven Soulgazer", 8, Rarity.UNCOMMON, mage.cards.a.AvenSoulgazer.class)); + cards.add(new SetCardInfo("Backslide", 70, Rarity.COMMON, mage.cards.b.Backslide.class)); cards.add(new SetCardInfo("Barkhide Mauler", 246, Rarity.COMMON, mage.cards.b.BarkhideMauler.class)); cards.add(new SetCardInfo("Barren Moor", 312, Rarity.COMMON, mage.cards.b.BarrenMoor.class)); cards.add(new SetCardInfo("Battering Craghorn", 188, Rarity.COMMON, mage.cards.b.BatteringCraghorn.class)); From 588dcc735ad034e4c32a19a56b3f30eb05bb8b14 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 18 Sep 2017 18:57:37 -0400 Subject: [PATCH 6/8] Implemented Master of the Veil --- .../src/mage/cards/m/MasterOfTheVeil.java | 120 ++++++++++++++++++ Mage.Sets/src/mage/sets/Legions.java | 1 + 2 files changed, 121 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/m/MasterOfTheVeil.java diff --git a/Mage.Sets/src/mage/cards/m/MasterOfTheVeil.java b/Mage.Sets/src/mage/cards/m/MasterOfTheVeil.java new file mode 100644 index 00000000000..47969292318 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MasterOfTheVeil.java @@ -0,0 +1,120 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.TurnedFaceUpSourceTriggeredAbility; +import mage.constants.SubType; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureAllEffect; +import mage.abilities.keyword.MorphAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicate; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.game.Game; +import mage.target.Target; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public class MasterOfTheVeil extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with a morph ability"); + + static { + filter.add(new AbilityPredicate(MorphAbility.class)); + } + + public MasterOfTheVeil(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Morph {2}{U} + this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{U}"))); + + // When Master of the Veil is turned face up, you may turn target creature with a morph ability face down. + Ability ability = new TurnedFaceUpSourceTriggeredAbility(new MasterOfTheVeilEffect(), false, true); + ability.addTarget(new TargetCreaturePermanent(1, 1, filter, false)); + this.addAbility(ability); + } + + public MasterOfTheVeil(final MasterOfTheVeil card) { + super(card); + } + + @Override + public MasterOfTheVeil copy() { + return new MasterOfTheVeil(this); + } +} + +class MasterOfTheVeilEffect extends OneShotEffect { + + MasterOfTheVeilEffect() { + super(Outcome.Benefit); + this.staticText = "turn target creature with a morph ability face down"; + } + + MasterOfTheVeilEffect(final MasterOfTheVeilEffect effect) { + super(effect); + } + + @Override + public MasterOfTheVeilEffect copy() { + return new MasterOfTheVeilEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Predicate pred = new PermanentIdPredicate(UUID.randomUUID()); + for (Target target : source.getTargets()) { + for (UUID targetId : target.getTargets()) { + pred = Predicates.or(pred, new PermanentIdPredicate(targetId)); + } + } + FilterCreaturePermanent filter = new FilterCreaturePermanent(); + filter.add(pred); + game.addEffect(new BecomesFaceDownCreatureAllEffect(filter), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/Legions.java b/Mage.Sets/src/mage/sets/Legions.java index f6826dc59db..07fb01d4605 100644 --- a/Mage.Sets/src/mage/sets/Legions.java +++ b/Mage.Sets/src/mage/sets/Legions.java @@ -133,6 +133,7 @@ public class Legions extends ExpansionSet { cards.add(new SetCardInfo("Lowland Tracker", 17, Rarity.COMMON, mage.cards.l.LowlandTracker.class)); cards.add(new SetCardInfo("Macetail Hystrodon", 106, Rarity.COMMON, mage.cards.m.MacetailHystrodon.class)); cards.add(new SetCardInfo("Magma Sliver", 107, Rarity.RARE, mage.cards.m.MagmaSliver.class)); + cards.add(new SetCardInfo("Master of the Veil", 43, Rarity.UNCOMMON, mage.cards.m.MasterOfTheVeil.class)); cards.add(new SetCardInfo("Merchant of Secrets", 44, Rarity.COMMON, mage.cards.m.MerchantOfSecrets.class)); cards.add(new SetCardInfo("Mistform Sliver", 46, Rarity.COMMON, mage.cards.m.MistformSliver.class)); cards.add(new SetCardInfo("Mistform Ultimus", 47, Rarity.RARE, mage.cards.m.MistformUltimus.class)); From 06ad8e65abf3a6d2a826ef10daf11e3a32b187c8 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 18 Sep 2017 20:16:24 -0400 Subject: [PATCH 7/8] Reverted Atarka, Worldrender to before text change implementation --- .../src/mage/cards/a/AtarkaWorldRender.java | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/Mage.Sets/src/mage/cards/a/AtarkaWorldRender.java b/Mage.Sets/src/mage/cards/a/AtarkaWorldRender.java index b9348f249ac..7cc32c280d6 100644 --- a/Mage.Sets/src/mage/cards/a/AtarkaWorldRender.java +++ b/Mage.Sets/src/mage/cards/a/AtarkaWorldRender.java @@ -35,14 +35,11 @@ import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.TrampleAbility; -import mage.abilities.text.TextPartSubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.TextPartSubtypePredicate; -import mage.filter.predicate.permanent.TappedPredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -68,11 +65,7 @@ public class AtarkaWorldRender extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Whenever a Dragon you control attacks, it gains double strike until end of turn. - TextPartSubType textPart1 = (TextPartSubType) addTextPart(new TextPartSubType(SubType.DRAGON)); - FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Dragon you control"); - filter.add(new TextPartSubtypePredicate(textPart1)); - filter.add(Predicates.not(new TappedPredicate())); - this.addAbility(new AtarkaWorldRenderEffect(filter)); + this.addAbility(new AtarkaWorldRenderEffect()); } @@ -88,16 +81,18 @@ public class AtarkaWorldRender extends CardImpl { class AtarkaWorldRenderEffect extends TriggeredAbilityImpl { - FilterControlledCreaturePermanent filter; + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("dragon you control"); - public AtarkaWorldRenderEffect(FilterControlledCreaturePermanent filter) { + static { + filter.add(new SubtypePredicate(SubType.DRAGON)); + } + + public AtarkaWorldRenderEffect() { super(Zone.BATTLEFIELD, new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn)); - this.filter = filter; } public AtarkaWorldRenderEffect(final AtarkaWorldRenderEffect ability) { super(ability); - this.filter = ability.filter.copy(); } @Override From 96f3896d56fd504124f138a66b1697f61c70c49e Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 18 Sep 2017 22:22:52 -0400 Subject: [PATCH 8/8] fixed Mavren Fein triggering on opponent's attacks (#4023) --- Mage.Sets/src/mage/cards/m/MavrenFeinDuskApostle.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/cards/m/MavrenFeinDuskApostle.java b/Mage.Sets/src/mage/cards/m/MavrenFeinDuskApostle.java index bd1251ac894..5f0834f82b2 100644 --- a/Mage.Sets/src/mage/cards/m/MavrenFeinDuskApostle.java +++ b/Mage.Sets/src/mage/cards/m/MavrenFeinDuskApostle.java @@ -79,7 +79,7 @@ public class MavrenFeinDuskApostle extends CardImpl { class MavrenFeinDuskApostleTriggeredAbility extends TriggeredAbilityImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken Vampire you control"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken Vampires you control"); static { filter.add(new SubtypePredicate(SubType.VAMPIRE)); @@ -109,7 +109,7 @@ class MavrenFeinDuskApostleTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { for (UUID creatureId : game.getCombat().getAttackers()) { Permanent creature = game.getPermanent(creatureId); - if (creature != null && filter.match(creature, game)) { + if (creature != null && filter.match(creature, game) && creature.getControllerId().equals(controllerId)) { return true; } }