diff --git a/Mage.Sets/src/mage/cards/k/KormusBell.java b/Mage.Sets/src/mage/cards/k/KormusBell.java index 241be3129ca..6eee0ad2e39 100644 --- a/Mage.Sets/src/mage/cards/k/KormusBell.java +++ b/Mage.Sets/src/mage/cards/k/KormusBell.java @@ -51,6 +51,8 @@ public class KormusBell extends CardImpl { // All Swamps are 1/1 black creatures that are still lands. ContinuousEffect effect = new BecomesCreatureAllEffect(new KormusBellToken(), "lands", new FilterPermanent(SubType.SWAMP, "Swamps"), Duration.WhileOnBattlefield); effect.setDependedToType(DependencyType.BecomeSwamp); + effect.addDependedToType(DependencyType.BecomeIsland); + effect.addDependedToType(DependencyType.BecomeMountain); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); } @@ -71,7 +73,7 @@ class KormusBellToken extends Token { cardType.add(CardType.CREATURE); power = new MageInt(1); toughness = new MageInt(1); - color.setBlack(true); //Check Oracle, yes they are black + color.setBlack(true); // black creatures } } diff --git a/Mage.Sets/src/mage/cards/m/MarchOfTheMachines.java b/Mage.Sets/src/mage/cards/m/MarchOfTheMachines.java index 28d8fae826b..56ef8afecfb 100644 --- a/Mage.Sets/src/mage/cards/m/MarchOfTheMachines.java +++ b/Mage.Sets/src/mage/cards/m/MarchOfTheMachines.java @@ -49,8 +49,7 @@ import mage.game.permanent.Permanent; public class MarchOfTheMachines extends CardImpl { public MarchOfTheMachines(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}"); // Each noncreature artifact is an artifact creature with power and toughness each equal to its converted mana cost. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MarchOfTheMachinesEffect())); @@ -69,13 +68,15 @@ public class MarchOfTheMachines extends CardImpl { class MarchOfTheMachinesEffect extends ContinuousEffectImpl { private static final FilterArtifactPermanent filter = new FilterArtifactPermanent(); + static { filter.add(Predicates.not(new CardTypePredicate(CardType.CREATURE))); } + public MarchOfTheMachinesEffect() { super(Duration.WhileOnBattlefield, Outcome.BecomeCreature); staticText = "Each noncreature artifact is an artifact creature with power and toughness each equal to its converted mana cost"; - dependendToType = DependencyType.ArtifactAddingRemoving; + dependendToTypes.add(DependencyType.ArtifactAddingRemoving); } public MarchOfTheMachinesEffect(final MarchOfTheMachinesEffect effect) { @@ -93,8 +94,8 @@ class MarchOfTheMachinesEffect extends ContinuousEffectImpl { case TypeChangingEffects_4: if (sublayer == SubLayer.NA) { affectedObjectList.clear(); - for(Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, game)){ - if(permanent != null){ + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, game)) { + if (permanent != null) { affectedObjectList.add(new MageObjectReference(permanent, game)); permanent.addCardType(CardType.CREATURE); } @@ -106,7 +107,7 @@ class MarchOfTheMachinesEffect extends ContinuousEffectImpl { if (sublayer == SubLayer.SetPT_7b) { for (Iterator it = affectedObjectList.iterator(); it.hasNext();) { Permanent permanent = it.next().getPermanent(game); - if (permanent != null){ + if (permanent != null) { int manaCost = permanent.getConvertedManaCost(); permanent.getPower().setValue(manaCost); permanent.getToughness().setValue(manaCost); @@ -122,7 +123,6 @@ class MarchOfTheMachinesEffect extends ContinuousEffectImpl { return false; } - @Override public boolean hasLayer(Layer layer) { return layer == Layer.PTChangingEffects_7 || layer == Layer.TypeChangingEffects_4; diff --git a/Mage.Sets/src/mage/cards/q/QuicksilverFountain.java b/Mage.Sets/src/mage/cards/q/QuicksilverFountain.java index 4c2a1f6b8e6..f0801b2df50 100644 --- a/Mage.Sets/src/mage/cards/q/QuicksilverFountain.java +++ b/Mage.Sets/src/mage/cards/q/QuicksilverFountain.java @@ -33,6 +33,7 @@ import mage.abilities.common.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BecomesBasicLandTargetEffect; @@ -104,7 +105,9 @@ class QuicksilverFountainEffect extends OneShotEffect { if (player.choose(Outcome.Neutral, targetNonIslandLand, source.getId(), game)) { Permanent landChosen = game.getPermanent(targetNonIslandLand.getFirstTarget()); landChosen.addCounters(CounterType.FLOOD.createInstance(), source, game); - ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new BecomesBasicLandTargetEffect(Duration.OneUse, "Island"), new LandHasFloodCounterCondition(this), staticText); + ContinuousEffect becomesBasicLandTargetEffect = new BecomesBasicLandTargetEffect(Duration.OneUse, "Island"); + becomesBasicLandTargetEffect.addDependencyType(DependencyType.BecomeIsland); + ConditionalContinuousEffect effect = new ConditionalContinuousEffect(becomesBasicLandTargetEffect, new LandHasFloodCounterCondition(this), staticText); this.setTargetPointer(new FixedTarget(landChosen, game)); effect.setTargetPointer(new FixedTarget(landChosen, game)); game.addEffect(effect, source); @@ -160,7 +163,7 @@ class AllLandsAreSubtypeCondition implements Condition { int landCount = game.getBattlefield().getAllActivePermanents(CardType.LAND).size(); return game.getBattlefield().getAllActivePermanents(filterLand, game).size() == landCount; } - + @Override public String toString() { return "if all lands on the battlefield are " + subtype + "s"; @@ -178,7 +181,7 @@ class LandHasFloodCounterCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(effect.getTargetPointer().getFirst(game, source)); - return permanent != null - && permanent.getCounters(game).getCount(CounterType.FLOOD) > 0; + return permanent != null + && permanent.getCounters(game).getCount(CounterType.FLOOD) > 0; } } diff --git a/Mage.Sets/src/mage/cards/v/VeteranExplorer.java b/Mage.Sets/src/mage/cards/v/VeteranExplorer.java index 4ea844a8ce8..b6f30d6be42 100644 --- a/Mage.Sets/src/mage/cards/v/VeteranExplorer.java +++ b/Mage.Sets/src/mage/cards/v/VeteranExplorer.java @@ -41,7 +41,6 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.filter.common.FilterBasicLandCard; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; @@ -53,7 +52,7 @@ import mage.target.common.TargetCardInLibrary; public class VeteranExplorer extends CardImpl { public VeteranExplorer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); this.subtype.add("Human"); this.subtype.add("Soldier"); this.subtype.add("Scout"); @@ -74,6 +73,7 @@ public class VeteranExplorer extends CardImpl { return new VeteranExplorer(this); } } + class VeteranExplorerEffect extends OneShotEffect { public VeteranExplorerEffect() { @@ -96,7 +96,7 @@ class VeteranExplorerEffect extends OneShotEffect { if (controller != null) { List usingPlayers = new ArrayList<>(); this.chooseAndSearchLibrary(usingPlayers, controller, source, game); - for (UUID playerId: game.getState().getPlayersInRange(controller.getId(), game)) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { if (!playerId.equals(controller.getId())) { Player player = game.getPlayer(playerId); if (player != null) { @@ -104,7 +104,7 @@ class VeteranExplorerEffect extends OneShotEffect { } } } - for (Player player: usingPlayers) { + for (Player player : usingPlayers) { player.shuffleLibrary(source, game); } return true; @@ -118,7 +118,7 @@ class VeteranExplorerEffect extends OneShotEffect { TargetCardInLibrary target = new TargetCardInLibrary(0, 2, StaticFilters.FILTER_BASIC_LAND_CARD); if (player.searchLibrary(target, game)) { if (!target.getTargets().isEmpty()) { - for (UUID cardId: (List)target.getTargets()) { + for (UUID cardId : (List) target.getTargets()) { Card card = player.getLibrary().getCard(cardId, game); if (card != null) { card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), player.getId()); @@ -128,5 +128,5 @@ class VeteranExplorerEffect extends OneShotEffect { } } } - + } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/LandTypeChangingEffectsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/LandTypeChangingEffectsTest.java index 091484c1128..ec0ec0888be 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/LandTypeChangingEffectsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/LandTypeChangingEffectsTest.java @@ -30,8 +30,11 @@ package org.mage.test.cards.continuous; import mage.abilities.mana.AnyColorManaAbility; import mage.constants.CardType; import mage.constants.PhaseStep; +import mage.constants.SubType; import mage.constants.Zone; import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.permanent.Permanent; import org.junit.Assert; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -130,14 +133,14 @@ public class LandTypeChangingEffectsTest extends CardTestPlayerBase { assertType("Forbidding Watchtower", CardType.LAND, "Island"); assertPowerToughness(playerB, "Forbidding Watchtower", 1, 5); } - + String urborgtoy = "Urborg, Tomb of Yawgmoth"; String bloodmoon = "Blood Moon"; String canopyvista = "Canopy Vista"; /* NOTE: this test is currently failing due to bug in code. See issue #3072 - */ + */ @Test public void testBloodMoonBeforeUrborg() { // Blood Moon 2R @@ -146,14 +149,14 @@ public class LandTypeChangingEffectsTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, bloodmoon); // Each land is a Swamp in addition to its other land types. addCard(Zone.HAND, playerA, urborgtoy); - + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); addCard(Zone.BATTLEFIELD, playerB, canopyvista, 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bloodmoon); playLand(1, PhaseStep.POSTCOMBAT_MAIN, playerA, urborgtoy); - + setStopAt(2, PhaseStep.PRECOMBAT_MAIN); execute(); @@ -169,7 +172,7 @@ public class LandTypeChangingEffectsTest extends CardTestPlayerBase { /* NOTE: this test is currently failing due to bug in code. See issue #3072 - */ + */ @Test public void testBloodMoonAfterUrborg() { // Blood Moon 2R @@ -178,14 +181,14 @@ public class LandTypeChangingEffectsTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, bloodmoon); // Each land is a Swamp in addition to its other land types. addCard(Zone.HAND, playerA, urborgtoy); - + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); addCard(Zone.BATTLEFIELD, playerB, canopyvista, 1); playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, urborgtoy); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, bloodmoon); - + setStopAt(2, PhaseStep.PRECOMBAT_MAIN); execute(); @@ -199,4 +202,66 @@ public class LandTypeChangingEffectsTest extends CardTestPlayerBase { Assert.assertTrue("The mana the land can produce should be [{R}] but it's " + playerB.getManaAvailable(currentGame).toString(), playerB.getManaAvailable(currentGame).toString().equals("[{R}]")); } + /* + I had Kormus Bell (all swamps are 1/1s) and Urborg, Tomb of Yawgmoth (all lands are swamps) and only basic lands (swamps) otherwise. + Opponent had Quicksilver Fountain (put a flood counter on non-island land). + In terms of time-stamp order, Urborg was down first, then Kormus Bell, then Quicksilver. + When I put a flood counter on a basic swamp, it would become a 0/0 instead of a 1/1 and die. + */ + @Test + public void testCormusBellAfterUrborg() { + // Land - Legendary + // Each land is a Swamp in addition to its other land types. + addCard(Zone.HAND, playerA, urborgtoy); + + // All Swamps are 1/1 black creatures that are still lands. + addCard(Zone.HAND, playerA, "Kormus Bell"); // Artifact {4} + + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); + + // At the beginning of each player's upkeep, that player puts a flood counter on target non-Island land he or she controls of his or her choice. + // That land is an Island for as long as it has a flood counter on it. + // At the beginning of each end step, if all lands on the battlefield are Islands, remove all flood counters from them. + addCard(Zone.HAND, playerB, "Quicksilver Fountain", 1); // Artifact {3} + addCard(Zone.BATTLEFIELD, playerB, "Forest", 3); + + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, urborgtoy); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Kormus Bell"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Quicksilver Fountain"); + addTarget(playerA, "Mountain"); + + setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, urborgtoy, 1); + assertPermanentCount(playerA, "Kormus Bell", 1); + assertPermanentCount(playerB, "Quicksilver Fountain", 1); + + assertGraveyardCount(playerA, "Mountain", 0); + + int islandTypes = 0; + int swampTypes = 0; + int mountainTypes = 0; + int creatures = 0; + for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_LAND, playerA.getId(), currentGame)) { + if (permanent.getSubtype(currentGame).contains(SubType.ISLAND)) { + islandTypes++; + } + if (permanent.getSubtype(currentGame).contains(SubType.MOUNTAIN)) { + mountainTypes++; + } + if (permanent.getSubtype(currentGame).contains(SubType.SWAMP)) { + swampTypes++; + } + if (permanent.isCreature()) { + creatures++; + } + } + Assert.assertTrue("1 land has to be of island type", islandTypes == 1); + Assert.assertTrue("3 lands have to be of mountain type", mountainTypes == 3); + Assert.assertTrue("4 lands have to be of swamp type", swampTypes == 4); + Assert.assertTrue("4 lands have to be creatures but there are " + creatures, creatures == 4); + } + } diff --git a/Mage/src/main/java/mage/abilities/decorator/ConditionalContinuousEffect.java b/Mage/src/main/java/mage/abilities/decorator/ConditionalContinuousEffect.java index 7f0ac802695..5a22141369e 100644 --- a/Mage/src/main/java/mage/abilities/decorator/ConditionalContinuousEffect.java +++ b/Mage/src/main/java/mage/abilities/decorator/ConditionalContinuousEffect.java @@ -1,5 +1,6 @@ package mage.abilities.decorator; +import java.util.EnumSet; import java.util.List; import java.util.Set; import java.util.UUID; @@ -10,6 +11,7 @@ import mage.abilities.condition.FixedCondition; import mage.abilities.condition.LockedInCondition; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffectImpl; +import mage.constants.DependencyType; import mage.constants.Duration; import mage.constants.Layer; import mage.constants.SubLayer; @@ -137,6 +139,14 @@ public class ConditionalContinuousEffect extends ContinuousEffectImpl { return new ConditionalContinuousEffect(this); } + @Override + public EnumSet getDependencyTypes() { + if (effect != null) { + return effect.getDependencyTypes(); + } + return super.getDependencyTypes(); + } + @Override public Set isDependentTo(List allEffectsInLayer) { if (effect != null) { diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java index 13cd406e9df..51df5b855d2 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java @@ -27,6 +27,7 @@ */ package mage.abilities.effects; +import java.util.EnumSet; import java.util.List; import java.util.Set; import java.util.UUID; @@ -74,12 +75,14 @@ public interface ContinuousEffect extends Effect { Set isDependentTo(List allEffectsInLayer); - Set getDependencyTypes(); + EnumSet getDependencyTypes(); void addDependencyType(DependencyType dependencyType); void setDependedToType(DependencyType dependencyType); + void addDependedToType(DependencyType dependencyType); + @Override void newId(); diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java index f838ef3eb6d..ac2720a3932 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java @@ -33,7 +33,6 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; -import java.util.stream.Collectors; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.MageSingleton; @@ -66,7 +65,7 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu protected List affectedObjectList = new ArrayList<>(); protected boolean temporary = false; protected EnumSet dependencyTypes; // this effect has the dependencyTypes defined here - protected DependencyType dependendToType; // this effect is dependent to this type + protected EnumSet dependendToTypes; // this effect is dependent to this types /* A Characteristic Defining Ability (CDA) is an ability that defines a characteristic of a card or token. There are 3 specific rules that distinguish a CDA from other abilities. @@ -86,7 +85,7 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu this.order = 0; this.effectType = EffectType.CONTINUOUS; this.dependencyTypes = EnumSet.noneOf(DependencyType.class); - this.dependendToType = null; + this.dependendToTypes = EnumSet.noneOf(DependencyType.class); } public ContinuousEffectImpl(Duration duration, Layer layer, SubLayer sublayer, Outcome outcome) { @@ -109,7 +108,7 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu this.startingTurn = effect.startingTurn; this.startingControllerId = effect.startingControllerId; this.dependencyTypes = effect.dependencyTypes; - this.dependendToType = effect.dependendToType; + this.dependendToTypes = effect.dependendToTypes; this.characterDefining = effect.characterDefining; } @@ -271,14 +270,28 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu @Override public Set isDependentTo(List allEffectsInLayer) { - if (dependendToType != null) { + Set dependentToEffects = new HashSet(); + if (dependendToTypes != null) { + for (ContinuousEffect effect : allEffectsInLayer) { + if (!effect.getId().equals(this.getId())) { + for (DependencyType dependencyType : effect.getDependencyTypes()) { + if (dependendToTypes.contains(dependencyType)) { + dependentToEffects.add(effect.getId()); + break; + } + } + } + } + } + return dependentToEffects; + /* return allEffectsInLayer.stream() - .filter(effect -> effect.getDependencyTypes().contains(dependendToType)) + .filter(effect -> effect.getDependencyTypes().contains(dependendToTypes)) .map(Effect::getId) .collect(Collectors.toSet()); } - return new HashSet<>(); + return new HashSet<>();*/ } @Override @@ -293,7 +306,13 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu @Override public void setDependedToType(DependencyType dependencyType) { - dependendToType = dependencyType; + dependendToTypes.clear(); + dependendToTypes.add(dependencyType); + } + + @Override + public void addDependedToType(DependencyType dependencyType) { + dependendToTypes.add(dependencyType); } }