implement [MH3] Tamiyo Inquisitive Student // Tamiyo, Seasoned Scholar

This commit is contained in:
Susucre 2024-05-22 21:43:07 +02:00
parent 833ecff409
commit 8002cdf88f
9 changed files with 397 additions and 62 deletions

View file

@ -1,14 +1,10 @@
package mage.cards.b;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.dynamicvalue.common.CardsInControllerLibraryCount;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.game.Game;
import mage.game.permanent.token.FractalToken;
import mage.players.Player;
import java.util.UUID;
@ -22,7 +18,7 @@ public final class BodyOfResearch extends CardImpl {
// Create a 0/0 green and blue Fractal creature token. Put X +1/+1 counters on it, where X is the number of cards in your library.
this.getSpellAbility().addEffect(FractalToken.getEffect(
BodyOfResearchValue.instance, "Put X +1/+1 counters on it, " +
CardsInControllerLibraryCount.instance, "Put X +1/+1 counters on it, " +
"where X is the number of cards in your library"
));
}
@ -35,24 +31,4 @@ public final class BodyOfResearch extends CardImpl {
public BodyOfResearch copy() {
return new BodyOfResearch(this);
}
}
enum BodyOfResearchValue implements DynamicValue {
instance;
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
Player player = game.getPlayer(sourceAbility.getControllerId());
return player != null ? player.getLibrary().size() : 0;
}
@Override
public BodyOfResearchValue copy() {
return instance;
}
@Override
public String getMessage() {
return "";
}
}
}

View file

@ -1,10 +1,8 @@
package mage.cards.e;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.dynamicvalue.common.CardsInControllerLibraryCount;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect;
@ -21,17 +19,18 @@ import mage.game.turn.Step;
import mage.players.Player;
import mage.target.common.TargetCardInHand;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class EnterTheInfinite extends CardImpl {
public EnterTheInfinite(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{8}{U}{U}{U}{U}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{8}{U}{U}{U}{U}");
// Draw cards equal to the number of cards in your library,
this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(new CardsInControllerLibraryCount()));
this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(CardsInControllerLibraryCount.instance));
//then put a card from your hand on top of your library.
this.getSpellAbility().addEffect(new PutCardOnLibraryEffect());
//You have no maximum hand size until your next turn.
@ -48,35 +47,6 @@ public final class EnterTheInfinite extends CardImpl {
}
}
class CardsInControllerLibraryCount implements DynamicValue {
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
if (sourceAbility != null) {
Player controller = game.getPlayer(sourceAbility.getControllerId());
if (controller != null) {
return controller.getLibrary().size();
}
}
return 0;
}
@Override
public CardsInControllerLibraryCount copy() {
return new CardsInControllerLibraryCount();
}
@Override
public String getMessage() {
return "card in your library";
}
@Override
public String toString() {
return "1";
}
}
class PutCardOnLibraryEffect extends OneShotEffect {
PutCardOnLibraryEffect() {

View file

@ -0,0 +1,58 @@
package mage.cards.t;
import mage.MageInt;
import mage.abilities.Pronoun;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.DrawNthCardTriggeredAbility;
import mage.abilities.effects.common.ExileAndReturnSourceEffect;
import mage.abilities.effects.keyword.InvestigateEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.PutCards;
import mage.constants.SubType;
import mage.constants.SuperType;
import java.util.UUID;
/**
* @author Susucr
*/
public final class TamiyoInquisitiveStudent extends CardImpl {
public TamiyoInquisitiveStudent(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.MOONFOLK);
this.subtype.add(SubType.WIZARD);
this.power = new MageInt(0);
this.toughness = new MageInt(3);
this.secondSideCardClazz = TamiyoSeasonedScholar.class;
// Flying
this.addAbility(FlyingAbility.getInstance());
// Whenever Tamiyo, Inquisitive Student attacks, investigate.
this.addAbility(new AttacksTriggeredAbility(new InvestigateEffect()));
// When you draw your third card in a turn, exile Tamiyo, then return her to the battlefield transformed under her owner's control.
this.addAbility(new TransformAbility());
this.addAbility(new DrawNthCardTriggeredAbility(
new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.SHE),
false, 3
));
}
private TamiyoInquisitiveStudent(final TamiyoInquisitiveStudent card) {
super(card);
}
@Override
public TamiyoInquisitiveStudent copy() {
return new TamiyoInquisitiveStudent(this);
}
}

