* Fixed some more available mana calculation problems. Mana of the pool is now taken into account (e.g. Coal Golem problem). Crucible of the Spirit Dragon - Conditional mana curretnly not handled correctly in available mana calculation. Crystalline Crawler works now.Related to #6698.

This commit is contained in:
LevelX2 2020-07-16 22:37:51 +02:00
parent e3b2fa1240
commit 3a82840e66
16 changed files with 253 additions and 89 deletions

View file

@ -1,5 +1,9 @@
package mage.player.ai;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
import mage.ConditionalMana;
import mage.MageObject;
import mage.MageObjectReference;
@ -57,11 +61,6 @@ import mage.util.TournamentUtil;
import mage.util.TreeNode;
import org.apache.log4j.Logger;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
/**
* suitable for two player games and some multiplayer games
*
@ -137,8 +136,6 @@ public class ComputerPlayer extends PlayerImpl implements Player {
// - target.getTargetController(), this.getId() -- player that must makes choices (must be same with this.getId)
// - target.getAbilityController(), abilityControllerId -- affected player/controller for all actions/filters
// - affected controler can be different from target controller (another player makes choices for controller)
// sometimes a target selection can be made from a player that does not control the ability
UUID abilityControllerId = playerId;
if (target.getTargetController() != null
@ -478,7 +475,6 @@ public class ComputerPlayer extends PlayerImpl implements Player {
// target - real target, make all changes and add targets to it
// target.getOriginalTarget() - copy spell effect replaces original target with TargetWithAdditionalFilter
// use originalTarget to get filters and target class info
// source can be null (as example: legendary rule permanent selection)
UUID sourceId = source != null ? source.getSourceId() : null;
@ -731,9 +727,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
// TODO: in multiplayer game there many opponents - if random opponents don't have targets then AI must use next opponent, but it skips
// (e.g. you randomOpponentId must be replaced by List<UUID> randomOpponents)
// normal cycle (good for you, bad for opponents)
// possible good/bad permanents
if (outcome.isGood()) {
targets = threats(abilityControllerId, source.getSourceId(), ((FilterPermanentOrPlayer) target.getFilter()).getPermanentFilter(), game, target.getTargets());
@ -1312,7 +1306,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
playableAbilities.clear();
Set<Card> nonLands = hand.getCards(new FilterNonlandCard(), game);
ManaOptions available = getManaAvailable(game);
available.addMana(manaPool.getMana());
// available.addMana(manaPool.getMana());
for (Card card : nonLands) {
ManaOptions options = card.getManaCost().getOptions();
@ -2562,7 +2556,6 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
}
protected List<Permanent> threats(UUID playerId, UUID sourceId, FilterPermanent filter, Game game, List<UUID> targets) {
return threats(playerId, sourceId, filter, game, targets, true);
}
@ -2688,7 +2681,6 @@ public class ComputerPlayer extends PlayerImpl implements Player {
return before != after;
}
/**
* Sets a possible target player
*/

View file

@ -1,4 +1,3 @@
package mage.cards.c;
import java.util.UUID;
@ -11,6 +10,7 @@ import mage.abilities.condition.Condition;
import mage.abilities.costs.common.RemoveVariableCountersSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.dynamicvalue.common.CountersSourceCount;
import mage.abilities.dynamicvalue.common.RemovedCountersForCostValue;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.mana.ColorlessManaAbility;
@ -31,13 +31,13 @@ import mage.game.Game;
public final class CrucibleOfTheSpiritDragon extends CardImpl {
public CrucibleOfTheSpiritDragon(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// {T}: Add {C}.
this.addAbility(new ColorlessManaAbility());
// {1}, {T}: Put a storage counter on Crucible of the Spirit Dragon.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.STORAGE.createInstance()),new GenericManaCost(1));
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.STORAGE.createInstance()), new GenericManaCost(1));
ability.addCost(new TapSourceCost());
this.addAbility(ability);
@ -45,9 +45,10 @@ public final class CrucibleOfTheSpiritDragon extends CardImpl {
ability = new ConditionalAnyColorManaAbility(
new TapSourceCost(),
RemovedCountersForCostValue.instance,
new CountersSourceCount(CounterType.STORAGE),
new CrucibleOfTheSpiritDragonManaBuilder(),
false
);
);
ability.addCost(new RemoveVariableCountersSourceCost(CounterType.STORAGE.createInstance()));
this.addAbility(ability);
}
@ -94,4 +95,4 @@ class CrucibleOfTheSpiritDragonManaCondition implements Condition {
}
return false;
}
}
}

