diff --git a/Mage.Sets/src/mage/cards/c/CyclopeanTomb.java b/Mage.Sets/src/mage/cards/c/CyclopeanTomb.java index 77e7787f930..b37803bd255 100644 --- a/Mage.Sets/src/mage/cards/c/CyclopeanTomb.java +++ b/Mage.Sets/src/mage/cards/c/CyclopeanTomb.java @@ -1,6 +1,9 @@ - package mage.cards.c; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; @@ -31,11 +34,6 @@ import mage.target.common.TargetLandPermanent; import mage.target.targetpointer.FixedTarget; import mage.watchers.Watcher; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - /** * * @author MTGfan @@ -123,7 +121,6 @@ class CyclopeanTombCreateTriggeredEffect extends OneShotEffect { if (controller != null) { Permanent tomb = game.getPermanentOrLKIBattlefield(source.getSourceId()); // we need to set the correct source object DelayedTriggeredAbility ability = new AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility(new CyclopeanTombEffect(), Duration.EndOfGame, false); - ability.setSourceObject(tomb, game); ability.setControllerId(source.getControllerId()); ability.setSourceId(source.getSourceId()); game.addDelayedTriggeredAbility(ability); diff --git a/Mage.Sets/src/mage/cards/g/GiantOyster.java b/Mage.Sets/src/mage/cards/g/GiantOyster.java index 05617d00dca..53e103906b8 100644 --- a/Mage.Sets/src/mage/cards/g/GiantOyster.java +++ b/Mage.Sets/src/mage/cards/g/GiantOyster.java @@ -1,5 +1,6 @@ package mage.cards.g; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; @@ -27,8 +28,6 @@ import mage.players.Player; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; -import java.util.UUID; - /** * * @author noahg @@ -43,7 +42,7 @@ public final class GiantOyster extends CardImpl { public GiantOyster(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); - + this.subtype.add(SubType.OYSTER); this.power = new MageInt(0); this.toughness = new MageInt(3); @@ -111,7 +110,6 @@ class GiantOysterCreateDelayedTriggerEffects extends OneShotEffect { Effect addCountersEffect = new AddCountersTargetEffect(CounterType.M1M1.createInstance(1)); addCountersEffect.setTargetPointer(getTargetPointer().getFixedTarget(game, source)); DelayedTriggeredAbility drawStepAbility = new AtTheBeginOfYourNextDrawStepDelayedTriggeredAbility(addCountersEffect, Duration.Custom, false); - drawStepAbility.setSourceObject(oyster, game); drawStepAbility.setControllerId(source.getControllerId()); UUID drawStepAbilityUUID = game.addDelayedTriggeredAbility(drawStepAbility, source); @@ -161,4 +159,4 @@ class GiantOysterLeaveUntapDelayedTriggeredAbility extends DelayedTriggeredAbili public String getRule() { return "When {this} leaves the battlefield or becomes untapped, remove all -1/-1 counters from the creature."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/p/PermeatingMass.java b/Mage.Sets/src/mage/cards/p/PermeatingMass.java index 58a7466de34..286739e23c1 100644 --- a/Mage.Sets/src/mage/cards/p/PermeatingMass.java +++ b/Mage.Sets/src/mage/cards/p/PermeatingMass.java @@ -1,4 +1,3 @@ - package mage.cards.p; import java.util.UUID; @@ -9,9 +8,9 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.util.functions.EmptyApplyToPermanent; @@ -23,7 +22,7 @@ import mage.util.functions.EmptyApplyToPermanent; public final class PermeatingMass extends CardImpl { public PermeatingMass(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); this.subtype.add(SubType.SPIRIT); this.power = new MageInt(1); this.toughness = new MageInt(3); @@ -62,7 +61,7 @@ class PermeatingMassEffect extends OneShotEffect { public boolean apply(Game game, Ability ability) { Permanent copyTo = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, ability)); if (copyTo != null) { - Permanent copyFrom = (Permanent) ability.getSourceObject(game); + Permanent copyFrom = ability.getSourcePermanentOrLKI(game); if (copyFrom != null) { game.copyPermanent(Duration.Custom, copyFrom, copyTo.getId(), ability, new EmptyApplyToPermanent()); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/SpitefulShadowsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/SpitefulShadowsTest.java index 42628bca6c2..4eaffcbd2b7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/SpitefulShadowsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/SpitefulShadowsTest.java @@ -39,9 +39,11 @@ public class SpitefulShadowsTest extends CardTestPlayerBase { @Test public void testCard1() { - addCard(Zone.BATTLEFIELD, playerA, "Craw Wurm"); + addCard(Zone.BATTLEFIELD, playerA, "Craw Wurm"); // Creature 6/4 addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); + // Enchant creature + // Whenever enchanted creature is dealt damage, it deals that much damage to its controller. addCard(Zone.HAND, playerA, "Spiteful Shadows"); addCard(Zone.HAND, playerA, "Lightning Bolt"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/FiendHunterTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/FiendHunterTest.java index 705a274c36d..e7aa5a62bd6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/FiendHunterTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/FiendHunterTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.abilities.oneshot.exile; import mage.constants.PhaseStep; @@ -70,10 +69,9 @@ public class FiendHunterTest extends CardTestPlayerBase { execute(); assertExileCount("Silvercoat Lion", 1); - assertPermanentCount(playerB, "Primeval Titan", 1); - assertPermanentCount(playerA, "Fiend Hunter", 1); assertPermanentCount(playerA, "Restoration Angel", 1); + assertPermanentCount(playerB, "Primeval Titan", 1); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/LimitedCountedActivationsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/LimitedCountedActivationsTest.java index 7901a6d153b..74b14b0b2f9 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/LimitedCountedActivationsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/LimitedCountedActivationsTest.java @@ -1,179 +1,180 @@ - -package org.mage.test.cards.abilities.other; - -import mage.constants.PhaseStep; -import mage.constants.Zone; -import org.junit.Test; -import org.mage.test.serverside.base.CardTestPlayerBase; - -/** - * - * @author LevelX2 - */ -public class LimitedCountedActivationsTest extends CardTestPlayerBase { - - /** - * Tests usage of ActivationInfo class - */ - @Test - public void testDragonWhelpActivatedThreeTimes() { - addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); - // Flying - // {R}: Dragon Whelp gets +1/+0 until end of turn. If this ability has been activated four or more times this turn, sacrifice Dragon Whelp at the beginning of the next end step. - addCard(Zone.BATTLEFIELD, playerA, "Dragon Whelp", 1); // 3/3 - - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - - attack(1, playerA, "Dragon Whelp"); - - setStopAt(2, PhaseStep.UPKEEP); - execute(); - - assertPermanentCount(playerA, "Dragon Whelp", 1); - - assertLife(playerA, 20); - assertLife(playerB, 15); - } - - @Test - public void testDragonWhelpActivatedFourTimes() { - addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); - // Flying - // {R}: Dragon Whelp gets +1/+0 until end of turn. If this ability has been activated four or more times this turn, sacrifice Dragon Whelp at the beginning of the next end step. - addCard(Zone.BATTLEFIELD, playerA, "Dragon Whelp", 1); // 3/3 - - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - - attack(1, playerA, "Dragon Whelp"); - - setStopAt(2, PhaseStep.UPKEEP); - execute(); - - assertPermanentCount(playerA, "Dragon Whelp", 0); - assertGraveyardCount(playerA, "Dragon Whelp", 1); - - assertLife(playerA, 20); - assertLife(playerB, 14); - } - - @Test - public void testDragonWhelpActivatedFiveTimes() { - addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); - // Flying - // {R}: Dragon Whelp gets +1/+0 until end of turn. If this ability has been activated four or more times this turn, sacrifice Dragon Whelp at the beginning of the next end step. - addCard(Zone.BATTLEFIELD, playerA, "Dragon Whelp", 1); // 3/3 - - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - - attack(1, playerA, "Dragon Whelp"); - - setStopAt(2, PhaseStep.UPKEEP); - execute(); - - assertPermanentCount(playerA, "Dragon Whelp", 0); - assertGraveyardCount(playerA, "Dragon Whelp", 1); - - assertLife(playerA, 20); - assertLife(playerB, 13); - } - - @Test - public void testDragonWhelpTwoObjects() { - addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); - addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); - // Flying - // {R}: Dragon Whelp gets +1/+0 until end of turn. If this ability has been activated four or more times this turn, sacrifice Dragon Whelp at the beginning of the next end step. - addCard(Zone.BATTLEFIELD, playerA, "Dragon Whelp", 1); // 3/3 - // Put target creature card from a graveyard onto the battlefield under your control. You lose life equal to its converted mana cost. - addCard(Zone.HAND, playerA, "Reanimate", 1); - // Target creature gains haste until end of turn. - addCard(Zone.HAND, playerA, "Unnatural Speed", 1); - - addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2); - // Destroy target nonartifact, nonblack creature. It can't be regenerated. - addCard(Zone.HAND, playerB, "Terror", 1); // {1}{B} - - activateAbility(1, PhaseStep.UPKEEP, playerA, "{R}: "); - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Terror", "Dragon Whelp"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate", "Dragon Whelp"); - castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Unnatural Speed", "Dragon Whelp"); - - activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); - activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); - activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); - - attack(1, playerA, "Dragon Whelp"); - - setStopAt(2, PhaseStep.UPKEEP); - execute(); - - assertGraveyardCount(playerA, "Unnatural Speed", 1); - assertGraveyardCount(playerA, "Reanimate", 1); - - assertGraveyardCount(playerB, "Terror", 1); - - assertPermanentCount(playerA, "Dragon Whelp", 1); - assertPowerToughness(playerA, "Dragon Whelp", 2, 3); - assertGraveyardCount(playerA, "Dragon Whelp", 0); - - assertLife(playerA, 16); - assertLife(playerB, 15); - } - - @Test - public void testDragonWhelpDontSacrificeNewObject() { - addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8); - addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); - // Flying - // {R}: Dragon Whelp gets +1/+0 until end of turn. If this ability has been activated four or more times this turn, sacrifice Dragon Whelp at the beginning of the next end step. - addCard(Zone.BATTLEFIELD, playerA, "Dragon Whelp", 1); // 3/3 - // Put target creature card from a graveyard onto the battlefield under your control. You lose life equal to its converted mana cost. - addCard(Zone.HAND, playerA, "Reanimate", 1); - // Target creature gains haste until end of turn. - addCard(Zone.HAND, playerA, "Unnatural Speed", 1); - - addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2); - // Destroy target nonartifact, nonblack creature. It can't be regenerated. - addCard(Zone.HAND, playerB, "Terror", 1); // {1}{B} - - activateAbility(1, PhaseStep.UPKEEP, playerA, "{R}: "); - activateAbility(1, PhaseStep.UPKEEP, playerA, "{R}: "); - activateAbility(1, PhaseStep.UPKEEP, playerA, "{R}: "); - activateAbility(1, PhaseStep.UPKEEP, playerA, "{R}: "); - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Terror", "Dragon Whelp"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate", "Dragon Whelp"); - castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Unnatural Speed", "Dragon Whelp"); - - activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); - activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); - activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); - - attack(1, playerA, "Dragon Whelp"); - - setStopAt(2, PhaseStep.UPKEEP); - execute(); - - assertGraveyardCount(playerA, "Unnatural Speed", 1); - assertGraveyardCount(playerA, "Reanimate", 1); - - assertGraveyardCount(playerB, "Terror", 1); - - assertPermanentCount(playerA, "Dragon Whelp", 1); - assertPowerToughness(playerA, "Dragon Whelp", 2, 3); - assertGraveyardCount(playerA, "Dragon Whelp", 0); - - assertLife(playerA, 16); - assertLife(playerB, 15); - } -} +package org.mage.test.cards.abilities.other; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class LimitedCountedActivationsTest extends CardTestPlayerBase { + + /** + * Tests usage of ActivationInfo class + */ + @Test + public void testDragonWhelpActivatedThreeTimes() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + // Flying + // {R}: Dragon Whelp gets +1/+0 until end of turn. If this ability has been activated four or more times this turn, sacrifice Dragon Whelp at the beginning of the next end step. + addCard(Zone.BATTLEFIELD, playerA, "Dragon Whelp", 1); // 3/3 + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + + attack(1, playerA, "Dragon Whelp"); + + setStopAt(2, PhaseStep.UPKEEP); + execute(); + + assertPermanentCount(playerA, "Dragon Whelp", 1); + + assertLife(playerA, 20); + assertLife(playerB, 15); + } + + @Test + public void testDragonWhelpActivatedFourTimes() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); + // Flying + // {R}: Dragon Whelp gets +1/+0 until end of turn. If this ability has been activated four or more times this turn, sacrifice Dragon Whelp at the beginning of the next end step. + addCard(Zone.BATTLEFIELD, playerA, "Dragon Whelp", 1); // 3/3 + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + + attack(1, playerA, "Dragon Whelp"); + + setStopAt(2, PhaseStep.UPKEEP); + execute(); + + assertPermanentCount(playerA, "Dragon Whelp", 0); + assertGraveyardCount(playerA, "Dragon Whelp", 1); + + assertLife(playerA, 20); + assertLife(playerB, 14); + } + + @Test + public void testDragonWhelpActivatedFiveTimes() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + // Flying + // {R}: Dragon Whelp gets +1/+0 until end of turn. If this ability has been activated four or more times this turn, sacrifice Dragon Whelp at the beginning of the next end step. + addCard(Zone.BATTLEFIELD, playerA, "Dragon Whelp", 1); // 3/3 + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + + attack(1, playerA, "Dragon Whelp"); + + setStopAt(2, PhaseStep.UPKEEP); + execute(); + + assertPermanentCount(playerA, "Dragon Whelp", 0); + assertGraveyardCount(playerA, "Dragon Whelp", 1); + + assertLife(playerA, 20); + assertLife(playerB, 13); + } + + @Test + public void testDragonWhelpTwoObjects() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + // Flying + // {R}: Dragon Whelp gets +1/+0 until end of turn. If this ability has been activated four or more times this turn, sacrifice Dragon Whelp at the beginning of the next end step. + addCard(Zone.BATTLEFIELD, playerA, "Dragon Whelp", 1); // 3/3 + // Put target creature card from a graveyard onto the battlefield under your control. You lose life equal to its converted mana cost. + addCard(Zone.HAND, playerA, "Reanimate", 1); + // Target creature gains haste until end of turn. + addCard(Zone.HAND, playerA, "Unnatural Speed", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2); + // Destroy target nonartifact, nonblack creature. It can't be regenerated. + addCard(Zone.HAND, playerB, "Terror", 1); // {1}{B} + + activateAbility(1, PhaseStep.UPKEEP, playerA, "{R}: "); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Terror", "Dragon Whelp"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate", "Dragon Whelp"); + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Unnatural Speed", "Dragon Whelp"); + + activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); + activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); + activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); + + attack(1, playerA, "Dragon Whelp"); + + setStopAt(2, PhaseStep.UPKEEP); + execute(); + + assertGraveyardCount(playerA, "Unnatural Speed", 1); + assertGraveyardCount(playerA, "Reanimate", 1); + + assertGraveyardCount(playerB, "Terror", 1); + + assertPermanentCount(playerA, "Dragon Whelp", 1); + assertPowerToughness(playerA, "Dragon Whelp", 2, 3); + assertGraveyardCount(playerA, "Dragon Whelp", 0); + + assertLife(playerA, 16); + assertLife(playerB, 15); + } + + @Test + public void testDragonWhelpDontSacrificeNewObject() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + // Flying + // {R}: Dragon Whelp gets +1/+0 until end of turn. If this ability has been activated four or more times this turn, sacrifice Dragon Whelp at the beginning of the next end step. + addCard(Zone.BATTLEFIELD, playerA, "Dragon Whelp", 1); // 3/3 + // Put target creature card from a graveyard onto the battlefield under your control. You lose life equal to its converted mana cost. + addCard(Zone.HAND, playerA, "Reanimate", 1); + // Target creature gains haste until end of turn. + addCard(Zone.HAND, playerA, "Unnatural Speed", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2); + // Destroy target nonartifact, nonblack creature. It can't be regenerated. + addCard(Zone.HAND, playerB, "Terror", 1); // {1}{B} + + activateAbility(1, PhaseStep.UPKEEP, playerA, "{R}: "); + activateAbility(1, PhaseStep.UPKEEP, playerA, "{R}: "); + activateAbility(1, PhaseStep.UPKEEP, playerA, "{R}: "); + activateAbility(1, PhaseStep.UPKEEP, playerA, "{R}: "); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Terror", "Dragon Whelp"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate", "Dragon Whelp"); + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Unnatural Speed", "Dragon Whelp"); + + activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); + activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); + activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); + + attack(1, playerA, "Dragon Whelp"); + + setStopAt(2, PhaseStep.UPKEEP); + execute(); + + assertGraveyardCount(playerA, "Unnatural Speed", 1); + assertGraveyardCount(playerA, "Reanimate", 1); + + assertGraveyardCount(playerB, "Terror", 1); + + assertLife(playerA, 16); + assertLife(playerB, 15); + + assertGraveyardCount(playerA, "Dragon Whelp", 0); + + assertPermanentCount(playerA, "Dragon Whelp", 1); + assertPowerToughness(playerA, "Dragon Whelp", 2, 3); + + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/mana/HarvestMageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/mana/HarvestMageTest.java new file mode 100644 index 00000000000..ac39080b792 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/mana/HarvestMageTest.java @@ -0,0 +1,35 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.mage.test.cards.mana; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class HarvestMageTest extends CardTestPlayerBase { + + @Test + public void testOneInstance() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + + // {G}, {T}, Discard a card: Until end of turn, if you tap a land for mana, it produces one mana of a color of your choice instead of any other type and amount. + addCard(Zone.HAND, playerA, "Harvest Mage", 1); // Creature 1/1 {G} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Harvest Mage"); + + activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{G}, {T}, Discard a card: Until end of turn"); + setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, "Harvest Mage", 1); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/multiplayer/BlatantThieveryTest.java b/Mage.Tests/src/test/java/org/mage/test/multiplayer/BlatantThieveryTest.java index a5447b94b15..049e958347b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/multiplayer/BlatantThieveryTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/multiplayer/BlatantThieveryTest.java @@ -52,6 +52,7 @@ public class BlatantThieveryTest extends CardTestMultiPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertGraveyardCount(playerA, "Blatant Thievery", 1); assertPermanentCount(playerA, "Silvercoat Lion", 1); assertPermanentCount(playerA, "Walking Corpse", 1); assertPermanentCount(playerA, "Pillarfield Ox", 1); diff --git a/Mage/src/main/java/mage/abilities/Ability.java b/Mage/src/main/java/mage/abilities/Ability.java index 9701e1a140a..4ef44edad6f 100644 --- a/Mage/src/main/java/mage/abilities/Ability.java +++ b/Mage/src/main/java/mage/abilities/Ability.java @@ -479,16 +479,7 @@ public interface Ability extends Controllable, Serializable { boolean activateAlternateOrAdditionalCosts(MageObject sourceObject, boolean noMana, Player controller, Game game); /** - * Sets the object that actually existed while a ability triggerd or an - * ability was activated. - * - * @param mageObject - * @param game - */ - void setSourceObject(MageObject mageObject, Game game); - - /** - * Returns the object that actually existed while a ability triggerd or an + * Returns the object that actually existed while a ability triggered or an * ability was activated. If not set yet, the current object will be * retrieved from the game. * @@ -497,6 +488,8 @@ public interface Ability extends Controllable, Serializable { */ MageObject getSourceObject(Game game); + void setSourceObjectZoneChangeCounter(int zoneChangeCounter); + int getSourceObjectZoneChangeCounter(); /** @@ -520,6 +513,8 @@ public interface Ability extends Controllable, Serializable { */ Permanent getSourcePermanentIfItStillExists(Game game); + Permanent getSourcePermanentOrLKI(Game game); + String getTargetDescription(Targets targets, Game game); void setCanFizzle(boolean canFizzle); diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index 7404a425274..481658c5078 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -5,7 +5,6 @@ import java.util.Iterator; import java.util.List; import java.util.UUID; import mage.MageObject; -import mage.MageObjectReference; import mage.Mana; import mage.abilities.costs.*; import mage.abilities.costs.common.PayLifeCost; @@ -67,7 +66,6 @@ public abstract class AbilityImpl implements Ability { protected boolean costModificationActive = true; protected boolean activated = false; protected boolean worksFaceDown = false; - protected MageObject sourceObject; protected int sourceObjectZoneChangeCounter; protected List watchers = new ArrayList<>(); protected List subAbilities = null; @@ -116,7 +114,6 @@ public abstract class AbilityImpl implements Ability { this.costModificationActive = ability.costModificationActive; this.worksFaceDown = ability.worksFaceDown; this.abilityWord = ability.abilityWord; - this.sourceObject = null; // you may not copy this because otherwise simulation may modify real game object this.sourceObjectZoneChangeCounter = ability.sourceObjectZoneChangeCounter; this.canFizzle = ability.canFizzle; this.targetAdjuster = ability.targetAdjuster; @@ -131,8 +128,6 @@ public abstract class AbilityImpl implements Ability { public void newId() { if (!(this instanceof MageSingleton)) { this.id = UUID.randomUUID(); -// this.sourceObject = null; -// this.sourceObjectZoneChangeCounter = -1; } getEffects().newId(); } @@ -226,8 +221,10 @@ public abstract class AbilityImpl implements Ability { return false; } - getSourceObject(game); - + MageObject sourceObject = getSourceObject(game); + if (getSourceObjectZoneChangeCounter() == 0) { + setSourceObjectZoneChangeCounter(game.getState().getZoneChangeCounter(getSourceId())); + } if (controller.isTestMode()) { if (!controller.addTargets(this, game)) { return false; @@ -1160,58 +1157,44 @@ public abstract class AbilityImpl implements Ability { @Override public MageObject getSourceObject(Game game) { - if (sourceObject == null) { - setSourceObject(null, game); - if (sourceObject == null) { - logger.warn("Source object could not be retrieved: " + this.getRule()); - } - } - return sourceObject; + return game.getObject(getSourceId()); } @Override public MageObject getSourceObjectIfItStillExists(Game game) { - MageObject currentObject = game.getObject(getSourceId()); - if (currentObject != null) { - if (sourceObject == null) { - setSourceObject(currentObject, game); - } - MageObjectReference mor = new MageObjectReference(currentObject, game); - if (mor.getZoneChangeCounter() == getSourceObjectZoneChangeCounter()) { - // source object has meanwhile not changed zone - return currentObject; - } + if (getSourceObjectZoneChangeCounter() == 0 + || getSourceObjectZoneChangeCounter() == game.getState().getZoneChangeCounter(getSourceId())) { + return game.getObject(getSourceId()); } return null; } @Override public Permanent getSourcePermanentIfItStillExists(Game game) { - if (sourceObject == null || !sourceObject.getId().equals(getSourceId())) { - setSourceObject(game.getObject(getSourceId()), game); - } - if (sourceObject instanceof Permanent) { - if (game.getState().getZoneChangeCounter(getSourceId()) == getSourceObjectZoneChangeCounter()) { - return (Permanent) sourceObject; - } + MageObject mageObject = getSourceObjectIfItStillExists(game); + if (mageObject instanceof Permanent) { + return (Permanent) mageObject; } return null; } @Override - public int getSourceObjectZoneChangeCounter() { - return sourceObjectZoneChangeCounter; + public Permanent getSourcePermanentOrLKI(Game game) { + if (getSourceObjectZoneChangeCounter() == 0 + || getSourceObjectZoneChangeCounter() == game.getState().getZoneChangeCounter(getSourceId())) { + return game.getPermanent(getSourceId()); + } + return (Permanent) game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD, getSourceObjectZoneChangeCounter()); } @Override - public void setSourceObject(MageObject sourceObject, Game game) { - if (sourceObject == null) { - this.sourceObject = game.getObject(sourceId); - this.sourceObjectZoneChangeCounter = game.getState().getZoneChangeCounter(sourceId); - } else { - this.sourceObject = sourceObject; - this.sourceObjectZoneChangeCounter = this.sourceObject.getZoneChangeCounter(game); - } + public void setSourceObjectZoneChangeCounter(int sourceObjectZoneChangeCounter) { + this.sourceObjectZoneChangeCounter = sourceObjectZoneChangeCounter; + } + + @Override + public int getSourceObjectZoneChangeCounter() { + return sourceObjectZoneChangeCounter; } @Override diff --git a/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java b/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java index e341ee74be2..55e5bfb9c2f 100644 --- a/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java @@ -1,4 +1,3 @@ - package mage.abilities; import java.util.Locale; @@ -45,9 +44,6 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge @Override public void trigger(Game game, UUID controllerId) { //20091005 - 603.4 - if (!(this instanceof DelayedTriggeredAbility)) { - setSourceObject(null, game); - } if (checkInterveningIfClause(game)) { game.addTriggeredAbility(this); } diff --git a/Mage/src/main/java/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java b/Mage/src/main/java/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java index c7c465dd247..8ec64e77600 100644 --- a/Mage/src/main/java/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java +++ b/Mage/src/main/java/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java @@ -1,4 +1,3 @@ - package mage.abilities.common.delayed; import java.util.LinkedHashSet; diff --git a/Mage/src/main/java/mage/abilities/effects/common/SacrificeSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SacrificeSourceEffect.java index b4e9339de44..806acf2a7ed 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/SacrificeSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/SacrificeSourceEffect.java @@ -1,13 +1,12 @@ - package mage.abilities.effects.common; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; +import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.stack.Spell; /** * @@ -34,11 +33,9 @@ public class SacrificeSourceEffect extends OneShotEffect { MageObject sourceObject = source.getSourceObjectIfItStillExists(game); if (sourceObject == null) { // Check if the effect was installed by the spell the source was cast by (e.g. Necromancy), if not don't sacrifice the permanent - if (source.getSourceObject(game) instanceof Spell) { + if (game.getState().getZone(source.getSourceId()).equals(Zone.BATTLEFIELD) + && source.getSourceObjectZoneChangeCounter() + 1 == game.getState().getZoneChangeCounter(source.getSourceId())) { sourceObject = game.getPermanent(source.getSourceId()); - if (sourceObject != null && sourceObject.getZoneChangeCounter(game) > source.getSourceObjectZoneChangeCounter() + 1) { - return false; - } } } if (sourceObject instanceof Permanent) { diff --git a/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java b/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java index ebd11af1fb6..1f0723298d2 100644 --- a/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java @@ -1,6 +1,5 @@ package mage.abilities.meta; -import mage.MageObject; import mage.abilities.TriggeredAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; @@ -14,9 +13,12 @@ import java.util.List; import java.util.UUID; /** - * A triggered ability that combines several others and triggers whenever one or more of them would. The abilities - * passed in should have null as their effect, and should have their own targets set if necessary. All other information - * will be passed in from changes to this Ability. Note: this does NOT work with abilities that have intervening if clauses. + * A triggered ability that combines several others and triggers whenever one or + * more of them would. The abilities passed in should have null as their effect, + * and should have their own targets set if necessary. All other information + * will be passed in from changes to this Ability. Note: this does NOT work with + * abilities that have intervening if clauses. + * * @author noahg */ public class OrTriggeredAbility extends TriggeredAbilityImpl { @@ -43,18 +45,17 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl { public OrTriggeredAbility(OrTriggeredAbility ability) { super(ability); this.triggeredAbilities = new TriggeredAbility[ability.triggeredAbilities.length]; - for (int i = 0; i < this.triggeredAbilities.length; i++){ + for (int i = 0; i < this.triggeredAbilities.length; i++) { this.triggeredAbilities[i] = ability.triggeredAbilities[i].copy(); } this.triggeringAbilities = new ArrayList<>(ability.triggeringAbilities); this.ruleTrigger = ability.ruleTrigger; } - @Override public boolean checkEventType(GameEvent event, Game game) { for (TriggeredAbility ability : triggeredAbilities) { - if (ability.checkEventType(event, game)){ + if (ability.checkEventType(event, game)) { System.out.println("Correct event type (" + event.getType() + ")"); return true; } @@ -101,7 +102,6 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl { return sb.toString() + super.getRule(); } - @Override public void setControllerId(UUID controllerId) { super.setControllerId(controllerId); @@ -126,11 +126,4 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl { } } - @Override - public void setSourceObject(MageObject sourceObject, Game game) { - super.setSourceObject(sourceObject, game); - for (TriggeredAbility ability : triggeredAbilities) { - ability.setSourceObject(sourceObject, game); - } - } } diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index e745c75e129..18747ba2cf5 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -1527,7 +1527,7 @@ public abstract class GameImpl implements Game, Serializable { @Override public void addEffect(ContinuousEffect continuousEffect, Ability source) { Ability newAbility = source.copy(); - newAbility.setSourceObject(null, this); // Update the source object to the currently existing Object + newAbility.setSourceObjectZoneChangeCounter(getState().getZoneChangeCounter(source.getSourceId())); ContinuousEffect newEffect = continuousEffect.copy(); newEffect.newId(); @@ -1698,11 +1698,17 @@ public abstract class GameImpl implements Game, Serializable { if (ability instanceof TriggeredManaAbility || ability instanceof DelayedTriggeredManaAbility) { // 20110715 - 605.4 Ability manaAbiltiy = ability.copy(); + if (manaAbiltiy.getSourceObjectZoneChangeCounter() == 0) { + manaAbiltiy.setSourceObjectZoneChangeCounter(getState().getZoneChangeCounter(ability.getSourceId())); + } manaAbiltiy.activate(this, false); manaAbiltiy.resolve(this); } else { TriggeredAbility newAbility = ability.copy(); newAbility.newId(); + if (newAbility.getSourceObjectZoneChangeCounter() == 0) { + newAbility.setSourceObjectZoneChangeCounter(getState().getZoneChangeCounter(ability.getSourceId())); + } state.addTriggeredAbility(newAbility); } } @@ -1711,10 +1717,10 @@ public abstract class GameImpl implements Game, Serializable { public UUID addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility, Ability source) { delayedAbility.setSourceId(source.getSourceId()); delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(this), this); // return addDelayedTriggeredAbility(delayedAbility); DelayedTriggeredAbility newAbility = delayedAbility.copy(); newAbility.newId(); + newAbility.setSourceObjectZoneChangeCounter(getState().getZoneChangeCounter(source.getSourceId())); newAbility.initOnAdding(this); // ability.init is called as the ability triggeres not now. // If a FixedTarget pointer is already set from the effect setting up this delayed ability diff --git a/Mage/src/main/java/mage/game/command/Emblem.java b/Mage/src/main/java/mage/game/command/Emblem.java index 898a5aeb562..d95cfb659d6 100644 --- a/Mage/src/main/java/mage/game/command/Emblem.java +++ b/Mage/src/main/java/mage/game/command/Emblem.java @@ -1,4 +1,3 @@ - package mage.game.command; import java.util.EnumSet; diff --git a/Mage/src/main/java/mage/game/command/Plane.java b/Mage/src/main/java/mage/game/command/Plane.java index b6a3768c298..ae34edade03 100644 --- a/Mage/src/main/java/mage/game/command/Plane.java +++ b/Mage/src/main/java/mage/game/command/Plane.java @@ -1,7 +1,5 @@ - package mage.game.command; -import static java.lang.Math.log; import java.lang.reflect.Constructor; import java.util.EnumSet; import java.util.List; @@ -289,7 +287,7 @@ public class Plane implements CommandObject { if (plane instanceof Plane) { return (Plane) plane; } - } catch (Exception ex) { + } catch (Exception ex) { } return null; } diff --git a/Mage/src/main/java/mage/game/stack/StackAbility.java b/Mage/src/main/java/mage/game/stack/StackAbility.java index 4c7259ed7d8..02546c99c23 100644 --- a/Mage/src/main/java/mage/game/stack/StackAbility.java +++ b/Mage/src/main/java/mage/game/stack/StackAbility.java @@ -518,14 +518,19 @@ public class StackAbility extends StackObjImpl implements Ability { return this.ability.getSourcePermanentIfItStillExists(game); } + @Override + public void setSourceObjectZoneChangeCounter(int zoneChangeCounter) { + ability.setSourceObjectZoneChangeCounter(zoneChangeCounter); + } + @Override public int getSourceObjectZoneChangeCounter() { return ability.getSourceObjectZoneChangeCounter(); } @Override - public void setSourceObject(MageObject sourceObject, Game game) { - throw new UnsupportedOperationException("Not supported."); + public Permanent getSourcePermanentOrLKI(Game game) { + return ability.getSourcePermanentOrLKI(game); } @Override diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 42eebc64e77..efc4c7b977d 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -1041,15 +1041,15 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean cast(SpellAbility ability, Game game, boolean noMana, MageObjectReference permittingObject) { - if (game == null || ability == null) { + public boolean cast(SpellAbility originalAbility, Game game, boolean noMana, MageObjectReference permittingObject) { + if (game == null || originalAbility == null) { return false; } // Use ability copy to avoid problems with targets and costs on recast (issue https://github.com/magefree/mage/issues/5189). - ability = ability.copy(); - + SpellAbility ability = originalAbility.copy(); ability.setControllerId(getId()); + ability.setSourceObjectZoneChangeCounter(game.getState().getZoneChangeCounter(ability.getSourceId())); if (ability.getSpellAbilityType() != SpellAbilityType.BASE) { ability = chooseSpellAbilityForCast(ability, game, noMana); if (ability == null) { @@ -1073,6 +1073,8 @@ public abstract class PlayerImpl implements Player, Serializable { logger.error("Got no spell from stack. ability: " + ability.getRule()); return false; } + // Update the zcc to the stack + ability.setSourceObjectZoneChangeCounter(game.getState().getZoneChangeCounter(ability.getSourceId())); // some effects set sourceId to cast without paying mana costs or other costs if (ability.getSourceId().equals(getCastSourceIdWithAlternateMana())) { Ability spellAbility = spell.getSpellAbility();