mirror of
https://github.com/correl/mage.git
synced 2024-12-24 11:50:45 +00:00
* Doubling Cube - Added support for possible mana calculation (related to #6698).
This commit is contained in:
parent
27db13605e
commit
c48331f216
15 changed files with 379 additions and 79 deletions
|
@ -1,5 +1,7 @@
|
|||
package mage.cards.d;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.ConditionalMana;
|
||||
import mage.Mana;
|
||||
|
@ -25,7 +27,8 @@ public final class DoublingCube extends CardImpl {
|
|||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
|
||||
|
||||
// {3}, {T}: Double the amount of each type of mana in your mana pool.
|
||||
Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new DoublingCubeEffect(), new ManaCostsImpl("{3}"));
|
||||
Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new DoublingCubeEffect(), new ManaCostsImpl("{3}"))
|
||||
.setPoolDependant(true);
|
||||
ability.addCost(new TapSourceCost());
|
||||
this.addAbility(ability);
|
||||
|
||||
|
@ -52,6 +55,22 @@ class DoublingCubeEffect extends ManaEffect {
|
|||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Mana> getNetMana(Game game, Mana possibleManaInPool, Ability source) {
|
||||
List<Mana> netMana = new ArrayList<>();
|
||||
netMana.add(new Mana( // remove possible mana conditions
|
||||
possibleManaInPool.getRed(),
|
||||
possibleManaInPool.getGreen(),
|
||||
possibleManaInPool.getBlue(),
|
||||
possibleManaInPool.getWhite(),
|
||||
possibleManaInPool.getBlack(),
|
||||
0, // Generic may not be included
|
||||
possibleManaInPool.getAny(),
|
||||
possibleManaInPool.getColorless())
|
||||
);
|
||||
return netMana;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mana produceMana(Game game, Ability source) {
|
||||
if (game != null) {
|
||||
|
|
|
@ -22,10 +22,10 @@ public final class FetidHeath extends CardImpl {
|
|||
public FetidHeath (UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.LAND},null);
|
||||
|
||||
// {tap}: Add {C}.
|
||||
// {T}: Add {C}.
|
||||
this.addAbility(new ColorlessManaAbility());
|
||||
|
||||
// {W/B}, {tap}: Add {W}{W}, {W}{B}, or {B}{B}.
|
||||
// {W/B}, {T}: Add {W}{W}, {W}{B}, or {B}{B}.
|
||||
SimpleManaAbility ability = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.WhiteMana(2), new ManaCostsImpl("{W/B}"));
|
||||
ability.addCost(new TapSourceCost());
|
||||
this.addAbility(ability);
|
||||
|
|
|
@ -21,7 +21,7 @@ public class CastDestroySpellsTest extends CardTestPlayerBaseAI {
|
|||
addCard(Zone.HAND, playerA, "Orzhov Charm"); // {W}{B}
|
||||
|
||||
// {T}: Add {C}.
|
||||
// {T} {W/B}, {T}: Add {W}{W}, {W}{B}, or {B}{B}.
|
||||
// {W/B}, {T}: Add {W}{W}, {W}{B}, or {B}{B}.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Fetid Heath", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
|
||||
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
package org.mage.test.cards.mana;
|
||||
|
||||
import mage.abilities.mana.ManaOptions;
|
||||
import mage.constants.ManaType;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
import static org.mage.test.utils.ManaOptionsTestUtils.assertManaOptions;
|
||||
|
||||
public class DoublingCubeTest extends CardTestPlayerBase {
|
||||
|
||||
|
@ -17,7 +21,7 @@ public class DoublingCubeTest extends CardTestPlayerBase {
|
|||
|
||||
//issue 3443
|
||||
@Test
|
||||
public void DoublingCubeEldraziTemple() {
|
||||
public void test_DoublingCubeEldraziTemple() {
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, temple);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
|
||||
|
@ -37,4 +41,105 @@ public class DoublingCubeTest extends CardTestPlayerBase {
|
|||
assertManaPool(playerA, ManaType.COLORLESS, 4);
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_AvailableMana() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
// {3}, {T}: Double the amount of each type of mana in your mana pool.
|
||||
addCard(Zone.BATTLEFIELD, playerA, cube);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||
|
||||
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
|
||||
execute();
|
||||
|
||||
assertAllCommandsUsed();
|
||||
|
||||
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
|
||||
Assert.assertEquals("mana variations don't fit", 4, manaOptions.size());
|
||||
assertManaOptions("{R}{R}{R}{R}{R}{R}{R}{R}{G}{G}", manaOptions);
|
||||
assertManaOptions("{R}{R}{R}{R}{R}{R}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{R}{R}{R}{R}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{R}{R}{G}{G}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_AvailableMana2() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
// {3}, {T}: Double the amount of each type of mana in your mana pool.
|
||||
addCard(Zone.BATTLEFIELD, playerA, cube, 2);
|
||||
// {T}: Add Colorless.
|
||||
// {1}, {T}: Add Black.
|
||||
// {2}, {T}: Add Blue or Red.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Castle Sengir", 2);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||
|
||||
setStopAt(1, PhaseStep.UPKEEP);
|
||||
|
||||
execute();
|
||||
|
||||
assertAllCommandsUsed();
|
||||
|
||||
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
|
||||
Assert.assertEquals("mana variations don't fit", 138, manaOptions.size());
|
||||
assertManaOptions("{C}{C}{C}{C}{C}{C}{C}{C}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{C}{C}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{C}{C}{C}{C}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{C}{C}{C}{C}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{C}{C}{C}{C}{R}{R}{R}{R}{R}{R}{R}{R}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{C}{C}{C}{C}{R}{R}{R}{R}{R}{R}{G}{G}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{C}{C}{C}{C}{R}{R}{R}{R}{G}{G}{G}{G}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{C}{C}{C}{C}{R}{R}{G}{G}{G}{G}{G}{G}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{C}{C}{C}{C}{G}{G}{G}{G}{G}{G}{G}{G}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}{G}{G}{G}{G}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{B}{B}{R}{R}{G}{G}{G}{G}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{B}{B}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{B}{B}{B}{B}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{B}{B}{R}{R}{R}{R}{R}{R}{R}{R}{R}{R}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{B}{B}{R}{R}{R}{R}{R}{R}{R}{R}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{B}{B}{B}{B}{R}{R}{R}{R}{R}{R}{R}{R}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{B}{B}{B}{B}{R}{R}{R}{R}{R}{R}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{B}{B}{R}{R}{R}{R}{R}{R}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{B}{B}{R}{R}{R}{R}{G}{G}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{B}{B}{B}{B}{R}{R}{R}{R}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{B}{B}{B}{B}{R}{R}{G}{G}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{B}{B}{G}{G}{G}{G}{G}{G}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{B}{B}{B}{B}{G}{G}{G}{G}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{U}{U}{R}{R}{R}{R}{R}{R}{R}{R}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{U}{U}{U}{U}{R}{R}{R}{R}{R}{R}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{U}{U}{R}{R}{R}{R}{R}{R}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{U}{U}{R}{R}{R}{R}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{U}{U}{U}{U}{R}{R}{R}{R}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{U}{U}{U}{U}{R}{R}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{U}{U}{R}{R}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{U}{U}{G}{G}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{C}{C}{U}{U}{U}{U}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{B}{B}{B}{B}{B}{B}{R}{R}{R}{R}{R}{R}{R}{R}", manaOptions);
|
||||
assertManaOptions("{B}{B}{B}{B}{B}{B}{B}{B}{R}{R}{R}{R}{R}{R}", manaOptions);
|
||||
assertManaOptions("{B}{B}{B}{B}{B}{B}{R}{R}{R}{R}{R}{R}{G}{G}", manaOptions);
|
||||
assertManaOptions("{B}{B}{B}{B}{B}{B}{R}{R}{R}{R}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{B}{B}{B}{B}{B}{B}{B}{B}{R}{R}{R}{R}{G}{G}", manaOptions);
|
||||
assertManaOptions("{B}{B}{B}{B}{B}{B}{B}{B}{R}{R}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{B}{B}{B}{B}{B}{B}{R}{R}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{B}{B}{B}{B}{B}{B}{G}{G}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{B}{B}{B}{B}{B}{B}{B}{B}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{U}{U}{B}{B}{R}{R}{R}{R}{R}{R}", manaOptions);
|
||||
assertManaOptions("{U}{U}{U}{U}{B}{B}{R}{R}{R}{R}", manaOptions);
|
||||
assertManaOptions("{U}{U}{B}{B}{B}{B}{R}{R}{R}{R}", manaOptions);
|
||||
assertManaOptions("{U}{U}{U}{U}{B}{B}{B}{B}{R}{R}", manaOptions);
|
||||
assertManaOptions("{U}{U}{B}{B}{R}{R}{R}{R}{G}{G}", manaOptions);
|
||||
assertManaOptions("{U}{U}{B}{B}{R}{R}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{U}{U}{U}{U}{B}{B}{R}{R}{G}{G}", manaOptions);
|
||||
assertManaOptions("{U}{U}{U}{U}{B}{B}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{U}{U}{B}{B}{B}{B}{R}{R}{G}{G}", manaOptions);
|
||||
assertManaOptions("{U}{U}{B}{B}{B}{B}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{U}{U}{U}{U}{B}{B}{B}{B}{G}{G}", manaOptions);
|
||||
assertManaOptions("{U}{U}{B}{B}{G}{G}{G}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{U}{U}{U}{U}{U}{U}", manaOptions);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -168,7 +168,7 @@ public class TappedForManaRelatedTest extends CardTestPlayerBase {
|
|||
addCard(Zone.BATTLEFIELD, playerA, "Castle Sengir", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
setStopAt(1, PhaseStep.UPKEEP);
|
||||
execute();
|
||||
|
||||
assertAllCommandsUsed();
|
||||
|
|
|
@ -5,7 +5,6 @@ import mage.constants.PhaseStep;
|
|||
import mage.constants.Zone;
|
||||
import mage.counters.CounterType;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
import static org.mage.test.utils.ManaOptionsTestUtils.*;
|
||||
|
@ -330,6 +329,8 @@ public class ManaOptionsTest extends CardTestPlayerBase {
|
|||
|
||||
@Test
|
||||
public void testFetidHeath() {
|
||||
// {T}: Add {C}.
|
||||
// {W/B}, {T}: Add {W}{W}, {W}{B}, or {B}{B}.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Fetid Heath", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
|
||||
|
||||
|
|
|
@ -267,6 +267,12 @@ public interface Abilities<T extends Ability> extends List<T>, Serializable {
|
|||
*/
|
||||
boolean containsClass(Class classObject);
|
||||
|
||||
/**
|
||||
* Returns true if one or more of the abilities are activated mana abilities with the pollDependant flag set to true.
|
||||
* @return
|
||||
*/
|
||||
boolean hasPoolDependantAbilities();
|
||||
|
||||
/**
|
||||
* Copies this set of abilities. This copy should be new instances of all
|
||||
* the contained abilities.
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.apache.log4j.Logger;
|
|||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import mage.abilities.mana.ManaAbility;
|
||||
|
||||
/**
|
||||
* @param <T>
|
||||
|
@ -185,6 +186,13 @@ public class AbilitiesImpl<T extends Ability> extends ArrayList<T> implements Ab
|
|||
return zonedAbilities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPoolDependantAbilities() {
|
||||
return stream()
|
||||
.anyMatch(ability -> ability.getAbilityType() == AbilityType.MANA
|
||||
&& ((ManaAbility) ability).isPoolDependant());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Abilities<ProtectionAbility> getProtectionAbilities() {
|
||||
return stream()
|
||||
|
@ -224,7 +232,7 @@ public class AbilitiesImpl<T extends Ability> extends ArrayList<T> implements Ab
|
|||
|
||||
@Override
|
||||
public boolean contains(T ability) {
|
||||
for (Iterator<T> iterator = this.iterator(); iterator.hasNext(); ) { // simple loop can cause java.util.ConcurrentModificationException
|
||||
for (Iterator<T> iterator = this.iterator(); iterator.hasNext();) { // simple loop can cause java.util.ConcurrentModificationException
|
||||
T test = iterator.next();
|
||||
// Checking also by getRule() without other restrictions is a problem when a triggered ability will be copied to a permanent that had the same ability
|
||||
// already before the copy. Because then it keeps the triggered ability twice and it triggers twice.
|
||||
|
|
|
@ -80,6 +80,22 @@ public abstract class ManaEffect extends OneShotEffect {
|
|||
return netMana;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently available max mana variations the effect can
|
||||
* produce. Also provides the possible before produced mana from other
|
||||
* abilities. Needed for some abilities that produce mana related to the
|
||||
* mana existing in the mana pool.
|
||||
*
|
||||
* @param game
|
||||
* @param possibleManaInPool The possible mana already produced by other
|
||||
* sources for this calculation option
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
public List<Mana> getNetMana(Game game, Mana possibleManaInPool, Ability source) {
|
||||
return getNetMana(game, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of mana a permanent "could produce" is the type of mana that any
|
||||
* ability of that permanent can generate, taking into account any
|
||||
|
@ -95,7 +111,6 @@ public abstract class ManaEffect extends OneShotEffect {
|
|||
return ManaType.getManaTypesFromManaList(getNetMana(game, source));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Produced the mana the effect can produce (DO NOT add it to mana pool --
|
||||
* return all added as mana object to process by replace events)
|
||||
|
|
|
@ -19,6 +19,7 @@ public abstract class ActivatedManaAbilityImpl extends ActivatedAbilityImpl impl
|
|||
|
||||
protected List<Mana> netMana = new ArrayList<>();
|
||||
protected boolean undoPossible;
|
||||
protected boolean poolDependant;
|
||||
|
||||
public ActivatedManaAbilityImpl(Zone zone, ManaEffect effect, Cost cost) {
|
||||
super(AbilityType.MANA, zone);
|
||||
|
@ -36,6 +37,7 @@ public abstract class ActivatedManaAbilityImpl extends ActivatedAbilityImpl impl
|
|||
super(ability);
|
||||
this.netMana.addAll(ability.netMana);
|
||||
this.undoPossible = ability.undoPossible;
|
||||
this.poolDependant = ability.poolDependant;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -101,6 +103,23 @@ public abstract class ActivatedManaAbilityImpl extends ActivatedAbilityImpl impl
|
|||
return netManaCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Mana> getNetMana(Game game, Mana possibleManaInPool) {
|
||||
if (isPoolDependant()) {
|
||||
List<Mana> poolDependantNetMana = new ArrayList<>();
|
||||
for (Effect effect : getEffects()) {
|
||||
if (effect instanceof ManaEffect) {
|
||||
List<Mana> effectNetMana = ((ManaEffect) effect).getNetMana(game, possibleManaInPool, this);
|
||||
if (effectNetMana != null) {
|
||||
poolDependantNetMana.addAll(effectNetMana);
|
||||
}
|
||||
}
|
||||
}
|
||||
return poolDependantNetMana;
|
||||
}
|
||||
return getNetMana(game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ManaType> getProducableManaTypes(Game game) {
|
||||
Set<ManaType> manaTypes = new HashSet<>();
|
||||
|
@ -127,8 +146,9 @@ public abstract class ActivatedManaAbilityImpl extends ActivatedAbilityImpl impl
|
|||
* game revealing information is related (like reveal the top card of the
|
||||
* library)
|
||||
* <p>
|
||||
* TODO: it helps with single mana activate for mana pool, but will not work while activates on paying for casting
|
||||
* (e.g. user can cheats to see next draw card)
|
||||
* TODO: it helps with single mana activate for mana pool, but will not work
|
||||
* while activates on paying for casting (e.g. user can cheats to see next
|
||||
* draw card)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
|
@ -140,4 +160,15 @@ public abstract class ActivatedManaAbilityImpl extends ActivatedAbilityImpl impl
|
|||
this.undoPossible = undoPossible;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPoolDependant() {
|
||||
return poolDependant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivatedManaAbilityImpl setPoolDependant(boolean poolDependant) {
|
||||
this.poolDependant = poolDependant;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ package mage.abilities.mana;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.constants.ManaType;
|
||||
import mage.game.Game;
|
||||
|
||||
|
@ -25,6 +26,17 @@ public interface ManaAbility {
|
|||
* @return
|
||||
*/
|
||||
List<Mana> getNetMana(Game game);
|
||||
|
||||
/**
|
||||
* Used to check the possible mana production to determine which spells
|
||||
* and/or abilities can be used. (player.getPlayable()).
|
||||
* Only used for abilities were the poolDependant flag is set
|
||||
*
|
||||
* @param game
|
||||
* @param possibleManaInPool The possible mana already produced by other sources for this calculation option
|
||||
* @return
|
||||
*/
|
||||
List<Mana> getNetMana(Game game, Mana possibleManaInPool);
|
||||
|
||||
/**
|
||||
* The type of mana a permanent "could produce" is the type of mana that any
|
||||
|
@ -45,4 +57,16 @@ public interface ManaAbility {
|
|||
* @return
|
||||
*/
|
||||
boolean definesMana(Game game);
|
||||
|
||||
/**
|
||||
* Set to true if the ability is dependant from the mana pool. E.g. the more
|
||||
* mana the pool contains the more mana the ability can produce (Doubling
|
||||
* Cube). Therefore the use of that ability after other mana abilities does produce more mana.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isPoolDependant();
|
||||
|
||||
ManaAbility setPoolDependant(boolean pooleDependant);
|
||||
|
||||
}
|
||||
|
|
|
@ -176,6 +176,7 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
newMana.add(mana);
|
||||
newMana.add(triggeredManaVariation);
|
||||
this.add(newMana);
|
||||
wasUsable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -190,7 +191,7 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
Mana startingMana = prevMana.copy();
|
||||
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)) {
|
||||
if (!subtractCostAddMana(manaCosts, triggeredManaVariation, ability.getCosts().isEmpty(), startingMana, ability, game)) {
|
||||
// the starting mana includes mana parts that the increased mana does not include, so add starting mana also as an option
|
||||
add(prevMana);
|
||||
}
|
||||
|
@ -219,6 +220,7 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
newMana.add(mana);
|
||||
newMana.add(triggeredManaVariation);
|
||||
this.add(newMana);
|
||||
wasUsable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -229,21 +231,8 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
for (Mana previousMana : copy) {
|
||||
CombineWithExisting:
|
||||
for (Mana manaOption : ability.getManaCosts().getManaOptions()) {
|
||||
Mana newMana = new Mana(previousMana);
|
||||
if (previousMana.includesMana(manaOption)) { // costs can be paid
|
||||
newMana.subtractCost(manaOption);
|
||||
newMana.add(triggeredManaVariation);
|
||||
// if the new mana is in all colors more than another already existing than replace
|
||||
for (Mana existingMana : this) {
|
||||
Mana moreValuable = Mana.getMoreValuableMana(newMana, existingMana);
|
||||
if (moreValuable != null) {
|
||||
existingMana.setToMana(moreValuable);
|
||||
replaces++;
|
||||
continue CombineWithExisting;
|
||||
}
|
||||
}
|
||||
// no existing Mana includes this new mana so add
|
||||
this.add(newMana);
|
||||
wasUsable |= subtractCostAddMana(manaOption, triggeredManaVariation, ability.getCosts().isEmpty(), previousMana, ability, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -264,6 +253,35 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
return wasUsable;
|
||||
}
|
||||
|
||||
public boolean addManaPoolDependant(List<ActivatedManaAbilityImpl> abilities, Game game) {
|
||||
boolean wasUsable = false;
|
||||
if (!abilities.isEmpty()) {
|
||||
if (abilities.size() == 1) {
|
||||
ActivatedManaAbilityImpl ability = (ActivatedManaAbilityImpl) abilities.get(0);
|
||||
List<Mana> copy = copy();
|
||||
this.clear();
|
||||
for (Mana previousMana : copy) {
|
||||
Mana startingMana = previousMana.copy();
|
||||
Mana manaCosts = ability.getManaCosts().getMana();
|
||||
if (startingMana.includesMana(manaCosts)) { // can pay the mana costs to use the ability
|
||||
for (Mana manaOption : ability.getManaCosts().getManaOptions()) {
|
||||
if (!subtractCostAddMana(manaOption, null, ability.getCosts().isEmpty(), startingMana, ability, game)) {
|
||||
// the starting mana includes mana parts that the increased mana does not include, so add starting mana also as an option
|
||||
add(previousMana);
|
||||
}
|
||||
}
|
||||
wasUsable = true;
|
||||
} else {
|
||||
// mana costs can't be paid so keep starting mana
|
||||
add(previousMana);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return wasUsable;
|
||||
}
|
||||
|
||||
public static List<Mana> getTriggeredManaVariations(Game game, Ability ability, Mana baseMana) {
|
||||
List<Mana> baseManaPlusTriggeredMana = new ArrayList<>();
|
||||
baseManaPlusTriggeredMana.add(baseMana);
|
||||
|
@ -391,62 +409,60 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
* @param oldManaWasReplaced returns the info if the new complete mana does
|
||||
* replace the current mana completely
|
||||
*/
|
||||
private boolean subtractCostAddMana(Mana cost, Mana manaToAdd, boolean onlyManaCosts, Mana currentMana) {
|
||||
private boolean subtractCostAddMana(Mana cost, Mana manaToAdd, boolean onlyManaCosts, Mana currentMana, ManaAbility manaAbility, Game game) {
|
||||
boolean oldManaWasReplaced = false; // true if the newly created mana includes all mana possibilities of the old
|
||||
boolean repeatable = false;
|
||||
if ((manaToAdd.countColored() > 0 || manaToAdd.getAny() > 0) && manaToAdd.count() > 0 && onlyManaCosts) {
|
||||
// deactivated because it does cause loops TODO: Find reason
|
||||
if (manaToAdd != null && (manaToAdd.countColored() > 0 || manaToAdd.getAny() > 0) && manaToAdd.count() > 0 && onlyManaCosts) {
|
||||
repeatable = true; // only replace to any with mana costs only will be repeated if able
|
||||
}
|
||||
Mana prevMana = currentMana.copy();
|
||||
// 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 : ManaOptions.getPossiblePayCombinations(cost.getGeneric(), currentMana)) {
|
||||
Mana currentManaCopy = currentMana.copy();
|
||||
while (currentManaCopy.includesMana(payCombination)) { // loop for multiple usage if possible
|
||||
boolean newCombinations = false;
|
||||
|
||||
for (Mana payCombination : ManaOptions.getPossiblePayCombinations(cost, currentMana)) {
|
||||
Mana currentManaCopy = currentMana.copy(); // copy start mana because in iteration it will be updated
|
||||
while (currentManaCopy.includesMana(payCombination)) { // loop for multiple usage if possible
|
||||
boolean newCombinations = false;
|
||||
|
||||
if (manaToAdd == null) {
|
||||
Mana newMana = currentManaCopy.copy();
|
||||
newMana.subtract(payCombination);
|
||||
for (Mana mana : manaAbility.getNetMana(game, newMana)) { // get the mana to add from the ability related to the currently generated possible mana pool
|
||||
newMana.add(mana);
|
||||
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
|
||||
|
||||
Mana moreValuable = Mana.getMoreValuableMana(currentManaCopy, newMana);
|
||||
if (newMana.equals(moreValuable)) {
|
||||
oldManaWasReplaced = true; // the new mana includes all possibilities of the old one, so no need to add it after return
|
||||
if (!currentMana.equalManaValue(currentManaCopy)) {
|
||||
this.removeEqualMana(currentManaCopy);
|
||||
}
|
||||
}
|
||||
currentManaCopy = newMana.copy();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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
|
||||
newCombinations = true; // repeat the while as long there are new combinations and usage is repeatable
|
||||
Mana moreValuable = Mana.getMoreValuableMana(currentManaCopy, newMana);
|
||||
if (newMana.equals(moreValuable)) {
|
||||
oldManaWasReplaced = true; // the new mana includes all possible mana of the old one, so no need to add it after return
|
||||
if (!currentMana.equalManaValue(currentManaCopy)) {
|
||||
this.removeEqualMana(currentManaCopy);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!newCombinations || !repeatable) {
|
||||
break;
|
||||
currentManaCopy = newMana.copy();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
forceManaDeduplication();
|
||||
|
||||
return oldManaWasReplaced;
|
||||
|
@ -457,12 +473,23 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
* @param manaAvailable
|
||||
* @return
|
||||
*/
|
||||
public static List<Mana> getPossiblePayCombinations(int number, Mana manaAvailable) {
|
||||
public static List<Mana> getPossiblePayCombinations(Mana manaCost, Mana manaAvailable) {
|
||||
List<Mana> payCombinations = new ArrayList<>();
|
||||
List<String> payCombinationsStrings = new ArrayList<>();
|
||||
// handle fixed mana costs
|
||||
Mana fixedMana = manaCost.copy();
|
||||
if (manaCost.getGeneric() == 0) {
|
||||
payCombinations.add(fixedMana);
|
||||
return payCombinations;
|
||||
}
|
||||
fixedMana.setGeneric(0);
|
||||
Mana manaAfterFixedPayment = manaAvailable.copy();
|
||||
manaAfterFixedPayment.subtract(fixedMana);
|
||||
|
||||
// handle generic mana costs
|
||||
if (manaAvailable.countColored() > 0) {
|
||||
|
||||
for (int i = 0; i < number; i++) {
|
||||
for (int i = 0; i < manaCost.getGeneric(); i++) {
|
||||
List<Mana> existingManas = new ArrayList<>();
|
||||
if (i > 0) {
|
||||
existingManas.addAll(payCombinations);
|
||||
|
@ -472,7 +499,7 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
existingManas.add(new Mana());
|
||||
}
|
||||
for (Mana existingMana : existingManas) {
|
||||
Mana manaToPayFrom = manaAvailable.copy();
|
||||
Mana manaToPayFrom = manaAfterFixedPayment.copy();
|
||||
manaToPayFrom.subtract(existingMana);
|
||||
if (manaToPayFrom.getBlack() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.BlackMana(1).toString())) {
|
||||
manaToPayFrom.subtract(Mana.BlackMana(1));
|
||||
|
@ -494,6 +521,10 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
manaToPayFrom.subtract(Mana.WhiteMana(1));
|
||||
ManaOptions.addManaCombination(Mana.WhiteMana(1), existingMana, payCombinations, payCombinationsStrings);
|
||||
}
|
||||
if (manaToPayFrom.getColorless() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.ColorlessMana(1).toString())) {
|
||||
manaToPayFrom.subtract(Mana.ColorlessMana(1));
|
||||
ManaOptions.addManaCombination(Mana.ColorlessMana(1), existingMana, payCombinations, payCombinationsStrings);
|
||||
}
|
||||
// Pay with any only needed if colored payment was not possible
|
||||
if (payCombinations.isEmpty() && manaToPayFrom.getAny() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.AnyMana(1).toString())) {
|
||||
manaToPayFrom.subtract(Mana.AnyMana(1));
|
||||
|
@ -502,7 +533,10 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
payCombinations.add(Mana.ColorlessMana(number));
|
||||
payCombinations.add(Mana.ColorlessMana(manaCost.getGeneric()));
|
||||
}
|
||||
for (Mana mana : payCombinations) {
|
||||
mana.add(fixedMana);
|
||||
}
|
||||
return payCombinations;
|
||||
}
|
||||
|
@ -517,6 +551,18 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
return false;
|
||||
}
|
||||
|
||||
public boolean removeEqualMana(Mana manaToRemove) {
|
||||
boolean result = false;
|
||||
for (Iterator<Mana> iterator = this.iterator(); iterator.hasNext();) {
|
||||
Mana next = iterator.next();
|
||||
if (next.equalManaValue(manaToRemove)) {
|
||||
iterator.remove();
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void addManaCombination(Mana mana, Mana existingMana, List<Mana> payCombinations, List<String> payCombinationsStrings) {
|
||||
Mana newMana = existingMana.copy();
|
||||
newMana.add(mana);
|
||||
|
@ -572,6 +618,7 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
Iterator<Mana> it = this.iterator();
|
||||
if (!it.hasNext()) {
|
||||
|
|
|
@ -71,5 +71,6 @@ public class SimpleManaAbility extends ActivatedManaAbilityImpl {
|
|||
}
|
||||
return new ArrayList<>(netMana);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import mage.constants.ManaType;
|
|||
public abstract class TriggeredManaAbility extends TriggeredAbilityImpl implements ManaAbility {
|
||||
|
||||
protected List<Mana> netMana = new ArrayList<>();
|
||||
protected boolean poolDependant;
|
||||
|
||||
public TriggeredManaAbility(Zone zone, ManaEffect effect) {
|
||||
this(zone, effect, false);
|
||||
|
@ -37,6 +38,7 @@ public abstract class TriggeredManaAbility extends TriggeredAbilityImpl implemen
|
|||
public TriggeredManaAbility(final TriggeredManaAbility ability) {
|
||||
super(ability);
|
||||
this.netMana.addAll(ability.netMana);
|
||||
this.poolDependant = ability.poolDependant;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -60,6 +62,23 @@ public abstract class TriggeredManaAbility extends TriggeredAbilityImpl implemen
|
|||
return new ArrayList<>(netMana);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Mana> getNetMana(Game game, Mana possibleManaInPool) {
|
||||
if (isPoolDependant()) {
|
||||
List<Mana> poolDependantNetMana = new ArrayList<>();
|
||||
for (Effect effect : getEffects()) {
|
||||
if (effect instanceof ManaEffect) {
|
||||
List<Mana> effectNetMana = ((ManaEffect) effect).getNetMana(game, possibleManaInPool, this);
|
||||
if (effectNetMana != null) {
|
||||
poolDependantNetMana.addAll(effectNetMana);
|
||||
}
|
||||
}
|
||||
}
|
||||
return poolDependantNetMana;
|
||||
}
|
||||
return getNetMana(game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ManaType> getProducableManaTypes(Game game) {
|
||||
Set<ManaType> manaTypes = new HashSet<>();
|
||||
|
@ -80,4 +99,16 @@ public abstract class TriggeredManaAbility extends TriggeredAbilityImpl implemen
|
|||
public boolean definesMana(Game game) {
|
||||
return !netMana.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPoolDependant() {
|
||||
return poolDependant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TriggeredManaAbility setPoolDependant(boolean poolDependant) {
|
||||
this.poolDependant = poolDependant;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2894,7 +2894,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
for (Permanent permanent : game.getBattlefield().getActivePermanents(playerId, game)) { // Some permanents allow use of abilities from non controlling players. so check all permanents in range
|
||||
Boolean canUse = null;
|
||||
boolean canAdd = false;
|
||||
boolean withCost = false;
|
||||
boolean useLater = false; // sources with mana costs or mana pool dependency
|
||||
Abilities<ActivatedManaAbilityImpl> manaAbilities
|
||||
= permanent.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, playerId, game); // returns ability only if canActivate is true
|
||||
for (Iterator<ActivatedManaAbilityImpl> it = manaAbilities.iterator(); it.hasNext();) {
|
||||
|
@ -2907,7 +2907,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (!ability.hasTapCost()) {
|
||||
it.remove();
|
||||
Abilities<ActivatedManaAbilityImpl> noTapAbilities = new AbilitiesImpl<>(ability);
|
||||
if (ability.getManaCosts().isEmpty()) {
|
||||
if (ability.getManaCosts().isEmpty() && !ability.isPoolDependant()) {
|
||||
sourceWithoutManaCosts.add(noTapAbilities);
|
||||
} else {
|
||||
sourceWithCosts.add(noTapAbilities);
|
||||
|
@ -2916,14 +2916,14 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
|
||||
canAdd = true;
|
||||
if (!ability.getManaCosts().isEmpty()) {
|
||||
withCost = true;
|
||||
if (!ability.getManaCosts().isEmpty() || ability.isPoolDependant()) {
|
||||
useLater = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (canAdd) {
|
||||
if (withCost) {
|
||||
if (useLater) {
|
||||
sourceWithCosts.add(manaAbilities);
|
||||
} else {
|
||||
sourceWithoutManaCosts.add(manaAbilities);
|
||||
|
@ -2936,17 +2936,29 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
|
||||
boolean anAbilityWasUsed = true;
|
||||
boolean usePoolDependantAbilities = false; // use such abilities later than other if possible because it can maximize mana production
|
||||
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;
|
||||
if (usePoolDependantAbilities || !manaAbilities.hasPoolDependantAbilities()) {
|
||||
boolean used;
|
||||
if (manaAbilities.hasPoolDependantAbilities()) {
|
||||
used = availableMana.addManaPoolDependant(manaAbilities, game);
|
||||
} else {
|
||||
used = availableMana.addManaWithCost(manaAbilities, game);
|
||||
}
|
||||
if (used) {
|
||||
iterator.remove();
|
||||
availableMana.removeDuplicated();
|
||||
anAbilityWasUsed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!anAbilityWasUsed && !usePoolDependantAbilities) {
|
||||
usePoolDependantAbilities = true;
|
||||
anAbilityWasUsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// remove duplicated variants (see ManaOptionsTest for info - when that rises)
|
||||
|
|
Loading…
Reference in a new issue