mirror of
https://github.com/magefree/mage.git
synced 2025-12-21 19:11:59 -08:00
[BLC] Implement Fortune Teller's Talent (#12608)
* Implement Fortune Teller's Talent * Remove outdated assert from PlayFromTopOfLibraryEffect and update comment
This commit is contained in:
parent
8ed3c0c12d
commit
ee3cab84ef
4 changed files with 185 additions and 6 deletions
95
Mage.Sets/src/mage/cards/f/FortuneTellersTalent.java
Normal file
95
Mage.Sets/src/mage/cards/f/FortuneTellersTalent.java
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
package mage.cards.f;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
|
import mage.abilities.condition.Condition;
|
||||||
|
import mage.abilities.decorator.ConditionalAsThoughEffect;
|
||||||
|
import mage.abilities.effects.Effect;
|
||||||
|
import mage.abilities.effects.common.continuous.GainClassAbilitySourceEffect;
|
||||||
|
import mage.abilities.effects.common.continuous.LookAtTopCardOfLibraryAnyTimeEffect;
|
||||||
|
import mage.abilities.effects.common.continuous.PlayFromTopOfLibraryEffect;
|
||||||
|
import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect;
|
||||||
|
import mage.abilities.keyword.ClassLevelAbility;
|
||||||
|
import mage.abilities.keyword.ClassReminderAbility;
|
||||||
|
import mage.constants.SubType;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.filter.FilterCard;
|
||||||
|
import mage.filter.predicate.other.SpellCastFromAnywhereOtherThanHand;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.stack.Spell;
|
||||||
|
import mage.watchers.common.SpellsCastWatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jimga150
|
||||||
|
*/
|
||||||
|
public final class FortuneTellersTalent extends CardImpl {
|
||||||
|
|
||||||
|
private static final FilterCard nonHandSpellFilter = new FilterCard("Spells you cast from anywhere other than your hand");
|
||||||
|
|
||||||
|
static {
|
||||||
|
nonHandSpellFilter.add(SpellCastFromAnywhereOtherThanHand.instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FortuneTellersTalent(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}");
|
||||||
|
|
||||||
|
this.subtype.add(SubType.CLASS);
|
||||||
|
|
||||||
|
// (Gain the next level as a sorcery to add its ability.)
|
||||||
|
this.addAbility(new ClassReminderAbility());
|
||||||
|
|
||||||
|
// You may look at the top card of your library any time.
|
||||||
|
this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect()));
|
||||||
|
|
||||||
|
// {3}{U}: Level 2
|
||||||
|
this.addAbility(new ClassLevelAbility(2, "{3}{U}"));
|
||||||
|
|
||||||
|
// As long as you've cast a spell this turn, you may play cards from the top of your library.
|
||||||
|
Effect lv2Effect = new ConditionalAsThoughEffect(
|
||||||
|
new PlayFromTopOfLibraryEffect(),
|
||||||
|
FortuneTellersTalentCondition.instance
|
||||||
|
);
|
||||||
|
lv2Effect.setText("As long as you've cast a spell this turn, you may play cards from the top of your library.");
|
||||||
|
this.addAbility(new SimpleStaticAbility(new GainClassAbilitySourceEffect(new SimpleStaticAbility(lv2Effect), 2)));
|
||||||
|
|
||||||
|
// {2}{U}: Level 3
|
||||||
|
this.addAbility(new ClassLevelAbility(3, "{2}{U}"));
|
||||||
|
|
||||||
|
// Spells you cast from anywhere other than your hand cost {2} less to cast.
|
||||||
|
Ability lv3Ability = new SimpleStaticAbility(new SpellsCostReductionControllerEffect(nonHandSpellFilter, 2));
|
||||||
|
this.addAbility(new SimpleStaticAbility(new GainClassAbilitySourceEffect(lv3Ability, 3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private FortuneTellersTalent(final FortuneTellersTalent card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FortuneTellersTalent copy() {
|
||||||
|
return new FortuneTellersTalent(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Based on LeapfrogCondition
|
||||||
|
enum FortuneTellersTalentCondition implements Condition {
|
||||||
|
instance;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class);
|
||||||
|
if (watcher == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
List<Spell> spells = watcher.getSpellsCastThisTurn(source.getControllerId());
|
||||||
|
return spells != null && spells
|
||||||
|
.stream()
|
||||||
|
.anyMatch(Objects::nonNull);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -104,6 +104,7 @@ public final class BloomburrowCommander extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Flubs, the Fool", 356, Rarity.MYTHIC, mage.cards.f.FlubsTheFool.class));
|
cards.add(new SetCardInfo("Flubs, the Fool", 356, Rarity.MYTHIC, mage.cards.f.FlubsTheFool.class));
|
||||||
cards.add(new SetCardInfo("Forgotten Ancient", 217, Rarity.RARE, mage.cards.f.ForgottenAncient.class));
|
cards.add(new SetCardInfo("Forgotten Ancient", 217, Rarity.RARE, mage.cards.f.ForgottenAncient.class));
|
||||||
cards.add(new SetCardInfo("Forgotten Cave", 305, Rarity.COMMON, mage.cards.f.ForgottenCave.class));
|
cards.add(new SetCardInfo("Forgotten Cave", 305, Rarity.COMMON, mage.cards.f.ForgottenCave.class));
|
||||||
|
cards.add(new SetCardInfo("Fortune Teller's Talent", 14, Rarity.RARE, mage.cards.f.FortuneTellersTalent.class));
|
||||||
cards.add(new SetCardInfo("Game Trail", 306, Rarity.RARE, mage.cards.g.GameTrail.class));
|
cards.add(new SetCardInfo("Game Trail", 306, Rarity.RARE, mage.cards.g.GameTrail.class));
|
||||||
cards.add(new SetCardInfo("Garruk's Packleader", 218, Rarity.UNCOMMON, mage.cards.g.GarruksPackleader.class));
|
cards.add(new SetCardInfo("Garruk's Packleader", 218, Rarity.UNCOMMON, mage.cards.g.GarruksPackleader.class));
|
||||||
cards.add(new SetCardInfo("Garruk's Uprising", 219, Rarity.UNCOMMON, mage.cards.g.GarruksUprising.class));
|
cards.add(new SetCardInfo("Garruk's Uprising", 219, Rarity.UNCOMMON, mage.cards.g.GarruksUprising.class));
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
package org.mage.test.cards.single.blc;
|
||||||
|
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Susucr
|
||||||
|
*/
|
||||||
|
public class FortuneTellersTalentTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link mage.cards.f.FortuneTellersTalent Fortune Teller's Talent} {U}
|
||||||
|
* Enchantment — Class
|
||||||
|
* You may look at the top card of your library any time.
|
||||||
|
* {3}{U}: Level 2
|
||||||
|
* As long as you’ve cast a spell this turn, you may play cards from the top of your library.
|
||||||
|
* {2}{U}: Level 3
|
||||||
|
* Spells you cast from anywhere other than your hand cost {2} less to cast.
|
||||||
|
*/
|
||||||
|
private static final String fortuneTeller = "Fortune Teller's Talent";
|
||||||
|
|
||||||
|
private void assertClassLevel(String cardName, int level) {
|
||||||
|
Permanent permanent = getPermanent(cardName);
|
||||||
|
Assert.assertEquals(
|
||||||
|
cardName + " should be level " + level +
|
||||||
|
" but was level " + permanent.getClassLevel(),
|
||||||
|
level, permanent.getClassLevel()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_PlayFromLibrary() {
|
||||||
|
skipInitShuffling();
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 14);
|
||||||
|
// {3}{U}: Instant: Return all attacking creatures to their owner’s hand.
|
||||||
|
addCard(Zone.LIBRARY, playerA, "Aetherize", 4);
|
||||||
|
addCard(Zone.HAND, playerA, fortuneTeller);
|
||||||
|
|
||||||
|
int islandsUsed = 0;
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, fortuneTeller, true);
|
||||||
|
islandsUsed++;
|
||||||
|
|
||||||
|
// checkPermanentTapped("Used " + islandsUsed + " Islands", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Island", true, islandsUsed);
|
||||||
|
|
||||||
|
// Level 2: As long as you’ve cast a spell this turn, you may play cards from the top of your library.
|
||||||
|
// (Fortune Teller counts)
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}{U}");
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||||
|
islandsUsed += 4;
|
||||||
|
|
||||||
|
checkPermanentTapped("Used " + islandsUsed + " Islands", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Island", true, islandsUsed);
|
||||||
|
|
||||||
|
checkHandCardCount("not in hand", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Aetherize", 0);
|
||||||
|
checkPlayableAbility("from library", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Aetherize", true);
|
||||||
|
//This will cast from the top of the library
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Aetherize", true);
|
||||||
|
islandsUsed += 4;
|
||||||
|
|
||||||
|
checkPermanentTapped("Used " + islandsUsed + " Islands", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Island", true, islandsUsed);
|
||||||
|
|
||||||
|
// Level 3: Spells you cast from anywhere other than your hand cost {2} less to cast.
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}{U}");
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||||
|
islandsUsed += 3;
|
||||||
|
|
||||||
|
checkHandCardCount("not in hand", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Aetherize", 0);
|
||||||
|
checkPlayableAbility("from library", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Aetherize", true);
|
||||||
|
//This will cast from the top of the library
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Aetherize", true);
|
||||||
|
islandsUsed += 2; // Should have had cost reduced by 2
|
||||||
|
|
||||||
|
checkPermanentTapped("Used " + islandsUsed + " Islands", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Island", true, islandsUsed);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertClassLevel(fortuneTeller, 3);
|
||||||
|
assertLibraryCount(playerA, "Aetherize", 2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -31,17 +31,12 @@ public class PlayFromTopOfLibraryEffect extends AsThoughEffectImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* You may [play lands and/or cast spells, according to filter] from the top of your library
|
* You may [play lands/cast spells/play cards, according to filter] from the top of your library
|
||||||
*/
|
*/
|
||||||
public PlayFromTopOfLibraryEffect(FilterCard filter) {
|
public PlayFromTopOfLibraryEffect(FilterCard filter) {
|
||||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit);
|
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit);
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
this.staticText = "you may " + filter.getMessage() + " from the top of your library";
|
this.staticText = "you may " + filter.getMessage() + " from the top of your library";
|
||||||
|
|
||||||
// verify check: this ability is to allow playing lands or casting spells, not playing a "card"
|
|
||||||
if (filter.getMessage().toLowerCase(Locale.ENGLISH).contains("card")) {
|
|
||||||
throw new IllegalArgumentException("Wrong code usage or wrong filter text: PlayTheTopCardEffect");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected PlayFromTopOfLibraryEffect(final PlayFromTopOfLibraryEffect effect) {
|
protected PlayFromTopOfLibraryEffect(final PlayFromTopOfLibraryEffect effect) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue