This commit is contained in:
fanch
2024-10-17 17:06:59 +02:00
1922 changed files with 4313 additions and 1857 deletions

View File

@@ -71,11 +71,11 @@ jobs:
- name: Install Android maven plugin - name: Install Android maven plugin
run: | run: |
mkdir -p ~/.m2/repository/com/simpligility/maven/plugins/android-maven-plugin/4.6.1 mkdir -p ~/.m2/repository/com/simpligility/maven/plugins/android-maven-plugin/4.6.2
cd ~/.m2/repository/com/simpligility/maven/plugins/android-maven-plugin/4.6.1 cd ~/.m2/repository/com/simpligility/maven/plugins/android-maven-plugin/4.6.2
curl -L -o android-maven-plugin-4.6.1.jar https://github.com/Card-Forge/android-maven-plugin/releases/download/4.6.1/android-maven-plugin-4.6.1.jar curl -L -o android-maven-plugin-4.6.2.jar https://github.com/Card-Forge/android-maven-plugin/releases/download/4.6.2/android-maven-plugin-4.6.2.jar
curl -L -o android-maven-plugin-4.6.1.pom https://github.com/Card-Forge/android-maven-plugin/releases/download/4.6.1/android-maven-plugin-4.6.1.pom curl -L -o android-maven-plugin-4.6.2.pom https://github.com/Card-Forge/android-maven-plugin/releases/download/4.6.2/android-maven-plugin-4.6.2.pom
#mvn install:install-file -Dfile=android-maven-plugin-4.6.1.jar -DgroupId=com.simpligility.maven.plugins -DartifactId=android-maven-plugin -Dversion=4.6.1 -Dpackaging=jar #mvn install:install-file -Dfile=android-maven-plugin-4.6.2.jar -DgroupId=com.simpligility.maven.plugins -DartifactId=android-maven-plugin -Dversion=4.6.2 -Dpackaging=jar
cd - cd -
mvn install -Dmaven.test.skip=true mvn install -Dmaven.test.skip=true
mvn dependency:tree mvn dependency:tree

View File

@@ -8,6 +8,11 @@ on:
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)' description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
required: false required: false
default: false default: false
upload_package:
type: boolean
description: 'Upload the completed Android package'
required: false
default: true
schedule: schedule:
# * is a special character in YAML so you have to quote this string # * is a special character in YAML so you have to quote this string
- cron: '00 19 * * *' - cron: '00 19 * * *'
@@ -74,11 +79,11 @@ jobs:
- name: Install Android maven plugin - name: Install Android maven plugin
run: | run: |
mkdir -p ~/.m2/repository/com/simpligility/maven/plugins/android-maven-plugin/4.6.1 mkdir -p ~/.m2/repository/com/simpligility/maven/plugins/android-maven-plugin/4.6.2
cd ~/.m2/repository/com/simpligility/maven/plugins/android-maven-plugin/4.6.1 cd ~/.m2/repository/com/simpligility/maven/plugins/android-maven-plugin/4.6.2
curl -L -o android-maven-plugin-4.6.1.jar https://github.com/Card-Forge/android-maven-plugin/releases/download/4.6.1/android-maven-plugin-4.6.1.jar curl -L -o android-maven-plugin-4.6.2.jar https://github.com/Card-Forge/android-maven-plugin/releases/download/4.6.2/android-maven-plugin-4.6.2.jar
curl -L -o android-maven-plugin-4.6.1.pom https://github.com/Card-Forge/android-maven-plugin/releases/download/4.6.1/android-maven-plugin-4.6.1.pom curl -L -o android-maven-plugin-4.6.2.pom https://github.com/Card-Forge/android-maven-plugin/releases/download/4.6.2/android-maven-plugin-4.6.2.pom
#mvn install:install-file -Dfile=android-maven-plugin-4.6.1.jar -DgroupId=com.simpligility.maven.plugins -DartifactId=android-maven-plugin -Dversion=4.6.1 -Dpackaging=jar #mvn install:install-file -Dfile=android-maven-plugin-4.6.2.jar -DgroupId=com.simpligility.maven.plugins -DartifactId=android-maven-plugin -Dversion=4.6.2 -Dpackaging=jar
cd - cd -
mvn install -Dmaven.test.skip=true mvn install -Dmaven.test.skip=true
mvn dependency:tree mvn dependency:tree
@@ -116,6 +121,7 @@ jobs:
- name: 📂 Sync files - name: 📂 Sync files
uses: SamKirkland/FTP-Deploy-Action@v4.3.4 uses: SamKirkland/FTP-Deploy-Action@v4.3.4
if: ${{ inputs.upload_package }}
with: with:
server: ftp.cardforge.org server: ftp.cardforge.org
username: ${{ secrets.FTP_USERNAME }} username: ${{ secrets.FTP_USERNAME }}

View File

