diff --git a/forge-ai/src/main/java/forge/ai/AiCostDecision.java b/forge-ai/src/main/java/forge/ai/AiCostDecision.java index f5c43be501f..f691ae0fd29 100644 --- a/forge-ai/src/main/java/forge/ai/AiCostDecision.java +++ b/forge-ai/src/main/java/forge/ai/AiCostDecision.java @@ -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(); diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java index c5e428cd87d..bab8cff9228 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java @@ -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); } } diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java index cda5239a2b1..74e01fe3fd3 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java @@ -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; - } } diff --git a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java index 3e2590964c0..4a0b0a5257c 100644 --- a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java +++ b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java @@ -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()) { diff --git a/forge-ai/src/main/java/forge/ai/SpecialCardAi.java b/forge-ai/src/main/java/forge/ai/SpecialCardAi.java index 96978de7320..2db5db8d659 100644 --- a/forge-ai/src/main/java/forge/ai/SpecialCardAi.java +++ b/forge-ai/src/main/java/forge/ai/SpecialCardAi.java @@ -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; + // 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; } } diff --git a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java index 3ca3777d814..419f51f0bda 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java @@ -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); diff --git a/forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java b/forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java index 461e6b2e60c..8c677d7dc6f 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java @@ -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; } diff --git a/forge-ai/src/main/java/forge/ai/ability/ChooseColorAi.java b/forge-ai/src/main/java/forge/ai/ability/ChooseColorAi.java index cefb6cfe3db..035366890cc 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChooseColorAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChooseColorAi.java @@ -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(); diff --git a/forge-ai/src/main/java/forge/ai/ability/ChooseTypeAi.java b/forge-ai/src/main/java/forge/ai/ability/ChooseTypeAi.java index 75ca4487057..02d815fb8f1 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChooseTypeAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChooseTypeAi.java @@ -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 diff --git a/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java b/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java index 1c8c72f6e32..cee64159ff9 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java @@ -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 diff --git a/forge-ai/src/main/java/forge/ai/ability/DrawAi.java b/forge-ai/src/main/java/forge/ai/ability/DrawAi.java index 579d731d625..a5575616222 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DrawAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DrawAi.java @@ -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))) { diff --git a/forge-ai/src/main/java/forge/ai/ability/ManaEffectAi.java b/forge-ai/src/main/java/forge/ai/ability/ManaEffectAi.java index 80f7b916f11..76d6c4f9cf5 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ManaEffectAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ManaEffectAi.java @@ -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. diff --git a/forge-ai/src/main/java/forge/ai/ability/PermanentAi.java b/forge-ai/src/main/java/forge/ai/ability/PermanentAi.java index 62012507864..d84745c747b 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PermanentAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/PermanentAi.java @@ -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(); @@ -258,7 +272,7 @@ public class PermanentAi extends SpellAbilityAi { return !dontCast; } - + return true; } diff --git a/forge-ai/src/main/java/forge/ai/ability/ScryAi.java b/forge-ai/src/main/java/forge/ai/ability/ScryAi.java index 2ec63fb82ac..a4da6b8784e 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ScryAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ScryAi.java @@ -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; } } @@ -140,12 +140,12 @@ public class ScryAi extends SpellAbilityAi { int maxToRemove = counterNum - maxCMC + 1; // no Scry 0, even if its catched from later stuff if (maxToRemove <= 0) { - return false; + 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; diff --git a/forge-game/src/main/java/forge/game/ability/effects/BidLifeEffect.java b/forge-game/src/main/java/forge/game/ability/effects/BidLifeEffect.java index 22391ec5f5d..2561aa7b3ae 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/BidLifeEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/BidLifeEffect.java @@ -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); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChooseNumberEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChooseNumberEffect.java index 986ddf51fd9..939fe632e51 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChooseNumberEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChooseNumberEffect.java @@ -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); diff --git a/forge-game/src/main/java/forge/game/cost/Cost.java b/forge-game/src/main/java/forge/game/cost/Cost.java index bda38820815..986e6d791e3 100644 --- a/forge-game/src/main/java/forge/game/cost/Cost.java +++ b/forge-game/src/main/java/forge/game/cost/Cost.java @@ -124,7 +124,7 @@ public class Cost implements Serializable { Collections.sort(this.costParts, new Comparator() { @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(); } diff --git a/forge-game/src/main/java/forge/game/cost/CostSacrifice.java b/forge-game/src/main/java/forge/game/cost/CostSacrifice.java index 0ac0cb3248a..9e312ae765c 100644 --- a/forge-game/src/main/java/forge/game/cost/CostSacrifice.java +++ b/forge-game/src/main/java/forge/game/cost/CostSacrifice.java @@ -6,17 +6,21 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ 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; @@ -38,7 +42,7 @@ public class CostSacrifice extends CostPartWithList { /** * Instantiates a new cost sacrifice. - * + * * @param amount * the amount * @param type @@ -53,9 +57,19 @@ 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) - * + * * @see forge.card.cost.CostPart#toString() */ @Override @@ -63,24 +77,18 @@ 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(); } /* * (non-Javadoc) - * + * * @see * forge.card.cost.CostPart#canPay(forge.card.spellability.SpellAbility, * forge.Card, forge.Player, forge.card.cost.Cost) @@ -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, getType().split(";"), activator, source, ability); + // it needs to check if everything can be sacrificed + return Iterables.all(typeList, CardPredicates.canBeSacrificedBy(ability)); + } - CardCollectionView typeList = activator.getCardsIn(ZoneType.Battlefield); - typeList = CardLists.getValidCards(typeList, this.getType().split(";"), activator, source, 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 diff --git a/forge-game/src/main/java/forge/game/player/PlayerController.java b/forge-game/src/main/java/forge/game/player/PlayerController.java index f525d8b1933..9bee0d925ef 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerController.java +++ b/forge-game/src/main/java/forge/game/player/PlayerController.java @@ -110,7 +110,7 @@ public abstract class PlayerController { public abstract Map 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); diff --git a/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java b/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java index 242e681cb4a..f557947a51a 100644 --- a/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java +++ b/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java @@ -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..."); } diff --git a/forge-gui/res/cardsfolder/a/ashiok_nightmare_weaver.txt b/forge-gui/res/cardsfolder/a/ashiok_nightmare_weaver.txt index 8c9b0e24551..1d15d5b69f7 100644 --- a/forge-gui/res/cardsfolder/a/ashiok_nightmare_weaver.txt +++ b/forge-gui/res/cardsfolder/a/ashiok_nightmare_weaver.txt @@ -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 | 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 | 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 diff --git a/forge-gui/res/cardsfolder/b/black_mana_battery.txt b/forge-gui/res/cardsfolder/b/black_mana_battery.txt index 1a7dd97c617..6a12adfc3ef 100644 --- a/forge-gui/res/cardsfolder/b/black_mana_battery.txt +++ b/forge-gui/res/cardsfolder/b/black_mana_battery.txt @@ -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 | 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. diff --git a/forge-gui/res/cardsfolder/b/blue_mana_battery.txt b/forge-gui/res/cardsfolder/b/blue_mana_battery.txt index 08def6bf791..f343607b8de 100644 --- a/forge-gui/res/cardsfolder/b/blue_mana_battery.txt +++ b/forge-gui/res/cardsfolder/b/blue_mana_battery.txt @@ -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 | 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. diff --git a/forge-gui/res/cardsfolder/b/bosh_iron_golem_avatar.txt b/forge-gui/res/cardsfolder/b/bosh_iron_golem_avatar.txt index 7d38377835f..305f03dab35 100644 --- a/forge-gui/res/cardsfolder/b/bosh_iron_golem_avatar.txt +++ b/forge-gui/res/cardsfolder/b/bosh_iron_golem_avatar.txt @@ -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 diff --git a/forge-gui/res/cardsfolder/b/bottomless_vault.txt b/forge-gui/res/cardsfolder/b/bottomless_vault.txt index 79bbc6cadd8..8578548ea47 100644 --- a/forge-gui/res/cardsfolder/b/bottomless_vault.txt +++ b/forge-gui/res/cardsfolder/b/bottomless_vault.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/b/brain_in_a_jar.txt b/forge-gui/res/cardsfolder/b/brain_in_a_jar.txt index 4197b75a1e6..36194f48586 100644 --- a/forge-gui/res/cardsfolder/b/brain_in_a_jar.txt +++ b/forge-gui/res/cardsfolder/b/brain_in_a_jar.txt @@ -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 | ScryNum$ ChosenX | References$ X | AILogic$ BrainJar | SpellDescription$ Scry X. -SVar:X:XChoice +A:AB$ Scry | Cost$ 3 T SubCounter | 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. diff --git a/forge-gui/res/cardsfolder/c/calciform_pools.txt b/forge-gui/res/cardsfolder/c/calciform_pools.txt index eee726f6710..4d2af8a5eb4 100644 --- a/forge-gui/res/cardsfolder/c/calciform_pools.txt +++ b/forge-gui/res/cardsfolder/c/calciform_pools.txt @@ -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 | 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 | 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}. diff --git a/forge-gui/res/cardsfolder/c/champion_of_stray_souls.txt b/forge-gui/res/cardsfolder/c/champion_of_stray_souls.txt index 82133fd81b0..297af3ee3b3 100644 --- a/forge-gui/res/cardsfolder/c/champion_of_stray_souls.txt +++ b/forge-gui/res/cardsfolder/c/champion_of_stray_souls.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/c/chandra_awakened_inferno.txt b/forge-gui/res/cardsfolder/c/chandra_awakened_inferno.txt index d11538fb734..8fc46bae7c5 100644 --- a/forge-gui/res/cardsfolder/c/chandra_awakened_inferno.txt +++ b/forge-gui/res/cardsfolder/c/chandra_awakened_inferno.txt @@ -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 | 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 -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. \ No newline at end of file +A:AB$ DealDamage | Cost$ SubCounter | 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. diff --git a/forge-gui/res/cardsfolder/c/chandra_flamecaller.txt b/forge-gui/res/cardsfolder/c/chandra_flamecaller.txt index 8e33c7b464e..481b4fc923a 100644 --- a/forge-gui/res/cardsfolder/c/chandra_flamecaller.txt +++ b/forge-gui/res/cardsfolder/c/chandra_flamecaller.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/c/chandra_nalaar.txt b/forge-gui/res/cardsfolder/c/chandra_nalaar.txt index 0af9e968418..8d9aa306b31 100644 --- a/forge-gui/res/cardsfolder/c/chandra_nalaar.txt +++ b/forge-gui/res/cardsfolder/c/chandra_nalaar.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/c/channeled_force.txt b/forge-gui/res/cardsfolder/c/channeled_force.txt index 3d6aae1c6bf..8ddc07ab7ef 100755 --- a/forge-gui/res/cardsfolder/c/channeled_force.txt +++ b/forge-gui/res/cardsfolder/c/channeled_force.txt @@ -1,7 +1,7 @@ Name:Channeled Force ManaCost:2 U R Types:Instant -A:SP$ Draw | Cost$ 2 U R Discard | 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 | 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. diff --git a/forge-gui/res/cardsfolder/c/crucible_of_the_spirit_dragon.txt b/forge-gui/res/cardsfolder/c/crucible_of_the_spirit_dragon.txt index a8de4176598..5dd2ff77a65 100644 --- a/forge-gui/res/cardsfolder/c/crucible_of_the_spirit_dragon.txt +++ b/forge-gui/res/cardsfolder/c/crucible_of_the_spirit_dragon.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/c/cruel_sadist.txt b/forge-gui/res/cardsfolder/c/cruel_sadist.txt index 00b6d03afe5..61667292857 100644 --- a/forge-gui/res/cardsfolder/c/cruel_sadist.txt +++ b/forge-gui/res/cardsfolder/c/cruel_sadist.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/d/dargo_the_shipwrecker.txt b/forge-gui/res/cardsfolder/d/dargo_the_shipwrecker.txt index 60013e89d72..d343d7aba23 100755 --- a/forge-gui/res/cardsfolder/d/dargo_the_shipwrecker.txt +++ b/forge-gui/res/cardsfolder/d/dargo_the_shipwrecker.txt @@ -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 | 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 | 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 diff --git a/forge-gui/res/cardsfolder/d/dreadship_reef.txt b/forge-gui/res/cardsfolder/d/dreadship_reef.txt index 855bf9ca607..fc488ae640c 100644 --- a/forge-gui/res/cardsfolder/d/dreadship_reef.txt +++ b/forge-gui/res/cardsfolder/d/dreadship_reef.txt @@ -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 | 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 | 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}. diff --git a/forge-gui/res/cardsfolder/d/dwarven_hold.txt b/forge-gui/res/cardsfolder/d/dwarven_hold.txt index 3dda386a35c..97cd7c08edf 100644 --- a/forge-gui/res/cardsfolder/d/dwarven_hold.txt +++ b/forge-gui/res/cardsfolder/d/dwarven_hold.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/e/eliminate_the_competition.txt b/forge-gui/res/cardsfolder/e/eliminate_the_competition.txt index 822998fef76..0fa790b9ee4 100644 --- a/forge-gui/res/cardsfolder/e/eliminate_the_competition.txt +++ b/forge-gui/res/cardsfolder/e/eliminate_the_competition.txt @@ -1,6 +1,7 @@ Name:Eliminate the Competition ManaCost:4 B Types:Sorcery -A:SP$ Destroy | Announce$ X | Cost$ 4 B Sac | 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 | 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. diff --git a/forge-gui/res/cardsfolder/e/emrakuls_evangel.txt b/forge-gui/res/cardsfolder/e/emrakuls_evangel.txt index 02c9c2f9cc6..ec76823d491 100644 --- a/forge-gui/res/cardsfolder/e/emrakuls_evangel.txt +++ b/forge-gui/res/cardsfolder/e/emrakuls_evangel.txt @@ -2,11 +2,10 @@ Name:Emrakul's Evangel ManaCost:2 G Types:Creature Human Horror PT:3/2 -A:AB$ Token | Cost$ T Sac 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 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. diff --git a/forge-gui/res/cardsfolder/f/fountain_of_cho.txt b/forge-gui/res/cardsfolder/f/fountain_of_cho.txt index a3181ca8392..f0bfec2d493 100644 --- a/forge-gui/res/cardsfolder/f/fountain_of_cho.txt +++ b/forge-gui/res/cardsfolder/f/fountain_of_cho.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/f/fungal_reaches.txt b/forge-gui/res/cardsfolder/f/fungal_reaches.txt index 257e9a07598..74ac2da8e31 100644 --- a/forge-gui/res/cardsfolder/f/fungal_reaches.txt +++ b/forge-gui/res/cardsfolder/f/fungal_reaches.txt @@ -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 | 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 | 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}. diff --git a/forge-gui/res/cardsfolder/g/green_mana_battery.txt b/forge-gui/res/cardsfolder/g/green_mana_battery.txt index 008c1da35ac..c7a707312e1 100644 --- a/forge-gui/res/cardsfolder/g/green_mana_battery.txt +++ b/forge-gui/res/cardsfolder/g/green_mana_battery.txt @@ -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 | 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. diff --git a/forge-gui/res/cardsfolder/h/hollow_trees.txt b/forge-gui/res/cardsfolder/h/hollow_trees.txt index 6657b73aaaf..5f44387dca8 100644 --- a/forge-gui/res/cardsfolder/h/hollow_trees.txt +++ b/forge-gui/res/cardsfolder/h/hollow_trees.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/i/icatian_store.txt b/forge-gui/res/cardsfolder/i/icatian_store.txt index 3ab8e9bf3f7..392f59d3c61 100644 --- a/forge-gui/res/cardsfolder/i/icatian_store.txt +++ b/forge-gui/res/cardsfolder/i/icatian_store.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/i/infused_arrows.txt b/forge-gui/res/cardsfolder/i/infused_arrows.txt index 02a4d277f6a..032c143a681 100644 --- a/forge-gui/res/cardsfolder/i/infused_arrows.txt +++ b/forge-gui/res/cardsfolder/i/infused_arrows.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/j/jeska_thrice_reborn.txt b/forge-gui/res/cardsfolder/j/jeska_thrice_reborn.txt index 940b5a89dfd..373c82b4170 100644 --- a/forge-gui/res/cardsfolder/j/jeska_thrice_reborn.txt +++ b/forge-gui/res/cardsfolder/j/jeska_thrice_reborn.txt @@ -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 | 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 | 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 diff --git a/forge-gui/res/cardsfolder/k/krav_the_unredeemed.txt b/forge-gui/res/cardsfolder/k/krav_the_unredeemed.txt index b3f82d1668e..60840f421da 100644 --- a/forge-gui/res/cardsfolder/k/krav_the_unredeemed.txt +++ b/forge-gui/res/cardsfolder/k/krav_the_unredeemed.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/m/mage_ring_network.txt b/forge-gui/res/cardsfolder/m/mage_ring_network.txt index 15b353f6398..bc9e49338c9 100644 --- a/forge-gui/res/cardsfolder/m/mage_ring_network.txt +++ b/forge-gui/res/cardsfolder/m/mage_ring_network.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/m/marath_will_of_the_wild.txt b/forge-gui/res/cardsfolder/m/marath_will_of_the_wild.txt index b5c02400a6a..0ae8c91e3af 100644 --- a/forge-gui/res/cardsfolder/m/marath_will_of_the_wild.txt +++ b/forge-gui/res/cardsfolder/m/marath_will_of_the_wild.txt @@ -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 | Announce$ X | XCantBe0$ True | Choices$ MarathCounters,MarathDmg,MarathToken | Defined$ You +A:AB$ Charm | Cost$ XCantBe0 X SubCounter | 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. diff --git a/forge-gui/res/cardsfolder/m/mercadian_bazaar.txt b/forge-gui/res/cardsfolder/m/mercadian_bazaar.txt index a333982d008..7828f5d3327 100644 --- a/forge-gui/res/cardsfolder/m/mercadian_bazaar.txt +++ b/forge-gui/res/cardsfolder/m/mercadian_bazaar.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/m/mercadian_lift.txt b/forge-gui/res/cardsfolder/m/mercadian_lift.txt index 98f54e90bab..00bd9b88ae2 100644 --- a/forge-gui/res/cardsfolder/m/mercadian_lift.txt +++ b/forge-gui/res/cardsfolder/m/mercadian_lift.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/m/molten_slagheap.txt b/forge-gui/res/cardsfolder/m/molten_slagheap.txt index eaf076cb4e5..52345d6fd97 100644 --- a/forge-gui/res/cardsfolder/m/molten_slagheap.txt +++ b/forge-gui/res/cardsfolder/m/molten_slagheap.txt @@ -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 | 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 | 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}. diff --git a/forge-gui/res/cardsfolder/n/nahiri_storm_of_stone.txt b/forge-gui/res/cardsfolder/n/nahiri_storm_of_stone.txt index b931015927e..0a0b4508e01 100644 --- a/forge-gui/res/cardsfolder/n/nahiri_storm_of_stone.txt +++ b/forge-gui/res/cardsfolder/n/nahiri_storm_of_stone.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/n/night_dealings.txt b/forge-gui/res/cardsfolder/n/night_dealings.txt index 523ecd28780..4fd8a088cc4 100644 --- a/forge-gui/res/cardsfolder/n/night_dealings.txt +++ b/forge-gui/res/cardsfolder/n/night_dealings.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/r/red_mana_battery.txt b/forge-gui/res/cardsfolder/r/red_mana_battery.txt index 082facea057..fe2561a53c6 100644 --- a/forge-gui/res/cardsfolder/r/red_mana_battery.txt +++ b/forge-gui/res/cardsfolder/r/red_mana_battery.txt @@ -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 | 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. diff --git a/forge-gui/res/cardsfolder/r/rushwood_grove.txt b/forge-gui/res/cardsfolder/r/rushwood_grove.txt index 3b3ba846c3b..0f188ad88c5 100644 --- a/forge-gui/res/cardsfolder/r/rushwood_grove.txt +++ b/forge-gui/res/cardsfolder/r/rushwood_grove.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/s/saltcrusted_steppe.txt b/forge-gui/res/cardsfolder/s/saltcrusted_steppe.txt index bfe2e7b941a..62af97d9921 100644 --- a/forge-gui/res/cardsfolder/s/saltcrusted_steppe.txt +++ b/forge-gui/res/cardsfolder/s/saltcrusted_steppe.txt @@ -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 | 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 | 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}. diff --git a/forge-gui/res/cardsfolder/s/sand_silos.txt b/forge-gui/res/cardsfolder/s/sand_silos.txt index 99db3fbe082..d2002bd71fa 100644 --- a/forge-gui/res/cardsfolder/s/sand_silos.txt +++ b/forge-gui/res/cardsfolder/s/sand_silos.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/s/saprazzan_cove.txt b/forge-gui/res/cardsfolder/s/saprazzan_cove.txt index d1fa6c9effc..86008bc2baa 100644 --- a/forge-gui/res/cardsfolder/s/saprazzan_cove.txt +++ b/forge-gui/res/cardsfolder/s/saprazzan_cove.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/s/simic_manipulator.txt b/forge-gui/res/cardsfolder/s/simic_manipulator.txt index 4d12bfd72ea..1c1439d30ca 100644 --- a/forge-gui/res/cardsfolder/s/simic_manipulator.txt +++ b/forge-gui/res/cardsfolder/s/simic_manipulator.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/s/sorin_grim_nemesis.txt b/forge-gui/res/cardsfolder/s/sorin_grim_nemesis.txt index 202a8fa93c0..116c12067ae 100644 --- a/forge-gui/res/cardsfolder/s/sorin_grim_nemesis.txt +++ b/forge-gui/res/cardsfolder/s/sorin_grim_nemesis.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/s/subterranean_hangar.txt b/forge-gui/res/cardsfolder/s/subterranean_hangar.txt index baa0831bfa9..99f94b761ff 100644 --- a/forge-gui/res/cardsfolder/s/subterranean_hangar.txt +++ b/forge-gui/res/cardsfolder/s/subterranean_hangar.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/t/tetravus.txt b/forge-gui/res/cardsfolder/t/tetravus.txt index f3ac57dae5b..6e4139a21ca 100644 --- a/forge-gui/res/cardsfolder/t/tetravus.txt +++ b/forge-gui/res/cardsfolder/t/tetravus.txt @@ -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 | 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 | 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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/t/tezzeret_the_seeker.txt b/forge-gui/res/cardsfolder/t/tezzeret_the_seeker.txt index 0310718891e..513c31f26e8 100644 --- a/forge-gui/res/cardsfolder/t/tezzeret_the_seeker.txt +++ b/forge-gui/res/cardsfolder/t/tezzeret_the_seeker.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/t/torgaar_famine_incarnate.txt b/forge-gui/res/cardsfolder/t/torgaar_famine_incarnate.txt index b8b58b9b4a1..7443e8b67c3 100644 --- a/forge-gui/res/cardsfolder/t/torgaar_famine_incarnate.txt +++ b/forge-gui/res/cardsfolder/t/torgaar_famine_incarnate.txt @@ -2,11 +2,12 @@ Name:Torgaar, Famine Incarnate ManaCost:6 B B Types:Legendary Creature Avatar PT:7/6 -A:SP$ PermanentCreature | Cost$ 6 B B Sac | 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 | 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 -Oracle: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.\nWhen Torgaar, Famine Incarnate enters the battlefield, up to one target player's life total becomes half their starting life total, rounded down. \ No newline at end of file +Oracle: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.\nWhen Torgaar, Famine Incarnate enters the battlefield, up to one target player's life total becomes half their starting life total, rounded down. diff --git a/forge-gui/res/cardsfolder/u/ugin_the_spirit_dragon.txt b/forge-gui/res/cardsfolder/u/ugin_the_spirit_dragon.txt index 9b0c7011047..db0c97292cb 100644 --- a/forge-gui/res/cardsfolder/u/ugin_the_spirit_dragon.txt +++ b/forge-gui/res/cardsfolder/u/ugin_the_spirit_dragon.txt @@ -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 | 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 | 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. diff --git a/forge-gui/res/cardsfolder/w/white_mana_battery.txt b/forge-gui/res/cardsfolder/w/white_mana_battery.txt index b8b0ca8bf2a..cf8b56a08f9 100644 --- a/forge-gui/res/cardsfolder/w/white_mana_battery.txt +++ b/forge-gui/res/cardsfolder/w/white_mana_battery.txt @@ -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 | 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. diff --git a/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java b/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java index 499532bc431..54e4e063ca3 100644 --- a/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java +++ b/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java @@ -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); } } diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index e2d31e40556..b7243562e3a 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -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); }