* Kormus Bell - Fixed a bug with order land type changing effects are applied (fixes #3470).

This commit is contained in:
LevelX2 2017-07-28 16:56:31 +02:00
parent 4e8026fe59
commit b9dff66fcb
8 changed files with 136 additions and 34 deletions

View file

@ -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
}
}

View file

@ -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<MageObjectReference> 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;

View file

@ -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;
}
}

View file

@ -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<Player> 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<UUID>)target.getTargets()) {
for (UUID cardId : (List<UUID>) 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 {
}
}
}
}

View file

@ -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);
}
}

View file

@ -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<DependencyType> getDependencyTypes() {
if (effect != null) {
return effect.getDependencyTypes();
}
return super.getDependencyTypes();
}
@Override
public Set<UUID> isDependentTo(List<ContinuousEffect> allEffectsInLayer) {
if (effect != null) {

View file

@ -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<UUID> isDependentTo(List<ContinuousEffect> allEffectsInLayer);
Set<DependencyType> getDependencyTypes();
EnumSet<DependencyType> getDependencyTypes();
void addDependencyType(DependencyType dependencyType);
void setDependedToType(DependencyType dependencyType);
void addDependedToType(DependencyType dependencyType);
@Override
void newId();

View file

@ -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<MageObjectReference> affectedObjectList = new ArrayList<>();
protected boolean temporary = false;
protected EnumSet<DependencyType> dependencyTypes; // this effect has the dependencyTypes defined here
protected DependencyType dependendToType; // this effect is dependent to this type
protected EnumSet<DependencyType> 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<UUID> isDependentTo(List<ContinuousEffect> allEffectsInLayer) {
if (dependendToType != null) {
Set<UUID> dependentToEffects = new HashSet<UUID>();
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);
}
}