-
Notifications
You must be signed in to change notification settings - Fork 88
CardCode
This is an explanation on how to add your own cards to Wagic. Please try to create your own sets and share them with everyone! If you have questions, feel free to ask them in our Discord.
This is a work in progress. Please report any errors, ambiguities, or incomprehensible passages to our Discord. Some statements in this document still require checking, these have been marked with (??).
The cards used in Wagic can be found in the Res/sets/ folder. This folder contains several subfolders, one for every set.
Each of these subfolders contains a _cards.dat file. As long as this file is included in a subdirectory of the "sets" folder, the cards it describes will be automatically loaded into the game.
For example: Having a file _Res/sets/MYSet/_cards.dat will automatically create a set called MYSet, which contains all cards specified in this _cards.dat file, whenever you start the game.
So what does this _cards.dat file look like? Well, you can open one of those with any text editor (Notepad, for example), and you'll see that it is a list of:
[card] (content)
[/card]
So what can be put in contents?
Contents is a list of keys and values spearated by a = sign. the keys can be the following:
- name
- primitive
- grade
- id
- rarity
- mana
- kicker
- color
- type
- subtype
- power
- toughness
- text
- target
- abilities
- auto
- autohand
- autograveyard
- alias
name, id, rarity, and type are compulsory. The other ones, in some circumstances, are needed as well (such as toughness and power for "regular" creatures). Text is compulsory if you do not plan to add pictures (or plan to add pictures that do not have that text) to your set.
# nameDescription: name denotes the name of the card
Example:
name=Grizzly Bears
Further information: The engine currently adds names to the list of types, to make cards like "Plague Rats" work. This shouldn't affect anything else, but if you're giving a card a name that is also a type (for example, naming a card "Goblin"), we advise thorough testing.
# primitiveDescription: primitive tells the engine to read all information for that card from a list of "primitives", which already contains an entry of this name.
Example:
primitive=Grizzly Bears
Usage: The idea of this feature is to allow you to add "reprints" of cards into your set very easily. For example, if you want to add a reprint of "Royal Assassin" to your set, you only have to specify its id, its rarity, and the line primitive=Royal Assassin. Since Royal Assassin has already been coded (and inlcuded in the primitives file), all other data for the card will be taken from there.
This also means that you don't need to update your set when wechange the coding of Royal Assassin - your set will always load the information from the primitives file, which in this case will contain the updated version of Royal Assassin.
# gradeDescription: gives a hint on the quality of the code of the card, how well the card respects the actual rules printed on it
Example:
grade=Borderline
Usage: Currently 5 values are accepted for the grade: Supported, Borderline, Unofficial, Crappy, Unsupported, Dangerous. When this line is not specified, the default grade is Supported. Here are the meanings of these values:
- Supported: Wagic handles this card 100% correctly, or the issues encountered with it are minor. This card can go into an AI Deck
- Borderline: Wagic handles this card correctly in most cases. In some edge cases, the card will not work as expected but this shouldn't be too much of an issue (example: Drain Life can use non black mana). Please think about it twice before putting such a card in an AI Deck
- Unofficial: The person who coded this card claims that you can use it, and according to this person, this card works as advertised. The only difference with such a card and a "Borderline" card is that the Wagic team hasn't had the time to review this card yet and mark it as "Supported" or "Borderline".
- Crappy: Wagic handles this card, but there are some side effects that can make it completely unbalanced. For example, an effect supposed to end at the end of the turn will last as long as the card is in play... DO NOT add a card marked as Crappy into an AI Deck
- Unsupported: The card doesn't work, mostly. For example for a creature, it can mean that its special abilities are not supported at all, and it will just be an expensive Vanilla creature. This is just for people who want to play with the card because they like the art, for example. Do not put these cards in an AI Deck
- Dangerous: This card can potentially crash Wagic. Even if it works 99% of the time, that's not our concern here. Of course, do not put those into an AI Deck!
Additionally, Wagic players have an option to choose which cards they want to have in their database. By default, this option is set to "Borderline", which means that both Supported and Borderline cards will be loaded at startup. Players who want to experiment with less safe cards can change this value. Next time the game is restarted, it will load the additional cards.
It is the role of the cards creators and developers to determine if a card goes to "Supported", "Borderline", or "Crappy". The line between these 3 categories is extremely thin, and the decision can take into account the popularity of the card, the inconvenience caused by the bugs, the difficulty involved with solving the bugs, etc... As a policy, the Wagic team will not accept bug reports for cards that are marked as "Crappy", "Unsupported", or "Dangerous". This can also be used as a factor in the decision to rank a card (especially between crappy and Borderline).
Note: it is possible to assign a grade to an entire primitive file by setting the grade at the very top of your file, BEFORE the first [card] tag.
Description: id is a unique integer identifying the card. This id cannot be the same as any other id used in this set or in any other set.
Example:
id=174908
Usage: To keep ids unique, it's best (for Magic cards) to use the id referenced at the Gatherer site. For example: http://www.wizards.com/gatherer/CardDetails.aspx?&id=49 (Bad Moon alpha), the id is 49, as you can see from the number at the end of the URL.
For your own sets, try to choose an id range that no other sets use. Official sets use ids between 1 and about 250,000, so for your own sets, we suggest using values between 1,000,000 (one million) and 2,000,000,000 (two billion).
The engine stores collections and decks as lists of card ids. If a card is part of a collection, and its id gets changed, then the engine will notice that it does not have a card of that id in its database, and remove it from the collection.
The id will also be used to retrieve the picture for the card. For the card with the id 1,234,567 in set MySet, the engine will look for a card picture with the path and filename Res/sets/MySet/1234567.jpg, and a thumbnail picture Res/sets/MySet/thumbnails/1234567.jpg
Thumbnails must have a size of 45x64 pixels, and pictures must be 200x285.
# rarityDescription: rarity denotes the probability of a card to be found in a booster pack. Valid values are C, U, R, M, L, T and respectively mean Common, Uncommon, Rare, Mythic Rare, Land, Token.
Example: rarity=U (for an Uncommon card)
Notes: Currently, a booster pack will have 1 card with rarity L, 10 cards with rarity C, 3 cards with rarity U, one card with rarity R (which has a 1/8 chance to be of of rarity M instead), and no cards of rarity T.
The T rarity can be used to create tokens with complex rules (see below).
Description: mana denotes the cost needed to play the card from the hand. Each part of the cost is enclosed in braces {}. Valid values are {W}, {U}, {B}, {R}, and {G} (meaning (W)hite, bl(U)e, (B)lack, (R)ed, and (G)reen respectively), and also integers like {3}, {16}, or {0}, which denote costs that can be paid with mana of any color.
Colorless Mana {c} are costs which can be paid by colorless mana only. All permanents that produce colorless mana produces {c} now.
To represent hybrid mana, you put two mana symbols inside the same braces.
Additional valid values:
-
{D}(Discarding a random card) -
{E}/{E(target|zone)}(Exiles something) -
{H}/{H(target|zone)}(Returns something to your hand) -
{i}(For Snow costs. Any mana produced by snow permanents can be used) -
{L:number}(life loss) -
{M}(Puts a card from the top of you library) -
{s2l}(put * target|whereever * on top of your library) -
{s2g}(put * target|whereever * on graveyard) (useful for cards that moves from exile to graveyard) -
{X}or{X}{X}(now 2 {X} are possible! (Card example:Decree of Justice)) -
{l2e}(Exiles the top card of you library )
Examples:
-
mana={W}{R}{R}(one white and two red mana) -
mana={3}{G}(1 green mana, and 3 mana of any color) -
mana={U}{WB}(1 blue mana, and one mana which can be either white or black) -
mana={2R}{2R}{2R}(3 red mana, but each one of those could also be paid by 2 mana of any other colors)
It is possible to specify any additional or alternative costs (like sacrificing or tapping cards) in the mana= line. Some kinds of additional costs can be snuck in by other means, see [cost of activated abilities](#auto cost).
# kicker (cost)Description: kicker denotes an additional cost that may be paid when playing the card. It uses the same format as [cost of activated abilities](#auto cost). You can specify effects for a card which apply only if its kicker cost was paid (see kicker (condition) for these).
Example: A card that gives you 1 life if you pay its normal cost of {W}, but an additional 4 life if you pay an additional cost of {1}{W}, could be coded like this:
mana={W}
kicker={1}{W}
auto=life:1 controller
auto=kicker life:4 controller
# other (cost)
Description: other denotes an alternate cost that may be paid instead of the mana cost, to play the card. It uses the same format as [cost|cost of activated abilities]](#auto). You can specify effects for a card which apply only if its "other" cost was paid (see [(condition)|alternative (condition)] for these).
# flashback (cost)Description: flashback denotes an alternate cost that may be paid to play the card from a graveyard instead of playing it from your hand.It uses the same format as [cost|cost of activated abilities]]([#auto). Such a card will be moved to your "exile" zone after being played through it flashback cost. Therefore this cost makes sense only for sorceries and instants
# buyback (cost)Description: buyback denotes an alternate cost that may be paid when playing the card. It uses the same format as [cost|cost of activated abilities]]([#auto). If the buyback cost was paid, the card will go back to your hand instead of going to the graveyard once it resolves. Therefore buyback only makes sense for sorceries and instants. Note that buyback is an additional cost in MTG, but is described as an alternate cost in Wagic. So you need to include the original mana cost as well
Example: A card that gives you 1 life if you pay its normal cost of {W}, but goes back to your hand if you pay an additional cost of {1}{W}, could be coded like this:
mana={W}
buyback={1}{W}{W}
auto=life:1 controller
Description: color denotes the color of the card. Usually colors get determined automatically from the mana cost, but some cards have special rules which determine their color(s). For these, the color key is provided. Valid values are white, blue, black, red, green, artifact.
Example:
color=red
It is possible to specify several different colors.
Example:
color=white,red,green
Description: type denotes the type(s) and supertype(s) of the card, space separated. Although anything's fine in there, most used values are: Sorcery, Instant, Creature, Artifact, Artifact Creature, Enchantment, Land. These can be prefixed by the following: Legendary, Snow, Basic,...
Examples:
type=Enchantmenttype=Legendary Creaturetype=Basic Land
Limitations:
- While you can specify types and subtypes on two separate lines, the engine currently treats only a few specific hardcoded values as "types" or "supertypes", the rest is treated as subtypes.
Description: subtype denotes all subtypes of the card, separated from each other by a space character.
Examples:
subtype=goblinsubtype=human wizard allysubtype=aura
Usage: Just as type, you can specify a list of several subtypes.
# powerDescription: power is an integer describing the power of the card. It is used for creatures only.
Example:
power=5
Usage: Some cards have a power of *, or " *+1. In this case, specify the value that the term would have if the * was a zero - e.g. power=0 and power=1 for the two examples above. The functionality of the " * can be coded by a later [#auto|auto] rule.
Description: toughness is an integer describing the toughness of the card. It is used for creatures only.
Example:
toughness=5
Usage: Some cards have a toughness of *, or " * + 1. In this case, specify the value that the term would have if the * was a zero - e.g. toughness=0 and toughness=1 for the two examples above. The functionality of the * can be coded by a later [#auto|auto] rule.
Description: text is a text describing the effects of the card. If the text contains a nel line (\n or back returns), then the remaining text would not be displayed, the cpncention is to sepparate with " -- " instead of a new line.
Example:
text=Flying. First Strike. Whenever this creature attacks, draw a card.
Description: abilities denotes those special abilities of a card that can be defined with a single keyword, i.e which don't need any values specified for them.
You can specify several abilities by separating them with commas.
The following abilities are supported:
absorb-
affinityartifacts/affinityforests/affinitygreencreatures/affinityislands/affinitymountains/affinityplains/affinityswamps -
auraward(aura cards with this ability has an exception from protection from quality) -
canplayfromgraveyard(controller can play cards from graveyard as though it were in your hand) cantattackcantblock-
cantlifelose(controller can't lose by getting to 0 life or below) -
cantlose(controller can't lose - Card example:Platinum Angel) -
cantmillose(controller can't lose by getting milled) -
cantregen(creature can't regnerate) -
cantwin(controller cant win the game / opponent cant lose) changeling-
cloud(can only block creatures with flying) -
controllershroud(Card example:True Believer) deathtouchdefender-
doesnotuntap(... during it's controller's untap phase) double strikeexalted-
exiledeath(will send the card to exile instead of to graveyard opon death. Treated as a replacement effect.) fearfirst strikeflashflankingflying-
foresthome/islandhome/mountainhome/plainshome/swamphome -
forestwalk/islandwalk/mountainwalk/plainswalk/swampwalk -
frozen*(card/target will not untap on its controllers next untap phase. Card example:Tangle)_ haste-
hexproof(cannot be targeted by spells or abilities that the opponent controls) horsemanshipindestructibleinfectintimidate-
leylineEnables the coding of the Leyline cycles -
librarydeath/shufflelibrarydeath(cards are moved to the library instead of putting in graveyard) lifelinkluremustattack-
mygraveexiler/oppgraveexiler(exile cards instead of putting in graveyard) -
nofizzle(cannot be countered) -
nolifegain(controller cannot gain life) -
nolifegainopponent(opponent cannot gain life) -
nomaxhand(controller has no maximum max hand) -
nolegend(legendary supertypes are not limited) -
replaced by hexproofopponentshroud persist-
phantom(prevents damage and remove one +1/+1 counter. Card examples:Phantom Centaur,Phantom Nishoba) -
playershroud??? -
poisontoxic/posiontwotoxic/poisonthreetoxis(card adds 1,2 or 3 poison counters to the player if damaged) -
protection from white/protection from blue/protection from black/protection from red/protection from green_(note that there's alsoprotection from(target_type)available as an auto rule)* -
rampage(??) (note that there's alsorampage(p/t,n)available as an auto rule) reach-
reachshadow(can block creatures with shadow) retraceshadowshroudsoulbondstormsunburst-
tokenizer(doubles the amount of tokens produced.. cumulative) trample-
treason(card withabilities=treasonwill be sacrificed at the end of the turn. Card example:Sneak Attack) -
unblockable(note that there's alsocantbeblockedby(target_type)available as an auto rule) vigilance-
vigor(instead of taking damage the source gains +1/+1 counters. Card examples:Phytohydra) -
wilting(source takes damage in the form of -1/-1 counters) witherlegendarylandwalkdesertlandwalk-
snowforestlandwalk/snowplainslandwalk/snowmountainlandwalk/snowislandlandwalk/snowswamplandwalk snowlandwalknonbasiclandwalk-
strong(cant be blocked by creature with less power) -
weak(cant block creatures with more power) phasingsplit second-
spellmastery(special keyword ability used in conjunction for alternative cost.)
Note that despite being supported, some of the abilities don't work like you would expect them to, due to some limitations in the engine.
Example:
abilities=flying,first strike,shadow
As wagic evolves, we simplify some of the abilities, make them more flexible, or get rid of abilities that don't work correctly. We try to stay backwards compatible, but sometimes there's no choice...
-
(deprecated since version 0.15, usebothnocreature(no player can cast creatures)maxCastinstead) -
(deprecated since version 0.15, usebothcantcast(no player can cast spell)maxCastinstead) -
(deprecated since version 0.15, usebothonecast(no player can cast more than one spell per turn)maxCastinstead) -
(deprecated since version 0.15, usecantcreaturecast(card controller cant cast creature)maxCastinstead) -
(deprecated since version 0.15, usecantspellcast(card controller can't cast spells)maxCastinstead) The following abilities were once available, but never worked right and have been removed for the time being:banding
Description: target defines the potential targets for the card.
There is an important distinction between instants/sorceries and other cards. Only instants/sorceries can use the target= key. All other cards specify targets in their auto rules.
The syntax for the target specification is the same though, no matter whether a target is specified with a target= key or inside an auto= rule. Therefore, the complete syntax is explained here.
The syntax is the following:
target=target_type_1[s][,target_type_2[s]][|zone1[,zone2]]
Valid keywords for target_type are:
- any word that can be found in the type or subtype key of any card
-
player(meaning "a player") - the
*symbol (asterisk), meaning "a card of any type" -
this(meaning: the one card that has this rule) -
mytgt(meaning: the target of the card that has this rule. Mytgt uses a very broad definition of "target". For example, an aura can always use mytgt to reference the permanent it enchants asmytgt, even though - according to the rules - it isn't technically targeting it anymore.)
Adding a s to a target means "1 target or more". Otherwise, it is 1 target. Note: This may not work as expected, depending on the effect applied to the targets. (??)
Examples:
| Keyword | Meaning |
|---|---|
creature |
targets one creature |
goblin,player |
targets one goblin OR one player |
wall,land,cat |
targets one wall or land or cat |
* |
targets one card of any type |
elfs |
targets one or more elves - note that the parser doesn't understand irregular plurals, so "elves" would not work |
*s |
targets one or more carda of any type (??) |
Limitations: Although you can use player as a target, you cannot specify anything about this player. For example, you cannot specify opponent (which would be useful for rules like "Whenever this card deals damage to an opponent ...").
A target can be followed by a string inside brackets ([]) to give more specific information on it. Keywords allowed inside the brackets are:
attackingblockingtapped- one or more colors (
white,blue,black,red,green,artifact) - one or more abilities, such as
flying. -
power,toughness, and/ormanacost -
gearlooks if a card is equippedthis(gear !=0) effector how many artifacts are on a cardthisforeach(equip) effect -
fresh-fresh|zonedonates a card that was placed into the determined zone this turn.freshworks for the zonesbattlefieldandgraveyard. -
multicolordenotes multicolored target -
levelerchecks if the card is a level up card -
enchantedchecks if the card is enchanted - the following checks if both the colors are present on the target -
blackandgreenblackandwhiteredandblueblueandgreenredandwhite
Keywords inside brackets can be prefixed by a minus (-) sign that means "not". For example, -tapped means "not tapped", i.e. untapped, or -multicolor means "not multicolored", i.e. monocolored.
Keywords inside brackets are separated by a semicolon (;). Currently, the relation between these restrictions is "or" if there is no minus sign inside the brackets and if the restrictions are of the same kind (for example, both are colors, or both are abilities), and "and" otherwise. (??) This has led to confusion and will probably change in the future.
Each of the three keywords power, toughness, and manacost, can be followed by one of three comparison operators: = (equal to), <= (less than or equal), <= (greater than or equal); and then by an integer, to which the value will be compared.
Examples:
| Expression | Meaning |
|---|---|
creature[blue] |
(targets one blue creature) |
artifact[-tapped] |
(targets one untapped artifact) |
creature[-black;-artifact] |
(targets one creature that is not black AND is not an artifact) |
creature[elf;warrior] |
(targets one creature that is an elf OR a warrior OR both) |
cleric[toughness<=4] |
(targets one cleric whose toughness is 4 or less) |
aura[manacost>=3] |
(targets one aura which has a converted manacost of 3 or more) |
creature[fresh] |
(targets a creature which was a put into the determined zone this turn) |
Limitations: Target resrictions are currently not available for targets using the keywords player, this or mytgt. So, unfortunately, it is not yet possible to code cards with rules like "When this card attacks ...", because aslongas(this[attacking;fresh]) cannot be parsed.
You can limit the targeting of your card to specific zones. The following zones are available:
battlefield, graveyard, library, hand, stack, exile, *
The asterisk ( * ) means "all zones". You can also use the term inplay synonymous for battlefield, and removedfromgame synonymous for exile.
The default value for zones is inplay.
Battlefield encompasses the whole battlefield, graveyard encompasses all graveyards, library encompasses all libraries, etc. This is often not desired, so you can limit the zone further by preceding its name with one of the following terms:
my, opponent, owner, targetcontroller, targetowner
The prefix and the zone name form a single word, e.g. mybattlefield (for: anything on the battlefield under my control) or opponentgraveyard.
These prefixes are always seen from the perspective of the player who controls the card that uses them in its code. Let's say I'm playing against "Sheila", and I control a creature called "Painter", which lets me target a graveyard and change the color of all cards inside to green. The following table shows which graveyard would be affected by this ability, depending on the prefix used before "graveyard":
| Prefix | Meaning | "Painter" affects ... |
|---|---|---|
| (none) | (the whole zone) | ... all graveyards of all players |
my |
(zone/cards controlled by the controller of the targeting card) | ... my graveyard, because I'm controlling Painter |
opponent |
(zone/cards controlled by the opponent of the targeting card's controller) | ... Sheila's graveyard, because she's the opponent of Painter |
owner |
(zone/cards controlled by the owner of the targeting card) | ... usually my graveyard, assuming that Painter was originally part of my deck. If Painter was originally part of Sheila's deck, and I merely took control of it during play, then Sheila is Painter's owner, and her graveyard would be targeted. |
targetcontroller |
(zone/cards controlled by the controller of the targeted card) | If target is a player, targetcontroller will be that player. If target is a card, targetcontroller will be that card's controller |
targetowner |
(zone/cards controlled by the owner of the targeted card) | If target is a player, targetcontroller will be that player. If target is a card, targetcontroller will be that card's owner |
Limitations:
-
Anything that allows a player to look into a library will cause the library to be shuffled after the effect has resolved.
-
mybattlefieldreally means "the zone formed by all permanents on the battlefield which I control". It does not mean "my half of the duel screen". This is important for auras cast on opponent creatures: these are displayed in their opponent's half of the screen, but nevertheless belong to their controller'sbattlefield.
All this sounds pretty complex, but it's not. Let's see some working examples:
| Expression | Meaning |
|---|---|
creature |
(any creature in play) |
artifact,enchantment |
(any artifact or enchantment in play) |
* graveyard |
(any card in any graveyard) |
creature,player |
(any creature or player in play) |
mountains |
(one or more mountains in play) |
artifact,enchantment mygraveyard |
(any artifact or enchantment in your graveyard) |
creature[-black;-artifact] |
(any non black, non artifact creature in play (that's what actually used for Terror) |
* stack |
(any spell on the stack) |
If you cannot describe the target with the available keywords, then you're doomed, you cannot add the card to the game without coding.
auto is the most complex key, as it allows to program the behavior of the cards to some extent. If you cannot add what you want with auto, it means you cannot add the card to the game without recompiling it.
Unlike other parameters, auto can appear several times in one card description.
Please note that the "auto" parameter is changing very often, and we cannot guarantee that future releases will be backward compatible!
Values for auto often consist of several parts. An (approximated) general syntax for auto values is this (values inside brackets [] are optional):
[$cost:|$trigger:] [$conditions] [$effect] [&& $further effects] [$target|$playertarget] [$restrictions]
The individual parts and their meaning:
- [cost](#auto cost) - the cost for activating this effect
- [trigger](#auto triggers) - an event that triggers this effect
- [conditions](#auto conditions) - special conditions which need to be fulfilled for this effect to take place
- [effect](#auto effects) - the effect itself
- [further effects](#auto effects) - additional effects
- [target](#auto target)|[playertarget](#auto playertarget) - the target(s) of the effect(s)
- [restrictions](#auto restrictions) - restrictions that apply to this rule, e.g. when and how often it can be activated
The order of elements if often interchangeable, but not always. The order used in this reference will give you maximal safety that your code can be parsed correctly. This can be important because the parser is a bit stingy with error messages (you'll only get any if you compile the game in debug mode, and even then they are sparse).
Spaces are necessary in some places, forbidden in some, and optional in some other places. The easiest rule to prevent problems is to never put a space in front of a ( character.
Colons are important signposts for the parser, make sure that you use them correctly (look at the examples provided here).
## auto costFor most effects, cost is an optional parameter. If an auto rule has no cost, then it will be executed whenever the card is played or enters the battlefield. For example, a creature coded with auto=life:2 would give its controller 2 life whenever it enters the battlefield. The effects of most instants and sorceries are coded without a cost as well, since their cost is being paid when casting the spell.
If an auto rule has a cost, then this denotes an activated ability of this card. In an auto rule, cost may contain any of the following elements:
- any kind and number of mana costs, specified with the same syntax as for [keys
- one
{T}symbol, for "tap this permanent", or{T([target])}, where target is anything that could be represented in a target key.
- one sacrifice, which can be specified either as
{S}(for "sacrifice this permanent"), or{S([target])}, where target is anything that could be represented in a target key.
-
{E}/{E(target|zone)}(Exiles something as additional casting/activation cost) -
{H}/{H(target|zone)}(Returns something to your hand as additional casting/activation cost) -
{L:number}(life loss as additional casting/activation cost,correct use must be {L:1} for 1 life, only {L} causes bugs) -
{L:number}(specific life loss as additional casting/activation cost) -
{D}(Discarding a random card as additional casting/activation cost) -
{M}(Puts a card from the top of you library as additional casting/activation cost) -
{N}(cost of returning an unblocked attacker to your hand) -
{Q}(Untap as a cost) -
{discard(target|zone)}_targeted discard cost Note: You have to type in one{D}and{M}for each of the autoline's activation (see "Examples"). -
{s2l}(put * target|whereever * on top of your library as additional casting/activation cost) -
{l2e}(Exiles the top card of you library as additional casting/activation cost.Card example:Arc-Slogger)
Examples:
-
{T}:- (tap this card) -
{G}{T}:- (pay one green mana and tap this card) -
{1}{S(goblin|mybattlefield)}:- (pay 1 mana and sacrifice a goblin you control) -
{S(*|myhand)}:- (choose and discard a card - discarding is technically very similar to "sacrificing from the hand") (??) -
{0}:- (This ability can be activated without any cost, but it needs to be activated, it does not fire automatically or continuously) -
{L:3}{B}{S(creature|mybattlefield)}:- (pay 3 life, 1 black mana and sacrifice a creature you control) -
{E( * |mygraveyard)}{T}:- (exile a card from your graveyard and tap this card) -
{T(elf|mybattlefield)}{T(elf|mybattlefield)}:- (tap 2 elves you control) As you can see, there are no limitations in combining the different auto costs.
Limitations:
-
previously only one targeted cost was possible, this is no longer the case. it is now possible to denote as many targeted cost in a single cost line as you wish.
-
Note that for targeted sacrifice costs, you always have to add a target zone (usually
|myinplay), otherwise the player will be able to sacrifice cards controlled by the opponent.
Triggers are effects that are executed not immediately, but when a certain event occurs. Each trigger defines the event that triggers it.
Triggers are declared with the keyword @, and end with a colon : The most basic trigger syntax is:
@$trigger: [$effect]
The following triggers are available in Wagic:
- [phase-based triggers](#phase-based triggers): trigger on phase start
-
@movedto: trigger on a card having changed zones -
@attacking: trigger on a card declared as an attacker -
@blocking: trigger on a card declared as an blocker -
@blocked: trigger on an attacking card being blocked -
@notblocked: trigger on an unblocked attacking card -
@damaged: trigger on a card or player being damaged -
@combatdamaged: trigger on a card or player being combat damaged -
@noncombatdamaged: trigger on a card or player being damaged by a noncombat source. -
@tapped: trigger on a card becoming tapped -
@tappedformana: trigger on a card becoming tapped for mana -
@untapped: trigger on a card becoming untapped -
@drawn: trigger related to each card draw -
@vampired: triggers when a card is put in graveyard this turn that was damaged by source -
@lifed: trigger related to life gain -
@lifeloss: trigger related to lifeloss -
@targeted: trigger related to a card being targeted -
@discarded: trigger related to cards being discarded -
@sacrificed: trigger related to cards being sacrificed -
@attackedalone: trigger related to when a card attacked alone
Limitation:
- It is currently not possible to pay a #auto cost during a triggered effect.
Controller Trigger:
-
These trigger/s below are for parsing current controller and current opponent of the card/s.
-
@damageof(player): trigger on a card/s current controller being damaged. -
@combatdamageof(player): trigger on a card/s current controller being damaged from combat. -
@noncombatdamageof(player): trigger on a card/s current controller being damaged noncombat. -
@damagefoeof(player): trigger on a card/s current opponent being damaged. -
@combatdamagefoeof(player): trigger on a card/s current opponent being damaged from combat. -
@noncombatdamagefoeof(player): trigger on a card/s current opponent being damaged -
the examples above for controller trigger is also available for:
card/s current controller
@drawof(player)@lifeof(player)@lifelostof(player)card/s current opponent
@drawfoeof(player)@lifefoeof(player)@lifelostfoeof(player)
@[next|each] [my|opponent|targetcontroller] (beginofturn|untap|upkeep|draw|firstmain|combatbegins|attackers|blockers|combatdamage|combatends|secondmain|endofturn|cleanup|beforenextturn): [$effect]
The effect will trigger at the beginning of the respective phase or step.
The keywords next and each determine whether the effect will trigger only the "next" time that the given phase begins, or "each" time that a phase of this name begins (as long as the rule is active).
The keywords my, opponent, and targetcontroller(??) determine whether only phases of the card's controller are counted ("my"), or only phases of the card controller's opponent ("opponent"). If neither of the three is specified, then both players' turns can fire the trigger.
Examples:
| Expression | Meaning |
|---|---|
@each my upkeep:life:2 controller |
(gives the card's controller 2 life at each of his upkeep phases) |
@each combatbegins:life:2 controller |
(gives the card's controller 2 life at each of his upkeep phases) |
@next opponent end:draw:2 opponent |
(lets the opponent draw 2 cards at the end of his next turn) |
Limitations:
It is currently not possible to trigger an effect at the end of a phase or step. A workaround is to let the effect trigger at the beginning of the following step (for example, instead of trying to trigger at the end of upkeep, let the effect trigger at the begin of the draw phase phase). This will work as long as Wagic has no cards which skip steps. (In the above example, skipping the draw phase would skip the trigger, which wouldn't be the desired outcome).
Some phases are currently "messy", and it's not guaranteed that triggers upon them will work. Specifically, the phase beginofturn may be over before all triggers had a chance to fire. The phases from draw to secondmain (including the two themselves) should be safe; for all others, thorough testing is advised.
@movedTo($target) [from($zone)]: [$effect]
The effect will be executed whenever a card matching the target specifications comes from "zone". The "from" parameter is optional and defaults to "anywhere".
Note that the first parameter is a target specification, not just a zone name. This means you can code rules like "Whenever a goblin comes into play ..." with a trigger @movedTo(goblin|battlefield).
@damaged($target1) [from($target2)]: [$effect]
The effect will be executed whenever a card (or player) matching the target1 specifications is damaged by a card matching the target2 specifications. The "from" part is optional and defaults to "any source".
This trigger will fire on any kind of damage being dealt, not only combat damage. An activated ability "Tap this card to deal 1 damage to target player" would cause the trigger to fire as well.
### @tapped@tapped($target): [$effect]
The effect will be executed whenever a card matching the target specifications get tapped.
- note that not all of the triggers can use all of the restrictions, these were added on a "needed" basis.
-
[trigger] once: this trigger will only fire once in its life time then become inactive -
[trigger] sourcenottap: this trigger will only fire if the source is not tapped. -
[trigger] sourcetap: this trigger will only fire if the source is tapped. -
[trigger] opponentpoisoned: this trigger will only fire if the opponent is poisoned. -
[trigger] turnlimited: this trigger will only fire once per turn.
The conditions in this section govern whether or not an effect will be executed. Currently Wagic knows two special conditions, kicker (condition) and may.
### kicker (condition)An effect that uses the term "kicker" in its auto= rule will only be executed if this card's #kicker (cost) was paid. Usually kicker is the first word in the auto= rule. See #kicker (cost) for an example.
kicker payment can be checked through restrictions using the following restriction check
auto=if paid(kicker) then [ability]
auto=ifnot paid(kicker) then [ability]
this allows you a very flexible way of coding effects, even those that replace a cards original form.
MultiKicker is also supported, simply add the word multi before the cost to denote that we will try to pay it more than once.
kicker=multi{b}{b}
you can access the variable for how many times payment was made by using the variable kicked
Dredge is supported with no extra code except dredge=dredge(NUMBER)
Examples:
dredge=dredge(3)
This will automatically give you the choice to draw or dredge when a draw event occurs, it than handles the depletion on it's own.
using the following lines allows you to denote that draw abilities will be replaced by a specified ability.
auto=replacedraw ABILITY
or for your opponent
auto=opponentreplacedraw ABILITY
it is important that the draw replacement be the first thing in the string to parse. it can be used in other abilities such as transforms subkeyword newability[however it still has to be the first thing parsed, the replacement ability is parsed after the white space.
Limitations: if you replace a draw with a draw ability, you need to use a subkeyword of draw:X , draw:2 noreplace. noreplace denotes that the draw was located in an ability that replaces draw effects, it runs the run ability a second time without sending a draw event. draw events and drawn card events are separate.
The may keyword is used to represent the text "When ... comes into play, you may ... ". When this rule is executed, then player will see a menu pop up, which will allow him to choose the rule's effect or cancel. The effect following the may keyword will only be executed if the player chose to do so.
Example:
-
auto=may life:2- (When this comes into play, you may gain 2 life.) -
auto=may bury target(creature)- (When this comes into play, you may bury target creature.) -
auto=@movedTo( *|stack[white]: may life:1 controller- (Whenever a white spell is cast, you may gain 1 life.)
Limitations:
-
Maywas designed for "comes into play" effects. It also works for triggers like the one in the last example. It may not work in other circumstances (e.g. in activated abilities), so thorough testing is advised for these cases. -
If a card has more than one
mayrule active in a given situation, then these rules will compete with each other (see [competing effects](#competing effects)). The player may choose one of them, but not more.
A wide (and ever-increasing) range of effects is available for auto= rules. The following effects are currently supported:
-
[cost:] bury [target]- destroys target, it cannot be regenerated -
[cost:] destroy [target]- destroys target -
[cost:] damage:n [target|playertarget]- does n damage to target. n may be a [variable](#auto parsed integers). -
[cost:] regenerate [target]- regenerates target creature -
[cost:] tap [target]- taps a target. If no target is available, taps the card itself -
[cost:] untap [target]- untaps a target. If no target is available, untaps the card itself -
[cost:] moveTo($zone) [target]- moves target card into specified zone. Allowed keywords forzoneare those listed under [target zone](#target zones). -
[cost:] [$ability] [target]* - gives ability to target. "ability" can be any of the keywords described in the ability section previously. For auras, instants and sorceries, cost is usually empty. For instants, sorceries, and activated abilities, the effect lasts until end of turn. For auras, it lasts as long as the aura is present. If a minus sign is used, this removes the ability from the target. -
[cost:] n/m [target]- gives +n/+m (+n power and +m toughness) to the target creature. n and m can be negative, or zero, or [variables](#auto parsed integers). For auras, instants and sorceries, cost is usually empty. For instants, sorceries, and activated abilities, the effect lasts until end of turn. For auras, it lasts as long as the aura is present. -
[cost:] counter(p/t,n,name) [target]- put n p/t counters on target creature. If n is negative, remove -n p/t counters from target creature. n defaults to 1. Name can be any name you can imagine acommon example counters with the nameCharge:counter(0/0,1,Charge). -
[cost:] add{mana}- Mana producer. Adds mana if the user pays [cost](#auto cost) . [cost](#auto cost) can be emtpy, or contain only{t}, which is the case for basic lands. -
[cost:] token(name,types], p/t, [[$abilities]] [[$colors]])[ * n]* - puts n tokens with name "name", types "types", power p, toughness t, abilities "abilities" and colors "colors" into play. Default value for n is 1. n may also be a [variable](#auto parsed integers). An example (Dragon Roost (10E)):
auto={5}{R}{R}:token(Dragon,creature dragon, 5/5,flying red)
Note: If you have specified the token in any _cards.dat file as its own card (with rarity T and id i), then you can simplify the command to: _ cost:token(i)[ * n]. It is recommended to use the negative id of the token-creating card as the id for the token, to prevent incompatibilities.
-
[$cost:] cycling- sends the card to the graveyard and draws a new one from the library -
[$cost:] fizzle $target- cancel a spell on the stack. The [target zone](#target zones) defaults tostack. -
[$cost:] copy $target- become a copy of target (used for clone) -
[$cost:] becomes(subtype, p/t, abilities, colors) $target- target becomes a card of types "types", power p, toughness t, abilities "abilities" and colors "colors". p and t may be #auto parsed integers. Cannot be used for activated abilities yet. Note: This feature is still experimental and needs thorough testing. -
[$cost:] transforms($types or $subtypes,$color,$ability)- similar tobecomes. The main difference is that you can change single parameters of a permanent like only color or type. -- (Card examples:Memnarch,Wild Mongrel) -
[$cost:] equip [$target]- equips target with the card. target defaults tocreature|myBattlefield. Can only be activated in the controller's main phases. -
[$cost:] attach [$target]- same asequip, but can be used anytime its controller has priority. -
protection from($target)- gives the card protection from all cards that match the criteria specified in target. Cannot be used in activated abilities or sorceries/instants. Can be used as continuous effect (as a permanent ability of the card, or transferred via aura / lord / etc.) -
cantbeblockedby($target)- makes the card unblockable by creatures that match the criteria specified in target. Can be used in anything if you use the ueot ability wrapper. -
cantbeblockeof($target)- makes the target unable to block creatures that match the criteria specified in target. Can be used in anything if you use the ueot ability wrapper. -
cantbeblockerof(this)- makes the source card unblockable by the targeted creatures. Can be used in anything if you use the ueot ability wrapper. -
[$cost:] maxCast($target) $n- sets the Maximum number of spells (defined by target) a player can cast (move to the stack) per turn -
[$cost:] maxPlay($target) $n- sets the Maximum number of cards (defined by target) a player can put into play (move to the battlefield) per turn. The difference with maxCast is that maxPlay can be used on cards that don't use the stack, such as lands. -
[$cost:] preventallcombatdamage [to($target1] [from($target2)]- no combat damage can be dealt from creatures matching the target2 specification to targets matching the target1 specification, for the duration of this effect.from()andto()are both optional and default to "anyone". This is a fairly recent feature, thorough testing is advised. -
[$cost:] fog- This is similar topreventallcombatdamage, which only worked for instants and sorceries.Fogworks only for permanents and is used in combination withoneshot -
[$cost:] preventallnoncombatdamage [to($target1] [from($target2)]- Extension of preventallcombatdamage, prevents all noncombat damage [from a target to a target]. -
[$cost:] preventalldamage [to($target1] [from($target2)]- Extension ofpreventallcombatdamage, prevents all damage (=combat damage + noncombat damage) [from a target to a target]. -
[$cost:] prevent:x- damage prevention to single creatures and players. (Card examples:Healing Salve,Battlefield Medic) -
[$cost:] rampage(p/t,n) [$target]- Whenever target creature gets blocked, it gets+p/+tfor each blocker beyond thenth.ndefaults to1. -
[$cost:] draw:n [$playertarget]- drawncards.nmay be a [variable](#auto parsed integers). -
[$cost:] life:n [$playertarget]- gainnlife. Ifnis negative, lose-nlife.nmay be a [variable](#auto parsed integers). -
[cost:] deplete:n [$playertarget]- movencards from the top of the library to the graveyard.nmay be a [variable](#auto parsed integers). -
[cost:] hmodifier:n [$playertarget]- increases or decreases player/s hand size.nmay be a [variable](#auto parsed integers). -
[cost:] ingest:n [$playertarget]- movencards from the top of the library to the exile.nmay be a [variable](#auto parsed integers). -
[$cost:] discard:n [$playertarget]- randomly discardncards -
[$cost:] shuffle [$playertarget]- shuffles the library of playertarget. Usually used in conjunction with other effect that affect the library without shuffling it by themselves. For example, "Pay {U}: Shuffle this card back into your library" can be coded as{U}:moveto(this|mylibrary) && shuffle -
[$cost:] lord($targets) [$effect] [$other]- Continuously applies effect to all cards matching the target desciption. effect is any effect that would work in an "auto=" line. other is used if the ability should not be applied the lord card itself. (Example: Lord of Atlantis islord(merfolk) islandwalk.) -
[$cost:] all($targets) [$effect] [$other]-all()works identical tolord(), but guarantees that the action will occur only once. Whenever you have problems withlord(), try to useall()instead. Example:bury all(creature) -
[$cost:] foreach($targets) [$effect] [$other] [$criterion]- Applies effect as many times as the amount of cards matching the target description.
- effect is any effect that would work in an
auto=line. - other is used if the ability should not be applied the lord card itself.
- criterion is an optional element consisting of a space character, then a
<or>sign, and then a number n. If a<ncriterion is specified, then effect is only applied if the number of matching targets m is smaller than n, and only n-m times. If a>ncriterion is specified, then effect is only applied if the number of matching targets m is greater than n, and only m-n times. This is a fairly new feature, testing is advised. - (Example: Keldon Warlord is
foreach([creature[-wall]|myinplay) 1/1) - (Example 2: Black Vise uses
foreach( * |opponenthand) damage:1 opponent >4)
-
[$cost:] aslongas($targets) [$effect] [$other] [$criterion]- Applies effect once, but only if there is at least one card matching the target description.
- effect is any effect that would work in an "auto=" line.
- other is used if the card itslf should not be counted as a match.
- criterion is an optional element consisting of a space character, then a "<" or ">" sign, and then a number n. If a "<n" criterion is specified, then effect is only applied if the number of matching targets m is smaller than n. If a ">n" criterion is specified, then effect is only applied if the number of matching targets m is greater than n. This is a fairly new feature, testing is advised.
- (Example: Kird Ape uses
aslongas(forest|myinplay) 1/2)
-
[$cost:] bloodthirst:n- if an opponent was dealt damage this turn, this creature enters the battlefield with n+1/+1counters on it. -
[$cost:] bushido(n/n)- When this blocks or becomes blocked, it gets+n/+nuntil end of turn. -
[$cost:] land:n- target player can play n additional lands this turn.
Note: Land:n does only work on instants and sorceries right now!
-
{N}[$cost]: ninjutsu- Return an unblocked attacker you control to hand: Put the card with ninjutsu onto the battlefield from your hand tapped and attacking.
Note: For a card with Ninjutsu, you basically need 2 things: {N} as cost which means return an unblocked attacker as a cost + the keyword ninjutsu. (Example: Higure, the Still Wind uses {N}{2}{U}{U}:ninjutsu)
-
[$cost:] twist [$target]- switches a creatures current power and toughness with each other. -
removemana([*|$cost])* - Removes mana from target player's manapool. ifis set, all mana matching the "cost" is removed. If` is set alone the manapool is emptied. If cost is set alone, this exact cost gets removed from the manapool -
resetDamage- Removes all damage received so far by a creature -
loseAbilities- Target Card loses all the abilities printed on it (BETA, needs testing) -
loseSubtypesOf([type])- Target Card loses its subtypes of a given type. Valid values for the type are currently hardcoded. e.g:loseSubtypesOf(land)
mypoolsave([colorless | red | white | black | blue | green]) is a static ability for perminents that tells the game that while this is in play, the manapool is not to empty the listed color, the parameter
only allows listing one color at a time. multiple lines might be needed for some cards.
opponentpoolsave([colorless | red | white | black | blue | green])
same as above but for opponent manapool.
add{MANA} doesntempty
doesntempty tag on mana producers tells the game that until end of turn this mana is not to be emptied from the manapool, it will empty all other untagged mana as normal.
altercost( [colorless | red | white | black | blue | green] , -x ) - reduces the target card casting cost by x. Cannot be used in activated abilities or sorceries/instants. Can be used as continuous effect (as a permanent ability of the card, or transferred via aura / lord / etc.)
- (Example: Edgewalker uses
auto=lord(cleric|myhand) altercost(white, -1)
auto=lord(cleric|myhand) altercost(black, -1)
The follow 4 lines have to be added in order to reset the cost if the coded permanent leaves play.
autoexile=all( *|myhand ) resetcost
autograveyard=all( *|myhand ) resetcost
autohand=all( *|myhand ) resetcost
autolibrary=all( *|myhand ) resetcost
altercost( [colorless | red | white | black | blue | green] , +x ) - increases the target card casting cost by x. Cannot be used in activated abilities or sorceries/instants. Can be used as continuous effect (as a permanent ability of the card, or transferred via aura / lord / etc.).
Example: chill uses
auto=lord( * [red]|myhand) altercost( colorless, +2 )
auto=lord( * [red]|opponenthand) altercost( colorless, +2 )
Likewise, the follow 4 lines have to be added in order to reset the cost if the coded permanent leaves play.
autoexile=all( *|myhand ) resetcost
autograveyard=all( *|myhand ) resetcost
autohand=all( *|myhand ) resetcost
autolibrary=all( *|myhand ) resetcost
name(...) && effect - When used in an autoline it replaces an autoline's "ability" text with a custom ability name.
-
(Please use[$cost:]nocreatures- target player cant play creatures this turn.maxCastinstead) -
(Please use[$cost:]nospells- target player cant play spells this turn.maxCastinstead) [$cost:]onlyonecast- target player can only play 1 spell this turn(Please usemaxCastinstead)
You can (and often need to) specify multiple effects for a card. You can code alternative [competing effects](#competing effects), or you can code [multiple effects for one cost](#multiple effects for one cost).
### competing effectsIf several auto effects compete with each other (i.e. if the game cannot determine automatically which action the player wants to take), then the game will automatically create a "choice" menu.
Effects compete with each other if they have a cost and if that cost can be paid in the given situation. Having more than one effect with a [condition active will cause those to compete as well(??). Effects without a cost never compete, instead the engine simply executes all of them.
Examples:
The following two effects (from a dual land) will compete. When the land is tapped for mana, the game will open a menu, which lets the player choose between the two effects:
auto={T}:add{B}
auto={T}:add{G}
The following two effects would also compete, since the cost for both could be paid, so the game cannot know which effect the player wants to activate:
auto={G}:damage:1 target(goblin)
auto={G}:untap target(elf)
The following two effects would compete if the player has green mana in his manapool when selecting the card (because then both effects could be paid for, but not if he has no green mana available (in that case there's only one effect available, and the game will execute this one automatically):
auto={1}:tap target(artifact)
auto={G}:untap target(elf)
The following two effects would not compete because they have no cost - both of them would be executed (although this would make the card a bit silly). The effects contradict each other, but that does not cause them to compete. Effects only compete under the conditions described above.
auto=1/1
auto=-1/-1
You may want one cost to activate several actions. This is done by putting the keyword && between two effects.
Examples:
-
auto={T}:add{W} && damage:1 controller- (Tap this card: You gain 1 white mana and receive 1 damage.) -
auto={2}:bury target(ooze) && regenerate all(treefolk)- (Pay 2 mana: bury target ooze, and regenerate all treefolk.)
Limitations:
-
The
&&keyword is only available for activated abilities, i.e. forauto=rules that actually do have a [auto](#auto cost) may segment. -
You can only specify one explicit target (i.e. a target that requires a choice by the player) per
auto=line. So, a rule like "Tap: Bury target elf, then bury target goblin" cannot be coded yet - you would need code likebury target(elf) && bury target(goblin), and you cannot have twotarget()specifications in the sameauto=line. -
The engine cannot easily handle auto= lines which combine an effect on a target with an effect on the card itself. This happens because the usual way to tell an engine to apply an effect to the card itself is to simply not specify a target, like this:
{2}:flying. If you add a targeted effect to this line, like this:{2}:flying *&& -1/-1 target(wall), then the "no target specified" condition isn't fulfilled anymore, and the game will give the "flying" ability to the wall. You can get around this problem by specifying the card itself as a target for the first effect (but without using a [target|target()]]([#auto) command), like this:{2}:flying **all(this)** && -1/-1 target(wall). -
The above workaround might work with
all(mytgt)too if required, but this has not been tested yet. (There's a risk thatmytgtandtarget()confuse each other.) -
The sequence of actions is not always from left to right. The game requires you to specify your target before any effects are executed, even when the target specification is the last element in your auto= line. This is according to the rules - the target needs to be specified when the ability is put on the stack, not when it resolves.
target defines a group of cards that share some characteristics (for example, all black or artifact creatures on the battlefield). Wagic uses such targets in four ways:
- If the target is part of another command, then it defines a group of cards that this command operates on. For example, in
lord(elf|mybattlefield) 1/1, the targetelf|mybattlefielddefines a group of cards (all elves on the player's battlefield) that the command operates upon (i.e. every card belonging to this group will receive a 1/1 bonus). In the syntax definitions of this reference, such targets are always enclosed in parantheses and attached directly to the command to which they belong. For example, the target for lord commands is written like this:lord($targets) [$effect] - If the target is not part of another command, then it defines a group of cards from which the player needs to choose one (or more). For example, in
bury target(goblin|mybattlefield), the targetgoblin|mybattlefielddefines a group of cards (goblins on the player's battlefield), and the player must then choose one of those, which will be buried. In the syntax definitions of this reference, such targets are never enclosed in parantheses and are preceded by a space. For example, the target for bury commands is written like this:bury target($targets). In card code, such targets explicitly need the termtarget()written out, they are coded like this:target(goblin|mybattlefield) - As an alternative to the notation in the paragraph above, Wagic also allows you to define targets with the keyword
notatarget(), e.g.copy notatarget(goblin|mybattlefield). The only difference between target() and notatarget() is that target() excludes cards which cannot be legally targeted (e.b. because they have the "shroud" ability), while notatarget() includes those. This is useful for cards like Clone, which allow the player to choose a card without technically targeting it.
A fourth usage of "target" is the way how targets appear in a [line. This line always defines targets of the second kind, but does not need the term "target" or parantheses around it. Example: target=zombie|graveyard.
Which values a target can have and how they are specified is explained in the target section.
If an auto= line requires a target, but none is specified, and a target= line is present, then the value of that target= line will be used as target for the auto= line. This is how instants and sorceries define their targets and effects.
For some effects, you can specify a special kind of target: a playertarget. This is an optional value for effects that indirectly target a player. For example, if an effect specifies to draw cards, then the playertarget defines which player does that.
Valid values for playertarget are:
-
controller- (the player who controls the card that has this rule) -
opponent- (the player who does not control the card that has this rule) -
targetcontroller- (the player who controls the [target|target]]([#auto) of this auto= rule)
When playertarget is not specified, Wagic tries to use the most logical value for it: if a "target=" line is specified for an effect, Wagic will use this target if it's a player, or the target's controller if it is a card.
## auto restrictionsFor activated abilities (i.e. #auto rules with a #auto cost segment) you can restrict when or how often they can be activated or how long they last. The following keywords are available:
- [phase restrictions](#phase restrictions) - allow the effect to be activated only at certain times
- limit - limits how often the ability can be activated per turn
- ueot - "until end of turn", forces the effect to end when the turn ends
Description: Non-activated restrictions allows the effect to be active only at certain times. The following variable tags are available:
-
controllerturn- (only active in the card controller's turn) -
opponentturn- (only active in the card opponent's turn)
Examples:
-
auto=this(variable{controllerturn}) 1/5- (During your turn, the 1/5 effect is always active) -
auto=this(variable{opponentturn}) 5/1- (During opponents turn, the 5/1 effect is always active)
Limitations:
- These restrictions were designed for continuous effects only.
Description: Activated phase restrictions allow the effect to be activated only at certain times. The following keywords are available:
-
myturnonly- (only usable in the card controller's turn) -
assorcery- (only usable when a sorcery could be played, i.e. in the card controller's first and second main phase) -
my[phasename]only- (only usable in the respective phase in the card controller's turn. [phasename] is written without the square brackets and can be any phase name. You can see a list of available phase names in the section for #phase-based triggers)
Examples:
-
{T}:add{B} asSorcery- (Tap this card: Add one black mana. Use this ability only when you could play a sorcery.) -
{3}:untap myupkeeponly- (In your upkeep phase, you may pay 3 mana to untap this card.)
Limitations:
-
These restrictions were designed for activated abilities so they probably won't work for continuous effects.
-
You can't (yet) restrict activation to other combinations of phases, like "only during combat" or "only before attachers have been declared".
Description: limit limits how often the ability can be activated per turn
Example:
-
{B}:add{W} limit:2- *(activating this card lets the player turn 1 black mana into 1 white mana, but no more than 2 times per turn)_
Description: ueot (meaning "until end of turn"), forces the effect to end when the turn ends.
Usually, Wagic guesses whether an effect is meant to last until end of turn, or indefinitely. For example, it assumes that any activated abilities only last until end of turn, and that the effects of enchantments last as long as the enchantment is in play. This guess is correct in the vast majority of cases.
Sometimes, however, the guess may be wrong, and you may want to explicitly tell Wagic that an effect is only meant to least until end of turn. In this case, use the "ueot" keyword.
Example:
An Enchantment that gives all cats +1/+1 (as long as it is in play), and also makes those cats unblockable for the turn in which it entered the battlefield, can be coded like this:
auto=lord(cat) 1/1
auto=lord(cat) unblockable ueot
Description: nonstatic means dynamic and the effect of power and toughness changes are applied above the default power and toughness. cdaactive is also dynamic but has the lowest priority and applied directly to the card's power and toughness.
Example:
nonstatic keyword
auto=type:artifact:mybattlefield/0 nonstatic A Creature card with +X/+0 where X is the number of Artifact you control(the number of X is dynamic)
Using nonstatic applies it on top, meaning if the creature has a default 1/1 Power and toughness, and X is 3, the final value of Power and Toughness is 4/1.
cdaactive keyword
auto=type: *:myhand/type: *:myhand cdaactive A Creature card with */ * where * is the number of any card in your hand( * is also dynamic )
On the otherhand cdaactive applies directly. If * is 5, The power and toughness of the creature will be 5/5.
Many #auto effects in #auto rules have numbers as parameters: how many cards to draw, how much life to give, how much power to add, etc. Usually, you simply write a fixed number into the rule. In many places, you can also use a variable instead of a fixed number. The following variables are available:
-
X- (the amount of mana paid for the "X" of the spell cost of this card) -
p- (the power of this card's target) -
t- (the toughness of this card's target) -
manacost- (the converted manacost of this card's target) lifetotalopponentlifetotal
Examples:
-
auto=draw:X controller- (draw one card for each mana paid for the "X" cost of this spell) -
auto=bury target(goblin) && life:p targetcontroller- (bury target goblin, and give its controller an amount of life equal to that goblin's power) -
auto={T}:0/manacost target(elf)- (target elf gains an amount of toughness equal to his converted manacost)
Limitations:
- Some #auto effects can use this functionality, others can't. Thorough testing is advised.
- For at least the following effects, this feature has been implemented:
becomes,damage,draw,life,power/toughnessmodifiers (excluding counters),token(for the number of tokens)
With time, the Wagic syntax for auto lines has evolved from a very simple series of keywords to a convoluted system, close to a programming language, with lots of exceptions and tribal knowledge. In an attempt to simplify this, we introduced auto macros, a system that allows to "summarize" a complex auto line into a simple keyword, actually a function accepting parameters. This is useful especially if you plan to code dozens of cards that share a complex ability.
Let's for example look at the code for cycling (as of 2011/11/12):
autohand={2}{cycle}:name(cycling) draw:1
It is not super long to type, but ideally we would prefer to type cycling({2}) or something similar. The macros system allows to simplify things by writing the complex ability once, and associating it to a keyword.
Here's and example:
#AUTO_DEFINE __CYCLING__($cost) $cost{cycle}:name(cycling) draw:1
The syntax is simple:
#AUTO_DEFINE [name and parameters] [ability code].
In our example, we define the keyword ___CYCLING___ which takes a variable $cost. We then tell the engine to "rewrite" that keyword and parameter into $cost{cycle}:name(cycling) draw:1 (note the $cost variable in there).
This then allows card coders to write:
autohand=__CYCLING__({2})
instead of
autohand={2}{cycle}:name(cycling) draw:1
- The keyword used for a macro cannot contain any space
- it is recommended to prefix parameters for the macros with the symbol
$, to avoid any weird replacement - Macros are global. Wherever you define them in your card files, they will apply everywhere
- ** We suggest to write all the macros in a single text file, inside the sets/primitives folder
- Macros are simply "replaced" with the code they describe, through a simple text replacement algorithm.
- ** For this reason, it is important to use unique macro names that cannot "conflict". For example, having a macro named
MACROand another one namedMACRO2is a bad idea, because the stringMACROexists in the stringMACRO2. As a convention, we start and end all our macro names by__, and we guarantee that we don't use__inside of the macro name anyplace else.
Description: autohand is a recently introduced key that allows you to specify effects which can be activated while the card is in your hand.
Regular auto= rules are only active when the card is on the battlefield, they are ignored if the card is in any other zone. However, you may want to code effects which can be activated from the hand (without actually playing them), for example to code Cycling effects. For such effects, autohand= has been introduced.
Example:
autohand={2}:cycling
Limitations: Currently, autohand= only works for activated abilities (i.e. rules with a [cost](#auto cost) segment). Continuous effects or triggers cannot be coded in autohand= lines.
This is a new feature, thorough testing is advised.
Description: autograveyard is a key that allows you to specify effects which can be activated while the card is in your graveyard.
Example:
autograveyard={B}{B}:moveTo(myBattlefield)
Limitations: Currently, autograveyard= only works for activated abilities (i.e. rules with a [cost](#auto cost) segment). Continuous effects or triggers cannot be coded in autohand= lines.
Description: alias is used to access existing hardcoded routines which were originally coded for other cards. Its main use is to create a new card that has the same hardcoded effects as an existing one.
For example, the effect of Control Magic (id 1194) currently cannot be coded with any auto= rule. Therefore, the card's functionality was hardcoded, i.e. directly programmed into the engine. The engine knows that whenever a card with the id 1194 is played, it needs to execute this hardcoded effect.
There's another card called Persuasion which has exactly the same effect as Control Magic. So we want to make Persuasion behave just like Control Magic. Usually we could just copy any rules and effects over from Control Magic's card data to make Persuasion work, but in this case there's nothing to copy, since the code is stored in the engine, not in the card's data. So, to make Persuasion work, we have to tell it that it needs to access the hardcoded functions that were meant for the card with id 1194 (Control Magic).
This is exactly what the alias= key does. So to make Persuasion work, we would add the line alias=1194 to its code. Note that we still need to specify all other data for Persuasion (type, mana, even the target) - the alias ** only ** makes the Persuasion access a hardcoded function, it copies no information over from the aliased card.
Limitations: Use alias with care. The only time you can be 100% sure that it's correct to use alias is when the card is a reprint of an existing card, or functionally identical.
The alias= key has led to confusion and may be removed from the parser in the future.
Now, the best piece of advice we can give you is to look at the existing primitives and get inspiration from there. If you have question or run into problems, ask for help in our Discord.
If you're planning to code many cards, then you will appreciate a comfortable way of testing their functions. Check the [Suite Reference]]([Wagic/TestSuite|Test) for that.
If you want to dig deeper, you can have a look at TargetChooser.cpp and MTGAbility.cpp in the source code. See our [Guide]]([Wagic/Compiling|Compilation) for help on obtaining Wagic's source code and compiling it.
Good luck!