[MOM] Implement Sheoldred

This commit is contained in:
theelk801 2023-04-14 20:54:59 -04:00
parent dd91a58c85
commit 25e8cf7cef
11 changed files with 258 additions and 70 deletions

View file

@ -1,29 +1,26 @@
package mage.cards.c;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbilityImpl;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.CardsInControllerGraveyardCondition;
import mage.abilities.costs.common.ExileFromGraveCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.Effects;
import mage.abilities.decorator.ConditionalActivatedAbility;
import mage.abilities.effects.common.discard.DiscardTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.constants.AbilityWord;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.TimingRule;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.target.TargetPlayer;
import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID;
/**
*
* @author cbt33
*/
public final class CabalInquisitor extends CardImpl {
@ -37,7 +34,10 @@ public final class CabalInquisitor extends CardImpl {
this.toughness = new MageInt(1);
// Threshold - {1}{B}, {T}, Exile two cards from your graveyard: Target player discards a card. Activate this ability only any time you could cast a sorcery, and only if seven or more cards are in your graveyard.
Ability ability = new ActivateAsSorceryConditionalActivatedAbility(Zone.BATTLEFIELD, new DiscardTargetEffect(1), new ManaCostsImpl<>("{1}{B}"), new CardsInControllerGraveyardCondition(7));
Ability ability = new ConditionalActivatedAbility(
new DiscardTargetEffect(1), new ManaCostsImpl<>("{1}{B}"),
new CardsInControllerGraveyardCondition(7)
).setTiming(TimingRule.SORCERY);
ability.addTarget(new TargetPlayer());
ability.addCost(new TapSourceCost());
ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(2, StaticFilters.FILTER_CARDS_FROM_YOUR_GRAVEYARD)));
@ -54,36 +54,3 @@ public final class CabalInquisitor extends CardImpl {
return new CabalInquisitor(this);
}
}
class ActivateAsSorceryConditionalActivatedAbility extends ActivatedAbilityImpl {
private static final Effects emptyEffects = new Effects();
public ActivateAsSorceryConditionalActivatedAbility(Zone zone, Effect effect, ManaCosts cost, Condition condition) {
super(zone, effect, cost);
this.condition = condition;
timing = TimingRule.SORCERY;
}
public ActivateAsSorceryConditionalActivatedAbility(final ActivateAsSorceryConditionalActivatedAbility ability) {
super(ability);
}
@Override
public Effects getEffects(Game game, EffectType effectType) {
if (!condition.apply(game, this)) {
return emptyEffects;
}
return super.getEffects(game, effectType);
}
@Override
public ActivateAsSorceryConditionalActivatedAbility copy() {
return new ActivateAsSorceryConditionalActivatedAbility(this);
}
@Override
public String getRule() {
return super.getRule() + " Activate only as a sorcery and only if seven or more cards are in your graveyard.";
}
}

View file

@ -48,11 +48,11 @@ public class JinGitaxias extends CardImpl {
//{3}{U}: Exile Jin-Gitaxias, then return it to the battlefield transformed under its owners control. Activate
//only as a sorcery and only if you have seven or more cards in hand.
this.addAbility(new TransformAbility());
ConditionalActivatedAbility conditionalActivatedAbility =
new ConditionalActivatedAbility(Zone.BATTLEFIELD, new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED),
new ManaCostsImpl<>("{3}{U}"), new CardsInHandCondition(ComparisonType.MORE_THAN, 6));
conditionalActivatedAbility.setTiming(TimingRule.SORCERY);
this.addAbility(conditionalActivatedAbility);
this.addAbility(new ConditionalActivatedAbility(
new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED),
new ManaCostsImpl<>("{3}{U}"),
new CardsInHandCondition(ComparisonType.MORE_THAN, 6)
).setTiming(TimingRule.SORCERY));
}
private JinGitaxias(final JinGitaxias card) {

View file

@ -41,7 +41,7 @@ public final class LifeOfToshiroUmezawa extends CardImpl {
this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II,
new Effects(new BoostTargetEffect(2, 2)),
new Targets(new TargetCreaturePermanent()), false,
mode, new Mode(new GainLifeEffect(2))
null, mode, new Mode(new GainLifeEffect(2))
);
// III Exile this Saga, then return it to the battlefield transformed under your control.

View file

@ -0,0 +1,65 @@
package mage.cards.s;
import mage.MageInt;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.CardsInOpponentGraveyardCondition;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.decorator.ConditionalActivatedAbility;
import mage.abilities.effects.common.ExileAndReturnSourceEffect;
import mage.abilities.effects.common.SacrificeOpponentsEffect;
import mage.abilities.keyword.MenaceAbility;
import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent;
import mage.filter.predicate.permanent.TokenPredicate;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class Sheoldred extends CardImpl {
private static final FilterPermanent filter
= new FilterCreatureOrPlaneswalkerPermanent("nontoken creature or planeswalker");
static {
filter.add(TokenPredicate.FALSE);
}
public Sheoldred(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}");
this.addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.PHYREXIAN);
this.subtype.add(SubType.PRAETOR);
this.power = new MageInt(4);
this.toughness = new MageInt(5);
this.secondSideCardClazz = mage.cards.t.TheTrueScriptures.class;
// Menace
this.addAbility(new MenaceAbility(false));
// When Sheoldred enters the battlefield, each opponent sacrifices a nontoken creature or planeswalker.
this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeOpponentsEffect(filter)));
// {4}{B}: Exile Sheoldred, then return it to the battlefield transformed under its owner's control. Activate only as a sorcery and only if an opponent has eight or more cards in their graveyard.
this.addAbility(new TransformAbility());
this.addAbility(new ConditionalActivatedAbility(
new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED),
new ManaCostsImpl<>("{4}{B}"), CardsInOpponentGraveyardCondition.EIGHT
).setTiming(TimingRule.SORCERY).addHint(CardsInOpponentGraveyardCondition.EIGHT.getHint()));
}
private Sheoldred(final Sheoldred card) {
super(card);
}
@Override
public Sheoldred copy() {
return new Sheoldred(this);
}
}

View file

@ -0,0 +1,137 @@
package mage.cards.t;
import mage.abilities.Ability;
import mage.abilities.common.SagaAbility;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.Effects;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect;
import mage.abilities.effects.common.MillCardsEachPlayerEffect;
import mage.abilities.effects.common.discard.DiscardEachPlayerEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetPermanent;
import mage.target.Targets;
import mage.target.targetadjustment.TargetAdjuster;
import mage.target.targetpointer.EachTargetPointer;
import java.util.Collection;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author TheElk801
*/
public final class TheTrueScriptures extends CardImpl {
public TheTrueScriptures(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "");
this.subtype.add(SubType.SAGA);
this.color.setBlack(true);
this.nightCard = true;
// (As this Saga enters and after your draw step, add a lore counter.)
SagaAbility sagaAbility = new SagaAbility(this, false);
// I -- For each opponent, destroy up to one target creature or planeswalker that player controls.
sagaAbility.addChapterEffect(
this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_I,
new Effects(
new DestroyTargetEffect().setTargetPointer(new EachTargetPointer())
.setText("for each opponent, destroy up to one target creature or planeswalker that player controls")
), new Targets(), false, TheTrueScripturesAdjuster.instance
);
// II -- Each opponent discards three cards, then mills three cards.
sagaAbility.addChapterEffect(
this, SagaChapter.CHAPTER_II,
new DiscardEachPlayerEffect(StaticValue.get(3), false, TargetController.OPPONENT),
new MillCardsEachPlayerEffect(3, TargetController.OPPONENT).setText(", then mills three cards")
);
// III -- Put all creature cards from all graveyards onto the battlefield under your control. Exile The True Scriptures, then return it to the battlefield.
sagaAbility.addChapterEffect(
this, SagaChapter.CHAPTER_III,
new TheTrueScripturesEffect(),
new ExileSourceAndReturnFaceUpEffect()
);
this.addAbility(sagaAbility);
}
private TheTrueScriptures(final TheTrueScriptures card) {
super(card);
}
@Override
public TheTrueScriptures copy() {
return new TheTrueScriptures(this);
}
}
enum TheTrueScripturesAdjuster implements TargetAdjuster {
instance;
@Override
public void adjustTargets(Ability ability, Game game) {
ability.getTargets().clear();
for (UUID playerId : game.getOpponents(ability.getControllerId())) {
Player player = game.getPlayer(playerId);
if (player == null) {
continue;
}
FilterPermanent filter = new FilterCreatureOrPlaneswalkerPermanent(
"creature or planswalker controlled by " + player.getName()
);
filter.add(new ControllerIdPredicate(playerId));
ability.addTarget(new TargetPermanent(0, 1, filter));
}
}
}
class TheTrueScripturesEffect extends OneShotEffect {
TheTrueScripturesEffect() {
super(Outcome.Benefit);
staticText = "put all creature cards from all graveyards onto the battlefield under your control";
}
private TheTrueScripturesEffect(final TheTrueScripturesEffect effect) {
super(effect);
}
@Override
public TheTrueScripturesEffect copy() {
return new TheTrueScripturesEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
Cards cards = new CardsImpl(game
.getState()
.getPlayersInRange(source.getControllerId(), game)
.stream()
.map(game::getPlayer)
.filter(Objects::nonNull)
.map(Player::getGraveyard)
.map(gy -> gy.getCards(StaticFilters.FILTER_CARD_CREATURE, game))
.flatMap(Collection::stream)
.collect(Collectors.toList()));
return player.moveCards(cards, Zone.BATTLEFIELD, source, game);
}
}

View file

@ -270,6 +270,7 @@ public final class MarchOfTheMachine extends ExpansionSet {
cards.add(new SetCardInfo("Serpent-Blade Assailant", 205, Rarity.COMMON, mage.cards.s.SerpentBladeAssailant.class));
cards.add(new SetCardInfo("Serra Faithkeeper", 21, Rarity.UNCOMMON, mage.cards.s.SerraFaithkeeper.class));
cards.add(new SetCardInfo("Shatter the Source", 164, Rarity.COMMON, mage.cards.s.ShatterTheSource.class));
cards.add(new SetCardInfo("Sheoldred", 125, Rarity.MYTHIC, mage.cards.s.Sheoldred.class));
cards.add(new SetCardInfo("Shivan Branch-Burner", 165, Rarity.UNCOMMON, mage.cards.s.ShivanBranchBurner.class));
cards.add(new SetCardInfo("Sigiled Sentinel", 37, Rarity.COMMON, mage.cards.s.SigiledSentinel.class));
cards.add(new SetCardInfo("Skittering Surveyor", 264, Rarity.COMMON, mage.cards.s.SkitteringSurveyor.class));
@ -296,6 +297,7 @@ public final class MarchOfTheMachine extends ExpansionSet {
cards.add(new SetCardInfo("The Argent Etchings", 12, Rarity.MYTHIC, mage.cards.t.TheArgentEtchings.class));
cards.add(new SetCardInfo("The Broken Sky", 241, Rarity.RARE, mage.cards.t.TheBrokenSky.class));
cards.add(new SetCardInfo("The Great Synthesis", 65, Rarity.MYTHIC, mage.cards.t.TheGreatSynthesis.class));
cards.add(new SetCardInfo("The True Scriptures", 125, Rarity.MYTHIC, mage.cards.t.TheTrueScriptures.class));
cards.add(new SetCardInfo("Thornwood Falls", 274, Rarity.COMMON, mage.cards.t.ThornwoodFalls.class));
cards.add(new SetCardInfo("Thrashing Frontliner", 167, Rarity.COMMON, mage.cards.t.ThrashingFrontliner.class));
cards.add(new SetCardInfo("Thunderhead Squadron", 81, Rarity.COMMON, mage.cards.t.ThunderheadSquadron.class));

View file

@ -83,7 +83,7 @@ public interface ActivatedAbility extends Ability {
int getMaxActivationsPerTurn(Game game);
public void setTiming(TimingRule timing);
ActivatedAbility setTiming(TimingRule timing);
public ActivatedAbility setCondition(Condition condition);
ActivatedAbility setCondition(Condition condition);
}

View file

@ -241,8 +241,9 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
}
@Override
public void setTiming(TimingRule timing) {
public ActivatedAbilityImpl setTiming(TimingRule timing) {
this.timing = timing;
return this;
}
protected boolean hasMoreActivationsThisTurn(Game game) {

View file

@ -20,6 +20,7 @@ import mage.game.stack.StackObject;
import mage.players.Player;
import mage.target.Target;
import mage.target.Targets;
import mage.target.targetadjustment.TargetAdjuster;
import mage.util.CardUtil;
import java.util.Arrays;
@ -89,7 +90,7 @@ public class SagaAbility extends SimpleStaticAbility {
}
public void addChapterEffect(Card card, SagaChapter fromChapter, SagaChapter toChapter, Effect effect, Target target, boolean optional) {
addChapterEffect(card, fromChapter, toChapter, new Effects(effect), new Targets(target), optional);
addChapterEffect(card, fromChapter, toChapter, new Effects(effect), new Targets(target), optional, null);
}
public void addChapterEffect(Card card, SagaChapter fromChapter, SagaChapter toChapter, Effects effects, Target target) {
@ -97,10 +98,10 @@ public class SagaAbility extends SimpleStaticAbility {
}
public void addChapterEffect(Card card, SagaChapter fromChapter, SagaChapter toChapter, Effects effects, Targets targets) {
addChapterEffect(card, fromChapter, toChapter, effects, targets, false);
addChapterEffect(card, fromChapter, toChapter, effects, targets, false, null);
}
public void addChapterEffect(Card card, SagaChapter fromChapter, SagaChapter toChapter, Effects effects, Targets targets, boolean optional, Mode... modes) {
public void addChapterEffect(Card card, SagaChapter fromChapter, SagaChapter toChapter, Effects effects, Targets targets, boolean optional, TargetAdjuster targetAdjuster, Mode... modes) {
for (int i = fromChapter.getNumber(); i <= toChapter.getNumber(); i++) {
ChapterTriggeredAbility ability = new ChapterTriggeredAbility(null, SagaChapter.getChapter(i), toChapter, optional, readAhead);
for (Effect effect : effects) {
@ -119,6 +120,9 @@ public class SagaAbility extends SimpleStaticAbility {
if (i > fromChapter.getNumber()) {
ability.setRuleVisible(false);
}
if (targetAdjuster != null) {
ability.setTargetAdjuster(targetAdjuster);
}
card.addAbility(ability);
}
}

View file

@ -85,7 +85,6 @@ public class CardsInHandCondition implements Condition {
@Override
public String toString() {
int workCount = count;
StringBuilder sb = new StringBuilder("if");
switch (targetController) {
case YOU:
@ -97,21 +96,22 @@ public class CardsInHandCondition implements Condition {
}
switch (this.type) {
case FEWER_THAN:
sb.append(" less or equal than ");
workCount++;
sb.append(CardUtil.numberToText(count));
sb.append(" or fewer ");
break;
case MORE_THAN:
sb.append(" more than ");
sb.append(CardUtil.numberToText(count));
sb.append(" or more ");
break;
case EQUAL_TO:
sb.append(" exactly ");
if (count > 0) {
sb.append(" exactly ");
sb.append(CardUtil.numberToText(count));
} else {
sb.append(" no ");
}
break;
}
if (count == 0) {
sb.append("no");
} else {
sb.append(CardUtil.numberToText(workCount));
}
sb.append(" cards in hand");
return sb.toString();
}

View file

@ -12,11 +12,11 @@ import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.effects.Effect;
import mage.abilities.effects.Effects;
import mage.constants.EffectType;
import mage.constants.TimingRule;
import mage.constants.Zone;
import mage.game.Game;
/**
*
* @author LevelX
*/
public class ConditionalActivatedAbility extends ActivatedAbilityImpl {
@ -25,6 +25,10 @@ public class ConditionalActivatedAbility extends ActivatedAbilityImpl {
private String ruleText = null;
public ConditionalActivatedAbility(Effect effect, Cost cost, Condition condition) {
this(Zone.BATTLEFIELD, effect, cost, condition);
}
public ConditionalActivatedAbility(Zone zone, Effect effect, Cost cost, Condition condition) {
super(zone, effect, cost);
this.condition = condition;
@ -71,13 +75,21 @@ public class ConditionalActivatedAbility extends ActivatedAbilityImpl {
if (ruleText != null && !ruleText.isEmpty()) {
return ruleText;
}
StringBuilder sb = new StringBuilder(super.getRule());
sb.append(" Activate only ");
if (timing == TimingRule.SORCERY) {
sb.append("as a sorcery and only");
}
String conditionText = condition.toString();
String additionalText = "if ";
if (conditionText.startsWith("during")
|| conditionText.startsWith("before")
|| conditionText.startsWith("if")) {
additionalText = "";
sb.append("");
} else {
sb.append("if ");
}
return super.getRule() + " Activate only " + additionalText + condition.toString() + ".";
sb.append(conditionText);
sb.append('.');
return sb.toString();
}
}