* Added getProducableManaTypes method for mana effects to handle Squandered Resources or Reflecting Pool like abilities.

* Fixes to Soldevi Adnate, Skirge Familiar, Mana Web.
This commit is contained in:
LevelX2 2020-08-02 10:51:22 +02:00
parent 121e1043ab
commit 67dd45c1c7
25 changed files with 420 additions and 404 deletions

View file

@ -3,7 +3,6 @@ package mage.cards.k;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.RestrictionEffect;
import mage.abilities.keyword.FlyingAbility;
@ -119,14 +118,12 @@ class KatabaticWindsRuleModifyingEffect extends ContinuousRuleModifyingEffectImp
public boolean applies(GameEvent event, Ability source, Game game) {
MageObject object = game.getObject(event.getSourceId());
Optional<Ability> ability = game.getAbility(event.getTargetId(), event.getSourceId());
if (ability.isPresent()
return ability.isPresent()
&& object != null
&& object.isCreature()
&& object.getAbilities().contains(FlyingAbility.getInstance())
&& game.getState().getPlayersInRange(source.getControllerId(), game).contains(event.getPlayerId())) {
return ability.get().getCosts().stream().anyMatch((cost) -> (cost instanceof TapSourceCost));
}
return false;
&& game.getState().getPlayersInRange(source.getControllerId(), game).contains(event.getPlayerId())
&& ability.get().hasTapCost();
}
@Override

View file

@ -66,10 +66,8 @@ class HasAbilityWithTapSymbolPredicate implements Predicate<MageObject> {
for (Ability ability : abilities) {
if ((ability.getAbilityType() == AbilityType.ACTIVATED || ability.getAbilityType() == AbilityType.MANA) && !ability.getCosts().isEmpty()) {
for (Cost cost : ability.getCosts()) {
if (cost instanceof TapSourceCost) {
if (ability.hasTapCost()) {
return true;
}
}
}
}

View file

@ -2,15 +2,18 @@
package mage.cards.m;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.mana.ActivatedManaAbilityImpl;
import mage.abilities.mana.AnyColorLandsProduceManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ManaType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.common.FilterLandPermanent;
@ -61,6 +64,9 @@ class ManaWebTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (game.inCheckPlayableState()) {
return false;
}
if (game.getOpponents(controllerId).contains(event.getPlayerId())) {
Permanent permanent = game.getPermanent(event.getSourceId());
@ -103,35 +109,19 @@ class ManaWebeffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = null;
if (game != null && source != null) {
permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
}
if (permanent != null && game != null) {
Mana mana = new Mana();
for (ActivatedManaAbilityImpl ability : permanent.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD)) {
for (Mana netMana : ability.getNetMana(game)) {
mana.add(netMana);
}
}
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null) {
Set<ManaType> manaTypesSource = AnyColorLandsProduceManaAbility.getManaTypesFromPermanent(permanent, game);
boolean tappedLands = false;
for (Permanent opponentPermanent : game.getBattlefield().getActivePermanents(filter, permanent.getControllerId(), game)) {
if (Objects.equals(opponentPermanent.getControllerId(), permanent.getControllerId())) {
Mana opponentLandMana = new Mana();
for (ActivatedManaAbilityImpl ability : opponentPermanent.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, game)) {
for (Mana netMana : ability.getNetMana(game)) {
opponentLandMana.add(netMana);
Set<ManaType> manaTypes = AnyColorLandsProduceManaAbility.getManaTypesFromPermanent(opponentPermanent, game);
for (ManaType manaType : manaTypes) {
if (manaTypesSource.contains(manaType)) {
tappedLands = opponentPermanent.tap(game) || tappedLands;
break;
}
}
if (mana.containsAny(opponentLandMana, true)) {
tappedLands = opponentPermanent.tap(game) || tappedLands;
}
}
}
return tappedLands;

View file

@ -3,8 +3,6 @@ package mage.cards.p;
import java.util.UUID;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.costs.Cost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.GainLifeEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -25,7 +23,7 @@ public final class Powerleech extends CardImpl {
public Powerleech(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}{G}");
// Whenever an artifact an opponent controls becomes tapped or an opponent activates an artifact's ability without {tap} in its activation cost, you gain 1 life.
// Whenever an artifact an opponent controls becomes tapped or an opponent activates an artifact's ability without {T} in its activation cost, you gain 1 life.
this.addAbility(new PowerleechTriggeredAbility());
}
@ -75,17 +73,8 @@ class PowerleechTriggeredAbility extends TriggeredAbilityImpl {
if (stackAbility == null) {
return false;
}
boolean triggerable = true;
for (Cost cost : stackAbility.getCosts()) {
if (cost instanceof TapSourceCost) {
triggerable = false;
break;
}
}
if (!triggerable) {
return false;
}
return player.hasOpponent(permanent.getControllerId(), game);
return !stackAbility.hasTapCost()
&& player.hasOpponent(permanent.getControllerId(), game);
}
if (event.getType() == GameEvent.EventType.TAPPED) {
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId());

View file

@ -7,7 +7,6 @@ import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.common.AttachEffect;
@ -104,16 +103,12 @@ class SerraBestiaryRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl
}
MageObject object = game.getObject(event.getSourceId());
Optional<Ability> ability = game.getAbility(event.getTargetId(), event.getSourceId());
if (ability.isPresent()
return ability.isPresent()
&& object != null
&& object.isCreature()
&& object.getId().equals(enchantedCreature.getId())
&& game.getState().getPlayersInRange(source.getControllerId(), game).contains(event.getPlayerId())) {
if (ability.get().getCosts().stream().anyMatch((cost) -> (cost instanceof TapSourceCost))) {
return true;
}
}
return false;
&& game.getState().getPlayersInRange(source.getControllerId(), game).contains(event.getPlayerId())
&& ability.get().hasTapCost();
}
@Override

View file

@ -5,6 +5,8 @@ import java.util.UUID;
import mage.MageInt;
import mage.Mana;
import mage.abilities.costs.common.DiscardCardCost;
import mage.abilities.dynamicvalue.IntPlusDynamicValue;
import mage.abilities.dynamicvalue.common.CardsInControllerHandCount;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.mana.SimpleManaAbility;
import mage.cards.CardImpl;
@ -29,7 +31,13 @@ public final class SkirgeFamiliar extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// Discard a card: Add {B}.
this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.BlackMana(1), new DiscardCardCost(false)));
// public SimpleManaAbility(Zone zone, Mana mana, Cost cost, DynamicValue netAmount) {
this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.BlackMana(1),
new DiscardCardCost(false),
// not perfect but for hand cards correct, activated abilities on Battlefield will miss one possible available mana
// to solve this we have to do possible mana calculation per pell/ability to use.
new IntPlusDynamicValue(-1, CardsInControllerHandCount.instance)
));
}
public SkirgeFamiliar(final SkirgeFamiliar card) {

View file

@ -7,6 +7,8 @@ import mage.Mana;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.costs.common.SacrificeTargetCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.dynamicvalue.common.HighestCMCOfPermanentValue;
import mage.abilities.dynamicvalue.common.SacrificeCostConvertedMana;
import mage.abilities.mana.DynamicManaAbility;
import mage.cards.CardImpl;
@ -38,8 +40,9 @@ public final class SoldeviAdnate extends CardImpl {
this.toughness = new MageInt(2);
// {T}, Sacrifice a black or artifact creature: Add an amount of {B} equal to the sacrificed creature's converted mana cost.
Ability ability = new DynamicManaAbility(Mana.BlackMana(1), new SacrificeCostConvertedMana("creature"),
"add an amount of {B} equal to the sacrificed creature's converted mana cost");
Ability ability = new DynamicManaAbility(Mana.BlackMana(1), new SacrificeCostConvertedMana("creature"), new TapSourceCost(),
"add an amount of {B} equal to the sacrificed creature's converted mana cost" , false,
new HighestCMCOfPermanentValue(filter, true));
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter)));
this.addAbility(ability);
}

