Refactor effects which disable the "legend rule" (#9662)

This commit is contained in:
Evan Kranzler 2022-10-28 18:04:23 -04:00 committed by GitHub
parent 1fece87819
commit 3ed26a2b1f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 243 additions and 211 deletions

View file

@ -1,12 +1,9 @@
package mage.cards.b; package mage.cards.b;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.effects.common.continuous.BoostAllEffect;
import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect;
import mage.abilities.keyword.BushidoAbility; import mage.abilities.keyword.BushidoAbility;
@ -16,14 +13,15 @@ import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.*;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import java.util.List;
import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class BrothersYamazaki extends CardImpl { public final class BrothersYamazaki extends CardImpl {
@ -36,7 +34,7 @@ public final class BrothersYamazaki extends CardImpl {
} }
public BrothersYamazaki(UUID ownerId, CardSetInfo setInfo) { public BrothersYamazaki(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}");
addSuperType(SuperType.LEGENDARY); addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN, SubType.SAMURAI); this.subtype.add(SubType.HUMAN, SubType.SAMURAI);
this.power = new MageInt(2); this.power = new MageInt(2);
@ -46,15 +44,15 @@ public final class BrothersYamazaki extends CardImpl {
this.addAbility(new BushidoAbility(1)); this.addAbility(new BushidoAbility(1));
// If there are exactly two permanents named Brothers Yamazaki on the battlefield, the "legend rule" doesn't apply to them. // If there are exactly two permanents named Brothers Yamazaki on the battlefield, the "legend rule" doesn't apply to them.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BrothersYamazakiIgnoreLegendRuleEffectEffect())); this.addAbility(new SimpleStaticAbility(new BrothersYamazakiIgnoreLegendRuleEffectEffect()));
// Each other creature named Brothers Yamazaki gets +2/+2 and has haste. // Each other creature named Brothers Yamazaki gets +2/+2 and has haste.
Effect effect = new BoostAllEffect(2, 2, Duration.WhileOnBattlefield, filter, true); Ability ability = new SimpleStaticAbility(new BoostAllEffect(
effect.setText("Each other creature named Brothers Yamazaki gets +2/+2"); 2, 2, Duration.WhileOnBattlefield, filter, true
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); ).setText("Each other creature named Brothers Yamazaki gets +2/+2"));
effect = new GainAbilityAllEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield, filter); ability.addEffect(new GainAbilityAllEffect(
effect.setText("and has haste"); HasteAbility.getInstance(), Duration.WhileOnBattlefield, filter
ability.addEffect(effect); ).setText("and has haste"));
this.addAbility(ability); this.addAbility(ability);
} }
@ -68,7 +66,7 @@ public final class BrothersYamazaki extends CardImpl {
} }
} }
class BrothersYamazakiIgnoreLegendRuleEffectEffect extends ContinuousRuleModifyingEffectImpl { class BrothersYamazakiIgnoreLegendRuleEffectEffect extends ContinuousEffectImpl {
private static final FilterPermanent filter = new FilterPermanent(); private static final FilterPermanent filter = new FilterPermanent();
@ -77,7 +75,7 @@ class BrothersYamazakiIgnoreLegendRuleEffectEffect extends ContinuousRuleModifyi
} }
public BrothersYamazakiIgnoreLegendRuleEffectEffect() { public BrothersYamazakiIgnoreLegendRuleEffectEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment, false, false); super(Duration.WhileOnBattlefield, Layer.RulesEffects, SubLayer.NA, Outcome.Detriment);
staticText = "If there are exactly two permanents named Brothers Yamazaki on the battlefield, the \"legend rule\" doesn't apply to them"; staticText = "If there are exactly two permanents named Brothers Yamazaki on the battlefield, the \"legend rule\" doesn't apply to them";
} }
@ -91,17 +89,16 @@ class BrothersYamazakiIgnoreLegendRuleEffectEffect extends ContinuousRuleModifyi
} }
@Override @Override
public boolean checksEventType(GameEvent event, Game game) { public boolean apply(Game game, Ability source) {
return event.getType() == GameEvent.EventType.DESTROY_PERMANENT_BY_LEGENDARY_RULE; List<Permanent> permanents = game.getBattlefield().getActivePermanents(
} filter, source.getControllerId(), source, game
);
@Override if (permanents.size() != 2) {
public boolean applies(GameEvent event, Ability source, Game game) { return false;
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent != null && permanent.getName().equals("Brothers Yamazaki")) {
return game.getBattlefield().count(filter, source.getControllerId(), source, game) == 2;
} }
return false; for (Permanent permanent : permanents) {
permanent.setLegendRuleApplies(false);
}
return true;
} }
} }

View file

@ -5,11 +5,11 @@ import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.abilities.effects.common.CreateTokenCopyTargetEffect;
import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.DoIfCostPaid;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.common.ruleModifying.LegendRuleDoesntApplyEffect;
import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.HasteAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
@ -19,9 +19,7 @@ import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.filter.predicate.permanent.TokenPredicate; import mage.filter.predicate.permanent.TokenPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentToken;
import mage.target.targetpointer.FixedTargets; import mage.target.targetpointer.FixedTargets;
import java.util.UUID; import java.util.UUID;
@ -33,11 +31,14 @@ public final class CadricSoulKindler extends CardImpl {
private static final FilterPermanent filter private static final FilterPermanent filter
= new FilterControlledPermanent("another nontoken legendary permanent"); = new FilterControlledPermanent("another nontoken legendary permanent");
private static final FilterPermanent filter2
= new FilterControlledPermanent("tokens you control");
static { static {
filter.add(TokenPredicate.FALSE); filter.add(TokenPredicate.FALSE);
filter.add(AnotherPredicate.instance); filter.add(AnotherPredicate.instance);
filter.add(SuperType.LEGENDARY.getPredicate()); filter.add(SuperType.LEGENDARY.getPredicate());
filter2.add(TokenPredicate.TRUE);
} }
public CadricSoulKindler(UUID ownerId, CardSetInfo setInfo) { public CadricSoulKindler(UUID ownerId, CardSetInfo setInfo) {
@ -50,7 +51,7 @@ public final class CadricSoulKindler extends CardImpl {
this.toughness = new MageInt(3); this.toughness = new MageInt(3);
// The "legend rule" doesn't apply to tokens you control. // The "legend rule" doesn't apply to tokens you control.
this.addAbility(new SimpleStaticAbility(new CadricSoulKindlerLegendEffect())); this.addAbility(new SimpleStaticAbility(new LegendRuleDoesntApplyEffect(filter2)));
// Whenever another nontoken legendary permanent enters the battlefield under your control, you may pay {1}. If you do, create a token that's a copy of it. That token gains haste. Sacrifice it at the beginning of the next end step. // Whenever another nontoken legendary permanent enters the battlefield under your control, you may pay {1}. If you do, create a token that's a copy of it. That token gains haste. Sacrifice it at the beginning of the next end step.
this.addAbility(new EntersBattlefieldControlledTriggeredAbility( this.addAbility(new EntersBattlefieldControlledTriggeredAbility(
@ -68,34 +69,6 @@ public final class CadricSoulKindler extends CardImpl {
} }
} }
class CadricSoulKindlerLegendEffect extends ContinuousRuleModifyingEffectImpl {
public CadricSoulKindlerLegendEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment, false, false);
staticText = "the \"legend rule\" doesn't apply to tokens you control";
}
public CadricSoulKindlerLegendEffect(final CadricSoulKindlerLegendEffect effect) {
super(effect);
}
@Override
public CadricSoulKindlerLegendEffect copy() {
return new CadricSoulKindlerLegendEffect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DESTROY_PERMANENT_BY_LEGENDARY_RULE;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
Permanent permanent = game.getPermanent(event.getTargetId());
return permanent instanceof PermanentToken && permanent.isControlledBy(source.getControllerId());
}
}
class CadricSoulKindlerTokenEffect extends OneShotEffect { class CadricSoulKindlerTokenEffect extends OneShotEffect {
CadricSoulKindlerTokenEffect() { CadricSoulKindlerTokenEffect() {

View file

@ -3,18 +3,14 @@ package mage.cards.m;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.abilities.effects.common.ruleModifying.LegendRuleDoesntApplyEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.TokenPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.util.CardUtil; import mage.util.CardUtil;
@ -36,7 +32,9 @@ public final class MirrorBox extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
// The "legend rule" doesn't apply to permanents you control. // The "legend rule" doesn't apply to permanents you control.
this.addAbility(new SimpleStaticAbility(new MirrorBoxLegendEffect())); this.addAbility(new SimpleStaticAbility(new LegendRuleDoesntApplyEffect(
StaticFilters.FILTER_CONTROLLED_PERMANENTS
)));
// Each legendary creature you control gets +1/+1. // Each legendary creature you control gets +1/+1.
this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(
@ -57,34 +55,6 @@ public final class MirrorBox extends CardImpl {
} }
} }
class MirrorBoxLegendEffect extends ContinuousRuleModifyingEffectImpl {
MirrorBoxLegendEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment, false, false);
staticText = "the \"legend rule\" doesn't apply to permanents you control";
}
private MirrorBoxLegendEffect(final MirrorBoxLegendEffect effect) {
super(effect);
}
@Override
public MirrorBoxLegendEffect copy() {
return new MirrorBoxLegendEffect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DESTROY_PERMANENT_BY_LEGENDARY_RULE;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
Permanent permanent = game.getPermanent(event.getTargetId());
return permanent != null && permanent.isControlledBy(source.getControllerId());
}
}
class MirrorBoxBoostEffect extends ContinuousEffectImpl { class MirrorBoxBoostEffect extends ContinuousEffectImpl {
public MirrorBoxBoostEffect() { public MirrorBoxBoostEffect() {

View file

@ -1,31 +1,23 @@
package mage.cards.m; package mage.cards.m;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.ruleModifying.LegendRuleDoesntApplyEffect;
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.Duration;
import mage.constants.Layer; import java.util.UUID;
import mage.constants.Outcome;
import mage.constants.SubLayer;
import mage.constants.Zone;
import mage.game.Game;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class MirrorGallery extends CardImpl { public final class MirrorGallery extends CardImpl {
public MirrorGallery(UUID ownerId, CardSetInfo setInfo) { public MirrorGallery(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{5}"); super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}");
// The "legend rule" doesn't apply. // The "legend rule" doesn't apply.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MirrorGalleryRuleEffect())); this.addAbility(new SimpleStaticAbility(new LegendRuleDoesntApplyEffect()));
} }
private MirrorGallery(final MirrorGallery card) { private MirrorGallery(final MirrorGallery card) {
@ -37,36 +29,3 @@ public final class MirrorGallery extends CardImpl {
return new MirrorGallery(this); return new MirrorGallery(this);
} }
} }
class MirrorGalleryRuleEffect extends ContinuousEffectImpl {
public MirrorGalleryRuleEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment);
staticText = "The \"legend rule\" doesn't apply";
}
public MirrorGalleryRuleEffect(final MirrorGalleryRuleEffect effect) {
super(effect);
}
@Override
public MirrorGalleryRuleEffect copy() {
return new MirrorGalleryRuleEffect(this);
}
@Override
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
game.getState().setLegendaryRuleActive(false);
return true;
}
@Override
public boolean apply(Game game, Ability source) {
return false;
}
@Override
public boolean hasLayer(Layer layer) {
return layer == Layer.RulesEffects;
}
}

View file

@ -5,16 +5,16 @@ import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.common.CopyPermanentEffect; import mage.abilities.effects.common.CopyPermanentEffect;
import mage.abilities.effects.common.ruleModifying.LegendRuleDoesntApplyEffect;
import mage.abilities.keyword.PartnerAbility; import mage.abilities.keyword.PartnerAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.util.functions.CopyApplier; import mage.util.functions.CopyApplier;
import java.util.UUID; import java.util.UUID;
@ -39,7 +39,7 @@ public final class SakashimaOfAThousandFaces extends CardImpl {
).setText("as a copy of another creature you control, except it has {this}'s other abilities"), true)); ).setText("as a copy of another creature you control, except it has {this}'s other abilities"), true));
// The "legend rule" doesn't apply to permanents you control. // The "legend rule" doesn't apply to permanents you control.
this.addAbility(new SimpleStaticAbility(new SakashimaOfAThousandFacesEffect())); this.addAbility(new SimpleStaticAbility(new LegendRuleDoesntApplyEffect(StaticFilters.FILTER_CONTROLLED_PERMANENTS)));
// Partner // Partner
this.addAbility(PartnerAbility.getInstance()); this.addAbility(PartnerAbility.getInstance());
@ -59,36 +59,8 @@ class SakashimaOfAThousandFacesCopyApplier extends CopyApplier {
@Override @Override
public boolean apply(Game game, MageObject blueprint, Ability source, UUID copyToObjectId) { public boolean apply(Game game, MageObject blueprint, Ability source, UUID copyToObjectId) {
blueprint.getAbilities().add(new SimpleStaticAbility(new SakashimaOfAThousandFacesEffect())); blueprint.getAbilities().add(new SimpleStaticAbility(new LegendRuleDoesntApplyEffect(StaticFilters.FILTER_CONTROLLED_PERMANENTS)));
blueprint.getAbilities().add(PartnerAbility.getInstance()); blueprint.getAbilities().add(PartnerAbility.getInstance());
return true; return true;
} }
} }
class SakashimaOfAThousandFacesEffect extends ContinuousRuleModifyingEffectImpl {
SakashimaOfAThousandFacesEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment, false, false);
staticText = "the \"legend rule\" doesn't apply to permanents you control";
}
private SakashimaOfAThousandFacesEffect(final SakashimaOfAThousandFacesEffect effect) {
super(effect);
}
@Override
public SakashimaOfAThousandFacesEffect copy() {
return new SakashimaOfAThousandFacesEffect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DESTROY_PERMANENT_BY_LEGENDARY_RULE;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
Permanent permanent = game.getPermanent(event.getTargetId());
return permanent != null && permanent.isControlledBy(source.getControllerId());
}
}