View file

@ -0,0 +1,111 @@
package mage.cards.t;
import mage.abilities.Ability;
import mage.abilities.LoyaltyAbility;
import mage.abilities.common.AttacksAllTriggeredAbility;
import mage.abilities.common.delayed.UntilYourNextTurnDelayedTriggeredAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.CardsInControllerLibraryCount;
import mage.abilities.dynamicvalue.common.HalfValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.GetEmblemEffect;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.mana.AddManaOfAnyColorEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.command.emblems.TamiyoSeasonedScholarEmblem;
import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID;
/**
* @author Susucr
*/
public final class TamiyoSeasonedScholar extends CardImpl {
private static final DynamicValue xValue = new HalfValue(CardsInControllerLibraryCount.instance, true);
public TamiyoSeasonedScholar(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.TAMIYO);
this.setStartingLoyalty(2);
this.color.setGreen(true);
this.color.setBlue(true);
this.nightCard = true;
// +2: Until your next turn, whenever a creature attacks you or a planeswalker you control, it gets -1/-0 until end of turn.
this.addAbility(new LoyaltyAbility(new CreateDelayedTriggeredAbilityEffect(
new UntilYourNextTurnDelayedTriggeredAbility(
new AttacksAllTriggeredAbility(
new BoostTargetEffect(-1, 0, Duration.EndOfTurn)
.setText("it gets -1/-0 until end of turn"),
false, StaticFilters.FILTER_OPPONENTS_PERMANENT_A_CREATURE,
SetTargetPointer.PERMANENT, true
)
)
), 2));
// -3: Return target instant or sorcery card from your graveyard to your hand. If it's a green card, add one mana of any color.
Ability ability = new LoyaltyAbility(new TamiyoSeasonedScholarMinus3Effect(), -3);
ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD));
this.addAbility(ability);
// -7: Draw cards equal to half the number of cards in your library, rounded up. You get an emblem with "You have no maximum hand size."
ability = new LoyaltyAbility(new DrawCardSourceControllerEffect(xValue), -7);
ability.addEffect(new GetEmblemEffect(new TamiyoSeasonedScholarEmblem()));
this.addAbility(ability);
}
private TamiyoSeasonedScholar(final TamiyoSeasonedScholar card) {
super(card);
}
@Override
public TamiyoSeasonedScholar copy() {
return new TamiyoSeasonedScholar(this);
}
}
class TamiyoSeasonedScholarMinus3Effect extends OneShotEffect {
TamiyoSeasonedScholarMinus3Effect() {
super(Outcome.DrawCard);
this.staticText = "Return target instant or sorcery card from your graveyard to your hand. "
+ "If it's a green card, add one mana of any color";
}
private TamiyoSeasonedScholarMinus3Effect(final TamiyoSeasonedScholarMinus3Effect effect) {
super(effect);
}
@Override
public TamiyoSeasonedScholarMinus3Effect copy() {
return new TamiyoSeasonedScholarMinus3Effect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Card card = game.getCard(source.getFirstTarget());
if (card == null) {
return false;
}
Effect effect = new ReturnToHandTargetEffect();
effect.setTargetPointer(getTargetPointer().copy());
effect.apply(game, source);
if (card.getColor(game).isGreen()) {
new AddManaOfAnyColorEffect().apply(game, source);
}
return true;
}
}

View file

