diff --git a/forge-core/src/main/java/forge/card/MagicColor.java b/forge-core/src/main/java/forge/card/MagicColor.java index 408b00d8080..13a73fb55d1 100644 --- a/forge-core/src/main/java/forge/card/MagicColor.java +++ b/forge-core/src/main/java/forge/card/MagicColor.java @@ -138,23 +138,11 @@ public final class MagicColor { public static final ImmutableList BASIC_LANDS = ImmutableList.of("Plains", "Island", "Swamp", "Mountain", "Forest"); public static final ImmutableList SNOW_LANDS = ImmutableList.of("Snow-Covered Plains", "Snow-Covered Island", "Snow-Covered Swamp", "Snow-Covered Mountain", "Snow-Covered Forest"); public static final ImmutableMap ANY_COLOR_CONVERSION = new ImmutableMap.Builder() - .put("ManaColorConversion", "Additive") - .put("WhiteConversion", "Color") - .put("BlueConversion", "Color") - .put("BlackConversion", "Color") - .put("RedConversion", "Color") - .put("GreenConversion", "Color") - .put("ColorlessConversion", "Color") + .put("ManaConversion", "AnyType->AnyColor") .build(); public static final ImmutableMap ANY_TYPE_CONVERSION = new ImmutableMap.Builder() - .put("ManaColorConversion", "Additive") - .put("WhiteConversion", "Type") - .put("BlueConversion", "Type") - .put("BlackConversion", "Type") - .put("RedConversion", "Type") - .put("GreenConversion", "Type") - .put("ColorlessConversion", "Type") + .put("ManaConversion", "AnyType->AnyType") .build(); /** * Private constructor to prevent instantiation. diff --git a/forge-core/src/main/java/forge/card/mana/ManaAtom.java b/forge-core/src/main/java/forge/card/mana/ManaAtom.java index 951f7fbf776..f04a90ac6f4 100644 --- a/forge-core/src/main/java/forge/card/mana/ManaAtom.java +++ b/forge-core/src/main/java/forge/card/mana/ManaAtom.java @@ -59,6 +59,18 @@ public abstract class ManaAtom { return 0; // generic } + public static byte fromConversion(String s) { + switch (s) { + case "AnyColor": return ALL_MANA_COLORS; + case "AnyType": return ALL_MANA_TYPES; + } + byte b = 0; + for (char c : s.toCharArray()) { + b |= fromName(c); + } + return b; + } + public static int getIndexOfFirstManaType(final byte color){ for (int i = 0; i < MANATYPES.length; i++) { if ((color & MANATYPES[i]) != 0) { diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index d010dd87c18..f9e56d059a3 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -1496,17 +1496,45 @@ public class AbilityUtils { else if (unlessCost.equals("ChosenNumber")) { cost = new Cost(new ManaCost(new ManaCostParser(String.valueOf(source.getChosenNumber()))), true); } - else if (unlessCost.equals("RememberedCostMinus2")) { - Card rememberedCard = (Card) source.getFirstRemembered(); - if (rememberedCard == null) { + else if (unlessCost.startsWith("DefinedCost")) { + CardCollection definedCards = AbilityUtils.getDefinedCards(sa.getHostCard(), unlessCost.split("_")[1], sa); + if (definedCards.isEmpty()) { sa.resolve(); resolveSubAbilities(sa, game); return; } - ManaCostBeingPaid newCost = new ManaCostBeingPaid(rememberedCard.getManaCost()); - newCost.decreaseGenericMana(2); + Card card = definedCards.getFirst(); + ManaCostBeingPaid newCost = new ManaCostBeingPaid(card.getManaCost()); + // Check if there's a third underscore for cost modifying + if (unlessCost.split("_").length == 3) { + String modifier = unlessCost.split("_")[2]; + if (modifier.startsWith("Minus")) { + newCost.decreaseGenericMana(Integer.parseInt(modifier.substring(5))); + } else { + newCost.increaseGenericMana(Integer.parseInt(modifier.substring(4))); + } + } cost = new Cost(newCost.toManaCost(), true); } + else if (unlessCost.startsWith("DefinedSACost")) { + FCollection definedSAs = AbilityUtils.getDefinedSpellAbilities(sa.getHostCard(), unlessCost.split("_")[1], sa); + if (definedSAs.isEmpty()) { + sa.resolve(); + resolveSubAbilities(sa, game); + return; + } + Card host = definedSAs.getFirst().getHostCard(); + if (host.getManaCost() == null) { + cost = new Cost(ManaCost.ZERO, true); + } else { + int xCount = host.getManaCost().countX(); + int xPaid = host.getXManaCostPaid() * xCount; + ManaCostBeingPaid toPay = new ManaCostBeingPaid(host.getManaCost()); + toPay.decreaseShard(ManaCostShard.X, xCount); + toPay.increaseGenericMana(xPaid); + cost = new Cost(toPay.toManaCost(), true); + } + } else if (!StringUtils.isBlank(sa.getSVar(unlessCost)) || !StringUtils.isBlank(source.getSVar(unlessCost))) { // check for X costs (stored in SVars int xCost = calculateAmount(source, TextUtil.fastReplace(sa.getParam("UnlessCost"), @@ -1864,30 +1892,19 @@ public class AbilityUtils { } public static final void applyManaColorConversion(ManaConversionMatrix matrix, final Map params) { - String conversionType = params.get("ManaColorConversion"); + String conversion = params.get("ManaConversion"); - // Choices are Additives(OR) or Restrictive(AND) - boolean additive = "Additive".equals(conversionType); + for (String pair : conversion.split(" ")) { + // Check if conversion is additive or restrictive and how to split + boolean additive = pair.contains("->"); + String[] sides = pair.split(additive ? "->" : "<-"); - for(String c : MagicColor.Constant.COLORS_AND_COLORLESS) { - // Use the strings from MagicColor, since that's how the Script will be coming in as - String key = StringUtils.capitalize(c) + "Conversion"; - if (params.containsKey(key)) { - String convertTo = params.get(key); - byte convertByte = 0; - if ("Type".equals(convertTo)) { - // IMPORTANT! We need to use Mana Color here not Card Color. - convertByte = ManaAtom.ALL_MANA_TYPES; - } else if ("Color".equals(convertTo)) { - // IMPORTANT! We need to use Mana Color here not Card Color. - convertByte = ManaAtom.ALL_MANA_COLORS; - } else { - for (final String convertColor : convertTo.split(",")) { - convertByte |= ManaAtom.fromName(convertColor); - } + if (sides[0].equals("AnyColor") || sides[0].equals("AnyType")) { + for (byte c : (sides[0].equals("AnyColor") ? MagicColor.WUBRG : MagicColor.WUBRGC)) { + matrix.adjustColorReplacement(c, ManaAtom.fromConversion(sides[1]), additive); } - // AdjustColorReplacement has two different matrices handling final mana conversion under the covers - matrix.adjustColorReplacement(ManaAtom.fromName(c), convertByte, additive); + } else { + matrix.adjustColorReplacement(ManaAtom.fromConversion(sides[0]), ManaAtom.fromConversion(sides[1]), additive); } } } diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 80fb8a21888..04523f5b091 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -1915,6 +1915,9 @@ public class Card extends GameEntity implements Comparable, IHasSVars { s.append(" on it."); } sbLong.append(s).append("\r\n"); + } else if (keyword.startsWith("ManaConvert")) { + final String[] k = keyword.split(":"); + sbLong.append(k[2]).append("\r\n"); } else if (keyword.startsWith("Protection:") || keyword.startsWith("DeckLimit")) { final String[] k = keyword.split(":"); sbLong.append(k[2]).append("\r\n"); diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java index 13bc3222651..84dd3759c70 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java @@ -591,7 +591,7 @@ public final class StaticAbilityContinuous { p.setMaxHandSize(p.getMaxHandSize() + rmax); } - if (params.containsKey("ManaColorConversion")) { + if (params.containsKey("ManaConversion")) { AbilityUtils.applyManaColorConversion(p.getManaPool(), params); } } diff --git a/forge-gui/res/cardsfolder/c/celestial_dawn.txt b/forge-gui/res/cardsfolder/c/celestial_dawn.txt index 0321d16c721..beb7c498d4f 100644 --- a/forge-gui/res/cardsfolder/c/celestial_dawn.txt +++ b/forge-gui/res/cardsfolder/c/celestial_dawn.txt @@ -4,9 +4,8 @@ Types:Enchantment S:Mode$ Continuous | Affected$ Land.YouCtrl | AddType$ Plains | RemoveLandTypes$ True | Description$ Lands you control are Plains. S:Mode$ Continuous | Affected$ Card.YouOwn+nonLand | SetColor$ White | AffectedZone$ Hand,Library,Graveyard,Exile,Command | Description$ Nonland permanents you control are white. The same is true for spells you control and nonland cards you own that aren't on the battlefield. S:Mode$ Continuous | Affected$ Card.YouCtrl+nonLand | SetColor$ White | AffectedZone$ Battlefield,Stack -S:Mode$ Continuous | Affected$ You | ManaColorConversion$ Additive | WhiteConversion$ Color | Description$ You may spend white mana as though it were mana of any color. -S:Mode$ Continuous | Affected$ You | ManaColorConversion$ Restrictive | BlueConversion$ Colorless | BlackConversion$ Colorless | RedConversion$ Colorless | GreenConversion$ Colorless | ColorlessConversion$ Colorless | Description$ You may spend other mana only as though it were colorless mana. +S:Mode$ Continuous | Affected$ You | ManaConversion$ W->AnyColor | Description$ You may spend white mana as though it were mana of any color. +S:Mode$ Continuous | Affected$ You | ManaConversion$ UBRG<-C | Description$ You may spend other mana only as though it were colorless mana. SVar:NonStackingEffect:True AI:RemoveDeck:Random -SVar:Picture:http://www.wizards.com/global/images/magic/general/celestial_dawn.jpg Oracle:Lands you control are Plains.\nNonland permanents you control are white. The same is true for spells you control and nonland cards you own that aren't on the battlefield.\nYou may spend white mana as though it were mana of any color. You may spend other mana only as though it were colorless mana. diff --git a/forge-gui/res/cardsfolder/c/chromatic_orrery.txt b/forge-gui/res/cardsfolder/c/chromatic_orrery.txt index 4dd331d7a08..25716f02691 100755 --- a/forge-gui/res/cardsfolder/c/chromatic_orrery.txt +++ b/forge-gui/res/cardsfolder/c/chromatic_orrery.txt @@ -1,7 +1,7 @@ Name:Chromatic Orrery ManaCost:7 Types:Legendary Artifact -S:Mode$ Continuous | Affected$ You | ManaColorConversion$ Additive | WhiteConversion$ Color | BlueConversion$ Color | BlackConversion$ Color | RedConversion$ Color | GreenConversion$ Color | ColorlessConversion$ Color | Description$ You may spend mana as though it were mana of any color. +S:Mode$ Continuous | Affected$ You | ManaConversion$ AnyType->AnyColor | Description$ You may spend mana as though it were mana of any color. SVar:NonStackingEffect:True A:AB$ Mana | Cost$ T | Produced$ C | Amount$ 5 | SpellDescription$ Add {C}{C}{C}{C}{C}. A:AB$ Draw | Cost$ 5 T | NumCards$ X | SpellDescription$ Draw a card for each color among permanents you control. diff --git a/forge-gui/res/cardsfolder/f/false_dawn.txt b/forge-gui/res/cardsfolder/f/false_dawn.txt index 53556221349..486b751db56 100644 --- a/forge-gui/res/cardsfolder/f/false_dawn.txt +++ b/forge-gui/res/cardsfolder/f/false_dawn.txt @@ -5,6 +5,6 @@ A:SP$ Effect | Cost$ 1 W | ReplacementEffects$ FDRep | StaticAbilities$ FDManaCo SVar:DBDraw:DB$ Draw | NumCards$ 1 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. +SVar:FDManaConvertion:Mode$ Continuous | EffectZone$ Command | Affected$ You | ManaConversion$ W->AnyColor | Description$ You may spend white mana as though it were mana of any color. AI:RemoveDeck:All Oracle:Until end of turn, spells and abilities you control that would add colored mana instead add that much white mana. Until end of turn, you may spend white mana as though it were mana of any color.\nDraw a card. diff --git a/forge-gui/res/cardsfolder/f/flash.txt b/forge-gui/res/cardsfolder/f/flash.txt index 70df31d4ff3..4b2ddd374da 100644 --- a/forge-gui/res/cardsfolder/f/flash.txt +++ b/forge-gui/res/cardsfolder/f/flash.txt @@ -2,8 +2,7 @@ Name:Flash ManaCost:1 U Types:Instant A:SP$ ChangeZone | Cost$ 1 U | Origin$ Hand | Destination$ Battlefield | ChangeType$ Creature | ChangeNum$ 1 | SubAbility$ DBSac | RememberChanged$ True | SpellDescription$ You may put a creature card from your hand onto the battlefield. If you do, sacrifice it unless you pay its mana cost reduced by up to {2}. -SVar:DBSac:DB$ SacrificeAll | Defined$ Remembered | UnlessCost$ RememberedCostMinus2 | UnlessPayer$ You | SubAbility$ DBCleanup +SVar:DBSac:DB$ SacrificeAll | Defined$ Remembered | UnlessCost$ DefinedCost_Remembered_Minus2 | UnlessPayer$ You | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True AI:RemoveDeck:All -SVar:Picture:http://www.wizards.com/global/images/magic/general/flash.jpg Oracle:You may put a creature card from your hand onto the battlefield. If you do, sacrifice it unless you pay its mana cost reduced by up to {2}. diff --git a/forge-gui/res/cardsfolder/i/ice_cave.txt b/forge-gui/res/cardsfolder/i/ice_cave.txt index 1057a2c36d6..db3a2b44a3e 100644 --- a/forge-gui/res/cardsfolder/i/ice_cave.txt +++ b/forge-gui/res/cardsfolder/i/ice_cave.txt @@ -2,6 +2,5 @@ Name:Ice Cave ManaCost:3 U U Types:Enchantment T:Mode$ SpellCast | ValidCard$ Card | TriggerZones$ Battlefield | Execute$ TrigCounter | TriggerDescription$ Whenever a player casts a spell, any other player may pay that spell's mana cost. If a player does, counter the spell. (Mana cost includes color.) -SVar:TrigCounter:DB$ Counter | Defined$ TriggeredSpellAbility | UnlessCost$ TriggeredSpellManaCost | UnlessPayer$ NonTriggeredCardController | UnlessSwitched$ True -SVar:Picture:http://www.wizards.com/global/images/magic/general/ice_cave.jpg +SVar:TrigCounter:DB$ Counter | Defined$ TriggeredSpellAbility | UnlessCost$ DefinedSACost_TriggeredSpellAbility | UnlessPayer$ NonTriggeredCardController | UnlessSwitched$ True Oracle:Whenever a player casts a spell, any other player may pay that spell's mana cost. If a player does, counter the spell. (Mana cost includes color.) diff --git a/forge-gui/res/cardsfolder/m/manascape_refractor.txt b/forge-gui/res/cardsfolder/m/manascape_refractor.txt index f22e8d8f583..fca84714a4b 100755 --- a/forge-gui/res/cardsfolder/m/manascape_refractor.txt +++ b/forge-gui/res/cardsfolder/m/manascape_refractor.txt @@ -2,12 +2,7 @@ Name:Manascape Refractor ManaCost:3 Types:Artifact K:CARDNAME enters the battlefield tapped. -K:ManaConvert:Black:All -K:ManaConvert:Blue:All -K:ManaConvert:Green:All -K:ManaConvert:Red:All -K:ManaConvert:White:All +K:ManaConvert:AnyType->AnyColor:You may spend mana as though it were mana of any color to pay the activation costs of CARDNAME's abilities. S:Mode$ Continuous | Affected$ Card.Self | EffectZone$ Battlefield | GainsAbilitiesOf$ Land | Description$ CARDNAME has all activated abilities of all lands on the battlefield. -Text:You may spend mana as though it were mana of any color to pay the activation costs of CARDNAME's abilities. AI:RemoveDeck:All Oracle:Manascape Refractor enters the battlefield tapped.\nManascape Refractor has all activated abilities of all lands on the battlefield.\nYou may spend mana as though it were mana of any color to pay the activation costs of Manascape Refractor's abilities. diff --git a/forge-gui/res/cardsfolder/m/mycosynth_lattice.txt b/forge-gui/res/cardsfolder/m/mycosynth_lattice.txt index bff1493b4cc..e56f91f4a87 100644 --- a/forge-gui/res/cardsfolder/m/mycosynth_lattice.txt +++ b/forge-gui/res/cardsfolder/m/mycosynth_lattice.txt @@ -3,8 +3,7 @@ ManaCost:6 Types:Artifact S:Mode$ Continuous | Affected$ Permanent | AddType$ Artifact | Description$ All permanents are artifact in addition to their other types. S:Mode$ Continuous| Affected$ Card | SetColor$ Colorless | AffectedZone$ Battlefield,Hand,Library,Graveyard,Exile,Stack,Command | Description$ All cards that aren't on the battlefield, spells, and permanents are colorless. -S:Mode$ Continuous | Affected$ Player | ManaColorConversion$ Additive | WhiteConversion$ Color | BlueConversion$ Color | BlackConversion$ Color | RedConversion$ Color | GreenConversion$ Color | ColorlessConversion$ Color | Description$ Players may spend mana as though it were mana of any color. +S:Mode$ Continuous | Affected$ Player | ManaConversion$ AnyType->AnyColor | Description$ Players may spend mana as though it were mana of any color. SVar:NonStackingEffect:True AI:RemoveDeck:Random -SVar:Picture:http://www.wizards.com/global/images/magic/general/mycosynth_lattice.jpg Oracle:All permanents are artifacts in addition to their other types.\nAll cards that aren't on the battlefield, spells, and permanents are colorless.\nPlayers may spend mana as though it were mana of any color. diff --git a/forge-gui/res/cardsfolder/q/quicksilver_elemental.txt b/forge-gui/res/cardsfolder/q/quicksilver_elemental.txt index 5735e9f915c..7ad2d66ebed 100644 --- a/forge-gui/res/cardsfolder/q/quicksilver_elemental.txt +++ b/forge-gui/res/cardsfolder/q/quicksilver_elemental.txt @@ -2,9 +2,8 @@ Name:Quicksilver Elemental ManaCost:3 U U Types:Creature Elemental PT:3/4 -K:ManaConvert:Blue:All +K:ManaConvert:U->AnyColor:You may spend blue mana as though it were mana of any color to pay the activation costs of CARDNAME's abilities. A:AB$ Effect | Cost$ U | ValidTgts$ Creature | TgtZone$ Battlefield | TgtPrompt$ Select target creature card | StaticAbilities$ STSteal | RememberObjects$ Targeted | SpellDescription$ CARDNAME gains all activated abilities of target creature until end of turn. -SVar:STSteal:Mode$ Continuous | Affected$ EffectSource | EffectZone$ Command | GainsAbilitiesOfDefined$ RememberedLKI | Description$ Quicksilver Elemental gains all activated abilities of that card until end of turn. +SVar:STSteal:Mode$ Continuous | Affected$ Card.EffectSource | EffectZone$ Command | GainsAbilitiesOfDefined$ RememberedLKI | Description$ Quicksilver Elemental gains all activated abilities of that card until end of turn. AI:RemoveDeck:All -SVar:Picture:http://www.wizards.com/global/images/magic/general/quicksilver_elemental.jpg Oracle:{U}: Quicksilver Elemental gains all activated abilities of target creature until end of turn. (If any of the abilities use that creature's name, use this creature's name instead.)\nYou may spend blue mana as though it were mana of any color to pay the activation costs of Quicksilver Elemental's abilities. diff --git a/forge-gui/res/cardsfolder/s/sunglasses_of_urza.txt b/forge-gui/res/cardsfolder/s/sunglasses_of_urza.txt index 62d4c2dd3bf..5cb606b55e5 100644 --- a/forge-gui/res/cardsfolder/s/sunglasses_of_urza.txt +++ b/forge-gui/res/cardsfolder/s/sunglasses_of_urza.txt @@ -1,8 +1,6 @@ Name:Sunglasses of Urza ManaCost:3 Types:Artifact -S:Mode$ Continuous | Affected$ You | ManaColorConversion$ Additive | WhiteConversion$ Red | Description$ You may spend white mana as though it were red mana. -AI:RemoveDeck:Random +S:Mode$ Continuous | Affected$ You | ManaConversion$ W->R | Description$ You may spend white mana as though it were red mana. AI:RemoveDeck:All -SVar:Picture:http://www.wizards.com/global/images/magic/general/sunglasses_of_urza.jpg Oracle:You may spend white mana as though it were red mana. diff --git a/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java b/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java index cccc0f3c3df..ad2e95121f6 100644 --- a/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java +++ b/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java @@ -93,11 +93,10 @@ public class HumanPlaySpellAbility { ability = GameActionUtil.addExtraKeywordCost(ability); if (ability.isSpell() && !ability.isCopied()) { // These hidden keywords should only apply on the Stack - final Card host = ability.getHostCard(); - if (host.hasKeyword("May spend mana as though it were mana of any type to cast CARDNAME") + if (c.hasKeyword("May spend mana as though it were mana of any type to cast CARDNAME") || (option != null && option.isIgnoreManaCostType())) { manaTypeConversion = true; - } else if (host.hasKeyword("May spend mana as though it were mana of any color to cast CARDNAME") + } else if (c.hasKeyword("May spend mana as though it were mana of any color to cast CARDNAME") || (option != null && option.isIgnoreManaCostColor())) { manaColorConversion = true; } @@ -127,13 +126,12 @@ public class HumanPlaySpellAbility { if (ability.isAbility() && ability.isActivatedAbility()) { final Map params = Maps.newHashMap(); - params.put("ManaColorConversion", "Additive"); for (KeywordInterface inst : c.getKeywords()) { String keyword = inst.getOriginal(); if (keyword.startsWith("ManaConvert")) { final String[] k = keyword.split(":"); - params.put(k[1] + "Conversion", k[2]); + params.put("ManaConversion", k[1]); keywordColor = true; } }