[FIN] Implement Zenos yae Galvus / Shinryu, Transcendent Rival

This commit is contained in:
theelk801 2025-05-07 17:31:22 -04:00
parent f90350c0c5
commit ada8211b4b
5 changed files with 251 additions and 8 deletions

View file

@ -0,0 +1,134 @@
package mage.cards.s;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.WinGameSourceControllerEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetPlayer;
import mage.target.common.TargetOpponent;
import java.util.Optional;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class ShinryuTranscendentRival extends CardImpl {
public ShinryuTranscendentRival(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.DRAGON);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
this.color.setBlack(true);
this.nightCard = true;
// Flying
this.addAbility(FlyingAbility.getInstance());
// As this creature transforms into Shinryu, choose an opponent.
this.addAbility(new SimpleStaticAbility(new ShinryuTranscendentRivalEffect()));
// Burning Chains -- When the chosen player loses the game, you win the game.
this.addAbility(new ShinryuTranscendentRivalTriggeredAbility());
}
private ShinryuTranscendentRival(final ShinryuTranscendentRival card) {
super(card);
}
@Override
public ShinryuTranscendentRival copy() {
return new ShinryuTranscendentRival(this);
}
}
class ShinryuTranscendentRivalEffect extends ReplacementEffectImpl {
ShinryuTranscendentRivalEffect() {
super(Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "as this creature transforms into {this}, choose an opponent";
}
private ShinryuTranscendentRivalEffect(final ShinryuTranscendentRivalEffect effect) {
super(effect);
}
@Override
public ShinryuTranscendentRivalEffect copy() {
return new ShinryuTranscendentRivalEffect(this);
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(source.getSourceId());
if (controller == null || permanent == null) {
return false;
}
TargetPlayer target = new TargetOpponent(true);
controller.choose(outcome, target, source, game);
Player opponent = game.getPlayer(target.getFirstTarget());
if (opponent == null) {
return false;
}
game.informPlayers(permanent.getName() + ": " + controller.getLogName() + " has chosen " + opponent.getLogName());
game.getState().setValue(permanent.getId() + "_" + permanent.getZoneChangeCounter(game) + "_opponent", opponent.getId());
return false;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.TRANSFORMING;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
return source.getSourceId().equals(event.getTargetId())
&& source.getSourcePermanentIfItStillExists(game) != null;
}
}
class ShinryuTranscendentRivalTriggeredAbility extends TriggeredAbilityImpl {
ShinryuTranscendentRivalTriggeredAbility() {
super(Zone.BATTLEFIELD, new WinGameSourceControllerEffect());
this.setTriggerPhrase("When the chosen player loses the game, ");
this.withFlavorWord("Burning Chains");
}
private ShinryuTranscendentRivalTriggeredAbility(final ShinryuTranscendentRivalTriggeredAbility ability) {
super(ability);
}
@Override
public ShinryuTranscendentRivalTriggeredAbility copy() {
return new ShinryuTranscendentRivalTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.LOSES;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return Optional
.ofNullable(this.getId() + "_" + this.getSourceObjectZoneChangeCounter() + "_opponent")
.map(game.getState()::getValue)
.map(event.getPlayerId()::equals)
.orElse(false);
}
}

View file

@ -0,0 +1,102 @@
package mage.cards.z;
import mage.MageInt;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.LeavesBattlefieldAllTriggeredAbility;
import mage.abilities.effects.common.ChooseCreatureEffect;
import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.effects.common.continuous.BoostAllEffect;
import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.ObjectSourcePlayer;
import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.util.CardUtil;
import java.util.Optional;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class ZenosYaeGalvus extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent();
private static final FilterPermanent filter2 = new FilterPermanent();
static {
filter.add(ZenosYaeGalvusPredicate.FALSE);
filter2.add(ZenosYaeGalvusPredicate.TRUE);
}
public ZenosYaeGalvus(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.NOBLE);
this.subtype.add(SubType.WARRIOR);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
this.secondSideCardClazz = mage.cards.s.ShinryuTranscendentRival.class;
// My First Friend -- When Zenos yae Galvus enters, choose a creature an opponent controls. Until end of turn, creatures other than Zenos yae Galvus and the chosen creature get -2/-2.
Ability ability = new EntersBattlefieldTriggeredAbility(
new ChooseCreatureEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE, false)
);
ability.addEffect(new BoostAllEffect(
-2, -2, Duration.EndOfTurn, filter, true
).setText("until end of turn, creatures other than {this} and the chosen creature get -2/-2"));
this.addAbility(ability.withFlavorWord("My First Friend"));
// When the chosen creature leaves the battlefield, transform Zenos yae Galvus.
this.addAbility(new TransformAbility());
this.addAbility(new LeavesBattlefieldAllTriggeredAbility(
new TransformSourceEffect(), filter2
).setTriggerPhrase("When the chosen creature leaves the battlefield, "));
}
private ZenosYaeGalvus(final ZenosYaeGalvus card) {
super(card);
}
@Override
public ZenosYaeGalvus copy() {
return new ZenosYaeGalvus(this);
}
}
enum ZenosYaeGalvusPredicate implements ObjectSourcePlayerPredicate<Permanent> {
TRUE(true),
FALSE(false);
private final boolean flag;
ZenosYaeGalvusPredicate(boolean flag) {
this.flag = flag;
}
@Override
public boolean apply(ObjectSourcePlayer<Permanent> input, Game game) {
return flag == Optional
.ofNullable(CardUtil.getObjectZoneString(
"chosenCreature", input.getSource().getSourceId(), game,
input.getSource().getSourceObjectZoneChangeCounter(), false
))
.map(game.getState()::getValue)
.filter(MageObjectReference.class::isInstance)
.map(MageObjectReference.class::cast)
.map(mor -> mor.refersTo(input.getObject(), game))
.orElse(false);
}
}

View file

@ -28,6 +28,7 @@ public final class FinalFantasy extends ExpansionSet {
cards.add(new SetCardInfo("Jumbo Cactuar", 191, Rarity.RARE, mage.cards.j.JumboCactuar.class));
cards.add(new SetCardInfo("Sazh's Chocobo", 200, Rarity.UNCOMMON, mage.cards.s.SazhsChocobo.class));
cards.add(new SetCardInfo("Sephiroth, Planet's Heir", 553, Rarity.MYTHIC, mage.cards.s.SephirothPlanetsHeir.class));
cards.add(new SetCardInfo("Shinryu, Transcendent Rival", 127, Rarity.RARE, mage.cards.s.ShinryuTranscendentRival.class));
cards.add(new SetCardInfo("Sidequest: Catch a Fish", 31, Rarity.UNCOMMON, mage.cards.s.SidequestCatchAFish.class));
cards.add(new SetCardInfo("Sin, Spira's Punishment", 242, Rarity.RARE, mage.cards.s.SinSpirasPunishment.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sin, Spira's Punishment", 348, Rarity.RARE, mage.cards.s.SinSpirasPunishment.class, NON_FULL_USE_VARIOUS));
@ -37,5 +38,6 @@ public final class FinalFantasy extends ExpansionSet {
cards.add(new SetCardInfo("Summon: Shiva", 78, Rarity.UNCOMMON, mage.cards.s.SummonShiva.class));
cards.add(new SetCardInfo("Tonberry", 122, Rarity.UNCOMMON, mage.cards.t.Tonberry.class));
cards.add(new SetCardInfo("Zell Dincht", 170, Rarity.RARE, mage.cards.z.ZellDincht.class));
cards.add(new SetCardInfo("Zenos yae Galvus", 127, Rarity.RARE, mage.cards.z.ZenosYaeGalvus.class));
}
}

View file

@ -13,27 +13,30 @@ import mage.target.TargetPermanent;
import mage.util.CardUtil;
/**
* To be used with AsEntersBattlefieldAbility (otherwise Zone Change Counter will be wrong)
* To be used with AsEntersBattlefieldAbility with useOffset=false (otherwise Zone Change Counter will be wrong)
*
* @author weirddan455
*/
public class ChooseCreatureEffect extends OneShotEffect {
private final FilterPermanent filter;
private final boolean useOffset;
public ChooseCreatureEffect() {
this(StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL);
this(StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL, true);
}
public ChooseCreatureEffect(FilterPermanent filter) {
public ChooseCreatureEffect(FilterPermanent filter, boolean useOffset) {
super(Outcome.Benefit);
this.filter = filter;
this.staticText = "choose " + filter.getMessage();
this.useOffset = useOffset;
}
private ChooseCreatureEffect(final ChooseCreatureEffect effect) {
super(effect);
this.filter = effect.filter;
this.useOffset = effect.useOffset;
}
@Override
@ -44,11 +47,8 @@ public class ChooseCreatureEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
Permanent sourcePermanent = game.getPermanentEntering(source.getSourceId());
if (sourcePermanent == null) {
if (controller == null || sourcePermanent == null) {
return false;
}
TargetPermanent target = new TargetPermanent(1, 1, filter, true);
@ -58,7 +58,10 @@ public class ChooseCreatureEffect extends OneShotEffect {
return false;
}
game.getState().setValue(
CardUtil.getObjectZoneString("chosenCreature", sourcePermanent.getId(), game, sourcePermanent.getZoneChangeCounter(game) + 1, false),
CardUtil.getObjectZoneString(
"chosenCreature", sourcePermanent.getId(), game,
sourcePermanent.getZoneChangeCounter(game) + (useOffset ? 1 : 0), false
),
new MageObjectReference(chosenCreature, game)
);
sourcePermanent.addInfo("chosen creature", CardUtil.addToolTipMarkTags("Chosen Creature " + chosenCreature.getIdName()), game);

View file

@ -57190,6 +57190,8 @@ Summon: Shiva|Final Fantasy|78|U|{3}{U}{U}|Enchantment Creature - Saga Elemental
Cecil, Dark Knight|Final Fantasy|91|R|{B}|Legendary Creature - Human Knight|2|3|Deathtouch$Darkness -- Whenever Cecil deals damage, you lose that much life. Then if your life total is less than or equal to half your starting life total, untap Cecil and transform it.|
Cecil, Redeemed Paladin|Final Fantasy|91|R||Legendary Creature - Human Knight|4|4|Lifelink$Protect -- Whenever Cecil attacks, other attacking creatures gain indestructible until end of turn.|
Tonberry|Final Fantasy|122|U|{B}|Creature - Salamander Horror|2|1|This creature enters tapped with a stun counter on it.$Chef's Knife -- During your turn, this creature has first strike and deathtouch.|
Zenos yae Galvus|Final Fantasy|127|R|{3}{B}{B}|Legendary Creature - Human Noble Warrior|4|4|My First Friend -- When Zenos yae Galvus enters, choose a creature an opponent controls. Until end of turn, creatures other than Zenos yae Galvus and the chosen creature get -2/-2.$When the chosen creature leaves the battlefield, transform Zenos yae Galvus.|
Shinryu, Transcendent Rival|Final Fantasy|127|R||Legendary Creature - Human Noble Warrior FP|4|4|Flying$As this creature transforms into Shinryu, choose an opponent.$Burning Chains -- When the chosen player loses the game, you win the game.|
Zell Dincht|Final Fantasy|170|R|{2}{R}|Legendary Creature - Human Monk|0|3|You may play an additional land on each of your turns.$Zell Dincht gets +1/+0 for each land you control.$At the beginning of your end step, return a land you control to its owner's hand.|
Jumbo Cactuar|Final Fantasy|191|R|{5}{G}{G}|Creature - Plant|1|7|10,000 Needles -- Whenever this creature attacks, it gets +9999/+0 until end of turn.|
Sazh's Chocobo|Final Fantasy|200|U|{G}|Creature - Bird|0|1|Landfall -- Whenever a land you control enters, put a +1/+1 counter on this creature.|