diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dd84ea7824f..6a8ca9e1859 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -4,6 +4,7 @@ about: Create a report to help us improve title: '' labels: '' assignees: '' +type: 'Bug' --- @@ -31,7 +32,6 @@ If applicable, add screenshots to help explain your problem. **Smartphone (please complete the following information):** - Device: [e.g. iPhone6] - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - Version [e.g. 22] **Additional context** diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7d615..8520249f9cb 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -4,6 +4,7 @@ about: Suggest an idea for this project title: '' labels: '' assignees: '' +type: 'Feature' --- diff --git a/.github/workflows/maven-publish.yml b/.github/workflows/maven-publish.yml index 808043bb503..877b16b0f1e 100644 --- a/.github/workflows/maven-publish.yml +++ b/.github/workflows/maven-publish.yml @@ -129,7 +129,9 @@ jobs: makeLatest: true - name: 🔧 Install XML tools - run: sudo apt-get install -y libxml2-utils + run: | + sudo apt-get update + sudo apt-get install -y libxml2-utils - name: 🔼 Bump versionCode in root POM id: bump_version diff --git a/.github/workflows/sync-wiki.yml b/.github/workflows/sync-wiki.yml new file mode 100644 index 00000000000..0e06a043862 --- /dev/null +++ b/.github/workflows/sync-wiki.yml @@ -0,0 +1,28 @@ +name: Publish wiki +on: + push: + branches: [master] + paths: + - docs/** + - .github/workflows/sync-wiki.yml + workflow_dispatch: +concurrency: + group: publish-wiki + cancel-in-progress: true +permissions: + contents: write +jobs: + publish-wiki: + if: github.repository_owner == 'Card-Forge' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: fix md links for Gollum + run: find ${{ github.workspace }}/docs/ -type f -name "*.md" -exec sed -i -E 's|(\[[^]]+]\()([^)]+\/)*([^).]+).md\)|\1\3)|g' '{}' \; + - name: fix image links for Gollum + run: find ${{ github.workspace }}/docs/ -type f -name "*.png" -exec mv '{}' ${{ github.workspace }}/docs/ \; + - uses: Andrew-Chen-Wang/github-wiki-action@v5 + with: + path: docs + preprocess: false + strategy: init diff --git a/docs/AI.md b/docs/AI.md new file mode 100644 index 00000000000..121a78ec28d --- /dev/null +++ b/docs/AI.md @@ -0,0 +1,68 @@ +# About Forge's Artificial Intelligence + +The AI is *not* "trained". It uses basic rules and can be easy to overcome knowing it's weaknesses. + +The AI is: +* Best with Aggro and midrange decks +* Poor to Ok in control decks +* Pretty bad for most combo decks + +If you want to train a model for the AI, please do. We would love to see something like that implemented in Forge. + +# AI Matches from Command Line + +The AI can battle itself in the command line, allowing the tests to be performed on headless servers or on computers that have poor graphic performance, and when you just don't need to see the match. This can be useful if you want to script testing of decks, test a large tournament, or just bash 100's of games out to see how well a deck performs. + +Please understand, the AI is still the AI, and it's limitations exist even against itself. Games can lag and become almost unbearably long when the AI has a lot to think about, and you can't see what's on the table for it to play against. It's best if you set up the tournament and walk away, you can analyze logs later, results are printed at the end. + +## Syntax + +`sim -d ... -D [path] -n [N] -f [F] -t [T] -p [P] -q` + +In linux and mac, command line arguments are not currently passed through the sh script, please call `java -jar` manually, instead of the exe. +- `sim` - "Simulation Mode" forces Forge to not start the GUI and automatically runs the AI matches in command line. Enables all other switches for simulation mode. +- `-d ... ` - Space separated list of deck files, in `-f` game type path. (For example; If `-f` is set to Commander, decks from `/decks/commander/` will be searched. If `-f` is not set then default is `/decks/constructed/`.) Names must use quote marks when they contain spaces. + - `deck1.dck` - Literal deck file name, when the value has ".dck" extension. + - `deck` - A meta deck name of a deck file. +- `-D [path]` - [path] is absolute directory path to load decks from. (Overrides path for `-d`.) +- `-n [N]` - [N] number of games, just flat test the AI multiple times. Default is 1. +- `-m [M]` - [M] number of matches, best of [M] matches. (Overrides -n) Recommended 1, 3, or 5. Default is 1. +- `-f [F]` - Runs [F] format of game. Default is "constructed" (other options may not work, list extracted from code) + - `Commander` + - `Oathbreaker` + - `TinyLeaders` + - `Brawl` + - `MomirBasic` + - `Vanguard` + - `MoJhoSto` +- `-t [T]` - for Tournament Mode, [T] for type of tournament. + - `Bracket` - See wikipedia for [Bracket Tournament](https://en.wikipedia.org/wiki/Bracket_(tournament)) + - `RoundRobin` - See wikipedia for [Round Robin Tournaments](https://en.wikipedia.org/wiki/Round-robin_tournament) + - `Swiss` - See wikipedia for [Swiss Pairing Tournaments](https://en.wikipedia.org/wiki/Swiss-system_tournament) +- `-p [P]` - [P] number of players paired, only used in tournament mode. Default is 2. +- `-q` - Quiet Mode, only prints the result not the entire log. + +## Examples +In linux and macos you must run forge by evoking java and calling the jar, currently command line parameters are not passed through the script. The forge jar filename is truncated in these examples from `forge-whatever-version-youre-on.jar` to `forge.jar`. + +In Windows, if you use the EXE file as described below, the simulation runs in the background and output is sent to the forge log file only. If you want to have output to the console, please use the `java -jar` evocation of forge. + +To simulate a basic three games of two decks (deck1 and deck2 must be meta deck names of decks in `\decks\constructed\`): +- Windows/Linux/MacOS: `java -jar forge.jar sim -d deck1 deck2 -n 3` +- Windows: `.\forge.exe sim -d deck1 deck2 -n 3` + +To simulate a single 3-player Commander game (deck1, deck2, and deck3 must be meta deck names of decks in `\decks\commander\`): +- Windows/Linux/MacOS: `java -jar forge.jar sim -d deck1 deck2 deck3 -f commander` +- Windows: `.\forge.exe sim -d deck1 deck2 deck3 -f commander` + +To simulate a round robin tournament; best of three, with all decks in a directory: +- Windows/Linux/MacOS: `java -jar forge.jar sim -D /path/to/DecksFolder/ -m 3 -t RoundRobin` +- Windows: `.\forge.exe sim -D C:\DecksFolder\ -m 3 -t RoundRobin` + +To simulate a swiss tournament; best of three, all decks in a directory, 3 player pairings: +- Windows/Linux/MacOS: `java -jar forge.jar sim -D /path/to/DecksFolder/ -m 3 -t Swiss -p 3` +- Windows: `.\forge.exe sim -D C:\DecksFolder\ -m 3 -t Swiss -p 3` + +*** + +Each game ends with an announcement of the winner, and the current status of the match. diff --git a/docs/Adventure-Mode.md b/docs/Adventure-Mode.md new file mode 100644 index 00000000000..69e9c1e29c8 --- /dev/null +++ b/docs/Adventure-Mode.md @@ -0,0 +1,12 @@ +# What is Adventure Mode? + +Adventure mode is a work-in-progress game mode where you explore the ever-changing landscape of Shandalar, duel creatures to earn gold and new cards to battle the various bosses. You can visit towns to buy equipment and cards, and crawl through dungeons to find artifacts and loot to help you on your journey. Adventure mode is an awesome reimagining of the original "Shandalar" 1997 PC Game in Forge, even though the scope of adventure is much broader and we don't constrain ourselves to the lore of the plane of Shandalar. You can play Shandalar on Desktop (Linux, Windows, IOS) or on Android devices. + +# How to run? + +1. Step 1: Download the latest version of Forge https://downloads.cardforge.org/dailysnapshots/ +2. Step 2: Make sure you have the required version of the JDK (https://www.oracle.com/be/java/technologies/downloads/) +3. Step 3: Launch the adventure mode from the "adventure.exe" file included in the forge version (on android, the adventure version should be embedded into the main Forge program) +4. Step 4: In order to have pictures show up make sure you enable "automatically download missing card images" in the settings. This should automatically download the picture of the card as you encounter them in game. + + diff --git a/docs/Card-Images.md b/docs/Card-Images.md new file mode 100644 index 00000000000..0067216f162 --- /dev/null +++ b/docs/Card-Images.md @@ -0,0 +1,109 @@ +# About + +Card images are assets used to represent the real cards in game. You DO NOT need images to play forge, however representing real cards is a nice ability forge provides. These images can be any image set you like, or custom images too. + +Primarily there are two types of images you'll care about; cards, and tokens. + +**Cards** - are the primary card image files, and can be generic (as all cards of the same name have the same rules) or per set since there may be different art work in different editions. Typically these are scans of the original cards and are provided by forge's FTP, or scryfall. You can customize a full generic set, or any edition if you desire... (you could for example, blur every card image and play a literal "blind" or "farsighted" game.) + +**Tokens** - are the images for the cards replacing a generic "1/1 zombie" for example. These are less frequently updated, and are typically the bulk of what is missing when doing an audit. However, these are probably where the more true "custom" replacements are available, with either custom artwork, or modified of other existing. + +# Downloading + +Due to charges in Forges hosting and scryfall terms you can no longer predownload card images. Turn on auto download in forge to download card images when first viewed. + +## In Forge Auto Download: + +**Download Missing Images - Setting** +- This will download the images from the sources as the game requests the image in situ. +- This can be useful if you don't want to have copies of every card... You can do small pre-caching by loading your decks in the deck editor prior to playing to download just those images. + +## Bulk Download Sites: (Not in game) + +- [http://download.austeregrim.net](http://download.austeregrim.net) + - Note from user AustereGrim; +> I provide my site for free for bulk downloading the entire image catalog. So you don't need to give those spam sites more advertising spots. If the server is loaded bandwidth is shared, right now it's not heavily used so please feel free to download the 4+gb zips, or the individual zips if you need sets. They are the images Kev has uploaded to my site, and the Zips are updated nightly automatically. + +**(I'm not gatekeeping, please if you have a private location for bulk downloads or for alternate or custom arts, you can update this wiki too or let us know in the discord. I'll be happy to update the wiki page with additional sources.)** + +# Storage + +Card images are stored in `pics/cards`, and tokens in `pics/tokens`, in the Cache folder for forge: + +- **Windows** - `C:\Users\\appdata\local\forge\Cache\` + - You'll need to enable hidden folders. +- **Android 11+** - `Internal Storage/Android/obb/forge.app/Forge/cache/` + - *_NOTE: You need a third party File Manager to access the obb folder and allow storage access permission_* +- **Android 8 to 10** - `Internal Storage/Forge/cache/` +- **Linux** - `/home//.cache/forge/` +- **MacOS** - `/Users//Library/caches/forge/` + - Use `Command + Shift + .` to show hidden files. + + +# Subfolders + +If you don't care about the edition's version of cards, images can be stored in the root directory of the cards folder. + +`/cache/pics/cards/` + +If you want the edition's versions of the cards, they need to go under the edition's code subfolder. + +`/cache/pics/cards/AFR` for example for Adventures in the Forgotten Realms. + +# File Naming + +**File Names:** +- Cards file names follow a simple principle: `Card Name#.border.ext` + - `Card Name` - Card Name with spaces. + - `#` - Alternate Art number; if more than one art exists for the card. + - `border` - Border Type; fullborder, crop. (I don't know all of them.) + - `ext` - Extension, jpg or png are supported. + +**Alternate images:** + +Alternate images are defined as cards with the same name in the set's edition file, if the edition file does not have the alternate listed forge will not see the alternate there! + +**Standard Alternate Arts:** + +So for example the AFR set (as most sets) shows these 4 versions of swamp; +``` +270 L Swamp @Piotr Dura +271 L Swamp @Sarah Finnigan +272 L Swamp @Titus Lunter +273 L Swamp @Adam Paquette +``` +The file naming would be represented by a number after the name: +``` +Swamp1.fullborder.jpg +Swamp2.fullborder.jpg +Swamp3.fullborder.jpg +Swamp4.fullborder.jpg +``` + +**Additional Alternate Arts:** + +They may also be listed separately as "extended arts", "showcase", or "borderless" in the same editions file: +``` +[cards] +90 U Black Dragon @Mark Zug +``` +and +``` +[borderless] +291 U Black Dragon @Jason A. Engle +``` +Where the files are: +``` +black dragon1.fullborder.jpg +black dragon2.fullborder.jpg +``` + +**Forcing an Alternate:** + +Renaming and creating a second of an existing card **will not work**, for example creating two "Burning hands" which does not have alternate art; +``` +burning hands1.fullborder.jpg +burning hands2.fullborder.jpg +``` +Forge will not see either of those, and will probably download the missing `burning hands.fullborder.jpg` for you. Similarly adding a 3rd black dragon `black dragon3.fullborder.jpg` will **not** work either. + diff --git a/docs/Card-scripting-API/AbilityFactory.md b/docs/Card-scripting-API/AbilityFactory.md new file mode 100644 index 00000000000..1305fa3721a --- /dev/null +++ b/docs/Card-scripting-API/AbilityFactory.md @@ -0,0 +1,900 @@ +AbilityFactory parses differently from the Keyword parser. Your Ability line will look more like this: + +`A:{AB/SP/DB/ST}$ | {Necessary$ Parameters} | {Separated$ By} | {Pipes$ Here} | [Optional$ Values]` + +In most cases, each AF subclass implements both the Spell and Ability. +Much of the code is shared, so creating the data object will look very similar. + + - **AB** is for Activated Abilities + - **SP** is for Spell + - **DB** is 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** is 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) + +>*NOTE:* +> - these factories are refactored from time to time (often to adapt to new sets), so while some entries could be slightly outdated, the base information should still be correct +> - 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 +> - when in doubt you can always cross check with the [available APIs](https://github.com/Card-Forge/forge/tree/master/forge-game/src/main/java/forge/game/ability/effects) code + +# Common Parameters + +## Cost / UnlessCost + +`Cost$ ` 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 parameter 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 the DB 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](Costs) + +## ValidTgts / Defined + +Most effects need to know (at least implicitly) which players or objects they're trying to affect. There are two different ways for that: +- `ValidTgts` will need to be used for abilities that target +- if your ability instead describes on what it's applied use `Defined` + +Read more about it in [Affected / Targets](Targeting) + +## Restrictions / Conditions + +Restrictions limit when abilities can be put on the stack and Conditions apply during resolving. Common examples are Putrid Leech's only activate this once per turn or different cards that can activate from Zones like the Hand or the Graveyard. + +Read more about it in [Restriction](Restrictions) + +## SpellDescription + +SpellDescription 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 (both AB and DB) is now displayed when (and if) the ability prompts for user input in the prompt pane so it is useful to put some nice text there. + +## StackDescription + +*(Optional)* StackDescription 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. + +## Remember* + +Remembering is often needed when a card becomes a new object, which is then further affected by the ability. Typical example: [Flicker](https://github.com/Card-Forge/forge/blob/master/forge-gui/res/cardsfolder/f/flicker.txt)
+Because cards keep their remembered parts when changing zones manual [cleanup](#Cleanup) is usually required. + +## AI params + +`IsCurse$ True` - For effects that are normally treated positive e.g. Pump + +`AITgts$ BetterThanEvalRating.130` + +# Factories (in Alphabetical Order) + +## AlterLife + +AlterLife is for Abilities that Alter a player's life total. + +### GainLife + +Have a player gain the specified amount of life. + +`A:AB$ GainLife | Cost$ T | LifeAmount$ 1 | SpellDescription$ You gain 1 life.` + +LifeAmount$ is required. This is how much life you will gain. + +Defined is optional, if it appears the defined player(s) gain life. +Target is optional, if it appears and Defined doesn't then targeted player(s) gain life. + +### LoseLife + +Have a player lose the specified amount of life. + +`A:AB$ LoseLife | Cost$ Sac<1/CARDNAME> | ValidTgts$ Player | TgtPrompt$ Target a player to lose a life | LifeAmount$ 1 | SpellDescription$ Target player loses 1 life.` +`A:SP$ LoseLife | Cost$ 2 B | Defined$ Opponent | LifeAmount$ 2 | SpellDescription$ Each opponent loses 2 life.` + +LifeAmount$ is required. This is how much life will be lost. + +Target is optional. If Target doesn't appear then Defined will be used. +Remember, if Defined is missing, the default for Players is "You" + +Part of resolving sets the **SVar AFLifeLost** to the amount of life lost by all players. + +### SetLife + +SetLife sets one or both player's life total to a specified value (i.e. +"your life total becomes 20" or "Target player's life total is equal to +the number of cards in your graveyard"). + +`A:SP$ SetLife | Cost$ 7 W W | ValidTgts$ Player | TgtPrompt$ Select target player | LifeAmount$ 20 | SpellDescription$ Target player's life total becomes 20.` + +Parameters: +LifeAmount (required) - the value to set the life total(s) to + +Defined is optional. If it exists, it will be used. Target is optional. +If it exists and defined doesn't it will be used. Default player is "You". + +### ExchangeLife + +ExchangeLife switches the Life total of two players. + +`A:AB$ ExchangeLife | Cost$ 6 T | ValidTgts$ Player | TargetMin$ 2 | TargetMax$ 2 | TgtPrompt$ Select target player | SpellDescription$ Two target players exchange life totals.` + +One of Defined or Target is required, since there needs to be two +Players exchanging life If Defined it will be used. If Target exists and +defined doesn't it will be used. + +If there aren't two determined players by the SA, the activating player is added as the second player. + +## Animate + +Animate handles animation effects like "This card becomes a 5/5 +green creature with flying until end of turn." It is designed to handle +color changing, type changing, P/T setting, and granting/removing abilities. + +`A:SP$Animate | Cost$ G | ValidTgts$ Land | TgtPrompt$ Select target land | Power$ 3 | Toughness$ 3 | Types$ Creature | SpellDescription$ Until end of turn, target land becomes a 3/3 creature that's still a land.` + +`A:AB$Animate | Cost$ 1 B | Defined$ Self | Power$ 1 | Toughness$ 1 | Types$ Creature,Skeleton | Colors$ Black | Abilities$ ABRegen | SpellDescription$ CARDNAME becomes a 1/1 black Skeleton creature with "B: Regenerate this creature" until end of turn. It's still a land. (If it regenerates, the next time it would be destroyed this turn, it isn't. Instead tap it, remove all damage from it, and remove it from combat.)` +`SVar:ABRegen:AB$Regenerate | Cost$ B | SpellDescription$ Regenerate CARDNAME.` + +`A:AB$Animate | Cost$ 2 R G | Defined$ Self | Power$ 3 | Toughness$ 3 | Types$ Creature,Elemental | Colors$ Red,Green | Triggers$ TrigAttack | SpellDescription$ Until end of turn, CARDNAME becomes a 3/3 red and green Elemental creature with "Whenever this creature attacks, put a +1/+1 counter on it." It's still a land.` +`SVar:TrigAttack:Mode$ Attacks | ValidCard$ Creature.Self | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME attacks, put a +1/+1 counter on it.` +`SVar:TrigPutCounter:AB$PutCounter | Cost$ 0 | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1` + +Parameters: + + - Power (required) - the power to assign to the animated card + - Toughness (required) - the toughness to assign to the animated card + - Types (optional) - the additional types to give the animated card; + comma delimited + - OverwriteTypes (optional) - set to True if the animated being should + have these types **instead** as opposed to **in addition to** + - RemoveTypes (optional) - a list of types to Remove from the animated + card + - ChosenType (optional) - overrides types before it and just will add + the ChosenType + - Keywords (optional) - a " & " delimited list of keywords to give the + animated being (just like AB$Pump) + - HiddenKeywords (optional) - a " & " delimited list of hidden + keywords to give the animated being (just like AB$Pump) + - RemoveKeywords (optional) - a " & " delimited list of keywords to + remove from the animated being (just like AB$Debuff) + - Colors (optional) - a comma-delimited list of Colors to give to the + animated being (capitalized and spelled out) (ChosenColor accepted) + - Abilities (optional) - a comma-delimited list of SVar names which + contain abilities that should be granted to the animated being + - OverwriteAbilities - Remove Abilities from animated being + - Triggers (optional) - a comma-delimited list of SVar names which + contain triggers that should be granted to the animated being + - OverwriteTriggers - Remove/suppress triggers from animated being + - staticAbilities (optional) - a comma-delimited list of SVar names + which contain static abilities that should be granted to the + animated being + - OverwriteStatics- Remove static abilities from animated being + - OverwriteReplacements - Remove replacement effects from animated + being + - RemoveAllAbilities - Remove all Abilities, Triggers, Statics, and + Replacement effects + - sVars(optional) - a comma-delimited list of SVars that should be + granted to the animated being + - Duration (Default is end of turn) + - Permanent + - UntilEndOfCombat - if the effect should last only until End of Combat instead of End of Turn + - UntilHostLeavesPlay - if the effect should last as long as the host is still in play + - UntilYourNextUpkeep + - UntilControllerNextUntap + - UntilYourNextTurn + +Target is optional, will be used if possible. Defined is optional, will be used if no Targets (Self by default) + +## Attach + +Attach is being used directly only for Auras, primarily for Aura Spells, but also for Auras entering the battlefield by some effect. + +`AB$ Attach | Cost$ R R | ValidTgts$ Creature | AILogic$ Pump` + +Parameters: + + - Object (optional) - This is the Object that will be Attached + (generally the Source Card for Auras) + - AILogic - AI Logic tells the AI which base AI code it should use for + Attaching + - GainControl - Gains Control of the Attached Permanent (Control + Magic) + - Curse - A Generic Curse the AI has a handful of checks to see + what the most appropriate Target is. + - Pump - A Generic Pump. The AI has a handful of checks to see + what the most appropriate Target is. + - ChangeType - For Attachments that change types. Evil Presence is + a good example. This logic should be expanded. + - KeepTapped - For Attachments that keep a Permanent tapped. The + AI will also check for a few things like Vigilance, and another + KeepTapped Aura. Paralyzing Grasp is a good example. + +Attach separates the actually granting of abilities from the attaching to permanents to streamline how things work. + +## BecomeMonarch + +## Bond + +Soulbonding two creatures. Only used internally by the engine. + +## Branch +Sometimes, an ability might do certain things when a specific condition is true, and other things if not. This can be implemented by using `Branch`. +The branch evaluates the SVar specified by the property `BranchConditionSVar`, using the comparison defined with `BranchConditionSVarCompare` (such as `GTY`, `LT1`, etc). Depending on whether the condition evaluated to true or false, the subability defined by `TrueSubAbility` or `FalseSubAbility` is executed. + +The example below is for "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 in play under your 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 +``` + +## Charm + +This allows cards that have a mode to be chosen to occur after a trigger. + +Parameters + + - CharmNum - Number of Modes to Choose + - Choices - A Comma delimited list of SVars containing the Modes + +## Choose* + +These can be used to chain effects together. However for common cases many effects already support this directly, e.g. `PutCounter | Choices$``.
+Besides making the script shorter using such shortcuts usually also helps the AI making better use of the effect. + +### ChooseType + +This can be used when you are asked to choose a card type or creature type. + + - Type - Required - Can be Card or Creature + - InvalidTypes - Optional - Use to specify any type that cannot be chosen (ex: "Choose any creature type except Wall") + +The Defined is for target players. + +## Clash + +This AF handles clashing. It takes two special parameters: WinSubAbility and +OtherwiseSubAbility. They are both optional and work the same way, +namely that it contains the name of an SVar that in turn contains a +drawback to be executed. The example below is for Release the Ants. + +`A:SP$ DealDamage | Cost$ 1 R | Tgt$ TgtCP | NumDmg$ 1 | SubAbility$ DBClash | SpellDescription$ Release the Ants deals 1 damage to target creature or player. Clash with an opponent. If you win, return CARDNAME to its owner's hand.` +`SVar:DBClash:DB$ Clash | WinSubAbility$ DBReturn` +`SVar:DBReturn:DB$ ChangeZone | Defined$ Self | Origin$ Stack | Destination$ Hand` + +## Cleanup + +A non-functional, maintenance AF used for Cleaning up certain Variables before a Spell finishes Resolving. + +Parameters + + - ClearRemembered$ (optional) Set to True to clear this card's + remembered list. Generally useful for Cards that Remember a card, do + something to it, then need to forget it once it's done. + - ClearImprinted$ (optional) Set to True to clear the list of + imprinted cards. + - ClearChosenX$ (optional) Set to True to clear the chosen X value. + - ClearTriggered$ (optional) Set to True to clear any delayed triggers + produced by this card. + - ClearCoinFlips$ (optional) Set to True to clear the remembered coin + flip result. + - ClearChosenCard$ (optional) Set to True to clear the chosen cards. + - ForgetDefined$ (optional) If present, remove the specified cards + from this card's remembered list. + +## Control + +### GainControl + +Example: Act of Aggression + +`A:SP$ GainControl | Cost$ 3 PR PR | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls. | LoseControl$ EOT | Untap$ True | AddKWs$ Haste | SpellDescription$ Gain control of target creature an opponent controls until end of turn. Untap that creature. It gains haste until end of turn.` + +Parameters: + +- NewController(Targeted player, if there is no target player, the + default is the ActivatingPlayer) +- AllValid(all valid types, no targets) +- LoseControl(LeavesPlay, Untap, LoseControl, EOT(end of turn)) + +### ControlExchange + +### ControlSpell + +## Copy* + +### CopyPermanent + +Copies a permanent on the battlefield. + +Parameters: + + - NumCopies - optional - the number of copies to put onto the + battlefield. Supports SVar:X:????. + - Keywords - optional - a list of keywords to add to the copies + - AtEOT - optional + - Sacrifice - set to this is copy should be sacrificed at End of + Turn + - Exile - set to this is copy should be exiled at End of Turn + +### CopySpellAbility + +Copies a spell on the stack (Twincast, etc.). + +## Counter + +Countering Spells or Abilities. + +`A:SP$ Counter | Cost$ 1 U | TargetType$ Spell | TgtPrompt$ Select target spell | ValidTgts$ Card | UnlessCost$ 3 | SpellDescription$ Counter target spell unless its controller pays 3.` +`A:SP$ Counter | Cost$ U | TgtPrompt$ Select target Activated or Triggered Ability | ValidTgts$ Card | TargetType$ Activated,Triggered | SpellDescription$ Counter target activated or triggered ability.` +`A:SP$ Counter | Cost$ G | TargetType$ Spell | ValidTgts$ Instant,Aura | TargetValidTargeting$ Permanent.YouCtrl | SpellDescription$ Counter target instant or Aura spell that targets a permanent you control. ` + +Parameters + + - TargetType - Can be Spell,Activated,Triggered. If more than one, + just put a comma in between. + - ValidTgts - a "valid" expression for types of source card (if you + don't know what it is it's just "Card") + - TargetValidTargeting- a "valid" expression for targets of this + spell's target + - Destination - send countered spell to: (only applies to Spells; ignored for Abilities) + - Graveyard (Default) + - Exile + - TopDeck + - Hand + - BottomDeck + - Shuffle + +## Counters* + +Factories to handle counters on cards. + +### Poison + +Poison gives a player the specified number of poison counters. + +`A:AB$ Poison | Cost$ B T | ValidTgts$ Player | TgtPrompt$ Select target player | Num$ 2 | SpellDescription$ Target player gets 2 poison counters.` + +Parameters: + +- Num (required) - the number of poison counters to give + +Target is optional and used if available. Defined is optional and used if no Target (defaults to "You"). + +### PutCounter + +Put any type of counter on a game object. + +`A:AB$ PutCounter | Cost$ T | CounterType$ CHARGE | CounterNum$1 | SpellDescription$ Put a charge counter on CARDNAME.` +`A:SP$ PutCounter | Cost$ G | Tgt$ TgtC | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a charge counter on CARDNAME.` + +Target is optional. If no Target is provided, the permanent will put counters on itself. + + - 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 put on + the chosen card. + +### PutCounterAll + +Put any type of counter on all valid cards. + + - 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 put on + the chosen cards. + - ValidCards (required) specifies the cards to add counters to. + +### RemoveCounter + +Remove any type of counter from a card. + +Target is optional. If no Target is provided, the permanent will remove +counters from itself. + + - 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. + +### RemoveCounterAll + +Remove any type of counter from all valid cards. + + - 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 cards. + - ValidCards$ (required) specifies the card to remove counters from. + +### Proliferate + +No own parameters. + +### MoveCounters + +Used for cards that Move Counters on Resolution, requiring the Host card +to have Counters for the Move to occur. + +Parameters + + - Source - The Source of the Moving Counters + - Defined - The Destination of the Moving Counters + - CounterType - The type of counter to move. + - CounterNum - The number of counters to move. + +## Damage + +### DealDamage + +Deal damage to a specified player or permanent. + +`A:AB$ DealDamage | Cost$ T | Tgt$ TgtCP | NumDmg$ 1 | SpellDescription$ CARDNAME deals 1 damage to target creature or player.` + +NumDmg is required. This is the amount of damage dealt. + +### EachDamage + +## Debuff + +Parameters + + - Keywords + - Duration + +An AbilityFactory for Removing Keywords, either temporarily or for longer durations. + +## Destroy + +These APIs handles destruction of cards on the battlefield. + +`A:SP$Destroy | Cost$ 1 W W | ValidTgts$ Artifact,Enchantment | TgtPrompt$ Select target artifact or enchantment | SpellDescription$ Destroy target artifact or enchantment.` + +## Effect + +Effect is an oddball of the AF family. Where usually AFs have similarities to each other to help with AI use, Effect doesn't fall under that jurisdiction. In general, an effect is some type of SA that +lasts longer than its resolution. + +A good example is High Tide. For the rest of the turn, High Tide makes +all Islands produce an extra mana. It doesn't matter if the Island was +in play, if it turned into an Island after High Tide was cast, any of that. + +`A:SP$ Effect | Cost$ U | Name$ High Tide Effect | Triggers$ IslandTrigger | SVars$ TrigMana | SpellDescription$ Until end of turn, whenever a player taps an Island for mana, that player adds U to his or her mana pool (in addition to the mana the land produces).` +`SVar:IslandTrigger:Mode$ TapsForMana | ValidCard$ Island | Execute$ TrigMana | TriggerDescription$ Whenever a player taps an Island for mana, that player adds U to his or her mana pool (in addition to the mana the land produces).` +`SVar:TrigMana:AB$Mana | Cost$ 0 | Produced$ U | Amount$ 1` + +Effect is most similar to Token as it creates a pseudo-permanent, except +Effect creates in the command zone rather than the battlefield. It stays +active there for a set Duration. + +Parameters + + - Abilities,Triggers,SVars are comma separated lists which contain + SVars that point to the appropriate type that the Effect will gain. + - Duration is how long the Effect lasts. Right now, most effects will + last Until End of Turn. In the future, they may have other + conditions. + +Duration$ Permanent for effects that have no specific Duration. + + - Stackable$ False - Most Effects are assumed to be Stackable. By + setting the Stackable Flag to False, the AI will know having a + second one in play is useless, so will save it's Resource for + something else. + - Image - a file\_name\_without\_extension (image needs to reside in + the tokens directory) + +## Explore + +## Fight + +## Fog + +Fog is an ability 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. + +## Game outcome + +### GameDraw + +### GameLoss + +### GameWin + +### RestartGame + +Used in the script of *Karn Liberated* + +## Goad + +## Investigate + +## Mana + +For lands or other permanent to produce mana. + +`A:AB$ Mana | Cost$ T | Produced$ | SpellDescription$ Add W to your mana pool.` + +In this example ManaType would be W. + +## Manifest + +## PermanentState + +API for things that alter a permanent's state. + +### Phases + +### SetState + +Changing a cards State. This is mostly for Flip Cards or the Transform mechanic. + +### Tap + +`A:AB$ Tap | Cost$ R | ValidTgts$ Wall | TgtPrompt$ Select target wall | SpellDescription$ Tap target wall.` + +### TapOrUntap + +### Untap + +`A:AB$ Untap | Cost$ G | ActivationLimit$ 1| SpellDescription$ Untap CARDNAME. Activate this ability only once each turn.` +`A:SP$ Untap | Cost$ W | ValidTgts$ Permanent | TgtPrompt$ Select target permanent | SpellDescription$ Untap target permanent.` + +Target is optional. If not provided, will untap the permanent with this ability. + +## Play + +Playing a card or cards as part of SA. 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. + +Sunbird's Invocation uses many of the parameters. + +Amount - How many cards can be played (a non-negative integer or "All"). + +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. + +ShowCards - Other cards in the zone to show when selecting valid cards. + +Optional - Casting the card is optional. + +RememberPlayed - Remember the card played. + +ForgetRemembered - Remove all remembered cards from the source (but only +if a card was successfully played) + +ForgetTargetRemembered - Remove the played card from remembered cards +(but only if it was successfully played) + +WithoutManaCost - The card can be cast without mana payment. + +## PreventDamage + +AF damage prevention effects. + + - A:SP$ PreventDamage | Cost$ W | ValidTgts$ Creature | Amount$ 3 + | TgtPrompt$ Select target creature | SpellDescription$ Prevent + the next 3 damage that would be dealt to target creature this + turn. + +## Protection + +Protection grants protection from colors or cards types, or creature +types. Anything that has "Protection from ..." + +Gains - required - the thing to gain protection from (green, artifacts, +Demons, etc.) or "Choice" if you can choose one of... + +Choices - optional +- if Gains$ Choice then this is a comma-delimited list of choices + +## Pump + +This factory handles pumping creatures power/toughness or granting abilities to permanents (usually creatures). + + - A:AB$ Pump | Cost$ R | NumAtt$ +1 | SpellDescription$ CARDNAME + gets +1/+0 until end of turn. + - A:SP$ Pump | Cost$ 1 U | ValidTgts$ Creature | KW$ Shroud| + SpellDescription$ Target creature gains shroud until end of + turn. | TgtPrompt$ Select target creature. + +Target is optional. If it's not provided, the activating permanent will be pumped. + +NumAtt$ is optional, will pump Power. + +NumDef$ is optional, will pump Toughness. + +KW$ is optional, will give temporary keywords. + +## Regenerate + +Regenerate is similar to abilities like Pump. But for creating +Regeneration shields. + + - A:AB$ Regenerate | Cost$ B | SpellDescription$ Regenerate + CARDNAME + - A:SP$ Regenerate | Cost$ W | ValidTgts$ Creature | TgtPrompt$ + Select target creature | SpellDescription$ Regenerate target + creature. + +Target is optional. If not provided, will regenerate the permanent with this ability. + +## Repeat + +Repeat the specified ability. + +### Repeat + +`A:SP$ Repeat | Cost$ 3 B B | RepeatSubAbility$ DBDig | RepeatOptional$ True` + + - MaxRepeat - optional - the maxium times to repeat, execute repeat + ability at least once + - RepeatSubAbility - required - setup subability to repeat + - RepeatOptional - optional - you make the choice whether to repeat + the process + - RepeatPresent, RepeatCompare, RepeatDefined, RepeatCheckSVar, + RepeatSVarCompare - optional - condition check + +### RepeatEach + + - 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 + +## Reveal + +### RevealHand + +Look at a player's hand. + +Target or Defined is required. + +`A:AB$ RevealHand | Cost$ T | ValidTgts$ Player | TgtPrompt$ Select target player | SpellDescription$ Look at target player's hand.` + +### Reveal + +`A:AB$ Reveal | Cost$ 2 U T | Defined$ You | RevealValid$ Card.Blue | AnyNumber$ True | RememberRevealed$ True` + +Parameters: + + - RevealValid: to limit the valid cards. + - AnyNumber + - Random + - RememberRevealed: to remember the cards revealed + +### PeekAndReveal + +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. + +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 + +## RollDice + +## Sacrifice + +Usually you choose a player and that player has to sacrifice something + +`A:SP$ Sacrifice | Cost$ 1 B | ValidTgts$ Player | SacValid$ Creature | SacMessage$ Creature | Amount$ 2 | SpellDescription$ Target player sacrifices a creature.` + +Destroy$ True - An optional parameter for destroying permanents target +player chooses (eg: Burning of Xinye, or Imperial Edict). + +`A:SP$ Sacrifice | Cost$ 1 B | ValidTgts$ Opponent | SacValid$ Creature | SacMessage$ Creature | Destroy$ True | SpellDescription$ Target opponent chooses a creature he or she controls. Destroy it.` + +## Scry + +`A:AB$ Scry | Cost$ 1 T | ScryNum$ 2` + +## StoreSVar + +## Token + +Token simply lets you create tokens of any type. + +`A:SP$ Token | Cost$ 3 W U | TokenImage$ W 1 1 Bird Flying | TokenAmount$ X | TokenName$ Bird | TokenTypes$ Creature,Bird | TokenOwner$ You | TokenColors$ Blue | TokenPower$ 1 | TokenToughness$ 1 | TokenKeywords$ Flying` + +This ability factory does not take a target. All the parameters are +mandatory except for TokenKeywords. If you provide a non-integer for +TokenAmount, TokenPower or TokenToughness the AF will attempt to look for +an SVar of that name and interpret it's contents as a Count$ line. Worth +noting is that TokenTypes and TokenColors are simple commaseparated +lists while TokenKeywords is a list where the items are separated by +"\<\>". If TokenImage is not provided, the factory will attempt to +construct a filename on it's own. TokenOwner can use Defined-like +parameters, such as "You" "Opponent" or the new Triggered-Variables. + +You can also use the parameters TokenAbilities$, TokenTriggers$ and +TokenSVars$ to give the created tokens any number of either. For +example, here's how Growth Spasm creates an Eldrazi Spawn token complete +with ability. + + SVar:DBToken:DB$Token | TokenAmount$ 1 | TokenName$ Eldrazi Spawn | TokenTypes$ Creature,Eldrazi,Spawn | TokenOwner$ You | TokenColors$ Colorless | TokenPower$ 0 | TokenToughness$ 1 | TokenAbilities$ ABMana SVar:ABMana:AB$Mana | Cost$ Sac<1/CARDNAME> | Produced$ 1 | Amount$ 1 | SpellDescription$ Add 1 to your mana pool. + +As another example, here's Mitotic Slimes' use of TokenTriggers$: + + T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigTokenSenior | TriggerDescription$ When CARDNAME is put into a graveyard from the battlefield, put two 2/2 green Ooze creature tokens onto the battlefield. They have "When this creature is put into a graveyard, put two 1/1 green Ooze creature tokens onto the battlefield." + SVar:TrigTokenSenior:AB$ Token | Cost$ 0 | TokenImage$ g 2 2 ooze | TokenName$ Ooze | TokenTypes$ Creature,Ooze | TokenColors$ Green | TokenOwner$ You | TokenPower$ 2 | TokenToughness$ 2 | TokenAmount$ 2 | TokenTriggers$ TriggerJunior | TokenSVars$ TrigTokenJunior + SVar:TriggerJunior:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigTokenJunior | TriggerDescription$ When this creature is put into a graveyard, put two 1/1 green Ooze creature tokens onto the battlefield. SVar:TrigTokenJunior:AB$Token | Cost$ 0 | TokenImage$ g 1 1 ooze | TokenName$ Ooze | TokenTypes$ Creature,Ooze | TokenColors$ Green | TokenOwner$ You | TokenPower$ 1 | TokenToughness$ 1 | TokenAmount$ 2 + +## Trigger + +If possible split the SpellDescription$ of the the effect so the part for the trigger can become the StackDescription directly. + +### DelayedTrigger + +### ImmediateTrigger + +## Turn structure + +### AddPhase + +### AddTurn + +`A:SP$ AddTurn | Cost$ 1 U | NumTurns$ 1 | SpellDescription$ Take an extra turn after this one.` + +### EndTurn + +### ReverseTurnOrder + +### SkipPhase + +### SkipTurn + +## ZoneAffecting + +For specific effects that handle zones in a specific manner + +### ChangeZone + +ChangeZone is a united front of any card that changes zone. This does +not include: drawing, discarding, destroying, or milling, as these +represent specific words on which triggers and replacements can react. +There are two primary forms, but the distinction is handled mostly in +the codebase. The only thing that is required is to set appropriate parameters. + +Origin and Destination are both required. + +Origin is where the card is coming from. + +Destination is where the card is going to. If Destination is Library, a +LibraryPosition is recommended, but not required. **Default value of the +LibraryPosition is 0.** 0 represents the top of the library, -1 represents the bottom. + +There are two primary versions of ChangeZone. + +#### Hidden Origin + +The first is hidden, generally used for Origin zones that are not known +information, like the Library or the Hand. The choice of "What card is +changing zones?" happens during resolution. + +`A:SP$ ChangeZone | Cost$ W | Origin$ Library | Destination$ Library | LibraryPosition$ 0 | ChangeType$ Artifact,Enchantment | ChangeNum$ 1 | SpellDescription$ Search your library for an artifact or enchantment card and reveal that card. Shuffle your library, then put the card on top of it.` +`A:AB$ ChangeZone | Cost$ T | Origin$ Hand | Destination$ Battlefield | ChangeType$ Land | ChangeNum$ 1 | Optional$ True | SpellDescription$ You may put a land card from your hand onto the battlefield.` + +For Hidden, things like ChangeType and ChangeNum are used to restrict +what can ChangeZone, and how many do. There are two parameters special +to Hidden Origin: + +"Chooser" defines which player has to decide which card changes zone +(example You, Opponent). + +"Mandatory" most of these abilities are not mandatory, but some are. + +#### Known Origin + +The second is known, generally used for Origin zones that are known +information, like the Battlefield or the Graveyard. The choice of "What +card is changing zones?" happens on activation, generally by targeting. + +`A:AB$ ChangeZone | Cost$ 1 U T | TgtPrompt$ Choose target artifact card in your graveyard | ValidTgts$ Artifact.YouCtrl | Origin$ Graveyard | Destination$ Library | SpellDescription$ Put target artifact card from your graveyard on top of your library.` +`A:SP$ ChangeZone | Cost$ U U | ValidTgts$ Permanent | TgtPrompt$ Select target permanent | Origin$ Battlefield | Destination$ Hand | SpellDescription$ Return target permanent to its owner's hand.` + +For Known, since it just uses Target, normal target parameters are used in this Scenario. + +### ChangeZoneResolve + +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" 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 + +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." +Think of Impulse. + +- DigNum - Required - look at the top number of cards of your library. +- Reveal - Optional - for abilities that say "Reveal the top X cards + of your library". Default is false. +- SourceZone - Optional - the zone to dig in. Default is Library. +- DestinationZone - Optional - the zone to put the Y cards in. Default + is Hand. +- LibraryPosition - Optional - if DestinationZone is Library, use this + to specify position. Default is -1 (bottom of library). +- ChangeNum - Optional - the number of cards to move to the + DestinationZone (or "All" when it's for things like "put all lands + revealed this way into your hand"). Default is 1. +- ChangeValid - Optional - use this to specify if "you may move an + artifact to DestinationZone". Default is any Card. +- AnyNumber - Optional - use if you can move any number of Cards to + DestinationZone. Default is false. (think of Lead the Stampede) +- Optional - Optional - set this if you "may" move a card to + DestinationZone. Default is false. +- DestinationZone2 - Optional - the zone to put the rest of the cards + in. If it is library, you are prompted for the order. Default is + Library. +- LibraryPosition2 - Optional - if DestinationZone2 is Library, use + this to specify position. Default is -1 (bottom of library). + +### DigUntil + +### Discard + +`A:AB$ Discard | Cost$ T | ValidTgts$ Opponent | NumCards$ 1 | Mode$ TgtChoose | SpellDescription$ Target opponent discards a card. ` + + - NumCards - the number of cards to be discarded (may be integer or X) + - Mode - the mode of discard - should match spDiscard + - Random + - TgtChoose + - RevealYouChoose + - Hand + - DiscardValid - a ValidCards syntax for acceptable cards to discard + - UnlessType - a ValidCards expression for "discard X unless you + discard " + +### Draw + +`A:AB$ Draw | Cost$ 1 Sac<1/CARDNAME> | NumCards$ 1 | SpellDescription$ Draw a card.` + +### Mill + +`A:AB$ Mill | Cost$ 2 T | NumCards$ 2 | ValidTgts$ Player | TgtPrompt$ Choose a player to mill | SpellDescription$ Target player puts the top two cards of his or her library into his or her graveyard.` + +### RearrangeTopOfLibrary + +### Shuffle + +Used for shuffling a player's library + + - Optional - Set this parameter if the user should be + prompted Yes/No to shuffle the given library. Default is false. + +### TwoPiles + +## Vote diff --git a/docs/Card-scripting-API/Card-scripting-API.md b/docs/Card-scripting-API/Card-scripting-API.md new file mode 100644 index 00000000000..cd1c7a962a0 --- /dev/null +++ b/docs/Card-scripting-API/Card-scripting-API.md @@ -0,0 +1,356 @@ +A reference guide for scripting cards using the API parsed by the Forge engine. + +# Base Structure + +By opening any file in the /res/cardsfolder folder you can see the basic structure of how the data is created.
+Here's an example of a vanilla creature: + +``` +Name:Vanilla Creature +ManaCost:2 G +Types:Creature Beast +PT:2/2 +Oracle: +``` + +The name of this card is Vanilla Creature.
+It's casting cost is {2}{G}.
+It has the types Creature and Beast.
+It has a Power-Toughness of 2/2.
+It will not display any additional text in the card's template.
+ +If a card has two faces, use AlternateMode:{CardStateName} in the front face and separate both by a new line with the text "ALTERNATE". + +There are a few other properties that will appear in many cards. These are + +| Property | Description +| - | - +|`A`|[Ability effect](AbilityFactory) +|`AI`|RemoveDeck:
* `All`
This will prevent the card from appearing in random AI decks. It is applicable for cards the AI can't use at all like Dark Ritual and also for cards that the AI could use, but only ineffectively like Tortoise Formation. The AI won't draft these cards.
* `Random`
This will prevent the card from appearing in random decks. It is only applicable for cards that are too narrow for random decks like Root Cage or Into the North. The AI won't draft these cards.
* `NonCommander`
+|`Colors`|Color(s) of the card

When a card's color is determined by a color indicator rather than shards in a mana cost, this property must be defined. If no identifier is needed, this property should be omitted.

* `Colors:red` - This is used on Kobolds of Kher Keep, which has a casting cost of {0} and requires a red indicator to make it red.

* `Colors:red,green` - Since Arlinn, Embraced by the Moon has no casting cost (it's the back of a double-faced card), the red and green indicator must be included. +|`DeckHints`|AI-related hints for a deck including this card

To improve synergy this will increase the rank of of all other cards that share some of its DeckHints types. This helps with smoothing the selection so cards without these Entries won't be at an unfair disadvantage.

The relevant code can be found in the [CardRanker](https://git.cardforge.org/core-developers/forge/-/blob/master/forge-gui/src/main/java/forge/gamemodes/limited/CardRanker.java) class. +|`DeckNeeds`|This can be considered a stronger variant when the AI should not put this card into its deck unless it has whatever other type is specified. The way this works is "inverted": it will directly decrease the rank of the card unless other cards are able to satisfy its types.
If a card demands more than one kind of type you can reuse it:
`DeckNeeds:Type$Human & Type$Warrior` will only find Human Warrior compared to `DeckNeeds:Type$Human\|Warrior` which is either +|`DeckHas`|specifies that the deck now has a certain ability (like, token generation or counters) so that the drafting/deckbuilding AI knows that it now meets requirements for DeckHints/DeckNeeds. This is actually very useful since many of these (such as `Ability$Graveyard, Ability$Token, Ability$Counters`) are not deduced by parsing the abilities, so an explicit hint is necessary. Using the other types is also supported in case the implicit parsing wouldn't find it.
It doesn't require exact matching to have an effect but cards that care about multiple entries for a given type will be judged higher if a card seems to provide even "more" synergy for it.
Example:
Chishiro has two abilities so `DeckHas:Ability$Token & Ability$Counters` is used, therefore score for `DeckNeeds:Ability$Token\|Counters` is increased +|`K`|Keyword (see below) +|`Loyalty`|Number of starting loyalty counters +|`ManaCost`|Cost to cast the card shown in mana shards

This property is required. It has a single parameter that is a mana cost.

* `ManaCost:no cost` for cards that cannot be cast
* `ManaCost:1 W W` sets the casting cost to {1}{W}{W} +|`Name`|Name of the card

A string of text that serves as the name of the card. Note that the registered trademark symbol cannot be included, and this property must have at least one character.

Example:
* `Name:A Display of My Dark Power` sets the card's name to "A Display of My Dark Power" +|`Oracle`|The current Oracle text used by the card.

We actually have a Python Script that runs to be able to fill in this information, so don't worry about manually editing a lot of cards when Wizards decides to change the rules.

This field is used by the Deck Editor to allow non-Legendary Creatures to be marked as potential commanders. Make sure "CARDNAME can be your commander." appears in the oracle text. +|`PT`|Power and toughness +|`R`|[Replacement effect](Replacements) +|`S`|[Static ability](static-abilities) +|`SVar`|String variable. Used throughout scripting in a handful of different ways. +|`T`|[Triggered ability](Triggers) +|`Text`|Additional text that needs to be displayed on the CardDetailPanel that doesn't have any spell/ability that generates a description for it, for example "CARDNAME can be your commander." or "X can't be 0.". +|`Types`|Card types and subtypes

Include all card types and subtypes, separated by spaces.

Example:
* `Types:Enchantment Artifact Creature Golem` for a card that reads Enchantment Artifact Creature -- Golem + +Rarity and Set info are now defined in edition definition files. These can be found at /res/reditions path. + +## Conventions +- filename: all lowercase, skip special characters, underscore for spaces +- Unix(LF) line endings +- use empty lines only when separating multiple faces on a card +- try to avoid writing default params to keep scripts concise + - e.g. just `SP$ Draw` instead of `SP$ Draw | Defined$ You | NumCards$ 1` + +# Keywords + +All keywords need to be prepended with "K:" to be parsed correctly. Each keyword must appear on a separate line. + +## Keywords without Parameters + +This section is for Keywords that require no additional parameters and are one or two words long. Most of these you would see exactly on cards in the game.
+Examples: + +- Cascade +- Changeling +- Cipher +- Conspire +- Convoke +- Deathtouch +- Defender +- Delve +- Devoid +- Double Strike +- Epic +- Exalted +- Fear +- First Strike +- Flanking +- Flash +- Flying +- Forestwalk +- Fuse +- Haste +- Hideaway +- Horsemanship +- Indestructible +- Infect +- Intimidate +- Islandwalk +- Landfall +- Legendary landwalk +- Lifelink +- Living Weapon +- Menace +- Mentor +- Mountainwalk +- Nonbasic landwalk +- Persist +- Plainswalk +- Prowess +- Provoke +- Reach +- Rebound +- Retrace +- Riot +- Shadow +- Shroud +- Snow forestwalk +- Snow islandwalk +- Snow landwalk +- Snow mountainwalk +- Snow plainswalk +- Snow swamp walk +- Soulbond +- Split second +- Storm +- Sunburst +- Swampwalk +- Totem Armor +- Trample +- Unblockable +- Undying +- Vigilance +- Wither + +## Keywords with parameters + +- Adapt:{cost} +- AdjustLandPlays:{params} +- Afterlife:{N} +- AlternateAdditionalCost:{cost} +- Amplify:{cost}:{validType(comma separated)} +- Annihilator:{magnitude} +- Bloodthirst:{magnitude} +- Bestow:{cost} +- Bushido:{magnitude} +- CantBeBlockedByAmount {xMath} +- Champion:{validType} +- CostChange:{params} +- Crew:{cost} +- Cumulative upkeep:{cost}:{Description} +- Cycling:{cost} +- Dash:{cost} +- Devour:{magnitude} +- Dredge:{magnitude} +- Echo:{cost} +- Emerge:{cost} +- Enchant {params} \[Curse\] +- Enchant {Type} +- Entwine:{cost} +- Equip:{cost} +- etbCounter:{CounterType}:{CounterAmount} +- ETBReplacement:{Control/Copy/Other}:{AbilitySVar}\[:Optional\] +- Evoke:{cost} +- Fabricate:{cost} +- Fading:{FadeCounters} +- Flashback:{cost} +- Foretell:{cost} +- Fortify:{cost} +- Graft:{value} +- Haunt:{ability}:{Description} +- Hexproof:{ValidCards}:{Description} +- Kicker:{cost} +- Level up:{cost} +- Madness:{cost} +- ManaConvert: +- maxLevel:{magnitude} +- MayEffectFromOpeningHand:{Effect} +- Miracle:{cost} +- Modular:{magnitude} +- Monstrosity:{cost} +- [Mega]Morph:{cost} +- Multikicker:{magnitude} +- Mutate:{cost} +- Ninjutsu:{cost} +- Outlast:{cost} +- Partner:{CardName} +- Poisonous {magnitude} +- PreventAllDamageBy {ValidCards} +- Protection:{ValidCards}:{Description} +- Prowl:{cost} +- Rampage:{magnitude} +- Recover:{cost} +- Renown:{N} +- Replicate:{cost} +- Ripple:{magnitude} +- Soulshift:{magnitude} +- Strive:{cost} +- Suspend:{turns}:{cost} +- Transmute:{cost} +- Toxic:{poisonCounters} +- TypeCycling:{Type}:{cost} +- Unearth:{cost} +- UpkeepCost:{cost} +- Vanishing:{TimeCounters} + +## Plaintext keywords + +These are hardcoded but not truly keywords rules-wise and will eventually be turned into static abilities. +Only listing the most common ones here so you can recognize them. +CARDNAME is replaced by the card's name ingame. + +- All creatures able to block CARDNAME do so. +- CARDNAME assigns no combat damage +- CARDNAME attacks each turn if able. +- CARDNAME attacks each combat if able. +- CARDNAME blocks each combat if able. +- CARDNAME blocks each turn if able. +- CARDNAME can attack as though it didn't have defender. +- CARDNAME can attack as though it had haste. +- CARDNAME can block as though it were untapped. +- CARDNAME can block creatures with shadow as though they didn't have shadow. +- CARDNAME can block creatures with landwalk abilities as though they didn't have those abilities. +- CARDNAME can block only creatures with flying. +- CARDNAME can only attack alone. +- CARDNAME can't attack. +- CARDNAME can't attack if you cast a spell this turn. +- CARDNAME can't attack if defending player controls an untapped creature with power {rest of text string} +- CARDNAME can't attack or block. +- CARDNAME can't attack or block alone. +- CARDNAME can't be countered. +- CARDNAME can't be enchanted. +- CARDNAME can't be equipped. +- CARDNAME can't be regenerated. +- CARDNAME can't be the target of Aura spells. +- CARDNAME can't block. +- CARDNAME can't block creatures with power {rest of text string} +- CARDNAME can't block unless a creature with greater power also blocks. +- CARDNAME can't block unless at least two other creatures block. +- CARDNAME can't transform +- CARDNAME doesn't untap during your untap step. +- CARDNAME enters the battlefield tapped. +- CARDNAME is {color}. +- CARDNAME must be blocked if able. +- CARDNAME must be blocked by exactly one creature if able. +- CARDNAME must be blocked by two or more creatures if able. +- CARDNAME can't be blocked unless all creatures defending player controls block it. +- CARDNAME's power and toughness are switched +- CARDNAME untaps during each other player's untap step. +- CARDNAME's activated abilities can't be activated. +- Creatures with power greater than CARDNAME's power can't block it. +- Creatures can't attack unless their controller pays:{params} +- Damage that would be dealt by CARDNAME can't be prevented. +- Damage that would reduce your life total to less than 1 reduces it to 1 instead. +- Enchant artifact +- Enchant creature +- Enchant creature with converted mana cost 2 or less +- Enchant creature without flying +- Enchant red or green creature +- Enchant land +- Enchant land you control +- Enchant tapped creature +- No more than one creature can attack each combat. +- No more than one creature can block each combat. +- No more than two creatures can attack you each combat. +- No more than two creatures can block each combat. +- Play with your hand revealed. +- Prevent all combat damage that would be dealt to and dealt by CARDNAME. +- Prevent all combat damage that would be dealt by CARDNAME. +- Prevent all combat damage that would be dealt to CARDNAME. +- Prevent all damage that would be dealt to and dealt by CARDNAME. +- Prevent all damage that would be dealt by CARDNAME. +- Prevent all damage that would be dealt to CARDNAME. +- Protection from {type} +- Remove CARDNAME from your deck before playing if you're not playing for ante. +- Spells and abilities your opponents control can't cause you to sacrifice permanents. +- You can't pay life to cast spells or activate abilities. +- You can't sacrifice creatures to cast spells or activate abilities. +- You can't draw cards. +- You can't gain life. +- You can't lose the game. +- You can't win the game. +- You don't lose the game for having 0 or less life. +- You may choose not to untap CARDNAME during your untap step. +- You may have CARDNAME assign its combat damage as though it weren't blocked. +- Your life total can't change. + +# General SVars + +`SVar:SoundEffect:goblinpolkaband.mp3` + +The sound system supports a special SVar that defines the sound that should be played when the spell is cast. + +`SVar:X:Count$` + +Count is our general value computation function. It's quite varied with a lot of different things it can calculate and is often being updated. + +# AI specific SVars + +`SVar:AIPreference:SacCost$Creature.token,Creature.cmcLE2` + +`SVar:AntiBuffedBy:[ValidCards]` + +If a permanent with this SVar is on the battlefield under human control +the AI will play the specified cards in Main1. Applicable for cards like +Heart Sliver or Timid Drake. + +`SVar:BuffedBy:[ValidCards]` + +If a permanent with this SVar is on the battlefield under its control +the AI will play the specified cards in Main1. Applicable for creatures +with a P/T setting static ability (Kithkin Rabble) or additional buffes +(Radiant, Archangel). + +`SVar:EnchantMe:[Multiple]/[Once]` + +Creatures with "Multiple" in this SVar will always be prefered when the +AI enchants (Rabid Wombat), creatures with "Once" only if they are not +enchanted already (Gate Hound). + +`SVar:EquipMe:[Multiple]/[Once]` + +Creatures with "Multiple" in this SVar will always be prefered when the +AI equippes (Myr Adapter), creatures with "Once" only if they are not +equipped already (Kor Duelist). + +`SVar:AIEvaluationModifier:[ValidAmount]` + +`SVar:EndOfTurnLeavePlay:True` + +`SVar:maxLevel:` + +`SVar:HasCombatEffect:True` + +`SVar:HasAttackEffect:True` + +`SVar:HasBlockEffect:True` + +`SVar:MustAttack:True` + +`SVar:MustBeBlocked:True` + +`SVar:NeedsToPlayVar:[ValidCards]` + +`SVar:ManaNeededToAvoidNegativeEffect:` + +`SVar:NonStackingEffect:True` + +`SVar:PlayMain1:TRUE/ALWAYS/OPPONENTCREATURES` + +The AI will play cards with this SVar in its first main phase. Without other AILogic, it will usually not play any permanents without this in Main1. + +`SVar:SacMe:[number]` + +The AI will sacrifice these cards to pay costs. The higher the number the higher the priority. Example: Hatching Plans has SVar:SacMe:5. + +`SVar:Targeting:Dies` + +`SVar:UntapMe:True` + +The AI will prioritize untapping of this card. + +`SVar:AIUntapPreference:` + +`SVar:NoZeroToughnessAI:True` diff --git a/docs/Card-scripting-API/Costs.md b/docs/Card-scripting-API/Costs.md new file mode 100644 index 00000000000..ff92bda177b --- /dev/null +++ b/docs/Card-scripting-API/Costs.md @@ -0,0 +1,186 @@ +Cost is a class that attempts to streamline costs throughout all cards. It requires that each cost is separated by a space. I will use examples that could be found in Ability, although certain Keyworded abilities do use Cost too. + +# Common + +## Description + +Description is an optional last parameter in the cost. This is to allow +for complex Type definitions to have a nice Description that is readable. + +## CostDesc / PrecostDesc + +## UnlessCost + +UnlessCost allows the player specified with UnlessPayer (same as +Defined, defaults to TargetedController) to pay mana to prevent the +resolving of the ability. If the script has the param "UnlessSwitched", +then the player pays mana to resolve the ability (usually used to handle +"any player may pay ..." ). + +## XChoice + +XChoice is the variable that basically means "You can choose whatever +you want for this variable. But you need to decide what X is before you +start paying." This would commonly appear as an SVar definition of X. + +## xPaid + +xPaid is the amount of Mana Paid for an X Cost. There are a few cards +that will use the X Payment to determine other costs (like Abandon Hope) +This would commonly appear as an SVar definition of X. + +## CARDNAME + +For Costs that do something to themselves (ex. Discard Self, Sacrifice +Self) + +# Types of Cost + +## Discard + +Discard has two required parameters and one optional in the form +Discard + +- The first is how many cards are being discarded. +- The second is what card types can be discarded. (Hand for the whole + hand, Random for chosen randomly) + +## Draw + +## Exert + +## Exile + +Exile has two required parameters and one option in the form of +Exile + +There are also a few sister abilities that all fit under the Exile +umbrella. + +- Exile (for cards on the Battlefield) +- ExileFromGraveyard +- ExileFromHand +- ExileFromTop (for cards on top of your library, this doesn't default + Type to Card, so make sure you add it) + +Some Examples + +- Exile<1/Creature> +- Exile<1/CARDNAME> +- ExileFromHand<1/CARDNAME> +- ExileFromHand<2/Creature> +- ExileFromGrave<1/CARDNAME> +- ExileFromGrave<1/Treefolk> +- ExileFromTop<10/Card> + +## FlipCoin + +Only used by "Karplusan Minotaur". + +## Mana + +- Cost$ 2 + - 2 colorless mana +- Cost$ B R + - 1 black and 1 red mana +- Cost$ WG + - Hybrid White/Green mana +- Cost$ S + - Snow Mana +- Cost$ Mana<2\\Creature> + - 2 colorless produced by a source with type 'creature'. Note the + backslash - it was chosen because hybrid costs already use slash + +Here's some examples: + +- Discard<1/Card> + - "Discard 1 Card" +- Discard<0/Hand> (The number is ignored when Hand is used as a + type.) + - Discard your hand +- Discard<2/Random> + - Discard 2 Cards at Random +- Discard<1/CARDNAME> + - Discard Self (CARDNAME) +- Discard<1/Creature.Black/Black Creature> + - Discard 1 Black Creature + +## Mill + +## Subtract(Remove) Counter + +SubCounter has two required parameters in the form of +SubCounter + +- SubCounter<2/P1P1> +- SubCounter<1/CHARGE> + +Remember the token name should appear all in caps. + +As third parameter you can use a ValidCard. + +## Sacrifice + +Sacrifice has two required parameters and one optional parameter in the +form of Sac + +- Sac<1/Artifact> +- Sac<1/CARDNAME> + +## Tap + +- Cost$ T + +## Untap + +- Cost$ Untap + +\- or - + +- Cost$ Q + +## Unattach + +## PayEnergy + +## PayLife + +PayLife has one required parameter in the form of PayLife + +- PayLife<2> + +## GainLife + +## TapXType + +TapXType has two required parameters and one option in the form of +tapXType + +- tapXType<3/Creature.White> + +## Return + +Return has two required parameters and one optional in the form of +Return + +- Return<1/Land> +- Return<1/CARDNAME> + +## Reveal + +# Putting it Together + +Putting it together is pretty simple. If a card needs to pay mana and tap, it would look like this: + +- Cost$1 W T + +For a spell that has an additional cost of sacrificing a land, put the +mana cost and the additional cost in the cost: + +- Cost$2 G Sac<1/Land> + +One of the features of Cost is you can have more than one of the same Cost type: + +- Cost$ Sac<1/Swamp> Sac<1/Creature> + +There are many examples, but they mostly fall into those categories. diff --git a/docs/Card-scripting-API/Replacements.md b/docs/Card-scripting-API/Replacements.md new file mode 100644 index 00000000000..e88520506a4 --- /dev/null +++ b/docs/Card-scripting-API/Replacements.md @@ -0,0 +1,90 @@ +Replacement create replacement effects, as you'd expect. Their script +follows the format introduced by AbilityFactory; simply begin a line +with "R:", to indicate that it's for a replacement effect, followed by a +collection of name-value pairs (name and value are separated by $) +separated by pipes (|). All Replacement effects expect an "Event$" +parameter, which declares what event should be replaced. Most replacement effects will also have a "ReplaceWith$" parameter which points to an SVar which contains what should replace the event. They may have a "Prevent$True" parameter, instead though, which means that nothing happens instead of the event. + +Similarly to triggers, the replacing code can access special variables +pertaining to the event it replaced (like triggered-variables). These +are specific to each event, and is listed below. Most replacement effects +will also have a "Description$" parameter which is simply the card text +for the ability. + +## DamageDone + +DamageDone events are checked when damage is about to be assigned to a +card or player. There are 5 special parameters: + + - ValidSource - The damage source must match this for the event to be + replaced. + - ValidTarget - The damage target must match this for the event to be + replaced. + - DamageAmount - The amount of damage must match this. + - IsCombat - If true, the damage must be combat damage, if false, it + can't be. + - IsEquipping - If true, the host card must be equipping something. + +There are 3 Replaced-variables: + + - DamageAmount - The amount of damage to be assigned. + - Target - The target of the damage. + - Source - The source of the damage. + +## Discard + +Discard events are checked when a player is about to discard a card. +There are 4 special parameters: + + - ValidPlayer - The player who would discard must match this. + - ValidCard - The the card that would be discarded must match this. + - ValidSource - The card causing the discard must match this. + - DiscardFromEffect - If true, only discards caused by spells/effects + will be replaced. Cleanup/statebased discards will not. + +There are 2 Replaced-variables: + + - Card - The card that would be discarded. + - Player - The player that would have discarded + +## Draw + +Draw events are checked when a player is about to draw a card. There is +1 special parameter: + + - ValidPlayer - The player who would draw must match this. + +There are no Replaced-variables. + +## GainLife + +GainLife events are checked when a player would gain life. There is 1 +special parameter: + + - ValidPlayer - The player who would gain life must match this. + +There is 1 Replaced-variable: + + - LifeGained - The amount of damage to be gained. + +## GameLoss + +GameLoss events are checked when a player would lose. There is 1 special +parameter: + + - ValidPlayer - The player who would lose must match this. + +There are no Replaced-variables. + +## Moved + +Moved events are checked when a card would be moved between zones. There +are 3 special parameters: + + - ValidCard - The moving card must match this. + - Origin - The card must be moving from this zone. + - Destination - The card must be moving to this zone. + +There is 1 Replaced-variable: + + - Card - The moving card. diff --git a/docs/Card-scripting-API/Restrictions.md b/docs/Card-scripting-API/Restrictions.md new file mode 100644 index 00000000000..f9006261059 --- /dev/null +++ b/docs/Card-scripting-API/Restrictions.md @@ -0,0 +1,103 @@ +### Activation + +Activation$