View file

@ -13,7 +13,6 @@ import mage.cards.CardSetInfo;
import mage.choices.Choice;
import mage.choices.ChoiceColor;
import mage.constants.CardType;
import mage.constants.ColoredManaSymbol;
import mage.constants.Zone;
import mage.filter.common.FilterControlledLandPermanent;
import mage.filter.common.FilterControlledPermanent;
@ -23,8 +22,13 @@ import mage.players.Player;
import mage.target.common.TargetControlledPermanent;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import mage.abilities.mana.AnyColorLandsProduceManaAbility;
import mage.constants.ManaType;
import mage.filter.StaticFilters;
/**
* @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
@ -64,24 +68,35 @@ class SquanderedResourcesEffect extends ManaEffect {
@Override
public List<Mana> getNetMana(Game game, Ability source) {
List<Mana> netManas = new ArrayList<>();
Mana types = getManaTypes(game, source);
if (types.getBlack() > 0) {
netManas.add(new Mana(ColoredManaSymbol.B));
Set<ManaType> manaTypes = new HashSet<>();
if (game != null && game.inCheckPlayableState()) {
for (Permanent land : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_LAND, source.getControllerId(), game)) {
manaTypes.addAll(AnyColorLandsProduceManaAbility.getManaTypesFromPermanent(land, game));
}
} else {
manaTypes = getManaTypesFromSacrificedPermanent(game, source);
}
if (types.getRed() > 0) {
netManas.add(new Mana(ColoredManaSymbol.R));
}
if (types.getBlue() > 0) {
netManas.add(new Mana(ColoredManaSymbol.U));
}
if (types.getGreen() > 0) {
netManas.add(new Mana(ColoredManaSymbol.G));
}
if (types.getWhite() > 0) {
netManas.add(new Mana(ColoredManaSymbol.W));
}
if (types.getGeneric() > 0) {
netManas.add(Mana.ColorlessMana(1));
if (manaTypes.size() == 5 && !manaTypes.contains(ManaType.COLORLESS) && !manaTypes.contains(ManaType.GENERIC)) {
netManas.add(Mana.AnyMana(1));
} else {
if (manaTypes.contains(ManaType.BLACK)) {
netManas.add(Mana.BlackMana(1));
}
if (manaTypes.contains(ManaType.RED)) {
netManas.add(Mana.RedMana(1));
}
if (manaTypes.contains(ManaType.BLUE)) {
netManas.add(Mana.BlueMana(1));
}
if (manaTypes.contains(ManaType.GREEN)) {
netManas.add(Mana.GreenMana(1));
}
if (manaTypes.contains(ManaType.WHITE)) {
netManas.add(Mana.WhiteMana(1));
}
if (manaTypes.contains(ManaType.COLORLESS)) {
netManas.add(Mana.ColorlessMana(1));
}
}
return netManas;
}
@ -92,34 +107,26 @@ class SquanderedResourcesEffect extends ManaEffect {
if (game == null) {
return mana;
}
Mana types = getManaTypes(game, source);
Set<ManaType> manaTypes = getManaTypesFromSacrificedPermanent(game, source);
Choice choice = new ChoiceColor(true);
choice.getChoices().clear();
choice.setMessage("Pick a mana color");
if (types.getBlack() > 0) {
if (manaTypes.contains(ManaType.BLACK)) {
choice.getChoices().add("Black");
}
if (types.getRed() > 0) {
if (manaTypes.contains(ManaType.RED)) {
choice.getChoices().add("Red");
}
if (types.getBlue() > 0) {
if (manaTypes.contains(ManaType.BLUE)) {
choice.getChoices().add("Blue");
}
if (types.getGreen() > 0) {
if (manaTypes.contains(ManaType.GREEN)) {
choice.getChoices().add("Green");
}
if (types.getWhite() > 0) {
if (manaTypes.contains(ManaType.WHITE)) {
choice.getChoices().add("White");
}
if (types.getColorless() > 0) {
choice.getChoices().add("Colorless");
}
if (types.getAny() > 0) {
choice.getChoices().add("Black");
choice.getChoices().add("Red");
choice.getChoices().add("Blue");
choice.getChoices().add("Green");
choice.getChoices().add("White");
if (manaTypes.contains(ManaType.COLORLESS)) {
choice.getChoices().add("Colorless");
}
if (!choice.getChoices().isEmpty()) {
@ -158,20 +165,14 @@ class SquanderedResourcesEffect extends ManaEffect {
return mana;
}
private Mana getManaTypes(Game game, Ability source) {
Mana types = new Mana();
private Set<ManaType> getManaTypesFromSacrificedPermanent(Game game, Ability source) {
Set<ManaType> types = new HashSet<>();
for (Cost cost : source.getCosts()) {
if (cost instanceof SacrificeTargetCost && !((SacrificeTargetCost) cost).getPermanents().isEmpty()) {
Permanent land = ((SacrificeTargetCost) cost).getPermanents().get(0);
if (land != null) {
Abilities<ActivatedManaAbilityImpl> manaAbilities = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD);
for (ActivatedManaAbilityImpl ability : manaAbilities) {
if (!ability.equals(source) && ability.definesMana(game)) {
for (Mana netMana : ability.getNetMana(game)) {
types.add(netMana);
}
}
}
types.addAll(AnyColorLandsProduceManaAbility.getManaTypesFromPermanent(land, game));
break;
}
}
}

View file

@ -1,43 +1,34 @@
package mage.cards.s;
import mage.Mana;
import mage.abilities.Abilities;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTappedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.mana.ActivatedManaAbilityImpl;
import mage.abilities.mana.SimpleManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.choices.Choice;
import mage.choices.ChoiceColor;
import mage.constants.CardType;
import mage.constants.ColoredManaSymbol;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.common.FilterControlledLandPermanent;
import mage.filter.common.FilterControlledPermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.abilities.mana.AnyColorLandsProduceManaAbility;
import mage.constants.TargetController;
/**
* @author anonymous
*/
public final class StarCompass extends CardImpl {
private static final FilterControlledPermanent filter = new FilterControlledLandPermanent();
static {
filter.add(SuperType.BASIC.getPredicate());
}
public StarCompass(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
// Star Compass enters the battlefield tapped.
this.addAbility(new EntersBattlefieldTappedAbility());
// {tap}: Add one mana of any color that a basic land you control could produce.
this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new StarCompassManaEffect(), new TapSourceCost()));
// {T}: Add one mana of any color that a basic land you control could produce.
this.addAbility(new AnyColorLandsProduceManaAbility(TargetController.YOU, true, filter));
}
public StarCompass(final StarCompass card) {
@ -48,144 +39,4 @@ public final class StarCompass extends CardImpl {
public StarCompass copy() {
return new StarCompass(this);
}
}
class StarCompassManaEffect extends ManaEffect {
private static final FilterControlledPermanent filter = new FilterControlledLandPermanent();
static {
filter.add(SuperType.BASIC.getPredicate());
}
public StarCompassManaEffect() {
super();
staticText = "Add one mana of any type that a basic land you control could produce";
}
public StarCompassManaEffect(final StarCompassManaEffect effect) {
super(effect);
}
@Override
public List<Mana> getNetMana(Game game, Ability source) {
List<Mana> netManas = new ArrayList<>();
Mana types = getManaTypes(game, source);
if (types.getBlack() > 0) {
netManas.add(new Mana(ColoredManaSymbol.B));
}
if (types.getRed() > 0) {
netManas.add(new Mana(ColoredManaSymbol.R));
}
if (types.getBlue() > 0) {
netManas.add(new Mana(ColoredManaSymbol.U));
}
if (types.getGreen() > 0) {
netManas.add(new Mana(ColoredManaSymbol.G));
}
if (types.getWhite() > 0) {
netManas.add(new Mana(ColoredManaSymbol.W));
}
if (types.getGeneric() > 0) {
netManas.add(Mana.ColorlessMana(1));
}
return netManas;
}
@Override
public Mana produceMana(Game game, Ability source) {
Mana mana = new Mana();
if (game == null) {
return mana;
}
Mana types = getManaTypes(game, source);
Choice choice = new ChoiceColor(true);
choice.getChoices().clear();
choice.setMessage("Pick a mana color");
if (types.getBlack() > 0) {
choice.getChoices().add("Black");
}
if (types.getRed() > 0) {
choice.getChoices().add("Red");
}
if (types.getBlue() > 0) {
choice.getChoices().add("Blue");
}
if (types.getGreen() > 0) {
choice.getChoices().add("Green");
}
if (types.getWhite() > 0) {
choice.getChoices().add("White");
}
if (types.getColorless() > 0) {
choice.getChoices().add("Colorless");
}
if (types.getAny() > 0) {
choice.getChoices().add("Black");
choice.getChoices().add("Red");
choice.getChoices().add("Blue");
choice.getChoices().add("Green");
choice.getChoices().add("White");
choice.getChoices().add("Colorless");
}
if (!choice.getChoices().isEmpty()) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return null;
}
if (choice.getChoices().size() == 1) {
choice.setChoice(choice.getChoices().iterator().next());
} else {
if (!player.choose(outcome, choice, game)) {
return mana;
}
}
if (choice.getChoice() != null) {
switch (choice.getChoice()) {
case "Black":
mana.setBlack(1);
break;
case "Blue":
mana.setBlue(1);
break;
case "Red":
mana.setRed(1);
break;
case "Green":
mana.setGreen(1);
break;
case "White":
mana.setWhite(1);
break;
case "Colorless":
mana.setColorless(1);
break;
}
}
}
return mana;
}
private Mana getManaTypes(Game game, Ability source) {
Mana types = new Mana();
if (game != null) {
List<Permanent> lands = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game);
for (Permanent land : lands) {
Abilities<ActivatedManaAbilityImpl> manaAbilities = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD);
for (ActivatedManaAbilityImpl ability : manaAbilities) {
if (!ability.equals(source) && ability.definesMana(game)) {
for (Mana netMana : ability.getNetMana(game)) {
types.add(netMana);
}
}
}
}
}
return types;
}
@Override
public StarCompassManaEffect copy() {
return new StarCompassManaEffect(this);
}
}
}

View file

@ -201,4 +201,58 @@ public class NonTappingManaAbilitiesTest extends CardTestPlayerBase {
Assert.assertEquals("mana variations don't fit", 1, manaOptions.size());
assertManaOptions("{R}{R}{R}", manaOptions);
}
@Test
public void TestSquanderedResources() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
addCard(Zone.BATTLEFIELD, playerA, "Taiga", 1); // ({T}: Add {R} or {G}.)
// {T}: Add {C}.
// {1}, {T}: Put a storage counter on Calciform Pools.
// {1}, Remove X storage counters from Calciform Pools: Add X mana in any combination of {W} and/or {U}.
addCard(Zone.BATTLEFIELD, playerA, "Calciform Pools", 1);
// {T}: Add {U}. If you played a land this turn, add {B} instead.
addCard(Zone.BATTLEFIELD, playerA, "River of Tears", 1);
// Sacrifice a land: Add one mana of any type the sacrificed land could produce.
addCard(Zone.BATTLEFIELD, playerA, "Squandered Resources", 1);
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
execute();
assertAllCommandsUsed();
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
Assert.assertEquals("mana variations don't fit", 9, manaOptions.size());
assertManaOptions("{C}{U}{R}{R}{G}", manaOptions);
assertManaOptions("{C}{U}{U}{G}{G}", manaOptions);
assertManaOptions("{C}{U}{U}{R}{G}", manaOptions);
assertManaOptions("{C}{U}{G}{G}{G}", manaOptions);
assertManaOptions("{C}{U}{R}{G}{G}", manaOptions);
assertManaOptions("{C}{W}{U}{G}{G}", manaOptions);
assertManaOptions("{C}{W}{U}{R}{G}", manaOptions);
assertManaOptions("{C}{C}{U}{G}{G}", manaOptions);
assertManaOptions("{C}{C}{U}{R}{G}", manaOptions);
}
@Test
public void TestSquanderedResourcesWithManaConfluence() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
// {T}, Pay 1 life: Add one mana of any color.
addCard(Zone.BATTLEFIELD, playerA, "Mana Confluence", 1);
// Sacrifice a land: Add one mana of any type the sacrificed land could produce.
addCard(Zone.BATTLEFIELD, playerA, "Squandered Resources", 1);
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
execute();
assertAllCommandsUsed();
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
Assert.assertEquals("mana variations don't fit", 1, manaOptions.size());
assertManaOptions("{G}{Any}{Any}", manaOptions);
}
}

