Stx add cards (#7709)

* WIP

* Implement Confront the Past

* Don't modify test

* Implement Plargg // Augusta

* Implement Shaile // Embrose

* Fix FDoC

* Fix CtP

* fix ordering

* remove extra plains

* FDoC PR fixes

* Augusta PR fixes

* Shaile PR fixes

* don't capitalize "learn"
This commit is contained in:
htrajan 2021-04-02 15:07:30 -07:00 committed by GitHub
parent 754a5b38eb
commit 0a3a4bc189
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 467 additions and 0 deletions

View file

@ -0,0 +1,102 @@
package mage.cards.c;
import com.google.common.collect.Iterables;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.common.FilterPermanentCard;
import mage.filter.common.FilterPlaneswalkerPermanent;
import mage.filter.predicate.mageobject.ConvertedManaCostPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCardInYourGraveyard;
import mage.target.common.TargetPlaneswalkerPermanent;
import mage.target.targetadjustment.TargetAdjuster;
import java.util.UUID;
/**
*
* @author htrajan
*/
public final class ConfrontThePast extends CardImpl {
public static final FilterPlaneswalkerPermanent filter = new FilterPlaneswalkerPermanent();
static {
filter.add(TargetController.OPPONENT.getControllerPredicate());
}
public ConfrontThePast(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{B}");
this.subtype.add(SubType.LESSON);
// Choose one
// Return target planeswalker card with mana value X or less from your graveyard to the battlefield.
this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()
.setText("return target planeswalker card with mana value X or less from your graveyard to the battlefield"));
this.getSpellAbility().setTargetAdjuster(ConfrontThePastAdjuster.instance);
// Remove twice X loyalty counters from target planeswalker an opponent controls.
Mode mode = new Mode();
mode.addEffect(new ConfrontThePastLoyaltyEffect());
mode.addTarget(new TargetPlaneswalkerPermanent(filter));
this.getSpellAbility().addMode(mode);
}
private ConfrontThePast(final ConfrontThePast card) {
super(card);
}
@Override
public ConfrontThePast copy() {
return new ConfrontThePast(this);
}
}
enum ConfrontThePastAdjuster implements TargetAdjuster {
instance;
@Override
public void adjustTargets(Ability ability, Game game) {
if (Iterables.getOnlyElement(ability.getEffects()) instanceof ReturnFromGraveyardToBattlefieldTargetEffect) {
int xValue = ability.getManaCostsToPay().getX();
ability.getTargets().clear();
FilterPermanentCard filter = new FilterPermanentCard("planeswalker card with mana value X or less");
filter.add(CardType.PLANESWALKER.getPredicate());
filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, xValue + 1));
ability.addTarget(new TargetCardInYourGraveyard(filter));
}
}
}
class ConfrontThePastLoyaltyEffect extends OneShotEffect {
ConfrontThePastLoyaltyEffect() {
super(Outcome.Benefit);
staticText = "remove twice X loyalty counters from target planeswalker an opponent controls";
}
public ConfrontThePastLoyaltyEffect(ConfrontThePastLoyaltyEffect effect) {
super(effect);
}
@Override
public ConfrontThePastLoyaltyEffect copy() {
return new ConfrontThePastLoyaltyEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
int xValue = source.getManaCostsToPay().getX();
Permanent target = game.getPermanent(source.getFirstTarget());
target.removeCounters(CounterType.LOYALTY.createInstance(xValue * 2), source, game);
return true;
}
}

View file

@ -0,0 +1,82 @@
package mage.cards.f;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.LearnEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.abilities.keyword.HasteAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
*
* @author htrajan
*/
public final class FirstDayOfClass extends CardImpl {
public FirstDayOfClass(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}");
// Whenever a creature enters the battlefield under your control this turn, put a +1/+1 counter on it and it gains haste until end of turn.
this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new FirstDayOfClassTriggeredAbility()));
// Learn.
this.getSpellAbility().addEffect(new LearnEffect().concatBy("<br>"));
}
private FirstDayOfClass(final FirstDayOfClass card) {
super(card);
}
@Override
public FirstDayOfClass copy() {
return new FirstDayOfClass(this);
}
}
class FirstDayOfClassTriggeredAbility extends DelayedTriggeredAbility {
public FirstDayOfClassTriggeredAbility() {
super(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), Duration.EndOfTurn, false);
this.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn));
}
public FirstDayOfClassTriggeredAbility(FirstDayOfClassTriggeredAbility ability) {
super(ability);
}
@Override
public FirstDayOfClassTriggeredAbility copy() {
return new FirstDayOfClassTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent.isCreature() && permanent.isControlledBy(this.getControllerId())) {
getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
return true;
}
return false;
}
@Override
public String getRule() {
return "Whenever a creature enters the battlefield under your control this turn, put a +1/+1 counter on it and it gains haste until end of turn";
}
}

