mirror of
https://github.com/correl/mage.git
synced 2025-01-12 11:08:01 +00:00
* Added handling of triggered mana to available mana calculation (fixes #585).
This commit is contained in:
parent
5be6e9398a
commit
89249888b5
26 changed files with 544 additions and 96 deletions
|
@ -20,7 +20,6 @@ import mage.game.events.GameEvent;
|
||||||
import mage.game.events.GameEvent.EventType;
|
import mage.game.events.GameEvent.EventType;
|
||||||
import mage.game.events.ManaEvent;
|
import mage.game.events.ManaEvent;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.players.Player;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|
|
@ -53,7 +53,7 @@ class DesolationEffect extends OneShotEffect {
|
||||||
|
|
||||||
public DesolationEffect() {
|
public DesolationEffect() {
|
||||||
super(Outcome.Damage);
|
super(Outcome.Damage);
|
||||||
this.staticText = "each player who tapped a land for mana this turn sacrifices a land. Desolation deals 2 damage to each player who sacrificed a Plains this way";
|
this.staticText = "each player who tapped a land for mana this turn sacrifices a land. {this} deals 2 damage to each player who sacrificed a Plains this way";
|
||||||
}
|
}
|
||||||
|
|
||||||
public DesolationEffect(DesolationEffect copy) {
|
public DesolationEffect(DesolationEffect copy) {
|
||||||
|
@ -108,7 +108,8 @@ class DesolationWatcher extends Watcher {
|
||||||
if (event.getType() == GameEvent.EventType.UNTAP_STEP_PRE) {
|
if (event.getType() == GameEvent.EventType.UNTAP_STEP_PRE) {
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
if (event.getType() == GameEvent.EventType.TAPPED_FOR_MANA) {
|
if (event.getType() == GameEvent.EventType.TAPPED_FOR_MANA
|
||||||
|
&& !game.inCheckPlayableState()) { // Ignored - see GameEvent.TAPPED_FOR_MANA
|
||||||
UUID playerId = event.getPlayerId();
|
UUID playerId = event.getPlayerId();
|
||||||
if (playerId != null) {
|
if (playerId != null) {
|
||||||
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId());
|
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId());
|
||||||
|
|
|
@ -86,7 +86,7 @@ class ForbiddenOrchardTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
return event.getSourceId().equals(getSourceId());
|
return event.getSourceId().equals(getSourceId()) && !game.inCheckPlayableState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package mage.cards.g;
|
package mage.cards.g;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import mage.Mana;
|
import mage.Mana;
|
||||||
import mage.ObjectColor;
|
import mage.ObjectColor;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
@ -43,10 +45,10 @@ public final class GauntletOfPower extends CardImpl {
|
||||||
// As Gauntlet of Power enters the battlefield, choose a color.
|
// As Gauntlet of Power enters the battlefield, choose a color.
|
||||||
this.addAbility(new EntersBattlefieldAbility(new ChooseColorEffect(Outcome.Neutral)));
|
this.addAbility(new EntersBattlefieldAbility(new ChooseColorEffect(Outcome.Neutral)));
|
||||||
// Creatures of the chosen color get +1/+1.
|
// Creatures of the chosen color get +1/+1.
|
||||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GauntletOfPowerEffect1()));
|
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GauntletOfPowerBoostEffect()));
|
||||||
|
|
||||||
// Whenever a basic land is tapped for mana of the chosen color, its controller adds one mana of that color.
|
// Whenever a basic land is tapped for mana of the chosen color, its controller adds one mana of that color.
|
||||||
this.addAbility(new TapForManaAllTriggeredAbility(new GauntletOfPowerEffectEffect2(), filter, SetTargetPointer.PERMANENT));
|
this.addAbility(new GauntletOfPowerTapForManaAllTriggeredAbility(new GauntletOfPowerManaEffect2(), filter, SetTargetPointer.PERMANENT));
|
||||||
}
|
}
|
||||||
|
|
||||||
public GauntletOfPower(final GauntletOfPower card) {
|
public GauntletOfPower(final GauntletOfPower card) {
|
||||||
|
@ -59,22 +61,22 @@ public final class GauntletOfPower extends CardImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GauntletOfPowerEffect1 extends ContinuousEffectImpl {
|
class GauntletOfPowerBoostEffect extends ContinuousEffectImpl {
|
||||||
|
|
||||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent();
|
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent();
|
||||||
|
|
||||||
public GauntletOfPowerEffect1() {
|
public GauntletOfPowerBoostEffect() {
|
||||||
super(Duration.WhileOnBattlefield, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.BoostCreature);
|
super(Duration.WhileOnBattlefield, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.BoostCreature);
|
||||||
staticText = "Creatures of the chosen color get +1/+1";
|
staticText = "Creatures of the chosen color get +1/+1";
|
||||||
}
|
}
|
||||||
|
|
||||||
public GauntletOfPowerEffect1(final GauntletOfPowerEffect1 effect) {
|
public GauntletOfPowerBoostEffect(final GauntletOfPowerBoostEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GauntletOfPowerEffect1 copy() {
|
public GauntletOfPowerBoostEffect copy() {
|
||||||
return new GauntletOfPowerEffect1(this);
|
return new GauntletOfPowerBoostEffect(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -93,18 +95,18 @@ class GauntletOfPowerEffect1 extends ContinuousEffectImpl {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TapForManaAllTriggeredAbility extends TriggeredManaAbility {
|
class GauntletOfPowerTapForManaAllTriggeredAbility extends TriggeredManaAbility {
|
||||||
|
|
||||||
private final FilterPermanent filter;
|
private final FilterPermanent filter;
|
||||||
private final SetTargetPointer setTargetPointer;
|
private final SetTargetPointer setTargetPointer;
|
||||||
|
|
||||||
public TapForManaAllTriggeredAbility(ManaEffect effect, FilterPermanent filter, SetTargetPointer setTargetPointer) {
|
public GauntletOfPowerTapForManaAllTriggeredAbility(ManaEffect effect, FilterPermanent filter, SetTargetPointer setTargetPointer) {
|
||||||
super(Zone.BATTLEFIELD, effect, false);
|
super(Zone.BATTLEFIELD, effect, false);
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
this.setTargetPointer = setTargetPointer;
|
this.setTargetPointer = setTargetPointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TapForManaAllTriggeredAbility(TapForManaAllTriggeredAbility ability) {
|
public GauntletOfPowerTapForManaAllTriggeredAbility(GauntletOfPowerTapForManaAllTriggeredAbility ability) {
|
||||||
super(ability);
|
super(ability);
|
||||||
this.filter = ability.filter.copy();
|
this.filter = ability.filter.copy();
|
||||||
this.setTargetPointer = ability.setTargetPointer;
|
this.setTargetPointer = ability.setTargetPointer;
|
||||||
|
@ -156,8 +158,8 @@ class TapForManaAllTriggeredAbility extends TriggeredManaAbility {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TapForManaAllTriggeredAbility copy() {
|
public GauntletOfPowerTapForManaAllTriggeredAbility copy() {
|
||||||
return new TapForManaAllTriggeredAbility(this);
|
return new GauntletOfPowerTapForManaAllTriggeredAbility(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -167,14 +169,14 @@ class TapForManaAllTriggeredAbility extends TriggeredManaAbility {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GauntletOfPowerEffectEffect2 extends ManaEffect {
|
class GauntletOfPowerManaEffect2 extends ManaEffect {
|
||||||
|
|
||||||
public GauntletOfPowerEffectEffect2() {
|
public GauntletOfPowerManaEffect2() {
|
||||||
super();
|
super();
|
||||||
staticText = "its controller adds one additional mana of that color";
|
staticText = "its controller adds one additional mana of that color";
|
||||||
}
|
}
|
||||||
|
|
||||||
public GauntletOfPowerEffectEffect2(final GauntletOfPowerEffectEffect2 effect) {
|
public GauntletOfPowerManaEffect2(final GauntletOfPowerManaEffect2 effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,6 +189,18 @@ class GauntletOfPowerEffectEffect2 extends ManaEffect {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Mana> getNetMana(Game game, Ability source) {
|
||||||
|
List<Mana> netMana = new ArrayList<>();
|
||||||
|
if (game != null) {
|
||||||
|
Mana mana = (Mana) getValue("mana");
|
||||||
|
if (mana != null) {
|
||||||
|
netMana.add(mana.copy());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return netMana;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mana produceMana(Game game, Ability source) {
|
public Mana produceMana(Game game, Ability source) {
|
||||||
if (game != null) {
|
if (game != null) {
|
||||||
|
@ -202,7 +216,7 @@ class GauntletOfPowerEffectEffect2 extends ManaEffect {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GauntletOfPowerEffectEffect2 copy() {
|
public GauntletOfPowerManaEffect2 copy() {
|
||||||
return new GauntletOfPowerEffectEffect2(this);
|
return new GauntletOfPowerManaEffect2(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package mage.cards.s;
|
package mage.cards.s;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.Mana;
|
import mage.Mana;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
@ -11,8 +12,6 @@ import mage.abilities.effects.common.FlipSourceEffect;
|
||||||
import mage.abilities.effects.common.ManaEffect;
|
import mage.abilities.effects.common.ManaEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.choices.Choice;
|
|
||||||
import mage.choices.ChoiceColor;
|
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.filter.FilterPermanent;
|
import mage.filter.FilterPermanent;
|
||||||
import mage.filter.common.FilterControlledLandPermanent;
|
import mage.filter.common.FilterControlledLandPermanent;
|
||||||
|
@ -26,9 +25,10 @@ import mage.game.permanent.Permanent;
|
||||||
import mage.game.permanent.token.TokenImpl;
|
import mage.game.permanent.token.TokenImpl;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import mage.choices.Choice;
|
||||||
|
import mage.choices.ChoiceColor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
|
@ -133,9 +133,55 @@ class SasayasEssenceManaEffect extends ManaEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Mana> getNetMana(Game game, Ability source) {
|
public List<Mana> getNetMana(Game game, Ability source) {
|
||||||
return new ArrayList<>();
|
List<Mana> netMana = new ArrayList<>();
|
||||||
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
|
Mana producedMana = (Mana) this.getValue("mana");
|
||||||
|
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||||
|
if (controller != null && producedMana != null && permanent != null) {
|
||||||
|
FilterPermanent filter = new FilterLandPermanent();
|
||||||
|
filter.add(Predicates.not(new PermanentIdPredicate(permanent.getId())));
|
||||||
|
filter.add(new NamePredicate(permanent.getName()));
|
||||||
|
int count = game.getBattlefield().countAll(filter, controller.getId(), game);
|
||||||
|
if (count > 0) {
|
||||||
|
if (producedMana.getBlack() > 0) {
|
||||||
|
netMana.add(Mana.BlackMana(count));
|
||||||
|
}
|
||||||
|
if (producedMana.getRed() > 0) {
|
||||||
|
netMana.add(Mana.RedMana(count));
|
||||||
|
}
|
||||||
|
if (producedMana.getBlue() > 0) {
|
||||||
|
netMana.add(Mana.BlueMana(count));
|
||||||
|
}
|
||||||
|
if (producedMana.getGreen() > 0) {
|
||||||
|
netMana.add(Mana.GreenMana(count));
|
||||||
|
}
|
||||||
|
if (producedMana.getWhite() > 0) {
|
||||||
|
netMana.add(Mana.WhiteMana(count));
|
||||||
|
}
|
||||||
|
if (producedMana.getColorless() > 0) {
|
||||||
|
netMana.add(Mana.ColorlessMana(count));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return netMana;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RULINGS 6/1/2005 If Sasaya’s Essence’s controller has four Forests and
|
||||||
|
* taps one of them for Green, the Essence will add GreenGreenGreen to that
|
||||||
|
* player’s mana pool for a total of GreenGreenGreenGreen.
|
||||||
|
*
|
||||||
|
* 6/1/2005 If Sasaya’s Essence’s controller has four Mossfire Valley and
|
||||||
|
* taps one of them for RedGreen, the Essence will add three mana (one for
|
||||||
|
* each other Mossfire Valley) of any combination of Red and/or Green to
|
||||||
|
* that player’s mana pool.
|
||||||
|
*
|
||||||
|
* 6/1/2005 If Sasaya’s Essence’s controller has two Brushlands and taps one
|
||||||
|
* of them for White, Sasaya’s Essence adds another White to that player’s
|
||||||
|
* mana pool. It won’t produce Green or Colorless unless the land was tapped
|
||||||
|
* for Green or Colorless instead.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Mana produceMana(Game game, Ability source) {
|
public Mana produceMana(Game game, Ability source) {
|
||||||
Mana newMana = new Mana();
|
Mana newMana = new Mana();
|
||||||
|
|
|
@ -74,6 +74,9 @@ class SavageFirecatTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
|
if (game.inCheckPlayableState()) { // Ignored - see GameEvent.TAPPED_FOR_MANA
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return game.getCard(event.getSourceId()).isLand() &&
|
return game.getCard(event.getSourceId()).isLand() &&
|
||||||
event.getPlayerId().equals(this.controllerId);
|
event.getPlayerId().equals(this.controllerId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ import mage.constants.Zone;
|
||||||
import mage.filter.common.FilterControlledLandPermanent;
|
import mage.filter.common.FilterControlledLandPermanent;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.events.GameEvent.EventType;
|
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.target.targetpointer.FixedTarget;
|
import mage.target.targetpointer.FixedTarget;
|
||||||
|
|
||||||
|
@ -72,12 +71,15 @@ class VorinclexTriggeredAbility2 extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkEventType(GameEvent event, Game game) {
|
public boolean checkEventType(GameEvent event, Game game) {
|
||||||
return event.getType() == EventType.TAPPED_FOR_MANA;
|
return event.getType() == GameEvent.EventType.TAPPED_FOR_MANA;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
if (game.getOpponents(controllerId).contains(event.getPlayerId())) {
|
if (game.inCheckPlayableState()) { // Ignored - see GameEvent.TAPPED_FOR_MANA
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (game.getOpponents(getControllerId()).contains(event.getPlayerId())) {
|
||||||
Permanent permanent = game.getPermanent(event.getSourceId());
|
Permanent permanent = game.getPermanent(event.getSourceId());
|
||||||
if (permanent != null && permanent.isLand()) {
|
if (permanent != null && permanent.isLand()) {
|
||||||
getEffects().get(0).setTargetPointer(new FixedTarget(permanent.getId()));
|
getEffects().get(0).setTargetPointer(new FixedTarget(permanent.getId()));
|
||||||
|
|
|
@ -22,7 +22,8 @@ import mage.filter.common.FilterLandPermanent;
|
||||||
public final class WintersNight extends CardImpl {
|
public final class WintersNight extends CardImpl {
|
||||||
|
|
||||||
private static final FilterLandPermanent filter = new FilterLandPermanent("a player taps a snow land");
|
private static final FilterLandPermanent filter = new FilterLandPermanent("a player taps a snow land");
|
||||||
{
|
|
||||||
|
static {
|
||||||
filter.add(SuperType.SNOW.getPredicate());
|
filter.add(SuperType.SNOW.getPredicate());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,13 +29,16 @@ public class SasayaOrochiAscendantTest extends CardTestPlayerBase {
|
||||||
addCard(Zone.HAND, playerA, "Upwelling", 1); // Enchantment {3}{G}
|
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");
|
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}");
|
||||||
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");
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Upwelling");
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
execute();
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
assertPermanentCount(playerA, "Sasaya's Essence", 1);
|
assertPermanentCount(playerA, "Sasaya's Essence", 1);
|
||||||
assertPermanentCount(playerA, "Upwelling", 1);
|
assertPermanentCount(playerA, "Upwelling", 1);
|
||||||
|
|
||||||
|
@ -45,7 +48,89 @@ public class SasayaOrochiAscendantTest extends CardTestPlayerBase {
|
||||||
assertDuplicatedManaOptions(manaOptions);
|
assertDuplicatedManaOptions(manaOptions);
|
||||||
|
|
||||||
Assert.assertEquals("mana variations don't fit", 1, manaOptions.size());
|
Assert.assertEquals("mana variations don't fit", 1, manaOptions.size());
|
||||||
assertManaOptions("{G}", manaOptions);
|
assertManaOptions("{G}{G}{G}", manaOptions);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSasayasEssence2() {
|
||||||
|
addCard(Zone.HAND, playerA, "Plains", 7);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Brushland", 3);
|
||||||
|
|
||||||
|
// Reveal your hand: If you have seven or more land cards in your hand, flip Sasaya, Orochi Ascendant.
|
||||||
|
// Sasaya's Essence: Legendary Enchantment
|
||||||
|
// Whenever a land you control is tapped for mana, for each other land you control with the same name, add one mana of any type that land produced.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Sasaya, Orochi Ascendant", 1);
|
||||||
|
// Mana pools don't empty as steps and phases end.
|
||||||
|
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");
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSasayasEssence3() {
|
||||||
|
addCard(Zone.HAND, playerA, "Plains", 7);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
|
||||||
|
// {1}, {T}: Add {R}{G}.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mossfire Valley", 2);
|
||||||
|
|
||||||
|
// Reveal your hand: If you have seven or more land cards in your hand, flip Sasaya, Orochi Ascendant.
|
||||||
|
// Sasaya's Essence: Legendary Enchantment
|
||||||
|
// Whenever a land you control is tapped for mana, for each other land you control with the same name, add one mana of any type that land produced.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Sasaya, Orochi Ascendant", 1);
|
||||||
|
// Mana pools don't empty as steps and phases end.
|
||||||
|
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");
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,6 @@ public class ConditionalManaTest extends CardTestPlayerBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
|
||||||
public void testWorkingWithReflectingPool() {
|
public void testWorkingWithReflectingPool() {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Cavern of Souls", 1); // can give {C] or {any} mana ({any} with restrictions)
|
addCard(Zone.BATTLEFIELD, playerA, "Cavern of Souls", 1); // can give {C] or {any} mana ({any} with restrictions)
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Reflecting Pool", 1); // must give {C} or {any} mana from the Cavern, but without restrictions
|
addCard(Zone.BATTLEFIELD, playerA, "Reflecting Pool", 1); // must give {C} or {any} mana from the Cavern, but without restrictions
|
||||||
|
@ -321,7 +320,6 @@ public class ConditionalManaTest extends CardTestPlayerBase {
|
||||||
// and process all available net mana by special call like TriggeredManaAbility->getNetManaForEvent(ManaEvent xxx)
|
// and process all available net mana by special call like TriggeredManaAbility->getNetManaForEvent(ManaEvent xxx)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
|
||||||
public void TriggeredManaAbilityMustGivesExtraManaOptions() {
|
public void TriggeredManaAbilityMustGivesExtraManaOptions() {
|
||||||
// TriggeredManaAbility must give extra mana options (2 red instead 1)
|
// TriggeredManaAbility must give extra mana options (2 red instead 1)
|
||||||
// Whenever you tap a land for mana, add one mana of any type that land produced.
|
// Whenever you tap a land for mana, add one mana of any type that land produced.
|
||||||
|
@ -340,7 +338,6 @@ public class ConditionalManaTest extends CardTestPlayerBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
|
||||||
public void DictateOfKarametra_AutoPay() {
|
public void DictateOfKarametra_AutoPay() {
|
||||||
// Whenever you tap a land for mana, add one mana of any type that land produced.
|
// Whenever you tap a land for mana, add one mana of any type that land produced.
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Dictate of Karametra");
|
addCard(Zone.BATTLEFIELD, playerA, "Dictate of Karametra");
|
||||||
|
|
|
@ -5,7 +5,6 @@ import mage.constants.ManaType;
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
@ -133,7 +132,6 @@ public class ReflectingPoolTest extends CardTestPlayerBase {
|
||||||
* producing mana
|
* producing mana
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
|
||||||
public void testWithDifferentLands() {
|
public void testWithDifferentLands() {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1);
|
||||||
|
|
||||||
|
@ -215,7 +213,6 @@ public class ReflectingPoolTest extends CardTestPlayerBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
|
||||||
public void testReflectingPoolAnyManaNeedWithoutCondition() {
|
public void testReflectingPoolAnyManaNeedWithoutCondition() {
|
||||||
// any mana source without conditions (use any mana at any time)
|
// any mana source without conditions (use any mana at any time)
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
|
||||||
|
@ -233,7 +230,6 @@ public class ReflectingPoolTest extends CardTestPlayerBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
|
||||||
public void testReflectingPoolAnyManaNeedWithCondition() {
|
public void testReflectingPoolAnyManaNeedWithCondition() {
|
||||||
// any mana source have condition to use (Reflecting Pool must ignore that condition)
|
// any mana source have condition to use (Reflecting Pool must ignore that condition)
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Cavern of Souls", 1); // {C} or {any}
|
addCard(Zone.BATTLEFIELD, playerA, "Cavern of Souls", 1); // {C} or {any}
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
package org.mage.test.cards.mana;
|
||||||
|
|
||||||
|
import mage.abilities.mana.ManaOptions;
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
import static org.mage.test.utils.ManaOptionsTestUtils.assertManaOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author LevelX2
|
||||||
|
*/
|
||||||
|
public class TappedForManaRelatedTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a new rule that slightly changes how we resolve abilities that
|
||||||
|
* trigger whenever a permanent is tapped for mana or for mana of a
|
||||||
|
* specified type. Now, you look at what was actually produced after the
|
||||||
|
* activated mana ability resolves. So, tapping a Gaea's Cradle while you no
|
||||||
|
* control no creatures won't cause a Wild Growth attached to it to trigger.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void TestCradleWithWildGrowthNoCreatures() {
|
||||||
|
// {T}: Add {G} for each creature you control.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Gaea's Cradle", 1);
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||||
|
// Enchant land
|
||||||
|
// Whenever enchanted land is tapped for mana, its controller adds {G}.
|
||||||
|
addCard(Zone.HAND, playerA, "Wild Growth", 1); // Enchantment {G}
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wild Growth", "Gaea's Cradle");
|
||||||
|
|
||||||
|
setStopAt(3, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "Wild Growth", 1);
|
||||||
|
|
||||||
|
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
|
||||||
|
Assert.assertEquals("mana variations don't fit", 1, manaOptions.size());
|
||||||
|
assertManaOptions("{G}{G}", manaOptions);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mana producedc by triggered mana abilities is not calculated in manaOptions calculations yet.
|
||||||
|
@Test
|
||||||
|
// @Ignore
|
||||||
|
public void TestCradleWithWildGrowthTwoCreatures() {
|
||||||
|
// {T}: Add {G} for each creature you control.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Gaea's Cradle", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 2);
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||||
|
// Enchant land
|
||||||
|
// Whenever enchanted land is tapped for mana, its controller adds {G}.
|
||||||
|
addCard(Zone.HAND, playerA, "Wild Growth", 1); // Enchantment {G}
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wild Growth", "Gaea's Cradle");
|
||||||
|
|
||||||
|
setStopAt(3, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "Wild Growth", 1);
|
||||||
|
|
||||||
|
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
|
||||||
|
Assert.assertEquals("mana variations don't fit", 1, manaOptions.size());
|
||||||
|
assertManaOptions("{G}{G}{G}{G}", manaOptions);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mana producedc by triggered mana abilities is not calculated in manaOptions calculations yet.
|
||||||
|
@Test
|
||||||
|
// @Ignore
|
||||||
|
public void TestWildGrowth() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 2);
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||||
|
// Enchant land
|
||||||
|
// Whenever enchanted land is tapped for mana, its controller adds {G}.
|
||||||
|
addCard(Zone.HAND, playerA, "Wild Growth", 1); // Enchantment {G}
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wild Growth", "Forest");
|
||||||
|
|
||||||
|
setStopAt(3, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "Wild Growth", 1);
|
||||||
|
|
||||||
|
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
|
||||||
|
Assert.assertEquals("mana variations don't fit", 1, manaOptions.size());
|
||||||
|
assertManaOptions("{G}{G}", manaOptions);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -63,6 +63,7 @@ import java.util.*;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import mage.Mana;
|
||||||
|
|
||||||
import static org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl.*;
|
import static org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl.*;
|
||||||
|
|
||||||
|
@ -3274,7 +3275,17 @@ public class TestPlayer implements Player {
|
||||||
public ManaOptions getManaAvailable(Game game) {
|
public ManaOptions getManaAvailable(Game game) {
|
||||||
return computerPlayer.getManaAvailable(game);
|
return computerPlayer.getManaAvailable(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addAvailableTriggeredMana(List<Mana> availableTriggeredMana) {
|
||||||
|
computerPlayer.addAvailableTriggeredMana(availableTriggeredMana);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<List<Mana>> getAvailableTriggeredMana() {
|
||||||
|
return computerPlayer.getAvailableTriggeredMana();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ActivatedAbility> getPlayable(Game game, boolean hidden) {
|
public List<ActivatedAbility> getPlayable(Game game, boolean hidden) {
|
||||||
return computerPlayer.getPlayable(game, hidden);
|
return computerPlayer.getPlayable(game, hidden);
|
||||||
|
|
|
@ -41,6 +41,7 @@ import mage.target.common.TargetCardInLibrary;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import mage.Mana;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Quercitron
|
* @author Quercitron
|
||||||
|
@ -1037,6 +1038,21 @@ public class PlayerStub implements Player {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addAvailableTriggeredMana(List<Mana> availableTriggeredMan) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<List<Mana>> getAvailableTriggeredMana() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int announceXMana(int min, int max, String message, Game game, Ability ability) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ActivatedAbility> getPlayable(Game game, boolean hidden) {
|
public List<ActivatedAbility> getPlayable(Game game, boolean hidden) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -209,11 +209,32 @@ public class ManaOptionsTest extends CardTestPlayerBase {
|
||||||
assertManaOptions("{C}{G}{Any}", manaOptions);
|
assertManaOptions("{C}{G}{Any}", manaOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Nykthos, Shrine to Nyx
|
||||||
|
@Test
|
||||||
|
public void testNykthos4a() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Sedge Scorpion", 4);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
|
||||||
|
// {T}: Add {C}.
|
||||||
|
// {2}, {T}: Choose a color. Add an amount of mana of that color equal to your devotion to that color. (Your devotion to a color is the number of mana symbols of that color in the mana costs of permanents you control.)
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Nykthos, Shrine to Nyx", 1);
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.UPKEEP);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
|
||||||
|
assertDuplicatedManaOptions(manaOptions);
|
||||||
|
|
||||||
|
Assert.assertEquals("mana variations don't fit", 2, manaOptions.size());
|
||||||
|
assertManaOptions("{C}{G}{G}{G}", manaOptions);
|
||||||
|
assertManaOptions("{G}{G}{G}{G}{G}", manaOptions);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Nykthos, Shrine to Nyx
|
// Nykthos, Shrine to Nyx
|
||||||
// {T}: Add {C}.
|
// {T}: Add {C}.
|
||||||
// {2}, {T}: Choose a color. Add an amount of mana of that color equal to your devotion to that color. (Your devotion to a color is the number of mana symbols of that color in the mana costs of permanents you control.)
|
// {2}, {T}: Choose a color. Add an amount of mana of that color equal to your devotion to that color. (Your devotion to a color is the number of mana symbols of that color in the mana costs of permanents you control.)
|
||||||
@Test
|
@Test
|
||||||
public void testNykthos4() {
|
public void testNykthos4b() {
|
||||||
// If a land is tapped for two or more mana, it produces {C} instead of any other type and amount.
|
// If a land is tapped for two or more mana, it produces {C} instead of any other type and amount.
|
||||||
// Each spell a player casts costs {1} more to cast for each other spell that player has cast this turn.
|
// Each spell a player casts costs {1} more to cast for each other spell that player has cast this turn.
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Damping Sphere", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Damping Sphere", 1);
|
||||||
|
@ -399,7 +420,6 @@ public class ManaOptionsTest extends CardTestPlayerBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore // TriggeredManaAbilities not supported yet for getAvailableMana
|
|
||||||
public void testCryptGhast() {
|
public void testCryptGhast() {
|
||||||
//Extort (Whenever you cast a spell, you may pay {WB}. If you do, each opponent loses 1 life and you gain that much life.)
|
//Extort (Whenever you cast a spell, you may pay {WB}. If you do, each opponent loses 1 life and you gain that much life.)
|
||||||
// Whenever you tap a Swamp for mana, add {B} (in addition to the mana the land produces).
|
// Whenever you tap a Swamp for mana, add {B} (in addition to the mana the land produces).
|
||||||
|
|
|
@ -34,6 +34,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import mage.abilities.effects.common.ManaEffect;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author BetaSteward_at_googlemail.com
|
* @author BetaSteward_at_googlemail.com
|
||||||
|
@ -171,6 +172,9 @@ public abstract class AbilityImpl implements Ability {
|
||||||
private boolean resolveMode(Game game) {
|
private boolean resolveMode(Game game) {
|
||||||
boolean result = true;
|
boolean result = true;
|
||||||
for (Effect effect : getEffects()) {
|
for (Effect effect : getEffects()) {
|
||||||
|
if (game.inCheckPlayableState() && !(effect instanceof ManaEffect)) {
|
||||||
|
continue; // Ignored non mana effects - see GameEvent.TAPPED_FOR_MANA
|
||||||
|
}
|
||||||
if (effect instanceof OneShotEffect) {
|
if (effect instanceof OneShotEffect) {
|
||||||
boolean effectResult = effect.apply(game, this);
|
boolean effectResult = effect.apply(game, this);
|
||||||
result &= effectResult;
|
result &= effectResult;
|
||||||
|
|
|
@ -41,6 +41,9 @@ public class TapForManaAllTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
|
if (game.inCheckPlayableState()) { // Ignored - see GameEvent.TAPPED_FOR_MANA
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId());
|
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId());
|
||||||
if (permanent != null && filter.match(permanent, getSourceId(), getControllerId(), game)) {
|
if (permanent != null && filter.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||||
ManaEvent mEvent = (ManaEvent) event;
|
ManaEvent mEvent = (ManaEvent) event;
|
||||||
|
|
|
@ -34,6 +34,9 @@ public class TapLandForManaAllTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
|
if (game.inCheckPlayableState()) { // Ignored - see GameEvent.TAPPED_FOR_MANA
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId());
|
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId());
|
||||||
if (permanent != null && permanent.isLand()) {
|
if (permanent != null && permanent.isLand()) {
|
||||||
if (setTargetPointer) {
|
if (setTargetPointer) {
|
||||||
|
|
|
@ -26,7 +26,7 @@ public class ReturnToHandChosenControlledPermanentCost extends CostImpl {
|
||||||
target.setNotTarget(true);
|
target.setNotTarget(true);
|
||||||
this.addTarget(target);
|
this.addTarget(target);
|
||||||
if (target.getMaxNumberOfTargets() > 1 && target.getMaxNumberOfTargets() == target.getNumberOfTargets()) {
|
if (target.getMaxNumberOfTargets() > 1 && target.getMaxNumberOfTargets() == target.getNumberOfTargets()) {
|
||||||
this.text = "return " + CardUtil.numberToText(target.getMaxNumberOfTargets()) + ' '
|
this.text = "Return " + CardUtil.numberToText(target.getMaxNumberOfTargets()) + ' '
|
||||||
+ target.getTargetName()
|
+ target.getTargetName()
|
||||||
+ (target.getTargetName().endsWith(" you control") ? "" : " you control")
|
+ (target.getTargetName().endsWith(" you control") ? "" : " you control")
|
||||||
+ " to their owner's hand";
|
+ " to their owner's hand";
|
||||||
|
|
|
@ -14,6 +14,7 @@ import mage.players.Player;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import mage.abilities.TriggeredAbility;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author BetaSteward_at_googlemail.com
|
* @author BetaSteward_at_googlemail.com
|
||||||
|
@ -38,6 +39,15 @@ public abstract class ManaEffect extends OneShotEffect {
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (game.inCheckPlayableState()) {
|
||||||
|
// During calculation of the available mana for a player the "TappedForMana" event is fired to simulate triggered mana production.
|
||||||
|
// By checking the inCheckPlayableState these events are handled to give back only the available mana of instead really producing mana
|
||||||
|
// So it's important if ManaEffects overwrite the apply method to take care for this.
|
||||||
|
if (source instanceof TriggeredAbility) {
|
||||||
|
player.addAvailableTriggeredMana(getNetMana(game, source));
|
||||||
|
}
|
||||||
|
return true; // No need to add mana to pool during checkPlayable
|
||||||
|
}
|
||||||
Mana manaToAdd = produceMana(game, source);
|
Mana manaToAdd = produceMana(game, source);
|
||||||
if (manaToAdd != null && manaToAdd.count() > 0) {
|
if (manaToAdd != null && manaToAdd.count() > 0) {
|
||||||
checkToFirePossibleEvents(manaToAdd, game, source);
|
checkToFirePossibleEvents(manaToAdd, game, source);
|
||||||
|
@ -72,11 +82,13 @@ public abstract class ManaEffect extends OneShotEffect {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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)
|
* 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)
|
||||||
* <p>
|
* <p>
|
||||||
* WARNING, produceMana can be called multiple times for mana and spell available calculations
|
* WARNING, produceMana can be called multiple times for mana and spell
|
||||||
* if you don't want it then overide getNetMana to return max possible mana values
|
* available calculations if you don't want it then overide getNetMana to
|
||||||
* (if you have choose dialogs or extra effects like new counters in produceMana)
|
* return max possible mana values (if you have choose dialogs or extra
|
||||||
|
* effects like new counters in produceMana)
|
||||||
*
|
*
|
||||||
* @param game warning, can be NULL for AI score calcs (game == null)
|
* @param game warning, can be NULL for AI score calcs (game == null)
|
||||||
* @param source
|
* @param source
|
||||||
|
|
|
@ -38,9 +38,26 @@ public class AddManaOfAnyTypeProducedEffect extends ManaEffect {
|
||||||
@Override
|
@Override
|
||||||
public List<Mana> getNetMana(Game game, Ability source) {
|
public List<Mana> getNetMana(Game game, Ability source) {
|
||||||
List<Mana> netMana = new ArrayList<>();
|
List<Mana> netMana = new ArrayList<>();
|
||||||
Mana types = (Mana) this.getValue("mana"); // TODO: will not work until TriggeredManaAbility fix (see TriggeredManaAbilityMustGivesExtraManaOptions test)
|
Mana types = (Mana) this.getValue("mana");
|
||||||
if (types != null) {
|
if (types != null) {
|
||||||
netMana.add(types.copy());
|
if (types.getBlack() > 0) {
|
||||||
|
netMana.add(Mana.BlackMana(1));
|
||||||
|
}
|
||||||
|
if (types.getRed() > 0) {
|
||||||
|
netMana.add(Mana.RedMana(1));
|
||||||
|
}
|
||||||
|
if (types.getBlue() > 0) {
|
||||||
|
netMana.add(Mana.BlueMana(1));
|
||||||
|
}
|
||||||
|
if (types.getGreen() > 0) {
|
||||||
|
netMana.add(Mana.GreenMana(1));
|
||||||
|
}
|
||||||
|
if (types.getWhite() > 0) {
|
||||||
|
netMana.add(Mana.WhiteMana(1));
|
||||||
|
}
|
||||||
|
if (types.getColorless() > 0) {
|
||||||
|
netMana.add(Mana.ColorlessMana(1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return netMana;
|
return netMana;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import mage.Mana;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.effects.common.ManaEffect;
|
import mage.abilities.effects.common.ManaEffect;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.players.Player;
|
|
||||||
|
|
||||||
public class BasicManaEffect extends ManaEffect {
|
public class BasicManaEffect extends ManaEffect {
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import mage.abilities.costs.common.TapSourceCost;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.events.ManaEvent;
|
import mage.game.events.ManaEvent;
|
||||||
|
import mage.players.Player;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,24 +45,11 @@ public class ManaOptions extends ArrayList<Mana> {
|
||||||
//if there is only one mana option available add it to all the existing options
|
//if there is only one mana option available add it to all the existing options
|
||||||
List<Mana> netManas = abilities.get(0).getNetMana(game);
|
List<Mana> netManas = abilities.get(0).getNetMana(game);
|
||||||
if (netManas.size() == 1) {
|
if (netManas.size() == 1) {
|
||||||
if (!hasTapCost(abilities.get(0)) || checkTappedForManaReplacement(abilities.get(0), game, netManas.get(0))) {
|
checkTappedForManaReplacement(abilities.get(0), game, netManas.get(0));
|
||||||
addMana(netManas.get(0));
|
addMana(netManas.get(0));
|
||||||
}
|
addTriggeredMana(game, abilities.get(0));
|
||||||
} else if (netManas.size() > 1) {
|
} else if (netManas.size() > 1) {
|
||||||
List<Mana> copy = copy();
|
addManaVariation(netManas, abilities.get(0), game);
|
||||||
this.clear();
|
|
||||||
// boolean hasTapCost = hasTapCost(abilities.get(0)); // needed if checkTappedForManaReplacement is reactivated
|
|
||||||
for (Mana netMana : netManas) {
|
|
||||||
for (Mana mana : copy) {
|
|
||||||
// checkTappedForManaReplacement seems in some situations to produce endless iterations so deactivated for now: https://github.com/magefree/mage/issues/5023
|
|
||||||
if (true/* !hasTapCost || checkTappedForManaReplacement(abilities.get(0), game, netMana) */) {
|
|
||||||
Mana newMana = new Mana();
|
|
||||||
newMana.add(mana);
|
|
||||||
newMana.add(netMana);
|
|
||||||
this.add(newMana);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else { // mana source has more than 1 ability
|
} else { // mana source has more than 1 ability
|
||||||
|
@ -69,14 +57,14 @@ public class ManaOptions extends ArrayList<Mana> {
|
||||||
List<Mana> copy = copy();
|
List<Mana> copy = copy();
|
||||||
this.clear();
|
this.clear();
|
||||||
for (ActivatedManaAbilityImpl ability : abilities) {
|
for (ActivatedManaAbilityImpl ability : abilities) {
|
||||||
boolean hasTapCost = hasTapCost(ability);
|
|
||||||
for (Mana netMana : ability.getNetMana(game)) {
|
for (Mana netMana : ability.getNetMana(game)) {
|
||||||
if (!hasTapCost || checkTappedForManaReplacement(ability, game, netMana)) {
|
checkTappedForManaReplacement(ability, game, netMana);
|
||||||
|
for (Mana triggeredManaVariation : getTriggeredManaVariations(game, ability, netMana)) {
|
||||||
SkipAddMana:
|
SkipAddMana:
|
||||||
for (Mana mana : copy) {
|
for (Mana mana : copy) {
|
||||||
Mana newMana = new Mana();
|
Mana newMana = new Mana();
|
||||||
newMana.add(mana);
|
newMana.add(mana);
|
||||||
newMana.add(netMana);
|
newMana.add(triggeredManaVariation);
|
||||||
for (Mana existingMana : this) {
|
for (Mana existingMana : this) {
|
||||||
if (existingMana.equalManaValue(newMana)) {
|
if (existingMana.equalManaValue(newMana)) {
|
||||||
continue SkipAddMana;
|
continue SkipAddMana;
|
||||||
|
@ -91,18 +79,48 @@ public class ManaOptions extends ArrayList<Mana> {
|
||||||
this.add(newMana);
|
this.add(newMana);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkTappedForManaReplacement(Ability ability, Game game, Mana mana) {
|
private void addManaVariation(List<Mana> netManas, ActivatedManaAbilityImpl ability, Game game) {
|
||||||
ManaEvent event = new ManaEvent(GameEvent.EventType.TAPPED_FOR_MANA, ability.getSourceId(), ability.getSourceId(), ability.getControllerId(), mana);
|
List<Mana> copy = copy();
|
||||||
if (!game.replaceEvent(event)) {
|
this.clear();
|
||||||
return true;
|
for (Mana netMana : netManas) {
|
||||||
|
for (Mana mana : copy) {
|
||||||
|
if (!hasTapCost(ability) || checkTappedForManaReplacement(ability, game, netMana)) {
|
||||||
|
Mana newMana = new Mana();
|
||||||
|
newMana.add(mana);
|
||||||
|
newMana.add(netMana);
|
||||||
|
this.add(newMana);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
private List<List<Mana>> getSimulatedTriggeredManaFromPlayer(Game game, Ability ability) {
|
||||||
|
Player player = game.getPlayer(ability.getControllerId());
|
||||||
|
List<List<Mana>> newList = new ArrayList<>();
|
||||||
|
if (player != null) {
|
||||||
|
newList.addAll(player.getAvailableTriggeredMana());
|
||||||
|
player.getAvailableTriggeredMana().clear();
|
||||||
|
}
|
||||||
|
return newList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkTappedForManaReplacement(Ability ability, Game game, Mana mana) {
|
||||||
|
if (hasTapCost(ability)) {
|
||||||
|
ManaEvent event = new ManaEvent(GameEvent.EventType.TAPPED_FOR_MANA, ability.getSourceId(), ability.getSourceId(), ability.getControllerId(), mana);
|
||||||
|
if (!game.replaceEvent(event)) {
|
||||||
|
game.fireEvent(event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasTapCost(Ability ability) {
|
private boolean hasTapCost(Ability ability) {
|
||||||
|
@ -127,31 +145,41 @@ public class ManaOptions extends ArrayList<Mana> {
|
||||||
// no mana costs
|
// no mana costs
|
||||||
if (ability.getManaCosts().isEmpty()) {
|
if (ability.getManaCosts().isEmpty()) {
|
||||||
if (netManas.size() == 1) {
|
if (netManas.size() == 1) {
|
||||||
|
checkTappedForManaReplacement(ability, game, netManas.get(0));
|
||||||
addMana(netManas.get(0));
|
addMana(netManas.get(0));
|
||||||
|
addTriggeredMana(game, ability);
|
||||||
} else {
|
} else {
|
||||||
List<Mana> copy = copy();
|
List<Mana> copy = copy();
|
||||||
this.clear();
|
this.clear();
|
||||||
for (Mana netMana : netManas) {
|
for (Mana netMana : netManas) {
|
||||||
for (Mana mana : copy) {
|
checkTappedForManaReplacement(ability, game, netMana);
|
||||||
Mana newMana = new Mana();
|
for (Mana triggeredManaVariation : getTriggeredManaVariations(game, ability, netMana)) {
|
||||||
newMana.add(mana);
|
for (Mana mana : copy) {
|
||||||
newMana.add(netMana);
|
Mana newMana = new Mana();
|
||||||
this.add(newMana);
|
newMana.add(mana);
|
||||||
|
newMana.add(triggeredManaVariation);
|
||||||
|
this.add(newMana);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else // the ability has mana costs
|
} else // the ability has mana costs
|
||||||
if (netManas.size() == 1) {
|
if (netManas.size() == 1) {
|
||||||
|
checkTappedForManaReplacement(ability, game, netManas.get(0));
|
||||||
subtractCostAddMana(ability.getManaCosts().getMana(), netManas.get(0), ability.getCosts().isEmpty());
|
subtractCostAddMana(ability.getManaCosts().getMana(), netManas.get(0), ability.getCosts().isEmpty());
|
||||||
|
addTriggeredMana(game, ability);
|
||||||
} else {
|
} else {
|
||||||
List<Mana> copy = copy();
|
List<Mana> copy = copy();
|
||||||
this.clear();
|
this.clear();
|
||||||
for (Mana netMana : netManas) {
|
for (Mana netMana : netManas) {
|
||||||
for (Mana mana : copy) {
|
checkTappedForManaReplacement(ability, game, netMana);
|
||||||
Mana newMana = new Mana();
|
for (Mana triggeredManaVariation : getTriggeredManaVariations(game, ability, netMana)) {
|
||||||
newMana.add(mana);
|
for (Mana mana : copy) {
|
||||||
newMana.add(netMana);
|
Mana newMana = new Mana();
|
||||||
subtractCostAddMana(ability.getManaCosts().getMana(), netMana, ability.getCosts().isEmpty());
|
newMana.add(mana);
|
||||||
|
newMana.add(triggeredManaVariation);
|
||||||
|
subtractCostAddMana(ability.getManaCosts().getMana(), netMana, ability.getCosts().isEmpty());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,30 +188,30 @@ public class ManaOptions extends ArrayList<Mana> {
|
||||||
List<Mana> copy = copy();
|
List<Mana> copy = copy();
|
||||||
this.clear();
|
this.clear();
|
||||||
for (ActivatedManaAbilityImpl ability : abilities) {
|
for (ActivatedManaAbilityImpl ability : abilities) {
|
||||||
boolean hasTapCost = hasTapCost(ability);
|
|
||||||
List<Mana> netManas = ability.getNetMana(game);
|
List<Mana> netManas = ability.getNetMana(game);
|
||||||
|
|
||||||
if (ability.getManaCosts().isEmpty()) {
|
if (ability.getManaCosts().isEmpty()) {
|
||||||
for (Mana netMana : netManas) {
|
for (Mana netMana : netManas) {
|
||||||
if (!hasTapCost || checkTappedForManaReplacement(ability, game, netMana)) {
|
checkTappedForManaReplacement(ability, game, netMana);
|
||||||
|
for (Mana triggeredManaVariation : getTriggeredManaVariations(game, ability, netMana)) {
|
||||||
for (Mana mana : copy) {
|
for (Mana mana : copy) {
|
||||||
Mana newMana = new Mana();
|
Mana newMana = new Mana();
|
||||||
newMana.add(mana);
|
newMana.add(mana);
|
||||||
newMana.add(netMana);
|
newMana.add(triggeredManaVariation);
|
||||||
this.add(newMana);
|
this.add(newMana);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (Mana netMana : netManas) {
|
for (Mana netMana : netManas) {
|
||||||
if (!hasTapCost || checkTappedForManaReplacement(ability, game, netMana)) {
|
checkTappedForManaReplacement(ability, game, netMana);
|
||||||
|
for (Mana triggeredManaVariation : getTriggeredManaVariations(game, ability, netMana)) {
|
||||||
for (Mana previousMana : copy) {
|
for (Mana previousMana : copy) {
|
||||||
CombineWithExisting:
|
CombineWithExisting:
|
||||||
for (Mana manaOption : ability.getManaCosts().getManaOptions()) {
|
for (Mana manaOption : ability.getManaCosts().getManaOptions()) {
|
||||||
Mana newMana = new Mana(previousMana);
|
Mana newMana = new Mana(previousMana);
|
||||||
if (previousMana.includesMana(manaOption)) { // costs can be paid
|
if (previousMana.includesMana(manaOption)) { // costs can be paid
|
||||||
newMana.subtractCost(manaOption);
|
newMana.subtractCost(manaOption);
|
||||||
newMana.add(netMana);
|
newMana.add(triggeredManaVariation);
|
||||||
// if the new mana is in all colors more than another already existing than replace
|
// if the new mana is in all colors more than another already existing than replace
|
||||||
for (Mana existingMana : this) {
|
for (Mana existingMana : this) {
|
||||||
Mana moreValuable = Mana.getMoreValuableMana(newMana, existingMana);
|
Mana moreValuable = Mana.getMoreValuableMana(newMana, existingMana);
|
||||||
|
@ -211,6 +239,52 @@ public class ManaOptions extends ArrayList<Mana> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Mana> getTriggeredManaVariations(Game game, Ability ability, Mana baseMana) {
|
||||||
|
List<Mana> baseManaPlusTriggeredMana = new ArrayList<>();
|
||||||
|
baseManaPlusTriggeredMana.add(baseMana);
|
||||||
|
List<List<Mana>> availableTriggeredManaList = getSimulatedTriggeredManaFromPlayer(game, ability);
|
||||||
|
for (List<Mana> availableTriggeredMana : availableTriggeredManaList) {
|
||||||
|
if (availableTriggeredMana.size() == 1) {
|
||||||
|
for (Mana prevMana : baseManaPlusTriggeredMana) {
|
||||||
|
prevMana.add(availableTriggeredMana.get(0));
|
||||||
|
}
|
||||||
|
} else if (availableTriggeredMana.size() > 1) {
|
||||||
|
List<Mana> copy = new ArrayList<>(baseManaPlusTriggeredMana);
|
||||||
|
baseManaPlusTriggeredMana.clear();
|
||||||
|
for (Mana triggeredMana : availableTriggeredMana) {
|
||||||
|
for (Mana prevMana : copy) {
|
||||||
|
Mana newMana = new Mana();
|
||||||
|
newMana.add(prevMana);
|
||||||
|
newMana.add(triggeredMana);
|
||||||
|
baseManaPlusTriggeredMana.add(newMana);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return baseManaPlusTriggeredMana;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addTriggeredMana(Game game, Ability ability) {
|
||||||
|
List<List<Mana>> netManaList = getSimulatedTriggeredManaFromPlayer(game, ability);
|
||||||
|
for (List<Mana> triggeredNetMana : netManaList) {
|
||||||
|
if (triggeredNetMana.size() == 1) {
|
||||||
|
addMana(triggeredNetMana.get(0));
|
||||||
|
} else if (triggeredNetMana.size() > 1) {
|
||||||
|
// Add variations
|
||||||
|
List<Mana> copy = copy();
|
||||||
|
this.clear();
|
||||||
|
for (Mana triggeredMana : triggeredNetMana) {
|
||||||
|
for (Mana mana : copy) {
|
||||||
|
Mana newMana = new Mana();
|
||||||
|
newMana.add(mana);
|
||||||
|
newMana.add(triggeredMana);
|
||||||
|
this.add(newMana);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void addMana(Mana addMana) {
|
public void addMana(Mana addMana) {
|
||||||
if (isEmpty()) {
|
if (isEmpty()) {
|
||||||
this.add(new Mana());
|
this.add(new Mana());
|
||||||
|
|
|
@ -133,7 +133,7 @@ public class GameEvent implements Serializable {
|
||||||
targetId id of the spell that's cast
|
targetId id of the spell that's cast
|
||||||
playerId player that casts the spell or ability
|
playerId player that casts the spell or ability
|
||||||
amount X multiplier to change X value, default 1
|
amount X multiplier to change X value, default 1
|
||||||
*/
|
*/
|
||||||
CAST_SPELL,
|
CAST_SPELL,
|
||||||
/* SPELL_CAST
|
/* SPELL_CAST
|
||||||
x-Costs are already defined
|
x-Costs are already defined
|
||||||
|
@ -153,13 +153,13 @@ public class GameEvent implements Serializable {
|
||||||
targetId id of the ability to activate / use
|
targetId id of the ability to activate / use
|
||||||
sourceId sourceId of the object with that ability
|
sourceId sourceId of the object with that ability
|
||||||
playerId player that tries to use this ability
|
playerId player that tries to use this ability
|
||||||
*/
|
*/
|
||||||
TAKE_SPECIAL_ACTION, TAKEN_SPECIAL_ACTION, // not used in implementation yet
|
TAKE_SPECIAL_ACTION, TAKEN_SPECIAL_ACTION, // not used in implementation yet
|
||||||
/* TAKE_SPECIAL_ACTION, TAKEN_SPECIAL_ACTION,
|
/* TAKE_SPECIAL_ACTION, TAKEN_SPECIAL_ACTION,
|
||||||
targetId id of the ability to activate / use
|
targetId id of the ability to activate / use
|
||||||
sourceId sourceId of the object with that ability
|
sourceId sourceId of the object with that ability
|
||||||
playerId player that tries to use this ability
|
playerId player that tries to use this ability
|
||||||
*/
|
*/
|
||||||
TRIGGERED_ABILITY,
|
TRIGGERED_ABILITY,
|
||||||
RESOLVING_ABILITY,
|
RESOLVING_ABILITY,
|
||||||
COPY_STACKOBJECT, COPIED_STACKOBJECT,
|
COPY_STACKOBJECT, COPIED_STACKOBJECT,
|
||||||
|
@ -254,7 +254,13 @@ public class GameEvent implements Serializable {
|
||||||
ENTERS_THE_BATTLEFIELD_CONTROL, // 616.1b
|
ENTERS_THE_BATTLEFIELD_CONTROL, // 616.1b
|
||||||
ENTERS_THE_BATTLEFIELD_COPY, // 616.1c
|
ENTERS_THE_BATTLEFIELD_COPY, // 616.1c
|
||||||
ENTERS_THE_BATTLEFIELD, // 616.1d
|
ENTERS_THE_BATTLEFIELD, // 616.1d
|
||||||
TAP, TAPPED, TAPPED_FOR_MANA,
|
TAP, TAPPED,
|
||||||
|
TAPPED_FOR_MANA,
|
||||||
|
/* TAPPED_FOR_MANA
|
||||||
|
During calculation of the available mana for a player the "TappedForMana" event is fired to simulate triggered mana production.
|
||||||
|
By checking the inCheckPlayableState these events are handled to give back only the available mana of instead really producing mana.
|
||||||
|
IMPORTANT: Triggered non mana abilities have to ignore the event if game.inCheckPlayableState is true.
|
||||||
|
*/
|
||||||
UNTAP, UNTAPPED,
|
UNTAP, UNTAPPED,
|
||||||
FLIP, FLIPPED,
|
FLIP, FLIPPED,
|
||||||
UNFLIP, UNFLIPPED,
|
UNFLIP, UNFLIPPED,
|
||||||
|
@ -412,12 +418,12 @@ public class GameEvent implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private GameEvent(EventType type, UUID customEventType,
|
private GameEvent(EventType type, UUID customEventType,
|
||||||
UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag) {
|
UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag) {
|
||||||
this(type, customEventType, targetId, sourceId, playerId, amount, flag, null);
|
this(type, customEventType, targetId, sourceId, playerId, amount, flag, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private GameEvent(EventType type, UUID customEventType,
|
private GameEvent(EventType type, UUID customEventType,
|
||||||
UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag, MageObjectReference reference) {
|
UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag, MageObjectReference reference) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.customEventType = customEventType;
|
this.customEventType = customEventType;
|
||||||
this.targetId = targetId;
|
this.targetId = targetId;
|
||||||
|
|
|
@ -40,6 +40,7 @@ import mage.util.Copyable;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import mage.Mana;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author BetaSteward_at_googlemail.com
|
* @author BetaSteward_at_googlemail.com
|
||||||
|
@ -635,6 +636,10 @@ public interface Player extends MageItem, Copyable<Player> {
|
||||||
void untap(Game game);
|
void untap(Game game);
|
||||||
|
|
||||||
ManaOptions getManaAvailable(Game game);
|
ManaOptions getManaAvailable(Game game);
|
||||||
|
|
||||||
|
void addAvailableTriggeredMana(List<Mana> netManaAvailable);
|
||||||
|
|
||||||
|
List<List<Mana>> getAvailableTriggeredMana();
|
||||||
|
|
||||||
List<ActivatedAbility> getPlayable(Game game, boolean hidden);
|
List<ActivatedAbility> getPlayable(Game game, boolean hidden);
|
||||||
|
|
||||||
|
|
|
@ -177,6 +177,9 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
|
|
||||||
protected FilterMana phyrexianColors;
|
protected FilterMana phyrexianColors;
|
||||||
|
|
||||||
|
// Used during available mana calculation to give back possible available net mana from triggered mana abilities (No need to copy)
|
||||||
|
protected final List<List<Mana>> availableTriggeredManaList = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* During some steps we can't play anything
|
* During some steps we can't play anything
|
||||||
*/
|
*/
|
||||||
|
@ -2848,8 +2851,18 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
return game.getBattlefield().getAllActivePermanents(blockFilter, playerId, game);
|
return game.getBattlefield().getAllActivePermanents(blockFilter, playerId, game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the mana options the player currently has. That means which combinations of
|
||||||
|
* mana are available to cast spells or activate abilities etc.
|
||||||
|
*
|
||||||
|
* @param game
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ManaOptions getManaAvailable(Game game) {
|
public ManaOptions getManaAvailable(Game game) {
|
||||||
|
boolean oldState = game.inCheckPlayableState();
|
||||||
|
game.setCheckPlayableState(true);
|
||||||
|
|
||||||
ManaOptions availableMana = new ManaOptions();
|
ManaOptions availableMana = new ManaOptions();
|
||||||
|
|
||||||
List<Abilities<ActivatedManaAbilityImpl>> sourceWithoutManaCosts = new ArrayList<>();
|
List<Abilities<ActivatedManaAbilityImpl>> sourceWithoutManaCosts = new ArrayList<>();
|
||||||
|
@ -2891,10 +2904,34 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
|
|
||||||
// remove duplicated variants (see ManaOptionsTest for info - when that rises)
|
// remove duplicated variants (see ManaOptionsTest for info - when that rises)
|
||||||
availableMana.removeDuplicated();
|
availableMana.removeDuplicated();
|
||||||
|
|
||||||
|
game.setCheckPlayableState(oldState);
|
||||||
return availableMana;
|
return availableMana;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used during calculation of available mana to gather the amount of producable triggered mana caused by using mana sources.
|
||||||
|
* So the set value is only used during the calculation of the mana produced by one source and cleared thereafter
|
||||||
|
*
|
||||||
|
* @param netManaAvailable the net mana produced by the triggered mana abaility
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addAvailableTriggeredMana(List<Mana> netManaAvailable) {
|
||||||
|
this.availableTriggeredManaList.add(netManaAvailable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used during calculation of available mana to get the amount of producable triggered mana caused by using mana sources.
|
||||||
|
* The list is cleared as soon the value is retrieved during available mana calculation.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<List<Mana>> getAvailableTriggeredMana() {
|
||||||
|
return availableTriggeredManaList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// returns only mana producers that don't require mana payment
|
// returns only mana producers that don't require mana payment
|
||||||
protected List<MageObject> getAvailableManaProducers(Game game) {
|
protected List<MageObject> getAvailableManaProducers(Game game) {
|
||||||
List<MageObject> result = new ArrayList<>();
|
List<MageObject> result = new ArrayList<>();
|
||||||
|
|
Loading…
Reference in a new issue