View file

@ -144,7 +144,7 @@ public class CleverImpersonatorTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Clever Impersonator"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Clever Impersonator");
setChoice(playerA, "Jace, Vryn's Prodigy"); setChoice(playerA, "Jace, Vryn's Prodigy");
addTarget(playerA, "Jace, Vryn's Prodigy[only copy]"); // keep the copied Jace setChoice(playerA, "Jace, Vryn's Prodigy[only copy]"); // keep the copied Jace
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Draw a card"); activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Draw a card");
setChoice(playerA, "Pillarfield Ox"); setChoice(playerA, "Pillarfield Ox");

View file

@ -55,25 +55,25 @@ public class SharuumTheHegemonTest extends CardTestPlayerBase {
setChoice(playerA, true); setChoice(playerA, true);
setChoice(playerA, "Sharuum the Hegemon"); // what creature to clone setChoice(playerA, "Sharuum the Hegemon"); // what creature to clone
addTarget(playerA, "Sharuum the Hegemon[only copy]"); // which legend to keep setChoice(playerA, "Sharuum the Hegemon[only copy]"); // which legend to keep
setChoice(playerA, "Whenever {this} or another creature dies"); // blood first setChoice(playerA, "Whenever {this} or another creature dies"); // blood first
addTarget(playerA, playerB); // damage by blood addTarget(playerA, playerB); // damage by blood
setChoice(playerA, true); // return setChoice(playerA, true); // return
// addTarget(playerA, "Sharuum the Hegemon"); // return real sharuum (Autochosen, only target) // addTarget(playerA, "Sharuum the Hegemon"); // return real sharuum (Autochosen, only target)
addTarget(playerA, "Sharuum the Hegemon[only copy]"); // which legend to keep setChoice(playerA, "Sharuum the Hegemon[only copy]"); // which legend to keep
setChoice(playerA, "Whenever {this} or another creature dies"); // blood first setChoice(playerA, "Whenever {this} or another creature dies"); // blood first
addTarget(playerA, playerB); // damage by blood addTarget(playerA, playerB); // damage by blood
setChoice(playerA, true); // return setChoice(playerA, true); // return
// addTarget(playerA, "Sharuum the Hegemon"); // return real sharuum (Autochosen, only target // addTarget(playerA, "Sharuum the Hegemon"); // return real sharuum (Autochosen, only target
addTarget(playerA, "Sharuum the Hegemon[only copy]"); // which legend to keep setChoice(playerA, "Sharuum the Hegemon[only copy]"); // which legend to keep
setChoice(playerA, "Whenever {this} or another creature dies"); // blood first setChoice(playerA, "Whenever {this} or another creature dies"); // blood first
addTarget(playerA, playerB); // damage by blood addTarget(playerA, playerB); // damage by blood
setChoice(playerA, true); // return setChoice(playerA, true); // return
// addTarget(playerA, "Sharuum the Hegemon"); // return real sharuum (Autochosen, only target) // addTarget(playerA, "Sharuum the Hegemon"); // return real sharuum (Autochosen, only target)
addTarget(playerA, "Sharuum the Hegemon[only copy]"); // which legend to keep setChoice(playerA, "Sharuum the Hegemon[only copy]"); // which legend to keep
setChoice(playerA, "Whenever {this} or another creature dies"); // blood first setChoice(playerA, "Whenever {this} or another creature dies"); // blood first
addTarget(playerA, playerB); // damage by blood addTarget(playerA, playerB); // damage by blood
setChoice(playerA, false); // Don't use it anymore setChoice(playerA, false); // Don't use it anymore

View file

@ -0,0 +1,32 @@
package org.mage.test.cards.rules;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author TheElk801
*/
public class LegendRuleTest extends CardTestPlayerBase {
private static final String isamaru = "Isamaru, Hound of Konda";
@Test
public void testRegular() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
addCard(Zone.HAND, playerA, isamaru, 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, isamaru);
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, isamaru);
setChoice(playerA, isamaru);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertGraveyardCount(playerA, isamaru, 1);
assertPermanentCount(playerA, isamaru, 1);
}
}

View file

@ -0,0 +1,53 @@
package org.mage.test.cards.single.dmc;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author TheElk801
*/
public class CadricSoulKindlerTest extends CardTestPlayerBase {
private static final String cadric = "Cadric, Soul Kindler";
private static final String isamaru = "Isamaru, Hound of Konda";
@Test
public void testOneCopy() {
addCard(Zone.BATTLEFIELD, playerA, cadric);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
addCard(Zone.HAND, playerA, isamaru);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, isamaru);
setChoice(playerA, true);
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
setStrictChooseMode(true);
execute();
assertPermanentCount(playerA, isamaru, 2);
assertGraveyardCount(playerA, isamaru, 0);
}
@Test
public void testTwoCopies() {
addCard(Zone.BATTLEFIELD, playerA, cadric);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
addCard(Zone.HAND, playerA, isamaru, 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, isamaru);
setChoice(playerA, true);
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, isamaru);
setChoice(playerA, true);
setChoice(playerA, isamaru);
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
setStrictChooseMode(true);
execute();
assertPermanentCount(playerA, isamaru, 3);
assertGraveyardCount(playerA, isamaru, 1);
}
}

View file

@ -0,0 +1,51 @@
package mage.abilities.effects.common.ruleModifying;
import mage.abilities.Ability;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.constants.Duration;
import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.SubLayer;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
* @author TheElk801
*/
public class LegendRuleDoesntApplyEffect extends ContinuousEffectImpl {
private final FilterPermanent filter;
public LegendRuleDoesntApplyEffect() {
this(StaticFilters.FILTER_PERMANENTS);
this.staticText = "the \"legend rule\" doesn't apply";
}
public LegendRuleDoesntApplyEffect(FilterPermanent filter) {
super(Duration.WhileOnBattlefield, Layer.RulesEffects, SubLayer.NA, Outcome.Detriment);
staticText = "the \"legend rule\" doesn't apply to " + filter.getMessage();
this.filter = filter;
}
private LegendRuleDoesntApplyEffect(final LegendRuleDoesntApplyEffect effect) {
super(effect);
this.filter = effect.filter;
}
@Override
public LegendRuleDoesntApplyEffect copy() {
return new LegendRuleDoesntApplyEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(
filter, source.getControllerId(), source, game
)) {
permanent.setLegendRuleApplies(false);
}
return true;
}
}