View file

@ -0,0 +1,185 @@
package mage.cards.p;
import mage.ApprovingObject;
import mage.abilities.Ability;
import mage.abilities.common.AttacksWithCreaturesTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.DiscardCardCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.UntapAllControllerEffect;
import mage.abilities.effects.common.continuous.BoostAllEffect;
import mage.cards.Card;
import mage.cards.CardSetInfo;
import mage.cards.CardsImpl;
import mage.cards.ModalDoubleFacesCard;
import mage.constants.*;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.TappedPredicate;
import mage.filter.predicate.permanent.UntappedPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetControlledCreaturePermanent;
import java.util.UUID;
/**
*
* @author htrajan
*/
public final class PlarggDeanOfChaos extends ModalDoubleFacesCard {
private static final FilterCreaturePermanent tappedFilter = new FilterCreaturePermanent("tapped creatures you control");
private static final FilterCreaturePermanent untappedFilter = new FilterCreaturePermanent("untapped creatures you control");
static {
tappedFilter.add(TappedPredicate.instance);
tappedFilter.add(TargetController.YOU.getControllerPredicate());
untappedFilter.add(UntappedPredicate.instance);
untappedFilter.add(TargetController.YOU.getControllerPredicate());
}
public PlarggDeanOfChaos(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo,
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ORC, SubType.SHAMAN}, "{1}{R}",
"Augusta, Dean of Order", new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.CLERIC}, "{2}{W}");
// 1.
// Plargg, Dean of Chaos
// Legendary Creature - Orc Shaman
this.getLeftHalfCard().addSuperType(SuperType.LEGENDARY);
this.getLeftHalfCard().setPT(2, 2);
// {T}, Discard a card: Draw a card.
SimpleActivatedAbility rummageAbility = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new TapSourceCost());
rummageAbility.addCost(new DiscardCardCost());
this.getLeftHalfCard().addAbility(rummageAbility);
// {4}{R}, {T}: Reveal cards from the top of your library until you reveal a nonlegendary, nonland card with mana value 3 or less. You may cast that card without paying its mana cost. Put all revealed cards not cast this way on the bottom of your library in a random order.
SimpleActivatedAbility ability = new SimpleActivatedAbility(new PlarggDeanOfChaosEffect(), new ManaCostsImpl<>("{4}{R}"));
ability.addCost(new TapSourceCost());
this.getLeftHalfCard().addAbility(ability);
// 2.
// Augusta, Dean of Order
// Legendary Creature - Human Cleric
this.getRightHalfCard().addSuperType(SuperType.LEGENDARY);
this.getRightHalfCard().setPT(1, 3);
// Other tapped creatures you control get +1/+0.
this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostAllEffect(
StaticValue.get(1), StaticValue.get(0), Duration.WhileOnBattlefield, tappedFilter, true)));
// Other untapped creatures you control get +0/+1.
this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostAllEffect(
StaticValue.get(0), StaticValue.get(1), Duration.WhileOnBattlefield, untappedFilter, true)));
// Whenever you attack, untap each creature you control, then tap any number of creatures you control.
AttacksWithCreaturesTriggeredAbility augustaAbility = new AttacksWithCreaturesTriggeredAbility(
new UntapAllControllerEffect(StaticFilters.FILTER_PERMANENT_CREATURES, "untap each creature you control"), 0);
augustaAbility.addEffect(new AugustaDeanOfOrderEffect().concatBy(", then"));
this.getRightHalfCard().addAbility(augustaAbility);
}
private PlarggDeanOfChaos(final PlarggDeanOfChaos card) {
super(card);
}
@Override
public PlarggDeanOfChaos copy() {
return new PlarggDeanOfChaos(this);
}
}
class PlarggDeanOfChaosEffect extends OneShotEffect {
public PlarggDeanOfChaosEffect() {
super(Outcome.PlayForFree);
this.staticText = "reveal cards from the top of your library until you reveal a "
+ "nonlegendary, nonland card with converted mana cost 3 or less. "
+ "You may cast that card without paying its mana cost. Put all revealed "
+ "cards not cast this way on the bottom of your library in a random order";
}
public PlarggDeanOfChaosEffect(PlarggDeanOfChaosEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
boolean cardWasCast = false;
Player controller = game.getPlayer(source.getControllerId());
if (controller != null && controller.getLibrary().hasCards()) {
CardsImpl toReveal = new CardsImpl();
Card eligibleCard = null;
for (Card card : controller.getLibrary().getCards(game)) {
toReveal.add(card);
if (!card.isLand() && !card.isLegendary() && card.getConvertedManaCost() < 4) {
eligibleCard = card;
break;
}
}
controller.revealCards(source, toReveal, game);
if (eligibleCard != null
&& controller.chooseUse(Outcome.PlayForFree, "Cast " + eligibleCard.getLogName() + " without paying its mana cost?", source, game)) {
game.getState().setValue("PlayFromNotOwnHandZone" + eligibleCard.getId(), Boolean.TRUE);
cardWasCast = controller.cast(controller.chooseAbilityForCast(eligibleCard, game, true),
game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + eligibleCard.getId(), null);
if (cardWasCast) {
toReveal.remove(eligibleCard);
}
}
controller.putCardsOnBottomOfLibrary(toReveal, game, source, false);
}
return cardWasCast;
}
@Override
public PlarggDeanOfChaosEffect copy() {
return new PlarggDeanOfChaosEffect(this);
}
}
class AugustaDeanOfOrderEffect extends OneShotEffect {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent();
static {
filter.add(UntappedPredicate.instance);
}
public AugustaDeanOfOrderEffect() {
super(Outcome.Benefit);
staticText = "tap any number of creatures you control";
}
public AugustaDeanOfOrderEffect(AugustaDeanOfOrderEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true);
Player controller = game.getPlayer(source.getControllerId());
controller.chooseTarget(Outcome.Benefit, target, source, game);
target.getTargets().forEach(t -> {
Permanent permanent = game.getPermanent(t);
permanent.tap(source, game);
});
return true;
}
@Override
public AugustaDeanOfOrderEffect copy() {
return new AugustaDeanOfOrderEffect(this);
}
}