View file

@ -288,8 +288,27 @@ public class ReflectingPoolTest extends CardTestPlayerBase {
execute();
ManaOptions options = playerA.getAvailableManaTest(currentGame);
Assert.assertEquals("Player A should be able to create only 3 different mana options", 2, options.size());
Assert.assertEquals("Player A should be able to create only 2 different mana options", 2, options.size());
assertManaOptions("{C}{C}{Any}", options);
assertManaOptions("{C}{Any}{Any}", options);
}
@Test
public void testWithCalciformPools() {
// {T}: Add {C}.
// {1}, {T}: Put a storage counter on Calciform Pools.
// {1}, Remove X storage counters from Calciform Pools: Add X mana in any combination of {W} and/or {U}.
addCard(Zone.BATTLEFIELD, playerA, "Calciform Pools", 1);
// {T}: Add one mana of any type that a land you control could produce.
addCard(Zone.BATTLEFIELD, playerA, "Reflecting Pool", 1);
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
execute();
ManaOptions options = playerA.getAvailableManaTest(currentGame);
Assert.assertEquals("Player A should be able to create only 3 different mana options", 3, options.size());
assertManaOptions("{C}{C}", options);
assertManaOptions("{C}{W}", options);
assertManaOptions("{C}{U}", options);
}
}

View file

@ -321,9 +321,11 @@ public class ManaOptionsTest extends CardTestPlayerBase {
execute();
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
Assert.assertEquals("mana variations don't fit", 1, manaOptions.size());
Assert.assertEquals("mana variations don't fit", 3, manaOptions.size());
assertDuplicatedManaOptions(manaOptions);
assertManaOptions("{C}{C}", manaOptions);
assertManaOptions("{Any}{Any}", manaOptions);
assertManaOptions("{C}{Any}", manaOptions);
}
@Test

View file

