mirror of
https://github.com/correl/mage.git
synced 2024-11-14 19:19:32 +00:00
* Fix of some problems of zone change related triggered abilities that had not been correctly implemented (fixes #6586).
This commit is contained in:
parent
40c01a04c4
commit
32ce1d85e9
5 changed files with 102 additions and 94 deletions
|
@ -1,7 +1,6 @@
|
|||
package mage.cards.a;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.dynamicvalue.common.DevotionCount;
|
||||
import mage.abilities.effects.common.CreateTokenEffect;
|
||||
|
@ -12,17 +11,27 @@ import mage.constants.*;
|
|||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
import mage.game.permanent.token.SatyrCantBlockToken;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.common.DiesThisOrAnotherCreatureTriggeredAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.permanent.TokenPredicate;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class AnaxHardenedInTheForge extends CardImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature you control");
|
||||
|
||||
static {
|
||||
filter.add(TargetController.YOU.getControllerPredicate());
|
||||
filter.add(Predicates.not(TokenPredicate.instance));
|
||||
}
|
||||
|
||||
public AnaxHardenedInTheForge(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{1}{R}{R}");
|
||||
|
||||
|
@ -38,8 +47,9 @@ public final class AnaxHardenedInTheForge extends CardImpl {
|
|||
.setText("{this}'s power is equal to your devotion to red")
|
||||
).addHint(DevotionCount.R.getHint()));
|
||||
|
||||
// Whenever Anax or another nontoken creature you control dies, create a 1/1 red Satyr creature token with "This creature can't block." If the creature had power 4 or greater, create two of those tokens instead.
|
||||
this.addAbility(new AnaxHardenedInTheForgeTriggeredAbility());
|
||||
// Whenever Anax or another nontoken creature you control dies, create a 1/1 red Satyr creature token
|
||||
// with "This creature can't block." If the creature had power 4 or greater, create two of those tokens instead.
|
||||
this.addAbility(new AnaxHardenedInTheForgeTriggeredAbility(null, false, filter));
|
||||
}
|
||||
|
||||
private AnaxHardenedInTheForge(final AnaxHardenedInTheForge card) {
|
||||
|
@ -52,10 +62,10 @@ public final class AnaxHardenedInTheForge extends CardImpl {
|
|||
}
|
||||
}
|
||||
|
||||
class AnaxHardenedInTheForgeTriggeredAbility extends TriggeredAbilityImpl {
|
||||
class AnaxHardenedInTheForgeTriggeredAbility extends DiesThisOrAnotherCreatureTriggeredAbility {
|
||||
|
||||
AnaxHardenedInTheForgeTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, null, false);
|
||||
AnaxHardenedInTheForgeTriggeredAbility(Effect effect, boolean optional, FilterCreaturePermanent filter) {
|
||||
super(effect, optional, filter);
|
||||
}
|
||||
|
||||
private AnaxHardenedInTheForgeTriggeredAbility(final AnaxHardenedInTheForgeTriggeredAbility ability) {
|
||||
|
@ -67,33 +77,21 @@ class AnaxHardenedInTheForgeTriggeredAbility extends TriggeredAbilityImpl {
|
|||
return new AnaxHardenedInTheForgeTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
if (!zEvent.isDiesEvent()) {
|
||||
return false;
|
||||
if (super.checkTrigger(event, game)) {
|
||||
int tokenCount = ((ZoneChangeEvent) event).getTarget().getPower().getValue() > 3 ? 2 : 1;
|
||||
this.getEffects().clear();
|
||||
this.addEffect(new CreateTokenEffect(new SatyrCantBlockToken(), tokenCount));
|
||||
return true;
|
||||
}
|
||||
if (!zEvent.getTarget().getId().equals(getSourceId())
|
||||
&& (zEvent.getTarget() instanceof PermanentToken
|
||||
|| !zEvent.getTarget().isCreature()
|
||||
|| !Objects.equals(zEvent.getTarget().getControllerId(), getControllerId()))) {
|
||||
return false;
|
||||
}
|
||||
int tokenCount = zEvent.getTarget().getPower().getValue() > 3 ? 2 : 1;
|
||||
this.getEffects().clear();
|
||||
this.addEffect(new CreateTokenEffect(new SatyrCantBlockToken(), tokenCount));
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever {this} or another nontoken creature you control dies, " +
|
||||
"create a 1/1 red Satyr creature token with \"This creature can't block.\" " +
|
||||
"If the creature had power 4 or greater, create two of those tokens instead.";
|
||||
return "Whenever {this} or another nontoken creature you control dies, "
|
||||
+ "create a 1/1 red Satyr creature token with \"This creature can't block.\" "
|
||||
+ "If the creature had power 4 or greater, create two of those tokens instead.";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,17 @@
|
|||
|
||||
package mage.cards.p;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.common.DiesThisOrAnotherCreatureTriggeredAbility;
|
||||
import mage.abilities.effects.common.CreateTokenEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.permanent.TokenPredicate;
|
||||
import mage.game.permanent.token.EldraziSpawnToken;
|
||||
|
||||
/**
|
||||
|
@ -24,16 +19,25 @@ import mage.game.permanent.token.EldraziSpawnToken;
|
|||
* @author North
|
||||
*/
|
||||
public final class PawnOfUlamog extends CardImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature you control");
|
||||
|
||||
static {
|
||||
filter.add(TargetController.YOU.getControllerPredicate());
|
||||
filter.add(Predicates.not(TokenPredicate.instance));
|
||||
}
|
||||
|
||||
public PawnOfUlamog(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}");
|
||||
this.subtype.add(SubType.VAMPIRE);
|
||||
this.subtype.add(SubType.SHAMAN);
|
||||
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(2);
|
||||
|
||||
this.addAbility(new PawnOfUlamogTriggeredAbility());
|
||||
// Whenever Pawn of Ulamog or another nontoken creature you control dies, you may create a 0/1 colorless
|
||||
// Eldrazi Spawn creature token. It has "Sacrifice this creature: Add {C}."
|
||||
this.addAbility(new DiesThisOrAnotherCreatureTriggeredAbility(new CreateTokenEffect(new EldraziSpawnToken()), true, filter));
|
||||
}
|
||||
|
||||
public PawnOfUlamog(final PawnOfUlamog card) {
|
||||
|
@ -44,49 +48,4 @@ public final class PawnOfUlamog extends CardImpl {
|
|||
public PawnOfUlamog copy() {
|
||||
return new PawnOfUlamog(this);
|
||||
}
|
||||
}
|
||||
|
||||
class PawnOfUlamogTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public PawnOfUlamogTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new CreateTokenEffect(new EldraziSpawnToken()), true);
|
||||
}
|
||||
|
||||
public PawnOfUlamogTriggeredAbility(PawnOfUlamogTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PawnOfUlamogTriggeredAbility copy() {
|
||||
return new PawnOfUlamogTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == EventType.ZONE_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
UUID targetId = event.getTargetId();
|
||||
MageObject card = game.getLastKnownInformation(targetId, Zone.BATTLEFIELD);
|
||||
if (card instanceof Permanent && !(card instanceof PermanentToken)) {
|
||||
Permanent permanent = (Permanent) card;
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
if (zEvent.isDiesEvent()
|
||||
&& permanent.isControlledBy(this.controllerId)
|
||||
&& (targetId.equals(this.getSourceId())
|
||||
|| (permanent.isCreature()
|
||||
&& !targetId.equals(this.getSourceId())
|
||||
&& !(permanent instanceof PermanentToken)))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever Pawn of Ulamog or another nontoken creature you control dies, you may create a 0/1 colorless Eldrazi Spawn creature token. It has \"Sacrifice this creature: Add {C}.\"";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,10 +9,17 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
|
|||
* Created by alexsandro on 06/03/17.
|
||||
*/
|
||||
public class SakashimaTheImpostorTest extends CardTestPlayerBase {
|
||||
|
||||
@Test
|
||||
public void copySpellStutterTest() {
|
||||
// Flash, Flying
|
||||
// When Spellstutter Sprite enters the battlefield, counter target spell with converted mana cost X or less,
|
||||
// where X is the number of Faeries you control.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Spellstutter Sprite", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Island", 4);
|
||||
// You may have Sakashima the Impostor enter the battlefield as a copy of any creature on the battlefield,
|
||||
// except its name is Sakashima the Impostor, it's legendary in addition to its other types,
|
||||
// and it has "{2}{U}{U}: Return Sakashima the Impostor to its owner's hand at the beginning of the next end step."
|
||||
addCard(Zone.HAND, playerB, "Sakashima the Impostor", 4);
|
||||
|
||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Sakashima the Impostor");
|
||||
|
@ -25,4 +32,42 @@ public class SakashimaTheImpostorTest extends CardTestPlayerBase {
|
|||
|
||||
assertPowerToughness(playerB, "Sakashima the Impostor", 1, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* I played Sakashima the Imposter copying an opponents Pawn of Ulamaog.
|
||||
* Sakashima gained the following ability: "Whenever Pawn of Ulamog or
|
||||
* another nontoken creature you control dies, you may create a 0/1
|
||||
* colorless Eldrazi Spawn creature token. It has "Sacrifice this creature:
|
||||
* Add {C}." Then Sakashima died due to combat damage and the ability did
|
||||
* not trigger.
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void copyDiesTriggeredTest() {
|
||||
// Whenever Pawn of Ulamog or another nontoken creature you control dies, you may create a 0/1 colorless
|
||||
// Eldrazi Spawn creature token. It has "Sacrifice this creature: Add {C}."
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Pawn of Ulamog", 1); // Creature 2/2
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); // Creature 2/2
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Island", 4);
|
||||
// You may have Sakashima the Impostor enter the battlefield as a copy of any creature on the battlefield,
|
||||
// except its name is Sakashima the Impostor, it's legendary in addition to its other types,
|
||||
// and it has "{2}{U}{U}: Return Sakashima the Impostor to its owner's hand at the beginning of the next end step."
|
||||
addCard(Zone.HAND, playerB, "Sakashima the Impostor", 4);
|
||||
|
||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Sakashima the Impostor");
|
||||
setChoice(playerB, "Pawn of Ulamog");
|
||||
|
||||
attack(4, playerB, "Sakashima the Impostor");
|
||||
block(4, playerA, "Silvercoat Lion", "Sakashima the Impostor");
|
||||
|
||||
setStopAt(4, PhaseStep.POSTCOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, "Silvercoat Lion", 1);
|
||||
assertGraveyardCount(playerB, "Sakashima the Impostor", 1);
|
||||
|
||||
assertPermanentCount(playerA, "Eldrazi Spawn", 1);
|
||||
assertPermanentCount(playerB, "Eldrazi Spawn", 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -171,21 +171,24 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
}
|
||||
}
|
||||
}
|
||||
if (isLeavesTheBattlefieldTrigger()) {
|
||||
source = zce.getTarget();
|
||||
}
|
||||
break;
|
||||
case DESTROYED_PERMANENT:
|
||||
if (isLeavesTheBattlefieldTrigger()) {
|
||||
if (event.getType() == EventType.DESTROYED_PERMANENT) {
|
||||
source = game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD);
|
||||
} else if (((ZoneChangeEvent) event).getTarget() != null) {
|
||||
source = ((ZoneChangeEvent) event).getTarget();
|
||||
} else {
|
||||
source = game.getLastKnownInformation(getSourceId(), event.getZone());
|
||||
}
|
||||
source = game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD);
|
||||
}
|
||||
break;
|
||||
case PHASED_OUT:
|
||||
case PHASED_IN:
|
||||
if (isLeavesTheBattlefieldTrigger()) {
|
||||
source = game.getLastKnownInformation(getSourceId(), event.getZone());
|
||||
}
|
||||
if (this.zone == Zone.ALL || game.getLastKnownInformation(getSourceId(), zone) != null) {
|
||||
return this.hasSourceObjectAbility(game, source, event);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return super.isInUseableZone(game, source, event);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,9 @@ public class ZoneChangeAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
public ZoneChangeAllTriggeredAbility(Zone zone, Zone fromZone, Zone toZone, Effect effect, FilterPermanent filter, String rule, boolean optional) {
|
||||
super(zone, effect, optional);
|
||||
if (fromZone == Zone.BATTLEFIELD) {
|
||||
setLeavesTheBattlefieldTrigger(true);
|
||||
}
|
||||
this.fromZone = fromZone;
|
||||
this.toZone = toZone;
|
||||
this.rule = rule;
|
||||
|
|
Loading…
Reference in a new issue