View file

@ -0,0 +1,91 @@
package mage.cards.s;
import mage.abilities.Ability;
import mage.abilities.common.DiesCreatureTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.counter.AddCountersAllEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardSetInfo;
import mage.cards.ModalDoubleFacesCard;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicate;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.filter.predicate.permanent.EnteredThisTurnPredicate;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author htrajan
*/
public final class ShaileDeanOfRadiance extends ModalDoubleFacesCard {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature");
private static final FilterPermanent shaileFilter = new FilterControlledCreaturePermanent("creature that entered the battlefield under your control this turn");
private static final FilterPermanent embroseFilter = new FilterControlledCreaturePermanent("a creature you control with a +1/+1 counter on it");
static {
filter.add(AnotherPredicate.instance);
shaileFilter.add(EnteredThisTurnPredicate.instance);
shaileFilter.add((Predicate<Permanent>) (input, game) -> !input.checkControlChanged(game));
embroseFilter.add(CounterType.P1P1.getPredicate());
}
public ShaileDeanOfRadiance(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo,
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.BIRD, SubType.CLERIC}, "{1}{W}",
"Embrose, Dean of Shadow", new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WARLOCK}, "{2}{B}{B}");
// 1.
// Shaile, Dean of Radiance
// Legendary Creature - Bird Cleric
this.getLeftHalfCard().addSuperType(SuperType.LEGENDARY);
this.getLeftHalfCard().setPT(1, 1);
// Flying
this.getLeftHalfCard().addAbility(FlyingAbility.getInstance());
// Vigilance
this.getLeftHalfCard().addAbility(VigilanceAbility.getInstance());
// {T}: Put a +1/+1 counter on each creature that entered the battlefield under your control this turn.
this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), shaileFilter), new TapSourceCost()));
// 2.
// Embrose, Dean of Shadow
// Legendary Creature - Human Warlock
this.getRightHalfCard().addSuperType(SuperType.LEGENDARY);
this.getRightHalfCard().setPT(4, 4);
// {T}: Put a +1/+1 counter on another target creature, then Embrose, Dean of Shadow deals 2 damage to that creature.
Ability ability = new SimpleActivatedAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new TapSourceCost());
ability.addEffect(new DamageTargetEffect(2).concatBy(", then").setText("{this} deals 2 damage to that creature"));
ability.addTarget(new TargetCreaturePermanent(filter));
this.getRightHalfCard().addAbility(ability);
// Whenever a creature you control with a +1/+1 counter on it dies, draw a card.
this.getRightHalfCard().addAbility(new DiesCreatureTriggeredAbility(new DrawCardSourceControllerEffect(1), false, embroseFilter));
}
private ShaileDeanOfRadiance(final ShaileDeanOfRadiance card) {
super(card);
}
@Override
public ShaileDeanOfRadiance copy() {
return new ShaileDeanOfRadiance(this);
}
}

View file

@ -48,6 +48,7 @@ public final class StrixhavenSchoolOfMages extends ExpansionSet {
cards.add(new SetCardInfo("Clever Lumimancer", 10, Rarity.UNCOMMON, mage.cards.c.CleverLumimancer.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));
cards.add(new SetCardInfo("Crackle with Power", 95, Rarity.MYTHIC, mage.cards.c.CrackleWithPower.class));
cards.add(new SetCardInfo("Creative Outburst", 171, Rarity.UNCOMMON, mage.cards.c.CreativeOutburst.class));
cards.add(new SetCardInfo("Culmination of Studies", 173, Rarity.RARE, mage.cards.c.CulminationOfStudies.class));
@ -65,6 +66,7 @@ public final class StrixhavenSchoolOfMages extends ExpansionSet {
cards.add(new SetCardInfo("Expel", 18, Rarity.COMMON, mage.cards.e.Expel.class));
cards.add(new SetCardInfo("Exponential Growth", 130, Rarity.RARE, mage.cards.e.ExponentialGrowth.class));
cards.add(new SetCardInfo("Field Trip", 131, Rarity.COMMON, mage.cards.f.FieldTrip.class));
cards.add(new SetCardInfo("First Day of Class", 102, Rarity.COMMON, mage.cards.f.FirstDayOfClass.class));
cards.add(new SetCardInfo("Forest", 374, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Fortifying Draught", 132, Rarity.UNCOMMON, mage.cards.f.FortifyingDraught.class));
cards.add(new SetCardInfo("Frost Trickster", 43, Rarity.COMMON, mage.cards.f.FrostTrickster.class));
@ -111,6 +113,7 @@ public final class StrixhavenSchoolOfMages extends ExpansionSet {
cards.add(new SetCardInfo("Pest Summoning", 211, Rarity.COMMON, mage.cards.p.PestSummoning.class));
cards.add(new SetCardInfo("Pilgrim of the Ages", 22, Rarity.COMMON, mage.cards.p.PilgrimOfTheAges.class));
cards.add(new SetCardInfo("Plains", 366, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plargg, Dean of Chaos", 155, Rarity.RARE, mage.cards.p.PlarggDeanOfChaos.class));
cards.add(new SetCardInfo("Pop Quiz", 49, Rarity.COMMON, mage.cards.p.PopQuiz.class));
cards.add(new SetCardInfo("Practical Research", 212, Rarity.UNCOMMON, mage.cards.p.PracticalResearch.class));
cards.add(new SetCardInfo("Prismari Apprentice", 213, Rarity.UNCOMMON, mage.cards.p.PrismariApprentice.class));
@ -136,6 +139,7 @@ public final class StrixhavenSchoolOfMages extends ExpansionSet {
cards.add(new SetCardInfo("Secret Rendezvous", 26, Rarity.UNCOMMON, mage.cards.s.SecretRendezvous.class));
cards.add(new SetCardInfo("Serpentine Curve", 52, Rarity.COMMON, mage.cards.s.SerpentineCurve.class));
cards.add(new SetCardInfo("Shadewing Laureate", 229, Rarity.COMMON, mage.cards.s.ShadewingLaureate.class));
cards.add(new SetCardInfo("Shaile, Dean of Radiance", 158, Rarity.RARE, mage.cards.s.ShaileDeanOfRadiance.class));
cards.add(new SetCardInfo("Shineshadow Snarl", 272, Rarity.RARE, mage.cards.s.ShineshadowSnarl.class));
cards.add(new SetCardInfo("Silverquill Apprentice", 231, Rarity.UNCOMMON, mage.cards.s.SilverquillApprentice.class));
cards.add(new SetCardInfo("Silverquill Campus", 273, Rarity.COMMON, mage.cards.s.SilverquillCampus.class));

View file

@ -67,6 +67,9 @@ public class AttacksWithCreaturesTriggeredAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
if (minAttackers == 0) {
return "Whenever you attack, " + super.getRule();
}
StringBuilder sb = new StringBuilder("Whenever you attack with " + CardUtil.numberToText(minAttackers) + " or more ");
sb.append(filter.getMessage());
sb.append(", ");