mirror of
https://github.com/magefree/mage.git
synced 2025-12-22 11:32:00 -08:00
Reworked ability source object handling.
This commit is contained in:
parent
e6b78d7a2e
commit
26a93d4427
19 changed files with 292 additions and 288 deletions
|
|
@ -1,6 +1,9 @@
|
||||||
|
|
||||||
package mage.cards.c;
|
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.MageObjectReference;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.DelayedTriggeredAbility;
|
import mage.abilities.DelayedTriggeredAbility;
|
||||||
|
|
@ -31,11 +34,6 @@ import mage.target.common.TargetLandPermanent;
|
||||||
import mage.target.targetpointer.FixedTarget;
|
import mage.target.targetpointer.FixedTarget;
|
||||||
import mage.watchers.Watcher;
|
import mage.watchers.Watcher;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author MTGfan
|
* @author MTGfan
|
||||||
|
|
@ -123,7 +121,6 @@ class CyclopeanTombCreateTriggeredEffect extends OneShotEffect {
|
||||||
if (controller != null) {
|
if (controller != null) {
|
||||||
Permanent tomb = game.getPermanentOrLKIBattlefield(source.getSourceId()); // we need to set the correct source object
|
Permanent tomb = game.getPermanentOrLKIBattlefield(source.getSourceId()); // we need to set the correct source object
|
||||||
DelayedTriggeredAbility ability = new AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility(new CyclopeanTombEffect(), Duration.EndOfGame, false);
|
DelayedTriggeredAbility ability = new AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility(new CyclopeanTombEffect(), Duration.EndOfGame, false);
|
||||||
ability.setSourceObject(tomb, game);
|
|
||||||
ability.setControllerId(source.getControllerId());
|
ability.setControllerId(source.getControllerId());
|
||||||
ability.setSourceId(source.getSourceId());
|
ability.setSourceId(source.getSourceId());
|
||||||
game.addDelayedTriggeredAbility(ability);
|
game.addDelayedTriggeredAbility(ability);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package mage.cards.g;
|
package mage.cards.g;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.DelayedTriggeredAbility;
|
import mage.abilities.DelayedTriggeredAbility;
|
||||||
|
|
@ -27,8 +28,6 @@ import mage.players.Player;
|
||||||
import mage.target.common.TargetCreaturePermanent;
|
import mage.target.common.TargetCreaturePermanent;
|
||||||
import mage.target.targetpointer.FixedTarget;
|
import mage.target.targetpointer.FixedTarget;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author noahg
|
* @author noahg
|
||||||
|
|
@ -43,7 +42,7 @@ public final class GiantOyster extends CardImpl {
|
||||||
|
|
||||||
public GiantOyster(UUID ownerId, CardSetInfo setInfo) {
|
public GiantOyster(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}");
|
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}");
|
||||||
|
|
||||||
this.subtype.add(SubType.OYSTER);
|
this.subtype.add(SubType.OYSTER);
|
||||||
this.power = new MageInt(0);
|
this.power = new MageInt(0);
|
||||||
this.toughness = new MageInt(3);
|
this.toughness = new MageInt(3);
|
||||||
|
|
@ -111,7 +110,6 @@ class GiantOysterCreateDelayedTriggerEffects extends OneShotEffect {
|
||||||
Effect addCountersEffect = new AddCountersTargetEffect(CounterType.M1M1.createInstance(1));
|
Effect addCountersEffect = new AddCountersTargetEffect(CounterType.M1M1.createInstance(1));
|
||||||
addCountersEffect.setTargetPointer(getTargetPointer().getFixedTarget(game, source));
|
addCountersEffect.setTargetPointer(getTargetPointer().getFixedTarget(game, source));
|
||||||
DelayedTriggeredAbility drawStepAbility = new AtTheBeginOfYourNextDrawStepDelayedTriggeredAbility(addCountersEffect, Duration.Custom, false);
|
DelayedTriggeredAbility drawStepAbility = new AtTheBeginOfYourNextDrawStepDelayedTriggeredAbility(addCountersEffect, Duration.Custom, false);
|
||||||
drawStepAbility.setSourceObject(oyster, game);
|
|
||||||
drawStepAbility.setControllerId(source.getControllerId());
|
drawStepAbility.setControllerId(source.getControllerId());
|
||||||
UUID drawStepAbilityUUID = game.addDelayedTriggeredAbility(drawStepAbility, source);
|
UUID drawStepAbilityUUID = game.addDelayedTriggeredAbility(drawStepAbility, source);
|
||||||
|
|
||||||
|
|
@ -161,4 +159,4 @@ class GiantOysterLeaveUntapDelayedTriggeredAbility extends DelayedTriggeredAbili
|
||||||
public String getRule() {
|
public String getRule() {
|
||||||
return "When {this} leaves the battlefield or becomes untapped, remove all -1/-1 counters from the creature.";
|
return "When {this} leaves the battlefield or becomes untapped, remove all -1/-1 counters from the creature.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
package mage.cards.p;
|
package mage.cards.p;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
@ -9,9 +8,9 @@ import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.SubType;
|
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.SubType;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.util.functions.EmptyApplyToPermanent;
|
import mage.util.functions.EmptyApplyToPermanent;
|
||||||
|
|
@ -23,7 +22,7 @@ import mage.util.functions.EmptyApplyToPermanent;
|
||||||
public final class PermeatingMass extends CardImpl {
|
public final class PermeatingMass extends CardImpl {
|
||||||
|
|
||||||
public PermeatingMass(UUID ownerId, CardSetInfo setInfo) {
|
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.subtype.add(SubType.SPIRIT);
|
||||||
this.power = new MageInt(1);
|
this.power = new MageInt(1);
|
||||||
this.toughness = new MageInt(3);
|
this.toughness = new MageInt(3);
|
||||||
|
|
@ -62,7 +61,7 @@ class PermeatingMassEffect extends OneShotEffect {
|
||||||
public boolean apply(Game game, Ability ability) {
|
public boolean apply(Game game, Ability ability) {
|
||||||
Permanent copyTo = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, ability));
|
Permanent copyTo = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, ability));
|
||||||
if (copyTo != null) {
|
if (copyTo != null) {
|
||||||
Permanent copyFrom = (Permanent) ability.getSourceObject(game);
|
Permanent copyFrom = ability.getSourcePermanentOrLKI(game);
|
||||||
if (copyFrom != null) {
|
if (copyFrom != null) {
|
||||||
game.copyPermanent(Duration.Custom, copyFrom, copyTo.getId(), ability, new EmptyApplyToPermanent());
|
game.copyPermanent(Duration.Custom, copyFrom, copyTo.getId(), ability, new EmptyApplyToPermanent());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,11 @@ public class SpitefulShadowsTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCard1() {
|
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, "Swamp", 2);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 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, "Spiteful Shadows");
|
||||||
addCard(Zone.HAND, playerA, "Lightning Bolt");
|
addCard(Zone.HAND, playerA, "Lightning Bolt");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
package org.mage.test.cards.abilities.oneshot.exile;
|
package org.mage.test.cards.abilities.oneshot.exile;
|
||||||
|
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
|
|
@ -70,10 +69,9 @@ public class FiendHunterTest extends CardTestPlayerBase {
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
assertExileCount("Silvercoat Lion", 1);
|
assertExileCount("Silvercoat Lion", 1);
|
||||||
assertPermanentCount(playerB, "Primeval Titan", 1);
|
|
||||||
|
|
||||||
assertPermanentCount(playerA, "Fiend Hunter", 1);
|
assertPermanentCount(playerA, "Fiend Hunter", 1);
|
||||||
assertPermanentCount(playerA, "Restoration Angel", 1);
|
assertPermanentCount(playerA, "Restoration Angel", 1);
|
||||||
|
assertPermanentCount(playerB, "Primeval Titan", 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,179 +1,180 @@
|
||||||
|
package org.mage.test.cards.abilities.other;
|
||||||
package org.mage.test.cards.abilities.other;
|
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.Zone;
|
||||||
import mage.constants.Zone;
|
import org.junit.Test;
|
||||||
import org.junit.Test;
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
|
||||||
|
/**
|
||||||
/**
|
*
|
||||||
*
|
* @author LevelX2
|
||||||
* @author LevelX2
|
*/
|
||||||
*/
|
public class LimitedCountedActivationsTest extends CardTestPlayerBase {
|
||||||
public class LimitedCountedActivationsTest extends CardTestPlayerBase {
|
|
||||||
|
/**
|
||||||
/**
|
* Tests usage of ActivationInfo class
|
||||||
* Tests usage of ActivationInfo class
|
*/
|
||||||
*/
|
@Test
|
||||||
@Test
|
public void testDragonWhelpActivatedThreeTimes() {
|
||||||
public void testDragonWhelpActivatedThreeTimes() {
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
|
// Flying
|
||||||
// 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.
|
||||||
// {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
|
||||||
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}: ");
|
||||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: ");
|
|
||||||
|
attack(1, playerA, "Dragon Whelp");
|
||||||
attack(1, playerA, "Dragon Whelp");
|
|
||||||
|
setStopAt(2, PhaseStep.UPKEEP);
|
||||||
setStopAt(2, PhaseStep.UPKEEP);
|
execute();
|
||||||
execute();
|
|
||||||
|
assertPermanentCount(playerA, "Dragon Whelp", 1);
|
||||||
assertPermanentCount(playerA, "Dragon Whelp", 1);
|
|
||||||
|
assertLife(playerA, 20);
|
||||||
assertLife(playerA, 20);
|
assertLife(playerB, 15);
|
||||||
assertLife(playerB, 15);
|
}
|
||||||
}
|
|
||||||
|
@Test
|
||||||
@Test
|
public void testDragonWhelpActivatedFourTimes() {
|
||||||
public void testDragonWhelpActivatedFourTimes() {
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
// Flying
|
||||||
// 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.
|
||||||
// {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
|
||||||
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}: ");
|
||||||
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");
|
||||||
attack(1, playerA, "Dragon Whelp");
|
|
||||||
|
setStopAt(2, PhaseStep.UPKEEP);
|
||||||
setStopAt(2, PhaseStep.UPKEEP);
|
execute();
|
||||||
execute();
|
|
||||||
|
assertPermanentCount(playerA, "Dragon Whelp", 0);
|
||||||
assertPermanentCount(playerA, "Dragon Whelp", 0);
|
assertGraveyardCount(playerA, "Dragon Whelp", 1);
|
||||||
assertGraveyardCount(playerA, "Dragon Whelp", 1);
|
|
||||||
|
assertLife(playerA, 20);
|
||||||
assertLife(playerA, 20);
|
assertLife(playerB, 14);
|
||||||
assertLife(playerB, 14);
|
}
|
||||||
}
|
|
||||||
|
@Test
|
||||||
@Test
|
public void testDragonWhelpActivatedFiveTimes() {
|
||||||
public void testDragonWhelpActivatedFiveTimes() {
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5);
|
// Flying
|
||||||
// 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.
|
||||||
// {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
|
||||||
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}: ");
|
||||||
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");
|
||||||
attack(1, playerA, "Dragon Whelp");
|
|
||||||
|
setStopAt(2, PhaseStep.UPKEEP);
|
||||||
setStopAt(2, PhaseStep.UPKEEP);
|
execute();
|
||||||
execute();
|
|
||||||
|
assertPermanentCount(playerA, "Dragon Whelp", 0);
|
||||||
assertPermanentCount(playerA, "Dragon Whelp", 0);
|
assertGraveyardCount(playerA, "Dragon Whelp", 1);
|
||||||
assertGraveyardCount(playerA, "Dragon Whelp", 1);
|
|
||||||
|
assertLife(playerA, 20);
|
||||||
assertLife(playerA, 20);
|
assertLife(playerB, 13);
|
||||||
assertLife(playerB, 13);
|
}
|
||||||
}
|
|
||||||
|
@Test
|
||||||
@Test
|
public void testDragonWhelpTwoObjects() {
|
||||||
public void testDragonWhelpTwoObjects() {
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5);
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
// Flying
|
||||||
// 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.
|
||||||
// {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
|
||||||
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.
|
||||||
// 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);
|
||||||
addCard(Zone.HAND, playerA, "Reanimate", 1);
|
// Target creature gains haste until end of turn.
|
||||||
// Target creature gains haste until end of turn.
|
addCard(Zone.HAND, playerA, "Unnatural Speed", 1);
|
||||||
addCard(Zone.HAND, playerA, "Unnatural Speed", 1);
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2);
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2);
|
// Destroy target nonartifact, nonblack creature. It can't be regenerated.
|
||||||
// Destroy target nonartifact, nonblack creature. It can't be regenerated.
|
addCard(Zone.HAND, playerB, "Terror", 1); // {1}{B}
|
||||||
addCard(Zone.HAND, playerB, "Terror", 1); // {1}{B}
|
|
||||||
|
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, playerB, "Terror", "Dragon Whelp");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate", "Dragon Whelp");
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate", "Dragon Whelp");
|
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Unnatural Speed", "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}: ");
|
||||||
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");
|
||||||
attack(1, playerA, "Dragon Whelp");
|
|
||||||
|
setStopAt(2, PhaseStep.UPKEEP);
|
||||||
setStopAt(2, PhaseStep.UPKEEP);
|
execute();
|
||||||
execute();
|
|
||||||
|
assertGraveyardCount(playerA, "Unnatural Speed", 1);
|
||||||
assertGraveyardCount(playerA, "Unnatural Speed", 1);
|
assertGraveyardCount(playerA, "Reanimate", 1);
|
||||||
assertGraveyardCount(playerA, "Reanimate", 1);
|
|
||||||
|
assertGraveyardCount(playerB, "Terror", 1);
|
||||||
assertGraveyardCount(playerB, "Terror", 1);
|
|
||||||
|
assertPermanentCount(playerA, "Dragon Whelp", 1);
|
||||||
assertPermanentCount(playerA, "Dragon Whelp", 1);
|
assertPowerToughness(playerA, "Dragon Whelp", 2, 3);
|
||||||
assertPowerToughness(playerA, "Dragon Whelp", 2, 3);
|
assertGraveyardCount(playerA, "Dragon Whelp", 0);
|
||||||
assertGraveyardCount(playerA, "Dragon Whelp", 0);
|
|
||||||
|
assertLife(playerA, 16);
|
||||||
assertLife(playerA, 16);
|
assertLife(playerB, 15);
|
||||||
assertLife(playerB, 15);
|
}
|
||||||
}
|
|
||||||
|
@Test
|
||||||
@Test
|
public void testDragonWhelpDontSacrificeNewObject() {
|
||||||
public void testDragonWhelpDontSacrificeNewObject() {
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8);
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
// Flying
|
||||||
// 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.
|
||||||
// {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
|
||||||
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.
|
||||||
// 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);
|
||||||
addCard(Zone.HAND, playerA, "Reanimate", 1);
|
// Target creature gains haste until end of turn.
|
||||||
// Target creature gains haste until end of turn.
|
addCard(Zone.HAND, playerA, "Unnatural Speed", 1);
|
||||||
addCard(Zone.HAND, playerA, "Unnatural Speed", 1);
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2);
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2);
|
// Destroy target nonartifact, nonblack creature. It can't be regenerated.
|
||||||
// Destroy target nonartifact, nonblack creature. It can't be regenerated.
|
addCard(Zone.HAND, playerB, "Terror", 1); // {1}{B}
|
||||||
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}: ");
|
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, playerB, "Terror", "Dragon Whelp");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate", "Dragon Whelp");
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate", "Dragon Whelp");
|
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Unnatural Speed", "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}: ");
|
||||||
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");
|
||||||
attack(1, playerA, "Dragon Whelp");
|
|
||||||
|
setStopAt(2, PhaseStep.UPKEEP);
|
||||||
setStopAt(2, PhaseStep.UPKEEP);
|
execute();
|
||||||
execute();
|
|
||||||
|
assertGraveyardCount(playerA, "Unnatural Speed", 1);
|
||||||
assertGraveyardCount(playerA, "Unnatural Speed", 1);
|
assertGraveyardCount(playerA, "Reanimate", 1);
|
||||||
assertGraveyardCount(playerA, "Reanimate", 1);
|
|
||||||
|
assertGraveyardCount(playerB, "Terror", 1);
|
||||||
assertGraveyardCount(playerB, "Terror", 1);
|
|
||||||
|
assertLife(playerA, 16);
|
||||||
assertPermanentCount(playerA, "Dragon Whelp", 1);
|
assertLife(playerB, 15);
|
||||||
assertPowerToughness(playerA, "Dragon Whelp", 2, 3);
|
|
||||||
assertGraveyardCount(playerA, "Dragon Whelp", 0);
|
assertGraveyardCount(playerA, "Dragon Whelp", 0);
|
||||||
|
|
||||||
assertLife(playerA, 16);
|
assertPermanentCount(playerA, "Dragon Whelp", 1);
|
||||||
assertLife(playerB, 15);
|
assertPowerToughness(playerA, "Dragon Whelp", 2, 3);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -52,6 +52,7 @@ public class BlatantThieveryTest extends CardTestMultiPlayerBase {
|
||||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
|
assertGraveyardCount(playerA, "Blatant Thievery", 1);
|
||||||
assertPermanentCount(playerA, "Silvercoat Lion", 1);
|
assertPermanentCount(playerA, "Silvercoat Lion", 1);
|
||||||
assertPermanentCount(playerA, "Walking Corpse", 1);
|
assertPermanentCount(playerA, "Walking Corpse", 1);
|
||||||
assertPermanentCount(playerA, "Pillarfield Ox", 1);
|
assertPermanentCount(playerA, "Pillarfield Ox", 1);
|
||||||
|
|
|
||||||
|
|
@ -479,16 +479,7 @@ public interface Ability extends Controllable, Serializable {
|
||||||
boolean activateAlternateOrAdditionalCosts(MageObject sourceObject, boolean noMana, Player controller, Game game);
|
boolean activateAlternateOrAdditionalCosts(MageObject sourceObject, boolean noMana, Player controller, Game game);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets 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.
|
|
||||||
*
|
|
||||||
* @param mageObject
|
|
||||||
* @param game
|
|
||||||
*/
|
|
||||||
void setSourceObject(MageObject mageObject, Game game);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the object that actually existed while a ability triggerd or an
|
|
||||||
* ability was activated. If not set yet, the current object will be
|
* ability was activated. If not set yet, the current object will be
|
||||||
* retrieved from the game.
|
* retrieved from the game.
|
||||||
*
|
*
|
||||||
|
|
@ -497,6 +488,8 @@ public interface Ability extends Controllable, Serializable {
|
||||||
*/
|
*/
|
||||||
MageObject getSourceObject(Game game);
|
MageObject getSourceObject(Game game);
|
||||||
|
|
||||||
|
void setSourceObjectZoneChangeCounter(int zoneChangeCounter);
|
||||||
|
|
||||||
int getSourceObjectZoneChangeCounter();
|
int getSourceObjectZoneChangeCounter();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -520,6 +513,8 @@ public interface Ability extends Controllable, Serializable {
|
||||||
*/
|
*/
|
||||||
Permanent getSourcePermanentIfItStillExists(Game game);
|
Permanent getSourcePermanentIfItStillExists(Game game);
|
||||||
|
|
||||||
|
Permanent getSourcePermanentOrLKI(Game game);
|
||||||
|
|
||||||
String getTargetDescription(Targets targets, Game game);
|
String getTargetDescription(Targets targets, Game game);
|
||||||
|
|
||||||
void setCanFizzle(boolean canFizzle);
|
void setCanFizzle(boolean canFizzle);
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.MageObjectReference;
|
|
||||||
import mage.Mana;
|
import mage.Mana;
|
||||||
import mage.abilities.costs.*;
|
import mage.abilities.costs.*;
|
||||||
import mage.abilities.costs.common.PayLifeCost;
|
import mage.abilities.costs.common.PayLifeCost;
|
||||||
|
|
@ -67,7 +66,6 @@ public abstract class AbilityImpl implements Ability {
|
||||||
protected boolean costModificationActive = true;
|
protected boolean costModificationActive = true;
|
||||||
protected boolean activated = false;
|
protected boolean activated = false;
|
||||||
protected boolean worksFaceDown = false;
|
protected boolean worksFaceDown = false;
|
||||||
protected MageObject sourceObject;
|
|
||||||
protected int sourceObjectZoneChangeCounter;
|
protected int sourceObjectZoneChangeCounter;
|
||||||
protected List<Watcher> watchers = new ArrayList<>();
|
protected List<Watcher> watchers = new ArrayList<>();
|
||||||
protected List<Ability> subAbilities = null;
|
protected List<Ability> subAbilities = null;
|
||||||
|
|
@ -116,7 +114,6 @@ public abstract class AbilityImpl implements Ability {
|
||||||
this.costModificationActive = ability.costModificationActive;
|
this.costModificationActive = ability.costModificationActive;
|
||||||
this.worksFaceDown = ability.worksFaceDown;
|
this.worksFaceDown = ability.worksFaceDown;
|
||||||
this.abilityWord = ability.abilityWord;
|
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.sourceObjectZoneChangeCounter = ability.sourceObjectZoneChangeCounter;
|
||||||
this.canFizzle = ability.canFizzle;
|
this.canFizzle = ability.canFizzle;
|
||||||
this.targetAdjuster = ability.targetAdjuster;
|
this.targetAdjuster = ability.targetAdjuster;
|
||||||
|
|
@ -131,8 +128,6 @@ public abstract class AbilityImpl implements Ability {
|
||||||
public void newId() {
|
public void newId() {
|
||||||
if (!(this instanceof MageSingleton)) {
|
if (!(this instanceof MageSingleton)) {
|
||||||
this.id = UUID.randomUUID();
|
this.id = UUID.randomUUID();
|
||||||
// this.sourceObject = null;
|
|
||||||
// this.sourceObjectZoneChangeCounter = -1;
|
|
||||||
}
|
}
|
||||||
getEffects().newId();
|
getEffects().newId();
|
||||||
}
|
}
|
||||||
|
|
@ -226,8 +221,10 @@ public abstract class AbilityImpl implements Ability {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
getSourceObject(game);
|
MageObject sourceObject = getSourceObject(game);
|
||||||
|
if (getSourceObjectZoneChangeCounter() == 0) {
|
||||||
|
setSourceObjectZoneChangeCounter(game.getState().getZoneChangeCounter(getSourceId()));
|
||||||
|
}
|
||||||
if (controller.isTestMode()) {
|
if (controller.isTestMode()) {
|
||||||
if (!controller.addTargets(this, game)) {
|
if (!controller.addTargets(this, game)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -1160,58 +1157,44 @@ public abstract class AbilityImpl implements Ability {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MageObject getSourceObject(Game game) {
|
public MageObject getSourceObject(Game game) {
|
||||||
if (sourceObject == null) {
|
return game.getObject(getSourceId());
|
||||||
setSourceObject(null, game);
|
|
||||||
if (sourceObject == null) {
|
|
||||||
logger.warn("Source object could not be retrieved: " + this.getRule());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sourceObject;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MageObject getSourceObjectIfItStillExists(Game game) {
|
public MageObject getSourceObjectIfItStillExists(Game game) {
|
||||||
MageObject currentObject = game.getObject(getSourceId());
|
if (getSourceObjectZoneChangeCounter() == 0
|
||||||
if (currentObject != null) {
|
|| getSourceObjectZoneChangeCounter() == game.getState().getZoneChangeCounter(getSourceId())) {
|
||||||
if (sourceObject == null) {
|
return game.getObject(getSourceId());
|
||||||
setSourceObject(currentObject, game);
|
|
||||||
}
|
|
||||||
MageObjectReference mor = new MageObjectReference(currentObject, game);
|
|
||||||
if (mor.getZoneChangeCounter() == getSourceObjectZoneChangeCounter()) {
|
|
||||||
// source object has meanwhile not changed zone
|
|
||||||
return currentObject;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Permanent getSourcePermanentIfItStillExists(Game game) {
|
public Permanent getSourcePermanentIfItStillExists(Game game) {
|
||||||
if (sourceObject == null || !sourceObject.getId().equals(getSourceId())) {
|
MageObject mageObject = getSourceObjectIfItStillExists(game);
|
||||||
setSourceObject(game.getObject(getSourceId()), game);
|
if (mageObject instanceof Permanent) {
|
||||||
}
|
return (Permanent) mageObject;
|
||||||
if (sourceObject instanceof Permanent) {
|
|
||||||
if (game.getState().getZoneChangeCounter(getSourceId()) == getSourceObjectZoneChangeCounter()) {
|
|
||||||
return (Permanent) sourceObject;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSourceObjectZoneChangeCounter() {
|
public Permanent getSourcePermanentOrLKI(Game game) {
|
||||||
return sourceObjectZoneChangeCounter;
|
if (getSourceObjectZoneChangeCounter() == 0
|
||||||
|
|| getSourceObjectZoneChangeCounter() == game.getState().getZoneChangeCounter(getSourceId())) {
|
||||||
|
return game.getPermanent(getSourceId());
|
||||||
|
}
|
||||||
|
return (Permanent) game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD, getSourceObjectZoneChangeCounter());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSourceObject(MageObject sourceObject, Game game) {
|
public void setSourceObjectZoneChangeCounter(int sourceObjectZoneChangeCounter) {
|
||||||
if (sourceObject == null) {
|
this.sourceObjectZoneChangeCounter = sourceObjectZoneChangeCounter;
|
||||||
this.sourceObject = game.getObject(sourceId);
|
}
|
||||||
this.sourceObjectZoneChangeCounter = game.getState().getZoneChangeCounter(sourceId);
|
|
||||||
} else {
|
@Override
|
||||||
this.sourceObject = sourceObject;
|
public int getSourceObjectZoneChangeCounter() {
|
||||||
this.sourceObjectZoneChangeCounter = this.sourceObject.getZoneChangeCounter(game);
|
return sourceObjectZoneChangeCounter;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
package mage.abilities;
|
package mage.abilities;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
@ -45,9 +44,6 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
||||||
@Override
|
@Override
|
||||||
public void trigger(Game game, UUID controllerId) {
|
public void trigger(Game game, UUID controllerId) {
|
||||||
//20091005 - 603.4
|
//20091005 - 603.4
|
||||||
if (!(this instanceof DelayedTriggeredAbility)) {
|
|
||||||
setSourceObject(null, game);
|
|
||||||
}
|
|
||||||
if (checkInterveningIfClause(game)) {
|
if (checkInterveningIfClause(game)) {
|
||||||
game.addTriggeredAbility(this);
|
game.addTriggeredAbility(this);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
package mage.abilities.common.delayed;
|
package mage.abilities.common.delayed;
|
||||||
|
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
|
|
||||||
package mage.abilities.effects.common;
|
package mage.abilities.effects.common;
|
||||||
|
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.game.stack.Spell;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|
@ -34,11 +33,9 @@ public class SacrificeSourceEffect extends OneShotEffect {
|
||||||
MageObject sourceObject = source.getSourceObjectIfItStillExists(game);
|
MageObject sourceObject = source.getSourceObjectIfItStillExists(game);
|
||||||
if (sourceObject == null) {
|
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
|
// 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());
|
sourceObject = game.getPermanent(source.getSourceId());
|
||||||
if (sourceObject != null && sourceObject.getZoneChangeCounter(game) > source.getSourceObjectZoneChangeCounter() + 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sourceObject instanceof Permanent) {
|
if (sourceObject instanceof Permanent) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package mage.abilities.meta;
|
package mage.abilities.meta;
|
||||||
|
|
||||||
import mage.MageObject;
|
|
||||||
import mage.abilities.TriggeredAbility;
|
import mage.abilities.TriggeredAbility;
|
||||||
import mage.abilities.TriggeredAbilityImpl;
|
import mage.abilities.TriggeredAbilityImpl;
|
||||||
import mage.abilities.effects.Effect;
|
import mage.abilities.effects.Effect;
|
||||||
|
|
@ -14,9 +13,12 @@ import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A triggered ability that combines several others and triggers whenever one or more of them would. The abilities
|
* A triggered ability that combines several others and triggers whenever one or
|
||||||
* passed in should have null as their effect, and should have their own targets set if necessary. All other information
|
* more of them would. The abilities passed in should have null as their effect,
|
||||||
* will be passed in from changes to this Ability. Note: this does NOT work with abilities that have intervening if clauses.
|
* 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
|
* @author noahg
|
||||||
*/
|
*/
|
||||||
public class OrTriggeredAbility extends TriggeredAbilityImpl {
|
public class OrTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
@ -43,18 +45,17 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
public OrTriggeredAbility(OrTriggeredAbility ability) {
|
public OrTriggeredAbility(OrTriggeredAbility ability) {
|
||||||
super(ability);
|
super(ability);
|
||||||
this.triggeredAbilities = new TriggeredAbility[ability.triggeredAbilities.length];
|
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.triggeredAbilities[i] = ability.triggeredAbilities[i].copy();
|
||||||
}
|
}
|
||||||
this.triggeringAbilities = new ArrayList<>(ability.triggeringAbilities);
|
this.triggeringAbilities = new ArrayList<>(ability.triggeringAbilities);
|
||||||
this.ruleTrigger = ability.ruleTrigger;
|
this.ruleTrigger = ability.ruleTrigger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkEventType(GameEvent event, Game game) {
|
public boolean checkEventType(GameEvent event, Game game) {
|
||||||
for (TriggeredAbility ability : triggeredAbilities) {
|
for (TriggeredAbility ability : triggeredAbilities) {
|
||||||
if (ability.checkEventType(event, game)){
|
if (ability.checkEventType(event, game)) {
|
||||||
System.out.println("Correct event type (" + event.getType() + ")");
|
System.out.println("Correct event type (" + event.getType() + ")");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -101,7 +102,6 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
return sb.toString() + super.getRule();
|
return sb.toString() + super.getRule();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setControllerId(UUID controllerId) {
|
public void setControllerId(UUID controllerId) {
|
||||||
super.setControllerId(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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1527,7 +1527,7 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
@Override
|
@Override
|
||||||
public void addEffect(ContinuousEffect continuousEffect, Ability source) {
|
public void addEffect(ContinuousEffect continuousEffect, Ability source) {
|
||||||
Ability newAbility = source.copy();
|
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();
|
ContinuousEffect newEffect = continuousEffect.copy();
|
||||||
|
|
||||||
newEffect.newId();
|
newEffect.newId();
|
||||||
|
|
@ -1698,11 +1698,17 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
if (ability instanceof TriggeredManaAbility || ability instanceof DelayedTriggeredManaAbility) {
|
if (ability instanceof TriggeredManaAbility || ability instanceof DelayedTriggeredManaAbility) {
|
||||||
// 20110715 - 605.4
|
// 20110715 - 605.4
|
||||||
Ability manaAbiltiy = ability.copy();
|
Ability manaAbiltiy = ability.copy();
|
||||||
|
if (manaAbiltiy.getSourceObjectZoneChangeCounter() == 0) {
|
||||||
|
manaAbiltiy.setSourceObjectZoneChangeCounter(getState().getZoneChangeCounter(ability.getSourceId()));
|
||||||
|
}
|
||||||
manaAbiltiy.activate(this, false);
|
manaAbiltiy.activate(this, false);
|
||||||
manaAbiltiy.resolve(this);
|
manaAbiltiy.resolve(this);
|
||||||
} else {
|
} else {
|
||||||
TriggeredAbility newAbility = ability.copy();
|
TriggeredAbility newAbility = ability.copy();
|
||||||
newAbility.newId();
|
newAbility.newId();
|
||||||
|
if (newAbility.getSourceObjectZoneChangeCounter() == 0) {
|
||||||
|
newAbility.setSourceObjectZoneChangeCounter(getState().getZoneChangeCounter(ability.getSourceId()));
|
||||||
|
}
|
||||||
state.addTriggeredAbility(newAbility);
|
state.addTriggeredAbility(newAbility);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1711,10 +1717,10 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
public UUID addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility, Ability source) {
|
public UUID addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility, Ability source) {
|
||||||
delayedAbility.setSourceId(source.getSourceId());
|
delayedAbility.setSourceId(source.getSourceId());
|
||||||
delayedAbility.setControllerId(source.getControllerId());
|
delayedAbility.setControllerId(source.getControllerId());
|
||||||
delayedAbility.setSourceObject(source.getSourceObject(this), this);
|
|
||||||
// return addDelayedTriggeredAbility(delayedAbility);
|
// return addDelayedTriggeredAbility(delayedAbility);
|
||||||
DelayedTriggeredAbility newAbility = delayedAbility.copy();
|
DelayedTriggeredAbility newAbility = delayedAbility.copy();
|
||||||
newAbility.newId();
|
newAbility.newId();
|
||||||
|
newAbility.setSourceObjectZoneChangeCounter(getState().getZoneChangeCounter(source.getSourceId()));
|
||||||
newAbility.initOnAdding(this);
|
newAbility.initOnAdding(this);
|
||||||
// ability.init is called as the ability triggeres not now.
|
// 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
|
// If a FixedTarget pointer is already set from the effect setting up this delayed ability
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
package mage.game.command;
|
package mage.game.command;
|
||||||
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
|
|
||||||
package mage.game.command;
|
package mage.game.command;
|
||||||
|
|
||||||
import static java.lang.Math.log;
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -289,7 +287,7 @@ public class Plane implements CommandObject {
|
||||||
if (plane instanceof Plane) {
|
if (plane instanceof Plane) {
|
||||||
return (Plane) plane;
|
return (Plane) plane;
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -518,14 +518,19 @@ public class StackAbility extends StackObjImpl implements Ability {
|
||||||
return this.ability.getSourcePermanentIfItStillExists(game);
|
return this.ability.getSourcePermanentIfItStillExists(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSourceObjectZoneChangeCounter(int zoneChangeCounter) {
|
||||||
|
ability.setSourceObjectZoneChangeCounter(zoneChangeCounter);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSourceObjectZoneChangeCounter() {
|
public int getSourceObjectZoneChangeCounter() {
|
||||||
return ability.getSourceObjectZoneChangeCounter();
|
return ability.getSourceObjectZoneChangeCounter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSourceObject(MageObject sourceObject, Game game) {
|
public Permanent getSourcePermanentOrLKI(Game game) {
|
||||||
throw new UnsupportedOperationException("Not supported.");
|
return ability.getSourcePermanentOrLKI(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -1041,15 +1041,15 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean cast(SpellAbility ability, Game game, boolean noMana, MageObjectReference permittingObject) {
|
public boolean cast(SpellAbility originalAbility, Game game, boolean noMana, MageObjectReference permittingObject) {
|
||||||
if (game == null || ability == null) {
|
if (game == null || originalAbility == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use ability copy to avoid problems with targets and costs on recast (issue https://github.com/magefree/mage/issues/5189).
|
// 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.setControllerId(getId());
|
||||||
|
ability.setSourceObjectZoneChangeCounter(game.getState().getZoneChangeCounter(ability.getSourceId()));
|
||||||
if (ability.getSpellAbilityType() != SpellAbilityType.BASE) {
|
if (ability.getSpellAbilityType() != SpellAbilityType.BASE) {
|
||||||
ability = chooseSpellAbilityForCast(ability, game, noMana);
|
ability = chooseSpellAbilityForCast(ability, game, noMana);
|
||||||
if (ability == null) {
|
if (ability == null) {
|
||||||
|
|
@ -1073,6 +1073,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
logger.error("Got no spell from stack. ability: " + ability.getRule());
|
logger.error("Got no spell from stack. ability: " + ability.getRule());
|
||||||
return false;
|
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
|
// some effects set sourceId to cast without paying mana costs or other costs
|
||||||
if (ability.getSourceId().equals(getCastSourceIdWithAlternateMana())) {
|
if (ability.getSourceId().equals(getCastSourceIdWithAlternateMana())) {
|
||||||
Ability spellAbility = spell.getSpellAbility();
|
Ability spellAbility = spell.getSpellAbility();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue