mirror of
https://github.com/correl/mage.git
synced 2024-11-28 19:19:55 +00:00
[STX] add more cards (#7720)
* implement AcademicProbation * implement AugmenterPugilist // EchoingEquation * Implement BalefulMastery * implement BasicConjuration * implement ClosingStatement * Test framework: added custom effect to return card from any zone to hand; Co-authored-by: Oleg Agafonov <jaydi85@gmail.com>
This commit is contained in:
parent
ac2c2acfe4
commit
10cd439955
14 changed files with 766 additions and 57 deletions
96
Mage.Sets/src/mage/cards/a/AcademicProbation.java
Normal file
96
Mage.Sets/src/mage/cards/a/AcademicProbation.java
Normal file
|
@ -0,0 +1,96 @@
|
|||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.RestrictionEffect;
|
||||
import mage.abilities.effects.common.OpponentsCantCastChosenUntilNextTurnEffect;
|
||||
import mage.abilities.effects.common.ChooseACardNameEffect;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.common.TargetNonlandPermanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author htrajan
|
||||
*/
|
||||
public final class AcademicProbation extends CardImpl {
|
||||
|
||||
public AcademicProbation(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{W}");
|
||||
|
||||
this.subtype.add(SubType.LESSON);
|
||||
|
||||
// Choose one —
|
||||
// • Choose a nonland card name. Opponents can't cast spells with the chosen name until your next turn.
|
||||
Effect effect = new ChooseACardNameEffect(ChooseACardNameEffect.TypeOfName.NON_LAND_NAME);
|
||||
effect.setText("Choose a nonland card name");
|
||||
this.getSpellAbility().addEffect(effect);
|
||||
this.getSpellAbility().addEffect(new OpponentsCantCastChosenUntilNextTurnEffect().setText("opponents can't cast spells with the chosen name until your next turn"));
|
||||
|
||||
// • Choose target nonland permanent. Until your next turn, it can't attack or block, and its activated abilities can't be activated.
|
||||
Mode restrictMode = new Mode();
|
||||
restrictMode.addEffect(new AcademicProbationRestrictionEffect());
|
||||
restrictMode.addTarget(new TargetNonlandPermanent());
|
||||
this.getSpellAbility().addMode(restrictMode);
|
||||
}
|
||||
|
||||
private AcademicProbation(final AcademicProbation card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AcademicProbation copy() {
|
||||
return new AcademicProbation(this);
|
||||
}
|
||||
}
|
||||
|
||||
class AcademicProbationRestrictionEffect extends RestrictionEffect {
|
||||
|
||||
AcademicProbationRestrictionEffect() {
|
||||
super(Duration.UntilYourNextTurn, Outcome.UnboostCreature);
|
||||
staticText = "choose target nonland permanent. Until your next turn, it can't attack or block, and its activated abilities can't be activated";
|
||||
}
|
||||
|
||||
AcademicProbationRestrictionEffect(final AcademicProbationRestrictionEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AcademicProbationRestrictionEffect copy() {
|
||||
return new AcademicProbationRestrictionEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||
return this.targetPointer.getTargets(game, source).contains(permanent.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAttack(Game game, boolean canUseChooseDialogs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) {
|
||||
return false;
|
||||
}
|
||||
}
|
110
Mage.Sets/src/mage/cards/a/AugmenterPugilist.java
Normal file
110
Mage.Sets/src/mage/cards/a/AugmenterPugilist.java
Normal file
|
@ -0,0 +1,110 @@
|
|||
package mage.cards.a;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
|
||||
import mage.abilities.decorator.ConditionalContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostSourceEffect;
|
||||
import mage.abilities.hint.common.LandsYouControlHint;
|
||||
import mage.abilities.keyword.TrampleAbility;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.cards.ModalDoubleFacesCard;
|
||||
import mage.constants.*;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
import mage.util.functions.CopyApplier;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author htrajan
|
||||
*/
|
||||
public final class AugmenterPugilist extends ModalDoubleFacesCard {
|
||||
|
||||
public AugmenterPugilist(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo,
|
||||
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.TROLL, SubType.DRUID}, "{1}{G}{G}",
|
||||
"Echoing Equation", new CardType[]{CardType.SORCERY}, new SubType[]{}, "{3}{U}{U}");
|
||||
|
||||
// 1.
|
||||
// Augmenter Pugilist
|
||||
// Creature — Troll Druid
|
||||
this.getLeftHalfCard().setPT(3, 3);
|
||||
|
||||
// Trample
|
||||
this.getLeftHalfCard().addAbility(TrampleAbility.getInstance());
|
||||
|
||||
// As long as you control eight or more lands, Augmenter Pugilist gets +5/+5.
|
||||
this.getLeftHalfCard().addAbility(new SimpleStaticAbility(
|
||||
Zone.BATTLEFIELD,
|
||||
new ConditionalContinuousEffect(
|
||||
new BoostSourceEffect(
|
||||
5, 5, Duration.WhileOnBattlefield
|
||||
),
|
||||
new PermanentsOnTheBattlefieldCondition(
|
||||
StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND,
|
||||
ComparisonType.MORE_THAN, 7
|
||||
),
|
||||
"as long as you control eight or more lands, {this} gets +5/+5"
|
||||
)
|
||||
).addHint(LandsYouControlHint.instance));
|
||||
|
||||
// 2.
|
||||
// Echoing Equation
|
||||
// Sorcery
|
||||
|
||||
// Choose target creature you control. Each other creature you control becomes a copy of it until end of turn, except those creatures aren’t legendary if the chosen creature is legendary.
|
||||
this.getRightHalfCard().getSpellAbility().addEffect(new EchoingEquationEffect());
|
||||
this.getRightHalfCard().getSpellAbility().addTarget(new TargetControlledCreaturePermanent());
|
||||
|
||||
}
|
||||
|
||||
private AugmenterPugilist(final AugmenterPugilist card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AugmenterPugilist copy() {
|
||||
return new AugmenterPugilist(this);
|
||||
}
|
||||
}
|
||||
|
||||
class EchoingEquationEffect extends OneShotEffect {
|
||||
|
||||
public EchoingEquationEffect() {
|
||||
super(Outcome.Benefit);
|
||||
staticText = "choose target creature you control. Each other creature you control becomes a copy of it until end of turn, except those creatures aren't legendary if the chosen creature is legendary";
|
||||
}
|
||||
|
||||
EchoingEquationEffect(EchoingEquationEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EchoingEquationEffect copy() {
|
||||
return new EchoingEquationEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent copyFrom = game.getPermanent(source.getFirstTarget());
|
||||
if (copyFrom != null) {
|
||||
game.getBattlefield().getAllActivePermanents(source.getControllerId()).stream()
|
||||
.filter(permanent -> permanent.isCreature() && !permanent.getId().equals(copyFrom.getId()))
|
||||
.forEach(copyTo -> game.copyPermanent(Duration.EndOfTurn, copyFrom, copyTo.getId(), source, new CopyApplier() {
|
||||
@Override
|
||||
public boolean apply(Game game, MageObject blueprint, Ability source, UUID targetObjectId) {
|
||||
blueprint.getSuperType().remove(SuperType.LEGENDARY);
|
||||
return true;
|
||||
}
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
87
Mage.Sets/src/mage/cards/b/BalefulMastery.java
Normal file
87
Mage.Sets/src/mage/cards/b/BalefulMastery.java
Normal file
|
@ -0,0 +1,87 @@
|
|||
package mage.cards.b;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.AlternativeCostSourceAbility;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.ExileTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCreatureOrPlaneswalker;
|
||||
import mage.target.common.TargetOpponent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author htrajan
|
||||
*/
|
||||
public final class BalefulMastery extends CardImpl {
|
||||
|
||||
public BalefulMastery(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{B}");
|
||||
|
||||
// You may pay {1}{B} rather than pay this spell's mana cost.
|
||||
Ability costAbility = new AlternativeCostSourceAbility(new ManaCostsImpl<>("{1}{B}"));
|
||||
this.addAbility(costAbility);
|
||||
|
||||
// If the {1}{B} cost was paid, an opponent draws a card.
|
||||
this.getSpellAbility().addEffect(new BalefulMasteryAlternativeCostEffect(costAbility.getOriginalId()));
|
||||
|
||||
// Exile target creature or planeswalker.
|
||||
this.getSpellAbility().addEffect(new ExileTargetEffect());
|
||||
this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker());
|
||||
}
|
||||
|
||||
private BalefulMastery(final BalefulMastery card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BalefulMastery copy() {
|
||||
return new BalefulMastery(this);
|
||||
}
|
||||
}
|
||||
|
||||
class BalefulMasteryAlternativeCostEffect extends OneShotEffect {
|
||||
|
||||
UUID alternativeCostOriginalID;
|
||||
|
||||
BalefulMasteryAlternativeCostEffect(UUID alternativeCostOriginalID) {
|
||||
super(Outcome.Detriment);
|
||||
staticText = "if the {1}{B} cost was paid, an opponent draws a card.<br>";
|
||||
this.alternativeCostOriginalID = alternativeCostOriginalID;
|
||||
}
|
||||
|
||||
BalefulMasteryAlternativeCostEffect(BalefulMasteryAlternativeCostEffect effect) {
|
||||
super(effect);
|
||||
this.alternativeCostOriginalID = effect.alternativeCostOriginalID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BalefulMasteryAlternativeCostEffect copy() {
|
||||
return new BalefulMasteryAlternativeCostEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
boolean wasActivated = AlternativeCostSourceAbility.getActivatedStatus(game, source, this.alternativeCostOriginalID, false);
|
||||
if (!wasActivated) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
TargetOpponent targetOpponent = new TargetOpponent(true);
|
||||
if (player.chooseTarget(Outcome.DrawCard, targetOpponent, source, game)) {
|
||||
Player opponent = game.getPlayer(targetOpponent.getFirstTarget());
|
||||
if (opponent != null) {
|
||||
opponent.drawCards(1, source, game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
41
Mage.Sets/src/mage/cards/b/BasicConjuration.java
Normal file
41
Mage.Sets/src/mage/cards/b/BasicConjuration.java
Normal file
|
@ -0,0 +1,41 @@
|
|||
package mage.cards.b;
|
||||
|
||||
import mage.abilities.effects.common.GainLifeEffect;
|
||||
import mage.abilities.effects.common.LookLibraryAndPickControllerEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.StaticFilters;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author htrajan
|
||||
*/
|
||||
public final class BasicConjuration extends CardImpl {
|
||||
|
||||
public BasicConjuration(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}{G}");
|
||||
|
||||
this.subtype.add(SubType.LESSON);
|
||||
|
||||
// Look at the top six cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. You gain 3 life.
|
||||
this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(
|
||||
6, 1, StaticFilters.FILTER_CARD_CREATURE_A,
|
||||
true, false, Zone.HAND, true
|
||||
).setBackInRandomOrder(true));
|
||||
this.getSpellAbility().addEffect(new GainLifeEffect(3));
|
||||
}
|
||||
|
||||
private BasicConjuration(final BasicConjuration card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicConjuration copy() {
|
||||
return new BasicConjuration(this);
|
||||
}
|
||||
}
|
97
Mage.Sets/src/mage/cards/c/ClosingStatement.java
Normal file
97
Mage.Sets/src/mage/cards/c/ClosingStatement.java
Normal file
|
@ -0,0 +1,97 @@
|
|||
package mage.cards.c;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.condition.common.IsPhaseCondition;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.DestroyTargetEffect;
|
||||
import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect;
|
||||
import mage.abilities.hint.ConditionHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.counters.CounterType;
|
||||
import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
import mage.target.common.TargetCreatureOrPlaneswalker;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author htrajan
|
||||
*/
|
||||
public final class ClosingStatement extends CardImpl {
|
||||
|
||||
private static final FilterCreatureOrPlaneswalkerPermanent filter = new FilterCreatureOrPlaneswalkerPermanent("creature or planeswalker you don't control");
|
||||
|
||||
static {
|
||||
filter.add(TargetController.NOT_YOU.getControllerPredicate());
|
||||
}
|
||||
|
||||
public ClosingStatement(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{W}{B}");
|
||||
|
||||
// This spell costs {2} less to cast during your end step.
|
||||
IsPhaseCondition condition = new IsPhaseCondition(TurnPhase.END, true);
|
||||
SimpleStaticAbility ability = new SimpleStaticAbility(Zone.ALL, new SpellCostReductionSourceEffect(2, condition).setText("this spell costs {2} less to cast during your end step"));
|
||||
ability.addHint(new ConditionHint(condition, "On your end step"));
|
||||
ability.setRuleAtTheTop(true);
|
||||
this.addAbility(ability);
|
||||
|
||||
// Destroy target creature or planeswalker you don't control. Put a +1/+1 counter on up to one target creature you control.
|
||||
this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker(1, 1, filter, false));
|
||||
this.getSpellAbility().addEffect(new DestroyTargetEffect());
|
||||
Target target = new TargetControlledCreaturePermanent(0, 1);
|
||||
target.setTargetTag(2);
|
||||
this.getSpellAbility().addTarget(target);
|
||||
this.getSpellAbility().addEffect(new ClosingStatementEffect());
|
||||
}
|
||||
|
||||
private ClosingStatement(final ClosingStatement card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClosingStatement copy() {
|
||||
return new ClosingStatement(this);
|
||||
}
|
||||
}
|
||||
|
||||
class ClosingStatementEffect extends OneShotEffect {
|
||||
|
||||
ClosingStatementEffect() {
|
||||
super(Outcome.Benefit);
|
||||
staticText = "put a +1/+1 counter on up to one target creature you control";
|
||||
}
|
||||
|
||||
private ClosingStatementEffect(final ClosingStatementEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClosingStatementEffect copy() {
|
||||
return new ClosingStatementEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
Target target = source.getTargets().stream()
|
||||
.filter(t -> t.getTargetTag() == 2)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("Expected to find target with tag 2 but none exists"));
|
||||
Permanent permanent = game.getPermanent(target.getFirstTarget());
|
||||
if (permanent != null) {
|
||||
return permanent.addCounters(CounterType.P1P1.createInstance(), source.getControllerId(), source, game);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,23 +1,15 @@
|
|||
package mage.cards.f;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.ChooseACardNameEffect;
|
||||
import mage.abilities.effects.common.OpponentsCantCastChosenUntilNextTurnEffect;
|
||||
import mage.abilities.effects.common.ReturnToHandTargetEffect;
|
||||
import mage.abilities.keyword.AftermathAbility;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.cards.SplitCard;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SpellAbilityType;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.target.TargetSpell;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -41,7 +33,7 @@ public final class FailureComply extends SplitCard {
|
|||
Effect effect = new ChooseACardNameEffect(ChooseACardNameEffect.TypeOfName.ALL);
|
||||
effect.setText("Choose a card name");
|
||||
getRightHalfCard().getSpellAbility().addEffect(effect);
|
||||
getRightHalfCard().getSpellAbility().addEffect(new ComplyCantCastEffect());
|
||||
getRightHalfCard().getSpellAbility().addEffect(new OpponentsCantCastChosenUntilNextTurnEffect());
|
||||
}
|
||||
|
||||
private FailureComply(final FailureComply card) {
|
||||
|
@ -53,45 +45,3 @@ public final class FailureComply extends SplitCard {
|
|||
return new FailureComply(this);
|
||||
}
|
||||
}
|
||||
|
||||
class ComplyCantCastEffect extends ContinuousRuleModifyingEffectImpl {
|
||||
|
||||
public ComplyCantCastEffect() {
|
||||
super(Duration.UntilYourNextTurn, Outcome.Benefit);
|
||||
staticText = "Until your next turn, your opponents can't cast spells with the chosen name";
|
||||
}
|
||||
|
||||
public ComplyCantCastEffect(final ComplyCantCastEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComplyCantCastEffect copy() {
|
||||
return new ComplyCantCastEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInfoMessage(Ability source, GameEvent event, Game game) {
|
||||
MageObject mageObject = game.getObject(source.getSourceId());
|
||||
String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY);
|
||||
if (mageObject != null && cardName != null) {
|
||||
return "You can't cast a card named " + cardName + " (" + mageObject.getIdName() + ").";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.CAST_SPELL_LATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY);
|
||||
if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) {
|
||||
MageObject object = game.getObject(event.getSourceId());
|
||||
return object != null && CardUtil.haveSameNames(object, cardName, game);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ public final class StrixhavenSchoolOfMages extends ExpansionSet {
|
|||
this.maxCardNumberInBooster = 275;
|
||||
|
||||
cards.add(new SetCardInfo("Academic Dispute", 91, Rarity.UNCOMMON, mage.cards.a.AcademicDispute.class));
|
||||
cards.add(new SetCardInfo("Academic Probation", 287, Rarity.RARE, mage.cards.a.AcademicProbation.class));
|
||||
cards.add(new SetCardInfo("Access Tunnel", 262, Rarity.UNCOMMON, mage.cards.a.AccessTunnel.class));
|
||||
cards.add(new SetCardInfo("Accomplished Alchemist", 119, Rarity.RARE, mage.cards.a.AccomplishedAlchemist.class));
|
||||
cards.add(new SetCardInfo("Aether Helix", 162, Rarity.UNCOMMON, mage.cards.a.AetherHelix.class));
|
||||
|
@ -42,6 +43,9 @@ public final class StrixhavenSchoolOfMages extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Archway Commons", 263, Rarity.COMMON, mage.cards.a.ArchwayCommons.class));
|
||||
cards.add(new SetCardInfo("Ardent Dustspeaker", 92, Rarity.UNCOMMON, mage.cards.a.ArdentDustspeaker.class));
|
||||
cards.add(new SetCardInfo("Arrogant Poet", 63, Rarity.COMMON, mage.cards.a.ArrogantPoet.class));
|
||||
cards.add(new SetCardInfo("Augmenter Pugilist", 147, Rarity.RARE, mage.cards.a.AugmenterPugilist.class));
|
||||
cards.add(new SetCardInfo("Baleful Mastery", 64, Rarity.RARE, mage.cards.b.BalefulMastery.class));
|
||||
cards.add(new SetCardInfo("Basic Conjuration", 120, Rarity.RARE, mage.cards.b.BasicConjuration.class));
|
||||
cards.add(new SetCardInfo("Bayou Groff", 121, Rarity.COMMON, mage.cards.b.BayouGroff.class));
|
||||
cards.add(new SetCardInfo("Beaming Defiance", 9, Rarity.COMMON, mage.cards.b.BeamingDefiance.class));
|
||||
cards.add(new SetCardInfo("Beledros Witherbloom", 163, Rarity.MYTHIC, mage.cards.b.BeledrosWitherbloom.class));
|
||||
|
@ -62,6 +66,7 @@ public final class StrixhavenSchoolOfMages extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Campus Guide", 252, Rarity.COMMON, mage.cards.c.CampusGuide.class));
|
||||
cards.add(new SetCardInfo("Charge Through", 124, Rarity.COMMON, mage.cards.c.ChargeThrough.class));
|
||||
cards.add(new SetCardInfo("Clever Lumimancer", 10, Rarity.UNCOMMON, mage.cards.c.CleverLumimancer.class));
|
||||
cards.add(new SetCardInfo("Closing Statement", 169, Rarity.UNCOMMON, mage.cards.c.ClosingStatement.class));
|
||||
cards.add(new SetCardInfo("Cogwork Archivist", 254, Rarity.COMMON, mage.cards.c.CogworkArchivist.class));
|
||||
cards.add(new SetCardInfo("Combat Professor", 11, Rarity.COMMON, mage.cards.c.CombatProfessor.class));
|
||||
cards.add(new SetCardInfo("Confront the Past", 67, Rarity.RARE, mage.cards.c.ConfrontThePast.class));
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
package org.mage.test.cards.single.stx;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author htrajan, JayDi85
|
||||
*/
|
||||
public class BalefulMasteryTest extends CardTestPlayerBase {
|
||||
|
||||
@Test
|
||||
public void test_BalefulMastery_NormalCost() {
|
||||
// You may pay {1}{B} rather than pay this spell's mana cost.
|
||||
// If the {1}{B} cost was paid, an opponent draws a card.
|
||||
// Exile target creature or planeswalker.
|
||||
addCard(Zone.HAND, playerA, "Baleful Mastery"); // {3}{B}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4);
|
||||
//
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Goblin Piker");
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Witchbane Orb");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Baleful Mastery", "Goblin Piker");
|
||||
setChoice(playerA, "No"); // use normal cost
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertHandCount(playerA, 0);
|
||||
assertHandCount(playerB, 0);
|
||||
assertExileCount(playerB, "Goblin Piker", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_BalefulMastery_AlternativeCost() {
|
||||
// You may pay {1}{B} rather than pay this spell's mana cost.
|
||||
// If the {1}{B} cost was paid, an opponent draws a card.
|
||||
// Exile target creature or planeswalker.
|
||||
addCard(Zone.HAND, playerA, "Baleful Mastery"); // {3}{B}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
|
||||
//
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Goblin Piker");
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Witchbane Orb");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Baleful Mastery", "Goblin Piker");
|
||||
setChoice(playerA, "Yes"); // use alternative cost
|
||||
addTarget(playerA, playerB); // select opponent
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertHandCount(playerA, 0);
|
||||
assertHandCount(playerB, 1); // +1 from cost's draw
|
||||
assertExileCount(playerB, "Goblin Piker", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_BalefulMastery_DoubleCast() {
|
||||
// You may pay {1}{B} rather than pay this spell's mana cost.
|
||||
// If the {1}{B} cost was paid, an opponent draws a card.
|
||||
// Exile target creature or planeswalker.
|
||||
addCard(Zone.HAND, playerA, "Baleful Mastery", 2);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2 + 4); // 1x normal, 1x alternative
|
||||
//
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Goblin Piker");
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears");
|
||||
|
||||
// cast 1 - alternative
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Baleful Mastery", "Goblin Piker");
|
||||
setChoice(playerA, "Yes"); // use alternative cost
|
||||
addTarget(playerA, playerB); // select opponent
|
||||
|
||||
// cast 2 - normal
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Baleful Mastery", "Grizzly Bears");
|
||||
setChoice(playerA, "No"); // normal cast
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertHandCount(playerA, 0);
|
||||
assertHandCount(playerB, 1);
|
||||
assertExileCount(playerB, "Goblin Piker", 1);
|
||||
assertExileCount(playerB, "Grizzly Bears", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_BalefulMastery_BlinkMustResetAlternativeCost() {
|
||||
addCustomEffect_ReturnFromAnyToHand(playerA);
|
||||
|
||||
// You may pay {1}{B} rather than pay this spell's mana cost.
|
||||
// If the {1}{B} cost was paid, an opponent draws a card.
|
||||
// Exile target creature or planeswalker.
|
||||
addCard(Zone.HAND, playerA, "Baleful Mastery"); // {3}{B}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2 + 4); // 1x normal, 1x alternative
|
||||
//
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Goblin Piker");
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears");
|
||||
|
||||
// cast 1 - with alternative
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Baleful Mastery", "Goblin Piker");
|
||||
setChoice(playerA, "Yes"); // use alternative cost
|
||||
addTarget(playerA, playerB); // select opponent
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkGraveyardCount("after cast 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Baleful Mastery", 1);
|
||||
checkHandCount("after cast 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 0);
|
||||
checkHandCount("after cast 1", 1, PhaseStep.PRECOMBAT_MAIN, playerB, 1); // +1 from cost's draw
|
||||
checkExileCount("after cast 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Goblin Piker", 1);
|
||||
checkExileCount("after cast 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears", 0);
|
||||
|
||||
// return to hand
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "return from graveyard");
|
||||
addTarget(playerA, "Baleful Mastery");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkHandCardCount("after return", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Baleful Mastery", 1);
|
||||
|
||||
// cast 2 - without alternative
|
||||
// possible bug: cost status can be found from previous object (e.g. it ask about opponent select, but must not)
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Baleful Mastery", "Grizzly Bears");
|
||||
setChoice(playerA, "No"); // do not use alternative cost
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkGraveyardCount("after cast 2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Baleful Mastery", 1);
|
||||
checkHandCount("after cast 2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 0);
|
||||
checkHandCount("after cast 2", 1, PhaseStep.PRECOMBAT_MAIN, playerB, 1); // no draws on cast 2
|
||||
checkExileCount("after cast 2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Goblin Piker", 1);
|
||||
checkExileCount("after cast 2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears", 1);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_BalefulMastery_CopyMustKeepAlternativeCost() {
|
||||
// You may pay {1}{B} rather than pay this spell's mana cost.
|
||||
// If the {1}{B} cost was paid, an opponent draws a card.
|
||||
// Exile target creature or planeswalker.
|
||||
addCard(Zone.HAND, playerA, "Baleful Mastery");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
|
||||
//
|
||||
// Copy target instant or sorcery spell. You may choose new targets for the copy.
|
||||
addCard(Zone.HAND, playerA, "Twincast"); // {U}{U}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
|
||||
//
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Goblin Piker");
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears");
|
||||
|
||||
// cast with alternative
|
||||
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {B}", 2);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Baleful Mastery", "Goblin Piker");
|
||||
setChoice(playerA, "Yes"); // use alternative cost
|
||||
// copy spell
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Twincast", "Cast Baleful Mastery", "Cast Baleful Mastery");
|
||||
setChoice(playerA, "Yes"); // change target
|
||||
addTarget(playerA, "Grizzly Bears"); // new target
|
||||
checkStackSize("before copy", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 2);
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA, true);
|
||||
checkStackSize("after copy", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 2);
|
||||
//
|
||||
// resolve copied spell
|
||||
// possible bug: alternative cost will be lost for copied spell, so no opponent selections
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA, true);
|
||||
addTarget(playerA, playerB); // select opponent
|
||||
checkStackSize("after copy resolve", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 1);
|
||||
// resolve original spell
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA, true);
|
||||
addTarget(playerA, playerB); // select opponent
|
||||
checkStackSize("after original resolve", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 0);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
}
|
|
@ -11,8 +11,11 @@ import mage.abilities.costs.mana.ManaCostsImpl;
|
|||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.DamageTargetEffect;
|
||||
import mage.abilities.effects.common.DestroyTargetEffect;
|
||||
import mage.abilities.effects.common.ReturnFromExileEffect;
|
||||
import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect;
|
||||
import mage.abilities.effects.common.cost.SpellsCostIncreasingAllEffect;
|
||||
import mage.abilities.effects.common.cost.SpellsCostReductionAllEffect;
|
||||
import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
@ -35,6 +38,9 @@ import mage.server.util.config.GamePlugin;
|
|||
import mage.server.util.config.Plugin;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetAnyTarget;
|
||||
import mage.target.common.TargetCardInExile;
|
||||
import mage.target.common.TargetCardInGraveyard;
|
||||
import mage.target.common.TargetCardInLibrary;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.Copier;
|
||||
import org.apache.log4j.Level;
|
||||
|
@ -484,6 +490,39 @@ public abstract class MageTestPlayerBase {
|
|||
ability
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return target card to hand that can be called by text "return from ..."
|
||||
*
|
||||
* @param controller
|
||||
*/
|
||||
protected void addCustomEffect_ReturnFromAnyToHand(TestPlayer controller) {
|
||||
// graveyard
|
||||
Ability ability = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect().setText("return from graveyard"), new ManaCostsImpl(""));
|
||||
ability.addTarget(new TargetCardInGraveyard(StaticFilters.FILTER_CARD));
|
||||
addCustomCardWithAbility(
|
||||
"return from graveyard for " + controller.getName(),
|
||||
controller,
|
||||
ability
|
||||
);
|
||||
|
||||
// exile
|
||||
ability = new SimpleActivatedAbility(new ReturnFromExileEffect(Zone.HAND).setText("return from exile"), new ManaCostsImpl(""));
|
||||
ability.addTarget(new TargetCardInExile(StaticFilters.FILTER_CARD));
|
||||
addCustomCardWithAbility(
|
||||
"return from exile for " + controller.getName(),
|
||||
controller,
|
||||
ability
|
||||
);
|
||||
|
||||
// library
|
||||
ability = new SimpleActivatedAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD)).setText("return from library"), new ManaCostsImpl(""));
|
||||
addCustomCardWithAbility(
|
||||
"return from library for " + controller.getName(),
|
||||
controller,
|
||||
ability
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// custom card with global abilities list to init (can contains abilities per card name)
|
||||
|
|
|
@ -586,6 +586,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
|||
*
|
||||
* @param player {@link Player} to remove all cards from hand.
|
||||
*/
|
||||
@Deprecated // TODO: remove, cause test games don't use starting draws
|
||||
public void removeAllCardsFromHand(TestPlayer player) {
|
||||
getCommands(player).put(Zone.HAND, "clear");
|
||||
}
|
||||
|
|
|
@ -15,19 +15,29 @@ import java.util.Locale;
|
|||
public class IsPhaseCondition implements Condition {
|
||||
|
||||
protected TurnPhase turnPhase;
|
||||
protected boolean yourTurn;
|
||||
|
||||
public IsPhaseCondition(TurnPhase turnPhase) {
|
||||
this(turnPhase, false);
|
||||
}
|
||||
|
||||
public IsPhaseCondition(TurnPhase turnPhase, boolean yourTurn) {
|
||||
this.turnPhase = turnPhase;
|
||||
this.yourTurn = yourTurn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return turnPhase == game.getTurn().getPhaseType();
|
||||
return turnPhase == game.getTurn().getPhaseType() && (!yourTurn || game.getActivePlayerId().equals(source.getControllerId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder("during ").append(turnPhase).toString().toLowerCase(Locale.ENGLISH);
|
||||
return new StringBuilder("during ")
|
||||
.append(yourTurn ? "your " : "")
|
||||
.append(turnPhase)
|
||||
.toString()
|
||||
.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.costs;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
|
@ -16,13 +15,15 @@ import mage.players.Player;
|
|||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.Iterator;
|
||||
import mage.MageObject;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class AlternativeCostSourceAbility extends StaticAbility implements AlternativeSourceCosts {
|
||||
|
||||
private static final String ALTERNATIVE_COST_ACTIVATION_KEY = "AlternativeCostActivated";
|
||||
|
||||
private Costs<AlternativeCost2> alternateCosts = new CostsImpl<>();
|
||||
protected Condition condition;
|
||||
protected String rule;
|
||||
|
@ -159,6 +160,9 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// save activated status
|
||||
game.getState().setValue(getActivatedKey(ability), Boolean.TRUE);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -169,6 +173,38 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter
|
|||
return isActivated(ability, game);
|
||||
}
|
||||
|
||||
private String getActivatedKey(Ability source) {
|
||||
return getActivatedKey(this.getOriginalId(), source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
||||
}
|
||||
|
||||
private static String getActivatedKey(UUID alternativeCostOriginalId, UUID sourceId, int sourceZCC) {
|
||||
// can't use sourceId cause copied cards are different...
|
||||
// TODO: enable sourceId after copy card fix (it must copy cards with all related game state values)
|
||||
return ALTERNATIVE_COST_ACTIVATION_KEY + "_" + alternativeCostOriginalId + "_" /*+ sourceId + "_"*/ + sourceZCC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search activated status of alternative cost.
|
||||
* <p>
|
||||
* If you need it on resolve then use current ZCC (on stack)
|
||||
* If you need it on battlefield then use previous ZCC (-1)
|
||||
*
|
||||
* @param game
|
||||
* @param source
|
||||
* @param alternativeCostOriginalId you must save originalId on card's creation
|
||||
* @param searchPrevZCC true on battlefield, false on stack
|
||||
* @return
|
||||
*/
|
||||
public static boolean getActivatedStatus(Game game, Ability source, UUID alternativeCostOriginalId, boolean searchPrevZCC) {
|
||||
String key = getActivatedKey(
|
||||
alternativeCostOriginalId,
|
||||
source.getSourceId(),
|
||||
source.getSourceObjectZoneChangeCounter() + (searchPrevZCC ? -1 : 0)
|
||||
);
|
||||
Boolean status = (Boolean) game.getState().getValue(key);
|
||||
return status != null && status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActivated(Ability source, Game game) {
|
||||
Costs<AlternativeCost2> alternativeCostsToCheck;
|
||||
|
|
|
@ -78,7 +78,7 @@ public class CopyEffect extends ContinuousEffectImpl {
|
|||
Permanent permanent = affectedObjectList.get(0).getPermanent(game);
|
||||
if (permanent == null) {
|
||||
permanent = (Permanent) game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD, source.getSourceObjectZoneChangeCounter());
|
||||
// As long as the permanent is still in the LKI continue to copy to get triggered abilities to TriggeredAbilites for dies events.
|
||||
// As long as the permanent is still in the LKI continue to copy to get triggered abilities to TriggeredAbilities for dies events.
|
||||
if (permanent == null) {
|
||||
discard();
|
||||
return false;
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
* This effect must be used in tandem with ChooseACardNameEffect
|
||||
*/
|
||||
public class OpponentsCantCastChosenUntilNextTurnEffect extends ContinuousRuleModifyingEffectImpl {
|
||||
|
||||
public OpponentsCantCastChosenUntilNextTurnEffect() {
|
||||
super(Duration.UntilYourNextTurn, Outcome.Benefit);
|
||||
staticText = "Until your next turn, your opponents can't cast spells with the chosen name";
|
||||
}
|
||||
|
||||
public OpponentsCantCastChosenUntilNextTurnEffect(final OpponentsCantCastChosenUntilNextTurnEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpponentsCantCastChosenUntilNextTurnEffect copy() {
|
||||
return new OpponentsCantCastChosenUntilNextTurnEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInfoMessage(Ability source, GameEvent event, Game game) {
|
||||
MageObject mageObject = game.getObject(source.getSourceId());
|
||||
String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY);
|
||||
if (mageObject != null && cardName != null) {
|
||||
return "You can't cast a card named " + cardName + " (" + mageObject.getIdName() + ").";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.CAST_SPELL_LATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY);
|
||||
if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) {
|
||||
MageObject object = game.getObject(event.getSourceId());
|
||||
return object != null && CardUtil.haveSameNames(object, cardName, game);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue