Merge branch 'thrivingMana' into 'master'

AbilityManaPart: support 'Combo X Chosen' Mana Part for Thriving Lands

See merge request core-developers/forge!6048
This commit is contained in:
Michael Kamensky
2022-01-15 13:13:24 +00:00
11 changed files with 61 additions and 96 deletions

View File

@@ -156,8 +156,8 @@ public class ComputerUtilMana {
// Mana abilities on the same card // Mana abilities on the same card
String shardMana = shard.toString().replaceAll("\\{", "").replaceAll("\\}", ""); String shardMana = shard.toString().replaceAll("\\{", "").replaceAll("\\}", "");
boolean payWithAb1 = ability1.getManaPart().mana().contains(shardMana); boolean payWithAb1 = ability1.getManaPart().mana(ability1).contains(shardMana);
boolean payWithAb2 = ability2.getManaPart().mana().contains(shardMana); boolean payWithAb2 = ability2.getManaPart().mana(ability2).contains(shardMana);
if (payWithAb1 && !payWithAb2) { if (payWithAb1 && !payWithAb2) {
return -1; return -1;
@@ -196,9 +196,9 @@ public class ComputerUtilMana {
Collections.sort(prefSortedAbilities, new Comparator<SpellAbility>() { Collections.sort(prefSortedAbilities, new Comparator<SpellAbility>() {
@Override @Override
public int compare(final SpellAbility ability1, final SpellAbility ability2) { public int compare(final SpellAbility ability1, final SpellAbility ability2) {
if (ability1.getManaPart().mana().contains(preferredShard)) if (ability1.getManaPart().mana(ability1).contains(preferredShard))
return -1; return -1;
else if (ability2.getManaPart().mana().contains(preferredShard)) else if (ability2.getManaPart().mana(ability2).contains(preferredShard))
return 1; return 1;
return 0; return 0;
@@ -207,9 +207,9 @@ public class ComputerUtilMana {
Collections.sort(otherSortedAbilities, new Comparator<SpellAbility>() { Collections.sort(otherSortedAbilities, new Comparator<SpellAbility>() {
@Override @Override
public int compare(final SpellAbility ability1, final SpellAbility ability2) { public int compare(final SpellAbility ability1, final SpellAbility ability2) {
if (ability1.getManaPart().mana().contains(preferredShard)) if (ability1.getManaPart().mana(ability1).contains(preferredShard))
return 1; return 1;
else if (ability2.getManaPart().mana().contains(preferredShard)) else if (ability2.getManaPart().mana(ability2).contains(preferredShard))
return -1; return -1;
return 0; return 0;
@@ -1021,7 +1021,7 @@ public class ComputerUtilMana {
} }
if (m.isComboMana()) { if (m.isComboMana()) {
for (String s : m.getComboColors().split(" ")) { for (String s : m.getComboColors(ma).split(" ")) {
if (toPay == ManaCostShard.COLORED_X && !ManaCostBeingPaid.canColoredXShardBePaidByColor(s, xManaCostPaidByColor)) { if (toPay == ManaCostShard.COLORED_X && !ManaCostBeingPaid.canColoredXShardBePaidByColor(s, xManaCostPaidByColor)) {
continue; continue;
} }
@@ -1048,7 +1048,7 @@ public class ComputerUtilMana {
} }
if (toPay == ManaCostShard.COLORED_X) { if (toPay == ManaCostShard.COLORED_X) {
for (String s : m.mana().split(" ")) { for (String s : m.mana(ma).split(" ")) {
if (ManaCostBeingPaid.canColoredXShardBePaidByColor(s, xManaCostPaidByColor)) { if (ManaCostBeingPaid.canColoredXShardBePaidByColor(s, xManaCostPaidByColor)) {
return true; return true;
} }
@@ -1164,7 +1164,7 @@ public class ComputerUtilMana {
if (abMana.isComboMana()) { if (abMana.isComboMana()) {
int amount = manaAb.hasParam("Amount") ? AbilityUtils.calculateAmount(source, manaAb.getParam("Amount"), manaAb) : 1; int amount = manaAb.hasParam("Amount") ? AbilityUtils.calculateAmount(source, manaAb.getParam("Amount"), manaAb) : 1;
final ManaCostBeingPaid testCost = new ManaCostBeingPaid(cost); final ManaCostBeingPaid testCost = new ManaCostBeingPaid(cost);
final String[] comboColors = abMana.getComboColors().split(" "); final String[] comboColors = abMana.getComboColors(manaAb).split(" ");
for (int nMana = 1; nMana <= amount; nMana++) { for (int nMana = 1; nMana <= amount; nMana++) {
String choice = ""; String choice = "";
// Use expressChoice first // Use expressChoice first
@@ -1198,7 +1198,7 @@ public class ComputerUtilMana {
} }
// check if combo mana can produce most common color in hand // check if combo mana can produce most common color in hand
String commonColor = ComputerUtilCard.getMostProminentColor(ai.getCardsIn(ZoneType.Hand)); String commonColor = ComputerUtilCard.getMostProminentColor(ai.getCardsIn(ZoneType.Hand));
if (!commonColor.isEmpty() && satisfiesColorChoice(abMana, choiceString, MagicColor.toShortString(commonColor)) && abMana.getComboColors().contains(MagicColor.toShortString(commonColor))) { if (!commonColor.isEmpty() && satisfiesColorChoice(abMana, choiceString, MagicColor.toShortString(commonColor)) && abMana.getComboColors(manaAb).contains(MagicColor.toShortString(commonColor))) {
choice = MagicColor.toShortString(commonColor); choice = MagicColor.toShortString(commonColor);
} else { } else {
// default to first available color // default to first available color
@@ -1536,7 +1536,7 @@ public class ComputerUtilMana {
} else if (producesAnyColor) { } else if (producesAnyColor) {
anyColorManaSources.add(card); anyColorManaSources.add(card);
} else if (usableManaAbilities == 1) { } else if (usableManaAbilities == 1) {
if (manaAbilities.get(0).getManaPart().mana().equals("C")) { if (manaAbilities.get(0).getManaPart().mana(manaAbilities.get(0)).equals("C")) {
colorlessManaSources.add(card); colorlessManaSources.add(card);
} else { } else {
oneManaSources.add(card); oneManaSources.add(card);

View File

@@ -733,7 +733,7 @@ public final class GameActionUtil {
} else if (abMana.isSpecialMana()) { } else if (abMana.isSpecialMana()) {
baseMana = abMana.getExpressChoice(); baseMana = abMana.getExpressChoice();
} else { } else {
baseMana = abMana.mana(); baseMana = abMana.mana(sa);
} }
if (sa.getSubAbility() != null) { if (sa.getSubAbility() != null) {

View File

@@ -54,7 +54,7 @@ public class ManaEffect extends SpellAbilityEffect {
int amount = sa.hasParam("Amount") ? AbilityUtils.calculateAmount(card, sa.getParam("Amount"), sa) : 1; int amount = sa.hasParam("Amount") ? AbilityUtils.calculateAmount(card, sa.getParam("Amount"), sa) : 1;
String express = abMana.getExpressChoice(); String express = abMana.getExpressChoice();
String[] colorsProduced = abMana.getComboColors().split(" "); String[] colorsProduced = abMana.getComboColors(sa).split(" ");
final StringBuilder choiceString = new StringBuilder(); final StringBuilder choiceString = new StringBuilder();
ColorSet colorOptions = ColorSet.fromNames(colorsProduced); ColorSet colorOptions = ColorSet.fromNames(colorsProduced);

View File

@@ -6,6 +6,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import forge.game.spellability.AbilityManaPart;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.util.*; import forge.util.*;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -1429,57 +1430,19 @@ public class CardView extends GameEntityView {
boolean cMana = false; boolean cMana = false;
int count = 0; int count = 0;
int basicLandTypes = 0; int basicLandTypes = 0;
if (!state.getManaAbilities().isEmpty()) { for (SpellAbility sa : state.getManaAbilities()) {
for (SpellAbility sa : state.getManaAbilities()) { if (sa == null)
if (sa == null || sa.getManaPart() == null) continue;
continue; for (AbilityManaPart mp : sa.getAllManaParts()) {
if (sa.getManaPart().isAnyMana()) { if (mp.isAnyMana()) {
anyMana = true; anyMana = true;
} }
if (sa.getManaPart().isComboMana()) {
String[] colorsProduced = sa.getManaPart().getComboColors().split(" "); String[] colorsProduced = mp.mana(sa).split(" ");
//todo improve this
for (final String s : colorsProduced) { //todo improve this
switch (s.toUpperCase()) { for (final String s : colorsProduced) {
case "R": switch (s.toUpperCase()) {
if (!rMana) {
count += 1;
rMana = true;
}
break;
case "G":
if (!gMana) {
count += 1;
gMana = true;
}
break;
case "B":
if (!bMana) {
count += 1;
bMana = true;
}
break;
case "U":
if (!uMana) {
count += 1;
uMana = true;
}
break;
case "W":
if (!wMana) {
count += 1;
wMana = true;
}
break;
case "C":
if (!cMana) {
cMana = true;
}
break;
}
}
} else {
switch (sa.getManaPart().getOrigProduced()) {
case "R": case "R":
if (!rMana) { if (!rMana) {
count += 1; count += 1;

View File

@@ -416,14 +416,15 @@ public class AbilityManaPart implements java.io.Serializable {
* *
* @return a {@link java.lang.String} object. * @return a {@link java.lang.String} object.
*/ */
public final String mana() { public final String mana(SpellAbility sa) {
if (this.getOrigProduced().contains("Chosen")) { if (isComboMana()) { // when asking combo, just go there
if (this.getSourceCard() != null && this.getSourceCard().hasChosenColor()) { return getComboColors(sa);
return MagicColor.toShortString(this.getSourceCard().getChosenColor());
}
return "";
} }
return this.getOrigProduced(); String produced = this.getOrigProduced();
if (produced.contains("Chosen")) {
produced = produced.replace("Chosen", this.getChosenColor(sa));
}
return produced;
} }
/** /**
@@ -488,7 +489,7 @@ public class AbilityManaPart implements java.io.Serializable {
} }
public boolean isComboMana() { public boolean isComboMana() {
return this.getOrigProduced().contains("Combo"); return this.getOrigProduced().startsWith("Combo");
} }
public boolean isSpecialMana() { public boolean isSpecialMana() {
@@ -506,22 +507,13 @@ public class AbilityManaPart implements java.io.Serializable {
*/ */
public final boolean canProduce(final String s, final SpellAbility sa) { public final boolean canProduce(final String s, final SpellAbility sa) {
// TODO: need to handle replacement effects like 106.7 // TODO: need to handle replacement effects like 106.7
// Any mana never means Colorless? // Any mana never means Colorless?
if (isAnyMana() && !s.equals("C")) { if (isAnyMana() && !s.equals("C")) {
return true; return true;
} }
String origProduced = getOrigProduced(); return mana(sa).contains(s);
if (origProduced.contains("Chosen") && sourceCard != null ) {
if (getSourceCard().hasChosenColor() && MagicColor.toShortString(getSourceCard().getChosenColor()).contains(s)) {
return true;
}
}
if (isComboMana()) {
return getComboColors().contains(s);
}
return origProduced.contains(s);
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@@ -553,14 +545,18 @@ public class AbilityManaPart implements java.io.Serializable {
/** /**
* @return the color available in combination mana * @return the color available in combination mana
*/ */
public String getComboColors() { public String getComboColors(SpellAbility sa) {
String origProduced = getOrigProduced(); String origProduced = getOrigProduced();
if (!origProduced.contains("Combo")) { if (!origProduced.startsWith("Combo")) {
return ""; return "";
} }
if (origProduced.contains("Any")) { if (origProduced.contains("Any")) {
return "W U B R G"; return "W U B R G";
} }
// replace Chosen for Combo colors
if (origProduced.contains("Chosen")) {
origProduced = origProduced.replace("Chosen", getChosenColor(sa));
}
if (!origProduced.contains("ColorIdentity")) { if (!origProduced.contains("ColorIdentity")) {
return TextUtil.fastReplace(origProduced, "Combo ", ""); return TextUtil.fastReplace(origProduced, "Combo ", "");
} }
@@ -582,6 +578,17 @@ public class AbilityManaPart implements java.io.Serializable {
return sb.length() == 0 ? "" : sb.substring(0, sb.length() - 1); return sb.length() == 0 ? "" : sb.substring(0, sb.length() - 1);
} }
public String getChosenColor(SpellAbility sa) {
if (sa == null) {
return "";
}
Card card = sa.getHostCard();
if (card != null && card.hasChosenColor()) {
return MagicColor.toShortString(card.getChosenColor());
}
return "";
}
public Card getSourceCard() { public Card getSourceCard() {
return sourceCard; return sourceCard;
} }
@@ -644,7 +651,7 @@ public class AbilityManaPart implements java.io.Serializable {
if (isSpecialMana()) { if (isSpecialMana()) {
return true; return true;
} }
String colorsProduced = isComboMana() ? getComboColors() : mana(); String colorsProduced = mana(am);
for (final String color : colorsProduced.split(" ")) { for (final String color : colorsProduced.split(" ")) {
if (0 != (neededColor & ManaAtom.fromName(color))) { if (0 != (neededColor & ManaAtom.fromName(color))) {
return true; return true;

View File

@@ -311,7 +311,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
result += amount; result += amount;
} else { } else {
// For cards that produce like {C}{R} vs cards that produce {R}{R}. // For cards that produce like {C}{R} vs cards that produce {R}{R}.
result += mp.mana().split(" ").length * amount; result += mp.mana(this).split(" ").length * amount;
} }
} }
return result; return result;
@@ -2246,7 +2246,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
if (manaPart == null) { if (manaPart == null) {
score++; //Assume a mana ability can generate at least 1 mana if the amount of mana can't be determined now. score++; //Assume a mana ability can generate at least 1 mana if the amount of mana can't be determined now.
} else { } else {
String mana = manaPart.mana(); String mana = manaPart.mana(this);
if (!mana.equals("Any")) { if (!mana.equals("Any")) {
score += mana.length(); score += mana.length();
if (!canProduce("C")) { if (!canProduce("C")) {

View File

@@ -4,6 +4,5 @@ Types:Land
K:CARDNAME enters the battlefield tapped. K:CARDNAME enters the battlefield tapped.
K:ETBReplacement:Other:ChooseColor K:ETBReplacement:Other:ChooseColor
SVar:ChooseColor:DB$ ChooseColor | Defined$ You | Exclude$ red | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a color other than red. SVar:ChooseColor:DB$ ChooseColor | Defined$ You | Exclude$ red | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a color other than red.
A:AB$ Mana | Cost$ T | Produced$ R | SpellDescription$ Add {R}. A:AB$ Mana | Cost$ T | Produced$ Combo R Chosen | SpellDescription$ Add {R} or one mana of the chosen color.
A:AB$ Mana | Cost$ T | Produced$ Chosen | SpellDescription$ Add one mana of the chosen color.
Oracle:Thriving Bluff enters the battlefield tapped.\nAs Thriving Bluff enters the battlefield, choose a color other than red.\n{T}: Add {R} or one mana of the chosen color. Oracle:Thriving Bluff enters the battlefield tapped.\nAs Thriving Bluff enters the battlefield, choose a color other than red.\n{T}: Add {R} or one mana of the chosen color.

View File

@@ -4,6 +4,5 @@ Types:Land
K:CARDNAME enters the battlefield tapped. K:CARDNAME enters the battlefield tapped.
K:ETBReplacement:Other:ChooseColor K:ETBReplacement:Other:ChooseColor
SVar:ChooseColor:DB$ ChooseColor | Defined$ You | Exclude$ green | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a color other than green. SVar:ChooseColor:DB$ ChooseColor | Defined$ You | Exclude$ green | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a color other than green.
A:AB$ Mana | Cost$ T | Produced$ G | SpellDescription$ Add {G}. A:AB$ Mana | Cost$ T | Produced$ Combo G Chosen | SpellDescription$ Add {G} or one mana of the chosen color.
A:AB$ Mana | Cost$ T | Produced$ Chosen | SpellDescription$ Add one mana of the chosen color.
Oracle:Thriving Grove enters the battlefield tapped.\nAs Thriving Grove enters the battlefield, choose a color other than green.\n{T}: Add {G} or one mana of the chosen color. Oracle:Thriving Grove enters the battlefield tapped.\nAs Thriving Grove enters the battlefield, choose a color other than green.\n{T}: Add {G} or one mana of the chosen color.

View File

@@ -4,6 +4,5 @@ Types:Land
K:CARDNAME enters the battlefield tapped. K:CARDNAME enters the battlefield tapped.
K:ETBReplacement:Other:ChooseColor K:ETBReplacement:Other:ChooseColor
SVar:ChooseColor:DB$ ChooseColor | Defined$ You | Exclude$ white | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a color other than white. SVar:ChooseColor:DB$ ChooseColor | Defined$ You | Exclude$ white | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a color other than white.
A:AB$ Mana | Cost$ T | Produced$ W | SpellDescription$ Add {W}. A:AB$ Mana | Cost$ T | Produced$ Combo W Chosen | SpellDescription$ Add {W} or one mana of the chosen color.
A:AB$ Mana | Cost$ T | Produced$ Chosen | SpellDescription$ Add one mana of the chosen color.
Oracle:Thriving Heath enters the battlefield tapped.\nAs Thriving Heath enters the battlefield, choose a color other than white.\n{T}: Add {W} or one mana of the chosen color. Oracle:Thriving Heath enters the battlefield tapped.\nAs Thriving Heath enters the battlefield, choose a color other than white.\n{T}: Add {W} or one mana of the chosen color.

View File

@@ -4,6 +4,5 @@ Types:Land
K:CARDNAME enters the battlefield tapped. K:CARDNAME enters the battlefield tapped.
K:ETBReplacement:Other:ChooseColor K:ETBReplacement:Other:ChooseColor
SVar:ChooseColor:DB$ ChooseColor | Defined$ You | Exclude$ blue | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a color other than blue. SVar:ChooseColor:DB$ ChooseColor | Defined$ You | Exclude$ blue | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a color other than blue.
A:AB$ Mana | Cost$ T | Produced$ U | SpellDescription$ Add {U}. A:AB$ Mana | Cost$ T | Produced$ Combo U Chosen | SpellDescription$ Add {U} or one mana of the chosen color.
A:AB$ Mana | Cost$ T | Produced$ Chosen | SpellDescription$ Add one mana of the chosen color.
Oracle:Thriving Isle enters the battlefield tapped.\nAs Thriving Isle enters the battlefield, choose a color other than blue.\n{T}: Add {U} or one mana of the chosen color. Oracle:Thriving Isle enters the battlefield tapped.\nAs Thriving Isle enters the battlefield, choose a color other than blue.\n{T}: Add {U} or one mana of the chosen color.

View File

@@ -4,6 +4,5 @@ Types:Land
K:CARDNAME enters the battlefield tapped. K:CARDNAME enters the battlefield tapped.
K:ETBReplacement:Other:ChooseColor K:ETBReplacement:Other:ChooseColor
SVar:ChooseColor:DB$ ChooseColor | Defined$ You | Exclude$ black | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a color other than black. SVar:ChooseColor:DB$ ChooseColor | Defined$ You | Exclude$ black | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a color other than black.
A:AB$ Mana | Cost$ T | Produced$ B | SpellDescription$ Add {B}. A:AB$ Mana | Cost$ T | Produced$ Combo B Chosen | SpellDescription$ Add {B} or one mana of the chosen color.
A:AB$ Mana | Cost$ T | Produced$ Chosen | SpellDescription$ Add one mana of the chosen color.
Oracle:Thriving Moor enters the battlefield tapped.\nAs Thriving Moor enters the battlefield, choose a color other than black.\n{T}: Add {B} or one mana of the chosen color. Oracle:Thriving Moor enters the battlefield tapped.\nAs Thriving Moor enters the battlefield, choose a color other than black.\n{T}: Add {B} or one mana of the chosen color.