mirror of
https://github.com/correl/mage.git
synced 2025-01-11 19:13:02 +00:00
* Fixed a problem of available mana generation caused by order of usage of mana sourced with costs (example Coal Golem and then Dromar's Attendant - related to #6698).
This commit is contained in:
parent
8e929d4e9d
commit
06968ad921
4 changed files with 127 additions and 48 deletions
|
@ -129,7 +129,7 @@ public class SasayaOrochiAscendantTest extends CardTestPlayerBase {
|
|||
assertManaOptions("{R}{R}{R}{R}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{R}{R}{R}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{R}{R}{G}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{R}{G}{G}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{R}{G}{G}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -108,6 +108,7 @@ public class NonTappingManaAbilitiesTest extends CardTestPlayerBase {
|
|||
assertManaOptions("{W}{B}{B}{B}", manaOptions);
|
||||
assertManaOptions("{B}{B}{B}{B}", manaOptions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestCrystallineCrawler() {
|
||||
setStrictChooseMode(true);
|
||||
|
@ -126,5 +127,58 @@ public class NonTappingManaAbilitiesTest extends CardTestPlayerBase {
|
|||
Assert.assertEquals("mana variations don't fit", 1, manaOptions.size());
|
||||
assertManaOptions("{Any}{Any}", manaOptions);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void TestCoalGolemAndDromarsAttendant() {
|
||||
setStrictChooseMode(true);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||
|
||||
// {1}, Sacrifice Dromar's Attendant: Add {W}{U}{B}.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Dromar's Attendant", 1);
|
||||
|
||||
// {3}, Sacrifice Coal Golem: Add {R}{R}{R}.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Coal Golem", 1);
|
||||
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertAllCommandsUsed();
|
||||
|
||||
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
|
||||
Assert.assertEquals("mana variations don't fit", 3, manaOptions.size());
|
||||
assertManaOptions("{G}", manaOptions);
|
||||
assertManaOptions("{W}{U}{B}", manaOptions);
|
||||
assertManaOptions("{R}{R}{R}", manaOptions);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The order the mana abilities are checked during available mana calculation does matter.
|
||||
* Because Coal Golem can not be used as long as Dromar's Attendant is not used yet to produce the 3 mana.
|
||||
*/
|
||||
@Test
|
||||
public void TestCoalGolemAndDromarsAttendantOrder2() {
|
||||
setStrictChooseMode(true);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||
|
||||
// {3}, Sacrifice Coal Golem: Add {R}{R}{R}.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Coal Golem", 1);
|
||||
|
||||
// {1}, Sacrifice Dromar's Attendant: Add {W}{U}{B}.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Dromar's Attendant", 1);
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertAllCommandsUsed();
|
||||
|
||||
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
|
||||
Assert.assertEquals("mana variations don't fit", 3, manaOptions.size());
|
||||
assertManaOptions("{G}", manaOptions);
|
||||
assertManaOptions("{W}{U}{B}", manaOptions);
|
||||
assertManaOptions("{R}{R}{R}", manaOptions);
|
||||
}
|
||||
|
||||
}
|
|
@ -146,7 +146,16 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
return false;
|
||||
}
|
||||
|
||||
public void addManaWithCost(List<ActivatedManaAbilityImpl> abilities, Game game) {
|
||||
/**
|
||||
* This adds the mana the abilities can produce to the possible mana
|
||||
* variabtion.
|
||||
*
|
||||
* @param abilities
|
||||
* @param game
|
||||
* @return false if the costs could not be paid
|
||||
*/
|
||||
public boolean addManaWithCost(List<ActivatedManaAbilityImpl> abilities, Game game) {
|
||||
boolean wasUsable = false;
|
||||
int replaces = 0;
|
||||
if (isEmpty()) {
|
||||
this.add(new Mana()); // needed if this is the first available mana, otherwise looping over existing options woold not loop
|
||||
|
@ -185,8 +194,15 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
for (Mana triggeredManaVariation : getTriggeredManaVariations(game, ability, netMana)) {
|
||||
for (Mana prevMana : copy) {
|
||||
Mana startingMana = prevMana.copy();
|
||||
if (!subtractCostAddMana(ability.getManaCosts().getMana(), triggeredManaVariation, ability.getCosts().isEmpty(), startingMana)) {
|
||||
// the starting mana includes mana parts that the increased mana does not include, so add starting mana also as an option
|
||||
Mana manaCosts = ability.getManaCosts().getMana();
|
||||
if (startingMana.includesMana(manaCosts)) { // can pay the mana costs to use the ability
|
||||
if (!subtractCostAddMana(manaCosts, triggeredManaVariation, ability.getCosts().isEmpty(), startingMana)) {
|
||||
// the starting mana includes mana parts that the increased mana does not include, so add starting mana also as an option
|
||||
add(prevMana);
|
||||
}
|
||||
wasUsable = true;
|
||||
} else {
|
||||
// mana costs can't be paid so keep starting mana
|
||||
add(prevMana);
|
||||
}
|
||||
}
|
||||
|
@ -248,6 +264,7 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
logger.trace("ManaOptionsCosts " + this.size() + " Ign:" + replaces + " => " + this.toString());
|
||||
logger.trace("Abilities: " + abilities.toString());
|
||||
}
|
||||
return wasUsable;
|
||||
}
|
||||
|
||||
private List<Mana> getTriggeredManaVariations(Game game, Ability ability, Mana baseMana) {
|
||||
|
@ -353,54 +370,52 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
repeatable = true; // only replace to any with mana costs only will be repeated if able
|
||||
}
|
||||
Mana prevMana = currentMana.copy();
|
||||
if (currentMana.includesMana(cost)) { // cost can be paid
|
||||
// generic mana costs can be paid with different colored mana, can lead to different color combinations
|
||||
if (cost.getGeneric() > 0 && cost.getGeneric() > (currentMana.getGeneric() + currentMana.getColorless())) {
|
||||
for (Mana payCombination : getPossiblePayCombinations(cost.getGeneric(), currentMana)) {
|
||||
Mana currentManaCopy = currentMana.copy();
|
||||
while (currentManaCopy.includesMana(payCombination)) { // loop for multiple usage if possible
|
||||
boolean newCombinations = false;
|
||||
// generic mana costs can be paid with different colored mana, can lead to different color combinations
|
||||
if (cost.getGeneric() > 0 && cost.getGeneric() > (currentMana.getGeneric() + currentMana.getColorless())) {
|
||||
for (Mana payCombination : getPossiblePayCombinations(cost.getGeneric(), currentMana)) {
|
||||
Mana currentManaCopy = currentMana.copy();
|
||||
while (currentManaCopy.includesMana(payCombination)) { // loop for multiple usage if possible
|
||||
boolean newCombinations = false;
|
||||
|
||||
Mana newMana = currentManaCopy.copy();
|
||||
newMana.subtract(payCombination);
|
||||
newMana.add(manaToAdd);
|
||||
// Mana moreValuable = Mana.getMoreValuableMana(currentMana, newMana);
|
||||
if (!isExistingManaCombination(newMana)) {
|
||||
this.add(newMana); // add the new combination
|
||||
newCombinations = true; // repeat the while as long there are new combinations and usage is repeatable
|
||||
currentManaCopy = newMana.copy();
|
||||
Mana moreValuable = Mana.getMoreValuableMana(currentMana, newMana);
|
||||
if (!oldManaWasReplaced && newMana.equals(moreValuable)) {
|
||||
oldManaWasReplaced = true; // the new mana includes all possibilities of the old one, so no need to add it after return
|
||||
}
|
||||
}
|
||||
if (!newCombinations || !repeatable) {
|
||||
break;
|
||||
Mana newMana = currentManaCopy.copy();
|
||||
newMana.subtract(payCombination);
|
||||
newMana.add(manaToAdd);
|
||||
// Mana moreValuable = Mana.getMoreValuableMana(currentMana, newMana);
|
||||
if (!isExistingManaCombination(newMana)) {
|
||||
this.add(newMana); // add the new combination
|
||||
newCombinations = true; // repeat the while as long there are new combinations and usage is repeatable
|
||||
currentManaCopy = newMana.copy();
|
||||
Mana moreValuable = Mana.getMoreValuableMana(currentMana, newMana);
|
||||
if (!oldManaWasReplaced && newMana.equals(moreValuable)) {
|
||||
oldManaWasReplaced = true; // the new mana includes all possibilities of the old one, so no need to add it after return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
while (currentMana.includesMana(cost)) { // loop for multiple usage if possible
|
||||
currentMana.subtractCost(cost);
|
||||
currentMana.add(manaToAdd);
|
||||
if (!repeatable) {
|
||||
break; // Stop adding multiple usages of the ability
|
||||
}
|
||||
}
|
||||
// Don't use mana that only reduce the available mana
|
||||
if (prevMana.contains(currentMana) && prevMana.count() > currentMana.count()) {
|
||||
currentMana.setToMana(prevMana);
|
||||
}
|
||||
Mana moreValuable = Mana.getMoreValuableMana(prevMana, currentMana);
|
||||
if (!prevMana.equals(moreValuable)) {
|
||||
this.add(currentMana);
|
||||
if (moreValuable != null) {
|
||||
oldManaWasReplaced = true; // the new mana includes all possibilities of the old one
|
||||
if (!newCombinations || !repeatable) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
while (currentMana.includesMana(cost)) { // loop for multiple usage if possible
|
||||
currentMana.subtractCost(cost);
|
||||
currentMana.add(manaToAdd);
|
||||
if (!repeatable) {
|
||||
break; // Stop adding multiple usages of the ability
|
||||
}
|
||||
}
|
||||
// Don't use mana that only reduce the available mana
|
||||
if (prevMana.contains(currentMana) && prevMana.count() > currentMana.count()) {
|
||||
currentMana.setToMana(prevMana);
|
||||
}
|
||||
Mana moreValuable = Mana.getMoreValuableMana(prevMana, currentMana);
|
||||
if (!prevMana.equals(moreValuable)) {
|
||||
this.add(currentMana);
|
||||
if (moreValuable != null) {
|
||||
oldManaWasReplaced = true; // the new mana includes all possibilities of the old one
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return oldManaWasReplaced;
|
||||
}
|
||||
|
|
|
@ -2936,9 +2936,19 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
for (Abilities<ActivatedManaAbilityImpl> manaAbilities : sourceWithoutManaCosts) {
|
||||
availableMana.addMana(manaAbilities, game);
|
||||
}
|
||||
for (Abilities<ActivatedManaAbilityImpl> manaAbilities : sourceWithCosts) {
|
||||
availableMana.removeDuplicated();
|
||||
availableMana.addManaWithCost(manaAbilities, game);
|
||||
|
||||
boolean anAbilityWasUsed = true;
|
||||
while (anAbilityWasUsed && !sourceWithCosts.isEmpty()) {
|
||||
anAbilityWasUsed = false;
|
||||
for (Iterator<Abilities<ActivatedManaAbilityImpl>> iterator = sourceWithCosts.iterator(); iterator.hasNext();) {
|
||||
Abilities<ActivatedManaAbilityImpl> manaAbilities = iterator.next();
|
||||
boolean used = availableMana.addManaWithCost(manaAbilities, game);
|
||||
if (used) {
|
||||
iterator.remove();
|
||||
availableMana.removeDuplicated();
|
||||
anAbilityWasUsed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove duplicated variants (see ManaOptionsTest for info - when that rises)
|
||||
|
|
Loading…
Reference in a new issue