diff --git a/Mage.Sets/src/mage/cards/f/FocusTheMind.java b/Mage.Sets/src/mage/cards/f/FocusTheMind.java new file mode 100644 index 00000000000..cdce75924b6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FocusTheMind.java @@ -0,0 +1,44 @@ +package mage.cards.f; + +import java.util.UUID; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CastAnotherSpellThisTurnCondition; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; + +/** + * + * @author Jmlundeen + */ +public final class FocusTheMind extends CardImpl { + + public FocusTheMind(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{U}"); + + + // This spell costs {2} less to cast if you've cast another spell this turn. + Effect effect = new SpellCostReductionSourceEffect(2, CastAnotherSpellThisTurnCondition.instance) + .setCanWorksOnStackOnly(true); + this.addAbility(new SimpleStaticAbility(Zone.ALL, effect) + .setRuleAtTheTop(true) + .addHint(CastAnotherSpellThisTurnCondition.instance.getHint())); + + // Draw three cards, then discard a card. + this.getSpellAbility().addEffect(new DrawDiscardControllerEffect(3, 1)); + } + + private FocusTheMind(final FocusTheMind card) { + super(card); + } + + @Override + public FocusTheMind copy() { + return new FocusTheMind(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RallyTheMonastery.java b/Mage.Sets/src/mage/cards/r/RallyTheMonastery.java index 335b01cee14..7867c2c0c48 100644 --- a/Mage.Sets/src/mage/cards/r/RallyTheMonastery.java +++ b/Mage.Sets/src/mage/cards/r/RallyTheMonastery.java @@ -1,19 +1,14 @@ package mage.cards.r; -import java.util.List; -import java.util.Objects; import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CastAnotherSpellThisTurnCondition; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; -import mage.abilities.hint.ConditionHint; -import mage.abilities.hint.Hint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -22,23 +17,15 @@ import mage.constants.Zone; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; -import mage.game.Game; -import mage.game.permanent.token.BirdToken; import mage.game.permanent.token.MonasteryMentorToken; -import mage.game.stack.Spell; import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; -import mage.watchers.common.SpellsCastWatcher; /** * @author balazskristof */ public final class RallyTheMonastery extends CardImpl { - private static final Hint hint = new ConditionHint( - RallyTheMonasteryCondition.instance, "You've cast a spell this turn" - ); - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with power 4 or greater"); static { @@ -51,8 +38,8 @@ public final class RallyTheMonastery extends CardImpl { // This spell costs {2} less to cast if you've cast another spell this turn. this.addAbility(new SimpleStaticAbility( Zone.ALL, - new SpellCostReductionSourceEffect(2, RallyTheMonasteryCondition.instance).setCanWorksOnStackOnly(true) - ).setRuleAtTheTop(true).addHint(hint)); + new SpellCostReductionSourceEffect(2, CastAnotherSpellThisTurnCondition.instance).setCanWorksOnStackOnly(true) + ).setRuleAtTheTop(true).addHint(CastAnotherSpellThisTurnCondition.instance.getHint())); // Choose one — this.getSpellAbility().getModes().setMinModes(1); @@ -79,25 +66,3 @@ public final class RallyTheMonastery extends CardImpl { } } -enum RallyTheMonasteryCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); - if (watcher == null) { - return false; - } - List spells = watcher.getSpellsCastThisTurn(source.getControllerId()); - return spells != null && spells - .stream() - .filter(Objects::nonNull) - .anyMatch(spell -> !spell.getSourceId().equals(source.getSourceId())); - } - - @Override - public String toString() { - return "you've cast another spell this turn"; - } -} - diff --git a/Mage.Sets/src/mage/cards/s/SageOfTheSkies.java b/Mage.Sets/src/mage/cards/s/SageOfTheSkies.java new file mode 100644 index 00000000000..f39973e8f30 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SageOfTheSkies.java @@ -0,0 +1,54 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.condition.common.CastAnotherSpellThisTurnCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CastSourceTriggeredAbility; +import mage.abilities.effects.common.CopySourceSpellEffect; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author Jmlundeen + */ +public final class SageOfTheSkies extends CardImpl { + + public SageOfTheSkies(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MONK); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // When you cast this spell, if you've cast another spell this turn, copy this spell. + OneShotEffect effect = new CopySourceSpellEffect().setText("copy this spell. (The copy becomes a token.)"); + this.addAbility(new CastSourceTriggeredAbility(effect) + .withInterveningIf(CastAnotherSpellThisTurnCondition.instance) + .addHint(CastAnotherSpellThisTurnCondition.instance.getHint()) + ); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + } + + private SageOfTheSkies(final SageOfTheSkies card) { + super(card); + } + + @Override + public SageOfTheSkies copy() { + return new SageOfTheSkies(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SlickSequence.java b/Mage.Sets/src/mage/cards/s/SlickSequence.java index 4c5d96c7bd0..852d441cf0c 100644 --- a/Mage.Sets/src/mage/cards/s/SlickSequence.java +++ b/Mage.Sets/src/mage/cards/s/SlickSequence.java @@ -1,22 +1,13 @@ package mage.cards.s; -import mage.MageObjectReference; -import mage.abilities.Ability; -import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CastAnotherSpellThisTurnCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.hint.ConditionHint; -import mage.abilities.hint.Hint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.WatcherScope; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.stack.Spell; import mage.target.common.TargetAnyTarget; -import mage.watchers.Watcher; import java.util.*; @@ -34,11 +25,10 @@ public final class SlickSequence extends CardImpl { this.getSpellAbility().addEffect( new ConditionalOneShotEffect( new DrawCardSourceControllerEffect(1), - SlickSequenceCondition.instance + CastAnotherSpellThisTurnCondition.instance ) ); - this.getSpellAbility().addHint(SlickSequenceCondition.hint); - this.getSpellAbility().addWatcher(new SlickSequenceWatcher()); + this.getSpellAbility().addHint(CastAnotherSpellThisTurnCondition.instance.getHint()); } private SlickSequence(final SlickSequence card) { @@ -49,68 +39,4 @@ public final class SlickSequence extends CardImpl { public SlickSequence copy() { return new SlickSequence(this); } -} - - -enum SlickSequenceCondition implements Condition { - instance; - static final Hint hint = new ConditionHint(instance, "you've cast another spell this turn"); - - @Override - public boolean apply(Game game, Ability source) { - SlickSequenceWatcher watcher = game.getState().getWatcher(SlickSequenceWatcher.class); - if (watcher == null) { - return false; - } - // may be null, watcher will handle that. - Spell sourceSpell = game.getSpell(source.getSourceId()); - return watcher.didPlayerCastAnotherSpellThisTurn(source.getControllerId(), sourceSpell, game); - } - - @Override - public String toString() { - return "you've cast another spell this turn"; - } -} - -class SlickSequenceWatcher extends Watcher { - - // Per player, MOR of the spells cast this turn. - private final Map> spellsCastThisTurn = new HashMap<>(); - - /** - * Game default watcher - */ - public SlickSequenceWatcher() { - super(WatcherScope.GAME); - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.SPELL_CAST) { - UUID playerId = event.getPlayerId(); - if (playerId != null) { - MageObjectReference mor = new MageObjectReference(event.getTargetId(), game); - spellsCastThisTurn.computeIfAbsent(playerId, x -> new HashSet<>()).add(mor); - } - } - } - - @Override - public void reset() { - super.reset(); - spellsCastThisTurn.clear(); - } - - boolean didPlayerCastAnotherSpellThisTurn(UUID playerId, Spell spell, Game game) { - Set spells = spellsCastThisTurn.getOrDefault(playerId, new HashSet<>()); - if (spell == null) { - // Not currently a spell, so any spell recorded does count as another. - return !spells.isEmpty(); - } else { - // Is currently a spell, so need to exclude that one. - MageObjectReference spellMOR = new MageObjectReference(spell.getId(), game); - return spells.stream().anyMatch(mor -> !mor.equals(spellMOR)); - } - } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index c5b32875aef..f00f98c0d99 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -107,6 +107,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Fire-Rim Form", 107, Rarity.COMMON, mage.cards.f.FireRimForm.class)); cards.add(new SetCardInfo("Flamehold Grappler", 185, Rarity.RARE, mage.cards.f.FlameholdGrappler.class)); cards.add(new SetCardInfo("Fleeting Effigy", 108, Rarity.UNCOMMON, mage.cards.f.FleetingEffigy.class)); + cards.add(new SetCardInfo("Focus the Mind", 45, Rarity.COMMON, mage.cards.f.FocusTheMind.class)); cards.add(new SetCardInfo("Forest", 285, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Formation Breaker", 143, Rarity.UNCOMMON, mage.cards.f.FormationBreaker.class)); cards.add(new SetCardInfo("Fortress Kin-Guard", 12, Rarity.COMMON, mage.cards.f.FortressKinGuard.class)); @@ -205,6 +206,8 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Rugged Highlands", 265, Rarity.COMMON, mage.cards.r.RuggedHighlands.class)); cards.add(new SetCardInfo("Runescale Stormbrood", 221, Rarity.UNCOMMON, mage.cards.r.RunescaleStormbrood.class)); cards.add(new SetCardInfo("Sage of the Fang", 155, Rarity.UNCOMMON, mage.cards.s.SageOfTheFang.class)); + cards.add(new SetCardInfo("Sage of the Skies", 22, Rarity.RARE, mage.cards.s.SageOfTheSkies.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sage of the Skies", 328, Rarity.RARE, mage.cards.s.SageOfTheSkies.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sagu Pummeler", 156, Rarity.COMMON, mage.cards.s.SaguPummeler.class)); cards.add(new SetCardInfo("Sagu Wildling", 157, Rarity.COMMON, mage.cards.s.SaguWildling.class)); cards.add(new SetCardInfo("Salt Road Packbeast", 23, Rarity.COMMON, mage.cards.s.SaltRoadPackbeast.class)); diff --git a/Mage/src/main/java/mage/abilities/condition/common/CastAnotherSpellThisTurnCondition.java b/Mage/src/main/java/mage/abilities/condition/common/CastAnotherSpellThisTurnCondition.java new file mode 100644 index 00000000000..10ee9bdd27f --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/CastAnotherSpellThisTurnCondition.java @@ -0,0 +1,44 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.watchers.common.SpellsCastWatcher; + +import java.util.List; +import java.util.Objects; + +/** + * @author balazskristof, Jmlundeen + */ +public enum CastAnotherSpellThisTurnCondition implements Condition { + instance; + private final Hint hint = new ConditionHint( + this, "You've cast another spell this turn" + ); + + @Override + public boolean apply(Game game, Ability source) { + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); + if (watcher == null) { + return false; + } + List spells = watcher.getSpellsCastThisTurn(source.getControllerId()); + return spells != null && spells + .stream() + .filter(Objects::nonNull) + .anyMatch(spell -> !spell.getSourceId().equals(source.getSourceId()) || spell.getZoneChangeCounter(game) != source.getSourceObjectZoneChangeCounter()); + } + + public Hint getHint() { + return hint; + } + + @Override + public String toString() { + return "you've cast another spell this turn"; + } +}