mirror of
https://github.com/correl/mage.git
synced 2024-11-14 19:19:32 +00:00
* Mana increase effects - fixed that some infinite mana combos gives 0 mana on too much permanents/effects (example: Nyxbloom Ancient);
This commit is contained in:
parent
cda79866ad
commit
2393485320
10 changed files with 165 additions and 103 deletions
|
@ -10,6 +10,7 @@ import mage.constants.*;
|
|||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ManaEvent;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -55,22 +56,22 @@ class ManaReflectionReplacementEffect extends ReplacementEffectImpl {
|
|||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
Mana mana = ((ManaEvent) event).getMana();
|
||||
if (mana.getBlack() > 0) {
|
||||
mana.set(ManaType.BLACK, mana.getBlack() * 2);
|
||||
mana.set(ManaType.BLACK, CardUtil.multiplyWithOverflowCheck(mana.getBlack(), 2));
|
||||
}
|
||||
if (mana.getBlue() > 0) {
|
||||
mana.set(ManaType.BLUE, mana.getBlue() * 2);
|
||||
mana.set(ManaType.BLUE, CardUtil.multiplyWithOverflowCheck(mana.getBlue(), 2));
|
||||
}
|
||||
if (mana.getWhite() > 0) {
|
||||
mana.set(ManaType.WHITE, mana.getWhite() * 2);
|
||||
mana.set(ManaType.WHITE, CardUtil.multiplyWithOverflowCheck(mana.getWhite(), 2));
|
||||
}
|
||||
if (mana.getGreen() > 0) {
|
||||
mana.set(ManaType.GREEN, mana.getGreen() * 2);
|
||||
mana.set(ManaType.GREEN, CardUtil.multiplyWithOverflowCheck(mana.getGreen(), 2));
|
||||
}
|
||||
if (mana.getRed() > 0) {
|
||||
mana.set(ManaType.RED, mana.getRed() * 2);
|
||||
mana.set(ManaType.RED, CardUtil.multiplyWithOverflowCheck(mana.getRed(), 2));
|
||||
}
|
||||
if (mana.getColorless() > 0) {
|
||||
mana.set(ManaType.COLORLESS, mana.getColorless() * 2);
|
||||
mana.set(ManaType.COLORLESS, CardUtil.multiplyWithOverflowCheck(mana.getColorless(), 2));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import mage.constants.*;
|
|||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ManaEvent;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -64,22 +65,22 @@ class NyxbloomAncientReplacementEffect extends ReplacementEffectImpl {
|
|||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
Mana mana = ((ManaEvent) event).getMana();
|
||||
if (mana.getBlack() > 0) {
|
||||
mana.set(ManaType.BLACK, mana.getBlack() * 3);
|
||||
mana.set(ManaType.BLACK, CardUtil.multiplyWithOverflowCheck(mana.getBlack(), 3));
|
||||
}
|
||||
if (mana.getBlue() > 0) {
|
||||
mana.set(ManaType.BLUE, mana.getBlue() * 3);
|
||||
mana.set(ManaType.BLUE, CardUtil.multiplyWithOverflowCheck(mana.getBlue(), 3));
|
||||
}
|
||||
if (mana.getWhite() > 0) {
|
||||
mana.set(ManaType.WHITE, mana.getWhite() * 3);
|
||||
mana.set(ManaType.WHITE, CardUtil.multiplyWithOverflowCheck(mana.getWhite(), 3));
|
||||
}
|
||||
if (mana.getGreen() > 0) {
|
||||
mana.set(ManaType.GREEN, mana.getGreen() * 3);
|
||||
mana.set(ManaType.GREEN, CardUtil.multiplyWithOverflowCheck(mana.getGreen(), 3));
|
||||
}
|
||||
if (mana.getRed() > 0) {
|
||||
mana.set(ManaType.RED, mana.getRed() * 3);
|
||||
mana.set(ManaType.RED, CardUtil.multiplyWithOverflowCheck(mana.getRed(), 3));
|
||||
}
|
||||
if (mana.getColorless() > 0) {
|
||||
mana.set(ManaType.COLORLESS, mana.getColorless() * 3);
|
||||
mana.set(ManaType.COLORLESS, CardUtil.multiplyWithOverflowCheck(mana.getColorless(), 3));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -383,10 +383,11 @@ public class CommandersCastTest extends CardTestCommander4Players {
|
|||
addCustomEffect_TargetDamage(playerA, 10); // kill creature
|
||||
|
||||
// use case:
|
||||
// cast adventure spell from command zone and keep it in exile (inc next command cost)
|
||||
// cast card from exile (do not inc next command cost)
|
||||
// return commander to command zone
|
||||
// cast as adventure spell (with x1 command cost)
|
||||
// cast adventure spell from command zone (inc command tax to 1x)
|
||||
// return to command zone
|
||||
// cast adventure spell from command zone (inc command tax to 2x)
|
||||
// return to command zone
|
||||
// cast as creature (with 2x command tax)
|
||||
|
||||
// Curious Pair, creature, {1}{G}, 1/3
|
||||
// Treats to Share, sorcery, {G}
|
||||
|
@ -418,7 +419,6 @@ public class CommandersCastTest extends CardTestCommander4Players {
|
|||
checkPlayableAbility("after mana add", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Curious Pair", false);
|
||||
checkPlayableAbility("after mana add", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Treats to Share", true);
|
||||
|
||||
|
||||
// play adventure spell, but keep it
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treats to Share");
|
||||
setChoice(playerA, "No"); // do not return commander
|
||||
|
|
|
@ -12,7 +12,7 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
|
|||
public class TappedForManaFromMultipleEffects extends CardTestPlayerBase {
|
||||
|
||||
@Test
|
||||
public void test_One() {
|
||||
public void test_NyxbloomAncient_One() {
|
||||
// If you tap a permanent for mana, it produces three times as much of that mana instead.
|
||||
addCard(Zone.HAND, playerA, "Nyxbloom Ancient"); // {4}{G}{G}{G}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 7);
|
||||
|
@ -36,7 +36,7 @@ public class TappedForManaFromMultipleEffects extends CardTestPlayerBase {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void test_Two() {
|
||||
public void test_NyxbloomAncient_Two() {
|
||||
// If you tap a permanent for mana, it produces three times as much of that mana instead.
|
||||
addCard(Zone.HAND, playerA, "Nyxbloom Ancient", 1); // {4}{G}{G}{G}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 7);
|
||||
|
@ -70,6 +70,25 @@ public class TappedForManaFromMultipleEffects extends CardTestPlayerBase {
|
|||
assertPermanentCount(playerA, "Chlorophant", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_NyxbloomAncient_IntegerOverflow() {
|
||||
// If you tap a permanent for mana, it produces three times as much of that mana instead.
|
||||
int permanentsCount = 30;
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Nyxbloom Ancient", permanentsCount);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||
|
||||
// total mana = 3^count, so must be Integer overflow protection (no zero or negative values)
|
||||
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {G}");
|
||||
checkManaPool("max mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "G", Integer.MAX_VALUE);
|
||||
setChoice(playerA, "Nyxbloom Ancient", permanentsCount - 1); // choose replacement effects order
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_ChromeMox_Direct() {
|
||||
// Imprint — When Chrome Mox enters the battlefield, you may exile a nonartifact, nonland card from your hand.
|
||||
|
|
|
@ -3,6 +3,7 @@ package mage;
|
|||
import mage.constants.ColoredManaSymbol;
|
||||
import mage.constants.ManaType;
|
||||
import mage.filter.FilterMana;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.Copyable;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
|
@ -10,6 +11,8 @@ import java.io.Serializable;
|
|||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* WARNING, all mana operations must use overflow check, see usage of CardUtil.addWithOverflowCheck and same methods
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
||||
|
@ -38,20 +41,20 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
}
|
||||
|
||||
protected void incrementAmount(ManaColor manaColor) {
|
||||
this.amount += manaColor.amount;
|
||||
this.snowAmount += manaColor.snowAmount;
|
||||
this.amount = CardUtil.addWithOverflowCheck(this.amount, manaColor.amount);
|
||||
this.snowAmount = CardUtil.addWithOverflowCheck(this.snowAmount, manaColor.snowAmount);
|
||||
}
|
||||
|
||||
protected void incrementAmount(int amount, boolean snow) {
|
||||
this.amount += amount;
|
||||
this.amount = CardUtil.addWithOverflowCheck(this.amount, amount);
|
||||
if (snow) {
|
||||
this.snowAmount += amount;
|
||||
this.snowAmount = CardUtil.addWithOverflowCheck(this.snowAmount, amount);
|
||||
}
|
||||
}
|
||||
|
||||
protected void removeAmount(ManaColor manaColor) {
|
||||
this.amount -= manaColor.amount;
|
||||
this.snowAmount -= manaColor.snowAmount;
|
||||
this.amount = CardUtil.subtractWithOverflowCheck(this.amount, manaColor.amount);
|
||||
this.snowAmount = CardUtil.subtractWithOverflowCheck(this.snowAmount, manaColor.snowAmount);
|
||||
}
|
||||
|
||||
protected void clear() {
|
||||
|
@ -64,11 +67,11 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
return false;
|
||||
}
|
||||
if (manaColor.getSnowAmount() > 0) {
|
||||
manaColor.snowAmount -= 1;
|
||||
snowAmount += 1;
|
||||
manaColor.snowAmount = CardUtil.subtractWithOverflowCheck(manaColor.snowAmount, 1);
|
||||
this.snowAmount = CardUtil.addWithOverflowCheck(this.snowAmount, 1);
|
||||
}
|
||||
manaColor.amount -= 1;
|
||||
amount += 1;
|
||||
manaColor.amount = CardUtil.subtractWithOverflowCheck(manaColor.amount, 1);
|
||||
this.amount = CardUtil.addWithOverflowCheck(this.amount, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -594,25 +597,25 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
}
|
||||
int count = 0;
|
||||
if (filter.isWhite()) {
|
||||
count += white.getAmount();
|
||||
count = CardUtil.addWithOverflowCheck(count, white.getAmount());
|
||||
}
|
||||
if (filter.isBlue()) {
|
||||
count += blue.getAmount();
|
||||
count = CardUtil.addWithOverflowCheck(count, blue.getAmount());
|
||||
}
|
||||
if (filter.isBlack()) {
|
||||
count += black.getAmount();
|
||||
count = CardUtil.addWithOverflowCheck(count, black.getAmount());
|
||||
}
|
||||
if (filter.isRed()) {
|
||||
count += red.getAmount();
|
||||
count = CardUtil.addWithOverflowCheck(count, red.getAmount());
|
||||
}
|
||||
if (filter.isGreen()) {
|
||||
count += green.getAmount();
|
||||
count = CardUtil.addWithOverflowCheck(count, green.getAmount());
|
||||
}
|
||||
if (filter.isGeneric()) {
|
||||
count += generic.getAmount();
|
||||
count = CardUtil.addWithOverflowCheck(count, generic.getAmount());
|
||||
}
|
||||
if (filter.isColorless()) {
|
||||
count += colorless.getAmount();
|
||||
count = CardUtil.addWithOverflowCheck(count, colorless.getAmount());
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
@ -640,29 +643,33 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
public String toString() {
|
||||
StringBuilder sbMana = new StringBuilder();
|
||||
if (generic.getAmount() > 0) {
|
||||
sbMana.append('{').append(Integer.toString(generic.getAmount())).append('}');
|
||||
sbMana.append('{').append(generic.getAmount()).append('}');
|
||||
}
|
||||
|
||||
// too many mana - replace by single icon
|
||||
if (colorless.getAmount() >= 20) {
|
||||
sbMana.append(Integer.toString(colorless.getAmount())).append("{C}");
|
||||
sbMana.append(colorless.getAmount()).append("{C}");
|
||||
}
|
||||
if (white.getAmount() >= 20) {
|
||||
sbMana.append(Integer.toString(white.getAmount())).append("{W}");
|
||||
sbMana.append(white.getAmount()).append("{W}");
|
||||
}
|
||||
if (blue.getAmount() >= 20) {
|
||||
sbMana.append(Integer.toString(blue.getAmount())).append("{U}");
|
||||
sbMana.append(blue.getAmount()).append("{U}");
|
||||
}
|
||||
if (black.getAmount() >= 20) {
|
||||
sbMana.append(Integer.toString(black.getAmount())).append("{B}");
|
||||
sbMana.append(black.getAmount()).append("{B}");
|
||||
}
|
||||
if (red.getAmount() >= 20) {
|
||||
sbMana.append(Integer.toString(red.getAmount())).append("{R}");
|
||||
sbMana.append(red.getAmount()).append("{R}");
|
||||
}
|
||||
if (green.getAmount() >= 20) {
|
||||
sbMana.append(Integer.toString(green.getAmount())).append("{G}");
|
||||
sbMana.append(green.getAmount()).append("{G}");
|
||||
}
|
||||
if (any.getAmount() >= 20) {
|
||||
sbMana.append(Integer.toString(any.getAmount())).append("{Any}");
|
||||
sbMana.append(any.getAmount()).append("{Any}");
|
||||
}
|
||||
|
||||
// normal mana
|
||||
for (int i = 0; i < colorless.getAmount() && colorless.getAmount() < 20; i++) {
|
||||
sbMana.append("{C}");
|
||||
}
|
||||
|
@ -684,6 +691,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
for (int i = 0; i < any.getAmount() && any.getAmount() < 20; i++) {
|
||||
sbMana.append("{Any}");
|
||||
}
|
||||
|
||||
return sbMana.toString();
|
||||
}
|
||||
|
||||
|
@ -757,9 +765,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
compare.generic.incrementAmount(compare.green);
|
||||
compare.generic.incrementAmount(compare.colorless);
|
||||
compare.generic.incrementAmount(compare.any);
|
||||
if (compare.generic.getAmount() < 0) {
|
||||
return false;
|
||||
}
|
||||
return compare.generic.getAmount() >= 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -805,13 +811,13 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
}
|
||||
if (compare.generic.getAmount() < 0) {
|
||||
int remaining = 0;
|
||||
remaining += Math.min(0, compare.white.getAmount());
|
||||
remaining += Math.min(0, compare.blue.getAmount());
|
||||
remaining += Math.min(0, compare.black.getAmount());
|
||||
remaining += Math.min(0, compare.red.getAmount());
|
||||
remaining += Math.min(0, compare.green.getAmount());
|
||||
remaining += Math.min(0, compare.colorless.getAmount());
|
||||
remaining += Math.min(0, compare.any.getAmount());
|
||||
remaining = CardUtil.addWithOverflowCheck(remaining, Math.min(0, compare.white.getAmount()));
|
||||
remaining = CardUtil.addWithOverflowCheck(remaining, Math.min(0, compare.blue.getAmount()));
|
||||
remaining = CardUtil.addWithOverflowCheck(remaining, Math.min(0, compare.black.getAmount()));
|
||||
remaining = CardUtil.addWithOverflowCheck(remaining, Math.min(0, compare.red.getAmount()));
|
||||
remaining = CardUtil.addWithOverflowCheck(remaining, Math.min(0, compare.green.getAmount()));
|
||||
remaining = CardUtil.addWithOverflowCheck(remaining, Math.min(0, compare.colorless.getAmount()));
|
||||
remaining = CardUtil.addWithOverflowCheck(remaining, Math.min(0, compare.any.getAmount()));
|
||||
if (remaining > 0) {
|
||||
int diff = Math.min(remaining, Math.abs(compare.generic.getAmount()));
|
||||
compare.generic.incrementAmount(diff, false);
|
||||
|
@ -1022,10 +1028,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
return true;
|
||||
} else if (color.isRed() && red.getSnowAmount() > 0) {
|
||||
return true;
|
||||
} else if (color.isGreen() && green.getSnowAmount() > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else return color.isGreen() && green.getSnowAmount() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1036,7 +1039,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
*/
|
||||
@Override
|
||||
public int compareTo(final Mana o) {
|
||||
return this.count() - o.count();
|
||||
return Integer.compare(this.count(), o.count());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1065,11 +1068,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
if (mana.colorless.getAmount() > 0 && this.colorless.getAmount() > 0) {
|
||||
return true;
|
||||
}
|
||||
if (mana.generic.getAmount() > 0 && this.count() > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return mana.generic.getAmount() > 0 && this.count() > 0;
|
||||
}
|
||||
|
||||
public boolean containsAny(final Mana mana) {
|
||||
|
@ -1098,11 +1097,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
return true;
|
||||
} else if (mana.colorless.getAmount() > 0 && this.colorless.getAmount() > 0 && includeColorless) {
|
||||
return true;
|
||||
} else if (mana.any.getAmount() > 0 && this.count() > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} else return mana.any.getAmount() > 0 && this.count() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1153,7 +1148,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
case GREEN:
|
||||
return green.getAmount();
|
||||
case COLORLESS:
|
||||
return generic.getAmount() + colorless.getAmount();
|
||||
return CardUtil.addWithOverflowCheck(generic.getAmount(), colorless.getAmount());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1161,6 +1156,9 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
/**
|
||||
* Set the color of mana specified by the passed in {@link ManaType} to
|
||||
* {@code amount} .
|
||||
* <p>
|
||||
* WARNING, you must check amount for overflow values, see CardUtil.multiplyWithOverflowCheck
|
||||
* and other CardUtil.xxxWithOverflowCheck math methods
|
||||
*
|
||||
* @param manaType the color of the mana to set
|
||||
* @param amount the value to set the mana too
|
||||
|
@ -1168,22 +1166,22 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
public void set(final ManaType manaType, final int amount) {
|
||||
switch (manaType) {
|
||||
case WHITE:
|
||||
setWhite(amount);
|
||||
setWhite(notNegative(amount, "white"));
|
||||
break;
|
||||
case BLUE:
|
||||
setBlue(amount);
|
||||
setBlue(notNegative(amount, "blue"));
|
||||
break;
|
||||
case BLACK:
|
||||
setBlack(amount);
|
||||
setBlack(notNegative(amount, "black"));
|
||||
break;
|
||||
case RED:
|
||||
setRed(amount);
|
||||
setRed(notNegative(amount, "red"));
|
||||
break;
|
||||
case GREEN:
|
||||
setGreen(amount);
|
||||
setGreen(notNegative(amount, "green"));
|
||||
break;
|
||||
case COLORLESS:
|
||||
setColorless(amount);
|
||||
setColorless(notNegative(amount, "colorless"));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown color: " + manaType);
|
||||
|
@ -1248,7 +1246,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
&& this.green.getAmount() >= mana.green.getAmount()
|
||||
&& this.colorless.getAmount() >= mana.colorless.getAmount()
|
||||
&& (this.generic.getAmount() >= mana.generic.getAmount()
|
||||
|| this.countColored() + this.colorless.getAmount() >= mana.count());
|
||||
|| CardUtil.addWithOverflowCheck(this.countColored(), this.colorless.getAmount()) >= mana.count());
|
||||
|
||||
}
|
||||
|
||||
|
@ -1284,33 +1282,33 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
moreMana = mana1;
|
||||
lessMana = mana2;
|
||||
}
|
||||
int anyDiff = mana2.getAny() - mana1.getAny();
|
||||
int anyDiff = CardUtil.subtractWithOverflowCheck(mana2.getAny(), mana1.getAny());
|
||||
if (lessMana.getWhite() > moreMana.getWhite()) {
|
||||
anyDiff -= lessMana.getWhite() - moreMana.getWhite();
|
||||
anyDiff = CardUtil.subtractWithOverflowCheck(anyDiff, CardUtil.subtractWithOverflowCheck(lessMana.getWhite(), moreMana.getWhite()));
|
||||
if (anyDiff < 0) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (lessMana.getRed() > moreMana.getRed()) {
|
||||
anyDiff -= lessMana.getRed() - moreMana.getRed();
|
||||
anyDiff = CardUtil.subtractWithOverflowCheck(anyDiff, CardUtil.subtractWithOverflowCheck(lessMana.getRed(), moreMana.getRed()));
|
||||
if (anyDiff < 0) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (lessMana.getGreen() > moreMana.getGreen()) {
|
||||
anyDiff -= lessMana.getGreen() - moreMana.getGreen();
|
||||
anyDiff = CardUtil.subtractWithOverflowCheck(anyDiff, CardUtil.subtractWithOverflowCheck(lessMana.getGreen(), moreMana.getGreen()));
|
||||
if (anyDiff < 0) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (lessMana.getBlue() > moreMana.getBlue()) {
|
||||
anyDiff -= lessMana.getBlue() - moreMana.getBlue();
|
||||
anyDiff = CardUtil.subtractWithOverflowCheck(anyDiff, CardUtil.subtractWithOverflowCheck(lessMana.getBlue(), moreMana.getBlue()));
|
||||
if (anyDiff < 0) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (lessMana.getBlack() > moreMana.getBlack()) {
|
||||
anyDiff -= lessMana.getBlack() - moreMana.getBlack();
|
||||
anyDiff = CardUtil.subtractWithOverflowCheck(anyDiff, CardUtil.subtractWithOverflowCheck(lessMana.getBlack(), moreMana.getBlack()));
|
||||
if (anyDiff < 0) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -5,14 +5,16 @@
|
|||
*/
|
||||
package mage.abilities.effects.mana;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.mana.builder.ConditionalManaBuilder;
|
||||
import mage.constants.ManaType;
|
||||
import mage.game.Game;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author LevelX2
|
||||
|
@ -55,8 +57,8 @@ public class AddConditionalManaEffect extends ManaEffect {
|
|||
int amountAvailableMana = netAmount.calculate(game, source, this);
|
||||
if (amountAvailableMana > 0) {
|
||||
Mana calculatedMana = mana.copy();
|
||||
for(ManaType manaType: ManaType.getTrueManaTypes()) {
|
||||
calculatedMana.set(manaType, calculatedMana.get(manaType) * amountAvailableMana);
|
||||
for (ManaType manaType : ManaType.getTrueManaTypes()) {
|
||||
calculatedMana.set(manaType, CardUtil.multiplyWithOverflowCheck(calculatedMana.get(manaType), amountAvailableMana));
|
||||
}
|
||||
maxAvailableMana.add(manaBuilder.setMana(calculatedMana, source, game).build());
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import mage.game.events.GameEvent.EventType;
|
|||
import mage.game.events.ManaEvent;
|
||||
import mage.game.events.ManaPaidEvent;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
@ -387,7 +388,7 @@ public class ManaPool implements Serializable {
|
|||
private void removeConditional(ConditionalManaInfo manaInfo, Ability ability, Game game, Cost costToPay, Mana usedManaToPay) {
|
||||
for (ConditionalMana mana : getConditionalMana()) {
|
||||
if (mana.get(manaInfo.manaType) > 0 && mana.apply(ability, game, mana.getManaProducerId(), costToPay)) {
|
||||
mana.set(manaInfo.manaType, mana.get(manaInfo.manaType) - 1);
|
||||
mana.set(manaInfo.manaType, CardUtil.subtractWithOverflowCheck(mana.get(manaInfo.manaType), 1));
|
||||
usedManaToPay.increase(manaInfo.manaType, manaInfo.sourceObject.isSnow());
|
||||
GameEvent event = new ManaPaidEvent(ability, mana.getManaProducerId(), mana.getFlag(), mana.getManaProducerOriginalId());
|
||||
game.fireEvent(event);
|
||||
|
|
|
@ -3244,7 +3244,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
restVal = 0;
|
||||
availableLifeMana -= oldPayOption.get(manaType);
|
||||
} else {
|
||||
restVal = oldPayOption.get(manaType) - availableLifeMana;
|
||||
restVal = CardUtil.subtractWithOverflowCheck(oldPayOption.get(manaType), availableLifeMana);
|
||||
availableLifeMana = 0;
|
||||
}
|
||||
manaCopy.set(manaType, restVal);
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
package mage.util;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import mage.MageObject;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Abilities;
|
||||
|
@ -43,6 +37,13 @@ import mage.target.targetpointer.FixedTarget;
|
|||
import mage.util.functions.CopyTokenFunction;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author nantuko
|
||||
*/
|
||||
|
@ -75,9 +76,9 @@ public final class CardUtil {
|
|||
/**
|
||||
* calculates the maximal possible generic mana reduction for a given mana cost
|
||||
*
|
||||
* @param mana mana costs that should be reduced
|
||||
* @param maxPossibleReduction max possible generic mana reduction
|
||||
* @param notLessThan the complete costs may not be reduced more than this CMC mana costs
|
||||
* @param mana mana costs that should be reduced
|
||||
* @param maxPossibleReduction max possible generic mana reduction
|
||||
* @param notLessThan the complete costs may not be reduced more than this CMC mana costs
|
||||
*/
|
||||
public static int calculateActualPossibleGenericManaReduction(Mana mana, int maxPossibleReduction, int notLessThan) {
|
||||
int nonGeneric = mana.count() - mana.getGeneric();
|
||||
|
@ -85,12 +86,11 @@ public final class CardUtil {
|
|||
int actualPossibleGenericManaReduction = Math.max(0, mana.getGeneric() - notPossibleGenericReduction);
|
||||
if (actualPossibleGenericManaReduction > maxPossibleReduction) {
|
||||
actualPossibleGenericManaReduction = maxPossibleReduction;
|
||||
}
|
||||
}
|
||||
return actualPossibleGenericManaReduction;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reduces ability cost to be paid.
|
||||
*
|
||||
|
@ -656,6 +656,16 @@ public final class CardUtil {
|
|||
return base - decrement;
|
||||
}
|
||||
|
||||
public static int multiplyWithOverflowCheck(int base, int multiply) {
|
||||
long result = ((long) base) * multiply;
|
||||
if (result > Integer.MAX_VALUE) {
|
||||
return Integer.MAX_VALUE;
|
||||
} else if (result < Integer.MIN_VALUE) {
|
||||
return Integer.MIN_VALUE;
|
||||
}
|
||||
return base * multiply;
|
||||
}
|
||||
|
||||
public static String createObjectRealtedWindowTitle(Ability source, Game game, String textSuffix) {
|
||||
String title;
|
||||
if (source != null) {
|
||||
|
@ -1032,7 +1042,7 @@ public final class CardUtil {
|
|||
/**
|
||||
* Add effects to game that allows to play/cast card from current zone and spend mana as any type for it.
|
||||
* Effects will be discarded/ignored on any card movements or blinks (after ZCC change)
|
||||
*
|
||||
* <p>
|
||||
* Affected to all card's parts
|
||||
*
|
||||
* @param game
|
||||
|
|
|
@ -656,4 +656,34 @@ public class ManaTest {
|
|||
assertEquals(0, mana.getGeneric());
|
||||
assertEquals(0, mana.getAny());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotOverflow() {
|
||||
// given
|
||||
Mana mana = new Mana();
|
||||
|
||||
// when
|
||||
mana.setRed(Integer.MAX_VALUE);
|
||||
mana.increaseRed();
|
||||
mana.setGreen(Integer.MAX_VALUE);
|
||||
mana.increaseGreen();
|
||||
mana.setBlue(Integer.MAX_VALUE);
|
||||
mana.increaseBlue();
|
||||
mana.setWhite(Integer.MAX_VALUE);
|
||||
mana.increaseWhite();
|
||||
mana.setBlack(Integer.MAX_VALUE);
|
||||
mana.increaseBlack();
|
||||
mana.setGeneric(Integer.MAX_VALUE);
|
||||
mana.increaseGeneric();
|
||||
mana.setAny(Integer.MAX_VALUE);
|
||||
|
||||
// then
|
||||
assertEquals(Integer.MAX_VALUE, mana.getRed());
|
||||
assertEquals(Integer.MAX_VALUE, mana.getGreen());
|
||||
assertEquals(Integer.MAX_VALUE, mana.getBlue());
|
||||
assertEquals(Integer.MAX_VALUE, mana.getWhite());
|
||||
assertEquals(Integer.MAX_VALUE, mana.getBlack());
|
||||
assertEquals(Integer.MAX_VALUE, mana.getGeneric());
|
||||
assertEquals(Integer.MAX_VALUE, mana.getAny());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue