mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 12:48:00 +00:00
- Fixing Autopay/AI payment of cards like Holdout Settlement
This commit is contained in:
@@ -105,30 +105,7 @@ public class ComputerUtilMana {
|
|||||||
for (SpellAbility ability : card.getSpellAbilities()) {
|
for (SpellAbility ability : card.getSpellAbilities()) {
|
||||||
ability.setActivatingPlayer(card.getController());
|
ability.setActivatingPlayer(card.getController());
|
||||||
if (ability.isManaAbility()) {
|
if (ability.isManaAbility()) {
|
||||||
if (ability.getManaPart() == null) {
|
score += ability.calculateScoreForManaAbility(ability);
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (!ability.isTrigger() && ability.isPossible()) {
|
else if (!ability.isTrigger() && ability.isPossible()) {
|
||||||
score += 13; //add 13 for any non-mana activated abilities
|
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());
|
int preOrder = orderedCards.indexOf(ability1.getHostCard()) - orderedCards.indexOf(ability2.getHostCard());
|
||||||
|
|
||||||
if (preOrder == 0) {
|
if (preOrder == 0) {
|
||||||
|
// Mana abilities on the same card
|
||||||
String shardMana = shard.toString().replaceAll("\\{", "").replaceAll("\\}", "");
|
String shardMana = shard.toString().replaceAll("\\{", "").replaceAll("\\}", "");
|
||||||
|
|
||||||
if (ability1.getManaPart().mana().contains(shardMana)
|
boolean payWithAb1 = ability1.getManaPart().mana().contains(shardMana);
|
||||||
&& !ability2.getManaPart().mana().contains(shardMana)) {
|
boolean payWithAb2 = ability2.getManaPart().mana().contains(shardMana);
|
||||||
|
|
||||||
|
if (payWithAb1 && !payWithAb2) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} else if (payWithAb2 && !payWithAb1) {
|
||||||
if (ability2.getManaPart().mana().contains(shardMana)
|
|
||||||
&& !ability1.getManaPart().mana().contains(shardMana)) {
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return ability1.compareTo(ability2);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return preOrder;
|
return preOrder;
|
||||||
@@ -941,7 +919,7 @@ public class ComputerUtilMana {
|
|||||||
if (ai.getManaPool().canPayForShardWithColor(shard, colorint.byteValue())) {
|
if (ai.getManaPool().canPayForShardWithColor(shard, colorint.byteValue())) {
|
||||||
for (SpellAbility sa : manaAbilityMap.get(colorint)) {
|
for (SpellAbility sa : manaAbilityMap.get(colorint)) {
|
||||||
if (!res.get(shard).contains(sa)) {
|
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();
|
AbilityManaPart mp = m.getManaPart();
|
||||||
|
|
||||||
// setup produce mana replacement effects
|
// setup produce mana replacement effects
|
||||||
@@ -1201,25 +1179,25 @@ public class ComputerUtilMana {
|
|||||||
Set<String> reflectedColors = CardUtil.getReflectableManaColors(m);
|
Set<String> reflectedColors = CardUtil.getReflectableManaColors(m);
|
||||||
// find possible colors
|
// find possible colors
|
||||||
if (mp.canProduce("W", m) || reflectedColors.contains(MagicColor.Constant.WHITE)) {
|
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)) {
|
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)) {
|
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)) {
|
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)) {
|
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)) {
|
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()) {
|
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) {
|
if (DEBUG_MANA_PAYMENT) {
|
||||||
System.out.println("DEBUG_MANA_PAYMENT: groupSourcesByManaColor manaMap = " + manaMap);
|
System.out.println("DEBUG_MANA_PAYMENT: groupSourcesByManaColor manaMap = " + manaMap);
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ public enum ManaCostShard {
|
|||||||
BLACK(ManaAtom.BLACK, "B"),
|
BLACK(ManaAtom.BLACK, "B"),
|
||||||
RED(ManaAtom.RED, "R"),
|
RED(ManaAtom.RED, "R"),
|
||||||
GREEN(ManaAtom.GREEN, "G"),
|
GREEN(ManaAtom.GREEN, "G"),
|
||||||
|
COLORLESS(ManaAtom.COLORLESS, "C"),
|
||||||
|
|
||||||
/* Hybrid */
|
/* Hybrid */
|
||||||
WU(ManaAtom.WHITE | ManaAtom.BLUE, "W/U", "WU"),
|
WU(ManaAtom.WHITE | ManaAtom.BLUE, "W/U", "WU"),
|
||||||
@@ -44,7 +45,7 @@ public enum ManaCostShard {
|
|||||||
GW(ManaAtom.GREEN | ManaAtom.WHITE, "G/W", "GW"),
|
GW(ManaAtom.GREEN | ManaAtom.WHITE, "G/W", "GW"),
|
||||||
GU(ManaAtom.GREEN | ManaAtom.BLUE, "G/U", "GU"),
|
GU(ManaAtom.GREEN | ManaAtom.BLUE, "G/U", "GU"),
|
||||||
|
|
||||||
/* Or 2 colorless */
|
/* Or 2 generic */
|
||||||
W2(ManaAtom.WHITE | ManaAtom.OR_2_GENERIC, "2/W", "2W"),
|
W2(ManaAtom.WHITE | ManaAtom.OR_2_GENERIC, "2/W", "2W"),
|
||||||
U2(ManaAtom.BLUE | ManaAtom.OR_2_GENERIC, "2/U", "2U"),
|
U2(ManaAtom.BLUE | ManaAtom.OR_2_GENERIC, "2/U", "2U"),
|
||||||
B2(ManaAtom.BLACK | ManaAtom.OR_2_GENERIC, "2/B", "2B"),
|
B2(ManaAtom.BLACK | ManaAtom.OR_2_GENERIC, "2/B", "2B"),
|
||||||
@@ -54,7 +55,7 @@ public enum ManaCostShard {
|
|||||||
// Snow and colorless
|
// Snow and colorless
|
||||||
S(ManaAtom.IS_SNOW, "S"),
|
S(ManaAtom.IS_SNOW, "S"),
|
||||||
GENERIC(ManaAtom.GENERIC, "1"),
|
GENERIC(ManaAtom.GENERIC, "1"),
|
||||||
COLORLESS(ManaAtom.COLORLESS, "C"),
|
|
||||||
|
|
||||||
/* Phyrexian */
|
/* Phyrexian */
|
||||||
PW(ManaAtom.WHITE | ManaAtom.OR_2_LIFE, "P/W", "PW"),
|
PW(ManaAtom.WHITE | ManaAtom.OR_2_LIFE, "P/W", "PW"),
|
||||||
|
|||||||
@@ -479,7 +479,8 @@ public class AbilityManaPart implements java.io.Serializable {
|
|||||||
* @return a boolean.
|
* @return a boolean.
|
||||||
*/
|
*/
|
||||||
public final boolean canProduce(final String s, final SpellAbility sa) {
|
public final boolean canProduce(final String s, final SpellAbility sa) {
|
||||||
if (isAnyMana()) {
|
// Any mana never means Colorless?
|
||||||
|
if (isAnyMana() && !s.equals("C")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -630,6 +631,7 @@ public class AbilityManaPart implements java.io.Serializable {
|
|||||||
// Replace any type
|
// Replace any type
|
||||||
for (String part : manaReplace.split(" & ")) {
|
for (String part : manaReplace.split(" & ")) {
|
||||||
final String[] v = splitter.split(part, 2);
|
final String[] v = splitter.split(part, 2);
|
||||||
|
// TODO Colorless mana replacement is probably different now?
|
||||||
if (v[0].equals("Colorless")) {
|
if (v[0].equals("Colorless")) {
|
||||||
repMap.put("[0-9][0-9]?", v.length > 1 ? v[1].trim() : "");
|
repMap.put("[0-9][0-9]?", v.length > 1 ? v[1].trim() : "");
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import forge.game.card.Card;
|
|||||||
import forge.game.card.CardCollection;
|
import forge.game.card.CardCollection;
|
||||||
import forge.game.card.CardCollectionView;
|
import forge.game.card.CardCollectionView;
|
||||||
import forge.game.cost.Cost;
|
import forge.game.cost.Cost;
|
||||||
|
import forge.game.cost.CostPart;
|
||||||
import forge.game.cost.CostPartMana;
|
import forge.game.cost.CostPartMana;
|
||||||
import forge.game.mana.Mana;
|
import forge.game.mana.Mana;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
@@ -54,7 +55,7 @@ import java.util.*;
|
|||||||
* @author Forge
|
* @author Forge
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
*/
|
*/
|
||||||
public abstract class SpellAbility extends CardTraitBase implements ISpellAbility, IIdentifiable {
|
public abstract class SpellAbility extends CardTraitBase implements ISpellAbility, IIdentifiable, Comparable<SpellAbility> {
|
||||||
private static int maxId = 0;
|
private static int maxId = 0;
|
||||||
private static int nextId() { return ++maxId; }
|
private static int nextId() { return ++maxId; }
|
||||||
|
|
||||||
@@ -1308,4 +1309,51 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
view.updatePromptIfOnlyPossibleAbility(this);
|
view.updatePromptIfOnlyPossibleAbility(this);
|
||||||
return view;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user