View file

@ -0,0 +1,17 @@
package mage.filter.predicate.permanent;
import mage.filter.predicate.Predicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
* @author TheElk801
*/
public enum LegendRuleAppliesPredicate implements Predicate<Permanent> {
instance;
@Override
public boolean apply(Permanent input, Game game) {
return input.legendRuleApplies();
}
}

View file

@ -36,6 +36,7 @@ import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.mageobject.NamePredicate;
import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.filter.predicate.permanent.LegendRuleAppliesPredicate;
import mage.game.combat.Combat; import mage.game.combat.Combat;
import mage.game.command.*; import mage.game.command.*;
import mage.game.command.dungeons.UndercityDungeon; import mage.game.command.dungeons.UndercityDungeon;
@ -2478,7 +2479,7 @@ public abstract class GameImpl implements Game {
somethingHappened = true; somethingHappened = true;
} }
} }
if (this.getState().isLegendaryRuleActive() && StaticFilters.FILTER_PERMANENT_LEGENDARY.match(perm, this)) { if (perm.isLegendary() && perm.legendRuleApplies()) {
legendary.add(perm); legendary.add(perm);
} }
if (StaticFilters.FILTER_PERMANENT_EQUIPMENT.match(perm, this)) { if (StaticFilters.FILTER_PERMANENT_EQUIPMENT.match(perm, this)) {
@ -2571,22 +2572,24 @@ public abstract class GameImpl implements Game {
filterLegendName.add(SuperType.LEGENDARY.getPredicate()); filterLegendName.add(SuperType.LEGENDARY.getPredicate());
filterLegendName.add(new NamePredicate(legend.getName())); filterLegendName.add(new NamePredicate(legend.getName()));
filterLegendName.add(new ControllerIdPredicate(legend.getControllerId())); filterLegendName.add(new ControllerIdPredicate(legend.getControllerId()));
if (getBattlefield().contains(filterLegendName, legend.getControllerId(), null, this, 2)) { filterLegendName.add(LegendRuleAppliesPredicate.instance);
if (!replaceEvent(GameEvent.getEvent(GameEvent.EventType.DESTROY_PERMANENT_BY_LEGENDARY_RULE, legend.getId(), legend.getControllerId()))) { if (!getBattlefield().contains(filterLegendName, legend.getControllerId(), null, this, 2)) {
Player controller = this.getPlayer(legend.getControllerId()); continue;
if (controller != null) { }
Target targetLegendaryToKeep = new TargetPermanent(filterLegendName); Player controller = this.getPlayer(legend.getControllerId());
targetLegendaryToKeep.setTargetName(legend.getName() + " to keep (Legendary Rule)?"); if (controller == null) {
controller.chooseTarget(Outcome.Benefit, targetLegendaryToKeep, null, this); continue;
for (Permanent dupLegend : getBattlefield().getActivePermanents(filterLegendName, legend.getControllerId(), this)) { }
if (!targetLegendaryToKeep.getTargets().contains(dupLegend.getId())) { Target targetLegendaryToKeep = new TargetPermanent(filterLegendName);
movePermanentToGraveyardWithInfo(dupLegend); targetLegendaryToKeep.setNotTarget(true);
} targetLegendaryToKeep.setTargetName(legend.getName() + " to keep (Legendary Rule)?");
} controller.choose(Outcome.Benefit, targetLegendaryToKeep, null, this);
} for (Permanent dupLegend : getBattlefield().getActivePermanents(filterLegendName, legend.getControllerId(), this)) {
return true; if (!targetLegendaryToKeep.getTargets().contains(dupLegend.getId())) {
movePermanentToGraveyardWithInfo(dupLegend);
} }
} }
return true;
} }
} }
//704.5k - World Enchantments //704.5k - World Enchantments