View file

@ -1,4 +1,3 @@
package mage.cards.c;
import java.util.UUID;
@ -8,6 +7,7 @@ import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.RemoveCountersSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.dynamicvalue.common.ColorsOfManaSpentToCastCount;
import mage.abilities.dynamicvalue.common.CountersSourceCount;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.mana.AnyColorManaAbility;
import mage.cards.CardImpl;
@ -30,13 +30,14 @@ public final class CrystallineCrawler extends CardImpl {
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// <i>Converge</i> &mdash; Crystalline Crawler enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.
// Converge - Crystalline Crawler enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.
this.addAbility(new EntersBattlefieldAbility(
new AddCountersSourceEffect(CounterType.P1P1.createInstance(), ColorsOfManaSpentToCastCount.getInstance(), true),
null, "<i>Converge</i> &mdash; {this} enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.", null));
// Remove a +1/+1 counter from Crystalline Crawler: Add one mana of any color.
this.addAbility(new AnyColorManaAbility(new RemoveCountersSourceCost(CounterType.P1P1.createInstance(1))));
this.addAbility(new AnyColorManaAbility(new RemoveCountersSourceCost(CounterType.P1P1.createInstance(1)),
new CountersSourceCount(CounterType.P1P1), false));
// {T}: Put a +1/+1 counter on Crystalline Crawler.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), new TapSourceCost()));

View file

@ -1,4 +1,3 @@
package mage.cards.d;
import java.util.UUID;
@ -7,16 +6,19 @@ import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.mana.AddManaOfAnyColorEffect;
import mage.abilities.dynamicvalue.LimitedDynamicValue;
import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.LoseLifeOpponentsEffect;
import mage.abilities.effects.mana.AddManaOfAnyColorEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreatureCard;
import mage.filter.common.FilterLandCard;
import mage.filter.predicate.Predicates;
@ -37,17 +39,18 @@ public final class DeathriteShaman extends CardImpl {
}
public DeathriteShaman(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B/G}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B/G}");
this.subtype.add(SubType.ELF);
this.subtype.add(SubType.SHAMAN);
this.power = new MageInt(1);
this.toughness = new MageInt(2);
// {T}: Exile target land card from a graveyard. Add one mana of any color.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(), new TapSourceCost());
ability.addEffect(new AddManaOfAnyColorEffect());
// Because this is no mana ability, this mana will not be calculated during available mana calculation
ability.addEffect(new AddManaOfAnyColorEffect(1, new LimitedDynamicValue(1,
new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_LAND)), false));
ability.addTarget(new TargetCardInGraveyard(new FilterLandCard("land card from a graveyard")));
this.addAbility(ability);
@ -74,4 +77,4 @@ public final class DeathriteShaman extends CardImpl {
public DeathriteShaman copy() {
return new DeathriteShaman(this);
}
}
}

View file

