mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 19:58:00 +00:00
Merge branch 'manaReplacementEffect' into 'master'
AbilityMana: better ReplacementEffect logic Closes #1266 See merge request core-developers/forge!2650
This commit is contained in:
@@ -429,8 +429,7 @@ public class AiController {
|
|||||||
byte color = MagicColor.fromName(c);
|
byte color = MagicColor.fromName(c);
|
||||||
for (Card land : landList) {
|
for (Card land : landList) {
|
||||||
for (final SpellAbility m : ComputerUtilMana.getAIPlayableMana(land)) {
|
for (final SpellAbility m : ComputerUtilMana.getAIPlayableMana(land)) {
|
||||||
AbilityManaPart mp = m.getManaPart();
|
if (m.canProduce(MagicColor.toShortString(color))) {
|
||||||
if (mp.canProduce(MagicColor.toShortString(color), m)) {
|
|
||||||
return land;
|
return land;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -483,8 +482,7 @@ public class AiController {
|
|||||||
return land;
|
return land;
|
||||||
}
|
}
|
||||||
for (final SpellAbility m : ComputerUtilMana.getAIPlayableMana(land)) {
|
for (final SpellAbility m : ComputerUtilMana.getAIPlayableMana(land)) {
|
||||||
AbilityManaPart mp = m.getManaPart();
|
if (m.canProduce(MagicColor.toShortString(color))) {
|
||||||
if (mp.canProduce(MagicColor.toShortString(color), m)) {
|
|
||||||
return land;
|
return land;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2075,9 +2075,8 @@ public class ComputerUtil {
|
|||||||
|
|
||||||
for (Card c : lands) {
|
for (Card c : lands) {
|
||||||
for (SpellAbility sa : c.getManaAbilities()) {
|
for (SpellAbility sa : c.getManaAbilities()) {
|
||||||
AbilityManaPart abmana = sa.getManaPart();
|
|
||||||
for (byte col : MagicColor.WUBRG) {
|
for (byte col : MagicColor.WUBRG) {
|
||||||
if (abmana.canProduce(MagicColor.toLongString(col))) {
|
if (sa.canProduce(MagicColor.toLongString(col))) {
|
||||||
numProducers.get(col).add(c);
|
numProducers.get(col).add(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,11 +10,10 @@ import forge.card.mana.ManaAtom;
|
|||||||
import forge.card.mana.ManaCost;
|
import forge.card.mana.ManaCost;
|
||||||
import forge.card.mana.ManaCostParser;
|
import forge.card.mana.ManaCostParser;
|
||||||
import forge.card.mana.ManaCostShard;
|
import forge.card.mana.ManaCostShard;
|
||||||
|
import forge.game.CardTraitPredicates;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.GameActionUtil;
|
import forge.game.GameActionUtil;
|
||||||
import forge.game.ability.AbilityKey;
|
import forge.game.ability.*;
|
||||||
import forge.game.ability.AbilityUtils;
|
|
||||||
import forge.game.ability.ApiType;
|
|
||||||
import forge.game.card.*;
|
import forge.game.card.*;
|
||||||
import forge.game.combat.CombatUtil;
|
import forge.game.combat.CombatUtil;
|
||||||
import forge.game.cost.*;
|
import forge.game.cost.*;
|
||||||
@@ -25,10 +24,13 @@ import forge.game.phase.PhaseType;
|
|||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.player.PlayerPredicates;
|
import forge.game.player.PlayerPredicates;
|
||||||
import forge.game.replacement.ReplacementEffect;
|
import forge.game.replacement.ReplacementEffect;
|
||||||
|
import forge.game.replacement.ReplacementLayer;
|
||||||
import forge.game.replacement.ReplacementType;
|
import forge.game.replacement.ReplacementType;
|
||||||
import forge.game.spellability.AbilityManaPart;
|
import forge.game.spellability.AbilityManaPart;
|
||||||
import forge.game.spellability.AbilitySub;
|
import forge.game.spellability.AbilitySub;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
|
import forge.game.trigger.Trigger;
|
||||||
|
import forge.game.trigger.TriggerType;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.util.MyRandom;
|
import forge.util.MyRandom;
|
||||||
import forge.util.TextUtil;
|
import forge.util.TextUtil;
|
||||||
@@ -317,6 +319,190 @@ public class ComputerUtilMana {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String predictManaReplacement(SpellAbility saPayment, Player ai, ManaCostShard toPay) {
|
||||||
|
Card hostCard = saPayment.getHostCard();
|
||||||
|
Game game = hostCard.getGame();
|
||||||
|
String manaProduced = toPay.isSnow() && hostCard.isSnow() ? "S" : GameActionUtil.generatedTotalMana(saPayment);
|
||||||
|
//String originalProduced = manaProduced;
|
||||||
|
|
||||||
|
final Map<AbilityKey, Object> repParams = AbilityKey.newMap();
|
||||||
|
repParams.put(AbilityKey.Mana, manaProduced);
|
||||||
|
repParams.put(AbilityKey.Affected, hostCard);
|
||||||
|
repParams.put(AbilityKey.Player, ai);
|
||||||
|
repParams.put(AbilityKey.AbilityMana, saPayment); // RootAbility
|
||||||
|
|
||||||
|
// TODO Damping Sphere might replace later?
|
||||||
|
|
||||||
|
// add flags to replacementEffects to filter better?
|
||||||
|
List<ReplacementEffect> reList = game.getReplacementHandler().getReplacementList(ReplacementType.ProduceMana, repParams, ReplacementLayer.Other);
|
||||||
|
|
||||||
|
List<SpellAbility> replaceMana = Lists.newArrayList();
|
||||||
|
List<SpellAbility> replaceType = Lists.newArrayList();
|
||||||
|
List<SpellAbility> replaceAmount = Lists.newArrayList(); // currently only multi
|
||||||
|
|
||||||
|
// try to guess the color the mana gets replaced to
|
||||||
|
for (ReplacementEffect re : reList) {
|
||||||
|
SpellAbility o = re.getOverridingAbility();
|
||||||
|
|
||||||
|
if (o == null || o.getApi() != ApiType.ReplaceMana) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this one does replace the amount too
|
||||||
|
if (o.hasParam("ReplaceMana")) {
|
||||||
|
replaceMana.add(o);
|
||||||
|
} else if (o.hasParam("ReplaceType") || o.hasParam("ReplaceColor")) {
|
||||||
|
// this one replaces the color/type
|
||||||
|
// check if this one can be replaced into wanted mana shard
|
||||||
|
replaceType.add(o);
|
||||||
|
} else if (o.hasParam("ReplaceAmount")) {
|
||||||
|
replaceAmount.add(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// it is better to apply these ones first
|
||||||
|
if (!replaceMana.isEmpty()) {
|
||||||
|
for (SpellAbility saMana : replaceMana) {
|
||||||
|
// one of then has to Any
|
||||||
|
// one of then has to C
|
||||||
|
// one of then has to B
|
||||||
|
String m = saMana.getParam("ReplaceMana");
|
||||||
|
if ("Any".equals(m)) {
|
||||||
|
byte rs = MagicColor.GREEN;
|
||||||
|
for (byte c : MagicColor.WUBRGC) {
|
||||||
|
if (toPay.canBePaidWithManaOfColor(c)) {
|
||||||
|
rs = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
manaProduced = MagicColor.toShortString(rs);
|
||||||
|
} else {
|
||||||
|
manaProduced = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// then apply this one
|
||||||
|
if (!replaceType.isEmpty()) {
|
||||||
|
for (SpellAbility saMana : replaceAmount) {
|
||||||
|
Card card = saMana.getHostCard();
|
||||||
|
if (saMana.hasParam("ReplaceType")) {
|
||||||
|
// replace color and colorless
|
||||||
|
String color = saMana.getParam("ReplaceType");
|
||||||
|
if ("Any".equals(color)) {
|
||||||
|
byte rs = MagicColor.GREEN;
|
||||||
|
for (byte c : MagicColor.WUBRGC) {
|
||||||
|
if (toPay.canBePaidWithManaOfColor(c)) {
|
||||||
|
rs = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
color = MagicColor.toShortString(rs);
|
||||||
|
}
|
||||||
|
for (byte c : MagicColor.WUBRGC) {
|
||||||
|
String s = MagicColor.toShortString(c);
|
||||||
|
manaProduced = manaProduced.replace(s, color);
|
||||||
|
}
|
||||||
|
} else if (saMana.hasParam("ReplaceColor")) {
|
||||||
|
// replace color
|
||||||
|
String color = saMana.getParam("ReplaceColor");
|
||||||
|
if ("Chosen".equals(color)) {
|
||||||
|
if (card.hasChosenColor()) {
|
||||||
|
color = MagicColor.toShortString(card.getChosenColor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (saMana.hasParam("ReplaceOnly")) {
|
||||||
|
manaProduced = manaProduced.replace(saMana.getParam("ReplaceOnly"), color);
|
||||||
|
} else {
|
||||||
|
for (byte c : MagicColor.WUBRG) {
|
||||||
|
String s = MagicColor.toShortString(c);
|
||||||
|
manaProduced = manaProduced.replace(s, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// then multiply if able
|
||||||
|
if (!replaceAmount.isEmpty()) {
|
||||||
|
int totalAmount = 1;
|
||||||
|
for (SpellAbility saMana : replaceAmount) {
|
||||||
|
totalAmount *= Integer.valueOf(saMana.getParam("ReplaceAmount"));
|
||||||
|
}
|
||||||
|
manaProduced = StringUtils.repeat(manaProduced, " ", totalAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return manaProduced;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String predictManafromSpellAbility(SpellAbility saPayment, Player ai, ManaCostShard toPay) {
|
||||||
|
Card hostCard = saPayment.getHostCard();
|
||||||
|
|
||||||
|
String manaProduced = predictManaReplacement(saPayment, ai, toPay);
|
||||||
|
String originalProduced = manaProduced;
|
||||||
|
|
||||||
|
if (originalProduced.isEmpty()) {
|
||||||
|
return manaProduced;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run triggers like Nissa
|
||||||
|
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(hostCard);
|
||||||
|
runParams.put(AbilityKey.Player, ai); // assuming AI would only ever gives itself mana
|
||||||
|
runParams.put(AbilityKey.AbilityMana, saPayment);
|
||||||
|
runParams.put(AbilityKey.Produced, manaProduced);
|
||||||
|
runParams.put(AbilityKey.Activator, ai);
|
||||||
|
for (Trigger tr : ai.getGame().getTriggerHandler().getActiveTrigger(TriggerType.TapsForMana, runParams)) {
|
||||||
|
SpellAbility trSA = tr.ensureAbility();
|
||||||
|
if (trSA == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ApiType.Mana.equals(trSA.getApi())) {
|
||||||
|
int pAmount = trSA.hasParam("Amount") ? Integer.valueOf(trSA.getParam("Amount")) : 1;
|
||||||
|
String produced = trSA.getParam("Produced");
|
||||||
|
if (produced.equals("Chosen")) {
|
||||||
|
produced = MagicColor.toShortString(trSA.getHostCard().getChosenColor());
|
||||||
|
}
|
||||||
|
manaProduced += " " + StringUtils.repeat(produced, pAmount);
|
||||||
|
} else if (ApiType.ManaReflected.equals(trSA.getApi())) {
|
||||||
|
final String colorOrType = trSA.getParamOrDefault("ColorOrType", "Color");
|
||||||
|
// currently Color or Type, Type is colors + colorless
|
||||||
|
final String reflectProperty = trSA.getParam("ReflectProperty");
|
||||||
|
|
||||||
|
if (reflectProperty.equals("Produced") && !originalProduced.isEmpty()) {
|
||||||
|
// check if a colorless shard can be paid from the trigger
|
||||||
|
if (toPay.equals(ManaCostShard.COLORLESS) && colorOrType.equals("Type") && originalProduced.contains("C")) {
|
||||||
|
manaProduced += " " + "C";
|
||||||
|
} else if (originalProduced.length() == 1) {
|
||||||
|
// if length is only one, and it either is equal C == Type
|
||||||
|
if (colorOrType.equals("Type") || !originalProduced.equals("C")) {
|
||||||
|
manaProduced += " " + originalProduced;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// should it look for other shards too?
|
||||||
|
boolean found = false;
|
||||||
|
for (String s : originalProduced.split(" ")) {
|
||||||
|
if (colorOrType.equals("Type") || !s.equals("C") && toPay.canBePaidWithManaOfColor(MagicColor.fromName(s))) {
|
||||||
|
found = true;
|
||||||
|
manaProduced += " " + s;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// no good mana found? just add the first generated color
|
||||||
|
if (!found) {
|
||||||
|
for (String s : originalProduced.split(" ")) {
|
||||||
|
if (colorOrType.equals("Type") || !s.equals("C")) {
|
||||||
|
manaProduced += " " + s;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return manaProduced;
|
||||||
|
}
|
||||||
|
|
||||||
public static CardCollection getManaSourcesToPayCost(final ManaCostBeingPaid cost, final SpellAbility sa, final Player ai) {
|
public static CardCollection getManaSourcesToPayCost(final ManaCostBeingPaid cost, final SpellAbility sa, final Player ai) {
|
||||||
CardCollection manaSources = new CardCollection();
|
CardCollection manaSources = new CardCollection();
|
||||||
|
|
||||||
@@ -392,23 +578,13 @@ public class ComputerUtilMana {
|
|||||||
manaSources.add(saPayment.getHostCard());
|
manaSources.add(saPayment.getHostCard());
|
||||||
setExpressColorChoice(sa, ai, cost, toPay, saPayment);
|
setExpressColorChoice(sa, ai, cost, toPay, saPayment);
|
||||||
|
|
||||||
String manaProduced = toPay.isSnow() ? "S" : GameActionUtil.generatedMana(saPayment);
|
String manaProduced = predictManafromSpellAbility(saPayment, ai, toPay);
|
||||||
manaProduced = AbilityManaPart.applyManaReplacement(saPayment, manaProduced);
|
|
||||||
//System.out.println(manaProduced);
|
//System.out.println(manaProduced);
|
||||||
payMultipleMana(cost, manaProduced, ai);
|
payMultipleMana(cost, manaProduced, ai);
|
||||||
|
|
||||||
// remove from available lists
|
// remove from available lists
|
||||||
/*
|
Iterables.removeIf(sourcesForShards.values(), CardTraitPredicates.isHostCard(saPayment.getHostCard()));
|
||||||
* Refactoring this code to sourcesForShards.values().removeIf((SpellAbility srcSa) -> srcSa.getHostCard().equals(saPayment.getHostCard()));
|
|
||||||
* causes Android build not to compile
|
|
||||||
* */
|
|
||||||
Iterator<SpellAbility> itSa = sourcesForShards.values().iterator();
|
|
||||||
while (itSa.hasNext()) {
|
|
||||||
SpellAbility srcSa = itSa.next();
|
|
||||||
if (srcSa.getHostCard().equals(saPayment.getHostCard())) {
|
|
||||||
itSa.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleOfferingsAI(sa, true, cost.isPaid());
|
handleOfferingsAI(sa, true, cost.isPaid());
|
||||||
@@ -443,6 +619,21 @@ public class ComputerUtilMana {
|
|||||||
|
|
||||||
// Loop over mana needed
|
// Loop over mana needed
|
||||||
while (!cost.isPaid()) {
|
while (!cost.isPaid()) {
|
||||||
|
while (!cost.isPaid() && !manapool.isEmpty()) {
|
||||||
|
boolean found = false;
|
||||||
|
for (byte color : MagicColor.WUBRGC) {
|
||||||
|
if (manapool.tryPayCostWithColor(color, sa, cost)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cost.isPaid()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
toPay = getNextShardToPay(cost);
|
toPay = getNextShardToPay(cost);
|
||||||
|
|
||||||
boolean lifeInsteadOfBlack = toPay.isBlack() && ai.hasKeyword("PayLifeInsteadOf:B");
|
boolean lifeInsteadOfBlack = toPay.isBlack() && ai.hasKeyword("PayLifeInsteadOf:B");
|
||||||
@@ -451,7 +642,8 @@ public class ComputerUtilMana {
|
|||||||
if (hasConverge &&
|
if (hasConverge &&
|
||||||
(toPay == ManaCostShard.GENERIC || toPay == ManaCostShard.X)) {
|
(toPay == ManaCostShard.GENERIC || toPay == ManaCostShard.X)) {
|
||||||
final int unpaidColors = cost.getUnpaidColors() + cost.getColorsPaid() ^ ManaCostShard.COLORS_SUPERPOSITION;
|
final int unpaidColors = cost.getUnpaidColors() + cost.getColorsPaid() ^ ManaCostShard.COLORS_SUPERPOSITION;
|
||||||
for (final byte b : ColorSet.fromMask(unpaidColors)) { // try and pay other colors for converge
|
for (final byte b : ColorSet.fromMask(unpaidColors)) {
|
||||||
|
// try and pay other colors for converge
|
||||||
final ManaCostShard shard = ManaCostShard.valueOf(b);
|
final ManaCostShard shard = ManaCostShard.valueOf(b);
|
||||||
saList = sourcesForShards.get(shard);
|
saList = sourcesForShards.get(shard);
|
||||||
if (saList != null && !saList.isEmpty()) {
|
if (saList != null && !saList.isEmpty()) {
|
||||||
@@ -459,7 +651,8 @@ public class ComputerUtilMana {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (saList == null || saList.isEmpty()) { // failed to converge, revert to paying generic
|
if (saList == null || saList.isEmpty()) {
|
||||||
|
// failed to converge, revert to paying generic
|
||||||
saList = sourcesForShards.get(toPay);
|
saList = sourcesForShards.get(toPay);
|
||||||
hasConverge = false;
|
hasConverge = false;
|
||||||
}
|
}
|
||||||
@@ -539,23 +732,13 @@ public class ComputerUtilMana {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String manaProduced = toPay.isSnow() ? "S" : GameActionUtil.generatedMana(saPayment);
|
String manaProduced = predictManafromSpellAbility(saPayment, ai, toPay);
|
||||||
manaProduced = AbilityManaPart.applyManaReplacement(saPayment, manaProduced);
|
|
||||||
// System.out.println(manaProduced);
|
// System.out.println(manaProduced);
|
||||||
payMultipleMana(cost, manaProduced, ai);
|
payMultipleMana(cost, manaProduced, ai);
|
||||||
|
|
||||||
// remove from available lists
|
// remove from available lists
|
||||||
/*
|
Iterables.removeIf(sourcesForShards.values(), CardTraitPredicates.isHostCard(saPayment.getHostCard()));
|
||||||
* Refactoring this code to sourcesForShards.values().removeIf((SpellAbility srcSa) -> srcSa.getHostCard().equals(saPayment.getHostCard()));
|
|
||||||
* causes Android build not to compile
|
|
||||||
* */
|
|
||||||
Iterator<SpellAbility> itSa = sourcesForShards.values().iterator();
|
|
||||||
while (itSa.hasNext()) {
|
|
||||||
SpellAbility srcSa = itSa.next();
|
|
||||||
if (srcSa.getHostCard().equals(saPayment.getHostCard())) {
|
|
||||||
itSa.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final CostPayment pay = new CostPayment(saPayment.getPayCosts(), saPayment);
|
final CostPayment pay = new CostPayment(saPayment.getPayCosts(), saPayment);
|
||||||
@@ -571,19 +754,9 @@ public class ComputerUtilMana {
|
|||||||
// no need to remove abilities from resource map,
|
// no need to remove abilities from resource map,
|
||||||
// once their costs are paid and consume resources, they can not be used again
|
// once their costs are paid and consume resources, they can not be used again
|
||||||
|
|
||||||
if (hasConverge) { // hack to prevent converge re-using sources
|
if (hasConverge) {
|
||||||
// remove from available lists
|
// hack to prevent converge re-using sources
|
||||||
/*
|
Iterables.removeIf(sourcesForShards.values(), CardTraitPredicates.isHostCard(saPayment.getHostCard()));
|
||||||
* Refactoring this code to sourcesForShards.values().removeIf((SpellAbility srcSa) -> srcSa.getHostCard().equals(saPayment.getHostCard()));
|
|
||||||
* causes Android build not to compile
|
|
||||||
* */
|
|
||||||
Iterator<SpellAbility> itSa = sourcesForShards.values().iterator();
|
|
||||||
while (itSa.hasNext()) {
|
|
||||||
SpellAbility srcSa = itSa.next();
|
|
||||||
if (srcSa.getHostCard().equals(saPayment.getHostCard())) {
|
|
||||||
itSa.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -596,15 +769,6 @@ public class ComputerUtilMana {
|
|||||||
// extraMana, sa.getHostCard(), sa.toUnsuppressedString(), StringUtils.join(paymentPlan, "\n\t"));
|
// extraMana, sa.getHostCard(), sa.toUnsuppressedString(), StringUtils.join(paymentPlan, "\n\t"));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// See if it's possible to pay with something that was left in the mana pool in corner cases,
|
|
||||||
// e.g. Gemstone Caverns with a Luck counter on it generating colored mana (which fails to be
|
|
||||||
// processed correctly on a per-ability basis, leaving floating mana in the pool)
|
|
||||||
if (!cost.isPaid() && !manapool.isEmpty()) {
|
|
||||||
for (byte color : MagicColor.WUBRGC) {
|
|
||||||
manapool.tryPayCostWithColor(color, sa, cost);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The cost is still unpaid, so refund the mana and report
|
// The cost is still unpaid, so refund the mana and report
|
||||||
if (!cost.isPaid()) {
|
if (!cost.isPaid()) {
|
||||||
refundMana(manaSpentToPay, ai, sa);
|
refundMana(manaSpentToPay, ai, sa);
|
||||||
@@ -641,7 +805,8 @@ public class ComputerUtilMana {
|
|||||||
List<Mana> manaSpentToPay, final boolean hasConverge) {
|
List<Mana> manaSpentToPay, final boolean hasConverge) {
|
||||||
// arrange all mana abilities by color produced.
|
// arrange all mana abilities by color produced.
|
||||||
final ListMultimap<Integer, SpellAbility> manaAbilityMap = ComputerUtilMana.groupSourcesByManaColor(ai, checkPlayable);
|
final ListMultimap<Integer, SpellAbility> manaAbilityMap = ComputerUtilMana.groupSourcesByManaColor(ai, checkPlayable);
|
||||||
if (manaAbilityMap.isEmpty()) { // no mana abilities, bailing out
|
if (manaAbilityMap.isEmpty()) {
|
||||||
|
// no mana abilities, bailing out
|
||||||
refundMana(manaSpentToPay, ai, sa);
|
refundMana(manaSpentToPay, ai, sa);
|
||||||
handleOfferingsAI(sa, test, cost.isPaid());
|
handleOfferingsAI(sa, test, cost.isPaid());
|
||||||
return null;
|
return null;
|
||||||
@@ -652,14 +817,15 @@ public class ComputerUtilMana {
|
|||||||
|
|
||||||
// select which abilities may be used for each shard
|
// select which abilities may be used for each shard
|
||||||
ListMultimap<ManaCostShard, SpellAbility> sourcesForShards = ComputerUtilMana.groupAndOrderToPayShards(ai, manaAbilityMap, cost);
|
ListMultimap<ManaCostShard, SpellAbility> sourcesForShards = ComputerUtilMana.groupAndOrderToPayShards(ai, manaAbilityMap, cost);
|
||||||
if (hasConverge) { // add extra colors for paying converge
|
if (hasConverge) {
|
||||||
|
// add extra colors for paying converge
|
||||||
final int unpaidColors = cost.getUnpaidColors() + cost.getColorsPaid() ^ ManaCostShard.COLORS_SUPERPOSITION;
|
final int unpaidColors = cost.getUnpaidColors() + cost.getColorsPaid() ^ ManaCostShard.COLORS_SUPERPOSITION;
|
||||||
for (final byte b : ColorSet.fromMask(unpaidColors)) {
|
for (final byte b : ColorSet.fromMask(unpaidColors)) {
|
||||||
final ManaCostShard shard = ManaCostShard.valueOf(b);
|
final ManaCostShard shard = ManaCostShard.valueOf(b);
|
||||||
if (!sourcesForShards.containsKey(shard)) {
|
if (!sourcesForShards.containsKey(shard)) {
|
||||||
if (ai.getManaPool().canPayForShardWithColor(shard, b)) {
|
if (ai.getManaPool().canPayForShardWithColor(shard, b)) {
|
||||||
for (SpellAbility saMana : manaAbilityMap.get((int)b)) {
|
for (SpellAbility saMana : manaAbilityMap.get((int)b)) {
|
||||||
sourcesForShards.get(shard).add(sourcesForShards.get(shard).size(), saMana);
|
sourcesForShards.get(shard).add(saMana);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1026,7 +1192,7 @@ public class ComputerUtilMana {
|
|||||||
choice = abMana.getExpressChoice();
|
choice = abMana.getExpressChoice();
|
||||||
abMana.clearExpressChoice();
|
abMana.clearExpressChoice();
|
||||||
byte colorMask = ManaAtom.fromName(choice);
|
byte colorMask = ManaAtom.fromName(choice);
|
||||||
if (abMana.canProduce(choice, manaAb) && testCost.isAnyPartPayableWith(colorMask, ai.getManaPool())) {
|
if (manaAb.canProduce(choice) && testCost.isAnyPartPayableWith(colorMask, ai.getManaPool())) {
|
||||||
choiceString.append(choice);
|
choiceString.append(choice);
|
||||||
payMultipleMana(testCost, choice, ai);
|
payMultipleMana(testCost, choice, ai);
|
||||||
continue;
|
continue;
|
||||||
@@ -1387,20 +1553,6 @@ public class ComputerUtilMana {
|
|||||||
final ListMultimap<Integer, SpellAbility> manaMap = ArrayListMultimap.create();
|
final ListMultimap<Integer, SpellAbility> manaMap = ArrayListMultimap.create();
|
||||||
final Game game = ai.getGame();
|
final Game game = ai.getGame();
|
||||||
|
|
||||||
List<ReplacementEffect> replacementEffects = new ArrayList<>();
|
|
||||||
for (final Player p : game.getPlayers()) {
|
|
||||||
for (final Card crd : p.getAllCards()) {
|
|
||||||
for (final ReplacementEffect replacementEffect : crd.getReplacementEffects()) {
|
|
||||||
if (replacementEffect.requirementsCheck(game)
|
|
||||||
&& replacementEffect.getMode() == ReplacementType.ProduceMana
|
|
||||||
&& replacementEffect.hasParam("ManaReplacement")
|
|
||||||
&& replacementEffect.zonesCheck(game.getZoneOf(crd))) {
|
|
||||||
replacementEffects.add(replacementEffect);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop over all current available mana sources
|
// Loop over all current available mana sources
|
||||||
for (final Card sourceCard : getAvailableManaSources(ai, checkPlayable)) {
|
for (final Card sourceCard : getAvailableManaSources(ai, checkPlayable)) {
|
||||||
if (DEBUG_MANA_PAYMENT) {
|
if (DEBUG_MANA_PAYMENT) {
|
||||||
@@ -1430,48 +1582,80 @@ public class ComputerUtilMana {
|
|||||||
}
|
}
|
||||||
|
|
||||||
manaMap.get(ManaAtom.GENERIC).add(m); // add to generic source list
|
manaMap.get(ManaAtom.GENERIC).add(m); // add to generic source list
|
||||||
|
|
||||||
|
SpellAbility tail = m;
|
||||||
|
while (tail != null) {
|
||||||
AbilityManaPart mp = m.getManaPart();
|
AbilityManaPart mp = m.getManaPart();
|
||||||
|
if (mp != null && tail.metConditions()) {
|
||||||
|
// TODO Replacement Check currently doesn't work for reflected colors
|
||||||
|
|
||||||
// setup produce mana replacement effects
|
// setup produce mana replacement effects
|
||||||
|
String origin = mp.getOrigProduced();
|
||||||
final Map<AbilityKey, Object> repParams = AbilityKey.newMap();
|
final Map<AbilityKey, Object> repParams = AbilityKey.newMap();
|
||||||
repParams.put(AbilityKey.Mana, mp.getOrigProduced());
|
repParams.put(AbilityKey.Mana, origin);
|
||||||
repParams.put(AbilityKey.Affected, sourceCard);
|
repParams.put(AbilityKey.Affected, sourceCard);
|
||||||
repParams.put(AbilityKey.Player, ai);
|
repParams.put(AbilityKey.Player, ai);
|
||||||
repParams.put(AbilityKey.AbilityMana, m);
|
repParams.put(AbilityKey.AbilityMana, m); // RootAbility
|
||||||
|
|
||||||
for (final ReplacementEffect replacementEffect : replacementEffects) {
|
List<ReplacementEffect> reList = game.getReplacementHandler().getReplacementList(ReplacementType.ProduceMana, repParams, ReplacementLayer.Other);
|
||||||
if (replacementEffect.canReplace(repParams)) {
|
|
||||||
Card crd = replacementEffect.getHostCard();
|
|
||||||
String repType = crd.getSVar(replacementEffect.getParam("ManaReplacement"));
|
|
||||||
if (repType.contains("Chosen")) {
|
|
||||||
repType = TextUtil.fastReplace(repType, "Chosen", MagicColor.toShortString(crd.getChosenColor()));
|
|
||||||
}
|
|
||||||
mp.setManaReplaceType(repType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (reList.isEmpty()) {
|
||||||
Set<String> reflectedColors = CardUtil.getReflectableManaColors(m);
|
Set<String> reflectedColors = CardUtil.getReflectableManaColors(m);
|
||||||
// find possible colors
|
// find possible colors
|
||||||
if (mp.canProduce("W", m) || reflectedColors.contains(MagicColor.Constant.WHITE)) {
|
for (byte color : MagicColor.WUBRG) {
|
||||||
manaMap.get(ManaAtom.WHITE).add(m);
|
if (tail.canThisProduce(MagicColor.toShortString(color)) || reflectedColors.contains(MagicColor.toLongString(color))) {
|
||||||
|
manaMap.put((int)color, m);
|
||||||
}
|
}
|
||||||
if (mp.canProduce("U", m) || reflectedColors.contains(MagicColor.Constant.BLUE)) {
|
|
||||||
manaMap.get(ManaAtom.BLUE).add(m);
|
|
||||||
}
|
}
|
||||||
if (mp.canProduce("B", m) || reflectedColors.contains(MagicColor.Constant.BLACK)) {
|
if (m.canThisProduce("C") || reflectedColors.contains(MagicColor.Constant.COLORLESS)) {
|
||||||
manaMap.get(ManaAtom.BLACK).add(m);
|
manaMap.put(ManaAtom.COLORLESS, m);
|
||||||
}
|
}
|
||||||
if (mp.canProduce("R", m) || reflectedColors.contains(MagicColor.Constant.RED)) {
|
} else {
|
||||||
manaMap.get(ManaAtom.RED).add(m);
|
// try to guess the color the mana gets replaced to
|
||||||
|
for (ReplacementEffect re : reList) {
|
||||||
|
SpellAbility o = re.getOverridingAbility();
|
||||||
|
String replaced = origin;
|
||||||
|
if (o == null || o.getApi() != ApiType.ReplaceMana) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (mp.canProduce("G", m) || reflectedColors.contains(MagicColor.Constant.GREEN)) {
|
if (o.hasParam("ReplaceMana")) {
|
||||||
manaMap.get(ManaAtom.GREEN).add(m);
|
replaced = o.getParam("ReplaceMana");
|
||||||
|
} else if (o.hasParam("ReplaceType")) {
|
||||||
|
String color = o.getParam("ReplaceType");
|
||||||
|
for (byte c : MagicColor.WUBRGC) {
|
||||||
|
String s = MagicColor.toShortString(c);
|
||||||
|
replaced = replaced.replace(s, color);
|
||||||
}
|
}
|
||||||
if (mp.canProduce("C", m) || reflectedColors.contains(MagicColor.Constant.COLORLESS)) {
|
} else if (o.hasParam("ReplaceColor")) {
|
||||||
manaMap.get(ManaAtom.COLORLESS).add(m);
|
String color = o.getParam("ReplaceColor");
|
||||||
|
if (o.hasParam("ReplaceOnly")) {
|
||||||
|
replaced = replaced.replace(o.getParam("ReplaceOnly"), color);
|
||||||
|
} else {
|
||||||
|
for (byte c : MagicColor.WUBRG) {
|
||||||
|
String s = MagicColor.toShortString(c);
|
||||||
|
replaced = replaced.replace(s, color);
|
||||||
}
|
}
|
||||||
if (mp.isSnow()) {
|
}
|
||||||
manaMap.get(ManaAtom.IS_SNOW).add(m);
|
}
|
||||||
|
|
||||||
|
for (byte color : MagicColor.WUBRG) {
|
||||||
|
if ("Any".equals(replaced) || replaced.contains(MagicColor.toShortString(color))) {
|
||||||
|
manaMap.put((int)color, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (replaced.contains("C")) {
|
||||||
|
manaMap.put(ManaAtom.COLORLESS, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tail = tail.getSubAbility();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m.getHostCard().isSnow()) {
|
||||||
|
manaMap.put(ManaAtom.IS_SNOW, m);
|
||||||
}
|
}
|
||||||
if (DEBUG_MANA_PAYMENT) {
|
if (DEBUG_MANA_PAYMENT) {
|
||||||
System.out.println("DEBUG_MANA_PAYMENT: groupSourcesByManaColor manaMap = " + manaMap);
|
System.out.println("DEBUG_MANA_PAYMENT: groupSourcesByManaColor manaMap = " + manaMap);
|
||||||
|
|||||||
@@ -833,6 +833,9 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte chooseColor(String message, SpellAbility sa, ColorSet colors) {
|
public byte chooseColor(String message, SpellAbility sa, ColorSet colors) {
|
||||||
|
if (colors.countColors() < 2) {
|
||||||
|
return Iterables.getFirst(colors, MagicColor.WHITE);
|
||||||
|
}
|
||||||
// You may switch on sa.getApi() here and use sa.getParam("AILogic")
|
// You may switch on sa.getApi() here and use sa.getParam("AILogic")
|
||||||
CardCollectionView hand = player.getCardsIn(ZoneType.Hand);
|
CardCollectionView hand = player.getCardsIn(ZoneType.Hand);
|
||||||
if (sa.getApi() == ApiType.Mana) {
|
if (sa.getApi() == ApiType.Mana) {
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ public abstract class SpellAbilityAi {
|
|||||||
if (aiLogic.equals("CheckCondition")) {
|
if (aiLogic.equals("CheckCondition")) {
|
||||||
SpellAbility saCopy = sa.copy();
|
SpellAbility saCopy = sa.copy();
|
||||||
saCopy.setActivatingPlayer(ai);
|
saCopy.setActivatingPlayer(ai);
|
||||||
return saCopy.getConditions().areMet(saCopy);
|
return saCopy.metConditions();
|
||||||
}
|
}
|
||||||
|
|
||||||
return !("Never".equals(aiLogic));
|
return !("Never".equals(aiLogic));
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ public class AnimateAi extends SpellAbilityAi {
|
|||||||
final Card source = sa.getHostCard();
|
final Card source = sa.getHostCard();
|
||||||
final Game game = aiPlayer.getGame();
|
final Game game = aiPlayer.getGame();
|
||||||
final PhaseHandler ph = game.getPhaseHandler();
|
final PhaseHandler ph = game.getPhaseHandler();
|
||||||
if (sa.getConditions() != null && !sa.getConditions().areMet(sa) && sa.getSubAbility() == null) {
|
if (!sa.metConditions() && sa.getSubAbility() == null) {
|
||||||
return false; // what is this for?
|
return false; // what is this for?
|
||||||
}
|
}
|
||||||
if (!game.getStack().isEmpty() && game.getStack().peekAbility().getApi() == ApiType.Sacrifice) {
|
if (!game.getStack().isEmpty() && game.getStack().peekAbility().getApi() == ApiType.Sacrifice) {
|
||||||
|
|||||||
@@ -304,10 +304,10 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// don't play if the conditions aren't met, unless it would trigger a beneficial sub-condition
|
// don't play if the conditions aren't met, unless it would trigger a beneficial sub-condition
|
||||||
if (!activateForCost && !sa.getConditions().areMet(sa)) {
|
if (!activateForCost && !sa.metConditions()) {
|
||||||
final AbilitySub abSub = sa.getSubAbility();
|
final AbilitySub abSub = sa.getSubAbility();
|
||||||
if (abSub != null && !sa.isWrapper() && "True".equals(source.getSVar("AIPlayForSub"))) {
|
if (abSub != null && !sa.isWrapper() && "True".equals(source.getSVar("AIPlayForSub"))) {
|
||||||
if (!abSub.getConditions().areMet(abSub)) {
|
if (!abSub.metConditions()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ public class CountersPutAi extends SpellAbilityAi {
|
|||||||
return doMoveCounterLogic(ai, sa, ph);
|
return doMoveCounterLogic(ai, sa, ph);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sa.getConditions() != null && !sa.getConditions().areMet(sa) && sa.getSubAbility() == null) {
|
if (!sa.metConditions() && sa.getSubAbility() == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ public class LifeGainAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
// don't play if the conditions aren't met, unless it would trigger a
|
// don't play if the conditions aren't met, unless it would trigger a
|
||||||
// beneficial sub-condition
|
// beneficial sub-condition
|
||||||
if (!activateForCost && !sa.getConditions().areMet(sa)) {
|
if (!activateForCost && !sa.metConditions()) {
|
||||||
final AbilitySub abSub = sa.getSubAbility();
|
final AbilitySub abSub = sa.getSubAbility();
|
||||||
if (abSub != null && !sa.isWrapper() && "True".equals(source.getSVar("AIPlayForSub"))) {
|
if (abSub != null && !sa.isWrapper() && "True".equals(source.getSVar("AIPlayForSub"))) {
|
||||||
if (!abSub.getConditions().areMet(abSub)) {
|
if (!abSub.getConditions().areMet(abSub)) {
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ public class PermanentAi extends SpellAbilityAi {
|
|||||||
final Card source = sa.getHostCard();
|
final Card source = sa.getHostCard();
|
||||||
final Cost cost = sa.getPayCosts();
|
final Cost cost = sa.getPayCosts();
|
||||||
|
|
||||||
if (sa.getConditions() != null && !sa.getConditions().areMet(sa)) {
|
if (!sa.metConditions()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,19 @@ package forge.game;
|
|||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
|
|
||||||
|
import forge.game.card.Card;
|
||||||
|
|
||||||
public class CardTraitPredicates {
|
public class CardTraitPredicates {
|
||||||
|
|
||||||
|
public static final Predicate<CardTraitBase> isHostCard(final Card host) {
|
||||||
|
return new Predicate<CardTraitBase>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(final CardTraitBase sa) {
|
||||||
|
return host.equals(sa.getHostCard());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public static final Predicate<CardTraitBase> hasParam(final String name) {
|
public static final Predicate<CardTraitBase> hasParam(final String name) {
|
||||||
return new Predicate<CardTraitBase>() {
|
return new Predicate<CardTraitBase>() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import forge.card.MagicColor;
|
|||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardState;
|
import forge.game.card.CardState;
|
||||||
|
import forge.game.cost.Cost;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.staticability.StaticAbility;
|
import forge.game.staticability.StaticAbility;
|
||||||
@@ -131,6 +132,9 @@ public class ForgeScript {
|
|||||||
return !sa.isManaAbility();
|
return !sa.isManaAbility();
|
||||||
} else if (property.equals("withoutXCost")) {
|
} else if (property.equals("withoutXCost")) {
|
||||||
return !sa.costHasManaX();
|
return !sa.costHasManaX();
|
||||||
|
} else if (property.equals("hasTapCost")) {
|
||||||
|
Cost cost = sa.getPayCosts();
|
||||||
|
return cost != null && cost.hasTapCost();
|
||||||
} else if (property.equals("Buyback")) {
|
} else if (property.equals("Buyback")) {
|
||||||
return sa.isBuyBackAbility();
|
return sa.isBuyBackAbility();
|
||||||
} else if (property.equals("Cycling")) {
|
} else if (property.equals("Cycling")) {
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
*/
|
*/
|
||||||
package forge.game;
|
package forge.game;
|
||||||
|
|
||||||
import com.google.common.base.Predicates;
|
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
@@ -252,6 +251,18 @@ public final class GameActionUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sa.isManaAbility() && sa.isActivatedAbility() && activator.hasKeyword("Piracy") && source.isLand() && source.isInPlay() && !activator.equals(source.getController()) && sa.getPayCosts().hasTapCost()) {
|
||||||
|
SpellAbility newSA = sa.copy(activator);
|
||||||
|
// to bypass Activator restriction, set Activator to Player
|
||||||
|
sa.getRestrictions().setActivator("Player");
|
||||||
|
|
||||||
|
// extra Mana restriction to only Spells
|
||||||
|
for (AbilityManaPart mp : newSA.getAllManaParts()) {
|
||||||
|
mp.setExtraManaRestriction("Spell");
|
||||||
|
}
|
||||||
|
alternatives.add(newSA);
|
||||||
|
}
|
||||||
|
|
||||||
// below are for some special cases of activated abilities
|
// below are for some special cases of activated abilities
|
||||||
if (sa.isCycling() && activator.hasKeyword("CyclingForZero")) {
|
if (sa.isCycling() && activator.hasKeyword("CyclingForZero")) {
|
||||||
for (final KeywordInterface inst : source.getKeywords()) {
|
for (final KeywordInterface inst : source.getKeywords()) {
|
||||||
@@ -277,7 +288,6 @@ public final class GameActionUtil {
|
|||||||
newSA.setDescription(sb.toString());
|
newSA.setDescription(sb.toString());
|
||||||
|
|
||||||
alternatives.add(newSA);
|
alternatives.add(newSA);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,44 +566,21 @@ public final class GameActionUtil {
|
|||||||
return eff;
|
return eff;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean hasUrzaLands(final Player p) {
|
public static String generatedTotalMana(final SpellAbility sa) {
|
||||||
final CardCollectionView landsControlled = p.getCardsIn(ZoneType.Battlefield);
|
StringBuilder sb = new StringBuilder();
|
||||||
return Iterables.any(landsControlled, Predicates.and(CardPredicates.isType("Urza's"), CardPredicates.isType("Mine")))
|
SpellAbility tail = sa;
|
||||||
&& Iterables.any(landsControlled, Predicates.and(CardPredicates.isType("Urza's"), CardPredicates.isType("Power-Plant")))
|
while (tail != null) {
|
||||||
&& Iterables.any(landsControlled, Predicates.and(CardPredicates.isType("Urza's"), CardPredicates.isType("Tower")));
|
String value = generatedMana(tail);
|
||||||
|
if (!value.isEmpty() && !"0".equals(value)) {
|
||||||
|
sb.append(value).append(" ");
|
||||||
}
|
}
|
||||||
|
tail = tail.getSubAbility();
|
||||||
public static int amountOfManaGenerated(final SpellAbility sa, boolean multiply) {
|
|
||||||
// Calculate generated mana here for stack description and resolving
|
|
||||||
|
|
||||||
int amount = sa.hasParam("Amount") ? AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("Amount"), sa) : 1;
|
|
||||||
AbilityManaPart abMana = sa.getManaPartRecursive();
|
|
||||||
|
|
||||||
if (sa.hasParam("Bonus")) {
|
|
||||||
// For mana abilities that get a bonus
|
|
||||||
// Bonus currently MULTIPLIES the base amount. Base Amounts should
|
|
||||||
// ALWAYS be Base
|
|
||||||
int bonus = 0;
|
|
||||||
if (sa.getParam("Bonus").equals("UrzaLands")) {
|
|
||||||
if (hasUrzaLands(sa.getActivatingPlayer())) {
|
|
||||||
bonus = Integer.parseInt(sa.getParam("BonusProduced"));
|
|
||||||
}
|
}
|
||||||
|
return sb.toString().trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
amount += bonus;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!multiply || abMana.isAnyMana() || abMana.isComboMana() || abMana.isSpecialMana()) {
|
|
||||||
return amount;
|
|
||||||
} else {
|
|
||||||
// For cards that produce like {C}{R} vs cards that produce {R}{R}.
|
|
||||||
return abMana.mana().split(" ").length * amount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static String generatedMana(final SpellAbility sa) {
|
public static String generatedMana(final SpellAbility sa) {
|
||||||
int amount = amountOfManaGenerated(sa, false);
|
int amount = sa.amountOfManaGenerated(false);
|
||||||
AbilityManaPart abMana = sa.getManaPart();
|
AbilityManaPart abMana = sa.getManaPart();
|
||||||
String baseMana;
|
String baseMana;
|
||||||
|
|
||||||
|
|||||||
@@ -77,4 +77,5 @@ public abstract class TriggerReplacementBase extends CardTraitBase implements II
|
|||||||
this.overridingAbility = overridingAbility0;
|
this.overridingAbility = overridingAbility0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract public SpellAbility ensureAbility();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
package forge.game.ability;
|
package forge.game.ability;
|
||||||
|
|
||||||
import forge.game.ability.effects.ChangeZoneAllEffect;
|
|
||||||
import forge.game.ability.effects.ChangeZoneEffect;
|
|
||||||
import forge.game.ability.effects.ManaEffect;
|
|
||||||
import forge.game.ability.effects.ManaReflectedEffect;
|
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.cost.Cost;
|
import forge.game.cost.Cost;
|
||||||
import forge.game.spellability.AbilityActivated;
|
import forge.game.spellability.AbilityActivated;
|
||||||
@@ -15,8 +11,6 @@ import java.util.Map;
|
|||||||
public class AbilityApiBased extends AbilityActivated {
|
public class AbilityApiBased extends AbilityActivated {
|
||||||
private final SpellAbilityEffect effect;
|
private final SpellAbilityEffect effect;
|
||||||
|
|
||||||
private static final long serialVersionUID = -4183793555528531978L;
|
|
||||||
|
|
||||||
public AbilityApiBased(ApiType api0, Card sourceCard, Cost abCost, TargetRestrictions tgt, Map<String, String> params0) {
|
public AbilityApiBased(ApiType api0, Card sourceCard, Cost abCost, TargetRestrictions tgt, Map<String, String> params0) {
|
||||||
super(sourceCard, abCost, tgt);
|
super(sourceCard, abCost, tgt);
|
||||||
originalMapParams.putAll(params0);
|
originalMapParams.putAll(params0);
|
||||||
@@ -24,13 +18,12 @@ public class AbilityApiBased extends AbilityActivated {
|
|||||||
api = api0;
|
api = api0;
|
||||||
effect = api.getSpellEffect();
|
effect = api.getSpellEffect();
|
||||||
|
|
||||||
if (effect instanceof ManaEffect || effect instanceof ManaReflectedEffect) {
|
if (api.equals(ApiType.Mana) || api.equals(ApiType.ManaReflected)) {
|
||||||
|
|
||||||
this.setManaPart(new AbilityManaPart(sourceCard, mapParams));
|
this.setManaPart(new AbilityManaPart(sourceCard, mapParams));
|
||||||
this.setUndoable(true); // will try at least
|
this.setUndoable(true); // will try at least
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effect instanceof ChangeZoneEffect || effect instanceof ChangeZoneAllEffect) {
|
if (api.equals(ApiType.ChangeZone) || api.equals(ApiType.ChangeZoneAll)) {
|
||||||
AbilityFactory.adjustChangeZoneTarget(mapParams, this);
|
AbilityFactory.adjustChangeZoneTarget(mapParams, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1388,7 +1388,7 @@ public class AbilityUtils {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// check conditions
|
// check conditions
|
||||||
if (sa.getConditions().areMet(sa)) {
|
if (sa.metConditions()) {
|
||||||
if (sa.isWrapper() || StringUtils.isBlank(sa.getParam("UnlessCost"))) {
|
if (sa.isWrapper() || StringUtils.isBlank(sa.getParam("UnlessCost"))) {
|
||||||
sa.resolve();
|
sa.resolve();
|
||||||
}
|
}
|
||||||
@@ -1656,10 +1656,15 @@ public class AbilityUtils {
|
|||||||
|
|
||||||
// Count$Kicked.<numHB>.<numNotHB>
|
// Count$Kicked.<numHB>.<numNotHB>
|
||||||
if (sq[0].startsWith("Kicked")) {
|
if (sq[0].startsWith("Kicked")) {
|
||||||
boolean kicked = ((SpellAbility)ctb).isKicked() || c.getKickerMagnitude() > 0;
|
boolean kicked = sa.isKicked() || c.getKickerMagnitude() > 0;
|
||||||
return CardFactoryUtil.doXMath(Integer.parseInt(kicked ? sq[1] : sq[2]), expr, c);
|
return CardFactoryUtil.doXMath(Integer.parseInt(kicked ? sq[1] : sq[2]), expr, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Count$UrzaLands.<numHB>.<numNotHB>
|
||||||
|
if (sq[0].startsWith("UrzaLands")) {
|
||||||
|
return CardFactoryUtil.doXMath(Integer.parseInt(sa.getActivatingPlayer().hasUrzaLands() ? sq[1] : sq[2]), expr, c);
|
||||||
|
}
|
||||||
|
|
||||||
//Count$SearchedLibrary.<DefinedPlayer>
|
//Count$SearchedLibrary.<DefinedPlayer>
|
||||||
if (sq[0].contains("SearchedLibrary")) {
|
if (sq[0].contains("SearchedLibrary")) {
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ public enum ApiType {
|
|||||||
Repeat (RepeatEffect.class),
|
Repeat (RepeatEffect.class),
|
||||||
RepeatEach (RepeatEachEffect.class),
|
RepeatEach (RepeatEachEffect.class),
|
||||||
ReplaceEffect (ReplaceEffect.class),
|
ReplaceEffect (ReplaceEffect.class),
|
||||||
|
ReplaceMana (ReplaceManaEffect.class),
|
||||||
ReplaceDamage (ReplaceDamageEffect.class),
|
ReplaceDamage (ReplaceDamageEffect.class),
|
||||||
ReplaceSplitDamage (ReplaceSplitDamageEffect.class),
|
ReplaceSplitDamage (ReplaceSplitDamageEffect.class),
|
||||||
RestartGame (RestartGameEffect.class),
|
RestartGame (RestartGameEffect.class),
|
||||||
|
|||||||
@@ -2,10 +2,6 @@ package forge.game.ability;
|
|||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import forge.game.ability.effects.ChangeZoneAllEffect;
|
|
||||||
import forge.game.ability.effects.ChangeZoneEffect;
|
|
||||||
import forge.game.ability.effects.ManaEffect;
|
|
||||||
import forge.game.ability.effects.ManaReflectedEffect;
|
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.cost.Cost;
|
import forge.game.cost.Cost;
|
||||||
import forge.game.spellability.AbilityManaPart;
|
import forge.game.spellability.AbilityManaPart;
|
||||||
@@ -28,11 +24,11 @@ public class SpellApiBased extends Spell {
|
|||||||
// A spell is always intrinsic
|
// A spell is always intrinsic
|
||||||
this.setIntrinsic(true);
|
this.setIntrinsic(true);
|
||||||
|
|
||||||
if (effect instanceof ManaEffect || effect instanceof ManaReflectedEffect) {
|
if (api.equals(ApiType.Mana) || api.equals(ApiType.ManaReflected)) {
|
||||||
this.setManaPart(new AbilityManaPart(sourceCard, mapParams));
|
this.setManaPart(new AbilityManaPart(sourceCard, mapParams));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effect instanceof ChangeZoneEffect || effect instanceof ChangeZoneAllEffect) {
|
if (api.equals(ApiType.ChangeZone) || api.equals(ApiType.ChangeZoneAll)) {
|
||||||
AbilityFactory.adjustChangeZoneTarget(mapParams, this);
|
AbilityFactory.adjustChangeZoneTarget(mapParams, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import forge.game.mana.Mana;
|
|||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.AbilityManaPart;
|
import forge.game.spellability.AbilityManaPart;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.spellability.TargetRestrictions;
|
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.util.Localizer;
|
import forge.util.Localizer;
|
||||||
|
|
||||||
@@ -37,7 +36,6 @@ public class ManaEffect extends SpellAbilityEffect {
|
|||||||
sa.setUndoable(sa.isAbility() && sa.isUndoable());
|
sa.setUndoable(sa.isAbility() && sa.isUndoable());
|
||||||
|
|
||||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
|
||||||
final boolean optional = sa.hasParam("Optional");
|
final boolean optional = sa.hasParam("Optional");
|
||||||
final Game game = sa.getActivatingPlayer().getGame();
|
final Game game = sa.getActivatingPlayer().getGame();
|
||||||
|
|
||||||
@@ -45,41 +43,21 @@ public class ManaEffect extends SpellAbilityEffect {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sa.hasParam("DoubleManaInPool")) {
|
|
||||||
for (final Player player : tgtPlayers) {
|
|
||||||
for (byte color : ManaAtom.MANATYPES) {
|
|
||||||
int amountColor = player.getManaPool().getAmountOfColor(color);
|
|
||||||
for (int i = 0; i < amountColor; i++) {
|
|
||||||
abMana.produceMana(MagicColor.toShortString(color), player, sa);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sa.hasParam("ProduceNoOtherMana")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (abMana.isComboMana()) {
|
|
||||||
for (Player p : tgtPlayers) {
|
for (Player p : tgtPlayers) {
|
||||||
int amount = sa.hasParam("Amount") ? AbilityUtils.calculateAmount(card, sa.getParam("Amount"), sa) : 1;
|
if (sa.usesTargeting() && !p.canBeTargetedBy(sa)) {
|
||||||
if (tgt != null && !p.canBeTargetedBy(sa)) {
|
|
||||||
// Illegal target. Skip.
|
// Illegal target. Skip.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player activator = sa.getActivatingPlayer();
|
if (abMana.isComboMana()) {
|
||||||
|
int amount = sa.hasParam("Amount") ? AbilityUtils.calculateAmount(card, sa.getParam("Amount"), sa) : 1;
|
||||||
|
|
||||||
String express = abMana.getExpressChoice();
|
String express = abMana.getExpressChoice();
|
||||||
String[] colorsProduced = abMana.getComboColors().split(" ");
|
String[] colorsProduced = abMana.getComboColors().split(" ");
|
||||||
|
|
||||||
final StringBuilder choiceString = new StringBuilder();
|
final StringBuilder choiceString = new StringBuilder();
|
||||||
ColorSet colorOptions = null;
|
ColorSet colorOptions = ColorSet.fromNames(colorsProduced);
|
||||||
String[] colorsNeeded = express.isEmpty() ? null : express.split(" ");
|
String[] colorsNeeded = express.isEmpty() ? null : express.split(" ");
|
||||||
if (!abMana.isAnyMana()) {
|
|
||||||
colorOptions = ColorSet.fromNames(colorsProduced);
|
|
||||||
} else {
|
|
||||||
colorOptions = ColorSet.fromNames(MagicColor.Constant.ONLY_COLORS);
|
|
||||||
}
|
|
||||||
boolean differentChoice = abMana.getOrigProduced().contains("Different");
|
boolean differentChoice = abMana.getOrigProduced().contains("Different");
|
||||||
ColorSet fullOptions = colorOptions;
|
ColorSet fullOptions = colorOptions;
|
||||||
for (int nMana = 0; nMana < amount; nMana++) {
|
for (int nMana = 0; nMana < amount; nMana++) {
|
||||||
@@ -93,10 +71,10 @@ public class ManaEffect extends SpellAbilityEffect {
|
|||||||
// just use the first possible color.
|
// just use the first possible color.
|
||||||
choice = colorsProduced[differentChoice ? nMana : 0];
|
choice = colorsProduced[differentChoice ? nMana : 0];
|
||||||
} else {
|
} else {
|
||||||
byte chosenColor = activator.getController().chooseColor(Localizer.getInstance().getMessage("lblSelectManaProduce"), sa,
|
byte chosenColor = p.getController().chooseColor(Localizer.getInstance().getMessage("lblSelectManaProduce"), sa,
|
||||||
differentChoice ? fullOptions : colorOptions);
|
differentChoice ? fullOptions : colorOptions);
|
||||||
if (chosenColor == 0)
|
if (chosenColor == 0)
|
||||||
throw new RuntimeException("ManaEffect::resolve() /*combo mana*/ - " + activator + " color mana choice is empty for " + card.getName());
|
throw new RuntimeException("ManaEffect::resolve() /*combo mana*/ - " + p + " color mana choice is empty for " + card.getName());
|
||||||
|
|
||||||
fullOptions = ColorSet.fromMask(fullOptions.getMyColor() - chosenColor);
|
fullOptions = ColorSet.fromMask(fullOptions.getMyColor() - chosenColor);
|
||||||
choice = MagicColor.toShortString(chosenColor);
|
choice = MagicColor.toShortString(chosenColor);
|
||||||
@@ -116,18 +94,10 @@ public class ManaEffect extends SpellAbilityEffect {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
game.action.nofityOfValue(sa, card, Localizer.getInstance().getMessage("lblPlayerPickedChosen", activator.getName(), choiceString), activator);
|
game.getAction().nofityOfValue(sa, card, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), choiceString), p);
|
||||||
abMana.setExpressChoice(choiceString.toString());
|
abMana.setExpressChoice(choiceString.toString());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (abMana.isAnyMana()) {
|
else if (abMana.isAnyMana()) {
|
||||||
for (Player p : tgtPlayers) {
|
|
||||||
if (tgt != null && !p.canBeTargetedBy(sa)) {
|
|
||||||
// Illegal target. Skip.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Player act = sa.getActivatingPlayer();
|
|
||||||
// AI color choice is set in ComputerUtils so only human players need to make a choice
|
// AI color choice is set in ComputerUtils so only human players need to make a choice
|
||||||
|
|
||||||
String colorsNeeded = abMana.getExpressChoice();
|
String colorsNeeded = abMana.getExpressChoice();
|
||||||
@@ -142,20 +112,14 @@ public class ManaEffect extends SpellAbilityEffect {
|
|||||||
colorMenu = mask == 0 ? ColorSet.ALL_COLORS : ColorSet.fromMask(mask);
|
colorMenu = mask == 0 ? ColorSet.ALL_COLORS : ColorSet.fromMask(mask);
|
||||||
byte val = p.getController().chooseColor(Localizer.getInstance().getMessage("lblSelectManaProduce"), sa, colorMenu);
|
byte val = p.getController().chooseColor(Localizer.getInstance().getMessage("lblSelectManaProduce"), sa, colorMenu);
|
||||||
if (0 == val) {
|
if (0 == val) {
|
||||||
throw new RuntimeException("ManaEffect::resolve() /*any mana*/ - " + act + " color mana choice is empty for " + card.getName());
|
throw new RuntimeException("ManaEffect::resolve() /*any mana*/ - " + p + " color mana choice is empty for " + card.getName());
|
||||||
}
|
}
|
||||||
choice = MagicColor.toShortString(val);
|
choice = MagicColor.toShortString(val);
|
||||||
|
|
||||||
game.action.nofityOfValue(sa, card, Localizer.getInstance().getMessage("lblPlayerPickedChosen", act.getName(), choice), act);
|
game.getAction().nofityOfValue(sa, card, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), choice), p);
|
||||||
abMana.setExpressChoice(choice);
|
abMana.setExpressChoice(choice);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (abMana.isSpecialMana()) {
|
else if (abMana.isSpecialMana()) {
|
||||||
for (Player p : tgtPlayers) {
|
|
||||||
if (tgt != null && !p.canBeTargetedBy(sa)) {
|
|
||||||
// Illegal target. Skip.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String type = abMana.getOrigProduced().split("Special ")[1];
|
String type = abMana.getOrigProduced().split("Special ")[1];
|
||||||
|
|
||||||
@@ -177,7 +141,7 @@ public class ManaEffect extends SpellAbilityEffect {
|
|||||||
if (cs.isMonoColor())
|
if (cs.isMonoColor())
|
||||||
sb.append(MagicColor.toShortString(s.getColorMask()));
|
sb.append(MagicColor.toShortString(s.getColorMask()));
|
||||||
else /* (cs.isMulticolor()) */ {
|
else /* (cs.isMulticolor()) */ {
|
||||||
byte chosenColor = sa.getActivatingPlayer().getController().chooseColor(Localizer.getInstance().getMessage("lblChooseSingleColorFromTarget", s.toString()), sa, cs);
|
byte chosenColor = p.getController().chooseColor(Localizer.getInstance().getMessage("lblChooseSingleColorFromTarget", s.toString()), sa, cs);
|
||||||
sb.append(MagicColor.toShortString(chosenColor));
|
sb.append(MagicColor.toShortString(chosenColor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,34 +174,36 @@ public class ManaEffect extends SpellAbilityEffect {
|
|||||||
abMana.setExpressChoice(ColorSet.fromMask(colors));
|
abMana.setExpressChoice(ColorSet.fromMask(colors));
|
||||||
} else if (type.startsWith("EachColoredManaSymbol")) {
|
} else if (type.startsWith("EachColoredManaSymbol")) {
|
||||||
final String res = type.split("_")[1];
|
final String res = type.split("_")[1];
|
||||||
final CardCollection list = AbilityUtils.getDefinedCards(card, res, sa);
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for (Card c : list) {
|
for (Card c : AbilityUtils.getDefinedCards(card, res, sa)) {
|
||||||
String mana = c.getManaCost().toString();
|
for (ManaCostShard s : c.getManaCost()) {
|
||||||
for (int i = 0; i < mana.length(); i++) {
|
ColorSet cs = ColorSet.fromMask(s.getColorMask());
|
||||||
char symbol = mana.charAt(i);
|
if(cs.isColorless())
|
||||||
switch (symbol) {
|
continue;
|
||||||
case 'W':
|
sb.append(' ');
|
||||||
case 'U':
|
if (cs.isMonoColor())
|
||||||
case 'B':
|
sb.append(MagicColor.toShortString(s.getColorMask()));
|
||||||
case 'R':
|
else /* (cs.isMulticolor()) */ {
|
||||||
case 'G':
|
byte chosenColor = p.getController().chooseColor(Localizer.getInstance().getMessage("lblChooseSingleColorFromTarget", s.toString()), sa, cs);
|
||||||
sb.append(symbol).append(' ');
|
sb.append(MagicColor.toShortString(chosenColor));
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
abMana.setExpressChoice(sb.toString().trim());
|
abMana.setExpressChoice(sb.toString().trim());
|
||||||
|
} else if (type.startsWith("DoubleManaInPool")) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (byte color : ManaAtom.MANATYPES) {
|
||||||
|
sb.append(StringUtils.repeat(MagicColor.toShortString(color), " ", p.getManaPool().getAmountOfColor(color))).append(" ");
|
||||||
|
}
|
||||||
|
abMana.setExpressChoice(sb.toString().trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (abMana.getExpressChoice().isEmpty()) {
|
if (abMana.getExpressChoice().isEmpty()) {
|
||||||
System.out.println("AbilityFactoryMana::manaResolve() - special mana effect is empty for " + sa.getHostCard().getName());
|
System.out.println("AbilityFactoryMana::manaResolve() - special mana effect is empty for " + sa.getHostCard().getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (final Player player : tgtPlayers) {
|
abMana.produceMana(GameActionUtil.generatedMana(sa), p, sa);
|
||||||
abMana.produceMana(GameActionUtil.generatedMana(sa), player, sa);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only clear express choice after mana has been produced
|
// Only clear express choice after mana has been produced
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import forge.game.spellability.SpellAbility;
|
|||||||
import forge.util.Localizer;
|
import forge.util.Localizer;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
@@ -29,8 +28,7 @@ public class ManaReflectedEffect extends SpellAbilityEffect {
|
|||||||
|
|
||||||
final Collection<String> colors = CardUtil.getReflectableManaColors(sa);
|
final Collection<String> colors = CardUtil.getReflectableManaColors(sa);
|
||||||
|
|
||||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
for (final Player player : getTargetPlayers(sa)) {
|
||||||
for (final Player player : tgtPlayers) {
|
|
||||||
final String generated = generatedReflectedMana(sa, colors, player);
|
final String generated = generatedReflectedMana(sa, colors, player);
|
||||||
ma.produceMana(generated, player, sa);
|
ma.produceMana(generated, player, sa);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ import forge.game.ability.AbilityKey;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
|
import forge.game.GameLogEntryType;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.replacement.ReplacementResult;
|
import forge.game.replacement.ReplacementResult;
|
||||||
import forge.game.replacement.ReplacementType;
|
import forge.game.replacement.ReplacementType;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
|
import forge.util.TextUtil;
|
||||||
|
|
||||||
public class ReplaceDamageEffect extends SpellAbilityEffect {
|
public class ReplaceDamageEffect extends SpellAbilityEffect {
|
||||||
|
|
||||||
@@ -58,6 +60,12 @@ public class ReplaceDamageEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
params.put(AbilityKey.DamageAmount, dmg);
|
params.put(AbilityKey.DamageAmount, dmg);
|
||||||
|
|
||||||
|
// need to log Updated events there, or the log is wrong order
|
||||||
|
String message = sa.getReplacementEffect().toString();
|
||||||
|
if ( !StringUtils.isEmpty(message)) {
|
||||||
|
message = TextUtil.fastReplace(message, "CARDNAME", card.getName());
|
||||||
|
game.getGameLog().add(GameLogEntryType.EFFECT_REPLACED, message);
|
||||||
|
}
|
||||||
|
|
||||||
//try to call replacementHandler with new Params
|
//try to call replacementHandler with new Params
|
||||||
ReplacementResult result = game.getReplacementHandler().run(event, params);
|
ReplacementResult result = game.getReplacementHandler().run(event, params);
|
||||||
|
|||||||
@@ -3,9 +3,12 @@ package forge.game.ability.effects;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
|
import forge.game.GameLogEntryType;
|
||||||
import forge.game.GameObject;
|
import forge.game.GameObject;
|
||||||
import forge.game.ability.AbilityKey;
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
@@ -16,6 +19,7 @@ import forge.game.player.Player;
|
|||||||
import forge.game.replacement.ReplacementResult;
|
import forge.game.replacement.ReplacementResult;
|
||||||
import forge.game.replacement.ReplacementType;
|
import forge.game.replacement.ReplacementType;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
|
import forge.util.TextUtil;
|
||||||
|
|
||||||
public class ReplaceEffect extends SpellAbilityEffect {
|
public class ReplaceEffect extends SpellAbilityEffect {
|
||||||
|
|
||||||
@@ -61,6 +65,13 @@ public class ReplaceEffect extends SpellAbilityEffect {
|
|||||||
params.put(AbilityKey.EffectOnly, true);
|
params.put(AbilityKey.EffectOnly, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// need to log Updated events there, or the log is wrong order
|
||||||
|
String message = sa.getReplacementEffect().toString();
|
||||||
|
if ( !StringUtils.isEmpty(message)) {
|
||||||
|
message = TextUtil.fastReplace(message, "CARDNAME", card.getName());
|
||||||
|
game.getGameLog().add(GameLogEntryType.EFFECT_REPLACED, message);
|
||||||
|
}
|
||||||
|
|
||||||
//try to call replacementHandler with new Params
|
//try to call replacementHandler with new Params
|
||||||
ReplacementResult result = game.getReplacementHandler().run(retype, params);
|
ReplacementResult result = game.getReplacementHandler().run(retype, params);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
package forge.game.ability.effects;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
import forge.card.ColorSet;
|
||||||
|
import forge.card.MagicColor;
|
||||||
|
import forge.game.Game;
|
||||||
|
import forge.game.GameLogEntryType;
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
|
import forge.game.card.Card;
|
||||||
|
import forge.game.player.Player;
|
||||||
|
import forge.game.replacement.ReplacementResult;
|
||||||
|
import forge.game.replacement.ReplacementType;
|
||||||
|
import forge.game.spellability.SpellAbility;
|
||||||
|
import forge.util.TextUtil;
|
||||||
|
|
||||||
|
public class ReplaceManaEffect extends SpellAbilityEffect {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolve(SpellAbility sa) {
|
||||||
|
final Card card = sa.getHostCard();
|
||||||
|
final Player player = sa.getActivatingPlayer();
|
||||||
|
final Game game = card.getGame();
|
||||||
|
|
||||||
|
// outside of Replacement Effect, unwanted result
|
||||||
|
if (!sa.isReplacementAbility()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ReplacementType event = sa.getReplacementEffect().getMode();
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<AbilityKey, Object> originalParams = (Map<AbilityKey, Object>) sa.getReplacingObject(AbilityKey.OriginalParams);
|
||||||
|
Map<AbilityKey, Object> params = Maps.newHashMap(originalParams);
|
||||||
|
|
||||||
|
String replaced = (String)sa.getReplacingObject(AbilityKey.Mana);
|
||||||
|
if (sa.hasParam("ReplaceMana")) {
|
||||||
|
// replace type and amount
|
||||||
|
replaced = sa.getParam("ReplaceMana");
|
||||||
|
if ("Any".equals(replaced)) {
|
||||||
|
byte rs = MagicColor.GREEN;
|
||||||
|
rs = player.getController().chooseColor("Choose a color", sa, ColorSet.ALL_COLORS);
|
||||||
|
replaced = MagicColor.toShortString(rs);
|
||||||
|
}
|
||||||
|
} else if (sa.hasParam("ReplaceType")) {
|
||||||
|
// replace color and colorless
|
||||||
|
String color = sa.getParam("ReplaceType");
|
||||||
|
if ("Any".equals(color)) {
|
||||||
|
byte rs = MagicColor.GREEN;
|
||||||
|
rs = player.getController().chooseColor("Choose a color", sa, ColorSet.ALL_COLORS);
|
||||||
|
color = MagicColor.toShortString(rs);
|
||||||
|
}
|
||||||
|
for (byte c : MagicColor.WUBRGC) {
|
||||||
|
String s = MagicColor.toShortString(c);
|
||||||
|
replaced = replaced.replace(s, color);
|
||||||
|
}
|
||||||
|
} else if (sa.hasParam("ReplaceColor")) {
|
||||||
|
// replace color
|
||||||
|
String color = sa.getParam("ReplaceColor");
|
||||||
|
if ("Chosen".equals(color)) {
|
||||||
|
if (card.hasChosenColor()) {
|
||||||
|
color = MagicColor.toShortString(card.getChosenColor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sa.hasParam("ReplaceOnly")) {
|
||||||
|
replaced = replaced.replace(sa.getParam("ReplaceOnly"), color);
|
||||||
|
} else {
|
||||||
|
for (byte c : MagicColor.WUBRG) {
|
||||||
|
String s = MagicColor.toShortString(c);
|
||||||
|
replaced = replaced.replace(s, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (sa.hasParam("ReplaceAmount")) {
|
||||||
|
// replace amount = multiples
|
||||||
|
replaced = StringUtils.repeat(replaced, " ", Integer.valueOf(sa.getParam("ReplaceAmount")));
|
||||||
|
}
|
||||||
|
params.put(AbilityKey.Mana, replaced);
|
||||||
|
|
||||||
|
// need to log Updated events there, or the log is wrong order
|
||||||
|
String message = sa.getReplacementEffect().toString();
|
||||||
|
if ( !StringUtils.isEmpty(message)) {
|
||||||
|
message = TextUtil.fastReplace(message, "CARDNAME", card.getName());
|
||||||
|
game.getGameLog().add(GameLogEntryType.EFFECT_REPLACED, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
//try to call replacementHandler with new Params
|
||||||
|
ReplacementResult result = game.getReplacementHandler().run(event, params);
|
||||||
|
switch (result) {
|
||||||
|
case NotReplaced:
|
||||||
|
case Updated: {
|
||||||
|
for (Map.Entry<AbilityKey, Object> e : params.entrySet()) {
|
||||||
|
originalParams.put(e.getKey(), e.getValue());
|
||||||
|
}
|
||||||
|
// effect was updated
|
||||||
|
originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// effect was replaced with something else
|
||||||
|
originalParams.put(AbilityKey.ReplacementResult, result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -53,7 +53,7 @@ public class ReplaceSplitDamageEffect extends SpellAbilityEffect {
|
|||||||
if (card.getType().hasStringType("Effect") && prevent <= 0) {
|
if (card.getType().hasStringType("Effect") && prevent <= 0) {
|
||||||
game.getAction().exile(card, null);
|
game.getAction().exile(card, null);
|
||||||
} else if (!StringUtils.isNumeric(varValue)) {
|
} else if (!StringUtils.isNumeric(varValue)) {
|
||||||
card.setSVar(varValue, "Number$" + prevent);
|
sa.setSVar(varValue, "Number$" + prevent);
|
||||||
}
|
}
|
||||||
|
|
||||||
Card sourceLKI = (Card) sa.getReplacingObject(AbilityKey.Source);
|
Card sourceLKI = (Card) sa.getReplacingObject(AbilityKey.Source);
|
||||||
|
|||||||
@@ -2353,7 +2353,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
if (ab.getApi() == ApiType.ManaReflected) {
|
if (ab.getApi() == ApiType.ManaReflected) {
|
||||||
colors.addAll(CardUtil.getReflectableManaColors(ab));
|
colors.addAll(CardUtil.getReflectableManaColors(ab));
|
||||||
} else {
|
} else {
|
||||||
colors = CardUtil.canProduce(6, ab.getManaPart(), colors);
|
colors = CardUtil.canProduce(6, ab, colors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2364,7 +2364,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (mana.getManaPart().canProduce(MagicColor.toShortString(s))) {
|
if (mana.canProduce(MagicColor.toShortString(s))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -358,12 +358,12 @@ public class CardFactory {
|
|||||||
// Name first so Senty has the Card name
|
// Name first so Senty has the Card name
|
||||||
c.setName(face.getName());
|
c.setName(face.getName());
|
||||||
|
|
||||||
|
for (Entry<String, String> v : face.getVariables()) c.setSVar(v.getKey(), v.getValue());
|
||||||
|
|
||||||
for (String r : face.getReplacements()) c.addReplacementEffect(ReplacementHandler.parseReplacement(r, c, true));
|
for (String r : face.getReplacements()) c.addReplacementEffect(ReplacementHandler.parseReplacement(r, c, true));
|
||||||
for (String s : face.getStaticAbilities()) c.addStaticAbility(s);
|
for (String s : face.getStaticAbilities()) c.addStaticAbility(s);
|
||||||
for (String t : face.getTriggers()) c.addTrigger(TriggerHandler.parseTrigger(t, c, true));
|
for (String t : face.getTriggers()) c.addTrigger(TriggerHandler.parseTrigger(t, c, true));
|
||||||
|
|
||||||
for (Entry<String, String> v : face.getVariables()) c.setSVar(v.getKey(), v.getValue());
|
|
||||||
|
|
||||||
// keywords not before variables
|
// keywords not before variables
|
||||||
c.addIntrinsicKeywords(face.getKeywords(), false);
|
c.addIntrinsicKeywords(face.getKeywords(), false);
|
||||||
|
|
||||||
|
|||||||
@@ -1475,7 +1475,7 @@ public class CardFactoryUtil {
|
|||||||
for (Card card : otb) {
|
for (Card card : otb) {
|
||||||
if (!card.isTapped() || !untappedOnly) {
|
if (!card.isTapped() || !untappedOnly) {
|
||||||
for (SpellAbility ma : card.getManaAbilities()) {
|
for (SpellAbility ma : card.getManaAbilities()) {
|
||||||
if (ma.getManaPart().canProduce(MagicColor.toShortString(color))) {
|
if (ma.canProduce(MagicColor.toShortString(color))) {
|
||||||
uniqueColors++;
|
uniqueColors++;
|
||||||
continue outer;
|
continue outer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -912,7 +912,7 @@ public class CardProperty {
|
|||||||
} else if (property.startsWith("canProduceManaColor")) {
|
} else if (property.startsWith("canProduceManaColor")) {
|
||||||
final String color = property.split("canProduceManaColor ")[1];
|
final String color = property.split("canProduceManaColor ")[1];
|
||||||
for (SpellAbility ma : card.getManaAbilities()) {
|
for (SpellAbility ma : card.getManaAbilities()) {
|
||||||
if (ma.getManaPart().canProduce(MagicColor.toShortString(color))) {
|
if (ma.canProduce(MagicColor.toShortString(color))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -391,7 +391,6 @@ public final class CardUtil {
|
|||||||
|
|
||||||
final String colorOrType = sa.getParam("ColorOrType");
|
final String colorOrType = sa.getParam("ColorOrType");
|
||||||
// currently Color or Type, Type is colors + colorless
|
// currently Color or Type, Type is colors + colorless
|
||||||
final String validCard = sa.getParam("Valid");
|
|
||||||
final String reflectProperty = sa.getParam("ReflectProperty");
|
final String reflectProperty = sa.getParam("ReflectProperty");
|
||||||
// Produce (Reflecting Pool) or Is (Meteor Crater)
|
// Produce (Reflecting Pool) or Is (Meteor Crater)
|
||||||
|
|
||||||
@@ -400,8 +399,10 @@ public final class CardUtil {
|
|||||||
maxChoices++;
|
maxChoices++;
|
||||||
}
|
}
|
||||||
|
|
||||||
CardCollection cards = null;
|
CardCollection cards;
|
||||||
|
|
||||||
|
if (sa.hasParam("Valid")) {
|
||||||
|
final String validCard = sa.getParam("Valid");
|
||||||
// Reuse AF_Defined in a slightly different way
|
// Reuse AF_Defined in a slightly different way
|
||||||
if (validCard.startsWith("Defined.")) {
|
if (validCard.startsWith("Defined.")) {
|
||||||
cards = AbilityUtils.getDefinedCards(card, TextUtil.fastReplace(validCard, "Defined.", ""), abMana);
|
cards = AbilityUtils.getDefinedCards(card, TextUtil.fastReplace(validCard, "Defined.", ""), abMana);
|
||||||
@@ -414,14 +415,14 @@ public final class CardUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remove anything cards that is already in parents
|
// remove anything cards that is already in parents
|
||||||
for (final Card p : parents) {
|
cards.removeAll(parents);
|
||||||
cards.remove(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((cards.size() == 0) && !reflectProperty.equals("Produced")) {
|
if (cards.isEmpty()) {
|
||||||
return colors;
|
return colors;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
cards = new CardCollection();
|
||||||
|
}
|
||||||
if (reflectProperty.equals("Is")) { // Meteor Crater
|
if (reflectProperty.equals("Is")) { // Meteor Crater
|
||||||
for (final Card card1 : cards) {
|
for (final Card card1 : cards) {
|
||||||
// For each card, go through all the colors and if the card is that color, add
|
// For each card, go through all the colors and if the card is that color, add
|
||||||
@@ -436,7 +437,7 @@ public final class CardUtil {
|
|||||||
}
|
}
|
||||||
} else if (reflectProperty.equals("Produced")) {
|
} else if (reflectProperty.equals("Produced")) {
|
||||||
// Why is this name so similar to the one below?
|
// Why is this name so similar to the one below?
|
||||||
final String producedColors = abMana instanceof AbilitySub ? (String) abMana.getRootAbility().getTriggeringObject(AbilityKey.Produced) : (String) abMana.getTriggeringObject(AbilityKey.Produced);
|
final String producedColors = (String) abMana.getRootAbility().getTriggeringObject(AbilityKey.Produced);
|
||||||
for (final String col : MagicColor.Constant.ONLY_COLORS) {
|
for (final String col : MagicColor.Constant.ONLY_COLORS) {
|
||||||
final String s = MagicColor.toShortString(col);
|
final String s = MagicColor.toShortString(col);
|
||||||
if (producedColors.contains(s)) {
|
if (producedColors.contains(s)) {
|
||||||
@@ -469,7 +470,7 @@ public final class CardUtil {
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
colors = canProduce(maxChoices, ab.getManaPart(), colors);
|
colors = canProduce(maxChoices, ab, colors);
|
||||||
if (!parents.contains(ab.getHostCard())) {
|
if (!parents.contains(ab.getHostCard())) {
|
||||||
parents.add(ab.getHostCard());
|
parents.add(ab.getHostCard());
|
||||||
}
|
}
|
||||||
@@ -486,19 +487,18 @@ public final class CardUtil {
|
|||||||
return colors;
|
return colors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Set<String> canProduce(final int maxChoices, final AbilityManaPart ab,
|
public static Set<String> canProduce(final int maxChoices, final SpellAbility sa,
|
||||||
final Set<String> colors) {
|
final Set<String> colors) {
|
||||||
if (ab == null) {
|
if (sa == null) {
|
||||||
return colors;
|
return colors;
|
||||||
}
|
}
|
||||||
for (final String col : MagicColor.Constant.ONLY_COLORS) {
|
for (final String col : MagicColor.Constant.ONLY_COLORS) {
|
||||||
final String s = MagicColor.toShortString(col);
|
if (sa.canProduce(MagicColor.toShortString(col))) {
|
||||||
if (ab.canProduce(s)) {
|
|
||||||
colors.add(col);
|
colors.add(col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxChoices == 6 && ab.canProduce("C")) {
|
if (maxChoices == 6 && sa.canProduce("C")) {
|
||||||
colors.add(MagicColor.Constant.COLORLESS);
|
colors.add(MagicColor.Constant.COLORLESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ package forge.game.mana;
|
|||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
import forge.card.ColorSet;
|
import forge.card.ColorSet;
|
||||||
import forge.card.MagicColor;
|
import forge.card.MagicColor;
|
||||||
import forge.card.mana.IParserManaCost;
|
import forge.card.mana.IParserManaCost;
|
||||||
@@ -105,11 +107,16 @@ public class ManaCostBeingPaid {
|
|||||||
xCount = copy.xCount;
|
xCount = copy.xCount;
|
||||||
totalCount = copy.totalCount;
|
totalCount = copy.totalCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "{x=" + xCount + " total=" + totalCount + "}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// holds Mana_Part objects
|
// holds Mana_Part objects
|
||||||
// ManaPartColor is stored before ManaPartGeneric
|
// ManaPartColor is stored before ManaPartGeneric
|
||||||
private final Map<ManaCostShard, ShardCount> unpaidShards = new HashMap<>();
|
private final Map<ManaCostShard, ShardCount> unpaidShards = Maps.newHashMap();
|
||||||
private Map<String, Integer> xManaCostPaidByColor;
|
private Map<String, Integer> xManaCostPaidByColor;
|
||||||
private final String sourceRestriction;
|
private final String sourceRestriction;
|
||||||
private byte sunburstMap = 0;
|
private byte sunburstMap = 0;
|
||||||
@@ -124,7 +131,7 @@ public class ManaCostBeingPaid {
|
|||||||
unpaidShards.put(m.getKey(), new ShardCount(m.getValue()));
|
unpaidShards.put(m.getKey(), new ShardCount(m.getValue()));
|
||||||
}
|
}
|
||||||
if (manaCostBeingPaid.xManaCostPaidByColor != null) {
|
if (manaCostBeingPaid.xManaCostPaidByColor != null) {
|
||||||
xManaCostPaidByColor = new HashMap<>(manaCostBeingPaid.xManaCostPaidByColor);
|
xManaCostPaidByColor = Maps.newHashMap(manaCostBeingPaid.xManaCostPaidByColor);
|
||||||
}
|
}
|
||||||
sourceRestriction = manaCostBeingPaid.sourceRestriction;
|
sourceRestriction = manaCostBeingPaid.sourceRestriction;
|
||||||
sunburstMap = manaCostBeingPaid.sunburstMap;
|
sunburstMap = manaCostBeingPaid.sunburstMap;
|
||||||
@@ -503,7 +510,7 @@ public class ManaCostBeingPaid {
|
|||||||
sc.xCount--;
|
sc.xCount--;
|
||||||
String color = MagicColor.toShortString(colorMask);
|
String color = MagicColor.toShortString(colorMask);
|
||||||
if (xManaCostPaidByColor == null) {
|
if (xManaCostPaidByColor == null) {
|
||||||
xManaCostPaidByColor = new HashMap<>();
|
xManaCostPaidByColor = Maps.newHashMap();
|
||||||
}
|
}
|
||||||
Integer xColor = xManaCostPaidByColor.get(color);
|
Integer xColor = xManaCostPaidByColor.get(color);
|
||||||
if (xColor == null) {
|
if (xColor == null) {
|
||||||
@@ -602,19 +609,7 @@ public class ManaCostBeingPaid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int nGeneric = getGenericManaAmount();
|
int nGeneric = getGenericManaAmount();
|
||||||
List<ManaCostShard> shards = new ArrayList<>(unpaidShards.keySet());
|
List<ManaCostShard> shards = Lists.newArrayList(unpaidShards.keySet());
|
||||||
|
|
||||||
// TODO Fix this. Should we really be changing Shards here?
|
|
||||||
if (false && pool != null) { //replace shards with generic mana if they can be paid with any color mana
|
|
||||||
for (int i = 0; i < shards.size(); i++) {
|
|
||||||
ManaCostShard shard = shards.get(i);
|
|
||||||
if (shard != ManaCostShard.GENERIC && pool.getPossibleColorUses(shard.getColorMask()) == ManaAtom.ALL_MANA_TYPES) {
|
|
||||||
nGeneric += unpaidShards.get(shard).totalCount;
|
|
||||||
shards.remove(i);
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nGeneric > 0) {
|
if (nGeneric > 0) {
|
||||||
if (nGeneric <= 20) {
|
if (nGeneric <= 20) {
|
||||||
|
|||||||
@@ -166,26 +166,30 @@ public class ManaPool extends ManaConversionMatrix implements Iterable<Mana> {
|
|||||||
owner.updateManaForView();
|
owner.updateManaForView();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeMana(final Mana mana) {
|
private boolean removeMana(final Mana mana) {
|
||||||
Collection<Mana> cm = floatingMana.get(mana.getColor());
|
if (floatingMana.remove(mana.getColor(), mana)) {
|
||||||
if (cm.remove(mana)) {
|
|
||||||
owner.updateManaForView();
|
owner.updateManaForView();
|
||||||
owner.getGame().fireEvent(new GameEventManaPool(owner, EventValueChangeType.Removed, mana));
|
owner.getGame().fireEvent(new GameEventManaPool(owner, EventValueChangeType.Removed, mana));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void payManaFromAbility(final SpellAbility saPaidFor, ManaCostBeingPaid manaCost, final SpellAbility saPayment) {
|
public final void payManaFromAbility(final SpellAbility saPaidFor, ManaCostBeingPaid manaCost, final SpellAbility saPayment) {
|
||||||
// Mana restriction must be checked before this method is called
|
// Mana restriction must be checked before this method is called
|
||||||
final List<SpellAbility> paidAbs = saPaidFor.getPayingManaAbilities();
|
final List<SpellAbility> paidAbs = saPaidFor.getPayingManaAbilities();
|
||||||
AbilityManaPart abManaPart = saPayment.getManaPartRecursive();
|
|
||||||
|
|
||||||
paidAbs.add(saPayment); // assumes some part on the mana produced by the ability will get used
|
paidAbs.add(saPayment); // assumes some part on the mana produced by the ability will get used
|
||||||
for (final Mana mana : abManaPart.getLastManaProduced()) {
|
|
||||||
|
// need to get all mana from all ManaAbilities of the SpellAbility
|
||||||
|
for (AbilityManaPart mp : saPayment.getAllManaParts()) {
|
||||||
|
for (final Mana mana : mp.getLastManaProduced()) {
|
||||||
if (tryPayCostWithMana(saPaidFor, manaCost, mana, false)) {
|
if (tryPayCostWithMana(saPaidFor, manaCost, mana, false)) {
|
||||||
saPaidFor.getPayingMana().add(0, mana);
|
saPaidFor.getPayingMana().add(0, mana);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean tryPayCostWithColor(byte colorCode, SpellAbility saPaidFor, ManaCostBeingPaid manaCost) {
|
public boolean tryPayCostWithColor(byte colorCode, SpellAbility saPaidFor, ManaCostBeingPaid manaCost) {
|
||||||
Mana manaFound = null;
|
Mana manaFound = null;
|
||||||
@@ -216,8 +220,12 @@ public class ManaPool extends ManaConversionMatrix implements Iterable<Mana> {
|
|||||||
if (!manaCost.isNeeded(mana, this)) {
|
if (!manaCost.isNeeded(mana, this)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// only pay mana into manaCost when the Mana could be removed from the Mana pool
|
||||||
|
// if the mana wasn't in the mana pool then something is wrong
|
||||||
|
if (!removeMana(mana)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
manaCost.payMana(mana, this);
|
manaCost.payMana(mana, this);
|
||||||
removeMana(mana);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3528,4 +3528,11 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
public void resetCycledThisTurn() {
|
public void resetCycledThisTurn() {
|
||||||
cycledThisTurn = 0;
|
cycledThisTurn = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasUrzaLands() {
|
||||||
|
final CardCollectionView landsControlled = getCardsIn(ZoneType.Battlefield);
|
||||||
|
return Iterables.any(landsControlled, Predicates.and(CardPredicates.isType("Urza's"), CardPredicates.isType("Mine")))
|
||||||
|
&& Iterables.any(landsControlled, Predicates.and(CardPredicates.isType("Urza's"), CardPredicates.isType("Power-Plant")))
|
||||||
|
&& Iterables.any(landsControlled, Predicates.and(CardPredicates.isType("Urza's"), CardPredicates.isType("Tower")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ public class ReplaceProduceMana extends ReplacementEffect {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||||
//Check for tapping
|
|
||||||
if (!hasParam("NoTapCheck")) {
|
if (hasParam("ValidAbility")) {
|
||||||
final SpellAbility manaAbility = (SpellAbility) runParams.get(AbilityKey.AbilityMana);
|
final SpellAbility manaAbility = (SpellAbility) runParams.get(AbilityKey.AbilityMana);
|
||||||
if (manaAbility == null || !manaAbility.getRootAbility().getPayCosts().hasTapCost()) {
|
if (!matchesValid(manaAbility, getParam("ValidAbility").split(","), getHostCard())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,15 +43,23 @@ public class ReplaceProduceMana extends ReplacementEffect {
|
|||||||
String full = getParam("ManaAmount");
|
String full = getParam("ManaAmount");
|
||||||
String operator = full.substring(0, 2);
|
String operator = full.substring(0, 2);
|
||||||
String operand = full.substring(2);
|
String operand = full.substring(2);
|
||||||
|
|
||||||
int intoperand = AbilityUtils.calculateAmount(getHostCard(), operand, this);
|
int intoperand = AbilityUtils.calculateAmount(getHostCard(), operand, this);
|
||||||
|
|
||||||
int manaAmount = StringUtils.countMatches((String) runParams.get(AbilityKey.Mana), " ") + 1;
|
int manaAmount = StringUtils.countMatches((String) runParams.get(AbilityKey.Mana), " ") + 1;
|
||||||
if (!Expressions.compare(manaAmount, operator, intoperand)) {
|
if (!Expressions.compare(manaAmount, operator, intoperand)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasParam("ValidPlayer")) {
|
||||||
|
if (!matchesValid(runParams.get(AbilityKey.Player), getParam("ValidPlayer").split(","), getHostCard())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (hasParam("ValidCard")) {
|
if (hasParam("ValidCard")) {
|
||||||
if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidCard").split(","), this.getHostCard())) {
|
if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidCard").split(","), getHostCard())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,4 +68,7 @@ public class ReplaceProduceMana extends ReplacementEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
|
||||||
|
sa.setReplacingObject(AbilityKey.Mana, runParams.get(AbilityKey.Mana));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package forge.game.replacement;
|
|||||||
|
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.TriggerReplacementBase;
|
import forge.game.TriggerReplacementBase;
|
||||||
|
import forge.game.ability.AbilityFactory;
|
||||||
import forge.game.ability.AbilityKey;
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
@@ -271,4 +272,13 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
|
|||||||
void setMode(ReplacementType mode) {
|
void setMode(ReplacementType mode) {
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SpellAbility ensureAbility() {
|
||||||
|
SpellAbility sa = getOverridingAbility();
|
||||||
|
if (sa == null && hasParam("ReplaceWith")) {
|
||||||
|
sa = AbilityFactory.getAbility(getHostCard(), getParam("ReplaceWith"));
|
||||||
|
setOverridingAbility(sa);
|
||||||
|
}
|
||||||
|
return sa;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
*/
|
*/
|
||||||
package forge.game.replacement;
|
package forge.game.replacement;
|
||||||
|
|
||||||
import forge.card.MagicColor;
|
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.GameLogEntryType;
|
import forge.game.GameLogEntryType;
|
||||||
import forge.game.ability.AbilityFactory;
|
import forge.game.ability.AbilityFactory;
|
||||||
@@ -259,12 +258,17 @@ public class ReplacementHandler {
|
|||||||
chosenRE.setHasRun(false);
|
chosenRE.setHasRun(false);
|
||||||
hasRun.remove(chosenRE);
|
hasRun.remove(chosenRE);
|
||||||
chosenRE.setOtherChoices(null);
|
chosenRE.setOtherChoices(null);
|
||||||
|
|
||||||
|
// Updated Replacements need to be logged elsewhere because its otherwise in the wrong order
|
||||||
|
if (res != ReplacementResult.Updated) {
|
||||||
String message = chosenRE.getDescription();
|
String message = chosenRE.getDescription();
|
||||||
if ( !StringUtils.isEmpty(message))
|
if ( !StringUtils.isEmpty(message))
|
||||||
if (chosenRE.getHostCard() != null) {
|
if (chosenRE.getHostCard() != null) {
|
||||||
message = TextUtil.fastReplace(message, "CARDNAME", chosenRE.getHostCard().getName());
|
message = TextUtil.fastReplace(message, "CARDNAME", chosenRE.getHostCard().getName());
|
||||||
}
|
}
|
||||||
game.getGameLog().add(GameLogEntryType.EFFECT_REPLACED, message);
|
game.getGameLog().add(GameLogEntryType.EFFECT_REPLACED, message);
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,26 +348,12 @@ public class ReplacementHandler {
|
|||||||
|
|
||||||
Player player = host.getController();
|
Player player = host.getController();
|
||||||
|
|
||||||
if (mapParams.containsKey("ManaReplacement")) {
|
|
||||||
final SpellAbility manaAb = (SpellAbility) runParams.get(AbilityKey.AbilityMana);
|
|
||||||
final Player player1 = (Player) runParams.get(AbilityKey.Player);
|
|
||||||
final String rep = (String) runParams.get(AbilityKey.Mana);
|
|
||||||
// Replaced mana type
|
|
||||||
final Card repHost = host;
|
|
||||||
String repType = repHost.getSVar(mapParams.get("ManaReplacement"));
|
|
||||||
if (repType.contains("Chosen") && repHost.hasChosenColor()) {
|
|
||||||
repType = TextUtil.fastReplace(repType, "Chosen", MagicColor.toShortString(repHost.getChosenColor()));
|
|
||||||
}
|
|
||||||
manaAb.getManaPart().setManaReplaceType(repType);
|
|
||||||
manaAb.getManaPart().produceMana(rep, player1, manaAb);
|
|
||||||
} else {
|
|
||||||
player.getController().playSpellAbilityNoStack(effectSA, true);
|
player.getController().playSpellAbilityNoStack(effectSA, true);
|
||||||
// if the spellability is a replace effect then its some new logic
|
// if the spellability is a replace effect then its some new logic
|
||||||
// if ReplacementResult is set in run params use that instead
|
// if ReplacementResult is set in run params use that instead
|
||||||
if (runParams.containsKey(AbilityKey.ReplacementResult)) {
|
if (runParams.containsKey(AbilityKey.ReplacementResult)) {
|
||||||
return (ReplacementResult) runParams.get(AbilityKey.ReplacementResult);
|
return (ReplacementResult) runParams.get(AbilityKey.ReplacementResult);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return ReplacementResult.Replaced;
|
return ReplacementResult.Replaced;
|
||||||
}
|
}
|
||||||
@@ -407,6 +397,10 @@ public class ReplacementHandler {
|
|||||||
ret.setActiveZone(EnumSet.copyOf(ZoneType.listValueOf(activeZones)));
|
ret.setActiveZone(EnumSet.copyOf(ZoneType.listValueOf(activeZones)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mapParams.containsKey("ReplaceWith")) {
|
||||||
|
ret.setOverridingAbility(AbilityFactory.getAbility(host, mapParams.get("ReplaceWith"), ret));
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,15 +18,18 @@
|
|||||||
package forge.game.spellability;
|
package forge.game.spellability;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
|
|
||||||
import forge.card.ColorSet;
|
import forge.card.ColorSet;
|
||||||
import forge.card.MagicColor;
|
import forge.card.MagicColor;
|
||||||
import forge.card.mana.ManaAtom;
|
import forge.card.mana.ManaAtom;
|
||||||
import forge.card.mana.ManaCostShard;
|
import forge.card.mana.ManaCostShard;
|
||||||
|
import forge.game.Game;
|
||||||
import forge.game.GameActionUtil;
|
import forge.game.GameActionUtil;
|
||||||
import forge.game.ability.AbilityKey;
|
import forge.game.ability.AbilityKey;
|
||||||
|
import forge.game.ability.ApiType;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
|
import forge.game.card.CardUtil;
|
||||||
import forge.game.mana.Mana;
|
import forge.game.mana.Mana;
|
||||||
import forge.game.mana.ManaPool;
|
import forge.game.mana.ManaPool;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
@@ -39,8 +42,6 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@@ -57,6 +58,7 @@ public class AbilityManaPart implements java.io.Serializable {
|
|||||||
private final String origProduced;
|
private final String origProduced;
|
||||||
private String lastExpressChoice = "";
|
private String lastExpressChoice = "";
|
||||||
private final String manaRestrictions;
|
private final String manaRestrictions;
|
||||||
|
private String extraManaRestrictions = "";
|
||||||
private final String cannotCounterSpell;
|
private final String cannotCounterSpell;
|
||||||
private final String addsKeywords;
|
private final String addsKeywords;
|
||||||
private final String addsKeywordsType;
|
private final String addsKeywordsType;
|
||||||
@@ -64,7 +66,6 @@ public class AbilityManaPart implements java.io.Serializable {
|
|||||||
private final String addsCounters;
|
private final String addsCounters;
|
||||||
private final String triggersWhenSpent;
|
private final String triggersWhenSpent;
|
||||||
private final boolean persistentMana;
|
private final boolean persistentMana;
|
||||||
private String manaReplaceType;
|
|
||||||
|
|
||||||
private transient List<Mana> lastManaProduced = Lists.newArrayList();
|
private transient List<Mana> lastManaProduced = Lists.newArrayList();
|
||||||
|
|
||||||
@@ -94,7 +95,6 @@ public class AbilityManaPart implements java.io.Serializable {
|
|||||||
this.addsCounters = params.get("AddsCounters");
|
this.addsCounters = params.get("AddsCounters");
|
||||||
this.triggersWhenSpent = params.get("TriggersWhenSpent");
|
this.triggersWhenSpent = params.get("TriggersWhenSpent");
|
||||||
this.persistentMana = (null != params.get("PersistentMana")) && "True".equalsIgnoreCase(params.get("PersistentMana"));
|
this.persistentMana = (null != params.get("PersistentMana")) && "True".equalsIgnoreCase(params.get("PersistentMana"));
|
||||||
this.manaReplaceType = params.containsKey("ManaReplaceType") ? params.get("ManaReplaceType") : "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -121,14 +121,26 @@ public class AbilityManaPart implements java.io.Serializable {
|
|||||||
public final void produceMana(final String produced, final Player player, SpellAbility sa) {
|
public final void produceMana(final String produced, final Player player, SpellAbility sa) {
|
||||||
final Card source = this.getSourceCard();
|
final Card source = this.getSourceCard();
|
||||||
final ManaPool manaPool = player.getManaPool();
|
final ManaPool manaPool = player.getManaPool();
|
||||||
String afterReplace = applyManaReplacement(sa, produced);
|
String afterReplace = produced;
|
||||||
|
|
||||||
|
SpellAbility root = sa == null ? null : sa.getRootAbility();
|
||||||
|
|
||||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(source);
|
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(source);
|
||||||
repParams.put(AbilityKey.Mana, produced);
|
repParams.put(AbilityKey.Mana, afterReplace);
|
||||||
repParams.put(AbilityKey.Player, player);
|
repParams.put(AbilityKey.Player, player);
|
||||||
repParams.put(AbilityKey.AbilityMana, sa);
|
repParams.put(AbilityKey.AbilityMana, root);
|
||||||
if (player.getGame().getReplacementHandler().run(ReplacementType.ProduceMana, repParams) != ReplacementResult.NotReplaced) {
|
repParams.put(AbilityKey.Activator, root == null ? null : root.getActivatingPlayer());
|
||||||
|
|
||||||
|
switch (player.getGame().getReplacementHandler().run(ReplacementType.ProduceMana, repParams)) {
|
||||||
|
case NotReplaced:
|
||||||
|
break;
|
||||||
|
case Updated:
|
||||||
|
afterReplace = (String) repParams.get(AbilityKey.Mana);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//clear lastProduced
|
//clear lastProduced
|
||||||
this.lastManaProduced.clear();
|
this.lastManaProduced.clear();
|
||||||
|
|
||||||
@@ -154,14 +166,14 @@ public class AbilityManaPart implements java.io.Serializable {
|
|||||||
// Run triggers
|
// Run triggers
|
||||||
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(source);
|
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(source);
|
||||||
runParams.put(AbilityKey.Player, player);
|
runParams.put(AbilityKey.Player, player);
|
||||||
runParams.put(AbilityKey.AbilityMana, sa);
|
|
||||||
runParams.put(AbilityKey.Produced, afterReplace);
|
runParams.put(AbilityKey.Produced, afterReplace);
|
||||||
|
runParams.put(AbilityKey.AbilityMana, root);
|
||||||
|
runParams.put(AbilityKey.Activator, root == null ? null : root.getActivatingPlayer());
|
||||||
|
|
||||||
player.getGame().getTriggerHandler().runTrigger(TriggerType.TapsForMana, runParams, false);
|
player.getGame().getTriggerHandler().runTrigger(TriggerType.TapsForMana, runParams, false);
|
||||||
if (source.isLand()) {
|
if (source.isLand() && sa.getPayCosts() != null && sa.getPayCosts().hasTapCost() ) {
|
||||||
player.setTappedLandForManaThisTurn(true);
|
player.setTappedLandForManaThisTurn(true);
|
||||||
}
|
}
|
||||||
// Clear Mana replacement
|
|
||||||
this.manaReplaceType = "";
|
|
||||||
} // end produceMana(String)
|
} // end produceMana(String)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -256,7 +268,15 @@ public class AbilityManaPart implements java.io.Serializable {
|
|||||||
* @return a {@link java.lang.String} object.
|
* @return a {@link java.lang.String} object.
|
||||||
*/
|
*/
|
||||||
public String getManaRestrictions() {
|
public String getManaRestrictions() {
|
||||||
return this.manaRestrictions;
|
return manaRestrictions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExtraManaRestriction(String str) {
|
||||||
|
this.extraManaRestrictions = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean meetsManaRestrictions(final SpellAbility sa) {
|
||||||
|
return meetsManaRestrictions(sa, this.manaRestrictions) && meetsManaRestrictions(sa, this.extraManaRestrictions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -268,14 +288,14 @@ public class AbilityManaPart implements java.io.Serializable {
|
|||||||
* a {@link forge.game.spellability.SpellAbility} object.
|
* a {@link forge.game.spellability.SpellAbility} object.
|
||||||
* @return a boolean.
|
* @return a boolean.
|
||||||
*/
|
*/
|
||||||
public boolean meetsManaRestrictions(final SpellAbility sa) {
|
public boolean meetsManaRestrictions(final SpellAbility sa, String restrictions) {
|
||||||
// No restrictions
|
// No restrictions
|
||||||
if (this.manaRestrictions.isEmpty()) {
|
if (restrictions.isEmpty()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop over restrictions
|
// Loop over restrictions
|
||||||
for (String restriction : this.manaRestrictions.split(",")) {
|
for (String restriction : restrictions.split(",")) {
|
||||||
if (restriction.equals("nonSpell")) {
|
if (restriction.equals("nonSpell")) {
|
||||||
return !sa.isSpell();
|
return !sa.isSpell();
|
||||||
}
|
}
|
||||||
@@ -465,10 +485,6 @@ public class AbilityManaPart implements java.io.Serializable {
|
|||||||
return this.getOrigProduced().contains("Special");
|
return this.getOrigProduced().contains("Special");
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean canProduce(final String s) {
|
|
||||||
return canProduce(s, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* canProduce.
|
* canProduce.
|
||||||
@@ -493,24 +509,9 @@ public class AbilityManaPart implements java.io.Serializable {
|
|||||||
if (isComboMana()) {
|
if (isComboMana()) {
|
||||||
return getComboColors().contains(s);
|
return getComboColors().contains(s);
|
||||||
}
|
}
|
||||||
if (sa != null) {
|
|
||||||
return applyManaReplacement(sa, origProduced).contains(s);
|
|
||||||
}
|
|
||||||
return origProduced.contains(s);
|
return origProduced.contains(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* isBasic.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a boolean.
|
|
||||||
*/
|
|
||||||
public final boolean isBasic() {
|
|
||||||
return this.getOrigProduced().length() == 1 || this.getOrigProduced().contains("Any")
|
|
||||||
|| this.getOrigProduced().contains("Chosen");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public final boolean equals(final Object o) {
|
public final boolean equals(final Object o) {
|
||||||
@@ -586,81 +587,59 @@ public class AbilityManaPart implements java.io.Serializable {
|
|||||||
return this.persistentMana;
|
return this.persistentMana;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
boolean abilityProducesManaColor(final SpellAbility am, final byte neededColor) {
|
||||||
* @return the manaReplaceType
|
if (0 != (neededColor & ManaAtom.GENERIC)) {
|
||||||
*/
|
return true;
|
||||||
public String getManaReplaceType() {
|
|
||||||
return manaReplaceType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
if (isAnyMana()) {
|
||||||
* setManaReplaceType.
|
return true;
|
||||||
*/
|
|
||||||
public void setManaReplaceType(final String type) {
|
|
||||||
this.manaReplaceType = type;
|
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* <p>
|
// check for produce mana replacement effects - they mess this up, so just use the mana ability
|
||||||
* applyManaReplacement.
|
final Card source = am.getHostCard();
|
||||||
* </p>
|
final Player activator = am.getActivatingPlayer();
|
||||||
* @return a String
|
final Game g = source.getGame();
|
||||||
*/
|
final Map<AbilityKey, Object> repParams = AbilityKey.newMap();
|
||||||
public static String applyManaReplacement(final SpellAbility sa, final String original) {
|
repParams.put(AbilityKey.Mana, getOrigProduced());
|
||||||
final Map<String, String> repMap = Maps.newHashMap();
|
repParams.put(AbilityKey.Affected, source);
|
||||||
final Player act = sa != null ? sa.getActivatingPlayer() : null;
|
repParams.put(AbilityKey.Player, activator);
|
||||||
final String manaReplace = sa != null ? sa.getManaPart().getManaReplaceType(): "";
|
repParams.put(AbilityKey.AbilityMana, am.getRootAbility());
|
||||||
if (manaReplace.isEmpty()) {
|
|
||||||
if (act != null && act.getLandsPlayedThisTurn() > 0 && sa.hasParam("ReplaceIfLandPlayed")) {
|
for (final Player p : g.getPlayers()) {
|
||||||
return sa.getParam("ReplaceIfLandPlayed");
|
for (final Card crd : p.getAllCards()) {
|
||||||
}
|
for (final ReplacementEffect replacementEffect : crd.getReplacementEffects()) {
|
||||||
return original;
|
if (replacementEffect.requirementsCheck(g)
|
||||||
}
|
&& replacementEffect.getMode() == ReplacementType.ProduceMana
|
||||||
if (manaReplace.startsWith("Any")) {
|
&& replacementEffect.canReplace(repParams)
|
||||||
// Replace any type and amount
|
&& replacementEffect.zonesCheck(g.getZoneOf(crd))) {
|
||||||
String replaced = manaReplace.split("->")[1];
|
return true;
|
||||||
if (replaced.equals("Any")) {
|
|
||||||
byte rs = MagicColor.GREEN;
|
|
||||||
if (act != null) {
|
|
||||||
rs = act.getController().chooseColor("Choose a color", sa, ColorSet.ALL_COLORS);
|
|
||||||
}
|
|
||||||
replaced = MagicColor.toShortString(rs);
|
|
||||||
}
|
|
||||||
return replaced;
|
|
||||||
}
|
|
||||||
final Pattern splitter = Pattern.compile("->");
|
|
||||||
// Replace any type
|
|
||||||
for (String part : manaReplace.split(" & ")) {
|
|
||||||
final String[] v = splitter.split(part, 2);
|
|
||||||
// TODO Colorless mana replacement is probably different now?
|
|
||||||
if (v[0].equals("Colorless")) {
|
|
||||||
repMap.put("[0-9][0-9]?", v.length > 1 ? v[1].trim() : "");
|
|
||||||
} else {
|
|
||||||
repMap.put(v[0], v.length > 1 ? v[1].trim() : "");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Handle different replacement simultaneously
|
|
||||||
Pattern pattern = Pattern.compile(StringUtils.join(repMap.keySet().iterator(), "|"));
|
|
||||||
Matcher m = pattern.matcher(original);
|
|
||||||
StringBuffer sb = new StringBuffer();
|
|
||||||
while(m.find()) {
|
|
||||||
if (m.group().matches("[0-9][0-9]?")) {
|
|
||||||
final String rep = StringUtils.repeat(repMap.get("[0-9][0-9]?") + " ",
|
|
||||||
Integer.parseInt(m.group())).trim();
|
|
||||||
m.appendReplacement(sb, rep);
|
|
||||||
} else {
|
|
||||||
m.appendReplacement(sb, repMap.get(m.group()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m.appendTail(sb);
|
|
||||||
String replaced = sb.toString();
|
if (am.getApi() == ApiType.ManaReflected) {
|
||||||
while (replaced.contains("Any")) {
|
final Iterable<String> reflectableColors = CardUtil.getReflectableManaColors(am);
|
||||||
byte rs = MagicColor.GREEN;
|
for (final String color : reflectableColors) {
|
||||||
if (act != null) {
|
if (0 != (neededColor & ManaAtom.fromName(color))) {
|
||||||
rs = act.getController().chooseColor("Choose a color", sa, ColorSet.ALL_COLORS);
|
return true;
|
||||||
}
|
}
|
||||||
replaced = replaced.replaceFirst("Any", MagicColor.toShortString(rs));
|
|
||||||
}
|
}
|
||||||
return replaced;
|
}
|
||||||
|
else {
|
||||||
|
// treat special mana if it always can be paid
|
||||||
|
if (isSpecialMana()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String colorsProduced = isComboMana() ? getComboColors() : mana();
|
||||||
|
for (final String color : colorsProduced.split(" ")) {
|
||||||
|
if (0 != (neededColor & ManaAtom.fromName(color))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end class AbilityMana
|
} // end class AbilityMana
|
||||||
|
|||||||
@@ -20,10 +20,6 @@ package forge.game.spellability;
|
|||||||
import forge.game.ability.AbilityFactory;
|
import forge.game.ability.AbilityFactory;
|
||||||
import forge.game.ability.ApiType;
|
import forge.game.ability.ApiType;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.ability.effects.ChangeZoneAllEffect;
|
|
||||||
import forge.game.ability.effects.ChangeZoneEffect;
|
|
||||||
import forge.game.ability.effects.ManaEffect;
|
|
||||||
import forge.game.ability.effects.ManaReflectedEffect;
|
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.cost.Cost;
|
import forge.game.cost.Cost;
|
||||||
|
|
||||||
@@ -92,11 +88,11 @@ public final class AbilitySub extends SpellAbility implements java.io.Serializab
|
|||||||
|
|
||||||
effect = api.getSpellEffect();
|
effect = api.getSpellEffect();
|
||||||
|
|
||||||
if (effect instanceof ManaEffect || effect instanceof ManaReflectedEffect) {
|
if (api.equals(ApiType.Mana) || api.equals(ApiType.ManaReflected)) {
|
||||||
this.setManaPart(new AbilityManaPart(ca, mapParams));
|
this.setManaPart(new AbilityManaPart(ca, mapParams));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effect instanceof ChangeZoneEffect || effect instanceof ChangeZoneAllEffect) {
|
if (api.equals(ApiType.ChangeZone) || api.equals(ApiType.ChangeZoneAll)) {
|
||||||
AbilityFactory.adjustChangeZoneTarget(mapParams, this);
|
AbilityFactory.adjustChangeZoneTarget(mapParams, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -237,19 +237,101 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
view.updateDescription(this); //description can change if host card does
|
view.updateDescription(this); //description can change if host card does
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean canThisProduce(final String s) {
|
||||||
|
AbilityManaPart mp = getManaPart();
|
||||||
|
if (mp != null && metConditions() && mp.canProduce(s, this)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canProduce(final String s) {
|
||||||
|
if (canThisProduce(s)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.subAbility != null ? this.subAbility.canProduce(s) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isManaAbilityFor(SpellAbility saPaidFor, byte colorNeeded) {
|
||||||
|
// is root ability
|
||||||
|
if (this.getParent() == null) {
|
||||||
|
if (!canPlay()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (isAbility() && getRestrictions().isInstantSpeed()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AbilityManaPart mp = getManaPart();
|
||||||
|
if (mp != null && metConditions() && mp.meetsManaRestrictions(saPaidFor) && mp.abilityProducesManaColor(this, colorNeeded)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return this.subAbility != null ? this.subAbility.isManaAbilityFor(saPaidFor, colorNeeded) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isManaCannotCounter(SpellAbility saPaidFor) {
|
||||||
|
AbilityManaPart mp = getManaPart();
|
||||||
|
if (mp != null && metConditions() && mp.meetsManaRestrictions(saPaidFor) && mp.cannotCounterPaidWith(saPaidFor)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return this.subAbility != null ? this.subAbility.isManaCannotCounter(saPaidFor) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int amountOfManaGenerated(boolean multiply) {
|
||||||
|
int result = 0;
|
||||||
|
AbilityManaPart mp = getManaPart();
|
||||||
|
if (mp != null && metConditions()) {
|
||||||
|
int amount = hasParam("Amount") ? AbilityUtils.calculateAmount(getHostCard(), getParam("Amount"), this) : 1;
|
||||||
|
|
||||||
|
if (!multiply || mp.isAnyMana() || mp.isComboMana() || mp.isSpecialMana()) {
|
||||||
|
result += amount;
|
||||||
|
} else {
|
||||||
|
// For cards that produce like {C}{R} vs cards that produce {R}{R}.
|
||||||
|
result += mp.mana().split(" ").length * amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int totalAmountOfManaGenerated(SpellAbility saPaidFor, boolean multiply) {
|
||||||
|
int result = 0;
|
||||||
|
AbilityManaPart mp = getManaPart();
|
||||||
|
if (mp != null && metConditions() && mp.meetsManaRestrictions(saPaidFor)) {
|
||||||
|
result += amountOfManaGenerated(multiply);
|
||||||
|
}
|
||||||
|
result += subAbility != null ? subAbility.totalAmountOfManaGenerated(saPaidFor, multiply) : 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setManaExpressChoice(ColorSet cs) {
|
||||||
|
AbilityManaPart mp = getManaPart();
|
||||||
|
if (mp != null) {
|
||||||
|
mp.setExpressChoice(cs);
|
||||||
|
}
|
||||||
|
if (subAbility != null) {
|
||||||
|
subAbility.setManaExpressChoice(cs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final AbilityManaPart getManaPart() {
|
public final AbilityManaPart getManaPart() {
|
||||||
return manaPart;
|
return manaPart;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final AbilityManaPart getManaPartRecursive() {
|
public final List<AbilityManaPart> getAllManaParts() {
|
||||||
SpellAbility tail = this;
|
AbilityManaPart mp = getManaPart();
|
||||||
while (tail != null) {
|
if (mp == null && subAbility == null) {
|
||||||
if (tail.manaPart != null) {
|
return ImmutableList.of();
|
||||||
return tail.manaPart;
|
|
||||||
}
|
}
|
||||||
tail = tail.getSubAbility();
|
List<AbilityManaPart> result = Lists.newArrayList();
|
||||||
|
if (mp != null) {
|
||||||
|
result.add(mp);
|
||||||
}
|
}
|
||||||
return null;
|
if (subAbility != null) {
|
||||||
|
result.addAll(subAbility.getAllManaParts());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean isManaAbility() {
|
public final boolean isManaAbility() {
|
||||||
@@ -266,7 +348,14 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return getManaPartRecursive() != null;
|
SpellAbility tail = this;
|
||||||
|
while (tail != null) {
|
||||||
|
if (tail.manaPart != null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
tail = tail.getSubAbility();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void setManaPart(AbilityManaPart manaPart0) {
|
protected final void setManaPart(AbilityManaPart manaPart0) {
|
||||||
@@ -464,6 +553,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
conditions = condition;
|
conditions = condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean metConditions() {
|
||||||
|
return getConditions() != null && getConditions().areMet(this);
|
||||||
|
}
|
||||||
|
|
||||||
public List<Mana> getPayingMana() {
|
public List<Mana> getPayingMana() {
|
||||||
return payingMana;
|
return payingMana;
|
||||||
}
|
}
|
||||||
@@ -1880,9 +1973,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
public boolean tracksManaSpent() {
|
public boolean tracksManaSpent() {
|
||||||
if (hostCard == null || hostCard.getRules() == null) { return false; }
|
if (hostCard == null || hostCard.getRules() == null) { return false; }
|
||||||
|
|
||||||
if (hostCard.hasKeyword(Keyword.SUNBURST)) {
|
if (isSpell() && hostCard.hasConverge()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String text = hostCard.getRules().getOracleText();
|
String text = hostCard.getRules().getOracleText();
|
||||||
if (isSpell() && text.contains("was spent to cast")) {
|
if (isSpell() && text.contains("was spent to cast")) {
|
||||||
return true;
|
return true;
|
||||||
@@ -2019,7 +2113,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
String mana = manaPart.mana();
|
String mana = manaPart.mana();
|
||||||
if (!mana.equals("Any")) {
|
if (!mana.equals("Any")) {
|
||||||
score += mana.length();
|
score += mana.length();
|
||||||
if (!manaPart.canProduce("C")) {
|
if (!canProduce("C")) {
|
||||||
// Producing colorless should produce a slightly lower score
|
// Producing colorless should produce a slightly lower score
|
||||||
score += 1;
|
score += 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,13 +169,7 @@ public class TriggerHandler {
|
|||||||
if (wt.getTriggers() != null)
|
if (wt.getTriggers() != null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
List<Trigger> trigger = Lists.newArrayList();
|
wt.setTriggers(getActiveTrigger(wt.getMode(), wt.getParams()));
|
||||||
for (final Trigger t : activeTriggers) {
|
|
||||||
if (canRunTrigger(t,wt.getMode(),wt.getParams())) {
|
|
||||||
trigger.add(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wt.setTriggers(trigger);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -678,4 +672,14 @@ public class TriggerHandler {
|
|||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Trigger> getActiveTrigger(final TriggerType mode, final Map<AbilityKey, Object> runParams) {
|
||||||
|
List<Trigger> trigger = Lists.newArrayList();
|
||||||
|
for (final Trigger t : activeTriggers) {
|
||||||
|
if (canRunTrigger(t, mode, runParams)) {
|
||||||
|
trigger.add(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return trigger;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ package forge.game.trigger;
|
|||||||
import forge.card.MagicColor;
|
import forge.card.MagicColor;
|
||||||
import forge.game.ability.AbilityKey;
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.player.Player;
|
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.util.Localizer;
|
import forge.util.Localizer;
|
||||||
|
|
||||||
@@ -68,25 +67,19 @@ public class TriggerTapsForMana extends Trigger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (hasParam("ValidCard")) {
|
if (hasParam("ValidCard")) {
|
||||||
final Card tapper = (Card) runParams.get(AbilityKey.Card);
|
if (!matchesValid(runParams.get(AbilityKey.Card), getParam("ValidCard").split(","), getHostCard())) {
|
||||||
if (!tapper.isValid(getParam("ValidCard").split(","), this.getHostCard().getController(),
|
|
||||||
this.getHostCard(), null)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasParam("Player")) {
|
if (hasParam("Player")) {
|
||||||
final Player player = (Player) runParams.get(AbilityKey.Player);
|
if (!matchesValid(runParams.get(AbilityKey.Player), getParam("Player").split(","), getHostCard())) {
|
||||||
if (!player.isValid(getParam("Player").split(","), this.getHostCard().getController(), this.getHostCard(), null)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasParam("Activator")) {
|
if (hasParam("Activator")) {
|
||||||
final SpellAbility sa = (SpellAbility) runParams.get(AbilityKey.AbilityMana);
|
if (!matchesValid(runParams.get(AbilityKey.Activator), getParam("Activator").split(","), getHostCard())) {
|
||||||
if (sa == null) return false;
|
|
||||||
final Player activator = sa.getActivatingPlayer();
|
|
||||||
if (!activator.isValid(getParam("Activator").split(","), this.getHostCard().getController(), this.getHostCard(), null)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,7 +106,7 @@ public class TriggerTapsForMana extends Trigger {
|
|||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public final void setTriggeringObjects(final SpellAbility sa, Map<AbilityKey, Object> runParams) {
|
public final void setTriggeringObjects(final SpellAbility sa, Map<AbilityKey, Object> runParams) {
|
||||||
sa.setTriggeringObjectsFrom(runParams, AbilityKey.Card, AbilityKey.Player, AbilityKey.Produced);
|
sa.setTriggeringObjectsFrom(runParams, AbilityKey.Card, AbilityKey.Player, AbilityKey.Produced, AbilityKey.Activator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -4,6 +4,5 @@ Types:Scheme
|
|||||||
T:Mode$ SetInMotion | ValidCard$ Card.Self | Execute$ DarkEffect | TriggerZones$ Command | TriggerDescription$ When you set this scheme in motion, until your next turn, whenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
T:Mode$ SetInMotion | ValidCard$ Card.Self | Execute$ DarkEffect | TriggerZones$ Command | TriggerDescription$ When you set this scheme in motion, until your next turn, whenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
||||||
SVar:DarkEffect:DB$ Effect | Name$ Dark Power Scheme | Duration$ UntilYourNextTurn | Triggers$ DarkPower | SVars$ DarkMana
|
SVar:DarkEffect:DB$ Effect | Name$ Dark Power Scheme | Duration$ UntilYourNextTurn | Triggers$ DarkPower | SVars$ DarkMana
|
||||||
SVar:DarkPower:Mode$ TapsForMana | ValidCard$ Land | Execute$ DarkMana | TriggerZones$ Command | Static$ True | TriggerDescription$ Whenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
SVar:DarkPower:Mode$ TapsForMana | ValidCard$ Land | Execute$ DarkMana | TriggerZones$ Command | Static$ True | TriggerDescription$ Whenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
||||||
SVar:DarkMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
SVar:DarkMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ TriggeredActivator
|
||||||
SVar:Picture:https://downloads.cardforge.org/images/cards/ARC/A Display of My Dark Power.full.jpg
|
|
||||||
Oracle:When you set this scheme in motion, until your next turn, whenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
Oracle:When you set this scheme in motion, until your next turn, whenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ Types:Artifact
|
|||||||
K:ETBReplacement:Other:ChooseColor
|
K:ETBReplacement:Other:ChooseColor
|
||||||
SVar:ChooseColor:DB$ ChooseColor | Defined$ You | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a color.
|
SVar:ChooseColor:DB$ ChooseColor | Defined$ You | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a color.
|
||||||
S:Mode$ Continuous | Affected$ Creature.ChosenColor+YouCtrl | AddPower$ 1 | AddToughness$ 1 | Description$ Creatures you control of the chosen color get +1/+1.
|
S:Mode$ Continuous | Affected$ Creature.ChosenColor+YouCtrl | AddPower$ 1 | AddToughness$ 1 | Description$ Creatures you control of the chosen color get +1/+1.
|
||||||
T:Mode$ TapsForMana | ValidCard$ Land | Produced$ ChosenColor | NoTapCheck$ True | Player$ You | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever a land's ability adds one or more mana of the chosen color, add one additional mana of that color.
|
T:Mode$ TapsForMana | ValidCard$ Land | Produced$ ChosenColor | NoTapCheck$ True | Player$ You | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever a land’s ability causes you to add one or more mana of the chosen color, add one additional mana of that color.
|
||||||
SVar:TrigMana:DB$ Mana | Produced$ Chosen | Amount$ 1 | Defined$ TriggeredPlayer
|
SVar:TrigMana:DB$ Mana | Produced$ Chosen | Amount$ 1 | Defined$ You
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/caged_sun.jpg
|
Oracle:As Caged Sun enters the battlefield, choose a color.\nCreatures you control of the chosen color get +1/+1.\nWhenever a land’s ability causes you to add one or more mana of the chosen color, add one additional mana of that color.
|
||||||
Oracle:As Caged Sun enters the battlefield, choose a color.\nCreatures you control of the chosen color get +1/+1.\nWhenever a land's ability adds one or more mana of the chosen color, add one additional mana of that color.
|
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ SVar:DBEffect:DB$ Effect | ReplacementEffects$ RepCurse | SVars$ ProduceColorles
|
|||||||
SVar:TrigRamp:Mode$ TapsForMana | ValidCard$ Mountain | Execute$ TrigMana | Static$ True | TriggerZones$ Command | TriggerDescription$ Whenever a player taps a Mountain for mana, that player adds {R}.
|
SVar:TrigRamp:Mode$ TapsForMana | ValidCard$ Mountain | Execute$ TrigMana | Static$ True | TriggerZones$ Command | TriggerDescription$ Whenever a player taps a Mountain for mana, that player adds {R}.
|
||||||
SVar:TrigMana:DB$ Mana | Produced$ R | Amount$ 1 | Defined$ TriggeredCardController
|
SVar:TrigMana:DB$ Mana | Produced$ R | Amount$ 1 | Defined$ TriggeredCardController
|
||||||
SVar:STPump:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Creature.Red | AddPower$ 1 | AddToughness$ 1
|
SVar:STPump:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Creature.Red | AddPower$ 1 | AddToughness$ 1
|
||||||
SVar:RepCurse:Event$ ProduceMana | ActiveZones$ Command | ValidCard$ Mountain | ManaReplacement$ ProduceColorless | Description$ If a player taps a Mountain for mana, that Mountain produces colorless mana instead of any other type.
|
SVar:RepCurse:Event$ ProduceMana | ActiveZones$ Command | ValidCard$ Mountain | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceColorless | Description$ If a player taps a Mountain for mana, that Mountain produces colorless mana instead of any other type.
|
||||||
SVar:ProduceColorless:R->1 & B->1 & U->1 & G->1 & W->1
|
SVar:ProduceColorless:DB$ ReplaceMana | ReplaceType$ C
|
||||||
SVar:STCurse:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Creature.Red | AddPower$ -1 | AddToughness$ -1
|
SVar:STCurse:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Creature.Red | AddPower$ -1 | AddToughness$ -1
|
||||||
SVar:X:Count$Valid Permanent
|
SVar:X:Count$Valid Permanent
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ Name:Contamination
|
|||||||
ManaCost:2 B
|
ManaCost:2 B
|
||||||
Types:Enchantment
|
Types:Enchantment
|
||||||
K:UpkeepCost:Sac<1/Creature>
|
K:UpkeepCost:Sac<1/Creature>
|
||||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Land | ManaReplacement$ ProduceB | Description$ If a land is tapped for mana, it produces {B} instead of any other type and amount.
|
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Land | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceB | Description$ If a land is tapped for mana, it produces {B} instead of any other type and amount.
|
||||||
SVar:ProduceB:Any->B
|
SVar:ProduceB:DB$ ReplaceMana | ReplaceMana$ B
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
SVar:NonStackingEffect:True
|
SVar:NonStackingEffect:True
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/contamination.jpg
|
|
||||||
Oracle:At the beginning of your upkeep, sacrifice Contamination unless you sacrifice a creature.\nIf a land is tapped for mana, it produces {B} instead of any other type and amount.
|
Oracle:At the beginning of your upkeep, sacrifice Contamination unless you sacrifice a creature.\nIf a land is tapped for mana, it produces {B} instead of any other type and amount.
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ ManaCost:3 B
|
|||||||
Types:Creature Spirit
|
Types:Creature Spirit
|
||||||
PT:2/2
|
PT:2/2
|
||||||
K:Extort
|
K:Extort
|
||||||
T:Mode$ TapsForMana | ValidCard$ Swamp.YouCtrl | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a Swamp for mana, add an additional {B}.
|
T:Mode$ TapsForMana | ValidCard$ Swamp | Activator$ You | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a Swamp for mana, add an additional {B}.
|
||||||
SVar:TrigMana:DB$ Mana | Produced$ B | Amount$ 1
|
SVar:TrigMana:DB$ Mana | Produced$ B | Amount$ 1
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/crypt_ghast.jpg
|
|
||||||
Oracle:Extort (Whenever you cast a spell, you may pay {W/B}. If you do, each opponent loses 1 life and you gain that much life.)\nWhenever you tap a Swamp for mana, add an additional {B}.
|
Oracle:Extort (Whenever you cast a spell, you may pay {W/B}. If you do, each opponent loses 1 life and you gain that much life.)\nWhenever you tap a Swamp for mana, add an additional {B}.
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
Name:Damping Sphere
|
Name:Damping Sphere
|
||||||
ManaCost:2
|
ManaCost:2
|
||||||
Types:Artifact
|
Types:Artifact
|
||||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Land | ManaAmount$ GE2 | ManaReplacement$ ProduceC | Description$ If a land is tapped for two or more mana, it produces {C} instead of any other type and amount.
|
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Land | ValidAbility$ Activated.hasTapCost | ManaAmount$ GE2 | ReplaceWith$ ProduceC | Description$ If a land is tapped for two or more mana, it produces {C} instead of any other type and amount.
|
||||||
SVar:ProduceC:Any->C
|
SVar:ProduceC:DB$ ReplaceMana | ReplaceMana$ C
|
||||||
S:Mode$ RaiseCost | Activator$ Player | Type$ Spell | Amount$ X | AffectedAmount$ True | Description$ Each spell a player casts costs {1} more to cast for each other spell that player has cast this turn.
|
S:Mode$ RaiseCost | Activator$ Player | Type$ Spell | Amount$ X | AffectedAmount$ True | Description$ Each spell a player casts costs {1} more to cast for each other spell that player has cast this turn.
|
||||||
SVar:X:Count$ThisTurnCast_Card.YouCtrl
|
SVar:X:Count$ThisTurnCast_Card.YouCtrl
|
||||||
SVar:NonStackingEffect:True
|
SVar:NonStackingEffect:True
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/damping_sphere.jpg
|
|
||||||
Oracle:If a land is tapped for two or more mana, it produces {C} instead of any other type and amount.\nEach spell a player casts costs {1} more to cast for each other spell that player has cast this turn.
|
Oracle:If a land is tapped for two or more mana, it produces {C} instead of any other type and amount.\nEach spell a player casts costs {1} more to cast for each other spell that player has cast this turn.
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ Name:Deep Water
|
|||||||
ManaCost:U U
|
ManaCost:U U
|
||||||
Types:Enchantment
|
Types:Enchantment
|
||||||
A:AB$ Effect | Cost$ U | ReplacementEffects$ ReplaceU | SVars$ ProduceU | SpellDescription$ Until end of turn, if you tap a land you control for mana, it produces {U} instead of any other type.
|
A:AB$ Effect | Cost$ U | ReplacementEffects$ ReplaceU | SVars$ ProduceU | SpellDescription$ Until end of turn, if you tap a land you control for mana, it produces {U} instead of any other type.
|
||||||
SVar:ReplaceU:Event$ ProduceMana | ActiveZones$ Command | ValidCard$ Land.YouCtrl | ManaReplacement$ ProduceU | Description$ If you tap a land you control for mana, it produces U instead of any other type.
|
SVar:ReplaceU:Event$ ProduceMana | ActiveZones$ Command | ValidPlayer$ You | ValidCard$ Land.YouCtrl | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceU | Description$ If you tap a land you control for mana, it produces U instead of any other type.
|
||||||
SVar:ProduceU:C->U & B->U & R->U & G->U & W->U
|
SVar:ProduceU:DB$ ReplaceMana | ReplaceType$ U
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/deep_water.jpg
|
|
||||||
Oracle:{U}: Until end of turn, if you tap a land you control for mana, it produces {U} instead of any other type.
|
Oracle:{U}: Until end of turn, if you tap a land you control for mana, it produces {U} instead of any other type.
|
||||||
|
|||||||
@@ -3,6 +3,5 @@ ManaCost:3 G G
|
|||||||
Types:Enchantment
|
Types:Enchantment
|
||||||
K:Flash
|
K:Flash
|
||||||
T:Mode$ TapsForMana | ValidCard$ Land | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
T:Mode$ TapsForMana | ValidCard$ Land | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
||||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ TriggeredActivator
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/dictate_of_karametra.jpg
|
|
||||||
Oracle:Flash\nWhenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
Oracle:Flash\nWhenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
Name:Doubling Cube
|
Name:Doubling Cube
|
||||||
ManaCost:2
|
ManaCost:2
|
||||||
Types:Artifact
|
Types:Artifact
|
||||||
A:AB$ Mana | Cost$ 3 T | DoubleManaInPool$ True | ProduceNoOtherMana$ True | SpellDescription$ Double the amount of each type of unspent mana you have.
|
A:AB$ Mana | Cost$ 3 T | Produced$ Special DoubleManaInPool | SpellDescription$ Double the amount of each type of unspent mana you have.
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/doubling_cube.jpg
|
|
||||||
Oracle:{3}, {T}: Double the amount of each type of unspent mana you have.
|
Oracle:{3}, {T}: Double the amount of each type of unspent mana you have.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Name:Eloren Wilds
|
|||||||
ManaCost:no cost
|
ManaCost:no cost
|
||||||
Types:Plane Shandalar
|
Types:Plane Shandalar
|
||||||
T:Mode$ TapsForMana | ValidCard$ Permanent | Execute$ TrigMana | TriggerZones$ Command | Static$ True | TriggerDescription$ Whenever a player taps a permanent for mana, that player adds one mana of any type that permanent produced.
|
T:Mode$ TapsForMana | ValidCard$ Permanent | Execute$ TrigMana | TriggerZones$ Command | Static$ True | TriggerDescription$ Whenever a player taps a permanent for mana, that player adds one mana of any type that permanent produced.
|
||||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ TriggeredActivator
|
||||||
T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll {CHAOS}, target player can't cast spells until a player planeswalks.
|
T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll {CHAOS}, target player can't cast spells until a player planeswalks.
|
||||||
SVar:RolledChaos:DB$ Effect | ValidTgts$ Player | IsCurse$ True | Name$ Eloren Wilds Effect | StaticAbilities$ STCantCast | Triggers$ TrigPlaneswalk | SVars$ ExileSelf | RememberObjects$ Targeted | Duration$ Permanent
|
SVar:RolledChaos:DB$ Effect | ValidTgts$ Player | IsCurse$ True | Name$ Eloren Wilds Effect | StaticAbilities$ STCantCast | Triggers$ TrigPlaneswalk | SVars$ ExileSelf | RememberObjects$ Targeted | Duration$ Permanent
|
||||||
SVar:STCantCast:Mode$ CantBeCast | EffectZone$ Command | ValidCard$ Card | Caster$ Player.IsRemembered | Description$ Target player can't cast spells until a player planeswalks.
|
SVar:STCantCast:Mode$ CantBeCast | EffectZone$ Command | ValidCard$ Card | Caster$ Player.IsRemembered | Description$ Target player can't cast spells until a player planeswalks.
|
||||||
|
|||||||
@@ -4,12 +4,11 @@ Types:Artifact
|
|||||||
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | Execute$ TrigExile | OptionalDecider$ You | TriggerDescription$ Imprint — When CARDNAME enters the battlefield, you may exile target land you control.
|
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | Execute$ TrigExile | OptionalDecider$ You | TriggerDescription$ Imprint — When CARDNAME enters the battlefield, you may exile target land you control.
|
||||||
SVar:TrigExile:DB$ ChangeZone | Imprint$ True | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Land.YouCtrl | TgtPrompt$ Select a target land you control | AILogic$ ExtraplanarLens
|
SVar:TrigExile:DB$ ChangeZone | Imprint$ True | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Land.YouCtrl | TgtPrompt$ Select a target land you control | AILogic$ ExtraplanarLens
|
||||||
T:Mode$ TapsForMana | ValidCard$ Land.sharesNameWith Imprinted | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever a land with the same name as the exiled card is tapped for mana, its controller adds one mana of any type that land produced.
|
T:Mode$ TapsForMana | ValidCard$ Land.sharesNameWith Imprinted | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever a land with the same name as the exiled card is tapped for mana, its controller adds one mana of any type that land produced.
|
||||||
SVar:TrigMana:DB$ ManaReflected | Valid$ Defined.Triggered | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ TriggeredCardController
|
||||||
T:Mode$ ChangesZone | Origin$ Battlefield | ValidCard$ Card.Self | Destination$ Any | Execute$ DBCleanup | Static$ True
|
T:Mode$ ChangesZone | Origin$ Battlefield | ValidCard$ Card.Self | Destination$ Any | Execute$ DBCleanup | Static$ True
|
||||||
SVar:DBCleanup:DB$ Cleanup | ClearImprinted$ True
|
SVar:DBCleanup:DB$ Cleanup | ClearImprinted$ True
|
||||||
T:Mode$ ChangesZone | ValidCard$ Card.IsImprinted+ExiledWithSource | Origin$ Exile | Execute$ DBForget | Static$ True
|
T:Mode$ ChangesZone | ValidCard$ Card.IsImprinted+ExiledWithSource | Origin$ Exile | Execute$ DBForget | Static$ True
|
||||||
SVar:DBForget:DB$ Pump | ForgetImprinted$ TriggeredCard
|
SVar:DBForget:DB$ Pump | ForgetImprinted$ TriggeredCard
|
||||||
SVar:NeedsToPlay:Land.Basic+YouCtrl
|
SVar:NeedsToPlay:Land.Basic+YouCtrl
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/extraplanar_lens.jpg
|
|
||||||
Oracle:Imprint — When Extraplanar Lens enters the battlefield, you may exile target land you control.\nWhenever a land with the same name as the exiled card is tapped for mana, its controller adds one mana of any type that land produced.
|
Oracle:Imprint — When Extraplanar Lens enters the battlefield, you may exile target land you control.\nWhenever a land with the same name as the exiled card is tapped for mana, its controller adds one mana of any type that land produced.
|
||||||
|
|||||||
@@ -3,9 +3,8 @@ ManaCost:1 W
|
|||||||
Types:Sorcery
|
Types:Sorcery
|
||||||
A:SP$ Effect | Cost$ 1 W | ReplacementEffects$ FDRep | StaticAbilities$ FDManaConvertion | SVars$ ProduceW | SubAbility$ DBDraw | SpellDescription$ Until end of turn, spells and abilities you control that would add colored mana add that much white mana instead. Until end of turn, you may spend white mana as though it were mana of any color. Draw a card.
|
A:SP$ Effect | Cost$ 1 W | ReplacementEffects$ FDRep | StaticAbilities$ FDManaConvertion | SVars$ ProduceW | SubAbility$ DBDraw | SpellDescription$ Until end of turn, spells and abilities you control that would add colored mana add that much white mana instead. Until end of turn, you may spend white mana as though it were mana of any color. Draw a card.
|
||||||
SVar:DBDraw:DB$ Draw | NumCards$ 1
|
SVar:DBDraw:DB$ Draw | NumCards$ 1
|
||||||
SVar:FDRep:Event$ ProduceMana | ActiveZones$ Command | ValidCard$ Card.YouCtrl | NoTapCheck$ True | ManaReplacement$ ProduceW | Description$ Spells and abilities you control that would add colored mana add that much white mana instead.
|
SVar:FDRep:Event$ ProduceMana | ActiveZones$ Command | ValidCard$ Card.YouCtrl | ReplaceWith$ ProduceW | Description$ Spells and abilities you control that would add colored mana add that much white mana instead.
|
||||||
SVar:ProduceW:R->W & B->W & U->W & G->W
|
SVar:ProduceW:DB$ ReplaceMana | ReplaceColor$ W
|
||||||
SVar:FDManaConvertion:Mode$ Continuous | EffectZone$ Command | Affected$ You | ManaColorConversion$ Additive | WhiteConversion$ Color | Description$ You may spend white mana as though it were mana of any color.
|
SVar:FDManaConvertion:Mode$ Continuous | EffectZone$ Command | Affected$ You | ManaColorConversion$ Additive | WhiteConversion$ Color | Description$ You may spend white mana as though it were mana of any color.
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/false_dawn.jpg
|
|
||||||
Oracle:Until end of turn, spells and abilities you control that would add colored mana add that much white mana instead. Until end of turn, you may spend white mana as though it were mana of any color.\nDraw a card.
|
Oracle:Until end of turn, spells and abilities you control that would add colored mana add that much white mana instead. Until end of turn, you may spend white mana as though it were mana of any color.\nDraw a card.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Name:Forsaken Monument
|
|||||||
ManaCost:5
|
ManaCost:5
|
||||||
Types:Legendary Artifact
|
Types:Legendary Artifact
|
||||||
S:Mode$ Continuous | Affected$ Creature.Colorless+YouCtrl | AddPower$ 2 | AddToughness$ 2 | Description$ Colorless creatures you control get +2/+2.
|
S:Mode$ Continuous | Affected$ Creature.Colorless+YouCtrl | AddPower$ 2 | AddToughness$ 2 | Description$ Colorless creatures you control get +2/+2.
|
||||||
T:Mode$ TapsForMana | ValidCard$ Permanent.YouCtrl | Produced$ C | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a permanent for {C}, add an additional {C}.
|
T:Mode$ TapsForMana | ValidCard$ Permanent | Activator$ You | Produced$ C | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a permanent for {C}, add an additional {C}.
|
||||||
SVar:TrigMana:DB$ Mana | Produced$ C
|
SVar:TrigMana:DB$ Mana | Produced$ C
|
||||||
T:Mode$ SpellCast | ValidCard$ Card.Colorless | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigGainLife | TriggerDescription$ Whenever you cast a colorless spell, you gain 2 life.
|
T:Mode$ SpellCast | ValidCard$ Card.Colorless | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigGainLife | TriggerDescription$ Whenever you cast a colorless spell, you gain 2 life.
|
||||||
SVar:TrigGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 2
|
SVar:TrigGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 2
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ Types:World Enchantment
|
|||||||
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ Player | Execute$ TrigChoose | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of each player's upkeep, that player chooses a color. Until end of turn, lands tapped for mana produce mana of the chosen color instead of any other color.
|
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ Player | Execute$ TrigChoose | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of each player's upkeep, that player chooses a color. Until end of turn, lands tapped for mana produce mana of the chosen color instead of any other color.
|
||||||
SVar:TrigChoose:DB$ ChooseColor | Defined$ TriggeredPlayer | AILogic$ MostProminentInActivePlayerHand | SubAbility$ DBEffect
|
SVar:TrigChoose:DB$ ChooseColor | Defined$ TriggeredPlayer | AILogic$ MostProminentInActivePlayerHand | SubAbility$ DBEffect
|
||||||
SVar:DBEffect:DB$ Effect | ReplacementEffects$ ReplaceChosen | SVars$ ProduceChosen
|
SVar:DBEffect:DB$ Effect | ReplacementEffects$ ReplaceChosen | SVars$ ProduceChosen
|
||||||
SVar:ReplaceChosen:Event$ ProduceMana | ActiveZones$ Command | ValidCard$ Land | ManaReplacement$ ProduceChosen | Description$ Lands tapped for mana produce mana of the chosen color instead of any other color.
|
SVar:ReplaceChosen:Event$ ProduceMana | ActiveZones$ Command | ValidCard$ Land | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceChosen | Description$ Lands tapped for mana produce mana of the chosen color instead of any other color.
|
||||||
SVar:ProduceChosen:C->Chosen & U->Chosen & B->Chosen & R->Chosen & G->Chosen & W->Chosen
|
SVar:ProduceChosen:DB$ ReplaceMana | ReplaceColor$ Chosen
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/hall_of_gemstone.jpg
|
|
||||||
Oracle:At the beginning of each player's upkeep, that player chooses a color. Until end of turn, lands tapped for mana produce mana of the chosen color instead of any other color.
|
Oracle:At the beginning of each player's upkeep, that player chooses a color. Until end of turn, lands tapped for mana produce mana of the chosen color instead of any other color.
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ ManaCost:G
|
|||||||
Types:Creature Human Spellshaper
|
Types:Creature Human Spellshaper
|
||||||
PT:1/1
|
PT:1/1
|
||||||
A:AB$ Effect | Cost$ G T Discard<1/Card> | ReplacementEffects$ HarvestReplacement | SVars$ HarvestProduce | References$ HarvestReplacement,HarvestProduce | AILogic$ Never | Stackable$ False | SpellDescription$ Until end of turn, if you tap a land for mana, it produces one mana of a color of your choice instead of any other type and amount.
|
A:AB$ Effect | Cost$ G T Discard<1/Card> | ReplacementEffects$ HarvestReplacement | SVars$ HarvestProduce | References$ HarvestReplacement,HarvestProduce | AILogic$ Never | Stackable$ False | SpellDescription$ Until end of turn, if you tap a land for mana, it produces one mana of a color of your choice instead of any other type and amount.
|
||||||
SVar:HarvestReplacement:Event$ ProduceMana | ActiveZones$ Command | ValidCard$ Land.YouCtrl | ManaReplacement$ HarvestProduce | Description$ If you tap a land for mana, it produces one mana of a color of your choice instead of any other type and amount.
|
SVar:HarvestReplacement:Event$ ProduceMana | ActiveZones$ Command | ValidPlayer$ You | ValidCard$ Land | ValidAbility$ Activated.hasTapCost | ReplaceWith$ HarvestProduce | Description$ If you tap a land for mana, it produces one mana of a color of your choice instead of any other type and amount.
|
||||||
SVar:HarvestProduce:Any->Any
|
SVar:HarvestProduce:DB$ ReplaceMana | ReplaceMana$ Any
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
SVar:NonStackingEffect:True
|
SVar:NonStackingEffect:True
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/harvest_mage.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/harvest_mage.jpg
|
||||||
|
|||||||
@@ -2,7 +2,5 @@ Name:Heartbeat of Spring
|
|||||||
ManaCost:2 G
|
ManaCost:2 G
|
||||||
Types:Enchantment
|
Types:Enchantment
|
||||||
T:Mode$ TapsForMana | ValidCard$ Land | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
T:Mode$ TapsForMana | ValidCard$ Land | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
||||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ TriggeredActivator
|
||||||
AI:RemoveDeck:All
|
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/heartbeat_of_spring.jpg
|
|
||||||
Oracle:Whenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
Oracle:Whenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ Name:Infernal Darkness
|
|||||||
ManaCost:2 B B
|
ManaCost:2 B B
|
||||||
Types:Enchantment
|
Types:Enchantment
|
||||||
K:Cumulative upkeep:B PayLife<1>:Pay {B} and 1 life.
|
K:Cumulative upkeep:B PayLife<1>:Pay {B} and 1 life.
|
||||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Land | ManaReplacement$ ProduceB | Description$ If a land is tapped for mana, it produces {B} instead of any other type.
|
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Land | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceB | Description$ If a land is tapped for mana, it produces {B} instead of any other type.
|
||||||
SVar:ProduceB:C->B & U->B & R->B & G->B & W->B
|
SVar:ProduceB:DB$ ReplaceMana | ReplaceType$ B
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/infernal_darkness.jpg
|
|
||||||
Oracle:Cumulative upkeep—Pay {B} and 1 life. (At the beginning of your upkeep, put an age counter on this permanent, then sacrifice it unless you pay its upkeep cost for each age counter on it.)\nIf a land is tapped for mana, it produces {B} instead of any other type.
|
Oracle:Cumulative upkeep—Pay {B} and 1 life. (At the beginning of your upkeep, put an age counter on this permanent, then sacrifice it unless you pay its upkeep cost for each age counter on it.)\nIf a land is tapped for mana, it produces {B} instead of any other type.
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ ManaCost:3 G
|
|||||||
Types:Creature Elf Druid
|
Types:Creature Elf Druid
|
||||||
PT:1/3
|
PT:1/3
|
||||||
T:Mode$ TapsForMana | ValidCard$ Mountain,Forest,Plains | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever a player taps a Mountain, Forest, or Plains for mana, that player adds one mana of any type that land produced.
|
T:Mode$ TapsForMana | ValidCard$ Mountain,Forest,Plains | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever a player taps a Mountain, Forest, or Plains for mana, that player adds one mana of any type that land produced.
|
||||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ TriggeredActivator
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/keeper_of_progenitus.jpg
|
|
||||||
Oracle:Whenever a player taps a Mountain, Forest, or Plains for mana, that player adds one mana of any type that land produced.
|
Oracle:Whenever a player taps a Mountain, Forest, or Plains for mana, that player adds one mana of any type that land produced.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Name:Kinnan, Bonder Prodigy
|
|||||||
ManaCost:G U
|
ManaCost:G U
|
||||||
Types:Legendary Creature Human Druid
|
Types:Legendary Creature Human Druid
|
||||||
PT:2/2
|
PT:2/2
|
||||||
T:Mode$ TapsForMana | ValidCard$ Permanent.nonLand+YouCtrl | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a nonland permanent for mana, add one mana of any type that permanent produced.
|
T:Mode$ TapsForMana | ValidCard$ Permanent.nonLand | Activator$ You | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a nonland permanent for mana, add one mana of any type that permanent produced.
|
||||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ You
|
||||||
A:AB$ Dig | Cost$ 5 G U | ForceRevealToController$ True | DigNum$ 5 | ChangeNum$ 1 | Optional$ True | ChangeValid$ Creature.nonHuman | DestinationZone$ Battlefield | RestRandomOrder$ True | SpellDescription$ Look at the top five cards of your library. You may put a non-Human creature card from among them onto the battlefield. Put the rest on the bottom of your library in a random order.
|
A:AB$ Dig | Cost$ 5 G U | ForceRevealToController$ True | DigNum$ 5 | ChangeNum$ 1 | Optional$ True | ChangeValid$ Creature.nonHuman | DestinationZone$ Battlefield | RestRandomOrder$ True | SpellDescription$ Look at the top five cards of your library. You may put a non-Human creature card from among them onto the battlefield. Put the rest on the bottom of your library in a random order.
|
||||||
Oracle:Whenever you tap a nonland permanent for mana, add one mana of any type that permanent produced.\n{5}{G}{U}: Look at the top five cards of your library. You may put a non-Human creature card from among them onto the battlefield. Put the rest on the bottom of your library in a random order.
|
Oracle:Whenever you tap a nonland permanent for mana, add one mana of any type that permanent produced.\n{5}{G}{U}: Look at the top five cards of your library. You may put a non-Human creature card from among them onto the battlefield. Put the rest on the bottom of your library in a random order.
|
||||||
|
|||||||
@@ -2,6 +2,5 @@ Name:Mana Flare
|
|||||||
ManaCost:2 R
|
ManaCost:2 R
|
||||||
Types:Enchantment
|
Types:Enchantment
|
||||||
T:Mode$ TapsForMana | ValidCard$ Land | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
T:Mode$ TapsForMana | ValidCard$ Land | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
||||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ TriggeredActivator
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/mana_flare.jpg
|
|
||||||
Oracle:Whenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
Oracle:Whenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
Name:Mana Reflection
|
Name:Mana Reflection
|
||||||
ManaCost:4 G G
|
ManaCost:4 G G
|
||||||
Types:Enchantment
|
Types:Enchantment
|
||||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Permanent.YouCtrl | ManaReplacement$ ProduceTwice | Description$ If you tap a permanent for mana, it produces twice as much of that mana instead.
|
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidPlayer$ You | ValidCard$ Permanent | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceTwice | Description$ If you tap a permanent for mana, it produces twice as much of that mana instead.
|
||||||
SVar:ProduceTwice:C->C C & R->R R & B->B B & U->U U & G->G G & W->W W
|
SVar:ProduceTwice:DB$ ReplaceMana | ReplaceAmount$ 2
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/mana_reflection.jpg
|
|
||||||
Oracle:If you tap a permanent for mana, it produces twice as much of that mana instead.
|
Oracle:If you tap a permanent for mana, it produces twice as much of that mana instead.
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ Name:Mirari's Wake
|
|||||||
ManaCost:3 G W
|
ManaCost:3 G W
|
||||||
Types:Enchantment
|
Types:Enchantment
|
||||||
S:Mode$ Continuous | Affected$ Creature.YouCtrl | AddPower$ 1 | AddToughness$ 1 | Description$ Creatures you control get +1/+1.
|
S:Mode$ Continuous | Affected$ Creature.YouCtrl | AddPower$ 1 | AddToughness$ 1 | Description$ Creatures you control get +1/+1.
|
||||||
T:Mode$ TapsForMana | ValidCard$ Land.YouCtrl | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a land for mana, add one mana of any type that land produced.
|
T:Mode$ TapsForMana | ValidCard$ Land | Activator$ You | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a land for mana, add one mana of any type that land produced.
|
||||||
SVar:TrigMana:DB$ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ You
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/miraris_wake.jpg
|
|
||||||
Oracle:Creatures you control get +1/+1.\nWhenever you tap a land for mana, add one mana of any type that land produced.
|
Oracle:Creatures you control get +1/+1.\nWhenever you tap a land for mana, add one mana of any type that land produced.
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ Name:Mirri
|
|||||||
ManaCost:no cost
|
ManaCost:no cost
|
||||||
Types:Vanguard
|
Types:Vanguard
|
||||||
HandLifeModifier:+0/+5
|
HandLifeModifier:+0/+5
|
||||||
R:Event$ ProduceMana | ActiveZones$ Command | ValidCard$ Land.Basic+YouCtrl | ManaReplacement$ ProduceAny | Description$ If a basic land you control is tapped for mana, it produces mana of a color of your choice instead of any other type.
|
R:Event$ ProduceMana | ActiveZones$ Command | ValidCard$ Land.Basic+YouCtrl | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceAny | Description$ If a basic land you control is tapped for mana, it produces mana of a color of your choice instead of any other type.
|
||||||
SVar:ProduceAny:C->Any & B->Any & R->Any & G->Any & W->Any & U->Any
|
SVar:ProduceAny:DB$ ReplaceMana | ReplaceType$ Any
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
SVar:Picture:https://downloads.cardforge.org/images/cards/VAN/Mirri.full.jpg
|
SVar:Picture:https://downloads.cardforge.org/images/cards/VAN/Mirri.full.jpg
|
||||||
Oracle:Hand +0, life +5\nIf a basic land you control is tapped for mana, it produces mana of a color of your choice instead of any other type.
|
Oracle:Hand +0, life +5\nIf a basic land you control is tapped for mana, it produces mana of a color of your choice instead of any other type.
|
||||||
|
|||||||
@@ -3,17 +3,16 @@ ManaCost:5
|
|||||||
Types:Artifact
|
Types:Artifact
|
||||||
Text:If tapped for mana, Plains produce {R}, Islands produce {G}, Swamps produce {W}, Mountains produce {U}, and Forests produce {B} instead of any other type.
|
Text:If tapped for mana, Plains produce {R}, Islands produce {G}, Swamps produce {W}, Mountains produce {U}, and Forests produce {B} instead of any other type.
|
||||||
K:Cumulative upkeep:3
|
K:Cumulative upkeep:3
|
||||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Plains | ManaReplacement$ ProduceR | Secondary$ True | Description$ If tapped for mana, Plains produce R.
|
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Plains | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceR | Secondary$ True | Description$ If tapped for mana, Plains produce R.
|
||||||
SVar:ProduceR:C->R & B->R & U->R & G->R & W->R
|
SVar:ProduceR:DB$ ReplaceMana | ReplaceType$ R
|
||||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Island | ManaReplacement$ ProduceG | Secondary$ True | Description$ If tapped for mana, Islands produce G.
|
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Island | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceG | Secondary$ True | Description$ If tapped for mana, Islands produce G.
|
||||||
SVar:ProduceG:C->G & B->G & U->G & R->G & W->G
|
SVar:ProduceG:DB$ ReplaceMana | ReplaceType$ G
|
||||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Swamp | ManaReplacement$ ProduceW | Secondary$ True | Description$ If tapped for mana, Swamps produce W.
|
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Swamp | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceW | Secondary$ True | Description$ If tapped for mana, Swamps produce W.
|
||||||
SVar:ProduceW:C->W & B->W & U->W & R->W & G->W
|
SVar:ProduceW:DB$ ReplaceMana | ReplaceType$ W
|
||||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Mountain | ManaReplacement$ ProduceU | Secondary$ True | Description$ If tapped for mana, Mountains produce U.
|
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Mountain | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceU | Secondary$ True | Description$ If tapped for mana, Mountains produce U.
|
||||||
SVar:ProduceU:C->U & B->U & G->U & R->U & W->U
|
SVar:ProduceU:DB$ ReplaceMana | ReplaceType$ U
|
||||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Forest | ManaReplacement$ ProduceB | Secondary$ True | Description$ If tapped for mana, Forests produce B.
|
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Forest | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceB | Secondary$ True | Description$ If tapped for mana, Forests produce B.
|
||||||
SVar:ProduceB:C->B & G->B & U->B & R->B & W->B
|
SVar:ProduceB:DB$ ReplaceMana | ReplaceType$ B
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/naked_singularity.jpg
|
|
||||||
Oracle:Cumulative upkeep {3} (At the beginning of your upkeep, put an age counter on this permanent, then sacrifice it unless you pay its upkeep cost for each age counter on it.)\nIf tapped for mana, Plains produce {R}, Islands produce {G}, Swamps produce {W}, Mountains produce {U}, and Forests produce {B} instead of any other type.
|
Oracle:Cumulative upkeep {3} (At the beginning of your upkeep, put an age counter on this permanent, then sacrifice it unless you pay its upkeep cost for each age counter on it.)\nIf tapped for mana, Plains produce {R}, Islands produce {G}, Swamps produce {W}, Mountains produce {U}, and Forests produce {B} instead of any other type.
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ ManaCost:3 R G
|
|||||||
Types:Legendary Creature Centaur Druid
|
Types:Legendary Creature Centaur Druid
|
||||||
PT:5/5
|
PT:5/5
|
||||||
S:Mode$ CantBeCast | ValidCard$ Card.nonCreature | Caster$ You | Description$ You can't cast noncreature spells.
|
S:Mode$ CantBeCast | ValidCard$ Card.nonCreature | Caster$ You | Description$ You can't cast noncreature spells.
|
||||||
T:Mode$ TapsForMana | ValidCard$ Land.YouCtrl | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a land for mana, add one mana of any type that land produced.
|
T:Mode$ TapsForMana | ValidCard$ Land | Activator$ You | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a land for mana, add one mana of any type that land produced.
|
||||||
SVar:TrigMana:DB$ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ You
|
||||||
Oracle:You can't cast noncreature spells.\nWhenever you tap a land for mana, add one mana of any type that land produced.
|
Oracle:You can't cast noncreature spells.\nWhenever you tap a land for mana, add one mana of any type that land produced.
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ ManaCost:4 B B
|
|||||||
Types:Creature Vampire Shade
|
Types:Creature Vampire Shade
|
||||||
PT:4/4
|
PT:4/4
|
||||||
A:AB$ Pump | Cost$ B | NumAtt$ +1 | NumDef$ +1 | SpellDescription$ CARDNAME gets +1/+1 until end of turn.
|
A:AB$ Pump | Cost$ B | NumAtt$ +1 | NumDef$ +1 | SpellDescription$ CARDNAME gets +1/+1 until end of turn.
|
||||||
T:Mode$ TapsForMana | ValidCard$ Swamp.YouCtrl | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a Swamp for mana, add an additional {B}.
|
T:Mode$ TapsForMana | ValidCard$ Swamp | Activator$ You | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a Swamp for mana, add an additional {B}.
|
||||||
SVar:TrigMana:DB$ Mana | Produced$ B | Amount$ 1
|
SVar:TrigMana:DB$ Mana | Produced$ B | Amount$ 1
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/nirkana_revenant.jpg
|
|
||||||
Oracle:Whenever you tap a Swamp for mana, add an additional {B}.\n{B}: Nirkana Revenant gets +1/+1 until end of turn.
|
Oracle:Whenever you tap a Swamp for mana, add an additional {B}.\n{B}: Nirkana Revenant gets +1/+1 until end of turn.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Name:Nissa, Who Shakes the World
|
|||||||
ManaCost:3 G G
|
ManaCost:3 G G
|
||||||
Types:Legendary Planeswalker Nissa
|
Types:Legendary Planeswalker Nissa
|
||||||
Loyalty:5
|
Loyalty:5
|
||||||
T:Mode$ TapsForMana | ValidCard$ Forest.YouCtrl | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a Forest for mana, add an additional {G}.
|
T:Mode$ TapsForMana | ValidCard$ Forest | Activator$ You | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a Forest for mana, add an additional {G}.
|
||||||
SVar:TrigMana:DB$ Mana | Produced$ G | Amount$ 1
|
SVar:TrigMana:DB$ Mana | Produced$ G | Amount$ 1
|
||||||
A:AB$ PutCounter | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | CounterType$ P1P1 | CounterNum$ 3 | ValidTgts$ Land.nonCreature+YouCtrl | TargetMin$ 0 | TargetMax$ 1 | TgtPrompt$ Select target noncreature land you control | SubAbility$ DBUntap | SpellDescription$ Put three +1/+1 counters on up to one target noncreature land you control. Untap it. It becomes a 0/0 Elemental creature with vigilance and haste that's still a land.
|
A:AB$ PutCounter | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | CounterType$ P1P1 | CounterNum$ 3 | ValidTgts$ Land.nonCreature+YouCtrl | TargetMin$ 0 | TargetMax$ 1 | TgtPrompt$ Select target noncreature land you control | SubAbility$ DBUntap | SpellDescription$ Put three +1/+1 counters on up to one target noncreature land you control. Untap it. It becomes a 0/0 Elemental creature with vigilance and haste that's still a land.
|
||||||
SVar:DBUntap:DB$ Untap | Defined$ Targeted | SubAbility$ DBAnimate
|
SVar:DBUntap:DB$ Untap | Defined$ Targeted | SubAbility$ DBAnimate
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ ManaCost:4 G G G
|
|||||||
Types:Enchantment Creature Elemental
|
Types:Enchantment Creature Elemental
|
||||||
PT:5/5
|
PT:5/5
|
||||||
K:Trample
|
K:Trample
|
||||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Permanent.YouCtrl | ManaReplacement$ ProduceThrice | Description$ If you tap a permanent for mana, it produces three times as much of that mana instead.
|
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Permanent.YouCtrl | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceThrice | Description$ If you tap a permanent for mana, it produces three times as much of that mana instead.
|
||||||
SVar:ProduceThrice:C->C C C & R->R R R & B->B B B & U->U U U & G->G G G & W->W W W
|
SVar:ProduceThrice:DB$ ReplaceMana | ReplaceAmount$ 3
|
||||||
Oracle:Trample\nIf you tap a permanent for mana, it produces three times as much of that mana instead.
|
Oracle:Trample\nIf you tap a permanent for mana, it produces three times as much of that mana instead.
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ ManaCost:1 R G
|
|||||||
Types:Enchantment
|
Types:Enchantment
|
||||||
T:Mode$ TapsForMana | ValidCard$ Land | Execute$ TrigDmg | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever a player taps a land for mana, that player adds one mana of any type that land produced, and CARDNAME deals 1 damage to them.
|
T:Mode$ TapsForMana | ValidCard$ Land | Execute$ TrigDmg | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever a player taps a land for mana, that player adds one mana of any type that land produced, and CARDNAME deals 1 damage to them.
|
||||||
SVar:TrigDmg:DB$ DealDamage | Defined$ TriggeredCardController | NumDmg$ 1 | SubAbility$ DBMana
|
SVar:TrigDmg:DB$ DealDamage | Defined$ TriggeredCardController | NumDmg$ 1 | SubAbility$ DBMana
|
||||||
SVar:DBMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredCardController
|
SVar:DBMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ TriggeredActivator
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/overabundance.jpg
|
|
||||||
Oracle:Whenever a player taps a land for mana, that player adds one mana of any type that land produced, and Overabundance deals 1 damage to them.
|
Oracle:Whenever a player taps a land for mana, that player adds one mana of any type that land produced, and Overabundance deals 1 damage to them.
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ Name:Pale Moon
|
|||||||
ManaCost:1 U
|
ManaCost:1 U
|
||||||
Types:Instant
|
Types:Instant
|
||||||
A:SP$ Effect | Cost$ 1 U | ReplacementEffects$ ReplaceColorless | SVars$ ProduceColorless | SpellDescription$ Until end of turn, if a player taps a nonbasic land for mana, it produces colorless mana instead of any other type.
|
A:SP$ Effect | Cost$ 1 U | ReplacementEffects$ ReplaceColorless | SVars$ ProduceColorless | SpellDescription$ Until end of turn, if a player taps a nonbasic land for mana, it produces colorless mana instead of any other type.
|
||||||
SVar:ReplaceColorless:Event$ ProduceMana | ActiveZones$ Command | ValidCard$ Land.nonBasic | ManaReplacement$ ProduceColorless | Description$ If a player taps a nonbasic land for mana, it produces colorless mana instead of any other type.
|
SVar:ReplaceColorless:Event$ ProduceMana | ActiveZones$ Command | ValidCard$ Land.nonBasic | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceColorless | Description$ If a player taps a nonbasic land for mana, it produces colorless mana instead of any other type.
|
||||||
SVar:ProduceColorless:U->1 & B->1 & R->1 & G->1 & W->1
|
SVar:ProduceColorless:DB$ ReplaceMana | ReplaceType$ C
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/pale_moon.jpg
|
|
||||||
Oracle:Until end of turn, if a player taps a nonbasic land for mana, it produces colorless mana instead of any other type.
|
Oracle:Until end of turn, if a player taps a nonbasic land for mana, it produces colorless mana instead of any other type.
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
Name:Pulse of Llanowar
|
Name:Pulse of Llanowar
|
||||||
ManaCost:3 G
|
ManaCost:3 G
|
||||||
Types:Enchantment
|
Types:Enchantment
|
||||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Land.Basic+YouCtrl | ManaReplacement$ ProduceAny | Description$ If a basic land you control is tapped for mana, it produces mana of a color of your choice instead of any other type.
|
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Land.Basic+YouCtrl | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceAny | Description$ If a basic land you control is tapped for mana, it produces mana of a color of your choice instead of any other type.
|
||||||
SVar:ProduceAny:C->Any & R->Any & B->Any & U->Any & G->Any & W->Any
|
SVar:ProduceAny:DB$ ReplaceMana | ReplaceType$ Any
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
SVar:NonStackingEffect:True
|
SVar:NonStackingEffect:True
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/pulse_of_llanowar.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/pulse_of_llanowar.jpg
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ Name:Quarum Trench Gnomes
|
|||||||
ManaCost:3 R
|
ManaCost:3 R
|
||||||
Types:Creature Gnome
|
Types:Creature Gnome
|
||||||
PT:1/1
|
PT:1/1
|
||||||
A:AB$ Animate | Cost$ T | ValidTgts$ Plains | IsCurse$ True | TgtPrompt$ Choose target plains | Replacements$ QuarumReplacement | sVars$ QuarumProduce | Permanent$ True | StackDescription$ If target {c:Targeted} is tapped for mana, it produces colorless mana instead of white mana. (This effect lasts indefinitely.) | SpellDescription$ If target Plains is tapped for mana, it produces colorless mana instead of white mana. (This effect lasts indefinitely.)
|
A:AB$ Effect | Cost$ T | ValidTgts$ Plains | IsCurse$ True | TgtPrompt$ Choose target plains | RememberObjects$ Targeted | ForgetOnMoved$ Battlefield | Duration$ Permanent | ReplacementEffects$ QuarumReplacement | SVars$ QuarumProduce | StackDescription$ If target {c:Targeted} is tapped for mana, it produces colorless mana instead of white mana. (This effect lasts indefinitely.) | SpellDescription$ If target Plains is tapped for mana, it produces colorless mana instead of white mana. (This effect lasts indefinitely.)
|
||||||
SVar:QuarumReplacement:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Card.Plains+Self | ManaReplacement$ QuarumProduce | Description$ If CARDNAME is tapped for mana, it produces colorless mana instead of white mana.
|
SVar:QuarumReplacement:Event$ ProduceMana | ValidCard$ Card.IsRemembered | ReplaceWith$ QuarumProduce | Description$ If this Land is tapped for mana, it produces colorless mana instead of white mana.
|
||||||
SVar:QuarumProduce:W->1
|
SVar:QuarumProduce:DB$ ReplaceMana | ReplaceColor$ C | ReplaceOnly$ W
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/quarum_trench_gnomes.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/quarum_trench_gnomes.jpg
|
||||||
|
|||||||
@@ -3,16 +3,15 @@ ManaCost:U U U
|
|||||||
Types:Enchantment
|
Types:Enchantment
|
||||||
Text:If tapped for mana, Plains produce {R}, Swamps produce {G}, Mountains produce {W}, and Forests produce {B} instead of any other type.
|
Text:If tapped for mana, Plains produce {R}, Swamps produce {G}, Mountains produce {W}, and Forests produce {B} instead of any other type.
|
||||||
K:Cumulative upkeep:1 U U
|
K:Cumulative upkeep:1 U U
|
||||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Plains | ManaReplacement$ ProduceR | Secondary$ True | Description$ If tapped for mana, Plains produce R.
|
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Plains | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceR | Secondary$ True | Description$ If tapped for mana, Plains produce R.
|
||||||
SVar:ProduceR:C->R & B->R & U->R & G->R & W->R
|
SVar:ProduceR:DB$ ReplaceMana | ReplaceType$ R
|
||||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Swamp | ManaReplacement$ ProduceG | Secondary$ True | Description$ If tapped for mana, Swamps produce G.
|
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Swamp | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceG | Secondary$ True | Description$ If tapped for mana, Swamps produce G.
|
||||||
SVar:ProduceG:C->G & B->G & U->G & R->G & W->G
|
SVar:ProduceG:DB$ ReplaceMana | ReplaceType$ G
|
||||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Mountain | ManaReplacement$ ProduceW | Secondary$ True | Description$ If tapped for mana, Mountains produce U.
|
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Mountain | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceW | Secondary$ True | Description$ If tapped for mana, Mountains produce U.
|
||||||
SVar:ProduceW:C->W & B->W & G->W & R->W & U->W
|
SVar:ProduceW:DB$ ReplaceMana | ReplaceType$ W
|
||||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Forest | ManaReplacement$ ProduceB | Secondary$ True | Description$ If tapped for mana, Forests produce B.
|
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Forest | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceB | Secondary$ True | Description$ If tapped for mana, Forests produce B.
|
||||||
SVar:ProduceB:C->B & G->B & U->B & R->B & W->B
|
SVar:ProduceB:DB$ ReplaceMana | ReplaceType$ B
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
SVar:NonStackingEffect:True
|
SVar:NonStackingEffect:True
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/reality_twist.jpg
|
|
||||||
Oracle:Cumulative upkeep {1}{U}{U} (At the beginning of your upkeep, put an age counter on this permanent, then sacrifice it unless you pay its upkeep cost for each age counter on it.)\nIf tapped for mana, Plains produce {R}, Swamps produce {G}, Mountains produce {W}, and Forests produce {B} instead of any other type.
|
Oracle:Cumulative upkeep {1}{U}{U} (At the beginning of your upkeep, put an age counter on this permanent, then sacrifice it unless you pay its upkeep cost for each age counter on it.)\nIf tapped for mana, Plains produce {R}, Swamps produce {G}, Mountains produce {W}, and Forests produce {B} instead of any other type.
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ PT:5/5
|
|||||||
K:Trample
|
K:Trample
|
||||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMonarch | TriggerDescription$ When CARDNAME enters the battlefield, you become the monarch.
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMonarch | TriggerDescription$ When CARDNAME enters the battlefield, you become the monarch.
|
||||||
SVar:TrigMonarch:DB$ BecomeMonarch | Defined$ You
|
SVar:TrigMonarch:DB$ BecomeMonarch | Defined$ You
|
||||||
T:Mode$ TapsForMana | ValidCard$ Land.YouCtrl | CheckDefinedPlayer$ You.isMonarch | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a land for mana while you're the monarch, add an additional one mana of any color.
|
T:Mode$ TapsForMana | ValidCard$ Land | Activator$ You | CheckDefinedPlayer$ You.isMonarch | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a land for mana while you're the monarch, add an additional one mana of any color.
|
||||||
SVar:TrigMana:DB$ Mana | Produced$ Combo Any | Amount$ 1 | AILogic$ MostProminentInComputerHand
|
SVar:TrigMana:DB$ Mana | Produced$ Combo Any | Amount$ 1 | AILogic$ MostProminentInComputerHand
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/regal_behemoth.jpg
|
|
||||||
Oracle:Trample\nWhen Regal Behemoth enters the battlefield, you become the monarch.\nWhenever you tap a land for mana while you're the monarch, add an additional one mana of any color.
|
Oracle:Trample\nWhen Regal Behemoth enters the battlefield, you become the monarch.\nWhenever you tap a land for mana while you're the monarch, add an additional one mana of any color.
|
||||||
@@ -2,10 +2,9 @@ Name:Ritual of Subdual
|
|||||||
ManaCost:4 G G
|
ManaCost:4 G G
|
||||||
Types:Enchantment
|
Types:Enchantment
|
||||||
K:Cumulative upkeep:2
|
K:Cumulative upkeep:2
|
||||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Land | ManaReplacement$ ProduceColorless | Description$ If a land is tapped for mana, it produces colorless mana instead of any other type.
|
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Land | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceColorless | Description$ If a land is tapped for mana, it produces colorless mana instead of any other type.
|
||||||
SVar:ProduceColorless:B->1 & U->1 & R->1 & G->1 & W->1
|
SVar:ProduceColorless:DB$ ReplaceMana | ReplaceType$ C
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
SVar:NonStackingEffect:True
|
SVar:NonStackingEffect:True
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/ritual_of_subdual.jpg
|
|
||||||
Oracle:Cumulative upkeep {2} (At the beginning of your upkeep, put an age counter on this permanent, then sacrifice it unless you pay its upkeep cost for each age counter on it.)\nIf a land is tapped for mana, it produces colorless mana instead of any other type.
|
Oracle:Cumulative upkeep {2} (At the beginning of your upkeep, put an age counter on this permanent, then sacrifice it unless you pay its upkeep cost for each age counter on it.)\nIf a land is tapped for mana, it produces colorless mana instead of any other type.
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
Name:River of Tears
|
Name:River of Tears
|
||||||
ManaCost:no cost
|
ManaCost:no cost
|
||||||
Types:Land
|
Types:Land
|
||||||
A:AB$ Mana | Cost$ T | Produced$ U | ReplaceIfLandPlayed$ B | SpellDescription$ Add {U}. If you played a land this turn, add {B} instead.
|
A:AB$ Mana | Cost$ T | Produced$ U | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ0 | References$ X | SubAbility$ ManaB | SpellDescription$ Add {U}. If you played a land this turn, add {B} instead.
|
||||||
|
SVar:ManaB:DB$ Mana | Produced$ B | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | References$ X
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
DeckHints:Color$Blue|Black
|
DeckHints:Color$Blue|Black
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/river_of_tears.jpg
|
SVar:X:Count$YourLandsPlayed
|
||||||
Oracle:{T}: Add {U}. If you played a land this turn, add {B} instead.
|
Oracle:{T}: Add {U}. If you played a land this turn, add {B} instead.
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ PT:2/3
|
|||||||
A:AB$ SetState | Cost$ Reveal<1/Hand> | Defined$ Self | Mode$ Flip | ConditionCheckSVar$ CheckHandLand | ConditionSVarCompare$ GE7 | AILogic$ CheckCondition | References$ CheckHandLand | SpellDescription$ If you have seven or more land cards in your hand, flip CARDNAME.
|
A:AB$ SetState | Cost$ Reveal<1/Hand> | Defined$ Self | Mode$ Flip | ConditionCheckSVar$ CheckHandLand | ConditionSVarCompare$ GE7 | AILogic$ CheckCondition | References$ CheckHandLand | SpellDescription$ If you have seven or more land cards in your hand, flip CARDNAME.
|
||||||
SVar:CheckHandLand:Count$ValidHand Land.YouCtrl
|
SVar:CheckHandLand:Count$ValidHand Land.YouCtrl
|
||||||
AlternateMode:Flip
|
AlternateMode:Flip
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/sasaya_orochi_ascendant.jpg
|
|
||||||
Oracle:Reveal your hand: If you have seven or more land cards in your hand, flip Sasaya, Orochi Ascendant.
|
Oracle:Reveal your hand: If you have seven or more land cards in your hand, flip Sasaya, Orochi Ascendant.
|
||||||
|
|
||||||
ALTERNATE
|
ALTERNATE
|
||||||
@@ -17,7 +16,6 @@ Types:Legendary Enchantment
|
|||||||
T:Mode$ TapsForMana | ValidCard$ Land.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigMana | Static$ True | TriggerDescription$ Whenever a land you control is tapped for mana, for each other land you control with the same name, add one mana of any type that land produced.
|
T:Mode$ TapsForMana | ValidCard$ Land.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigMana | Static$ True | TriggerDescription$ Whenever a land you control is tapped for mana, for each other land you control with the same name, add one mana of any type that land produced.
|
||||||
SVar:TrigMana:DB$ Pump | RememberObjects$ TriggeredCard | SubAbility$ DBRepeat
|
SVar:TrigMana:DB$ Pump | RememberObjects$ TriggeredCard | SubAbility$ DBRepeat
|
||||||
SVar:DBRepeat:DB$ RepeatEach | UseImprinted$ True | RepeatCards$ Land.YouCtrl+IsNotRemembered+sharesNameWith Remembered | RepeatSubAbility$ DBManaReflect | SubAbility$ DBCleanup
|
SVar:DBRepeat:DB$ RepeatEach | UseImprinted$ True | RepeatCards$ Land.YouCtrl+IsNotRemembered+sharesNameWith Remembered | RepeatSubAbility$ DBManaReflect | SubAbility$ DBCleanup
|
||||||
SVar:DBManaReflect:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Imprinted | ReflectProperty$ Produced | Defined$ You
|
SVar:DBManaReflect:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ You
|
||||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/sasayas_essence.jpg
|
|
||||||
Oracle:Whenever a land you control is tapped for mana, for each other land you control with the same name, add one mana of any type that land produced.
|
Oracle:Whenever a land you control is tapped for mana, for each other land you control with the same name, add one mana of any type that land produced.
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ Types:Creature Elemental Cat
|
|||||||
PT:0/0
|
PT:0/0
|
||||||
K:etbCounter:P1P1:7
|
K:etbCounter:P1P1:7
|
||||||
K:Trample
|
K:Trample
|
||||||
T:Mode$ TapsForMana | ValidCard$ Land.YouCtrl | Execute$ TrigRemoveCounter | TriggerZones$ Battlefield | TriggerDescription$ Whenever you tap a land for mana, remove a +1/+1 counter from CARDNAME.
|
T:Mode$ TapsForMana | ValidCard$ Land | Activator$ You | Execute$ TrigRemoveCounter | TriggerZones$ Battlefield | TriggerDescription$ Whenever you tap a land for mana, remove a +1/+1 counter from CARDNAME.
|
||||||
SVar:TrigRemoveCounter:DB$ RemoveCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
|
SVar:TrigRemoveCounter:DB$ RemoveCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/savage_firecat.jpg
|
|
||||||
Oracle:Trample\nSavage Firecat enters the battlefield with seven +1/+1 counters on it.\nWhenever you tap a land for mana, remove a +1/+1 counter from Savage Firecat.
|
Oracle:Trample\nSavage Firecat enters the battlefield with seven +1/+1 counters on it.\nWhenever you tap a land for mana, remove a +1/+1 counter from Savage Firecat.
|
||||||
|
|||||||
@@ -9,8 +9,7 @@ SVar:Y:ReplaceCount$TokenNum/Twice
|
|||||||
SVar:Z:ReplaceCount$CounterNum/Twice
|
SVar:Z:ReplaceCount$CounterNum/Twice
|
||||||
T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll {CHAOS}, until end of turn, whenever you tap a land for mana, add one mana of any type that land produced.
|
T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll {CHAOS}, until end of turn, whenever you tap a land for mana, add one mana of any type that land produced.
|
||||||
SVar:RolledChaos:DB$ Effect | AILogic$ Always | Triggers$ TrigTapForMana | SVars$ TrigMana
|
SVar:RolledChaos:DB$ Effect | AILogic$ Always | Triggers$ TrigTapForMana | SVars$ TrigMana
|
||||||
SVar:TrigTapForMana:Mode$ TapsForMana | TriggerZones$ Command | ValidCard$ Land.YouCtrl | Execute$ TrigMana | Static$ True | TriggerDescription$ Whenever you tap a land for mana, add one mana of any type that land produced.
|
SVar:TrigTapForMana:Mode$ TapsForMana | TriggerZones$ Command | ValidCard$ Land | Activator$ You | Execute$ TrigMana | Static$ True | TriggerDescription$ Whenever you tap a land for mana, add one mana of any type that land produced.
|
||||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ You
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/selesnya_loft_gardens.jpg
|
|
||||||
SVar:AIRollPlanarDieParams:Mode$ Always | MinTurn$ 1 | RollInMain1$ True
|
SVar:AIRollPlanarDieParams:Mode$ Always | MinTurn$ 1 | RollInMain1$ True
|
||||||
Oracle:If an effect would create one or more tokens, it creates twice that many of those tokens instead.\nIf an effect would put one or more counters on a permanent, it puts twice that many of those counters on that permanent instead.\nWhenever you roll {CHAOS}, until end of turn, whenever you tap a land for mana, add one mana of any type that land produced.
|
Oracle:If an effect would create one or more tokens, it creates twice that many of those tokens instead.\nIf an effect would put one or more counters on a permanent, it puts twice that many of those counters on that permanent instead.\nWhenever you roll {CHAOS}, until end of turn, whenever you tap a land for mana, add one mana of any type that land produced.
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ Name:Sisay
|
|||||||
ManaCost:no cost
|
ManaCost:no cost
|
||||||
Types:Vanguard
|
Types:Vanguard
|
||||||
HandLifeModifier:-2/-3
|
HandLifeModifier:-2/-3
|
||||||
T:Mode$ TapsForMana | TriggerZones$ Command | ValidCard$ Land.YouCtrl | Execute$ TrigMana | Static$ True | TriggerDescription$ Whenever you tap a land for mana, add one mana of any type that land produced.
|
T:Mode$ TapsForMana | TriggerZones$ Command | ValidCard$ Land | Activator$ You | Execute$ TrigMana | Static$ True | TriggerDescription$ Whenever you tap a land for mana, add one mana of any type that land produced.
|
||||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ You
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
SVar:Picture:https://downloads.cardforge.org/images/cards/VAN/Sisay.full.jpg
|
|
||||||
Oracle:Hand -2, life -3\nWhenever you tap a land for mana, add one mana of any type that land produced.
|
Oracle:Hand -2, life -3\nWhenever you tap a land for mana, add one mana of any type that land produced.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
Name:Urza's Mine
|
Name:Urza's Mine
|
||||||
ManaCost:no cost
|
ManaCost:no cost
|
||||||
Types:Land Urza's Mine
|
Types:Land Urza's Mine
|
||||||
A:AB$ Mana | Cost$ T | Produced$ C | Bonus$ UrzaLands | BonusProduced$ 1 | SpellDescription$ Add {C}. If you control an Urza's Power-Plant and an Urza's Tower, add {C}{C} instead.
|
A:AB$ Mana | Cost$ T | Produced$ C | Amount$ UrzaAmount | References$ UrzaAmount | SpellDescription$ Add {C}. If you control an Urza's Power-Plant and an Urza's Tower, add {C}{C} instead.
|
||||||
|
SVar:UrzaAmount:Count$UrzaLands.2.1
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/urzas_mine.jpg
|
|
||||||
Oracle:{T}: Add {C}. If you control an Urza's Power-Plant and an Urza's Tower, add {C}{C} instead.
|
Oracle:{T}: Add {C}. If you control an Urza's Power-Plant and an Urza's Tower, add {C}{C} instead.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
Name:Urza's Power Plant
|
Name:Urza's Power Plant
|
||||||
ManaCost:no cost
|
ManaCost:no cost
|
||||||
Types:Land Urza's Power-Plant
|
Types:Land Urza's Power-Plant
|
||||||
A:AB$ Mana | Cost$ T | Produced$ C | Bonus$ UrzaLands | BonusProduced$ 1 | SpellDescription$ Add {C}. If you control an Urza's Mine and an Urza's Tower, add {C}{C} instead.
|
A:AB$ Mana | Cost$ T | Produced$ C | Amount$ UrzaAmount | References$ UrzaAmount | SpellDescription$ Add {C}. If you control an Urza's Mine and an Urza's Tower, add {C}{C} instead.
|
||||||
|
SVar:UrzaAmount:Count$UrzaLands.2.1
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/urzas_power_plant.jpg
|
|
||||||
Oracle:{T}: Add {C}. If you control an Urza's Mine and an Urza's Tower, add {C}{C} instead.
|
Oracle:{T}: Add {C}. If you control an Urza's Mine and an Urza's Tower, add {C}{C} instead.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
Name:Urza's Tower
|
Name:Urza's Tower
|
||||||
ManaCost:no cost
|
ManaCost:no cost
|
||||||
Types:Land Urza's Tower
|
Types:Land Urza's Tower
|
||||||
A:AB$ Mana | Cost$ T | Produced$ C | Bonus$ UrzaLands | BonusProduced$ 2 | SpellDescription$ Add {C}. If you control an Urza's Mine and an Urza's Power-Plant, add {C}{C}{C} instead.
|
A:AB$ Mana | Cost$ T | Produced$ C | Amount$ UrzaAmount | References$ UrzaAmount | SpellDescription$ Add {C}. If you control an Urza's Mine and an Urza's Power-Plant, add {C}{C}{C} instead.
|
||||||
|
SVar:UrzaAmount:Count$UrzaLands.3.1
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/urzas_tower.jpg
|
|
||||||
Oracle:{T}: Add {C}. If you control an Urza's Mine and an Urza's Power-Plant, add {C}{C}{C} instead.
|
Oracle:{T}: Add {C}. If you control an Urza's Mine and an Urza's Power-Plant, add {C}{C}{C} instead.
|
||||||
|
|||||||
6
forge-gui/res/cardsfolder/upcoming/piracy.txt
Normal file
6
forge-gui/res/cardsfolder/upcoming/piracy.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Name:Piracy
|
||||||
|
ManaCost:U U
|
||||||
|
Types:Sorcery
|
||||||
|
A:SP$ Effect | Cost$ U U | StaticAbilities$ STPiracy | AINoRecursiveCheck$ True | SpellDescription$ Until end of turn, you may tap lands you don’t control for mana. Spend this mana only to cast spells.
|
||||||
|
SVar:STPiracy:Mode$ Continuous | Affected$ You | AddKeyword$ Piracy | Description$ Until end of turn, you may tap lands you don’t control for mana. Spend this mana only to cast spells.
|
||||||
|
Oracle:Until end of turn, you may tap lands you don’t control for mana. Spend this mana only to cast spells.
|
||||||
@@ -3,8 +3,8 @@ ManaCost:6 G G
|
|||||||
Types:Legendary Creature Praetor
|
Types:Legendary Creature Praetor
|
||||||
PT:7/6
|
PT:7/6
|
||||||
K:Trample
|
K:Trample
|
||||||
T:Mode$ TapsForMana | ValidCard$ Land.YouCtrl | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a land for mana, add one mana of any type that land produced.
|
T:Mode$ TapsForMana | ValidCard$ Land | Activator$ You | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a land for mana, add one mana of any type that land produced.
|
||||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ You
|
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ You
|
||||||
T:Mode$ TapsForMana | ValidCard$ Land.OppCtrl | Execute$ TrigPump | TriggerZones$ Battlefield | TriggerDescription$ Whenever an opponent taps a land for mana, that land doesn't untap during its controller's next untap step.
|
T:Mode$ TapsForMana | ValidCard$ Land.OppCtrl | Execute$ TrigPump | TriggerZones$ Battlefield | TriggerDescription$ Whenever an opponent taps a land for mana, that land doesn't untap during its controller's next untap step.
|
||||||
SVar:TrigPump:DB$ Pump | Defined$ TriggeredCard | Permanent$ True | KW$ HIDDEN This card doesn't untap during your next untap step.
|
SVar:TrigPump:DB$ Pump | Defined$ TriggeredCard | Permanent$ True | KW$ HIDDEN This card doesn't untap during your next untap step.
|
||||||
Oracle:Trample\nWhenever you tap a land for mana, add one mana of any type that land produced.\nWhenever an opponent taps a land for mana, that land doesn't untap during its controller's next untap step.
|
Oracle:Trample\nWhenever you tap a land for mana, add one mana of any type that land produced.\nWhenever an opponent taps a land for mana, that land doesn't untap during its controller's next untap step.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Name:Winter's Night
|
|||||||
ManaCost:R G W
|
ManaCost:R G W
|
||||||
Types:World Enchantment
|
Types:World Enchantment
|
||||||
T:Mode$ TapsForMana | ValidCard$ Land.Snow | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever a player taps a snow land for mana, that player adds one mana of any type that land produced. That land doesn't untap during its controller's next untap step.
|
T:Mode$ TapsForMana | ValidCard$ Land.Snow | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever a player taps a snow land for mana, that player adds one mana of any type that land produced. That land doesn't untap during its controller's next untap step.
|
||||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer | SubAbility$ DBPump
|
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ TriggeredActivator | SubAbility$ DBPump
|
||||||
SVar:DBPump:DB$ Pump | Defined$ TriggeredCard | Permanent$ True | KW$ HIDDEN This card doesn't untap during your next untap step.
|
SVar:DBPump:DB$ Pump | Defined$ TriggeredCard | Permanent$ True | KW$ HIDDEN This card doesn't untap during your next untap step.
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
Name:Zendikar Resurgent
|
Name:Zendikar Resurgent
|
||||||
ManaCost:5 G G
|
ManaCost:5 G G
|
||||||
Types:Enchantment
|
Types:Enchantment
|
||||||
T:Mode$ TapsForMana | ValidCard$ Land.YouCtrl | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a land for mana, add one mana of any type that land produced. (The types of mana are white, blue, black, red, green, and colorless.)
|
T:Mode$ TapsForMana | ValidCard$ Land | Activator$ You | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a land for mana, add one mana of any type that land produced. (The types of mana are white, blue, black, red, green, and colorless.)
|
||||||
SVar:TrigMana:DB$ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ You
|
||||||
T:Mode$ SpellCast | ValidCard$ Creature | ValidActivatingPlayer$ You | Execute$ TrigDraw | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast a creature spell, draw a card.
|
T:Mode$ SpellCast | ValidCard$ Creature | ValidActivatingPlayer$ You | Execute$ TrigDraw | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast a creature spell, draw a card.
|
||||||
SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 1
|
SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 1
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/zendikar_resurgent.jpg
|
|
||||||
Oracle:Whenever you tap a land for mana, add one mana of any type that land produced. (The types of mana are white, blue, black, red, green, and colorless.)\nWhenever you cast a creature spell, draw a card.
|
Oracle:Whenever you tap a land for mana, add one mana of any type that land produced. (The types of mana are white, blue, black, red, green, and colorless.)\nWhenever you cast a creature spell, draw a card.
|
||||||
|
|||||||
@@ -3,6 +3,5 @@ ManaCost:3 R G
|
|||||||
Types:Creature Beast
|
Types:Creature Beast
|
||||||
PT:7/5
|
PT:7/5
|
||||||
T:Mode$ TapsForMana | ValidCard$ Land | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
T:Mode$ TapsForMana | ValidCard$ Land | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
||||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ TriggeredActivator
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/zhur_taa_ancient.jpg
|
|
||||||
Oracle:Whenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
Oracle:Whenever a player taps a land for mana, that player adds one mana of any type that land produced.
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ package forge.match.input;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import forge.GuiBase;
|
import forge.GuiBase;
|
||||||
import forge.game.GameActionUtil;
|
|
||||||
import forge.game.ability.AbilityKey;
|
|
||||||
import forge.game.spellability.SpellAbilityView;
|
import forge.game.spellability.SpellAbilityView;
|
||||||
import forge.util.TextUtil;
|
import forge.util.TextUtil;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@@ -18,15 +16,11 @@ import forge.card.ColorSet;
|
|||||||
import forge.card.MagicColor;
|
import forge.card.MagicColor;
|
||||||
import forge.card.mana.ManaAtom;
|
import forge.card.mana.ManaAtom;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.ability.ApiType;
|
import forge.game.GameActionUtil;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardUtil;
|
|
||||||
import forge.game.mana.ManaCostBeingPaid;
|
import forge.game.mana.ManaCostBeingPaid;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.player.PlayerView;
|
import forge.game.player.PlayerView;
|
||||||
import forge.game.replacement.ReplacementEffect;
|
|
||||||
import forge.game.replacement.ReplacementType;
|
|
||||||
import forge.game.spellability.AbilityManaPart;
|
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.player.HumanPlay;
|
import forge.player.HumanPlay;
|
||||||
import forge.player.PlayerControllerHuman;
|
import forge.player.PlayerControllerHuman;
|
||||||
@@ -77,7 +71,7 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
|||||||
// Mobile Forge allows to tap cards underneath the current card even if the current one is tapped
|
// Mobile Forge allows to tap cards underneath the current card even if the current one is tapped
|
||||||
if (otherCardsToSelect != null) {
|
if (otherCardsToSelect != null) {
|
||||||
for (Card c : otherCardsToSelect) {
|
for (Card c : otherCardsToSelect) {
|
||||||
for (SpellAbility sa : c.getManaAbilities()) {
|
for (SpellAbility sa : getAllManaAbilities(c)) {
|
||||||
if (sa.canPlay()) {
|
if (sa.canPlay()) {
|
||||||
delaySelectCards.add(c);
|
delaySelectCards.add(c);
|
||||||
break;
|
break;
|
||||||
@@ -85,16 +79,17 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!card.getManaAbilities().isEmpty() && activateManaAbility(card)) {
|
if (!getAllManaAbilities(card).isEmpty() && activateManaAbility(card)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return activateDelayedCard();
|
return activateDelayedCard();
|
||||||
} else {
|
} else {
|
||||||
|
List<SpellAbility> manaAbilities = getAllManaAbilities(card);
|
||||||
// Desktop Forge floating menu functionality
|
// Desktop Forge floating menu functionality
|
||||||
if (card.getManaAbilities().size() == 1) {
|
if (manaAbilities.size() == 1) {
|
||||||
activateManaAbility(card, card.getManaAbilities().get(0));
|
activateManaAbility(card, manaAbilities.get(0));
|
||||||
} else {
|
} else {
|
||||||
SpellAbility spellAbility = getController().getAbilityToPlay(card, Lists.newArrayList(card.getManaAbilities()), triggerEvent);
|
SpellAbility spellAbility = getController().getAbilityToPlay(card, manaAbilities, triggerEvent);
|
||||||
if (spellAbility != null) {
|
if (spellAbility != null) {
|
||||||
activateManaAbility(card, spellAbility);
|
activateManaAbility(card, spellAbility);
|
||||||
}
|
}
|
||||||
@@ -103,9 +98,29 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected List<SpellAbility> getAllManaAbilities(Card card) {
|
||||||
|
List<SpellAbility> result = Lists.newArrayList();
|
||||||
|
for (SpellAbility sa : card.getManaAbilities()) {
|
||||||
|
result.add(sa);
|
||||||
|
result.addAll(GameActionUtil.getAlternativeCosts(sa, player));
|
||||||
|
}
|
||||||
|
final Collection<SpellAbility> toRemove = Lists.newArrayListWithCapacity(result.size());
|
||||||
|
for (final SpellAbility sa : result) {
|
||||||
|
sa.setActivatingPlayer(player);
|
||||||
|
// fix things like retrace
|
||||||
|
// check only if SA can't be cast normally
|
||||||
|
if (sa.canPlay(true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
toRemove.add(sa);
|
||||||
|
}
|
||||||
|
result.removeAll(toRemove);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getActivateAction(Card card) {
|
public String getActivateAction(Card card) {
|
||||||
for (SpellAbility sa : card.getManaAbilities()) {
|
for (SpellAbility sa : getAllManaAbilities(card)) {
|
||||||
if (sa.canPlay()) {
|
if (sa.canPlay()) {
|
||||||
return "pay mana with card";
|
return "pay mana with card";
|
||||||
}
|
}
|
||||||
@@ -135,6 +150,7 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public List<SpellAbility> getUsefulManaAbilities(Card card) {
|
public List<SpellAbility> getUsefulManaAbilities(Card card) {
|
||||||
List<SpellAbility> abilities = new ArrayList<>();
|
List<SpellAbility> abilities = new ArrayList<>();
|
||||||
|
|
||||||
@@ -160,14 +176,9 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
|||||||
return abilities;
|
return abilities;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (SpellAbility ma : card.getManaAbilities()) {
|
for (SpellAbility ma : getAllManaAbilities(card)) {
|
||||||
ma.setActivatingPlayer(player);
|
ma.setActivatingPlayer(player);
|
||||||
AbilityManaPart m = ma.getManaPartRecursive();
|
if (ma.isManaAbilityFor(saPaidFor, colorCanUse))
|
||||||
if (m == null || !ma.canPlay()) { continue; }
|
|
||||||
if (!abilityProducesManaColor(ma, m, colorCanUse)) { continue; }
|
|
||||||
if (ma.isAbility() && ma.getRestrictions().isInstantSpeed()) { continue; }
|
|
||||||
if (!m.meetsManaRestrictions(saPaidFor)) { continue; }
|
|
||||||
|
|
||||||
abilities.add(ma);
|
abilities.add(ma);
|
||||||
}
|
}
|
||||||
return abilities;
|
return abilities;
|
||||||
@@ -191,9 +202,6 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make sure computer's lands aren't selected
|
// make sure computer's lands aren't selected
|
||||||
if (card.getController() != player) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte colorCanUse = 0;
|
byte colorCanUse = 0;
|
||||||
byte colorNeeded = 0;
|
byte colorNeeded = 0;
|
||||||
@@ -210,6 +218,8 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final SpellAbility chosen;
|
||||||
|
if (chosenAbility == null) {
|
||||||
HashMap<SpellAbilityView, SpellAbility> abilitiesMap = new HashMap<>();
|
HashMap<SpellAbilityView, SpellAbility> abilitiesMap = new HashMap<>();
|
||||||
// you can't remove unneeded abilities inside a for (am:abilities) loop :(
|
// you can't remove unneeded abilities inside a for (am:abilities) loop :(
|
||||||
|
|
||||||
@@ -220,17 +230,13 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
|||||||
|
|
||||||
boolean guessAbilityWithRequiredColors = true;
|
boolean guessAbilityWithRequiredColors = true;
|
||||||
int amountOfMana = -1;
|
int amountOfMana = -1;
|
||||||
for (SpellAbility ma : card.getManaAbilities()) {
|
for (SpellAbility ma : getAllManaAbilities(card)) {
|
||||||
ma.setActivatingPlayer(player);
|
ma.setActivatingPlayer(player);
|
||||||
|
|
||||||
AbilityManaPart m = ma.getManaPartRecursive();
|
if (!ma.isManaAbilityFor(saPaidFor, colorCanUse)) { continue; }
|
||||||
if (m == null || !ma.canPlay()) { continue; }
|
|
||||||
if (!abilityProducesManaColor(ma, m, colorCanUse)) { continue; }
|
|
||||||
if (ma.isAbility() && ma.getRestrictions().isInstantSpeed()) { continue; }
|
|
||||||
if (!m.meetsManaRestrictions(saPaidFor)) { continue; }
|
|
||||||
|
|
||||||
// If Mana Abilities produce differing amounts of mana, let the player choose
|
// If Mana Abilities produce differing amounts of mana, let the player choose
|
||||||
int maAmount = GameActionUtil.amountOfManaGenerated(ma, true);
|
int maAmount = ma.totalAmountOfManaGenerated(saPaidFor, true);
|
||||||
if (amountOfMana == -1) {
|
if (amountOfMana == -1) {
|
||||||
amountOfMana = maAmount;
|
amountOfMana = maAmount;
|
||||||
} else {
|
} else {
|
||||||
@@ -242,12 +248,13 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
|||||||
abilitiesMap.put(ma.getView(), ma);
|
abilitiesMap.put(ma.getView(), ma);
|
||||||
|
|
||||||
// skip express mana if the ability is not undoable or reusable
|
// skip express mana if the ability is not undoable or reusable
|
||||||
if (!ma.isUndoable() || !ma.getPayCosts().isRenewableResource() || ma.getSubAbility() != null) {
|
if (!ma.isUndoable() || !ma.getPayCosts().isRenewableResource() || ma.getSubAbility() != null
|
||||||
|
|| ma.isManaCannotCounter(saPaidFor)) {
|
||||||
guessAbilityWithRequiredColors = false;
|
guessAbilityWithRequiredColors = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (abilitiesMap.isEmpty() || (chosenAbility != null && !abilitiesMap.containsKey(chosenAbility.getView()))) {
|
if (abilitiesMap.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +276,6 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean choice = true;
|
boolean choice = true;
|
||||||
boolean isPayingGeneric = false;
|
|
||||||
if (guessAbilityWithRequiredColors) {
|
if (guessAbilityWithRequiredColors) {
|
||||||
// express Mana Choice
|
// express Mana Choice
|
||||||
if (colorNeeded == 0) {
|
if (colorNeeded == 0) {
|
||||||
@@ -277,12 +283,11 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
|||||||
//avoid unnecessary prompt by pretending we need White
|
//avoid unnecessary prompt by pretending we need White
|
||||||
//for the sake of "Add one mana of any color" effects
|
//for the sake of "Add one mana of any color" effects
|
||||||
colorNeeded = MagicColor.WHITE;
|
colorNeeded = MagicColor.WHITE;
|
||||||
isPayingGeneric = true; // for further processing
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final HashMap<SpellAbilityView, SpellAbility> colorMatches = new HashMap<>();
|
final HashMap<SpellAbilityView, SpellAbility> colorMatches = new HashMap<>();
|
||||||
for (SpellAbility sa : abilitiesMap.values()) {
|
for (SpellAbility sa : abilitiesMap.values()) {
|
||||||
if (abilityProducesManaColor(sa, sa.getManaPartRecursive(), colorNeeded)) {
|
if (sa.isManaAbilityFor(saPaidFor, colorNeeded)) {
|
||||||
colorMatches.put(sa.getView(), sa);
|
colorMatches.put(sa.getView(), sa);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -299,13 +304,6 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exceptions for cards that have conditional abilities which are better handled manually
|
|
||||||
if (card.getName().equals("Cavern of Souls") && isPayingGeneric) {
|
|
||||||
choice = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
final SpellAbility chosen;
|
|
||||||
if (chosenAbility == null) {
|
|
||||||
ArrayList<SpellAbilityView> choices = new ArrayList<>(abilitiesMap.keySet());
|
ArrayList<SpellAbilityView> choices = new ArrayList<>(abilitiesMap.keySet());
|
||||||
chosen = abilitiesMap.size() > 1 && choice ? abilitiesMap.get(getController().getGui().one(Localizer.getInstance().getMessage("lblChooseManaAbility"), choices)) : abilitiesMap.get(choices.get(0));
|
chosen = abilitiesMap.size() > 1 && choice ? abilitiesMap.get(getController().getGui().one(Localizer.getInstance().getMessage("lblChooseManaAbility"), choices)) : abilitiesMap.get(choices.get(0));
|
||||||
} else {
|
} else {
|
||||||
@@ -317,14 +315,13 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
|||||||
// Filter the colors for the express choice so that only actually producible colors can be chosen
|
// Filter the colors for the express choice so that only actually producible colors can be chosen
|
||||||
int producedColorMask = 0;
|
int producedColorMask = 0;
|
||||||
for (final byte color : ManaAtom.MANATYPES) {
|
for (final byte color : ManaAtom.MANATYPES) {
|
||||||
if (chosen.getManaPartRecursive().getOrigProduced().contains(MagicColor.toShortString(color))
|
if (chosen.canProduce(MagicColor.toShortString(color)) && colors.hasAnyColor(color)) {
|
||||||
&& colors.hasAnyColor(color)) {
|
|
||||||
producedColorMask |= color;
|
producedColorMask |= color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ColorSet producedAndNeededColors = ColorSet.fromMask(producedColorMask);
|
ColorSet producedAndNeededColors = ColorSet.fromMask(producedColorMask);
|
||||||
|
|
||||||
chosen.getManaPartRecursive().setExpressChoice(producedAndNeededColors);
|
chosen.setManaExpressChoice(producedAndNeededColors);
|
||||||
|
|
||||||
// System.out.println("Chosen sa=" + chosen + " of " + chosen.getHostCard() + " to pay mana");
|
// System.out.println("Chosen sa=" + chosen + " of " + chosen.getHostCard() + " to pay mana");
|
||||||
|
|
||||||
@@ -344,62 +341,6 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean abilityProducesManaColor(final SpellAbility am, AbilityManaPart m, final byte neededColor) {
|
|
||||||
if (0 != (neededColor & ManaAtom.GENERIC)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m.isAnyMana()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for produce mana replacement effects - they mess this up, so just use the mana ability
|
|
||||||
final Card source = am.getHostCard();
|
|
||||||
final Player activator = am.getActivatingPlayer();
|
|
||||||
final Game g = source.getGame();
|
|
||||||
final Map<AbilityKey, Object> repParams = AbilityKey.newMap();
|
|
||||||
repParams.put(AbilityKey.Mana, m.getOrigProduced());
|
|
||||||
repParams.put(AbilityKey.Affected, source);
|
|
||||||
repParams.put(AbilityKey.Player, activator);
|
|
||||||
repParams.put(AbilityKey.AbilityMana, am);
|
|
||||||
|
|
||||||
for (final Player p : g.getPlayers()) {
|
|
||||||
for (final Card crd : p.getAllCards()) {
|
|
||||||
for (final ReplacementEffect replacementEffect : crd.getReplacementEffects()) {
|
|
||||||
if (replacementEffect.requirementsCheck(g)
|
|
||||||
&& replacementEffect.getMode() == ReplacementType.ProduceMana
|
|
||||||
&& replacementEffect.canReplace(repParams)
|
|
||||||
&& replacementEffect.hasParam("ManaReplacement")
|
|
||||||
&& replacementEffect.zonesCheck(g.getZoneOf(crd))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (am.getApi() == ApiType.ManaReflected) {
|
|
||||||
final Iterable<String> reflectableColors = CardUtil.getReflectableManaColors(am);
|
|
||||||
for (final String color : reflectableColors) {
|
|
||||||
if (0 != (neededColor & ManaAtom.fromName(color))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// treat special mana if it always can be paid
|
|
||||||
if (m.isSpecialMana()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
String colorsProduced = m.isComboMana() ? m.getComboColors() : m.mana();
|
|
||||||
for (final String color : colorsProduced.split(" ")) {
|
|
||||||
if (0 != (neededColor & ManaAtom.fromName(color))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isAlreadyPaid() {
|
protected boolean isAlreadyPaid() {
|
||||||
if (manaCost.isPaid()) {
|
if (manaCost.isPaid()) {
|
||||||
bPaid = true;
|
bPaid = true;
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import forge.game.event.GameEventTokenCreated;
|
|||||||
import forge.game.event.GameEventTurnEnded;
|
import forge.game.event.GameEventTurnEnded;
|
||||||
import forge.game.event.GameEventZone;
|
import forge.game.event.GameEventZone;
|
||||||
import forge.game.event.IGameEventVisitor;
|
import forge.game.event.IGameEventVisitor;
|
||||||
|
import forge.game.spellability.AbilityManaPart;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.util.TextUtil;
|
import forge.util.TextUtil;
|
||||||
@@ -208,11 +209,14 @@ public class EventVisualizer extends IGameEventVisitor.Base<SoundEffectType> imp
|
|||||||
// I want to get all real colors this land can produce - no interest in colorless or devoid
|
// I want to get all real colors this land can produce - no interest in colorless or devoid
|
||||||
StringBuilder fullManaColors = new StringBuilder();
|
StringBuilder fullManaColors = new StringBuilder();
|
||||||
for (final SpellAbility sa : land.getManaAbilities()) {
|
for (final SpellAbility sa : land.getManaAbilities()) {
|
||||||
String currManaColor = sa.getManaPartRecursive().getOrigProduced();
|
for (AbilityManaPart mp : sa.getAllManaParts()) {
|
||||||
|
String currManaColor = mp.getOrigProduced();
|
||||||
if(!"C".equals(currManaColor)) {
|
if(!"C".equals(currManaColor)) {
|
||||||
fullManaColors.append(currManaColor);
|
fullManaColors.append(currManaColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
// No interest if "colors together" or "alternative colors" - only interested in colors themselves
|
// No interest if "colors together" or "alternative colors" - only interested in colors themselves
|
||||||
fullManaColors = new StringBuilder(TextUtil.fastReplace(fullManaColors.toString()," ", ""));
|
fullManaColors = new StringBuilder(TextUtil.fastReplace(fullManaColors.toString()," ", ""));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user