diff --git a/Mage.Sets/src/mage/cards/m/MephidrossVampire.java b/Mage.Sets/src/mage/cards/m/MephidrossVampire.java index 3d95b59e693..0b0f9a53099 100644 --- a/Mage.Sets/src/mage/cards/m/MephidrossVampire.java +++ b/Mage.Sets/src/mage/cards/m/MephidrossVampire.java @@ -46,14 +46,12 @@ import mage.game.permanent.Permanent; import java.util.UUID; /** - * * @author jeffwadsworth - * */ public class MephidrossVampire extends CardImpl { public MephidrossVampire(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); this.subtype.add(SubType.VAMPIRE); this.power = new MageInt(3); @@ -88,6 +86,9 @@ class MephidrossVampireEffect extends ContinuousEffectImpl { MephidrossVampireEffect() { super(Duration.WhileOnBattlefield, Outcome.Detriment); this.staticText = "Each creature you control is a Vampire in addition to its other creature types and has \"Whenever this creature deals damage to a creature, put a +1/+1 counter on this creature.\""; + + // wait become creature effects first then apply own + this.addDependedToType(DependencyType.BecomeCreature); } MephidrossVampireEffect(final MephidrossVampireEffect effect) { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ConstellationTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ConstellationTest.java new file mode 100644 index 00000000000..22755f1ac7d --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ConstellationTest.java @@ -0,0 +1,231 @@ +package org.mage.test.cards.abilities.keywords; + +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.HasteAbility; +import mage.constants.CardType; +import mage.constants.PhaseStep; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.util.functions.Function; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author JayDi85 + */ +public class ConstellationTest extends CardTestPlayerBase { + + /** + * Daxos's Torment {3}{B} + * Constellation — Whenever Daxos’s Torment or another enchantment enters the battlefield under your control, + * Daxos’s Torment becomes a 5/5 Demon creature with flying and haste in addition to its other types until end of turn. + */ + + private final String daxosCard = "Daxos's Torment"; + + private void assertDaxosBoost(boolean mustHave) { + if (mustHave) { + assertPowerToughness(playerA, daxosCard, 5, 5); + assertType(daxosCard, CardType.CREATURE, SubType.DEMON); + assertAbility(playerA, daxosCard, FlyingAbility.getInstance(), true); + assertAbility(playerA, daxosCard, HasteAbility.getInstance(), true); + } else { + assertPowerToughness(playerA, daxosCard, 0, 0); + assertNotSubtype(daxosCard, SubType.DEMON); + assertAbility(playerA, daxosCard, FlyingAbility.getInstance(), false); + assertAbility(playerA, daxosCard, HasteAbility.getInstance(), false); + } + } + + @Test + public void test_DaxosGotBoostOnEnter() { + addCard(Zone.HAND, playerA, daxosCard, 1); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, daxosCard); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertHandCount(playerA, daxosCard, 0); + assertPermanentCount(playerA, daxosCard, 1); + assertDaxosBoost(true); + } + + @Test + public void test_DaxosLostBoostOnNextTurn() { + addCard(Zone.HAND, playerA, daxosCard, 1); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, daxosCard); + + setStopAt(2, PhaseStep.BEGIN_COMBAT); + execute(); + + assertHandCount(playerA, daxosCard, 0); + assertPermanentCount(playerA, daxosCard, 1); + assertDaxosBoost(false); + } + + @Test + public void test_DaxosGotBoostOnOtherEnchantment() { + addCard(Zone.HAND, playerA, daxosCard, 1); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); + + addCard(Zone.HAND, playerA, "Absolute Grace", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, daxosCard); + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Absolute Grace"); + + setStopAt(3, PhaseStep.BEGIN_COMBAT); + execute(); + + assertHandCount(playerA, "Absolute Grace", 0); + assertPermanentCount(playerA, "Absolute Grace", 1); + assertHandCount(playerA, daxosCard, 0); + assertPermanentCount(playerA, daxosCard, 1); + assertDaxosBoost(true); + } + + @Test + public void test_DaxosGotBoostAndWithPTLose() { + addCard(Zone.HAND, playerA, daxosCard, 1); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); + addCard(Zone.BATTLEFIELD, playerA, "Night of Souls' Betrayal", 1); // All creatures get -1/-1 + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, daxosCard); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertHandCount(playerA, daxosCard, 0); + assertPermanentCount(playerA, daxosCard, 1); + + assertPowerToughness(playerA, daxosCard, 5 - 1, 5 - 1); + assertType(daxosCard, CardType.CREATURE, SubType.DEMON); + assertAbility(playerA, daxosCard, FlyingAbility.getInstance(), true); + assertAbility(playerA, daxosCard, HasteAbility.getInstance(), true); + } + + @Test + public void test_DaxosGotBoostWithLoseFly() { + // 112.10c If two or more effects add and remove the same ability, in general the most recent one prevails. + addCard(Zone.HAND, playerA, daxosCard, 1); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); + // + addCard(Zone.HAND, playerB, "Invert the Skies", 1); // Creatures your opponents control lose flying until end of turn + addCard(Zone.BATTLEFIELD, playerB, "Forest", 4); + + // got fly on enter + checkHandCount("start hand", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 1); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, daxosCard); + checkHandCount("first cast hand", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, 0); + checkPermanentCount("dax exist", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, daxosCard, 1); + checkPT("pt after enter", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, daxosCard, 5, 5); + checkAbility("fly after enter", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, daxosCard, FlyingAbility.class, true); + // lose fly on invert + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Invert the Skies"); + checkPT("pt after invert", 1, PhaseStep.END_TURN, playerA, daxosCard, 5, 5); + checkAbility("fly after invert", 1, PhaseStep.END_TURN, playerA, daxosCard, FlyingAbility.class, false); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + } + + @Test + public void test_DaxosGotBoostWithLoseFlyAndGotItAgain() { + // 112.10c If two or more effects add and remove the same ability, in general the most recent one prevails. + addCard(Zone.HAND, playerA, daxosCard, 1); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); + addCard(Zone.HAND, playerA, "Gravity Sphere", 1); // All creatures lose flying. + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + + // got fly on enter, lose on gravity, got fly on gravity enter + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, daxosCard); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Gravity Sphere"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertHandCount(playerA, daxosCard, 0); + assertPermanentCount(playerA, daxosCard, 1); + assertHandCount(playerA, "Gravity Sphere", 0); + assertPermanentCount(playerA, "Gravity Sphere", 1); + + assertPowerToughness(playerA, daxosCard, 5, 5); + assertType(daxosCard, CardType.CREATURE, SubType.DEMON); + assertAbility(playerA, daxosCard, FlyingAbility.getInstance(), true); + assertAbility(playerA, daxosCard, HasteAbility.getInstance(), true); + } + + @Test + public void test_DaxosGotBoostAndSaveColor() { + addCard(Zone.HAND, playerA, daxosCard, 1); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); + // + addCard(Zone.HAND, playerA, "Chaoslace", 1); // Target spell or permanent becomes red. + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + // + addCard(Zone.HAND, playerA, "Archetype of Courage", 1); // Enchantment to trigger Daxos + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + + // dax cast + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, daxosCard); + checkPermanentCount("dax exist", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, daxosCard, 1); + checkColor("dax without color", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, daxosCard, "R", false); + // give dax new color + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Chaoslace", daxosCard); + checkPT("dax not boost", 3, PhaseStep.BEGIN_COMBAT, playerA, daxosCard, 0, 0); + checkColor("dax is red", 3, PhaseStep.BEGIN_COMBAT, playerA, daxosCard, "R", true); + // color is saved on boost + castSpell(5, PhaseStep.PRECOMBAT_MAIN, playerA, "Archetype of Courage"); // make dax to creature + checkPT("dax boost", 5, PhaseStep.BEGIN_COMBAT, playerA, daxosCard, 5, 5); + checkAbility("dax fly", 5, PhaseStep.BEGIN_COMBAT, playerA, daxosCard, FlyingAbility.class, true); + checkColor("dax is red", 5, PhaseStep.BEGIN_COMBAT, playerA, daxosCard, "R", true); + + setStopAt(5, PhaseStep.END_TURN); + execute(); + } + + public void playDaxosAndVampire(boolean castVampireDifferentWay) { + // 112.10c If two or more effects add and remove the same ability, in general the most recent one prevails. + // 613.7 -- dependacy effects (Mephidross Vampire must ALWAYS wait Daxos effect, not timestamp) + addCard(Zone.HAND, playerA, daxosCard, 1); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); + // + addCard(Zone.HAND, playerA, "Mephidross Vampire", 1); // Each creature you control is a Vampire in addition to its other creature types + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 6); + // + addCard(Zone.HAND, playerA, "Archetype of Courage", 1); // Enchantment to trigger Daxos + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + + // dax cast + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, daxosCard); + checkPermanentCount("dax exist", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, daxosCard, 1); + + // give dax a new type (on next turn) -- effects dependacy + if (castVampireDifferentWay) { + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Archetype of Courage"); // make dax to creature + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Mephidross Vampire"); // give vampire to creatures + } else { + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Mephidross Vampire"); // give vampire to creatures + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Archetype of Courage"); // make dax to creature + } + + checkPT("dax boost", 3, PhaseStep.BEGIN_COMBAT, playerA, daxosCard, 5, 5); + checkAbility("dax fly", 3, PhaseStep.BEGIN_COMBAT, playerA, daxosCard, FlyingAbility.class, true); + checkSubType("dax is vampire", 3, PhaseStep.BEGIN_COMBAT, playerA, daxosCard, SubType.VAMPIRE, true); + + setStopAt(3, PhaseStep.END_TURN); + execute(); + } + + @Test + public void test_DaxosGotBoostAndNewTypeByDependencyEffects() { + playDaxosAndVampire(false); + playDaxosAndVampire(true); + } +} + + diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java index db908e4a289..90306488a3c 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java @@ -926,6 +926,14 @@ public class ContinuousEffects implements Serializable { while (!done) { // loop needed if a added effect adds again an effect (e.g. Level 5- of Joraga Treespeaker) done = true; layer = filterLayeredEffects(activeLayerEffects, Layer.AbilityAddingRemovingEffects_6); + + // debug + /* + System.out.println(game.getTurn() + ", " + game.getPhase() + ": " + "need apply " + layer.stream() + .map((eff) -> {return eff.getClass().getName().replaceAll(".+\\.(.+)", "$1");}) + .collect(Collectors.joining(", "))); + */ + for (ContinuousEffect effect : layer) { if (activeLayerEffects.contains(effect) && !appliedEffects.contains(effect.getId())) { // Effect does still exist and was not applied yet Set dependentTo = effect.isDependentTo(layer); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java index 55c68421124..3f818e36597 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java @@ -31,6 +31,7 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.keyword.FlyingAbility; import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; @@ -64,6 +65,8 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements this.power = power; this.toughness = toughness; setText(); + + this.addDependencyType(DependencyType.BecomeCreature); } public BecomesCreatureSourceEffect(final BecomesCreatureSourceEffect effect) { @@ -110,6 +113,7 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements for (CardType cardType : token.getCardType()) { permanent.addCardType(cardType); } + if (theyAreStillType != null && theyAreStillType.isEmpty() || theyAreStillType == null && permanent.isLand()) { permanent.getSubtype(game).retainAll(SubType.getLandTypes(false)); } diff --git a/Mage/src/main/java/mage/constants/DependencyType.java b/Mage/src/main/java/mage/constants/DependencyType.java index e5533442bf6..abb7a8fb846 100644 --- a/Mage/src/main/java/mage/constants/DependencyType.java +++ b/Mage/src/main/java/mage/constants/DependencyType.java @@ -39,7 +39,6 @@ package mage.constants; * @author LevelX2 */ public enum DependencyType { - AuraAddingRemoving, ArtifactAddingRemoving, AddingAbility, @@ -48,6 +47,7 @@ public enum DependencyType { BecomeMountain, BecomePlains, BecomeSwamp, + BecomeCreature, EnchantmentAddingRemoving, LooseDefenderEffect -} +} \ No newline at end of file