Don't transform X shards of UnlessCost before paying (#5041)

* Refactor fake X shard on UnlessCost
This commit is contained in:
tool4ever
2024-04-15 10:07:56 +02:00
committed by GitHub
parent af0da10fc9
commit 04b995ed7e
41 changed files with 157 additions and 158 deletions

View File

@@ -1415,77 +1415,12 @@ public class AbilityUtils {
final boolean execSubsWhenNotPaid = "WhenNotPaid".equals(resolveSubs) || StringUtils.isBlank(resolveSubs);
final boolean isSwitched = sa.hasParam("UnlessSwitched");
// The cost
Cost cost;
String unlessCost = sa.getParam("UnlessCost").trim();
if (unlessCost.equals("CardManaCost")) {
cost = new Cost(source.getManaCost(), true);
}
else if (unlessCost.equals("ChosenManaCost")) {
if (!source.hasChosenCard()) {
cost = new Cost(ManaCost.ZERO, true);
} else {
cost = new Cost(Iterables.getFirst(source.getChosenCards(), null).getManaCost(), true);
}
}
else if (unlessCost.equals("ChosenNumber")) {
cost = new Cost(new ManaCost(new ManaCostParser(String.valueOf(source.getChosenNumber()))), true);
}
else if (unlessCost.startsWith("DefinedCost")) {
CardCollection definedCards = getDefinedCards(source, unlessCost.split("_")[1], sa);
if (definedCards.isEmpty()) {
sa.resolve();
resolveSubAbilities(sa, game);
return;
}
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")) {
int max = Integer.parseInt(modifier.substring(5));
if (sa.hasParam("UnlessUpTo")) { // Flash
max = allPayers.get(0).getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblChooseNumber"), 0, max);
}
newCost.decreaseGenericMana(max);
} else {
newCost.increaseGenericMana(Integer.parseInt(modifier.substring(4)));
}
}
cost = new Cost(newCost.toManaCost(), true);
}
else if (unlessCost.startsWith("DefinedSACost")) {
FCollection<SpellAbility> definedSAs = getDefinedSpellAbilities(source, 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"),
" ", ""), sa);
//Check for XColor
ManaCostBeingPaid toPay = new ManaCostBeingPaid(ManaCost.ZERO);
byte xColor = ManaAtom.fromName(sa.getParamOrDefault("UnlessXColor", "1"));
toPay.increaseShard(ManaCostShard.valueOf(xColor), xCost);
cost = new Cost(toPay.toManaCost(), true);
}
else {
cost = new Cost(unlessCost, true);
Cost cost = calculateUnlessCost(sa, unlessCost, true);
if (cost == null) {
sa.resolve();
resolveSubAbilities(sa, game);
return;
}
boolean alreadyPaid = false;
@@ -1510,6 +1445,67 @@ public class AbilityUtils {
}
}
public static Cost calculateUnlessCost(SpellAbility sa, String unlessCost, boolean beforePayment) {
final Card source = sa.getHostCard();
Cost cost;
if (unlessCost.equals("ChosenNumber")) {
cost = new Cost(new ManaCost(new ManaCostParser(String.valueOf(source.getChosenNumber()))), true);
}
else if (unlessCost.startsWith("DefinedCost")) {
CardCollection definedCards = getDefinedCards(source, unlessCost.split("_")[1], sa);
if (definedCards.isEmpty()) {
return null;
}
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")) {
int max = Integer.parseInt(modifier.substring(5));
if (sa.hasParam("UnlessUpTo") && beforePayment) { // Flash
max = sa.getActivatingPlayer().getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblChooseNumber"), 0, max);
}
newCost.decreaseGenericMana(max);
} else {
newCost.increaseGenericMana(Integer.parseInt(modifier.substring(4)));
}
}
cost = new Cost(newCost.toManaCost(), true);
}
else if (unlessCost.startsWith("DefinedSACost")) {
FCollection<SpellAbility> definedSAs = getDefinedSpellAbilities(source, unlessCost.split("_")[1], sa);
if (definedSAs.isEmpty()) {
return null;
}
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)) && !unlessCost.equals("X")) {
// check for non-X costs (stored in SVars
int xCost = calculateAmount(source, TextUtil.fastReplace(sa.getParam("UnlessCost"),
" ", ""), sa);
//Check for XColor
ManaCostBeingPaid toPay = new ManaCostBeingPaid(ManaCost.ZERO);
byte xColor = ManaAtom.fromName(sa.getParamOrDefault("UnlessColor", "1"));
toPay.increaseShard(ManaCostShard.valueOf(xColor), xCost);
cost = new Cost(toPay.toManaCost(), true);
}
else {
cost = new Cost(unlessCost, true);
}
return cost;
}
/**
* <p>
* handleRemembering.

View File

@@ -54,7 +54,7 @@ public class ManaRefundService {
payingAbilities.clear();
// update battlefield of all activating players - to redraw cards used to pay mana as untapped
for(Player p : payers) {
for (Player p : payers) {
p.getGame().fireEvent(new GameEventZone(ZoneType.Battlefield, p, EventValueChangeType.ComplexUpdate, null));
}
}

View File

@@ -32,10 +32,12 @@ import forge.game.Game;
import forge.game.GameActionUtil;
import forge.game.IHasSVars;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardUtil;
import forge.game.cost.Cost;
import forge.game.mana.Mana;
import forge.game.mana.ManaPool;
import forge.game.player.Player;
@@ -389,10 +391,19 @@ public class AbilityManaPart implements java.io.Serializable {
}
if (restriction.startsWith("CostContains")) {
if (restriction.endsWith("X") && sa.costHasManaX()) {
Game game = sa.getHostCard().getGame();
Cost payment = sa.getPayCosts();
if (game.getStack().isResolving() && sa.hasParam("UnlessCost")) {
payment = AbilityUtils.calculateUnlessCost(sa, sa.getParam("UnlessCost"), false);
}
if (payment.hasNoManaCost()) {
continue;
}
// TODO Thassa's Intervention with "twice {X}" is tricky
if (restriction.endsWith("X") && payment.getCostMana().getAmountOfX() > 0) {
return true;
}
if (restriction.endsWith("C") && sa.getPayCosts().hasManaCost() && sa.getPayCosts().getCostMana().getMana().getShardCount(ManaCostShard.COLORLESS) > 0) {
if (restriction.endsWith("C") && payment.getCostMana().getMana().getShardCount(ManaCostShard.COLORLESS) > 0) {
return true;
}
continue;

View File

@@ -191,6 +191,13 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
bResolving = b;
}
public final boolean isResolving(Card c) {
if (!isResolving() || curResolvingCard == null) {
return false;
}
return c.equals(curResolvingCard);
}
public final boolean canUndo(Player player) {
return undoStackOwner == player;
}
@@ -937,13 +944,6 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
}
}
public final boolean isResolving(Card c) {
if (!isResolving() || curResolvingCard == null) {
return false;
}
return c.equals(curResolvingCard);
}
public final boolean hasSourceOnStack(final Card source, final Predicate<SpellAbility> pred) {
if (source == null) {
return false;