Use this file to discover all available pages before exploring further.
Every mechanical behavior in XMage — from tapping a land to produce mana, to a triggered ability firing when a creature attacks, to a planeswalker loyalty activation — is modelled as an Ability paired with one or more Effect objects. Understanding which abstract base class to extend, and when to reach for a pre-built class in mage.abilities.common, is the key skill for implementing new cards efficiently. This page covers all the ability types available in the mage.abilities package and the effect categories in mage.abilities.effects, with working code examples drawn directly from the XMage source.
All abilities implement mage.abilities.Ability, which extends both Controllable and Serializable. The interface exposes the core components of any ability:
AbilityType getAbilityType() — returns the enum constant identifying this ability’s category (e.g. AbilityType.ACTIVATED_NONMANA, AbilityType.TRIGGERED_NONMANA, AbilityType.STATIC).
Costs<Cost> getCosts() / ManaCosts<ManaCost> getManaCosts() — the costs that must be paid to activate or use the ability.
Effects getEffects() — the list of effects that resolve when the ability resolves.
Targets getTargets() — targeting information.
UUID getSourceId() / UUID getControllerId() — the permanent or spell this ability belongs to, and who controls it.
The concrete base for nearly every ability is AbilityImpl, which provides implementations for all of these. You will rarely extend AbilityImpl directly — instead extend one of the specialised subclasses described below.
Activated abilities have an explicit cost that the controller chooses to pay. They go on the stack. The abstract base ActivatedAbilityImpl holds the timing (TimingRule.INSTANT by default) and maxActivationsPerTurn / maxActivationsPerGame limits.For straightforward cases, use SimpleActivatedAbility from mage.abilities.common:
// SimpleActivatedAbility(Effect effect, Cost cost) — defaults to Zone.BATTLEFIELD// SimpleActivatedAbility(Zone zone, Effect effect, Cost cost) — explicit zone// {3}: Untap this permanent.this.addAbility(new SimpleActivatedAbility( new UntapSourceEffect(), new GenericManaCost(3)));// {T}: Draw a card.this.addAbility(new SimpleActivatedAbility( new DrawCardSourceControllerEffect(1), new TapSourceCost()));
When you need multiple costs, chain addCost():
Ability ability = new SimpleActivatedAbility( new DamageTargetEffect(2), new TapSourceCost());ability.addCost(new ManaCostsImpl<>("{R}"));ability.addTarget(new TargetAnyTarget());this.addAbility(ability);
mage.abilities.mana.SimpleManaAbility is the preferred class for mana-producing activated abilities. It handles the mana pool correctly and is recognised by the engine as a mana ability (which means it does not use the stack).
Setting optional = true means the controller will be asked “Do you want to use this ability?” when it triggers.mage.abilities.common provides many ready-made triggered abilities. EntersBattlefieldTriggeredAbility is one of the most common:
// When this creature enters, draw a card.this.addAbility(new EntersBattlefieldTriggeredAbility( new DrawCardSourceControllerEffect(1)));
When a custom triggered ability is needed, write it as a package-private inner class in the same file as the card. The Goblin Guide pattern (from mage/cards/g/GoblinGuide.java) is the canonical template:
class GoblinGuideTriggeredAbility extends TriggeredAbilityImpl { public GoblinGuideTriggeredAbility(Effect effect, boolean optional) { super(Zone.BATTLEFIELD, effect, optional); } private GoblinGuideTriggeredAbility(final GoblinGuideTriggeredAbility ability) { super(ability); } @Override public boolean checkEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.ATTACKER_DECLARED; } @Override public boolean checkTrigger(GameEvent event, Game game) { if (event.getSourceId().equals(this.getSourceId())) { UUID defenderId = game.getCombat() .getDefendingPlayerId(getSourceId(), game); if (defenderId != null) { for (Effect effect : this.getEffects()) { effect.setTargetPointer(new FixedTarget(defenderId, game)); } return true; } } return false; } @Override public String getRule() { return "Whenever {this} attacks, defending player reveals the top card " + "of their library. If it's a land card, that player puts it " + "into their hand."; } @Override public GoblinGuideTriggeredAbility copy() { return new GoblinGuideTriggeredAbility(this); }}
Static abilities are always in effect while the permanent is on the battlefield (or, for some, in other zones). They do not use the stack. StaticAbility extends AbilityImpl with AbilityType.STATIC and zone Zone.BATTLEFIELD by default.Use SimpleStaticAbility for the common case:
// SimpleStaticAbility(Effect effect) — Zone.BATTLEFIELD// SimpleStaticAbility(Zone zone, Effect effect) — explicit zone// This permanent doesn't untap during your untap step.this.addAbility(new SimpleStaticAbility( new DontUntapInControllersUntapStepSourceEffect()));// Other creatures you control get +1/+1.this.addAbility(new SimpleStaticAbility( new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES, true)));
SimpleEvasionAbility (also in mage.abilities.common) is the preferred wrapper for evasion rules like Menace, Fear, and Intimidate, since the engine treats evasion abilities differently from other static effects when calculating blocks:
// Can't be blocked except by two or more creatures (Menace).this.addAbility(new SimpleEvasionAbility( new CantBeBlockedByOneEffect()));
SpellAbility is the default ability that lets a card be cast from hand. CardImpl creates it automatically in its constructor — you do not instantiate it yourself. You access it via this.getSpellAbility() to attach effects and targets for instants and sorceries:
// The spell deals 3 damage to any target.this.getSpellAbility().addEffect(new DamageTargetEffect(3));this.getSpellAbility().addTarget(new TargetAnyTarget());
Planeswalker loyalty abilities extend ActivatedAbilityImpl with TimingRule.SORCERY and a PayLoyaltyCost. Pass a positive integer for +N abilities and a negative integer for −N abilities:
// +1: Put a +1/+1 counter on up to one target creature.Ability plusOne = new LoyaltyAbility( new AddCountersTargetEffect(CounterType.P1P1.createInstance()), 1);plusOne.addTarget(new TargetCreaturePermanent(0, 1));this.addAbility(plusOne);// -3: Target creature gains flying and double strike until end of turn.Ability minusThree = new LoyaltyAbility( new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), -3);minusThree.addEffect(new GainAbilityTargetEffect( DoubleStrikeAbility.getInstance(), Duration.EndOfTurn));minusThree.addTarget(new TargetCreaturePermanent());this.addAbility(minusThree);// -8: Create X 2/2 white Cat tokens, where X is your life total.this.addAbility(new LoyaltyAbility( new CreateTokenEffect(new CatToken(), ControllerLifeCount.instance), -8));
A DelayedTriggeredAbility is created at resolution time and placed into the game state to fire on a future event. Use it when an effect says something like “at the beginning of the next end step, do X”. You create the ability inside a OneShotEffect and register it with the game:
// Inside an OneShotEffect.apply():DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility( new DrawCardSourceControllerEffect(1));game.addDelayedTriggeredAbility(delayedAbility, source);
Pre-built delayed ability wrappers for common timing windows (end step, next upkeep, next combat) live in mage.abilities.common.
Effects are attached to abilities and carry out the mechanical action when the ability resolves. All effects live in the mage.abilities.effects package (and its common/ subdirectory).
Persists over time (often until end of turn, or while a condition is met). The engine re-evaluates these continuously. Subtypes include ContinuousEffect for stat modifications, ContinuousRuleModifyingEffect for rule changes, and ReplacementEffect for event replacement.
// Give a creature +2/+2 until end of turn — a ContinuousEffectImplthis.addAbility(new SimpleActivatedAbility( new BoostSourceEffect(2, 2, Duration.EndOfTurn), new ManaCostsImpl<>("{2}")));// All creatures you control gain flying until end of turnthis.getSpellAbility().addEffect( new GainAbilityControlledEffect( FlyingAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES));
Replaces a game event with a different one before it happens. For example, replacing “draw a card” with “draw two cards” or replacing “this permanent would be destroyed” with “exile it instead”. Implement ReplacementEffect and override replaces(GameEvent, Ability, Game) and apply(GameEvent, Ability, Game).
A specialised replacement effect that prevents damage. Implement PreventionEffect and override applies(GameEvent, Ability, Game) to select which damage events to intercept, then apply(GameEvent, Ability, Game) to reduce or zero out the damage value.
Allows something to happen “as though” a condition were true — for example, casting cards from exile as though they were in your hand, or activating abilities as though it were your turn. Extend AsThoughEffectImpl and specify an AsThoughEffectType.
Before writing a custom ability or effect class, search mage.abilities.common and mage.abilities.effects.common. These two packages contain hundreds of reusable implementations covering nearly every standard Magic mechanic. Using them keeps card code short, consistent, and easier to maintain. Common examples include EntersBattlefieldTriggeredAbility, AttacksTriggeredAbility, DiesSourceTriggeredAbility, SimpleStaticAbility, SimpleActivatedAbility, DrawCardSourceControllerEffect, DamageTargetEffect, CreateTokenEffect, AddCountersTargetEffect, and GainAbilityControlledEffect.
import mage.abilities.common.SimpleActivatedAbility;import mage.abilities.costs.common.TapSourceCost;import mage.abilities.costs.mana.GenericManaCost;import mage.abilities.effects.common.DrawCardSourceControllerEffect;// {2}, {T}: Draw a card.Ability drawAbility = new SimpleActivatedAbility( new DrawCardSourceControllerEffect(1), new TapSourceCost());drawAbility.addCost(new GenericManaCost(2));this.addAbility(drawAbility);
When no pre-built class fits and you need a custom triggered ability, the minimal implementation requires:
A class extending TriggeredAbilityImpl (or ActivatedAbilityImpl / StaticAbility) with its own copy constructor and copy().
An effect class extending OneShotEffect or ContinuousEffectImpl with apply() and copy().
Both the ability and its effects must implement copy() returning a new MyClass(this) — this is required for correct game-state serialisation and AI cloning.
// Custom OneShotEffect skeletonclass MyEffect extends OneShotEffect { MyEffect() { super(Outcome.Benefit); staticText = "draw a card"; // shown in the tooltip } private MyEffect(final MyEffect effect) { super(effect); } @Override public MyEffect copy() { return new MyEffect(this); } @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { controller.drawCards(1, source, game); return true; } return false; }}