mirror of
https://github.com/correl/mage.git
synced 2024-11-14 19:19:32 +00:00
parent
dafd7f8e7c
commit
c3ce7898de
7 changed files with 179 additions and 25 deletions
57
Mage.Sets/src/mage/cards/s/SilverScrutiny.java
Normal file
57
Mage.Sets/src/mage/cards/s/SilverScrutiny.java
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package mage.cards.s;
|
||||||
|
|
||||||
|
import mage.MageObject;
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.common.CastAsThoughItHadFlashIfConditionAbility;
|
||||||
|
import mage.abilities.condition.Condition;
|
||||||
|
import mage.abilities.dynamicvalue.common.ManacostVariableValue;
|
||||||
|
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.stack.Spell;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author awjackson
|
||||||
|
*/
|
||||||
|
public final class SilverScrutiny extends CardImpl {
|
||||||
|
|
||||||
|
public SilverScrutiny(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{U}{U}");
|
||||||
|
|
||||||
|
// You may cast Silver Scrutiny as though it had flash if X is 3 or less.
|
||||||
|
this.addAbility(new CastAsThoughItHadFlashIfConditionAbility(
|
||||||
|
SilverScrutinyCondition.instance,
|
||||||
|
"You may cast {this} as though it had flash if X is 3 or less."
|
||||||
|
));
|
||||||
|
|
||||||
|
// Draw X cards.
|
||||||
|
this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(ManacostVariableValue.REGULAR));
|
||||||
|
}
|
||||||
|
|
||||||
|
private SilverScrutiny(final SilverScrutiny card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SilverScrutiny copy() {
|
||||||
|
return new SilverScrutiny(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SilverScrutinyCondition implements Condition {
|
||||||
|
instance;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Spell spell = game.getStack().getSpell(source.getSourceId());
|
||||||
|
if (spell == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return spell.getStackAbility().getManaCostsToPay().getX() < 4;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,11 @@
|
||||||
package mage.cards.t;
|
package mage.cards.t;
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.common.CastAsThoughItHadFlashIfConditionAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.condition.Condition;
|
import mage.abilities.condition.Condition;
|
||||||
import mage.abilities.condition.common.SourceTargetsPermanentCondition;
|
import mage.abilities.condition.common.SourceTargetsPermanentCondition;
|
||||||
import mage.abilities.decorator.ConditionalAsThoughEffect;
|
|
||||||
import mage.abilities.effects.common.AttachEffect;
|
import mage.abilities.effects.common.AttachEffect;
|
||||||
import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashSourceEffect;
|
|
||||||
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
|
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
|
||||||
import mage.abilities.keyword.EnchantAbility;
|
import mage.abilities.keyword.EnchantAbility;
|
||||||
import mage.abilities.keyword.IndestructibleAbility;
|
import mage.abilities.keyword.IndestructibleAbility;
|
||||||
|
@ -39,9 +38,9 @@ public final class TimelyWard extends CardImpl {
|
||||||
this.subtype.add(SubType.AURA);
|
this.subtype.add(SubType.AURA);
|
||||||
|
|
||||||
// You may cast this spell as though it had flash if it targets a commander.
|
// You may cast this spell as though it had flash if it targets a commander.
|
||||||
this.addAbility(new SimpleStaticAbility(Zone.ALL, new ConditionalAsThoughEffect(
|
this.addAbility(new CastAsThoughItHadFlashIfConditionAbility(condition,
|
||||||
new CastAsThoughItHadFlashSourceEffect(Duration.EndOfGame), condition
|
"You may cast this spell as though it had flash if it targets a commander."
|
||||||
).setText("you may cast this spell as though it had flash if it targets a commander")));
|
));
|
||||||
|
|
||||||
// Enchant creature
|
// Enchant creature
|
||||||
TargetPermanent auraTarget = new TargetCreaturePermanent();
|
TargetPermanent auraTarget = new TargetCreaturePermanent();
|
||||||
|
|
|
@ -223,6 +223,7 @@ public final class DominariaUnited extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Shivan Devastator", 143, Rarity.MYTHIC, mage.cards.s.ShivanDevastator.class));
|
cards.add(new SetCardInfo("Shivan Devastator", 143, Rarity.MYTHIC, mage.cards.s.ShivanDevastator.class));
|
||||||
cards.add(new SetCardInfo("Shivan Reef", 255, Rarity.RARE, mage.cards.s.ShivanReef.class));
|
cards.add(new SetCardInfo("Shivan Reef", 255, Rarity.RARE, mage.cards.s.ShivanReef.class));
|
||||||
cards.add(new SetCardInfo("Shore Up", 64, Rarity.COMMON, mage.cards.s.ShoreUp.class));
|
cards.add(new SetCardInfo("Shore Up", 64, Rarity.COMMON, mage.cards.s.ShoreUp.class));
|
||||||
|
cards.add(new SetCardInfo("Silver Scrutiny", 65, Rarity.RARE, mage.cards.s.SilverScrutiny.class));
|
||||||
cards.add(new SetCardInfo("Silverback Elder", 177, Rarity.MYTHIC, mage.cards.s.SilverbackElder.class));
|
cards.add(new SetCardInfo("Silverback Elder", 177, Rarity.MYTHIC, mage.cards.s.SilverbackElder.class));
|
||||||
cards.add(new SetCardInfo("Slimefoot's Survey", 178, Rarity.UNCOMMON, mage.cards.s.SlimefootsSurvey.class));
|
cards.add(new SetCardInfo("Slimefoot's Survey", 178, Rarity.UNCOMMON, mage.cards.s.SlimefootsSurvey.class));
|
||||||
cards.add(new SetCardInfo("Smash to Dust", 144, Rarity.COMMON, mage.cards.s.SmashToDust.class));
|
cards.add(new SetCardInfo("Smash to Dust", 144, Rarity.COMMON, mage.cards.s.SmashToDust.class));
|
||||||
|
|
|
@ -56,6 +56,7 @@ public class MeddlingMageTest extends CardTestPlayerBase {
|
||||||
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{2}, {T}:");
|
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{2}, {T}:");
|
||||||
setChoice(playerA, true); // create copy
|
setChoice(playerA, true); // create copy
|
||||||
setChoice(playerA, true); // cast copy
|
setChoice(playerA, true); // cast copy
|
||||||
|
addTarget(playerA, "Meddling Mage");
|
||||||
|
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
|
|
@ -309,15 +309,6 @@ public abstract class AbilityImpl implements Ability {
|
||||||
VariableManaCost variableManaCost = handleManaXCosts(game, noMana, controller);
|
VariableManaCost variableManaCost = handleManaXCosts(game, noMana, controller);
|
||||||
String announceString = handleOtherXCosts(game, controller);
|
String announceString = handleOtherXCosts(game, controller);
|
||||||
|
|
||||||
// For effects from cards like Void Winnower x costs have to be set
|
|
||||||
if (this.getAbilityType() == AbilityType.SPELL) {
|
|
||||||
GameEvent castEvent = GameEvent.getEvent(GameEvent.EventType.CAST_SPELL_LATE, this.getId(), this, getControllerId());
|
|
||||||
castEvent.setZone(game.getState().getZone(CardUtil.getMainCardId(game, sourceId)));
|
|
||||||
if (game.replaceEvent(castEvent, this)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handlePhyrexianManaCosts(game, controller);
|
handlePhyrexianManaCosts(game, controller);
|
||||||
|
|
||||||
/* 20130201 - 601.2b
|
/* 20130201 - 601.2b
|
||||||
|
@ -343,7 +334,7 @@ public abstract class AbilityImpl implements Ability {
|
||||||
for (UUID modeId : this.getModes().getSelectedModes()) {
|
for (UUID modeId : this.getModes().getSelectedModes()) {
|
||||||
this.getModes().setActiveMode(modeId);
|
this.getModes().setActiveMode(modeId);
|
||||||
|
|
||||||
//20121001 - 601.2c
|
// 20121001 - 601.2c
|
||||||
// 601.2c The player announces their choice of an appropriate player, object, or zone for
|
// 601.2c The player announces their choice of an appropriate player, object, or zone for
|
||||||
// each target the spell requires. A spell may require some targets only if an alternative or
|
// each target the spell requires. A spell may require some targets only if an alternative or
|
||||||
// additional cost (such as a buyback or kicker cost), or a particular mode, was chosen for it;
|
// additional cost (such as a buyback or kicker cost), or a particular mode, was chosen for it;
|
||||||
|
@ -376,6 +367,18 @@ public abstract class AbilityImpl implements Ability {
|
||||||
}
|
}
|
||||||
} // end modes
|
} // end modes
|
||||||
|
|
||||||
|
// 20220908 - 601.2e
|
||||||
|
// 601.2e The game checks to see if the proposed spell can legally be cast. If the proposed spell
|
||||||
|
// is illegal, the game returns to the moment before the casting of that spell was proposed
|
||||||
|
// (see rule 727, "Handling Illegal Actions").
|
||||||
|
if (this.getAbilityType() == AbilityType.SPELL) {
|
||||||
|
GameEvent castEvent = GameEvent.getEvent(GameEvent.EventType.CAST_SPELL_LATE, this.getId(), this, getControllerId());
|
||||||
|
castEvent.setZone(game.getState().getZone(CardUtil.getMainCardId(game, sourceId)));
|
||||||
|
if (game.replaceEvent(castEvent, this)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// this is a hack to prevent mana abilities with mana costs from causing endless loops - pay other costs first
|
// this is a hack to prevent mana abilities with mana costs from causing endless loops - pay other costs first
|
||||||
if (this instanceof ActivatedManaAbilityImpl && !costs.pay(this, game, this, controllerId, noMana, null)) {
|
if (this instanceof ActivatedManaAbilityImpl && !costs.pay(this, game, this, controllerId, noMana, null)) {
|
||||||
logger.debug("activate mana ability failed - non mana costs");
|
logger.debug("activate mana ability failed - non mana costs");
|
||||||
|
@ -437,7 +440,7 @@ public abstract class AbilityImpl implements Ability {
|
||||||
case MADNESS:
|
case MADNESS:
|
||||||
case DISTURB:
|
case DISTURB:
|
||||||
// from Snapcaster Mage:
|
// from Snapcaster Mage:
|
||||||
// If you cast a spell from a graveyard using its flashback ability, you can’t pay other alternative costs
|
// If you cast a spell from a graveyard using its flashback ability, you can't pay other alternative costs
|
||||||
// (such as that of Foil). (2018-12-07)
|
// (such as that of Foil). (2018-12-07)
|
||||||
canUseAlternativeCost = false;
|
canUseAlternativeCost = false;
|
||||||
// You may pay any optional additional costs the spell has, such as kicker costs. You must pay any
|
// You may pay any optional additional costs the spell has, such as kicker costs. You must pay any
|
||||||
|
@ -570,10 +573,10 @@ public abstract class AbilityImpl implements Ability {
|
||||||
protected VariableManaCost handleManaXCosts(Game game, boolean noMana, Player controller) {
|
protected VariableManaCost handleManaXCosts(Game game, boolean noMana, Player controller) {
|
||||||
// 20210723 - 601.2b
|
// 20210723 - 601.2b
|
||||||
// If the spell has alternative or additional costs that will
|
// If the spell has alternative or additional costs that will
|
||||||
// be paid as it’s being cast such as buyback or kicker costs (see rules 118.8 and 118.9),
|
// be paid as it's being cast such as buyback or kicker costs (see rules 118.8 and 118.9),
|
||||||
// the player announces their intentions to pay any or all of those costs (see rule 601.2f).
|
// the player announces their intentions to pay any or all of those costs (see rule 601.2f).
|
||||||
// A player can’t apply two alternative methods of casting or two alternative costs to a
|
// A player can't apply two alternative methods of casting or two alternative costs to a
|
||||||
// single spell. If the spell has a variable cost that will be paid as it’s being cast
|
// single spell. If the spell has a variable cost that will be paid as it's being cast
|
||||||
// (such as an {X} in its mana cost; see rule 107.3), the player announces the value of that
|
// (such as an {X} in its mana cost; see rule 107.3), the player announces the value of that
|
||||||
// variable. If the value of that variable is defined in the text of the spell by a choice
|
// variable. If the value of that variable is defined in the text of the spell by a choice
|
||||||
// that player would make later in the announcement or resolution of the spell, that player
|
// that player would make later in the announcement or resolution of the spell, that player
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
package mage.abilities.common;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.condition.Condition;
|
||||||
|
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||||
|
import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashSourceEffect;
|
||||||
|
import mage.constants.Duration;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.events.GameEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements:
|
||||||
|
* You may cast {this} as though it had flash if [condition that depends on X value, targets, etc.]
|
||||||
|
*
|
||||||
|
* @author awjackson
|
||||||
|
*/
|
||||||
|
public class CastAsThoughItHadFlashIfConditionAbility extends SimpleStaticAbility {
|
||||||
|
|
||||||
|
private final String rule;
|
||||||
|
|
||||||
|
public CastAsThoughItHadFlashIfConditionAbility(Condition condition, String rule) {
|
||||||
|
super(Zone.ALL, new CastAsThoughItHadFlashSourceEffect(Duration.EndOfGame));
|
||||||
|
this.addEffect(new CantFlashUnlessConditionEffect(condition));
|
||||||
|
this.setRuleAtTheTop(true);
|
||||||
|
this.rule = rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CastAsThoughItHadFlashIfConditionAbility(final CastAsThoughItHadFlashIfConditionAbility ability) {
|
||||||
|
super(ability);
|
||||||
|
this.rule = ability.rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CastAsThoughItHadFlashIfConditionAbility copy() {
|
||||||
|
return new CastAsThoughItHadFlashIfConditionAbility(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRule() {
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CantFlashUnlessConditionEffect extends ContinuousRuleModifyingEffectImpl {
|
||||||
|
|
||||||
|
private final Condition condition;
|
||||||
|
|
||||||
|
public CantFlashUnlessConditionEffect(Condition condition) {
|
||||||
|
super(Duration.EndOfGame, Outcome.Neutral);
|
||||||
|
this.condition = condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CantFlashUnlessConditionEffect(final CantFlashUnlessConditionEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
this.condition = effect.condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CantFlashUnlessConditionEffect copy() {
|
||||||
|
return new CantFlashUnlessConditionEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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) {
|
||||||
|
if (!event.getSourceId().equals(source.getSourceId())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// the condition can't be evaluated until the spell is on the stack
|
||||||
|
if (game.inCheckPlayableState()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// ignore if casting as a sorcery
|
||||||
|
if (game.isMainPhase() && game.isActivePlayer(event.getPlayerId()) && game.getStack().size() == 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// TODO: this is a hack and doesn't handle all other ways a spell could be cast as though it had flash
|
||||||
|
if (Boolean.TRUE.equals(game.getState().getValue("PlayFromNotOwnHandZone" + source.getSourceId()))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !condition.apply(game, source);
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,14 +38,18 @@ public class SacrificeIfCastAtInstantTimeTriggeredAbility extends TriggeredAbili
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
// The sacrifice occurs only if you cast it using its own ability. If you cast it using some other
|
// TODO: The sacrifice should occur only if you cast it using its own ability. If you cast it using some
|
||||||
// effect (for instance, if it gained flash from Vedalken Orrery), then it won't be sacrificed.
|
// other effect (for instance, if it gained flash from Vedalken Orrery), then it shouldn't be sacrificed.
|
||||||
// CHECK
|
// see https://github.com/magefree/mage/issues/9512
|
||||||
Spell spell = game.getStack().getSpell(event.getTargetId());
|
Spell spell = game.getStack().getSpell(event.getTargetId());
|
||||||
if (spell != null && spell.getSourceId().equals(getSourceId())) {
|
if (spell == null || !spell.getSourceId().equals(getSourceId())) {
|
||||||
return !(game.isMainPhase() && game.isActivePlayer(event.getPlayerId()) && game.getStack().size() == 1);
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
// TODO: this is a hack and doesn't handle all other ways a spell could be cast as though it had flash
|
||||||
|
if (Boolean.TRUE.equals(game.getState().getValue("PlayFromNotOwnHandZone" + getSourceId()))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !(game.isMainPhase() && game.isActivePlayer(event.getPlayerId()) && game.getStack().size() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in a new issue