@ -170,39 +170,22 @@ public abstract class MageObjectImpl implements MageObject {
// its frame colors.
if (this.isLand()) {
ObjectColor cl = frameColor.copy();
Set<ManaType> manaTypes = EnumSet.noneOf(ManaType.class);
for (Ability ab : getAbilities()) {
if (ab instanceof ActivatedManaAbilityImpl) {
ActivatedManaAbilityImpl mana = (ActivatedManaAbilityImpl) ab;
try {
List<Mana> manaAdded = mana.getNetMana(game);
for (Mana m : manaAdded) {
if (m.getAny() > 0) {
return new ObjectColor("WUBRG");
}
if (m.getWhite() > 0) {
cl.setWhite(true);
}
if (m.getBlue() > 0) {
cl.setBlue(true);
}
if (m.getBlack() > 0) {
cl.setBlack(true);
}
if (m.getRed() > 0) {
cl.setRed(true);
}
if (m.getGreen() > 0) {
cl.setGreen(true);
}
}
} catch (NullPointerException e) {
// Ability depends on game
// but no game passed
// All such abilities are 5-color ones
return new ObjectColor("WUBRG");
}
manaTypes.addAll(((ActivatedManaAbilityImpl) ab).getProducableManaTypes(game));
}
}
cl.setWhite(manaTypes.contains(ManaType.WHITE));
cl.setBlue(manaTypes.contains(ManaType.BLUE));
cl.setBlack(manaTypes.contains(ManaType.BLACK));
cl.setRed(manaTypes.contains(ManaType.RED));
cl.setGreen(manaTypes.contains(ManaType.GREEN));
// // Ability depends on game
// // but no game passed
// // All such abilities are 5-color ones
// return new ObjectColor("WUBRG");
return cl;
} else {
// For everything else, just return the frame colors

View file

@ -1152,10 +1152,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
}
}
if (lessMana.getColorless() > moreMana.getColorless()) {
anyDiff -= lessMana.getColorless() - moreMana.getColorless();
if (anyDiff < 0) {
return null;
}
return null; // Any (color) can't produce colorless mana
}
if (lessMana.getAny() > moreMana.getAny()) {
return null;

View file

@ -23,6 +23,7 @@ import mage.watchers.Watcher;
import java.io.Serializable;
import java.util.List;
import java.util.UUID;
import mage.abilities.costs.common.TapSourceCost;
/**
* Practically everything in the game is started from an Ability. This interface
@ -366,6 +367,19 @@ public interface Ability extends Controllable, Serializable {
* @return
*/
boolean hasSourceObjectAbility(Game game, MageObject source, GameEvent event);
/**
* Returns true if the ability has a tap itself in their costs
* @return
*/
default boolean hasTapCost() {
for (Cost cost : this.getCosts()) {
if (cost instanceof TapSourceCost) {
return true;
}
}
return false;
}
/**
* Returns true if this ability has to be shown as topmost of all the rules

View file

@ -35,6 +35,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import mage.abilities.costs.common.TapSourceCost;
/**
* @author BetaSteward_at_googlemail.com

View file

@ -13,24 +13,23 @@ import mage.game.events.ManaEvent;
import mage.players.Player;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import mage.abilities.TriggeredAbility;
import mage.constants.ManaType;
/**
* @author BetaSteward_at_googlemail.com
*/
public abstract class ManaEffect extends OneShotEffect {
protected Mana createdMana;
public ManaEffect() {
super(Outcome.PutManaInPool);
createdMana = null;
}
public ManaEffect(final ManaEffect effect) {
super(effect);
this.createdMana = effect.createdMana == null ? null : effect.createdMana.copy();
}
@Override
@ -81,6 +80,53 @@ public abstract class ManaEffect extends OneShotEffect {
return netMana;
}
/**
* 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
* applicable replacement effects. If the type of mana cant be defined,
* theres no type of mana that that permanent could produce. The "type" of
* mana is its color, or lack thereof (for colorless mana).
*
* @param game
* @param source
* @return
*/
public Set<ManaType> getProducableManaTypes(Game game, Ability source) {
return getManaTypesFromManaList(getNetMana(game, source));
}
public static Set<ManaType> getManaTypesFromManaList(List<Mana> manaList) {
Set<ManaType> manaTypes = new HashSet<>();
for (Mana mana : manaList) {
if (mana.getAny() > 0) {
manaTypes.add(ManaType.BLACK);
manaTypes.add(ManaType.BLUE);
manaTypes.add(ManaType.GREEN);
manaTypes.add(ManaType.WHITE);
manaTypes.add(ManaType.RED);
}
if (mana.getBlack() > 0) {
manaTypes.add(ManaType.BLACK);
}
if (mana.getBlue() > 0) {
manaTypes.add(ManaType.BLUE);
}
if (mana.getGreen() > 0) {
manaTypes.add(ManaType.GREEN);
}
if (mana.getWhite() > 0) {
manaTypes.add(ManaType.WHITE);
}
if (mana.getRed() > 0) {
manaTypes.add(ManaType.RED);
}
if (mana.getColorless() > 0) {
manaTypes.add(ManaType.COLORLESS);
}
}
return manaTypes;
}
/**
* 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)
@ -105,14 +151,10 @@ public abstract class ManaEffect extends OneShotEffect {
* @param source
*/
public void checkToFirePossibleEvents(Mana mana, Game game, Ability source) {
if (source.getAbilityType() == AbilityType.MANA) {
for (Cost cost : source.getCosts()) {
if (cost instanceof TapSourceCost) {
ManaEvent event = new ManaEvent(GameEvent.EventType.TAPPED_FOR_MANA, source.getSourceId(), source.getSourceId(), source.getControllerId(), mana);
if (!game.replaceEvent(event)) {
game.fireEvent(event);
}
}
if (source.getAbilityType() == AbilityType.MANA && source.hasTapCost()) {
ManaEvent event = new ManaEvent(GameEvent.EventType.TAPPED_FOR_MANA, source.getSourceId(), source.getSourceId(), source.getControllerId(), mana);
if (!game.replaceEvent(event)) {
game.fireEvent(event);
}
}
}

View file

@ -2,7 +2,9 @@ package mage.abilities.effects.mana;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import mage.Mana;
import mage.abilities.Ability;
@ -11,6 +13,7 @@ import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.mana.ManaOptions;
import mage.constants.ColoredManaSymbol;
import mage.constants.ManaType;
import mage.game.Game;
import mage.players.Player;
import mage.util.CardUtil;
@ -101,8 +104,7 @@ public class AddManaInAnyCombinationEffect extends ManaEffect {
}
@Override
public Mana produceMana(Game game, Ability source
) {
public Mana produceMana(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
Mana mana = new Mana();
@ -130,6 +132,29 @@ public class AddManaInAnyCombinationEffect extends ManaEffect {
return null;
}
@Override
public Set<ManaType> getProducableManaTypes(Game game, Ability source) {
Set<ManaType> manaTypes = new HashSet<>();
for(ColoredManaSymbol coloredManaSymbol: manaSymbols) {
if (coloredManaSymbol.equals(ColoredManaSymbol.B)) {
manaTypes.add(ManaType.BLACK);
}
if (coloredManaSymbol.equals(ColoredManaSymbol.R)) {
manaTypes.add(ManaType.RED);
}
if (coloredManaSymbol.equals(ColoredManaSymbol.G)) {
manaTypes.add(ManaType.GREEN);
}
if (coloredManaSymbol.equals(ColoredManaSymbol.U)) {
manaTypes.add(ManaType.BLUE);
}
if (coloredManaSymbol.equals(ColoredManaSymbol.W)) {
manaTypes.add(ManaType.WHITE);
}
}
return manaTypes;
}
private String setText() {
StringBuilder sb = new StringBuilder("Add ");
sb.append(CardUtil.numberToText(amount.toString()));

View file

@ -47,29 +47,31 @@ public class BasicManaEffect extends ManaEffect {
// calculate the maximum available mana
int count = netAmount.calculate(game, source, this);
Mana computedMana = new Mana();
if (manaTemplate.getBlack() > 0) {
computedMana.setBlack(count * manaTemplate.getBlack());
}
if (manaTemplate.getBlue() > 0) {
computedMana.setBlue(count * manaTemplate.getBlue());
}
if (manaTemplate.getGreen() > 0) {
computedMana.setGreen(count * manaTemplate.getGreen());
}
if (manaTemplate.getRed() > 0) {
computedMana.setRed(count * manaTemplate.getRed());
}
if (manaTemplate.getWhite() > 0) {
computedMana.setWhite(count * manaTemplate.getWhite());
}
if (manaTemplate.getColorless() > 0) {
computedMana.setColorless(count * manaTemplate.getColorless());
}
if (manaTemplate.getAny() > 0) {
throw new IllegalArgumentException("BasicManaEffect does not support {Any} mana!");
}
if (manaTemplate.getGeneric() > 0) {
computedMana.setGeneric(count * manaTemplate.getGeneric());
if (count > 0) {
if (manaTemplate.getBlack() > 0) {
computedMana.setBlack(count * manaTemplate.getBlack());
}
if (manaTemplate.getBlue() > 0) {
computedMana.setBlue(count * manaTemplate.getBlue());
}
if (manaTemplate.getGreen() > 0) {
computedMana.setGreen(count * manaTemplate.getGreen());
}
if (manaTemplate.getRed() > 0) {
computedMana.setRed(count * manaTemplate.getRed());
}
if (manaTemplate.getWhite() > 0) {
computedMana.setWhite(count * manaTemplate.getWhite());
}
if (manaTemplate.getColorless() > 0) {
computedMana.setColorless(count * manaTemplate.getColorless());
}
if (manaTemplate.getAny() > 0) {
throw new IllegalArgumentException("BasicManaEffect does not support {Any} mana!");
}
if (manaTemplate.getGeneric() > 0) {
computedMana.setGeneric(count * manaTemplate.getGeneric());
}
}
return new ArrayList<>(Arrays.asList(computedMana));
}

View file

@ -1,15 +1,19 @@
package mage.abilities.mana;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbilityImpl;
import mage.abilities.costs.Cost;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.ManaEffect;
import mage.constants.AbilityType;
import mage.constants.AsThoughEffectType;
import mage.constants.ManaType;
import mage.constants.TimingRule;
import mage.constants.Zone;
import mage.game.Game;
@ -105,6 +109,17 @@ public abstract class ActivatedManaAbilityImpl extends ActivatedAbilityImpl impl
return netManaCopy;
}
@Override
public Set<ManaType> getProducableManaTypes(Game game) {
Set<ManaType> manaTypes = new HashSet<>();
for (Effect effect : getEffects()) {
if (effect instanceof ManaEffect) {
manaTypes.addAll(((ManaEffect) effect).getProducableManaTypes(game, this));
}
}
return manaTypes;
}
/**
* Used to check if the ability itself defines mana types it can produce.
*

View file

@ -17,7 +17,10 @@ import mage.game.permanent.Permanent;
import mage.players.Player;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import mage.constants.ManaType;
/**
* @author LevelX2
@ -55,6 +58,16 @@ public class AnyColorLandsProduceManaAbility extends ActivatedManaAbilityImpl {
return true;
}
public static Set<ManaType> getManaTypesFromPermanent(Permanent permanent, Game game) {
Set<ManaType> allTypes = new HashSet<>();
if (permanent != null) {
Abilities<ActivatedManaAbilityImpl> manaAbilities = permanent.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD);
for (ActivatedManaAbilityImpl ability : manaAbilities) {
allTypes.addAll(ability.getProducableManaTypes(game));
}
}
return allTypes;
}
}
class AnyColorLandsProduceManaEffect extends ManaEffect {
@ -87,27 +100,30 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
@Override
public List<Mana> getNetMana(Game game, Ability source) {
List<Mana> netManas = new ArrayList<>();
Mana types = getManaTypes(game, source);
if (types.getBlack() > 0) {
netManas.add(new Mana(ColoredManaSymbol.B));
}
if (types.getRed() > 0) {
netManas.add(new Mana(ColoredManaSymbol.R));
}
if (types.getBlue() > 0) {
netManas.add(new Mana(ColoredManaSymbol.U));
}
if (types.getGreen() > 0) {
netManas.add(new Mana(ColoredManaSymbol.G));
}
if (types.getWhite() > 0) {
netManas.add(new Mana(ColoredManaSymbol.W));
}
if (!onlyColors && types.getColorless() > 0) {
netManas.add(Mana.ColorlessMana(1));
}
if (types.getAny() > 0) {
netManas.add(Mana.AnyMana(1));
if (game != null) {
Set<ManaType> manaTypes = getManaTypes(game, source);
if ((manaTypes.size() == 5 && !manaTypes.contains(ManaType.COLORLESS)) || manaTypes.size() == 6) { // GENERIC should never be returned from getManaTypes
netManas.add(Mana.AnyMana(1));
} else {
if (manaTypes.contains(ManaType.BLACK)) {
netManas.add(Mana.BlackMana(1));
}
if (manaTypes.contains(ManaType.RED)) {
netManas.add(Mana.RedMana(1));
}
if (manaTypes.contains(ManaType.BLUE)) {
netManas.add(Mana.BlueMana(1));
}
if (manaTypes.contains(ManaType.GREEN)) {
netManas.add(Mana.GreenMana(1));
}
if (manaTypes.contains(ManaType.WHITE)) {
netManas.add(Mana.WhiteMana(1));
}
}
if (!onlyColors && manaTypes.contains(ManaType.COLORLESS)) {
netManas.add(Mana.ColorlessMana(1));
}
}
return netManas;
}
@ -118,35 +134,28 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
if (game == null) {
return mana;
}
Mana types = getManaTypes(game, source);
Set<ManaType> types = getManaTypes(game, source);
Choice choice = new ChoiceColor(true);
choice.getChoices().clear();
choice.setMessage("Pick a mana color");
if (types.getBlack() > 0) {
choice.setMessage("Pick a mana " + (onlyColors ? "color" : "type"));
if (types.contains(ManaType.BLACK)) {
choice.getChoices().add("Black");
}
if (types.getRed() > 0) {
if (types.contains(ManaType.RED)) {
choice.getChoices().add("Red");
}
if (types.getBlue() > 0) {
if (types.contains(ManaType.BLUE)) {
choice.getChoices().add("Blue");
}
if (types.getGreen() > 0) {
if (types.contains(ManaType.GREEN)) {
choice.getChoices().add("Green");
}
if (types.getWhite() > 0) {
if (types.contains(ManaType.WHITE)) {
choice.getChoices().add("White");
}
if (!onlyColors && types.getColorless() > 0) {
if (types.contains(ManaType.COLORLESS)) {
choice.getChoices().add("Colorless");
}
if (types.getAny() > 0) { // Only any Color
choice.getChoices().add("Black");
choice.getChoices().add("Red");
choice.getChoices().add("Blue");
choice.getChoices().add("Green");
choice.getChoices().add("White");
}
if (!choice.getChoices().isEmpty()) {
Player player = game.getPlayer(source.getControllerId());
if (choice.getChoices().size() == 1) {
@ -182,24 +191,19 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
return mana;
}
private Mana getManaTypes(Game game, Ability source) {
Mana types = new Mana();
private Set<ManaType> getManaTypes(Game game, Ability source) {
Set types = new HashSet<>();
if (game == null || game.getPhase() == null) {
return types;
}
if (inManaTypeCalculation) {
if (inManaTypeCalculation) { // Stop endless loops
return types;
}
inManaTypeCalculation = true;
List<Permanent> lands = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game);
for (Permanent land : lands) {
Abilities<ActivatedManaAbilityImpl> mana = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD);
for (ActivatedManaAbilityImpl ability : mana) {
if (!ability.getSourceId().equals(source.getSourceId()) && ability.definesMana(game)) {
for (Mana netMana : ability.getNetMana(game)) {
types.add(netMana);
}
}
if (!land.getId().equals(source.getSourceId())) {
types.addAll(AnyColorLandsProduceManaAbility.getManaTypesFromPermanent(land, game));
}
}
inManaTypeCalculation = false;
@ -210,4 +214,5 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
public AnyColorLandsProduceManaEffect copy() {
return new AnyColorLandsProduceManaEffect(this);
}
}

View file

@ -6,7 +6,9 @@
package mage.abilities.mana;
import java.util.List;
import java.util.Set;
import mage.Mana;
import mage.constants.ManaType;
import mage.game.Game;
/**
@ -24,6 +26,18 @@ public interface ManaAbility {
*/
List<Mana> getNetMana(Game game);
/**
* 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
* applicable replacement effects. If the type of mana cant be defined,
* theres no type of mana that that permanent could produce. The "type" of
* mana is its color, or lack thereof (for colorless mana).
*
* @param game
* @return
*/
Set<ManaType> getProducableManaTypes(Game game);
/**
* Used to check if the ability itself defines mana types it can produce.
*

View file

@ -94,7 +94,7 @@ public class ManaOptions extends ArrayList<Mana> {
this.clear();
for (Mana netMana : netManas) {
for (Mana mana : copy) {
if (!hasTapCost(ability) || checkManaReplacementAndTriggeredMana(ability, game, netMana)) {
if (ability.hasTapCost() || checkManaReplacementAndTriggeredMana(ability, game, netMana)) {
Mana newMana = new Mana();
newMana.add(mana);
newMana.add(netMana);
@ -104,7 +104,7 @@ public class ManaOptions extends ArrayList<Mana> {
}
}
private List<List<Mana>> getSimulatedTriggeredManaFromPlayer(Game game, Ability ability) {
private static List<List<Mana>> getSimulatedTriggeredManaFromPlayer(Game game, Ability ability) {
Player player = game.getPlayer(ability.getControllerId());
List<List<Mana>> newList = new ArrayList<>();
if (player != null) {
@ -124,7 +124,7 @@ public class ManaOptions extends ArrayList<Mana> {
* @return false if mana production was completely replaced
*/
private boolean checkManaReplacementAndTriggeredMana(Ability ability, Game game, Mana mana) {
if (hasTapCost(ability)) {
if (ability.hasTapCost()) {
ManaEvent event = new ManaEvent(GameEvent.EventType.TAPPED_FOR_MANA, ability.getSourceId(), ability.getSourceId(), ability.getControllerId(), mana);
if (game.replaceEvent(event)) {
return false;
@ -137,15 +137,6 @@ public class ManaOptions extends ArrayList<Mana> {
return true;
}
public boolean hasTapCost(Ability ability) {
for (Cost cost : ability.getCosts()) {
if (cost instanceof TapSourceCost) {
return true;
}
}
return false;
}
/**
* This adds the mana the abilities can produce to the possible mana
* variabtion.
@ -267,10 +258,10 @@ public class ManaOptions extends ArrayList<Mana> {
return wasUsable;
}
private List<Mana> getTriggeredManaVariations(Game game, Ability ability, Mana baseMana) {
public static List<Mana> getTriggeredManaVariations(Game game, Ability ability, Mana baseMana) {
List<Mana> baseManaPlusTriggeredMana = new ArrayList<>();
baseManaPlusTriggeredMana.add(baseMana);
List<List<Mana>> availableTriggeredManaList = getSimulatedTriggeredManaFromPlayer(game, ability);
List<List<Mana>> availableTriggeredManaList = ManaOptions.getSimulatedTriggeredManaFromPlayer(game, ability);
for (List<Mana> availableTriggeredMana : availableTriggeredManaList) {
if (availableTriggeredMana.size() == 1) {
for (Mana prevMana : baseManaPlusTriggeredMana) {
@ -372,7 +363,7 @@ public class ManaOptions extends ArrayList<Mana> {
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 : getPossiblePayCombinations(cost.getGeneric(), currentMana)) {
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;
@ -420,7 +411,13 @@ public class ManaOptions extends ArrayList<Mana> {
return oldManaWasReplaced;
}
private List<Mana> getPossiblePayCombinations(int number, Mana manaAvailable) {
/**
*
* @param number of generic mana
* @param manaAvailable
* @return
*/
public static List<Mana> getPossiblePayCombinations(int number, Mana manaAvailable) {
List<Mana> payCombinations = new ArrayList<>();
List<String> payCombinationsStrings = new ArrayList<>();
if (manaAvailable.countColored() > 0) {
@ -439,28 +436,28 @@ public class ManaOptions extends ArrayList<Mana> {
manaToPayFrom.subtract(existingMana);
if (manaToPayFrom.getBlack() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.BlackMana(1).toString())) {
manaToPayFrom.subtract(Mana.BlackMana(1));
addManaCombination(Mana.BlackMana(1), existingMana, payCombinations, payCombinationsStrings);
ManaOptions.addManaCombination(Mana.BlackMana(1), existingMana, payCombinations, payCombinationsStrings);
}
if (manaToPayFrom.getBlue() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.BlueMana(1).toString())) {
manaToPayFrom.subtract(Mana.BlueMana(1));
addManaCombination(Mana.BlueMana(1), existingMana, payCombinations, payCombinationsStrings);
ManaOptions.addManaCombination(Mana.BlueMana(1), existingMana, payCombinations, payCombinationsStrings);
}
if (manaToPayFrom.getGreen() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.GreenMana(1).toString())) {
manaToPayFrom.subtract(Mana.GreenMana(1));
addManaCombination(Mana.GreenMana(1), existingMana, payCombinations, payCombinationsStrings);
ManaOptions.addManaCombination(Mana.GreenMana(1), existingMana, payCombinations, payCombinationsStrings);
}
if (manaToPayFrom.getRed() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.RedMana(1).toString())) {
manaToPayFrom.subtract(Mana.RedMana(1));
addManaCombination(Mana.RedMana(1), existingMana, payCombinations, payCombinationsStrings);
ManaOptions.addManaCombination(Mana.RedMana(1), existingMana, payCombinations, payCombinationsStrings);
}
if (manaToPayFrom.getWhite() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.WhiteMana(1).toString())) {
manaToPayFrom.subtract(Mana.WhiteMana(1));
addManaCombination(Mana.WhiteMana(1), existingMana, payCombinations, payCombinationsStrings);
ManaOptions.addManaCombination(Mana.WhiteMana(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));
addManaCombination(Mana.AnyMana(1), existingMana, payCombinations, payCombinationsStrings);
ManaOptions.addManaCombination(Mana.AnyMana(1), existingMana, payCombinations, payCombinationsStrings);
}
}
}
@ -480,7 +477,7 @@ public class ManaOptions extends ArrayList<Mana> {
return false;
}
private void addManaCombination(Mana mana, Mana existingMana, List<Mana> payCombinations, List<String> payCombinationsStrings) {
public static void addManaCombination(Mana mana, Mana existingMana, List<Mana> payCombinations, List<String> payCombinationsStrings) {
Mana newMana = existingMana.copy();
newMana.add(mana);
payCombinations.add(newMana);

View file

@ -9,7 +9,10 @@ import mage.constants.Zone;
import mage.game.Game;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import mage.constants.ManaType;
/**
* see 20110715 - 605.1b
@ -56,7 +59,18 @@ public abstract class TriggeredManaAbility extends TriggeredAbilityImpl implemen
}
return new ArrayList<>(netMana);
}
@Override
public Set<ManaType> getProducableManaTypes(Game game) {
Set<ManaType> manaTypes = new HashSet<>();
for (Effect effect : getEffects()) {
if (effect instanceof ManaEffect) {
manaTypes.addAll(((ManaEffect) effect).getProducableManaTypes(game, this));
}
}
return manaTypes;
}
/**
* Used to check if the ability itself defines mana types it can produce.
*

View file

@ -2906,7 +2906,7 @@ public abstract class PlayerImpl implements Player, Serializable {
}
if (canUse && ability.canActivate(playerId, game).canActivate()) {
// abilities without Tap costs have to be handled as separate sources, because they can be used also
if (!availableMana.hasTapCost(ability)) {
if (!ability.hasTapCost()) {
it.remove();
Abilities<ActivatedManaAbilityImpl> noTapAbilities = new AbilitiesImpl<>(ability);
if (ability.getManaCosts().isEmpty()) {