@ -80,6 +80,8 @@ public final class ModernHorizons3 extends ExpansionSet {
cards.add(new SetCardInfo("Spawn-Gang Commander", 140, Rarity.UNCOMMON, mage.cards.s.SpawnGangCommander.class));
cards.add(new SetCardInfo("Swamp", 306, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Sylvan Safekeeper", 287, Rarity.RARE, mage.cards.s.SylvanSafekeeper.class));
cards.add(new SetCardInfo("Tamiyo, Inquisitive Student", 242, Rarity.MYTHIC, mage.cards.t.TamiyoInquisitiveStudent.class));
cards.add(new SetCardInfo("Tamiyo, Seasoned Scholar", 242, Rarity.MYTHIC, mage.cards.t.TamiyoSeasonedScholar.class));
cards.add(new SetCardInfo("Trickster's Elk", 175, Rarity.UNCOMMON, mage.cards.t.TrickstersElk.class));
cards.add(new SetCardInfo("Ugin's Labyrinth", 233, Rarity.MYTHIC, mage.cards.u.UginsLabyrinth.class));
cards.add(new SetCardInfo("Urza's Cave", 234, Rarity.UNCOMMON, mage.cards.u.UrzasCave.class));

View file

@ -0,0 +1,148 @@
package org.mage.test.cards.single.mh3;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author Susucr
*/
public class TamiyoInquisitiveStudentTest extends CardTestPlayerBase {
/**
* {@link mage.cards.t.TamiyoInquisitiveStudent Tamiyo, Inquisitive Student} {U}
* Legendary Creature Moonfolk Wizard
* Flying
* Whenever Tamiyo, Inquisitive Student attacks, investigate.
* When you draw your third card in a turn, exile Tamiyo, then return her to the battlefield transformed under her owner's control.
* 0/3
* // {@link mage.cards.t.TamiyoSeasonedScholar Tamiyo, Seasoned Scholar}
* +2: Until your next turn, whenever a creature attacks you or a planeswalker you control, it gets -1/-0 until end of turn.
* 3: Return target instant or sorcery card from your graveyard to your hand. If its a green card, add one mana of any color.
* 7: Draw cards equal to half the number of cards in your library, rounded up. You get an emblem with You have no maximum hand size.
*/
private static final String tamiyo = "Tamiyo, Inquisitive Student";
private static final String tamiyoPW = "Tamiyo, Seasoned Scholar";
@Test
public void test_Trigger_Attack() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, tamiyo);
attack(1, playerA, tamiyo, playerB);
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertPermanentCount(playerA, tamiyo, 1);
assertPermanentCount(playerA, "Clue Token", 1);
}
@Test
public void test_Trigger_Transform() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, tamiyo);
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
addCard(Zone.HAND, playerA, "Divination", 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Divination");
checkPermanentCount("1: Tamiyo didn't transform after draw 2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, tamiyo, 1);
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Divination");
// Tamiyo triggered, as playerA did draw its third card for the turn
setStopAt(3, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, tamiyo, 0);
assertPermanentCount(playerA, tamiyoPW, 1);
}
@Test
public void test_PlusTwo() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, tamiyoPW);
addCard(Zone.BATTLEFIELD, playerA, "Memnite"); // 1/1
addCard(Zone.BATTLEFIELD, playerB, "Elite Vanguard"); // 2/1
addCard(Zone.BATTLEFIELD, playerB, "Centaur Courser"); // 3/3
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+2");
attack(1, playerA, "Memnite", playerB);
attack(2, playerB, "Elite Vanguard", tamiyoPW);
attack(2, playerB, "Centaur Courser", playerA);
setChoice(playerA, "Until"); // Stack the triggers
setStopAt(2, PhaseStep.END_COMBAT);
execute();
assertLife(playerB, 20 - 1);
assertLife(playerA, 20 - (3 - 1));
assertCounterCount(playerA, tamiyoPW, CounterType.LOYALTY, 2 + 2 - (2 - 1));
}
@Test
public void test_Minus3_NonGreen() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, tamiyoPW);
addCard(Zone.GRAVEYARD, playerA, "Lightning Bolt");
addCounters(1, PhaseStep.PRECOMBAT_MAIN, playerA, tamiyoPW, CounterType.LOYALTY, 2);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "-3");
addTarget(playerA, "Lightning Bolt");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertHandCount(playerA, "Lightning Bolt", 1);
assertCounterCount(playerA, tamiyoPW, CounterType.LOYALTY, 1);
}
@Test
public void test_Minus3_Green() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, tamiyoPW);
addCard(Zone.GRAVEYARD, playerA, "Regrowth");
addCard(Zone.HAND, playerA, "Lightning Bolt");
addCounters(1, PhaseStep.PRECOMBAT_MAIN, playerA, tamiyoPW, CounterType.LOYALTY, 2);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "-3");
addTarget(playerA, "Regrowth");
setChoice(playerA, "Red"); // choose that color of mana
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertLife(playerB, 20 - 3);
assertHandCount(playerA, "Regrowth", 1);
assertCounterCount(playerA, tamiyoPW, CounterType.LOYALTY, 1);
}
@Test
public void test_Minus7() {
setStrictChooseMode(true);
removeAllCardsFromLibrary(playerA);
addCard(Zone.LIBRARY, playerA, "Taiga", 45);
addCard(Zone.BATTLEFIELD, playerA, tamiyoPW);
addCounters(1, PhaseStep.PRECOMBAT_MAIN, playerA, tamiyoPW, CounterType.LOYALTY, 6);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "-7");
setStopAt(2, PhaseStep.UPKEEP);
execute();
assertHandCount(playerA, 23); // Drew half of library, and emblem mean no maximum end size
assertCounterCount(playerA, tamiyoPW, CounterType.LOYALTY, 1);
}
}

