[FIN] Implement spoilers (#13616)

* [FIN] Implement Commune with Beavers

* [FIN] Implement Adventurer's Inn

* [FIN] Implement Job Select keyword ability

* [FIN] Implement White Mage's Staff

* [FIN] Implement Black Mage's Rod

* [FIN] Implement Ultimecia, Time Sorceress / Ultimecia, Omnipotent
This commit is contained in:
Balázs Kristóf 2025-05-10 21:26:25 +02:00 committed by GitHub
parent 145c88ac90
commit 52bb919cd4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 382 additions and 0 deletions

View file

@ -0,0 +1,37 @@
package mage.cards.a;
import java.util.UUID;
import mage.constants.SubType;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.mana.ColorlessManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
/**
* @author balazskristof
*/
public final class AdventurersInn extends CardImpl {
public AdventurersInn(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
this.subtype.add(SubType.TOWN);
// When this land enters, you gain 2 life.
this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(2)));
// {T}: Add {C}.
this.addAbility(new ColorlessManaAbility());
}
private AdventurersInn(final AdventurersInn card) {
super(card);
}
@Override
public AdventurersInn copy() {
return new AdventurersInn(this);
}
}

View file

@ -0,0 +1,65 @@
package mage.cards.b;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
import mage.abilities.effects.common.DamagePlayersEffect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.continuous.AddCardSubtypeAttachedEffect;
import mage.abilities.effects.common.continuous.BoostEquippedEffect;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.constants.AttachmentType;
import mage.constants.SubType;
import mage.abilities.keyword.EquipAbility;
import mage.abilities.keyword.JobSelectAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.TargetController;
import mage.filter.StaticFilters;
/**
*
* @author anonymous
*/
public final class BlackMagesRod extends CardImpl {
public BlackMagesRod(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{B}");
this.subtype.add(SubType.EQUIPMENT);
// Job select
this.addAbility(new JobSelectAbility());
// Equipped creature gets +1/+0, has "Whenever you cast a noncreature spell, this creature deals 1 damage to each opponent," and is a Wizard in addition to its other types.
Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(1, 0));
ability.addEffect(new GainAbilityAttachedEffect(
new SpellCastControllerTriggeredAbility(
new DamagePlayersEffect(1, TargetController.OPPONENT, "this creature"),
StaticFilters.FILTER_SPELL_A_NON_CREATURE, false
),
AttachmentType.EQUIPMENT
).setText(", has \"Whenever you cast a noncreature spell, this creature deals 1 damage to each opponent,\""));
ability.addEffect(new AddCardSubtypeAttachedEffect(
SubType.WIZARD,
AttachmentType.EQUIPMENT
).setText("is a Wizard in addition to its other types").concatBy("and"));
this.addAbility(ability);
// Equip {3}
this.addAbility(new EquipAbility(3));
}
private BlackMagesRod(final BlackMagesRod card) {
super(card);
}
@Override
public BlackMagesRod copy() {
return new BlackMagesRod(this);
}
}

View file

@ -0,0 +1,44 @@
package mage.cards.c;
import java.util.UUID;
import mage.abilities.effects.common.LookLibraryAndPickControllerEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.PutCards;
import mage.filter.FilterCard;
import mage.filter.common.FilterPermanentCard;
import mage.filter.predicate.Predicates;
/**
* @author balazskristof
*/
public final class CommuneWithBeavers extends CardImpl {
private static final FilterCard filter = new FilterPermanentCard("an artifact, creature, or land card");
static {
filter.add(Predicates.or(
CardType.ARTIFACT.getPredicate(),
CardType.CREATURE.getPredicate(),
CardType.LAND.getPredicate()
));
}
public CommuneWithBeavers(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}");
// Look at the top three cards of your library. You may reveal an artifact, creature, or land card from among them and put it into your hand. Put the rest on hte bottom of your library in any order.
this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(3, 1, filter, PutCards.HAND, PutCards.BOTTOM_ANY));
}
private CommuneWithBeavers(final CommuneWithBeavers card) {
super(card);
}
@Override
public CommuneWithBeavers copy() {
return new CommuneWithBeavers(this);
}
}

View file

@ -0,0 +1,49 @@
package mage.cards.u;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.effects.common.turn.AddExtraTurnControllerEffect;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.abilities.common.TransformIntoSourceTriggeredAbility;
import mage.abilities.keyword.MenaceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
/**
*
* @author anonymous
*/
public final class UltimeciaOmnipotent extends CardImpl {
public UltimeciaOmnipotent(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.NIGHTMARE);
this.subtype.add(SubType.WARLOCK);
this.power = new MageInt(7);
this.toughness = new MageInt(7);
this.color.setBlack(true);
this.color.setBlue(true);
this.nightCard = true;
// Menace
this.addAbility(new MenaceAbility());
// Time Compression -- When this creature transforms into Ultimecia, Omnipotent, take an extra turn after this one.
this.addAbility(new TransformIntoSourceTriggeredAbility(new AddExtraTurnControllerEffect()).withFlavorWord("Time Compression"));
}
private UltimeciaOmnipotent(final UltimeciaOmnipotent card) {
super(card);
}
@Override
public UltimeciaOmnipotent copy() {
return new UltimeciaOmnipotent(this);
}
}

View file

@ -0,0 +1,62 @@
package mage.cards.u;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility;
import mage.abilities.costs.CompositeCost;
import mage.abilities.costs.common.ExileFromGraveCost;
import mage.abilities.costs.common.ExileXFromYourGraveCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.DoIfCostPaid;
import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.effects.keyword.SurveilEffect;
import mage.abilities.keyword.TransformAbility;
import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.target.common.TargetCardInYourGraveyard;
/**
*
* @author anonymous
*/
public final class UltimeciaTimeSorceress extends CardImpl {
public UltimeciaTimeSorceress(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{B}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.WARLOCK);
this.power = new MageInt(4);
this.toughness = new MageInt(5);
this.secondSideCardClazz = mage.cards.u.UltimeciaOmnipotent.class;
// Whenever Ultimecia enters or attacks, surveil 2.
this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new SurveilEffect(2)));
// At the beginning of your end step, you may pay {4}{U}{U}{B}{B} and exile eight cards from your graveyard. If you do, transform Ultimecia.
this.addAbility(new BeginningOfEndStepTriggeredAbility(new DoIfCostPaid(
new TransformSourceEffect(),
new CompositeCost(
new ManaCostsImpl<>("{4}{U}{U}{B}{B}"),
new ExileFromGraveCost(new TargetCardInYourGraveyard(8)),
"{4}{U}{U}{B}{B} and exile eight cards from your graveyard"
)
)));
this.addAbility(new TransformAbility());
}
private UltimeciaTimeSorceress(final UltimeciaTimeSorceress card) {
super(card);
}
@Override
public UltimeciaTimeSorceress copy() {
return new UltimeciaTimeSorceress(this);
}
}

View file

@ -0,0 +1,57 @@
package mage.cards.w;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.continuous.AddCardSubtypeAttachedEffect;
import mage.abilities.effects.common.continuous.BoostEquippedEffect;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.abilities.keyword.EquipAbility;
import mage.abilities.keyword.JobSelectAbility;
import mage.constants.AttachmentType;
import mage.constants.SubType;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
/**
* @author balazskristof
*/
public final class WhiteMagesStaff extends CardImpl {
public WhiteMagesStaff(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{W}");
this.subtype.add(SubType.EQUIPMENT);
// Job select
this.addAbility(new JobSelectAbility());
// Equipped creature gets +1/+1, has "Whenever this creature attacks, you gain 1 life," and is a Cleric in addition to its other types.
Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(1, 1));
ability.addEffect(new GainAbilityAttachedEffect(
new AttacksTriggeredAbility(new GainLifeEffect(1)),
AttachmentType.EQUIPMENT
).setText(", has \"Whenever this creature attacks, you gain 1 life,\""));
ability.addEffect(new AddCardSubtypeAttachedEffect(
SubType.CLERIC,
AttachmentType.EQUIPMENT
).setText("is a Cleric in addition to its other types").concatBy("and"));
this.addAbility(ability);
// Equip {3}
this.addAbility(new EquipAbility(3));
}
private WhiteMagesStaff(final WhiteMagesStaff card) {
super(card);
}
@Override
public WhiteMagesStaff copy() {
return new WhiteMagesStaff(this);
}
}

View file

@ -20,8 +20,11 @@ public final class FinalFantasy extends ExpansionSet {
this.blockName = "Final Fantasy"; // for sorting in GUI
this.hasBasicLands = false; // temporary
cards.add(new SetCardInfo("Adventurer's Inn", 271, Rarity.COMMON, mage.cards.a.AdventurersInn.class));
cards.add(new SetCardInfo("Black Mage's Rod", 90, Rarity.COMMON, mage.cards.b.BlackMagesRod.class));
cards.add(new SetCardInfo("Chaos, the Endless", 221, Rarity.UNCOMMON, mage.cards.c.ChaosTheEndless.class));
cards.add(new SetCardInfo("Cloud, Planet's Champion", 552, Rarity.MYTHIC, mage.cards.c.CloudPlanetsChampion.class));
cards.add(new SetCardInfo("Commune with Beavers", 102, Rarity.COMMON, mage.cards.c.CommuneWithBeavers.class));
cards.add(new SetCardInfo("Cooking Campsite", 31, Rarity.UNCOMMON, mage.cards.c.CookingCampsite.class));
cards.add(new SetCardInfo("Emet-Selch, Unsundered", 218, Rarity.MYTHIC, mage.cards.e.EmetSelchUnsundered.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Emet-Selch, Unsundered", 394, Rarity.MYTHIC, mage.cards.e.EmetSelchUnsundered.class, NON_FULL_USE_VARIOUS));
@ -43,6 +46,9 @@ public final class FinalFantasy extends ExpansionSet {
cards.add(new SetCardInfo("Stiltzkin, Moogle Merchant", 327, Rarity.RARE, mage.cards.s.StiltzkinMoogleMerchant.class, NON_FULL_USE_VARIOUS));
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("Ultimecia, Omnipotent", 247, Rarity.UNCOMMON, mage.cards.u.UltimeciaOmnipotent.class));
cards.add(new SetCardInfo("Ultimecia, Time Sorceress", 247, Rarity.UNCOMMON, mage.cards.u.UltimeciaTimeSorceress.class));
cards.add(new SetCardInfo("White Mage's Staff", 42, Rarity.COMMON, mage.cards.w.WhiteMagesStaff.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

@ -0,0 +1,30 @@
package mage.abilities.keyword;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.CreateTokenAttachSourceEffect;
import mage.game.permanent.token.HeroToken;
/**
* @author balazskristof
*/
public class JobSelectAbility extends EntersBattlefieldTriggeredAbility {
public JobSelectAbility() {
super(new CreateTokenAttachSourceEffect(new HeroToken()));
}
protected JobSelectAbility(final JobSelectAbility ability) {
super(ability);
}
@Override
public String getRule() {
return "Job select <i>(When this Equipment enters, " +
"create a 1/1 colorless Hero creature token, then attach this to it.)</i>";
}
@Override
public JobSelectAbility copy() {
return new JobSelectAbility(this);
}
}

View file

@ -36,6 +36,7 @@ public enum SubType {
MINE("Mine", SubTypeSet.NonBasicLandType),
POWER_PLANT("Power-Plant", SubTypeSet.NonBasicLandType),
TOWER("Tower", SubTypeSet.NonBasicLandType),
TOWN("Town", SubTypeSet.NonBasicLandType),
// 205.3h Enchantments have their own unique set of subtypes; these subtypes are called enchantment types.
AURA("Aura", SubTypeSet.EnchantmentType),
BACKGROUND("Background", SubTypeSet.EnchantmentType),

View file

@ -0,0 +1,23 @@
package mage.game.permanent.token;
import mage.MageInt;
import mage.constants.CardType;
import mage.constants.SubType;
/**
* @author balazskristof
*/
public class HeroToken extends TokenImpl {
public HeroToken() {
super("Hero Token", "1/1 colorless Hero creature token");
this.power = new MageInt(1);
this.toughness = new MageInt(1);
cardType.add(CardType.CREATURE);
subtype.add(SubType.HERO);
}
private HeroToken(final HeroToken token) { super(token); }
public HeroToken copy() { return new HeroToken(this); }
}

View file

@ -2773,6 +2773,7 @@
# FIN
|Generate|TOK:FIN|Food|||FoodToken|
|Generate|TOK:FIN|Hero|||HeroToken|
# JVC
|Generate|TOK:JVC|Elemental Shaman|||ElementalShamanToken|

View file

@ -76,6 +76,7 @@ Intimidate|instance|
Ingest|new|
Islandcycling|cost|
Islandwalk|new|
Job select|new|
Jump-start|card|
Kicker|manaString|
Level up|cost|

View file

@ -57186,9 +57186,12 @@ Tifa, Martial Artist|Final Fantasy Commander|206|M|{1}{R}{G}{W}|Legendary Creatu
Sidequest: Catch a Fish|Final Fantasy|31|U|{2}{W}|Enchantment|||At the beginning of your upkeep, look at the top card of your library. If it's an artifact or creature card, you may reveal it and put it into your hand. If you put a card into your hand this way, create a Food token and transform this enchantment.|
Cooking Campsite|Final Fantasy|31|U||Land|||{T}: Add {W}.${3}, {T}, Sacrifice an artifact: Put a +1/+1 counter on each creature you control. Activate only as a sorcery.|
Stiltzkin, Moogle Merchant|Final Fantasy|34|R|{W}|Legendary Creature - Moogle|1|2|Lifelink${2}, {T}: Target opponent gains control of another target permanent you control. If they do, you draw a card.|
White Mage's Staff|Final Fantasy|42|C|{1}{W}|Artifact - Equipment|||Job select$Equipped creature gets +1/+1, has "Whenever this creature attacks, you gain 1 life," and is a Cleric in addition to its other types.$Equip {3}|
Summon: Shiva|Final Fantasy|78|U|{3}{U}{U}|Enchantment Creature - Saga Elemental|4|5|(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)$I, II -- Heavenly Strike -- Tap target creature an opponent controls. Put a stun counter on it.$III -- Diamond Dust -- Draw a card for each tapped creature your opponents control.|
Black Mage's Rod|Final Fantasy|90|C|{1}{B}|Artifact - Equipment|||Job select$Equipped creature gets +1/+0, has "Whenever you cast a noncreature spell, this creature deals 1 damage to each opponent," and is a Wizard in addition to its other types.$Equip {3}|
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.|
Commune with Beavers|Final Fantasy|102|C|{G}|Sorcery|||Look at the top three cards of your library. You may reveal an artifact, creature, or land card from among them and put it into your hand. Put the rest on hte bottom of your library in any order.|
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.|
@ -57201,6 +57204,9 @@ Garland, Knight of Cornelia|Final Fantasy|221|U|{B}{R}|Legendary Creature - Huma
Chaos, the Endless|Final Fantasy|221|U||Legendary Creature - Demon|5|5|Flying$When Chaos dies, put it on the bottom of its owner's library.|
Gladiolus Amicitia|Final Fantasy|224|U|{4}{R}{G}|Legendary Creature - Human Warrior|6|6|When Gladiolus Amicitia enters, search your library for a land card, put it onto the battlefield tapped, then shuffle.$Landfall -- Whenever a land you control enters, another target creature you control gets +2/+2 and gains trample until end of turn.|
Sin, Spira's Punishment|Final Fantasy|242|R|{4}{B}{G}{U}|Legendary Creature - Leviathan Avatar|7|7|Flying$Whenever Sin enters or attacks, exile a permanent card from your graveyard at random, then create a tapped token that's a copy of that card. If the exiled card is a land card, repeat this process.|
Ultimecia, Time Sorceress|Final Fantasy|247|U|{3}{U}{B}|Legendary Creature - Human Warlock|4|5|Whenever Ultimecia enters or attacks, surveil 2.$At the beginning of your end step, you may pay {4}{U}{U}{B}{B} and exile eight cards from your graveyard. If you do, transform Ultimecia.|
Ultimecia, Omnipotent|Final Fantasy|247|U||Legendary Creature - Nightmare Warlock|7|7|Menace$Time Compression -- When this creature transforms into Ultimecia, Omnipotent, take an extra turn after this one.|
Adventurer's Inn|Final Fantasy|271|C||Land - Town|||When this land enters, you gain 2 life.${T}: Add {C}.|
Cloud, Planet's Champion|Final Fantasy|552|M|{3}{R}{W}|Legendary Creature - Human Soldier Mercenary|4|4|During your turn, as long as Cloud is equipped, it has double strike and indestructible.$Equip abilities you activate that target Cloud cost {2} less to activate.|
Sephiroth, Planet's Heir|Final Fantasy|553|M|{4}{U}{B}|Legendary Creature - Human Avatar Soldier|4|4|Vigilance$When Sephiroth enters, creatures your opponents control get -2/-2 until end of turn.$Whenever a creature an opponent controls dies, put a +1/+1 counter on Sephiroth.|
Ugin, Eye of the Storms|Tarkir: Dragonstorm|1|M|{7}|Legendary Planeswalker - Ugin|7|When you cast this spell, exile up to one target permanent that's one or more colors.$Whenever you cast a colorless spell, exile up to one target permanent that's one or more colors.$+2: You gain 3 life and draw a card.$0: Add {C}{C}{C}.$-11: Search your library for any number of colorless nonland cards, exile them, then shuffle. Until end of turn, you may cast those cards without paying their mana costs.|