AI: logic for X in Sac cost

This commit is contained in:
Hans Mackowiak
2021-01-02 05:15:08 +00:00
committed by Michael Kamensky
parent 6841f3c084
commit 7c9ac66e8a
69 changed files with 283 additions and 320 deletions

View File

@@ -558,17 +558,14 @@ public class AiCostDecision extends CostDecisionMakerBase {
return null;
}
final String amount = cost.getAmount();
Integer c = cost.convertAmount();
if (c == null) {
if (ability.getSVar(cost.getAmount()).equals("XChoice")) {
final String sVar = ability.getSVar(amount);
if (sVar.equals("XChoice")) {
String logic = ability.getParamOrDefault("AILogic", "");
if ("SacToReduceCost".equals(logic)) {
// e.g. Torgaar, Famine Incarnate
// TODO: currently returns an empty list, so the AI doesn't sacrifice anything. Trying to make
// the AI decide on creatures to sac makes the AI sacrifice them, but the cost is not reduced and the
// AI pays the full mana cost anyway (despite sacrificing creatures).
return PaymentDecision.card(new CardCollection());
} else if (!logic.isEmpty() && !logic.equals("Never")) {
if (!logic.isEmpty() && !logic.equals("Never")) {
// If at least some other AI logic is specified, assume that the AI for that API knows how
// to define ChosenX and thus honor that value.
// Cards which have no special logic for this yet but which do work in a simple/suboptimal way
@@ -578,8 +575,10 @@ public class AiCostDecision extends CostDecisionMakerBase {
// Other cards are assumed to be flagged AI:RemoveDeck:All for now
return null;
}
} else if (sVar.equals("Count$xPaid")) {
c = AbilityUtils.calculateAmount(source, "PayX", ability);
} else {
c = AbilityUtils.calculateAmount(source, cost.getAmount(), ability);
c = AbilityUtils.calculateAmount(source, amount, ability);
}
}
final AiController aic = ((PlayerControllerAi)player.getController()).getAi();

View File

@@ -90,9 +90,7 @@ public class ComputerUtilCost {
// value later as the AI decides what to do (in checkApiLogic / checkAiLogic)
if (sa.hasSVar(remCounter.getAmount())) {
final String sVar = sa.getSVar(remCounter.getAmount());
if (sVar.equals("XChoice") && !sa.hasSVar("ChosenX")) {
sa.setSVar("ChosenX", String.valueOf(source.getCounters(type)));
} else if (sVar.equals("Count$xPaid") && sa.hasSVar("PayX")) {
if (sVar.equals("Count$xPaid") && sa.hasSVar("PayX")) {
sa.setSVar("PayX", Integer.toString(Math.min(Integer.valueOf(sa.getSVar("PayX")), source.getCounters(type))));
}
}
@@ -675,6 +673,7 @@ public class ComputerUtilCost {
}
public static int getMaxXValue(SpellAbility sa, Player ai) {
final Card source = sa.getHostCard();
final Cost abCost = sa.getPayCosts();
if (abCost == null || !abCost.hasXInAnyCostPart()) {
return 0;
@@ -691,8 +690,42 @@ public class ComputerUtilCost {
if ("X".equals(sa.getTargetRestrictions().getMinTargets())) {
val = ObjectUtils.min(val, CardUtil.getValidCardsToTarget(sa.getTargetRestrictions(), sa).size());
}
if (sa.hasParam("AIMaxTgtsCount")) {
// Cards that have confusing costs for the AI (e.g. Eliminate the Competition) can have forced max target constraints specified
// TODO: is there a better way to predict things like "sac X" costs without needing a special AI variable?
val = ObjectUtils.min(val, AbilityUtils.calculateAmount(sa.getHostCard(), "Count$" + sa.getParam("AIMaxTgtsCount"), sa));
}
}
return ObjectUtils.defaultIfNull(ObjectUtils.min(val, abCost.getMaxForNonManaX(sa, ai)), 0);
val = ObjectUtils.min(val, abCost.getMaxForNonManaX(sa, ai));
if (val != null && val > 0) {
// filter cost parts for preferences, don't choose X > than possible preferences
for (final CostPart part : abCost.getCostParts()) {
if (part instanceof CostSacrifice) {
if (part.payCostFromSource()) {
continue;
}
if (!part.getAmount().equals("X")) {
continue;
}
final CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), part.getType().split(";"), source.getController(), source, null);
int count = 0;
while (count < val) {
Card prefCard = ComputerUtil.getCardPreference(ai, source, "SacCost", typeList);
if (prefCard == null) {
break;
}
typeList.remove(prefCard);
count++;
}
val = ObjectUtils.min(val, count);
}
}
}
return ObjectUtils.defaultIfNull(val, 0);
}
}

View File

@@ -1162,7 +1162,7 @@ public class ComputerUtilMana {
* @param extraMana extraMana
* @return ManaCost
*/
static ManaCostBeingPaid calculateManaCost(final SpellAbility sa, final boolean test, final int extraMana) {
public static ManaCostBeingPaid calculateManaCost(final SpellAbility sa, final boolean test, final int extraMana) {
Card card = sa.getHostCard();
ZoneType castFromBackup = null;
if (test && sa.isSpell()) {
@@ -1627,31 +1627,4 @@ public class ComputerUtilMana {
}
return convoke;
}
public static int determineMaxAffordableX(Player ai, SpellAbility sa) {
if (sa.getPayCosts().getCostMana() == null) {
return -1;
}
int numTgts = 0;
int numX = sa.getPayCosts().getCostMana().getAmountOfX();
if (numX == 0) {
return -1;
}
int testX = 1;
while (testX <= 100) {
if (ComputerUtilMana.canPayManaCost(sa, ai, testX)) {
numTgts++;
} else {
break;
}
testX++;
}
numTgts /= numX;
return numTgts;
}
}

View File

@@ -103,7 +103,7 @@ public class PlayerControllerAi extends PlayerController {
}
@Override
public Integer announceRequirements(SpellAbility ability, String announce, boolean allowZero) {
public Integer announceRequirements(SpellAbility ability, String announce) {
// For now, these "announcements" are made within the AI classes of the appropriate SA effects
if (ability.getApi() != null) {
switch (ability.getApi()) {

View File

@@ -40,6 +40,7 @@ import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.player.PlayerPredicates;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityPredicates;
import forge.game.spellability.SpellPermanent;
import forge.game.staticability.StaticAbility;
import forge.game.trigger.Trigger;
@@ -1400,7 +1401,7 @@ public class SpecialCardAi {
int x = -1, best = 0;
Card single = null;
for (int i = 0; i < loyalty; i++) {
sa.setSVar("ChosenX", "Number$" + i);
sa.setXManaCostPaid(i);
oppType = CardLists.filterControlledBy(game.getCardsIn(origin), ai.getOpponents());
oppType = AbilityUtils.filterListByType(oppType, sa.getParam("ChangeType"), sa);
computerType = AbilityUtils.filterListByType(ai.getCardsIn(origin), sa.getParam("ChangeType"), sa);
@@ -1417,13 +1418,8 @@ public class SpecialCardAi {
}
// check if +1 would be sufficient
if (single != null) {
SpellAbility ugin_burn = null;
for (final SpellAbility s : source.getSpellAbilities()) {
if (s.getApi() == ApiType.DealDamage) {
ugin_burn = s;
break;
}
}
// TODO use better logic to find the right Deal Damage Effect?
SpellAbility ugin_burn = Iterables.find(source.getSpellAbilities(), SpellAbilityPredicates.isApi(ApiType.DealDamage), null);
if (ugin_burn != null) {
// basic logic copied from DamageDealAi::dealDamageChooseTgtC
if (ugin_burn.canTarget(single)) {
@@ -1434,17 +1430,18 @@ public class SpecialCardAi {
if (can_kill) {
return false;
}
}
// simple check to burn player instead of exiling planeswalker
if (single.isPlaneswalker() && single.getCurrentLoyalty() <= 3) {
return false;
}
}
}
}
if (x == -1) {
return false;
}
sa.setSVar("ChosenX", "Number$" + x);
sa.setXManaCostPaid(x);
sa.setSVar("PayX", String.valueOf(x));
return true;
}
}

View File

@@ -845,7 +845,6 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
final ZoneType destination = ZoneType.smartValueOf(sa.getParam("Destination"));
final TargetRestrictions tgt = sa.getTargetRestrictions();
final Game game = ai.getGame();
final AbilitySub abSub = sa.getSubAbility();
@@ -859,8 +858,17 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
sa.resetTargets();
CardCollection list = CardLists.getValidCards(game.getCardsIn(origin), tgt.getValidTgts(), ai, source, sa);
list = CardLists.getTargetableCards(list, sa);
// X controls the minimum targets
if ("X".equals(sa.getTargetRestrictions().getMinTargets()) && sa.getSVar("X").equals("Count$xPaid")) {
// Set PayX here to maximum value.
int xPay = ComputerUtilCost.getMaxXValue(sa, ai);
sa.setSVar("PayX", Integer.toString(xPay));
// TODO need to set XManaCostPaid for targets, maybe doesn't need PayX anymore?
sa.setXManaCostPaid(xPay);
// TODO since change of PayX. the shouldCastLessThanMax logic might be faulty
}
CardCollection list = CardLists.getTargetableCards(game.getCardsIn(origin), sa);
// Filter AI-specific targets if provided
list = ComputerUtil.filterAITgts(sa, ai, list, true);
@@ -896,7 +904,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
//System.out.println("isPreferredTarget ok " + list);
}
if (list.size() < tgt.getMinTargets(sa.getHostCard(), sa)) {
if (list.size() < sa.getMinTargets()) {
return false;
}
@@ -921,7 +929,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
// Combat bouncing
if (tgt.getMinTargets(sa.getHostCard(), sa) <= 1) {
if (sa.getMinTargets() <= 1) {
if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
Combat currCombat = game.getCombat();
CardCollection attackers = currCombat.getAttackers();
@@ -964,7 +972,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
// if it's blink or bounce, try to save my about to die stuff
final boolean blink = (destination.equals(ZoneType.Exile) && (subApi == ApiType.DelayedTrigger
|| "DelayedBlink".equals(sa.getParam("AILogic")) || (subApi == ApiType.ChangeZone && subAffected.equals("Remembered"))));
if ((destination.equals(ZoneType.Hand) || blink) && (tgt.getMinTargets(sa.getHostCard(), sa) <= 1)) {
if ((destination.equals(ZoneType.Hand) || blink) && (sa.getMinTargets() <= 1)) {
// save my about to die stuff
Card tobounce = canBouncePermanent(ai, sa, list);
if (tobounce != null) {
@@ -974,7 +982,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
sa.getTargets().add(tobounce);
boolean saheeliFelidarCombo = sa.getHostCard().getName().equals("Felidar Guardian")
boolean saheeliFelidarCombo = ComputerUtilAbility.getAbilitySourceName(sa).equals("Felidar Guardian")
&& tobounce.getName().equals("Saheeli Rai")
&& CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.nameEquals("Felidar Guardian")).size() <
CardLists.filter(ai.getOpponents().getCardsIn(ZoneType.Battlefield), CardPredicates.isType("Creature")).size() + ai.getOpponentsGreatestLifeTotal() + 10;
@@ -1107,7 +1115,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
boolean doWithoutTarget = sa.hasParam("Planeswalker") && sa.usesTargeting()
&& sa.getTargetRestrictions().getMinTargets(source, sa) == 0
&& sa.getMinTargets() == 0
&& sa.getPayCosts().hasSpecificCostType(CostPutCounter.class);
if (list.isEmpty() && !doWithoutTarget) {
@@ -1118,12 +1126,12 @@ public class ChangeZoneAi extends SpellAbilityAi {
// the Unless cost (for example, Erratic Portal)
list.removeAll(getSafeTargetsIfUnlessCostPaid(ai, sa, list));
if (!mandatory && list.size() < tgt.getMinTargets(sa.getHostCard(), sa)) {
if (!mandatory && sa.isTargetNumberValid()) {
return false;
}
// target loop
while (sa.getTargets().size() < tgt.getMaxTargets(sa.getHostCard(), sa)) {
while (sa.canAddMoreTarget()) {
// AI Targeting
Card choice = null;
@@ -1152,7 +1160,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
//option to hold removal instead only applies for single targeted removal
if (!immediately && tgt.getMaxTargets(source, sa) == 1) {
if (!immediately && sa.getMaxTargets() == 1) {
if (!ComputerUtilCard.useRemovalNow(sa, choice, 0, destination)) {
return false;
}
@@ -1188,7 +1196,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
}
if (choice == null) { // can't find anything left
if (sa.getTargets().size() == 0 || sa.getTargets().size() < tgt.getMinTargets(sa.getHostCard(), sa)) {
if (sa.getTargets().size() == 0 || !sa.isTargetNumberValid()) {
if (!mandatory) {
sa.resetTargets();
}
@@ -1223,7 +1231,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
// honor the Same Creature Type restriction
if (tgt.isWithSameCreatureType()) {
if (sa.getTargetRestrictions().isWithSameCreatureType()) {
Card firstTarget = sa.getTargetCard();
if (firstTarget != null && !choice.sharesCreatureTypeWith(firstTarget)) {
list.remove(choice);

View File

@@ -102,9 +102,10 @@ public class ChooseCardAi extends SpellAbilityAi {
} else if (aiLogic.equals("Ashiok")) {
final int loyalty = host.getCounters(CounterEnumType.LOYALTY) - 1;
for (int i = loyalty; i >= 0; i--) {
host.setSVar("ChosenX", "Number$" + i);
sa.setSVar("PayX", String.valueOf(i));
sa.setXManaCostPaid(i);
choices = ai.getGame().getCardsIn(choiceZone);
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), host.getController(), host);
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), host.getController(), host, sa);
if (!choices.isEmpty()) {
return true;
}

View File

@@ -20,7 +20,6 @@ public class ChooseColorAi extends SpellAbilityAi {
@Override
protected boolean canPlayAI(Player ai, SpellAbility sa) {
final Card source = sa.getHostCard();
final Game game = ai.getGame();
final String sourceName = ComputerUtilAbility.getAbilitySourceName(sa);
final PhaseHandler ph = game.getPhaseHandler();

View File

@@ -45,7 +45,7 @@ public class ChooseTypeAi extends SpellAbilityAi {
return false;
}
int maxX = ComputerUtilMana.determineMaxAffordableX(aiPlayer, sa);
int maxX = ComputerUtilMana.determineLeftoverMana(sa, aiPlayer);
int avgPower = 0;
// predict the opposition

View File

@@ -137,11 +137,6 @@ public class DestroyAi extends SpellAbilityAi {
} else {
maxTargets = sa.getMaxTargets();
}
if (sa.hasParam("AIMaxTgtsCount")) {
// Cards that have confusing costs for the AI (e.g. Eliminate the Competition) can have forced max target constraints specified
// TODO: is there a better way to predict things like "sac X" costs without needing a special AI variable?
maxTargets = Math.min(CardFactoryUtil.xCount(sa.getHostCard(), "Count$" + sa.getParam("AIMaxTgtsCount")), maxTargets);
}
if (maxTargets == 0) {
// can't afford X or otherwise target anything

View File

@@ -23,8 +23,6 @@ import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.cost.*;
@@ -180,8 +178,7 @@ public class DrawAi extends SpellAbilityAi {
int numHand = ai.getCardsIn(ZoneType.Hand).size();
if ("Jace, Vryn's Prodigy".equals(sourceName) && ai.getCardsIn(ZoneType.Graveyard).size() > 3) {
return CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.PLANESWALKERS,
CardPredicates.isType("Jace")).size() <= 0;
return !ai.isCardInPlay("Jace, Telepath Unbound");
}
if (source.isSpell() && ai.getCardsIn(ZoneType.Hand).contains(source)) {
numHand--; // remember to count looter card if it is a spell in hand
@@ -222,6 +219,7 @@ public class DrawAi extends SpellAbilityAi {
final int computerLibrarySize = ai.getCardsIn(ZoneType.Library).size();
final int computerMaxHandSize = ai.getMaxHandSize();
final SpellAbility gainLife = sa.findSubAbilityByType(ApiType.GainLife);
final SpellAbility loseLife = sa.findSubAbilityByType(ApiType.LoseLife);
final SpellAbility getPoison = sa.findSubAbilityByType(ApiType.Poison);
@@ -243,7 +241,7 @@ public class DrawAi extends SpellAbilityAi {
if (drawback && !sa.getSVar("PayX").equals("")) {
numCards = Integer.parseInt(sa.getSVar("PayX"));
} else {
numCards = ComputerUtilMana.determineLeftoverMana(sa, ai);
numCards = ComputerUtilCost.getMaxXValue(sa, ai);
// try not to overdraw
int safeDraw = Math.min(computerMaxHandSize - computerHandSize, computerLibrarySize - 3);
if (sa.getHostCard().isInstant() || sa.getHostCard().isSorcery()) { safeDraw++; } // card will be spent
@@ -252,8 +250,7 @@ public class DrawAi extends SpellAbilityAi {
assumeSafeX = true;
}
xPaid = true;
}
if (sa.getSVar(num).equals("Count$Converge")) {
} else if (sa.getSVar(num).equals("Count$Converge")) {
numCards = ComputerUtilMana.getConvergeCount(sa, ai);
}
}
@@ -270,14 +267,6 @@ public class DrawAi extends SpellAbilityAi {
while ((ComputerUtil.aiLifeInDanger(ai, false, numCards) && (numCards > 0))) {
numCards--;
}
} else if (sa.getPayCosts().hasSpecificCostType(CostSacrifice.class)) {
// [e.g. Krav, the Unredeemed and other cases which say "Sacrifice X creatures: draw X cards]
// TODO: Add special logic to limit/otherwise modify the ChosenX value here
// Skip this ability if nothing is to be chosen for sacrifice
if (numCards <= 0) {
return false;
}
}
sa.setSVar("ChosenX", Integer.toString(numCards));
@@ -347,6 +336,20 @@ public class DrawAi extends SpellAbilityAi {
}
}
}
// that opponent can gain life and also lose life and that life gain is negative
if (gainLife != null && oppA.canGainLife() && oppA.canLoseLife() && ComputerUtil.lifegainNegative(oppA, source)) {
if (gainLife.hasParam("Defined") && "Targeted".equals(gainLife.getParam("Defined"))) {
if (numCards >= oppA.getLife()) {
if (xPaid) {
sa.setSVar("PayX", Integer.toString(oppA.getLife()));
}
sa.getTargets().add(oppA);
return true;
}
}
}
// try to make opponent lose to poison
// currently only Caress of Phyrexia
if (getPoison != null && oppA.canReceiveCounters(CounterType.get(CounterEnumType.POISON))) {

View File

@@ -118,8 +118,7 @@ public class ManaEffectAi extends SpellAbilityAi {
int numCounters = 0;
int manaSurplus = 0;
if ("XChoice".equals(host.getSVar("X"))
&& sa.getPayCosts().hasSpecificCostType(CostRemoveCounter.class)) {
if ("Count$xPaid".equals(host.getSVar("X")) && sa.getPayCosts().hasSpecificCostType(CostRemoveCounter.class)) {
CounterType ctrType = CounterType.get(CounterEnumType.KI); // Petalmane Baku
for (CostPart part : sa.getPayCosts().getCostParts()) {
if (part instanceof CostRemoveCounter) {
@@ -206,7 +205,9 @@ public class ManaEffectAi extends SpellAbilityAi {
// Don't remove more counters than would be needed to cast the more expensive thing we want to cast,
// otherwise the AI grabs too many counters at once.
int maxCtrs = Aggregates.max(castableSpells, CardPredicates.Accessors.fnGetCmc) - manaSurplus;
sa.setSVar("ChosenX", "Number$" + Math.min(numCounters, maxCtrs));
int min = Math.min(numCounters, maxCtrs);
sa.setXManaCostPaid(min);
sa.setSVar("PayX", Integer.toString(min));
}
// TODO: this will probably still waste the card from time to time. Somehow improve detection of castable material.

View File

@@ -102,7 +102,7 @@ public class PermanentAi extends SpellAbilityAi {
ManaCost mana = sa.getPayCosts().getTotalMana();
if (mana.countX() > 0) {
// Set PayX here to maximum value.
final int xPay = ComputerUtilMana.determineLeftoverMana(sa, ai);
final int xPay = ComputerUtilCost.getMaxXValue(sa, ai);
final Card source = sa.getHostCard();
if (source.hasConverge()) {
card.setSVar("PayX", Integer.toString(0));
@@ -134,6 +134,20 @@ public class PermanentAi extends SpellAbilityAi {
}
}
if ("SacToReduceCost".equals(sa.getParam("AILogic"))) {
// reset X to better calculate
sa.setXManaCostPaid(0);
ManaCostBeingPaid paidCost = ComputerUtilMana.calculateManaCost(sa, true, 0);
int generic = paidCost.getGenericManaAmount();
// Set PayX here to maximum value.
int xPay = ComputerUtilCost.getMaxXValue(sa, ai);
// currently cards with SacToReduceCost reduce by 2 generic
xPay = Math.min(xPay, generic / 2);
card.setSVar("PayX", Integer.toString(xPay));
sa.setXManaCostPaid(xPay);
}
if (sa.hasParam("Announce") && sa.getParam("Announce").startsWith("Multikicker")) {
// String announce = sa.getParam("Announce");
ManaCost mkCost = sa.getMultiKickerManaCost();

View File

@@ -115,7 +115,7 @@ public class ScryAi extends SpellAbilityAi {
}
// has spell that can be cast if one counter is removed
if (!CardLists.filter(hand, CardPredicates.hasCMC(counterNum)).isEmpty()) {
sa.setSVar("ChosenX", "Number$1");
sa.setSVar("PayX", "1");
return true;
}
}
@@ -142,10 +142,10 @@ public class ScryAi extends SpellAbilityAi {
if (maxToRemove <= 0) {
return false;
}
sa.setSVar("ChosenX", "Number$" + maxToRemove);
sa.setSVar("PayX", String.valueOf(maxToRemove));
} else {
// no Instant or Sorceries anymore, just scry
sa.setSVar("ChosenX", "Number$" + Math.min(counterNum, libsize));
sa.setSVar("PayX", String.valueOf(Math.min(counterNum, libsize)));
}
}
return true;

View File

@@ -28,7 +28,7 @@ public class BidLifeEffect extends SpellAbilityEffect {
if (sa.hasParam("StartBidding")) {
String start = sa.getParam("StartBidding");
if ("Any".equals(start)) {
startBidding = activator.getController().announceRequirements(sa, Localizer.getInstance().getMessage("lblChooseStartingBid"), true);
startBidding = activator.getController().announceRequirements(sa, Localizer.getInstance().getMessage("lblChooseStartingBid"));
} else {
startBidding = AbilityUtils.calculateAmount(host, start, sa);
}

View File

@@ -60,7 +60,7 @@ public class ChooseNumberEffect extends SpellAbilityEffect {
} else {
String title = sa.hasParam("ListTitle") ? sa.getParam("ListTitle") : Localizer.getInstance().getMessage("lblChooseNumber");
if (anyNumber) {
Integer value = p.getController().announceRequirements(sa, title, true);
Integer value = p.getController().announceRequirements(sa, title);
chosen = (value == null ? 0 : value);
} else {
chosen = p.getController().chooseNumber(sa, title, min, max);

View File

@@ -124,7 +124,7 @@ public class Cost implements Serializable {
Collections.sort(this.costParts, new Comparator<CostPart>() {
@Override
public int compare(CostPart o1, CostPart o2) {
return o1.paymentOrder() - o2.paymentOrder();
return ObjectUtils.compare(o1.paymentOrder(), o2.paymentOrder());
}
});
}
@@ -254,34 +254,15 @@ public class Cost implements Serializable {
}
if (parsedMana == null && manaParts.length() > 0) {
if (parsedMana == null && (manaParts.length() > 0 || xCantBe0)) {
parsedMana = new CostPartMana(new ManaCost(new ManaCostParser(manaParts.toString())), xCantBe0 ? "XCantBe0" : null);
}
if (parsedMana != null) {
if(parsedMana.shouldPayLast()) // back from the brink pays mana after 'exile' part is paid
this.costParts.add(parsedMana);
else
this.costParts.add(0, parsedMana);
}
// inspect parts to set Sac, {T} and {Q} flags
for (int iCp = 0; iCp < costParts.size(); iCp++) {
CostPart cp = costParts.get(iCp);
// untap cost has to be last so that a card can't use e.g. its own mana ability while paying for a part of its own mana cost
// (e.g. Zhur-Taa Druid equipped with Umbral Mantle, paying the mana cost of {3}, {Q} )
if (cp instanceof CostUntap) {
costParts.remove(iCp);
costParts.add(cp);
}
// tap cost has to be first so that a card can't use e.g. its own mana ability while paying for a part of its own mana cost
// (e.g. Ally Encampment with the cost of 1, {T} )
if (cp instanceof CostTap) {
costParts.remove(iCp);
costParts.add(0, cp);
}
costParts.add(parsedMana);
}
// technically the user might pay the costs in any order
// but needs to activate mana ability first
sort();
}

View File

@@ -17,6 +17,10 @@
*/
package forge.game.cost;
import org.apache.commons.lang3.ObjectUtils;
import com.google.common.collect.Iterables;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollectionView;
@@ -53,6 +57,16 @@ public class CostSacrifice extends CostPartWithList {
@Override
public int paymentOrder() { return 15; }
@Override
public Integer getMaxAmountX(SpellAbility ability, Player payer) {
final Card source = ability.getHostCard();
CardCollectionView typeList = payer.getCardsIn(ZoneType.Battlefield);
typeList = CardLists.getValidCards(typeList, getType().split(";"), payer, source, ability);
typeList = CardLists.filter(typeList, CardPredicates.canBeSacrificedBy(ability));
return typeList.size();
}
/*
* (non-Javadoc)
*
@@ -63,17 +77,11 @@ public class CostSacrifice extends CostPartWithList {
final StringBuilder sb = new StringBuilder();
sb.append("Sacrifice ");
final Integer i = this.convertAmount();
if (this.payCostFromSource()) {
sb.append(this.getType());
if (payCostFromSource()) {
sb.append(getType());
} else {
final String desc = this.getTypeDescription() == null ? this.getType() : this.getTypeDescription();
if (i != null) {
sb.append(Cost.convertIntAndTypeToWords(i, desc));
} else {
sb.append(Cost.convertAmountTypeToWords(this.getAmount(), desc));
}
final String desc = ObjectUtils.firstNonNull(getTypeDescription(), getType());
sb.append(Cost.convertAmountTypeToWords(convertAmount(), getAmount(), desc));
}
return sb.toString();
}
@@ -90,21 +98,20 @@ public class CostSacrifice extends CostPartWithList {
final Card source = ability.getHostCard();
// You can always sac all
if (!this.payCostFromSource()) {
// If the sacrificed type is dependant on an annoucement, can't necesarily rule out the CanPlay call
boolean needsAnnoucement = ability.hasParam("Announce") && this.getType().contains(ability.getParam("Announce"));
if (!payCostFromSource()) {
if ("All".equalsIgnoreCase(getAmount())) {
CardCollectionView typeList = activator.getCardsIn(ZoneType.Battlefield);
typeList = CardLists.getValidCards(typeList, this.getType().split(";"), activator, source, ability);
typeList = CardLists.getValidCards(typeList, getType().split(";"), activator, source, ability);
// it needs to check if everything can be sacrificed
return Iterables.all(typeList, CardPredicates.canBeSacrificedBy(ability));
}
Integer amount = this.convertAmount();
if (amount == null) {
amount = AbilityUtils.calculateAmount(source, getAmount(), ability);
}
typeList = CardLists.filter(typeList, CardPredicates.canBeSacrificedBy(ability));
return needsAnnoucement || (amount == null) || (typeList.size() >= amount);
return getMaxAmountX(ability, activator) >= amount;
// If amount is null, it's either "ALL" or "X"
// if X is defined, it needs to be calculated and checked, if X is
// choice, it can be Paid even if it's 0

View File

@@ -110,7 +110,7 @@ public abstract class PlayerController {
public abstract Map<Card, Integer> assignCombatDamage(Card attacker, CardCollectionView blockers, int damageDealt, GameEntity defender, boolean overrideOrder);
public abstract Integer announceRequirements(SpellAbility ability, String announce, boolean allowZero);
public abstract Integer announceRequirements(SpellAbility ability, String announce);
public abstract CardCollectionView choosePermanentsToSacrifice(SpellAbility sa, int min, int max, CardCollectionView validTargets, String message);
public abstract CardCollectionView choosePermanentsToDestroy(SpellAbility sa, int min, int max, CardCollectionView validTargets, String message);
public abstract TargetChoices chooseNewTargetsFor(SpellAbility ability);

View File

@@ -127,7 +127,7 @@ public class PlayerControllerForTests extends PlayerController {
}
@Override
public Integer announceRequirements(SpellAbility ability, String announce, boolean allowZero) {
public Integer announceRequirements(SpellAbility ability, String announce) {
throw new IllegalStateException("Erring on the side of caution here...");
}

View File

@@ -3,11 +3,11 @@ ManaCost:1 U B
Types:Legendary Planeswalker Ashiok
Loyalty:3
A:AB$ Dig | Cost$ AddCounter<2/LOYALTY> | Planeswalker$ True | ValidTgts$ Opponent | DigNum$ 3 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | SpellDescription$ Exile the top three cards of target opponent's library.
A:AB$ ChooseCard | Cost$ SubCounter<X/LOYALTY> | References$ X | Choices$ Creature.cmcEQChosenX+IsRemembered+ExiledWithSource | ChoiceZone$ Exile | Planeswalker$ True | SubAbility$ DBChangeZone | AILogic$ Ashiok | SpellDescription$ Put a creature card with converted mana cost X exiled with CARDNAME onto the battlefield under your control. That creature is a Nightmare in addition to its other types.
SVar:DBChangeZone:DB$ ChangeZone | Defined$ ChosenCard | Origin$ Exile | Destination$ Battlefield | ChangeType$ Creature.cmcEQChosenX+IsRemembered+ExiledWithSource | ChangeNum$ 1 | GainControl$ True | SubAbility$ DBAnimate
A:AB$ ChooseCard | Cost$ SubCounter<X/LOYALTY> | References$ X | Choices$ Creature.cmcEQX+IsRemembered+ExiledWithSource | ChoiceZone$ Exile | Planeswalker$ True | SubAbility$ DBChangeZone | AILogic$ Ashiok | SpellDescription$ Put a creature card with converted mana cost X exiled with CARDNAME onto the battlefield under your control. That creature is a Nightmare in addition to its other types.
SVar:DBChangeZone:DB$ ChangeZone | Defined$ ChosenCard | Origin$ Exile | Destination$ Battlefield | ChangeType$ Creature.cmcEQX+IsRemembered+ExiledWithSource | ChangeNum$ 1 | GainControl$ True | SubAbility$ DBAnimate
SVar:DBAnimate:DB$ Animate | Defined$ ChosenCard | Types$ Nightmare | Permanent$ True | SubAbility$ DBCleanMinus
SVar:DBCleanMinus:DB$ Cleanup | ForgetDefined$ ChosenCard | ClearChosenCard$ True
SVar:X:XChoice
SVar:X:Count$xPaid
A:AB$ ChangeZoneAll | Cost$ SubCounter<10/LOYALTY> | ChangeType$ Card.OppCtrl | Origin$ Graveyard,Hand | Destination$ Exile | RememberChanged$ True | Planeswalker$ True | Ultimate$ True | SpellDescription$ Exile all cards from all opponents' hands and graveyards.
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered+ExiledWithSource | Execute$ DBForget
SVar:DBForget:DB$ Pump | ForgetObjects$ TriggeredCard

View File

@@ -3,9 +3,7 @@ ManaCost:4
Types:Artifact
A:AB$ PutCounter | Cost$ 2 T | CounterType$ CHARGE | CounterNum$ 1 | SpellDescription$ Put a charge counter on CARDNAME.
A:AB$ Mana | Cost$ T SubCounter<X/CHARGE> | References$ X,Y | Produced$ B | Amount$ Y | CostDesc$ {T}, Remove any number of charge counters from CARDNAME: | AILogic$ ManaRitualBattery.1 | AINoRecursiveCheck$ True | SpellDescription$ Add {B}, then add an additional {B} for each charge counter removed this way.
SVar:Y:Number$1/Plus.ChosenX
SVar:X:XChoice
#ChosenX SVar created by Cost payment
SVar:Y:SVar$X/Plus.1
SVar:X:Count$xPaid
AI:RemoveDeck:Random
SVar:Picture:http://www.wizards.com/global/images/magic/general/black_mana_battery.jpg
Oracle:{2}, {T}: Put a charge counter on Black Mana Battery.\n{T}, Remove any number of charge counters from Black Mana Battery: Add {B}, then add an additional {B} for each charge counter removed this way.

View File

@@ -3,9 +3,7 @@ ManaCost:4
Types:Artifact
A:AB$ PutCounter | Cost$ 2 T | CounterType$ CHARGE | CounterNum$ 1 | SpellDescription$ Put a charge counter on CARDNAME.
A:AB$ Mana | Cost$ T SubCounter<X/CHARGE> | Produced$ U | Amount$ Y | CostDesc$ {T}, Remove any number of charge counters from CARDNAME: | References$ X,Y | AILogic$ ManaRitualBattery.1 | AINoRecursiveCheck$ True | SpellDescription$ Add {U}, then add an additional {U} for each charge counter removed this way.
SVar:Y:Number$1/Plus.ChosenX
SVar:X:XChoice
#ChosenX SVar created by Cost payment
SVar:Y:SVar$X/Plus.1
SVar:X:Count$xPaid
AI:RemoveDeck:Random
SVar:Picture:http://www.wizards.com/global/images/magic/general/blue_mana_battery.jpg
Oracle:{2}, {T}: Put a charge counter on Blue Mana Battery.\n{T}, Remove any number of charge counters from Blue Mana Battery: Add {U}, then add an additional {U} for each charge counter removed this way.

View File

@@ -2,7 +2,7 @@ Name:Bosh, Iron Golem Avatar
ManaCost:no cost
Types:Vanguard
HandLifeModifier:+0/-2
A:AB$ DealDamage | ActivationZone$ Command | Announce$ X | Cost$ X Sac<1/Artifact.cmcEQX/artifact with converted mana cost X> | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ X | References$ X | SpellDescription$ CARDNAME deals X damage to any target.
A:AB$ DealDamage | ActivationZone$ Command | Cost$ X Sac<1/Artifact.cmcEQX/artifact with converted mana cost X> | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ X | References$ X | SpellDescription$ CARDNAME deals X damage to any target.
SVar:X:Count$xPaid
SVar:Picture:https://downloads.cardforge.org/images/cards/VAN/Bosh, Iron Golem Avatar.full.jpg
AI:RemoveDeck:All

View File

@@ -5,9 +5,7 @@ K:CARDNAME enters the battlefield tapped.
K:You may choose not to untap CARDNAME during your untap step.
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | IsPresent$ Card.Self+tapped | Execute$ TrigStore | TriggerDescription$ At the beginning of your upkeep, if CARDNAME is tapped, put a storage counter on it.
SVar:TrigStore:DB$PutCounter | Defined$ Self | CounterType$ STORAGE | CounterNum$ 1
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ B | Amount$ ChosenX | CostDesc$ {T}, Remove any number of storage counters from CARDNAME: | References$ X | SpellDescription$ Add {B} for each storage counter removed this way.
SVar:X:XChoice
#ChosenX SVar created by Cost payment
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ B | Amount$ X | CostDesc$ {T}, Remove any number of storage counters from CARDNAME: | References$ X | AILogic$ ManaRitualBattery | SpellDescription$ Add {B} for each storage counter removed this way.
SVar:X:Count$xPaid
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/bottomless_vault.jpg
Oracle:Bottomless Vault enters the battlefield tapped.\nYou may choose not to untap Bottomless Vault during your untap step.\nAt the beginning of your upkeep, if Bottomless Vault is tapped, put a storage counter on it.\n{T}, Remove any number of storage counters from Bottomless Vault: Add {B} for each storage counter removed this way.

View File

@@ -3,8 +3,7 @@ ManaCost:2
Types:Artifact
A:AB$ PutCounter | Cost$ 1 T | CounterType$ CHARGE | CounterNum$ 1 | SubAbility$ DBCast | SpellDescription$ Put a charge counter on Brain in a Jar, then you may cast an instant or sorcery card with converted mana cost equal to the number of charge counters on Brain in a Jar from your hand without paying its mana cost.
SVar:DBCast:DB$ Play | ValidZone$ Hand | Valid$ Instant.YouOwn+cmcEQY,Sorcery.YouOwn+cmcEQY | Controller$ You | WithoutManaCost$ True | Optional$ True | Amount$ 1 | References$ Y
A:AB$ Scry | Cost$ 3 T SubCounter<X/CHARGE> | ScryNum$ ChosenX | References$ X | AILogic$ BrainJar | SpellDescription$ Scry X.
SVar:X:XChoice
A:AB$ Scry | Cost$ 3 T SubCounter<X/CHARGE> | ScryNum$ X | References$ X | AILogic$ BrainJar | SpellDescription$ Scry X.
SVar:X:Count$xPaid
SVar:Y:Count$CardCounters.CHARGE
SVar:Picture:http://www.wizards.com/global/images/magic/general/brain_in_a_jar.jpg
Oracle:{1}, {T}: Put a charge counter on Brain in a Jar, then you may cast an instant or sorcery card with converted mana cost equal to the number of charge counters on Brain in a Jar from your hand without paying its mana cost.\n{3}, {T}, Remove X charge counters from Brain in a Jar: Scry X.

View File

@@ -3,8 +3,7 @@ ManaCost:no cost
Types:Land
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.
A:AB$ PutCounter | Cost$ 1 T | CounterType$ STORAGE | CounterNum$ 1 | SpellDescription$ Put a storage counter on CARDNAME.
A:AB$ Mana | Cost$ 1 SubCounter<X/STORAGE> | Produced$ Combo W U | Amount$ ChosenX | CostDesc$ {1}, Remove X storage counters from CARDNAME: | References$ X | SpellDescription$ Add X mana in any combination of {W} and/or {U}.
SVar:X:XChoice
A:AB$ Mana | Cost$ 1 SubCounter<X/STORAGE> | Produced$ Combo W U | Amount$ X | CostDesc$ {1}, Remove X storage counters from CARDNAME: | References$ X | SpellDescription$ Add X mana in any combination of {W} and/or {U}.
SVar:X:Count$xPaid
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/calciform_pools.jpg
Oracle:{T}: Add {C}.\n{1}, {T}: Put a storage counter on Calciform Pools.\n{1}, Remove X storage counters from Calciform Pools: Add X mana in any combination of {W} and/or {U}.

View File

@@ -2,8 +2,9 @@ Name:Champion of Stray Souls
ManaCost:4 B B
Types:Creature Skeleton Warrior
PT:4/4
# TODO: The AI will never activate this ability since it can't properly pay the cost. Consider updating.
A:AB$ ChangeZone | Announce$ X | Cost$ 3 B B T Sac<X/Creature.Other/other creature(s)> | CostDesc$ {3}{B}{B}, {T}, Sacrifice X other creatures: | Origin$ Graveyard | Destination$ Battlefield | ValidTgts$ Creature.YouOwn | TgtPrompt$ Select X target creature cards from your graveyard | TargetMin$ X | TargetMax$ X | References$ X | AILogic$ Never | SpellDescription$ Return X target creatures from your graveyard to the battlefield.
A:AB$ ChangeZone | Cost$ 3 B B T Sac<X/Creature.Other/other creature(s)> | CostDesc$ {3}{B}{B}, {T}, Sacrifice X other creatures: | Origin$ Graveyard | Destination$ Battlefield | ValidTgts$ Creature.YouOwn | TgtPrompt$ Select X target creature cards from your graveyard | TargetMin$ X | TargetMax$ X | References$ X | AIMinTgts$ 3 | SpellDescription$ Return X target creatures from your graveyard to the battlefield.
A:AB$ ChangeZone | Cost$ 5 B B | Origin$ Graveyard | Destination$ Library | ActivationZone$ Graveyard | Defined$ Self | SpellDescription$ Put CARDNAME on top of your library from your graveyard.
SVar:X:Count$xPaid
SVar:AIPreference:SacCost$Creature.token,Creature.cmcLE3
AI:RemoveDeck:All
Oracle:{3}{B}{B}, {T}, Sacrifice X other creatures: Return X target creature cards from your graveyard to the battlefield.\n{5}{B}{B}: Put Champion of Stray Souls on top of your library from your graveyard.

View File

@@ -7,6 +7,6 @@ A:AB$ Effect | Cost$ AddCounter<2/LOYALTY> | Planeswalker$ True | EffectOwner$ P
SVar:BOTTrig:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Command | Execute$ ChandraDmg | TriggerDescription$ At the beginning of your upkeep, this emblem deals 1 damage to you.
SVar:ChandraDmg:DB$ DealDamage | Defined$ TriggeredPlayer | NumDmg$ 1
A:AB$ DamageAll | Cost$ SubCounter<3/LOYALTY> | Planeswalker$ True | ValidCards$ Creature.nonElemental | NumDmg$ 3 | SpellDescription$ CARDNAME deals 3 damage to each non-Elemental creature.
A:AB$ DealDamage | Cost$ SubCounter<X/LOYALTY> | Planeswalker$ True | Ultimate$ True | ValidTgts$ Creature,Planeswalker | NumDmg$ ChosenX | References$ X | ReplaceDyingDefined$ Targeted | SpellDescription$ CARDNAME deals X damage to target creature or planeswalker. If a permanent dealt damage this way would die this turn, exile it instead.
SVar:X:XChoice
A:AB$ DealDamage | Cost$ SubCounter<X/LOYALTY> | Planeswalker$ True | Ultimate$ True | ValidTgts$ Creature,Planeswalker | NumDmg$ X | References$ X | ReplaceDyingDefined$ Targeted | SpellDescription$ CARDNAME deals X damage to target creature or planeswalker. If a permanent dealt damage this way would die this turn, exile it instead.
SVar:X:Count$xPaid
Oracle:This spell can't be countered.\n[+2]: Each opponent gets an emblem with "At the beginning of your upkeep, this emblem deals 1 damage to you."\n[-3]: Chandra, Awakened Inferno deals 3 damage to each non-Elemental creature.\n[-X]: Chandra, Awakened Inferno deals X damage to target creature or planeswalker. If a permanent dealt damage this way would die this turn, exile it instead.

View File

@@ -7,9 +7,8 @@ A:AB$ Discard | Cost$ AddCounter<0/LOYALTY> | Planeswalker$ True | Defined$ You
SVar:DBDraw:DB$ Draw | NumCards$ Y | Defined$ You | SubAbility$ DBCleanup | SpellDescription$ Draw that many cards | References$ Y
SVar:Y:Remembered$Amount.Plus.1
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
A:AB$ DamageAll | Cost$ SubCounter<X/LOYALTY> | NumDmg$ ChosenX | References$ X | ValidCards$ Creature | Planeswalker$ True | Ultimate$ True | ValidDescription$ each creature. | SpellDescription$ CARDNAME deals X damage to each creature.
SVar:X:XChoice
A:AB$ DamageAll | Cost$ SubCounter<X/LOYALTY> | NumDmg$ X | References$ X | ValidCards$ Creature | Planeswalker$ True | Ultimate$ True | ValidDescription$ each creature. | SpellDescription$ CARDNAME deals X damage to each creature.
SVar:X:Count$xPaid
DeckHas:Ability$Token
SVar:PlayMain1:ALWAYS
SVar:Picture:http://www.wizards.com/global/images/magic/general/chandra_flamecaller.jpg
Oracle:[+1]: Create two 3/1 red Elemental creature tokens with haste. Exile them at the beginning of the next end step.\n[0]: Discard all the cards in your hand, then draw that many cards plus one.\n[X]: Chandra, Flamecaller deals X damage to each creature.

View File

@@ -3,10 +3,9 @@ ManaCost:3 R R
Types:Legendary Planeswalker Chandra
Loyalty:6
A:AB$ DealDamage | Cost$ AddCounter<1/LOYALTY> | ValidTgts$ Player,Planeswalker | TgtPrompt$ Select target player or planeswalker | NumDmg$ 1 | Planeswalker$ True | SpellDescription$ CARDNAME deals 1 damage to target player or planeswalker.
A:AB$ DealDamage | Cost$ SubCounter<X/LOYALTY> | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ ChosenX | Planeswalker$ True | References$ X | SpellDescription$ CARDNAME deals X damage to target creature.
A:AB$ DealDamage | Cost$ SubCounter<X/LOYALTY> | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ X | Planeswalker$ True | References$ X | SpellDescription$ CARDNAME deals X damage to target creature.
A:AB$ DealDamage | Cost$ SubCounter<8/LOYALTY> | Planeswalker$ True | Ultimate$ True | ValidTgts$ Player,Planeswalker | TgtPrompt$ Select a player or planeswalker | NumDmg$ 10 | SubAbility$ DmgAll | DamageMap$ True | SpellDescription$ CARDNAME deals 10 damage to target player or planeswalker and each creature that player or that planeswalker's controller controls.
SVar:DmgAll:DB$ DamageAll | NumDmg$ 10 | ValidCards$ Creature.ControlledBy TargetedOrController | SubAbility$ DBDamageResolve
SVar:DBDamageResolve:DB$ DamageResolve
SVar:X:XChoice
SVar:Picture:http://resources.wizards.com/magic/cards/lrw/en/card140176.jpg
SVar:X:Count$xPaid
Oracle:[+1]: Chandra Nalaar deals 1 damage to target player or planeswalker.\n[-X]: Chandra Nalaar deals X damage to target creature.\n[-8]: Chandra Nalaar deals 10 damage to target player or planeswalker and each creature that player or that planeswalker's controller controls.

View File

@@ -1,7 +1,7 @@
Name:Channeled Force
ManaCost:2 U R
Types:Instant
A:SP$ Draw | Cost$ 2 U R Discard<X/Card/card> | CostDesc$ As an additional cost to cast this spell, discard X cards. | NumCards$ ChosenX | ValidTgts$ Player | TgtPrompt$ Choose a player | References$ X | SubAbility$ DBDamage | SpellDescription$ Target player draws X cards. CARDNAME deals X damage to up to one target creature or planeswalker.
SVar:DBDamage:DB$ DealDamage | ValidTgts$ Creature,Planeswalker | TargetMin$ 0 | TargetMax$ 1 | TgtPrompt$ Select target creature or planeswalker. | NumDmg$ ChosenX | References$ X
SVar:X:XChoice
A:SP$ Draw | Cost$ 2 U R Discard<X/Card/card> | CostDesc$ As an additional cost to cast this spell, discard X cards. | NumCards$ X | ValidTgts$ Player | TgtPrompt$ Choose a player | References$ X | SubAbility$ DBDamage | SpellDescription$ Target player draws X cards. CARDNAME deals X damage to up to one target creature or planeswalker.
SVar:DBDamage:DB$ DealDamage | ValidTgts$ Creature,Planeswalker | TargetMin$ 0 | TargetMax$ 1 | TgtPrompt$ Select target creature or planeswalker. | NumDmg$ X | References$ X
SVar:X:Count$xPaid
Oracle:As an additional cost to cast this spell, discard X cards.\nTarget player draws X cards. Channeled Force deals X damage to up to one target creature or planeswalker.

View File

@@ -3,8 +3,7 @@ ManaCost:no cost
Types:Land
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.
A:AB$ PutCounter | Cost$ 1 T | CounterType$ STORAGE | CounterNum$ 1 | SpellDescription$ Put a storage counter on CARDNAME.
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ Combo W U B R G | Amount$ ChosenX | RestrictValid$ Card.Dragon,Activated.Dragon | CostDesc$ {T}, Remove X storage counters from CARDNAME: | References$ X | SpellDescription$ Add X mana in any combination of colors. Spend this mana only to cast Dragon spells or activate abilities of Dragons.
SVar:X:XChoice
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ Combo W U B R G | Amount$ X | RestrictValid$ Card.Dragon,Activated.Dragon | CostDesc$ {T}, Remove X storage counters from CARDNAME: | References$ X | SpellDescription$ Add X mana in any combination of colors. Spend this mana only to cast Dragon spells or activate abilities of Dragons.
SVar:X:Count$xPaid
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/crucible_of_the_spirit_dragon.jpg
Oracle:{T}: Add {C}.\n{1}, {T}: Put a storage counter on Crucible of the Spirit Dragon.\n{T}, Remove X storage counters from Crucible of the Spirit Dragon: Add X mana in any combination of colors. Spend this mana only to cast Dragon spells or activate abilities of Dragons.

View File

@@ -3,8 +3,7 @@ ManaCost:B
Types:Creature Human Assassin
PT:1/1
A:AB$ PutCounter | Cost$ B T PayLife<1> | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a +1/+1 counter on CARDNAME.
A:AB$ DealDamage | Cost$ 2 B T SubCounter<X/P1P1> | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ ChosenX | References$ X | SpellDescription$ CARDNAME deals X damage to target creature.
SVar:X:XChoice
A:AB$ DealDamage | Cost$ 2 B T SubCounter<X/P1P1> | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ X | References$ X | SpellDescription$ CARDNAME deals X damage to target creature.
SVar:X:Count$xPaid
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/cruel_sadist.jpg
Oracle:{B}, {T}, Pay 1 life: Put a +1/+1 counter on Cruel Sadist.\n{2}{B}, {T}, Remove X +1/+1 counters from Cruel Sadist: It deals X damage to target creature.

View File

@@ -2,10 +2,10 @@ Name:Dargo, the Shipwrecker
ManaCost:6 R
Types:Legendary Creature Giant Pirate
PT:7/5
A:SP$ PermanentCreature | Announce$ X | Cost$ 6 R Sac<X/Artifact;Creature/artifacts or creatures> | AILogic$ SacToReduceCost | References$ X,Y | CostDesc$ As an additional cost to cast this spell, you may sacrifice any number of artifacts and/or creatures. | SpellDescription$
S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ Y | EffectZone$ All | References$ Y | Description$ This spell costs {2} less to cast for each permanent sacrificed this way and {2} less to cast for each other artifact or creature you've sacrificed this turn.
A:SP$ PermanentCreature | Cost$ 6 R Sac<X/Artifact;Creature/artifacts or creatures> | AILogic$ SacToReduceCost | References$ X,Y | CostDesc$ As an additional cost to cast this spell, you may sacrifice any number of artifacts and/or creatures. | SpellDescription$
S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ Y | EffectZone$ All | References$ Y | Relative$ True | Description$ This spell costs {2} less to cast for each permanent sacrificed this way and {2} less to cast for each other artifact or creature you've sacrificed this turn.
S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ Z | EffectZone$ All | References$ Z | Secondary$ True | Description$ This spell costs {2} less to cast for each permanent sacrificed this way and {2} less to cast for each other artifact or creature you've sacrificed this turn.
SVar:X:XChoice
SVar:X:Count$xPaid
SVar:Y:SVar$X/Times.2
SVar:Z:Count$SacrificedThisTurn Artifact,Creature/Times.2
SVar:AIPreference:SacCost$Creature.token,Creature.cmcLE2

View File

@@ -3,8 +3,7 @@ ManaCost:no cost
Types:Land
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.
A:AB$ PutCounter | Cost$ 1 T | CounterType$ STORAGE | CounterNum$ 1 | SpellDescription$ Put a storage counter on CARDNAME.
A:AB$ Mana | Cost$ 1 SubCounter<X/STORAGE> | Produced$ Combo U B | Amount$ ChosenX | CostDesc$ {1}, Remove X storage counters from CARDNAME: | References$ X | SpellDescription$ Add X mana in any combination of {U} and/or {B}.
SVar:X:XChoice
A:AB$ Mana | Cost$ 1 SubCounter<X/STORAGE> | Produced$ Combo U B | Amount$ X | CostDesc$ {1}, Remove X storage counters from CARDNAME: | References$ X | SpellDescription$ Add X mana in any combination of {U} and/or {B}.
SVar:X:Count$xPaid
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/dreadship_reef.jpg
Oracle:{T}: Add {C}.\n{1}, {T}: Put a storage counter on Dreadship Reef.\n{1}, Remove X storage counters from Dreadship Reef: Add X mana in any combination of {U} and/or {B}.

View File

@@ -5,9 +5,7 @@ K:CARDNAME enters the battlefield tapped.
K:You may choose not to untap CARDNAME during your untap step.
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | IsPresent$ Card.Self+tapped | Execute$ TrigStore | TriggerDescription$ At the beginning of your upkeep, if CARDNAME is tapped, put a storage counter on it.
SVar:TrigStore:DB$PutCounter | Defined$ Self | CounterType$ STORAGE | CounterNum$ 1
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ R | Amount$ ChosenX | CostDesc$ {T}, Remove any number of storage counters from CARDNAME: | References$ X | SpellDescription$ Add {R} for each storage counter removed this way.
SVar:X:XChoice
#ChosenX SVar created by Cost payment
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ R | Amount$ X | CostDesc$ {T}, Remove any number of storage counters from CARDNAME: | References$ X | AILogic$ ManaRitualBattery | SpellDescription$ Add {R} for each storage counter removed this way.
SVar:X:Count$xPaid
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/dwarven_hold.jpg
Oracle:Dwarven Hold enters the battlefield tapped.\nYou may choose not to untap Dwarven Hold during your untap step.\nAt the beginning of your upkeep, if Dwarven Hold is tapped, put a storage counter on it.\n{T}, Remove any number of storage counters from Dwarven Hold: Add {R} for each storage counter removed this way.

View File

@@ -1,6 +1,7 @@
Name:Eliminate the Competition
ManaCost:4 B
Types:Sorcery
A:SP$ Destroy | Announce$ X | Cost$ 4 B Sac<X/Creature/creature(s)> | CostDesc$ As an additional cost to cast this spell, sacrifice X creatures. | TargetMin$ X | TargetMax$ X | ValidTgts$ Creature | References$ X | TgtPrompt$ Select X target creatures | AIMaxTgtsCount$ Valid Creature.YouCtrl+cmcLE2 | SpellDescription$ Destroy X target creatures.
A:SP$ Destroy | Cost$ 4 B Sac<X/Creature/creature(s)> | CostDesc$ As an additional cost to cast this spell, sacrifice X creatures. | TargetMin$ X | TargetMax$ X | ValidTgts$ Creature | References$ X | TgtPrompt$ Select X target creatures | AIMaxTgtsCount$ Valid Creature.YouCtrl+cmcLE2 | SpellDescription$ Destroy X target creatures.
SVar:X:Count$xPaid
SVar:AIPreference:SacCost$Creature.token,Creature.cmcLE2
Oracle:As an additional cost to cast this spell, sacrifice X creatures.\nDestroy X target creatures.

View File

@@ -2,11 +2,10 @@ Name:Emrakul's Evangel
ManaCost:2 G
Types:Creature Human Horror
PT:3/2
A:AB$ Token | Cost$ T Sac<X/Creature.Other+nonEldrazi/other non-Eldrazi creatures> Sac<1/CARDNAME> | Announce$ X | TokenAmount$ Y | TokenScript$ c_3_2_eldrazi_horror | TokenOwner$ You | LegacyImage$ c 3 2 eldrazi horror emn | References$ Y | SpellDescription$ Create a 3/2 colorless Eldrazi Horror creature token for each creature sacrificed this way. | CostDesc$ {T}, Sacrifice CARDNAME and any number of other non-Eldrazi creatures:
A:AB$ Token | Cost$ T Sac<X/Creature.Other+nonEldrazi/other non-Eldrazi creatures> Sac<1/CARDNAME> | TokenAmount$ Y | TokenScript$ c_3_2_eldrazi_horror | TokenOwner$ You | LegacyImage$ c 3 2 eldrazi horror emn | References$ Y | SpellDescription$ Create a 3/2 colorless Eldrazi Horror creature token for each creature sacrificed this way. | CostDesc$ {T}, Sacrifice CARDNAME and any number of other non-Eldrazi creatures:
SVar:Y:Sacrificed$Valid Creature
SVar:X:XChoice
SVar:X:Count$xPaid
DeckHints:Ability$Token & Type$Eldrazi|Horror
DeckHas:Ability$Token
DeckHas:Ability$Token & Ability$Sacrifice
SVar:AIPreference:SacCost$Creature.token
SVar:Picture:http://www.wizards.com/global/images/magic/general/emrakuls_evangel.jpg
Oracle:{T}, Sacrifice Emrakul's Evangel and any number of other non-Eldrazi creatures: Create a 3/2 colorless Eldrazi Horror creature token for each creature sacrificed this way.

View File

@@ -3,8 +3,6 @@ ManaCost:no cost
Types:Land
K:CARDNAME enters the battlefield tapped.
A:AB$ PutCounter | Cost$ T | Defined$ Self | CounterType$ STORAGE | CounterNum$ 1 | SpellDescription$ Put a storage counter on CARDNAME.
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ W | Amount$ ChosenX | CostDesc$ {T}, Remove any number of storage counters from CARDNAME: | References$ X | AILogic$ ManaRitualBattery | AINoRecursiveCheck$ True | SpellDescription$ Add {W} for each storage counter removed this way.
SVar:X:XChoice
#ChosenX SVar created by Cost payment
SVar:Picture:http://www.wizards.com/global/images/magic/general/fountain_of_cho.jpg
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ W | Amount$ X | CostDesc$ {T}, Remove any number of storage counters from CARDNAME: | References$ X | AILogic$ ManaRitualBattery | AINoRecursiveCheck$ True | SpellDescription$ Add {W} for each storage counter removed this way.
SVar:X:Count$xPaid
Oracle:Fountain of Cho enters the battlefield tapped.\n{T}: Put a storage counter on Fountain of Cho.\n{T}, Remove any number of storage counters from Fountain of Cho: Add {W} for each storage counter removed this way.

View File

@@ -3,8 +3,7 @@ ManaCost:no cost
Types:Land
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.
A:AB$ PutCounter | Cost$ 1 T | CounterType$ STORAGE | CounterNum$ 1 | SpellDescription$ Put a storage counter on CARDNAME.
A:AB$ Mana | Cost$ 1 SubCounter<X/STORAGE> | Produced$ Combo R G | Amount$ ChosenX | CostDesc$ {1}, Remove X storage counters from CARDNAME: | References$ X | SpellDescription$ Add X mana in any combination of {R} and/or {G}.
SVar:X:XChoice
A:AB$ Mana | Cost$ 1 SubCounter<X/STORAGE> | Produced$ Combo R G | Amount$ X | CostDesc$ {1}, Remove X storage counters from CARDNAME: | References$ X | SpellDescription$ Add X mana in any combination of {R} and/or {G}.
SVar:X:Count$xPaid
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/fungal_reaches.jpg
Oracle:{T}: Add {C}.\n{1}, {T}: Put a storage counter on Fungal Reaches.\n{1}, Remove X storage counters from Fungal Reaches: Add X mana in any combination of {R} and/or {G}.

View File

@@ -3,9 +3,7 @@ ManaCost:4
Types:Artifact
A:AB$ PutCounter | Cost$ 2 T | CounterType$ CHARGE | CounterNum$ 1 | SpellDescription$ Put a charge counter on CARDNAME.
A:AB$ Mana | Cost$ T SubCounter<X/CHARGE> | Produced$ G | Amount$ Y | CostDesc$ {T}, Remove any number of charge counters from CARDNAME: | References$ X,Y | AILogic$ ManaRitualBattery.1 | AINoRecursiveCheck$ True | SpellDescription$ Add {G}, then add an additional {G} for each charge counter removed this way.
SVar:Y:Number$1/Plus.ChosenX
SVar:X:XChoice
#ChosenX SVar created by Cost payment
SVar:Y:SVar$X/Plus.1
SVar:X:Count$xPaid
AI:RemoveDeck:Random
SVar:Picture:http://www.wizards.com/global/images/magic/general/green_mana_battery.jpg
Oracle:{2}, {T}: Put a charge counter on Green Mana Battery.\n{T}, Remove any number of charge counters from Green Mana Battery: Add {G}, then add an additional {G} for each charge counter removed this way.

View File

@@ -5,9 +5,7 @@ K:CARDNAME enters the battlefield tapped.
K:You may choose not to untap CARDNAME during your untap step.
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | IsPresent$ Card.Self+tapped | Execute$ TrigStore | TriggerDescription$ At the beginning of your upkeep, if CARDNAME is tapped, put a storage counter on it.
SVar:TrigStore:DB$PutCounter | Defined$ Self | CounterType$ STORAGE | CounterNum$ 1
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ G | Amount$ ChosenX | CostDesc$ {T}, Remove any number of storage counters from CARDNAME: | References$ X | SpellDescription$ Add {G} for each storage counter removed this way.
SVar:X:XChoice
#ChosenX SVar created by Cost payment
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ G | Amount$ X | CostDesc$ {T}, Remove any number of storage counters from CARDNAME: | References$ X | AILogic$ ManaRitualBattery | SpellDescription$ Add {G} for each storage counter removed this way.
SVar:X:Count$xPaid
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/hollow_trees.jpg
Oracle:Hollow Trees enters the battlefield tapped.\nYou may choose not to untap Hollow Trees during your untap step.\nAt the beginning of your upkeep, if Hollow Trees is tapped, put a storage counter on it.\n{T}, Remove any number of storage counters from Hollow Trees: Add {G} for each storage counter removed this way.

View File

@@ -5,9 +5,7 @@ K:CARDNAME enters the battlefield tapped.
K:You may choose not to untap CARDNAME during your untap step.
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | IsPresent$ Card.Self+tapped | Execute$ TrigStore | TriggerDescription$ At the beginning of your upkeep, if CARDNAME is tapped, put a storage counter on it.
SVar:TrigStore:DB$PutCounter | Defined$ Self | CounterType$ STORAGE | CounterNum$ 1
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ W | Amount$ ChosenX | CostDesc$ {T}, Remove any number of storage counters from CARDNAME: | References$ X | SpellDescription$ Add {W} for each storage counter removed this way.
SVar:X:XChoice
#ChosenX SVar created by Cost payment
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ W | Amount$ X | CostDesc$ {T}, Remove any number of storage counters from CARDNAME: | References$ X | AILogic$ ManaRitualBattery | SpellDescription$ Add {W} for each storage counter removed this way.
SVar:X:Count$xPaid
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/icatian_store.jpg
Oracle:Icatian Store enters the battlefield tapped.\nYou may choose not to untap Icatian Store during your untap step.\nAt the beginning of your upkeep, if Icatian Store is tapped, put a storage counter on it.\n{T}, Remove any number of storage counters from Icatian Store: Add {W} for each storage counter removed this way.

View File

@@ -2,12 +2,10 @@ Name:Infused Arrows
ManaCost:4
Types:Artifact
K:Sunburst
#ChosenX SVar created by Cost payment
A:AB$ Pump | Cost$ T SubCounter<X/CHARGE> | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ -ChosenX | NumDef$ -ChosenX | References$ X | SpellDescription$ Target creature gets -X/-X until end of turn.
SVar:X:XChoice
A:AB$ Pump | Cost$ T SubCounter<X/CHARGE> | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ -X | NumDef$ -X | References$ X | SpellDescription$ Target creature gets -X/-X until end of turn.
SVar:X:Count$xPaid
AI:RemoveDeck:All
SVar:NeedsToPlayVar:Z GE1
SVar:Z:Count$UniqueManaColorsProduced.ByUntappedSources
DeckHints:Ability$Proliferate
SVar:Picture:http://www.wizards.com/global/images/magic/general/infused_arrows.jpg
Oracle:Sunburst (This enters the battlefield with a charge counter on it for each color of mana spent to cast it.)\n{T}, Remove X charge counters from Infused Arrows: Target creature gets -X/-X until end of turn.

View File

@@ -8,8 +8,8 @@ A:AB$ Effect | Cost$ AddCounter<0/LOYALTY> | Planeswalker$ True | Duration$ Unti
SVar:TripleCombatDamage:Event$ DamageDone | ValidSource$ Creature.IsRemembered | CombatDamage$ True | ValidTarget$ Player.Opponent | ReplaceWith$ DmgTriple | Description$ Choose target creature. Until your next turn, if that creature would deal combat damage to one of your opponents, it deals triple that damage to that player instead.
SVar:DmgTriple:DB$ ReplaceEffect | VarName$ DamageAmount | VarValue$ Z | References$ Z
SVar:Z:ReplaceCount$DamageAmount/Thrice
A:AB$ DealDamage | Cost$ SubCounter<X/LOYALTY> | Planeswalker$ True | Ultimate$ True | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Choose up to three targets | TargetMin$ 0 | TargetMax$ 3 | NumDmg$ ChosenX | References$ X | SpellDescription$ CARDNAME deals X damage to each of up to three targets.
SVar:X:XChoice
A:AB$ DealDamage | Cost$ SubCounter<X/LOYALTY> | Planeswalker$ True | Ultimate$ True | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Choose up to three targets | TargetMin$ 0 | TargetMax$ 3 | NumDmg$ X | References$ X | SpellDescription$ CARDNAME deals X damage to each of up to three targets.
SVar:X:Count$xPaid
AI:RemoveDeck:NonCommander
Text:CARDNAME can be your commander.
K:Partner

View File

@@ -5,10 +5,9 @@ PT:3/3
K:Partner:Regna, the Redeemer:Regna
# TODO: AILogic$ DoSacrifice is a placeholder which signals AiCostDecision that the API knows how to properly determine
# the number of creatures to sacrifice. Currently DrawAi doesn't handle it too optimally and this can be improved.
A:AB$Draw | Cost$ B Sac<X/Creature/creatures> | NumCards$ ChosenX | ValidTgts$ Player | TgtPrompt$ Choose a player | References$ X | SubAbility$ DBGainLife | AILogic$ DoSacrifice | SpellDescription$ Target player draws X cards and gains X life. Put X +1/+1 counters on CARDNAME.
SVar:DBGainLife:DB$GainLife | Defined$ Targeted | LifeAmount$ ChosenX | SubAbility$ DBPutCounter
SVar:DBPutCounter:DB$PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ ChosenX
SVar:X:XChoice
A:AB$ Draw | Cost$ B Sac<X/Creature/creatures> | NumCards$ X | ValidTgts$ Player | TgtPrompt$ Choose a player | References$ X | SubAbility$ DBGainLife | AILogic$ DoSacrifice | SpellDescription$ Target player draws X cards and gains X life. Put X +1/+1 counters on CARDNAME.
SVar:DBGainLife:DB$ GainLife | Defined$ Targeted | LifeAmount$ X | SubAbility$ DBPutCounter | References$ X
SVar:DBPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ X | References$ X
SVar:X:Count$xPaid
DeckHints:Name$Regna, the Redeemer
SVar:Picture:http://www.wizards.com/global/images/magic/general/krav_the_unredeemed.jpg
Oracle:Partner with Regna, the Redeemer (When this creature enters the battlefield, target player may put Regna into their hand from their library, then shuffle.)\n{B}, Sacrifice X creatures: Target player draws X cards and gains X life. Put X +1/+1 counters on Krav, the Unredeemed.

View File

@@ -3,7 +3,6 @@ ManaCost:no cost
Types:Land
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.
A:AB$ PutCounter | Cost$ 1 T | CounterType$ STORAGE | CounterNum$ 1 | SpellDescription$ Put a storage counter on CARDNAME.
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ C | Amount$ ChosenX | CostDesc$ {T}, Remove X storage counters from CARDNAME: | References$ X | AILogic$ ManaRitualBattery | AINoRecursiveCheck$ True | SpellDescription$ Add {C} equal to the amount of counters removed.
SVar:X:XChoice
SVar:Picture:http://www.wizards.com/global/images/magic/general/mage_ring_network.jpg
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ C | Amount$ X | CostDesc$ {T}, Remove X storage counters from CARDNAME: | References$ X | AILogic$ ManaRitualBattery | AINoRecursiveCheck$ True | SpellDescription$ Add {C} equal to the amount of counters removed.
SVar:X:Count$xPaid
Oracle:{T}: Add {C}.\n{1}, {T}: Put a storage counter on Mage-Ring Network.\n{T}, Remove X storage counters from Mage-Ring Network: Add {C} equal to the amount of counters removed.

View File

@@ -4,11 +4,10 @@ Types:Legendary Creature Elemental Beast
PT:0/0
K:etbCounter:P1P1:Y:no Condition:CARDNAME enters the battlefield with a number of +1/+1 counters on it equal to the amount of mana spent to cast it.
SVar:Y:Count$CastTotalManaSpent
A:AB$ Charm | Cost$ X SubCounter<X/P1P1> | Announce$ X | XCantBe0$ True | Choices$ MarathCounters,MarathDmg,MarathToken | Defined$ You
A:AB$ Charm | Cost$ XCantBe0 X SubCounter<X/P1P1> | Announce$ X | Choices$ MarathCounters,MarathDmg,MarathToken | Defined$ You
SVar:MarathCounters:DB$ PutCounter | ValidTgts$ Creature | CounterType$ P1P1 | CounterNum$ Z | References$ Z | SpellDescription$ Put X +1/+1 counters on target creature. X can't be 0.
SVar:MarathDmg:DB$ DealDamage | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ Z | References$ Z | SpellDescription$ CARDNAME deals X damage to any target. X can't be 0.
SVar:MarathToken:DB$ Token | TokenAmount$ 1 | TokenScript$ g_x_x_elemental | TokenOwner$ You | TokenPower$ Z | TokenToughness$ Z | References$ Z | LegacyImage$ g x x elemental c13 | SpellDescription$ Create an X/X green Elemental creature token. X can't be 0.
SVar:Z:SVar$CostCountersRemoved
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/marath_will_of_the_wild.jpg
Oracle:Marath, Will of the Wild enters the battlefield with a number of +1/+1 counters on it equal to the amount of mana spent to cast it.\n{X}, Remove X +1/+1 counters from Marath: Choose one —\n• Put X +1/+1 counters on target creature. X can't be 0.\n• Marath deals X damage to any target. X can't be 0.\n• Create an X/X green Elemental creature token. X can't be 0.

View File

@@ -3,8 +3,6 @@ ManaCost:no cost
Types:Land
K:CARDNAME enters the battlefield tapped.
A:AB$ PutCounter | Cost$ T | Defined$ Self | CounterType$ STORAGE | CounterNum$ 1 | SpellDescription$ Put a storage counter on CARDNAME.
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ R | Amount$ ChosenX | References$ X | CostDesc$ {T}, Remove any number of storage counters from CARDNAME: | AILogic$ ManaRitualBattery | AINoRecursiveCheck$ True | SpellDescription$ Add {R} for each storage counter removed this way.
SVar:X:XChoice
#ChosenX SVar created by Cost payment
SVar:Picture:http://www.wizards.com/global/images/magic/general/mercadian_bazaar.jpg
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ R | Amount$ X | References$ X | CostDesc$ {T}, Remove any number of storage counters from CARDNAME: | AILogic$ ManaRitualBattery | AINoRecursiveCheck$ True | SpellDescription$ Add {R} for each storage counter removed this way.
SVar:X:Count$xPaid
Oracle:Mercadian Bazaar enters the battlefield tapped.\n{T}: Put a storage counter on Mercadian Bazaar.\n{T}, Remove any number of storage counters from Mercadian Bazaar: Add {R} for each storage counter removed this way.

View File

@@ -2,8 +2,7 @@ Name:Mercadian Lift
ManaCost:2
Types:Artifact
A:AB$ PutCounter | Cost$ 1 T | CounterType$ WINCH | CounterNum$ 1 | SpellDescription$ Put a winch counter on CARDNAME.
A:AB$ ChangeZone | Cost$ T SubCounter<X/WINCH> | ChangeNum$ 1 | ChangeType$ Creature.cmcEQChosenX | Origin$ Hand | Destination$ Battlefield | References$ X | Optional$ True | SpellDescription$ You may put a creature card with converted mana cost X from your hand onto the battlefield.
SVar:X:XChoice
A:AB$ ChangeZone | Cost$ T SubCounter<X/WINCH> | ChangeNum$ 1 | ChangeType$ Creature.cmcEQX | Origin$ Hand | Destination$ Battlefield | References$ X | Optional$ True | SpellDescription$ You may put a creature card with converted mana cost X from your hand onto the battlefield.
SVar:X:Count$xPaid
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/mercadian_lift.jpg
Oracle:{1}, {T}: Put a winch counter on Mercadian Lift.\n{T}, Remove X winch counters from Mercadian Lift: You may put a creature card with converted mana cost X from your hand onto the battlefield.

View File

@@ -3,8 +3,7 @@ ManaCost:no cost
Types:Land
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.
A:AB$ PutCounter | Cost$ 1 T | CounterType$ STORAGE | CounterNum$ 1 | SpellDescription$ Put a storage counter on CARDNAME.
A:AB$ Mana | Cost$ 1 SubCounter<X/STORAGE> | Produced$ Combo B R | Amount$ ChosenX | CostDesc$ {1}, Remove X storage counters from CARDNAME: | References$ X | SpellDescription$ Add X mana in any combination of {B} and/or {R}.
SVar:X:XChoice
A:AB$ Mana | Cost$ 1 SubCounter<X/STORAGE> | Produced$ Combo B R | Amount$ X | CostDesc$ {1}, Remove X storage counters from CARDNAME: | References$ X | SpellDescription$ Add X mana in any combination of {B} and/or {R}.
SVar:X:Count$xPaid
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/molten_slagheap.jpg
Oracle:{T}: Add {C}.\n{1}, {T}: Put a storage counter on Molten Slagheap.\n{1}, Remove X storage counters from Molten Slagheap: Add X mana in any combination of {B} and/or {R}.

View File

@@ -4,6 +4,6 @@ Types:Legendary Planeswalker Nahiri
Loyalty:6
S:Mode$ Continuous | Affected$ Creature.YouCtrl | EffectZone$ Battlefield | AddKeyword$ First Strike | Condition$ PlayerTurn | Description$ As long as it's your turn, creatures you control have first strike and equip abilities you activate cost {1} less to activate.
S:Mode$ ReduceCost | ValidCard$ Card | ValidSpell$ Activated.Equip | Activator$ You | Amount$ 1 | Condition$ PlayerTurn | Secondary$ True | Description$ Equip abilities you activate cost {1} less to activate.
A:AB$ DealDamage | Cost$ SubCounter<X/LOYALTY> | Planeswalker$ True | ValidTgts$ Creature.tapped | TgtPrompt$ Select target tapped creature | NumDmg$ ChosenX | References$ X | SpellDescription$ CARDNAME deals X damage to target tapped creature.
SVar:X:XChoice
A:AB$ DealDamage | Cost$ SubCounter<X/LOYALTY> | Planeswalker$ True | ValidTgts$ Creature.tapped | TgtPrompt$ Select target tapped creature | NumDmg$ X | References$ X | SpellDescription$ CARDNAME deals X damage to target tapped creature.
SVar:X:Count$xPaid
Oracle:As long as it's your turn, creatures you control have first strike and equip abilities you activate cost {1} less to activate.\n-X: Nahiri, Storm of Stone deals X damage to target tapped creature.

View File

@@ -3,9 +3,8 @@ ManaCost:2 B B
Types:Enchantment
T:Mode$ DamageDone | ValidSource$ Card.YouCtrl,Emblem.YouCtrl | ValidTarget$ Player.Other | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever a source you control deals damage to another player, put that many theft counters on CARDNAME.
SVar:TrigPutCounter:DB$ PutCounter | CounterType$ THEFT | CounterNum$ Y | References$ Y
A:AB$ ChangeZone | Cost$ 2 B B SubCounter<X/THEFT> | Origin$ Library | Destination$ Hand | ChangeType$ Card.nonLand+YouCtrl+cmcEQChosenX | ChangeNum$ 1 | Reveal$ True | Shuffle$ True | References$ X | SpellDescription$ Search your library for a nonland card with converted mana cost X, reveal it, put it into your hand, then shuffle your library.
SVar:X:XChoice
A:AB$ ChangeZone | Cost$ 2 B B SubCounter<X/THEFT> | Origin$ Library | Destination$ Hand | ChangeType$ Card.nonLand+YouCtrl+cmcEQX | ChangeNum$ 1 | Reveal$ True | Shuffle$ True | References$ X | SpellDescription$ Search your library for a nonland card with converted mana cost X, reveal it, put it into your hand, then shuffle your library.
SVar:X:Count$xPaid
SVar:Y:TriggerCount$DamageAmount
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/night_dealings.jpg
Oracle:Whenever a source you control deals damage to another player, put that many theft counters on Night Dealings.\n{2}{B}{B}, Remove X theft counters from Night Dealings: Search your library for a nonland card with converted mana cost X, reveal it, put it into your hand, then shuffle your library.

View File

@@ -3,9 +3,7 @@ ManaCost:4
Types:Artifact
A:AB$ PutCounter | Cost$ 2 T | CounterType$ CHARGE | CounterNum$ 1 | SpellDescription$ Put a charge counter on CARDNAME.
A:AB$ Mana | Cost$ T SubCounter<X/CHARGE> | Produced$ R | Amount$ Y | References$ X,Y | CostDesc$ {T}, Remove any number of charge counters from CARDNAME: | AILogic$ ManaRitualBattery.1 | AINoRecursiveCheck$ True | SpellDescription$ Add {R}, then add an additional {R} for each charge counter removed this way.
SVar:Y:Number$1/Plus.ChosenX
SVar:X:XChoice
#ChosenX SVar created by Cost payment
SVar:Y:SVar$X/Plus.1
SVar:X:Count$xPaid
AI:RemoveDeck:Random
SVar:Picture:http://www.wizards.com/global/images/magic/general/red_mana_battery.jpg
Oracle:{2}, {T}: Put a charge counter on Red Mana Battery.\n{T}, Remove any number of charge counters from Red Mana Battery: Add {R}, then add an additional {R} for each charge counter removed this way.

View File

@@ -3,8 +3,6 @@ ManaCost:no cost
Types:Land
K:CARDNAME enters the battlefield tapped.
A:AB$ PutCounter | Cost$ T | Defined$ Self | CounterType$ STORAGE | CounterNum$ 1 | SpellDescription$ Put a storage counter on CARDNAME.
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ G | Amount$ ChosenX | CostDesc$ {T}, Remove any number of storage counters from CARDNAME: | References$ X | AILogic$ ManaRitualBattery | AINoRecursiveCheck$ True | SpellDescription$ Add {G} for each storage counter removed this way.
SVar:X:XChoice
#ChosenX SVar created by Cost payment
SVar:Picture:http://www.wizards.com/global/images/magic/general/rushwood_grove.jpg
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ G | Amount$ X | CostDesc$ {T}, Remove any number of storage counters from CARDNAME: | References$ X | AILogic$ ManaRitualBattery | AINoRecursiveCheck$ True | SpellDescription$ Add {G} for each storage counter removed this way.
SVar:X:Count$xPaid
Oracle:Rushwood Grove enters the battlefield tapped.\n{T}: Put a storage counter on Rushwood Grove.\n{T}, Remove any number of storage counters from Rushwood Grove: Add {G} for each storage counter removed this way.

View File

@@ -3,8 +3,7 @@ ManaCost:no cost
Types:Land
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.
A:AB$ PutCounter | Cost$ 1 T | CounterType$ STORAGE | CounterNum$ 1 | SpellDescription$ Put a storage counter on CARDNAME.
A:AB$ Mana | Cost$ 1 SubCounter<X/STORAGE> | Produced$ Combo G W | Amount$ ChosenX | CostDesc$ {1}, Remove X storage counters from CARDNAME: | References$ X | SpellDescription$ Add X mana in any combination of {G} and/or {W}.
SVar:X:XChoice
A:AB$ Mana | Cost$ 1 SubCounter<X/STORAGE> | Produced$ Combo G W | Amount$ X | CostDesc$ {1}, Remove X storage counters from CARDNAME: | References$ X | SpellDescription$ Add X mana in any combination of {G} and/or {W}.
SVar:X:Count$xPaid
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/saltcrusted_steppe.jpg
Oracle:{T}: Add {C}.\n{1}, {T}: Put a storage counter on Saltcrusted Steppe.\n{1}, Remove X storage counters from Saltcrusted Steppe: Add X mana in any combination of {G} and/or {W}.

View File

@@ -5,9 +5,7 @@ K:CARDNAME enters the battlefield tapped.
K:You may choose not to untap CARDNAME during your untap step.
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | IsPresent$ Card.Self+tapped | Execute$ TrigStore | TriggerDescription$ At the beginning of your upkeep, if CARDNAME is tapped, put a storage counter on it.
SVar:TrigStore:DB$PutCounter | Defined$ Self | CounterType$ STORAGE | CounterNum$ 1
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ U | Amount$ ChosenX | CostDesc$ {T}, Remove any number of storage counters from CARDNAME: | References$ X | SpellDescription$ Add {U} for each storage counter removed this way.
SVar:X:XChoice
#ChosenX SVar created by Cost payment
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ U | Amount$ X | CostDesc$ {T}, Remove any number of storage counters from CARDNAME: | References$ X | AILogic$ ManaRitualBattery | SpellDescription$ Add {U} for each storage counter removed this way.
SVar:X:Count$xPaid
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/sand_silos.jpg
Oracle:Sand Silos enters the battlefield tapped.\nYou may choose not to untap Sand Silos during your untap step.\nAt the beginning of your upkeep, if Sand Silos is tapped, put a storage counter on it.\n{T}, Remove any number of storage counters from Sand Silos: Add {U} for each storage counter removed this way.

View File

@@ -3,8 +3,6 @@ ManaCost:no cost
Types:Land
K:CARDNAME enters the battlefield tapped.
A:AB$ PutCounter | Cost$ T | Defined$ Self | CounterType$ STORAGE | CounterNum$ 1 | SpellDescription$ Put a storage counter on CARDNAME.
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ U | Amount$ ChosenX | CostDesc$ {T}, Remove any number of storage counters from CARDNAME: | References$ X | AILogic$ ManaRitualBattery | AINoRecursiveCheck$ True | SpellDescription$ Add {U} for each storage counter removed this way.
SVar:X:XChoice
#ChosenX SVar created by Cost payment
SVar:Picture:http://www.wizards.com/global/images/magic/general/saprazzan_cove.jpg
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ U | Amount$ X | CostDesc$ {T}, Remove any number of storage counters from CARDNAME: | References$ X | AILogic$ ManaRitualBattery | AINoRecursiveCheck$ True | SpellDescription$ Add {U} for each storage counter removed this way.
SVar:X:Count$xPaid
Oracle:Saprazzan Cove enters the battlefield tapped.\n{T}: Put a storage counter on Saprazzan Cove.\n{T}, Remove any number of storage counters from Saprazzan Cove: Add {U} for each storage counter removed this way.

View File

@@ -3,10 +3,9 @@ ManaCost:1 U U
Types:Creature Mutant Wizard
PT:0/1
K:Evolve
A:AB$ GainControl | Announce$ X | XCantBe0$ True | Cost$ T SubCounter<X/P1P1> | ValidTgts$ Creature.powerLEX | TgtPrompt$ Select target with power less than or equal to the number of +1/+1 counters removed this way | SpellDescription$ Gain control of target creature with power less than or equal to the number of +1/+1 counters removed this way.
A:AB$ GainControl | Cost$ XCantBe0 T SubCounter<X/P1P1> | ValidTgts$ Creature.powerLEX | TgtPrompt$ Select target with power less than or equal to the number of +1/+1 counters removed this way | SpellDescription$ Gain control of target creature with power less than or equal to the number of +1/+1 counters removed this way.
SVar:X:Count$xPaid
AI:RemoveDeck:All
DeckHas:Ability$Counters
DeckHints:Ability$Counters
SVar:Picture:http://www.wizards.com/global/images/magic/general/simic_manipulator.jpg
Oracle:Evolve (Whenever a creature enters the battlefield under your control, if that creature has greater power or toughness than this creature, put a +1/+1 counter on this creature.)\n{T}, Remove one or more +1/+1 counters from Simic Manipulator: Gain control of target creature with power less than or equal to the number of +1/+1 counters removed this way.

View File

@@ -6,10 +6,9 @@ A:AB$ Dig | Cost$ AddCounter<1/LOYALTY> | DigNum$ 1 | Reveal$ True | ChangeNum$
SVar:DBLoseLife:DB$ LoseLife | LifeAmount$ Y | Defined$ Opponent | SubAbility$ DBCleanup | References$ Y
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:Y:Remembered$CardManaCost
A:AB$ DealDamage | Cost$ SubCounter<X/LOYALTY> | ValidTgts$ Creature,Planeswalker | TgtPrompt$ Select target creature or planeswalker | NumDmg$ ChosenX | Planeswalker$ True | SubAbility$ DBGainLife | References$ X,ChosenX | SpellDescription$ CARDNAME deals X damage to target creature or planeswalker and you gain X life.
SVar:DBGainLife:DB$GainLife | LifeAmount$ ChosenX | Defined$ You | References$ ChosenX
SVar:X:XChoice
A:AB$ DealDamage | Cost$ SubCounter<X/LOYALTY> | ValidTgts$ Creature,Planeswalker | TgtPrompt$ Select target creature or planeswalker | NumDmg$ X | Planeswalker$ True | SubAbility$ DBGainLife | References$ X | SpellDescription$ CARDNAME deals X damage to target creature or planeswalker and you gain X life.
SVar:DBGainLife:DB$GainLife | LifeAmount$ X | Defined$ You | References$ X
SVar:X:Count$xPaid
A:AB$ Token | Cost$ SubCounter<9/LOYALTY> | Planeswalker$ True | TokenAmount$ Z | References$ Z | TokenScript$ b_1_1_vampire_knight_lifelink | TokenOwner$ You | LegacyImage$ b 1 1 vampire knight lifelink soi | Ultimate$ True | SpellDescription$ Create a number of 1/1 black Vampire Knight creature tokens with lifelink equal to the highest life total among all players.
SVar:Z:PlayerCountPlayers$HighestLifeTotal
SVar:Picture:http://www.wizards.com/global/images/magic/general/sorin_grim_nemesis.jpg
Oracle:[+1]: Reveal the top card of your library and put that card into your hand. Each opponent loses life equal to its converted mana cost.\n[-X]: Sorin, Grim Nemesis deals X damage to target creature or planeswalker and you gain X life.\n[-9]: Create a number of 1/1 black Vampire Knight creature tokens with lifelink equal to the highest life total among all players.

View File

@@ -3,8 +3,6 @@ ManaCost:no cost
Types:Land
K:CARDNAME enters the battlefield tapped.
A:AB$ PutCounter | Cost$ T | Defined$ Self | CounterType$ STORAGE | CounterNum$ 1 | SpellDescription$ Put a storage counter on CARDNAME.
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ B | Amount$ ChosenX | CostDesc$ {T}, Remove any number of storage counters from CARDNAME: | References$ X | AILogic$ ManaRitualBattery | AINoRecursiveCheck$ True | SpellDescription$ Add {B} for each storage counter removed this way.
SVar:X:XChoice
#ChosenX SVar created by Cost payment
SVar:Picture:http://www.wizards.com/global/images/magic/general/subterranean_hangar.jpg
A:AB$ Mana | Cost$ T SubCounter<X/STORAGE> | Produced$ B | Amount$ X | CostDesc$ {T}, Remove any number of storage counters from CARDNAME: | References$ X | AILogic$ ManaRitualBattery | AINoRecursiveCheck$ True | SpellDescription$ Add {B} for each storage counter removed this way.
SVar:X:Count$xPaid
Oracle:Subterranean Hangar enters the battlefield tapped.\n{T}: Put a storage counter on Subterranean Hangar.\n{T}, Remove any number of storage counters from Subterranean Hangar: Add {B} for each storage counter removed this way.

View File

@@ -5,10 +5,8 @@ PT:1/1
K:etbCounter:P1P1:3
K:Flying
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ At the beginning of your upkeep, you may remove any number of +1/+1 counters from CARDNAME. If you do, create that many 1/1 colorless Tetravite artifact creature tokens. They each have flying and "This creature can't be enchanted."
SVar:TrigToken:AB$Token | Cost$ SubCounter<X/P1P1> | References$ X | TokenAmount$ ChosenX | LegacyImage$ c 1 1 tetravite flying noenchant atq | TokenScript$ c_1_1_a_tetravite_flying_noenchant | TokenOwner$ You | RememberTokens$ True | SubAbility$ DBClearXChoice
SVar:DBClearXChoice:DB$ Cleanup | ClearChosenX$ True
SVar:X:XChoice
SVar:TrigToken:AB$Token | Cost$ SubCounter<X/P1P1> | References$ X | TokenAmount$ X | LegacyImage$ c 1 1 tetravite flying noenchant atq | TokenScript$ c_1_1_a_tetravite_flying_noenchant | TokenOwner$ You | RememberTokens$ True
SVar:X:Count$xPaid
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPutCounters | TriggerDescription$ At the beginning of your upkeep, you may exile any number of tokens created with CARDNAME. If you do, put that many +1/+1 counters on CARDNAME.
SVar:TrigPutCounters:AB$PutCounter | Cost$ Exile<X/Creature.IsRemembered/Tetravite> | References$ X | Defined$ Self | CounterType$ P1P1 | CounterNum$ ChosenX | CostDesc$ Exile any number of tokens put onto the battlefield with CARDNAME. | SubAbility$ DBClearXChoice
SVar:Picture:http://www.wizards.com/global/images/magic/general/tetravus.jpg
SVar:TrigPutCounters:AB$PutCounter | Cost$ Exile<X/Creature.IsRemembered/Tetravite> | References$ X | Defined$ Self | CounterType$ P1P1 | CounterNum$ X | CostDesc$ Exile any number of tokens put onto the battlefield with CARDNAME.
Oracle:Flying\nTetravus enters the battlefield with three +1/+1 counters on it.\nAt the beginning of your upkeep, you may remove any number of +1/+1 counters from Tetravus. If you do, create that many 1/1 colorless Tetravite artifact creature tokens. They each have flying and "This creature can't be enchanted."\nAt the beginning of your upkeep, you may exile any number of tokens created with Tetravus. If you do, put that many +1/+1 counters on Tetravus.

View File

@@ -3,11 +3,9 @@ ManaCost:3 U U
Types:Legendary Planeswalker Tezzeret
Loyalty:4
A:AB$ Untap | Cost$ AddCounter<1/LOYALTY> | ValidTgts$ Artifact | TgtPrompt$ Choose target artifact | TargetMin$ 0 | TargetMax$ 2 | Planeswalker$ True | SpellDescription$ Untap up to two target artifacts.
A:AB$ ChangeZone | Cost$ SubCounter<X/LOYALTY> | Origin$ Library | Destination$ Battlefield | ChangeType$ Artifact.cmcLEChosenX | References$ X | ChangeNum$ 1 | Shuffle$ True | Planeswalker$ True | SpellDescription$ Search your library for an artifact card with converted mana cost X or less, put it onto the battlefield, then shuffle your library.
A:AB$ ChangeZone | Cost$ SubCounter<X/LOYALTY> | Origin$ Library | Destination$ Battlefield | ChangeType$ Artifact.cmcLEX | References$ X | ChangeNum$ 1 | Shuffle$ True | Planeswalker$ True | SpellDescription$ Search your library for an artifact card with converted mana cost X or less, put it onto the battlefield, then shuffle your library.
A:AB$ AnimateAll | Cost$ SubCounter<5/LOYALTY> | Power$ 5 | Toughness$ 5 | Types$ Creature,Artifact | ValidCards$ Artifact.YouCtrl | Planeswalker$ True | Ultimate$ True | SpellDescription$ Artifacts you control become artifact creatures with base power and toughness 5/5 until end of turn.
#ChosenX SVar created by Cost payment
SVar:X:XChoice
SVar:X:Count$xPaid
AI:RemoveDeck:Random
DeckNeeds:Type$Artifact
SVar:Picture:http://www.wizards.com/global/images/magic/general/tezzeret_the_seeker.jpg
Oracle:[+1]: Untap up to two target artifacts.\n[-X]: Search your library for an artifact card with converted mana cost X or less, put it onto the battlefield, then shuffle your library.\n[-5]: Artifacts you control become artifact creatures with base power and toughness 5/5 until end of turn.

View File

@@ -2,10 +2,11 @@ Name:Torgaar, Famine Incarnate
ManaCost:6 B B
Types:Legendary Creature Avatar
PT:7/6
A:SP$ PermanentCreature | Cost$ 6 B B Sac<X/Creature> | Announce$ X | References$ X,Y | AILogic$ SacToReduceCost
S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ Y | EffectZone$ All | References$ Y | Description$ As an additional cost to cast this spell, you may sacrifice any number of creatures. This spell costs {2} less to cast for each creature sacrificed as an additional cost.
SVar:X:XChoice
A:SP$ PermanentCreature | Cost$ 6 B B Sac<X/Creature> | References$ X,Y | AILogic$ SacToReduceCost
S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ Y | EffectZone$ All | References$ X,Y | Relative$ True | Description$ As an additional cost to cast this spell, you may sacrifice any number of creatures. This spell costs {2} less to cast for each creature sacrificed as an additional cost.
SVar:X:Count$xPaid
SVar:Y:SVar$X/Times.2
SVar:AIPreference:SacCost$Creature.token,Creature.cmcLE2
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSetLife | TriggerDescription$ When CARDNAME enters the battlefield, up to one target player's life total becomes half their starting life total, rounded down.
SVar:TrigSetLife:DB$ SetLife | ValidTgts$ Player | LifeAmount$ HalfLife | TargetMin$ 0 | TargetMax$ 1 | References$ HalfLife
SVar:HalfLife:TargetedPlayer$StartingLife/HalfDown

View File

@@ -3,10 +3,9 @@ ManaCost:8
Types:Legendary Planeswalker Ugin
Loyalty:7
A:AB$ DealDamage | Cost$ AddCounter<2/LOYALTY> | Planeswalker$ True | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ 3 | SpellDescription$ CARDNAME deals 3 damage to any target.
A:AB$ ChangeZoneAll | Cost$ SubCounter<X/LOYALTY> | UseAllOriginZones$ True | Planeswalker$ True | ChangeType$ Permanent.nonColorless+cmcLEChosenX | References$ X | Origin$ Battlefield | Destination$ Exile | SpellDescription$ Exile each permanent with converted mana cost X or less that's one or more colors.
SVar:X:XChoice
A:AB$ ChangeZoneAll | Cost$ SubCounter<X/LOYALTY> | UseAllOriginZones$ True | Planeswalker$ True | ChangeType$ Permanent.nonColorless+cmcLEX | References$ X | Origin$ Battlefield | Destination$ Exile | SpellDescription$ Exile each permanent with converted mana cost X or less that's one or more colors.
SVar:X:Count$xPaid
A:AB$ GainLife | Cost$ SubCounter<10/LOYALTY> | Planeswalker$ True | Ultimate$ True | LifeAmount$ 7 | SubAbility$ DBDraw | SpellDescription$ You gain 7 life, draw seven cards, then put up to seven permanent cards from your hand onto the battlefield.
SVar:DBDraw:DB$ Draw | NumCards$ 7 | SubAbility$ DBChangeZone
SVar:DBChangeZone:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | ChangeType$ Permanent | ChangeNum$ 7
SVar:Picture:http://www.wizards.com/global/images/magic/general/ugin_the_spirit_dragon.jpg
Oracle:[+2]: Ugin, the Spirit Dragon deals 3 damage to any target.\n[-X]: Exile each permanent with converted mana cost X or less that's one or more colors.\n[-10]: You gain 7 life, draw seven cards, then put up to seven permanent cards from your hand onto the battlefield.

View File

@@ -3,9 +3,7 @@ ManaCost:4
Types:Artifact
A:AB$ PutCounter | Cost$ 2 T | CounterType$ CHARGE | CounterNum$ 1 | SpellDescription$ Put a charge counter on CARDNAME.
A:AB$ Mana | Cost$ T SubCounter<X/CHARGE> | Produced$ W | Amount$ Y | CostDesc$ {T}, Remove any number of charge counters from CARDNAME: | AILogic$ ManaRitualBattery.1 | AINoRecursiveCheck$ True | SpellDescription$ Add {W}, then add an additional {W} for each charge counter removed this way.
SVar:Y:Number$1/Plus.ChosenX
SVar:X:XChoice
#ChosenX SVar created by Cost payment
SVar:Y:SVar$X/Plus.1
SVar:X:Count$xPaid
AI:RemoveDeck:Random
SVar:Picture:http://www.wizards.com/global/images/magic/general/white_mana_battery.jpg
Oracle:{2}, {T}: Put a charge counter on White Mana Battery.\n{T}, Remove any number of charge counters from White Mana Battery: Add {W}, then add an additional {W} for each charge counter removed this way.

View File

@@ -29,7 +29,6 @@ import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardPlayOption;
import forge.game.cost.Cost;
import forge.game.cost.CostPartMana;
import forge.game.cost.CostPayment;
import forge.game.keyword.KeywordInterface;
import forge.game.mana.ManaPool;
@@ -221,9 +220,7 @@ public class HumanPlaySpellAbility {
if (ability.isCopied()) { return true; } //don't re-announce for spell copies
boolean needX = true;
final boolean allowZero = !ability.hasParam("XCantBe0");
final Cost cost = ability.getPayCosts();
final CostPartMana manaCost = cost.getCostMana();
final PlayerController controller = ability.getActivatingPlayer().getController();
final Card card = ability.getHostCard();
@@ -237,7 +234,7 @@ public class HumanPlaySpellAbility {
final boolean isX = "X".equalsIgnoreCase(varName);
if (isX) { needX = false; }
final Integer value = controller.announceRequirements(ability, varName, allowZero && (!isX || manaCost == null || manaCost.canXbe0()));
final Integer value = controller.announceRequirements(ability, varName);
if (value == null) {
return false;
}
@@ -254,17 +251,17 @@ public class HumanPlaySpellAbility {
}
}
if (needX && manaCost != null) {
if (needX) {
if (cost.hasXInAnyCostPart()) {
final String sVar = ability.getSVar("X"); //only prompt for new X value if card doesn't determine it another way
if ("Count$xPaid".equals(sVar) || sVar.isEmpty()) {
final Integer value = controller.announceRequirements(ability, "X", allowZero && manaCost.canXbe0());
final Integer value = controller.announceRequirements(ability, "X");
if (value == null) {
return false;
}
ability.setXManaCostPaid(value);
}
} else if (manaCost.getMana().isZero() && ability.isSpell()) {
} else {
ability.setXManaCostPaid(0);
}
}

View File

@@ -320,12 +320,12 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
}
@Override
public Integer announceRequirements(final SpellAbility ability, final String announce,
final boolean canChooseZero) {
final int min = canChooseZero ? 0 : 1;
public Integer announceRequirements(final SpellAbility ability, final String announce) {
int max = Integer.MAX_VALUE;
boolean canChooseZero = true;
if ("X".equals(announce)) {
canChooseZero = !ability.hasParam("XCantBe0");
Cost cost = ability.getPayCosts();
if (ability.hasParam("XMaxLimit")) {
max = Math.min(max, AbilityUtils.calculateAmount(ability.getHostCard(), ability.getParam("XMaxLimit"), ability));
@@ -333,10 +333,14 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
if (cost != null) {
Integer costX = cost.getMaxForNonManaX(ability, player);
if (costX != null) {
max = Math.min(max, min);
max = Math.min(max, costX);
}
if (cost.hasManaCost() && !cost.getCostMana().canXbe0()) {
canChooseZero = false;
}
}
}
final int min = canChooseZero ? 0 : 1;
if (ability.usesTargeting()) {
// if announce is used as min targets, check what the max possible number would be
@@ -344,6 +348,9 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
max = Math.min(max, CardUtil.getValidCardsToTarget(ability.getTargetRestrictions(), ability).size());
}
}
if (min > max) {
return null;
}
return getGui().getInteger(localizer.getMessage("lblChooseAnnounceForCard", announce,
CardTranslation.getTranslatedName(ability.getHostCard().getName())) , min, max, min + 9);
}