Reworked ability source object handling.

This commit is contained in:
LevelX2 2018-10-21 21:37:23 +02:00
parent e6b78d7a2e
commit 26a93d4427
19 changed files with 292 additions and 288 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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<Watcher> watchers = new ArrayList<>();
protected List<Ability> 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

View file

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

View file

@ -1,4 +1,3 @@
package mage.abilities.common.delayed;
import java.util.LinkedHashSet;

View file

@ -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) {

View file

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

View file

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

View file

@ -1,4 +1,3 @@
package mage.game.command;
import java.util.EnumSet;

View file

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

View file

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

View file

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