View file

@ -0,0 +1,35 @@
package mage.abilities.dynamicvalue.common;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.game.Game;
import mage.players.Player;
/**
* @author Susucr
*/
public enum CardsInControllerLibraryCount implements DynamicValue {
instance;
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
Player controller = game.getPlayer(sourceAbility.getControllerId());
return controller != null ? controller.getLibrary().size() : 0;
}
@Override
public CardsInControllerLibraryCount copy() {
return this;
}
@Override
public String getMessage() {
return "the number of cards in your library";
}
@Override
public String toString() {
return "1";
}
}

View file

@ -0,0 +1,34 @@
package mage.game.command.emblems;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect;
import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect.HandSizeModification;
import mage.constants.Duration;
import mage.constants.Zone;
import mage.game.command.Emblem;
/**
* @author Susucr
*/
public final class TamiyoSeasonedScholarEmblem extends Emblem {
/**
* Emblem with "You have no maximum hand size"
*/
public TamiyoSeasonedScholarEmblem() {
super("Emblem Tamiyo");
this.getAbilities().add(new SimpleStaticAbility(Zone.COMMAND, new MaximumHandSizeControllerEffect(
Integer.MAX_VALUE, Duration.Custom, HandSizeModification.SET
)));
}
private TamiyoSeasonedScholarEmblem(final TamiyoSeasonedScholarEmblem card) {
super(card);
}
@Override
public TamiyoSeasonedScholarEmblem copy() {
return new TamiyoSeasonedScholarEmblem(this);
}
}

View file

@ -131,6 +131,7 @@
|Generate|EMBLEM:RVR|Emblem Domri|||DomriRadeEmblem|
|Generate|EMBLEM:SCD|Emblem Nixilis|||ObNixilisReignitedEmblem|
|Generate|EMBLEM:SCD|Emblem Sarkhan|||SarkhanTheDragonspeakerEmblem|
|Generate|EMBLEM:MH3|Emblem Tamiyo|||TamiyoSeasonedScholarEmblem|
# ALL PLANES
# Usage hints: