[TLA] Implement Appa, Steadfast Guardian

This commit is contained in:
theelk801 2025-08-12 18:03:15 -04:00
parent 66b96cc232
commit 5841d63c60
6 changed files with 225 additions and 0 deletions

View file

@ -0,0 +1,70 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.keyword.AirbendTargetEffect;
import mage.abilities.keyword.FlashAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterNonlandPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.game.permanent.token.AllyToken;
import mage.target.TargetPermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AppaSteadfastGuardian extends CardImpl {
private static final FilterPermanent filter = new FilterNonlandPermanent("other target nonland permanents you control");
static {
filter.add(AnotherPredicate.instance);
filter.add(TargetController.YOU.getControllerPredicate());
}
public AppaSteadfastGuardian(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.BISON);
this.subtype.add(SubType.ALLY);
this.power = new MageInt(3);
this.toughness = new MageInt(4);
// Flash
this.addAbility(FlashAbility.getInstance());
// Flying
this.addAbility(FlyingAbility.getInstance());
// When Appa enters, airbend any number of other target nonland permanents you control.
Ability ability = new EntersBattlefieldTriggeredAbility(new AirbendTargetEffect());
ability.addTarget(new TargetPermanent(0, Integer.MAX_VALUE, filter));
this.addAbility(ability);
// Whenever you cast a spell from exile, create a 1/1 white Ally creature token.
this.addAbility(new SpellCastControllerTriggeredAbility(
Zone.BATTLEFIELD, new CreateTokenEffect(new AllyToken()), StaticFilters.FILTER_SPELL_A,
false, SetTargetPointer.NONE, Zone.EXILED
));
}
private AppaSteadfastGuardian(final AppaSteadfastGuardian card) {
super(card);
}
@Override
public AppaSteadfastGuardian copy() {
return new AppaSteadfastGuardian(this);
}
}

View file

@ -21,6 +21,8 @@ public final class AvatarTheLastAirbender extends ExpansionSet {
this.rotationSet = true; this.rotationSet = true;
this.hasBasicLands = false; // temporary this.hasBasicLands = false; // temporary
cards.add(new SetCardInfo("Appa, Steadfast Guardian", 10, Rarity.MYTHIC, mage.cards.a.AppaSteadfastGuardian.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Appa, Steadfast Guardian", 316, Rarity.MYTHIC, mage.cards.a.AppaSteadfastGuardian.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Avatar Enthusiasts", 11, Rarity.COMMON, mage.cards.a.AvatarEnthusiasts.class)); cards.add(new SetCardInfo("Avatar Enthusiasts", 11, Rarity.COMMON, mage.cards.a.AvatarEnthusiasts.class));
cards.add(new SetCardInfo("Earthbending Lesson", 176, Rarity.COMMON, mage.cards.e.EarthbendingLesson.class)); cards.add(new SetCardInfo("Earthbending Lesson", 176, Rarity.COMMON, mage.cards.e.EarthbendingLesson.class));
cards.add(new SetCardInfo("Fire Nation Attacks", 133, Rarity.UNCOMMON, mage.cards.f.FireNationAttacks.class)); cards.add(new SetCardInfo("Fire Nation Attacks", 133, Rarity.UNCOMMON, mage.cards.f.FireNationAttacks.class));

View file

@ -0,0 +1,122 @@
package mage.abilities.effects.keyword;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.costs.Cost;
import mage.abilities.costs.Costs;
import mage.abilities.costs.CostsImpl;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.AsThoughEffectType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author TheElk801
*/
public class AirbendTargetEffect extends OneShotEffect {
public AirbendTargetEffect() {
super(Outcome.Benefit);
}
private AirbendTargetEffect(final AirbendTargetEffect effect) {
super(effect);
}
@Override
public AirbendTargetEffect copy() {
return new AirbendTargetEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
Set<Permanent> permanents = this
.getTargetPointer()
.getTargets(game, source)
.stream()
.map(game::getPermanent)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
if (player == null || permanents.isEmpty()) {
return false;
}
player.moveCards(permanents, Zone.EXILED, source, game);
Cards cards = new CardsImpl(permanents);
cards.retainZone(Zone.EXILED, game);
for (Card card : cards.getCards(game)) {
game.addEffect(new AirbendingCastEffect(card, game), source);
}
game.fireEvent(GameEvent.getEvent(
GameEvent.EventType.AIRBENDED, source.getSourceId(),
source, source.getControllerId()
));
return true;
}
@Override
public String getText(Mode mode) {
if (staticText != null && !staticText.isEmpty()) {
return staticText;
}
return "airbend " + getTargetPointer().describeTargets(mode.getTargets(), "");
}
}
class AirbendingCastEffect extends AsThoughEffectImpl {
AirbendingCastEffect(Card card, Game game) {
super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.AIDontUseIt);
this.setTargetPointer(new FixedTarget(card, game));
}
private AirbendingCastEffect(final AirbendingCastEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public AirbendingCastEffect copy() {
return new AirbendingCastEffect(this);
}
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
Card card = game.getCard(getTargetPointer().getFirst(game, source));
if (card == null) {
discard();
return false;
}
if (!card.getId().equals(objectId) || !card.isOwnedBy(affectedControllerId)) {
return false;
}
Player player = game.getPlayer(affectedControllerId);
if (player == null) {
return false;
}
Costs<Cost> newCosts = new CostsImpl<>();
newCosts.addAll(card.getSpellAbility().getCosts());
player.setCastSourceIdWithAlternateMana(card.getId(), new ManaCostsImpl<>("{2}"), newCosts);
return true;
}
}

View file

@ -109,6 +109,7 @@ public enum SubType {
BEHOLDER("Beholder", SubTypeSet.CreatureType), BEHOLDER("Beholder", SubTypeSet.CreatureType),
BERSERKER("Berserker", SubTypeSet.CreatureType), BERSERKER("Berserker", SubTypeSet.CreatureType),
BIRD("Bird", SubTypeSet.CreatureType), BIRD("Bird", SubTypeSet.CreatureType),
BISON("Bison", SubTypeSet.CreatureType),
BITH("Bith", SubTypeSet.CreatureType, true), // Star Wars BITH("Bith", SubTypeSet.CreatureType, true), // Star Wars
BLINKMOTH("Blinkmoth", SubTypeSet.CreatureType), BLINKMOTH("Blinkmoth", SubTypeSet.CreatureType),
BOAR("Boar", SubTypeSet.CreatureType), BOAR("Boar", SubTypeSet.CreatureType),

View file

@ -696,6 +696,7 @@ public class GameEvent implements Serializable {
*/ */
PAY_SACRIFICE_COST, PAY_SACRIFICE_COST,
EARTHBENDED, EARTHBENDED,
AIRBENDED,
FIREBENDED, FIREBENDED,
// custom events - must store some unique data to track // custom events - must store some unique data to track
CUSTOM_EVENT; CUSTOM_EVENT;

View file

@ -0,0 +1,29 @@
package mage.game.permanent.token;
import mage.MageInt;
import mage.constants.CardType;
import mage.constants.SubType;
/**
* @author TheElk801
*/
public final class AllyToken extends TokenImpl {
public AllyToken() {
super("Ally Token", "1/1 white Ally creature token");
cardType.add(CardType.CREATURE);
color.setWhite(true);
subtype.add(SubType.ALLY);
power = new MageInt(1);
toughness = new MageInt(1);
}
private AllyToken(final AllyToken token) {
super(token);
}
public AllyToken copy() {
return new AllyToken(this);
}
}