From cb14b2ef80a4e8779e1569acd4f0a527aec732a1 Mon Sep 17 00:00:00 2001 From: Sol Date: Sun, 17 Jan 2016 03:18:39 +0000 Subject: [PATCH] - Fixing Autopay/AI payment of cards like Holdout Settlement --- .../main/java/forge/ai/ComputerUtilMana.java | 56 ++++++------------- .../java/forge/card/mana/ManaCostShard.java | 5 +- .../game/spellability/AbilityManaPart.java | 4 +- .../forge/game/spellability/SpellAbility.java | 50 ++++++++++++++++- 4 files changed, 72 insertions(+), 43 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java index 7e8a8265d8a..5686fe83afb 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java @@ -105,30 +105,7 @@ public class ComputerUtilMana { for (SpellAbility ability : card.getSpellAbilities()) { ability.setActivatingPlayer(card.getController()); if (ability.isManaAbility()) { - if (ability.getManaPart() == null) { - score++; //Assume a mana ability can generate at least 1 mana if the amount of mana can't be determined now. - } - else { - String mana = ability.getManaPart().mana(); - if (!mana.equals("Any")) { - score += mana.length(); - } - else { - score += 6; - } - } - //increase score if any part of ability's cost is not reusable or renewable (such as paying life) - for (CostPart costPart : ability.getPayCosts().getCostParts()) { - if (!costPart.isReusable()) { - score += 3; - } - if (!costPart.isRenewable()) { - score += 3; - } - } - if (!ability.isUndoable()) { - score += 50; //only use non-undoable mana abilities as a last resort - } + score += ability.calculateScoreForManaAbility(ability); } else if (!ability.isTrigger() && ability.isPossible()) { score += 13; //add 13 for any non-mana activated abilities @@ -189,18 +166,19 @@ public class ComputerUtilMana { int preOrder = orderedCards.indexOf(ability1.getHostCard()) - orderedCards.indexOf(ability2.getHostCard()); if (preOrder == 0) { + // Mana abilities on the same card String shardMana = shard.toString().replaceAll("\\{", "").replaceAll("\\}", ""); - if (ability1.getManaPart().mana().contains(shardMana) - && !ability2.getManaPart().mana().contains(shardMana)) { + boolean payWithAb1 = ability1.getManaPart().mana().contains(shardMana); + boolean payWithAb2 = ability2.getManaPart().mana().contains(shardMana); + + if (payWithAb1 && !payWithAb2) { return -1; - } - if (ability2.getManaPart().mana().contains(shardMana) - && !ability1.getManaPart().mana().contains(shardMana)) { + } else if (payWithAb2 && !payWithAb1) { return 1; } - return 0; + return ability1.compareTo(ability2); } else { return preOrder; @@ -941,7 +919,7 @@ public class ComputerUtilMana { if (ai.getManaPool().canPayForShardWithColor(shard, colorint.byteValue())) { for (SpellAbility sa : manaAbilityMap.get(colorint)) { if (!res.get(shard).contains(sa)) { - res.get(shard).add(res.get(shard).size(), sa); + res.get(shard).add(sa); } } } @@ -1176,7 +1154,7 @@ public class ComputerUtilMana { } } - manaMap.get(ManaAtom.GENERIC).add(manaMap.get(ManaAtom.GENERIC).size(), m); // add to generic source list + manaMap.get(ManaAtom.GENERIC).add(m); // add to generic source list AbilityManaPart mp = m.getManaPart(); // setup produce mana replacement effects @@ -1201,25 +1179,25 @@ public class ComputerUtilMana { Set reflectedColors = CardUtil.getReflectableManaColors(m); // find possible colors if (mp.canProduce("W", m) || reflectedColors.contains(MagicColor.Constant.WHITE)) { - manaMap.get(ManaAtom.WHITE).add(manaMap.get(ManaAtom.WHITE).size(), m); + manaMap.get(ManaAtom.WHITE).add(m); } if (mp.canProduce("U", m) || reflectedColors.contains(MagicColor.Constant.BLUE)) { - manaMap.get(ManaAtom.BLUE).add(manaMap.get(ManaAtom.BLUE).size(), m); + manaMap.get(ManaAtom.BLUE).add(m); } if (mp.canProduce("B", m) || reflectedColors.contains(MagicColor.Constant.BLACK)) { - manaMap.get(ManaAtom.BLACK).add(manaMap.get(ManaAtom.BLACK).size(), m); + manaMap.get(ManaAtom.BLACK).add(m); } if (mp.canProduce("R", m) || reflectedColors.contains(MagicColor.Constant.RED)) { - manaMap.get(ManaAtom.RED).add(manaMap.get(ManaAtom.RED).size(), m); + manaMap.get(ManaAtom.RED).add(m); } if (mp.canProduce("G", m) || reflectedColors.contains(MagicColor.Constant.GREEN)) { - manaMap.get(ManaAtom.GREEN).add(manaMap.get(ManaAtom.GREEN).size(), m); + manaMap.get(ManaAtom.GREEN).add(m); } if (mp.canProduce("C", m) || reflectedColors.contains(MagicColor.Constant.COLORLESS)) { - manaMap.get(ManaAtom.COLORLESS).add(manaMap.get(ManaAtom.COLORLESS).size(), m); + manaMap.get(ManaAtom.COLORLESS).add(m); } if (mp.isSnow()) { - manaMap.get(ManaAtom.IS_SNOW).add(manaMap.get(ManaAtom.IS_SNOW).size(), m); + manaMap.get(ManaAtom.IS_SNOW).add(m); } if (DEBUG_MANA_PAYMENT) { System.out.println("DEBUG_MANA_PAYMENT: groupSourcesByManaColor manaMap = " + manaMap); diff --git a/forge-core/src/main/java/forge/card/mana/ManaCostShard.java b/forge-core/src/main/java/forge/card/mana/ManaCostShard.java index 8683d89eff6..51c8fb4a327 100644 --- a/forge-core/src/main/java/forge/card/mana/ManaCostShard.java +++ b/forge-core/src/main/java/forge/card/mana/ManaCostShard.java @@ -31,6 +31,7 @@ public enum ManaCostShard { BLACK(ManaAtom.BLACK, "B"), RED(ManaAtom.RED, "R"), GREEN(ManaAtom.GREEN, "G"), + COLORLESS(ManaAtom.COLORLESS, "C"), /* Hybrid */ WU(ManaAtom.WHITE | ManaAtom.BLUE, "W/U", "WU"), @@ -44,7 +45,7 @@ public enum ManaCostShard { GW(ManaAtom.GREEN | ManaAtom.WHITE, "G/W", "GW"), GU(ManaAtom.GREEN | ManaAtom.BLUE, "G/U", "GU"), - /* Or 2 colorless */ + /* Or 2 generic */ W2(ManaAtom.WHITE | ManaAtom.OR_2_GENERIC, "2/W", "2W"), U2(ManaAtom.BLUE | ManaAtom.OR_2_GENERIC, "2/U", "2U"), B2(ManaAtom.BLACK | ManaAtom.OR_2_GENERIC, "2/B", "2B"), @@ -54,7 +55,7 @@ public enum ManaCostShard { // Snow and colorless S(ManaAtom.IS_SNOW, "S"), GENERIC(ManaAtom.GENERIC, "1"), - COLORLESS(ManaAtom.COLORLESS, "C"), + /* Phyrexian */ PW(ManaAtom.WHITE | ManaAtom.OR_2_LIFE, "P/W", "PW"), diff --git a/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java b/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java index 972dd2e526a..524b060c22a 100644 --- a/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java +++ b/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java @@ -479,7 +479,8 @@ public class AbilityManaPart implements java.io.Serializable { * @return a boolean. */ public final boolean canProduce(final String s, final SpellAbility sa) { - if (isAnyMana()) { + // Any mana never means Colorless? + if (isAnyMana() && !s.equals("C")) { return true; } @@ -630,6 +631,7 @@ public class AbilityManaPart implements java.io.Serializable { // 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 { diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java index 023cf0049e3..1aa452b1102 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -32,6 +32,7 @@ import forge.game.card.Card; import forge.game.card.CardCollection; import forge.game.card.CardCollectionView; import forge.game.cost.Cost; +import forge.game.cost.CostPart; import forge.game.cost.CostPartMana; import forge.game.mana.Mana; import forge.game.player.Player; @@ -54,7 +55,7 @@ import java.util.*; * @author Forge * @version $Id$ */ -public abstract class SpellAbility extends CardTraitBase implements ISpellAbility, IIdentifiable { +public abstract class SpellAbility extends CardTraitBase implements ISpellAbility, IIdentifiable, Comparable { private static int maxId = 0; private static int nextId() { return ++maxId; } @@ -1308,4 +1309,51 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit view.updatePromptIfOnlyPossibleAbility(this); return view; } + + @Override + public int compareTo(SpellAbility ab) { + if (this.isManaAbility() && ab.isManaAbility()){ + return calculateScoreForManaAbility(this) - calculateScoreForManaAbility(ab); + } + + return 0; + } + + public static int calculateScoreForManaAbility(SpellAbility ability) { + int score = 0; + if (ability.getManaPart() == null) { + score++; //Assume a mana ability can generate at least 1 mana if the amount of mana can't be determined now. + } + else { + String mana = ability.getManaPart().mana(); + if (!mana.equals("Any")) { + score += mana.length(); + } + else { + score += 6; + } + } + + //increase score if any part of ability's cost is not reusable or renewable (such as paying life) + for (CostPart costPart : ability.getPayCosts().getCostParts()) { + if (!costPart.isReusable()) { + score += 3; + } + if (!costPart.isRenewable()) { + score += 3; + } + // Increase score by 1 for each costpart in general + score++; + } + + if (!ability.isUndoable()) { + score += 50; //only use non-undoable mana abilities as a last resort + } + if (ability.getSubAbility() != null) { + // If the primary ability has a sub, it's probably "more expensive" + score += 2; + } + + return score; + } } \ No newline at end of file