@@ -1,50 +1,93 @@
# Forge # ⚔️ Forge: The Magic: The Gathering Rules Engine
Join the [Discord](https://discord.gg/HcPJNyD66a) Join the **Forge community** on [Discord](https://discord.gg/HcPJNyD66a)!
[![Test build](https://github.com/Card-Forge/forge/actions/workflows/test-build.yaml/badge.svg)](https://github.com/Card-Forge/forge/actions/workflows/test-build.yaml) [![Test build](https://github.com/Card-Forge/forge/actions/workflows/test-build.yaml/badge.svg)](https://github.com/Card-Forge/forge/actions/workflows/test-build.yaml)
## Introduction ---
Forge is a "Rules Engine" for the game Magic: the Gathering. ## ✨ Introduction
Forge is not related in any way with Wizards of the Coast.
Forge is open source software released under the GNU Public License.
Forge is developed by a community of programmers who love trading card games.
Forge is a cross-platform application and can be run on Windows, Mac, Linux and Android. It is written in Java. The engine is written in Java. The engine is designed to be extensible, so any interested programmer can join and help add new features and cards to the game. Any tech savvy user could read out card scripting system to create cards to be used inside Forge. **Forge** is a dynamic and open-source **Rules Engine** tailored for **Magic: The Gathering** enthusiasts. Developed by a community of passionate programmers, Forge allows players to explore the rich universe of MTG through a flexible, engaging platform.
The engine allows you to play in a handful of different single player environments or online against other players.
**Note:** Forge operates independently and is not affiliated with Wizards of the Coast.
## Installation ---
For a more in depth User Guide, please visit the [User Guide](https://github.com/Card-Forge/forge/wiki/User-Guide) ## 🌟 Key Features
For Desktop users, download the [Latest Releases](https://github.com/Card-Forge/forge/releases/latest) which are typically based around Set releases. - **🌐 Cross-Platform Support:** Play on **Windows, Mac, Linux,** and **Android**.
Or download the [Snapshot Build](https://downloads.cardforge.org/dailysnapshots/) the file that starts with "forge-gui-desktop". - **🔧 Extensible Architecture:** Built in **Java**, Forge encourages developers to contribute by adding features and cards.
This file is tarball, and may need to be extracted twice depending on which program is being used to extract it. - **🎮 Versatile Gameplay:** Dive into single-player modes or challenge opponents online!
We recommend extracting to a new folder rather than on top of an existing installation.
**For users who have played Forge before all of your user data is stored separately so you don't have to worry about losing it on upgrade.**
Java 8 or later is required to run Forge. Please make sure is the right version is installed in your enviroment. Check the user guide for more info. ---
For Android users, download the APK file from [Snapshot Build](https://downloads.cardforge.org/dailysnapshots/) to your device. ## 🛠️ Installation Guide
On first run, Forge will download all needed data.
## Modes of Play ### 📥 Desktop Installation
1. **Latest Releases:** Download the latest version [here](https://github.com/Card-Forge/forge/releases/latest).
2. **Snapshot Build:** For the latest development version, grab the `forge-gui-desktop` tarball from our [Snapshot Build](https://downloads.cardforge.org/dailysnapshots/).
- **Tip:** Extract to a new folder to prevent version conflicts.
3. **User Data Management:** Previous players data is preserved during upgrades.
4. **Java Requirement:** Ensure you have **Java 17 or later** installed.
Forge has a variety of ways to play the game. The most popular way is our Adventure mode, which is a single player campaign that allows you to play against a variety of AI opponents. ### 📱 Android Installation
You walk around an overworld map, and can challenge opponents to games of Magic. As you play, you'll collect more cards and items to improve your abilities. - Download the **APK** from the [Snapshot Build](https://downloads.cardforge.org/dailysnapshots/). On the first launch, Forge will automatically download all necessary assets.
Check the [Gameplay Guide](https://github.com/Card-Forge/forge/wiki/Gameplay-Guide) for more info. ---
## 🎮 Modes of Play
Forge offers various exciting gameplay options:
### 🌍 Adventure Mode
Embark on a thrilling single-player journey where you can:
- Explore an overworld map.
- Challenge diverse AI opponents.
- Collect cards and items to boost your abilities.
![Adventure Mode](https://downloads.cardforge.org/images/site/adventure-mode.png "Adventure Mode") ![Adventure Mode](https://downloads.cardforge.org/images/site/adventure-mode.png "Adventure Mode")
### 🔍 Quest Modes
Engage in focused gameplay without the overworld exploration—perfect for quick sessions!
Forge has several Quest modes, which is similar but without the overworld map. ### 🤖 AI Formats
Test your skills against AI in multiple formats:
- **Sealed**
- **Draft**
- **Commander**
- **Cube**
You can also play against the AI in a variety of formats, such as Sealed, Draft, Commander and Cube. For comprehensive gameplay instructions, visit our [Gameplay Guide](https://github.com/Card-Forge/forge/wiki/Gameplay-Guide).
## Questions ---
If you have any questions, please join the Discord channel. Read the #rules and the frequently-asked-questions. ## 💬 Support & Community
If your question is not answered there, feel free to ask in the #help channel.
Need help? Join our vibrant Discord community!
- 📜 Read the **#rules** and explore the **FAQ**.
- ❓ Ask your questions in the **#help** channel for assistance.
---
## 🤝 Contributing to Forge
We love community contributions! Interested in helping? Check out our [Contributing Guidelines](CONTRIBUTING.md) for details on how to get started.
---
## About Forge
Forge aims to deliver an immersive and customizable Magic: The Gathering experience for fans around the world.
### 📊 Repository Statistics
| Metric | Count |
|----------------|-------------------------------------------------------------|
| **⭐ Stars:** | [![GitHub stars](https://img.shields.io/github/stars/Card-Forge/forge?style=flat-square)](https://github.com/Card-Forge/forge/stargazers) |
| **🍴 Forks:** | [![GitHub forks](https://img.shields.io/github/forks/Card-Forge/forge?style=flat-square)](https://github.com/Card-Forge/forge/network) |
| **👥 Contributors:** | [![GitHub contributors](https://img.shields.io/github/contributors/Card-Forge/forge?style=flat-square)](https://github.com/Card-Forge/forge/graphs/contributors) |
---
**📄 License:** [GPL-3.0](LICENSE)

View File

@@ -3,7 +3,7 @@
<parent> <parent>
<artifactId>forge</artifactId> <artifactId>forge</artifactId>
<groupId>forge</groupId> <groupId>forge</groupId>
<version>1.6.65-SNAPSHOT</version> <version>1.6.66-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -6,7 +6,7 @@
<parent> <parent>
<artifactId>forge</artifactId> <artifactId>forge</artifactId>
<groupId>forge</groupId> <groupId>forge</groupId>
<version>1.6.65-SNAPSHOT</version> <version>1.6.66-SNAPSHOT</version>
</parent> </parent>
<artifactId>forge-ai</artifactId> <artifactId>forge-ai</artifactId>

View File

@@ -923,6 +923,10 @@ public class AiController {
if (checkCurseEffects(sa)) { if (checkCurseEffects(sa)) {
return AiPlayDecision.CurseEffects; return AiPlayDecision.CurseEffects;
} }
// TODO maybe other location for this?
if (!sa.isLegalAfterStack()) {
return AiPlayDecision.AnotherTime;
}
Card spellHost = card; Card spellHost = card;
if (sa.isSpell()) { if (sa.isSpell()) {
spellHost = CardCopyService.getLKICopy(spellHost); spellHost = CardCopyService.getLKICopy(spellHost);
@@ -930,10 +934,6 @@ public class AiController {
spellHost.setLastKnownZone(game.getStackZone()); // need to add to stack to make check Restrictions respect stack cmc spellHost.setLastKnownZone(game.getStackZone()); // need to add to stack to make check Restrictions respect stack cmc
spellHost.setCastFrom(card.getZone()); spellHost.setCastFrom(card.getZone());
} }
// TODO maybe other location for this?
if (!sa.isLegalAfterStack()) {
return AiPlayDecision.AnotherTime;
}
if (!sa.checkRestrictions(spellHost, player)) { if (!sa.checkRestrictions(spellHost, player)) {
return AiPlayDecision.AnotherTime; return AiPlayDecision.AnotherTime;
} }
@@ -946,7 +946,7 @@ public class AiController {
} }
} }
if (sa instanceof Spell) { if (sa instanceof Spell) {
if (card.isPermanent()) { if (sa.getApi() == ApiType.PermanentCreature || sa.getApi() == ApiType.PermanentNoncreature) {
return canPlayFromEffectAI((Spell) sa, false, true); return canPlayFromEffectAI((Spell) sa, false, true);
} }
if (!player.cantLoseForZeroOrLessLife() && player.canLoseLife() && if (!player.cantLoseForZeroOrLessLife() && player.canLoseLife() &&

View File

@@ -651,7 +651,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
// TODO sort negatives to remove from best Cards first? // TODO sort negatives to remove from best Cards first?
for (final Card crd : negatives) { for (final Card crd : negatives) {
for (Map.Entry<CounterType, Integer> e : table.filterToRemove(crd).entrySet()) { for (Map.Entry<CounterType, Integer> e : table.filterToRemove(crd).entrySet()) {
if (ComputerUtil.isNegativeCounter(e.getKey(), crd)) { if (ComputerUtil.isNegativeCounter(e.getKey(), crd) && crd.canRemoveCounters(e.getKey())) {
int over = Math.min(e.getValue(), c - toRemove); int over = Math.min(e.getValue(), c - toRemove);
if (over > 0) { if (over > 0) {
toRemove += over; toRemove += over;
@@ -762,7 +762,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
} }
} }
// if table is empty, than no counter was removed // if table is empty, then no counter was removed
return table.isEmpty() ? null : PaymentDecision.counters(table); return table.isEmpty() ? null : PaymentDecision.counters(table);
} }

View File

@@ -836,10 +836,9 @@ public class ComputerUtil {
} }
public static CardCollection chooseUntapType(final Player ai, final String type, final Card activate, final boolean untap, final int amount, SpellAbility sa) { public static CardCollection chooseUntapType(final Player ai, final String type, final Card activate, final boolean untap, final int amount, SpellAbility sa) {
CardCollection typeList = CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, sa);
CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, sa);
typeList = CardLists.filter(typeList, Presets.TAPPED); typeList = CardLists.filter(typeList, Presets.TAPPED, c -> c.getCounters(CounterEnumType.STUN) == 0 || c.canRemoveCounters(CounterType.get(CounterEnumType.STUN)));
if (untap) { if (untap) {
typeList.remove(activate); typeList.remove(activate);
@@ -851,12 +850,7 @@ public class ComputerUtil {
CardLists.sortByPowerDesc(typeList); CardLists.sortByPowerDesc(typeList);
final CardCollection untapList = new CardCollection(); return typeList.subList(0, amount);
for (int i = 0; i < amount; i++) {
untapList.add(typeList.get(i));
}
return untapList;
} }
public static CardCollection chooseReturnType(final Player ai, final String type, final Card activate, final Card target, final int amount, SpellAbility sa) { public static CardCollection chooseReturnType(final Player ai, final String type, final Card activate, final Card target, final int amount, SpellAbility sa) {

View File

@@ -222,6 +222,8 @@ public class CountersRemoveAi extends SpellAbilityAi {
return true; return true;
} }
// TODO stun counters with canRemoveCounters check
// remove P1P1 counters from opposing creatures // remove P1P1 counters from opposing creatures
CardCollection oppP1P1List = CardLists.filter(list, CardCollection oppP1P1List = CardLists.filter(list,
Predicates.and(CardPredicates.Presets.CREATURES, CardPredicates.isControlledByAnyOf(ai.getOpponents())), Predicates.and(CardPredicates.Presets.CREATURES, CardPredicates.isControlledByAnyOf(ai.getOpponents())),

View File

@@ -155,7 +155,7 @@ public class SetStateAi extends SpellAbilityAi {
} }
// non-permanent facedown can't be turned face up // non-permanent facedown can't be turned face up
if (!card.getRules().getType().isPermanent()) { if (!card.getRules().getType().isPermanent() || !card.canBeTurnedFaceUp()) {
return false; return false;
} }
} else { } else {

View File

@@ -6,7 +6,7 @@
<parent> <parent>
<artifactId>forge</artifactId> <artifactId>forge</artifactId>
<groupId>forge</groupId> <groupId>forge</groupId>
<version>1.6.65-SNAPSHOT</version> <version>1.6.66-SNAPSHOT</version>
</parent> </parent>
<artifactId>forge-core</artifactId> <artifactId>forge-core</artifactId>

View File

@@ -224,7 +224,7 @@ public class DeckHints {
return true; return true;
} }
for (String tok : card.getTokens()) { for (String tok : card.getTokens()) {
if (tdb != null && tdb.containsRule(tok) && predicate.apply(tdb.getToken(tok).getRules())) { if (tdb != null && tdb.containsRule(tok) && rulesWithTokens(predicate).apply(tdb.getToken(tok).getRules())) {
return true; return true;
} }
} }

View File

@@ -6,7 +6,7 @@
<parent> <parent>
<artifactId>forge</artifactId> <artifactId>forge</artifactId>
<groupId>forge</groupId> <groupId>forge</groupId>
<version>1.6.65-SNAPSHOT</version> <version>1.6.66-SNAPSHOT</version>
</parent> </parent>
<artifactId>forge-game</artifactId> <artifactId>forge-game</artifactId>

View File

@@ -309,8 +309,10 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
abstract public void setCounters(final Map<CounterType, Integer> allCounters); abstract public void setCounters(final Map<CounterType, Integer> allCounters);
abstract public boolean canRemoveCounters(final CounterType type);
abstract public boolean canReceiveCounters(final CounterType type); abstract public boolean canReceiveCounters(final CounterType type);
abstract public void subtractCounter(final CounterType counterName, final int n, final Player remover); abstract public int subtractCounter(final CounterType counterName, final int n, final Player remover);
abstract public void clearCounters(); abstract public void clearCounters();
public boolean canReceiveCounters(final CounterEnumType type) { public boolean canReceiveCounters(final CounterEnumType type) {
@@ -331,8 +333,8 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
addCounter(CounterType.get(counterType), n, source, table); addCounter(CounterType.get(counterType), n, source, table);
} }
public void subtractCounter(final CounterEnumType counterName, final int n, final Player remover) { public int subtractCounter(final CounterEnumType counterName, final int n, final Player remover) {
subtractCounter(CounterType.get(counterName), n, remover); return subtractCounter(CounterType.get(counterName), n, remover);
} }
abstract public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params); abstract public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params);

View File

@@ -285,7 +285,16 @@ public final class AbilityFactory {
final String key = "Choices"; final String key = "Choices";
if (mapParams.containsKey(key)) { if (mapParams.containsKey(key)) {
List<String> names = Lists.newArrayList(mapParams.get(key).split(",")); List<String> names = Lists.newArrayList(mapParams.get(key).split(","));
spellAbility.setAdditionalAbilityList(key, Lists.transform(names, input -> getSubAbility(state, input, sVarHolder))); spellAbility.setAdditionalAbilityList(key, Lists.transform(names, input -> {
AbilitySub sub = getSubAbility(state, input, sVarHolder);
if (api == ApiType.GenericChoice) {
// support scripters adding restrictions to filter illegal choices
sub.setRestrictions(new SpellAbilityRestriction());
makeRestrictions(sub);
}
return sub;
}
));
} }
} }

View File

@@ -2526,6 +2526,23 @@ public class AbilityUtils {
return doXMath(unlocked, expr, c, ctb); return doXMath(unlocked, expr, c, ctb);
} }
// Count$DistinctUnlockedDoors <Valid>
// Counts the distinct names of unlocked doors. Used for the "Promising Stairs"
if (sq[0].startsWith("DistinctUnlockedDoors")) {
final String[] workingCopy = l[0].split(" ", 2);
final String validFilter = workingCopy[1];
Set<String> viewedNames = new HashSet<>();
for (Card doorCard : CardLists.getValidCards(player.getCardsIn(ZoneType.Battlefield), validFilter, player, c, ctb)) {
for(CardStateName stateName : doorCard.getUnlockedRooms()) {
viewedNames.add(doorCard.getState(stateName).getName());
}
}
int distinctUnlocked = viewedNames.size();
return doXMath(distinctUnlocked, expr, c, ctb);
}
// Manapool // Manapool
if (sq[0].startsWith("ManaPool")) { if (sq[0].startsWith("ManaPool")) {
final String color = l[0].split(":")[1]; final String color = l[0].split(":")[1];

View File

@@ -4,7 +4,6 @@ import com.google.common.base.Predicates;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import forge.card.CardStateName; import forge.card.CardStateName;
import forge.card.CardType; import forge.card.CardType;
import forge.game.*; import forge.game.*;
@@ -27,7 +26,9 @@ import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import java.util.*; import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class ChangeZoneEffect extends SpellAbilityEffect { public class ChangeZoneEffect extends SpellAbilityEffect {
@@ -1085,8 +1086,10 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
String selectPrompt = sa.hasParam("SelectPrompt") ? sa.getParam("SelectPrompt") : MessageUtil.formatMessage(Localizer.getInstance().getMessage("lblSelectCardFromPlayerZone", "{player's}", Lang.joinHomogenous(origin, ZoneType::getTranslatedName).toLowerCase()), decider, player); String selectPrompt = sa.hasParam("SelectPrompt") ? sa.getParam("SelectPrompt") : MessageUtil.formatMessage(Localizer.getInstance().getMessage("lblSelectCardFromPlayerZone", "{player's}", Lang.joinHomogenous(origin, ZoneType::getTranslatedName).toLowerCase()), decider, player);
final String totalcmc = sa.getParam("WithTotalCMC"); final String totalcmc = sa.getParam("WithTotalCMC");
final String totalpower = sa.getParam("WithTotalPower"); final String totalpower = sa.getParam("WithTotalPower");
final String totalCardTypes = sa.getParam("WithTotalCardTypes");
int totcmc = AbilityUtils.calculateAmount(source, totalcmc, sa); int totcmc = AbilityUtils.calculateAmount(source, totalcmc, sa);
int totpower = AbilityUtils.calculateAmount(source, totalpower, sa); int totpower = AbilityUtils.calculateAmount(source, totalpower, sa);
int totCardTypes = AbilityUtils.calculateAmount(source, totalCardTypes, sa);
CardCollection chosenCards = new CardCollection(); CardCollection chosenCards = new CardCollection();
if (changeType.startsWith("EACH")) { if (changeType.startsWith("EACH")) {
@@ -1160,6 +1163,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
} }
} }
// If we're choosing multiple cards, only need to show the reveal dialog the first time through. // If we're choosing multiple cards, only need to show the reveal dialog the first time through.
boolean shouldReveal = (i == 0); boolean shouldReveal = (i == 0);
Card c = null; Card c = null;
@@ -1170,6 +1174,10 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
c = Aggregates.random(fetchList); c = Aggregates.random(fetchList);
} else if (defined && !chooseFromDef) { } else if (defined && !chooseFromDef) {
c = Iterables.getFirst(fetchList, null); c = Iterables.getFirst(fetchList, null);
} else if (totalCardTypes != null) {
String title = selectPrompt;
title += "\nCard types left: " + Math.max(totCardTypes, 0);
c = decider.getController().chooseSingleCardForZoneChange(destination, origin, sa, fetchList, shouldReveal ? delayedReveal : null, title, !mandatory, decider);
} else { } else {
String title = selectPrompt; String title = selectPrompt;
if (changeNum > 1) { //indicate progress if multiple cards being chosen if (changeNum > 1) { //indicate progress if multiple cards being chosen
@@ -1202,6 +1210,13 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (totalpower != null) { if (totalpower != null) {
totpower -= c.getCurrentPower(); totpower -= c.getCurrentPower();
} }
if (totalCardTypes != null) {
totCardTypes -= Iterables.size(c.getType().getCoreTypes());
}
}
if (totalCardTypes != null && totCardTypes > 0) {
chosenCards.clear();
} }
} }
@@ -1537,7 +1552,8 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
&& !sa.hasParam("AtRandom") && !sa.hasParam("AtRandom")
&& (!sa.hasParam("Defined") || sa.hasParam("ChooseFromDefined")) && (!sa.hasParam("Defined") || sa.hasParam("ChooseFromDefined"))
&& !sa.hasParam("WithTotalCMC") && !sa.hasParam("WithTotalCMC")
&& !sa.hasParam("WithTotalPower"); && !sa.hasParam("WithTotalPower")
&& !sa.hasParam("WithTotalCardTypes");
} }
/** /**

View File

@@ -101,8 +101,7 @@ public class CountersMoveEffect extends SpellAbilityEffect {
// uses for multi sources -> one defined/target // uses for multi sources -> one defined/target
// this needs given counter type // this needs given counter type
if (sa.hasParam("ValidSource")) { if (sa.hasParam("ValidSource")) {
CardCollectionView srcCards = game.getCardsIn(ZoneType.Battlefield); CardCollectionView srcCards = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), sa.getParam("ValidSource"), activator, host, sa);
srcCards = CardLists.getValidCards(srcCards, sa.getParam("ValidSource"), activator, host, sa);
List<Card> tgtCards = getDefinedCardsOrTargeted(sa); List<Card> tgtCards = getDefinedCardsOrTargeted(sa);
if (tgtCards.isEmpty()) { if (tgtCards.isEmpty()) {
@@ -147,11 +146,6 @@ public class CountersMoveEffect extends SpellAbilityEffect {
Map<CounterType, Integer> countersToAdd = Maps.newHashMap(); Map<CounterType, Integer> countersToAdd = Maps.newHashMap();
for (Card src : srcCards) { for (Card src : srcCards) {
// rule 121.5: If the first and second objects are the same object, nothing happens
if (src.equals(dest)) {
continue;
}
if ("All".equals(counterName)) { if ("All".equals(counterName)) {
final Map<CounterType, Integer> tgtCounters = Maps.newHashMap(src.getCounters()); final Map<CounterType, Integer> tgtCounters = Maps.newHashMap(src.getCounters());
for (Map.Entry<CounterType, Integer> e : tgtCounters.entrySet()) { for (Map.Entry<CounterType, Integer> e : tgtCounters.entrySet()) {
@@ -183,8 +177,7 @@ public class CountersMoveEffect extends SpellAbilityEffect {
params.put("CounterType", cType); params.put("CounterType", cType);
params.put("Source", source); params.put("Source", source);
CardCollectionView tgtCards = game.getCardsIn(ZoneType.Battlefield); CardCollectionView tgtCards = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), sa.getParam("ValidDefined"), activator, host, sa);
tgtCards = CardLists.getValidCards(tgtCards, sa.getParam("ValidDefined"), activator, host, sa);
if (counterNum.equals("Any")) { if (counterNum.equals("Any")) {
tgtCards = activator.getController().chooseCardsForEffect( tgtCards = activator.getController().chooseCardsForEffect(
@@ -203,6 +196,9 @@ public class CountersMoveEffect extends SpellAbilityEffect {
if (!dest.canReceiveCounters(cType)) { if (!dest.canReceiveCounters(cType)) {
continue; continue;
} }
if (!source.canRemoveCounters(cType)) {
continue;
}
Card cur = game.getCardState(dest, null); Card cur = game.getCardState(dest, null);
if (cur == null || !cur.equalsWithGameTimestamp(dest)) { if (cur == null || !cur.equalsWithGameTimestamp(dest)) {
@@ -287,7 +283,7 @@ public class CountersMoveEffect extends SpellAbilityEffect {
final List<CounterType> typeChoices = Lists.newArrayList(); final List<CounterType> typeChoices = Lists.newArrayList();
// get types of counters // get types of counters
for (CounterType ct : tgtCounters.keySet()) { for (CounterType ct : tgtCounters.keySet()) {
if (dest.canReceiveCounters(ct)) { if (dest.canReceiveCounters(ct) && source.canRemoveCounters(cType)) {
typeChoices.add(ct); typeChoices.add(ct);
} }
} }
@@ -337,6 +333,9 @@ public class CountersMoveEffect extends SpellAbilityEffect {
if (!dest.canReceiveCounters(cType)) { if (!dest.canReceiveCounters(cType)) {
return; return;
} }
if (!src.canRemoveCounters(cType)) {
return;
}
int cmax = src.getCounters(cType); int cmax = src.getCounters(cType);
if (cmax <= 0) { if (cmax <= 0) {

View File

@@ -127,7 +127,18 @@ public class CountersPutOrRemoveEffect extends SpellAbilityEffect {
putCounter = !Expressions.compare(value, operator, operandValue); putCounter = !Expressions.compare(value, operator, operandValue);
} else { } else {
putCounter = pc.chooseBinary(sa, prompt, BinaryChoiceType.AddOrRemove, params); boolean canReceive = tgtCard.canReceiveCounters(ctype);
boolean canRemove = tgtCard.canRemoveCounters(ctype);
if (!canReceive && !canRemove) {
return;
}
if (canReceive && !canRemove) {
putCounter = true;
} else if (!canReceive && canRemove) {
putCounter = false;
} else {
putCounter = pc.chooseBinary(sa, prompt, BinaryChoiceType.AddOrRemove, params);
}
} }
if (putCounter) { if (putCounter) {

View File

@@ -63,8 +63,7 @@ public class CountersRemoveAllEffect extends SpellAbilityEffect {
for (final Card tgtCard : cards) { for (final Card tgtCard : cards) {
if (sa.hasParam("AllCounterTypes")) { if (sa.hasParam("AllCounterTypes")) {
for (Map.Entry<CounterType, Integer> e : Lists.newArrayList(tgtCard.getCounters().entrySet())) { for (Map.Entry<CounterType, Integer> e : Lists.newArrayList(tgtCard.getCounters().entrySet())) {
numberRemoved += e.getValue(); numberRemoved += tgtCard.subtractCounter(e.getKey(), e.getValue(), sa.getActivatingPlayer());
tgtCard.subtractCounter(e.getKey(), e.getValue(), sa.getActivatingPlayer());
} }
//tgtCard.getCounters().clear(); //tgtCard.getCounters().clear();
continue; continue;
@@ -74,7 +73,7 @@ public class CountersRemoveAllEffect extends SpellAbilityEffect {
} }
if (counterAmount > 0) { if (counterAmount > 0) {
tgtCard.subtractCounter(CounterType.getType(type), counterAmount, sa.getActivatingPlayer()); numberRemoved += tgtCard.subtractCounter(CounterType.getType(type), counterAmount, sa.getActivatingPlayer());
game.updateLastStateForCard(tgtCard); game.updateLastStateForCard(tgtCard);
} }
} }

View File

@@ -110,8 +110,7 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
// Removing energy // Removing energy
if (type.equals("All")) { if (type.equals("All")) {
for (Map.Entry<CounterType, Integer> e : Lists.newArrayList(tgtPlayer.getCounters().entrySet())) { for (Map.Entry<CounterType, Integer> e : Lists.newArrayList(tgtPlayer.getCounters().entrySet())) {
tgtPlayer.subtractCounter(e.getKey(), e.getValue(), activator); totalRemoved += tgtPlayer.subtractCounter(e.getKey(), e.getValue(), activator);
totalRemoved += e.getValue();
} }
} else { } else {
if (num.equals("All")) { if (num.equals("All")) {
@@ -120,8 +119,7 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
if (type.equals("Any")) { if (type.equals("Any")) {
totalRemoved += removeAnyType(tgtPlayer, cntToRemove, sa); totalRemoved += removeAnyType(tgtPlayer, cntToRemove, sa);
} else { } else {
tgtPlayer.subtractCounter(counterType, cntToRemove, activator); totalRemoved += tgtPlayer.subtractCounter(counterType, cntToRemove, activator);
totalRemoved += cntToRemove;
} }
} }
} }
@@ -165,11 +163,11 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
if (gameCard == null || !tgtCard.equalsWithGameTimestamp(gameCard)) { if (gameCard == null || !tgtCard.equalsWithGameTimestamp(gameCard)) {
continue; continue;
} }
final Zone zone = game.getZoneOf(gameCard); final Zone zone = game.getZoneOf(gameCard);
if (type.equals("All")) { if (type.equals("All")) {
for (Map.Entry<CounterType, Integer> e : Lists.newArrayList(gameCard.getCounters().entrySet())) { for (Map.Entry<CounterType, Integer> e : Lists.newArrayList(gameCard.getCounters().entrySet())) {
gameCard.subtractCounter(e.getKey(), e.getValue(), activator); totalRemoved += gameCard.subtractCounter(e.getKey(), e.getValue(), activator);
totalRemoved += e.getValue();
} }
game.updateLastStateForCard(gameCard); game.updateLastStateForCard(gameCard);
continue; continue;
@@ -180,6 +178,9 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
if (type.equals("Any")) { if (type.equals("Any")) {
totalRemoved += removeAnyType(gameCard, cntToRemove, sa); totalRemoved += removeAnyType(gameCard, cntToRemove, sa);
} else { } else {
if (!tgtCard.canRemoveCounters(counterType)) {
continue;
}
cntToRemove = Math.min(cntToRemove, gameCard.getCounters(counterType)); cntToRemove = Math.min(cntToRemove, gameCard.getCounters(counterType));
if (zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Exile)) { if (zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Exile)) {
@@ -221,14 +222,18 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
final Player activator = sa.getActivatingPlayer(); final Player activator = sa.getActivatingPlayer();
final PlayerController pc = activator.getController(); final PlayerController pc = activator.getController();
final Map<CounterType, Integer> tgtCounters = Maps.newHashMap(entity.getCounters()); final Map<CounterType, Integer> tgtCounters = Maps.newHashMap(entity.getCounters());
for (CounterType ct : ImmutableList.copyOf(tgtCounters.keySet())) {
if (!entity.canRemoveCounters(ct)) {
tgtCounters.remove(ct);
}
}
while (cntToRemove > 0 && !tgtCounters.isEmpty()) { while (cntToRemove > 0 && !tgtCounters.isEmpty()) {
Map<String, Object> params = Maps.newHashMap(); Map<String, Object> params = Maps.newHashMap();
params.put("Target", entity); params.put("Target", entity);
String prompt = Localizer.getInstance().getMessage("lblSelectCountersTypeToRemove"); String prompt = Localizer.getInstance().getMessage("lblSelectCountersTypeToRemove");
CounterType chosenType = pc.chooseCounterType( CounterType chosenType = pc.chooseCounterType(ImmutableList.copyOf(tgtCounters.keySet()), sa, prompt, params);
ImmutableList.copyOf(tgtCounters.keySet()), sa, prompt, params);
int max = Math.min(cntToRemove, tgtCounters.get(chosenType)); int max = Math.min(cntToRemove, tgtCounters.get(chosenType));
// remove selection so player can't cheat additional trigger by choosing the same type multiple times // remove selection so player can't cheat additional trigger by choosing the same type multiple times

View File

@@ -21,15 +21,6 @@ public class VillainousChoiceEffect extends SpellAbilityEffect {
for (Player p : getDefinedPlayersOrTargeted(sa)) { for (Player p : getDefinedPlayersOrTargeted(sa)) {
int choiceAmount = p.getAdditionalVillainousChoices() + 1; int choiceAmount = p.getAdditionalVillainousChoices() + 1;
List<SpellAbility> saToRemove = Lists.newArrayList();
for (SpellAbility saChoice : abilities) {
if (saChoice.getRestrictions() != null && !saChoice.getRestrictions().checkOtherRestrictions(sa.getHostCard(), saChoice, sa.getActivatingPlayer())) {
saToRemove.add(saChoice);
}
}
abilities.removeAll(saToRemove);
// For the AI chooseSAForEffect really should take the least good ability. Currently it just takes the first // For the AI chooseSAForEffect really should take the least good ability. Currently it just takes the first
List<SpellAbility> chosenSAs = Lists.newArrayList(); List<SpellAbility> chosenSAs = Lists.newArrayList();
for(int i = 0; i < choiceAmount; i++) { for(int i = 0; i < choiceAmount; i++) {

View File

@@ -805,6 +805,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
return setState(CardStateName.FaceDown, false); return setState(CardStateName.FaceDown, false);
} }
public boolean canBeTurnedFaceUp() {
Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
return !getGame().getReplacementHandler().cantHappenCheck(ReplacementType.TurnFaceUp, repParams);
}
public void forceTurnFaceUp() { public void forceTurnFaceUp() {
turnFaceUp(false, null); turnFaceUp(false, null);
} }
@@ -813,14 +818,10 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
return turnFaceUp(true, cause); return turnFaceUp(true, cause);
} }
public boolean turnFaceUp(boolean runTriggers, SpellAbility cause) { public boolean turnFaceUp(boolean runTriggers, SpellAbility cause) {
if (!isFaceDown()) { if (!isFaceDown() || !canBeTurnedFaceUp()) {
return false; return false;
} }
// Check replacement effects
Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
if (game.getReplacementHandler().cantHappenCheck(ReplacementType.TurnFaceUp, repParams)) return false;
CardCollectionView cards = hasMergedCard() ? getMergedCards() : new CardCollection(this); CardCollectionView cards = hasMergedCard() ? getMergedCards() : new CardCollection(this);
boolean retResult = false; boolean retResult = false;
long ts = game.getNextTimestamp(); long ts = game.getNextTimestamp();
@@ -855,10 +856,9 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
triggerHandler.registerActiveTrigger(this, false); triggerHandler.registerActiveTrigger(this, false);
} }
if (runTriggers) { if (runTriggers) {
// Run replacement effects Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
game.getReplacementHandler().run(ReplacementType.TurnFaceUp, repParams); game.getReplacementHandler().run(ReplacementType.TurnFaceUp, repParams);
// Run triggers
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(this); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(this);
runParams.put(AbilityKey.Cause, cause); runParams.put(AbilityKey.Cause, cause);
@@ -1600,6 +1600,21 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
return true; return true;
} }
@Override
public final boolean canRemoveCounters(final CounterType type) {
if (isPhasedOut()) {
return false;
}
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
repParams.put(AbilityKey.CounterType, type);
repParams.put(AbilityKey.Result, 0);
repParams.put(AbilityKey.IsDamage, false);
if (game.getReplacementHandler().cantHappenCheck(ReplacementType.RemoveCounter, repParams)) {
return false;
}
return true;
}
@Override @Override
public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params) { public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params) {
int addAmount = n; int addAmount = n;
@@ -1736,11 +1751,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
} }
@Override @Override
public final void subtractCounter(final CounterType counterName, final int n, final Player remover) { public final int subtractCounter(final CounterType counterName, final int n, final Player remover) {
subtractCounter(counterName, n, remover, false); return subtractCounter(counterName, n, remover, false);
} }
public final void subtractCounter(final CounterType counterName, final int n, final Player remover, final boolean isDamage) { public final int subtractCounter(final CounterType counterName, final int n, final Player remover, final boolean isDamage) {
int oldValue = getCounters(counterName); int oldValue = getCounters(counterName);
int newValue = Math.max(oldValue - n, 0); int newValue = Math.max(oldValue - n, 0);
@@ -1758,12 +1773,14 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
newValue = 0; newValue = 0;
} }
break; break;
case Replaced:
return 0;
default: default:
break; break;
} }
final int delta = oldValue - newValue; final int delta = oldValue - newValue;
if (delta == 0) { return; } if (delta == 0) { return 0; }
int powerBonusBefore = getPowerBonusFromCounters(); int powerBonusBefore = getPowerBonusFromCounters();
int toughnessBonusBefore = getToughnessBonusFromCounters(); int toughnessBonusBefore = getToughnessBonusFromCounters();
@@ -1800,6 +1817,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
runParams.put(AbilityKey.CounterAmount, delta); runParams.put(AbilityKey.CounterAmount, delta);
runParams.put(AbilityKey.NewCounterAmount, newValue); runParams.put(AbilityKey.NewCounterAmount, newValue);
getGame().getTriggerHandler().runTrigger(TriggerType.CounterRemovedOnce, runParams, false); getGame().getTriggerHandler().runTrigger(TriggerType.CounterRemovedOnce, runParams, false);
return delta;
} }
@Override @Override

View File

@@ -119,7 +119,7 @@ public class CardCopyService {
c.setSetCode(in.getSetCode()); c.setSetCode(in.getSetCode());
for (final CardStateName state : in.getStates()) { for (final CardStateName state : in.getStates()) {
copyState(in, state, c, state); copyState(in, state, c, state, false);
} }
c.setState(in.getCurrentStateName(), false); c.setState(in.getCurrentStateName(), false);

View File

@@ -1924,6 +1924,18 @@ public class CardProperty {
if (!card.isGoaded()) { if (!card.isGoaded()) {
return false; return false;
} }
} else if (property.equals("FullyUnlocked")) {
if (card.getUnlockedRooms().size() < 2) {
return false;
}
} else if (property.startsWith("canReceiveCounters")) {
if (!card.canReceiveCounters(CounterType.getType(property.split(" ")[1]))) {
return false;
}
} else if (property.equals("canBeTurnedFaceUp")) {
if (!card.canBeTurnedFaceUp()) {
return false;
}
} else if (property.equals("NoAbilities")) { } else if (property.equals("NoAbilities")) {
if (!card.hasNoAbilities()) { if (!card.hasNoAbilities()) {
return false; return false;

View File

@@ -70,10 +70,16 @@ public class CostRemoveAnyCounter extends CostPart {
int allCounters = 0; int allCounters = 0;
for (Card c : validCards) { for (Card c : validCards) {
if (this.counter != null) { if (this.counter != null) {
if (!c.canRemoveCounters(this.counter)) {
continue;
}
allCounters += c.getCounters(this.counter); allCounters += c.getCounters(this.counter);
} else { } else {
for (Integer value : c.getCounters().values()) { for (Map.Entry<CounterType, Integer> entry : c.getCounters().entrySet()) {
allCounters += value; if (!c.canRemoveCounters(entry.getKey())) {
continue;
}
allCounters += entry.getValue();
} }
} }
} }

View File

@@ -21,6 +21,8 @@ import com.google.common.collect.Maps;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCollection; import forge.game.card.CardCollection;
import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.trigger.TriggerType; import forge.game.trigger.TriggerType;
@@ -78,7 +80,8 @@ public class CostUntap extends CostPart {
@Override @Override
public final boolean canPay(final SpellAbility ability, final Player payer, final boolean effect) { public final boolean canPay(final SpellAbility ability, final Player payer, final boolean effect) {
final Card source = ability.getHostCard(); final Card source = ability.getHostCard();
return source.isTapped() && !source.isAbilitySick(); return source.isTapped() && !source.isAbilitySick() &&
(source.getCounters(CounterEnumType.STUN) == 0 || source.canRemoveCounters(CounterType.get(CounterEnumType.STUN)));
} }
@Override @Override

View File

@@ -23,6 +23,8 @@ import forge.game.card.Card;
import forge.game.card.CardCollection; import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView; import forge.game.card.CardCollectionView;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.card.CardPredicates.Presets; import forge.game.card.CardPredicates.Presets;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
@@ -90,7 +92,7 @@ public class CostUntapType extends CostPartWithList {
if (!canUntapSource) { if (!canUntapSource) {
typeList.remove(source); typeList.remove(source);
} }
typeList = CardLists.filter(typeList, Presets.TAPPED); typeList = CardLists.filter(typeList, Presets.TAPPED, c -> c.getCounters(CounterEnumType.STUN) == 0 || c.canRemoveCounters(CounterType.get(CounterEnumType.STUN)));
final int amount = this.getAbilityAmount(ability); final int amount = this.getAbilityAmount(ability);
return (typeList.size() != 0) && (typeList.size() >= amount); return (typeList.size() != 0) && (typeList.size() >= amount);

View File

@@ -1049,6 +1049,7 @@ public class PhaseHandler implements java.io.Serializable {
for (SpellAbility sa : chosenSa) { for (SpellAbility sa : chosenSa) {
Card saHost = sa.getHostCard(); Card saHost = sa.getHostCard();
final Zone originZone = saHost.getZone(); final Zone originZone = saHost.getZone();
final CardZoneTable triggerList = new CardZoneTable(game.getLastStateBattlefield(), game.getLastStateGraveyard());
if (pPlayerPriority.getController().playChosenSpellAbility(sa)) { if (pPlayerPriority.getController().playChosenSpellAbility(sa)) {
// 117.3c If a player has priority when they cast a spell, activate an ability, [play a land] // 117.3c If a player has priority when they cast a spell, activate an ability, [play a land]
@@ -1064,7 +1065,6 @@ public class PhaseHandler implements java.io.Serializable {
// Need to check if Zone did change // Need to check if Zone did change
if (currentZone != null && originZone != null && !currentZone.equals(originZone) && (sa.isSpell() || sa.isLandAbility())) { if (currentZone != null && originZone != null && !currentZone.equals(originZone) && (sa.isSpell() || sa.isLandAbility())) {
// currently there can be only one Spell put on the Stack at once, or Land Abilities be played // currently there can be only one Spell put on the Stack at once, or Land Abilities be played
final CardZoneTable triggerList = new CardZoneTable(game.getLastStateBattlefield(), game.getLastStateGraveyard());
triggerList.put(originZone.getZoneType(), currentZone.getZoneType(), saHost); triggerList.put(originZone.getZoneType(), currentZone.getZoneType(), saHost);
triggerList.triggerChangesZoneAll(game, sa); triggerList.triggerChangesZoneAll(game, sa);
} }

View File

@@ -855,6 +855,14 @@ public class Player extends GameEntity implements Comparable<Player> {
return true; return true;
} }
public final boolean canRemoveCounters(final CounterType type) {
if (!isInGame()) {
return false;
}
// no RE affecting players currently, skip check for performance
return true;
}
@Override @Override
public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params) { public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params) {
int addAmount = n; int addAmount = n;
@@ -896,12 +904,12 @@ public class Player extends GameEntity implements Comparable<Player> {
} }
@Override @Override
public void subtractCounter(CounterType counterName, int num, final Player remover) { public int subtractCounter(CounterType counterName, int num, final Player remover) {
int oldValue = getCounters(counterName); int oldValue = getCounters(counterName);
int newValue = Math.max(oldValue - num, 0); int newValue = Math.max(oldValue - num, 0);
final int delta = oldValue - newValue; final int delta = oldValue - newValue;
if (delta == 0) { return; } if (delta == 0) { return 0; }
setCounters(counterName, newValue, null, true); setCounters(counterName, newValue, null, true);
@@ -917,6 +925,7 @@ public class Player extends GameEntity implements Comparable<Player> {
getGame().getTriggerHandler().runTrigger(TriggerType.CounterRemoved, runParams, false); getGame().getTriggerHandler().runTrigger(TriggerType.CounterRemoved, runParams, false);
} }
*/ */
return delta;
} }
public final void clearCounters() { public final void clearCounters() {

View File

@@ -18,12 +18,8 @@
package forge.game.spellability; package forge.game.spellability;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.game.ability.AbilityKey;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.cost.Cost; import forge.game.cost.Cost;
import forge.game.replacement.ReplacementType;
import java.util.Map;
/** /**
* <p> * <p>
@@ -58,9 +54,8 @@ public abstract class AbilityStatic extends Ability implements Cloneable {
// Check if ability can't be attempted because of replacement effect // Check if ability can't be attempted because of replacement effect
// Initial usage is Karlov Watchdog preventing disguise/morph/cloak/manifest turning face up // Initial usage is Karlov Watchdog preventing disguise/morph/cloak/manifest turning face up
if (this.isTurnFaceUp()) { if (this.isTurnFaceUp() && !c.canBeTurnedFaceUp()) {
Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(c); return false;
if (c.getGame().getReplacementHandler().cantHappenCheck(ReplacementType.TurnFaceUp, repParams)) return false;
} }
return this.getRestrictions().canPlay(c, this); return this.getRestrictions().canPlay(c, this);

View File

@@ -4,10 +4,12 @@
<properties> <properties>
<timestamp>${maven.build.timestamp}</timestamp> <timestamp>${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss</maven.build.timestamp.format> <maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss</maven.build.timestamp.format>
<android.manifest.versionCodeUpdateFromVersion>true</android.manifest.versionCodeUpdateFromVersion>
<android.manifestMerger.versionDigits>2,2,2,4</android.manifestMerger.versionDigits>
<packaging.type>jar</packaging.type> <packaging.type>jar</packaging.type>
<build.min.memory>-Xms1024m</build.min.memory> <build.min.memory>-Xms1024m</build.min.memory>
<build.max.memory>-Xmx1536m</build.max.memory> <build.max.memory>-Xmx1536m</build.max.memory>
<alpha-version>1.6.65-SNAPSHOT</alpha-version> <alpha-version>1.6.66-SNAPSHOT</alpha-version>
<sign.keystore>keystore</sign.keystore> <sign.keystore>keystore</sign.keystore>
<sign.alias>alias</sign.alias> <sign.alias>alias</sign.alias>
<sign.storepass>storepass</sign.storepass> <sign.storepass>storepass</sign.storepass>
@@ -20,7 +22,7 @@
<parent> <parent>
<artifactId>forge</artifactId> <artifactId>forge</artifactId>
<groupId>forge</groupId> <groupId>forge</groupId>
<version>1.6.65-SNAPSHOT</version> <version>1.6.66-SNAPSHOT</version>
</parent> </parent>
<artifactId>forge-gui-android</artifactId> <artifactId>forge-gui-android</artifactId>
@@ -228,7 +230,7 @@
<version>6.2.2</version> <version>6.2.2</version>
</dependency> </dependency>
</dependencies> </dependencies>
<version>4.6.1</version> <version>4.6.2</version>
<extensions>true</extensions> <extensions>true</extensions>
<configuration> <configuration>
<sign> <sign>
@@ -239,7 +241,6 @@
<buildTools>30.0.3</buildTools> <buildTools>30.0.3</buildTools>
</sdk> </sdk>
<dexForceJumbo>true</dexForceJumbo> <dexForceJumbo>true</dexForceJumbo>
<androidManifestFile>${project.basedir}/AndroidManifest.xml</androidManifestFile>
<assetsDirectory>${project.basedir}/assets</assetsDirectory> <assetsDirectory>${project.basedir}/assets</assetsDirectory>
<resourceDirectory>${project.basedir}/res</resourceDirectory> <resourceDirectory>${project.basedir}/res</resourceDirectory>
<nativeLibrariesDirectory>${project.basedir}/libs</nativeLibrariesDirectory> <nativeLibrariesDirectory>${project.basedir}/libs</nativeLibrariesDirectory>
@@ -266,6 +267,14 @@
<dexArguments>--min-sdk-version=26</dexArguments> <dexArguments>--min-sdk-version=26</dexArguments>
</dex> </dex>
</configuration> </configuration>
<executions>
<execution>
<id>update-manifest</id>
<goals>
<goal>manifest-merger</goal>
</goals>
</execution>
</executions>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
@@ -292,7 +301,7 @@
<version>6.2.2</version> <version>6.2.2</version>
</dependency> </dependency>
</dependencies> </dependencies>
<version>4.6.1</version> <version>4.6.2</version>
<extensions>true</extensions> <extensions>true</extensions>
<configuration> <configuration>
<sign> <sign>
@@ -306,7 +315,6 @@
<verbose>false</verbose> <verbose>false</verbose>
</zipalign> </zipalign>
<dexForceJumbo>true</dexForceJumbo> <dexForceJumbo>true</dexForceJumbo>
<androidManifestFile>${project.basedir}/AndroidManifest.xml</androidManifestFile>
<assetsDirectory>${project.basedir}/assets</assetsDirectory> <assetsDirectory>${project.basedir}/assets</assetsDirectory>
<resourceDirectory>${project.basedir}/res</resourceDirectory> <resourceDirectory>${project.basedir}/res</resourceDirectory>
<nativeLibrariesDirectory>${project.basedir}/libs</nativeLibrariesDirectory> <nativeLibrariesDirectory>${project.basedir}/libs</nativeLibrariesDirectory>
@@ -333,6 +341,14 @@
<dexArguments>--min-sdk-version=26</dexArguments> <dexArguments>--min-sdk-version=26</dexArguments>
</dex> </dex>
</configuration> </configuration>
<executions>
<execution>
<id>update-manifest</id>
<goals>
<goal>manifest-merger</goal>
</goals>
</execution>
</executions>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
@@ -393,7 +409,7 @@
<version>6.2.2</version> <version>6.2.2</version>
</dependency> </dependency>
</dependencies> </dependencies>
<version>4.6.1</version> <version>4.6.2</version>
<inherited>true</inherited> <inherited>true</inherited>
<configuration> <configuration>
<sign> <sign>
@@ -414,6 +430,12 @@
<goal>zipalign</goal> <goal>zipalign</goal>
</goals> </goals>
</execution> </execution>
<execution>
<id>update-manifest</id>
<goals>
<goal>manifest-merger</goal>
</goals>
</execution>
</executions> </executions>
</plugin> </plugin>
<plugin> <plugin>

View File

@@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="forge.app" package="forge.app">
android:versionCode="106650000"
android:versionName="1.6.65" > <!-- versionName should be updated and it's used for Sentry releases tag -->
<uses-sdk <uses-sdk
android:minSdkVersion="26" android:minSdkVersion="26"

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>forge</artifactId> <artifactId>forge</artifactId>
<groupId>forge</groupId> <groupId>forge</groupId>
<version>1.6.65-SNAPSHOT</version> <version>1.6.66-SNAPSHOT</version>
</parent> </parent>
<artifactId>forge-gui-desktop</artifactId> <artifactId>forge-gui-desktop</artifactId>
@@ -118,7 +118,7 @@
</goals> </goals>
<configuration> <configuration>
<!-- TODO: insert placeholder for latest version tag --> <!-- TODO: insert placeholder for latest version tag -->
<fromRef>forge-1.6.64</fromRef> <fromRef>forge-1.6.65</fromRef>
<file>../forge-gui/release-files/CHANGES.txt</file> <file>../forge-gui/release-files/CHANGES.txt</file>
<templateContent> <templateContent>
<![CDATA[ <![CDATA[

View File

@@ -12,7 +12,7 @@
<parent> <parent>
<artifactId>forge</artifactId> <artifactId>forge</artifactId>
<groupId>forge</groupId> <groupId>forge</groupId>
<version>1.6.65-SNAPSHOT</version> <version>1.6.66-SNAPSHOT</version>
</parent> </parent>
<artifactId>forge-gui-ios</artifactId> <artifactId>forge-gui-ios</artifactId>

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>forge</artifactId> <artifactId>forge</artifactId>
<groupId>forge</groupId> <groupId>forge</groupId>
<version>1.6.65-SNAPSHOT</version> <version>1.6.66-SNAPSHOT</version>
</parent> </parent>
<artifactId>forge-gui-mobile-dev</artifactId> <artifactId>forge-gui-mobile-dev</artifactId>

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>forge</artifactId> <artifactId>forge</artifactId>
<groupId>forge</groupId> <groupId>forge</groupId>
<version>1.6.65-SNAPSHOT</version> <version>1.6.66-SNAPSHOT</version>
</parent> </parent>
<artifactId>forge-gui-mobile</artifactId> <artifactId>forge-gui-mobile</artifactId>

View File

@@ -1,11 +1,7 @@
package forge; package forge;
import com.badlogic.gdx.Application; import com.badlogic.gdx.*;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.controllers.Controller; import com.badlogic.gdx.controllers.Controller;
import com.badlogic.gdx.controllers.ControllerAdapter; import com.badlogic.gdx.controllers.ControllerAdapter;
import com.badlogic.gdx.controllers.ControllerListener; import com.badlogic.gdx.controllers.ControllerListener;
@@ -54,7 +50,7 @@ import java.nio.file.Paths;
import java.util.*; import java.util.*;
public class Forge implements ApplicationListener { public class Forge implements ApplicationListener {
public static final String CURRENT_VERSION = "1.6.65-SNAPSHOT"; public static final String CURRENT_VERSION = "1.6.66-SNAPSHOT";
private static ApplicationListener app = null; private static ApplicationListener app = null;
static Scene currentScene = null; static Scene currentScene = null;

View File

@@ -4,6 +4,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Array;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import forge.Forge; import forge.Forge;
import forge.adventure.character.EnemySprite; import forge.adventure.character.EnemySprite;
import forge.adventure.pointofintrest.PointOfInterestChanges; import forge.adventure.pointofintrest.PointOfInterestChanges;
@@ -432,8 +433,9 @@ public class AdventureEventData implements Serializable {
public void generateParticipants(int numberOfOpponents) { public void generateParticipants(int numberOfOpponents) {
participants = new AdventureEventParticipant[numberOfOpponents + 1]; participants = new AdventureEventParticipant[numberOfOpponents + 1];
List<EnemyData> data = Aggregates.random(WorldData.getAllEnemies(), numberOfOpponents); //TODO: Switch this to a stream with StreamUtil.random once the guava migration branch is merged.
data.removeIf(q -> q.nextEnemy != null); Iterable<EnemyData> validParticipants = Iterables.filter(WorldData.getAllEnemies(), q -> q.nextEnemy == null);
List<EnemyData> data = Aggregates.random(validParticipants, numberOfOpponents);
for (int i = 0; i < numberOfOpponents; i++) { for (int i = 0; i < numberOfOpponents; i++) {
participants[i] = new AdventureEventParticipant().generate(data.get(i)); participants[i] = new AdventureEventParticipant().generate(data.get(i));
} }

View File

@@ -180,7 +180,7 @@ public class InventoryScene extends UIScene {
Deck data = (deckLocation.get(selected)); Deck data = (deckLocation.get(selected));
if (data == null) return; if (data == null) return;
done(); //done();
setSelected(null); setSelected(null);
RewardScene.instance().loadRewards(data, RewardScene.Type.Loot, null, data.getTags().contains("noSell")); RewardScene.instance().loadRewards(data, RewardScene.Type.Loot, null, data.getTags().contains("noSell"));
Forge.switchScene(RewardScene.instance()); Forge.switchScene(RewardScene.instance());
@@ -206,15 +206,7 @@ public class InventoryScene extends UIScene {
Deck data = deckLocation.get(selected); Deck data = deckLocation.get(selected);
if (data == null) if (data == null)
return; return;
if (openDialog == null) { this.openBooster();
openDialog = createGenericDialog("", null, Forge.getLocalizer().getMessage("lblYes"),
Forge.getLocalizer().getMessage("lblNo"), () -> {
this.openBooster();
removeDialog();
}, this::removeDialog);
openDialog.getContentTable().add(Controls.newTextraLabel("Open Booster Pack?"));
}
showDialog(openDialog);
} }
} }
@@ -277,7 +269,7 @@ public class InventoryScene extends UIScene {
useButton.layout(); useButton.layout();
equipButton.setDisabled(true); equipButton.setDisabled(true);
itemDescription.setText("Card Pack - " + data.getName() + "\n[%98]" + (data.getComment() == null?"":data.getComment()+" - ") + data.getAllCardsInASinglePool().countAll() + " cards"); itemDescription.setText(data.getName() + "\n[%98]" + (data.getComment() == null?"":data.getComment()+" - ") + data.getAllCardsInASinglePool().countAll() + " cards");
} }

View File

@@ -26,6 +26,7 @@ import forge.item.PaperCard;
import forge.sound.SoundEffectType; import forge.sound.SoundEffectType;
import forge.sound.SoundSystem; import forge.sound.SoundSystem;
import forge.util.ItemPool; import forge.util.ItemPool;
import java.util.Comparator;
/** /**
* Displays the rewards of a fight or a treasure * Displays the rewards of a fight or a treasure
@@ -318,6 +319,14 @@ public class RewardScene extends UIScene {
} }
public void loadRewards(Array<Reward> newRewards, Type type, ShopActor shopActor) { public void loadRewards(Array<Reward> newRewards, Type type, ShopActor shopActor) {
// Sort the rewards based on the rarity of the card inside the reward/ lets give items rarity
newRewards.sort(Comparator.comparing(reward -> {
if (reward.getCard() != null && reward.getCard().getRarity() != null) {
return reward.getCard().getRarity().ordinal();
}
// Return a default value or handle the case where rarity is not present
return Integer.MAX_VALUE; // Assuming higher values mean less priority in sorting
}));
clearSelectable(); clearSelectable();
this.type = type; this.type = type;
doneClicked = false; doneClicked = false;

View File

@@ -11,6 +11,7 @@ import forge.item.SealedTemplate;
import forge.item.generation.BoosterGenerator; import forge.item.generation.BoosterGenerator;
import forge.item.generation.UnOpenedProduct; import forge.item.generation.UnOpenedProduct;
import forge.model.CardBlock; import forge.model.CardBlock;
import forge.model.FModel;
import forge.util.Aggregates; import forge.util.Aggregates;
import java.io.Serializable; import java.io.Serializable;
@@ -136,7 +137,8 @@ public class AdventureEventController implements Serializable {
List<PaperCard> cards = BoosterGenerator.getBoosterPack(StaticData.instance().getBoosters().get(setCode)); List<PaperCard> cards = BoosterGenerator.getBoosterPack(StaticData.instance().getBoosters().get(setCode));
Deck output = new Deck(); Deck output = new Deck();
output.getMain().add(cards); output.getMain().add(cards);
output.setName("Booster Pack: " + setCode); String editionName = FModel.getMagicDb().getEditions().get(setCode).getName();
output.setName(editionName + " Booster");
output.setComment(setCode); output.setComment(setCode);
return output; return output;
} }

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>forge</artifactId> <artifactId>forge</artifactId>
<groupId>forge</groupId> <groupId>forge</groupId>
<version>1.6.65-SNAPSHOT</version> <version>1.6.66-SNAPSHOT</version>
</parent> </parent>
<artifactId>forge-gui</artifactId> <artifactId>forge-gui</artifactId>

View File

@@ -27,7 +27,7 @@
<object id="66" template="../../obj/door_up.tx" x="35.2402" y="285.749"> <object id="66" template="../../obj/door_up.tx" x="35.2402" y="285.749">
<properties> <properties>
<property name="teleport" value="../common/maps/map/vampirecastle/vampirecastle_4B.tmx"/> <property name="teleport" value="../common/maps/map/vampirecastle/vampirecastle_4B.tmx"/>
<property name="teleportObjectId" value="67"/> <property name="teleportObjectId" value="66"/>
</properties> </properties>
</object> </object>
<object id="75" template="../../obj/treasure.tx" x="784.167" y="63.75"/> <object id="75" template="../../obj/treasure.tx" x="784.167" y="63.75"/>

View File

@@ -12250,7 +12250,7 @@
"difficulty": 1, "difficulty": 1,
"speed": 30, "speed": 30,
"scale": 0.5, "scale": 0.5,
"life": 35, "life": 55,
"rewards": [ "rewards": [
{ {
"type": "card", "type": "card",

View File

@@ -134,3 +134,4 @@ Murders at Karlov Manor, 3/6/MKM, MKM
Outlaws of Thunder Junction, 3/6/OTJ, OTJ Outlaws of Thunder Junction, 3/6/OTJ, OTJ
Modern Horizons 3, 3/6/MH3, MH3 Modern Horizons 3, 3/6/MH3, MH3
Bloomburrow, 3/6/BLB, BLB Bloomburrow, 3/6/BLB, BLB
Duskmourn: House of Horror, 3/6/DSK, DSK

View File

@@ -9,6 +9,6 @@ SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Remembered$Amount SVar:X:Remembered$Amount
SVar:MaxTgts:Count$Valid Permanent.Other+nonLand+YouCtrl SVar:MaxTgts:Count$Valid Permanent.Other+nonLand+YouCtrl
K:Choose a Background K:Choose a Background
DeckHas:Ability$Token & Type$Soldier
AI:RemoveDeck:Random AI:RemoveDeck:Random
DeckHas:Ability$Token & Type$Soldier
Oracle:When Abdel Adrian, Gorion's Ward enters, exile any number of other nonland permanents you control until Abdel Adrian leaves the battlefield. Create a 1/1 white Soldier creature token for each permanent exiled this way.\nChoose a Background (You can have a Background as a second commander.) Oracle:When Abdel Adrian, Gorion's Ward enters, exile any number of other nonland permanents you control until Abdel Adrian leaves the battlefield. Create a 1/1 white Soldier creature token for each permanent exiled this way.\nChoose a Background (You can have a Background as a second commander.)

View File

@@ -4,6 +4,6 @@ Types:Instant
K:Devoid K:Devoid
A:SP$ Counter | TargetType$ Spell | TgtPrompt$ Select target spell | ValidTgts$ Card | UnlessCost$ 1 | SubAbility$ DBToken | SpellDescription$ Counter target spell unless its controller pays {1}. A:SP$ Counter | TargetType$ Spell | TgtPrompt$ Select target spell | ValidTgts$ Card | UnlessCost$ 1 | SubAbility$ DBToken | SpellDescription$ Counter target spell unless its controller pays {1}.
SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_1_1_eldrazi_scion_sac | TokenOwner$ You | SpellDescription$ You create a 1/1 colorless Eldrazi Scion creature token. It has "Sacrifice this creature: Add {C}." ({C} represents colorless mana.) SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_1_1_eldrazi_scion_sac | TokenOwner$ You | SpellDescription$ You create a 1/1 colorless Eldrazi Scion creature token. It has "Sacrifice this creature: Add {C}." ({C} represents colorless mana.)
DeckHints:Type$Eldrazi
DeckHas:Ability$Mana.Colorless|Token DeckHas:Ability$Mana.Colorless|Token
DeckHints:Type$Eldrazi
Oracle:Devoid (This card has no color.)\nCounter target spell unless its controller pays {1}. You create a 1/1 colorless Eldrazi Scion creature token. It has "Sacrifice this creature: Add {C}." ({C} represents colorless mana.) Oracle:Devoid (This card has no color.)\nCounter target spell unless its controller pays {1}. You create a 1/1 colorless Eldrazi Scion creature token. It has "Sacrifice this creature: Add {C}." ({C} represents colorless mana.)

View File

@@ -5,6 +5,6 @@ PT:3/2
K:Outlast:W K:Outlast:W
S:Mode$ Continuous | Affected$ Creature.YouCtrl+counters_GE1_P1P1 | AddKeyword$ Lifelink | Description$ Each creature you control with a +1/+1 counter on it has lifelink. S:Mode$ Continuous | Affected$ Creature.YouCtrl+counters_GE1_P1P1 | AddKeyword$ Lifelink | Description$ Each creature you control with a +1/+1 counter on it has lifelink.
SVar:PlayMain1:TRUE SVar:PlayMain1:TRUE
DeckHints:Ability$Counters
DeckHas:Ability$Counters DeckHas:Ability$Counters
DeckHints:Ability$Counters
Oracle:Outlast {W} ({W}, {T}: Put a +1/+1 counter on this creature. Outlast only as a sorcery.)\nEach creature you control with a +1/+1 counter on it has lifelink. Oracle:Outlast {W} ({W}, {T}: Put a +1/+1 counter on this creature. Outlast only as a sorcery.)\nEach creature you control with a +1/+1 counter on it has lifelink.

View File

@@ -5,6 +5,6 @@ PT:2/3
K:Outlast:W K:Outlast:W
S:Mode$ Continuous | Affected$ Creature.YouCtrl+counters_GE1_P1P1 | AddKeyword$ Flying | Description$ Each creature you control wth a +1/+1 counter on it has flying. S:Mode$ Continuous | Affected$ Creature.YouCtrl+counters_GE1_P1P1 | AddKeyword$ Flying | Description$ Each creature you control wth a +1/+1 counter on it has flying.
SVar:PlayMain1:TRUE SVar:PlayMain1:TRUE
DeckHints:Ability$Counters
DeckHas:Ability$Counters DeckHas:Ability$Counters
DeckHints:Ability$Counters
Oracle:Outlast {W} ({W}, {T}: Put a +1/+1 counter on this creature. Outlast only as a sorcery.)\nEach creature you control with a +1/+1 counter on it has flying. Oracle:Outlast {W} ({W}, {T}: Put a +1/+1 counter on this creature. Outlast only as a sorcery.)\nEach creature you control with a +1/+1 counter on it has flying.

View File

@@ -3,6 +3,6 @@ ManaCost:1 G
Types:Legendary Enchantment Background Types:Legendary Enchantment Background
S:Mode$ Continuous | Affected$ Creature.IsCommander+YouOwn | AddStaticAbility$ DragonReduce | Description$ Commander creatures you own have "The first Dragon spell you cast each turn costs {2} less to cast." S:Mode$ Continuous | Affected$ Creature.IsCommander+YouOwn | AddStaticAbility$ DragonReduce | Description$ Commander creatures you own have "The first Dragon spell you cast each turn costs {2} less to cast."
SVar:DragonReduce:Mode$ ReduceCost | EffectZone$ Battlefield | ValidCard$ Card.Dragon | Activator$ You | Type$ Spell | OnlyFirstSpell$ True | Amount$ 2 | Description$ The first Dragon spell you cast each turn costs {2} less to cast. SVar:DragonReduce:Mode$ ReduceCost | EffectZone$ Battlefield | ValidCard$ Card.Dragon | Activator$ You | Type$ Spell | OnlyFirstSpell$ True | Amount$ 2 | Description$ The first Dragon spell you cast each turn costs {2} less to cast.
DeckNeeds:Type$Dragon
AI:RemoveDeck:NonCommander AI:RemoveDeck:NonCommander
DeckNeeds:Type$Dragon
Oracle:Commander creatures you own have "The first Dragon spell you cast each turn costs {2} less to cast." Oracle:Commander creatures you own have "The first Dragon spell you cast each turn costs {2} less to cast."

View File

@@ -4,6 +4,6 @@ Types:Creature Human Soldier
PT:2/1 PT:2/1
T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | IsPresent$ Planeswalker.Basri+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ At the beginning of combat on your turn, if you control a Basri planeswalker, put a +1/+1 counter on CARDNAME. T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | IsPresent$ Planeswalker.Basri+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ At the beginning of combat on your turn, if you control a Basri planeswalker, put a +1/+1 counter on CARDNAME.
SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
DeckNeeds:Type$Basri
DeckHas:Ability$Counters DeckHas:Ability$Counters
DeckNeeds:Type$Basri
Oracle:At the beginning of combat on your turn, if you control a Basri planeswalker, put a +1/+1 counter on Adherent of Hope. Oracle:At the beginning of combat on your turn, if you control a Basri planeswalker, put a +1/+1 counter on Adherent of Hope.

View File

@@ -5,6 +5,6 @@ K:Devoid
A:SP$ Tap | TargetMin$ 0 | TargetMax$ 2 | TgtPrompt$ Choose target creature | ValidTgts$ Creature | SubAbility$ TrigPump | SpellDescription$ Tap up to two target creatures. A:SP$ Tap | TargetMin$ 0 | TargetMax$ 2 | TgtPrompt$ Choose target creature | ValidTgts$ Creature | SubAbility$ TrigPump | SpellDescription$ Tap up to two target creatures.
SVar:TrigPump:DB$ Pump | Defined$ Targeted | KW$ HIDDEN This card doesn't untap during your next untap step. | Duration$ Permanent | SubAbility$ DBToken | SpellDescription$ Those creatures don't untap during their controller's next untap step. SVar:TrigPump:DB$ Pump | Defined$ Targeted | KW$ HIDDEN This card doesn't untap during your next untap step. | Duration$ Permanent | SubAbility$ DBToken | SpellDescription$ Those creatures don't untap during their controller's next untap step.
SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_1_1_eldrazi_scion_sac | TokenOwner$ You | SpellDescription$ Create a 1/1 colorless Eldrazi Scion creature token. It has "Sacrifice this creature: Add {C}." SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_1_1_eldrazi_scion_sac | TokenOwner$ You | SpellDescription$ Create a 1/1 colorless Eldrazi Scion creature token. It has "Sacrifice this creature: Add {C}."
DeckHints:Type$Eldrazi
DeckHas:Ability$Mana.Colorless|Token DeckHas:Ability$Mana.Colorless|Token
DeckHints:Type$Eldrazi
Oracle:Devoid (This card has no color.)\nTap up to two target creatures. Those creatures don't untap during their controller's next untap step. Create a 1/1 colorless Eldrazi Scion creature token. It has "Sacrifice this creature: Add {C}." Oracle:Devoid (This card has no color.)\nTap up to two target creatures. Those creatures don't untap during their controller's next untap step. Create a 1/1 colorless Eldrazi Scion creature token. It has "Sacrifice this creature: Add {C}."

View File

@@ -5,6 +5,6 @@ A:SP$ Dig | DigNum$ 5 | ChangeNum$ 1 | SubAbility$ Dig2 | ConditionCheckSVar$ X
SVar:Dig2:DB$ Dig | DigNum$ 5 | ChangeNum$ 2 | ConditionCheckSVar$ X | ConditionSVarCompare$ GTY SVar:Dig2:DB$ Dig | DigNum$ 5 | ChangeNum$ 2 | ConditionCheckSVar$ X | ConditionSVarCompare$ GTY
SVar:X:Count$Valid Creature.YouCtrl SVar:X:Count$Valid Creature.YouCtrl
SVar:Y:PlayerCountOther$HighestValid Creature.YouCtrl SVar:Y:PlayerCountOther$HighestValid Creature.YouCtrl
DeckNeeds:Color$Blue
AI:RemoveDeck:Random AI:RemoveDeck:Random
DeckNeeds:Color$Blue
Oracle:({2/U} can be paid with any two mana or with {U}. This card's mana value is 6.)\nLook at the top five cards of your library. If you control more creatures than each other player, put two of those cards into your hand. Otherwise, put one of them into your hand. Then put the rest on the bottom of your library in any order. Oracle:({2/U} can be paid with any two mana or with {U}. This card's mana value is 6.)\nLook at the top five cards of your library. If you control more creatures than each other player, put two of those cards into your hand. Otherwise, put one of them into your hand. Then put the rest on the bottom of your library in any order.

View File

@@ -5,6 +5,6 @@ PT:3/4
K:Flying K:Flying
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPut | TriggerDescription$ When CARDNAME enters, put a +1/+1 counter on another target Soldier you control. T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPut | TriggerDescription$ When CARDNAME enters, put a +1/+1 counter on another target Soldier you control.
SVar:TrigPut:DB$ PutCounter | ValidTgts$ Soldier.Other+YouCtrl | TgtPrompt$ Select another target Soldier you control | CounterType$ P1P1 SVar:TrigPut:DB$ PutCounter | ValidTgts$ Soldier.Other+YouCtrl | TgtPrompt$ Select another target Soldier you control | CounterType$ P1P1
DeckHints:Type$Soldier
DeckHas:Ability$Counters DeckHas:Ability$Counters
DeckHints:Type$Soldier
Oracle:Flying\nWhen Aeronaut Cavalry enters, put a +1/+1 counter on another target Soldier you control. Oracle:Flying\nWhen Aeronaut Cavalry enters, put a +1/+1 counter on another target Soldier you control.

View File

@@ -1,7 +1,7 @@
Name:Aether Searcher Name:Aether Searcher
ManaCost:7 ManaCost:7
PT:6/4
Types:Artifact Creature Construct Types:Artifact Creature Construct
PT:6/4
Draft:Reveal CARDNAME as you draft it. Draft:Reveal CARDNAME as you draft it.
Draft:Reveal the next card you draft and note its name. Draft:Reveal the next card you draft and note its name.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSearchHand | TriggerDescription$ When CARDNAME enters, you may search your hand and/or library for a card with a name noted as you drafted cards named Aether Searcher. You may cast it without paying its mana cost. If you searched your library this way, shuffle. T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSearchHand | TriggerDescription$ When CARDNAME enters, you may search your hand and/or library for a card with a name noted as you drafted cards named Aether Searcher. You may cast it without paying its mana cost. If you searched your library this way, shuffle.

View File

@@ -7,6 +7,6 @@ K:Trample
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self+bargained | Execute$ TrigKicker | TriggerDescription$ When CARDNAME enters, if it was bargained, it fights up to one target creature you don't control. (Each deals damage equal to its power to the other.) T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self+bargained | Execute$ TrigKicker | TriggerDescription$ When CARDNAME enters, if it was bargained, it fights up to one target creature you don't control. (Each deals damage equal to its power to the other.)
SVar:TrigKicker:DB$ Fight | Defined$ TriggeredCardLKICopy | ValidTgts$ Creature.YouDontCtrl | TgtPrompt$ Select up to one target creature an opponent controls | TargetMin$ 0 | TargetMax$ 1 SVar:TrigKicker:DB$ Fight | Defined$ TriggeredCardLKICopy | ValidTgts$ Creature.YouDontCtrl | TgtPrompt$ Select up to one target creature an opponent controls | TargetMin$ 0 | TargetMax$ 1
SVar:PlayMain1:TRUE SVar:PlayMain1:TRUE
DeckHints:Type$Artifact|Enchantment & Ability$Token
DeckHas:Ability$Sacrifice DeckHas:Ability$Sacrifice
DeckHints:Type$Artifact|Enchantment & Ability$Token
Oracle:Bargain (You may sacrifice an artifact, enchantment, or token as you cast this spell.)\nTrample\nWhen Agatha's Champion enters, if it was bargained, it fights up to one target creature you don't control. (Each deals damage equal to its power to the other.) Oracle:Bargain (You may sacrifice an artifact, enchantment, or token as you cast this spell.)\nTrample\nWhen Agatha's Champion enters, if it was bargained, it fights up to one target creature you don't control. (Each deals damage equal to its power to the other.)

View File

@@ -4,6 +4,6 @@ Types:Legendary Enchantment Background
S:Mode$ Continuous | Affected$ Creature.IsCommander+YouOwn | AddTrigger$ Dies | Description$ Commander creatures you own have "Whenever an artifact or creature you control is put into a graveyard from the battlefield, each opponent loses 1 life." S:Mode$ Continuous | Affected$ Creature.IsCommander+YouOwn | AddTrigger$ Dies | Description$ Commander creatures you own have "Whenever an artifact or creature you control is put into a graveyard from the battlefield, each opponent loses 1 life."
SVar:Dies:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Artifact.YouCtrl,Creature.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigDrain | TriggerDescription$ Whenever an artifact or creature you control is put into a graveyard from the battlefield, each opponent loses 1 life. SVar:Dies:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Artifact.YouCtrl,Creature.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigDrain | TriggerDescription$ Whenever an artifact or creature you control is put into a graveyard from the battlefield, each opponent loses 1 life.
SVar:TrigDrain:DB$ LoseLife | Defined$ Opponent | LifeAmount$ 1 SVar:TrigDrain:DB$ LoseLife | Defined$ Opponent | LifeAmount$ 1
DeckHints:Type$Artifact & Ability$Sacrifice
AI:RemoveDeck:NonCommander AI:RemoveDeck:NonCommander
DeckHints:Type$Artifact & Ability$Sacrifice
Oracle:Commander creatures you own have "Whenever an artifact or creature you control is put into a graveyard from the battlefield, each opponent loses 1 life." Oracle:Commander creatures you own have "Whenever an artifact or creature you control is put into a graveyard from the battlefield, each opponent loses 1 life."

View File

@@ -5,6 +5,6 @@ S:Mode$ Continuous | Affected$ Creature.IsCommander+YouOwn | AddTrigger$ Attacks
SVar:AttacksPlayer:Mode$ Attacks | ValidCard$ Card.Self | Attacked$ Player | Condition$ NoOpponentHasMoreLifeThanAttacked | Execute$ TrigPutCounter | TriggerDescription$ Whenever this creature attacks a player, if no opponent has more life than that player, put a +1/+1 counter on this creature. It gains deathtouch and indestructible until end of turn. SVar:AttacksPlayer:Mode$ Attacks | ValidCard$ Card.Self | Attacked$ Player | Condition$ NoOpponentHasMoreLifeThanAttacked | Execute$ TrigPutCounter | TriggerDescription$ Whenever this creature attacks a player, if no opponent has more life than that player, put a +1/+1 counter on this creature. It gains deathtouch and indestructible until end of turn.
SVar:TrigPutCounter:DB$ PutCounter | CounterType$ P1P1 | CounterNum$ 1 | Defined$ Self | SubAbility$ DBPump SVar:TrigPutCounter:DB$ PutCounter | CounterType$ P1P1 | CounterNum$ 1 | Defined$ Self | SubAbility$ DBPump
SVar:DBPump:DB$ Pump | Defined$ Self | KW$ Deathtouch & Indestructible SVar:DBPump:DB$ Pump | Defined$ Self | KW$ Deathtouch & Indestructible
DeckHas:Ability$Counters
AI:RemoveDeck:NonCommander AI:RemoveDeck:NonCommander
DeckHas:Ability$Counters
Oracle:Commander creatures you own have "Whenever this creature attacks a player, if no opponent has more life than that player, put a +1/+1 counter on this creature. It gains deathtouch and indestructible until end of turn." Oracle:Commander creatures you own have "Whenever this creature attacks a player, if no opponent has more life than that player, put a +1/+1 counter on this creature. It gains deathtouch and indestructible until end of turn."

View File

@@ -5,6 +5,6 @@ PT:2/1
K:Outlast:1 W K:Outlast:1 W
S:Mode$ Continuous | Affected$ Creature.YouCtrl+counters_GE1_P1P1 | AddKeyword$ First Strike | Description$ Each creature you control with a +1/+1 counter on it has first strike. S:Mode$ Continuous | Affected$ Creature.YouCtrl+counters_GE1_P1P1 | AddKeyword$ First Strike | Description$ Each creature you control with a +1/+1 counter on it has first strike.
SVar:PlayMain1:TRUE SVar:PlayMain1:TRUE
DeckHints:Ability$Counters
DeckHas:Ability$Counters DeckHas:Ability$Counters
DeckHints:Ability$Counters
Oracle:Outlast {1}{W} ({1}{W}, {T}: Put a +1/+1 counter on this creature. Outlast only as a sorcery.)\nEach creature you control with a +1/+1 counter on it has first strike. Oracle:Outlast {1}{W} ({1}{W}, {T}: Put a +1/+1 counter on this creature. Outlast only as a sorcery.)\nEach creature you control with a +1/+1 counter on it has first strike.

View File

@@ -6,6 +6,6 @@ SVar:TrigSearch:DB$ ChangeZone | Origin$ Library | OriginAlternative$ Graveyard
A:AB$ ChooseCard | Cost$ Sac<1/CARDNAME> | Choices$ Creature | Mandatory$ True | AILogic$ NeedsPrevention | SubAbility$ DBEffect | SpellDescription$ Prevent all combat damage a creature of your choice would deal this turn. A:AB$ ChooseCard | Cost$ Sac<1/CARDNAME> | Choices$ Creature | Mandatory$ True | AILogic$ NeedsPrevention | SubAbility$ DBEffect | SpellDescription$ Prevent all combat damage a creature of your choice would deal this turn.
SVar:DBEffect:DB$ Effect | ReplacementEffects$ RPreventNextFromSource | RememberObjects$ ChosenCard | ExileOnMoved$ Battlefield SVar:DBEffect:DB$ Effect | ReplacementEffects$ RPreventNextFromSource | RememberObjects$ ChosenCard | ExileOnMoved$ Battlefield
SVar:RPreventNextFromSource:Event$ DamageDone | IsCombat$ True | ValidSource$ Card.IsRemembered | Prevent$ True | Description$ Prevent all combat damage a creature of your choice would deal this turn. SVar:RPreventNextFromSource:Event$ DamageDone | IsCombat$ True | ValidSource$ Card.IsRemembered | Prevent$ True | Description$ Prevent all combat damage a creature of your choice would deal this turn.
DeckHints:Name$Ajani, Valiant Protector
DeckHas:Ability$Sacrifice DeckHas:Ability$Sacrifice
DeckHints:Name$Ajani, Valiant Protector
Oracle:When Ajani's Aid enters, you may search your library and/or graveyard for a card named Ajani, Valiant Protector, reveal it, and put it into your hand. If you search your library this way, shuffle.\nSacrifice Ajani's Aid: Prevent all combat damage a creature of your choice would deal this turn. Oracle:When Ajani's Aid enters, you may search your library and/or graveyard for a card named Ajani, Valiant Protector, reveal it, and put it into your hand. If you search your library this way, shuffle.\nSacrifice Ajani's Aid: Prevent all combat damage a creature of your choice would deal this turn.

View File

@@ -4,6 +4,6 @@ Types:Creature Cat Soldier
PT:2/2 PT:2/2
T:Mode$ LifeGained | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever you gain life, put a +1/+1 counter on CARDNAME. T:Mode$ LifeGained | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever you gain life, put a +1/+1 counter on CARDNAME.
SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
DeckHints:Ability$LifeGain
DeckHas:Ability$Counters DeckHas:Ability$Counters
DeckHints:Ability$LifeGain
Oracle:Whenever you gain life, put a +1/+1 counter on Ajani's Pridemate. Oracle:Whenever you gain life, put a +1/+1 counter on Ajani's Pridemate.

View File

@@ -5,6 +5,6 @@ PT:1/5
T:Mode$ Phase | Phase$ End of Turn | TriggerZones$ Battlefield | CheckSVar$ X | SVarCompare$ GE1 | Execute$ TrigDig | TriggerDescription$ At the beginning of each player's end step, if an artifact entered the battlefield under your control this turn, look at the top two cards of your library. Put one of them into your hand and the other into your graveyard. T:Mode$ Phase | Phase$ End of Turn | TriggerZones$ Battlefield | CheckSVar$ X | SVarCompare$ GE1 | Execute$ TrigDig | TriggerDescription$ At the beginning of each player's end step, if an artifact entered the battlefield under your control this turn, look at the top two cards of your library. Put one of them into your hand and the other into your graveyard.
SVar:TrigDig:DB$ Dig | DigNum$ 2 | ChangeNum$ 1 | DestinationZone2$ Graveyard | NoReveal$ True SVar:TrigDig:DB$ Dig | DigNum$ 2 | ChangeNum$ 1 | DestinationZone2$ Graveyard | NoReveal$ True
SVar:X:Count$ThisTurnEntered_Battlefield_Artifact.YouCtrl SVar:X:Count$ThisTurnEntered_Battlefield_Artifact.YouCtrl
DeckNeeds:Type$Artifact
DeckHas:Ability$Graveyard DeckHas:Ability$Graveyard
DeckNeeds:Type$Artifact
Oracle:At the beginning of each player's end step, if an artifact entered the battlefield under your control this turn, look at the top two cards of your library. Put one of them into your hand and the other into your graveyard. Oracle:At the beginning of each player's end step, if an artifact entered the battlefield under your control this turn, look at the top two cards of your library. Put one of them into your hand and the other into your graveyard.

View File

@@ -7,7 +7,7 @@ SVar:TrigToken:DB$ Token | TokenScript$ u_2_2_drake_flying
T:Mode$ Drawn | ValidCard$ Card.YouCtrl | Number$ 5 | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Whenever you draw your fifth card each turn, CARDNAME and Drakes you control get +X/+X until end of turn, where X is the number of cards in your hand. T:Mode$ Drawn | ValidCard$ Card.YouCtrl | Number$ 5 | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Whenever you draw your fifth card each turn, CARDNAME and Drakes you control get +X/+X until end of turn, where X is the number of cards in your hand.
SVar:TrigPump:DB$ PumpAll | ValidCards$ Card.Self,Drake.YouCtrl | NumAtt$ X | NumDef$ X SVar:TrigPump:DB$ PumpAll | ValidCards$ Card.Self,Drake.YouCtrl | NumAtt$ X | NumDef$ X
SVar:X:Count$InYourHand SVar:X:Count$InYourHand
AI:RemoveDeck:Random
DeckHas:Ability$Token & Type$Drake DeckHas:Ability$Token & Type$Drake
DeckHints:Type$Drake DeckHints:Type$Drake
AI:RemoveDeck:Random
Oracle:Whenever you draw your second card each turn, create a 2/2 blue Drake creature token with flying.\nWhenever you draw your fifth card each turn, Alandra, Sky Dreamer and Drakes you control get +X/+X until end of turn, where X is the number of cards in your hand. Oracle:Whenever you draw your second card each turn, create a 2/2 blue Drake creature token with flying.\nWhenever you draw your fifth card each turn, Alandra, Sky Dreamer and Drakes you control get +X/+X until end of turn, where X is the number of cards in your hand.

View File

@@ -7,9 +7,9 @@ K:Trample
K:Ward:1 K:Ward:1
T:Mode$ Sacrificed | ValidPlayer$ You | ValidCard$ Card.token | TriggerZones$ Battlefield,Exile | Execute$ TrigPump | TriggerDescription$ Whenever you sacrifice a token, NICKNAME perpetually gets +1/+1. This ability also triggers if NICKNAME is in exile. T:Mode$ Sacrificed | ValidPlayer$ You | ValidCard$ Card.token | TriggerZones$ Battlefield,Exile | Execute$ TrigPump | TriggerDescription$ Whenever you sacrifice a token, NICKNAME perpetually gets +1/+1. This ability also triggers if NICKNAME is in exile.
SVar:TrigPump:DB$ Pump | PumpZone$ Battlefield,Exile | NumAtt$ 1 | NumDef$ 1 | Duration$ Perpetual SVar:TrigPump:DB$ Pump | PumpZone$ Battlefield,Exile | NumAtt$ 1 | NumDef$ 1 | Duration$ Perpetual
AlternateMode:Adventure
DeckHas:Ability$Discard|Token & Type$Food DeckHas:Ability$Discard|Token & Type$Food
DeckHints:Ability$Token & Type$Treasure|Food|Clue DeckHints:Ability$Token & Type$Treasure|Food|Clue
AlternateMode:Adventure
Oracle:Flying, Trample, Ward {1}\nWhenever you sacrifice a token, Albiorix perpetually gets +1/+1. This ability also triggers if Albiorix is in exile. Oracle:Flying, Trample, Ward {1}\nWhenever you sacrifice a token, Albiorix perpetually gets +1/+1. This ability also triggers if Albiorix is in exile.
ALTERNATE ALTERNATE

View File

@@ -7,7 +7,7 @@ SVar:TrigToken:DB$ Token | TokenScript$ w_1_1_soldier
T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigPumpAll | TriggerDescription$ Whenever NICKNAME attacks, you may pay {8}. If you do, creatures you control get +X/+X until end of turn, where X is the number of historic permanents you control. T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigPumpAll | TriggerDescription$ Whenever NICKNAME attacks, you may pay {8}. If you do, creatures you control get +X/+X until end of turn, where X is the number of historic permanents you control.
SVar:TrigPumpAll:AB$ PumpAll | Cost$ 8 | ValidCards$ Creature.YouCtrl | NumAtt$ X | NumDef$ X SVar:TrigPumpAll:AB$ PumpAll | Cost$ 8 | ValidCards$ Creature.YouCtrl | NumAtt$ X | NumDef$ X
SVar:X:Count$Valid Permanent.YouCtrl+Historic SVar:X:Count$Valid Permanent.YouCtrl+Historic
SVar:HasAttackEffect:TRUE
DeckHas:Ability$Token DeckHas:Ability$Token
DeckHints:Type$Artifact|Legendary|Saga DeckHints:Type$Artifact|Legendary|Saga
SVar:HasAttackEffect:TRUE
Oracle:Whenever you cast a historic spell, create a 1/1 white Soldier creature token. (Artifacts, legendaries, and Sagas are historic.)\nWhenever Alistair attacks, you may pay {8}. If you do, creatures you control get +X/+X until end of turn, where X is the number of historic permanents you control. Oracle:Whenever you cast a historic spell, create a 1/1 white Soldier creature token. (Artifacts, legendaries, and Sagas are historic.)\nWhenever Alistair attacks, you may pay {8}. If you do, creatures you control get +X/+X until end of turn, where X is the number of historic permanents you control.

View File

@@ -8,6 +8,6 @@ SVar:TrigInvestigate:DB$ Investigate
A:AB$ Draw | Cost$ X W U U T Sac<1/Clue> | NumCards$ X | SubAbility$ DBGainLife | SpellDescription$ You draw X cards and gain X life. A:AB$ Draw | Cost$ X W U U T Sac<1/Clue> | NumCards$ X | SubAbility$ DBGainLife | SpellDescription$ You draw X cards and gain X life.
SVar:DBGainLife:DB$ GainLife | LifeAmount$ X SVar:DBGainLife:DB$ GainLife | LifeAmount$ X
SVar:X:Count$xPaid SVar:X:Count$xPaid
DeckHints:Ability$Investigate
DeckHas:Ability$Investigate|Token|Sacrifice|LifeGain & Type$Artifact|Clue DeckHas:Ability$Investigate|Token|Sacrifice|LifeGain & Type$Artifact|Clue
DeckHints:Ability$Investigate
Oracle:Vigilance\nWhen Alquist Proft, Master Sleuth enters, investigate. (Create a Clue token. It's an artifact with "{2}, Sacrifice this artifact: Draw a card.")\n{X}{W}{U}{U}, {T}, Sacrifice a Clue: You draw X cards and gain X life. Oracle:Vigilance\nWhen Alquist Proft, Master Sleuth enters, investigate. (Create a Clue token. It's an artifact with "{2}, Sacrifice this artifact: Draw a card.")\n{X}{W}{U}{U}, {T}, Sacrifice a Clue: You draw X cards and gain X life.

View File

@@ -9,8 +9,8 @@ SVar:Z:SVar$X/Plus.Y
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigChooseCardType | TriggerDescription$ At the beginning of your end step, choose a card type, then reveal the top two cards of your library. Put all cards of the chosen type revealed this way into your hand and the rest on the bottom of your library in any order. T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigChooseCardType | TriggerDescription$ At the beginning of your end step, choose a card type, then reveal the top two cards of your library. Put all cards of the chosen type revealed this way into your hand and the rest on the bottom of your library in any order.
SVar:TrigChooseCardType:DB$ ChooseType | Defined$ You | Type$ Card | SubAbility$ DBDig SVar:TrigChooseCardType:DB$ ChooseType | Defined$ You | Type$ Card | SubAbility$ DBDig
SVar:DBDig:DB$ Dig | DigNum$ 2 | Reveal$ True | ChangeNum$ All | ChangeValid$ Card.ChosenType | DestinationZone2$ Library | LibraryPosition$ -1 SVar:DBDig:DB$ Dig | DigNum$ 2 | Reveal$ True | ChangeNum$ All | ChangeValid$ Card.ChosenType | DestinationZone2$ Library | LibraryPosition$ -1
DeckHints:Keyword$Foretell
AI:RemoveDeck:All AI:RemoveDeck:All
DeckHints:Keyword$Foretell
AlternateMode:Modal AlternateMode:Modal
Oracle:Alrund gets +1/+1 for each card in your hand and each foretold card you own in exile.\nAt the beginning of your end step, choose a card type, then reveal the top two cards of your library. Put all cards of the chosen type revealed this way into your hand and the rest on the bottom of your library in any order. Oracle:Alrund gets +1/+1 for each card in your hand and each foretold card you own in exile.\nAt the beginning of your end step, choose a card type, then reveal the top two cards of your library. Put all cards of the chosen type revealed this way into your hand and the rest on the bottom of your library in any order.

View File

@@ -8,9 +8,9 @@ SVar:Y:Sacrificed$CardPower
K:Craft:2 B B XMin1 ExileCtrlOrGrave<X/Creature.Other> K:Craft:2 B B XMin1 ExileCtrlOrGrave<X/Creature.Other>
SVar:X:Count$xPaid SVar:X:Count$xPaid
A:AB$ ChangeZone | Cost$ 2 B | Origin$ Graveyard | Destination$ Hand | ActivationZone$ Graveyard | SpellDescription$ Return CARDNAME from your graveyard to your hand. A:AB$ ChangeZone | Cost$ 2 B | Origin$ Graveyard | Destination$ Hand | ActivationZone$ Graveyard | SpellDescription$ Return CARDNAME from your graveyard to your hand.
DeckHints:Ability$Discard|Mill|Sacrifice
DeckHas:Ability$Graveyard|Sacrifice|Mill
AI:RemoveDeck:All AI:RemoveDeck:All
DeckHas:Ability$Graveyard|Sacrifice|Mill
DeckHints:Ability$Discard|Mill|Sacrifice
AlternateMode:DoubleFaced AlternateMode:DoubleFaced
Oracle:When Altar of the Wretched enters, you may sacrifice a nontoken creature. If you do, draw X cards, then mill X cards, where X is that creature's power.\nCraft with one or more creatures {2}{B}{B}\n{2}{B}: Return Altar of the Wretched from your graveyard to your hand. Oracle:When Altar of the Wretched enters, you may sacrifice a nontoken creature. If you do, draw X cards, then mill X cards, where X is that creature's power.\nCraft with one or more creatures {2}{B}{B}\n{2}{B}: Return Altar of the Wretched from your graveyard to your hand.

View File

@@ -10,6 +10,6 @@ SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ bg_1_1_insect | Remembe
SVar:DBPutCounter:DB$ PutCounter | Defined$ Remembered | CounterNum$ X | CounterType$ P1P1 | SubAbility$ DBCleanup SVar:DBPutCounter:DB$ PutCounter | Defined$ Remembered | CounterNum$ X | CounterType$ P1P1 | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:TriggerObjectsCards$GreatestCMC SVar:X:TriggerObjectsCards$GreatestCMC
DeckHints:Type$Insect & Ability$Graveyard
DeckHas:Ability$Token & Ability$Graveyard DeckHas:Ability$Token & Ability$Graveyard
DeckHints:Type$Insect & Ability$Graveyard
Oracle:Flying, menace\nOther Insects you control have menace.\nWhenever one or more cards leave your graveyard, you may create a 1/1 black and green Insect creature token, then put a number of +1/+1 counters on it equal to the greatest mana value among those cards. Do this only once each turn. Oracle:Flying, menace\nOther Insects you control have menace.\nWhenever one or more cards leave your graveyard, you may create a 1/1 black and green Insect creature token, then put a number of +1/+1 counters on it equal to the greatest mana value among those cards. Do this only once each turn.

View File

@@ -11,6 +11,6 @@ SVar:VolverPumped:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNu
SVar:VolverResilience:DB$ Animate | Defined$ Self | Abilities$ ABRegen | Duration$ Permanent SVar:VolverResilience:DB$ Animate | Defined$ Self | Abilities$ ABRegen | Duration$ Permanent
SVar:ABRegen:AB$ Regenerate | Cost$ PayLife<3> | SpellDescription$ Regenerate CARDNAME. SVar:ABRegen:AB$ Regenerate | Cost$ PayLife<3> | SpellDescription$ Regenerate CARDNAME.
AI:RemoveDeck:Random AI:RemoveDeck:Random
DeckNeeds:Color$Blue|Black
DeckHas:Ability$Counters DeckHas:Ability$Counters
DeckNeeds:Color$Blue|Black
Oracle:Kicker {1}{U} and/or {B} (You may pay an additional {1}{U} and/or {B} as you cast this spell.)\nIf Anavolver was kicked with its {1}{U} kicker, it enters with two +1/+1 counters on it and with flying.\nIf Anavolver was kicked with its {B} kicker, it enters with a +1/+1 counter on it and with "Pay 3 life: Regenerate Anavolver." Oracle:Kicker {1}{U} and/or {B} (You may pay an additional {1}{U} and/or {B} as you cast this spell.)\nIf Anavolver was kicked with its {1}{U} kicker, it enters with two +1/+1 counters on it and with flying.\nIf Anavolver was kicked with its {B} kicker, it enters with a +1/+1 counter on it and with "Pay 3 life: Regenerate Anavolver."

View File

@@ -7,6 +7,6 @@ SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Count$Compare Y LTZ.2.0 SVar:X:Count$Compare Y LTZ.2.0
SVar:Y:Remembered$CardManaCost SVar:Y:Remembered$CardManaCost
SVar:Z:Sacrificed$CardManaCost SVar:Z:Sacrificed$CardManaCost
DeckNeeds:Type$Artifact|Creature|Equipment|Vehicle
AI:RemoveDeck:Random AI:RemoveDeck:Random
DeckNeeds:Type$Artifact|Creature|Equipment|Vehicle
Oracle:As an additional cost to cast this spell, sacrifice an artifact or creature.\nSearch your library for an Equipment or Vehicle card, put that card onto the battlefield, then shuffle. If it has mana value less than the sacrificed permanent's mana value, scry 2. Oracle:As an additional cost to cast this spell, sacrifice an artifact or creature.\nSearch your library for an Equipment or Vehicle card, put that card onto the battlefield, then shuffle. If it has mana value less than the sacrificed permanent's mana value, scry 2.

View File

@@ -6,6 +6,6 @@ K:Flying
T:Mode$ DamageDealtOnce | ValidSource$ Card.Self | Execute$ TrigChange | Delirium$ True | TriggerZones$ Battlefield | TriggerDescription$ Delirium — Whenever CARDNAME deals damage, if there are four or more card types among cards in your graveyard, exile target creature an opponent controls. T:Mode$ DamageDealtOnce | ValidSource$ Card.Self | Execute$ TrigChange | Delirium$ True | TriggerZones$ Battlefield | TriggerDescription$ Delirium — Whenever CARDNAME deals damage, if there are four or more card types among cards in your graveyard, exile target creature an opponent controls.
SVar:TrigChange:DB$ ChangeZone | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | Origin$ Battlefield | Destination$ Exile SVar:TrigChange:DB$ ChangeZone | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | Origin$ Battlefield | Destination$ Exile
SVar:HasCombatEffect:TRUE SVar:HasCombatEffect:TRUE
DeckHints:Ability$Graveyard|Discard
DeckHas:Ability$Delirium DeckHas:Ability$Delirium
DeckHints:Ability$Graveyard|Discard
Oracle:Flying\nDelirium — Whenever Angel of Deliverance deals damage, if there are four or more card types among cards in your graveyard, exile target creature an opponent controls. Oracle:Flying\nDelirium — Whenever Angel of Deliverance deals damage, if there are four or more card types among cards in your graveyard, exile target creature an opponent controls.

View File

@@ -7,6 +7,6 @@ K:Vigilance
K:Lifelink K:Lifelink
K:Fabricate:2 K:Fabricate:2
S:Mode$ Continuous | Affected$ Creature.Other+YouCtrl | AddPower$ 1 | AddToughness$ 1 | Description$ Other creatures you control get +1/+1. S:Mode$ Continuous | Affected$ Creature.Other+YouCtrl | AddPower$ 1 | AddToughness$ 1 | Description$ Other creatures you control get +1/+1.
DeckHas:Ability$Counters|Token
SVar:PlayMain1:TRUE SVar:PlayMain1:TRUE
DeckHas:Ability$Counters|Token
Oracle:Flying, vigilance, lifelink\nFabricate 2 (When this creature enters, put two +1/+1 counters on it or create two 1/1 colorless Servo artifact creature tokens.)\nOther creatures you control get +1/+1. Oracle:Flying, vigilance, lifelink\nFabricate 2 (When this creature enters, put two +1/+1 counters on it or create two 1/1 colorless Servo artifact creature tokens.)\nOther creatures you control get +1/+1.

View File

@@ -9,7 +9,7 @@ T:Mode$ SpellCast | ValidCard$ Card.Party | ValidActivatingPlayer$ You | Execute
SVar:TrigChoose:DB$ ChooseCard | ChoiceZone$ Hand | Choices$ Creature.Party+YouOwn | ChoiceTitle$ Choose a party creature card in your hand | Amount$ 1 | SubAbility$ DBPump SVar:TrigChoose:DB$ ChooseCard | ChoiceZone$ Hand | Choices$ Creature.Party+YouOwn | ChoiceTitle$ Choose a party creature card in your hand | Amount$ 1 | SubAbility$ DBPump
SVar:DBPump:DB$ Pump | Defined$ ChosenCard | PumpZone$ Hand | NumAtt$ 1 | NumDef$ 1 | Duration$ Perpetual | SubAbility$ DBCleanup SVar:DBPump:DB$ Pump | Defined$ ChosenCard | PumpZone$ Hand | NumAtt$ 1 | NumDef$ 1 | Duration$ Perpetual | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True
DeckHas:Ability$Party|LifeGain
SVar:BuffedBy:Cleric,Rogue,Warrior,Wizard SVar:BuffedBy:Cleric,Rogue,Warrior,Wizard
DeckHas:Ability$Party|LifeGain
DeckHints:Type$Rogue|Warrior|Wizard DeckHints:Type$Rogue|Warrior|Wizard
Oracle:Flying, lifelink\nWhenever Angel of Unity enters or you cast a party spell, choose a party creature card in your hand. It perpetually gets +1/+1. (A party card or spell is a Cleric, Rogue, Warrior, or Wizard.) Oracle:Flying, lifelink\nWhenever Angel of Unity enters or you cast a party spell, choose a party creature card in your hand. It perpetually gets +1/+1. (A party card or spell is a Cleric, Rogue, Warrior, or Wizard.)

View File

@@ -3,6 +3,6 @@ ManaCost:3 W
Types:Instant Types:Instant
S:Mode$ AlternativeCost | ValidSA$ Spell.Self | EffectZone$ All | Cost$ tapXType<1/Creature> | IsPresent$ Plains.YouCtrl | Description$ If you control a Plains, you may tap an untapped creature you control rather than pay this spell's mana cost. S:Mode$ AlternativeCost | ValidSA$ Spell.Self | EffectZone$ All | Cost$ tapXType<1/Creature> | IsPresent$ Plains.YouCtrl | Description$ If you control a Plains, you may tap an untapped creature you control rather than pay this spell's mana cost.
A:SP$ Token | TokenScript$ w_4_4_angel_flying | AtEOT$ Exile | ActivationPhases$ BeginCombat->EndCombat | StackDescription$ {p:You} creates a 4/4 white Angel creature token with flying. Exile it at the beginning of the next end step. | SpellDescription$ Cast this spell only during combat. Create a 4/4 white Angel creature token with flying. Exile it at the beginning of the next end step. A:SP$ Token | TokenScript$ w_4_4_angel_flying | AtEOT$ Exile | ActivationPhases$ BeginCombat->EndCombat | StackDescription$ {p:You} creates a 4/4 white Angel creature token with flying. Exile it at the beginning of the next end step. | SpellDescription$ Cast this spell only during combat. Create a 4/4 white Angel creature token with flying. Exile it at the beginning of the next end step.
DeckHas:Ability$Token
AI:RemoveDeck:All AI:RemoveDeck:All
DeckHas:Ability$Token
Oracle:If you control a Plains, you may tap an untapped creature you control rather than pay this spell's mana cost.\nCast this spell only during combat.\nCreate a 4/4 white Angel creature token with flying. Exile it at the beginning of the next end step. Oracle:If you control a Plains, you may tap an untapped creature you control rather than pay this spell's mana cost.\nCast this spell only during combat.\nCreate a 4/4 white Angel creature token with flying. Exile it at the beginning of the next end step.

View File

@@ -5,6 +5,6 @@ PT:2/3
K:Flying K:Flying
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Permanent.YouCtrl+Other+HasCounters | TriggerZones$ Battlefield | Execute$ TrigInvestigate | TriggerDescription$ Whenever another permanent you control leaves the battlefield, if it had counters on it, investigate. T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Permanent.YouCtrl+Other+HasCounters | TriggerZones$ Battlefield | Execute$ TrigInvestigate | TriggerDescription$ Whenever another permanent you control leaves the battlefield, if it had counters on it, investigate.
SVar:TrigInvestigate:DB$ Investigate SVar:TrigInvestigate:DB$ Investigate
DeckHints:Ability$Counters
DeckHas:Ability$Investigate|Token|Sacrifice & Type$Artifact|Clue DeckHas:Ability$Investigate|Token|Sacrifice & Type$Artifact|Clue
DeckHints:Ability$Counters
Oracle:Flying\nWhenever another permanent you control leaves the battlefield, if it had counters on it, investigate. Oracle:Flying\nWhenever another permanent you control leaves the battlefield, if it had counters on it, investigate.

View File

@@ -9,8 +9,8 @@ T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigExile | Secondary$ True |
SVar:TrigExile:DB$ ChangeZone | ValidTgts$ Enchantment.nonAura+YouCtrl | Origin$ Graveyard | TargetMin$ 0 | TargetMax$ 1 | Destination$ Exile | TgtPrompt$ Select up to one target non-Aura enchantment card from your graveyard | RememberChanged$ True | SubAbility$ DBCopy SVar:TrigExile:DB$ ChangeZone | ValidTgts$ Enchantment.nonAura+YouCtrl | Origin$ Graveyard | TargetMin$ 0 | TargetMax$ 1 | Destination$ Exile | TgtPrompt$ Select up to one target non-Aura enchantment card from your graveyard | RememberChanged$ True | SubAbility$ DBCopy
SVar:DBCopy:DB$ CopyPermanent | Defined$ Remembered | SetPower$ 3 | SetToughness$ 3 | AddTypes$ Creature & Zombie | SetColor$ Black | SubAbility$ DBCleanup SVar:DBCopy:DB$ CopyPermanent | Defined$ Remembered | SetPower$ 3 | SetToughness$ 3 | AddTypes$ Creature & Zombie | SetColor$ Black | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
DeckHas:Ability$Token|Graveyard
DeckNeeds:Type$Enchantment
DeckHints:Ability$Graveyard|Mill
SVar:HasAttackEffect:TRUE SVar:HasAttackEffect:TRUE
DeckHas:Ability$Token|Graveyard
DeckHints:Ability$Graveyard|Mill
DeckNeeds:Type$Enchantment
Oracle:Menace\nOther enchantment creatures you control have menace.\nWhenever Anikthea enters or attacks, exile up to one target non-Aura enchantment card from your graveyard. Create a token that's a copy of that card, except it's a 3/3 black Zombie creature in addition to its other types. Oracle:Menace\nOther enchantment creatures you control have menace.\nWhenever Anikthea enters or attacks, exile up to one target non-Aura enchantment card from your graveyard. Create a token that's a copy of that card, except it's a 3/3 black Zombie creature in addition to its other types.

View File

@@ -4,6 +4,6 @@ Types:Artifact
T:Mode$ CounterAddedOnce | ValidCard$ Permanent.YouCtrl | TriggerZones$ Battlefield | CounterType$ P1P1 | Execute$ TrigToken | TriggerDescription$ Whenever one or more +1/+1 counters are put on a permanent you control, you may pay {1}. If you do, create a 1/1 colorless Servo artifact creature token. T:Mode$ CounterAddedOnce | ValidCard$ Permanent.YouCtrl | TriggerZones$ Battlefield | CounterType$ P1P1 | Execute$ TrigToken | TriggerDescription$ Whenever one or more +1/+1 counters are put on a permanent you control, you may pay {1}. If you do, create a 1/1 colorless Servo artifact creature token.
SVar:TrigToken:AB$ Token | Cost$ 1 | TokenAmount$ 1 | TokenScript$ c_1_1_a_servo | TokenOwner$ You SVar:TrigToken:AB$ Token | Cost$ 1 | TokenAmount$ 1 | TokenScript$ c_1_1_a_servo | TokenOwner$ You
A:AB$ PutCounter | Cost$ 3 T | ValidTgts$ Permanent,Player | TgtPrompt$ Select target player or permanent | CounterType$ ExistingCounter | CounterNum$ 1 | AILogic$ AtOppEOT | SpellDescription$ Choose a counter on target permanent or player. Give that permanent or player another counter of that kind. A:AB$ PutCounter | Cost$ 3 T | ValidTgts$ Permanent,Player | TgtPrompt$ Select target player or permanent | CounterType$ ExistingCounter | CounterNum$ 1 | AILogic$ AtOppEOT | SpellDescription$ Choose a counter on target permanent or player. Give that permanent or player another counter of that kind.
DeckHints:Ability$Counters
AI:RemoveDeck:All AI:RemoveDeck:All
DeckHints:Ability$Counters
Oracle:Whenever one or more +1/+1 counters are put on a permanent you control, you may pay {1}. If you do, create a 1/1 colorless Servo artifact creature token.\n{3}, {T}: Choose a counter on target permanent or player. Give that permanent or player another counter of that kind. Oracle:Whenever one or more +1/+1 counters are put on a permanent you control, you may pay {1}. If you do, create a 1/1 colorless Servo artifact creature token.\n{3}, {T}: Choose a counter on target permanent or player. Give that permanent or player another counter of that kind.

View File

@@ -3,6 +3,6 @@ ManaCost:1 B
Types:Instant Types:Instant
A:SP$ ChangeZone | Defined$ Targeted | ValidTgts$ Creature | ConditionCheckSVar$ X | ConditionSVarCompare$ GE3 | Origin$ Battlefield | Destination$ Exile | SubAbility$ NotPoisoned | SpellDescription$ Exile target creature if it has mana value 3 or less. Corrupted — Exile that creature instead if its controller has three or more poison counters. A:SP$ ChangeZone | Defined$ Targeted | ValidTgts$ Creature | ConditionCheckSVar$ X | ConditionSVarCompare$ GE3 | Origin$ Battlefield | Destination$ Exile | SubAbility$ NotPoisoned | SpellDescription$ Exile target creature if it has mana value 3 or less. Corrupted — Exile that creature instead if its controller has three or more poison counters.
SVar:NotPoisoned:DB$ ChangeZone | Defined$ Targeted | Origin$ Battlefield | Destination$ Exile | ConditionDefined$ Targeted | ConditionPresent$ Creature.cmcLE3 SVar:NotPoisoned:DB$ ChangeZone | Defined$ Targeted | Origin$ Battlefield | Destination$ Exile | ConditionDefined$ Targeted | ConditionPresent$ Creature.cmcLE3
DeckHints:Ability$Proliferate & Keyword$Infect|Toxic
SVar:X:TargetedController$Counters.Poison SVar:X:TargetedController$Counters.Poison
DeckHints:Ability$Proliferate & Keyword$Infect|Toxic
Oracle:Exile target creature if it has mana value 3 or less.\nCorrupted — Exile that creature instead if its controller has three or more poison counters. Oracle:Exile target creature if it has mana value 3 or less.\nCorrupted — Exile that creature instead if its controller has three or more poison counters.

View File

@@ -8,6 +8,6 @@ SVar:TrigMill:DB$ Mill | Defined$ TriggeredTarget | NumCards$ X | RememberMilled
SVar:DBDraw:DB$ Draw | Defined$ You | ConditionDefined$ Remembered | ConditionPresent$ Creature | SubAbility$ DBCleanup SVar:DBDraw:DB$ Draw | Defined$ You | ConditionDefined$ Remembered | ConditionPresent$ Creature | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:TriggerCount$DamageAmount SVar:X:TriggerCount$DamageAmount
DeckNeeds:Type$Rogue
DeckHas:Ability$Mill DeckHas:Ability$Mill
DeckNeeds:Type$Rogue
Oracle:Other Rogues you control get +1/+1.\nWhenever one or more Rogues you control deal combat damage to a player, that player mills a card for each 1 damage dealt to them. If the player mills at least one creature card this way, you draw a card. (To mill a card, a player puts the top card of their library into their graveyard.) Oracle:Other Rogues you control get +1/+1.\nWhenever one or more Rogues you control deal combat damage to a player, that player mills a card for each 1 damage dealt to them. If the player mills at least one creature card this way, you draw a card. (To mill a card, a player puts the top card of their library into their graveyard.)

View File

@@ -4,7 +4,7 @@ Types:Creature Spider Mutant
PT:0/0 PT:0/0
K:Graft:2 K:Graft:2
A:AB$ Pump | Cost$ G | ValidTgts$ Creature.counters_GE1_P1P1 | TgtPrompt$ Select target creature with a +1/+1 counter | KW$ Reach | SpellDescription$ Target creature with a +1/+1 counter on it gains reach until end of turn. (It can block creatures with flying.) A:AB$ Pump | Cost$ G | ValidTgts$ Creature.counters_GE1_P1P1 | TgtPrompt$ Select target creature with a +1/+1 counter | KW$ Reach | SpellDescription$ Target creature with a +1/+1 counter on it gains reach until end of turn. (It can block creatures with flying.)
DeckNeeds:Ability$Counters
DeckHas:Ability$Counters
SVar:AIGraftPreference:DontMoveCounterIfLethal SVar:AIGraftPreference:DontMoveCounterIfLethal
DeckHas:Ability$Counters
DeckNeeds:Ability$Counters
Oracle:Graft 2 (This creature enters with two +1/+1 counters on it. Whenever another creature enters, you may move a +1/+1 counter from this creature onto it.)\n{G}: Target creature with a +1/+1 counter on it gains reach until end of turn. (It can block creatures with flying.) Oracle:Graft 2 (This creature enters with two +1/+1 counters on it. Whenever another creature enters, you may move a +1/+1 counter from this creature onto it.)\n{G}: Target creature with a +1/+1 counter on it gains reach until end of turn. (It can block creatures with flying.)

View File

@@ -4,8 +4,8 @@ Types:Creature Elemental
PT:1/3 PT:1/3
T:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | ActivatorThisTurnCast$ EQ1 | Execute$ TrigPump | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast your first instant or sorcery spell each turn, CARDNAME gets +2/+0 until end of turn. T:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | ActivatorThisTurnCast$ EQ1 | Execute$ TrigPump | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast your first instant or sorcery spell each turn, CARDNAME gets +2/+0 until end of turn.
SVar:TrigPump:DB$ Pump | Defined$ Self | NumAtt$ 2 SVar:TrigPump:DB$ Pump | Defined$ Self | NumAtt$ 2
DeckHints:Type$Instant|Sorcery
DeckHas:Ability$Graveyard DeckHas:Ability$Graveyard
DeckHints:Type$Instant|Sorcery
AlternateMode:Adventure AlternateMode:Adventure
Oracle:Whenever you cast your first instant or sorcery spell each turn, Aquatic Alchemist gets +2/+0 until end of turn. Oracle:Whenever you cast your first instant or sorcery spell each turn, Aquatic Alchemist gets +2/+0 until end of turn.

View File

@@ -8,6 +8,6 @@ T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigPutCounterAll | Secondary$
SVar:TrigPutCounterAll:DB$ PutCounterAll | ValidCards$ Creature.YouCtrl+StrictlyOther | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBGainLife SVar:TrigPutCounterAll:DB$ PutCounterAll | ValidCards$ Creature.YouCtrl+StrictlyOther | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBGainLife
SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ X SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ X
SVar:X:Count$Valid Creature.YouCtrl+StrictlyOther SVar:X:Count$Valid Creature.YouCtrl+StrictlyOther
DeckHas:Ability$Counters|LifeGain
SVar:HasAttackEffect:TRUE SVar:HasAttackEffect:TRUE
DeckHas:Ability$Counters|LifeGain
Oracle:Vigilance\nWhenever Aragorn and Arwen, Wed enters or attacks, put a +1/+1 counter on each other creature you control. You gain 1 life for each other creature you control. Oracle:Vigilance\nWhenever Aragorn and Arwen, Wed enters or attacks, put a +1/+1 counter on each other creature you control. You gain 1 life for each other creature you control.

View File

@@ -3,6 +3,6 @@ ManaCost:U R
Types:Instant Types:Instant
A:SP$ Dig | DigNum$ 4 | ChangeNum$ 1 | Optional$ True | ForceRevealToController$ True | ChangeValid$ Card.Instant,Card.Sorcery | RestRandomOrder$ True | StackDescription$ SpellDescription | SpellDescription$ Look at the top four cards of your library. You may reveal an instant or sorcery card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. A:SP$ Dig | DigNum$ 4 | ChangeNum$ 1 | Optional$ True | ForceRevealToController$ True | ChangeValid$ Card.Instant,Card.Sorcery | RestRandomOrder$ True | StackDescription$ SpellDescription | SpellDescription$ Look at the top four cards of your library. You may reveal an instant or sorcery card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.
K:Flashback:3 U R K:Flashback:3 U R
DeckNeeds:Type$Instant|Sorcery
DeckHas:Ability$Graveyard DeckHas:Ability$Graveyard
DeckNeeds:Type$Instant|Sorcery
Oracle:Look at the top four cards of your library. You may reveal an instant or sorcery card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.\nFlashback {3}{U}{R} (You may cast this card from your graveyard for its flashback cost. Then exile it.) Oracle:Look at the top four cards of your library. You may reveal an instant or sorcery card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.\nFlashback {3}{U}{R} (You may cast this card from your graveyard for its flashback cost. Then exile it.)

View File

@@ -2,6 +2,6 @@ Name:Arcane Melee
ManaCost:4 U ManaCost:4 U
Types:Enchantment Types:Enchantment
S:Mode$ ReduceCost | ValidCard$ Instant,Sorcery | Type$ Spell | Amount$ 2 | Description$ Instant and sorcery spells cost {2} less to cast. S:Mode$ ReduceCost | ValidCard$ Instant,Sorcery | Type$ Spell | Amount$ 2 | Description$ Instant and sorcery spells cost {2} less to cast.
DeckNeeds:Type$Instant|Sorcery
AI:RemoveDeck:Random AI:RemoveDeck:Random
DeckNeeds:Type$Instant|Sorcery
Oracle:Instant and sorcery spells cost {2} less to cast. Oracle:Instant and sorcery spells cost {2} less to cast.

View File

@@ -7,6 +7,6 @@ T:Mode$ ChangesZone | ValidCard$ Card.Self+wasCastByYou | Destination$ Battlefie
SVar:TrigExile:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | TgtPrompt$ Select target instant or sorcery card with mana value less than or equal to CARDNAME's power | ValidTgts$ Instant.YouOwn+cmcLEX,Sorcery.YouOwn+cmcLEX | RememberChanged$ True | SubAbility$ DBPlay SVar:TrigExile:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | TgtPrompt$ Select target instant or sorcery card with mana value less than or equal to CARDNAME's power | ValidTgts$ Instant.YouOwn+cmcLEX,Sorcery.YouOwn+cmcLEX | RememberChanged$ True | SubAbility$ DBPlay
SVar:DBPlay:DB$ Play | Valid$ Card.IsRemembered | ValidZone$ Exile | Controller$ You | CopyCard$ True | WithoutManaCost$ True | ValidSA$ Spell | Optional$ True | SubAbility$ DBCleanup SVar:DBPlay:DB$ Play | Valid$ Card.IsRemembered | ValidZone$ Exile | Controller$ You | CopyCard$ True | WithoutManaCost$ True | ValidSA$ Spell | Optional$ True | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
DeckHints:Type$Instant|Sorcery & Color$Blue
SVar:X:Count$CardPower SVar:X:Count$CardPower
DeckHints:Type$Instant|Sorcery & Color$Blue
Oracle:Prototype {1}{U}{U} — 2/1 (You may cast this spell with different mana cost, color, and size. It keeps its abilities and types.)\nWhen Arcane Proxy enters, if you cast it, exile target instant or sorcery card with mana value less than or equal to Arcane Proxy's power from your graveyard. Copy that card. You may cast the copy without paying its mana cost. Oracle:Prototype {1}{U}{U} — 2/1 (You may cast this spell with different mana cost, color, and size. It keeps its abilities and types.)\nWhen Arcane Proxy enters, if you cast it, exile target instant or sorcery card with mana value less than or equal to Arcane Proxy's power from your graveyard. Copy that card. You may cast the copy without paying its mana cost.

View File

@@ -6,6 +6,6 @@ K:First Strike
T:Mode$ ChangesZone | ValidCard$ Card.Self | Destination$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ When CARDNAME enters, put a +1/+1 counter on each other artifact creature you control. T:Mode$ ChangesZone | ValidCard$ Card.Self | Destination$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ When CARDNAME enters, put a +1/+1 counter on each other artifact creature you control.
SVar:TrigPutCounter:DB$ PutCounterAll | ValidCards$ Creature.Artifact+StrictlyOther+YouCtrl | CounterType$ P1P1 | CounterNum$ 1 SVar:TrigPutCounter:DB$ PutCounterAll | ValidCards$ Creature.Artifact+StrictlyOther+YouCtrl | CounterType$ P1P1 | CounterNum$ 1
K:Modular:2 K:Modular:2
DeckHas:Ability$Counters
SVar:PlayMain1:TRUE SVar:PlayMain1:TRUE
DeckHas:Ability$Counters
Oracle:First strike\nWhen Arcbound Shikari enters, put a +1/+1 counter on each other artifact creature you control.\nModular 2 (This creature enters with two +1/+1 counters on it. When it dies, you may put its +1/+1 counters on target artifact creature.) Oracle:First strike\nWhen Arcbound Shikari enters, put a +1/+1 counter on each other artifact creature you control.\nModular 2 (This creature enters with two +1/+1 counters on it. When it dies, you may put its +1/+1 counters on target artifact creature.)

View File

@@ -3,7 +3,7 @@ ManaCost:6
Types:Artifact Creature Golem Types:Artifact Creature Golem
PT:0/0 PT:0/0
K:Modular:Sunburst K:Modular:Sunburst
AI:RemoveDeck:Random
DeckHas:Ability$Counters DeckHas:Ability$Counters
DeckHints:Ability$Proliferate DeckHints:Ability$Proliferate
AI:RemoveDeck:Random
Oracle:Modular—Sunburst (This creature enters with a +1/+1 counter on it for each color of mana spent to cast it. When it dies, you may put its +1/+1 counters on target artifact creature.) Oracle:Modular—Sunburst (This creature enters with a +1/+1 counter on it for each color of mana spent to cast it. When it dies, you may put its +1/+1 counters on target artifact creature.)

View File

@@ -9,6 +9,6 @@ SVar:TrigRemoveCtr:DB$ RemoveCounter | Defined$ Self | CounterType$ OIL | Counte
SVar:LoseGame:DB$ LosesGame | Defined$ You | ConditionDefined$ Self | ConditionPresent$ Card.counters_EQ0_OIL SVar:LoseGame:DB$ LosesGame | Defined$ You | ConditionDefined$ Self | ConditionPresent$ Card.counters_EQ0_OIL
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.OppCtrl | TriggerZones$ Battlefield | Execute$ TrigLoseLife | TriggerDescription$ Whenever a creature an opponent controls dies, its controller loses 2 life. T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.OppCtrl | TriggerZones$ Battlefield | Execute$ TrigLoseLife | TriggerDescription$ Whenever a creature an opponent controls dies, its controller loses 2 life.
SVar:TrigLoseLife:DB$ LoseLife | LifeAmount$ 2 | Defined$ TriggeredCardController SVar:TrigLoseLife:DB$ LoseLife | LifeAmount$ 2 | Defined$ TriggeredCardController
DeckHas:Ability$Counters
AI:RemoveDeck:Random AI:RemoveDeck:Random
DeckHas:Ability$Counters
Oracle:Flying\nArchfiend of the Dross enters with four oil counters on it.\nAt the beginning of your upkeep, remove an oil counter from Archfiend of the Dross. Then if it has no oil counters on it, you lose the game.\nWhenever a creature an opponent controls dies, its controller loses 2 life. Oracle:Flying\nArchfiend of the Dross enters with four oil counters on it.\nAt the beginning of your upkeep, remove an oil counter from Archfiend of the Dross. Then if it has no oil counters on it, you lose the game.\nWhenever a creature an opponent controls dies, its controller loses 2 life.

Some files were not shown because too many files have changed in this diff Show More