View file

@ -88,7 +88,6 @@ public class GameState implements Serializable, Copyable<GameState> {
private int stepNum = 0; private int stepNum = 0;
private UUID turnId = null; private UUID turnId = null;
private boolean extraTurn = false; private boolean extraTurn = false;
private boolean legendaryRuleActive = true;
private boolean gameOver; private boolean gameOver;
private boolean paused; private boolean paused;
private ContinuousEffects effects; private ContinuousEffects effects;
@ -159,7 +158,6 @@ public class GameState implements Serializable, Copyable<GameState> {
this.turnNum = state.turnNum; this.turnNum = state.turnNum;
this.stepNum = state.stepNum; this.stepNum = state.stepNum;
this.extraTurn = state.extraTurn; this.extraTurn = state.extraTurn;
this.legendaryRuleActive = state.legendaryRuleActive;
this.effects = state.effects.copy(); this.effects = state.effects.copy();
for (TriggeredAbility trigger : state.triggered) { for (TriggeredAbility trigger : state.triggered) {
this.triggered.add(trigger.copy()); this.triggered.add(trigger.copy());
@ -227,7 +225,6 @@ public class GameState implements Serializable, Copyable<GameState> {
turnNum = 1; turnNum = 1;
stepNum = 0; stepNum = 0;
extraTurn = false; extraTurn = false;
legendaryRuleActive = true;
gameOver = false; gameOver = false;
specialActions.clear(); specialActions.clear();
cardState.clear(); cardState.clear();
@ -264,7 +261,6 @@ public class GameState implements Serializable, Copyable<GameState> {
this.turnNum = state.turnNum; this.turnNum = state.turnNum;
this.stepNum = state.stepNum; this.stepNum = state.stepNum;
this.extraTurn = state.extraTurn; this.extraTurn = state.extraTurn;
this.legendaryRuleActive = state.legendaryRuleActive;
this.effects = state.effects; this.effects = state.effects;
this.triggered = state.triggered; this.triggered = state.triggered;
this.triggers = state.triggers; this.triggers = state.triggers;
@ -1224,7 +1220,6 @@ public class GameState implements Serializable, Copyable<GameState> {
// All gained abilities have to be removed to prevent adding it multiple times // All gained abilities have to be removed to prevent adding it multiple times
triggers.removeAllGainedAbilities(); triggers.removeAllGainedAbilities();
getContinuousEffects().removeAllTemporaryEffects(); getContinuousEffects().removeAllTemporaryEffects();
this.setLegendaryRuleActive(true);
for (CardState state : cardState.values()) { for (CardState state : cardState.values()) {
state.clearAbilities(); state.clearAbilities();
} }
@ -1244,14 +1239,6 @@ public class GameState implements Serializable, Copyable<GameState> {
return this.paused; return this.paused;
} }
public boolean isLegendaryRuleActive() {
return legendaryRuleActive;
}
public void setLegendaryRuleActive(boolean legendaryRuleActive) {
this.legendaryRuleActive = legendaryRuleActive;
}
/** /**
* Only used for diagnostic purposes of tests * Only used for diagnostic purposes of tests
* *
@ -1447,21 +1434,22 @@ public class GameState implements Serializable, Copyable<GameState> {
boolean isDaytime() { boolean isDaytime() {
return isDaytime; return isDaytime;
} }
@Override @Override
public String toString() { public String toString() {
return CardUtil.getTurnInfo(this); return CardUtil.getTurnInfo(this);
} }
public boolean setReverseTurnOrder(boolean reverse){ public boolean setReverseTurnOrder(boolean reverse) {
if(this.reverseTurnOrder&&reverse){ if (this.reverseTurnOrder && reverse) {
this.reverseTurnOrder = false; this.reverseTurnOrder = false;
} else { } else {
this.reverseTurnOrder = reverse; this.reverseTurnOrder = reverse;
} }
return this.reverseTurnOrder; return this.reverseTurnOrder;
} }
public boolean getReverseTurnOrder(){
public boolean getReverseTurnOrder() {
return this.reverseTurnOrder; return this.reverseTurnOrder;
} }
} }

View file

@ -222,6 +222,10 @@ public interface Permanent extends Card, Controllable {
boolean canLoyaltyBeUsed(Game game); boolean canLoyaltyBeUsed(Game game);
void setLegendRuleApplies(boolean legendRuleApplies);
boolean legendRuleApplies();
void resetControl(); void resetControl();
boolean changeControllerId(UUID controllerId, Game game, Ability source); boolean changeControllerId(UUID controllerId, Game game, Ability source);

View file

@ -106,6 +106,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
protected int transformCount = 0; protected int transformCount = 0;
protected Map<String, String> info; protected Map<String, String> info;
protected int createOrder; protected int createOrder;
protected boolean legendRuleApplies = true;
private static final List<UUID> emptyList = Collections.unmodifiableList(new ArrayList<UUID>()); private static final List<UUID> emptyList = Collections.unmodifiableList(new ArrayList<UUID>());
@ -171,6 +172,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
this.bandedCards.addAll(permanent.bandedCards); this.bandedCards.addAll(permanent.bandedCards);
this.timesLoyaltyUsed = permanent.timesLoyaltyUsed; this.timesLoyaltyUsed = permanent.timesLoyaltyUsed;
this.loyaltyActivationsAvailable = permanent.loyaltyActivationsAvailable; this.loyaltyActivationsAvailable = permanent.loyaltyActivationsAvailable;
this.legendRuleApplies = permanent.legendRuleApplies;
this.transformCount = permanent.transformCount; this.transformCount = permanent.transformCount;
this.morphed = permanent.morphed; this.morphed = permanent.morphed;
@ -214,6 +216,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
this.copy = false; this.copy = false;
this.goadingPlayers.clear(); this.goadingPlayers.clear();
this.loyaltyActivationsAvailable = 1; this.loyaltyActivationsAvailable = 1;
this.legendRuleApplies = true;
} }
@Override @Override
@ -491,6 +494,16 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
return false; return false;
} }
@Override
public void setLegendRuleApplies(boolean legendRuleApplies) {
this.legendRuleApplies = legendRuleApplies;
}
@Override
public boolean legendRuleApplies() {
return this.legendRuleApplies;
}
@Override @Override
public boolean isTapped() { public boolean isTapped() {
return tapped; return tapped;