-
Notifications
You must be signed in to change notification settings - Fork 820
AbilityFactory
AbilityFactory parses differently from the Keyword parser. Your Ability line will look more like a collection of name-value pairs:
A:<AB/SP/DB/ST>$ <AFSubclass> | <Necessary$ Parameters> | (<Separated$ By> | <Pipes$ Here>) | [Optional$ {Values} [Nested$ Dependency]]
The ability types are:
- AB for Activated Abilities
- SP for Spell
- DB for Drawback and many abilities that are subsidiary to other things, like replacements. They are only used to chain AFs together, and will never be the root AF
-
ST for Static, this gets used in case the API should resolve without using the stack
(e.g. the unique Circling Vultures special action is directly implemented in the script this way)
Syntax definitions like the above will use different symbols to separate the variable parts from the plaintext:
- angle brackets for mandatory parts
- square brackets for optional parts
- round brackets for grouping parts that are exclusive to each other
- curly brackets to denote the type of a parameter
NOTE:
- these factories are refactored from time to time (often to adapt to new mechanics), so while some entries could be slightly outdated, the base information should still be correct
- when in doubt you can always cross-check with the available APIs code
- a few factories also have *All variants, these are slowly being phased out
- some parameters are only added for very exotic cards, these won't be included here to keep the focus on understanding the general concepts of scripting
- a good knowledge of the game rules is often helpful for some of the more complex cases covered
Tip: the convention is to put most of these before AF-specific params for readability (with the exception of Descriptions better suited at the very end)
Cost$ {AbilityCost} is the appropriate way to set the cost of the ability. Currently for spells, any additional costs including the original Mana cost need to appear in the Cost param in the AbilityFactory. For each card that uses it, the order in which the cost is paid will always be the same.
Secondary abilities such as those executed by triggers or replacements (usually) don't need costs. (This is one reason to use DB over AB in these cases.)
Read more about it in Costs
Most effects need to know (at least implicitly) which players or objects they're trying to affect. There are two different ways for that:
-
Defined$ {Defined}if the ability describes on what it's applied -
ValidTgts$ {Valid}for abilities that target
Read more about it in Affected / Targets
Restrictions limit when abilities can be put on the stack and Conditions apply during resolving. Typical examples are "Activate only once each turn" or "If this spell’s additional cost was paid, [...]".
Read more about it in Restriction
SpellDescription$ {String} is how the text of the ability will display on the card and in the option dialog for cards with multiple abilities.
The SpellDescription for secondary abilities is displayed when (and if) the ability prompts for user input in the prompt pane so it is useful to put some text there or rather split the text into the different effect parts.
StackDescription$ {String} is the description the ability will have on the stack. This is automatically generated by the effect, but may be overridden using this parameter. This is sometimes needed with complex effects, when the generated text can't handle some details. Properties of the spell can be accessed like this: {c:Targeted}. You can reuse the spell text by just putting SpellDescription or None to leave it empty.
Remembering is often needed when a card becomes a new object, which is then further affected by the ability. Typical example: Flicker
Because cards keep their remembered parts when changing zones manual cleanup is usually required.
611.2a. A continuous effect generated by the resolution of a spell or ability lasts as long as stated by the spell or ability creating it (such as "until end of turn"). If no duration is stated, it lasts until the end of the game.
Values:
- EndOfTurn (Default)
Note: since more often an effect only lasts until end of turn this was chosen as default instead of following how the rule defines it - Permanent
- AsLongAsControl
- AsLongAsInPlay - it really depends on each card's wording if this or the below one is correct, since here CR 702.26f defines phasing out as an extra way of ending the effect
- UntilHostLeavesPlay - if the effect should last while the host is still in play
- UntilEndOfCombat
- UntilYourNextTurn
-
IsCurse$ True- for effects that are normally treated positive e.g. Pump -
AICheckSVar$ {Count} -
AILogic$ {String} -
AITgts$ BetterThanEvalRating.130Normally the AI will only prefer targeting cards that satisfy the constraint. However, you can addAITgtsStrict$ Trueif playing it should only happen when enough of these cards are available, e.g. Rootwater Matriarch.
Animate handles animation effects like "This card becomes a 5/5 green creature with flying until end of turn."
Parameters (all optional):
-
Power- the power to assign to the animated card -
Toughness- the toughness to assign to the animated card -
Types/RemoveTypes- the types to give to/remove from the animated card; comma delimited -
RemoveSuperTypes/RemoveCardTypes/RemoveSubTypes$/RemoveCreatureTypes True- if the animated being should have these types instead as opposed to in addition to -
Keywords/RemoveKeywords- a " & " delimited list of keywords to give to/remove from the animated being -
Colors- a comma-delimited list of colors to give to the animated being (capitalized and spelled out)-
ChosenColoraccepted
-
-
Abilities/Replacements/Triggers/staticAbilities- a comma-delimited list of SVar names which contain abilities that should be granted to the animated being -
RemoveAllAbilities- Remove all Abilities, Triggers, Statics and Replacement effects -
sVars- a comma-delimited list of SVars that should be granted to the animated being
Attaches a permanent to an affected card or player.
Parameters:
-
Object$ {Defined}(Default: Self) - This is the Object that will be Attached -
Choices$ {ValidCard}- can be used to choose the attachment instead
can also be combined withObjectso the choice is for what it should attach to RememberAttached
Note that Forge's engine handles this automatically for Aura spells, so adding AILogic is a bit different but usually required:
SVar:AttachAILogic:{String}
-
Curse/Pump- A generic Curse/Pump for which the AI has a handful of checks to see if an appropriate target exists -
GainControl- Gains control of the attached permanent -
ChangeType- For attachments that change types, e.g. Evil Presence
No own parameters.
Soulbonding two creatures. Only used internally by the engine.
Sometimes, an ability might do certain things when a specific condition is true, and others if not. This can be implemented by using Branch.
Parameters:
BranchConditionSVar$ {Count}BranchConditionSVarCompare {comparator}-
TrueSubAbility/FalseSubAbility$ {SubAbility}- executes the specified ability depending on how the condition evaluated
The example below is from Composer of Spring, which allows either a "land" or a "land or creature" to be put on the battlefield, depending on the number of enchantments you control:
SVar:TrigBranch:DB$ Branch | BranchConditionSVar$ X | BranchConditionSVarCompare$ GE6 | TrueSubAbility$ PutLandCreature | FalseSubAbility$ PutLand
SVar:PutLand:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | Tapped$ True | ChangeType$ Land.YouOwn
SVar:PutLandCreature:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | Tapped$ True | ChangeType$ Creature.YouOwn,Land.YouOwn
SVar:X:Count$Valid Enchantment.YouCtrl
Note: sometimes you could also implement this via standard ability Conditions instead, but that requires careful consideration if the relevant property could be changed by one of the applicable effects.
This AF represents modal effects.
Parameters:
-
CharmNum$ {Integer}(Default: 1) - number of modes to choose -
MinCharmNum$ {Integer}(Default: same as CharmNum) - if "up to" allows a variable number -
Choices$ {SubAbilities}- a comma delimited list of SVars containing the modes
AF in this group let the player make choices from all kinds of categories and are often used to chain effects together. However, for common cases many effects already support this directly, e.g. PutCounter | Choices$.
Besides making the script more concise using such shortcuts usually also helps the AI making better use of the effect.
This can be used when a player is asked to choose a card (sub)type.
Parameters:
-
Type- Typically "Card", "Creature" or a few special cases -
ValidTypes {String}- alternative to above param to explicitly define the types -
InvalidTypes$ {String}(Optional) - used to specify any type that can't be chosen
This AF handles clashing.
Parameters:
-
WinSubAbility$(Optional) -
OtherwiseSubAbility$(Optional)
A non-functional, maintenance AF used for cleaning up certain variables before a spell finishes resolving.
Parameters:
-
ClearRemembered$ True- clear this card's remembered list. Generally useful for abilities that remember an object, do something to it, then need to forget it once it's done -
ClearImprinted$ True- clear the imprinted cards -
ClearChosenCard$ True- clear the chosen cards
Parameters:
-
NewController$ {Defined}(Default: You)
Copies a permanent.
Parameters:
-
NumCopies(Default: 1) - the number of copies to put onto the battlefield. -
Keywords(Optional) - a list of keywords to add to the copies
Parameters:
-
Num$ {Integer}(Default: 1)
Countering Spells or Abilities.
Parameters:
-
Destination- send countered spell to: (only applies to Spells; ignored for Abilities)- TopDeck
Factories to handle counters on cards or players.
Poison gives a player the specified number of poison counters.
Parameters:
-
Num$ {Integer}- the number of poison counters to give
Put any type of counter on a game object.
Parameters:
-
CounterType- specifies the type of counter and should appear in all caps -
CounterNum$ {Integer}(Default: 1) - how many counters will be put on the chosen card Placer$ {Defined}-
ETB$ True- for ETB counters
Remove any type of counter from a game object.
- CounterType (required) specifies the type of counter and should appear in all caps. It should be one of the values in the Counters enum.
- CounterNum (required) specifies how many counters will be removed from the chosen card.
- UpTo is optional. If an effect states you may remove "up to X counters", set this to True.
Used for effects that move counters.
Parameters:
-
Source- The Source of the counters -
Defined- The Destination of the counters -
CounterType- The type of counter to move -
CounterNum- The number of counters to move
Deal damage to a specified player or permanent.
Parameters:
-
NumDmg$ {Integer}- amount of damage dealt
Removing Keywords.
Parameters:
KeywordsDuration
Handles destruction of permanents.
Parameters:
NoRegen$ True
Effect is an oddball of the AF family. Where usually AFs have similarities to each other to help with AI use, this one's used for all sorts of continuous effects.
A good example is High Tide. It doesn't matter if the Island was in play, if it turned into an Island after the spell resolved, any of that.
A:SP$ Effect | Triggers$ IslandTrigger | SpellDescription$ Until end of turn, whenever a player taps an Island for mana, that player adds an additional {U}.
SVar:IslandTrigger:Mode$ TapsForMana | ValidCard$ Island | Execute$ TrigMana | Static$ True | TriggerDescription$ Whenever a player taps an Island for mana, that player adds an additional {U}.
SVar:TrigMana:DB$ Mana | Produced$ U | Amount$ 1 | Defined$ TriggeredActivator
Effect is most similar to Token as it creates a pseudo-permanent, except Effect creates in the command zone rather than the battlefield.
Parameters:
-
Abilities,Triggers,ReplacementEffects,StaticAbilities,SVars- comma separated lists which contain SVars that point to the appropriate type that the Effect will gain. You don't need to put the zone-specific params like EffectZone$ onto these DurationEffectOwner$ {Defined}-
ForgetOnMoved$ {ZoneType}- gets rid of the effect if all remembered cards have left the affected zone RememberObjects$ {Defined}-
Stackable$ False- most effects are assumed to be stackable. By using this flag, the AI will know having a second one active is (at least mostly) useless, so it will save its resources for something else -
Name$ {String}(Optional) - usually auto-generated -
Image$ filename\without\extension(Optional) - image needs to reside in the tokens directory
This AF is based on the original Fog spell: "Prevent all combat damage that would be dealt this turn." While this could be done with an Effect, the specialized nature of the AI gives it its own AF.
Have a player gain or lose the specified amount of life.
Parameters:
-
LifeAmount$ {Integer}- the value to modify the life total(s)
Used in the script of Karn Liberated.
Repeat the specified ability.
Parameters:
-
MaxRepeat- optional - the maximum times to repeat, execute repeat ability at least once -
RepeatSubAbility- setup subability to repeat -
RepeatOptional$ True- you make the choice whether to repeat the process - RepeatPresent, RepeatCompare, RepeatDefined, RepeatCheckSVar, RepeatSVarCompare - optional - condition check
A more complex variant that iterates over objects of some type instead. During each RepeatSubAbility execution the current object is remembered.
Parameters:
-
RepeatSubAbility- required - to set up repeat subability -
RepeatCards- to repeat for each valid card (zone: present zone of the valid repeat cards, default: battlefield) DefinedCards-
RepeatPlayers- to repeat for each valid player -
RepeatCounters- to repeat for each valid counters
Add mana to a player's mana pool.
Parameters:
Produced$ {String}
AF for effects that alter a permanent's state.
Changing a cards state. This is mostly for Flip Cards or the Transform mechanic.
Playing cards as part of another ability. The player may have to make a choice about which card to play if there are more choices than the number of cards to play.
Parameters:
-
Amount$ {Integer/All}(Default: 1) - how many cards can be played -
Valid- selection criteria for valid cards from the zone to cast -
ValidSA- applied after Valid, this will filter based on all spells of the cards -
ValidZone- the zone to look in to determine the valid cards -
Optional$ True- playing is optional -
RememberPlayed$ True- remember the card played PlayCost$ {AbilityCost}-
WithoutManaCost$ True- The card can be cast without its normal mana cost -
Controller$ {Defined}(Default: You) - controller of the ability
Grants protection from traits like colors or card types.
Parameters:
-
Gains- the thing to gain protection from (green, artifacts, Demons, etc.) or "Choice" if you can choose one of a comma-delimited list ofChoices$
Handles pumping creatures power/toughness or granting keywords to cards or players.
Parameters (all optional):
-
NumAtt$- pumps Power -
NumDef$- pumps Toughness -
KW$- gives keywords
Due to its generic nature Pump is also the conventional "helper AF" when an effect requires more than one target with different restrictions, e.g. Political Trickery:
A:SP$ Pump | ValidTgts$ Land.YouCtrl | TgtPrompt$ Choose target land you control | SubAbility$ DBExchange | SpellDescription$ Exchange control of target land you control and target land an opponent controls. (This effect lasts indefinitely.)
SVar:DBExchange:DB$ ExchangeControl | Defined$ ParentTarget | ValidTgts$ Land.OppCtrl | TgtPrompt$ Choose target land an opponent controls
Creating regeneration shields.
Look at a player's hand.
Parameters:
-
RevealValidto limit the valid cards AnyNumberRandom-
RememberRevealedto remember the cards revealed
This AF is very similar to things that Dig can do, but handle a much simpler form, with less complex coding underneath. Similar to how RearrangeTopOfLibrary could be handled with Dig.
Primarily used with cards that allow you to Peek at the top card of your library, and allow you to reveal it if it's of a certain type. The Kinship cards fit this bill perfectly, so they are used to simplify the complex popups that would be required if using multiple Dig SubAbilities.
Parameters:
-
RevealOptional- Whether or not the Reveal is optional. -
RememberRevealed- Whether to remember the revealed cards (after filtering by Valid) -
RememberPeeked- Whether to remember the peeked cards (only if they are not revealed!) -
RevealValid- defaults to Card, but allows you to set a specific ValidType if you can only have certain things -
PeekAmount- defaults to 1, but allows you to peek at multiple cards if possible
Forces a player to sacrifice something of their choice.
Parameters:
-
SacValid$ {ValidCard}(Default: Card.Self)
Token lets you create tokens of any type. They get defined by creating scripts in the res/tokenscripts folder.
Parameters:
-
TokenScript$ {filename[,filename]}- list of tokens to create -
TokenAmount$ {Integer}(Default: 1) -
TokenOwner$ {DefinedPlayer}(Default: You)
If possible split the SpellDescription of the effect so the part for the trigger can become the StackDescription directly.
The trigger-specific params are defined in Triggers.
Parameters:
-
TriggerAmount$ {Integer}(Default: 1)
No own parameters.
For effects that modify zones in a specific manner.
ChangeZone is a united front of any card that changes zone. This does not include: drawing, destroying, etc. as these represent specific words on which triggers and replacements can react.
Two primary forms are available after setting these parameters, depending on how the effect is templated:
-
Origin$ {ZoneType}is where the card is coming from -
Destination$ {ZoneType}is where the card is going to -
LibraryPosition {Integer}(Default: 0) - ignored when not moving to library. 0 represents the top, -1 the bottom
Hidden syntax
Hidden is generally used for origin zones that are not known information, e.g. the Library. The choice of "What card is changing zones?" happens during resolution. If you need this for public zones Hidden$ True is required.
Example (Call the Gatewatch):
A:SP$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Planeswalker | SpellDescription$ Search your library for a planeswalker card, reveal it, put it into your hand, then shuffle.
Parameters:
ChangeType$ {ValidCard}ChangeNum$ {Integer}-
Chooser$ {DefinedPlayer} -which player decides which card changes zone -
Mandatory$ True- most of these abilities aren't mandatory, but CR 701.23d. means cards like Demonic Tutor are different
Known syntax
The second is known, instead designed for origin zones that are known information, like the battlefield. The choice of "What card is changing zones?" happens when it's put on the stack (or is at least fixed some other way).
Example (Excommunicate):
A:SP$ ChangeZone | ValidTgts$ Creature | Origin$ Battlefield | Destination$ Library | LibraryPosition$ 0 | SpellDescription$ Put target creature on top of its owner's library.
This is a helper AF, for chained effects that create multiple permanents which should enter the battlefield at the same time.
To use it, you need to set the param ChangeZoneTable$ True on the first effect and then call this at the end.
This is supported by the following effects:
- Amass
- CopyPermanent
- RepeatEach (NOTE: if you wrap the creation, you don't need to call this AF on its own)
- Token
Dig is for an ability that does basically this: "You look at the X cards of your Library, put Y of them somewhere, then put the rest somewhere."
Parameters:
-
DigNum$ {Integer}- look at the top X number of cards -
Reveal$ True(Default: False) -
ChangeNum$ {Integer/Any/All}(Default: 1)- the number of cards to move to the DestinationZone
- "Any" if you can move any number of Cards to DestinationZone
- "All" when it's for things like "put all lands revealed this way into your hand"
-
ChangeValid$ {ValidCard}(Default: Card) - use this to specify if only certain types can be moved to DestinationZone -
Optional$ True(Default: False) - if you "may" move a card to DestinationZone -
SourceZone$ {ZoneType}(Default: Library) - the zone to dig in -
DestinationZone$ {ZoneType}(Default: Hand) - the zone to put the Y cards in -
DestinationZone2$ {ZoneType}(Default: Library) - the zone to put the rest in -
LibraryPosition/LibraryPosition2 {Integer}(Default: -1) - if DestinationZone is Library, use this to specify position
Parameters:
-
NumCards$ {Integer}(Default: 1) - the number of cards to discard -
Mode$ {String}- the mode of discard- Random
- TgtChoose
- RevealYouChoose
- Hand
-
DiscardValid$ {ValidCard}(Default: Card) - acceptable cards to discard -
UnlessType$ {ValidCard}- expression for "discard X unless you discard valid"
Parameters:
-
NumCards$ {Integer}(Default: 1) - the number of cards to draw
Parameters:
-
NumCards$ {Integer}(Default: 1) - the number of cards to mill
Used for shuffling a player's library.
Parameters:
-
Optional$ True- if the activator gets to decide if each affected player shuffles
-
Adventure Mode
-
Gameplay Guide
-
Tutorials
-
-
Development
-
Customization & Themes