diff --git a/Mage.Sets/src/mage/cards/a/ArsenalThresher.java b/Mage.Sets/src/mage/cards/a/ArsenalThresher.java index e89e013484..6d29d90343 100644 --- a/Mage.Sets/src/mage/cards/a/ArsenalThresher.java +++ b/Mage.Sets/src/mage/cards/a/ArsenalThresher.java @@ -27,6 +27,8 @@ */ package mage.cards.a; +import java.util.ArrayList; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; @@ -45,8 +47,6 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInHand; -import java.util.UUID; - /** * * @author jeffwadsworth @@ -54,7 +54,7 @@ import java.util.UUID; public class ArsenalThresher extends CardImpl { public ArsenalThresher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{2}{W/B}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{W/B}{U}"); this.subtype.add("Construct"); this.power = new MageInt(2); @@ -109,7 +109,8 @@ class ArsenalThresherEffect extends OneShotEffect { } if (arsenalThresher != null) { controller.revealCards(arsenalThresher.getIdName(), cards, game); - arsenalThresher.addCounters(CounterType.P1P1.createInstance(cards.size()), source, game); + ArrayList appliedEffects = (ArrayList) this.getValue("appliedEffects"); // the basic event is the EntersBattlefieldEvent, so use already applied replacement effects from that event + arsenalThresher.addCounters(CounterType.P1P1.createInstance(cards.size()), source, game, appliedEffects); } } } diff --git a/Mage.Sets/src/mage/cards/b/BramblewoodParagon.java b/Mage.Sets/src/mage/cards/b/BramblewoodParagon.java index cf63da767f..363ace046d 100644 --- a/Mage.Sets/src/mage/cards/b/BramblewoodParagon.java +++ b/Mage.Sets/src/mage/cards/b/BramblewoodParagon.java @@ -27,6 +27,7 @@ */ package mage.cards.b; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -47,8 +48,6 @@ import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import java.util.UUID; - /** * * @author emerald000 @@ -62,7 +61,7 @@ public class BramblewoodParagon extends CardImpl { } public BramblewoodParagon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add("Elf"); this.subtype.add("Warrior"); this.power = new MageInt(2); @@ -120,7 +119,7 @@ class BramblewoodParagonReplacementEffect extends ReplacementEffectImpl { public boolean replaceEvent(GameEvent event, Ability source, Game game) { Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); if (creature != null) { - creature.addCounters(CounterType.P1P1.createInstance(), source, game); + creature.addCounters(CounterType.P1P1.createInstance(), source, game, event.getAppliedEffects()); } return false; } diff --git a/Mage.Sets/src/mage/cards/c/ChorusOfTheConclave.java b/Mage.Sets/src/mage/cards/c/ChorusOfTheConclave.java index 736bee7b7e..421996644d 100644 --- a/Mage.Sets/src/mage/cards/c/ChorusOfTheConclave.java +++ b/Mage.Sets/src/mage/cards/c/ChorusOfTheConclave.java @@ -27,6 +27,9 @@ */ package mage.cards.c; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -45,10 +48,6 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - /** * * @author jeffwadsworth @@ -57,7 +56,7 @@ import java.util.UUID; public class ChorusOfTheConclave extends CardImpl { public ChorusOfTheConclave(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{G}{G}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}{W}{W}"); addSuperType(SuperType.LEGENDARY); this.subtype.add("Dryad"); @@ -198,7 +197,7 @@ class ChorusOfTheConclaveReplacementEffect2 extends ReplacementEffectImpl { String key = event.getSourceId().toString() + (game.getState().getZoneChangeCounter(event.getSourceId()) - 1); int xValue = spellX.get(key); if (xValue > 0) { - creature.addCounters(CounterType.P1P1.createInstance(xValue), source, game); + creature.addCounters(CounterType.P1P1.createInstance(xValue), source, game, event.getAppliedEffects()); game.informPlayers(sourceObject.getLogName() + ": " + creature.getLogName() + " enters the battlefield with " + xValue + " +1/+1 counter" + (xValue > 1 ? "s" : "") + " on it"); } spellX.remove(key); diff --git a/Mage.Sets/src/mage/cards/d/DearlyDeparted.java b/Mage.Sets/src/mage/cards/d/DearlyDeparted.java index 4e90e35ec3..061dad9b26 100644 --- a/Mage.Sets/src/mage/cards/d/DearlyDeparted.java +++ b/Mage.Sets/src/mage/cards/d/DearlyDeparted.java @@ -27,6 +27,7 @@ */ package mage.cards.d; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -45,15 +46,13 @@ import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; -import java.util.UUID; - /** * @author nantuko */ public class DearlyDeparted extends CardImpl { public DearlyDeparted(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}"); this.subtype.add("Spirit"); this.power = new MageInt(5); @@ -104,7 +103,7 @@ class DearlyDepartedEntersBattlefieldEffect extends ReplacementEffectImpl { public boolean replaceEvent(GameEvent event, Ability source, Game game) { Permanent target = ((EntersTheBattlefieldEvent) event).getTarget(); if (target != null) { - target.addCounters(CounterType.P1P1.createInstance(), source, game); + target.addCounters(CounterType.P1P1.createInstance(), source, game, event.getAppliedEffects()); } return false; } diff --git a/Mage.Sets/src/mage/cards/l/LongRoadHome.java b/Mage.Sets/src/mage/cards/l/LongRoadHome.java index 1dbb18589f..43a94cfd71 100644 --- a/Mage.Sets/src/mage/cards/l/LongRoadHome.java +++ b/Mage.Sets/src/mage/cards/l/LongRoadHome.java @@ -58,7 +58,7 @@ import mage.target.common.TargetCreaturePermanent; public class LongRoadHome extends CardImpl { public LongRoadHome(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); // Exile target creature. At the beginning of the next end step, return that card to the battlefield under its owner's control with a +1/+1 counter on it. this.getSpellAbility().addEffect(new LongRoadHomeEffect()); @@ -163,7 +163,7 @@ class LongRoadHomeEntersBattlefieldEffect extends ReplacementEffectImpl { public LongRoadHomeEntersBattlefieldEffect(MageObjectReference objectToReturn) { super(Duration.Custom, Outcome.BoostCreature); this.objectToReturn = objectToReturn; - staticText = "that card returns to the battlefield with a +1/+1 counter on it"; + staticText = "that card to the battlefield under its owner's control with a +1/+1 counter on it"; } public LongRoadHomeEntersBattlefieldEffect(LongRoadHomeEntersBattlefieldEffect effect) { @@ -188,7 +188,7 @@ class LongRoadHomeEntersBattlefieldEffect extends ReplacementEffectImpl { public boolean replaceEvent(GameEvent event, Ability source, Game game) { Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (permanent != null) { - permanent.addCounters(CounterType.P1P1.createInstance(), source, game); + permanent.addCounters(CounterType.P1P1.createInstance(), source, game, event.getAppliedEffects()); discard(); // use only once } return false; diff --git a/Mage.Sets/src/mage/cards/n/NecromanticSummons.java b/Mage.Sets/src/mage/cards/n/NecromanticSummons.java index 025dd70559..a2c07949d2 100644 --- a/Mage.Sets/src/mage/cards/n/NecromanticSummons.java +++ b/Mage.Sets/src/mage/cards/n/NecromanticSummons.java @@ -30,17 +30,19 @@ package mage.cards.n; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.common.SpellMasteryCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.Outcome; import mage.counters.CounterType; import mage.filter.common.FilterCreatureCard; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.common.TargetCardInGraveyard; @@ -51,16 +53,15 @@ import mage.target.common.TargetCardInGraveyard; public class NecromanticSummons extends CardImpl { public NecromanticSummons(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); + this.getSpellAbility().addEffect(new NecromanticSummoningReplacementEffect());// has to be added before the moving effect // Put target creature card from a graveyard onto the battlefield under your control. this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card from a graveyard"))); // Spell mastery - If there are two or more instant and/or sorcery cards in your graveyard, that creature enters the battlefield with two additional +1/+1 counters on it. - Effect effect = new ConditionalOneShotEffect(new NecromanticSummoningEffect(), - SpellMasteryCondition.instance, "
Spell mastery - If there are two or more instant and/or sorcery cards in your graveyard, that creature enters the battlefield with two additional +1/+1 counters on it"); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(new InfoEffect("\"
Spell mastery - If there are two or more instant and/or sorcery cards in your graveyard, that creature enters the battlefield with two additional +1/+1 counters on it\"")); } public NecromanticSummons(final NecromanticSummons card) { @@ -73,29 +74,46 @@ public class NecromanticSummons extends CardImpl { } } -class NecromanticSummoningEffect extends OneShotEffect { +class NecromanticSummoningReplacementEffect extends ReplacementEffectImpl { - public NecromanticSummoningEffect() { - super(Outcome.BoostCreature); - this.staticText = "
Spell mastery - If there are two or more instant and/or sorcery cards in your graveyard, that creature enters the battlefield with two additional +1/+1 counters on it"; + NecromanticSummoningReplacementEffect() { + super(Duration.EndOfStep, Outcome.BoostCreature); } - public NecromanticSummoningEffect(final NecromanticSummoningEffect effect) { + NecromanticSummoningReplacementEffect(NecromanticSummoningReplacementEffect effect) { super(effect); } @Override - public NecromanticSummoningEffect copy() { - return new NecromanticSummoningEffect(this); + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getTargetId().equals(getTargetPointer().getFirst(game, source))) { + return SpellMasteryCondition.instance.apply(game, source); + } + return false; } @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent != null) { - permanent.addCounters(CounterType.P1P1.createInstance(2), source, game); - return true; + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); + if (creature != null) { + creature.addCounters(CounterType.P1P1.createInstance(2), source, game, event.getAppliedEffects()); + discard(); } return false; } + + @Override + public NecromanticSummoningReplacementEffect copy() { + return new NecromanticSummoningReplacementEffect(this); + } } diff --git a/Mage.Sets/src/mage/cards/o/OonasBlackguard.java b/Mage.Sets/src/mage/cards/o/OonasBlackguard.java index 9499e54389..53db6dfd14 100644 --- a/Mage.Sets/src/mage/cards/o/OonasBlackguard.java +++ b/Mage.Sets/src/mage/cards/o/OonasBlackguard.java @@ -58,7 +58,7 @@ import mage.target.targetpointer.FixedTarget; public class OonasBlackguard extends CardImpl { public OonasBlackguard(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); this.subtype.add("Faerie"); this.subtype.add("Rogue"); this.power = new MageInt(1); @@ -121,7 +121,7 @@ class OonasBlackguardReplacementEffect extends ReplacementEffectImpl { public boolean replaceEvent(GameEvent event, Ability source, Game game) { Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); if (creature != null) { - creature.addCounters(CounterType.P1P1.createInstance(), source, game); + creature.addCounters(CounterType.P1P1.createInstance(), source, game, event.getAppliedEffects()); } return false; } diff --git a/Mage.Sets/src/mage/cards/o/OtherworldlyJourney.java b/Mage.Sets/src/mage/cards/o/OtherworldlyJourney.java index 1c24520f24..3caa368577 100644 --- a/Mage.Sets/src/mage/cards/o/OtherworldlyJourney.java +++ b/Mage.Sets/src/mage/cards/o/OtherworldlyJourney.java @@ -57,7 +57,7 @@ import mage.target.common.TargetCreaturePermanent; public class OtherworldlyJourney extends CardImpl { public OtherworldlyJourney(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); this.subtype.add("Arcane"); // Exile target creature. At the beginning of the next end step, return that card to the battlefield under its owner's control with a +1/+1 counter on it. @@ -184,7 +184,7 @@ class OtherworldlyJourneyEntersBattlefieldEffect extends ReplacementEffectImpl { public boolean replaceEvent(GameEvent event, Ability source, Game game) { Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (permanent != null) { - permanent.addCounters(CounterType.P1P1.createInstance(), source, game); + permanent.addCounters(CounterType.P1P1.createInstance(), source, game, event.getAppliedEffects()); discard(); // use only once } return false; diff --git a/Mage.Sets/src/mage/cards/s/SageOfFables.java b/Mage.Sets/src/mage/cards/s/SageOfFables.java index 1191c3f0e6..8f8b69733f 100644 --- a/Mage.Sets/src/mage/cards/s/SageOfFables.java +++ b/Mage.Sets/src/mage/cards/s/SageOfFables.java @@ -56,7 +56,7 @@ import mage.target.common.TargetControlledCreaturePermanent; public class SageOfFables extends CardImpl { public SageOfFables(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); this.subtype.add("Merfolk"); this.subtype.add("Wizard"); this.power = new MageInt(2); @@ -115,7 +115,7 @@ class SageOfFablesReplacementEffect extends ReplacementEffectImpl { public boolean replaceEvent(GameEvent event, Ability source, Game game) { Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); if (creature != null) { - creature.addCounters(CounterType.P1P1.createInstance(), source, game); + creature.addCounters(CounterType.P1P1.createInstance(), source, game, event.getAppliedEffects()); } return false; } diff --git a/Mage.Sets/src/mage/cards/s/SavageSummoning.java b/Mage.Sets/src/mage/cards/s/SavageSummoning.java index fd659f974e..3986eb2461 100644 --- a/Mage.Sets/src/mage/cards/s/SavageSummoning.java +++ b/Mage.Sets/src/mage/cards/s/SavageSummoning.java @@ -64,7 +64,7 @@ import mage.watchers.Watcher; public class SavageSummoning extends CardImpl { public SavageSummoning(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}"); // Savage Summoning can't be countered. Ability ability = new CantBeCounteredAbility(); @@ -315,7 +315,7 @@ class SavageSummoningEntersBattlefieldEffect extends ReplacementEffectImpl { public boolean replaceEvent(GameEvent event, Ability source, Game game) { Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); if (creature != null) { - creature.addCounters(CounterType.P1P1.createInstance(), source, game); + creature.addCounters(CounterType.P1P1.createInstance(), source, game, event.getAppliedEffects()); } discard(); return false; diff --git a/Mage.Sets/src/mage/cards/t/ThoughtReflection.java b/Mage.Sets/src/mage/cards/t/ThoughtReflection.java index 68f161bf8f..39a743dc06 100644 --- a/Mage.Sets/src/mage/cards/t/ThoughtReflection.java +++ b/Mage.Sets/src/mage/cards/t/ThoughtReflection.java @@ -49,8 +49,8 @@ import mage.players.Player; public class ThoughtReflection extends CardImpl { public ThoughtReflection(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{4}{U}{U}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{U}{U}{U}"); + // If you would draw a card, draw two cards instead. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ThoughtReflectionReplacementEffect())); @@ -90,13 +90,13 @@ class ThoughtReflectionReplacementEffect extends ReplacementEffectImpl { @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.DRAW_CARD; - } + } @Override public boolean applies(GameEvent event, Ability source, Game game) { return event.getPlayerId().equals(source.getControllerId()); } - + @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player you = game.getPlayer(event.getPlayerId()); @@ -104,5 +104,5 @@ class ThoughtReflectionReplacementEffect extends ReplacementEffectImpl { you.drawCards(2, game, event.getAppliedEffects()); } return true; - } + } } diff --git a/Mage.Sets/src/mage/cards/v/VigorMortis.java b/Mage.Sets/src/mage/cards/v/VigorMortis.java index 7bf05119ab..4bf838e099 100644 --- a/Mage.Sets/src/mage/cards/v/VigorMortis.java +++ b/Mage.Sets/src/mage/cards/v/VigorMortis.java @@ -30,17 +30,20 @@ package mage.cards.v; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.common.ManaWasSpentCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ColoredManaSymbol; +import mage.constants.Duration; import mage.constants.Outcome; import mage.counters.CounterType; import mage.filter.common.FilterCreatureCard; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.common.TargetCardInYourGraveyard; @@ -51,12 +54,14 @@ import mage.target.common.TargetCardInYourGraveyard; public class VigorMortis extends CardImpl { public VigorMortis(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}{B}"); // Return target creature card from your graveyard to the battlefield. If {G} was spent to cast Vigor Mortis, that creature enters the battlefield with an additional +1/+1 counter on it. + this.getSpellAbility().addEffect(new VigorMortisReplacementEffect()); // has to be added before the moving effect this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); + this.getSpellAbility().addEffect(new InfoEffect("If {G} was spent to cast {this}, that creature enters the battlefield with an additional +1/+1 counter on it")); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard())); - this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new VigorMortisAddCounterEffect(), new ManaWasSpentCondition(ColoredManaSymbol.G))); + } public VigorMortis(final VigorMortis card) { @@ -69,29 +74,46 @@ public class VigorMortis extends CardImpl { } } -class VigorMortisAddCounterEffect extends OneShotEffect { - - VigorMortisAddCounterEffect() { - super(Outcome.BoostCreature); - this.staticText = "that creature enters the battlefield with an additional +1/+1 counter on it"; +class VigorMortisReplacementEffect extends ReplacementEffectImpl { + + VigorMortisReplacementEffect() { + super(Duration.EndOfStep, Outcome.BoostCreature); } - - VigorMortisAddCounterEffect(final VigorMortisAddCounterEffect effect) { + + VigorMortisReplacementEffect(VigorMortisReplacementEffect effect) { super(effect); } - + @Override - public VigorMortisAddCounterEffect copy() { - return new VigorMortisAddCounterEffect(this); + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; } - + @Override - public boolean apply(Game game, Ability source) { - // targetPointer can't be used because target moved from graveyard to battlefield - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent != null) { - permanent.addCounters(CounterType.P1P1.createInstance(), source, game); + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getTargetId().equals(getTargetPointer().getFirst(game, source))) { + return new ManaWasSpentCondition(ColoredManaSymbol.G).apply(game, source); } return false; } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); + if (creature != null) { + creature.addCounters(CounterType.P1P1.createInstance(), source, game, event.getAppliedEffects()); + discard(); + } + return false; + } + + @Override + public VigorMortisReplacementEffect copy() { + return new VigorMortisReplacementEffect(this); + } } diff --git a/Mage.Sets/src/mage/cards/z/ZameckGuildmage.java b/Mage.Sets/src/mage/cards/z/ZameckGuildmage.java index 986e717a00..b691159e4f 100644 --- a/Mage.Sets/src/mage/cards/z/ZameckGuildmage.java +++ b/Mage.Sets/src/mage/cards/z/ZameckGuildmage.java @@ -55,7 +55,7 @@ import mage.target.common.TargetControlledCreaturePermanent; public class ZameckGuildmage extends CardImpl { public ZameckGuildmage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{U}"); this.subtype.add("Elf"); this.subtype.add("Wizard"); @@ -112,7 +112,7 @@ class ZameckGuildmageEntersBattlefieldEffect extends ReplacementEffectImpl { public boolean replaceEvent(GameEvent event, Ability source, Game game) { Permanent target = ((EntersTheBattlefieldEvent) event).getTarget(); if (target != null) { - target.addCounters(CounterType.P1P1.createInstance(), source, game); + target.addCounters(CounterType.P1P1.createInstance(), source, game, event.getAppliedEffects()); } return false; } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DrawEffectsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DrawEffectsTest.java index 58548cfc8e..59a0784801 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DrawEffectsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DrawEffectsTest.java @@ -52,7 +52,7 @@ public class DrawEffectsTest extends CardTestPlayerBase { setStopAt(2, PhaseStep.PRECOMBAT_MAIN); execute(); - Assert.assertEquals("Player B has to have 4 cards in hand", 8, playerB.getHand().size()); + Assert.assertEquals("Player B has to have 8 cards in hand", 8, playerB.getHand().size()); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/entersBattlefield/HardenedScaleTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/entersBattlefield/HardenedScaleTest.java new file mode 100644 index 0000000000..fe4424442c --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/entersBattlefield/HardenedScaleTest.java @@ -0,0 +1,142 @@ +/* + * 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 org.mage.test.cards.replacement.entersBattlefield; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class HardenedScaleTest extends CardTestPlayerBase { + + /* + Reported bug: Hangarback interaciton with Hardened Scales and Metallic Mimic on board is incorrect. + */ + @Test + public void hangarBackHardenedScalesMetallicMimicTest() { + + /* + Hangarback Walker {X}{X} + Artifact Creature — Construct 0/0 + Hangarback Walker enters the battlefield with X +1/+1 counters on it. + When Hangarback Walker dies, create a 1/1 colorless Thopter artifact creature token with flying for each +1/+1 counter on Hangarback Walker. + {1}, {T}: Put a +1/+1 counter on Hangarback Walker. + */ + String hWalker = "Hangarback Walker"; + + /* + Hardened Scales {G} + Enchantment + If one or more +1/+1 counters would be placed on a creature you control, that many plus one +1/+1 counters are placed on it instead. + */ + String hScales = "Hardened Scales"; + + /* + Metallic Mimic {2} + Artifact Creature — Shapeshifter 2/1 + As Metallic Mimic enters the battlefield, choose a creature type. + Metallic Mimic is the chosen type in addition to its other types. + Each other creature you control of the chosen type enters the battlefield with an additional +1/+1 counter on it. + */ + String mMimic = "Metallic Mimic"; + + addCard(Zone.BATTLEFIELD, playerA, hScales); + addCard(Zone.HAND, playerA, mMimic); + addCard(Zone.HAND, playerA, hWalker); + addCard(Zone.BATTLEFIELD, playerA, "Wastes", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, mMimic); + setChoice(playerA, "Construct"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, hWalker); + setChoice(playerA, "X=1"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, mMimic, 1); + assertPermanentCount(playerA, hWalker, 1); + assertCounterCount(playerA, hWalker, CounterType.P1P1, 3); + assertPowerToughness(playerA, hWalker, 3, 3); + } + + @Test + public void testWithVigorMortis() { + + /* + Vigor Mortis {2}{B}{B} + Sorcery + Return target creature card from your graveyard to the battlefield. If {G} was spent to cast Vigor Mortis, + that creature enters the battlefield with an additional +1/+1 counter on it. + */ + String vMortis = "Vigor Mortis"; + + /* + Hardened Scales {G} + Enchantment + If one or more +1/+1 counters would be placed on a creature you control, that many plus one +1/+1 counters are placed on it instead. + */ + String hScales = "Hardened Scales"; + + /* + Metallic Mimic {2} + Artifact Creature — Shapeshifter 2/1 + As Metallic Mimic enters the battlefield, choose a creature type. + Metallic Mimic is the chosen type in addition to its other types. + Each other creature you control of the chosen type enters the battlefield with an additional +1/+1 counter on it. + */ + String mMimic = "Metallic Mimic"; + + addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion"); + addCard(Zone.BATTLEFIELD, playerA, hScales); + addCard(Zone.HAND, playerA, mMimic); + addCard(Zone.HAND, playerA, vMortis); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, mMimic); + setChoice(playerA, "Cat"); + + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, vMortis, "Silvercoat Lion"); + + setStopAt(3, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, mMimic, 1); + + assertPermanentCount(playerA, "Silvercoat Lion", 1); + assertCounterCount(playerA, "Silvercoat Lion", CounterType.P1P1, 3); + assertPowerToughness(playerA, "Silvercoat Lion", 5, 5); // Hardened Scales is only once applied to EntersTheBattlefield event + assertGraveyardCount(playerA, vMortis, 1); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java index 4f42e77923..e732999149 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java @@ -27,6 +27,9 @@ */ package mage.abilities.effects; +import java.io.Serializable; +import java.util.*; +import java.util.Map.Entry; import mage.MageObject; import mage.abilities.*; import mage.abilities.keyword.SpliceOntoArcaneAbility; @@ -49,10 +52,6 @@ import mage.players.Player; import mage.target.common.TargetCardInHand; import org.apache.log4j.Logger; -import java.io.Serializable; -import java.util.*; -import java.util.Map.Entry; - /** * @author BetaSteward_at_googlemail.com */ @@ -691,8 +690,7 @@ public class ContinuousEffects implements Serializable { spliceAbilities.remove(selectedAbility); } } - } - while (!spliceAbilities.isEmpty() && controller.chooseUse(Outcome.Benefit, "Splice another card?", abilityToModify, game)); + } while (!spliceAbilities.isEmpty() && controller.chooseUse(Outcome.Benefit, "Splice another card?", abilityToModify, game)); controller.revealCards("Spliced cards", cardsToReveal, game); } } @@ -702,10 +700,10 @@ public class ContinuousEffects implements Serializable { * Checks if an event won't happen because of an rule modifying effect * * @param event - * @param targetAbility ability the event is attached to. can be null. + * @param targetAbility ability the event is attached to. can be null. * @param game * @param checkPlayableMode true if the event does not really happen but - * it's checked if the event would be replaced + * it's checked if the event would be replaced * @return */ public boolean preventedByRuleModification(GameEvent event, Ability targetAbility, Game game, boolean checkPlayableMode) { @@ -752,7 +750,7 @@ public class ContinuousEffects implements Serializable { do { HashMap> rEffects = getApplicableReplacementEffects(event, game); // Remove all consumed effects (ability dependant) - for (Iterator it1 = rEffects.keySet().iterator(); it1.hasNext(); ) { + for (Iterator it1 = rEffects.keySet().iterator(); it1.hasNext();) { ReplacementEffect entry = it1.next(); if (consumed.containsKey(entry.getId())) { HashSet consumedAbilitiesIds = consumed.get(entry.getId()); @@ -933,7 +931,7 @@ public class ContinuousEffects implements Serializable { if (!waitingEffects.isEmpty()) { // check if waiting effects can be applied now - for (Iterator>> iterator = waitingEffects.entrySet().iterator(); iterator.hasNext(); ) { + for (Iterator>> iterator = waitingEffects.entrySet().iterator(); iterator.hasNext();) { Map.Entry> entry = iterator.next(); if (appliedEffects.containsAll(entry.getValue())) { // all dependent to effects are applied now so apply the effect itself appliedAbilities = appliedEffectAbilities.get(entry.getKey()); diff --git a/Mage/src/main/java/mage/abilities/effects/EntersBattlefieldEffect.java b/Mage/src/main/java/mage/abilities/effects/EntersBattlefieldEffect.java index ef78e432bb..923bc5f22b 100644 --- a/Mage/src/main/java/mage/abilities/effects/EntersBattlefieldEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/EntersBattlefieldEffect.java @@ -148,6 +148,7 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl { if (spell != null) { effect.setValue(SOURCE_CAST_SPELL_ABILITY, spell.getSpellAbility()); } + effect.setValue("appliedEffects", event.getAppliedEffects()); effect.apply(game, source); } // } diff --git a/Mage/src/main/java/mage/abilities/effects/common/EntersBattlefieldWithXCountersEffect.java b/Mage/src/main/java/mage/abilities/effects/common/EntersBattlefieldWithXCountersEffect.java index 78f14bc36a..d326d359d2 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/EntersBattlefieldWithXCountersEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/EntersBattlefieldWithXCountersEffect.java @@ -27,6 +27,8 @@ */ package mage.abilities.effects.common; +import java.util.ArrayList; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.effects.EntersBattlefieldEffect; @@ -75,7 +77,8 @@ public class EntersBattlefieldWithXCountersEffect extends OneShotEffect { if (amount > 0) { Counter counterToAdd = counter.copy(); counterToAdd.add(amount - counter.getCount()); - permanent.addCounters(counterToAdd, source, game); + ArrayList appliedEffects = (ArrayList) this.getValue("appliedEffects"); + permanent.addCounters(counterToAdd, source, game, appliedEffects); } } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersSourceEffect.java index 3233d7a286..1f28040a73 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersSourceEffect.java @@ -27,6 +27,8 @@ */ package mage.abilities.effects.common.counter; +import java.util.ArrayList; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; @@ -103,7 +105,8 @@ public class AddCountersSourceEffect extends OneShotEffect { countersToAdd--; } newCounter.add(countersToAdd); - card.addCounters(newCounter, source, game); + ArrayList appliedEffects = (ArrayList) this.getValue("appliedEffects"); + card.addCounters(newCounter, source, game, appliedEffects); if (informPlayers && !game.isSimulation()) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { @@ -128,7 +131,8 @@ public class AddCountersSourceEffect extends OneShotEffect { } newCounter.add(countersToAdd); int before = permanent.getCounters(game).getCount(newCounter.getName()); - permanent.addCounters(newCounter, source, game); + ArrayList appliedEffects = (ArrayList) this.getValue("appliedEffects"); + permanent.addCounters(newCounter, source, game, appliedEffects); // if used from a replacement effect, the basic event determines if an effect was already applied to an event if (informPlayers && !game.isSimulation()) { int amountAdded = permanent.getCounters(game).getCount(newCounter.getName()) - before; Player player = game.getPlayer(source.getControllerId()); @@ -150,12 +154,10 @@ public class AddCountersSourceEffect extends OneShotEffect { sb.append("put "); if (counter.getCount() > 1) { sb.append(CardUtil.numberToText(counter.getCount())).append(' '); + } else if (amount.toString().equals("X") && amount.getMessage().isEmpty()) { + sb.append("X "); } else { - if (amount.toString().equals("X") && amount.getMessage().isEmpty()) { - sb.append("X "); - } else { - sb.append("a "); - } + sb.append("a "); } sb.append(counter.getName().toLowerCase()).append(" counter on {this}"); if (!amount.getMessage().isEmpty()) { diff --git a/Mage/src/main/java/mage/abilities/keyword/BloodthirstAbility.java b/Mage/src/main/java/mage/abilities/keyword/BloodthirstAbility.java index b57e67959e..93941494ba 100644 --- a/Mage/src/main/java/mage/abilities/keyword/BloodthirstAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/BloodthirstAbility.java @@ -1,5 +1,7 @@ package mage.abilities.keyword; +import java.util.ArrayList; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.effects.OneShotEffect; @@ -71,7 +73,8 @@ class BloodthirstEffect extends OneShotEffect { if (watcher != null && watcher.conditionMet()) { Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (permanent != null) { - permanent.addCounters(CounterType.P1P1.createInstance(amount), source, game); + ArrayList appliedEffects = (ArrayList) this.getValue("appliedEffects"); // the basic event is the EntersBattlefieldEvent, so use already applied replacement effects from that event + permanent.addCounters(CounterType.P1P1.createInstance(amount), source, game, appliedEffects); } } return true; diff --git a/Mage/src/main/java/mage/abilities/keyword/ModularAbility.java b/Mage/src/main/java/mage/abilities/keyword/ModularAbility.java index bb155c232b..250992d472 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ModularAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ModularAbility.java @@ -1,5 +1,7 @@ package mage.abilities.keyword; +import java.util.ArrayList; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.StaticAbility; import mage.abilities.common.DiesTriggeredAbility; @@ -159,7 +161,8 @@ class ModularDistributeCounterEffect extends OneShotEffect { if (sourcePermanent != null && targetArtifact != null && player != null) { int numberOfCounters = sourcePermanent.getCounters(game).getCount(CounterType.P1P1); if (numberOfCounters > 0) { - targetArtifact.addCounters(CounterType.P1P1.createInstance(numberOfCounters), source, game); + ArrayList appliedEffects = (ArrayList) this.getValue("appliedEffects"); // the basic event is the EntersBattlefieldEvent, so use already applied replacement effects from that event + targetArtifact.addCounters(CounterType.P1P1.createInstance(numberOfCounters), source, game, appliedEffects); } return true; } diff --git a/Mage/src/main/java/mage/abilities/keyword/SunburstAbility.java b/Mage/src/main/java/mage/abilities/keyword/SunburstAbility.java index 3aa9182d2f..7a61d06c41 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SunburstAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SunburstAbility.java @@ -27,13 +27,14 @@ */ package mage.abilities.keyword; +import java.util.ArrayList; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.SunburstCount; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; -import mage.constants.CardType; import mage.constants.Outcome; import mage.counters.Counter; import mage.counters.CounterType; @@ -97,8 +98,8 @@ class SunburstEffect extends OneShotEffect { counter = CounterType.CHARGE.createInstance(amount.calculate(game, source, this)); } if (counter != null) { - - permanent.addCounters(counter, source, game); + ArrayList appliedEffects = (ArrayList) this.getValue("appliedEffects"); // the basic event is the EntersBattlefieldEvent, so use already applied replacement effects from that event + permanent.addCounters(counter, source, game, appliedEffects); if (!game.isSimulation()) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { diff --git a/Mage/src/main/java/mage/abilities/keyword/UnleashAbility.java b/Mage/src/main/java/mage/abilities/keyword/UnleashAbility.java index 6cdc697f12..77bad12188 100644 --- a/Mage/src/main/java/mage/abilities/keyword/UnleashAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/UnleashAbility.java @@ -105,7 +105,7 @@ class UnleashReplacementEffect extends ReplacementEffectImpl { if (!game.isSimulation()) { game.informPlayers(controller.getLogName() + " unleashes " + creature.getName()); } - creature.addCounters(CounterType.P1P1.createInstance(), source, game); + creature.addCounters(CounterType.P1P1.createInstance(), source, game, event.getAppliedEffects()); } } return false; diff --git a/Mage/src/main/java/mage/actions/MageDrawAction.java b/Mage/src/main/java/mage/actions/MageDrawAction.java index ba7922b590..619cd9da75 100644 --- a/Mage/src/main/java/mage/actions/MageDrawAction.java +++ b/Mage/src/main/java/mage/actions/MageDrawAction.java @@ -76,7 +76,7 @@ public class MageDrawAction extends MageAction { */ protected int drawCard(Game game) { GameEvent event = GameEvent.getEvent(GameEvent.EventType.DRAW_CARD, player.getId(), player.getId()); - event.setAppliedEffects(appliedEffects); + event.addAppliedEffects(appliedEffects); if (!game.replaceEvent(event)) { Card card = player.getLibrary().removeFromTop(game); if (card != null) { diff --git a/Mage/src/main/java/mage/game/events/GameEvent.java b/Mage/src/main/java/mage/game/events/GameEvent.java index a554d27655..e135c0ad5f 100644 --- a/Mage/src/main/java/mage/game/events/GameEvent.java +++ b/Mage/src/main/java/mage/game/events/GameEvent.java @@ -451,12 +451,19 @@ public class GameEvent implements Serializable { return type == EventType.CUSTOM_EVENT && this.customEventType.equals(customEventType); } - public void setAppliedEffects(ArrayList appliedEffects) { - if (this.appliedEffects == null) { - this.appliedEffects = new ArrayList<>(); - } + public void addAppliedEffects(ArrayList appliedEffects) { if (appliedEffects != null) { this.appliedEffects.addAll(appliedEffects); } } + + public void setAppliedEffects(ArrayList appliedEffects) { + if (appliedEffects != null) { + if (this.appliedEffects.isEmpty()) { + this.appliedEffects = appliedEffects; // Use object refecence to handle that an replacement effect can only be once applied to an event + } else { + this.appliedEffects.addAll(appliedEffects); + } + } + } }