mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-11 16:26:22 +00:00
Merge branch 'master' into code-cleanup
# Conflicts: # forge-ai/src/main/java/forge/ai/ComputerUtil.java # forge-core/src/main/java/forge/card/DeckHints.java # forge-game/src/main/java/forge/game/ability/AbilityFactory.java # forge-game/src/main/java/forge/game/cost/CostUntapType.java # forge-gui/src/main/java/forge/player/HumanCostDecision.java
This commit is contained in:
@@ -25,7 +25,7 @@ This file is tarball, and may need to be extracted twice depending on which prog
|
||||
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.
|
||||
Java 8 or later is required to run Forge. Please make sure is the right version is installed in your environment. 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.
|
||||
On first run, Forge will download all needed data.
|
||||
@@ -47,4 +47,4 @@ You can also play against the AI in a variety of formats, such as Sealed, Draft,
|
||||
## Questions
|
||||
|
||||
If you have any questions, please join the Discord channel. Read the #rules and the frequently-asked-questions.
|
||||
If your question is not answered there, feel free to ask in the #help channel.
|
||||
If your question is not answered there, feel free to ask in the #help channel.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.65-SNAPSHOT</version>
|
||||
<version>1.6.66-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.65-SNAPSHOT</version>
|
||||
<version>1.6.66-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-ai</artifactId>
|
||||
|
||||
@@ -919,6 +919,10 @@ public class AiController {
|
||||
if (checkCurseEffects(sa)) {
|
||||
return AiPlayDecision.CurseEffects;
|
||||
}
|
||||
// TODO maybe other location for this?
|
||||
if (!sa.isLegalAfterStack()) {
|
||||
return AiPlayDecision.AnotherTime;
|
||||
}
|
||||
Card spellHost = card;
|
||||
if (sa.isSpell()) {
|
||||
spellHost = CardCopyService.getLKICopy(spellHost);
|
||||
@@ -926,10 +930,6 @@ public class AiController {
|
||||
spellHost.setLastKnownZone(game.getStackZone()); // need to add to stack to make check Restrictions respect stack cmc
|
||||
spellHost.setCastFrom(card.getZone());
|
||||
}
|
||||
// TODO maybe other location for this?
|
||||
if (!sa.isLegalAfterStack()) {
|
||||
return AiPlayDecision.AnotherTime;
|
||||
}
|
||||
if (!sa.checkRestrictions(spellHost, player)) {
|
||||
return AiPlayDecision.AnotherTime;
|
||||
}
|
||||
@@ -942,7 +942,7 @@ public class AiController {
|
||||
}
|
||||
}
|
||||
if (sa instanceof Spell) {
|
||||
if (card.isPermanent()) {
|
||||
if (sa.getApi() == ApiType.PermanentCreature || sa.getApi() == ApiType.PermanentNoncreature) {
|
||||
return canPlayFromEffectAI((Spell) sa, false, true);
|
||||
}
|
||||
if (!player.cantLoseForZeroOrLessLife() && player.canLoseLife() &&
|
||||
|
||||
@@ -650,7 +650,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
|
||||
// TODO sort negatives to remove from best Cards first?
|
||||
for (final Card crd : negatives) {
|
||||
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);
|
||||
if (over > 0) {
|
||||
toRemove += over;
|
||||
@@ -761,7 +761,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -827,10 +827,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) {
|
||||
CardCollection typeList =
|
||||
CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, sa);
|
||||
CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, sa);
|
||||
|
||||
typeList = CardLists.filter(typeList, CardPredicates.TAPPED);
|
||||
typeList = CardLists.filter(typeList, CardPredicates.TAPPED, c -> c.getCounters(CounterEnumType.STUN) == 0 || c.canRemoveCounters(CounterType.get(CounterEnumType.STUN)));
|
||||
|
||||
if (untap) {
|
||||
typeList.remove(activate);
|
||||
@@ -842,12 +841,7 @@ public class ComputerUtil {
|
||||
|
||||
CardLists.sortByPowerDesc(typeList);
|
||||
|
||||
final CardCollection untapList = new CardCollection();
|
||||
|
||||
for (int i = 0; i < amount; i++) {
|
||||
untapList.add(typeList.get(i));
|
||||
}
|
||||
return untapList;
|
||||
return typeList.subList(0, amount);
|
||||
}
|
||||
|
||||
public static CardCollection chooseReturnType(final Player ai, final String type, final Card activate, final Card target, final int amount, SpellAbility sa) {
|
||||
|
||||
@@ -213,6 +213,8 @@ public class CountersRemoveAi extends SpellAbilityAi {
|
||||
sa.getTargets().add(ComputerUtilCard.getBestCreatureAI(aiUndyingList));
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO stun counters with canRemoveCounters check
|
||||
|
||||
// remove P1P1 counters from opposing creatures
|
||||
CardCollection oppP1P1List = CardLists.filter(list,
|
||||
|
||||
@@ -154,7 +154,7 @@ public class SetStateAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
// non-permanent facedown can't be turned face up
|
||||
if (!card.getRules().getType().isPermanent()) {
|
||||
if (!card.getRules().getType().isPermanent() || !card.canBeTurnedFaceUp()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.65-SNAPSHOT</version>
|
||||
<version>1.6.66-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-core</artifactId>
|
||||
|
||||
@@ -770,7 +770,6 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
|
||||
if (ctOther == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (final CoreType type : getCoreTypes()) {
|
||||
if (ctOther.hasType(type)) {
|
||||
return true;
|
||||
@@ -779,6 +778,23 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean sharesAllCardTypesWith(final CardTypeView ctOther) {
|
||||
if (ctOther == null) {
|
||||
return false;
|
||||
}
|
||||
for (final CoreType type : getCoreTypes()) {
|
||||
if (!ctOther.hasType(type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (final CoreType type : ctOther.getCoreTypes()) {
|
||||
if (!this.hasType(type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean sharesSubtypeWith(final CardTypeView ctOther) {
|
||||
if (ctOther == null) {
|
||||
return false;
|
||||
|
||||
@@ -30,6 +30,7 @@ public interface CardTypeView extends Iterable<String>, Serializable {
|
||||
public boolean sharesLandTypeWith(final CardTypeView ctOther);
|
||||
public boolean sharesPermanentTypeWith(final CardTypeView ctOther);
|
||||
public boolean sharesCardTypeWith(final CardTypeView ctOther);
|
||||
public boolean sharesAllCardTypesWith(final CardTypeView ctOther);
|
||||
|
||||
boolean isPermanent();
|
||||
boolean isCreature();
|
||||
|
||||
@@ -222,7 +222,7 @@ public class DeckHints {
|
||||
return true;
|
||||
}
|
||||
for (String tok : card.getTokens()) {
|
||||
if (tdb != null && tdb.containsRule(tok) && predicate.test(tdb.getToken(tok).getRules())) {
|
||||
if (tdb != null && tdb.containsRule(tok) && rulesWithTokens(predicate).test(tdb.getToken(tok).getRules())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +106,14 @@ public final class MagicColor {
|
||||
}
|
||||
}
|
||||
|
||||
public static String toSymbol(final byte color) {
|
||||
return MagicColor.Color.fromByte(color).getSymbol();
|
||||
}
|
||||
|
||||
public static String toSymbol(final String color) {
|
||||
return toSymbol(fromName(color));
|
||||
}
|
||||
|
||||
/**
|
||||
* The Interface Color.
|
||||
*/
|
||||
@@ -165,6 +173,17 @@ public final class MagicColor {
|
||||
symbol = symbol0;
|
||||
}
|
||||
|
||||
public static Color fromByte(final byte color) {
|
||||
switch (color) {
|
||||
case MagicColor.WHITE: return WHITE;
|
||||
case MagicColor.BLUE: return BLUE;
|
||||
case MagicColor.BLACK: return BLACK;
|
||||
case MagicColor.RED: return RED;
|
||||
case MagicColor.GREEN: return GREEN;
|
||||
default: return COLORLESS;
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.65-SNAPSHOT</version>
|
||||
<version>1.6.66-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-game</artifactId>
|
||||
|
||||
@@ -1870,6 +1870,8 @@ public class GameAction {
|
||||
|
||||
public final CardCollection sacrifice(final Iterable<Card> list, final SpellAbility source, final boolean effect, Map<AbilityKey, Object> params) {
|
||||
Multimap<Player, Card> lki = MultimapBuilder.hashKeys().arrayListValues().build();
|
||||
final boolean showRevealDialog = source != null && source.hasParam("ShowSacrificedCards");
|
||||
|
||||
CardCollection result = new CardCollection();
|
||||
for (Card c : list) {
|
||||
if (c == null) {
|
||||
@@ -1890,6 +1892,10 @@ public class GameAction {
|
||||
if (changed != null) {
|
||||
result.add(changed);
|
||||
}
|
||||
if (showRevealDialog) {
|
||||
final String message = Localizer.getInstance().getMessage("lblSacrifice");
|
||||
game.getAction().reveal(result, ZoneType.Graveyard, c.getOwner(), false, message, false);
|
||||
}
|
||||
}
|
||||
for (Map.Entry<Player, Collection<Card>> e : lki.asMap().entrySet()) {
|
||||
// Run triggers
|
||||
|
||||
@@ -308,8 +308,10 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
||||
|
||||
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 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();
|
||||
|
||||
public boolean canReceiveCounters(final CounterEnumType type) {
|
||||
@@ -330,8 +332,8 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
||||
addCounter(CounterType.get(counterType), n, source, table);
|
||||
}
|
||||
|
||||
public void subtractCounter(final CounterEnumType counterName, final int n, final Player remover) {
|
||||
subtractCounter(CounterType.get(counterName), n, remover);
|
||||
public int subtractCounter(final CounterEnumType counterName, final int n, final Player 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);
|
||||
|
||||
@@ -286,7 +286,15 @@ public final class AbilityFactory {
|
||||
final String key = "Choices";
|
||||
if (mapParams.containsKey(key)) {
|
||||
List<String> names = Lists.newArrayList(mapParams.get(key).split(","));
|
||||
spellAbility.setAdditionalAbilityList(key, names.stream().map(input -> getSubAbility(state, input, sVarHolder)).collect(Collectors.toList()));
|
||||
spellAbility.setAdditionalAbilityList(key, names.stream().map(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;
|
||||
}).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1295,7 +1295,7 @@ public class AbilityUtils {
|
||||
}
|
||||
}
|
||||
} else if (defined.startsWith("ValidStack")) {
|
||||
String valid = changedDef.split(" ", 2)[1];
|
||||
String[] valid = changedDef.split(" ", 2)[1].split(",");
|
||||
for (SpellAbilityStackInstance stackInstance : game.getStack()) {
|
||||
SpellAbility instanceSA = stackInstance.getSpellAbility();
|
||||
if (instanceSA != null && instanceSA.isValid(valid, player, card, sa)) {
|
||||
@@ -2303,6 +2303,10 @@ public class AbilityUtils {
|
||||
return doXMath(player.getNumDrawnThisTurn(), expr, c, ctb);
|
||||
}
|
||||
|
||||
if (sq[0].equals("YouDrewLastTurn")) {
|
||||
return doXMath(player.getNumDrawnLastTurn(), expr, c, ctb);
|
||||
}
|
||||
|
||||
if (sq[0].equals("YouRollThisTurn")) {
|
||||
return doXMath(player.getNumRollsThisTurn(), expr, c, ctb);
|
||||
}
|
||||
@@ -2521,6 +2525,23 @@ public class AbilityUtils {
|
||||
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
|
||||
if (sq[0].startsWith("ManaPool")) {
|
||||
final String color = l[0].split(":")[1];
|
||||
|
||||
@@ -3,7 +3,6 @@ package forge.game.ability.effects;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import forge.card.CardStateName;
|
||||
import forge.card.CardType;
|
||||
import forge.game.*;
|
||||
@@ -26,7 +25,9 @@ import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
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 {
|
||||
|
||||
@@ -1084,8 +1085,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);
|
||||
final String totalcmc = sa.getParam("WithTotalCMC");
|
||||
final String totalpower = sa.getParam("WithTotalPower");
|
||||
final String totalCardTypes = sa.getParam("WithTotalCardTypes");
|
||||
int totcmc = AbilityUtils.calculateAmount(source, totalcmc, sa);
|
||||
int totpower = AbilityUtils.calculateAmount(source, totalpower, sa);
|
||||
int totCardTypes = AbilityUtils.calculateAmount(source, totalCardTypes, sa);
|
||||
|
||||
CardCollection chosenCards = new CardCollection();
|
||||
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.
|
||||
boolean shouldReveal = (i == 0);
|
||||
Card c = null;
|
||||
@@ -1170,6 +1174,10 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
c = Aggregates.random(fetchList);
|
||||
} else if (defined && !chooseFromDef) {
|
||||
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 {
|
||||
String title = selectPrompt;
|
||||
if (changeNum > 1) { //indicate progress if multiple cards being chosen
|
||||
@@ -1202,6 +1210,13 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
if (totalpower != null) {
|
||||
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("Defined") || sa.hasParam("ChooseFromDefined"))
|
||||
&& !sa.hasParam("WithTotalCMC")
|
||||
&& !sa.hasParam("WithTotalPower");
|
||||
&& !sa.hasParam("WithTotalPower")
|
||||
&& !sa.hasParam("WithTotalCardTypes");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -101,8 +101,7 @@ public class CountersMoveEffect extends SpellAbilityEffect {
|
||||
// uses for multi sources -> one defined/target
|
||||
// this needs given counter type
|
||||
if (sa.hasParam("ValidSource")) {
|
||||
CardCollectionView srcCards = game.getCardsIn(ZoneType.Battlefield);
|
||||
srcCards = CardLists.getValidCards(srcCards, sa.getParam("ValidSource"), activator, host, sa);
|
||||
CardCollectionView srcCards = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), sa.getParam("ValidSource"), activator, host, sa);
|
||||
List<Card> tgtCards = getDefinedCardsOrTargeted(sa);
|
||||
|
||||
if (tgtCards.isEmpty()) {
|
||||
@@ -147,11 +146,6 @@ public class CountersMoveEffect extends SpellAbilityEffect {
|
||||
Map<CounterType, Integer> countersToAdd = Maps.newHashMap();
|
||||
|
||||
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)) {
|
||||
final Map<CounterType, Integer> tgtCounters = Maps.newHashMap(src.getCounters());
|
||||
for (Map.Entry<CounterType, Integer> e : tgtCounters.entrySet()) {
|
||||
@@ -183,8 +177,7 @@ public class CountersMoveEffect extends SpellAbilityEffect {
|
||||
params.put("CounterType", cType);
|
||||
params.put("Source", source);
|
||||
|
||||
CardCollectionView tgtCards = game.getCardsIn(ZoneType.Battlefield);
|
||||
tgtCards = CardLists.getValidCards(tgtCards, sa.getParam("ValidDefined"), activator, host, sa);
|
||||
CardCollectionView tgtCards = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), sa.getParam("ValidDefined"), activator, host, sa);
|
||||
|
||||
if (counterNum.equals("Any")) {
|
||||
tgtCards = activator.getController().chooseCardsForEffect(
|
||||
@@ -203,6 +196,9 @@ public class CountersMoveEffect extends SpellAbilityEffect {
|
||||
if (!dest.canReceiveCounters(cType)) {
|
||||
continue;
|
||||
}
|
||||
if (!source.canRemoveCounters(cType)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Card cur = game.getCardState(dest, null);
|
||||
if (cur == null || !cur.equalsWithGameTimestamp(dest)) {
|
||||
@@ -287,7 +283,7 @@ public class CountersMoveEffect extends SpellAbilityEffect {
|
||||
final List<CounterType> typeChoices = Lists.newArrayList();
|
||||
// get types of counters
|
||||
for (CounterType ct : tgtCounters.keySet()) {
|
||||
if (dest.canReceiveCounters(ct)) {
|
||||
if (dest.canReceiveCounters(ct) && source.canRemoveCounters(cType)) {
|
||||
typeChoices.add(ct);
|
||||
}
|
||||
}
|
||||
@@ -337,6 +333,9 @@ public class CountersMoveEffect extends SpellAbilityEffect {
|
||||
if (!dest.canReceiveCounters(cType)) {
|
||||
return;
|
||||
}
|
||||
if (!src.canRemoveCounters(cType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int cmax = src.getCounters(cType);
|
||||
if (cmax <= 0) {
|
||||
|
||||
@@ -127,7 +127,18 @@ public class CountersPutOrRemoveEffect extends SpellAbilityEffect {
|
||||
|
||||
putCounter = !Expressions.compare(value, operator, operandValue);
|
||||
} 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) {
|
||||
|
||||
@@ -63,8 +63,7 @@ public class CountersRemoveAllEffect extends SpellAbilityEffect {
|
||||
for (final Card tgtCard : cards) {
|
||||
if (sa.hasParam("AllCounterTypes")) {
|
||||
for (Map.Entry<CounterType, Integer> e : Lists.newArrayList(tgtCard.getCounters().entrySet())) {
|
||||
numberRemoved += e.getValue();
|
||||
tgtCard.subtractCounter(e.getKey(), e.getValue(), sa.getActivatingPlayer());
|
||||
numberRemoved += tgtCard.subtractCounter(e.getKey(), e.getValue(), sa.getActivatingPlayer());
|
||||
}
|
||||
//tgtCard.getCounters().clear();
|
||||
continue;
|
||||
@@ -74,7 +73,7 @@ public class CountersRemoveAllEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
if (counterAmount > 0) {
|
||||
tgtCard.subtractCounter(CounterType.getType(type), counterAmount, sa.getActivatingPlayer());
|
||||
numberRemoved += tgtCard.subtractCounter(CounterType.getType(type), counterAmount, sa.getActivatingPlayer());
|
||||
game.updateLastStateForCard(tgtCard);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,8 +109,7 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
|
||||
// Removing energy
|
||||
if (type.equals("All")) {
|
||||
for (Map.Entry<CounterType, Integer> e : Lists.newArrayList(tgtPlayer.getCounters().entrySet())) {
|
||||
tgtPlayer.subtractCounter(e.getKey(), e.getValue(), activator);
|
||||
totalRemoved += e.getValue();
|
||||
totalRemoved += tgtPlayer.subtractCounter(e.getKey(), e.getValue(), activator);
|
||||
}
|
||||
} else {
|
||||
if (num.equals("All")) {
|
||||
@@ -119,8 +118,7 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
|
||||
if (type.equals("Any")) {
|
||||
totalRemoved += removeAnyType(tgtPlayer, cntToRemove, sa);
|
||||
} else {
|
||||
tgtPlayer.subtractCounter(counterType, cntToRemove, activator);
|
||||
totalRemoved += cntToRemove;
|
||||
totalRemoved += tgtPlayer.subtractCounter(counterType, cntToRemove, activator);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,11 +162,11 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
|
||||
if (gameCard == null || !tgtCard.equalsWithGameTimestamp(gameCard)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Zone zone = game.getZoneOf(gameCard);
|
||||
if (type.equals("All")) {
|
||||
for (Map.Entry<CounterType, Integer> e : Lists.newArrayList(gameCard.getCounters().entrySet())) {
|
||||
gameCard.subtractCounter(e.getKey(), e.getValue(), activator);
|
||||
totalRemoved += e.getValue();
|
||||
totalRemoved += gameCard.subtractCounter(e.getKey(), e.getValue(), activator);
|
||||
}
|
||||
game.updateLastStateForCard(gameCard);
|
||||
continue;
|
||||
@@ -179,6 +177,9 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
|
||||
if (type.equals("Any")) {
|
||||
totalRemoved += removeAnyType(gameCard, cntToRemove, sa);
|
||||
} else {
|
||||
if (!tgtCard.canRemoveCounters(counterType)) {
|
||||
continue;
|
||||
}
|
||||
cntToRemove = Math.min(cntToRemove, gameCard.getCounters(counterType));
|
||||
|
||||
if (zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Exile)) {
|
||||
@@ -220,14 +221,18 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
|
||||
final Player activator = sa.getActivatingPlayer();
|
||||
final PlayerController pc = activator.getController();
|
||||
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()) {
|
||||
Map<String, Object> params = Maps.newHashMap();
|
||||
params.put("Target", entity);
|
||||
|
||||
String prompt = Localizer.getInstance().getMessage("lblSelectCountersTypeToRemove");
|
||||
CounterType chosenType = pc.chooseCounterType(
|
||||
ImmutableList.copyOf(tgtCounters.keySet()), sa, prompt, params);
|
||||
CounterType chosenType = pc.chooseCounterType(ImmutableList.copyOf(tgtCounters.keySet()), sa, prompt, params);
|
||||
|
||||
int max = Math.min(cntToRemove, tgtCounters.get(chosenType));
|
||||
// remove selection so player can't cheat additional trigger by choosing the same type multiple times
|
||||
|
||||
@@ -55,11 +55,14 @@ public class ManaEffect extends SpellAbilityEffect {
|
||||
|
||||
if (abMana.isComboMana()) {
|
||||
int amount = sa.hasParam("Amount") ? AbilityUtils.calculateAmount(card, sa.getParam("Amount"), sa) : 1;
|
||||
if(amount <= 0)
|
||||
continue;
|
||||
|
||||
String express = abMana.getExpressChoice();
|
||||
String[] colorsProduced = abMana.getComboColors(sa).split(" ");
|
||||
|
||||
final StringBuilder choiceString = new StringBuilder();
|
||||
final StringBuilder choiceSymbols = new StringBuilder();
|
||||
ColorSet colorOptions = ColorSet.fromNames(colorsProduced);
|
||||
String[] colorsNeeded = express.isEmpty() ? null : express.split(" ");
|
||||
boolean differentChoice = abMana.getOrigProduced().contains("Different");
|
||||
@@ -70,12 +73,14 @@ public class ManaEffect extends SpellAbilityEffect {
|
||||
for (Map.Entry<Byte, Integer> e : choices.entrySet()) {
|
||||
Byte chosenColor = e.getKey();
|
||||
String choice = MagicColor.toShortString(chosenColor);
|
||||
String symbol = MagicColor.toSymbol(chosenColor);
|
||||
Integer count = e.getValue();
|
||||
while (count > 0) {
|
||||
if (choiceString.length() > 0) {
|
||||
choiceString.append(" ");
|
||||
}
|
||||
choiceString.append(choice);
|
||||
choiceSymbols.append(symbol);
|
||||
--count;
|
||||
}
|
||||
}
|
||||
@@ -106,25 +111,26 @@ public class ManaEffect extends SpellAbilityEffect {
|
||||
choiceString.append(" ");
|
||||
}
|
||||
choiceString.append(choice);
|
||||
choiceSymbols.append(MagicColor.toSymbol(choice));
|
||||
if (sa.hasParam("TwoEach")) {
|
||||
choiceString.append(" ").append(choice);
|
||||
choiceSymbols.append(MagicColor.toSymbol(choice));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (choiceString.toString().isEmpty() && "Combo ColorIdentity".equals(abMana.getOrigProduced())) {
|
||||
// No mana could be produced here (non-EDH match?), so cut short
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
game.getAction().notifyOfValue(sa, card, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), choiceString), p);
|
||||
game.getAction().notifyOfValue(sa, p, choiceSymbols.toString(), p);
|
||||
abMana.setExpressChoice(choiceString.toString());
|
||||
}
|
||||
else if (abMana.isAnyMana()) {
|
||||
// AI color choice is set in ComputerUtils so only human players need to make a choice
|
||||
|
||||
String colorsNeeded = abMana.getExpressChoice();
|
||||
String choice = "";
|
||||
|
||||
ColorSet colorMenu = null;
|
||||
byte mask = 0;
|
||||
@@ -137,10 +143,9 @@ public class ManaEffect extends SpellAbilityEffect {
|
||||
if (0 == val) {
|
||||
throw new RuntimeException("ManaEffect::resolve() /*any mana*/ - " + p + " color mana choice is empty for " + card.getName());
|
||||
}
|
||||
choice = MagicColor.toShortString(val);
|
||||
|
||||
game.getAction().notifyOfValue(sa, card, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), choice), p);
|
||||
abMana.setExpressChoice(choice);
|
||||
game.getAction().notifyOfValue(sa, card, MagicColor.toSymbol(val), p);
|
||||
abMana.setExpressChoice(MagicColor.toShortString(val));
|
||||
}
|
||||
else if (abMana.isSpecialMana()) {
|
||||
String type = abMana.getOrigProduced().split("Special ")[1];
|
||||
@@ -183,7 +188,7 @@ public class ManaEffect extends SpellAbilityEffect {
|
||||
int nMana = 0;
|
||||
for (Object o : card.getRemembered()) {
|
||||
if (o instanceof String) {
|
||||
sb.append(o.toString());
|
||||
sb.append(o);
|
||||
nMana++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,15 +21,6 @@ public class VillainousChoiceEffect extends SpellAbilityEffect {
|
||||
for (Player p : getDefinedPlayersOrTargeted(sa)) {
|
||||
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
|
||||
List<SpellAbility> chosenSAs = Lists.newArrayList();
|
||||
for(int i = 0; i < choiceAmount; i++) {
|
||||
|
||||
@@ -803,6 +803,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
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() {
|
||||
turnFaceUp(false, null);
|
||||
}
|
||||
@@ -811,14 +816,10 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
return turnFaceUp(true, cause);
|
||||
}
|
||||
public boolean turnFaceUp(boolean runTriggers, SpellAbility cause) {
|
||||
if (!isFaceDown()) {
|
||||
if (!isFaceDown() || !canBeTurnedFaceUp()) {
|
||||
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);
|
||||
boolean retResult = false;
|
||||
long ts = game.getNextTimestamp();
|
||||
@@ -853,10 +854,9 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
triggerHandler.registerActiveTrigger(this, false);
|
||||
}
|
||||
if (runTriggers) {
|
||||
// Run replacement effects
|
||||
Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
|
||||
game.getReplacementHandler().run(ReplacementType.TurnFaceUp, repParams);
|
||||
|
||||
// Run triggers
|
||||
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(this);
|
||||
runParams.put(AbilityKey.Cause, cause);
|
||||
|
||||
@@ -1598,6 +1598,21 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
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
|
||||
public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params) {
|
||||
int addAmount = n;
|
||||
@@ -1734,11 +1749,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void subtractCounter(final CounterType counterName, final int n, final Player remover) {
|
||||
subtractCounter(counterName, n, remover, false);
|
||||
public final int subtractCounter(final CounterType counterName, final int n, final Player remover) {
|
||||
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 newValue = Math.max(oldValue - n, 0);
|
||||
|
||||
@@ -1756,12 +1771,14 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
newValue = 0;
|
||||
}
|
||||
break;
|
||||
case Replaced:
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
final int delta = oldValue - newValue;
|
||||
if (delta == 0) { return; }
|
||||
if (delta == 0) { return 0; }
|
||||
|
||||
int powerBonusBefore = getPowerBonusFromCounters();
|
||||
int toughnessBonusBefore = getToughnessBonusFromCounters();
|
||||
@@ -1798,6 +1815,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
runParams.put(AbilityKey.CounterAmount, delta);
|
||||
runParams.put(AbilityKey.NewCounterAmount, newValue);
|
||||
getGame().getTriggerHandler().runTrigger(TriggerType.CounterRemovedOnce, runParams, false);
|
||||
|
||||
return delta;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -6085,6 +6104,13 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
return getType().sharesCardTypeWith(c1.getType());
|
||||
}
|
||||
|
||||
public final boolean sharesAllCardTypesWith(final Card c1) {
|
||||
if (c1 == null) {
|
||||
return false;
|
||||
}
|
||||
return getType().sharesAllCardTypesWith(c1.getType());
|
||||
}
|
||||
|
||||
public final boolean sharesControllerWith(final Card c1) {
|
||||
return c1 != null && getController().equals(c1.getController());
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ public class CardCopyService {
|
||||
c.setSetCode(in.getSetCode());
|
||||
|
||||
for (final CardStateName state : in.getStates()) {
|
||||
copyState(in, state, c, state);
|
||||
copyState(in, state, c, state, false);
|
||||
}
|
||||
|
||||
c.setState(in.getCurrentStateName(), false);
|
||||
|
||||
@@ -116,6 +116,10 @@ public final class CardPredicates {
|
||||
return c -> c.sharesCardTypeWith(card);
|
||||
}
|
||||
|
||||
public static Predicate<Card> sharesAllCardTypesWith(final Card card) {
|
||||
return c -> c.sharesAllCardTypesWith(card);
|
||||
}
|
||||
|
||||
public static Predicate<Card> sharesCreatureTypeWith(final Card card) {
|
||||
return c -> c.sharesCreatureTypeWith(card);
|
||||
}
|
||||
|
||||
@@ -35,10 +35,7 @@ import forge.util.collect.FCollectionView;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
public class CardProperty {
|
||||
|
||||
@@ -847,6 +844,11 @@ public class CardProperty {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (property.startsWith("sharesAllCardTypesWithOther")) {
|
||||
final String restriction = property.split("sharesAllCardTypesWithOther ")[1];
|
||||
CardCollection list = AbilityUtils.getDefinedCards(source, restriction, spellAbility);
|
||||
list.remove(card);
|
||||
return Iterables.any(list, CardPredicates.sharesAllCardTypesWith(card));
|
||||
} else if (property.startsWith("sharesLandTypeWith")) {
|
||||
final String restriction = property.split("sharesLandTypeWith ")[1];
|
||||
if (!AbilityUtils.getDefinedCards(source, restriction, spellAbility).anyMatch(CardPredicates.sharesLandTypeWith(card))) {
|
||||
@@ -1504,7 +1506,7 @@ public class CardProperty {
|
||||
}
|
||||
} else if (property.startsWith("power") || property.startsWith("toughness") || property.startsWith("cmc")
|
||||
|| property.startsWith("totalPT") || property.startsWith("numColors")
|
||||
|| property.startsWith("basePower") || property.startsWith("baseToughness")) {
|
||||
|| property.startsWith("basePower") || property.startsWith("baseToughness") || property.startsWith("numTypes")) {
|
||||
int x;
|
||||
int y = 0;
|
||||
String rhs = "";
|
||||
@@ -1530,6 +1532,9 @@ public class CardProperty {
|
||||
} else if (property.startsWith("numColors")) {
|
||||
rhs = property.substring(11);
|
||||
y = card.getColor().countColors();
|
||||
} else if (property.startsWith("numTypes")) {
|
||||
rhs = property.substring(10);
|
||||
y = Iterables.size(card.getType().getCoreTypes());
|
||||
}
|
||||
x = AbilityUtils.calculateAmount(source, rhs, spellAbility);
|
||||
|
||||
@@ -1920,6 +1925,18 @@ public class CardProperty {
|
||||
if (!card.isGoaded()) {
|
||||
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")) {
|
||||
if (!card.hasNoAbilities()) {
|
||||
return false;
|
||||
|
||||
@@ -69,10 +69,16 @@ public class CostRemoveAnyCounter extends CostPart {
|
||||
int allCounters = 0;
|
||||
for (Card c : validCards) {
|
||||
if (this.counter != null) {
|
||||
if (!c.canRemoveCounters(this.counter)) {
|
||||
continue;
|
||||
}
|
||||
allCounters += c.getCounters(this.counter);
|
||||
} else {
|
||||
for (Integer value : c.getCounters().values()) {
|
||||
allCounters += value;
|
||||
for (Map.Entry<CounterType, Integer> entry : c.getCounters().entrySet()) {
|
||||
if (!c.canRemoveCounters(entry.getKey())) {
|
||||
continue;
|
||||
}
|
||||
allCounters += entry.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ import com.google.common.collect.Maps;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CounterEnumType;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.trigger.TriggerType;
|
||||
@@ -78,7 +80,8 @@ public class CostUntap extends CostPart {
|
||||
@Override
|
||||
public final boolean canPay(final SpellAbility ability, final Player payer, final boolean effect) {
|
||||
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
|
||||
|
||||
@@ -86,7 +86,7 @@ public class CostUntapType extends CostPartWithList {
|
||||
if (!canUntapSource) {
|
||||
typeList.remove(source);
|
||||
}
|
||||
typeList = CardLists.filter(typeList, CardPredicates.TAPPED);
|
||||
typeList = CardLists.filter(typeList, CardPredicates.TAPPED, c -> c.getCounters(CounterEnumType.STUN) == 0 || c.canRemoveCounters(CounterType.get(CounterEnumType.STUN)));
|
||||
|
||||
final int amount = this.getAbilityAmount(ability);
|
||||
return (typeList.size() != 0) && (typeList.size() >= amount);
|
||||
|
||||
@@ -1050,6 +1050,7 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
for (SpellAbility sa : chosenSa) {
|
||||
Card saHost = sa.getHostCard();
|
||||
final Zone originZone = saHost.getZone();
|
||||
final CardZoneTable triggerList = new CardZoneTable(game.getLastStateBattlefield(), game.getLastStateGraveyard());
|
||||
|
||||
if (pPlayerPriority.getController().playChosenSpellAbility(sa)) {
|
||||
// 117.3c If a player has priority when they cast a spell, activate an ability, [play a land]
|
||||
@@ -1065,7 +1066,6 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
// Need to check if Zone did change
|
||||
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
|
||||
final CardZoneTable triggerList = new CardZoneTable(game.getLastStateBattlefield(), game.getLastStateGraveyard());
|
||||
triggerList.put(originZone.getZoneType(), currentZone.getZoneType(), saHost);
|
||||
triggerList.triggerChangesZoneAll(game, sa);
|
||||
}
|
||||
|
||||
@@ -103,6 +103,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
private int numPowerSurgeLands;
|
||||
private int numLibrarySearchedOwn; //The number of times this player has searched his library
|
||||
private int numDrawnThisTurn;
|
||||
private int numDrawnLastTurn;
|
||||
private int numDrawnThisDrawStep;
|
||||
private int numRollsThisTurn;
|
||||
private int numExploredThisTurn;
|
||||
@@ -852,6 +853,14 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
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
|
||||
public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params) {
|
||||
int addAmount = n;
|
||||
@@ -893,12 +902,12 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
}
|
||||
|
||||
@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 newValue = Math.max(oldValue - num, 0);
|
||||
|
||||
final int delta = oldValue - newValue;
|
||||
if (delta == 0) { return; }
|
||||
if (delta == 0) { return 0; }
|
||||
|
||||
setCounters(counterName, newValue, null, true);
|
||||
|
||||
@@ -914,6 +923,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
getGame().getTriggerHandler().runTrigger(TriggerType.CounterRemoved, runParams, false);
|
||||
}
|
||||
*/
|
||||
return delta;
|
||||
}
|
||||
|
||||
public final void clearCounters() {
|
||||
@@ -1442,6 +1452,10 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
return numDrawnThisTurn;
|
||||
}
|
||||
|
||||
public final int getNumDrawnLastTurn() {
|
||||
return numDrawnLastTurn;
|
||||
}
|
||||
|
||||
public final int numDrawnThisDrawStep() {
|
||||
return numDrawnThisDrawStep;
|
||||
}
|
||||
@@ -2253,6 +2267,9 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public final void setLandsPlayedLastTurn(int num) {
|
||||
landsPlayedLastTurn = num;
|
||||
}
|
||||
public final void setNumDrawnLastTurn(int num) {
|
||||
numDrawnLastTurn= num;
|
||||
}
|
||||
|
||||
public final int getInvestigateNumThisTurn() {
|
||||
return investigatedThisTurn;
|
||||
@@ -2472,6 +2489,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
for (final PlayerZone pz : zones.values()) {
|
||||
pz.resetCardsAddedThisTurn();
|
||||
}
|
||||
setNumDrawnLastTurn(getNumDrawnThisTurn());
|
||||
resetNumDrawnThisTurn();
|
||||
resetNumRollsThisTurn();
|
||||
resetNumExploredThisTurn();
|
||||
|
||||
@@ -18,12 +18,8 @@
|
||||
package forge.game.spellability;
|
||||
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.cost.Cost;
|
||||
import forge.game.replacement.ReplacementType;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -58,9 +54,8 @@ public abstract class AbilityStatic extends Ability implements Cloneable {
|
||||
|
||||
// Check if ability can't be attempted because of replacement effect
|
||||
// Initial usage is Karlov Watchdog preventing disguise/morph/cloak/manifest turning face up
|
||||
if (this.isTurnFaceUp()) {
|
||||
Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(c);
|
||||
if (c.getGame().getReplacementHandler().cantHappenCheck(ReplacementType.TurnFaceUp, repParams)) return false;
|
||||
if (this.isTurnFaceUp() && !c.canBeTurnedFaceUp()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.getRestrictions().canPlay(c, this);
|
||||
|
||||
@@ -41,6 +41,7 @@ public class MessageUtil {
|
||||
case Seek:
|
||||
return value;
|
||||
case ChooseColor:
|
||||
case Mana:
|
||||
return sa.hasParam("Random")
|
||||
? Localizer.getInstance().getMessage("lblRandomColorChosen", value)
|
||||
: Localizer.getInstance().getMessage("lblPlayerPickedChosen", choser, value);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="forge.app"
|
||||
android:versionCode="106650000"
|
||||
android:versionName="1.6.65" > <!-- versionName should be updated and it's used for Sentry releases tag -->
|
||||
android:versionCode="106660000"
|
||||
android:versionName="1.6.66" > <!-- versionName should be updated and it's used for Sentry releases tag -->
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="26"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<packaging.type>jar</packaging.type>
|
||||
<build.min.memory>-Xms1024m</build.min.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.alias>alias</sign.alias>
|
||||
<sign.storepass>storepass</sign.storepass>
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.65-SNAPSHOT</version>
|
||||
<version>1.6.66-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-gui-android</artifactId>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.65-SNAPSHOT</version>
|
||||
<version>1.6.66-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-gui-desktop</artifactId>
|
||||
@@ -118,7 +118,7 @@
|
||||
</goals>
|
||||
<configuration>
|
||||
<!-- 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>
|
||||
<templateContent>
|
||||
<![CDATA[
|
||||
|
||||
@@ -6,15 +6,15 @@ import java.awt.FontMetrics;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.*;
|
||||
import javax.swing.text.StyleConstants;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import forge.gui.FThreads;
|
||||
import forge.localinstance.skin.FSkinProp;
|
||||
import forge.toolbox.FSkin.SkinImage;
|
||||
import forge.util.Localizer;
|
||||
@@ -87,20 +87,25 @@ public class FOptionPane extends FDialog {
|
||||
if (FView.SINGLETON_INSTANCE.getSplash() != null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
final FOptionPane optionPane = new FOptionPane(message, title, icon, null, options, defaultOption);
|
||||
optionPane.setVisible(true);
|
||||
final int dialogResult = optionPane.result;
|
||||
optionPane.dispose();
|
||||
return dialogResult;
|
||||
return showOptionDialog(message, title, icon, null, options, defaultOption);
|
||||
}
|
||||
|
||||
public static int showOptionDialog(final String message, final String title, final SkinImage icon, final Component comp, final List<String> options, final int defaultOption) {
|
||||
final FOptionPane optionPane = new FOptionPane(message, title, icon, comp, options, defaultOption);
|
||||
optionPane.setVisible(true);
|
||||
final int dialogResult = optionPane.result;
|
||||
optionPane.dispose();
|
||||
return dialogResult;
|
||||
final Callable<Integer> showChoice = () -> {
|
||||
final FOptionPane optionPane = new FOptionPane(message, title, icon, comp, options, defaultOption);
|
||||
optionPane.setVisible(true);
|
||||
final int dialogResult = optionPane.result;
|
||||
optionPane.dispose();
|
||||
return dialogResult;
|
||||
};
|
||||
final FutureTask<Integer> future = new FutureTask<>(showChoice);
|
||||
FThreads.invokeInEdtAndWait(future);
|
||||
try {
|
||||
return future.get();
|
||||
} catch (final Exception e) { // should be no exception here
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String showInputDialog(final String message, final String title) {
|
||||
@@ -117,45 +122,56 @@ public class FOptionPane extends FDialog {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T showInputDialog(final String message, final String title, final SkinImage icon, final String initialInput, final List<T> inputOptions) {
|
||||
final JComponent inputField;
|
||||
FTextField txtInput = null;
|
||||
FComboBox<T> cbInput = null;
|
||||
if (inputOptions == null) {
|
||||
txtInput = new FTextField.Builder().text(initialInput).build();
|
||||
inputField = txtInput;
|
||||
} else {
|
||||
cbInput = new FComboBox<>(inputOptions);
|
||||
cbInput.setSelectedItem(initialInput);
|
||||
inputField = cbInput;
|
||||
}
|
||||
final Callable<T> showChoice = () -> {
|
||||
final JComponent inputField;
|
||||
FTextField txtInput = null;
|
||||
FComboBox<T> cbInput = null;
|
||||
if (inputOptions == null) {
|
||||
txtInput = new FTextField.Builder().text(initialInput).build();
|
||||
inputField = txtInput;
|
||||
} else {
|
||||
cbInput = new FComboBox<>(inputOptions);
|
||||
cbInput.setSelectedItem(initialInput);
|
||||
inputField = cbInput;
|
||||
}
|
||||
|
||||
final FOptionPane optionPane = new FOptionPane(message, title, icon, inputField, ImmutableList.of(Localizer.getInstance().getMessage("lblOK"), Localizer.getInstance().getMessage("lblCancel")), -1);
|
||||
optionPane.setDefaultFocus(inputField);
|
||||
inputField.addKeyListener(new KeyAdapter() { //hook so pressing Enter on field accepts dialog
|
||||
@Override
|
||||
public void keyPressed(final KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
|
||||
optionPane.setResult(0);
|
||||
final FOptionPane optionPane = new FOptionPane(message, title, icon, inputField, ImmutableList.of(Localizer.getInstance().getMessage("lblOK"), Localizer.getInstance().getMessage("lblCancel")), -1);
|
||||
optionPane.setDefaultFocus(inputField);
|
||||
inputField.addKeyListener(new KeyAdapter() { //hook so pressing Enter on field accepts dialog
|
||||
@Override
|
||||
public void keyPressed(final KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
|
||||
optionPane.setResult(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
optionPane.setVisible(true);
|
||||
final int dialogResult = optionPane.result;
|
||||
optionPane.dispose();
|
||||
if (dialogResult == 0) {
|
||||
if (inputOptions == null) {
|
||||
return (T)txtInput.getText();
|
||||
} else {
|
||||
return cbInput.getSelectedItem();
|
||||
}
|
||||
}
|
||||
});
|
||||
optionPane.setVisible(true);
|
||||
final int dialogResult = optionPane.result;
|
||||
optionPane.dispose();
|
||||
if (dialogResult == 0) {
|
||||
if (inputOptions == null) {
|
||||
return (T)txtInput.getText();
|
||||
} else {
|
||||
return cbInput.getSelectedItem();
|
||||
}
|
||||
return null;
|
||||
};
|
||||
final FutureTask<T> future = new FutureTask<>(showChoice);
|
||||
FThreads.invokeInEdtAndWait(future);
|
||||
try {
|
||||
return future.get();
|
||||
} catch (final Exception e) { // should be no exception here
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int result = -1; //default result to -1, indicating dialog closed without choosing option
|
||||
private final FButton[] buttons;
|
||||
|
||||
public FOptionPane(final String message, final String title, final SkinImage icon, final Component comp, final List<String> options, final int defaultOption) {
|
||||
FThreads.assertExecutedByEdt(true);
|
||||
this.setTitle(title);
|
||||
|
||||
final int padding = 10;
|
||||
@@ -163,7 +179,7 @@ public class FOptionPane extends FDialog {
|
||||
final int gapAboveButtons = padding * 3 / 2;
|
||||
final int gapBottom = comp == null ? gapAboveButtons : padding;
|
||||
FLabel centeredLabel = null;
|
||||
FTextPane centeredPrompt = null;
|
||||
FTextPane prompt = null;
|
||||
|
||||
if (icon != null) {
|
||||
if (icon.getWidth() < 100) {
|
||||
@@ -179,23 +195,16 @@ public class FOptionPane extends FDialog {
|
||||
}
|
||||
}
|
||||
if (message != null) {
|
||||
if (centeredLabel == null) {
|
||||
final FTextArea prompt = new FTextArea(message);
|
||||
prompt.setFont(FSkin.getFont(14));
|
||||
prompt.setAutoSize(true);
|
||||
final Dimension parentSize = JOptionPane.getRootFrame().getSize();
|
||||
prompt.setMaximumSize(new Dimension(parentSize.width / 2, parentSize.height - 100));
|
||||
this.add(prompt, "x " + x + ", ay top, wrap, gaptop " + (icon == null ? 0 : 7) + ", gapbottom " + gapBottom);
|
||||
}
|
||||
else {
|
||||
final FTextPane prompt = new FTextPane(message);
|
||||
prompt.setFont(FSkin.getFont(14));
|
||||
prompt = new FTextPane();
|
||||
prompt.setContentType("text/html");
|
||||
prompt.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);
|
||||
prompt.setText(FSkin.encodeSymbols(message, false));
|
||||
prompt.setFont(FSkin.getFont(14));
|
||||
if(centeredLabel != null)
|
||||
prompt.setTextAlignment(StyleConstants.ALIGN_CENTER);
|
||||
final Dimension parentSize = JOptionPane.getRootFrame().getSize();
|
||||
prompt.setMaximumSize(new Dimension(parentSize.width / 2, parentSize.height - 100));
|
||||
this.add(prompt, "x " + x + ", ay top, wrap, gapbottom " + gapBottom);
|
||||
centeredPrompt = prompt;
|
||||
}
|
||||
final Dimension parentSize = JOptionPane.getRootFrame().getSize();
|
||||
prompt.setMaximumSize(new Dimension(parentSize.width / 2, parentSize.height - 100));
|
||||
this.add(prompt, "x " + x + ", ay top, wrap, gaptop " + (icon == null ? 0 : 7) + ", gapbottom " + gapBottom);
|
||||
x = padding;
|
||||
}
|
||||
if (comp != null) {
|
||||
@@ -277,7 +286,8 @@ public class FOptionPane extends FDialog {
|
||||
|
||||
if (centeredLabel != null) {
|
||||
centeredLabel.setPreferredSize(new Dimension(width - 2 * padding, centeredLabel.getMinimumSize().height));
|
||||
centeredPrompt.setPreferredSize(new Dimension(width - 2 * padding, centeredPrompt.getPreferredSize().height));
|
||||
if(prompt != null)
|
||||
prompt.setPreferredSize(new Dimension(width - 2 * padding, prompt.getPreferredSize().height));
|
||||
}
|
||||
|
||||
this.setSize(width, this.getHeight() + buttonHeight); //resize dialog again to account for buttons
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.65-SNAPSHOT</version>
|
||||
<version>1.6.66-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-gui-ios</artifactId>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.65-SNAPSHOT</version>
|
||||
<version>1.6.66-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-gui-mobile-dev</artifactId>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.65-SNAPSHOT</version>
|
||||
<version>1.6.66-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-gui-mobile</artifactId>
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
package forge;
|
||||
|
||||
import com.badlogic.gdx.Application;
|
||||
import com.badlogic.gdx.ApplicationListener;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.*;
|
||||
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.ControllerAdapter;
|
||||
import com.badlogic.gdx.controllers.ControllerListener;
|
||||
@@ -54,7 +50,7 @@ import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
|
||||
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;
|
||||
static Scene currentScene = null;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.65-SNAPSHOT</version>
|
||||
<version>1.6.66-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-gui</artifactId>
|
||||
|
||||
@@ -133,4 +133,5 @@ Ravnica Remastered, 3/6/RAV, RVR
|
||||
Murders at Karlov Manor, 3/6/MKM, MKM
|
||||
Outlaws of Thunder Junction, 3/6/OTJ, OTJ
|
||||
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
|
||||
@@ -1,10 +1,10 @@
|
||||
Name:A Premonition of Your Demise
|
||||
ManaCost:no cost
|
||||
Types:Scheme
|
||||
T:Mode$ SetInMotion | ValidCard$ Card.Self | Execute$ DBDig | TriggerZones$ Command | TriggerDescription$ When you set this scheme in motion, reveal the top two cards of your library and put them into your hand. When you reveal one or more nonland cards this way, this scheme deals damage equal to their total mana value to any target.
|
||||
SVar:DBDig:DB$ Dig | DigNum$ 2 | Reveal$ True | ChangeNum$ All | ChangeValid$ Card | DestinationZone$ Hand | RememberChanged$ True | SubAbility$ DBImmediateTrigger
|
||||
SVar:DBImmediateTrigger:DB$ ImmediateTrigger | ConditionDefined$ Remembered | ConditionPresent$ Card.nonLand | Execute$ TrigDamage | SubAbility$ DBCleanup | SpellDescription$ When you reveal one or more nonland cards this way, this scheme deals damage equal to their total mana value to any target.
|
||||
SVar:TrigDamage:DB$ DealDamage | ValidTgts$ Any | NumDmg$ X
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:X:Count$ValidHand Card.IsRemembered+nonLand$SumCMC
|
||||
Oracle:When you set this scheme in motion, reveal the top two cards of your library and put them into your hand. When you reveal one or more nonland cards this way, this scheme deals damage equal to their total mana value to any target.
|
||||
Name:A Premonition of Your Demise
|
||||
ManaCost:no cost
|
||||
Types:Scheme
|
||||
T:Mode$ SetInMotion | ValidCard$ Card.Self | Execute$ DBDig | TriggerZones$ Command | TriggerDescription$ When you set this scheme in motion, reveal the top two cards of your library and put them into your hand. When you reveal one or more nonland cards this way, this scheme deals damage equal to their total mana value to any target.
|
||||
SVar:DBDig:DB$ Dig | DigNum$ 2 | Reveal$ True | ChangeNum$ All | ChangeValid$ Card | DestinationZone$ Hand | RememberChanged$ True | SubAbility$ DBImmediateTrigger
|
||||
SVar:DBImmediateTrigger:DB$ ImmediateTrigger | ConditionDefined$ Remembered | ConditionPresent$ Card.nonLand | Execute$ TrigDamage | SubAbility$ DBCleanup | SpellDescription$ When you reveal one or more nonland cards this way, this scheme deals damage equal to their total mana value to any target.
|
||||
SVar:TrigDamage:DB$ DealDamage | ValidTgts$ Any | NumDmg$ X
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:X:Count$ValidHand Card.IsRemembered+nonLand$SumCMC
|
||||
Oracle:When you set this scheme in motion, reveal the top two cards of your library and put them into your hand. When you reveal one or more nonland cards this way, this scheme deals damage equal to their total mana value to any target.
|
||||
@@ -1,8 +1,8 @@
|
||||
Name:Abandoned Campground
|
||||
ManaCost:no cost
|
||||
Types:Land
|
||||
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | ReplaceWith$ LandTapped | ReplacementResult$ Updated | Description$ CARDNAME enters tapped unless a player has 13 or less life.
|
||||
SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionCheckSVar$ X | ConditionSVarCompare$ GT13
|
||||
SVar:X:PlayerCountPlayers$LowestLifeTotal
|
||||
A:AB$ Mana | Cost$ T | Produced$ Combo W U | SpellDescription$ Add {W} or {U}.
|
||||
Oracle:Abandoned Campground enters tapped unless a player has 13 or less life.\n{T}: Add {W} or {U}.
|
||||
Name:Abandoned Campground
|
||||
ManaCost:no cost
|
||||
Types:Land
|
||||
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | ReplaceWith$ LandTapped | ReplacementResult$ Updated | Description$ CARDNAME enters tapped unless a player has 13 or less life.
|
||||
SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionCheckSVar$ X | ConditionSVarCompare$ GT13
|
||||
SVar:X:PlayerCountPlayers$LowestLifeTotal
|
||||
A:AB$ Mana | Cost$ T | Produced$ Combo W U | SpellDescription$ Add {W} or {U}.
|
||||
Oracle:Abandoned Campground enters tapped unless a player has 13 or less life.\n{T}: Add {W} or {U}.
|
||||
@@ -9,6 +9,6 @@ SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:X:Remembered$Amount
|
||||
SVar:MaxTgts:Count$Valid Permanent.Other+nonLand+YouCtrl
|
||||
K:Choose a Background
|
||||
DeckHas:Ability$Token & Type$Soldier
|
||||
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.)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
Name:Abhorrent Oculus
|
||||
ManaCost:2 U
|
||||
Types:Creature Eye
|
||||
PT:5/5
|
||||
A:SP$ PermanentCreature | Cost$ 2 U ExileFromGrave<6/Card>
|
||||
K:Flying
|
||||
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ Opponent | TriggerZones$ Battlefield | Execute$ TrigDread | TriggerDescription$ At the beginning of each opponent's upkeep, manifest dread. (Look at the top two cards of your library. Put one onto the battlefield face down as a 2/2 creature, and the other into your graveyard. Turn it face up any time for its mana cost if it's a creature card.)
|
||||
SVar:TrigDread:DB$ ManifestDread
|
||||
Oracle:As an additional cost to cast this spell, exile six cards from your graveyard.\nFlying\nAt the beginning of each opponent's upkeep, manifest dread. (Look at the top two cards of your library. Put one onto the battlefield face down as a 2/2 creature, and the other into your graveyard. Turn it face up any time for its mana cost if it's a creature card.)
|
||||
Name:Abhorrent Oculus
|
||||
ManaCost:2 U
|
||||
Types:Creature Eye
|
||||
PT:5/5
|
||||
A:SP$ PermanentCreature | Cost$ 2 U ExileFromGrave<6/Card>
|
||||
K:Flying
|
||||
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ Opponent | TriggerZones$ Battlefield | Execute$ TrigDread | TriggerDescription$ At the beginning of each opponent's upkeep, manifest dread. (Look at the top two cards of your library. Put one onto the battlefield face down as a 2/2 creature, and the other into your graveyard. Turn it face up any time for its mana cost if it's a creature card.)
|
||||
SVar:TrigDread:DB$ ManifestDread
|
||||
Oracle:As an additional cost to cast this spell, exile six cards from your graveyard.\nFlying\nAt the beginning of each opponent's upkeep, manifest dread. (Look at the top two cards of your library. Put one onto the battlefield face down as a 2/2 creature, and the other into your graveyard. Turn it face up any time for its mana cost if it's a creature card.)
|
||||
@@ -4,6 +4,6 @@ Types:Instant
|
||||
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}.
|
||||
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
|
||||
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.)
|
||||
|
||||
@@ -5,6 +5,6 @@ PT:3/2
|
||||
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.
|
||||
SVar:PlayMain1:TRUE
|
||||
DeckHints: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.
|
||||
|
||||
@@ -5,6 +5,6 @@ PT:2/3
|
||||
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.
|
||||
SVar:PlayMain1:TRUE
|
||||
DeckHints: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.
|
||||
|
||||
@@ -3,6 +3,6 @@ ManaCost:1 G
|
||||
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."
|
||||
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
|
||||
DeckNeeds:Type$Dragon
|
||||
Oracle:Commander creatures you own have "The first Dragon spell you cast each turn costs {2} less to cast."
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Name:Acrobatic Cheerleader
|
||||
ManaCost:1 W
|
||||
Types:Creature Human Survivor
|
||||
PT:2/2
|
||||
T:Mode$ Phase | Phase$ Main | PhaseCount$ 2 | ValidPlayer$ You | PresentDefined$ Self | IsPresent$ Card.tapped | TriggerZones$ Battlefield | Execute$ TrigPutCounter | GameActivationLimit$ 1 | TriggerDescription$ Survival — At the beginning of your second main phase, if CARDNAME is tapped, put a flying counter on it. This ability triggers only once.
|
||||
SVar:TrigPutCounter:DB$ PutCounter | CounterType$ Flying | CounterNum$ 1
|
||||
Oracle:Survival — At the beginning of your second main phase, if Acrobatic Cheerleader is tapped, put a flying counter on it. This ability triggers only once.
|
||||
Name:Acrobatic Cheerleader
|
||||
ManaCost:1 W
|
||||
Types:Creature Human Survivor
|
||||
PT:2/2
|
||||
T:Mode$ Phase | Phase$ Main | PhaseCount$ 2 | ValidPlayer$ You | PresentDefined$ Self | IsPresent$ Card.tapped | TriggerZones$ Battlefield | Execute$ TrigPutCounter | GameActivationLimit$ 1 | TriggerDescription$ Survival — At the beginning of your second main phase, if CARDNAME is tapped, put a flying counter on it. This ability triggers only once.
|
||||
SVar:TrigPutCounter:DB$ PutCounter | CounterType$ Flying | CounterNum$ 1
|
||||
Oracle:Survival — At the beginning of your second main phase, if Acrobatic Cheerleader is tapped, put a flying counter on it. This ability triggers only once.
|
||||
@@ -4,6 +4,6 @@ Types:Creature Human Soldier
|
||||
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.
|
||||
SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
|
||||
DeckNeeds:Type$Basri
|
||||
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.
|
||||
|
||||
@@ -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.
|
||||
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}."
|
||||
DeckHints:Type$Eldrazi
|
||||
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}."
|
||||
|
||||
@@ -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:X:Count$Valid Creature.YouCtrl
|
||||
SVar:Y:PlayerCountOther$HighestValid Creature.YouCtrl
|
||||
DeckNeeds:Color$Blue
|
||||
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.
|
||||
|
||||
@@ -5,6 +5,6 @@ PT:3/4
|
||||
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.
|
||||
SVar:TrigPut:DB$ PutCounter | ValidTgts$ Soldier.Other+YouCtrl | TgtPrompt$ Select another target Soldier you control | CounterType$ P1P1
|
||||
DeckHints:Type$Soldier
|
||||
DeckHas:Ability$Counters
|
||||
DeckHints:Type$Soldier
|
||||
Oracle:Flying\nWhen Aeronaut Cavalry enters, put a +1/+1 counter on another target Soldier you control.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Name:Aether Searcher
|
||||
ManaCost:7
|
||||
PT:6/4
|
||||
Types:Artifact Creature Construct
|
||||
PT:6/4
|
||||
Draft:Reveal CARDNAME as you draft it.
|
||||
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.
|
||||
|
||||
@@ -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.)
|
||||
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
|
||||
DeckHints:Type$Artifact|Enchantment & Ability$Token
|
||||
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.)
|
||||
|
||||
@@ -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."
|
||||
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
|
||||
DeckHints:Type$Artifact & Ability$Sacrifice
|
||||
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."
|
||||
|
||||
@@ -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:TrigPutCounter:DB$ PutCounter | CounterType$ P1P1 | CounterNum$ 1 | Defined$ Self | SubAbility$ DBPump
|
||||
SVar:DBPump:DB$ Pump | Defined$ Self | KW$ Deathtouch & Indestructible
|
||||
DeckHas:Ability$Counters
|
||||
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."
|
||||
|
||||
@@ -5,6 +5,6 @@ PT:2/1
|
||||
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.
|
||||
SVar:PlayMain1:TRUE
|
||||
DeckHints: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.
|
||||
|
||||
@@ -21,10 +21,11 @@ Types:Legendary Planeswalker Ajani
|
||||
Loyalty:3
|
||||
A:AB$ PutCounterAll | Cost$ AddCounter<2/LOYALTY> | ValidCards$ Cat.YouCtrl | CounterType$ P1P1 | CounterNum$ 1 | Planeswalker$ True | SpellDescription$ Put a +1/+1 counter on each Cat you control.
|
||||
A:AB$ Token | Cost$ AddCounter<0/LOYALTY> | TokenAmount$ 1 | TokenScript$ w_2_1_cat_warrior | TokenOwner$ You | RememberOriginalTokens$ True | SubAbility$ DBImmediateTrig1 | Planeswalker$ True | SpellDescription$ Create a 2/1 white Cat Warrior creature token. When you do, if you control a red permanent other than CARDNAME, he deals damage equal to the number of creatures you control to any target.
|
||||
SVar:DBImmediateTrig1:DB$ ImmediateTrigger | TriggerAmount$ Remembered$Amount | ConditionPresent$ Permanent.Red+YouCtrl+Other | Execute$ TrigDamage | TriggerDescription$ When you do, if you control a red permanent other than CARDNAME, he deals damage equal to the number of creatures you control to any target.
|
||||
SVar:TrigDamage:DB$ DealDamage | NumDmg$ X | ValidTgts$ Any | ConditionPresent$ Permanent.Red+YouCtrl+Other | SubAbility$ DBCleanup | TgtPrompt$ Select any valid target | SpellDescription$ CARDNAME deals damage equal to the number of creatures you control to any target.
|
||||
SVar:DBImmediateTrig1:DB$ ImmediateTrigger | TriggerAmount$ Remembered$Amount | ConditionPresent$ Permanent.Red+YouCtrl+Other | Execute$ TrigDamage | SubAbility$ DBCleanup2 | TriggerDescription$ When you do, if you control a red permanent other than CARDNAME, he deals damage equal to the number of creatures you control to any target.
|
||||
SVar:TrigDamage:DB$ DealDamage | NumDmg$ X | ValidTgts$ Any | ConditionPresent$ Permanent.Red+YouCtrl+Other | TgtPrompt$ Select any valid target | SpellDescription$ CARDNAME deals damage equal to the number of creatures you control to any target.
|
||||
SVar:X:Count$Valid Creature.YouCtrl
|
||||
A:AB$ ChooseCard | Cost$ SubCounter<4/LOYALTY> | Planeswalker$ True | Ultimate$ True | Defined$ Opponent | Choices$ Permanent.nonLand | ChooseEach$ Artifact & Creature & Enchantment & Planeswalker | ControlledByPlayer$ Chooser | Mandatory$ True | Reveal$ True | SubAbility$ SacAllOthers | StackDescription$ SpellDescription | SpellDescription$ Each opponent chooses an artifact, a creature, an enchantment, and a planeswalker from among the nonland permanents they control, then sacrifices the rest.
|
||||
SVar:SacAllOthers:DB$ SacrificeAll | ValidCards$ Permanent.nonLand+OppCtrl+nonChosenCard | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True
|
||||
SVar:DBCleanup2:DB$ Cleanup | ClearRemembered$ True
|
||||
Oracle:[+2]: Put a +1/+1 counter on each Cat you control.\n[0]: Create a 2/1 white Cat Warrior creature token. When you do, if you control a red permanent other than Ajani, Nacatl Avenger, he deals damage equal to the number of creatures you control to any target.\n[-4]: Each opponent chooses an artifact, a creature, an enchantment and a planeswalker from among the nonland permanents they control, then sacrifices the rest.
|
||||
|
||||
@@ -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.
|
||||
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.
|
||||
DeckHints:Name$Ajani, Valiant Protector
|
||||
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.
|
||||
|
||||
@@ -4,6 +4,6 @@ Types:Creature Cat Soldier
|
||||
PT:2/2
|
||||
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
|
||||
DeckHints:Ability$LifeGain
|
||||
DeckHas:Ability$Counters
|
||||
DeckHints:Ability$LifeGain
|
||||
Oracle:Whenever you gain life, put a +1/+1 counter on Ajani's Pridemate.
|
||||
|
||||
@@ -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.
|
||||
SVar:TrigDig:DB$ Dig | DigNum$ 2 | ChangeNum$ 1 | DestinationZone2$ Graveyard | NoReveal$ True
|
||||
SVar:X:Count$ThisTurnEntered_Battlefield_Artifact.YouCtrl
|
||||
DeckNeeds:Type$Artifact
|
||||
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.
|
||||
|
||||
@@ -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.
|
||||
SVar:TrigPump:DB$ PumpAll | ValidCards$ Card.Self,Drake.YouCtrl | NumAtt$ X | NumDef$ X
|
||||
SVar:X:Count$InYourHand
|
||||
AI:RemoveDeck:Random
|
||||
DeckHas:Ability$Token & 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.
|
||||
|
||||
@@ -7,9 +7,9 @@ K:Trample
|
||||
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.
|
||||
SVar:TrigPump:DB$ Pump | PumpZone$ Battlefield,Exile | NumAtt$ 1 | NumDef$ 1 | Duration$ Perpetual
|
||||
AlternateMode:Adventure
|
||||
DeckHas:Ability$Discard|Token & Type$Food
|
||||
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.
|
||||
|
||||
ALTERNATE
|
||||
|
||||
@@ -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.
|
||||
SVar:TrigPumpAll:AB$ PumpAll | Cost$ 8 | ValidCards$ Creature.YouCtrl | NumAtt$ X | NumDef$ X
|
||||
SVar:X:Count$Valid Permanent.YouCtrl+Historic
|
||||
SVar:HasAttackEffect:TRUE
|
||||
DeckHas:Ability$Token
|
||||
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.
|
||||
|
||||
@@ -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.
|
||||
SVar:DBGainLife:DB$ GainLife | LifeAmount$ X
|
||||
SVar:X:Count$xPaid
|
||||
DeckHints:Ability$Investigate
|
||||
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.
|
||||
|
||||
@@ -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.
|
||||
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
|
||||
DeckHints:Keyword$Foretell
|
||||
AI:RemoveDeck:All
|
||||
DeckHints:Keyword$Foretell
|
||||
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.
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
Name:Altanak, the Thrice-Called
|
||||
ManaCost:5 G G
|
||||
Types:Legendary Creature Insect Beast
|
||||
PT:9/9
|
||||
K:Trample
|
||||
T:Mode$ BecomesTarget | ValidTarget$ Card.Self | ValidSource$ SpellAbility.OppCtrl | TriggerZones$ Battlefield | Execute$ TrigDraw | TriggerDescription$ Whenever CARDNAME becomes the target of a spell or ability an opponent controls, draw a card.
|
||||
SVar:TrigDraw:DB$ Draw
|
||||
A:AB$ ChangeZone | Cost$ 1 G Discard<1/CARDNAME> | ActivationZone$ Hand | Origin$ Graveyard | Destination$ Battlefield| TgtPrompt$ Select target land card in your graveyard | ValidTgts$ Land.YouOwn | Tapped$ True | SpellDescription$ Return target land card from your graveyard to the battlefield tapped.
|
||||
Oracle:Trample\nWhenever Altanak, the Thrice-Called becomes the target of a spell or ability an opponent controls, draw a card.\n{1}{G}, Discard Altanak, the Thrice-Called: Return target land card from your graveyard to the battlefield tapped.
|
||||
Name:Altanak, the Thrice-Called
|
||||
ManaCost:5 G G
|
||||
Types:Legendary Creature Insect Beast
|
||||
PT:9/9
|
||||
K:Trample
|
||||
T:Mode$ BecomesTarget | ValidTarget$ Card.Self | ValidSource$ SpellAbility.OppCtrl | TriggerZones$ Battlefield | Execute$ TrigDraw | TriggerDescription$ Whenever CARDNAME becomes the target of a spell or ability an opponent controls, draw a card.
|
||||
SVar:TrigDraw:DB$ Draw
|
||||
A:AB$ ChangeZone | Cost$ 1 G Discard<1/CARDNAME> | ActivationZone$ Hand | Origin$ Graveyard | Destination$ Battlefield | TgtPrompt$ Select target land card in your graveyard | ValidTgts$ Land.YouOwn | Tapped$ True | SpellDescription$ Return target land card from your graveyard to the battlefield tapped.
|
||||
Oracle:Trample\nWhenever Altanak, the Thrice-Called becomes the target of a spell or ability an opponent controls, draw a card.\n{1}{G}, Discard Altanak, the Thrice-Called: Return target land card from your graveyard to the battlefield tapped.
|
||||
@@ -8,9 +8,9 @@ SVar:Y:Sacrificed$CardPower
|
||||
K:Craft:2 B B XMin1 ExileCtrlOrGrave<X/Creature.Other>
|
||||
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.
|
||||
DeckHints:Ability$Discard|Mill|Sacrifice
|
||||
DeckHas:Ability$Graveyard|Sacrifice|Mill
|
||||
AI:RemoveDeck:All
|
||||
DeckHas:Ability$Graveyard|Sacrifice|Mill
|
||||
DeckHints:Ability$Discard|Mill|Sacrifice
|
||||
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.
|
||||
|
||||
|
||||
@@ -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:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:X:TriggerObjectsCards$GreatestCMC
|
||||
DeckHints:Type$Insect & 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.
|
||||
|
||||
@@ -11,6 +11,6 @@ SVar:VolverPumped:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNu
|
||||
SVar:VolverResilience:DB$ Animate | Defined$ Self | Abilities$ ABRegen | Duration$ Permanent
|
||||
SVar:ABRegen:AB$ Regenerate | Cost$ PayLife<3> | SpellDescription$ Regenerate CARDNAME.
|
||||
AI:RemoveDeck:Random
|
||||
DeckNeeds:Color$Blue|Black
|
||||
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."
|
||||
|
||||
@@ -7,6 +7,6 @@ SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:X:Count$Compare Y LTZ.2.0
|
||||
SVar:Y:Remembered$CardManaCost
|
||||
SVar:Z:Sacrificed$CardManaCost
|
||||
DeckNeeds:Type$Artifact|Creature|Equipment|Vehicle
|
||||
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.
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
Name:Ancient Cellarspawn
|
||||
ManaCost:1 B B
|
||||
Types:Enchantment Creature Horror
|
||||
PT:3/3
|
||||
S:Mode$ ReduceCost | ValidCard$ Demon,Horror,Nightmare | Type$ Spell | Activator$ You | Amount$ 1 | Description$ Each spell you cast that's a Demon, Horror, or Nightmare costs {1} less to cast.
|
||||
T:Mode$ SpellCast | ValidCard$ Card | ValidActivatingPlayer$ You | Execute$ TrigLoseLife | TriggerZones$ Battlefield | ValidSAonCard$ Spell.ManaSpent LTX | TriggerDescription$ Whenever you cast a spell, if the amount of mana spent to cast it was less than its mana value, target opponent loses life equal to the difference.
|
||||
SVar:TrigLoseLife:DB$ LoseLife | ValidTgts$ Opponent | LifeAmount$ SVar$Y/Minus.Z
|
||||
SVar:X:Count$CardManaCost
|
||||
SVar:Y:TriggeredCard$CardManaCost
|
||||
SVar:Z:TriggeredCard$CastTotalManaSpent
|
||||
Oracle:Each spell you cast that's a Demon, Horror, or Nightmare costs {1} less to cast.\nWhenever you cast a spell, if the amount of mana spent to cast it was less than its mana value, target opponent loses life equal to the difference.
|
||||
Name:Ancient Cellarspawn
|
||||
ManaCost:1 B B
|
||||
Types:Enchantment Creature Horror
|
||||
PT:3/3
|
||||
S:Mode$ ReduceCost | ValidCard$ Demon,Horror,Nightmare | Type$ Spell | Activator$ You | Amount$ 1 | Description$ Each spell you cast that's a Demon, Horror, or Nightmare costs {1} less to cast.
|
||||
T:Mode$ SpellCast | ValidCard$ Card | ValidActivatingPlayer$ You | Execute$ TrigLoseLife | TriggerZones$ Battlefield | ValidSAonCard$ Spell.ManaSpent LTX | TriggerDescription$ Whenever you cast a spell, if the amount of mana spent to cast it was less than its mana value, target opponent loses life equal to the difference.
|
||||
SVar:TrigLoseLife:DB$ LoseLife | ValidTgts$ Opponent | LifeAmount$ SVar$Y/Minus.Z
|
||||
SVar:X:Count$CardManaCost
|
||||
SVar:Y:TriggeredCard$CardManaCost
|
||||
SVar:Z:TriggeredCard$CastTotalManaSpent
|
||||
Oracle:Each spell you cast that's a Demon, Horror, or Nightmare costs {1} less to cast.\nWhenever you cast a spell, if the amount of mana spent to cast it was less than its mana value, target opponent loses life equal to the difference.
|
||||
@@ -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.
|
||||
SVar:TrigChange:DB$ ChangeZone | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | Origin$ Battlefield | Destination$ Exile
|
||||
SVar:HasCombatEffect:TRUE
|
||||
DeckHints:Ability$Graveyard|Discard
|
||||
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.
|
||||
|
||||
@@ -7,6 +7,6 @@ K:Vigilance
|
||||
K:Lifelink
|
||||
K:Fabricate:2
|
||||
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
|
||||
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.
|
||||
|
||||
@@ -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:DBPump:DB$ Pump | Defined$ ChosenCard | PumpZone$ Hand | NumAtt$ 1 | NumDef$ 1 | Duration$ Perpetual | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True
|
||||
DeckHas:Ability$Party|LifeGain
|
||||
SVar:BuffedBy:Cleric,Rogue,Warrior,Wizard
|
||||
DeckHas:Ability$Party|LifeGain
|
||||
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.)
|
||||
|
||||
@@ -3,6 +3,6 @@ ManaCost:3 W
|
||||
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.
|
||||
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
|
||||
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.
|
||||
|
||||
@@ -5,6 +5,6 @@ PT:2/3
|
||||
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.
|
||||
SVar:TrigInvestigate:DB$ Investigate
|
||||
DeckHints:Ability$Counters
|
||||
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.
|
||||
|
||||
@@ -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:DBCopy:DB$ CopyPermanent | Defined$ Remembered | SetPower$ 3 | SetToughness$ 3 | AddTypes$ Creature & Zombie | SetColor$ Black | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
DeckHas:Ability$Token|Graveyard
|
||||
DeckNeeds:Type$Enchantment
|
||||
DeckHints:Ability$Graveyard|Mill
|
||||
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.
|
||||
|
||||
@@ -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.
|
||||
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.
|
||||
DeckHints:Ability$Counters
|
||||
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.
|
||||
|
||||
@@ -3,6 +3,6 @@ ManaCost:1 B
|
||||
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.
|
||||
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
|
||||
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.
|
||||
|
||||
@@ -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:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:X:TriggerCount$DamageAmount
|
||||
DeckNeeds:Type$Rogue
|
||||
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.)
|
||||
|
||||
11
forge-gui/res/cardsfolder/a/anthropede.txt
Normal file
11
forge-gui/res/cardsfolder/a/anthropede.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
Name:Anthropede
|
||||
ManaCost:3 G
|
||||
Types:Creature Insect
|
||||
PT:3/4
|
||||
K:Reach
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChoice | TriggerDescription$ When CARDNAME enters, you may discard a card or pay {2}. When you do, destroy target Room.
|
||||
SVar:TrigChoice:DB$ GenericChoice | Choices$ PayDiscard,Pay2
|
||||
SVar:Pay2:DB$ ImmediateTrigger | UnlessCost$ 2 | UnlessPayer$ You | UnlessSwitched$ True | Execute$ TrigDestroy | SpellDescription$ pay {2}: When you do, destroy target Room.
|
||||
SVar:PayDiscard:DB$ ImmediateTrigger | UnlessCost$ Discard<1/Card> | UnlessPayer$ You | UnlessSwitched$ True | Execute$ TrigDestroy | SpellDescription$ discard a card: When you do, destroy target Room.
|
||||
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Room | TgtPrompt$ Select target Room
|
||||
Oracle:Reach\nWhen Anthropede enters, you may discard a card or pay {2}. When you do, destroy target Room.
|
||||
@@ -1,10 +1,10 @@
|
||||
Name:Appendage Amalgam
|
||||
ManaCost:2 B
|
||||
Types:Enchantment Creature Horror
|
||||
PT:3/2
|
||||
K:Flash
|
||||
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigSurveil | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME attacks, surveil 1. (Look at the top card of your library. You may put that card into your graveyard.)
|
||||
SVar:TrigSurveil:DB$ Surveil | Amount$ 1
|
||||
SVar:HasAttackEffect:TRUE
|
||||
DeckHas:Ability$Surveil|Graveyard
|
||||
Oracle:Flash\nWhenever Appendage Amalgam attacks, surveil 1. (Look at the top card of your library. You may put that card into your graveyard.)
|
||||
Name:Appendage Amalgam
|
||||
ManaCost:2 B
|
||||
Types:Enchantment Creature Horror
|
||||
PT:3/2
|
||||
K:Flash
|
||||
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigSurveil | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME attacks, surveil 1. (Look at the top card of your library. You may put that card into your graveyard.)
|
||||
SVar:TrigSurveil:DB$ Surveil | Amount$ 1
|
||||
SVar:HasAttackEffect:TRUE
|
||||
DeckHas:Ability$Surveil|Graveyard
|
||||
Oracle:Flash\nWhenever Appendage Amalgam attacks, surveil 1. (Look at the top card of your library. You may put that card into your graveyard.)
|
||||
@@ -4,7 +4,7 @@ Types:Creature Spider Mutant
|
||||
PT:0/0
|
||||
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.)
|
||||
DeckNeeds:Ability$Counters
|
||||
DeckHas:Ability$Counters
|
||||
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.)
|
||||
|
||||
@@ -4,8 +4,8 @@ Types:Creature Elemental
|
||||
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.
|
||||
SVar:TrigPump:DB$ Pump | Defined$ Self | NumAtt$ 2
|
||||
DeckHints:Type$Instant|Sorcery
|
||||
DeckHas:Ability$Graveyard
|
||||
DeckHints:Type$Instant|Sorcery
|
||||
AlternateMode:Adventure
|
||||
Oracle:Whenever you cast your first instant or sorcery spell each turn, Aquatic Alchemist gets +2/+0 until end of turn.
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
Name:Arabella, Abandoned Doll
|
||||
ManaCost:R W
|
||||
Types:Legendary Artifact Creature Toy
|
||||
PT:1/3
|
||||
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigDamageAll | TriggerDescription$ Whenever CARDNAME attacks, it deals X damage to each opponent and you gain X life, where X is the number of creatures you control with power 2 or less.
|
||||
SVar:TrigDamageAll:DB$ DamageAll | ValidPlayers$ Player.Opponent | NumDmg$ X | SubAbility$ DBGainLife
|
||||
SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ X
|
||||
SVar:X:Count$Valid Creature.YouCtrl+powerLE2
|
||||
Oracle:Whenever Arabella, Abandoned Doll attacks, it deals X damage to each opponent and you gain X life, where X is the number of creatures you control with power 2 or less.
|
||||
Name:Arabella, Abandoned Doll
|
||||
ManaCost:R W
|
||||
Types:Legendary Artifact Creature Toy
|
||||
PT:1/3
|
||||
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigDamageAll | TriggerDescription$ Whenever CARDNAME attacks, it deals X damage to each opponent and you gain X life, where X is the number of creatures you control with power 2 or less.
|
||||
SVar:TrigDamageAll:DB$ DamageAll | ValidPlayers$ Player.Opponent | NumDmg$ X | SubAbility$ DBGainLife
|
||||
SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ X
|
||||
SVar:X:Count$Valid Creature.YouCtrl+powerLE2
|
||||
Oracle:Whenever Arabella, Abandoned Doll attacks, it deals X damage to each opponent and you gain X life, where X is the number of creatures you control with power 2 or less.
|
||||
@@ -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:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ X
|
||||
SVar:X:Count$Valid Creature.YouCtrl+StrictlyOther
|
||||
DeckHas:Ability$Counters|LifeGain
|
||||
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.
|
||||
|
||||
@@ -3,6 +3,6 @@ ManaCost:U R
|
||||
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.
|
||||
K:Flashback:3 U R
|
||||
DeckNeeds:Type$Instant|Sorcery
|
||||
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.)
|
||||
|
||||
@@ -2,6 +2,6 @@ Name:Arcane Melee
|
||||
ManaCost:4 U
|
||||
Types:Enchantment
|
||||
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
|
||||
DeckNeeds:Type$Instant|Sorcery
|
||||
Oracle:Instant and sorcery spells cost {2} less to cast.
|
||||
|
||||
@@ -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: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
|
||||
DeckHints:Type$Instant|Sorcery & Color$Blue
|
||||
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.
|
||||
|
||||
@@ -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.
|
||||
SVar:TrigPutCounter:DB$ PutCounterAll | ValidCards$ Creature.Artifact+StrictlyOther+YouCtrl | CounterType$ P1P1 | CounterNum$ 1
|
||||
K:Modular:2
|
||||
DeckHas:Ability$Counters
|
||||
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.)
|
||||
|
||||
@@ -3,7 +3,7 @@ ManaCost:6
|
||||
Types:Artifact Creature Golem
|
||||
PT:0/0
|
||||
K:Modular:Sunburst
|
||||
AI:RemoveDeck:Random
|
||||
DeckHas:Ability$Counters
|
||||
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.)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user