* Fixed a bug that created a endless loop if mana producer were involved, that create mana of any type lands of players could produce (fixes ##3374).

This commit is contained in:
LevelX2 2017-07-23 19:34:24 +02:00
parent c87e992e1d
commit a9e2303f7e
4 changed files with 52 additions and 370 deletions

View file

@ -27,29 +27,13 @@
*/
package mage.cards.n;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.MageInt;
import mage.Mana;
import mage.abilities.Abilities;
import mage.abilities.Ability;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.mana.ActivatedManaAbilityImpl;
import mage.abilities.mana.ManaAbility;
import mage.abilities.mana.AnyColorLandsProduceManaAbility;
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.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 mage.constants.TargetController;
/**
*
@ -66,7 +50,7 @@ public class NagaVitalist extends CardImpl {
this.toughness = new MageInt(2);
// {T}: Add to your mana pool one mana of any type that a land you control could produce.
this.addAbility(new NagaVitalistManaAbility());
this.addAbility(new AnyColorLandsProduceManaAbility(TargetController.YOU));
}
public NagaVitalist(final NagaVitalist card) {
@ -78,166 +62,3 @@ public class NagaVitalist extends CardImpl {
return new NagaVitalist(this);
}
}
class NagaVitalistManaAbility extends ActivatedManaAbilityImpl {
public NagaVitalistManaAbility() {
super(Zone.BATTLEFIELD, new NagaVitalistEffect(), new TapSourceCost());
}
public NagaVitalistManaAbility(final NagaVitalistManaAbility ability) {
super(ability);
}
@Override
public NagaVitalistManaAbility copy() {
return new NagaVitalistManaAbility(this);
}
@Override
public List<Mana> getNetMana(Game game) {
return ((NagaVitalistEffect) getEffects().get(0)).getNetMana(game, this);
}
}
class NagaVitalistEffect extends ManaEffect {
private static final FilterControlledPermanent filter = new FilterControlledLandPermanent();
public NagaVitalistEffect() {
super();
staticText = "Add to your mana pool one mana of any type that a land you control could produce";
}
public NagaVitalistEffect(final NagaVitalistEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
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 (choice.getChoices().size() == 1) {
choice.setChoice(choice.getChoices().iterator().next());
} else {
player.choose(outcome, choice, game);
}
if (choice.getChoice() != null) {
Mana mana = new Mana();
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;
}
checkToFirePossibleEvents(mana, game, source);
player.getManaPool().addMana(mana, game, source);
return true;
}
return false;
}
return true;
}
public List<Mana> getNetMana(Game game, Ability source) {
List<Mana> netManas = new ArrayList<>();
Mana types = getManaTypes(game, source);
if (types.getAny() > 0) {
netManas.add(new Mana(0, 0, 0, 0, 0, 0, 1, 0));
return netManas;
}
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.getColorless() > 0) {
netManas.add(Mana.ColorlessMana(1));
}
return netManas;
}
private Mana getManaTypes(Game game, Ability source) {
List<Permanent> lands = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game);
Mana types = new Mana();
for (Permanent land : lands) {
Abilities<Ability> manaAbilities = land.getAbilities(game).getManaAbilities(Zone.BATTLEFIELD);
for (Ability basicAbility : manaAbilities) {
ManaAbility ability = (ManaAbility) basicAbility;
if (!ability.equals(source) && ability.definesMana(game)) {
for (Mana netMana : ability.getNetMana(game)) {
types.add(netMana);
if (netMana.getAny() > 0) {
return types;
}
}
}
}
}
return types;
}
@Override
public Mana getMana(Game game, Ability source) {
return null;
}
@Override
public NagaVitalistEffect copy() {
return new NagaVitalistEffect(this);
}
}

View file

@ -27,28 +27,12 @@
*/
package mage.cards.r;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.Mana;
import mage.abilities.Abilities;
import mage.abilities.Ability;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.mana.ActivatedManaAbilityImpl;
import mage.abilities.mana.ManaAbility;
import mage.abilities.mana.AnyColorLandsProduceManaAbility;
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.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 mage.constants.TargetController;
/**
*
@ -60,7 +44,7 @@ public class ReflectingPool extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// {T}: Add to your mana pool one mana of any type that a land you control could produce.
this.addAbility(new ReflectingPoolManaAbility());
this.addAbility(new AnyColorLandsProduceManaAbility(TargetController.YOU));
}
public ReflectingPool(final ReflectingPool card) {
@ -72,170 +56,3 @@ public class ReflectingPool extends CardImpl {
return new ReflectingPool(this);
}
}
class ReflectingPoolManaAbility extends ActivatedManaAbilityImpl {
public ReflectingPoolManaAbility() {
super(Zone.BATTLEFIELD, new ReflectingPoolEffect(), new TapSourceCost());
}
public ReflectingPoolManaAbility(final ReflectingPoolManaAbility ability) {
super(ability);
}
@Override
public ReflectingPoolManaAbility copy() {
return new ReflectingPoolManaAbility(this);
}
@Override
public List<Mana> getNetMana(Game game) {
return ((ReflectingPoolEffect) getEffects().get(0)).getNetMana(game, this);
}
}
class ReflectingPoolEffect extends ManaEffect {
private static final FilterControlledPermanent filter = new FilterControlledLandPermanent();
public ReflectingPoolEffect() {
super();
staticText = "Add to your mana pool one mana of any type that a land you control could produce";
}
public ReflectingPoolEffect(final ReflectingPoolEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
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 (choice.getChoices().size() == 1) {
choice.setChoice(choice.getChoices().iterator().next());
} else {
player.choose(outcome, choice, game);
}
if (choice.getChoice() != null) {
Mana mana = new Mana();
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;
}
checkToFirePossibleEvents(mana, game, source);
player.getManaPool().addMana(mana, game, source);
return true;
}
return false;
}
return true;
}
public List<Mana> getNetMana(Game game, Ability source) {
List<Mana> netManas = new ArrayList<>();
Mana types = getManaTypes(game, source);
if (types.getAny() > 0) {
netManas.add(new Mana(0, 0, 0, 0, 0, 0, 1, 0));
return netManas;
}
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.getColorless() > 0) {
netManas.add(Mana.ColorlessMana(1));
}
return netManas;
}
private Mana getManaTypes(Game game, Ability source) {
Mana types = new Mana();
if (game == null || game.getPhase() == null) {
return types;
}
List<Permanent> lands = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game);
for (Permanent land : lands) {
Abilities<Ability> manaAbilities = land.getAbilities().getManaAbilities(Zone.BATTLEFIELD);
for (Ability basicAbility : manaAbilities) {
ManaAbility ability = (ManaAbility) basicAbility;
if (!(ability instanceof ReflectingPoolManaAbility) // can't get types from own ability class
&& ability.definesMana(game)) {
for (Mana netMana : ability.getNetMana(game)) {
types.add(netMana);
if (netMana.getAny() > 0) {
return types;
}
}
}
}
}
return types;
}
@Override
public Mana getMana(Game game, Ability source) {
return null;
}
@Override
public ReflectingPoolEffect copy() {
return new ReflectingPoolEffect(this);
}
}

View file

@ -150,4 +150,39 @@ public class ReflectingPoolTest extends CardTestPlayerBase {
Assert.assertEquals("Player should be able to create 2 red mana", "{G}{G}", options.get(0).toString());
}
/**
* Reflecting Pool does not see Gaea's Cradle or Serra's Sanctum as
* producing mana
*/
@Test
public void testWithDifferentLands() {
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1);
// {T}: Add to your mana pool one mana of any type that a land you control could produce.
addCard(Zone.BATTLEFIELD, playerA, "Reflecting Pool", 1);
// {T}: Add to your mana pool one mana of any color that a land an opponent controls could produce.
addCard(Zone.BATTLEFIELD, playerA, "Exotic Orchard", 1);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
// {T}: Add to your mana pool one mana of any color that a land an opponent controls could produce.
addCard(Zone.BATTLEFIELD, playerB, "Exotic Orchard", 1);
addCard(Zone.BATTLEFIELD, playerB, "Plains", 1);
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
execute();
ManaOptions options = playerA.getAvailableManaTest(currentGame);
Assert.assertEquals("Player A should be able to create the ", "{G}{G}{G}", options.get(0).toString());
Assert.assertEquals("Player A should be able to create the ", "{G}{G}{W}", options.get(1).toString());
Assert.assertEquals("Player A should be able to create the ", "{G}{G}{W}", options.get(2).toString()); // ManaOption type optimzing seems not optimal yet
Assert.assertEquals("Player A should be able to create the ", "{G}{W}{W}", options.get(3).toString());
Assert.assertEquals("Player A should be able to create only 3 different mana options", 4, options.size());
options = playerB.getAvailableManaTest(currentGame);
Assert.assertEquals("Player B should be able to create the ", "{G}{W}", options.get(0).toString());
Assert.assertEquals("Player B should be able to create the ", "{W}{W}", options.get(1).toString());
Assert.assertEquals("Player B should be able to create only 3 different mana options", 2, options.size());
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* Copyright 20 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@ -80,6 +80,7 @@ public class AnyColorLandsProduceManaAbility extends ActivatedManaAbilityImpl {
class AnyColorLandsProduceManaEffect extends ManaEffect {
private final FilterPermanent filter;
private boolean inManaTypeCalculation = false;
public AnyColorLandsProduceManaEffect(TargetController targetController) {
super();
@ -161,9 +162,16 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
}
private Mana getManaTypes(Game game, Ability source) {
Mana types = new Mana();
if (game == null || game.getPhase() == null) {
return types;
}
if (inManaTypeCalculation) {
return types;
}
inManaTypeCalculation = true;
// Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "needed to identify endless loop causing cards: {0}", source.getSourceObject(game).getName());
List<Permanent> lands = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game);
Mana types = new Mana();
for (Permanent land : lands) {
Abilities<ActivatedManaAbilityImpl> mana = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD);
for (ActivatedManaAbilityImpl ability : mana) {
@ -174,6 +182,7 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
}
}
}
inManaTypeCalculation = false;
return types;
}