@ -10,11 +10,11 @@ import mage.abilities.effects.common.DoIfCostPaid;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.mana.AddConditionalManaOfAnyColorEffect;
import mage.abilities.mana.conditional.ConditionalSpellManaBuilder;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterSpell;
import mage.game.permanent.token.DragonToken2;
@ -46,6 +46,7 @@ public final class SarkhanFireblood extends CardImpl {
// +1: Add two mana of any combination of colors. Spend this mana only to cast Dragon spells.
this.addAbility(new LoyaltyAbility(
new AddConditionalManaOfAnyColorEffect(
StaticValue.get(2),
StaticValue.get(2),
new ConditionalSpellManaBuilder(filter),
false

View file

@ -45,7 +45,7 @@ public class SpliceOnArcaneTest extends CardTestPlayerBase {
assertHandCount(playerA, "Through the Breach", 1);
assertPermanentCount(playerA, "Silvercoat Lion", 1);
assertAbility(playerA, "Silvercoat Lion", HasteAbility.getInstance(), true);
Assert.assertEquals("All available mana has to be used", 0, playerA.getManaAvailable(currentGame).size());
Assert.assertEquals("All available mana has to be used", "[]", playerA.getManaAvailable(currentGame).toString());
}
@Test

View file

@ -29,7 +29,7 @@ public class SasayaOrochiAscendantTest extends CardTestPlayerBase {
addCard(Zone.HAND, playerA, "Upwelling", 1); // Enchantment {3}{G}
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reveal your hand: If you have seven or more land cards in your hand, flip");
activateManaAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{T}: Add {G}");
activateManaAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{T}: Add {G}");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Upwelling");
@ -38,7 +38,7 @@ public class SasayaOrochiAscendantTest extends CardTestPlayerBase {
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Sasaya's Essence", 1);
assertPermanentCount(playerA, "Upwelling", 1);
@ -48,11 +48,11 @@ public class SasayaOrochiAscendantTest extends CardTestPlayerBase {
assertDuplicatedManaOptions(manaOptions);
Assert.assertEquals("mana variations don't fit", 1, manaOptions.size());
assertManaOptions("{G}{G}{G}", manaOptions);
assertManaOptions("{G}{G}{G}{G}{G}", manaOptions);
}
@Test
@Test
public void testSasayasEssence2() {
addCard(Zone.HAND, playerA, "Plains", 7);
addCard(Zone.BATTLEFIELD, playerA, "Brushland", 3);
@ -73,26 +73,25 @@ public class SasayaOrochiAscendantTest extends CardTestPlayerBase {
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Sasaya's Essence", 1);
assertPermanentCount(playerA, "Upwelling", 1);
assertManaPool(playerA, ManaType.GREEN, 2);
assertLife(playerA, 18);
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
assertDuplicatedManaOptions(manaOptions);
Assert.assertEquals("mana variations don't fit", 3, manaOptions.size());
assertManaOptions("{C}{C}{C}", manaOptions);
assertManaOptions("{G}{G}{G}", manaOptions);
assertManaOptions("{W}{W}{W}", manaOptions);
assertManaOptions("{C}{C}{C}{G}{G}", manaOptions);
assertManaOptions("{G}{G}{G}{G}{G}", manaOptions);
assertManaOptions("{W}{W}{W}{G}{G}", manaOptions);
}
@Test
}
@Test
public void testSasayasEssence3() {
addCard(Zone.HAND, playerA, "Plains", 7);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
@ -115,22 +114,22 @@ public class SasayaOrochiAscendantTest extends CardTestPlayerBase {
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Sasaya's Essence", 1);
assertPermanentCount(playerA, "Upwelling", 1);
assertManaPool(playerA, ManaType.GREEN, 2);
assertLife(playerA, 20);
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
assertDuplicatedManaOptions(manaOptions);
Assert.assertEquals("mana variations don't fit", 4, manaOptions.size());
assertManaOptions("{R}{R}{R}{R}{G}{G}{G}", manaOptions);
assertManaOptions("{R}{R}{R}{G}{G}{G}{G}", manaOptions);
assertManaOptions("{R}{R}{G}{G}{G}{G}{G}", manaOptions);
assertManaOptions("{R}{G}{G}{G}{G}{G}{G}", manaOptions);
}
assertManaOptions("{R}{R}{R}{R}{G}{G}{G}{G}{G}", manaOptions);
assertManaOptions("{R}{R}{R}{G}{G}{G}{G}{G}{G}", manaOptions);
assertManaOptions("{R}{R}{G}{G}{G}{G}{G}{G}{G}", manaOptions);
assertManaOptions("{R}{G}{G}{G}{G}{G}{G}{G}{G}", manaOptions);
}
}

View file

@ -5,6 +5,7 @@ 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.assertManaOptions;
@ -199,4 +200,44 @@ public class TappedForManaRelatedTest extends CardTestPlayerBase {
assertManaOptions("{U}", manaOptions);
assertManaOptions("{R}", manaOptions);
}
@Test
public void TestCrystallineCrawler() {
setStrictChooseMode(true);
// Converge - Crystalline Crawler enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.
// Remove a +1/+1 counter from Crystalline Crawler: Add one mana of any color.
// {T}: Put a +1/+1 counter on Crystalline Crawler.
addCard(Zone.BATTLEFIELD, playerA, "Crystalline Crawler", 1);
addCounters(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Crystalline Crawler", CounterType.P1P1, 2);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertAllCommandsUsed();
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
Assert.assertEquals("mana variations don't fit", 1, manaOptions.size());
assertManaOptions("{Any}{Any}", manaOptions);
}
@Test
@Ignore // Because this is no mana ability, this mana will not be calculated during available mana calculation
public void TestDeathriteShaman() {
setStrictChooseMode(true);
// {T}: Exile target land card from a graveyard. Add one mana of any color.
// {B}, {T}: Exile target instant or sorcery card from a graveyard. Each opponent loses 2 life.
// {G}, {T}: Exile target creature card from a graveyard. You gain 2 life.
addCard(Zone.BATTLEFIELD, playerA, "Deathrite Shaman", 1);
addCard(Zone.GRAVEYARD, playerA, "Mountain", 3);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertAllCommandsUsed();
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
Assert.assertEquals("mana variations don't fit", 1, manaOptions.size());
assertManaOptions("{Any}", manaOptions);
}
}

View file

@ -0,0 +1,56 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mage.abilities.dynamicvalue;
import mage.abilities.Ability;
import mage.abilities.effects.Effect;
import mage.game.Game;
/**
*
* @author LevelX2
*/
public class LimitedDynamicValue implements DynamicValue {
private final DynamicValue value;
private final int limit;
/**
* Returns a dynamic but with an upper limit.
*
* @param limit the max value the dynamic value will return
* @param value the dynamic value to calculate the row dynamic value
*/
public LimitedDynamicValue(int limit, DynamicValue value) {
this.value = value;
this.limit = limit;
}
LimitedDynamicValue(final LimitedDynamicValue dynamicValue) {
this.value = dynamicValue.value;
this.limit = dynamicValue.limit;
}
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
return Math.min(limit, value.calculate(game, sourceAbility, effect));
}
@Override
public LimitedDynamicValue copy() {
return new LimitedDynamicValue(this);
}
@Override
public String toString() {
return value.toString();
}
@Override
public String getMessage() {
return value.getMessage();
}
}

View file

@ -1,5 +1,7 @@
package mage.abilities.effects.mana;
import java.util.ArrayList;
import java.util.List;
import mage.ConditionalMana;
import mage.Mana;
import mage.abilities.Ability;
@ -13,9 +15,6 @@ import mage.players.Player;
import mage.util.CardUtil;
import org.apache.log4j.Logger;
import java.util.ArrayList;
import java.util.List;
/**
* @author noxx
*/
@ -24,20 +23,22 @@ public class AddConditionalManaOfAnyColorEffect extends ManaEffect {
private static final Logger logger = Logger.getLogger(AddConditionalManaOfAnyColorEffect.class);
private final DynamicValue amount;
private final DynamicValue netAmount;
private final ConditionalManaBuilder manaBuilder;
private final boolean oneChoice;
public AddConditionalManaOfAnyColorEffect(int amount, ConditionalManaBuilder manaBuilder) {
this(StaticValue.get(amount), manaBuilder);
this(StaticValue.get(amount), StaticValue.get(amount), manaBuilder);
}
public AddConditionalManaOfAnyColorEffect(DynamicValue amount, ConditionalManaBuilder manaBuilder) {
this(amount, manaBuilder, true);
public AddConditionalManaOfAnyColorEffect(DynamicValue amount, DynamicValue netAmount, ConditionalManaBuilder manaBuilder) {
this(amount, netAmount, manaBuilder, true);
}
public AddConditionalManaOfAnyColorEffect(DynamicValue amount, ConditionalManaBuilder manaBuilder, boolean oneChoice) {
public AddConditionalManaOfAnyColorEffect(DynamicValue amount, DynamicValue netAmount, ConditionalManaBuilder manaBuilder, boolean oneChoice) {
super();
this.amount = amount;
this.netAmount = netAmount;
this.manaBuilder = manaBuilder;
this.oneChoice = oneChoice;
//
@ -53,6 +54,7 @@ public class AddConditionalManaOfAnyColorEffect extends ManaEffect {
public AddConditionalManaOfAnyColorEffect(final AddConditionalManaOfAnyColorEffect effect) {
super(effect);
this.amount = effect.amount;
this.netAmount = effect.netAmount;
this.manaBuilder = effect.manaBuilder;
this.oneChoice = effect.oneChoice;
}
@ -66,9 +68,16 @@ public class AddConditionalManaOfAnyColorEffect extends ManaEffect {
public List<Mana> getNetMana(Game game, Ability source) {
List<Mana> netMana = new ArrayList<>();
if (game != null) {
int value = amount.calculate(game, source, this);
if (value > 0) {
netMana.add(Mana.AnyMana(value));
if (game.inCheckPlayableState()) {
int amountAvailableMana = netAmount.calculate(game, source, this);
if (amountAvailableMana > 0) {
netMana.add(manaBuilder.setMana(Mana.AnyMana(amountAvailableMana), source, game).build());
}
} else {
int amountOfManaLeft = amount.calculate(game, source, this);
if (amountOfManaLeft > 0) {
netMana.add(Mana.AnyMana(amountOfManaLeft));
}
}
}
return netMana;

View file

@ -1,21 +1,22 @@
package mage.abilities.effects.mana;
import java.util.ArrayList;
import java.util.List;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.choices.ChoiceColor;
import mage.game.Game;
import mage.players.Player;
import mage.util.CardUtil;
import java.util.ArrayList;
import java.util.List;
/**
* @author BetaSteward_at_googlemail.com
*/
public class AddManaOfAnyColorEffect extends BasicManaEffect {
protected final int amount;
protected final DynamicValue netAmount;
protected final ArrayList<Mana> netMana = new ArrayList<>();
protected final boolean setFlag;
@ -28,8 +29,13 @@ public class AddManaOfAnyColorEffect extends BasicManaEffect {
}
public AddManaOfAnyColorEffect(int amount, boolean setFlag) {
this(amount, null, setFlag);
}
public AddManaOfAnyColorEffect(int amount, DynamicValue netAmount, boolean setFlag) {
super(new Mana(0, 0, 0, 0, 0, 0, amount, 0));
this.amount = amount;
this.netAmount = netAmount;
netMana.add(Mana.AnyMana(amount));
this.staticText = "add " + CardUtil.numberToText(amount) + " mana of any " + (amount > 1 ? "one " : "") + "color";
this.setFlag = setFlag;
@ -40,6 +46,12 @@ public class AddManaOfAnyColorEffect extends BasicManaEffect {
this.amount = effect.amount;
this.netMana.addAll(effect.netMana);
this.setFlag = effect.setFlag;
if (effect.netAmount == null) {
this.netAmount = null;
} else {
this.netAmount = effect.netAmount.copy();
}
}
@Override
@ -49,6 +61,16 @@ public class AddManaOfAnyColorEffect extends BasicManaEffect {
@Override
public List<Mana> getNetMana(Game game, Ability source) {
if (game != null && game.inCheckPlayableState()) {
if (netAmount != null) {
int count = netAmount.calculate(game, source, this);
Mana mana = new Mana();
mana.setAny(count * amount);
ArrayList<Mana> possibleNetMana = new ArrayList<>();
possibleNetMana.add(mana);
return possibleNetMana;
}
}
return new ArrayList<>(this.netMana);
}

View file

@ -1,5 +1,6 @@
package mage.abilities.keyword;
import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.SpecialAction;
@ -20,22 +21,20 @@ import mage.target.Target;
import mage.target.TargetPlayer;
import mage.util.ManaUtil;
import java.util.UUID;
/**
* 702.131. Assist
* <p>
* 702.131a Assist is a static ability that modifies the rules of paying for the spell with assist (see rules 601.2g-h).
* If the total cost to cast a spell with assist includes a generic mana component, before you activate mana
* abilities while casting it, you may choose another player. That player has a chance to activate mana abilities.
* Once that player chooses not to activate any more mana abilities, you have a chance to activate mana abilities.
* Before you begin to pay the total cost of the spell, the player you chose may pay for any amount of the generic
* mana in the spells total cost.
* 702.131a Assist is a static ability that modifies the rules of paying for the
* spell with assist (see rules 601.2g-h). If the total cost to cast a spell
* with assist includes a generic mana component, before you activate mana
* abilities while casting it, you may choose another player. That player has a
* chance to activate mana abilities. Once that player chooses not to activate
* any more mana abilities, you have a chance to activate mana abilities. Before
* you begin to pay the total cost of the spell, the player you chose may pay
* for any amount of the generic mana in the spells total cost.
*
* @author emerald000, JayDi85
*/
public class AssistAbility extends SimpleStaticAbility implements AlternateManaPaymentAbility {
private static final FilterPlayer filter = new FilterPlayer("another player");
@ -107,7 +106,7 @@ public class AssistAbility extends SimpleStaticAbility implements AlternateManaP
if (opponent != null) {
// basic and pool, but no coditional mana
ManaOptions availableMana = opponent.getManaAvailable(game);
availableMana.addMana(opponent.getManaPool().getMana());
// availableMana.addMana(opponent.getManaPool().getMana());
for (Mana mana : availableMana) {
if (mana.count() > 0) {
opponentCanPayMax = Math.max(opponentCanPayMax, mana.count());

View file

@ -1,10 +1,16 @@
package mage.abilities.mana;
import java.util.ArrayList;
import java.util.List;
import mage.Mana;
import mage.abilities.costs.Cost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.effects.mana.AddManaOfAnyColorEffect;
import mage.constants.Zone;
import mage.game.Game;
public class AnyColorManaAbility extends ActivatedManaAbilityImpl {
@ -21,10 +27,39 @@ public class AnyColorManaAbility extends ActivatedManaAbilityImpl {
this.netMana.add(new Mana(0, 0, 0, 0, 0, 0, 1, 0));
}
/**
*
* @param cost
* @param netAmount dynamic value used during available mana calculation to
* set the max possible amount the source can produce
* @param setFlag
*/
public AnyColorManaAbility(Cost cost, DynamicValue netAmount, boolean setFlag) {
super(Zone.BATTLEFIELD, new AddManaOfAnyColorEffect(1, netAmount, setFlag), cost);
this.netMana.add(new Mana(0, 0, 0, 0, 0, 0, 1, 0));
}
public AnyColorManaAbility(final AnyColorManaAbility ability) {
super(ability);
}
@Override
public List<Mana> getNetMana(Game game) {
if (game != null && game.inCheckPlayableState()) {
List<Mana> dynamicNetMana = new ArrayList<>();
for (Effect effect : getEffects()) {
if (effect instanceof ManaEffect) {
List<Mana> effectNetMana = ((ManaEffect) effect).getNetMana(game, this);
if (effectNetMana != null) {
dynamicNetMana.addAll(effectNetMana);
}
}
}
return dynamicNetMana;
}
return super.getNetMana(game);
}
@Override
public AnyColorManaAbility copy() {
return new AnyColorManaAbility(this);

View file

@ -1,6 +1,6 @@
package mage.abilities.mana;
import java.util.List;
import mage.Mana;
import mage.abilities.costs.Cost;
import mage.abilities.costs.common.TapSourceCost;
@ -11,11 +11,9 @@ import mage.abilities.mana.builder.ConditionalManaBuilder;
import mage.constants.Zone;
import mage.game.Game;
import java.util.List;
/**
* For cards like:
* {tap}: Add three mana of any one color. Spend this mana only to cast creature spells.
* For cards like: {tap}: Add three mana of any one color. Spend this mana only
* to cast creature spells.
*
* @author noxx
*/
@ -32,11 +30,11 @@ public class ConditionalAnyColorManaAbility extends ActivatedManaAbilityImpl {
}
public ConditionalAnyColorManaAbility(Cost cost, int amount, ConditionalManaBuilder manaBuilder, boolean oneChoice) {
this(cost, StaticValue.get(amount), manaBuilder, oneChoice);
this(cost, StaticValue.get(amount), StaticValue.get(amount), manaBuilder, oneChoice);
}
public ConditionalAnyColorManaAbility(Cost cost, DynamicValue amount, ConditionalManaBuilder manaBuilder, boolean oneChoice) {
super(Zone.BATTLEFIELD, new AddConditionalManaOfAnyColorEffect(amount, manaBuilder, oneChoice), cost);
public ConditionalAnyColorManaAbility(Cost cost, DynamicValue amount, DynamicValue netAmount, ConditionalManaBuilder manaBuilder, boolean oneChoice) {
super(Zone.BATTLEFIELD, new AddConditionalManaOfAnyColorEffect(amount, netAmount, manaBuilder, oneChoice), cost);
this.amount = amount;
}
@ -60,7 +58,6 @@ public class ConditionalAnyColorManaAbility extends ActivatedManaAbilityImpl {
return true;
}
@Override
public ConditionalAnyColorManaAbility copy() {
return new ConditionalAnyColorManaAbility(this);

View file

@ -22,6 +22,9 @@ import org.apache.log4j.Logger;
* be used to find all the ways to pay a mana cost or all the different mana
* combinations available to a player
*
* TODO: Conditional Mana is not supported yet. The mana adding removes the
* condition of conditional mana
*
*/
public class ManaOptions extends ArrayList<Mana> {

View file

@ -2881,6 +2881,11 @@ public abstract class PlayerImpl implements Player, Serializable {
game.setCheckPlayableState(true);
ManaOptions availableMana = new ManaOptions();
availableMana.addMana(manaPool.getMana());
// conditional mana
for (ConditionalMana conditionalMana : manaPool.getConditionalMana()) {
availableMana.addMana(conditionalMana);
}
List<Abilities<ActivatedManaAbilityImpl>> sourceWithoutManaCosts = new ArrayList<>();
List<Abilities<ActivatedManaAbilityImpl>> sourceWithCosts = new ArrayList<>();
@ -3407,11 +3412,11 @@ public abstract class PlayerImpl implements Player, Serializable {
try {
// basic mana
ManaOptions availableMana = getManaAvailable(game);
availableMana.addMana(manaPool.getMana());
// availableMana.addMana(manaPool.getMana());
// conditional mana
for (ConditionalMana conditionalMana : manaPool.getConditionalMana()) {
availableMana.addMana(conditionalMana);
}
// for (ConditionalMana conditionalMana : manaPool.getConditionalMana()) {
// availableMana.addMana(conditionalMana);
// }
boolean fromAll = fromZone.equals(Zone.ALL);
if (hidden && (fromAll || fromZone == Zone.HAND)) {