mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 19:58:00 +00:00
Merge remote-tracking branch 'core/master'
This commit is contained in:
@@ -429,8 +429,7 @@ public class AiController {
|
||||
byte color = MagicColor.fromName(c);
|
||||
for (Card land : landList) {
|
||||
for (final SpellAbility m : ComputerUtilMana.getAIPlayableMana(land)) {
|
||||
AbilityManaPart mp = m.getManaPart();
|
||||
if (mp.canProduce(MagicColor.toShortString(color), m)) {
|
||||
if (m.canProduce(MagicColor.toShortString(color))) {
|
||||
return land;
|
||||
}
|
||||
}
|
||||
@@ -483,8 +482,7 @@ public class AiController {
|
||||
return land;
|
||||
}
|
||||
for (final SpellAbility m : ComputerUtilMana.getAIPlayableMana(land)) {
|
||||
AbilityManaPart mp = m.getManaPart();
|
||||
if (mp.canProduce(MagicColor.toShortString(color), m)) {
|
||||
if (m.canProduce(MagicColor.toShortString(color))) {
|
||||
return land;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2075,9 +2075,8 @@ public class ComputerUtil {
|
||||
|
||||
for (Card c : lands) {
|
||||
for (SpellAbility sa : c.getManaAbilities()) {
|
||||
AbilityManaPart abmana = sa.getManaPart();
|
||||
for (byte col : MagicColor.WUBRG) {
|
||||
if (abmana.canProduce(MagicColor.toLongString(col))) {
|
||||
if (sa.canProduce(MagicColor.toLongString(col))) {
|
||||
numProducers.get(col).add(c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,10 @@ import forge.card.mana.ManaAtom;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostParser;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.game.CardTraitPredicates;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameActionUtil;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.ability.*;
|
||||
import forge.game.card.*;
|
||||
import forge.game.combat.CombatUtil;
|
||||
import forge.game.cost.*;
|
||||
@@ -25,10 +24,13 @@ import forge.game.phase.PhaseType;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerPredicates;
|
||||
import forge.game.replacement.ReplacementEffect;
|
||||
import forge.game.replacement.ReplacementLayer;
|
||||
import forge.game.replacement.ReplacementType;
|
||||
import forge.game.spellability.AbilityManaPart;
|
||||
import forge.game.spellability.AbilitySub;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.trigger.Trigger;
|
||||
import forge.game.trigger.TriggerType;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.MyRandom;
|
||||
import forge.util.TextUtil;
|
||||
@@ -52,17 +54,17 @@ public class ComputerUtilMana {
|
||||
public static boolean canPayManaCost(final SpellAbility sa, final Player ai, final int extraMana) {
|
||||
return payManaCost(sa, ai, true, extraMana, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the number of colors used for payment for Converge
|
||||
*/
|
||||
public static int getConvergeCount(final SpellAbility sa, final Player ai) {
|
||||
ManaCostBeingPaid cost = ComputerUtilMana.calculateManaCost(sa, true, 0);
|
||||
if (payManaCost(cost, sa, ai, true, true)) {
|
||||
return cost.getSunburst();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
ManaCostBeingPaid cost = ComputerUtilMana.calculateManaCost(sa, true, 0);
|
||||
if (payManaCost(cost, sa, ai, true, true)) {
|
||||
return cost.getSunburst();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Does not check if mana sources can be used right now, just checks for potential chance.
|
||||
@@ -124,7 +126,7 @@ public class ComputerUtilMana {
|
||||
|
||||
for (final ManaCostShard shard : manaAbilityMap.keySet()) {
|
||||
for (SpellAbility ability : manaAbilityMap.get(shard)) {
|
||||
final Card hostCard = ability.getHostCard();
|
||||
final Card hostCard = ability.getHostCard();
|
||||
if (!manaCardMap.containsKey(hostCard)) {
|
||||
manaCardMap.put(hostCard, scoreManaProducingCard(hostCard));
|
||||
orderedCards.add(hostCard);
|
||||
@@ -238,7 +240,7 @@ public class ComputerUtilMana {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static SpellAbility chooseManaAbility(ManaCostBeingPaid cost, SpellAbility sa, Player ai, ManaCostShard toPay,
|
||||
Collection<SpellAbility> saList, boolean checkCosts) {
|
||||
for (final SpellAbility ma : saList) {
|
||||
@@ -316,7 +318,191 @@ public class ComputerUtilMana {
|
||||
}
|
||||
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) {
|
||||
CardCollection manaSources = new CardCollection();
|
||||
|
||||
@@ -392,29 +578,19 @@ public class ComputerUtilMana {
|
||||
manaSources.add(saPayment.getHostCard());
|
||||
setExpressColorChoice(sa, ai, cost, toPay, saPayment);
|
||||
|
||||
String manaProduced = toPay.isSnow() ? "S" : GameActionUtil.generatedMana(saPayment);
|
||||
manaProduced = AbilityManaPart.applyManaReplacement(saPayment, manaProduced);
|
||||
String manaProduced = predictManafromSpellAbility(saPayment, ai, toPay);
|
||||
|
||||
//System.out.println(manaProduced);
|
||||
payMultipleMana(cost, manaProduced, ai);
|
||||
|
||||
// remove from available lists
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
Iterables.removeIf(sourcesForShards.values(), CardTraitPredicates.isHostCard(saPayment.getHostCard()));
|
||||
}
|
||||
|
||||
handleOfferingsAI(sa, true, cost.isPaid());
|
||||
|
||||
refundMana(manaSpentToPay, ai, sa);
|
||||
|
||||
|
||||
return manaSources;
|
||||
} // getManaSourcesToPayCost()
|
||||
|
||||
@@ -427,14 +603,14 @@ public class ComputerUtilMana {
|
||||
List<SpellAbility> paymentList = Lists.newArrayList();
|
||||
|
||||
if (payManaCostFromPool(cost, sa, ai, test, manaSpentToPay)) {
|
||||
return true; // paid all from floating mana
|
||||
return true; // paid all from floating mana
|
||||
}
|
||||
|
||||
|
||||
boolean hasConverge = sa.getHostCard().hasConverge();
|
||||
ListMultimap<ManaCostShard, SpellAbility> sourcesForShards = getSourcesForShards(cost, sa, ai, test,
|
||||
checkPlayable, manaSpentToPay, hasConverge);
|
||||
checkPlayable, manaSpentToPay, hasConverge);
|
||||
if (sourcesForShards == null && !purePhyrexian) {
|
||||
return false; // no mana abilities to use for paying
|
||||
return false; // no mana abilities to use for paying
|
||||
}
|
||||
|
||||
final ManaPool manapool = ai.getManaPool();
|
||||
@@ -443,26 +619,43 @@ public class ComputerUtilMana {
|
||||
|
||||
// Loop over mana needed
|
||||
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);
|
||||
|
||||
boolean lifeInsteadOfBlack = toPay.isBlack() && ai.hasKeyword("PayLifeInsteadOf:B");
|
||||
|
||||
Collection<SpellAbility> saList = null;
|
||||
if (hasConverge &&
|
||||
(toPay == ManaCostShard.GENERIC || toPay == ManaCostShard.X)) {
|
||||
final int unpaidColors = cost.getUnpaidColors() + cost.getColorsPaid() ^ ManaCostShard.COLORS_SUPERPOSITION;
|
||||
for (final byte b : ColorSet.fromMask(unpaidColors)) { // try and pay other colors for converge
|
||||
final ManaCostShard shard = ManaCostShard.valueOf(b);
|
||||
saList = sourcesForShards.get(shard);
|
||||
if (saList != null && !saList.isEmpty()) {
|
||||
toPay = shard;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (saList == null || saList.isEmpty()) { // failed to converge, revert to paying generic
|
||||
saList = sourcesForShards.get(toPay);
|
||||
hasConverge = false;
|
||||
}
|
||||
if (hasConverge &&
|
||||
(toPay == ManaCostShard.GENERIC || toPay == ManaCostShard.X)) {
|
||||
final int unpaidColors = cost.getUnpaidColors() + cost.getColorsPaid() ^ ManaCostShard.COLORS_SUPERPOSITION;
|
||||
for (final byte b : ColorSet.fromMask(unpaidColors)) {
|
||||
// try and pay other colors for converge
|
||||
final ManaCostShard shard = ManaCostShard.valueOf(b);
|
||||
saList = sourcesForShards.get(shard);
|
||||
if (saList != null && !saList.isEmpty()) {
|
||||
toPay = shard;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (saList == null || saList.isEmpty()) {
|
||||
// failed to converge, revert to paying generic
|
||||
saList = sourcesForShards.get(toPay);
|
||||
hasConverge = false;
|
||||
}
|
||||
} else {
|
||||
if (!(sourcesForShards == null && purePhyrexian)) {
|
||||
saList = sourcesForShards.get(toPay);
|
||||
@@ -529,33 +722,23 @@ public class ComputerUtilMana {
|
||||
setExpressColorChoice(sa, ai, cost, toPay, saPayment);
|
||||
|
||||
if (test) {
|
||||
// Check energy when testing
|
||||
CostPayEnergy energyCost = saPayment.getPayCosts().getCostEnergy();
|
||||
if (energyCost != null) {
|
||||
testEnergyPool -= Integer.parseInt(energyCost.getAmount());
|
||||
if (testEnergyPool < 0) {
|
||||
// Can't pay energy cost
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Check energy when testing
|
||||
CostPayEnergy energyCost = saPayment.getPayCosts().getCostEnergy();
|
||||
if (energyCost != null) {
|
||||
testEnergyPool -= Integer.parseInt(energyCost.getAmount());
|
||||
if (testEnergyPool < 0) {
|
||||
// Can't pay energy cost
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String manaProduced = toPay.isSnow() ? "S" : GameActionUtil.generatedMana(saPayment);
|
||||
manaProduced = AbilityManaPart.applyManaReplacement(saPayment, manaProduced);
|
||||
//System.out.println(manaProduced);
|
||||
String manaProduced = predictManafromSpellAbility(saPayment, ai, toPay);
|
||||
|
||||
// System.out.println(manaProduced);
|
||||
payMultipleMana(cost, manaProduced, ai);
|
||||
|
||||
// remove from available lists
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
Iterables.removeIf(sourcesForShards.values(), CardTraitPredicates.isHostCard(saPayment.getHostCard()));
|
||||
}
|
||||
else {
|
||||
final CostPayment pay = new CostPayment(saPayment.getPayCosts(), saPayment);
|
||||
@@ -570,20 +753,10 @@ public class ComputerUtilMana {
|
||||
|
||||
// no need to remove abilities from resource map,
|
||||
// once their costs are paid and consume resources, they can not be used again
|
||||
|
||||
if (hasConverge) { // hack to prevent converge re-using sources
|
||||
// remove from available lists
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
||||
if (hasConverge) {
|
||||
// hack to prevent converge re-using sources
|
||||
Iterables.removeIf(sourcesForShards.values(), CardTraitPredicates.isHostCard(saPayment.getHostCard()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -596,15 +769,6 @@ public class ComputerUtilMana {
|
||||
// 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
|
||||
if (!cost.isPaid()) {
|
||||
refundMana(manaSpentToPay, ai, sa);
|
||||
@@ -633,15 +797,16 @@ public class ComputerUtilMana {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a mapping between the required mana shards and the available spell abilities to pay for them
|
||||
*/
|
||||
private static ListMultimap<ManaCostShard, SpellAbility> getSourcesForShards(final ManaCostBeingPaid cost,
|
||||
final SpellAbility sa, final Player ai, final boolean test, final boolean checkPlayable,
|
||||
List<Mana> manaSpentToPay, final boolean hasConverge) {
|
||||
// arrange all mana abilities by color produced.
|
||||
/**
|
||||
* Creates a mapping between the required mana shards and the available spell abilities to pay for them
|
||||
*/
|
||||
private static ListMultimap<ManaCostShard, SpellAbility> getSourcesForShards(final ManaCostBeingPaid cost,
|
||||
final SpellAbility sa, final Player ai, final boolean test, final boolean checkPlayable,
|
||||
List<Mana> manaSpentToPay, final boolean hasConverge) {
|
||||
// arrange all mana abilities by color produced.
|
||||
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);
|
||||
handleOfferingsAI(sa, test, cost.isPaid());
|
||||
return null;
|
||||
@@ -652,25 +817,26 @@ public class ComputerUtilMana {
|
||||
|
||||
// select which abilities may be used for each shard
|
||||
ListMultimap<ManaCostShard, SpellAbility> sourcesForShards = ComputerUtilMana.groupAndOrderToPayShards(ai, manaAbilityMap, cost);
|
||||
if (hasConverge) { // add extra colors for paying converge
|
||||
final int unpaidColors = cost.getUnpaidColors() + cost.getColorsPaid() ^ ManaCostShard.COLORS_SUPERPOSITION;
|
||||
for (final byte b : ColorSet.fromMask(unpaidColors)) {
|
||||
final ManaCostShard shard = ManaCostShard.valueOf(b);
|
||||
if (!sourcesForShards.containsKey(shard)) {
|
||||
if (ai.getManaPool().canPayForShardWithColor(shard, b)) {
|
||||
if (hasConverge) {
|
||||
// add extra colors for paying converge
|
||||
final int unpaidColors = cost.getUnpaidColors() + cost.getColorsPaid() ^ ManaCostShard.COLORS_SUPERPOSITION;
|
||||
for (final byte b : ColorSet.fromMask(unpaidColors)) {
|
||||
final ManaCostShard shard = ManaCostShard.valueOf(b);
|
||||
if (!sourcesForShards.containsKey(shard)) {
|
||||
if (ai.getManaPool().canPayForShardWithColor(shard, b)) {
|
||||
for (SpellAbility saMana : manaAbilityMap.get((int)b)) {
|
||||
sourcesForShards.get(shard).add(sourcesForShards.get(shard).size(), saMana);
|
||||
sourcesForShards.get(shard).add(saMana);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sortManaAbilities(sourcesForShards, sa);
|
||||
if (DEBUG_MANA_PAYMENT) {
|
||||
System.out.println("DEBUG_MANA_PAYMENT: sourcesForShards = " + sourcesForShards);
|
||||
}
|
||||
return sourcesForShards;
|
||||
}
|
||||
return sourcesForShards;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given mana cost can be paid from floating mana.
|
||||
@@ -681,9 +847,9 @@ public class ComputerUtilMana {
|
||||
* @param manaSpentToPay list of mana spent
|
||||
* @return whether the floating mana is sufficient to pay the cost fully
|
||||
*/
|
||||
private static boolean payManaCostFromPool(final ManaCostBeingPaid cost, final SpellAbility sa, final Player ai,
|
||||
private static boolean payManaCostFromPool(final ManaCostBeingPaid cost, final SpellAbility sa, final Player ai,
|
||||
final boolean test, List<Mana> manaSpentToPay) {
|
||||
final boolean hasConverge = sa.getHostCard().hasConverge();
|
||||
final boolean hasConverge = sa.getHostCard().hasConverge();
|
||||
List<ManaCostShard> unpaidShards = cost.getUnpaidShards();
|
||||
Collections.sort(unpaidShards); // most difficult shards must come first
|
||||
for (ManaCostShard part : unpaidShards) {
|
||||
@@ -764,15 +930,15 @@ public class ComputerUtilMana {
|
||||
|
||||
// if we are simulating mana payment for the human controller, use the first mana available (and avoid prompting the human player)
|
||||
if (!(ai.getController() instanceof PlayerControllerAi)) {
|
||||
return manaChoices.get(0);
|
||||
return manaChoices.get(0);
|
||||
}
|
||||
|
||||
// Let them choose then
|
||||
return ai.getController().chooseManaFromPool(manaChoices);
|
||||
}
|
||||
|
||||
private static List<Pair<Mana, Integer>> selectManaToPayFor(final ManaPool manapool, final ManaCostShard shard,
|
||||
final SpellAbility saBeingPaidFor, String restriction, final byte colorsPaid) {
|
||||
private static List<Pair<Mana, Integer>> selectManaToPayFor(final ManaPool manapool, final ManaCostShard shard,
|
||||
final SpellAbility saBeingPaidFor, String restriction, final byte colorsPaid) {
|
||||
final List<Pair<Mana, Integer>> weightedOptions = new ArrayList<>();
|
||||
for (final Mana thisMana : manapool) {
|
||||
if (!manapool.canPayForShardWithColor(shard, thisMana.getColor())) {
|
||||
@@ -794,11 +960,11 @@ public class ComputerUtilMana {
|
||||
|
||||
int weight = 0;
|
||||
if (colorsPaid == -1) {
|
||||
// prefer colorless mana to spend
|
||||
weight += thisMana.isColorless() ? 5 : 0;
|
||||
// prefer colorless mana to spend
|
||||
weight += thisMana.isColorless() ? 5 : 0;
|
||||
} else {
|
||||
// get more colors for converge
|
||||
weight += (thisMana.getColor() | colorsPaid) != colorsPaid ? 5 : 0;
|
||||
// get more colors for converge
|
||||
weight += (thisMana.getColor() | colorsPaid) != colorsPaid ? 5 : 0;
|
||||
}
|
||||
|
||||
// prefer restricted mana to spend
|
||||
@@ -815,7 +981,7 @@ public class ComputerUtilMana {
|
||||
}
|
||||
return weightedOptions;
|
||||
}
|
||||
|
||||
|
||||
private static void setExpressColorChoice(final SpellAbility sa, final Player ai, ManaCostBeingPaid cost,
|
||||
ManaCostShard toPay, SpellAbility saPayment) {
|
||||
|
||||
@@ -856,7 +1022,7 @@ public class ComputerUtilMana {
|
||||
if (isManaSourceReserved(ai, sourceCard, sa)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (toPay.isSnow() && !sourceCard.isSnow()) {
|
||||
return false;
|
||||
}
|
||||
@@ -1002,7 +1168,7 @@ public class ComputerUtilMana {
|
||||
* <p>
|
||||
* getComboManaChoice.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param manaAb
|
||||
* a {@link forge.game.spellability.SpellAbility} object.
|
||||
* @param saRoot
|
||||
@@ -1026,7 +1192,7 @@ public class ComputerUtilMana {
|
||||
choice = abMana.getExpressChoice();
|
||||
abMana.clearExpressChoice();
|
||||
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);
|
||||
payMultipleMana(testCost, choice, ai);
|
||||
continue;
|
||||
@@ -1103,7 +1269,7 @@ public class ComputerUtilMana {
|
||||
}
|
||||
return unused.isEmpty() ? null : StringUtils.join(unused, ' ');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find all mana sources.
|
||||
* @param manaAbilityMap The map of SpellAbilities that produce mana.
|
||||
@@ -1135,7 +1301,7 @@ public class ComputerUtilMana {
|
||||
res.putAll(shard, manaAbilityMap.get(ManaAtom.GENERIC));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (shard == ManaCostShard.GENERIC) {
|
||||
continue;
|
||||
}
|
||||
@@ -1163,7 +1329,7 @@ public class ComputerUtilMana {
|
||||
* @return ManaCost
|
||||
*/
|
||||
public static ManaCostBeingPaid calculateManaCost(final SpellAbility sa, final boolean test, final int extraMana) {
|
||||
Card card = sa.getHostCard();
|
||||
Card card = sa.getHostCard();
|
||||
ZoneType castFromBackup = null;
|
||||
if (test && sa.isSpell()) {
|
||||
castFromBackup = card.getCastFrom();
|
||||
@@ -1196,14 +1362,14 @@ public class ComputerUtilMana {
|
||||
sa.setXManaCostPaid(manaToAdd / cost.getXcounter());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CostAdjustment.adjust(cost, sa, null, test);
|
||||
|
||||
int timesMultikicked = card.getKickerMagnitude();
|
||||
if (timesMultikicked > 0 && sa.hasParam("Announce") && sa.getParam("Announce").startsWith("Multikicker")) {
|
||||
ManaCost mkCost = sa.getMultiKickerManaCost();
|
||||
for (int i = 0; i < timesMultikicked; i++) {
|
||||
cost.addManaCost(mkCost);
|
||||
cost.addManaCost(mkCost);
|
||||
}
|
||||
sa.setSVar("Multikicker", String.valueOf(timesMultikicked));
|
||||
}
|
||||
@@ -1387,20 +1553,6 @@ public class ComputerUtilMana {
|
||||
final ListMultimap<Integer, SpellAbility> manaMap = ArrayListMultimap.create();
|
||||
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
|
||||
for (final Card sourceCard : getAvailableManaSources(ai, checkPlayable)) {
|
||||
if (DEBUG_MANA_PAYMENT) {
|
||||
@@ -1430,48 +1582,80 @@ public class ComputerUtilMana {
|
||||
}
|
||||
|
||||
manaMap.get(ManaAtom.GENERIC).add(m); // add to generic source list
|
||||
AbilityManaPart mp = m.getManaPart();
|
||||
|
||||
// setup produce mana replacement effects
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.newMap();
|
||||
repParams.put(AbilityKey.Mana, mp.getOrigProduced());
|
||||
repParams.put(AbilityKey.Affected, sourceCard);
|
||||
repParams.put(AbilityKey.Player, ai);
|
||||
repParams.put(AbilityKey.AbilityMana, m);
|
||||
SpellAbility tail = m;
|
||||
while (tail != null) {
|
||||
AbilityManaPart mp = m.getManaPart();
|
||||
if (mp != null && tail.metConditions()) {
|
||||
// TODO Replacement Check currently doesn't work for reflected colors
|
||||
|
||||
for (final ReplacementEffect replacementEffect : replacementEffects) {
|
||||
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()));
|
||||
// setup produce mana replacement effects
|
||||
String origin = mp.getOrigProduced();
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.newMap();
|
||||
repParams.put(AbilityKey.Mana, origin);
|
||||
repParams.put(AbilityKey.Affected, sourceCard);
|
||||
repParams.put(AbilityKey.Player, ai);
|
||||
repParams.put(AbilityKey.AbilityMana, m); // RootAbility
|
||||
|
||||
List<ReplacementEffect> reList = game.getReplacementHandler().getReplacementList(ReplacementType.ProduceMana, repParams, ReplacementLayer.Other);
|
||||
|
||||
if (reList.isEmpty()) {
|
||||
Set<String> reflectedColors = CardUtil.getReflectableManaColors(m);
|
||||
// find possible colors
|
||||
for (byte color : MagicColor.WUBRG) {
|
||||
if (tail.canThisProduce(MagicColor.toShortString(color)) || reflectedColors.contains(MagicColor.toLongString(color))) {
|
||||
manaMap.put((int)color, m);
|
||||
}
|
||||
}
|
||||
if (m.canThisProduce("C") || reflectedColors.contains(MagicColor.Constant.COLORLESS)) {
|
||||
manaMap.put(ManaAtom.COLORLESS, m);
|
||||
}
|
||||
} else {
|
||||
// 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 (o.hasParam("ReplaceMana")) {
|
||||
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);
|
||||
}
|
||||
} else if (o.hasParam("ReplaceColor")) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
mp.setManaReplaceType(repType);
|
||||
}
|
||||
tail = tail.getSubAbility();
|
||||
}
|
||||
|
||||
Set<String> reflectedColors = CardUtil.getReflectableManaColors(m);
|
||||
// find possible colors
|
||||
if (mp.canProduce("W", m) || reflectedColors.contains(MagicColor.Constant.WHITE)) {
|
||||
manaMap.get(ManaAtom.WHITE).add(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)) {
|
||||
manaMap.get(ManaAtom.BLACK).add(m);
|
||||
}
|
||||
if (mp.canProduce("R", m) || reflectedColors.contains(MagicColor.Constant.RED)) {
|
||||
manaMap.get(ManaAtom.RED).add(m);
|
||||
}
|
||||
if (mp.canProduce("G", m) || reflectedColors.contains(MagicColor.Constant.GREEN)) {
|
||||
manaMap.get(ManaAtom.GREEN).add(m);
|
||||
}
|
||||
if (mp.canProduce("C", m) || reflectedColors.contains(MagicColor.Constant.COLORLESS)) {
|
||||
manaMap.get(ManaAtom.COLORLESS).add(m);
|
||||
}
|
||||
if (mp.isSnow()) {
|
||||
manaMap.get(ManaAtom.IS_SNOW).add(m);
|
||||
if (m.getHostCard().isSnow()) {
|
||||
manaMap.put(ManaAtom.IS_SNOW, m);
|
||||
}
|
||||
if (DEBUG_MANA_PAYMENT) {
|
||||
System.out.println("DEBUG_MANA_PAYMENT: groupSourcesByManaColor manaMap = " + manaMap);
|
||||
@@ -1486,7 +1670,7 @@ public class ComputerUtilMana {
|
||||
* <p>
|
||||
* determineLeftoverMana.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param sa
|
||||
* a {@link forge.game.spellability.SpellAbility} object.
|
||||
* @param player
|
||||
@@ -1507,7 +1691,7 @@ public class ComputerUtilMana {
|
||||
* <p>
|
||||
* determineLeftoverMana.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param sa
|
||||
* a {@link forge.game.spellability.SpellAbility} object.
|
||||
* @param player
|
||||
@@ -1536,7 +1720,7 @@ public class ComputerUtilMana {
|
||||
* <p>
|
||||
* getAIPlayableMana.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @return a {@link java.util.List} object.
|
||||
*/
|
||||
public static List<SpellAbility> getAIPlayableMana(Card c) {
|
||||
@@ -1583,8 +1767,8 @@ public class ComputerUtilMana {
|
||||
sa.resetSacrificedAsEmerge();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Matches list of creatures to shards in mana cost for convoking.
|
||||
* @param cost cost of convoked ability
|
||||
|
||||
@@ -833,6 +833,9 @@ public class PlayerControllerAi extends PlayerController {
|
||||
|
||||
@Override
|
||||
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")
|
||||
CardCollectionView hand = player.getCardsIn(ZoneType.Hand);
|
||||
if (sa.getApi() == ApiType.Mana) {
|
||||
|
||||
@@ -111,7 +111,7 @@ public abstract class SpellAbilityAi {
|
||||
if (aiLogic.equals("CheckCondition")) {
|
||||
SpellAbility saCopy = sa.copy();
|
||||
saCopy.setActivatingPlayer(ai);
|
||||
return saCopy.getConditions().areMet(saCopy);
|
||||
return saCopy.metConditions();
|
||||
}
|
||||
|
||||
return !("Never".equals(aiLogic));
|
||||
|
||||
@@ -122,7 +122,7 @@ public class AnimateAi extends SpellAbilityAi {
|
||||
final Card source = sa.getHostCard();
|
||||
final Game game = aiPlayer.getGame();
|
||||
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?
|
||||
}
|
||||
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
|
||||
if (!activateForCost && !sa.getConditions().areMet(sa)) {
|
||||
if (!activateForCost && !sa.metConditions()) {
|
||||
final AbilitySub abSub = sa.getSubAbility();
|
||||
if (abSub != null && !sa.isWrapper() && "True".equals(source.getSVar("AIPlayForSub"))) {
|
||||
if (!abSub.getConditions().areMet(abSub)) {
|
||||
if (!abSub.metConditions()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -290,7 +290,7 @@ public class CountersPutAi extends SpellAbilityAi {
|
||||
return doMoveCounterLogic(ai, sa, ph);
|
||||
}
|
||||
|
||||
if (sa.getConditions() != null && !sa.getConditions().areMet(sa) && sa.getSubAbility() == null) {
|
||||
if (!sa.metConditions() && sa.getSubAbility() == null) {
|
||||
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
|
||||
// beneficial sub-condition
|
||||
if (!activateForCost && !sa.getConditions().areMet(sa)) {
|
||||
if (!activateForCost && !sa.metConditions()) {
|
||||
final AbilitySub abSub = sa.getSubAbility();
|
||||
if (abSub != null && !sa.isWrapper() && "True".equals(source.getSVar("AIPlayForSub"))) {
|
||||
if (!abSub.getConditions().areMet(abSub)) {
|
||||
|
||||
@@ -279,7 +279,7 @@ public class PermanentAi extends SpellAbilityAi {
|
||||
final Card source = sa.getHostCard();
|
||||
final Cost cost = sa.getPayCosts();
|
||||
|
||||
if (sa.getConditions() != null && !sa.getConditions().areMet(sa)) {
|
||||
if (!sa.metConditions()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,19 @@ package forge.game;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import forge.game.card.Card;
|
||||
|
||||
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) {
|
||||
return new Predicate<CardTraitBase>() {
|
||||
@Override
|
||||
|
||||
@@ -5,6 +5,7 @@ import forge.card.MagicColor;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardState;
|
||||
import forge.game.cost.Cost;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.staticability.StaticAbility;
|
||||
@@ -131,6 +132,9 @@ public class ForgeScript {
|
||||
return !sa.isManaAbility();
|
||||
} else if (property.equals("withoutXCost")) {
|
||||
return !sa.costHasManaX();
|
||||
} else if (property.equals("hasTapCost")) {
|
||||
Cost cost = sa.getPayCosts();
|
||||
return cost != null && cost.hasTapCost();
|
||||
} else if (property.equals("Buyback")) {
|
||||
return sa.isBuyBackAbility();
|
||||
} else if (property.equals("Cycling")) {
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
package forge.game;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
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
|
||||
if (sa.isCycling() && activator.hasKeyword("CyclingForZero")) {
|
||||
for (final KeywordInterface inst : source.getKeywords()) {
|
||||
@@ -277,7 +288,6 @@ public final class GameActionUtil {
|
||||
newSA.setDescription(sb.toString());
|
||||
|
||||
alternatives.add(newSA);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -556,44 +566,21 @@ public final class GameActionUtil {
|
||||
return eff;
|
||||
}
|
||||
|
||||
private static boolean hasUrzaLands(final Player p) {
|
||||
final CardCollectionView landsControlled = p.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")));
|
||||
}
|
||||
|
||||
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"));
|
||||
}
|
||||
public static String generatedTotalMana(final SpellAbility sa) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
SpellAbility tail = sa;
|
||||
while (tail != null) {
|
||||
String value = generatedMana(tail);
|
||||
if (!value.isEmpty() && !"0".equals(value)) {
|
||||
sb.append(value).append(" ");
|
||||
}
|
||||
|
||||
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;
|
||||
tail = tail.getSubAbility();
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
|
||||
|
||||
public static String generatedMana(final SpellAbility sa) {
|
||||
int amount = amountOfManaGenerated(sa, false);
|
||||
int amount = sa.amountOfManaGenerated(false);
|
||||
AbilityManaPart abMana = sa.getManaPart();
|
||||
String baseMana;
|
||||
|
||||
|
||||
@@ -77,4 +77,5 @@ public abstract class TriggerReplacementBase extends CardTraitBase implements II
|
||||
this.overridingAbility = overridingAbility0;
|
||||
}
|
||||
|
||||
abstract public SpellAbility ensureAbility();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
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.cost.Cost;
|
||||
import forge.game.spellability.AbilityActivated;
|
||||
@@ -15,8 +11,6 @@ import java.util.Map;
|
||||
public class AbilityApiBased extends AbilityActivated {
|
||||
private final SpellAbilityEffect effect;
|
||||
|
||||
private static final long serialVersionUID = -4183793555528531978L;
|
||||
|
||||
public AbilityApiBased(ApiType api0, Card sourceCard, Cost abCost, TargetRestrictions tgt, Map<String, String> params0) {
|
||||
super(sourceCard, abCost, tgt);
|
||||
originalMapParams.putAll(params0);
|
||||
@@ -24,13 +18,12 @@ public class AbilityApiBased extends AbilityActivated {
|
||||
api = api0;
|
||||
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.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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1388,7 +1388,7 @@ public class AbilityUtils {
|
||||
);
|
||||
|
||||
// check conditions
|
||||
if (sa.getConditions().areMet(sa)) {
|
||||
if (sa.metConditions()) {
|
||||
if (sa.isWrapper() || StringUtils.isBlank(sa.getParam("UnlessCost"))) {
|
||||
sa.resolve();
|
||||
}
|
||||
@@ -1656,10 +1656,15 @@ public class AbilityUtils {
|
||||
|
||||
// Count$Kicked.<numHB>.<numNotHB>
|
||||
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);
|
||||
}
|
||||
|
||||
// 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>
|
||||
if (sq[0].contains("SearchedLibrary")) {
|
||||
int sum = 0;
|
||||
|
||||
@@ -135,6 +135,7 @@ public enum ApiType {
|
||||
Repeat (RepeatEffect.class),
|
||||
RepeatEach (RepeatEachEffect.class),
|
||||
ReplaceEffect (ReplaceEffect.class),
|
||||
ReplaceMana (ReplaceManaEffect.class),
|
||||
ReplaceDamage (ReplaceDamageEffect.class),
|
||||
ReplaceSplitDamage (ReplaceSplitDamageEffect.class),
|
||||
RestartGame (RestartGameEffect.class),
|
||||
|
||||
@@ -2,10 +2,6 @@ package forge.game.ability;
|
||||
|
||||
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.cost.Cost;
|
||||
import forge.game.spellability.AbilityManaPart;
|
||||
@@ -28,11 +24,11 @@ public class SpellApiBased extends Spell {
|
||||
// A spell is always intrinsic
|
||||
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));
|
||||
}
|
||||
|
||||
if (effect instanceof ChangeZoneEffect || effect instanceof ChangeZoneAllEffect) {
|
||||
if (api.equals(ApiType.ChangeZone) || api.equals(ApiType.ChangeZoneAll)) {
|
||||
AbilityFactory.adjustChangeZoneTarget(mapParams, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import forge.game.mana.Mana;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.AbilityManaPart;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Localizer;
|
||||
|
||||
@@ -37,7 +36,6 @@ public class ManaEffect extends SpellAbilityEffect {
|
||||
sa.setUndoable(sa.isAbility() && sa.isUndoable());
|
||||
|
||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
final boolean optional = sa.hasParam("Optional");
|
||||
final Game game = sa.getActivatingPlayer().getGame();
|
||||
|
||||
@@ -45,46 +43,26 @@ public class ManaEffect extends SpellAbilityEffect {
|
||||
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);
|
||||
}
|
||||
}
|
||||
for (Player p : tgtPlayers) {
|
||||
if (sa.usesTargeting() && !p.canBeTargetedBy(sa)) {
|
||||
// Illegal target. Skip.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (sa.hasParam("ProduceNoOtherMana")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (abMana.isComboMana()) {
|
||||
for (Player p : tgtPlayers) {
|
||||
if (abMana.isComboMana()) {
|
||||
int amount = sa.hasParam("Amount") ? AbilityUtils.calculateAmount(card, sa.getParam("Amount"), sa) : 1;
|
||||
if (tgt != null && !p.canBeTargetedBy(sa)) {
|
||||
// Illegal target. Skip.
|
||||
continue;
|
||||
}
|
||||
|
||||
Player activator = sa.getActivatingPlayer();
|
||||
String express = abMana.getExpressChoice();
|
||||
String[] colorsProduced = abMana.getComboColors().split(" ");
|
||||
|
||||
final StringBuilder choiceString = new StringBuilder();
|
||||
ColorSet colorOptions = null;
|
||||
ColorSet colorOptions = ColorSet.fromNames(colorsProduced);
|
||||
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");
|
||||
ColorSet fullOptions = colorOptions;
|
||||
for (int nMana = 0; nMana < amount; nMana++) {
|
||||
String choice = "";
|
||||
if (colorsNeeded != null && colorsNeeded.length > nMana) { // select from express choices if possible
|
||||
if (colorsNeeded != null && colorsNeeded.length > nMana) { // select from express choices if possible
|
||||
colorOptions = ColorSet
|
||||
.fromMask(fullOptions.getColor() & ManaAtom.fromName(colorsNeeded[nMana]));
|
||||
}
|
||||
@@ -93,10 +71,10 @@ public class ManaEffect extends SpellAbilityEffect {
|
||||
// just use the first possible color.
|
||||
choice = colorsProduced[differentChoice ? nMana : 0];
|
||||
} else {
|
||||
byte chosenColor = activator.getController().chooseColor(Localizer.getInstance().getMessage("lblSelectManaProduce"), sa,
|
||||
byte chosenColor = p.getController().chooseColor(Localizer.getInstance().getMessage("lblSelectManaProduce"), sa,
|
||||
differentChoice ? fullOptions : colorOptions);
|
||||
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);
|
||||
choice = MagicColor.toShortString(chosenColor);
|
||||
@@ -116,18 +94,10 @@ public class ManaEffect extends SpellAbilityEffect {
|
||||
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());
|
||||
}
|
||||
}
|
||||
else if (abMana.isAnyMana()) {
|
||||
for (Player p : tgtPlayers) {
|
||||
if (tgt != null && !p.canBeTargetedBy(sa)) {
|
||||
// Illegal target. Skip.
|
||||
continue;
|
||||
}
|
||||
|
||||
Player act = sa.getActivatingPlayer();
|
||||
else if (abMana.isAnyMana()) {
|
||||
// AI color choice is set in ComputerUtils so only human players need to make a choice
|
||||
|
||||
String colorsNeeded = abMana.getExpressChoice();
|
||||
@@ -142,20 +112,14 @@ public class ManaEffect extends SpellAbilityEffect {
|
||||
colorMenu = mask == 0 ? ColorSet.ALL_COLORS : ColorSet.fromMask(mask);
|
||||
byte val = p.getController().chooseColor(Localizer.getInstance().getMessage("lblSelectManaProduce"), sa, colorMenu);
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
else if (abMana.isSpecialMana()) {
|
||||
for (Player p : tgtPlayers) {
|
||||
if (tgt != null && !p.canBeTargetedBy(sa)) {
|
||||
// Illegal target. Skip.
|
||||
continue;
|
||||
}
|
||||
else if (abMana.isSpecialMana()) {
|
||||
|
||||
String type = abMana.getOrigProduced().split("Special ")[1];
|
||||
|
||||
@@ -177,7 +141,7 @@ public class ManaEffect extends SpellAbilityEffect {
|
||||
if (cs.isMonoColor())
|
||||
sb.append(MagicColor.toShortString(s.getColorMask()));
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -210,34 +174,36 @@ public class ManaEffect extends SpellAbilityEffect {
|
||||
abMana.setExpressChoice(ColorSet.fromMask(colors));
|
||||
} else if (type.startsWith("EachColoredManaSymbol")) {
|
||||
final String res = type.split("_")[1];
|
||||
final CardCollection list = AbilityUtils.getDefinedCards(card, res, sa);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Card c : list) {
|
||||
String mana = c.getManaCost().toString();
|
||||
for (int i = 0; i < mana.length(); i++) {
|
||||
char symbol = mana.charAt(i);
|
||||
switch (symbol) {
|
||||
case 'W':
|
||||
case 'U':
|
||||
case 'B':
|
||||
case 'R':
|
||||
case 'G':
|
||||
sb.append(symbol).append(' ');
|
||||
break;
|
||||
for (Card c : AbilityUtils.getDefinedCards(card, res, sa)) {
|
||||
for (ManaCostShard s : c.getManaCost()) {
|
||||
ColorSet cs = ColorSet.fromMask(s.getColorMask());
|
||||
if(cs.isColorless())
|
||||
continue;
|
||||
sb.append(' ');
|
||||
if (cs.isMonoColor())
|
||||
sb.append(MagicColor.toShortString(s.getColorMask()));
|
||||
else /* (cs.isMulticolor()) */ {
|
||||
byte chosenColor = p.getController().chooseColor(Localizer.getInstance().getMessage("lblChooseSingleColorFromTarget", s.toString()), sa, cs);
|
||||
sb.append(MagicColor.toShortString(chosenColor));
|
||||
}
|
||||
}
|
||||
}
|
||||
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()) {
|
||||
System.out.println("AbilityFactoryMana::manaResolve() - special mana effect is empty for " + sa.getHostCard().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (final Player player : tgtPlayers) {
|
||||
abMana.produceMana(GameActionUtil.generatedMana(sa), player, sa);
|
||||
abMana.produceMana(GameActionUtil.generatedMana(sa), p, sa);
|
||||
}
|
||||
|
||||
// Only clear express choice after mana has been produced
|
||||
|
||||
@@ -11,7 +11,6 @@ import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@@ -29,8 +28,7 @@ public class ManaReflectedEffect extends SpellAbilityEffect {
|
||||
|
||||
final Collection<String> colors = CardUtil.getReflectableManaColors(sa);
|
||||
|
||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
for (final Player player : tgtPlayers) {
|
||||
for (final Player player : getTargetPlayers(sa)) {
|
||||
final String generated = generatedReflectedMana(sa, colors, player);
|
||||
ma.produceMana(generated, player, sa);
|
||||
}
|
||||
|
||||
@@ -6,12 +6,14 @@ import forge.game.ability.AbilityKey;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.GameLogEntryType;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.replacement.ReplacementResult;
|
||||
import forge.game.replacement.ReplacementType;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.TextUtil;
|
||||
|
||||
public class ReplaceDamageEffect extends SpellAbilityEffect {
|
||||
|
||||
@@ -58,6 +60,12 @@ public class ReplaceDamageEffect extends SpellAbilityEffect {
|
||||
}
|
||||
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
|
||||
ReplacementResult result = game.getReplacementHandler().run(event, params);
|
||||
|
||||
@@ -3,9 +3,12 @@ package forge.game.ability.effects;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.GameLogEntryType;
|
||||
import forge.game.GameObject;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
@@ -16,6 +19,7 @@ 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 ReplaceEffect extends SpellAbilityEffect {
|
||||
|
||||
@@ -61,6 +65,13 @@ public class ReplaceEffect extends SpellAbilityEffect {
|
||||
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
|
||||
ReplacementResult result = game.getReplacementHandler().run(retype, params);
|
||||
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) {
|
||||
game.getAction().exile(card, null);
|
||||
} else if (!StringUtils.isNumeric(varValue)) {
|
||||
card.setSVar(varValue, "Number$" + prevent);
|
||||
sa.setSVar(varValue, "Number$" + prevent);
|
||||
}
|
||||
|
||||
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) {
|
||||
colors.addAll(CardUtil.getReflectableManaColors(ab));
|
||||
} 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;
|
||||
}
|
||||
} else {
|
||||
if (mana.getManaPart().canProduce(MagicColor.toShortString(s))) {
|
||||
if (mana.canProduce(MagicColor.toShortString(s))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,12 +358,12 @@ public class CardFactory {
|
||||
// Name first so Senty has the Card name
|
||||
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 s : face.getStaticAbilities()) c.addStaticAbility(s);
|
||||
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
|
||||
c.addIntrinsicKeywords(face.getKeywords(), false);
|
||||
|
||||
|
||||
@@ -1475,7 +1475,7 @@ public class CardFactoryUtil {
|
||||
for (Card card : otb) {
|
||||
if (!card.isTapped() || !untappedOnly) {
|
||||
for (SpellAbility ma : card.getManaAbilities()) {
|
||||
if (ma.getManaPart().canProduce(MagicColor.toShortString(color))) {
|
||||
if (ma.canProduce(MagicColor.toShortString(color))) {
|
||||
uniqueColors++;
|
||||
continue outer;
|
||||
}
|
||||
|
||||
@@ -912,7 +912,7 @@ public class CardProperty {
|
||||
} else if (property.startsWith("canProduceManaColor")) {
|
||||
final String color = property.split("canProduceManaColor ")[1];
|
||||
for (SpellAbility ma : card.getManaAbilities()) {
|
||||
if (ma.getManaPart().canProduce(MagicColor.toShortString(color))) {
|
||||
if (ma.canProduce(MagicColor.toShortString(color))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,7 +391,6 @@ public final class CardUtil {
|
||||
|
||||
final String colorOrType = sa.getParam("ColorOrType");
|
||||
// currently Color or Type, Type is colors + colorless
|
||||
final String validCard = sa.getParam("Valid");
|
||||
final String reflectProperty = sa.getParam("ReflectProperty");
|
||||
// Produce (Reflecting Pool) or Is (Meteor Crater)
|
||||
|
||||
@@ -400,28 +399,30 @@ public final class CardUtil {
|
||||
maxChoices++;
|
||||
}
|
||||
|
||||
CardCollection cards = null;
|
||||
CardCollection cards;
|
||||
|
||||
// Reuse AF_Defined in a slightly different way
|
||||
if (validCard.startsWith("Defined.")) {
|
||||
cards = AbilityUtils.getDefinedCards(card, TextUtil.fastReplace(validCard, "Defined.", ""), abMana);
|
||||
} else {
|
||||
if (sa.getActivatingPlayer() == null) {
|
||||
sa.setActivatingPlayer(sa.getHostCard().getController());
|
||||
if (sa.hasParam("Valid")) {
|
||||
final String validCard = sa.getParam("Valid");
|
||||
// Reuse AF_Defined in a slightly different way
|
||||
if (validCard.startsWith("Defined.")) {
|
||||
cards = AbilityUtils.getDefinedCards(card, TextUtil.fastReplace(validCard, "Defined.", ""), abMana);
|
||||
} else {
|
||||
if (sa.getActivatingPlayer() == null) {
|
||||
sa.setActivatingPlayer(sa.getHostCard().getController());
|
||||
}
|
||||
final Game game = sa.getActivatingPlayer().getGame();
|
||||
cards = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), validCard, abMana.getActivatingPlayer(), card);
|
||||
}
|
||||
final Game game = sa.getActivatingPlayer().getGame();
|
||||
cards = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), validCard, abMana.getActivatingPlayer(), card);
|
||||
}
|
||||
|
||||
// remove anything cards that is already in parents
|
||||
for (final Card p : parents) {
|
||||
cards.remove(p);
|
||||
}
|
||||
// remove anything cards that is already in parents
|
||||
cards.removeAll(parents);
|
||||
|
||||
if ((cards.size() == 0) && !reflectProperty.equals("Produced")) {
|
||||
return colors;
|
||||
if (cards.isEmpty()) {
|
||||
return colors;
|
||||
}
|
||||
} else {
|
||||
cards = new CardCollection();
|
||||
}
|
||||
|
||||
if (reflectProperty.equals("Is")) { // Meteor Crater
|
||||
for (final Card card1 : cards) {
|
||||
// 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")) {
|
||||
// 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) {
|
||||
final String s = MagicColor.toShortString(col);
|
||||
if (producedColors.contains(s)) {
|
||||
@@ -469,7 +470,7 @@ public final class CardUtil {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
colors = canProduce(maxChoices, ab.getManaPart(), colors);
|
||||
colors = canProduce(maxChoices, ab, colors);
|
||||
if (!parents.contains(ab.getHostCard())) {
|
||||
parents.add(ab.getHostCard());
|
||||
}
|
||||
@@ -486,19 +487,18 @@ public final class CardUtil {
|
||||
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) {
|
||||
if (ab == null) {
|
||||
if (sa == null) {
|
||||
return colors;
|
||||
}
|
||||
for (final String col : MagicColor.Constant.ONLY_COLORS) {
|
||||
final String s = MagicColor.toShortString(col);
|
||||
if (ab.canProduce(s)) {
|
||||
if (sa.canProduce(MagicColor.toShortString(col))) {
|
||||
colors.add(col);
|
||||
}
|
||||
}
|
||||
|
||||
if (maxChoices == 6 && ab.canProduce("C")) {
|
||||
if (maxChoices == 6 && sa.canProduce("C")) {
|
||||
colors.add(MagicColor.Constant.COLORLESS);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ package forge.game.mana;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.mana.IParserManaCost;
|
||||
@@ -105,11 +107,16 @@ public class ManaCostBeingPaid {
|
||||
xCount = copy.xCount;
|
||||
totalCount = copy.totalCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{x=" + xCount + " total=" + totalCount + "}";
|
||||
}
|
||||
}
|
||||
|
||||
// holds Mana_Part objects
|
||||
// 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 final String sourceRestriction;
|
||||
private byte sunburstMap = 0;
|
||||
@@ -124,7 +131,7 @@ public class ManaCostBeingPaid {
|
||||
unpaidShards.put(m.getKey(), new ShardCount(m.getValue()));
|
||||
}
|
||||
if (manaCostBeingPaid.xManaCostPaidByColor != null) {
|
||||
xManaCostPaidByColor = new HashMap<>(manaCostBeingPaid.xManaCostPaidByColor);
|
||||
xManaCostPaidByColor = Maps.newHashMap(manaCostBeingPaid.xManaCostPaidByColor);
|
||||
}
|
||||
sourceRestriction = manaCostBeingPaid.sourceRestriction;
|
||||
sunburstMap = manaCostBeingPaid.sunburstMap;
|
||||
@@ -503,7 +510,7 @@ public class ManaCostBeingPaid {
|
||||
sc.xCount--;
|
||||
String color = MagicColor.toShortString(colorMask);
|
||||
if (xManaCostPaidByColor == null) {
|
||||
xManaCostPaidByColor = new HashMap<>();
|
||||
xManaCostPaidByColor = Maps.newHashMap();
|
||||
}
|
||||
Integer xColor = xManaCostPaidByColor.get(color);
|
||||
if (xColor == null) {
|
||||
@@ -602,19 +609,7 @@ public class ManaCostBeingPaid {
|
||||
}
|
||||
|
||||
int nGeneric = getGenericManaAmount();
|
||||
List<ManaCostShard> shards = new ArrayList<>(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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
List<ManaCostShard> shards = Lists.newArrayList(unpaidShards.keySet());
|
||||
|
||||
if (nGeneric > 0) {
|
||||
if (nGeneric <= 20) {
|
||||
|
||||
@@ -166,23 +166,27 @@ public class ManaPool extends ManaConversionMatrix implements Iterable<Mana> {
|
||||
owner.updateManaForView();
|
||||
}
|
||||
|
||||
private void removeMana(final Mana mana) {
|
||||
Collection<Mana> cm = floatingMana.get(mana.getColor());
|
||||
if (cm.remove(mana)) {
|
||||
private boolean removeMana(final Mana mana) {
|
||||
if (floatingMana.remove(mana.getColor(), mana)) {
|
||||
owner.updateManaForView();
|
||||
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) {
|
||||
// Mana restriction must be checked before this method is called
|
||||
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
|
||||
for (final Mana mana : abManaPart.getLastManaProduced()) {
|
||||
if (tryPayCostWithMana(saPaidFor, manaCost, mana, false)) {
|
||||
saPaidFor.getPayingMana().add(0, mana);
|
||||
|
||||
// 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)) {
|
||||
saPaidFor.getPayingMana().add(0, mana);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -216,8 +220,12 @@ public class ManaPool extends ManaConversionMatrix implements Iterable<Mana> {
|
||||
if (!manaCost.isNeeded(mana, this)) {
|
||||
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);
|
||||
removeMana(mana);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3528,4 +3528,11 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public void resetCycledThisTurn() {
|
||||
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
|
||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||
//Check for tapping
|
||||
if (!hasParam("NoTapCheck")) {
|
||||
|
||||
if (hasParam("ValidAbility")) {
|
||||
final SpellAbility manaAbility = (SpellAbility) runParams.get(AbilityKey.AbilityMana);
|
||||
if (manaAbility == null || !manaAbility.getRootAbility().getPayCosts().hasTapCost()) {
|
||||
if (!matchesValid(manaAbility, getParam("ValidAbility").split(","), getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -43,15 +43,23 @@ public class ReplaceProduceMana extends ReplacementEffect {
|
||||
String full = getParam("ManaAmount");
|
||||
String operator = full.substring(0, 2);
|
||||
String operand = full.substring(2);
|
||||
|
||||
int intoperand = AbilityUtils.calculateAmount(getHostCard(), operand, this);
|
||||
|
||||
int manaAmount = StringUtils.countMatches((String) runParams.get(AbilityKey.Mana), " ") + 1;
|
||||
if (!Expressions.compare(manaAmount, operator, intoperand)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasParam("ValidPlayer")) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Player), getParam("ValidPlayer").split(","), getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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.TriggerReplacementBase;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.card.Card;
|
||||
@@ -271,4 +272,13 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
|
||||
void setMode(ReplacementType 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;
|
||||
|
||||
import forge.card.MagicColor;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameLogEntryType;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
@@ -259,12 +258,17 @@ public class ReplacementHandler {
|
||||
chosenRE.setHasRun(false);
|
||||
hasRun.remove(chosenRE);
|
||||
chosenRE.setOtherChoices(null);
|
||||
String message = chosenRE.getDescription();
|
||||
if ( !StringUtils.isEmpty(message))
|
||||
if (chosenRE.getHostCard() != null) {
|
||||
message = TextUtil.fastReplace(message, "CARDNAME", chosenRE.getHostCard().getName());
|
||||
}
|
||||
game.getGameLog().add(GameLogEntryType.EFFECT_REPLACED, message);
|
||||
|
||||
// Updated Replacements need to be logged elsewhere because its otherwise in the wrong order
|
||||
if (res != ReplacementResult.Updated) {
|
||||
String message = chosenRE.getDescription();
|
||||
if ( !StringUtils.isEmpty(message))
|
||||
if (chosenRE.getHostCard() != null) {
|
||||
message = TextUtil.fastReplace(message, "CARDNAME", chosenRE.getHostCard().getName());
|
||||
}
|
||||
game.getGameLog().add(GameLogEntryType.EFFECT_REPLACED, message);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -344,25 +348,11 @@ public class ReplacementHandler {
|
||||
|
||||
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);
|
||||
// if the spellability is a replace effect then its some new logic
|
||||
// if ReplacementResult is set in run params use that instead
|
||||
if (runParams.containsKey(AbilityKey.ReplacementResult)) {
|
||||
return (ReplacementResult) runParams.get(AbilityKey.ReplacementResult);
|
||||
}
|
||||
player.getController().playSpellAbilityNoStack(effectSA, true);
|
||||
// if the spellability is a replace effect then its some new logic
|
||||
// if ReplacementResult is set in run params use that instead
|
||||
if (runParams.containsKey(AbilityKey.ReplacementResult)) {
|
||||
return (ReplacementResult) runParams.get(AbilityKey.ReplacementResult);
|
||||
}
|
||||
|
||||
return ReplacementResult.Replaced;
|
||||
@@ -407,6 +397,10 @@ public class ReplacementHandler {
|
||||
ret.setActiveZone(EnumSet.copyOf(ZoneType.listValueOf(activeZones)));
|
||||
}
|
||||
|
||||
if (mapParams.containsKey("ReplaceWith")) {
|
||||
ret.setOverridingAbility(AbilityFactory.getAbility(host, mapParams.get("ReplaceWith"), ret));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,15 +18,18 @@
|
||||
package forge.game.spellability;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.mana.ManaAtom;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameActionUtil;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardUtil;
|
||||
import forge.game.mana.Mana;
|
||||
import forge.game.mana.ManaPool;
|
||||
import forge.game.player.Player;
|
||||
@@ -39,8 +42,6 @@ import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -57,6 +58,7 @@ public class AbilityManaPart implements java.io.Serializable {
|
||||
private final String origProduced;
|
||||
private String lastExpressChoice = "";
|
||||
private final String manaRestrictions;
|
||||
private String extraManaRestrictions = "";
|
||||
private final String cannotCounterSpell;
|
||||
private final String addsKeywords;
|
||||
private final String addsKeywordsType;
|
||||
@@ -64,7 +66,6 @@ public class AbilityManaPart implements java.io.Serializable {
|
||||
private final String addsCounters;
|
||||
private final String triggersWhenSpent;
|
||||
private final boolean persistentMana;
|
||||
private String manaReplaceType;
|
||||
|
||||
private transient List<Mana> lastManaProduced = Lists.newArrayList();
|
||||
|
||||
@@ -94,7 +95,6 @@ public class AbilityManaPart implements java.io.Serializable {
|
||||
this.addsCounters = params.get("AddsCounters");
|
||||
this.triggersWhenSpent = params.get("TriggersWhenSpent");
|
||||
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) {
|
||||
final Card source = this.getSourceCard();
|
||||
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);
|
||||
repParams.put(AbilityKey.Mana, produced);
|
||||
repParams.put(AbilityKey.Mana, afterReplace);
|
||||
repParams.put(AbilityKey.Player, player);
|
||||
repParams.put(AbilityKey.AbilityMana, sa);
|
||||
if (player.getGame().getReplacementHandler().run(ReplacementType.ProduceMana, repParams) != ReplacementResult.NotReplaced) {
|
||||
repParams.put(AbilityKey.AbilityMana, root);
|
||||
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;
|
||||
}
|
||||
|
||||
//clear lastProduced
|
||||
this.lastManaProduced.clear();
|
||||
|
||||
@@ -154,14 +166,14 @@ public class AbilityManaPart implements java.io.Serializable {
|
||||
// Run triggers
|
||||
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(source);
|
||||
runParams.put(AbilityKey.Player, player);
|
||||
runParams.put(AbilityKey.AbilityMana, sa);
|
||||
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);
|
||||
if (source.isLand()) {
|
||||
player.setTappedLandForManaThisTurn(true);
|
||||
if (source.isLand() && sa.getPayCosts() != null && sa.getPayCosts().hasTapCost() ) {
|
||||
player.setTappedLandForManaThisTurn(true);
|
||||
}
|
||||
// Clear Mana replacement
|
||||
this.manaReplaceType = "";
|
||||
} // end produceMana(String)
|
||||
|
||||
/**
|
||||
@@ -256,7 +268,15 @@ public class AbilityManaPart implements java.io.Serializable {
|
||||
* @return a {@link java.lang.String} object.
|
||||
*/
|
||||
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.
|
||||
* @return a boolean.
|
||||
*/
|
||||
public boolean meetsManaRestrictions(final SpellAbility sa) {
|
||||
public boolean meetsManaRestrictions(final SpellAbility sa, String restrictions) {
|
||||
// No restrictions
|
||||
if (this.manaRestrictions.isEmpty()) {
|
||||
if (restrictions.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Loop over restrictions
|
||||
for (String restriction : this.manaRestrictions.split(",")) {
|
||||
for (String restriction : restrictions.split(",")) {
|
||||
if (restriction.equals("nonSpell")) {
|
||||
return !sa.isSpell();
|
||||
}
|
||||
@@ -306,9 +326,9 @@ public class AbilityManaPart implements java.io.Serializable {
|
||||
if (sa.isValid(restriction, this.getSourceCard().getController(), this.getSourceCard(), null)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (restriction.equals("CantPayGenericCosts")) {
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sa.isAbility()) {
|
||||
@@ -331,7 +351,7 @@ public class AbilityManaPart implements java.io.Serializable {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* meetsManaShardRestrictions.
|
||||
@@ -340,44 +360,44 @@ public class AbilityManaPart implements java.io.Serializable {
|
||||
* @param shard
|
||||
* a {@link forge.card.mana.ManaCostShard} object.
|
||||
* @param color
|
||||
* the color of mana being paid
|
||||
* the color of mana being paid
|
||||
* @return a boolean.
|
||||
*/
|
||||
public boolean meetsManaShardRestrictions(final ManaCostShard shard, final byte color) {
|
||||
if (this.manaRestrictions.isEmpty()) {
|
||||
if (this.manaRestrictions.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
for (String restriction : this.manaRestrictions.split(",")) {
|
||||
if (restriction.equals("CantPayGenericCosts")) {
|
||||
if (shard.isGeneric()) {
|
||||
if (shard.isOr2Generic() && shard.isColor(color)) {
|
||||
continue;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (restriction.equals("CantPayGenericCosts")) {
|
||||
if (shard.isGeneric()) {
|
||||
if (shard.isOr2Generic() && shard.isColor(color)) {
|
||||
continue;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* meetsSpellAndShardRestrictions.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param sa
|
||||
* a {@link forge.game.spellability.SpellAbility} object.
|
||||
* @param shard
|
||||
* a {@link forge.card.mana.ManaCostShard} object.
|
||||
* @param color
|
||||
* the color of mana being paid
|
||||
* the color of mana being paid
|
||||
* @return a boolean.
|
||||
*/
|
||||
public boolean meetsSpellAndShardRestrictions(final SpellAbility sa, final ManaCostShard shard, final byte color) {
|
||||
return this.meetsManaRestrictions(sa) && this.meetsManaShardRestrictions(shard, color);
|
||||
return this.meetsManaRestrictions(sa) && this.meetsManaShardRestrictions(shard, color);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -465,10 +485,6 @@ public class AbilityManaPart implements java.io.Serializable {
|
||||
return this.getOrigProduced().contains("Special");
|
||||
}
|
||||
|
||||
public final boolean canProduce(final String s) {
|
||||
return canProduce(s, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* canProduce.
|
||||
@@ -493,24 +509,9 @@ public class AbilityManaPart implements java.io.Serializable {
|
||||
if (isComboMana()) {
|
||||
return getComboColors().contains(s);
|
||||
}
|
||||
if (sa != null) {
|
||||
return applyManaReplacement(sa, 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} */
|
||||
@Override
|
||||
public final boolean equals(final Object o) {
|
||||
@@ -586,81 +587,59 @@ public class AbilityManaPart implements java.io.Serializable {
|
||||
return this.persistentMana;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the manaReplaceType
|
||||
*/
|
||||
public String getManaReplaceType() {
|
||||
return manaReplaceType;
|
||||
}
|
||||
boolean abilityProducesManaColor(final SpellAbility am, final byte neededColor) {
|
||||
if (0 != (neededColor & ManaAtom.GENERIC)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* setManaReplaceType.
|
||||
*/
|
||||
public void setManaReplaceType(final String type) {
|
||||
this.manaReplaceType = type;
|
||||
}
|
||||
/**
|
||||
* <p>
|
||||
* applyManaReplacement.
|
||||
* </p>
|
||||
* @return a String
|
||||
*/
|
||||
public static String applyManaReplacement(final SpellAbility sa, final String original) {
|
||||
final Map<String, String> repMap = Maps.newHashMap();
|
||||
final Player act = sa != null ? sa.getActivatingPlayer() : null;
|
||||
final String manaReplace = sa != null ? sa.getManaPart().getManaReplaceType(): "";
|
||||
if (manaReplace.isEmpty()) {
|
||||
if (act != null && act.getLandsPlayedThisTurn() > 0 && sa.hasParam("ReplaceIfLandPlayed")) {
|
||||
return sa.getParam("ReplaceIfLandPlayed");
|
||||
}
|
||||
return original;
|
||||
if (isAnyMana()) {
|
||||
return true;
|
||||
}
|
||||
if (manaReplace.startsWith("Any")) {
|
||||
// Replace any type and amount
|
||||
String replaced = manaReplace.split("->")[1];
|
||||
if (replaced.equals("Any")) {
|
||||
byte rs = MagicColor.GREEN;
|
||||
if (act != null) {
|
||||
rs = act.getController().chooseColor("Choose a color", sa, ColorSet.ALL_COLORS);
|
||||
|
||||
// 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, getOrigProduced());
|
||||
repParams.put(AbilityKey.Affected, source);
|
||||
repParams.put(AbilityKey.Player, activator);
|
||||
repParams.put(AbilityKey.AbilityMana, am.getRootAbility());
|
||||
|
||||
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.zonesCheck(g.getZoneOf(crd))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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()));
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
m.appendTail(sb);
|
||||
String replaced = sb.toString();
|
||||
while (replaced.contains("Any")) {
|
||||
byte rs = MagicColor.GREEN;
|
||||
if (act != null) {
|
||||
rs = act.getController().chooseColor("Choose a color", sa, ColorSet.ALL_COLORS);
|
||||
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;
|
||||
}
|
||||
}
|
||||
replaced = replaced.replaceFirst("Any", MagicColor.toShortString(rs));
|
||||
}
|
||||
return replaced;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // end class AbilityMana
|
||||
|
||||
@@ -20,10 +20,6 @@ package forge.game.spellability;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.ApiType;
|
||||
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.cost.Cost;
|
||||
|
||||
@@ -92,11 +88,11 @@ public final class AbilitySub extends SpellAbility implements java.io.Serializab
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
if (effect instanceof ChangeZoneEffect || effect instanceof ChangeZoneAllEffect) {
|
||||
if (api.equals(ApiType.ChangeZone) || api.equals(ApiType.ChangeZoneAll)) {
|
||||
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
|
||||
}
|
||||
|
||||
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() {
|
||||
return manaPart;
|
||||
}
|
||||
|
||||
public final AbilityManaPart getManaPartRecursive() {
|
||||
SpellAbility tail = this;
|
||||
while (tail != null) {
|
||||
if (tail.manaPart != null) {
|
||||
return tail.manaPart;
|
||||
}
|
||||
tail = tail.getSubAbility();
|
||||
public final List<AbilityManaPart> getAllManaParts() {
|
||||
AbilityManaPart mp = getManaPart();
|
||||
if (mp == null && subAbility == null) {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
return null;
|
||||
List<AbilityManaPart> result = Lists.newArrayList();
|
||||
if (mp != null) {
|
||||
result.add(mp);
|
||||
}
|
||||
if (subAbility != null) {
|
||||
result.addAll(subAbility.getAllManaParts());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public final boolean isManaAbility() {
|
||||
@@ -266,7 +348,14 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
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) {
|
||||
@@ -464,6 +553,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
conditions = condition;
|
||||
}
|
||||
|
||||
public boolean metConditions() {
|
||||
return getConditions() != null && getConditions().areMet(this);
|
||||
}
|
||||
|
||||
public List<Mana> getPayingMana() {
|
||||
return payingMana;
|
||||
}
|
||||
@@ -1880,9 +1973,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
public boolean tracksManaSpent() {
|
||||
if (hostCard == null || hostCard.getRules() == null) { return false; }
|
||||
|
||||
if (hostCard.hasKeyword(Keyword.SUNBURST)) {
|
||||
if (isSpell() && hostCard.hasConverge()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String text = hostCard.getRules().getOracleText();
|
||||
if (isSpell() && text.contains("was spent to cast")) {
|
||||
return true;
|
||||
@@ -2019,7 +2113,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
String mana = manaPart.mana();
|
||||
if (!mana.equals("Any")) {
|
||||
score += mana.length();
|
||||
if (!manaPart.canProduce("C")) {
|
||||
if (!canProduce("C")) {
|
||||
// Producing colorless should produce a slightly lower score
|
||||
score += 1;
|
||||
}
|
||||
|
||||
@@ -169,13 +169,7 @@ public class TriggerHandler {
|
||||
if (wt.getTriggers() != null)
|
||||
continue;
|
||||
|
||||
List<Trigger> trigger = Lists.newArrayList();
|
||||
for (final Trigger t : activeTriggers) {
|
||||
if (canRunTrigger(t,wt.getMode(),wt.getParams())) {
|
||||
trigger.add(t);
|
||||
}
|
||||
}
|
||||
wt.setTriggers(trigger);
|
||||
wt.setTriggers(getActiveTrigger(wt.getMode(), wt.getParams()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -678,4 +672,14 @@ public class TriggerHandler {
|
||||
|
||||
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.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Localizer;
|
||||
|
||||
@@ -68,25 +67,19 @@ public class TriggerTapsForMana extends Trigger {
|
||||
}
|
||||
|
||||
if (hasParam("ValidCard")) {
|
||||
final Card tapper = (Card) runParams.get(AbilityKey.Card);
|
||||
if (!tapper.isValid(getParam("ValidCard").split(","), this.getHostCard().getController(),
|
||||
this.getHostCard(), null)) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Card), getParam("ValidCard").split(","), getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasParam("Player")) {
|
||||
final Player player = (Player) runParams.get(AbilityKey.Player);
|
||||
if (!player.isValid(getParam("Player").split(","), this.getHostCard().getController(), this.getHostCard(), null)) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Player), getParam("Player").split(","), getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasParam("Activator")) {
|
||||
final SpellAbility sa = (SpellAbility) runParams.get(AbilityKey.AbilityMana);
|
||||
if (sa == null) return false;
|
||||
final Player activator = sa.getActivatingPlayer();
|
||||
if (!activator.isValid(getParam("Activator").split(","), this.getHostCard().getController(), this.getHostCard(), null)) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Activator), getParam("Activator").split(","), getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -113,7 +106,7 @@ public class TriggerTapsForMana extends Trigger {
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
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
|
||||
|
||||
@@ -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.
|
||||
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:DarkMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
||||
SVar:Picture:https://downloads.cardforge.org/images/cards/ARC/A Display of My Dark Power.full.jpg
|
||||
SVar:DarkMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ TriggeredActivator
|
||||
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
|
||||
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.
|
||||
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.
|
||||
SVar:TrigMana:DB$ Mana | Produced$ Chosen | Amount$ 1 | Defined$ TriggeredPlayer
|
||||
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 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$ You
|
||||
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.
|
||||
|
||||
@@ -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: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: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:ProduceColorless:R->1 & B->1 & U->1 & G->1 & W->1
|
||||
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:DB$ ReplaceMana | ReplaceType$ C
|
||||
SVar:STCurse:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Creature.Red | AddPower$ -1 | AddToughness$ -1
|
||||
SVar:X:Count$Valid Permanent
|
||||
AI:RemoveDeck:All
|
||||
|
||||
@@ -2,9 +2,8 @@ Name:Contamination
|
||||
ManaCost:2 B
|
||||
Types:Enchantment
|
||||
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.
|
||||
SVar:ProduceB:Any->B
|
||||
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:DB$ ReplaceMana | ReplaceMana$ B
|
||||
AI:RemoveDeck:All
|
||||
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.
|
||||
|
||||
@@ -3,7 +3,6 @@ ManaCost:3 B
|
||||
Types:Creature Spirit
|
||||
PT:2/2
|
||||
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}.
|
||||
SVar:TrigMana:DB$Mana | Produced$ B | Amount$ 1
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/crypt_ghast.jpg
|
||||
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
|
||||
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
|
||||
ManaCost:2
|
||||
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.
|
||||
SVar:ProduceC:Any->C
|
||||
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: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.
|
||||
SVar:X:Count$ThisTurnCast_Card.YouCtrl
|
||||
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.
|
||||
|
||||
@@ -2,9 +2,8 @@ Name:Deep Water
|
||||
ManaCost:U U
|
||||
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.
|
||||
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:ProduceU:C->U & B->U & R->U & G->U & W->U
|
||||
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:DB$ ReplaceMana | ReplaceType$ U
|
||||
AI:RemoveDeck:All
|
||||
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.
|
||||
|
||||
@@ -3,6 +3,5 @@ ManaCost:3 G G
|
||||
Types:Enchantment
|
||||
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.
|
||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/dictate_of_karametra.jpg
|
||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ TriggeredActivator
|
||||
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
|
||||
ManaCost:2
|
||||
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
|
||||
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.
|
||||
|
||||
@@ -2,7 +2,7 @@ Name:Eloren Wilds
|
||||
ManaCost:no cost
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
|
||||
@@ -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.
|
||||
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.
|
||||
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
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearImprinted$ True
|
||||
T:Mode$ ChangesZone | ValidCard$ Card.IsImprinted+ExiledWithSource | Origin$ Exile | Execute$ DBForget | Static$ True
|
||||
SVar:DBForget:DB$ Pump | ForgetImprinted$ TriggeredCard
|
||||
SVar:NeedsToPlay:Land.Basic+YouCtrl
|
||||
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.
|
||||
|
||||
@@ -3,9 +3,8 @@ ManaCost:1 W
|
||||
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.
|
||||
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:ProduceW:R->W & B->W & U->W & G->W
|
||||
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: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.
|
||||
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.
|
||||
|
||||
@@ -2,7 +2,7 @@ Name:Forsaken Monument
|
||||
ManaCost:5
|
||||
Types:Legendary Artifact
|
||||
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
|
||||
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
|
||||
|
||||
@@ -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.
|
||||
SVar:TrigChoose:DB$ ChooseColor | Defined$ TriggeredPlayer | AILogic$ MostProminentInActivePlayerHand | SubAbility$ DBEffect
|
||||
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:ProduceChosen:C->Chosen & U->Chosen & B->Chosen & R->Chosen & G->Chosen & W->Chosen
|
||||
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:DB$ ReplaceMana | ReplaceColor$ Chosen
|
||||
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.
|
||||
|
||||
@@ -3,8 +3,8 @@ ManaCost:G
|
||||
Types:Creature Human Spellshaper
|
||||
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.
|
||||
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:HarvestProduce:Any->Any
|
||||
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:DB$ ReplaceMana | ReplaceMana$ Any
|
||||
AI:RemoveDeck:All
|
||||
SVar:NonStackingEffect:True
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/harvest_mage.jpg
|
||||
|
||||
@@ -2,7 +2,5 @@ Name:Heartbeat of Spring
|
||||
ManaCost:2 G
|
||||
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.
|
||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
||||
AI:RemoveDeck:All
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/heartbeat_of_spring.jpg
|
||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ TriggeredActivator
|
||||
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
|
||||
Types:Enchantment
|
||||
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.
|
||||
SVar:ProduceB:C->B & U->B & R->B & G->B & W->B
|
||||
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:DB$ ReplaceMana | ReplaceType$ B
|
||||
AI:RemoveDeck:All
|
||||
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.
|
||||
|
||||
@@ -3,7 +3,6 @@ ManaCost:3 G
|
||||
Types:Creature Elf Druid
|
||||
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.
|
||||
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/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.
|
||||
|
||||
@@ -2,7 +2,7 @@ Name:Kinnan, Bonder Prodigy
|
||||
ManaCost:G U
|
||||
Types:Legendary Creature Human Druid
|
||||
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.
|
||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
||||
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 | 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.
|
||||
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
|
||||
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.
|
||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/mana_flare.jpg
|
||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ TriggeredActivator
|
||||
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
|
||||
ManaCost:4 G G
|
||||
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.
|
||||
SVar:ProduceTwice:C->C C & R->R R & B->B B & U->U U & G->G G & W->W W
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/mana_reflection.jpg
|
||||
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:DB$ ReplaceMana | ReplaceAmount$ 2
|
||||
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
|
||||
Types:Enchantment
|
||||
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.
|
||||
SVar:TrigMana:DB$ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/miraris_wake.jpg
|
||||
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 | ReflectProperty$ Produced | Defined$ You
|
||||
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
|
||||
Types:Vanguard
|
||||
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.
|
||||
SVar:ProduceAny:C->Any & B->Any & R->Any & G->Any & W->Any & U->Any
|
||||
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:DB$ ReplaceMana | ReplaceType$ Any
|
||||
AI:RemoveDeck:All
|
||||
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.
|
||||
|
||||
@@ -3,17 +3,16 @@ ManaCost:5
|
||||
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.
|
||||
K:Cumulative upkeep:3
|
||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Plains | ManaReplacement$ ProduceR | Secondary$ True | Description$ If tapped for mana, Plains produce R.
|
||||
SVar:ProduceR:C->R & B->R & U->R & G->R & W->R
|
||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Island | ManaReplacement$ ProduceG | Secondary$ True | Description$ If tapped for mana, Islands produce G.
|
||||
SVar:ProduceG:C->G & B->G & U->G & R->G & W->G
|
||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Swamp | ManaReplacement$ ProduceW | Secondary$ True | Description$ If tapped for mana, Swamps produce W.
|
||||
SVar:ProduceW:C->W & B->W & U->W & R->W & G->W
|
||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Mountain | ManaReplacement$ ProduceU | Secondary$ True | Description$ If tapped for mana, Mountains produce U.
|
||||
SVar:ProduceU:C->U & B->U & G->U & R->U & W->U
|
||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Forest | ManaReplacement$ ProduceB | Secondary$ True | Description$ If tapped for mana, Forests produce B.
|
||||
SVar:ProduceB:C->B & G->B & U->B & R->B & W->B
|
||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Plains | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceR | Secondary$ True | Description$ If tapped for mana, Plains produce R.
|
||||
SVar:ProduceR:DB$ ReplaceMana | ReplaceType$ R
|
||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Island | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceG | Secondary$ True | Description$ If tapped for mana, Islands produce G.
|
||||
SVar:ProduceG:DB$ ReplaceMana | ReplaceType$ G
|
||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Swamp | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceW | Secondary$ True | Description$ If tapped for mana, Swamps produce W.
|
||||
SVar:ProduceW:DB$ ReplaceMana | ReplaceType$ W
|
||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Mountain | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceU | Secondary$ True | Description$ If tapped for mana, Mountains produce U.
|
||||
SVar:ProduceU:DB$ ReplaceMana | ReplaceType$ U
|
||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Forest | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceB | Secondary$ True | Description$ If tapped for mana, Forests produce B.
|
||||
SVar:ProduceB:DB$ ReplaceMana | ReplaceType$ B
|
||||
AI:RemoveDeck:All
|
||||
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.
|
||||
|
||||
@@ -3,6 +3,6 @@ ManaCost:3 R G
|
||||
Types:Legendary Creature Centaur Druid
|
||||
PT:5/5
|
||||
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.
|
||||
SVar:TrigMana:DB$ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
||||
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 | 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.
|
||||
|
||||
@@ -3,7 +3,6 @@ ManaCost:4 B B
|
||||
Types:Creature Vampire Shade
|
||||
PT:4/4
|
||||
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}.
|
||||
SVar:TrigMana:DB$Mana | Produced$ B | Amount$ 1
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/nirkana_revenant.jpg
|
||||
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
|
||||
Oracle:Whenever you tap a Swamp for mana, add an additional {B}.\n{B}: Nirkana Revenant gets +1/+1 until end of turn.
|
||||
|
||||
@@ -2,8 +2,8 @@ Name:Nissa, Who Shakes the World
|
||||
ManaCost:3 G G
|
||||
Types:Legendary Planeswalker Nissa
|
||||
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}.
|
||||
SVar:TrigMana:DB$Mana | Produced$ G | Amount$ 1
|
||||
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
|
||||
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:DBAnimate:DB$ Animate | Defined$ Targeted | Power$ 0 | Toughness$ 0 | Types$ Creature,Elemental | Keywords$ Vigilance & Haste | Permanent$ True
|
||||
|
||||
@@ -3,6 +3,6 @@ ManaCost:4 G G G
|
||||
Types:Enchantment Creature Elemental
|
||||
PT:5/5
|
||||
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.
|
||||
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
|
||||
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:DB$ ReplaceMana | ReplaceAmount$ 3
|
||||
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
|
||||
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: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
|
||||
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.
|
||||
|
||||
@@ -2,9 +2,8 @@ Name:Pale Moon
|
||||
ManaCost:1 U
|
||||
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.
|
||||
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:ProduceColorless:U->1 & B->1 & R->1 & G->1 & W->1
|
||||
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:DB$ ReplaceMana | ReplaceType$ C
|
||||
AI:RemoveDeck:All
|
||||
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.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
Name:Pulse of Llanowar
|
||||
ManaCost:3 G
|
||||
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.
|
||||
SVar:ProduceAny:C->Any & R->Any & B->Any & U->Any & G->Any & W->Any
|
||||
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:DB$ ReplaceMana | ReplaceType$ Any
|
||||
AI:RemoveDeck:All
|
||||
SVar:NonStackingEffect:True
|
||||
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
|
||||
Types:Creature Gnome
|
||||
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.)
|
||||
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:QuarumProduce:W->1
|
||||
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 | ValidCard$ Card.IsRemembered | ReplaceWith$ QuarumProduce | Description$ If this Land is tapped for mana, it produces colorless mana instead of white mana.
|
||||
SVar:QuarumProduce:DB$ ReplaceMana | ReplaceColor$ C | ReplaceOnly$ W
|
||||
AI:RemoveDeck:All
|
||||
AI:RemoveDeck:Random
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/quarum_trench_gnomes.jpg
|
||||
|
||||
@@ -3,16 +3,15 @@ ManaCost:U U U
|
||||
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.
|
||||
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.
|
||||
SVar:ProduceR:C->R & B->R & U->R & G->R & W->R
|
||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Swamp | ManaReplacement$ ProduceG | Secondary$ True | Description$ If tapped for mana, Swamps produce G.
|
||||
SVar:ProduceG:C->G & B->G & U->G & R->G & W->G
|
||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Mountain | ManaReplacement$ ProduceW | Secondary$ True | Description$ If tapped for mana, Mountains produce U.
|
||||
SVar:ProduceW:C->W & B->W & G->W & R->W & U->W
|
||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Forest | ManaReplacement$ ProduceB | Secondary$ True | Description$ If tapped for mana, Forests produce B.
|
||||
SVar:ProduceB:C->B & G->B & U->B & R->B & W->B
|
||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Plains | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceR | Secondary$ True | Description$ If tapped for mana, Plains produce R.
|
||||
SVar:ProduceR:DB$ ReplaceMana | ReplaceType$ R
|
||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Swamp | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceG | Secondary$ True | Description$ If tapped for mana, Swamps produce G.
|
||||
SVar:ProduceG:DB$ ReplaceMana | ReplaceType$ G
|
||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Mountain | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceW | Secondary$ True | Description$ If tapped for mana, Mountains produce U.
|
||||
SVar:ProduceW:DB$ ReplaceMana | ReplaceType$ W
|
||||
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Forest | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceB | Secondary$ True | Description$ If tapped for mana, Forests produce B.
|
||||
SVar:ProduceB:DB$ ReplaceMana | ReplaceType$ B
|
||||
AI:RemoveDeck:All
|
||||
AI:RemoveDeck:Random
|
||||
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.
|
||||
|
||||
@@ -5,7 +5,6 @@ PT:5/5
|
||||
K:Trample
|
||||
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
|
||||
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: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
|
||||
Types:Enchantment
|
||||
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.
|
||||
SVar:ProduceColorless:B->1 & U->1 & R->1 & G->1 & W->1
|
||||
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:DB$ ReplaceMana | ReplaceType$ C
|
||||
AI:RemoveDeck:All
|
||||
AI:RemoveDeck:Random
|
||||
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.
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
Name:River of Tears
|
||||
ManaCost:no cost
|
||||
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
|
||||
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.
|
||||
|
||||
@@ -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.
|
||||
SVar:CheckHandLand:Count$ValidHand Land.YouCtrl
|
||||
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.
|
||||
|
||||
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.
|
||||
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: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: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.
|
||||
|
||||
@@ -4,8 +4,7 @@ Types:Creature Elemental Cat
|
||||
PT:0/0
|
||||
K:etbCounter:P1P1:7
|
||||
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.
|
||||
SVar:TrigRemoveCounter:DB$RemoveCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
|
||||
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
|
||||
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.
|
||||
|
||||
@@ -9,8 +9,7 @@ SVar:Y:ReplaceCount$TokenNum/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.
|
||||
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:TrigMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/selesnya_loft_gardens.jpg
|
||||
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 | ReflectProperty$ Produced | Defined$ You
|
||||
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.
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Sisay
|
||||
ManaCost:no cost
|
||||
Types:Vanguard
|
||||
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.
|
||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
||||
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 | ReflectProperty$ Produced | Defined$ You
|
||||
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.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Name:Urza's Mine
|
||||
ManaCost:no cost
|
||||
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
|
||||
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.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Name:Urza's Power Plant
|
||||
ManaCost:no cost
|
||||
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
|
||||
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.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Name:Urza's Tower
|
||||
ManaCost:no cost
|
||||
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
|
||||
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.
|
||||
|
||||
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
|
||||
PT:7/6
|
||||
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.
|
||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ You
|
||||
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 | 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.
|
||||
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.
|
||||
|
||||
@@ -2,7 +2,7 @@ Name:Winter's Night
|
||||
ManaCost:R G W
|
||||
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.
|
||||
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.
|
||||
AI:RemoveDeck:All
|
||||
AI:RemoveDeck:Random
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
Name:Zendikar Resurgent
|
||||
ManaCost:5 G G
|
||||
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.)
|
||||
SVar:TrigMana:DB$ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
||||
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 | 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.
|
||||
SVar:TrigDraw:DB$Draw | Defined$ You | NumCards$ 1
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/zendikar_resurgent.jpg
|
||||
SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 1
|
||||
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
|
||||
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.
|
||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | Valid$ Defined.Triggered | ReflectProperty$ Produced | Defined$ TriggeredPlayer
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/zhur_taa_ancient.jpg
|
||||
SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ TriggeredActivator
|
||||
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 forge.GuiBase;
|
||||
import forge.game.GameActionUtil;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.util.TextUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -18,15 +16,11 @@ import forge.card.ColorSet;
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.mana.ManaAtom;
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.GameActionUtil;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardUtil;
|
||||
import forge.game.mana.ManaCostBeingPaid;
|
||||
import forge.game.player.Player;
|
||||
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.player.HumanPlay;
|
||||
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
|
||||
if (otherCardsToSelect != null) {
|
||||
for (Card c : otherCardsToSelect) {
|
||||
for (SpellAbility sa : c.getManaAbilities()) {
|
||||
for (SpellAbility sa : getAllManaAbilities(c)) {
|
||||
if (sa.canPlay()) {
|
||||
delaySelectCards.add(c);
|
||||
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 activateDelayedCard();
|
||||
} else {
|
||||
List<SpellAbility> manaAbilities = getAllManaAbilities(card);
|
||||
// Desktop Forge floating menu functionality
|
||||
if (card.getManaAbilities().size() == 1) {
|
||||
activateManaAbility(card, card.getManaAbilities().get(0));
|
||||
if (manaAbilities.size() == 1) {
|
||||
activateManaAbility(card, manaAbilities.get(0));
|
||||
} else {
|
||||
SpellAbility spellAbility = getController().getAbilityToPlay(card, Lists.newArrayList(card.getManaAbilities()), triggerEvent);
|
||||
SpellAbility spellAbility = getController().getAbilityToPlay(card, manaAbilities, triggerEvent);
|
||||
if (spellAbility != null) {
|
||||
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
|
||||
public String getActivateAction(Card card) {
|
||||
for (SpellAbility sa : card.getManaAbilities()) {
|
||||
for (SpellAbility sa : getAllManaAbilities(card)) {
|
||||
if (sa.canPlay()) {
|
||||
return "pay mana with card";
|
||||
}
|
||||
@@ -135,6 +150,7 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public List<SpellAbility> getUsefulManaAbilities(Card card) {
|
||||
List<SpellAbility> abilities = new ArrayList<>();
|
||||
|
||||
@@ -151,7 +167,7 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
||||
if (manaCost.isAnyPartPayableWith((byte) ManaAtom.GENERIC, player.getManaPool())) {
|
||||
colorCanUse |= ManaAtom.GENERIC;
|
||||
}
|
||||
if (colorCanUse == 0) { // no mana cost or something
|
||||
if (colorCanUse == 0) { // no mana cost or something
|
||||
return abilities;
|
||||
}
|
||||
|
||||
@@ -160,15 +176,10 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
||||
return abilities;
|
||||
}
|
||||
|
||||
for (SpellAbility ma : card.getManaAbilities()) {
|
||||
for (SpellAbility ma : getAllManaAbilities(card)) {
|
||||
ma.setActivatingPlayer(player);
|
||||
AbilityManaPart m = ma.getManaPartRecursive();
|
||||
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);
|
||||
if (ma.isManaAbilityFor(saPaidFor, colorCanUse))
|
||||
abilities.add(ma);
|
||||
}
|
||||
return abilities;
|
||||
}
|
||||
@@ -189,11 +200,8 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
||||
System.err.print("Should wait till previous call to playAbility finishes.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// make sure computer's lands aren't selected
|
||||
if (card.getController() != player) {
|
||||
return false;
|
||||
}
|
||||
|
||||
byte colorCanUse = 0;
|
||||
byte colorNeeded = 0;
|
||||
@@ -206,106 +214,96 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
||||
colorCanUse |= ManaAtom.GENERIC;
|
||||
}
|
||||
|
||||
if (colorCanUse == 0) { // no mana cost or something
|
||||
if (colorCanUse == 0) { // no mana cost or something
|
||||
return false;
|
||||
}
|
||||
|
||||
HashMap<SpellAbilityView, SpellAbility> abilitiesMap = new HashMap<>();
|
||||
// you can't remove unneeded abilities inside a for (am:abilities) loop :(
|
||||
|
||||
final String typeRes = manaCost.getSourceRestriction();
|
||||
if (StringUtils.isNotBlank(typeRes) && !card.getType().hasStringType(typeRes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean guessAbilityWithRequiredColors = true;
|
||||
int amountOfMana = -1;
|
||||
for (SpellAbility ma : card.getManaAbilities()) {
|
||||
ma.setActivatingPlayer(player);
|
||||
|
||||
AbilityManaPart m = ma.getManaPartRecursive();
|
||||
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
|
||||
int maAmount = GameActionUtil.amountOfManaGenerated(ma, true);
|
||||
if (amountOfMana == -1) {
|
||||
amountOfMana = maAmount;
|
||||
} else {
|
||||
if (amountOfMana != maAmount) {
|
||||
guessAbilityWithRequiredColors = false;
|
||||
}
|
||||
}
|
||||
|
||||
abilitiesMap.put(ma.getView(), ma);
|
||||
|
||||
// skip express mana if the ability is not undoable or reusable
|
||||
if (!ma.isUndoable() || !ma.getPayCosts().isRenewableResource() || ma.getSubAbility() != null) {
|
||||
guessAbilityWithRequiredColors = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (abilitiesMap.isEmpty() || (chosenAbility != null && !abilitiesMap.containsKey(chosenAbility.getView()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store some information about color costs to help with any mana choices
|
||||
if (colorNeeded == 0) { // only colorless left
|
||||
if (saPaidFor.getHostCard() != null && saPaidFor.getHostCard().hasSVar("ManaNeededToAvoidNegativeEffect")) {
|
||||
String[] negEffects = saPaidFor.getHostCard().getSVar("ManaNeededToAvoidNegativeEffect").split(",");
|
||||
for (String negColor : negEffects) {
|
||||
byte col = ManaAtom.fromName(negColor);
|
||||
colorCanUse |= col;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the card has any ability that tracks mana spent, skip express Mana choice
|
||||
if (saPaidFor.tracksManaSpent()) {
|
||||
colorCanUse = ColorSet.ALL_COLORS.getColor();
|
||||
guessAbilityWithRequiredColors = false;
|
||||
}
|
||||
|
||||
boolean choice = true;
|
||||
boolean isPayingGeneric = false;
|
||||
if (guessAbilityWithRequiredColors) {
|
||||
// express Mana Choice
|
||||
if (colorNeeded == 0) {
|
||||
choice = false;
|
||||
//avoid unnecessary prompt by pretending we need White
|
||||
//for the sake of "Add one mana of any color" effects
|
||||
colorNeeded = MagicColor.WHITE;
|
||||
isPayingGeneric = true; // for further processing
|
||||
}
|
||||
else {
|
||||
final HashMap<SpellAbilityView, SpellAbility> colorMatches = new HashMap<>();
|
||||
for (SpellAbility sa : abilitiesMap.values()) {
|
||||
if (abilityProducesManaColor(sa, sa.getManaPartRecursive(), colorNeeded)) {
|
||||
colorMatches.put(sa.getView(), sa);
|
||||
}
|
||||
}
|
||||
|
||||
if (colorMatches.isEmpty()) {
|
||||
// can only match colorless just grab the first and move on.
|
||||
// This is wrong. Sometimes all abilities aren't created equal
|
||||
choice = false;
|
||||
}
|
||||
else if (colorMatches.size() < abilitiesMap.size()) {
|
||||
// leave behind only color matches
|
||||
abilitiesMap = colorMatches;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
HashMap<SpellAbilityView, SpellAbility> abilitiesMap = new HashMap<>();
|
||||
// you can't remove unneeded abilities inside a for (am:abilities) loop :(
|
||||
|
||||
final String typeRes = manaCost.getSourceRestriction();
|
||||
if (StringUtils.isNotBlank(typeRes) && !card.getType().hasStringType(typeRes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean guessAbilityWithRequiredColors = true;
|
||||
int amountOfMana = -1;
|
||||
for (SpellAbility ma : getAllManaAbilities(card)) {
|
||||
ma.setActivatingPlayer(player);
|
||||
|
||||
if (!ma.isManaAbilityFor(saPaidFor, colorCanUse)) { continue; }
|
||||
|
||||
// If Mana Abilities produce differing amounts of mana, let the player choose
|
||||
int maAmount = ma.totalAmountOfManaGenerated(saPaidFor, true);
|
||||
if (amountOfMana == -1) {
|
||||
amountOfMana = maAmount;
|
||||
} else {
|
||||
if (amountOfMana != maAmount) {
|
||||
guessAbilityWithRequiredColors = false;
|
||||
}
|
||||
}
|
||||
|
||||
abilitiesMap.put(ma.getView(), ma);
|
||||
|
||||
// skip express mana if the ability is not undoable or reusable
|
||||
if (!ma.isUndoable() || !ma.getPayCosts().isRenewableResource() || ma.getSubAbility() != null
|
||||
|| ma.isManaCannotCounter(saPaidFor)) {
|
||||
guessAbilityWithRequiredColors = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (abilitiesMap.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store some information about color costs to help with any mana choices
|
||||
if (colorNeeded == 0) { // only colorless left
|
||||
if (saPaidFor.getHostCard() != null && saPaidFor.getHostCard().hasSVar("ManaNeededToAvoidNegativeEffect")) {
|
||||
String[] negEffects = saPaidFor.getHostCard().getSVar("ManaNeededToAvoidNegativeEffect").split(",");
|
||||
for (String negColor : negEffects) {
|
||||
byte col = ManaAtom.fromName(negColor);
|
||||
colorCanUse |= col;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the card has any ability that tracks mana spent, skip express Mana choice
|
||||
if (saPaidFor.tracksManaSpent()) {
|
||||
colorCanUse = ColorSet.ALL_COLORS.getColor();
|
||||
guessAbilityWithRequiredColors = false;
|
||||
}
|
||||
|
||||
boolean choice = true;
|
||||
if (guessAbilityWithRequiredColors) {
|
||||
// express Mana Choice
|
||||
if (colorNeeded == 0) {
|
||||
choice = false;
|
||||
//avoid unnecessary prompt by pretending we need White
|
||||
//for the sake of "Add one mana of any color" effects
|
||||
colorNeeded = MagicColor.WHITE;
|
||||
}
|
||||
else {
|
||||
final HashMap<SpellAbilityView, SpellAbility> colorMatches = new HashMap<>();
|
||||
for (SpellAbility sa : abilitiesMap.values()) {
|
||||
if (sa.isManaAbilityFor(saPaidFor, colorNeeded)) {
|
||||
colorMatches.put(sa.getView(), sa);
|
||||
}
|
||||
}
|
||||
|
||||
if (colorMatches.isEmpty()) {
|
||||
// can only match colorless just grab the first and move on.
|
||||
// This is wrong. Sometimes all abilities aren't created equal
|
||||
choice = false;
|
||||
}
|
||||
else if (colorMatches.size() < abilitiesMap.size()) {
|
||||
// leave behind only color matches
|
||||
abilitiesMap = colorMatches;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
} 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
|
||||
int producedColorMask = 0;
|
||||
for (final byte color : ManaAtom.MANATYPES) {
|
||||
if (chosen.getManaPartRecursive().getOrigProduced().contains(MagicColor.toShortString(color))
|
||||
&& colors.hasAnyColor(color)) {
|
||||
if (chosen.canProduce(MagicColor.toShortString(color)) && colors.hasAnyColor(color)) {
|
||||
producedColorMask |= color;
|
||||
}
|
||||
}
|
||||
ColorSet producedAndNeededColors = ColorSet.fromMask(producedColorMask);
|
||||
|
||||
chosen.getManaPartRecursive().setExpressChoice(producedAndNeededColors);
|
||||
chosen.setManaExpressChoice(producedAndNeededColors);
|
||||
|
||||
// System.out.println("Chosen sa=" + chosen + " of " + chosen.getHostCard() + " to pay mana");
|
||||
|
||||
@@ -344,62 +341,6 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
||||
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() {
|
||||
if (manaCost.isPaid()) {
|
||||
bPaid = true;
|
||||
|
||||
@@ -33,6 +33,7 @@ import forge.game.event.GameEventTokenCreated;
|
||||
import forge.game.event.GameEventTurnEnded;
|
||||
import forge.game.event.GameEventZone;
|
||||
import forge.game.event.IGameEventVisitor;
|
||||
import forge.game.spellability.AbilityManaPart;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.TextUtil;
|
||||
@@ -179,10 +180,10 @@ public class EventVisualizer extends IGameEventVisitor.Base<SoundEffectType> imp
|
||||
@Override
|
||||
public SoundEffectType visit(final GameEventLandPlayed event) {
|
||||
SoundEffectType resultSound = null;
|
||||
return resultSound;
|
||||
return resultSound;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public SoundEffectType visit(GameEventZone event) {
|
||||
Card card = event.card;
|
||||
@@ -208,10 +209,13 @@ 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
|
||||
StringBuilder fullManaColors = new StringBuilder();
|
||||
for (final SpellAbility sa : land.getManaAbilities()) {
|
||||
String currManaColor = sa.getManaPartRecursive().getOrigProduced();
|
||||
if(!"C".equals(currManaColor)) {
|
||||
fullManaColors.append(currManaColor);
|
||||
for (AbilityManaPart mp : sa.getAllManaParts()) {
|
||||
String currManaColor = mp.getOrigProduced();
|
||||
if(!"C".equals(currManaColor)) {
|
||||
fullManaColors.append(currManaColor);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// No interest if "colors together" or "alternative colors" - only interested in colors themselves
|
||||
fullManaColors = new StringBuilder(TextUtil.fastReplace(fullManaColors.toString()," ", ""));
|
||||
|
||||
Reference in New Issue
Block a user